dock: Refactor to use ratio for dock, panel size. (#833)

This commit is contained in:
Jason Lee 2025-05-07 01:32:31 +08:00 committed by GitHub
parent e530af9b51
commit 6514aec22a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 229 additions and 217 deletions

View file

@ -279,7 +279,7 @@ impl StoryWorkspace {
cx, cx,
), ),
], ],
vec![None, Some(px(360.))], vec![None, Some(0.2)],
&dock_area, &dock_area,
window, window,
cx, cx,
@ -328,9 +328,9 @@ impl StoryWorkspace {
_ = dock_area.update(cx, |view, cx| { _ = dock_area.update(cx, |view, cx| {
view.set_version(MAIN_DOCK_AREA.version, window, cx); view.set_version(MAIN_DOCK_AREA.version, window, cx);
view.set_center(dock_item, window, cx); view.set_center(dock_item, window, cx);
view.set_left_dock(left_panels, Some(px(350.)), true, window, cx); view.set_left_dock(left_panels, 0.3, true, window, cx);
view.set_bottom_dock(bottom_panels, Some(px(200.)), true, window, cx); view.set_bottom_dock(bottom_panels, 0.2, true, window, cx);
view.set_right_dock(right_panels, Some(px(320.)), true, window, cx); view.set_right_dock(right_panels, 0.3, true, window, cx);
Self::save_state(&view.dump(cx)).unwrap(); Self::save_state(&view.dump(cx)).unwrap();
}); });

View file

@ -53,36 +53,32 @@ impl ResizableStory {
v_resizable() v_resizable()
.group( .group(
h_resizable() h_resizable()
.size(px(150.)) .ratio(0.1)
.child( .child(
resizable_panel() resizable_panel()
.size(px(300.)) .ratio(0.3)
.content(|_, cx| panel_box("Left 1 (Min 120px)", cx)), .content(|_, cx| panel_box("Left 1 (Min 120px)", cx)),
cx, cx,
) )
.child( .child(
resizable_panel() resizable_panel().content(|_, cx| panel_box("Center 1", cx)),
.size(px(400.))
.content(|_, cx| panel_box("Center 1", cx)),
cx, cx,
) )
.child( .child(
resizable_panel() resizable_panel()
.size(px(300.)) .ratio(0.4)
.content(|_, cx| panel_box("Right (Grow)", cx)), .content(|_, cx| panel_box("Right (Grow)", cx)),
cx, cx,
), ),
cx, cx,
) )
.child( .child(
resizable_panel() resizable_panel().content(|_, cx| panel_box("Center (Grow)", cx)),
.size(px(150.))
.content(|_, cx| panel_box("Center (Grow)", cx)),
cx, cx,
) )
.child( .child(
resizable_panel() resizable_panel()
.size(px(210.)) .ratio(0.5)
.content(|_, cx| panel_box("Bottom", cx)), .content(|_, cx| panel_box("Bottom", cx)),
cx, cx,
) )
@ -92,14 +88,12 @@ impl ResizableStory {
h_resizable() h_resizable()
.child( .child(
resizable_panel() resizable_panel()
.size(px(300.)) .ratio(0.3)
.content(|_, cx| panel_box("Left 2", cx)), .content(|_, cx| panel_box("Left 2", cx)),
cx, cx,
) )
.child( .child(
resizable_panel() resizable_panel().content(|_, cx| panel_box("Right (Grow)", cx)),
.size(px(400.))
.content(|_, cx| panel_box("Right (Grow)", cx)),
cx, cx,
) )
}); });
@ -114,8 +108,9 @@ impl ResizableStory {
impl Render for ResizableStory { impl Render for ResizableStory {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement { fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
v_flex() v_flex()
.h_full()
.gap_6() .gap_6()
.child(self.group1.clone()) .child(div().h(px(800.)).child(self.group1.clone()))
.child(self.group2.clone()) .child(self.group2.clone())
} }
} }

View file

