Commit Graph
219 Commits
Author SHA1 Message Date
Hakan SevenandClaude Fable 5 d154a01cb4 chore(release): v0.8.5
Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-21 10:13:27 +03:00
Hakan SevenandClaude Fable 5 e8411c1b6d feat(ole): render EMF/WMF OLE presentations
OLE2FRAME entities whose compound file carries a metafile presentation
(Excel/Word previews, scanned WMF pages) drew only their border frame —
the old decoder scanned the raw blob for a contiguous BMP, which the
CFB sector layout almost never provides. acadrust now extracts the
picture bytes tagged by kind; the new scene/model/gdi player rasterizes
EMF and WMF record streams on the CPU (pens/brushes, polygons, paths,
DIB blits, clipping, transforms) with text drawn through the existing
system-font glyph cache, and image_model feeds the result into the
raster pipeline. Rasters (BMP/PNG/JPEG/GIF, CF_DIB) decode as before
via the image crate.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-21 01:23:31 +03:00
Hakan SevenandClaude Opus 4.8 1cfb856224 refactor(dwg): use the first-class SectionSymbol and ViewBorder entities
Section marks and drawing-view borders are now real acadrust entity
types instead of Unknown-with-extras, so the renderer dispatches on the
variant directly, the arrow-direction resolver reads the active viewport
off the ViewBorder entity, and selection / properties show "Section
Symbol" and "View Border" instead of "Unknown". View borders are
non-plotting and tessellate to nothing; both count toward the lossy
Save-As warning since they round-trip via their raw records.

Bumps acadrust for the entity promotion.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-21 00:19:51 +03:00
Hakan SevenandClaude Opus 4.8 3b2b8ad21d feat(dwg): render section marks from their decoded style and view graph
The section mark's appearance now comes entirely from file data instead
of invented conventions:

- Arrow direction: resolved through the drawing-view graph — the
  symbol's parent AcDbViewRep, the section view (owner of the section
  definition), each view border's active viewport — by projecting the
  section camera's sight onto the parent camera's basis, using the same
  yaw/pitch/twist convention the viewport renderer does. Only when the
  chain is unavailable (DXF, older files) does a geometric fallback
  apply.
- Broken cutting line: driven by the style's plane-line / end-segment
  flags rather than hard-coded.
- Arrowhead: resolved through the shared dimension/leader arrow table
  from the style's arrow block handle; a null handle gives the standard
  ClosedFilled default.
- Label gap: the style's identifier offset.

Bumps acadrust for the style and view-graph decode.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-20 23:50:58 +03:00
Hakan SevenandClaude Opus 4.8 46e636b955 feat(dwg): render section marks on model-documentation layouts
Draw decoded section symbols (AcDbSectionSymbol) as their "A-A" cut mark:
the cut line through both endpoints extended past each end by its signed
tick, a short perpendicular barb at each tip, and the identifier glyph.
The mark now appears on the layout alongside the drawing views instead
of being silently dropped.

Bumps acadrust to pick up the section-symbol decode.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-20 22:20:58 +03:00
Hakan SevenandClaude Opus 4.8 1b6a3a6f5b feat(mtext): evaluate dynamic text fields at render time
Re-evaluate AcDbField-driven MTEXT — date/login/document-property fields, table
formulas and object properties — against the current system instead of showing
the frozen last-save cache. The evaluation engine lives in `acadrust::fields`;
OCS supplies only the environment (system clock, OS login, env vars) through a
FieldContext implementation, and hooks the resolved text into MTEXT rendering,
falling back to the cached value for anything it can't evaluate.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-20 00:06:58 +03:00
Hakan SevenandClaude Opus 4.8 b30f9b9741 feat(scene): draw nonprint light, camera and geo-location glyphs
Lights, camera views and the geographic-location marker had no on-screen
representation. Add display glyphs for all three:

- Lights render through a new EntityType::Light: a cone/flashlight for spot
  lights, a wire sphere for point lights, a sun for distant lights, sized in
  screen space (fixed-world fallback).
- Camera views (perspective VIEW records) and the GEODATA "daisy" marker are
  synthesized into the model-space resident wire set from the document, since
  they are not entities.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-19 22:15:40 +03:00
