From b18070caefca9ca39b9484962eb2665d794604da Mon Sep 17 00:00:00 2001 From: Adrien Zianne Date: Tue, 21 Oct 2025 10:42:42 +0200 Subject: [PATCH] checkbox & cleanup --- crates/egui/src/style_trait.rs | 78 ++++--------------------- crates/egui/src/widgets/button.rs | 2 +- crates/egui/src/widgets/checkbox.rs | 12 +++- crates/egui/src/widgets/drag_value.rs | 13 ++--- crates/egui/src/widgets/label.rs | 11 +--- crates/egui/src/widgets/separator.rs | 15 ++++- examples/hello_world_simple/src/main.rs | 72 ++++------------------- 7 files changed, 50 insertions(+), 153 deletions(-) diff --git a/crates/egui/src/style_trait.rs b/crates/egui/src/style_trait.rs index cacf5ebe3..ecb7b8fbd 100644 --- a/crates/egui/src/style_trait.rs +++ b/crates/egui/src/style_trait.rs @@ -1,4 +1,3 @@ -use emath::Vec2; use epaint::{Color32, FontId, Shadow, Stroke, text::TextWrapMode}; use crate::{ @@ -36,9 +35,9 @@ pub struct CheckboxStyle { pub frame: Frame, /// Text next to it pub text: TextVisuals, - /// Box size + /// Checkbox size pub size: f32, - /// Check size + /// Checkmark size pub check_size: f32, /// Frame of the checkbox itself pub checkbox_frame: Frame, @@ -46,30 +45,6 @@ pub struct CheckboxStyle { pub stroke: Stroke, } -pub struct DragValueStyle { - /// Frame around - pub frame: Frame, - /// Text of the value - pub text: TextVisuals, - pub min_size: Vec2, -} - -pub struct HyperlinkStyle { - pub frame: Frame, - pub text: TextVisuals, - pub size: Vec2, - pub checkbox_frame: Frame, - pub stroke: Stroke, -} - -pub struct ImageStyle { - pub frame: Frame, - pub text: TextVisuals, - pub size: Vec2, - pub checkbox_frame: Frame, - pub stroke: Stroke, -} - pub struct LabelStyle { /// Frame around pub frame: Frame, @@ -79,32 +54,10 @@ pub struct LabelStyle { pub wrap_mode: TextWrapMode, } -pub struct RadioButtonStyle { - pub frame: Frame, - pub text: TextVisuals, - pub size: Vec2, - pub checkbox_frame: Frame, - pub stroke: Stroke, -} - pub struct SeparatorStyle { - pub size: f32, - pub stroke: Stroke, -} - -pub struct SliderStyle { - pub frame: Frame, - pub text: TextVisuals, - pub size: Vec2, - pub checkbox_frame: Frame, - pub stroke: Stroke, -} - -pub struct SpinnerStyle { - pub frame: Frame, - pub text: TextVisuals, - pub size: Vec2, - pub checkbox_frame: Frame, + /// How much space is allocated in the layout direction + pub spacing: f32, + /// How to paint it pub stroke: Stroke, } @@ -206,22 +159,11 @@ impl Style { } } - pub fn drag_value_style(&self, state: WidgetState) -> DragValueStyle { - let ws = self.widget_style(state); - DragValueStyle { - frame: ws.frame.inner_margin(self.spacing.button_padding), - min_size: self.spacing.interact_size, - text: ws.text, + pub fn separator_style(&self, state: WidgetState) -> SeparatorStyle { + let visuals = self.visuals.widgets.state(state); + SeparatorStyle { + spacing: 0.0, + stroke: visuals.fg_stroke, } } - - // pub fn hyperlink_style(&self, state: WidgetState) -> HyperlinkStyle {} - - // pub fn image_style(&self, state: WidgetState) -> ImageStyle {} - - // pub fn slider_style(&self, state: WidgetState) -> SliderStyle {} - - // pub fn separator_style(&self, state: WidgetState) -> SeparatorStyle {} - - // pub fn spinner_style(&self, state: WidgetState) -> SpinnerStyle {} } diff --git a/crates/egui/src/widgets/button.rs b/crates/egui/src/widgets/button.rs index 24ea33ab3..6b5e77b5f 100644 --- a/crates/egui/src/widgets/button.rs +++ b/crates/egui/src/widgets/button.rs @@ -284,7 +284,7 @@ impl<'a> Button<'a> { let text = layout.text().map(String::from); - // Get the widget style by reading the rect from the previous pass + // Get the widget style by reading the response from the previous pass let id = ui.next_auto_id(); let response: Option = ui.ctx().read_response(id); let state = response.map(|r| r.widget_state()).unwrap_or_default(); diff --git a/crates/egui/src/widgets/checkbox.rs b/crates/egui/src/widgets/checkbox.rs index 598fc15e0..d8458eeb1 100644 --- a/crates/egui/src/widgets/checkbox.rs +++ b/crates/egui/src/widgets/checkbox.rs @@ -1,3 +1,5 @@ +use emath::Rect; + use crate::{ Atom, AtomLayout, Atoms, Id, IntoAtoms, NumExt as _, Response, Sense, Shape, Ui, Vec2, Widget, WidgetInfo, WidgetType, epaint, pos2, @@ -55,7 +57,7 @@ impl Widget for Checkbox<'_> { indeterminate, } = self; - // Get the widget style by reading the rect from the previous pass + // Get the widget style by reading the response from the previous pass let id = ui.next_auto_id(); let response: Option = ui.ctx().read_response(id); let state = response.map(|r| r.widget_state()).unwrap_or_default(); @@ -109,7 +111,13 @@ impl Widget for Checkbox<'_> { let response = prepared.paint(ui); if let Some(rect) = response.rect(rect_id) { - let (small_icon_rect, big_icon_rect) = ui.spacing().icon_rectangles(rect); + let big_icon_rect = Rect::from_center_size( + pos2(rect.left() + icon_width / 2.0, rect.center().y), + Vec2::splat(style.size), + ); + let small_icon_rect = + Rect::from_center_size(big_icon_rect.center(), Vec2::splat(style.check_size)); + ui.painter().add(epaint::RectShape::new( big_icon_rect, style.checkbox_frame.corner_radius, diff --git a/crates/egui/src/widgets/drag_value.rs b/crates/egui/src/widgets/drag_value.rs index 1c4caf995..9515726c2 100644 --- a/crates/egui/src/widgets/drag_value.rs +++ b/crates/egui/src/widgets/drag_value.rs @@ -4,7 +4,7 @@ use std::{cmp::Ordering, ops::RangeInclusive}; use crate::{ Button, CursorIcon, Id, Key, MINUS_CHAR_STR, Modifiers, NumExt as _, Response, RichText, Sense, - TextEdit, TextWrapMode, Ui, Widget, WidgetInfo, emath, grid::State, text, + TextEdit, TextWrapMode, Ui, Widget, WidgetInfo, emath, text, }; // ---------------------------------------------------------------------------- @@ -447,10 +447,6 @@ impl Widget for DragValue<'_> { let id = ui.next_auto_id(); let is_slow_speed = shift && ui.ctx().is_being_dragged(id); - let response = ui.ctx().read_response(id); - let state = response.map(|r| r.widget_state()).unwrap_or_default(); - let style = ui.style().drag_value_style(state); - // The following ensures that when a `DragValue` receives focus, // it is immediately rendered in edit mode, rather than being rendered // in button mode for just one frame. This is important for @@ -564,14 +560,13 @@ impl Widget for DragValue<'_> { .clip_text(false) .horizontal_align(ui.layout().horizontal_align()) .vertical_align(ui.layout().vertical_align()) - .margin(style.frame.inner_margin) - .min_size(style.min_size) + .margin(ui.spacing().button_padding) + .min_size(ui.spacing().interact_size) .id(id) .desired_width( ui.spacing().interact_size.x - 2.0 * ui.spacing().button_padding.x, ) - .text_color(style.text.color) - .font(style.text.font_id), + .font(text_style), ); // Select all text when the edit gains focus. diff --git a/crates/egui/src/widgets/label.rs b/crates/egui/src/widgets/label.rs index a0805b7de..bd0d347fe 100644 --- a/crates/egui/src/widgets/label.rs +++ b/crates/egui/src/widgets/label.rs @@ -179,7 +179,7 @@ impl Label { return (pos, galley, response); } - // Get the widget style by reading the rect from the previous pass + // Get the widget style by reading the response from the previous pass let id = ui.next_auto_id(); let response: Option = ui.ctx().read_response(id); let state = response.map(|r| r.widget_state()).unwrap_or_default(); @@ -280,10 +280,6 @@ impl Widget for Label { let selectable = self.selectable; let show_tooltip_when_elided = self.show_tooltip_when_elided; - // Get the widget style by reading the rect from the previous pass - // let id = ui.next_auto_id(); - // let response: Option = ui.ctx().read_response(id); - let (galley_pos, galley, mut response) = self.layout_in_ui(ui); response .widget_info(|| WidgetInfo::labeled(WidgetType::Label, ui.is_enabled(), galley.text())); @@ -309,11 +305,6 @@ impl Widget for Label { ui.style().visuals.text_color() }; - // let underline = if response.has_focus() || response.highlighted() { - // Stroke::new(1.0, response_color) - // } else { - // Stroke::NONE - // }; let underline = style.text.underline; let selectable = selectable.unwrap_or_else(|| ui.style().interaction.selectable_labels); diff --git a/crates/egui/src/widgets/separator.rs b/crates/egui/src/widgets/separator.rs index 6fdd03b96..f130d9272 100644 --- a/crates/egui/src/widgets/separator.rs +++ b/crates/egui/src/widgets/separator.rs @@ -88,11 +88,22 @@ impl Separator { impl Widget for Separator { fn ui(self, ui: &mut Ui) -> Response { let Self { - spacing, + mut spacing, grow, is_horizontal_line, } = self; + // Get the widget style by reading the response from the previous pass + let id = ui.next_auto_id(); + let response: Option = ui.ctx().read_response(id); + let state = response.map(|r| r.widget_state()).unwrap_or_default(); + let style = ui.style().separator_style(state); + + // override the spacing if not set + if spacing == 0.0 && style.spacing != 0.0 { + spacing = style.spacing; + } + let is_horizontal_line = is_horizontal_line .unwrap_or_else(|| ui.is_grid() || !ui.layout().main_dir().is_horizontal()); @@ -111,7 +122,7 @@ impl Widget for Separator { let (rect, response) = ui.allocate_at_least(size, Sense::hover()); if ui.is_rect_visible(response.rect) { - let stroke = ui.visuals().widgets.noninteractive.bg_stroke; + let stroke = style.stroke; let painter = ui.painter(); if is_horizontal_line { painter.hline( diff --git a/examples/hello_world_simple/src/main.rs b/examples/hello_world_simple/src/main.rs index 8f3da8a44..4fe49a89d 100644 --- a/examples/hello_world_simple/src/main.rs +++ b/examples/hello_world_simple/src/main.rs @@ -1,10 +1,7 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release #![allow(rustdoc::missing_crate_level_docs)] // it's an example -use eframe::egui::{ - self, Atom, Checkbox, Color32, FontId, Label, RichText, Sense, Stroke, style::WidgetVisuals, - vec2, -}; +use eframe::egui; fn main() -> eframe::Result { env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`). @@ -17,67 +14,20 @@ fn main() -> eframe::Result { // Our application state: let mut name = "Arthur".to_owned(); let mut age = 42; - let mut is_adult = age >= 18; eframe::run_simple_native("My egui App", options, move |ctx, _frame| { egui::CentralPanel::default().show(ctx, |ui| { - ui.ctx().style_mut(|s| { - s.spacing.icon_width_inner = 8.0; - s.spacing.icon_width = 15.0; - s.spacing.button_padding = vec2(5.0, 5.0); - // s.spacing.interact_size.y = 30.0; - s.visuals.widgets.inactive = WidgetVisuals { - fg_stroke: Stroke::new(1.0, Color32::LIGHT_GRAY), - bg_stroke: Stroke::new(1.0, Color32::LIGHT_GRAY), - ..s.visuals.widgets.inactive - }; - s.visuals.widgets.active = WidgetVisuals { - fg_stroke: Stroke::new(1.0, Color32::LIGHT_BLUE), - ..s.visuals.widgets.inactive - }; - s.visuals.widgets.hovered = WidgetVisuals { - fg_stroke: Stroke::new(3.0, Color32::LIGHT_YELLOW), - ..s.visuals.widgets.inactive - }; - s.visuals.widgets.noninteractive = WidgetVisuals { - fg_stroke: Stroke::new(1.0, Color32::RED), - ..s.visuals.widgets.inactive - }; + ui.heading("My egui Application"); + ui.horizontal(|ui| { + let name_label = ui.label("Your name: "); + ui.text_edit_singleline(&mut name) + .labelled_by(name_label.id); }); - - // ui.heading("My egui Application"); - // ui.horizontal(|ui| { - // let name_label = ui.label("Your name: "); - // ui.text_edit_singleline(&mut name) - // .labelled_by(name_label.id); - // }); - // ui.add(egui::Slider::new(&mut age, 0..=120).text("age")); - // if ui.button("Increment").clicked() { - // age += 1; - // } - - // Button test - // ui.add(Button::new("no frame").frame(false)); - // ui.add(Button::new("small").small()); - // ui.add_enabled(false, Button::new("disabled")); - // ui.add(Button::new("no frame inactive").frame_when_inactive(false)); - - // ui.label("Normal text"); - // // Should not be affected by WidgetStyle - // ui.label( - // RichText::new("Unaffected by style") - // .font(FontId::monospace(15.0)) - // .color(Color32::KHAKI), - // ); - - // ui.add(Label::new("interaction click").sense(Sense::click())); - // ui.add(Label::new("focusable").sense(Sense::focusable_noninteractive())) - // .request_focus(); - - ui.add(Checkbox::new(&mut is_adult, "test")); - ui.add(Checkbox::new(&mut is_adult, "test")); - ui.add(Checkbox::new(&mut is_adult, Atom::default())); - ui.add(Checkbox::new(&mut is_adult, Atom::default()).indeterminate(true)); + ui.add(egui::Slider::new(&mut age, 0..=120).text("age")); + if ui.button("Increment").clicked() { + age += 1; + } + ui.label(format!("Hello '{name}', age {age}")); }); }) }