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 that calls cx.propogate_event
 511                if let MouseEvent::Down(e) = &mouse_event {
 512                    if valid_region
 513                        .handlers
 514                        .contains(MouseEvent::click_disc(), Some(e.button))
 515                        || valid_region
 516                            .handlers
 517                            .contains(MouseEvent::drag_disc(), Some(e.button))
 518                    {
 519                        event_cx.handled = true;
 520                    }
 521                }
 522
 523                // `event_consumed` should only be true if there are any handlers for this event.
 524                let mut event_consumed = event_cx.handled;
 525                if let Some(callbacks) = valid_region.handlers.get(&mouse_event.handler_key()) {
 526                    event_consumed = true;
 527                    for callback in callbacks {
 528                        event_cx.handled = true;
 529                        event_cx.with_current_view(valid_region.id().view_id(), {
 530                            let region_event = mouse_event.clone();
 531                            |cx| callback(region_event, cx)
 532                        });
 533                        event_consumed &= event_cx.handled;
 534                        any_event_handled |= event_cx.handled;
 535                    }
 536                }
 537
 538                any_event_handled |= event_cx.handled;
 539
 540                // For bubbling events, if the event was handled, don't continue dispatching.
 541                // This only makes sense for local events which return false from is_capturable.
 542                if event_consumed && mouse_event.is_capturable() {
 543                    break;
 544                }
 545            }
 546        }
 547
 548        for view_id in notified_views {
 549            cx.notify_view(self.window_id, view_id);
 550        }
 551
 552        any_event_handled
 553    }
 554
 555    pub fn build_event_context<'a>(
 556        &'a mut self,
 557        notified_views: &'a mut HashSet<usize>,
 558        cx: &'a mut MutableAppContext,
 559    ) -> EventContext<'a> {
 560        EventContext {
 561            font_cache: &self.font_cache,
 562            text_layout_cache: &self.text_layout_cache,
 563            view_stack: Default::default(),
 564            notified_views,
 565            notify_count: 0,
 566            handled: false,
 567            window_id: self.window_id,
 568            app: cx,
 569        }
 570    }
 571
 572    pub fn debug_elements(&self, cx: &AppContext) -> Option<json::Value> {
 573        let view = cx.root_view(self.window_id)?;
 574        Some(json!({
 575            "root_view": view.debug_json(cx),
 576            "root_element": self.rendered_views.get(&view.id())
 577                .map(|root_element| {
 578                    root_element.debug(&DebugContext {
 579                        rendered_views: &self.rendered_views,
 580                        font_cache: &self.font_cache,
 581                        app: cx,
 582                    })
 583                })
 584        }))
 585    }
 586}
 587
 588pub struct LayoutContext<'a> {
 589    window_id: usize,
 590    rendered_views: &'a mut HashMap<usize, ElementBox>,
 591    view_stack: Vec<usize>,
 592    pub font_cache: &'a Arc<FontCache>,
 593    pub font_system: Arc<dyn FontSystem>,
 594    pub text_layout_cache: &'a TextLayoutCache,
 595    pub asset_cache: &'a AssetCache,
 596    pub app: &'a mut MutableAppContext,
 597    pub refreshing: bool,
 598    pub window_size: Vector2F,
 599    titlebar_height: f32,
 600    appearance: Appearance,
 601    hovered_region_ids: HashSet<MouseRegionId>,
 602    clicked_region_ids: Option<(HashSet<MouseRegionId>, MouseButton)>,
 603}
 604
 605impl<'a> LayoutContext<'a> {
 606    fn layout(&mut self, view_id: usize, constraint: SizeConstraint) -> Vector2F {
 607        let print_error = |view_id| {
 608            format!(
 609                "{} with id {}",
 610                self.app.name_for_view(self.window_id, view_id).unwrap(),
 611                view_id,
 612            )
 613        };
 614        match (
 615            self.view_stack.last(),
 616            self.app.parents.get(&(self.window_id, view_id)),
 617        ) {
 618            (Some(layout_parent), Some(ParentId::View(app_parent))) => {
 619                if layout_parent != app_parent {
 620                    panic!(
 621                        "View {} was laid out with parent {} when it was constructed with parent {}", 
 622                        print_error(view_id),
 623                        print_error(*layout_parent),
 624                        print_error(*app_parent))
 625                }
 626            }
 627            (None, Some(ParentId::View(app_parent))) => panic!(
 628                "View {} was laid out without a parent when it was constructed with parent {}",
 629                print_error(view_id),
 630                print_error(*app_parent)
 631            ),
 632            (Some(layout_parent), Some(ParentId::Root)) => panic!(
 633                "View {} was laid out with parent {} when it was constructed as a window root",
 634                print_error(view_id),
 635                print_error(*layout_parent),
 636            ),
 637            (_, None) => panic!(
 638                "View {} did not have a registered parent in the app context",
 639                print_error(view_id),
 640            ),
 641            _ => {}
 642        }
 643
 644        self.view_stack.push(view_id);
 645        let mut rendered_view = self.rendered_views.remove(&view_id).unwrap();
 646        let size = rendered_view.layout(constraint, self);
 647        self.rendered_views.insert(view_id, rendered_view);
 648        self.view_stack.pop();
 649        size
 650    }
 651
 652    pub fn render<F, V, T>(&mut self, handle: &ViewHandle<V>, f: F) -> T
 653    where
 654        F: FnOnce(&mut V, &mut RenderContext<V>) -> T,
 655        V: View,
 656    {
 657        handle.update(self.app, |view, cx| {
 658            let mut render_cx = RenderContext {
 659                app: cx,
 660                window_id: handle.window_id(),
 661                view_id: handle.id(),
 662                view_type: PhantomData,
 663                titlebar_height: self.titlebar_height,
 664                hovered_region_ids: self.hovered_region_ids.clone(),
 665                clicked_region_ids: self.clicked_region_ids.clone(),
 666                refreshing: self.refreshing,
 667                appearance: self.appearance,
 668            };
 669            f(view, &mut render_cx)
 670        })
 671    }
 672}
 673
 674impl<'a> Deref for LayoutContext<'a> {
 675    type Target = MutableAppContext;
 676
 677    fn deref(&self) -> &Self::Target {
 678        self.app
 679    }
 680}
 681
 682impl<'a> DerefMut for LayoutContext<'a> {
 683    fn deref_mut(&mut self) -> &mut Self::Target {
 684        self.app
 685    }
 686}
 687
 688impl<'a> ReadView for LayoutContext<'a> {
 689    fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
 690        self.app.read_view(handle)
 691    }
 692}
 693
 694impl<'a> ReadModel for LayoutContext<'a> {
 695    fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
 696        self.app.read_model(handle)
 697    }
 698}
 699
 700impl<'a> UpgradeModelHandle for LayoutContext<'a> {
 701    fn upgrade_model_handle<T: Entity>(
 702        &self,
 703        handle: &WeakModelHandle<T>,
 704    ) -> Option<ModelHandle<T>> {
 705        self.app.upgrade_model_handle(handle)
 706    }
 707
 708    fn model_handle_is_upgradable<T: Entity>(&self, handle: &WeakModelHandle<T>) -> bool {
 709        self.app.model_handle_is_upgradable(handle)
 710    }
 711
 712    fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option<AnyModelHandle> {
 713        self.app.upgrade_any_model_handle(handle)
 714    }
 715}
 716
 717impl<'a> UpgradeViewHandle for LayoutContext<'a> {
 718    fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>> {
 719        self.app.upgrade_view_handle(handle)
 720    }
 721
 722    fn upgrade_any_view_handle(&self, handle: &crate::AnyWeakViewHandle) -> Option<AnyViewHandle> {
 723        self.app.upgrade_any_view_handle(handle)
 724    }
 725}
 726
 727pub struct PaintContext<'a> {
 728    rendered_views: &'a mut HashMap<usize, ElementBox>,
 729    view_stack: Vec<usize>,
 730    pub window_size: Vector2F,
 731    pub scene: &'a mut SceneBuilder,
 732    pub font_cache: &'a FontCache,
 733    pub text_layout_cache: &'a TextLayoutCache,
 734    pub app: &'a AppContext,
 735}
 736
 737impl<'a> PaintContext<'a> {
 738    fn paint(&mut self, view_id: usize, origin: Vector2F, visible_bounds: RectF) {
 739        if let Some(mut tree) = self.rendered_views.remove(&view_id) {
 740            self.view_stack.push(view_id);
 741            tree.paint(origin, visible_bounds, self);
 742            self.rendered_views.insert(view_id, tree);
 743            self.view_stack.pop();
 744        }
 745    }
 746
 747    #[inline]
 748    pub fn paint_stacking_context<F>(
 749        &mut self,
 750        clip_bounds: Option<RectF>,
 751        z_index: Option<usize>,
 752        f: F,
 753    ) where
 754        F: FnOnce(&mut Self),
 755    {
 756        self.scene.push_stacking_context(clip_bounds, z_index);
 757        f(self);
 758        self.scene.pop_stacking_context();
 759    }
 760
 761    #[inline]
 762    pub fn paint_layer<F>(&mut self, clip_bounds: Option<RectF>, f: F)
 763    where
 764        F: FnOnce(&mut Self),
 765    {
 766        self.scene.push_layer(clip_bounds);
 767        f(self);
 768        self.scene.pop_layer();
 769    }
 770
 771    pub fn current_view_id(&self) -> usize {
 772        *self.view_stack.last().unwrap()
 773    }
 774}
 775
 776impl<'a> Deref for PaintContext<'a> {
 777    type Target = AppContext;
 778
 779    fn deref(&self) -> &Self::Target {
 780        self.app
 781    }
 782}
 783
 784pub struct EventContext<'a> {
 785    pub font_cache: &'a FontCache,
 786    pub text_layout_cache: &'a TextLayoutCache,
 787    pub app: &'a mut MutableAppContext,
 788    pub window_id: usize,
 789    pub notify_count: usize,
 790    view_stack: Vec<usize>,
 791    handled: bool,
 792    notified_views: &'a mut HashSet<usize>,
 793}
 794
 795impl<'a> EventContext<'a> {
 796    fn with_current_view<F, T>(&mut self, view_id: usize, f: F) -> T
 797    where
 798        F: FnOnce(&mut Self) -> T,
 799    {
 800        self.view_stack.push(view_id);
 801        let result = f(self);
 802        self.view_stack.pop();
 803        result
 804    }
 805
 806    pub fn window_id(&self) -> usize {
 807        self.window_id
 808    }
 809
 810    pub fn view_id(&self) -> Option<usize> {
 811        self.view_stack.last().copied()
 812    }
 813
 814    pub fn is_parent_view_focused(&self) -> bool {
 815        if let Some(parent_view_id) = self.view_stack.last() {
 816            self.app.focused_view_id(self.window_id) == Some(*parent_view_id)
 817        } else {
 818            false
 819        }
 820    }
 821
 822    pub fn focus_parent_view(&mut self) {
 823        if let Some(parent_view_id) = self.view_stack.last() {
 824            self.app.focus(self.window_id, Some(*parent_view_id))
 825        }
 826    }
 827
 828    pub fn dispatch_any_action(&mut self, action: Box<dyn Action>) {
 829        self.app
 830            .dispatch_any_action_at(self.window_id, *self.view_stack.last().unwrap(), action)
 831    }
 832
 833    pub fn dispatch_action<A: Action>(&mut self, action: A) {
 834        self.dispatch_any_action(Box::new(action));
 835    }
 836
 837    pub fn notify(&mut self) {
 838        self.notify_count += 1;
 839        if let Some(view_id) = self.view_stack.last() {
 840            self.notified_views.insert(*view_id);
 841        }
 842    }
 843
 844    pub fn notify_count(&self) -> usize {
 845        self.notify_count
 846    }
 847
 848    pub fn propagate_event(&mut self) {
 849        self.handled = false;
 850    }
 851}
 852
 853impl<'a> Deref for EventContext<'a> {
 854    type Target = MutableAppContext;
 855
 856    fn deref(&self) -> &Self::Target {
 857        self.app
 858    }
 859}
 860
 861impl<'a> DerefMut for EventContext<'a> {
 862    fn deref_mut(&mut self) -> &mut Self::Target {
 863        self.app
 864    }
 865}
 866
 867pub struct MeasurementContext<'a> {
 868    app: &'a AppContext,
 869    rendered_views: &'a HashMap<usize, ElementBox>,
 870    pub window_id: usize,
 871}
 872
 873impl<'a> Deref for MeasurementContext<'a> {
 874    type Target = AppContext;
 875
 876    fn deref(&self) -> &Self::Target {
 877        self.app
 878    }
 879}
 880
 881impl<'a> MeasurementContext<'a> {
 882    fn rect_for_text_range(&self, view_id: usize, range_utf16: Range<usize>) -> Option<RectF> {
 883        let element = self.rendered_views.get(&view_id)?;
 884        element.rect_for_text_range(range_utf16, self)
 885    }
 886}
 887
 888pub struct DebugContext<'a> {
 889    rendered_views: &'a HashMap<usize, ElementBox>,
 890    pub font_cache: &'a FontCache,
 891    pub app: &'a AppContext,
 892}
 893
 894#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
 895pub enum Axis {
 896    #[default]
 897    Horizontal,
 898    Vertical,
 899}
 900
 901impl Axis {
 902    pub fn invert(self) -> Self {
 903        match self {
 904            Self::Horizontal => Self::Vertical,
 905            Self::Vertical => Self::Horizontal,
 906        }
 907    }
 908
 909    pub fn component(&self, point: Vector2F) -> f32 {
 910        match self {
 911            Self::Horizontal => point.x(),
 912            Self::Vertical => point.y(),
 913        }
 914    }
 915}
 916
 917impl ToJson for Axis {
 918    fn to_json(&self) -> serde_json::Value {
 919        match self {
 920            Axis::Horizontal => json!("horizontal"),
 921            Axis::Vertical => json!("vertical"),
 922        }
 923    }
 924}
 925
 926impl StaticColumnCount for Axis {}
 927impl Bind for Axis {
 928    fn bind(&self, statement: &Statement, start_index: i32) -> anyhow::Result<i32> {
 929        match self {
 930            Axis::Horizontal => "Horizontal",
 931            Axis::Vertical => "Vertical",
 932        }
 933        .bind(statement, start_index)
 934    }
 935}
 936
 937impl Column for Axis {
 938    fn column(statement: &mut Statement, start_index: i32) -> anyhow::Result<(Self, i32)> {
 939        String::column(statement, start_index).and_then(|(axis_text, next_index)| {
 940            Ok((
 941                match axis_text.as_str() {
 942                    "Horizontal" => Axis::Horizontal,
 943                    "Vertical" => Axis::Vertical,
 944                    _ => bail!("Stored serialized item kind is incorrect"),
 945                },
 946                next_index,
 947            ))
 948        })
 949    }
 950}
 951
 952pub trait Vector2FExt {
 953    fn along(self, axis: Axis) -> f32;
 954}
 955
 956impl Vector2FExt for Vector2F {
 957    fn along(self, axis: Axis) -> f32 {
 958        match axis {
 959            Axis::Horizontal => self.x(),
 960            Axis::Vertical => self.y(),
 961        }
 962    }
 963}
 964
 965#[derive(Copy, Clone, Debug)]
 966pub struct SizeConstraint {
 967    pub min: Vector2F,
 968    pub max: Vector2F,
 969}
 970
 971impl SizeConstraint {
 972    pub fn new(min: Vector2F, max: Vector2F) -> Self {
 973        Self { min, max }
 974    }
 975
 976    pub fn strict(size: Vector2F) -> Self {
 977        Self {
 978            min: size,
 979            max: size,
 980        }
 981    }
 982
 983    pub fn strict_along(axis: Axis, max: f32) -> Self {
 984        match axis {
 985            Axis::Horizontal => Self {
 986                min: vec2f(max, 0.0),
 987                max: vec2f(max, f32::INFINITY),
 988            },
 989            Axis::Vertical => Self {
 990                min: vec2f(0.0, max),
 991                max: vec2f(f32::INFINITY, max),
 992            },
 993        }
 994    }
 995
 996    pub fn max_along(&self, axis: Axis) -> f32 {
 997        match axis {
 998            Axis::Horizontal => self.max.x(),
 999            Axis::Vertical => self.max.y(),
1000        }
1001    }
1002
1003    pub fn min_along(&self, axis: Axis) -> f32 {
1004        match axis {
1005            Axis::Horizontal => self.min.x(),
1006            Axis::Vertical => self.min.y(),
1007        }
1008    }
1009
1010    pub fn constrain(&self, size: Vector2F) -> Vector2F {
1011        vec2f(
1012            size.x().min(self.max.x()).max(self.min.x()),
1013            size.y().min(self.max.y()).max(self.min.y()),
1014        )
1015    }
1016}
1017
1018impl Default for SizeConstraint {
1019    fn default() -> Self {
1020        SizeConstraint {
1021            min: Vector2F::zero(),
1022            max: Vector2F::splat(f32::INFINITY),
1023        }
1024    }
1025}
1026
1027impl ToJson for SizeConstraint {
1028    fn to_json(&self) -> serde_json::Value {
1029        json!({
1030            "min": self.min.to_json(),
1031            "max": self.max.to_json(),
1032        })
1033    }
1034}
1035
1036pub struct ChildView {
1037    view: AnyWeakViewHandle,
1038    view_name: &'static str,
1039}
1040
1041impl ChildView {
1042    pub fn new(view: impl Into<AnyViewHandle>, cx: &AppContext) -> Self {
1043        let view = view.into();
1044        let view_name = cx.view_ui_name(view.window_id(), view.id()).unwrap();
1045        Self {
1046            view: view.downgrade(),
1047            view_name,
1048        }
1049    }
1050}
1051
1052impl Element for ChildView {
1053    type LayoutState = bool;
1054    type PaintState = ();
1055
1056    fn layout(
1057        &mut self,
1058        constraint: SizeConstraint,
1059        cx: &mut LayoutContext,
1060    ) -> (Vector2F, Self::LayoutState) {
1061        if cx.rendered_views.contains_key(&self.view.id()) {
1062            let size = cx.layout(self.view.id(), constraint);
1063            (size, true)
1064        } else {
1065            log::error!(
1066                "layout called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
1067                self.view.id(),
1068                self.view_name
1069            );
1070            (Vector2F::zero(), false)
1071        }
1072    }
1073
1074    fn paint(
1075        &mut self,
1076        bounds: RectF,
1077        visible_bounds: RectF,
1078        view_is_valid: &mut Self::LayoutState,
1079        cx: &mut PaintContext,
1080    ) {
1081        if *view_is_valid {
1082            cx.paint(self.view.id(), bounds.origin(), visible_bounds);
1083        } else {
1084            log::error!(
1085                "paint called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
1086                self.view.id(),
1087                self.view_name
1088            );
1089        }
1090    }
1091
1092    fn rect_for_text_range(
1093        &self,
1094        range_utf16: Range<usize>,
1095        _: RectF,
1096        _: RectF,
1097        view_is_valid: &Self::LayoutState,
1098        _: &Self::PaintState,
1099        cx: &MeasurementContext,
1100    ) -> Option<RectF> {
1101        if *view_is_valid {
1102            cx.rect_for_text_range(self.view.id(), range_utf16)
1103        } else {
1104            log::error!(
1105                "rect_for_text_range called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
1106                self.view.id(),
1107                self.view_name
1108            );
1109            None
1110        }
1111    }
1112
1113    fn debug(
1114        &self,
1115        bounds: RectF,
1116        _: &Self::LayoutState,
1117        _: &Self::PaintState,
1118        cx: &DebugContext,
1119    ) -> serde_json::Value {
1120        json!({
1121            "type": "ChildView",
1122            "view_id": self.view.id(),
1123            "bounds": bounds.to_json(),
1124            "view": if let Some(view) = self.view.upgrade(cx.app) {
1125                view.debug_json(cx.app)
1126            } else {
1127                json!(null)
1128            },
1129            "child": if let Some(view) = cx.rendered_views.get(&self.view.id()) {
1130                view.debug(cx)
1131            } else {
1132                json!(null)
1133            }
1134        })
1135    }
1136}