mirror of
https://github.com/emilk/egui.git
synced 2026-06-26 22:53:14 -04:00
Transfer to UiStack & rename to Classes
This commit is contained in:
@@ -15,8 +15,6 @@
|
||||
//!
|
||||
//! Add your [`crate::Window`]:s after any top-level panels.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use emath::{GuiRounding as _, Pos2};
|
||||
|
||||
use crate::{
|
||||
@@ -1029,12 +1027,10 @@ impl CentralPanel {
|
||||
.max_rect(panel_rect)
|
||||
.layout(Layout::top_down(Align::Min)),
|
||||
);
|
||||
let style_stack = ui.style_stack_mut().clone();
|
||||
panel_ui.set_clip_rect(panel_rect); // If we overflow, don't do so visibly (#4475)
|
||||
|
||||
let frame = frame.unwrap_or_else(|| Frame::central_panel(ui.style()));
|
||||
let response = frame.show(&mut panel_ui, |ui| {
|
||||
ui.style_stack_mut().parent = Some(Arc::new(style_stack));
|
||||
ui.expand_to_include_rect(ui.max_rect()); // Expand frame to include it all
|
||||
add_contents(ui)
|
||||
});
|
||||
|
||||
@@ -7,7 +7,6 @@ use emath::GuiRounding as _;
|
||||
use epaint::mutex::RwLock;
|
||||
|
||||
use crate::containers::menu;
|
||||
use crate::widget_style::{HasModifiers, StyleModifiers, StyleStack};
|
||||
use crate::{containers::*, ecolor::*, layout::*, placer::Placer, widgets::*, *};
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -90,9 +89,6 @@ pub struct Ui {
|
||||
/// This is an optimization, so we don't call [`Ui::remember_min_rect`] multiple times at the
|
||||
/// end of a [`Ui::scope`].
|
||||
min_rect_already_remembered: bool,
|
||||
|
||||
/// test
|
||||
style_stack: Arc<StyleStack>,
|
||||
}
|
||||
|
||||
/// Allow using [`Ui`] like a [`Context`].
|
||||
@@ -127,6 +123,7 @@ impl Ui {
|
||||
style,
|
||||
sense,
|
||||
accessibility_parent,
|
||||
classes: modifiers,
|
||||
} = ui_builder;
|
||||
|
||||
let layer_id = layer_id.unwrap_or_else(LayerId::background);
|
||||
@@ -142,6 +139,7 @@ impl Ui {
|
||||
let disabled = disabled || invisible;
|
||||
let style = style.unwrap_or_else(|| ctx.global_style());
|
||||
let sense = sense.unwrap_or_else(Sense::hover);
|
||||
let modifiers = modifiers.unwrap_or_default();
|
||||
|
||||
// Temporary use of user tags as proof of concept
|
||||
ui_stack_info = ui_stack_info.with_tag("root");
|
||||
@@ -154,11 +152,7 @@ impl Ui {
|
||||
parent: None,
|
||||
min_rect: placer.min_rect(),
|
||||
max_rect: placer.max_rect(),
|
||||
};
|
||||
|
||||
let style_stack = StyleStack {
|
||||
modifiers: StyleModifiers::default(),
|
||||
parent: None,
|
||||
classes: modifiers,
|
||||
};
|
||||
|
||||
let mut ui = Ui {
|
||||
@@ -174,7 +168,6 @@ impl Ui {
|
||||
stack: Arc::new(ui_stack),
|
||||
sense,
|
||||
min_rect_already_remembered: false,
|
||||
style_stack: Arc::new(style_stack),
|
||||
};
|
||||
|
||||
if let Some(accessibility_parent) = accessibility_parent {
|
||||
@@ -275,6 +268,7 @@ impl Ui {
|
||||
style,
|
||||
sense,
|
||||
accessibility_parent,
|
||||
classes: modifiers,
|
||||
} = ui_builder;
|
||||
|
||||
let mut painter = self.painter.clone();
|
||||
@@ -292,6 +286,7 @@ impl Ui {
|
||||
let sizing_pass = self.sizing_pass || sizing_pass;
|
||||
let style = style.unwrap_or_else(|| Arc::clone(&self.style));
|
||||
let sense = sense.unwrap_or_else(Sense::hover);
|
||||
let modifiers = modifiers.unwrap_or_default();
|
||||
|
||||
if sizing_pass {
|
||||
// During the sizing pass we want widgets to use up as little space as possible,
|
||||
@@ -323,11 +318,7 @@ impl Ui {
|
||||
parent: Some(Arc::clone(&self.stack)),
|
||||
min_rect: placer.min_rect(),
|
||||
max_rect: placer.max_rect(),
|
||||
};
|
||||
|
||||
let style_stack = StyleStack {
|
||||
modifiers: StyleModifiers::default(),
|
||||
parent: Some(Arc::clone(&self.style_stack)),
|
||||
classes: modifiers,
|
||||
};
|
||||
|
||||
let mut child_ui = Ui {
|
||||
@@ -343,7 +334,6 @@ impl Ui {
|
||||
stack: Arc::new(ui_stack),
|
||||
sense,
|
||||
min_rect_already_remembered: false,
|
||||
style_stack: Arc::new(style_stack),
|
||||
};
|
||||
|
||||
if disabled {
|
||||
@@ -3166,35 +3156,6 @@ impl Drop for Ui {
|
||||
}
|
||||
}
|
||||
|
||||
impl HasModifiers for Ui {
|
||||
fn modifiers(&self) -> &StyleModifiers {
|
||||
&self.style_stack.modifiers
|
||||
}
|
||||
|
||||
fn modifiers_mut(&mut self) -> &mut StyleModifiers {
|
||||
&mut self.style_stack_mut().modifiers
|
||||
}
|
||||
}
|
||||
|
||||
impl Ui {
|
||||
/// borrow internal [`StyleStack`].
|
||||
/// Allow the access to the modifiers of the ui's ancestors
|
||||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// # egui::__run_test_ui(|ui| {
|
||||
/// ui.style_stack().parent_has("test");
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn style_stack(&self) -> &StyleStack {
|
||||
&self.style_stack
|
||||
}
|
||||
|
||||
pub(crate) fn style_stack_mut(&mut self) -> &mut StyleStack {
|
||||
Arc::make_mut(&mut self.style_stack)
|
||||
}
|
||||
}
|
||||
|
||||
/// Show this rectangle to the user if certain debug options are set.
|
||||
#[cfg(debug_assertions)]
|
||||
fn register_rect(ui: &Ui, rect: Rect) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::{hash::Hash, sync::Arc};
|
||||
|
||||
use crate::ClosableTag;
|
||||
#[expect(unused_imports)] // Used for doclinks
|
||||
use crate::Ui;
|
||||
use crate::{ClosableTag, widget_style::Classes};
|
||||
use crate::{Id, LayerId, Layout, Rect, Sense, Style, UiStackInfo};
|
||||
|
||||
/// Build a [`Ui`] as the child of another [`Ui`].
|
||||
@@ -25,6 +25,7 @@ pub struct UiBuilder {
|
||||
pub style: Option<Arc<Style>>,
|
||||
pub sense: Option<Sense>,
|
||||
pub accessibility_parent: Option<Id>,
|
||||
pub classes: Option<Classes>,
|
||||
}
|
||||
|
||||
impl UiBuilder {
|
||||
@@ -191,4 +192,11 @@ impl UiBuilder {
|
||||
self.accessibility_parent = Some(parent_id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set classes for this [`Ui`].
|
||||
#[inline]
|
||||
pub fn classes(mut self, classes: Classes) -> Self {
|
||||
self.classes = Some(classes);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
use std::{any::Any, iter::FusedIterator};
|
||||
|
||||
use crate::widget_style::Classes;
|
||||
use crate::{Direction, Frame, Id, Rect};
|
||||
|
||||
/// What kind is this [`crate::Ui`]?
|
||||
@@ -210,6 +211,7 @@ pub struct UiStack {
|
||||
pub min_rect: Rect,
|
||||
pub max_rect: Rect,
|
||||
pub parent: Option<Arc<Self>>,
|
||||
pub classes: Classes,
|
||||
}
|
||||
|
||||
// these methods act on this specific node
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use std::{iter::FusedIterator, sync::Arc};
|
||||
use std::{borrow::Cow, fmt};
|
||||
|
||||
use emath::Vec2;
|
||||
use epaint::{Color32, FontId, Shadow, Stroke, text::TextWrapMode};
|
||||
|
||||
use crate::{
|
||||
Frame, Response, Style, TextStyle, Theme,
|
||||
Frame, Response, Style, TextBuffer as _, TextStyle,
|
||||
style::{WidgetVisuals, Widgets},
|
||||
};
|
||||
|
||||
@@ -109,8 +109,8 @@ impl Response {
|
||||
}
|
||||
|
||||
impl Style {
|
||||
pub fn widget_style(&self, modifier: &StyleModifiers) -> WidgetStyle {
|
||||
let visuals = self.visuals.widgets.state(modifier.state);
|
||||
pub fn widget_style(&self, _classes: &Classes, state: WidgetState) -> WidgetStyle {
|
||||
let visuals = self.visuals.widgets.state(state);
|
||||
let font_id = self.override_font_id.clone();
|
||||
WidgetStyle {
|
||||
frame: Frame {
|
||||
@@ -133,11 +133,11 @@ impl Style {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn button_style(&self, modifier: &StyleModifiers) -> ButtonStyle {
|
||||
let mut visuals = *self.visuals.widgets.state(modifier.state);
|
||||
let mut ws = self.widget_style(modifier);
|
||||
pub fn button_style(&self, classes: &Classes, state: WidgetState) -> ButtonStyle {
|
||||
let mut visuals = *self.visuals.widgets.state(state);
|
||||
let mut ws = self.widget_style(classes, state);
|
||||
|
||||
if modifier.has("selected") {
|
||||
if classes.has("selected") {
|
||||
visuals.weak_bg_fill = self.visuals.selection.bg_fill;
|
||||
visuals.bg_fill = self.visuals.selection.bg_fill;
|
||||
visuals.fg_stroke = self.visuals.selection.stroke;
|
||||
@@ -159,9 +159,9 @@ impl Style {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checkbox_style(&self, modifier: &StyleModifiers) -> CheckboxStyle {
|
||||
let visuals = self.visuals.widgets.state(modifier.state);
|
||||
let ws = self.widget_style(modifier);
|
||||
pub fn checkbox_style(&self, classes: &Classes, state: WidgetState) -> CheckboxStyle {
|
||||
let visuals = self.visuals.widgets.state(state);
|
||||
let ws = self.widget_style(classes, state);
|
||||
CheckboxStyle {
|
||||
frame: Frame::new(),
|
||||
checkbox_size: self.spacing.icon_width,
|
||||
@@ -177,8 +177,8 @@ impl Style {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn label_style(&self, modifier: &StyleModifiers) -> LabelStyle {
|
||||
let ws = self.widget_style(modifier);
|
||||
pub fn label_style(&self, classes: &Classes, state: WidgetState) -> LabelStyle {
|
||||
let ws = self.widget_style(classes, state);
|
||||
LabelStyle {
|
||||
frame: Frame {
|
||||
fill: ws.frame.fill,
|
||||
@@ -193,7 +193,7 @@ impl Style {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn separator_style(&self, _modifier: &StyleModifiers) -> SeparatorStyle {
|
||||
pub fn separator_style(&self, _classes: &Classes, _state: WidgetState) -> SeparatorStyle {
|
||||
let visuals = self.visuals.noninteractive();
|
||||
SeparatorStyle {
|
||||
spacing: 6.0,
|
||||
@@ -202,123 +202,93 @@ impl Style {
|
||||
}
|
||||
}
|
||||
|
||||
pub type WidgetStyleModifier = String;
|
||||
pub type ClassName = Cow<'static, str>;
|
||||
|
||||
/// For now we use Vec for the modifiers but later we could use `SmallVev` for performance
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct StyleModifiers {
|
||||
modifiers: Vec<WidgetStyleModifier>,
|
||||
theme: Option<Theme>,
|
||||
state: WidgetState,
|
||||
pub struct Classes {
|
||||
classes: Vec<ClassName>,
|
||||
}
|
||||
|
||||
impl StyleModifiers {
|
||||
/// Add multiples modifiers in one method and return the list for method chaining
|
||||
#[inline]
|
||||
pub fn with_modifiers(mut self, modifiers: &[WidgetStyleModifier]) -> Self {
|
||||
self.modifiers.append(&mut modifiers.to_vec());
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a single modifier and return the list for method chaining
|
||||
#[inline]
|
||||
pub fn with_modifier(mut self, modifier: impl Into<WidgetStyleModifier>) -> Self {
|
||||
self.modifiers.push(modifier.into());
|
||||
self
|
||||
}
|
||||
|
||||
impl Classes {
|
||||
/// Add a class to the list if the condition is true
|
||||
#[inline]
|
||||
pub fn add_if(&mut self, modifier: impl Into<WidgetStyleModifier>, condition: bool) {
|
||||
fn add_if(&mut self, class: impl Into<ClassName>, condition: bool) {
|
||||
if condition {
|
||||
self.modifiers.push(modifier.into());
|
||||
self.classes.push(class.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasClasses for Classes {
|
||||
fn classes(&self) -> &Classes {
|
||||
self
|
||||
}
|
||||
|
||||
fn classes_mut(&mut self) -> &mut Classes {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Classes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.classes.iter().for_each(|class| {
|
||||
let _ = f.write_str(class.as_str());
|
||||
});
|
||||
f.write_str("")
|
||||
}
|
||||
}
|
||||
|
||||
/// Any widgets supporting [`Classes`] must implement this trait
|
||||
pub trait HasClasses {
|
||||
fn classes(&self) -> &Classes;
|
||||
|
||||
fn classes_mut(&mut self) -> &mut Classes;
|
||||
|
||||
/// Add a class to the list and return the list for method chaining
|
||||
#[inline]
|
||||
pub fn with_if(mut self, modifier: impl Into<WidgetStyleModifier>, condition: bool) -> Self {
|
||||
self.add_if(modifier.into(), condition);
|
||||
fn with_class(mut self, class: impl Into<ClassName>) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.classes_mut().add_if(class.into(), true);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_class_if(mut self, class: impl Into<ClassName>, condition: bool) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.classes_mut().add_if(class.into(), condition);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn add_class(&mut self, class: impl Into<ClassName>) -> &mut Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.classes_mut().add_if(class.into(), true);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn add_class_if(&mut self, class: impl Into<ClassName>, condition: bool) -> &mut Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.classes_mut().add_if(class.into(), condition);
|
||||
self
|
||||
}
|
||||
|
||||
/// Return true if the modifier is present in the list
|
||||
pub fn has(&self, modifier: impl Into<WidgetStyleModifier>) -> bool {
|
||||
self.modifiers.contains(&modifier.into())
|
||||
}
|
||||
|
||||
pub fn with_theme(&mut self, theme: Theme) {
|
||||
self.theme = Some(theme);
|
||||
}
|
||||
|
||||
pub fn with_state(&mut self, state: WidgetState) {
|
||||
self.state = state;
|
||||
}
|
||||
|
||||
pub fn list(&self) -> Vec<WidgetStyleModifier> {
|
||||
self.modifiers.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Any widgets supporting [`StyleModifiers`] must implement this trait
|
||||
pub trait HasModifiers {
|
||||
fn modifiers(&self) -> &StyleModifiers;
|
||||
|
||||
fn modifiers_mut(&mut self) -> &mut StyleModifiers;
|
||||
|
||||
#[inline]
|
||||
fn with_modifier(mut self, modifier: impl Into<WidgetStyleModifier>) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.modifiers_mut().add_if(modifier.into(), true);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_modifier_if(mut self, modifier: impl Into<WidgetStyleModifier>, condition: bool) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.modifiers_mut().add_if(modifier.into(), condition);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn add_modifier(&mut self, modifier: impl Into<WidgetStyleModifier>) -> &mut Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.modifiers_mut().add_if(modifier.into(), true);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn add_modifier_if(
|
||||
&mut self,
|
||||
modifier: impl Into<WidgetStyleModifier>,
|
||||
condition: bool,
|
||||
) -> &mut Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.modifiers_mut().add_if(modifier.into(), condition);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn theme(mut self, theme: Theme) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.modifiers_mut().with_theme(theme);
|
||||
self
|
||||
fn has(&self, class: impl Into<ClassName>) -> bool {
|
||||
self.classes().classes.contains(&class.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a shortcut to add modifiers. The syntax is `add_modifiers`!(Name: (modifier1, modifier2, modifier3,)) for any number of modifiers
|
||||
#[macro_export]
|
||||
macro_rules! add_modifiers {
|
||||
macro_rules! define_modifiers {
|
||||
($trait_name:ident: ($( $name:ident )+),?) => {
|
||||
|
||||
pub trait $trait_name {
|
||||
@@ -333,67 +303,8 @@ macro_rules! add_modifiers {
|
||||
{
|
||||
#[inline]
|
||||
$(fn $name(mut self) -> Self {
|
||||
self.with_modifier(stringify!($name))
|
||||
self.with_class(stringify!($name))
|
||||
})?
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StyleStack {
|
||||
pub modifiers: StyleModifiers,
|
||||
pub parent: Option<Arc<Self>>,
|
||||
}
|
||||
|
||||
// these methods act on the entire stack
|
||||
impl StyleStack {
|
||||
/// Return an iterator that walks the stack from this node to the root.
|
||||
#[expect(clippy::iter_without_into_iter)]
|
||||
pub fn iter(&self) -> StyleStackIterator<'_> {
|
||||
StyleStackIterator { next: Some(self) }
|
||||
}
|
||||
|
||||
/// Check if any of the ancestor has the modifiers
|
||||
pub fn ancestors_have(&self, modifier: impl Into<WidgetStyleModifier>) -> bool {
|
||||
let modifier = modifier.into();
|
||||
self.iter()
|
||||
.any(|parent| parent.modifiers.has(modifier.clone()))
|
||||
}
|
||||
|
||||
/// Check if the direct parent has the modifiers
|
||||
pub fn parent_has(&self, modifier: impl Into<WidgetStyleModifier>) -> bool {
|
||||
if let Some(parent) = &self.parent {
|
||||
parent.modifiers.has(modifier)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parent_modifiers(&self) -> Option<&StyleModifiers> {
|
||||
self.parent.as_ref().map(|parent| &parent.modifiers)
|
||||
}
|
||||
|
||||
pub fn ancestors_modifiers(&self) -> Vec<&StyleModifiers> {
|
||||
self.iter().map(|f| &f.modifiers).collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator that walks up a stack of `StackFrame`s.
|
||||
///
|
||||
/// See [`StyleStack::iter`].
|
||||
pub struct StyleStackIterator<'a> {
|
||||
next: Option<&'a StyleStack>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for StyleStackIterator<'a> {
|
||||
type Item = &'a StyleStack;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let current = self.next;
|
||||
self.next = current.and_then(|style| style.parent.as_deref());
|
||||
current
|
||||
}
|
||||
}
|
||||
|
||||
impl FusedIterator for StyleStackIterator<'_> {}
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::{
|
||||
Atom, AtomExt as _, AtomKind, AtomLayout, AtomLayoutResponse, Color32, CornerRadius, Frame,
|
||||
Image, IntoAtoms, NumExt as _, Response, Sense, Stroke, TextStyle, TextWrapMode, Ui, Vec2,
|
||||
Widget, WidgetInfo, WidgetText, WidgetType,
|
||||
widget_style::{ButtonStyle, HasModifiers, StyleModifiers, WidgetState},
|
||||
widget_style::{ButtonStyle, Classes, HasClasses, WidgetState},
|
||||
};
|
||||
|
||||
/// Clickable button with text.
|
||||
@@ -38,7 +38,7 @@ pub struct Button<'a> {
|
||||
selected: bool,
|
||||
image_tint_follows_text_color: bool,
|
||||
limit_image_size: bool,
|
||||
modifiers: StyleModifiers,
|
||||
classes: Classes,
|
||||
}
|
||||
|
||||
impl<'a> Button<'a> {
|
||||
@@ -57,7 +57,7 @@ impl<'a> Button<'a> {
|
||||
selected: false,
|
||||
image_tint_follows_text_color: false,
|
||||
limit_image_size: false,
|
||||
modifiers: StyleModifiers::default(),
|
||||
classes: Classes::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,7 +275,7 @@ impl<'a> Button<'a> {
|
||||
selected,
|
||||
image_tint_follows_text_color,
|
||||
limit_image_size,
|
||||
mut modifiers,
|
||||
mut classes,
|
||||
} = self;
|
||||
|
||||
// Min size height always equal or greater than interact size if not small
|
||||
@@ -300,11 +300,10 @@ impl<'a> Button<'a> {
|
||||
let id = ui.next_auto_id();
|
||||
let response: Option<Response> = ui.ctx().read_response(id);
|
||||
let state = response.map(|r| r.widget_state()).unwrap_or_default();
|
||||
modifiers.with_state(state);
|
||||
|
||||
modifiers.add_if("selected", selected);
|
||||
classes.add_class_if("selected", selected);
|
||||
|
||||
let ButtonStyle { frame, text_style } = ui.style().button_style(&modifiers);
|
||||
let ButtonStyle { frame, text_style } = ui.style().button_style(&classes, state);
|
||||
|
||||
let mut button_padding = if has_frame_margin {
|
||||
frame.inner_margin
|
||||
@@ -376,12 +375,12 @@ impl Widget for Button<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl HasModifiers for Button<'_> {
|
||||
fn modifiers(&self) -> &StyleModifiers {
|
||||
&self.modifiers
|
||||
impl HasClasses for Button<'_> {
|
||||
fn classes(&self) -> &Classes {
|
||||
&self.classes
|
||||
}
|
||||
|
||||
fn modifiers_mut(&mut self) -> &mut StyleModifiers {
|
||||
&mut self.modifiers
|
||||
fn classes_mut(&mut self) -> &mut Classes {
|
||||
&mut self.classes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use emath::Rect;
|
||||
use crate::{
|
||||
Atom, AtomLayout, Atoms, Id, IntoAtoms, NumExt as _, Response, Sense, Shape, Ui, Vec2, Widget,
|
||||
WidgetInfo, WidgetType, epaint, pos2,
|
||||
widget_style::{CheckboxStyle, HasModifiers, StyleModifiers},
|
||||
widget_style::{CheckboxStyle, Classes, HasClasses},
|
||||
};
|
||||
|
||||
// TODO(emilk): allow checkbox without a text label
|
||||
@@ -24,7 +24,7 @@ pub struct Checkbox<'a> {
|
||||
checked: &'a mut bool,
|
||||
atoms: Atoms<'a>,
|
||||
indeterminate: bool,
|
||||
modifiers: StyleModifiers,
|
||||
classes: Classes,
|
||||
}
|
||||
|
||||
impl<'a> Checkbox<'a> {
|
||||
@@ -33,7 +33,7 @@ impl<'a> Checkbox<'a> {
|
||||
checked,
|
||||
atoms: atoms.into_atoms(),
|
||||
indeterminate: false,
|
||||
modifiers: StyleModifiers::default(),
|
||||
classes: Classes::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,14 +58,13 @@ impl Widget for Checkbox<'_> {
|
||||
checked,
|
||||
mut atoms,
|
||||
indeterminate,
|
||||
modifiers: mut modifier,
|
||||
classes,
|
||||
} = self;
|
||||
|
||||
// Get the widget style by reading the response from the previous pass
|
||||
let id = ui.next_auto_id();
|
||||
let response: Option<Response> = ui.ctx().read_response(id);
|
||||
let state = response.map(|r| r.widget_state()).unwrap_or_default();
|
||||
modifier.with_state(state);
|
||||
|
||||
let CheckboxStyle {
|
||||
check_size,
|
||||
@@ -74,7 +73,7 @@ impl Widget for Checkbox<'_> {
|
||||
frame,
|
||||
check_stroke,
|
||||
text_style,
|
||||
} = ui.style().checkbox_style(&modifier);
|
||||
} = ui.style().checkbox_style(&classes, state);
|
||||
|
||||
let mut min_size = Vec2::splat(ui.spacing().interact_size.y);
|
||||
min_size.y = min_size.y.at_least(checkbox_size);
|
||||
@@ -159,12 +158,12 @@ impl Widget for Checkbox<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl HasModifiers for Checkbox<'_> {
|
||||
fn modifiers(&self) -> &crate::widget_style::StyleModifiers {
|
||||
&self.modifiers
|
||||
impl HasClasses for Checkbox<'_> {
|
||||
fn classes(&self) -> &Classes {
|
||||
&self.classes
|
||||
}
|
||||
|
||||
fn modifiers_mut(&mut self) -> &mut crate::widget_style::StyleModifiers {
|
||||
&mut self.modifiers
|
||||
fn classes_mut(&mut self) -> &mut Classes {
|
||||
&mut self.classes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
Response, Sense, Ui, Vec2, Widget, vec2,
|
||||
widget_style::{HasModifiers, SeparatorStyle, StyleModifiers},
|
||||
widget_style::{Classes, HasClasses, SeparatorStyle},
|
||||
};
|
||||
|
||||
/// A visual separator. A horizontal or vertical line (depending on [`crate::Layout`]).
|
||||
@@ -19,7 +19,7 @@ pub struct Separator {
|
||||
spacing: Option<f32>,
|
||||
grow: f32,
|
||||
is_horizontal_line: Option<bool>,
|
||||
modifiers: StyleModifiers,
|
||||
classes: Classes,
|
||||
}
|
||||
|
||||
impl Default for Separator {
|
||||
@@ -28,7 +28,7 @@ impl Default for Separator {
|
||||
spacing: None,
|
||||
grow: 0.0,
|
||||
is_horizontal_line: None,
|
||||
modifiers: StyleModifiers::default(),
|
||||
classes: Classes::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,18 +96,17 @@ impl Widget for Separator {
|
||||
spacing,
|
||||
grow,
|
||||
is_horizontal_line,
|
||||
modifiers: mut modifier,
|
||||
classes,
|
||||
} = self;
|
||||
|
||||
// Get the widget style by reading the response from the previous pass
|
||||
let id = ui.next_auto_id();
|
||||
let response: Option<Response> = ui.ctx().read_response(id);
|
||||
let state = response.map(|r| r.widget_state()).unwrap_or_default();
|
||||
modifier.with_state(state);
|
||||
let SeparatorStyle {
|
||||
spacing: spacing_style,
|
||||
stroke,
|
||||
} = ui.style().separator_style(&modifier);
|
||||
} = ui.style().separator_style(&classes, state);
|
||||
|
||||
// override the spacing if not set
|
||||
let spacing = spacing.unwrap_or(spacing_style);
|
||||
@@ -150,12 +149,12 @@ impl Widget for Separator {
|
||||
}
|
||||
}
|
||||
|
||||
impl HasModifiers for Separator {
|
||||
fn modifiers(&self) -> &crate::widget_style::StyleModifiers {
|
||||
&self.modifiers
|
||||
impl HasClasses for Separator {
|
||||
fn classes(&self) -> &Classes {
|
||||
&self.classes
|
||||
}
|
||||
|
||||
fn modifiers_mut(&mut self) -> &mut crate::widget_style::StyleModifiers {
|
||||
&mut self.modifiers
|
||||
fn classes_mut(&mut self) -> &mut Classes {
|
||||
&mut self.classes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
|
||||
|
||||
use eframe::egui::{self, Button, Frame, Grid, Margin, Panel, widget_style::HasModifiers as _};
|
||||
use eframe::egui::{
|
||||
self, Frame, Grid, Margin, Panel, UiBuilder,
|
||||
widget_style::{Classes, HasClasses as _},
|
||||
};
|
||||
|
||||
fn main() -> eframe::Result {
|
||||
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
|
||||
@@ -14,31 +17,57 @@ fn main() -> eframe::Result {
|
||||
let mut style_code = "// future style code live editor".to_owned();
|
||||
|
||||
eframe::run_ui_native("My egui App", options, move |ui, _frame| {
|
||||
// Add a modifier to this ui
|
||||
ui.add_modifier("body");
|
||||
ui.label("body");
|
||||
egui::CentralPanel::default().show_inside(ui, |ui| {
|
||||
// Add a modifier to this ui
|
||||
ui.add_modifier("central panel");
|
||||
ui.label("central panel");
|
||||
ui.scope_builder(
|
||||
UiBuilder::new().classes(Classes::default().with_class("body")),
|
||||
|ui| {
|
||||
ui.label("body");
|
||||
ui.label("central panel");
|
||||
|
||||
Panel::left("style_code").show_inside(ui, |ui| {
|
||||
ui.add_modifier("style code editor");
|
||||
ui.label("style code editor");
|
||||
Panel::left("style_code").show_inside(ui, |ui| {
|
||||
ui.scope_builder(
|
||||
UiBuilder::new().classes(Classes::default().with_class("panel_left")),
|
||||
|ui| {
|
||||
ui.label("style code editor");
|
||||
|
||||
ui.text_edit_multiline(&mut style_code);
|
||||
});
|
||||
ui.text_edit_multiline(&mut style_code);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
Grid::new("grid").show(ui, |ui| {
|
||||
ui.add_modifier("grid");
|
||||
|
||||
Frame::new().inner_margin(Margin::same(10)).show(ui, |ui| {
|
||||
ui.add_modifier("frame1");
|
||||
|
||||
ui.add(Button::new("button1").with_modifier("button1"));
|
||||
ui.add(Button::new("button2").with_modifier("button2"));
|
||||
})
|
||||
});
|
||||
});
|
||||
Grid::new("grid").show(ui, |ui| {
|
||||
ui.scope_builder(
|
||||
UiBuilder::new().classes(Classes::default().with_class("grid")),
|
||||
|ui| {
|
||||
Frame::new().inner_margin(Margin::same(10)).show(ui, |ui| {
|
||||
ui.scope_builder(
|
||||
UiBuilder::new()
|
||||
.classes(Classes::default().with_class("frame1")),
|
||||
|ui| {
|
||||
let mut parent = Some(ui.stack());
|
||||
let mut text = vec![];
|
||||
let mut i: i32 = 0;
|
||||
while let Some(p) = parent {
|
||||
text.push(format!(
|
||||
"{}{}class : '{}', kind : {:?}",
|
||||
" ".repeat((2 * 0_i32.max(i - 1)) as usize),
|
||||
if i > 0 { "\\- " } else { "" },
|
||||
p.classes,
|
||||
p.kind()
|
||||
));
|
||||
i += 1;
|
||||
parent = p.parent.as_ref();
|
||||
}
|
||||
ui.label(format!(
|
||||
"Current hierarchy :\n{}",
|
||||
text.join("\n")
|
||||
));
|
||||
},
|
||||
)
|
||||
})
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user