dock: Improve dock, panel to support absolute or fraction size. (#839)

This commit is contained in:
Jason Lee 2025-05-08 12:01:16 +08:00 committed by GitHub
parent 4aaaaa2d91
commit a26311dc0e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 56 additions and 27 deletions

View file

@ -279,7 +279,7 @@ impl StoryWorkspace {
cx, cx,
), ),
], ],
vec![None, Some(0.2)], vec![None, Some(relative(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, 0.3, true, window, cx); view.set_left_dock(left_panels, relative(0.3), true, window, cx);
view.set_bottom_dock(bottom_panels, 0.2, true, window, cx); view.set_bottom_dock(bottom_panels, relative(0.2), true, window, cx);
view.set_right_dock(right_panels, 0.3, true, window, cx); view.set_right_dock(right_panels, px(320.), true, window, cx);
Self::save_state(&view.dump(cx)).unwrap(); Self::save_state(&view.dump(cx)).unwrap();
}); });

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, Along, App, AppContext, Axis, Context, Element, Empty, div, prelude::FluentBuilder as _, px, Along, App, AppContext, Axis, Context, DefiniteLength,
Entity, IntoElement, MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, Point, Render, Element, Empty, Entity, IntoElement, MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels,
Style, StyleRefinement, Styled as _, WeakEntity, Window, Point, Render, Style, StyleRefinement, Styled as _, WeakEntity, Window,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -14,7 +14,7 @@ use crate::{
StyledExt, StyledExt,
}; };
use super::{DockArea, DockItem, PanelView, TabPanel}; use super::{definite_length_to_window_ratio, DockArea, DockItem, PanelView, TabPanel};
#[derive(Clone)] #[derive(Clone)]
struct ResizePanel; struct ResizePanel;
@ -249,8 +249,13 @@ impl Dock {
} }
/// Set the size of the Dock. /// Set the size of the Dock.
pub fn set_ratio(&mut self, ratio: f32, _: &mut Window, cx: &mut Context<Self>) { pub fn set_size(
self.ratio = ratio; &mut self,
size: impl Into<DefiniteLength>,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.ratio = definite_length_to_window_ratio(size, self.placement.axis(), window);
cx.notify(); cx.notify();
} }

View file

@ -8,9 +8,10 @@ mod tiles;
use anyhow::Result; use anyhow::Result;
use gpui::{ use gpui::{
actions, canvas, div, prelude::FluentBuilder, AnyElement, AnyView, App, AppContext, Axis, actions, canvas, div, prelude::FluentBuilder, relative, Along, AnyElement, AnyView, App,
Bounds, Context, Edges, Entity, EntityId, EventEmitter, InteractiveElement as _, IntoElement, AppContext, Axis, Bounds, Context, DefiniteLength, Edges, Entity, EntityId, EventEmitter,
ParentElement as _, Pixels, Render, SharedString, Styled, Subscription, WeakEntity, Window, InteractiveElement as _, IntoElement, ParentElement as _, Pixels, Render, SharedString, Styled,
Subscription, WeakEntity, Window,
}; };
use std::sync::Arc; use std::sync::Arc;
@ -27,6 +28,22 @@ pub fn init(cx: &mut App) {
actions!(dock, [ToggleZoom, ClosePanel]); actions!(dock, [ToggleZoom, ClosePanel]);
/// Convert [`gpui::DefiniteLength`] to ratio of window.
pub(crate) fn definite_length_to_window_ratio(
length: impl Into<DefiniteLength>,
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 { pub enum DockEvent {
/// The layout of the dock has changed, subscribers this to save the layout. /// The layout of the dock has changed, subscribers this to save the layout.
/// ///
@ -143,12 +160,17 @@ impl DockItem {
pub fn split_with_sizes( pub fn split_with_sizes(
axis: Axis, axis: Axis,
items: Vec<DockItem>, items: Vec<DockItem>,
ratios: Vec<Option<f32>>, sizes: Vec<Option<DefiniteLength>>,
dock_area: &WeakEntity<DockArea>, dock_area: &WeakEntity<DockArea>,
window: &mut Window, window: &mut Window,
cx: &mut App, cx: &mut App,
) -> Self { ) -> Self {
let mut items = items; let mut items = items;
let ratios: Vec<Option<f32>> = sizes
.into_iter()
.map(|size| size.map(|val| definite_length_to_window_ratio(val, axis, window)))
.collect();
let stack_panel = cx.new(|cx| { let stack_panel = cx.new(|cx| {
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() {
@ -530,7 +552,7 @@ impl DockArea {
pub fn set_left_dock( pub fn set_left_dock(
&mut self, &mut self,
panel: DockItem, panel: DockItem,
ratio: f32, size: impl Into<DefiniteLength>,
open: bool, open: bool,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@ -539,7 +561,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);
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
@ -550,7 +572,7 @@ impl DockArea {
pub fn set_bottom_dock( pub fn set_bottom_dock(
&mut self, &mut self,
panel: DockItem, panel: DockItem,
ratio: f32, size: impl Into<DefiniteLength>,
open: bool, open: bool,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@ -559,7 +581,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);
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
@ -570,7 +592,7 @@ impl DockArea {
pub fn set_right_dock( pub fn set_right_dock(
&mut self, &mut self,
panel: DockItem, panel: DockItem,
ratio: f32, size: impl Into<DefiniteLength>,
open: bool, open: bool,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@ -579,7 +601,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);
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
@ -723,7 +745,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),
0.2, relative(0.2),
true, true,
window, window,
cx, cx,
@ -736,7 +758,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),
0.2, relative(0.2),
true, true,
window, window,
cx, cx,
@ -749,7 +771,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),
0.2, relative(0.2),
true, true,
window, window,
cx, cx,

View file

@ -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 itertools::Itertools as _;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -206,7 +208,7 @@ impl PanelState {
} else { } else {
Axis::Vertical 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) DockItem::split_with_sizes(axis, items, ratios, &dock_area, window, cx)
} }
PanelInfo::Tabs { active_index } => { PanelInfo::Tabs { active_index } => {

View file

@ -1,7 +1,7 @@
use std::sync::Arc; use std::sync::Arc;
use gpui::{ 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, DismissEvent, DragMoveEvent, Empty, Entity, EventEmitter, FocusHandle, Focusable,
InteractiveElement as _, IntoElement, ParentElement, Render, ScrollHandle, SharedString, InteractiveElement as _, IntoElement, ParentElement, Render, ScrollHandle, SharedString,
StatefulInteractiveElement, StyleRefinement, Styled, WeakEntity, Window, StatefulInteractiveElement, StyleRefinement, Styled, WeakEntity, Window,
@ -823,7 +823,7 @@ impl TabPanel {
.bg(cx.theme().drop_target) .bg(cx.theme().drop_target)
.map(|this| match self.will_split_placement { .map(|this| match self.will_split_placement {
Some(placement) => { Some(placement) => {
let size = DefiniteLength::Fraction(0.35); let size = relative(0.35);
match placement { match placement {
Placement::Left => this.left_0().top_0().bottom_0().w(size), Placement::Left => this.left_0().top_0().bottom_0().w(size),
Placement::Right => { Placement::Right => {