Artboards: Artboard Options' Show Center Mark and Show Cross Hairs draw on the canvas

The Artboard Options help pages describe two display options
(https://helpx.adobe.com/illustrator/desktop/create-manage-artboards/organize-manage-artboards/modify-display-settings-of-artboards.html,
.../set-video-display-options-for-artboards.html): a mark at the artboard's
center, and lines from the middle of each side through the center. The
document already had show_center_mark and show_cross_hairs on Artboard, but
nothing set or drew them.

artboard.setProps (each `artboards` entry too) and artboard.new take
showCenterMark and showCrossHairs as true/false, in the same single undo
step as the other fields; a locked artboard can still change them.
Artboard Options has both checkboxes, filled in from the artboard whether
it opens from the panel or a double-click with the Artboard tool, and its
New Artboard form passes them to artboard.new. The canvas draws them in the
new theme token artboard_mark, 1 point wide on screen at any zoom: a cross
12 points across at the center whose arms follow the artboard's sides, and
the two cross hairs. They are screen-only like the edges; exports and print
never read the fields. inspect_document reports them when on. Saved files
are unchanged: the two keys were already always written, so a document that
never shows them saves byte for byte as before, and a file without the keys
opens with both off. Video safe areas, video rulers and the pixel aspect
ratio are not part of this change.

