From 7390932ab63be661c7ba3532cfda6f80bf5dabe6 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 4 Aug 2026 14:30:25 +0200 Subject: [PATCH] Fix widgets being styled with the wrong state on their first pass `Ui::widget_style` reads the widget state from the response of the previous pass. When there is no such response yet it fell back to `WidgetState::Inactive`, styling the widget wrong for one pass. Now we request a discard instead, so the widget is painted only once we know its state. Also make the default `SeparatorStyle` read `noninteractive.bg_stroke` directly: a separator is never interactive, so its stroke should not depend on the widget state. `inactive.bg_stroke` is `Stroke::NONE`, which made the separator invisible. Co-Authored-By: Claude Opus 5 (1M context) --- crates/egui/src/theme/default_style.rs | 6 +++--- crates/egui/src/theme/mod.rs | 17 +++++++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/crates/egui/src/theme/default_style.rs b/crates/egui/src/theme/default_style.rs index 4842f415d..2680297b4 100644 --- a/crates/egui/src/theme/default_style.rs +++ b/crates/egui/src/theme/default_style.rs @@ -143,12 +143,12 @@ impl StyleProvider for DefaultStyle { impl StyleProvider for DefaultStyle { fn style(&mut self, modifiers: &StyleArgs<'_>) -> SeparatorStyle { - let StyleArgs { ctx, .. } = modifiers; - let ws: BaseStyle = ctx.get_widget_style(modifiers); + let StyleArgs { style, .. } = modifiers; SeparatorStyle { spacing: 6.0, - stroke: ws.frame.stroke, + // A separator is never interactive, so its stroke doesn't depend on the widget state: + stroke: style.visuals.widgets.noninteractive.bg_stroke, } } } diff --git a/crates/egui/src/theme/mod.rs b/crates/egui/src/theme/mod.rs index 59641acc4..fbd253a1e 100644 --- a/crates/egui/src/theme/mod.rs +++ b/crates/egui/src/theme/mod.rs @@ -8,7 +8,7 @@ pub use self::{style_provider::StyleProvider, themes::Themes}; use crate::{ Ui, - widget_style::{Classes, StyleArgs, WidgetStyle}, + widget_style::{Classes, StyleArgs, WidgetState, WidgetStyle}, }; impl Ui { @@ -19,11 +19,16 @@ impl Ui { id: crate::Id, classes: &Classes, ) -> S { - // Fetch the current state of the widget - let state = self - .read_response(id) - .map(|r| r.widget_state()) - .unwrap_or_default(); + // Fetch the state of the widget, as it was in the previous pass + let state = if let Some(response) = self.read_response(id) { + response.widget_state() + } else { + // We don't know the state of the widget yet, so we would style it wrong. + // Discard this pass and style it correctly in the next one. + self.ctx() + .request_discard("Widget style depends on a widget response we don't have yet"); + WidgetState::default() + }; self.get_widget_style::(&StyleArgs { classes,