Checkpoint
This commit is contained in:
parent
da8919002f
commit
96f2c4a9de
8 changed files with 170 additions and 57 deletions
|
@ -9,11 +9,11 @@ use refineable::Refineable;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
current_platform, image_cache::ImageCache, Action, AppMetadata, AssetSource, Context,
|
current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AppMetadata, AssetSource,
|
||||||
DispatchPhase, DisplayId, Executor, FocusEvent, FocusHandle, FocusId, KeyBinding, Keymap,
|
Context, DispatchPhase, DisplayId, Executor, FocusEvent, FocusHandle, FocusId, KeyBinding,
|
||||||
LayoutId, MainThread, MainThreadOnly, Platform, SharedString, SubscriberSet, Subscription,
|
Keymap, LayoutId, MainThread, MainThreadOnly, Platform, SharedString, SubscriberSet,
|
||||||
SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, View, Window, WindowContext,
|
Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, View, Window,
|
||||||
WindowHandle, WindowId,
|
WindowContext, WindowHandle, WindowId,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use collections::{HashMap, HashSet, VecDeque};
|
use collections::{HashMap, HashSet, VecDeque};
|
||||||
|
@ -91,6 +91,7 @@ impl App {
|
||||||
global_observers: SubscriberSet::new(),
|
global_observers: SubscriberSet::new(),
|
||||||
layout_id_buffer: Default::default(),
|
layout_id_buffer: Default::default(),
|
||||||
propagate_event: true,
|
propagate_event: true,
|
||||||
|
active_drag: None,
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -168,6 +169,7 @@ pub struct AppContext {
|
||||||
text_system: Arc<TextSystem>,
|
text_system: Arc<TextSystem>,
|
||||||
flushing_effects: bool,
|
flushing_effects: bool,
|
||||||
pending_updates: usize,
|
pending_updates: usize,
|
||||||
|
pub(crate) active_drag: Option<AnyDrag>,
|
||||||
pub(crate) next_frame_callbacks: HashMap<DisplayId, Vec<FrameCallback>>,
|
pub(crate) next_frame_callbacks: HashMap<DisplayId, Vec<FrameCallback>>,
|
||||||
pub(crate) executor: Executor,
|
pub(crate) executor: Executor,
|
||||||
pub(crate) svg_renderer: SvgRenderer,
|
pub(crate) svg_renderer: SvgRenderer,
|
||||||
|
@ -732,6 +734,12 @@ pub(crate) enum Effect {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct AnyDrag {
|
||||||
|
pub drag_handle_view: AnyView,
|
||||||
|
pub state: AnyBox,
|
||||||
|
pub state_type: TypeId,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::AppContext;
|
use super::AppContext;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
point, AnyElement, BorrowWindow, Bounds, Element, ElementFocus, ElementId, ElementInteraction,
|
point, AnyElement, BorrowWindow, Bounds, Element, ElementFocus, ElementId,
|
||||||
FocusDisabled, FocusEnabled, FocusHandle, FocusListeners, Focusable, GlobalElementId,
|
ElementInteraction, FocusDisabled, FocusEnabled, FocusHandle, FocusListeners, Focusable,
|
||||||
GroupBounds, InteractiveElementState, IntoAnyElement, LayoutId, Overflow, ParentElement,
|
GlobalElementId, GroupBounds, InteractiveElementState, IntoAnyElement, LayoutId, Overflow,
|
||||||
Pixels, Point, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction,
|
ParentElement, Pixels, Point, SharedString, StatefulInteraction, StatefulInteractive,
|
||||||
StatelessInteractive, Style, StyleRefinement, Styled, ViewContext,
|
StatelessInteraction, StatelessInteractive, Style, StyleRefinement, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use refineable::Refineable;
|
use refineable::Refineable;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
@ -364,7 +364,7 @@ where
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
fn stateful_interactivity(&mut self) -> &mut StatefulInteraction<Self::ViewState> {
|
fn stateful_interaction(&mut self) -> &mut StatefulInteraction<Self::ViewState> {
|
||||||
&mut self.interaction
|
&mut self.interaction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,8 +166,8 @@ where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
fn stateful_interactivity(&mut self) -> &mut StatefulInteraction<Self::ViewState> {
|
fn stateful_interaction(&mut self) -> &mut StatefulInteraction<Self::ViewState> {
|
||||||
self.base.stateful_interactivity()
|
self.base.stateful_interaction()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,8 +140,8 @@ where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
fn stateful_interactivity(&mut self) -> &mut StatefulInteraction<Self::ViewState> {
|
fn stateful_interaction(&mut self) -> &mut StatefulInteraction<Self::ViewState> {
|
||||||
self.base.stateful_interactivity()
|
self.base.stateful_interaction()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
point, px, Action, AppContext, BorrowWindow, Bounds, DispatchContext, DispatchPhase, Element,
|
point, px, view, Action, AnyDrag, AppContext, BorrowWindow, Bounds, DispatchContext,
|
||||||
ElementId, FocusHandle, KeyMatch, Keystroke, Modifiers, Overflow, Pixels, Point, SharedString,
|
DispatchPhase, Element, ElementId, FocusHandle, KeyMatch, Keystroke, Modifiers, Overflow,
|
||||||
Size, Style, StyleRefinement, ViewContext,
|
Pixels, Point, SharedString, Size, Style, StyleRefinement, ViewContext,
|
||||||
};
|
};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
|
@ -11,6 +11,7 @@ use smallvec::SmallVec;
|
||||||
use std::{
|
use std::{
|
||||||
any::{Any, TypeId},
|
any::{Any, TypeId},
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
|
marker::PhantomData,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
@ -257,13 +258,13 @@ pub trait StatelessInteractive: Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait StatefulInteractive: StatelessInteractive {
|
pub trait StatefulInteractive: StatelessInteractive {
|
||||||
fn stateful_interactivity(&mut self) -> &mut StatefulInteraction<Self::ViewState>;
|
fn stateful_interaction(&mut self) -> &mut StatefulInteraction<Self::ViewState>;
|
||||||
|
|
||||||
fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateful_interactivity().active_style = f(StyleRefinement::default());
|
self.stateful_interaction().active_style = f(StyleRefinement::default());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +276,7 @@ pub trait StatefulInteractive: StatelessInteractive {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateful_interactivity().group_active_style = Some(GroupStyle {
|
self.stateful_interaction().group_active_style = Some(GroupStyle {
|
||||||
group: group_name.into(),
|
group: group_name.into(),
|
||||||
style: f(StyleRefinement::default()),
|
style: f(StyleRefinement::default()),
|
||||||
});
|
});
|
||||||
|
@ -284,7 +285,7 @@ pub trait StatefulInteractive: StatelessInteractive {
|
||||||
|
|
||||||
fn on_click(
|
fn on_click(
|
||||||
mut self,
|
mut self,
|
||||||
handler: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
|
listener: impl Fn(&mut Self::ViewState, &ClickEvent, &mut ViewContext<Self::ViewState>)
|
||||||
+ Send
|
+ Send
|
||||||
+ Sync
|
+ Sync
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
@ -292,9 +293,45 @@ pub trait StatefulInteractive: StatelessInteractive {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateful_interactivity()
|
self.stateful_interaction()
|
||||||
.mouse_click_listeners
|
.click_listeners
|
||||||
.push(Arc::new(move |view, event, cx| handler(view, event, cx)));
|
.push(Arc::new(move |view, event, cx| listener(view, event, cx)));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_drag<S, R, E>(
|
||||||
|
mut self,
|
||||||
|
listener: impl Fn(
|
||||||
|
&mut Self::ViewState,
|
||||||
|
&mut ViewContext<Self::ViewState>,
|
||||||
|
) -> Drag<S, R, Self::ViewState, E>
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
S: 'static + Send + Sync,
|
||||||
|
R: 'static + Fn(&mut Self::ViewState, &mut ViewContext<Self::ViewState>) -> E + Send + Sync,
|
||||||
|
E: Element<ViewState = Self::ViewState>,
|
||||||
|
{
|
||||||
|
debug_assert!(
|
||||||
|
self.stateful_interaction().drag_listener.is_none(),
|
||||||
|
"calling on_drag more than once on the same element is not supported"
|
||||||
|
);
|
||||||
|
self.stateful_interaction().drag_listener = Some(Arc::new(move |view_state, cx| {
|
||||||
|
let drag = listener(view_state, cx);
|
||||||
|
let view_handle = cx.handle().upgrade().unwrap();
|
||||||
|
let drag_handle_view = view(view_handle, move |view_state, cx| {
|
||||||
|
(drag.render_drag_handle)(view_state, cx)
|
||||||
|
})
|
||||||
|
.into_any();
|
||||||
|
AnyDrag {
|
||||||
|
drag_handle_view,
|
||||||
|
state: Box::new(drag.state),
|
||||||
|
state_type: TypeId::of::<S>(),
|
||||||
|
}
|
||||||
|
}));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -419,31 +456,46 @@ pub trait ElementInteraction<V: 'static + Send + Sync>: 'static + Send + Sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(stateful) = self.as_stateful() {
|
if let Some(stateful) = self.as_stateful() {
|
||||||
let click_listeners = stateful.mouse_click_listeners.clone();
|
let click_listeners = stateful.click_listeners.clone();
|
||||||
|
let drag_listener = stateful.drag_listener.clone();
|
||||||
|
|
||||||
let pending_click = element_state.pending_click.clone();
|
if !click_listeners.is_empty() || drag_listener.is_some() {
|
||||||
let mouse_down = pending_click.lock().clone();
|
let pending_mouse_down = element_state.pending_mouse_down.clone();
|
||||||
|
let mouse_down = pending_mouse_down.lock().clone();
|
||||||
if let Some(mouse_down) = mouse_down {
|
if let Some(mouse_down) = mouse_down {
|
||||||
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
|
if let Some(drag_listener) = drag_listener {
|
||||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
cx.on_mouse_event(move |view_state, _: &MouseMoveEvent, phase, cx| {
|
||||||
let mouse_click = MouseClickEvent {
|
if phase == DispatchPhase::Bubble {
|
||||||
|
let any_drag = drag_listener(view_state, cx);
|
||||||
|
cx.start_drag(any_drag);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
cx.on_mouse_event(move |view_state, event: &MouseUpEvent, phase, cx| {
|
||||||
|
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position)
|
||||||
|
{
|
||||||
|
let mouse_click = ClickEvent {
|
||||||
down: mouse_down.clone(),
|
down: mouse_down.clone(),
|
||||||
up: event.clone(),
|
up: event.clone(),
|
||||||
};
|
};
|
||||||
for listener in &click_listeners {
|
for listener in &click_listeners {
|
||||||
listener(state, &mouse_click, cx);
|
listener(view_state, &mouse_click, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*pending_click.lock() = None;
|
cx.end_drag();
|
||||||
|
*pending_mouse_down.lock() = None;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
|
cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
|
||||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position)
|
||||||
*pending_click.lock() = Some(event.clone());
|
{
|
||||||
|
*pending_mouse_down.lock() = Some(event.clone());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let active_state = element_state.active_state.clone();
|
let active_state = element_state.active_state.clone();
|
||||||
if active_state.lock().is_none() {
|
if active_state.lock().is_none() {
|
||||||
|
@ -526,7 +578,8 @@ pub struct StatefulInteraction<V: 'static + Send + Sync> {
|
||||||
#[deref]
|
#[deref]
|
||||||
#[deref_mut]
|
#[deref_mut]
|
||||||
stateless: StatelessInteraction<V>,
|
stateless: StatelessInteraction<V>,
|
||||||
pub mouse_click_listeners: SmallVec<[MouseClickListener<V>; 2]>,
|
pub click_listeners: SmallVec<[ClickListener<V>; 2]>,
|
||||||
|
pub(crate) drag_listener: Option<DragListener<V>>,
|
||||||
pub active_style: StyleRefinement,
|
pub active_style: StyleRefinement,
|
||||||
pub group_active_style: Option<GroupStyle>,
|
pub group_active_style: Option<GroupStyle>,
|
||||||
}
|
}
|
||||||
|
@ -560,7 +613,8 @@ where
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
stateless: StatelessInteraction::default(),
|
stateless: StatelessInteraction::default(),
|
||||||
mouse_click_listeners: SmallVec::new(),
|
click_listeners: SmallVec::new(),
|
||||||
|
drag_listener: None,
|
||||||
active_style: StyleRefinement::default(),
|
active_style: StyleRefinement::default(),
|
||||||
group_active_style: None,
|
group_active_style: None,
|
||||||
}
|
}
|
||||||
|
@ -586,7 +640,8 @@ where
|
||||||
StatefulInteraction {
|
StatefulInteraction {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
stateless: self,
|
stateless: self,
|
||||||
mouse_click_listeners: SmallVec::new(),
|
click_listeners: SmallVec::new(),
|
||||||
|
drag_listener: None,
|
||||||
active_style: StyleRefinement::default(),
|
active_style: StyleRefinement::default(),
|
||||||
group_active_style: None,
|
group_active_style: None,
|
||||||
}
|
}
|
||||||
|
@ -642,7 +697,7 @@ impl ActiveState {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct InteractiveElementState {
|
pub struct InteractiveElementState {
|
||||||
active_state: Arc<Mutex<ActiveState>>,
|
active_state: Arc<Mutex<ActiveState>>,
|
||||||
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
|
pending_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
|
||||||
scroll_offset: Option<Arc<Mutex<Point<Pixels>>>>,
|
scroll_offset: Option<Arc<Mutex<Point<Pixels>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -740,11 +795,39 @@ pub struct MouseUpEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct MouseClickEvent {
|
pub struct ClickEvent {
|
||||||
pub down: MouseDownEvent,
|
pub down: MouseDownEvent,
|
||||||
pub up: MouseUpEvent,
|
pub up: MouseUpEvent,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Drag<S, R, V, E>
|
||||||
|
where
|
||||||
|
S: 'static + Send + Sync,
|
||||||
|
R: Fn(&mut V, &mut ViewContext<V>) -> E,
|
||||||
|
V: 'static + Send + Sync,
|
||||||
|
E: Element<ViewState = V>,
|
||||||
|
{
|
||||||
|
pub state: S,
|
||||||
|
pub render_drag_handle: R,
|
||||||
|
view_type: PhantomData<V>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, R, V, E> Drag<S, R, V, E>
|
||||||
|
where
|
||||||
|
S: 'static + Send + Sync,
|
||||||
|
R: Fn(&mut V, &mut ViewContext<V>) -> E + Send + Sync,
|
||||||
|
V: 'static + Send + Sync,
|
||||||
|
E: Element<ViewState = V>,
|
||||||
|
{
|
||||||
|
pub fn new(state: S, render_drag_handle: R) -> Self {
|
||||||
|
Drag {
|
||||||
|
state,
|
||||||
|
render_drag_handle,
|
||||||
|
view_type: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
|
#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
|
||||||
pub enum MouseButton {
|
pub enum MouseButton {
|
||||||
Left,
|
Left,
|
||||||
|
@ -919,8 +1002,6 @@ pub type MouseUpListener<V> = Arc<
|
||||||
+ Sync
|
+ Sync
|
||||||
+ 'static,
|
+ 'static,
|
||||||
>;
|
>;
|
||||||
pub type MouseClickListener<V> =
|
|
||||||
Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
|
|
||||||
|
|
||||||
pub type MouseMoveListener<V> = Arc<
|
pub type MouseMoveListener<V> = Arc<
|
||||||
dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||||
|
@ -936,6 +1017,12 @@ pub type ScrollWheelListener<V> = Arc<
|
||||||
+ 'static,
|
+ 'static,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
pub type ClickListener<V> =
|
||||||
|
Arc<dyn Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||||
|
|
||||||
|
pub(crate) type DragListener<V> =
|
||||||
|
Arc<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyDrag + Send + Sync + 'static>;
|
||||||
|
|
||||||
pub type KeyListener<V> = Arc<
|
pub type KeyListener<V> = Arc<
|
||||||
dyn Fn(
|
dyn Fn(
|
||||||
&mut V,
|
&mut V,
|
||||||
|
|
|
@ -201,7 +201,7 @@ impl InputEvent {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
window_height.map(|window_height| {
|
dbg!(window_height.map(|window_height| {
|
||||||
Self::MouseMoved(MouseMoveEvent {
|
Self::MouseMoved(MouseMoveEvent {
|
||||||
pressed_button: Some(pressed_button),
|
pressed_button: Some(pressed_button),
|
||||||
position: point(
|
position: point(
|
||||||
|
@ -210,7 +210,7 @@ impl InputEvent {
|
||||||
),
|
),
|
||||||
modifiers: read_modifiers(native_event),
|
modifiers: read_modifiers(native_event),
|
||||||
})
|
})
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
NSEventType::NSMouseMoved => window_height.map(|window_height| {
|
NSEventType::NSMouseMoved => window_height.map(|window_height| {
|
||||||
Self::MouseMoved(MouseMoveEvent {
|
Self::MouseMoved(MouseMoveEvent {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
px, size, Action, AnyBox, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
|
px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
|
||||||
BorrowAppContext, Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext,
|
BorrowAppContext, Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext,
|
||||||
DisplayId, Edges, Effect, Element, EntityId, EventEmitter, FocusEvent, FontId, GlobalElementId,
|
DisplayId, Edges, Effect, Element, EntityId, EventEmitter, FocusEvent, FontId, GlobalElementId,
|
||||||
GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher,
|
GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher,
|
||||||
|
@ -1605,6 +1605,14 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn start_drag(&mut self, drag: AnyDrag) {
|
||||||
|
self.app.active_drag = Some(drag);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn end_drag(&mut self) {
|
||||||
|
self.app.active_drag = None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'w, V: EventEmitter + Send + Sync + 'static> ViewContext<'a, 'w, V> {
|
impl<'a, 'w, V: EventEmitter + Send + Sync + 'static> ViewContext<'a, 'w, V> {
|
||||||
|
|
|
@ -17,6 +17,10 @@ pub struct Tab<S: 'static + Send + Sync + Clone> {
|
||||||
close_side: IconSide,
|
close_side: IconSide,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TabDragState {
|
||||||
|
title: String,
|
||||||
|
}
|
||||||
|
|
||||||
impl<S: 'static + Send + Sync + Clone> Tab<S> {
|
impl<S: 'static + Send + Sync + Clone> Tab<S> {
|
||||||
pub fn new(id: impl Into<ElementId>) -> Self {
|
pub fn new(id: impl Into<ElementId>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -113,6 +117,12 @@ impl<S: 'static + Send + Sync + Clone> Tab<S> {
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.id(self.id.clone())
|
.id(self.id.clone())
|
||||||
|
// .on_drag(|_view, _cx| Drag {
|
||||||
|
// element: div().w_8().h_4().bg(black()),
|
||||||
|
// state: TabDragState {
|
||||||
|
// title: self.title.clone(),
|
||||||
|
// },
|
||||||
|
// })
|
||||||
.px_2()
|
.px_2()
|
||||||
.py_0p5()
|
.py_0p5()
|
||||||
.flex()
|
.flex()
|
||||||
|
@ -148,7 +158,7 @@ impl<S: 'static + Send + Sync + Clone> Tab<S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use gpui2::ElementId;
|
use gpui2::{black, ElementId};
|
||||||
#[cfg(feature = "stories")]
|
#[cfg(feature = "stories")]
|
||||||
pub use stories::*;
|
pub use stories::*;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue