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 self.window
742 .rendered_views
743 .insert(root_view_id, rendered_root);
744
745 self.window.text_layout_cache.finish_frame();
746 let scene = scene_builder.build();
747 self.window.cursor_regions = scene.cursor_regions();
748 self.window.mouse_regions = scene.mouse_regions();
749
750 if self.window_is_active() {
751 if let Some(event) = self.window.last_mouse_moved_event.clone() {
752 self.dispatch_event(event, true);
753 }
754 }
755
756 scene
757 }
758
759 pub fn rect_for_text_range(&self, range_utf16: Range<usize>) -> Option<RectF> {
760 let root_view_id = self.window.root_view().id();
761 self.window
762 .rendered_views
763 .get(&root_view_id)?
764 .rect_for_text_range(range_utf16, self)
765 .log_err()
766 .flatten()
767 }
768
769 pub fn debug_elements(&self) -> Option<json::Value> {
770 let view = self.window.root_view();
771 Some(json!({
772 "root_view": view.debug_json(self),
773 "root_element": self.window.rendered_views.get(&view.id())
774 .and_then(|root_element| {
775 root_element.debug(self).log_err()
776 })
777 }))
778 }
779
780 pub fn set_window_title(&mut self, title: &str) {
781 self.window.platform_window.set_title(title);
782 }
783
784 pub fn set_window_edited(&mut self, edited: bool) {
785 self.window.platform_window.set_edited(edited);
786 }
787
788 pub fn is_topmost_window_for_position(&self, position: Vector2F) -> bool {
789 self.window
790 .platform_window
791 .is_topmost_for_position(position)
792 }
793
794 pub fn activate_window(&self) {
795 self.window.platform_window.activate();
796 }
797
798 pub fn window_is_active(&self) -> bool {
799 self.window.is_active
800 }
801
802 pub fn window_is_fullscreen(&self) -> bool {
803 self.window.is_fullscreen
804 }
805
806 pub fn focused_view_id(&self) -> Option<usize> {
807 self.window.focused_view_id
808 }
809
810 pub fn window_bounds(&self) -> WindowBounds {
811 self.window.platform_window.bounds()
812 }
813
814 pub fn window_appearance(&self) -> Appearance {
815 self.window.appearance
816 }
817
818 pub fn window_display_uuid(&self) -> Option<Uuid> {
819 self.window.platform_window.screen().display_uuid()
820 }
821
822 pub fn show_character_palette(&self) {
823 self.window.platform_window.show_character_palette();
824 }
825
826 pub fn minimize_window(&self) {
827 self.window.platform_window.minimize();
828 }
829
830 pub fn zoom_window(&self) {
831 self.window.platform_window.zoom();
832 }
833
834 pub fn toggle_full_screen(&self) {
835 self.window.platform_window.toggle_full_screen();
836 }
837
838 pub fn prompt(
839 &self,
840 level: PromptLevel,
841 msg: &str,
842 answers: &[&str],
843 ) -> oneshot::Receiver<usize> {
844 self.window.platform_window.prompt(level, msg, answers)
845 }
846
847 pub fn replace_root_view<V, F>(&mut self, build_root_view: F) -> ViewHandle<V>
848 where
849 V: View,
850 F: FnOnce(&mut ViewContext<V>) -> V,
851 {
852 let root_view = self
853 .build_and_insert_view(ParentId::Root, |cx| Some(build_root_view(cx)))
854 .unwrap();
855 self.window.root_view = Some(root_view.clone().into_any());
856 self.window.focused_view_id = Some(root_view.id());
857 root_view
858 }
859
860 pub(crate) fn build_and_insert_view<T, F>(
861 &mut self,
862 parent_id: ParentId,
863 build_view: F,
864 ) -> Option<ViewHandle<T>>
865 where
866 T: View,
867 F: FnOnce(&mut ViewContext<T>) -> Option<T>,
868 {
869 let window_id = self.window_id;
870 let view_id = post_inc(&mut self.next_entity_id);
871 // Make sure we can tell child views about their parentu
872 self.parents.insert((window_id, view_id), parent_id);
873 let mut cx = ViewContext::mutable(self, view_id);
874 let handle = if let Some(view) = build_view(&mut cx) {
875 self.views.insert((window_id, view_id), Box::new(view));
876 self.window
877 .invalidation
878 .get_or_insert_with(Default::default)
879 .updated
880 .insert(view_id);
881 Some(ViewHandle::new(window_id, view_id, &self.ref_counts))
882 } else {
883 self.parents.remove(&(window_id, view_id));
884 None
885 };
886 handle
887 }
888}
889
890pub struct RenderParams {
891 pub view_id: usize,
892 pub titlebar_height: f32,
893 pub hovered_region_ids: HashSet<MouseRegionId>,
894 pub clicked_region_ids: Option<(HashSet<MouseRegionId>, MouseButton)>,
895 pub refreshing: bool,
896 pub appearance: Appearance,
897}
898
899#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
900pub enum Axis {
901 #[default]
902 Horizontal,
903 Vertical,
904}
905
906impl Axis {
907 pub fn invert(self) -> Self {
908 match self {
909 Self::Horizontal => Self::Vertical,
910 Self::Vertical => Self::Horizontal,
911 }
912 }
913
914 pub fn component(&self, point: Vector2F) -> f32 {
915 match self {
916 Self::Horizontal => point.x(),
917 Self::Vertical => point.y(),
918 }
919 }
920}
921
922impl ToJson for Axis {
923 fn to_json(&self) -> serde_json::Value {
924 match self {
925 Axis::Horizontal => json!("horizontal"),
926 Axis::Vertical => json!("vertical"),
927 }
928 }
929}
930
931impl StaticColumnCount for Axis {}
932impl Bind for Axis {
933 fn bind(&self, statement: &Statement, start_index: i32) -> anyhow::Result<i32> {
934 match self {
935 Axis::Horizontal => "Horizontal",
936 Axis::Vertical => "Vertical",
937 }
938 .bind(statement, start_index)
939 }
940}
941
942impl Column for Axis {
943 fn column(statement: &mut Statement, start_index: i32) -> anyhow::Result<(Self, i32)> {
944 String::column(statement, start_index).and_then(|(axis_text, next_index)| {
945 Ok((
946 match axis_text.as_str() {
947 "Horizontal" => Axis::Horizontal,
948 "Vertical" => Axis::Vertical,
949 _ => bail!("Stored serialized item kind is incorrect"),
950 },
951 next_index,
952 ))
953 })
954 }
955}
956
957pub trait Vector2FExt {
958 fn along(self, axis: Axis) -> f32;
959}
960
961impl Vector2FExt for Vector2F {
962 fn along(self, axis: Axis) -> f32 {
963 match axis {
964 Axis::Horizontal => self.x(),
965 Axis::Vertical => self.y(),
966 }
967 }
968}
969
970#[derive(Copy, Clone, Debug)]
971pub struct SizeConstraint {
972 pub min: Vector2F,
973 pub max: Vector2F,
974}
975
976impl SizeConstraint {
977 pub fn new(min: Vector2F, max: Vector2F) -> Self {
978 Self { min, max }
979 }
980
981 pub fn strict(size: Vector2F) -> Self {
982 Self {
983 min: size,
984 max: size,
985 }
986 }
987
988 pub fn strict_along(axis: Axis, max: f32) -> Self {
989 match axis {
990 Axis::Horizontal => Self {
991 min: vec2f(max, 0.0),
992 max: vec2f(max, f32::INFINITY),
993 },
994 Axis::Vertical => Self {
995 min: vec2f(0.0, max),
996 max: vec2f(f32::INFINITY, max),
997 },
998 }
999 }
1000
1001 pub fn max_along(&self, axis: Axis) -> f32 {
1002 match axis {
1003 Axis::Horizontal => self.max.x(),
1004 Axis::Vertical => self.max.y(),
1005 }
1006 }
1007
1008 pub fn min_along(&self, axis: Axis) -> f32 {
1009 match axis {
1010 Axis::Horizontal => self.min.x(),
1011 Axis::Vertical => self.min.y(),
1012 }
1013 }
1014
1015 pub fn constrain(&self, size: Vector2F) -> Vector2F {
1016 vec2f(
1017 size.x().min(self.max.x()).max(self.min.x()),
1018 size.y().min(self.max.y()).max(self.min.y()),
1019 )
1020 }
1021}
1022
1023impl Default for SizeConstraint {
1024 fn default() -> Self {
1025 SizeConstraint {
1026 min: Vector2F::zero(),
1027 max: Vector2F::splat(f32::INFINITY),
1028 }
1029 }
1030}
1031
1032impl ToJson for SizeConstraint {
1033 fn to_json(&self) -> serde_json::Value {
1034 json!({
1035 "min": self.min.to_json(),
1036 "max": self.max.to_json(),
1037 })
1038 }
1039}
1040
1041pub struct ChildView {
1042 view_id: usize,
1043 view_name: &'static str,
1044}
1045
1046impl ChildView {
1047 pub fn new(view: &AnyViewHandle, cx: &AppContext) -> Self {
1048 let view_name = cx.view_ui_name(view.window_id(), view.id()).unwrap();
1049 Self {
1050 view_id: view.id(),
1051 view_name,
1052 }
1053 }
1054}
1055
1056impl<V: View> Drawable<V> for ChildView {
1057 type LayoutState = ();
1058 type PaintState = ();
1059
1060 fn layout(
1061 &mut self,
1062 constraint: SizeConstraint,
1063 _: &mut V,
1064 cx: &mut ViewContext<V>,
1065 ) -> (Vector2F, Self::LayoutState) {
1066 if let Some(mut rendered_view) = cx.window.rendered_views.remove(&self.view_id) {
1067 let size = rendered_view
1068 .layout(constraint, cx)
1069 .log_err()
1070 .unwrap_or(Vector2F::zero());
1071 cx.window.rendered_views.insert(self.view_id, rendered_view);
1072 (size, ())
1073 } else {
1074 log::error!(
1075 "layout called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
1076 self.view_id,
1077 self.view_name
1078 );
1079 (Vector2F::zero(), ())
1080 }
1081 }
1082
1083 fn paint(
1084 &mut self,
1085 scene: &mut SceneBuilder,
1086 bounds: RectF,
1087 visible_bounds: RectF,
1088 _: &mut Self::LayoutState,
1089 _: &mut V,
1090 cx: &mut ViewContext<V>,
1091 ) {
1092 if let Some(mut rendered_view) = cx.window.rendered_views.remove(&self.view_id) {
1093 rendered_view
1094 .paint(scene, bounds.origin(), visible_bounds, cx)
1095 .log_err();
1096 cx.window.rendered_views.insert(self.view_id, rendered_view);
1097 } else {
1098 log::error!(
1099 "paint called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
1100 self.view_id,
1101 self.view_name
1102 );
1103 }
1104 }
1105
1106 fn rect_for_text_range(
1107 &self,
1108 range_utf16: Range<usize>,
1109 _: RectF,
1110 _: RectF,
1111 _: &Self::LayoutState,
1112 _: &Self::PaintState,
1113 _: &V,
1114 cx: &ViewContext<V>,
1115 ) -> Option<RectF> {
1116 if let Some(rendered_view) = cx.window.rendered_views.get(&self.view_id) {
1117 rendered_view
1118 .rect_for_text_range(range_utf16, &cx.window_context)
1119 .log_err()
1120 .flatten()
1121 } else {
1122 log::error!(
1123 "rect_for_text_range called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
1124 self.view_id,
1125 self.view_name
1126 );
1127 None
1128 }
1129 }
1130
1131 fn debug(
1132 &self,
1133 bounds: RectF,
1134 _: &Self::LayoutState,
1135 _: &Self::PaintState,
1136 _: &V,
1137 cx: &ViewContext<V>,
1138 ) -> serde_json::Value {
1139 json!({
1140 "type": "ChildView",
1141 "view_id": self.view_id,
1142 "bounds": bounds.to_json(),
1143 "view": if let Some(view) = cx.views.get(&(cx.window_id, self.view_id)) {
1144 view.debug_json(cx)
1145 } else {
1146 json!(null)
1147 },
1148 "child": if let Some(element) = cx.window.rendered_views.get(&self.view_id) {
1149 element.debug(&cx.window_context).log_err().unwrap_or_else(|| json!(null))
1150 } else {
1151 json!(null)
1152 }
1153 })
1154 }
1155}