improved mixed filament ui perf

This commit is contained in:
Rad
2026-03-10 20:55:16 +01:00
parent dd9945747f
commit f1a4ff6116
3 changed files with 79 additions and 53 deletions

View File

@@ -10,10 +10,18 @@
#include <sstream>
#include <iomanip>
#include <numeric>
#include <set>
#include <unordered_map>
#include <unordered_set>
namespace Slic3r {
static uint64_t canonical_pair_key(unsigned int a, unsigned int b)
{
const unsigned int lo = std::min(a, b);
const unsigned int hi = std::max(a, b);
return (uint64_t(lo) << 32) | uint64_t(hi);
}
// ---------------------------------------------------------------------------
// Colour helpers (internal)
// ---------------------------------------------------------------------------
@@ -738,9 +746,13 @@ void MixedFilamentManager::auto_generate(const std::vector<std::string> &filamen
std::vector<MixedFilament> custom_rows;
custom_rows.reserve(old.size());
std::unordered_map<uint64_t, const MixedFilament *> old_auto_rows;
old_auto_rows.reserve(old.size());
for (const MixedFilament &prev : old) {
if (!prev.custom)
if (!prev.custom) {
old_auto_rows.emplace(canonical_pair_key(prev.component_a, prev.component_b), &prev);
continue;
}
if (prev.component_a == 0 || prev.component_b == 0 || prev.component_a > n || prev.component_b > n || prev.component_a == prev.component_b)
continue;
MixedFilament custom = prev;
@@ -762,18 +774,14 @@ void MixedFilamentManager::auto_generate(const std::vector<std::string> &filamen
mf.custom = false;
mf.origin_auto = true;
// Try to preserve previous settings.
for (const auto &prev : old) {
if (!prev.custom &&
prev.component_a == mf.component_a &&
prev.component_b == mf.component_b) {
mf.enabled = prev.enabled;
mf.deleted = prev.deleted;
mf.stable_id = prev.stable_id;
if (mf.deleted)
mf.enabled = false;
break;
}
const auto it_prev = old_auto_rows.find(canonical_pair_key(mf.component_a, mf.component_b));
if (it_prev != old_auto_rows.end()) {
const MixedFilament &prev = *it_prev->second;
mf.enabled = prev.enabled;
mf.deleted = prev.deleted;
mf.stable_id = prev.stable_id;
if (mf.deleted)
mf.enabled = false;
}
mf.stable_id = normalize_stable_id(mf.stable_id);
m_mixed.push_back(mf);
@@ -931,21 +939,23 @@ void MixedFilamentManager::load_custom_entries(const std::string &serialized, co
size_t appended_auto = 0;
size_t skipped_rows = 0;
auto canonical_pair = [](unsigned int a, unsigned int b) {
return std::make_pair(std::min(a, b), std::max(a, b));
};
std::vector<MixedFilament> auto_rows;
auto_rows.reserve(m_mixed.size());
std::vector<const MixedFilament *> auto_rows_in_order;
auto_rows_in_order.reserve(m_mixed.size());
std::unordered_map<uint64_t, const MixedFilament *> auto_rows_by_pair;
auto_rows_by_pair.reserve(m_mixed.size());
for (const MixedFilament &mf : m_mixed) {
if (!mf.custom)
auto_rows.push_back(mf);
if (!mf.custom) {
auto_rows_in_order.push_back(&mf);
auto_rows_by_pair.emplace(canonical_pair_key(mf.component_a, mf.component_b), &mf);
}
}
std::vector<MixedFilament> rebuilt;
rebuilt.reserve(m_mixed.size() + 8);
std::set<std::pair<unsigned int, unsigned int>> consumed_auto_pairs;
std::set<uint64_t> used_stable_ids;
std::unordered_set<uint64_t> consumed_auto_pairs;
consumed_auto_pairs.reserve(auto_rows_by_pair.size());
std::unordered_set<uint64_t> used_stable_ids;
used_stable_ids.reserve(m_mixed.size() + 8);
auto dedupe_stable_id = [this, &used_stable_ids](uint64_t stable_id) {
stable_id = normalize_stable_id(stable_id);
if (used_stable_ids.insert(stable_id).second)
@@ -991,31 +1001,29 @@ void MixedFilamentManager::load_custom_entries(const std::string &serialized, co
}
if (!custom) {
const auto key = canonical_pair(a, b);
const uint64_t key = canonical_pair_key(a, b);
if (consumed_auto_pairs.count(key) != 0) {
++skipped_rows;
BOOST_LOG_TRIVIAL(warning) << "MixedFilamentManager::load_custom_entries duplicate auto row"
<< ", row=" << row
<< ", a=" << key.first
<< ", b=" << key.second;
<< ", a=" << std::min(a, b)
<< ", b=" << std::max(a, b);
continue;
}
auto it_auto = std::find_if(auto_rows.begin(), auto_rows.end(), [key, canonical_pair](const MixedFilament &mf) {
return canonical_pair(mf.component_a, mf.component_b) == key;
});
if (it_auto == auto_rows.end()) {
auto it_auto = auto_rows_by_pair.find(key);
if (it_auto == auto_rows_by_pair.end()) {
++skipped_rows;
BOOST_LOG_TRIVIAL(warning) << "MixedFilamentManager::load_custom_entries auto row missing after regenerate"
<< ", row=" << row
<< ", a=" << key.first
<< ", b=" << key.second;
<< ", a=" << std::min(a, b)
<< ", b=" << std::max(a, b);
continue;
}
MixedFilament mf = *it_auto;
mf.component_a = key.first;
mf.component_b = key.second;
MixedFilament mf = *it_auto->second;
mf.component_a = std::min(a, b);
mf.component_b = std::max(a, b);
mf.stable_id = dedupe_stable_id(stable_id != 0 ? stable_id : mf.stable_id);
mf.enabled = enabled;
mf.pointillism_all_filaments = pointillism_all_filaments;
@@ -1064,13 +1072,17 @@ void MixedFilamentManager::load_custom_entries(const std::string &serialized, co
// Keep any newly generated auto rows that were not present in serialized
// definitions and append them at the end to preserve existing virtual IDs.
for (const MixedFilament &auto_mf : auto_rows) {
const auto key = canonical_pair(auto_mf.component_a, auto_mf.component_b);
for (const MixedFilament *auto_mf_ptr : auto_rows_in_order) {
if (auto_mf_ptr == nullptr)
continue;
const uint64_t key = canonical_pair_key(auto_mf_ptr->component_a, auto_mf_ptr->component_b);
if (consumed_auto_pairs.count(key) != 0)
continue;
MixedFilament mf = auto_mf;
mf.component_a = key.first;
mf.component_b = key.second;
MixedFilament mf = *auto_mf_ptr;
const unsigned int lo = std::min(mf.component_a, mf.component_b);
const unsigned int hi = std::max(mf.component_a, mf.component_b);
mf.component_a = lo;
mf.component_b = hi;
mf.stable_id = dedupe_stable_id(mf.stable_id);
mf.custom = false;
mf.origin_auto = true;

View File

@@ -658,6 +658,7 @@ struct Sidebar::priv
Button* m_btn_add_pattern = nullptr; // Add pattern button
Button* m_btn_toggle_mixed_filaments = nullptr; // Collapse/expand toggle button
bool m_mixed_filaments_collapsed = false; // Collapse state
bool m_skip_mixed_filament_sync_once = false; // Local edits already mutated manager in place.
std::unordered_set<size_t> m_expanded_mixed_filament_rows; // Expanded row editors
wxStaticLine* m_staticline2;
wxPanel* m_panel_project_title;
@@ -1471,7 +1472,7 @@ Sidebar::Sidebar(Plater *parent)
// Persist the custom entries so they survive the clear/load cycle in update_mixed_filament_panel
if (ConfigOptionString *opt = wxGetApp().preset_bundle->project_config.option<ConfigOptionString>("mixed_filament_definitions"))
opt->value = mgr.serialize_custom_entries();
update_mixed_filament_panel();
update_mixed_filament_panel(false);
m_scrolled_sizer->Layout();
}
});
@@ -1497,7 +1498,7 @@ Sidebar::Sidebar(Plater *parent)
// Persist the custom entries so they survive the clear/load cycle in update_mixed_filament_panel
if (ConfigOptionString *opt = wxGetApp().preset_bundle->project_config.option<ConfigOptionString>("mixed_filament_definitions"))
opt->value = mgr.serialize_custom_entries();
update_mixed_filament_panel();
update_mixed_filament_panel(false);
m_scrolled_sizer->Layout();
}
});
@@ -2266,12 +2267,16 @@ void Sidebar::on_filaments_change(size_t num_filaments)
if (num_filaments == choices.size()) {
// Project load may keep the same physical filament count while mixed
// definitions changed. Refresh mixed panel even without count changes.
const bool sync_manager = !p->m_skip_mixed_filament_sync_once;
p->m_skip_mixed_filament_sync_once = false;
update_ui_from_settings();
update_dynamic_filament_list();
update_mixed_filament_panel();
update_mixed_filament_panel(sync_manager);
return;
}
p->m_skip_mixed_filament_sync_once = false;
if (choices.size() == 1 || num_filaments == 1)
choices[0]->GetDropDown().Invalidate();
@@ -3867,12 +3872,15 @@ void MixedFilamentConfigPanel::update_preview()
} // namespace
void Sidebar::update_mixed_filament_panel()
void Sidebar::update_mixed_filament_panel(bool sync_manager)
{
// Check for new collapsible structure
if (!p->m_panel_mixed_filaments_title || !p->m_panel_mixed_filaments_content)
return;
wxWindowUpdateLocker noUpdates_sidebar(this);
wxWindowUpdateLocker noUpdates_mixed_panel(p->m_panel_mixed_filaments_content);
auto refresh_model_canvas_colors = []() {
Plater *plater = wxGetApp().plater();
if (plater == nullptr)
@@ -4292,10 +4300,12 @@ void Sidebar::update_mixed_filament_panel()
const std::string mixed_definitions = get_mixed_string("mixed_filament_definitions");
auto &mixed_mgr = preset_bundle->mixed_filaments;
mixed_mgr.auto_generate(physical_colors);
mixed_mgr.clear_custom_entries();
mixed_mgr.load_custom_entries(mixed_definitions, physical_colors);
mixed_mgr.apply_gradient_settings(gradient_mode, lower_bound, upper_bound, advanced_dithering);
if (sync_manager) {
mixed_mgr.auto_generate(physical_colors);
mixed_mgr.clear_custom_entries();
mixed_mgr.load_custom_entries(mixed_definitions, physical_colors);
mixed_mgr.apply_gradient_settings(gradient_mode, lower_bound, upper_bound, advanced_dithering);
}
// During project load, sidebar may refresh before physical filament combos
// finish syncing. Avoid overwriting persisted mixed definitions while the
@@ -4477,8 +4487,10 @@ void Sidebar::update_mixed_filament_panel()
mgr.apply_gradient_settings(mode, lo, hi, advanced);
update_dynamic_filament_list();
if (rebuild_virtual_id_remap && wxGetApp().plater())
if (rebuild_virtual_id_remap && wxGetApp().plater()) {
p->m_skip_mixed_filament_sync_once = true;
wxGetApp().plater()->on_filaments_change(num_physical);
}
};
size_t visible_mixed_idx = 0;
@@ -4603,8 +4615,10 @@ void Sidebar::update_mixed_filament_panel()
notify_mixed_change();
if (wxGetApp().plater())
wxGetApp().plater()->update_project_dirty_from_presets();
if (wxGetApp().plater())
if (wxGetApp().plater()) {
p->m_skip_mixed_filament_sync_once = true;
wxGetApp().plater()->on_filaments_change(num_physical);
}
}
}
});

View File

@@ -156,7 +156,7 @@ public:
void edit_filament();
void on_filaments_delete(size_t filament_id);
void update_mixed_filament_panel();
void update_mixed_filament_panel(bool sync_manager = true);
// BBS
void on_bed_type_change(BedType bed_type);
void load_ams_list(std::string const & device, MachineObject* obj);
@@ -862,4 +862,4 @@ std::vector<int> get_min_flush_volumes(const DynamicPrintConfig& full_config);
} // namespace GUI
} // namespace Slic3r
#endif
#endif