* Fix incorrect early exit for CLI mode no-support preventing parameters from being read
* Use PartPlate's m_height to allow CLI to perform proper BuildVolume check
* Add safeguard against extruder_pintable_heights and extruder_areas vector size mismatch
* Preserve printable_height precision in PartPlate/PartPlateList
* Fixed multiple BuildVolume warning issue, and keep check_outside diff minimal
* build: enable /Zc:lambda for MSVC
MSVC keeps its legacy lambda processor under /std:c++17, which rejects
reading a constexpr constant inside a lambda that does not capture it
(C3493). No other compiler requires that capture, and clang reports it as
an unused one, so the two cannot both be satisfied without the flag.
/Zc:lambda selects the conforming lambda parser that clang and GCC
already use. It is implied by /std:c++20 and /permissive-, so it is only
needed while we are on C++17. clang-cl is conforming already and does not
take the flag.
It requires VS2019 16.8, so build_release_vs.bat now says 16.8+.
* build: clear 237 unused lambda capture warnings
236 captures across 81 files, 142 of them `this`. Removing an unused
capture changes no behavior; clang does not report a capture whose type
has a non-trivial destructor, so nothing held only to extend an object's
lifetime is in this set.
Nine of them are the second half of the warning, "is not required to be
captured for this use", where the capture is a const or constexpr value
the body does read. Those depend on the /Zc:lambda change in the previous
commit. One of them, in FillRectilinear.cpp, had been worked around with
an #ifndef __APPLE__ guard around the capture list, which is now gone.
GUI_ObjectTableSettings.cpp captured its reset button only to read it
inside #ifdef __WXOSX_MAC__. That branch now takes the button from the
event it is already handling.
* build: fail configure on MSVC older than 19.28 instead of dropping /Zc:lambda
cl.exe answers an unrecognized /Zc: sub-option with warning D9002 and keeps
going, so on VS2019 before 16.8 the flag is silently ignored and the build
instead dies with C3493 in FillRectilinear.cpp, nowhere near the cause.
* fix: delete three locals that are now unused
Their only remaining use was the lambda capture this branch removed. The
Clang builds set -Wno-unused-variable, so the build never flagged them.
---------
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
* build: remove std::move that blocks copy elision
std::move wrapped around a temporary, or around a local being returned,
stops the compiler constructing it in place. Each edit is the fix clang
suggests, which is to delete the std::move call and keep its argument.
Three of the 39 sites save a move, the two return std::move(local) in
Print.cpp and TreeSupport.cpp:2749. The rest are equivalent either way
and match how the codebase already writes this elsewhere.
Clears 39 -Wpessimizing-move warnings.
* build: drop null checks on references and this
A reference cannot be bound to null and this cannot be null, so the
compiler folds these conditions to true and drops the guard. Seven are
if (&bitmap && bitmap.IsOk()), where IsOk() already does the work; two
test this directly. The guarded code runs either way, so removing the
dead operand changes nothing.
Clears 11 -Wundefined-bool-conversion warnings.
* 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.
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.
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.
Mixed-colour slots are virtual and never flushed. Guard auto_calc_flushing_volumes_internal against them as BambuStudio does, and make the flushing dialog's default matrix and the sidebar 'modified' comparison physical-only so the untouched mixed rows no longer count as a user edit and the Re-calculate result matches the physical-only table.
Selecting the web Device tab loaded the printer's web UI from the selected discovered machine
when the preset carried no host. That arm was lost merging main into this branch — two of the
three Plater.cpp hunks from #15134 survived, this one did not — leaving the tab blank, since
PrinterWebView starts on an empty URL and nothing else navigates it.
Fix Windows crash in Replace all with 3D file
Keep the replacement result message as wxString and substitute the volume
name directly.
On Windows, wxString::ToStdString() cannot encode the Unicode status icon
through the active ANSI code page and returns an empty string. Passing that
empty string to boost::format with a volume-name argument throws
boost::too_many_args and exits OrcaSlicer.
Replace per-printer auto-activation
(is_current_printer_agent_plugin)
with a global experimental AppConfig
toggle, default off: legacy
print-host behavior is unchanged
until the user opts in. The toggle
drives device-tab routing, print
button defaults, connect-button
visibility and sidebar layout, and
dedups machine-select dialog opens.
* For dialog without explicitly `SetMinSize`, we should use `SetSizerAndFit` instead, otherwise the dialog will not show correctly on GTK3. (OrcaSlicer/OrcaSlicer#14561)
- and if `SetSizer` is called before the full layout has been built, then an extra `SetSizeHints` should be called before layout/fit so the min size can be properly set automatically based on children's min sizes accordingly.
* Fix GTK3 dialog min size: SetSizer → SetSizerAndFit for dialogs without explicit SetMinSize
Replace SetSizer() with SetSizerAndFit() in 11 dialog constructors that
neither call SetMinSize() nor SetSizeHints(), ensuring proper minimum
size propagation from child widgets on GTK3.
SetSizerAndFit internally calls sizer->SetSizeHints(window), which
sets the window's minimum size based on children — the same fix
applied to ProjectDropDialog in 8a7662083e.
Also drop sizer->Fit(this) calls where present, since they only
resize but don't set the min size hint needed by GTK3.
Co-Authored-By: Claude <noreply@anthropic.com>
* Update code style
* Update TroubleshootDialog.hpp
* Fix unsaved preset dialog layout
* Fix MsgDialog layout
* Fix other 3 instances in MsgDialog.cpp
* Fix a few more instances
* Fix printer option dialog too big on Windows
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: yw4z <ywsyildiz@gmail.com>
## Problem
On H2C (carousel) printers, the wipe tower purge volume calculation in
`_make_wipe_tower()` tracks filament state **per-extruder** (2 slots).
Since H2C has up to 7 carousel nozzle slots on a single extruder, all
filaments sharing that extruder are collapsed into one tracking slot.
This causes:
Test:
[5cubes.3mf.zip](https://github.com/user-attachments/files/30092551/5cubes.3mf.zip)
- **Massive redundant AMS flushing** every filament change on the
carousel triggers a full purge against the "previous" filament, even
when the target nozzle slot already has the correct filament loaded
- **60.9g total weight** instead of ~17g (**3.5× material waste**)
- **3h09m print time** instead of ~1h57m (**60% longer**)
## Root Cause
The code uses `nozzle_cur_filament_ids[extruder_id]` (a 2-element array)
to track which filament was last used for each extruder. BambuStudio
uses `NozzleStatusRecorder`, which tracks per `group_id` (physical
carousel slot 0..6).
## Changes
| File | Change |
|---|---|
| `Print.cpp` | Replace `nozzle_cur_filament_ids` with
`NozzleStatusRecorder`. Use `get_nozzle_for_filament()` to resolve the
physical carousel slot per layer. Select `filament_prime_volume_nc` for
nozzle changes, `filament_prime_volume` for filament changes. |
| `PrintConfig.hpp` | Add `ConfigOptionFloats filament_prime_volume`
(per-filament EC prime volume, missing from upstream but present in BBS
and H2C profiles) |
| `PrintConfig.cpp` | Register `filament_prime_volume` with default
45mm³ (matching BBS) |
| `Preset.cpp` | Add `filament_prime_volume` to preset keys |
Also includes `tests/compare_analyzer/` - two standalone Python tools
for G-code slice comparison and temperature timeline analysis (stdlib
only, no dependencies).
## Test Results (5-color H2C Hybrid print, same 3mf project)
| Metric | Upstream (broken) | **Fixed** | BBS (reference) |
|---|---|---|---|
| **Total weight** | 60.90g | **16.20g** ✅ | 17.47g |
| **Print time** | 3h09m | **1h57m** ✅ | 1h51m |
| **Filament changes** | 105 | 105 | 140 |
| **Tool changes** | 35 | 35 | 35 |
| **Critical discrepancies vs BBS** | ⚠️ YES | ✅ None | — |
## Analysis Tools (`tests/compare_analyzer/`)
Two standalone Python tools (stdlib only, no dependencies) for deep
G-code comparison:
- **`compare_slices.py`** - comprehensive .3mf slice comparison:
filament usage, nozzle mapping, tool change sequences, prime tower
analysis, temperature timeline, retract parameters, and automatic
critical discrepancy detection (weight/time anomalies)
- **`show_temp_plot.py`** - interactive HTML temperature timeline
plotter for visualising heater profiles during multi-nozzle prints
(supports single-file and side-by-side comparison)
Usage:
```bash
python3 tests/compare_analyzer/compare_slices.py file1.3mf file2.3mf --labels "Upstream" "Fixed"
python3 tests/compare_analyzer/show_temp_plot.py file1.3mf file2.3mf
```
## Screenshots
### OrcaSlicer Upstream (unfixed) - 60.90g, 3h09m
<img width="1512" height="982" alt="Screenshot 2026-07-16 at 15 22 58"
src="https://github.com/user-attachments/assets/3efb2bff-ff1e-43db-9669-feafa5921b51"
/>
### OrcaSlicer Fixed - 16.20g, 1h57m
<img width="1512" height="982" alt="Screenshot 2026-07-16 at 15 23 08"
src="https://github.com/user-attachments/assets/c1d36dc5-9b01-4691-80ef-7364540e1f4e"
/>
### BambuStudio Reference - 17.47g, 1h51m
<img width="1512" height="982" alt="Screenshot 2026-07-16 at 15 24 52"
src="https://github.com/user-attachments/assets/5c0b11e2-64f4-40e9-8c7c-3f42519786c3"
/>
### Temperature Timeline: Upstream vs Fixed
<img width="1511" height="829" alt="Screenshot 2026-07-16 at 15 23 35"
src="https://github.com/user-attachments/assets/926c2cb5-dfd4-4ce0-bb40-82e6165eb134"
/>
### Temperature Timeline: Fixed vs BBS
<img width="1512" height="825" alt="Screenshot 2026-07-16 at 15 23 51"
src="https://github.com/user-attachments/assets/85c72dda-e779-4aa6-8118-fb17e5f8482d"
/>
## Compatibility
Safe for non-carousel printers: when each extruder has a single nozzle,
`group_id == extruder_id`, so `NozzleStatusRecorder` behaves identically
to the original per-extruder tracking. The `filament_prime_volume`
default (45mm³) matches the existing global `prime_volume` default.
## Reference
BambuStudio `Print.cpp` `_make_wipe_tower()` L3341-3392 -
`NozzleStatusRecorder` pattern.
Give previously-bare panels a keyed background so the existing dark-UI walk
can theme them. Runtime-created widgets (HMS items, device firmware/nozzle
panels) route their whole subtree through one UpdateDarkUIWin(this) call
instead of per-widget darkModeColorFor, which also themes their child text
and follows live light/dark switches. Extruder-card chips re-apply their
colours from Sidebar::sys_color_changed so a live switch updates them too.
Replace hand-rolled nozzle type comparison + Hybrid hack with
BBS-style NozzleGroupInfo comparison in check_ams_status_impl.
Previous approach: direct nozzle_volume_type == printer_flow_type
with a Hybrid tolerance lambda. This either suppressed the dialog
entirely (Hybrid always matched) or showed it on every Preview switch.
New approach (matching BBS):
- Build preset NozzleGroupInfo from extruder_nozzle_stats config
- For Hybrid presets: expand into per-type counts (Std#N, HF#M)
- nozzle_count==0 (never synced): dialog appears for first sync
- nozzle_count>0 (after sync): compare with printer GetNozzleGroups()
- Counts match → dialog suppressed on Prepare↔Preview switches
Safe for all multi-extruder printers (H2C, H2D): non-Hybrid presets
use single NozzleGroupInfo per extruder. Single-extruder printers
exit at is_multi_extruders() guard before reaching this code.
Reference to BBS: BambuStudio/src/slic3r/GUI/Plater.cpp
is_extruder_stat_synced() line 16642