Commit Graph
47 Commits
Author SHA1 Message Date
Claude 44f8f76ab3 Merge main into codex/graphic-attributes-cleanup
Resolve conflicts from main's rustfmt pass by taking main's versions of
command.rs, style.rs, view/mod.rs, scene/mod.rs, ui/window/mod.rs and
ui/properties.rs and re-applying this branch's Graphic Attributes changes.
Add the Graphic Attributes strings to the new lo-LA catalog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E1QnME6WJbD5iGFae1eeCb
2026-10-11 19:09:37 +00:00
Claude 2fca3fd18d Merge main into Pallet-placement
Resolved conflicts:
- app/update/mod.rs: keep the dock's dock_open_at_default for the XREF
  manager; take main's stable xref row identity (row_index(&id)).
- app/view/mod.rs: keep the edge layout from app::dock; drop main's copy
  of the old edge-stack code (main only reformatted it there).
- ui/window/layers.rs: keep main's new visible_indices next to the
  branch's view_panel.
Files the branch only reformatted take main's version. Adds the Lao
(lo-LA) translations for the new dock texts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-11 18:44:00 +00:00
Claude bf1c4ddc74 style: apply cargo fmt across workspace (as on main)
Formats the branch the way main's 9cf9ff2 did, so merging main only
conflicts where the code itself differs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-11 18:29:37 +00:00
Claude cc17d10ca9 Dock: drop dead pallet-width setters, split on_dock, share span maths
- Only docked pallets have a width divider, so the Width drag and
  WidthReset no longer carry a branch for an undocked pallet; remove the
  then unused DockState::set_width / reset_width. Per-pallet widths are
  still read (older configs, floating size). Tests now size groups.
- on_dock hands hover messages to dock_hover and the release to
  dock_drag_release.
- dock_slot_spans and dock_landing share dock_open_spans.

No behaviour change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-10 12:34:02 +00:00
Claude 02404301a5 Dock: review cleanups - hover pending enum, FloatFrame, comment fixes
- dock_hover_pending is an Option<HoverPending> (Reveal / Hide) instead
  of a nested Option.
- dock_float_frame returns a FloatFrame with width() and bar_x(), so the
  floating menu no longer repeats the frame-width formula.
- Put dock_reveal's doc comment back on dock_reveal, and the group-move
  comment back above the match it describes.

No behaviour change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-10 11:55:23 +00:00
Claude 2135dd499a Dock: floating windows hold one pallet again
Remove floating groups: a floating window is a single pallet once more,
and the Pallets submenu is gone from its title-bar menu. Kept: the menu
opens at the pointer with Allow docking, Dock left and Dock right;
close / pin show only while the bar is hovered; content is clipped to
its frame. A config saved by the floating-group build still loads, its
windows floating their first pallet. Drops the unused Pallets string.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-10 11:32:51 +00:00
Claude 75fb9e32dd Dock: floating menu at the pointer, hover-only bar buttons, Allow docking, clip pallets
- The floating title bar's right-click menu opens where the pointer is,
  flipped to stay on screen; the Pallets submenu sits beside it.
- Close and pin on a floating title bar only show while it is hovered,
  as on docked title bars.
- New Allow docking check in that menu: off, dragging the window (or a
  pallet out of it) only floats it, never docks it on an edge.
- Floating windows and stacked pallets clip their content, so a pallet
  sized below its content no longer draws outside its frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-10 11:18:42 +00:00
Claude f19948bc07 Dock: floating groups, floating title bar menu, translations
- A docked group floats as one window: drag its edge band over the
  drawing or double-click the band. Floating windows hold a stack of
  pallets with splitters; the vertical title bar shows each pallet's
  icon (press one to drag that pallet out). Dragging the bar moves the
  whole window; dropping it on an edge docks or joins it as a group.
- Right-click a floating title bar: Pallets submenu (add or hide
  pallets in the window), Dock left, Dock right.
- Close on a floating bar closes every pallet in the window; its pin
  sets auto-hide for the whole window.
- Older configs with single floating pallets still load.
- Translate the new dock texts (Auto-hide, Dock left/right, New group,
  Pallets, Browser, Node Graph) in all 21 languages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-10 10:40:55 +00:00
