From 0099cc1fe61f9c7e4fbb1cef5b2d310ae9b8a3bd 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 | 15 +++++++++++++-- crates/egui/src/theme/themes.rs | 9 +++++++-- crates/egui/src/widget_style/mod.rs | 15 +++++++++++++++ 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/crates/egui/src/containers/popup.rs b/crates/egui/src/containers/popup.rs index c1b150a37..a643bffdb 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 _, MENU_CLASS}, + widget_style::{Classes, HasClasses as _, MENU_CLASS, PopupStyle}, }; /// What should we anchor the popup to? @@ -594,8 +594,10 @@ impl<'a> Popup<'a> { let (pivot, anchor) = best_align.pivot_pos(&anchor_rect, gap); + let classes = Classes::default().with_class_if(MENU_CLASS, kind == PopupKind::Menu); + let mut area = Area::new(id) - .with_class_if(MENU_CLASS, kind == PopupKind::Menu) + .with_classes(classes.clone()) .order(kind.order()) .pivot(pivot) .fixed_pos(anchor) @@ -618,7 +620,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 0cb665f3f..7aa882098 100644 --- a/crates/egui/src/theme/default_style.rs +++ b/crates/egui/src/theme/default_style.rs @@ -6,8 +6,8 @@ use crate::{ theme::StyleProvider, widget_style::{ BaseStyle, ButtonStyle, CheckboxStyle, HasClasses as _, LabelStyle, LayoutStyle, - READ_ONLY_CLASS, SELECTED_CLASS, SeparatorStyle, StyleArgs, TextEditStyle, TextVisuals, - WidgetState, + PopupStyle, READ_ONLY_CLASS, SELECTED_CLASS, SeparatorStyle, StyleArgs, TextEditStyle, + TextVisuals, WidgetState, }, }; @@ -99,6 +99,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/theme/themes.rs b/crates/egui/src/theme/themes.rs index 5c31f669a..be84d0fc9 100644 --- a/crates/egui/src/theme/themes.rs +++ b/crates/egui/src/theme/themes.rs @@ -7,8 +7,8 @@ use crate::{ theme::{StyleProvider, default_style::DefaultStyle}, util::IdTypeMap, widget_style::{ - BaseStyle, ButtonStyle, CheckboxStyle, LabelStyle, SeparatorStyle, TextEditStyle, - WidgetStyle, + BaseStyle, ButtonStyle, CheckboxStyle, LabelStyle, PopupStyle, SeparatorStyle, + TextEditStyle, WidgetStyle, }, }; @@ -52,6 +52,11 @@ impl Default for Themes { Arc::new(Mutex::new(Box::new(DefaultStyle))), ); + themes.insert_temp::>( + Id::NULL, + Arc::new(Mutex::new(Box::new(DefaultStyle))), + ); + themes.insert_temp::>( Id::NULL, Arc::new(Mutex::new(Box::new(DefaultStyle))), diff --git a/crates/egui/src/widget_style/mod.rs b/crates/egui/src/widget_style/mod.rs index f063cd1ce..d25e424fc 100644 --- a/crates/egui/src/widget_style/mod.rs +++ b/crates/egui/src/widget_style/mod.rs @@ -98,6 +98,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 {