.cargo/config.toml 🔗
@@ -1,7 +0,0 @@
-[target.'cfg(all())']
-rustflags = [
- "-Dwarnings",
- "-Aclippy::reversed_empty_ranges",
- "-Aclippy::missing_safety_doc",
- "-Aclippy::let_unit_value",
-]
K Simmons created
.cargo/config.toml | 7
crates/drag_and_drop/src/drag_and_drop.rs | 22 +-
crates/gpui/src/presenter.rs | 43 +---
crates/workspace/src/pane.rs | 224 ++++++++++++++++++------
4 files changed, 191 insertions(+), 105 deletions(-)
@@ -1,7 +0,0 @@
-[target.'cfg(all())']
-rustflags = [
- "-Dwarnings",
- "-Aclippy::reversed_empty_ranges",
- "-Aclippy::missing_safety_doc",
- "-Aclippy::let_unit_value",
-]
@@ -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<V: View> {
position: Vector2F,
region_offset: Vector2F,
- payload: Arc<dyn Any>,
- render: Arc<dyn Fn(Arc<dyn Any>, &mut RenderContext<V>) -> ElementBox>,
+ payload: Rc<dyn Any + 'static>,
+ render: Rc<dyn Fn(Rc<dyn Any>, &mut RenderContext<V>) -> ElementBox>,
}
impl<V: View> Clone for State<V> {
@@ -46,13 +46,15 @@ impl<V: View> DragAndDrop<V> {
}
}
- pub fn currently_dragged<T: Any>(&self) -> Option<(Vector2F, &T)> {
+ pub fn currently_dragged<T: Any>(&self) -> Option<(Vector2F, Rc<T>)> {
self.currently_dragged.as_ref().and_then(
|State {
position, payload, ..
}| {
payload
- .downcast_ref::<T>()
+ .clone()
+ .downcast::<T>()
+ .ok()
.map(|payload| (position.clone(), payload))
},
)
@@ -61,9 +63,9 @@ impl<V: View> DragAndDrop<V> {
pub fn dragging<T: Any>(
relative_to: Option<RectF>,
position: Vector2F,
- payload: Arc<T>,
+ payload: Rc<T>,
cx: &mut EventContext,
- render: Arc<impl 'static + Fn(&T, &mut RenderContext<V>) -> ElementBox>,
+ render: Rc<impl 'static + Fn(&T, &mut RenderContext<V>) -> ElementBox>,
) {
cx.update_global::<Self, _, _>(|this, cx| {
let region_offset = if let Some(previous_state) = this.currently_dragged.as_ref() {
@@ -80,7 +82,7 @@ impl<V: View> DragAndDrop<V> {
region_offset,
position,
payload,
- render: Arc::new(move |payload, cx| {
+ render: Rc::new(move |payload, cx| {
render(payload.downcast_ref::<T>().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();
@@ -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<usize>,
- clicked_region: &'a mut Option<MouseRegion>,
- prev_drag_position: &'a mut Option<Vector2F>,
handled: bool,
invalidated_views: HashSet<usize>,
}
@@ -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);
}
@@ -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<Pane>,
}
+#[derive(Clone, PartialEq)]
+pub struct MoveItem {
+ pub item_id: usize,
+ pub from: WeakViewHandle<Pane>,
+ pub to: WeakViewHandle<Pane>,
+ 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::<Vec<_>>());
+ });
+ }
+ });
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<Pane>,
item: Box<dyn ItemHandle>,
activate_pane: bool,
focus_item: bool,
+ destination_index: Option<usize>,
cx: &mut ViewContext<Workspace>,
) {
// 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<Pane>,
+ item: Box<dyn ItemHandle>,
+ activate_pane: bool,
+ focus_item: bool,
+ cx: &mut ViewContext<Workspace>,
+ ) {
+ Self::add_item_at(workspace, pane, item, activate_pane, focus_item, None, cx)
+ }
+
pub fn items(&self) -> impl Iterator<Item = &Box<dyn ItemHandle>> {
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<Self>) {
+ 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<Project>,
pane: &ViewHandle<Pane>,
@@ -880,6 +951,11 @@ impl Pane {
fn render_tab_bar(&mut self, cx: &mut RenderContext<Self>) -> impl Element {
let theme = cx.global::<Settings>().theme.clone();
+ struct DraggedItem {
+ item: Box<dyn ItemHandle>,
+ pane: WeakViewHandle<Pane>,
+ }
+
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<Workspace>| {
- 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::<DragAndDrop<Workspace>>()
+ .currently_dragged::<DraggedItem>()
+ {
+ 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<Workspace>| {
+ Pane::render_tab(
+ &dragged_item.item,
+ dragged_item.pane.clone(),
+ detail,
+ false,
+ pane_active,
+ tab_active,
+ cx,
+ )
+ }
+ },
+ )
.boxed()
})
}