mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2026-01-26 15:07:33 -07:00
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:
parent
5a1dc90e8c
commit
9ee76e4775
17 changed files with 1369 additions and 82 deletions
|
|
@ -683,8 +683,11 @@ std::string AppConfig::load()
|
|||
m_filament_presets = iter.value().get<std::vector<std::string>>();
|
||||
} else if (iter.key() == "filament_colors") {
|
||||
m_filament_colors = iter.value().get<std::vector<std::string>>();
|
||||
}
|
||||
else {
|
||||
} else if(iter.key() == "filament_multi_colors") {
|
||||
m_filament_multi_colors = iter.value().get<std::vector<std::string>>();
|
||||
} else if(iter.key() == "filament_color_types") {
|
||||
m_filament_color_types = iter.value().get<std::vector<std::string>>();
|
||||
} else {
|
||||
if (iter.value().is_string())
|
||||
m_storage[it.key()][iter.key()] = iter.value().get<std::string>();
|
||||
else {
|
||||
|
|
@ -768,6 +771,13 @@ void AppConfig::save()
|
|||
for (const auto &filament_color : m_filament_colors) {
|
||||
j["app"]["filament_colors"].push_back(filament_color);
|
||||
}
|
||||
for (const auto &filament_multi_color : m_filament_multi_colors) {
|
||||
j["app"]["filament_multi_colors"].push_back(filament_multi_color);
|
||||
}
|
||||
|
||||
for (const auto &filament_color_type : m_filament_color_types) {
|
||||
j["app"]["filament_color_types"].push_back(filament_color_type);
|
||||
}
|
||||
|
||||
for (const auto &cali_info : m_printer_cali_infos) {
|
||||
json cali_json;
|
||||
|
|
@ -803,7 +813,7 @@ void AppConfig::save()
|
|||
} else if (category.first == "presets") {
|
||||
json j_filament_array;
|
||||
for(const auto& kvp : category.second) {
|
||||
if (boost::starts_with(kvp.first, "filament") && kvp.first != "filament_colors") {
|
||||
if (boost::starts_with(kvp.first, "filament") && kvp.first != "filament_colors" && kvp.first != "filament_multi_colors" && kvp.first != "filament_color_types") {
|
||||
j_filament_array.push_back(kvp.second);
|
||||
} else {
|
||||
j[category.first][kvp.first] = kvp.second;
|
||||
|
|
|
|||
|
|
@ -383,6 +383,8 @@ private:
|
|||
|
||||
std::vector<std::string> m_filament_presets;
|
||||
std::vector<std::string> m_filament_colors;
|
||||
std::vector<std::string> m_filament_multi_colors;
|
||||
std::vector<std::string> m_filament_color_types;
|
||||
|
||||
std::vector<PrinterCaliInfo> m_printer_cali_infos;
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ static std::vector<std::string> s_project_options {
|
|||
"flush_volumes_matrix",
|
||||
// BBS
|
||||
"filament_colour",
|
||||
"filament_colour_type",
|
||||
"filament_multi_colour",
|
||||
"wipe_tower_x",
|
||||
"wipe_tower_y",
|
||||
"wipe_tower_rotation_angle",
|
||||
|
|
@ -1787,6 +1789,8 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
|
|||
break;
|
||||
this->filament_presets.emplace_back(remove_ini_suffix(f_name));
|
||||
}
|
||||
|
||||
// Load data from AppConfig to ProjectConfig when Studio is initialized.
|
||||
std::vector<std::string> filament_colors;
|
||||
auto f_colors = config.get_printer_setting(initial_printer_profile_name, "filament_colors");
|
||||
if (!f_colors.empty()) {
|
||||
|
|
@ -1795,6 +1799,20 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
|
|||
filament_colors.resize(filament_presets.size(), "#26A69A");
|
||||
project_config.option<ConfigOptionStrings>("filament_colour")->values = filament_colors;
|
||||
|
||||
std::vector<std::string> multi_filament_colors;
|
||||
if (config.has("presets", "filament_multi_colors")) {
|
||||
boost::algorithm::split(multi_filament_colors, config.get("presets", "filament_multi_colors"), boost::algorithm::is_any_of(","));
|
||||
}
|
||||
if (multi_filament_colors.size() == 0) project_config.option<ConfigOptionStrings>("filament_multi_colour")->values = filament_colors;
|
||||
else project_config.option<ConfigOptionStrings>("filament_multi_colour")->values = multi_filament_colors;
|
||||
|
||||
std::vector<std::string> filament_color_types;
|
||||
if (config.has("presets", "filament_color_types")) {
|
||||
boost::algorithm::split(filament_color_types, config.get("presets", "filament_color_types"), boost::algorithm::is_any_of(","));
|
||||
}
|
||||
filament_color_types.resize(filament_presets.size(), "1");
|
||||
project_config.option<ConfigOptionStrings>("filament_colour_type")->values = filament_color_types;
|
||||
|
||||
std::vector<int> filament_maps(filament_colors.size(), 1);
|
||||
project_config.option<ConfigOptionInts>("filament_map")->values = filament_maps;
|
||||
|
||||
|
|
@ -1884,7 +1902,7 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
|
|||
}
|
||||
|
||||
// Export selections (current print, current filaments, current printer) into config.ini
|
||||
//BBS: change directories by design
|
||||
// BBS: change directories by design
|
||||
void PresetBundle::export_selections(AppConfig &config)
|
||||
{
|
||||
assert(this->printers.get_edited_preset().printer_technology() != ptFFF || filament_presets.size() >= 1);
|
||||
|
|
@ -1904,10 +1922,19 @@ void PresetBundle::export_selections(AppConfig &config)
|
|||
sprintf(name, "filament_%02u", i);
|
||||
config.set_printer_setting(printer_name, name, filament_presets[i]);
|
||||
}
|
||||
// Load project config data into app config
|
||||
CNumericLocalesSetter locales_setter;
|
||||
std::string filament_colors = boost::algorithm::join(project_config.option<ConfigOptionStrings>("filament_colour")->values, ",");
|
||||
config.set_printer_setting(printer_name, "filament_colors", filament_colors);
|
||||
|
||||
// Load filament multi color data into app config
|
||||
std::string filament_multi_colors = boost::algorithm::join(project_config.option<ConfigOptionStrings>("filament_multi_colour")->values, ",");
|
||||
config.set("presets", "filament_multi_colors", filament_multi_colors);
|
||||
|
||||
// Load filament color type data into app config
|
||||
std::string filament_color_types = boost::algorithm::join(project_config.option<ConfigOptionStrings>("filament_colour_type")->values, ",");
|
||||
config.set("presets", "filament_color_types", filament_color_types);
|
||||
|
||||
std::string flush_volumes_matrix = boost::algorithm::join(project_config.option<ConfigOptionFloats>("flush_volumes_matrix")->values |
|
||||
boost::adaptors::transformed(static_cast<std::string (*)(double)>(std::to_string)),
|
||||
"|");
|
||||
|
|
@ -1960,10 +1987,13 @@ void PresetBundle::set_num_filaments(unsigned int n, std::string new_color)
|
|||
else {
|
||||
filament_presets.resize(n);
|
||||
}
|
||||
|
||||
ConfigOptionStrings* filament_color = project_config.option<ConfigOptionStrings>("filament_colour");
|
||||
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
||||
ConfigOptionStrings* filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
||||
ConfigOptionInts* filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
||||
filament_color->resize(n);
|
||||
filament_multi_color->resize(n);
|
||||
filament_color_type->resize(n);
|
||||
filament_map->values.resize(n, 1);
|
||||
ams_multi_color_filment.resize(n);
|
||||
|
||||
|
|
@ -1972,6 +2002,8 @@ void PresetBundle::set_num_filaments(unsigned int n, std::string new_color)
|
|||
if (!new_color.empty()) {
|
||||
for (int i = old_filament_count; i < n; i++) {
|
||||
filament_color->values[i] = new_color;
|
||||
filament_multi_color->values[i] = new_color;
|
||||
filament_color_type->values[i] = "1"; // default color type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2000,8 +2032,9 @@ void PresetBundle::update_num_filaments(unsigned int to_del_flament_id)
|
|||
}
|
||||
|
||||
ConfigOptionStrings *filament_color = project_config.option<ConfigOptionStrings>("filament_colour");
|
||||
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
||||
ConfigOptionStrings *filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
||||
ConfigOptionInts* filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
||||
|
||||
if (filament_color->values.size() > to_del_flament_id) {
|
||||
filament_color->values.erase(filament_color->values.begin() + to_del_flament_id);
|
||||
if (filament_map->values.size() > to_del_flament_id) {
|
||||
|
|
@ -2013,12 +2046,18 @@ void PresetBundle::update_num_filaments(unsigned int to_del_flament_id)
|
|||
filament_map->values.resize(to_del_flament_id, 1);
|
||||
}
|
||||
|
||||
if (ams_multi_color_filment.size() > to_del_flament_id){
|
||||
ams_multi_color_filment.erase(ams_multi_color_filment.begin() + to_del_flament_id);
|
||||
}
|
||||
else {
|
||||
ams_multi_color_filment.resize(to_del_flament_id);
|
||||
}
|
||||
// lambda function to erase or resize the container
|
||||
auto erase_or_resize = [to_del_flament_id](auto& container) {
|
||||
if (container.size() > to_del_flament_id) {
|
||||
container.erase(container.begin() + to_del_flament_id);
|
||||
} else {
|
||||
container.resize(to_del_flament_id);
|
||||
}
|
||||
};
|
||||
|
||||
erase_or_resize(filament_multi_color->values);
|
||||
erase_or_resize(filament_color_type->values);
|
||||
erase_or_resize(ams_multi_color_filment);
|
||||
|
||||
update_multi_material_filament_presets(to_del_flament_id);
|
||||
}
|
||||
|
|
@ -2033,7 +2072,7 @@ void PresetBundle::get_ams_cobox_infos(AMSComboInfo& combox_info)
|
|||
auto filament_color = ams.opt_string("filament_colour", 0u);
|
||||
auto ams_name = ams.opt_string("tray_name", 0u);
|
||||
auto filament_changed = !ams.has("filament_changed") || ams.opt_bool("filament_changed");
|
||||
auto filament_multi_color = ams.opt<ConfigOptionStrings>("filament_multi_colors")->values;
|
||||
auto filament_multi_color = ams.opt<ConfigOptionStrings>("filament_multi_colour")->values;
|
||||
if (filament_id.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -2081,6 +2120,7 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "use_map:" << use_map << " enable_append:" << enable_append;
|
||||
std::vector<std::string> ams_filament_presets;
|
||||
std::vector<std::string> ams_filament_colors;
|
||||
std::vector<std::string> ams_filament_color_types;
|
||||
std::vector<AMSMapInfo> ams_array_maps;
|
||||
ams_multi_color_filment.clear();
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": filament_ams_list size: %1%") % filament_ams_list.size();
|
||||
|
|
@ -2089,6 +2129,7 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||
bool valid{false};
|
||||
bool is_map{false};
|
||||
std::string filament_color = "";
|
||||
std::string filament_color_type = "";
|
||||
std::string filament_preset = "";
|
||||
std::vector<std::string> mutli_filament_color;
|
||||
};
|
||||
|
|
@ -2099,8 +2140,9 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||
auto & ams = entry.second;
|
||||
auto filament_id = ams.opt_string("filament_id", 0u);
|
||||
auto filament_color = ams.opt_string("filament_colour", 0u);
|
||||
auto filament_color_type = ams.opt_string("filament_colour_type", 0u);
|
||||
auto filament_changed = !ams.has("filament_changed") || ams.opt_bool("filament_changed");
|
||||
auto filament_multi_color = ams.opt<ConfigOptionStrings>("filament_multi_colors")->values;
|
||||
auto filament_multi_color = ams.opt<ConfigOptionStrings>("filament_multi_colour")->values;
|
||||
auto ams_id = ams.opt_string("ams_id", 0u);
|
||||
auto slot_id = ams.opt_string("slot_id", 0u);
|
||||
ams_infos.push_back({filament_id.empty() ? false : true,false, filament_color});
|
||||
|
|
@ -2117,6 +2159,7 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||
ams_filament_presets.push_back("Generic PLA");//for unknow matieral
|
||||
auto default_unknown_color = "#CECECE";
|
||||
ams_filament_colors.push_back(default_unknown_color);
|
||||
ams_filament_color_types.push_back("1");
|
||||
if (filament_multi_color.size() == 0) {
|
||||
filament_multi_color.push_back(default_unknown_color);
|
||||
}
|
||||
|
|
@ -2127,6 +2170,7 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||
if (!filament_changed && this->filament_presets.size() > ams_filament_presets.size()) {
|
||||
ams_filament_presets.push_back(this->filament_presets[ams_filament_presets.size()]);
|
||||
ams_filament_colors.push_back(filament_color);
|
||||
ams_filament_color_types.push_back(filament_color_type);
|
||||
ams_multi_color_filment.push_back(filament_multi_color);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -2149,6 +2193,7 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||
if (ams_filament_presets.size() < this->filament_presets.size()) {
|
||||
ams_filament_presets.push_back(this->filament_presets[ams_filament_presets.size()]);
|
||||
ams_filament_colors.push_back(filament_color);
|
||||
ams_filament_color_types.push_back(filament_color_type);
|
||||
ams_multi_color_filment.push_back(filament_multi_color);
|
||||
unknowns.emplace_back(&ams, has_type ? L("The filament may not be compatible with the current machine settings. Generic filament presets will be used.") :
|
||||
L("The filament model is unknown. Still using the previous filament preset."));
|
||||
|
|
@ -2169,12 +2214,14 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||
}
|
||||
ams_filament_presets.push_back(iter->name);
|
||||
ams_filament_colors.push_back(filament_color);
|
||||
ams_filament_color_types.push_back(filament_color_type);
|
||||
ams_multi_color_filment.push_back(filament_multi_color);
|
||||
}
|
||||
if (ams_filament_presets.empty())
|
||||
return 0;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "get filament_colour and from config";
|
||||
ConfigOptionStrings *filament_color = project_config.option<ConfigOptionStrings>("filament_colour");
|
||||
ConfigOptionStrings *filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
||||
ConfigOptionInts * filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
||||
if (use_map) {
|
||||
auto check_has_merge_info = [](std::map<int, AMSMapInfo> &maps, MergeFilamentInfo &merge_info, int exist_colors_size) {
|
||||
|
|
@ -2211,6 +2258,7 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||
};
|
||||
std::vector<AmsInfo> need_append_colors;
|
||||
auto exist_colors = filament_color->values;
|
||||
auto exist_color_types = filament_color_type->values;
|
||||
auto exist_filament_presets = this->filament_presets;
|
||||
std::vector<std::vector<std::string>> exist_multi_color_filment;
|
||||
exist_multi_color_filment.resize(exist_colors.size());
|
||||
|
|
@ -2222,6 +2270,7 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||
auto valid_index = get_map_index(ams_array_maps, maps[i]);
|
||||
if (valid_index >= 0 && valid_index < ams_filament_presets.size()) {
|
||||
exist_colors[i] = ams_filament_colors[valid_index];
|
||||
exist_color_types[i] = ams_filament_color_types[valid_index];
|
||||
exist_filament_presets[i] = ams_filament_presets[valid_index];
|
||||
exist_multi_color_filment[i] = ams_multi_color_filment[valid_index];
|
||||
} else {
|
||||
|
|
@ -2240,12 +2289,14 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||
if (!ams_infos[i].is_map) {
|
||||
need_append_colors.emplace_back(ams_infos[i]);
|
||||
ams_filament_colors[i] = "";
|
||||
ams_filament_color_types[i] = "";
|
||||
ams_filament_presets[i] = "";
|
||||
ams_multi_color_filment[i] = std::vector<std::string>();
|
||||
}
|
||||
}
|
||||
else {
|
||||
ams_filament_colors[i] = "";
|
||||
ams_filament_color_types[i] = "";
|
||||
ams_filament_presets[i] = "";
|
||||
ams_multi_color_filment[i] = std::vector<std::string>();
|
||||
}
|
||||
|
|
@ -2253,6 +2304,8 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||
//delete redundant color
|
||||
ams_filament_colors.erase(std::remove_if(ams_filament_colors.begin(), ams_filament_colors.end(), [](std::string &value) { return value.empty(); }),
|
||||
ams_filament_colors.end());
|
||||
ams_filament_color_types.erase(std::remove_if(ams_filament_color_types.begin(), ams_filament_color_types.end(), [](std::string &value) { return value.empty(); }),
|
||||
ams_filament_color_types.end());
|
||||
ams_filament_presets.erase(std::remove_if(ams_filament_presets.begin(), ams_filament_presets.end(), [](std::string &value) { return value.empty(); }),
|
||||
ams_filament_presets.end());
|
||||
ams_multi_color_filment.erase(std::remove_if(ams_multi_color_filment.begin(), ams_multi_color_filment.end(),
|
||||
|
|
@ -2278,11 +2331,14 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||
}
|
||||
exist_filament_presets.push_back(need_append_colors[i].filament_preset);
|
||||
exist_colors.push_back(need_append_colors[i].filament_color);
|
||||
exist_color_types.push_back(need_append_colors[i].filament_color_type);
|
||||
exist_multi_color_filment.push_back(need_append_colors[i].mutli_filament_color);
|
||||
}
|
||||
}
|
||||
filament_color->resize(exist_colors.size());
|
||||
filament_color->values = exist_colors;
|
||||
filament_color_type->resize(exist_colors.size());
|
||||
filament_color_type->values = exist_color_types;
|
||||
ams_multi_color_filment = exist_multi_color_filment;
|
||||
this->filament_presets = exist_filament_presets;
|
||||
filament_map->values.resize(exist_filament_presets.size(), 1);
|
||||
|
|
@ -2290,15 +2346,39 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||
else {//overwrite
|
||||
filament_color->resize(ams_filament_presets.size());
|
||||
filament_color->values = ams_filament_colors;
|
||||
filament_color_type->resize(ams_filament_presets.size());
|
||||
filament_color_type->values = ams_filament_color_types;
|
||||
this->filament_presets = ams_filament_presets;
|
||||
filament_map->values.resize(ams_filament_colors.size(), 1);
|
||||
}
|
||||
|
||||
// Update ams_multi_color_filment
|
||||
update_filament_multi_color();
|
||||
update_multi_material_filament_presets();
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "finish sync ams list";
|
||||
return this->filament_presets.size();
|
||||
}
|
||||
|
||||
void PresetBundle::update_filament_multi_color()
|
||||
{
|
||||
std::vector<std::string> exsit_multi_colors;
|
||||
for (auto &fil_item : ams_multi_color_filment){
|
||||
if (fil_item.empty()) break;
|
||||
if (fil_item.size() == 1)
|
||||
exsit_multi_colors.push_back(fil_item[0]);
|
||||
else {
|
||||
std::string colors = "";
|
||||
for (auto &color : fil_item){
|
||||
colors += color + " ";
|
||||
}
|
||||
colors.erase(colors.size() - 1); // remove last space
|
||||
exsit_multi_colors.push_back(colors);
|
||||
}
|
||||
}
|
||||
ConfigOptionStrings *filament_multi_colour = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
||||
filament_multi_colour->resize(exsit_multi_colors.size());
|
||||
filament_multi_colour->values = exsit_multi_colors;
|
||||
}
|
||||
|
||||
std::vector<int> PresetBundle::get_used_tpu_filaments(const std::vector<int> &used_filaments)
|
||||
{
|
||||
std::vector<int> tpu_filaments;
|
||||
|
|
|
|||
|
|
@ -355,6 +355,8 @@ private:
|
|||
std::pair<PresetsConfigSubstitutions, std::string> load_system_presets_from_json(ForwardCompatibilitySubstitutionRule compatibility_rule);
|
||||
// Merge one vendor's presets with the other vendor's presets, report duplicates.
|
||||
std::vector<std::string> merge_presets(PresetBundle &&other);
|
||||
// Update the multicolor information for filaments.
|
||||
void update_filament_multi_color();
|
||||
// Update renamed_from and alias maps of system profiles.
|
||||
void update_system_maps();
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ namespace Slic3r {
|
|||
|
||||
const std::vector<std::string> filament_extruder_override_keys = {
|
||||
// floats
|
||||
"filament_retraction_length",
|
||||
"filament_retraction_length",
|
||||
"filament_z_hop",
|
||||
"filament_z_hop_types",
|
||||
"filament_retract_lift_above",
|
||||
|
|
@ -2164,6 +2164,14 @@ void PrintConfigDef::init_fff_params()
|
|||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionStrings { "" });
|
||||
|
||||
|
||||
def = this->add("filament_multi_colour", coStrings);
|
||||
def->set_default_value(new ConfigOptionStrings{""});
|
||||
|
||||
// 0: gradient color, 1: default color(single or multi color)
|
||||
def = this->add("filament_colour_type", coStrings);
|
||||
def->set_default_value(new ConfigOptionStrings{"1"}); // Init as default color
|
||||
|
||||
//bbs
|
||||
def = this->add("required_nozzle_HRC", coInts);
|
||||
def->label = L("Required nozzle HRC");
|
||||
|
|
|
|||
|
|
@ -241,6 +241,10 @@ set(SLIC3R_GUI_SOURCES
|
|||
GUI/ImageGrid.cpp
|
||||
GUI/ImageGrid.h
|
||||
GUI/ImGuiWrapper.cpp
|
||||
GUI/FilamentPickerDialog.cpp
|
||||
GUI/FilamentPickerDialog.hpp
|
||||
GUI/FilamentBitmapUtils.cpp
|
||||
GUI/FilamentBitmapUtils.hpp
|
||||
GUI/BaseTransparentDPIFrame.cpp
|
||||
GUI/BaseTransparentDPIFrame.hpp
|
||||
GUI/SyncAmsInfoDialog.cpp
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ private:
|
|||
/* loaded info*/
|
||||
std::string m_fila_path;
|
||||
|
||||
std::unordered_map<wxString, FilamentColorCodes*>* m_fila_id2colors_map; //
|
||||
std::unordered_map<wxString, FilamentColorCodes*>* m_fila_id2colors_map; //
|
||||
};
|
||||
|
||||
// EncodedFilaColorsInfo class holds a mapping of filament codes to specific filamet type
|
||||
|
|
@ -201,7 +201,7 @@ public:
|
|||
public:
|
||||
wxString GetFilaCode() const { return m_owner->GetFilaCode(); }
|
||||
wxString GetFilaType() const { return m_owner->GetFilaType(); }
|
||||
|
||||
|
||||
|
||||
wxString GetFilaColorCode() const { return m_fila_color_code; } // eg. Q01B00
|
||||
FilamentColor GetFilaColor() const { return m_fila_color; }
|
||||
|
|
|
|||
184
src/slic3r/GUI/FilamentBitmapUtils.cpp
Normal file
184
src/slic3r/GUI/FilamentBitmapUtils.cpp
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
#include <wx/dcmemory.h>
|
||||
#include <wx/graphics.h>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include "EncodedFilament.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
// Helper struct to hold bitmap and DC
|
||||
struct BitmapDC {
|
||||
wxBitmap bitmap;
|
||||
wxMemoryDC dc;
|
||||
|
||||
BitmapDC(const wxSize& size) : bitmap(size), dc(bitmap) {
|
||||
// Don't set white background - let the color patterns fill the entire area
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
}
|
||||
};
|
||||
|
||||
static BitmapDC init_bitmap_dc(const wxSize& size) {
|
||||
return BitmapDC(size);
|
||||
}
|
||||
|
||||
// Sort colors by HSV values (primarily by hue, then saturation, then value)
|
||||
static void sort_colors_by_hsv(std::vector<wxColour>& colors) {
|
||||
if (colors.size() < 2) return;
|
||||
std::sort(colors.begin(), colors.end(),
|
||||
[](const wxColour& a, const wxColour& b) {
|
||||
ColourHSV ha = wxColourToHSV(a);
|
||||
ColourHSV hb = wxColourToHSV(b);
|
||||
if (ha.h != hb.h) return ha.h < hb.h;
|
||||
if (ha.s != hb.s) return ha.s < hb.s;
|
||||
return ha.v < hb.v;
|
||||
});
|
||||
}
|
||||
|
||||
static wxBitmap create_single_filament_bitmap(const wxColour& color, const wxSize& size)
|
||||
{
|
||||
BitmapDC bdc = init_bitmap_dc(size);
|
||||
if (!bdc.dc.IsOk()) return wxNullBitmap;
|
||||
|
||||
bdc.dc.SetBrush(wxBrush(color));
|
||||
bdc.dc.DrawRectangle(0, 0, size.GetWidth(), size.GetHeight());
|
||||
|
||||
// Add gray border for light colors (similar to wxExtensions.cpp logic)
|
||||
if (color.Red() > 224 && color.Blue() > 224 && color.Green() > 224) {
|
||||
bdc.dc.SetPen(*wxGREY_PEN);
|
||||
bdc.dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
bdc.dc.DrawRectangle(0, 0, size.GetWidth(), size.GetHeight());
|
||||
}
|
||||
|
||||
bdc.dc.SelectObject(wxNullBitmap);
|
||||
return bdc.bitmap;
|
||||
}
|
||||
|
||||
static wxBitmap create_dual_filament_bitmap(const wxColour& color1, const wxColour& color2, const wxSize& size)
|
||||
{
|
||||
BitmapDC bdc = init_bitmap_dc(size);
|
||||
|
||||
int half_width = size.GetWidth() / 2;
|
||||
|
||||
bdc.dc.SetBrush(wxBrush(color1));
|
||||
bdc.dc.DrawRectangle(0, 0, half_width, size.GetHeight());
|
||||
|
||||
bdc.dc.SetBrush(wxBrush(color2));
|
||||
bdc.dc.DrawRectangle(half_width, 0, size.GetWidth() - half_width, size.GetHeight());
|
||||
|
||||
bdc.dc.SelectObject(wxNullBitmap);
|
||||
return bdc.bitmap;
|
||||
}
|
||||
|
||||
static wxBitmap create_triple_filament_bitmap(const std::vector<wxColour>& colors, const wxSize& size)
|
||||
{
|
||||
BitmapDC bdc = init_bitmap_dc(size);
|
||||
|
||||
int third_width = size.GetWidth() / 3;
|
||||
int remaining_width = size.GetWidth() - (third_width * 2);
|
||||
|
||||
// Draw three vertical sections
|
||||
bdc.dc.SetBrush(wxBrush(colors[0]));
|
||||
bdc.dc.DrawRectangle(0, 0, third_width, size.GetHeight());
|
||||
|
||||
bdc.dc.SetBrush(wxBrush(colors[1]));
|
||||
bdc.dc.DrawRectangle(third_width, 0, third_width, size.GetHeight());
|
||||
|
||||
bdc.dc.SetBrush(wxBrush(colors[2]));
|
||||
bdc.dc.DrawRectangle(third_width * 2, 0, remaining_width, size.GetHeight());
|
||||
|
||||
bdc.dc.SelectObject(wxNullBitmap);
|
||||
return bdc.bitmap;
|
||||
}
|
||||
|
||||
static wxBitmap create_quadruple_filament_bitmap(const std::vector<wxColour>& colors, const wxSize& size)
|
||||
{
|
||||
BitmapDC bdc = init_bitmap_dc(size);
|
||||
|
||||
int half_width = (size.GetWidth() + 1) / 2;
|
||||
int half_height = (size.GetHeight() + 1) / 2;
|
||||
|
||||
const int rects[4][4] = {
|
||||
{0, 0, half_width, half_height}, // Top left
|
||||
{half_width, 0, size.GetWidth() - half_width, half_height}, // Top right
|
||||
{0, half_height, half_width, size.GetHeight() - half_height}, // Bottom left
|
||||
{half_width, half_height, size.GetWidth() - half_width, size.GetHeight() - half_height} // Bottom right
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
bdc.dc.SetBrush(wxBrush(colors[i]));
|
||||
bdc.dc.DrawRectangle(rects[i][0], rects[i][1], rects[i][2], rects[i][3]);
|
||||
}
|
||||
|
||||
bdc.dc.SelectObject(wxNullBitmap);
|
||||
return bdc.bitmap;
|
||||
}
|
||||
|
||||
static wxBitmap create_gradient_filament_bitmap(const std::vector<wxColour>& colors, const wxSize& size)
|
||||
{
|
||||
BitmapDC bdc = init_bitmap_dc(size);
|
||||
|
||||
if (colors.size() == 1) {
|
||||
return create_single_filament_bitmap(colors[0], size);
|
||||
}
|
||||
|
||||
// use segment gradient, make transition more natural
|
||||
wxDC& dc = bdc.dc;
|
||||
int total_width = size.GetWidth();
|
||||
int height = size.GetHeight();
|
||||
|
||||
// calculate segment count
|
||||
int segment_count = colors.size() - 1;
|
||||
double segment_width = (double)total_width / segment_count;
|
||||
|
||||
int left = 0;
|
||||
for (int i = 0; i < segment_count; i++) {
|
||||
int current_width = (int)segment_width;
|
||||
|
||||
// handle last segment, ensure fully filled
|
||||
if (i == segment_count - 1) {
|
||||
current_width = total_width - left;
|
||||
}
|
||||
|
||||
// avoid width exceed boundary
|
||||
if (left + current_width > total_width) {
|
||||
current_width = total_width - left;
|
||||
}
|
||||
|
||||
if (current_width > 0) {
|
||||
auto rect = wxRect(left, 0, current_width, height);
|
||||
dc.GradientFillLinear(rect, colors[i], colors[i + 1], wxEAST);
|
||||
left += current_width;
|
||||
}
|
||||
}
|
||||
|
||||
bdc.dc.SelectObject(wxNullBitmap);
|
||||
return bdc.bitmap;
|
||||
}
|
||||
|
||||
wxBitmap create_filament_bitmap(const std::vector<wxColour>& colors, const wxSize& size, bool force_gradient)
|
||||
{
|
||||
if (colors.empty()) return wxNullBitmap;
|
||||
|
||||
// Make a copy to sort without modifying original
|
||||
std::vector<wxColour> sorted_colors = colors;
|
||||
|
||||
// Sort colors by HSV when there are 2 or more colors
|
||||
if (sorted_colors.size() >= 2) {
|
||||
sort_colors_by_hsv(sorted_colors);
|
||||
}
|
||||
|
||||
if (force_gradient && sorted_colors.size() >= 2) {
|
||||
return create_gradient_filament_bitmap(sorted_colors, size);
|
||||
}
|
||||
|
||||
switch (sorted_colors.size()) {
|
||||
case 1: return create_single_filament_bitmap(sorted_colors[0], size);
|
||||
case 2: return create_dual_filament_bitmap(sorted_colors[0], sorted_colors[1], size);
|
||||
case 3: return create_triple_filament_bitmap(sorted_colors, size);
|
||||
case 4: return create_quadruple_filament_bitmap(sorted_colors, size);
|
||||
default: return create_gradient_filament_bitmap(sorted_colors, size);
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
26
src/slic3r/GUI/FilamentBitmapUtils.hpp
Normal file
26
src/slic3r/GUI/FilamentBitmapUtils.hpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef slic3r_GUI_FilamentBitmapUtils_hpp_
|
||||
#define slic3r_GUI_FilamentBitmapUtils_hpp_
|
||||
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/colour.h>
|
||||
#include <vector>
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
enum class FilamentRenderMode {
|
||||
Single,
|
||||
Dual,
|
||||
Triple,
|
||||
Quadruple,
|
||||
Gradient
|
||||
};
|
||||
|
||||
// Create a colour swatch bitmap. The render mode is chosen automatically from the
|
||||
// number of colours unless force_gradient is true.
|
||||
wxBitmap create_filament_bitmap(const std::vector<wxColour>& colors,
|
||||
const wxSize& size,
|
||||
bool force_gradient = false);
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
#endif // slic3r_GUI_FilamentBitmapUtils_hpp_
|
||||
618
src/slic3r/GUI/FilamentPickerDialog.cpp
Normal file
618
src/slic3r/GUI/FilamentPickerDialog.cpp
Normal file
|
|
@ -0,0 +1,618 @@
|
|||
#include "FilamentPickerDialog.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "EncodedFilament.hpp"
|
||||
#include "Widgets/Label.hpp"
|
||||
#include <wx/wx.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/button.h>
|
||||
|
||||
#define COLOR_DEMO_SIZE wxSize(FromDIP(50), FromDIP(50))
|
||||
#define COLOR_BTN_BITMAP_SIZE wxSize(FromDIP(24), FromDIP(24))
|
||||
#define COLOR_BTN_SIZE wxSize(FromDIP(30), FromDIP(30))
|
||||
#define GRID_GAP FromDIP(2)
|
||||
#define COLS 9 // fixed column count
|
||||
#define MAX_VISIBLE_ROWS 7 // max rows before scrollbar appears
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
wxColour FilamentPickerDialog::GetSelectedColour() const
|
||||
{
|
||||
if (!m_color_demo) return wxNullColour;
|
||||
return m_color_demo->GetBackgroundColour();
|
||||
}
|
||||
|
||||
void FilamentPickerDialog::on_dpi_changed(const wxRect &suggested_rect)
|
||||
{
|
||||
// Handle DPI change
|
||||
CreateShapedBitmap();
|
||||
SetWindowShape();
|
||||
Refresh();
|
||||
Layout();
|
||||
}
|
||||
|
||||
FilamentPickerDialog::FilamentPickerDialog(wxWindow *parent, const wxString& fila_id, const FilamentColor& fila_color, const std::string& fila_type)
|
||||
: DPIDialog(parent ? parent : wxGetApp().mainframe,
|
||||
wxID_ANY,
|
||||
_L("Select Filament"),
|
||||
wxDefaultPosition,
|
||||
wxDefaultSize,
|
||||
wxBORDER_NONE | wxFRAME_NO_TASKBAR | wxFRAME_SHAPED)
|
||||
{
|
||||
SetBackgroundColour(wxColour(255, 255, 255));
|
||||
|
||||
m_color_query = new FilamentColorCodeQuery();
|
||||
m_is_data_loaded = LoadFilamentData(fila_id);
|
||||
m_current_filament_color = fila_color;
|
||||
wxString color_name = m_color_query->GetFilaColorName(fila_id, fila_color);
|
||||
m_cur_color_name = new wxString(color_name);
|
||||
|
||||
wxBoxSizer *container_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxBoxSizer *main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// Preview panel (always present)
|
||||
wxBoxSizer *preview_sizer = CreatePreviewPanel(fila_color, fila_type);
|
||||
main_sizer->AddSpacer(FromDIP(4));
|
||||
main_sizer->Add(preview_sizer, 0, wxEXPAND, 0);
|
||||
main_sizer->AddSpacer(FromDIP(12));
|
||||
|
||||
wxBoxSizer *line_sizer = CreateSeparatorLine();
|
||||
main_sizer->Add(line_sizer, 0, wxEXPAND, 0);
|
||||
|
||||
// If caller passed an initial colour, reflect it in preview box.
|
||||
if (m_is_data_loaded) {
|
||||
// Colour grid with all filaments
|
||||
wxScrolledWindow* color_grid = CreateColorGrid();
|
||||
main_sizer->Add(color_grid, 0, wxEXPAND | wxTOP | wxBOTTOM, FromDIP(8));
|
||||
}
|
||||
|
||||
// "More colours" button (always present)
|
||||
m_more_btn = new wxButton(this, wxID_ANY, "+ " + _L("More Colors"),
|
||||
wxDefaultPosition, wxSize(-1, FromDIP(36)), 0);
|
||||
m_more_btn->SetBackgroundColour(wxColour(248, 248, 248)); // Light gray background
|
||||
main_sizer->Add(m_more_btn, 0, wxEXPAND | wxTOP | wxBOTTOM, FromDIP(8));
|
||||
main_sizer->AddSpacer(FromDIP(8));
|
||||
|
||||
// OK / Cancel buttons
|
||||
wxBoxSizer* btn_sizer = CreateButtonPanel();
|
||||
main_sizer->Add(btn_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(10));
|
||||
container_sizer->Add(main_sizer, 1, wxEXPAND | wxALL, FromDIP(16));
|
||||
|
||||
SetSizer(container_sizer);
|
||||
Layout();
|
||||
container_sizer->Fit(this);
|
||||
|
||||
// Position the dialog relative to the parent window
|
||||
if (GetParent()) {
|
||||
// Align the dialog with the sidebar
|
||||
auto& sidebar = wxGetApp().sidebar();
|
||||
wxPoint sidebar_pos = sidebar.GetScreenPosition();
|
||||
wxSize sidebar_size = sidebar.GetSize();
|
||||
|
||||
wxPoint new_pos(
|
||||
sidebar_pos.x + sidebar_size.GetWidth() + FromDIP(10),
|
||||
sidebar_pos.y + FromDIP(80)
|
||||
);
|
||||
SetPosition(new_pos);
|
||||
} else {
|
||||
Centre(wxBOTH); // If no parent window, center the dialog
|
||||
}
|
||||
|
||||
// Create shaped window after sizing
|
||||
CreateShapedBitmap();
|
||||
#ifndef __WXGTK__
|
||||
// Windows and macOS can set shape immediately
|
||||
SetWindowShape();
|
||||
#endif
|
||||
#ifdef __WXGTK__
|
||||
// GTK platform needs to wait for window creation
|
||||
Bind(wxEVT_CREATE, &FilamentPickerDialog::OnWindowCreate, this);
|
||||
#endif
|
||||
|
||||
Layout();
|
||||
// Set window transparency
|
||||
SetTransparent(255);
|
||||
BindEvents();
|
||||
}
|
||||
|
||||
FilamentPickerDialog::~FilamentPickerDialog()
|
||||
{
|
||||
delete m_color_query;
|
||||
m_color_query = nullptr;
|
||||
|
||||
delete m_cur_color_name;
|
||||
m_cur_color_name = nullptr;
|
||||
}
|
||||
|
||||
void FilamentPickerDialog::CreateShapedBitmap()
|
||||
{
|
||||
wxSize size = GetSize();
|
||||
if (size.GetWidth() <= 0 || size.GetHeight() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a bitmap with alpha channel
|
||||
m_shape_bmp.Create(size.GetWidth(), size.GetHeight(), 32);
|
||||
|
||||
wxMemoryDC dc;
|
||||
dc.SelectObject(m_shape_bmp);
|
||||
|
||||
dc.SetBackground(wxBrush(wxColour(0, 0, 0)));
|
||||
dc.Clear();
|
||||
|
||||
// Draw main white shape on top, positioned to let shadow show through
|
||||
dc.SetBrush(wxBrush(wxColour(255, 255, 255, 255)));
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
dc.DrawRoundedRectangle(0, 0,
|
||||
size.GetWidth(),
|
||||
size.GetHeight(),
|
||||
FromDIP(m_corner_radius));
|
||||
|
||||
dc.SelectObject(wxNullBitmap);
|
||||
}
|
||||
|
||||
void FilamentPickerDialog::SetWindowShape()
|
||||
{
|
||||
if (!m_shape_bmp.IsOk()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a region from the bitmap using magenta as transparent mask color
|
||||
wxRegion region(m_shape_bmp, wxColour(0, 0, 0));
|
||||
|
||||
if (region.IsOk()) {
|
||||
SetShape(region);
|
||||
}
|
||||
}
|
||||
|
||||
bool FilamentPickerDialog::LoadFilamentData(const wxString& fila_id)
|
||||
{
|
||||
m_current_color_codes = m_color_query->GetFilaInfoMap(fila_id);
|
||||
|
||||
if (!m_current_color_codes) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "No color codes found for filament ID: " << fila_id.ToStdString();
|
||||
return false;
|
||||
}
|
||||
|
||||
FilamentColor2CodeMap* color_map = m_current_color_codes->GetFilamentColor2CodeMap();
|
||||
if (!color_map) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "No color map found for filament ID: " << fila_id.ToStdString();
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Successfully loaded " << color_map->size() << " color variants for filament " << fila_id.ToStdString();
|
||||
return !color_map->empty();
|
||||
}
|
||||
|
||||
wxBoxSizer* FilamentPickerDialog::CreatePreviewPanel(const FilamentColor& fila_color, const std::string& fila_type)
|
||||
{
|
||||
wxBoxSizer *preview_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
// Bitmap preview box UI
|
||||
m_color_demo = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap,
|
||||
wxDefaultPosition, COLOR_DEMO_SIZE, 0);
|
||||
|
||||
preview_sizer->Add(m_color_demo, 0, wxALIGN_CENTER_VERTICAL, 0);
|
||||
preview_sizer->AddSpacer(FromDIP(12));
|
||||
|
||||
|
||||
// Basic info box UI
|
||||
wxBoxSizer *label_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
wxStaticBox *basic_info_box = new wxStaticBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition);
|
||||
wxStaticBoxSizer *basic_info_sizer = new wxStaticBoxSizer(basic_info_box, wxHORIZONTAL);
|
||||
basic_info_sizer->SetMinSize(wxSize(-1, -1)); // Set minimal margins
|
||||
// Color name
|
||||
m_label_preview_color = new wxStaticText(this, wxID_ANY, _L("Custom Color"));
|
||||
wxFont cfont = m_label_preview_color->GetFont();
|
||||
cfont.SetWeight(wxFONTWEIGHT_BOLD);
|
||||
cfont.SetPointSize(FromDIP(8));
|
||||
m_label_preview_color->SetFont(cfont);
|
||||
// Color index
|
||||
m_label_preview_idx = new wxStaticText(this, wxID_ANY, _L(""));
|
||||
m_label_preview_idx->SetFont(cfont);
|
||||
// Filament type
|
||||
m_label_preview_type = new wxStaticText(this, wxID_ANY, _L(""));
|
||||
m_label_preview_type->SetForegroundColour(wxColour(128, 128, 128));
|
||||
|
||||
// Add labels to sizer
|
||||
basic_info_sizer->Add(m_label_preview_color, 0, wxALIGN_CENTER_VERTICAL, 0);
|
||||
basic_info_sizer->AddSpacer(FromDIP(8));
|
||||
basic_info_sizer->Add(m_label_preview_idx, 0, wxALIGN_CENTER_VERTICAL, 0);
|
||||
|
||||
label_sizer->Add(basic_info_sizer, 0, wxTOP, FromDIP(-6));
|
||||
label_sizer->AddSpacer(FromDIP(2));
|
||||
label_sizer->Add(m_label_preview_type, 0, wxEXPAND | wxLEFT, FromDIP(6));
|
||||
|
||||
preview_sizer->Add(label_sizer, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL, 0);
|
||||
|
||||
// Bitmap preview content
|
||||
std::vector<wxColour> wx_colors(fila_color.m_colors.begin(), fila_color.m_colors.end());
|
||||
wxBitmap init_bmp = create_filament_bitmap(wx_colors, COLOR_DEMO_SIZE,
|
||||
fila_color.m_color_type == FilamentColor::ColorType::GRADIENT_CLR);
|
||||
m_color_demo->SetBitmap(init_bmp);
|
||||
|
||||
// Basic info content
|
||||
m_label_preview_type->SetLabel(fila_type);
|
||||
if (m_cur_color_name && !m_cur_color_name->IsEmpty()) {
|
||||
m_label_preview_color->SetLabel(*m_cur_color_name);
|
||||
|
||||
// Try to get additional color code information
|
||||
if (m_current_color_codes) {
|
||||
FilamentColorCode* color_code = m_current_color_codes->GetColorCode(fila_color);
|
||||
if (color_code) {
|
||||
m_label_preview_idx->SetLabel(wxString::Format("(%s)", color_code->GetFilaColorCode()));
|
||||
m_label_preview_type->SetLabel(color_code->GetFilaType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return preview_sizer;
|
||||
}
|
||||
|
||||
wxBoxSizer* FilamentPickerDialog::CreateSeparatorLine()
|
||||
{
|
||||
wxBoxSizer *line_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxPanel* separator_line = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, FromDIP(1)));
|
||||
separator_line->SetBackgroundColour(wxColour(220, 220, 220));
|
||||
wxStaticText* line_text = new wxStaticText(this, wxID_ANY, _L("Official Filament"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL);
|
||||
line_text->SetForegroundColour(wxColour(128, 128, 128));
|
||||
line_sizer->Add(line_text, 0, wxEXPAND, 0);
|
||||
line_sizer->AddSpacer(FromDIP(8));
|
||||
line_sizer->Add(separator_line, 1, wxALIGN_CENTER_VERTICAL, 0);
|
||||
return line_sizer;
|
||||
}
|
||||
|
||||
wxScrolledWindow* FilamentPickerDialog::CreateColorGrid()
|
||||
{
|
||||
if (!m_current_color_codes) return nullptr;
|
||||
|
||||
FilamentColor2CodeMap* color_map = m_current_color_codes->GetFilamentColor2CodeMap();
|
||||
if (!color_map) return nullptr;
|
||||
|
||||
// Calculate required row count
|
||||
int total_colors = color_map->size();
|
||||
int needed_rows = (total_colors + COLS - 1) / COLS; // round-up division
|
||||
bool need_scroll = needed_rows > MAX_VISIBLE_ROWS;
|
||||
|
||||
// Create a vertical-only scrolled window
|
||||
wxScrolledWindow* scroll_win = new wxScrolledWindow(
|
||||
this,
|
||||
wxID_ANY,
|
||||
wxDefaultPosition,
|
||||
wxDefaultSize,
|
||||
wxVSCROLL | wxNO_BORDER
|
||||
);
|
||||
|
||||
wxGridSizer* grid_sizer = new wxGridSizer(needed_rows, COLS, GRID_GAP, GRID_GAP);
|
||||
|
||||
if (!color_map->empty()) {
|
||||
for (const auto& color_pair : *color_map) {
|
||||
const FilamentColor& fila_color = color_pair.first; // color info
|
||||
FilamentColorCode* color_code = color_pair.second; // color code
|
||||
|
||||
if (!color_code) continue;
|
||||
std::vector<wxColour> wx_colors(fila_color.m_colors.begin(), fila_color.m_colors.end());
|
||||
wxBitmap btn_bmp = create_filament_bitmap(
|
||||
wx_colors,
|
||||
COLOR_BTN_BITMAP_SIZE,
|
||||
fila_color.m_color_type == FilamentColor::ColorType::GRADIENT_CLR
|
||||
);
|
||||
|
||||
if (!btn_bmp.IsOk()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to create bitmap for filament " << color_code->GetFilaColorCode().ToStdString();
|
||||
continue;
|
||||
}
|
||||
|
||||
wxBitmapButton* btn = new wxBitmapButton(
|
||||
scroll_win,
|
||||
wxID_ANY,
|
||||
btn_bmp,
|
||||
wxDefaultPosition,
|
||||
COLOR_BTN_SIZE,
|
||||
wxBU_EXACTFIT | wxNO_BORDER
|
||||
);
|
||||
|
||||
if (btn) {
|
||||
// Remove any default background and borders
|
||||
btn->SetBackgroundColour(*wxWHITE);
|
||||
|
||||
// Set tooltip with filament information
|
||||
wxString tooltip = wxString::Format("%s", color_code->GetFilaColorName());
|
||||
btn->SetToolTip(tooltip);
|
||||
|
||||
// Check if this color matches the current color name and set as selected
|
||||
bool is_matching_color = (m_cur_color_name &&
|
||||
!m_cur_color_name->IsEmpty() &&
|
||||
*m_cur_color_name == color_code->GetFilaColorName());
|
||||
|
||||
if (is_matching_color) {
|
||||
m_current_filament_color = color_code->GetFilaColor();
|
||||
m_currently_selected_btn = btn;
|
||||
UpdatePreview(*color_code);
|
||||
btn->Bind(wxEVT_PAINT, &FilamentPickerDialog::OnButtonPaint, this);
|
||||
}
|
||||
|
||||
// Bind click
|
||||
btn->Bind(wxEVT_LEFT_DOWN, [this, btn, color_code](wxMouseEvent& evt) {
|
||||
m_current_filament_color = color_code->GetFilaColor();
|
||||
UpdatePreview(*color_code);
|
||||
UpdateButtonStates(btn);
|
||||
evt.Skip();
|
||||
});
|
||||
|
||||
// Hover highlight
|
||||
btn->Bind(wxEVT_ENTER_WINDOW, [btn](wxMouseEvent& evt) {
|
||||
evt.Skip();
|
||||
});
|
||||
|
||||
btn->Bind(wxEVT_LEAVE_WINDOW, [btn](wxMouseEvent& evt) {
|
||||
evt.Skip();
|
||||
});
|
||||
|
||||
grid_sizer->Add(btn, 0, wxALL | wxALIGN_CENTER, FromDIP(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scroll_win->SetSizer(grid_sizer);
|
||||
|
||||
if (need_scroll) {
|
||||
int row_height = COLOR_BTN_SIZE.GetHeight() + FromDIP(2);
|
||||
int col_width = COLOR_BTN_SIZE.GetWidth() + FromDIP(4);
|
||||
|
||||
// Reserve space for vertical scrollbar so it doesn't overlay content
|
||||
int scrollbar_width = wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
|
||||
|
||||
// Set minimum visible area (including scrollbar width)
|
||||
scroll_win->SetMinSize(wxSize(col_width * COLS + scrollbar_width, row_height * MAX_VISIBLE_ROWS));
|
||||
|
||||
// Let wxScrolledWindow calculate appropriate virtual size
|
||||
scroll_win->FitInside();
|
||||
scroll_win->SetScrollRate(0, row_height);
|
||||
} else {
|
||||
scroll_win->FitInside();
|
||||
scroll_win->SetScrollRate(0, 0);
|
||||
}
|
||||
|
||||
return scroll_win;
|
||||
}
|
||||
|
||||
void FilamentPickerDialog::UpdatePreview(const FilamentColorCode& color_code)
|
||||
{
|
||||
FilamentColor fila_color = color_code.GetFilaColor();
|
||||
|
||||
std::vector<wxColour> wx_colors(fila_color.m_colors.begin(), fila_color.m_colors.end());
|
||||
|
||||
// Update preview bitmap
|
||||
wxBitmap bmp = create_filament_bitmap(wx_colors, COLOR_DEMO_SIZE,
|
||||
fila_color.m_color_type == FilamentColor::ColorType::GRADIENT_CLR);
|
||||
|
||||
if (bmp.IsOk()) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Bitmap created successfully: " << bmp.GetWidth() << "x" << bmp.GetHeight();
|
||||
m_color_demo->SetBitmap(bmp);
|
||||
if (!wx_colors.empty()) {
|
||||
m_color_demo->SetBackgroundColour(wx_colors[0]);
|
||||
}
|
||||
m_color_demo->Refresh();
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to create bitmap";
|
||||
}
|
||||
|
||||
// Update preview labels
|
||||
m_label_preview_color->SetLabel(color_code.GetFilaColorName());
|
||||
m_label_preview_idx->SetLabel(wxString::Format("(%s)", color_code.GetFilaColorCode()));
|
||||
m_label_preview_type->SetLabel(color_code.GetFilaType());
|
||||
Layout();
|
||||
}
|
||||
|
||||
void FilamentPickerDialog::UpdateButtonStates(wxBitmapButton* selected_btn)
|
||||
{
|
||||
// Reset selected button appearance
|
||||
if (m_currently_selected_btn) {
|
||||
m_currently_selected_btn->SetBackgroundColour(*wxWHITE); // Restore white background
|
||||
m_currently_selected_btn->Unbind(wxEVT_PAINT, &FilamentPickerDialog::OnButtonPaint, this);
|
||||
m_currently_selected_btn->Refresh();
|
||||
}
|
||||
|
||||
if (selected_btn) {
|
||||
// Bind paint event to draw custom green border
|
||||
selected_btn->Bind(wxEVT_PAINT, &FilamentPickerDialog::OnButtonPaint, this);
|
||||
selected_btn->Refresh();
|
||||
}
|
||||
|
||||
m_currently_selected_btn = selected_btn;
|
||||
}
|
||||
|
||||
wxBoxSizer* FilamentPickerDialog::CreateButtonPanel()
|
||||
{
|
||||
wxBoxSizer* btn_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
// Add spacer to push buttons to the right
|
||||
btn_sizer->AddStretchSpacer();
|
||||
|
||||
// standard button color style
|
||||
StateColor btn_bg_green(
|
||||
std::pair<wxColour, int>(wxColour(27, 136, 68), StateColor::Pressed),
|
||||
std::pair<wxColour, int>(wxColour(61, 203, 115), StateColor::Hovered),
|
||||
std::pair<wxColour, int>(wxColour(0, 174, 66), StateColor::Normal)
|
||||
);
|
||||
StateColor btn_bd_green(
|
||||
std::pair<wxColour, int>(wxColour(0, 174, 66), StateColor::Normal)
|
||||
);
|
||||
StateColor btn_text_green(
|
||||
std::pair<wxColour, int>(wxColour(255, 255, 254), StateColor::Normal)
|
||||
);
|
||||
|
||||
StateColor btn_bg_white(
|
||||
std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Pressed),
|
||||
std::pair<wxColour, int>(wxColour(238, 238, 238), StateColor::Hovered),
|
||||
std::pair<wxColour, int>(wxColour(255, 255, 255), StateColor::Normal)
|
||||
);
|
||||
StateColor btn_bd_white(
|
||||
std::pair<wxColour, int>(wxColour(38, 46, 48), StateColor::Normal)
|
||||
);
|
||||
StateColor btn_text_white(
|
||||
std::pair<wxColour, int>(wxColour(38, 46, 48), StateColor::Normal)
|
||||
);
|
||||
|
||||
// Create Cancel button using project's Button class
|
||||
m_cancel_btn = new Button(this, _L("Cancel"), "", 0, 0, wxID_CANCEL);
|
||||
m_cancel_btn->SetMinSize(wxSize(FromDIP(72), FromDIP(24)));
|
||||
m_cancel_btn->SetCornerRadius(FromDIP(12));
|
||||
m_cancel_btn->SetBackgroundColor(btn_bg_white);
|
||||
m_cancel_btn->SetBorderColor(btn_bd_white);
|
||||
m_cancel_btn->SetTextColor(btn_text_white);
|
||||
btn_sizer->Add(m_cancel_btn, 0, wxEXPAND, 0);
|
||||
btn_sizer->AddSpacer(FromDIP(10));
|
||||
|
||||
// Create OK button using project's Button class
|
||||
m_ok_btn = new Button(this, _L("OK"), "", 0, 0, wxID_OK);
|
||||
m_ok_btn->SetMinSize(wxSize(FromDIP(72), FromDIP(24)));
|
||||
m_ok_btn->SetCornerRadius(FromDIP(12));
|
||||
m_ok_btn->SetBackgroundColor(btn_bg_green);
|
||||
m_ok_btn->SetBorderColor(btn_bd_green);
|
||||
m_ok_btn->SetTextColor(btn_text_green);
|
||||
m_ok_btn->SetFocus();
|
||||
btn_sizer->Add(m_ok_btn, 0, wxEXPAND, 0);
|
||||
|
||||
return btn_sizer;
|
||||
}
|
||||
|
||||
void FilamentPickerDialog::BindEvents()
|
||||
{
|
||||
// Bind mouse events
|
||||
Bind(wxEVT_LEFT_DOWN, &FilamentPickerDialog::OnMouseLeftDown, this);
|
||||
Bind(wxEVT_MOTION, &FilamentPickerDialog::OnMouseMove, this);
|
||||
Bind(wxEVT_LEFT_UP, &FilamentPickerDialog::OnMouseLeftUp, this);
|
||||
|
||||
// Add safety event handlers to ensure mouse capture is released
|
||||
Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent& event) {
|
||||
if (HasCapture()) {
|
||||
ReleaseMouse();
|
||||
}
|
||||
event.Skip();
|
||||
});
|
||||
|
||||
Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& event) {
|
||||
if (HasCapture()) {
|
||||
ReleaseMouse();
|
||||
}
|
||||
event.Skip();
|
||||
});
|
||||
|
||||
// Bind more colors button event
|
||||
if (m_more_btn) {
|
||||
m_more_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
|
||||
auto parent = dynamic_cast<PlaterPresetComboBox*>(GetParent());
|
||||
if (parent) {
|
||||
parent->show_default_color_picker();
|
||||
EndModal(wxID_CANCEL);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Bind OK button event
|
||||
if (m_ok_btn) {
|
||||
m_ok_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
|
||||
EndModal(wxID_OK);
|
||||
});
|
||||
}
|
||||
|
||||
// Bind Cancel button event
|
||||
if (m_cancel_btn) {
|
||||
m_cancel_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
|
||||
EndModal(wxID_CANCEL);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __WXGTK__
|
||||
void FilamentPickerDialog::OnWindowCreate(wxWindowCreateEvent& event)
|
||||
{
|
||||
// GTK platform needs to wait for window creation
|
||||
SetWindowShape();
|
||||
}
|
||||
#endif
|
||||
|
||||
void FilamentPickerDialog::OnMouseLeftDown(wxMouseEvent& event)
|
||||
{
|
||||
// Only allow dragging from empty areas (not from buttons or other controls)
|
||||
wxWindow* hit_window = wxFindWindowAtPoint(ClientToScreen(event.GetPosition()));
|
||||
if (hit_window && hit_window != this) {
|
||||
// Click was on a child control, don't drag
|
||||
event.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
// Release any existing capture first
|
||||
if (HasCapture()) {
|
||||
ReleaseMouse();
|
||||
}
|
||||
|
||||
CaptureMouse();
|
||||
wxPoint pt = ClientToScreen(event.GetPosition());
|
||||
wxPoint origin = GetPosition();
|
||||
int dx = pt.x - origin.x;
|
||||
int dy = pt.y - origin.y;
|
||||
m_drag_delta = wxPoint(dx, dy);
|
||||
|
||||
// Don't skip the event for dragging to work properly
|
||||
}
|
||||
|
||||
void FilamentPickerDialog::OnMouseMove(wxMouseEvent& event)
|
||||
{
|
||||
wxPoint pt = event.GetPosition();
|
||||
|
||||
if (event.Dragging() && event.LeftIsDown() && HasCapture()) {
|
||||
wxPoint pos = ClientToScreen(pt);
|
||||
Move(wxPoint(pos.x - m_drag_delta.x, pos.y - m_drag_delta.y));
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void FilamentPickerDialog::OnMouseLeftUp(wxMouseEvent& event)
|
||||
{
|
||||
if (HasCapture()) {
|
||||
ReleaseMouse();
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void FilamentPickerDialog::OnButtonPaint(wxPaintEvent& event)
|
||||
{
|
||||
wxWindow* button = dynamic_cast<wxWindow*>(event.GetEventObject());
|
||||
if (!button) {
|
||||
event.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create paint DC and let default painting happen first
|
||||
wxPaintDC dc(button);
|
||||
|
||||
//Clear the button with white background
|
||||
dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH));
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
dc.DrawRectangle(0, 0, COLOR_BTN_SIZE.GetWidth(), COLOR_BTN_SIZE.GetHeight());
|
||||
|
||||
// Draw the bitmap in the center
|
||||
wxBitmapButton* bmpBtn = dynamic_cast<wxBitmapButton*>(button);
|
||||
if (bmpBtn && bmpBtn->GetBitmap().IsOk()) {
|
||||
wxBitmap bmp = bmpBtn->GetBitmap();
|
||||
int x = (COLOR_BTN_SIZE.GetWidth() - COLOR_BTN_BITMAP_SIZE.GetWidth()) / 2;
|
||||
int y = (COLOR_BTN_SIZE.GetHeight() - COLOR_BTN_BITMAP_SIZE.GetHeight()) / 2;
|
||||
dc.DrawBitmap(bmp, x, y, true);
|
||||
}
|
||||
|
||||
// Draw the green border
|
||||
dc.SetPen(wxPen(wxColour("#00AE42"), 2)); // Green pen, 2px thick
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.DrawRectangle(1, 1, COLOR_BTN_SIZE.GetWidth() - 1, COLOR_BTN_SIZE.GetHeight() - 1);
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
89
src/slic3r/GUI/FilamentPickerDialog.hpp
Normal file
89
src/slic3r/GUI/FilamentPickerDialog.hpp
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#ifndef slic3r_GUI_FilamentPickerDialog_hpp_
|
||||
#define slic3r_GUI_FilamentPickerDialog_hpp_
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "FilamentBitmapUtils.hpp"
|
||||
#include "Widgets/Button.hpp"
|
||||
#include "EncodedFilament.hpp"
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/wx.h>
|
||||
#include <wx/scrolwin.h>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/region.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
class FilamentPickerDialog : public DPIDialog
|
||||
{
|
||||
public:
|
||||
FilamentPickerDialog(wxWindow *parent, const wxString &fila_id, const FilamentColor &fila_color, const std::string &fila_type);
|
||||
virtual ~FilamentPickerDialog();
|
||||
|
||||
// Public interface methods
|
||||
bool IsDataLoaded() const { return m_is_data_loaded; }
|
||||
wxColour GetSelectedColour() const;
|
||||
const FilamentColor& GetSelectedFilamentColor() const { return m_current_filament_color; }
|
||||
|
||||
protected:
|
||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||
|
||||
// Event handlers
|
||||
#ifdef __WXGTK__
|
||||
void OnWindowCreate(wxWindowCreateEvent& event);
|
||||
#endif
|
||||
void OnMouseLeftDown(wxMouseEvent& event);
|
||||
void OnMouseMove(wxMouseEvent& event);
|
||||
void OnMouseLeftUp(wxMouseEvent& event);
|
||||
void OnButtonPaint(wxPaintEvent& event);
|
||||
|
||||
private:
|
||||
// UI creation methods
|
||||
wxBoxSizer* CreatePreviewPanel(const FilamentColor& fila_color, const std::string& fila_type);
|
||||
wxScrolledWindow* CreateColorGrid();
|
||||
wxBoxSizer* CreateSeparatorLine();
|
||||
wxBoxSizer* CreateButtonPanel();
|
||||
void BindEvents();
|
||||
|
||||
// UI update methods
|
||||
void UpdatePreview(const FilamentColorCode& filament);
|
||||
void UpdateButtonStates(wxBitmapButton* selected_btn);
|
||||
|
||||
// Shaped window methods
|
||||
void SetWindowShape();
|
||||
void CreateShapedBitmap();
|
||||
|
||||
// Data loading
|
||||
bool LoadFilamentData(const wxString& fila_id);
|
||||
|
||||
// UI elements
|
||||
wxStaticBitmap* m_color_demo{nullptr};
|
||||
wxStaticText* m_label_preview_color{nullptr};
|
||||
wxStaticText* m_label_preview_idx{nullptr};
|
||||
wxStaticText* m_label_preview_type{nullptr};
|
||||
wxButton* m_more_btn{nullptr};
|
||||
Button* m_ok_btn{nullptr};
|
||||
Button* m_cancel_btn{nullptr};
|
||||
wxString* m_cur_color_name{nullptr};
|
||||
|
||||
// Data members
|
||||
FilamentColorCodeQuery* m_color_query{nullptr};
|
||||
FilamentColorCodes* m_current_color_codes{nullptr};
|
||||
bool m_is_data_loaded{false};
|
||||
wxBitmapButton* m_currently_selected_btn{nullptr};
|
||||
FilamentColor m_current_filament_color;
|
||||
|
||||
// Shaped window members
|
||||
wxBitmap m_shape_bmp;
|
||||
int m_corner_radius{8};
|
||||
|
||||
// Mouse drag members
|
||||
wxPoint m_drag_delta;
|
||||
};
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
#endif
|
||||
|
|
@ -2923,14 +2923,15 @@ std::map<int, DynamicPrintConfig> Sidebar::build_filament_ams_list(MachineObject
|
|||
tray_config.set_key_value("tray_name", new ConfigOptionStrings{ name });
|
||||
tray_config.set_key_value("filament_colour", new ConfigOptionStrings{into_u8(wxColour("#" + tray.color).GetAsString(wxC2S_HTML_SYNTAX))});
|
||||
tray_config.set_key_value("filament_exist", new ConfigOptionBools{tray.is_exists});
|
||||
tray_config.set_key_value("filament_multi_colors", new ConfigOptionStrings{});
|
||||
tray_config.set_key_value("filament_multi_colour", new ConfigOptionStrings{});
|
||||
tray_config.set_key_value("filament_colour_type", new ConfigOptionStrings{std::to_string(tray.ctype)});
|
||||
std::optional<FilamentBaseInfo> info;
|
||||
if (wxGetApp().preset_bundle) {
|
||||
info = wxGetApp().preset_bundle->get_filament_by_filament_id(tray.setting_id);
|
||||
}
|
||||
tray_config.set_key_value("filament_is_support", new ConfigOptionBools{ info.has_value() ? info->is_support : false});
|
||||
for (int i = 0; i < tray.cols.size(); ++i) {
|
||||
tray_config.opt<ConfigOptionStrings>("filament_multi_colors")->values.push_back(into_u8(wxColour("#" + tray.cols[i]).GetAsString(wxC2S_HTML_SYNTAX)));
|
||||
tray_config.opt<ConfigOptionStrings>("filament_multi_colour")->values.push_back(into_u8(wxColour("#" + tray.cols[i]).GetAsString(wxC2S_HTML_SYNTAX)));
|
||||
}
|
||||
return tray_config;
|
||||
};
|
||||
|
|
@ -5809,11 +5810,42 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
*wipe_tower_y = *file_wipe_tower_y;
|
||||
|
||||
ConfigOptionStrings* filament_color = proj_cfg.opt<ConfigOptionStrings>("filament_colour");
|
||||
ConfigOptionInts* filament_map = proj_cfg.opt<ConfigOptionInts>("filament_map", true);
|
||||
if (filament_color && filament_color->size() != filament_map->size()) {
|
||||
filament_map->values.resize(filament_color->size(), 1);
|
||||
if (filament_color) {
|
||||
size_t filament_count = filament_color->size();
|
||||
|
||||
// Sync filament map
|
||||
ConfigOptionInts* filament_map = proj_cfg.opt<ConfigOptionInts>("filament_map", true);
|
||||
if (filament_map->size() != filament_count) {
|
||||
filament_map->values.resize(filament_count, 1);
|
||||
}
|
||||
|
||||
// Sync filament multi colour
|
||||
ConfigOptionStrings* filament_multi_color = proj_cfg.opt<ConfigOptionStrings>("filament_multi_colour", true);
|
||||
if (filament_multi_color->size() != filament_count) {
|
||||
filament_multi_color->values.resize(filament_count);
|
||||
}
|
||||
// If there is no multi-color data or color is not match, use single color as default value
|
||||
for (size_t i = 0; i < filament_count; i++) {
|
||||
std::vector<std::string> colors = Slic3r::split_string(filament_multi_color->values[i], ',');
|
||||
if (i >= filament_multi_color->values.size() || colors.empty() || colors[0] != filament_color->values[i] ) {
|
||||
filament_multi_color->values[i] = filament_color->values[i];
|
||||
}
|
||||
}
|
||||
// Sync filament colour type
|
||||
ConfigOptionStrings* filament_color_type = proj_cfg.opt<ConfigOptionStrings>("filament_colour_type", true);
|
||||
if (filament_color_type && filament_color_type->size() != filament_count) {
|
||||
filament_color_type->values.resize(filament_count);
|
||||
|
||||
for (size_t i = 0; i < filament_count; i++) {
|
||||
if (i >= filament_color_type->values.size() || filament_color_type->values[i].empty()) {
|
||||
filament_color_type->values[i] = "1";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Update filament combobox after loading config
|
||||
wxGetApp().plater()->sidebar().update_presets(Preset::TYPE_FILAMENT);
|
||||
}
|
||||
}
|
||||
if (!silence) wxGetApp().app_config->update_config_dir(path.parent_path().string());
|
||||
|
|
@ -15501,6 +15533,26 @@ std::vector<std::string> Plater::get_extruder_colors_from_plater_config(const GC
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> Plater::get_filament_colors_render_info() const
|
||||
{
|
||||
const Slic3r::DynamicPrintConfig* config = &wxGetApp().preset_bundle->project_config;
|
||||
std::vector<std::string> color_packs;
|
||||
if (!config->has("filament_multi_colour")) return color_packs;
|
||||
|
||||
color_packs = (config->option<ConfigOptionStrings>("filament_multi_colour"))->values;
|
||||
return color_packs;
|
||||
}
|
||||
|
||||
std::vector<std::string> Plater::get_filament_color_render_type() const
|
||||
{
|
||||
const Slic3r::DynamicPrintConfig *config = &wxGetApp().preset_bundle->project_config;
|
||||
std::vector<std::string> ctype;
|
||||
if (!config->has("filament_colour_type")) return ctype;
|
||||
|
||||
ctype = (config->option<ConfigOptionStrings>("filament_colour_type"))->values;
|
||||
return ctype;
|
||||
}
|
||||
|
||||
/* Get vector of colors used for rendering of a Preview scene in "Color print" mode
|
||||
* It consists of extruder colors and colors, saved in model.custom_gcode_per_print_z
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -557,6 +557,8 @@ public:
|
|||
// On activating the parent window.
|
||||
void on_activate();
|
||||
std::vector<std::string> get_extruder_colors_from_plater_config(const GCodeProcessorResult* const result = nullptr) const;
|
||||
std::vector<std::string> get_filament_colors_render_info() const;
|
||||
std::vector<std::string> get_filament_color_render_type() const;
|
||||
std::vector<std::string> get_colors_for_color_print(const GCodeProcessorResult* const result = nullptr) const;
|
||||
|
||||
void set_global_filament_map_mode(FilamentMapMode mode);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <wx/sizer.h>
|
||||
|
|
@ -41,6 +42,8 @@
|
|||
#include "SavePresetDialog.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "ParamsDialog.hpp"
|
||||
#include "FilamentPickerDialog.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
|
||||
// A workaround for a set of issues related to text fitting into gtk widgets:
|
||||
#if defined(__WXGTK20__) || defined(__WXGTK3__)
|
||||
|
|
@ -219,6 +222,8 @@ int PresetComboBox::update_ams_color()
|
|||
if (m_filament_idx < 0) return -1;
|
||||
int idx = selected_ams_filament();
|
||||
std::string color;
|
||||
std::string ctype;
|
||||
std::vector<std::string> colors;
|
||||
if (idx < 0) {
|
||||
auto name = Preset::remove_suffix_modified(GetValue().ToUTF8().data());
|
||||
auto *preset = m_collection->find_preset(name);
|
||||
|
|
@ -233,12 +238,30 @@ int PresetComboBox::update_ams_color()
|
|||
return -1;
|
||||
}
|
||||
color = iter->second.opt_string("filament_colour", 0u);
|
||||
ctype = iter->second.opt_string("filament_colour_type", 0u);
|
||||
colors = iter->second.opt<ConfigOptionStrings>("filament_multi_colour")->values;
|
||||
}
|
||||
DynamicPrintConfig *cfg = &wxGetApp().preset_bundle->project_config;
|
||||
auto colors = static_cast<ConfigOptionStrings*>(cfg->option("filament_colour")->clone());
|
||||
colors->values[m_filament_idx] = color;
|
||||
auto color_head = static_cast<ConfigOptionStrings*>(cfg->option("filament_colour")->clone()); // single color (the first color if multi-color filament)
|
||||
auto color_pack = static_cast<ConfigOptionStrings *>(cfg->option("filament_multi_colour")->clone()); // multi color (all colors in all kinds of filament)
|
||||
auto color_type = static_cast<ConfigOptionStrings*>(cfg->option("filament_colour_type")->clone()); // color type
|
||||
|
||||
color_head->values[m_filament_idx] = color;
|
||||
color_type->values[m_filament_idx] = ctype;
|
||||
std::string color_str = ""; // Translate multi color info to config storage format
|
||||
for (auto &c : colors) {
|
||||
if (c.empty()) continue;
|
||||
color_str += c + " ";
|
||||
}
|
||||
if (color_str.empty()) color_str = color;
|
||||
else color_str.erase(color_str.size() - 1);
|
||||
color_pack->values[m_filament_idx] = color_str;
|
||||
|
||||
// Update color informations in config
|
||||
DynamicPrintConfig new_cfg;
|
||||
new_cfg.set_key_value("filament_colour", colors);
|
||||
new_cfg.set_key_value("filament_colour", color_head);
|
||||
new_cfg.set_key_value("filament_colour_type", color_type);
|
||||
new_cfg.set_key_value("filament_multi_colour", color_pack);
|
||||
cfg->apply(new_cfg);
|
||||
wxGetApp().plater()->on_config_change(new_cfg);
|
||||
//trigger the filament color changed
|
||||
|
|
@ -507,6 +530,7 @@ bool PresetComboBox::add_ams_filaments(std::string selected, bool alias_name)
|
|||
}
|
||||
const_cast<Preset&>(*iter).is_visible = true;
|
||||
auto color = tray.opt_string("filament_colour", 0u);
|
||||
auto multi_color = tray.opt<ConfigOptionStrings>("filament_multi_colour")->values;
|
||||
wxBitmap bmp(*get_extruder_color_icon(color, name, icon_width, 16));
|
||||
auto text = get_preset_name(*iter);
|
||||
int item_id = Append(text, bmp.ConvertToImage(), &m_first_ams_filament + entry.first);
|
||||
|
|
@ -809,39 +833,48 @@ PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset
|
|||
for (int i = 0; i < colors.size(); i++) {
|
||||
m_clrData.SetCustomColour(i, string_to_wxColor(colors[i]));
|
||||
}
|
||||
wxColourDialog dialog(this, &m_clrData);
|
||||
dialog.SetTitle(_L("Please choose the filament color"));
|
||||
if ( dialog.ShowModal() == wxID_OK )
|
||||
{
|
||||
m_clrData = dialog.GetColourData();
|
||||
if (colors.size() != CUSTOM_COLOR_COUNT) {
|
||||
colors.resize(CUSTOM_COLOR_COUNT);
|
||||
|
||||
// Check if it's an official filament
|
||||
auto fila_type = Preset::remove_suffix_modified(GetValue().ToUTF8().data());
|
||||
bool is_official = boost::algorithm::starts_with(fila_type, "Bambu");
|
||||
if (is_official) {
|
||||
// Get filament_id from filament_presets
|
||||
const std::string& preset_name = m_preset_bundle->filament_presets[m_filament_idx];
|
||||
const Preset* selected_preset = m_collection->find_preset(preset_name);
|
||||
wxString fila_id = selected_preset ? wxString::FromUTF8(selected_preset->filament_id) : "GFA00";
|
||||
FilamentColor fila_color = get_cur_color_info();
|
||||
|
||||
// Show filament picker dialog
|
||||
FilamentPickerDialog dialog(this, fila_id, fila_color, fila_type);
|
||||
|
||||
if (!dialog.IsDataLoaded()) {
|
||||
// If FilamentPicker fails, fallback to default color picker
|
||||
show_default_color_picker();
|
||||
} else if (dialog.ShowModal() == wxID_OK) {
|
||||
// Get selected filament color data
|
||||
FilamentColor fila_color = dialog.GetSelectedFilamentColor();
|
||||
|
||||
// Check if we have valid color data
|
||||
if (!fila_color.m_colors.empty()) {
|
||||
// Convert to storage format
|
||||
std::vector<std::string> colors;
|
||||
for (const wxColour& color : fila_color.m_colors) {
|
||||
colors.push_back(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString());
|
||||
}
|
||||
|
||||
bool is_gradient = (fila_color.m_color_type == FilamentColor::ColorType::GRADIENT_CLR);
|
||||
this->sync_colour_config(colors, is_gradient);
|
||||
} else {
|
||||
// Fallback to basic color if no FilamentColor data
|
||||
wxColour selected_color = dialog.GetSelectedColour();
|
||||
if (selected_color.IsOk()) {
|
||||
std::vector<std::string> color = {selected_color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString()};
|
||||
this->sync_colour_config(color, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < CUSTOM_COLOR_COUNT; i++) {
|
||||
colors[i] = color_to_string(m_clrData.GetCustomColour(i));
|
||||
}
|
||||
wxGetApp().app_config->save_custom_color_to_config(colors);
|
||||
// get current color
|
||||
DynamicPrintConfig* cfg = &wxGetApp().preset_bundle->project_config;
|
||||
auto colors = static_cast<ConfigOptionStrings*>(cfg->option("filament_colour")->clone());
|
||||
wxColour clr(colors->values[m_filament_idx]);
|
||||
if (!clr.IsOk())
|
||||
clr = wxColour(0, 0, 0); // Don't set alfa to transparence
|
||||
|
||||
colors->values[m_filament_idx] = m_clrData.GetColour().GetAsString(wxC2S_HTML_SYNTAX).ToStdString();
|
||||
DynamicPrintConfig cfg_new = *cfg;
|
||||
cfg_new.set_key_value("filament_colour", colors);
|
||||
|
||||
//wxGetApp().get_tab(Preset::TYPE_PRINTER)->load_config(cfg_new);
|
||||
cfg->apply(cfg_new);
|
||||
wxGetApp().plater()->update_project_dirty_from_presets();
|
||||
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
|
||||
update();
|
||||
wxGetApp().plater()->on_config_change(cfg_new);
|
||||
|
||||
wxCommandEvent *evt = new wxCommandEvent(EVT_FILAMENT_COLOR_CHANGED);
|
||||
evt->SetInt(m_filament_idx);
|
||||
wxQueueEvent(wxGetApp().plater(), evt);
|
||||
} else {
|
||||
show_default_color_picker();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1066,13 +1099,8 @@ void PlaterPresetComboBox::update()
|
|||
invalidate_selection();
|
||||
|
||||
const Preset* selected_filament_preset = nullptr;
|
||||
std::string filament_color;
|
||||
if (m_type == Preset::TYPE_FILAMENT)
|
||||
{
|
||||
//unsigned char rgb[3];
|
||||
filament_color = m_preset_bundle->project_config.opt_string("filament_colour", (unsigned int) m_filament_idx);
|
||||
wxColor clr(filament_color);
|
||||
clr_picker->SetBackgroundColour(clr);
|
||||
std::vector<wxBitmap *> bitmaps = get_extruder_color_icons(true);
|
||||
if (m_filament_idx < bitmaps.size()) {
|
||||
clr_picker->SetBitmap(*bitmaps[m_filament_idx]);
|
||||
|
|
@ -1160,7 +1188,6 @@ void PlaterPresetComboBox::update()
|
|||
preset_filament_types[name] = preset.config.option<ConfigOptionStrings>("filament_type")->values.at(0);
|
||||
}
|
||||
}
|
||||
|
||||
wxBitmap* bmp = get_bmp(preset);
|
||||
assert(bmp);
|
||||
|
||||
|
|
@ -1332,7 +1359,7 @@ void PlaterPresetComboBox::update()
|
|||
|
||||
update_selection();
|
||||
if (m_type == Preset::TYPE_FILAMENT) {
|
||||
if (wxGetApp().plater()->is_same_printer_for_connected_and_selected(false)) {
|
||||
if (wxGetApp().plater()->is_same_printer_for_connected_and_selected(false)) {
|
||||
update_badge_according_flag();
|
||||
}
|
||||
}
|
||||
|
|
@ -1370,6 +1397,80 @@ void PlaterPresetComboBox::msw_rescale()
|
|||
}
|
||||
|
||||
|
||||
FilamentColor PlaterPresetComboBox::get_cur_color_info()
|
||||
{
|
||||
std::vector<std::string> filaments_multi_color = Slic3r::GUI::wxGetApp().plater()->get_filament_colors_render_info();
|
||||
std::vector<std::string> filament_color_type = Slic3r::GUI::wxGetApp().plater()->get_filament_color_render_type();
|
||||
std::string filament_color_info = filaments_multi_color[m_filament_idx];
|
||||
std::vector<std::string> colors;
|
||||
boost::split(colors, filament_color_info, boost::is_any_of(" "));
|
||||
|
||||
FilamentColor fila_color;
|
||||
for (const std::string& color_str : colors) {
|
||||
if (!color_str.empty()) {
|
||||
wxColour color(color_str);
|
||||
if (color.IsOk()) {
|
||||
fila_color.m_colors.insert(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fila_color.EndSet(filament_color_type[m_filament_idx] == "0" ? 0 : 1);
|
||||
return fila_color;
|
||||
}
|
||||
|
||||
void PlaterPresetComboBox::show_default_color_picker()
|
||||
{
|
||||
wxColourDialog dialog(this, &m_clrData);
|
||||
dialog.SetTitle(_L("Please choose the filament colour"));
|
||||
if (dialog.ShowModal() == wxID_OK)
|
||||
{
|
||||
m_clrData = dialog.GetColourData();
|
||||
std::vector<std::string> color = {m_clrData.GetColour().GetAsString(wxC2S_HTML_SYNTAX).ToStdString()};
|
||||
this->sync_colour_config(color, false);
|
||||
}
|
||||
}
|
||||
|
||||
void PlaterPresetComboBox::sync_colour_config(const std::vector<std::string> &clrs, bool is_gradient)
|
||||
{
|
||||
DynamicPrintConfig *cfg = &wxGetApp().preset_bundle->project_config;
|
||||
|
||||
// Clone the string vector and patch the value at current extruder index.
|
||||
auto multi_colour_opt = static_cast<ConfigOptionStrings *>(cfg->option("filament_multi_colour")->clone());
|
||||
auto colour_type_opt = static_cast<ConfigOptionStrings *>(cfg->option("filament_colour_type")->clone());
|
||||
auto colour_opt = static_cast<ConfigOptionStrings *>(cfg->option("filament_colour")->clone());
|
||||
|
||||
if (m_filament_idx >= multi_colour_opt->values.size()) multi_colour_opt->values.resize(m_filament_idx + 1);
|
||||
if (m_filament_idx >= colour_type_opt->values.size()) colour_type_opt->values.resize(m_filament_idx + 1);
|
||||
if (m_filament_idx >= colour_opt->values.size()) colour_opt->values.resize(m_filament_idx + 1);
|
||||
|
||||
std::string clr_str = "";
|
||||
for(auto &clr : clrs) {
|
||||
clr_str += clr + " ";
|
||||
}
|
||||
clr_str.pop_back();
|
||||
|
||||
multi_colour_opt->values[m_filament_idx] = clr_str;
|
||||
colour_opt->values[m_filament_idx] = clrs[0];
|
||||
colour_type_opt->values[m_filament_idx] = is_gradient ? "0" : "1";
|
||||
DynamicPrintConfig cfg_new = *cfg;
|
||||
cfg_new.set_key_value("filament_multi_colour", multi_colour_opt);
|
||||
cfg_new.set_key_value("filament_colour", colour_opt);
|
||||
cfg_new.set_key_value("filament_colour_type", colour_type_opt);
|
||||
cfg->apply(cfg_new);
|
||||
|
||||
wxGetApp().plater()->update_project_dirty_from_presets();
|
||||
|
||||
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
|
||||
update(); // refresh the preset combobox with new config
|
||||
|
||||
wxGetApp().plater()->on_config_change(cfg_new);
|
||||
|
||||
wxCommandEvent *evt = new wxCommandEvent(EVT_CALI_TRAY_CHANGED);
|
||||
evt->SetInt(m_filament_idx);
|
||||
wxQueueEvent(wxGetApp().plater(), evt);
|
||||
}
|
||||
|
||||
// ---------------------------------
|
||||
// *** TabPresetComboBox ***
|
||||
// ---------------------------------
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "BitmapComboBox.hpp"
|
||||
#include "Widgets/ComboBox.hpp"
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "EncodedFilament.hpp"
|
||||
|
||||
class wxString;
|
||||
class wxTextCtrl;
|
||||
|
|
@ -205,6 +206,10 @@ public:
|
|||
void OnSelect(wxCommandEvent& evt) override;
|
||||
void update_badge_according_flag();
|
||||
|
||||
FilamentColor get_cur_color_info();
|
||||
void show_default_color_picker();
|
||||
void sync_colour_config(const std::vector<std::string> &clrs, bool is_gradient);
|
||||
|
||||
private:
|
||||
// BBS
|
||||
wxColor m_color;
|
||||
|
|
|
|||
|
|
@ -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/* = ""*/,
|
||||
|
|
|
|||
|
|
@ -75,6 +75,9 @@ wxBitmap create_scaled_bitmap(const std::string& bmp_name, wxWindow *win = nullp
|
|||
wxBitmap* get_default_extruder_color_icon(bool thin_icon = false);
|
||||
std::vector<wxBitmap *> get_extruder_color_icons(bool thin_icon = false);
|
||||
wxBitmap * get_extruder_color_icon(std::string color, std::string label, int icon_width, int icon_height);
|
||||
wxBitmap * get_extruder_color_icon(std::vector<std::string> colors, bool is_gradient, std::string label, int icon_width, int icon_height);
|
||||
std::vector<std::vector<std::string>> read_color_pack(std::vector<std::string> color_pack);
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
class BitmapComboBox;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue