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    keymap::Keystroke,
   8    platform::{CursorStyle, Event},
   9    scene::CursorRegion,
  10    text_layout::TextLayoutCache,
  11    Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AssetCache, ElementBox, Entity,
  12    FontSystem, ModelHandle, MouseButton, MouseEvent, MouseMovedEvent, MouseRegion, MouseRegionId,
  13    ReadModel, ReadView, RenderContext, RenderParams, Scene, UpgradeModelHandle, UpgradeViewHandle,
  14    View, ViewHandle, WeakModelHandle, WeakViewHandle,
  15};
  16use pathfinder_geometry::vector::{vec2f, Vector2F};
  17use serde_json::json;
  18use smallvec::SmallVec;
  19use std::{
  20    collections::{HashMap, HashSet},
  21    marker::PhantomData,
  22    ops::{Deref, DerefMut, Range},
  23    sync::Arc,
  24};
  25
  26pub struct Presenter {
  27    window_id: usize,
  28    pub(crate) rendered_views: HashMap<usize, ElementBox>,
  29    parents: HashMap<usize, usize>,
  30    cursor_regions: Vec<CursorRegion>,
  31    mouse_regions: Vec<(MouseRegion, usize)>,
  32    font_cache: Arc<FontCache>,
  33    text_layout_cache: TextLayoutCache,
  34    asset_cache: Arc<AssetCache>,
  35    last_mouse_moved_event: Option<Event>,
  36    hovered_region_ids: HashSet<MouseRegionId>,
  37    clicked_region: Option<MouseRegion>,
  38    right_clicked_region: Option<MouseRegion>,
  39    prev_drag_position: Option<Vector2F>,
  40    titlebar_height: f32,
  41}
  42
  43impl Presenter {
  44    pub fn new(
  45        window_id: usize,
  46        titlebar_height: f32,
  47        font_cache: Arc<FontCache>,
  48        text_layout_cache: TextLayoutCache,
  49        asset_cache: Arc<AssetCache>,
  50        cx: &mut MutableAppContext,
  51    ) -> Self {
  52        Self {
  53            window_id,
  54            rendered_views: cx.render_views(window_id, titlebar_height),
  55            parents: HashMap::new(),
  56            cursor_regions: Default::default(),
  57            mouse_regions: Default::default(),
  58            font_cache,
  59            text_layout_cache,
  60            asset_cache,
  61            last_mouse_moved_event: None,
  62            hovered_region_ids: Default::default(),
  63            clicked_region: None,
  64            right_clicked_region: None,
  65            prev_drag_position: None,
  66            titlebar_height,
  67        }
  68    }
  69
  70    pub fn dispatch_path(&self, app: &AppContext) -> Vec<usize> {
  71        let mut path = Vec::new();
  72        if let Some(view_id) = app.focused_view_id(self.window_id) {
  73            self.compute_dispatch_path_from(view_id, &mut path)
  74        }
  75        path
  76    }
  77
  78    pub(crate) fn compute_dispatch_path_from(&self, mut view_id: usize, path: &mut Vec<usize>) {
  79        path.push(view_id);
  80        while let Some(parent_id) = self.parents.get(&view_id).copied() {
  81            path.push(parent_id);
  82            view_id = parent_id;
  83        }
  84        path.reverse();
  85    }
  86
  87    pub fn invalidate(
  88        &mut self,
  89        invalidation: &mut WindowInvalidation,
  90        cx: &mut MutableAppContext,
  91    ) {
  92        cx.start_frame();
  93        for view_id in &invalidation.removed {
  94            invalidation.updated.remove(&view_id);
  95            self.rendered_views.remove(&view_id);
  96            self.parents.remove(&view_id);
  97        }
  98        for view_id in &invalidation.updated {
  99            self.rendered_views.insert(
 100                *view_id,
 101                cx.render_view(RenderParams {
 102                    window_id: self.window_id,
 103                    view_id: *view_id,
 104                    titlebar_height: self.titlebar_height,
 105                    hovered_region_ids: self.hovered_region_ids.clone(),
 106                    clicked_region_id: self.clicked_region.as_ref().and_then(MouseRegion::id),
 107                    right_clicked_region_id: self
 108                        .right_clicked_region
 109                        .as_ref()
 110                        .and_then(MouseRegion::id),
 111                    refreshing: false,
 112                })
 113                .unwrap(),
 114            );
 115        }
 116    }
 117
 118    pub fn refresh(&mut self, invalidation: &mut WindowInvalidation, cx: &mut MutableAppContext) {
 119        self.invalidate(invalidation, cx);
 120        for (view_id, view) in &mut self.rendered_views {
 121            if !invalidation.updated.contains(view_id) {
 122                *view = cx
 123                    .render_view(RenderParams {
 124                        window_id: self.window_id,
 125                        view_id: *view_id,
 126                        titlebar_height: self.titlebar_height,
 127                        hovered_region_ids: self.hovered_region_ids.clone(),
 128                        clicked_region_id: self.clicked_region.as_ref().and_then(MouseRegion::id),
 129                        right_clicked_region_id: self
 130                            .right_clicked_region
 131                            .as_ref()
 132                            .and_then(MouseRegion::id),
 133                        refreshing: true,
 134                    })
 135                    .unwrap();
 136            }
 137        }
 138    }
 139
 140    pub fn build_scene(
 141        &mut self,
 142        window_size: Vector2F,
 143        scale_factor: f32,
 144        refreshing: bool,
 145        cx: &mut MutableAppContext,
 146    ) -> Scene {
 147        let mut scene = Scene::new(scale_factor);
 148
 149        if let Some(root_view_id) = cx.root_view_id(self.window_id) {
 150            self.layout(window_size, refreshing, cx);
 151            let mut paint_cx = self.build_paint_context(&mut scene, window_size, cx);
 152            paint_cx.paint(
 153                root_view_id,
 154                Vector2F::zero(),
 155                RectF::new(Vector2F::zero(), window_size),
 156            );
 157            self.text_layout_cache.finish_frame();
 158            self.cursor_regions = scene.cursor_regions();
 159            self.mouse_regions = scene.mouse_regions();
 160
 161            if cx.window_is_active(self.window_id) {
 162                if let Some(event) = self.last_mouse_moved_event.clone() {
 163                    let mut invalidated_views = Vec::new();
 164                    self.handle_hover_events(&event, &mut invalidated_views, cx);
 165
 166                    for view_id in invalidated_views {
 167                        cx.notify_view(self.window_id, view_id);
 168                    }
 169                }
 170            }
 171        } else {
 172            log::error!("could not find root_view_id for window {}", self.window_id);
 173        }
 174
 175        scene
 176    }
 177
 178    fn layout(&mut self, window_size: Vector2F, refreshing: bool, cx: &mut MutableAppContext) {
 179        if let Some(root_view_id) = cx.root_view_id(self.window_id) {
 180            self.build_layout_context(window_size, refreshing, cx)
 181                .layout(root_view_id, SizeConstraint::strict(window_size));
 182        }
 183    }
 184
 185    pub fn build_layout_context<'a>(
 186        &'a mut self,
 187        window_size: Vector2F,
 188        refreshing: bool,
 189        cx: &'a mut MutableAppContext,
 190    ) -> LayoutContext<'a> {
 191        LayoutContext {
 192            window_id: self.window_id,
 193            rendered_views: &mut self.rendered_views,
 194            parents: &mut self.parents,
 195            font_cache: &self.font_cache,
 196            font_system: cx.platform().fonts(),
 197            text_layout_cache: &self.text_layout_cache,
 198            asset_cache: &self.asset_cache,
 199            view_stack: Vec::new(),
 200            refreshing,
 201            hovered_region_ids: self.hovered_region_ids.clone(),
 202            clicked_region_id: self.clicked_region.as_ref().and_then(MouseRegion::id),
 203            right_clicked_region_id: self.right_clicked_region.as_ref().and_then(MouseRegion::id),
 204            titlebar_height: self.titlebar_height,
 205            window_size,
 206            app: cx,
 207        }
 208    }
 209
 210    pub fn build_paint_context<'a>(
 211        &'a mut self,
 212        scene: &'a mut Scene,
 213        window_size: Vector2F,
 214        cx: &'a mut MutableAppContext,
 215    ) -> PaintContext {
 216        PaintContext {
 217            scene,
 218            window_size,
 219            font_cache: &self.font_cache,
 220            text_layout_cache: &self.text_layout_cache,
 221            rendered_views: &mut self.rendered_views,
 222            view_stack: Vec::new(),
 223            app: cx,
 224        }
 225    }
 226
 227    pub fn rect_for_text_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<RectF> {
 228        cx.focused_view_id(self.window_id).and_then(|view_id| {
 229            let cx = MeasurementContext {
 230                app: cx,
 231                rendered_views: &self.rendered_views,
 232                window_id: self.window_id,
 233            };
 234            cx.rect_for_text_range(view_id, range_utf16)
 235        })
 236    }
 237
 238    pub fn dispatch_event(&mut self, event: Event, cx: &mut MutableAppContext) -> bool {
 239        if let Some(root_view_id) = cx.root_view_id(self.window_id) {
 240            let mut invalidated_views = Vec::new();
 241            let mut mouse_down_out_handlers = Vec::new();
 242            let mut mouse_down_region = None;
 243            let mut clicked_region = None;
 244            let mut right_mouse_down_region = None;
 245            let mut right_clicked_region = None;
 246            let mut dragged_region = None;
 247
 248            match event {
 249                Event::MouseDown(MouseEvent {
 250                    position,
 251                    button: MouseButton::Left,
 252                    ..
 253                }) => {
 254                    let mut hit = false;
 255                    for (region, _) in self.mouse_regions.iter().rev() {
 256                        if region.bounds.contains_point(position) {
 257                            if !hit {
 258                                hit = true;
 259                                invalidated_views.push(region.view_id);
 260                                mouse_down_region = Some((region.clone(), position));
 261                                self.clicked_region = Some(region.clone());
 262                                self.prev_drag_position = Some(position);
 263                            }
 264                        } else if let Some(handler) = region.mouse_down_out.clone() {
 265                            mouse_down_out_handlers.push((handler, region.view_id, position));
 266                        }
 267                    }
 268                }
 269                Event::MouseUp(MouseEvent {
 270                    position,
 271                    click_count,
 272                    button: MouseButton::Left,
 273                    ..
 274                }) => {
 275                    self.prev_drag_position.take();
 276                    if let Some(region) = self.clicked_region.take() {
 277                        invalidated_views.push(region.view_id);
 278                        if region.bounds.contains_point(position) {
 279                            clicked_region = Some((region, position, click_count));
 280                        }
 281                    }
 282                }
 283                Event::MouseDown(MouseEvent {
 284                    position,
 285                    button: MouseButton::Right,
 286                    ..
 287                }) => {
 288                    let mut hit = false;
 289                    for (region, _) in self.mouse_regions.iter().rev() {
 290                        if region.bounds.contains_point(position) {
 291                            if !hit {
 292                                hit = true;
 293                                invalidated_views.push(region.view_id);
 294                                right_mouse_down_region = Some((region.clone(), position));
 295                                self.right_clicked_region = Some(region.clone());
 296                            }
 297                        } else if let Some(handler) = region.right_mouse_down_out.clone() {
 298                            mouse_down_out_handlers.push((handler, region.view_id, position));
 299                        }
 300                    }
 301                }
 302                Event::MouseUp(MouseEvent {
 303                    position,
 304                    click_count,
 305                    button: MouseButton::Right,
 306                    ..
 307                }) => {
 308                    if let Some(region) = self.right_clicked_region.take() {
 309                        invalidated_views.push(region.view_id);
 310                        if region.bounds.contains_point(position) {
 311                            right_clicked_region = Some((region, position, click_count));
 312                        }
 313                    }
 314                }
 315                Event::MouseMoved(MouseMovedEvent {
 316                    pressed_button,
 317                    position,
 318                    shift,
 319                    ctrl,
 320                    alt,
 321                    cmd,
 322                    ..
 323                }) => {
 324                    if let Some(MouseButton::Left) = pressed_button {
 325                        if let Some((clicked_region, prev_drag_position)) = self
 326                            .clicked_region
 327                            .as_ref()
 328                            .zip(self.prev_drag_position.as_mut())
 329                        {
 330                            dragged_region =
 331                                Some((clicked_region.clone(), *prev_drag_position, position));
 332                            *prev_drag_position = position;
 333                        }
 334
 335                        self.last_mouse_moved_event = Some(Event::MouseMoved(MouseMovedEvent {
 336                            position,
 337                            pressed_button: Some(MouseButton::Left),
 338                            shift,
 339                            ctrl,
 340                            alt,
 341                            cmd,
 342                        }));
 343                    }
 344
 345                    self.last_mouse_moved_event = Some(event.clone());
 346                }
 347                _ => {}
 348            }
 349
 350            let (mut handled, mut event_cx) =
 351                self.handle_hover_events(&event, &mut invalidated_views, cx);
 352
 353            for (handler, view_id, position) in mouse_down_out_handlers {
 354                event_cx.with_current_view(view_id, |event_cx| handler(position, event_cx))
 355            }
 356
 357            if let Some((mouse_down_region, position)) = mouse_down_region {
 358                handled = true;
 359                if let Some(mouse_down_callback) = mouse_down_region.mouse_down {
 360                    event_cx.with_current_view(mouse_down_region.view_id, |event_cx| {
 361                        mouse_down_callback(position, event_cx);
 362                    })
 363                }
 364            }
 365
 366            if let Some((clicked_region, position, click_count)) = clicked_region {
 367                handled = true;
 368                if let Some(click_callback) = clicked_region.click {
 369                    event_cx.with_current_view(clicked_region.view_id, |event_cx| {
 370                        click_callback(position, click_count, event_cx);
 371                    })
 372                }
 373            }
 374
 375            if let Some((right_mouse_down_region, position)) = right_mouse_down_region {
 376                handled = true;
 377                if let Some(right_mouse_down_callback) = right_mouse_down_region.right_mouse_down {
 378                    event_cx.with_current_view(right_mouse_down_region.view_id, |event_cx| {
 379                        right_mouse_down_callback(position, event_cx);
 380                    })
 381                }
 382            }
 383
 384            if let Some((right_clicked_region, position, click_count)) = right_clicked_region {
 385                handled = true;
 386                if let Some(right_click_callback) = right_clicked_region.right_click {
 387                    event_cx.with_current_view(right_clicked_region.view_id, |event_cx| {
 388                        right_click_callback(position, click_count, event_cx);
 389                    })
 390                }
 391            }
 392
 393            if let Some((dragged_region, prev_position, position)) = dragged_region {
 394                handled = true;
 395                if let Some(drag_callback) = dragged_region.drag {
 396                    event_cx.with_current_view(dragged_region.view_id, |event_cx| {
 397                        drag_callback(prev_position, position, event_cx);
 398                    })
 399                }
 400            }
 401
 402            if !handled {
 403                handled = event_cx.dispatch_event(root_view_id, &event);
 404            }
 405
 406            invalidated_views.extend(event_cx.invalidated_views);
 407            let dispatch_directives = event_cx.dispatched_actions;
 408
 409            for view_id in invalidated_views {
 410                cx.notify_view(self.window_id, view_id);
 411            }
 412
 413            let mut dispatch_path = Vec::new();
 414            for directive in dispatch_directives {
 415                dispatch_path.clear();
 416                if let Some(view_id) = directive.dispatcher_view_id {
 417                    self.compute_dispatch_path_from(view_id, &mut dispatch_path);
 418                }
 419                cx.dispatch_action_any(self.window_id, &dispatch_path, directive.action.as_ref());
 420            }
 421
 422            handled
 423        } else {
 424            false
 425        }
 426    }
 427
 428    fn handle_hover_events<'a>(
 429        &'a mut self,
 430        event: &Event,
 431        invalidated_views: &mut Vec<usize>,
 432        cx: &'a mut MutableAppContext,
 433    ) -> (bool, EventContext<'a>) {
 434        let mut unhovered_regions = Vec::new();
 435        let mut hovered_regions = Vec::new();
 436
 437        if let Event::MouseMoved(MouseMovedEvent {
 438            position,
 439            pressed_button,
 440            ..
 441        }) = event
 442        {
 443            if let None = pressed_button {
 444                let mut style_to_assign = CursorStyle::Arrow;
 445                for region in self.cursor_regions.iter().rev() {
 446                    if region.bounds.contains_point(*position) {
 447                        style_to_assign = region.style;
 448                        break;
 449                    }
 450                }
 451                cx.platform().set_cursor_style(style_to_assign);
 452
 453                let mut hover_depth = None;
 454                for (region, depth) in self.mouse_regions.iter().rev() {
 455                    if region.bounds.contains_point(*position)
 456                        && hover_depth.map_or(true, |hover_depth| hover_depth == *depth)
 457                    {
 458                        hover_depth = Some(*depth);
 459                        if let Some(region_id) = region.id() {
 460                            if !self.hovered_region_ids.contains(&region_id) {
 461                                invalidated_views.push(region.view_id);
 462                                hovered_regions.push((region.clone(), position));
 463                                self.hovered_region_ids.insert(region_id);
 464                            }
 465                        }
 466                    } else {
 467                        if let Some(region_id) = region.id() {
 468                            if self.hovered_region_ids.contains(&region_id) {
 469                                invalidated_views.push(region.view_id);
 470                                unhovered_regions.push((region.clone(), position));
 471                                self.hovered_region_ids.remove(&region_id);
 472                            }
 473                        }
 474                    }
 475                }
 476            }
 477        }
 478
 479        let mut event_cx = self.build_event_context(cx);
 480        let mut handled = false;
 481
 482        for (unhovered_region, position) in unhovered_regions {
 483            handled = true;
 484            if let Some(hover_callback) = unhovered_region.hover {
 485                event_cx.with_current_view(unhovered_region.view_id, |event_cx| {
 486                    hover_callback(*position, false, event_cx);
 487                })
 488            }
 489        }
 490
 491        for (hovered_region, position) in hovered_regions {
 492            handled = true;
 493            if let Some(hover_callback) = hovered_region.hover {
 494                event_cx.with_current_view(hovered_region.view_id, |event_cx| {
 495                    hover_callback(*position, true, event_cx);
 496                })
 497            }
 498        }
 499
 500        (handled, event_cx)
 501    }
 502
 503    pub fn build_event_context<'a>(
 504        &'a mut self,
 505        cx: &'a mut MutableAppContext,
 506    ) -> EventContext<'a> {
 507        EventContext {
 508            rendered_views: &mut self.rendered_views,
 509            dispatched_actions: Default::default(),
 510            font_cache: &self.font_cache,
 511            text_layout_cache: &self.text_layout_cache,
 512            view_stack: Default::default(),
 513            invalidated_views: Default::default(),
 514            notify_count: 0,
 515            window_id: self.window_id,
 516            app: cx,
 517        }
 518    }
 519
 520    pub fn debug_elements(&self, cx: &AppContext) -> Option<json::Value> {
 521        let view = cx.root_view(self.window_id)?;
 522        Some(json!({
 523            "root_view": view.debug_json(cx),
 524            "root_element": self.rendered_views.get(&view.id())
 525                .map(|root_element| {
 526                    root_element.debug(&DebugContext {
 527                        rendered_views: &self.rendered_views,
 528                        font_cache: &self.font_cache,
 529                        app: cx,
 530                    })
 531                })
 532        }))
 533    }
 534}
 535
 536pub struct DispatchDirective {
 537    pub dispatcher_view_id: Option<usize>,
 538    pub action: Box<dyn Action>,
 539}
 540
 541pub struct LayoutContext<'a> {
 542    window_id: usize,
 543    rendered_views: &'a mut HashMap<usize, ElementBox>,
 544    parents: &'a mut HashMap<usize, usize>,
 545    view_stack: Vec<usize>,
 546    pub font_cache: &'a Arc<FontCache>,
 547    pub font_system: Arc<dyn FontSystem>,
 548    pub text_layout_cache: &'a TextLayoutCache,
 549    pub asset_cache: &'a AssetCache,
 550    pub app: &'a mut MutableAppContext,
 551    pub refreshing: bool,
 552    pub window_size: Vector2F,
 553    titlebar_height: f32,
 554    hovered_region_ids: HashSet<MouseRegionId>,
 555    clicked_region_id: Option<MouseRegionId>,
 556    right_clicked_region_id: Option<MouseRegionId>,
 557}
 558
 559impl<'a> LayoutContext<'a> {
 560    pub(crate) fn keystrokes_for_action(
 561        &self,
 562        action: &dyn Action,
 563    ) -> Option<SmallVec<[Keystroke; 2]>> {
 564        self.app
 565            .keystrokes_for_action(self.window_id, &self.view_stack, action)
 566    }
 567
 568    fn layout(&mut self, view_id: usize, constraint: SizeConstraint) -> Vector2F {
 569        if let Some(parent_id) = self.view_stack.last() {
 570            self.parents.insert(view_id, *parent_id);
 571        }
 572        self.view_stack.push(view_id);
 573        let mut rendered_view = self.rendered_views.remove(&view_id).unwrap();
 574        let size = rendered_view.layout(constraint, self);
 575        self.rendered_views.insert(view_id, rendered_view);
 576        self.view_stack.pop();
 577        size
 578    }
 579
 580    pub fn render<F, V, T>(&mut self, handle: &ViewHandle<V>, f: F) -> T
 581    where
 582        F: FnOnce(&mut V, &mut RenderContext<V>) -> T,
 583        V: View,
 584    {
 585        handle.update(self.app, |view, cx| {
 586            let mut render_cx = RenderContext {
 587                app: cx,
 588                window_id: handle.window_id(),
 589                view_id: handle.id(),
 590                view_type: PhantomData,
 591                titlebar_height: self.titlebar_height,
 592                hovered_region_ids: self.hovered_region_ids.clone(),
 593                clicked_region_id: self.clicked_region_id,
 594                right_clicked_region_id: self.right_clicked_region_id,
 595                refreshing: self.refreshing,
 596            };
 597            f(view, &mut render_cx)
 598        })
 599    }
 600}
 601
 602impl<'a> Deref for LayoutContext<'a> {
 603    type Target = MutableAppContext;
 604
 605    fn deref(&self) -> &Self::Target {
 606        self.app
 607    }
 608}
 609
 610impl<'a> DerefMut for LayoutContext<'a> {
 611    fn deref_mut(&mut self) -> &mut Self::Target {
 612        self.app
 613    }
 614}
 615
 616impl<'a> ReadView for LayoutContext<'a> {
 617    fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
 618        self.app.read_view(handle)
 619    }
 620}
 621
 622impl<'a> ReadModel for LayoutContext<'a> {
 623    fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
 624        self.app.read_model(handle)
 625    }
 626}
 627
 628impl<'a> UpgradeModelHandle for LayoutContext<'a> {
 629    fn upgrade_model_handle<T: Entity>(
 630        &self,
 631        handle: &WeakModelHandle<T>,
 632    ) -> Option<ModelHandle<T>> {
 633        self.app.upgrade_model_handle(handle)
 634    }
 635
 636    fn model_handle_is_upgradable<T: Entity>(&self, handle: &WeakModelHandle<T>) -> bool {
 637        self.app.model_handle_is_upgradable(handle)
 638    }
 639
 640    fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option<AnyModelHandle> {
 641        self.app.upgrade_any_model_handle(handle)
 642    }
 643}
 644
 645impl<'a> UpgradeViewHandle for LayoutContext<'a> {
 646    fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>> {
 647        self.app.upgrade_view_handle(handle)
 648    }
 649
 650    fn upgrade_any_view_handle(&self, handle: &crate::AnyWeakViewHandle) -> Option<AnyViewHandle> {
 651        self.app.upgrade_any_view_handle(handle)
 652    }
 653}
 654
 655pub struct PaintContext<'a> {
 656    rendered_views: &'a mut HashMap<usize, ElementBox>,
 657    view_stack: Vec<usize>,
 658    pub window_size: Vector2F,
 659    pub scene: &'a mut Scene,
 660    pub font_cache: &'a FontCache,
 661    pub text_layout_cache: &'a TextLayoutCache,
 662    pub app: &'a AppContext,
 663}
 664
 665impl<'a> PaintContext<'a> {
 666    fn paint(&mut self, view_id: usize, origin: Vector2F, visible_bounds: RectF) {
 667        if let Some(mut tree) = self.rendered_views.remove(&view_id) {
 668            self.view_stack.push(view_id);
 669            tree.paint(origin, visible_bounds, self);
 670            self.rendered_views.insert(view_id, tree);
 671            self.view_stack.pop();
 672        }
 673    }
 674
 675    #[inline]
 676    pub fn paint_layer<F>(&mut self, clip_bounds: Option<RectF>, f: F)
 677    where
 678        F: FnOnce(&mut Self) -> (),
 679    {
 680        self.scene.push_layer(clip_bounds);
 681        f(self);
 682        self.scene.pop_layer();
 683    }
 684
 685    pub fn current_view_id(&self) -> usize {
 686        *self.view_stack.last().unwrap()
 687    }
 688}
 689
 690impl<'a> Deref for PaintContext<'a> {
 691    type Target = AppContext;
 692
 693    fn deref(&self) -> &Self::Target {
 694        self.app
 695    }
 696}
 697
 698pub struct EventContext<'a> {
 699    rendered_views: &'a mut HashMap<usize, ElementBox>,
 700    dispatched_actions: Vec<DispatchDirective>,
 701    pub font_cache: &'a FontCache,
 702    pub text_layout_cache: &'a TextLayoutCache,
 703    pub app: &'a mut MutableAppContext,
 704    pub window_id: usize,
 705    pub notify_count: usize,
 706    view_stack: Vec<usize>,
 707    invalidated_views: HashSet<usize>,
 708}
 709
 710impl<'a> EventContext<'a> {
 711    fn dispatch_event(&mut self, view_id: usize, event: &Event) -> bool {
 712        if let Some(mut element) = self.rendered_views.remove(&view_id) {
 713            let result =
 714                self.with_current_view(view_id, |this| element.dispatch_event(event, this));
 715            self.rendered_views.insert(view_id, element);
 716            result
 717        } else {
 718            false
 719        }
 720    }
 721
 722    fn with_current_view<F, T>(&mut self, view_id: usize, f: F) -> T
 723    where
 724        F: FnOnce(&mut Self) -> T,
 725    {
 726        self.view_stack.push(view_id);
 727        let result = f(self);
 728        self.view_stack.pop();
 729        result
 730    }
 731
 732    pub fn window_id(&self) -> usize {
 733        self.window_id
 734    }
 735
 736    pub fn view_id(&self) -> Option<usize> {
 737        self.view_stack.last().copied()
 738    }
 739
 740    pub fn is_parent_view_focused(&self) -> bool {
 741        if let Some(parent_view_id) = self.view_stack.last() {
 742            self.app.focused_view_id(self.window_id) == Some(*parent_view_id)
 743        } else {
 744            false
 745        }
 746    }
 747
 748    pub fn focus_parent_view(&mut self) {
 749        if let Some(parent_view_id) = self.view_stack.last() {
 750            self.app.focus(self.window_id, Some(*parent_view_id))
 751        }
 752    }
 753
 754    pub fn dispatch_any_action(&mut self, action: Box<dyn Action>) {
 755        self.dispatched_actions.push(DispatchDirective {
 756            dispatcher_view_id: self.view_stack.last().copied(),
 757            action,
 758        });
 759    }
 760
 761    pub fn dispatch_action<A: Action>(&mut self, action: A) {
 762        self.dispatch_any_action(Box::new(action));
 763    }
 764
 765    pub fn notify(&mut self) {
 766        self.notify_count += 1;
 767        if let Some(view_id) = self.view_stack.last() {
 768            self.invalidated_views.insert(*view_id);
 769        }
 770    }
 771
 772    pub fn notify_count(&self) -> usize {
 773        self.notify_count
 774    }
 775}
 776
 777impl<'a> Deref for EventContext<'a> {
 778    type Target = MutableAppContext;
 779
 780    fn deref(&self) -> &Self::Target {
 781        self.app
 782    }
 783}
 784
 785impl<'a> DerefMut for EventContext<'a> {
 786    fn deref_mut(&mut self) -> &mut Self::Target {
 787        self.app
 788    }
 789}
 790
 791pub struct MeasurementContext<'a> {
 792    app: &'a AppContext,
 793    rendered_views: &'a HashMap<usize, ElementBox>,
 794    pub window_id: usize,
 795}
 796
 797impl<'a> Deref for MeasurementContext<'a> {
 798    type Target = AppContext;
 799
 800    fn deref(&self) -> &Self::Target {
 801        self.app
 802    }
 803}
 804
 805impl<'a> MeasurementContext<'a> {
 806    fn rect_for_text_range(&self, view_id: usize, range_utf16: Range<usize>) -> Option<RectF> {
 807        let element = self.rendered_views.get(&view_id)?;
 808        element.rect_for_text_range(range_utf16, self)
 809    }
 810}
 811
 812pub struct DebugContext<'a> {
 813    rendered_views: &'a HashMap<usize, ElementBox>,
 814    pub font_cache: &'a FontCache,
 815    pub app: &'a AppContext,
 816}
 817
 818#[derive(Clone, Copy, Debug, Eq, PartialEq)]
 819pub enum Axis {
 820    Horizontal,
 821    Vertical,
 822}
 823
 824impl Axis {
 825    pub fn invert(self) -> Self {
 826        match self {
 827            Self::Horizontal => Self::Vertical,
 828            Self::Vertical => Self::Horizontal,
 829        }
 830    }
 831}
 832
 833impl ToJson for Axis {
 834    fn to_json(&self) -> serde_json::Value {
 835        match self {
 836            Axis::Horizontal => json!("horizontal"),
 837            Axis::Vertical => json!("vertical"),
 838        }
 839    }
 840}
 841
 842pub trait Vector2FExt {
 843    fn along(self, axis: Axis) -> f32;
 844}
 845
 846impl Vector2FExt for Vector2F {
 847    fn along(self, axis: Axis) -> f32 {
 848        match axis {
 849            Axis::Horizontal => self.x(),
 850            Axis::Vertical => self.y(),
 851        }
 852    }
 853}
 854
 855#[derive(Copy, Clone, Debug)]
 856pub struct SizeConstraint {
 857    pub min: Vector2F,
 858    pub max: Vector2F,
 859}
 860
 861impl SizeConstraint {
 862    pub fn new(min: Vector2F, max: Vector2F) -> Self {
 863        Self { min, max }
 864    }
 865
 866    pub fn strict(size: Vector2F) -> Self {
 867        Self {
 868            min: size,
 869            max: size,
 870        }
 871    }
 872
 873    pub fn strict_along(axis: Axis, max: f32) -> Self {
 874        match axis {
 875            Axis::Horizontal => Self {
 876                min: vec2f(max, 0.0),
 877                max: vec2f(max, f32::INFINITY),
 878            },
 879            Axis::Vertical => Self {
 880                min: vec2f(0.0, max),
 881                max: vec2f(f32::INFINITY, max),
 882            },
 883        }
 884    }
 885
 886    pub fn max_along(&self, axis: Axis) -> f32 {
 887        match axis {
 888            Axis::Horizontal => self.max.x(),
 889            Axis::Vertical => self.max.y(),
 890        }
 891    }
 892
 893    pub fn min_along(&self, axis: Axis) -> f32 {
 894        match axis {
 895            Axis::Horizontal => self.min.x(),
 896            Axis::Vertical => self.min.y(),
 897        }
 898    }
 899
 900    pub fn constrain(&self, size: Vector2F) -> Vector2F {
 901        vec2f(
 902            size.x().min(self.max.x()).max(self.min.x()),
 903            size.y().min(self.max.y()).max(self.min.y()),
 904        )
 905    }
 906}
 907
 908impl Default for SizeConstraint {
 909    fn default() -> Self {
 910        SizeConstraint {
 911            min: Vector2F::zero(),
 912            max: Vector2F::splat(f32::INFINITY),
 913        }
 914    }
 915}
 916
 917impl ToJson for SizeConstraint {
 918    fn to_json(&self) -> serde_json::Value {
 919        json!({
 920            "min": self.min.to_json(),
 921            "max": self.max.to_json(),
 922        })
 923    }
 924}
 925
 926pub struct ChildView {
 927    view: AnyViewHandle,
 928}
 929
 930impl ChildView {
 931    pub fn new(view: impl Into<AnyViewHandle>) -> Self {
 932        Self { view: view.into() }
 933    }
 934}
 935
 936impl Element for ChildView {
 937    type LayoutState = ();
 938    type PaintState = ();
 939
 940    fn layout(
 941        &mut self,
 942        constraint: SizeConstraint,
 943        cx: &mut LayoutContext,
 944    ) -> (Vector2F, Self::LayoutState) {
 945        let size = cx.layout(self.view.id(), constraint);
 946        (size, ())
 947    }
 948
 949    fn paint(
 950        &mut self,
 951        bounds: RectF,
 952        visible_bounds: RectF,
 953        _: &mut Self::LayoutState,
 954        cx: &mut PaintContext,
 955    ) -> Self::PaintState {
 956        cx.paint(self.view.id(), bounds.origin(), visible_bounds);
 957    }
 958
 959    fn dispatch_event(
 960        &mut self,
 961        event: &Event,
 962        _: RectF,
 963        _: RectF,
 964        _: &mut Self::LayoutState,
 965        _: &mut Self::PaintState,
 966        cx: &mut EventContext,
 967    ) -> bool {
 968        cx.dispatch_event(self.view.id(), event)
 969    }
 970
 971    fn rect_for_text_range(
 972        &self,
 973        range_utf16: Range<usize>,
 974        _: RectF,
 975        _: RectF,
 976        _: &Self::LayoutState,
 977        _: &Self::PaintState,
 978        cx: &MeasurementContext,
 979    ) -> Option<RectF> {
 980        cx.rect_for_text_range(self.view.id(), range_utf16)
 981    }
 982
 983    fn debug(
 984        &self,
 985        bounds: RectF,
 986        _: &Self::LayoutState,
 987        _: &Self::PaintState,
 988        cx: &DebugContext,
 989    ) -> serde_json::Value {
 990        json!({
 991            "type": "ChildView",
 992            "view_id": self.view.id(),
 993            "bounds": bounds.to_json(),
 994            "view": self.view.debug_json(cx.app),
 995            "child": if let Some(view) = cx.rendered_views.get(&self.view.id()) {
 996                view.debug(cx)
 997            } else {
 998                json!(null)
 999            }
1000        })
1001    }
1002}