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