Skip to content

feat: Add Reload Presets button and menu item (Cmd+R)#9919

Open
adele-with-a-b wants to merge 3 commits intobambulab:masterfrom
adele-with-a-b:preset-hot-reload
Open

feat: Add Reload Presets button and menu item (Cmd+R)#9919
adele-with-a-b wants to merge 3 commits intobambulab:masterfrom
adele-with-a-b:preset-hot-reload

Conversation

@adele-with-a-b
Copy link
Copy Markdown
Contributor

@adele-with-a-b adele-with-a-b commented Mar 8, 2026

Reload Presets (Cmd+R)

Reload user presets from disk without restarting the app.

  • Menu: File → Reload Presets (Cmd+R)
  • Button: Refresh icon next to the preset dropdown on all tabs (process, filament, printer)
  • Auto-select: When new presets are detected after reload, the most recent one is automatically selected

This enables external tools (scripts, AI assistants, CLI workflows) to generate Bambu Studio preset JSON files that appear in the slicer immediately — no restart required.

Preset Directory

User presets are stored at:

OS Path
macOS ~/Library/Application Support/BambuStudio/user/<user_id>/process/
Windows %APPDATA%\BambuStudio\user\<user_id>\process\
Linux ~/.config/BambuStudio/user/<user_id>/process/

Replace <user_id> with your Bambu account ID (visible in the directory), or default if not logged in. Filament presets go in filament/ instead of process/.

Each preset needs two files: a .json and a .info.

Process Preset Example

Structural PETG-CF 0.6mm @bbl H2C.json — a structural profile with 4 walls and 40% infill:

{
    "from": "User",
    "inherits": "0.24mm Balanced Strength @BBL H2C 0.6 nozzle",
    "name": "Structural PETG-CF 0.6mm @BBL H2C",
    "print_extruder_id": ["1", "1", "2", "2"],
    "print_extruder_variant": ["Direct Drive Standard", "Direct Drive High Flow", "Direct Drive Standard", "Direct Drive High Flow"],
    "print_settings_id": "Structural PETG-CF 0.6mm @BBL H2C",
    "version": "2.5.0.7",
    "wall_loops": "4",
    "sparse_infill_density": "40%"
}

Structural PETG-CF 0.6mm @bbl H2C.info:

sync_info = create
user_id = <your_user_id>
setting_id = 
base_id = <parent_profile_setting_id>
updated_time = 0

The base_id is the setting_id from the parent system profile JSON (found in the system/BBL/process/ directory). Only settings that differ from the inherited base need to be included.

Drop both files into the preset directory and hit Cmd+R.

Implementation

  • GUI_App::reload_user_presets_from_disk() — snapshots existing user presets, calls load_user_presets(), detects new presets, and selects them via Tab::select_preset() for proper UI update
  • MainFrame::init_menubar_as_editor() — adds File → Reload Presets menu item with Cmd+R shortcut
  • Tab — adds refresh button between preset dropdown and save/delete buttons on all tabs
  • Custom reload_preset.svg icon matching the existing monochrome style

Features:
- Reload button (refresh icon) next to preset dropdown on all tabs
- File > Reload Presets menu item with Cmd+R shortcut
- Reloads user presets from disk without app restart
- Auto-selects newly found presets after reload
- Properly updates all tab UI including delete button visibility

Also:
- Custom monochrome reload_preset.svg icon matching save/cross style
- cmake 4.x compatibility fix for dependency builds
@mpaperno
Copy link
Copy Markdown
Contributor

mpaperno commented Mar 9, 2026

Hey this is great, exactly what I wanted to add as well! Thanks for working on it.

I'm not sure I understand the part with selecting the last newly found preset after a reload, and haven't had a chance test (sorry!). This may change what is currently selected by the user? If I'm understanding correctly... personally I wouldn't want that at all. If the currently selected preset was updated, then the UI should reflect those changes, but I think it's weird if it arbitrarily selects some newly added preset... would it even be compatible? And "last" in this case is somewhat arbitrary (sorted alphabetically by name IIRC). But maybe I misunderstand the intention?

Thanks again,
-Max

@adele-with-a-b
Copy link
Copy Markdown
Contributor Author

adele-with-a-b commented Mar 9, 2026

Hey Max!

The original intent of updating the dropdown selection was a convenience for my own workflow: I generate preset JSON files externally (via scripts/LLM), hit Cmd+R, and wanted to immediately see the new preset, plus it gives a visual feedback that something actually happened. But
you're correct that this might not be a widespread use case:

  • It silently changes the user's active selection. If there are unsaved changes in the active process it won't get rid of all of them but the ones that intersect with the new preset would be overwritten
  • The "last" new preset is arbitrary (depends on iteration order)
  • If the new preset is not compatible with the current printer/nozzle config it won't show in the dropdown until you change, for instance, the nozzle size. It inherits the configuration compatibility from the system preset set in the "inherits" key.

