presenter.rs

   1use crate::{
   2    app::{AppContext, MutableAppContext, WindowInvalidation},
   3    elements::Element,
   4    font_cache::FontCache,
   5    geometry::rect::RectF,
   6    json::{self, ToJson},
   7    platform::{CursorStyle, Event},
   8    scene::{
   9        CursorRegion, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover,
  10        MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene,
  11    },
  12    text_layout::TextLayoutCache,
  13    Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AnyWeakViewHandle, Appearance,
  14    AssetCache, ElementBox, Entity, FontSystem, ModelHandle, MouseButton, MouseMovedEvent,
  15    MouseRegion, MouseRegionId, ParentId, ReadModel, ReadView, RenderContext, RenderParams,
  16    SceneBuilder, UpgradeModelHandle, UpgradeViewHandle, View, ViewHandle, WeakModelHandle,
  17    WeakViewHandle,
  18};
  19use anyhow::bail;
  20use collections::{HashMap, HashSet};
  21use pathfinder_geometry::vector::{vec2f, Vector2F};
  22use serde_json::json;
  23use smallvec::SmallVec;
  24use sqlez::{
  25    bindable::{Bind, Column, StaticColumnCount},
  26    statement::Statement,
  27};
  28use std::{
  29    marker::PhantomData,
  30    ops::{Deref, DerefMut, Range},
  31    sync::Arc,
  32};
  33
  34pub struct Presenter {
  35    window_id: usize,
  36    pub(crate) rendered_views: HashMap<usize, ElementBox>,
  37    cursor_regions: Vec<CursorRegion>,
  38    mouse_regions: Vec<(MouseRegion, usize)>,
  39    font_cache: Arc<FontCache>,
  40    text_layout_cache: TextLayoutCache,
  41    asset_cache: Arc<AssetCache>,
  42    last_mouse_moved_event: Option<Event>,
  43    hovered_region_ids: HashSet<MouseRegionId>,
  44    clicked_region_ids: HashSet<MouseRegionId>,
  45    clicked_button: Option<MouseButton>,
  46    mouse_position: Vector2F,
  47    titlebar_height: f32,
  48    appearance: Appearance,
  49}
  50
  51impl Presenter {
  52    pub fn new(
  53        window_id: usize,
  54        titlebar_height: f32,
  55        appearance: Appearance,
  56        font_cache: Arc<FontCache>,
  57        text_layout_cache: TextLayoutCache,
  58        asset_cache: Arc<AssetCache>,
  59        cx: &mut MutableAppContext,
  60    ) -> Self {
  61        Self {
  62            window_id,
  63            rendered_views: cx.render_views(window_id, titlebar_height, appearance),
  64            cursor_regions: Default::default(),
  65            mouse_regions: Default::default(),
  66            font_cache,
  67            text_layout_cache,
  68            asset_cache,
  69            last_mouse_moved_event: None,
  70            hovered_region_ids: Default::default(),
  71            clicked_region_ids: Default::default(),
  72            clicked_button: None,
  73            mouse_position: vec2f(0., 0.),
  74            titlebar_height,
  75            appearance,
  76        }
  77    }
  78
  79    pub fn invalidate(
  80        &mut self,
  81        invalidation: &mut WindowInvalidation,
  82        appearance: Appearance,
  83        cx: &mut MutableAppContext,
  84    ) {
  85        cx.start_frame();
  86        self.appearance = appearance;
  87        for view_id in &invalidation.removed {
  88            invalidation.updated.remove(view_id);
  89            self.rendered_views.remove(view_id);
  90        }
  91        for view_id in &invalidation.updated {
  92            self.rendered_views.insert(
  93                *view_id,
  94                cx.render_view(RenderParams {
  95                    window_id: self.window_id,
  96                    view_id: *view_id,
  97                    titlebar_height: self.titlebar_height,
  98                    hovered_region_ids: self.hovered_region_ids.clone(),
  99                    clicked_region_ids: self
 100                        .clicked_button
 101                        .map(|button| (self.clicked_region_ids.clone(), button)),
 102                    refreshing: false,
 103                    appearance,
 104                })
 105                .unwrap(),
 106            );
 107        }
 108    }
 109
 110    pub fn refresh(
 111        &mut self,
 112        invalidation: &mut WindowInvalidation,
 113        appearance: Appearance,
 114        cx: &mut MutableAppContext,
 115    ) {
 116        self.invalidate(invalidation, appearance, cx);
 117        for (view_id, view) in &mut self.rendered_views {
 118            if !invalidation.updated.contains(view_id) {
 119                *view = cx
 120                    .render_view(RenderParams {
 121                        window_id: self.window_id,
 122                        view_id: *view_id,
 123                        titlebar_height: self.titlebar_height,
 124                        hovered_region_ids: self.hovered_region_ids.clone(),
 125                        clicked_region_ids: self
 126                            .clicked_button
 127                            .map(|button| (self.clicked_region_ids.clone(), button)),
 128                        refreshing: true,
 129                        appearance,
 130                    })
 131                    .unwrap();
 132            }
 133        }
 134    }
 135
 136    pub fn build_scene(
 137        &mut self,
 138        window_size: Vector2F,
 139        scale_factor: f32,
 140        refreshing: bool,
 141        cx: &mut MutableAppContext,
 142    ) -> Scene {
 143        let mut scene_builder = SceneBuilder::new(scale_factor);
 144
 145        if let Some(root_view_id) = cx.root_view_id(self.window_id) {
 146            self.layout(window_size, refreshing, cx);
 147            let mut paint_cx = self.build_paint_context(&mut scene_builder, window_size, cx);
 148            paint_cx.paint(
 149                root_view_id,
 150                Vector2F::zero(),
 151                RectF::new(Vector2F::zero(), window_size),
 152            );
 153            self.text_layout_cache.finish_frame();
 154            let scene = scene_builder.build();
 155            self.cursor_regions = scene.cursor_regions();
 156            self.mouse_regions = scene.mouse_regions();
 157
 158            // window.is_topmost for the mouse moved event's postion?
 159            if cx.window_is_active(self.window_id) {
 160                if let Some(event) = self.last_mouse_moved_event.clone() {
 161                    self.dispatch_event(event, true, cx);
 162                }
 163            }
 164
 165            scene
 166        } else {
 167            log::error!("could not find root_view_id for window {}", self.window_id);
 168            scene_builder.build()
 169        }
 170    }
 171
 172    fn layout(&mut self, window_size: Vector2F, refreshing: bool, cx: &mut MutableAppContext) {
 173        if let Some(root_view_id) = cx.root_view_id(self.window_id) {
 174            self.build_layout_context(window_size, refreshing, cx)
 175                .layout(root_view_id, SizeConstraint::strict(window_size));
 176        }
 177    }
 178
 179    pub fn build_layout_context<'a>(
 180        &'a mut self,
 181        window_size: Vector2F,
 182        refreshing: bool,
 183        cx: &'a mut MutableAppContext,
 184    ) -> LayoutContext<'a> {
 185        LayoutContext {
 186            window_id: self.window_id,
 187            rendered_views: &mut self.rendered_views,
 188            font_cache: &self.font_cache,
 189            font_system: cx.platform().fonts(),
 190            text_layout_cache: &self.text_layout_cache,
 191            asset_cache: &self.asset_cache,
 192            view_stack: Vec::new(),
 193            refreshing,
 194            hovered_region_ids: self.hovered_region_ids.clone(),
 195            clicked_region_ids: self
 196                .clicked_button
 197                .map(|button| (self.clicked_region_ids.clone(), button)),
 198            titlebar_height: self.titlebar_height,
 199            appearance: self.appearance,
 200            window_size,
 201            app: cx,
 202        }
 203    }
 204
 205    pub fn build_paint_context<'a>(
 206        &'a mut self,
 207        scene: &'a mut SceneBuilder,
 208        window_size: Vector2F,
 209        cx: &'a mut MutableAppContext,
 210    ) -> PaintContext {
 211        PaintContext {
 212            scene,
 213            window_size,
 214            font_cache: &self.font_cache,
 215            text_layout_cache: &self.text_layout_cache,
 216            rendered_views: &mut self.rendered_views,
 217            view_stack: Vec::new(),
 218            app: cx,
 219        }
 220    }
 221
 222    pub fn rect_for_text_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<RectF> {
 223        cx.focused_view_id(self.window_id).and_then(|view_id| {
 224            let cx = MeasurementContext {
 225                app: cx,
 226                rendered_views: &self.rendered_views,
 227                window_id: self.window_id,
 228            };
 229            cx.rect_for_text_range(view_id, range_utf16)
 230        })
 231    }
 232
 233    pub fn dispatch_event(
 234        &mut self,
 235        event: Event,
 236        event_reused: bool,
 237        cx: &mut MutableAppContext,
 238    ) -> bool {
 239        let mut mouse_events = SmallVec::<[_; 2]>::new();
 240        let mut notified_views: HashSet<usize> = Default::default();
 241
 242        // 1. Handle platform event. Keyboard events get dispatched immediately, while mouse events
 243        //    get mapped into the mouse-specific MouseEvent type.
 244        //  -> These are usually small: [Mouse Down] or [Mouse up, Click] or [Mouse Moved, Mouse Dragged?]
 245        //  -> Also updates mouse-related state
 246        match &event {
 247            Event::KeyDown(e) => return cx.dispatch_key_down(self.window_id, e),
 248
 249            Event::KeyUp(e) => return cx.dispatch_key_up(self.window_id, e),
 250
 251            Event::ModifiersChanged(e) => return cx.dispatch_modifiers_changed(self.window_id, e),
 252
 253            Event::MouseDown(e) => {
 254                // Click events are weird because they can be fired after a drag event.
 255                // MDN says that browsers handle this by starting from 'the most
 256                // specific ancestor element that contained both [positions]'
 257                // So we need to store the overlapping regions on mouse down.
 258
 259                // If there is already clicked_button stored, don't replace it.
 260                if self.clicked_button.is_none() {
 261                    self.clicked_region_ids = self
 262                        .mouse_regions
 263                        .iter()
 264                        .filter_map(|(region, _)| {
 265                            if region.bounds.contains_point(e.position) {
 266                                Some(region.id())
 267                            } else {
 268                                None
 269                            }
 270                        })
 271                        .collect();
 272
 273                    self.clicked_button = Some(e.button);
 274                }
 275
 276                mouse_events.push(MouseEvent::Down(MouseDown {
 277                    region: Default::default(),
 278                    platform_event: e.clone(),
 279                }));
 280                mouse_events.push(MouseEvent::DownOut(MouseDownOut {
 281                    region: Default::default(),
 282                    platform_event: e.clone(),
 283                }));
 284            }
 285
 286            Event::MouseUp(e) => {
 287                // NOTE: The order of event pushes is important! MouseUp events MUST be fired
 288                // before click events, and so the MouseUp events need to be pushed before
 289                // MouseClick events.
 290                mouse_events.push(MouseEvent::Up(MouseUp {
 291                    region: Default::default(),
 292                    platform_event: e.clone(),
 293                }));
 294                mouse_events.push(MouseEvent::UpOut(MouseUpOut {
 295                    region: Default::default(),
 296                    platform_event: e.clone(),
 297                }));
 298                mouse_events.push(MouseEvent::Click(MouseClick {
 299                    region: Default::default(),
 300                    platform_event: e.clone(),
 301                }));
 302            }
 303
 304            Event::MouseMoved(
 305                e @ MouseMovedEvent {
 306                    position,
 307                    pressed_button,
 308                    ..
 309                },
 310            ) => {
 311                let mut style_to_assign = CursorStyle::Arrow;
 312                for region in self.cursor_regions.iter().rev() {
 313                    if region.bounds.contains_point(*position) {
 314                        style_to_assign = region.style;
 315                        break;
 316                    }
 317                }
 318
 319                if cx.is_topmost_window_for_position(self.window_id, *position) {
 320                    cx.platform().set_cursor_style(style_to_assign);
 321                }
 322
 323                if !event_reused {
 324                    if pressed_button.is_some() {
 325                        mouse_events.push(MouseEvent::Drag(MouseDrag {
 326                            region: Default::default(),
 327                            prev_mouse_position: self.mouse_position,
 328                            platform_event: e.clone(),
 329                        }));
 330                    } else if let Some(clicked_button) = self.clicked_button {
 331                        // Mouse up event happened outside the current window. Simulate mouse up button event
 332                        let button_event = e.to_button_event(clicked_button);
 333                        mouse_events.push(MouseEvent::Up(MouseUp {
 334                            region: Default::default(),
 335                            platform_event: button_event.clone(),
 336                        }));
 337                        mouse_events.push(MouseEvent::UpOut(MouseUpOut {
 338                            region: Default::default(),
 339                            platform_event: button_event.clone(),
 340                        }));
 341                        mouse_events.push(MouseEvent::Click(MouseClick {
 342                            region: Default::default(),
 343                            platform_event: button_event.clone(),
 344                        }));
 345                    }
 346
 347                    mouse_events.push(MouseEvent::Move(MouseMove {
 348                        region: Default::default(),
 349                        platform_event: e.clone(),
 350                    }));
 351                }
 352
 353                mouse_events.push(MouseEvent::Hover(MouseHover {
 354                    region: Default::default(),
 355                    platform_event: e.clone(),
 356                    started: false,
 357                }));
 358                mouse_events.push(MouseEvent::MoveOut(MouseMoveOut {
 359                    region: Default::default(),
 360                }));
 361
 362                self.last_mouse_moved_event = Some(event.clone());
 363            }
 364
 365            Event::MouseExited(event) => {
 366                // When the platform sends a MouseExited event, synthesize
 367                // a MouseMoved event whose position is outside the window's
 368                // bounds so that hover and cursor state can be updated.
 369                return self.dispatch_event(
 370                    Event::MouseMoved(MouseMovedEvent {
 371                        position: event.position,
 372                        pressed_button: event.pressed_button,
 373                        modifiers: event.modifiers,
 374                    }),
 375                    event_reused,
 376                    cx,
 377                );
 378            }
 379
 380            Event::ScrollWheel(e) => mouse_events.push(MouseEvent::ScrollWheel(MouseScrollWheel {
 381                region: Default::default(),
 382                platform_event: e.clone(),
 383            })),
 384        }
 385
 386        if let Some(position) = event.position() {
 387            self.mouse_position = position;
 388        }
 389
 390        // 2. Dispatch mouse events on regions
 391        let mut any_event_handled = false;
 392        for mut mouse_event in mouse_events {
 393            let mut valid_regions = Vec::new();
 394
 395            // GPUI elements are arranged by z_index but sibling elements can register overlapping
 396            // mouse regions. As such, hover events are only fired on overlapping elements which
 397            // are at the same z-index as the topmost element which overlaps with the mouse.
 398            match &mouse_event {
 399                MouseEvent::Hover(_) => {
 400                    let mut highest_z_index = None;
 401                    let mouse_position = self.mouse_position.clone();
 402                    for (region, z_index) in self.mouse_regions.iter().rev() {
 403                        // Allow mouse regions to appear transparent to hovers
 404                        if !region.hoverable {
 405                            continue;
 406                        }
 407
 408                        let contains_mouse = region.bounds.contains_point(mouse_position);
 409
 410                        if contains_mouse && highest_z_index.is_none() {
 411                            highest_z_index = Some(z_index);
 412                        }
 413
 414                        // This unwrap relies on short circuiting boolean expressions
 415                        // The right side of the && is only executed when contains_mouse
 416                        // is true, and we know above that when contains_mouse is true
 417                        // highest_z_index is set.
 418                        if contains_mouse && z_index == highest_z_index.unwrap() {
 419                            //Ensure that hover entrance events aren't sent twice
 420                            if self.hovered_region_ids.insert(region.id()) {
 421                                valid_regions.push(region.clone());
 422                                if region.notify_on_hover {
 423                                    notified_views.insert(region.id().view_id());
 424                                }
 425                            }
 426                        } else {
 427                            // Ensure that hover exit events aren't sent twice
 428                            if self.hovered_region_ids.remove(&region.id()) {
 429                                valid_regions.push(region.clone());
 430                                if region.notify_on_hover {
 431                                    notified_views.insert(region.id().view_id());
 432                                }
 433                            }
 434                        }
 435                    }
 436                }
 437
 438                MouseEvent::Down(_) | MouseEvent::Up(_) => {
 439                    for (region, _) in self.mouse_regions.iter().rev() {
 440                        if region.bounds.contains_point(self.mouse_position) {
 441                            valid_regions.push(region.clone());
 442                            if region.notify_on_click {
 443                                notified_views.insert(region.id().view_id());
 444                            }
 445                        }
 446                    }
 447                }
 448
 449                MouseEvent::Click(e) => {
 450                    // Only raise click events if the released button is the same as the one stored
 451                    if self
 452                        .clicked_button
 453                        .map(|clicked_button| clicked_button == e.button)
 454                        .unwrap_or(false)
 455                    {
 456                        // Clear clicked regions and clicked button
 457                        let clicked_region_ids =
 458                            std::mem::replace(&mut self.clicked_region_ids, Default::default());
 459                        self.clicked_button = None;
 460
 461                        // Find regions which still overlap with the mouse since the last MouseDown happened
 462                        for (mouse_region, _) in self.mouse_regions.iter().rev() {
 463                            if clicked_region_ids.contains(&mouse_region.id()) {
 464                                if mouse_region.bounds.contains_point(self.mouse_position) {
 465                                    valid_regions.push(mouse_region.clone());
 466                                }
 467                            }
 468                        }
 469                    }
 470                }
 471
 472                MouseEvent::Drag(_) => {
 473                    for (mouse_region, _) in self.mouse_regions.iter().rev() {
 474                        if self.clicked_region_ids.contains(&mouse_region.id()) {
 475                            valid_regions.push(mouse_region.clone());
 476                        }
 477                    }
 478                }
 479
 480                MouseEvent::MoveOut(_) | MouseEvent::UpOut(_) | MouseEvent::DownOut(_) => {
 481                    for (mouse_region, _) in self.mouse_regions.iter().rev() {
 482                        // NOT contains
 483                        if !mouse_region.bounds.contains_point(self.mouse_position) {
 484                            valid_regions.push(mouse_region.clone());
 485                        }
 486                    }
 487                }
 488
 489                _ => {
 490                    for (mouse_region, _) in self.mouse_regions.iter().rev() {
 491                        // Contains
 492                        if mouse_region.bounds.contains_point(self.mouse_position) {
 493                            valid_regions.push(mouse_region.clone());
 494                        }
 495                    }
 496                }
 497            }
 498
 499            //3. Fire region events
 500            let hovered_region_ids = self.hovered_region_ids.clone();
 501            for valid_region in valid_regions.into_iter() {
 502                let mut event_cx = self.build_event_context(&mut notified_views, cx);
 503
 504                mouse_event.set_region(valid_region.bounds);
 505                if let MouseEvent::Hover(e) = &mut mouse_event {
 506                    e.started = hovered_region_ids.contains(&valid_region.id())
 507                }
 508                // Handle Down events if the MouseRegion has a Click or Drag handler. This makes the api more intuitive as you would
 509                // not expect a MouseRegion to be transparent to Down events if it also has a Click handler.
 510                // This behavior can be overridden by adding a Down handler
 511                if let MouseEvent::Down(e) = &mouse_event {
 512                    let has_click = valid_region
 513                        .handlers
 514                        .contains(MouseEvent::click_disc(), Some(e.button));
 515                    let has_drag = valid_region
 516                        .handlers
 517                        .contains(MouseEvent::drag_disc(), Some(e.button));
 518                    let has_down = valid_region
 519                        .handlers
 520                        .contains(MouseEvent::down_disc(), Some(e.button));
 521                    if !has_down && (has_click || has_drag) {
 522                        event_cx.handled = true;
 523                    }
 524                }
 525
 526                // `event_consumed` should only be true if there are any handlers for this event.
 527                let mut event_consumed = event_cx.handled;
 528                if let Some(callbacks) = valid_region.handlers.get(&mouse_event.handler_key()) {
 529                    for callback in callbacks {
 530                        event_cx.handled = true;
 531                        event_cx.with_current_view(valid_region.id().view_id(), {
 532                            let region_event = mouse_event.clone();
 533                            |cx| callback(region_event, cx)
 534                        });
 535                        event_consumed |= event_cx.handled;
 536                        any_event_handled |= event_cx.handled;
 537                    }
 538                }
 539
 540                any_event_handled |= event_cx.handled;
 541
 542                // For bubbling events, if the event was handled, don't continue dispatching.
 543                // This only makes sense for local events which return false from is_capturable.
 544                if event_consumed && mouse_event.is_capturable() {
 545                    break;
 546                }
 547            }
 548        }
 549
 550        for view_id in notified_views {
 551            cx.notify_view(self.window_id, view_id);
 552        }
 553
 554        any_event_handled
 555    }
 556
 557    pub fn build_event_context<'a>(
 558        &'a mut self,
 559        notified_views: &'a mut HashSet<usize>,
 560        cx: &'a mut MutableAppContext,
 561    ) -> EventContext<'a> {
 562        EventContext {
 563            font_cache: &self.font_cache,
 564            text_layout_cache: &self.text_layout_cache,
 565            view_stack: Default::default(),
 566            notified_views,
 567            notify_count: 0,
 568            handled: false,
 569            window_id: self.window_id,
 570            app: cx,
 571        }
 572    }
 573
 574    pub fn debug_elements(&self, cx: &AppContext) -> Option<json::Value> {
 575        let view = cx.root_view(self.window_id)?;
 576        Some(json!({
 577            "root_view": view.debug_json(cx),
 578            "root_element": self.rendered_views.get(&view.id())
 579                .map(|root_element| {
 580                    root_element.debug(&DebugContext {
 581                        rendered_views: &self.rendered_views,
 582                        font_cache: &self.font_cache,
 583                        app: cx,
 584                    })
 585                })
 586        }))
 587    }
 588}
 589
 590pub struct LayoutContext<'a> {
 591    window_id: usize,
 592    rendered_views: &'a mut HashMap<usize, ElementBox>,
 593    view_stack: Vec<usize>,
 594    pub font_cache: &'a Arc<FontCache>,
 595    pub font_system: Arc<dyn FontSystem>,
 596    pub text_layout_cache: &'a TextLayoutCache,
 597    pub asset_cache: &'a AssetCache,
 598    pub app: &'a mut MutableAppContext,
 599    pub refreshing: bool,
 600    pub window_size: Vector2F,
 601    titlebar_height: f32,
 602    appearance: Appearance,
 603    hovered_region_ids: HashSet<MouseRegionId>,
 604    clicked_region_ids: Option<(HashSet<MouseRegionId>, MouseButton)>,
 605}
 606
 607impl<'a> LayoutContext<'a> {
 608    fn layout(&mut self, view_id: usize, constraint: SizeConstraint) -> Vector2F {
 609        let print_error = |view_id| {
 610            format!(
 611                "{} with id {}",
 612                self.app.name_for_view(self.window_id, view_id).unwrap(),
 613                view_id,
 614            )
 615        };
 616        match (
 617            self.view_stack.last(),
 618            self.app.parents.get(&(self.window_id, view_id)),
 619        ) {
 620            (Some(layout_parent), Some(ParentId::View(app_parent))) => {
 621                if layout_parent != app_parent {
 622                    panic!(
 623                        "View {} was laid out with parent {} when it was constructed with parent {}", 
 624                        print_error(view_id),
 625                        print_error(*layout_parent),
 626                        print_error(*app_parent))
 627                }
 628            }
 629            (None, Some(ParentId::View(app_parent))) => panic!(
 630                "View {} was laid out without a parent when it was constructed with parent {}",
 631                print_error(view_id),
 632                print_error(*app_parent)
 633            ),
 634            (Some(layout_parent), Some(ParentId::Root)) => panic!(
 635                "View {} was laid out with parent {} when it was constructed as a window root",
 636                print_error(view_id),
 637                print_error(*layout_parent),
 638            ),
 639            (_, None) => panic!(
 640                "View {} did not have a registered parent in the app context",
 641                print_error(view_id),
 642            ),
 643            _ => {}
 644        }
 645
 646        self.view_stack.push(view_id);
 647        let mut rendered_view = self.rendered_views.remove(&view_id).unwrap();
 648        let size = rendered_view.layout(constraint, self);
 649        self.rendered_views.insert(view_id, rendered_view);
 650        self.view_stack.pop();
 651        size
 652    }
 653
 654    pub fn render<F, V, T>(&mut self, handle: &ViewHandle<V>, f: F) -> T
 655    where
 656        F: FnOnce(&mut V, &mut RenderContext<V>) -> T,
 657        V: View,
 658    {
 659        handle.update(self.app, |view, cx| {
 660            let mut render_cx = RenderContext {
 661                app: cx,
 662                window_id: handle.window_id(),
 663                view_id: handle.id(),
 664                view_type: PhantomData,
 665                titlebar_height: self.titlebar_height,
 666                hovered_region_ids: self.hovered_region_ids.clone(),
 667                clicked_region_ids: self.clicked_region_ids.clone(),
 668                refreshing: self.refreshing,
 669                appearance: self.appearance,
 670            };
 671            f(view, &mut render_cx)
 672        })
 673    }
 674}
 675
 676impl<'a> Deref for LayoutContext<'a> {
 677    type Target = MutableAppContext;
 678
 679    fn deref(&self) -> &Self::Target {
 680        self.app
 681    }
 682}
 683
 684impl<'a> DerefMut for LayoutContext<'a> {
 685    fn deref_mut(&mut self) -> &mut Self::Target {
 686        self.app
 687    }
 688}
 689
 690impl<'a> ReadView for LayoutContext<'a> {
 691    fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
 692        self.app.read_view(handle)
 693    }
 694}
 695
 696impl<'a> ReadModel for LayoutContext<'a> {
 697    fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
 698        self.app.read_model(handle)
 699    }
 700}
 701
 702impl<'a> UpgradeModelHandle for LayoutContext<'a> {
 703    fn upgrade_model_handle<T: Entity>(
 704        &self,
 705        handle: &WeakModelHandle<T>,
 706    ) -> Option<ModelHandle<T>> {
 707        self.app.upgrade_model_handle(handle)
 708    }
 709
 710    fn model_handle_is_upgradable<T: Entity>(&self, handle: &WeakModelHandle<T>) -> bool {
 711        self.app.model_handle_is_upgradable(handle)
 712    }
 713
 714    fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option<AnyModelHandle> {
 715        self.app.upgrade_any_model_handle(handle)
 716    }
 717}
 718
 719impl<'a> UpgradeViewHandle for LayoutContext<'a> {
 720    fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>> {
 721        self.app.upgrade_view_handle(handle)
 722    }
 723
 724    fn upgrade_any_view_handle(&self, handle: &crate::AnyWeakViewHandle) -> Option<AnyViewHandle> {
 725        self.app.upgrade_any_view_handle(handle)
 726    }
 727}
 728
 729pub struct PaintContext<'a> {
 730    rendered_views: &'a mut HashMap<usize, ElementBox>,
 731    view_stack: Vec<usize>,
 732    pub window_size: Vector2F,
 733    pub scene: &'a mut SceneBuilder,
 734    pub font_cache: &'a FontCache,
 735    pub text_layout_cache: &'a TextLayoutCache,
 736    pub app: &'a AppContext,
 737}
 738
 739impl<'a> PaintContext<'a> {
 740    fn paint(&mut self, view_id: usize, origin: Vector2F, visible_bounds: RectF) {
 741        if let Some(mut tree) = self.rendered_views.remove(&view_id) {
 742            self.view_stack.push(view_id);
 743            tree.paint(origin, visible_bounds, self);
 744            self.rendered_views.insert(view_id, tree);
 745            self.view_stack.pop();
 746        }
 747    }
 748
 749    #[inline]
 750    pub fn paint_stacking_context<F>(
 751        &mut self,
 752        clip_bounds: Option<RectF>,
 753        z_index: Option<usize>,
 754        f: F,
 755    ) where
 756        F: FnOnce(&mut Self),
 757    {
 758        self.scene.push_stacking_context(clip_bounds, z_index);
 759        f(self);
 760        self.scene.pop_stacking_context();
 761    }
 762
 763    #[inline]
 764    pub fn paint_layer<F>(&mut self, clip_bounds: Option<RectF>, f: F)
 765    where
 766        F: FnOnce(&mut Self),
 767    {
 768        self.scene.push_layer(clip_bounds);
 769        f(self);
 770        self.scene.pop_layer();
 771    }
 772
 773    pub fn current_view_id(&self) -> usize {
 774        *self.view_stack.last().unwrap()
 775    }
 776}
 777
 778impl<'a> Deref for PaintContext<'a> {
 779    type Target = AppContext;
 780
 781    fn deref(&self) -> &Self::Target {
 782        self.app
 783    }
 784}
 785
 786pub struct EventContext<'a> {
 787    pub font_cache: &'a FontCache,
 788    pub text_layout_cache: &'a TextLayoutCache,
 789    pub app: &'a mut MutableAppContext,
 790    pub window_id: usize,
 791    pub notify_count: usize,
 792    view_stack: Vec<usize>,
 793    handled: bool,
 794    notified_views: &'a mut HashSet<usize>,
 795}
 796
 797impl<'a> EventContext<'a> {
 798    fn with_current_view<F, T>(&mut self, view_id: usize, f: F) -> T
 799    where
 800        F: FnOnce(&mut Self) -> T,
 801    {
 802        self.view_stack.push(view_id);
 803        let result = f(self);
 804        self.view_stack.pop();
 805        result
 806    }
 807
 808    pub fn window_id(&self) -> usize {
 809        self.window_id
 810    }
 811
 812    pub fn view_id(&self) -> Option<usize> {
 813        self.view_stack.last().copied()
 814    }
 815
 816    pub fn is_parent_view_focused(&self) -> bool {
 817        if let Some(parent_view_id) = self.view_stack.last() {
 818            self.app.focused_view_id(self.window_id) == Some(*parent_view_id)
 819        } else {
 820            false
 821        }
 822    }
 823
 824    pub fn focus_parent_view(&mut self) {
 825        if let Some(parent_view_id) = self.view_stack.last() {
 826            self.app.focus(self.window_id, Some(*parent_view_id))
 827        }
 828    }
 829
 830    pub fn dispatch_any_action(&mut self, action: Box<dyn Action>) {
 831        self.app
 832            .dispatch_any_action_at(self.window_id, *self.view_stack.last().unwrap(), action)
 833    }
 834
 835    pub fn dispatch_action<A: Action>(&mut self, action: A) {
 836        self.dispatch_any_action(Box::new(action));
 837    }
 838
 839    pub fn notify(&mut self) {
 840        self.notify_count += 1;
 841        if let Some(view_id) = self.view_stack.last() {
 842            self.notified_views.insert(*view_id);
 843        }
 844    }
 845
 846    pub fn notify_count(&self) -> usize {
 847        self.notify_count
 848    }
 849
 850    pub fn propagate_event(&mut self) {
 851        self.handled = false;
 852    }
 853}
 854
 855impl<'a> Deref for EventContext<'a> {
 856    type Target = MutableAppContext;
 857
 858    fn deref(&self) -> &Self::Target {
 859        self.app
 860    }
 861}
 862
 863impl<'a> DerefMut for EventContext<'a> {
 864    fn deref_mut(&mut self) -> &mut Self::Target {
 865        self.app
 866    }
 867}
 868
 869pub struct MeasurementContext<'a> {
 870    app: &'a AppContext,
 871    rendered_views: &'a HashMap<usize, ElementBox>,
 872    pub window_id: usize,
 873}
 874
 875impl<'a> Deref for MeasurementContext<'a> {
 876    type Target = AppContext;
 877
 878    fn deref(&self) -> &Self::Target {
 879        self.app
 880    }
 881}
 882
 883impl<'a> MeasurementContext<'a> {
 884    fn rect_for_text_range(&self, view_id: usize, range_utf16: Range<usize>) -> Option<RectF> {
 885        let element = self.rendered_views.get(&view_id)?;
 886        element.rect_for_text_range(range_utf16, self)
 887    }
 888}
 889
 890pub struct DebugContext<'a> {
 891    rendered_views: &'a HashMap<usize, ElementBox>,
 892    pub font_cache: &'a FontCache,
 893    pub app: &'a AppContext,
 894}
 895
 896#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
 897pub enum Axis {
 898    #[default]
 899    Horizontal,
 900    Vertical,
 901}
 902
 903impl Axis {
 904    pub fn invert(self) -> Self {
 905        match self {
 906            Self::Horizontal => Self::Vertical,
 907            Self::Vertical => Self::Horizontal,
 908        }
 909    }
 910
 911    pub fn component(&self, point: Vector2F) -> f32 {
 912        match self {
 913            Self::Horizontal => point.x(),
 914            Self::Vertical => point.y(),
 915        }
 916    }
 917}
 918
 919impl ToJson for Axis {
 920    fn to_json(&self) -> serde_json::Value {
 921        match self {
 922            Axis::Horizontal => json!("horizontal"),
 923            Axis::Vertical => json!("vertical"),
 924        }
 925    }
 926}
 927
 928impl StaticColumnCount for Axis {}
 929impl Bind for Axis {
 930    fn bind(&self, statement: &Statement, start_index: i32) -> anyhow::Result<i32> {
 931        match self {
 932            Axis::Horizontal => "Horizontal",
 933            Axis::Vertical => "Vertical",
 934        }
 935        .bind(statement, start_index)
 936    }
 937}
 938
 939impl Column for Axis {
 940    fn column(statement: &mut Statement, start_index: i32) -> anyhow::Result<(Self, i32)> {
 941        String::column(statement, start_index).and_then(|(axis_text, next_index)| {
 942            Ok((
 943                match axis_text.as_str() {
 944                    "Horizontal" => Axis::Horizontal,
 945                    "Vertical" => Axis::Vertical,
 946                    _ => bail!("Stored serialized item kind is incorrect"),
 947                },
 948                next_index,
 949            ))
 950        })
 951    }
 952}
 953
 954pub trait Vector2FExt {
 955    fn along(self, axis: Axis) -> f32;
 956}
 957
 958impl Vector2FExt for Vector2F {
 959    fn along(self, axis: Axis) -> f32 {
 960        match axis {
 961            Axis::Horizontal => self.x(),
 962            Axis::Vertical => self.y(),
 963        }
 964    }
 965}
 966
 967#[derive(Copy, Clone, Debug)]
 968pub struct SizeConstraint {
 969    pub min: Vector2F,
 970    pub max: Vector2F,
 971}
 972
 973impl SizeConstraint {
 974    pub fn new(min: Vector2F, max: Vector2F) -> Self {
 975        Self { min, max }
 976    }
 977
 978    pub fn strict(size: Vector2F) -> Self {
 979        Self {
 980            min: size,
 981            max: size,
 982        }
 983    }
 984
 985    pub fn strict_along(axis: Axis, max: f32) -> Self {
 986        match axis {
 987            Axis::Horizontal => Self {
 988                min: vec2f(max, 0.0),
 989                max: vec2f(max, f32::INFINITY),
 990            },
 991            Axis::Vertical => Self {
 992                min: vec2f(0.0, max),
 993                max: vec2f(f32::INFINITY, max),
 994            },
 995        }
 996    }
 997
 998    pub fn max_along(&self, axis: Axis) -> f32 {
 999        match axis {
1000            Axis::Horizontal => self.max.x(),
1001            Axis::Vertical => self.max.y(),
1002        }
1003    }
1004
1005    pub fn min_along(&self, axis: Axis) -> f32 {
1006        match axis {
1007            Axis::Horizontal => self.min.x(),
1008            Axis::Vertical => self.min.y(),
1009        }
1010    }
1011
1012    pub fn constrain(&self, size: Vector2F) -> Vector2F {
1013        vec2f(
1014            size.x().min(self.max.x()).max(self.min.x()),
1015            size.y().min(self.max.y()).max(self.min.y()),
1016        )
1017    }
1018}
1019
1020impl Default for SizeConstraint {
1021    fn default() -> Self {
1022        SizeConstraint {
1023            min: Vector2F::zero(),
1024            max: Vector2F::splat(f32::INFINITY),
1025        }
1026    }
1027}
1028
1029impl ToJson for SizeConstraint {
1030    fn to_json(&self) -> serde_json::Value {
1031        json!({
1032            "min": self.min.to_json(),
1033            "max": self.max.to_json(),
1034        })
1035    }
1036}
1037
1038pub struct ChildView {
1039    view: AnyWeakViewHandle,
1040    view_name: &'static str,
1041}
1042
1043impl ChildView {
1044    pub fn new(view: impl Into<AnyViewHandle>, cx: &AppContext) -> Self {
1045        let view = view.into();
1046        let view_name = cx.view_ui_name(view.window_id(), view.id()).unwrap();
1047        Self {
1048            view: view.downgrade(),
1049            view_name,
1050        }
1051    }
1052}
1053
1054impl Element for ChildView {
1055    type LayoutState = bool;
1056    type PaintState = ();
1057
1058    fn layout(
1059        &mut self,
1060        constraint: SizeConstraint,
1061        cx: &mut LayoutContext,
1062    ) -> (Vector2F, Self::LayoutState) {
1063        if cx.rendered_views.contains_key(&self.view.id()) {
1064            let size = cx.layout(self.view.id(), constraint);
1065            (size, true)
1066        } else {
1067            log::error!(
1068                "layout called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
1069                self.view.id(),
1070                self.view_name
1071            );
1072            (Vector2F::zero(), false)
1073        }
1074    }
1075
1076    fn paint(
1077        &mut self,
1078        bounds: RectF,
1079        visible_bounds: RectF,
1080        view_is_valid: &mut Self::LayoutState,
1081        cx: &mut PaintContext,
1082    ) {
1083        if *view_is_valid {
1084            cx.paint(self.view.id(), bounds.origin(), visible_bounds);
1085        } else {
1086            log::error!(
1087                "paint called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
1088                self.view.id(),
1089                self.view_name
1090            );
1091        }
1092    }
1093
1094    fn rect_for_text_range(
1095        &self,
1096        range_utf16: Range<usize>,
1097        _: RectF,
1098        _: RectF,
1099        view_is_valid: &Self::LayoutState,
1100        _: &Self::PaintState,
1101        cx: &MeasurementContext,
1102    ) -> Option<RectF> {
1103        if *view_is_valid {
1104            cx.rect_for_text_range(self.view.id(), range_utf16)
1105        } else {
1106            log::error!(
1107                "rect_for_text_range called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
1108                self.view.id(),
1109                self.view_name
1110            );
1111            None
1112        }
1113    }
1114
1115    fn debug(
1116        &self,
1117        bounds: RectF,
1118        _: &Self::LayoutState,
1119        _: &Self::PaintState,
1120        cx: &DebugContext,
1121    ) -> serde_json::Value {
1122        json!({
1123            "type": "ChildView",
1124            "view_id": self.view.id(),
1125            "bounds": bounds.to_json(),
1126            "view": if let Some(view) = self.view.upgrade(cx.app) {
1127                view.debug_json(cx.app)
1128            } else {
1129                json!(null)
1130            },
1131            "child": if let Some(view) = cx.rendered_views.get(&self.view.id()) {
1132                view.debug(cx)
1133            } else {
1134                json!(null)
1135            }
1136        })
1137    }
1138}