1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-29 04:40:03 -04:00

Add Panel to replace SidePanel and TopBottomPanel (#5659)

This combines `SidePanel` and `TopBottomPanel` into a single `Panel`.

The old types are still there as type aliases, but are deprecated.

`.min_width(…)` etc are now called `.min_size(…)` etc.

Again, the old names are still there, but deprecated.

(edited by @emilk)

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
Bruno Paré-Simard
2025-11-18 09:46:01 -05:00
committed by GitHub
parent 178f3c9198
commit 5b6a0196f9
20 changed files with 695 additions and 795 deletions

View File

@@ -137,7 +137,7 @@ impl CreationContext<'_> {
pub trait App { pub trait App {
/// Called each time the UI needs repainting, which may be many times per second. /// Called each time the UI needs repainting, which may be many times per second.
/// ///
/// Put your widgets into a [`egui::SidePanel`], [`egui::TopBottomPanel`], [`egui::CentralPanel`], [`egui::Window`] or [`egui::Area`]. /// Put your widgets into a [`egui::Panel`], [`egui::CentralPanel`], [`egui::Window`] or [`egui::Area`].
/// ///
/// The [`egui::Context`] can be cloned and saved if you like. /// The [`egui::Context`] can be cloned and saved if you like.
/// ///

View File

@@ -1,4 +1,4 @@
//! Containers are pieces of the UI which wraps other pieces of UI. Examples: [`Window`], [`ScrollArea`], [`Resize`], [`SidePanel`], etc. //! Containers are pieces of the UI which wraps other pieces of UI. Examples: [`Window`], [`ScrollArea`], [`Resize`], [`Panel`], etc.
//! //!
//! For instance, a [`Frame`] adds a frame and background to some contained UI. //! For instance, a [`Frame`] adds a frame and background to some contained UI.
@@ -27,7 +27,7 @@ pub use {
frame::Frame, frame::Frame,
modal::{Modal, ModalResponse}, modal::{Modal, ModalResponse},
old_popup::*, old_popup::*,
panel::{CentralPanel, SidePanel, TopBottomPanel}, panel::*,
popup::*, popup::*,
resize::Resize, resize::Resize,
scene::{DragPanButtons, Scene}, scene::{DragPanButtons, Scene},

File diff suppressed because it is too large Load Diff

View File

@@ -764,7 +764,7 @@ impl Context {
/// and only on the rare occasion that [`Context::request_discard`] is called. /// and only on the rare occasion that [`Context::request_discard`] is called.
/// Usually, it `run_ui` will only be called once. /// Usually, it `run_ui` will only be called once.
/// ///
/// Put your widgets into a [`crate::SidePanel`], [`crate::TopBottomPanel`], [`crate::CentralPanel`], [`crate::Window`] or [`crate::Area`]. /// Put your widgets into a [`crate::Panel`], [`crate::CentralPanel`], [`crate::Window`] or [`crate::Area`].
/// ///
/// Instead of calling `run`, you can alternatively use [`Self::begin_pass`] and [`Context::end_pass`]. /// Instead of calling `run`, you can alternatively use [`Self::begin_pass`] and [`Context::end_pass`].
/// ///

View File

@@ -9,7 +9,7 @@
//! which uses [`eframe`](https://docs.rs/eframe). //! which uses [`eframe`](https://docs.rs/eframe).
//! //!
//! To create a GUI using egui you first need a [`Context`] (by convention referred to by `ctx`). //! To create a GUI using egui you first need a [`Context`] (by convention referred to by `ctx`).
//! Then you add a [`Window`] or a [`SidePanel`] to get a [`Ui`], which is what you'll be using to add all the buttons and labels that you need. //! Then you add a [`Window`] or a [`Panel`] to get a [`Ui`], which is what you'll be using to add all the buttons and labels that you need.
//! //!
//! //!
//! ## Feature flags //! ## Feature flags
@@ -45,7 +45,7 @@
//! //!
//! ### Getting a [`Ui`] //! ### Getting a [`Ui`]
//! //!
//! Use one of [`SidePanel`], [`TopBottomPanel`], [`CentralPanel`], [`Window`] or [`Area`] to //! Use one of [`Panel`], [`CentralPanel`], [`Window`] or [`Area`] to
//! get access to an [`Ui`] where you can put widgets. For example: //! get access to an [`Ui`] where you can put widgets. For example:
//! //!
//! ``` //! ```
@@ -322,7 +322,7 @@
//! when you release the panel/window shrinks again. //! when you release the panel/window shrinks again.
//! This is an artifact of immediate mode, and here are some alternatives on how to avoid it: //! This is an artifact of immediate mode, and here are some alternatives on how to avoid it:
//! //!
//! 1. Turn off resizing with [`Window::resizable`], [`SidePanel::resizable`], [`TopBottomPanel::resizable`]. //! 1. Turn off resizing with [`Window::resizable`], [`Panel::resizable`].
//! 2. Wrap your panel contents in a [`ScrollArea`], or use [`Window::vscroll`] and [`Window::hscroll`]. //! 2. Wrap your panel contents in a [`ScrollArea`], or use [`Window::vscroll`] and [`Window::hscroll`].
//! 3. Use a justified layout: //! 3. Use a justified layout:
//! //!

View File

@@ -84,7 +84,7 @@ fn set_menu_style(style: &mut Style) {
} }
} }
/// The menu bar goes well in a [`crate::TopBottomPanel::top`], /// The menu bar goes well in a [`crate::Panel::top`],
/// but can also be placed in a [`crate::Window`]. /// but can also be placed in a [`crate::Window`].
/// In the latter case you may want to wrap it in [`Frame`]. /// In the latter case you may want to wrap it in [`Frame`].
#[deprecated = "Use `egui::MenuBar::new().ui(` instead"] #[deprecated = "Use `egui::MenuBar::new().ui(` instead"]

View File

@@ -119,7 +119,7 @@ impl Ui {
/// Create a new top-level [`Ui`]. /// Create a new top-level [`Ui`].
/// ///
/// Normally you would not use this directly, but instead use /// Normally you would not use this directly, but instead use
/// [`crate::SidePanel`], [`crate::TopBottomPanel`], [`crate::CentralPanel`], [`crate::Window`] or [`crate::Area`]. /// [`crate::Panel`], [`crate::CentralPanel`], [`crate::Window`] or [`crate::Area`].
pub fn new(ctx: Context, id: Id, ui_builder: UiBuilder) -> Self { pub fn new(ctx: Context, id: Id, ui_builder: UiBuilder) -> Self {
let UiBuilder { let UiBuilder {
id_salt, id_salt,

View File

@@ -12,16 +12,16 @@ pub enum UiKind {
/// A [`crate::CentralPanel`]. /// A [`crate::CentralPanel`].
CentralPanel, CentralPanel,
/// A left [`crate::SidePanel`]. /// A left [`crate::Panel`].
LeftPanel, LeftPanel,
/// A right [`crate::SidePanel`]. /// A right [`crate::Panel`].
RightPanel, RightPanel,
/// A top [`crate::TopBottomPanel`]. /// A top [`crate::Panel`].
TopPanel, TopPanel,
/// A bottom [`crate::TopBottomPanel`]. /// A bottom [`crate::Panel`].
BottomPanel, BottomPanel,
/// A modal [`crate::Modal`]. /// A modal [`crate::Modal`].

View File

@@ -1,12 +1,13 @@
use std::mem;
use accesskit::{Action, ActionRequest, NodeId}; use accesskit::{Action, ActionRequest, NodeId};
use accesskit_consumer::{FilterResult, Node, Tree, TreeChangeHandler}; use accesskit_consumer::{FilterResult, Node, Tree, TreeChangeHandler};
use eframe::epaint::text::TextWrapMode; use eframe::epaint::text::TextWrapMode;
use egui::collapsing_header::CollapsingState;
use egui::{ use egui::{
Button, Color32, Context, Event, Frame, FullOutput, Id, Key, KeyboardShortcut, Label, Button, Color32, Context, Event, Frame, FullOutput, Id, Key, KeyboardShortcut, Label,
Modifiers, RawInput, RichText, ScrollArea, SidePanel, TopBottomPanel, Ui, Modifiers, Panel, RawInput, RichText, ScrollArea, Ui, collapsing_header::CollapsingState,
}; };
use std::mem;
/// This [`egui::Plugin`] adds an inspector Panel. /// This [`egui::Plugin`] adds an inspector Panel.
/// ///
@@ -86,10 +87,10 @@ impl egui::Plugin for AccessibilityInspectorPlugin {
ctx.enable_accesskit(); ctx.enable_accesskit();
SidePanel::right(Self::id()).show(ctx, |ui| { Panel::right(Self::id()).show(ctx, |ui| {
ui.heading("🔎 AccessKit Inspector"); ui.heading("🔎 AccessKit Inspector");
if let Some(selected_node) = self.selected_node { if let Some(selected_node) = self.selected_node {
TopBottomPanel::bottom(Self::id().with("details_panel")) Panel::bottom(Self::id().with("details_panel"))
.frame(Frame::new()) .frame(Frame::new())
.show_separator_line(false) .show_separator_line(false)
.show_inside(ui, |ui| { .show_inside(ui, |ui| {

View File

@@ -61,7 +61,7 @@ impl Default for HttpApp {
impl eframe::App for HttpApp { impl eframe::App for HttpApp {
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
egui::TopBottomPanel::bottom("http_bottom").show(ctx, |ui| { egui::Panel::bottom("http_bottom").show(ctx, |ui| {
let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true); let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true);
ui.allocate_ui_with_layout(ui.available_size(), layout, |ui| { ui.allocate_ui_with_layout(ui.available_size(), layout, |ui| {
ui.add(egui_demo_lib::egui_github_link_file!()) ui.add(egui_demo_lib::egui_github_link_file!())

View File

@@ -2,8 +2,6 @@ use egui::ImageFit;
use egui::Slider; use egui::Slider;
use egui::Vec2; use egui::Vec2;
use egui::emath::Rot2; use egui::emath::Rot2;
use egui::panel::Side;
use egui::panel::TopBottomSide;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct ImageViewer { pub struct ImageViewer {
@@ -52,7 +50,7 @@ impl Default for ImageViewer {
impl eframe::App for ImageViewer { impl eframe::App for ImageViewer {
fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) { fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) {
egui::TopBottomPanel::new(TopBottomSide::Top, "url bar").show(ctx, |ui| { egui::Panel::top("url bar").show(ctx, |ui| {
ui.horizontal_centered(|ui| { ui.horizontal_centered(|ui| {
let label = ui.label("URI:"); let label = ui.label("URI:");
ui.text_edit_singleline(&mut self.uri_edit_text) ui.text_edit_singleline(&mut self.uri_edit_text)
@@ -73,7 +71,7 @@ impl eframe::App for ImageViewer {
}); });
}); });
egui::SidePanel::new(Side::Left, "controls").show(ctx, |ui| { egui::Panel::left("controls").show(ctx, |ui| {
// uv // uv
ui.label("UV"); ui.label("UV");
ui.add(Slider::new(&mut self.image_options.uv.min.x, 0.0..=1.0).text("min x")); ui.add(Slider::new(&mut self.image_options.uv.min.x, 0.0..=1.0).text("min x"));

View File

@@ -295,7 +295,7 @@ impl eframe::App for WrapApp {
} }
let mut cmd = Command::Nothing; let mut cmd = Command::Nothing;
egui::TopBottomPanel::top("wrap_app_top_bar") egui::Panel::top("wrap_app_top_bar")
.frame(egui::Frame::new().inner_margin(4)) .frame(egui::Frame::new().inner_margin(4))
.show(ctx, |ui| { .show(ctx, |ui| {
ui.horizontal_wrapped(|ui| { ui.horizontal_wrapped(|ui| {
@@ -341,7 +341,7 @@ impl WrapApp {
let mut cmd = Command::Nothing; let mut cmd = Command::Nothing;
egui::SidePanel::left("backend_panel") egui::Panel::left("backend_panel")
.resizable(false) .resizable(false)
.show_animated(ctx, is_open, |ui| { .show_animated(ctx, is_open, |ui| {
ui.add_space(4.0); ui.add_space(4.0);

View File

@@ -236,7 +236,7 @@ impl DemoWindows {
} }
fn mobile_top_bar(&mut self, ctx: &Context) { fn mobile_top_bar(&mut self, ctx: &Context) {
egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| { egui::Panel::top("menu_bar").show(ctx, |ui| {
menu::MenuBar::new() menu::MenuBar::new()
.config(menu::MenuConfig::new().style(StyleModifier::default())) .config(menu::MenuConfig::new().style(StyleModifier::default()))
.ui(ui, |ui| { .ui(ui, |ui| {
@@ -262,10 +262,10 @@ impl DemoWindows {
} }
fn desktop_ui(&mut self, ctx: &Context) { fn desktop_ui(&mut self, ctx: &Context) {
egui::SidePanel::right("egui_demo_panel") egui::Panel::right("egui_demo_panel")
.resizable(false) .resizable(false)
.default_width(160.0) .default_size(160.0)
.min_width(160.0) .min_size(160.0)
.show(ctx, |ui| { .show(ctx, |ui| {
ui.add_space(4.0); ui.add_space(4.0);
ui.vertical_centered(|ui| { ui.vertical_centered(|ui| {
@@ -289,7 +289,7 @@ impl DemoWindows {
self.demo_list_ui(ui); self.demo_list_ui(ui);
}); });
egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| { egui::Panel::top("menu_bar").show(ctx, |ui| {
menu::MenuBar::new().ui(ui, |ui| { menu::MenuBar::new().ui(ui, |ui| {
file_menu_button(ui); file_menu_button(ui);
}); });

View File

@@ -22,9 +22,9 @@ impl crate::View for Panels {
fn ui(&mut self, ui: &mut egui::Ui) { fn ui(&mut self, ui: &mut egui::Ui) {
// Note that the order we add the panels is very important! // Note that the order we add the panels is very important!
egui::TopBottomPanel::top("top_panel") egui::Panel::top("top_panel")
.resizable(true) .resizable(true)
.min_height(32.0) .min_size(32.0)
.show_inside(ui, |ui| { .show_inside(ui, |ui| {
egui::ScrollArea::vertical().show(ui, |ui| { egui::ScrollArea::vertical().show(ui, |ui| {
ui.vertical_centered(|ui| { ui.vertical_centered(|ui| {
@@ -34,10 +34,10 @@ impl crate::View for Panels {
}); });
}); });
egui::SidePanel::left("left_panel") egui::Panel::left("left_panel")
.resizable(true) .resizable(true)
.default_width(150.0) .default_size(150.0)
.width_range(80.0..=200.0) .size_range(80.0..=200.0)
.show_inside(ui, |ui| { .show_inside(ui, |ui| {
ui.vertical_centered(|ui| { ui.vertical_centered(|ui| {
ui.heading("Left Panel"); ui.heading("Left Panel");
@@ -47,10 +47,10 @@ impl crate::View for Panels {
}); });
}); });
egui::SidePanel::right("right_panel") egui::Panel::right("right_panel")
.resizable(true) .resizable(true)
.default_width(150.0) .default_size(150.0)
.width_range(80.0..=200.0) .size_range(80.0..=200.0)
.show_inside(ui, |ui| { .show_inside(ui, |ui| {
ui.vertical_centered(|ui| { ui.vertical_centered(|ui| {
ui.heading("Right Panel"); ui.heading("Right Panel");
@@ -60,9 +60,9 @@ impl crate::View for Panels {
}); });
}); });
egui::TopBottomPanel::bottom("bottom_panel") egui::Panel::bottom("bottom_panel")
.resizable(false) .resizable(false)
.min_height(0.0) .min_size(0.0)
.show_inside(ui, |ui| { .show_inside(ui, |ui| {
ui.vertical_centered(|ui| { ui.vertical_centered(|ui| {
ui.heading("Bottom Panel"); ui.heading("Bottom Panel");

View File

@@ -35,7 +35,7 @@ impl crate::View for Tooltips {
ui.add(crate::egui_github_link_file_line!()); ui.add(crate::egui_github_link_file_line!());
}); });
egui::SidePanel::right("scroll_test").show_inside(ui, |ui| { egui::Panel::right("scroll_test").show_inside(ui, |ui| {
ui.label( ui.label(
"The scroll area below has many labels with interactive tooltips. \ "The scroll area below has many labels with interactive tooltips. \
The purpose is to test that the tooltips close when you scroll.", The purpose is to test that the tooltips close when you scroll.",

View File

@@ -33,7 +33,7 @@ impl Default for EasyMarkEditor {
impl EasyMarkEditor { impl EasyMarkEditor {
pub fn panels(&mut self, ctx: &egui::Context) { pub fn panels(&mut self, ctx: &egui::Context) {
egui::TopBottomPanel::bottom("easy_mark_bottom").show(ctx, |ui| { egui::Panel::bottom("easy_mark_bottom").show(ctx, |ui| {
let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true); let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true);
ui.allocate_ui_with_layout(ui.available_size(), layout, |ui| { ui.allocate_ui_with_layout(ui.available_size(), layout, |ui| {
ui.add(crate::egui_github_link_file!()) ui.add(crate::egui_github_link_file!())

View File

@@ -218,7 +218,7 @@ impl winit::application::ApplicationHandler<UserEvent> for GlowApp {
self.egui_glow.as_mut().unwrap().run( self.egui_glow.as_mut().unwrap().run(
self.gl_window.as_mut().unwrap().window(), self.gl_window.as_mut().unwrap().window(),
|egui_ctx| { |egui_ctx| {
egui::SidePanel::left("my_side_panel").show(egui_ctx, |ui| { egui::Panel::left("my_side_panel").show(egui_ctx, |ui| {
ui.heading("Hello World!"); ui.heading("Hello World!");
if ui.button("Quit").clicked() { if ui.button("Quit").clicked() {
quit = true; quit = true;

View File

@@ -41,7 +41,7 @@ impl eframe::App for MyApp {
// TODO(lucasmerlin): This is a pretty big hack, should be fixed once safe_area implemented // TODO(lucasmerlin): This is a pretty big hack, should be fixed once safe_area implemented
// for android: // for android:
// https://github.com/rust-windowing/winit/issues/3910 // https://github.com/rust-windowing/winit/issues/3910
egui::TopBottomPanel::top("status_bar_space").show(ctx, |ui| { egui::Panel::top("status_bar_space").show(ctx, |ui| {
ui.set_height(32.0); ui.set_height(32.0);
}); });

View File

@@ -9,7 +9,7 @@ fn main() -> eframe::Result {
let options = eframe::NativeOptions::default(); let options = eframe::NativeOptions::default();
eframe::run_simple_native("My egui App", options, move |ctx, _frame| { eframe::run_simple_native("My egui App", options, move |ctx, _frame| {
// A bottom panel to force the tooltips to consider if the fit below or under the widget: // A bottom panel to force the tooltips to consider if the fit below or under the widget:
egui::TopBottomPanel::bottom("bottom").show(ctx, |ui| { egui::Panel::bottom("bottom").show(ctx, |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.vertical(|ui| { ui.vertical(|ui| {
ui.label("Single tooltips:"); ui.label("Single tooltips:");

View File

@@ -34,7 +34,7 @@ impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
ctx.all_styles_mut(|style| style.interaction.tooltip_delay = 0.0); ctx.all_styles_mut(|style| style.interaction.tooltip_delay = 0.0);
egui::SidePanel::left("side_panel_left").show(ctx, |ui| { egui::Panel::left("side_panel_left").show(ctx, |ui| {
ui.heading("Information"); ui.heading("Information");
ui.label( ui.label(
"This is a demo/test environment of the `UiStack` feature. The tables display \ "This is a demo/test environment of the `UiStack` feature. The tables display \
@@ -82,7 +82,7 @@ impl eframe::App for MyApp {
}); });
}); });
egui::SidePanel::right("side_panel_right").show(ctx, |ui| { egui::Panel::right("side_panel_right").show(ctx, |ui| {
egui::ScrollArea::both().auto_shrink(false).show(ui, |ui| { egui::ScrollArea::both().auto_shrink(false).show(ui, |ui| {
stack_ui(ui); stack_ui(ui);
@@ -170,7 +170,7 @@ impl eframe::App for MyApp {
}); });
}); });
egui::TopBottomPanel::bottom("bottom_panel") egui::Panel::bottom("bottom_panel")
.resizable(true) .resizable(true)
.show(ctx, |ui| { .show(ctx, |ui| {
egui::ScrollArea::vertical() egui::ScrollArea::vertical()