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