Checkpoint

This commit is contained in:
Nathan Sobo 2023-10-11 12:47:43 -06:00
parent e2da2b232e
commit 47b64a5074
11 changed files with 197 additions and 61 deletions

View file

@ -1,4 +1,9 @@
use crate::{BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, ViewContext};
use std::sync::Arc;
use crate::{
BorrowWindow, Bounds, Clickable, ElementId, LayoutId, MouseDownEvent, MouseUpEvent, Pixels,
Point, ViewContext,
};
use derive_more::{Deref, DerefMut};
pub(crate) use smallvec::SmallVec;
@ -24,10 +29,26 @@ pub trait Element: 'static + Send + Sync {
);
}
pub trait StatefulElement: Element {
pub trait IdentifiedElement: Element {
fn element_id(&self) -> ElementId {
Element::element_id(self).unwrap()
}
fn on_click(
self,
listener: impl Fn(
&mut Self::ViewState,
(&MouseDownEvent, &MouseUpEvent),
&mut ViewContext<Self::ViewState>,
) + Send
+ Sync
+ 'static,
) -> Clickable<Self>
where
Self: Sized,
{
Clickable::new(self, Arc::from(listener))
}
}
#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]

View file

@ -1,3 +1,4 @@
mod clickable;
mod div;
mod hoverable;
mod identified;
@ -6,6 +7,7 @@ mod pressable;
mod svg;
mod text;
pub use clickable::*;
pub use div::*;
pub use hoverable::*;
pub use identified::*;

View file

@ -0,0 +1,138 @@
use crate::{
AnyElement, Bounds, DispatchPhase, Element, IdentifiedElement, Interactive, MouseDownEvent,
MouseEventListeners, MouseUpEvent, ParentElement, Pixels, Styled, ViewContext,
};
use parking_lot::Mutex;
use refineable::RefinementCascade;
use smallvec::SmallVec;
use std::sync::Arc;
pub type ClickListener<S> =
dyn Fn(&mut S, (&MouseDownEvent, &MouseUpEvent), &mut ViewContext<S>) + Send + Sync + 'static;
pub struct Clickable<E: Element> {
child: E,
listener: Arc<ClickListener<E::ViewState>>,
}
pub struct ClickableState<S> {
last_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
child_state: S,
}
impl<E: Element> Clickable<E> {
pub fn new(child: E, listener: Arc<ClickListener<E::ViewState>>) -> Self {
Self { child, listener }
}
}
impl<E> Styled for Clickable<E>
where
E: Styled + IdentifiedElement,
{
type Style = E::Style;
fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
self.child.style_cascade()
}
fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
self.child.declared_style()
}
}
impl<S, E> Interactive<S> for Clickable<E>
where
S: 'static + Send + Sync,
E: IdentifiedElement + Interactive<S>,
{
fn listeners(&mut self) -> &mut MouseEventListeners<S> {
self.child.listeners()
}
}
impl<E> Element for Clickable<E>
where
E: IdentifiedElement,
{
type ViewState = E::ViewState;
type ElementState = ClickableState<E::ElementState>;
fn element_id(&self) -> Option<crate::ElementId> {
Some(IdentifiedElement::element_id(&self.child))
}
fn layout(
&mut self,
state: &mut Self::ViewState,
element_state: Option<Self::ElementState>,
cx: &mut ViewContext<Self::ViewState>,
) -> (crate::LayoutId, Self::ElementState) {
if let Some(element_state) = element_state {
let (layout_id, child_state) =
self.child
.layout(state, Some(element_state.child_state), cx);
let element_state = ClickableState {
last_mouse_down: element_state.last_mouse_down,
child_state,
};
(layout_id, element_state)
} else {
let (layout_id, child_state) = self.child.layout(state, None, cx);
let element_state = ClickableState {
last_mouse_down: Default::default(),
child_state,
};
(layout_id, element_state)
}
}
fn paint(
&mut self,
bounds: Bounds<Pixels>,
state: &mut Self::ViewState,
element_state: &mut Self::ElementState,
cx: &mut ViewContext<Self::ViewState>,
) {
let last_mouse_down = element_state.last_mouse_down.clone();
let is_some = last_mouse_down.lock().is_some();
if is_some {
let listener = self.listener.clone();
cx.on_mouse_event(move |view, up_event: &MouseUpEvent, phase, cx| {
if phase == DispatchPhase::Capture && !bounds.contains_point(up_event.position) {
*last_mouse_down.lock() = None;
} else if phase == DispatchPhase::Bubble && bounds.contains_point(up_event.position)
{
if let Some(down_event) = last_mouse_down.lock().take() {
listener(view, (&down_event, up_event), cx);
} else {
log::error!("No mouse down event found for click event");
}
}
})
} else {
cx.on_mouse_event(move |_, event: &MouseDownEvent, phase, _| {
if phase == DispatchPhase::Bubble {
if bounds.contains_point(event.position) {
*last_mouse_down.lock() = Some(event.clone());
}
}
})
}
self.child
.paint(bounds, state, &mut element_state.child_state, cx);
}
}
impl<E: IdentifiedElement + ParentElement> ParentElement for Clickable<E> {
type State = E::State;
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
self.child.children_mut()
}
}
impl<E> IdentifiedElement for Clickable<E> where E: IdentifiedElement + Styled {}

