diff --git a/.cargo/config.toml b/.cargo/config.toml deleted file mode 100644 index cf5c88d091..0000000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,7 +0,0 @@ -[target.'cfg(all())'] -rustflags = [ - "-Dwarnings", - "-Aclippy::reversed_empty_ranges", - "-Aclippy::missing_safety_doc", - "-Aclippy::let_unit_value", -] diff --git a/crates/drag_and_drop/src/drag_and_drop.rs b/crates/drag_and_drop/src/drag_and_drop.rs index 9fe239d2b5..1f77664cb4 100644 --- a/crates/drag_and_drop/src/drag_and_drop.rs +++ b/crates/drag_and_drop/src/drag_and_drop.rs @@ -1,4 +1,4 @@ -use std::{any::Any, sync::Arc}; +use std::{any::Any, rc::Rc}; use gpui::{ elements::{Container, MouseEventHandler}, @@ -10,8 +10,8 @@ use gpui::{ struct State { position: Vector2F, region_offset: Vector2F, - payload: Arc, - render: Arc, &mut RenderContext) -> ElementBox>, + payload: Rc, + render: Rc, &mut RenderContext) -> ElementBox>, } impl Clone for State { @@ -46,13 +46,15 @@ impl DragAndDrop { } } - pub fn currently_dragged(&self) -> Option<(Vector2F, &T)> { + pub fn currently_dragged(&self) -> Option<(Vector2F, Rc)> { self.currently_dragged.as_ref().and_then( |State { position, payload, .. }| { payload - .downcast_ref::() + .clone() + .downcast::() + .ok() .map(|payload| (position.clone(), payload)) }, ) @@ -61,9 +63,9 @@ impl DragAndDrop { pub fn dragging( relative_to: Option, position: Vector2F, - payload: Arc, + payload: Rc, cx: &mut EventContext, - render: Arc) -> ElementBox>, + render: Rc) -> ElementBox>, ) { cx.update_global::(|this, cx| { let region_offset = if let Some(previous_state) = this.currently_dragged.as_ref() { @@ -80,7 +82,7 @@ impl DragAndDrop { region_offset, position, payload, - render: Arc::new(move |payload, cx| { + render: Rc::new(move |payload, cx| { render(payload.downcast_ref::().unwrap(), cx) }), }); @@ -143,8 +145,8 @@ impl Draggable for MouseEventHandler { where Self: Sized, { - let payload = Arc::new(payload); - let render = Arc::new(render); + let payload = Rc::new(payload); + let render = Rc::new(render); self.on_drag(MouseButton::Left, move |e, cx| { let payload = payload.clone(); let render = render.clone(); diff --git a/crates/gpui/src/presenter.rs b/crates/gpui/src/presenter.rs index 92665dcaba..f279b470da 100644 --- a/crates/gpui/src/presenter.rs +++ b/crates/gpui/src/presenter.rs @@ -224,6 +224,8 @@ impl Presenter { Event::MouseDown(e @ MouseButtonEvent { position, .. }) => { for (region, _) in self.mouse_regions.iter().rev() { if region.bounds.contains_point(*position) { + self.clicked_region = Some(region.clone()); + self.prev_drag_position = Some(*position); events_to_send.push(( region.clone(), MouseRegionEvent::Down(DownRegionEvent { @@ -277,19 +279,19 @@ impl Presenter { } } Event::MouseMoved(e @ MouseMovedEvent { position, .. }) => { - if let Some((clicked_region, prev_drag_position)) = self - .clicked_region - .as_ref() - .zip(self.prev_drag_position.as_mut()) - { - events_to_send.push(( - clicked_region.clone(), - MouseRegionEvent::Drag(DragRegionEvent { - region: clicked_region.bounds, - prev_drag_position: *prev_drag_position, - platform_event: e.clone(), - }), - )); + if let Some(clicked_region) = self.clicked_region.as_ref() { + if let Some(prev_drag_position) = self.prev_drag_position { + events_to_send.push(( + clicked_region.clone(), + MouseRegionEvent::Drag(DragRegionEvent { + region: clicked_region.bounds, + prev_drag_position, + platform_event: e.clone(), + }), + )); + } + + self.prev_drag_position = Some(*position) } for (region, _) in self.mouse_regions.iter().rev() { @@ -417,8 +419,6 @@ impl Presenter { view_stack: Default::default(), invalidated_views: Default::default(), notify_count: 0, - clicked_region: &mut self.clicked_region, - prev_drag_position: &mut self.prev_drag_position, handled: false, window_id: self.window_id, app: cx, @@ -639,8 +639,6 @@ pub struct EventContext<'a> { pub window_id: usize, pub notify_count: usize, view_stack: Vec, - clicked_region: &'a mut Option, - prev_drag_position: &'a mut Option, handled: bool, invalidated_views: HashSet, } @@ -664,17 +662,6 @@ impl<'a> EventContext<'a> { continue; } - match &event { - MouseRegionEvent::Down(e) => { - *self.clicked_region = Some(region.clone()); - *self.prev_drag_position = Some(e.position); - } - MouseRegionEvent::Drag(e) => { - *self.prev_drag_position = Some(e.position); - } - _ => {} - } - self.invalidated_views.insert(region.view_id); } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index f28f42997c..3b97f084a9 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -3,7 +3,7 @@ use crate::{toolbar::Toolbar, Item, NewFile, NewSearch, NewTerminal, WeakItemHan use anyhow::Result; use collections::{HashMap, HashSet, VecDeque}; use context_menu::{ContextMenu, ContextMenuItem}; -use drag_and_drop::Draggable; +use drag_and_drop::{DragAndDrop, Draggable}; use futures::StreamExt; use gpui::{ actions, @@ -49,6 +49,14 @@ pub struct CloseItem { pub pane: WeakViewHandle, } +#[derive(Clone, PartialEq)] +pub struct MoveItem { + pub item_id: usize, + pub from: WeakViewHandle, + pub to: WeakViewHandle, + pub destination_index: usize, +} + #[derive(Clone, Deserialize, PartialEq)] pub struct GoBack { #[serde(skip_deserializing)] @@ -72,7 +80,7 @@ pub struct DeployNewMenu { } impl_actions!(pane, [GoBack, GoForward, ActivateItem]); -impl_internal_actions!(pane, [CloseItem, DeploySplitMenu, DeployNewMenu]); +impl_internal_actions!(pane, [CloseItem, DeploySplitMenu, DeployNewMenu, MoveItem]); const MAX_NAVIGATION_HISTORY_LEN: usize = 1024; @@ -99,6 +107,47 @@ pub fn init(cx: &mut MutableAppContext) { Ok(()) })) }); + cx.add_action(|workspace: &mut Workspace, action: &MoveItem, cx| { + // Get item handle to move + let from = if let Some(from) = action.from.upgrade(cx) { + from + } else { + return; + }; + + let (item_ix, item_handle) = from + .read(cx) + .items() + .enumerate() + .find(|(_, item_handle)| item_handle.id() == action.item_id) + .expect("Tried to move item handle which was not in from pane"); + + // Add item to new pane at given index + let to = if let Some(to) = action.to.upgrade(cx) { + to + } else { + return; + }; + + // This automatically removes duplicate items in the pane + Pane::add_item_at( + workspace, + to, + item_handle.clone(), + true, + true, + Some(action.destination_index), + cx, + ); + + if action.from != action.to { + // Close item from previous pane + from.update(cx, |from, cx| { + from.remove_item(item_ix, cx); + dbg!(from.items().collect::>()); + }); + } + }); cx.add_action(|pane: &mut Pane, _: &SplitLeft, cx| pane.split(SplitDirection::Left, cx)); cx.add_action(|pane: &mut Pane, _: &SplitUp, cx| pane.split(SplitDirection::Up, cx)); cx.add_action(|pane: &mut Pane, _: &SplitRight, cx| pane.split(SplitDirection::Right, cx)); @@ -408,12 +457,13 @@ impl Pane { } } - pub(crate) fn add_item( + pub fn add_item_at( workspace: &mut Workspace, pane: ViewHandle, item: Box, activate_pane: bool, focus_item: bool, + destination_index: Option, cx: &mut ViewContext, ) { // Prevent adding the same item to the pane more than once. @@ -428,16 +478,20 @@ impl Pane { item.added_to_pane(workspace, pane.clone(), cx); pane.update(cx, |pane, cx| { - // If there is already an active item, then insert the new item - // right after it. Otherwise, adjust the `active_item_index` field - // before activating the new item, so that in the `activate_item` - // method, we can detect that the active item is changing. - let item_ix; - if pane.active_item_index < pane.items.len() { - item_ix = pane.active_item_index + 1 + let item_ix = if let Some(destination_index) = destination_index { + destination_index } else { - item_ix = pane.items.len(); - pane.active_item_index = usize::MAX; + // If there is already an active item, then insert the new item + // right after it. Otherwise, adjust the `active_item_index` field + // before activating the new item, so that in the `activate_item` + // method, we can detect that the active item is changing. + if pane.active_item_index < pane.items.len() { + pane.active_item_index + 1 + } else { + let ix = pane.items.len(); + pane.active_item_index = usize::MAX; + ix + } }; cx.reparent(&item); @@ -447,6 +501,17 @@ impl Pane { }); } + pub(crate) fn add_item( + workspace: &mut Workspace, + pane: ViewHandle, + item: Box, + activate_pane: bool, + focus_item: bool, + cx: &mut ViewContext, + ) { + Self::add_item_at(workspace, pane, item, activate_pane, focus_item, None, cx) + } + pub fn items(&self) -> impl Iterator> { self.items.iter() } @@ -673,48 +738,7 @@ impl Pane { // Remove the item from the pane. pane.update(&mut cx, |pane, cx| { if let Some(item_ix) = pane.items.iter().position(|i| i.id() == item.id()) { - if item_ix == pane.active_item_index { - // Activate the previous item if possible. - // This returns the user to the previously opened tab if they closed - // a ne item they just navigated to. - if item_ix > 0 { - pane.activate_prev_item(cx); - } else if item_ix + 1 < pane.items.len() { - pane.activate_next_item(cx); - } - } - - let item = pane.items.remove(item_ix); - cx.emit(Event::RemoveItem); - if pane.items.is_empty() { - item.deactivated(cx); - pane.update_toolbar(cx); - cx.emit(Event::Remove); - } - - if item_ix < pane.active_item_index { - pane.active_item_index -= 1; - } - - pane.nav_history - .borrow_mut() - .set_mode(NavigationMode::ClosingItem); - item.deactivated(cx); - pane.nav_history - .borrow_mut() - .set_mode(NavigationMode::Normal); - - if let Some(path) = item.project_path(cx) { - pane.nav_history - .borrow_mut() - .paths_by_item - .insert(item.id(), path); - } else { - pane.nav_history - .borrow_mut() - .paths_by_item - .remove(&item.id()); - } + pane.remove_item(item_ix, cx); } }); } @@ -724,6 +748,53 @@ impl Pane { }) } + fn remove_item(&mut self, item_ix: usize, cx: &mut ViewContext) { + if item_ix == self.active_item_index { + // Activate the previous item if possible. + // This returns the user to the previously opened tab if they closed + // a new item they just navigated to. + if item_ix > 0 { + self.activate_prev_item(cx); + } else if item_ix + 1 < self.items.len() { + self.activate_next_item(cx); + } + } + + let item = self.items.remove(item_ix); + cx.emit(Event::RemoveItem); + if self.items.is_empty() { + item.deactivated(cx); + self.update_toolbar(cx); + cx.emit(Event::Remove); + } + + if item_ix < self.active_item_index { + self.active_item_index -= 1; + } + + self.nav_history + .borrow_mut() + .set_mode(NavigationMode::ClosingItem); + item.deactivated(cx); + self.nav_history + .borrow_mut() + .set_mode(NavigationMode::Normal); + + if let Some(path) = item.project_path(cx) { + self.nav_history + .borrow_mut() + .paths_by_item + .insert(item.id(), path); + } else { + self.nav_history + .borrow_mut() + .paths_by_item + .remove(&item.id()); + } + + cx.notify(); + } + pub async fn save_item( project: ModelHandle, pane: &ViewHandle, @@ -880,6 +951,11 @@ impl Pane { fn render_tab_bar(&mut self, cx: &mut RenderContext) -> impl Element { let theme = cx.global::().theme.clone(); + struct DraggedItem { + item: Box, + pane: WeakViewHandle, + } + enum Tabs {} enum Tab {} let pane = cx.handle(); @@ -940,15 +1016,43 @@ impl Pane { }) } }) - .as_draggable(item, { + .on_up(MouseButton::Left, { let pane = pane.clone(); - let detail = detail.clone(); - - move |item, cx: &mut RenderContext| { - let pane = pane.clone(); - Pane::render_tab(item, pane, detail, false, pane_active, tab_active, cx) + move |_, cx: &mut EventContext| { + if let Some((_, dragged_item)) = cx + .global::>() + .currently_dragged::() + { + cx.dispatch_action(MoveItem { + item_id: dragged_item.item.id(), + from: dragged_item.pane.clone(), + to: pane.clone(), + destination_index: ix, + }) + } + cx.propogate_event(); } }) + .as_draggable( + DraggedItem { + item, + pane: pane.clone(), + }, + { + let detail = detail.clone(); + move |dragged_item, cx: &mut RenderContext| { + Pane::render_tab( + &dragged_item.item, + dragged_item.pane.clone(), + detail, + false, + pane_active, + tab_active, + cx, + ) + } + }, + ) .boxed() }) }