From 9baada4fb4746685b39389906468a7b2ce9c53bd Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Fri, 6 Sep 2024 17:51:21 +0800 Subject: [PATCH] dock: Reduce dock item member (#223) --- crates/app/src/story_workspace.rs | 152 +++++---------------------- crates/story/src/button_story.rs | 18 ++++ crates/story/src/calendar_story.rs | 14 +++ crates/story/src/dropdown_story.rs | 14 +++ crates/story/src/icon_story.rs | 14 +++ crates/story/src/image_story.rs | 10 ++ crates/story/src/input_story.rs | 30 ++++-- crates/story/src/lib.rs | 97 ++++++++--------- crates/story/src/list_story.rs | 14 +++ crates/story/src/modal_story.rs | 14 +++ crates/story/src/popup_story.rs | 33 ++++-- crates/story/src/progress_story.rs | 10 ++ crates/story/src/resizable_story.rs | 14 +++ crates/story/src/scrollable_story.rs | 14 +++ crates/story/src/switch_story.rs | 14 +++ crates/story/src/table_story.rs | 14 +++ crates/story/src/text_story.rs | 14 +++ crates/story/src/tooltip_story.rs | 10 ++ crates/story/src/webview_story.rs | 10 ++ crates/ui/src/dock/mod.rs | 77 +++++--------- 20 files changed, 346 insertions(+), 241 deletions(-) diff --git a/crates/app/src/story_workspace.rs b/crates/app/src/story_workspace.rs index 5865c93c..cf8f25db 100644 --- a/crates/app/src/story_workspace.rs +++ b/crates/app/src/story_workspace.rs @@ -59,18 +59,8 @@ impl StoryWorkspace { DockItem::split( Axis::Vertical, vec![ - DockItem::panel(StoryContainer::panel( - "Icon", - "Icon use examples", - IconStory::view(cx).into(), - cx, - )), - DockItem::panel(StoryContainer::panel( - "Calendar", - "A calendar component.", - CalendarStory::view(cx).into(), - cx, - )), + DockItem::tab(StoryContainer::panel::(cx), &dock_area, cx), + DockItem::tab(StoryContainer::panel::(cx), &dock_area, cx), ], &dock_area, cx, @@ -80,83 +70,18 @@ impl StoryWorkspace { vec![ DockItem::tabs( vec![ - DockItem::panel(StoryContainer::panel( - "Button", - "Displays a button or a component that looks like a button.", - ButtonStory::view(cx).into(), - cx, - )), - DockItem::panel(StoryContainer::panel( - "Input", - "A control that allows the user to input text.", - InputStory::view(cx).into(), - cx, - )), - DockItem::panel(StoryContainer::panel( - "Dropdown", - "Displays a list of options for the user to pick from—triggered by a button.", - DropdownStory::view(cx).into(), - cx, - )), - DockItem::panel(StoryContainer::panel( - "Modal", - "Modal & Drawer use examples", - ModalStory::view(cx).into(), - cx, - )), - DockItem::panel(StoryContainer::panel( - "Popup", - "A popup displays content on top of the main page.", - PopupStory::view(cx).into(), - cx, - )), - DockItem::tabs( - vec![DockItem::panel(StoryContainer::panel( - "List", - "A list displays a series of items.", - ListStory::view(cx).into(), - cx, - ))], - None, - &dock_area, - cx, - ), - DockItem::panel(StoryContainer::panel( - "Switch", - "A control that allows the user to toggle between two states.", - SwitchStory::view(cx).into(), - cx, - )), - DockItem::panel(StoryContainer::panel( - "Progress", - "Progress use examples", - ProgressStory::view(cx).into(), - cx, - )), - DockItem::panel(StoryContainer::panel( - "Table", - "Table use examples", - TableStory::view(cx).into(), - cx, - )), - DockItem::panel(StoryContainer::panel( - "Image", - "Image use examples", - ImageStory::view(cx).into(), - cx, - )), - DockItem::panel(StoryContainer::panel( - "Resizable", - "Resizable use examples", - ResizableStory::view(cx).into(), - cx, - )), - DockItem::panel(StoryContainer::panel( - "Scrollable", - "Scrollable use examples", - ScrollableStory::view(cx).into(), - cx, - )), + StoryContainer::panel::(cx), + StoryContainer::panel::(cx), + StoryContainer::panel::(cx), + StoryContainer::panel::(cx), + StoryContainer::panel::(cx), + StoryContainer::panel::(cx), + StoryContainer::panel::(cx), + StoryContainer::panel::(cx), + StoryContainer::panel::(cx), + StoryContainer::panel::(cx), + StoryContainer::panel::(cx), + StoryContainer::panel::(cx), ], None, &dock_area, @@ -164,48 +89,29 @@ impl StoryWorkspace { ), DockItem::tabs( vec![ - DockItem::panel(StoryContainer::panel( - "Progress", - "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.", - ProgressStory::view(cx).into(), - cx, - )), - DockItem::panel(StoryContainer::panel( - "Text", - "Links, paragraphs, checkboxes, and more.", - TextStory::view(cx).into(), - cx, - ))], + StoryContainer::panel::(cx), + StoryContainer::panel::(cx), + ], None, &dock_area, cx, ), ], - vec![None, Some(px(300.))], + vec![None, None, Some(px(300.))], + &dock_area, + cx, + ), + DockItem::split_with_sizes( + Axis::Vertical, + vec![ + DockItem::tab(StoryContainer::panel::(cx), &dock_area, cx), + DockItem::tab(StoryContainer::panel::(cx), &dock_area, cx), + DockItem::tab(StoryContainer::panel::(cx), &dock_area, cx), + ], + vec![None, None, Some(px(300.))], &dock_area, cx, ), - DockItem::split_with_sizes(Axis::Vertical, vec![ - DockItem::panel(StoryContainer::panel( - "Tooltip", - "Displays a short message when users hover over an element.", - TooltipStory::view(cx).into(), - cx, - )), - DockItem::panel(StoryContainer::panel( - "Calendar", - "A calendar component.", - CalendarStory::view(cx).into(), - cx, - )), - DockItem::panel(StoryContainer::panel( - "Image", - "Render SVG image and Chart", - ImageStory::view(cx).into(), - cx, - )), - ], vec![None, None, Some(px(300.))], &dock_area, cx), - ], vec![Some(px(300.)), None, Some(px(350.))], &dock_area, diff --git a/crates/story/src/button_story.rs b/crates/story/src/button_story.rs index 18a392b7..c07f98ce 100644 --- a/crates/story/src/button_story.rs +++ b/crates/story/src/button_story.rs @@ -37,6 +37,24 @@ impl ButtonStory { } } +impl super::Story for ButtonStory { + fn title() -> &'static str { + "Button" + } + + fn description() -> &'static str { + "Displays a button or a component that looks like a button." + } + + fn closeable() -> bool { + false + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl Render for ButtonStory { fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { let disabled = self.disabled; diff --git a/crates/story/src/calendar_story.rs b/crates/story/src/calendar_story.rs index e4e376da..faebc2d5 100644 --- a/crates/story/src/calendar_story.rs +++ b/crates/story/src/calendar_story.rs @@ -17,6 +17,20 @@ pub struct CalendarStory { default_range_mode_picker: View, } +impl super::Story for CalendarStory { + fn title() -> &'static str { + "Calendar" + } + + fn description() -> &'static str { + "A date picker and calendar component." + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl CalendarStory { pub fn view(cx: &mut WindowContext) -> View { cx.new_view(Self::new) diff --git a/crates/story/src/dropdown_story.rs b/crates/story/src/dropdown_story.rs index b3799d9f..a62346f9 100644 --- a/crates/story/src/dropdown_story.rs +++ b/crates/story/src/dropdown_story.rs @@ -55,6 +55,20 @@ pub struct DropdownStory { disabled_dropdown: View>>, } +impl super::Story for DropdownStory { + fn title() -> &'static str { + "Dropdown" + } + + fn description() -> &'static str { + "Displays a list of options for the user to pick from—triggered by a button." + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl DropdownStory { fn new(cx: &mut WindowContext) -> View { let countries = vec![ diff --git a/crates/story/src/icon_story.rs b/crates/story/src/icon_story.rs index 26f9ce9f..1f5ccd41 100644 --- a/crates/story/src/icon_story.rs +++ b/crates/story/src/icon_story.rs @@ -18,6 +18,20 @@ impl IconStory { } } +impl super::Story for IconStory { + fn title() -> &'static str { + "Icon" + } + + fn description() -> &'static str { + "Icon use examples" + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl Render for IconStory { fn render(&mut self, cx: &mut gpui::ViewContext) -> impl gpui::IntoElement { v_flex().gap_3().child( diff --git a/crates/story/src/image_story.rs b/crates/story/src/image_story.rs index 6c6865c7..1be285a1 100644 --- a/crates/story/src/image_story.rs +++ b/crates/story/src/image_story.rs @@ -10,6 +10,16 @@ pub struct ImageStory { inbox_img: SvgImg, } +impl super::Story for ImageStory { + fn title() -> &'static str { + "Image" + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl ImageStory { pub fn new(_: &WindowContext) -> Self { let chart = charts_rs::PieChart::from_json(PIE_JSON).unwrap(); diff --git a/crates/story/src/input_story.rs b/crates/story/src/input_story.rs index c8d81d49..aea1451e 100644 --- a/crates/story/src/input_story.rs +++ b/crates/story/src/input_story.rs @@ -1,4 +1,8 @@ -use gpui::{actions, div, px, AppContext, FocusHandle, InteractiveElement, IntoElement, KeyBinding, ParentElement as _, Render, SharedString, Styled, View, ViewContext, VisualContext, WindowContext}; +use gpui::{ + actions, div, px, AppContext, FocusHandle, InteractiveElement, IntoElement, KeyBinding, + ParentElement as _, Render, SharedString, Styled, View, ViewContext, VisualContext, + WindowContext, +}; use crate::section; use ui::{ @@ -8,11 +12,7 @@ use ui::{ input::{InputEvent, OtpInput, TextInput}, prelude::FluentBuilder as _, scroll::ScrollbarAxis, - v_flex, - FocusableCycle, - IconName, - Sizable, - StyledExt, + v_flex, FocusableCycle, IconName, Sizable, StyledExt, }; actions!(input_story, [Tab, TabPrev]); @@ -44,6 +44,24 @@ pub struct InputStory { opt_input_sized: View, } +impl super::Story for InputStory { + fn title() -> &'static str { + "Input" + } + + fn description() -> &'static str { + "A control that allows the user to input text." + } + + fn closeable() -> bool { + false + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl InputStory { pub fn view(cx: &mut WindowContext) -> View { cx.new_view(Self::new) diff --git a/crates/story/src/lib.rs b/crates/story/src/lib.rs index 29f91ab0..682f6076 100644 --- a/crates/story/src/lib.rs +++ b/crates/story/src/lib.rs @@ -16,8 +16,6 @@ mod text_story; mod tooltip_story; mod webview_story; -use std::sync::Arc; - pub use button_story::ButtonStory; pub use calendar_story::CalendarStory; pub use dropdown_story::DropdownStory; @@ -38,20 +36,19 @@ pub use webview_story::WebViewStory; use gpui::{ actions, div, prelude::FluentBuilder as _, px, AnyView, AppContext, Div, EventEmitter, - FocusableView, Hsla, InteractiveElement, IntoElement, ParentElement, Pixels, Render, - SharedString, StatefulInteractiveElement, Styled as _, View, ViewContext, VisualContext, - WindowContext, + FocusableView, Hsla, InteractiveElement, IntoElement, ParentElement, Render, SharedString, + StatefulInteractiveElement, Styled as _, View, ViewContext, VisualContext, WindowContext, }; use ui::{ divider::Divider, - dock::{Panel, PanelEvent, TabPanel, TitleStyle}, + dock::{Panel, PanelEvent, TitleStyle}, h_flex, label::Label, notification::Notification, popup_menu::PopupMenu, theme::ActiveTheme, - v_flex, ContextModal, Placement, + v_flex, ContextModal, }; pub fn init(cx: &mut AppContext) { @@ -87,6 +84,7 @@ pub struct StoryContainer { width: Option, height: Option, story: Option, + story_klass: Option, closeable: bool, } @@ -95,66 +93,59 @@ pub enum ContainerEvent { Close, } +pub trait Story { + fn klass() -> &'static str { + std::any::type_name::() + } + + fn title() -> &'static str; + fn description() -> &'static str { + "" + } + fn closeable() -> bool { + true + } + fn title_bg() -> Option { + None + } + fn new_view(cx: &mut WindowContext) -> AnyView; +} + impl EventEmitter for StoryContainer {} impl StoryContainer { - pub fn new( - name: impl Into, - description: impl Into, - closeable: bool, - cx: &mut WindowContext, - ) -> Self { + pub fn new(closeable: bool, cx: &mut WindowContext) -> Self { let focus_handle = cx.focus_handle(); Self { focus_handle, - name: name.into(), + name: "".into(), title_bg: None, - description: description.into(), + description: "".into(), width: None, height: None, story: None, + story_klass: None, closeable, } } - pub fn panel( - name: impl Into, - description: impl Into, - story: AnyView, - cx: &mut WindowContext, - ) -> View { - cx.new_view(|cx| Self::new(name, description, true, cx).story(story)) - } - #[allow(clippy::too_many_arguments)] - pub fn add_panel( - name: impl Into, - description: impl Into, - story: AnyView, - tab_panel: View, - placement: Option, - size: Option, - closeable: bool, - title_bg: Option, - cx: &mut WindowContext, - ) { - let name = name.into(); - let description = description.into(); + pub fn panel(cx: &mut WindowContext) -> View { + let name = S::title(); + let description = S::description(); + let story = S::new_view(cx); + let story_klass = S::klass(); - tab_panel.update(cx, |panel, cx| { - let view = cx.new_view(|cx| { - Self::new(name, description, closeable, cx) - .story(story) - .title_bg(title_bg) - }); - if let Some(placement) = placement { - panel.add_panel_at(Arc::new(view.clone()), placement, size, cx); - } else { - panel.add_panel(Arc::new(view.clone()), cx); - } - view + let view = cx.new_view(|cx| { + let mut story = Self::new(S::closeable(), cx).story(story, story_klass); + story.name = name.into(); + story.description = description.into(); + story.title_bg = S::title_bg(); + story }); + + view } pub fn width(mut self, width: gpui::Pixels) -> Self { @@ -167,13 +158,9 @@ impl StoryContainer { self } - pub fn story(mut self, story: AnyView) -> Self { + pub fn story(mut self, story: AnyView, story_klass: impl Into) -> Self { self.story = Some(story); - self - } - - pub fn title_bg(mut self, title_bg: Option) -> Self { - self.title_bg = title_bg; + self.story_klass = Some(story_klass.into()); self } diff --git a/crates/story/src/list_story.rs b/crates/story/src/list_story.rs index 6a1ff4e6..eec701a9 100644 --- a/crates/story/src/list_story.rs +++ b/crates/story/src/list_story.rs @@ -196,6 +196,20 @@ pub struct ListStory { selected_company: Option, } +impl super::Story for ListStory { + fn title() -> &'static str { + "List" + } + + fn description() -> &'static str { + "A list displays a series of items." + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl ListStory { pub fn view(cx: &mut WindowContext) -> View { cx.new_view(Self::new) diff --git a/crates/story/src/modal_story.rs b/crates/story/src/modal_story.rs index 179c15fc..c8a3c381 100644 --- a/crates/story/src/modal_story.rs +++ b/crates/story/src/modal_story.rs @@ -151,6 +151,20 @@ pub struct ModalStory { model_padding: bool, } +impl super::Story for ModalStory { + fn title() -> &'static str { + "Modal" + } + + fn description() -> &'static str { + "Modal & Drawer use examples" + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl ModalStory { pub fn view(cx: &mut WindowContext) -> View { cx.new_view(Self::new) diff --git a/crates/story/src/popup_story.rs b/crates/story/src/popup_story.rs index 6664ad98..28ee3094 100644 --- a/crates/story/src/popup_story.rs +++ b/crates/story/src/popup_story.rs @@ -79,6 +79,20 @@ pub struct PopupStory { window_mode: bool, } +impl super::Story for PopupStory { + fn title() -> &'static str { + "Popup" + } + + fn description() -> &'static str { + "A popup displays content on top of the main page." + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl PopupStory { pub fn view(cx: &mut WindowContext) -> View { cx.new_view(Self::new) @@ -199,9 +213,10 @@ impl Render for PopupStory { .small(), ) .into_any() - }).max_w(px(600.)) + }) + .max_w(px(600.)) }) - }) + }), ), ) .child( @@ -209,7 +224,7 @@ impl Render for PopupStory { .anchor(AnchorCorner::TopRight) .trigger(Button::new("info-top-right", cx).label("Top Right")) .content(|cx| { - cx.new_view(|cx| + cx.new_view(|cx| { PopoverContent::new(cx, |cx| { v_flex() .gap_4() @@ -223,7 +238,8 @@ impl Render for PopupStory { .small(), ) .into_any() - })) + }) + }) }), ), ) @@ -284,11 +300,13 @@ impl Render for PopupStory { .w(px(300.)), ) .content(|cx| { - cx.new_view(|cx| + cx.new_view(|cx| { PopoverContent::new(cx, |cx| { v_flex() .gap_4() - .child("Hello, this is a Popover on the Bottom Right.") + .child( + "Hello, this is a Popover on the Bottom Right.", + ) .child(Divider::horizontal()) .child( Button::new("info1", cx) @@ -297,7 +315,8 @@ impl Render for PopupStory { .small(), ) .into_any() - })) + }) + }) }), ), ), diff --git a/crates/story/src/progress_story.rs b/crates/story/src/progress_story.rs index 44ab451d..1301e82a 100644 --- a/crates/story/src/progress_story.rs +++ b/crates/story/src/progress_story.rs @@ -21,6 +21,16 @@ pub struct ProgressStory { slider2_value: f32, } +impl super::Story for ProgressStory { + fn title() -> &'static str { + "Progress" + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl ProgressStory { pub fn view(cx: &mut WindowContext) -> View { cx.new_view(Self::new) diff --git a/crates/story/src/resizable_story.rs b/crates/story/src/resizable_story.rs index 54219d89..2a26fdf1 100644 --- a/crates/story/src/resizable_story.rs +++ b/crates/story/src/resizable_story.rs @@ -13,6 +13,20 @@ pub struct ResizableStory { group2: View, } +impl super::Story for ResizableStory { + fn title() -> &'static str { + "Resizable" + } + + fn description() -> &'static str { + "The resizable panels." + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl ResizableStory { pub fn view(cx: &mut WindowContext) -> View { cx.new_view(|cx| Self::new(cx)) diff --git a/crates/story/src/scrollable_story.rs b/crates/story/src/scrollable_story.rs index 81b5e49e..f0bb02b2 100644 --- a/crates/story/src/scrollable_story.rs +++ b/crates/story/src/scrollable_story.rs @@ -60,6 +60,20 @@ impl ScrollableStory { } } +impl super::Story for ScrollableStory { + fn title() -> &'static str { + "Scrollable" + } + + fn description() -> &'static str { + "Add vertical or horizontal, or both scrollbars to a container." + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl Render for ScrollableStory { fn render(&mut self, cx: &mut gpui::ViewContext) -> impl gpui::IntoElement { let view = cx.view().clone(); diff --git a/crates/story/src/switch_story.rs b/crates/story/src/switch_story.rs index bd1b5395..2b50441f 100644 --- a/crates/story/src/switch_story.rs +++ b/crates/story/src/switch_story.rs @@ -18,6 +18,20 @@ pub struct SwitchStory { switch3: bool, } +impl super::Story for SwitchStory { + fn title() -> &'static str { + "Switch" + } + + fn description() -> &'static str { + "A control that allows the user to toggle between two states." + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl SwitchStory { pub fn view(cx: &mut WindowContext) -> View { cx.new_view(|cx| Self::new(cx)) diff --git a/crates/story/src/table_story.rs b/crates/story/src/table_story.rs index 17bfc95b..d7dc0358 100644 --- a/crates/story/src/table_story.rs +++ b/crates/story/src/table_story.rs @@ -362,6 +362,20 @@ pub struct TableStory { table: View>, } +impl super::Story for TableStory { + fn title() -> &'static str { + "Table" + } + + fn description() -> &'static str { + "A complex data table with selection, sorting, column moving, and loading more." + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl TableStory { pub fn view(cx: &mut WindowContext) -> View { cx.new_view(Self::new) diff --git a/crates/story/src/text_story.rs b/crates/story/src/text_story.rs index ff52b953..0f2ebd11 100644 --- a/crates/story/src/text_story.rs +++ b/crates/story/src/text_story.rs @@ -25,6 +25,20 @@ pub struct TextStory { masked: bool, } +impl super::Story for TextStory { + fn title() -> &'static str { + "Text" + } + + fn description() -> &'static str { + "The text render testing and examples" + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl TextStory { pub(crate) fn new(_cx: &mut WindowContext) -> Self { Self { diff --git a/crates/story/src/tooltip_story.rs b/crates/story/src/tooltip_story.rs index 2ed30de6..b658896b 100644 --- a/crates/story/src/tooltip_story.rs +++ b/crates/story/src/tooltip_story.rs @@ -24,6 +24,16 @@ impl TooltipStory { } } +impl super::Story for TooltipStory { + fn title() -> &'static str { + "Tooltip" + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl Render for TooltipStory { fn render(&mut self, cx: &mut gpui::ViewContext) -> impl gpui::IntoElement { v_flex() diff --git a/crates/story/src/webview_story.rs b/crates/story/src/webview_story.rs index 4b5bdc24..203b4406 100644 --- a/crates/story/src/webview_story.rs +++ b/crates/story/src/webview_story.rs @@ -18,6 +18,16 @@ pub struct WebViewStory { address_input: View, } +impl super::Story for WebViewStory { + fn title() -> &'static str { + "WebView" + } + + fn new_view(cx: &mut WindowContext) -> gpui::AnyView { + Self::view(cx).into() + } +} + impl WebViewStory { pub fn view(cx: &mut WindowContext) -> View { let focus_handle = cx.focus_handle(); diff --git a/crates/ui/src/dock/mod.rs b/crates/ui/src/dock/mod.rs index 8f63050f..477f62ec 100644 --- a/crates/ui/src/dock/mod.rs +++ b/crates/ui/src/dock/mod.rs @@ -32,13 +32,10 @@ pub enum DockItem { view: View, }, Tabs { - items: Vec, + items: Vec>, active_ix: usize, view: View, }, - Panel { - view: Arc, - }, } impl DockItem { @@ -68,26 +65,12 @@ impl DockItem { let stack_panel = cx.new_view(|cx| { let mut stack_panel = StackPanel::new(axis, cx); for (i, item) in items.iter_mut().enumerate() { - // Always convert DockItem::Panel to DockItem::Tabs in split layout. - // This makes they can subscribe the Zoom event. - match item { - DockItem::Panel { .. } => { - *item = DockItem::tabs(vec![item.clone()], None, &dock_area, cx); - } - _ => {} - } - let view = item.view(); let size = sizes.get(i).copied().flatten(); stack_panel.add_panel(view.clone(), size, dock_area.downgrade(), cx) } for (i, item) in items.iter().enumerate() { - let item = match item { - DockItem::Panel { .. } => Self::tabs(vec![item.clone()], None, &dock_area, cx), - _ => item.clone(), - }; - let view = item.view(); let size = sizes.get(i).copied().flatten(); stack_panel.add_panel(view.clone(), size, dock_area.downgrade(), cx) @@ -106,8 +89,30 @@ impl DockItem { /// Create DockItem with tabs layout, items are displayed as tabs. /// /// The `active_ix` is the index of the active tab, if `None` the first tab is active. - pub fn tabs( - items: Vec, + pub fn tabs( + items: Vec>, + active_ix: Option, + dock_area: &View, + cx: &mut WindowContext, + ) -> Self { + let mut new_items: Vec> = vec![]; + for item in items.into_iter() { + let item: Arc = Arc::new(item); + new_items.push(item) + } + Self::new_tabs(new_items, active_ix, dock_area, cx) + } + + pub fn tab( + item: View

, + dock_area: &View, + cx: &mut WindowContext, + ) -> Self { + Self::new_tabs(vec![Arc::new(item.clone())], None, dock_area, cx) + } + + fn new_tabs( + items: Vec>, active_ix: Option, dock_area: &View, cx: &mut WindowContext, @@ -115,10 +120,8 @@ impl DockItem { let active_ix = active_ix.unwrap_or(0); let tab_panel = cx.new_view(|cx| { let mut tab_panel = TabPanel::new(None, dock_area.downgrade(), cx); - for item in items.iter() { - let view = item.view(); - tab_panel.add_panel(view, cx) + tab_panel.add_panel(item.clone(), cx) } tab_panel @@ -131,22 +134,11 @@ impl DockItem { } } - /// Create DockItem with a single panel, the `view` must implement `Panel`. - pub fn panel

(view: View

) -> Self - where - P: Panel, - { - Self::Panel { - view: Arc::new(view), - } - } - /// Returns the views of the dock item. fn view(&self) -> Arc { match self { Self::Split { view, .. } => Arc::new(view.clone()), Self::Tabs { view, .. } => Arc::new(view.clone()), - Self::Panel { view } => view.clone(), } } @@ -156,16 +148,7 @@ impl DockItem { Self::Split { items, .. } => { items.iter().find_map(|item| item.find_panel(panel.clone())) } - Self::Tabs { items, .. } => { - items.iter().find_map(|item| item.find_panel(panel.clone())) - } - Self::Panel { view } => { - if view == &panel { - Some(view.clone()) - } else { - None - } - } + Self::Tabs { items, .. } => items.iter().find(|item| *item == &panel).cloned(), } } } @@ -245,11 +228,6 @@ impl DockArea { // Because we always wrap the DockItem::Panel in a DockItem::Tabs subscribe_zoom(view, dock_area.clone(), cx); } - DockItem::Panel { .. } => { - // The DockItem::Panel is not need to handle the zoom events - // Because the DockItem::Panel is always wrapped in a DockItem::Tabs - // So we only need to subscribe the zoom events on the TabPanel - } } } @@ -272,7 +250,6 @@ impl DockArea { match &self.items { DockItem::Split { view, .. } => view.clone().into_any_element(), DockItem::Tabs { view, .. } => view.clone().into_any_element(), - DockItem::Panel { view } => view.view().into_any_element(), } } }