mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-06 10:42:08 +00:00
Show red box when dragging
This commit is contained in:
parent
96f2c4a9de
commit
d1adce5890
8 changed files with 95 additions and 50 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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::*;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue