The bodies now always draw over the preview on every face a feature leaves unchanged, for
all features. Since a hole's cut sits inside the body, the Hole preview now hides the
bodies and shows the result alone, as Fillet/Chamfer and Draft do.
# Description
Follow-up to #15238. A review of the Design tab, and then testing its
Linux AppImage on desktops, turned up UX inconsistencies, kernel bugs
and a crash. This PR fixes them and fills the gaps found along the way.
Everything stays behind `SLIC3R_CAD` and the `enable_cad_feature`
preference. With the preference off, Prepare and Preview behave and
render exactly as before.
The first four commits are Design-tab fixes that landed on the fork
after #15238 and were never sent upstream: the value-field label, the
`GUI.hpp` include, sketch tool batches 9–14 and honest tool messages.
The later commits build on them.
**Interaction: one rule for mouse, Enter and Esc** (charter
`docs/CAD/cad_ux_guidelines.md` §4.2)
- Enter does what ✓ does; Esc does what ✗ does. Esc steps back one level
(value field → gesture → tool → selection) and never deletes anything.
- A click on empty space clears the selection and never applies a
pending operation.
- A right-click with nothing pending opens the offer. The click is
recognised by drift alone; the 200 ms timing rule is gone, since §6.2
forbids timing-dependent gestures.
- The panel's CHAR_HOOK owns Delete, Esc, Ctrl+Z/Y and F, so the
duplicate handlers in `GLCanvas3D` are removed.
- Ctrl+Z/Y work inside a sketch, and Edit ▸ Undo/Redo drive the Design
history while that tab is shown.
- A value the geometry cannot take (zero length, sweep > 360°, …) is
refused inside the field, and the field says why.
**Kernel**
- Solver: tangency and point-on-line pick the correct side;
circle–circle tangency is handled; the partitioned solve maps sentinel
references; constraints that could not be applied are reported instead
of silently dropped.
- Trim, extend, offset and mirror are fixed for arcs and ellipses.
Negative scale is handled, and zero-radius circles no longer produce
geometry.
- Feature → body references resolve by identity, so hiding, reordering
or deleting a feature no longer re-targets later features.
- Hole standards table corrected: inch countersinks are 82°. New threads
use the nominal diameter; new patterns use inclusive spacing. Both are
gated by flags, so existing recipes rebuild unchanged.
- **A closed loop that crosses or folds back is not a region.** Such a
loop passed the closed-loop check and MakeFace, and extruded into an
invalid solid with no caps. `SketchEngine::wires_to_face` now checks the
face (BRepCheck) and fails with a reason; `sketch_loop_defect()` finds
the crossing or cusp exactly, and the sketch tints the loop red and
marks the point.
- Recipe: saves origin, body colours and the loop auto-close setting in
a trailing block; the v4 reader is frozen as `load_flat_v4`; the 3MF
reader caps the entry at 1 GiB and the legacy entry name never overrides
the current one. New fields (`dressup_edges`, the Text parameters,
`revolve_axis_entity`) are appended at the end of the framed recipe, so
existing projects load and rebuild unchanged.
- OCCT failures are caught before `std::exception` in the new code (OCCT
≥ 8).
**Modelling**
- **Several solid edges in one Fillet/Chamfer.** Shift/Ctrl+click adds
or removes edges of the picked body; one feature dresses them all at one
size, every id resolved against the same body. The card and the offer
name the count.
- **Sketch Offset takes the whole outline** the picked curve belongs to,
with a live preview, instead of one segment (on a text outline a segment
is a fraction of a millimetre, so nothing seemed to happen).
- **Revolve about a line of the sketch.** The axis was only the sketch
plane's X or Y axis. It can now be any line of the profile sketch: a
construction centerline (preselected when the sketch has exactly one) or
an edge of the profile. The gizmo draws the axis dashed. A profile on
both sides of the axis is refused with the reason (MakeRevol failed
there with none). Surface Revolve takes the same axes.
**Panel, offer, text**
- The offer menu: its strings are translatable (the generator emits
`L()` markers, and the files are added to `list.txt`); it opens with a
title naming the selection; blocked verbs stay in place, greyed, with
their reason; each verb has one refusal wording.
- Extrude defaults to Join when the profile touches a solid, otherwise
New body. All result menus use one vocabulary: New body / Join / Cut /
Intersect.
- Interference and volume/area reports go to the status line, in
mm³/mm². Delete Body no longer asks for confirmation, since it is
undoable.
- **Text is its own feature** ("Text N" in the tree). Its dialog offers
any installed font (bold, italic) and the height in mm; it is modeless
and opens at the top right of the window, and the outline is drawn in
the view where it will go while typing. Editing the feature reopens the
dialog with its string, font and height. The outlines are saved too, so
the project opens the same on a machine without that font.
- New feature names match the card header (`Extrude 3`) and are
translated. Terminology and units are unified ("Coordinate system",
"Angle (°)").
- The Prepare Sketch/Primitive gizmos can be selected only when the CAD
feature is on.
- MCP: write methods are refused while the tab is busy (including while
the Text dialog is open); a timed-out command never runs; only a socket
is ever unlinked; `fillet`/`chamfer` accept an array of edges.
**Rendering in the Design view**
- Once extruded, a part was hard to read: both lights of the object
shaders sit near the camera, so the sides of a part came out in nearly
the same tone, and nothing marked where one face ends.
- The phong shader gains a studio lighting model, selected by a new
`lighting_model` uniform: a sky/ground hemisphere in world space, a key
light from the upper left and a weak fill, a plastic-like highlight, and
a darker base with a faint sheen toward the silhouette.
`GLCanvas3D::set_studio_lighting()` enables it per canvas; only the
Design canvas does. Every canvas sets the uniform on each use (0 for the
slicer's canvases), so Prepare and Preview render exactly as before.
- Every B-rep edge of a body is drawn as a 2 px dark line, depth tested
and pulled a few pixels toward the eye, so it hides behind the faces in
front. Seams of closed surfaces and degenerate edges are left out
(`GeometryEngine::display_edges`).
**Crash fix (Linux AppImage)**
- Drawing anything in a sketch crashed the AppImage: the constraint list
labels were formatted from narrow literals holding `—`, `·` and `°`;
`AppRun` sets `LC_ALL=C`, so wx's conversion returned NULL and
`wxString::Format` dereferenced it. They now go through
`wxString::FromUTF8`, as the panel's other non-ASCII literals already
do.
Docs updated to describe the design as it now stands: `design_tab.md`,
`interaction-model.md` and the portability note.
No change to slicing, profiles or presets. Existing 3MF recipes load and
rebuild as before: the v3/v4/v5 fixture tests pass.
# Screenshots/Recordings/Graphs
None attached. The behaviour was checked on the fork's Linux tester
AppImages, driven under Xvfb (see Tests).
## Tests
- `libslic3r_tests` on this branch, rebased on `main` (dc0e26918): 943
of 944 cases pass (1 skipped), 79,733 assertions. Linux, system OCCT.
- New or updated cases cover: the solver side and tangency fixes;
trim/offset/mirror on arcs and ellipses; body identity across history
edits; datum remapping, expressions, bindable fields; circular pattern,
hole standards, threads; the round trip of colours, origin and
auto-close; `body_touching_sketch`; multi-edge fillet/chamfer and its
save/load; the crossing/cusp loop analysis and the extrude refusal; the
Text parameters' save/load; `display_edges` on box, cylinder and cone;
revolve about a centerline, about the profile's own edge, refused
through the profile, stale axis index, axis save/load. The
truncated-recipe test accounts for every new tail field.
- All touched GUI translation units compile with GCC, and with clang
`-fsyntax-only` under the macOS job's warning flags. The modified
shaders pass `glslangValidator`.
- `gen_offer_table.py --check` passes, and `xgettext` + `msgfmt
--check-format` are clean on the CAD sources.
- On the fork's Linux tester AppImages (same code on `cad-mainline`),
driven headless:
- drawing lines and rounded rectangles no longer crashes;
- Offset on one side of a rectangle selects and previews the whole
outline; Enter adds it;
- Text: the dialog opens at the top right, "Text N" appears in the tree
and the outline in the view while typing; double-clicking the feature
reopens it and a new string redraws in place;
- a block with a through hole and fillets: faces separate by
orientation, fillets shade round, edges are drawn and hidden behind the
part;
- a half-profile beside a construction centerline: Revolve preselects
the centerline, shows the axis dashed and builds the expected tube
(4000π mm³).
- **Not verified by hand:** multi-edge selection and the red loop
marking; Windows and macOS were not run.
[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
The only use of Slic3r::create_thread in this file sits behind
!BBL_RELEASE_TO_PUBLIC && __WINDOWS__, so the include looked unused in
every configuration CI builds. Windows Debug and RelWithDebInfo builds
failed without it.
A Linux job configures without the precompiled header and runs clang-tidy over the C++ lines a pull request changes. The only check for now is misc-include-cleaner for missing includes; .clang-tidy is where further checks get enabled.
scripts/run_clang_tidy.sh (Linux, macOS) and scripts/run_clang_tidy.ps1 (Windows) run the same check locally: the same configure, the clang-tidy version pinned in scripts/clang_tidy_requirements.txt, and the same comparison against OrcaSlicer's main. They offer to install what is missing, or print the command to do it by hand.
* Remove Unused Project Includes and Forward-Declare Where a Type Is Only Referenced
Generated with include-what-you-use and applied conservatively. Only OrcaSlicer's own headers, the ones under src/ and tests/, are removed or forward-declared; standard-library and third-party includes are left alone. An include is removed only when both the Release and the Debug configuration leave it unused, never from inside a conditional block, and never from a file with platform-specific blocks, which only gain includes. Files whose only use of a header sits behind a feature or debug macro (libvgcode's OpenGL ES and marker code, the ARACHNE/TESTS_EXPORT_SVGS debug output) keep their includes.
clonable_ptr.hpp gains #pragma once; it had no include guard and was only safe while Config.hpp was its sole includer.
* Remove Unused Project Includes From Files With Platform-Specific Code
A Linux include-what-you-use run cannot see the code inside _WIN32, __APPLE__ or __linux__ blocks, so its verdict is only taken where nothing the removed header declares, directly or through what it includes, is named inside those blocks. Removals also have to hold in both the Release and Debug configuration and never touch a line inside a conditional block.
* Restore the libslic3r Precompiled Header and Direct Includes Lost in the Platform Pass
The platform-file pass treated pchheader.hpp as an ordinary header and
emptied it, and left GUI_Preview.hpp and 14 other files relying on
headers they no longer reached directly.
* Restore MainFrame.hpp in ParamsDialog.cpp for the Windows-Only Reparent Call
* Include Headers That Files Reached Through Ones the Cleanup Removed
* Drop Includes Duplicated by the Cleanup or by Main's Own Additions
* Leave PreciseSeam.cpp as Main Has It After the Precise Seam Rework
The Design view drew sinking outlines by looking up its bodies in the
plate's model, reading past the end of an object's volumes once a body
was committed. The Design canvas no longer draws sinking outlines.
Merged by /bot merge on behalf of @peachismomo (id 52488812).
Grants: resources/profiles/OrcaFilamentLibrary/filament/Elegoo, resources/profiles/OrcaFilamentLibrary.json, resources/profiles/Elegoo, resources/profiles/Elegoo.json
Head: 00276bf8ee
Commit to Plate now sends all visible bodies to Prepare as one object with a
part per body, so their relative placement survives. A dropdown beside the
button switches to Commit to Plate (as bodies), the previous one-object-per-body
behaviour, and the choice is remembered.
GLGizmoSlaSupports, GLGizmoHollow, GLGizmoFaceDetector, GLGizmoText and GLGizmoAdvancedCut were already left out of the build, and GLGizmos.hpp, the only header including some of them, had no includers. VoxelizeCSGMesh.hpp uses types that no longer exist, SLA/bicubic.h does not compile, and Utils/ProfileDescription.hpp is included nowhere. Their CMake and gettext source-list entries go with them.
Selections are drawn as opaque faces in the selection colour with a cased outline instead of a
translucent tint over the body, so they read on a body of any colour. Selecting a Feature tree
row lights the faces that feature made rather than its whole body, which also makes fillet and
chamfer rows highlight again.
* Add opt-in printer overrides for filament tool-change settings
Allow printer presets to define uniform ramming, loading, unloading,
cooling, purge, filament scripts and pressure-advance enable settings
without duplicating material presets. Apply overrides during preset
composition and FDM normalization, and expose the switch in Multimaterial.
Keep the feature disabled by default. Omitted or empty override vectors
preserve material settings; a single value applies to every filament,
including an explicitly empty script. Reject multi-value overrides.
Preserve empty float vectors across project serialization and initialize
empty nullable filament overrides before resizing them, preventing preset
cache generation from accessing an empty vector.
Include focused override tests and document the configuration semantics,
Prusa MMU3 integration and INDX tool-change behavior.
Co-authored-by: Codex <codex@openai.com>
* Add Prusa MMU3 and CORE One INDX profiles with shared material tuning
Add MK4 MMU3 and four-tool/eight-tool CORE One INDX printer definitions,
process presets and printer resources. Reuse ordinary MK4 and CORE One
printer/process inheritance while retaining device-specific startup,
shutdown, tool-change and wipe-tower behavior.
Move uniform MMU3 tip forming and INDX handling into machine filament
overrides. Keep MMU3 pressure advance and purge material-specific, retain
INDX material tuning, and share surviving materials with migration aliases
for retired MMU3 and XL tool-change copies.
Preserve unrelated Prusa filament identities, scalar value formats and
inheritance rather than applying broad profile cleanup.
Validation: Prusa profile checks and all 69 printer smoke slices passed.
The final cleanup preserved emitted commands with identical filament
selections.
Co-authored-by: Codex <codex@openai.com>
* Refresh filament controls after loading printer presets
Synchronize the plater filament controls after preset loading, even when the internal filament list already matches the nozzle count.
Co-authored-by: Codex <codex@openai.com>
* Fix nullable Z-hop overrides in Prusa filament variants
Represent empty overrides as nil for each inherited extruder variant so
the native profile loader preserves machine Z-hop settings.
Validation: full profile checks, native loading, and 1,115-printer slicing
sweep passed.
Co-authored-by: Codex <codex@openai.com>
* Separate Prusa profiles from machine-owned filament overrides
Retain profile tuning without unsupported machine override keys. Move supporting code, tests and override documentation into a separate feature change.
Co-authored-by: Codex <codex@openai.com>
* Default INDX tools to hardened high-flow nozzles
Use the High Flow variant for every INDX tool and its dedicated filament presets. Raise Generic PLA throughput to 28 mm3/s.
Co-authored-by: codex <codex@openai.com>
* Use normal filament-change lifts for INDX and MMU3
Avoid duplicate INDX retraction and account for its 12.5-second dock swap in print estimates.
Co-authored-by: codex <codex@openai.com>
* Set z_hop_types for the machine too
* Fix profile check failures in the Prusa CORE One filament presets
---------
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: SoftFever <103989404+SoftFever@users.noreply.github.com>
Co-authored-by: SoftFever <softfeverever@gmail.com>
* Add Pragostroj KINARB profile set
This adds the new Pragostroj vendor profile with KINARB 1HB and 2HB machine models, nozzle variants, common machine/process settings, and default material mappings. It also includes the corresponding filament and print presets for PLA, PETG, PP, and HIPS, covering the printer family’s standard profiles and tuning.
Each Feature tree row now carries Edit, Show/hide and Delete, and each
Bodies row carries Move, Show/hide and Delete. These act on that row
instead of on the selection. The eye shows a closed eye when the item
is hidden. Every clickable icon in the sidebar now highlights on hover.
Rename and Color now come first in the right-click menu, as items of
their own instead of inside Modify. This applies wherever they appear,
whether opened from the viewport or from a Bodies row.
Clicking an already-selected row no longer starts a rename; use F2,
the row's right-click menu, or the Rename command.
Restore slicing progress after notification reset
Ensure the cleared slicing-progress controller is recreated before its initial state transition, and calculate the Daily Tips size before positioning the popup.
perf: skip estimating curled walls when nothing reads them
The curled extrusion estimate ran whenever a region had overhang speed on,
which is the default, but only the slowdown for curled perimeters reads the
curled lines it produces, and that slowdown is off by default. The step now
also requires a region with the slowdown on, and clears the curled lines
when it skips the estimate, so none are left from an earlier slice.
Also fixes stale fan commands due to the stale curled lines on the reused layers.
Every file that included STEP.hpp, directly or not, got namespace fs = boost::filesystem at global scope, and 29 sources and three headers relied on it without saying so. Headers now spell out boost::filesystem, and each source that uses fs declares the alias itself.
* Fix CLI Crashes on Malformed Project, Assemble List and No-Input Runs
Four CLI paths indexed vectors without checking their size and crashed
with SIGSEGV on malformed input:
- A project inherits_group whose length is not the filament count plus
the process and printer entries was split by position. It is now
ignored with a warning, as if the project had none.
- An assemble list object with an empty filaments list passed validation
and was then read at index 0. It is now rejected as a config error, as
is a negative filament id.
- --slice N --arrange 1 on a project without plate metadata read the
missing plate data. It now falls back to the plate's own filaments,
like the other plate data reads.
- --assemble with no input model built an object with no volumes. It is
now rejected as invalid parameters.
A tests/cli script covers each case through the binary, since all four
live inline in CLI::run().
* Move the Assemble List Parser into libslic3r
Behaviour-preserving move of the --load-assemble-list JSON parser and
its plate/object structs from the CLI into libslic3r/Format/AssembleList,
so the format can be unit tested. The parser returns its own
AssembleListResult and takes the plate limit as a parameter; CLI::run
maps the result to the same exit codes as before. Every validation rule
and log message is unchanged.
Adds Catch2 coverage of the valid layout and each validation rule.
* Keep the Process and Printer of an inherits_group of the Wrong Length
A project whose inherits_group did not have one entry per filament plus
the process and printer entries was loaded as if it had none. The CLI
then looked for system presets under the names of the user presets,
found none and refused to slice a project that slices on main.
The group is now read as before: the process first, the printer last
and the filaments in between, up to the filament count. A filament
without an entry counts as a system preset. A group with fewer than two
entries is still ignored. The warning stays.
Release builds install each vendor as its preset cache alone. The
read-only preset load the CLI uses to resolve an inheriting user preset
passed allow_cache = false to keep caches from being written, which
also stopped them from being read, so every vendor fell back to JSONs
that are not installed and the CLI failed.
The flag now only gates writing: a read-only load reads caches and
writes none. The filament library is also read from its cache whenever
that is all that is installed, so a vendor updated over the air still
resolves against it.
* Refresh a CLI Project's Filament Settings From Their System Presets
The CLI loads a project's printer and process settings as the GUI does,
taking every key the project does not list as changed from the current
system preset, but it kept the stored filament values. A project saved
before a profile update then sliced with old filament values on the
command line and with the current ones in the GUI.
Every project filament that no loaded filament replaces is now resolved
by its system preset name and fed to the filament merge the up-to-date
path already uses, which keeps the keys listed in
different_settings_to_system and maps per-variant values onto the
preset's variants. This covers a plain run, --uptodate without
--uptodate-filaments, and the slots --load-filaments leaves empty. The
merge tells refreshed entries from loaded ones per entry instead of by
the global loaded-filament count, and the entries are kept in slot
order. A project filament saved under a name the presets have since
split per nozzle is resolved through the name conversion the GUI uses,
which PresetBundle now exposes.
* Check the Project Refresh Test's Result Directly
Shellcheck SC2181: test the checker's exit status in the if instead of
reading $? afterwards.
After undo, redo, New Design, a project load, a delete or a reorder, a sketch
profile picked beforehand stayed selected even though it was gone. The
right-click menu then offered "Sketch profile" over an empty design with Create
greyed out. Those operations now clear the selection.
The Confirm button no longer stays greyed in a sketch session after a card whose
preview was invalid has been closed.
Delete and reorder now wait while a sketch or constrain session, the Text dialog,
an Insert placement or the move gizmo is open, instead of editing whichever
feature took its place in the list.