"Save changes?" and Drawing Recovery appear at once (#2144)

An egui modal showed a frame late (its first frame only measured it) and
then faded in, dim included, over 0.2 s. These alerts answer a key press or
menu choice, so they now skip the fade, and their first show reruns the pass
with the measured size, which draws them in the first frame presented.
This commit is contained in:
aiongg
2026-10-25 12:07:54 -04:00
committed by GitHub
parent 0a14fc7d3a
commit 1d9ddd2406
6 changed files with 59 additions and 2 deletions
+1 -1
View File
@@ -150,7 +150,7 @@ pub fn show(app: &mut CadApp, ctx: &egui::Context) {
let mut open = None;
let mut discard = None;
let mut later = false;
egui::Modal::new(egui::Id::unique("cc_drawing_recovery")).show(ctx, |ui| {
crate::modal::instant(ctx, egui::Id::unique("cc_drawing_recovery")).show(ctx, |ui| {
ui.set_width(460.0);
ui.label(RichText::new("Drawing Recovery").strong());
ui.add_space(4.0);
+1 -1
View File
@@ -204,7 +204,7 @@ pub fn prompt(app: &mut CadApp, ctx: &egui::Context) {
};
let t = Tokens::get();
let mut choice = None;
egui::Modal::new(egui::Id::unique("cc_close_prompt")).show(ctx, |ui| {
crate::modal::instant(ctx, egui::Id::unique("cc_close_prompt")).show(ctx, |ui| {
ui.set_width(360.0);
ui.label(RichText::new(crate::tl!("CADCraft")).strong());
ui.add_space(4.0);
+1
View File
@@ -39,6 +39,7 @@ pub mod icons;
pub mod layers;
pub mod managers;
pub mod menus;
pub mod modal;
pub mod opening;
pub mod options;
pub mod palettes;
+14
View File
@@ -0,0 +1,14 @@
//! Alerts that appear in the frame that asks for them.
//!
//! An `egui::Modal` normally shows a frame late and then fades in over `animation_time`
//! (0.2 s): its area's first frame only measures it and draws nothing, and the dim behind it
//! fades with it. An alert that answers a key press or menu choice should be there at once.
/// A modal with no fade-in. On its first show it asks egui to run the pass again with the
/// measured size, so the first frame presented already draws it.
pub fn instant(ctx: &egui::Context, id: egui::Id) -> egui::Modal {
if egui::AreaState::load(ctx, id).is_none() {
ctx.request_discard("an instant modal's first show only measures it");
}
egui::Modal::new(id).area(egui::Modal::default_area(id).fade_in(false))
}
+41
View File
@@ -0,0 +1,41 @@
//! "Save changes?" is fully drawn, dim included, in the frame of the Close that asks it.
use cadcraft_engine::Session;
use cadcraft_ui_egui::{CadApp, Services, menus};
use egui::epaint::Shape;
use egui::vec2;
use egui_kittest::Harness;
use serde_json::json;
/// The opacity of each painted text containing `needle`.
fn text_opacity(shapes: &[egui::epaint::ClippedShape], needle: &str) -> Vec<f32> {
fn walk(shape: &Shape, needle: &str, out: &mut Vec<f32>) {
match shape {
Shape::Vec(shapes) => shapes.iter().for_each(|s| walk(s, needle, out)),
Shape::Text(text) if text.galley.text().contains(needle) => out.push(text.opacity_factor),
_ => {}
}
}
let mut out = Vec::new();
shapes.iter().for_each(|s| walk(&s.shape, needle, &mut out));
out
}
#[test]
fn close_prompt_is_fully_drawn_in_the_frame_of_the_menu_choice() {
let mut app = CadApp::new(Session::default(), Services::default());
app.ui.start_tab = false;
let mut h = Harness::builder().with_size(vec2(1280.0, 800.0)).build_ui_state(
|ui, app: &mut CadApp| {
app.logic(&ui.ctx().clone());
app.ui(ui);
},
app,
);
h.run_steps(5);
h.state_mut().run("line", json!({"points": [[0, 0], [10, 0]]})).unwrap();
h.run_steps(2);
menus::activate(h.state_mut(), "close");
h.step();
assert_eq!(text_opacity(&h.output().shapes, "Save changes to"), [1.0]);
}
+1
View File
@@ -12,6 +12,7 @@ mod drafting_spacing;
mod file_tab_titles;
mod gpu_viewport_stencil;
mod hidden_command_line;
mod instant_modals;
mod lisp_files;
mod measure_distance_snapping;
mod menubar_hover;