Commit Graph
411 Commits
Author SHA1 Message Date
Hakan Seven 5b663bfe38 Fix issues found while integrating contributor PRs 2026-09-08 12:14:28 +03:00
JonathanandCopilot 725a7b3e7e Align ByLayer property dropdowns consistently in Properties panel
Use SELECTOR_PAD_V (calculated from ROW_H and FONT_SZ) instead of
hardcoded [3, 6] padding for color selector buttons. This matches the
padding used by combo_box widgets for Lineweight and Linetype,
ensuring all three ByLayer dropdowns align vertically and have
consistent height.

Fixes #1047

Co-authored-by: Copilot <[email protected]>
2026-09-08 09:26:28 +02:00
JonathanandCopilot 8497abecfd Fix ribbon command labels wrapping in the middle of words
Replace Wrapping::WordOrGlyph with Wrapping::Word to prevent labels
like 'Dimensions' from breaking as 'Dimensio' + 'ns'. Word-only wrapping
ensures labels only wrap at word boundaries.

Fixes #1046

Co-authored-by: Copilot <[email protected]>
2026-09-08 08:34:58 +02:00
Hakan Seven d66e89ca19 Complete application localization across all supported languages 2026-09-07 01:05:02 +03:00
gianlucafiore 1b0a42a35c Merge pull request #1022 from gianlucafiore/feat/drawing-cursor-dot
feat(cursor): add point cursor for active commands
2026-09-05 22:52:00 -03:00
gianlucafiore 5bca05d913 feat(cursor): add point cursor for active commands 2026-09-05 22:39:34 -03:00
Karim Jerbi 0dab3ec54a feat: add COMMANDLINEFADETIME sysvar for overlay history fade
Controls how long command-line history lines stay visible, in ms (0-60000, default 3000). Bare form stays active until a value or Esc.
2026-09-06 02:13:09 +01:00
Hakan Seven 13afc1479f Automate weekly releases and synchronize application versions 2026-09-05 02:13:20 +03:00
Hakan Seven 17e5cda3fb Tighten MCP command line control 2026-09-04 23:38:46 +03:00
Hakan Seven d7c3422dbe Space MCP control from command line edge 2026-09-04 23:30:26 +03:00
Hakan Seven 071e224d26 Add client-neutral native MCP control 2026-09-04 23:27:03 +03:00
Hakan Seven 28cc473062 Add persistent live OpenCADStudio control 2026-09-04 22:25:55 +03:00
Karim Jerbi a9fda66ac0 fix(ui): add non-color marker to CLI info entries and drop dead desk parameter
- Add 'i  ' prefix to EntryKind::Info and coordinate set_step_prompt deduplication to satisfy WCAG 1.4.1 across all 22 themes
- Drop unused _desk parameter from crosshair_background and clean up its call sites
- Document AutoCAD-standard context-based crosshair drafting surface architecture in crosshair_background
- Add doc comments documenting deliberate alpha omission in canvas_is_light and backlog scope in is_wide
2026-09-04 16:26:13 +01:00
Karim Jerbi b53cd580f6 feat(ui): shared dropdown popup width calculation with wide-character support
- Add dropdown_popup_width helper in common.rs replacing magic formula heuristics
- Implement is_wide range table to count East Asian Wide/Fullwidth (CJK) glyphs double for localized strings
- Calibrate unit scale factor to 0.68 * font_size preserving existing width behavior at font size 11
- Apply shared calculation across viewport controls and ribbon dropdowns
- Update unit tests to verify width calculation on standard and CJK labels
2026-09-04 16:26:12 +01:00
Karim Jerbi a7e3cf3a6d fix(ui): enforce WCAG AA contrast thresholds across UI themes
- Raise accessible_accent default threshold from 2.0 to 3.0 (WCAG 1.4.11 UI state indicators)
- Raise EntryKind::Info command line history threshold from 3.0 to 4.5 (WCAG 1.4.3 normal text)
- Update themed_check_cell to verify >= 3.0:1 contrast across both weak popup panel and strong highlighted rows
- Replace fully-qualified accessible_accent_threshold calls inside closures with use imports
- Add comprehensive 9-suite theme accessibility contrast test suite covering all 22 themes across core surfaces
2026-09-04 15:34:24 +01:00
Karim Jerbi 23a9884f90 fix(ui): canvas-aware selection colors and paper space detection
- Add canvas_is_light helper based on WCAG luminance (> 0.5)
- Ensure crosshair_background always returns sheet white in paper space
- Update resolve_selection_base_color to resolve user ACI -> light-canvas palette -> theme palette
- Add light_canvas_color with curated deep-green/deep-blue pairs for light surfaces
- Extract selection_fill_alpha with 1.35x contrast compensation on light surfaces
- Thread canvas_bg through draw_marquee and poly selection
- Note deliberate limitation for desk-spanning marquee edge case
- Add test coverage for paper space, ClassicDark, custom light bg, and fill alpha clamping
2026-09-04 15:28:25 +01:00
Karim Jerbi 688785a6cf feat(model-space): theme-aware model space canvas and CAD selection/grip sysvars
Model space appearance now follows the active UI theme instead of a
hardcoded dark background. Canvas mode is user-selectable (Match Theme /
Classic CAD Dark / Custom RGB), with matching controls for the paper
sheet and desk surround backgrounds and grid opacity.
Implements industry-standard CAD system variables, all settable via
command name, SETVAR, and the Options dialog:
- COLORTHEME (0/1 dark/light UI scheme, preserves custom palettes)
- COLORSCHEME (interactive named-theme selection)
- BACKGROUND (THEME/CLASSIC/DEFAULT/DESK presets, RGB triplets)
- SELECTIONAREA, SELECTIONAREAOPACITY (translucent marquee fill)
- WINDOWSAREACOLOR/WINDOWAREACOLOR, CROSSINGAREACOLOR (ACI or theme)
- SELECTIONEFFECT, SELECTIONEFFECTCOLOR (GPU highlight pass, driven by
  selection_generation invalidation — no retessellation)
