1use std::{any::TypeId, rc::Rc};
2
3use crate::{element::LayoutId, style::Style};
4use anyhow::{anyhow, Result};
5use derive_more::{Deref, DerefMut};
6use gpui::{
7 geometry::Size, scene::EventHandler, AnyWindowHandle, BorrowWindowContext, EventContext,
8 Layout, MeasureParams, WindowContext,
9};
10pub use gpui::{taffy::tree::NodeId, ViewContext as LegacyViewContext};
11
12#[derive(Deref, DerefMut)]
13pub struct ViewContext<'a, 'b, 'c, V> {
14 #[deref]
15 #[deref_mut]
16 pub(crate) legacy_cx: &'c mut LegacyViewContext<'a, 'b, V>,
17}
18
19impl<'a, 'b, 'c, V: 'static> ViewContext<'a, 'b, 'c, V> {
20 pub fn new(legacy_cx: &'c mut LegacyViewContext<'a, 'b, V>) -> Self {
21 Self { legacy_cx }
22 }
23
24 pub fn add_layout_node(
25 &mut self,
26 style: Style,
27 children: impl IntoIterator<Item = NodeId>,
28 ) -> Result<LayoutId> {
29 let rem_size = self.rem_size();
30 let style = style.to_taffy(rem_size);
31 let id = self
32 .legacy_cx
33 .layout_engine()
34 .ok_or_else(|| anyhow!("no layout engine"))?
35 .add_node(style, children)?;
36
37 Ok(id)
38 }
39
40 pub fn add_measured_layout_node<F>(&mut self, style: Style, measure: F) -> Result<LayoutId>
41 where
42 F: Fn(MeasureParams) -> Size<f32> + Sync + Send + 'static,
43 {
44 let rem_size = self.rem_size();
45 let layout_id = self
46 .layout_engine()
47 .ok_or_else(|| anyhow!("no layout engine"))?
48 .add_measured_node(style.to_taffy(rem_size), measure)?;
49
50 Ok(layout_id)
51 }
52
53 pub fn on_event<E: 'static>(
54 &mut self,
55 order: u32,
56 handler: impl Fn(&mut V, &E, &mut EventContext<V>) + 'static,
57 ) {
58 let view = self.weak_handle();
59
60 self.scene().event_handlers.push(EventHandler {
61 order,
62 handler: Rc::new(move |event, window_cx| {
63 if let Some(view) = view.upgrade(window_cx) {
64 view.update(window_cx, |view, view_cx| {
65 let mut event_cx = EventContext::new(view_cx);
66 handler(view, event.downcast_ref().unwrap(), &mut event_cx);
67 event_cx.bubble
68 })
69 } else {
70 true
71 }
72 }),
73 event_type: TypeId::of::<E>(),
74 })
75 }
76
77 pub(crate) fn computed_layout(&mut self, layout_id: LayoutId) -> Result<Layout> {
78 self.layout_engine()
79 .ok_or_else(|| anyhow!("no layout engine present"))?
80 .computed_layout(layout_id)
81 }
82}
83
84impl<'a, 'b, 'c, V: 'static> BorrowWindowContext for ViewContext<'a, 'b, 'c, V> {
85 type Result<T> = T;
86
87 fn read_window<T, F>(&self, window: AnyWindowHandle, f: F) -> Self::Result<T>
88 where
89 F: FnOnce(&WindowContext) -> T,
90 {
91 self.legacy_cx.read_window(window, f)
92 }
93
94 fn read_window_optional<T, F>(&self, window: AnyWindowHandle, f: F) -> Option<T>
95 where
96 F: FnOnce(&WindowContext) -> Option<T>,
97 {
98 self.legacy_cx.read_window_optional(window, f)
99 }
100
101 fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Self::Result<T>
102 where
103 F: FnOnce(&mut WindowContext) -> T,
104 {
105 self.legacy_cx.update_window(window, f)
106 }
107
108 fn update_window_optional<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Option<T>
109 where
110 F: FnOnce(&mut WindowContext) -> Option<T>,
111 {
112 self.legacy_cx.update_window_optional(window, f)
113 }
114}