mirror of
https://github.com/emilk/egui.git
synced 2026-08-29 21:00:03 -04:00
Refactor panels into proper containers
This commit is contained in:
@@ -31,9 +31,9 @@ impl Frame {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn menu_bar(style: &Style) -> Self {
|
||||
pub(crate) fn panel(style: &Style) -> Self {
|
||||
Self {
|
||||
margin: Vec2::splat(1.0),
|
||||
margin: Vec2::new(8.0, 2.0),
|
||||
corner_radius: 0.0,
|
||||
fill: style.visuals.widgets.noninteractive.bg_fill,
|
||||
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
||||
@@ -58,10 +58,6 @@ impl Frame {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn panel(style: &Style) -> Self {
|
||||
Self::popup(style)
|
||||
}
|
||||
|
||||
pub fn fill(mut self, fill: Srgba) -> Self {
|
||||
self.fill = fill;
|
||||
self
|
||||
|
||||
@@ -6,12 +6,20 @@ pub(crate) mod area;
|
||||
pub(crate) mod collapsing_header;
|
||||
mod combo_box;
|
||||
pub(crate) mod frame;
|
||||
pub(crate) mod panel;
|
||||
pub(crate) mod popup;
|
||||
pub(crate) mod resize;
|
||||
pub(crate) mod scroll_area;
|
||||
pub(crate) mod window;
|
||||
|
||||
pub use {
|
||||
area::Area, collapsing_header::*, combo_box::*, frame::Frame, popup::*, resize::Resize,
|
||||
scroll_area::ScrollArea, window::Window,
|
||||
area::Area,
|
||||
collapsing_header::*,
|
||||
combo_box::*,
|
||||
frame::Frame,
|
||||
panel::{SidePanel, TopPanel},
|
||||
popup::*,
|
||||
resize::Resize,
|
||||
scroll_area::ScrollArea,
|
||||
window::Window,
|
||||
};
|
||||
|
||||
105
egui/src/containers/panel.rs
Normal file
105
egui/src/containers/panel.rs
Normal file
@@ -0,0 +1,105 @@
|
||||
//! Panels
|
||||
|
||||
use crate::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// A panel that covers the entire left side of the screen.
|
||||
///
|
||||
/// Panels should be added before adding any `Window`s.
|
||||
pub struct SidePanel {
|
||||
id: Id,
|
||||
max_width: f32,
|
||||
}
|
||||
|
||||
impl SidePanel {
|
||||
/// The given `max_width` is a soft maximum (as always), and the actual panel may be smaller or larger.
|
||||
pub fn left(id: Id, max_width: f32) -> Self {
|
||||
Self { id, max_width }
|
||||
}
|
||||
}
|
||||
|
||||
impl SidePanel {
|
||||
pub fn show<R>(
|
||||
self,
|
||||
ctx: &Arc<Context>,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||
) -> (R, Response) {
|
||||
let Self { id, max_width } = self;
|
||||
|
||||
let mut panel_rect = ctx.available_rect();
|
||||
panel_rect.max.x = panel_rect.max.x.at_most(panel_rect.min.x + max_width);
|
||||
|
||||
let layer_id = LayerId::background();
|
||||
|
||||
let clip_rect = ctx.input().screen_rect();
|
||||
let mut panel_ui = Ui::new(ctx.clone(), layer_id, id, panel_rect, clip_rect);
|
||||
|
||||
let frame = Frame::panel(&ctx.style());
|
||||
let r = frame.show(&mut panel_ui, |ui| {
|
||||
ui.set_min_height(ui.max_rect_finite().height()); // fill full height
|
||||
add_contents(ui)
|
||||
});
|
||||
|
||||
let panel_rect = panel_ui.min_rect();
|
||||
let response = panel_ui.interact_hover(panel_rect);
|
||||
|
||||
ctx.allocate_left_panel(panel_rect);
|
||||
|
||||
(r, response)
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// A panel that covers the entire top side of the screen.
|
||||
///
|
||||
/// Panels should be added before adding any `Window`s.
|
||||
pub struct TopPanel {
|
||||
id: Id,
|
||||
max_height: Option<f32>,
|
||||
}
|
||||
|
||||
impl TopPanel {
|
||||
/// Default height is that of `interact_size.y` (i.e. a button),
|
||||
/// but the panel will expand as needed.
|
||||
pub fn top(id: Id) -> Self {
|
||||
Self {
|
||||
id,
|
||||
max_height: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TopPanel {
|
||||
pub fn show<R>(
|
||||
self,
|
||||
ctx: &Arc<Context>,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||
) -> (R, Response) {
|
||||
let Self { id, max_height } = self;
|
||||
let max_height = max_height.unwrap_or_else(|| ctx.style().spacing.interact_size.y);
|
||||
|
||||
let mut panel_rect = ctx.available_rect();
|
||||
panel_rect.max.y = panel_rect.max.y.at_most(panel_rect.min.y + max_height);
|
||||
|
||||
let layer_id = LayerId::background();
|
||||
|
||||
let clip_rect = ctx.input().screen_rect();
|
||||
let mut panel_ui = Ui::new(ctx.clone(), layer_id, id, panel_rect, clip_rect);
|
||||
|
||||
let frame = Frame::panel(&ctx.style());
|
||||
let r = frame.show(&mut panel_ui, |ui| {
|
||||
ui.set_min_width(ui.max_rect_finite().width()); // fill full width
|
||||
add_contents(ui)
|
||||
});
|
||||
|
||||
let panel_rect = panel_ui.min_rect();
|
||||
let response = panel_ui.interact_hover(panel_rect);
|
||||
|
||||
ctx.allocate_top_panel(panel_rect);
|
||||
|
||||
(r, response)
|
||||
}
|
||||
}
|
||||
@@ -287,77 +287,18 @@ impl Context {
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/// Create a panel that covers the entire left side of the screen.
|
||||
/// The given `max_width` is a soft maximum (as always), and the actual panel may be smaller or larger.
|
||||
/// You should call this *before* adding windows to Egui.
|
||||
pub fn panel_left<R>(
|
||||
self: &Arc<Context>,
|
||||
max_width: f32,
|
||||
frame: Frame,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||
) -> (R, Response) {
|
||||
let mut panel_rect = self.available_rect();
|
||||
panel_rect.max.x = panel_rect.max.x.at_most(panel_rect.min.x + max_width);
|
||||
|
||||
let id = Id::background();
|
||||
let layer_id = LayerId {
|
||||
order: Order::Background,
|
||||
id,
|
||||
};
|
||||
|
||||
let clip_rect = self.input.screen_rect();
|
||||
let mut panel_ui = Ui::new(self.clone(), layer_id, id, panel_rect, clip_rect);
|
||||
let r = frame.show(&mut panel_ui, |ui| {
|
||||
ui.set_min_height(ui.max_rect_finite().height()); // fill full height
|
||||
add_contents(ui)
|
||||
});
|
||||
|
||||
let panel_rect = panel_ui.min_rect();
|
||||
let response = panel_ui.interact_hover(panel_rect);
|
||||
|
||||
// Shrink out `available_rect`:
|
||||
/// Shrink `available_rect()`.
|
||||
pub(crate) fn allocate_left_panel(&self, panel_rect: Rect) {
|
||||
let mut remainder = self.available_rect();
|
||||
remainder.min.x = panel_rect.max.x;
|
||||
*self.available_rect.lock() = Some(remainder);
|
||||
|
||||
(r, response)
|
||||
}
|
||||
|
||||
/// Create a panel that covers the entire top side of the screen.
|
||||
/// This can be useful to add a menu bar to the whole window.
|
||||
/// The given `max_height` is a soft maximum (as always), and the actual panel may be smaller or larger.
|
||||
/// You should call this *before* adding windows to Egui.
|
||||
pub fn panel_top<R>(
|
||||
self: &Arc<Context>,
|
||||
max_height: f32,
|
||||
frame: Frame,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||
) -> (R, Response) {
|
||||
let mut panel_rect = self.available_rect();
|
||||
panel_rect.max.y = panel_rect.max.y.at_most(panel_rect.min.y + max_height);
|
||||
|
||||
let id = Id::background();
|
||||
let layer_id = LayerId {
|
||||
order: Order::Background,
|
||||
id,
|
||||
};
|
||||
|
||||
let clip_rect = self.input.screen_rect();
|
||||
let mut panel_ui = Ui::new(self.clone(), layer_id, id, panel_rect, clip_rect);
|
||||
let r = frame.show(&mut panel_ui, |ui| {
|
||||
ui.set_min_width(ui.max_rect_finite().width()); // fill full width
|
||||
add_contents(ui)
|
||||
});
|
||||
|
||||
let panel_rect = panel_ui.min_rect();
|
||||
let response = panel_ui.interact_hover(panel_rect);
|
||||
|
||||
// Shrink out `available_rect`:
|
||||
/// Shrink `available_rect()`.
|
||||
pub(crate) fn allocate_top_panel(&self, panel_rect: Rect) {
|
||||
let mut remainder = self.available_rect();
|
||||
remainder.min.y = panel_rect.max.y;
|
||||
*self.available_rect.lock() = Some(remainder);
|
||||
|
||||
(r, response)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{app, demos, Context, Resize, ScrollArea, Ui, Window};
|
||||
use crate::{app, demos, Context, Id, Resize, ScrollArea, Ui, Window};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -63,8 +63,7 @@ impl DemoWindows {
|
||||
self.previous_link = env.link;
|
||||
}
|
||||
|
||||
let frame = crate::Frame::panel(ui.style());
|
||||
ctx.panel_left(240.0, frame, |ui| {
|
||||
crate::SidePanel::left(Id::new("side_panel"), 200.0).show(ctx, |ui| {
|
||||
ui.heading("Egui Demo");
|
||||
ui.label("Egui is an immediate mode GUI library written in Rust.");
|
||||
ui.add(crate::Hyperlink::new("https://github.com/emilk/egui").text("Egui home page"));
|
||||
@@ -83,7 +82,8 @@ impl DemoWindows {
|
||||
self.open_windows.ui(ui);
|
||||
});
|
||||
});
|
||||
ctx.panel_top(0.0, crate::Frame::none(), |ui| {
|
||||
|
||||
crate::TopPanel::top(Id::new("menu_bar")).show(ctx, |ui| {
|
||||
show_menu_bar(ui, &mut self.open_windows, env.seconds_since_midnight);
|
||||
});
|
||||
|
||||
|
||||
@@ -34,6 +34,13 @@ impl LayerId {
|
||||
id: Id::new("debug"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn background() -> Self {
|
||||
Self {
|
||||
order: Order::Background,
|
||||
id: Id::background(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A unique identifier of a specific `PaintCmd` in a `PaintList`.
|
||||
|
||||
@@ -37,25 +37,26 @@ impl BarState {
|
||||
}
|
||||
}
|
||||
|
||||
/// The menu bar goes well in `TopPanel`,
|
||||
/// but can also be placed in a `Window`.
|
||||
/// In the latter case you may want to wrap it in `Frame`.
|
||||
pub fn bar<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Response) {
|
||||
Frame::menu_bar(ui.style()).show(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
let mut style = ui.style().clone();
|
||||
style.spacing.button_padding = vec2(2.0, 0.0);
|
||||
// style.visuals.widgets.active.bg_fill = TRANSPARENT;
|
||||
style.visuals.widgets.active.bg_stroke = Stroke::none();
|
||||
// style.visuals.widgets.hovered.bg_fill = TRANSPARENT;
|
||||
style.visuals.widgets.hovered.bg_stroke = Stroke::none();
|
||||
style.visuals.widgets.inactive.bg_fill = TRANSPARENT;
|
||||
style.visuals.widgets.inactive.bg_stroke = Stroke::none();
|
||||
ui.set_style(style);
|
||||
ui.horizontal(|ui| {
|
||||
let mut style = ui.style().clone();
|
||||
style.spacing.button_padding = vec2(2.0, 0.0);
|
||||
// style.visuals.widgets.active.bg_fill = TRANSPARENT;
|
||||
style.visuals.widgets.active.bg_stroke = Stroke::none();
|
||||
// style.visuals.widgets.hovered.bg_fill = TRANSPARENT;
|
||||
style.visuals.widgets.hovered.bg_stroke = Stroke::none();
|
||||
style.visuals.widgets.inactive.bg_fill = TRANSPARENT;
|
||||
style.visuals.widgets.inactive.bg_stroke = Stroke::none();
|
||||
ui.set_style(style);
|
||||
|
||||
// Take full width and fixed height:
|
||||
let height = ui.style().spacing.interact_size.y;
|
||||
ui.set_min_size(vec2(ui.available().width(), height));
|
||||
// Take full width and fixed height:
|
||||
let height = ui.style().spacing.interact_size.y;
|
||||
ui.set_min_size(vec2(ui.available().width(), height));
|
||||
|
||||
add_contents(ui)
|
||||
})
|
||||
add_contents(ui)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user