mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-24 10:08:00 -06:00
Merge PR #4178: fix(ui): the added-text editor keeps the box's alignment
This commit is contained in:
@@ -537,6 +537,16 @@ pub(crate) fn editor(ctx: &egui::Context, view: &mut DocView, info: &DocInfo, ad
|
||||
}
|
||||
let r = screen_rect(&xf, info, page, draft.rect);
|
||||
let source_rect = draft.index.map(|_| screen_rect(&xf, info, page, draft.style.rect));
|
||||
// At least 60 points wide, so a short box can still be clicked into. Where that is wider than
|
||||
// the box, the editor reaches past it away from the edge its text keeps (the right edge for
|
||||
// right-aligned text, both halves for centred), so the text stays where the page draws it.
|
||||
let width = r.width().max(60.0);
|
||||
let anchor = match draft.style.align {
|
||||
pdfcraft_engine::TextAlign::Center => 0.5,
|
||||
pdfcraft_engine::TextAlign::Right => 1.0,
|
||||
pdfcraft_engine::TextAlign::Left | pdfcraft_engine::TextAlign::Justify => 0.0,
|
||||
};
|
||||
let at = r.min - egui::vec2((width - r.width()) * anchor, 0.0);
|
||||
let background_ready = draft.index.is_some_and(|index| view.text_background.ready_added(page, index));
|
||||
let tokens = Tokens::get(ctx);
|
||||
let (mut commit, mut cancel, mut done) = (false, false, false);
|
||||
@@ -548,7 +558,7 @@ pub(crate) fn editor(ctx: &egui::Context, view: &mut DocView, info: &DocInfo, ad
|
||||
egui::Area::new(egui::Id::new(("added-text", view.id.0)))
|
||||
.fade_in(false)
|
||||
.order(egui::Order::Foreground)
|
||||
.fixed_pos(r.min)
|
||||
.fixed_pos(at)
|
||||
.constrain_to(view.viewport_rect())
|
||||
.constrain(false)
|
||||
.show(ctx, |ui| {
|
||||
@@ -560,13 +570,21 @@ pub(crate) fn editor(ctx: &egui::Context, view: &mut DocView, info: &DocInfo, ad
|
||||
// The box is white in every theme, so the caret must not follow the theme (pale in dark mode) (#655).
|
||||
ui.visuals_mut().text_cursor.stroke.color = crate::edit_text_ui::caret_color_on(Color32::WHITE);
|
||||
let [cr, cg, cb] = t.style.color.map(|v| (v.clamp(0.0, 1.0) * 255.0) as u8);
|
||||
// Laid out as the page draws it, so opening the box doesn't show it realigned.
|
||||
// shortcut: justified text is shown left-aligned here (TextEdit can't justify), until the editor gets its own layouter.
|
||||
let halign = match t.style.align {
|
||||
pdfcraft_engine::TextAlign::Center => egui::Align::Center,
|
||||
pdfcraft_engine::TextAlign::Right => egui::Align::Max,
|
||||
pdfcraft_engine::TextAlign::Left | pdfcraft_engine::TextAlign::Justify => egui::Align::Min,
|
||||
};
|
||||
ui.horizontal_top(|ui| {
|
||||
ui.spacing_mut().item_spacing.x = 4.0;
|
||||
let resp = ui.add(
|
||||
egui::TextEdit::multiline(&mut t.text)
|
||||
.font(font)
|
||||
.desired_width(r.width().max(60.0))
|
||||
.desired_width(width)
|
||||
.desired_rows(1)
|
||||
.horizontal_align(halign)
|
||||
.background_color(if background_ready { Color32::TRANSPARENT } else { Color32::WHITE })
|
||||
.text_color(Color32::from_rgb(cr, cg, cb))
|
||||
.hint_text(tl!("Type text"))
|
||||
|
||||
@@ -715,6 +715,55 @@ fn format_text_panel_sets_alignment_and_lists_planned_controls_disabled() {
|
||||
}
|
||||
|
||||
/// Where a mode bar tab is, by its label.
|
||||
/// Opening right-aligned added text to edit it shows it right-aligned, as the page does, not at
|
||||
/// the box's left edge, where it never was.
|
||||
#[test]
|
||||
fn the_text_editor_keeps_the_boxs_alignment() {
|
||||
let _gpu = gpu();
|
||||
let mut h = harness();
|
||||
let rect = [40.0, 195.0, 240.0, 210.0];
|
||||
let text = pdfcraft_engine::AddedText { rect, text: "Hi".into(), align: pdfcraft_engine::TextAlign::Right, ..Default::default() };
|
||||
assert!(h.state_mut().apply_edit(pdfcraft_engine::Edit::AddText { page: 0, text }));
|
||||
assert!(h.state_mut().execute("edit.text"));
|
||||
h.run_steps(3);
|
||||
let point = at(&h, 200.0, 195.0);
|
||||
click(&mut h, point);
|
||||
assert_eq!(h.state().views[0].content.draft.as_ref().and_then(|d| d.index), Some(0), "the editor opened on the text");
|
||||
h.run_steps(3);
|
||||
let r = item_on_screen(&h, rect);
|
||||
let pixels = h.render().unwrap();
|
||||
let left = ink(&pixels, egui::Rect::from_min_max(r.min, pos2(r.center().x, r.max.y)));
|
||||
let right = ink(&pixels, egui::Rect::from_min_max(pos2(r.center().x, r.min.y), r.max));
|
||||
assert!(left == 0 && right > 20, "the text is drawn at the right ({left} dark pixels left, {right} right)");
|
||||
}
|
||||
|
||||
/// A box narrower than the editor's least width (60 points on screen): right-aligned text stays
|
||||
/// at the box's right edge, not the wider editor's, which lies past it.
|
||||
#[test]
|
||||
fn the_text_editor_aligns_a_narrow_box_to_its_own_edge() {
|
||||
let _gpu = gpu();
|
||||
let mut h = harness();
|
||||
let rect = [40.0, 195.0, 60.0, 210.0];
|
||||
let text = pdfcraft_engine::AddedText { rect, text: "Hi".into(), align: pdfcraft_engine::TextAlign::Right, ..Default::default() };
|
||||
assert!(h.state_mut().apply_edit(pdfcraft_engine::Edit::AddText { page: 0, text }));
|
||||
assert!(h.state_mut().execute("edit.text"));
|
||||
h.run_steps(3);
|
||||
let point = at(&h, 50.0, 195.0);
|
||||
click(&mut h, point);
|
||||
assert_eq!(h.state().views[0].content.draft.as_ref().and_then(|d| d.index), Some(0), "the editor opened on the text");
|
||||
h.run_steps(3);
|
||||
let r = item_on_screen(&h, rect);
|
||||
assert!(r.width() < 60.0, "the box is narrower than the editor: {}", r.width());
|
||||
let pixels = h.render().unwrap();
|
||||
let inside = ink(&pixels, r);
|
||||
let edge = ink(&pixels, egui::Rect::from_min_max(pos2(r.right() - r.width() * 0.25, r.min.y), r.max));
|
||||
let past = ink(&pixels, egui::Rect::from_min_max(pos2(r.right() + 2.0, r.min.y), pos2(r.right() + 40.0, r.max.y)));
|
||||
assert!(
|
||||
inside > 20 && edge > 0 && past == 0,
|
||||
"the text is drawn in its box, up to its right edge ({inside} dark pixels in it, {edge} in its last quarter, {past} past it)"
|
||||
);
|
||||
}
|
||||
|
||||
fn mode_tab(h: &Harness<'static, PdfCraftApp>, label: &str) -> egui::Rect {
|
||||
h.get_all_by_role_and_label(egui::accesskit::Role::Button, label).map(|n| n.rect()).find(|r| r.bottom() < 120.0).expect("a mode tab")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user