Commit Graph
2702 Commits
Author SHA1 Message Date
aiongg bc357c3885 Integration: German entry for Kanji 2026-10-10 22:47:23 +00:00
con3codeandClaude Opus 5.5 a62188aa9b UI: CJK interface text from installed fonts, on the Latin baseline
Without the craft-fonts build input the interface had no CJK glyphs:
egui can't find system fonts, so Japanese and Chinese menus and labels
drew as boxes, and Korean and Traditional Chinese font names in the
font menus did in every build.

- The first installed UI face of each script (Japanese, Simplified
  Chinese, Traditional Chinese, Korean; macOS, Windows and Linux
  families) is added as a fallback for the scripts craft-fonts doesn't
  cover.
- A fallback face sits on the UI face's baseline: egui centres a
  fallback's line height in the primary's, so a CJK face with a taller
  ascent or a line gap sat above or below the Latin text beside it.
  The tweak is computed from the two faces' line metrics.
- The interface language's script comes first, before the built-in CJK
  faces, so Han characters take that language's forms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013phQ3ekq6uGBEWD6FjFYG2
2026-10-11 07:47:14 +09:00
aiongg 47736dfb5b Merge swatch-layer-rename: Swatch Options and Layer Options dialogs rename them
Conflict resolutions:
- crates/engine/src/cmd/layout.rs: next's start_number, chapter_numbering and
  layer.move validation kept; the branch's set_layer added after them;
  spread_rotation_input_tests and layer_options_tests both kept.
- crates/engine/src/cmd/style.rs: next's delete_tests and the branch's
  swatch_options_tests kept as separate modules.
- crates/ui-egui/src/dialogs.rs: both module declarations (style_cjk,
  options) and both confirm arms (deleteCharacterStyle, swatchOptions /
  colorGroupOptions / layerSettings) kept.
- crates/ui-egui/src/i18n.rs, i18n/{ar,it,ja,pt_br,uk}.rs: both sides' rows
  appended; no key was duplicated.
- crates/ui-egui/src/panels/layers.rs: #378's drag-and-drop row
  (Sense::click_and_drag, deferred cmds, payloads) kept; the branch's
  accessibility name, double-click -> app.layerOptionsDialog (after the
  eye/lock/triangle/selection-square branches, before activate) and the
  Layer Options for "<name>"... context entry added through cmds.
- crates/ui-egui/src/panels/swatches.rs: next's apply_swatch kept, with the
  branch's single-click-only guard so a double-click opens Swatch Options.

Integration:
- Document::rename_swatch_refs also renames table cell stroke gap colours
  (CellStroke and CellStrokeAttrs gap_color), kenten and ruby fill/stroke
  colours (CharAttrs kenten_fill, kenten_stroke, ruby_fill, ruby_stroke)
  and paragraph border gap colours (ParaAttrs border_gap_color).
- The swatch rename test covers a table's cell gap colour, kenten fill,
  ruby stroke and border gap colour.
- The Layer Options double-click test checks that the double-click does
  not reorder layers.
- German rows for the 29 new shared keys in i18n/de.rs.
2026-10-10 22:46:57 +00:00
con3codeandClaude Opus 5.5 bf173db1de UI: no crash on textures past the GPU limit
The Glyphs panel drew its whole grid as one texture: up to 1200
characters of a large CJK font in a narrow panel (7 columns x 60 px)
made it 10320 px tall and wgpu panicked past the 8192 px limit. The
grid now stops at the rows the largest texture holds, and every UI
texture goes through widgets::fit_texture / load_texture, which
sample an oversized image down instead of panicking.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013phQ3ekq6uGBEWD6FjFYG2
2026-10-11 07:46:07 +09:00
aiongg 11532d961e Documents: Save adds .designcraft, and the OS opens DesignCraft and IDML files
- file.save / file.saveAs / file.saveACopy add the .designcraft extension to a
  given path that lacks it and report the path written; saving back to the
  document's own file keeps its name.
- file.open tells DesignCraft and IDML packages apart by content, so files
  without an extension open; anything else is "not a DesignCraft or IDML file".
