Checkpoint
This commit is contained in:
parent
e2da2b232e
commit
47b64a5074
11 changed files with 197 additions and 61 deletions
|
@ -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};
|
use derive_more::{Deref, DerefMut};
|
||||||
pub(crate) use smallvec::SmallVec;
|
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 {
|
fn element_id(&self) -> ElementId {
|
||||||
Element::element_id(self).unwrap()
|
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)]
|
#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
mod clickable;
|
||||||
mod div;
|
mod div;
|
||||||
mod hoverable;
|
mod hoverable;
|
||||||
mod identified;
|
mod identified;
|
||||||
|
@ -6,6 +7,7 @@ mod pressable;
|
||||||
mod svg;
|
mod svg;
|
||||||
mod text;
|
mod text;
|
||||||
|
|
||||||
|
pub use clickable::*;
|
||||||
pub use div::*;
|
pub use div::*;
|
||||||
pub use hoverable::*;
|
pub use hoverable::*;
|
||||||
pub use identified::*;
|
pub use identified::*;
|
||||||
|
|
138
crates/gpui3/src/elements/clickable.rs
Normal file
138
crates/gpui3/src/elements/clickable.rs
Normal 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 {}
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyElement, Bounds, Element, ElementId, Interactive, LayoutId, MouseEventListeners, Overflow,
|
AnyElement, Bounds, Element, ElementId, IdentifiedElement, Interactive, LayoutId,
|
||||||
ParentElement, Pixels, Point, Refineable, RefinementCascade, StatefulElement, Style, Styled,
|
MouseEventListeners, Overflow, ParentElement, Pixels, Point, Refineable, RefinementCascade,
|
||||||
ViewContext,
|
Style, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use smallvec::SmallVec;
|
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> {
|
impl<V: Send + Sync + 'static> Interactive<V> for Div<V, HasId> {
|
||||||
fn listeners(&mut self) -> &mut MouseEventListeners<V> {
|
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> {
|
impl<V: 'static, Marker: 'static + Send + Sync> ParentElement for Div<V, Marker> {
|
||||||
type State = S;
|
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
|
&mut self.children
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyElement, Bounds, DispatchPhase, Element, ElementId, Interactive, MouseEventListeners,
|
AnyElement, Bounds, DispatchPhase, Element, ElementId, IdentifiedElement, Interactive,
|
||||||
MouseMoveEvent, ParentElement, Pixels, StatefulElement, Styled, ViewContext,
|
MouseEventListeners, MouseMoveEvent, ParentElement, Pixels, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
||||||
use smallvec::SmallVec;
|
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
|
where
|
||||||
E: StatefulElement + Styled,
|
E: IdentifiedElement + Styled,
|
||||||
<E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
|
<E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
|
||||||
<<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
|
<<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,8 @@ use refineable::{Refineable, RefinementCascade};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyElement, BorrowWindow, Bounds, Element, ElementId, LayoutId, ParentElement, StatefulElement,
|
AnyElement, BorrowWindow, Bounds, Element, ElementId, IdentifiedElement, LayoutId,
|
||||||
Styled, ViewContext,
|
ParentElement, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Identified<E> {
|
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> {
|
impl<E: Styled> Styled for Identified<E> {
|
||||||
type Style = E::Style;
|
type Style = E::Style;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyElement, Bounds, DispatchPhase, Element, Interactive, MouseDownEvent, MouseEventListeners,
|
AnyElement, Bounds, DispatchPhase, Element, IdentifiedElement, Interactive, MouseDownEvent,
|
||||||
MouseUpEvent, ParentElement, Pixels, StatefulElement, Styled, ViewContext,
|
MouseEventListeners, MouseUpEvent, ParentElement, Pixels, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
||||||
use smallvec::SmallVec;
|
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>
|
impl<E> Element for Pressable<E>
|
||||||
where
|
where
|
||||||
E: Styled + StatefulElement,
|
E: Styled + IdentifiedElement,
|
||||||
<E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
|
<E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
|
||||||
<<E as Styled>::Style as Refineable>::Refinement: '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>;
|
type ElementState = PressableState<E::ElementState>;
|
||||||
|
|
||||||
fn element_id(&self) -> Option<crate::ElementId> {
|
fn element_id(&self) -> Option<crate::ElementId> {
|
||||||
Some(StatefulElement::element_id(&self.child))
|
Some(IdentifiedElement::element_id(&self.child))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout(
|
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;
|
type State = E::State;
|
||||||
|
|
||||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
|
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
|
where
|
||||||
E: StatefulElement + Styled,
|
E: IdentifiedElement + Styled,
|
||||||
<E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
|
<E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
|
||||||
<<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
|
<<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,6 @@ use crate::{
|
||||||
Bounds, DispatchPhase, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
|
Bounds, DispatchPhase, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
|
||||||
ScrollWheelEvent, ViewContext,
|
ScrollWheelEvent, ViewContext,
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -93,37 +92,6 @@ pub trait Interactive<S: 'static + Send + Sync> {
|
||||||
self
|
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(
|
fn on_mouse_move(
|
||||||
mut self,
|
mut self,
|
||||||
handler: impl Fn(&mut S, &MouseMoveEvent, &mut ViewContext<S>) + Send + Sync + 'static,
|
handler: impl Fn(&mut S, &MouseMoveEvent, &mut ViewContext<S>) + Send + Sync + 'static,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::theme::{theme, Theme};
|
use crate::theme::{theme, Theme};
|
||||||
use gpui3::{
|
use gpui3::{
|
||||||
div, img, svg, view, AppContext, Context, Element, ElementId, IntoAnyElement, MouseButton,
|
div, img, svg, view, AppContext, Context, Element, ElementId, IdentifiedElement,
|
||||||
ParentElement, ScrollState, SharedString, StyleHelpers, Styled, View, ViewContext,
|
IntoAnyElement, ParentElement, ScrollState, SharedString, StyleHelpers, Styled, View,
|
||||||
WindowContext,
|
ViewContext, WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct CollabPanel {
|
pub struct CollabPanel {
|
||||||
|
@ -45,7 +45,8 @@ impl CollabPanel {
|
||||||
// List Container
|
// List Container
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.on_click(MouseButton::Left, |_, _, _| {
|
.id(0)
|
||||||
|
.on_click(|_, _, _| {
|
||||||
dbg!("click!");
|
dbg!("click!");
|
||||||
})
|
})
|
||||||
.fill(theme.lowest.base.default.background)
|
.fill(theme.lowest.base.default.background)
|
||||||
|
|
|
@ -147,6 +147,10 @@ impl<E: Element> Element for Themed<E> {
|
||||||
type ViewState = E::ViewState;
|
type ViewState = E::ViewState;
|
||||||
type ElementState = E::ElementState;
|
type ElementState = E::ElementState;
|
||||||
|
|
||||||
|
fn element_id(&self) -> Option<gpui3::ElementId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut E::ViewState,
|
state: &mut E::ViewState,
|
||||||
|
|
|
@ -47,8 +47,7 @@ impl Workspace {
|
||||||
.flex_row()
|
.flex_row()
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
.child(self.left_panel.clone())
|
.child(self.left_panel.clone())
|
||||||
.child(div().h_full().flex_1())
|
.child(div().h_full().flex_1()), // .child(self.right_panel.clone()),
|
||||||
.child(self.right_panel.clone()),
|
|
||||||
)
|
)
|
||||||
.child(statusbar::statusbar(cx))
|
.child(statusbar::statusbar(cx))
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue