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