1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-02 06:40:06 -04:00

Add support for calling ui.close() within animating panel

This commit is contained in:
Emil Ernerfeldt
2025-06-18 19:29:37 -07:00
parent 5a5235dab0
commit bd97a93643

View File

@@ -223,13 +223,14 @@ impl SidePanel {
ui: &mut Ui, ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
self.show_inside_dyn(ui, Box::new(add_contents)) self.show_inside_dyn(ui, false, Box::new(add_contents))
} }
/// Show the panel inside a [`Ui`]. /// Show the panel inside a [`Ui`].
fn show_inside_dyn<'c, R>( fn show_inside_dyn<'c, R>(
self, self,
ui: &mut Ui, ui: &mut Ui,
closable: bool,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>, add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
let Self { let Self {
@@ -257,6 +258,7 @@ impl SidePanel {
let resize_id = id.with("__resize"); let resize_id = id.with("__resize");
let mut resize_hover = false; let mut resize_hover = false;
let mut is_resizing = false; let mut is_resizing = false;
let mut drag_to_close = false;
if resizable { if resizable {
// First we read the resize interaction results, to avoid frame latency in the resize: // First we read the resize interaction results, to avoid frame latency in the resize:
if let Some(resize_response) = ui.ctx().read_response(resize_id) { if let Some(resize_response) = ui.ctx().read_response(resize_id) {
@@ -265,9 +267,15 @@ impl SidePanel {
if is_resizing { if is_resizing {
if let Some(pointer) = resize_response.interact_pointer_pos() { if let Some(pointer) = resize_response.interact_pointer_pos() {
let old_width = width;
width = (pointer.x - side.side_x(panel_rect)).abs(); width = (pointer.x - side.side_x(panel_rect)).abs();
width = clamp_to_range(width, width_range).at_most(available_rect.width()); width = clamp_to_range(width, width_range).at_most(available_rect.width());
side.set_rect_width(&mut panel_rect, width); side.set_rect_width(&mut panel_rect, width);
if closable && width <= width_range.min && width < old_width {
drag_to_close = true;
}
} }
} }
} }
@@ -283,13 +291,14 @@ impl SidePanel {
Side::Right => UiKind::RightPanel, Side::Right => UiKind::RightPanel,
})) }))
.max_rect(panel_rect) .max_rect(panel_rect)
.layout(Layout::top_down(Align::Min)), .layout(Layout::top_down(Align::Min))
.with_closable(closable),
); );
panel_ui.expand_to_include_rect(panel_rect); panel_ui.expand_to_include_rect(panel_rect);
panel_ui.set_clip_rect(panel_rect); // If we overflow, don't do so visibly (#4475) panel_ui.set_clip_rect(panel_rect); // If we overflow, don't do so visibly (#4475)
let frame = frame.unwrap_or_else(|| Frame::side_top_panel(ui.style())); let frame = frame.unwrap_or_else(|| Frame::side_top_panel(ui.style()));
let inner_response = frame.show(&mut panel_ui, |ui| { let mut inner_response = frame.show(&mut panel_ui, |ui| {
ui.set_min_height(ui.max_rect().height()); // Make sure the frame fills the full height ui.set_min_height(ui.max_rect().height()); // Make sure the frame fills the full height
ui.set_min_width((width_range.min - frame.inner_margin.sum().x).at_least(0.0)); ui.set_min_width((width_range.min - frame.inner_margin.sum().x).at_least(0.0));
add_contents(ui) add_contents(ui)
@@ -361,6 +370,10 @@ impl SidePanel {
ui.painter().vline(resize_x, panel_rect.y_range(), stroke); ui.painter().vline(resize_x, panel_rect.y_range(), stroke);
} }
if panel_ui.should_close() || drag_to_close {
inner_response.response.set_close();
}
inner_response inner_response
} }
@@ -370,13 +383,14 @@ impl SidePanel {
ctx: &Context, ctx: &Context,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
self.show_dyn(ctx, Box::new(add_contents)) self.show_dyn(ctx, false, Box::new(add_contents))
} }
/// Show the panel at the top level. /// Show the panel at the top level.
fn show_dyn<'c, R>( fn show_dyn<'c, R>(
self, self,
ctx: &Context, ctx: &Context,
closable: bool,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>, add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
let side = self.side; let side = self.side;
@@ -390,7 +404,7 @@ impl SidePanel {
); );
panel_ui.set_clip_rect(ctx.screen_rect()); panel_ui.set_clip_rect(ctx.screen_rect());
let inner_response = self.show_inside_dyn(&mut panel_ui, add_contents); let inner_response = self.show_inside_dyn(&mut panel_ui, closable, add_contents);
let rect = inner_response.response.rect; let rect = inner_response.response.rect;
match side { match side {
@@ -433,7 +447,8 @@ impl SidePanel {
None None
} else { } else {
// Show the real panel: // Show the real panel:
Some(self.show(ctx, add_contents)) let closable = true;
Some(self.show_dyn(ctx, closable, Box::new(add_contents)))
} }
} }
@@ -466,7 +481,8 @@ impl SidePanel {
None None
} else { } else {
// Show the real panel: // Show the real panel:
Some(self.show_inside(ui, add_contents)) let closable = true;
Some(self.show_inside_dyn(ui, closable, Box::new(add_contents)))
} }
} }
@@ -713,13 +729,14 @@ impl TopBottomPanel {
ui: &mut Ui, ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
self.show_inside_dyn(ui, Box::new(add_contents)) self.show_inside_dyn(ui, false, Box::new(add_contents))
} }
/// Show the panel inside a [`Ui`]. /// Show the panel inside a [`Ui`].
fn show_inside_dyn<'c, R>( fn show_inside_dyn<'c, R>(
self, self,
ui: &mut Ui, ui: &mut Ui,
closable: bool,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>, add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
let Self { let Self {
@@ -753,6 +770,7 @@ impl TopBottomPanel {
let resize_id = id.with("__resize"); let resize_id = id.with("__resize");
let mut resize_hover = false; let mut resize_hover = false;
let mut is_resizing = false; let mut is_resizing = false;
let mut drag_to_close = false;
if resizable { if resizable {
// First we read the resize interaction results, to avoid frame latency in the resize: // First we read the resize interaction results, to avoid frame latency in the resize:
if let Some(resize_response) = ui.ctx().read_response(resize_id) { if let Some(resize_response) = ui.ctx().read_response(resize_id) {
@@ -761,10 +779,16 @@ impl TopBottomPanel {
if is_resizing { if is_resizing {
if let Some(pointer) = resize_response.interact_pointer_pos() { if let Some(pointer) = resize_response.interact_pointer_pos() {
let old_height = height;
height = (pointer.y - side.side_y(panel_rect)).abs(); height = (pointer.y - side.side_y(panel_rect)).abs();
height = height =
clamp_to_range(height, height_range).at_most(available_rect.height()); clamp_to_range(height, height_range).at_most(available_rect.height());
side.set_rect_height(&mut panel_rect, height); side.set_rect_height(&mut panel_rect, height);
if closable && height <= height_range.min && height < old_height {
drag_to_close = true;
}
} }
} }
} }
@@ -780,12 +804,13 @@ impl TopBottomPanel {
TopBottomSide::Bottom => UiKind::BottomPanel, TopBottomSide::Bottom => UiKind::BottomPanel,
})) }))
.max_rect(panel_rect) .max_rect(panel_rect)
.layout(Layout::top_down(Align::Min)), .layout(Layout::top_down(Align::Min))
.with_closable(closable),
); );
panel_ui.expand_to_include_rect(panel_rect); panel_ui.expand_to_include_rect(panel_rect);
panel_ui.set_clip_rect(panel_rect); // If we overflow, don't do so visibly (#4475) panel_ui.set_clip_rect(panel_rect); // If we overflow, don't do so visibly (#4475)
let inner_response = frame.show(&mut panel_ui, |ui| { let mut inner_response = frame.show(&mut panel_ui, |ui| {
ui.set_min_width(ui.max_rect().width()); // Make the frame fill full width ui.set_min_width(ui.max_rect().width()); // Make the frame fill full width
ui.set_min_height((height_range.min - frame.inner_margin.sum().y).at_least(0.0)); ui.set_min_height((height_range.min - frame.inner_margin.sum().y).at_least(0.0));
add_contents(ui) add_contents(ui)
@@ -858,6 +883,10 @@ impl TopBottomPanel {
ui.painter().hline(panel_rect.x_range(), resize_y, stroke); ui.painter().hline(panel_rect.x_range(), resize_y, stroke);
} }
if panel_ui.should_close() || drag_to_close {
inner_response.response.set_close();
}
inner_response inner_response
} }
@@ -867,13 +896,14 @@ impl TopBottomPanel {
ctx: &Context, ctx: &Context,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
self.show_dyn(ctx, Box::new(add_contents)) self.show_dyn(ctx, false, Box::new(add_contents))
} }
/// Show the panel at the top level. /// Show the panel at the top level.
fn show_dyn<'c, R>( fn show_dyn<'c, R>(
self, self,
ctx: &Context, ctx: &Context,
closable: bool,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>, add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
let available_rect = ctx.available_rect(); let available_rect = ctx.available_rect();
@@ -888,7 +918,7 @@ impl TopBottomPanel {
); );
panel_ui.set_clip_rect(ctx.screen_rect()); panel_ui.set_clip_rect(ctx.screen_rect());
let inner_response = self.show_inside_dyn(&mut panel_ui, add_contents); let inner_response = self.show_inside_dyn(&mut panel_ui, closable, add_contents);
let rect = inner_response.response.rect; let rect = inner_response.response.rect;
match side { match side {
@@ -973,7 +1003,8 @@ impl TopBottomPanel {
None None
} else { } else {
// Show the real panel: // Show the real panel:
Some(self.show_inside(ui, add_contents)) let closable = true;
Some(self.show_inside_dyn(ui, closable, Box::new(add_contents)))
} }
} }