Claude 4e210f65b5 Dock: LAYERS opens its pallet like Insert Block, Layer Manager layout fixes, 150 ms auto-hide hover delay
- LAYERS ribbon button runs a command that opens the Layer Manager pallet;
  the ribbon no longer keeps it highlighted.
- Layer Manager: search box stays right-aligned, the column header fills
  the row, no stray contour lines when the pallet is taller than its rows.
- Auto-hidden edges don't show the shown-group accent bar.
- Auto-hide reveal and hide wait 150 ms of rest, so passing over the
  strip doesn't flash groups open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-10 10:22:47 +00:00
Claude b12a29b233 Dock: review fixes - hover, preview width, stale indexes, config healing
Fixes:
- Hover state no longer drops when the pointer moves up from one strip
  icon, group grip or title bar to the one above: iced handles the
  element above first, so the old element's "left" (None) cleared the
  hover just set. Leave messages now carry the element and only clear
  their own hover.
- The drop preview used the pallets' own widths; it now uses the
  group's width, matching where the pallet lands.
- Group indexes from messages (group grab, splitter) are looked up
  safely, so a message from before a layout change no longer panics.
- Floating placements read from the config are healed (finite, positive,
  at least the minimum size), like the group weights already were.
- The shown group's edge bar is centred in its row: a stack takes its
  height from its first layer, and the icon column was shorter than the
  row. The "Drag to move group" tooltip is removed.

Simplifications (no behaviour change):
- dock_open_at_default / dock_unpeek replace seven copies of "dock on
  the right if unplaced, then reveal" and four of "stop peeking".
- The drop target takes the grab offset as a parameter, so a drag
  update stores its state once.
- dock_set_open, ensure_settings, the shown-index bookkeeping after a
  group is removed and the on-screen width clamp each lose duplication.
- VBarLabel drops options its single caller never varied.
- The drop preview's landing computation is one helper.

Naming and consistency: pallet names in the + menu, the drag ghost and
the floating title bar go through t!(); StripHit::Tab becomes
StripHit::Join; stale comments updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 20:53:42 +00:00
Claude 7448472291 Dock: move app-side dock code into app::dock, trim tests, drop icon tooltip
- The dock's state handling and drawing move out of update/dialog.rs and
  view/mod.rs into src/app/dock/ (update.rs, view.rs, tests.rs). The
  overlay view_main stacked over the workspace (floating pallets, + menu,
  drag preview, pointer capture) becomes one `dock_overlay` call. Code is
  moved, not changed.
- Strip icons no longer show the pallet name on hover.
- Tests trimmed where they overlapped: the top / bottom half drops are
  one test, the two hover tests are one, and the in-group icon reorder,
  raise-float, empty floating title bar and slot-span tests are dropped
  (each is covered by another test).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 20:25:34 +00:00
Claude 4db24b3bbd Dock: simplify drag, peek, width and open/close state
No intended behaviour change except the fixes noted below.

- One drag state: a single `DockDrag` (move pallet / group, width,
  splitter, floating size, Layer Manager column) replaces nine fields
  (dragging, dragging group, resizing, split, float resizing, origin,
  target, grab offset, layer column flag) that had to be kept in sync.
- `dock_expanded` becomes `dock_peek` with one meaning: a pallet revealed
  although it auto-hides. `dock_reveal(id)` shows a pallet's group and
  peeks it; commands that open a pallet now use it, so opening a pallet
  also switches its edge to that pallet's group.
- Each group stores its own width (falling back to its widest pallet's
  width until first sized), instead of every pallet's width being kept in
  sync. Pallet widths now only size floating pallets and new groups.
- One `dock_set_open(id, open)` holds every pallet's open and close path.
- Leftovers removed: the tab-group config format that never reached main,
  the multi-tab drag ghost header, the separate icon-hover message.

Fixes:
- Hovering a strip icon reveals an auto-hiding edge again (the icons had
  lost the hover message in the option B strip). Covered by a test that
  moves the pointer over the icon in the real view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 20:15:09 +00:00
