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

Move button classes onto Button

This commit is contained in:
Lucas Meurer
2026-08-28 14:21:34 +02:00
parent 7a18bc9cf3
commit a6fa160c59
6 changed files with 44 additions and 45 deletions

View File

@@ -499,6 +499,7 @@ pub use self::{
ui_stack::*, ui_stack::*,
viewport::*, viewport::*,
widget_rect::{InteractOptions, WidgetRect, WidgetRects}, widget_rect::{InteractOptions, WidgetRect, WidgetRects},
widget_style::class,
widget_text::{RichText, WidgetText}, widget_text::{RichText, WidgetText},
widgets::*, widgets::*,
}; };

View File

@@ -2,12 +2,12 @@ use emath::Vec2;
use epaint::Margin; use epaint::Margin;
use crate::{ use crate::{
Frame, Style, TextStyle, Button, Frame, Style, TextStyle,
style::WidgetVisuals, style::WidgetVisuals,
theme::StyleProvider, theme::StyleProvider,
widget_style::{ widget_style::{
ButtonStyle, CheckboxStyle, HasClasses as _, NO_FRAME_CLASS, BUTTON_NO_FRAME_WHEN_INACTIVE_CLASS, ButtonStyle, CheckboxStyle, HasClasses as _, SeparatorStyle, StyleArgs, TextVisuals,
SELECTED_CLASS, SMALL_CLASS, SeparatorStyle, StyleArgs, TextVisuals, WidgetState, WidgetState,
}, },
}; };
@@ -38,7 +38,7 @@ impl StyleProvider<ButtonStyle> for DefaultStyle {
let spacing = &style.spacing; let spacing = &style.spacing;
let mut widget_visuals = *style.visuals.widgets.state(*state); let mut widget_visuals = *style.visuals.widgets.state(*state);
if classes.has_class(SELECTED_CLASS) { if classes.has_class(Button::CLASS_SELECTED) {
let visuals = &style.visuals; let visuals = &style.visuals;
widget_visuals.weak_bg_fill = visuals.selection.bg_fill; widget_visuals.weak_bg_fill = visuals.selection.bg_fill;
widget_visuals.bg_fill = visuals.selection.bg_fill; widget_visuals.bg_fill = visuals.selection.bg_fill;
@@ -51,15 +51,17 @@ impl StyleProvider<ButtonStyle> for DefaultStyle {
.into(); .into();
// A small button is meant to be embedded into text, so it must not add any height. // A small button is meant to be embedded into text, so it must not add any height.
if classes.has_class(SMALL_CLASS) { if classes.has_class(Button::CLASS_SMALL) {
inner_margin.top = 0; inner_margin.top = 0;
inner_margin.bottom = 0; inner_margin.bottom = 0;
} }
let frame = if classes.has_class(NO_FRAME_CLASS) { let frame = if classes.has_class(Button::CLASS_NO_FRAME) {
// No frame at all: the button takes up no more room than its contents. // No frame at all: the button takes up no more room than its contents.
Frame::new() Frame::new()
} else if classes.has_class(BUTTON_NO_FRAME_WHEN_INACTIVE_CLASS) && *state == WidgetState::Inactive { } else if classes.has_class(Button::CLASS_NO_FRAME_WHEN_INACTIVE)
&& *state == WidgetState::Inactive
{
// Invisible, but as big as it will be once the user interacts with it. // Invisible, but as big as it will be once the user interacts with it.
Frame::new().inner_margin(inner_margin) Frame::new().inner_margin(inner_margin)
} else { } else {

View File

@@ -5,8 +5,8 @@ use core::{any::Any, ops::Deref};
use std::sync::Arc; use std::sync::Arc;
use crate::containers::menu; use crate::containers::menu;
use crate::widget_style::{HasClasses as _, ROOT_CLASS};
use crate::{IdSource, containers::*, ecolor::*, layout::*, placer::Placer, widgets::*, *}; use crate::{IdSource, containers::*, ecolor::*, layout::*, placer::Placer, widgets::*, *};
use crate::{class, widget_style::HasClasses as _};
use emath::GuiRounding as _; use emath::GuiRounding as _;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -135,7 +135,7 @@ impl Ui {
let disabled = disabled || invisible; let disabled = disabled || invisible;
let style = style.unwrap_or_else(|| ctx.global_style()); let style = style.unwrap_or_else(|| ctx.global_style());
let sense = sense.unwrap_or_else(Sense::hover); let sense = sense.unwrap_or_else(Sense::hover);
let classes = classes.with_class(ROOT_CLASS); let classes = classes.with_class(class::ROOT);
let placer = Placer::new(max_rect, layout); let placer = Placer::new(max_rect, layout);
let ui_stack = UiStack { let ui_stack = UiStack {

View File

@@ -4,22 +4,6 @@ use smallvec::SmallVec;
use crate::TextBuffer as _; use crate::TextBuffer as _;
/// The root class is a special class present on every top-level [`crate::Ui`].
pub const ROOT_CLASS: &str = "egui::root";
/// The selected class is a special class present on selected [`crate::Button`].
pub const SELECTED_CLASS: &str = "egui::selected";
/// The small class is a special class present on small [`crate::Button`].
pub const SMALL_CLASS: &str = "egui::small";
/// Present on a [`crate::Button`] that should have no frame at all.
pub const NO_FRAME_CLASS: &str = "egui::no_frame";
/// Present on a [`crate::Button`] that should have no frame while it is
/// [`crate::widget_style::WidgetState::Inactive`].
pub const BUTTON_NO_FRAME_WHEN_INACTIVE_CLASS: &str = "egui::button::no_frame_when_inactive";
/// A class is a static string identifier. /// A class is a static string identifier.
pub type ClassName = Cow<'static, str>; pub type ClassName = Cow<'static, str>;

View File

@@ -4,10 +4,13 @@
mod classes; mod classes;
pub use self::classes::{ pub use self::classes::{ClassName, Classes, HasClasses};
ClassName, Classes, HasClasses, NO_FRAME_CLASS, BUTTON_NO_FRAME_WHEN_INACTIVE_CLASS, ROOT_CLASS,
SELECTED_CLASS, SMALL_CLASS, /// Built-in classes shared by all widgets.
}; pub mod class {
/// Present on every top-level [`crate::Ui`].
pub const ROOT: &str = "egui::root";
}
use core::fmt::Debug; use core::fmt::Debug;

View File

@@ -2,10 +2,7 @@ use crate::{
Atom, AtomExt as _, AtomKind, AtomLayout, AtomLayoutResponse, Atoms, Color32, CornerRadius, Atom, AtomExt as _, AtomKind, AtomLayout, AtomLayoutResponse, Atoms, Color32, CornerRadius,
Image, IntoAtoms, NumExt as _, Response, Sense, Stroke, TextStyle, TextWrapMode, Ui, Vec2, Image, IntoAtoms, NumExt as _, Response, Sense, Stroke, TextStyle, TextWrapMode, Ui, Vec2,
Widget, WidgetInfo, WidgetText, WidgetType, Widget, WidgetInfo, WidgetText, WidgetType,
widget_style::{ widget_style::{ButtonStyle, Classes, HasClasses},
ButtonStyle, Classes, HasClasses, NO_FRAME_CLASS, BUTTON_NO_FRAME_WHEN_INACTIVE_CLASS,
SELECTED_CLASS, SMALL_CLASS,
},
}; };
/// Clickable button with text. /// Clickable button with text.
@@ -41,6 +38,18 @@ pub struct Button<'a> {
} }
impl<'a> Button<'a> { impl<'a> Button<'a> {
/// Present on a selected button.
pub const CLASS_SELECTED: &'static str = "egui::selected";
/// Present on a small button.
pub const CLASS_SMALL: &'static str = "egui::small";
/// Present on a button that should have no frame at all.
pub const CLASS_NO_FRAME: &'static str = "egui::no_frame";
/// Present on a button that should have no frame while it is inactive.
pub const CLASS_NO_FRAME_WHEN_INACTIVE: &'static str = "egui::button::no_frame_when_inactive";
pub fn new(atoms: impl IntoAtoms<'a>) -> Self { pub fn new(atoms: impl IntoAtoms<'a>) -> Self {
Self { Self {
layout: AtomLayout::new(atoms.into_atoms()) layout: AtomLayout::new(atoms.into_atoms())
@@ -69,7 +78,7 @@ impl<'a> Button<'a> {
/// # }); /// # });
/// ``` /// ```
/// ///
/// When selected, [`SELECTED_CLASS`] is added. /// When selected, [`Self::CLASS_SELECTED`] is added.
/// ///
/// See also: /// See also:
/// - [`Ui::selectable_value`] /// - [`Ui::selectable_value`]
@@ -155,30 +164,30 @@ impl<'a> Button<'a> {
/// Make this a small button, suitable for embedding into text. /// Make this a small button, suitable for embedding into text.
/// ///
/// This adds the built-in [`SMALL_CLASS`], which with the default style removes the top and /// This adds the built-in [`Self::CLASS_SMALL`], which with the default style removes the top and
/// bottom margin. /// bottom margin.
#[inline] #[inline]
pub fn small(mut self) -> Self { pub fn small(mut self) -> Self {
self.add_class(SMALL_CLASS); self.add_class(Self::CLASS_SMALL);
self self
} }
/// Turn off the frame /// Turn off the frame
/// ///
/// If `false`, this adds the built-in [`NO_FRAME_CLASS`], which with the default style /// If `false`, this adds the built-in [`Self::CLASS_NO_FRAME`], which with the default style
/// removes the fill, the stroke and the margin. /// removes the fill, the stroke and the margin.
/// ///
/// Default: `ui.visuals().button_frame`. /// Default: `ui.visuals().button_frame`.
#[inline] #[inline]
pub fn frame(mut self, frame: bool) -> Self { pub fn frame(mut self, frame: bool) -> Self {
self.frame = Some(frame); self.frame = Some(frame);
self.set_class(NO_FRAME_CLASS, !frame); self.set_class(Self::CLASS_NO_FRAME, !frame);
self self
} }
/// If `false`, the button will not have a frame when inactive. /// If `false`, the button will not have a frame when inactive.
/// ///
/// This adds the built-in [`BUTTON_NO_FRAME_WHEN_INACTIVE_CLASS`], which with the /// This adds the built-in [`Self::CLASS_NO_FRAME_WHEN_INACTIVE`], which with the
/// default style removes the fill and the stroke, but keeps the margin, so the button does /// default style removes the fill and the stroke, but keeps the margin, so the button does
/// not change size once the user interacts with it. /// not change size once the user interacts with it.
/// ///
@@ -188,7 +197,7 @@ impl<'a> Button<'a> {
/// has no effect. /// has no effect.
#[inline] #[inline]
pub fn frame_when_inactive(mut self, frame_when_inactive: bool) -> Self { pub fn frame_when_inactive(mut self, frame_when_inactive: bool) -> Self {
self.set_class(BUTTON_NO_FRAME_WHEN_INACTIVE_CLASS, !frame_when_inactive); self.set_class(Self::CLASS_NO_FRAME_WHEN_INACTIVE, !frame_when_inactive);
self self
} }
@@ -279,12 +288,12 @@ impl<'a> Button<'a> {
/// technologies (e.g. screen readers). Plain buttons that never call /// technologies (e.g. screen readers). Plain buttons that never call
/// `selected` are not announced as toggles. /// `selected` are not announced as toggles.
/// ///
/// When selected, [`SELECTED_CLASS`] is added. You should prefer calling this though over /// When selected, [`Self::CLASS_SELECTED`] is added. You should prefer calling this though over
/// just adding [`SELECTED_CLASS`] manually, since this also exposes accessibility information. /// just adding [`Self::CLASS_SELECTED`] manually, since this also exposes accessibility information.
#[inline] #[inline]
pub fn selected(mut self, selected: bool) -> Self { pub fn selected(mut self, selected: bool) -> Self {
self.selected = Some(selected); self.selected = Some(selected);
self.set_class(SELECTED_CLASS, selected); self.set_class(Self::CLASS_SELECTED, selected);
self self
} }
@@ -318,7 +327,7 @@ impl<'a> Button<'a> {
} = self; } = self;
// Min size height always equal or greater than interact size if not small // Min size height always equal or greater than interact size if not small
if !classes.has_class(SMALL_CLASS) { if !classes.has_class(Self::CLASS_SMALL) {
min_size.y = min_size.y.at_least(ui.spacing().interact_size.y); min_size.y = min_size.y.at_least(ui.spacing().interact_size.y);
} }
@@ -337,7 +346,7 @@ impl<'a> Button<'a> {
// An explicit `frame` call already updated the classes at the call site, preserving // An explicit `frame` call already updated the classes at the call site, preserving
// its order relative to user classes. Only apply the global default here. // its order relative to user classes. Only apply the global default here.
if frame.is_none() { if frame.is_none() {
classes.add_class_if(NO_FRAME_CLASS, !ui.visuals().button_frame); classes.add_class_if(Self::CLASS_NO_FRAME, !ui.visuals().button_frame);
} }
let id = ui.next_auto_id(); let id = ui.next_auto_id();