History

Checkpoint

Antonio Scandurra committed 3 years ago

Commit dd7e1c51 parent 0fbf84e8 files · +207 −191Browse files

Unified · Split

8 files
  1. crates/gpui3/src/element.rs +134 −13
  2. crates/gpui3/src/elements/div.rs +24 −50
  3. crates/gpui3/src/elements/img.rs +11 −8
  4. crates/gpui3/src/elements/svg.rs +11 −8
  5. crates/gpui3/src/interactive.rs +23 −108
  6. crates/ui2/src/components/icon_button.rs +1 −1
  7. crates/ui2/src/elements/button.rs +1 −1
  8. crates/ui2/src/prelude.rs +2 −2
crates/gpui3/src/element.rs+134−13
@@ -1,11 +1,15 @@
1use crate::{1use crate::{
2 BorrowWindow, Bounds, DispatchPhase, ElementId, FocusHandle, FocusListeners, LayoutId,2 BorrowWindow, Bounds, DispatchPhase, ElementId, FocusHandle, FocusListeners, KeyDownEvent,
3 MouseDownEvent, Pixels, Point, Style, StyleRefinement, ViewContext, WindowContext,3 KeyListener, KeyMatch, LayoutId, MouseClickEvent, MouseClickListener, MouseDownEvent,
4 MouseDownListener, MouseMoveEvent, MouseMoveListener, MouseUpEvent, MouseUpListener, Pixels,
5 Point, ScrollWheelEvent, ScrollWheelListener, Style, StyleRefinement, ViewContext,
6 WindowContext,
4};7};
5use derive_more::{Deref, DerefMut};8use derive_more::{Deref, DerefMut};
9use parking_lot::Mutex;
6use refineable::Refineable;10use refineable::Refineable;
7pub(crate) use smallvec::SmallVec;11pub(crate) use smallvec::SmallVec;
8use std::{marker::PhantomData, mem};12use std::{any::TypeId, mem, sync::Arc};
9 13
10pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {14pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
11 type ViewState: 'static + Send + Sync;15 type ViewState: 'static + Send + Sync;
@@ -40,19 +44,98 @@ pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> { · 28 unmodified lines
40pub struct GlobalElementId(SmallVec<[ElementId; 32]>);44pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
41 45
42pub trait ElementInteractivity<V: 'static + Send + Sync>: 'static + Send + Sync {46pub trait ElementInteractivity<V: 'static + Send + Sync>: 'static + Send + Sync {
47 fn as_stateless(&self) -> &StatelessInteractivity<V>;
48 fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V>;
43 fn as_stateful(&self) -> Option<&StatefulInteractivity<V>>;49 fn as_stateful(&self) -> Option<&StatefulInteractivity<V>>;
50 fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>>;
51
52 fn paint(
53 &mut self,
54 bounds: Bounds<Pixels>,
55 pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
56 cx: &mut ViewContext<V>,
57 ) {
58 let stateless = self.as_stateless();
59 for listener in stateless.mouse_down_listeners.iter().cloned() {
60 cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
61 listener(state, event, &bounds, phase, cx);
62 })
63 }
64
65 for listener in stateless.mouse_up_listeners.iter().cloned() {
66 cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
67 listener(state, event, &bounds, phase, cx);
68 })
69 }
70
71 for listener in stateless.mouse_move_listeners.iter().cloned() {
72 cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
73 listener(state, event, &bounds, phase, cx);
74 })
75 }
76
77 for listener in stateless.scroll_wheel_listeners.iter().cloned() {
78 cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
79 listener(state, event, &bounds, phase, cx);
80 })
81 }
82
83 if let Some(stateful) = self.as_stateful() {
84 let click_listeners = stateful.mouse_click_listeners.clone();
85
86 let mouse_down = pending_click.lock().clone();
87 if let Some(mouse_down) = mouse_down {
88 cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
89 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
90 let mouse_click = MouseClickEvent {
91 down: mouse_down.clone(),
92 up: event.clone(),
93 };
94 for listener in &click_listeners {
95 listener(state, &mouse_click, cx);
96 }
97 }
98
99 *pending_click.lock() = None;
100 });
101 } else {
102 cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
103 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
104 *pending_click.lock() = Some(event.clone());
105 }
106 });
107 };
108 }
109 }
44 110
45 fn initialize<R>(111 fn initialize<R>(
46 &self,112 &mut self,
47 cx: &mut ViewContext<V>,113 cx: &mut ViewContext<V>,
48 f: impl FnOnce(Option<GlobalElementId>, &mut ViewContext<V>) -> R,114 f: impl FnOnce(&mut ViewContext<V>) -> R,
49 ) -> R {115 ) -> R {
50 if let Some(identified) = self.as_stateful() {116 if let Some(stateful) = self.as_stateful_mut() {
51 cx.with_element_id(identified.id.clone(), |global_id, cx| {117 cx.with_element_id(stateful.id.clone(), |global_id, cx| {
52 f(Some(global_id), cx)118 stateful.key_listeners.push((
119 TypeId::of::<KeyDownEvent>(),
120 Arc::new(move |_, key_down, context, phase, cx| {
121 if phase == DispatchPhase::Bubble {
122 let key_down = key_down.downcast_ref::<KeyDownEvent>().unwrap();
123 if let KeyMatch::Some(action) =
124 cx.match_keystroke(&global_id, &key_down.keystroke, context)
125 {
126 return Some(action);
127 }
128 }
129
130 None
131 }),
132 ));
133 let result = stateful.stateless.initialize(cx, f);
134 stateful.key_listeners.pop();
135 result
53 })136 })
54 } else {137 } else {
55 f(None, cx)138 cx.with_key_listeners(&self.as_stateless().key_listeners, f)
56 }139 }
57 }140 }
58}141}
@@ -62,7 +145,8 @@ pub struct StatefulInteractivity<V: 'static + Send + Sync> { · 3 unmodified lines
62 pub id: ElementId,145 pub id: ElementId,
63 #[deref]146 #[deref]
64 #[deref_mut]147 #[deref_mut]
65 common: StatelessInteractivity<V>,148 stateless: StatelessInteractivity<V>,
149 pub mouse_click_listeners: SmallVec<[MouseClickListener<V>; 2]>,
66}150}
67 151
68impl<V> ElementInteractivity<V> for StatefulInteractivity<V>152impl<V> ElementInteractivity<V> for StatefulInteractivity<V>
@@ -72,6 +156,18 @@ where · 3 unmodified lines
72 fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {156 fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
73 Some(self)157 Some(self)
74 }158 }
159
160 fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> {
161 Some(self)
162 }
163
164 fn as_stateless(&self) -> &StatelessInteractivity<V> {
165 &self.stateless
166 }
167
168 fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> {
169 &mut self.stateless
170 }
75}171}
76 172
77impl<V> From<ElementId> for StatefulInteractivity<V>173impl<V> From<ElementId> for StatefulInteractivity<V>
@@ -81,16 +177,29 @@ where · 3 unmodified lines
81 fn from(id: ElementId) -> Self {177 fn from(id: ElementId) -> Self {
82 Self {178 Self {
83 id,179 id,
84 common: StatelessInteractivity::default(),180 stateless: StatelessInteractivity::default(),
181 mouse_click_listeners: SmallVec::new(),
85 }182 }
86 }183 }
87}184}
88 185
89pub struct StatelessInteractivity<V>(PhantomData<V>);186pub struct StatelessInteractivity<V> {
187 pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
188 pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
189 pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
190 pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
191 pub key_listeners: SmallVec<[(TypeId, KeyListener<V>); 32]>,
192}
90 193
91impl<V> Default for StatelessInteractivity<V> {194impl<V> Default for StatelessInteractivity<V> {
92 fn default() -> Self {195 fn default() -> Self {
93 Self(PhantomData)196 Self {
197 mouse_down_listeners: SmallVec::new(),
198 mouse_up_listeners: SmallVec::new(),
199 mouse_move_listeners: SmallVec::new(),
200 scroll_wheel_listeners: SmallVec::new(),
201 key_listeners: SmallVec::new(),
202 }
94 }203 }
95}204}
96 205
@@ -101,6 +210,18 @@ where · 4 unmodified lines
101 fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {210 fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
102 None211 None
103 }212 }
213
214 fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> {
215 None
216 }
217
218 fn as_stateless(&self) -> &StatelessInteractivity<V> {
219 self
220 }
221
222 fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> {
223 self
224 }
104}225}
105 226
106pub trait ElementFocusability<V: 'static + Send + Sync>: 'static + Send + Sync {227pub trait ElementFocusability<V: 'static + Send + Sync>: 'static + Send + Sync {
crates/gpui3/src/elements/div.rs+24−50
@@ -1,16 +1,16 @@
1use crate::{1use crate::{
2 Active, AnyElement, AppContext, BorrowWindow, Bounds, Click, DispatchPhase, Element,2 Active, AnyElement, AppContext, BorrowWindow, Bounds, DispatchPhase, Element,
3 ElementFocusability, ElementId, ElementInteractivity, Focus, FocusHandle, FocusListeners,3 ElementFocusability, ElementId, ElementInteractivity, Focus, FocusHandle, FocusListeners,
4 Focusable, GlobalElementId, Hover, Interactive, Interactivity, IntoAnyElement, KeyDownEvent,4 Focusable, GlobalElementId, Hover, IntoAnyElement, LayoutId, MouseDownEvent, MouseMoveEvent,
5 KeyMatch, LayoutId, MouseDownEvent, MouseMoveEvent, MouseUpEvent, NonFocusable, Overflow,5 MouseUpEvent, NonFocusable, Overflow, ParentElement, Pixels, Point, SharedString,
6 ParentElement, Pixels, Point, SharedString, StatefulInteractivity, StatelessInteractivity,6 StatefulInteractivity, StatefullyInteractive, StatelessInteractivity, StatelesslyInteractive,
7 Style, StyleRefinement, Styled, ViewContext,7 Style, StyleRefinement, Styled, ViewContext,
8};8};
9use collections::HashMap;9use collections::HashMap;
10use parking_lot::Mutex;10use parking_lot::Mutex;
11use refineable::Refineable;11use refineable::Refineable;
12use smallvec::SmallVec;12use smallvec::SmallVec;
13use std::{any::TypeId, mem, sync::Arc};13use std::sync::Arc;
14 14
15#[derive(Default)]15#[derive(Default)]
16pub struct DivState {16pub struct DivState {
@@ -66,9 +66,8 @@ pub struct Div< · 49 unmodified lines
66 I: ElementInteractivity<V> = StatelessInteractivity<V>,66 I: ElementInteractivity<V> = StatelessInteractivity<V>,
67 F: ElementFocusability<V> = NonFocusable,67 F: ElementFocusability<V> = NonFocusable,
68> {68> {
69 identity: I,69 interactivity: I,
70 focusability: F,70 focusability: F,
71 interactivity: Interactivity<V>,
72 children: SmallVec<[AnyElement<V>; 2]>,71 children: SmallVec<[AnyElement<V>; 2]>,
73 group: Option<SharedString>,72 group: Option<SharedString>,
74 base_style: StyleRefinement,73 base_style: StyleRefinement,
@@ -83,9 +82,8 @@ where · 8 unmodified lines
83 V: 'static + Send + Sync,82 V: 'static + Send + Sync,
84{83{
85 Div {84 Div {
86 identity: StatelessInteractivity::default(),85 interactivity: StatelessInteractivity::default(),
87 focusability: NonFocusable,86 focusability: NonFocusable,
88 interactivity: Interactivity::default(),
89 children: SmallVec::new(),87 children: SmallVec::new(),
90 group: None,88 group: None,
91 base_style: StyleRefinement::default(),89 base_style: StyleRefinement::default(),
@@ -108,9 +106,8 @@ where · 16 unmodified lines
108{106{
109 pub fn id(self, id: impl Into<ElementId>) -> Div<V, StatefulInteractivity<V>, F> {107 pub fn id(self, id: impl Into<ElementId>) -> Div<V, StatefulInteractivity<V>, F> {
110 Div {108 Div {
111 identity: id.into().into(),109 interactivity: id.into().into(),
112 focusability: self.focusability,110 focusability: self.focusability,
113 interactivity: self.interactivity,
114 children: self.children,111 children: self.children,
115 group: self.group,112 group: self.group,
116 base_style: self.base_style,113 base_style: self.base_style,
@@ -277,7 +274,7 @@ where · 160 unmodified lines
277{274{
278 pub fn focusable(self, handle: &FocusHandle) -> Div<V, I, Focusable<V>> {275 pub fn focusable(self, handle: &FocusHandle) -> Div<V, I, Focusable<V>> {
279 Div {276 Div {
280 identity: self.identity,277 interactivity: self.interactivity,
281 focusability: handle.clone().into(),278 focusability: handle.clone().into(),
282 children: self.children,279 children: self.children,
283 group: self.group,280 group: self.group,
@@ -286,7 +283,6 @@ where · 2 unmodified lines
286 group_hover: self.group_hover,283 group_hover: self.group_hover,
287 active_style: self.active_style,284 active_style: self.active_style,
288 group_active: self.group_active,285 group_active: self.group_active,
289 interactivity: self.interactivity,
290 }286 }
291 }287 }
292}288}
@@ -327,7 +323,7 @@ where · 34 unmodified lines
327 type ElementState = DivState;323 type ElementState = DivState;
328 324
329 fn id(&self) -> Option<ElementId> {325 fn id(&self) -> Option<ElementId> {
330 self.identity326 self.interactivity
331 .as_stateful()327 .as_stateful()
332 .map(|identified| identified.id.clone())328 .map(|identified| identified.id.clone())
333 }329 }
@@ -338,39 +334,14 @@ where · 4 unmodified lines
338 element_state: Option<Self::ElementState>,334 element_state: Option<Self::ElementState>,
339 cx: &mut ViewContext<Self::ViewState>,335 cx: &mut ViewContext<Self::ViewState>,
340 ) -> Self::ElementState {336 ) -> Self::ElementState {
341 self.with_element_id(cx, |this, global_id, cx| {337 self.interactivity.initialize(cx, |cx| {
342 let element_state = element_state.unwrap_or_default();338 self.focusability.initialize(cx, |cx| {
343 339 for child in &mut self.children {
344 let mut key_listeners = mem::take(&mut this.interactivity.key);340 child.initialize(view_state, cx);
345 if let Some(global_id) = global_id {341 }
346 key_listeners.push((
347 TypeId::of::<KeyDownEvent>(),
348 Arc::new(move |_, key_down, context, phase, cx| {
349 if phase == DispatchPhase::Bubble {
350 let key_down = key_down.downcast_ref::<KeyDownEvent>().unwrap();
351 if let KeyMatch::Some(action) =
352 cx.match_keystroke(&global_id, &key_down.keystroke, context)
353 {
354 return Some(action);
355 }
356 }
357
358 None
359 }),
360 ));
361 }
362
363 cx.with_key_listeners(&key_listeners, |cx| {
364 this.focusability.initialize(cx, |cx| {
365 for child in &mut this.children {
366 child.initialize(view_state, cx);
367 }
368 });
369 });342 });
370 this.interactivity.key = key_listeners;343 });
371 344 element_state.unwrap_or_default()
372 element_state
373 })
374 }345 }
375 346
376 fn layout(347 fn layout(
@@ -490,14 +461,14 @@ where · 113 unmodified lines
490 }461 }
491}462}
492 463
493impl<V, I, F> Interactive for Div<V, I, F>464impl<V, I, F> StatelesslyInteractive for Div<V, I, F>
494where465where
495 I: ElementInteractivity<V>,466 I: ElementInteractivity<V>,
496 F: ElementFocusability<V>,467 F: ElementFocusability<V>,
497 V: 'static + Send + Sync,468 V: 'static + Send + Sync,
498{469{
499 fn interactivity(&mut self) -> &mut Interactivity<V> {470 fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
500 &mut self.interactivity471 self.interactivity.as_stateless_mut()
501 }472 }
502}473}
503 474
@@ -516,11 +487,14 @@ where · 12 unmodified lines
516 }487 }
517}488}
518 489
519impl<V, F> Click for Div<V, StatefulInteractivity<V>, F>490impl<V, F> StatefullyInteractive for Div<V, StatefulInteractivity<V>, F>
520where491where
521 F: ElementFocusability<V>,492 F: ElementFocusability<V>,
522 V: 'static + Send + Sync,493 V: 'static + Send + Sync,
523{494{
495 fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState> {
496 &mut self.interactivity
497 }
524}498}
525 499
526impl<V, F> Active for Div<V, StatefulInteractivity<V>, F>500impl<V, F> Active for Div<V, StatefulInteractivity<V>, F>
crates/gpui3/src/elements/img.rs+11−8
@@ -1,8 +1,8 @@
1use crate::{1use crate::{
2 div, Active, AnyElement, BorrowWindow, Bounds, Click, Div, DivState, Element,2 div, Active, AnyElement, BorrowWindow, Bounds, Div, DivState, Element, ElementFocusability,
3 ElementFocusability, ElementId, ElementInteractivity, Focus, FocusListeners, Focusable, Hover,3 ElementId, ElementInteractivity, Focus, FocusListeners, Focusable, Hover, IntoAnyElement,
4 Interactive, Interactivity, IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString,4 LayoutId, NonFocusable, Pixels, SharedString, StatefulInteractivity, StatefullyInteractive,
5 StatefulInteractivity, StatelessInteractivity, StyleRefinement, Styled, ViewContext,5 StatelessInteractivity, StatelesslyInteractive, StyleRefinement, Styled, ViewContext,
6};6};
7use futures::FutureExt;7use futures::FutureExt;
8use util::ResultExt;8use util::ResultExt;
@@ -150,14 +150,14 @@ where · 141 unmodified lines
150 }150 }
151}151}
152 152
153impl<V, I, F> Interactive for Img<V, I, F>153impl<V, I, F> StatelesslyInteractive for Img<V, I, F>
154where154where
155 V: 'static + Send + Sync,155 V: 'static + Send + Sync,
156 I: ElementInteractivity<V>,156 I: ElementInteractivity<V>,
157 F: ElementFocusability<V>,157 F: ElementFocusability<V>,
158{158{
159 fn interactivity(&mut self) -> &mut Interactivity<V> {159 fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
160 self.base.interactivity()160 self.base.stateless_interactivity()
161 }161 }
162}162}
163 163
@@ -172,11 +172,14 @@ where · 8 unmodified lines
172 }172 }
173}173}
174 174
175impl<V, F> Click for Img<V, StatefulInteractivity<V>, F>175impl<V, F> StatefullyInteractive for Img<V, StatefulInteractivity<V>, F>
176where176where
177 V: 'static + Send + Sync,177 V: 'static + Send + Sync,
178 F: ElementFocusability<V>,178 F: ElementFocusability<V>,
179{179{
180 fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState> {
181 self.base.stateful_interactivity()
182 }
180}183}
181 184
182impl<V, F> Active for Img<V, StatefulInteractivity<V>, F>185impl<V, F> Active for Img<V, StatefulInteractivity<V>, F>
crates/gpui3/src/elements/svg.rs+11−8
@@ -1,8 +1,8 @@
1use crate::{1use crate::{
2 div, Active, AnyElement, Bounds, Click, Div, DivState, Element, ElementFocusability, ElementId,2 div, Active, AnyElement, Bounds, Div, DivState, Element, ElementFocusability, ElementId,
3 ElementInteractivity, Focus, FocusListeners, Focusable, Hover, Interactive, Interactivity,3 ElementInteractivity, Focus, FocusListeners, Focusable, Hover, IntoAnyElement, LayoutId,
4 IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString, StatefulInteractivity,4 NonFocusable, Pixels, SharedString, StatefulInteractivity, StatefullyInteractive,
5 StatelessInteractivity, StyleRefinement, Styled, ViewContext,5 StatelessInteractivity, StatelesslyInteractive, StyleRefinement, Styled, ViewContext,
6};6};
7use util::ResultExt;7use util::ResultExt;
8 8
@@ -124,14 +124,14 @@ where · 115 unmodified lines
124 }124 }
125}125}
126 126
127impl<V, I, F> Interactive for Svg<V, I, F>127impl<V, I, F> StatelesslyInteractive for Svg<V, I, F>
128where128where
129 V: 'static + Send + Sync,129 V: 'static + Send + Sync,
130 I: ElementInteractivity<V>,130 I: ElementInteractivity<V>,
131 F: ElementFocusability<V>,131 F: ElementFocusability<V>,
132{132{
133 fn interactivity(&mut self) -> &mut Interactivity<V> {133 fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
134 self.base.interactivity()134 self.base.stateless_interactivity()
135 }135 }
136}136}
137 137
@@ -146,11 +146,14 @@ where · 8 unmodified lines
146 }146 }
147}147}
148 148
149impl<V, F> Click for Svg<V, StatefulInteractivity<V>, F>149impl<V, F> StatefullyInteractive for Svg<V, StatefulInteractivity<V>, F>
150where150where
151 V: 'static + Send + Sync,151 V: 'static + Send + Sync,
152 F: ElementFocusability<V>,152 F: ElementFocusability<V>,
153{153{
154 fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState> {
155 self.base.stateful_interactivity()
156 }
154}157}
155 158
156impl<V, F> Active for Svg<V, StatefulInteractivity<V>, F>159impl<V, F> Active for Svg<V, StatefulInteractivity<V>, F>
crates/gpui3/src/interactive.rs+23−108
@@ -1,19 +1,15 @@
1use parking_lot::Mutex;
2use smallvec::SmallVec;
3
4use crate::{1use crate::{
5 point, Action, Bounds, DispatchContext, DispatchPhase, Element, FocusHandle, Keystroke,2 point, Action, Bounds, DispatchContext, DispatchPhase, Element, FocusHandle, Keystroke,
6 Modifiers, Pixels, Point, ViewContext,3 Modifiers, Pixels, Point, StatefulInteractivity, StatelessInteractivity, ViewContext,
7};4};
8use std::{5use std::{
9 any::{Any, TypeId},6 any::{Any, TypeId},
10 mem,
11 ops::Deref,7 ops::Deref,
12 sync::Arc,8 sync::Arc,
13};9};
14 10
15pub trait Interactive: Element {11pub trait StatelesslyInteractive: Element {
16 fn interactivity(&mut self) -> &mut Interactivity<Self::ViewState>;12 fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<Self::ViewState>;
17 13
18 fn on_mouse_down(14 fn on_mouse_down(
19 mut self,15 mut self,
@@ -26,8 +22,8 @@ pub trait Interactive: Element { · 6 unmodified lines
26 where22 where
27 Self: Sized,23 Self: Sized,
28 {24 {
29 self.interactivity()25 self.stateless_interactivity()
30 .mouse_down26 .mouse_down_listeners
31 .push(Arc::new(move |view, event, bounds, phase, cx| {27 .push(Arc::new(move |view, event, bounds, phase, cx| {
32 if phase == DispatchPhase::Bubble28 if phase == DispatchPhase::Bubble
33 && event.button == button29 && event.button == button
@@ -50,8 +46,8 @@ pub trait Interactive: Element { · 16 unmodified lines
50 where46 where
51 Self: Sized,47 Self: Sized,
52 {48 {
53 self.interactivity()49 self.stateless_interactivity()
54 .mouse_up50 .mouse_up_listeners
55 .push(Arc::new(move |view, event, bounds, phase, cx| {51 .push(Arc::new(move |view, event, bounds, phase, cx| {
56 if phase == DispatchPhase::Bubble52 if phase == DispatchPhase::Bubble
57 && event.button == button53 && event.button == button
@@ -74,8 +70,8 @@ pub trait Interactive: Element { · 16 unmodified lines
74 where70 where
75 Self: Sized,71 Self: Sized,
76 {72 {
77 self.interactivity()73 self.stateless_interactivity()
78 .mouse_down74 .mouse_down_listeners
79 .push(Arc::new(move |view, event, bounds, phase, cx| {75 .push(Arc::new(move |view, event, bounds, phase, cx| {
80 if phase == DispatchPhase::Capture76 if phase == DispatchPhase::Capture
81 && event.button == button77 && event.button == button
@@ -98,8 +94,8 @@ pub trait Interactive: Element { · 16 unmodified lines
98 where94 where
99 Self: Sized,95 Self: Sized,
100 {96 {
101 self.interactivity()97 self.stateless_interactivity()
102 .mouse_up98 .mouse_up_listeners
103 .push(Arc::new(move |view, event, bounds, phase, cx| {99 .push(Arc::new(move |view, event, bounds, phase, cx| {
104 if phase == DispatchPhase::Capture100 if phase == DispatchPhase::Capture
105 && event.button == button101 && event.button == button
@@ -121,8 +117,8 @@ pub trait Interactive: Element { · 15 unmodified lines
121 where117 where
122 Self: Sized,118 Self: Sized,
123 {119 {
124 self.interactivity()120 self.stateless_interactivity()
125 .mouse_move121 .mouse_move_listeners
126 .push(Arc::new(move |view, event, bounds, phase, cx| {122 .push(Arc::new(move |view, event, bounds, phase, cx| {
127 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {123 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
128 handler(view, event, cx);124 handler(view, event, cx);
@@ -141,8 +137,8 @@ pub trait Interactive: Element { · 12 unmodified lines
141 where137 where
142 Self: Sized,138 Self: Sized,
143 {139 {
144 self.interactivity()140 self.stateless_interactivity()
145 .scroll_wheel141 .scroll_wheel_listeners
146 .push(Arc::new(move |view, event, bounds, phase, cx| {142 .push(Arc::new(move |view, event, bounds, phase, cx| {
147 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {143 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
148 handler(view, event, cx);144 handler(view, event, cx);
@@ -165,7 +161,7 @@ pub trait Interactive: Element { · 16 unmodified lines
165 where161 where
166 Self: Sized,162 Self: Sized,
167 {163 {
168 self.interactivity().key.push((164 self.stateless_interactivity().key_listeners.push((
169 TypeId::of::<KeyDownEvent>(),165 TypeId::of::<KeyDownEvent>(),
170 Arc::new(move |view, event, _, phase, cx| {166 Arc::new(move |view, event, _, phase, cx| {
171 let event = event.downcast_ref().unwrap();167 let event = event.downcast_ref().unwrap();
@@ -186,7 +182,7 @@ pub trait Interactive: Element { · 14 unmodified lines
186 where182 where
187 Self: Sized,183 Self: Sized,
188 {184 {
189 self.interactivity().key.push((185 self.stateless_interactivity().key_listeners.push((
190 TypeId::of::<KeyUpEvent>(),186 TypeId::of::<KeyUpEvent>(),
191 Arc::new(move |view, event, _, phase, cx| {187 Arc::new(move |view, event, _, phase, cx| {
192 let event = event.downcast_ref().unwrap();188 let event = event.downcast_ref().unwrap();
@@ -207,7 +203,7 @@ pub trait Interactive: Element { · 14 unmodified lines
207 where203 where
208 Self: Sized,204 Self: Sized,
209 {205 {
210 self.interactivity().key.push((206 self.stateless_interactivity().key_listeners.push((
211 TypeId::of::<A>(),207 TypeId::of::<A>(),
212 Arc::new(move |view, event, _, phase, cx| {208 Arc::new(move |view, event, _, phase, cx| {
213 let event = event.downcast_ref().unwrap();209 let event = event.downcast_ref().unwrap();
@@ -219,7 +215,9 @@ pub trait Interactive: Element { · 5 unmodified lines
219 }215 }
220}216}
221 217
222pub trait Click: Interactive {218pub trait StatefullyInteractive: StatelesslyInteractive {
219 fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState>;
220
223 fn on_click(221 fn on_click(
224 mut self,222 mut self,
225 handler: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)223 handler: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
@@ -230,8 +228,8 @@ pub trait Click: Interactive { · 4 unmodified lines
230 where228 where
231 Self: Sized,229 Self: Sized,
232 {230 {
233 self.interactivity()231 self.stateful_interactivity()
234 .mouse_click232 .mouse_click_listeners
235 .push(Arc::new(move |view, event, cx| handler(view, event, cx)));233 .push(Arc::new(move |view, event, cx| handler(view, event, cx)));
236 self234 self
237 }235 }
@@ -495,86 +493,3 @@ pub type KeyListener<V> = Arc< · 257 unmodified lines
495 + Sync493 + Sync
496 + 'static,494 + 'static,
497>;495>;
498
499pub struct Interactivity<V> {
500 pub mouse_down: SmallVec<[MouseDownListener<V>; 2]>,
501 pub mouse_up: SmallVec<[MouseUpListener<V>; 2]>,
502 pub mouse_click: SmallVec<[MouseClickListener<V>; 2]>,
503 pub mouse_move: SmallVec<[MouseMoveListener<V>; 2]>,
504 pub scroll_wheel: SmallVec<[ScrollWheelListener<V>; 2]>,
505 pub key: SmallVec<[(TypeId, KeyListener<V>); 32]>,
506}
507
508impl<V> Default for Interactivity<V> {
509 fn default() -> Self {
510 Self {
511 mouse_down: SmallVec::new(),
512 mouse_up: SmallVec::new(),
513 mouse_click: SmallVec::new(),
514 mouse_move: SmallVec::new(),
515 scroll_wheel: SmallVec::new(),
516 key: SmallVec::new(),
517 }
518 }
519}
520
521impl<V> Interactivity<V>
522where
523 V: 'static + Send + Sync,
524{
525 pub fn paint(
526 &mut self,
527 bounds: Bounds<Pixels>,
528 pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
529 cx: &mut ViewContext<V>,
530 ) {
531 let click_listeners = mem::take(&mut self.mouse_click);
532
533 let mouse_down = pending_click.lock().clone();
534 if let Some(mouse_down) = mouse_down {
535 cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
536 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
537 let mouse_click = MouseClickEvent {
538 down: mouse_down.clone(),
539 up: event.clone(),
540 };
541 for listener in &click_listeners {
542 listener(state, &mouse_click, cx);
543 }
544 }
545
546 *pending_click.lock() = None;
547 });
548 } else {
549 cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
550 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
551 *pending_click.lock() = Some(event.clone());
552 }
553 });
554 }
555
556 for listener in mem::take(&mut self.mouse_down) {
557 cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
558 listener(state, event, &bounds, phase, cx);
559 })
560 }
561
562 for listener in mem::take(&mut self.mouse_up) {
563 cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
564 listener(state, event, &bounds, phase, cx);
565 })
566 }
567
568 for listener in mem::take(&mut self.mouse_move) {
569 cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
570 listener(state, event, &bounds, phase, cx);
571 })
572 }
573
574 for listener in mem::take(&mut self.scroll_wheel) {
575 cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
576 listener(state, event, &bounds, phase, cx);
577 })
578 }
579 }
580}
crates/ui2/src/components/icon_button.rs+1−1
@@ -1,7 +1,7 @@
1use std::marker::PhantomData;1use std::marker::PhantomData;
2use std::sync::Arc;2use std::sync::Arc;
3 3
4use gpui3::{Interactive, MouseButton};4use gpui3::{MouseButton, StatelesslyInteractive};
5 5
6use crate::{h_stack, prelude::*};6use crate::{h_stack, prelude::*};
7use crate::{theme, ClickHandler, Icon, IconColor, IconElement};7use crate::{theme, ClickHandler, Icon, IconColor, IconElement};
crates/ui2/src/elements/button.rs+1−1
@@ -1,7 +1,7 @@
1use std::marker::PhantomData;1use std::marker::PhantomData;
2use std::sync::Arc;2use std::sync::Arc;
3 3
4use gpui3::{DefiniteLength, Hsla, Interactive, MouseButton, WindowContext};4use gpui3::{DefiniteLength, Hsla, MouseButton, StatelesslyInteractive, WindowContext};
5 5
6use crate::settings::user_settings;6use crate::settings::user_settings;
7use crate::{h_stack, Icon, IconColor, IconElement, Label, LabelColor};7use crate::{h_stack, Icon, IconColor, IconElement, Label, LabelColor};
crates/ui2/src/prelude.rs+2−2
@@ -1,6 +1,6 @@
1pub use gpui3::{1pub use gpui3::{
2 div, Active, Click, Element, Hover, IntoAnyElement, ParentElement, ScrollState, SharedString,2 div, Click, Element, Hover, IntoAnyElement, ParentElement, ScrollState, SharedString,
3 Styled, ViewContext, WindowContext,3 StatefullyInteractivee, Styled, ViewContext, WindowContext,
4};4};
5 5
6use crate::settings::user_settings;6use crate::settings::user_settings;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t