- SELECTIONPREVIEW (bit 0 = idle rollover, bit 1 = in-command hover)
- GRIPSIZE, GRIPCOLOR, GRIPHOT, GRIPHOVER (grip overlay styling)
2026-09-03 17:44:44 +01:00
NgoQuocViet2001 074e589ce8 fix(dimension): render DIMAUNIT 4 as a surveyor's bearing
DIMAUNIT 4 is Surveyor's units, but format_angular_value matched only
0-3 and let 4 fall through the catch-all to decimal degrees. An angular
dimension in a drawing authored with surveyor units therefore read as
plain degrees, while AUNITS 4 in the same drawing writes a bearing for
the coordinate readout — the two disagreed on one angle.

Format the bearing from the dimension's own DMS path so it carries
DIMADEC, DIMAZIN and DIMDSEP, quantise before picking the quadrant so a
value just short of a cardinal does not quote a quarter turn, and offer
the option in the dimension-style dialog.
2026-09-03 15:23:42 +07:00
Karim Jerbi 46190ccba1 refactor(selection): migrate Scene.selection to Arc<RefCell> to avoid per-frame deep clone
Scene.selection was Rc<RefCell<SelectionState>> (31 fields, ~1.6KB
with poly_points) cloned deep per view_main per pane via
(*sel_ref).clone() at view/mod.rs:760. Replace with
Arc<RefCell<SelectionState>> (Arc::new(RefCell::new(...)) at
scene/mod.rs:1436,1868), SelectionCanvas holds Arc<RefCell> and
selection_overlay takes Arc<RefCell> (overlay.rs:365,415),
view_main does Arc::clone(&tab.scene.selection) (atomic bump)
instead of deep clone. sel_ref stays borrowed for field reads
(vp_size etc.).

Bench (release, n=5000): SelectionState::clone 39-68ns (64pts) /
11-22ns (0pts) vs Arc::clone 7ns — 5-9x on the hot path.

Tests:
- selection_is_arc_not_refcell: asserts type_name contains Arc
- bench_selection_state_clone / bench_selection_arc_clone / bench_selection_state_clone_empty (ignored, release)
2026-09-02 22:14:32 +01:00
Hakan Seven 76bdab1e5b feat(display): add model lineweight scale 2026-09-02 23:03:04 +03:00
Hakan Seven 0f337db488 Keep rotation prompt visible with arc label 2026-09-02 22:02:10 +03:00
Hakan Seven 7edf268eef Keep rotation angle label on guide arc 2026-09-02 21:53:29 +03:00
Hakan Seven 947ff94015 Keep dynamic angle input near cursor
Anchor angle boxes to the screen-space cursor and flip them at viewport edges while preserving the geometric guide.

