Commit Graph

151 Commits

Author SHA1 Message Date
SoftFever
edab1c0dc1 Support the 02.08.01 network plug-in and resync the Bambu device workflow (#14837)
# Description

Support the 02.08.01 network plug-in and resync the Bambu device
workflow

Brings the Bambu network plug-in up to the 02.08.01 series and reworks
the plug-in
lifecycle around it (ABI gating, OTA install, hot reload), then catches
the device and
monitor side up to what that plug-in and current firmware expose — AMS
mapping, send-flow
checks, print options, and the device status pages.

**Included:**

_Network plug-in_
- Default to the 02.08.01 series and bind its new ABI symbols; bump the
reported
  `SLIC3R_VERSION` to 02.08.01.55
- Gate loading to ABI-compatible `AA.BB.CC` series, and store plug-in
identity by series
  rather than by exact build
- Fix the OTA update flow: install immediately, hot-reload without a
restart, and destroy
  the agent before unloading the DLL
- Version selector lists same-series OTA builds newest first, with
dynamic
  "(Latest)" / "(installed)" labels
- Restart printer discovery and reload saved LAN printers after a hot
reload

_Device layer_
- Move axis, calibration, chamber, status and upgrade handling into
DeviceCore; drop the
  transitional shims
- Resync the DeviceCore state models, accessory firmware versions,
cold-pull state and
  filament checks

_Device UI_
- Resync the AMS control/item widgets, device dialogs, device tab
widgets and status pages
- Add the AMS best-position popup, filament-change stop button, hub
version row and HMS
  fallback
- Device error dialog: print-failure snapshot, purification and
don't-remind actions

_Send flow_
- Resync the send flow and port the remaining pre-send checks and
advisories
- Warn when a filament will switch extruders mid-print; block TPU on the
l
  without firmware support (O1D/O1E)
- Map switch-bound AMS trays to both extruders and show combined nozzle
mapping
- Add the shared-PA-profile toggle

_Print options / timelapse_
- Restructure DevPrintOptions around a detection-option map and parse
the
  bits on the live push path
- Add firmware print-option toggles, plus timelapse storage-location
selection with a
  free-space check

_Fixes_
- Inverted MQTT jog on i3-architecture printers, plus assorted popup,
mapping and
  status-parse defects

_Tests_
- New Catch2 coverage for network version selection and device filament
mapping

Printers that don't advertise the new capabilities are unaffected —
every added behavior is
gated on a firmware or plug-in capability flag, and the only profile
chang
`support_print_check_firmware_for_tpu_left` to O1D/O1E.

# Screenshots/Recordings/Graphs

<img width="714" height="500" alt="image"
src="https://github.com/user-attachments/assets/33e54581-3fb0-4a3e-b80c-afa8adfabe4c"
/>

<img width="530" height="212" alt="image"
src="https://github.com/user-attachments/assets/d0c55fd5-74c3-4aab-81a5-786d0aaf8828"
/>

<img width="483" height="527" alt="image"
src="https://github.com/user-attachments/assets/71ceaad1-a082-41cb-aa1a-4b9abb30d9db"
/>


## 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-07-19 17:10:35 +08:00
SoftFever
8ee6095e08 fix ci test errors 2026-07-19 12:07:58 +08:00
Kiss Lorand
d6ca71be95 Fix skirt and brim handling for duplicated objects (instances) (#14683) 2026-07-18 19:57:56 -03:00
SoftFever
afb4505ea7 Store network plug-in identity by AA.BB.CC series
The stored plug-in identity is now the AA.BB.CC series (matching BambuStudio)
rather than the full build version, so the meaningless 4th build digit stops
driving config, the whitelist, filenames, and the version selector. This fixes
the macOS "can't switch to an older build" bug: the cloud endpoint is
series-keyed and only ever serves a series' newest build, so downgrade-by-
download was impossible and the download silently adopted the latest.

A startup migration normalizes an existing full-version config and file name to
the series form with no re-download, the loader resolves a bare series to the
newest same-series build on disk, and user-provided custom-named plug-ins
(libbambu_networking_02.08.01_custom.*) are still enumerated and loaded.
2026-07-19 00:26:05 +08:00
SoftFever
2804e06cf2 Sort network plug-in versions newest first and mark only the loaded build
Discovered builds were inserted positionally behind the whitelist entry they
anchored to, so an OTA-installed 02.08.01.53 listed below 02.08.01.52. The list
is now built by appending and sorting once, which also drops the per-entry
insertion scans.

"(installed)" tested whether the library was present on disk, so it marked every
version ever selected - switching leaves the previous library in place. The flag
is now is_loaded, resolved against the plug-in actually loaded, and the two
combo populators share one label helper.
2026-07-18 16:23:50 +08:00
SoftFever
ddfa961111 Merge branch 'main' into feature/bambu_printer_housekeeping
# Conflicts:
#	tests/slic3rutils/CMakeLists.txt
2026-07-18 02:08:13 +08:00
SoftFever
4683c17f6f Fix device popup, mapping, and status-parse defects
- 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
2026-07-18 01:46:10 +08:00
SoftFever
12720ccbd8 Gate network plugin loading to ABI-compatible series
Trim the version whitelist to the latest series plus the pinned legacy build,
and reject out-of-series configured versions at startup, compatibility check,
and load failure - falling back to the latest installed build or the clean
re-download flow so the config never keeps pointing at an unsupported build.
2026-07-18 01:45:54 +08:00
SoftFever
88fb89b5eb Plugin audit (#14821)
* Block plugins from reading or writing app config and cloud credentials

Add a denied-filename registry to the plugin audit sandbox, seeded with OrcaSlicer's config (.conf/.ini) and the cloud refresh-token file. The deny is checked above the loading-mode read exemption and the allowed roots, so a plugin cannot reach these files even though they sit inside data_dir(), which is itself an allowed root. Case-insensitive prefix matching also covers the .bak/.tmp companions that hold the same data, and os.rename/os.remove are hooked alongside open so the files cannot be deleted or clobbered either.
2026-07-18 01:24:44 +08:00
SoftFever
ee2e7e7a28 Add actions speed dial to run plugin scripts (#14697)
# Description

Use Space to trigger a new **speed dial**, which allows users to run
**app actions**. The only app actions implemented currently are python
plugin scripts.

## Notes

- Only toggleable in the Prepare (3D) view. Press Space, type to filter,
Enter or double-click to run.
- Focuses on search bar automatically
- Frecency-sorted (run count + recency) with alphabetical fallback (C++
computes)
- Pin actions as favourites and they will show on the top favourites
bar. Done through star icon on each row.
- Script plugins have no icon art yet, so tiles show a collision-aware
monogram: the capability's initial, escalating only when names collide -
prepend the package initial, then add an ordinal - so same-named actions
from different plugins stay distinguishable.
- E.g., capability Bravo from plugin Alpha normally shows just B. If
another action's name also starts with B, they disambiguate by
prepending the package initial (Alpha -> AB). If two still collide on
both initials (both AB), they become AB1 and AB2.
- "Run X?" confirm with a per-plugin "don't ask again" scope, owned
C++-side; suppression persists.
- Persistence (`speed_dial` AppConfig section): `favourite_actions`
(ordered id list) + per-action `stats` + `ask_suppressed`.

- Example of shape in data_dir:
```json
{
    "speed_dial": {
        "ask_suppressed": "[\"9b12aa079924bbc4\"]",
        "favourite_actions": "[\"ccfdf8b9e492b624\",\"9b12aa079924bbc4\",\"b7abfa67626248e4\"]",
        "stats": "{\"31d9d129a616a8b7\":{\"count\":4,\"last\":1783924989},\"53ec17d430634f62\":{\"count\":3,\"last\":1783939329},\"9b12aa079924bbc4\":{\"count\":5,\"last\":1783924981},\"9f2cb0d3ca56a87c\":{\"count\":1,\"last\":1783668370},\"b7abfa67626248e4\":{\"count\":4,\"last\":1783939325},\"f93469da14248128\":{\"count\":3,\"last\":1783939337}}"
	},
}
```

# Screenshots/Recordings/Graphs

<img width="688" height="335" alt="image"
src="https://github.com/user-attachments/assets/683efa3b-9401-4977-a347-d70193188165"
/>

<img width="681" height="172" alt="image"
src="https://github.com/user-attachments/assets/fafb4965-054b-4fd5-ad6a-03145264fbe0"
/>

<img width="683" height="335" alt="image"
src="https://github.com/user-attachments/assets/00d5bd49-95c0-4f2f-966b-6c04c14c3cf3"
/>


## Tests

- **Web layer (green):** node-vm logic test `test-speeddial-logic.js`
covers `filterActions`, `visibleFavourites` (incl. the runnable guard),
`selectedActionId`, `resultCountText`, `actionLabel`, `tileCode`,
`nextSel`, and payload seeding - pure helpers, DOM-free.
- **Backend:** `ActionRegistry` FNV-1a id golden-vector Catch2 test
(`test_speed_dial_action_id`) pins the hash; the registry was verified
by fresh-context review including a threading fix (`run()` operates on a
stack copy so a queued refresh can't reallocate the action vector
mid-run).
- **Manual (all passing):**
- Space opens the dial in Prepare only; no regression to existing
Prepare-tab keys or the Plugins dialog.
- Search auto-focuses; typing filters live; a freshly-run action rises
in the frecency order.
- Up jumps to the favourites bar, Down into the list, Alt+1..9 hits
favourites; Enter and double-click run the highlighted action.
- Star pins/unpins an action; favourites persist across an app restart.
- "Run X?" confirm with per-plugin "don't ask again" is respected on
later runs.
  - The `?` shortcuts dialog shows the Space row.
  - Verified in both light and dark themes.

## Known Issues

When there are no actions, plugins, or scripts, the search bar will show
"Search 0 actions". This is bad UX. One alternative considered was to
show a call to action, for example "Please load plugin scripts so that
they appear here".

However, this is ultimately not implemented, as eventually it is not
expected that actions will be empty. The action registry will not be
expected to be empty because we will include in-app actions such as
opening dialogues or other app actions.

<img width="722" height="117" alt="image"
src="https://github.com/user-attachments/assets/a4b9c0db-b2bf-44bc-9550-398dd8b4c7aa"
/>

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
2026-07-17 23:36:34 +08:00
Ian Chua
1c82b88c0a fix: unit test shutting down pythonintepreter 2026-07-17 21:56:04 +08:00
Ian Chua
dda49a2b7b Merge branch 'feat/plugin-feature' into feature/speed-dial 2026-07-17 21:29:25 +08:00
Ian Chua
5e15a67425 fix: deprecate show_dialog api and add an option to create_window params 2026-07-17 21:12:55 +08:00
SoftFever
f0f496e9c3 Merge branch 'feat/plugin-feature' into feature/speed-dial
Adapt the speed dial's ActionRegistry to the collapsed
get_plugin_capability(PluginCapabilityId) overload, and restore the
script success/skipped status message the dialog lost when its
PluginScriptRunner refactor was superseded by ActionRegistry.
2026-07-17 19:32:44 +08:00
SoftFever
6767ab5ae0 Make the Latest and installed version labels dynamic 2026-07-17 16:25:10 +08:00
SoftFever
c2f88b17be Complete the plugin settings removal after the feat/plugin-feature merge
The merge kept this branch's PluginConfig design, which deletes
PluginDescriptor::settings, get_plugin_settings() and ctx.params, but left
references to them behind: the slic3rutils target did not build, and the
bindings test still asserted the removed ctx.params attribute.

Port the two settings tests onto PluginConfig instead of dropping them. They
guard a field bug where a cloud-metadata refresh wiped a plugin's settings and
it silently ran on its own defaults, so the equivalent properties are still
worth pinning: that a stored config survives the refresh, and that an edited
config reaches the plugin through a real dispatch.

Also defer PluginsConfigDialog's web commands off the webview script-message
callback, as PluginsDialog already does. Its remove_preset_override handler put
a modal wxMessageBox on that stack, which is the GTK crash class fixed in
b779a7bfed/f2ccbfc8b5 for the sibling dialog.
2026-07-17 16:09:19 +08:00
SoftFever
79593e07c6 List same-series OTA plugin builds in the version selector 2026-07-17 14:23:40 +08:00
Ian Chua
4c60781cf4 fix: merge branch feat/plugin-feature 2026-07-17 14:02:10 +08:00
Andrew
b4f6573753 Merge branch 'feat/plugin-feature' into feature/speed-dial
# Conflicts:
#	src/slic3r/GUI/PluginsDialog.hpp
2026-07-17 13:59:56 +08:00
SoftFever
1c9fda463b Fix plugin settings lost on cloud metadata refresh
Cloud catalog records never carry [tool.orcaslicer.plugin.settings], so the
metadata merge wiped the locally-parsed settings and plugins silently ran on
their built-in defaults (ctx.params arrived empty).
2026-07-17 02:09:34 +08:00
SoftFever
6f30d03e28 fix test errors 2026-07-16 21:40:21 +08:00
Ian Chua
d9f8460a4e fix: merge PythonFileUtils into PluginFsUtils 2026-07-16 20:40:32 +08:00
Ian Chua
f4414dd72b fix: collapse plugincapabilityid 2026-07-16 18:18:07 +08:00
Andrew
30170839c1 Merge branch 'feat/plugin-feature' into feature/speed-dial 2026-07-16 17:15:24 +08:00
Andrew
1c33983edf Confine plugin lifecycle callbacks to UI thread
Drop the orphaned PluginCallbackList (dead
after the PluginManager migration) and hop
run_on_*_callbacks onto the UI thread via
CallAfter, snapshotting under the mutex on the
worker first. Keeps wx subscribers off the
detached load/unload workers.
2026-07-16 17:08:03 +08:00
SoftFever
8bb093b50b Map switch-bound AMS trays to both extruders 2026-07-16 15:54:56 +08:00
Ian Chua
49396699e7 fix: initialize embedded python from bundled runtime 2026-07-16 15:40:13 +08:00
Andrew
c816e48b78 refactor: collapse speed-dial action source abstraction
Only one action source ever existed, so the
IActionSource interface and ScriptActionSource
are gone. ActionRegistry now subscribes to the
plugin loader and enumerates actions directly
in init() - no polymorphism for one impl.

Replace the opaque FNV-hash SpeedDialActionId
with a readable composed id of the form
prefix:title:source_key. Split AppAction's
single source field into source_key (stable
identity, e.g. plugin_key) and source_name
(display), so identity and display no longer
share one field.
2026-07-16 13:08:48 +08:00
Ian Chua
b6f98d9592 fix: load default config on initial load 2026-07-16 12:57:59 +08:00
Ian Chua
525a16177c fix: bundle python runtime for macos plugin tests 2026-07-16 12:06:45 +08:00
Ian Chua
8ba478913f fix merge conflicts 2026-07-15 22:09:47 +08:00
Ian Chua
d2b5008156 fix: test_slicing_pipeline_hook 2026-07-15 21:39:55 +08:00
Ian Chua
9cdd399fdd fix: test slicing pipeline hook 2026-07-15 21:32:37 +08:00
Ian Chua
cd8c42b125 fix merge conflicts 2026-07-15 21:04:42 +08:00
Ian Chua
62afea225a Fix/impl refactor (#14776)
* fix: impl refactor

* fix: unload/load python module, race conditions, freezes

* remove dead code

* remove extra hook

* remove more dead code

* fix gil run script
2026-07-15 20:12:51 +08:00
SoftFever
bf932e8797 Merge branch 'main' into feat/plugin-feature 2026-07-15 17:19:14 +08:00
SoftFever
8cb0cb7693 Merge branch 'main' into feat/plugin-feature
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).
2026-07-15 17:18:46 +08:00
Kris Austin
d500ba4e9e test: fix flaky k-medoids goldens added with H2C/A2L support (#14773)
The filament-group golden harness landed with H2C/A2L support (#14685). Its
"FilamentGroup golden regression" / stress_66 case fails intermittently on
Windows x64, on main and on unrelated PRs alike. The test depends on how fast the
runner is.

The k-medoids clustering these goldens exercise is an anytime search bounded by a
3 second wall clock. Every restart is seeded from its own index, so nothing about
it is random. What varies is how many restarts fit in the budget, and the best
cost is a minimum over completed restarts, so a slower runner is never better.
Grading a score produced that way measures the machine as much as the code.

Add a ClusteringBudget struct and let the tests set it. The defaults are the
current 3 seconds and 30 restarts, so slicing behavior is unchanged. A
non-positive timeout removes the wall clock and bounds the search by restart
count alone.

The goldens are then graded under a fixed budget of four restarts, where every
one of them reaches the BambuStudio reference within 3%, so the score becomes a
property of the code. This retires the machine-specific 125103 lock on stress_66.

The default wall-clock path keeps its own test, asserting the grouping is valid
and the search does not run away. It makes no score assertion, because under a
wall clock that number is not a property of the code.

The golden test also checks the run fits in ten times the default wall clock.
Slicing quality depends on how many restarts fit in the budget, so a search an
order of magnitude slower would degrade real groupings while a fixed-budget score
gate stayed green.

The 3% tolerance stays as the parity allowance against the goldens. It also
covers a small spread across standard libraries: the k-medoids search seeds each
restart with std::shuffle, whose algorithm the C++ standard leaves unspecified,
so libstdc++, libc++ and the MSVC STL permute the same seed differently, start
from different medoids, and settle on slightly different groupings, about 3e-4
apart and only on the goldens heavy enough to reach the k-medoids search.
2026-07-15 16:59:55 +08:00
SoftFever
d55e7834c8 Fix unit-test segfault on missing shipped profile in sparse CI checkout
The Unit Tests job sparse-checks-out only .github/scripts/tests, so the
baked-in absolute PROFILES_DIR was missing at runtime; the shipped-profile
test then read a non-existent JSON and null-dereferenced in opt_string.
Check out resources/ in the unit-test job, and guard the test helper to
skip when the profile is absent and require the key before dereferencing.
2026-07-15 14:55:41 +08:00
SoftFever
f1fd49c12f Add slice-validation sweep for shipped profiles 2026-07-15 01:49:04 +08:00
Ian Chua
71d0380467 fix: preset resolution 2026-07-14 19:48:39 +08:00
Ian Chua
fbed6f7dc6 cleanup 2026-07-14 13:10:42 +08:00
Ian Chua
86a4cec753 fix: preset overrides on sidebar 2026-07-14 12:57:06 +08:00
SoftFever
2268544a68 fix test error on Windows ARM64 2026-07-13 23:26:16 +08:00
Ian Chua
5b3e1b921c feat: sidebar plugin config UI 2026-07-13 20:39:41 +08:00
Andrew
635f5a3529 Merge remote-tracking branch 'public/feat/plugin-feature' into feature/speed-dial
# Conflicts:
#	src/slic3r/GUI/PluginsDialog.cpp
2026-07-13 19:39:42 +08:00
Andrew
87c9ab138c Protect action identity from mutation
Keep action identity and display metadata
constructor-set so registry keys cannot drift
from the objects they index.

Require sources to publish unique ownership while
the registry retains shared keepalive for runs.

Preserve opaque IDs and persisted state keys.
2026-07-13 17:32:34 +08:00
Andrew
b4c9747f09 fix(plugins): prevent callback races
Lifecycle callbacks can be registered while
another thread dispatches them, risking races
and iterator invalidation.

Snapshot shared callback objects under a mutex,
then invoke them unlocked to preserve reentrancy
and mutable callback state.
2026-07-13 17:25:39 +08:00
Andrew
c29ffdfc1a Extract script actions into an action source
Move plugin capability enumeration, loader
subscriptions, and action construction into
ScriptActionSource. Keep ActionRegistry focused
on generic action state, dispatch, and snapshots.

Use source rather than package for generic origin
metadata so future non-plugin providers share the
same interface. Action IDs and persisted
configuration remain unchanged.

Subscribe before initial enumeration so plugin
events cannot be missed between the snapshot and
callback registration. Add a focused test for
source startup.
2026-07-13 14:28:05 +08:00
Ian Chua
0c69b9982d merge 2026-07-13 12:26:10 +08:00