From a8ff4677e3f62bc6480215e6a574dd1f3054a282 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 | 13 ++++++++++--- crates/egui/src/theme/default_style.rs | 16 ++++++++++++++-- crates/egui/src/widget_style/mod.rs | 15 +++++++++++++++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/crates/egui/src/containers/popup.rs b/crates/egui/src/containers/popup.rs index 4295686ee..284dec69f 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::{Classes, HasClasses as _, PopupStyle}, }; /// What should we anchor the popup to? @@ -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 4ad0b2dcc..145583b43 100644 --- a/crates/egui/src/theme/default_style.rs +++ b/crates/egui/src/theme/default_style.rs @@ -5,8 +5,8 @@ use crate::{ Button, Context, Frame, TextEdit, TextStyle, theme::StyleProvider, widget_style::{ - AtomLayoutStyle, ButtonStyle, CheckboxStyle, HasClasses as _, SeparatorStyle, StyleArgs, - TextEditStyle, TextVisuals, WidgetState, + AtomLayoutStyle, ButtonStyle, CheckboxStyle, HasClasses as _, PopupStyle, SeparatorStyle, + StyleArgs, TextEditStyle, TextVisuals, WidgetState, }, }; @@ -26,6 +26,7 @@ impl DefaultStyle { ctx.themes.register::(Self, false); ctx.themes.register::(Self, false); ctx.themes.register::(Self, false); + ctx.themes.register::(Self, false); }); } } @@ -105,6 +106,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 ef62d800b..6597c1588 100644 --- a/crates/egui/src/widget_style/mod.rs +++ b/crates/egui/src/widget_style/mod.rs @@ -136,6 +136,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 {