window.rs

  1use crate::{
  2    px, AnyView, AppContext, AvailableSpace, Bounds, Context, Effect, Element, EntityId, Handle,
  3    LayoutId, MainThreadOnly, Pixels, Platform, PlatformWindow, Point, Reference, Scene, Size,
  4    Style, TaffyLayoutEngine, TextStyle, TextStyleRefinement, WeakHandle, WindowOptions,
  5};
  6use anyhow::Result;
  7use collections::HashMap;
  8use derive_more::{Deref, DerefMut};
  9use refineable::Refineable;
 10use std::{
 11    any::{Any, TypeId},
 12    future,
 13    marker::PhantomData,
 14    sync::Arc,
 15};
 16use util::ResultExt;
 17
 18pub struct AnyWindow {}
 19
 20pub struct Window {
 21    handle: AnyWindowHandle,
 22    platform_window: MainThreadOnly<Box<dyn PlatformWindow>>,
 23    rem_size: Pixels,
 24    content_size: Size<Pixels>,
 25    layout_engine: TaffyLayoutEngine,
 26    text_style_stack: Vec<TextStyleRefinement>,
 27    state_stacks_by_type: HashMap<TypeId, Vec<Box<dyn Any + Send + Sync>>>,
 28    pub(crate) root_view: Option<AnyView<()>>,
 29    mouse_position: Point<Pixels>,
 30    pub(crate) scene: Scene,
 31    pub(crate) dirty: bool,
 32}
 33
 34impl Window {
 35    pub fn new(
 36        handle: AnyWindowHandle,
 37        options: WindowOptions,
 38        platform: &dyn Platform,
 39        cx: &mut AppContext,
 40    ) -> Self {
 41        let platform_window = platform.open_window(handle, options);
 42        let mouse_position = platform_window.mouse_position();
 43        let content_size = platform_window.content_size();
 44        let scale_factor = platform_window.scale_factor();
 45        platform_window.on_resize(Box::new({
 46            let handle = handle;
 47            let cx = cx.to_async();
 48            move |content_size, scale_factor| {
 49                cx.update_window(handle, |cx| {
 50                    cx.window.scene = Scene::new(scale_factor);
 51                    cx.window.content_size = content_size;
 52                    cx.window.dirty = true;
 53                })
 54                .log_err();
 55            }
 56        }));
 57
 58        let platform_window = MainThreadOnly::new(Arc::new(platform_window), platform.dispatcher());
 59
 60        Window {
 61            handle,
 62            platform_window,
 63            rem_size: px(16.),
 64            content_size,
 65            layout_engine: TaffyLayoutEngine::new(),
 66            text_style_stack: Vec::new(),
 67            state_stacks_by_type: HashMap::default(),
 68            root_view: None,
 69            mouse_position,
 70            scene: Scene::new(scale_factor),
 71            dirty: true,
 72        }
 73    }
 74}
 75
 76#[derive(Deref, DerefMut)]
 77pub struct WindowContext<'a, 'b> {
 78    #[deref]
 79    #[deref_mut]
 80    app: Reference<'a, AppContext>,
 81    window: Reference<'b, Window>,
 82}
 83
 84impl<'a, 'w> WindowContext<'a, 'w> {
 85    pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window) -> Self {
 86        Self {
 87            app: Reference::Mutable(app),
 88            window: Reference::Mutable(window),
 89        }
 90    }
 91
 92    // pub(crate) fn immutable(app: &'a AppContext, window: &'w Window) -> Self {
 93    //     Self {
 94    //         app: Reference::Immutable(app),
 95    //         window: Reference::Immutable(window),
 96    //     }
 97    // }
 98
 99    pub(crate) fn draw(&mut self) -> Result<()> {
100        let unit_entity = self.unit_entity.clone();
101        self.update_entity(&unit_entity, |_, cx| {
102            let mut root_view = cx.window.root_view.take().unwrap();
103            let (root_layout_id, mut frame_state) = root_view.layout(&mut (), cx)?;
104            let available_space = cx.window.content_size.map(Into::into);
105            cx.window
106                .layout_engine
107                .compute_layout(root_layout_id, available_space)?;
108            let layout = cx.window.layout_engine.layout(root_layout_id)?;
109            root_view.paint(layout, &mut (), &mut frame_state, cx)?;
110            cx.window.root_view = Some(root_view);
111            let scene = cx.window.scene.take();
112            dbg!(&scene);
113            let _ = cx.window.platform_window.read(|platform_window| {
114                platform_window.draw(scene);
115                future::ready(())
116            });
117
118            Ok(())
119        })
120    }
121
122    pub fn request_layout(
123        &mut self,
124        style: Style,
125        children: impl IntoIterator<Item = LayoutId>,
126    ) -> Result<LayoutId> {
127        self.app.layout_id_buffer.clear();
128        self.app.layout_id_buffer.extend(children.into_iter());
129        let rem_size = self.rem_size();
130
131        self.window
132            .layout_engine
133            .request_layout(style, rem_size, &self.app.layout_id_buffer)
134    }
135
136    pub fn request_measured_layout<
137        F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>) -> Size<Pixels> + Send + Sync + 'static,
138    >(
139        &mut self,
140        style: Style,
141        rem_size: Pixels,
142        measure: F,
143    ) -> Result<LayoutId> {
144        self.window
145            .layout_engine
146            .request_measured_layout(style, rem_size, measure)
147    }
148
149    pub fn layout(&mut self, layout_id: LayoutId) -> Result<Layout> {
150        Ok(self
151            .window
152            .layout_engine
153            .layout(layout_id)
154            .map(Into::into)?)
155    }
156
157    pub fn rem_size(&self) -> Pixels {
158        self.window.rem_size
159    }
160
161    pub fn push_text_style(&mut self, text_style: TextStyleRefinement) {
162        self.window.text_style_stack.push(text_style);
163    }
164
165    pub fn pop_text_style(&mut self) {
166        self.window.text_style_stack.pop();
167    }
168
169    pub fn push_cascading_state<T: Send + Sync + 'static>(&mut self, theme: T) {
170        self.window
171            .state_stacks_by_type
172            .entry(TypeId::of::<T>())
173            .or_default()
174            .push(Box::new(theme));
175    }
176
177    pub fn pop_cascading_state<T: Send + Sync + 'static>(&mut self) {
178        self.window
179            .state_stacks_by_type
180            .get_mut(&TypeId::of::<T>())
181            .and_then(|stack| stack.pop())
182            .expect("cascading state not found");
183    }
184
185    pub fn cascading_state<T: Send + Sync + 'static>(&self) -> &T {
186        let type_id = TypeId::of::<T>();
187        self.window
188            .state_stacks_by_type
189            .get(&type_id)
190            .and_then(|stack| stack.last())
191            .expect("no cascading state of the specified type has been pushed")
192            .downcast_ref::<T>()
193            .unwrap()
194    }
195
196    pub fn text_style(&self) -> TextStyle {
197        let mut style = TextStyle::default();
198        for refinement in &self.window.text_style_stack {
199            style.refine(refinement);
200        }
201        style
202    }
203
204    pub fn mouse_position(&self) -> Point<Pixels> {
205        self.window.mouse_position
206    }
207}
208
209impl Context for WindowContext<'_, '_> {
210    type EntityContext<'a, 'w, T: Send + Sync + 'static> = ViewContext<'a, 'w, T>;
211    type Result<T> = T;
212
213    fn entity<T: Send + Sync + 'static>(
214        &mut self,
215        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
216    ) -> Handle<T> {
217        let id = self.entities.insert(None);
218        let entity = Box::new(build_entity(&mut ViewContext::mutable(
219            &mut *self.app,
220            &mut self.window,
221            id,
222        )));
223        self.entities.get_mut(id).unwrap().replace(entity);
224
225        Handle {
226            id,
227            entity_type: PhantomData,
228        }
229    }
230
231    fn update_entity<T: Send + Sync + 'static, R>(
232        &mut self,
233        handle: &Handle<T>,
234        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
235    ) -> R {
236        let mut entity = self
237            .app
238            .entities
239            .get_mut(handle.id)
240            .unwrap()
241            .take()
242            .unwrap()
243            .downcast::<T>()
244            .unwrap();
245
246        let result = update(
247            &mut *entity,
248            &mut ViewContext::mutable(&mut *self.app, &mut *self.window, handle.id),
249        );
250
251        self.app
252            .entities
253            .get_mut(handle.id)
254            .unwrap()
255            .replace(entity);
256
257        result
258    }
259}
260
261#[derive(Deref, DerefMut)]
262pub struct ViewContext<'a, 'w, T> {
263    #[deref]
264    #[deref_mut]
265    window_cx: WindowContext<'a, 'w>,
266    entity_type: PhantomData<T>,
267    entity_id: EntityId,
268}
269
270impl<'a, 'w, T: Send + Sync + 'static> ViewContext<'a, 'w, T> {
271    fn mutable(app: &'a mut AppContext, window: &'w mut Window, entity_id: EntityId) -> Self {
272        Self {
273            window_cx: WindowContext::mutable(app, window),
274            entity_id,
275            entity_type: PhantomData,
276        }
277    }
278
279    // fn immutable(app: &'a AppContext, window: &'w Window, entity_id: EntityId) -> Self {
280    //     Self {
281    //         window_cx: WindowContext::immutable(app, window),
282    //         entity_id,
283    //         entity_type: PhantomData,
284    //     }
285    // }
286
287    pub fn erase_state<R>(&mut self, f: impl FnOnce(&mut ViewContext<()>) -> R) -> R {
288        let entity_id = self.unit_entity.id;
289        let mut cx = ViewContext::mutable(
290            &mut *self.window_cx.app,
291            &mut *self.window_cx.window,
292            entity_id,
293        );
294        f(&mut cx)
295    }
296
297    pub fn handle(&self) -> WeakHandle<T> {
298        WeakHandle {
299            id: self.entity_id,
300            entity_type: PhantomData,
301        }
302    }
303
304    pub fn observe<E: Send + Sync + 'static>(
305        &mut self,
306        handle: &Handle<E>,
307        on_notify: impl Fn(&mut T, Handle<E>, &mut ViewContext<'_, '_, T>) + Send + Sync + 'static,
308    ) {
309        let this = self.handle();
310        let handle = handle.downgrade();
311        let window_handle = self.window.handle;
312        self.app
313            .observers
314            .entry(handle.id)
315            .or_default()
316            .push(Arc::new(move |cx| {
317                cx.update_window(window_handle.id, |cx| {
318                    if let Some(handle) = handle.upgrade(cx) {
319                        this.update(cx, |this, cx| on_notify(this, handle, cx))
320                            .is_ok()
321                    } else {
322                        false
323                    }
324                })
325                .unwrap_or(false)
326            }));
327    }
328
329    pub fn notify(&mut self) {
330        let entity_id = self.entity_id;
331        self.app
332            .pending_effects
333            .push_back(Effect::Notify(entity_id));
334        self.window.dirty = true;
335    }
336}
337
338impl<'a, 'w, T: 'static> Context for ViewContext<'a, 'w, T> {
339    type EntityContext<'b, 'c, U: Send + Sync + 'static> = ViewContext<'b, 'c, U>;
340    type Result<U> = U;
341
342    fn entity<T2: Send + Sync + 'static>(
343        &mut self,
344        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T2>) -> T2,
345    ) -> Handle<T2> {
346        self.window_cx.entity(build_entity)
347    }
348
349    fn update_entity<U: Send + Sync + 'static, R>(
350        &mut self,
351        handle: &Handle<U>,
352        update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
353    ) -> R {
354        self.window_cx.update_entity(handle, update)
355    }
356}
357
358// #[derive(Clone, Copy, Eq, PartialEq, Hash)]
359slotmap::new_key_type! { pub struct WindowId; }
360
361#[derive(PartialEq, Eq)]
362pub struct WindowHandle<S> {
363    id: WindowId,
364    state_type: PhantomData<S>,
365}
366
367impl<S> Copy for WindowHandle<S> {}
368
369impl<S> Clone for WindowHandle<S> {
370    fn clone(&self) -> Self {
371        WindowHandle {
372            id: self.id,
373            state_type: PhantomData,
374        }
375    }
376}
377
378impl<S> WindowHandle<S> {
379    pub fn new(id: WindowId) -> Self {
380        WindowHandle {
381            id,
382            state_type: PhantomData,
383        }
384    }
385}
386
387impl<S: 'static> Into<AnyWindowHandle> for WindowHandle<S> {
388    fn into(self) -> AnyWindowHandle {
389        AnyWindowHandle {
390            id: self.id,
391            state_type: TypeId::of::<S>(),
392        }
393    }
394}
395
396#[derive(Copy, Clone, PartialEq, Eq)]
397pub struct AnyWindowHandle {
398    pub(crate) id: WindowId,
399    state_type: TypeId,
400}
401
402#[derive(Clone)]
403pub struct Layout {
404    pub order: u32,
405    pub bounds: Bounds<Pixels>,
406}