Hakan SevenandClaude Opus 4.8 4479ba8c29 fix(mtext): correct imported-text size in the editor (#394)
The editor preview mis-sized imported MTEXT badly (tiny, huge, or
collapsed). Two root causes:

- The entity's base height often isn't the visible text height: relative
  `\H…x;` codes compound, so an entity of height 1 whose body is `\H0.2x`
  renders at 0.2. Normalize the preview scale by the DOMINANT rendered run
  height (the mode of glyph-box heights, skipping zero-width caret slots),
  not `height_value()`, so the body lands at a fixed readable size and
  headings keep their proportions. EM_PX = 15.
- The bug that made it "completely wrong" was in the serializer, fixed in
  acadrust 389b31a (\H heights decayed on the parse→serialize→parse the
  editor does via folded_value); bumped here.

Also render multi-column MTEXT with its columns side by side (as the
drawing does) and let the preview scroll horizontally to reach them.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-19 17:16:53 +03:00
Hakan SevenandClaude Opus 4.8 f797fd800b chore(release): v0.8.4
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-19 02:58:25 +03:00
Hakan SevenandClaude Opus 4.8 b2720987a7 build(deps): bump acadrust to 9d2e67f (reject out-of-range ACI)
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-19 01:36:40 +03:00
Hakan SevenandClaude Opus 4.8 4e9ff101b1 build(deps): bump acadrust to 8e86b4d (MTEXT parser gap fixes)
Picks up the ezdxf-audited MTEXT parser fixes: raw LF as a paragraph
break, control chars rendered as spaces, and the corrected `\c`
true-color byte order (so `\c` colors no longer come out red/blue
swapped).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-19 01:31:57 +03:00
Hakan SevenandClaude Opus 4.8 f808030eb6 fix(mtext): tab stops are column-relative and align-aware when wrapping
Two defects in tabbed fields inside a multi-column MText:

- Stop positions are relative to the paragraph's own left edge, but the
  tab logic compared them against the column-absolute `cursor_x`. In a
  second column `cursor_x` already carries the column offset, so no stop
  ever matched and the field shot off to the default 4-em grid, way past
  the page. Measure against the column's `box_left` instead.
- A field after a center/right/decimal tab aligns on the stop, reaching
  only part of its width to the right, but word-wrap flushed it left and
  wrapped it off the line by its full width — dropping a wide decimal
  number onto a fresh, un-tabbed line. Don't wrap the field that follows
  an aligning tab.

Picks up acadrust b16137f (decimal stop position parse).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-19 01:10:56 +03:00
Hakan SevenandClaude Opus 4.8 3da678b2ca feat(mtext): align tabbed fields on center/right/decimal tab stops
A `\t` reaching a center, right, or decimal (`D`) tab stop now aligns the
field that follows it — the run of words up to the next space/tab — instead
of just advancing the pen:

- decimal: the field's first `.` lands on the stop (a column of numbers
  aligns on the decimal point; a field with no `.` aligns its end),
- right: the field's end lands on the stop,
- center: its middle.

The stop wins even when the field is wider than the room before it, so the
dot/edge stays put and the field overruns to the left, keeping the column
aligned. Left stops and the default 4-em grid are unchanged. Picks up
acadrust 162f194, which carries the tab-stop kinds.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-19 00:45:26 +03:00
Hakan SevenandClaude Opus 4.8 0de2f76921 feat(mtext): render justify and distribute paragraph alignment
`qj`/`qd` were stubbed to left. Now the layout fills the line to the
content width:

- Distribute (`qd`, and headings that reset with `q*` → justify) shares
  the slack across every glyph gap — word gaps widen and letters spread
  via tracking (LFF stroke fonts; TTF with zero letter-spacing spread
  their word gaps only). Every line, including the paragraph's last.
- Justify spreads only the word gaps and leaves the last line ragged.

