Fix panel resize when window resized. (#181)
Co-authored-by: Floyd Wang <gassnake999@gmail.com>
This commit is contained in:
parent
237b0f6956
commit
9768755eab
8 changed files with 55 additions and 61 deletions
|
|
@ -65,7 +65,7 @@ impl StoryWorkspace {
|
||||||
let stock_panel1 = cx.new_view(|cx| StackPanel::new(Axis::Vertical, cx));
|
let stock_panel1 = cx.new_view(|cx| StackPanel::new(Axis::Vertical, cx));
|
||||||
view.add_panel(
|
view.add_panel(
|
||||||
stock_panel1.clone(),
|
stock_panel1.clone(),
|
||||||
Some(px(400.)),
|
Some(px(380.)),
|
||||||
weak_dock_area.clone(),
|
weak_dock_area.clone(),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
@ -307,7 +307,6 @@ impl Render for StoryWorkspace {
|
||||||
.relative()
|
.relative()
|
||||||
.size_full()
|
.size_full()
|
||||||
.flex()
|
.flex()
|
||||||
.flex_1()
|
|
||||||
.flex_col()
|
.flex_col()
|
||||||
.bg(cx.theme().background)
|
.bg(cx.theme().background)
|
||||||
.text_color(cx.theme().foreground)
|
.text_color(cx.theme().foreground)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use crate::{
|
||||||
h_flex,
|
h_flex,
|
||||||
indicator::Indicator,
|
indicator::Indicator,
|
||||||
theme::{ActiveTheme, Colorize as _},
|
theme::{ActiveTheme, Colorize as _},
|
||||||
|
tooltip::Tooltip,
|
||||||
Disableable, Icon, Selectable, Sizable, Size,
|
Disableable, Icon, Selectable, Sizable, Size,
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
|
|
@ -385,6 +386,9 @@ impl RenderOnce for Button {
|
||||||
.children(self.children)
|
.children(self.children)
|
||||||
})
|
})
|
||||||
.when(self.loading, |this| this.bg(normal_style.bg.opacity(0.8)))
|
.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))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,7 @@ impl Render for DockArea {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
div()
|
div()
|
||||||
.id("dock-area")
|
.id("dock-area")
|
||||||
.flex()
|
.size_full()
|
||||||
.flex_grow()
|
|
||||||
.flex_shrink()
|
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
.map(|this| match self.zoom_view.clone() {
|
.map(|this| match self.zoom_view.clone() {
|
||||||
Some(view) => this.bg(cx.theme().tab_bar).p_3().child(
|
Some(view) => this.bg(cx.theme().tab_bar).p_3().child(
|
||||||
|
|
|
||||||
|
|
@ -265,8 +265,6 @@ impl Render for StackPanel {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
h_flex()
|
h_flex()
|
||||||
.size_full()
|
.size_full()
|
||||||
.flex_grow()
|
|
||||||
.flex_shrink()
|
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
.bg(cx.theme().tab_bar)
|
.bg(cx.theme().tab_bar)
|
||||||
.child(self.panel_group.clone())
|
.child(self.panel_group.clone())
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ use crate::{
|
||||||
popup_menu::PopupMenuExt,
|
popup_menu::PopupMenuExt,
|
||||||
tab::{Tab, TabBar},
|
tab::{Tab, TabBar},
|
||||||
theme::ActiveTheme,
|
theme::ActiveTheme,
|
||||||
|
tooltip::Tooltip,
|
||||||
v_flex, AxisExt, IconName, Placement, Selectable, Sizable, StyledExt,
|
v_flex, AxisExt, IconName, Placement, Selectable, Sizable, StyledExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -174,6 +175,7 @@ impl TabPanel {
|
||||||
.icon(IconName::Minimize)
|
.icon(IconName::Minimize)
|
||||||
.xsmall()
|
.xsmall()
|
||||||
.ghost()
|
.ghost()
|
||||||
|
.tooltip(t!("Dock.Zoom Out"))
|
||||||
.on_click(
|
.on_click(
|
||||||
cx.listener(|view, _, cx| view.on_action_toggle_zoom(&ToggleZoom, cx)),
|
cx.listener(|view, _, cx| view.on_action_toggle_zoom(&ToggleZoom, cx)),
|
||||||
),
|
),
|
||||||
|
|
@ -203,6 +205,7 @@ impl TabPanel {
|
||||||
|
|
||||||
if self.panels.len() == 1 {
|
if self.panels.len() == 1 {
|
||||||
let panel = self.panels.get(0).unwrap();
|
let panel = self.panels.get(0).unwrap();
|
||||||
|
let title = panel.title(cx);
|
||||||
|
|
||||||
return h_flex()
|
return h_flex()
|
||||||
.justify_between()
|
.justify_between()
|
||||||
|
|
@ -216,8 +219,9 @@ impl TabPanel {
|
||||||
.px_3()
|
.px_3()
|
||||||
.min_w_16()
|
.min_w_16()
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
.whitespace_nowrap()
|
.text_ellipsis()
|
||||||
.child(panel.title(cx))
|
.child(title.clone())
|
||||||
|
.tooltip(move |cx| Tooltip::new(title.clone(), cx))
|
||||||
.on_drag(
|
.on_drag(
|
||||||
DragPanel {
|
DragPanel {
|
||||||
panel: panel.clone(),
|
panel: panel.clone(),
|
||||||
|
|
@ -302,6 +306,7 @@ impl TabPanel {
|
||||||
.id("tab-content")
|
.id("tab-content")
|
||||||
.group("")
|
.group("")
|
||||||
.overflow_y_scroll()
|
.overflow_y_scroll()
|
||||||
|
.overflow_x_hidden()
|
||||||
.flex_1()
|
.flex_1()
|
||||||
.child(panel.view())
|
.child(panel.view())
|
||||||
.on_drag_move(cx.listener(Self::on_panel_drag_move))
|
.on_drag_move(cx.listener(Self::on_panel_drag_move))
|
||||||
|
|
@ -500,9 +505,6 @@ impl Render for TabPanel {
|
||||||
.track_focus(&self.focus_handle)
|
.track_focus(&self.focus_handle)
|
||||||
.on_action(cx.listener(Self::on_action_toggle_zoom))
|
.on_action(cx.listener(Self::on_action_toggle_zoom))
|
||||||
.size_full()
|
.size_full()
|
||||||
.flex_grow()
|
|
||||||
.flex_shrink()
|
|
||||||
.flex_none()
|
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
.bg(cx.theme().background)
|
.bg(cx.theme().background)
|
||||||
.child(self.render_tabs(cx))
|
.child(self.render_tabs(cx))
|
||||||
|
|
|
||||||
|
|
@ -472,6 +472,8 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toggle_menu(&mut self, _: &ClickEvent, cx: &mut ViewContext<Self>) {
|
fn toggle_menu(&mut self, _: &ClickEvent, cx: &mut ViewContext<Self>) {
|
||||||
|
cx.stop_propagation();
|
||||||
|
|
||||||
self.open = !self.open;
|
self.open = !self.open;
|
||||||
if self.open {
|
if self.open {
|
||||||
self.list.focus_handle(cx).focus(cx);
|
self.list.focus_handle(cx).focus(cx);
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,13 @@ use std::rc::Rc;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
canvas, div, prelude::FluentBuilder, px, Along, AnyElement, AnyView, Axis, Bounds, Element,
|
canvas, div, prelude::FluentBuilder, px, Along, AnyElement, AnyView, Axis, Bounds, Element,
|
||||||
EntityId, InteractiveElement as _, IntoElement, MouseMoveEvent, MouseUpEvent, ParentElement,
|
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,
|
VisualContext as _, WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{h_flex, theme::ActiveTheme, v_flex, AxisExt};
|
use crate::{h_flex, theme::ActiveTheme, v_flex, AxisExt};
|
||||||
|
|
||||||
|
const PANEL_MIN_SIZE: Pixels = px(100.);
|
||||||
const HANDLE_PADDING: Pixels = px(4.);
|
const HANDLE_PADDING: Pixels = px(4.);
|
||||||
|
|
||||||
#[derive(Clone, Render)]
|
#[derive(Clone, Render)]
|
||||||
|
|
@ -20,29 +21,29 @@ pub struct ResizablePanelGroup {
|
||||||
sizes: Vec<Pixels>,
|
sizes: Vec<Pixels>,
|
||||||
axis: Axis,
|
axis: Axis,
|
||||||
handle_size: Pixels,
|
handle_size: Pixels,
|
||||||
size: Pixels,
|
size: Option<Pixels>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
resizing_panel_ix: Option<usize>,
|
resizing_panel_ix: Option<usize>,
|
||||||
last_window_size: Size<Pixels>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResizablePanelGroup {
|
impl ResizablePanelGroup {
|
||||||
pub(super) fn new(cx: &mut ViewContext<Self>) -> Self {
|
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();
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
axis: Axis::Horizontal,
|
axis: Axis::Horizontal,
|
||||||
sizes: Vec::new(),
|
sizes: Vec::new(),
|
||||||
panels: Vec::new(),
|
panels: Vec::new(),
|
||||||
handle_size: px(1.),
|
handle_size: px(1.),
|
||||||
size: px(20.),
|
size: None,
|
||||||
bounds: Bounds::default(),
|
bounds: Bounds::default(),
|
||||||
resizing_panel_ix: None,
|
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.
|
/// Set the axis of the resizable panel group, default is horizontal.
|
||||||
pub fn axis(mut self, axis: Axis) -> Self {
|
pub fn axis(mut self, axis: Axis) -> Self {
|
||||||
self.axis = axis;
|
self.axis = axis;
|
||||||
|
|
@ -63,19 +64,19 @@ impl ResizablePanelGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a resizable panel to the group.
|
/// 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_child(panel, cx);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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 WindowContext) -> Self {
|
pub fn group(self, group: ResizablePanelGroup, cx: &mut ViewContext<Self>) -> Self {
|
||||||
let mut group: ResizablePanelGroup = group;
|
let mut group: ResizablePanelGroup = group;
|
||||||
group.handle_size = self.handle_size;
|
group.handle_size = self.handle_size;
|
||||||
let size = group.size;
|
let size = group.size;
|
||||||
let panel = ResizablePanel::new()
|
let panel = ResizablePanel::new()
|
||||||
.content_view(cx.new_view(|_| group).into())
|
.content_view(cx.new_view(|_| group).into())
|
||||||
.size(size);
|
.when_some(size, |this, size| this.size(size));
|
||||||
self.child(panel, cx)
|
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 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 size(mut self, size: Pixels) -> Self {
|
||||||
self.size = size;
|
self.size = Some(size);
|
||||||
self
|
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;
|
let mut panel = panel;
|
||||||
panel.axis = self.axis;
|
panel.axis = self.axis;
|
||||||
|
panel.size = self.default_panel_size();
|
||||||
self.sizes.push(panel.size);
|
self.sizes.push(panel.size);
|
||||||
self.panels.push(cx.new_view(|_| panel));
|
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>) {
|
pub fn insert_child(&mut self, panel: ResizablePanel, ix: usize, cx: &mut ViewContext<Self>) {
|
||||||
let mut panel = panel;
|
let mut panel = panel;
|
||||||
panel.axis = self.axis;
|
panel.axis = self.axis;
|
||||||
|
panel.size = self.default_panel_size();
|
||||||
self.sizes.insert(ix, panel.size);
|
self.sizes.insert(ix, panel.size);
|
||||||
self.panels.insert(ix, cx.new_view(|_| panel));
|
self.panels.insert(ix, cx.new_view(|_| panel));
|
||||||
cx.notify()
|
cx.notify()
|
||||||
|
|
@ -112,6 +122,7 @@ impl ResizablePanelGroup {
|
||||||
) {
|
) {
|
||||||
let mut panel = panel;
|
let mut panel = panel;
|
||||||
panel.axis = self.axis;
|
panel.axis = self.axis;
|
||||||
|
panel.size = self.default_panel_size();
|
||||||
self.sizes[ix] = panel.size;
|
self.sizes[ix] = panel.size;
|
||||||
self.panels[ix] = cx.new_view(|_| panel);
|
self.panels[ix] = cx.new_view(|_| panel);
|
||||||
cx.notify()
|
cx.notify()
|
||||||
|
|
@ -129,22 +140,6 @@ impl ResizablePanelGroup {
|
||||||
cx.notify()
|
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 {
|
fn render_resize_handle(&self, ix: usize, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
let axis = self.axis;
|
let axis = self.axis;
|
||||||
let neg_offset = -HANDLE_PADDING + px(1.);
|
let neg_offset = -HANDLE_PADDING + px(1.);
|
||||||
|
|
@ -253,7 +248,7 @@ impl ResizablePanelGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.sizes = new_sizes;
|
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];
|
let size = self.sizes[i];
|
||||||
panel.update(cx, |this, _| this.size = size);
|
panel.update(cx, |this, _| this.size = size);
|
||||||
}
|
}
|
||||||
|
|
@ -271,15 +266,6 @@ impl Render for ResizablePanelGroup {
|
||||||
|
|
||||||
container
|
container
|
||||||
.size_full()
|
.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)| {
|
.children(self.panels.iter().enumerate().map(|(ix, panel)| {
|
||||||
if ix < self.panels.len() - 1 {
|
if ix < self.panels.len() - 1 {
|
||||||
let handle = self.render_resize_handle(ix, cx);
|
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 {
|
pub struct ResizablePanel {
|
||||||
size: Pixels,
|
size: Pixels,
|
||||||
axis: Axis,
|
axis: Axis,
|
||||||
|
|
@ -320,7 +304,7 @@ pub struct ResizablePanel {
|
||||||
impl ResizablePanel {
|
impl ResizablePanel {
|
||||||
pub(super) fn new() -> Self {
|
pub(super) fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
size: px(20.),
|
size: PANEL_MIN_SIZE,
|
||||||
axis: Axis::Horizontal,
|
axis: Axis::Horizontal,
|
||||||
content_builder: None,
|
content_builder: None,
|
||||||
content_view: None,
|
content_view: None,
|
||||||
|
|
@ -353,18 +337,24 @@ impl FluentBuilder for ResizablePanel {}
|
||||||
impl Render for ResizablePanel {
|
impl Render for ResizablePanel {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
let view = cx.view().clone();
|
let view = cx.view().clone();
|
||||||
|
let axis = self.axis;
|
||||||
let size = self.size.max(PANEL_MIN_SIZE);
|
let size = self.size.max(PANEL_MIN_SIZE);
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.relative()
|
.flex()
|
||||||
.size_full()
|
|
||||||
.flex_grow()
|
.flex_grow()
|
||||||
.flex_shrink()
|
.relative()
|
||||||
.when(self.axis.is_vertical(), |this| this.h(size))
|
.overflow_hidden()
|
||||||
.when(self.axis.is_horizontal(), |this| this.w(size))
|
.when(self.axis.is_vertical(), |this| this.w_full().h(size))
|
||||||
|
.when(self.axis.is_horizontal(), |this| this.h_full().w(size))
|
||||||
.child({
|
.child({
|
||||||
canvas(
|
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()
|
.absolute()
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ impl RenderOnce for Tab {
|
||||||
.items_center()
|
.items_center()
|
||||||
.flex_shrink_0()
|
.flex_shrink_0()
|
||||||
.cursor_pointer()
|
.cursor_pointer()
|
||||||
|
.overflow_hidden()
|
||||||
.text_color(text_color)
|
.text_color(text_color)
|
||||||
.bg(bg_color)
|
.bg(bg_color)
|
||||||
.border_x_1()
|
.border_x_1()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue