diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 6019ec0167..2ed1046940 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -821,7 +821,7 @@ impl DerefMut for GlobalLease { } pub(crate) struct AnyDrag { - pub drag_handle_view: AnyView, + pub drag_handle_view: Option, pub cursor_offset: Point, pub state: AnyBox, pub state_type: TypeId, diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index ac23c915f4..60869d7eeb 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -374,10 +374,12 @@ pub trait StatefulInteractive: StatelessInteractive { Some(Arc::new(move |view_state, cursor_offset, 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(); + let drag_handle_view = Some( + view(view_handle, move |view_state, cx| { + (drag.render_drag_handle)(view_state, cx) + }) + .into_any(), + ); AnyDrag { drag_handle_view, cursor_offset, @@ -780,11 +782,7 @@ impl GroupBounds { } pub fn pop(name: &SharedString, cx: &mut AppContext) { - cx.default_global::() - .0 - .get_mut(name) - .unwrap() - .pop(); + cx.default_global::().0.get_mut(name).unwrap().pop(); } } @@ -1035,16 +1033,21 @@ impl Deref for MouseExitEvent { } #[derive(Debug, Clone, Default)] +pub struct DroppedFiles(pub(crate) SmallVec<[PathBuf; 2]>); + +#[derive(Debug, Clone)] pub enum FileDropEvent { - #[default] - End, + Entered { + position: Point, + files: DroppedFiles, + }, Pending { position: Point, }, Submit { position: Point, - paths: Vec, }, + Exited, } #[derive(Clone, Debug)] @@ -1054,7 +1057,7 @@ pub enum InputEvent { ModifiersChanged(ModifiersChangedEvent), MouseDown(MouseDownEvent), MouseUp(MouseUpEvent), - MouseMoved(MouseMoveEvent), + MouseMove(MouseMoveEvent), MouseExited(MouseExitEvent), ScrollWheel(ScrollWheelEvent), FileDrop(FileDropEvent), @@ -1068,12 +1071,14 @@ impl InputEvent { InputEvent::ModifiersChanged { .. } => None, InputEvent::MouseDown(event) => Some(event.position), InputEvent::MouseUp(event) => Some(event.position), - InputEvent::MouseMoved(event) => Some(event.position), + InputEvent::MouseMove(event) => Some(event.position), InputEvent::MouseExited(event) => Some(event.position), InputEvent::ScrollWheel(event) => Some(event.position), - InputEvent::FileDrop(FileDropEvent::End) => None, + InputEvent::FileDrop(FileDropEvent::Exited) => None, InputEvent::FileDrop( - FileDropEvent::Pending { position } | FileDropEvent::Submit { position, .. }, + FileDropEvent::Entered { position, .. } + | FileDropEvent::Pending { position, .. } + | FileDropEvent::Submit { position, .. }, ) => Some(*position), } } @@ -1085,7 +1090,7 @@ impl InputEvent { InputEvent::ModifiersChanged { .. } => None, InputEvent::MouseDown(event) => Some(event), InputEvent::MouseUp(event) => Some(event), - InputEvent::MouseMoved(event) => Some(event), + InputEvent::MouseMove(event) => Some(event), InputEvent::MouseExited(event) => Some(event), InputEvent::ScrollWheel(event) => Some(event), InputEvent::FileDrop(event) => Some(event), @@ -1099,7 +1104,7 @@ impl InputEvent { InputEvent::ModifiersChanged(event) => Some(event), InputEvent::MouseDown(_) => None, InputEvent::MouseUp(_) => None, - InputEvent::MouseMoved(_) => None, + InputEvent::MouseMove(_) => None, InputEvent::MouseExited(_) => None, InputEvent::ScrollWheel(_) => None, InputEvent::FileDrop(_) => None, diff --git a/crates/gpui2/src/platform/mac/events.rs b/crates/gpui2/src/platform/mac/events.rs index 916b9a18be..b2d68497ef 100644 --- a/crates/gpui2/src/platform/mac/events.rs +++ b/crates/gpui2/src/platform/mac/events.rs @@ -202,7 +202,7 @@ impl InputEvent { }; window_height.map(|window_height| { - Self::MouseMoved(MouseMoveEvent { + Self::MouseMove(MouseMoveEvent { pressed_button: Some(pressed_button), position: point( px(native_event.locationInWindow().x as f32), @@ -213,7 +213,7 @@ impl InputEvent { }) } NSEventType::NSMouseMoved => window_height.map(|window_height| { - Self::MouseMoved(MouseMoveEvent { + Self::MouseMove(MouseMoveEvent { position: point( px(native_event.locationInWindow().x as f32), window_height - px(native_event.locationInWindow().y as f32), diff --git a/crates/gpui2/src/platform/mac/window.rs b/crates/gpui2/src/platform/mac/window.rs index 9cd2bf20ee..195684e2c2 100644 --- a/crates/gpui2/src/platform/mac/window.rs +++ b/crates/gpui2/src/platform/mac/window.rs @@ -1,10 +1,10 @@ use super::{display_bounds_from_native, ns_string, MacDisplay, MetalRenderer, NSRange}; use crate::{ - display_bounds_to_native, point, px, size, AnyWindowHandle, Bounds, Executor, FileDropEvent, - GlobalPixels, InputEvent, KeyDownEvent, Keystroke, Modifiers, ModifiersChangedEvent, - MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, PlatformAtlas, - PlatformDisplay, PlatformInputHandler, PlatformWindow, Point, Scene, Size, Timer, - WindowAppearance, WindowBounds, WindowKind, WindowOptions, WindowPromptLevel, + display_bounds_to_native, point, px, size, AnyWindowHandle, Bounds, DroppedFiles, Executor, + FileDropEvent, GlobalPixels, InputEvent, KeyDownEvent, Keystroke, Modifiers, + ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, + PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point, Scene, Size, + Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions, WindowPromptLevel, }; use block::ConcreteBlock; use cocoa::{ @@ -31,6 +31,7 @@ use objc::{ sel, sel_impl, }; use parking_lot::Mutex; +use smallvec::SmallVec; use std::{ any::Any, cell::{Cell, RefCell}, @@ -1177,7 +1178,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { }; match &event { - InputEvent::MouseMoved( + InputEvent::MouseMove( event @ MouseMoveEvent { pressed_button: Some(_), .. @@ -1194,7 +1195,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { .detach(); } - InputEvent::MouseMoved(_) if !(is_active || lock.kind == WindowKind::PopUp) => return, + InputEvent::MouseMove(_) if !(is_active || lock.kind == WindowKind::PopUp) => return, InputEvent::MouseUp(MouseUpEvent { button: MouseButton::Left, @@ -1633,11 +1634,14 @@ extern "C" fn accepts_first_mouse(this: &Object, _: Sel, _: id) -> BOOL { extern "C" fn dragging_entered(this: &Object, _: Sel, dragging_info: id) -> NSDragOperation { let window_state = unsafe { get_window_state(this) }; - let position = drag_event_position(&window_state, dragging_info); - if send_new_event( - &window_state, - InputEvent::FileDrop(FileDropEvent::Pending { position }), - ) { + if send_new_event(&window_state, { + let position = drag_event_position(&window_state, dragging_info); + let paths = external_paths_from_event(dragging_info); + InputEvent::FileDrop(FileDropEvent::Entered { + position, + files: paths, + }) + }) { NSDragOperationCopy } else { NSDragOperationNone @@ -1659,26 +1663,17 @@ extern "C" fn dragging_updated(this: &Object, _: Sel, dragging_info: id) -> NSDr extern "C" fn dragging_exited(this: &Object, _: Sel, _: id) { let window_state = unsafe { get_window_state(this) }; - send_new_event(&window_state, InputEvent::FileDrop(FileDropEvent::End)); + send_new_event(&window_state, InputEvent::FileDrop(FileDropEvent::Exited)); } extern "C" fn perform_drag_operation(this: &Object, _: Sel, dragging_info: id) -> BOOL { - let mut paths = Vec::new(); - let pb: id = unsafe { msg_send![dragging_info, draggingPasteboard] }; - let filenames = unsafe { NSPasteboard::propertyListForType(pb, NSFilenamesPboardType) }; - for file in unsafe { filenames.iter() } { - let path = unsafe { - let f = NSString::UTF8String(file); - CStr::from_ptr(f).to_string_lossy().into_owned() - }; - paths.push(PathBuf::from(path)) - } + let files = external_paths_from_event(dragging_info); let window_state = unsafe { get_window_state(this) }; let position = drag_event_position(&window_state, dragging_info); if send_new_event( &window_state, - InputEvent::FileDrop(FileDropEvent::Submit { position, paths }), + InputEvent::FileDrop(FileDropEvent::Submit { position }), ) { YES } else { @@ -1686,9 +1681,23 @@ extern "C" fn perform_drag_operation(this: &Object, _: Sel, dragging_info: id) - } } +fn external_paths_from_event(dragging_info: *mut Object) -> DroppedFiles { + let mut paths = SmallVec::new(); + let pasteboard: id = unsafe { msg_send![dragging_info, draggingPasteboard] }; + let filenames = unsafe { NSPasteboard::propertyListForType(pasteboard, NSFilenamesPboardType) }; + for file in unsafe { filenames.iter() } { + let path = unsafe { + let f = NSString::UTF8String(file); + CStr::from_ptr(f).to_string_lossy().into_owned() + }; + paths.push(PathBuf::from(path)) + } + DroppedFiles(paths) +} + extern "C" fn conclude_drag_operation(this: &Object, _: Sel, _: id) { let window_state = unsafe { get_window_state(this) }; - send_new_event(&window_state, InputEvent::FileDrop(FileDropEvent::End)); + send_new_event(&window_state, InputEvent::FileDrop(FileDropEvent::Exited)); } async fn synthetic_drag( @@ -1703,7 +1712,7 @@ async fn synthetic_drag( if lock.synthetic_drag_counter == drag_id { if let Some(mut callback) = lock.event_callback.take() { drop(lock); - callback(InputEvent::MouseMoved(event.clone())); + callback(InputEvent::MouseMove(event.clone())); window_state.lock().event_callback = Some(callback); } } else { diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index e042ec7805..55efe124b0 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -1,13 +1,14 @@ use crate::{ - px, size, Action, AnyBox, AnyView, AppContext, AsyncWindowContext, AvailableSpace, Bounds, - BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect, Element, - EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, GlobalElementId, GlyphId, Handle, - Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, LayoutId, - MainThread, MainThreadOnly, MonochromeSprite, MouseMoveEvent, MouseUpEvent, Path, Pixels, - PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, - RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, - Style, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle, - WindowOptions, SUBPIXEL_VARIANTS, + px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace, + Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, DroppedFiles, + Edges, Effect, Element, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, + GlobalElementId, GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, + KeyMatcher, Keystroke, LayoutId, MainThread, MainThreadOnly, Modifiers, MonochromeSprite, + MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, + PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams, + RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, Subscription, + TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle, WindowOptions, + SUBPIXEL_VARIANTS, }; use anyhow::Result; use collections::HashMap; @@ -816,7 +817,9 @@ impl<'a, 'w> WindowContext<'a, 'w> { cx.with_element_offset(Some(offset), |cx| { let available_space = size(AvailableSpace::MinContent, AvailableSpace::MinContent); - draw_any_view(&mut active_drag.drag_handle_view, available_space, cx); + if let Some(drag_handle_view) = &mut active_drag.drag_handle_view { + draw_any_view(drag_handle_view, available_space, cx); + } cx.active_drag = Some(active_drag); }); }); @@ -889,27 +892,48 @@ impl<'a, 'w> WindowContext<'a, 'w> { } fn dispatch_event(&mut self, event: InputEvent) -> bool { + let event = match event { + InputEvent::MouseMove(mouse_move) => { + self.window.mouse_position = mouse_move.position; + InputEvent::MouseMove(mouse_move) + } + InputEvent::FileDrop(file_drop) => match file_drop { + FileDropEvent::Entered { position, files } => { + self.active_drag.get_or_insert_with(|| AnyDrag { + drag_handle_view: None, + cursor_offset: position, + state: Box::new(files), + state_type: TypeId::of::(), + }); + InputEvent::MouseDown(MouseDownEvent { + position, + button: MouseButton::Left, + click_count: 1, + modifiers: Modifiers::default(), + }) + } + FileDropEvent::Pending { position } => InputEvent::MouseMove(MouseMoveEvent { + position, + pressed_button: Some(MouseButton::Left), + modifiers: Modifiers::default(), + }), + FileDropEvent::Submit { position } => InputEvent::MouseUp(MouseUpEvent { + button: MouseButton::Left, + position, + modifiers: Modifiers::default(), + click_count: 1, + }), + FileDropEvent::Exited => InputEvent::MouseUp(MouseUpEvent { + button: MouseButton::Left, + position: Point::default(), + modifiers: Modifiers::default(), + click_count: 1, + }), + }, + _ => event, + }; + if let Some(any_mouse_event) = event.mouse_event() { - if let Some(MouseMoveEvent { position, .. }) = any_mouse_event.downcast_ref() { - self.window.mouse_position = *position; - } - - match any_mouse_event.downcast_ref() { - Some(FileDropEvent::Pending { position }) => { - dbg!("FileDropEvent::Pending", position); - return true; - } - Some(FileDropEvent::Submit { position, paths }) => { - dbg!("FileDropEvent::Submit", position, paths); - return true; - } - Some(FileDropEvent::End) => { - self.active_drag = None; - return true; - } - _ => {} - } - // Handlers may set this to false by calling `stop_propagation` self.app.propagate_event = true; self.window.default_prevented = false; diff --git a/crates/gpui2_macros/src/style_helpers.rs b/crates/gpui2_macros/src/style_helpers.rs index b1e93cc5b2..9e47d85ef1 100644 --- a/crates/gpui2_macros/src/style_helpers.rs +++ b/crates/gpui2_macros/src/style_helpers.rs @@ -305,7 +305,18 @@ fn box_prefixes() -> Vec<(&'static str, bool, Vec, &'static str)> vec![quote! { padding.right }], "Sets the right padding of the element. [Docs](https://tailwindcss.com/docs/padding#add-padding-to-a-single-side)" ), - ("top", true, vec![quote! { inset.top }], "Sets the top value of a positioned element. [Docs](https://tailwindcss.com/docs/top-right-bottom-left)",), + ( + "inset", + true, + vec![quote! { inset.top }, quote! { inset.right }, quote! { inset.bottom }, quote! { inset.left }], + "Sets the top, right, bottom, and left values of a positioned element. [Docs](https://tailwindcss.com/docs/top-right-bottom-left)", + ), + ( + "top", + true, + vec![quote! { inset.top }], + "Sets the top value of a positioned element. [Docs](https://tailwindcss.com/docs/top-right-bottom-left)", + ), ( "bottom", true, diff --git a/crates/ui2/src/color.rs b/crates/ui2/src/color.rs index 222eaa8aac..14cad34823 100644 --- a/crates/ui2/src/color.rs +++ b/crates/ui2/src/color.rs @@ -159,8 +159,6 @@ pub struct ThemeColor { impl std::fmt::Debug for ThemeColor { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - dbg!("ThemeColor debug"); - f.debug_struct("ThemeColor") .field("transparent", &self.transparent.to_rgb().to_hex()) .field( diff --git a/crates/ui2/src/components/panes.rs b/crates/ui2/src/components/panes.rs index 48d4327cab..d9a7b0a483 100644 --- a/crates/ui2/src/components/panes.rs +++ b/crates/ui2/src/components/panes.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; -use gpui2::{hsla, AnyElement, ElementId, Hsla, Length, Size}; +use gpui2::{hsla, red, AnyElement, DroppedFiles, ElementId, Hsla, Length, Size}; use smallvec::SmallVec; use crate::prelude::*; @@ -50,8 +50,19 @@ impl Pane { .bg(self.fill) .w(self.size.width) .h(self.size.height) - .overflow_y_scroll() - .children(self.children.drain(..)) + .relative() + .children(cx.stack(0, |_| self.children.drain(..))) + .child(cx.stack(1, |_| { + // TODO kb! Figure out why we can't we see the red background when we drag a file over this div. + div() + .id("drag-target") + .drag_over::(|d| d.bg(red())) + .on_drop(|_, files: DroppedFiles, _| { + dbg!("dropped files!", files); + }) + .absolute() + .inset_0() + })) } } diff --git a/crates/ui2/src/components/workspace.rs b/crates/ui2/src/components/workspace.rs index 2ae49fb7c6..ff51220053 100644 --- a/crates/ui2/src/components/workspace.rs +++ b/crates/ui2/src/components/workspace.rs @@ -179,8 +179,6 @@ impl Workspace { let color = ThemeColor::new(cx); - dbg!(color); - // HACK: This should happen inside of `debug_toggle_user_settings`, but // we don't have `cx.global::()` in event handlers at the moment. // Need to talk with Nathan/Antonio about this.