Commit Graph
414 Commits
Author SHA1 Message Date
Felix RiestraandClaude Sonnet 5 7cddf31bcb Add named parameters, UI scale setting, OPTIONS/OP dispatch, and help manual
Named parameters (docs/named_parameters_design.md, stages 3-4):
- ParameterTable (src/scene/named_parameters.rs): a document-wide table of
  named formulas, each resolved through a shared expression evaluator with
  cross-parameter references, cycle detection, and division-by-zero/parse
  error reporting. SketchConstraint::driving_param becomes DrivingValue
  (Literal | Named) instead of a bare f64, resolved at solve time by
  sketch_solve::build_constraint via Scene::named_parameters.
- Persistence (src/scene/named_parameters_persist.rs): same lazy XRecord
  model sketch_persist.rs already established, synced around open/save.
  Bumps the sketch-constraint XRecord's own format version (1 -> 2) since
  DrivingValue's shape doesn't line up with a version-1 blob's bytes.
- PARAMETERS command and its editor (src/ui/window/named_parameters.rs):
  add/remove/edit rows, live validation, duplicate-name detection: Apply
  defines the table and re-solves every constraint scope with a
  named-parameter-driven constraint (command_driver.rs). Distance/Angle
  constraint prompts (modules/draw/constrain/value.rs) now accept either a
  literal or an existing parameter's name, mirroring how the constraint's
  own value prompt already worked.
- Undo scope-down carried over from this project's own established pattern
  (constraint-system stage 9): the geometry an Apply moves is one undo
  step, but the parameter table edit itself has no undo entry yet — a
  documented follow-up, not a silent gap.

UI scale setting (src/app/settings.rs, app/mod.rs, ui/window/options.rs):
  a whole-interface scale percentage (50-200%), wired directly into iced's
  own per-window scale_factor hook rather than per-panel font-size
  plumbing, so it applies immediately to every panel, dialog, and the
  ribbon at once. Persisted alongside the existing lineweight-display-scale
  setting.

OPTIONS/OP command dispatch (app/commands/view.rs, app/commands/mod.rs):
  OPTIONS was registered for autocomplete but had no dispatch arm — the
  Start-tab welcome screen's own button was the only way to reach it.
  Found live-testing the UI-scale setting, unrelated to that feature
  itself. "OP" is AutoCAD's own short alias.

help/: a new self-contained static user-help manual (manual.md as the
authored source, tools/build_help.py splits it into the committed static
HTML pages plus search index) — not yet wired into the application.

64 new/updated tests across the named-parameters and constraint-prompt
changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 13:50:08 +02:00
Felix Riestra e2d39b049d Merge branch 'main' into feature/parametric-constraint-system
# Conflicts:
#	src/app/automation.rs
#	src/app/mod.rs
#	src/ui/ribbon/widgets.rs
2026-09-09 13:35:07 +02:00
Felix RiestraandClaude Sonnet 5 63a74b19a9 Add persistent sketch-constraint system (ocs_gcs port) and named-parameters handoff docs
Ports FreeCAD's planegcs 2D geometric constraint solver to Rust as a new
crates/ocs_gcs workspace member, and wires it into the document/scene model
as a persistent SketchConstraintSet: Coincident, Horizontal/Vertical,
Parallel/Perpendicular, Equal, Tangent, Distance, Angle and Radius
constraints that re-solve live (including mid-drag, not just on release),
render glyphs and a DOF badge, flag conflicts with a one-click resolver
pill, and round-trip through save/load via an XRecord blob.

Also includes docs/command_reference.md (a statically generated reference
of every registered command and its prompt sequence) and
docs/named_parameters_design.md + docs/backlog.md, which hand off the next
queued feature (a named-parameter/expression table) and consolidate every
deliberate scope-down and open gap found along the way, so a fresh session
has a complete starting point.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 22:19:23 +02:00
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 <223556219+Copilot@users.noreply.github.com>
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 <223556219+Copilot@users.noreply.github.com>
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