main added view twist. Kept from both: a drawing opens on the view it was saved at, with its saved twist; one that stores none fits its extents through main's twisted box. The VPORT reader takes main's twisted view centre and keeps this PR's first-*ACTIVE view; the writer writes the saved view, else main's twisted fit, with the fallback still fitting the width through the record's aspect.
* fix(ui): About credits tables fit without side-scrolling and their columns resize
The Contributors table and the Models table were egui Grids inside a
two-way scroll area: they opened wider than the dialog, so they scrolled
sideways, and Company and Model sat almost touching. Both are now
egui_extras tables. Each column opens at the width of its header and widest
cell, the spare width goes to the text columns (Name; Company and Model),
and every column edge can be dragged. Widening a column grows the table
like a spreadsheet, and only then does it scroll sideways; the header stays
put while the rows scroll. Counts and dates are right-aligned and every
cell is vertically centred.
The sorted column stays highlighted and its direction shows on the
toolbar's sort-order button, so headers no longer reserve room for an
arrow. The opening widths come from fit_widths, a pure function with unit
tests that a fitted table fills its room exactly and that only the text
columns give way when room is short.
The About dialog opens 820 points wide, so every column fits at its natural width.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Let every credits column be dragged, and refit changed tables
The last column was egui's remainder column, which has no drag handle, so
it could only be resized from the edge before it. It is now an ordinary
column with its own handle.
A table keeps its column widths, so switching to a longer name left the
Name column at its old width and clipped the text. The table now goes
back to the opening fit whenever that fit changes: a longer widest cell
or a resized window. Dragged widths are dropped at that point.
fit_widths could overflow the room when one column hit the minimum,
because the other columns did not take up its share. Columns now give
way in proportion to their width above the minimum.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Refit credits tables on what they measure, not the fitted widths
Comparing the fitted widths missed the case it was meant for. Name is the
only growing column, so a longer name takes its extra width from the
spare room and the fit comes out the same: a dragged Name width stayed,
clipping the longer name.
It could also drop dragged widths by accident. The fit comes from the
available width inside the scroll area, which scrolling can nudge, so
scrolling a widened table could reset it.
The table now compares the natural widths and the clip rect's width,
which scrolling does not move.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- The linked-folder test (Unix only) passes a slice without a clone (clippy
cloned_ref_to_slice_refs, which failed the Linux gate).
- In a DOS 862 Hebrew SHX font, %%d still draws from the old degree shape 127: only 128-129
are letters there.
- The viewport highlight, drag preview and command preview caches key on the font set too,
so text in them is drawn again when fonts change.
* New and redrawn icons (drawn in code); a click on a painted control leaves the keyboard with the drawing
Split out of #2034. No image files: every icon is drawn in code.
- New: Zoom In / Zoom Out / Zoom to Fit, Move to Top / Up / Down /
Bottom, Text Style and Dimension Style (with a small gear); redrawn:
Undo, Redo, Plot, Preview, the dimension tools and others.
- icons::button_bare: a button without its hover text, for callers that
show a richer tooltip.
- Clicking a painted control (a file tab) no longer takes keyboard focus,
so Ctrl+C in one drawing and Ctrl+V in another keep working; Tab still
reaches it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RzTHYMZTCtkW9FExLCKj5V
* Undo/Redo icons of our own design; the clipboard test requires the copied text
Review (CodeRabbit): the Undo/Redo comment named another product's icons as
the model. The icons are redrawn to our own design (a straight run and a
half-turn back, in the icon colour) and the reference is gone.
The cross-drawing clipboard test no longer falls back to placeholder text:
it installs a DXF writer and requires the copy to reach the system
clipboard.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RzTHYMZTCtkW9FExLCKj5V
* Icons: fit upstream's split icon painter (the pen's painter, theme colours, dim flag)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RzTHYMZTCtkW9FExLCKj5V
* Icons: drop the dangling tool_button doc link; describe the tab click focus as it behaves
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
- A face found by family name in the user's font folders is loaded within the font-byte
budget: no uncharged read past it (CodeRabbit on #2316).
- Linked font folders are followed again, as before #2316, in the system scan, the user
scan and the SHX folder search; each real folder is read once, so a circle of links
can't use up the scan's entry budget (CodeRabbit on #2316).
- The user-font-folder test changes process-wide font settings and emptied the font table
under tests running beside it (2 of 3 runs failed): it moves to its own test binary,
tests/ttf_font_folders.rs; that a list keeps no font bytes is checked on a local table.
The extents took the first copy and the far corner copy only. Turned, the grid's
other two corner copies lie outside that box, so ZOOM Extents cut them off. All
four corner copies count now, and the counts are clamped to the 10,000 columns
and rows the renderer draws. Found by CodeRabbit on #2756.
Rebuilt on main after #1944 (SHX shape fonts, big fonts, unifonts) landed: this part now
keeps only what #1944 doesn't do.
- User font folders (Options > Fonts, fontFolders): TrueType and OpenType files in them are
found before the system's and listed first (ttf::set_font_dirs, installed, available,
rescan); a face is found by its family name in any file there. SHX files in them, or in a
folder under them, are found by the SHX font table too (shx::set_font_dirs), after the
drawings' folders and before the search path. Folders are cleaned and capped, links to
folders are not followed.
- Hebrew SHX fonts: a one-byte font with the letters at their Windows-1255 or DOS 862 places
draws Hebrew text from them; a Cyrillic font with letters at those places is not taken for
Hebrew. In a DOS 862 font, %%d %%p %%c come from shapes 256-258 only.
- The canvas draws text again when the TrueType or SHX font set changes (a font folder, a
rescan, a drawing folder), the active viewport's model space included.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RzTHYMZTCtkW9FExLCKj5V
AutoCAD 2024 writes no group 290 on a SPATIAL_FILTER in a DXF and discards a file whose
filter has one (measured by 2ez4gcx, #2756). An inverted clip's filter now gets an
extension dictionary with the ACAD_XREC_ROUNDTRIP XRECORD (ACAD_INVERTEDCLIP_ROUNDTRIP,
then ..._COMPARE). Reading takes the ROUNDTRIP list as the boundary while COMPARE matches
the filter's vertices, so AutoCAD's keyhole filters read as the clip drawn; 290 is still
read when present. The record survives DWG, so CADCraft's own CADCRAFT_XCLIP flag is gone.
- objects are found through a handle index when reading and writing clips, and removed in one pass (no scan per reference)
- the writer's handle seed starts past the clip objects, so a drawing with many clipped references gets no duplicate handles
- a clipped copy that runs out of the block budget marks the list truncated, like an unclipped one
- clipped block contents keep their own layers in plots
Review fixes from CodeRabbit on #2748:
- DVIEW TWist and view.set refuse to turn a locked active viewport ("The viewport is locked.")
- the untiled *Active VPORT record fits the extents rotated by the twist it writes, with the twist normalised
Review fixes from CodeRabbit on #2749:
- the image file is read through read_capped, so a file that grows after the size check can't exhaust memory
- an image cut by a layout viewport widens the sheet's bounds only by the part inside it, as other primitives do
- uploaded tiles of closed drawings are dropped also when the next list has no images
* fix(render): charge every block entry, index attribute definitions, and walk dashes and outlines in linear time
Array copies skipped ATTDEF entries before charging the expansion budget, each attribute searched its block for a definition, each dash scanned every centreline sample, and outline chaining searched a vertex's segment list from its start on every visit. Each is now charged, indexed or cursored.
* address review: drop wall-clock bound from outline test
The heartbeat opened <instance>.lock with a create-and-truncate that followed symlinks, and fell back to std::fs::write, so another account sharing SAVEFILEPATH could plant a link and have the app truncate a file of the victim's. The lock is now opened with O_NOFOLLOW|O_NONBLOCK and must be a plain file, and unlocked writes replace the file through the atomic writer. Autosave files are created 0600 regardless of umask. Lock pruning parses the folder's autosave names once instead of once per lock.
- Every engine twist (DVIEW, view.set, opening a drawing, the untiled view) goes through norm_angle, so a tiny negative twist is 0, not a full turn.
- VIEW Window in a twisted view stores the window's size along the view's axes (View::twisted_box), so a restore shows all of it.
- A deferred tangent or perpendicular snap on an arc in a twisted layout viewport turns the arc's angles with its centre.
- The active viewport's cached drawing is rebuilt when its twist changes; moving and scaling it can't turn it.