Claude 6c00b8bc91 Dock: fix double-click on title bars, centre the strip bar, close + menu
- Double-clicking a docked or floating title bar did nothing. iced keeps
  a widget's state (including the first click of a double-click) only
  while the widget tree keeps its shape, and pressing a title bar starts
  a possible drag that wrapped the workspace in an extra pointer-capture
  layer, rebuilding the title bar and forgetting the first click. The
  workspace is now always inside the same stack and mouse area; the
  capture handlers are only attached while dragging. A test drives the
  real view through iced's UserInterface (keeping its cache between
  events, as the runtime does) and fails without this fix.
- The shown group's edge bar was shorter than its row (the tooltip
  around the edge band sized it to its content), so it looked off
  centre. Band and bar now have explicit heights.
- Picking a pallet in the + menu closes the menu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 20:03:15 +00:00
Claude 96b4479f58 Dock: option B icon strip with an edge-band group grip
The icon strip follows the agreed "option B" concept:

- Flat 40 px strip; groups are rows of their pallets' icons separated by
  hairline dividers, with no grip lines. The + button is a small round
  button under the last group.
- The shown group is marked by a blue bar on its window-side edge and
  brighter icons. That 8 px edge band is the group grip: hovering it
  widens and lights the bar, tints the row, shows a grab cursor and a
  "Drag to move group" tooltip; dragging it moves the whole group.
- Icons still drag single pallets: within their group or into another
  group (between its icons), or onto a divider to start a new group.
  Hovering an icon gives it a soft background and shows its name.
