Commit Graph
955 Commits
Author SHA1 Message Date
aiongg fbfc4eecf9 Merge #394: CJK interface text from installed fonts, on the Latin baseline
Conflict: crates/ui-egui/src/theme.rs install_fonts: the PR's
system_ui_fonts/add_system_fallbacks replace next's #126 system-font loop
(fallback_for per CJK sample char into system-ui-{id} faces when
CRAFT_FONTS is empty), so installed faces are not loaded twice. No #126
helper in theme.rs is left unused; FontDb::fallback_for stays (compose,
images use it).
2026-10-10 23:29:09 +00:00
aiongg ea69df5bff Integration: canvas edits patch only a full-resolution texture (#393)
patch_texture writes full-resolution dirty rects with set_partial; when
upload() has shrunk the canvas texture to max_texture_side (a viewport
wider than the GPU limit), the edit takes a full render instead of a
partial write past the texture's bounds (a wgpu validation error). Test:
edits_patch_the_canvas_only_at_full_resolution.

The content ghost proxy goes through widgets::fit_texture (capped at 4096)
instead of skipping graphics larger than the limit.
2026-10-10 23:28:09 +00:00
aiongg 9ba7e9e8c7 Merge #393: no crash on textures past the GPU limit
No conflicts.
2026-10-10 23:25:09 +00:00
aiongg 0c1d021dfd Integration: macOS menu bar rebuilds when Show CJK Features changes (#397, #336)
NativeMenu keys its rebuild on (language, cjk_features(app)), so the
CJK commands that menus::shown filters appear or disappear at once.
2026-10-10 23:24:57 +00:00
aiongg 3667fcc3a3 Merge #397: macOS menu bar follows the interface language at once
No conflicts.
2026-10-10 23:24:36 +00:00
aiongg 62fe6eb23b Merge #396: the welcome screen's Discord button clears the text beside it
No conflicts.
2026-10-10 23:24:27 +00:00
aiongg 153fa60054 Merge #388: Show the Pencil stroke while drawing
Conflict: crates/ui-egui/src/canvas.rs draw_tool_overlays: the PR's
Overlay::Path arm (draw_path_overlay) and next's Overlay::ContentGhost
arm both kept; draw_path_overlay sits before draw_content_ghost.
2026-10-10 23:23:48 +00:00
aiongg 0430763918 Merge #325 update: New Document in the progress docs
The PR was rebased onto upstream main; its code commits are unchanged
(range-diff shows only ROADMAP lines moved into the new docs commit), so
next already carries them.

Conflicts: crates/ui-egui/src/{dialogs.rs,i18n.rs,i18n/it.rs,lib.rs}:
next's versions (the old PR code plus next's own dialogs, findFont and
numberingSection work). ROADMAP.md and docs/target-app-parity.md take the
PR's New Document entries.
2026-10-10 23:22:41 +00:00
aiongg 62df5e764a Merge file-open-os: Save adds .designcraft, and the OS opens DesignCraft and IDML files
- apps/designcraft/Cargo.toml: the macOS target keeps objc2 0.6 / objc2-app-kit 0.3 (IME) and
  adds fmv-macos-events =0.1.0, which uses the same objc2 and objc2-app-kit versions.
- apps/designcraft/src/main.rs: the shared Arc<gpu::Startup>, catch_unwind and restart flow
  stay; the Apple-event handlers are installed before run_native (outside catch_unwind, held
  until the window ends), the app drains the inbox each frame, and documents that arrived are
  noted on the Startup. The open dialog keeps the INDD/INDT filter and ends with All files.
  The open-filter test checks both; the save-dialog test is added.
- apps/designcraft/src/gpu.rs: Startup::opening records the documents the OS handed this run;
  a start again after a graphics failure (both finish and the first-frame watch) passes them
  as file arguments, since Finder doesn't send them twice.
- apps/designcraft/src/apple_events.rs: poll returns the documents it handed the app, and
  queued() returns those still in the inbox when the window ends.
- crates/engine/src/cmd/file.rs: file.open decides by content first (IDML by its mimetype
  entry, then a DesignCraft package or JSON), then an InDesign file by its signature or
  .indd/.indt extension, then a .idml or .designcraft extension for the reader's own error;
  anything else is "not a DesignCraft or IDML file". INDD stays in file.openBytes. Save
  commands add .designcraft as on file-open-os; the params docs describe all of it.
- crates/engine/src/cmd/mod.rs: re-exports from both sides (is_document,
  with_document_extension and layout::chapter_numbering).
2026-10-10 23:21:12 +00:00
con3codeandClaude Opus 5.5 6252dc3737 UI: the welcome screen's Discord button clears the text beside it
The community card is wider and its text wraps before the button's
space, so a longer translation of the line under the title no longer
runs under the button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013phQ3ekq6uGBEWD6FjFYG2
2026-10-11 07:49:49 +09:00
con3codeandClaude Opus 5.5 cc12ea576f macOS: the menu bar follows the interface language at once
The system menu bar was built once at launch, so Edit › Interface
Language changed the panels but left the menus in the old language
until the next launch. It is rebuilt when the language changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013phQ3ekq6uGBEWD6FjFYG2
2026-10-11 07:49:21 +09:00
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
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 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 70a04944a5 Layout: the CLI's performance document builds its graphics with a wrap 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
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
aiongg c1c44a3a2a Integration: German entry for the Layers panel's selection square 2026-10-10 20:07:31 +00:00