@ -3,9 +3,9 @@
use std::{ops::Deref, sync::Arc}; use std::{ops::Deref, sync::Arc};
use gpui::{ use gpui::{
div, prelude::FluentBuilder as _, px, App, AppContext, Axis, Context, Element, Empty, Entity, div, prelude::FluentBuilder as _, px, Along, App, AppContext, Axis, Context, Element, Empty,
IntoElement, MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, Point, Render, Style, Entity, IntoElement, MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, Point, Render,
StyleRefinement, Styled as _, WeakEntity, Window, Style, StyleRefinement, Styled as _, WeakEntity, Window,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -66,8 +66,8 @@ pub struct Dock {
pub(super) placement: DockPlacement, pub(super) placement: DockPlacement,
dock_area: WeakEntity<DockArea>, dock_area: WeakEntity<DockArea>,
pub(crate) panel: DockItem, pub(crate) panel: DockItem,
/// 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. /// The ratio of the dock.
pub(super) size: Pixels, pub(super) ratio: f32,
pub(super) open: bool, pub(super) open: bool,
/// Whether the Dock is collapsible, default: true /// Whether the Dock is collapsible, default: true
pub(super) collapsible: bool, pub(super) collapsible: bool,
@ -104,7 +104,7 @@ impl Dock {
panel, panel,
open: true, open: true,
collapsible: true, collapsible: true,
size: px(200.0), ratio: 0.2,
resizing: false, resizing: false,
} }
} }
@ -147,7 +147,7 @@ impl Dock {
pub(super) fn from_state( pub(super) fn from_state(
dock_area: WeakEntity<DockArea>, dock_area: WeakEntity<DockArea>,
placement: DockPlacement, placement: DockPlacement,
size: Pixels, ratio: f32,
panel: DockItem, panel: DockItem,
open: bool, open: bool,
window: &mut Window, window: &mut Window,
@ -176,7 +176,7 @@ impl Dock {
dock_area, dock_area,
panel, panel,
open, open,
size, ratio,
collapsible: true, collapsible: true,
resizing: false, resizing: false,
} }
@ -244,13 +244,13 @@ impl Dock {
/// Returns the size of the Dock, the size is means the width or height of /// Returns the size of the Dock, the size is means the width or height of
/// the Dock, if the placement is left or right, the size is width, /// the Dock, if the placement is left or right, the size is width,
/// otherwise the size is height. /// otherwise the size is height.
pub fn size(&self) -> Pixels { pub fn ratio(&self) -> f32 {
self.size self.ratio
} }
/// Set the size of the Dock. /// Set the size of the Dock.
pub fn set_size(&mut self, size: Pixels, _: &mut Window, cx: &mut Context<Self>) { pub fn set_ratio(&mut self, ratio: f32, _: &mut Window, cx: &mut Context<Self>) {
self.size = size.max(PANEL_MIN_SIZE); self.ratio = ratio;
cx.notify(); cx.notify();
} }
@ -287,6 +287,16 @@ impl Dock {
cx.notify(); cx.notify();
} }
fn container_size(&self, cx: &App) -> Pixels {
let dock_area = self
.dock_area
.upgrade()
.expect("DockArea is missing")
.read(cx);
let area_bounds = dock_area.bounds;
area_bounds.size.along(self.placement.axis())
}
fn render_resize_handle(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render_resize_handle(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let axis = self.placement.axis(); let axis = self.placement.axis();
let view = cx.entity().clone(); let view = cx.entity().clone();
@ -301,6 +311,7 @@ impl Dock {
cx.new(|_| info.deref().clone()) cx.new(|_| info.deref().clone())
}) })
} }
fn resize(&mut self, mouse_position: Point<Pixels>, _: &mut Window, cx: &mut Context<Self>) { fn resize(&mut self, mouse_position: Point<Pixels>, _: &mut Window, cx: &mut Context<Self>) {
if !self.resizing { if !self.resizing {
return; return;
@ -312,28 +323,6 @@ impl Dock {
.expect("DockArea is missing") .expect("DockArea is missing")
.read(cx); .read(cx);
let area_bounds = dock_area.bounds; let area_bounds = dock_area.bounds;
let mut left_dock_size = Pixels(0.0);
let mut right_dock_size = Pixels(0.0);
// Get the size of the left dock if it's open and not the current dock
if let Some(left_dock) = &dock_area.left_dock {
if left_dock.entity_id() != cx.entity().entity_id() {
let left_dock_read = left_dock.read(cx);
if left_dock_read.is_open() {
left_dock_size = left_dock_read.size;
}
}
}
// Get the size of the right dock if it's open and not the current dock
if let Some(right_dock) = &dock_area.right_dock {
if right_dock.entity_id() != cx.entity().entity_id() {
let right_dock_read = right_dock.read(cx);
if right_dock_read.is_open() {
right_dock_size = right_dock_read.size;
}
}
}
let size = match self.placement { let size = match self.placement {
DockPlacement::Left => mouse_position.x - area_bounds.left(), DockPlacement::Left => mouse_position.x - area_bounds.left(),
@ -341,21 +330,10 @@ impl Dock {
DockPlacement::Bottom => area_bounds.bottom() - mouse_position.y, DockPlacement::Bottom => area_bounds.bottom() - mouse_position.y,
DockPlacement::Center => unreachable!(), DockPlacement::Center => unreachable!(),
}; };
match self.placement { let container_size = self.container_size(cx);
DockPlacement::Left => { let ratio = size / container_size;
let max_size = area_bounds.size.width - PANEL_MIN_SIZE - right_dock_size; let min_ratio = PANEL_MIN_SIZE / container_size;
self.size = size.clamp(PANEL_MIN_SIZE, max_size); self.ratio = ratio.clamp(min_ratio, 1.);
}
DockPlacement::Right => {
let max_size = area_bounds.size.width - PANEL_MIN_SIZE - left_dock_size;
self.size = size.clamp(PANEL_MIN_SIZE, max_size);
}
DockPlacement::Bottom => {
let max_size = area_bounds.size.height - PANEL_MIN_SIZE;
self.size = size.clamp(PANEL_MIN_SIZE, max_size);
}
DockPlacement::Center => unreachable!(),
}
cx.notify(); cx.notify();
} }
@ -372,13 +350,15 @@ impl Render for Dock {
} }
let cache_style = StyleRefinement::default().absolute().size_full(); let cache_style = StyleRefinement::default().absolute().size_full();
let container_size = self.container_size(cx);
let dock_size = (self.ratio * container_size).max(PANEL_MIN_SIZE);
div() div()
.relative() .relative()
.overflow_hidden() .overflow_hidden()
.map(|this| match self.placement { .map(|this| match self.placement {
DockPlacement::Left | DockPlacement::Right => this.h_flex().h_full().w(self.size), DockPlacement::Left | DockPlacement::Right => this.h_flex().h_full().w(dock_size),
DockPlacement::Bottom => this.w_full().h(self.size), DockPlacement::Bottom => this.w_full().h(dock_size),
DockPlacement::Center => unreachable!(), DockPlacement::Center => unreachable!(),
}) })
// Bottom Dock should keep the title bar, then user can click the Toggle button // Bottom Dock should keep the title bar, then user can click the Toggle button

View file

@ -78,7 +78,7 @@ pub enum DockItem {
Split { Split {
axis: Axis, axis: Axis,
items: Vec<DockItem>, items: Vec<DockItem>,
sizes: Vec<Option<Pixels>>, ratios: Vec<Option<f32>>,
view: Entity<StackPanel>, view: Entity<StackPanel>,
}, },
/// Tab layout /// Tab layout
@ -100,12 +100,15 @@ impl std::fmt::Debug for DockItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
DockItem::Split { DockItem::Split {
axis, items, sizes, .. axis,
items,
ratios,
..
} => f } => f
.debug_struct("Split") .debug_struct("Split")
.field("axis", axis) .field("axis", axis)
.field("items", &items.len()) .field("items", &items.len())
.field("sizes", sizes) .field("ratios", ratios)
.finish(), .finish(),
DockItem::Tabs { DockItem::Tabs {
items, active_ix, .. items, active_ix, ..
@ -140,7 +143,7 @@ impl DockItem {
pub fn split_with_sizes( pub fn split_with_sizes(
axis: Axis, axis: Axis,
items: Vec<DockItem>, items: Vec<DockItem>,
sizes: Vec<Option<Pixels>>, ratios: Vec<Option<f32>>,
dock_area: &WeakEntity<DockArea>, dock_area: &WeakEntity<DockArea>,
window: &mut Window, window: &mut Window,
cx: &mut App, cx: &mut App,
@ -150,14 +153,14 @@ impl DockItem {
let mut stack_panel = StackPanel::new(axis, window, cx); let mut stack_panel = StackPanel::new(axis, window, cx);
for (i, item) in items.iter_mut().enumerate() { for (i, item) in items.iter_mut().enumerate() {
let view = item.view(); let view = item.view();
let size = sizes.get(i).copied().flatten(); let ratio = ratios.get(i).copied().flatten();
stack_panel.add_panel(view.clone(), size, dock_area.clone(), window, cx) stack_panel.add_panel(view.clone(), ratio, dock_area.clone(), window, cx)
} }
for (i, item) in items.iter().enumerate() { for (i, item) in items.iter().enumerate() {
let view = item.view(); let view = item.view();
let size = sizes.get(i).copied().flatten(); let ratio = ratios.get(i).copied().flatten();
stack_panel.add_panel(view.clone(), size, dock_area.clone(), window, cx) stack_panel.add_panel(view.clone(), ratio, dock_area.clone(), window, cx)
} }
stack_panel stack_panel
@ -176,7 +179,7 @@ impl DockItem {
Self::Split { Self::Split {
axis, axis,
items, items,
sizes, ratios,
view: stack_panel, view: stack_panel,
} }
} }
@ -447,7 +450,7 @@ impl DockArea {
let dock_item = DockItem::Split { let dock_item = DockItem::Split {
axis: Axis::Horizontal, axis: Axis::Horizontal,
items: vec![], items: vec![],
sizes: vec![], ratios: vec![],
view: stack_panel.clone(), view: stack_panel.clone(),
}; };
@ -527,7 +530,7 @@ impl DockArea {
pub fn set_left_dock( pub fn set_left_dock(
&mut self, &mut self,
panel: DockItem, panel: DockItem,
size: Option<Pixels>, ratio: f32,
open: bool, open: bool,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@ -536,9 +539,7 @@ impl DockArea {
let weak_self = cx.entity().downgrade(); let weak_self = cx.entity().downgrade();
self.left_dock = Some(cx.new(|cx| { self.left_dock = Some(cx.new(|cx| {
let mut dock = Dock::left(weak_self.clone(), window, cx); let mut dock = Dock::left(weak_self.clone(), window, cx);
if let Some(size) = size { dock.set_ratio(ratio, window, cx);
dock.set_size(size, window, cx);
}
dock.set_panel(panel, window, cx); dock.set_panel(panel, window, cx);
dock.set_open(open, window, cx); dock.set_open(open, window, cx);
dock dock
@ -549,7 +550,7 @@ impl DockArea {
pub fn set_bottom_dock( pub fn set_bottom_dock(
&mut self, &mut self,
panel: DockItem, panel: DockItem,
size: Option<Pixels>, ratio: f32,
open: bool, open: bool,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@ -558,9 +559,7 @@ impl DockArea {
let weak_self = cx.entity().downgrade(); let weak_self = cx.entity().downgrade();
self.bottom_dock = Some(cx.new(|cx| { self.bottom_dock = Some(cx.new(|cx| {
let mut dock = Dock::bottom(weak_self.clone(), window, cx); let mut dock = Dock::bottom(weak_self.clone(), window, cx);
if let Some(size) = size { dock.set_ratio(ratio, window, cx);
dock.set_size(size, window, cx);
}
dock.set_panel(panel, window, cx); dock.set_panel(panel, window, cx);
dock.set_open(open, window, cx); dock.set_open(open, window, cx);
dock dock
@ -571,7 +570,7 @@ impl DockArea {
pub fn set_right_dock( pub fn set_right_dock(
&mut self, &mut self,
panel: DockItem, panel: DockItem,
size: Option<Pixels>, ratio: f32,
open: bool, open: bool,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@ -580,9 +579,7 @@ impl DockArea {
let weak_self = cx.entity().downgrade(); let weak_self = cx.entity().downgrade();
self.right_dock = Some(cx.new(|cx| { self.right_dock = Some(cx.new(|cx| {
let mut dock = Dock::right(weak_self.clone(), window, cx); let mut dock = Dock::right(weak_self.clone(), window, cx);
if let Some(size) = size { dock.set_ratio(ratio, window, cx);
dock.set_size(size, window, cx);
}
dock.set_panel(panel, window, cx); dock.set_panel(panel, window, cx);
dock.set_open(open, window, cx); dock.set_open(open, window, cx);
dock dock
@ -726,7 +723,7 @@ impl DockArea {
} else { } else {
self.set_left_dock( self.set_left_dock(
DockItem::tabs(vec![panel], None, &weak_self, window, cx), DockItem::tabs(vec![panel], None, &weak_self, window, cx),
None, 0.2,
true, true,
window, window,
cx, cx,
@ -739,7 +736,7 @@ impl DockArea {
} else { } else {
self.set_bottom_dock( self.set_bottom_dock(
DockItem::tabs(vec![panel], None, &weak_self, window, cx), DockItem::tabs(vec![panel], None, &weak_self, window, cx),
None, 0.2,
true, true,
window, window,
cx, cx,
@ -752,7 +749,7 @@ impl DockArea {
} else { } else {
self.set_right_dock( self.set_right_dock(
DockItem::tabs(vec![panel], None, &weak_self, window, cx), DockItem::tabs(vec![panel], None, &weak_self, window, cx),
None, 0.2,
true, true,
window, window,
cx, cx,

View file

@ -13,8 +13,8 @@ use crate::{
use super::{DockArea, Panel, PanelEvent, PanelState, PanelView, TabPanel}; use super::{DockArea, Panel, PanelEvent, PanelState, PanelView, TabPanel};
use gpui::{ use gpui::{
prelude::FluentBuilder as _, App, AppContext, Axis, Context, DismissEvent, Entity, prelude::FluentBuilder as _, App, AppContext, Axis, Context, DismissEvent, Entity,
EventEmitter, FocusHandle, Focusable, IntoElement, ParentElement, Pixels, Render, Styled, EventEmitter, FocusHandle, Focusable, IntoElement, ParentElement, Render, Styled, Subscription,
Subscription, WeakEntity, Window, WeakEntity, Window,
}; };
use smallvec::SmallVec; use smallvec::SmallVec;
@ -41,11 +41,11 @@ impl Panel for StackPanel {
} }
} }
fn dump(&self, cx: &App) -> PanelState { fn dump(&self, cx: &App) -> PanelState {
let sizes = self.panel_group.read(cx).sizes(); let flexes = self.panel_group.read(cx).ratios();
let mut state = PanelState::new(self); let mut state = PanelState::new(self);
for panel in &self.panels { for panel in &self.panels {
state.add_child(panel.dump(cx)); state.add_child(panel.dump(cx));
state.info = PanelInfo::stack(sizes.clone(), self.axis); state.info = PanelInfo::stack(flexes.clone(), self.axis);
} }
state state
@ -111,19 +111,19 @@ impl StackPanel {
pub fn add_panel( pub fn add_panel(
&mut self, &mut self,
panel: Arc<dyn PanelView>, panel: Arc<dyn PanelView>,
size: Option<Pixels>, ratio: Option<f32>,
dock_area: WeakEntity<DockArea>, dock_area: WeakEntity<DockArea>,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
self.insert_panel(panel, self.panels.len(), size, dock_area, window, cx); self.insert_panel(panel, self.panels.len(), ratio, dock_area, window, cx);
} }
pub fn add_panel_at( pub fn add_panel_at(
&mut self, &mut self,
panel: Arc<dyn PanelView>, panel: Arc<dyn PanelView>,
placement: Placement, placement: Placement,
size: Option<Pixels>, ratio: Option<f32>,
dock_area: WeakEntity<DockArea>, dock_area: WeakEntity<DockArea>,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@ -132,7 +132,7 @@ impl StackPanel {
panel, panel,
self.panels_len(), self.panels_len(),
placement, placement,
size, ratio,
dock_area, dock_area,
window, window,
cx, cx,
@ -145,17 +145,17 @@ impl StackPanel {
panel: Arc<dyn PanelView>, panel: Arc<dyn PanelView>,
ix: usize, ix: usize,
placement: Placement, placement: Placement,
size: Option<Pixels>, ratio: Option<f32>,
dock_area: WeakEntity<DockArea>, dock_area: WeakEntity<DockArea>,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
match placement { match placement {
Placement::Top | Placement::Left => { Placement::Top | Placement::Left => {
self.insert_panel_before(panel, ix, size, dock_area, window, cx) self.insert_panel_before(panel, ix, ratio, dock_area, window, cx)
} }
Placement::Right | Placement::Bottom => { Placement::Right | Placement::Bottom => {
self.insert_panel_after(panel, ix, size, dock_area, window, cx) self.insert_panel_after(panel, ix, ratio, dock_area, window, cx)
} }
} }
} }
@ -165,12 +165,12 @@ impl StackPanel {
&mut self, &mut self,
panel: Arc<dyn PanelView>, panel: Arc<dyn PanelView>,
ix: usize, ix: usize,
size: Option<Pixels>, ratio: Option<f32>,
dock_area: WeakEntity<DockArea>, dock_area: WeakEntity<DockArea>,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
self.insert_panel(panel, ix, size, dock_area, window, cx); self.insert_panel(panel, ix, ratio, dock_area, window, cx);
} }
/// Insert a panel after the index. /// Insert a panel after the index.
@ -178,26 +178,26 @@ impl StackPanel {
&mut self, &mut self,
panel: Arc<dyn PanelView>, panel: Arc<dyn PanelView>,
ix: usize, ix: usize,
size: Option<Pixels>, ratio: Option<f32>,
dock_area: WeakEntity<DockArea>, dock_area: WeakEntity<DockArea>,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
self.insert_panel(panel, ix + 1, size, dock_area, window, cx); self.insert_panel(panel, ix + 1, ratio, dock_area, window, cx);
} }
fn new_resizable_panel(panel: Arc<dyn PanelView>, size: Option<Pixels>) -> ResizablePanel { fn new_resizable_panel(panel: Arc<dyn PanelView>, ratio: Option<f32>) -> ResizablePanel {
resizable_panel() resizable_panel()
.content_view(panel.view()) .content_view(panel.view())
.content_visible(move |_, cx| panel.visible(cx)) .content_visible(move |_, cx| panel.visible(cx))
.when_some(size, |this, size| this.size(size)) .when_some(ratio, |this, ratio| this.ratio(ratio))
} }
fn insert_panel( fn insert_panel(
&mut self, &mut self,
panel: Arc<dyn PanelView>, panel: Arc<dyn PanelView>,
ix: usize, ix: usize,
size: Option<Pixels>, ratio: Option<f32>,
dock_area: WeakEntity<DockArea>, dock_area: WeakEntity<DockArea>,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@ -241,7 +241,7 @@ impl StackPanel {
self.panels.insert(ix, panel.clone()); self.panels.insert(ix, panel.clone());
self.panel_group.update(cx, |view, cx| { self.panel_group.update(cx, |view, cx| {
view.insert_child( view.insert_child(
Self::new_resizable_panel(panel.clone(), size), Self::new_resizable_panel(panel.clone(), ratio),
ix, ix,
window, window,
cx, cx,

View file

@ -26,17 +26,22 @@ pub struct DockAreaState {
pub struct DockState { pub struct DockState {
panel: PanelState, panel: PanelState,
placement: DockPlacement, placement: DockPlacement,
size: Pixels, #[serde(default = "default_ratio")]
ratio: f32,
open: bool, open: bool,
} }
fn default_ratio() -> f32 {
0.2
}
impl DockState { impl DockState {
pub fn new(dock: Entity<Dock>, cx: &App) -> Self { pub fn new(dock: Entity<Dock>, cx: &App) -> Self {
let dock = dock.read(cx); let dock = dock.read(cx);
Self { Self {
placement: dock.placement, placement: dock.placement,
size: dock.size, ratio: dock.ratio,
open: dock.open, open: dock.open,
panel: dock.panel.view().dump(cx), panel: dock.panel.view().dump(cx),
} }
@ -54,7 +59,7 @@ impl DockState {
Dock::from_state( Dock::from_state(
dock_area.clone(), dock_area.clone(),
self.placement, self.placement,
self.size, self.ratio,
item, item,
self.open, self.open,
window, window,
@ -100,7 +105,8 @@ impl From<Bounds<Pixels>> for TileMeta {
pub enum PanelInfo { pub enum PanelInfo {
#[serde(rename = "stack")] #[serde(rename = "stack")]
Stack { Stack {
sizes: Vec<Pixels>, #[serde(default)]
ratios: Vec<f32>,
axis: usize, // 0 for horizontal, 1 for vertical axis: usize, // 0 for horizontal, 1 for vertical
}, },
#[serde(rename = "tabs")] #[serde(rename = "tabs")]
@ -112,9 +118,9 @@ pub enum PanelInfo {
} }
impl PanelInfo { impl PanelInfo {
pub fn stack(sizes: Vec<Pixels>, axis: Axis) -> Self { pub fn stack(ratios: Vec<f32>, axis: Axis) -> Self {
Self::Stack { Self::Stack {
sizes, ratios,
axis: if axis == Axis::Horizontal { 0 } else { 1 }, axis: if axis == Axis::Horizontal { 0 } else { 1 },
} }
} }
@ -142,9 +148,9 @@ impl PanelInfo {
} }
} }
pub fn sizes(&self) -> Option<&Vec<Pixels>> { pub fn ratios(&self) -> Option<&Vec<f32>> {
match self { match self {
Self::Stack { sizes, .. } => Some(sizes), Self::Stack { ratios, .. } => Some(ratios),
_ => None, _ => None,
} }
} }
@ -194,14 +200,14 @@ impl PanelState {
.collect(); .collect();
match info { match info {
PanelInfo::Stack { sizes, axis } => { PanelInfo::Stack { ratios, axis } => {
let axis = if axis == 0 { let axis = if axis == 0 {
Axis::Horizontal Axis::Horizontal
} else { } else {
Axis::Vertical Axis::Vertical
}; };
let sizes = sizes.iter().map(|s| Some(*s)).collect_vec(); let ratios = ratios.iter().map(|&ratio| Some(ratio)).collect();
DockItem::split_with_sizes(axis, items, sizes, &dock_area, window, cx) DockItem::split_with_sizes(axis, items, ratios, &dock_area, window, cx)
} }
PanelInfo::Tabs { active_index } => { PanelInfo::Tabs { active_index } => {
if items.len() == 1 { if items.len() == 1 {
@ -239,8 +245,6 @@ impl PanelState {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use gpui::px;
use super::*; use super::*;
#[test] #[test]
fn test_deserialize_item_state() { fn test_deserialize_item_state() {
@ -259,7 +263,7 @@ mod tests {
let left_dock = state.left_dock.unwrap(); let left_dock = state.left_dock.unwrap();
assert_eq!(left_dock.open, true); assert_eq!(left_dock.open, true);
assert_eq!(left_dock.size, px(350.0)); assert_eq!(left_dock.ratio, 0.2);
assert_eq!(left_dock.placement, DockPlacement::Left); assert_eq!(left_dock.placement, DockPlacement::Left);
assert_eq!(left_dock.panel.panel_name, "TabPanel"); assert_eq!(left_dock.panel.panel_name, "TabPanel");
assert_eq!(left_dock.panel.children.len(), 1); assert_eq!(left_dock.panel.children.len(), 1);
@ -267,14 +271,14 @@ mod tests {
let bottom_dock = state.bottom_dock.unwrap(); let bottom_dock = state.bottom_dock.unwrap();
assert_eq!(bottom_dock.open, true); assert_eq!(bottom_dock.open, true);
assert_eq!(bottom_dock.size, px(200.0)); assert_eq!(bottom_dock.ratio, 0.32);
assert_eq!(bottom_dock.panel.panel_name, "TabPanel"); assert_eq!(bottom_dock.panel.panel_name, "TabPanel");
assert_eq!(bottom_dock.panel.children.len(), 2); assert_eq!(bottom_dock.panel.children.len(), 2);
assert_eq!(bottom_dock.panel.children[0].panel_name, "StoryContainer"); assert_eq!(bottom_dock.panel.children[0].panel_name, "StoryContainer");
let right_dock = state.right_dock.unwrap(); let right_dock = state.right_dock.unwrap();
assert_eq!(right_dock.open, true); assert_eq!(right_dock.open, true);
assert_eq!(right_dock.size, px(320.0)); assert_eq!(right_dock.ratio, 0.2);
assert_eq!(right_dock.panel.panel_name, "TabPanel"); assert_eq!(right_dock.panel.panel_name, "TabPanel");
assert_eq!(right_dock.panel.children.len(), 1); assert_eq!(right_dock.panel.children.len(), 1);
assert_eq!(right_dock.panel.children[0].panel_name, "StoryContainer"); assert_eq!(right_dock.panel.children[0].panel_name, "StoryContainer");

View file

@ -3,8 +3,8 @@ use std::sync::Arc;
use gpui::{ use gpui::{
div, prelude::FluentBuilder, px, rems, App, AppContext, Context, Corner, DefiniteLength, div, prelude::FluentBuilder, px, rems, App, AppContext, Context, Corner, DefiniteLength,
DismissEvent, DragMoveEvent, Empty, Entity, EventEmitter, FocusHandle, Focusable, DismissEvent, DragMoveEvent, Empty, Entity, EventEmitter, FocusHandle, Focusable,
InteractiveElement as _, IntoElement, ParentElement, Pixels, Render, ScrollHandle, InteractiveElement as _, IntoElement, ParentElement, Render, ScrollHandle, SharedString,
SharedString, StatefulInteractiveElement, StyleRefinement, Styled, WeakEntity, Window, StatefulInteractiveElement, StyleRefinement, Styled, WeakEntity, Window,
}; };
use rust_i18n::t; use rust_i18n::t;
@ -264,7 +264,7 @@ impl TabPanel {
&mut self, &mut self,
panel: Arc<dyn PanelView>, panel: Arc<dyn PanelView>,
placement: Placement, placement: Placement,
size: Option<Pixels>, ratio: Option<f32>,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
@ -272,7 +272,7 @@ impl TabPanel {
cx.update(|window, cx| { cx.update(|window, cx| {
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
view.will_split_placement = Some(placement); view.will_split_placement = Some(placement);
view.split_panel(panel, placement, size, window, cx) view.split_panel(panel, placement, ratio, window, cx)
}) })
.ok() .ok()
}) })
@ -930,7 +930,7 @@ impl TabPanel {
&self, &self,
panel: Arc<dyn PanelView>, panel: Arc<dyn PanelView>,
placement: Placement, placement: Placement,
size: Option<Pixels>, ratio: Option<f32>,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
@ -959,7 +959,7 @@ impl TabPanel {
Arc::new(new_tab_panel), Arc::new(new_tab_panel),
ix, ix,
placement, placement,
size, ratio,
dock_area.clone(), dock_area.clone(),
window, window,
cx, cx,
@ -971,7 +971,7 @@ impl TabPanel {
Arc::new(new_tab_panel), Arc::new(new_tab_panel),
ix, ix,
placement, placement,
size, ratio,
dock_area.clone(), dock_area.clone(),
window, window,
cx, cx,
@ -1001,7 +1001,13 @@ impl TabPanel {
new_stack_panel.update(cx, |view, cx| match placement { new_stack_panel.update(cx, |view, cx| match placement {
Placement::Left | Placement::Top => { Placement::Left | Placement::Top => {
view.add_panel(Arc::new(new_tab_panel), size, dock_area.clone(), window, cx); view.add_panel(
Arc::new(new_tab_panel),
ratio,
dock_area.clone(),
window,
cx,
);
view.add_panel( view.add_panel(
Arc::new(tab_panel.clone()), Arc::new(tab_panel.clone()),
None, None,
@ -1018,7 +1024,13 @@ impl TabPanel {
window, window,
cx, cx,
); );
view.add_panel(Arc::new(new_tab_panel), size, dock_area.clone(), window, cx); view.add_panel(
Arc::new(new_tab_panel),
ratio,
dock_area.clone(),
window,
cx,
);
} }
}); });

View file

@ -2,7 +2,7 @@ use std::{ops::Deref, rc::Rc};
use gpui::{ use gpui::{
canvas, div, prelude::FluentBuilder, px, relative, Along, AnyElement, AnyView, App, AppContext, canvas, div, prelude::FluentBuilder, px, relative, Along, AnyElement, AnyView, App, AppContext,
Axis, Bounds, Context, Element, Empty, Entity, EntityId, EventEmitter, IntoElement, IsZero, Axis, Bounds, Context, Element, Empty, Entity, EntityId, EventEmitter, IntoElement,
MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Render, Style, Styled, WeakEntity, Window, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Render, Style, Styled, WeakEntity, Window,
}; };
@ -28,9 +28,9 @@ impl Render for DragPanel {
#[derive(Clone)] #[derive(Clone)]
pub struct ResizablePanelGroup { pub struct ResizablePanelGroup {
panels: Vec<Entity<ResizablePanel>>, panels: Vec<Entity<ResizablePanel>>,
sizes: Vec<Pixels>, ratios: Vec<f32>,
axis: Axis, axis: Axis,
size: Option<Pixels>, ratio: Option<f32>,
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
resizing_panel_ix: Option<usize>, resizing_panel_ix: Option<usize>,
} }
@ -39,16 +39,16 @@ impl ResizablePanelGroup {
pub(super) fn new() -> Self { pub(super) fn new() -> Self {
Self { Self {
axis: Axis::Horizontal, axis: Axis::Horizontal,
sizes: Vec::new(), ratios: Vec::new(),
panels: Vec::new(), panels: Vec::new(),
size: None, ratio: None,
bounds: Bounds::default(), bounds: Bounds::default(),
resizing_panel_ix: None, resizing_panel_ix: None,
} }
} }
pub fn load(&mut self, sizes: Vec<Pixels>, panels: Vec<Entity<ResizablePanel>>) { pub fn load(&mut self, ratios: Vec<f32>, panels: Vec<Entity<ResizablePanel>>) {
self.sizes = sizes; self.ratios = ratios;
self.panels = panels; self.panels = panels;
} }
@ -72,10 +72,10 @@ impl ResizablePanelGroup {
/// Add a ResizablePanelGroup as a child to the group. /// Add a ResizablePanelGroup as a child to the group.
pub fn group(self, group: ResizablePanelGroup, cx: &mut Context<Self>) -> Self { pub fn group(self, group: ResizablePanelGroup, cx: &mut Context<Self>) -> Self {
let group: ResizablePanelGroup = group; let group: ResizablePanelGroup = group;
let size = group.size; let ratio = group.ratio;
let panel = ResizablePanel::new() let panel = ResizablePanel::new()
.content_view(cx.new(|_| group).into()) .content_view(cx.new(|_| group).into())
.when_some(size, |this, size| this.size(size)); .when_some(ratio, |this, ratio| this.ratio(ratio));
self.child(panel, cx) self.child(panel, cx)
} }
@ -83,26 +83,31 @@ impl ResizablePanelGroup {
/// ///
/// - When the axis is horizontal, the size is the height of the group. /// - When the axis is horizontal, the size is the height of the group.
/// - When the axis is vertical, the size is the width of the group. /// - When the axis is vertical, the size is the width of the group.
pub fn size(mut self, size: Pixels) -> Self { pub fn ratio(mut self, ratio: f32) -> Self {
self.size = Some(size); self.ratio = Some(ratio);
self self
} }
/// Returns the sizes of the resizable panels. /// Returns the ratios of the panels.
pub(crate) fn sizes(&self) -> Vec<Pixels> { pub(crate) fn ratios(&self) -> &Vec<f32> {
self.sizes.clone() &self.ratios
} }
/// Calculates the sum of all panel sizes within the group. /// Calculates the sum of all panel sizes within the group.
pub fn total_size(&self) -> Pixels { pub fn total_size(&self) -> Pixels {
self.sizes.iter().fold(px(0.0), |acc, &size| acc + size) self.bounds.size.along(self.axis)
} }
pub fn add_child(&mut self, panel: ResizablePanel, cx: &mut Context<Self>) { pub fn add_child(&mut self, panel: ResizablePanel, cx: &mut Context<Self>) {
let mut panel = panel; let mut panel = panel;
panel.axis = self.axis; panel.axis = self.axis;
panel.group = Some(cx.entity().downgrade()); panel.group = Some(cx.entity().downgrade());
self.sizes.push(panel.initial_size.unwrap_or_default()); let ratio = match panel.ratio {
Some(ratio) => ratio,
None => panel.initial_radio.unwrap_or_default(),
};
self.ratios.push(ratio);
self.panels.push(cx.new(|_| panel)); self.panels.push(cx.new(|_| panel));
} }
@ -116,9 +121,11 @@ impl ResizablePanelGroup {
let mut panel = panel; let mut panel = panel;
panel.axis = self.axis; panel.axis = self.axis;
panel.group = Some(cx.entity().downgrade()); panel.group = Some(cx.entity().downgrade());
let ratio = match panel.ratio {
self.sizes Some(ratio) => ratio,
.insert(ix, panel.initial_size.unwrap_or_default()); None => panel.initial_radio.unwrap_or_default(),
};
self.ratios.insert(ix, ratio);
self.panels.insert(ix, cx.new(|_| panel)); self.panels.insert(ix, cx.new(|_| panel));
cx.notify() cx.notify()
} }
@ -134,26 +141,32 @@ impl ResizablePanelGroup {
let mut panel = panel; let mut panel = panel;
let old_panel = self.panels[ix].clone(); let old_panel = self.panels[ix].clone();
let old_panel_initial_size = old_panel.read(cx).initial_size; let old_panel_initial_ratio = old_panel.read(cx).initial_radio;
let old_panel_size_ratio = old_panel.read(cx).size_ratio; let old_panel_ratio = old_panel.read(cx).ratio;
panel.initial_size = old_panel_initial_size; panel.initial_radio = old_panel_initial_ratio;
panel.size_ratio = old_panel_size_ratio; panel.ratio = old_panel_ratio;
panel.axis = self.axis; panel.axis = self.axis;
panel.group = Some(cx.entity().downgrade()); panel.group = Some(cx.entity().downgrade());
self.sizes[ix] = panel.initial_size.unwrap_or_default();
let ratio = match panel.ratio {
Some(ratio) => ratio,
None => panel.initial_radio.unwrap_or_default(),
};
self.ratios[ix] = ratio;
self.panels[ix] = cx.new(|_| panel); self.panels[ix] = cx.new(|_| panel);
cx.notify() cx.notify()
} }
pub fn remove_child(&mut self, ix: usize, _: &mut Window, cx: &mut Context<Self>) { pub fn remove_child(&mut self, ix: usize, _: &mut Window, cx: &mut Context<Self>) {
self.sizes.remove(ix); self.ratios.remove(ix);
self.panels.remove(ix); self.panels.remove(ix);
cx.notify() cx.notify()
} }
pub(crate) fn remove_all_children(&mut self, _: &mut Window, cx: &mut Context<Self>) { pub(crate) fn remove_all_children(&mut self, _: &mut Window, cx: &mut Context<Self>) {
self.sizes.clear(); self.ratios.clear();
self.panels.clear(); self.panels.clear();
cx.notify() cx.notify()
} }
@ -183,9 +196,10 @@ impl ResizablePanelGroup {
self.resizing_panel_ix = None; self.resizing_panel_ix = None;
} }
fn sync_real_panel_sizes(&mut self, _: &Window, cx: &App) { fn sync_real_panel_sizes(&mut self, _: &Window, cx: &mut App) {
let total_size = self.total_size();
for (i, panel) in self.panels.iter().enumerate() { for (i, panel) in self.panels.iter().enumerate() {
self.sizes[i] = panel.read(cx).bounds.size.along(self.axis) self.ratios[i] = panel.read(cx).bounds.size.along(self.axis) / total_size;
} }
} }
@ -208,53 +222,54 @@ impl ResizablePanelGroup {
self.sync_real_panel_sizes(window, cx); self.sync_real_panel_sizes(window, cx);
let mut changed = size - self.sizes[ix]; let new_ratio = size / container_size;
let is_expand = changed > px(0.); let mut changed = new_ratio - self.ratios[ix];
let is_expand = changed > 0.;
let main_ix = ix; let main_ix = ix;
let mut new_sizes = self.sizes.clone(); let mut new_ratios = self.ratios.clone();
let min_ratio = PANEL_MIN_SIZE / container_size;
if is_expand { if is_expand {
new_sizes[ix] = size; new_ratios[ix] = new_ratio;
// Now to expand logic is correct. // Now to expand logic is correct.
while changed > px(0.) && ix < self.panels.len() - 1 { while changed > 0. && ix < self.panels.len() - 1 {
ix += 1; ix += 1;
let available_size = (new_sizes[ix] - PANEL_MIN_SIZE).max(px(0.)); let available_ratio = (new_ratios[ix] - min_ratio).max(0.);
let to_reduce = changed.min(available_size); let to_reduce = changed.min(available_ratio);
new_sizes[ix] -= to_reduce; new_ratios[ix] -= to_reduce;
changed -= to_reduce; changed -= to_reduce;
} }
} else { } else {
let new_size = size.max(PANEL_MIN_SIZE); let new_size = new_ratio.max(min_ratio);
new_sizes[ix] = new_size; new_ratios[ix] = new_size;
changed = size - PANEL_MIN_SIZE; changed = new_ratio - min_ratio;
new_sizes[ix + 1] += self.sizes[ix] - new_size; new_ratios[ix + 1] += self.ratios[ix] - new_size;
while changed < px(0.) && ix > 0 { while changed < 0. && ix > 0 {
ix -= 1; ix -= 1;
let available_size = self.sizes[ix] - PANEL_MIN_SIZE; let available_ratio = self.ratios[ix] - min_ratio;
let to_increase = (changed).min(available_size); let to_increase = (changed).min(available_ratio);
new_sizes[ix] += to_increase; new_ratios[ix] += to_increase;
changed += to_increase; changed += to_increase;
} }
} }
// If total size exceeds container size, adjust the main panel // If total size exceeds container size, adjust the main panel
let total_size: Pixels = new_sizes.iter().map(|s| s.0).sum::<f32>().into(); let total_ratio: f32 = new_ratios.iter().sum();
if total_size > container_size { if total_ratio > 1. {
let overflow = total_size - container_size; let overflow = 1.0 - total_ratio;
new_sizes[main_ix] = (new_sizes[main_ix] - overflow).max(PANEL_MIN_SIZE); new_ratios[main_ix] = (new_ratios[main_ix] - overflow).max(min_ratio);
} }
let total_size = new_sizes.iter().fold(px(0.0), |acc, &size| acc + size); self.ratios = new_ratios;
self.sizes = new_sizes;
for (i, panel) in self.panels.iter().enumerate() { for (i, panel) in self.panels.iter().enumerate() {
let size = self.sizes[i]; let ratio = self.ratios[i];
if size > px(0.) { if ratio > 0. {
panel.update(cx, |this, _| { panel.update(cx, |this, _| {
this.size = Some(size); this.size = Some(container_size * ratio);
this.size_ratio = Some(size / total_size); this.ratio = Some(ratio);
}); });
} }
} }
@ -300,11 +315,11 @@ impl Render for ResizablePanelGroup {
pub struct ResizablePanel { pub struct ResizablePanel {
group: Option<WeakEntity<ResizablePanelGroup>>, group: Option<WeakEntity<ResizablePanelGroup>>,
/// Initial size is the size that the panel has when it is created. /// Initial size is the size that the panel has when it is created.
initial_size: Option<Pixels>, initial_radio: Option<f32>,
/// size is the size that the panel has when it is resized or adjusted by flex layout. /// size is the size that the panel has when it is resized or adjusted by flex layout.
size: Option<Pixels>, size: Option<Pixels>,
/// the size ratio that the panel has relative to its group /// the size ratio that the panel has relative to its group
size_ratio: Option<f32>, ratio: Option<f32>,
axis: Axis, axis: Axis,
content_builder: Option<Rc<dyn Fn(&mut Window, &mut App) -> AnyElement>>, content_builder: Option<Rc<dyn Fn(&mut Window, &mut App) -> AnyElement>>,
content_view: Option<AnyView>, content_view: Option<AnyView>,
@ -318,9 +333,9 @@ impl ResizablePanel {
pub(super) fn new() -> Self { pub(super) fn new() -> Self {
Self { Self {
group: None, group: None,
initial_size: None, initial_radio: None,
size: None, size: None,
size_ratio: None, ratio: None,
axis: Axis::Horizontal, axis: Axis::Horizontal,
content_builder: None, content_builder: None,
content_view: None, content_view: None,
@ -351,28 +366,36 @@ impl ResizablePanel {
self self
} }
/// Set the initial size of the panel. // /// Set the initial size of the panel.
pub fn size(mut self, size: Pixels) -> Self { // pub fn size(mut self, size: Pixels) -> Self {
self.initial_size = Some(size); // self.initial_size = Some(size);
// self
// }
/// Set the flex ratio of the panel, the ratio is relative to the total size of the group.
///
/// The `ratio` is 0.0 to 1.0.
pub fn ratio(mut self, ratio: f32) -> Self {
self.initial_radio = Some(ratio);
self.ratio = Some(ratio);
self self
} }
/// Save the real panel size, and update group sizes /// Save the real panel size, and update group sizes
fn update_size(&mut self, bounds: Bounds<Pixels>, _: &mut Window, cx: &mut Context<Self>) { fn update_size(&mut self, bounds: Bounds<Pixels>, window: &mut Window, cx: &mut Context<Self>) {
let new_size = bounds.size.along(self.axis); let new_size = bounds.size.along(self.axis);
self.bounds = bounds; self.bounds = bounds;
self.size_ratio = None; self.ratio = None;
self.size = Some(new_size); self.size = Some(new_size);
cx.notify();
let entity_id = cx.entity().entity_id(); if let Some(group) = self.group.clone() {
if let Some(group) = self.group.as_ref() { window.defer(cx, move |window, cx| {
_ = group.update(cx, |view, _| { _ = group.update(cx, |view, cx| {
if let Some(ix) = view.panels.iter().position(|v| v.entity_id() == entity_id) { view.sync_real_panel_sizes(window, cx);
view.sizes[ix] = new_size; });
}
}); });
} }
cx.notify();
} }
} }
@ -382,7 +405,7 @@ impl Render for ResizablePanel {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
if !(self.content_visible)(window, cx) { if !(self.content_visible)(window, cx) {
// To keep size as initial size, to make sure the size will not be changed. // To keep size as initial size, to make sure the size will not be changed.
self.initial_size = self.size; self.initial_radio = self.ratio;
self.size = None; self.size = None;
return div(); return div();
} }
@ -399,23 +422,23 @@ impl Render for ResizablePanel {
.flex_grow() .flex_grow()
.size_full() .size_full()
.relative() .relative()
.when(self.initial_size.is_none(), |this| this.flex_shrink()) .when(self.initial_radio.is_none(), |this| this.flex_shrink())
.when(self.axis.is_vertical(), |this| this.min_h(PANEL_MIN_SIZE)) .when(self.axis.is_vertical(), |this| this.min_h(PANEL_MIN_SIZE))
.when(self.axis.is_horizontal(), |this| this.min_w(PANEL_MIN_SIZE)) .when(self.axis.is_horizontal(), |this| this.min_w(PANEL_MIN_SIZE))
.when_some(self.initial_size, |this, size| { .when_some(self.initial_radio, |this, radio| {
if size.is_zero() { if radio == 0. {
this this
} else { } else {
// The `self.size` is None, that mean the initial size for the panel, so we need set flex_shrink_0 // The `self.size` is None, that mean the initial size for the panel, so we need set flex_shrink_0
// To let it keep the initial size. // To let it keep the initial size.
this.when(self.size.is_none() && size > px(0.), |this| { this.when(self.size.is_none() && radio > 0., |this| {
this.flex_shrink_0() this.flex_shrink_0()
}) })
.flex_basis(size) .flex_basis(relative(radio))
} }
}) })
.map(|this| match (self.size_ratio, self.size, total_size) { .map(|this| match (self.ratio, self.size, total_size) {
(Some(size_ratio), _, _) => this.flex_basis(relative(size_ratio)), (Some(ratio), _, _) => this.flex_basis(relative(ratio)),
(None, Some(size), Some(total_size)) => { (None, Some(size), Some(total_size)) => {
this.flex_basis(relative(size / total_size)) this.flex_basis(relative(size / total_size))
} }

View file

@ -255,6 +255,7 @@
}, },
"placement": "bottom", "placement": "bottom",
"size": 200.0, "size": 200.0,
"ratio": 0.32,
"open": true, "open": true,
"resizeable": true "resizeable": true
} }