Show red box when dragging

This commit is contained in:
Nathan Sobo 2023-10-23 15:09:22 +02:00
parent 96f2c4a9de
commit d1adce5890
8 changed files with 95 additions and 50 deletions

View file

@ -155,6 +155,15 @@ pub fn white() -> Hsla {
} }
} }
pub fn red() -> Hsla {
Hsla {
h: 0.,
s: 1.,
l: 0.5,
a: 1.,
}
}
impl Hsla { impl Hsla {
/// Returns true if the HSLA color is fully transparent, false otherwise. /// Returns true if the HSLA color is fully transparent, false otherwise.
pub fn is_transparent(&self) -> bool { pub fn is_transparent(&self) -> bool {

View file

@ -1,9 +1,9 @@
use crate::{ use crate::{
point, AnyElement, BorrowWindow, Bounds, Element, ElementFocus, ElementId, point, AnyElement, BorrowWindow, Bounds, Element, ElementFocus, ElementId, ElementInteraction,
ElementInteraction, FocusDisabled, FocusEnabled, FocusHandle, FocusListeners, Focusable, FocusDisabled, FocusEnabled, FocusHandle, FocusListeners, Focusable, GlobalElementId,
GlobalElementId, GroupBounds, InteractiveElementState, IntoAnyElement, LayoutId, Overflow, GroupBounds, InteractiveElementState, IntoAnyElement, LayoutId, Overflow, ParentElement,
ParentElement, Pixels, Point, SharedString, StatefulInteraction, StatefulInteractive, Pixels, Point, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction,
StatelessInteraction, StatelessInteractive, Style, StyleRefinement, Styled, ViewContext, StatelessInteractive, Style, StyleRefinement, Styled, ViewContext,
}; };
use refineable::Refineable; use refineable::Refineable;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -298,7 +298,7 @@ where
style.apply_text_style(cx, |cx| { style.apply_text_style(cx, |cx| {
style.apply_overflow(bounds, cx, |cx| { style.apply_overflow(bounds, cx, |cx| {
let scroll_offset = element_state.interactive.scroll_offset(); let scroll_offset = element_state.interactive.scroll_offset();
cx.with_scroll_offset(scroll_offset, |cx| { cx.with_element_offset(scroll_offset, |cx| {
for child in &mut this.children { for child in &mut this.children {
child.paint(view_state, cx); child.paint(view_state, cx);
} }

View file

@ -7,7 +7,9 @@ use std::{
ops::{Add, Div, Mul, MulAssign, Sub}, ops::{Add, Div, Mul, MulAssign, Sub},
}; };
#[derive(Refineable, Default, Add, AddAssign, Sub, SubAssign, Copy, Debug, PartialEq, Eq, Hash)] #[derive(
Refineable, Default, Add, AddAssign, Sub, SubAssign, Copy, Debug, PartialEq, Eq, Hash, Neg,
)]
#[refineable(debug)] #[refineable(debug)]
#[repr(C)] #[repr(C)]
pub struct Point<T: Default + Clone + Debug> { pub struct Point<T: Default + Clone + Debug> {

View file

@ -464,10 +464,17 @@ pub trait ElementInteraction<V: 'static + Send + Sync>: 'static + Send + Sync {
let mouse_down = pending_mouse_down.lock().clone(); let mouse_down = pending_mouse_down.lock().clone();
if let Some(mouse_down) = mouse_down { if let Some(mouse_down) = mouse_down {
if let Some(drag_listener) = drag_listener { if let Some(drag_listener) = drag_listener {
cx.on_mouse_event(move |view_state, _: &MouseMoveEvent, phase, cx| { cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| {
if phase == DispatchPhase::Bubble { if cx.active_drag.is_some() {
if phase == DispatchPhase::Capture {
cx.notify();
}
} else if phase == DispatchPhase::Bubble
&& bounds.contains_point(&event.position)
{
let any_drag = drag_listener(view_state, cx); let any_drag = drag_listener(view_state, cx);
cx.start_drag(any_drag); cx.start_drag(any_drag);
cx.stop_propagation();
} }
}); });
} }
@ -484,7 +491,9 @@ pub trait ElementInteraction<V: 'static + Send + Sync>: 'static + Send + Sync {
} }
} }
cx.end_drag(); if cx.active_drag.is_some() {
cx.end_drag();
}
*pending_mouse_down.lock() = None; *pending_mouse_down.lock() = None;
}); });
} else { } else {

View file

@ -201,7 +201,7 @@ impl InputEvent {
_ => return None, _ => return None,
}; };
dbg!(window_height.map(|window_height| { 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 {

View file

@ -129,7 +129,7 @@ impl TaffyLayoutEngine {
self.taffy self.taffy
.compute_layout(id.into(), available_space.into()) .compute_layout(id.into(), available_space.into())
.expect(EXPECT_MESSAGE); .expect(EXPECT_MESSAGE);
println!("compute_layout took {:?}", started_at.elapsed()); // println!("compute_layout took {:?}", started_at.elapsed());
} }
pub fn layout_bounds(&mut self, id: LayoutId) -> Bounds<Pixels> { pub fn layout_bounds(&mut self, id: LayoutId) -> Bounds<Pixels> {

View file

@ -159,7 +159,7 @@ pub struct Window {
key_matchers: HashMap<GlobalElementId, KeyMatcher>, key_matchers: HashMap<GlobalElementId, KeyMatcher>,
z_index_stack: StackingOrder, z_index_stack: StackingOrder,
content_mask_stack: Vec<ContentMask<Pixels>>, content_mask_stack: Vec<ContentMask<Pixels>>,
scroll_offset_stack: Vec<Point<Pixels>>, element_offset_stack: Vec<Point<Pixels>>,
mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyListener)>>, mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyListener)>>,
key_dispatch_stack: Vec<KeyDispatchStackFrame>, key_dispatch_stack: Vec<KeyDispatchStackFrame>,
freeze_key_dispatch_stack: bool, freeze_key_dispatch_stack: bool,
@ -177,7 +177,7 @@ pub struct Window {
} }
impl Window { impl Window {
pub fn new( pub(crate) fn new(
handle: AnyWindowHandle, handle: AnyWindowHandle,
options: WindowOptions, options: WindowOptions,
cx: &mut MainThread<AppContext>, cx: &mut MainThread<AppContext>,
@ -234,7 +234,7 @@ impl Window {
key_matchers: HashMap::default(), key_matchers: HashMap::default(),
z_index_stack: StackingOrder(SmallVec::new()), z_index_stack: StackingOrder(SmallVec::new()),
content_mask_stack: Vec::new(), content_mask_stack: Vec::new(),
scroll_offset_stack: Vec::new(), element_offset_stack: Vec::new(),
mouse_listeners: HashMap::default(), mouse_listeners: HashMap::default(),
key_dispatch_stack: Vec::new(), key_dispatch_stack: Vec::new(),
freeze_key_dispatch_stack: false, freeze_key_dispatch_stack: false,
@ -469,7 +469,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
.layout_engine .layout_engine
.layout_bounds(layout_id) .layout_bounds(layout_id)
.map(Into::into); .map(Into::into);
bounds.origin -= self.scroll_offset(); bounds.origin -= self.element_offset();
bounds bounds
} }
@ -805,14 +805,22 @@ impl<'a, 'w> WindowContext<'a, 'w> {
let mut root_view = cx.window.root_view.take().unwrap(); let mut root_view = cx.window.root_view.take().unwrap();
if let Some(element_id) = root_view.id() { cx.stack(0, |cx| {
cx.with_element_state(element_id, |element_state, cx| { let available_space = cx.window.content_size.map(Into::into);
let element_state = draw_with_element_state(&mut root_view, element_state, cx); draw_any_view(&mut root_view, available_space, cx);
((), element_state) });
if let Some(mut active_drag) = cx.active_drag.take() {
cx.stack(1, |cx| {
let mouse_position = -cx.mouse_position();
cx.with_element_offset(Some(mouse_position), |cx| {
let available_space =
size(AvailableSpace::MinContent, AvailableSpace::MinContent);
draw_any_view(&mut active_drag.drag_handle_view, available_space, cx);
cx.active_drag = Some(active_drag);
});
}); });
} else { }
draw_with_element_state(&mut root_view, None, cx);
};
cx.window.root_view = Some(root_view); cx.window.root_view = Some(root_view);
let scene = cx.window.scene_builder.build(); let scene = cx.window.scene_builder.build();
@ -827,20 +835,21 @@ impl<'a, 'w> WindowContext<'a, 'w> {
.detach(); .detach();
}); });
fn draw_with_element_state( fn draw_any_view(
root_view: &mut AnyView, view: &mut AnyView,
element_state: Option<AnyBox>, available_space: Size<AvailableSpace>,
cx: &mut ViewContext<()>, cx: &mut ViewContext<()>,
) -> AnyBox { ) {
let mut element_state = root_view.initialize(&mut (), element_state, cx); cx.with_optional_element_state(view.id(), |element_state, cx| {
let layout_id = root_view.layout(&mut (), &mut element_state, cx); let mut element_state = view.initialize(&mut (), element_state, cx);
let available_space = cx.window.content_size.map(Into::into); let layout_id = view.layout(&mut (), &mut element_state, cx);
cx.window cx.window
.layout_engine .layout_engine
.compute_layout(layout_id, available_space); .compute_layout(layout_id, available_space);
let bounds = cx.window.layout_engine.layout_bounds(layout_id); let bounds = cx.window.layout_engine.layout_bounds(layout_id);
root_view.paint(bounds, &mut (), &mut element_state, cx); view.paint(bounds, &mut (), &mut element_state, cx);
element_state ((), element_state)
});
} }
} }
@ -1209,7 +1218,7 @@ pub trait BorrowWindow: BorrowAppContext {
result result
} }
fn with_scroll_offset<R>( fn with_element_offset<R>(
&mut self, &mut self,
offset: Option<Point<Pixels>>, offset: Option<Point<Pixels>>,
f: impl FnOnce(&mut Self) -> R, f: impl FnOnce(&mut Self) -> R,
@ -1218,16 +1227,16 @@ pub trait BorrowWindow: BorrowAppContext {
return f(self); return f(self);
}; };
let offset = self.scroll_offset() + offset; let offset = self.element_offset() + offset;
self.window_mut().scroll_offset_stack.push(offset); self.window_mut().element_offset_stack.push(offset);
let result = f(self); let result = f(self);
self.window_mut().scroll_offset_stack.pop(); self.window_mut().element_offset_stack.pop();
result result
} }
fn scroll_offset(&self) -> Point<Pixels> { fn element_offset(&self) -> Point<Pixels> {
self.window() self.window()
.scroll_offset_stack .element_offset_stack
.last() .last()
.copied() .copied()
.unwrap_or_default() .unwrap_or_default()
@ -1266,6 +1275,18 @@ pub trait BorrowWindow: BorrowAppContext {
}) })
} }
fn with_optional_element_state<S: 'static + Send + Sync, R>(
&mut self,
element_id: Option<ElementId>,
f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
) -> R {
if let Some(element_id) = element_id {
self.with_element_state(element_id, f)
} else {
f(None, self).0
}
}
fn content_mask(&self) -> ContentMask<Pixels> { fn content_mask(&self) -> ContentMask<Pixels> {
self.window() self.window()
.content_mask_stack .content_mask_stack
@ -1608,10 +1629,12 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
pub(crate) fn start_drag(&mut self, drag: AnyDrag) { pub(crate) fn start_drag(&mut self, drag: AnyDrag) {
self.app.active_drag = Some(drag); self.app.active_drag = Some(drag);
self.notify();
} }
pub(crate) fn end_drag(&mut self) { pub(crate) fn end_drag(&mut self) {
self.app.active_drag = None; self.app.active_drag = None;
self.notify();
} }
} }

View file

@ -17,6 +17,7 @@ pub struct Tab<S: 'static + Send + Sync + Clone> {
close_side: IconSide, close_side: IconSide,
} }
#[derive(Clone)]
struct TabDragState { struct TabDragState {
title: String, title: String,
} }
@ -115,14 +116,15 @@ impl<S: 'static + Send + Sync + Clone> Tab<S> {
), ),
}; };
let drag_state = TabDragState {
title: self.title.clone(),
};
div() div()
.id(self.id.clone()) .id(self.id.clone())
// .on_drag(|_view, _cx| Drag { .on_drag(move |_view, _cx| {
// element: div().w_8().h_4().bg(black()), Drag::new(drag_state.clone(), |view, cx| div().w_8().h_4().bg(red()))
// state: TabDragState { })
// title: self.title.clone(),
// },
// })
.px_2() .px_2()
.py_0p5() .py_0p5()
.flex() .flex()
@ -158,7 +160,7 @@ impl<S: 'static + Send + Sync + Clone> Tab<S> {
} }
} }
use gpui2::{black, ElementId}; use gpui2::{red, Drag, ElementId};
#[cfg(feature = "stories")] #[cfg(feature = "stories")]
pub use stories::*; pub use stories::*;