The web app ran CadApp with Services::default(), so OPEN found no file
picker and returned without doing anything: no picker, no message.
The web app now installs an open picker (apps/cadcraft-web/src/upload.rs,
web-sys only): a hidden <input type="file" accept=".dxf,.dwg"> is
clicked, the chosen file is read in the background (Blob.arrayBuffer)
and handed to the app on its next frame, which runs OPEN with
{data, name} through the new CadApp::open_bytes. Cancelling the picker
does nothing. Files dropped on the page, which eframe hands over unread
on the web and the UI ignored there, take the same route.
Files over 256 MB (CadApp::MAX_OPEN_BYTES; the browser holds the drawing
several times while decoding it) are refused before they are read.
Unreadable or rejected files report on the command line and in the
status bar; nothing panics.
Co-authored-by: Claude Opus 5.5 <[email protected]>
The canvas hides the OS cursor (CursorIcon::None, which winit turns into
ShowCursor(FALSE) on Windows) and draws its own crosshair, so Windows
Magnifier's "follow the mouse pointer", screen readers, recorders and
remote desktops lose the pointer there. View > Accessibility > Show System
Cursor (ui.toggle.systemcursor, ui.set {"systemCursor": true}, or
CADCRAFT_SYSTEM_CURSOR=1 at startup) keeps a system crosshair visible at
the centre of the drawn one.
Co-authored-by: Claude Opus 5.5 <[email protected]>
AppKit draws the traffic lights centred in its standard 28 pt title-bar
band, and the integrated title row is that band, but the title text sat
1 pt below the centre line. It is now centred on the lights. Neither
winit nor eframe can move the lights without AppKit calls (unsafe), so
the row fits them instead, as in WordCraft (storytold/wordcraft#255).
The geometry lives in chrome.rs. A long drawing name in a narrow window
no longer slides under the lights: the title starts after them, with the
same gap the lights keep from the top of the window.
Co-authored-by: Claude Opus 5.5 <[email protected]>
UNDO now prompts "Enter the number of operations to undo or
[Auto/Control/BEgin/End/Mark/Back] <1>" and undoes that many; Enter undoes
one. Its other options say they are not available yet (Auto and Control
still take their value), so nothing that follows is run as a command.
The JSON form (`undo {count?}`) is unchanged.
U is its own command, as in AutoCAD: it undoes one operation without
asking and is what Edit > Undo, Cmd+Z and the toolbar button run.
An interactive command outside undo that changed the drawing (UNDO)
records no undo step when it finishes, matching `execute`.
Co-authored-by: Claude Opus 5.5 <[email protected]>
TEXTEDIT's prompt no longer reads "or or". Undo reverts the last edit made
in this TEXTEDIT, and Mode switches between Multiple (keep selecting) and
Single (end after one edit). At the command line and in scripts, MTEXT
takes one paragraph per input line until an empty line, instead of ending
after the first line and running the next one as a command. The Text
Editor window sends its contents and then Enter, so it still ends MTEXT.
Co-authored-by: Claude Opus 5.5 <[email protected]>
AREA's Object option measures picked objects; Add area / Subtract area keep
a running "Total area" over areas measured by points or by object, and
Enter at the first-corner prompt ends the command. Length continues the
last segment by a typed length in AREA and DIST point sequences. DIST's
Multiple points measures a path and reports the running and total
distance. Arc now says it is not available yet instead of being ignored
(or ending AREA as Total).
Co-authored-by: Claude Opus 5.5 <[email protected]>
"Specify the reference angle <0>" takes a typed angle or two points;
"Specify the new angle or [Points] <0>" takes a typed angle, a point
measured from the base point, or two points after `P`. The objects turn by
the new angle minus the reference angle. Previously Reference only said
"not available yet" and the values that followed were misread or run as
commands.
Co-authored-by: Claude Opus 5.5 <[email protected]>
ELLIPSE: after Rotation the next value is the rotation around the major
axis (ratio = cos angle, 0 to 89.4 degrees; a picked point gives the
angle from the centre), instead of the other-axis distance. At the
elliptical arc's start/end prompts, Parameter reads the values as
ellipse parameters and Angle switches back to true angles.
BREAK: First point asks for a new first break point; the selection pick
then only selects the object.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Raster images: the reader now follows an IMAGE's group 340 to its IMAGEDEF
and keeps the file path and the definition's name (its ACAD_IMAGE_DICT
key), pixel size and resolution unit. It also keeps the clip boundary (in
pixel coordinates), the clipping state, the display flags and
brightness/contrast/fade. The writer emits the IMAGE entity, plus one
IMAGEDEF per path and name, an IMAGEDEF_REACTOR per image,
RASTERVARIABLES, the ACAD_IMAGE_DICT and ACAD_IMAGE_VARS entries in the
named object dictionary, and the four CLASS records, as the DXF Reference
describes. An image without a clip boundary gets the full-image rectangle.
DWG save keeps the same data, except the resolution unit, which the DWG
bridge drops. The pixels are still not loaded.
Entity types CADCraft doesn't model (MLINE, MULTILEADER, 3DSOLID, REGION,
MESH, ...) are still not written. Writing their raw groups back into the
R2000 file would leave references to objects that aren't kept
(MLINESTYLE, MLEADERSTYLE, ACIS data in later versions), and some of the
types don't exist in R2000 at all. Another CAD program could then reject
the whole file. Instead, qsave, saveas and document.bytes now say on the
command line which ones weren't saved ("Not saved (CADCraft can't write
these object types yet): 1 3DSOLID, 2 MLINE") and list them by type in the
result's `notSaved`. `cadcraft-cli run --save` and `convert` print the
same line.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Saving to DXF and reopening lost several table and object-section items.
They are now written and read as the DXF Reference describes:
- LTYPE: embedded text and shape elements (74 type flags, 75 shape number,
340 STYLE, 46 scale, 50 rotation, 44/45 offset, 9 text). Shapes from a
shape file get an unnamed shape STYLE record (70 bit 1). DashElement
gains an `absolute` flag for absolute rotations (74 bit 1). The built-in
FENCELINE1 names its text style (Standard).
- MLEADERSTYLE objects in ACAD_MLEADERSTYLE with arrow size, text height,
landing gap, dogleg length and text style, plus $CMLEADERSTYLE, so the
current multileader style survives reopening.
- LAYOUT plot settings: device (2), plot style table (7), plot area (74),
custom scale (142/143, 147), scale to fit (70 bit 16 with 75 = 0),
centred plot and lineweights (70 bits 4 and 128). The layout's saved
paper-space view goes in CADCraft xdata on the LAYOUT object.
- VIEW and UCS table records, and GROUP objects in ACAD_GROUP (members
that were written to the file). A named view's layer state is CADCraft
xdata on the VIEW record.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Saving to DXF and reopening lost several entity, block and style
properties:
- Thickness (group 39) is written for LINE, POINT, CIRCLE, ARC, TEXT,
SOLID, TRACE, LWPOLYLINE and POLYLINE when non-zero.
- POINT writes its X-axis angle (group 50).
- HATCH: the origin goes into the pattern lines' base points (43/44), so
other programs see the shift, and travels with the background colour as
CADCRAFT xdata (1000 HATCH, 1011 origin, 1000 colour name); the DXF
Reference has no groups for either. It is appended to the gradient
xdata when there is one. The reader takes the elevation from the z of
the first group 10.
- Xref blocks get BLOCK 70 bit 4 and their path in group 1, and the
reader reads the path.
- The built-in "CADCraft Stroke" font is still written as "txt" for other
readers; its name travels as CADCRAFT xdata (1000 FONT) and is used
while group 3 is still "txt".
- Polyface (70 bit 64) and polygon mesh (bit 16) POLYLINEs from other
programs are read as 3D faces instead of a 3D polyline through their
vertices; face records no longer become vertices at the origin. Bad
indices and counts are skipped.
Co-authored-by: Claude Opus 5.5 <[email protected]>
The ATTDEF writer put only the invisible bit into group 70, so constant
attribute definitions came back as variable ones: INSERT then created an
attribute for them, and other programs stopped drawing their text. The
constant bit (2) is now written too.
BLOCK's description was never written (BLOCK group 4) nor read, and the
insertion units (BLOCK_RECORD 70) and explodability (280) of blocks were
neither read nor written. All three now round-trip.
Co-authored-by: Claude Opus 5.5 <[email protected]>
LAYERSTATE.SAVE stored its states in Drawing::layer_states, but the DXF
writer never wrote them and the reader never read any, so every saved
layer state was gone after saving and reopening (DWG too, as it is
written from the same DXF).
They are now written like the parametric constraints: as JSON in a
CADCRAFT_LAYERSTATES XRECORD of the named object dictionary, read back
with the same payload and size limits. The XRECORD chunking and reading
are shared by both records.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Progress docs per craftrules standards/progress-docs.md: target-app parity, gaps, roadmap with alpha gate, readiness by audience (full / mainstream / essentials) with Opus 5.5 hours, and feature, format, geometry, hardware, UI and localization parity docs.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Rebase onto main: the interface language is saved with main's other
preferences (cadcraft.prefs, beside the theme) instead of its own storage
key, on desktop and web; strings main added or changed in the touched
places (Dynamic Input settings, Properties header and current-property
rows, block picker, theme and command-history menu items, open/save
filters) are wrapped and translated; main's native-menu poll order is kept.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Closing the window (title bar, File > Exit, Cmd+Q) with unsaved drawings now
cancels the close and asks Save / Don't Save / Cancel for each one, through
the same in-app prompt as File > Close All (#172). The app quits once every
drawing has been saved or discarded; Cancel keeps it open. The control
channel's app.quit never asks.
Rebuilt on top of #172 from LloydNicholson's original PR.
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Dynamic Input: pointer input boxes, Tab separator, relative entry
While a command asks for a point and Dynamic Input is on, the cursor
tooltip shows a pair of value boxes, following AutoCAD's pointer input:
- The first point of a command is X and Y, absolute.
- Second and next points default to polar (distance and angle) measured
from the last point, so no `@` is needed.
- Typing `,` after a value locks it as X and moves to Y; `<` locks it as
the distance and moves to the angle. A locked value holds the cursor and
shows a lock.
- Tab types the separator for the format on show, so `40` Tab `90` is 40
units at 90 degrees, and with the Cartesian setting `40` Tab `40` is 40
over and 40 up.
- Enter or Space sends the entry with `@` in front, filling an empty box
from the cursor. A plain number and Enter is still direct distance entry;
`@`/`#` entries, keywords and command names go through untouched.
The command-line text is the single source of truth: the boxes are a view
of it, so the command line always shows exactly what will be sent
(`40,`, `40<90`) and Backspace simply edits it.
Tab is taken from egui in the raw input hook (desktop and web) while no
widget has focus. Otherwise egui moves keyboard focus to the next button on
Tab and the command line stops receiving keystrokes.
Two new settings mirror AutoCAD's: DYNPIFORMAT (1 = second points start
Cartesian) and DYNPICOORDS (1 = absolute), through SETVAR and in Drafting
Settings under Dynamic Input. The tooltip uses the theme tokens, matching
the command line.
Scripts, the control channel and MCP never pass through the boxes and keep
the plain command-line rules. The parsing lives in a small pure module
(dyninput.rs) with unit tests.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019uMCkRAB8DMd8MEmoY9Vyr
* Dynamic Input tooltip: border colour from theme tokens
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
Typing UNITS ran the JSON form with no parameters, which changed nothing
and printed nothing. Typed or menu-invoked UNITS (no parameters) now opens
a Drawing Units dialog like QSELECT does: length type and precision, angle
type and precision, insertion units and a sample output. OK applies the
values through the `units` command; JSON calls run the command as before.
SETVAR had no prompts either, so `SETVAR LUNITS 2` ran with no name and
the remaining inputs were dropped. Space acting as Enter was not the
cause. SETVAR now asks "Enter variable name or [?]" and then "Enter new
value for NAME <current>"; `?` lists the variables, unknown names end the
command, and a value of the wrong type re-prompts.
sysvars::set now refuses variables that `get` derives from state
(DWGNAME, DBMOD, EXTMIN, ...) and keeps integer header variables integer,
so a typo can no longer store text in LUNITS.
Co-authored-by: Claude Opus 5.5 <[email protected]>
* DIMANGULAR: accept a circle
The first prompt offers "arc, circle, line" but picking a circle was
rejected. Picking a circle now uses its center as the angle vertex and
the picked point as the first endpoint, then asks for the second
endpoint.
* cargo fmt
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
`SETVAR DIMSCALE 24` was stored in the header but never reached new
dimensions: they were created with no overrides, and the header DIMSCALE
was only a fallback for styles whose scale is zero.
As in AutoCAD, the header DIM* variables that differ from the current
dimension style are now its overrides, and new dimensions take them on
(`Drawing::dim_overrides`). Existing dimensions keep their size. Making a
style current, or editing the current style, sets the variables back to
the style's values (`Drawing::sync_dim_vars`), so
`dimstyle {"name": "Standard", "DIMSCALE": 24}` still works.
GETVAR/SETVAR read DIM* variables the header doesn't carry from the
current style.
Dimension extents now use the same scale as the geometry (the style with
the dimension's overrides) instead of multiplying by the header DIMSCALE.
A DIMSCALE of zero (AutoCAD: scale to the layout viewport) falls back to
the drawing's DIMSCALE and then 1 instead of 1e-9.
Reading DXF, $DIMDSEP becomes the separator character, as the DIMSTYLE
table already is, so AutoCAD's header variables don't turn into spurious
overrides.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Selection windows only worked click-then-click: the canvas reacts to clicks,
and a press that moves before release is a drag, not a click, so a drag was
ignored entirely.
Now, while objects are being selected (no command running, or a command
asking for objects), a drag opens the window where the button went down and
letting go closes it, as with AutoCAD's default PICKDRAG = 2. Dragging right
is a window, dragging left a crossing window, Shift still removes, and
click-click works as before. Drags that start on a grip or while a command
asks for a point are left alone.
Session::begin_window opens the window at the drag's start, even over an
object (a click there would pick the object instead), with an engine test.
Claude-Session: https://claude.ai/code/session_019uMCkRAB8DMd8MEmoY9Vyr
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Write Wipeout entities to DXF so saving keeps them (#79)
* Wipeout: clip vertices are in image pixel space (origin top-left, y down)
Write and read the boundary with y flipped, so other programs show the same
shape and wipeouts from other programs are no longer mirrored vertically.
Tested with an asymmetric boundary.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Wipeout: collapse nested if (clippy)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
* DXF/DWG: keep hatch gradients through save and reopen (fixes#80)
The HATCH writer never emitted a gradient and the reader always set
`gradient: None`, so a GRADIENT fill reopened as a plain SOLID hatch after
any DXF or DWG save.
- Writer: native HATCH groups per the DXF Reference (450 gradient flag,
451, 452 two-colour, 453 colour count, 460 angle in radians, 461 shift
(0 = centered), 462 tint, 463 per-colour records with 63 ACI and 421 true
colour, 470 name), plus a `CADCRAFT` `GRADIENT` xdata copy (name cut to
255 bytes, angle, centered, colour names).
- Reader: native groups win when present (another program may have edited
them); otherwise the xdata copy is used. The xdata is what survives DWG
saves: the file is R2000 (AC1015), whose DWG HATCH has no gradient fields,
so the DWG bridge drops the native groups.
- Hostile values (NaN angles, out-of-range colours, extra colour records,
missing groups) fall back to the GRADIENT command's defaults.
Tests: gradient_hatch_roundtrips_through_dxf,
gradient_hatch_roundtrips_through_dwg,
gradient_falls_back_to_xdata_and_native_groups_win,
long_gradient_name_is_cut_only_in_xdata, hostile_gradient_groups_never_panic.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* contributors: add vangel76
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Gradient test: expect \U+ escapes now that non-ASCII text is escaped (#169)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
The squash for #159 picked up an earlier revision of the #140 test, which
called as_bytes() on a Vec<u8>. Also apply rustfmt to code from #120 and #155.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* DIMANGULAR: accept polyline segments (fixes#10)
Picking a side of a rectangle or a PLINE segment was rejected with
"Select a line or an arc." because only LINE and ARC entities were
accepted. The picked object is now resolved to the segment under the
cursor: straight polyline segments work like lines and arc segments
like arcs.
* Redraw edits made while a command is still running (fixes#4)
LINE and PLINE add geometry on every point, but the canvas only rebuilt
its display list when the drawing revision or the document pointer
changed. The revision was bumped when a command finished, and the
pointer changed only on the first copy-on-write edit, so only the first
segment appeared until the command ended. Session::feed now bumps the
revision after each input once the running command has changed the
drawing.
* Fix#14: include DWG in the Open drawing filter
* Blocks window: click a block to insert it (#8)
Each block name in the Blocks window is now a button. Clicking it starts INSERT with that block already chosen, so the command line asks for the insertion point.
* SCALE: Reference option (#17)
SCALE > Reference printed "not available yet". It now asks for the reference length (typed, or two points) and the new length (typed, or a point measured from the base point), and scales by new / reference. Zero, negative or non-finite lengths are rejected and asked again.
* Print and Ctrl+P ask where to save the PDF (#5)
PLOT/EXPORTPDF started from the menu, the toolbar, Ctrl+P or the command line had no path,
so the PDF was built in memory and dropped. They now open the save dialog (PDF filter first)
and write the file there. JSON calls from scripts, the control channel and MCP still never
open a dialog. Ctrl+P was shown in the menu but not bound; it is now.
* Scripts: split a line at keyword prompts so POLYGON 6 200,20 I 15 works (#43)
* Layer Properties Manager: stop the window growing every frame (fixes#29)
The vertical separator between the filter tree and the table takes all the
height it is offered, and a resizable window offers its previous height, so
the window grew 30px per frame until it filled the screen. Cap the row at the
table's fixed height. Regression test runs the dialog headless for 30 frames
and checks the height stays put.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* ui.render: fit the drawing and return pngBase64 like the headless render (#49, #50)
* Linux: default to XWayland for file drag-and-drop on Wayland desktops
* Fonts: per-character fallback, FONTALT and .ttc for CJK text in SHX styles (#130)
CJK text in a style that uses an SHX font (romans.shx + chineset.shx big font)
drew every ideograph as an empty box: the SHX name resolves to our stroke font,
which has no CJK glyphs, and the font scan skipped .ttc collections, where most
CJK system fonts live.
- Per-character fallback: a character the text's font lacks (stroke font or
TrueType) is drawn from an installed font that has it, checked by cmap.
Wide-coverage fonts go first (Noto Sans CJK, Source Han, WenQuanYi, Droid
Sans Fallback, PingFang, Microsoft JhengHei/YaHei, MS Gothic, ...), regular
weights before others. Fallback glyphs are sized like TrueType text (cap
height = text height). Lookups are cached; the search is bounded (24 files,
160 MiB, 256 faces per character, files over 96 MiB never read) and skips
spaces, controls and private-use code points. No fallback: the box as before.
- FONTALT (sysvar, seeded from CADCRAFT_FONTALT): font used for a style font
that can't be found (an SHX file, a missing TTF). Empty = our stroke font.
- FONTFALLBACK (sysvar, seeded from CADCRAFT_FONTFALLBACK): fonts tried first
for missing characters, e.g. "Noto Sans CJK TC".
- .ttc/.otc are scanned; TextFont::Outline carries a ttf::Face (bytes + face
index). Fonts are also found by family name among files with a similar
stem, so "Noto Sans CJK TC" picks face 3 of NotoSansCJK-Regular.ttc.
- Cap height falls back to the height of "H" when OS/2 has none (DejaVu
Sans), which fixes ttf_tests::system_font_outlines_when_available and
render's truetype_text_is_filled_or_outlined on machines without Arial.
- README: a Fonts section for the two settings; ROADMAP M4 note.
Native SHX / big-font rendering stays on the roadmap (M4).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Fonts: cap the total bytes of system font files loaded from disk
A drawing naming many text styles could otherwise load every installed font
into memory through family-name lookups.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Pan with a two-finger trackpad swipe; keep wheel and pinch zoom
Trackpad two-finger swipes arrive as scroll events, and the canvas turned
every scroll into a zoom, so trackpad users had no realtime pan (middle-drag
needs a middle button).
Scroll now follows the device: precise point deltas (trackpad, Magic Mouse)
pan the view by x and y; notched line deltas (mouse wheel) zoom about the
cursor as before. Pinch and Cmd+scroll still zoom through zoom_delta, and
middle-drag still pans.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019uMCkRAB8DMd8MEmoY9Vyr
* Add Tru10 to contributors/people.toml
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019uMCkRAB8DMd8MEmoY9Vyr
* Trackpad pan: only on macOS, where point deltas mean a trackpad
Browsers and Wayland smooth-scroll mice report ordinary wheels in points too,
so the wheel keeps zooming there.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Keep arc-length dimensions as arc-length through DXF save and reopen (#100)
* PLINE: Halfwidth is centre-to-edge, and Width answers taper the next segment (fixes#83, #104)
Interactive PLINE kept one width value: Halfwidth answers were stored as
the total width, and the ending-width answer overwrote the starting one,
so a taper became a constant width. The next segment's starting and
ending widths are now tracked separately, Halfwidth answers are doubled,
and each new segment (including the closing one) gets its widths on its
first vertex; later segments are uniform at the ending width, as in
AutoCAD. Uniform polylines are still stored as const_width, so their DXF
output is unchanged.
Fixes#83. Fixes#104.
* Arc-length dimensions: write a standard aligned record plus CADCraft xdata
DXF has no arc-length DIMENSION type, so write type 1 and mark the kind and
arc centre in CADCRAFT xdata (like ASSOC). Other programs read an aligned
dimension; CADCraft restores the arc length, through DXF and DWG.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Desktop: write log records to standard error and a rotating log file
The desktop app installed no logger, so every log::warn!/log::error!/
log::info! in the workspace was discarded: a broken app icon, the GPU
canvas set-up, the engine's command-line echo at debug level. A launch
from a desktop menu has no terminal either, so there was nothing to
attach to a bug report.
apps/cadcraft/src/logging.rs (no new dependency):
- standard error plus <settings dir>/logs/cadcraft.log; each launch
rotates the previous log to cadcraft.1.log and .2.log, so the log of a
run that crashed survives the next start; the file is capped at 16 MiB
- records logged before the settings directory is known are buffered
(bounded) and written once the file is attached
- default levels: info for cadcraft*, warn for everything else;
RUST_LOG replaces them with env_logger-style directives
- never panics: an unusable directory or a failed write leaves standard
error as the only sink; a poisoned lock is tolerated
CADCraft had no per-user directory yet. config_dir in main.rs adds one:
CADCRAFT_CONFIG_DIR, else $XDG_CONFIG_HOME/cadcraft or ~/.config/cadcraft
(Linux, BSDs), ~/Library/Application Support/CADCraft (macOS),
%APPDATA%\CADCraft (Windows).
The logger is installed first in main and the file is opened after
argument parsing (--version leaves no file). The control server's
eprintln!s now go through the logger. A --control or
CADCRAFT_CONTROL_PORT value that is not a port is now logged instead of
silently leaving the control channel off. Documented in README.md
(Quick start > Logs).
---------
Co-authored-by: DWAA1660 <[email protected]>
Co-authored-by: MarekSpodBiedry <[email protected]>
Co-authored-by: lloyd <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Dylan M. Taylor <[email protected]>
Co-authored-by: vangel76 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Tru10 <[email protected]>
Co-authored-by: Gert Pellin <[email protected]>
* DIMANGULAR: accept polyline segments (fixes#10)
Picking a side of a rectangle or a PLINE segment was rejected with
"Select a line or an arc." because only LINE and ARC entities were
accepted. The picked object is now resolved to the segment under the
cursor: straight polyline segments work like lines and arc segments
like arcs.
* Redraw edits made while a command is still running (fixes#4)
LINE and PLINE add geometry on every point, but the canvas only rebuilt
its display list when the drawing revision or the document pointer
changed. The revision was bumped when a command finished, and the
pointer changed only on the first copy-on-write edit, so only the first
segment appeared until the command ended. Session::feed now bumps the
revision after each input once the running command has changed the
drawing.
* Fix#14: include DWG in the Open drawing filter
* Blocks window: click a block to insert it (#8)
Each block name in the Blocks window is now a button. Clicking it starts INSERT with that block already chosen, so the command line asks for the insertion point.
* SCALE: Reference option (#17)
SCALE > Reference printed "not available yet". It now asks for the reference length (typed, or two points) and the new length (typed, or a point measured from the base point), and scales by new / reference. Zero, negative or non-finite lengths are rejected and asked again.
* Print and Ctrl+P ask where to save the PDF (#5)
PLOT/EXPORTPDF started from the menu, the toolbar, Ctrl+P or the command line had no path,
so the PDF was built in memory and dropped. They now open the save dialog (PDF filter first)
and write the file there. JSON calls from scripts, the control channel and MCP still never
open a dialog. Ctrl+P was shown in the menu but not bound; it is now.
* Scripts: split a line at keyword prompts so POLYGON 6 200,20 I 15 works (#43)
* Layer Properties Manager: stop the window growing every frame (fixes#29)
The vertical separator between the filter tree and the table takes all the
height it is offered, and a resizable window offers its previous height, so
the window grew 30px per frame until it filled the screen. Cap the row at the
table's fixed height. Regression test runs the dialog headless for 30 frames
and checks the height stays put.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* ui.render: fit the drawing and return pngBase64 like the headless render (#49, #50)
* Linux: default to XWayland for file drag-and-drop on Wayland desktops
* Fonts: per-character fallback, FONTALT and .ttc for CJK text in SHX styles (#130)
CJK text in a style that uses an SHX font (romans.shx + chineset.shx big font)
drew every ideograph as an empty box: the SHX name resolves to our stroke font,
which has no CJK glyphs, and the font scan skipped .ttc collections, where most
CJK system fonts live.
- Per-character fallback: a character the text's font lacks (stroke font or
TrueType) is drawn from an installed font that has it, checked by cmap.
Wide-coverage fonts go first (Noto Sans CJK, Source Han, WenQuanYi, Droid
Sans Fallback, PingFang, Microsoft JhengHei/YaHei, MS Gothic, ...), regular
weights before others. Fallback glyphs are sized like TrueType text (cap
height = text height). Lookups are cached; the search is bounded (24 files,
160 MiB, 256 faces per character, files over 96 MiB never read) and skips
spaces, controls and private-use code points. No fallback: the box as before.
- FONTALT (sysvar, seeded from CADCRAFT_FONTALT): font used for a style font
that can't be found (an SHX file, a missing TTF). Empty = our stroke font.
- FONTFALLBACK (sysvar, seeded from CADCRAFT_FONTFALLBACK): fonts tried first
for missing characters, e.g. "Noto Sans CJK TC".
- .ttc/.otc are scanned; TextFont::Outline carries a ttf::Face (bytes + face
index). Fonts are also found by family name among files with a similar
stem, so "Noto Sans CJK TC" picks face 3 of NotoSansCJK-Regular.ttc.
- Cap height falls back to the height of "H" when OS/2 has none (DejaVu
Sans), which fixes ttf_tests::system_font_outlines_when_available and
render's truetype_text_is_filled_or_outlined on machines without Arial.
- README: a Fonts section for the two settings; ROADMAP M4 note.
Native SHX / big-font rendering stays on the roadmap (M4).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Fonts: cap the total bytes of system font files loaded from disk
A drawing naming many text styles could otherwise load every installed font
into memory through family-name lookups.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Pan with a two-finger trackpad swipe; keep wheel and pinch zoom
Trackpad two-finger swipes arrive as scroll events, and the canvas turned
every scroll into a zoom, so trackpad users had no realtime pan (middle-drag
needs a middle button).
Scroll now follows the device: precise point deltas (trackpad, Magic Mouse)
pan the view by x and y; notched line deltas (mouse wheel) zoom about the
cursor as before. Pinch and Cmd+scroll still zoom through zoom_delta, and
middle-drag still pans.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019uMCkRAB8DMd8MEmoY9Vyr
* Add Tru10 to contributors/people.toml
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019uMCkRAB8DMd8MEmoY9Vyr
* Trackpad pan: only on macOS, where point deltas mean a trackpad
Browsers and Wayland smooth-scroll mice report ordinary wheels in points too,
so the wheel keeps zooming there.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Keep arc-length dimensions as arc-length through DXF save and reopen (#100)
* PLINE: Halfwidth is centre-to-edge, and Width answers taper the next segment (fixes#83, #104)
Interactive PLINE kept one width value: Halfwidth answers were stored as
the total width, and the ending-width answer overwrote the starting one,
so a taper became a constant width. The next segment's starting and
ending widths are now tracked separately, Halfwidth answers are doubled,
and each new segment (including the closing one) gets its widths on its
first vertex; later segments are uniform at the ending width, as in
AutoCAD. Uniform polylines are still stored as const_width, so their DXF
output is unchanged.
Fixes#83. Fixes#104.
* Arc-length dimensions: write a standard aligned record plus CADCraft xdata
DXF has no arc-length DIMENSION type, so write type 1 and mark the kind and
arc centre in CADCRAFT xdata (like ASSOC). Other programs read an aligned
dimension; CADCraft restores the arc length, through DXF and DWG.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Desktop: write log records to standard error and a rotating log file
The desktop app installed no logger, so every log::warn!/log::error!/
log::info! in the workspace was discarded: a broken app icon, the GPU
canvas set-up, the engine's command-line echo at debug level. A launch
from a desktop menu has no terminal either, so there was nothing to
attach to a bug report.
apps/cadcraft/src/logging.rs (no new dependency):
- standard error plus <settings dir>/logs/cadcraft.log; each launch
rotates the previous log to cadcraft.1.log and .2.log, so the log of a
run that crashed survives the next start; the file is capped at 16 MiB
- records logged before the settings directory is known are buffered
(bounded) and written once the file is attached
- default levels: info for cadcraft*, warn for everything else;
RUST_LOG replaces them with env_logger-style directives
- never panics: an unusable directory or a failed write leaves standard
error as the only sink; a poisoned lock is tolerated
CADCraft had no per-user directory yet. config_dir in main.rs adds one:
CADCRAFT_CONFIG_DIR, else $XDG_CONFIG_HOME/cadcraft or ~/.config/cadcraft
(Linux, BSDs), ~/Library/Application Support/CADCraft (macOS),
%APPDATA%\CADCraft (Windows).
The logger is installed first in main and the file is opened after
argument parsing (--version leaves no file). The control server's
eprintln!s now go through the logger. A --control or
CADCRAFT_CONTROL_PORT value that is not a port is now logged instead of
silently leaving the control channel off. Documented in README.md
(Quick start > Logs).
---------
Co-authored-by: SBaksa <[email protected]>
Co-authored-by: DWAA1660 <[email protected]>
Co-authored-by: lloyd <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Dylan M. Taylor <[email protected]>
Co-authored-by: vangel76 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Tru10 <[email protected]>
Co-authored-by: Gert Pellin <[email protected]>
* DIMANGULAR: accept polyline segments (fixes#10)
Picking a side of a rectangle or a PLINE segment was rejected with
"Select a line or an arc." because only LINE and ARC entities were
accepted. The picked object is now resolved to the segment under the
cursor: straight polyline segments work like lines and arc segments
like arcs.
* Redraw edits made while a command is still running (fixes#4)
LINE and PLINE add geometry on every point, but the canvas only rebuilt
its display list when the drawing revision or the document pointer
changed. The revision was bumped when a command finished, and the
pointer changed only on the first copy-on-write edit, so only the first
segment appeared until the command ended. Session::feed now bumps the
revision after each input once the running command has changed the
drawing.
* Fix#14: include DWG in the Open drawing filter
* Blocks window: click a block to insert it (#8)
Each block name in the Blocks window is now a button. Clicking it starts INSERT with that block already chosen, so the command line asks for the insertion point.
* SCALE: Reference option (#17)
SCALE > Reference printed "not available yet". It now asks for the reference length (typed, or two points) and the new length (typed, or a point measured from the base point), and scales by new / reference. Zero, negative or non-finite lengths are rejected and asked again.
* Print and Ctrl+P ask where to save the PDF (#5)
PLOT/EXPORTPDF started from the menu, the toolbar, Ctrl+P or the command line had no path,
so the PDF was built in memory and dropped. They now open the save dialog (PDF filter first)
and write the file there. JSON calls from scripts, the control channel and MCP still never
open a dialog. Ctrl+P was shown in the menu but not bound; it is now.
* Scripts: split a line at keyword prompts so POLYGON 6 200,20 I 15 works (#43)
* Layer Properties Manager: stop the window growing every frame (fixes#29)
The vertical separator between the filter tree and the table takes all the
height it is offered, and a resizable window offers its previous height, so
the window grew 30px per frame until it filled the screen. Cap the row at the
table's fixed height. Regression test runs the dialog headless for 30 frames
and checks the height stays put.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* ui.render: fit the drawing and return pngBase64 like the headless render (#49, #50)
* Linux: default to XWayland for file drag-and-drop on Wayland desktops
* Fonts: per-character fallback, FONTALT and .ttc for CJK text in SHX styles (#130)
CJK text in a style that uses an SHX font (romans.shx + chineset.shx big font)
drew every ideograph as an empty box: the SHX name resolves to our stroke font,
which has no CJK glyphs, and the font scan skipped .ttc collections, where most
CJK system fonts live.
- Per-character fallback: a character the text's font lacks (stroke font or
TrueType) is drawn from an installed font that has it, checked by cmap.
Wide-coverage fonts go first (Noto Sans CJK, Source Han, WenQuanYi, Droid
Sans Fallback, PingFang, Microsoft JhengHei/YaHei, MS Gothic, ...), regular
weights before others. Fallback glyphs are sized like TrueType text (cap
height = text height). Lookups are cached; the search is bounded (24 files,
160 MiB, 256 faces per character, files over 96 MiB never read) and skips
spaces, controls and private-use code points. No fallback: the box as before.
- FONTALT (sysvar, seeded from CADCRAFT_FONTALT): font used for a style font
that can't be found (an SHX file, a missing TTF). Empty = our stroke font.
- FONTFALLBACK (sysvar, seeded from CADCRAFT_FONTFALLBACK): fonts tried first
for missing characters, e.g. "Noto Sans CJK TC".
- .ttc/.otc are scanned; TextFont::Outline carries a ttf::Face (bytes + face
index). Fonts are also found by family name among files with a similar
stem, so "Noto Sans CJK TC" picks face 3 of NotoSansCJK-Regular.ttc.
- Cap height falls back to the height of "H" when OS/2 has none (DejaVu
Sans), which fixes ttf_tests::system_font_outlines_when_available and
render's truetype_text_is_filled_or_outlined on machines without Arial.
- README: a Fonts section for the two settings; ROADMAP M4 note.
Native SHX / big-font rendering stays on the roadmap (M4).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Fonts: cap the total bytes of system font files loaded from disk
A drawing naming many text styles could otherwise load every installed font
into memory through family-name lookups.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Pan with a two-finger trackpad swipe; keep wheel and pinch zoom
Trackpad two-finger swipes arrive as scroll events, and the canvas turned
every scroll into a zoom, so trackpad users had no realtime pan (middle-drag
needs a middle button).
Scroll now follows the device: precise point deltas (trackpad, Magic Mouse)
pan the view by x and y; notched line deltas (mouse wheel) zoom about the
cursor as before. Pinch and Cmd+scroll still zoom through zoom_delta, and
middle-drag still pans.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019uMCkRAB8DMd8MEmoY9Vyr
* Add Tru10 to contributors/people.toml
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019uMCkRAB8DMd8MEmoY9Vyr
* Trackpad pan: only on macOS, where point deltas mean a trackpad
Browsers and Wayland smooth-scroll mice report ordinary wheels in points too,
so the wheel keeps zooming there.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Keep arc-length dimensions as arc-length through DXF save and reopen (#100)
* PLINE: Halfwidth is centre-to-edge, and Width answers taper the next segment (fixes#83, #104)
Interactive PLINE kept one width value: Halfwidth answers were stored as
the total width, and the ending-width answer overwrote the starting one,
so a taper became a constant width. The next segment's starting and
ending widths are now tracked separately, Halfwidth answers are doubled,
and each new segment (including the closing one) gets its widths on its
first vertex; later segments are uniform at the ending width, as in
AutoCAD. Uniform polylines are still stored as const_width, so their DXF
output is unchanged.
Fixes#83. Fixes#104.
* Arc-length dimensions: write a standard aligned record plus CADCraft xdata
DXF has no arc-length DIMENSION type, so write type 1 and mark the kind and
arc centre in CADCRAFT xdata (like ASSOC). Other programs read an aligned
dimension; CADCraft restores the arc length, through DXF and DWG.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Desktop: write log records to standard error and a rotating log file
The desktop app installed no logger, so every log::warn!/log::error!/
log::info! in the workspace was discarded: a broken app icon, the GPU
canvas set-up, the engine's command-line echo at debug level. A launch
from a desktop menu has no terminal either, so there was nothing to
attach to a bug report.
apps/cadcraft/src/logging.rs (no new dependency):
- standard error plus <settings dir>/logs/cadcraft.log; each launch
rotates the previous log to cadcraft.1.log and .2.log, so the log of a
run that crashed survives the next start; the file is capped at 16 MiB
- records logged before the settings directory is known are buffered
(bounded) and written once the file is attached
- default levels: info for cadcraft*, warn for everything else;
RUST_LOG replaces them with env_logger-style directives
- never panics: an unusable directory or a failed write leaves standard
error as the only sink; a poisoned lock is tolerated
CADCraft had no per-user directory yet. config_dir in main.rs adds one:
CADCRAFT_CONFIG_DIR, else $XDG_CONFIG_HOME/cadcraft or ~/.config/cadcraft
(Linux, BSDs), ~/Library/Application Support/CADCraft (macOS),
%APPDATA%\CADCraft (Windows).
The logger is installed first in main and the file is opened after
argument parsing (--version leaves no file). The control server's
eprintln!s now go through the logger. A --control or
CADCRAFT_CONTROL_PORT value that is not a port is now logged instead of
silently leaving the control channel off. Documented in README.md
(Quick start > Logs).
---------
Co-authored-by: SBaksa <[email protected]>
Co-authored-by: DWAA1660 <[email protected]>
Co-authored-by: MarekSpodBiedry <[email protected]>
Co-authored-by: lloyd <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Dylan M. Taylor <[email protected]>
Co-authored-by: vangel76 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Gert Pellin <[email protected]>
* DIMANGULAR: accept polyline segments (fixes#10)
Picking a side of a rectangle or a PLINE segment was rejected with
"Select a line or an arc." because only LINE and ARC entities were
accepted. The picked object is now resolved to the segment under the
cursor: straight polyline segments work like lines and arc segments
like arcs.
* Redraw edits made while a command is still running (fixes#4)
LINE and PLINE add geometry on every point, but the canvas only rebuilt
its display list when the drawing revision or the document pointer
changed. The revision was bumped when a command finished, and the
pointer changed only on the first copy-on-write edit, so only the first
segment appeared until the command ended. Session::feed now bumps the
revision after each input once the running command has changed the
drawing.
* Fix#14: include DWG in the Open drawing filter
* Blocks window: click a block to insert it (#8)
Each block name in the Blocks window is now a button. Clicking it starts INSERT with that block already chosen, so the command line asks for the insertion point.
* SCALE: Reference option (#17)
SCALE > Reference printed "not available yet". It now asks for the reference length (typed, or two points) and the new length (typed, or a point measured from the base point), and scales by new / reference. Zero, negative or non-finite lengths are rejected and asked again.
* Print and Ctrl+P ask where to save the PDF (#5)
PLOT/EXPORTPDF started from the menu, the toolbar, Ctrl+P or the command line had no path,
so the PDF was built in memory and dropped. They now open the save dialog (PDF filter first)
and write the file there. JSON calls from scripts, the control channel and MCP still never
open a dialog. Ctrl+P was shown in the menu but not bound; it is now.
* Scripts: split a line at keyword prompts so POLYGON 6 200,20 I 15 works (#43)
* Layer Properties Manager: stop the window growing every frame (fixes#29)
The vertical separator between the filter tree and the table takes all the
height it is offered, and a resizable window offers its previous height, so
the window grew 30px per frame until it filled the screen. Cap the row at the
table's fixed height. Regression test runs the dialog headless for 30 frames
and checks the height stays put.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* ui.render: fit the drawing and return pngBase64 like the headless render (#49, #50)
* Linux: default to XWayland for file drag-and-drop on Wayland desktops
* Fonts: per-character fallback, FONTALT and .ttc for CJK text in SHX styles (#130)
CJK text in a style that uses an SHX font (romans.shx + chineset.shx big font)
drew every ideograph as an empty box: the SHX name resolves to our stroke font,
which has no CJK glyphs, and the font scan skipped .ttc collections, where most
CJK system fonts live.
- Per-character fallback: a character the text's font lacks (stroke font or
TrueType) is drawn from an installed font that has it, checked by cmap.
Wide-coverage fonts go first (Noto Sans CJK, Source Han, WenQuanYi, Droid
Sans Fallback, PingFang, Microsoft JhengHei/YaHei, MS Gothic, ...), regular
weights before others. Fallback glyphs are sized like TrueType text (cap
height = text height). Lookups are cached; the search is bounded (24 files,
160 MiB, 256 faces per character, files over 96 MiB never read) and skips
spaces, controls and private-use code points. No fallback: the box as before.
- FONTALT (sysvar, seeded from CADCRAFT_FONTALT): font used for a style font
that can't be found (an SHX file, a missing TTF). Empty = our stroke font.
- FONTFALLBACK (sysvar, seeded from CADCRAFT_FONTFALLBACK): fonts tried first
for missing characters, e.g. "Noto Sans CJK TC".
- .ttc/.otc are scanned; TextFont::Outline carries a ttf::Face (bytes + face
index). Fonts are also found by family name among files with a similar
stem, so "Noto Sans CJK TC" picks face 3 of NotoSansCJK-Regular.ttc.
- Cap height falls back to the height of "H" when OS/2 has none (DejaVu
Sans), which fixes ttf_tests::system_font_outlines_when_available and
render's truetype_text_is_filled_or_outlined on machines without Arial.
- README: a Fonts section for the two settings; ROADMAP M4 note.
Native SHX / big-font rendering stays on the roadmap (M4).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Fonts: cap the total bytes of system font files loaded from disk
A drawing naming many text styles could otherwise load every installed font
into memory through family-name lookups.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Pan with a two-finger trackpad swipe; keep wheel and pinch zoom
Trackpad two-finger swipes arrive as scroll events, and the canvas turned
every scroll into a zoom, so trackpad users had no realtime pan (middle-drag
needs a middle button).
Scroll now follows the device: precise point deltas (trackpad, Magic Mouse)
pan the view by x and y; notched line deltas (mouse wheel) zoom about the
cursor as before. Pinch and Cmd+scroll still zoom through zoom_delta, and
middle-drag still pans.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019uMCkRAB8DMd8MEmoY9Vyr
* Add Tru10 to contributors/people.toml
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019uMCkRAB8DMd8MEmoY9Vyr
* Trackpad pan: only on macOS, where point deltas mean a trackpad
Browsers and Wayland smooth-scroll mice report ordinary wheels in points too,
so the wheel keeps zooming there.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Keep arc-length dimensions as arc-length through DXF save and reopen (#100)
* PLINE: Halfwidth is centre-to-edge, and Width answers taper the next segment (fixes#83, #104)
Interactive PLINE kept one width value: Halfwidth answers were stored as
the total width, and the ending-width answer overwrote the starting one,
so a taper became a constant width. The next segment's starting and
ending widths are now tracked separately, Halfwidth answers are doubled,
and each new segment (including the closing one) gets its widths on its
first vertex; later segments are uniform at the ending width, as in
AutoCAD. Uniform polylines are still stored as const_width, so their DXF
output is unchanged.
Fixes#83. Fixes#104.
* Arc-length dimensions: write a standard aligned record plus CADCraft xdata
DXF has no arc-length DIMENSION type, so write type 1 and mark the kind and
arc centre in CADCRAFT xdata (like ASSOC). Other programs read an aligned
dimension; CADCraft restores the arc length, through DXF and DWG.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Desktop: write log records to standard error and a rotating log file
The desktop app installed no logger, so every log::warn!/log::error!/
log::info! in the workspace was discarded: a broken app icon, the GPU
canvas set-up, the engine's command-line echo at debug level. A launch
from a desktop menu has no terminal either, so there was nothing to
attach to a bug report.
apps/cadcraft/src/logging.rs (no new dependency):
- standard error plus <settings dir>/logs/cadcraft.log; each launch
rotates the previous log to cadcraft.1.log and .2.log, so the log of a
run that crashed survives the next start; the file is capped at 16 MiB
- records logged before the settings directory is known are buffered
(bounded) and written once the file is attached
- default levels: info for cadcraft*, warn for everything else;
RUST_LOG replaces them with env_logger-style directives
- never panics: an unusable directory or a failed write leaves standard
error as the only sink; a poisoned lock is tolerated
CADCraft had no per-user directory yet. config_dir in main.rs adds one:
CADCRAFT_CONFIG_DIR, else $XDG_CONFIG_HOME/cadcraft or ~/.config/cadcraft
(Linux, BSDs), ~/Library/Application Support/CADCraft (macOS),
%APPDATA%\CADCraft (Windows).
The logger is installed first in main and the file is opened after
argument parsing (--version leaves no file). The control server's
eprintln!s now go through the logger. A --control or
CADCRAFT_CONTROL_PORT value that is not a port is now logged instead of
silently leaving the control channel off. Documented in README.md
(Quick start > Logs).
---------
Co-authored-by: SBaksa <[email protected]>
Co-authored-by: DWAA1660 <[email protected]>
Co-authored-by: MarekSpodBiedry <[email protected]>
Co-authored-by: lloyd <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Dylan M. Taylor <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Tru10 <[email protected]>
Co-authored-by: Gert Pellin <[email protected]>
* DIMANGULAR: accept polyline segments (fixes#10)
Picking a side of a rectangle or a PLINE segment was rejected with
"Select a line or an arc." because only LINE and ARC entities were
accepted. The picked object is now resolved to the segment under the
cursor: straight polyline segments work like lines and arc segments
like arcs.
* Redraw edits made while a command is still running (fixes#4)
LINE and PLINE add geometry on every point, but the canvas only rebuilt
its display list when the drawing revision or the document pointer
changed. The revision was bumped when a command finished, and the
pointer changed only on the first copy-on-write edit, so only the first
segment appeared until the command ended. Session::feed now bumps the
revision after each input once the running command has changed the
drawing.
* Fix#14: include DWG in the Open drawing filter
* Blocks window: click a block to insert it (#8)
Each block name in the Blocks window is now a button. Clicking it starts INSERT with that block already chosen, so the command line asks for the insertion point.
* SCALE: Reference option (#17)
SCALE > Reference printed "not available yet". It now asks for the reference length (typed, or two points) and the new length (typed, or a point measured from the base point), and scales by new / reference. Zero, negative or non-finite lengths are rejected and asked again.
* Print and Ctrl+P ask where to save the PDF (#5)
PLOT/EXPORTPDF started from the menu, the toolbar, Ctrl+P or the command line had no path,
so the PDF was built in memory and dropped. They now open the save dialog (PDF filter first)
and write the file there. JSON calls from scripts, the control channel and MCP still never
open a dialog. Ctrl+P was shown in the menu but not bound; it is now.
* Scripts: split a line at keyword prompts so POLYGON 6 200,20 I 15 works (#43)
* Layer Properties Manager: stop the window growing every frame (fixes#29)
The vertical separator between the filter tree and the table takes all the
height it is offered, and a resizable window offers its previous height, so
the window grew 30px per frame until it filled the screen. Cap the row at the
table's fixed height. Regression test runs the dialog headless for 30 frames
and checks the height stays put.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* ui.render: fit the drawing and return pngBase64 like the headless render (#49, #50)
* Linux: default to XWayland for file drag-and-drop on Wayland desktops
* Fonts: per-character fallback, FONTALT and .ttc for CJK text in SHX styles (#130)
CJK text in a style that uses an SHX font (romans.shx + chineset.shx big font)
drew every ideograph as an empty box: the SHX name resolves to our stroke font,
which has no CJK glyphs, and the font scan skipped .ttc collections, where most
CJK system fonts live.
- Per-character fallback: a character the text's font lacks (stroke font or
TrueType) is drawn from an installed font that has it, checked by cmap.
Wide-coverage fonts go first (Noto Sans CJK, Source Han, WenQuanYi, Droid
Sans Fallback, PingFang, Microsoft JhengHei/YaHei, MS Gothic, ...), regular
weights before others. Fallback glyphs are sized like TrueType text (cap
height = text height). Lookups are cached; the search is bounded (24 files,
160 MiB, 256 faces per character, files over 96 MiB never read) and skips
spaces, controls and private-use code points. No fallback: the box as before.
- FONTALT (sysvar, seeded from CADCRAFT_FONTALT): font used for a style font
that can't be found (an SHX file, a missing TTF). Empty = our stroke font.
- FONTFALLBACK (sysvar, seeded from CADCRAFT_FONTFALLBACK): fonts tried first
for missing characters, e.g. "Noto Sans CJK TC".
- .ttc/.otc are scanned; TextFont::Outline carries a ttf::Face (bytes + face
index). Fonts are also found by family name among files with a similar
stem, so "Noto Sans CJK TC" picks face 3 of NotoSansCJK-Regular.ttc.
- Cap height falls back to the height of "H" when OS/2 has none (DejaVu
Sans), which fixes ttf_tests::system_font_outlines_when_available and
render's truetype_text_is_filled_or_outlined on machines without Arial.
- README: a Fonts section for the two settings; ROADMAP M4 note.
Native SHX / big-font rendering stays on the roadmap (M4).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Fonts: cap the total bytes of system font files loaded from disk
A drawing naming many text styles could otherwise load every installed font
into memory through family-name lookups.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Pan with a two-finger trackpad swipe; keep wheel and pinch zoom
Trackpad two-finger swipes arrive as scroll events, and the canvas turned
every scroll into a zoom, so trackpad users had no realtime pan (middle-drag
needs a middle button).
Scroll now follows the device: precise point deltas (trackpad, Magic Mouse)
pan the view by x and y; notched line deltas (mouse wheel) zoom about the
cursor as before. Pinch and Cmd+scroll still zoom through zoom_delta, and
middle-drag still pans.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019uMCkRAB8DMd8MEmoY9Vyr
* Add Tru10 to contributors/people.toml
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019uMCkRAB8DMd8MEmoY9Vyr
* Trackpad pan: only on macOS, where point deltas mean a trackpad
Browsers and Wayland smooth-scroll mice report ordinary wheels in points too,
so the wheel keeps zooming there.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Keep arc-length dimensions as arc-length through DXF save and reopen (#100)
* PLINE: Halfwidth is centre-to-edge, and Width answers taper the next segment (fixes#83, #104)
Interactive PLINE kept one width value: Halfwidth answers were stored as
the total width, and the ending-width answer overwrote the starting one,
so a taper became a constant width. The next segment's starting and
ending widths are now tracked separately, Halfwidth answers are doubled,
and each new segment (including the closing one) gets its widths on its
first vertex; later segments are uniform at the ending width, as in
AutoCAD. Uniform polylines are still stored as const_width, so their DXF
output is unchanged.
Fixes#83. Fixes#104.
* Arc-length dimensions: write a standard aligned record plus CADCraft xdata
DXF has no arc-length DIMENSION type, so write type 1 and mark the kind and
arc centre in CADCRAFT xdata (like ASSOC). Other programs read an aligned
dimension; CADCraft restores the arc length, through DXF and DWG.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Desktop: write log records to standard error and a rotating log file
The desktop app installed no logger, so every log::warn!/log::error!/
log::info! in the workspace was discarded: a broken app icon, the GPU
canvas set-up, the engine's command-line echo at debug level. A launch
from a desktop menu has no terminal either, so there was nothing to
attach to a bug report.
apps/cadcraft/src/logging.rs (no new dependency):
- standard error plus <settings dir>/logs/cadcraft.log; each launch
rotates the previous log to cadcraft.1.log and .2.log, so the log of a
run that crashed survives the next start; the file is capped at 16 MiB
- records logged before the settings directory is known are buffered
(bounded) and written once the file is attached
- default levels: info for cadcraft*, warn for everything else;
RUST_LOG replaces them with env_logger-style directives
- never panics: an unusable directory or a failed write leaves standard
error as the only sink; a poisoned lock is tolerated
CADCraft had no per-user directory yet. config_dir in main.rs adds one:
CADCRAFT_CONFIG_DIR, else $XDG_CONFIG_HOME/cadcraft or ~/.config/cadcraft
(Linux, BSDs), ~/Library/Application Support/CADCraft (macOS),
%APPDATA%\CADCraft (Windows).
The logger is installed first in main and the file is opened after
argument parsing (--version leaves no file). The control server's
eprintln!s now go through the logger. A --control or
CADCRAFT_CONTROL_PORT value that is not a port is now logged instead of
silently leaving the control channel off. Documented in README.md
(Quick start > Logs).
---------
Co-authored-by: SBaksa <[email protected]>
Co-authored-by: DWAA1660 <[email protected]>
Co-authored-by: MarekSpodBiedry <[email protected]>
Co-authored-by: lloyd <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: vangel76 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Tru10 <[email protected]>
Co-authored-by: Gert Pellin <[email protected]>
The vertical separator between the filter tree and the table takes all the
height it is offered, and a resizable window offers its previous height, so
the window grew 30px per frame until it filled the screen. Cap the row at the
table's fixed height. Regression test runs the dialog headless for 30 frames
and checks the height stays put.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Each block name in the Blocks window is now a button. Clicking it starts INSERT with that block already chosen, so the command line asks for the insertion point.
SCALE > Reference printed "not available yet". It now asks for the reference length (typed, or two points) and the new length (typed, or a point measured from the base point), and scales by new / reference. Zero, negative or non-finite lengths are rejected and asked again.
PLOT/EXPORTPDF started from the menu, the toolbar, Ctrl+P or the command line had no path,
so the PDF was built in memory and dropped. They now open the save dialog (PDF filter first)
and write the file there. JSON calls from scripts, the control channel and MCP still never
open a dialog. Ctrl+P was shown in the menu but not bound; it is now.
Picking a side of a rectangle or a PLINE segment was rejected with
"Select a line or an arc." because only LINE and ARC entities were
accepted. The picked object is now resolved to the segment under the
cursor: straight polyline segments work like lines and arc segments
like arcs.