From 1b97ff61fd758a74e5bb773c2da27ea45a43a8ea Mon Sep 17 00:00:00 2001 From: Lucas Meurer Date: Fri, 21 Aug 2026 16:44:55 +0200 Subject: [PATCH] Add a PopupStyle, so the theme frames popups and menus A `Popup` framed itself with `Frame::popup` and left item spacing to the ambient style. Both now come from a `PopupStyle`, which is what lets a theme give a menu its own padding and its own item rhythm. Co-Authored-By: Claude Opus 5 (1M context) --- crates/egui/src/containers/popup.rs | 15 +++++++++++---- crates/egui/src/theme/default_style.rs | 16 ++++++++++++++-- crates/egui/src/widget_style/mod.rs | 15 +++++++++++++++ 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/crates/egui/src/containers/popup.rs b/crates/egui/src/containers/popup.rs index 4295686ee..7bb33c435 100644 --- a/crates/egui/src/containers/popup.rs +++ b/crates/egui/src/containers/popup.rs @@ -7,7 +7,7 @@ use crate::{ Sense, Ui, UiKind, UiStackInfo, containers::menu::{MenuConfig, MenuState, menu_style}, style::StyleModifier, - widget_style::HasClasses as _, + widget_style::{ClassName, Classes, HasClasses as _, PopupStyle}, }; /// What should we anchor the popup to? @@ -193,7 +193,7 @@ impl<'a> Popup<'a> { /// /// A menu lays its items out itself, so a widget in one is generally styled to fit that /// layout rather than to stand on its own. - pub const CLASS_MENU: &'static str = "egui::popup::menu"; + pub const CLASS_MENU: ClassName = ClassName::from_static("egui::popup::menu"); /// Create a new popup pub fn new(id: Id, ctx: Context, anchor: impl Into, layer_id: LayerId) -> Self { @@ -600,8 +600,10 @@ impl<'a> Popup<'a> { let (pivot, anchor) = best_align.pivot_pos(&anchor_rect, gap); + let classes = Classes::default().with_class_if(Self::CLASS_MENU, kind == PopupKind::Menu); + let mut area = Area::new(id) - .with_class_if(Self::CLASS_MENU, kind == PopupKind::Menu) + .with_classes(classes.clone()) .order(kind.order()) .pivot(pivot) .fixed_pos(anchor) @@ -624,7 +626,12 @@ impl<'a> Popup<'a> { let mut response = area.show(&ctx, |ui| { style.apply(ui.style_mut()); - let frame = frame.unwrap_or_else(|| Frame::popup(ui.style())); + + // The theme decides how the popup is framed and how tightly its items sit together. + let popup_style: PopupStyle = ui.widget_style(id, &classes); + ui.spacing_mut().item_spacing = popup_style.item_spacing; + + let frame = frame.unwrap_or(popup_style.frame); frame.show(ui, content).inner }); diff --git a/crates/egui/src/theme/default_style.rs b/crates/egui/src/theme/default_style.rs index 63ff3b306..ab12906da 100644 --- a/crates/egui/src/theme/default_style.rs +++ b/crates/egui/src/theme/default_style.rs @@ -6,8 +6,8 @@ use crate::{ class::HasClasses as _, theme::StyleProvider, widget_style::{ - AtomLayoutStyle, ButtonStyle, CheckboxStyle, SeparatorStyle, StyleArgs, TextEditStyle, - TextVisuals, WidgetState, + AtomLayoutStyle, ButtonStyle, CheckboxStyle, PopupStyle, SeparatorStyle, StyleArgs, + TextEditStyle, TextVisuals, WidgetState, }, }; @@ -26,6 +26,7 @@ impl DefaultStyle { ctx.add_widget_theme::(Self); ctx.add_widget_theme::(Self); ctx.add_widget_theme::(Self); + ctx.add_widget_theme::(Self); } } @@ -106,6 +107,17 @@ impl StyleProvider for DefaultStyle { } } +impl StyleProvider for DefaultStyle { + fn style(&mut self, modifiers: &StyleArgs<'_>) -> PopupStyle { + let StyleArgs { style, .. } = modifiers; + + PopupStyle { + frame: Frame::popup(style), + item_spacing: style.spacing.item_spacing, + } + } +} + impl StyleProvider for DefaultStyle { fn style(&mut self, modifiers: &StyleArgs<'_>) -> TextEditStyle { let StyleArgs { diff --git a/crates/egui/src/widget_style/mod.rs b/crates/egui/src/widget_style/mod.rs index 163b88a3b..f661cc5cc 100644 --- a/crates/egui/src/widget_style/mod.rs +++ b/crates/egui/src/widget_style/mod.rs @@ -127,6 +127,21 @@ pub struct ButtonStyle { impl WidgetStyle for ButtonStyle {} +/// Dedicated style for a [`crate::Popup`], including menus and tooltips +#[derive(Debug, Clone)] +pub struct PopupStyle { + /// Frame around the popup's contents, including its padding. + pub frame: Frame, + + /// Spacing between the items inside the popup. + /// + /// A menu wants its items flush against each other, while a tooltip wants them spaced out + /// like any other content. + pub item_spacing: Vec2, +} + +impl WidgetStyle for PopupStyle {} + /// Dedicated text edit style #[derive(Debug, Clone)] pub struct TextEditStyle {