- Dropped or web-picked files without an extension open as documents when their
  content is one.
- Desktop save dialogs filter on the suggested extension and add it to a name
  typed without it, asking before replacing an existing file; the open dialog
  gains "All files".
- macOS: open-documents Apple events (Finder, Dock, Open With) through
  fmv-macos-events, queued until the window is ready; Info.plist declares the
  .designcraft type and an imported .idml type with CFBundleDocumentTypes.
- Windows MSI: .designcraft ProgId with an Open verb, IDML under Open with.
- Linux: shared-mime-info for both types and MimeType in the .desktop file.

Fixes #158, #211, #375
2026-10-10 22:40:06 +00:00
aiongg bf8c3486f1 Swatches and layers: Swatch Options and Layer Options dialogs rename them
- swatch.options: rename, Name with Color Value, process/spot, colour mode
  and values, tint, in one undo step; special swatches keep their names,
  and a taken or empty name changes nothing.
- Document::rename_swatch_refs points every use at a renamed swatch:
  tints, colour groups, inks, paragraph/character/object/cell/table
  styles, item fills, strokes, gaps, effects and column rules, text
  colours, rules, shading, borders, table cells and the footnote rule.
- layer.set takes every Layer field (show guides, suppress wrap when
  hidden), a layer colour name, and rejects empty or duplicate names and
  unknown colours.
- Swatches panel: double-click or Swatch Options… opens the dialog;
  colour groups get Color Group Options…. Layers panel: double-click or
  Layer Options for "name"… opens Layer Options (app.layerOptionsDialog).
2026-10-10 22:37:47 +00:00
aiongg bafd86d65e Merge content-move: move a placed graphic inside its frame
Direct Selection selects and drags a frame's content, the Selection tool
drags it by the content grabber, and double-clicking a frame with content
toggles between frame and content, alongside #84's text threading and
canvas click counting.

Conflicts:
- crates/tools/src/select.rs: module doc keeps both paragraphs (ports,
  content). The frame/content toggle runs on the second press of a double
  click (Down with clicks 2, or a DoubleClick from the control channel),
  Selection tool only, after threading ports and the text-frame
  double-click, so those keep priority; the DoubleClick arm stays empty.
  Overlays keep the Drag::Place marquee and add the content ghost.
- crates/tools/src/tests.rs: both sets of tests and fixtures kept; the
  graphic fixture sets Graphic::wrap; the double-click toggle test drives
  the click-count sequence and the DoubleClick form.
