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

Fixes from review

This commit is contained in:
Lucas Meurer
2026-08-31 16:18:40 +02:00
parent 5d725fab5e
commit d6f507c448
6 changed files with 184 additions and 37 deletions

View File

@@ -372,7 +372,7 @@ impl ViewportRepaintInfo {
// ----------------------------------------------------------------------------
#[derive(Default)]
pub(crate) struct ContextImpl {
struct ContextImpl {
fonts: Option<Fonts>,
font_definitions: FontDefinitions,
@@ -414,7 +414,7 @@ pub(crate) struct ContextImpl {
loaders: Arc<Loaders>,
pub(crate) themes: theme::Themes,
themes: theme::Themes,
}
impl ContextImpl {
@@ -767,7 +767,7 @@ impl Context {
}
/// Do read-write (exclusive access) transaction on Context
pub(crate) fn write<R>(&self, writer: impl FnOnce(&mut ContextImpl) -> R) -> R {
fn write<R>(&self, writer: impl FnOnce(&mut ContextImpl) -> R) -> R {
writer(&mut self.0.write())
}
@@ -2107,7 +2107,10 @@ impl Context {
/// If a theme is already registered for this widget, this is a no-op (useful for `eframe::run_simple_native`).
///
/// If you want to add the theme anyway, use [`Self::replace_widget_theme`] instead.
#[cfg(feature = "experimental")]
///
/// The types you need to call this (e.g. `StyleProvider`) are only public
/// with the `experimental_theme` feature.
#[cfg_attr(not(feature = "experimental"), doc(hidden))]
pub fn add_widget_theme<S: WidgetStyle + 'static>(
&self,
theme: impl theme::StyleProvider<S> + Send + Sync + 'static,
@@ -2119,7 +2122,10 @@ impl Context {
///
/// Overwrite any theme already registered for the specified widget [`WidgetStyle`].
/// This allow to live edit a theme.
#[cfg(feature = "experimental")]
///
/// The types you need to call this (e.g. `StyleProvider`) are only public
/// with the `experimental_theme` feature.
#[cfg_attr(not(feature = "experimental"), doc(hidden))]
pub fn replace_widget_theme<S: WidgetStyle + 'static>(
&self,
theme: impl theme::StyleProvider<S> + Send + Sync + 'static,

View File

@@ -21,11 +21,9 @@ impl DefaultStyle {
/// [`Context::default`] does this. Any theme you register yourself
/// replaces the default one for that widget style.
pub fn register(ctx: &Context) {
ctx.write(|ctx| {
ctx.themes.register::<ButtonStyle>(Self, false);
ctx.themes.register::<SeparatorStyle>(Self, false);
ctx.themes.register::<CheckboxStyle>(Self, false);
});
ctx.add_widget_theme::<ButtonStyle>(Self);
ctx.add_widget_theme::<SeparatorStyle>(Self);
ctx.add_widget_theme::<CheckboxStyle>(Self);
}
}

View File

@@ -12,6 +12,8 @@ use crate::{Id, theme::StyleProvider, util::IdTypeMap, widget_style::WidgetStyle
///
/// A default provider is registered for every built-in style. Register your
/// own with [`crate::Context::add_widget_theme`] or [`crate::Context::replace_widget_theme`].
///
/// The [`crate::theme::DefaultStyle`] is registered in [`crate::Context::default`].
#[derive(Default)]
pub struct Themes {
themes: IdTypeMap,

View File

@@ -1,11 +1,152 @@
use std::{borrow::Cow, fmt};
use smallvec::SmallVec;
use std::borrow::{Borrow, Cow};
use std::fmt;
use std::sync::Arc;
use crate::TextBuffer as _;
/// A class is a static string identifier.
pub type ClassName = Cow<'static, str>;
/// A class, used to customize widget styling and behavior.
#[derive(Clone)]
pub struct ClassName(ClassNameInner);
#[derive(Clone)]
enum ClassNameInner {
Static(&'static str),
Owned(Arc<str>),
}
impl ClassName {
/// A class from a string known at compile time. This never allocates.
#[inline]
pub const fn from_static(class: &'static str) -> Self {
Self(ClassNameInner::Static(class))
}
/// A class from anything that converts into one.
#[inline]
pub fn new(class: impl Into<ClassName>) -> Self {
class.into()
}
/// The class as a string.
#[inline]
pub fn as_str(&self) -> &str {
match &self.0 {
ClassNameInner::Static(class) => class,
ClassNameInner::Owned(class) => class,
}
}
}
impl From<&'static str> for ClassName {
#[inline]
fn from(class: &'static str) -> Self {
Self::from_static(class)
}
}
impl From<String> for ClassName {
#[inline]
fn from(class: String) -> Self {
Self(ClassNameInner::Owned(class.into()))
}
}
impl From<&String> for ClassName {
#[inline]
fn from(class: &String) -> Self {
Self(ClassNameInner::Owned(class.as_str().into()))
}
}
impl From<Arc<str>> for ClassName {
#[inline]
fn from(class: Arc<str>) -> Self {
Self(ClassNameInner::Owned(class))
}
}
impl From<Cow<'static, str>> for ClassName {
#[inline]
fn from(class: Cow<'static, str>) -> Self {
match class {
Cow::Borrowed(class) => Self::from_static(class),
Cow::Owned(class) => class.into(),
}
}
}
impl From<&ClassName> for ClassName {
#[inline]
fn from(class: &ClassName) -> Self {
class.clone()
}
}
impl Borrow<str> for ClassName {
#[inline]
fn borrow(&self) -> &str {
self.as_str()
}
}
impl AsRef<str> for ClassName {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl std::ops::Deref for ClassName {
type Target = str;
#[inline]
fn deref(&self) -> &str {
self.as_str()
}
}
impl PartialEq for ClassName {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_str() == other.as_str()
}
}
impl Eq for ClassName {}
impl PartialEq<str> for ClassName {
#[inline]
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl PartialEq<&str> for ClassName {
#[inline]
fn eq(&self, other: &&str) -> bool {
self.as_str() == *other
}
}
impl std::hash::Hash for ClassName {
#[inline]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.as_str().hash(state);
}
}
impl fmt::Debug for ClassName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_str().fmt(f)
}
}
impl fmt::Display for ClassName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
/// Classes are string identifier that can be set on widget/Ui.
///
@@ -62,13 +203,13 @@ impl core::fmt::Display for Classes {
}
}
/// Any widgets supporting [`Classes`] must implement this trait
/// Any widgets supporting [`Classes`] must implement this trait.
pub trait HasClasses {
fn classes(&self) -> &Classes;
fn classes_mut(&mut self) -> &mut Classes;
/// Add the given class by consuming `self`
/// Add the given class by consuming `self`.
#[inline]
fn with_class(mut self, class: impl Into<ClassName>) -> Self
where
@@ -78,9 +219,7 @@ pub trait HasClasses {
self
}
/// Add all the given classes by consuming `self`
///
/// Useful to forward the classes of a composite widget to the widgets it is built from.
/// Add all the given classes by consuming `self`.
#[inline]
fn with_classes(mut self, classes: Classes) -> Self
where
@@ -90,7 +229,7 @@ pub trait HasClasses {
self
}
/// Add the given class by consuming `self` if the condition is true
/// Add the given class by consuming `self` if the condition is true.
#[inline]
fn with_class_if(mut self, class: impl Into<ClassName>, condition: bool) -> Self
where
@@ -100,7 +239,7 @@ pub trait HasClasses {
self
}
/// Add the given class in-place
/// Add the given class in-place.
#[inline]
fn add_class(&mut self, class: impl Into<ClassName>) -> &mut Self
where
@@ -110,13 +249,14 @@ pub trait HasClasses {
self
}
/// Add all the given classes.
#[inline]
fn add_classes(&mut self, classes: Classes) -> &mut Self {
self.classes_mut().classes.extend(classes.classes);
self
}
/// Add the given class in-place if the condition is true
/// Add the given class in-place if the condition is true.
#[inline]
fn add_class_if(&mut self, class: impl Into<ClassName>, condition: bool) -> &mut Self
where
@@ -126,7 +266,7 @@ pub trait HasClasses {
self
}
/// Add the given class in-place if `present`, remove it otherwise
/// Add the given class in-place if `present`, remove it otherwise.
///
/// Use this for a setter that takes a `bool`, so that the last call wins.
#[inline]
@@ -138,7 +278,7 @@ pub trait HasClasses {
self
}
/// Remove the given class in-place
/// Remove the given class in-place.
#[inline]
fn remove_class(&mut self, class: impl Into<ClassName>) -> &mut Self
where
@@ -148,13 +288,13 @@ pub trait HasClasses {
self
}
/// True if the class is present
/// True if the class is present.
#[inline]
fn has_class(&self, class: impl Into<ClassName>) -> bool {
self.classes().classes.contains(&class.into())
}
/// The list of class
/// The list of class.
fn as_slice(&self) -> &[ClassName] {
&self.classes().classes
}

View File

@@ -8,8 +8,10 @@ pub use self::classes::{ClassName, Classes, HasClasses};
/// Built-in classes shared by all widgets.
pub mod class {
use super::ClassName;
/// Present on every top-level [`crate::Ui`].
pub const ROOT: &str = "egui::root";
pub const ROOT: ClassName = ClassName::from_static("egui::root");
}
use core::fmt::Debug;

View File

@@ -2,7 +2,7 @@ use crate::{
Atom, AtomExt as _, AtomKind, AtomLayout, AtomLayoutResponse, Atoms, Color32, CornerRadius,
Image, IntoAtoms, NumExt as _, Response, Sense, Stroke, TextStyle, TextWrapMode, Ui, Vec2,
Widget, WidgetInfo, WidgetText, WidgetType,
widget_style::{ButtonStyle, Classes, HasClasses},
widget_style::{ButtonStyle, ClassName, Classes, HasClasses},
};
/// Clickable button with text.
@@ -38,20 +38,20 @@ pub struct Button<'a> {
impl<'a> Button<'a> {
/// Present on a selected button.
pub const CLASS_SELECTED: &'static str = "egui::selected";
pub const CLASS_SELECTED: ClassName = ClassName::from_static("egui::selected");
/// Present on a small button.
pub const CLASS_SMALL: &'static str = "egui::small";
pub const CLASS_SMALL: ClassName = ClassName::from_static("egui::small");
/// Present on a button that should have no frame at all.
pub const CLASS_NO_FRAME: &'static str = "egui::no_frame";
pub const CLASS_NO_FRAME: ClassName = ClassName::from_static("egui::no_frame");
/// Present on a button that should have a frame, even when the global default is frameless.
pub const CLASS_FRAME: &'static str = "egui::frame";
pub const CLASS_FRAME: ClassName = ClassName::from_static("egui::frame");
/// Present on a button that should have no frame while it is inactive.
pub const CLASS_HIDE_FRAME_WHEN_INACTIVE: &'static str =
"egui::button::hide_frame_when_inactive";
pub const CLASS_HIDE_FRAME_WHEN_INACTIVE: ClassName =
ClassName::from_static("egui::button::hide_frame_when_inactive");
pub fn new(atoms: impl IntoAtoms<'a>) -> Self {
Self {
@@ -168,9 +168,8 @@ impl<'a> Button<'a> {
/// This adds the built-in [`Self::CLASS_SMALL`], which with the default style removes the top and
/// bottom margin.
#[inline]
pub fn small(mut self) -> Self {
self.add_class(Self::CLASS_SMALL);
self
pub fn small(self) -> Self {
self.with_class(Self::CLASS_SMALL)
}
/// Turn off the frame