mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-02 00:36:46 +00:00
Merge PR #3862: M7: open the paragraph editor without a fade-in
crates/ui-egui/src/edit_text_ui.rs: #3862's Area builder with fade_in(false), keeping the reveal/look locals and their uses after the Area (#3952, #3863). crates/ui-egui/tests/editing.rs: kept all new tests.
This commit is contained in:
commit
2a3482c951
5 files changed
+72
-8
No files matched your search
@@ -523,7 +523,9 @@ pub(crate) fn editor(ctx: &egui::Context, view: &mut DocView, info: &DocInfo, ad
|
||||
let (mut commit, mut cancel, mut done) = (false, false, false);
|
||||
let mut undrawable = None;
|
||||
let memo = &view.content.undrawable;
|
||||
egui::Area::new(egui::Id::new(("added-text", view.id.0))).order(egui::Order::Foreground).fixed_pos(r.min).constrain(false).show(ctx, |ui| {
|
||||
// Shown at once, like the paragraph editor: a fade-in shows the page's copy through it.
|
||||
let area = egui::Area::new(egui::Id::new(("added-text", view.id.0))).fade_in(false);
|
||||
area.order(egui::Order::Foreground).fixed_pos(r.min).constrain(false).show(ctx, |ui| {
|
||||
let Some(t) = view.content.draft.as_mut() else { return };
|
||||
ui.set_width(r.width() + 64.0);
|
||||
if let Some(source_rect) = source_rect.filter(|_| !background_ready) {
|
||||
|
||||
@@ -1531,9 +1531,12 @@ pub(crate) fn overlay(ctx: &egui::Context, view: &mut DocView, info: &DocInfo) -
|
||||
let mut done = None;
|
||||
let mut reveal = false;
|
||||
let mut look = None;
|
||||
egui::Area::new(egui::Id::new("edit-text-line")).order(egui::Order::Foreground).fixed_pos(Pos2::new(ed.rect.left(), ed.rect.top())).show(
|
||||
ctx,
|
||||
|ui| {
|
||||
// No fade-in: while it faded, the page's own copy of the text showed through the cover.
|
||||
egui::Area::new(egui::Id::new("edit-text-line"))
|
||||
.order(egui::Order::Foreground)
|
||||
.fade_in(false)
|
||||
.fixed_pos(Pos2::new(ed.rect.left(), ed.rect.top()))
|
||||
.show(ctx, |ui| {
|
||||
// The editor opens at the source size. Once text changes, show the real draft
|
||||
// extent: single rows grow toward the page edge, paragraphs rewrap at their
|
||||
// source width, and the visible frame grows/shrinks vertically with their rows.
|
||||
@@ -1626,8 +1629,7 @@ pub(crate) fn overlay(ctx: &egui::Context, view: &mut DocView, info: &DocInfo) -
|
||||
done = Some(true);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
if reveal {
|
||||
view.text_background.reveal();
|
||||
}
|
||||
|
||||
@@ -706,7 +706,9 @@ pub(crate) fn type_box(ctx: &egui::Context, view: &mut DocView, info: &DocInfo,
|
||||
let zoom = xf.rect.width() / xf.pw.max(1.0);
|
||||
let mut commit = false;
|
||||
let mut cancel = false;
|
||||
egui::Area::new(egui::Id::new(("fill-text", view.id.0))).order(egui::Order::Foreground).fixed_pos(pos).show(ctx, |ui| {
|
||||
// Shown at once, like the paragraph editor: a fade-in shows the page's copy through it.
|
||||
let area = egui::Area::new(egui::Id::new(("fill-text", view.id.0))).fade_in(false);
|
||||
area.order(egui::Order::Foreground).fixed_pos(pos).show(ctx, |ui| {
|
||||
let Some(t) = view.fill_text.as_mut() else { return };
|
||||
// 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);
|
||||
|
||||
@@ -503,7 +503,9 @@ pub(crate) fn overlay(ctx: &egui::Context, view: &mut DocView, info: &DocInfo, f
|
||||
match f.kind {
|
||||
FormFieldKind::Text => {
|
||||
let multiline = f.has(field_flags::MULTILINE);
|
||||
egui::Area::new(egui::Id::new(("form-editor", view.id.0))).order(egui::Order::Foreground).fixed_pos(rect.min).show(ctx, |ui| {
|
||||
// Shown at once, like the paragraph editor: a fade-in shows the field's value through it.
|
||||
let area = egui::Area::new(egui::Id::new(("form-editor", view.id.0))).fade_in(false);
|
||||
area.order(egui::Order::Foreground).fixed_pos(rect.min).show(ctx, |ui| {
|
||||
ui.set_min_size(rect.size());
|
||||
let Some(fx) = view.forms.focus.as_mut() else { return };
|
||||
// Sized from the text being typed, so an auto-sized field shrinks to keep it in view.
|
||||
|
||||
@@ -2996,6 +2996,62 @@ fn a_paragraph_whose_edit_fails_stays_open_with_its_typing() {
|
||||
assert_eq!(doc.text_blocks(0).iter().map(|b| b.text.clone()).collect::<Vec<_>>(), ["Top edited", "Bottom"]);
|
||||
}
|
||||
|
||||
/// Two boxes, "Top" and "Bottom", in Edit text, with egui's animations on: the window animates
|
||||
/// unless the system asks for less motion, and the test harness turns them off.
|
||||
fn two_boxes_animated() -> (Harness<'static, PdfCraftApp>, [egui::Rect; 2]) {
|
||||
let bytes = source_font_fixture_with_text("BT /F1 24 Tf 20 220 Td (Top) Tj ET BT /F2 24 Tf 20 120 Td (Bottom) Tj ET");
|
||||
let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).with_step_dt(1.0 / 60.0).build_eframe(move |_cc| {
|
||||
let mut app = PdfCraftApp::new();
|
||||
app.set_option("language", "en").unwrap();
|
||||
app.open_bytes("boxes.pdf", None, bytes).expect("opens");
|
||||
app
|
||||
});
|
||||
h.ctx.all_styles_mut(|s| s.animation_time = 0.2);
|
||||
h.run_steps(4);
|
||||
assert!(h.state_mut().execute("edit.edit_text"));
|
||||
h.run_steps(2);
|
||||
let r = h.state().views[0].page_screen_rect(0).expect("on screen");
|
||||
let k = r.width() / 300.0;
|
||||
let mut blocks = {
|
||||
let s = h.state();
|
||||
s.session.get(s.views[0].id).unwrap().text_blocks(0)
|
||||
};
|
||||
blocks.sort_by(|a, b| b.rect[1].partial_cmp(&a.rect[1]).unwrap_or(std::cmp::Ordering::Equal));
|
||||
let on_screen = |b: &pdfcraft_engine::TextBlock| {
|
||||
egui::Rect::from_min_max(
|
||||
egui::pos2(r.left() + b.rect[0] as f32 * k, r.top() + (300.0 - b.rect[3] as f32) * k),
|
||||
egui::pos2(r.left() + b.rect[2] as f32 * k, r.top() + (300.0 - b.rect[1] as f32) * k),
|
||||
)
|
||||
};
|
||||
(h, [on_screen(&blocks[0]), on_screen(&blocks[1])])
|
||||
}
|
||||
|
||||
/// The colour of the editor's frame (the accent stroke around `r`) this frame, if it is painted.
|
||||
fn editor_frame_color(h: &Harness<'static, PdfCraftApp>, r: egui::Rect) -> Option<egui::Color32> {
|
||||
h.output().shapes.iter().find_map(|shape| match &shape.shape {
|
||||
egui::Shape::Rect(rect) if rect.stroke.width == 1.5 && rect.rect.contains(r.center()) => Some(rect.stroke.color),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// A paragraph opens at once: it used to fade in over a fifth of a second, its frame dimmed and
|
||||
/// the page's own copy of the text showing through the editor's cover.
|
||||
#[test]
|
||||
fn a_paragraph_editor_opens_at_full_opacity() {
|
||||
let (mut h, [top, _]) = two_boxes_animated();
|
||||
h.hover_at(top.center());
|
||||
h.run_steps(1);
|
||||
h.drag_at(top.center());
|
||||
h.run_steps(1);
|
||||
h.drop_at(top.center());
|
||||
let accent = egui::Color32::from_rgb(0x14, 0x73, 0xE6);
|
||||
for frame in 0..8 {
|
||||
h.step();
|
||||
// The click's own frame opens it: the editor's frame is there from then on, at full colour.
|
||||
assert_eq!(editor_frame_color(&h, top), Some(accent), "frame {frame} after the click");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn editing_existing_text_in_place() {
|
||||
let mut h = harness(1, |_| {});
|
||||
|
||||
Reference in new issue
Block a user