- crates/engine/src/tests.rs: both sets of tests kept.
- crates/engine/src/cmd/object.rs: both test modules kept.
2026-10-10 22:37:06 +00:00
noah1400andClaude Opus 5.5 4e8575b5c8 Merge main into fix/188-smart-guides-vertical
ROADMAP.md was restructured in #355 and its feature list moved to
docs/target-app-parity.md. The smart guides line this branch reworded
is changed there instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:35:30 +02:00
aiongg 971cad3c0f Tools: move a placed graphic inside its frame
Direct Selection selects and drags a frame's content; the Selection tool
drags it by the content grabber (hand cursor, shown on hover too) and
double-clicking a frame toggles between frame and content. Arrow keys
nudge a content selection. transform.move takes content?: bool (default:
the selection's content flag) and moves the placed graphic or pasted-in
items in the frame's inner space; nested items move in their container's
space. A content drag shows the whole graphic faintly with its bounds.
2026-10-10 22:21:06 +00:00
moppeeerandClaude Opus 5.5 f6e96d2106 fix(ui): Show the Pencil stroke while drawing
The Pencil tool's stroke only appeared once the mouse button was
released. The tool reported the stroke so far as a path overlay, but the
canvas skipped path overlays (they were never drawn), so nothing showed
while drawing. The canvas now draws them: curves flattened to about a
quarter of a screen pixel, dashed when asked. That also brings back the
Smooth and Erase tools' dashed drag previews.

The Pencil's preview was black, lost on a dark pasteboard; it is drawn in
the colour of the layer the path goes on, as InDesign does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:18:59 +02:00
aiongg f359098e8e Merge #374: Russian interface
Conflict: ui-egui i18n.rs tr_context (#374's match with next's Japanese context arm).
2026-10-10 22:12:52 +00:00
moppeeerandClaude Opus 5.5 543fc41016 docs: New Document in the progress docs
Rebased on the progress-docs restructure (#355): the ROADMAP bullets this
PR added moved to the inventory in docs/target-app-parity.md, and the
ROADMAP progress log gets a line for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:06:58 +02:00
moppeeerandClaude Opus 5.5 f67f604bbb fix(ui): Keep Enter and Escape in the Save Document Preset popup; saved presets in the engine
Review follow-up. Enter in the Save Document Preset popup created the
document and Escape closed the whole dialog: the dialog footer took
both keys while a popup was open. The dialog now leaves Enter and
Escape to an open popup (read before it draws, as egui closes a popup
on Escape that frame): Enter in the preset name saves the preset,
Escape closes only the popup. Clicking the name field no longer closes
the popup either (menus close on any click; this one only outside), and
the field takes focus when the popup opens.

Saved presets lived only in the UI state, so `file.new {preset: name}`
refused them. They are now engine preferences (saved with prefs.json):
`file.savePreset {name, …the file.new settings}` replaces a preset of
that name and refuses built-in names, `file.deletePreset {name}` removes
one, `file.presets` lists them after the built-in ones (`saved: true`),
and `file.new {preset}` makes documents from them by name. The Saved tab
reads and writes them through those commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:00:29 +02:00
moppeeerandClaude Opus 5.5 f78d667d89 feat(ui): Lay out the New Document window like InDesign's
File > New > Document now shows Recent, Saved, Print, Web and Mobile
tabs of page cards (drawn to the preset's proportions; double-click
creates) beside the preset's details: document name, width and height
with arrows, units, orientation, pages, start page #, facing pages,
primary text frame, columns and gutter, and collapsible margins and
bleed and slug per edge with link toggles. Save Document Preset keeps
presets by name; documents made are remembered for the Recent tab.
Small windows stack the details above the presets and scroll; the
layout mirrors for right-to-left languages. New strings go through the
translation tables (Italian, German, French, Spanish, Japanese, Chinese).

file.new takes intent, units, startPage and per-edge bleed and slug.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:00:28 +02:00
aiongg b6b5d4c705 Merge table-cell-strokes: edits start from the drawn edge, bounded dash patterns, Cell Options fixes, closed corners
Conflict: ui-egui dialogs.rs tests (the branch's new test kept; its copies of the dialog test helpers already on next dropped).
2026-10-10 21:45:22 +00:00
aiongg ac4b83fa39 Tables: cell stroke edits and queries start from the drawn edge; bounded dash patterns; closed table corners
- table.setCell starts each chosen edge from the stroke rendering draws there (the winning
  copy of a shared edge, the row/column pattern, or the table border) and writes the result
  to both copies; table.getCellStroke reports drawn edges, counting each shared edge once.
  compose::table::cell_side_strokes shares the resolution with the renderer.
- Commands accept dash patterns of 1-64 lengths, each 0 or 0.1-10000 pt. Screen and PDF
  draw a dash or dot pattern that would repeat more than 20000 times along a path as solid.
- Stripes, wavy, hash and gap colour extend by half the weight at table corners.
- Cell Options: an edge change reseeds every stroke field and tolerates a non-object seed.
- Edge proxy: a triple-click decides from the choice before the first click.
2026-10-10 21:44:09 +00:00
aiongg 17c7bb3fd2 Merge contour-wrap: wrap both sides of an object and around its contour
Combines contour-wrap (wrap side, contour type, multi-segment lines) with
the placed-graphic and nested wraps already on next.

- crates/compose/src/lib.rs: exclusion() and the new graphic_exclusion()
  share wrap_exclusion() (offsets, spine sides resolved per page, contour).
  wrap_obstacles() builds every obstacle through them: the item's own wrap,
  the graphic's wrap around its shown bounds, and children of groups and
  pasted-into frames with their own transform (depth <= 64). Contour type
  Bounding Box follows the shown part of the graphic, other types the frame
  path. wrap_slot() returns all free segments (free_slots) and steps 1 pt
  at a time beside a contour; Jump Object stays in wrap_slot only. The line
  loop keeps grid gyoudori, Jump Object leading steps and grid snapping for
  a line's first segment, and carries the other segments (with the line's
  grid end) to the next lines; estimate_slots() lists every segment through
  wrap_slot(). hit_line() breaks ties between segments by x, used by hit()
  next to the drop-cap lookup.
- crates/compose/src/tests.rs: both sides' tests; the hostile-geometry
  test builds Exclusion with side and contour.
- crates/engine/src/cmd/object.rs: object.textWrap is text_wrap() with
  mode/side/contour (unknown values are errors) and content?, applied to
  the frame's or the graphic's wrap.
- crates/idml/src/import.rs, export.rs: ContourOption/@ContourType is read
  in the shared text_wrap() and written by text_wrap_pref() as a child of
  TextWrapPreference after Properties, so graphic wraps carry it too.
- crates/idml/src/tests.rs: both sides' tests. tests/wrap.rs gains a test
  of a contour, right-side wrap on a placed graphic shown in part.
- crates/ui-egui/src/panels/mod.rs: the Text Wrap panel's side and contour
  combos read the targeted wrap (tw), the graphic's when content is selected.
2026-10-10 21:39:26 +00:00
aiongg fbfd0b2fe9 Merge gpu-startup: recovered documents survive restarts, the watchdog only restarts a hung adapter, software adapters last, the skip list as an argument
Conflicts: designcraft main.rs ui() (#366's macOS marked-text discard, then the startup watch's leave);
engine recovery.rs (the branch's rewrite-then-discard with next's bump_revision).
2026-10-10 21:28:17 +00:00
aiongg fbda023d7f Layout: wrap both sides of an object and around its contour
Lines beside an object that lets text through on both sides are set in
segments, left then right, and the paragraph runs on from one to the
next. One-sided wraps (left, right, spine sides, largest area) block the
other side. A contour wrap follows the object's outline band by band,
with the offset around it; graphic frames follow their contour type
(bounding box of the graphic, frame path, same as clipping; detected
edges, alpha channel and image paths follow the frame path). The Text
Wrap panel sets the wrap side and contour type through object.textWrap,
and IDML import and export keep ContourOption.
2026-10-10 21:28:03 +00:00
aiongg aa743eee88 Merge kanji-page-numbers: Kanji page numbers
Conflicts: engine layout.rs and notes.rs params docs (next's lists plus kanji).
2026-10-10 21:27:19 +00:00
aiongg 158f366af8 Startup: restarts keep recovered documents, a busy UI never counts as a GPU hang, software renderers last
- Recovery: file.recovery.open moves each entry to the reopened document's uid
  (written before the old one is removed), so recovered documents stay on disk
  until saved or closed, also when the app restarts on another adapter or
  stops before its first recovery save.
- First-frame watch: a late first frame is logged and noted in the status bar.
  The adapter counts as hanging only when the UI thread has been stuck outside
  the app's code (logic/ui mark entry and exit) with no progress for 60 s while
  the window isn't known to be minimized, occluded or unfocused. The watch asks
  for a repaint on each look, so an idle UI ends it. VectorCraft restarts on
  the late frame alone, which a held-back compositor or a long compose can set
  off.
- Software renderers (WARP, llvmpipe) are passed over while another backend is
  left; once no hardware adapter of any backend could show the window, the app
  starts again with them allowed, once.
- A restart clears gpu.json's backend entry just before exec or spawn and puts
  it back when starting again fails. Backends a restart left out are no longer
  recorded as failed.
- The watch ends a hung process with TerminateProcess on Windows.
- The skip list travels as the restarted app's --gpu-skip= argument instead of
  an environment variable, so processes the app starts don't inherit it.
2026-10-10 21:26:51 +00:00
aiongg ee529362d6 Merge rtl-master-sides: right-to-left binding puts parent page items on the right side
Conflict: idml tests.rs test modules (both).
2026-10-10 21:26:39 +00:00
aiongg 70a04944a5 Layout: the CLI's performance document builds its graphics with a wrap 2026-10-10 21:26:25 +00:00
aiongg 9d8bdaef2c Merge wrap-placed-graphic: the CLI's performance document 2026-10-10 21:26:25 +00:00
aiongg d32134d337 Merge wrap-placed-graphic: text wrap set on a placed graphic wraps text
Conflicts: compose lib.rs imports (both; Composer unused), idml tests.rs (both test modules), ui-egui
panels/mod.rs (next's ruler origin with the branch's graphic wrap for Direct Selection).
2026-10-10 21:26:25 +00:00
aiongg cdd32a5066 Layout: right-to-left binding puts parent page items on the right side
A right-to-left bound spread lists its right page first, parent spreads
included. The parent page shown behind a document page was picked by list
index (first = left), so every page of an imported right-to-left document
showed the other side's parent items. Pick it by position instead: the
leftmost parent page for a left page, the rightmost for a right page.

New parent spreads in a right-to-left document list their pages right
first, and changing the binding reorders existing parent spreads, so IDML
export writes them in binding order. Spread bleed on the canvas and in
spread PDF export takes the outer edges by position as well.
2026-10-10 21:24:02 +00:00
aiongg 720165a709 Merge layers-drag: group members move with their group, no-op drops record nothing, locked layers need Cmd 2026-10-10 21:23:20 +00:00
aiongg c28387eaf9 Sections: Kanji page numbers
Kanji numbering style (一, 二, 三, …, written digit by digit: 10 is 一〇)
for sections, footnotes, endnotes and lists. IDML PageNumberStyle and
FootnoteNumberingStyle read and write Kanji and the leading-zero styles;
the list format "一, 二, 三, 四..." maps to it.
2026-10-10 21:23:01 +00:00
aiongg 7f2b5cfa68 Layout: text wrap set on a placed graphic wraps text
A placed graphic carries its own text wrap (Graphic.wrap). IDML import
reads TextWrapPreference on the Image/PDF element and export writes it
back there. Layout treats it as an obstacle around the part of the
graphic its frame shows, plus the offsets, and also collects wraps of
items inside groups. object.textWrap acts on the graphic when the
selection is the frame's content, and the Text Wrap panel shows its wrap.
2026-10-10 21:23:00 +00:00
aiongg b84a58391f Layers: group members move with their group; no-op reorders leave history alone; Cmd for locked layers
- object.setLayer moves a group member's top-level group (and its members)
  and rejects an unknown or missing layer; object.reorder sets the layer on
  moved groups' members too.
- object.reorder returns without editing when the order and layers would
  not change, so no undo step is recorded.
- Layers panel: locked and hidden layers take object and selection drops
  only with Cmd/Ctrl held; the selection square drops the selected
  members' top-level groups.
2026-10-10 21:22:57 +00:00
aiongg c403cae4c7 Merge #83 update (feat/layout-parity f386a98d): Em Box Height first baseline offset
Conflicts: fonts fontdb.rs (the branch's em box with its from-BASE flag beside next's ICF cache); idml
tests.rs (the branch's copies of tests already on next, and the mojikumi test #129 replaced, dropped;
the Em Box Height test kept). German entry for Em Box Height.
2026-10-10 21:16:13 +00:00
aiongg f386a98d7c Layout: Em Box Height first baseline offset
The first baseline sits the em box top below the frame's top inset: the
font's BASE em box (idtp, else ideo + 1 em), else 0.88 em, for the
largest size on the first line. IDML FirstBaselineOffset="EmboxHeight"
imports and exports as itself; the footnote options list it and the
frame and footnote option commands take emboxHeight.
2026-10-10 21:04:33 +00:00
skylar taylor-barrick c62866443c UI.9: integrate shared panel docking and preserve workspace behavior 2026-10-10 14:42:40 -06:00
aiongg 754d09ac2d Merge table-cell-strokes: the style test names the [Black] swatch 2026-10-10 20:38:00 +00:00
aiongg 43d6a5264d Tables: the style test names the [Black] swatch, which style strokes now check 2026-10-10 20:37:55 +00:00
aiongg 16bb39e531 Merge gpu-startup: pick the GPU that drives the display, fall back across adapters and backends, and log startup errors (#273, #334) 2026-10-10 20:30:59 +00:00
aiongg 23da490a42 Merge table-cell-strokes: cell edge strokes in the Stroke panel and Cell Options, with gap colour and tint (#370)
Conflicts: ui-egui dialogs.rs (next's numberingSection arm and the branch's cellOptions arm; the branch's
copies of the dialog test helpers already on next dropped, its cell options test kept); idml tests.rs and
the i18n tables appended at the end on both sides (both kept; the branch's Gap Tint: and Tint: rows that
next already had dropped).
2026-10-10 20:30:54 +00:00
aiongg 279336c445 Startup: pick the GPU that drives the display, restart on the next adapter or backend, and log startup errors
Ported from VectorCraft's start-up fixes (#502, #545, #651, the display-GPU
choice, #806, #964) and reconciled with the backend fallback of #297:

- The app picks the window's adapter itself (eframe's native_adapter_selector,
  apps/designcraft/src/gpu.rs): adapters that can't present never, then
  WGPU_ADAPTER_NAME, hardware before software, native backends before OpenGL,
  the GPU that drives the primary display (Windows EnumDisplayDevices through
  winsafe, Linux /sys/class/drm), the power preference (WGPU_POWER_PREF;
  otherwise power saving on Windows and macOS, the system's order elsewhere),
  then DX12 before Vulkan. Every adapter and the choice are logged.
- wgpu's indirect-call validation is off (WGPU_VALIDATION_INDIRECT_CALL=1 turns
  it back on): its compute shader failed to compile on an Intel Mac and lost
  the Metal device (#334, first error).
- run_native runs under catch_unwind. A wgpu error or a panic in wgpu,
  egui-wgpu or naga during the first frames, or a first frame that doesn't
  reach the screen in 20 s, starts the app again without that adapter
  (DESIGNCRAFT_GPU_SKIP; exec on Unix, a new process on Windows). When no
  adapter of the start's backends is left, it starts again with the next
  backend. Each restart leaves out one more adapter or backend, so they end.
  Adapters without PCI ids (Metal) are keyed by name.
- The backend fallback (gpu/backend.rs, gpu.json) stays for driver faults that
  take the process down. Windows tries DirectX 12, then OpenGL, then Vulkan,
  each in its own instance: Vulkan last because creating its instance loads
  every installed Vulkan driver, and OpenGL kept out of the DX12 instance
  because creating it crashed in AMD's atio6axx.dll (#167).
- main returns an ExitCode and logs why the app stopped to standard error and
  the log file, which is all a Windows start without a console leaves (#273).

README, architecture, gaps, hardware and target-app parity docs and ROADMAP
describe the choice, the restarts and the variables.
2026-10-10 20:26:06 +00:00
aiongg cce6f986c5 Tables: cell and table style strokes take type, gap colour and gap tint
style.cell.create/edit stroke and style.table.create/edit border use the
table.setCell stroke parser: type, gapColor (alias gapSwatch) and gapTint, with
the same validation. A bad value is an error and changes nothing.
2026-10-10 20:25:40 +00:00
aiongg 57d9761c69 Tables: cell strokes in the Stroke panel and Cell Options › Strokes and Fills
With cells selected, or the text cursor in a cell, the Stroke panel edits the
cell edges chosen on a drawn edge proxy: weight, type, colour, tint, gap colour
and gap tint. A click toggles a line, a double-click chooses all outer or all
inner lines, a triple-click chooses or clears all. Table › Cell Options ›
Strokes and Fills… has the same proxy and fields plus the cell fill colour and
tint, and applies the changed values in one undoable step. Translations for
the new strings in every interface language.
2026-10-10 20:16:53 +00:00
KnottyDyesandClaude Opus 5.5 f15781dafa SVG: a font family named in any case finds the installed font
DesignCraft matched an SVG font-family case-insensitively when importing
the installed faces, but the final fontdb query compares names exactly,
so "DeJaVu SaNs" loaded DejaVu Sans and then set the text in the serif
fallback (Source Serif 4) without a word. Text frames already accept any
case. The SVG font selector now runs usvg default query with each named
family spelled the way the font database spells it; family order,
generics, weight, stretch and style are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BSB7fMQUccqFQekksDGWpo
2026-10-10 14:12:52 -06:00
aiongg c1c44a3a2a Integration: German entry for the Layers panel's selection square 2026-10-10 20:07:31 +00:00
aiongg e33cb52248 Merge layers-drag: drag layers and objects to reorder them in the Layers panel (#371) 2026-10-10 20:07:20 +00:00
aiongg 1b9125ceea Layers: drag layers and objects to reorder them
- object.reorder {ids, above|below: id | index, layer?}: restacks sibling
  objects in front of or behind a target, or at an index counted from the
  top of a layer, moving them to that layer. Group members stay in their
  group. Bad input is an error and leaves the document unchanged.
- layer.move rejects a missing id or an out-of-range index.
- Layers panel: drag a layer row to reorder layers, an object row to
  restack it or move it to another layer, and a filled selection square
  onto a layer to move the selection there; a line or box shows the drop.
  Groups expand to list their members. Layers list top (frontmost) first,
  matching the stacking order.
2026-10-10 20:06:34 +00:00
aiongg 20d4178c43 Tables: cell edge gap colour and tint, all stroke types on cell edges, inner horizontal/vertical edge choice
CellStroke and cell/table style edge attributes carry gap colour and gap tint
(IDML ...EdgeStrokeGapColor/GapTint, ...BorderStrokeGapColor/GapTint). The table
renderer and PDF export draw every stroke type on cell edges, with the gap colour
under dashes, dots and stripes.

table.setCell validates stroke values, takes gapColor/gapTint and an edges list
(top/left/bottom/right are the target range's outer sides; innerHorizontal and
innerVertical the lines between its rows and columns). table.getCellStroke reports
the shown values of the chosen edges, null where they differ.
2026-10-10 20:04:57 +00:00
Wondarkus f5da9d2b58 feat(i18n): apply russian language wiring patch 2026-10-10 23:56:21 +04:00
aiongg 74eda5579f Merge canvas-context-menu: the menu reopens on a second right-click, blocks both panes, and follows menu hiding 2026-10-10 19:29:37 +00:00
aiongg 1fe1ec9cc6 UI: canvas context menu reopens on a second right-click; menu keeps both panes' input
- A right-click while the menu is open closes it as a click outside;
  the request now stays until a frame ends with the menu open, so the
  menu reopens at the new click with the new target selected.
- While a context menu is open in either split-view pane, neither pane
  takes pointer presses, guide drags or keys. The open state is read
  once per frame, so the Escape or click that closes pane 0's menu does
  not reach pane 1.
- Submenus copied from the menu bar (Arrange, Select, Fitting, Type
  submenus...) are keyed by their menu bar path, so rows hidden with
  Edit > Menus are hidden in the context menu too, with Show All Menu
  Items below.

Tests: reopening on another object, Escape in split view, Escape with a
non-selection tool and a selection, the Type tool's keep-or-place-caret
rule, and hidden rows in a context submenu.
2026-10-10 19:29:13 +00:00
aiongg d5fb84d5e1 Merge nobreak-justify: jidori runs keep their width; tests for nonbreaking-space lines 2026-10-10 19:22:40 +00:00
aiongg 0474a8b5ec Compose: jidori runs keep their width when their spaces could stretch; tests for nonbreaking-space lines 2026-10-10 19:22:22 +00:00