Detailed changes
@@ -8,7 +8,7 @@ use crate::{
ElementStateHandle, MouseButton, MouseRegion, RenderContext, View,
};
-use super::{ConstrainedBox, Flex, Hook, ParentElement};
+use super::{ConstrainedBox, Hook};
#[derive(Copy, Clone, Debug)]
pub enum Side {
@@ -53,8 +53,12 @@ impl Side {
fn of_rect(&self, bounds: RectF, handle_size: f32) -> RectF {
match self {
Side::Top => RectF::new(bounds.origin(), vec2f(bounds.width(), handle_size)),
- Side::Bottom => RectF::new(bounds.lower_left(), vec2f(bounds.width(), handle_size)),
Side::Left => RectF::new(bounds.origin(), vec2f(handle_size, bounds.height())),
+ Side::Bottom => {
+ let mut origin = bounds.lower_left();
+ origin.set_y(origin.y() - handle_size);
+ RectF::new(origin, vec2f(bounds.width(), handle_size))
+ }
Side::Right => {
let mut origin = bounds.upper_right();
origin.set_x(origin.x() - handle_size);
@@ -96,27 +100,21 @@ impl Resizable {
let state = state_handle.read(cx).clone();
- let mut flex = Flex::new(side.axis());
-
- 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(),
- );
-
- let child = flex.boxed();
+ let 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();
Self {
side,
@@ -126,10 +124,14 @@ impl Resizable {
_state_handle: state_handle,
}
}
+
+ pub fn current_size(&self) -> f32 {
+ self.state.actual_dimension.get()
+ }
}
impl Element for Resizable {
- type LayoutState = Vector2F;
+ type LayoutState = ();
type PaintState = ();
fn layout(
@@ -137,8 +139,7 @@ impl Element for Resizable {
constraint: crate::SizeConstraint,
cx: &mut crate::LayoutContext,
) -> (Vector2F, Self::LayoutState) {
- let child_size = self.child.layout(constraint, cx);
- (child_size, child_size)
+ (self.child.layout(constraint, cx), ())
}
fn paint(
@@ -151,7 +151,7 @@ pub enum WorkingDirectory {
Always { directory: String },
}
-#[derive(PartialEq, Eq, Debug, Default, Copy, Clone, Deserialize, JsonSchema)]
+#[derive(PartialEq, Eq, Debug, Default, Copy, Clone, Hash, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum DockAnchor {
#[default]
@@ -48,7 +48,7 @@ pub struct Workspace {
pub pane_divider: Border,
pub leader_border_opacity: f32,
pub leader_border_width: f32,
- pub sidebar_resize_handle: ContainerStyle,
+ pub sidebar: Sidebar,
pub status_bar: StatusBar,
pub toolbar: Toolbar,
pub disconnected_overlay: ContainedText,
@@ -152,6 +152,8 @@ pub struct Toolbar {
#[derive(Clone, Deserialize, Default)]
pub struct Dock {
+ pub initial_size_right: f32,
+ pub initial_size_bottom: f32,
pub wash_color: Color,
pub flex: f32,
pub panel: ContainerStyle,
@@ -240,7 +242,9 @@ pub struct StatusBarLspStatus {
#[derive(Deserialize, Default)]
pub struct Sidebar {
- pub resize_handle: ContainerStyle,
+ pub initial_size: f32,
+ #[serde(flatten)]
+ pub container: ContainerStyle,
}
#[derive(Clone, Copy, Deserialize, Default)]
@@ -1,3 +1,4 @@
+use collections::HashMap;
use gpui::{
actions,
elements::{ChildView, Container, Empty, Margin, MouseEventHandler, Side, Svg},
@@ -8,7 +9,7 @@ use serde::Deserialize;
use settings::{DockAnchor, Settings};
use theme::Theme;
-use crate::{ItemHandle, Pane, StatusItemView, Workspace};
+use crate::{sidebar::SidebarSide, ItemHandle, Pane, StatusItemView, Workspace};
#[derive(PartialEq, Clone, Deserialize)]
pub struct MoveDock(pub DockAnchor);
@@ -78,6 +79,7 @@ pub type DefaultItemFactory =
pub struct Dock {
position: DockPosition,
+ panel_sizes: HashMap<DockAnchor, f32>,
pane: ViewHandle<Pane>,
default_item_factory: DefaultItemFactory,
}
@@ -94,6 +96,7 @@ impl Dock {
Self {
pane,
+ panel_sizes: Default::default(),
position: DockPosition::Hidden(anchor),
default_item_factory,
}
@@ -107,6 +110,10 @@ impl Dock {
self.position.is_visible().then(|| self.pane())
}
+ pub fn is_anchored_at(&self, anchor: DockAnchor) -> bool {
+ self.position.is_visible() && self.position.anchor() == anchor
+ }
+
fn set_dock_position(
workspace: &mut Workspace,
new_position: DockPosition,
@@ -118,8 +125,14 @@ impl Dock {
pane.set_docked(Some(new_position.anchor()), cx)
});
- let now_visible = workspace.dock.visible_pane().is_some();
- if now_visible {
+ if workspace.dock.position.is_visible() {
+ // Close the right sidebar if the dock is on the right side and the right sidebar is open
+ if workspace.dock.position.anchor() == DockAnchor::Right {
+ if workspace.right_sidebar().read(cx).is_open() {
+ workspace.toggle_sidebar(SidebarSide::Right, cx);
+ }
+ }
+
// Ensure that the pane has at least one item or construct a default item to put in it
let pane = workspace.dock.pane.clone();
if pane.read(cx).items().next().is_none() {
@@ -127,10 +140,8 @@ impl Dock {
Pane::add_item(workspace, &pane, item_to_add, true, true, None, cx);
}
cx.focus(pane);
- } else {
- if let Some(last_active_center_pane) = workspace.last_active_center_pane.clone() {
- cx.focus(last_active_center_pane);
- }
+ } else if let Some(last_active_center_pane) = workspace.last_active_center_pane.clone() {
+ cx.focus(last_active_center_pane);
}
cx.emit(crate::Event::DockAnchorChanged);
cx.notify();
@@ -182,11 +193,28 @@ impl Dock {
};
enum DockResizeHandle {}
- Container::new(ChildView::new(self.pane.clone()).boxed())
- .with_style(style.panel)
- .with_resize_handle::<DockResizeHandle, _>(0, resize_side, 4., 200., cx)
- .flex(style.flex, false)
- .boxed()
+
+ let resizable = Container::new(ChildView::new(self.pane.clone()).boxed())
+ .with_style(panel_style)
+ .with_resize_handle::<DockResizeHandle, _>(
+ resize_side as usize,
+ resize_side,
+ 4.,
+ self.panel_sizes.get(&anchor).copied().unwrap_or(200.),
+ cx,
+ );
+
+ let size = resizable.current_size();
+ let workspace = cx.handle();
+ cx.defer(move |cx| {
+ if let Some(workspace) = workspace.upgrade(cx) {
+ workspace.update(cx, |workspace, _| {
+ workspace.dock.panel_sizes.insert(anchor, size);
+ })
+ }
+ });
+
+ resizable.flex(style.flex, false).boxed()
}
DockAnchor::Expanded => Container::new(
MouseEventHandler::<Dock>::new(0, cx, |_state, _cx| {
@@ -1367,7 +1367,7 @@ impl View for Pane {
Flex::column()
.with_child({
let mut tab_row = Flex::row()
- .with_child(self.render_tabs(cx).flex(1., true).named("tabs"));
+ .with_child(self.render_tabs(cx).flex(1.0, true).named("tabs"));
// Render pane buttons
let theme = cx.global::<Settings>().theme.clone();
@@ -1389,7 +1389,7 @@ impl View for Pane {
icon_for_dock_anchor(anchor);
tab_bar_button(
- 2,
+ 1,
dock_icon,
cx,
|position| DeployDockMenu { position },
@@ -1398,7 +1398,7 @@ impl View for Pane {
.unwrap_or_else(|| {
// Add the split menu if this pane is not a dock
tab_bar_button(
- 1,
+ 2,
"icons/split_12.svg",
cx,
|position| DeployNewMenu { position },
@@ -1413,6 +1413,7 @@ impl View for Pane {
}))
.contained()
.with_style(theme.workspace.tab_bar.container)
+ .flex(1., false)
.boxed(),
)
}
@@ -1422,6 +1423,7 @@ impl View for Pane {
.with_height(theme.workspace.tab_bar.height)
.contained()
.with_style(theme.workspace.tab_bar.container)
+ .flex(1., false)
.named("tab bar")
})
.with_child(ChildView::new(&self.toolbar).boxed())
@@ -1506,13 +1508,14 @@ fn tab_bar_button<A: Action>(
.constrained()
.with_width(style.button_width)
.with_height(style.button_width)
- .aligned()
+ // .aligned()
.boxed()
})
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, move |e, cx| {
cx.dispatch_action(action_builder(e.region.lower_right()));
})
+ .flex(1., false)
.boxed()
}
@@ -189,13 +189,15 @@ impl View for Sidebar {
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
if let Some(active_item) = self.active_item() {
enum ResizeHandleTag {}
+ let style = &cx.global::<Settings>().theme.workspace.sidebar;
ChildView::new(active_item.to_any())
+ .contained()
+ .with_style(style.container)
.with_resize_handle::<ResizeHandleTag, _>(
self.sidebar_side as usize,
self.sidebar_side.to_resizable_side(),
- // TODO: Expose both of these constants in the theme
4.,
- 260.,
+ style.initial_size,
cx,
)
.boxed()
@@ -1479,11 +1479,17 @@ impl Workspace {
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);
+ let open = sidebar.update(cx, |sidebar, cx| {
+ let open = !sidebar.is_open();
+ sidebar.set_open(open, cx);
+ open
});
+ if open && sidebar_side == SidebarSide::Right && self.dock.is_anchored_at(DockAnchor::Right)
+ {
+ Dock::hide(self, cx);
+ }
+
cx.focus_self();
cx.notify();
}
@@ -1493,7 +1499,7 @@ impl Workspace {
SidebarSide::Left => &mut self.left_sidebar,
SidebarSide::Right => &mut self.right_sidebar,
};
- let active_item = sidebar.update(cx, |sidebar, cx| {
+ let active_item = sidebar.update(cx, move |sidebar, cx| {
if sidebar.is_open() && sidebar.active_item_ix() == action.item_index {
sidebar.set_open(false, cx);
None
@@ -1503,7 +1509,16 @@ impl Workspace {
sidebar.active_item().cloned()
}
});
+
if let Some(active_item) = active_item {
+ // If there is an active item, that means the sidebar was opened,
+ // which means we need to check if the dock is open and close it
+ if action.sidebar_side == SidebarSide::Right
+ && self.dock.is_anchored_at(DockAnchor::Right)
+ {
+ Dock::hide(self, cx);
+ }
+
if active_item.is_focused(cx) {
cx.focus_self();
} else {
@@ -1531,6 +1546,12 @@ impl Workspace {
sidebar.active_item().cloned()
});
if let Some(active_item) = active_item {
+ // If there is an active item, that means the sidebar was opened,
+ // which means we need to check if the dock is open and close it
+ if sidebar_side == SidebarSide::Right && self.dock.is_anchored_at(DockAnchor::Right) {
+ Dock::hide(self, cx);
+ }
+
if active_item.is_focused(cx) {
cx.focus_self();
} else {
@@ -37,11 +37,14 @@ export default function workspace(theme: Theme) {
},
cursor: "Arrow",
},
- sidebarResizeHandle: {
- background: border(theme, "primary").color,
- padding: {
- left: 1,
- },
+ sidebar: {
+ initialSize: 240,
+ border: {
+ color: border(theme, "primary").color,
+ width: 1,
+ left: true,
+ right: true,
+ }
},
paneDivider: {
color: border(theme, "secondary").color,
@@ -157,6 +160,8 @@ export default function workspace(theme: Theme) {
margin: { right: 10, bottom: 10 },
},
dock: {
+ initialSizeRight: 240,
+ initialSizeBottom: 360,
wash_color: withOpacity(theme.backgroundColor[500].base, 0.5),
flex: 0.5,
panel: {