Commit Graph
99 Commits
Author SHA1 Message Date
PanosandClaude Opus 5 7a75d430cd fix(plot-style): load plot style tables written by other applications
Tables copied from other applications into the plot styles folder were
listed but refused on selection, showing as "missing" with the reason
lost on a console: the loader failed hard on a checksum or a text length
that did not add up and on any non-UTF-8 byte — and those files carry
their descriptions in Windows-1252.

- decompress_ctb reads the file as it is: a checksum or length mismatch is
  reported and read past (a genuinely cut-off file is still an error), a
  zlib stream with a bad trailer is retried as raw deflate, and text that
  is not UTF-8 is read as Windows-1252 (pens and colours are numbers and
  unaffected; other code pages only show wrong characters in descriptions).
- PlotStyleTable carries load_warnings; every load site reports them on the
  command line, so a table that needed tolerance says so.
- load_named explains itself: a .stb name says named tables are not
  supported yet, a .ctb missing from the folder says which folder to copy
  it into (instead of "Unknown built-in plot style").
- The Plot dialog shows the reason under the Table row (style_error) —
  from a selection, from a page setup that names a table, and from the
  Load… picker, whose error used to be swallowed.
- A table picked with Load… from outside the plot styles folder is copied
  into it (unless a file of that name is already there), so it is listed
  from then on and page setups naming it resolve after a restart.

Tests: flipped checksum, text length off by one, a short payload field,
Windows-1252 descriptions, a truncated stream, .stb and missing names.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 19:00:28 +03:00
PanosandClaude Opus 5 0fbb5bcb4f ui: neutral wording in code and help text; keywords first in the command menu
Comments and the Options help text describe the behaviour of commercial
solutions without naming any product. The command menu puts the command's
keywords directly under Enter / Cancel, with Recent Input and Snap
Overrides below them, so the choices that change from step to step are the
closest to the pointer.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 12:05:15 +03:00
PanosandClaude Opus 5 02cd98e790 feat(ui): feature-parity context menu — Snap Overrides, transparent Pan/Zoom, ARC keyword flow
The command menu now follows the commercial solutions' layout row for row: Enter, Cancel,
Recent Input ▸, the command's keywords, Snap Overrides ▸ (every object snap
with its glyph, Mid Between 2 Points, None, Osnap Settings…), then Pan and
Zoom. Pan / Zoom run transparently while a command is active ('PAN,
'ZOOM …): navigation modes leave the command untouched and an interactive
ZOOM Window parks it and resumes it afterwards. Rows carry an icon gutter
so labels align; the Enter row shows a default value ("<0.5000>") as its
hint instead of a second finish row.

ARC gets the commercial solutions' prompt flow with all keywords: start [Center], second
point [Center/End], end; after Center: end [Angle/chord Length]; after
End: center [Angle/Direction/Radius]; Enter continues tangent. The
previous default (Center/Start/End with method codes) stays as ARC_CSE.

Object snaps gain a one-shot "None" override. New strings in all locales.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 12:05:15 +03:00
PanosandClaude Opus 5 426af2d3a5 i18n: catalogue entries for the context menu, PLINE and modify options
Every new UI string (menu rows, Options → Right-click Customization, the
PLINE sub-prompts and keyword labels, MOVE/COPY/OFFSET prompts) gets its
Fluent attribute in all 21 locales plus the source → attribute rows in
locale_catalog.rs; the SETVAR help line lists SHORTCUTMENU and
SHORTCUTMENUDURATION. Tests that compared prompt text now check command
state so they pass under any UI language.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 12:05:15 +03:00
PanosandClaude Opus 5 d753874fe4 feat(modify): commercial solutions keyword options for MOVE, COPY, FILLET, CHAMFER, OFFSET
MOVE: Displacement, Enter at the second point uses the base as the vector.
COPY: Displacement, mOde (Single/Multiple), Undo of the last copy.
FILLET: Undo of the last fillet (the command refreshes its entity cache
through the new CadCommand::on_document_undone hook after the host undoes
the document step). CHAMFER: Multiple and Undo. OFFSET: Erase (the offset
replaces its source), Layer (Current/Source), Undo, Exit.
POLY3D, TRACE, MIRROR and MEASUREGEOM expose the keywords they already
accepted as options, so the context menu and option buttons list them.

The pinned prompt now keeps informational bracket groups such as
"[3 objects]" and only drops real option listings when the buttons take over.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 12:05:14 +03:00
PanosandClaude Opus 5 737666b894 feat(plot): printer driver properties and a roomier plot dialog
Properties… next to the printer used to open the CUPS web interface in a
browser. It now edits the driver options of the *selected* printer the
way LibreOffice's Properties… does, without leaving the plot dialog:

- CUPS platforms (Linux, any desktop; macOS): an in-line editor lists the
  printer's PPD options as `lpoptions -l` reports them — media type,
  colour mode, quality, duplex, trays, scaling — with readable choice
  labels, Reset / Cancel / Apply. Apply keeps only the choices that differ
  from the driver defaults, per printer, in the plot config, and every job
  for that printer passes them as `lp -o key=value`. Where CUPS cannot
  answer, the desktop's printer settings panel opens instead of a browser.
- Windows: the driver's document-properties sheet (`DocumentPropertiesW`
  with prompt, owned by the main window) and, on OK, the result stored as
  the user's printing preferences for that printer (`SetPrinter` level 9),
  which the job honours. `printui /e` (printing preferences) replaces the
  device-properties sheet as the fallback.

