Fix plugin configuration not taking effect, and improve the plugin config UI (#14944)

# Description

Changing a slicing plugin's configuration had no effect on the sliced
result until you forced a re-slice some other way; it now applies
immediately. Print, printer and filament presets also keep their plugin
configuration separately, so configuring a plugin on one no longer wipes
out what you set on another.

A plugin's custom configuration page gets the same round of improvements
in both the Plugins dialog and the per-preset dialog: it follows the
app's light/dark theme, keeps its state while you edit instead of
resetting under the cursor, and can tell whether it is being edited
globally or for a preset, so "Restore defaults" can be labeled for what
it will actually do. The two bundled examples show this off — Twistify
now ships a custom configuration UI, and Inspector is themed, groups

# Screenshots/Recordings/Graphs



https://github.com/user-attachments/assets/02ca062a-5143-49a3-abe0-a2a040b3a928



## Tests

<!--
> Please describe the tests that you have conducted to verify the
changes made in this PR.
-->

<!--
> A guide for users on how to download the artifacts from this PR.
-->

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
This commit is contained in:
SoftFever
2026-07-25 20:00:56 +08:00
committed by GitHub
parent d6cb667b89
commit 9a72dda79a
18 changed files with 1202 additions and 408 deletions

View File

@@ -324,12 +324,6 @@ bool PluginConfig::dirty() const
return m_dirty;
}
std::string plugin_overrides_of(const Preset& preset)
{
const auto* opt = dynamic_cast<const ConfigOptionString*>(preset.config.option(PLUGIN_OVERRIDES_OPTION_KEY));
return opt == nullptr ? std::string() : opt->value;
}
bool parse_plugin_overrides(const std::string& raw, CapabilityConfigDocument& document, std::string& error)
{
document = CapabilityConfigDocument();
@@ -357,9 +351,9 @@ std::string serialize_plugin_overrides(const CapabilityConfigDocument& document)
return document.empty() ? std::string() : document.serialize_entries().dump();
}
bool prune_stale_plugin_overrides(DynamicConfig& config)
bool prune_stale_plugin_overrides(DynamicConfig& config, const std::string& overrides_key)
{
const auto* overrides_opt = dynamic_cast<const ConfigOptionString*>(config.option(PLUGIN_OVERRIDES_OPTION_KEY));
const auto* overrides_opt = dynamic_cast<const ConfigOptionString*>(config.option(overrides_key));
if (overrides_opt == nullptr || overrides_opt->value.empty())
return false;
@@ -397,7 +391,7 @@ bool prune_stale_plugin_overrides(DynamicConfig& config)
if (!overrides.prune_unreferenced(referenced))
return false;
config.set_key_value(PLUGIN_OVERRIDES_OPTION_KEY, new ConfigOptionString(serialize_plugin_overrides(overrides)));
config.set_key_value(overrides_key, new ConfigOptionString(serialize_plugin_overrides(overrides)));
return true;
}
@@ -470,27 +464,29 @@ EffectiveCapabilityConfig active_capability_config(const PluginCapabilityId& id)
if (bundle != nullptr) {
const std::string type_key = plugin_capability_type_to_string(id.type);
// The edited preset of each type that can hold plugin-backed options, keyed by its option list.
const std::pair<const std::vector<std::string>*, const Preset*> scopes[] = {
{&Preset::print_options(), &bundle->prints.get_edited_preset()},
{&Preset::printer_options(), &bundle->printers.get_edited_preset()},
{&Preset::filament_options(), &bundle->filaments.get_edited_preset()},
};
for (const auto& [key, def] : print_config_def.options) {
if (def.plugin_type != type_key)
continue;
const auto& print_options = Preset::print_options();
if (std::find(print_options.begin(), print_options.end(), key) != print_options.end()) {
preset = &bundle->prints.get_edited_preset();
for (const auto& [options, edited] : scopes)
if (contains(*options, key)) {
preset = edited;
break;
}
if (preset != nullptr)
break;
}
const auto& printer_options = Preset::printer_options();
if (std::find(printer_options.begin(), printer_options.end(), key) != printer_options.end()) {
preset = &bundle->printers.get_edited_preset();
break;
}
}
}
if (preset != nullptr) {
const auto* stored = dynamic_cast<const ConfigOptionString*>(preset->config.option(Preset::plugin_overrides_key(preset->type)));
std::string error;
if (!parse_plugin_overrides(plugin_overrides_of(*preset), overrides, error)) {
if (!parse_plugin_overrides(stored == nullptr ? std::string() : stored->value, overrides, error)) {
// Text we cannot read is not an override: log it and resolve against the base config.
BOOST_LOG_TRIVIAL(error) << "Preset \"" << preset->name << "\": " << error;
overrides = CapabilityConfigDocument();