View file

@ -1,7 +1,7 @@
use crate::{
AnyElement, Bounds, Element, ElementId, Interactive, LayoutId, MouseEventListeners, Overflow,
ParentElement, Pixels, Point, Refineable, RefinementCascade, StatefulElement, Style, Styled,
ViewContext,
AnyElement, Bounds, Element, ElementId, IdentifiedElement, Interactive, LayoutId,
MouseEventListeners, Overflow, ParentElement, Pixels, Point, Refineable, RefinementCascade,
Style, Styled, ViewContext,
};
use parking_lot::Mutex;
use smallvec::SmallVec;
@ -171,7 +171,7 @@ impl<V: 'static + Send + Sync, Marker: 'static + Send + Sync> Styled for Div<V,
}
}
impl<V: Send + Sync + 'static> StatefulElement for Div<V, HasId> {}
impl<V: Send + Sync + 'static> IdentifiedElement for Div<V, HasId> {}
impl<V: Send + Sync + 'static> Interactive<V> for Div<V, HasId> {
fn listeners(&mut self) -> &mut MouseEventListeners<V> {
@ -179,10 +179,10 @@ impl<V: Send + Sync + 'static> Interactive<V> for Div<V, HasId> {
}
}
impl<S: 'static> ParentElement for Div<S> {
type State = S;
impl<V: 'static, Marker: 'static + Send + Sync> ParentElement for Div<V, Marker> {
type State = V;
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<S>; 2]> {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
&mut self.children
}
}

View file

