Skip to content

Commit ca5a0e0

Browse files
authored
dock: Add to support save left, right, bottom dock state. (longbridge#303)
The dock state have been updated to use `DockAreaState`.
1 parent 19bb5ee commit ca5a0e0

9 files changed

Lines changed: 658 additions & 430 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
/target
22
.DS_Store
33
/layout.json
4+
.vscode

.vscode/settings.json

Lines changed: 0 additions & 4 deletions
This file was deleted.

crates/app/src/story_workspace.rs

Lines changed: 68 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use anyhow::Result;
1+
use anyhow::{Context, Result};
22
use gpui::*;
33
use prelude::FluentBuilder as _;
44
use serde::Deserialize;
@@ -11,7 +11,7 @@ use story::{
1111
use ui::{
1212
button::{Button, ButtonStyled as _},
1313
color_picker::{ColorPicker, ColorPickerEvent},
14-
dock::{DockArea, DockEvent, DockItem, DockItemState, PanelView},
14+
dock::{DockArea, DockAreaState, DockEvent, DockItem, PanelView},
1515
h_flex,
1616
popup_menu::PopupMenuExt,
1717
theme::{ActiveTheme, Colorize as _, Theme},
@@ -39,59 +39,62 @@ pub struct StoryWorkspace {
3939
dock_area: View<DockArea>,
4040
locale_selector: View<LocaleSelector>,
4141
theme_color_picker: View<ColorPicker>,
42-
last_layout_state: Option<DockItemState>,
42+
last_layout_state: Option<DockAreaState>,
4343
_save_layout_task: Option<Task<()>>,
4444
}
4545

4646
impl StoryWorkspace {
4747
pub fn new(_app_state: Arc<AppState>, cx: &mut ViewContext<Self>) -> Self {
48-
cx.observe_window_appearance(|_workspace, cx| {
48+
cx.observe_window_appearance(|_, cx| {
4949
Theme::sync_system_appearance(cx);
5050
})
5151
.detach();
5252

5353
let dock_area = cx.new_view(|cx| DockArea::new("main-dock", cx));
5454
let weak_dock_area = dock_area.downgrade();
5555

56-
let dock_item = match Self::load_layout(&weak_dock_area, cx) {
57-
Ok(item) => item,
56+
match Self::load_layout(dock_area.clone(), cx) {
57+
Ok(_) => {
58+
println!("load layout success");
59+
}
5860
Err(err) => {
5961
eprintln!("load layout error: {:?}", err);
60-
Self::init_default_layout(&weak_dock_area, cx)
61-
}
62-
};
62+
let dock_item = Self::init_default_layout(&weak_dock_area, cx);
6363

64-
let left_panels: Vec<Arc<dyn PanelView>> =
65-
vec![Arc::new(StoryContainer::panel::<ListStory>(cx))];
64+
let left_panels: Vec<Arc<dyn PanelView>> =
65+
vec![Arc::new(StoryContainer::panel::<ListStory>(cx))];
6666

67-
let bottom_panels: Vec<Arc<dyn PanelView>> = vec![
68-
Arc::new(StoryContainer::panel::<TextStory>(cx)),
69-
Arc::new(StoryContainer::panel::<IconStory>(cx)),
70-
];
67+
let bottom_panels: Vec<Arc<dyn PanelView>> = vec![
68+
Arc::new(StoryContainer::panel::<TextStory>(cx)),
69+
Arc::new(StoryContainer::panel::<IconStory>(cx)),
70+
];
7171

72-
let right_panels: Vec<Arc<dyn PanelView>> =
73-
vec![Arc::new(StoryContainer::panel::<ImageStory>(cx))];
72+
let right_panels: Vec<Arc<dyn PanelView>> =
73+
vec![Arc::new(StoryContainer::panel::<ImageStory>(cx))];
7474

75-
dock_area.update(cx, |view, cx| {
76-
view.set_root(dock_item, cx);
77-
view.set_left_dock(left_panels, Some(px(350.)), cx);
78-
view.set_bottom_dock(bottom_panels, Some(px(200.)), cx);
79-
view.set_right_dock(right_panels, Some(px(320.)), cx);
80-
});
75+
_ = dock_area.update(cx, |view, cx| {
76+
view.set_root(dock_item, cx);
77+
view.set_left_dock(left_panels, Some(px(350.)), cx);
78+
view.set_bottom_dock(bottom_panels, Some(px(200.)), cx);
79+
view.set_right_dock(right_panels, Some(px(320.)), cx);
80+
});
81+
}
82+
};
8183

8284
cx.subscribe(&dock_area, |this, dock_area, ev: &DockEvent, cx| match ev {
8385
DockEvent::LayoutChanged => this.save_layout(dock_area, cx),
8486
})
8587
.detach();
8688

87-
let dock_area1 = dock_area.clone();
88-
cx.on_app_quit(move |cx| {
89-
let state = dock_area1.read(cx).dump(cx);
90-
91-
cx.background_executor().spawn(async move {
92-
// Save layout before quitting
93-
Self::save_state(&state).unwrap();
94-
})
89+
cx.on_app_quit({
90+
let dock_area = dock_area.clone();
91+
move |cx| {
92+
let state = dock_area.read(cx).dump(cx);
93+
cx.background_executor().spawn(async move {
94+
// Save layout before quitting
95+
Self::save_state(&state).unwrap();
96+
})
97+
}
9598
})
9699
.detach();
97100

@@ -132,7 +135,7 @@ impl StoryWorkspace {
132135

133136
fn save_layout(&mut self, dock_area: View<DockArea>, cx: &mut ViewContext<Self>) {
134137
self._save_layout_task = Some(cx.spawn(|this, mut cx| async move {
135-
Timer::after(Duration::from_secs(1)).await;
138+
Timer::after(Duration::from_secs(10)).await;
136139

137140
let _ = cx.update(|cx| {
138141
let dock_area = dock_area.read(cx);
@@ -151,82 +154,52 @@ impl StoryWorkspace {
151154
}));
152155
}
153156

154-
fn save_state(state: &DockItemState) -> Result<()> {
157+
fn save_state(state: &DockAreaState) -> Result<()> {
155158
println!("Save layout...");
156159
let json = serde_json::to_string_pretty(state)?;
157160
std::fs::write("layout.json", json)?;
158161
Ok(())
159162
}
160163

161-
fn load_layout(dock_area: &WeakView<DockArea>, cx: &mut WindowContext) -> Result<DockItem> {
164+
fn load_layout(dock_area: View<DockArea>, cx: &mut WindowContext) -> Result<()> {
162165
let fname = "layout.json";
163166
let json = std::fs::read_to_string(fname)?;
164-
let state = serde_json::from_str::<DockItemState>(&json)?;
167+
let state = serde_json::from_str::<DockAreaState>(&json)?;
168+
169+
dock_area.update(cx, |dock_area, cx| {
170+
dock_area.load(state, cx).context("load layout")?;
165171

166-
return Ok(state.to_item(dock_area.clone(), cx));
172+
Ok::<(), anyhow::Error>(())
173+
})
167174
}
168175

169176
fn init_default_layout(dock_area: &WeakView<DockArea>, cx: &mut WindowContext) -> DockItem {
170177
DockItem::split_with_sizes(
171-
Axis::Horizontal,
172-
vec![
173-
DockItem::split(
174-
Axis::Vertical,
175-
vec![
176-
DockItem::tab(StoryContainer::panel::<IconStory>(cx), &dock_area, cx),
177-
DockItem::tab(StoryContainer::panel::<CalendarStory>(cx), &dock_area, cx),
178-
],
179-
&dock_area,
180-
cx,
181-
),
182-
DockItem::split_with_sizes(
183-
Axis::Vertical,
184-
vec![
185-
DockItem::tabs(
186-
vec![
187-
Arc::new(StoryContainer::panel::<ButtonStory>(cx)),
188-
Arc::new(StoryContainer::panel::<InputStory>(cx)),
189-
Arc::new(StoryContainer::panel::<DropdownStory>(cx)),
190-
Arc::new(StoryContainer::panel::<ModalStory>(cx)),
191-
Arc::new(StoryContainer::panel::<PopupStory>(cx)),
192-
Arc::new(StoryContainer::panel::<SwitchStory>(cx)),
193-
Arc::new(StoryContainer::panel::<ProgressStory>(cx)),
194-
Arc::new(StoryContainer::panel::<TableStory>(cx)),
195-
Arc::new(StoryContainer::panel::<ImageStory>(cx)),
196-
Arc::new(StoryContainer::panel::<ResizableStory>(cx)),
197-
Arc::new(StoryContainer::panel::<ScrollableStory>(cx)),
198-
],
199-
None,
200-
&dock_area,
201-
cx,
202-
),
203-
DockItem::tabs(
204-
vec![
205-
Arc::new(StoryContainer::panel::<ProgressStory>(cx)),
206-
Arc::new(StoryContainer::panel::<TextStory>(cx)),
207-
],
208-
None,
209-
&dock_area,
210-
cx,
211-
),
212-
],
213-
vec![None, None, Some(px(300.))],
214-
&dock_area,
215-
cx,
216-
),
217-
DockItem::split_with_sizes(
218-
Axis::Vertical,
219-
vec![
220-
DockItem::tab(StoryContainer::panel::<TooltipStory>(cx), &dock_area, cx),
221-
DockItem::tab(StoryContainer::panel::<CalendarStory>(cx), &dock_area, cx),
222-
DockItem::tab(StoryContainer::panel::<ImageStory>(cx), &dock_area, cx),
223-
],
224-
vec![None, None, Some(px(300.))],
225-
&dock_area,
226-
cx,
227-
),
228-
],
229-
vec![Some(px(300.)), None, Some(px(350.))],
178+
Axis::Vertical,
179+
vec![DockItem::tabs(
180+
vec![
181+
Arc::new(StoryContainer::panel::<ButtonStory>(cx)),
182+
Arc::new(StoryContainer::panel::<InputStory>(cx)),
183+
Arc::new(StoryContainer::panel::<TextStory>(cx)),
184+
Arc::new(StoryContainer::panel::<DropdownStory>(cx)),
185+
Arc::new(StoryContainer::panel::<ModalStory>(cx)),
186+
Arc::new(StoryContainer::panel::<PopupStory>(cx)),
187+
Arc::new(StoryContainer::panel::<SwitchStory>(cx)),
188+
Arc::new(StoryContainer::panel::<ProgressStory>(cx)),
189+
Arc::new(StoryContainer::panel::<TableStory>(cx)),
190+
Arc::new(StoryContainer::panel::<ImageStory>(cx)),
191+
Arc::new(StoryContainer::panel::<IconStory>(cx)),
192+
Arc::new(StoryContainer::panel::<TooltipStory>(cx)),
193+
Arc::new(StoryContainer::panel::<ProgressStory>(cx)),
194+
Arc::new(StoryContainer::panel::<CalendarStory>(cx)),
195+
Arc::new(StoryContainer::panel::<ResizableStory>(cx)),
196+
Arc::new(StoryContainer::panel::<ScrollableStory>(cx)),
197+
],
198+
None,
199+
&dock_area,
200+
cx,
201+
)],
202+
vec![None],
230203
&dock_area,
231204
cx,
232205
)

crates/ui/src/dock/dock.rs

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use gpui::{
88
StatefulInteractiveElement, Style, Styled as _, View, ViewContext, VisualContext as _,
99
WeakView,
1010
};
11+
use serde::{Deserialize, Serialize};
1112

1213
use crate::{
1314
resizable::{HANDLE_PADDING, HANDLE_SIZE, PANEL_MIN_SIZE},
@@ -20,10 +21,13 @@ use super::{DockArea, PanelView, TabPanel};
2021
#[derive(Clone, Render)]
2122
struct ResizePanel;
2223

23-
#[derive(Debug, Clone, Copy)]
24+
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
2425
pub enum DockPlacement {
26+
#[serde(rename = "left")]
2527
Left,
28+
#[serde(rename = "bottom")]
2629
Bottom,
30+
#[serde(rename = "right")]
2731
Right,
2832
}
2933

@@ -52,18 +56,17 @@ impl DockPlacement {
5256
///
5357
/// This is unlike Panel, it can't be move or add any other panel.
5458
pub struct Dock {
55-
placement: DockPlacement,
59+
pub(super) placement: DockPlacement,
5660
dock_area: WeakView<DockArea>,
5761
pub(crate) panel: View<TabPanel>,
5862
/// The size is means the width or height of the Dock, if the placement is left or right, the size is width, otherwise the size is height.
59-
size: Pixels,
60-
open: bool,
61-
resizeable: bool,
63+
pub(super) size: Pixels,
64+
pub(super) open: bool,
6265
is_resizing: bool,
6366
}
6467

6568
impl Dock {
66-
fn new(
69+
pub(crate) fn new(
6770
dock_area: WeakView<DockArea>,
6871
placement: DockPlacement,
6972
cx: &mut ViewContext<Self>,
@@ -80,7 +83,6 @@ impl Dock {
8083
dock_area,
8184
panel,
8285
open: true,
83-
resizeable: true,
8486
size: px(200.0),
8587
is_resizing: false,
8688
}
@@ -98,6 +100,23 @@ impl Dock {
98100
Self::new(dock_area, DockPlacement::Right, cx)
99101
}
100102

103+
pub(super) fn from_state(
104+
dock_area: WeakView<DockArea>,
105+
placement: DockPlacement,
106+
size: Pixels,
107+
panel: View<TabPanel>,
108+
open: bool,
109+
) -> Self {
110+
Self {
111+
placement,
112+
dock_area,
113+
panel,
114+
open,
115+
size,
116+
is_resizing: false,
117+
}
118+
}
119+
101120
pub fn set_panels(&mut self, panels: Vec<Arc<dyn PanelView>>, cx: &mut ViewContext<Self>) {
102121
self.panel.update(cx, |tab_panel, _| {
103122
tab_panel.panels = panels;
@@ -106,12 +125,6 @@ impl Dock {
106125
cx.notify();
107126
}
108127

109-
/// Set the Dock to be resizeable, default: true
110-
pub fn resizeable(mut self, resizeable: bool) -> Self {
111-
self.resizeable = resizeable;
112-
self
113-
}
114-
115128
pub fn is_open(&self) -> bool {
116129
self.open
117130
}

0 commit comments

Comments
 (0)