The desktop print portal was tried first and dropped: GTK 4's print
dialog loses the preselected printer when the default queue is listed
before it, so the dialog always opened on the wrong printer.

Dialog layout: the modal grows to 940×620; Printer / plotter and Paper
size share a line with their pickers (long queue and media names now fit);
Copies + Properties… and Custom… sit beneath; the custom-sheet editor
labels each margin (Left / Right, Top / Bottom) and shows the unit.

Also recognises `none_device`, AutoCAD's stored spelling for "no plotter",
and writes it back unchanged.

Tests: `lpoptions` parsing and keyword humanising, the editor flow (load,
stale answer ignored, set, apply, remember, reset, error, cancel), device
name round-trips including `none_device`.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-16 16:05:47 +03:00
PanosandClaude Opus 5 5e271e2dbb feat(plot): custom paper sizes with printable margins
AutoCAD lets a plotter configuration carry user-defined sheets; a drawing
then names them like any other media (`Roll_24_(609.60_x_1500.00_MM)`).
The plot dialog now defines such sheets inline, under the Size row:
name, width/height, unit, and the printable margins in that unit. Added
sheets are selected at once, offered for every device after the device's
own list, remembered in the plot config across sessions, and written to
the layout with their own margins (a printer that reports the same size
still wins with its hardware margins). A selected user-defined sheet can
be removed; the sheet itself stays selectable in the drawing that uses it.

