diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 0580b0df50..6f1d87bc2e 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -61,6 +61,7 @@ #include #include #include +#include #include // We are using quite an old TBB 2017 U7, which does not support global control API officially. @@ -343,7 +344,10 @@ void set_log_path_and_level(const std::string& file, unsigned int level) // Keep g_data_dir fallback for non-Windows or missing environment. boost::filesystem::path log_folder = boost::filesystem::path(g_data_dir) / "log"; #ifdef _WIN32 - if (const char *local_appdata = std::getenv("LOCALAPPDATA"); local_appdata != nullptr && *local_appdata != '\0') + // boost::filesystem is configured to interpret narrow paths as UTF-8. + // On Windows, std::getenv() may return ANSI-encoded bytes, which breaks + // non-ASCII profile paths (for example usernames containing umlauts). + if (const char *local_appdata = boost::nowide::getenv("LOCALAPPDATA"); local_appdata != nullptr && *local_appdata != '\0') log_folder = boost::filesystem::path(local_appdata) / "Snapmaker_Orca" / "log"; #endif if (!boost::filesystem::exists(log_folder)) { diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b0c2152336..a82ba4f734 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3235,26 +3235,40 @@ std::string MixedFilamentConfigPanel::summarize_sequence(const std::vector &colors, const std::vector &seq, const std::string &fallback) { - if (seq.empty()) return fallback; - std::unordered_map counts; - for (unsigned int id : seq) counts[id]++; - double r = 0, g = 0, b = 0; - int total = 0; - for (auto &kv : counts) { - unsigned int id = kv.first; - int cnt = kv.second; - std::string hex = (id >= 1 && id <= colors.size()) ? colors[id - 1] : fallback; - wxColour c(hex); - if (c.IsOk()) { - r += c.Red() * cnt; - g += c.Green() * cnt; - b += c.Blue() * cnt; - total += cnt; + if (colors.empty() || seq.empty()) + return fallback; + + std::vector counts(colors.size() + 1, size_t(0)); + size_t total = 0; + for (const unsigned int id : seq) { + if (id == 0 || id > colors.size()) + continue; + ++counts[id]; + ++total; + } + if (total == 0) + return fallback; + + unsigned int first_id = 0; + for (size_t id = 1; id <= colors.size(); ++id) { + if (counts[id] > 0) { + first_id = unsigned(id); + break; } } - if (total <= 0) return fallback; - wxColour blended(int(r / total), int(g / total), int(b / total)); - return blended.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(); + if (first_id == 0 || first_id > colors.size()) + return fallback; + + std::string blended = colors[first_id - 1]; + int acc = int(counts[first_id]); + for (size_t id = size_t(first_id + 1); id <= colors.size(); ++id) { + if (counts[id] == 0) + continue; + blended = MixedFilamentManager::blend_color(blended, colors[id - 1], acc, int(counts[id])); + acc += int(counts[id]); + } + + return blended; } MixedFilamentConfigPanel::MixedFilamentConfigPanel(wxWindow *parent, @@ -4160,6 +4174,42 @@ void Sidebar::update_mixed_filament_panel() } return blended; }; + auto build_entry_preview_sequence = [decode_manual_pattern_ids, decode_gradient_ids, decode_gradient_weights, + build_weighted_multi_sequence, build_weighted_pair_sequence](const MixedFilament &entry) { + const std::string normalized_pattern = MixedFilamentManager::normalize_manual_pattern(entry.manual_pattern); + if (!normalized_pattern.empty()) + return decode_manual_pattern_ids(normalized_pattern, entry.component_a, entry.component_b); + + const bool simple_mode = entry.distribution_mode == int(MixedFilament::Simple); + if (!simple_mode) { + const std::vector gradient_ids = decode_gradient_ids(entry.gradient_component_ids); + if (gradient_ids.size() >= 3) { + const std::vector gradient_weights = + decode_gradient_weights(entry.gradient_component_weights, gradient_ids.size()); + return build_weighted_multi_sequence(gradient_ids, gradient_weights); + } + } + + return build_weighted_pair_sequence(entry.component_a, entry.component_b, std::clamp(entry.mix_b_percent, 0, 100)); + }; + auto compute_entry_display_color = [num_physical, &physical_colors, blend_from_sequence, build_entry_preview_sequence](const MixedFilament &entry) { + const std::vector sequence = build_entry_preview_sequence(entry); + if (!sequence.empty()) + return blend_from_sequence(physical_colors, sequence, "#26A69A"); + + if (entry.component_a == 0 || entry.component_b == 0 || + entry.component_a > num_physical || entry.component_b > num_physical || + entry.component_a > physical_colors.size() || entry.component_b > physical_colors.size()) { + return std::string("#26A69A"); + } + + const int mix_b = std::clamp(entry.mix_b_percent, 0, 100); + return MixedFilamentManager::blend_color( + physical_colors[entry.component_a - 1], + physical_colors[entry.component_b - 1], + 100 - mix_b, + mix_b); + }; const bool height_weighted_mode = get_mixed_mode(false); int gradient_mode = height_weighted_mode ? 1 : 0; @@ -4368,8 +4418,11 @@ void Sidebar::update_mixed_filament_panel() auto *header_panel = new wxPanel(row, wxID_ANY); header_panel->SetBackgroundColour(mixed_row_bg); auto *header_sizer = new wxBoxSizer(wxHORIZONTAL); - - wxColour swatch_color(mf.display_color); + + const std::string synced_color = compute_entry_display_color(mf); + if (mf.display_color != synced_color) + mf.display_color = synced_color; + wxColour swatch_color = parse_mixed_color(mf.display_color); auto *swatch = new wxPanel(header_panel, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(12), FromDIP(12))); swatch->SetBackgroundColour(swatch_color); swatch->SetMinSize(wxSize(FromDIP(12), FromDIP(12))); @@ -4475,7 +4528,7 @@ void Sidebar::update_mixed_filament_panel() apply_mixed_entry_changes(mixed_id, updated_mf, true); if (swatch) { - swatch->SetBackgroundColour(wxColour(updated_mf.display_color)); + swatch->SetBackgroundColour(parse_mixed_color(updated_mf.display_color)); swatch->Refresh(); } if (summary_label) {