NEW: Official filament color selection approved

- Add a filament picker dialog for official color selection
- Enable displaying multiple filament colors in the picker dialog and preview sidebar
- Introduce two new config options:
  - `filament_multi_colors`
  - `filament_color_types`
  to both the application config and the 3MF config

jira: STUDIO-12346

Change-Id: I66f8c1ec9147df4f5948c8a329c1737551280e63
(cherry picked from commit 522dc0bbca49033a1ba9725ca7f6c3ea729691a6)
This commit is contained in:
fei2.fang
2025-06-12 21:12:23 +08:00
committed by Noisyfox
parent 5a1dc90e8c
commit 9ee76e4775
17 changed files with 1369 additions and 82 deletions

View File

@@ -18,6 +18,7 @@
#include "Widgets/StaticBox.hpp"
#include "Widgets/Label.hpp"
#include "../Utils/WxFontUtils.hpp"
#include "FilamentBitmapUtils.hpp"
#ifndef __linux__
// msw_menuitem_bitmaps is used for MSW and OSX
static std::map<int, std::string> msw_menuitem_bitmaps;
@@ -529,27 +530,128 @@ std::vector<wxBitmap*> get_extruder_color_icons(bool thin_icon/* = false*/)
{
// Create the bitmap with color bars.
std::vector<wxBitmap*> bmps;
std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
std::vector<std::string> filaments_color_info = Slic3r::GUI::wxGetApp().plater()->get_filament_colors_render_info();
std::vector<std::string> ctype = Slic3r::GUI::wxGetApp().plater()->get_filament_color_render_type();
if (colors.empty())
return bmps;
if (!filaments_color_info.empty() && !ctype.empty() && ctype.size() == filaments_color_info.size()) {
std::vector<std::vector<std::string>> readable_color_info = read_color_pack(filaments_color_info);
/* It's supposed that standard size of an icon is 36px*16px for 100% scaled display.
* So set sizes for solid_colored icons used for filament preset
* and scale them in respect to em_unit value
*/
const double em = Slic3r::GUI::wxGetApp().em_unit();
const int icon_width = lround((thin_icon ? 2 : 4.4) * em);
const int icon_height = lround(2 * em);
/* It's supposed that standard size of an icon is 36px*16px for 100% scaled display.
* So set sizes for solid_colored icons used for filament preset
* and scale them in respect to em_unit value
*/
const double em = Slic3r::GUI::wxGetApp().em_unit();
const int icon_width = lround((thin_icon ? 2 : 4.4) * em);
const int icon_height = lround(2 * em);
int index = 0;
for (const auto &colors : readable_color_info) {
auto label = std::to_string(++index);
bool is_gradient = ctype[index-1] == "0";
if (colors.size() == 1) {
bmps.push_back(get_extruder_color_icon(colors[0], label, icon_width, icon_height));
} else {
bmps.push_back(get_extruder_color_icon(colors, is_gradient, label, icon_width, icon_height));
}
}
} else {
std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
if (colors.empty()) return bmps;
int index = 0;
for (const std::string &color : colors)
{
auto label = std::to_string(++index);
bmps.push_back(get_extruder_color_icon(color, label, icon_width, icon_height));
const double em = Slic3r::GUI::wxGetApp().em_unit();
const int icon_width = lround((thin_icon ? 2 : 4.4) * em);
const int icon_height = lround(2 * em);
int index = 0;
for (const auto &color : colors) {
auto label = std::to_string(++index);
bmps.push_back(get_extruder_color_icon(color, label, icon_width, icon_height));
}
}
return bmps;
}
std::vector<std::vector<std::string>> read_color_pack(std::vector<std::string> color_pack) {
std::vector<std::vector<std::string>> color_info;
for (const std::string &color : color_pack) {
std::vector<std::string> colors;
colors = Slic3r::split_string(color, ' ');
color_info.push_back(colors);
}
return color_info;
}
wxBitmap *get_extruder_color_icon(std::vector<std::string> colors, bool is_gradient, std::string label, int icon_width, int icon_height){
static Slic3r::GUI::BitmapCache bmp_cache;
// build cache key, include all color info
std::string bitmap_key = "";
for (const auto& color : colors) {
bitmap_key += color + "_";
}
bitmap_key += "h" + std::to_string(icon_height) + "-w" + std::to_string(icon_width) + "-i" + label;
wxBitmap *bitmap = bmp_cache.find(bitmap_key);
if (bitmap == nullptr) {
std::vector<wxColour> wx_colors;
for (const auto& color_str : colors) {
wx_colors.push_back(wxColour(color_str));
}
// create filament bitmap in multi color
wxBitmap base_bitmap = Slic3r::GUI::create_filament_bitmap(wx_colors, wxSize(icon_width, icon_height), is_gradient);
if (!base_bitmap.IsOk()) {
// if create failed, return nullptr
return nullptr;
}
// add text label directly on base_bitmap
if (!label.empty()) {
#ifndef __WXMSW__
wxMemoryDC dc(base_bitmap);
#else
wxClientDC cdc((wxWindow *) Slic3r::GUI::wxGetApp().mainframe);
wxMemoryDC dc(&cdc);
dc.SelectObject(base_bitmap);
#endif
// Ensure no background contamination
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetFont(::Label::Body_12);
Slic3r::GUI::WxFontUtils::get_suitable_font_size(icon_height - 2, dc);
auto size = dc.GetTextExtent(wxString(label));
// Set transparent background mode for text rendering
dc.SetBackgroundMode(wxTRANSPARENT);
// draw text with black border effect
int text_x = (icon_width - size.x) / 2;
int text_y = (icon_height - size.y) / 2;
// Draw very thin border with lighter color and fewer directions
dc.SetTextForeground(wxColor("262E30")); // Semi-transparent dark gray
dc.DrawText(label, text_x - 1, text_y); // Left
dc.DrawText(label, text_x + 1, text_y); // Right
dc.DrawText(label, text_x, text_y - 1); // Up
dc.DrawText(label, text_x, text_y + 1); // Down
// Draw main white text on top
dc.SetTextForeground(*wxWHITE);
dc.DrawText(label, text_x, text_y);
dc.SelectObject(wxNullBitmap);
}
// cache result
bitmap = bmp_cache.insert(bitmap_key, base_bitmap);
}
return bitmap;
}
wxBitmap *get_extruder_color_icon(std::string color, std::string label, int icon_width, int icon_height)
@@ -601,7 +703,6 @@ wxBitmap *get_extruder_color_icon(std::string color, std::string label, int icon
}
return bitmap;
}
void apply_extruder_selector(Slic3r::GUI::BitmapComboBox** ctrl,
wxWindow* parent,
const std::string& first_item/* = ""*/,