Detailed changes
@@ -1,6 +1,6 @@
use gpui::{ModelHandle, ViewContext};
use settings::{Settings, WorkingDirectory};
-use workspace::{programs::Dock, Workspace};
+use workspace::{dock::Dock, Workspace};
use crate::{
terminal_container_view::{
@@ -10,55 +10,55 @@ use crate::{
};
pub fn deploy_modal(workspace: &mut Workspace, _: &DeployModal, cx: &mut ViewContext<Workspace>) {
- let window = cx.window_id();
+ // let window = cx.window_id();
- // Pull the terminal connection out of the global if it has been stored
- let possible_terminal = Dock::remove::<Terminal, _>(window, cx);
+ // // Pull the terminal connection out of the global if it has been stored
+ // let possible_terminal = Dock::remove::<Terminal, _>(window, cx);
- if let Some(terminal_handle) = possible_terminal {
- workspace.toggle_modal(cx, |_, cx| {
- // Create a view from the stored connection if the terminal modal is not already shown
- cx.add_view(|cx| TerminalContainer::from_terminal(terminal_handle.clone(), true, cx))
- });
- // Toggle Modal will dismiss the terminal modal if it is currently shown, so we must
- // store the terminal back in the global
- Dock::insert_or_replace::<Terminal, _>(window, terminal_handle, cx);
- } else {
- // No connection was stored, create a new terminal
- if let Some(closed_terminal_handle) = workspace.toggle_modal(cx, |workspace, cx| {
- // No terminal modal visible, construct a new one.
- let wd_strategy = cx
- .global::<Settings>()
- .terminal_overrides
- .working_directory
- .clone()
- .unwrap_or(WorkingDirectory::CurrentProjectDirectory);
+ // if let Some(terminal_handle) = possible_terminal {
+ // workspace.toggle_modal(cx, |_, cx| {
+ // // Create a view from the stored connection if the terminal modal is not already shown
+ // cx.add_view(|cx| TerminalContainer::from_terminal(terminal_handle.clone(), true, cx))
+ // });
+ // // Toggle Modal will dismiss the terminal modal if it is currently shown, so we must
+ // // store the terminal back in the global
+ // Dock::insert_or_replace::<Terminal, _>(window, terminal_handle, cx);
+ // } else {
+ // // No connection was stored, create a new terminal
+ // if let Some(closed_terminal_handle) = workspace.toggle_modal(cx, |workspace, cx| {
+ // // No terminal modal visible, construct a new one.
+ // let wd_strategy = cx
+ // .global::<Settings>()
+ // .terminal_overrides
+ // .working_directory
+ // .clone()
+ // .unwrap_or(WorkingDirectory::CurrentProjectDirectory);
- let working_directory = get_working_directory(workspace, cx, wd_strategy);
+ // let working_directory = get_working_directory(workspace, cx, wd_strategy);
- let this = cx.add_view(|cx| TerminalContainer::new(working_directory, true, cx));
+ // let this = cx.add_view(|cx| TerminalContainer::new(working_directory, true, cx));
- if let TerminalContainerContent::Connected(connected) = &this.read(cx).content {
- let terminal_handle = connected.read(cx).handle();
- cx.subscribe(&terminal_handle, on_event).detach();
- // Set the global immediately if terminal construction was successful,
- // in case the user opens the command palette
- Dock::insert_or_replace::<Terminal, _>(window, terminal_handle, cx);
- }
+ // if let TerminalContainerContent::Connected(connected) = &this.read(cx).content {
+ // let terminal_handle = connected.read(cx).handle();
+ // cx.subscribe(&terminal_handle, on_event).detach();
+ // // Set the global immediately if terminal construction was successful,
+ // // in case the user opens the command palette
+ // Dock::insert_or_replace::<Terminal, _>(window, terminal_handle, cx);
+ // }
- this
- }) {
- // Terminal modal was dismissed and the terminal view is connected, store the terminal
- if let TerminalContainerContent::Connected(connected) =
- &closed_terminal_handle.read(cx).content
- {
- let terminal_handle = connected.read(cx).handle();
- // Set the global immediately if terminal construction was successful,
- // in case the user opens the command palette
- Dock::insert_or_replace::<Terminal, _>(window, terminal_handle, cx);
- }
- }
- }
+ // this
+ // }) {
+ // // Terminal modal was dismissed and the terminal view is connected, store the terminal
+ // if let TerminalContainerContent::Connected(connected) =
+ // &closed_terminal_handle.read(cx).content
+ // {
+ // let terminal_handle = connected.read(cx).handle();
+ // // Set the global immediately if terminal construction was successful,
+ // // in case the user opens the command palette
+ // Dock::insert_or_replace::<Terminal, _>(window, terminal_handle, cx);
+ // }
+ // }
+ // }
}
pub fn on_event(
@@ -68,11 +68,11 @@ pub fn on_event(
cx: &mut ViewContext<Workspace>,
) {
// Dismiss the modal if the terminal quit
- if let Event::CloseTerminal = event {
- Dock::remove::<Terminal, _>(cx.window_id(), cx);
+ // if let Event::CloseTerminal = event {
+ // Dock::remove::<Terminal, _>(cx.window_id(), cx);
- if workspace.modal::<TerminalContainer>().is_some() {
- workspace.dismiss_modal(cx)
- }
- }
+ // if workspace.modal::<TerminalContainer>().is_some() {
+ // workspace.dismiss_modal(cx)
+ // }
+ // }
}
@@ -0,0 +1,35 @@
+use gpui::{elements::ChildView, Element, ElementBox, ViewContext, ViewHandle};
+use theme::Theme;
+
+use crate::{Pane, Workspace};
+
+#[derive(PartialEq, Eq)]
+pub enum DockPosition {
+ Bottom,
+ Right,
+ Fullscreen,
+ Hidden,
+}
+
+pub struct Dock {
+ position: DockPosition,
+ pane: ViewHandle<Pane>,
+}
+
+impl Dock {
+ pub fn new(cx: &mut ViewContext<Workspace>) -> Self {
+ let pane = cx.add_view(Pane::new);
+ Self {
+ pane,
+ position: DockPosition::Bottom,
+ }
+ }
+
+ pub fn render(&self, _theme: &Theme, position: DockPosition) -> Option<ElementBox> {
+ if position == self.position {
+ Some(ChildView::new(self.pane.clone()).boxed())
+ } else {
+ None
+ }
+ }
+}
@@ -1412,6 +1412,10 @@ impl View for Pane {
.on_down(MouseButton::Left, |_, cx| {
cx.focus_parent_view();
})
+ .on_up(MouseButton::Left, {
+ let pane = this.clone();
+ move |_, cx: &mut EventContext| Pane::handle_dropped_item(&pane, 0, cx)
+ })
.boxed()
})
.on_navigate_mouse_down(move |direction, cx| {
@@ -1,75 +0,0 @@
-// TODO: Need to put this basic structure in workspace, and make 'program handles'
-// based off of the 'searchable item' pattern except with models. This way, the workspace's clients
-// can register their models as programs with a specific identity and capable of notifying the workspace
-// Programs are:
-// - Kept alive by the program manager, they need to emit an event to get dropped from it
-// - Can be interacted with directly, (closed, activated, etc.) by the program manager, bypassing
-// associated view(s)
-// - Have special rendering methods that the program manager requires them to implement to fill out
-// the status bar
-// - Can emit events for the program manager which:
-// - Add a jewel (notification, change, etc.)
-// - Drop the program
-// - ???
-// - Program Manager is kept in a global, listens for window drop so it can drop all it's program handles
-
-use collections::HashMap;
-use gpui::{AnyModelHandle, Entity, ModelHandle, View, ViewContext};
-
-/// This struct is going to be the starting point for the 'program manager' feature that will
-/// eventually be implemented to provide a collaborative way of engaging with identity-having
-/// features like the terminal.
-pub struct Dock {
- // TODO: Make this a hashset or something
- modals: HashMap<usize, AnyModelHandle>,
-}
-
-impl Dock {
- pub fn insert_or_replace<T: Entity, V: View>(
- window: usize,
- program: ModelHandle<T>,
- cx: &mut ViewContext<V>,
- ) -> Option<AnyModelHandle> {
- cx.update_global::<Dock, _, _>(|pm, _| pm.insert_or_replace_internal::<T>(window, program))
- }
-
- pub fn remove<T: Entity, V: View>(
- window: usize,
- cx: &mut ViewContext<V>,
- ) -> Option<ModelHandle<T>> {
- cx.update_global::<Dock, _, _>(|pm, _| pm.remove_internal::<T>(window))
- }
-
- pub fn new() -> Self {
- Self {
- modals: Default::default(),
- }
- }
-
- /// Inserts or replaces the model at the given location.
- fn insert_or_replace_internal<T: Entity>(
- &mut self,
- window: usize,
- program: ModelHandle<T>,
- ) -> Option<AnyModelHandle> {
- self.modals.insert(window, AnyModelHandle::from(program))
- }
-
- /// Remove the program associated with this window, if it's of the given type
- fn remove_internal<T: Entity>(&mut self, window: usize) -> Option<ModelHandle<T>> {
- let program = self.modals.remove(&window);
- if let Some(program) = program {
- if program.is::<T>() {
- // Guaranteed to be some, but leave it in the option
- // anyway for the API
- program.downcast()
- } else {
- // Model is of the incorrect type, put it back
- self.modals.insert(window, program);
- None
- }
- } else {
- None
- }
- }
-}
@@ -1,3 +1,4 @@
+pub mod dock;
/// NOTE: Focus only 'takes' after an update has flushed_effects. Pane sends an event in on_focus_in
/// which the workspace uses to change the activated pane.
///
@@ -5,7 +6,6 @@
/// specific locations.
pub mod pane;
pub mod pane_group;
-pub mod programs;
pub mod searchable;
pub mod sidebar;
mod status_bar;
@@ -18,6 +18,7 @@ use client::{
};
use clock::ReplicaId;
use collections::{hash_map, HashMap, HashSet};
+use dock::{Dock, DockPosition};
use drag_and_drop::DragAndDrop;
use futures::{channel::oneshot, FutureExt};
use gpui::{
@@ -37,7 +38,6 @@ use log::error;
pub use pane::*;
pub use pane_group::*;
use postage::prelude::Stream;
-use programs::Dock;
use project::{fs, Fs, Project, ProjectEntryId, ProjectPath, ProjectStore, Worktree, WorktreeId};
use searchable::SearchableItemHandle;
use serde::Deserialize;
@@ -146,9 +146,6 @@ impl_internal_actions!(
impl_actions!(workspace, [ToggleProjectOnline, ActivatePane]);
pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
- // Initialize the program manager immediately
- cx.set_global(Dock::new());
-
pane::init(cx);
cx.add_global_action(open);
@@ -893,6 +890,7 @@ pub struct Workspace {
panes_by_item: HashMap<usize, WeakViewHandle<Pane>>,
active_pane: ViewHandle<Pane>,
status_bar: ViewHandle<StatusBar>,
+ dock: Dock,
notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>,
project: ModelHandle<Project>,
leader_state: LeaderState,
@@ -998,10 +996,13 @@ impl Workspace {
drag_and_drop.register_container(weak_self.clone());
});
+ let dock = Dock::new(cx);
+
let mut this = Workspace {
modal: None,
weak_self,
center: PaneGroup::new(pane.clone()),
+ dock,
panes: vec![pane.clone()],
panes_by_item: Default::default(),
active_pane: pane.clone(),
@@ -2557,14 +2558,36 @@ impl View for Workspace {
},
)
.with_child(
- FlexItem::new(self.center.render(
- &theme,
- &self.follower_states_by_leader,
- self.project.read(cx).collaborators(),
- ))
+ FlexItem::new(
+ Flex::column()
+ .with_child(
+ FlexItem::new(self.center.render(
+ &theme,
+ &self.follower_states_by_leader,
+ self.project.read(cx).collaborators(),
+ ))
+ .flex(1., true)
+ .boxed(),
+ )
+ .with_children(
+ self.dock
+ .render(&theme, DockPosition::Bottom)
+ .map(|dock| {
+ FlexItem::new(dock)
+ .flex(1., true)
+ .boxed()
+ }),
+ )
+ .boxed(),
+ )
.flex(1., true)
.boxed(),
)
+ .with_children(
+ self.dock
+ .render(&theme, DockPosition::Right)
+ .map(|dock| FlexItem::new(dock).flex(1., true).boxed()),
+ )
.with_children(
if self.right_sidebar.read(cx).active_item().is_some() {
Some(
@@ -2578,6 +2601,7 @@ impl View for Workspace {
)
.boxed()
})
+ .with_children(self.dock.render(&theme, DockPosition::Fullscreen))
.with_children(self.modal.as_ref().map(|m| {
ChildView::new(m)
.contained()