Verification: artboard_display_marks_are_set_and_cleared_in_one_undo_step,
artboard_display_marks_round_trip_through_the_native_format,
artboard_display_marks_stay_out_of_exports (SVG and PDF identical with the
marks on and off), an_artboard_shows_its_center_mark_and_cross_hairs
(positions, screen-constant size under zoom, rotated view) and
artboard_options_show_center_mark_and_cross_hairs. cargo xtask ci: all 10
steps passed.
This commit is contained in:
Taha-Mahmoodi
2026-10-23 09:42:09 +07:00
committed by bflatastic
parent 08cfb45561
commit 64f6d2db50
39 changed files with 384 additions and 27 deletions
+22 -7
View File
@@ -1,8 +1,11 @@
//! Artboard Options (double-click with the Artboard tool, double-click the tool, or the Artboards
//! panel's options icon or menu): the artboard's fields, sizes parsed with units, its position
//! from a reference point, and its background color (`color`: a color as the paint commands take
//! it, or null for none). Sizing choices also go to the other selected artboards; fitting
//! changes only the active artboard around stationary artwork.
//! from a reference point, its background color (`color`: a color as the paint commands take
//! it, or null for none), and Show Center Mark and Show Cross Hairs (`showCenterMark`,
//! `showCrossHairs`), the display marks the canvas draws on the artboard
//! (https://helpx.adobe.com/illustrator/desktop/create-manage-artboards/organize-manage-artboards/modify-display-settings-of-artboards.html).
//! Sizing choices also go to the other selected artboards; fitting changes only the active
//! artboard around stationary artwork.
use serde_json::{Value, json};
use vectorcraft_color::Color;
@@ -32,7 +35,7 @@ fn placed(d: &Dialog) -> Rect {
/// as the Transform panel and the Control bar show an artboard's. A new Width or Height keeps the
/// reference point where it was, as their sizes do.
/// Then Background Color: the Fill list (None, White, Black; Custom for another color) and a swatch
/// that picks a color of its own.
/// that picks a color of its own, and the Show Center Mark and Show Cross Hairs checkboxes.
fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
let (unit, origin, refi) = (app.session.general_unit(), app.ruler_origin(), reference_index(ui));
let (was, w0, h0) = (placed(d), d.f64("width", 0.0), d.f64("height", 0.0));
@@ -92,6 +95,9 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
if let Some(c) = set {
d.fields.insert("color".into(), c.as_ref().map_or(Value::Null, crate::panels::color_json));
}
ui.add_space(8.0);
form::check(ui, d, "showCenterMark", tl!("Show Center Mark"));
form::check(ui, d, "showCrossHairs", tl!("Show Cross Hairs"));
false
}
@@ -194,7 +200,10 @@ pub fn open(app: &mut VectorcraftApp) -> Result<Value, String> {
let a = st.doc.artboards.get(index).ok_or("no artboard")?;
let r = a.rect;
let color = a.color.as_ref().map(crate::panels::color_json);
let fields = json!({"index": index, "name": a.name, "x": r.x0, "y": r.y0, "width": r.width(), "height": r.height(), "color": color});
let fields = json!({
"index": index, "name": a.name, "x": r.x0, "y": r.y0, "width": r.width(), "height": r.height(), "color": color,
"showCenterMark": a.show_center_mark, "showCrossHairs": a.show_cross_hairs,
});
app.ui.dialog = Some(Dialog::new(KIND, fields));
Ok(json!({ "dialog": KIND }))
}
@@ -265,8 +274,9 @@ pub fn open_new(app: &mut VectorcraftApp) -> Result<Value, String> {
Ok(json!({ "dialog": KIND }))
}
/// OK for a new artboard: `artboard.new` with the fields (an empty name gives the default one) and
/// the background color picked, and the new artboard becomes the active one.
/// OK for a new artboard: `artboard.new` with the fields (an empty name gives the default one),
/// the background color picked and the display marks ticked, and the new artboard becomes the
/// active one.
fn confirm_new(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
let mut p = json!({});
for k in ["x", "y", "width", "height"] {
@@ -279,6 +289,11 @@ fn confirm_new(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
if let Some(c) = d.fields.get("color") {
p["color"] = c.clone();
}
for k in ["showCenterMark", "showCrossHairs"] {
if d.bool(k) {
p[k] = json!(true);
}
}
let r = run_and_close(app, "artboard.new", p)?;
if let Some(i) = r["index"].as_u64().and_then(|i| usize::try_from(i).ok()) {
crate::panels::artboards::select(app, i);
+50
View File
@@ -1102,6 +1102,56 @@ fn new_artboard_options_give_the_new_artboard_its_background_color() {
}
}
/// Artboard Options shows Show Center Mark and Show Cross Hairs, ticked as the artboard has them
/// whether it opens from the Artboards panel or from a double-click with the Artboard tool. OK
/// sets them in one undo step, and a new artboard's Artboard Options gives it the ones ticked.
#[test]
fn artboard_options_show_center_mark_and_cross_hairs() {
use vectorcraft_tools::{PointerEvent, PointerKind};
let mut app = app();
let marks = |app: &VectorcraftApp, i: usize| {
let a = &app.session.doc().unwrap().doc.artboards[i];
(a.show_center_mark, a.show_cross_hairs)
};
crate::dialogs::artboard_options::open(&mut app).unwrap();
let text = crate::tests_labels::painted_text(&mut app, |app, ui| show(app, ui.ctx()));
assert!(text.contains("Show Center Mark") && text.contains("Show Cross Hairs"), "{text}");
let d = app.ui.dialog.as_mut().unwrap();
assert!(!d.bool("showCenterMark") && !d.bool("showCrossHairs"));
d.fields.insert("showCenterMark".into(), json!(true));
let undo = app.session.doc().unwrap().history.undo.len();
super::confirm(&mut app).unwrap();
assert_eq!(marks(&app, 0), (true, false));
assert_eq!(app.session.doc().unwrap().history.undo.len(), undo + 1);
// Opened again, it shows them; unticking one clears it.
crate::dialogs::artboard_options::open(&mut app).unwrap();
let d = app.ui.dialog.as_mut().unwrap();
assert!(d.bool("showCenterMark"));
d.fields.insert("showCenterMark".into(), json!(false));
d.fields.insert("showCrossHairs".into(), json!(true));
super::confirm(&mut app).unwrap();
assert_eq!(marks(&app, 0), (false, true));
// A double-click with the Artboard tool on the artboard's empty space.
app.select_tool("artboard");
let view = app.view_info();
for kind in [PointerKind::Down, PointerKind::Up, PointerKind::Down, PointerKind::Up, PointerKind::DoubleClick] {
crate::canvas::dispatch(&mut app, &PointerEvent::new(kind, 100.0, 100.0), view);
}
let d = app.ui.dialog.clone().expect("Artboard Options opened");
assert_eq!((d.kind.as_str(), d.bool("showCenterMark"), d.bool("showCrossHairs")), ("artboardOptions", false, true));
cancel(&mut app);
// A new artboard takes the ones ticked, and none when none is.
for (ticked, want) in [(Some("showCenterMark"), (true, false)), (None, (false, false))] {
app.run("ui.newArtboard", json!({})).unwrap();
if let Some(k) = ticked {
app.ui.dialog.as_mut().unwrap().fields.insert(k.into(), json!(true));
}
super::confirm(&mut app).unwrap();
let last = app.session.doc().unwrap().doc.artboards.len() - 1;
assert_eq!(marks(&app, last), want);
}
}
/// #1482: with Artboards 1 and 3 selected with the Artboard tool, a new Width in Artboard Options
/// goes to both, each keeping its top-left corner and its height, in one undo step. The new name
/// goes only to the artboard the dialog shows, and Artboard 2 keeps its size. A name alone resizes