diff --git a/crates/story/examples/dock.rs b/crates/story/examples/dock.rs index de238f14..3ea4ce35 100644 --- a/crates/story/examples/dock.rs +++ b/crates/story/examples/dock.rs @@ -258,8 +258,7 @@ impl StoryWorkspace { fn reset_default_layout(dock_area: WeakEntity, window: &mut Window, cx: &mut App) { let dock_item = Self::init_default_layout(&dock_area, window, cx); - let left_panels = DockItem::split_with_sizes( - Axis::Vertical, + let left_panels = DockItem::v_split( vec![ DockItem::tab( StoryContainer::panel::(window, cx), @@ -272,38 +271,33 @@ impl StoryWorkspace { Arc::new(StoryContainer::panel::(window, cx)), Arc::new(StoryContainer::panel::(window, cx)), ], - None, &dock_area, window, cx, - ), + ) + .size(px(360.)), ], - vec![None, Some(px(360.))], &dock_area, window, cx, ); - let bottom_panels = DockItem::split_with_sizes( - Axis::Vertical, + let bottom_panels = DockItem::v_split( vec![DockItem::tabs( vec![ Arc::new(StoryContainer::panel::(window, cx)), Arc::new(StoryContainer::panel::(window, cx)), ], - None, &dock_area, window, cx, )], - vec![None], &dock_area, window, cx, ); - let right_panels = DockItem::split_with_sizes( - Axis::Vertical, + let right_panels = DockItem::v_split( vec![ DockItem::tab( StoryContainer::panel::(window, cx), @@ -318,7 +312,6 @@ impl StoryWorkspace { cx, ), ], - vec![None], &dock_area, window, cx, @@ -340,8 +333,7 @@ impl StoryWorkspace { window: &mut Window, cx: &mut App, ) -> DockItem { - DockItem::split_with_sizes( - Axis::Vertical, + DockItem::v_split( vec![DockItem::tabs( vec![ Arc::new(StoryContainer::panel::(window, cx)), @@ -364,12 +356,10 @@ impl StoryWorkspace { Arc::new(StoryContainer::panel::(window, cx)), Arc::new(StoryContainer::panel::(window, cx)), ], - None, &dock_area, window, cx, )], - vec![None], &dock_area, window, cx, diff --git a/crates/ui/src/dock/dock.rs b/crates/ui/src/dock/dock.rs index 39dc0494..2672cc94 100644 --- a/crates/ui/src/dock/dock.rs +++ b/crates/ui/src/dock/dock.rs @@ -3,15 +3,15 @@ use std::{ops::Deref, sync::Arc}; use gpui::{ - div, prelude::FluentBuilder as _, px, App, AppContext, Axis, Context, Element, Empty, Entity, - IntoElement, MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, Point, Render, Style, - StyleRefinement, Styled as _, WeakEntity, Window, + App, AppContext, Axis, Context, Element, Empty, Entity, IntoElement, MouseMoveEvent, + MouseUpEvent, ParentElement as _, Pixels, Point, Render, Style, StyleRefinement, Styled as _, + WeakEntity, Window, div, prelude::FluentBuilder as _, px, }; use serde::{Deserialize, Serialize}; use crate::{ - resizable::{resize_handle, PANEL_MIN_SIZE}, StyledExt, + resizable::{PANEL_MIN_SIZE, resize_handle}, }; use super::{DockArea, DockItem, PanelView, TabPanel}; @@ -91,6 +91,7 @@ impl Dock { }); let panel = DockItem::Tabs { + size: None, items: Vec::new(), active_ix: 0, view: panel.clone(), diff --git a/crates/ui/src/dock/mod.rs b/crates/ui/src/dock/mod.rs index 39c211c4..acfe60cc 100644 --- a/crates/ui/src/dock/mod.rs +++ b/crates/ui/src/dock/mod.rs @@ -78,20 +78,31 @@ pub enum DockItem { /// Split layout Split { axis: Axis, + /// Self size, only used for build split panels + size: Option, items: Vec, + /// Items sizes sizes: Vec>, view: Entity, }, /// Tab layout Tabs { + /// Self size, only used for build split panels + size: Option, items: Vec>, active_ix: usize, view: Entity, }, /// Panel layout - Panel { view: Arc }, + Panel { + /// Self size, only used for build split panels + size: Option, + view: Arc, + }, /// Tiles layout Tiles { + /// Self size, only used for build split panels + size: Option, items: Vec, view: Entity, }, @@ -122,7 +133,45 @@ impl std::fmt::Debug for DockItem { } impl DockItem { - /// Create DockItem with split layout, each item of panel have equal size. + /// Get the size of the DockItem. + fn get_size(&self) -> Option { + match self { + Self::Split { size, .. } => *size, + Self::Tabs { size, .. } => *size, + Self::Panel { size, .. } => *size, + Self::Tiles { size, .. } => *size, + } + } + + /// Set size for the DockItem. + pub fn size(mut self, new_size: impl Into) -> Self { + let new_size: Option = Some(new_size.into()); + match self { + Self::Split { ref mut size, .. } => *size = new_size, + Self::Tabs { ref mut size, .. } => *size = new_size, + Self::Tiles { ref mut size, .. } => *size = new_size, + Self::Panel { ref mut size, .. } => *size = new_size, + } + self + } + + /// Set active index for the DockItem, only valid for [`DockItem::Tabs`]. + pub fn active_index(mut self, new_active_ix: usize) -> Self { + debug_assert!( + matches!(self, Self::Tabs { .. }), + "active_ix can only be set for DockItem::Tabs" + ); + + if let Self::Tabs { + ref mut active_ix, .. + } = self + { + *active_ix = new_active_ix; + } + self + } + + /// Create DockItem::Split with given split layout. pub fn split( axis: Axis, items: Vec, @@ -130,10 +179,30 @@ impl DockItem { window: &mut Window, cx: &mut App, ) -> Self { - let sizes = vec![None; items.len()]; + let sizes = items.iter().map(|item| item.get_size()).collect(); Self::split_with_sizes(axis, items, sizes, dock_area, window, cx) } + /// Create DockItem with vertical split layout. + pub fn v_split( + items: Vec, + dock_area: &WeakEntity, + window: &mut Window, + cx: &mut App, + ) -> Self { + Self::split(Axis::Vertical, items, dock_area, window, cx) + } + + /// Create DockItem with horizontal split layout. + pub fn h_split( + items: Vec, + dock_area: &WeakEntity, + window: &mut Window, + cx: &mut App, + ) -> Self { + Self::split(Axis::Horizontal, items, dock_area, window, cx) + } + /// Create DockItem with split layout, each item of panel have specified size. /// /// Please note that the `items` and `sizes` must have the same length. @@ -176,6 +245,7 @@ impl DockItem { Self::Split { axis, + size: None, items, sizes, view: stack_panel, @@ -184,7 +254,10 @@ impl DockItem { /// Create DockItem with panel layout pub fn panel(panel: Arc) -> Self { - Self::Panel { view: panel } + Self::Panel { + size: None, + view: panel, + } } /// Create DockItem with tiles layout @@ -209,7 +282,7 @@ impl DockItem { TileItem::new(Arc::new(view), meta.bounds).z_index(meta.z_index); tiles.add_item(tile_item, dock_area, window, cx); } - DockItem::Panel { view } => { + DockItem::Panel { view, .. } => { let meta: TileMeta = metas[ix].into(); let tile_item = TileItem::new(view.clone(), meta.bounds).z_index(meta.z_index); @@ -235,6 +308,7 @@ impl DockItem { }); Self::Tiles { + size: None, items: tile_panel.read(cx).panels.clone(), view: tile_panel, } @@ -245,7 +319,6 @@ impl DockItem { /// The `active_ix` is the index of the active tab, if `None` the first tab is active. pub fn tabs( items: Vec>, - active_ix: Option, dock_area: &WeakEntity, window: &mut Window, cx: &mut App, @@ -254,7 +327,7 @@ impl DockItem { for item in items.into_iter() { new_items.push(item) } - Self::new_tabs(new_items, active_ix, dock_area, window, cx) + Self::new_tabs(new_items, None, dock_area, window, cx) } pub fn tab( @@ -284,6 +357,7 @@ impl DockItem { }); Self::Tabs { + size: None, items, active_ix, view: tab_panel, @@ -307,7 +381,7 @@ impl DockItem { items.iter().find_map(|item| item.find_panel(panel.clone())) } Self::Tabs { items, .. } => items.iter().find(|item| *item == &panel).cloned(), - Self::Panel { view } => Some(view.clone()), + Self::Panel { view, .. } => Some(view.clone()), Self::Tiles { items, .. } => items.iter().find_map(|item| { if &item.panel == &panel { Some(item.panel.clone()) @@ -346,13 +420,13 @@ impl DockItem { } // Unable to find tabs, create new tabs - let new_item = Self::tabs(vec![panel.clone()], None, dock_area, window, cx); + let new_item = Self::tabs(vec![panel.clone()], dock_area, window, cx); items.push(new_item.clone()); view.update(cx, |stack_panel, cx| { stack_panel.add_panel(new_item.view(), None, dock_area.clone(), window, cx); }); } - Self::Tiles { view, items } => { + Self::Tiles { view, items, .. } => { let tile_item = TileItem::new( Arc::new(cx.new(|cx| { let mut tab_panel = TabPanel::new(None, dock_area.clone(), window, cx); @@ -411,7 +485,7 @@ impl DockItem { } } DockItem::Tiles { .. } => {} - DockItem::Panel { view } => view.set_active(!collapsed, window, cx), + DockItem::Panel { view, .. } => view.set_active(!collapsed, window, cx), } } @@ -447,6 +521,7 @@ impl DockArea { let dock_item = DockItem::Split { axis: Axis::Horizontal, + size: None, items: vec![], sizes: vec![], view: stack_panel.clone(), @@ -726,7 +801,7 @@ impl DockArea { dock.update(cx, |dock, cx| dock.add_panel(panel, window, cx)) } else { self.set_left_dock( - DockItem::tabs(vec![panel], None, &weak_self, window, cx), + DockItem::tabs(vec![panel], &weak_self, window, cx), None, true, window, @@ -739,7 +814,7 @@ impl DockArea { dock.update(cx, |dock, cx| dock.add_panel(panel, window, cx)) } else { self.set_bottom_dock( - DockItem::tabs(vec![panel], None, &weak_self, window, cx), + DockItem::tabs(vec![panel], &weak_self, window, cx), None, true, window, @@ -752,7 +827,7 @@ impl DockArea { dock.update(cx, |dock, cx| dock.add_panel(panel, window, cx)) } else { self.set_right_dock( - DockItem::tabs(vec![panel], None, &weak_self, window, cx), + DockItem::tabs(vec![panel], &weak_self, window, cx), None, true, window, diff --git a/crates/ui/src/dock/state.rs b/crates/ui/src/dock/state.rs index e8259160..f54d0c3e 100644 --- a/crates/ui/src/dock/state.rs +++ b/crates/ui/src/dock/state.rs @@ -1,4 +1,4 @@ -use gpui::{point, px, size, App, AppContext, Axis, Bounds, Entity, Pixels, WeakEntity, Window}; +use gpui::{App, AppContext, Axis, Bounds, Entity, Pixels, WeakEntity, Window, point, px, size}; use itertools::Itertools as _; use serde::{Deserialize, Serialize}; @@ -219,7 +219,7 @@ impl PanelState { }) .collect_vec(); - DockItem::tabs(items, Some(active_index), &dock_area, window, cx) + DockItem::tabs(items, &dock_area, window, cx).active_index(active_index) } PanelInfo::Panel(_) => { let view = PanelRegistry::build_panel( @@ -230,7 +230,7 @@ impl PanelState { window, cx, ); - DockItem::tabs(vec![view.into()], None, &dock_area, window, cx) + DockItem::tabs(vec![view.into()], &dock_area, window, cx) } PanelInfo::Tiles { metas } => DockItem::tiles(items, metas, &dock_area, window, cx), } diff --git a/crates/ui/src/menu/app_menu_bar.rs b/crates/ui/src/menu/app_menu_bar.rs index 41a785f6..b9ee3eab 100644 --- a/crates/ui/src/menu/app_menu_bar.rs +++ b/crates/ui/src/menu/app_menu_bar.rs @@ -57,7 +57,7 @@ impl AppMenuBar { } else { selected_ix.saturating_sub(1) }; - self.set_selected_ix(Some(new_ix), window, cx); + self.set_selected_index(Some(new_ix), window, cx); } fn on_move_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context) { @@ -70,14 +70,14 @@ impl AppMenuBar { } else { selected_ix + 1 }; - self.set_selected_ix(Some(new_ix), window, cx); + self.set_selected_index(Some(new_ix), window, cx); } fn on_cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context) { - self.set_selected_ix(None, window, cx); + self.set_selected_index(None, window, cx); } - fn set_selected_ix(&mut self, ix: Option, _: &mut Window, cx: &mut Context) { + fn set_selected_index(&mut self, ix: Option, _: &mut Window, cx: &mut Context) { self.selected_ix = ix; cx.notify(); } @@ -189,7 +189,7 @@ impl AppMenu { _ = self.menu_bar.update(cx, |state, cx| { let new_ix = if is_selected { None } else { Some(self.ix) }; - state.set_selected_ix(new_ix, window, cx); + state.set_selected_index(new_ix, window, cx); }); } @@ -204,7 +204,7 @@ impl AppMenu { } _ = self.menu_bar.update(cx, |state, cx| { - state.set_selected_ix(Some(self.ix), window, cx); + state.set_selected_index(Some(self.ix), window, cx); }); } }