Commit Graph
18405 Commits
Author SHA1 Message Date
SoftFever 41365736ff Fix the Windows build 2026-08-28 19:06:55 +08:00
SoftFever 7fc97a81bd Build only the OCCT and solver pieces the Design tab needs
SLIC3R_CAD=OFF now builds without SolveSpace or OCCT's ModelingAlgorithms
module, leaving the dependency set identical to upstream's, and the Design
tab's mate connector preference no longer appears in builds without the tab.
When the deps prefix and the project disagree about the option, the configure
fails naming the cause, rather than failing at link time or at first launch
on Windows. The Windows packaging step stages exactly the toolkits libslic3r
links.
2026-08-28 12:59:39 +08:00
SoftFever f693b8d9fe List the Design tab headers and drop the unrelated build changes 2026-08-28 12:06:37 +08:00
SoftFever 62f49bd105 Restore the upstream idle-loop dirty handling 2026-08-28 02:19:41 +08:00
SoftFever 0eae703030 Pass plate chrome suppression as a render argument 2026-08-28 02:07:25 +08:00
SoftFever 72639ee12a wrong place 2026-08-28 01:26:15 +08:00
SoftFever 806db473de Give the Design tab its own camera view
The Camera is Plater-owned and shared by every canvas, and Design sits
outside the panel switch that saves and restores it for Prepare,
Preview and Assemble — so orbiting in Design moved what the editor
tabs showed, and Design lost its own view on every switch. Trade the
live camera for a parked one on the way in and back on the way out, so
Design keeps its view the way Assemble already does.
2026-08-28 01:05:01 +08:00
SoftFever ba1df32e88 Reset the CAD document with the project, and track its changes
New Project and Open Project went through Plater::priv::reset, which
drops ModelObjects but not the Model-level recipe, and never touched
the Design panel's document at all — so the previous design stayed
loaded and its next edit wrote itself into the new project.

A design that has not been committed to the plate has no ModelObjects,
so the project also read as clean: no autosave, and no unsaved-changes
prompt before the reset threw the design away.
2026-08-27 23:35:18 +08:00
SoftFever a1110b0050 Revert unrelated Stealth mode and cloud login changes 2026-08-27 23:13:41 +08:00
SoftFever 1750c52211 Build the Design tab on first use instead of at startup
DesignPanel's constructor creates several hundred controls and its own GL
canvas, which every launch paid for whether or not the user ever opened the
tab. The notebook page is now an empty placeholder and the panel is built
into it the first time the tab is selected, so m_design_panel stays null
until then.

