Merge pull request #7062 from dotCooCoo/fix/para-style-options-height

Text styles: Paragraph Style Options keeps OK and Cancel on a small screen after a section switch
This commit is contained in:
BFlat
2026-11-13 14:17:31 +07:00
committed by GitHub
2 changed files with 66 additions and 5 deletions
@@ -979,7 +979,7 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
ui.separator();
let section = d.str("section");
let content_w = ui.available_width();
egui::ScrollArea::both()
let shown = egui::ScrollArea::both()
.id_salt(("para-style-sections", section))
.max_height(room)
.min_scrolled_height(room)
@@ -987,15 +987,17 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
.auto_shrink([false, true])
.show(ui, |ui| {
ui.vertical(|ui| section_body(ui, d));
})
.inner_rect
.height()
});
// `inner_rect` is the height offered before a short section shrinks the area to its content.
shown.inner_rect.height().min(shown.content_size.y)
});
let content_h = drawn.inner;
let was = ui.ctx().data(|m| m.get_temp::<f32>(content_id(ui)));
ui.ctx().data_mut(|m| m.insert_temp(content_id(ui), content_h));
// A new height lays the frame out again before it is shown, so the window is placed at its new
// size and OK and Cancel stay on the screen in the frame of a section switch.
if was.is_none_or(|was| (was - content_h).abs() > 0.5) {
ui.ctx().request_repaint();
ui.ctx().request_discard("paragraph style content height changed");
}
reset_button(ui, d);
match edited_attrs(d) {
@@ -578,3 +578,62 @@ fn every_section_draws_its_fields() {
}
}
}
/// The texts of one headless frame at a screen `w` by `h`, with their screen rects.
fn texts_at(ctx: &egui::Context, app: &mut VectorcraftApp, w: f32, h: f32) -> Vec<(String, egui::Rect)> {
fn collect(s: &egui::Shape, out: &mut Vec<(String, egui::Rect)>) {
match s {
egui::Shape::Text(t) => out.push((t.galley.text().to_string(), t.visual_bounding_rect())),
egui::Shape::Vec(v) => v.iter().for_each(|s| collect(s, out)),
_ => {}
}
}
let screen = egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(w, h));
let mut out = ctx.run_ui(egui::RawInput { screen_rect: Some(screen), ..Default::default() }, |ui| super::super::show(app, ui.ctx()));
out.textures_delta.clear();
let mut texts = vec![];
for c in &out.shapes {
collect(&c.shape, &mut texts);
}
texts
}
/// Going from a shorter section to a longer one keeps OK and Cancel on a small screen in the first
/// frame after the switch, not only once the window has measured itself again.
#[test]
fn switching_to_a_long_section_keeps_the_buttons_on_a_small_screen() {
let mut app = app();
let mut attrs: Value = serde_json::from_str(KEPT).unwrap();
for (key, value) in [
("right_indent", json!(4.0)),
("first_line_indent", json!(12.0)),
("space_after", json!(6.0)),
("composer", json!("singleLine")),
("roman_hanging", json!(true)),
("hyphenate", json!(true)),
("justification", json!({"auto_leading": 150.0})),
("korean_line_break_anywhere", json!(true)),
] {
attrs[key] = value;
}
app.run("paraStyle.new", json!({"name": "Body", "attrs": attrs})).unwrap();
app.run("ui.paraStyleOptions", json!({"name": "Body"})).unwrap();
for h in [500.0, 560.0, 640.0, 720.0] {
for to in SECTIONS {
for from in SECTIONS.into_iter().filter(|s| *s != to) {
let ctx = egui::Context::default();
crate::theme::install_fonts(&ctx);
set(&mut app, "section", json!(from));
for _ in 0..5 {
let _ = texts_at(&ctx, &mut app, 900.0, h);
}
set(&mut app, "section", json!(to));
let texts = texts_at(&ctx, &mut app, 900.0, h);
for label in ["OK", "Cancel"] {
let r = texts.iter().find(|(text, _)| text == label).unwrap_or_else(|| panic!("{label} is drawn")).1;
assert!(r.bottom() <= h + 1.0, "{label} stays on a {h}-point screen going from {from} to {to}: {r:?}");
}
}
}
}
}