Show the innermost debug rectangle when pressing all modifier keys (#4782)
This is usually what the user is interested in.
This commit is contained in:
parent
ad597a8491
commit
143119943d
|
@ -1942,6 +1942,10 @@ impl Context {
|
|||
paint_widget(widget, "drag", Color32::GREEN);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(debug_rect) = self.frame_state_mut(|fs| fs.debug_rect.take()) {
|
||||
debug_rect.paint(&self.debug_painter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,99 @@ pub struct AccessKitFrameState {
|
|||
pub parent_stack: Vec<Id>,
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
#[derive(Clone)]
|
||||
pub struct DebugRect {
|
||||
pub rect: Rect,
|
||||
pub callstack: String,
|
||||
pub is_clicking: bool,
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
impl DebugRect {
|
||||
pub fn paint(self, painter: &Painter) {
|
||||
let Self {
|
||||
rect,
|
||||
callstack,
|
||||
is_clicking,
|
||||
} = self;
|
||||
|
||||
let ctx = painter.ctx();
|
||||
|
||||
// Paint rectangle around widget:
|
||||
{
|
||||
// Print width and height:
|
||||
let text_color = if ctx.style().visuals.dark_mode {
|
||||
Color32::WHITE
|
||||
} else {
|
||||
Color32::BLACK
|
||||
};
|
||||
painter.debug_text(
|
||||
rect.left_center() + 2.0 * Vec2::LEFT,
|
||||
Align2::RIGHT_CENTER,
|
||||
text_color,
|
||||
format!("H: {:.1}", rect.height()),
|
||||
);
|
||||
painter.debug_text(
|
||||
rect.center_top(),
|
||||
Align2::CENTER_BOTTOM,
|
||||
text_color,
|
||||
format!("W: {:.1}", rect.width()),
|
||||
);
|
||||
|
||||
// Paint rect:
|
||||
let rect_fg_color = if is_clicking {
|
||||
Color32::WHITE
|
||||
} else {
|
||||
Color32::LIGHT_BLUE
|
||||
};
|
||||
let rect_bg_color = Color32::BLUE.gamma_multiply(0.5);
|
||||
painter.rect(rect, 0.0, rect_bg_color, (1.0, rect_fg_color));
|
||||
}
|
||||
|
||||
if !callstack.is_empty() {
|
||||
let font_id = FontId::monospace(12.0);
|
||||
let text = format!("{callstack}\n\n(click to copy)");
|
||||
let text_color = Color32::WHITE;
|
||||
let galley = painter.layout_no_wrap(text, font_id, text_color);
|
||||
|
||||
// Position the text either under or above:
|
||||
let screen_rect = ctx.screen_rect();
|
||||
let y = if galley.size().y <= rect.top() {
|
||||
// Above
|
||||
rect.top() - galley.size().y - 16.0
|
||||
} else {
|
||||
// Below
|
||||
rect.bottom()
|
||||
};
|
||||
|
||||
let y = y
|
||||
.at_most(screen_rect.bottom() - galley.size().y)
|
||||
.at_least(0.0);
|
||||
|
||||
let x = rect
|
||||
.left()
|
||||
.at_most(screen_rect.right() - galley.size().x)
|
||||
.at_least(0.0);
|
||||
let text_pos = pos2(x, y);
|
||||
|
||||
let text_bg_color = Color32::from_black_alpha(180);
|
||||
let text_rect_stroke_color = if is_clicking {
|
||||
Color32::WHITE
|
||||
} else {
|
||||
text_bg_color
|
||||
};
|
||||
let text_rect = Rect::from_min_size(text_pos, galley.size());
|
||||
painter.rect(text_rect, 0.0, text_bg_color, (1.0, text_rect_stroke_color));
|
||||
painter.galley(text_pos, galley, text_color);
|
||||
|
||||
if is_clicking {
|
||||
ctx.copy_text(callstack);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// State that is collected during a frame, then saved for the next frame,
|
||||
/// and then cleared.
|
||||
///
|
||||
|
@ -99,7 +192,7 @@ pub struct FrameState {
|
|||
pub highlight_next_frame: IdSet,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub has_debug_viewed_this_frame: bool,
|
||||
pub debug_rect: Option<DebugRect>,
|
||||
}
|
||||
|
||||
impl Default for FrameState {
|
||||
|
@ -119,7 +212,7 @@ impl Default for FrameState {
|
|||
highlight_next_frame: Default::default(),
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
has_debug_viewed_this_frame: false,
|
||||
debug_rect: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +235,7 @@ impl FrameState {
|
|||
highlight_next_frame,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
has_debug_viewed_this_frame,
|
||||
debug_rect,
|
||||
} = self;
|
||||
|
||||
used_ids.clear();
|
||||
|
@ -157,7 +250,7 @@ impl FrameState {
|
|||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
*has_debug_viewed_this_frame = false;
|
||||
*debug_rect = None;
|
||||
}
|
||||
|
||||
#[cfg(feature = "accesskit")]
|
||||
|
|
|
@ -106,7 +106,7 @@
|
|||
//!
|
||||
//! `egui` uses logical _points_ as its coordinate system.
|
||||
//! Those related to physical _pixels_ by the `pixels_per_point` scale factor.
|
||||
//! For example, a high-dpi screeen can have `pixels_per_point = 2.0`,
|
||||
//! For example, a high-dpi screen can have `pixels_per_point = 2.0`,
|
||||
//! meaning there are two physical screen pixels for each logical point.
|
||||
//!
|
||||
//! Angles are in radians, and are measured clockwise from the X-axis, which has angle=0.
|
||||
|
|
|
@ -727,7 +727,7 @@ pub struct Interaction {
|
|||
|
||||
/// Can the user select text that span multiple labels?
|
||||
///
|
||||
/// The default is `true`, but text seelction can be slightly glitchy,
|
||||
/// The default is `true`, but text selection can be slightly glitchy,
|
||||
/// so you may want to disable it.
|
||||
pub multi_widget_text_select: bool,
|
||||
}
|
||||
|
|
|
@ -2599,110 +2599,50 @@ fn register_rect(ui: &Ui, rect: Rect) {
|
|||
return;
|
||||
}
|
||||
|
||||
if ui.ctx().frame_state(|o| o.has_debug_viewed_this_frame) {
|
||||
return;
|
||||
}
|
||||
|
||||
if !ui.rect_contains_pointer(rect) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We only show one debug rectangle, or things get confusing:
|
||||
ui.ctx()
|
||||
.frame_state_mut(|o| o.has_debug_viewed_this_frame = true);
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
let is_clicking = ui.input(|i| i.pointer.could_any_button_be_click());
|
||||
|
||||
// Use the debug-painter to avoid clip rect,
|
||||
// otherwise the content of the widget may cover what we paint here!
|
||||
let painter = ui.ctx().debug_painter();
|
||||
|
||||
// Paint rectangle around widget:
|
||||
{
|
||||
// Print width and height:
|
||||
let text_color = if ui.visuals().dark_mode {
|
||||
Color32::WHITE
|
||||
} else {
|
||||
Color32::BLACK
|
||||
};
|
||||
painter.debug_text(
|
||||
rect.left_center() + 2.0 * Vec2::LEFT,
|
||||
Align2::RIGHT_CENTER,
|
||||
text_color,
|
||||
format!("H: {:.1}", rect.height()),
|
||||
);
|
||||
painter.debug_text(
|
||||
rect.center_top(),
|
||||
Align2::CENTER_BOTTOM,
|
||||
text_color,
|
||||
format!("W: {:.1}", rect.width()),
|
||||
);
|
||||
|
||||
// Paint rect:
|
||||
let rect_fg_color = if is_clicking {
|
||||
Color32::WHITE
|
||||
} else {
|
||||
Color32::LIGHT_BLUE
|
||||
};
|
||||
let rect_bg_color = Color32::BLUE.gamma_multiply(0.5);
|
||||
painter.rect(rect, 0.0, rect_bg_color, (1.0, rect_fg_color));
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
if debug.hover_shows_next {
|
||||
ui.placer.debug_paint_cursor(&painter, "next");
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
#[cfg(feature = "callstack")]
|
||||
let callstack = crate::callstack::capture();
|
||||
|
||||
#[cfg(not(feature = "callstack"))]
|
||||
let callstack = String::default();
|
||||
|
||||
if !callstack.is_empty() {
|
||||
let font_id = FontId::monospace(12.0);
|
||||
let text = format!("{callstack}\n\n(click to copy)");
|
||||
let text_color = Color32::WHITE;
|
||||
let galley = painter.layout_no_wrap(text, font_id, text_color);
|
||||
// We only show one debug rectangle, or things get confusing:
|
||||
let debug_rect = frame_state::DebugRect {
|
||||
rect,
|
||||
callstack,
|
||||
is_clicking,
|
||||
};
|
||||
|
||||
// Position the text either under or above:
|
||||
let screen_rect = ui.ctx().screen_rect();
|
||||
let y = if galley.size().y <= rect.top() {
|
||||
// Above
|
||||
rect.top() - galley.size().y - 16.0
|
||||
let mut kept = false;
|
||||
ui.ctx().frame_state_mut(|fs| {
|
||||
if let Some(final_debug_rect) = &mut fs.debug_rect {
|
||||
// or maybe pick the one with deepest callstack?
|
||||
if final_debug_rect.rect.contains_rect(rect) {
|
||||
*final_debug_rect = debug_rect;
|
||||
kept = true;
|
||||
}
|
||||
} else {
|
||||
// Below
|
||||
rect.bottom()
|
||||
};
|
||||
|
||||
let y = y
|
||||
.at_most(screen_rect.bottom() - galley.size().y)
|
||||
.at_least(0.0);
|
||||
|
||||
let x = rect
|
||||
.left()
|
||||
.at_most(screen_rect.right() - galley.size().x)
|
||||
.at_least(0.0);
|
||||
let text_pos = pos2(x, y);
|
||||
|
||||
let text_bg_color = Color32::from_black_alpha(180);
|
||||
let text_rect_stroke_color = if is_clicking {
|
||||
Color32::WHITE
|
||||
} else {
|
||||
text_bg_color
|
||||
};
|
||||
let text_rect = Rect::from_min_size(text_pos, galley.size());
|
||||
painter.rect(text_rect, 0.0, text_bg_color, (1.0, text_rect_stroke_color));
|
||||
painter.galley(text_pos, galley, text_color);
|
||||
|
||||
if ui.input(|i| i.pointer.any_click()) {
|
||||
ui.ctx().copy_text(callstack);
|
||||
fs.debug_rect = Some(debug_rect);
|
||||
kept = true;
|
||||
}
|
||||
});
|
||||
if !kept {
|
||||
return;
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
// Use the debug-painter to avoid clip rect,
|
||||
// otherwise the content of the widget may cover what we paint here!
|
||||
let painter = ui.ctx().debug_painter();
|
||||
|
||||
if debug.hover_shows_next {
|
||||
ui.placer.debug_paint_cursor(&painter, "next");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -713,7 +713,7 @@ fn quadratic_for_each_local_extremum<F: FnMut(f32)>(p0: f32, p1: f32, p2: f32, c
|
|||
|
||||
fn cubic_for_each_local_extremum<F: FnMut(f32)>(p0: f32, p1: f32, p2: f32, p3: f32, cb: &mut F) {
|
||||
// See www.faculty.idc.ac.il/arik/quality/appendixa.html for an explanation
|
||||
// A cubic Bézier curve can be derivated by the following equation:
|
||||
// A cubic Bézier curve can be derived by the following equation:
|
||||
// B'(t) = 3(1-t)^2(p1-p0) + 6(1-t)t(p2-p1) + 3t^2(p3-p2) or
|
||||
// f(x) = a * x² + b * x + c
|
||||
let a = 3.0 * (p3 + 3.0 * (p1 - p2) - p0);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
//!
|
||||
//! `epaint` uses logical _points_ as its coordinate system.
|
||||
//! Those related to physical _pixels_ by the `pixels_per_point` scale factor.
|
||||
//! For example, a high-dpi screeen can have `pixels_per_point = 2.0`,
|
||||
//! For example, a high-dpi screen can have `pixels_per_point = 2.0`,
|
||||
//! meaning there are two physical screen pixels for each logical point.
|
||||
//!
|
||||
//! Angles are in radians, and are measured clockwise from the X-axis, which has angle=0.
|
||||
|
|
|
@ -42,7 +42,7 @@ disallowed-types = [
|
|||
# { path = "std::path::PathBuf", reason = "Can't read/write files on web" }, // TODO(emilk): consider banning Path on wasm
|
||||
]
|
||||
|
||||
# Allow-list of words for markdown in dosctrings https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
|
||||
# Allow-list of words for markdown in docstrings https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
|
||||
doc-valid-idents = [
|
||||
# You must also update the same list in the root `clippy.toml`!
|
||||
"AccessKit",
|
||||
|
|
Loading…
Reference in New Issue