- Drop feedback: a short accent line with end caps between icons means
  "join this group here" (the target group's bar lights up); a
  full-width line on a divider with a "+ New group" badge means "new
  group here". The dragged icon (or whole group) fades in place and a
  ghost follows the pointer.
- The zone around a divider (a few px into the icons on either side)
  starts a new group; the lower half of a group's last icon still joins
  that group at the end.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 19:46:27 +00:00
Claude 77ddc59df3 Dock: fix crash dragging a pallet that is alone in its group
Dragging a pallet over its own group (e.g. the block palette, alone on
the right edge) targeted joining that group. Joining first detached the
pallet, which removed the now-empty group, then indexed it: an
out-of-bounds panic, hit already by the live drop preview. A pallet alone
in the group it would join now just stays put.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 19:29:37 +00:00
Claude 258762f992 Dock: auto-hide per edge, hover only flies out when auto-hiding, menu per edge
- Auto-hide is a setting of the left / right edge rather than of each
  pallet: the pin on any docked pallet turns it on for its whole edge,
  which then shows only its icon strip until an icon is hovered. A
  floating pallet keeps its own auto-hide.
- Hovering the strip icons only shows a group while the edge auto-hides;
  otherwise groups switch on click.
- The + menu checks only the pallets open on that edge. Picking one that
  is open elsewhere (the other edge, floating) moves it to this edge;
  unchecking a checked one hides it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 17:44:52 +00:00
Claude 47c2e2f2fe Dock: one group per edge at a time, pallets stacked within a group
A group is now a set of pallets shown together, stacked top to bottom,
and an edge shows one group at a time. The icon strip lists every group
(grip bar over its pallets' icons, the shown group on a grey
background); clicking any icon of a group shows that whole group.

- Dropping a pallet on the top / bottom half of a pallet in the shown
  group stacks it above / below; dropping on the strip's icons places it
  in that group at that spot, and on a grip or below the last group
  starts a new group (which is then shown).
- Splitters set the heights of the pallets within a group; double-click
  makes them equal again.
- Each group keeps its own width; the divider sizes only the group it
  belongs to, and switching groups switches width.
- A group whose pallets all auto-hide shows only while hovered.
- Layouts saved by older builds load with their stacked pallets as one
  group.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 17:30:00 +00:00
Claude f038fcc9a1 Dock: Photoshop-style vertical icon strip for docked groups
Each dock edge now has a vertical icon strip along the window edge in
place of the horizontal tab row and the auto-hide rail.

- Every shown group gets a grip bar with its pallets' icons below it;
  the shown pallet's icon has a grey background. Clicking an icon shows
  that pallet in its group; hovering the icons of an auto-hiding group
  opens it.
- Dragging an icon within the strip reorders it or moves it into
  another group; dropping it on a grip or below the last group makes it
  a new group there. On the pallet area, the top / bottom bands still
  start a new group above / below and the middle joins the group.
- Dragging a grip moves the whole group to another position or edge.
- A + button under the groups opens the pallet menu (icon, name, check
  mark). Opening a pallet from it docks it on that edge as a new group,
  or in its existing group there; a checked pallet is hidden.
- Groups keep their width when moved; the divider against the viewport
  sizes the whole edge column.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 16:01:31 +00:00
Claude 1176789125 Dock: tab row only for tab groups, larger plain icon tabs, working menu
- The tab row shows only when at least two pallets share a slot.
- Tab icons are larger (18 px). The shown tab gets the grey background
  without a border; other tabs have no background.
- The pallet menu was drawn by a dropdown that squeezed it to one icon
  wide. It is now its own overlay hanging under the menu button, laid
  out like the right-click menu: pallet icon, name, and a check mark on
  the right for the pallets shown in this slot. Any click outside closes
  it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 15:34:02 +00:00
Claude 09e4792a0a Dock: Layer Manager pallet, double-click to float / dock
- LAYERS opens the Layer Manager as a dockable pallet instead of a modal
  dialog with a darkened backdrop. It floats over the middle of the
  drawing the first time and keeps its place after that; LAYERS again
  (or its close button) hides it. The table keeps its natural width and
  scrolls sideways when the pallet is narrower, and the Name column
  divider now drags through the dock's pointer capture. Ctrl+A selects
  all layers while a layer row is selected in the open pallet.
- The Layer Manager is listed in the tab-row pallet menu like the others.
- Double-clicking a docked title bar floats the panel beside its edge;
  double-clicking a floating title bar docks the panel on the side its
  title bar faces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 15:24:33 +00:00
Claude 1f3fae6d1e Dock: icon tabs with a pallet menu, wider stacking zones
- Dropping on a docked pallet now stacks it above or below over the top
  and bottom 35 % of the slot; only the middle 30 % makes it a tab.
- Tabs show the pallet icon (title as tooltip), aligned to the left.
  Every docked slot has the tab row, so its menu is always reachable.
- A menu button at the right of the tab row lists every pallet with a
  check mark for those shown in this slot. Checking one opens it as a
  tab here (moving it from wherever it was docked); unchecking hides it
  and keeps its tab for next time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 15:17:31 +00:00
Claude 2b2581eb46 Dock: reorder tabs by dragging, one width per tab group, plain rail hover
- Dragging a tab along its slot's tab strip moves it to the gap under the
  pointer; the drop preview shows the new tab order. A panel dragged from
  elsewhere onto a tab strip lands at that position too. A drop in the
  middle of the slot still appends a newcomer and leaves a member where
  it is.
- All tabs of a slot share one width: a joining panel takes the slot's
  width, resizing or resetting one tab sizes them all, and slots sized
  apart by older configs render at their widest tab. Switching tabs no
  longer changes the column width.
- Hovering an auto-hide rail raises its slot without turning the rail
  blue.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 10:58:37 +00:00
Claude 1de5597216 Dock: hover-only title buttons, tilted pin, mirrored float grip
- Docked title bars show the pin and close only while the pointer is
  over the bar; the bar keeps a fixed height so nothing jumps.
- Auto-hide on is drawn as a 30° tilted pin (new pin_active.svg)
  instead of a coloured button background, on docked and floating bars.
- A floating panel's resize grip sits in the bottom corner away from its
  title bar. With the bar on the right it is bottom-left (new mirrored
  resize_left.svg) and resizing from there keeps the right edge fixed.
  The bar stays on its side while resizing.
- While a floating panel is dragged, only the drop preview shows it; the
  panel no longer stays drawn at its old place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 10:37:11 +00:00
Claude 03763ff197 Dock: flush title bars and a vertical title bar for floating panels
Every docked panel now shows its title bar flush along the top, like the
Properties panel: dock::frame takes the title bar separately and pads
only the content below it.

A floating panel drops its horizontal title bar for a vertical one on
the side facing the nearer workspace edge. Close and the auto-hide pin
sit at the top; the panel's icon sits at the bottom with the title
reading upward above it. The free part of the bar drags the panel. With
auto-hide on, a floating panel shrinks to its title bar until hovered.

Panel views take a dock::Chrome (auto-collapse plus floating) in place
of the bare auto-collapse flag, so the shared title bar knows when to
step aside.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 10:11:02 +00:00
Claude 089f572373 Dock: keep the slot splitter at the edge column's width
A Fill-width splitter stretched the whole edge column across the
workspace when two slots were stacked, squeezing the drawing view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-09 08:09:25 +00:00
Claude 76883695c3 Dock: floating panels, tab groups and adjustable slot heights
Panels can now float over the workspace, share a docked slot as tabs,
and split an edge at heights the user picks.

- Dropping a panel away from the edges floats it at the pointer. Floating
  panels move by their title bar, resize from a corner grip, and come to
  the front when clicked.
- Dropping in the top or bottom quarter of a docked slot docks the panel
  above or below it, as before. Dropping in the middle adds the panel as
  a tab of that slot. Pressing a tab shows that panel; dragging a tab
  pulls the panel out again.
- While dragging, a blue ghost previews the result: the new slot, the
  slot with its future tab row, or the floating window.
- A splitter between stacked slots sets their heights; double-click it
  to make the slots equal again. Heights persist.
- A press only becomes a drag after 5 px of movement, so clicking a title
  bar or tab never moves the panel.

The persisted layout now stores each edge as tab groups with a height
weight, plus a list of floating panels. Configs with the old
bare-panel-id stacks still load as single-panel slots.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-08 19:10:36 +00:00
Claude 7aa456407b Context menu: trailing check mark, faded icons on disabled rows
Checked rows (Properties, grip Stretch/Copy) drew a leading "✓ " that
pushed their label out of line with the other rows. The check mark now
sits in the trailing column where submenu headers draw their caret.

Disabled Undo/Redo rows had grey text but full-strength icons:
themed_disabled faded the icon through the SVG tint colour's alpha, which
iced ignores (the tint only replaces RGB). Fade via the widget's opacity
instead, which fixes every themed_disabled icon.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeV3kCDBWCrpYaJEs8CRQU
2026-10-08 18:39:00 +00:00
Claude 7a03e1c43c Merge main into codex/graphic-attributes-cleanup
Conflicts were additions on both sides, kept together: the Count palette
and Sheet Set toggles next to the Graphic Attributes toggle in the ribbon,
main's new locale groups and catalog entries next to graphic-attributes,
and module declarations. The palette code follows main's crate renames
(acadrust -> codec, cadkernel -> kernel).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VgkJN8DEojuPTumAXLHotu
2026-10-07 20:11:05 +00:00
Claude 32ed58fe77 Graphic Attributes: show *VARIES* on the colour swatch again
Differing colours are spelled out on the swatch again; ByLayer and ByBlock
still show only on the L / B button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VgkJN8DEojuPTumAXLHotu
2026-10-07 19:24:04 +00:00
Claude 33a105a619 Graphic Attributes: quieter swatches, Enter in linetype scale, undo names
- Colour swatches carry no *VARIES* or ByBlock text; the L / B / C / V
  button already shows that.
- A separator sits between "Create Layer with active settings" and the
  "Create fills on the current layer" checkbox.
- The linetype scale field is a plain text field like the Properties
  panel: the first click selects its value, Enter applies it (decimal
  comma and expressions accepted) instead of repeating the last command.
  This drops the iced_aw number_input feature again.
- Undo/redo name fill changes "Fill change" and linetype changes
  "Linetype", in all 21 locales.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VgkJN8DEojuPTumAXLHotu
2026-10-07 19:01:25 +00:00
Claude c21a1e6538 Graphic Attributes: tidy helpers, split tests, translate the palette
- The hatch pattern picker takes its messages as one PatternPickerMessages
  struct instead of eight arguments.
- The palette's fill index is keyed on the scene's geometry epoch alone;
  epochs are unique across scenes, so the scene address is not needed.
- The ribbon lineweight handler is an on_ribbon_lineweight_changed method,
  used by the palette instead of a recursive update() call.
- The 430-line palette test is split into eight focused tests with shared
  helpers; no checks were dropped.
- Palette, gradient editor, prompts, messages and undo labels go through
  t!/tf!. The 33 new strings are in a graphic-attributes Fluent group in
  all 21 locales; "[Yes / No] <Yes>", ByLayer and ByBlock stay English.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VgkJN8DEojuPTumAXLHotu
2026-10-07 18:38:04 +00:00
Claude 119131ee10 Graphic Attributes: faster view, fills on object layer, dock on first show
- The palette view looks fills up through an index of associative fills
  that is rebuilt only when the scene's geometry epoch changes, instead
  of scanning the drawing twice per frame. The gradient previews are
  cached and rebuilt only when the gradient changes.
- New fills go to the layer of the filled object. A checkbox in the
  palette menu ("Create fills on the current layer") restores the HATCH
  behaviour and is saved in the config. Objects on locked layers are
  skipped with a message.
- The palette is no longer part of the default dock layout; it is docked
  below Properties the first time it is shown and keeps a place the user
  chose. The original dock test is restored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VgkJN8DEojuPTumAXLHotu
2026-10-07 17:45:38 +00:00
Claude 3c859c6b0e Clean up Graphic Attributes palette
- Revert formatting, import/module reordering and unrelated rewrites
  outside the feature (command.rs, style.rs, paper.rs, view/mod.rs,
  properties.rs, dialog.rs, ValuePromptCommand); the new SVG icons stay.
- Move the palette logic out of dialog.rs into update/graphic_attributes.rs.
- Replace 14 loose app fields and ~50 Message variants by
  GraphicAttributesState (one Menu enum for the open drop-down) and a
  nested GraphicAttributesMsg / GradientMsg, like BlockPaletteMsg.
- Share the selection -> line/fill handles -> unlocked edit path, reuse
  valid_block_name, the ribbon lineweight handler and fill_handles, and
  drop the unused GradientColorToggle, color_open and LineLinetypeScaleInput.
- Linetype scale accepts any positive value (e.g. ISO pen widths 0.13,
  0.18, 0.25, 0.35) instead of rounding to 0.1 with a 0.1 minimum.
- Closing open boundaries and creating the fill is one undo step.
- The close prompt also answers typed Y/N + Enter, a bare Enter (Yes)
  and Escape (cancel), not only the option buttons.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VgkJN8DEojuPTumAXLHotu
2026-10-07 16:45:39 +00:00
Claude 9af327ed0b feat(insert): grip each block attribute
Selecting a block showed one grip, at its insertion point, so there was
no handle to pick an attribute up by: an attribute could only be moved
by moving the whole block.

Give the INSERT one grip per attribute, taken from the attribute's own
`Grippable` implementation, at ids `1 + index`. A drag on one moves that
attribute alone, through the same `apply_grip` the attribute already has
(which carries `alignment_point` along, so non-left alignments stay put
relative to the text). Grip 0 keeps translating the block and every
attribute with it (#255).

A constant attribute belongs to the block definition and an invisible one
is not drawn, so neither offers a grip; a locked-position attribute
declines on its own.

Fixes HakanSeven12/OpenCADStudio#1259

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQzYZsXBwPZ5HwBaGitEUV
(cherry picked from commit 7eb966f6a2)
2026-09-20 21:29:15 +03:00
Claude 033319a4e3 feat(otrack): draw both vectors of an intersection lock
An OTRACK crossing is the meeting of two tracking vectors, but
`OtrackHit` carried only the one a typed distance is measured along, so
the overlay had a single guide to draw. Snapping to the crossing of two
vectors worked and looked like an unexplained point on one line.

Carry the crossed ray out of `otrack_snap` as `OtrackHit::cross`, keep it
on the app beside `otrack_active`, and let the overlay take a list of
guides rather than one. `otrack_active` still drives typed-distance
entry on its own, so distance entry is unchanged.

Fixes HakanSeven12/OpenCADStudio#1313

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQzYZsXBwPZ5HwBaGitEUV
(cherry picked from commit 2f6caacece)
2026-09-20 21:29:15 +03:00
Claude e83c8a28a5 fix(trim): skip polyline segments with no plan-view shape
`sample_entity_xy` walks a polyline's exploded segments and drops the
vertex each segment shares with the previous one. A segment whose curve
plane is upright — any non-horizontal run of a 3D polyline — has no XY
curve, so `entity_curve_xy` declines it and the segment samples to
nothing. With nothing accumulated yet, the seam test compared the two
empty ends as equal and then sliced the empty sample from index 1:

    panicked at src/modules/draw/modify/trim.rs:3982:42:
    range start index 1 out of range for slice of length 0

On the web build that panic unwinds through winit's event-loop runner
and leaves its state borrowed, which is the "RefCell already borrowed"
follow-on in the same report.

Skip an empty sample instead, which leaves the seam handling to the
segments that do have a plan-view shape.

Fixes HakanSeven12/OpenCADStudio#1318

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQzYZsXBwPZ5HwBaGitEUV
(cherry picked from commit ac9a6ce91a)
2026-09-20 21:29:15 +03:00
Claude e87f331a1f Revert "ci: allow workflow_dispatch to upload to an existing release tag"
This reverts commit 0bceb1e2a0.
2026-06-12 11:55:16 +00:00
Claude 0bceb1e2a0 ci: allow workflow_dispatch to upload to an existing release tag
Adds a release_tag input so the workflow can be manually triggered
to rebuild and upload artifacts to an already-published release
(e.g. after a hotfix on main without re-tagging).

https://claude.ai/code/session_01F7yMUY48VuGNUF1Q3ma2cZ
2026-06-12 11:54:17 +00:00
Claude d0870745f2 fix(windows): cast COINIT_APARTMENTTHREADED to u32 for windows-sys 0.61.2
windows-sys 0.61.2 changed CoInitializeEx's dwcoinit parameter type
from i32 to u32, causing a mismatched types compile error on Windows.

https://claude.ai/code/session_01F7yMUY48VuGNUF1Q3ma2cZ
2026-06-12 11:47:52 +00:00
Claude 13eef50a00 fix(windows): add DefaultIcon to Applications entry so "Open with" icon shows
Both the MSI and the portable build were missing Applications\OpenCADStudio.exe\
DefaultIcon, causing a blank generic icon in the "Open with" context-menu list
and the "Choose another app" picker.

- packaging/windows/main.wxs: add Applications\OpenCADStudio.exe\DefaultIcon
  (+ FriendlyAppName, shell\open\command, SupportedTypes) to the
  DefaultPrograms component for MSI installs (HKLM).

- src/io/file_association.rs: add DefaultIcon to the Applications\
  OpenCADStudio.exe block written at runtime for portable builds (HKCU).

https://claude.ai/code/session_01DFVSKgViFaxEjZD2KsTdtt
2026-06-12 11:42:41 +00:00
Claude 73cb0b7e21 fix(linux): install SVG icon to XDG hicolor theme so "Open with" shows the icon
The .desktop file used a named icon (Icon=io.github.HakanSeven12.OpenCadStudio)
but the icon file was never written to the XDG icon theme directory, so file
managers and the "Open with" picker fell back to a generic blank document icon.

install_icon() now writes assets/logo.svg (embedded at compile time) to
~/.local/share/icons/hicolor/scalable/apps/{APP_ID}.svg alongside the
.desktop file, and runs gtk-update-icon-cache so the change is picked up
immediately. The write is skipped when the on-disk file is already identical.

https://claude.ai/code/session_01DFVSKgViFaxEjZD2KsTdtt
2026-06-12 11:39:28 +00:00
Claude db607cca1f fix(windows): register HKCU ProgIDs + Capabilities for portable .exe default-app support
For MSI installs the installer already writes HKLM Capabilities +
RegisteredApplications, so the "Set as default" dialog works.  For
portable .exe builds those registry keys are never created, so the
IApplicationAssociationRegistrationUI dialog silently does nothing.

register_handler() now also writes:
- HKCU\Software\Classes\Applications\OpenCADStudio.exe  (Open-with list)
- HKCU\Software\Classes\OpenCADStudio.DWG / .DXF        (ProgIDs + icon + open cmd)
- HKCU\Software\Classes\.dwg|.dxf\OpenWithProgids
- HKCU\Software\Open CAD Studio\Capabilities            (AssociationToasts shown)
- HKCU\Software\RegisteredApplications                  (Windows Default Programs)

This makes the "Yes, set as default" button work correctly for portable
builds on all supported Windows versions.

https://claude.ai/code/session_01DFVSKgViFaxEjZD2KsTdtt
2026-06-12 10:54:34 +00:00
Claude 5ba7101022 feat(app): silently register as a .dwg/.dxf handler so portable builds show in "Open with"
Installed builds already register a handler (MSI ProgIDs, the Linux
.desktop MimeType, the macOS Info.plist), but the portable .exe and the
AppImage register nothing, so they never appear in the OS "Open with"
list. Add a best-effort, idempotent runtime registration that runs
silently on a detached thread at startup:

  * Windows — writes HKCU\Software\Classes\Applications\OpenCADStudio.exe
    (open command + FriendlyAppName + SupportedTypes .dwg/.dxf), which is
    what lists the exe in "Open with → Choose another app".
  * Linux — writes a user-level .desktop pointing at the running binary
    ($APPIMAGE when set) and refreshes the desktop database. Skipped when
    a system package already provides the desktop entry, so we never
    shadow a distro install.
  * macOS — no-op; .app bundles auto-register with LaunchServices.

Unlike the default-app prompt this changes no defaults and shows no UI;
it only makes the binary discoverable as a handler.

https://claude.ai/code/session_01DFVSKgViFaxEjZD2KsTdtt
2026-06-12 08:00:18 +00:00
Claude a7d85fe148 feat(app): first-launch prompt to set Open CAD Studio as default for .dwg/.dxf
On the first launch that hasn't answered it yet, the app shows a small
dialog offering to become the default handler for .dwg and .dxf files.
The choice is persisted (default_assoc_prompted) so the prompt never
reappears.

The platform plumbing lives in io/file_association.rs:
  * Windows — opens the OS's own per-app default-programs dialog via
    IApplicationAssociationRegistrationUI::LaunchAdvancedAssociationUI,
    passing the "Open CAD Studio" RegisteredApplications name the MSI
    registers. Modern Windows guards the actual default behind a
    UserChoice hash, so this is the supported consent path.
  * Linux — xdg-mime default against the installed .desktop file, whose
    MimeType entries already cover image/vnd.dwg and image/vnd.dxf.
  * macOS — LSSetDefaultRoleHandlerForContentType binds the DWG/DXF UTIs
    declared in Info.plist to the app bundle id.

The work runs on a dedicated thread (the Windows dialog is modal) with
the result delivered back through a oneshot channel and surfaced in the
command line.

https://claude.ai/code/session_01DFVSKgViFaxEjZD2KsTdtt
2026-06-12 07:50:41 +00:00
Claude e24447a70d feat(installer): register Open CAD Studio as a default-app candidate for .dwg/.dxf
Adds a DefaultPrograms component publishing Capabilities and a
RegisteredApplications entry under HKLM. This makes Open CAD Studio
appear in Settings > Default Apps and the shell "Open with" list, so
users can set it as the default handler for .dwg and .dxf files.

Modern Windows guards the actual default behind a per-user UserChoice
hash that an installer cannot forge, so this is the supported path to
becoming the default rather than silently overwriting the association.

https://claude.ai/code/session_01DFVSKgViFaxEjZD2KsTdtt
2026-06-12 07:30:49 +00:00
Claude fd949b74c7 refactor(installer): split installer UI into its own ui.wxs
Moves the WixUI_Minimal UI and finish-screen launch checkbox out of
main.wxs into a dedicated ui.wxs fragment, referenced from main.wxs via
<UIRef Id='OpenCADStudioUI'>. Keeps the package/feature definition and
the UI concerns in separate files.

Updates the release workflow to compile both .wxs files (candle now
writes per-source .wixobj into a directory) and link both objects.

https://claude.ai/code/session_01DFVSKgViFaxEjZD2KsTdtt
2026-06-12 07:28:04 +00:00
Claude 556989dbdb feat(installer): add finish screen with launch-app checkbox to Windows MSI
Adds WixUI_Minimal UI to the WiX installer so users see a proper
Welcome → Progress → Finish wizard. The finish screen includes a
pre-ticked "Launch Open CAD Studio" checkbox; clicking Finish with
it checked starts the application immediately after the installer closes.

Also updates the light.exe invocation in release.yml to include
-ext WixUIExtension, which is required to link the WixUI dialogs.

https://claude.ai/code/session_01DFVSKgViFaxEjZD2KsTdtt
2026-06-12 07:24:36 +00:00