1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-02 14:50: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 4b2bae1e0f
commit a8ff4677e3
3 changed files with 39 additions and 5 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 _,
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
});

View File

@@ -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::<SeparatorStyle>(Self, false);
ctx.themes.register::<CheckboxStyle>(Self, false);
ctx.themes.register::<TextEditStyle>(Self, false);
ctx.themes.register::<PopupStyle>(Self, false);
});
}
}
@@ -105,6 +106,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

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