I think I'd be ok with striping out the auto-select logic and keep the reload to just: reload from disk → refresh UI → keep current selection. If the currently selected preset was modified on disk,
the UI will reflect those changes. If it was deleted, it can fall back to the default. I might just add a quick pop up with maybe a count of loaded presets or some sort of indicator that something happened. Open to suggestions if you give it a try and have some extra feedback.

Best,
Abdel.

@mpaperno
Copy link
Copy Markdown
Contributor

mpaperno commented Mar 9, 2026

Hi Abdel, thanks for your response!

Both of them :-) And that screenshot was helpful. I'm also very interested in improving the preset management situation, and using external tools (even a text editor) is a quick step forward w/out needing any changes in Studio. And this reload function is key to making that more practical. 👍🏼

I even just recently started a thread on the BL forums about editing files manually and using inheritance features:
https://forum.bambulab.com/t/bambu-studio-presets-management-utilizing-inheritance-features/239148

It silently changes the user's active selection.

Yea that was my first thought. Kinda one of my "golden rules" not to do. Not that I like rules usually. (Have you ever read the book Don't Make Me Think? Great short little book about UI design.)

And your other points all speak against that mechanism as well, I agree. Although I get your use case (adding a preset externally and you want to use it right away, IIUC), there would be other usage scenarios, like adding a bunch of presets at once (something I'm probably more likely to do, myself). And maybe the user doesn't even remember that they had added those (also likely scenario for me personally 😃 , or some script went haywire or whatever).

Visual feedback would be good, indeed, and some stats would be a nice bonus too. The "newly added is selected" only works when a preset is added anyway (vs. edited), so that doesn't really work in its favor either. I'm not a big fan of popups though (plus I think that would work against one of your goals here to make the process as seamless as possible). What about the "toast" notifications that show up at bottom right? Nice and unobtrusive. (I haven't looked at that code at all yet, so I have no idea how simple of a suggestion this is, or not.)

I also have a question about that reload button, next to the process profile selector. I'm not sure it makes sense there...? As a user, visually I'm not really sure what it will do at first -- reload the current profile, it looks like, but that's weird since you're there editing it why would it need a reload? The other buttons on the same row act on the current profile, so one may expect reload to do the same (and not expect it to reload everything). And then it also reloads filaments and machines, so that's entirely unexpected (until/unless one reads the tooltip, but "no one reads" is my usual assumption).

IMHO the File menu entry is enough, especially with the shortcut. But I'd move it down below "Batch Preset Management" instead of in the middle of the "save" options. And also get it to show up for Mac users. (The current Mac vs. rest preprocessor distinctions in that code are ugly, just for one difference in a variable(!), but that's another matter and I think you can avoid duplicating it anyway.)

As a future addition it could be cool if a preset reload could be triggered externally, for example by whatever script or app is being used to edit them. And maybe even granular reload (a specific profile) to make it more efficient.

OK that got long, sorry! LMK what you think!

Thanks,
-Max

@adele-with-a-b
Copy link
Copy Markdown
Contributor Author

adele-with-a-b commented Mar 10, 2026

Hey Max, great feedback, really appreciate the thoroughness!

I'm on board with pretty much everything you've laid out. Here's the plan:

Auto-select removal — Agreed, that needs to go. Silently changing the user's active selection violates the principle of least surprise. I'll strip that logic out and just reload in place. When I thought of this feature and started implementing it I had no intent on posting a PR 😬

Toast notification — I used a misnomer but that's what I had pictured. Something like "Reloaded presets: 2 new, 1 modified" in the bottom-right toast is the right level of feedback without being intrusive. I'll look into the existing toast system and wire it up.

Remove the reload button from the Tab toolbar — You're right that it's misleading next to the profile-specific buttons. The File menu entry + shortcut is sufficient. I was just lazy

Move the menu entry — I'll relocate it below Batch Preset Management where it fits better semantically.

Cross-platform visibility — So funny enough, it's actually the opposite of what you might expect — the menu item currently only exists in the Mac code path. I'll pull it out of the platform-specific #ifdef block so it shows up everywhere. I have no way of testing it on Windows, or Linux for the time being (my instance has no GUI but maybe I'll set it up just to test this out)

External trigger — Interesting idea for the future. Could see a file watcher or even a simple IPC mechanism working well there.


One more thing I'm thinking about as a follow-up: an Import Presets menu item. The idea is you select one or more preset JSON files, and the app handles the rest — detects whether each is a filament or process preset, validates it, generates the companion .info file with the correct base_id, and drops everything into the right user preset directory. Then it triggers a reload automatically. This would make the external editing workflow you're describing in your forum thread a lot more accessible — users wouldn't need to know the directory structure or .info file format at all. Thinking of that as a separate PR that builds on this one. 😂 OMG that's already there!!!!! (Goes to show how little I know about this app)

I'll get started on the changes. Thanks again for the detailed review!

PS: Is there a magical way of circumventing that very annoying network plugin so I can actually print from my fork? 😭

- Remove auto-select of newly found presets (don't change user's selection)
- Add toast notification showing reload stats (new process/filament counts)
- Remove reload button from Tab toolbar (was confusing next to profile-specific buttons)
- Move File menu entry below Batch Preset Management
- Make menu entry cross-platform (was Mac-only, now shows on all platforms)
- Change shortcut to Cmd+Shift+R / Ctrl+Shift+R (Cmd+R conflicts with slice)
@mpaperno
Copy link
Copy Markdown
Contributor

mpaperno commented Mar 10, 2026

Sounds awesome, thanks!

Happy to test it out on Windows here. Haven't thrown it on any Linux system yet, but that's in the plan. For me the MacOS versions are usually the pain point for testing... and this one in particular really needs serious video resources to be usable. 😐

Yea noticed the logic reversal on those macros once I looked in the editor... OMG, the smell. Definitely need to stay on one's toes in this code base. 🙄 The more I look the more surprised I am that it works at all (missing nullptr and index bounds checks in critical areas, for example).

IIRC I got the network to work by using the latest beta version plugin (or for the latest beta version of Studio, I mean). It's tagged as v. 02.05.01.52 in the downloads (so the Windows filename is Studio-connector-win_02.05.01.52.zip), which I think matches the current build version in the source code. IIRC I "hacked" the download URL to get it 'cuz installing the beta just for that would have been a pain... though now I can't remember where I got the URL in the first place. From the error in the log maybe, when it failed to do it the automatic way. The URL formatter is in GUI_App.cpp @ 1545: get_plugin_url(), FWIW.

And yea... it's a massive program, lots to discover!

Ooops.. speaking of which... did you know there's a Help -> Keyboard Shortcuts window? I didn't until I noticed it in the code... lol. But it claims in there that CTRL+R is used for "Slice plate" in the "Global" group. I haven't checked if that's true (or even where it gets that list from)... but that would be good to resolve probably.

Thanks again, and looking forward to the update!
-Max

PS. I only use the printer/Studio in "LAN Mode" so I can't speak to the whole cloud thing with the network plugin. Don't even get me started on the cloud thing... LOL.

Comment thread deps/CMakeLists.txt Outdated
-DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
-DCMAKE_TOOLCHAIN_FILE:STRING=${CMAKE_TOOLCHAIN_FILE}
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
Copy link
Copy Markdown
Contributor

@weishibambu weishibambu Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The minimum cmake version requirement is 3.13. You can set the cmake_policy_version in your local build or upgrade your cmake. It's not necessary to commit this file to the repo.

: DEFAULT_USER_FOLDER_NAME;

// Snapshot existing preset names before reload
std::set<std::string> old_prints, old_filaments;
Copy link
Copy Markdown
Contributor

@weishibambu weishibambu Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "set" is not included. The repo may build failed in Mac, it's better to include the "set" in this cpp file.

Comment thread src/slic3r/GUI/GUI_App.cpp Outdated

BOOST_LOG_TRIVIAL(info) << "Reloading user presets from disk for user: " << user_id;
preset_bundle->load_user_presets(user_id, ForwardCompatibilitySubstitutionRule::Enable);
mainframe->update_side_preset_ui();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The side preset ui should be updated only if there are new presets loaded. So it's better to move this line to 5718 and check whether the new_print or the new filament is empty.


// Find new presets and select the last one found
std::string new_print, new_filament;
for (const auto& p : preset_bundle->prints)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Selecting the new print or new filament may not be expected by the user.

Comment thread src/slic3r/GUI/MainFrame.cpp Outdated
[this](){return m_plater != nullptr && can_save(); }, this);

// Reload user presets from disk
append_menu_item(fileMenu, wxID_ANY, _L("Reload Presets") + "\t" + ctrl + "R", _L("Reload user presets from disk"),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This menu item is added only in MAC. What about Windows or Linux?

@mpaperno
Copy link
Copy Markdown
Contributor

mpaperno commented Mar 13, 2026

@weishibambu You might wish to read our previous conversation here which covers some of the comments you're making. I believe @adele-with-a-b is going to be working on updating this PR.

#9919 (comment)

Thank you,
-Max

@mpaperno
Copy link
Copy Markdown
Contributor

Hi Abdel,

The first of your new commits looks great, just as discussed, nice!

But did you mean to push all the following ones here also?

Thanks!
-Max

@adele-with-a-b
Copy link
Copy Markdown
Contributor Author

Hey Max,

Was just playing around with some improvements and got carried away: they are here https://github.com/adele-with-a-b/BambuStudio/tree/preset-explorer if you wanna take a look/contribute some ideas.

Best!
Abdel.

- Remove CMAKE_POLICY_VERSION_MINIMUM from deps/CMakeLists.txt (local build compat, not needed in repo)
- Add missing #include <set> for std::set usage (portability across compilers)
- Only call update_side_preset_ui() when new presets are detected
@adele-with-a-b
Copy link
Copy Markdown
Contributor Author

Hey @weishibambu, thanks for the review! All points addressed in 835e2a1:

  1. deps/CMakeLists.txt — Removed. That was a workaround for building with cmake 4.x (which errors on old cmake_minimum_required calls in dependency source trees). Agreed it doesn't belong in the repo — it's a local build environment issue.

  2. Missing #include <set> — Added. It was compiling on my end via transitive includes but that's not portable. Good catch.

  3. update_side_preset_ui() called unconditionally — Moved after the new-preset detection loop and now only called when new_prints > 0 || new_filaments > 0.

  4. Auto-selecting new presets — Already removed in the previous commit (2a1709e).

  5. Menu item Mac-only — Already fixed cross-platform in the previous commit (2a1709e). It now shows on all platforms with Ctrl+Shift+R / Cmd+Shift+R.


// Only update UI if presets changed
if (new_prints > 0 || new_filaments > 0)
mainframe->update_side_preset_ui();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I would always reload the UI, w/out any condition, because it would be complex to check for all types of change that could have happened with the profiles. Some could have been removed, or just edited. If anyone is manually reloading configs, I think it is likely because they know something changed in there, so a refresh seems more likely to be needed than not.


// Show toast notification with reload stats
std::string msg = "Presets reloaded";
if (new_prints > 0 || new_filaments > 0) {
Copy link
Copy Markdown
Contributor

@mpaperno mpaperno Mar 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion:

std::string msg = "Presets reloaded";
std::vector<std::string> parts;
if (new_prints > 0)
    parts.push_back(std::to_string(new_prints) + " new process");
if (new_filaments > 0)
    parts.push_back(std::to_string(new_filaments) + " new filament");
if (!parts.empty())
    msg += ": " + boost::algorithm::join(parts, ", ");

boost::algorithm::join should already be included via boost/algorithm/string.hpp

}

// Reload user presets from disk without restart
void GUI_App::reload_user_presets_from_disk()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this method be const ? Seems like it but I'm not sure.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This icon isn't used anymore, is it?

@JohnSmithCYM
Copy link
Copy Markdown
Contributor

Thanks for the improvement. Reloading presets without restarting Studio is useful in some cases but I have a few suggestions:

  1. It targets an advanced workflows and it might be better to treat it as an advanced feature and place it better in locations like Batch Preset Management.
  2. 'Reload Presets from Disk' seems better than 'Reload Local Presets' in this case.

@mpaperno
Copy link
Copy Markdown
Contributor

I do like it in the menu, or with a shortcut at least, but I agree it's "advanced" and would simplify the "basic" UI a bit to exclude it. Not sure if the menu or shortcuts config reloads when switching modes, but having to restart would be fine I think.

Placing it in some other place as well, like the batch preset management is also a good idea, a logical place for that. I haven't look into what that means in terms of reloading the batch preset UI, but OTOH it would provide immediate feedback about the reloaded profiles, which is really nice.

Agree on the title change also, it is clearer.

Thanks!

@mpaperno
Copy link
Copy Markdown
Contributor

I just realized (while working on another feature) that this is missing the actual shortcut handler, right? (I'm too used to Qt where a lot of this is handled in one call.)

Something like this seems to capture the shortcut at the top level (adding to MainFrame's wxEVT_CHAR_HOOK handler):

--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -664,6 +664,10 @@ MainFrame::MainFrame()
             return;}
 #endif
         if (evt.CmdDown() && evt.GetKeyCode() == 'R') { if (m_slice_enable) { wxGetApp().plater()->update(true, true); wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_PLATE)); this->m_tabpanel->SetSelection(tpPreview); } return; }
+        if (evt.CmdDown() && evt.ShiftDown() && evt.GetKeyCode() == 'R') {
+            wxGetApp().reload_user_presets_from_disk();
+            return;
+        }
         if (evt.CmdDown() && evt.ShiftDown() && evt.GetKeyCode() == 'G') {
             m_plater->apply_background_progress();
             m_print_enable = get_enable_print_status();

@mpaperno
Copy link
Copy Markdown
Contributor

@adele-with-a-b Hi, are you planning on revisiting this PR? Would still be a great feature. I can take over if you don't have time or inclination to continue it (will try to keep your contributions via cherry-pick). Just let me know.

Thanks,
-Max

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants