This commit is contained in:
Brandon Thomas committed 2026-10-14 12:39:59 -04:00
commit b8d975b094
14 files changed
+430 -8

No files matched your search

+2
View File
@@ -134,6 +134,8 @@ Newest first.
- **2026-10-13** · Object › Fitting has InDesign's shortcuts: Fill Frame Proportionally ⌘⌥⇧C, Fit Content Proportionally ⌘⌥⇧E, Fit Frame to Content ⌘⌥C, Fit Content to Frame ⌘⌥E, Center Content ⌘⇧E. No readiness percentage change.
- **2026-10-13** · Gradients between process colours blend as inks, as InDesign shows them: magenta to cyan passes through C 50 M 50 (a light lilac) on screen instead of the darker RGB mix, and a midpoint between CMYK or grey stops no longer turns the PDF shading RGB. No readiness percentage change.
- **2026-10-14** · The Swatches panel has InDesign's header: a Fill/Stroke proxy, Formatting Affects Container/Text and the Tint of the colour in front (a tint alone keeps each object's own swatch). Clicking a swatch applies it to the fill or stroke in front (of the text, when formatting affects text), and the bottom row has New Color Group, New Swatch and Delete Swatch. No readiness percentage change.
- **2026-10-14** · With the Page tool, the Control panel shows the page as InDesign's does: W/H from a reference point, page-size preset (US Business Card added), orientation, Liquid Page Rule (now with Controlled by Parent) and Show Parent Page Overlay, which draws the parent page's size over a resized page. No readiness percentage change.
- **2026-10-14** · On an object-based page the Page tool shows a selected object's liquid pins and resize locks as InDesign does: a click pins a side to the page edge or locks the width or height, with InDesign's tooltips. No readiness percentage change.
- **2026-10-14** · With the Page tool, the Control panel shows the page as InDesign's does: W/H from a reference point, page-size preset (US Business Card added), orientation, Liquid Page Rule and Show Parent Page Overlay, which draws the parent page's size over a resized page. No readiness percentage change.
- **2026-10-14** · The Page tool works as InDesign's: a click selects a page and shows its handles and liquid page rule; dragging a handle previews the rule and springs back, Alt-drag resizes the page from the opposite edge, Shift keeps proportions, with a W/H readout. No readiness percentage change.
- **2026-10-12** · Text threads by hand: click a selected text frame's in or out port to load
+18 -3
View File
@@ -389,20 +389,35 @@ pub fn specs() -> Vec<CommandSpec> {
has_doc,
page_options
),
cmd!(noundo "layout.selectPage", "Select Page", [], None, "{page: 1-based | null} — the page the Page tool selects (its handles, the Control panel)", has_doc, |s, p| {
cmd!(
noundo "layout.selectPage",
"Select Page",
[],
None,
"{page: 1-based | null, ids?: [item ids] (objects selected with it: the Page tool on an object-based page)} — the page the Page tool selects (its handles, the Control panel)",
has_doc,
|s, p| {
let n = s.doc()?.doc.page_count();
let page = match p.get("page") {
None | Some(Value::Null) => None,
Some(v) => Some(v.as_u64().filter(|v| *v >= 1 && *v as usize <= n).ok_or_else(|| bad("layout.selectPage", format!("`page`: 1–{n}")))? as usize - 1),
};
let ids: Vec<designcraft_doc::ItemId> = {
let d = &s.doc()?.doc;
p.get("ids")
.and_then(Value::as_array)
.map(|a| a.iter().filter_map(Value::as_u64).map(designcraft_doc::ItemId).filter(|id| d.item(*id).is_some()).collect())
.unwrap_or_default()
};
let st = s.doc_mut()?;
if page.is_some() {
st.selection = Default::default();
st.selection = designcraft_doc::Selection::items(ids);
}
st.selection.page = page;
st.revision += 1;
Ok(json!({"page": page.map(|p| p + 1)}))
}),
}
),
cmd!(
"layout.section",
"Numbering & Section Options…",
+56
View File
@@ -668,6 +668,62 @@ fn controlled_by_parent_takes_the_parent_pages_rule() {
assert!(s.execute("layout.pageOptions", &json!({"pages": [2], "showParentOverlay": true})).is_err());
}
#[test]
fn page_tool_pins_and_locks_objects_on_object_based_pages() {
use designcraft_tools::{CanvasLayout, Mods, PointerEvent, PointerKind};
let mut s = Session::new();
s.execute("file.new", &json!({"width": 612, "height": 792, "facingPages": false})).unwrap();
let id = s.execute("frame.create", &json!({"rect": [256, 72, 356, 132]})).unwrap()["id"].as_u64().unwrap();
s.execute("liquid.pageRule", &json!({"rule": "objectBased"})).unwrap();
s.execute("edit.deselectAll", &json!({})).unwrap();
s.set_tool("page");
let v = ViewInfo::at_zoom(1.0);
let ev =
|kind, p: designcraft_geom::Point, alt: bool| PointerEvent { mods: Mods { alt, ..Default::default() }, ..PointerEvent::new(kind, p.x, p.y) };
let canvas = |s: &Session| {
let d = &s.doc().unwrap().doc;
let l = CanvasLayout::new(d, false);
(
l.page_rect(d, 0).unwrap(),
l.xf(designcraft_doc::SpreadRef::Doc(0)).transform_rect_bbox(d.item(designcraft_doc::ItemId(id)).unwrap().bounds()),
)
};
let click = |s: &mut Session, p: designcraft_geom::Point| {
s.pointer(&ev(PointerKind::Down, p, false), v).unwrap();
s.pointer(&ev(PointerKind::Up, p, false), v).unwrap();
};
let liquid = |s: &Session| s.doc().unwrap().doc.item(designcraft_doc::ItemId(id)).unwrap().liquid;
// A click on the object selects it with its page; its pins and locks show.
let (_, o) = canvas(&s);
click(&mut s, o.center());
let sel = s.doc().unwrap().selection.clone();
assert_eq!((sel.page, sel.items.clone()), (Some(0), vec![designcraft_doc::ItemId(id)]));
assert!(
s.overlays(v)
.iter()
.any(|o| matches!(o, designcraft_tools::Overlay::LiquidPins { pins: [false, false, false, false], resize: [true, true], .. }))
);
// The right pin (14 px outside the right edge) and the width lock (10 px right of the centre).
click(&mut s, designcraft_geom::Point::new(o.x1 + 14.0, o.center().y));
click(&mut s, designcraft_geom::Point::new(o.center().x + 10.0, o.center().y));
let l = liquid(&s).unwrap();
assert!(l.pin_right && !l.resize_width && l.resize_height && !l.pin_left, "{l:?}");
// Alt-drag the page 100 pt wider: the pinned, width-locked frame keeps its size by the right edge.
let (p, _) = canvas(&s);
let right = designcraft_geom::Point::new(p.x1, p.center().y);
s.pointer(&ev(PointerKind::Down, right, true), v).unwrap();
s.pointer(&ev(PointerKind::Drag, right + designcraft_geom::Vec2::new(100.0, 0.0), true), v).unwrap();
s.pointer(&ev(PointerKind::Up, right + designcraft_geom::Vec2::new(100.0, 0.0), true), v).unwrap();
let d = &s.doc().unwrap().doc;
let (pg, b) = (&d.spreads[0].pages[0], d.item(designcraft_doc::ItemId(id)).unwrap().bounds());
assert_eq!(pg.width, 712.0);
assert!((b.width() - 100.0).abs() < 1e-6 && (pg.x + pg.width - b.x1 - 256.0).abs() < 1e-6, "{b:?}");
// Hovering a pin shows its tooltip.
let (_, o) = canvas(&s);
s.pointer(&ev(PointerKind::Move, designcraft_geom::Point::new(o.x1 + 14.0, o.center().y), false), v).unwrap();
assert!(s.overlays(v).iter().any(|o| matches!(o, designcraft_tools::Overlay::Tip { text, .. } if text.starts_with("Object is pinned"))));
}
/// Load the text from a frame's out port with the Selection tool and click on the pasteboard:
/// a new frame is threaded there and the overset text flows into it.
#[test]
+15
View File
@@ -15,6 +15,7 @@ mod frame;
mod gradient;
pub mod layout;
mod nav;
pub use nav::{LOCK_OFFSET_PX, PIN_OFFSET_PX};
mod pen;
mod pencil;
pub mod select;
@@ -330,6 +331,20 @@ pub enum Overlay {
p: Point,
text: String,
},
/// A tooltip near the pointer (English; the UI translates it).
Tip {
p: Point,
text: String,
},
/// An object's liquid pins and resize locks on an object-based page (Page tool), canvas
/// coordinates: pinned sides (top, right, bottom, left) and whether width and height follow the
/// page.
LiquidPins {
object: Rect,
page: Rect,
pins: [bool; 4],
resize: [bool; 2],
},
}
/// Correction from a snap, in spread coordinates for `delta`.
+135 -4
View File
@@ -168,6 +168,75 @@ impl Tool for PlaceGun {
#[derive(Default)]
pub struct PageTool {
drag: Option<PageDrag>,
/// The pin or lock under the pointer (for its tooltip).
hover: Option<(LiquidControl, Point)>,
}
/// An object's liquid control on an object-based page: a side's pin (top, right, bottom, left) or
/// the width/height lock.
#[derive(Clone, Copy, Debug, PartialEq)]
enum LiquidControl {
Pin(usize),
Width,
Height,
}
impl LiquidControl {
/// The `liquid.object` parameter it toggles.
fn key(self) -> &'static str {
match self {
LiquidControl::Pin(0) => "pinTop",
LiquidControl::Pin(1) => "pinRight",
LiquidControl::Pin(2) => "pinBottom",
LiquidControl::Pin(_) => "pinLeft",
LiquidControl::Width => "resizeWidth",
LiquidControl::Height => "resizeHeight",
}
}
/// InDesign's tooltip for the control in its current state.
fn tip(self, l: &designcraft_doc::ObjectLiquid) -> &'static str {
match self {
LiquidControl::Pin(i) if [l.pin_top, l.pin_right, l.pin_bottom, l.pin_left][i.min(3)] => {
"Object is pinned relative to the page edge. Click to release."
}
LiquidControl::Pin(_) => "Click to pin the object relative to the page edge.",
LiquidControl::Width if l.resize_width => "The object changes width as the page changes width. Click to lock the object width.",
LiquidControl::Width => "The object's width is locked. Click to let the object change width as the page changes width.",
LiquidControl::Height if l.resize_height => "The object changes height as the page changes height. Click to lock the object height.",
LiquidControl::Height => "The object's height is locked. Click to let the object change height as the page changes height.",
}
}
fn value(self, l: &designcraft_doc::ObjectLiquid) -> bool {
match self {
LiquidControl::Pin(0) => l.pin_top,
LiquidControl::Pin(1) => l.pin_right,
LiquidControl::Pin(2) => l.pin_bottom,
LiquidControl::Pin(_) => l.pin_left,
LiquidControl::Width => l.resize_width,
LiquidControl::Height => l.resize_height,
}
}
}
/// Screen pixels between an object's edge and its pin (the canvas draws them there too).
pub const PIN_OFFSET_PX: f64 = 14.0;
/// Screen pixels between an object's centre and its width/height locks.
pub const LOCK_OFFSET_PX: f64 = 10.0;
/// Where an object's liquid controls sit (canvas): pins outside each edge's middle, the width lock
/// right of the centre, the height lock above it.
fn liquid_control_points(cx: &ToolContext, r: designcraft_geom::Rect) -> [(LiquidControl, Point); 6] {
let (c, o, k) = (r.center(), cx.tol(PIN_OFFSET_PX), cx.tol(LOCK_OFFSET_PX));
[
(LiquidControl::Pin(0), Point::new(c.x, r.y0 - o)),
(LiquidControl::Pin(1), Point::new(r.x1 + o, c.y)),
(LiquidControl::Pin(2), Point::new(c.x, r.y1 + o)),
(LiquidControl::Pin(3), Point::new(r.x0 - o, c.y)),
(LiquidControl::Width, Point::new(c.x + k, c.y)),
(LiquidControl::Height, Point::new(c.x, c.y - k)),
]
}
/// A page handle being dragged.
@@ -202,7 +271,43 @@ pub fn rule_label(rule: designcraft_doc::LiquidRule) -> &'static str {
}
}
/// Whether page `abs` follows the object-based rule (its own, or its parent page's).
fn object_based(doc: &designcraft_doc::Document, abs: usize) -> bool {
use designcraft_doc::LiquidRule as R;
let Some((si, pi)) = doc.page_loc(abs) else { return false };
match doc.spreads[si].pages[pi].liquid {
R::ObjectBased => true,
R::ControlledByParent => {
doc.parent_page_for(abs).and_then(|(ppi, ppg)| doc.parents.get(ppi)?.pages.get(ppg).map(|p| p.liquid == R::ObjectBased)).unwrap_or(false)
}
_ => false,
}
}
impl PageTool {
/// The selected object's liquid settings, canvas bounds and page bounds when the Page tool
/// shows its pins: one object selected on the selected page, whose rule is object-based.
fn liquid_target(
cx: &ToolContext,
) -> Option<(designcraft_doc::ItemId, designcraft_doc::ObjectLiquid, designcraft_geom::Rect, designcraft_geom::Rect)> {
let page = cx.selection.page?;
let [id] = cx.selection.items.as_slice() else { return None };
let (si, _) = cx.doc.page_loc(page)?;
if !object_based(cx.doc, page) || cx.doc.page_of_item(*id) != Some(page) {
return None;
}
let it = cx.doc.item(*id)?;
let l = it.liquid.unwrap_or(designcraft_doc::ObjectLiquid { resize_width: true, resize_height: true, ..Default::default() });
let r = cx.layout.xf(designcraft_doc::SpreadRef::Doc(si)).transform_rect_bbox(it.bounds());
Some((*id, l, r, cx.layout.page_rect(cx.doc, page)?))
}
/// The selected object's pin or lock under `p`.
fn control_at(cx: &ToolContext, p: Point) -> Option<(designcraft_doc::ItemId, designcraft_doc::ObjectLiquid, LiquidControl)> {
let (id, l, r, _) = Self::liquid_target(cx)?;
liquid_control_points(cx, r).into_iter().find(|(_, q)| (q.x - p.x).hypot(q.y - p.y) <= cx.tol(6.0)).map(|(c, _)| (id, l, c))
}
/// The selected page's handle under `p`.
fn handle_at(&self, cx: &ToolContext, p: Point) -> Option<(usize, usize)> {
let page = cx.selection.page?;
@@ -255,12 +360,21 @@ impl Tool for PageTool {
self.drag = Some(PageDrag { page, handle, start: ev.pos, cur: ev.pos, size: (pg.width, pg.height), alt: ev.mods.alt });
return vec![Action::Begin("Resize Page".into())];
}
// A click selects the page under the pointer (none on the pasteboard).
// An object-based page's object: a click on a pin or lock toggles it.
if let Some((id, l, c)) = Self::control_at(cx, ev.pos) {
return vec![Action::Exec("liquid.object".into(), json!({"ids": [id.0], c.key(): !c.value(&l)}))];
}
// A click selects the page under the pointer (none on the pasteboard), and on an
// object-based page the object clicked too.
let page = (0..cx.doc.page_count()).find(|p| cx.layout.page_rect(cx.doc, *p).is_some_and(|r| r.contains(ev.pos)));
if page == cx.selection.page {
let object = page
.filter(|p| object_based(cx.doc, *p))
.and_then(|p| cx.hit(ev.pos).map(|(_, id)| id).filter(|id| cx.doc.page_of_item(*id) == Some(p)));
let ids: Vec<u64> = object.map(|id| id.0).into_iter().collect();
if page == cx.selection.page && cx.selection.items.iter().map(|i| i.0).eq(ids.iter().copied()) {
return vec![];
}
vec![Action::Exec("layout.selectPage".into(), json!({"page": page.map(|p| p + 1)}))]
vec![Action::Exec("layout.selectPage".into(), json!({"page": page.map(|p| p + 1), "ids": ids}))]
}
PointerKind::Drag => {
let Some(d) = self.drag.as_mut() else { return vec![] };
@@ -285,7 +399,10 @@ impl Tool for PageTool {
let pg = &cx.doc.spreads[si].pages[pi];
vec![Action::Dialog("cmd:layout.pageSize".into(), json!({"pages": [page + 1], "width": pg.width, "height": pg.height}))]
}
PointerKind::Move => vec![],
PointerKind::Move => {
self.hover = Self::control_at(cx, ev.pos).map(|(_, _, c)| (c, ev.pos));
vec![]
}
}
}
fn overlays(&self, cx: &ToolContext) -> Vec<Overlay> {
@@ -294,6 +411,17 @@ impl Tool for PageTool {
let Some((si, pi)) = cx.doc.page_loc(page) else { return vec![] };
let pg = &cx.doc.spreads[si].pages[pi];
let mut v = vec![Overlay::PageHandles(r), Overlay::Tag { p: Point::new(r.x0, r.y0 - cx.tol(6.0)), text: rule_label(pg.liquid).into() }];
if let Some((_, l, object, page)) = Self::liquid_target(cx) {
v.push(Overlay::LiquidPins {
object,
page,
pins: [l.pin_top, l.pin_right, l.pin_bottom, l.pin_left],
resize: [l.resize_width, l.resize_height],
});
if let Some((c, p)) = self.hover {
v.push(Overlay::Tip { p, text: c.tip(&l).into() });
}
}
if let Some(d) = self.drag {
v.push(Overlay::Measure {
p: d.cur,
@@ -307,6 +435,9 @@ impl Tool for PageTool {
v
}
fn cursor(&self, cx: &ToolContext, p: Point, _m: Mods) -> Cursor {
if self.drag.is_none() && Self::control_at(cx, p).is_some() {
return Cursor::Hand;
}
let handle = self.drag.map(|d| d.handle).or_else(|| self.handle_at(cx, p).map(|(_, h)| h));
match handle {
Some(1 | 7) => Cursor::ResizeV,
+1 -1
View File
@@ -235,7 +235,7 @@ fn page_tool_selects_a_page_and_opens_page_size_on_double_click() {
let (x, y) = (200.0 + off.x + d.spreads[0].pages[0].x, 200.0 + off.y);
let mut t = create("page");
let a = t.pointer(&cx, &PointerEvent::new(PointerKind::Down, x, y));
assert_eq!(a, vec![Action::Exec("layout.selectPage".into(), serde_json::json!({"page": 1}))]);
assert_eq!(a, vec![Action::Exec("layout.selectPage".into(), serde_json::json!({"page": 1, "ids": []}))]);
let a = t.pointer(&cx, &PointerEvent::new(PointerKind::DoubleClick, x, y));
assert_eq!(a, vec![Action::Dialog("cmd:layout.pageSize".into(), serde_json::json!({"pages": [1], "width": 612.0, "height": 792.0}))]);
// The selected page shows its handles and its liquid page rule.
+52
View File
@@ -1332,11 +1332,63 @@ fn draw_tool_overlays(app: &mut DesignApp, painter: &egui::Painter, xf: &Xf) {
painter.rect_stroke(r, 2.0, Stroke::new(1.0, Color32::from_rgb(79, 153, 255)), StrokeKind::Inside);
painter.galley(r.min + vec2(4.0, 2.0), g, tok.measure_text);
}
Overlay::Tip { p, text } => {
let text = crate::i18n::tr(&app.ui.language, &text).to_owned();
let s = xf.to_screen(p) + vec2(14.0, 14.0);
let g = painter.layout(text, egui::FontId::proportional(11.0), tok.measure_text, 260.0);
let r = Rect::from_min_size(s, g.size() + vec2(10.0, 6.0));
painter.rect_filled(r, 3.0, tok.measure_bg);
painter.galley(r.min + vec2(5.0, 3.0), g, tok.measure_text);
}
Overlay::LiquidPins { object, page, pins, resize } => draw_liquid_pins(painter, xf.rect(object), xf.rect(page), pins, resize),
Overlay::Path { .. } => {}
}
}
}
/// An object's liquid controls on an object-based page, as InDesign draws them in orange: a
/// dashed line across the object for width and height with a padlock (closed: locked), and a pin
/// outside each edge (pinned: a line to the page edge).
fn draw_liquid_pins(painter: &egui::Painter, o: Rect, page: Rect, pins: [bool; 4], resize: [bool; 2]) {
let col = Color32::from_rgb(178, 88, 18);
let st = Stroke::new(1.5, col);
let c = o.center();
let mids = [pos2(c.x, o.min.y), pos2(o.max.x, c.y), pos2(c.x, o.max.y), pos2(o.min.x, c.y)];
// The width and height lines between the edges' middles.
for (a, b) in [(mids[3], mids[1]), (mids[0], mids[2])] {
dashed(painter, a, b, Stroke::new(1.0, col), 3.0, 3.0);
}
for m in mids {
painter.circle_filled(m, 3.5, col);
}
let (po, lo) = (designcraft_tools::PIN_OFFSET_PX as f32, designcraft_tools::LOCK_OFFSET_PX as f32);
let outward = [vec2(0.0, -1.0), vec2(1.0, 0.0), vec2(0.0, 1.0), vec2(-1.0, 0.0)];
let edge = [pos2(c.x, page.min.y), pos2(page.max.x, c.y), pos2(c.x, page.max.y), pos2(page.min.x, c.y)];
for i in 0..4 {
if pins[i] {
painter.line_segment([mids[i], edge[i]], st);
painter.circle_filled(edge[i], 4.0, col);
} else {
painter.circle_stroke(mids[i] + outward[i] * po, 4.0, st);
}
}
// Padlocks: the width lock right of the centre, the height lock above it.
for (at, locked) in [(c + vec2(lo, 0.0), !resize[0]), (c + vec2(0.0, -lo), !resize[1])] {
let body = Rect::from_center_size(at + vec2(0.0, 2.0), vec2(8.0, 6.0));
painter.rect_filled(body.expand(1.0), 1.0, Color32::WHITE);
painter.rect_filled(body, 1.0, col);
// The shackle: over the body when locked, swung open when not.
let base = if locked { body.center().x } else { body.center().x + 3.0 };
let pts: Vec<_> = (0..=8)
.map(|k| {
let a = std::f32::consts::PI * k as f32 / 8.0;
pos2(base - 2.6 * a.cos(), body.min.y - 3.0 * a.sin())
})
.collect();
painter.add(egui::Shape::line(pts, Stroke::new(1.3, col)));
}
}
#[allow(clippy::too_many_arguments)]
fn draw_rulers(app: &DesignApp, ui: &egui::Ui, full: Rect, rect: Rect, xf: &Xf, doc: &Document, layout: &CanvasLayout, t: &Tokens) {
let painter = ui.painter_at(full);
+60
View File
@@ -2538,6 +2538,66 @@ const TABLE: &[(&str, [&str; 5])] = &[
["Durch übergeordnete Seite gesteuert", "Contrôlé par le parent", "Controlado por principal", "親ページで制御", "由父页面控制"],
),
("US Business Card", ["US-Visitenkarte", "Carte de visite US", "Tarjeta de visita EE. UU.", "US 名刺", "美国名片"]),
(
"Object is pinned relative to the page edge. Click to release.",
[
"Das Objekt ist relativ zum Seitenrand fixiert. Zum Lösen klicken.",
"L’objet est épinglé par rapport au bord de la page. Cliquez pour le libérer.",
"El objeto está fijado respecto al borde de la página. Haga clic para soltarlo.",
"オブジェクトはページの端を基準に固定されています。クリックすると解除します。",
"对象已相对于页面边缘固定。单击可释放。",
],
),
(
"Click to pin the object relative to the page edge.",
[
"Klicken, um das Objekt relativ zum Seitenrand zu fixieren.",
"Cliquez pour épingler l’objet par rapport au bord de la page.",
"Haga clic para fijar el objeto respecto al borde de la página.",
"クリックすると、オブジェクトをページの端を基準に固定します。",
"单击可将对象相对于页面边缘固定。",
],
),
(
"The object changes width as the page changes width. Click to lock the object width.",
[
"Die Objektbreite ändert sich mit der Seitenbreite. Zum Sperren der Breite klicken.",
"La largeur de l’objet suit celle de la page. Cliquez pour verrouiller la largeur.",
"El ancho del objeto cambia con el de la página. Haga clic para bloquear el ancho.",
"オブジェクトの幅はページの幅に合わせて変わります。クリックすると幅をロックします。",
"对象宽度随页面宽度变化。单击可锁定对象宽度。",
],
),
(
"The object's width is locked. Click to let the object change width as the page changes width.",
[
"Die Objektbreite ist gesperrt. Klicken, damit sie sich mit der Seitenbreite ändert.",
"La largeur de l’objet est verrouillée. Cliquez pour qu’elle suive celle de la page.",
"El ancho del objeto está bloqueado. Haga clic para que cambie con el de la página.",
"オブジェクトの幅はロックされています。クリックすると、ページの幅に合わせて変わります。",
"对象宽度已锁定。单击可让其随页面宽度变化。",
],
),
(
"The object changes height as the page changes height. Click to lock the object height.",
[
"Die Objekthöhe ändert sich mit der Seitenhöhe. Zum Sperren der Höhe klicken.",
"La hauteur de l’objet suit celle de la page. Cliquez pour verrouiller la hauteur.",
"El alto del objeto cambia con el de la página. Haga clic para bloquear el alto.",
"オブジェクトの高さはページの高さに合わせて変わります。クリックすると高さをロックします。",
"对象高度随页面高度变化。单击可锁定对象高度。",
],
),
(
"The object's height is locked. Click to let the object change height as the page changes height.",
[
"Die Objekthöhe ist gesperrt. Klicken, damit sie sich mit der Seitenhöhe ändert.",
"La hauteur de l’objet est verrouillée. Cliquez pour qu’elle suive celle de la page.",
"El alto del objeto está bloqueado. Haga clic para que cambie con el de la página.",
"オブジェクトの高さはロックされています。クリックすると、ページの高さに合わせて変わります。",
"对象高度已锁定。单击可让其随页面高度变化。",
],
),
("Loop", ["Loop", "Loop", "Loop", "Loop", "循环播放"]),
("Object-based", ["Object-based", "Object-based", "Object-based", "Object-based", "基于对象"]),
("Off", ["Off", "Off", "Off", "Off", "关闭"]),
+18
View File
@@ -725,6 +725,24 @@ pub(super) const TABLE: &[(&str, &str)] = &[
("Show Parent Page Overlay", "إظهار تراكب الصفحة الأصل"),
("Controlled by Parent", "تتحكم فيه الصفحة الأصل"),
("US Business Card", "بطاقة عمل أمريكية"),
("Object is pinned relative to the page edge. Click to release.", "الكائن مثبت بالنسبة إلى حافة الصفحة. انقر لتحريره."),
("Click to pin the object relative to the page edge.", "انقر لتثبيت الكائن بالنسبة إلى حافة الصفحة."),
(
"The object changes width as the page changes width. Click to lock the object width.",
"يتغير عرض الكائن مع تغير عرض الصفحة. انقر لقفل عرض الكائن.",
),
(
"The object's width is locked. Click to let the object change width as the page changes width.",
"عرض الكائن مقفل. انقر للسماح بتغيره مع عرض الصفحة.",
),
(
"The object changes height as the page changes height. Click to lock the object height.",
"يتغير ارتفاع الكائن مع تغير ارتفاع الصفحة. انقر لقفل ارتفاع الكائن.",
),
(
"The object's height is locked. Click to let the object change height as the page changes height.",
"ارتفاع الكائن مقفل. انقر للسماح بتغيره مع ارتفاع الصفحة.",
),
("Loop", "تكرار"),
("Object-based", "استنادًا إلى الكائنات"),
("Play on Page Load", "تشغيل عند تحميل الصفحة"),
+18
View File
@@ -1303,6 +1303,24 @@ pub(super) const TABLE: &[(&str, &str)] = &[
("Show Parent Page Overlay", "Mostra sovrapposizione pagina principale"),
("Controlled by Parent", "Controllato dalla pagina principale"),
("US Business Card", "Biglietto da visita USA"),
("Object is pinned relative to the page edge. Click to release.", "L’oggetto è fissato rispetto al bordo della pagina. Fai clic per sbloccarlo."),
("Click to pin the object relative to the page edge.", "Fai clic per fissare l’oggetto rispetto al bordo della pagina."),
(
"The object changes width as the page changes width. Click to lock the object width.",
"La larghezza dell’oggetto cambia con quella della pagina. Fai clic per bloccarla.",
),
(
"The object's width is locked. Click to let the object change width as the page changes width.",
"La larghezza dell’oggetto è bloccata. Fai clic perché cambi con quella della pagina.",
),
(
"The object changes height as the page changes height. Click to lock the object height.",
"L’altezza dell’oggetto cambia con quella della pagina. Fai clic per bloccarla.",
),
(
"The object's height is locked. Click to let the object change height as the page changes height.",
"L’altezza dell’oggetto è bloccata. Fai clic perché cambi con quella della pagina.",
),
("Loop", "Ciclo continuo"),
("Object-based", "Basato su oggetti"),
("Off", "Disattivato"),
+18
View File
@@ -1299,6 +1299,24 @@ pub(super) const TABLE: &[(&str, &str)] = &[
("Show Parent Page Overlay", "親ページオーバーレイを表示"),
("Controlled by Parent", "親ページで制御"),
("US Business Card", "US 名刺"),
("Object is pinned relative to the page edge. Click to release.", "オブジェクトはページの端を基準に固定されています。クリックすると解除します。"),
("Click to pin the object relative to the page edge.", "クリックすると、オブジェクトをページの端を基準に固定します。"),
(
"The object changes width as the page changes width. Click to lock the object width.",
"オブジェクトの幅はページの幅に合わせて変わります。クリックすると幅をロックします。",
),
(
"The object's width is locked. Click to let the object change width as the page changes width.",
"オブジェクトの幅はロックされています。クリックすると、ページの幅に合わせて変わります。",
),
(
"The object changes height as the page changes height. Click to lock the object height.",
"オブジェクトの高さはページの高さに合わせて変わります。クリックすると高さをロックします。",
),
(
"The object's height is locked. Click to let the object change height as the page changes height.",
"オブジェクトの高さはロックされています。クリックすると、ページの高さに合わせて変わります。",
),
("Loop", "繰り返し再生"),
("Object-based", "オブジェクト基準"),
("Off", "オフ"),
+18
View File
@@ -716,6 +716,24 @@ pub(super) const TABLE: &[(&str, &str)] = &[
("Show Parent Page Overlay", "Mostrar sobreposição da página principal"),
("Controlled by Parent", "Controlado pela página principal"),
("US Business Card", "Cartão de visita EUA"),
("Object is pinned relative to the page edge. Click to release.", "O objeto está fixado em relação à borda da página. Clique para liberar."),
("Click to pin the object relative to the page edge.", "Clique para fixar o objeto em relação à borda da página."),
(
"The object changes width as the page changes width. Click to lock the object width.",
"A largura do objeto muda com a da página. Clique para bloquear a largura.",
),
(
"The object's width is locked. Click to let the object change width as the page changes width.",
"A largura do objeto está bloqueada. Clique para que mude com a da página.",
),
(
"The object changes height as the page changes height. Click to lock the object height.",
"A altura do objeto muda com a da página. Clique para bloquear a altura.",
),
(
"The object's height is locked. Click to let the object change height as the page changes height.",
"A altura do objeto está bloqueada. Clique para que mude com a da página.",
),
("Loop", "Repetir"),
("Object-based", "Baseado em objetos"),
("Play on Page Load", "Reproduzir ao carregar a página"),
+18
View File
@@ -1300,6 +1300,24 @@ pub(super) const TABLE: &[(&str, &str)] = &[
("Show Parent Page Overlay", "Показати накладення батьківської сторінки"),
("Controlled by Parent", "Керується батьківською сторінкою"),
("US Business Card", "Візитна картка (США)"),
("Object is pinned relative to the page edge. Click to release.", "Об’єкт закріплено відносно краю сторінки. Клацніть, щоб звільнити."),
("Click to pin the object relative to the page edge.", "Клацніть, щоб закріпити об’єкт відносно краю сторінки."),
(
"The object changes width as the page changes width. Click to lock the object width.",
"Ширина об’єкта змінюється разом зі сторінкою. Клацніть, щоб заблокувати ширину.",
),
(
"The object's width is locked. Click to let the object change width as the page changes width.",
"Ширину об’єкта заблоковано. Клацніть, щоб вона змінювалася разом зі сторінкою.",
),
(
"The object changes height as the page changes height. Click to lock the object height.",
"Висота об’єкта змінюється разом зі сторінкою. Клацніть, щоб заблокувати висоту.",
),
(
"The object's height is locked. Click to let the object change height as the page changes height.",
"Висоту об’єкта заблоковано. Клацніть, щоб вона змінювалася разом зі сторінкою.",
),
("Loop", "Зациклити"),
("Object-based", "На основі об’єктів"),
("Off", "Вимкнено"),
+1
View File
@@ -398,6 +398,7 @@ It is evidence of breadth: each item exists. It is not a claim of InDesign-level
- Type on a Path (⇧T tool, `type.onPath`): a story along any line, curve or shape on screen and in PDF; Type on a Path Options (start, flip, baseline/ascender/descender/centre) and Delete Type from Path. Round-trips through IDML as TextPath; on-path caret drawing is still to come.
- Preferences › Appearance of Black: 100% K on screen accurately (dark grey) or as rich black (`window.richBlack`); the printing/export side is still to come.
- Spreads of up to 10 pages: Add to Previous Spread and Allow Spread to Shuffle (Pages panel; `layout.pages.toSpread`, `layout.spreadShuffle`); inserted pages go around kept spreads.
- Page tool (⇧P) and `layout.pageSize`: pages of their own size (or a preset); the spine stays put and objects keep their place on their page. A click selects a page (handles, its liquid page rule tagged above it); dragging a handle previews the liquid rule and springs back, Alt-drag resizes, Shift keeps proportions, with a W/H readout; `anchor` keeps a reference point in place; double-click for exact sizes. With the Page tool the Control panel shows the page (reference point, W/H, preset, orientation, Liquid Page Rule including Controlled by Parent, Show Parent Page Overlay); X/Y and Objects Move with Page are shown, but pages don't move within their spread yet. On an object-based page it selects objects and shows their pins and width/height locks on the canvas (click to toggle, with tooltips).
- Page tool (⇧P) and `layout.pageSize`: pages of their own size (or a preset); the spine stays put and objects keep their place on their page. A click selects a page (handles, its liquid page rule tagged above it); dragging a handle previews the liquid rule and springs back, Alt-drag resizes, Shift keeps proportions, with a W/H readout; `anchor` keeps a reference point in place; double-click for exact sizes. With the Page tool the Control panel shows the page (reference point, W/H, preset, orientation, Liquid Page Rule, Show Parent Page Overlay); X/Y are shown, but pages don't move within their spread yet.
- File › Print (⌘P): printer, copies, page range, spreads, marks, bleed; printed as PDF through the system spooler (`file.print`, `file.printers`, `dryRun` for agents). Shortcuts now act like choosing the menu item (dialogs open), and UI commands win shortcut ties (⌘N opens New Document).
- Nested styles (through/up to N sentences, words, characters, letters, digits, tabs, breaks, spaces or given characters) and GREP styles (regex → character style), edited in Paragraph Style Options and composed under local formatting; `ui.dialog.open` for agents. Nested line styles are still to come; nested and GREP styles round-trip through IDML.