Only show id clash warnings in debug builds by default (#2930)
Change with `egui_ctx.options_mut(|opt| opt.warn_on_id_clash = true);`
This commit is contained in:
parent
d486c76a9f
commit
b8e798777d
|
|
@ -463,67 +463,72 @@ impl Context {
|
||||||
/// because that's where the warning will be painted. If you don't know what size to pick, just pick [`Vec2::ZERO`].
|
/// because that's where the warning will be painted. If you don't know what size to pick, just pick [`Vec2::ZERO`].
|
||||||
pub fn check_for_id_clash(&self, id: Id, new_rect: Rect, what: &str) {
|
pub fn check_for_id_clash(&self, id: Id, new_rect: Rect, what: &str) {
|
||||||
let prev_rect = self.frame_state_mut(move |state| state.used_ids.insert(id, new_rect));
|
let prev_rect = self.frame_state_mut(move |state| state.used_ids.insert(id, new_rect));
|
||||||
if let Some(prev_rect) = prev_rect {
|
|
||||||
// it is ok to reuse the same ID for e.g. a frame around a widget,
|
|
||||||
// or to check for interaction with the same widget twice:
|
|
||||||
if prev_rect.expand(0.1).contains_rect(new_rect)
|
|
||||||
|| new_rect.expand(0.1).contains_rect(prev_rect)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let show_error = |widget_rect: Rect, text: String| {
|
if !self.options(|opt| opt.warn_on_id_clash) {
|
||||||
let text = format!("🔥 {}", text);
|
return;
|
||||||
let color = self.style().visuals.error_fg_color;
|
}
|
||||||
let painter = self.debug_painter();
|
|
||||||
painter.rect_stroke(widget_rect, 0.0, (1.0, color));
|
|
||||||
|
|
||||||
let below = widget_rect.bottom() + 32.0 < self.input(|i| i.screen_rect.bottom());
|
let Some(prev_rect) = prev_rect else { return };
|
||||||
|
|
||||||
let text_rect = if below {
|
// it is ok to reuse the same ID for e.g. a frame around a widget,
|
||||||
painter.debug_text(
|
// or to check for interaction with the same widget twice:
|
||||||
widget_rect.left_bottom() + vec2(0.0, 2.0),
|
if prev_rect.expand(0.1).contains_rect(new_rect)
|
||||||
Align2::LEFT_TOP,
|
|| new_rect.expand(0.1).contains_rect(prev_rect)
|
||||||
color,
|
{
|
||||||
text,
|
return;
|
||||||
)
|
}
|
||||||
} else {
|
|
||||||
painter.debug_text(
|
|
||||||
widget_rect.left_top() - vec2(0.0, 2.0),
|
|
||||||
Align2::LEFT_BOTTOM,
|
|
||||||
color,
|
|
||||||
text,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(pointer_pos) = self.pointer_hover_pos() {
|
let show_error = |widget_rect: Rect, text: String| {
|
||||||
if text_rect.contains(pointer_pos) {
|
let text = format!("🔥 {}", text);
|
||||||
let tooltip_pos = if below {
|
let color = self.style().visuals.error_fg_color;
|
||||||
text_rect.left_bottom() + vec2(2.0, 4.0)
|
let painter = self.debug_painter();
|
||||||
} else {
|
painter.rect_stroke(widget_rect, 0.0, (1.0, color));
|
||||||
text_rect.left_top() + vec2(2.0, -4.0)
|
|
||||||
};
|
|
||||||
|
|
||||||
painter.error(
|
let below = widget_rect.bottom() + 32.0 < self.input(|i| i.screen_rect.bottom());
|
||||||
tooltip_pos,
|
|
||||||
format!("Widget is {} this text.\n\n\
|
let text_rect = if below {
|
||||||
|
painter.debug_text(
|
||||||
|
widget_rect.left_bottom() + vec2(0.0, 2.0),
|
||||||
|
Align2::LEFT_TOP,
|
||||||
|
color,
|
||||||
|
text,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
painter.debug_text(
|
||||||
|
widget_rect.left_top() - vec2(0.0, 2.0),
|
||||||
|
Align2::LEFT_BOTTOM,
|
||||||
|
color,
|
||||||
|
text,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(pointer_pos) = self.pointer_hover_pos() {
|
||||||
|
if text_rect.contains(pointer_pos) {
|
||||||
|
let tooltip_pos = if below {
|
||||||
|
text_rect.left_bottom() + vec2(2.0, 4.0)
|
||||||
|
} else {
|
||||||
|
text_rect.left_top() + vec2(2.0, -4.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
painter.error(
|
||||||
|
tooltip_pos,
|
||||||
|
format!("Widget is {} this text.\n\n\
|
||||||
ID clashes happens when things like Windows or CollapsingHeaders share names,\n\
|
ID clashes happens when things like Windows or CollapsingHeaders share names,\n\
|
||||||
or when things like Plot and Grid:s aren't given unique id_source:s.\n\n\
|
or when things like Plot and Grid:s aren't given unique id_source:s.\n\n\
|
||||||
Sometimes the solution is to use ui.push_id.",
|
Sometimes the solution is to use ui.push_id.",
|
||||||
if below { "above" } else { "below" })
|
if below { "above" } else { "below" })
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
let id_str = id.short_debug_format();
|
|
||||||
|
|
||||||
if prev_rect.min.distance(new_rect.min) < 4.0 {
|
|
||||||
show_error(new_rect, format!("Double use of {} ID {}", what, id_str));
|
|
||||||
} else {
|
|
||||||
show_error(prev_rect, format!("First use of {} ID {}", what, id_str));
|
|
||||||
show_error(new_rect, format!("Second use of {} ID {}", what, id_str));
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let id_str = id.short_debug_format();
|
||||||
|
|
||||||
|
if prev_rect.min.distance(new_rect.min) < 4.0 {
|
||||||
|
show_error(new_rect, format!("Double use of {} ID {}", what, id_str));
|
||||||
|
} else {
|
||||||
|
show_error(prev_rect, format!("First use of {} ID {}", what, id_str));
|
||||||
|
show_error(new_rect, format!("Second use of {} ID {}", what, id_str));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ pub(crate) struct AccessKitFrameState {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct FrameState {
|
pub(crate) struct FrameState {
|
||||||
/// All [`Id`]s that were used this frame.
|
/// All [`Id`]s that were used this frame.
|
||||||
/// Used to debug [`Id`] clashes of widgets.
|
|
||||||
pub(crate) used_ids: IdMap<Rect>,
|
pub(crate) used_ids: IdMap<Rect>,
|
||||||
|
|
||||||
/// Starts off as the screen_rect, shrinks as panels are added.
|
/// Starts off as the screen_rect, shrinks as panels are added.
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,11 @@ pub struct Options {
|
||||||
/// This can lead to fewer texture operations, but may use up the texture atlas quicker
|
/// This can lead to fewer texture operations, but may use up the texture atlas quicker
|
||||||
/// if you are changing [`Style::text_styles`], of have a lot of text styles.
|
/// if you are changing [`Style::text_styles`], of have a lot of text styles.
|
||||||
pub preload_font_glyphs: bool,
|
pub preload_font_glyphs: bool,
|
||||||
|
|
||||||
|
/// Check reusing of [`Id`]s, and show a visual warning on screen when one is found.
|
||||||
|
///
|
||||||
|
/// By default this is `true` in debug builds.
|
||||||
|
pub warn_on_id_clash: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Options {
|
impl Default for Options {
|
||||||
|
|
@ -130,6 +135,7 @@ impl Default for Options {
|
||||||
tessellation_options: Default::default(),
|
tessellation_options: Default::default(),
|
||||||
screen_reader: false,
|
screen_reader: false,
|
||||||
preload_font_glyphs: true,
|
preload_font_glyphs: true,
|
||||||
|
warn_on_id_clash: cfg!(debug_assertions),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,9 @@ impl super::Demo for IdTest {
|
||||||
|
|
||||||
impl super::View for IdTest {
|
impl super::View for IdTest {
|
||||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
|
// Make sure the warnings are on (by default they are only on in debug builds).
|
||||||
|
ui.ctx().options_mut(|opt| opt.warn_on_id_clash = true);
|
||||||
|
|
||||||
ui.heading("Name collision example");
|
ui.heading("Name collision example");
|
||||||
|
|
||||||
ui.label("\
|
ui.label("\
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue