Add controls for auto-generated mixed filament gradients

Add an app preference for mixed filament gradient auto-generation and
sync the manager state from startup and preferences changes.

Prompt before generating large gradient sets, preserve custom rows
when auto-generation is disabled, and refresh remapping/UI handling
accordingly. Add mixed filament coverage and a dumpinfo helper for
inspecting Windows minidumps.
This commit is contained in:
Rad
2026-03-21 21:05:31 +01:00
parent 970630275e
commit 778a8e45af
10 changed files with 334 additions and 8 deletions
+110 -4
View File
@@ -1352,6 +1352,7 @@ Sidebar::Sidebar(Plater *parent)
return;
int filament_count = p->combos_filament.size() + 1;
wxGetApp().plater()->confirm_auto_generated_gradients(filament_count);
wxColour new_col = Plater::get_next_color_for_filament();
std::string new_color = new_col.GetAsString(wxC2S_HTML_SYNTAX).ToStdString();
wxGetApp().preset_bundle->set_num_filaments(filament_count, new_color);
@@ -6878,7 +6879,7 @@ void Sidebar::update_mixed_filament_panel(bool sync_manager)
if (p->m_btn_add_color)
p->m_btn_add_color->Enable(num_physical >= 2);
if (mixed.empty()) {
if (num_physical < 2) {
p->m_panel_mixed_filaments_title->Hide();
p->m_panel_mixed_filaments_content->Hide();
Layout();
@@ -6900,6 +6901,27 @@ void Sidebar::update_mixed_filament_panel(bool sync_manager)
auto *rows_sizer = new wxBoxSizer(wxVERTICAL);
rows_scroller->SetSizer(rows_sizer);
if (mixed.empty()) {
auto *empty_label = new wxStaticText(rows_scroller, wxID_ANY,
_L("No mixed filaments yet. Use Add Gradient, Add Pattern, or Add Color to create one."));
empty_label->SetForegroundColour(mixed_summary_fg);
empty_label->SetFont(::Label::Body_13);
empty_label->Wrap(FromDIP(360));
rows_sizer->Add(empty_label, 0, wxALL | wxEXPAND, FromDIP(12));
rows_scroller->Layout();
rows_scroller->FitInside();
const int empty_content_h = empty_label->GetBestSize().GetHeight() + FromDIP(28);
const int empty_rows_h = std::max(FromDIP(86), empty_content_h);
rows_scroller->SetMinSize(wxSize(-1, empty_rows_h));
rows_scroller->SetMaxSize(wxSize(-1, empty_rows_h));
if (content_sizer)
content_sizer->Add(rows_scroller, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(SidebarProps::ContentMargin()));
p->m_panel_mixed_filaments_content->Layout();
Layout();
refresh_model_canvas_colors();
return;
}
auto adjust_rows_scroller_height = [this, rows_scroller]() {
if (!rows_scroller)
return;
@@ -7581,6 +7603,7 @@ void Sidebar::add_custom_filament(wxColour new_col) {
if (p->combos_filament.size() >= MAXIMUM_EXTRUDER_NUMBER) return;
int filament_count = p->combos_filament.size() + 1;
wxGetApp().plater()->confirm_auto_generated_gradients(filament_count);
std::string new_color = new_col.GetAsString(wxC2S_HTML_SYNTAX).ToStdString();
wxGetApp().preset_bundle->set_num_filaments(filament_count, new_color);
wxGetApp().plater()->on_filaments_change(filament_count);
@@ -8409,9 +8432,13 @@ struct Plater::priv
static const std::regex pattern_prusa;
bool m_is_dark = false;
size_t m_last_auto_gradient_prompt_physical_count = 0;
bool m_last_auto_gradient_prompt_accepted = false;
priv(Plater *q, MainFrame *main_frame);
~priv();
bool confirm_auto_generated_gradients(wxWindow *parent, size_t num_physical);
void set_auto_generated_gradient_decision(size_t num_physical, bool create_auto_gradients);
bool need_update() const { return m_need_update; }
@@ -9933,9 +9960,10 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
"mixed_filament_surface_indentation"
};
preset_bundle->project_config.apply_only(config_loaded, imported_project_option_keys, true);
if (current_num_filaments != desired_physical_filaments)
if (current_num_filaments != desired_physical_filaments) {
q->confirm_auto_generated_gradients(desired_physical_filaments);
preset_bundle->set_num_filaments(unsigned(desired_physical_filaments));
else
} else
preset_bundle->update_multi_material_filament_presets();
BOOST_LOG_TRIVIAL(info) << "3MF geometry import applied imported project config"
<< " current_num_filaments=" << current_num_filaments
@@ -9948,6 +9976,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
new_colors.assign(imported_filament_colors.begin() + current_num_filaments,
imported_filament_colors.begin() + desired_physical_filaments);
}
q->confirm_auto_generated_gradients(desired_physical_filaments);
preset_bundle->set_num_filaments(unsigned(desired_physical_filaments), new_colors);
wxGetApp().plater()->on_filaments_change(desired_physical_filaments);
}
@@ -9956,6 +9985,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
int filament_size = sidebar->combos_filament().size();
while (filament_size < MAXIMUM_EXTRUDER_NUMBER && filament_size < size) {
int filament_count = filament_size + 1;
wxGetApp().plater()->confirm_auto_generated_gradients(filament_count);
wxColour new_col = Plater::get_next_color_for_filament();
std::string new_color = new_col.GetAsString(wxC2S_HTML_SYNTAX).ToStdString();
wxGetApp().preset_bundle->set_num_filaments(filament_count, new_color);
@@ -13746,6 +13776,76 @@ void Plater::priv::on_repair_model(wxCommandEvent &event)
wxGetApp().obj_list()->fix_through_netfabb();
}
bool Plater::priv::confirm_auto_generated_gradients(wxWindow *parent, size_t num_physical)
{
auto *app_config = wxGetApp().app_config;
if (app_config == nullptr)
return MixedFilamentManager::auto_generate_enabled();
const bool pref_enabled = app_config->get_bool("auto_generate_gradients");
if (!pref_enabled) {
m_last_auto_gradient_prompt_physical_count = 0;
m_last_auto_gradient_prompt_accepted = false;
MixedFilamentManager::set_auto_generate_enabled(false);
return false;
}
if (num_physical <= 4) {
m_last_auto_gradient_prompt_physical_count = 0;
m_last_auto_gradient_prompt_accepted = false;
MixedFilamentManager::set_auto_generate_enabled(true);
return true;
}
if (parent == nullptr || !parent->IsShownOnScreen()) {
m_last_auto_gradient_prompt_physical_count = 0;
m_last_auto_gradient_prompt_accepted = false;
MixedFilamentManager::set_auto_generate_enabled(true);
return true;
}
if (m_last_auto_gradient_prompt_physical_count == num_physical) {
MixedFilamentManager::set_auto_generate_enabled(m_last_auto_gradient_prompt_accepted);
return m_last_auto_gradient_prompt_accepted;
}
const size_t auto_gradient_count = num_physical * (num_physical - 1) / 2;
const wxString message = wxString::Format(
_L("Using %d physical filaments will create %d auto-generated gradients.\nDo you want to create them now?"),
int(num_physical),
int(auto_gradient_count));
const int result = MessageDialog(parent,
message,
wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Auto gradients"),
wxYES_NO | wxYES_DEFAULT | wxCENTRE | wxICON_QUESTION)
.ShowModal();
const bool accepted = result == wxID_YES;
m_last_auto_gradient_prompt_physical_count = num_physical;
m_last_auto_gradient_prompt_accepted = accepted;
MixedFilamentManager::set_auto_generate_enabled(accepted);
return accepted;
}
void Plater::priv::set_auto_generated_gradient_decision(size_t num_physical, bool create_auto_gradients)
{
m_last_auto_gradient_prompt_physical_count = num_physical;
m_last_auto_gradient_prompt_accepted = create_auto_gradients;
MixedFilamentManager::set_auto_generate_enabled(create_auto_gradients);
}
bool Plater::confirm_auto_generated_gradients(size_t num_physical)
{
return p != nullptr ? p->confirm_auto_generated_gradients(this, num_physical) : MixedFilamentManager::auto_generate_enabled();
}
void Plater::set_auto_generated_gradient_decision(size_t num_physical, bool create_auto_gradients)
{
if (p != nullptr)
p->set_auto_generated_gradient_decision(num_physical, create_auto_gradients);
else
MixedFilamentManager::set_auto_generate_enabled(create_auto_gradients);
}
void Plater::priv::on_filament_color_changed(wxCommandEvent &event)
{
//q->update_all_plate_thumbnails(true);
@@ -13760,7 +13860,9 @@ void Plater::priv::on_filament_color_changed(wxCommandEvent &event)
sidebar->auto_calc_flushing_volumes(modify_id);
}
// Regenerate mixed filaments and update the sidebar panel.
// Regenerate mixed filaments and refresh the mixed panel only. Color
// changes do not alter filament IDs, so the full on_filaments_change()
// path is unnecessary and can re-enter UI rebuilds mid-update.
wxGetApp().preset_bundle->update_multi_material_filament_presets();
sidebar->update_mixed_filament_panel();
}
@@ -19647,6 +19749,8 @@ void Plater::on_filaments_change(size_t num_filaments)
update_filament_colors_in_full_config();
const size_t old_num_filaments = sidebar().combos_filament().size();
const bool auto_generate_before = MixedFilamentManager::auto_generate_enabled();
const bool allow_auto_gradients = p->confirm_auto_generated_gradients(this, num_filaments);
auto summarize_uint_vector = [](const std::vector<unsigned int> &values, size_t max_items = 24) {
std::string out = "[";
const size_t n = std::min(values.size(), max_items);
@@ -19681,6 +19785,8 @@ void Plater::on_filaments_change(size_t num_filaments)
return out;
};
PresetBundle *preset_bundle = wxGetApp().preset_bundle;
if (preset_bundle != nullptr && auto_generate_before && !allow_auto_gradients)
preset_bundle->update_multi_material_filament_presets(size_t(-1), old_num_filaments);
// Consume remap before sidebar refresh, which may trigger config sync
// paths that regenerate mixed filaments and clear this remap buffer.
std::vector<unsigned int> id_remap;