Fix panel resize when window resized. (#181)

Co-authored-by: Floyd Wang <gassnake999@gmail.com>
This commit is contained in:
Jason Lee 2024-08-28 19:40:35 +08:00 committed by GitHub
parent 237b0f6956
commit 9768755eab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 55 additions and 61 deletions

View file

@ -65,7 +65,7 @@ impl StoryWorkspace {
let stock_panel1 = cx.new_view(|cx| StackPanel::new(Axis::Vertical, cx));
view.add_panel(
stock_panel1.clone(),
Some(px(400.)),
Some(px(380.)),
weak_dock_area.clone(),
cx,
);
@ -307,7 +307,6 @@ impl Render for StoryWorkspace {
.relative()
.size_full()
.flex()
.flex_1()
.flex_col()
.bg(cx.theme().background)
.text_color(cx.theme().foreground)

View file

@ -2,6 +2,7 @@ use crate::{
h_flex,
indicator::Indicator,
theme::{ActiveTheme, Colorize as _},
tooltip::Tooltip,
Disableable, Icon, Selectable, Sizable, Size,
};
use gpui::{
@ -385,6 +386,9 @@ impl RenderOnce for Button {
.children(self.children)
})
.when(self.loading, |this| this.bg(normal_style.bg.opacity(0.8)))
.when_some(self.tooltip.clone(), |this, tooltip| {
this.tooltip(move |cx| Tooltip::new(tooltip.clone(), cx))
})
}
}

View file

@ -43,9 +43,7 @@ impl Render for DockArea {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
div()
.id("dock-area")
.flex()
.flex_grow()
.flex_shrink()
.size_full()
.overflow_hidden()
.map(|this| match self.zoom_view.clone() {
Some(view) => this.bg(cx.theme().tab_bar).p_3().child(

View file

@ -265,8 +265,6 @@ impl Render for StackPanel {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
h_flex()
.size_full()
.flex_grow()
.flex_shrink()
.overflow_hidden()
.bg(cx.theme().tab_bar)
.child(self.panel_group.clone())

View file

@ -14,6 +14,7 @@ use crate::{
popup_menu::PopupMenuExt,
tab::{Tab, TabBar},
theme::ActiveTheme,
tooltip::Tooltip,
v_flex, AxisExt, IconName, Placement, Selectable, Sizable, StyledExt,
};
@ -174,6 +175,7 @@ impl TabPanel {
.icon(IconName::Minimize)
.xsmall()
.ghost()
.tooltip(t!("Dock.Zoom Out"))
.on_click(
cx.listener(|view, _, cx| view.on_action_toggle_zoom(&ToggleZoom, cx)),
),
@ -203,6 +205,7 @@ impl TabPanel {
if self.panels.len() == 1 {
let panel = self.panels.get(0).unwrap();
let title = panel.title(cx);
return h_flex()
.justify_between()
@ -216,8 +219,9 @@ impl TabPanel {
.px_3()
.min_w_16()
.overflow_hidden()
.whitespace_nowrap()
.child(panel.title(cx))
.text_ellipsis()
.child(title.clone())
.tooltip(move |cx| Tooltip::new(title.clone(), cx))
.on_drag(
DragPanel {
panel: panel.clone(),
@ -302,6 +306,7 @@ impl TabPanel {
.id("tab-content")
.group("")
.overflow_y_scroll()
.overflow_x_hidden()
.flex_1()
.child(panel.view())
.on_drag_move(cx.listener(Self::on_panel_drag_move))
@ -500,9 +505,6 @@ impl Render for TabPanel {
.track_focus(&self.focus_handle)
.on_action(cx.listener(Self::on_action_toggle_zoom))
.size_full()
.flex_grow()
.flex_shrink()
.flex_none()
.overflow_hidden()
.bg(cx.theme().background)
.child(self.render_tabs(cx))

View file

@ -472,6 +472,8 @@ where
}
fn toggle_menu(&mut self, _: &ClickEvent, cx: &mut ViewContext<Self>) {
cx.stop_propagation();
self.open = !self.open;
if self.open {
self.list.focus_handle(cx).focus(cx);

View file

@ -3,12 +3,13 @@ use std::rc::Rc;
use gpui::{
canvas, div, prelude::FluentBuilder, px, Along, AnyElement, AnyView, Axis, Bounds, Element,
EntityId, InteractiveElement as _, IntoElement, MouseMoveEvent, MouseUpEvent, ParentElement,
Pixels, Render, Size, StatefulInteractiveElement, Style, Styled, View, ViewContext,
Pixels, Render, StatefulInteractiveElement, Style, Styled, View, ViewContext,
VisualContext as _, WindowContext,
};
use crate::{h_flex, theme::ActiveTheme, v_flex, AxisExt};
const PANEL_MIN_SIZE: Pixels = px(100.);
const HANDLE_PADDING: Pixels = px(4.);
#[derive(Clone, Render)]
@ -20,29 +21,29 @@ pub struct ResizablePanelGroup {
sizes: Vec<Pixels>,
axis: Axis,
handle_size: Pixels,
size: Pixels,
size: Option<Pixels>,
bounds: Bounds<Pixels>,
resizing_panel_ix: Option<usize>,
last_window_size: Size<Pixels>,
}
impl ResizablePanelGroup {
pub(super) fn new(cx: &mut ViewContext<Self>) -> Self {
// Observe the window size to update the bounds of the resizable panel group.
cx.observe_window_bounds(Self::on_window_resize).detach();
pub(super) fn new(_cx: &mut ViewContext<Self>) -> Self {
Self {
axis: Axis::Horizontal,
sizes: Vec::new(),
panels: Vec::new(),
handle_size: px(1.),
size: px(20.),
size: None,
bounds: Bounds::default(),
resizing_panel_ix: None,
last_window_size: cx.bounds().size,
}
}
pub fn load(&mut self, sizes: Vec<Pixels>, panels: Vec<View<ResizablePanel>>) {
self.sizes = sizes;
self.panels = panels;
}
/// Set the axis of the resizable panel group, default is horizontal.
pub fn axis(mut self, axis: Axis) -> Self {
self.axis = axis;
@ -63,19 +64,19 @@ impl ResizablePanelGroup {
}
/// Add a resizable panel to the group.
pub fn child(mut self, panel: ResizablePanel, cx: &mut WindowContext) -> Self {
pub fn child(mut self, panel: ResizablePanel, cx: &mut ViewContext<Self>) -> Self {
self.add_child(panel, cx);
self
}
/// Add a ResizablePanelGroup as a child to the group.
pub fn group(self, group: ResizablePanelGroup, cx: &mut WindowContext) -> Self {
pub fn group(self, group: ResizablePanelGroup, cx: &mut ViewContext<Self>) -> Self {
let mut group: ResizablePanelGroup = group;
group.handle_size = self.handle_size;
let size = group.size;
let panel = ResizablePanel::new()
.content_view(cx.new_view(|_| group).into())
.size(size);
.when_some(size, |this, size| this.size(size));
self.child(panel, cx)
}
@ -84,13 +85,21 @@ impl ResizablePanelGroup {
/// - 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.
pub fn size(mut self, size: Pixels) -> Self {
self.size = size;
self.size = Some(size);
self
}
pub fn add_child(&mut self, panel: ResizablePanel, cx: &mut WindowContext) {
/// When add a child panel to the group, resize other panels each into half of the remaining space.
fn default_panel_size(&self) -> Pixels {
let container_size = self.bounds.size.along(self.axis);
let each_size = container_size / (self.panels.len() + 1) as f32;
each_size.round()
}
pub fn add_child(&mut self, panel: ResizablePanel, cx: &mut ViewContext<Self>) {
let mut panel = panel;
panel.axis = self.axis;
panel.size = self.default_panel_size();
self.sizes.push(panel.size);
self.panels.push(cx.new_view(|_| panel));
}
@ -98,6 +107,7 @@ impl ResizablePanelGroup {
pub fn insert_child(&mut self, panel: ResizablePanel, ix: usize, cx: &mut ViewContext<Self>) {
let mut panel = panel;
panel.axis = self.axis;
panel.size = self.default_panel_size();
self.sizes.insert(ix, panel.size);
self.panels.insert(ix, cx.new_view(|_| panel));
cx.notify()
@ -112,6 +122,7 @@ impl ResizablePanelGroup {
) {
let mut panel = panel;
panel.axis = self.axis;
panel.size = self.default_panel_size();
self.sizes[ix] = panel.size;
self.panels[ix] = cx.new_view(|_| panel);
cx.notify()
@ -129,22 +140,6 @@ impl ResizablePanelGroup {
cx.notify()
}
fn on_window_resize(&mut self, cx: &mut ViewContext<Self>) {
let changed_size = cx.bounds().size - self.last_window_size;
self.last_window_size = cx.bounds().size;
let changed = changed_size.along(self.axis);
// Avg the change in size across all panels.
// The minimum size limited in ResizablePanel.
let avg_change = changed / self.panels.len() as f32;
for (ix, panel) in self.panels.iter().enumerate() {
self.sizes[ix] += avg_change;
panel.update(cx, |this, _| this.size = self.sizes[ix]);
}
cx.notify();
}
fn render_resize_handle(&self, ix: usize, cx: &mut ViewContext<Self>) -> impl IntoElement {
let axis = self.axis;
let neg_offset = -HANDLE_PADDING + px(1.);
@ -253,7 +248,7 @@ impl ResizablePanelGroup {
}
self.sizes = new_sizes;
for (i, panel) in self.panels.iter_mut().enumerate() {
for (i, panel) in self.panels.iter().enumerate() {
let size = self.sizes[i];
panel.update(cx, |this, _| this.size = size);
}
@ -271,15 +266,6 @@ impl Render for ResizablePanelGroup {
container
.size_full()
.flex_grow()
.flex_shrink()
// .map(|this| {
// use crate::StyledExt as _;
// match self.axis {
// Axis::Horizontal => this.debug_red(),
// Axis::Vertical => this.debug_blue(),
// }
// })
.children(self.panels.iter().enumerate().map(|(ix, panel)| {
if ix < self.panels.len() - 1 {
let handle = self.render_resize_handle(ix, cx);
@ -305,8 +291,6 @@ impl Render for ResizablePanelGroup {
}
}
const PANEL_MIN_SIZE: Pixels = px(100.);
pub struct ResizablePanel {
size: Pixels,
axis: Axis,
@ -320,7 +304,7 @@ pub struct ResizablePanel {
impl ResizablePanel {
pub(super) fn new() -> Self {
Self {
size: px(20.),
size: PANEL_MIN_SIZE,
axis: Axis::Horizontal,
content_builder: None,
content_view: None,
@ -353,18 +337,24 @@ impl FluentBuilder for ResizablePanel {}
impl Render for ResizablePanel {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let view = cx.view().clone();
let axis = self.axis;
let size = self.size.max(PANEL_MIN_SIZE);
div()
.relative()
.size_full()
.flex()
.flex_grow()
.flex_shrink()
.when(self.axis.is_vertical(), |this| this.h(size))
.when(self.axis.is_horizontal(), |this| this.w(size))
.relative()
.overflow_hidden()
.when(self.axis.is_vertical(), |this| this.w_full().h(size))
.when(self.axis.is_horizontal(), |this| this.h_full().w(size))
.child({
canvas(
move |bounds, cx| view.update(cx, |r, _| r.bounds = bounds),
move |bounds, cx| {
view.update(cx, |r, _| {
r.size = bounds.size.along(axis);
r.bounds = bounds;
})
},
|_, _, _| {},
)
.absolute()

View file

@ -75,6 +75,7 @@ impl RenderOnce for Tab {
.items_center()
.flex_shrink_0()
.cursor_pointer()
.overflow_hidden()
.text_color(text_color)
.bg(bg_color)
.border_x_1()