diff --git a/docs/HLSD/deferred-page-construction.md b/docs/HLSD/deferred-page-construction.md new file mode 100644 index 0000000000..748ca65d52 --- /dev/null +++ b/docs/HLSD/deferred-page-construction.md @@ -0,0 +1,220 @@ +# Deferred Page Construction: High Level Design + +## Why it exists + +The main window is a notebook of tabs. When the first frame appears, one tab is on +screen and the others are not; some of them are opened later in the session, some +never, and some only exist for certain printers. Building a tab before the first frame +adds its cost to every startup, whether or not the tab is used. + +This subsystem builds a tab's panel the first time the tab is shown. It also builds the +remaining tabs while the user is idle after startup, in units of tens of milliseconds, +so a click that lands in the middle of one waits for that unit and no longer. Startup +pays only for what the first frame shows, and the other tabs are usually built before +anyone opens them. + +## The parts + +`src/slic3r/GUI/Lazy.hpp`, `LazyPage.hpp`, `StagedBuild.hpp` and `IdleScheduler.hpp/.cpp` +(with its wx-free `PrebuildQueue.hpp`) are independent. A holder can hold anything a +factory makes, a page is a holder with a placeholder widget, a staged object can live +outside a holder, and the scheduler knows none of them; it runs tasks, which `MainFrame` +makes from the holders. + +### Lazy: the holder + +Holds an object that a factory makes on first use, under a name for the log and a place +in the idle queue, both given by the owner. The header has no wx dependency; the busy +cursor for an on-demand build lives in `Lazy.cpp` and is skipped when there is no app, +so the holder is unit-tested. + +- `get()` is null until the object is completely built; `built()` says the same. +- `ensure()` builds whatever is left now, under a busy cursor, and returns the object, or + null in the two cases below. A click on an unbuilt tab or a first open of a dialog goes + through this, and it logs the units and time it took. +- `build_step()` runs one unit of construction and returns true while more remain. The + first unit is the factory call, and each later unit is one `StagedBuild` step if the + type has them. +- `when_built(fn)` runs `fn(object)` now if it exists, otherwise once it is built. +- `pending()` says whether the idle prebuild has work here: not built, and the factory + has not returned null. A null factory result is logged and the holder stays unbuilt. +- A unit that pumps the event loop cannot re-enter the holder; a nested `build_step()` + does nothing and a nested `ensure()` returns null. +- After a unit throws, the holder and the scheduler still run the next one. + +The holder does not own the object; its wx parent does, as for any window. A type with +one instance in the app derives from `LazyInstance`, which points at that instance's +holder (the holder registers itself, and a recreated `MainFrame`'s holder replaces the +old frame's) and gives the type the static entry points the rest of the app uses, +`T::if_built()`, `T::ensure()` and `T::when_built(fn)`. They return null, or do +nothing, while no holder exists, so a caller needs no `mainframe` check. + +`built()` is an atomic flag, since a job worker reads it through the statics +(`MainFrame::get_calibration_curr_tab()`); it is set after the object is complete. + +`LazyBase` is the holder's type-free interface (`name()`, `built()`, `pending()`, +`build_step()`, `prebuild_order()`) and is what the scheduler side sees. + +### LazyPage: the placeholder + +A `wxPanel` placed in the parent in place of the real panel, and a `Lazy` whose +factory makes the panel inside it (by default `new Panel(parent)`). The notebook needs a +page object for the tab to exist and for `show_device()` to insert and remove tabs by +pointer, and the placeholder is that object. `MainFrame` creates every page once, named +after its `TAB_ID_*`, and keeps it for the frame's life; `show_device()` only moves +pages in and out of the book. + +- `Show()` is forwarded to the panel, so a panel's own `Show()` override stays its + activation hook (refresh timers, machine sync) and `SelectPageByName()` works + unchanged. A show builds the panel unless the frame itself is still hidden, because + the book selects its first page as it is inserted; `MainFrame::Show()` shows the + current page again when the frame becomes visible, which builds it. +- `in_book()` says whether the parent notebook currently lists the page, and + `pending()` is that and not built, so a tab `show_device()` has taken out of the book + is not prebuilt. +- A panel built while its page is hidden stays hidden, and a completed panel gets the + dark-mode pass the frame ran before it existed. + +The Compare presets dialog is a holder without a page. `MainFrame` keeps a +`Lazy` whose factory constructs the dialog and binds its events, the +dialog derives from `LazyInstance`, and its callers use +`DiffPresetDialog::ensure()->show()` and `DiffPresetDialog::if_built()` like a tab's +callers do. Saving a preset refreshes the dialog only while it is shown, since `show()` +reloads the presets. + +### StagedBuild: construction in units + +A mixin for a panel whose constructor is too big to be one unit. The constructor builds +the skeleton (sizers, and the parts other code may touch) and queues the rest with +`add_build_step()`. `build_step()` runs one step, and `add_build_steps_of(child)` +forwards a child's steps so a nested panel is spread the same way; the parent is built +only once the child is, including steps the child queues later. Steps run in order, on +the main thread. A `Lazy` recognises a staged type at compile time and runs its steps +one per unit. + +Nothing may touch what a step builds before the last step has run. In practice: + +- nothing paints the panel before it is complete, since a panel built at idle is hidden + with its page and one built on demand finishes inside `ensure()` before the event loop + runs again; +- members created in steps are initialised to null in the header, so a partially built + panel can be destroyed; +- timers and event handlers that use step content check `built()` first + (`MonitorPanel::update_all()`, `CalibrationPanel::update_all()`), and a child's steps + are queued before anything in the constructor can fire such a handler; +- a destructor that disconnects from step content checks `built()` first; +- a constructor or step does not take focus while the panel is off screen + (`IsShownOnScreen()` before `SetFocus()`), since it may run while the user is typing + elsewhere; +- where a step's widgets must keep their place in a sizer that later steps also fill, the + constructor adds an empty slot sizer in that position and the step fills the slot + (`StatusBasePanel`). + +### IdleScheduler: when to build + +A task is any `LazyBase`: a name for the log, `pending()`, `build_step()` and +`prebuild_order()`. `PrebuildQueue` holds the tasks by order (equal order in the order +added) and runs a slice, the units of the first pending task until it completes, the +budget is spent on the clock it is given, or the interrupt predicate says input arrived. +It has no wx dependency and is unit-tested with a fake clock. A task whose work is gone +is passed over and stays in the queue, so a tab that `show_device()` removes and later +re-inserts is pending again. + +`IdleScheduler` drives the queue with the real clock, the app's input timestamp and the +Windows queue check, and logs each unit and slice. Each slice is a timer message: a +period of 250 ms while waiting for the user to go quiet, and a one-shot of zero after a +slice that left work, so the event loop dispatches whatever it has queued (paint, +timers, input) before the next slice runs. Chaining slices with `CallAfter` would not do +this: wx drains pending events fully before the next native message, on every platform. +On GTK the one-shot is 5 ms, because a due GLib timeout runs ahead of the redraw and +idle sources that paint and deliver posted events. +A slice runs only once the user has been idle for the quiet time, and the timer stops +itself once no task is pending. The tick period, quiet time and slice length are +constants in `IdleScheduler.cpp`. A unit cannot be interrupted once started, so the +largest unit bounds click latency on Windows; on the other platforms a click also waits +for the rest of the slice. A unit that pumps the event loop lets the timer fire inside +its own slice, and that tick does nothing. + +The tasks are made by their owners. `MainFrame::prebuild_pages_when_idle()` registers +every `LazyPage` the frame created, in or out of the book (`pending()` is false for a +page out of the book), the Compare presets holder, and the Prepare sidebar's settings +page from `ParamsPanel::settings_page_prebuild()`, whose first unit selects the default +tab if none is selected yet and whose later units build one option group each. +`show_device()` only restarts the timer. `MainFrame` owns the scheduler because it owns +everything the tasks build, and clearing the queue with the frame is what keeps a task +from outliving its object. + +Idle time comes from `GUI_App::FilterEvent`, which timestamps mouse and keyboard events +(`wxEVT_CATEGORY_USER_INPUT` minus command events, which all claim that category), and +`GUI_App::input_idle_ms()` reports it. On Windows a slice additionally refuses to start +when the message queue holds keyboard, button, touch or pen input. Mouse moves are +excluded because Windows synthesises one whenever a window appears under the cursor, +which every unit does. Other platforms use the timestamp alone. + +Once every registered page is built the timer is stopped and the subsystem costs +nothing. + +## Rules + +**What builds before the first frame.** The Prepare tab's plater, because `post_init()` +needs its GL canvas on screen to initialise OpenGL in every startup state, and the start +page the user configured. Home is built by the first `MainFrame::Show()`, Prepare's +settings page by selecting the tab. `post_init()` passes through the Prepare tab for GL +init under `Freeze()` with `MainFrame::select_prepare_for_gl_init()`, which changes the +selection without the page-changed event, so nothing else is built for that pass. + +**Reaching a lazy object.** A caller uses the type's own statics. `T::if_built()` may +return null and is for telling the object something it can live without (a rescale, a +colour change, a status update). `T::ensure()` builds the object and is for navigating +to it or for a caller that is about to show it. A caller that tells the object something +it would not fetch for itself on construction uses `T::when_built()`, which keeps the +message until the object exists. A panel that pulls its state when constructed (the Home +page requests the recent list on load, the Device tab reads the device manager on show) +is reached with `if_built()`; one that cannot pull gets `when_built()`. + +**Unit size.** A unit cannot be interrupted, so it should stay within the slice length on +a fast machine. A constructor above that is staged. A single widget above it is the +floor unless the widget itself is split. + +**Order.** Cheapest and most likely to be opened first, given where `MainFrame` creates +each holder. The settings page is 0 (the Prepare tab's own content), Home 10, Device 20 +(a Bambu user's usual second stop), Calibration 30, Multi-device 40, the web Device +view 50, Project 60 (a second WebView2 instance) and the Compare presets dialog 100; +steps of ten so a new tab takes a value between its neighbours without renumbering +them. `MainFrame::prebuild_pages_when_idle()` registers the tasks once, from +`post_init()`. + +**Never prebuilt.** A holder with a negative order, for a tab that few sessions open +and that costs more to build unasked than it saves (the Design tab), and plugin-provided +tabs, which are Python-side and not lazy pages. + +## Adopting it + +A lazy tab needs: + +1. The panel derived from `LazyInstance`, since a tab's panel has one instance. +2. A `LazyPage*` member in `MainFrame`, created once in `init_tabpanel()` with + its `TAB_ID_*` as the name, its place by the order rule (and a factory if + `new Panel(parent)` is not enough), added to `m_lazy_pages`, and used wherever the + tab is added to or looked up in the notebook. +3. Every use of the panel outside `MainFrame` going through one of the panel's statics, + chosen by the rule above. When converting an existing member, `grep` for it; the + compiler finds the rest. +4. A constructor that copes with the frame already existing and the user being busy + elsewhere, since `wxGetApp().mainframe` is set, the frame may be shown, and the user + may be typing when a lazy panel is built: no `SetFocus()` while off screen, and + whatever the constructor did through a `MainFrame` accessor before (a mode update, a + deferred URL) done in the constructor itself. + +To stage a heavy constructor, inherit `StagedBuild`, keep the skeleton in the constructor, +move the rest into `add_build_step()` lambdas in the original order, and follow the +staged-panel rules above. Measure the units. A step that is still one big widget has to +be split inside that widget or accepted as the floor. + +Verification is by log. `MainFrame::prebuild_pages_when_idle` lists the queue it +registered, `IdleScheduler::tick` reports each completed task by name at info level and +each slice and unit at debug level, and `Lazy::ensure` reports an object a user built +on demand with the units and time it took. A run from the configured start +page shows every registered page complete, in order, with no unit longer than intended. +A click on a tab mid-prebuild shows the finished panel with an `ensure` line for what was +left, and the slices resume for the remaining tasks once the user is idle again. diff --git a/resources/profiles/Sovol.json b/resources/profiles/Sovol.json index 7f08417ed7..81dab20239 100644 --- a/resources/profiles/Sovol.json +++ b/resources/profiles/Sovol.json @@ -1,7 +1,7 @@ { "name": "Sovol", "url": "", - "version": "02.04.00.04", + "version": "02.04.00.07", "force_update": "0", "description": "Sovol configurations", "machine_model_list": [ @@ -167,10 +167,6 @@ "name": "0.20mm Standard @Sovol SV08 MAX 0.4 nozzle", "sub_path": "process/0.20mm Standard @Sovol SV08 MAX 0.4 nozzle.json" }, - { - "name": "0.20mm Standard @Sovol Zero 0.4 nozzle", - "sub_path": "process/0.20mm Standard @Sovol Zero 0.4 nozzle.json" - }, { "name": "0.28mm Fast @Sovol SV06 ACE", "sub_path": "process/0.28mm Fast @Sovol SV06 ACE 0.4 nozzle.json" @@ -198,6 +194,74 @@ { "name": "0.40mm Standard @Sovol SV08 MAX 0.8 nozzle", "sub_path": "process/0.40mm Standard @Sovol SV08 MAX 0.8 nozzle.json" + }, + { + "name": "fdm_process_zero", + "sub_path": "process/fdm_process_zero.json" + }, + { + "name": "0.06mm Quality @Sovol Zero 0.2 nozzle", + "sub_path": "process/0.06mm Quality @Sovol Zero 0.2 nozzle.json" + }, + { + "name": "0.10mm Standard @Sovol Zero 0.2 nozzle", + "sub_path": "process/0.10mm Standard @Sovol Zero 0.2 nozzle.json" + }, + { + "name": "0.12mm Quality @Sovol Zero 0.4 nozzle", + "sub_path": "process/0.12mm Quality @Sovol Zero 0.4 nozzle.json" + }, + { + "name": "0.14mm Fast @Sovol Zero 0.2 nozzle", + "sub_path": "process/0.14mm Fast @Sovol Zero 0.2 nozzle.json" + }, + { + "name": "0.15mm Quality @Sovol Zero 0.6 nozzle", + "sub_path": "process/0.15mm Quality @Sovol Zero 0.6 nozzle.json" + }, + { + "name": "0.20mm Quality @Sovol Zero 0.8 nozzle", + "sub_path": "process/0.20mm Quality @Sovol Zero 0.8 nozzle.json" + }, + { + "name": "0.20mm Standard @Sovol Zero 0.4 nozzle", + "sub_path": "process/0.20mm Standard @Sovol Zero 0.4 nozzle.json" + }, + { + "name": "0.25mm Quality @Sovol Zero 1.0 nozzle", + "sub_path": "process/0.25mm Quality @Sovol Zero 1.0 nozzle.json" + }, + { + "name": "0.25mm SPEEDBENCHY @Sovol Zero 0.4 nozzle", + "sub_path": "process/0.25mm SPEEDBENCHY @Sovol Zero 0.4 nozzle.json" + }, + { + "name": "0.28mm Fast @Sovol Zero 0.4 nozzle", + "sub_path": "process/0.28mm Fast @Sovol Zero 0.4 nozzle.json" + }, + { + "name": "0.30mm Standard @Sovol Zero 0.6 nozzle", + "sub_path": "process/0.30mm Standard @Sovol Zero 0.6 nozzle.json" + }, + { + "name": "0.40mm Standard @Sovol Zero 0.8 nozzle", + "sub_path": "process/0.40mm Standard @Sovol Zero 0.8 nozzle.json" + }, + { + "name": "0.42mm Fast @Sovol Zero 0.6 nozzle", + "sub_path": "process/0.42mm Fast @Sovol Zero 0.6 nozzle.json" + }, + { + "name": "0.50mm Standard @Sovol Zero 1.0 nozzle", + "sub_path": "process/0.50mm Standard @Sovol Zero 1.0 nozzle.json" + }, + { + "name": "0.56mm Fast @Sovol Zero 0.8 nozzle", + "sub_path": "process/0.56mm Fast @Sovol Zero 0.8 nozzle.json" + }, + { + "name": "0.70mm Fast @Sovol Zero 1.0 nozzle", + "sub_path": "process/0.70mm Fast @Sovol Zero 1.0 nozzle.json" } ], "filament_list": [ @@ -249,6 +313,10 @@ "name": "Generic PETG @Sovol Zero", "sub_path": "filament/Generic PETG @Sovol Zero.json" }, + { + "name": "Generic PETG @Sovol Zero Hardened Steel nozzle", + "sub_path": "filament/Generic PETG @Sovol Zero Hardened Steel nozzle.json" + }, { "name": "Generic PLA @Sovol SV06 ACE", "sub_path": "filament/Generic PLA @Sovol SV06 ACE.json" @@ -277,6 +345,14 @@ "name": "Generic PLA @Sovol Zero", "sub_path": "filament/Generic PLA @Sovol Zero.json" }, + { + "name": "Generic PLA @Sovol Zero Hardened Steel nozzle", + "sub_path": "filament/Generic PLA @Sovol Zero Hardened Steel nozzle.json" + }, + { + "name": "Generic PLA SPEEDBENCHY @Sovol Zero", + "sub_path": "filament/Generic PLA SPEEDBENCHY @Sovol Zero.json" + }, { "name": "Generic PLA Silk @Sovol SV08 MAX", "sub_path": "filament/Generic PLA Silk @Sovol SV08 MAX.json" @@ -285,6 +361,10 @@ "name": "Generic PLA Silk @Sovol Zero", "sub_path": "filament/Generic PLA Silk @Sovol Zero.json" }, + { + "name": "Generic PLA Silk @Sovol Zero Hardened Steel nozzle", + "sub_path": "filament/Generic PLA Silk @Sovol Zero Hardened Steel nozzle.json" + }, { "name": "Generic TPU @Sovol SV06 ACE", "sub_path": "filament/Generic TPU @Sovol SV06 ACE.json" @@ -312,18 +392,6 @@ { "name": "SUNLU PETG @Sovol SV08 MAX", "sub_path": "filament/SUNLU PETG @Sovol SV08 MAX.json" - }, - { - "name": "Sovol Zero PETG HS Nozzle", - "sub_path": "filament/Sovol Zero PETG HS Nozzle.json" - }, - { - "name": "Sovol Zero PLA Basic HS Nozzle", - "sub_path": "filament/Sovol Zero PLA Basic HS Nozzle.json" - }, - { - "name": "Sovol Zero PLA Silk HS Nozzle", - "sub_path": "filament/Sovol Zero PLA Silk HS Nozzle.json" } ], "machine_list": [ @@ -415,9 +483,45 @@ "name": "Sovol SV08 MAX 0.8 nozzle", "sub_path": "machine/Sovol SV08 MAX 0.8 nozzle.json" }, + { + "name": "Sovol Zero 0.2 nozzle", + "sub_path": "machine/Sovol Zero 0.2 nozzle.json" + }, { "name": "Sovol Zero 0.4 nozzle", "sub_path": "machine/Sovol Zero 0.4 nozzle.json" + }, + { + "name": "Sovol Zero 0.6 nozzle", + "sub_path": "machine/Sovol Zero 0.6 nozzle.json" + }, + { + "name": "Sovol Zero 0.8 nozzle", + "sub_path": "machine/Sovol Zero 0.8 nozzle.json" + }, + { + "name": "Sovol Zero 1.0 nozzle", + "sub_path": "machine/Sovol Zero 1.0 nozzle.json" + }, + { + "name": "Sovol Zero 0.2 Hardened Steel nozzle", + "sub_path": "machine/Sovol Zero 0.2 Hardened Steel nozzle.json" + }, + { + "name": "Sovol Zero 0.4 Hardened Steel nozzle", + "sub_path": "machine/Sovol Zero 0.4 Hardened Steel nozzle.json" + }, + { + "name": "Sovol Zero 0.6 Hardened Steel nozzle", + "sub_path": "machine/Sovol Zero 0.6 Hardened Steel nozzle.json" + }, + { + "name": "Sovol Zero 0.8 Hardened Steel nozzle", + "sub_path": "machine/Sovol Zero 0.8 Hardened Steel nozzle.json" + }, + { + "name": "Sovol Zero 1.0 Hardened Steel nozzle", + "sub_path": "machine/Sovol Zero 1.0 Hardened Steel nozzle.json" } ] } diff --git a/resources/profiles/Sovol/filament/Generic ABS @Sovol Zero.json b/resources/profiles/Sovol/filament/Generic ABS @Sovol Zero.json index 3b737e2a18..7c24b7a0aa 100644 --- a/resources/profiles/Sovol/filament/Generic ABS @Sovol Zero.json +++ b/resources/profiles/Sovol/filament/Generic ABS @Sovol Zero.json @@ -1,10 +1,11 @@ { "type": "filament", "name": "Generic ABS @Sovol Zero", - "inherits": "Generic ABS @System", "renamed_from": "Sovol Zero ABS", + "inherits": "fdm_filament_abs", "from": "system", "setting_id": "g6sSyyIFYJUzlXsp", + "filament_id": "OFY9muEs", "instantiation": "true", "filament_flow_ratio": [ "0.98" @@ -73,6 +74,39 @@ "0" ], "compatible_printers": [ - "Sovol Zero 0.4 nozzle" + "Sovol Zero 0.2 nozzle", + "Sovol Zero 0.4 nozzle", + "Sovol Zero 0.6 nozzle", + "Sovol Zero 0.8 nozzle", + "Sovol Zero 1.0 nozzle", + "Sovol Zero 0.2 Hardened Steel nozzle", + "Sovol Zero 0.4 Hardened Steel nozzle", + "Sovol Zero 0.6 Hardened Steel nozzle", + "Sovol Zero 0.8 Hardened Steel nozzle", + "Sovol Zero 1.0 Hardened Steel nozzle" + ], + "cool_plate_temp": [ + "80" + ], + "eng_plate_temp": [ + "80" + ], + "textured_plate_temp": [ + "80" + ], + "cool_plate_temp_initial_layer": [ + "80" + ], + "eng_plate_temp_initial_layer": [ + "80" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_density": [ + "1.10" ] } diff --git a/resources/profiles/Sovol/filament/Generic PC @Sovol Zero.json b/resources/profiles/Sovol/filament/Generic PC @Sovol Zero.json index dd0eb60594..832deb1368 100644 --- a/resources/profiles/Sovol/filament/Generic PC @Sovol Zero.json +++ b/resources/profiles/Sovol/filament/Generic PC @Sovol Zero.json @@ -1,11 +1,12 @@ { "type": "filament", + "filament_id": "OFLakOUI", + "setting_id": "yRKCiPMN6fxibcyg", "name": "Generic PC @Sovol Zero", - "inherits": "Generic PC @System", "renamed_from": "Sovol Zero PC", "from": "system", - "setting_id": "yRKCiPMN6fxibcyg", "instantiation": "true", + "inherits": "fdm_filament_pc", "filament_flow_ratio": [ "0.98" ], @@ -13,7 +14,16 @@ "21" ], "compatible_printers": [ - "Sovol Zero 0.4 nozzle" + "Sovol Zero 0.2 nozzle", + "Sovol Zero 0.4 nozzle", + "Sovol Zero 0.6 nozzle", + "Sovol Zero 0.8 nozzle", + "Sovol Zero 1.0 nozzle", + "Sovol Zero 0.2 Hardened Steel nozzle", + "Sovol Zero 0.4 Hardened Steel nozzle", + "Sovol Zero 0.6 Hardened Steel nozzle", + "Sovol Zero 0.8 Hardened Steel nozzle", + "Sovol Zero 1.0 Hardened Steel nozzle" ], "nozzle_temperature_initial_layer": [ "290" @@ -51,7 +61,9 @@ "slow_down_min_speed": [ "10" ], - "dont_slow_down_outer_wall": "0", + "dont_slow_down_outer_wall": [ + "0" + ], "overhang_fan_speed": [ "20" ], @@ -61,8 +73,19 @@ "temperature_vitrification": [ "60" ], - "additional_cooling_fan_speed": "0", - "activate_air_filtration": "1", - "during_print_exhaust_fan_speed": "50", - "complete_print_exhaust_fan_speed": "50" + "additional_cooling_fan_speed": [ + "0" + ], + "activate_air_filtration": [ + "1" + ], + "during_print_exhaust_fan_speed": [ + "50" + ], + "complete_print_exhaust_fan_speed": [ + "50" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ] } diff --git a/resources/profiles/Sovol/filament/Generic PETG @Sovol Zero Hardened Steel nozzle.json b/resources/profiles/Sovol/filament/Generic PETG @Sovol Zero Hardened Steel nozzle.json new file mode 100644 index 0000000000..ef6a6324e3 --- /dev/null +++ b/resources/profiles/Sovol/filament/Generic PETG @Sovol Zero Hardened Steel nozzle.json @@ -0,0 +1,116 @@ +{ + "type": "filament", + "filament_id": "OFYPdQJh", + "setting_id": "d9QbCESNz3ZLU6eu", + "name": "Generic PETG @Sovol Zero Hardened Steel nozzle", + "renamed_from": "Sovol Zero PETG HS Nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pet", + "filament_flow_ratio": [ + "0.98" + ], + "enable_pressure_advance": [ + "1" + ], + "pressure_advance": [ + "0.048" + ], + "filament_max_volumetric_speed": [ + "15" + ], + "nozzle_temperature_initial_layer": [ + "265" + ], + "nozzle_temperature": [ + "250" + ], + "nozzle_temperature_range_low": [ + "230" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "hot_plate_temp": [ + "85" + ], + "hot_plate_temp_initial_layer": [ + "85" + ], + "fan_min_speed": [ + "10" + ], + "fan_max_speed": [ + "40" + ], + "fan_cooling_layer_time": [ + "50" + ], + "full_fan_speed_layer": [ + "3" + ], + "slow_down_layer_time": [ + "10" + ], + "slow_down_min_speed": [ + "10" + ], + "overhang_fan_speed": [ + "70" + ], + "overhang_fan_threshold": [ + "10%" + ], + "temperature_vitrification": [ + "60" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "filament_retraction_length": [ + "0.5" + ], + "filament_z_hop": [ + "0.4" + ], + "activate_air_filtration": [ + "1" + ], + "during_print_exhaust_fan_speed": [ + "50" + ], + "complete_print_exhaust_fan_speed": [ + "50" + ], + "compatible_printers": [ + "Sovol Zero 0.2 Hardened Steel nozzle", + "Sovol Zero 0.4 Hardened Steel nozzle", + "Sovol Zero 0.6 Hardened Steel nozzle", + "Sovol Zero 0.8 Hardened Steel nozzle", + "Sovol Zero 1.0 Hardened Steel nozzle" + ], + "cool_plate_temp": [ + "85" + ], + "eng_plate_temp": [ + "85" + ], + "textured_plate_temp": [ + "85" + ], + "cool_plate_temp_initial_layer": [ + "85" + ], + "eng_plate_temp_initial_layer": [ + "85" + ], + "textured_plate_temp_initial_layer": [ + "85" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ] +} diff --git a/resources/profiles/Sovol/filament/Generic PETG @Sovol Zero.json b/resources/profiles/Sovol/filament/Generic PETG @Sovol Zero.json index a223521d25..b9632637ad 100644 --- a/resources/profiles/Sovol/filament/Generic PETG @Sovol Zero.json +++ b/resources/profiles/Sovol/filament/Generic PETG @Sovol Zero.json @@ -1,16 +1,21 @@ { "type": "filament", + "filament_id": "OFYPdQJh", + "setting_id": "i4OW2eAtXOKdtVNj", "name": "Generic PETG @Sovol Zero", - "inherits": "Generic PETG @System", "renamed_from": "Sovol Zero PETG", "from": "system", - "setting_id": "i4OW2eAtXOKdtVNj", "instantiation": "true", + "inherits": "fdm_filament_pet", "filament_flow_ratio": [ "1.0348" ], - "enable_pressure_advance": "1", - "pressure_advance": "0.046", + "enable_pressure_advance": [ + "1" + ], + "pressure_advance": [ + "0.046" + ], "filament_max_volumetric_speed": [ "15" ], @@ -68,10 +73,44 @@ "filament_z_hop": [ "0.4" ], - "activate_air_filtration": "1", - "during_print_exhaust_fan_speed": "50", - "complete_print_exhaust_fan_speed": "50", + "activate_air_filtration": [ + "1" + ], + "during_print_exhaust_fan_speed": [ + "50" + ], + "complete_print_exhaust_fan_speed": [ + "50" + ], "compatible_printers": [ - "Sovol Zero 0.4 nozzle" + "Sovol Zero 0.2 nozzle", + "Sovol Zero 0.4 nozzle", + "Sovol Zero 0.6 nozzle", + "Sovol Zero 0.8 nozzle", + "Sovol Zero 1.0 nozzle" + ], + "cool_plate_temp": [ + "85" + ], + "eng_plate_temp": [ + "85" + ], + "textured_plate_temp": [ + "85" + ], + "cool_plate_temp_initial_layer": [ + "85" + ], + "eng_plate_temp_initial_layer": [ + "85" + ], + "textured_plate_temp_initial_layer": [ + "85" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_start_gcode": [ + "; filament start gcode\n" ] } diff --git a/resources/profiles/Sovol/filament/Generic PLA @Sovol Zero Hardened Steel nozzle.json b/resources/profiles/Sovol/filament/Generic PLA @Sovol Zero Hardened Steel nozzle.json new file mode 100644 index 0000000000..bba0cbfb51 --- /dev/null +++ b/resources/profiles/Sovol/filament/Generic PLA @Sovol Zero Hardened Steel nozzle.json @@ -0,0 +1,110 @@ +{ + "type": "filament", + "filament_id": "OFDSrzZ8", + "setting_id": "nZgETe4CTpicEjQX", + "name": "Generic PLA @Sovol Zero Hardened Steel nozzle", + "renamed_from": "Sovol Zero PLA Basic HS Nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pla", + "filament_flow_ratio": [ + "1.0348" + ], + "filament_max_volumetric_speed": [ + "21" + ], + "enable_pressure_advance": [ + "1" + ], + "pressure_advance": [ + "0.03" + ], + "compatible_printers": [ + "Sovol Zero 0.2 Hardened Steel nozzle", + "Sovol Zero 0.4 Hardened Steel nozzle", + "Sovol Zero 0.6 Hardened Steel nozzle", + "Sovol Zero 0.8 Hardened Steel nozzle", + "Sovol Zero 1.0 Hardened Steel nozzle" + ], + "nozzle_temperature_initial_layer": [ + "245" + ], + "nozzle_temperature": [ + "230" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_range_high": [ + "250" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "fan_min_speed": [ + "70" + ], + "fan_max_speed": [ + "100" + ], + "fan_cooling_layer_time": [ + "80" + ], + "full_fan_speed_layer": [ + "3" + ], + "slow_down_layer_time": [ + "5" + ], + "slow_down_min_speed": [ + "10" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "temperature_vitrification": [ + "60" + ], + "additional_cooling_fan_speed": [ + "75%" + ], + "activate_air_filtration": [ + "1" + ], + "during_print_exhaust_fan_speed": [ + "80%" + ], + "complete_print_exhaust_fan_speed": [ + "80%" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp": [ + "60" + ], + "textured_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "55" + ], + "eng_plate_temp_initial_layer": [ + "55" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ] +} diff --git a/resources/profiles/Sovol/filament/Generic PLA @Sovol Zero.json b/resources/profiles/Sovol/filament/Generic PLA @Sovol Zero.json index 131867f6b8..c8424af4f4 100644 --- a/resources/profiles/Sovol/filament/Generic PLA @Sovol Zero.json +++ b/resources/profiles/Sovol/filament/Generic PLA @Sovol Zero.json @@ -1,21 +1,24 @@ { "type": "filament", + "filament_id": "OFDSrzZ8", + "setting_id": "NNDerIjh7qtuh1I3", "name": "Generic PLA @Sovol Zero", - "inherits": "Generic PLA @System", "renamed_from": "Sovol Zero PLA Basic", "from": "system", - "setting_id": "NNDerIjh7qtuh1I3", "instantiation": "true", + "inherits": "fdm_filament_pla", "filament_flow_ratio": [ "0.98" ], "filament_max_volumetric_speed": [ - "21" + "25" ], - "enable_pressure_advance": "1", - "pressure_advance": "0.032", "compatible_printers": [ - "Sovol Zero 0.4 nozzle" + "Sovol Zero 0.2 nozzle", + "Sovol Zero 0.4 nozzle", + "Sovol Zero 0.6 nozzle", + "Sovol Zero 0.8 nozzle", + "Sovol Zero 1.0 nozzle" ], "nozzle_temperature_initial_layer": [ "230" @@ -24,28 +27,28 @@ "210" ], "nozzle_temperature_range_low": [ - "190" + "180" ], "nozzle_temperature_range_high": [ - "250" + "240" ], "hot_plate_temp": [ - "65" + "60" ], "hot_plate_temp_initial_layer": [ - "65" + "60" ], "fan_min_speed": [ - "70" + "100" ], "fan_max_speed": [ "100" ], "fan_cooling_layer_time": [ - "80" + "60" ], "full_fan_speed_layer": [ - "3" + "2" ], "slow_down_layer_time": [ "5" @@ -53,18 +56,43 @@ "slow_down_min_speed": [ "10" ], - "dont_slow_down_outer_wall": "0", "overhang_fan_speed": [ "100" ], "overhang_fan_threshold": [ - "50%" + "10%" ], "temperature_vitrification": [ + "50" + ], + "filament_z_hop": [ + "0.4" + ], + "filament_retraction_length": [ + "0.4" + ], + "filament_diameter": [ + "1.75" + ], + "cool_plate_temp": [ "60" ], - "additional_cooling_fan_speed": "75%", - "activate_air_filtration": "1", - "during_print_exhaust_fan_speed": "80%", - "complete_print_exhaust_fan_speed": "80%" + "eng_plate_temp": [ + "60" + ], + "textured_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "55" + ], + "eng_plate_temp_initial_layer": [ + "55" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ] } diff --git a/resources/profiles/Sovol/filament/Generic PLA SPEEDBENCHY @Sovol Zero.json b/resources/profiles/Sovol/filament/Generic PLA SPEEDBENCHY @Sovol Zero.json new file mode 100644 index 0000000000..a9aefc6bd2 --- /dev/null +++ b/resources/profiles/Sovol/filament/Generic PLA SPEEDBENCHY @Sovol Zero.json @@ -0,0 +1,118 @@ +{ + "type": "filament", + "filament_id": "OFIUkWYN", + "setting_id": "MC2InZ7iKDjIGike", + "name": "Generic PLA SPEEDBENCHY @Sovol Zero", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pla", + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "50" + ], + "compatible_printers": [ + "Sovol Zero 0.4 nozzle", + "Sovol Zero 0.4 Hardened Steel nozzle" + ], + "nozzle_temperature_initial_layer": [ + "245" + ], + "nozzle_temperature": [ + "225" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_range_high": [ + "250" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "enable_pressure_advance": [ + "1" + ], + "pressure_advance": [ + "0.032" + ], + "fan_min_speed": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_cooling_layer_time": [ + "30" + ], + "full_fan_speed_layer": [ + "3" + ], + "slow_down_layer_time": [ + "1.7" + ], + "slow_down_min_speed": [ + "40" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "75%" + ], + "additional_cooling_fan_speed": [ + "100" + ], + "filament_z_hop": [ + "0" + ], + "filament_retraction_length": [ + "0.35" + ], + "filament_retraction_speed": [ + "90" + ], + "filament_deretraction_speed": [ + "90" + ], + "filament_retract_before_wipe": [ + "0%" + ], + "filament_wipe_distance": [ + "2" + ], + "filament_retract_when_changing_layer": [ + "0" + ], + "filament_diameter": [ + "1.75" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp": [ + "60" + ], + "textured_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "55" + ], + "eng_plate_temp_initial_layer": [ + "55" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ], + "temperature_vitrification": [ + "100" + ] +} diff --git a/resources/profiles/Sovol/filament/Generic PLA Silk @Sovol Zero Hardened Steel nozzle.json b/resources/profiles/Sovol/filament/Generic PLA Silk @Sovol Zero Hardened Steel nozzle.json new file mode 100644 index 0000000000..7347fa08de --- /dev/null +++ b/resources/profiles/Sovol/filament/Generic PLA Silk @Sovol Zero Hardened Steel nozzle.json @@ -0,0 +1,110 @@ +{ + "type": "filament", + "filament_id": "OFesA6rF", + "setting_id": "LA8X1RsMdV2xNT1o", + "name": "Generic PLA Silk @Sovol Zero Hardened Steel nozzle", + "renamed_from": "Sovol Zero PLA Silk HS Nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pla", + "filament_flow_ratio": [ + "0.98" + ], + "filament_max_volumetric_speed": [ + "15" + ], + "enable_pressure_advance": [ + "1" + ], + "pressure_advance": [ + "0.027" + ], + "compatible_printers": [ + "Sovol Zero 0.2 Hardened Steel nozzle", + "Sovol Zero 0.4 Hardened Steel nozzle", + "Sovol Zero 0.6 Hardened Steel nozzle", + "Sovol Zero 0.8 Hardened Steel nozzle", + "Sovol Zero 1.0 Hardened Steel nozzle" + ], + "nozzle_temperature_initial_layer": [ + "245" + ], + "nozzle_temperature": [ + "230" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_range_high": [ + "250" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "fan_min_speed": [ + "70" + ], + "fan_max_speed": [ + "100" + ], + "fan_cooling_layer_time": [ + "80" + ], + "full_fan_speed_layer": [ + "3" + ], + "slow_down_layer_time": [ + "5" + ], + "slow_down_min_speed": [ + "10" + ], + "dont_slow_down_outer_wall": [ + "0" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "temperature_vitrification": [ + "60" + ], + "additional_cooling_fan_speed": [ + "75%" + ], + "activate_air_filtration": [ + "1" + ], + "during_print_exhaust_fan_speed": [ + "80%" + ], + "complete_print_exhaust_fan_speed": [ + "80%" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp": [ + "60" + ], + "textured_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "55" + ], + "eng_plate_temp_initial_layer": [ + "55" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ] +} diff --git a/resources/profiles/Sovol/filament/Generic PLA Silk @Sovol Zero.json b/resources/profiles/Sovol/filament/Generic PLA Silk @Sovol Zero.json index 5b46a92d64..6c9c27a00a 100644 --- a/resources/profiles/Sovol/filament/Generic PLA Silk @Sovol Zero.json +++ b/resources/profiles/Sovol/filament/Generic PLA Silk @Sovol Zero.json @@ -1,27 +1,30 @@ { "type": "filament", + "filament_id": "OFesA6rF", + "setting_id": "Se2yKerHRStYtWf5", "name": "Generic PLA Silk @Sovol Zero", - "inherits": "Generic PLA Silk @System", "renamed_from": "Sovol Zero PLA Silk", "from": "system", - "setting_id": "Se2yKerHRStYtWf5", "instantiation": "true", - "filament_multitool_ramming_flow": [ - "20" - ], - "filament_retraction_length": [ - "nil" - ], + "inherits": "fdm_filament_pla", "filament_flow_ratio": [ "0.98" ], "filament_max_volumetric_speed": [ "15" ], - "enable_pressure_advance": "1", - "pressure_advance": "0.029", + "enable_pressure_advance": [ + "1" + ], + "pressure_advance": [ + "0.029" + ], "compatible_printers": [ - "Sovol Zero 0.4 nozzle" + "Sovol Zero 0.2 nozzle", + "Sovol Zero 0.4 nozzle", + "Sovol Zero 0.6 nozzle", + "Sovol Zero 0.8 nozzle", + "Sovol Zero 1.0 nozzle" ], "nozzle_temperature_initial_layer": [ "245" @@ -59,7 +62,9 @@ "slow_down_min_speed": [ "10" ], - "dont_slow_down_outer_wall": "0", + "dont_slow_down_outer_wall": [ + "0" + ], "overhang_fan_speed": [ "100" ], @@ -69,8 +74,43 @@ "temperature_vitrification": [ "60" ], - "additional_cooling_fan_speed": "75%", - "activate_air_filtration": "1", - "during_print_exhaust_fan_speed": "80%", - "complete_print_exhaust_fan_speed": "80%" + "additional_cooling_fan_speed": [ + "75%" + ], + "activate_air_filtration": [ + "1" + ], + "during_print_exhaust_fan_speed": [ + "80%" + ], + "complete_print_exhaust_fan_speed": [ + "80%" + ], + "filament_multitool_ramming_flow": [ + "20" + ], + "filament_retraction_length": [ + "nil" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp": [ + "60" + ], + "textured_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "55" + ], + "eng_plate_temp_initial_layer": [ + "55" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ] } diff --git a/resources/profiles/Sovol/filament/Generic TPU @Sovol Zero.json b/resources/profiles/Sovol/filament/Generic TPU @Sovol Zero.json index 8c7c18c523..8624043cf9 100644 --- a/resources/profiles/Sovol/filament/Generic TPU @Sovol Zero.json +++ b/resources/profiles/Sovol/filament/Generic TPU @Sovol Zero.json @@ -1,11 +1,12 @@ { "type": "filament", + "filament_id": "OFgbpcy9", + "setting_id": "MlY6WQ41FE8zDPSV", "name": "Generic TPU @Sovol Zero", - "inherits": "Generic TPU @System", "renamed_from": "Sovol Zero TPU", "from": "system", - "setting_id": "MlY6WQ41FE8zDPSV", "instantiation": "true", + "inherits": "fdm_filament_tpu", "filament_flow_ratio": [ "0.98" ], @@ -60,11 +61,55 @@ "filament_z_hop": [ "0.4" ], - "additional_cooling_fan_speed": "50", - "activate_air_filtration": "1", - "during_print_exhaust_fan_speed": "100", - "complete_print_exhaust_fan_speed": "50", + "additional_cooling_fan_speed": [ + "50" + ], + "activate_air_filtration": [ + "1" + ], + "during_print_exhaust_fan_speed": [ + "100" + ], + "complete_print_exhaust_fan_speed": [ + "50" + ], "compatible_printers": [ - "Sovol Zero 0.4 nozzle" + "Sovol Zero 0.2 nozzle", + "Sovol Zero 0.4 nozzle", + "Sovol Zero 0.6 nozzle", + "Sovol Zero 0.8 nozzle", + "Sovol Zero 1.0 nozzle", + "Sovol Zero 0.2 Hardened Steel nozzle", + "Sovol Zero 0.4 Hardened Steel nozzle", + "Sovol Zero 0.6 Hardened Steel nozzle", + "Sovol Zero 0.8 Hardened Steel nozzle", + "Sovol Zero 1.0 Hardened Steel nozzle" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp": [ + "60" + ], + "textured_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "55" + ], + "eng_plate_temp_initial_layer": [ + "55" + ], + "textured_plate_temp_initial_layer": [ + "55" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_start_gcode": [ + "; filament start gcode\n" ] } diff --git a/resources/profiles/Sovol/filament/Sovol Zero PETG HS Nozzle.json b/resources/profiles/Sovol/filament/Sovol Zero PETG HS Nozzle.json deleted file mode 100644 index ce68719ba9..0000000000 --- a/resources/profiles/Sovol/filament/Sovol Zero PETG HS Nozzle.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "type": "filament", - "name": "Sovol Zero PETG HS Nozzle", - "inherits": "Generic PETG @System", - "from": "system", - "setting_id": "AfxHmpdOkMDJa2fk", - "filament_id": "OFymnal9", - "instantiation": "true", - "filament_flow_ratio": [ - "0.98" - ], - "enable_pressure_advance": "1", - "pressure_advance": "0.048", - "filament_max_volumetric_speed": [ - "15" - ], - "nozzle_temperature_initial_layer": [ - "265" - ], - "nozzle_temperature": [ - "250" - ], - "nozzle_temperature_range_low": [ - "230" - ], - "nozzle_temperature_range_high": [ - "280" - ], - "hot_plate_temp": [ - "85" - ], - "hot_plate_temp_initial_layer": [ - "85" - ], - "fan_min_speed": [ - "10" - ], - "fan_max_speed": [ - "40" - ], - "fan_cooling_layer_time": [ - "50" - ], - "full_fan_speed_layer": [ - "3" - ], - "slow_down_layer_time": [ - "10" - ], - "slow_down_min_speed": [ - "10" - ], - "overhang_fan_speed": [ - "70" - ], - "overhang_fan_threshold": [ - "10%" - ], - "temperature_vitrification": [ - "60" - ], - "close_fan_the_first_x_layers": [ - "1" - ], - "filament_retraction_length": [ - "0.5" - ], - "filament_z_hop": [ - "0.4" - ], - "activate_air_filtration": "1", - "during_print_exhaust_fan_speed": "50", - "complete_print_exhaust_fan_speed": "50", - "compatible_printers": [ - "Sovol Zero 0.4 nozzle" - ] -} diff --git a/resources/profiles/Sovol/filament/Sovol Zero PLA Basic HS Nozzle.json b/resources/profiles/Sovol/filament/Sovol Zero PLA Basic HS Nozzle.json deleted file mode 100644 index 6dfb630e0a..0000000000 --- a/resources/profiles/Sovol/filament/Sovol Zero PLA Basic HS Nozzle.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "type": "filament", - "name": "Sovol Zero PLA Basic HS Nozzle", - "inherits": "Generic PLA @System", - "from": "system", - "setting_id": "i9wDnSEIrOBPbOZl", - "filament_id": "OFzB4uOs", - "instantiation": "true", - "filament_flow_ratio": [ - "1.0348" - ], - "filament_max_volumetric_speed": [ - "21" - ], - "enable_pressure_advance": "1", - "pressure_advance": "0.03", - "compatible_printers": [ - "Sovol Zero 0.4 nozzle" - ], - "nozzle_temperature_initial_layer": [ - "245" - ], - "nozzle_temperature": [ - "230" - ], - "nozzle_temperature_range_low": [ - "190" - ], - "nozzle_temperature_range_high": [ - "250" - ], - "hot_plate_temp": [ - "65" - ], - "hot_plate_temp_initial_layer": [ - "65" - ], - "fan_min_speed": [ - "70" - ], - "fan_max_speed": [ - "100" - ], - "fan_cooling_layer_time": [ - "80" - ], - "full_fan_speed_layer": [ - "3" - ], - "slow_down_layer_time": [ - "5" - ], - "slow_down_min_speed": [ - "10" - ], - "dont_slow_down_outer_wall": "0", - "overhang_fan_speed": [ - "100" - ], - "overhang_fan_threshold": [ - "50%" - ], - "temperature_vitrification": [ - "60" - ], - "additional_cooling_fan_speed": "75%", - "activate_air_filtration": "1", - "during_print_exhaust_fan_speed": "80%", - "complete_print_exhaust_fan_speed": "80%" -} diff --git a/resources/profiles/Sovol/filament/Sovol Zero PLA Silk HS Nozzle.json b/resources/profiles/Sovol/filament/Sovol Zero PLA Silk HS Nozzle.json deleted file mode 100644 index 97e4050b8c..0000000000 --- a/resources/profiles/Sovol/filament/Sovol Zero PLA Silk HS Nozzle.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "type": "filament", - "name": "Sovol Zero PLA Silk HS Nozzle", - "inherits": "Generic PLA @System", - "from": "system", - "setting_id": "XxEJBNFLRltR2Xwn", - "filament_id": "OFAO9A7J", - "instantiation": "true", - "filament_flow_ratio": [ - "0.98" - ], - "filament_max_volumetric_speed": [ - "15" - ], - "enable_pressure_advance": "1", - "pressure_advance": "0.027", - "compatible_printers": [ - "Sovol Zero 0.4 nozzle" - ], - "nozzle_temperature_initial_layer": [ - "245" - ], - "nozzle_temperature": [ - "230" - ], - "nozzle_temperature_range_low": [ - "190" - ], - "nozzle_temperature_range_high": [ - "250" - ], - "hot_plate_temp": [ - "65" - ], - "hot_plate_temp_initial_layer": [ - "65" - ], - "fan_min_speed": [ - "70" - ], - "fan_max_speed": [ - "100" - ], - "fan_cooling_layer_time": [ - "80" - ], - "full_fan_speed_layer": [ - "3" - ], - "slow_down_layer_time": [ - "5" - ], - "slow_down_min_speed": [ - "10" - ], - "dont_slow_down_outer_wall": "0", - "overhang_fan_speed": [ - "100" - ], - "overhang_fan_threshold": [ - "50%" - ], - "temperature_vitrification": [ - "60" - ], - "additional_cooling_fan_speed": "75%", - "activate_air_filtration": "1", - "during_print_exhaust_fan_speed": "80%", - "complete_print_exhaust_fan_speed": "80%" -} diff --git a/resources/profiles/Sovol/machine/Sovol Zero 0.2 Hardened Steel nozzle.json b/resources/profiles/Sovol/machine/Sovol Zero 0.2 Hardened Steel nozzle.json new file mode 100644 index 0000000000..89ee9c1c09 --- /dev/null +++ b/resources/profiles/Sovol/machine/Sovol Zero 0.2 Hardened Steel nozzle.json @@ -0,0 +1,19 @@ +{ + "type": "machine", + "name": "Sovol Zero 0.2 Hardened Steel nozzle", + "inherits": "Sovol Zero 0.2 nozzle", + "from": "system", + "setting_id": "OkvEInEyzUUJzw9K", + "instantiation": "true", + "printer_model": "Sovol Zero", + "printer_variant": "0.2HS", + "nozzle_diameter": [ + "0.2" + ], + "default_filament_profile": [ + "Generic PLA @Sovol Zero Hardened Steel nozzle" + ], + "nozzle_type": [ + "hardened_steel" + ] +} diff --git a/resources/profiles/Sovol/machine/Sovol Zero 0.2 nozzle.json b/resources/profiles/Sovol/machine/Sovol Zero 0.2 nozzle.json new file mode 100644 index 0000000000..33fb16508a --- /dev/null +++ b/resources/profiles/Sovol/machine/Sovol Zero 0.2 nozzle.json @@ -0,0 +1,118 @@ +{ + "type": "machine", + "setting_id": "MAF2n6b8uoY92qVH", + "name": "Sovol Zero 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_machine_common", + "printer_model": "Sovol Zero", + "default_print_profile": "0.10mm Standard @Sovol Zero 0.2 nozzle", + "printer_variant": "0.2", + "nozzle_diameter": [ + "0.2" + ], + "min_layer_height": [ + "0.04" + ], + "max_layer_height": [ + "0.2" + ], + "retract_before_wipe": [ + "0%" + ], + "printable_area": [ + "0x0", + "152.4x0", + "152.4x152.4", + "0x152.4" + ], + "printable_height": "152.4", + "gcode_flavor": "klipper", + "retraction_length": [ + "1.8" + ], + "machine_max_speed_e": [ + "50" + ], + "machine_max_speed_x": [ + "1200" + ], + "machine_max_speed_y": [ + "1200" + ], + "machine_max_speed_z": [ + "30" + ], + "machine_max_acceleration_e": [ + "20000" + ], + "machine_max_acceleration_extruding": [ + "40000" + ], + "machine_max_acceleration_retracting": [ + "20000" + ], + "machine_max_acceleration_travel": [ + "40000" + ], + "machine_max_acceleration_x": [ + "40000" + ], + "machine_max_acceleration_y": [ + "40000" + ], + "machine_max_acceleration_z": [ + "1000" + ], + "machine_max_jerk_e": [ + "2.5" + ], + "machine_max_jerk_x": [ + "5" + ], + "machine_max_jerk_y": [ + "5" + ], + "machine_max_jerk_z": [ + "0.5" + ], + "z_hop": [ + "0.6" + ], + "retraction_speed": [ + "40" + ], + "deretraction_speed": [ + "40" + ], + "retraction_minimum_travel": [ + "0" + ], + "retract_length_toolchange": [ + "2" + ], + "wipe": [ + "1" + ], + "wipe_distance": [ + "3" + ], + "z_hop_types": [ + "Auto Lift" + ], + "thumbnails": [ + "300x300", + "32x32" + ], + "retract_lift_below": [ + "150" + ], + "auxiliary_fan": "1", + "thumbnails_format": "PNG", + "before_layer_change_gcode": "TIMELAPSE_TAKE_FRAME\nG92 E0\nSET_PRINT_STATS_INFO CURRENT_LAYER=[layer_num]\n", + "machine_start_gcode": "M140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\nG28\nSTART_PRINT\nG28\nG90\nG1 X0 Y0 F12000\nG1 Z0.300 F600\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nM109 S[nozzle_temperature_initial_layer];wait for extruder temp\n{if first_layer_print_min[1] - 6 > print_bed_min[1]}\nG90\nM83\nG1 E-0.5 F600\nG1 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4} Y{first_layer_print_min[1] - 5} F12000\nG0 Z0.3 F600 ;Move to start position\nG1 E0.200 F600\n{if first_layer_print_max[0] - first_layer_print_min[0] > 50}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*1} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*4} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*5} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*8} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*9} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n{else}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 2} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0])} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\n{endif}\nG1 E-0.300 F600\nG0 Z1 F600\nG1 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4} Y{first_layer_print_min[1] - 4} F12000\nG0 Z0.3 F600 ;Move to start position\nG1 E0.200 F600\n{if first_layer_print_max[0] - first_layer_print_min[0] > 50}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*1} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*4} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*5} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*8} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*9} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n{else}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 2} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0])} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\n{endif}\nG1 E-0.300 F600\nG0 Z5 F600\nM400\n{else}\nG90\nM83\nG1 E-0.300 Z3 F600\nG1 X{print_bed_max[1] / 3} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 Z0.3 F600\nG1 E0.300 F600\nG1 X{print_bed_max[1] / 3 + 5*1} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*4} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*5} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*8} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*9} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3} Y1 F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*1} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*4} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*5} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*8} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*9} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 E-0.300 Z3 F600\nM400\n{endif}\nSET_PRINT_STATS_INFO TOTAL_LAYER=[total_layer_count]\n\n", + "machine_end_gcode": "END_PRINT\n", + "default_filament_profile": [ + "Generic PLA @Sovol Zero" + ] +} diff --git a/resources/profiles/Sovol/machine/Sovol Zero 0.4 Hardened Steel nozzle.json b/resources/profiles/Sovol/machine/Sovol Zero 0.4 Hardened Steel nozzle.json new file mode 100644 index 0000000000..515c4cf696 --- /dev/null +++ b/resources/profiles/Sovol/machine/Sovol Zero 0.4 Hardened Steel nozzle.json @@ -0,0 +1,19 @@ +{ + "type": "machine", + "name": "Sovol Zero 0.4 Hardened Steel nozzle", + "inherits": "Sovol Zero 0.4 nozzle", + "from": "system", + "setting_id": "RqwHKS8MYRdoeJPi", + "instantiation": "true", + "printer_model": "Sovol Zero", + "printer_variant": "0.4HS", + "nozzle_diameter": [ + "0.4" + ], + "default_filament_profile": [ + "Generic PLA @Sovol Zero Hardened Steel nozzle" + ], + "nozzle_type": [ + "hardened_steel" + ] +} diff --git a/resources/profiles/Sovol/machine/Sovol Zero 0.4 nozzle.json b/resources/profiles/Sovol/machine/Sovol Zero 0.4 nozzle.json index a5699a9eed..932c5b9121 100644 --- a/resources/profiles/Sovol/machine/Sovol Zero 0.4 nozzle.json +++ b/resources/profiles/Sovol/machine/Sovol Zero 0.4 nozzle.json @@ -1,18 +1,24 @@ { "type": "machine", - "name": "Sovol Zero 0.4 nozzle", - "inherits": "fdm_machine_common", - "from": "system", "setting_id": "QclEa2nmpBiii6Y0", + "name": "Sovol Zero 0.4 nozzle", + "from": "system", "instantiation": "true", + "inherits": "fdm_machine_common", "printer_model": "Sovol Zero", "default_print_profile": "0.20mm Standard @Sovol Zero 0.4 nozzle", "printer_variant": "0.4", "nozzle_diameter": [ "0.4" ], + "min_layer_height": [ + "0.08" + ], + "max_layer_height": [ + "0.32" + ], "retract_before_wipe": [ - "100%" + "0%" ], "printable_area": [ "0x0", @@ -23,7 +29,7 @@ "printable_height": "152.4", "gcode_flavor": "klipper", "retraction_length": [ - "0.8" + "1.8" ], "machine_max_speed_e": [ "50" @@ -71,7 +77,7 @@ "0.5" ], "z_hop": [ - "0.4" + "0.6" ], "retraction_speed": [ "40" @@ -89,7 +95,7 @@ "1" ], "wipe_distance": [ - "2" + "3" ], "z_hop_types": [ "Auto Lift" @@ -104,7 +110,7 @@ "auxiliary_fan": "1", "thumbnails_format": "PNG", "before_layer_change_gcode": "TIMELAPSE_TAKE_FRAME\nG92 E0\nSET_PRINT_STATS_INFO CURRENT_LAYER=[layer_num]\n", - "machine_start_gcode": "M140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\nG28\nSTART_PRINT\nG28\nG90\nG1 X0 Y0 F12000\nG1 Z0.300 F600\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nM109 S[nozzle_temperature_initial_layer];wait for extruder temp\n{if first_layer_print_min[1] - 6 > print_bed_min[1]}\nG90\nM83\nG1 E-0.5 F600\nG1 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4} Y{first_layer_print_min[1] - 5} F12000\nG0 Z0.3 F600 ;Move to start position\nG1 E0.200 F600\n{if first_layer_print_max[0] - first_layer_print_min[0] > 50}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*1} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*4} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*5} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*8} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*9} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n{else}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 2} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0])} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n{endif}\nG1 E-0.300 F600\nG0 Z1 F600\nG1 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4} Y{first_layer_print_min[1] - 4} F12000\nG0 Z0.3 F600 ;Move to start position\nG1 E0.200 F600\n{if first_layer_print_max[0] - first_layer_print_min[0] > 50}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*1} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*4} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*5} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*8} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*9} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n{else}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 2} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0])} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n{endif}\nG1 E-0.300 F600\nG0 Z5 F600\nM400\n{else}\nG90\nM83\nG1 E-0.300 Z3 F600\nG1 X{print_bed_max[1] / 3} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 Z0.3 F600\nG1 E0.300 F600\nG1 X{print_bed_max[1] / 3 + 5*1} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*4} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*5} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*8} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*9} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3} Y1 F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*1} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*4} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*5} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*8} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*9} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 E-0.300 Z3 F600\nM400\n{endif}\nSET_PRINT_STATS_INFO TOTAL_LAYER=[total_layer_count]\n\n", + "machine_start_gcode": "M140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\nG28\nSTART_PRINT\nG28\nG90\nG1 X0 Y0 F12000\nG1 Z0.300 F600\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nM109 S[nozzle_temperature_initial_layer];wait for extruder temp\n{if first_layer_print_min[1] - 6 > print_bed_min[1]}\nG90\nM83\nG1 E-0.5 F600\nG1 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4} Y{first_layer_print_min[1] - 5} F12000\nG0 Z0.3 F600 ;Move to start position\nG1 E0.200 F600\n{if first_layer_print_max[0] - first_layer_print_min[0] > 50}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*1} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*4} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*5} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*8} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*9} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n{else}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 2} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0])} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\n{endif}\nG1 E-0.300 F600\nG0 Z1 F600\nG1 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4} Y{first_layer_print_min[1] - 4} F12000\nG0 Z0.3 F600 ;Move to start position\nG1 E0.200 F600\n{if first_layer_print_max[0] - first_layer_print_min[0] > 50}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*1} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*4} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*5} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*8} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*9} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n{else}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 2} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0])} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\n{endif}\nG1 E-0.300 F600\nG0 Z5 F600\nM400\n{else}\nG90\nM83\nG1 E-0.300 Z3 F600\nG1 X{print_bed_max[1] / 3} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 Z0.3 F600\nG1 E0.300 F600\nG1 X{print_bed_max[1] / 3 + 5*1} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*4} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*5} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*8} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*9} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3} Y1 F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*1} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*4} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*5} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*8} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*9} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 E-0.300 Z3 F600\nM400\n{endif}\nSET_PRINT_STATS_INFO TOTAL_LAYER=[total_layer_count]\n\n", "machine_end_gcode": "END_PRINT\n", "default_filament_profile": [ "Generic PLA @Sovol Zero" diff --git a/resources/profiles/Sovol/machine/Sovol Zero 0.6 Hardened Steel nozzle.json b/resources/profiles/Sovol/machine/Sovol Zero 0.6 Hardened Steel nozzle.json new file mode 100644 index 0000000000..5b53d59ae2 --- /dev/null +++ b/resources/profiles/Sovol/machine/Sovol Zero 0.6 Hardened Steel nozzle.json @@ -0,0 +1,19 @@ +{ + "type": "machine", + "name": "Sovol Zero 0.6 Hardened Steel nozzle", + "inherits": "Sovol Zero 0.6 nozzle", + "from": "system", + "setting_id": "s3N3FJkWrzOylFm8", + "instantiation": "true", + "printer_model": "Sovol Zero", + "printer_variant": "0.6HS", + "nozzle_diameter": [ + "0.6" + ], + "default_filament_profile": [ + "Generic PLA @Sovol Zero Hardened Steel nozzle" + ], + "nozzle_type": [ + "hardened_steel" + ] +} diff --git a/resources/profiles/Sovol/machine/Sovol Zero 0.6 nozzle.json b/resources/profiles/Sovol/machine/Sovol Zero 0.6 nozzle.json new file mode 100644 index 0000000000..e2cfc7ccc5 --- /dev/null +++ b/resources/profiles/Sovol/machine/Sovol Zero 0.6 nozzle.json @@ -0,0 +1,118 @@ +{ + "type": "machine", + "setting_id": "BlngL0WExXTeyrXg", + "name": "Sovol Zero 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_machine_common", + "printer_model": "Sovol Zero", + "default_print_profile": "0.30mm Standard @Sovol Zero 0.6 nozzle", + "printer_variant": "0.6", + "nozzle_diameter": [ + "0.6" + ], + "min_layer_height": [ + "0.12" + ], + "max_layer_height": [ + "0.48" + ], + "retract_before_wipe": [ + "0%" + ], + "printable_area": [ + "0x0", + "152.4x0", + "152.4x152.4", + "0x152.4" + ], + "printable_height": "152.4", + "gcode_flavor": "klipper", + "retraction_length": [ + "3.0" + ], + "machine_max_speed_e": [ + "50" + ], + "machine_max_speed_x": [ + "1200" + ], + "machine_max_speed_y": [ + "1200" + ], + "machine_max_speed_z": [ + "30" + ], + "machine_max_acceleration_e": [ + "20000" + ], + "machine_max_acceleration_extruding": [ + "40000" + ], + "machine_max_acceleration_retracting": [ + "20000" + ], + "machine_max_acceleration_travel": [ + "40000" + ], + "machine_max_acceleration_x": [ + "40000" + ], + "machine_max_acceleration_y": [ + "40000" + ], + "machine_max_acceleration_z": [ + "1000" + ], + "machine_max_jerk_e": [ + "2.5" + ], + "machine_max_jerk_x": [ + "5" + ], + "machine_max_jerk_y": [ + "5" + ], + "machine_max_jerk_z": [ + "0.5" + ], + "z_hop": [ + "0.6" + ], + "retraction_speed": [ + "40" + ], + "deretraction_speed": [ + "40" + ], + "retraction_minimum_travel": [ + "0" + ], + "retract_length_toolchange": [ + "2" + ], + "wipe": [ + "1" + ], + "wipe_distance": [ + "3" + ], + "z_hop_types": [ + "Auto Lift" + ], + "thumbnails": [ + "300x300", + "32x32" + ], + "retract_lift_below": [ + "150" + ], + "auxiliary_fan": "1", + "thumbnails_format": "PNG", + "before_layer_change_gcode": "TIMELAPSE_TAKE_FRAME\nG92 E0\nSET_PRINT_STATS_INFO CURRENT_LAYER=[layer_num]\n", + "machine_start_gcode": "M140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\nG28\nSTART_PRINT\nG28\nG90\nG1 X0 Y0 F12000\nG1 Z0.300 F600\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nM109 S[nozzle_temperature_initial_layer];wait for extruder temp\n{if first_layer_print_min[1] - 6 > print_bed_min[1]}\nG90\nM83\nG1 E-0.5 F600\nG1 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4} Y{first_layer_print_min[1] - 5} F12000\nG0 Z0.3 F600 ;Move to start position\nG1 E0.200 F600\n{if first_layer_print_max[0] - first_layer_print_min[0] > 50}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*1} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*4} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*5} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*8} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*9} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n{else}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 2} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0])} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\n{endif}\nG1 E-0.300 F600\nG0 Z1 F600\nG1 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4} Y{first_layer_print_min[1] - 4} F12000\nG0 Z0.3 F600 ;Move to start position\nG1 E0.200 F600\n{if first_layer_print_max[0] - first_layer_print_min[0] > 50}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*1} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*4} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*5} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*8} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*9} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n{else}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 2} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0])} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\n{endif}\nG1 E-0.300 F600\nG0 Z5 F600\nM400\n{else}\nG90\nM83\nG1 E-0.300 Z3 F600\nG1 X{print_bed_max[1] / 3} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 Z0.3 F600\nG1 E0.300 F600\nG1 X{print_bed_max[1] / 3 + 5*1} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*4} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*5} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*8} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*9} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3} Y1 F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*1} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*4} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*5} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*8} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*9} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 E-0.300 Z3 F600\nM400\n{endif}\nSET_PRINT_STATS_INFO TOTAL_LAYER=[total_layer_count]\n\n", + "machine_end_gcode": "END_PRINT\n", + "default_filament_profile": [ + "Generic PLA @Sovol Zero" + ] +} diff --git a/resources/profiles/Sovol/machine/Sovol Zero 0.8 Hardened Steel nozzle.json b/resources/profiles/Sovol/machine/Sovol Zero 0.8 Hardened Steel nozzle.json new file mode 100644 index 0000000000..db6bd740fb --- /dev/null +++ b/resources/profiles/Sovol/machine/Sovol Zero 0.8 Hardened Steel nozzle.json @@ -0,0 +1,19 @@ +{ + "type": "machine", + "name": "Sovol Zero 0.8 Hardened Steel nozzle", + "inherits": "Sovol Zero 0.8 nozzle", + "from": "system", + "setting_id": "houacf8sQ3bLozqD", + "instantiation": "true", + "printer_model": "Sovol Zero", + "printer_variant": "0.8HS", + "nozzle_diameter": [ + "0.8" + ], + "default_filament_profile": [ + "Generic PLA @Sovol Zero Hardened Steel nozzle" + ], + "nozzle_type": [ + "hardened_steel" + ] +} diff --git a/resources/profiles/Sovol/machine/Sovol Zero 0.8 nozzle.json b/resources/profiles/Sovol/machine/Sovol Zero 0.8 nozzle.json new file mode 100644 index 0000000000..bc67a64ce5 --- /dev/null +++ b/resources/profiles/Sovol/machine/Sovol Zero 0.8 nozzle.json @@ -0,0 +1,118 @@ +{ + "type": "machine", + "setting_id": "DDpJMY1A2r4k1Cho", + "name": "Sovol Zero 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_machine_common", + "printer_model": "Sovol Zero", + "default_print_profile": "0.40mm Standard @Sovol Zero 0.8 nozzle", + "printer_variant": "0.8", + "nozzle_diameter": [ + "0.8" + ], + "min_layer_height": [ + "0.08" + ], + "max_layer_height": [ + "0.64" + ], + "retract_before_wipe": [ + "0%" + ], + "printable_area": [ + "0x0", + "152.4x0", + "152.4x152.4", + "0x152.4" + ], + "printable_height": "152.4", + "gcode_flavor": "klipper", + "retraction_length": [ + "3.0" + ], + "machine_max_speed_e": [ + "50" + ], + "machine_max_speed_x": [ + "1200" + ], + "machine_max_speed_y": [ + "1200" + ], + "machine_max_speed_z": [ + "30" + ], + "machine_max_acceleration_e": [ + "20000" + ], + "machine_max_acceleration_extruding": [ + "40000" + ], + "machine_max_acceleration_retracting": [ + "20000" + ], + "machine_max_acceleration_travel": [ + "40000" + ], + "machine_max_acceleration_x": [ + "40000" + ], + "machine_max_acceleration_y": [ + "40000" + ], + "machine_max_acceleration_z": [ + "1000" + ], + "machine_max_jerk_e": [ + "2.5" + ], + "machine_max_jerk_x": [ + "5" + ], + "machine_max_jerk_y": [ + "5" + ], + "machine_max_jerk_z": [ + "0.5" + ], + "z_hop": [ + "0.6" + ], + "retraction_speed": [ + "40" + ], + "deretraction_speed": [ + "40" + ], + "retraction_minimum_travel": [ + "0" + ], + "retract_length_toolchange": [ + "2" + ], + "wipe": [ + "1" + ], + "wipe_distance": [ + "3" + ], + "z_hop_types": [ + "Auto Lift" + ], + "thumbnails": [ + "300x300", + "32x32" + ], + "retract_lift_below": [ + "150" + ], + "auxiliary_fan": "1", + "thumbnails_format": "PNG", + "before_layer_change_gcode": "TIMELAPSE_TAKE_FRAME\nG92 E0\nSET_PRINT_STATS_INFO CURRENT_LAYER=[layer_num]\n", + "machine_start_gcode": "M140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\nG28\nSTART_PRINT\nG28\nG90\nG1 X0 Y0 F12000\nG1 Z0.300 F600\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nM109 S[nozzle_temperature_initial_layer];wait for extruder temp\n{if first_layer_print_min[1] - 6 > print_bed_min[1]}\nG90\nM83\nG1 E-0.5 F600\nG1 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4} Y{first_layer_print_min[1] - 5} F12000\nG0 Z0.3 F600 ;Move to start position\nG1 E0.200 F600\n{if first_layer_print_max[0] - first_layer_print_min[0] > 50}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*1} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*4} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*5} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*8} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*9} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n{else}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 2} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0])} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\n{endif}\nG1 E-0.300 F600\nG0 Z1 F600\nG1 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4} Y{first_layer_print_min[1] - 4} F12000\nG0 Z0.3 F600 ;Move to start position\nG1 E0.200 F600\n{if first_layer_print_max[0] - first_layer_print_min[0] > 50}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*1} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*4} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*5} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*8} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*9} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n{else}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 2} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0])} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\n{endif}\nG1 E-0.300 F600\nG0 Z5 F600\nM400\n{else}\nG90\nM83\nG1 E-0.300 Z3 F600\nG1 X{print_bed_max[1] / 3} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 Z0.3 F600\nG1 E0.300 F600\nG1 X{print_bed_max[1] / 3 + 5*1} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*4} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*5} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*8} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*9} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3} Y1 F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*1} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*4} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*5} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*8} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*9} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 E-0.300 Z3 F600\nM400\n{endif}\nSET_PRINT_STATS_INFO TOTAL_LAYER=[total_layer_count]\n\n", + "machine_end_gcode": "END_PRINT\n", + "default_filament_profile": [ + "Generic PLA @Sovol Zero" + ] +} diff --git a/resources/profiles/Sovol/machine/Sovol Zero 1.0 Hardened Steel nozzle.json b/resources/profiles/Sovol/machine/Sovol Zero 1.0 Hardened Steel nozzle.json new file mode 100644 index 0000000000..73b99e55ef --- /dev/null +++ b/resources/profiles/Sovol/machine/Sovol Zero 1.0 Hardened Steel nozzle.json @@ -0,0 +1,19 @@ +{ + "type": "machine", + "name": "Sovol Zero 1.0 Hardened Steel nozzle", + "inherits": "Sovol Zero 1.0 nozzle", + "from": "system", + "setting_id": "sqlEiL0in8LSjmmn", + "instantiation": "true", + "printer_model": "Sovol Zero", + "printer_variant": "1.0HS", + "nozzle_diameter": [ + "1.0" + ], + "default_filament_profile": [ + "Generic PLA @Sovol Zero Hardened Steel nozzle" + ], + "nozzle_type": [ + "hardened_steel" + ] +} diff --git a/resources/profiles/Sovol/machine/Sovol Zero 1.0 nozzle.json b/resources/profiles/Sovol/machine/Sovol Zero 1.0 nozzle.json new file mode 100644 index 0000000000..beb6db80bd --- /dev/null +++ b/resources/profiles/Sovol/machine/Sovol Zero 1.0 nozzle.json @@ -0,0 +1,118 @@ +{ + "type": "machine", + "setting_id": "CGunT3KHnCqEAlrN", + "name": "Sovol Zero 1.0 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_machine_common", + "printer_model": "Sovol Zero", + "default_print_profile": "0.50mm Standard @Sovol Zero 1.0 nozzle", + "printer_variant": "1.0", + "nozzle_diameter": [ + "1.0" + ], + "min_layer_height": [ + "0.16" + ], + "max_layer_height": [ + "0.8" + ], + "retract_before_wipe": [ + "0%" + ], + "printable_area": [ + "0x0", + "152.4x0", + "152.4x152.4", + "0x152.4" + ], + "printable_height": "152.4", + "gcode_flavor": "klipper", + "retraction_length": [ + "3.0" + ], + "machine_max_speed_e": [ + "50" + ], + "machine_max_speed_x": [ + "1200" + ], + "machine_max_speed_y": [ + "1200" + ], + "machine_max_speed_z": [ + "30" + ], + "machine_max_acceleration_e": [ + "20000" + ], + "machine_max_acceleration_extruding": [ + "40000" + ], + "machine_max_acceleration_retracting": [ + "20000" + ], + "machine_max_acceleration_travel": [ + "40000" + ], + "machine_max_acceleration_x": [ + "40000" + ], + "machine_max_acceleration_y": [ + "40000" + ], + "machine_max_acceleration_z": [ + "1000" + ], + "machine_max_jerk_e": [ + "2.5" + ], + "machine_max_jerk_x": [ + "5" + ], + "machine_max_jerk_y": [ + "5" + ], + "machine_max_jerk_z": [ + "0.5" + ], + "z_hop": [ + "0.6" + ], + "retraction_speed": [ + "40" + ], + "deretraction_speed": [ + "40" + ], + "retraction_minimum_travel": [ + "0" + ], + "retract_length_toolchange": [ + "2" + ], + "wipe": [ + "1" + ], + "wipe_distance": [ + "3" + ], + "z_hop_types": [ + "Auto Lift" + ], + "thumbnails": [ + "300x300", + "32x32" + ], + "retract_lift_below": [ + "150" + ], + "auxiliary_fan": "1", + "thumbnails_format": "PNG", + "before_layer_change_gcode": "TIMELAPSE_TAKE_FRAME\nG92 E0\nSET_PRINT_STATS_INFO CURRENT_LAYER=[layer_num]\n", + "machine_start_gcode": "M140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\nG28\nSTART_PRINT\nG28\nG90\nG1 X0 Y0 F12000\nG1 Z0.300 F600\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nM109 S[nozzle_temperature_initial_layer];wait for extruder temp\n{if first_layer_print_min[1] - 6 > print_bed_min[1]}\nG90\nM83\nG1 E-0.5 F600\nG1 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4} Y{first_layer_print_min[1] - 5} F12000\nG0 Z0.3 F600 ;Move to start position\nG1 E0.200 F600\n{if first_layer_print_max[0] - first_layer_print_min[0] > 50}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*1} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*4} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*5} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*8} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*9} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n{else}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 2} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0])} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\n{endif}\nG1 E-0.300 F600\nG0 Z1 F600\nG1 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4} Y{first_layer_print_min[1] - 4} F12000\nG0 Z0.3 F600 ;Move to start position\nG1 E0.200 F600\n{if first_layer_print_max[0] - first_layer_print_min[0] > 50}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*1} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*4} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*5} E{5 * 0.2}F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*8} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*9} E{5 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 4 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n{else}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0]) / 2} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG0 X{first_layer_print_min[0] + (first_layer_print_max[0] - first_layer_print_min[0])} E{(first_layer_print_max[0] - first_layer_print_min[0]) / 2 * 0.2}F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\n{endif}\nG1 E-0.300 F600\nG0 Z5 F600\nM400\n{else}\nG90\nM83\nG1 E-0.300 Z3 F600\nG1 X{print_bed_max[1] / 3} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 Z0.3 F600\nG1 E0.300 F600\nG1 X{print_bed_max[1] / 3 + 5*1} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*4} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*5} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*8} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*9} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3} Y1 F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*1} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*2} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*3} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*4} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*5} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*6} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG1 X{print_bed_max[1] / 3 + 5*7} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20) * 60}\nG1 X{print_bed_max[1] / 3 + 5*8} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 X{print_bed_max[1] / 3 + 5*9} E{5 * 0.2} F{outer_wall_volumetric_speed/(24/20)* 60}\nG1 X{print_bed_max[1] / 3 + 5*10} E{5 * 0.2} F{outer_wall_volumetric_speed/(0.3*0.5)/4* 60}\nG1 E-0.300 Z3 F600\nM400\n{endif}\nSET_PRINT_STATS_INFO TOTAL_LAYER=[total_layer_count]\n\n", + "machine_end_gcode": "END_PRINT\n", + "default_filament_profile": [ + "Generic PLA @Sovol Zero" + ] +} diff --git a/resources/profiles/Sovol/machine/Sovol Zero.json b/resources/profiles/Sovol/machine/Sovol Zero.json index 6f99e8f8d0..1c67135cf9 100644 --- a/resources/profiles/Sovol/machine/Sovol Zero.json +++ b/resources/profiles/Sovol/machine/Sovol Zero.json @@ -2,11 +2,11 @@ "type": "machine_model", "name": "Sovol Zero", "model_id": "Sovol-Zero", - "nozzle_diameter": "0.4", + "nozzle_diameter": "0.2;0.4;0.6;0.8;1.0;0.2HS;0.4HS;0.6HS;0.8HS;1.0HS", "machine_tech": "FFF", "family": "Sovol", "bed_model": "sovol_zero_buildplate_model.stl", "bed_texture": "sovol_zero_buildplate_texture.svg", "hotend_model": "", - "default_materials": "Generic PLA @Sovol Zero;Sovol Zero PLA Basic HS Nozzle;Generic PLA Silk @Sovol Zero;Sovol Zero PLA Silk HS Nozzle;Generic ABS @Sovol Zero;Generic PETG @Sovol Zero;Sovol Zero PETG HS Nozzle;Generic TPU @Sovol Zero;Generic PC @Sovol Zero" + "default_materials": "Generic PLA @Sovol Zero;Generic PLA SPEEDBENCHY @Sovol Zero;Generic PLA @Sovol Zero Hardened Steel nozzle;Generic PLA Silk @Sovol Zero;Generic PLA Silk @Sovol Zero Hardened Steel nozzle;Generic ABS @Sovol Zero;Generic PETG @Sovol Zero;Generic PETG @Sovol Zero Hardened Steel nozzle;Generic TPU @Sovol Zero;Generic PC @Sovol Zero" } diff --git a/resources/profiles/Sovol/process/0.06mm Quality @Sovol Zero 0.2 nozzle.json b/resources/profiles/Sovol/process/0.06mm Quality @Sovol Zero 0.2 nozzle.json new file mode 100644 index 0000000000..908bfd9813 --- /dev/null +++ b/resources/profiles/Sovol/process/0.06mm Quality @Sovol Zero 0.2 nozzle.json @@ -0,0 +1,36 @@ +{ + "type": "process", + "name": "0.06mm Quality @Sovol Zero 0.2 nozzle", + "inherits": "fdm_process_zero", + "from": "system", + "setting_id": "fWP7jaL7sJmmZ6QN", + "instantiation": "true", + "layer_height": "0.06", + "bottom_shell_layers": "8", + "bottom_shell_thickness": "0.8", + "bridge_speed": "30", + "outer_wall_acceleration": "10000", + "top_surface_acceleration": "5000", + "outer_wall_line_width": "0.21", + "line_width": "0.21", + "sparse_infill_density": "15%", + "inner_wall_acceleration": "12000", + "initial_layer_print_height": "0.06", + "initial_layer_line_width": "0.3", + "infill_wall_overlap": "18", + "inner_wall_line_width": "0.22", + "wall_loops": "3", + "internal_solid_infill_line_width": "0.21", + "sparse_infill_line_width": "0.21", + "support_top_z_distance": "0.10", + "support_line_width": "0.21", + "tree_support_tip_diameter": "0.21", + "support_speed": "100", + "top_surface_line_width": "0.21", + "top_shell_layers": "8", + "top_shell_thickness": "1", + "compatible_printers": [ + "Sovol Zero 0.2 nozzle", + "Sovol Zero 0.2 Hardened Steel nozzle" + ] +} diff --git a/resources/profiles/Sovol/process/0.10mm Standard @Sovol Zero 0.2 nozzle.json b/resources/profiles/Sovol/process/0.10mm Standard @Sovol Zero 0.2 nozzle.json new file mode 100644 index 0000000000..15540bb172 --- /dev/null +++ b/resources/profiles/Sovol/process/0.10mm Standard @Sovol Zero 0.2 nozzle.json @@ -0,0 +1,36 @@ +{ + "type": "process", + "name": "0.10mm Standard @Sovol Zero 0.2 nozzle", + "inherits": "fdm_process_zero", + "from": "system", + "setting_id": "Gql3487jsaTXyuYZ", + "instantiation": "true", + "layer_height": "0.10", + "bottom_shell_layers": "4", + "bottom_shell_thickness": "0.8", + "bridge_speed": "50", + "outer_wall_acceleration": "10000", + "top_surface_acceleration": "5000", + "outer_wall_line_width": "0.22", + "line_width": "0.22", + "sparse_infill_density": "15%", + "inner_wall_acceleration": "12000", + "initial_layer_print_height": "0.12", + "initial_layer_line_width": "0.3", + "infill_wall_overlap": "20", + "inner_wall_line_width": "0.22", + "wall_loops": "2", + "internal_solid_infill_line_width": "0.22", + "sparse_infill_line_width": "0.22", + "support_top_z_distance": "0.20", + "support_line_width": "0.22", + "tree_support_tip_diameter": "0.22", + "support_speed": "100", + "top_surface_line_width": "0.22", + "top_shell_layers": "4", + "top_shell_thickness": "1", + "compatible_printers": [ + "Sovol Zero 0.2 nozzle", + "Sovol Zero 0.2 Hardened Steel nozzle" + ] +} diff --git a/resources/profiles/Sovol/process/0.12mm Quality @Sovol Zero 0.4 nozzle.json b/resources/profiles/Sovol/process/0.12mm Quality @Sovol Zero 0.4 nozzle.json new file mode 100644 index 0000000000..c1cc06a737 --- /dev/null +++ b/resources/profiles/Sovol/process/0.12mm Quality @Sovol Zero 0.4 nozzle.json @@ -0,0 +1,35 @@ +{ + "type": "process", + "setting_id": "CaEopiv2Wg6pQJjH", + "name": "0.12mm Quality @Sovol Zero 0.4 nozzle", + "from": "system", + "inherits": "fdm_process_zero", + "instantiation": "true", + "layer_height": "0.12", + "bottom_shell_layers": "8", + "bottom_shell_thickness": "0.8", + "bridge_speed": "30", + "outer_wall_acceleration": "10000", + "top_surface_acceleration": "5000", + "outer_wall_line_width": "0.42", + "line_width": "0.42", + "sparse_infill_density": "15%", + "inner_wall_acceleration": "12000", + "initial_layer_print_height": "0.12", + "initial_layer_line_width": "0.6", + "sparse_infill_line_width": "0.42", + "infill_wall_overlap": "18", + "inner_wall_line_width": "0.44", + "wall_loops": "3", + "support_top_z_distance": "0.10", + "support_line_width": "0.42", + "tree_support_tip_diameter": "0.42", + "support_speed": "100", + "top_surface_line_width": "0.42", + "internal_solid_infill_line_width": "0.42", + "top_shell_layers": "8", + "compatible_printers": [ + "Sovol Zero 0.4 nozzle", + "Sovol Zero 0.4 Hardened Steel nozzle" + ] +} diff --git a/resources/profiles/Sovol/process/0.14mm Fast @Sovol Zero 0.2 nozzle.json b/resources/profiles/Sovol/process/0.14mm Fast @Sovol Zero 0.2 nozzle.json new file mode 100644 index 0000000000..79fe17eb39 --- /dev/null +++ b/resources/profiles/Sovol/process/0.14mm Fast @Sovol Zero 0.2 nozzle.json @@ -0,0 +1,36 @@ +{ + "type": "process", + "name": "0.14mm Fast @Sovol Zero 0.2 nozzle", + "inherits": "fdm_process_zero", + "from": "system", + "setting_id": "I9yoyCcGGTRrDoKu", + "instantiation": "true", + "layer_height": "0.14", + "bottom_shell_layers": "3", + "bottom_shell_thickness": "0", + "bridge_speed": "60", + "outer_wall_acceleration": "22000", + "top_surface_acceleration": "22000", + "outer_wall_line_width": "0.24", + "line_width": "0.24", + "sparse_infill_density": "10%", + "inner_wall_acceleration": "28000", + "initial_layer_print_height": "0.14", + "initial_layer_line_width": "0.3", + "infill_wall_overlap": "20", + "inner_wall_line_width": "0.24", + "wall_loops": "2", + "internal_solid_infill_line_width": "0.24", + "sparse_infill_line_width": "0.24", + "support_top_z_distance": "0.30", + "support_line_width": "0.24", + "tree_support_tip_diameter": "0.24", + "support_speed": "120", + "top_surface_line_width": "0.24", + "top_shell_layers": "4", + "top_shell_thickness": "1", + "compatible_printers": [ + "Sovol Zero 0.2 nozzle", + "Sovol Zero 0.2 Hardened Steel nozzle" + ] +} diff --git a/resources/profiles/Sovol/process/0.15mm Quality @Sovol Zero 0.6 nozzle.json b/resources/profiles/Sovol/process/0.15mm Quality @Sovol Zero 0.6 nozzle.json new file mode 100644 index 0000000000..f532985258 --- /dev/null +++ b/resources/profiles/Sovol/process/0.15mm Quality @Sovol Zero 0.6 nozzle.json @@ -0,0 +1,34 @@ +{ + "type": "process", + "setting_id": "IfDpa3vM99D4ytny", + "name": "0.15mm Quality @Sovol Zero 0.6 nozzle", + "from": "system", + "inherits": "fdm_process_zero", + "instantiation": "true", + "layer_height": "0.15", + "bottom_shell_layers": "5", + "bottom_shell_thickness": "0.8", + "bridge_speed": "30", + "outer_wall_acceleration": "10000", + "top_surface_acceleration": "5000", + "outer_wall_line_width": "0.63", + "line_width": "0.63", + "sparse_infill_density": "15%", + "inner_wall_acceleration": "12000", + "initial_layer_line_width": "0.9", + "sparse_infill_line_width": "0.63", + "infill_wall_overlap": "18", + "inner_wall_line_width": "0.66", + "wall_loops": "3", + "support_top_z_distance": "0.15", + "support_line_width": "0.63", + "tree_support_tip_diameter": "0.63", + "support_speed": "100", + "top_surface_line_width": "0.63", + "top_shell_layers": "5", + "internal_solid_infill_line_width": "0.63", + "compatible_printers": [ + "Sovol Zero 0.6 nozzle", + "Sovol Zero 0.6 Hardened Steel nozzle" + ] +} diff --git a/resources/profiles/Sovol/process/0.20mm Quality @Sovol Zero 0.8 nozzle.json b/resources/profiles/Sovol/process/0.20mm Quality @Sovol Zero 0.8 nozzle.json new file mode 100644 index 0000000000..c9774c6d65 --- /dev/null +++ b/resources/profiles/Sovol/process/0.20mm Quality @Sovol Zero 0.8 nozzle.json @@ -0,0 +1,42 @@ +{ + "type": "process", + "name": "0.20mm Quality @Sovol Zero 0.8 nozzle", + "inherits": "fdm_process_zero", + "from": "system", + "setting_id": "MSxikpQZNYdoBynZ", + "instantiation": "true", + "layer_height": "0.20", + "bottom_shell_layers": "4", + "bottom_shell_thickness": "0.8", + "bridge_speed": "30", + "outer_wall_acceleration": "10000", + "top_surface_acceleration": "5000", + "outer_wall_line_width": "0.84", + "line_width": "0.84", + "sparse_infill_density": "15%", + "inner_wall_acceleration": "12000", + "initial_layer_print_height": "0.36", + "initial_layer_line_width": "1.2", + "sparse_infill_line_width": "0.84", + "infill_wall_overlap": "18", + "inner_wall_line_width": "0.88", + "wall_loops": "3", + "support_top_z_distance": "0.20", + "support_line_width": "0.84", + "tree_support_tip_diameter": "0.84", + "support_speed": "100", + "top_surface_line_width": "0.84", + "top_shell_layers": "4", + "outer_wall_speed": "350", + "inner_wall_speed": "400", + "small_perimeter_speed": "50%", + "internal_solid_infill_speed": "200", + "internal_solid_infill_line_width": "0.84", + "top_surface_speed": "200", + "gap_infill_speed": "200", + "sparse_infill_speed": "500", + "compatible_printers": [ + "Sovol Zero 0.8 nozzle", + "Sovol Zero 0.8 Hardened Steel nozzle" + ] +} diff --git a/resources/profiles/Sovol/process/0.20mm Standard @Sovol Zero 0.4 nozzle.json b/resources/profiles/Sovol/process/0.20mm Standard @Sovol Zero 0.4 nozzle.json index 323553beaa..d8820163d6 100644 --- a/resources/profiles/Sovol/process/0.20mm Standard @Sovol Zero 0.4 nozzle.json +++ b/resources/profiles/Sovol/process/0.20mm Standard @Sovol Zero 0.4 nozzle.json @@ -1,141 +1,36 @@ { "type": "process", - "name": "0.20mm Standard @Sovol Zero 0.4 nozzle", - "inherits": "fdm_process_common", - "from": "system", "setting_id": "ShJTVnJ492No1j2j", + "name": "0.20mm Standard @Sovol Zero 0.4 nozzle", + "from": "system", + "inherits": "fdm_process_zero", "instantiation": "true", - "reduce_crossing_wall": "1", - "max_travel_detour_distance": "100%", "layer_height": "0.20", - "bottom_surface_pattern": "monotonic", - "bottom_shell_layers": "3", - "bottom_shell_thickness": "0", - "bridge_flow": "1.2", - "internal_bridge_flow": "1.2", + "bottom_shell_layers": "4", + "bottom_shell_thickness": "0.8", "bridge_speed": "50", - "internal_bridge_speed": "200", - "brim_type": "auto_brim", - "brim_width": "5", - "brim_object_gap": "0", - "compatible_printers_condition": "", - "print_sequence": "by layer", - "default_acceleration": "40000", "outer_wall_acceleration": "10000", "top_surface_acceleration": "5000", - "bridge_no_support": "0", - "draft_shield": "disabled", - "elefant_foot_compensation": "0.1", - "enable_arc_fitting": "0", - "exclude_object": "1", - "outer_wall_line_width": "0.4", - "wall_infill_order": "inner wall/outer wall/infill", - "line_width": "0.4", - "infill_direction": "45", - "sparse_infill_density": "10%", - "sparse_infill_pattern": "grid", - "internal_solid_infill_acceleration": "50%", - "initial_layer_acceleration": "1000", - "initial_solid_infill_acceleration": "3000", - "travel_acceleration": "40000", + "outer_wall_line_width": "0.44", + "line_width": "0.44", + "sparse_infill_density": "15%", "inner_wall_acceleration": "12000", - "outer_wall_jerk": "5", - "inner_wall_jerk": "5", - "infill_jerk": "5", - "top_surface_jerk": "5", - "initial_layer_jerk": "5", - "travel_jerk": "5", - "initial_layer_line_width": "0.42", - "initial_layer_print_height": "0.25", - "infill_combination": "0", - "sparse_infill_line_width": "0.45", - "infill_wall_overlap": "15%", - "interface_shells": "0", - "ironing_flow": "15%", - "ironing_spacing": "0.25", - "ironing_speed": "15", - "ironing_type": "no ironing", - "reduce_infill_retraction": "1", - "filename_format": "{printer_model}_{input_filename_base}_{filament_type[0]}_{layer_height}_{print_time}.gcode", - "detect_overhang_wall": "1", - "overhang_1_4_speed": "0", - "overhang_2_4_speed": "50", - "overhang_3_4_speed": "30", - "overhang_4_4_speed": "20", - "inner_wall_line_width": "0.4", + "initial_layer_print_height": "0.24", + "initial_layer_line_width": "0.6", + "sparse_infill_line_width": "0.44", + "infill_wall_overlap": "20", + "ironing_speed": "100", + "inner_wall_line_width": "0.44", "wall_loops": "2", - "print_settings_id": "", - "raft_layers": "0", - "seam_position": "aligned", - "skirt_distance": "0.8", - "skirt_height": "1", - "skirt_loops": "1", - "minimum_sparse_infill_area": "15", - "internal_solid_infill_line_width": "0.45", - "spiral_mode": "0", - "standby_temperature_delta": "-5", - "enable_support": "0", - "resolution": "0.012", - "support_type": "tree(auto)", - "support_style": "default", - "support_on_build_plate_only": "0", - "support_top_z_distance": "0.235", - "support_bottom_z_distance": "0.235", - "support_filament": "0", - "support_line_width": "0.45", - "support_interface_loop_pattern": "0", - "support_interface_filament": "0", - "support_interface_top_layers": "5", - "support_interface_bottom_layers": "-1", - "support_interface_spacing": "0.2", - "support_bottom_interface_spacing": "0.2", - "support_interface_speed": "100%", - "support_interface_pattern": "grid", - "support_base_pattern": "rectilinear", - "support_base_pattern_spacing": "3.5", - "support_speed": "100", - "support_threshold_angle": "20", - "support_object_xy_distance": "0.35", - "tree_support_branch_angle": "40", - "tree_support_wall_count": "0", - "detect_thin_wall": "1", - "top_surface_pattern": "monotonic", - "top_surface_line_width": "0.38", + "support_top_z_distance": "0.20", + "support_line_width": "0.44", + "tree_support_tip_diameter": "0.44", + "support_speed": "60", + "top_surface_line_width": "0.44", "top_shell_layers": "4", - "top_shell_thickness": "1", - "initial_layer_speed": "55", - "initial_layer_infill_speed": "105", - "initial_layer_travel_speed": "60%", - "outer_wall_speed": "350", - "inner_wall_speed": "400", - "small_perimeter_speed": "50%", - "internal_solid_infill_speed": "200", - "top_surface_speed": "200", - "gap_infill_speed": "200", - "sparse_infill_speed": "500", - "accel_to_decel_enable": "1", - "accel_to_decel_factor": "25%", - "travel_speed": "1000", - "enable_prime_tower": "1", - "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "60", - "xy_hole_compensation": "0", - "xy_contour_compensation": "0", - "bridge_acceleration": "50%", - "seam_gap": "10%", - "precise_outer_wall": "1", - "wall_generator": "classic", - "gcode_label_objects": "1", - "slow_down_layers": "3", - "top_solid_infill_flow_ratio": "0.9", - "only_one_wall_top": "1", - "wall_loop_direction": "clockwise", - "top_bottom_infill_wall_overlap": "25%", - "filter_out_gap_fill": "0", - "detect_narrow_internal_solid_infill": "1", - "thick_bridges": "1", - "bridge_angle": "0", + "internal_solid_infill_line_width": "0.44", "compatible_printers": [ - "Sovol Zero 0.4 nozzle" + "Sovol Zero 0.4 nozzle", + "Sovol Zero 0.4 Hardened Steel nozzle" ] } diff --git a/resources/profiles/Sovol/process/0.25mm Quality @Sovol Zero 1.0 nozzle.json b/resources/profiles/Sovol/process/0.25mm Quality @Sovol Zero 1.0 nozzle.json new file mode 100644 index 0000000000..60e8db168f --- /dev/null +++ b/resources/profiles/Sovol/process/0.25mm Quality @Sovol Zero 1.0 nozzle.json @@ -0,0 +1,79 @@ +{ + "type": "process", + "name": "0.25mm Quality @Sovol Zero 1.0 nozzle", + "inherits": "fdm_process_zero", + "from": "system", + "setting_id": "JUmnFOoEMJrbWCN9", + "instantiation": "true", + "layer_height": "0.25", + "bottom_shell_layers": "4", + "bottom_shell_thickness": "0.8", + "bridge_speed": "30", + "internal_bridge_speed": "200", + "default_acceleration": "40000", + "outer_wall_acceleration": "10000", + "top_surface_acceleration": "5000", + "outer_wall_line_width": "1.05", + "line_width": "1.05", + "sparse_infill_density": "15%", + "inner_wall_acceleration": "12000", + "initial_layer_print_height": "0.45", + "initial_layer_line_width": "1.5", + "infill_combination": "0", + "sparse_infill_line_width": "1.05", + "infill_wall_overlap": "18", + "interface_shells": "0", + "ironing_flow": "15%", + "ironing_spacing": "0.25", + "ironing_speed": "15", + "ironing_type": "no ironing", + "filename_format": "{input_filename_base}_{nozzle_diameter[0]}n_{filament_type[0]}_{layer_height}_{print_time}.gcode", + "detect_overhang_wall": "1", + "overhang_1_4_speed": "0", + "overhang_2_4_speed": "50", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "20", + "inner_wall_line_width": "1.1", + "wall_loops": "3", + "print_settings_id": "", + "raft_layers": "0", + "seam_position": "aligned", + "skirt_distance": "0.8", + "skirt_height": "1", + "skirt_loops": "1", + "minimum_sparse_infill_area": "15", + "internal_solid_infill_line_width": "1.05", + "spiral_mode": "0", + "standby_temperature_delta": "-5", + "enable_support": "0", + "resolution": "0.012", + "support_type": "tree(auto)", + "support_style": "snug", + "support_on_build_plate_only": "0", + "support_top_z_distance": "0.25", + "support_bottom_z_distance": "0.235", + "support_filament": "0", + "support_line_width": "1.05", + "tree_support_tip_diameter": "1.05", + "support_interface_loop_pattern": "0", + "support_interface_filament": "0", + "support_interface_top_layers": "5", + "support_interface_bottom_layers": "-1", + "support_interface_spacing": "0.2", + "support_bottom_interface_spacing": "0.2", + "support_interface_speed": "100%", + "support_interface_pattern": "grid", + "support_base_pattern": "rectilinear", + "support_base_pattern_spacing": "3.5", + "support_speed": "100", + "support_threshold_angle": "50", + "support_object_xy_distance": "0.35", + "tree_support_branch_angle": "40", + "top_surface_line_width": "1.05", + "top_shell_layers": "4", + "top_shell_thickness": "1", + "compatible_printers": [ + "Sovol Zero 1.0 nozzle", + "Sovol Zero 1.0 Hardened Steel nozzle" + ] +} diff --git a/resources/profiles/Sovol/process/0.25mm SPEEDBENCHY @Sovol Zero 0.4 nozzle.json b/resources/profiles/Sovol/process/0.25mm SPEEDBENCHY @Sovol Zero 0.4 nozzle.json new file mode 100644 index 0000000000..89e248b223 --- /dev/null +++ b/resources/profiles/Sovol/process/0.25mm SPEEDBENCHY @Sovol Zero 0.4 nozzle.json @@ -0,0 +1,85 @@ +{ + "type": "process", + "setting_id": "oFrWcSxmad1b6sD4", + "name": "0.25mm SPEEDBENCHY @Sovol Zero 0.4 nozzle", + "from": "system", + "inherits": "fdm_process_zero", + "instantiation": "true", + "layer_height": "0.25", + "initial_layer_print_height": "0.25", + "line_width": "0.5", + "initial_layer_line_width": "0.5", + "outer_wall_line_width": "0.5", + "inner_wall_line_width": "0.5", + "top_surface_line_width": "0.55", + "internal_solid_infill_line_width": "0.55", + "sparse_infill_line_width": "0.55", + "support_line_width": "0.5", + "tree_support_tip_diameter": "0.5", + "wall_loops": "2", + "top_shell_layers": "3", + "bottom_shell_layers": "3", + "bottom_shell_thickness": "0", + "sparse_infill_density": "10%", + "sparse_infill_pattern": "grid", + "bottom_solid_infill_flow_ratio": "1.2", + "top_solid_infill_flow_ratio": "1.4", + "bridge_flow": "1", + "internal_bridge_flow": "1", + "bridge_speed": "250", + "internal_bridge_speed": "250", + "bridge_acceleration": "100%", + "thick_bridges": "0", + "thick_internal_bridges": "0", + "brim_type": "outer_only", + "brim_width": "1", + "brim_object_gap": "0", + "filter_out_gap_fill": "13", + "gap_fill_target": "nowhere", + "min_width_top_surface": "200%", + "minimum_sparse_infill_area": "0", + "infill_direction": "0", + "solid_infill_direction": "0", + "infill_wall_overlap": "15%", + "reduce_crossing_wall": "0", + "skirt_loops": "0", + "only_one_wall_top": "1", + "slow_down_layers": "1", + "wall_direction": "cw", + "initial_layer_speed": "300", + "initial_layer_infill_speed": "300", + "initial_layer_travel_speed": "100%", + "outer_wall_speed": "350", + "inner_wall_speed": "400", + "small_perimeter_speed": "100%", + "internal_solid_infill_speed": "400", + "top_surface_speed": "300", + "gap_infill_speed": "350", + "sparse_infill_speed": "500", + "support_speed": "100", + "travel_speed": "1200", + "default_acceleration": "40000", + "initial_layer_acceleration": "20000", + "outer_wall_acceleration": "40000", + "inner_wall_acceleration": "40000", + "top_surface_acceleration": "20000", + "internal_solid_infill_acceleration": "100%", + "travel_acceleration": "40000", + "accel_to_decel_factor": "50%", + "outer_wall_jerk": "20", + "inner_wall_jerk": "20", + "infill_jerk": "20", + "top_surface_jerk": "20", + "initial_layer_jerk": "20", + "travel_jerk": "20", + "overhang_1_4_speed": "160", + "overhang_2_4_speed": "100", + "overhang_3_4_speed": "60", + "overhang_4_4_speed": "40", + "support_top_z_distance": "0.235", + "support_bottom_z_distance": "0.235", + "compatible_printers": [ + "Sovol Zero 0.4 nozzle", + "Sovol Zero 0.4 Hardened Steel nozzle" + ] +} diff --git a/resources/profiles/Sovol/process/0.28mm Fast @Sovol Zero 0.4 nozzle.json b/resources/profiles/Sovol/process/0.28mm Fast @Sovol Zero 0.4 nozzle.json new file mode 100644 index 0000000000..1ad361e3e2 --- /dev/null +++ b/resources/profiles/Sovol/process/0.28mm Fast @Sovol Zero 0.4 nozzle.json @@ -0,0 +1,39 @@ +{ + "type": "process", + "name": "0.28mm Fast @Sovol Zero 0.4 nozzle", + "inherits": "fdm_process_zero", + "from": "system", + "setting_id": "1VoML2LGDk4TJgLI", + "instantiation": "true", + "layer_height": "0.28", + "bottom_shell_layers": "3", + "bottom_shell_thickness": "0", + "bridge_speed": "60", + "outer_wall_acceleration": "22000", + "top_surface_acceleration": "22000", + "outer_wall_line_width": "0.48", + "line_width": "0.48", + "sparse_infill_density": "10%", + "inner_wall_acceleration": "28000", + "initial_layer_print_height": "0.28", + "initial_layer_line_width": "0.6", + "sparse_infill_line_width": "0.48", + "inner_wall_line_width": "0.48", + "internal_solid_infill_line_width": "0.48", + "support_top_z_distance": "0.30", + "support_line_width": "0.48", + "tree_support_tip_diameter": "0.48", + "support_speed": "120", + "top_surface_line_width": "0.48", + "outer_wall_speed": "350", + "inner_wall_speed": "400", + "small_perimeter_speed": "50%", + "internal_solid_infill_speed": "200", + "top_surface_speed": "200", + "gap_infill_speed": "200", + "sparse_infill_speed": "500", + "compatible_printers": [ + "Sovol Zero 0.4 nozzle", + "Sovol Zero 0.4 Hardened Steel nozzle" + ] +} diff --git a/resources/profiles/Sovol/process/0.30mm Standard @Sovol Zero 0.6 nozzle.json b/resources/profiles/Sovol/process/0.30mm Standard @Sovol Zero 0.6 nozzle.json new file mode 100644 index 0000000000..4f1f487bdf --- /dev/null +++ b/resources/profiles/Sovol/process/0.30mm Standard @Sovol Zero 0.6 nozzle.json @@ -0,0 +1,35 @@ +{ + "type": "process", + "setting_id": "lTAs2USEP8D749K7", + "name": "0.30mm Standard @Sovol Zero 0.6 nozzle", + "from": "system", + "inherits": "fdm_process_zero", + "instantiation": "true", + "layer_height": "0.30", + "bottom_shell_layers": "4", + "bottom_shell_thickness": "0.8", + "bridge_speed": "50", + "outer_wall_acceleration": "10000", + "top_surface_acceleration": "5000", + "outer_wall_line_width": "0.66", + "line_width": "0.66", + "sparse_infill_density": "15%", + "inner_wall_acceleration": "12000", + "initial_layer_print_height": "0.36", + "initial_layer_line_width": "0.9", + "sparse_infill_line_width": "0.66", + "infill_wall_overlap": "20", + "inner_wall_line_width": "0.66", + "wall_loops": "2", + "support_top_z_distance": "0.30", + "support_line_width": "0.66", + "tree_support_tip_diameter": "0.66", + "support_speed": "100", + "top_surface_line_width": "0.66", + "top_shell_layers": "4", + "internal_solid_infill_line_width": "0.66", + "compatible_printers": [ + "Sovol Zero 0.6 nozzle", + "Sovol Zero 0.6 Hardened Steel nozzle" + ] +} diff --git a/resources/profiles/Sovol/process/0.40mm Standard @Sovol Zero 0.8 nozzle.json b/resources/profiles/Sovol/process/0.40mm Standard @Sovol Zero 0.8 nozzle.json new file mode 100644 index 0000000000..7eeecf4ece --- /dev/null +++ b/resources/profiles/Sovol/process/0.40mm Standard @Sovol Zero 0.8 nozzle.json @@ -0,0 +1,42 @@ +{ + "type": "process", + "name": "0.40mm Standard @Sovol Zero 0.8 nozzle", + "inherits": "fdm_process_zero", + "from": "system", + "setting_id": "8x4CsuqroC9HOdAN", + "instantiation": "true", + "layer_height": "0.40", + "bottom_shell_layers": "4", + "bottom_shell_thickness": "0.8", + "bridge_speed": "50", + "outer_wall_acceleration": "10000", + "top_surface_acceleration": "5000", + "outer_wall_line_width": "0.88", + "line_width": "0.88", + "sparse_infill_density": "15%", + "inner_wall_acceleration": "12000", + "initial_layer_print_height": "0.48", + "initial_layer_line_width": "1.2", + "sparse_infill_line_width": "0.88", + "infill_wall_overlap": "20", + "inner_wall_line_width": "0.88", + "wall_loops": "2", + "support_top_z_distance": "0.40", + "support_line_width": "0.88", + "tree_support_tip_diameter": "0.88", + "support_speed": "100", + "top_surface_line_width": "0.88", + "top_shell_layers": "4", + "outer_wall_speed": "350", + "inner_wall_speed": "400", + "small_perimeter_speed": "50%", + "internal_solid_infill_speed": "200", + "top_surface_speed": "200", + "gap_infill_speed": "200", + "sparse_infill_speed": "500", + "internal_solid_infill_line_width": "0.88", + "compatible_printers": [ + "Sovol Zero 0.8 nozzle", + "Sovol Zero 0.8 Hardened Steel nozzle" + ] +} diff --git a/resources/profiles/Sovol/process/0.42mm Fast @Sovol Zero 0.6 nozzle.json b/resources/profiles/Sovol/process/0.42mm Fast @Sovol Zero 0.6 nozzle.json new file mode 100644 index 0000000000..75a9522c62 --- /dev/null +++ b/resources/profiles/Sovol/process/0.42mm Fast @Sovol Zero 0.6 nozzle.json @@ -0,0 +1,39 @@ +{ + "type": "process", + "name": "0.42mm Fast @Sovol Zero 0.6 nozzle", + "inherits": "fdm_process_zero", + "from": "system", + "setting_id": "illqJAnGiA2pY0hw", + "instantiation": "true", + "layer_height": "0.42", + "bottom_shell_layers": "3", + "bottom_shell_thickness": "0", + "bridge_speed": "60", + "outer_wall_acceleration": "22000", + "top_surface_acceleration": "22000", + "outer_wall_line_width": "0.72", + "line_width": "0.72", + "sparse_infill_density": "10%", + "inner_wall_acceleration": "28000", + "initial_layer_print_height": "0.42", + "initial_layer_line_width": "0.9", + "sparse_infill_line_width": "0.72", + "inner_wall_line_width": "0.72", + "internal_solid_infill_line_width": "0.72", + "support_top_z_distance": "0.45", + "support_line_width": "0.72", + "tree_support_tip_diameter": "0.72", + "support_speed": "120", + "top_surface_line_width": "0.72", + "outer_wall_speed": "350", + "inner_wall_speed": "400", + "small_perimeter_speed": "50%", + "internal_solid_infill_speed": "200", + "top_surface_speed": "200", + "gap_infill_speed": "200", + "sparse_infill_speed": "500", + "compatible_printers": [ + "Sovol Zero 0.6 nozzle", + "Sovol Zero 0.6 Hardened Steel nozzle" + ] +} diff --git a/resources/profiles/Sovol/process/0.50mm Standard @Sovol Zero 1.0 nozzle.json b/resources/profiles/Sovol/process/0.50mm Standard @Sovol Zero 1.0 nozzle.json new file mode 100644 index 0000000000..c1446a6536 --- /dev/null +++ b/resources/profiles/Sovol/process/0.50mm Standard @Sovol Zero 1.0 nozzle.json @@ -0,0 +1,87 @@ +{ + "type": "process", + "name": "0.50mm Standard @Sovol Zero 1.0 nozzle", + "inherits": "fdm_process_zero", + "from": "system", + "setting_id": "E5K55O4RkMyYCAlt", + "instantiation": "true", + "layer_height": "0.50", + "bottom_shell_layers": "4", + "bottom_shell_thickness": "0.8", + "bridge_speed": "45", + "internal_bridge_speed": "200", + "default_acceleration": "22000", + "outer_wall_acceleration": "16000", + "top_surface_acceleration": "16000", + "outer_wall_line_width": "1.1", + "line_width": "1.1", + "sparse_infill_density": "15%", + "inner_wall_acceleration": "22000", + "initial_layer_print_height": "0.60", + "initial_layer_line_width": "1.5", + "infill_combination": "0", + "sparse_infill_line_width": "1.1", + "infill_wall_overlap": "20", + "interface_shells": "0", + "ironing_flow": "15%", + "ironing_spacing": "0.25", + "ironing_speed": "15", + "ironing_type": "no ironing", + "filename_format": "{input_filename_base}_{nozzle_diameter[0]}n_{filament_type[0]}_{layer_height}_{print_time}.gcode", + "detect_overhang_wall": "1", + "overhang_1_4_speed": "0", + "overhang_2_4_speed": "50", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "20", + "inner_wall_line_width": "1.1", + "wall_loops": "2", + "print_settings_id": "", + "raft_layers": "0", + "seam_position": "aligned", + "skirt_distance": "0.8", + "skirt_height": "1", + "skirt_loops": "1", + "minimum_sparse_infill_area": "15", + "internal_solid_infill_line_width": "1.1", + "spiral_mode": "0", + "standby_temperature_delta": "-5", + "enable_support": "0", + "resolution": "0.012", + "support_type": "tree(auto)", + "support_style": "snug", + "support_on_build_plate_only": "0", + "support_top_z_distance": "0.50", + "support_bottom_z_distance": "0.235", + "support_filament": "0", + "support_line_width": "1.1", + "tree_support_tip_diameter": "1.1", + "support_interface_loop_pattern": "0", + "support_interface_filament": "0", + "support_interface_top_layers": "5", + "support_interface_bottom_layers": "-1", + "support_interface_spacing": "0.2", + "support_bottom_interface_spacing": "0.2", + "support_interface_speed": "100%", + "support_interface_pattern": "grid", + "support_base_pattern": "rectilinear", + "support_base_pattern_spacing": "3.5", + "support_speed": "60", + "support_threshold_angle": "50", + "support_object_xy_distance": "0.35", + "tree_support_branch_angle": "40", + "top_surface_line_width": "1.1", + "top_shell_layers": "4", + "top_shell_thickness": "1", + "outer_wall_speed": "30", + "inner_wall_speed": "45", + "small_perimeter_speed": "45", + "internal_solid_infill_speed": "45", + "top_surface_speed": "35", + "gap_infill_speed": "35", + "sparse_infill_speed": "70", + "travel_acceleration": "38000", + "compatible_printers": [ + "Sovol Zero 1.0 nozzle", + "Sovol Zero 1.0 Hardened Steel nozzle" + ] +} diff --git a/resources/profiles/Sovol/process/0.56mm Fast @Sovol Zero 0.8 nozzle.json b/resources/profiles/Sovol/process/0.56mm Fast @Sovol Zero 0.8 nozzle.json new file mode 100644 index 0000000000..3bef013a12 --- /dev/null +++ b/resources/profiles/Sovol/process/0.56mm Fast @Sovol Zero 0.8 nozzle.json @@ -0,0 +1,40 @@ +{ + "type": "process", + "name": "0.56mm Fast @Sovol Zero 0.8 nozzle", + "inherits": "fdm_process_zero", + "from": "system", + "setting_id": "g9PPRM4FLMwjMUfy", + "instantiation": "true", + "layer_height": "0.56", + "bottom_shell_layers": "3", + "bottom_shell_thickness": "0", + "bridge_speed": "60", + "default_acceleration": "28000", + "outer_wall_acceleration": "22000", + "top_surface_acceleration": "22000", + "outer_wall_line_width": "0.96", + "line_width": "0.96", + "sparse_infill_density": "10%", + "inner_wall_acceleration": "28000", + "initial_layer_print_height": "0.56", + "initial_layer_line_width": "1.2", + "sparse_infill_line_width": "0.96", + "inner_wall_line_width": "0.96", + "internal_solid_infill_line_width": "0.96", + "support_top_z_distance": "0.60", + "support_line_width": "0.96", + "tree_support_tip_diameter": "0.96", + "top_surface_line_width": "0.96", + "top_shell_layers": "4", + "outer_wall_speed": "35", + "inner_wall_speed": "55", + "small_perimeter_speed": "60", + "internal_solid_infill_speed": "55", + "top_surface_speed": "40", + "gap_infill_speed": "40", + "sparse_infill_speed": "80", + "compatible_printers": [ + "Sovol Zero 0.8 nozzle", + "Sovol Zero 0.8 Hardened Steel nozzle" + ] +} diff --git a/resources/profiles/Sovol/process/0.70mm Fast @Sovol Zero 1.0 nozzle.json b/resources/profiles/Sovol/process/0.70mm Fast @Sovol Zero 1.0 nozzle.json new file mode 100644 index 0000000000..39d5309914 --- /dev/null +++ b/resources/profiles/Sovol/process/0.70mm Fast @Sovol Zero 1.0 nozzle.json @@ -0,0 +1,33 @@ +{ + "type": "process", + "name": "0.70mm Fast @Sovol Zero 1.0 nozzle", + "inherits": "fdm_process_zero", + "from": "system", + "setting_id": "fW5KJBVndgQE868q", + "instantiation": "true", + "layer_height": "0.70", + "bottom_shell_layers": "3", + "bottom_shell_thickness": "0", + "bridge_speed": "60", + "outer_wall_acceleration": "22000", + "top_surface_acceleration": "22000", + "outer_wall_line_width": "1.2", + "line_width": "1.2", + "sparse_infill_density": "10%", + "inner_wall_acceleration": "28000", + "initial_layer_print_height": "0.70", + "initial_layer_line_width": "1.5", + "sparse_infill_line_width": "1.2", + "inner_wall_line_width": "1.2", + "internal_solid_infill_line_width": "1.2", + "support_top_z_distance": "0.75", + "support_line_width": "1.2", + "tree_support_tip_diameter": "1.2", + "support_speed": "120", + "top_surface_line_width": "1.2", + "top_shell_layers": "3", + "compatible_printers": [ + "Sovol Zero 1.0 nozzle", + "Sovol Zero 1.0 Hardened Steel nozzle" + ] +} diff --git a/resources/profiles/Sovol/process/fdm_process_zero.json b/resources/profiles/Sovol/process/fdm_process_zero.json new file mode 100644 index 0000000000..da4df2686e --- /dev/null +++ b/resources/profiles/Sovol/process/fdm_process_zero.json @@ -0,0 +1,73 @@ +{ + "type": "process", + "name": "fdm_process_zero", + "inherits": "fdm_process_common", + "from": "system", + "instantiation": "false", + "reduce_crossing_wall": "1", + "max_travel_detour_distance": "10", + "bottom_surface_pattern": "monotonic", + "bridge_flow": "1.2", + "internal_bridge_flow": "1.2", + "brim_type": "auto_brim", + "brim_width": "5", + "brim_object_gap": "0", + "print_sequence": "by layer", + "bridge_no_support": "0", + "draft_shield": "disabled", + "elefant_foot_compensation": "0.1", + "enable_arc_fitting": "0", + "exclude_object": "1", + "wall_infill_order": "inner wall/outer wall/infill", + "infill_direction": "45", + "sparse_infill_pattern": "grid", + "internal_solid_infill_acceleration": "50%", + "initial_layer_acceleration": "1000", + "travel_acceleration": "40000", + "outer_wall_jerk": "5", + "inner_wall_jerk": "5", + "infill_jerk": "5", + "top_surface_jerk": "5", + "initial_layer_jerk": "5", + "travel_jerk": "5", + "tree_support_wall_count": "0", + "reduce_infill_retraction": "1", + "detect_thin_wall": "1", + "top_surface_pattern": "monotonic", + "initial_layer_speed": "55", + "initial_layer_infill_speed": "105", + "initial_layer_travel_speed": "60%", + "outer_wall_speed": "350", + "inner_wall_speed": "400", + "small_perimeter_speed": "50%", + "internal_solid_infill_speed": "200", + "top_surface_speed": "200", + "gap_infill_speed": "200", + "sparse_infill_speed": "500", + "accel_to_decel_enable": "1", + "accel_to_decel_factor": "25%", + "travel_speed": "1000", + "enable_prime_tower": "0", + "wipe_tower_no_sparse_layers": "0", + "prime_tower_width": "60", + "xy_hole_compensation": "0", + "xy_contour_compensation": "0", + "bridge_acceleration": "50%", + "seam_gap": "10%", + "precise_outer_wall": "1", + "wall_generator": "classic", + "gcode_label_objects": "1", + "slow_down_layers": "3", + "top_solid_infill_flow_ratio": "0.9", + "only_one_wall_top": "1", + "top_bottom_infill_wall_overlap": "25%", + "filter_out_gap_fill": "0", + "detect_narrow_internal_solid_infill": "1", + "thick_bridges": "1", + "bridge_angle": "0", + "initial_layer_line_width": "150%", + "default_acceleration": "40000", + "compatible_printers": [], + "internal_bridge_speed": "150", + "filename_format": "{input_filename_base}_{nozzle_diameter[0]}n_{filament_type[0]}_{layer_height}_{print_time}.gcode" +} diff --git a/scripts/tests/test_filament_id.py b/scripts/tests/test_filament_id.py index 001763fca9..fc62f5abc3 100644 --- a/scripts/tests/test_filament_id.py +++ b/scripts/tests/test_filament_id.py @@ -405,6 +405,20 @@ class TestTripleResolution(unittest.TestCase): self.assertEqual(afi.resolve_triple("MyPLA @P1", fmap, {}), ("MyVendor", "PLA", "MyPLA")) + def test_split_vendor_and_type_bases_resolve(self): + # A partial base is normal, not an error: vendor and type may live on + # different ancestors, with an intermediate supplying neither (the + # Snapmaker shape). The pair is complete at the instantiated preset. + recs = [ + self.rec("APLA @P1", inherits="mid"), + self.rec("mid", inherits="typebase"), + self.rec("typebase", filament_type=["PLA"], inherits="vendorbase"), + self.rec("vendorbase", filament_vendor=["AV"]), + ] + fmap = {r["name"]: r for r in recs} + self.assertEqual(afi.resolve_triple("APLA @P1", fmap, {}), + ("AV", "PLA", "APLA")) + # --------------------------------------------------------------------------- # checks on synthetic trees @@ -417,6 +431,24 @@ class TestChecks(OfCleanTreeCase): self.assertNotIn("[ERROR]", out) self.assertNotIn("[WARNING]", out) + def test_instantiated_preset_over_partial_bases_is_silent(self): + # Vendor and type split across two non-instantiated bases, an + # intermediate base with neither: base profiles are allowed to be + # partial. Only the instantiated preset must resolve both. + self.t.write_preset("VendorA", preset("XPLA vendorbase", instantiation=False, + filament_vendor="XV")) + self.t.write_preset("VendorA", preset("XPLA typebase", instantiation=False, + filament_type="PLA", + inherits="XPLA vendorbase")) + self.t.write_preset("VendorA", preset("XPLA mid", instantiation=False, + inherits="XPLA typebase")) + self.t.write_preset("VendorA", preset( + "XPLA @P1", inherits="XPLA mid", + filament_id=afi.generate_filament_id("XV", "PLA", "XPLA"), + compatible_printers=["P1"])) + errors, out = self.t.check() + self.assertEqual(errors, 0, out) + def test_check1_unknown_non_of_id(self): self.t.write_preset("VendorA", preset("BPLA @base", filament_id="BOGUS_9", instantiation=False, @@ -1523,6 +1555,19 @@ class TestRealTree(unittest.TestCase): self.assertEqual(analysis["missing_effective"], []) self.assertEqual(analysis["read_errors"], []) + def test_every_instantiated_filament_resolves_vendor_and_type(self): + # The property the web guide resolves at load: a partial base is fine as + # long as the instantiated preset ends up with both fields. Guards the + # split-base bundles (Snapmaker, Anker, SeeMeCNC). + analysis = afi.analyze_tree(REAL_PROFILES) + unresolved = [ + (vendor, rec["name"], rec["triple"][0], rec["triple"][1]) + for vendor, filaments in analysis["vendors"].items() + for rec in filaments.values() + if rec["instantiation"] and not (rec["triple"][0] and rec["triple"][1]) + ] + self.assertEqual(unresolved, []) + # --------------------------------------------------------------------------- # review-fix regressions # --------------------------------------------------------------------------- diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 7ac307c87b..584fc2a2aa 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -286,6 +286,8 @@ set(SLIC3R_GUI_SOURCES GUI/FilamentMapDialog.hpp GUI/IconManager.cpp GUI/IconManager.hpp + GUI/IdleScheduler.cpp + GUI/IdleScheduler.hpp GUI/ImageGrid.cpp GUI/ImageGrid.h GUI/ImGuiWrapper.cpp @@ -347,6 +349,10 @@ set(SLIC3R_GUI_SOURCES GUI/KBShortcutsDialog.hpp GUI/KeyChord.cpp GUI/KeyChord.hpp + GUI/Lazy.cpp + GUI/Lazy.hpp + GUI/LazyPage.cpp + GUI/LazyPage.hpp GUI/LibVGCode/LibVGCodeWrapper.hpp GUI/LibVGCode/LibVGCodeWrapper.cpp GUI/LinuxDisplayBackend.cpp @@ -433,6 +439,7 @@ set(SLIC3R_GUI_SOURCES GUI/Plater.hpp GUI/PlateSettingsDialog.cpp GUI/PlateSettingsDialog.hpp + GUI/PrebuildQueue.hpp GUI/Preferences.cpp GUI/Preferences.hpp GUI/PresetBundleDialog.cpp @@ -512,6 +519,7 @@ set(SLIC3R_GUI_SOURCES GUI/SliceInfoPanel.hpp GUI/SlicingProgressNotification.cpp GUI/SlicingProgressNotification.hpp + GUI/StagedBuild.hpp GUI/StatusPanel.cpp GUI/StatusPanel.hpp GUI/StepMeshDialog.cpp diff --git a/src/slic3r/GUI/Auxiliary.cpp b/src/slic3r/GUI/Auxiliary.cpp index 13ca173eb6..14b8d238a2 100644 --- a/src/slic3r/GUI/Auxiliary.cpp +++ b/src/slic3r/GUI/Auxiliary.cpp @@ -863,17 +863,27 @@ void AuxiliaryPanel::init_tabpanel() m_tabpanel->SetBackgroundColour(wxColour("#FEFFFF")); m_tabpanel->Bind(wxEVT_BOOKCTRL_PAGE_CHANGED, [](wxBookCtrlEvent &e) { /* Event handling */ }); - m_designer_panel = new DesignerPanel(m_tabpanel, AuxiliaryFolderType::DESIGNER); - m_pictures_panel = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::MODEL_PICTURE); - m_bill_of_materials_panel = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::BILL_OF_MATERIALS); - m_assembly_panel = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::ASSEMBLY_GUIDE); - m_others_panel = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::OTHERS); - - m_tabpanel->AddPage(m_designer_panel, _L("Basic Info"), true); - m_tabpanel->AddPage(m_pictures_panel, _L("Pictures"), false); - m_tabpanel->AddPage(m_bill_of_materials_panel, _L("Bill of Materials"), false); - m_tabpanel->AddPage(m_assembly_panel, _L("Assembly Guide"), false); - m_tabpanel->AddPage(m_others_panel, _L("Others"), false); + add_build_step([this] { + m_designer_panel = new DesignerPanel(m_tabpanel, AuxiliaryFolderType::DESIGNER); + m_tabpanel->AddPage(m_designer_panel, _L("Basic Info"), true); + }); + add_build_step([this] { + m_pictures_panel = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::MODEL_PICTURE); + m_tabpanel->AddPage(m_pictures_panel, _L("Pictures"), false); + }); + add_build_step([this] { + m_bill_of_materials_panel = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::BILL_OF_MATERIALS); + m_tabpanel->AddPage(m_bill_of_materials_panel, _L("Bill of Materials"), false); + }); + add_build_step([this] { + m_assembly_panel = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::ASSEMBLY_GUIDE); + m_tabpanel->AddPage(m_assembly_panel, _L("Assembly Guide"), false); + }); + add_build_step([this] { + m_others_panel = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::OTHERS); + m_tabpanel->AddPage(m_others_panel, _L("Others"), false); + Layout(); + }); } wxWindow *AuxiliaryPanel::create_side_tools() diff --git a/src/slic3r/GUI/Auxiliary.hpp b/src/slic3r/GUI/Auxiliary.hpp index 0bced37115..76e6adf97b 100644 --- a/src/slic3r/GUI/Auxiliary.hpp +++ b/src/slic3r/GUI/Auxiliary.hpp @@ -46,6 +46,7 @@ #include "slic3r/GUI/UpgradePanel.hpp" #include "slic3r/GUI/AmsWidgets.hpp" #include "Widgets/SideTools.hpp" +#include "StagedBuild.hpp" #define AUFILE_GREY700 wxColour(107, 107, 107) #define AUFILE_GREY500 wxColour(158, 158, 158) @@ -194,7 +195,7 @@ public: }; -class AuxiliaryPanel : public wxPanel +class AuxiliaryPanel : public wxPanel, public StagedBuild { private: Tabbook *m_tabpanel = {nullptr}; diff --git a/src/slic3r/GUI/CAD/DesignPanel.hpp b/src/slic3r/GUI/CAD/DesignPanel.hpp index 88b445534d..16f0a2722c 100644 --- a/src/slic3r/GUI/CAD/DesignPanel.hpp +++ b/src/slic3r/GUI/CAD/DesignPanel.hpp @@ -12,6 +12,7 @@ #include "libslic3r/CAD/CadDocument.hpp" #include "slic3r/GUI/CAD/DesignInteraction.hpp" // CadLevel: what one Esc press means +#include "slic3r/GUI/Lazy.hpp" class ComboBox; // Orca dropdown (Widgets/ComboBox.hpp) — replaces wxChoice everywhere here class StaticBox; // Orca rounded card frame (Widgets/StaticBox.hpp) @@ -46,7 +47,7 @@ class DesignCanvas; // Design (CAD) tab: a sketch-first, Onshape-style form-driven CAD panel. // Sketch and Extrude are independent tools: the user creates a Sketch first, // then selects it and Extrudes to produce a solid. -class DesignPanel : public wxPanel +class DesignPanel : public wxPanel, public LazyInstance { public: explicit DesignPanel(wxWindow* parent); diff --git a/src/slic3r/GUI/CAD/McpControl.cpp b/src/slic3r/GUI/CAD/McpControl.cpp index 8e34e2aac8..0ad05667c3 100644 --- a/src/slic3r/GUI/CAD/McpControl.cpp +++ b/src/slic3r/GUI/CAD/McpControl.cpp @@ -1989,11 +1989,10 @@ json action_set_feature_expr(DesignPanel* panel, const json& params) // Dispatch one parsed request ON THE MAIN THREAD. Returns a JSON-RPC reply string. std::string handle_on_main(const std::string& method, const json& params, const json& id) { - MainFrame* mf = wxGetApp().mainframe; // The panel is built on first use, and in a headless session nobody clicks the tab that // would build it -- so build it here rather than refusing. Safe: this runs on the main // thread (see the CallAfter that dispatches us). - DesignPanel* panel = mf ? mf->ensure_design_panel() : nullptr; + DesignPanel* panel = DesignPanel::ensure(); if (!panel) return rpc_error(id, -32001, "Design panel not ready"); diff --git a/src/slic3r/GUI/CalibrationPanel.cpp b/src/slic3r/GUI/CalibrationPanel.cpp index bdc79c1c8e..fca9fa2be9 100644 --- a/src/slic3r/GUI/CalibrationPanel.cpp +++ b/src/slic3r/GUI/CalibrationPanel.cpp @@ -491,14 +491,15 @@ void CalibrationPanel::init_tabpanel() { selected); } + for (int i = 0; i < (int)CALI_MODE_COUNT; i++) + add_build_steps_of(*m_cali_panels[i]); + // ORCA use standard paddings and keep arrow icon for consistent look between sidebars //for (int i = 0; i < (int)CALI_MODE_COUNT; i++) // m_tabpanel->SetPageImage(i, ""); //auto padding_size = m_tabpanel->GetBtnsListCtrl()->GetPaddingSize(0); //m_tabpanel->GetBtnsListCtrl()->SetPaddingSize({ FromDIP(15), padding_size.y }); - - m_initialized = true; } void CalibrationPanel::init_timer() @@ -534,6 +535,8 @@ void CalibrationPanel::update_print_error_info(int code, std::string msg, std::s } void CalibrationPanel::update_all() { + // Every wizard's pages exist once the last build step has run. + if (!built()) return; NetworkAgent* m_agent = wxGetApp().getAgent(); Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); @@ -597,7 +600,7 @@ void CalibrationPanel::update_all() { void CalibrationPanel::show_status(int status) { - if (!m_initialized) return; + if (!built()) return; if (last_status == status)return; last_status = status; diff --git a/src/slic3r/GUI/CalibrationPanel.hpp b/src/slic3r/GUI/CalibrationPanel.hpp index 1f6b097af9..960c5eed37 100644 --- a/src/slic3r/GUI/CalibrationPanel.hpp +++ b/src/slic3r/GUI/CalibrationPanel.hpp @@ -3,6 +3,7 @@ #include "CalibrationWizard.hpp" #include "Tabbook.hpp" +#include "Lazy.hpp" //#include "Widgets/SideTools.hpp" namespace Slic3r { namespace GUI { @@ -88,7 +89,7 @@ private: }; -class CalibrationPanel : public wxPanel +class CalibrationPanel : public wxPanel, public StagedBuild, public LazyInstance { public: CalibrationPanel(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL); @@ -109,7 +110,6 @@ protected: int last_status; - bool m_initialized { false }; std::string last_conn_type = "undedefined"; MachineObject* obj{ nullptr }; MachineObject* last_obj { nullptr }; diff --git a/src/slic3r/GUI/CalibrationWizard.cpp b/src/slic3r/GUI/CalibrationWizard.cpp index f80562578d..fa42143f06 100644 --- a/src/slic3r/GUI/CalibrationWizard.cpp +++ b/src/slic3r/GUI/CalibrationWizard.cpp @@ -130,6 +130,15 @@ CalibrationWizard::~CalibrationWizard() ; } +void CalibrationWizard::add_page_step(CalibrationWizardPageStep*& step, std::function make) +{ + add_build_step([this, &step, make = std::move(make)] { + step = new CalibrationWizardPageStep(make()); + m_all_pages_sizer->Add(step->page, 1, wxEXPAND | wxALL, FromDIP(25)); + step->page->Hide(); + }); +} + void CalibrationWizard::on_cali_job_finished(wxCommandEvent& event) { this->on_cali_job_finished(event.GetString()); @@ -520,33 +529,28 @@ void PressureAdvanceWizard::on_cali_job_finished(wxString evt_data) void PressureAdvanceWizard::create_pages() { - start_step = new CalibrationWizardPageStep(new CalibrationPAStartPage(m_scrolledWindow)); - preset_step = new CalibrationWizardPageStep(new CalibrationPresetPage(m_scrolledWindow, m_mode, false)); - cali_step = new CalibrationWizardPageStep(new CalibrationCaliPage(m_scrolledWindow, m_mode)); - save_step = new CalibrationWizardPageStep(new CalibrationPASavePage(m_scrolledWindow)); + add_page_step(start_step, [this] { return new CalibrationPAStartPage(m_scrolledWindow); }); + add_page_step(preset_step, [this] { return new CalibrationPresetPage(m_scrolledWindow, m_mode, false); }); + add_page_step(cali_step, [this] { return new CalibrationCaliPage(m_scrolledWindow, m_mode); }); + add_page_step(save_step, [this] { return new CalibrationPASavePage(m_scrolledWindow); }); - m_all_pages_sizer->Add(start_step->page, 1, wxEXPAND | wxALL, FromDIP(25)); - m_all_pages_sizer->Add(preset_step->page, 1, wxEXPAND | wxALL, FromDIP(25)); - m_all_pages_sizer->Add(cali_step->page, 1, wxEXPAND | wxALL, FromDIP(25)); - m_all_pages_sizer->Add(save_step->page, 1, wxEXPAND | wxALL, FromDIP(25)); + add_build_step([this] { + m_page_steps.push_back(start_step); + m_page_steps.push_back(preset_step); + m_page_steps.push_back(cali_step); + m_page_steps.push_back(save_step); + for (int i = 0; i < m_page_steps.size() -1; i++) { + m_page_steps[i]->chain(m_page_steps[i+1]); + } - m_page_steps.push_back(start_step); - m_page_steps.push_back(preset_step); - m_page_steps.push_back(cali_step); - m_page_steps.push_back(save_step); + for (int i = 0; i < m_page_steps.size(); i++) { + m_page_steps[i]->page->Bind(EVT_CALI_ACTION, &PressureAdvanceWizard::on_cali_action, this); + } - for (int i = 0; i < m_page_steps.size() -1; i++) { - m_page_steps[i]->chain(m_page_steps[i+1]); - } - - for (int i = 0; i < m_page_steps.size(); i++) { - m_page_steps[i]->page->Hide(); - m_page_steps[i]->page->Bind(EVT_CALI_ACTION, &PressureAdvanceWizard::on_cali_action, this); - } - - if (!m_page_steps.empty()) - show_step(m_page_steps.front()); + if (!m_page_steps.empty()) + show_step(m_page_steps.front()); + }); } void PressureAdvanceWizard::on_cali_action(wxCommandEvent& evt) @@ -1053,59 +1057,46 @@ FlowRateWizard::FlowRateWizard(wxWindow* parent, wxWindowID id, const wxPoint& p void FlowRateWizard::create_pages() { - start_step = new CalibrationWizardPageStep(new CalibrationFlowRateStartPage(m_scrolledWindow)); - preset_step = new CalibrationWizardPageStep(new CalibrationPresetPage(m_scrolledWindow, m_mode, false)); + add_page_step(start_step, [this] { return new CalibrationFlowRateStartPage(m_scrolledWindow); }); + add_page_step(preset_step, [this] { return new CalibrationPresetPage(m_scrolledWindow, m_mode, false); }); // manual - cali_coarse_step = new CalibrationWizardPageStep(new CalibrationCaliPage(m_scrolledWindow, m_mode, CaliPageType::CALI_PAGE_CALI)); - coarse_save_step = new CalibrationWizardPageStep(new CalibrationFlowCoarseSavePage(m_scrolledWindow)); - cali_fine_step = new CalibrationWizardPageStep(new CalibrationCaliPage(m_scrolledWindow, m_mode, CaliPageType::CALI_PAGE_FINE_CALI)); - fine_save_step = new CalibrationWizardPageStep(new CalibrationFlowFineSavePage(m_scrolledWindow)); + add_page_step(cali_coarse_step, [this] { return new CalibrationCaliPage(m_scrolledWindow, m_mode, CaliPageType::CALI_PAGE_CALI); }); + add_page_step(coarse_save_step, [this] { return new CalibrationFlowCoarseSavePage(m_scrolledWindow); }); + add_page_step(cali_fine_step, [this] { return new CalibrationCaliPage(m_scrolledWindow, m_mode, CaliPageType::CALI_PAGE_FINE_CALI); }); + add_page_step(fine_save_step, [this] { return new CalibrationFlowFineSavePage(m_scrolledWindow); }); // auto - cali_step = new CalibrationWizardPageStep(new CalibrationCaliPage(m_scrolledWindow, m_mode)); - save_step = new CalibrationWizardPageStep(new CalibrationFlowX1SavePage(m_scrolledWindow)); + add_page_step(cali_step, [this] { return new CalibrationCaliPage(m_scrolledWindow, m_mode); }); + add_page_step(save_step, [this] { return new CalibrationFlowX1SavePage(m_scrolledWindow); }); - m_all_pages_sizer->Add(start_step->page, 1, wxEXPAND | wxALL, FromDIP(25)); - m_all_pages_sizer->Add(preset_step->page, 1, wxEXPAND | wxALL, FromDIP(25)); - m_all_pages_sizer->Add(cali_coarse_step->page, 1, wxEXPAND | wxALL, FromDIP(25)); - m_all_pages_sizer->Add(coarse_save_step->page, 1, wxEXPAND | wxALL, FromDIP(25)); - m_all_pages_sizer->Add(cali_fine_step->page, 1, wxEXPAND | wxALL, FromDIP(25)); - m_all_pages_sizer->Add(fine_save_step->page, 1, wxEXPAND | wxALL, FromDIP(25)); + add_build_step([this] { + m_page_steps.push_back(start_step); + m_page_steps.push_back(preset_step); + m_page_steps.push_back(cali_coarse_step); + m_page_steps.push_back(coarse_save_step); + m_page_steps.push_back(cali_fine_step); + m_page_steps.push_back(fine_save_step); - m_all_pages_sizer->Add(cali_step->page, 1, wxEXPAND | wxALL, FromDIP(25)); - m_all_pages_sizer->Add(save_step->page, 1, wxEXPAND | wxALL, FromDIP(25)); + //m_page_steps.push_back(cali_step); + //m_page_steps.push_back(save_step); - m_page_steps.push_back(start_step); - m_page_steps.push_back(preset_step); - m_page_steps.push_back(cali_coarse_step); - m_page_steps.push_back(coarse_save_step); - m_page_steps.push_back(cali_fine_step); - m_page_steps.push_back(fine_save_step); + for (int i = 0; i < m_page_steps.size() - 1; i++) { + m_page_steps[i]->chain(m_page_steps[i + 1]); + } - //m_page_steps.push_back(cali_step); - //m_page_steps.push_back(save_step); + for (int i = 0; i < m_page_steps.size(); i++) { + m_page_steps[i]->page->Bind(EVT_CALI_ACTION, &FlowRateWizard::on_cali_action, this); + } - for (int i = 0; i < m_page_steps.size() - 1; i++) { - m_page_steps[i]->chain(m_page_steps[i + 1]); - } + cali_step->page->Bind(EVT_CALI_ACTION, &FlowRateWizard::on_cali_action, this); + save_step->page->Bind(EVT_CALI_ACTION, &FlowRateWizard::on_cali_action, this); - // hide all pages - cali_step->page->Hide(); - save_step->page->Hide(); - for (int i = 0; i < m_page_steps.size(); i++) { - m_page_steps[i]->page->Hide(); - m_page_steps[i]->page->Bind(EVT_CALI_ACTION, &FlowRateWizard::on_cali_action, this); - } + if (!m_page_steps.empty()) + show_step(m_page_steps.front()); - - cali_step->page->Bind(EVT_CALI_ACTION, &FlowRateWizard::on_cali_action, this); - save_step->page->Bind(EVT_CALI_ACTION, &FlowRateWizard::on_cali_action, this); - - if (!m_page_steps.empty()) - show_step(m_page_steps.front()); - - set_cali_method(CalibrationMethod::CALI_METHOD_MANUAL); + set_cali_method(CalibrationMethod::CALI_METHOD_MANUAL); + }); } void FlowRateWizard::on_cali_action(wxCommandEvent& evt) diff --git a/src/slic3r/GUI/CalibrationWizard.hpp b/src/slic3r/GUI/CalibrationWizard.hpp index d72d5fcb7b..89c515eb80 100644 --- a/src/slic3r/GUI/CalibrationWizard.hpp +++ b/src/slic3r/GUI/CalibrationWizard.hpp @@ -9,6 +9,7 @@ #include "CalibrationWizardPresetPage.hpp" #include "CalibrationWizardCaliPage.hpp" #include "CalibrationWizardSavePage.hpp" +#include "StagedBuild.hpp" namespace Slic3r { namespace GUI { @@ -36,7 +37,7 @@ struct ConfigIndexValue int index{0}; }; -class CalibrationWizard : public wxPanel { +class CalibrationWizard : public wxPanel, public StagedBuild { public: CalibrationWizard(wxWindow* parent, CalibMode mode, wxWindowID id = wxID_ANY, @@ -79,6 +80,9 @@ public: protected: void on_cali_go_home(); + // Queues a page as a build step, created hidden and added to the pages sizer. + void add_page_step(CalibrationWizardPageStep*& step, std::function make); + protected: /* wx widgets*/ wxScrolledWindow* m_scrolledWindow; diff --git a/src/slic3r/GUI/CalibrationWizardCaliPage.cpp b/src/slic3r/GUI/CalibrationWizardCaliPage.cpp index 152f46f37c..2dc766dca3 100644 --- a/src/slic3r/GUI/CalibrationWizardCaliPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardCaliPage.cpp @@ -192,8 +192,10 @@ void CalibrationCaliPage::update(MachineObject* obj) set_cali_img(); } + // A calibration can run before the Device tab is ever opened, and only its status + // panel shows a print error. if (obj->print_error > 0) { - StatusPanel* status_panel = Slic3r::GUI::wxGetApp().mainframe->m_monitor->get_status_panel(); + StatusPanel* status_panel = MonitorPanel::ensure()->get_status_panel(); status_panel->obj = obj; status_panel->update_error_message(); } diff --git a/src/slic3r/GUI/DeviceErrorDialog.cpp b/src/slic3r/GUI/DeviceErrorDialog.cpp index 2a55d77d24..9790db67bd 100644 --- a/src/slic3r/GUI/DeviceErrorDialog.cpp +++ b/src/slic3r/GUI/DeviceErrorDialog.cpp @@ -538,7 +538,8 @@ void DeviceErrorDialog::on_button_click(ActionButton btn_id) break; } case DeviceErrorDialog::CHECK_ASSISTANT: { - wxGetApp().mainframe->m_monitor->jump_to_HMS(); // go to assistant page + if (MonitorPanel* monitor = MonitorPanel::if_built()) + monitor->jump_to_HMS(); // go to assistant page break; } case DeviceErrorDialog::FILAMENT_EXTRUDED: { @@ -568,7 +569,8 @@ void DeviceErrorDialog::on_button_click(ActionButton btn_id) } case DeviceErrorDialog::JUMP_TO_LIVEVIEW: { Slic3r::GUI::wxGetApp().mainframe->jump_to_monitor(); - Slic3r::GUI::wxGetApp().mainframe->m_monitor->jump_to_LiveView(); + if (MonitorPanel* monitor = MonitorPanel::if_built()) + monitor->jump_to_LiveView(); break; } case DeviceErrorDialog::NO_REMINDER_NEXT_TIME: { @@ -618,7 +620,8 @@ void DeviceErrorDialog::on_button_click(ActionButton btn_id) } case DeviceErrorDialog::OK_JUMP_RACK: { Slic3r::GUI::wxGetApp().mainframe->jump_to_monitor(); - Slic3r::GUI::wxGetApp().mainframe->m_monitor->jump_to_Rack(); + if (MonitorPanel* monitor = MonitorPanel::if_built()) + monitor->jump_to_Rack(); break; } case DeviceErrorDialog::ABORT: { diff --git a/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRack.cpp b/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRack.cpp index 44394866c8..00d4c3e809 100644 --- a/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRack.cpp +++ b/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRack.cpp @@ -934,7 +934,8 @@ void wgtDeviceNozzleRackNozzleItem::OnBtnNozzleStatus(wxMouseEvent& evt) dlg.AddButton(wxID_OK,_L("Jump to the upgrade page"), true); if (dlg.ShowModal() == wxID_OK) { - wxGetApp().mainframe->m_monitor->jump_to_Upgrade(); + if (MonitorPanel* monitor = MonitorPanel::if_built()) + monitor->jump_to_Upgrade(); }; } } diff --git a/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRackUpdate.cpp b/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRackUpdate.cpp index fac14e31d9..eae377c147 100644 --- a/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRackUpdate.cpp +++ b/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRackUpdate.cpp @@ -344,7 +344,8 @@ void wgtDeviceNozzleRackHotendUpdate::OnStatusIconClick(wxMouseEvent& event) if (dlg.ShowModal() == wxID_OK) { - wxGetApp().mainframe->m_monitor->jump_to_Upgrade(); + if (MonitorPanel* monitor = MonitorPanel::if_built()) + monitor->jump_to_Upgrade(); wxCommandEvent evt(wxEVT_NOZZLE_JUMP_UPGRADE, GetId()); evt.SetEventObject(this); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 887d13aedc..cc3a1deb0a 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -20,6 +20,7 @@ #include "libslic3r/AppConfig.hpp" #include "3DScene.hpp" #include "BackgroundSlicingProcess.hpp" +#include "CameraUtils.hpp" #include "GLShader.hpp" #include "GUI.hpp" #include "Tab.hpp" @@ -117,6 +118,36 @@ void GLCanvas3D::load_render_colors() namespace Slic3r { namespace GUI { +static void pan_camera(Camera& camera, const Vec2d& screen_delta, const Vec3d& anchor) +{ + // Orca: Derive world-units-per-pixel from the projection which produced the visible frame. + // Perspective additionally scales with the eye-space depth of the point being dragged. + const auto& viewport = camera.get_viewport(); + const auto& projection = camera.get_projection_matrix().matrix(); + const double depth_scale = camera.get_type() == Camera::EType::Perspective ? + (anchor - camera.get_position()).dot(camera.get_dir_forward()) : 1.0; + const double projection_x = projection(0, 0) * viewport[2]; + const double projection_y = projection(1, 1) * viewport[3]; + + // Orca: X/Y projection coefficients already include zoom. Using them directly avoids a + // project/unproject round-trip through window depth, whose precision depends on the scene frustum. + if (viewport[2] > 0 && viewport[3] > 0 && anchor.allFinite() && depth_scale > EPSILON && + std::abs(projection_x) > EPSILON && std::abs(projection_y) > EPSILON) { + const Vec3d displacement = 2.0 * depth_scale * + (screen_delta.y() / projection_y * camera.get_dir_up() - + screen_delta.x() / projection_x * camera.get_dir_right()); + if (displacement.allFinite()) { + camera.translate(displacement); + return; + } + } + + // Orca: Preserve the former target-plane behavior if the projection or anchor is invalid. + // Screen Y grows downward, and the camera moves opposite to the drag. + camera.translate(camera.get_inv_zoom() * + (screen_delta.y() * camera.get_dir_up() - screen_delta.x() * camera.get_dir_right())); +} + #ifdef __WXGTK3__ // wxGTK3 seems to simulate OSX behavior in regard to HiDPI scaling support. RetinaHelper::RetinaHelper(wxWindow* window) : m_window(window), m_self(nullptr) {} @@ -2206,15 +2237,14 @@ void GLCanvas3D::_render_scene(const Camera& camera, const Size& cnv_size) _render_background(); //BBS add partplater rendering logic - bool only_current = false, only_body = false, no_partplate = false; + bool only_current = false, only_body = false; + const bool show_bed = is_bed_visible(); bool show_grid = true; GLGizmosManager::EType gizmo_type = m_gizmos.get_current_type(); if (!m_main_toolbar.is_enabled()) { //only_body = true; only_current = true; } - else if ((gizmo_type == GLGizmosManager::FdmSupports) || (gizmo_type == GLGizmosManager::Seam) || (gizmo_type == GLGizmosManager::MmSegmentation) || (gizmo_type == GLGizmosManager::FuzzySkin)) - no_partplate = true; else if (gizmo_type == GLGizmosManager::BrimEars && !camera.is_looking_downward()) show_grid = false; if (m_axes_at_bed_center) @@ -2228,11 +2258,11 @@ void GLCanvas3D::_render_scene(const Camera& camera, const Size& cnv_size) if (m_canvas_type == ECanvasType::CanvasView3D) { // m_show_bed gates the plate list too: hiding the bed but leaving its grid and outline // floating would read as a rendering fault rather than a deliberate view option. - if (!no_partplate && m_show_bed) + if (show_bed) _render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), m_show_world_axes); - if (!no_partplate && m_show_bed) //BBS: add outline logic + if (show_bed) //BBS: add outline logic _render_platelist(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), only_current, only_body, hover_id, true, show_grid); - if (m_axes_at_bed_center && m_show_bed && !no_partplate) + if (m_axes_at_bed_center && show_bed) // Design tab: replace the plate's corner-origin grid with the origin-centred CAD grid. _render_cad_grid(camera.get_view_matrix(), camera.get_projection_matrix()); @@ -3281,6 +3311,9 @@ void GLCanvas3D::unbind_event_handlers() m_canvas->Unbind(wxEVT_GESTURE_PAN, &GLCanvas3D::on_gesture, this); m_canvas->Unbind(wxEVT_GESTURE_ZOOM, &GLCanvas3D::on_gesture, this); m_canvas->Unbind(wxEVT_GESTURE_ROTATE, &GLCanvas3D::on_gesture, this); +#if __WXOSX__ + initGestures(m_canvas->GetHandle(), nullptr); +#endif } } @@ -4029,27 +4062,38 @@ void GLCanvas3D::on_gesture(wxGestureEvent &evt) auto & camera = wxGetApp().plater()->get_camera(); if (evt.GetEventType() == wxEVT_GESTURE_PAN) { - auto p = evt.GetPosition(); + // Orca: Gesture coordinates must use framebuffer pixels, and one stable world-space + // anchor must be retained for the complete gesture to prevent perspective drift. + const auto p = evt.GetPosition(); auto d = static_cast(evt).GetDelta(); - float z = 0; - const Vec3d &p2 = _mouse_to_3d({p.x, p.y}, &z); - const Vec3d &p1 = _mouse_to_3d({p.x - d.x, p.y - d.y}, &z); - camera.set_target(camera.get_target() + p1 - p2); + Vec2d screen_position(p.x, p.y); + Vec2d screen_delta(d.x, d.y); + apply_retina_scale(screen_position); + apply_retina_scale(screen_delta); + if (evt.IsGestureStart() || !m_gesture_pan_anchor.has_value()) + m_gesture_pan_anchor = get_camera_pan_anchor(camera, ECameraNavigationType::Gesture, + screen_position - screen_delta); + pan_camera(camera, screen_delta, *m_gesture_pan_anchor); + if (evt.IsGestureEnd()) + m_gesture_pan_anchor.reset(); } else if (evt.GetEventType() == wxEVT_GESTURE_ZOOM) { static float zoom_start = 1; if (evt.IsGestureStart()) zoom_start = camera.get_zoom(); camera.set_zoom(zoom_start * static_cast(evt).GetZoomFactor()); } else if (evt.GetEventType() == wxEVT_GESTURE_ROTATE) { - PartPlate* plate = wxGetApp().plater()->get_partplate_list().get_curr_plate(); + // Orca: Rotation starts a different navigation operation, so a previous pan anchor + // must not be reused; rotation and pan fallbacks share the same navigation pivot. + m_gesture_pan_anchor.reset(); bool rotate_limit = current_printer_technology() != ptSLA; static double last_rotate = 0; if (evt.IsGestureStart()) last_rotate = 0; auto rotate = static_cast(evt).GetRotationAngle() - last_rotate; last_rotate += rotate; - if (plate) - camera.rotate_on_sphere_with_target(-rotate, 0, rotate_limit, plate->get_bounding_box().center()); + const std::optional rotate_target = get_camera_orbit_target(ECameraNavigationType::Gesture); + if (rotate_target.has_value()) + camera.rotate_on_sphere_with_target(-rotate, 0, rotate_limit, *rotate_target); else camera.rotate_on_sphere(-rotate, 0, rotate_limit); camera.auto_type(Camera::EType::Perspective); @@ -4339,6 +4383,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) post_event(SimpleEvent(EVT_GLCANVAS_SWITCH_TO_GLOBAL)); } else if (evt.LeftDown() || evt.RightDown() || evt.MiddleDown()) { + // Orca: Retain the click position even if the first motion event crosses a surface edge. + m_mouse.set_start_position_2D_as_invalid(); + m_mouse.drag.start_position_2D = pos; + //BBS: add orient deactivate logic if (!m_gizmos.on_mouse(evt)) { if (_deactivate_arrange_menu() || _deactivate_orient_menu()) @@ -4532,6 +4580,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } // do not process the dragging if the left mouse was set down in another canvas else if (is_camera_rotate(evt, button_mappings)) { + // Orca: Rotation and panning use different drag coordinates and cached anchors. + // Clear the pan state before processing rotation or switching buttons mid-drag. + m_mouse.set_start_position_2D_as_invalid(); if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds m_canvas->CaptureMouse(); @@ -4549,12 +4600,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (this->m_canvas_type == ECanvasType::CanvasAssembleView || m_gizmos.get_current_type() == GLGizmosManager::FdmSupports || m_gizmos.get_current_type() == GLGizmosManager::Seam || m_gizmos.get_current_type() == GLGizmosManager::MmSegmentation || m_gizmos.get_current_type() == GLGizmosManager::FuzzySkin) { - Vec3d rotate_target = Vec3d::Zero(); - if (!m_selection.is_empty()) - rotate_target = m_selection.get_bounding_box().center(); + // Orca: Reuse the centralized pivot policy for scene-oriented tools. + const std::optional rotate_target = get_camera_orbit_target(ECameraNavigationType::Mouse); + if (rotate_target.has_value()) + camera.rotate_on_sphere_with_target(rot.x(), rot.y(), false, *rotate_target); else - rotate_target = volumes_bounding_box().center(); - camera.rotate_on_sphere_with_target(rot.x(), rot.y(), false, rotate_target); + camera.rotate_on_sphere(rot.x(), rot.y(), false); } else { if (wxGetApp().app_config->get_bool("use_free_camera")) @@ -4578,28 +4629,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } camera.rotate_on_sphere_with_target(rot.x(), rot.y(), rotate_limit, m_rotation_center); } else { - Vec3d rotate_target = Vec3d::Zero(); - if (m_canvas_type == ECanvasType::CanvasPreview) { - PartPlate *plate = wxGetApp().plater()->get_partplate_list().get_curr_plate(); - if (plate) - rotate_target = plate->get_bounding_box().center(); - } - else { - if (!m_selection.is_empty()) - rotate_target = m_selection.get_bounding_box().center(); - else { - // Rotate around the center of objects on current plate - auto bbox = volumes_bounding_box(true); - if (!bbox.defined) { - // Rotate around current plate center if current plate is empty - bbox = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_bounding_box(); - } - rotate_target = bbox.center(); - } - } - - if (!rotate_target.isZero()) - camera.rotate_on_sphere_with_target(rot.x(), rot.y(), rotate_limit, rotate_target); + // Orca: Keep regular mouse orbit and perspective-pan fallback centered + // on the same selection, active-plate, or scene reference. + const std::optional rotate_target = get_camera_orbit_target(ECameraNavigationType::Mouse); + if (rotate_target.has_value()) + camera.rotate_on_sphere_with_target(rot.x(), rot.y(), rotate_limit, *rotate_target); else camera.rotate_on_sphere(rot.x(), rot.y(), rotate_limit); } @@ -4615,16 +4649,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.drag.start_position_3D = Vec3d((double)pos(0), (double)pos(1), 0.0); } else if (is_camera_pan(evt, button_mappings)) { + // Orca: Pan uses screen coordinates and must not inherit the rotation start point. + m_mouse.set_start_position_3D_as_invalid(); if (!has_mouse_capture()) // ORCA keep tracking mouse position while drag active and cursor not in window bounds m_canvas->CaptureMouse(); // if dragging with right button or if button functions swapped and dragging with left button over blank area then pan if (m_mouse.is_start_position_2D_defined()) { - // get point in model space at Z = 0 - float z = 0.0f; - const Vec3d& cur_pos = _mouse_to_3d(pos, &z); - Vec3d orig = _mouse_to_3d(m_mouse.drag.start_position_2D, &z); Camera& camera = wxGetApp().plater()->get_camera(); if (this->m_canvas_type != ECanvasType::CanvasAssembleView) { // Orca: Use a constrained camera when navigating the 3D scene with a regular mouse, if the free camera is not selected @@ -4636,7 +4668,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) camera.recover_from_free_camera(); } - camera.set_target(camera.get_target() + orig - cur_pos); + // Orca: Cache the surface under the initial click and apply every incremental + // cursor delta at that depth, so perspective zoom and camera angle stay exact. + const Vec2d screen_delta = + pos.cast() - m_mouse.drag.start_position_2D.cast(); + if (!m_mouse.drag.camera_pan_anchor.has_value()) + m_mouse.drag.camera_pan_anchor = get_camera_pan_anchor(camera, ECameraNavigationType::Mouse, + m_mouse.drag.start_position_2D.cast()); + pan_camera(camera, screen_delta, *m_mouse.drag.camera_pan_anchor); m_dirty = true; m_mouse.ignore_right_up = true; // will be reset on button up event even if not right button is pressed } @@ -7329,11 +7368,8 @@ void GLCanvas3D::_picking_pass() m_hover_volume_idxs.clear(); m_hover_plate_idxs.clear(); - // Orca: ignore clipping plane if not applying - GLGizmoBase *current_gizmo = m_gizmos.get_current(); - const ClippingPlane clipping_plane = ((!current_gizmo || current_gizmo->apply_clipping_plane()) ? m_gizmos.get_clipping_plane() : - ClippingPlane::ClipsNothing()) - .inverted_normal(); + // Orca: Picking and camera navigation must interpret the active gizmo clipping plane identically. + const ClippingPlane clipping_plane = get_raycaster_clipping_plane(); const SceneRaycaster::HitResult hit = m_scene_raycaster.hit(m_mouse.position, wxGetApp().plater()->get_camera(), &clipping_plane); if (hit.is_valid()) { switch (hit.type) @@ -10627,6 +10663,129 @@ Vec3d GLCanvas3D::_mouse_to_bed_3d(const Point& mouse_pos) return mouse_ray(mouse_pos).intersect_plane(0.0); } +ClippingPlane GLCanvas3D::get_raycaster_clipping_plane() const +{ + // Orca: Ignore the gizmo clipping plane when the active tool does not apply it, and + // invert the result into the convention expected by SceneRaycaster. + GLGizmoBase* current_gizmo = m_gizmos.get_current(); + return ((!current_gizmo || current_gizmo->apply_clipping_plane()) ? m_gizmos.get_clipping_plane() : + ClippingPlane::ClipsNothing()) + .inverted_normal(); +} + +std::optional GLCanvas3D::get_camera_orbit_target(ECameraNavigationType navigation_type) const +{ + // Orca: Centralize the pre-existing pivot rules so orbiting and pan fallback cannot + // choose different reference depths for the same canvas and active tool. + PartPlate* current_plate = wxGetApp().plater()->get_partplate_list().get_curr_plate(); + if (navigation_type == ECameraNavigationType::Gesture) + return current_plate == nullptr ? std::nullopt : + std::make_optional(current_plate->get_bounding_box().center()); + + const GLGizmosManager::EType gizmo_type = m_gizmos.get_current_type(); + const bool use_scene_target = m_canvas_type == ECanvasType::CanvasAssembleView || + gizmo_type == GLGizmosManager::FdmSupports || gizmo_type == GLGizmosManager::Seam || + gizmo_type == GLGizmosManager::MmSegmentation || gizmo_type == GLGizmosManager::FuzzySkin; + if (use_scene_target) { + if (!m_selection.is_empty()) + return m_selection.get_bounding_box().center(); + + // Orca: Preserve the world-origin fallback used by orbit in an empty scene. + return volumes_bounding_box().center(); + } + + // Orca: Free-camera rotation uses Camera::m_target rather than a plate or selection pivot. + if (wxGetApp().app_config->get_bool("use_free_camera")) + return std::nullopt; + + Vec3d target = Vec3d::Zero(); + if (m_canvas_type == ECanvasType::CanvasPreview) { + if (current_plate != nullptr) + target = current_plate->get_bounding_box().center(); + } else if (!m_selection.is_empty()) { + target = m_selection.get_bounding_box().center(); + } else { + // Orca: Match regular mouse orbit: objects on the active plate, then the plate itself. + BoundingBoxf3 bbox = volumes_bounding_box(true); + if (!bbox.defined && current_plate != nullptr) + bbox = current_plate->get_bounding_box(); + if (bbox.defined) + target = bbox.center(); + } + + // Orca: Preserve the existing zero sentinel used by regular mouse orbit. + return target.isZero() ? std::nullopt : std::make_optional(target); +} + +bool GLCanvas3D::is_bed_visible() const +{ + if (m_canvas_type == ECanvasType::CanvasPreview) + return m_render_preview; + if (m_canvas_type != ECanvasType::CanvasView3D || !m_show_bed) + return false; + if (!m_main_toolbar.is_enabled()) + return true; + + const auto type = m_gizmos.get_current_type(); + return type != GLGizmosManager::FdmSupports && type != GLGizmosManager::Seam && + type != GLGizmosManager::MmSegmentation && type != GLGizmosManager::FuzzySkin; +} + +Vec3d GLCanvas3D::get_camera_pan_anchor(Camera& camera, ECameraNavigationType navigation_type, + const Vec2d& screen_position) const +{ + // Orthographic panning has the same scale at every depth, so no raycast is needed. + if (camera.get_type() != Camera::EType::Perspective) + return camera.get_target(); + + // Orca: Reject non-finite anchors and points behind the camera before their depth is + // allowed to scale a perspective pan. + const Vec3d camera_position = camera.get_position(); + const Vec3d camera_forward = camera.get_dir_forward(); + const auto is_valid_anchor = [&camera_position, &camera_forward](const Vec3d& anchor) { + return anchor.allFinite() && (anchor - camera_position).dot(camera_forward) > EPSILON; + }; + + // Orca: Prefer the nearest visible bed or volume surface and exclude gizmos and + // selected-volume picking priority from navigation depth selection. + const ClippingPlane clipping_plane = get_raycaster_clipping_plane(); + const bool bed_visible = is_bed_visible(); + const SceneRaycaster::HitResult hit = m_scene_raycaster.hit(screen_position, camera, &clipping_plane, + bed_visible ? SceneRaycaster::EHitMode::SceneOnly : SceneRaycaster::EHitMode::VolumesOnly); + if (hit.is_valid()) { + const Vec3d hit_position = hit.position.cast(); + if (is_valid_anchor(hit_position)) + return hit_position; + } + + // Orca: When the cursor is just outside the visible plate, use the point under it on the active + // plate plane. Using the plate center here would give it a different perspective depth. + PartPlate* current_plate = wxGetApp().plater()->get_partplate_list().get_curr_plate(); + // Orca: An almost edge-on perspective makes intersection depth extremely sensitive to + // the cursor's vertical position. Use the stable orbit depth around horizontal views. + static constexpr double min_plate_plane_forward_z = 0.05; + if (bed_visible && std::abs(camera_forward.z()) >= min_plate_plane_forward_z && + current_plate != nullptr && current_plate->get_bounding_box().defined) { + Vec3d ray_origin; + Vec3d ray_direction; + CameraUtils::ray_from_screen_pos(camera, screen_position, ray_origin, ray_direction); + const double z_direction = ray_direction.z(); + if (ray_origin.allFinite() && ray_direction.allFinite() && std::abs(z_direction) > EPSILON) { + const double plate_z = current_plate->get_bounding_box().center().z(); + const double distance = (plate_z - ray_origin.z()) / z_direction; + const Vec3d plate_position = ray_origin + distance * ray_direction; + const double eye_depth = (plate_position - camera_position).dot(camera_forward); + if (distance >= 0.0 && is_valid_anchor(plate_position) && + eye_depth >= camera.get_near_z() && eye_depth <= camera.get_far_z()) + return plate_position; + } + } + + // Orca: Near-horizontal rays and points outside the scene depth use the orbit reference point. + const std::optional orbit_target = get_camera_orbit_target(navigation_type); + return orbit_target.has_value() && is_valid_anchor(*orbit_target) ? *orbit_target : camera.get_target(); +} + // While it looks like we can call // this->reload_scene(true, true) // the two functions are quite different: diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 75820694b0..254fa9ddca 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -338,6 +338,8 @@ class GLCanvas3D int move_volume_idx{ -1 }; bool move_requires_threshold{ false }; Point move_start_threshold_position_2D{ Invalid_2D_Point }; + // Orca: Keep the world-space point selected at the start of a mouse pan. + std::optional camera_pan_anchor; }; bool dragging{ false }; @@ -346,7 +348,12 @@ class GLCanvas3D Drag drag; bool ignore_right_up; - void set_start_position_2D_as_invalid() { drag.start_position_2D = Drag::Invalid_2D_Point; } + // Orca: The screen-space start and world-space anchor describe the same pan session. + // Invalidating one must invalidate the other so a new drag cannot reuse stale depth. + void set_start_position_2D_as_invalid() { + drag.start_position_2D = Drag::Invalid_2D_Point; + drag.camera_pan_anchor.reset(); + } void set_start_position_3D_as_invalid() { drag.start_position_3D = Drag::Invalid_3D_Point; } void set_move_start_threshold_position_2D_as_invalid() { drag.move_start_threshold_position_2D = Drag::Invalid_2D_Point; } @@ -549,6 +556,8 @@ private: bool m_fps_overlay_tick{ false }; LayersEditing m_layers_editing; Mouse m_mouse; + // Orca: Gesture pans have their own lifecycle and stable world-space anchor. + std::optional m_gesture_pan_anchor; GLGizmosManager m_gizmos; //BBS: GUI refactor: GLToolbar mutable GLToolbar m_main_toolbar; @@ -1406,6 +1415,20 @@ private: // Convert the screen space coordinate to world coordinate on the bed. Vec3d _mouse_to_bed_3d(const Point& mouse_pos); + // Orca: Navigation type selects the legacy pivot policy used when no visible surface is hit. + enum class ECameraNavigationType : unsigned char + { + Mouse, + Gesture + }; + + // Orca: These helpers keep clipping, orbit pivots, and perspective-pan depth selection consistent. + ClippingPlane get_raycaster_clipping_plane() const; + bool is_bed_visible() const; + std::optional get_camera_orbit_target(ECameraNavigationType navigation_type) const; + Vec3d get_camera_pan_anchor(Camera& camera, ECameraNavigationType navigation_type, + const Vec2d& screen_position) const; + void _start_timer() { m_timer.Start(100, wxTIMER_CONTINUOUS); } void _stop_timer() { m_timer.Stop(); } diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 29bab18aeb..1a153ed4fb 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -863,8 +863,11 @@ void GUI_App::post_init() mainframe->Freeze(); #endif plater_->canvas3D()->enable_render(false); - mainframe->select_tab(TAB_ID_PREPARE); + mainframe->select_prepare_for_gl_init(); plater_->select_view_3D("3D"); + // The first render happens before the queued new_project() sets the same view. + plater_->get_camera().select_view("topfront"); + plater_->get_camera().requires_zoom_to_bed = true; //BBS init the opengl resource here if (!plater_->canvas3D()->get_wxglcanvas()->IsShownOnScreen() || !plater_->canvas3D()->make_current_for_postinit()) { @@ -900,10 +903,10 @@ void GUI_App::post_init() BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", finished rendering a first frame for test"; } } - if (is_editor()) - mainframe->select_tab(TAB_ID_HOME); - if (app_config->get("default_page") == "1") + if (starts_on_prepare()) mainframe->select_tab(TAB_ID_PREPARE); + else if (is_editor()) + mainframe->select_tab(TAB_ID_HOME); #ifndef __linux__ mainframe->Thaw(); #endif @@ -912,6 +915,7 @@ void GUI_App::post_init() plater_->trigger_restore_project(1); //#endif + mainframe->prebuild_pages_when_idle(); //BBS: remove GCodeViewer as seperate APP logic /*if (this->init_params->start_as_gcodeviewer) { @@ -1926,9 +1930,9 @@ bool GUI_App::hot_reload_network_plugin() m_device_manager->add_user_subscribe(); } - if (mainframe && mainframe->m_monitor) { - mainframe->m_monitor->update_network_version_footer(); - mainframe->m_monitor->set_default(); + if (MonitorPanel* monitor = MonitorPanel::if_built()) { + monitor->update_network_version_footer(); + monitor->set_default(); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": reset monitor panel"; } @@ -3419,14 +3423,16 @@ bool GUI_App::on_init_inner() } BOOST_LOG_TRIVIAL(info) << "create the main window"; mainframe = new MainFrame(); - // hide settings tabs after first Layout if (is_editor()) { - mainframe->select_tab(TAB_ID_HOME); + if (starts_on_prepare()) { + mainframe->select_tab(TAB_ID_PREPARE); + } else { + mainframe->select_tab(TAB_ID_HOME); + } } sidebar().obj_list()->init(); //sidebar().aux_list()->init_auxiliary(); - mainframe->m_project->init_auxiliary(); // update_mode(); // !!! do that later SetTopWindow(mainframe); @@ -4137,13 +4143,13 @@ void GUI_App::select_machine(const std::string& agent_id) // Use MonitorPanel::select_machine() to trigger full selection flow // This reuses existing logic for machine switching (UI updates, callbacks, etc.) - if (mainframe && mainframe->m_monitor) { - mainframe->m_monitor->select_machine(dev_id); + if (MonitorPanel* monitor = MonitorPanel::if_built()) { + monitor->select_machine(dev_id); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": triggered select_machine for dev_id=" << dev_id; - } else { - // Fallback if MonitorPanel not available - m_device_manager->set_selected_machine(dev_id); - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": fallback set_selected_machine dev_id=" << dev_id; + } else if (m_device_manager->set_selected_machine(dev_id)) { + // The Device tab's own state is set when the tab is built. + MonitorPanel::on_machine_selected(m_device_manager->get_selected_machine()); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": set_selected_machine dev_id=" << dev_id; } } @@ -4667,6 +4673,7 @@ void GUI_App::recreate_GUI(const wxString &msg_name) //BBS: trigger restore project logic here, and skip confirm plater_->trigger_restore_project(1); + mainframe->prebuild_pages_when_idle(); // #ys_FIXME_delete_after_testing Do we still need this ? // CallAfter([]() { @@ -5008,7 +5015,8 @@ void GUI_App::get_login_info(const std::string& provider/* = ORCA_CLOUD_PROVIDER wxString strJS = wxString::Format("window.postMessage(%s)", from_u8(logout_cmd)); GUI::wxGetApp().run_script(strJS); } - mainframe->m_webview->SetLoginPanelVisibility(true); + if (WebViewPanel* home = WebViewPanel::if_built()) + home->SetLoginPanelVisibility(true); } } @@ -5140,9 +5148,9 @@ std::string GUI_App::handle_web_request(std::string cmd) "homepage_bambu_login_or_register", }; if (app_config->get_stealth_mode() && stealth_blocked_info_commands.count(command_str)) { - CallAfter([this] { - if (mainframe && mainframe->m_webview) - mainframe->m_webview->SendCloudProvidersInfo(); + CallAfter([] { + if (WebViewPanel* home = WebViewPanel::if_built()) + home->SendCloudProvidersInfo(); }); return ""; } @@ -5156,8 +5164,8 @@ std::string GUI_App::handle_web_request(std::string cmd) if (dlg.ShowModal() == wxID_OK) { app_config->set_bool("stealth_mode", false); app_config->save(); - if (mainframe && mainframe->m_webview) - mainframe->m_webview->SendCloudProvidersInfo(); + if (WebViewPanel* home = WebViewPanel::if_built()) + home->SendCloudProvidersInfo(); // Continue with login if (command_str == "homepage_login_or_register") this->request_login(true); @@ -5238,8 +5246,8 @@ std::string GUI_App::handle_web_request(std::string cmd) } else if (command_str.compare("get_recent_projects") == 0) { if (mainframe) { - if (mainframe->m_webview) { - mainframe->m_webview->SendRecentList(INT_MAX); + if (WebViewPanel* home = WebViewPanel::if_built()) { + home->SendRecentList(INT_MAX); } } } @@ -7772,8 +7780,8 @@ void GUI_App::on_stealth_mode_enter() BOOST_LOG_TRIVIAL(info) << "logout: on_stealth_mode_enter"; request_user_logout(ORCA_CLOUD_PROVIDER); request_user_logout(BBL_CLOUD_PROVIDER); - if (mainframe && mainframe->m_webview) { - mainframe->m_webview->SendCloudProvidersInfo(); + if (WebViewPanel* home = WebViewPanel::if_built()) { + home->SendCloudProvidersInfo(); } } @@ -8183,6 +8191,24 @@ ConfigOptionMode GUI_App::get_saved_mode() return saved_mode_from_string(app_config->get("user_mode")); } +bool GUI_App::starts_on_prepare() const +{ + return app_config->get("default_page") == "1"; +} + +int GUI_App::input_idle_ms() const +{ + return int(std::chrono::duration_cast(std::chrono::steady_clock::now() - m_last_input).count()); +} + +// Every wxCommandEvent claims the user-input category, so only real mouse and key events count. +int GUI_App::FilterEvent(wxEvent& event) +{ + if (!event.IsCommandEvent() && (event.GetEventCategory() & wxEVT_CATEGORY_USER_INPUT)) + m_last_input = std::chrono::steady_clock::now(); + return Event_Skip; +} + ConfigOptionMode GUI_App::get_mode() { return app_config->get_bool("developer_mode") ? comDevelop : get_saved_mode(); @@ -8234,9 +8260,10 @@ void GUI_App::update_mode() mainframe->m_param_panel->update_mode(); if (mainframe->m_param_dialog) mainframe->m_param_dialog->panel()->update_mode(); - if (mainframe->m_printer_view) - mainframe->m_printer_view->update_mode(); - mainframe->m_webview->update_mode(); + if (PrinterWebView* view = PrinterWebView::if_built()) + view->update_mode(); + if (WebViewPanel* home = WebViewPanel::if_built()) + home->update_mode(); #ifdef _MSW_DARK_MODE if (!wxGetApp().tabs_as_menu()) @@ -8254,9 +8281,10 @@ void GUI_App::update_mode() } void GUI_App::update_internal_development() { - mainframe->m_webview->update_mode(); - if (mainframe->m_printer_view) - mainframe->m_printer_view->update_mode(); + if (WebViewPanel* home = WebViewPanel::if_built()) + home->update_mode(); + if (PrinterWebView* view = PrinterWebView::if_built()) + view->update_mode(); } void GUI_App::show_ip_address_enter_dialog(wxString title) diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 2d55c5e96c..e888a52b06 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_GUI_App_hpp_ #define slic3r_GUI_App_hpp_ +#include #include #include #include @@ -248,6 +249,7 @@ private: bool m_app_conf_exists{ false }; EAppMode m_app_mode{ EAppMode::Editor }; bool m_is_recreating_gui{ false }; + std::chrono::steady_clock::time_point m_last_input{ std::chrono::steady_clock::now() }; #ifdef __linux__ bool m_opengl_initialized{ false }; #endif @@ -387,6 +389,11 @@ public: bool is_editor() const { return m_app_mode == EAppMode::Editor; } bool is_gcode_viewer() const { return m_app_mode == EAppMode::GCodeViewer; } bool is_recreating_gui() const { return m_is_recreating_gui; } + // Milliseconds since the last mouse or keyboard event the app processed. + int input_idle_ms() const; + int FilterEvent(wxEvent& event) override; + // The Preferences "Default page" choice, stored as its index: 0 Home, 1 Prepare. + bool starts_on_prepare() const; std::string logo_name() const { return is_editor() ? "OrcaSlicer" : "OrcaSlicer-gcodeviewer"; } bool is_closing() const { return m_is_closing.load(std::memory_order_acquire); } diff --git a/src/slic3r/GUI/HMSPanel.cpp b/src/slic3r/GUI/HMSPanel.cpp index cd3d35bfc8..c2a8314bd5 100644 --- a/src/slic3r/GUI/HMSPanel.cpp +++ b/src/slic3r/GUI/HMSPanel.cpp @@ -122,7 +122,8 @@ HMSNotifyItem::HMSNotifyItem(const std::string& dev_id, wxWindow *parent, DevHMS m_hms_content->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent& e) { wxCommandEvent evt(EVT_ALREADY_READ_HMS); evt.SetString(long_error_code); - wxPostEvent(wxGetApp().mainframe->m_monitor, evt); + if (MonitorPanel* monitor = MonitorPanel::if_built()) + wxPostEvent(monitor, evt); if (!m_url.empty()) wxLaunchDefaultBrowser(m_url); }); diff --git a/src/slic3r/GUI/IdleScheduler.cpp b/src/slic3r/GUI/IdleScheduler.cpp new file mode 100644 index 0000000000..2b71a9f8e6 --- /dev/null +++ b/src/slic3r/GUI/IdleScheduler.cpp @@ -0,0 +1,100 @@ +#include "IdleScheduler.hpp" + +#include + +#include + +#include "libslic3r/Utils.hpp" + +#ifdef _WIN32 +#include +#endif + +namespace Slic3r { namespace GUI { + +namespace { + +// The timer's period while waiting for the user to go quiet. +constexpr int tick_ms = 250; +// Input-free time before a slice may start, about a double-click interval, so a user +// mid-gesture is left alone. +constexpr int quiet_ms = 500; +// Budget of one slice. The next slice is a timer message, so paint, timers and input +// queued meanwhile are handled first; a click waits at most a slice plus the unit that +// overran it. +constexpr int slice_ms = 40; +// On GTK a due timer runs ahead of repaints and posted events, so the next slice waits a few ms. +#ifdef __WXGTK__ +constexpr int next_slice_ms = 5; +#else +constexpr int next_slice_ms = 0; +#endif + +// True when unhandled keyboard, button, touch or pen input is queued; only Windows can ask. +bool input_pending() +{ +#ifdef _WIN32 + // Windows synthesizes a mouse move whenever a window appears under the cursor, so those + // do not count. + return (GetQueueStatus(QS_INPUT & ~QS_MOUSEMOVE) >> 16) != 0; +#else + return false; +#endif +} + +} // namespace + +IdleScheduler::IdleScheduler(std::function input_idle_ms) : m_input_idle_ms(std::move(input_idle_ms)) +{ + m_timer.Bind(wxEVT_TIMER, [this](wxTimerEvent&) { tick(); }); +} + +void IdleScheduler::start() +{ + if (!m_timer.IsRunning()) + m_timer.Start(tick_ms); +} + +void IdleScheduler::stop() +{ + m_timer.Stop(); +} + +void IdleScheduler::tick() +{ + // A unit that pumps the event loop lets the timer fire inside its own slice. + if (m_in_slice) + return; + if (!m_queue.pending()) { + stop(); + return; + } + if (m_input_idle_ms() < quiet_ms || input_pending()) { + start(); + return; + } + const auto now_ms = [] { + return std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); + }; + const char* const fn = __FUNCTION__; + m_in_slice = true; + PrebuildQueue::Slice slice; + { + ScopeGuard in_slice([this] { m_in_slice = false; }); + slice = m_queue.run_slice(slice_ms, now_ms, input_pending, [fn](const std::string& name, long long ms) { + BOOST_LOG_TRIVIAL(debug) << fn << ": " << name << ": unit took " << ms << " ms"; + }); + } + if (slice.completed) + BOOST_LOG_TRIVIAL(info) << fn << ": task complete: " << slice.name << ", " << slice.units << " unit(s) in " << slice.ms << " ms this slice"; + else + BOOST_LOG_TRIVIAL(debug) << fn << ": " << slice.name << ": " << slice.units << " unit(s) in " << slice.ms << " ms, yielding"; + if (!slice.remaining) + stop(); + else if (input_pending()) + m_timer.Start(tick_ms); + else + m_timer.StartOnce(next_slice_ms); +} + +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/IdleScheduler.hpp b/src/slic3r/GUI/IdleScheduler.hpp new file mode 100644 index 0000000000..7c31e9414c --- /dev/null +++ b/src/slic3r/GUI/IdleScheduler.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +#include +#include + +#include "PrebuildQueue.hpp" + +namespace Slic3r { namespace GUI { + +// Runs the queue's units while the user is idle. Once the user has been idle long enough, +// slices run one per timer message until the work is done or input arrives, so the event +// loop handles what it has between slices. Main thread only. +class IdleScheduler +{ +public: + // input_idle_ms reports how long ago the user last touched the mouse or keyboard. + explicit IdleScheduler(std::function input_idle_ms); + + void add(LazyBase& task) { m_queue.add(task); } + void clear() { m_queue.clear(); } + // The task names in queue order, for a log line. + std::string names() const { return m_queue.names(); } + + // Arms the timer; it stops itself once no task is pending, so call again when a task + // appears. + void start(); + void stop(); + +private: + void tick(); + + PrebuildQueue m_queue; + wxTimer m_timer; + std::function m_input_idle_ms; + bool m_in_slice{ false }; +}; + +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Lazy.cpp b/src/slic3r/GUI/Lazy.cpp new file mode 100644 index 0000000000..2a1a74510a --- /dev/null +++ b/src/slic3r/GUI/Lazy.cpp @@ -0,0 +1,27 @@ +#include "Lazy.hpp" + +#include +#include +#include + +namespace Slic3r { namespace GUI { + +LazyBase::OnDemandBuild::OnDemandBuild(const LazyBase& lazy) : m_lazy(lazy), m_started(std::chrono::steady_clock::now()) +{ + // The unit tests have no app. + if (wxTheApp != nullptr) + m_busy = std::make_unique(); +} + +LazyBase::OnDemandBuild::~OnDemandBuild() +{ + BOOST_LOG_TRIVIAL(info) << "Lazy::ensure: built " << m_lazy.name() << " on demand, " << m_units << " unit(s) in " + << std::chrono::duration_cast(std::chrono::steady_clock::now() - m_started).count() << " ms"; +} + +void LazyBase::log_null_factory(const std::string& name) +{ + BOOST_LOG_TRIVIAL(error) << "Lazy::build_step: the factory for " << name << " returned null"; +} + +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Lazy.hpp b/src/slic3r/GUI/Lazy.hpp new file mode 100644 index 0000000000..33e092d887 --- /dev/null +++ b/src/slic3r/GUI/Lazy.hpp @@ -0,0 +1,198 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "StagedBuild.hpp" + +class wxBusyCursor; + +// Deferred construction of one object. Lazy holds the factory and builds the object on +// demand or, unit by unit, from an IdleScheduler; LazyBase is what the scheduler sees of +// it; LazyInstance gives a type with one such object app-wide static access to it. +// docs/HLSD/deferred-page-construction.md covers the design. + +namespace Slic3r { namespace GUI { + +template class LazyInstance; + +// A prebuild task: what PrebuildQueue sees of a Lazy. A type with its own unit sequence +// implements it directly. +class LazyBase +{ +public: + virtual ~LazyBase() = default; + + // Labels the object in logs. + virtual const std::string& name() const = 0; + virtual bool built() const = 0; + // Whether the idle prebuild has work here. + virtual bool pending() const { return !built(); } + // Runs one unit and returns true while more remain. + virtual bool build_step() = 0; + // Position in the idle queue: lower builds first, negative is never prebuilt. + virtual int prebuild_order() const = 0; + +protected: + // Busy cursor around a build the user is waiting on, and a log line after it. + class OnDemandBuild + { + public: + explicit OnDemandBuild(const LazyBase& lazy); + ~OnDemandBuild(); + void unit() { ++m_units; } + + private: + const LazyBase& m_lazy; + std::unique_ptr m_busy; + std::chrono::steady_clock::time_point m_started; + int m_units{ 0 }; + }; + + static void log_null_factory(const std::string& name); +}; + +// Holds an object a factory makes on the first build_step() or ensure(), followed by one +// StagedBuild step per unit if the type has them, and keeps callbacks until the object is +// complete. The object's parent owns it, not the holder. A LazyInstance type is registered +// for its statics; any other type is reached only through the holder. +template +class Lazy : public LazyBase +{ +public: + using Factory = std::function; + + Lazy(std::string name, int order, Factory make) : m_name(std::move(name)), m_order(order), m_make(std::move(make)) + { + if constexpr (registered()) + LazyInstance::s_lazy = this; + } + ~Lazy() override + { + if constexpr (registered()) + if (LazyInstance::s_lazy == this) + LazyInstance::s_lazy = nullptr; + } + Lazy(const Lazy&) = delete; + Lazy& operator=(const Lazy&) = delete; + + // Null until completely built. + T* get() const { return built() ? m_object : nullptr; } + + // Builds whatever is left now and returns the object, null if the factory returned null + // or a nested call finds the object mid-build. + T* ensure() + { + if (!built() && !m_building) { + OnDemandBuild build(*this); + do + build.unit(); + while (build_step()); + } + return get(); + } + + // Runs fn on the object now if it is built, otherwise once it is. + void when_built(std::function fn) + { + if (built()) + fn(*m_object); + else + m_deferred.push_back(std::move(fn)); + } + + const std::string& name() const override { return m_name; } + // Read by a worker thread through the statics; the last write in build_step() releases it. + bool built() const override { return m_complete.load(std::memory_order_acquire); } + bool pending() const override { return !built() && !m_failed; } + int prebuild_order() const override { return m_order; } + + // The factory is the first unit, then one StagedBuild step each. A unit that pumps the + // event loop cannot re-enter; a nested call does nothing. + bool build_step() override + { + if (built() || m_building || m_failed) + return false; + m_building = true; + try { + if (m_object == nullptr) + m_object = m_make(); + else + step(); + } catch (...) { + m_building = false; + throw; + } + m_building = false; + if (m_object == nullptr) { + m_failed = true; + log_null_factory(m_name); + return false; + } + if (steps_remain()) + return true; + m_complete.store(true, std::memory_order_release); + for (auto& fn : m_deferred) + fn(*m_object); + m_deferred.clear(); + return false; + } + +private: + static constexpr bool registered() { return std::is_base_of_v, T>; } + static constexpr bool staged() { return std::is_base_of_v; } + + bool steps_remain() const + { + if constexpr (staged()) + return !m_object->built(); + else + return false; + } + void step() + { + if constexpr (staged()) + m_object->build_step(); + } + + std::string m_name; + int m_order; + Factory m_make; + T* m_object{ nullptr }; + std::atomic m_complete{ false }; + bool m_building{ false }; + bool m_failed{ false }; + std::vector> m_deferred; +}; + +// Mixin for a type with one lazily built instance in the app. The statics reach that +// instance through its Lazy holder (a recreated MainFrame's holder replaces the old +// frame's). +template +class LazyInstance +{ +public: + // Null until completely built. + static Self* if_built() { return s_lazy ? s_lazy->get() : nullptr; } + // Builds the object if needed; null while no holder exists or the holder has no + // object. + static Self* ensure() { return s_lazy ? s_lazy->ensure() : nullptr; } + // Runs fn on the object now if it is built, otherwise once it is. + static void when_built(std::function fn) + { + if (s_lazy) + s_lazy->when_built(std::move(fn)); + } + +private: + friend class Lazy; + inline static Lazy* s_lazy{ nullptr }; +}; + +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/LazyPage.cpp b/src/slic3r/GUI/LazyPage.cpp new file mode 100644 index 0000000000..d14947bd80 --- /dev/null +++ b/src/slic3r/GUI/LazyPage.cpp @@ -0,0 +1,14 @@ +#include "LazyPage.hpp" + +#include "GUI_App.hpp" + +namespace Slic3r { namespace GUI { + +void apply_dark_ui_to_lazy_panel(wxWindow* panel) +{ +#ifdef _MSW_DARK_MODE + wxGetApp().UpdateDarkUIWin(panel); +#endif +} + +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/LazyPage.hpp b/src/slic3r/GUI/LazyPage.hpp new file mode 100644 index 0000000000..fc85f69285 --- /dev/null +++ b/src/slic3r/GUI/LazyPage.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +#include "Lazy.hpp" + +namespace Slic3r { namespace GUI { + +// Applies the app's dark-mode pass to a panel built after the frame's own pass ran. +void apply_dark_ui_to_lazy_panel(wxWindow* panel); + +// A page whose panel is built the first time the page is shown, or earlier by an +// IdleScheduler; nothing builds while the frame is still hidden. The Lazy side holds the +// panel and, for a LazyInstance panel type, registers it for the type's statics. +template +class LazyPage : public wxPanel, public Lazy +{ +public: + using Factory = std::function; + + LazyPage(wxWindow* parent, std::string name, int order, Factory make = [](wxWindow* parent) { return new Panel(parent); }) + : wxPanel(parent), Lazy(std::move(name), order, [this, make = std::move(make)] { + Panel* panel = make(this); + GetSizer()->Add(panel, 1, wxEXPAND); + // Hidden while its page is, as an inserted page would be. + if (!IsShown()) + panel->Hide(); + return panel; + }) + { + SetSizer(new wxBoxSizer(wxVERTICAL)); + // Shown by the book when its tab is selected. + Hide(); + this->when_built([this](Panel& panel) { + apply_dark_ui_to_lazy_panel(&panel); + Layout(); + }); + } + + // The parent book currently lists this page. + bool in_book() const + { + auto* book = dynamic_cast(GetParent()); + return book != nullptr && book->FindPage(this) != wxNOT_FOUND; + } + + // Pending only while the tab is in the book. + bool pending() const override { return in_book() && Lazy::pending(); } + + // Forwarded so the panel's own Show() override stays its activation hook; wx calls this + // virtual from the book's ShowWithEffect() only for wxSHOW_EFFECT_NONE, the default. + bool Show(bool show = true) override + { + const bool changed = wxPanel::Show(show); + if (show) { + // The book shows its first page as it is inserted, before startup has chosen the + // start page, so a hidden frame builds nothing; MainFrame::Show() completes it. + if (this->built() || wxGetTopLevelParent(this)->IsShown()) { + if (Panel* panel = this->ensure()) + panel->Show(true); + // The sizer skipped the panel while the book kept it hidden. + Layout(); + } + } else if (Panel* panel = this->get()) { + panel->Show(false); + } + return changed; + } +}; + +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index ca0ef95a76..ec4428a32a 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -317,7 +317,8 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ // BBS , m_recent_projects(18) , m_settings_dialog(this) - , diff_dialog(this) + , m_idle([] { return wxGetApp().input_idle_ms(); }) + , m_diff_dialog("compare_presets", 100, [this] { return make_diff_dialog(); }) { #ifdef __WXOSX__ set_miniaturizable(GetHandle()); @@ -737,9 +738,6 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ wxGetApp().persist_window_geometry(this, true); wxGetApp().persist_window_geometry(&m_settings_dialog, true); - // bind events from DiffDlg - - bind_diff_dialog(); } bool MainFrame::handle_global_shortcut(const KeyChord& chord) @@ -832,8 +830,10 @@ bool MainFrame::handle_global_shortcut(const KeyChord& chord) return true; } -void MainFrame::bind_diff_dialog() +DiffPresetDialog* MainFrame::make_diff_dialog() { + auto* dialog = new DiffPresetDialog(this); + auto get_tab = [](Preset::Type type) { Tab* null_tab = nullptr; for (Tab* tab : wxGetApp().tabs_list) @@ -842,23 +842,24 @@ void MainFrame::bind_diff_dialog() return null_tab; }; - auto transfer = [this, get_tab](Preset::Type type) { - get_tab(type)->transfer_options(diff_dialog.get_left_preset_name(type), - diff_dialog.get_right_preset_name(type), - diff_dialog.get_selected_options(type)); + auto transfer = [dialog, get_tab](Preset::Type type) { + get_tab(type)->transfer_options(dialog->get_left_preset_name(type), + dialog->get_right_preset_name(type), + dialog->get_selected_options(type)); }; - auto process_options = [this](std::function process) { - const Preset::Type diff_dlg_type = diff_dialog.view_type(); + auto process_options = [dialog](std::function process) { + const Preset::Type diff_dlg_type = dialog->view_type(); if (diff_dlg_type == Preset::TYPE_INVALID) { - for (const Preset::Type& type : diff_dialog.types_list() ) + for (const Preset::Type& type : dialog->types_list() ) process(type); } else process(diff_dlg_type); }; - diff_dialog.Bind(EVT_DIFF_DIALOG_TRANSFER, [process_options, transfer](SimpleEvent&) { process_options(transfer); }); + dialog->Bind(EVT_DIFF_DIALOG_TRANSFER, [process_options, transfer](SimpleEvent&) { process_options(transfer); }); + return dialog; } @@ -1186,8 +1187,9 @@ void MainFrame::update_edge_panels() void MainFrame::shutdown() { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "MainFrame::shutdown enter"; - if (m_project != nullptr) - m_project->shutdown(); + m_idle.stop(); + if (ProjectPanel* project = ProjectPanel::if_built()) + project->shutdown(); m_plugin_pages.shutdown(); if (m_plater != nullptr) m_plater->remove_dock_panes(); @@ -1314,19 +1316,6 @@ void MainFrame::show_option(bool show) } } -#ifdef SLIC3R_CAD -DesignPanel* MainFrame::ensure_design_panel() -{ - if (m_design_panel == nullptr && m_design_page != nullptr) { - wxBusyCursor busy; - m_design_panel = new DesignPanel(m_design_page); - m_design_page->GetSizer()->Add(m_design_panel, 1, wxEXPAND); - m_design_page->Layout(); - } - return m_design_panel; -} -#endif - void MainFrame::init_tabpanel() { // wxNB_NOPAGETHEME: Disable Windows Vista theme for the Notebook background. The theme performance is terrible on // Windows 10 with multiple high resolution displays connected. @@ -1369,23 +1358,20 @@ void MainFrame::init_tabpanel() { // m_param_panel->OnActivate(); #ifdef SLIC3R_CAD else if (m_design_page != nullptr && panel == m_design_page) { - // Built on first activation, never at startup: the panel creates several hundred - // controls and its own GL canvas, which a user who does not open the tab should - // not pay for. - ensure_design_panel(); // Re-sync the Design bed to the active printer: the panel is built before the // printer profile is fully applied, so its bed must refresh on activation or the // grid (true bed) spills past the stale default bed quad. - m_design_panel->on_tab_shown(); + DesignPanel::ensure()->on_tab_shown(); } #endif - else if (panel == m_monitor) { + else if (panel == m_monitor_page) { //monitor } #ifdef SLIC3R_CAD // Any page that is not Design takes the Design status line down with it — see // DesignPanel::on_tab_hidden for why the popup does not follow the page on its own. - if (m_design_panel != nullptr && panel != m_design_page) m_design_panel->on_tab_hidden(); + if (DesignPanel* design = DesignPanel::if_built(); design != nullptr && panel != m_design_page) + design->on_tab_hidden(); #endif #ifndef __APPLE__ if (m_last_selected_tab == TAB_ID_PREPARE) { @@ -1401,13 +1387,14 @@ void MainFrame::init_tabpanel() { }); if (wxGetApp().is_editor()) { - m_webview = new WebViewPanel(m_tabpanel); + m_home_page = new LazyPage(m_tabpanel, TAB_ID_HOME, 10); + m_lazy_pages.push_back(m_home_page); Bind(EVT_LOAD_URL, [this](wxCommandEvent &evt) { wxString url = evt.GetString(); select_tab(TAB_ID_HOME); - m_webview->load_url(url); + WebViewPanel::ensure()->load_url(url); }); - m_tabpanel->AddPage(TAB_ID_HOME, m_webview, "", "tab_home_active"); + m_tabpanel->AddPage(TAB_ID_HOME, m_home_page, "", "tab_home_active"); m_param_panel = new ParamsPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL); } @@ -1418,15 +1405,13 @@ void MainFrame::init_tabpanel() { wxGetApp().plater_ = m_plater; #ifdef SLIC3R_CAD - // Stand-in page for the Design tab. The real DesignPanel is built into it the first time - // the tab is selected (see the page-changed handler above), so nothing it constructs sits - // on the startup path. The experimental feature is off by default, and when it is off the - // page is never created, so the tab does not appear at all (the preference takes effect on - // the next start, like the other feature toggles). + // The experimental feature is off by default, and when it is off the page is never + // created, so the tab does not appear at all (the preference takes effect on the next + // start, like the other feature toggles). if (wxGetApp().is_enable_cad_feature()) { - m_design_page = new wxPanel(this); - m_design_page->SetSizer(new wxBoxSizer(wxVERTICAL)); - m_design_page->Hide(); + // Experimental and heavy enough that building it unasked would cost more than it saves. + m_design_page = new LazyPage(this, TAB_ID_DESIGN, -1); + m_lazy_pages.push_back(m_design_page); start_mcp_control_if_enabled(); // opens the MCP socket iff ORCA_CAD_MCP is set } #endif @@ -1434,33 +1419,41 @@ void MainFrame::init_tabpanel() { create_preset_tabs(); //BBS add pages - m_monitor = new MonitorPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); - m_monitor->SetBackgroundColour(*wxWHITE); - m_tabpanel->AddPage(TAB_ID_MONITOR, m_monitor, _L("Device"), "tab_monitor_active"); + m_monitor_page = new LazyPage(m_tabpanel, TAB_ID_MONITOR, 20); + m_lazy_pages.push_back(m_monitor_page); + m_tabpanel->AddPage(TAB_ID_MONITOR, m_monitor_page, _L("Device"), "tab_monitor_active"); - m_printer_view = new PrinterWebView(m_tabpanel); + m_printer_view_page = new LazyPage(m_tabpanel, TAB_ID_MONITOR_WEB, 50, [this](wxWindow* parent) { + auto* view = new PrinterWebView(parent); + if (!m_printer_url.empty()) + view->load_url(m_printer_url, m_printer_api_key); + return view; + }); + m_lazy_pages.push_back(m_printer_view_page); Bind(EVT_LOAD_PRINTER_URL, [this](LoadPrinterViewEvent &evt) { - wxString url = evt.GetString(); - wxString key = evt.GetAPIkey(); //select_tab(MainFrame::tpMonitor); - m_printer_view->load_url(url, key); + m_printer_url = evt.GetString(); + m_printer_api_key = evt.GetAPIkey(); + if (PrinterWebView* view = PrinterWebView::if_built()) + view->load_url(m_printer_url, m_printer_api_key); }); - m_printer_view->Hide(); + m_multi_machine_page = new LazyPage(m_tabpanel, TAB_ID_MULTI_DEVICE, 40); + m_lazy_pages.push_back(m_multi_machine_page); if (wxGetApp().is_enable_multi_machine()) { - m_multi_machine = new MultiMachinePage(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); - m_multi_machine->SetBackgroundColour(*wxWHITE); // TODO: change the bitmap - m_tabpanel->AddPage(TAB_ID_MULTI_DEVICE, m_multi_machine, _L("Multi-device"), "tab_multi_active"); + m_tabpanel->AddPage(TAB_ID_MULTI_DEVICE, m_multi_machine_page, _L("Multi-device"), "tab_multi_active"); } - m_project = new ProjectPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); - m_project->SetBackgroundColour(*wxWHITE); - m_tabpanel->AddPage(TAB_ID_PROJECT, m_project, _L("Project"), "tab_auxiliary_active"); + m_project_page = new LazyPage(m_tabpanel, TAB_ID_PROJECT, 60); + m_lazy_pages.push_back(m_project_page); + m_tabpanel->AddPage(TAB_ID_PROJECT, m_project_page, _L("Project"), "tab_auxiliary_active"); - m_calibration = new CalibrationPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); - m_calibration->SetBackgroundColour(*wxWHITE); - m_tabpanel->AddPage(TAB_ID_CALIBRATION, m_calibration, _L("Calibration"), "tab_calibration_active"); + // show_device() removes this tab for printers without the Bambu device tab, and the page + // then never builds its panel. + m_calibration_page = new LazyPage(m_tabpanel, TAB_ID_CALIBRATION, 30); + m_lazy_pages.push_back(m_calibration_page); + m_tabpanel->AddPage(TAB_ID_CALIBRATION, m_calibration_page, _L("Calibration"), "tab_calibration_active"); // Plugin pages are appended after the built-in tabs; their ids are namespaced // (plugin..) so they can't collide with the built-in TAB_ID_* constants. @@ -1495,67 +1488,44 @@ void MainFrame::show_device(bool should_use_native) { // Remove the extra page before switching to any layout that shouldn't have it. if (!want_web_device_tab) { if ((idx = m_tabpanel->FindPageByName(TAB_ID_MONITOR_WEB)) != wxNOT_FOUND) { - m_printer_view->Show(false); + m_printer_view_page->Show(false); m_tabpanel->RemovePage(idx); } } if (use_printer_agents) { - if (!m_monitor) { - m_monitor = new MonitorPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); - m_monitor->SetBackgroundColour(*wxWHITE); - } - - if (m_tabpanel->FindPage(m_monitor) == wxNOT_FOUND) { - if ((idx = m_tabpanel->FindPage(m_printer_view)) != wxNOT_FOUND) { - m_printer_view->Show(false); + if (!m_monitor_page->in_book()) { + if ((idx = m_tabpanel->FindPage(m_printer_view_page)) != wxNOT_FOUND) { + m_printer_view_page->Show(false); m_tabpanel->RemovePage(idx); } - m_monitor->Show(false); - m_tabpanel->InsertPage(m_tabpanel->PositionAfter({TAB_ID_PREVIEW}), TAB_ID_MONITOR, m_monitor, + m_monitor_page->Show(false); + m_tabpanel->InsertPage(m_tabpanel->PositionAfter({TAB_ID_PREVIEW}), TAB_ID_MONITOR, m_monitor_page, _L("Device"), "tab_monitor_active"); } - if (m_printer_view == nullptr) { - m_printer_view = new PrinterWebView(m_tabpanel); - Bind(EVT_LOAD_PRINTER_URL, [this](LoadPrinterViewEvent& evt) { - wxString url = evt.GetString(); - wxString key = evt.GetAPIkey(); - // select_tab(MainFrame::tpMonitor); - m_printer_view->load_url(url, key); - }); - } - if (wxGetApp().is_enable_multi_machine()) { - if (!m_multi_machine) { - m_multi_machine = new MultiMachinePage(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); - m_multi_machine->SetBackgroundColour(*wxWHITE); - } // TODO: change the bitmap - if (m_tabpanel->FindPage(m_multi_machine) == wxNOT_FOUND) { - m_multi_machine->Show(false); + if (!m_multi_machine_page->in_book()) { + m_multi_machine_page->Show(false); // Past the web Device tab when it is already there, so enabling multi-machine // later can't wedge this page between the two Device tabs. m_tabpanel->InsertPage(m_tabpanel->PositionAfter({TAB_ID_MONITOR_WEB, TAB_ID_MONITOR}), - TAB_ID_MULTI_DEVICE, m_multi_machine, _L("Multi-device"), "tab_multi_active"); + TAB_ID_MULTI_DEVICE, m_multi_machine_page, _L("Multi-device"), "tab_multi_active"); } } - if (!m_calibration) { - m_calibration = new CalibrationPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); - m_calibration->SetBackgroundColour(*wxWHITE); - } - if (m_tabpanel->FindPage(m_calibration) == wxNOT_FOUND) { - m_calibration->Show(false); - m_tabpanel->InsertPage(m_tabpanel->PositionAfter({TAB_ID_PROJECT}), TAB_ID_CALIBRATION, m_calibration, + if (!m_calibration_page->in_book()) { + m_calibration_page->Show(false); + m_tabpanel->InsertPage(m_tabpanel->PositionAfter({TAB_ID_PROJECT}), TAB_ID_CALIBRATION, m_calibration_page, _L("Calibration"), "tab_calibration_active"); } if (want_web_device_tab) { - if ((idx = m_tabpanel->FindPage(m_printer_view)) == wxNOT_FOUND) { - m_printer_view->Show(false); + if ((idx = m_tabpanel->FindPage(m_printer_view_page)) == wxNOT_FOUND) { + m_printer_view_page->Show(false); // Immediately right of the native Device tab, not at the end of the tab bar. m_tabpanel->InsertPage(m_tabpanel->PositionAfter({TAB_ID_MONITOR}), TAB_ID_MONITOR_WEB, - m_printer_view, _L("Device (Web)"), "tab_monitor_active"); + m_printer_view_page, _L("Device (Web)"), "tab_monitor_active"); } else { m_tabpanel->SetPageText(idx, _L("Device (Web)")); } @@ -1567,48 +1537,37 @@ void MainFrame::show_device(bool should_use_native) { fit_tab_labels(); // ORCA on printer change m_plugin_pages.relayout(); // re-sync plugin tabs against the native tabs just mutated above - + if (m_prebuild_started) + m_idle.start(); return; } if (should_use_native) { - if (m_tabpanel->FindPage(m_monitor) != wxNOT_FOUND) { + if (m_monitor_page->in_book()) { fit_tab_labels(); // ORCA on printer change - same button layout return; } // Remove printer view - if ((idx = m_tabpanel->FindPage(m_printer_view)) != wxNOT_FOUND) { - m_printer_view->Show(false); + if ((idx = m_tabpanel->FindPage(m_printer_view_page)) != wxNOT_FOUND) { + m_printer_view_page->Show(false); m_tabpanel->RemovePage(idx); } - // Create/insert monitor page - if (!m_monitor) { - m_monitor = new MonitorPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); - m_monitor->SetBackgroundColour(*wxWHITE); - } - m_monitor->Show(false); - m_tabpanel->InsertPage(m_tabpanel->PositionAfter({TAB_ID_PREVIEW}), TAB_ID_MONITOR, m_monitor, + // Insert monitor page + m_monitor_page->Show(false); + m_tabpanel->InsertPage(m_tabpanel->PositionAfter({TAB_ID_PREVIEW}), TAB_ID_MONITOR, m_monitor_page, _L("Device"), "tab_monitor_active"); if (wxGetApp().is_enable_multi_machine()) { - if (!m_multi_machine) { - m_multi_machine = new MultiMachinePage(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); - m_multi_machine->SetBackgroundColour(*wxWHITE); - } // TODO: change the bitmap - m_multi_machine->Show(false); - m_tabpanel->InsertPage(m_tabpanel->PositionAfter({TAB_ID_MONITOR}), TAB_ID_MULTI_DEVICE, m_multi_machine, + m_multi_machine_page->Show(false); + m_tabpanel->InsertPage(m_tabpanel->PositionAfter({TAB_ID_MONITOR}), TAB_ID_MULTI_DEVICE, m_multi_machine_page, _L("Multi-device"), "tab_multi_active"); } - if (!m_calibration) { - m_calibration = new CalibrationPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); - m_calibration->SetBackgroundColour(*wxWHITE); - } - m_calibration->Show(false); + m_calibration_page->Show(false); // Last of the built-in tabs, but plugin tabs already sit past it — anchor rather than // append, so its position doesn't depend on the relayout() below running afterwards. - m_tabpanel->InsertPage(m_tabpanel->PositionAfter({TAB_ID_PROJECT}), TAB_ID_CALIBRATION, m_calibration, + m_tabpanel->InsertPage(m_tabpanel->PositionAfter({TAB_ID_PROJECT}), TAB_ID_CALIBRATION, m_calibration_page, _L("Calibration"), "tab_calibration_active"); #ifdef _MSW_DARK_MODE @@ -1616,37 +1575,30 @@ void MainFrame::show_device(bool should_use_native) { #endif // _MSW_DARK_MODE } else { - if (m_tabpanel->FindPage(m_printer_view) != wxNOT_FOUND) { + if (m_printer_view_page->in_book()) { fit_tab_labels(); // ORCA on printer change - same button layout return; } - if ((idx = m_tabpanel->FindPage(m_calibration)) != wxNOT_FOUND) { - m_calibration->Show(false); + if ((idx = m_tabpanel->FindPage(m_calibration_page)) != wxNOT_FOUND) { + m_calibration_page->Show(false); m_tabpanel->RemovePage(idx); } - if ((idx = m_tabpanel->FindPage(m_multi_machine)) != wxNOT_FOUND) { - m_multi_machine->Show(false); + if ((idx = m_tabpanel->FindPage(m_multi_machine_page)) != wxNOT_FOUND) { + m_multi_machine_page->Show(false); m_tabpanel->RemovePage(idx); } - if ((idx = m_tabpanel->FindPage(m_monitor)) != wxNOT_FOUND) { - m_monitor->Show(false); + if ((idx = m_tabpanel->FindPage(m_monitor_page)) != wxNOT_FOUND) { + m_monitor_page->Show(false); m_tabpanel->RemovePage(idx); } - if (m_printer_view == nullptr) { - m_printer_view = new PrinterWebView(m_tabpanel); - Bind(EVT_LOAD_PRINTER_URL, [this](LoadPrinterViewEvent& evt) { - wxString url = evt.GetString(); - wxString key = evt.GetAPIkey(); - // select_tab(MainFrame::tpMonitor); - m_printer_view->load_url(url, key); - }); - } - m_printer_view->Show(false); - m_tabpanel->InsertPage(m_tabpanel->PositionAfter({TAB_ID_PREVIEW}), TAB_ID_MONITOR, m_printer_view, + m_printer_view_page->Show(false); + m_tabpanel->InsertPage(m_tabpanel->PositionAfter({TAB_ID_PREVIEW}), TAB_ID_MONITOR, m_printer_view_page, _L("Device"), "tab_monitor_active"); } fit_tab_labels(); // ORCA on printer change m_plugin_pages.relayout(); // re-sync plugin tabs against the native tabs just mutated above + if (m_prebuild_started) + m_idle.start(); } bool MainFrame::is_prepare_or_preview_tab() const @@ -2692,13 +2644,11 @@ void MainFrame::on_dpi_changed(const wxRect& suggested_rect) //BBS GUI refactor: remove unused layout new/dlg //if (m_layout != ESettingsLayout::Dlg) // Do not update tabs if the Settings are in the separated dialog m_param_panel->msw_rescale(); - m_project->msw_rescale(); - if(m_monitor) - m_monitor->msw_rescale(); - if(m_multi_machine) - m_multi_machine->msw_rescale(); - if(m_calibration) - m_calibration->msw_rescale(); + // A panel mid-build gets the pass once it is complete. + ProjectPanel::when_built([](ProjectPanel& project) { project.msw_rescale(); }); + MonitorPanel::when_built([](MonitorPanel& monitor) { monitor.msw_rescale(); }); + MultiMachinePage::when_built([](MultiMachinePage& multi_machine) { multi_machine.msw_rescale(); }); + CalibrationPanel::when_built([](CalibrationPanel& calibration) { calibration.msw_rescale(); }); // BBS #if 0 @@ -2752,7 +2702,8 @@ void MainFrame::on_sys_color_changed() #endif #endif - diff_dialog.on_sys_color_changed(); + if (DiffPresetDialog* dialog = DiffPresetDialog::if_built()) + dialog->on_sys_color_changed(); // BBS m_tabpanel->Rescale(); @@ -2760,10 +2711,8 @@ void MainFrame::on_sys_color_changed() // update Plater wxGetApp().plater()->sys_color_changed(); - if(m_monitor) - m_monitor->on_sys_color_changed(); - if(m_calibration) - m_calibration->on_sys_color_changed(); + MonitorPanel::when_built([](MonitorPanel& monitor) { monitor.on_sys_color_changed(); }); + CalibrationPanel::when_built([](CalibrationPanel& calibration) { calibration.on_sys_color_changed(); }); // update Tabs for (auto tab : wxGetApp().tabs_list) tab->sys_color_changed(); @@ -3696,7 +3645,8 @@ void MainFrame::set_max_recent_count(int max) } wxGetApp().app_config->set_recent_projects(recent_projects); wxGetApp().app_config->save(); - m_webview->SendRecentList(-1); + if (WebViewPanel* home = WebViewPanel::if_built()) + home->SendRecentList(-1); } } @@ -4040,23 +3990,56 @@ void MainFrame::select_tab(wxPanel* panel) select_tab(page_name); } +// Selects the Prepare page without the page-changed event, so the GL canvas is on screen +// and nothing else is built for the pass. +void MainFrame::select_prepare_for_gl_init() +{ + m_tabpanel->ChangeSelection(m_tabpanel->FindPageByName(TAB_ID_PREPARE)); +} + +// The book shows its first page as it is inserted, while the frame is hidden and nothing +// may build; the first show completes that page. +bool MainFrame::Show(bool show) +{ + const bool changed = DPIFrame::Show(show); + if (show && changed && m_tabpanel != nullptr) + if (wxWindow* page = m_tabpanel->GetCurrentPage()) + page->Show(true); + return changed; +} + +// A page out of the book stays registered and is passed over; a negative order is never +// registered. +void MainFrame::prebuild_pages_when_idle() +{ + m_idle.clear(); + if (m_param_panel) + m_idle.add(m_param_panel->settings_page_prebuild()); + for (LazyBase* page : m_lazy_pages) + if (page->prebuild_order() >= 0) + m_idle.add(*page); + m_idle.add(m_diff_dialog); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": prebuild queue: " << m_idle.names(); + m_idle.start(); + m_prebuild_started = true; +} + //BBS void MainFrame::jump_to_monitor(std::string dev_id) { - if(!m_monitor) - return; m_tabpanel->SelectPageByName(TAB_ID_MONITOR); if (!dev_id.empty()) { - ((MonitorPanel*)m_monitor)->select_machine(dev_id); + MonitorPanel::ensure()->select_machine(dev_id); } } void MainFrame::jump_to_multipage() { - if(!m_multi_machine) + if (!m_multi_machine_page->in_book()) return; m_tabpanel->SelectPageByName(TAB_ID_MULTI_DEVICE); - ((MultiMachinePage*)m_multi_machine)->jump_to_send_page(); + if (MultiMachinePage* page = m_multi_machine_page->ensure()) + page->jump_to_send_page(); } @@ -4105,8 +4088,8 @@ void MainFrame::request_select_tab(const wxString& id) } int MainFrame::get_calibration_curr_tab() { - if (m_calibration) - return m_calibration->get_tabpanel()->GetSelection(); + if (CalibrationPanel* calibration = CalibrationPanel::if_built()) + return calibration->get_tabpanel()->GetSelection(); return -1; } @@ -4215,7 +4198,8 @@ void MainFrame::add_to_recent_projects(const wxString& filename) recent_projects.push_back(into_u8(m_recent_projects.GetHistoryFile(i))); } wxGetApp().app_config->set_recent_projects(recent_projects); - m_webview->SendRecentList(0); + if (WebViewPanel* home = WebViewPanel::if_built()) + home->SendRecentList(0); } } @@ -4331,7 +4315,8 @@ void MainFrame::open_recent_project(size_t file_id, wxString const & filename) recent_projects.push_back(into_u8(m_recent_projects.GetHistoryFile(i))); } wxGetApp().app_config->set_recent_projects(recent_projects); - m_webview->SendRecentList(-1); + if (WebViewPanel* home = WebViewPanel::if_built()) + home->SendRecentList(-1); } } } @@ -4354,7 +4339,8 @@ void MainFrame::remove_recent_project(size_t file_id, wxString const &filename) recent_projects.push_back(into_u8(m_recent_projects.GetHistoryFile(i))); } wxGetApp().app_config->set_recent_projects(recent_projects); - m_webview->SendRecentList(-1); + if (WebViewPanel* home = WebViewPanel::if_built()) + home->SendRecentList(-1); } void MainFrame::load_url(wxString url) @@ -4408,14 +4394,14 @@ bool MainFrame::is_printer_view() const { return m_tabpanel->GetSelectedPageName void MainFrame::refresh_plugin_tips() { - if (m_webview != nullptr) - m_webview->ShowNetpluginTip(); + if (WebViewPanel* home = WebViewPanel::if_built()) + home->ShowNetpluginTip(); } void MainFrame::RunScript(wxString js) { - if (m_webview != nullptr) - m_webview->RunScript(js); + if (WebViewPanel* home = WebViewPanel::if_built()) + home->RunScript(js); } void MainFrame::technology_changed() @@ -4524,7 +4510,8 @@ void MainFrame::update_side_preset_ui() //take off multi machine - if(m_multi_machine){m_multi_machine->clear_page();} + if (MultiMachinePage* multi_machine = MultiMachinePage::if_built()) + multi_machine->clear_page(); } void MainFrame::on_select_default_preset(SimpleEvent& evt) diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 66f3b31263..f580de57e0 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -26,6 +26,8 @@ #include "Widgets/SideButton.hpp" #include "Widgets/SideMenuPopup.hpp" #include "FilamentGroupPopup.hpp" +#include "LazyPage.hpp" +#include "IdleScheduler.hpp" #include @@ -136,6 +138,13 @@ class MainFrame : public DPIFrame #endif bool m_loaded {false}; wxTimer* m_reset_title_text_colour_timer{ nullptr }; + IdleScheduler m_idle; + bool m_prebuild_started{ false }; + // Every LazyPage, in and out of the book; prebuild_pages_when_idle() registers them. + std::vector m_lazy_pages; + // The latest EVT_LOAD_PRINTER_URL, applied when the web Device view is built. + wxString m_printer_url; + wxString m_printer_api_key; wxString m_qs_last_input_file = wxEmptyString; wxString m_qs_last_output_file = wxEmptyString; @@ -180,7 +189,7 @@ class MainFrame : public DPIFrame bool can_delete() const; bool can_delete_all() const; bool can_reslice() const; - void bind_diff_dialog(); + DiffPresetDialog* make_diff_dialog(); // BBS wxBoxSizer* create_side_tools(); @@ -377,6 +386,12 @@ public: void select_tab(wxPanel* panel); void select_tab(const wxString& id = wxString()); void request_select_tab(const wxString& id); + // post_init() needs the plater's canvas on screen to initialize OpenGL; this pass does not + // build the settings page. + void select_prepare_for_gl_init(); + // Builds the lazy tab pages while the user is idle; post_init() calls it once. + void prebuild_pages_when_idle(); + bool Show(bool show = true) override; int get_calibration_curr_tab(); void select_view(const std::string& direction); void update_shortcut_labels(); @@ -435,27 +450,21 @@ public: BBLTopbar* m_topbar{ nullptr }; PrintHostQueueDialog* printhost_queue_dlg() { return m_printhost_queue_dlg; } Plater* m_plater { nullptr }; + // Lazy pages, created once and kept for the frame's life; their panels are reached + // through LazyInstance's statics, and show_device() only moves pages in and out of the book. #ifdef SLIC3R_CAD - // The tab page is the placeholder; m_design_panel stays null until the tab is first - // selected, so everything the Design panel builds stays off the startup path. - wxPanel* m_design_page { nullptr }; - DesignPanel* m_design_panel { nullptr }; - // Builds the Design panel if it does not exist yet and returns it (null only before the - // placeholder page itself exists). Main thread only -- it creates wx controls. Both the - // tab activation and the MCP socket go through this: the socket is driven headlessly, - // with nobody to click the tab, and without this every verb would answer "not ready". - DesignPanel* ensure_design_panel(); + LazyPage* m_design_page { nullptr }; #endif //BBS: GUI refactor - MonitorPanel* m_monitor{ nullptr }; + LazyPage* m_monitor_page{ nullptr }; //AuxiliaryPanel* m_auxiliary{ nullptr }; - MultiMachinePage* m_multi_machine{ nullptr }; - ProjectPanel* m_project{ nullptr }; + LazyPage* m_multi_machine_page{ nullptr }; + LazyPage* m_project_page{ nullptr }; - CalibrationPanel* m_calibration{ nullptr }; - WebViewPanel* m_webview { nullptr }; - PrinterWebView* m_printer_view{nullptr}; + LazyPage* m_calibration_page{ nullptr }; + LazyPage* m_home_page { nullptr }; + LazyPage* m_printer_view_page{nullptr}; PluginPages m_plugin_pages; wxLogWindow* m_log_window { nullptr }; // BBS @@ -466,7 +475,8 @@ public: ParamsDialog* m_param_dialog{ nullptr }; //BBS SettingsDialog m_settings_dialog; - DiffPresetDialog diff_dialog; + // The Compare presets dialog, built on first use or at idle through its holder. + Lazy m_diff_dialog; wxWindow* m_plater_page{ nullptr }; PrintHostQueueDialog* m_printhost_queue_dlg; diff --git a/src/slic3r/GUI/Monitor.cpp b/src/slic3r/GUI/Monitor.cpp index 1a6d969988..7352ee3dd7 100644 --- a/src/slic3r/GUI/Monitor.cpp +++ b/src/slic3r/GUI/Monitor.cpp @@ -103,6 +103,7 @@ MonitorPanel::MonitorPanel(wxWindow* parent, wxWindowID id, const wxPoint& pos, : wxPanel(parent, id, pos, size, style), m_select_machine(SelectMachinePopup(this)) { + SetBackgroundColour(*wxWHITE); #ifdef __WINDOWS__ SetDoubleBuffered(true); #endif //__WINDOWS__ @@ -180,31 +181,36 @@ void MonitorPanel::init_tabpanel() auto title = m_tabpanel->GetPageText(m_tabpanel->GetSelection()); m_media_file_panel->SwitchStorage(title == _L("Storage")); } - page->SetFocus(); + // The first page is selected while the panel is built off screen. + if (page->IsShownOnScreen()) + page->SetFocus(); update_all(); }, m_tabpanel->GetId()); - //m_status_add_machine_panel = new AddMachinePanel(m_tabpanel); - m_status_info_panel = new StatusPanel(m_tabpanel); + m_status_info_panel = new StatusPanel(m_tabpanel); + // Queued before the page is added, since adding it selects it and runs the handler above, + // where built() must already be false. + add_build_steps_of(*m_status_info_panel); m_tabpanel->AddPage(m_status_info_panel, _L("Status"), true); + add_build_step([this] { + m_media_file_panel = new MediaFilePanel(m_tabpanel); + m_tabpanel->AddPage(m_media_file_panel, _L("Storage"), false); + }); + add_build_step([this] { + m_upgrade_panel = new UpgradePanel(m_tabpanel); + m_tabpanel->AddPage(m_upgrade_panel, _L_CONTEXT(L_CONTEXT("Update", "Firmware"), "Firmware"), false); + }); + add_build_step([this] { + m_hms_panel = new HMSPanel(m_tabpanel); + m_tabpanel->AddPage(m_hms_panel, _L("Assistant(HMS)"), false); - m_media_file_panel = new MediaFilePanel(m_tabpanel); - m_tabpanel->AddPage(m_media_file_panel, _L("Storage"), false); - //m_tabpanel->AddPage(m_media_file_panel, _L("Internal Storage"), false); + std::string network_ver = Slic3r::NetworkAgent::get_version(); + if (!network_ver.empty()) { + m_tabpanel->SetFooterText(wxString::Format(_L("Network plug-in v%s"), network_ver)); + } - m_upgrade_panel = new UpgradePanel(m_tabpanel); - m_tabpanel->AddPage(m_upgrade_panel, _L_CONTEXT(L_CONTEXT("Update", "Firmware"), "Firmware"), false); - - m_hms_panel = new HMSPanel(m_tabpanel); - m_tabpanel->AddPage(m_hms_panel, _L("Assistant(HMS)"), false); - - std::string network_ver = Slic3r::NetworkAgent::get_version(); - if (!network_ver.empty()) { - m_tabpanel->SetFooterText(wxString::Format(_L("Network plug-in v%s"), network_ver)); - } - - m_initialized = true; - show_status((int)MonitorStatus::MONITOR_NO_PRINTER); + show_status((int)MonitorStatus::MONITOR_NO_PRINTER); + }); } void MonitorPanel::set_default() @@ -288,19 +294,23 @@ void MonitorPanel::on_select_printer(wxCommandEvent& event) set_default(); update_all(); - MachineObject *obj_ = dev->get_selected_machine(); - if (obj_) { - obj_->last_cali_version = -1; - obj_->reset_pa_cali_history_result(); - obj_->reset_pa_cali_result(); - Sidebar &sidebar = GUI::wxGetApp().sidebar(); - sidebar.update_sync_status(obj_); - sidebar.set_need_auto_sync_after_connect_printer(sidebar.need_auto_sync_extruder_list_after_connect_priner(obj_)); - } + on_machine_selected(dev->get_selected_machine()); Layout(); } +void MonitorPanel::on_machine_selected(MachineObject* obj) +{ + if (obj == nullptr) + return; + obj->last_cali_version = -1; + obj->reset_pa_cali_history_result(); + obj->reset_pa_cali_result(); + Sidebar& sidebar = GUI::wxGetApp().sidebar(); + sidebar.update_sync_status(obj); + sidebar.set_need_auto_sync_after_connect_printer(sidebar.need_auto_sync_extruder_list_after_connect_priner(obj)); +} + void MonitorPanel::on_printer_clicked(wxMouseEvent &event) { auto mouse_pos = ClientToScreen(event.GetPosition()); @@ -331,7 +341,8 @@ void MonitorPanel::on_size(wxSizeEvent &event) void MonitorPanel::update_all() { - if (!m_initialized) + // Every page exists once the last build step has run. + if (!built()) return; NetworkAgent* m_agent = wxGetApp().getAgent(); @@ -412,16 +423,12 @@ void MonitorPanel::update_hms_tag() bool MonitorPanel::Show(bool show) { -#ifdef __APPLE__ - // Notebook::InsertPage() hides every page it appends, so this also runs while MainFrame is - // still constructing, before GUI_App::mainframe is assigned. Same guard as Plater::Show(). - if (wxGetApp().mainframe) - wxGetApp().mainframe->SetMinSize(wxGetApp().plater()->GetMinSize()); -#endif - NetworkAgent* m_agent = wxGetApp().getAgent(); DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); if (show) { +#ifdef __APPLE__ + wxGetApp().mainframe->SetMinSize(wxGetApp().plater()->GetMinSize()); +#endif start_update(); update_network_version_footer(); @@ -448,7 +455,7 @@ bool MonitorPanel::Show(bool show) void MonitorPanel::show_status(int status) { - if (!m_initialized) return; + if (!built()) return; if (last_status == status)return; if ((last_status & (int)MonitorStatus::MONITOR_CONNECTING) != 0) { NetworkAgent* agent = wxGetApp().getAgent(); diff --git a/src/slic3r/GUI/Monitor.hpp b/src/slic3r/GUI/Monitor.hpp index 9252b04559..94474f73b0 100644 --- a/src/slic3r/GUI/Monitor.hpp +++ b/src/slic3r/GUI/Monitor.hpp @@ -49,6 +49,7 @@ #include "slic3r/GUI/AmsWidgets.hpp" #include "Widgets/SideTools.hpp" #include "SelectMachinePop.hpp" +#include "Lazy.hpp" namespace Slic3r { namespace GUI { @@ -72,16 +73,16 @@ public: void msw_rescale(); }; -class MonitorPanel : public wxPanel +class MonitorPanel : public wxPanel, public StagedBuild, public LazyInstance { private: Tabbook* m_tabpanel{ nullptr }; wxSizer* m_main_sizer{ nullptr }; - StatusPanel* m_status_info_panel; - MediaFilePanel* m_media_file_panel; - UpgradePanel* m_upgrade_panel; - HMSPanel* m_hms_panel; + StatusPanel* m_status_info_panel{ nullptr }; + MediaFilePanel* m_media_file_panel{ nullptr }; + UpgradePanel* m_upgrade_panel{ nullptr }; + HMSPanel* m_hms_panel{ nullptr }; /* side tools */ SideTools* m_side_tools{nullptr}; @@ -96,7 +97,6 @@ private: wxBitmap m_arrow_img; int last_status; - bool m_initialized { false }; bool update_flag{false}; wxTimer* m_refresh_timer = nullptr; @@ -125,6 +125,8 @@ public: StatusPanel* get_status_panel() {return m_status_info_panel;}; void select_machine(std::string machine_sn); + // Resets the selected printer's calibration results and syncs the sidebar, without the Device tab. + static void on_machine_selected(MachineObject* obj); void on_timer(wxTimerEvent& event); void on_select_printer(wxCommandEvent& event); void on_printer_clicked(wxMouseEvent &event); diff --git a/src/slic3r/GUI/MultiMachineManagerPage.cpp b/src/slic3r/GUI/MultiMachineManagerPage.cpp index 792c23fb13..d5f9cbce8a 100644 --- a/src/slic3r/GUI/MultiMachineManagerPage.cpp +++ b/src/slic3r/GUI/MultiMachineManagerPage.cpp @@ -21,8 +21,9 @@ MultiMachineItem::MultiMachineItem(wxWindow* parent, MachineObject* obj) Bind(wxEVT_MOTION, &MultiMachineItem::OnMove, this); Bind(EVT_MULTI_DEVICE_VIEW, [obj](auto& e) { wxGetApp().mainframe->jump_to_monitor(obj->get_dev_id()); - if (wxGetApp().mainframe->m_monitor->get_status_panel()->get_media_play_ctrl()) { - wxGetApp().mainframe->m_monitor->get_status_panel()->get_media_play_ctrl()->jump_to_play(); + MonitorPanel* monitor = MonitorPanel::if_built(); + if (monitor && monitor->get_status_panel()->get_media_play_ctrl()) { + monitor->get_status_panel()->get_media_play_ctrl()->jump_to_play(); } }); wxGetApp().UpdateDarkUIWin(this); diff --git a/src/slic3r/GUI/MultiMachinePage.cpp b/src/slic3r/GUI/MultiMachinePage.cpp index dd67e099a0..e48e402405 100644 --- a/src/slic3r/GUI/MultiMachinePage.cpp +++ b/src/slic3r/GUI/MultiMachinePage.cpp @@ -11,6 +11,7 @@ namespace GUI { MultiMachinePage::MultiMachinePage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : wxPanel(parent, id, pos, size, style) { + SetBackgroundColour(*wxWHITE); init_tabpanel(); m_main_sizer = new wxBoxSizer(wxHORIZONTAL); m_main_sizer->Add(m_tabpanel, 1, wxEXPAND | wxLEFT, 0); diff --git a/src/slic3r/GUI/MultiMachinePage.hpp b/src/slic3r/GUI/MultiMachinePage.hpp index 724eeed2a9..14d531e8ab 100644 --- a/src/slic3r/GUI/MultiMachinePage.hpp +++ b/src/slic3r/GUI/MultiMachinePage.hpp @@ -7,6 +7,7 @@ #include "MultiTaskManagerPage.hpp" #include "MultiMachineManagerPage.hpp" #include "Tabbook.hpp" +#include "Lazy.hpp" #include "wx/button.h" @@ -19,7 +20,7 @@ namespace GUI { #define PICK_LEFT_DEV_STATUS 250 #define PICK_DEVICE_MAX 6 -class MultiMachinePage : public wxPanel +class MultiMachinePage : public wxPanel, public LazyInstance { private: wxTimer* m_refresh_timer = nullptr; diff --git a/src/slic3r/GUI/ParamsPanel.cpp b/src/slic3r/GUI/ParamsPanel.cpp index 5a49df1280..b4fd81706a 100644 --- a/src/slic3r/GUI/ParamsPanel.cpp +++ b/src/slic3r/GUI/ParamsPanel.cpp @@ -290,7 +290,7 @@ ParamsPanel::ParamsPanel( wxWindow* parent, wxWindowID id, const wxPoint& pos, c m_compare_btn = new ScalableButton(m_top_panel, wxID_ANY, "compare", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true); m_compare_btn->SetToolTip(_L("Compare presets")); - m_compare_btn->Bind(wxEVT_BUTTON, ([](wxCommandEvent e) { wxGetApp().mainframe->diff_dialog.show(); })); + m_compare_btn->Bind(wxEVT_BUTTON, ([](wxCommandEvent e) { DiffPresetDialog::ensure()->show(); })); m_setting_btn = new ScalableButton(m_top_panel, wxID_ANY, "table", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true); m_setting_btn->SetToolTip(_L("View all object's settings")); @@ -550,18 +550,36 @@ void ParamsPanel::clear_page() void ParamsPanel::OnActivate() { if (m_current_tab == NULL) - { - //the first time - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": first time opened, set current tab to print"); - // BBS: open/close tab - //m_current_tab = m_tab_print; - set_active_tab(m_tab_print ? m_tab_print : m_tab_filament); - } + select_default_tab(); Tab* cur_tab = dynamic_cast (m_current_tab); if (cur_tab) cur_tab->OnActivate(); } +void ParamsPanel::select_default_tab() +{ + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": first time opened, set current tab to print"); + // BBS: open/close tab + //m_current_tab = m_tab_print; + set_active_tab(m_tab_print ? m_tab_print : m_tab_filament); +} + +bool ParamsPanel::SettingsPagePrebuild::built() const +{ + Tab* tab = dynamic_cast(m_panel.m_current_tab); + return tab != nullptr && !tab->page_build_pending(); +} + +bool ParamsPanel::SettingsPagePrebuild::build_step() +{ + if (m_panel.m_current_tab == nullptr) { + m_panel.select_default_tab(); + return !built(); + } + Tab* tab = dynamic_cast(m_panel.m_current_tab); + return tab != nullptr && tab->page_build_step(); +} + void ParamsPanel::OnToggled(wxCommandEvent& event) { if (m_mode_region && m_mode_region->GetId() == event.GetId()) { diff --git a/src/slic3r/GUI/ParamsPanel.hpp b/src/slic3r/GUI/ParamsPanel.hpp index 91bf3d2a7e..9f9264b480 100644 --- a/src/slic3r/GUI/ParamsPanel.hpp +++ b/src/slic3r/GUI/ParamsPanel.hpp @@ -30,6 +30,7 @@ #include "wxExtensions.hpp" #include "GUI_Utils.hpp" #include "Widgets/Button.hpp" +#include "Lazy.hpp" class ModeSwitchButton; class SwitchButton; @@ -121,6 +122,22 @@ class ParamsPanel : public wxPanel wxPanel* m_current_tab { nullptr }; + // Builds the selected page's option groups at idle; while no tab is selected yet, + // its first unit selects the default one. + class SettingsPagePrebuild : public LazyBase + { + public: + explicit SettingsPagePrebuild(ParamsPanel& panel) : m_panel(panel) {} + const std::string& name() const override { return m_name; } + bool built() const override; + bool build_step() override; + int prebuild_order() const override { return 0; } + + private: + ParamsPanel& m_panel; + std::string m_name{ "settings_page" }; + } m_settings_page_prebuild{ *this }; + bool m_has_object_config { false }; struct Highlighter @@ -149,6 +166,10 @@ class ParamsPanel : public wxPanel //clear the right page void clear_page(); void OnActivate(); + // The print tab, or the filament tab without one. + void select_default_tab(); + // The settings page's prebuild task. + LazyBase& settings_page_prebuild() { return m_settings_page_prebuild; } void set_active_tab(wxPanel*tab); bool is_active_and_shown_tab(wxPanel*tab); void update_mode(); diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 3493506228..e90b21e0ff 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -3555,8 +3555,11 @@ void PartPlate::render(const Transform3d& view_matrix, const Transform3d& projec shader->stop_using(); } - if (wxGetApp().show_plate_gridlines() && show_grid) + if (wxGetApp().show_plate_gridlines() && show_grid) { + glsafe(::glDepthMask(bottom ? GL_TRUE : GL_FALSE)); render_grid(bottom); + glsafe(::glDepthMask(GL_TRUE)); + } if (!hide_chrome && !bottom && m_selected && !force_background_color) { if (m_partplate_list) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index d4386fbe93..5eb36f20f9 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -7033,7 +7033,7 @@ struct Plater::priv void remove(size_t obj_idx); bool delete_object_from_model(size_t obj_idx, bool refresh_immediately = true); //BBS void delete_all_objects_from_model(); - void reset(bool apply_presets_change = false); + void reset(bool apply_presets_change = false, bool reload_presets = true); void center_selection(); void drop_selection(); void mirror(Axis axis); @@ -7891,7 +7891,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) if (this->q->get_project_filename().IsEmpty() && this->q->is_empty_project()) { int skip_confirm = e.GetInt(); - this->q->new_project(skip_confirm, true); + // Skips the preset reload; trigger_restore_project()'s callers load the presets first. + this->q->new_project(skip_confirm, true, wxString(), false); } }); //wxPostEvent(this->q, wxCommandEvent{EVT_RESTORE_PROJECT}); @@ -10356,7 +10357,7 @@ void Plater::priv::delete_all_objects_from_model() model.plates_custom_gcodes.clear(); } -void Plater::priv::reset(bool apply_presets_change) +void Plater::priv::reset(bool apply_presets_change, bool reload_presets) { // TakeSnapshot below and load_current_presets() further down each re-evaluate the // aggregate dirty flag against a baseline that hasn't been reset yet, so they can toggle @@ -10411,8 +10412,8 @@ void Plater::priv::reset(bool apply_presets_change) // Same reason, one level up: the Design tab keeps the editable document, not the Model, so // clearing the recipe alone leaves the tab showing the previous project's feature tree — // and its next edit syncs that tree straight back into the new project. - if (wxGetApp().mainframe != nullptr && wxGetApp().mainframe->m_design_panel != nullptr) - wxGetApp().mainframe->m_design_panel->clear_document(); + if (DesignPanel* design = DesignPanel::if_built()) + design->clear_document(); #endif assemble_view->get_canvas3d()->reset_explosion_ratio(); update(); @@ -10431,7 +10432,7 @@ void Plater::priv::reset(bool apply_presets_change) wxGetApp().preset_bundle->reset_project_embedded_presets(); if (apply_presets_change) wxGetApp().apply_keeped_preset_modifications(); - else + else if (reload_presets) wxGetApp().load_current_presets(false, false); //BBS @@ -13183,17 +13184,17 @@ void Plater::priv::on_tab_selection_changing(wxBookCtrlEvent& e) // Pointer test, not a name lookup: in printer-agents mode this page is TAB_ID_MONITOR_WEB // while the native Device tab holds TAB_ID_MONITOR, and in legacy-web mode it holds // TAB_ID_MONITOR itself. - const bool selecting_web_device_tab = main_frame->m_printer_view && - main_frame->m_tabpanel->GetPage(new_sel) == main_frame->m_printer_view; + const bool selecting_web_device_tab = main_frame->m_printer_view_page && + main_frame->m_tabpanel->GetPage(new_sel) == main_frame->m_printer_view_page; if (selecting_web_device_tab) { // Use the selected discovered machine when the preset has no host. main_frame->load_printer_url(); } else if (new_name == TAB_ID_MONITOR && wxGetApp().preset_bundle != nullptr) { auto cfg = wxGetApp().preset_bundle->printers.get_edited_preset().config; wxString url = from_u8(PrintHost::get_print_host_webui(&cfg)); - if (main_frame->m_printer_view && url.empty()) { + if (PrinterWebView* view = PrinterWebView::if_built(); view != nullptr && url.empty()) { // It's missing_connection page, reload so that we can replay the gif image - main_frame->m_printer_view->reload(); + view->reload(); } } } @@ -13924,8 +13925,8 @@ void Plater::priv::unbind_canvas_event_handlers() // The Design tab's viewport is a fourth GLCanvas3D on the same shared GL context, owned by // MainFrame rather than by us — same reach as reset() uses for clear_document(). Null until // the tab has been opened once, so most sessions skip it. - if (wxGetApp().mainframe != nullptr && wxGetApp().mainframe->m_design_panel != nullptr) - wxGetApp().mainframe->m_design_panel->unbind_canvas_event_handlers(); + if (DesignPanel* design = DesignPanel::if_built()) + design->unbind_canvas_event_handlers(); #endif } @@ -13938,8 +13939,8 @@ void Plater::priv::reset_canvas_volumes() preview->get_canvas3d()->reset_volumes(); #ifdef SLIC3R_CAD - if (wxGetApp().mainframe != nullptr && wxGetApp().mainframe->m_design_panel != nullptr) - wxGetApp().mainframe->m_design_panel->reset_canvas_volumes(); + if (DesignPanel* design = DesignPanel::if_built()) + design->reset_canvas_volumes(); #endif } @@ -15351,7 +15352,7 @@ Print& Plater::fff_print() { return p->fff_print; } const SLAPrint& Plater::sla_print() const { return p->sla_print; } SLAPrint& Plater::sla_print() { return p->sla_print; } -int Plater::new_project(bool skip_confirm, bool silent, const wxString& project_name) +int Plater::new_project(bool skip_confirm, bool silent, const wxString& project_name, bool reload_presets) { model().calib_pa_pattern.reset(nullptr); model().plates_custom_gcodes.clear(); @@ -15399,7 +15400,7 @@ int Plater::new_project(bool skip_confirm, bool silent, const wxString& project_ // completes, so hold notifications until then to avoid firing on transient flips. ProjectDirtyStateManager::NotificationSuppressor dirty_notify_suppressor(p->dirty_state); - reset(transfer_preset_changes); + reset(transfer_preset_changes, reload_presets); reset_project_dirty_after_save(); reset_project_dirty_initial_presets(); wxGetApp().update_saved_preset_from_current_preset(); @@ -17984,7 +17985,7 @@ void Plater::deselect_all() { p->deselect_all(); } void Plater::exit_gizmo() { p->exit_gizmo(); } void Plater::remove(size_t obj_idx) { p->remove(obj_idx); } -void Plater::reset(bool apply_presets_change) { p->reset(apply_presets_change); } +void Plater::reset(bool apply_presets_change, bool reload_presets) { p->reset(apply_presets_change, reload_presets); } void Plater::reset_with_confirm() { if (p->model.objects.empty() || MessageDialog(static_cast(this), _L("All objects will be removed, continue?"), @@ -20001,7 +20002,7 @@ int Plater::export_config_3mf(int plate_idx, Export3mfProgressFn proFn) void Plater::send_calibration_job_finished(wxCommandEvent & evt) { p->main_frame->request_select_tab(TAB_ID_CALIBRATION); - auto calibration_panel = p->main_frame->m_calibration; + CalibrationPanel* calibration_panel = CalibrationPanel::ensure(); if (calibration_panel) { auto curr_wizard = static_cast(calibration_panel->get_tabpanel()->GetPage(evt.GetInt())); wxCommandEvent event(EVT_CALIBRATION_JOB_FINISHED); @@ -20033,8 +20034,8 @@ void Plater::print_job_finished(wxCommandEvent &evt) dev->set_selected_machine(evt.GetString().ToStdString()); p->main_frame->request_select_tab(TAB_ID_MONITOR); - //jump to monitor and select device status panel - MonitorPanel* curr_monitor = p->main_frame->m_monitor; + // Selects the status page on a built Device tab; one built by the switch starts there. + MonitorPanel* curr_monitor = MonitorPanel::if_built(); if(curr_monitor) curr_monitor->get_tabpanel()->ChangeSelection(MonitorPanel::PrinterTab::PT_STATUS); } @@ -20774,8 +20775,8 @@ void Plater::update_print_error_info(int code, std::string msg, std::string extr if (p->m_send_to_sdcard_dlg) { p->m_send_to_sdcard_dlg->update_print_error_info(code, msg, extra); } - if (p->main_frame->m_calibration) - p->main_frame->m_calibration->update_print_error_info(code, msg, extra); + if (CalibrationPanel* calibration = CalibrationPanel::if_built()) + calibration->update_print_error_info(code, msg, extra); } wxString Plater::get_project_filename(const wxString& extension) const @@ -21068,7 +21069,8 @@ void Plater::pop_warning_and_go_to_device_page(wxString printer_name, PrinterWar { printer_name.Replace("Bambu Lab", "", false); wxString content; - bool device_page = (wxGetApp().mainframe == nullptr) && (wxGetApp().mainframe->m_monitor->IsShown()); + MainFrame* frame = wxGetApp().mainframe; + bool device_page = frame != nullptr && frame->m_monitor_page->in_book(); if (type == PrinterWarningType::NOT_CONNECTED) { if (device_page) { content = wxString::Format(_L("Printer not connected. Please go to the device page to connect %s before syncing."), diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index b30f0298ee..90d0e5e673 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -339,7 +339,7 @@ public: // Helper: returns config indices where filament_is_mixed == false std::vector physical_filament_config_indices() const; - int new_project(bool skip_confirm = false, bool silent = false, const wxString& project_name = wxString()); + int new_project(bool skip_confirm = false, bool silent = false, const wxString& project_name = wxString(), bool reload_presets = true); // BBS: save & backup void load_project(wxString const & filename = "", wxString const & originfile = "-"); int save_project(bool saveAs = false); @@ -499,7 +499,7 @@ public: void deselect_all(); void exit_gizmo(); void remove(size_t obj_idx); - void reset(bool apply_presets_change = false); + void reset(bool apply_presets_change = false, bool reload_presets = true); void reset_with_confirm(); //BBS: return int for various result int close_with_confirm(std::function second_check = nullptr); // BBS close project diff --git a/src/slic3r/GUI/PrebuildQueue.hpp b/src/slic3r/GUI/PrebuildQueue.hpp new file mode 100644 index 0000000000..c013f53865 --- /dev/null +++ b/src/slic3r/GUI/PrebuildQueue.hpp @@ -0,0 +1,89 @@ +#pragma once + +#include +#include +#include +#include + +#include "Lazy.hpp" + +namespace Slic3r { namespace GUI { + +// Holders to build at idle, ordered by prebuild_order(), run one slice at a time. The +// holders outlive the queue. Main thread only. +class PrebuildQueue +{ +public: + struct Slice + { + std::string name; // the task that ran; empty when nothing was pending + int units{ 0 }; // units run + long long ms{ 0 }; // time spent + bool completed{ false }; // the task has no more units + bool remaining{ false }; // some task is still pending + }; + + // Lower order runs first, equal order in the order added. + void add(LazyBase& task) + { + auto after = std::find_if(m_tasks.begin(), m_tasks.end(), [&](const LazyBase* t) { return t->prebuild_order() > task.prebuild_order(); }); + m_tasks.insert(after, &task); + } + + void clear() { m_tasks.clear(); } + + bool pending() const + { + return std::any_of(m_tasks.begin(), m_tasks.end(), [](const LazyBase* t) { return t->pending(); }); + } + + // The task names in queue order, comma separated. + std::string names() const + { + std::string out; + for (const LazyBase* t : m_tasks) + out += (out.empty() ? "" : ", ") + t->name(); + return out; + } + + // Runs units of the first pending task until it completes, budget_ms of now_ms() have + // passed, or interrupt() is true after a unit; on_unit gets the task name and each + // unit's duration. A task with no work is passed over and stays in the queue, so one + // whose work returns is pending again. + Slice run_slice(int budget_ms, + const std::function& now_ms, + const std::function& interrupt, + const std::function& on_unit = {}) + { + Slice slice; + auto next = std::find_if(m_tasks.begin(), m_tasks.end(), [](const LazyBase* t) { return t->pending(); }); + if (next == m_tasks.end()) + return slice; + // The pointer is copied out, since a unit may add tasks and reallocate m_tasks. + LazyBase* const task = *next; + slice.name = task->name(); + const long long started = now_ms(); + for (;;) { + const long long unit_started = now_ms(); + const bool more = task->build_step(); + const long long now = now_ms(); + ++slice.units; + if (on_unit) + on_unit(slice.name, now - unit_started); + slice.ms = now - started; + if (!more) { + slice.completed = true; + break; + } + if (slice.ms >= budget_ms || interrupt()) + break; + } + slice.remaining = pending(); + return slice; + } + +private: + std::vector m_tasks; +}; + +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 001866bfd9..fd5012b5ef 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -1044,8 +1044,8 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxString too if (m_bambu_cloud_checkbox) m_bambu_cloud_checkbox->Enable(!enabled); } else if (param == "hide_login_side_panel") { - if (wxGetApp().mainframe && wxGetApp().mainframe->m_webview) { - wxGetApp().mainframe->m_webview->SendCloudProvidersInfo(); + if (WebViewPanel* home = WebViewPanel::if_built()) { + home->SendCloudProvidersInfo(); } } // ORCA: apply the preview dimming change immediately to the currently loaded preview @@ -1254,9 +1254,8 @@ wxBoxSizer *PreferencesDialog::create_item_bambu_cloud(wxString title, wxString app_config->save(); // Update homepage visibility immediately - auto *mainframe = wxGetApp().mainframe; - if (mainframe && mainframe->m_webview) - mainframe->m_webview->SendCloudProvidersInfo(); + if (WebViewPanel* home = WebViewPanel::if_built()) + home->SendCloudProvidersInfo(); }); m_sizer->Add(cb, 0, wxALIGN_CENTER); diff --git a/src/slic3r/GUI/PrinterWebView.hpp b/src/slic3r/GUI/PrinterWebView.hpp index 8a62ce70a2..1ab1e17932 100644 --- a/src/slic3r/GUI/PrinterWebView.hpp +++ b/src/slic3r/GUI/PrinterWebView.hpp @@ -26,6 +26,7 @@ #include "wx/textctrl.h" #include #include +#include "Lazy.hpp" namespace Slic3r { @@ -34,7 +35,7 @@ namespace GUI { class PrinterWebViewHandler; -class PrinterWebView : public wxPanel { +class PrinterWebView : public wxPanel, public LazyInstance { public: PrinterWebView(wxWindow *parent); virtual ~PrinterWebView(); diff --git a/src/slic3r/GUI/Project.cpp b/src/slic3r/GUI/Project.cpp index 6d1eb0e180..8d87939afc 100644 --- a/src/slic3r/GUI/Project.cpp +++ b/src/slic3r/GUI/Project.cpp @@ -44,6 +44,7 @@ const std::vector license_list = { ProjectPanel::ProjectPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style) : wxPanel(parent, id, pos, size, style) { + SetBackgroundColour(*wxWHITE); m_project_home_url = wxString::Format("file://%s/web/model/index.html", from_u8(resources_dir())); wxString strlang = wxGetApp().current_language_code_safe(); if (strlang != "") @@ -67,6 +68,7 @@ ProjectPanel::ProjectPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, m_auxiliary = new AuxiliaryPanel(this); m_auxiliary->Hide(); main_sizer->Add(m_auxiliary, wxSizerFlags().Expand().Proportion(1)); + add_build_steps_of(*m_auxiliary); Bind(EVT_AUXILIARY_DONE, [this](wxCommandEvent& e) { update_model_data();}); SetSizer(main_sizer); diff --git a/src/slic3r/GUI/Project.hpp b/src/slic3r/GUI/Project.hpp index a590212cb7..a22bc44430 100644 --- a/src/slic3r/GUI/Project.hpp +++ b/src/slic3r/GUI/Project.hpp @@ -35,6 +35,7 @@ #include "libslic3r/ProjectTask.hpp" #include "wxExtensions.hpp" #include "Auxiliary.hpp" +#include "Lazy.hpp" #define AUFILE_GREY700 wxColour(107, 107, 107) #define AUFILE_GREY500 wxColour(158, 158, 158) @@ -59,7 +60,7 @@ struct project_file{ std::string size; }; -class ProjectPanel : public wxPanel +class ProjectPanel : public wxPanel, public StagedBuild, public LazyInstance { private: std::atomic m_web_init_completed{false}; @@ -90,7 +91,6 @@ public: void msw_rescale(); void update_model_data(); void clear_model_info(); - void init_auxiliary() { m_auxiliary->init_auxiliary(); } bool Show(bool show); void OnScriptMessage(wxWebViewEvent& evt); diff --git a/src/slic3r/GUI/SceneRaycaster.cpp b/src/slic3r/GUI/SceneRaycaster.cpp index 64a091211b..408e910ff8 100644 --- a/src/slic3r/GUI/SceneRaycaster.cpp +++ b/src/slic3r/GUI/SceneRaycaster.cpp @@ -99,8 +99,11 @@ void SceneRaycaster::remove_raycaster(std::shared_ptr item) } } -SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Camera& camera, const ClippingPlane* clipping_plane) const +SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Camera& camera, + const ClippingPlane* clipping_plane, SceneRaycaster::EHitMode mode) const { + // Orca: Picking may favor an already selected volume for interaction, while camera + // navigation must always use the geometrically closest visible scene surface. // helper class used to return currently selected volume as hit when overlapping with other volumes // to allow the user to click and drag on a selected volume class VolumeKeeper @@ -110,7 +113,11 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came bool m_selected_volume_already_found{ false }; public: - VolumeKeeper() { + explicit VolumeKeeper(bool enabled) { + // Orca: Disable selected-volume bias for navigation raycasts. + if (!enabled) + return; + const Selection& selection = wxGetApp().plater()->get_selection(); if (selection.is_single_volume() || selection.is_single_modifier()) { const GLVolume* volume = selection.get_first_volume(); @@ -135,7 +142,7 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came } }; - VolumeKeeper volume_keeper; + VolumeKeeper volume_keeper(mode == EHitMode::Picking); double closest_hit_squared_distance = std::numeric_limits::max(); auto is_closest = [&closest_hit_squared_distance, &volume_keeper](const Camera& camera, const Vec3f& hit) { @@ -154,7 +161,7 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came HitResult ret; - auto test_raycasters = [this, is_closest, clipping_plane, &volume_keeper](EType type, const Vec2d& mouse_pos, const Camera& camera, HitResult& ret) { + auto test_raycasters = [this, is_closest, clipping_plane, mode, &volume_keeper](EType type, const Vec2d& mouse_pos, const Camera& camera, HitResult& ret) { const ClippingPlane* clip_plane = (clipping_plane != nullptr && type == EType::Volume) ? clipping_plane : nullptr; const std::vector>* raycasters = get_raycasters(type); const Vec3f camera_forward = camera.get_dir_forward().cast(); @@ -163,12 +170,22 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came if (!item->is_active()) continue; + // Each plate's component 0 is its surface; the remaining Bed IDs are controls. + // Keep controls clickable, but do not use them as camera-pan anchors. + if (mode != EHitMode::Picking && type == EType::Bed && + decode_id(type, item->get_id()) % PartPlate::GRABBER_COUNT != 0) + continue; + current_hit.raycaster_id = item->get_id(); const Transform3d& trafo = item->get_transform(); if (item->get_raycaster()->closest_hit(mouse_pos, trafo, camera, current_hit.position, current_hit.normal, clip_plane)) { current_hit.position = (trafo * current_hit.position.cast()).cast(); current_hit.normal = (trafo.matrix().block(0, 0, 3, 3).inverse().transpose() * current_hit.normal.cast()).normalized().cast(); - if (item->use_back_faces() || current_hit.normal.dot(camera_forward) < 0.0f) { + // Orca: Perspective rays away from the viewport center are not parallel to camera_forward. + // Keep picking's legacy policy, but accept every front-facing navigation surface. + const Vec3f view_direction = mode != EHitMode::Picking && camera.get_type() == Camera::EType::Perspective ? + Vec3f((current_hit.position.cast() - camera.get_position()).cast()) : camera_forward; + if (item->use_back_faces() || current_hit.normal.dot(view_direction) < 0.0f) { if (is_closest(camera, current_hit.position)) { if (volume_keeper.is_active()) { if (volume_keeper.check_hit_result(current_hit)) @@ -182,14 +199,18 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came } }; - if (!m_gizmos.empty()) - test_raycasters(EType::Gizmo, mouse_pos, camera, ret); + // Orca: Gizmo geometry is an interaction target, not a valid depth anchor for camera movement. + if (mode == EHitMode::Picking) { + if (!m_gizmos.empty()) + test_raycasters(EType::Gizmo, mouse_pos, camera, ret); - if (!m_fallback_gizmos.empty() && !ret.is_valid()) - test_raycasters(EType::FallbackGizmo, mouse_pos, camera, ret); + if (!m_fallback_gizmos.empty() && !ret.is_valid()) + test_raycasters(EType::FallbackGizmo, mouse_pos, camera, ret); + } if (!m_gizmos_on_top || !ret.is_valid()) { - if (camera.is_looking_downward() && !m_bed.empty()) + // Orca: In perspective the bottom of the viewport can see the bed even at a horizontal view. + if ((mode == EHitMode::SceneOnly || (mode == EHitMode::Picking && camera.is_looking_downward())) && !m_bed.empty()) test_raycasters(EType::Bed, mouse_pos, camera, ret); if (!m_volumes.empty()) test_raycasters(EType::Volume, mouse_pos, camera, ret); diff --git a/src/slic3r/GUI/SceneRaycaster.hpp b/src/slic3r/GUI/SceneRaycaster.hpp index 99152712dd..9aa527abee 100644 --- a/src/slic3r/GUI/SceneRaycaster.hpp +++ b/src/slic3r/GUI/SceneRaycaster.hpp @@ -57,6 +57,15 @@ public: FallbackGizmo = 2000000 }; + // Orca: Navigation needs the closest visible scene surface, without picking-specific + // gizmo and selected-volume priority. + enum class EHitMode : unsigned char + { + Picking, + SceneOnly, + VolumesOnly // Navigation when the bed is hidden. + }; + struct HitResult { EType type{ EType::None }; @@ -97,7 +106,8 @@ public: void set_gizmos_on_top(bool value) { m_gizmos_on_top = value; } - HitResult hit(const Vec2d& mouse_pos, const Camera& camera, const ClippingPlane* clipping_plane = nullptr) const; + HitResult hit(const Vec2d& mouse_pos, const Camera& camera, const ClippingPlane* clipping_plane = nullptr, + EHitMode mode = EHitMode::Picking) const; #if ENABLE_RAYCAST_PICKING_DEBUG void render_hit(const Camera& camera); diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 629aef7296..a9767d6c72 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -3470,7 +3470,7 @@ void SelectMachineDialog::navigate_to_timelapse_page() main_frame->jump_to_monitor(); // then switch to Storage (Media) tab inside Monitor - auto* monitor = dynamic_cast(main_frame->m_monitor); + MonitorPanel* monitor = MonitorPanel::if_built(); if (monitor) { auto* tabpanel = monitor->get_tabpanel(); if (tabpanel) { diff --git a/src/slic3r/GUI/StagedBuild.hpp b/src/slic3r/GUI/StagedBuild.hpp new file mode 100644 index 0000000000..8f4c0454c3 --- /dev/null +++ b/src/slic3r/GUI/StagedBuild.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include + +namespace Slic3r { namespace GUI { + +// A panel whose constructor builds the skeleton and queues the rest as steps, run in order +// on the main thread, one at a time. +class StagedBuild +{ +public: + virtual ~StagedBuild() = default; + + bool built() const + { + return m_next_step == m_steps.size() && + std::all_of(m_children.begin(), m_children.end(), [](const StagedBuild* child) { return child->built(); }); + } + + // Runs one step and returns true while more remain. Own steps first, then whatever a + // child queued after its steps were forwarded. + bool build_step() + { + if (m_next_step < m_steps.size()) { + // Copied out, since a step may queue more steps and reallocate m_steps. + auto step = std::move(m_steps[m_next_step++]); + step(); + } else if (StagedBuild* child = unfinished_child()) { + child->build_step(); + } + return !built(); + } + +protected: + void add_build_step(std::function step) { m_steps.push_back(std::move(step)); } + + // Queues one step per step the child has now, and keeps the child so that built() waits + // for any it queues later. + void add_build_steps_of(StagedBuild& child) + { + m_children.push_back(&child); + for (size_t i = child.m_next_step; i < child.m_steps.size(); ++i) + add_build_step([&child] { child.build_step(); }); + } + +private: + StagedBuild* unfinished_child() const + { + auto it = std::find_if(m_children.begin(), m_children.end(), [](const StagedBuild* child) { return !child->built(); }); + return it == m_children.end() ? nullptr : *it; + } + + std::vector> m_steps; + std::vector m_children; + size_t m_next_step{ 0 }; +}; + +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index fb0029edc3..218371f0b5 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -1328,18 +1328,21 @@ StatusBasePanel::StatusBasePanel(wxWindow *parent, wxWindowID id, const wxPoint wxBoxSizer *bSizer_left = new wxBoxSizer(wxVERTICAL); - auto m_monitoring_sizer = create_monitoring_page(); - bSizer_left->Add(m_monitoring_sizer, 1, wxEXPAND | wxALL, 0); + // The sizers are nested here so each step only appends to its own. + add_build_step([this, bSizer_left] { + auto m_monitoring_sizer = create_monitoring_page(); + bSizer_left->Add(m_monitoring_sizer, 1, wxEXPAND | wxALL, 0); - auto m_panel_separotor1 = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); - m_panel_separotor1->SetBackgroundColour(STATUS_PANEL_BG); - m_panel_separotor1->SetMinSize(wxSize(-1, PAGE_SPACING)); - m_panel_separotor1->SetMaxSize(wxSize(-1, PAGE_SPACING)); - m_monitoring_sizer->Add(m_panel_separotor1, 0, wxEXPAND, 0); + auto m_panel_separotor1 = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + m_panel_separotor1->SetBackgroundColour(STATUS_PANEL_BG); + m_panel_separotor1->SetMinSize(wxSize(-1, PAGE_SPACING)); + m_panel_separotor1->SetMaxSize(wxSize(-1, PAGE_SPACING)); + m_monitoring_sizer->Add(m_panel_separotor1, 0, wxEXPAND, 0); - m_project_task_panel = new PrintingTaskPanel(this, PrintingTaskType::PRINGINT); - m_project_task_panel->init_bitmaps(); - m_monitoring_sizer->Add(m_project_task_panel, 0, wxALL | wxEXPAND , 0); + m_project_task_panel = new PrintingTaskPanel(this, PrintingTaskType::PRINGINT); + m_project_task_panel->init_bitmaps(); + m_monitoring_sizer->Add(m_project_task_panel, 0, wxALL | wxEXPAND , 0); + }); // auto m_panel_separotor2 = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); // m_panel_separotor2->SetBackgroundColour(STATUS_PANEL_BG); @@ -1359,8 +1362,10 @@ StatusBasePanel::StatusBasePanel(wxWindow *parent, wxWindowID id, const wxPoint m_machine_ctrl_panel->SetDoubleBuffered(true); auto m_machine_control = create_machine_control_page(m_machine_ctrl_panel); m_machine_ctrl_panel->SetSizer(m_machine_control); - m_machine_ctrl_panel->Layout(); - m_machine_control->Fit(m_machine_ctrl_panel); + add_build_step([this, m_machine_control] { + m_machine_ctrl_panel->Layout(); + m_machine_control->Fit(m_machine_ctrl_panel); + }); bSizer_status_below->Add(m_machine_ctrl_panel, 0, wxALL, 0); @@ -1375,8 +1380,11 @@ StatusBasePanel::StatusBasePanel(wxWindow *parent, wxWindowID id, const wxPoint m_panel_separotor_bottom->SetBackgroundColour(STATUS_PANEL_BG); bSizer_status->Add(m_panel_separotor_bottom, 0, wxEXPAND | wxALL, 0); - this->SetSizerAndFit(bSizer_status); - this->Layout(); + this->SetSizer(bSizer_status); + add_build_step([this, bSizer_status] { + bSizer_status->SetSizeHints(this); + this->Layout(); + }); } StatusBasePanel::~StatusBasePanel() @@ -1614,16 +1622,24 @@ wxBoxSizer *StatusBasePanel::create_machine_control_page(wxWindow *parent) wxBoxSizer *bSizer_control = new wxBoxSizer(wxVERTICAL); - auto temp_axis_ctrl_sizer = create_temp_axis_group(parent); - auto m_filament_load_sizer = create_filament_group(parent); - + // The slot sizers keep each group's place in bSizer_control. + wxBoxSizer *temp_axis_slot = new wxBoxSizer(wxVERTICAL); + wxBoxSizer *filament_slot = new wxBoxSizer(wxVERTICAL); /* ams control box or live nozzle-rack panel (rack printers switch between the two) */ wxSizer *ams_rack_sizer = new wxBoxSizer(wxHORIZONTAL); - ams_rack_sizer->Add(create_ams_group(parent), 0, wxEXPAND | wxLEFT); - m_panel_nozzle_rack = new wgtDeviceNozzleRack(parent); - m_panel_nozzle_rack->Show(false); - ams_rack_sizer->Add(m_panel_nozzle_rack, 0, wxEXPAND | wxLEFT); + add_build_step([this, parent, temp_axis_slot, filament_slot] { + temp_axis_slot->Add(create_temp_axis_group(parent), 0, wxEXPAND); + filament_slot->Add(create_filament_group(parent), 0, wxEXPAND); + }); + add_build_step([this, parent, ams_rack_sizer] { + ams_rack_sizer->Add(create_ams_group(parent), 0, wxEXPAND | wxLEFT); + }); + add_build_step([this, parent, ams_rack_sizer] { + m_panel_nozzle_rack = new wgtDeviceNozzleRack(parent); + m_panel_nozzle_rack->Show(false); + ams_rack_sizer->Add(m_panel_nozzle_rack, 0, wxEXPAND | wxLEFT); + }); m_ams_rack_switch = new SwitchBoard(parent, _L("Filament"), _L("Hotends"), wxSize(FromDIP(126), FromDIP(26))); m_ams_rack_switch->updateState("left"); @@ -1631,12 +1647,12 @@ wxBoxSizer *StatusBasePanel::create_machine_control_page(wxWindow *parent) m_ams_rack_switch->Bind(wxCUSTOMEVT_SWITCH_POS, &StatusBasePanel::on_ams_rack_switch, this); bSizer_control->Add(0, 0, 0, wxTOP, FromDIP(8)); - bSizer_control->Add(temp_axis_ctrl_sizer, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, FromDIP(8)); + bSizer_control->Add(temp_axis_slot, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, FromDIP(8)); bSizer_control->Add(m_ams_rack_switch, 0, wxALIGN_CENTRE|wxTOP, FromDIP(6)); bSizer_control->Add(0, 0, 0, wxTOP, FromDIP(6)); bSizer_control->Add(ams_rack_sizer, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, FromDIP(8)); bSizer_control->Add(0, 0, 0, wxTOP, FromDIP(6)); - bSizer_control->Add(m_filament_load_sizer, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, FromDIP(8)); + bSizer_control->Add(filament_slot, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, FromDIP(8)); bSizer_control->Add(0, 0, 0, wxTOP, FromDIP(4)); bSizer_right->Add(bSizer_control, 1, wxEXPAND | wxALL, 0); @@ -2228,8 +2244,10 @@ void StatusBasePanel::expand_filament_loading(wxMouseEvent& e) m_filament_step->Show(tag_show); Layout(); Fit(); - wxGetApp().mainframe->m_monitor->get_status_panel()->Layout(); - wxGetApp().mainframe->m_monitor->Layout(); + if (MonitorPanel* monitor = MonitorPanel::if_built()) { + monitor->get_status_panel()->Layout(); + monitor->Layout(); + } } void StatusBasePanel::show_ams_group(bool show) @@ -2240,7 +2258,8 @@ void StatusBasePanel::show_ams_group(bool show) m_ams_control->Fit(); Layout(); Fit(); - wxGetApp().mainframe->m_monitor->Layout(); + if (MonitorPanel* monitor = MonitorPanel::if_built()) + monitor->Layout(); } // On rack printers, don't clobber the rack view when the user has the switch on "Hotends". @@ -2253,7 +2272,8 @@ void StatusBasePanel::show_ams_group(bool show) m_ams_control->Fit(); Layout(); Fit(); - wxGetApp().mainframe->m_monitor->Layout(); + if (MonitorPanel* monitor = MonitorPanel::if_built()) + monitor->Layout(); } } @@ -2277,8 +2297,10 @@ void StatusBasePanel::show_filament_load_group(bool show) Layout(); Fit(); - wxGetApp().mainframe->m_monitor->get_status_panel()->Layout(); - wxGetApp().mainframe->m_monitor->Layout(); + if (MonitorPanel* monitor = MonitorPanel::if_built()) { + monitor->get_status_panel()->Layout(); + monitor->Layout(); + } } } @@ -2403,6 +2425,12 @@ void StatusPanel::update_camera_state(MachineObject* obj) StatusPanel::StatusPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style, const wxString &name) : StatusBasePanel(parent, id, pos, size, style) +{ + // Wires the controls the base class builds in steps, so it is the last step. + add_build_step([this] { wire_controls(); }); +} + +void StatusPanel::wire_controls() { init_scaled_buttons(); m_buttons.push_back(m_bpButton_z_10); @@ -2514,47 +2542,50 @@ StatusPanel::StatusPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, co StatusPanel::~StatusPanel() { - // Disconnect Events - m_project_task_panel->get_bitmap_thumbnail()->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(StatusPanel::refresh_thumbnail_webrequest), NULL, this); - m_project_task_panel->get_partskip_button()->Disconnect(wxEVT_LEFT_DOWN, wxCommandEventHandler(StatusPanel::on_subtask_partskip), NULL, this); - m_project_task_panel->get_pause_resume_button()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_pause_resume), NULL, this); - m_project_task_panel->get_abort_button()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_abort), NULL, this); - m_project_task_panel->get_market_scoring_button()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_market_scoring), NULL, this); - m_project_task_panel->get_market_retry_buttom()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_market_retry), NULL, this); - m_project_task_panel->get_clean_button()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_print_error_clean), NULL, this); + // The controls only exist once the last build step has run. + if (built()) { + // Disconnect Events + m_project_task_panel->get_bitmap_thumbnail()->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(StatusPanel::refresh_thumbnail_webrequest), NULL, this); + m_project_task_panel->get_partskip_button()->Disconnect(wxEVT_LEFT_DOWN, wxCommandEventHandler(StatusPanel::on_subtask_partskip), NULL, this); + m_project_task_panel->get_pause_resume_button()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_pause_resume), NULL, this); + m_project_task_panel->get_abort_button()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_abort), NULL, this); + m_project_task_panel->get_market_scoring_button()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_market_scoring), NULL, this); + m_project_task_panel->get_market_retry_buttom()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_market_retry), NULL, this); + m_project_task_panel->get_clean_button()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_print_error_clean), NULL, this); - m_setting_button->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(StatusPanel::on_camera_enter), NULL, this); - m_setting_button->Disconnect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(StatusPanel::on_camera_enter), NULL, this); - m_tempCtrl_bed->Disconnect(wxEVT_KILL_FOCUS, wxFocusEventHandler(StatusPanel::on_bed_temp_kill_focus), NULL, this); - m_tempCtrl_bed->Disconnect(wxEVT_SET_FOCUS, wxFocusEventHandler(StatusPanel::on_bed_temp_set_focus), NULL, this); - m_tempCtrl_nozzle->Disconnect(wxEVT_KILL_FOCUS, wxFocusEventHandler(StatusPanel::on_nozzle_temp_kill_focus), NULL, this); - m_tempCtrl_nozzle->Disconnect(wxEVT_SET_FOCUS, wxFocusEventHandler(StatusPanel::on_nozzle_temp_set_focus), NULL, this); + m_setting_button->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(StatusPanel::on_camera_enter), NULL, this); + m_setting_button->Disconnect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(StatusPanel::on_camera_enter), NULL, this); + m_tempCtrl_bed->Disconnect(wxEVT_KILL_FOCUS, wxFocusEventHandler(StatusPanel::on_bed_temp_kill_focus), NULL, this); + m_tempCtrl_bed->Disconnect(wxEVT_SET_FOCUS, wxFocusEventHandler(StatusPanel::on_bed_temp_set_focus), NULL, this); + m_tempCtrl_nozzle->Disconnect(wxEVT_KILL_FOCUS, wxFocusEventHandler(StatusPanel::on_nozzle_temp_kill_focus), NULL, this); + m_tempCtrl_nozzle->Disconnect(wxEVT_SET_FOCUS, wxFocusEventHandler(StatusPanel::on_nozzle_temp_set_focus), NULL, this); - m_tempCtrl_nozzle_deputy->Disconnect(wxEVT_KILL_FOCUS, wxFocusEventHandler(StatusPanel::on_nozzle_temp_kill_focus), NULL, this); - m_tempCtrl_nozzle_deputy->Disconnect(wxEVT_SET_FOCUS, wxFocusEventHandler(StatusPanel::on_nozzle_temp_set_focus), NULL, this); + m_tempCtrl_nozzle_deputy->Disconnect(wxEVT_KILL_FOCUS, wxFocusEventHandler(StatusPanel::on_nozzle_temp_kill_focus), NULL, this); + m_tempCtrl_nozzle_deputy->Disconnect(wxEVT_SET_FOCUS, wxFocusEventHandler(StatusPanel::on_nozzle_temp_set_focus), NULL, this); - m_switch_lamp->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_lamp_switch), NULL, this); - /*m_switch_nozzle_fan->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this); - m_switch_printing_fan->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this); - m_switch_cham_fan->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this);*/ + m_switch_lamp->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_lamp_switch), NULL, this); + /*m_switch_nozzle_fan->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this); + m_switch_printing_fan->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this); + m_switch_cham_fan->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this);*/ - //m_switch_fan->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this); - //m_switch_fan->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this); - m_switch_fan->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this); + //m_switch_fan->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this); + //m_switch_fan->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this); + m_switch_fan->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this); - m_bpButton_xy->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_xy), NULL, this); - m_bpButton_z_10->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_z_up_10), NULL, this); - m_bpButton_z_1->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_z_up_1), NULL, this); - m_bpButton_z_down_1->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_z_down_1), NULL, this); - m_bpButton_z_down_10->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_z_down_10), NULL, this); - m_bpButton_e_10->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_e_up_10), NULL, this); - m_bpButton_e_down_10->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_e_down_10), NULL, this); - m_nozzle_btn_panel->Disconnect(wxCUSTOMEVT_SWITCH_POS, wxCommandEventHandler(StatusPanel::on_nozzle_selected), NULL, this); - m_switch_speed->Disconnect(wxEVT_LEFT_DOWN, wxCommandEventHandler(StatusPanel::on_switch_speed), NULL, this); - m_calibration_btn->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_start_calibration), NULL, this); - m_options_btn->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_show_print_options), NULL, this); - m_safety_btn->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_show_safety_options), NULL, this); - m_parts_btn->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_show_parts_options), NULL, this); + m_bpButton_xy->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_xy), NULL, this); + m_bpButton_z_10->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_z_up_10), NULL, this); + m_bpButton_z_1->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_z_up_1), NULL, this); + m_bpButton_z_down_1->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_z_down_1), NULL, this); + m_bpButton_z_down_10->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_z_down_10), NULL, this); + m_bpButton_e_10->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_e_up_10), NULL, this); + m_bpButton_e_down_10->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_e_down_10), NULL, this); + m_nozzle_btn_panel->Disconnect(wxCUSTOMEVT_SWITCH_POS, wxCommandEventHandler(StatusPanel::on_nozzle_selected), NULL, this); + m_switch_speed->Disconnect(wxEVT_LEFT_DOWN, wxCommandEventHandler(StatusPanel::on_switch_speed), NULL, this); + m_calibration_btn->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_start_calibration), NULL, this); + m_options_btn->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_show_print_options), NULL, this); + m_safety_btn->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_show_safety_options), NULL, this); + m_parts_btn->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_show_parts_options), NULL, this); + } // remove warning dialogs if (abort_dlg != nullptr) @@ -5216,7 +5247,9 @@ void StatusPanel::set_default() m_filament_step->Hide(); error_info_reset(); #ifndef __WXGTK__ - SetFocus(); + // Also reached while the panel is built off screen. + if (IsShownOnScreen()) + SetFocus(); #endif } diff --git a/src/slic3r/GUI/StatusPanel.hpp b/src/slic3r/GUI/StatusPanel.hpp index 341bb9ab69..d79c3d3915 100644 --- a/src/slic3r/GUI/StatusPanel.hpp +++ b/src/slic3r/GUI/StatusPanel.hpp @@ -36,6 +36,7 @@ #include "HMS.hpp" #include "PartSkipDialog.hpp" #include "DeviceErrorDialog.hpp" +#include "StagedBuild.hpp" class StepIndicator; @@ -375,7 +376,7 @@ public: void paint(wxPaintEvent&); }; -class StatusBasePanel : public wxScrolledWindow +class StatusBasePanel : public wxScrolledWindow, public StagedBuild { protected: wxBitmap m_item_placeholder; @@ -443,7 +444,7 @@ protected: wxMediaCtrl3 * m_media_ctrl; - MediaPlayCtrl * m_media_play_ctrl; + MediaPlayCtrl * m_media_play_ctrl{nullptr}; Label * m_staticText_printing; wxStaticBitmap *m_bitmap_thumbnail; @@ -629,6 +630,7 @@ class StatusPanel : public StatusBasePanel { private: friend class MonitorPanel; + void wire_controls(); protected: std::shared_ptr m_slice_info_popup; @@ -679,7 +681,7 @@ protected: std::map m_print_connect_types; std::vector