mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-14 14:22:39 +00:00
Text Frame Options: link the insets only when every selected frame has even sides
The dialog turned the inset link on when the first selected frame had the same inset on all four sides. With a second frame whose sides differ, typing one side then set all four sides of every selected frame, so the second frame lost its other insets. The link is now on only when every frame the dialog changes has even sides: the selected items, else the caret's frame, else every frame of the caret's story.
This commit is contained in:
1 parent
92043b4c48
commit
20319e991e
2 files changed
+71
-1
No files matched your search
@@ -1005,6 +1005,24 @@ fn selected_frame_options(app: &DesignApp) -> Option<designcraft_doc::TextFrameO
|
||||
st.doc.item(fid)?.text_frame().map(|t| t.options.clone())
|
||||
}
|
||||
|
||||
/// True when every text frame the dialog changes has the same inset on all four sides: the
|
||||
/// selected items, else the caret's frame, else every frame of the caret's story.
|
||||
fn selected_frames_have_even_insets(app: &DesignApp) -> bool {
|
||||
let Some(st) = app.session.active() else {
|
||||
return true;
|
||||
};
|
||||
let mut ids = st.selection.items.clone();
|
||||
if ids.is_empty()
|
||||
&& let Some(t) = st.selection.text
|
||||
{
|
||||
ids = match t.frame {
|
||||
Some(f) => vec![f],
|
||||
None => st.doc.story(t.story).map(|s| s.frames.clone()).unwrap_or_default(),
|
||||
};
|
||||
}
|
||||
ids.iter().filter_map(|id| st.doc.item(*id)?.text_frame()).all(|t| t.options.inset.iter().all(|v| (v - t.options.inset[0]).abs() < 1e-9))
|
||||
}
|
||||
|
||||
/// Object › Text Frame Options shows the selected frame's options. `_shown` keeps what it showed,
|
||||
/// so OK sends only the fields the user changed. Fields given when the dialog opened count as
|
||||
/// changed.
|
||||
@@ -1056,7 +1074,8 @@ fn seed_text_frame_options(app: &DesignApp, d: &mut Dialog) {
|
||||
d.fields.entry(k.clone()).or_insert_with(|| v.clone());
|
||||
}
|
||||
}
|
||||
d.fields.entry("insetLinked".to_string()).or_insert_with(|| json!(o.inset.iter().all(|v| (v - o.inset[0]).abs() < 1e-9)));
|
||||
// Linked only when no selected frame has uneven sides, so a typed side cannot overwrite them.
|
||||
d.fields.entry("insetLinked".to_string()).or_insert_with(|| json!(selected_frames_have_even_insets(app)));
|
||||
// The frame's width: Fixed Number shows each column's width from it as the fields change.
|
||||
if let Some(w) = selected_frame_width(app) {
|
||||
d.fields.insert("_frameWidth".into(), json!(w));
|
||||
|
||||
@@ -1485,6 +1485,57 @@ fn text_frame_options_change_only_what_was_edited() {
|
||||
assert_eq!(opts(&app), before);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn text_frame_options_link_the_insets_only_when_every_selected_frame_has_even_sides() {
|
||||
let mut app = crate::DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
|
||||
app.run("file.new", json!({})).unwrap();
|
||||
let frame = |app: &mut DesignApp, rect: [u32; 4], inset: Value| {
|
||||
let r = app.run("frame.create", json!({"rect": rect, "content": "text", "text": "Hello"})).unwrap();
|
||||
let id = r["id"].as_u64().unwrap();
|
||||
app.run("object.textFrameOptions", json!({"ids": [id], "inset": inset})).unwrap();
|
||||
(designcraft_doc::ItemId(id), r["story"].clone())
|
||||
};
|
||||
let (even, _) = frame(&mut app, [36, 36, 236, 236], json!(6));
|
||||
let (uneven, uneven_story) = frame(&mut app, [300, 36, 500, 236], json!([1, 2, 3, 4]));
|
||||
let (other_even, other_even_story) = frame(&mut app, [36, 300, 236, 500], json!(9));
|
||||
let inset = |app: &DesignApp, id| app.session.doc().unwrap().doc.item(id).unwrap().text_frame().unwrap().options.inset;
|
||||
let seeded = |app: &DesignApp| {
|
||||
let mut d = Dialog::new("textFrameOptions", json!({}));
|
||||
seed_text_frame_options(app, &mut d);
|
||||
d
|
||||
};
|
||||
// The frame with even sides is selected first: the uneven one still turns the link off.
|
||||
app.run("selection.set", json!({"ids": [even.0, uneven.0]})).unwrap();
|
||||
let mut d = seeded(&app);
|
||||
assert_eq!(d.s("insetTop"), "0p6");
|
||||
assert!(!d.b("insetLinked"), "a selected frame with uneven sides leaves the link off");
|
||||
// Top edited while unlinked: only Top changes, and each frame keeps its other sides.
|
||||
d.fields.insert("insetTop".into(), json!("1p0"));
|
||||
app.ui.dialog = Some(d);
|
||||
confirm(&mut app).unwrap();
|
||||
assert_eq!(inset(&app, even), [12.0, 6.0, 6.0, 6.0]);
|
||||
assert_eq!(inset(&app, uneven), [12.0, 2.0, 3.0, 4.0]);
|
||||
// A frame with even sides alone keeps the link on; selected with the uneven one, the link is off.
|
||||
app.run("selection.set", json!({"ids": [other_even.0]})).unwrap();
|
||||
assert!(seeded(&app).b("insetLinked"));
|
||||
app.run("selection.set", json!({"ids": [other_even.0, uneven.0]})).unwrap();
|
||||
assert!(!seeded(&app).b("insetLinked"));
|
||||
// A caret: the frames the dialog changes decide.
|
||||
app.run("text.select", json!({"story": uneven_story, "anchor": 0, "focus": 0})).unwrap();
|
||||
assert!(!seeded(&app).b("insetLinked"));
|
||||
app.run("text.select", json!({"story": other_even_story, "anchor": 0, "focus": 0})).unwrap();
|
||||
assert!(seeded(&app).b("insetLinked"));
|
||||
// A story threaded on into the uneven frame: a caret placed in the first frame changes only
|
||||
// that frame, and a caret with no frame changes every frame of the story.
|
||||
let (first, story) = frame(&mut app, [300, 300, 500, 500], json!(6));
|
||||
let (last, _) = frame(&mut app, [300, 520, 500, 700], json!([1, 2, 3, 4]));
|
||||
app.run("text.thread", json!({"from": first.0, "to": last.0})).unwrap();
|
||||
app.run("text.placeCaret", json!({"frame": first.0, "point": [310, 310]})).unwrap();
|
||||
assert!(seeded(&app).b("insetLinked"));
|
||||
app.run("text.select", json!({"story": story, "anchor": 0, "focus": 0})).unwrap();
|
||||
assert!(!seeded(&app).b("insetLinked"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn toc_dialog_adds_a_style_and_ok_makes_the_table_of_contents() {
|
||||
let mut app = DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
|
||||
|
||||
Reference in new issue
Block a user