Checkpoint
Co-Authored-By: Antonio Scandurra <antonio@zed.dev>
This commit is contained in:
parent
3921278319
commit
733df38f9b
10 changed files with 199 additions and 211 deletions
|
@ -47,7 +47,7 @@ impl<V: 'static> gpui::Element<V> for AdapterElement<V> {
|
||||||
let (layout_engine, layout_id) = layout_data.take().unwrap();
|
let (layout_engine, layout_id) = layout_data.take().unwrap();
|
||||||
legacy_cx.push_layout_engine(layout_engine);
|
legacy_cx.push_layout_engine(layout_engine);
|
||||||
let mut cx = PaintContext::new(legacy_cx, scene);
|
let mut cx = PaintContext::new(legacy_cx, scene);
|
||||||
self.0.paint(view, layout_id, &mut cx);
|
self.0.paint(view, &mut cx);
|
||||||
*layout_data = legacy_cx.pop_layout_engine().zip(Some(layout_id));
|
*layout_data = legacy_cx.pop_layout_engine().zip(Some(layout_id));
|
||||||
debug_assert!(layout_data.is_some());
|
debug_assert!(layout_data.is_some());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,24 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
element::{AnyElement, Element, Layout, ParentElement},
|
element::{AnyElement, Element, Layout, ParentElement},
|
||||||
|
interactive::{InteractionHandlers, Interactive},
|
||||||
layout_context::LayoutContext,
|
layout_context::LayoutContext,
|
||||||
paint_context::PaintContext,
|
paint_context::PaintContext,
|
||||||
style::{Style, StyleHelpers, StyleRefinement, Styleable},
|
style::{Style, StyleHelpers, StyleRefinement, Styleable},
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use gpui::{platform::MouseMovedEvent, EventContext, LayoutId};
|
use gpui::LayoutId;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub struct Div<V> {
|
pub struct Div<V: 'static> {
|
||||||
style: StyleRefinement,
|
style: StyleRefinement,
|
||||||
|
handlers: InteractionHandlers<V>,
|
||||||
children: SmallVec<[AnyElement<V>; 2]>,
|
children: SmallVec<[AnyElement<V>; 2]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn div<V>() -> Div<V> {
|
pub fn div<V>() -> Div<V> {
|
||||||
Div {
|
Div {
|
||||||
style: Default::default(),
|
style: Default::default(),
|
||||||
|
handlers: Default::default(),
|
||||||
children: Default::default(),
|
children: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,45 +46,34 @@ impl<V: 'static> Element<V> for Div<V> {
|
||||||
let style = self.style();
|
let style = self.style();
|
||||||
|
|
||||||
style.paint_background::<V, Self>(layout, cx);
|
style.paint_background::<V, Self>(layout, cx);
|
||||||
|
for child in &mut self.children {
|
||||||
|
child.paint(view, cx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> Styleable for Div<V> {
|
impl<V> Styleable for Div<V> {
|
||||||
type Style = Style;
|
type Style = Style;
|
||||||
|
|
||||||
fn declared_style(&mut self) -> &mut crate::style::StyleRefinement {
|
fn declared_style(&mut self) -> &mut StyleRefinement {
|
||||||
&mut self.style
|
&mut self.style
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> StyleHelpers for Div<V> {}
|
impl<V> StyleHelpers for Div<V> {}
|
||||||
|
|
||||||
|
impl<V> Interactive<V> for Div<V> {
|
||||||
|
fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
|
||||||
|
&mut self.handlers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<V: 'static> ParentElement<V> for Div<V> {
|
impl<V: 'static> ParentElement<V> for Div<V> {
|
||||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
||||||
&mut self.children
|
&mut self.children
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Interactive<V> {
|
|
||||||
fn declared_interactions(&mut self) -> &mut Interactions<V>;
|
|
||||||
|
|
||||||
fn on_mouse_move<H>(mut self, handler: H) -> Self
|
|
||||||
where
|
|
||||||
H: 'static + Fn(&mut V, &MouseMovedEvent, &mut EventContext<V>),
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
self.declared_interactions().mouse_moved = Some(Rc::new(move |view, event, cx| {
|
|
||||||
handler(view, event, cx);
|
|
||||||
cx.bubble
|
|
||||||
}));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Interactions<V> {
|
|
||||||
mouse_moved: Option<Rc<dyn Fn(&mut V, &MouseMovedEvent, &mut EventContext<V>) -> bool>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
// let elt = div().w_auto();
|
// let elt = div().w_auto();
|
||||||
|
|
|
@ -10,6 +10,79 @@ pub use crate::paint_context::PaintContext;
|
||||||
|
|
||||||
type LayoutId = gpui::LayoutId;
|
type LayoutId = gpui::LayoutId;
|
||||||
|
|
||||||
|
pub trait Element<V: 'static>: 'static {
|
||||||
|
type Layout;
|
||||||
|
|
||||||
|
fn layout(
|
||||||
|
&mut self,
|
||||||
|
view: &mut V,
|
||||||
|
cx: &mut LayoutContext<V>,
|
||||||
|
) -> Result<Layout<V, Self::Layout>>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
|
fn paint(
|
||||||
|
&mut self,
|
||||||
|
view: &mut V,
|
||||||
|
layout: &mut Layout<V, Self::Layout>,
|
||||||
|
cx: &mut PaintContext<V>,
|
||||||
|
) where
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
|
fn into_any(self) -> AnyElement<V>
|
||||||
|
where
|
||||||
|
Self: 'static + Sized,
|
||||||
|
{
|
||||||
|
AnyElement(Box::new(ElementState {
|
||||||
|
element: self,
|
||||||
|
layout: None,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used to make ElementState<V, E> into a trait object, so we can wrap it in AnyElement<V>.
|
||||||
|
trait ElementStateObject<V> {
|
||||||
|
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId>;
|
||||||
|
fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A wrapper around an element that stores its layout state.
|
||||||
|
struct ElementState<V: 'static, E: Element<V>> {
|
||||||
|
element: E,
|
||||||
|
layout: Option<Layout<V, E::Layout>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// We blanket-implement the object-safe ElementStateObject interface to make ElementStates into trait objects
|
||||||
|
impl<V, E: Element<V>> ElementStateObject<V> for ElementState<V, E> {
|
||||||
|
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
|
||||||
|
let layout = self.element.layout(view, cx)?;
|
||||||
|
let layout_id = layout.id;
|
||||||
|
self.layout = Some(layout);
|
||||||
|
Ok(layout_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
|
||||||
|
let layout = self.layout.as_mut().expect("paint called before layout");
|
||||||
|
if layout.engine_layout.is_none() {
|
||||||
|
layout.engine_layout = cx.computed_layout(layout.id).log_err()
|
||||||
|
}
|
||||||
|
self.element.paint(view, layout, cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A dynamic element.
|
||||||
|
pub struct AnyElement<V>(Box<dyn ElementStateObject<V>>);
|
||||||
|
|
||||||
|
impl<V> AnyElement<V> {
|
||||||
|
pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
|
||||||
|
self.0.layout(view, cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
|
||||||
|
self.0.paint(view, cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deref, DerefMut)]
|
#[derive(Deref, DerefMut)]
|
||||||
pub struct Layout<V, D> {
|
pub struct Layout<V, D> {
|
||||||
id: LayoutId,
|
id: LayoutId,
|
||||||
|
@ -47,84 +120,11 @@ impl<V: 'static, D> Layout<V, D> {
|
||||||
impl<V: 'static> Layout<V, Option<AnyElement<V>>> {
|
impl<V: 'static> Layout<V, Option<AnyElement<V>>> {
|
||||||
pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
|
pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
|
||||||
let mut element = self.element_data.take().unwrap();
|
let mut element = self.element_data.take().unwrap();
|
||||||
element.paint(view, self.id, cx);
|
element.paint(view, cx);
|
||||||
self.element_data = Some(element);
|
self.element_data = Some(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Element<V: 'static>: 'static {
|
|
||||||
type Layout;
|
|
||||||
|
|
||||||
fn layout(
|
|
||||||
&mut self,
|
|
||||||
view: &mut V,
|
|
||||||
cx: &mut LayoutContext<V>,
|
|
||||||
) -> Result<Layout<V, Self::Layout>>
|
|
||||||
where
|
|
||||||
Self: Sized;
|
|
||||||
|
|
||||||
fn paint(
|
|
||||||
&mut self,
|
|
||||||
view: &mut V,
|
|
||||||
layout: &mut Layout<V, Self::Layout>,
|
|
||||||
cx: &mut PaintContext<V>,
|
|
||||||
) where
|
|
||||||
Self: Sized;
|
|
||||||
|
|
||||||
fn into_any(self) -> AnyElement<V>
|
|
||||||
where
|
|
||||||
Self: 'static + Sized,
|
|
||||||
{
|
|
||||||
AnyElement(Box::new(ElementState {
|
|
||||||
element: self,
|
|
||||||
layout: None,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used to make ElementState<V, E> into a trait object, so we can wrap it in AnyElement<V>.
|
|
||||||
trait ElementStateObject<V> {
|
|
||||||
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId>;
|
|
||||||
fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext<V>);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A wrapper around an element that stores its layout state.
|
|
||||||
struct ElementState<V: 'static, E: Element<V>> {
|
|
||||||
element: E,
|
|
||||||
layout: Option<Layout<V, E::Layout>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// We blanket-implement the object-safe ElementStateObject interface to make ElementStates into trait objects
|
|
||||||
impl<V, E: Element<V>> ElementStateObject<V> for ElementState<V, E> {
|
|
||||||
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
|
|
||||||
let layout = self.element.layout(view, cx)?;
|
|
||||||
let layout_id = layout.id;
|
|
||||||
self.layout = Some(layout);
|
|
||||||
Ok(layout_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext<V>) {
|
|
||||||
let layout = self.layout.as_mut().expect("paint called before layout");
|
|
||||||
if layout.engine_layout.is_none() {
|
|
||||||
layout.engine_layout = cx.computed_layout(layout_id).log_err()
|
|
||||||
}
|
|
||||||
self.element.paint(view, layout, cx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A dynamic element.
|
|
||||||
pub struct AnyElement<V>(Box<dyn ElementStateObject<V>>);
|
|
||||||
|
|
||||||
impl<V> AnyElement<V> {
|
|
||||||
pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
|
|
||||||
self.0.layout(view, cx)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext<V>) {
|
|
||||||
self.0.paint(view, layout_id, cx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ParentElement<V: 'static> {
|
pub trait ParentElement<V: 'static> {
|
||||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
|
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
|
||||||
|
|
||||||
|
|
|
@ -42,14 +42,6 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<V, E> {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
if self.hovered.get() {
|
|
||||||
// If hovered, refine the child's style with this element's style.
|
|
||||||
self.child.declared_style().refine(&self.hovered_style);
|
|
||||||
} else {
|
|
||||||
// Otherwise, set the child's style back to its original style.
|
|
||||||
*self.child.declared_style() = self.child_style.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.child.layout(view, cx)
|
self.child.layout(view, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,10 +53,24 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<V, E> {
|
||||||
) where
|
) where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
if self.hovered.get() {
|
||||||
|
// If hovered, refine the child's style with this element's style.
|
||||||
|
self.child.declared_style().refine(&self.hovered_style);
|
||||||
|
} else {
|
||||||
|
// Otherwise, set the child's style back to its original style.
|
||||||
|
*self.child.declared_style() = self.child_style.clone();
|
||||||
|
}
|
||||||
|
|
||||||
let bounds = layout.bounds(cx);
|
let bounds = layout.bounds(cx);
|
||||||
let order = layout.order(cx);
|
let order = layout.order(cx);
|
||||||
self.hovered.set(bounds.contains_point(cx.mouse_position()));
|
self.hovered.set(bounds.contains_point(cx.mouse_position()));
|
||||||
let hovered = self.hovered.clone();
|
let was_hovered = self.hovered.clone();
|
||||||
cx.on_event(order, move |view, event: &MouseMovedEvent, cx| {});
|
cx.on_event(order, move |view, event: &MouseMovedEvent, cx| {
|
||||||
|
let is_hovered = bounds.contains_point(event.position);
|
||||||
|
if is_hovered != was_hovered.get() {
|
||||||
|
was_hovered.set(is_hovered);
|
||||||
|
cx.repaint();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
34
crates/gpui/playground/src/interactive.rs
Normal file
34
crates/gpui/playground/src/interactive.rs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
use gpui::{platform::MouseMovedEvent, EventContext};
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub trait Interactive<V: 'static> {
|
||||||
|
fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V>;
|
||||||
|
|
||||||
|
fn on_mouse_move<H>(mut self, handler: H) -> Self
|
||||||
|
where
|
||||||
|
H: 'static + Fn(&mut V, &MouseMovedEvent, bool, &mut EventContext<V>),
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.interaction_handlers()
|
||||||
|
.mouse_moved
|
||||||
|
.push(Rc::new(move |view, event, hit_test, cx| {
|
||||||
|
handler(view, event, hit_test, cx);
|
||||||
|
cx.bubble
|
||||||
|
}));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InteractionHandlers<V: 'static> {
|
||||||
|
mouse_moved:
|
||||||
|
SmallVec<[Rc<dyn Fn(&mut V, &MouseMovedEvent, bool, &mut EventContext<V>) -> bool>; 2]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V> Default for InteractionHandlers<V> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
mouse_moved: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,6 @@
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
use gpui::{
|
use gpui::{scene::EventHandler, EngineLayout, EventContext, LayoutId, RenderContext, ViewContext};
|
||||||
geometry::rect::RectF, scene::EventHandler, EngineLayout, EventContext, LayoutId,
|
|
||||||
RenderContext, ViewContext,
|
|
||||||
};
|
|
||||||
pub use gpui::{LayoutContext, PaintContext as LegacyPaintContext};
|
pub use gpui::{LayoutContext, PaintContext as LegacyPaintContext};
|
||||||
use std::{any::TypeId, rc::Rc};
|
use std::{any::TypeId, rc::Rc};
|
||||||
pub use taffy::tree::NodeId;
|
pub use taffy::tree::NodeId;
|
||||||
|
@ -47,48 +44,25 @@ impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> {
|
||||||
order: u32,
|
order: u32,
|
||||||
handler: impl Fn(&mut V, &E, &mut ViewContext<V>) + 'static,
|
handler: impl Fn(&mut V, &E, &mut ViewContext<V>) + 'static,
|
||||||
) {
|
) {
|
||||||
|
let view = self.weak_handle();
|
||||||
|
|
||||||
self.scene.event_handlers.push(EventHandler {
|
self.scene.event_handlers.push(EventHandler {
|
||||||
order,
|
order,
|
||||||
handler: Rc::new(move |view, event, window_cx, view_id| {
|
handler: Rc::new(move |event, window_cx| {
|
||||||
let mut view_context = ViewContext::mutable(window_cx, view_id);
|
if let Some(view) = view.upgrade(window_cx) {
|
||||||
handler(
|
view.update(window_cx, |view, view_cx| {
|
||||||
view.downcast_mut().unwrap(),
|
let mut event_cx = EventContext::new(view_cx);
|
||||||
event.downcast_ref().unwrap(),
|
handler(view, event.downcast_ref().unwrap(), &mut event_cx);
|
||||||
&mut view_context,
|
event_cx.bubble
|
||||||
);
|
})
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
event_type: TypeId::of::<E>(),
|
event_type: TypeId::of::<E>(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_interactive_region<E: 'static>(
|
|
||||||
&mut self,
|
|
||||||
order: u32,
|
|
||||||
bounds: RectF,
|
|
||||||
outside_bounds: bool,
|
|
||||||
event_handler: impl Fn(&mut V, &E, &mut EventContext<V>) + 'static,
|
|
||||||
) {
|
|
||||||
// We'll sort these later when `take_interactive_regions` is called.
|
|
||||||
self.scene
|
|
||||||
.interactive_regions
|
|
||||||
.push(gpui::scene::InteractiveRegion {
|
|
||||||
order,
|
|
||||||
bounds,
|
|
||||||
outside_bounds,
|
|
||||||
event_handler: Rc::new(move |view, event, window_cx, view_id| {
|
|
||||||
let mut view_context = ViewContext::mutable(window_cx, view_id);
|
|
||||||
let mut event_context = EventContext::new(&mut view_context);
|
|
||||||
event_handler(
|
|
||||||
view.downcast_mut().unwrap(),
|
|
||||||
event.downcast_ref().unwrap(),
|
|
||||||
&mut event_context,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
event_type: TypeId::of::<E>(),
|
|
||||||
view_id: self.view_id(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn computed_layout(&mut self, layout_id: LayoutId) -> Result<EngineLayout> {
|
pub(crate) fn computed_layout(&mut self, layout_id: LayoutId) -> Result<EngineLayout> {
|
||||||
self.layout_engine()
|
self.layout_engine()
|
||||||
.ok_or_else(|| anyhow!("no layout engine present"))?
|
.ok_or_else(|| anyhow!("no layout engine present"))?
|
||||||
|
|
|
@ -16,6 +16,7 @@ mod components;
|
||||||
mod div;
|
mod div;
|
||||||
mod element;
|
mod element;
|
||||||
mod hoverable;
|
mod hoverable;
|
||||||
|
mod interactive;
|
||||||
mod layout_context;
|
mod layout_context;
|
||||||
mod paint_context;
|
mod paint_context;
|
||||||
mod style;
|
mod style;
|
||||||
|
|
|
@ -4680,18 +4680,37 @@ impl<V: 'static> WeakViewHandle<V> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update<T>(
|
pub fn update<T, B>(
|
||||||
&self,
|
&self,
|
||||||
cx: &mut AsyncAppContext,
|
cx: &mut B,
|
||||||
update: impl FnOnce(&mut V, &mut ViewContext<V>) -> T,
|
update: impl FnOnce(&mut V, &mut ViewContext<V>) -> T,
|
||||||
) -> Result<T> {
|
) -> Result<T>
|
||||||
cx.update(|cx| {
|
where
|
||||||
let handle = cx
|
B: BorrowWindowContext,
|
||||||
.upgrade_view_handle(self)
|
B::Result<Option<T>>: Flatten<T>,
|
||||||
.ok_or_else(|| anyhow!("view was dropped"))?;
|
{
|
||||||
cx.update_window(self.window, |cx| handle.update(cx, update))
|
cx.update_window(self.window(), |cx| {
|
||||||
.ok_or_else(|| anyhow!("window was removed"))
|
cx.upgrade_view_handle(self)
|
||||||
|
.map(|handle| handle.update(cx, update))
|
||||||
})
|
})
|
||||||
|
.flatten()
|
||||||
|
.ok_or_else(|| anyhow!("window was removed"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Flatten<T> {
|
||||||
|
fn flatten(self) -> Option<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Flatten<T> for Option<Option<T>> {
|
||||||
|
fn flatten(self) -> Option<T> {
|
||||||
|
self.flatten()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Flatten<T> for Option<T> {
|
||||||
|
fn flatten(self) -> Option<T> {
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,9 @@ use crate::{
|
||||||
MouseButton, MouseMovedEvent, PromptLevel, WindowBounds,
|
MouseButton, MouseMovedEvent, PromptLevel, WindowBounds,
|
||||||
},
|
},
|
||||||
scene::{
|
scene::{
|
||||||
CursorRegion, InteractiveRegion, MouseClick, MouseClickOut, MouseDown, MouseDownOut,
|
CursorRegion, EventHandler, MouseClick, MouseClickOut, MouseDown, MouseDownOut, MouseDrag,
|
||||||
MouseDrag, MouseEvent, MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp,
|
MouseEvent, MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut,
|
||||||
MouseUpOut, Scene,
|
Scene,
|
||||||
},
|
},
|
||||||
text_layout::TextLayoutCache,
|
text_layout::TextLayoutCache,
|
||||||
util::post_inc,
|
util::post_inc,
|
||||||
|
@ -57,7 +57,7 @@ pub struct Window {
|
||||||
appearance: Appearance,
|
appearance: Appearance,
|
||||||
cursor_regions: Vec<CursorRegion>,
|
cursor_regions: Vec<CursorRegion>,
|
||||||
mouse_regions: Vec<(MouseRegion, usize)>,
|
mouse_regions: Vec<(MouseRegion, usize)>,
|
||||||
interactive_regions: Vec<InteractiveRegion>,
|
event_handlers: Vec<EventHandler>,
|
||||||
last_mouse_moved_event: Option<Event>,
|
last_mouse_moved_event: Option<Event>,
|
||||||
pub(crate) hovered_region_ids: Vec<MouseRegionId>,
|
pub(crate) hovered_region_ids: Vec<MouseRegionId>,
|
||||||
pub(crate) clicked_region_ids: Vec<MouseRegionId>,
|
pub(crate) clicked_region_ids: Vec<MouseRegionId>,
|
||||||
|
@ -91,7 +91,7 @@ impl Window {
|
||||||
rendered_views: Default::default(),
|
rendered_views: Default::default(),
|
||||||
cursor_regions: Default::default(),
|
cursor_regions: Default::default(),
|
||||||
mouse_regions: Default::default(),
|
mouse_regions: Default::default(),
|
||||||
interactive_regions: Vec::new(),
|
event_handlers: Default::default(),
|
||||||
text_layout_cache: TextLayoutCache::new(cx.font_system.clone()),
|
text_layout_cache: TextLayoutCache::new(cx.font_system.clone()),
|
||||||
last_mouse_moved_event: None,
|
last_mouse_moved_event: None,
|
||||||
hovered_region_ids: Default::default(),
|
hovered_region_ids: Default::default(),
|
||||||
|
@ -119,8 +119,8 @@ impl Window {
|
||||||
.expect("root_view called during window construction")
|
.expect("root_view called during window construction")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_interactive_regions(&mut self) -> Vec<InteractiveRegion> {
|
pub fn take_event_handlers(&mut self) -> Vec<EventHandler> {
|
||||||
mem::take(&mut self.interactive_regions)
|
mem::take(&mut self.event_handlers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -889,26 +889,13 @@ impl<'a> WindowContext<'a> {
|
||||||
fn dispatch_to_interactive_regions(&mut self, event: &Event) {
|
fn dispatch_to_interactive_regions(&mut self, event: &Event) {
|
||||||
if let Some(mouse_event) = event.mouse_event() {
|
if let Some(mouse_event) = event.mouse_event() {
|
||||||
let mouse_position = event.position().expect("mouse events must have a position");
|
let mouse_position = event.position().expect("mouse events must have a position");
|
||||||
let interactive_regions = self.window.take_interactive_regions();
|
let event_handlers = self.window.take_event_handlers();
|
||||||
|
for event_handler in event_handlers.iter().rev() {
|
||||||
for region in interactive_regions.iter().rev() {
|
if event_handler.event_type == mouse_event.type_id() {
|
||||||
if region.event_type == mouse_event.type_id() {
|
(event_handler.handler)(mouse_event, self);
|
||||||
let in_bounds = region.bounds.contains_point(mouse_position);
|
|
||||||
|
|
||||||
if in_bounds == !region.outside_bounds {
|
|
||||||
self.update_any_view(region.view_id, |view, window_cx| {
|
|
||||||
(region.event_handler)(
|
|
||||||
view.as_any_mut(),
|
|
||||||
mouse_event,
|
|
||||||
window_cx,
|
|
||||||
region.view_id,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.window.event_handlers = event_handlers;
|
||||||
self.window.interactive_regions = interactive_regions;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1066,7 +1053,7 @@ impl<'a> WindowContext<'a> {
|
||||||
let mut scene = scene_builder.build();
|
let mut scene = scene_builder.build();
|
||||||
self.window.cursor_regions = scene.cursor_regions();
|
self.window.cursor_regions = scene.cursor_regions();
|
||||||
self.window.mouse_regions = scene.mouse_regions();
|
self.window.mouse_regions = scene.mouse_regions();
|
||||||
self.window.interactive_regions = scene.take_interactive_regions();
|
self.window.event_handlers = scene.take_event_handlers();
|
||||||
|
|
||||||
if self.window_is_active() {
|
if self.window_is_active() {
|
||||||
if let Some(event) = self.window.last_mouse_moved_event.clone() {
|
if let Some(event) = self.window.last_mouse_moved_event.clone() {
|
||||||
|
|
|
@ -31,8 +31,6 @@ pub struct SceneBuilder {
|
||||||
scale_factor: f32,
|
scale_factor: f32,
|
||||||
stacking_contexts: Vec<StackingContext>,
|
stacking_contexts: Vec<StackingContext>,
|
||||||
active_stacking_context_stack: Vec<usize>,
|
active_stacking_context_stack: Vec<usize>,
|
||||||
/// Used by the playground crate. I hope to replace it with event_handlers.
|
|
||||||
pub interactive_regions: Vec<InteractiveRegion>,
|
|
||||||
/// Used by the playground crate.
|
/// Used by the playground crate.
|
||||||
pub event_handlers: Vec<EventHandler>,
|
pub event_handlers: Vec<EventHandler>,
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
@ -42,7 +40,6 @@ pub struct SceneBuilder {
|
||||||
pub struct Scene {
|
pub struct Scene {
|
||||||
scale_factor: f32,
|
scale_factor: f32,
|
||||||
stacking_contexts: Vec<StackingContext>,
|
stacking_contexts: Vec<StackingContext>,
|
||||||
interactive_regions: Vec<InteractiveRegion>,
|
|
||||||
event_handlers: Vec<EventHandler>,
|
event_handlers: Vec<EventHandler>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,15 +282,9 @@ impl Scene {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO: Hoping to replace this with take_event_handlers
|
|
||||||
pub fn take_interactive_regions(&mut self) -> Vec<InteractiveRegion> {
|
|
||||||
self.interactive_regions
|
|
||||||
.sort_by(|a, b| a.order.cmp(&b.order));
|
|
||||||
std::mem::take(&mut self.interactive_regions)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn take_event_handlers(&mut self) -> Vec<EventHandler> {
|
pub fn take_event_handlers(&mut self) -> Vec<EventHandler> {
|
||||||
self.event_handlers.sort_by(|a, b| a.order.cmp(&b.order));
|
self.event_handlers
|
||||||
|
.sort_by(|a, b| a.order.cmp(&b.order).reverse());
|
||||||
std::mem::take(&mut self.event_handlers)
|
std::mem::take(&mut self.event_handlers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -307,7 +298,6 @@ impl SceneBuilder {
|
||||||
active_stacking_context_stack: vec![0],
|
active_stacking_context_stack: vec![0],
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
mouse_region_ids: Default::default(),
|
mouse_region_ids: Default::default(),
|
||||||
interactive_regions: Vec::new(),
|
|
||||||
event_handlers: Vec::new(),
|
event_handlers: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -318,7 +308,6 @@ impl SceneBuilder {
|
||||||
Scene {
|
Scene {
|
||||||
scale_factor: self.scale_factor,
|
scale_factor: self.scale_factor,
|
||||||
stacking_contexts: self.stacking_contexts,
|
stacking_contexts: self.stacking_contexts,
|
||||||
interactive_regions: self.interactive_regions,
|
|
||||||
event_handlers: self.event_handlers,
|
event_handlers: self.event_handlers,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -716,23 +705,10 @@ impl MouseRegion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is currently only used in the playground crate. It represents a region
|
|
||||||
/// with which the user can interact via a pointing device. It aims to replace
|
|
||||||
/// MouseRegion and CursorRegion.
|
|
||||||
pub struct InteractiveRegion {
|
|
||||||
pub order: u32,
|
|
||||||
pub bounds: RectF,
|
|
||||||
pub outside_bounds: bool,
|
|
||||||
pub event_handler: Rc<dyn Fn(&mut dyn Any, &dyn Any, &mut WindowContext, usize)>,
|
|
||||||
pub event_type: TypeId,
|
|
||||||
pub view_id: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EventHandler {
|
pub struct EventHandler {
|
||||||
pub order: u32,
|
pub order: u32,
|
||||||
// First param is a dynamic view reference
|
// The &dyn Any parameter below expects an event.
|
||||||
// Second param is a dynamic event reference
|
pub handler: Rc<dyn Fn(&dyn Any, &mut WindowContext) -> bool>,
|
||||||
pub handler: Rc<dyn Fn(&mut dyn Any, &dyn Any, &mut WindowContext, usize)>,
|
|
||||||
pub event_type: TypeId,
|
pub event_type: TypeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue