diff --git a/crates/gpui/playground/src/div.rs b/crates/gpui/playground/src/div.rs index 73f196b4f07088cd3d007b071759a18eb373b164..98cebfe4ea84bcb3c061fe504d4b8444e9c60340 100644 --- a/crates/gpui/playground/src/div.rs +++ b/crates/gpui/playground/src/div.rs @@ -1,5 +1,5 @@ use crate::{ - element::{AnyElement, Element, Layout, ParentElement}, + element::{AnyElement, Element, IntoElement, Layout, ParentElement}, interactive::{InteractionHandlers, Interactive}, layout_context::LayoutContext, paint_context::PaintContext, @@ -47,6 +47,8 @@ impl Element for Div { { self.computed_style() .paint_background(layout.bounds(cx), cx); + self.interaction_handlers() + .paint(layout.order(cx), layout.bounds(cx), cx); for child in &mut self.children { child.paint(view, cx); } @@ -79,35 +81,10 @@ impl ParentElement for Div { } } -#[test] -fn test() { - // let elt = div().w_auto(); -} - -// trait Element { -// type Style; - -// fn layout() -// } - -// trait Stylable: Element { -// type Style; - -// fn with_style(self, style: Self::Style) -> Self; -// } +impl IntoElement for Div { + type Element = Self; -// pub struct HoverStyle { -// default: S, -// hovered: S, -// } - -// struct Hover> { -// child: C, -// style: HoverStyle, -// } - -// impl> Hover { -// fn new(child: C, style: HoverStyle) -> Self { -// Self { child, style } -// } -// } + fn into_element(self) -> Self::Element { + self + } +} diff --git a/crates/gpui/playground/src/hoverable.rs b/crates/gpui/playground/src/hoverable.rs index 5aec6dd85e37c201de74f6ab2336e6b26aa6e7d3..7da8334225fe3743f999692aacba63931517bbbf 100644 --- a/crates/gpui/playground/src/hoverable.rs +++ b/crates/gpui/playground/src/hoverable.rs @@ -1,5 +1,6 @@ use crate::{ - element::{Element, Layout}, + element::{AnyElement, Element, IntoElement, Layout, ParentElement}, + interactive::{InteractionHandlers, Interactive}, layout_context::LayoutContext, paint_context::PaintContext, style::{Style, StyleHelpers, Styleable}, @@ -7,6 +8,7 @@ use crate::{ use anyhow::Result; use gpui::platform::MouseMovedEvent; use refineable::{CascadeSlot, Refineable, RefinementCascade}; +use smallvec::SmallVec; use std::{cell::Cell, rc::Rc}; pub struct Hoverable { @@ -76,3 +78,23 @@ impl + Styleable> Element for Hoverable { } impl> StyleHelpers for Hoverable {} + +impl + Styleable> Interactive for Hoverable { + fn interaction_handlers(&mut self) -> &mut InteractionHandlers { + self.child.interaction_handlers() + } +} + +impl + Styleable> ParentElement for Hoverable { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { + self.child.children_mut() + } +} + +impl + Styleable> IntoElement for Hoverable { + type Element = Self; + + fn into_element(self) -> Self::Element { + self + } +} diff --git a/crates/gpui/playground/src/interactive.rs b/crates/gpui/playground/src/interactive.rs index 8debcb1692cc5bcd42a8e65e82aa27ad6a02d4a0..3afe928b3e6dad9f09abac49c768df106903b2dd 100644 --- a/crates/gpui/playground/src/interactive.rs +++ b/crates/gpui/playground/src/interactive.rs @@ -1,34 +1,147 @@ -use gpui::{platform::MouseMovedEvent, EventContext}; +use gpui::{ + geometry::rect::RectF, + platform::{MouseButton, MouseButtonEvent}, + EventContext, +}; use smallvec::SmallVec; -use std::rc::Rc; +use std::{cell::Cell, rc::Rc}; + +use crate::element::PaintContext; pub trait Interactive { fn interaction_handlers(&mut self) -> &mut InteractionHandlers; - fn on_mouse_move(mut self, handler: H) -> Self + fn on_mouse_down( + mut self, + button: MouseButton, + handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext) + 'static, + ) -> Self where - H: 'static + Fn(&mut V, &MouseMovedEvent, bool, &mut EventContext), Self: Sized, { self.interaction_handlers() - .mouse_moved - .push(Rc::new(move |view, event, hit_test, cx| { - handler(view, event, hit_test, cx); - cx.bubble - })); + .mouse_down + .push(Rc::new(handler)); self } + + fn on_mouse_up( + mut self, + button: MouseButton, + handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext) + 'static, + ) -> Self + where + Self: Sized, + { + self.interaction_handlers().mouse_up.push(Rc::new(handler)); + self + } + + fn on_mouse_down_out( + mut self, + button: MouseButton, + handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext) + 'static, + ) -> Self + where + Self: Sized, + { + self.interaction_handlers() + .mouse_down_out + .push(Rc::new(handler)); + self + } + + fn on_mouse_up_out( + mut self, + button: MouseButton, + handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext) + 'static, + ) -> Self + where + Self: Sized, + { + self.interaction_handlers() + .mouse_up_out + .push(Rc::new(handler)); + self + } + + fn on_click( + self, + button: MouseButton, + handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext) + 'static, + ) -> Self + where + Self: Sized, + { + let pressed = Rc::new(Cell::new(false)); + self.on_mouse_down(button, { + let pressed = pressed.clone(); + move |_, _, _| { + pressed.set(true); + } + }) + .on_mouse_up_out(button, { + let pressed = pressed.clone(); + move |_, _, _| { + pressed.set(false); + } + }) + .on_mouse_up(button, move |view, event, cx| { + if pressed.get() { + pressed.set(false); + handler(view, event, cx); + } + }) + } } pub struct InteractionHandlers { - mouse_moved: - SmallVec<[Rc) -> bool>; 2]>, + mouse_down: SmallVec<[Rc)>; 2]>, + mouse_down_out: SmallVec<[Rc)>; 2]>, + mouse_up: SmallVec<[Rc)>; 2]>, + mouse_up_out: SmallVec<[Rc)>; 2]>, +} + +impl InteractionHandlers { + pub fn paint(&self, order: u32, bounds: RectF, cx: &mut PaintContext) { + for handler in self.mouse_down.iter().cloned() { + cx.on_event(order, move |view, event: &MouseButtonEvent, cx| { + if event.is_down && bounds.contains_point(event.position) { + handler(view, event, cx); + } + }) + } + for handler in self.mouse_up.iter().cloned() { + cx.on_event(order, move |view, event: &MouseButtonEvent, cx| { + if !event.is_down && bounds.contains_point(event.position) { + handler(view, event, cx); + } + }) + } + for handler in self.mouse_down_out.iter().cloned() { + cx.on_event(order, move |view, event: &MouseButtonEvent, cx| { + if event.is_down && !bounds.contains_point(event.position) { + handler(view, event, cx); + } + }) + } + for handler in self.mouse_up_out.iter().cloned() { + cx.on_event(order, move |view, event: &MouseButtonEvent, cx| { + if !event.is_down && !bounds.contains_point(event.position) { + handler(view, event, cx); + } + }) + } + } } impl Default for InteractionHandlers { fn default() -> Self { Self { - mouse_moved: Default::default(), + mouse_down: Default::default(), + mouse_up: Default::default(), + mouse_down_out: Default::default(), + mouse_up_out: Default::default(), } } } diff --git a/crates/gpui/playground/src/paint_context.rs b/crates/gpui/playground/src/paint_context.rs index d853aff7f85ff4b8b434dffb6e99caca9f91d0d2..e3e8c2b1515b8806bed0f45a26b0958ce595b7b9 100644 --- a/crates/gpui/playground/src/paint_context.rs +++ b/crates/gpui/playground/src/paint_context.rs @@ -42,7 +42,7 @@ impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> { pub fn on_event( &mut self, order: u32, - handler: impl Fn(&mut V, &E, &mut ViewContext) + 'static, + handler: impl Fn(&mut V, &E, &mut EventContext) + 'static, ) { let view = self.weak_handle(); diff --git a/crates/gpui/playground/src/playground.rs b/crates/gpui/playground/src/playground.rs index e387aeb7d21ec3041477c53d8dde188d1d09752d..486f1b20b79183c9c5b784e6b4b6bb989888f200 100644 --- a/crates/gpui/playground/src/playground.rs +++ b/crates/gpui/playground/src/playground.rs @@ -1,6 +1,7 @@ #![allow(dead_code, unused_variables)] use crate::{ color::black, + element::ParentElement, style::{StyleHelpers, Styleable}, }; use element::Element; @@ -59,7 +60,14 @@ fn playground(theme: &ThemeColors) -> impl Element { .fill(theme.error(0.5)) .pressed() .fill(theme.warning(0.5)) - // .child(button().label("Hello").click(|_, _, _| println!("click!"))) + .child( + div() + .h_6() + .w_6() + .absolute() + .bottom_0() + .fill(theme.success(0.)), + ) } // todo!() diff --git a/crates/gpui/playground/src/pressable.rs b/crates/gpui/playground/src/pressable.rs index 1428bf402116a88a65921fb83bcbc91b6b45a27c..a6d35d65c8e6b59ea501360c4953a6fda5e4acba 100644 --- a/crates/gpui/playground/src/pressable.rs +++ b/crates/gpui/playground/src/pressable.rs @@ -1,5 +1,6 @@ use crate::{ - element::{Element, Layout}, + element::{AnyElement, Element, IntoElement, Layout, ParentElement}, + interactive::{InteractionHandlers, Interactive}, layout_context::LayoutContext, paint_context::PaintContext, style::{Style, StyleHelpers, Styleable}, @@ -7,6 +8,7 @@ use crate::{ use anyhow::Result; use gpui::platform::MouseButtonEvent; use refineable::{CascadeSlot, Refineable, RefinementCascade}; +use smallvec::SmallVec; use std::{cell::Cell, rc::Rc}; pub struct Pressable { @@ -79,3 +81,23 @@ impl + Styleable> Element for Pressable { } impl> StyleHelpers for Pressable {} + +impl + Styleable> Interactive for Pressable { + fn interaction_handlers(&mut self) -> &mut InteractionHandlers { + self.child.interaction_handlers() + } +} + +impl + Styleable> ParentElement for Pressable { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { + self.child.children_mut() + } +} + +impl + Styleable> IntoElement for Pressable { + type Element = Self; + + fn into_element(self) -> Self::Element { + self + } +} diff --git a/crates/gpui/playground/src/style.rs b/crates/gpui/playground/src/style.rs index f2a64348d2cf089444f68f457985fc8a5934d630..0decdb232f117bfbdfc6ce9ea11260bb7bca46c5 100644 --- a/crates/gpui/playground/src/style.rs +++ b/crates/gpui/playground/src/style.rs @@ -274,6 +274,22 @@ pub trait Styleable { pub trait StyleHelpers: Styleable