mirror of
https://github.com/storytold/wordcraft.git
synced 2026-11-14 14:32:31 +00:00
The #5858 early return kept page anchoring for any object that does not move with text, which includes a body frame that came from an .odt with text:anchor-type="page". Moving it then skipped the paragraph placement and the save wrote the page anchor and number back, contradicting #5705's an_odt_frame_moved_from_its_page_loses_the_page_number. Only header/footer objects (and drops on a page with no anchoring text) keep page anchoring now, which is what #5812 needed. The body test that pinned the opposite is updated to the #5705 rule.
This commit is contained in:
1 parent
69ea44776d
commit
c37baf764d
2 files changed
+15
-15
No files matched your search
@@ -147,8 +147,8 @@ pub(super) fn move_object(s: &mut Session, pos: Pos, page: Option<u64>, x: f32,
|
||||
}
|
||||
|
||||
/// [`move_object`]'s one placement: move the object's character to the anchor under (x, y) on
|
||||
/// `page` and offset it from there. Objects in headers/footers, on pages without anchoring text,
|
||||
/// or configured not to move with text retain page-relative anchoring.
|
||||
/// `page` and offset it from there. Objects in headers/footers, or on pages without anchoring
|
||||
/// text, retain page-relative anchoring; a body object is placed by its paragraph (#5705).
|
||||
fn move_object_once(s: &mut Session, pos: &Pos, page: usize, x: f32, y: f32, (w, h): (f32, f32)) -> Result<Pos, CmdError> {
|
||||
use wordcraft_doc::para::Anchor;
|
||||
if pos.path.depth() > 0 || !movable_story(s, pos.story) {
|
||||
@@ -165,8 +165,6 @@ fn move_object_once(s: &mut Session, pos: &Pos, page: usize, x: f32, y: f32, (w,
|
||||
Some(path) => (Pos { story, path, off: 0 }, false),
|
||||
None => (nearest_line(&layout, page, y, story).ok_or_else(|| CmdError::Params("no text on that page to anchor to".into()))?, true),
|
||||
};
|
||||
let was_with_text =
|
||||
s.doc.para_at(pos).and_then(|p| p.object_at(pos.off)).and_then(|o| o.frame()).map_or(story == StoryRef::Body, |(_, _, f)| moves_with_text(f));
|
||||
// Move its character to the anchor, unless it's already in that paragraph and drawn on this
|
||||
// page (one anchored on a later page of it is drawn there, #4250).
|
||||
let at = if anchor.story == pos.story && anchor.path == pos.path && !on_page && layout.object(pos, page).is_some_and(|o| o.page == page) {
|
||||
@@ -199,7 +197,7 @@ fn move_object_once(s: &mut Session, pos: &Pos, page: usize, x: f32, y: f32, (w,
|
||||
f.x = x.clamp(-MAX_OFFSET, MAX_OFFSET);
|
||||
f.y = y.clamp(-MAX_OFFSET, MAX_OFFSET);
|
||||
})?;
|
||||
if on_page || story != StoryRef::Body || !was_with_text {
|
||||
if on_page || story != StoryRef::Body {
|
||||
return Ok(at);
|
||||
}
|
||||
// Then offsets from its paragraph, as laid out with the object there.
|
||||
|
||||
@@ -1295,10 +1295,11 @@ fn arrange_bounds_on_header_picture_writes_page_anchored_odt_frame() {
|
||||
assert!(styles.contains(r#"svg:x="10pt""#) && styles.contains(r#"svg:y="20pt""#), "{styles}");
|
||||
}
|
||||
|
||||
/// Turning off `moveWithText` on a body picture anchors it to the page, and subsequent
|
||||
/// `arrange.bounds` retains page-relative anchoring and writes a page-anchored ODT frame.
|
||||
/// A body picture set to stay on the page (`moveWithText` off) is still placed by its paragraph
|
||||
/// once moved: the move is the placement, and the file keeps no page number to put it back
|
||||
/// (#5705). Header and footer pictures stay page-anchored (see above).
|
||||
#[test]
|
||||
fn body_picture_with_move_with_text_false_retains_page_anchor_and_coordinates() {
|
||||
fn a_moved_body_picture_is_placed_by_its_paragraph_even_when_fixed_to_the_page() {
|
||||
use wordcraft_doc::para::Anchor;
|
||||
let mut s = Session::new(wordcraft_doc::Document::new());
|
||||
s.run("text.insert", &json!({"text": "First line of paragraph.\n"})).unwrap();
|
||||
@@ -1310,24 +1311,25 @@ fn body_picture_with_move_with_text_false_retains_page_anchor_and_coordinates()
|
||||
let float = obj.frame().unwrap().2;
|
||||
assert_eq!((float.h_rel, float.v_rel), (Anchor::Column, Anchor::Column));
|
||||
|
||||
// Turn off moveWithText
|
||||
// Turn off moveWithText: fixed on the page until it is moved.
|
||||
s.run("arrange.moveWithText", &json!({"value": false})).unwrap();
|
||||
let (_, obj) = selected(&s).unwrap();
|
||||
let float = obj.frame().unwrap().2;
|
||||
assert_eq!((float.h_rel, float.v_rel), (Anchor::Column, Anchor::Page));
|
||||
|
||||
// Now call arrange.bounds on a page where a paragraph starts
|
||||
s.run("arrange.bounds", &json!({"page": 0, "x": 50.0, "y": 80.0})).unwrap();
|
||||
let (_, obj) = selected(&s).unwrap();
|
||||
let (pos, obj) = selected(&s).unwrap();
|
||||
let float = obj.frame().unwrap().2;
|
||||
assert_eq!((float.h_rel, float.v_rel), (Anchor::Page, Anchor::Page));
|
||||
assert_eq!((float.x, float.y), (50.0, 80.0));
|
||||
assert_eq!((float.h_rel, float.v_rel), (Anchor::Column, Anchor::Paragraph));
|
||||
assert_eq!(float.page, 0);
|
||||
let hit = s.layout().object(&pos, 0).expect("laid out");
|
||||
assert!((hit.rect.x - 50.0).abs() < 1.0 && (hit.rect.y - 80.0).abs() < 1.0, "dropped: {:?}", hit.rect);
|
||||
|
||||
let mut z = zip::ZipArchive::new(std::io::Cursor::new(wordcraft_formats::odt::export(&s.doc).unwrap())).unwrap();
|
||||
let mut content = String::new();
|
||||
std::io::Read::read_to_string(&mut z.by_name("content.xml").unwrap(), &mut content).unwrap();
|
||||
assert!(content.contains(r#"text:anchor-type="page""#), "body picture should export with page anchor: {content}");
|
||||
assert!(content.contains(r#"svg:x="50pt""#) && content.contains(r#"svg:y="80pt""#), "{content}");
|
||||
assert!(content.contains(r#"text:anchor-type="paragraph""#), "body picture should export with paragraph anchor: {content}");
|
||||
assert!(!content.contains("anchor-page-number"), "{content}");
|
||||
}
|
||||
|
||||
/// Changing `moveWithText` on an object with `h_align` set preserves its horizontal
|
||||
|
||||
Reference in new issue
Block a user