This also lifts the ordering constraint that had pushed the plater's
background colour and Hide() below the panel construction; they go back
where they were.
2026-08-27 22:50:30 +08:00
SoftFever 5a170520d3 refactor: rename SnapOrca references to Orca in CAD components to avoid confusion and update recipe versioning 2026-08-27 18:49:50 +08:00
SoftFever 0aeb6df122 Merge branch 'main' into cad-mainline 2026-08-27 17:06:37 +08:00
Ian Chua 3ab5157a49 Merge branch 'main' into feat/plugin-storage-api 2026-08-27 14:52:00 +08:00
Kris Austin 142c63ab0e build: clear 143 -Woverloaded-virtual warnings in GUI widgets (#15377) 2026-08-26 19:14:30 -03:00
SoftFever 5552ed6cf1 Keep mixed-color filaments intact when the extruder count changes (#15385)
* Keep mixed-color filaments intact when the extruder count changes

The extruder-count spinner resized the filament arrays in bulk at the tail,
which is where mixed-color slots live, so a new filament landed behind the
mix and the sidebar skipped a slot number. It now adds and removes one slot
at a time through the same calls the sidebar's +/- buttons use, so a new
slot opens ahead of the mixed tail and a removal renumbers object filament
ids, painted facets, custom g-code and mixed components rather than
clamping them away.

Drops the vector overload of set_num_filaments(), which this leaves without
callers.
2026-08-26 19:06:33 +08:00
Ian BassiandRodrigo Faselli 9dc9b42475 Pass closure state to fuzzy skin (#15378)
Update perimeter traversal to pass each extrusion's closed/open state into `apply_fuzzy_skin`. This lets fuzzy skin logic distinguish contours from closed loops when processing perimeters.

Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
2026-08-26 07:39:23 -03:00
Kris Austin 1e4b48c548 build: clear 227 warnings - dead private fields, malformed comments (#15376)
build: drop dead private fields, close malformed comments (227 warnings)

Clears 227 of the clang-cl warnings tracked in #15374, taking a full
Windows build from 1,491 to 1,264. Five of the six changes are in
headers, which are re-diagnosed in every translation unit that includes
them, so the count is large for a 14-line diff.

Tabbook.hpp: delete two private fields, unread since the 2022 import.
m_parent also shadowed wxWindowBase::m_parent.

GUI_Utils.hpp: the wxEVT_SYS_COLOUR_CHANGED lambda body is empty on
Windows, so its `this` capture is unused there. (void) this; leaves the
handler bound, which is what stops the event propagating.

DevFirmware.h: mark m_owner [[maybe_unused]]. The class is never
instantiated, and the file tracks BambuStudio, so this is the smallest
divergence.

Eight DeviceTab/ files, AMSItem.cpp and SelectMachine.cpp: block
comments malformed so that they read as a nested /*.

No behavior change. -Wcomment goes to zero, and only the three intended
categories move.
2026-08-26 07:38:52 -03:00
Valerii BokhanandIan Bassi 24967b543a Fix contour cleanup across coplanar triangles (#15366)
* Fix contour cleanup across coplanar triangles

Avoid generic collinear simplification after slicing. Skip only junctions created by shared edges between coplanar faces so contours stay stable without altering shallow geometry.

Fixes #15364

* Fix contour cleanup across coplanar triangles (code review fixes)

---------

Co-authored-by: Ian Bassi <ian.bassi@outlook.com>
2026-08-25 19:31:09 -03:00
Ian Bassi ea4a4a60f1 Refresh dynamic filament list on mixed slot changes (#15375)
Call update_dynamic_filament_list() alongside update_mixed_filament_list() in two places: after editing a mixed filament slot and when the filament count doesn't change (e.g., adding a mixed/virtual slot). This ensures per-feature filament lists reflect the updated blended colour and type without requiring a full filament count change.
2026-08-25 16:18:45 -03:00
Ian Bassi a5223279ac Fix uneven corner rounding in multiline infill (#15352)
* Skip straight-run splits in corner smoothing

Teach `CornerSmoother` to treat vertices that only continue a straight segment as part of the same leg instead of rounding them as corners. The smoother now keeps a three-point window so it can emit a corner only once both adjoining legs are known, which avoids unnecessary corner processing while preserving real turns such as hairpins.

* Add regression test for split-leg smoothing

Adds a FillCornerSmoothing regression test covering polylines with an extra collinear vertex in a straight run. The test ensures corner smoothing treats split and unsplit geometry identically, preventing inconsistent rounding radii in triangular/grid infill paths.
2026-08-25 12:46:34 -03:00
SoftFever 9e34dde632 Color mixing feature (#15347)
# Description

This PR ports the color mixing feature from BambuStudio.
The port is based on the previous work by @ianalexis in #15231.
This PR completes the port and fixes various bugs.

Several improvements were also made during the porting process.

WIP


# Screenshots/Recordings/Graphs

<!--
> Please attach relevant screenshots to showcase the UI changes.
> Please attach images that can help explain the changes.
-->

## Tests

<!--
> Please describe the tests that you have conducted to verify the
changes made in this PR.
-->

<!--
> A guide for users on how to download the artifacts from this PR.
-->

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
2026-08-25 22:10:49 +08:00
Kris Austin 56f9edc572 build: mark missing overrides and drop unused lambda captures (1,156 clang warnings) (#15334)
* chore: mark every declaration that overrides a base virtual

clang-cl reports 42 member functions across 28 files that override a
base virtual without being marked `override`, inside classes that
already mark their other overrides. That is every occurrence of
-Winconsistent-missing-override in the tree, so the category drops to
zero and -Werror=inconsistent-missing-override becomes available as a
guard against it coming back.

Behaviour is unchanged. Each keyword goes only where clang had already
resolved the declaration to a base virtual, so it records what the
compiler already worked out and cannot affect overload resolution or
dispatch. If any of these signatures had not really overridden a base
method, the build would have failed rather than warned.

Where a declaration already carried `virtual` it is left alone and the
keyword appended, matching the surrounding declarations. Plain
`override` is used rather than the wxWidgets `wxOVERRIDE` macro, which
wx/defs.h defines as `override` beneath a comment marking it obsolete,
and which the rest of src/slic3r already avoids by 1742 occurrences to
113.

A full clang-cl build takes -Winconsistent-missing-override from 1,146
warning lines to 0. Those 42 declarations produce that many lines
because a header is re-diagnosed in every translation unit that
includes it. CalibrationWizardStartPage.hpp alone accounts for 336 of
them from 4 declarations.

* chore: drop unused lambda captures in GUI/Widgets

clang-cl reports 10 lambda captures in src/slic3r/GUI/Widgets that are
never read. Removing them changes nothing at runtime.

Every capture removed is `this` or a raw pointer. clang does not report
a capture whose type has a non-trivial destructor, since such a capture
can be held purely for its effect on an object's lifetime, so nothing
that owns or extends a lifetime is touched. The std::weak_ptr captured
beside the removed `this` in MultiNozzleSync.cpp stays.

This clears the category in GUI/Widgets only. A full clang-cl build
takes -Wunused-lambda-capture from 312 warning lines to 302, leaving
235 sites in other directories for a follow-up.
2026-08-25 08:18:48 -03:00
Ian Chua 390e47a8c6 Merge branch 'main' into feat/plugin-storage-api 2026-08-25 13:49:04 +08:00
yw4z 2f9ef86e97 match style of dialog buttons 2026-08-25 00:04:14 +03:00
yw4z fbe4cdff23 fix mixed filaments area cannot be hidden 2026-08-24 23:07:11 +03:00
yw4z a3231aa723 rebuild menus from scratch to remove duplicate item check and match "delete" item order 2026-08-24 22:02:47 +03:00
yw4z ce75a66e7c fix duplicate decompose menu item 2026-08-24 21:38:51 +03:00
Valerii Bokhan 524fd5e9c0 Fix: resolve 23 MSVC compiler warnings (#15280)
* fix: resolve MSVC compiler warnings and build error

C4101 - unreferenced local variables:
  - STEP.cpp, FilamentGroup.cpp: remove unused catch variable 'e'
  - GLGizmoMeasure.cpp: remove unused 'direction_on_model'
  - PartPlate.cpp: remove unused 'origin1, origin2'
  - DevStatus.cpp: suppress unused 'e' via (void)e

C4005 - macro redefinition:
  - Wrap NOMINMAX defines in #ifndef guards (OrcaSlicer.cpp, Preset.cpp,
    SupportTreeBuilder.cpp, OpenVDBUtils.cpp, GUI.cpp)
  - Remove conflicting DESIGN_INPUT_SIZE redefine in DownloadProgressDialog.cpp

C4172 - return address of local/temporary:
  - Config.cpp: return static const double instead of temporary 0

C4996 - deprecated API usage:
  - ImGuiWrapper.cpp: use GetText().Length() instead of GetTextLength()
  - OrcaCloudServiceAgent.cpp: replace deprecated wxPATH_NORM_ALL with
    explicit flags matching old default behavior
  - ASCIIFolding.cpp: replace deprecated std::wstring_convert/codecvt_utf8
    with boost::locale::conv::utf_to_utf (already used in same function)

C2440 - build error from deprecated wxTipWindow constructor:
  - Button.hpp/cpp: replace raw wxTipWindow* with wxTipWindow::Ref (weak
    reference). Ref auto-nulls when the tip window closes, eliminating
    the manual Bind(wxEVT_DESTROY) handler. delete uses operator->() to
    access the raw pointer since Ref is non-owning

* fix: avoid duplicate GetText() call in ImGuiWrapper clipboard handler

Capture wxTextDataObject::GetText() result in a local variable instead
of calling it twice (for .Length() check and into_u8()). GetText()
returns wxString by value, so this avoids an extra allocation/copy.

* fix: resolve MSVC compiler warnings (code review fixes)

* fix: resolve MSVC compiler warnings (code review fixes)
2026-08-24 15:37:47 -03:00
Tommaso BianchiandClaude Opus 5 3fd5c3353a A reference is a reference whatever feature holds it
Port of snaporca 1bb9825db0. Four defects from an independent 20-agent audit,
each verified in the code first; two further findings from the same report were
verified OUT and are not in this commit.

remove_feature()/move_feature() remapped Extrude::sketch_ref and a Mate's two
connectors and nothing else, leaving seven of the nine index-bearing fields —
sweep_path_ref, loft_profile_refs[], pattern_curve_sketch, rib_sketch_ref, and
sketch_ref on Revolve, Sweep, Rib and the Surface* family — pointing at whatever
slid into the slot. Quiet by construction: the shifted index still names a real
feature, recompute() succeeds, the solid is built from the wrong profile. The
comment above the loop already required "EVERY field holding a feature index"; the
code under it handled two, because a type switch is only correct on the day it is
written. for_each_feature_ref() visits the FIELDS instead, so a feature type added
later is covered the moment it reuses one. plane_base and axis_plane_a/b are
excluded on purpose and documented at the helper — they encode an ordinal into the
datum-plane list, not an index into features[], and are filed separately. The
delete cascade got the same field-based treatment.

The regression test was run against the pre-fix code to prove it bites: all three
sections fail there, and move_feature returns TRUE while leaving sketch_ref == 1
where it must be 0 — success with the wrong answer, which is what makes this class
expensive.

apply_constraint, commit_entity_constraints and delete_constraint mutated the
recipe with no checkpoint() and no sync_recipe_to_model(), alone among seventeen
mutation sites in that file: Ctrl+Z reached past the constraint edit and discarded
unrelated work, and saving persisted the pre-constraint blob. A rejected constraint
now calls abandon_checkpoint() rather than leaving an undo step that does nothing.

MCP: params["generation"].get<uint64_t>() sat outside the try inside a bare
CallAfter lambda, so one malformed string terminated the process through the wx
event loop; it is type-checked now and the lambda lets nothing escape. The socket
bound with no mode of its own in a world-writable directory — umask around bind()
plus chmod, and it refuses to listen rather than listen wide. The reply write is no
longer a bare write(), which could SIGPIPE the app when a client hung up.

Kernel suite on this fork: 190 cases / 2562 assertions, green. GUI target compiles.
The full ladder gate ran on snaporca (ALL LADDERS HELD — gestures 98/98, offer
108/108, corpus and corpus-scale green) and fork-check parity holds at 17 identical
/ 8 diverging as expected, which is what makes that gate transferable here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MrMzTpAf78U4NG2M8jfvHY
2026-08-24 19:00:45 +02:00
SoftFever 0fa25acda8 Match OrcaSlicer's color theme in the color-mixing UI 2026-08-25 00:47:25 +08:00
SoftFever 55812a7a8d Merge branch 'main' into color-mixing 2026-08-24 16:26:33 +08:00
SoftFever e342698d8e Update sublayer option check. Add validation warning for gradient mixed filament without sublayer mixing 2026-08-24 15:30:02 +08:00
Tommaso Bianchi 6e7f6429fa A body carries its own name, because a body is not its first feature
User report 2026-08-23, and it is right: "you have renamed the feature extrusion,
not the body. i clicked rename on the body feature tree and the feature extrude
changed name. this means that you consider the extrusion = the body. this is very
far from truth as a body can contain several extrusions."

That is exactly what the previous commit did. It resolved a selected body to
CadBody::source_feature and renamed THAT feature, on the reasoning that a body has
no name of its own. The reasoning described an implementation detail — CadBody::
name is derived and restamped on every recompute — and mistook it for the user's
model. An Extrude, a Cut and a Fillet all land on the same body: the maker is one
operation in its history, and renaming it renames the wrong object.

A body now has a name of its own. CadBody::user_name, set only by a rename, is:
  - carried across recompute() by body index, next to the per-body colour override
    and under the same index contract the GUI already relies on for visibility and
    Move — without which a name would survive exactly until the next feature;
  - written into the recipe, because bodies are recomputed and never serialised, so
    a name has nowhere else to live and would otherwise vanish on reopen;
  - shown on the Bodies row ahead of the derived maker name, as "Body N — name",
    with the number still leading because every status line, the interference
    report and the mate errors identify a body that way.

The recipe block is APPENDED after the variables block rather than given a version
bump. A build that predates it reads features and variables, returns, and never
looks at the trailing bytes — so yesterday's projects open here and today's
projects still open there. A bump would have cost every project written today its
readability by the previous build, for one optional field.

Renaming a FEATURE is unchanged. The feature tree renames features; the Bodies
list renames bodies; neither reaches into the other.

WHAT THIS COST, and why it is written down. Getting here took two wrong turns
inside one fix, both mine:

  1. UnselectAll() -> Unselect(). Both trees are wxTR_SINGLE, where UnselectAll()
     — the MULTI-selection call — does nothing. That was the one-word reason the
     rename had been vetoed everywhere (BEGIN_LABEL_EDIT refuses while
     tree_body_selection() >= 0). Fixing it turned a pair of harmless no-ops into
     a real loop: the two lists clear each other so "the target" is unambiguous,
     so clicking a body row ran apply_body_row -> m_tree->Unselect() -> the feature
     tree's SEL_CHANGED -> m_parts->Unselect(), which cleared the row just clicked.
     The handler now clears the other list only when it actually holds a selection.
  2. Trusting a screenshot taken after a polluted run. A leftover Rib card had
     shifted the whole panel, so a click measured against it landed nowhere near
     the row. Relaunch, then measure.

VERIFIED, on the rig and in the kernel:
  body renamed          ('Extrude', user_name=False) -> ('Bracket', user_name=True)
  features untouched    ['Sketch', 'Extrude'] before and after
  survives a recompute  add a Hole to the same body: features become
                        ['Sketch', 'Extrude', 'Hole'], body stays 'Bracket'
  survives the recipe   serialize -> deserialize -> 'Bracket'

New kernel test "a body carries its own name, through recompute and the recipe"
pins all three properties; the suite is 189 cases / 2547 assertions.

Gate green: ALL LADDERS HELD — offer table matches the atlas, kernel suite,
engine rungs 1-8, 977-sheet corpus + the heaviest sheets, gesture ladder 98/98,
offer ladder 108/108.
2026-08-23 19:09:17 +02:00
Tommaso Bianchi 0ac9ac91f7 A body can be renamed, and the one-word reason it could not
User report 2026-08-23: "clicking on a body row in feature tree, I cannot find
rename on right click", then "still i cannot rename body1 in custom name".

TWO SEPARATE CAUSES, one in data and one in a single method call.

THE MISSING ROW WAS DATA. The `rename` verb's accepts list in the tool atlas was
["sk_loop"] alone, so the offer built for a selected BODY carried no Rename row.
Right-clicking a body row already opens the offer — that is the designed gesture,
bound on m_parts as wxEVT_TREE_ITEM_MENU — so the menu the user was looking at
was the right menu, and it was simply missing the verb. accepts is now
["sk_loop", "body_solid"], the generated table regenerated with it (the accept
mask moves 0x00004000 -> 0x00004080), and the offer trace confirms the row:
"[OFFER] row=7 Modify > rename".

THE RENAME ITSELF WAS BLOCKED BY UnselectAll(). Both trees are wxTR_SINGLE, and
wxTreeCtrl::UnselectAll() is the MULTI-selection call: on a single-selection tree
it leaves the row selected. So every path that tried to open the label editor
while a body row was selected hit the BEGIN_LABEL_EDIT guard — which vetoes while
tree_body_selection() >= 0, the rule that stops a body taking a name it cannot
keep across a recompute — and the editor never opened. Unselect() is the call
that works, and it fixes every route at once.

That took five attempts, four of them wrong, and the reason they were wrong is
worth more than the fix: each one addressed a plausible cause that the evidence
did not actually support — the popup's nested event loop, keyboard focus,
deferring with CallAfter, dispatching through a different verb. What settled it
was a DISCRIMINATOR rather than another fix: pressing F2 on a selected body row
takes the same handler with no menu and no nested loop. F2 failed identically,
which ruled out every menu-shaped theory in one measurement and left only the
state the veto reads.

A body still has no name of its own — it is recomputed from the recipe on every
change and CadBody::name is derived from the feature that builds it — so the verb
resolves the body to CadBody::source_feature and renames THAT, saying so on the
status line: "A body takes its name from the feature that makes it — renaming
'Extrude'". The Bodies row now reads "Body 1 — Extrude" so the rename is visible
where it was made; the positional "Body N" leads, because every status message,
the interference report and the mate errors identify bodies that way. Confirmed
as the wanted format by the user.

Also here, from the same report: the Bodies card keeps its own action row (Move,
Show / hide, Delete, Colour), and the competing context menu an earlier pass had
added to body rows is REMOVED — right-clicking a body belongs to the offer, and
two menus on one gesture is how the offer ended up being blamed for a veto.

Verified on the rig, both routes, with a body selected:
  F2 on the body row        -> ['Sketch', 'Extrude'] became ['Sketch', 'Base block']
  the offer's rename verb   -> {'applies': True, 'dispatched': True,
                                'selection_kind': 7, 'ok': True} and the same rename

Gate green: ALL LADDERS HELD — offer table matches the atlas, kernel 188 cases /
2532 assertions, engine rungs 1-8, 977-sheet corpus + the heaviest sheets,
gesture ladder 98/98, offer ladder 108/108.

RIG DISCIPLINE, repeated twice in one session and now written down: ladder-all.sh
does not relaunch the app, so hand-driving the rig immediately before a gate
leaves state its reset_document() cannot clear — both times the first rung drew
nothing and reported "sides []", which reads exactly like a broken rectangle
tool. Relaunch before gating.
2026-08-23 18:15:11 +02:00
Ian Bassi ea376e858c Show move length in Previewr panel (#15326)
Adds a new "Length" row to the sequential marker position popup in GCodeViewer and updates row capacity accordingly.
For arc commands (G2/G3) that are split into multiple vertices, it now sums segment distances across vertices with the same gcode_id so the displayed value reflects the full move length instead of a single chord.
2026-08-23 12:18:22 -03:00
Ian Bassi 877180829c Unify colinear simplify tolerance in Arachne (#15314)
Introduced a shared `colinear_vertex_tolerance()` helper in `ExtrusionLine.hpp` and updated both simplify paths (`ExtrusionLine.cpp` and `WallToolPaths.cpp`) to use it instead of duplicated hardcoded `0.005` scaled thresholds. This keeps the near-colinear early-out tied to `SCALED_EPSILON` (rounding-noise scale) and avoids unintended curve decimation from larger tolerances, while documenting the geometric impact in code.
2026-08-23 12:18:06 -03:00
Tommaso Bianchi b0657fb2c9 The row menu carries the whole row, and Move body goes where bodies live
Two decisions from the user, 2026-08-23, after the first pass at making rename
reachable.

ONE SURFACE CARRIES THE VOCABULARY, and it is the row's own menu: Rename (F2),
Edit, then Move up, Move down, Show / hide, then Delete. Offered as a choice
between completing the menu or completing the header icons; the menu won because
the element you click answering with what applies to it is this fork's charter,
and because a menu grows without spending an icon nobody recognises. The header
icons stay exactly as they are — a quick bar for the common three — so nothing
that worked yesterday moved.

The menu is grouped rather than listed: what the row IS (name, contents), where
it SITS (order, visibility), and what removes it. Right-click SELECTS what it
points at before opening, so the menu can never act on a row other than the one
under the cursor.

MOVE BODY LEAVES THE FEATURE-TREE HEADER. It never belonged there: that header
sits over the FEATURE tree, and the button had to guess its subject from
whatever happened to be selected — a feature row got answered with "Select a
body to move it", an instruction about a different kind of object in a list that
does not contain one. A body now has its own action row on the Bodies card:
Move, Show / hide, Delete, Colour. The last three are deliberate COPIES of
feature-tree actions, not a reorganisation: a body row is a different subject,
and someone working in the Bodies list should not travel to another card to hide
or recolour what they have just selected. Each handler already resolves the body
row itself (on_toggle_visibility, on_delete_body, on_set_body_color), so the
card gives them a home and decides nothing.

The offer already carried Move for a selected body (verb `transform`, accepts
body_solid), so that half of the requirement was in place and is untouched.

One piece of the old button was function, not clutter: it also scaled imported
Text/SVG artwork, which IS a feature-row action. That moved to the row's own
menu as "Scale artwork", shown only on a row that has imported regions — so the
capability survives the split instead of disappearing with the button.

Verified on the rig, by the gestures themselves: right-click a row -> the six
items in their three groups; choosing Move down turned ['Sketch1', 'Sketch2']
into ['Sketch2', 'Sketch1']; and with a body present the Bodies card shows its
four actions while the feature header no longer shows Move.

Gate green: ALL LADDERS HELD — offer table OK, kernel 188 cases / 2532
assertions, engine rungs 1-8, 977-sheet corpus + the heaviest sheets, gesture
ladder 98/98, offer ladder 108/108.

RIG DISCIPLINE, learned the expensive way in this session: ladder-all.sh does
NOT relaunch the app, so hand-driving the rig immediately before it leaves state
the ladder's reset_document() does not clear — here the first rung drew nothing
at all and reported "sides []", which reads exactly like a regression in the
rectangle tool. Relaunch the app before a gate, and re-run before believing a
failure that appears in rung one.
2026-08-23 16:53:43 +02:00
SoftFever 2b1499a087 clean up comments 2026-08-23 22:43:41 +08:00
Tommaso Bianchi 3d3324d663 A feature-tree row can be renamed by someone who does not already know F2
User report 2026-08-23: "on feature tree, i cannot rename sketch name".

The rename was not broken. Verified on the rig before changing anything: select
the row, press F2, type, Enter — Sketch1 becomes Base, the name reaches
m_doc.features[idx].name and sync_recipe_to_model() persists it. The offer's
btn:rename verb does the same. What was missing was any way to find that out.

Everything a person would try did something else:
  - the pencil in the section header is EDIT (on_edit_feature)
  - a double-click fires wxEVT_TREE_ITEM_ACTIVATED, which is also Edit
  - none of the seven header icons renames
  - right-clicking a row did nothing at all
and the comment above the label-edit handlers claimed a "slow double-click"
renames, which does not survive wxGTK: the activation wins and the sketch opens
for editing instead. So the only route was an undocumented function key, and the
report is exactly right from where the user stands.

The row now answers the gesture people actually use on a named row: right-click
gives Rename (F2) / Edit / Delete, with Rename opening the in-place editor on
that row. Right-click SELECTS what it points at first, so the menu can never act
on a different row than the one under the cursor.

And selecting a row now says what the row can do: "Sketch1 selected — F2 or
right-click renames it, double-click edits it". Cheaper than a tooltip nobody
hovers, and it uses the status line that already exists for exactly this.

A note on the surface, since it is a design call: the CANVAS right-click is the
offer, this fork's single adaptive menu, and this is not that. A tree row is a
different surface, and its menu is three items about the row. Routing tree rows
through the offer would mean teaching the offer a selection kind that is not
geometry, which is a larger change and not what this report needed.

Verified on the rig by the gesture it names: right-click the row, choose Rename,
type, Enter -> ['Sketch1'] becomes ['Base profile'] in describe_scene.

Gate green: ALL LADDERS HELD — offer table OK, kernel 188 cases / 2532
assertions, engine rungs 1-8, 977-sheet corpus + the heaviest sheets, gesture
ladder 98/98, offer ladder 108/108.
2026-08-23 16:21:23 +02:00
SoftFever 7934814077 fix wrong size of the last swatch of each row in Mixing Recommendations 2026-08-23 22:11:49 +08:00
SoftFever 4a32a9e066 Match mixed filament swatches to the editor's gradient preview
The sidebar Mixed Filament list, the extruder icons, the color painting
gizmo and the canvas filament bar now show the same bottom-to-top fade the
Edit Mixed Filament preview shows, custom gradient curves included, instead
of a horizontal fade between the two component colours. Ordinary and vendor
multi-colour filaments are drawn exactly as before.
2026-08-23 22:11:49 +08:00
SoftFever ff35dacf4c Fix UI hanging on Mac 2026-08-23 22:11:49 +08:00
SoftFever 6f32d59997 Fixed an issue that gradient color button in color painting gizmo don't have number 2026-08-23 22:11:49 +08:00
SoftFever f02423074c Warn about mixed color sublayer when adding height ranges 2026-08-23 22:11:49 +08:00
SoftFever 38d51783ae Refresh the mixed filament list when a component preset changes 2026-08-23 22:11:49 +08:00
SoftFever af5397d678 Close the single-extruder mixed filament warning by type 2026-08-23 22:11:49 +08:00
SoftFever 9985688b5b Blend mixed slots in the machine-send and AMS-sync thumbnails 2026-08-23 22:11:49 +08:00
SoftFever d27766aff0 Reject a mixed filament as the wipe tower filament 2026-08-23 22:11:49 +08:00
SoftFever cfeca9b9ff Hide mixed slots from the support and wipe tower filament dropdowns 2026-08-23 22:11:49 +08:00
SoftFever 716bba53df Refuse to slice a broken mixed filament 2026-08-23 22:11:49 +08:00