diff --git a/crates/drag_and_drop/src/drag_and_drop.rs b/crates/drag_and_drop/src/drag_and_drop.rs index 8fa0e19c6695f9f1ca42224b36a942a496b1883e..7a16acae07d6dd24dd506736c5fa01861fa17dd1 100644 --- a/crates/drag_and_drop/src/drag_and_drop.rs +++ b/crates/drag_and_drop/src/drag_and_drop.rs @@ -2,7 +2,7 @@ use std::{any::Any, rc::Rc}; use collections::HashSet; use gpui::{ - elements::{Container, MouseEventHandler, Overlay}, + elements::{MouseEventHandler, Overlay}, geometry::vector::Vector2F, scene::DragRegionEvent, CursorStyle, Element, ElementBox, EventContext, MouseButton, MutableAppContext, RenderContext, diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 714338474af89492cbbb18dcc169f93991d33fee..73c3b3f478e8988ded07b78489dc41aa48f57b76 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1960,6 +1960,7 @@ impl MutableAppContext { { let mut app = self.upgrade(); let presenter = Rc::downgrade(&presenter); + window.on_event(Box::new(move |event| { app.update(|cx| { if let Some(presenter) = presenter.upgrade() { @@ -4089,9 +4090,10 @@ impl<'a, V: View> RenderContext<'a, V> { } } - pub fn element_state( + pub fn element_state( &mut self, element_id: usize, + initial: T, ) -> ElementStateHandle { let id = ElementStateId { view_id: self.view_id(), @@ -4101,9 +4103,16 @@ impl<'a, V: View> RenderContext<'a, V> { self.cx .element_states .entry(id) - .or_insert_with(|| Box::new(T::default())); + .or_insert_with(|| Box::new(initial)); ElementStateHandle::new(id, self.frame_count, &self.cx.ref_counts) } + + pub fn default_element_state( + &mut self, + element_id: usize, + ) -> ElementStateHandle { + self.element_state::(element_id, T::default()) + } } impl AsRef for &AppContext { @@ -5226,6 +5235,10 @@ impl ElementStateHandle { } } + pub fn id(&self) -> ElementStateId { + self.id + } + pub fn read<'a>(&self, cx: &'a AppContext) -> &'a T { cx.element_states .get(&self.id) diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index b6ab1ec5d02a6bf075f5ee7fed32a6effa3900b3..b22f0b3250d7a94dabaa58bc84fbe22688077d3f 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -12,6 +12,7 @@ mod label; mod list; mod mouse_event_handler; mod overlay; +mod resizable; mod stack; mod svg; mod text; @@ -21,8 +22,8 @@ mod uniform_list; use self::expanded::Expanded; pub use self::{ align::*, canvas::*, constrained_box::*, container::*, empty::*, flex::*, hook::*, image::*, - keystroke_label::*, label::*, list::*, mouse_event_handler::*, overlay::*, stack::*, svg::*, - text::*, tooltip::*, uniform_list::*, + keystroke_label::*, label::*, list::*, mouse_event_handler::*, overlay::*, resizable::*, + stack::*, svg::*, text::*, tooltip::*, uniform_list::*, }; pub use crate::presenter::ChildView; use crate::{ @@ -186,6 +187,27 @@ pub trait Element { { Tooltip::new::(id, text, action, style, self.boxed(), cx) } + + fn with_resize_handle( + self, + element_id: usize, + side: Side, + handle_size: f32, + initial_size: f32, + cx: &mut RenderContext, + ) -> Resizable + where + Self: 'static + Sized, + { + Resizable::new::( + self.boxed(), + element_id, + side, + handle_size, + initial_size, + cx, + ) + } } pub enum Lifecycle { diff --git a/crates/gpui/src/elements/container.rs b/crates/gpui/src/elements/container.rs index 326efdfd19f82205bb5b77356dbbdc1b0647b8ff..dc0d0bac1bda4044a6b9a3157b6734a6115b9876 100644 --- a/crates/gpui/src/elements/container.rs +++ b/crates/gpui/src/elements/container.rs @@ -373,6 +373,24 @@ pub struct Padding { pub right: f32, } +impl Padding { + pub fn horizontal(padding: f32) -> Self { + Self { + left: padding, + right: padding, + ..Default::default() + } + } + + pub fn vertical(padding: f32) -> Self { + Self { + top: padding, + bottom: padding, + ..Default::default() + } + } +} + impl<'de> Deserialize<'de> for Padding { fn deserialize(deserializer: D) -> Result where diff --git a/crates/gpui/src/elements/flex.rs b/crates/gpui/src/elements/flex.rs index 798fb3e8c0106b3d5ec9dc7d2578418721b38c36..e68810fb360527dd2e047d12c98f75632bac6105 100644 --- a/crates/gpui/src/elements/flex.rs +++ b/crates/gpui/src/elements/flex.rs @@ -52,7 +52,7 @@ impl Flex { Tag: 'static, V: View, { - let scroll_state = cx.element_state::(element_id); + let scroll_state = cx.default_element_state::(element_id); scroll_state.update(cx, |scroll_state, _| scroll_state.scroll_to = scroll_to); self.scroll_state = Some(scroll_state); self diff --git a/crates/gpui/src/elements/resizable.rs b/crates/gpui/src/elements/resizable.rs new file mode 100644 index 0000000000000000000000000000000000000000..b4bc5124969674bacf0867453ab274085c41e07b --- /dev/null +++ b/crates/gpui/src/elements/resizable.rs @@ -0,0 +1,238 @@ +use std::{cell::Cell, rc::Rc}; + +use pathfinder_geometry::vector::Vector2F; +use serde_json::json; + +use crate::{ + color::Color, scene::DragRegionEvent, Axis, Border, CursorStyle, Element, ElementBox, + ElementStateHandle, MouseButton, RenderContext, View, MouseRegion, +}; + +use super::{ConstrainedBox, Empty, Flex, Hook, MouseEventHandler, Padding, ParentElement}; + +#[derive(Copy, Clone, Debug)] +pub enum Side { + Top, + Bottom, + Left, + Right, +} + +impl Side { + fn axis(&self) -> Axis { + match self { + Side::Left | Side::Right => Axis::Horizontal, + Side::Top | Side::Bottom => Axis::Vertical, + } + } + + /// 'before' is in reference to the standard english document ordering of left-to-right + /// then top-to-bottom + fn before_content(self) -> bool { + match self { + Side::Left | Side::Top => true, + Side::Right | Side::Bottom => false, + } + } + + fn resize_padding(&self, padding_size: f32) -> Padding { + match self.axis() { + Axis::Horizontal => Padding::horizontal(padding_size), + Axis::Vertical => Padding::vertical(padding_size), + } + } + + fn relevant_component(&self, vector: Vector2F) -> f32 { + match self.axis() { + Axis::Horizontal => vector.x(), + Axis::Vertical => vector.y(), + } + } + + fn compute_delta(&self, e: DragRegionEvent) -> f32 { + if self.before_content() { + self.relevant_component(e.prev_mouse_position) - self.relevant_component(e.position) + } else { + self.relevant_component(e.position) - self.relevant_component(e.prev_mouse_position) + } + } +} + +struct ResizeHandleState { + actual_dimension: Cell, + custom_dimension: Cell, +} + +pub struct Resizable { + side: Side, + child: ElementBox, + state: Rc, + _state_handle: ElementStateHandle>, +} + +impl Resizable { + pub fn new( + child: ElementBox, + element_id: usize, + side: Side, + handle_size: f32, + initial_size: f32, + cx: &mut RenderContext, + ) -> Self { + let state_handle = cx.element_state::>( + element_id, + Rc::new(ResizeHandleState { + actual_dimension: Cell::new(initial_size), + custom_dimension: Cell::new(initial_size), + }), + ); + + let state = state_handle.read(cx).clone(); + + let mut flex = Flex::new(side.axis()); + + if side.before_content() { + dbg!("HANDLE BEING RENDERED BEFORE"); + flex.add_child(render_resize_handle(state.clone(), side, handle_size, cx)) + } + + flex.add_child( + Hook::new({ + let constrained = ConstrainedBox::new(child); + match side.axis() { + Axis::Horizontal => constrained.with_max_width(state.custom_dimension.get()), + Axis::Vertical => constrained.with_max_height(state.custom_dimension.get()), + } + .boxed() + }) + .on_after_layout({ + let state = state.clone(); + move |size, _| { + state.actual_dimension.set(side.relevant_component(size)); + } + }) + .boxed(), + ); + + if !side.before_content() { + dbg!("HANDLE BEING RENDERED AFTER"); + flex.add_child(render_resize_handle(state.clone(), side, handle_size, cx)) + } + + let child = flex.boxed(); + + Self { + side, + child, + state, + _state_handle: state_handle, + } + } +} + +fn render_resize_handle( + state: Rc, + side: Side, + padding_size: f32, + cx: &mut RenderContext, +) -> ElementBox { + enum ResizeHandle {} + MouseEventHandler::::new(side as usize, cx, |_, _| { + Empty::new() + // Border necessary to properly add a MouseRegion + .contained() + .with_border(Border { + width: 4., + left: true, + color: Color::red(), + ..Default::default() + }) + .boxed() + }) + .with_padding(side.resize_padding(padding_size)) + .with_cursor_style(match side.axis() { + Axis::Horizontal => CursorStyle::ResizeLeftRight, + Axis::Vertical => CursorStyle::ResizeUpDown, + }) + .on_down(MouseButton::Left, |_, _| {}) // This prevents the mouse down event from being propagated elsewhere + .on_drag(MouseButton::Left, move |e, cx| { + let prev_width = state.actual_dimension.get(); + state + .custom_dimension + .set(0f32.max(prev_width + side.compute_delta(e)).round()); + cx.notify(); + }) + .boxed() +} + +impl Element for Resizable { + type LayoutState = Vector2F; + type PaintState = (); + + fn layout( + &mut self, + constraint: crate::SizeConstraint, + cx: &mut crate::LayoutContext, + ) -> (Vector2F, Self::LayoutState) { + let child_size = self.child.layout(constraint, cx); + (child_size, child_size) + } + + fn paint( + &mut self, + bounds: pathfinder_geometry::rect::RectF, + visible_bounds: pathfinder_geometry::rect::RectF, + child_size: &mut Self::LayoutState, + cx: &mut crate::PaintContext, + ) -> Self::PaintState { + cx.scene.push_stacking_context(None); + + // Render a mouse region on the appropriate border (likely just bounds) + // Use the padding in the above code to decide the size of the rect to pass to the mouse region + // Add handlers for Down and Drag like above + + // Maybe try pushing a quad to visually inspect where the region gets placed + // Push a cursor region + cx.scene.push_mouse_region(MouseRegion::) + + cx.scene.pop_stacking_context(); + + self.child.paint(bounds.origin(), visible_bounds, cx); + } + + fn dispatch_event( + &mut self, + event: &crate::Event, + _bounds: pathfinder_geometry::rect::RectF, + _visible_bounds: pathfinder_geometry::rect::RectF, + _layout: &mut Self::LayoutState, + _paint: &mut Self::PaintState, + cx: &mut crate::EventContext, + ) -> bool { + self.child.dispatch_event(event, cx) + } + + fn rect_for_text_range( + &self, + range_utf16: std::ops::Range, + _bounds: pathfinder_geometry::rect::RectF, + _visible_bounds: pathfinder_geometry::rect::RectF, + _layout: &Self::LayoutState, + _paint: &Self::PaintState, + cx: &crate::MeasurementContext, + ) -> Option { + self.child.rect_for_text_range(range_utf16, cx) + } + + fn debug( + &self, + _bounds: pathfinder_geometry::rect::RectF, + _layout: &Self::LayoutState, + _paint: &Self::PaintState, + cx: &crate::DebugContext, + ) -> serde_json::Value { + json!({ + "child": self.child.debug(cx), + }) + } +} diff --git a/crates/gpui/src/elements/tooltip.rs b/crates/gpui/src/elements/tooltip.rs index 37ebced44ac0bfa59b87688f55df9c164c0f3dd7..55ab7e44d25e0fb8edfdcdb210a6630ce62bbad6 100644 --- a/crates/gpui/src/elements/tooltip.rs +++ b/crates/gpui/src/elements/tooltip.rs @@ -62,7 +62,7 @@ impl Tooltip { struct ElementState(Tag); struct MouseEventHandlerState(Tag); - let state_handle = cx.element_state::, Rc>(id); + let state_handle = cx.default_element_state::, Rc>(id); let state = state_handle.read(cx).clone(); let tooltip = if state.visible.get() { let mut collapsed_tooltip = Self::render_tooltip( diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 38e8348ac30e3c0fff472eb8df1009f8ec1ce67a..61cd025db5aea022fe65605ae3ac5342c690faa4 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -163,6 +163,7 @@ pub enum PromptLevel { pub enum CursorStyle { Arrow, ResizeLeftRight, + ResizeUpDown, PointingHand, IBeam, } diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index 113653478a8a235e47ab597229360dc5952b60cc..58b1517cbca55eec432f7432be97c2e615b329c6 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -681,6 +681,7 @@ impl platform::Platform for MacPlatform { let cursor: id = match style { CursorStyle::Arrow => msg_send![class!(NSCursor), arrowCursor], CursorStyle::ResizeLeftRight => msg_send![class!(NSCursor), resizeLeftRightCursor], + CursorStyle::ResizeUpDown => msg_send![class!(NSCursor), resizeUpDownCursor], CursorStyle::PointingHand => msg_send![class!(NSCursor), pointingHandCursor], CursorStyle::IBeam => msg_send![class!(NSCursor), IBeamCursor], }; diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 70e73ef33d8d2cf70955f3a298cd2bc82c8f3867..4ba9617be91e2d3d4dd43cec76dc31757634ebfe 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -1,6 +1,6 @@ use gpui::{ actions, - elements::{ChildView, Container, FlexItem, Margin, MouseEventHandler, Svg}, + elements::{ChildView, Container, Empty, FlexItem, Margin, MouseEventHandler, Side, Svg}, impl_internal_actions, CursorStyle, Element, ElementBox, Entity, MouseButton, MutableAppContext, RenderContext, View, ViewContext, ViewHandle, WeakViewHandle, }; @@ -36,7 +36,22 @@ impl Default for DockPosition { } } +pub fn icon_for_dock_anchor(anchor: DockAnchor) -> &'static str { + match anchor { + DockAnchor::Right => "icons/dock_right_12.svg", + DockAnchor::Bottom => "icons/dock_bottom_12.svg", + DockAnchor::Expanded => "icons/dock_modal_12.svg", + } +} + impl DockPosition { + fn is_visible(&self) -> bool { + match self { + DockPosition::Shown(_) => true, + DockPosition::Hidden(_) => false, + } + } + fn anchor(&self) -> DockAnchor { match self { DockPosition::Shown(anchor) | DockPosition::Hidden(anchor) => *anchor, @@ -50,13 +65,6 @@ impl DockPosition { } } - fn visible(&self) -> Option { - match self { - DockPosition::Shown(anchor) => Some(*anchor), - DockPosition::Hidden(_) => None, - } - } - fn hide(self) -> Self { match self { DockPosition::Shown(anchor) => DockPosition::Hidden(anchor), @@ -96,7 +104,7 @@ impl Dock { } pub fn visible_pane(&self) -> Option<&ViewHandle> { - self.position.visible().map(|_| self.pane()) + self.position.is_visible().then(|| self.pane()) } fn set_dock_position( @@ -124,6 +132,7 @@ impl Dock { cx.focus(last_active_center_pane); } } + cx.emit(crate::Event::DockAnchorChanged); cx.notify(); } @@ -152,29 +161,32 @@ impl Dock { let style = &theme.workspace.dock; self.position - .visible() + .is_visible() + .then(|| self.position.anchor()) .filter(|current_anchor| *current_anchor == anchor) .map(|anchor| match anchor { DockAnchor::Bottom | DockAnchor::Right => { let mut panel_style = style.panel.clone(); - if anchor == DockAnchor::Bottom { + let resize_side = if anchor == DockAnchor::Bottom { panel_style.margin = Margin { top: panel_style.margin.top, ..Default::default() }; + Side::Top } else { panel_style.margin = Margin { left: panel_style.margin.left, ..Default::default() }; - } - FlexItem::new( - Container::new(ChildView::new(self.pane.clone()).boxed()) - .with_style(style.panel) - .boxed(), - ) - .flex(style.flex, true) - .boxed() + Side::Left + }; + + enum DockResizeHandle {} + Container::new(ChildView::new(self.pane.clone()).boxed()) + .with_style(style.panel) + .with_resize_handle::(0, resize_side, 4., 200., cx) + .flex(style.flex, false) + .boxed() } DockAnchor::Expanded => Container::new( MouseEventHandler::::new(0, cx, |_state, _cx| { @@ -197,8 +209,13 @@ pub struct ToggleDockButton { } impl ToggleDockButton { - pub fn new(workspace: WeakViewHandle, _cx: &mut ViewContext) -> Self { - Self { workspace } + pub fn new(workspace: ViewHandle, cx: &mut ViewContext) -> Self { + // When dock moves, redraw so that the icon and toggle status matches. + cx.subscribe(&workspace, |_, _, _, cx| cx.notify()).detach(); + + Self { + workspace: workspace.downgrade(), + } } } @@ -212,35 +229,46 @@ impl View for ToggleDockButton { } fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox { - let dock_is_open = self - .workspace - .upgrade(cx) - .map(|workspace| workspace.read(cx).dock.position.visible().is_some()) - .unwrap_or(false); - - MouseEventHandler::::new(0, cx, |state, cx| { - let theme = &cx - .global::() - .theme - .workspace - .status_bar - .sidebar_buttons; - let style = theme.item.style_for(state, dock_is_open); - - Svg::new("icons/terminal_16.svg") - .with_color(style.icon_color) - .constrained() - .with_width(style.icon_size) - .with_height(style.icon_size) - .contained() - .with_style(style.container) - .boxed() + let workspace = self.workspace.upgrade(cx); + + if workspace.is_none() { + return Empty::new().boxed(); + } + + let dock_position = workspace.unwrap().read(cx).dock.position; + + let theme = cx.global::().theme.clone(); + MouseEventHandler::::new(0, cx, { + let theme = theme.clone(); + move |state, _| { + let style = theme + .workspace + .status_bar + .sidebar_buttons + .item + .style_for(state, dock_position.is_visible()); + + Svg::new(icon_for_dock_anchor(dock_position.anchor())) + .with_color(style.icon_color) + .constrained() + .with_width(style.icon_size) + .with_height(style.icon_size) + .contained() + .with_style(style.container) + .boxed() + } }) .with_cursor_style(CursorStyle::PointingHand) .on_click(MouseButton::Left, |_, cx| { cx.dispatch_action(ToggleDock); }) - // TODO: Add tooltip + .with_tooltip::( + 0, + "Toggle Dock".to_string(), + Some(Box::new(ToggleDock)), + theme.tooltip.clone(), + cx, + ) .boxed() } } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 6a37d01f0fec5e12f436c9d706afe3f3717b81ae..97cdfaca7d4cc410712eb811dfe494d1155cafc6 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1,6 +1,6 @@ use super::{ItemHandle, SplitDirection}; use crate::{ - dock::{MoveDock, ToggleDock}, + dock::{icon_for_dock_anchor, MoveDock, ToggleDock}, toolbar::Toolbar, Item, NewFile, NewSearch, NewTerminal, WeakItemHandle, Workspace, }; @@ -1385,17 +1385,8 @@ impl View for Pane { self.docked .map(|anchor| { // Add the dock menu button if this pane is a dock - let dock_icon = match anchor { - DockAnchor::Right => { - "icons/dock_right_12.svg" - } - DockAnchor::Bottom => { - "icons/dock_bottom_12.svg" - } - DockAnchor::Expanded => { - "icons/dock_modal_12.svg" - } - }; + let dock_icon = + icon_for_dock_anchor(anchor); tab_bar_button( 2, diff --git a/crates/workspace/src/sidebar.rs b/crates/workspace/src/sidebar.rs index ee2102972f003b2636f421962fd9d37f9ee3d754..89a750964304dd42f9686ac56087cf8fbb5be520 100644 --- a/crates/workspace/src/sidebar.rs +++ b/crates/workspace/src/sidebar.rs @@ -5,8 +5,7 @@ use gpui::{ }; use serde::Deserialize; use settings::Settings; -use std::{cell::RefCell, rc::Rc}; -use theme::Theme; +use std::rc::Rc; pub trait SidebarItem: View { fn should_activate_item_on_event(&self, _: &Self::Event, _: &AppContext) -> bool { @@ -53,20 +52,27 @@ impl From<&dyn SidebarItemHandle> for AnyViewHandle { } pub struct Sidebar { - side: Side, + sidebar_side: SidebarSide, items: Vec, is_open: bool, active_item_ix: usize, - actual_width: Rc>, - custom_width: Rc>, } #[derive(Clone, Copy, Debug, Deserialize, PartialEq)] -pub enum Side { +pub enum SidebarSide { Left, Right, } +impl SidebarSide { + fn to_resizable_side(self) -> Side { + match self { + Self::Left => Side::Right, + Self::Right => Side::Left, + } + } +} + struct Item { icon_path: &'static str, tooltip: String, @@ -80,21 +86,19 @@ pub struct SidebarButtons { #[derive(Clone, Debug, Deserialize, PartialEq)] pub struct ToggleSidebarItem { - pub side: Side, + pub sidebar_side: SidebarSide, pub item_index: usize, } impl_actions!(workspace, [ToggleSidebarItem]); impl Sidebar { - pub fn new(side: Side) -> Self { + pub fn new(sidebar_side: SidebarSide) -> Self { Self { - side, + sidebar_side, items: Default::default(), active_item_ix: 0, is_open: false, - actual_width: Rc::new(RefCell::new(260.)), - custom_width: Rc::new(RefCell::new(260.)), } } @@ -171,38 +175,6 @@ impl Sidebar { None } } - - fn render_resize_handle(&self, theme: &Theme, cx: &mut RenderContext) -> ElementBox { - let actual_width = self.actual_width.clone(); - let custom_width = self.custom_width.clone(); - let side = self.side; - MouseEventHandler::::new(side as usize, cx, |_, _| { - Empty::new() - .contained() - .with_style(theme.workspace.sidebar_resize_handle) - .boxed() - }) - .with_padding(Padding { - left: 4., - right: 4., - ..Default::default() - }) - .with_cursor_style(CursorStyle::ResizeLeftRight) - .on_down(MouseButton::Left, |_, _| {}) // This prevents the mouse down event from being propagated elsewhere - .on_drag(MouseButton::Left, move |e, cx| { - let delta = e.position.x() - e.prev_mouse_position.x(); - let prev_width = *actual_width.borrow(); - *custom_width.borrow_mut() = 0f32 - .max(match side { - Side::Left => prev_width + delta, - Side::Right => prev_width - delta, - }) - .round(); - - cx.notify(); - }) - .boxed() - } } impl Entity for Sidebar { @@ -215,31 +187,18 @@ impl View for Sidebar { } fn render(&mut self, cx: &mut RenderContext) -> ElementBox { - let theme = cx.global::().theme.clone(); if let Some(active_item) = self.active_item() { - let mut container = Flex::row(); - if matches!(self.side, Side::Right) { - container.add_child(self.render_resize_handle(&theme, cx)); - } - - container.add_child( - Hook::new( - ChildView::new(active_item.to_any()) - .constrained() - .with_max_width(*self.custom_width.borrow()) - .boxed(), + enum ResizeHandleTag {} + ChildView::new(active_item.to_any()) + .with_resize_handle::( + self.sidebar_side as usize, + self.sidebar_side.to_resizable_side(), + // TODO: Expose both of these constants in the theme + 4., + 260., + cx, ) - .on_after_layout({ - let actual_width = self.actual_width.clone(); - move |size, _| *actual_width.borrow_mut() = size.x() - }) - .flex(1., false) - .boxed(), - ); - if matches!(self.side, Side::Left) { - container.add_child(self.render_resize_handle(&theme, cx)); - } - container.boxed() + .boxed() } else { Empty::new().boxed() } @@ -271,10 +230,10 @@ impl View for SidebarButtons { let badge_style = theme.badge; let active_ix = sidebar.active_item_ix; let is_open = sidebar.is_open; - let side = sidebar.side; - let group_style = match side { - Side::Left => theme.group_left, - Side::Right => theme.group_right, + let sidebar_side = sidebar.sidebar_side; + let group_style = match sidebar_side { + SidebarSide::Left => theme.group_left, + SidebarSide::Right => theme.group_right, }; #[allow(clippy::needless_collect)] @@ -288,7 +247,7 @@ impl View for SidebarButtons { .with_children(items.into_iter().enumerate().map( |(ix, (icon_path, tooltip, item_view))| { let action = ToggleSidebarItem { - side, + sidebar_side, item_index: ix, }; MouseEventHandler::::new(ix, cx, move |state, cx| { diff --git a/crates/workspace/src/waiting_room.rs b/crates/workspace/src/waiting_room.rs index 8102bb7bb23fb684249f873c165d4a127568a2e9..bdced26c8b137a288be97621b22d2281714579f2 100644 --- a/crates/workspace/src/waiting_room.rs +++ b/crates/workspace/src/waiting_room.rs @@ -1,4 +1,4 @@ -use crate::{sidebar::Side, AppState, ToggleFollow, Workspace}; +use crate::{sidebar::SidebarSide, AppState, ToggleFollow, Workspace}; use anyhow::Result; use client::{proto, Client, Contact}; use gpui::{ @@ -101,7 +101,7 @@ impl WaitingRoom { &app_state, cx, ); - workspace.toggle_sidebar(Side::Left, cx); + workspace.toggle_sidebar(SidebarSide::Left, cx); if let Some((host_peer_id, _)) = workspace .project .read(cx) diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 636449ee368451e18a88dfb6ff272357de29f638..ec48b29f899e740c06a34ff77bf4ccfa6cf8c98d 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -42,7 +42,7 @@ use project::{fs, Fs, Project, ProjectEntryId, ProjectPath, ProjectStore, Worktr use searchable::SearchableItemHandle; use serde::Deserialize; use settings::{Autosave, DockAnchor, Settings}; -use sidebar::{Side, Sidebar, SidebarButtons, ToggleSidebarItem}; +use sidebar::{Sidebar, SidebarButtons, SidebarSide, ToggleSidebarItem}; use smallvec::SmallVec; use status_bar::StatusBar; pub use status_bar::StatusItemView; @@ -215,10 +215,10 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { workspace.activate_next_pane(cx) }); cx.add_action(|workspace: &mut Workspace, _: &ToggleLeftSidebar, cx| { - workspace.toggle_sidebar(Side::Left, cx); + workspace.toggle_sidebar(SidebarSide::Left, cx); }); cx.add_action(|workspace: &mut Workspace, _: &ToggleRightSidebar, cx| { - workspace.toggle_sidebar(Side::Right, cx); + workspace.toggle_sidebar(SidebarSide::Right, cx); }); cx.add_action(Workspace::activate_pane_at_index); @@ -875,6 +875,7 @@ impl AppState { } pub enum Event { + DockAnchorChanged, PaneAdded(ViewHandle), ContactRequestedJoin(u64), } @@ -984,16 +985,18 @@ impl Workspace { } }); - let weak_self = cx.weak_handle(); - cx.emit_global(WorkspaceCreated(weak_self.clone())); + let handle = cx.handle(); + let weak_handle = cx.weak_handle(); + + cx.emit_global(WorkspaceCreated(weak_handle.clone())); let dock = Dock::new(cx, dock_default_factory); let dock_pane = dock.pane().clone(); - let left_sidebar = cx.add_view(|_| Sidebar::new(Side::Left)); - let right_sidebar = cx.add_view(|_| Sidebar::new(Side::Right)); + let left_sidebar = cx.add_view(|_| Sidebar::new(SidebarSide::Left)); + let right_sidebar = cx.add_view(|_| Sidebar::new(SidebarSide::Right)); let left_sidebar_buttons = cx.add_view(|cx| SidebarButtons::new(left_sidebar.clone(), cx)); - let toggle_dock = cx.add_view(|cx| ToggleDockButton::new(weak_self.clone(), cx)); + let toggle_dock = cx.add_view(|cx| ToggleDockButton::new(handle, cx)); let right_sidebar_buttons = cx.add_view(|cx| SidebarButtons::new(right_sidebar.clone(), cx)); let status_bar = cx.add_view(|cx| { @@ -1005,12 +1008,12 @@ impl Workspace { }); cx.update_default_global::, _, _>(|drag_and_drop, _| { - drag_and_drop.register_container(weak_self.clone()); + drag_and_drop.register_container(weak_handle.clone()); }); let mut this = Workspace { modal: None, - weak_self, + weak_self: weak_handle, center: PaneGroup::new(center_pane.clone()), dock, panes: vec![center_pane.clone(), dock_pane], @@ -1472,10 +1475,11 @@ impl Workspace { } } - pub fn toggle_sidebar(&mut self, side: Side, cx: &mut ViewContext) { - let sidebar = match side { - Side::Left => &mut self.left_sidebar, - Side::Right => &mut self.right_sidebar, + pub fn toggle_sidebar(&mut self, sidebar_side: SidebarSide, cx: &mut ViewContext) { + let sidebar = match sidebar_side { + SidebarSide::Left => &mut self.left_sidebar, + SidebarSide::Right => &mut self.right_sidebar, + // Side::Top | Side::Bottom => unreachable!(), }; sidebar.update(cx, |sidebar, cx| { sidebar.set_open(!sidebar.is_open(), cx); @@ -1485,9 +1489,9 @@ impl Workspace { } pub fn toggle_sidebar_item(&mut self, action: &ToggleSidebarItem, cx: &mut ViewContext) { - let sidebar = match action.side { - Side::Left => &mut self.left_sidebar, - Side::Right => &mut self.right_sidebar, + let sidebar = match action.sidebar_side { + SidebarSide::Left => &mut self.left_sidebar, + SidebarSide::Right => &mut self.right_sidebar, }; let active_item = sidebar.update(cx, |sidebar, cx| { if sidebar.is_open() && sidebar.active_item_ix() == action.item_index { @@ -1513,13 +1517,13 @@ impl Workspace { pub fn toggle_sidebar_item_focus( &mut self, - side: Side, + sidebar_side: SidebarSide, item_index: usize, cx: &mut ViewContext, ) { - let sidebar = match side { - Side::Left => &mut self.left_sidebar, - Side::Right => &mut self.right_sidebar, + let sidebar = match sidebar_side { + SidebarSide::Left => &mut self.left_sidebar, + SidebarSide::Right => &mut self.right_sidebar, }; let active_item = sidebar.update(cx, |sidebar, cx| { sidebar.set_open(true, cx); @@ -2840,7 +2844,7 @@ pub fn open_paths( let mut workspace = Workspace::new(project, app_state.default_item_factory, cx); (app_state.initialize_workspace)(&mut workspace, &app_state, cx); if contains_directory { - workspace.toggle_sidebar(Side::Left, cx); + workspace.toggle_sidebar(SidebarSide::Left, cx); } workspace }) diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 73e87b0fce95f1f7d5ba18f7ce1856c03c026c17..883225e4dbafb713c320ce31e2b1232cde42a6d5 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -33,7 +33,7 @@ use settings::{keymap_file_json_schema, settings_file_json_schema, Settings}; use std::{env, path::Path, str, sync::Arc}; use util::ResultExt; pub use workspace; -use workspace::{sidebar::Side, AppState, Workspace}; +use workspace::{sidebar::SidebarSide, AppState, Workspace}; #[derive(Deserialize, Clone, PartialEq)] struct OpenBrowser { @@ -204,14 +204,14 @@ pub fn init(app_state: &Arc, cx: &mut gpui::MutableAppContext) { |workspace: &mut Workspace, _: &project_panel::ToggleFocus, cx: &mut ViewContext| { - workspace.toggle_sidebar_item_focus(Side::Left, 0, cx); + workspace.toggle_sidebar_item_focus(SidebarSide::Left, 0, cx); }, ); cx.add_action( |workspace: &mut Workspace, _: &contacts_panel::ToggleFocus, cx: &mut ViewContext| { - workspace.toggle_sidebar_item_focus(Side::Right, 0, cx); + workspace.toggle_sidebar_item_focus(SidebarSide::Right, 0, cx); }, );