set_live_printer_agent centralizes
the swap: deselect the machine,
clear stale sidebar state and the
previous agent's Other Devices, then
install the new agent (or null when
its provider vanished). Plugin
load/unload callbacks refresh the
dropdown and re-run agent selection.
load_last_machine no longer falls
back to the first available machine.
get_user_print_info()'s HTTP fetch can run on a worker thread (e.g. BindJob),
but parse_user_print_info() mutates userMachineList (insert/erase/delete
MachineObject). on_machine_alive (SSDP) mutates the same maps on the UI thread
without locking, so parsing off-thread races the map and frees MachineObjects
out from under it -> heap corruption.
Keep all device-list mutation on the UI thread: parse inline when already on
the main thread, otherwise marshal via CallAfter so it stays serialized with
on_machine_alive.
* Add wxInspector dep
* Initial intergration of wxInspector
* docs: add wxInspector plugins design spec
Design spec for two wxInspector plugins (DPIAware + CustomWidgets) that expose
OrcaSlicer's custom control properties in the inspector property grid.
Covers: DPIAware scale-factor properties, Button, CheckBox, TextInput,
SwitchButton, ProgressBar, Label, and LabeledStaticBox.
* docs: add wxInspector plugins implementation plan
6-task plan covering: source changes to existing widget headers,
DPIAwarePlugin, CustomWidgetsPlugin, registration helper,
MainFrame/CMake wiring, and build verification.
* feat: add getters/setters for wxInspector plugin access
Add minimal public accessors to DPIAware (set_scale_factor,
set_prev_scale_factor, set_em_unit, force_rescale), Button
(GetStyle, GetType, IsSelected), CheckBox (IsHalfChecked),
TextInput (GetCornerRadius), and LabeledStaticBox
(GetCornerRadius, GetBorderWidth, GetBorderColor, GetScale).
* feat: add wxInspector plugin registration helper
Add RegisterOrcaInspectorPlugins() inline function that creates
and registers the DPIAwarePlugin and CustomWidgetsPlugin as
static instances (matching wxInspector's built-in pattern).
* feat: add DPIAware wxInspector plugin
Exposes DPI scaling properties (scale_factor, prev_scale_factor,
em_unit, normal_font, force_rescale) on DPIFrame and DPIDialog
widgets. Uses dynamic_cast for detection and a template helper
to capture the correct static type for lambda accessors.
* feat: add OrcaCustomWidgets wxInspector plugin
Exposes Orca-specific properties on 7 widget types:
- Button: Style, Type, Selected
- CheckBox: Half Checked
- TextInput: Label, Text Value, Corner Radius
- SwitchButton: Value
- ProgressBar: Proportion, Show Number
- Label: Is Hyperlink, Font Point Size
- LabeledStaticBox: Corner Radius, Border Width, Border Color, Scale
Each widget type uses dynamic_cast for safe detection.
* feat: wire wxInspector plugins into MainFrame and build
Call RegisterOrcaInspectorPlugins() in MainFrame constructor after
SetupInspectorAccelerator(). Add all 5 plugin source files to
SLIC3R_GUI_SOURCES in CMakeLists.txt.
* fix: move plugin registration to GUI_App::on_init_inner
Register plugins once in app init rather than in MainFrame
constructor, which may be recreated during the application
lifetime.
* fix: include plugin headers in Registration.hpp for complete types
Static locals require complete type. Include DPIAwarePlugin.hpp and
CustomWidgetsPlugin.hpp instead of forward-declaring. Also remove
unused include from MainFrame.cpp (registration moved to GUI_App).
* fix: qualify DPIFrame/DPIDialog with Slic3r::GUI namespace
* Make DPIDialog inspectable. For other dialogs, we will add them if necessary later.
* docs: add spec for moving wxInspectable into DPIAware template
Move wxInspector::wxInspectable base class from DPIDialog and MainFrame
into the common DPIAware<P> template, making all DPIAware widgets
automatically visible in the inspector tree.
Co-Authored-By: Claude <noreply@anthropic.com>
* docs: add implementation plan for moving wxInspectable into DPIAware
Co-Authored-By: Claude <noreply@anthropic.com>
* docs: update spec/plan — move SetupInspectorAccelerator into DPIAware too
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: move wxInspectable and SetupInspectorAccelerator into DPIAware
DPIAware<P> now inherits wxInspector::wxInspectable and calls
SetupInspectorAccelerator in its constructor, making all DPIAware
widgets automatically appear in the inspector tree with the
Ctrl+Shift+I shortcut. DPIDialog now uses 'using' to inherit the
constructor. Remove redundant wxInspectable inheritance and
SetupInspectorAccelerator calls from DPIDialog and MainFrame.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: use LB_HYPERLINK constant instead of magic number 0x0020
Co-Authored-By: Claude <noreply@anthropic.com>
* Clean up
* Fix Linux build
* Don't build wxInspector sample
* Use shallow clone
* Try fix flatpak build
* Attempt to fix build again
* Fix build failure caused by 436c16135e
* wxWidgets build only download required submodules
* This should fix build on Windows on ARM
* Enable PIC
* Disable layout inspector by default for public release
* Use wxInspector 1.0.0 release
---------
Co-authored-by: Claude <noreply@anthropic.com>
# Description
attempt to fix#14851
# 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)
Adopt BambuStudio's load_last_machine (cloud machines only, remembered
machine preferred) and port record_user_last_machine /
get_user_last_machine. Orca's version auto-connected an arbitrary LAN
printer, starting an unrequested connection that the user's first
printer switch tore down mid-flight, which the 02.08 plugin's connect
worker does not survive. This also caused the 100% crash-on-relaunch
loop: the crashed-on printer was auto-connected at startup, so
re-selecting it always hit the same-machine disconnect+reconnect path.
load_local_machines_from_config() iterated a reference to the live
m_local_machines map while erase_local_machine() erased from it for
printers without access rights, invalidating the range-for iterator
(use-after-free on ++it). Iterate a copy instead, as the code did
before commit 5028a5000e.
When the network plugin is not yet installed at startup, on_init_network builds
the DeviceManager without an agent, so its constructor skips loading the persisted
LAN printers. After the plugin is installed and the network stack hot-reloads, the
manager is reused via set_agent(), which never loaded them - so previously paired
printers stayed missing from the device list until an app restart. Load them once a
real agent first arrives.
- Allow mapping to EMPTY trays only from the multi-machine send page and keep
both panels pickable in the LEFT_AND_RIGHT view
- Guard the error-dialog cloud snapshot against stale callbacks and fall back
to the local illustration on timeout
- Parse the ipcam storage-check ack and axis/chamber pushes defensively
- Strip fan-control telemetry, initialize the upgrade error code, restore the
.json filter in the model-id scan
- Fix best-position popup tray lookup, gradient placement, and colour-list
ownership
- Cover switch binding sets and invalid-track transients in DevMapping tests
Resolve five conflicts, all of which needed both sides rather than a pick:
- BackgroundSlicingProcess: ours was a pure tabs->spaces reformat of base, so
keep main's per-filament volume/nozzle map read-back (its only change here).
- GUI_App: main's #12506 else-if attached to an `if` this branch deleted;
re-expressed onto the same-agent early-return path (the agent factory caches
per id, so pointer equality is the same predicate).
- MainFrame: both sides relocated Sync Presets independently; keep main's
push_notification plus the branch's Plugins menu items.
- Tab: the "TODO: Orca: Support hybrid" blocks were unchanged base, not a branch
decision; take main's enabled Hybrid to match the already auto-merged siblings.
- test_config: union of both sides' cases (6 plugin + 9 multi-nozzle).
A print sliced for a nozzle that sits in the hotend rack (but is not
mounted) was blocked by the send dialog's mounted-nozzle diameter check,
even though the printer fetches the required nozzle itself (#14685).
Consolidate the three mounted-nozzle gates (_is_nozzle_data_valid,
is_nozzle_type_match, _is_same_nozzle_diameters) into a single
CheckErrorExtruderNozzleWithSlicing fed by s_get_slicing_extuder_nozzles,
which collects the plate's per-extruder nozzle requirements (hybrid
extruders contribute one entry per used sub-nozzle flow). The rack
extruder validates against its whole inventory (mounted + rack) with
guidance to calibrate the rack, refresh nozzle info, or re-slice, and
blocks when toolhead + rack are full (no free slot to stow a nozzle).
Other extruders keep the validity/flow/diameter checks against the
mounted nozzle.
Also add CheckErrorRackStatus, which holds Send while the printer is
still reading the rack hotend information, and judge material hardness
for the rack extruder per dispatch-mapped nozzle as a non-blocking
caution (mounted nozzles keep the blocking gate).
The Filament Track Switch (H2-series accessory, product code O2L-FTS) feeds
every AMS to both extruders through a two-track switch. Port full support
across the device layer, project config, and GUI.
Device / config:
- Model the switch-aware AMS binding (the set of extruders an AMS can feed
and which input track A/B feeds it), switch readiness, the O2L-FTS firmware
module, and the fun2 capability bit for checking a slice against installed
hardware.
- Register has_filament_switcher and enable_filament_dynamic_map as project
config that persists with the project and restores from a saved 3mf, and
force both back to false on every project/printer/CLI load path. Live
device sync is the only thing that sets them true.
GUI:
- Sidebar sync activates the switch from live device state, attributes each
AMS to the extruder its input track feeds, shows a floating status icon
(ready / not-calibrated), and surfaces a one-time tip / not-calibrated
warning.
- Send dialog gains a non-blocking slice-vs-hardware mismatch warning and a
blocking error when a slice needs dynamic nozzle mapping but the switch is
missing or not set up.
- AMS load/unload guards, AMS-view routing glyph + un-calibrated banner +
hidden external-spool road, and mapping-popup external-spool lockout.
- Filament pickers collapse the per-extruder split into a single deduplicated
"AMS filaments" group with a smart-assign toggle when the switch is ready.
- Firmware-upgrade panel lists the O2L-FTS accessory and its version.
- Device-provided filament-change steps (ams.cfs) drive the change-step
display when firmware sends them, including the three switch steps.
- "Load current filament" asks which extruder to feed via a
FeedDirectionDialog when the switch is calibrated.
Inert without the accessory: every path is gated on the switch being
installed (MQTT aux bit 29, default off) or ready, both project flags default
false, and the per-extruder AMS attribution is byte-identical, so AMS state,
the send/load UI, and sliced g-code are unchanged for every printer that does
not report a Filament Track Switch.
Nozzle rack data model and device-tab panel, multi-nozzle sync, per-nozzle filament blacklist, and print-dispatch nozzle mapping (DevNozzleMappingCtrl V0/V1).
* Remove unused `get_printer_preset` calls.
* `Plater::check_printer_initialized` should skip nozzle flow type checks if nozzle is unknown.
Also remove unnecessary `is_multi_extruders` check.
* Remove unused `CalibUtils::is_same_nozzle_diameters()` fn.
* Simplify `CalibUtils::check_printable_status_before_cali`.
The single-arity can delegate to the vectorized arity.
* Add `DevExtruderSystem::NozzleDiameterMatchesOrUnknown` to simply checks.
* Update `CalibrationPresetPage::update_sync_button_status()` to use `NozzleDiameterMatchesOrUnknown`.
Simplify logic by iterating over each extruder and checking for diameter and volume type match.
The previous code had several mistakes (from what I could tell):
- `curr_obj->is_multi_extruders()` doesn't imply exactly 2 extruders
- the single/multi branch served no purpose
- the single branch failed to check the volume type
* Specify `std::fabs` and add explicit import.
Ref: https://github.com/OrcaSlicer/OrcaSlicer/pull/13330#discussion_r3133613736
Not sure how idiomatic this is in C++ / OrcaSlicer codebase, but CoPilot suggested it and it seems reasonable.
---------
Co-authored-by: SoftFever <softfeverever@gmail.com>
* Clean up code
* Filament mapping select ext slot automatically when no AMS filament inserted (OrcaSlicer/OrcaSlicer#13103)
* Show warning if external filament type does not match the one in sliced file
* Add OrcaCloud sync platform and preset bundle sharing system
Introduce OrcaCloud, a cloud sync platform for user presets, alongside
a preset bundle system that enables sharing printer/filament/process
profiles as local exportable bundles or subscribed cloud bundles.
OrcaCloud platform:
- Auth to Orca Cloud
- Encrypted token storage (file-based or system keychain)
- User preset sync with
- Profile migration from default/bambu folders on first login
- Homepage integration with entrance to cloud.orcaslicer.com
Preset bundles:
- Local bundle import/export with bundle_structure.json metadata
- Subscribed cloud bundles with version-based update checking
- Thread-safe concurrent bundle access with read-write mutex
- Canonical bundle preset naming (_local/<id>/... and _subscribed/<id>/...)
- Bundle presets are read-only; grouped under subheaders in combo boxes
- PresetBundleDialog with auto-sync toggle, refresh, update notifications
- Hyperlinked bundle names to cloud bundle pages
Co-authored-by: Sabriel Koh <sabrielkcr@gmail.com>
Co-authored-by: Derrick <derrick992110@gmail.com>
Co-authored-by: Mykola Nahirnyi <mnahirnyi@amcbridge.com>
Co-authored-by: Ian Chua <iancrb00@gmail.com>
Co-authored-by: Draginraptor <draginraptor@gmail.com>
Co-authored-by: ExPikaPaka <112851715+ExPikaPaka@users.noreply.github.com>
Co-authored-by: Ian Bassi <ian.bassi@outlook.com>
Co-authored-by: Ocraftyone <Ocraftyone@users.noreply.github.com>
Co-authored-by: yw4z <ywsyildiz@gmail.com>
Co-authored-by: peterm-m <101202951+peterm-m@users.noreply.github.com>
* Fixed an issue on Windows it failed to login Orca Cloud with Google account
* Don't assume 0.4mm nozzle; format as "unknown" if not defined.
* Skip nozzle diameter and hardness checks if nozzle info unknown.
---------
Co-authored-by: SoftFever <softfeverever@gmail.com>