Fixes #966
2026-09-02 21:32:37 +03:00
Hakan Seven 93b441d4b8 Unify mixed color selection
Use the shared color selector for mixed property values and remove the legacy inline palette and its state.
2026-09-02 21:28:15 +03:00
Hakan Seven 8c9ef80b90 Fix color palette width
Make palette rows fill the available panel width while reserving an embedded scrollbar lane. Keep the final row aligned with the 16-column grid.\n\nFixes #968
2026-09-02 21:17:53 +03:00
Karim Jerbi 50cb21e4d4 refactor(ribbon): make StyleContext borrowed to avoid 8 clones per view
Replace the 8 owned clones in StyleContext construction (4 Vec<String>
+ 4 String) at ribbon/mod.rs:568 and :1059 with borrowed refs.
StyleContext is now StyleContext<'a> with &'a [String]/&'a str
(widgets.rs:313), RenderCtx holds &'a StyleContext<'a> (:633),
and call sites pass &self.x instead of .clone(). The view-local
borrow is valid for the duration of Ribbon::view() and the style
dropdown overlay.

TDD: RED style_context_tests failed E0308 (owned vs borrowed),
GREEN added lifetime and updated 4 type sites + 2 construction sites.
2026-09-02 18:20:29 +01:00
Karim Jerbi bdedcf63fc refactor(style): dedup muted_style into ui::style::common
Centralize the 7 byte-identical `muted_style` helpers (alpha 0.68)
previously duplicated across src/ui/style/* into a single
`src/ui/style/common.rs::muted_style` (+ alias `muted_text_style`).
All 7 style windows and the style_manager wrapper now call the
common helper, ensuring a theme palette change updates one place.

`btn_s` is intentionally NOT deduped: plotstyle.rs:41 and
style_manager.rs:299 have divergent bodies (Disabled handling +
text alpha 0.45). Unifying would silently change plotstyle
disabled appearance :  documented in common.rs and covered by test.

TDD: RED `common_tests` failed E0433 (missing common), GREEN
added common.rs and wired `pub mod common`, REFACTOR replaced
locals with `use crate::ui::style::common::muted_style`.

Tests:
- common_muted_style_matches_local_copy: asserts common output equals 0.68 alpha reference
- common_muted_text_style_alias_matches: alias identity
- btn_s_bodies_documented_as_divergent: documents intentional non-dedup
2026-09-02 16:43:57 +01:00
Karim Jerbi afff1a40dd feat(ui): add press-to-capture shortcut editing to Keyboard Shortcuts dialog
Replace manual key entry with per-row capture cells: clicking + Add
inserts a draft row at the top with its key cell armed, and the next
key combination is recorded and normalized (Ctrl+Shift+S →
CTRL+SHIFT+S). While armed, a dedicated keyboard listener swallows all
input so recorded shortcuts do not execute in the drawing.

Draft rows are transient and confirmed only through an explicit accept
button, so the table never retains empty rows. Duplicate keys and
unrunnable commands are flagged in danger styling with a persistent
warning naming the conflicting command. Added reset-to-defaults with
confirmation, apply-and-exit, a shortcut count, and an unsaved-changes
guard on close.
2026-09-01 12:17:47 +01:00
Hakan Seven 6d6defa0ad fix(color): show color book identity 2026-09-01 08:44:28 +03:00
ramox81 9d947d75c5 Align polygon mesh properties 2026-08-31 10:13:12 +03:00
gianlucafiore b7aed86d48 fix(ui): restore context menu actions 2026-08-31 00:22:54 -03:00
Karim Jerbi 166d758820 fix(ui): stabilize themed cache keys with static byte slices and harden tests
The themed handle cache (introduced in cc430cdb) keys entries by (address, length) of &'static [u8] art. However, the art was declared as const; Rust may inline distinct copies of a const at each use site, giving the same logical icon different addresses. This broke cache lookups for wrapper functions (e.g., themed_arrow_down) that refer to the same icon from a different module than the cache test. Convert the ~30 themed-relevant byte slices (TRI_*, HOME, UNDO, REDO, CHECK, etc.) to static so each artwork has one stable address process-wide.

Also refactor themed_handle to drop the immutable borrow before building a miss handle, preventing a reentrant call from panicking on a second borrow_mut.

Adjust themed_cache_tests to use delta assertions and per-test cache removal for isolation, and add coverage for second-call cache hits, wrapper delegation, and the length component of the key.

Test: ui::icons::themed_cache_tests::themed_cache_returns_same_handle_for_same_bytes
Test: ui::icons::themed_cache_tests::themed_cache_caches_distinct_bytes_separately
Test: ui::icons::themed_cache_tests::themed_cache_second_call_is_a_cache_hit
Test: ui::icons::themed_cache_tests::themed_wrapper_populates_cache_for_underlying_bytes
Test: ui::icons::themed_cache_tests::themed_cache_key_includes_length
Test: ui::icons::themed_cache_tests::themed_cache_speedup_over_uncached_handle_creation
2026-08-30 00:36:04 +01:00
Hakan Seven 5062c26c88 Merge pull request #931 from schoeller/rustc_plugin_gate
feat(plugins): include rustc version in plugin compatibility gate
2026-08-29 15:55:04 +03:00
Hakan Seven 466ab99c63 fix(plugins): enforce rustc compatibility
BREAKING CHANGE: API v4+ plugin packages must declare the exact rustc version used to build the binary.

Refs #901
2026-08-29 15:54:41 +03:00
Karim Jerbi 6bf84d8f5e feat(ui): show color swatch and layer in selection cycling popup
Improve the selection-cycling list box so overlapping objects can be
identified at a glance:

- Add a color swatch per row showing the object's effective drawn color
- Show the layer name right-aligned next to the element type
- Size the popup to fit its content with consistent padding

Widen render_style_for_viewport visibility from scene-internal to
crate-wide so the view layer resolves the same color the renderer uses.
2026-08-29 12:31:03 +01:00
Karim Jerbi 452749f58c fix(ribbon): align combo panel dropdowns to a shared baseline
Style selectors (Standard, layer, Color/Linetype/Lineweight) sat at
different heights across ribbon panels because each combo panel
vertically centered its content: panels with fewer icon rows
(Multiline Text, Table) centered their dropdown differently than
panels with two rows (Dimensions, Multileader).

- Pin all combo panels (Layers, Properties, style combos) to the top
  of the fixed 3-row panel with a shared COMBO_PANEL_PAD, so every
  primary dropdown shares one baseline regardless of icon-row count
- Extract the duplicated tool-row and panel-container code into
  tool_row() / combo_panel_col() helpers + named spacing constants
- Bundle the per-view render state into RenderCtx, shrinking
  render_large/render_large_dropdown from 12-14 positional args to
  (item, &ctx)
- print_to_printer: silence the Windows-only dead-code warning on
  PrintOptions::quality with the platform split documented (the field
  is read by the CUPS `lp -o print-quality` path)
2026-08-29 11:35:06 +01:00
Hakan Seven 0237652963 style(icons): unify theme-aware palette 2026-08-29 12:20:24 +03:00
Sebastian ed3e064a47 feat(plugins): include rustc version in plugin compatibility gate
OpenCADStudio/plugins#901

- Record the host's rustc --version output in the embedded version_info.json.
- Add rustc_version/rustc_declared/rustc_compatible to plugin manifests and
  release metadata, mirroring the existing acadrust gate.
- Reject API v4+ plugins whose declared rustc differs from the host, with a
  clear one-line error message.
- Propagate the rustc gate through the marketplace, install flow, and UI.
- Update plugin architecture docs to describe the new ABI metadata.
2026-08-29 10:34:47 +02:00
Hakan Seven 3024869de0 fix(i18n): localize linetype inheritance 2026-08-29 10:10:39 +03:00
Hakan Seven 8dd3eb897b fix(properties): embed scrollbar lane 2026-08-28 21:05:26 +03:00
Hakan Seven 6da2685e13 chore(properties): integrate main 2026-08-28 19:48:12 +03:00
Hakan Seven 50e5dcaaac fix(polyline): correct 3D smoothing 2026-08-28 19:46:13 +03:00
Hakan Seven ff1f873633 fix(mleader): repair creation and editing 2026-08-28 19:36:48 +03:00
ramox81 1cc7d3cb67 Prevent properties scrollbar overlap 2026-08-28 11:54:37 +03:00
ramox81 3ca959a34b Fix 3D polyline behavior and properties 2026-08-28 11:21:03 +03:00
Karim Jerbi cc430cdbe9 perf(ui): cache svg::Handle in themed* icon functions
The 9 themed* functions that take &'static [u8] artwork each built a
fresh svg::Handle::from_memory(bytes) on every call, with 113
icons::themed call sites per frame across ribbon/statusbar/popups.
Add a thread_local THEMED_CACHE keyed by the bytes' (address, length)
and a single themed_handle(bytes) helper; the 9 themed* functions all
go through it. The 13 wrapper functions (themed_arrow_*, themed_home,
themed_undo, themed_redo, themed_check_cell, ...) delegate to those 9
and pick up the cache transparently, so all 22 themed* functions (and
the 113 call sites) are deduped.

The cache key is (address, length) -- not pointer alone -- to match the
existing SEMANTIC_CACHE belt-and-braces pattern and guard against any
future call site that passes a sub-slice of a static (e.g. &BYTES[1..]),
which would otherwise alias the wrong handle. Every include_bytes!
produces a unique static slice today, so the length is defensive.

Construction is amortised to once per artwork per process. No semantic
change; visual output is byte-identical.

Measured performance gains (integrated
themed_cache_speedup_over_uncached_handle_creation bench, 20_000
iterations each, same machine):

  |                | dev profile   | release profile |
  |----------------|---------------|-----------------|
  | Before         | 235 ns/iter   | 26 ns/iter      |
  | After (cached) |  78 ns/iter   |  9 ns/iter      |
  | Cold miss      | 900 ns        | 100 ns          |
  | Speedup        | 3.0x          | 2.9x            |

Release-mode warm path: 9 ns/iter. At 60 fps with up to 113 themed*
calls per frame, that is ~1 us/frame of handle work -- a rounding
error against a 16.6 ms frame budget. The cold-miss cost (one parse
+ one insert, 100 ns release) is the one-time price per new artwork
and is amortised to negligible per-frame overhead (it happens at
most once per artwork per process). The speedup is stable at ~3x
across dev and release because the ratio of work is the same:
hashmap-get + Handle clone vs. a full SVG parse + allocation.

test ui::icons::themed_cache_tests::themed_cache_returns_same_handle_for_same_bytes
test ui::icons::themed_cache_tests::themed_cache_caches_distinct_bytes_separately
test ui::icons::themed_cache_tests::themed_cache_speedup_over_uncached_handle_creation
2026-08-28 06:05:31 +01:00
ramox81 cce25be83a Complete multileader creation and property behavior 2026-08-27 17:35:47 +03:00
Karim Jerbi 513ab958a8 perf(grid): cache overlay geometry behind a params-keyed key
Introduce a cache for the grid overlay to prevent redundant geometry
reconstruction on every UI redraw. Extract the pure projection logic
from draw_grid into a renderer-free grid_segments function, and add
GridKey and GridCanvasState to memoize the resulting Geometry.

The cache key includes all per-pane GridParams and the overlay bounds,
preventing stale geometry when camera changes within the same canvas
size. On a params-key miss, the iced cache is cleared before redrawing
to bypass its bounds-only reuse.

Tests: 8 new unit tests cover key invalidation and state handling.
Benchmarks: uncached geometry ~32 us/frame vs cached decision ~90 ns,
a >99% reduction. Verified: 472 passed / 1 pre-existing failure / 4
ignored.

Tests:
  ui::overlay::grid_key_tests::grid_key_matches_identical_params
  ui::overlay::grid_key_tests::grid_key_invalidates_on_changed_fields
  ui::overlay::grid_key_tests::grid_key_invalidates_when_any_pane_changes
  ui::overlay::grid_key_tests::should_reuse_empty
  ui::overlay::grid_key_tests::should_reuse_equal
  ui::overlay::grid_key_tests::should_reuse_changed
  ui::overlay::grid_canvas_state_tests::default_state_has_no_cached_key
  ui::overlay::grid_canvas_state_tests::stored_key_is_recognized_by_should_reuse
2026-08-26 23:53:31 +01:00
Hakan Seven 81e7add1dd fix(tolerance): complete workflow integration
Sync current main and companion codec changes before preserving unsupported frame rows, rendering in the entity plane, and sharing final layout metrics with placement preview.
2026-08-27 00:14:08 +03:00
ramox81 de294447a9 Complete geometric tolerance workflow and properties 2026-08-26 13:54:20 +03:00