`CustomPaper` / `Margins` live in the paper catalogue with serde support;
`PlotDevice::margins_mm` consults the user's definitions. The Plot
dialog's form helpers (button and field styles, dividers, `label :
control` rows) move to `ui::style::form` so the next dialogs share them
instead of copying.

Tests: draft validation and seeding, catalogue naming of user sheets,
device margins with user definitions, and dialog round-trips (add,
select, persist, write, replace, remove, refuse an invalid size).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-16 16:05:47 +03:00
PanosandClaude Opus 5 c03a40cb33 feat(plot): plot device model with AutoCAD names and printable areas
A page setup names its plotter, and AutoCAD looks that name up in its own
configurations: `DWG To PDF.pc3` for PDF output, the spooler name for a
system printer, `None` when nothing is assigned. Drawings saved here used
to carry the dialog's label ("Save to PDF file…"), so AutoCAD reported a
missing device on every layout plotted to PDF from Open CAD Studio.

- New `io::plot_device`: `PlotDevice { None, Pdf, Printer }` with AutoCAD's
  spellings, a reader for stored names that keeps any plotter
  configuration AutoCAD wrote (an HP `.pc3`, `DWF6 ePlot.pc3` — plotted to
  PDF here but preserved for AutoCAD) and upgrades the legacy label.
- Printable areas: the PDF driver's margins per sheet variant (full bleed
  edge to edge; standard / expand insets provisional until read off
  AutoCAD's plotter configuration), and for CUPS printers the media and
  margins the queue reports over IPP (`ipptool` `media-col-database`),
  parsed once per printer and cached. Windows enumeration follows with
  native GDI printing.
- Page setups now store the device in AutoCAD's spelling and the margins
  of the chosen device/sheet, keeping the drawing's own values while
  neither changed (AutoCAD's `PAPERUPDATE` behaviour). The paper-space
  printable-area rectangle follows.
- Plot dialog: the default entry names the printer it resolves to; a
  printer that answered lists its own sheets with a note; the media query
  runs in the background and answers for a since-deselected printer are
  dropped.

Tests: device names, stored-name resolution, PDF margin table, IPP media
parsing (sizes, margins, borderless folding, default sheet), PWG names,
plus dialog ↔ layout round-trips for PDF, legacy label, preserved plotter
configuration, sheet change → margins, and printer selection.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-16 16:05:46 +03:00
Karim Jerbi 1450fdeedf chore(i18n): sync locale catalog and translations with source strings
Remove the dead catalog entry for the deleted XREF dead-end text and add the 389 source strings missing from the catalog (data extraction, drafting settings, panels, commands). Every locale gets the English text as placeholder under common/insert following existing practice. scripts/test_locales.py passes (5077 lookups).
2026-09-15 23:56:32 +01:00
Karim Jerbi 1c8e3ff3d7 feat(xref): 8-item filtered row menu, preview on selection, details display size
Row right-click menu is exactly Open, Attach..., Unload, Reload, Detach, Change Path Type group with Make Absolute, Make Relative, Remove Path, Select New Path, Find and Replace. Change Path Type renders as indented group. Open uses OCS for DWG and OS default for images and PDFs. Preview decodes on selection change, not only at refresh. Details shows placed display width and height for image instances.
2026-09-15 23:56:31 +01:00
Karim Jerbi e9151ea2f4 feat(xref): wider panel default, Attach DWG/Image/PDF menu, status icons
External References dock default 360 to 460 for the column-rich table. Attach split button reads Attach DWG with Attach Image and Attach PDF options, all menu rows full width. List view shows one distinct glyph and theme color per reference status.
2026-09-15 23:56:31 +01:00
Karim Jerbi 22a9bd602c feat(xref): row-level context menu actions and unified split-button toolbar
Right-click actions bound to the row under the cursor, split-button toolbar groups with shared borders and hover states, and a notice when an operation needs a selection first.
2026-09-15 23:56:31 +01:00
Karim Jerbi 019422d220 feat(xref): docked External References panel with previews and translations
Docked External References panel with host row, thumbnail previews, and translated interface strings.
2026-09-15 23:56:31 +01:00
Karim Jerbi d0d946a568 feat(xref): detach, unload, reload, bind, overlay, and path operations
Detach, unload, reload preserving host layer overrides, bind, overlay, and saved-path editing, with per-tab session state and a read-only web list.
2026-09-15 23:56:31 +01:00
Hakan Seven 7b4cef41f7 Complete parametric ribbon and constraint tools 2026-09-14 01:05:39 +03:00
PanosandClaude Opus 5 02b0f4c7d9 Tell the user when the scene is drawn without a GPU
A day of pan/zoom that had suddenly become unusable on a 1.2M-entity
drawing turned out to be no regression at all: an unattended NVIDIA
userspace update had been applied without a reboot, the Vulkan ICD could
no longer talk to the still-loaded kernel module, and wgpu silently fell
through to Mesa's llvmpipe. Nothing in the app said so. iced picks the
adapter and names it only under RUST_LOG, so the only evidence was 32
`llvmpipe-N` threads in /proc. The same silence covers WARP on Windows,
SwiftShader in browsers, and the case where wgpu finds no adapter at all
and iced quietly draws the chrome with tiny-skia while the shader widget
is dropped, leaving a blank viewport. This commit makes all of that
visible, on every platform, without new dependencies.

Detection (src/scene/pipeline/mod.rs)
-------------------------------------
`GpuStatus` is derived from two signals:

* `record_gpu_adapter`, run from `MultiPipeline::new` (once per device,
  next to the existing uncaptured-error handler), reads
  `Device::adapter_info()`, prints one `[gpu] adapter: <name> (<backend>,
  <device type>, driver …)` line — stderr natively, `console.warn` on the
  web, which has no stderr — and keeps a copy.
* `note_scene_draw`, run from `ViewportPane::draw`, counts how often the
  viewport asked for a primitive. Every renderer makes that call; only
  wgpu goes on to `prepare` and create a device. Three draws with no
  device ever recorded therefore mean the primitive is being dropped.

The verdict is one of `Unknown`, `Hardware`, `Software(adapter)` or
`NoRenderer`. `Software` is `DeviceType::Cpu` — what Vulkan reports for
llvmpipe, DX12 for WARP and GL for a renderer string that gives it away —
plus a name match on the fallbacks browsers expose (SwiftShader, llvmpipe,
lavapipe, "Microsoft Basic Render"), because the WebGPU backend reports
every adapter as `Other` (gfx-rs/wgpu#8819). Metal has no software device,
so on macOS only `NoRenderer` can occur (a VM without a GPU); it is caught
by the draw count like everywhere else.

`gpu_status_if_changed` costs one atomic load per app message: a
generation counter moves only when a device is recorded or the draw count
crosses its threshold, so the app re-derives the verdict a handful of
times per session.

Notification (src/app/startup.rs, view/modal.rs, ui/statusbar)
-------------------------------------------------------------
`refresh_gpu_status` runs after every message. On a degraded verdict it
speaks through three channels, because many users never read the command
line:

* A popup, `ModalKind::GpuWarning`, queued once per verdict through the
  startup-modal queue so it waits its turn behind the file open. It names
  the adapter, states the consequence (slow navigation, unstable or
  missing rendering) and gives the remedy that usually applies on the
  running platform: a driver update not yet followed by a reboot on
  Linux, a missing driver or a Remote Desktop / VM session on Windows, a
  VM without a Metal device on macOS, hardware acceleration switched off
  in the browser. "Don't show again for this device" stores
  `GpuStatus::identity()` in `settings.gpu_warning_silenced`; keying it by
  verdict means silencing "software rendering on llvmpipe" does not
  silence a later, different failure.
* A status-bar pill in the theme's warning colours, `⚠ Software rendering`
  or `⚠ No GPU renderer`. It is not a `StatusPill`, so it cannot be hidden,
  and it stays for the session; clicking it reopens the popup, silenced or
  not.
* A command-line entry through the new `CommandLine::push_warning`, which
  is styled like an error but deliberately does not touch `last_error` /
  `error_revision`: automation reads those to decide whether the command it
  just ran failed, and a graphics warning is not a failed command.

`subscription()` requests frames only while the verdict is `Unknown` on a
document tab (the Start page draws no viewport), so the probe costs one
frame on a working GPU, three on none, then stops.

Verification
------------
* Live on the machine that had the incident, with the Vulkan loader
  restricted to Mesa (`VK_DRIVER_FILES=…/lvp_icd.json WGPU_BACKEND=vulkan`):
  popup → OK → pill → click reopens; "Don't show again" → restart → pill
  only, no popup.
* `gpu_tests::the_adapter_is_reported_once_per_device` (ignored, needs an
  adapter) asserts the classification on a real device; it was run on both
  llvmpipe (`Cpu`) and an NVIDIA GT 1030 (`DiscreteGpu`).
* Unit tests cover the name heuristic, the verdict function, the identity
  rule, the warning text with an adapter name that itself contains
  parentheses and commas, the settings round trip and the command-line
  semantics. New strings are in all 21 locales as the `gpu` Fluent group.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-12 16:19:41 +03:00
PanosandClaude Opus 5 5f161bb037 Show the exact build in About, Copy Info, REPORT and --version
Builds from main reported only the release version (2026.36) even when
HEAD was hundreds of commits past the tag. build.rs now also emits
OCS_TAG_DISTANCE, OCS_COMMIT_DATE, OCS_BUILD_METADATA and
OCS_FULL_VERSION: a clean checkout of the release tag stays "2026.36",
anything else becomes "2026.36+194.gef189d77", with ".dirty" appended
for uncommitted changes and only the hash when no tag can be counted
from (shallow clone, tarball). OCS_APP_VERSION is unchanged so the
update check, donation gate, User-Agents and window title keep working.

The About dialog gains Build / Commit date / Profile cards, Copy Info,
the REPORT issue template and recovery reports carry the full version,
and `-V`/`--version` print it instead of Cargo's 2026.36.0. Release
workflows check out full history so release binaries see the tag.

Also fixes the build being marked dirty when there is no repository:
diff-index exits 128 there, not 1.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-12 16:19:40 +03:00
Hakan Seven 754cc89fab Merge PR #1216: expose MTP in snap menus 2026-09-12 15:12:04 +03:00
Hakan Seven cf33455e93 Move parametric tools to their own ribbon tab 2026-09-11 20:58:37 +03:00
ramox81 14b98231f5 Align spline fit properties and menu arrows 2026-09-11 15:53:51 +03:00
Hakan Seven c50427a834 i18n(tr): shorten shaded render mode labels 2026-09-10 21:48:37 +03:00
PanosandClaude Opus 5 55b2dc1796 Translate the Options dialog into all 21 languages
Sixty-five new strings, each one added to the source catalogue and given a
value in every locale — not English placeholders. Terminology follows what
each locale already uses for the surrounding labels rather than being coined
fresh: grips, selection, preview, viewport, annotation scale and the UCS all
have established words in these files, and the new strings use them.

System-variable names stay in Latin uppercase inside the parentheses, as they
already do in every locale's SETVAR listing — they are identifiers, not prose.

One trap worth recording: Fluent attribute names must begin with a letter, so
the obvious slug for "3D Modeling" is not a legal key. It parses as far as
the message body and then fails the whole file, which surfaces as
`Invalid Fluent syntax in EnUs` with a byte offset rather than as anything
naming the attribute.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 08:55:34 +03:00
PanosandClaude Opus 5 08d339d38f Translate the new Selection labels, and pin what SELECTIONPREVIEW's bits do
The ten strings the Options card gained were English in nineteen of the
twenty-one locales. They are now translated in all of them, using the words
each locale already uses for the surrounding labels — de-DE "Griffe",
fr-FR "Poignées", zh-CN "夹点", zh-TW "掣點" and so on for grips, and the
same for selection, preview and object. System-variable names stay in Latin
uppercase, as they already do in every locale's SETVAR listing.

Composing them from existing keys, the way el-GR composes the neighbouring
labels, only worked for one of the ten: there is no existing key for "limit",
"unlimited", "shift", "rectangle" or "lasso", and "Grips: Objects" as the
label of a numeric limit would read worse than English.

The rollover preview was reported as possibly not working. It works, and now
says so: `the_idle_rollover_follows_bit_one` drives a settled hover over a
line and checks what the scene highlighted, for all four values of the
bitmask. Bit 1 alone highlights, bit 2 alone does not, both do, neither does
not. That is the assertion the inverted config comment would have made
someone doubt — the pick simply needs the cursor still for the 500 ms of
`HOVER_DWELL_MS` before it runs.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 14:15:44 +03:00
PanosandClaude Opus 5 cabb20db45 Put the rest of the selection settings on the Options card
Options → Selection already carried the pick box, the selection-area effect
and the grip visuals. Four settings behind it were finished, persisted and
reachable only by typing a system variable, and one more was a constant.

**Four that only needed a widget.** `SELECTIONEFFECT`, `SELECTIONPREVIEW`,
`PICKADD` and `PICKDRAG` are all wired end to end already. `SELECTIONEFFECT`
was the odd one: the card's own "Restore Defaults" button resets it, so it
could be turned off by a button and only turned back on from the command
line.

`SELECTIONPREVIEW` is a bitmask and gets one checkbox per bit, which is why
`set_preview_bit` exists rather than two inline expressions — the bits are
the thing this change is most able to get backwards.

The `PICKADD` checkbox is worded as AutoCAD words it, "use Shift to add to
selection", which is the *inverse* of the stored flag. That inversion is
commented at both ends; it reads as a bug otherwise.

**`GRIPOBJLIMIT`.** The limit past which a selection gets no grips arrived
with the selection work as a hardcoded 100, matching AutoCAD's default. It is
now a setting, a slider and a system variable, following `PICKBOX`'s path
exactly. AutoCAD's 0 means "no limit", which the old `>` comparison could not
express, so the read now guards on it — with a test, because zero is the one
value that would otherwise suppress every grip instead of allowing all of
them.

The slider covers 0..=1000, where every useful value lives; the sysvar takes
AutoCAD's full 0..=32767, and a larger value set from the command line parks
the handle at the end while the read-out keeps showing the real number.

**`SelectionPrefs`** replaces the `pick_box` parameter rather than adding
three more. `view_window` already took seventeen positional arguments, and
`pick_add` / `pick_drag_rect` are two adjacent `bool`s that would swap
silently at the call site.

**Two fixes found on the way.** `OPTIONS` and `OP` were registered for
autocomplete but never dispatched, so typing either answered "Unknown
command" and the dialog could only be opened from the start page. And the
`SELECTIONPREVIEW` doc comment had its bits the wrong way round — the code
reads `& 1` for the idle rollover and `& 2` for the in-command one, as
AutoCAD does — which would have put the two new checkboxes' labels backwards.

**Not done, deliberately.** `PICKFIRST` and `PICKAUTO` exist but are always
on, with no variable. `PICKSTYLE` is stored in the header and read by nobody
— group expansion decides from the group's own `selectable` flag — so an
"object grouping" checkbox would control nothing. Associative-hatch selection
does not exist as a selection behaviour. Each needs a behaviour change rather
than an exposure.

Of the ten new strings, en-US and el-GR are translated; the other nineteen
locales carry the English text. Composing them from existing keys, the way
el-GR composes the neighbouring labels, only works for one of the ten —
there is no existing key for "limit", "unlimited", "shift", "rectangle" or
"lasso", and "Grips: Objects" as the label of a numeric limit would be worse
than an untranslated string.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 13:19:06 +03:00
Hakan Seven fd3ddc1608 Finish Ramox edge and slice integration 2026-09-08 19:02:08 +03:00
Hakan Seven 7ec07f3222 Merge pull request #1070 from ramox81/codex/filletedge-parity
# Conflicts:
#	Cargo.lock
2026-09-08 18:30:34 +03:00
Hakan Seven 001605baa1 Merge pull request #1065 from ramox81/codex/slice-command-parity 2026-09-08 18:28:01 +03:00
ramox81 8bb6703c70 Complete FILLETEDGE workflow and history 2026-09-08 12:36:49 +03:00
Hakan Seven 5b663bfe38 Fix issues found while integrating contributor PRs 2026-09-08 12:14:28 +03:00
ramox81 21a357f55a Complete SLICE command behavior 2026-09-08 10:27:23 +03:00
JonathanandCopilot 7a706e24ac Improve Dutch CAD terminology translations
- Multiverwijslijn → Multiverwijs Lijn (proper spacing)
- Multiline → Multilijn Tekst (better clarity)
- Unie → Samenvoegen (more accurate for boolean union)
- Aftrekken → Verschil (better term for boolean subtract)

These terms align better with Dutch CAD industry standards.

Co-authored-by: Copilot <[email protected]>
2026-09-08 08:52:18 +02:00
Hakan Seven d66e89ca19 Complete application localization across all supported languages 2026-09-07 01:05:02 +03:00
Hakan Seven 2c83ae2736 Show donation request once per app version 2026-09-06 11:44:38 +03:00
MarcelP102 fe841f746c Fix capitalization in Dutch translations 2026-09-05 19:53:53 +02:00
MarcelP102 cd7c3102f5 Merge branch 'HakanSeven12:main' into main 2026-09-05 19:39:19 +02:00
Hakan Seven ac8a545669 Fix layout cache correctness and GPU resource recovery 2026-09-05 19:56:49 +03:00
PanosandClaude Opus 5 09838be9ec feat: draw a notice for one frame before rebuilding a layout
Switching to a Layout stops the main thread long enough that the
compositor decides the application has stopped responding and offers to
kill it. The switch itself is not the problem — `layout-switch` reports
about 10 ms — it is the frame after it, which rebuilds the whole wire set.

That frame now has a cheap one in front of it. `layout_settling` is set
when the switch takes, and while it holds, the viewport is replaced by a
centered "Preparing layout…" on the canvas background. No shader widget
means no scene primitive, so `prepare` has nothing to do and the frame
costs nothing. A `window::frames` subscription clears the flag, which is
the guarantee this needs: that callback runs once a frame has actually
been presented, so the notice is on screen and the compositor has been
answered before the expensive frame starts.

The deferral is of the *frame*, not the switch. Two callers depend on the
switch having completed when it returns — one calls `fit_all` immediately
after, another compares `current_layout` — so deferring the switch itself
would have broken both.

This restarts the compositor's timer immediately before the slow frame and
replaces a stale window with something that says what is happening. It
does not make the slow frame fast: if the rebuild still exceeds the
compositor's timeout the dialog can return, and the durable fix is the
2 s `memo_miss` behind it, which is a separate change.

Only `en-US` is validated against at build time; Greek is filled in too
since it is in use here, and the rest fall back until translated.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 18:53:02 +03:00
MarcelP102 87407e5000 Update Dutch Translation 2026-09-05 13:09:44 +02:00
Hakan Seven 9d991d7feb Bound GPU uploads and complete Greek and performance integration 2026-09-04 20:26:29 +03:00
PanosandClaude Opus 5 0d11421dea fix: free superseded wire buffers before allocating their replacement
The renderer shares one set of wire GPU buffers per wire_content_id
across every pane and viewport slot. Every geometry edit mints a new
content id, so every edit builds a new set -- and the old one stayed in
wire_buffer_cache until the map exceeded sixteen entries.

Sixteen entries is a sane bound for small drawings and fatal for large
ones. The policy counted entries, not bytes. On the reproducer a single
set is most of the card: the VRAM trace shows 572 MiB baseline rising to
1871 MiB on a 2048 MiB GT 1030. The second set has nowhere to go, so the
first edit after opening exhausts VRAM. The perf log shows exactly that
-- two `shared-fullupload` lines, an edit, then the process dies.

Evict on every miss instead of at a count threshold, and do it before
building the replacement rather than after, so the old allocation is
released while the new one is still being sized. Dropping this slot's own
handles first is what lets the retain see the superseded entry as
garbage; a pane still drawing that content keeps its own clone and its
strong count stays above one, so shared geometry is never pulled out
from under a live viewport.

The trade is that returning to a previous content id -- undo, mostly --
now rebuilds instead of hitting a warm entry. On a card where the
alternative is dying, that is the right way round.

Adds a PERF line reporting evicted and retained entry counts, so the
policy can be watched rather than assumed.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-04 16:21:08 +03:00
ramox81 5bbb0bbe1f Harden revolve validation and properties 2026-09-03 15:01:38 +03:00
Hakan Seven 612ec8d60f Merge main and localize surveyor units 2026-09-03 12:45:24 +03:00
ramox81 9d947d75c5 Align polygon mesh properties 2026-08-31 10:13:12 +03:00
Hakan Seven 8c0af9d584 fix(i18n): complete missing translations 2026-08-29 09:46:47 +03:00
Hakan Seven f61d65dced fix(i18n): correct jogged radius lookup
Refs #926
2026-08-28 21:20:29 +03:00
Hakan Seven 50e5dcaaac fix(polyline): correct 3D smoothing 2026-08-28 19:46:13 +03:00
ramox81 3ca959a34b Fix 3D polyline behavior and properties 2026-08-28 11:21:03 +03:00
ramox81 ef7f26be68 Align multileader property visibility 2026-08-28 09:59:23 +03:00
ramox81 5a9894fd3e Complete jogged radius dimension workflow 2026-08-26 17:17:55 +03:00
Hakan Seven 968ee3fda4 fix(dimension): complete ordinate workflow 2026-08-25 21:36:04 +03:00