From 3a70f02cbf2f4c0bd1e855190850b41afd47d42b Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 19 Oct 2023 23:21:26 +0200 Subject: [PATCH] Checkpoint --- crates/gpui3/src/element.rs | 156 ++++++++++++---- crates/gpui3/src/elements/div.rs | 98 ++-------- crates/ui2/src/prelude.rs | 4 +- crates/ui2/src/settings.rs | 311 +++++++++++++++---------------- 4 files changed, 290 insertions(+), 279 deletions(-) diff --git a/crates/gpui3/src/element.rs b/crates/gpui3/src/element.rs index 435cedd461..4457390171 100644 --- a/crates/gpui3/src/element.rs +++ b/crates/gpui3/src/element.rs @@ -1,10 +1,11 @@ use crate::{ - BorrowWindow, Bounds, DispatchPhase, ElementId, FocusHandle, FocusListeners, KeyDownEvent, - KeyListener, KeyMatch, LayoutId, MouseClickEvent, MouseClickListener, MouseDownEvent, - MouseDownListener, MouseMoveEvent, MouseMoveListener, MouseUpEvent, MouseUpListener, Pixels, - Point, ScrollWheelEvent, ScrollWheelListener, Style, StyleRefinement, ViewContext, - WindowContext, + AppContext, BorrowWindow, Bounds, DispatchPhase, ElementId, FocusHandle, FocusListeners, + KeyDownEvent, KeyListener, KeyMatch, LayoutId, MouseClickEvent, MouseClickListener, + MouseDownEvent, MouseDownListener, MouseMoveEvent, MouseMoveListener, MouseUpEvent, + MouseUpListener, Pixels, Point, ScrollWheelEvent, ScrollWheelListener, SharedString, Style, + StyleRefinement, ViewContext, WindowContext, }; +use collections::HashMap; use derive_more::{Deref, DerefMut}; use parking_lot::Mutex; use refineable::Refineable; @@ -49,6 +50,52 @@ pub trait ElementInteractivity: 'static + Send + Sync fn as_stateful(&self) -> Option<&StatefulInteractivity>; fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity>; + fn initialize( + &mut self, + cx: &mut ViewContext, + f: impl FnOnce(&mut ViewContext) -> R, + ) -> R { + if let Some(stateful) = self.as_stateful_mut() { + cx.with_element_id(stateful.id.clone(), |global_id, cx| { + stateful.key_listeners.push(( + TypeId::of::(), + Arc::new(move |_, key_down, context, phase, cx| { + if phase == DispatchPhase::Bubble { + let key_down = key_down.downcast_ref::().unwrap(); + if let KeyMatch::Some(action) = + cx.match_keystroke(&global_id, &key_down.keystroke, context) + { + return Some(action); + } + } + + None + }), + )); + let result = stateful.stateless.initialize(cx, f); + stateful.key_listeners.pop(); + result + }) + } else { + cx.with_key_listeners(&self.as_stateless().key_listeners, f) + } + } + + fn refine_style(&self, style: &mut Style, bounds: Bounds, cx: &mut ViewContext) { + let mouse_position = cx.mouse_position(); + let stateless = self.as_stateless(); + if let Some(group_hover) = stateless.group_hover.as_ref() { + if let Some(group_bounds) = group_bounds(&group_hover.group, cx) { + if group_bounds.contains_point(&mouse_position) { + style.refine(&group_hover.style); + } + } + } + if bounds.contains_point(&mouse_position) { + style.refine(&stateless.hover_style); + } + } + fn paint( &mut self, bounds: Bounds, @@ -80,6 +127,19 @@ pub trait ElementInteractivity: 'static + Send + Sync }) } + let hover_group_bounds = stateless + .group_hover + .as_ref() + .and_then(|group_hover| GroupBounds::get(&group_hover.group, cx)); + + if let Some(group_bounds) = hover_group_bounds { + paint_hover_listener(group_bounds, cx); + } + + if stateless.hover_style.is_some() { + paint_hover_listener(bounds, cx); + } + if let Some(stateful) = self.as_stateful() { let click_listeners = stateful.mouse_click_listeners.clone(); @@ -107,37 +167,20 @@ pub trait ElementInteractivity: 'static + Send + Sync }; } } +} - fn initialize( - &mut self, - cx: &mut ViewContext, - f: impl FnOnce(&mut ViewContext) -> R, - ) -> R { - if let Some(stateful) = self.as_stateful_mut() { - cx.with_element_id(stateful.id.clone(), |global_id, cx| { - stateful.key_listeners.push(( - TypeId::of::(), - Arc::new(move |_, key_down, context, phase, cx| { - if phase == DispatchPhase::Bubble { - let key_down = key_down.downcast_ref::().unwrap(); - if let KeyMatch::Some(action) = - cx.match_keystroke(&global_id, &key_down.keystroke, context) - { - return Some(action); - } - } - - None - }), - )); - let result = stateful.stateless.initialize(cx, f); - stateful.key_listeners.pop(); - result - }) - } else { - cx.with_key_listeners(&self.as_stateless().key_listeners, f) +fn paint_hover_listener(bounds: Bounds, cx: &mut ViewContext) +where + V: 'static + Send + Sync, +{ + let hovered = bounds.contains_point(&cx.mouse_position()); + cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| { + if phase == DispatchPhase::Capture { + if bounds.contains_point(&event.position) != hovered { + cx.notify(); + } } - } + }); } #[derive(Deref, DerefMut)] @@ -189,6 +232,49 @@ pub struct StatelessInteractivity { pub mouse_move_listeners: SmallVec<[MouseMoveListener; 2]>, pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener; 2]>, pub key_listeners: SmallVec<[(TypeId, KeyListener); 32]>, + pub hover_style: StyleRefinement, + pub group_hover: Option, +} + +pub struct GroupStyle { + pub group: SharedString, + pub style: StyleRefinement, +} + +#[derive(Default)] +pub struct GroupBounds(HashMap; 1]>>); + +impl GroupBounds { + pub fn get(name: &SharedString, cx: &mut AppContext) -> Option> { + cx.default_global::() + .0 + .get(name) + .and_then(|bounds_stack| bounds_stack.last()) + .cloned() + } + + pub fn push(name: SharedString, bounds: Bounds, cx: &mut AppContext) { + cx.default_global::() + .0 + .entry(name) + .or_default() + .push(bounds); + } + + pub fn pop(name: &SharedString, cx: &mut AppContext) { + cx.default_global::() + .0 + .get_mut(name) + .unwrap() + .pop(); + } +} + +pub fn group_bounds(name: &SharedString, cx: &mut AppContext) -> Option> { + cx.default_global::() + .0 + .get(name) + .and_then(|bounds_stack| bounds_stack.last().cloned()) } impl Default for StatelessInteractivity { @@ -199,6 +285,8 @@ impl Default for StatelessInteractivity { mouse_move_listeners: SmallVec::new(), scroll_wheel_listeners: SmallVec::new(), key_listeners: SmallVec::new(), + hover_style: StyleRefinement::default(), + group_hover: None, } } } diff --git a/crates/gpui3/src/elements/div.rs b/crates/gpui3/src/elements/div.rs index 88c1f2e8fd..8a4b29cea7 100644 --- a/crates/gpui3/src/elements/div.rs +++ b/crates/gpui3/src/elements/div.rs @@ -1,12 +1,11 @@ use crate::{ - Active, AnyElement, AppContext, BorrowWindow, Bounds, DispatchPhase, Element, - ElementFocusability, ElementId, ElementInteractivity, Focus, FocusHandle, FocusListeners, - Focusable, GlobalElementId, Hover, IntoAnyElement, LayoutId, MouseDownEvent, MouseMoveEvent, + Active, AnyElement, BorrowWindow, Bounds, DispatchPhase, Element, ElementFocusability, + ElementId, ElementInteractivity, Focus, FocusHandle, FocusListeners, Focusable, + GlobalElementId, GroupBounds, GroupStyle, Hover, IntoAnyElement, LayoutId, MouseDownEvent, MouseUpEvent, NonFocusable, Overflow, ParentElement, Pixels, Point, SharedString, StatefulInteractivity, StatefullyInteractive, StatelessInteractivity, StatelesslyInteractive, Style, StyleRefinement, Styled, ViewContext, }; -use collections::HashMap; use parking_lot::Mutex; use refineable::Refineable; use smallvec::SmallVec; @@ -30,16 +29,6 @@ impl ActiveState { } } -#[derive(Default)] -struct GroupBounds(HashMap; 1]>>); - -pub fn group_bounds(name: &SharedString, cx: &mut AppContext) -> Option> { - cx.default_global::() - .0 - .get(name) - .and_then(|bounds_stack| bounds_stack.last().cloned()) -} - #[derive(Default, Clone)] pub struct ScrollState(Arc>>); @@ -71,8 +60,6 @@ pub struct Div< children: SmallVec<[AnyElement; 2]>, group: Option, base_style: StyleRefinement, - hover_style: StyleRefinement, - group_hover: Option, active_style: StyleRefinement, group_active: Option, } @@ -87,18 +74,11 @@ where children: SmallVec::new(), group: None, base_style: StyleRefinement::default(), - hover_style: StyleRefinement::default(), - group_hover: None, active_style: StyleRefinement::default(), group_active: None, } } -struct GroupStyle { - group: SharedString, - style: StyleRefinement, -} - impl Div, F> where F: ElementFocusability, @@ -111,8 +91,6 @@ where children: self.children, group: self.group, base_style: self.base_style, - hover_style: self.hover_style, - group_hover: self.group_hover, active_style: self.active_style, group_active: self.group_active, } @@ -195,19 +173,8 @@ where computed_style.refine(&self.base_style); self.focusability.refine_style(&mut computed_style, cx); - - let mouse_position = cx.mouse_position(); - - if let Some(group_hover) = self.group_hover.as_ref() { - if let Some(group_bounds) = group_bounds(&group_hover.group, cx) { - if group_bounds.contains_point(&mouse_position) { - computed_style.refine(&group_hover.style); - } - } - } - if bounds.contains_point(&mouse_position) { - computed_style.refine(&self.hover_style); - } + self.interactivity + .refine_style(&mut computed_style, bounds, cx); let active_state = *state.active_state.lock(); if active_state.group { @@ -222,21 +189,6 @@ where computed_style } - fn paint_hover_listeners( - &self, - bounds: Bounds, - group_bounds: Option>, - cx: &mut ViewContext, - ) { - if let Some(group_bounds) = group_bounds { - paint_hover_listener(group_bounds, cx); - } - - if self.hover_style.is_some() { - paint_hover_listener(bounds, cx); - } - } - fn paint_active_listener( &self, bounds: Bounds, @@ -279,8 +231,6 @@ where children: self.children, group: self.group, base_style: self.base_style, - hover_style: self.hover_style, - group_hover: self.group_hover, active_style: self.active_style, group_active: self.group_active, } @@ -372,21 +322,13 @@ where ) { self.with_element_id(cx, |this, _global_id, cx| { if let Some(group) = this.group.clone() { - cx.default_global::() - .0 - .entry(group) - .or_default() - .push(bounds); + GroupBounds::push(group, bounds, cx); } - let hover_group_bounds = this - .group_hover - .as_ref() - .and_then(|group_hover| group_bounds(&group_hover.group, cx)); let active_group_bounds = this .group_active .as_ref() - .and_then(|group_active| group_bounds(&group_active.group, cx)); + .and_then(|group_active| GroupBounds::get(&group_active.group, cx)); let style = this.compute_style(bounds, element_state, cx); let z_index = style.z_index.unwrap_or(0); @@ -394,7 +336,6 @@ where cx.stack(z_index, |cx| { cx.stack(0, |cx| { style.paint(bounds, cx); - this.paint_hover_listeners(bounds, hover_group_bounds, cx); this.paint_active_listener( bounds, active_group_bounds, @@ -418,11 +359,7 @@ where }); if let Some(group) = this.group.as_ref() { - cx.default_global::() - .0 - .get_mut(group) - .unwrap() - .pop(); + GroupBounds::pop(group, cx); } }) } @@ -479,10 +416,11 @@ where V: 'static + Send + Sync, { fn set_hover_style(&mut self, group: Option, style: StyleRefinement) { + let stateless = self.interactivity.as_stateless_mut(); if let Some(group) = group { - self.group_hover = Some(GroupStyle { group, style }); + stateless.group_hover = Some(GroupStyle { group, style }); } else { - self.hover_style = style; + stateless.hover_style = style; } } } @@ -510,17 +448,3 @@ where } } } - -fn paint_hover_listener(bounds: Bounds, cx: &mut ViewContext) -where - V: 'static + Send + Sync, -{ - let hovered = bounds.contains_point(&cx.mouse_position()); - cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| { - if phase == DispatchPhase::Capture { - if bounds.contains_point(&event.position) != hovered { - cx.notify(); - } - } - }); -} diff --git a/crates/ui2/src/prelude.rs b/crates/ui2/src/prelude.rs index 85ed8a3a1f..613101b19e 100644 --- a/crates/ui2/src/prelude.rs +++ b/crates/ui2/src/prelude.rs @@ -1,6 +1,6 @@ pub use gpui3::{ - div, Click, Element, Hover, IntoAnyElement, ParentElement, ScrollState, SharedString, - StatefullyInteractivee, Styled, ViewContext, WindowContext, + div, Element, Hover, IntoAnyElement, ParentElement, ScrollState, SharedString, + StatefullyInteractive, Styled, ViewContext, WindowContext, }; use crate::settings::user_settings; diff --git a/crates/ui2/src/settings.rs b/crates/ui2/src/settings.rs index 995da199cf..106155d7ca 100644 --- a/crates/ui2/src/settings.rs +++ b/crates/ui2/src/settings.rs @@ -1,180 +1,179 @@ -use std::ops::Deref; -use std::sync::Arc; +// use std::ops::Deref; +// use std::sync::Arc; -use gpui3::{ - rems, AbsoluteLength, AnyElement, BorrowAppContext, Bounds, Interactive, LayoutId, Pixels, - WindowContext, -}; +// use gpui3::{ +// rems, AbsoluteLength, AnyElement, BorrowAppContext, Bounds, LayoutId, Pixels, WindowContext, +// }; -use crate::prelude::*; +// use crate::prelude::*; -/// Returns the user settings. -pub fn user_settings(cx: &WindowContext) -> FakeSettings { - cx.global::().clone() -} +// /// Returns the user settings. +// pub fn user_settings(cx: &WindowContext) -> FakeSettings { +// cx.global::().clone() +// } -pub fn user_settings_mut<'cx>(cx: &'cx mut WindowContext) -> &'cx mut FakeSettings { - cx.global_mut::() -} +// pub fn user_settings_mut<'cx>(cx: &'cx mut WindowContext) -> &'cx mut FakeSettings { +// cx.global_mut::() +// } -#[derive(Clone)] -pub enum SettingValue { - UserDefined(T), - Default(T), -} +// #[derive(Clone)] +// pub enum SettingValue { +// UserDefined(T), +// Default(T), +// } -impl Deref for SettingValue { - type Target = T; +// impl Deref for SettingValue { +// type Target = T; - fn deref(&self) -> &Self::Target { - match self { - Self::UserDefined(value) => value, - Self::Default(value) => value, - } - } -} +// fn deref(&self) -> &Self::Target { +// match self { +// Self::UserDefined(value) => value, +// Self::Default(value) => value, +// } +// } +// } -#[derive(Clone)] -pub struct TitlebarSettings { - pub show_project_owner: SettingValue, - pub show_git_status: SettingValue, - pub show_git_controls: SettingValue, -} +// #[derive(Clone)] +// pub struct TitlebarSettings { +// pub show_project_owner: SettingValue, +// pub show_git_status: SettingValue, +// pub show_git_controls: SettingValue, +// } -impl Default for TitlebarSettings { - fn default() -> Self { - Self { - show_project_owner: SettingValue::Default(true), - show_git_status: SettingValue::Default(true), - show_git_controls: SettingValue::Default(true), - } - } -} +// impl Default for TitlebarSettings { +// fn default() -> Self { +// Self { +// show_project_owner: SettingValue::Default(true), +// show_git_status: SettingValue::Default(true), +// show_git_controls: SettingValue::Default(true), +// } +// } +// } -// These should be merged into settings -#[derive(Clone)] -pub struct FakeSettings { - pub default_panel_size: SettingValue, - pub list_disclosure_style: SettingValue, - pub list_indent_depth: SettingValue, - pub titlebar: TitlebarSettings, - pub ui_scale: SettingValue, -} +// // These should be merged into settings +// #[derive(Clone)] +// pub struct FakeSettings { +// pub default_panel_size: SettingValue, +// pub list_disclosure_style: SettingValue, +// pub list_indent_depth: SettingValue, +// pub titlebar: TitlebarSettings, +// pub ui_scale: SettingValue, +// } -impl Default for FakeSettings { - fn default() -> Self { - Self { - titlebar: TitlebarSettings::default(), - list_disclosure_style: SettingValue::Default(DisclosureControlStyle::ChevronOnHover), - list_indent_depth: SettingValue::Default(rems(0.3).into()), - default_panel_size: SettingValue::Default(rems(16.).into()), - ui_scale: SettingValue::Default(1.), - } - } -} +// impl Default for FakeSettings { +// fn default() -> Self { +// Self { +// titlebar: TitlebarSettings::default(), +// list_disclosure_style: SettingValue::Default(DisclosureControlStyle::ChevronOnHover), +// list_indent_depth: SettingValue::Default(rems(0.3).into()), +// default_panel_size: SettingValue::Default(rems(16.).into()), +// ui_scale: SettingValue::Default(1.), +// } +// } +// } -impl FakeSettings {} +// impl FakeSettings {} -pub fn with_settings( - settings: FakeSettings, - cx: &mut ViewContext, - build_child: F, -) -> WithSettings -where - E: Element, - F: FnOnce(&mut ViewContext) -> E, -{ - let child = cx.with_global(settings.clone(), |cx| build_child(cx)); - WithSettings { settings, child } -} +// pub fn with_settings( +// settings: FakeSettings, +// cx: &mut ViewContext, +// build_child: F, +// ) -> WithSettings +// where +// E: Element, +// F: FnOnce(&mut ViewContext) -> E, +// { +// let child = cx.with_global(settings.clone(), |cx| build_child(cx)); +// WithSettings { settings, child } +// } -pub struct WithSettings { - pub(crate) settings: FakeSettings, - pub(crate) child: E, -} +// pub struct WithSettings { +// pub(crate) settings: FakeSettings, +// pub(crate) child: E, +// } -impl IntoAnyElement for WithSettings -where - E: Element, -{ - fn into_any(self) -> AnyElement { - AnyElement::new(self) - } -} +// impl IntoAnyElement for WithSettings +// where +// E: Element, +// { +// fn into_any(self) -> AnyElement { +// AnyElement::new(self) +// } +// } -impl Element for WithSettings { - type ViewState = E::ViewState; - type ElementState = E::ElementState; +// impl Element for WithSettings { +// type ViewState = E::ViewState; +// type ElementState = E::ElementState; - fn id(&self) -> Option { - None - } +// fn id(&self) -> Option { +// None +// } - fn initialize( - &mut self, - view_state: &mut Self::ViewState, - element_state: Option, - cx: &mut ViewContext, - ) -> Self::ElementState { - cx.with_global(self.settings.clone(), |cx| { - self.child.initialize(view_state, element_state, cx) - }) - } +// fn initialize( +// &mut self, +// view_state: &mut Self::ViewState, +// element_state: Option, +// cx: &mut ViewContext, +// ) -> Self::ElementState { +// cx.with_global(self.settings.clone(), |cx| { +// self.child.initialize(view_state, element_state, cx) +// }) +// } - fn layout( - &mut self, - view_state: &mut E::ViewState, - element_state: &mut Self::ElementState, - cx: &mut ViewContext, - ) -> LayoutId - where - Self: Sized, - { - cx.with_global(self.settings.clone(), |cx| { - self.child.layout(view_state, element_state, cx) - }) - } +// fn layout( +// &mut self, +// view_state: &mut E::ViewState, +// element_state: &mut Self::ElementState, +// cx: &mut ViewContext, +// ) -> LayoutId +// where +// Self: Sized, +// { +// cx.with_global(self.settings.clone(), |cx| { +// self.child.layout(view_state, element_state, cx) +// }) +// } - fn paint( - &mut self, - bounds: Bounds, - view_state: &mut Self::ViewState, - frame_state: &mut Self::ElementState, - cx: &mut ViewContext, - ) where - Self: Sized, - { - cx.with_global(self.settings.clone(), |cx| { - self.child.paint(bounds, view_state, frame_state, cx); - }); - } -} +// fn paint( +// &mut self, +// bounds: Bounds, +// view_state: &mut Self::ViewState, +// frame_state: &mut Self::ElementState, +// cx: &mut ViewContext, +// ) where +// Self: Sized, +// { +// cx.with_global(self.settings.clone(), |cx| { +// self.child.paint(bounds, view_state, frame_state, cx); +// }); +// } +// } -impl Interactive for WithSettings { - fn listeners(&mut self) -> &mut gpui3::EventListeners { - self.child.listeners() - } +// impl Interactive for WithSettings { +// fn listeners(&mut self) -> &mut gpui3::EventListeners { +// self.child.listeners() +// } - fn on_mouse_down( - mut self, - button: gpui3::MouseButton, - handler: impl Fn(&mut Self::ViewState, &gpui3::MouseDownEvent, &mut ViewContext) - + Send - + Sync - + 'static, - ) -> Self - where - Self: Sized, - { - println!("WithSettings on_mouse_down"); +// fn on_mouse_down( +// mut self, +// button: gpui3::MouseButton, +// handler: impl Fn(&mut Self::ViewState, &gpui3::MouseDownEvent, &mut ViewContext) +// + Send +// + Sync +// + 'static, +// ) -> Self +// where +// Self: Sized, +// { +// println!("WithSettings on_mouse_down"); - let settings = self.settings.clone(); +// let settings = self.settings.clone(); - self.listeners() - .mouse_down - .push(Arc::new(move |view, event, bounds, phase, cx| { - cx.with_global(settings.clone(), |cx| handler(view, event, cx)) - })); - self - } -} +// self.listeners() +// .mouse_down +// .push(Arc::new(move |view, event, bounds, phase, cx| { +// cx.with_global(settings.clone(), |cx| handler(view, event, cx)) +// })); +// self +// } +// }