Bumps acadrust to 504281a, which parses `\pqd` as Distributed and
`\pq*` as Justified so these alignments reach the layout at all.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-19 00:00:24 +03:00
Hakan SevenandClaude Opus 4.8 1b974df505 feat(image): show the file path for an unresolved raster reference
An IMAGE whose file can't be opened (a URL, or a missing/renamed file) now
draws its clip/frame outline plus the saved path as centred text in the
image colour — AutoCAD's broken-reference placeholder — instead of an empty
frame. OCS never fetches remote paths. Bumps acadrust so the entity's path
is populated from its ImageDefinition.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-18 19:32:14 +03:00
Hakan SevenandClaude Opus 4.8 cb83575fdc chore(deps): bump acadrust — ATTDEF flag decode
Picks up the ATTDEF flags/geometry fix so a CONSTANT block attribute
renders instead of being skipped as a template.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-18 18:02:47 +03:00
Hakan SevenandClaude Opus 4.8 0658601c41 fix(block): render constant attributes; bump acadrust for multiline attrs
A CONSTANT ATTDEF has no per-insert ATTRIB — its value belongs to the block
itself — so block expansion must draw it instead of skipping every ATTDEF.
Non-constant templates are still skipped (the insert supplies their ATTRIB).

Also bumps acadrust to decode the embedded MTEXT of R2018 multiline
attributes, so a value like "A\PB" renders both lines.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-18 17:57:23 +03:00
Hakan SevenandClaude Opus 4.8 e26b1ad488 chore(deps): bump acadrust — ATTRIB invisible flag decode
Picks up the ATTRIB flags/generation/field-length/lock fix so an
attribute tagged invisible is no longer drawn (ATTMODE 1).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-18 17:29:32 +03:00
Hakan SevenandClaude Opus 4.8 f2adfad2b3 chore(deps): bump acadrust — MULTILEADER has_ds decode fix
Pulls the acadrust fix that decides the R2013 has_ds bit for MULTILEADER by
peeking the class_version, so a MULTILEADER whose writer emits the bit
(budweiser handle 9821) decodes its leader roots / arrowhead / content instead
of an empty context. The leader now renders.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-18 16:03:16 +03:00
Hakan SevenandClaude Opus 4.8 5e127ffa75 fix(table): place a baked *T table block at the table's insertion point
A Table whose cells are baked into a *T block (block_record_handle) was rendered
by tessellating the block's sub-entities directly. Those are laid out in
block-local space (origin at the table's top-left corner) — the Table entity
carries the world placement in insertion_point + horizontal_direction, exactly
like an INSERT — so the whole table drew at the world origin instead of its
location.

Each baked sub-entity is now cloned and placed (rotated about the local origin
by the horizontal_direction angle, then translated by insertion_point) before
tessellation, so tessellate_entity produces correctly located, relative-to-eye
geometry. Verified on budweiser handle 9378: its baked lines move from (0,0) to
the insertion point (-1200018.7, -800071.4).

Also bumps acadrust to pull the OLE2FRAME corner-decode fix, which places
OLE2FRAME entities (e.g. handle 3088) at their real corners instead of the
(1,1)/(0,0) defaults.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-18 13:12:08 +03:00
Hakan SevenandClaude Opus 4.8 d80d037e2f chore(deps): bump acadrust — SatIntCurve spline decoder
Adds SatIntCurve (nubs B-spline parse + De Boor sampler, plus sample_range
for an edge's own arc), so intcurve-curve spline edges decode to real
geometry instead of nothing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-18 00:18:10 +03:00
Hakan SevenandClaude Opus 4.8 6d7eb94701 chore(deps): bump acadrust — keep \N column breaks distinct
The MTEXT parser turned `\N` into a plain paragraph, identical to `\P`, so
a multi-column MTEXT arrived with nothing left to lay columns out from —
and the writer sent every break back as `\P`, collapsing the columns for
good on round-trip. `MTextParagraph::starts_column` now carries it.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-17 16:47:47 +03:00
Hakan SevenandClaude Opus 4.8 3bd5453c3b chore(deps): bump acadrust — surface class-based entities the reader can't type
Pulls acadrust 769741d: the classes reader never derived is_an_entity from
item_class_id, so the flag was false for every class and any class-based entity
without an explicit type mapping was decoded as an object and dropped. Drawings
carrying an application's custom entity silently lost it.

Surfaces such entities as EntityType::Unknown with their raw record and proxy
graphics, so the renderer can fall back to the cached outline the way AutoCAD
does for an object whose enabler is absent.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-17 12:47:51 +03:00
Hakan SevenandClaude Opus 4.8 8f3cd33ff0 chore(deps): bump acadrust — fix linked raster images vanishing
Pulls acadrust dd4a4dc: the R2013+ has_ds bit was skipped for any entity
carrying preview graphics, which desynced every preview-bearing IMAGE and
WIPEOUT — an IMAGE's imagedef handle decoded one off, so the IMAGEDEF lookup
missed, the file path resolved to nothing and the linked image silently
disappeared. Regression since v0.8.1 (the has_ds gate landed in 208bb09).

The skip is now narrowed to MULTILEADER, the one type actually observed to
omit the bit; IMAGE, WIPEOUT and MULTILEADER all decode correctly.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-17 12:22:01 +03:00
Hakan SevenandClaude Opus 4.8 1d6a04183e feat(render): draw DGN line-style symbols on linetypes
Linetypes converted from MicroStation DGN keep their pattern in DGN line-style
objects (empty standard LTYPE), so entities using them drew as a plain line and
lost the symbols (e.g. a pipe's end circles). Walk the line-style tree
(resolved by name to its LSDefinition), collect the symbol components' anonymous
blocks, and draw each at the host polyline's endpoints, scaled by the symbol's
decoded scale (geometry / scale) so it matches the drawing (verified: a 0.75
ellipse renders at the file's intended 0.375 radius).

Bumps acadrust to 8e18c6b (DGN line-style symbol-scale decode). First pass: the
stroke dash pattern and exact per-vertex placement need more of the line-style
leaf decoded; the base line still draws solid.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-16 21:48:06 +03:00
Hakan SevenandClaude Opus 4.8 7647fb427c chore(deps): bump acadrust to the DGN line-style reader
Picks up acadrust 6508b76: reads DGN line-style objects (AcDbLS*) into the
document's dgn_ls_definitions / dgn_ls_components tables. No OCS code consumes
them yet — that lands with the linetype linkage and renderer.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-16 19:54:08 +03:00
Hakan SevenandClaude Opus 4.8 0e18b5bb33 feat(mline): render multilines from their MLINESTYLE + complex linetypes
Multilines were drawn with a fixed ±scale/2 two-line guess in the entity
colour, ignoring the MLINESTYLE entirely, so a drawing's custom style (per-
element offsets, colours and linetypes) was lost — a red/yellow multiline
rendered as a white box.

- mline.rs: resolve the MLINESTYLE (by style_handle, then name) and build one
  parallel line per element from its offset x scale + justification shift.
- tessellate.rs: special-case MLINE (like Leader) to emit one WireModel per
  element in the element's own colour, CPU-dashing every element through
  apply_along so the parallel lines stay in phase.
- linetypes.rs: render a drawing's OWN complex linetypes (embedded text/shape),
  document definition first and the bundled .lin catalog only as a fallback, so
  a file-defined text linetype like PLYN shows its text.
- Run the dash/glyph layout in a local frame (f64 origin subtracted, re-split to
  double-single after) so spacing stays precise at UTM coordinates, and pass
  tracking = 1.0 so embedded text keeps its letter spacing.

Cargo.lock pins acadrust to the MLINE->MLINESTYLE handle-link reader fix.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-16 18:44:15 +03:00
Hakan Seven 60c70ba023 release: v0.8.3 2026-07-16 11:57:34 +03:00
Hakan SevenandClaude Opus 4.8 9a86a7394c build(deps): compile acadrust from the OpenAEC-Foundation/acadifc fork
Point the acadrust patch at the OpenAEC-Foundation/acadifc fork (still the
`acadrust` crate). Its main carries the Arc copy-on-write entity storage that
makes the undo document clone O(entities) refcount bumps instead of a full deep
copy — cutting the per-edit snapshot on a 788k-entity drawing from ~1.7s to
~70ms. No source changes here: acadrust`s public API is unchanged.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-15 07:55:27 +03:00
Hakan SevenandClaude Opus 4.8 4bcf5063e9 release: v0.8.2
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-14 22:29:21 +03:00
Hakan SevenandClaude Opus 4.8 8fb6c0339d deps: bump acadrust to d1e198b (DXF dimension block_name)
Picks up the DXF fix that reads DIMENSION group code 2, so dimensions
imported from DXF keep their baked *D block and render (their text no
longer drifts vs the DWG of the same drawing).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-14 13:59:57 +03:00
Hakan SevenandClaude Opus 4.8 61502d8c2d deps: bump acadrust to 6365020 (MULTILEADER annotative default false)
Picks up the DXF over-annotative MULTILEADER fix (companion to the MTEXT
one): enable_annotation_scale now defaults false and DXF reads code 293.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-14 13:44:59 +03:00
Hakan SevenandClaude Opus 4.8 64b4560708 deps: bump acadrust to 2af0eb5 (MTEXT is_annotative default false)
Picks up the DXF over-annotative-MTEXT fix: acadrust now defaults
MTEXT.is_annotative to false, so imported DXF MTEXT is no longer flagged
annotative and over-scaled in annotation-scaled viewports.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-14 13:34:28 +03:00
Hakan SevenandClaude Opus 4.8 c0844ad55c feat(annotative): synthesize per-object contexts + editable UI
Make objects genuinely annotative — carrying real per-scale
representations that interoperate with other CAD apps — rather than just
a native flag. `create_annotation_context` synthesizes the extension-dict
chain (AcDbContextDataManager -> ACDB_ANNOTATIONSCALES -> per-scale leaf)
from the entity's placement; the editable Annotative toggle now covers
Text and block references as well as MText/MLeader; and a new
"Annotation Object Scale" dialog (OBJECTSCALE) adds/removes an object's
per-scale memberships. Requires the acadrust ObjectContextData encoder
(Cargo.lock bump).

Also fixes a render bug where objects carrying an *empty*
ACDB_ANNOTATIONSCALES (a single-representation marker with no per-scale
reps) were treated as annotative and (mis)scaled by the annotation factor
in scaled paper viewports, ballooning the text: an object is now
annotative-by-context only when its scale collection is non-empty, so
such objects render at their base geometry.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 22:38:29 +03:00
Hakan SevenandClaude Opus 4.8 d005cc4ab1 feat(props): make dim-line colour editable for leaders and dimensions
The "Dim line color" row on Leader and Dimension entities was
read-only: an earlier attempt wired it to Leader.override_color, which
acadrust never serialises, so the pick was lost on save. Store it
instead as a standard ACAD_DSTYLE per-object dimension-style override
(DXF code 176, an ACI index) through the existing dim_override codec,
so it round-trips through both DWG and DXF like the other dim
overrides. RGB picks collapse to the nearest ACI, matching the rest of
the dim-colour stack (dimension styles are index-only through the file
layer). The renderer prefers the override over the style's DIMCLRD.

The write branch is guarded to leaders and dimensions so a mixed
selection cannot stamp the override onto other entity types.

Bumps acadrust to c9fe982, which carries parsed XDATA onto dimensions
on DXF read (it was dropping common.extended_data), so the dimension
override persists on DXF save as well as DWG.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 17:31:09 +03:00
Hakan SevenandClaude Opus 4.8 0c4272fbb0 chore(release): bump to 0.8.1
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 14:38:56 +03:00
Hakan SevenandClaude Opus 4.8 e378998dc3 chore(deps): bump acadrust — write entity XDATA to DXF
Pulls the acadrust fix that emits XDATA for every entity on DXF save (not
just hatches), so the leader dimension overrides and hyperlinks now
round-trip through DXF as well as DWG.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 01:14:15 +03:00
Hakan SevenandClaude Opus 4.8 15d1bdbdfe chore(deps): bump acadrust — read model-space CANNOSCALE from DWG
Picks up the DWG reader reflecting CANNOSCALE from the AcDbVariableDictionary
into the header, so the status-bar annotation-scale pill shows the drawing's
real model-space scale (e.g. 1:70) instead of the "1:1" default.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-12 19:36:46 +03:00
Hakan SevenandClaude Opus 4.8 d62057b869 feat(properties): show Annotative state + applied annotation scale
Resolve, per selected entity, whether it is annotative (from its text /
dimension / multileader style, or its own flag) and — when annotative — the
name(s) of the annotation scale(s) applied to it, shown as a read-only
"Annotative scale" row (Text / MText / Leader / MLeader).

The applied scale is read from the entity's per-scale object-context leaves
via the new acadrust CadDocument.context_scales map (context leaf ->
AcDbScale handle), walked from the entity's extension dictionary
(AcDbContextDataManager -> ACDB_ANNOTATIONSCALES). Bumps acadrust to pick up
that parsing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-12 19:26:11 +03:00
Hakan SevenandClaude Opus 4.8 208bb099d5 chore(deps): bump acadrust — MLeader/WIPEOUT preview has_ds parse fix (#347)
Pulls acadrust 4ac3d68: entities with proxy/preview vector graphics
(MULTILEADER, WIPEOUT) omit the R2013+ has_ds_data bit, so reading it
desynced the record and produced garbage MultiLeader text_location
(~2e39 → NaN glyphs). The labels now parse with finite locations and
render through the existing MText SDF path.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-12 11:36:33 +03:00
Hakan SevenandClaude Opus 4.8 f3482e8b3e chore(release): bump to 0.8.0
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-11 02:32:06 +03:00
Hakan SevenandClaude Opus 4.8 3c57260ddb fix(thumbnailer-win): make the COM DLL compile on the MSVC target
First real Windows build surfaced errors that a Linux host couldn't catch:

* Enable the missing `windows` feature gates (Win32_System_LibraryLoader,
  Win32_System_SystemServices, Win32_Security — the last brings in the
  `Ex` registry APIs) so the imports resolve.
* Depend on `windows-core`: the `#[implement]` macro expands to
  `windows_core::` paths, which need the crate nameable in the root.
* `IClassFactory::LockServer` takes `Win32::Foundation::BOOL`, not a
  `core` BOOL.
* Name the returned image type via a new `dwg_thumbnailer::RgbaImage`
  re-export instead of a direct `image` dependency.

Verified with `cargo check --target x86_64-pc-windows-gnu -p
dwg-thumbnailer-win` (and the native check still passes).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-11 02:11:22 +03:00
Hakan SevenandClaude Opus 4.8 ba3b3202e8 feat(thumbnails): embed DWG previews and wire cross-platform file thumbnails
Round-trip a raster preview through the DWG's embedded preview slot and
surface it to the OS file managers, so drawings show their contents in
Explorer / Finder / Nautilus instead of a generic document icon.

OCS:
* io::thumbnail — rasterize the scene to a BMP DIB on save (embedded via
  acadrust's new Preview type) and read it back on open for the Start
  page recent list; `--dwg-thumbnail IN OUT SIZE` CLI extracts a badged
  PNG for external thumbnailers.
* io::file_association::install_thumbnailer — self-install the OS
  integration on startup: Linux writes a .thumbnailer + hicolor mimetype
  icons; Windows registers the IThumbnailProvider DLL under HKCU.

Shared core:
* crates/dwg-thumbnailer — lean (image-only) preview extractor + the
  `badge_dwg` full-width "DWG" band, used by every platform so the
  ribbon is single-sourced. Ships an rlib+staticlib.
* crates/dwg-thumbnailer-win — IThumbnailProvider COM in-proc server
  (cfg(windows), CI-built as a workspace member).
* macos/ — QuickLook thumbnail extension (Swift + C-ABI bridge to the
  core staticlib), assembled into a .appex.

Icons & packaging (single SVG source -> per-platform assets in CI):
* assets/mimetypes/image-vnd.{dwg,dxf}.svg — themed file icons.
* packaging: WiX ships dwg/dxf.ico + the thumbnail DLL and points the
  ProgIds at them; Info.plist gets CFBundleTypeIconFile + the QuickLook
  extension in Contents/PlugIns.
* release.yml — generate .ico (Windows) and .icns (macOS) from the SVGs,
  build the QuickLook .appex, and bundle everything.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-11 01:27:17 +03:00
Hakan SevenandClaude Opus 4.8 5c4ba97c5f feat(thumbnail): embed a DWG preview on save, show it on the Start page
Generate a small wire-raster thumbnail when saving a DWG and embed it via
acadrust's preview API, so OCS drawings show a thumbnail in file browsers
and other CAD applications. Read the embedded preview back cheaply (file
header + preview bytes only, no full parse) to show a thumbnail per file
in the Start page's Recent Documents panel.

- io/thumbnail.rs: CPU rasterizer (current-layout wires -> BMP DIB) plus
  a preview-only reader/decoder (BMP/PNG -> iced handle) for the Start
  page.
- Embedded on save via stamp_thumbnail on both save paths.
- recent_thumbs cache filled on config load / recents change (never from
  a view); a thumbnail is drawn beside each recent file.

Requires acadrust at 3111694 (preview read/write), already pinned in
Cargo.lock.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-10 23:03:23 +03:00
Hakan SevenandClaude Opus 4.8 dc7117f203 refactor(config): consolidate settings into one grouped settings.json
App preferences were spread across six flat plain-text files (settings.txt,
recent.txt, recent_limit.txt, statusbar.txt, ribbon.txt, plot.txt), each with a
bespoke line parser and no grouping. Replace them with a single grouped JSON,
serialized via serde (enabling the derive feature; serde_json was already a
dependency).

- New app/config.rs: AppConfig { settings, recent, statusbar, ribbon, plot } →
  <config>/settings.json (pretty JSON), load()/save().
- Make UserSettings, StatusBarConfig/StatusPill, CollapseMode and
  PlotDialogState serde-derived; #[serde(skip)] marks the plot dialog's runtime
  fields so only print preferences persist. Their bespoke .txt load/save is
  removed.
- App gains current_config/apply_config/save_config: one AppConfig::load at
  startup distributes into live state; every settings-change site
  (persist_settings_if_changed, recent add/remove/limit, status-bar pill
  toggle, ribbon density, plot commit) routes through save_config, which diffs
  against the last write to avoid thrashing.
- Clean start: the old flat files are ignored (no migration). ocad.pgp stays a
  separate hand-editable file.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-10 16:41:34 +03:00
Hakan SevenandClaude Opus 4.8 f5b8a7d993 chore(deps): bump acadrust for *Model_Space block-record fix
Picks up acadrust 716d4b4: DWG reader synthesizes the mandatory
*Model_Space/*Paper_Space block records when a file's BLOCK_HEADER for
them never materialised, so model-space geometry is no longer dropped on
save (file shrank + reopened blank).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-10 11:33:40 +03:00
Hakan Seven 3928f1cfa5 chore(release): v0.7.9 2026-07-10 00:17:32 +03:00
Hakan SevenandClaude Opus 4.8 9838cd6d83 fix(dxf): stop writing a duplicate *Active viewport (#319)
Opening a DXF whose active viewport is stored uppercase (*ACTIVE),
editing and re-saving produced a file with two full-window model-space
viewports — the file's own *ACTIVE plus a fresh *Active we add on save.
The reserved viewport name is case-insensitive, so the two didn't
collapse and other CAD apps drew them one on top of the other, which
read as the copied objects being linked / "reacting as one".

save_model_tiles_to_vports dropped existing active viewports with a
case-sensitive `name != "*Active"` filter, so an uppercase *ACTIVE
survived and sat next to the new entry. Route every *Active comparison
(save filter + camera/tile restore) through a case-insensitive
is_active_vport_name helper so the file's record is recognised and
replaced instead of duplicated.

Also bumps acadrust to #99f75fe (merged PR #1): the ASCII DXF writer now
emits shortest round-trippable floats instead of the full 16-digit
expansion, halving the round-tripped file size.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-09 22:36:00 +03:00
Hakan SevenandClaude Opus 4.8 26cab3b712 fix(dxf): bump acadrust for DXF hatch pattern parsing (#330)
Pulls acadrust f1f4dbf, which makes the DXF reader parse hatch pattern
definition lines (and types group code 79 correctly) so custom/dashed
patterns load identically to the DWG instead of collapsing to flat
horizontal lines.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-09 20:42:55 +03:00
Hakan SevenandClaude Opus 4.8 f91e45a62a chore(release): v0.7.8
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-09 00:42:01 +03:00