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