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

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) <noreply@anthropic.com>
This commit is contained in:
Lucas Meurer
2026-08-21 16:44:55 +02:00
parent a23d588038
commit 0099cc1fe6
4 changed files with 45 additions and 7 deletions

View File

@@ -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
});

View File

@@ -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<ButtonStyle> for DefaultStyle {
}
}
impl StyleProvider<PopupStyle> 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<TextEditStyle> for DefaultStyle {
fn style(&mut self, modifiers: &StyleArgs<'_>) -> TextEditStyle {
let StyleArgs {

View File

@@ -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::<ThemeWrap<PopupStyle>>(
Id::NULL,
Arc::new(Mutex::new(Box::new(DefaultStyle))),
);
themes.insert_temp::<ThemeWrap<TextEditStyle>>(
Id::NULL,
Arc::new(Mutex::new(Box::new(DefaultStyle))),

View File

@@ -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 {