@ -1,6 +1,6 @@
use crate::{
AnyElement, Bounds, DispatchPhase, Element, ElementId, Interactive, MouseEventListeners,
MouseMoveEvent, ParentElement, Pixels, StatefulElement, Styled, ViewContext,
AnyElement, Bounds, DispatchPhase, Element, ElementId, IdentifiedElement, Interactive,
MouseEventListeners, MouseMoveEvent, ParentElement, Pixels, Styled, ViewContext,
};
use refineable::{CascadeSlot, Refineable, RefinementCascade};
use smallvec::SmallVec;
@ -104,9 +104,9 @@ impl<E: ParentElement + Styled> ParentElement for Hoverable<E> {
}
}
impl<E> StatefulElement for Hoverable<E>
impl<E> IdentifiedElement for Hoverable<E>
where
E: StatefulElement + Styled,
E: IdentifiedElement + Styled,
<E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
<<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
{

View file

@ -2,8 +2,8 @@ use refineable::{Refineable, RefinementCascade};
use smallvec::SmallVec;
use crate::{
AnyElement, BorrowWindow, Bounds, Element, ElementId, LayoutId, ParentElement, StatefulElement,
Styled, ViewContext,
AnyElement, BorrowWindow, Bounds, Element, ElementId, IdentifiedElement, LayoutId,
ParentElement, Styled, ViewContext,
};
pub struct Identified<E> {
@ -41,7 +41,7 @@ impl<E: Element> Element for Identified<E> {
}
}
impl<E: Element> StatefulElement for Identified<E> {}
impl<E: Element> IdentifiedElement for Identified<E> {}
impl<E: Styled> Styled for Identified<E> {
type Style = E::Style;

View file

@ -1,6 +1,6 @@
use crate::{
AnyElement, Bounds, DispatchPhase, Element, Interactive, MouseDownEvent, MouseEventListeners,
MouseUpEvent, ParentElement, Pixels, StatefulElement, Styled, ViewContext,
AnyElement, Bounds, DispatchPhase, Element, IdentifiedElement, Interactive, MouseDownEvent,
MouseEventListeners, MouseUpEvent, ParentElement, Pixels, Styled, ViewContext,
};
use refineable::{CascadeSlot, Refineable, RefinementCascade};
use smallvec::SmallVec;
@ -53,7 +53,7 @@ impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Pr
impl<E> Element for Pressable<E>
where
E: Styled + StatefulElement,
E: Styled + IdentifiedElement,
<E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
<<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
{
@ -61,7 +61,7 @@ where
type ElementState = PressableState<E::ElementState>;
fn element_id(&self) -> Option<crate::ElementId> {
Some(StatefulElement::element_id(&self.child))
Some(IdentifiedElement::element_id(&self.child))
}
fn layout(
@ -127,7 +127,10 @@ where
}
}
impl<E: ParentElement + Styled> ParentElement for Pressable<E> {
impl<E> ParentElement for Pressable<E>
where
E: ParentElement + IdentifiedElement + Styled,
{
type State = E::State;
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
@ -135,9 +138,9 @@ impl<E: ParentElement + Styled> ParentElement for Pressable<E> {
}
}
impl<E> StatefulElement for Pressable<E>
impl<E> IdentifiedElement for Pressable<E>
where
E: StatefulElement + Styled,
E: IdentifiedElement + Styled,
<E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
<<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
{

View file

@ -2,7 +2,6 @@ use crate::{
Bounds, DispatchPhase, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
ScrollWheelEvent, ViewContext,
};
use parking_lot::Mutex;
use smallvec::SmallVec;
use std::sync::Arc;
@ -93,37 +92,6 @@ pub trait Interactive<S: 'static + Send + Sync> {
self
}
fn on_click(
self,
button: MouseButton,
handler: impl Fn(&mut S, (&MouseDownEvent, &MouseUpEvent), &mut ViewContext<S>)
+ Send
+ Sync
+ 'static,
) -> Self
where
Self: Sized,
{
let down_event = Arc::new(Mutex::new(None));
self.on_mouse_down(button, {
let down_event = down_event.clone();
move |_, event, _| {
down_event.lock().replace(event.clone());
}
})
.on_mouse_up_out(button, {
let down_event = down_event.clone();
move |_, _, _| {
down_event.lock().take();
}
})
.on_mouse_up(button, move |view, event, cx| {
if let Some(down_event) = down_event.lock().take() {
handler(view, (&down_event, event), cx);
}
})
}
fn on_mouse_move(
mut self,
handler: impl Fn(&mut S, &MouseMoveEvent, &mut ViewContext<S>) + Send + Sync + 'static,

View file

@ -1,8 +1,8 @@
use crate::theme::{theme, Theme};
use gpui3::{
div, img, svg, view, AppContext, Context, Element, ElementId, IntoAnyElement, MouseButton,
ParentElement, ScrollState, SharedString, StyleHelpers, Styled, View, ViewContext,
WindowContext,
div, img, svg, view, AppContext, Context, Element, ElementId, IdentifiedElement,
IntoAnyElement, ParentElement, ScrollState, SharedString, StyleHelpers, Styled, View,
ViewContext, WindowContext,
};
pub struct CollabPanel {
@ -45,7 +45,8 @@ impl CollabPanel {
// List Container
.child(
div()
.on_click(MouseButton::Left, |_, _, _| {
.id(0)
.on_click(|_, _, _| {
dbg!("click!");
})
.fill(theme.lowest.base.default.background)

View file

@ -147,6 +147,10 @@ impl<E: Element> Element for Themed<E> {
type ViewState = E::ViewState;
type ElementState = E::ElementState;
fn element_id(&self) -> Option<gpui3::ElementId> {
None
}
fn layout(
&mut self,
state: &mut E::ViewState,

View file

@ -47,8 +47,7 @@ impl Workspace {
.flex_row()
.overflow_hidden()
.child(self.left_panel.clone())
.child(div().h_full().flex_1())
.child(self.right_panel.clone()),
.child(div().h_full().flex_1()), // .child(self.right_panel.clone()),
)
.child(statusbar::statusbar(cx))
})