Commit Graph
191 Commits
Author SHA1 Message Date
Brandon ThomasandClaude Opus 5.5 8d2d180062 Merge origin/main into multi-language-fix
Resolve i18n conflicts: keep this branch's revised zh/ar wording plus
main's new rows (font-name, missing-glyph, Korean line-break labels).
Brazilian Portuguese (#103) now uses the same cached HashMap lookup as
Arabic; the cached-lookup test covers pt-br too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 22:32:13 -04:00
Brandon Thomas e97d98977f Merge pull request #103 from RicSchonfelder/i18n-pt-br
i18n: add Brazilian Portuguese (pt-br) UI translation
2026-10-07 22:13:15 -04:00
Brandon Thomas aee756d604 Merge remote-tracking branch 'origin/main' into feat/cjk-and-fonts
# Conflicts:
#	crates/ui-egui/Cargo.toml
2026-10-07 22:04:42 -04:00
Brandon Thomas 864d0b6008 Merge pull request #53 from epfabian/middle-mouse-pan
Canvas: middle-mouse drag pans the view
2026-10-07 22:04:01 -04:00
Brandon Thomas a42bd84e89 Merge pull request #79 from aiongg/fix/34-transform-dialogs
Transform: Rotate and Shear open their dialogs (#34)
2026-10-07 22:03:56 -04:00
Brandon ThomasandClaude Opus 5.5 fdffbb4b23 M9: distinct zh label for Revert; translations are our own
Revert no longer shares Undo's Simplified Chinese label. Drop the
comments and ROADMAP wording that tied terminology to a vendor's help.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 22:01:57 -04:00
Brandon ThomasandClaude Opus 5.5 927191d25f About: contributor and model credits compiled in (grab bag + table, self-submitted names) (#108)
* About: contributors compiled in from contributors.json (grab bag + table, sortable, name toggle)

Adds the craftrules standard (standards/contributors.md) to Help > About DesignCraft, which now
has tabs About · Contributors · Models (`help.about {tab}` selects one).
contributors/contributors.json is generated by craftrules/scripts/contributors.py and baked
into the binary by crates/ui-egui/build.rs as static tables (crates/ui-egui/src/credits.rs).
Each contributor line: @username, opt-in display/real name, PRs, commits, lines +/−/Δ,
binary assets +/−, first/last commit. Sortable by every column; alphabetical ignores
case and the leading @.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors docs: craftrules is two levels up (../../craftrules)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: self-submitted names in contributors/people.toml; AGENTS.md credit-yourself section

build.rs reads contributors/people.toml next to the generated contributors.json and shows a name only
for entries the generator verified as written by that person (craftrules standards/contributors.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: regenerate (verified people.toml entries)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:16:42 -04:00
RicSchonfelder bd8291c55f i18n: add Brazilian Portuguese (pt-br) UI translation
Registers pt-br in the interface-language menu (Edit › Interface
Language) with a dedicated pt_br.rs catalog mirroring the ar.rs
pattern: 1005 (en, pt-br) pairs covering the same key set, with the
'pt-br' dispatch added to i18n::tr and the translation test extended.
2026-10-07 17:43:34 -03:00
Brandon ThomasandClaude Opus 5.5 f17397c305 Rename PrintCraft to PdfCraft (storytold/pdfcraft) (#95)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 14:55:09 -04:00
aiongg c64e538de5 UI: the font menu groups fonts by script, CJK fonts by language
Font menus list Western (and other-script) families first, then
Japanese, Simplified Chinese, Traditional Chinese and Korean families,
each group alphabetical by the name shown, with a separator between
groups. The group comes from the font's own data, strongest signal
first: the meta table's dlng (else slng) languages, family names in a
CJK language (Windows and Macintosh language IDs), OS/2 code pages (JIS,
Chinese Simplified, Korean Wansung, Chinese Traditional, Korean Johab);
a font declaring none of these goes by what it covers (kana, Hangul,
ideographs). Ties go Japanese, Simplified, Traditional, Korean. Loaded faces are classified
once; installed fonts by the font scan, which also reads their OS/2 and
meta tables (and cmap only for fonts declaring nothing), capped.

CJK families show their family name in their language, the English
name on hover; Preferences > Type > Show Font Names in English
(prefs.set {showFontNamesInEnglish}, off by default) shows English
names. Search matches either name; documents store the English name.
The Character panel, Control bar, Properties, style dialogs, Find Font
and Glyphs panel lists all follow this order. The main font menu stays
open while searching or starring (it closed on any click inside).

Font previews don't draw DesignCraft's missing-glyph box for fonts
whose .notdef is empty.
2026-10-07 10:44:46 -04:00
aiongg 1ef187ad02 Text: missing glyphs show as boxes
A character the applied font lacks is drawn as that font's missing-glyph
box (its .notdef, gid 0), on screen and in PDF, and Preflight lists the
characters by font ("Missing glyphs in <family> <style>: …", an error,
at most 20 named). A .notdef without an outline is drawn as a hollow box
across its advance, so a missing character never disappears. PDF draws
.notdef glyphs as paths, which PDF/A and PDF/UA accept. Kenten marks are
set in their text's font the same way.

The document setting Draw Missing Glyphs from Fallback Fonts
(DocSettings::glyph_fallback; Preferences > Composition,
document.preferences {glyphFallback}, undoable) draws them from fallback
fonts instead (the language-aware chains, then any font; kenten marks
from a fallback font, else a bullet). It is off in new documents and
IDML imports and on in files saved before it existed, which keep
drawing as they did. A missing font's substitute always uses fallback
fonts. The composition cache's signature includes the setting. Tests
whose Arabic comes from a fallback font turn the setting on.
2026-10-07 10:44:46 -04:00
aiongg 5f52150b31 CJK 1.9: document fonts belong to their document
The fonts in a document's Document Fonts folder are registered under a
font scope that the document holds while it is open (Document::font_scope,
runtime only; DocState keeps the scope alive and closes it when the last
copy of the state goes: file.close, closing a tab, revert, a book
chapter's export, the session ending). Composition, preflight, font.list,
Package and the font menus, Glyphs panel and previews look fonts up
through FontDb::scoped(scope): the document's own faces first, then the
shared ones. Other open documents don't see them, and two documents with
fonts of the same name each set text in their own. Composite fonts'
member fonts and the fallback for kenten marks are looked up the same
way.

Font files stay in memory for the session (FaceRef keeps faces for the
process); a document opened again reuses the faces of its unchanged files
(same path, length and modification time) instead of reading them again.
The composition cache's signature includes the scope; the word cache and
the outline and PDF font caches are keyed by face. Variable font
instances are kept per base face.

A family's installed faces join the shared fonts all at once, and a
face two lookups load at the same time is kept once, so a parallel
fallback lookup never takes a family's bold before its regular has
loaded.
2026-10-07 10:44:46 -04:00
aiongg 6df33fa344 CJK 1.7: story direction belongs to the story
Vertical is a story property: every frame of a thread is vertical or
horizontal together, a frame threaded onto a story takes its direction,
and frames split off by threading or breaking a thread keep theirs.
Type > Story Direction is type.storyDirection {vertical} (checked in the
menu) for the stories of the text selection or selected frames;
object.textFrameOptions {vertical} and frame.create {vertical} set the
frames' stories. Documents that stored Vertical on the frame open with
each story taking its first frame's direction. IDML StoryOrientation is
read into and written from the story, beside its column direction
(StoryDirection), which stays a separate setting.
2026-10-07 10:44:46 -04:00
aiongg e0fb78a230 CJK 1.4: Korean breaks at spaces
Korean is set word by word (KLREQ): Hangul, in any language, and Han
ideographs in Korean-language text take no line breaks between
characters, so lines break at spaces. Glyphs carry their language tag
for this. A paragraph attribute, koreanCharBreaks (type.para, paragraph
styles, Paragraph Style Options > Justification), breaks between
syllables instead. It is DesignCraft-only; IDML doesn't carry it.
A paragraph's kinsoku set decides which breaks it forbids, and Korean
still breaks at spaces under one.

Kinsoku still holds, also when the single-line composer has to split a
word wider than the measure: the split moves back so no line starts
with closing punctuation.
2026-10-07 09:33:52 -04:00
aiongg 2a516761ef CJK 1.1: the character language reaches the shaper
The character's language (as IDML names it) maps to a BCP 47 tag
(designcraft_doc::language_tag) and is the shaping context's language
on the harfrust buffer, so OpenType locl applies for every language in
the list (Japanese, Chinese, Korean, Turkish, ...), not only Arabic,
Persian, Urdu, Hebrew and English: other names used to reach the
shaper as they were written, which it doesn't know, so their locl never
applied. designcraft_fonts no longer maps names itself. The word-shaping
cache is keyed by the tag. Chinese: Simplified and Chinese: Traditional
join the language list (plain Chinese stays, tagged zh); Simplified
Chinese takes curly quotes, Traditional Chinese corner brackets.
2026-10-07 09:33:40 -04:00
Shao Wenbin 1c792b41e4 M9: remove stale localization terminology references
Remove links to the deleted localization-terminology.json from ROADMAP.md
and the Chinese/Arabic translation module comments. Preserve the scope
statement about verified Adobe help terminology and original labels.

Validation: cargo xtask ci passed fmt, clippy, tests, assets and layers.
WASM checks remain blocked by the missing wasm32-unknown-unknown standard
library in the local toolchain. Repository search finds no remaining
references to localization-terminology.json.
2026-10-07 19:47:38 +08:00
Shao Wenbin f52c591b87 M9: cache final RTL label layouts
Reuse wrapped and shaped RTL galleys across frames using a bounded,
context-local cache keyed by the complete LayoutJob. Invalidate cached
results when egui replaces its font-cache token, including font, DPI and
atlas changes. Preserve existing wrapping and elision behavior.

Add regression coverage for cross-frame reuse, layout parameter changes,
font/scale/atlas invalidation and cache eviction, plus an opt-in benchmark.

Validation: cargo xtask ci passed fmt, clippy, 590 tests, assets and layers.
WASM checks are blocked by the missing wasm32-unknown-unknown standard
library in the local Homebrew Rust toolchain (E0463).
Arabic menu screenshots remained identical after ten additional frames.
Manual benchmark: 200 wrapped labels took 31.46 ms uncached vs 0.082 ms
with final-layout cache hits on this machine.
2026-10-07 19:45:38 +08:00
Shao Wenbin ffcc2ef320 erf(i18n): cache translations and skip unnecessary bidi analysis
tr() uses a OnceLock<HashMap>, initialized once, changing lookups from a linear scan to average O(1).
Labels without RTL text, such as Chinese, Japanese, and Western-language labels, skip BidiInfo. Arabic, Hebrew, and directional controls retain their existing handling.
2026-10-07 19:45:38 +08:00
Shao Wenbin 0f09d48a7c Adjust all UI translation according to InDesign UI 2026-10-07 19:45:38 +08:00
Shao Wenbin 852ea64643 add missing Arabic UI translation 2026-10-07 19:45:38 +08:00
aiongg 0193ac9285 UI: the Scale and Shear tools get their own icons
Scale: a small square grown into a larger one from their shared corner,
with a diagonal arrow. Shear: a rectangle slanted into a parallelogram
along its base, with an arrow. Both are drawn in code in the icon set's
stroke weight; Free Transform keeps its drawing.
2026-10-07 02:00:34 -04:00
aiongg b6162dd11d Transform dialogs: Rotate and Shear open their dialogs (#34)
A parameter written as `key (description)` was dropped by the command
form parser, so Object › Transform › Rotate… and Shear… (and Basic
Feather) had no required field, opened no dialog and ran with defaults.
The key is now the leading word and the parenthetical becomes its hint.
Double-clicking the Selection, Rotate, Scale or Shear tool opens Move,
Rotate, Scale or Shear.
2026-10-06 18:13:29 -04:00
Brandon ThomasandClaude Opus 5.5 d582277cc7 i18n: fonts from craft-fonts, not the repo; rebase onto main
- Noto Sans CJK SC and Noto Sans Arabic now live in storytold/craft-fonts
  (byte-identical to upstream); the UI picks them up by script (Hans,
  Arab) from CRAFT_FONTS, Chinese forms first in the zh interface, and
  the fonts reinstall when the interface language changes.
- Rebased onto main: zh column for the vertical-type and smart-guide
  rows added since; duplicate rows removed; ROADMAP merged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:12:49 -04:00
Shao Wenbin 11900ad923 UI: add translation for remained UI 2026-10-06 15:12:49 -04:00
Shao Wenbin 9d85777546 UI: add Chinese and Arabic localization with RTL-safe interface text
Extend interface language selection with Chinese and Arabic translations
across menus, dialogs, panels, tooltips, and common application controls.
Keep English fallback for untranslated strings, return borrowed translation
text, and validate translation key uniqueness and language switching.

Bundle redistributable Noto CJK and Arabic fonts with OFL license files and
ASSETS.md attribution so native and WASM builds have portable glyph coverage.
Register Arabic regular and semibold families while retaining existing font
fallbacks for proportional and monospace controls.

Render Arabic labels using Unicode bidirectional runs and contextual shaping.
Wrap logical text at grapheme boundaries before ordering each visual line,
mirror neutral punctuation, preserve logical source text for accessibility,
and handle truncation, empty lines, and mixed Latin text and numbers. Keep
ASCII labels on the normal rendering path. Disable selection on shaped RTL
labels because egui's default label cursor mapping assumes LTR text.

Adapt welcome controls, menu ordering, popup alignment, and new-document rows
for RTL layout. Bound popup geometry and avoid unsupported RTL grid behavior;
keep numeric inputs LTR. Isolate user-provided document names from Latin
application and zoom metadata. Interface language changes leave document
binding, paragraph direction, editable text, and engine state unchanged.

Add regressions for contextual Arabic joining, bidirectional punctuation,
mixed document names, logical wrapping, truncation, language switching, and
finite widget geometry. Update the roadmap with localization coverage.
Apply equivalent chunk-iteration and PDF Option/borrow simplifications needed
by the current Rust toolchain's strict Clippy checks.

Validation:
- cargo xtask ci: fmt, Clippy, native tests, assets, and layers passed;
  native tests total 517 passed and 2 ignored.
- UI regression suite: 26 passed.
- Headless UI screenshots verified Arabic welcome/new-document creation,
  menus, mixed-script document names, and switching back to Chinese/English.
- Default WASM gate is blocked by this host's missing precompiled wasm32
  standard library. All 15 WASM crates pass using the installed Rust sources:
  RUSTC_BOOTSTRAP=1 CARGO_UNSTABLE_BUILD_STD=std,panic_abort
  target/debug/xtask wasm.
2026-10-06 15:12:49 -04:00
epfabianandClaude Opus 5.5 9bbaa2940a Canvas: middle-mouse drag pans the view
Dragging with the middle mouse button pans the canvas with any tool, like
Space-drag, and shows the grabbing hand. Tools still only see the primary
button. ui.click / ui.drag accept "button": "middle".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 20:34:28 +02:00
Brandon ThomasandClaude Opus 5.5 a6519d8a55 Fonts: use craft-fonts as an optional build input; move the Japanese fonts out
Shippori Mincho (8.7 MB) and its licence leave assets/fonts. Japanese fonts now
come from storytold/craft-fonts when built with CRAFT_FONTS_DIR (never a
Cargo.toml dependency): crates/fonts/build.rs embeds its manifest as
designcraft_fonts::CRAFT_FONTS. Native builds embed all four fonts; wasm32
embeds BIZ UDPGothic Regular only (web size budget).

- UI (egui): the Jpan faces at the end of every family, BIZ UDPGothic first
  (Bold first in the semibold family).
- Documents: FontDb loads them after the bundled fonts, Mincho first, so they
  are the Japanese fallback ahead of system fonts; SVG text gets them too.
- Vertical alternates test runs on every craft-fonts face and skips when
  CRAFT_FONTS is empty; new UI no-tofu test and without-craft-fonts tests.
- FreeBSD CI tests with craft-fonts; release.yml builds every platform with
  CRAFT_FONTS_DIR + CRAFT_FONTS_REQUIRED=1 at a pinned commit, packages carry
  OFL-<family>.txt; NOTICE, ASSETS.md, AGENTS.md/CLAUDE.md, README, ROADMAP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 11:01:35 -04:00
Brandon ThomasandClaude Opus 5.5 99b6228abd Snap: snap preferences as a command, overlay colours from tokens, tidy-up
- view.snapPreferences {alignEdges, alignCenters, smartDimensions,
  smartSpacing, zone} sets the smart guide options; the Preferences
  dialog goes through it, so the control channel and MCP reach them.
- Smart guide, gap and measurement colours come from theme::Tokens.
- Remove the unused closest-target helper (snap_rect and friends).
- Drop the agent planning docs (docs/superpowers) and the .worktrees
  ignore line; ROADMAP entry for smart guides and snapping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 09:05:59 -04:00
Cameron Gilroy b0f9773205 Snap: view commands and guide preferences 2026-10-06 09:05:59 -04:00
Cameron Gilroy 4de93d1345 Snap: carry SnapView on the tool context 2026-10-06 09:05:59 -04:00
japbcoelhoandClaude Opus 5.5 48e409e214 Fonts: installed fonts are found by name whatever ran before
FontDb cataloged the system fonts only when a character needed a fallback
(nothing else calls load_system_fonts), so a document set in an installed
family was composed in Source Sans 3, and font.list and preflight reported
the family missing (#22).

Every lookup by family name now waits for one scan of the font folders per
session, as VectorCraft does since #130: the app starts the scan in the
background at startup, other processes run it on first use. The scan reads
only each file's table directory and name table, and skips folders it has
already read, so a symlink loop can't hang it. has_family counts installed
families. FontDb::with_font_dirs and system_font_dirs let tests use their
own font folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 09:05:40 -04:00
Brandon ThomasandClaude Opus 5.5 7d721c92eb Fonts: embed Shippori Mincho once, shared by documents and the UI
The UI theme included the 8.7 MB font a second time; it now uses
designcraft_fonts::JAPANESE_FALLBACK (release binary 72 MB -> 63 MB).
The ROADMAP note joins the Interface language entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 17:32:47 -04:00
midasdf 3ef82f850c i18n: bundle Japanese font fallback and translate vertical controls 2026-10-05 17:32:47 -04:00
Brandon ThomasandClaude Opus 5.5 2c46e97a48 Never crash: UI
The canvas, Properties panel and QR dialog skip a frame instead of
expect()ing a document; the control channel caps ui.drag steps. ui-egui
denies the panicking lints.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 12:43:34 -04:00
Brandon ThomasandClaude Opus 5.5 a2bbd96f30 UI: tool shortcuts work right after clicking the canvas (#1)
Only a focused text field blocks global shortcuts; the canvas (or a
button) holding egui focus after a click no longer swallows V/F/… until
Esc.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 11:38:17 -04:00
storybored379andClaude Opus 5.5 01753f90f3 File: file.serialize returns the file's bytes (base64) — web Save wrote corrupt documents
file.serialize returned {json: String::from_utf8_lossy(to_bytes(doc))},
but since M6.1 the native format is a zip (deflated document.json + raw
assets), not JSON text. from_utf8_lossy turns every invalid UTF-8
sequence into U+FFFD, so the result is not the file: on the web, File ›
Save downloads exactly those bytes (download_document), and the
downloaded .designcraft can't be opened again ("invalid Zip archive").
Agents calling file.serialize got the same unusable string.

Return {base64, bytes} like the other byte-producing commands
(file.exportIdml, file.exportPdf, snippet.export) and decode it in
download_document.

Test: serialized_document_opens_again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-04 09:51:34 -04:00
Brandon ThomasandClaude Opus 5.5 5294c8f677 T: ruby and kenten
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 02:47:55 -04:00
Brandon ThomasandClaude Opus 5.5 558e798dfc E: CMYK transparency blend space on screen
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 02:09:26 -04:00
Brandon ThomasandClaude Opus 5.5 e856b849bb M: video and sound in interactive PDF (screen annotations, renditions)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 01:44:50 -04:00
Brandon ThomasandClaude Opus 5.5 5b7969901c T: right-to-left carets and selections; Binding: Right to Left
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 01:34:47 -04:00
Brandon ThomasandClaude Opus 5.5 6334734b3a T: Insert Kashidas in the paragraph style Justification tab
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 01:18:41 -04:00
Brandon ThomasandClaude Opus 5.5 ee55acd858 T: Digits (World-Ready) — figures in Arabic-Indic, Persian and native scripts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 01:06:38 -04:00
Brandon ThomasandClaude Opus 5.5 f888e6b061 X: DTDs — load, validate the structure, Tags panel
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 00:57:18 -04:00
Brandon ThomasandClaude Opus 5.5 fe40d4b80b T: tate-chu-yoko in vertical frames
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 00:46:52 -04:00
Brandon ThomasandClaude Opus 5.5 b13135472a V: Rotate Spread per spread — canvas layout through per-spread transforms
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 00:25:16 -04:00
Brandon ThomasandClaude Opus 5.5 1c8952f6db W: New Window in its own OS window
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 00:08:02 -04:00
Brandon ThomasandClaude Opus 5.5 79f266c04c T: text language — hyphenation, spelling and quotes follow it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 00:01:50 -04:00
Brandon ThomasandClaude Opus 5.5 7b636fb9f5 C: separations from source colours
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 23:54:54 -04:00
Brandon ThomasandClaude Opus 5.5 0d02222dab W: Scripts panel and script.run (one undo step)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 10:48:58 -04:00
Brandon ThomasandClaude Opus 5.5 8eca6305f8 I: Object Export Options — artifact, rasterize, alignment, page break
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 10:48:58 -04:00