From a26311dc0ebb6b7269df5a5a7fe163c0506ddb1c Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 8 May 2025 12:01:16 +0800 Subject: [PATCH] dock: Improve dock, panel to support absolute or fraction size. (#839) --- crates/story/examples/dock.rs | 8 +++--- crates/ui/src/dock/dock.rs | 17 +++++++----- crates/ui/src/dock/mod.rs | 48 ++++++++++++++++++++++++--------- crates/ui/src/dock/state.rs | 6 +++-- crates/ui/src/dock/tab_panel.rs | 4 +-- 5 files changed, 56 insertions(+), 27 deletions(-) diff --git a/crates/story/examples/dock.rs b/crates/story/examples/dock.rs index b7a0862c..77768649 100644 --- a/crates/story/examples/dock.rs +++ b/crates/story/examples/dock.rs @@ -279,7 +279,7 @@ impl StoryWorkspace { cx, ), ], - vec![None, Some(0.2)], + vec![None, Some(relative(0.2))], &dock_area, window, cx, @@ -328,9 +328,9 @@ impl StoryWorkspace { _ = dock_area.update(cx, |view, cx| { view.set_version(MAIN_DOCK_AREA.version, window, cx); view.set_center(dock_item, window, cx); - view.set_left_dock(left_panels, 0.3, true, window, cx); - view.set_bottom_dock(bottom_panels, 0.2, true, window, cx); - view.set_right_dock(right_panels, 0.3, true, window, cx); + view.set_left_dock(left_panels, relative(0.3), true, window, cx); + view.set_bottom_dock(bottom_panels, relative(0.2), true, window, cx); + view.set_right_dock(right_panels, px(320.), true, window, cx); Self::save_state(&view.dump(cx)).unwrap(); }); diff --git a/crates/ui/src/dock/dock.rs b/crates/ui/src/dock/dock.rs index 9ac9b3f2..e1ccb098 100644 --- a/crates/ui/src/dock/dock.rs +++ b/crates/ui/src/dock/dock.rs @@ -3,9 +3,9 @@ use std::{ops::Deref, sync::Arc}; use gpui::{ - div, prelude::FluentBuilder as _, px, Along, 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, Along, App, AppContext, Axis, Context, DefiniteLength, + Element, Empty, Entity, IntoElement, MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, + Point, Render, Style, StyleRefinement, Styled as _, WeakEntity, Window, }; use serde::{Deserialize, Serialize}; @@ -14,7 +14,7 @@ use crate::{ StyledExt, }; -use super::{DockArea, DockItem, PanelView, TabPanel}; +use super::{definite_length_to_window_ratio, DockArea, DockItem, PanelView, TabPanel}; #[derive(Clone)] struct ResizePanel; @@ -249,8 +249,13 @@ impl Dock { } /// Set the size of the Dock. - pub fn set_ratio(&mut self, ratio: f32, _: &mut Window, cx: &mut Context) { - self.ratio = ratio; + pub fn set_size( + &mut self, + size: impl Into, + window: &mut Window, + cx: &mut Context, + ) { + self.ratio = definite_length_to_window_ratio(size, self.placement.axis(), window); cx.notify(); } diff --git a/crates/ui/src/dock/mod.rs b/crates/ui/src/dock/mod.rs index ce2dd9dd..2e83a0e7 100644 --- a/crates/ui/src/dock/mod.rs +++ b/crates/ui/src/dock/mod.rs @@ -8,9 +8,10 @@ mod tiles; use anyhow::Result; use gpui::{ - actions, canvas, div, prelude::FluentBuilder, AnyElement, AnyView, App, AppContext, Axis, - Bounds, Context, Edges, Entity, EntityId, EventEmitter, InteractiveElement as _, IntoElement, - ParentElement as _, Pixels, Render, SharedString, Styled, Subscription, WeakEntity, Window, + actions, canvas, div, prelude::FluentBuilder, relative, Along, AnyElement, AnyView, App, + AppContext, Axis, Bounds, Context, DefiniteLength, Edges, Entity, EntityId, EventEmitter, + InteractiveElement as _, IntoElement, ParentElement as _, Pixels, Render, SharedString, Styled, + Subscription, WeakEntity, Window, }; use std::sync::Arc; @@ -27,6 +28,22 @@ pub fn init(cx: &mut App) { actions!(dock, [ToggleZoom, ClosePanel]); +/// Convert [`gpui::DefiniteLength`] to ratio of window. +pub(crate) fn definite_length_to_window_ratio( + length: impl Into, + axis: Axis, + window: &Window, +) -> f32 { + let length: DefiniteLength = length.into(); + match length { + DefiniteLength::Absolute(size) => { + let container_size = window.bounds().size.along(axis); + size.to_pixels(window.rem_size()) / container_size + } + DefiniteLength::Fraction(ratio) => ratio, + } +} + pub enum DockEvent { /// The layout of the dock has changed, subscribers this to save the layout. /// @@ -143,12 +160,17 @@ impl DockItem { pub fn split_with_sizes( axis: Axis, items: Vec, - ratios: Vec>, + sizes: Vec>, dock_area: &WeakEntity, window: &mut Window, cx: &mut App, ) -> Self { let mut items = items; + let ratios: Vec> = sizes + .into_iter() + .map(|size| size.map(|val| definite_length_to_window_ratio(val, axis, window))) + .collect(); + let stack_panel = cx.new(|cx| { let mut stack_panel = StackPanel::new(axis, window, cx); for (i, item) in items.iter_mut().enumerate() { @@ -530,7 +552,7 @@ impl DockArea { pub fn set_left_dock( &mut self, panel: DockItem, - ratio: f32, + size: impl Into, open: bool, window: &mut Window, cx: &mut Context, @@ -539,7 +561,7 @@ impl DockArea { let weak_self = cx.entity().downgrade(); self.left_dock = Some(cx.new(|cx| { let mut dock = Dock::left(weak_self.clone(), window, cx); - dock.set_ratio(ratio, window, cx); + dock.set_size(size, window, cx); dock.set_panel(panel, window, cx); dock.set_open(open, window, cx); dock @@ -550,7 +572,7 @@ impl DockArea { pub fn set_bottom_dock( &mut self, panel: DockItem, - ratio: f32, + size: impl Into, open: bool, window: &mut Window, cx: &mut Context, @@ -559,7 +581,7 @@ impl DockArea { let weak_self = cx.entity().downgrade(); self.bottom_dock = Some(cx.new(|cx| { let mut dock = Dock::bottom(weak_self.clone(), window, cx); - dock.set_ratio(ratio, window, cx); + dock.set_size(size, window, cx); dock.set_panel(panel, window, cx); dock.set_open(open, window, cx); dock @@ -570,7 +592,7 @@ impl DockArea { pub fn set_right_dock( &mut self, panel: DockItem, - ratio: f32, + size: impl Into, open: bool, window: &mut Window, cx: &mut Context, @@ -579,7 +601,7 @@ impl DockArea { let weak_self = cx.entity().downgrade(); self.right_dock = Some(cx.new(|cx| { let mut dock = Dock::right(weak_self.clone(), window, cx); - dock.set_ratio(ratio, window, cx); + dock.set_size(size, window, cx); dock.set_panel(panel, window, cx); dock.set_open(open, window, cx); dock @@ -723,7 +745,7 @@ impl DockArea { } else { self.set_left_dock( DockItem::tabs(vec![panel], None, &weak_self, window, cx), - 0.2, + relative(0.2), true, window, cx, @@ -736,7 +758,7 @@ impl DockArea { } else { self.set_bottom_dock( DockItem::tabs(vec![panel], None, &weak_self, window, cx), - 0.2, + relative(0.2), true, window, cx, @@ -749,7 +771,7 @@ impl DockArea { } else { self.set_right_dock( DockItem::tabs(vec![panel], None, &weak_self, window, cx), - 0.2, + relative(0.2), true, window, cx, diff --git a/crates/ui/src/dock/state.rs b/crates/ui/src/dock/state.rs index c4e6c17b..d9952d21 100644 --- a/crates/ui/src/dock/state.rs +++ b/crates/ui/src/dock/state.rs @@ -1,4 +1,6 @@ -use gpui::{point, px, size, App, AppContext, Axis, Bounds, Entity, Pixels, WeakEntity, Window}; +use gpui::{ + point, px, relative, size, App, AppContext, Axis, Bounds, Entity, Pixels, WeakEntity, Window, +}; use itertools::Itertools as _; use serde::{Deserialize, Serialize}; @@ -206,7 +208,7 @@ impl PanelState { } else { Axis::Vertical }; - let ratios = ratios.iter().map(|&ratio| Some(ratio)).collect(); + let ratios = ratios.iter().map(|&ratio| Some(relative(ratio))).collect(); DockItem::split_with_sizes(axis, items, ratios, &dock_area, window, cx) } PanelInfo::Tabs { active_index } => { diff --git a/crates/ui/src/dock/tab_panel.rs b/crates/ui/src/dock/tab_panel.rs index bdcb2931..bf3001f0 100644 --- a/crates/ui/src/dock/tab_panel.rs +++ b/crates/ui/src/dock/tab_panel.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use gpui::{ - div, prelude::FluentBuilder, px, rems, App, AppContext, Context, Corner, DefiniteLength, + div, prelude::FluentBuilder, px, relative, rems, App, AppContext, Context, Corner, DismissEvent, DragMoveEvent, Empty, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement as _, IntoElement, ParentElement, Render, ScrollHandle, SharedString, StatefulInteractiveElement, StyleRefinement, Styled, WeakEntity, Window, @@ -823,7 +823,7 @@ impl TabPanel { .bg(cx.theme().drop_target) .map(|this| match self.will_split_placement { Some(placement) => { - let size = DefiniteLength::Fraction(0.35); + let size = relative(0.35); match placement { Placement::Left => this.left_0().top_0().bottom_0().w(size), Placement::Right => {