From b01b616f682593956e17056d1806670383f78420 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:32:29 -0500 Subject: [PATCH 01/57] Modify project description in README.md Updated project description to include 'test' in the title. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index afd418ea0a..e4915a6ba4 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![GitHub Repo stars](https://img.shields.io/github/stars/OrcaSlicer/OrcaSlicer)](https://github.com/OrcaSlicer/OrcaSlicer/stargazers) [![Build all](https://github.com/OrcaSlicer/OrcaSlicer/actions/workflows/build_all.yml/badge.svg?branch=main)](https://github.com/OrcaSlicer/OrcaSlicer/actions/workflows/build_all.yml) -OrcaSlicer: an open source Next-Gen Slicing Software for Precision 3D Prints. +OrcaSlicer test: an open source Next-Gen Slicing Software for Precision 3D Prints. Optimize your prints with ultra-fast slicing, intelligent support generation, and seamless printer compatibility—engineered for perfection.

From e02b97904de24b93b8ebf99821691980ae57dcda Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Wed, 14 Jan 2026 18:06:45 -0500 Subject: [PATCH 02/57] Update README.md for improved project description Corrected the introductory sentence for clarity and added a brief description of features. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e4915a6ba4..afd418ea0a 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![GitHub Repo stars](https://img.shields.io/github/stars/OrcaSlicer/OrcaSlicer)](https://github.com/OrcaSlicer/OrcaSlicer/stargazers) [![Build all](https://github.com/OrcaSlicer/OrcaSlicer/actions/workflows/build_all.yml/badge.svg?branch=main)](https://github.com/OrcaSlicer/OrcaSlicer/actions/workflows/build_all.yml) -OrcaSlicer test: an open source Next-Gen Slicing Software for Precision 3D Prints. +OrcaSlicer: an open source Next-Gen Slicing Software for Precision 3D Prints. Optimize your prints with ultra-fast slicing, intelligent support generation, and seamless printer compatibility—engineered for perfection.

From 04b5cbdefffa5a2dc195bad09ccffadd27ce12cd Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 01:32:06 -0500 Subject: [PATCH 03/57] Add printer preset support for filament index base --- src/libslic3r/Preset.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 4e78b31b46..f752692364 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1024,7 +1024,8 @@ static std::vector s_Preset_printer_options { "use_relative_e_distances", "extruder_type", "use_firmware_retraction", "printer_notes", "grab_length", "support_object_skip_flush", "physical_extruder_map", "cooling_tube_retraction", - "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "purge_in_prime_tower", "enable_filament_ramming", + "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "start_filament_index_at_1", + "purge_in_prime_tower", "enable_filament_ramming", "z_offset", "disable_m73", "preferred_orientation", "emit_machine_limits_to_gcode", "pellet_modded_printer", "support_multi_bed_types", "default_bed_type", "bed_mesh_min","bed_mesh_max","bed_mesh_probe_distance", "adaptive_bed_mesh_margin", "enable_long_retraction_when_cut","long_retractions_when_cut","retraction_distances_when_cut", "bed_temperature_formula", "nozzle_flush_dataset" From 78c5554a0d44f7dcee871830a38c3287074bf31b Mon Sep 17 00:00:00 2001 From: Jonas Bouchard Date: Fri, 16 Jan 2026 01:14:29 -1000 Subject: [PATCH 04/57] try adding start filament index at 1 in the ui --- CMakeSettings.json | 15 +++++++++++++++ src/libslic3r/PrintConfig.cpp | 7 +++++++ src/libslic3r/PrintConfig.hpp | 2 ++ src/slic3r/GUI/Tab.cpp | 1 + 4 files changed, 25 insertions(+) create mode 100644 CMakeSettings.json diff --git a/CMakeSettings.json b/CMakeSettings.json new file mode 100644 index 0000000000..122c8186c3 --- /dev/null +++ b/CMakeSettings.json @@ -0,0 +1,15 @@ +{ + "configurations": [ + { + "name": "x64-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ "msvc_x64_x64" ], + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "" + } + ] +} \ No newline at end of file diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 91beca4c3c..894a3c00f2 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4428,6 +4428,13 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(-2.)); + def = this->add("start_filament_index_at_1", coBool); + def->label = L("Start filament index at 1"); + def->tooltip = L("When enabled, filament/extruder indices are treated as 1-based (1..N) instead of 0-based (0..N-1). " + "Enable this if your firmware / macros expect filament indices starting at 1."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("start_end_points", coPoints); def->label = L("Start end points"); def->tooltip = L("The start and end points which is from cutter area to garbage can."); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 64fc0ddfbf..a4512a9f97 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1385,6 +1385,8 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, purge_in_prime_tower)) ((ConfigOptionBool, enable_filament_ramming)) ((ConfigOptionBool, support_multi_bed_types)) + ((ConfigOptionBool, start_filament_index_at_1)) + // Small Area Infill Flow Compensation ((ConfigOptionStrings, small_area_infill_flow_compensation_model)) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index d4d31a3573..1e2a10102b 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4911,6 +4911,7 @@ if (is_marlin_flavor) optgroup->append_single_option_line("parking_pos_retraction", "printer_multimaterial_semm_parameters#filament-parking-position"); optgroup->append_single_option_line("extra_loading_move", "printer_multimaterial_semm_parameters#extra-loading-distance"); optgroup->append_single_option_line("high_current_on_filament_swap", "printer_multimaterial_semm_parameters#high-extruder-current-on-filament-swap"); + optgroup->append_single_option_line("start_filament_index_at_1", "printer_multimaterial_semm_parameters#start_filament_index_at_1"); optgroup = page->new_optgroup(L("Advanced"), L"param_advanced"); optgroup->append_single_option_line("machine_load_filament_time", "printer_multimaterial_advanced#filament-load-time"); From 6c337d17688f4abf48ed8bd56e435c960da4d2a9 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard Date: Fri, 16 Jan 2026 01:38:30 -1000 Subject: [PATCH 06/57] Revert "Merge pull request #7 from JonasBouchard/codex/fix-exception-after-adding-start_filament_index_at_1" This reverts commit cdd70bb64175c2239cb8f1d0c2b4cac54d9ec83a, reversing changes made to 78c5554a0d44f7dcee871830a38c3287074bf31b. --- src/libslic3r/Preset.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index f752692364..4e78b31b46 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1024,8 +1024,7 @@ static std::vector s_Preset_printer_options { "use_relative_e_distances", "extruder_type", "use_firmware_retraction", "printer_notes", "grab_length", "support_object_skip_flush", "physical_extruder_map", "cooling_tube_retraction", - "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "start_filament_index_at_1", - "purge_in_prime_tower", "enable_filament_ramming", + "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "purge_in_prime_tower", "enable_filament_ramming", "z_offset", "disable_m73", "preferred_orientation", "emit_machine_limits_to_gcode", "pellet_modded_printer", "support_multi_bed_types", "default_bed_type", "bed_mesh_min","bed_mesh_max","bed_mesh_probe_distance", "adaptive_bed_mesh_margin", "enable_long_retraction_when_cut","long_retractions_when_cut","retraction_distances_when_cut", "bed_temperature_formula", "nozzle_flush_dataset" From ea3991358f182908bf58896a4300c2c1cc3b7cbd Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 01:59:10 -0500 Subject: [PATCH 07/57] Honor filament index base in UI --- src/slic3r/GUI/GUI.cpp | 682 ++++---- src/slic3r/GUI/GUI.hpp | 46 +- src/slic3r/GUI/GUI_Factories.cpp | 1435 +++++++++-------- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 684 ++++---- 4 files changed, 1440 insertions(+), 1407 deletions(-) diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index d133720c7e..90b7c46488 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -42,74 +42,88 @@ IOPMAssertionID assertionID; void disable_screensaver() { - #if __APPLE__ - CFStringRef reasonForActivity = CFSTR("Slic3r"); - [[maybe_unused]]IOReturn success = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, - kIOPMAssertionLevelOn, reasonForActivity, &assertionID); - // ignore result: success == kIOReturnSuccess - #elif _WIN32 +#if __APPLE__ + CFStringRef reasonForActivity = CFSTR("Slic3r"); + [[maybe_unused]] IOReturn success = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, + reasonForActivity, &assertionID); +// ignore result: success == kIOReturnSuccess +#elif _WIN32 SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_CONTINUOUS); - #endif +#endif } void enable_screensaver() { - #if __APPLE__ +#if __APPLE__ IOPMAssertionRelease(assertionID); - #elif _WIN32 +#elif _WIN32 SetThreadExecutionState(ES_CONTINUOUS); - #endif +#endif } bool debugged() { - #ifdef _WIN32 +#ifdef _WIN32 return IsDebuggerPresent() == TRUE; - #else - return false; - #endif /* _WIN32 */ +#else + return false; +#endif /* _WIN32 */ } void break_to_debugger() { - #ifdef _WIN32 +#ifdef _WIN32 if (IsDebuggerPresent()) DebugBreak(); - #endif /* _WIN32 */ +#endif /* _WIN32 */ } const std::string& shortkey_ctrl_prefix() { - static const std::string str = + static const std::string str = #ifdef __APPLE__ - u8"\u2318+" // "⌘+" (Mac Command+) + u8"\u2318+" // "⌘+" (Mac Command+) #else - _u8L("Ctrl+") + _u8L("Ctrl+") #endif - ; - return str; + ; + return str; } const std::string& shortkey_alt_prefix() { - static const std::string str = + static const std::string str = #ifdef __APPLE__ - u8"\u2325+" // "⌥+" (Mac Option+) + u8"\u2325+" // "⌥+" (Mac Option+) #else - _u8L("Alt+") + _u8L("Alt+") #endif - ; - return str; + ; + return str; } +bool start_filament_index_at_1() +{ + const auto* preset_bundle = wxGetApp().preset_bundle; + if (!preset_bundle) + return false; + + const auto& config = preset_bundle->printers.get_edited_preset().config; + const auto* opt = config.option("start_filament_index_at_1"); + return opt != nullptr && opt->value; +} + +int filament_index_from_zero_based(int index) { return index + (start_filament_index_at_1() ? 1 : 0); } + +int filament_index_from_one_based(int index) { return start_filament_index_at_1() ? index : index - 1; } + // opt_index = 0, by the reason of zero-index in ConfigOptionVector by default (in case only one element) void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index /*= 0*/) { - try{ - + try { if (config.def()->get(opt_key)->type == coBools && config.def()->get(opt_key)->nullable) { - const auto v = boost::any_cast(value); - auto vec_new = std::make_unique(1, v); + const auto v = boost::any_cast(value); + auto vec_new = std::make_unique(1, v); if (v == ConfigOptionBoolsNullable::nil_value()) { vec_new->set_at_to_nil(0); } @@ -118,125 +132,109 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt return; } - const ConfigOptionDef *opt_def = config.def()->get(opt_key); - switch (opt_def->type) { - case coFloatOrPercent:{ - std::string str = boost::any_cast(value); - bool percent = false; - if (str.back() == '%') { - str.pop_back(); - percent = true; - } - double val = std::stod(str); // locale-dependent (on purpose - the input is the actual content of the field) - config.set_key_value(opt_key, new ConfigOptionFloatOrPercent(val, percent)); - break;} - case coFloatsOrPercents:{ - std::string str = boost::any_cast(value); - bool percent = false; - if (str.back() == '%') { - str.pop_back(); - percent = true; - } + const ConfigOptionDef* opt_def = config.def()->get(opt_key); + switch (opt_def->type) { + case coFloatOrPercent: { + std::string str = boost::any_cast(value); + bool percent = false; + if (str.back() == '%') { + str.pop_back(); + percent = true; + } double val = std::stod(str); // locale-dependent (on purpose - the input is the actual content of the field) + config.set_key_value(opt_key, new ConfigOptionFloatOrPercent(val, percent)); + break; + } + case coFloatsOrPercents: { + std::string str = boost::any_cast(value); + bool percent = false; + if (str.back() == '%') { + str.pop_back(); + percent = true; + } + double val = std::stod(str); // locale-dependent (on purpose - the input is the actual content of the field) auto vec_new = std::make_unique(val, percent); config.option(opt_key)->set_at(vec_new.get(), opt_index, opt_index); - break;} - case coPercent: - config.set_key_value(opt_key, new ConfigOptionPercent(boost::any_cast(value))); - break; - case coFloat:{ - double& val = config.opt_float(opt_key); - val = boost::any_cast(value); - break; - } - case coPercents:{ - auto vec_new = std::make_unique (boost::any_cast(value)); - config.option(opt_key)->set_at(vec_new.get(), opt_index, opt_index); - break; - } - case coFloats:{ + break; + } + case coPercent: config.set_key_value(opt_key, new ConfigOptionPercent(boost::any_cast(value))); break; + case coFloat: { + double& val = config.opt_float(opt_key); + val = boost::any_cast(value); + break; + } + case coPercents: { + auto vec_new = std::make_unique(boost::any_cast(value)); + config.option(opt_key)->set_at(vec_new.get(), opt_index, opt_index); + break; + } + case coFloats: { auto vec_new = std::make_unique(boost::any_cast(value)); - config.option(opt_key)->set_at(vec_new.get(), opt_index, opt_index); - break; - } - case coString: - config.set_key_value(opt_key, new ConfigOptionString(boost::any_cast(value))); - break; - case coStrings:{ - if (opt_key == "compatible_prints" || opt_key == "compatible_printers") { - config.option(opt_key)->values = - boost::any_cast>(value); - } - else if (config.def()->get(opt_key)->gui_flags.compare("serialized") == 0) { - std::string str = boost::any_cast(value); - std::vector values {}; + config.option(opt_key)->set_at(vec_new.get(), opt_index, opt_index); + break; + } + case coString: config.set_key_value(opt_key, new ConfigOptionString(boost::any_cast(value))); break; + case coStrings: { + if (opt_key == "compatible_prints" || opt_key == "compatible_printers") { + config.option(opt_key)->values = boost::any_cast>(value); + } else if (config.def()->get(opt_key)->gui_flags.compare("serialized") == 0) { + std::string str = boost::any_cast(value); + std::vector values{}; if (!str.empty()) { - if (str.back() == ';') str.pop_back(); - // Split a string to multiple strings by a semi - colon.This is the old way of storing multi - string values. - // Currently used for the post_process config value only. - boost::split(values, str, boost::is_any_of(";")); - if (values.size() == 1 && values[0] == "") - values.resize(0); + if (str.back() == ';') + str.pop_back(); + // Split a string to multiple strings by a semi - colon.This is the old way of storing multi - string values. + // Currently used for the post_process config value only. + boost::split(values, str, boost::is_any_of(";")); + if (values.size() == 1 && values[0] == "") + values.resize(0); } - config.option(opt_key)->values = values; - } - else{ + config.option(opt_key)->values = values; + } else { auto vec_new = std::make_unique(boost::any_cast(value)); - config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); - } - } - break; - case coBool: - config.set_key_value(opt_key, new ConfigOptionBool(boost::any_cast(value))); - break; - case coBools:{ + config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); + } + } break; + case coBool: config.set_key_value(opt_key, new ConfigOptionBool(boost::any_cast(value))); break; + case coBools: { auto vec_new = std::make_unique(boost::any_cast(value) != 0); - config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); - break;} - case coInt: - config.set_key_value(opt_key, new ConfigOptionInt(boost::any_cast(value))); - break; - case coInts:{ + config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); + break; + } + case coInt: config.set_key_value(opt_key, new ConfigOptionInt(boost::any_cast(value))); break; + case coInts: { auto vec_new = std::make_unique(boost::any_cast(value)); - config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); - } - break; - case coEnum:{ - auto *opt = opt_def->default_value.get()->clone(); - opt->setInt(boost::any_cast(value)); - config.set_key_value(opt_key, opt); - } - break; - // BBS - case coEnums:{ + config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); + } break; + case coEnum: { + auto* opt = opt_def->default_value.get()->clone(); + opt->setInt(boost::any_cast(value)); + config.set_key_value(opt_key, opt); + } break; + // BBS + case coEnums: { auto vec_new = std::make_unique(std::vector{boost::any_cast(value)}); - if (config.has(opt_key)) - config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); - } - break; - case coPoint:{ - config.set_key_value(opt_key, new ConfigOptionPoint(boost::any_cast(value))); - } - break; - case coPoints:{ - if (opt_key == "printable_area" || opt_key == "bed_exclude_area" || opt_key == "thumbnails" || opt_key == "wrapping_exclude_area" ) { - config.option(opt_key)->values = boost::any_cast>(value); - break; - } + if (config.has(opt_key)) + config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); + } break; + case coPoint: { + config.set_key_value(opt_key, new ConfigOptionPoint(boost::any_cast(value))); + } break; + case coPoints: { + if (opt_key == "printable_area" || opt_key == "bed_exclude_area" || opt_key == "thumbnails" || + opt_key == "wrapping_exclude_area") { + config.option(opt_key)->values = boost::any_cast>(value); + break; + } auto vec_new = std::make_unique(boost::any_cast(value)); - config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); - } - break; - case coNone: - break; - default: - break; - } - } - catch (const std::exception &e) - { - wxLogError(format_wxstr("Internal error when changing value for %1%: %2%", opt_key, e.what())); - } + config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); + } break; + case coNone: break; + default: break; + } + } catch (const std::exception& e) { + wxLogError(format_wxstr("Internal error when changing value for %1%: %2%", opt_key, e.what())); + } } void show_error(wxWindow* parent, const wxString& message, bool monospaced_font) @@ -249,166 +247,151 @@ void show_error(wxWindow* parent, const wxString& message, bool monospaced_font) void show_error(wxWindow* parent, const char* message, bool monospaced_font) { - assert(message); - show_error(parent, wxString::FromUTF8(message), monospaced_font); + assert(message); + show_error(parent, wxString::FromUTF8(message), monospaced_font); } void show_error_id(int id, const std::string& message) { - auto *parent = id != 0 ? wxWindow::FindWindowById(id) : nullptr; - show_error(parent, message); + auto* parent = id != 0 ? wxWindow::FindWindowById(id) : nullptr; + show_error(parent, message); } void show_info(wxWindow* parent, const wxString& message, const wxString& title) { - //wxMessageDialog msg_wingow(parent, message, wxString(SLIC3R_APP_NAME " - ") + (title.empty() ? _L("Notice") : title), wxOK | wxICON_INFORMATION); - MessageDialog msg_wingow(parent, message, wxString(SLIC3R_APP_FULL_NAME " - ") + (title.empty() ? _L("Notice") : title), wxOK | wxICON_INFORMATION); - msg_wingow.ShowModal(); + // wxMessageDialog msg_wingow(parent, message, wxString(SLIC3R_APP_NAME " - ") + (title.empty() ? _L("Notice") : title), wxOK | + // wxICON_INFORMATION); + MessageDialog msg_wingow(parent, message, wxString(SLIC3R_APP_FULL_NAME " - ") + (title.empty() ? _L("Notice") : title), + wxOK | wxICON_INFORMATION); + msg_wingow.ShowModal(); } void show_info(wxWindow* parent, const char* message, const char* title) { - assert(message); - show_info(parent, wxString::FromUTF8(message), title ? wxString::FromUTF8(title) : wxString()); + assert(message); + show_info(parent, wxString::FromUTF8(message), title ? wxString::FromUTF8(title) : wxString()); } void warning_catcher(wxWindow* parent, const wxString& message) { - MessageDialog msg(parent, message, _L("Warning"), wxOK | wxICON_WARNING); - msg.ShowModal(); + MessageDialog msg(parent, message, _L("Warning"), wxOK | wxICON_WARNING); + msg.ShowModal(); } -static wxString bold(const wxString& str) -{ - return wxString::Format("%s", str); -}; +static wxString bold(const wxString& str) { return wxString::Format("%s", str); }; -static wxString bold_string(const wxString& str) -{ - return wxString::Format("\"%s\"", str); -}; +static wxString bold_string(const wxString& str) { return wxString::Format("\"%s\"", str); }; static void add_config_substitutions(const ConfigSubstitutions& conf_substitutions, wxString& changes) { - changes += ""; - for (const ConfigSubstitution& conf_substitution : conf_substitutions) { - wxString new_val; - const ConfigOptionDef* def = conf_substitution.opt_def; - if (!def) - continue; - switch (def->type) { - case coEnum: - { - const std::vector& labels = def->enum_labels; - const std::vector& values = def->enum_values; - int val = conf_substitution.new_value->getInt(); + changes += "
"; + for (const ConfigSubstitution& conf_substitution : conf_substitutions) { + wxString new_val; + const ConfigOptionDef* def = conf_substitution.opt_def; + if (!def) + continue; + switch (def->type) { + case coEnum: { + const std::vector& labels = def->enum_labels; + const std::vector& values = def->enum_values; + int val = conf_substitution.new_value->getInt(); - bool is_infill = def->opt_key == "top_surface_pattern" || - def->opt_key == "bottom_surface_pattern" || - def->opt_key == "internal_solid_infill_pattern" || - def->opt_key == "support_base_pattern" || - def->opt_key == "support_interface_pattern" || - def->opt_key == "ironing_pattern" || - def->opt_key == "support_ironing_pattern" || - def->opt_key == "sparse_infill_pattern"; + bool is_infill = def->opt_key == "top_surface_pattern" || def->opt_key == "bottom_surface_pattern" || + def->opt_key == "internal_solid_infill_pattern" || def->opt_key == "support_base_pattern" || + def->opt_key == "support_interface_pattern" || def->opt_key == "ironing_pattern" || + def->opt_key == "support_ironing_pattern" || def->opt_key == "sparse_infill_pattern"; - // Each infill doesn't use all list of infill declared in PrintConfig.hpp. - // So we should "convert" val to the correct one - if (is_infill) { - for (const auto& key_val : *def->enum_keys_map) - if ((int)key_val.second == val) { - auto it = std::find(values.begin(), values.end(), key_val.first); - if (it == values.end()) - break; - auto idx = it - values.begin(); - new_val = wxString("\"") + values[idx] + "\"" + " (" + from_u8(_utf8(labels[idx])) + ")"; - break; - } - if (new_val.IsEmpty()) { - assert(false); - new_val = _L("Undefined"); - } - } - else - new_val = wxString("\"") + values[val] + "\"" + " (" + from_u8(_utf8(labels[val])) + ")"; - break; - } - case coEnums: - { - const std::vector& labels = def->enum_labels; - const std::vector& values = def->enum_values; - std::string val = conf_substitution.new_value->serialize(); - new_val = wxString("\"") + from_u8(_utf8(val)) + "\""; - break; - } - case coBool: - new_val = conf_substitution.new_value->getBool() ? "true" : "false"; - break; - case coBools: - if (conf_substitution.new_value->nullable()) - for (const char v : static_cast(conf_substitution.new_value.get())->values) - new_val += std::string(v == ConfigOptionBoolsNullable::nil_value() ? "nil" : v ? "true" : "false") + ", "; - else - for (const char v : static_cast(conf_substitution.new_value.get())->values) - new_val += std::string(v ? "true" : "false") + ", "; - if (! new_val.empty()) - new_val.erase(new_val.begin() + new_val.size() - 2, new_val.end()); - break; - default: - assert(false); - } + // Each infill doesn't use all list of infill declared in PrintConfig.hpp. + // So we should "convert" val to the correct one + if (is_infill) { + for (const auto& key_val : *def->enum_keys_map) + if ((int) key_val.second == val) { + auto it = std::find(values.begin(), values.end(), key_val.first); + if (it == values.end()) + break; + auto idx = it - values.begin(); + new_val = wxString("\"") + values[idx] + "\"" + " (" + from_u8(_utf8(labels[idx])) + ")"; + break; + } + if (new_val.IsEmpty()) { + assert(false); + new_val = _L("Undefined"); + } + } else + new_val = wxString("\"") + values[val] + "\"" + " (" + from_u8(_utf8(labels[val])) + ")"; + break; + } + case coEnums: { + const std::vector& labels = def->enum_labels; + const std::vector& values = def->enum_values; + std::string val = conf_substitution.new_value->serialize(); + new_val = wxString("\"") + from_u8(_utf8(val)) + "\""; + break; + } + case coBool: new_val = conf_substitution.new_value->getBool() ? "true" : "false"; break; + case coBools: + if (conf_substitution.new_value->nullable()) + for (const char v : static_cast(conf_substitution.new_value.get())->values) + new_val += std::string(v == ConfigOptionBoolsNullable::nil_value() ? "nil" : v ? "true" : "false") + ", "; + else + for (const char v : static_cast(conf_substitution.new_value.get())->values) + new_val += std::string(v ? "true" : "false") + ", "; + if (!new_val.empty()) + new_val.erase(new_val.begin() + new_val.size() - 2, new_val.end()); + break; + default: assert(false); + } - changes += format_wxstr(""; - } - changes += "
\"%1%\" (%2%): ", def->opt_key, _(def->label)) + - format_wxstr(_L("%1% was replaced with %2%"), bold_string(conf_substitution.old_value), bold(new_val)) + - "
"; + changes += format_wxstr("\"%1%\" (%2%): ", def->opt_key, _(def->label)) + + format_wxstr(_L("%1% was replaced with %2%"), bold_string(conf_substitution.old_value), bold(new_val)) + ""; + } + changes += ""; } static wxString substitution_message(const wxString& changes) { - return - _L("The configuration may be generated by a newer version of OrcaSlicer.") + " " + - _L("Some values have been replaced. Please check them:") + "\n" + changes + "\n"; + return _L("The configuration may be generated by a newer version of OrcaSlicer.") + " " + + _L("Some values have been replaced. Please check them:") + "\n" + changes + "\n"; } void show_substitutions_info(const PresetsConfigSubstitutions& presets_config_substitutions) { - wxString changes; + wxString changes; - auto preset_type_name = [](Preset::Type type) { - switch (type) { - case Preset::TYPE_PRINT: return _L("Process"); - // BBS: remove TYPE_SLA_PRINT - case Preset::TYPE_FILAMENT: return _L("Filament"); - // BBS: remove TYPE_SLA_MATERIAL - case Preset::TYPE_PRINTER: return _L("Machine"); - // BBS: remove TYPE_PHYSICAL_PRINTER - default: assert(false); return wxString(); - } - }; + auto preset_type_name = [](Preset::Type type) { + switch (type) { + case Preset::TYPE_PRINT: return _L("Process"); + // BBS: remove TYPE_SLA_PRINT + case Preset::TYPE_FILAMENT: return _L("Filament"); + // BBS: remove TYPE_SLA_MATERIAL + case Preset::TYPE_PRINTER: return _L("Machine"); + // BBS: remove TYPE_PHYSICAL_PRINTER + default: assert(false); return wxString(); + } + }; - for (const PresetConfigSubstitutions& substitution : presets_config_substitutions) { - changes += "\n\n" + format_wxstr("%1% : %2%", preset_type_name(substitution.preset_type), bold_string(substitution.preset_name)); - if (!substitution.preset_file.empty()) - changes += format_wxstr(" (%1%)", substitution.preset_file); + for (const PresetConfigSubstitutions& substitution : presets_config_substitutions) { + changes += "\n\n" + format_wxstr("%1% : %2%", preset_type_name(substitution.preset_type), bold_string(substitution.preset_name)); + if (!substitution.preset_file.empty()) + changes += format_wxstr(" (%1%)", substitution.preset_file); - add_config_substitutions(substitution.substitutions, changes); - } + add_config_substitutions(substitution.substitutions, changes); + } - InfoDialog msg(nullptr, _L("Configuration package was loaded, but some values were not recognized."), substitution_message(changes), true); - msg.ShowModal(); + InfoDialog msg(nullptr, _L("Configuration package was loaded, but some values were not recognized."), substitution_message(changes), + true); + msg.ShowModal(); } void show_substitutions_info(const ConfigSubstitutions& config_substitutions, const std::string& filename) { - wxString changes = "\n"; - add_config_substitutions(config_substitutions, changes); + wxString changes = "\n"; + add_config_substitutions(config_substitutions, changes); - InfoDialog msg(nullptr, - format_wxstr(_L("Configuration file \"%1%\" was loaded, but some values were not recognized."), from_u8(filename)), - substitution_message(changes), true); - msg.ShowModal(); + InfoDialog msg(nullptr, + format_wxstr(_L("Configuration file \"%1%\" was loaded, but some values were not recognized."), from_u8(filename)), + substitution_message(changes), true); + msg.ShowModal(); } void create_combochecklist(wxComboCtrl* comboCtrl, const std::string& text, const std::string& items) @@ -419,98 +402,89 @@ void create_combochecklist(wxComboCtrl* comboCtrl, const std::string& text, cons wxCheckListBoxComboPopup* popup = new wxCheckListBoxComboPopup; if (popup != nullptr) { - // FIXME If the following line is removed, the combo box popup list will not react to mouse clicks. + // FIXME If the following line is removed, the combo box popup list will not react to mouse clicks. // On the other side, with this line the combo box popup cannot be closed by clicking on the combo button on Windows 10. comboCtrl->UseAltPopupWindow(); - int max_width = 0; + int max_width = 0; - // the following line messes up the popup size the first time it is shown on wxWidgets 3.1.3 + // the following line messes up the popup size the first time it is shown on wxWidgets 3.1.3 // comboCtrl->EnablePopupAnimation(false); #ifdef _WIN32 - popup->SetFont(comboCtrl->GetFont()); + popup->SetFont(comboCtrl->GetFont()); #endif // _WIN32 - comboCtrl->SetPopupControl(popup); - wxString title = from_u8(text); - max_width = std::max(max_width, 60 + comboCtrl->GetTextExtent(title).x); - popup->SetStringValue(title); - popup->Bind(wxEVT_CHECKLISTBOX, [popup](wxCommandEvent& evt) { popup->OnCheckListBox(evt); }); - popup->Bind(wxEVT_LISTBOX, [popup](wxCommandEvent& evt) { popup->OnListBoxSelection(evt); }); + comboCtrl->SetPopupControl(popup); + wxString title = from_u8(text); + max_width = std::max(max_width, 60 + comboCtrl->GetTextExtent(title).x); + popup->SetStringValue(title); + popup->Bind(wxEVT_CHECKLISTBOX, [popup](wxCommandEvent& evt) { popup->OnCheckListBox(evt); }); + popup->Bind(wxEVT_LISTBOX, [popup](wxCommandEvent& evt) { popup->OnListBoxSelection(evt); }); popup->Bind(wxEVT_KEY_DOWN, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); }); popup->Bind(wxEVT_KEY_UP, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); }); std::vector items_str; boost::split(items_str, items, boost::is_any_of("|"), boost::token_compress_off); - // each item must be composed by 2 parts - assert(items_str.size() %2 == 0); + // each item must be composed by 2 parts + assert(items_str.size() % 2 == 0); - for (size_t i = 0; i < items_str.size(); i += 2) { - wxString label = from_u8(items_str[i]); - max_width = std::max(max_width, 60 + popup->GetTextExtent(label).x); - popup->Append(label); - popup->Check(i / 2, items_str[i + 1] == "1"); - } + for (size_t i = 0; i < items_str.size(); i += 2) { + wxString label = from_u8(items_str[i]); + max_width = std::max(max_width, 60 + popup->GetTextExtent(label).x); + popup->Append(label); + popup->Check(i / 2, items_str[i + 1] == "1"); + } - comboCtrl->SetMinClientSize(wxSize(max_width, -1)); + comboCtrl->SetMinClientSize(wxSize(max_width, -1)); wxGetApp().UpdateDarkUI(popup); - } + } } unsigned int combochecklist_get_flags(wxComboCtrl* comboCtrl) { - unsigned int flags = 0; + unsigned int flags = 0; - wxCheckListBoxComboPopup* popup = wxDynamicCast(comboCtrl->GetPopupControl(), wxCheckListBoxComboPopup); - if (popup != nullptr) { - for (unsigned int i = 0; i < popup->GetCount(); ++i) { - if (popup->IsChecked(i)) - flags |= 1 << i; - } - } + wxCheckListBoxComboPopup* popup = wxDynamicCast(comboCtrl->GetPopupControl(), wxCheckListBoxComboPopup); + if (popup != nullptr) { + for (unsigned int i = 0; i < popup->GetCount(); ++i) { + if (popup->IsChecked(i)) + flags |= 1 << i; + } + } - return flags; + return flags; } void combochecklist_set_flags(wxComboCtrl* comboCtrl, unsigned int flags) { - wxCheckListBoxComboPopup* popup = wxDynamicCast(comboCtrl->GetPopupControl(), wxCheckListBoxComboPopup); - if (popup != nullptr) { - for (unsigned int i = 0; i < popup->GetCount(); ++i) { - popup->Check(i, (flags & (1 << i)) != 0); - } - } + wxCheckListBoxComboPopup* popup = wxDynamicCast(comboCtrl->GetPopupControl(), wxCheckListBoxComboPopup); + if (popup != nullptr) { + for (unsigned int i = 0; i < popup->GetCount(); ++i) { + popup->Check(i, (flags & (1 << i)) != 0); + } + } } -AppConfig* get_app_config() +AppConfig* get_app_config() { return wxGetApp().app_config; } + +wxString from_u8(const std::string& str) { return wxString::FromUTF8(str.c_str()); } + +std::string into_u8(const wxString& str) { - return wxGetApp().app_config; + auto buffer_utf8 = str.utf8_str(); + return std::string(buffer_utf8.data()); } -wxString from_u8(const std::string &str) -{ - return wxString::FromUTF8(str.c_str()); -} - -std::string into_u8(const wxString &str) -{ - auto buffer_utf8 = str.utf8_str(); - return std::string(buffer_utf8.data()); -} - -wxString from_path(const boost::filesystem::path &path) +wxString from_path(const boost::filesystem::path& path) { #ifdef _WIN32 - return wxString(path.string()); + return wxString(path.string()); #else - return from_u8(path.string()); + return from_u8(path.string()); #endif } -boost::filesystem::path into_path(const wxString &str) -{ - return boost::filesystem::path(str.wx_str()); -} +boost::filesystem::path into_path(const wxString& str) { return boost::filesystem::path(str.wx_str()); } void about() { @@ -520,62 +494,62 @@ void about() void login() { - //LoginDialog dlg; - //dlg.ShowModal(); + // LoginDialog dlg; + // dlg.ShowModal(); - ZUserLogin dlg; + ZUserLogin dlg; dlg.run(); } void desktop_open_datadir_folder() { - // Execute command to open a file explorer, platform dependent. - // FIXME: The const_casts aren't needed in wxWidgets 3.1, remove them when we upgrade. + // Execute command to open a file explorer, platform dependent. + // FIXME: The const_casts aren't needed in wxWidgets 3.1, remove them when we upgrade. - const auto path = data_dir(); + const auto path = data_dir(); #ifdef _WIN32 - const wxString widepath = from_u8(path); - const wchar_t *argv[] = { L"explorer", widepath.GetData(), nullptr }; - ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr); + const wxString widepath = from_u8(path); + const wchar_t* argv[] = {L"explorer", widepath.GetData(), nullptr}; + ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr); #elif __APPLE__ - const char *argv[] = { "open", path.data(), nullptr }; - ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr); + const char* argv[] = {"open", path.data(), nullptr}; + ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr); #else - const char *argv[] = { "xdg-open", path.data(), nullptr }; + const char* argv[] = {"xdg-open", path.data(), nullptr}; - // Check if we're running in an AppImage container, if so, we need to remove AppImage's env vars, - // because they may mess up the environment expected by the file manager. - // Mostly this is about LD_LIBRARY_PATH, but we remove a few more too for good measure. - if (wxGetEnv("APPIMAGE", nullptr)) { - // We're running from AppImage - wxEnvVariableHashMap env_vars; - wxGetEnvMap(&env_vars); + // Check if we're running in an AppImage container, if so, we need to remove AppImage's env vars, + // because they may mess up the environment expected by the file manager. + // Mostly this is about LD_LIBRARY_PATH, but we remove a few more too for good measure. + if (wxGetEnv("APPIMAGE", nullptr)) { + // We're running from AppImage + wxEnvVariableHashMap env_vars; + wxGetEnvMap(&env_vars); - env_vars.erase("APPIMAGE"); - env_vars.erase("APPDIR"); - env_vars.erase("LD_LIBRARY_PATH"); - env_vars.erase("LD_PRELOAD"); - env_vars.erase("UNION_PRELOAD"); + env_vars.erase("APPIMAGE"); + env_vars.erase("APPDIR"); + env_vars.erase("LD_LIBRARY_PATH"); + env_vars.erase("LD_PRELOAD"); + env_vars.erase("UNION_PRELOAD"); - wxExecuteEnv exec_env; - exec_env.env = std::move(env_vars); + wxExecuteEnv exec_env; + exec_env.env = std::move(env_vars); - wxString owd; - if (wxGetEnv("OWD", &owd)) { - // This is the original work directory from which the AppImage image was run, - // set it as CWD for the child process: - exec_env.cwd = std::move(owd); - } + wxString owd; + if (wxGetEnv("OWD", &owd)) { + // This is the original work directory from which the AppImage image was run, + // set it as CWD for the child process: + exec_env.cwd = std::move(owd); + } - ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, &exec_env); - } else { - // Looks like we're NOT running from AppImage, we'll make no changes to the environment. - ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, nullptr); - } + ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, &exec_env); + } else { + // Looks like we're NOT running from AppImage, we'll make no changes to the environment. + ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, nullptr); + } #endif } -void desktop_open_any_folder( const std::string& path ) +void desktop_open_any_folder(const std::string& path) { // Execute command to open a file explorer, platform dependent. // FIXME: The const_casts aren't needed in wxWidgets 3.1, remove them when we upgrade. @@ -588,7 +562,7 @@ void desktop_open_any_folder( const std::string& path ) #else // Orca#6449: Open containing dir instead of opening the file directly. - std::string new_path = path; + std::string new_path = path; boost::filesystem::path p(new_path); if (!fs::is_directory(p)) { new_path = p.parent_path().string(); @@ -619,13 +593,13 @@ void desktop_open_any_folder( const std::string& path ) exec_env.cwd = std::move(owd); } - ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, &exec_env); + ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, &exec_env); } else { // Looks like we're NOT running from AppImage, we'll make no changes to the environment. - ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, nullptr); + ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, nullptr); } #endif } - -} } +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp index db8cf06a61..1da42ddc2d 100644 --- a/src/slic3r/GUI/GUI.hpp +++ b/src/slic3r/GUI/GUI.hpp @@ -1,8 +1,12 @@ #ifndef slic3r_GUI_hpp_ #define slic3r_GUI_hpp_ -namespace boost { class any; } -namespace boost::filesystem { class path; } +namespace boost { +class any; +} +namespace boost::filesystem { +class path; +} #include @@ -15,7 +19,7 @@ class wxComboCtrl; class wxFileDialog; class wxTopLevelWindow; -namespace Slic3r { +namespace Slic3r { class AppConfig; class DynamicPrintConfig; @@ -28,26 +32,36 @@ void enable_screensaver(); bool debugged(); void break_to_debugger(); -// Platform specific Ctrl+/Alt+ (Windows, Linux) vs. ⌘/⌥ (OSX) prefixes +// Platform specific Ctrl+/Alt+ (Windows, Linux) vs. ⌘/⌥ (OSX) prefixes extern const std::string& shortkey_ctrl_prefix(); extern const std::string& shortkey_alt_prefix(); +bool start_filament_index_at_1(); +int filament_index_from_zero_based(int index); +int filament_index_from_one_based(int index); + extern AppConfig* get_app_config(); -extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_language_change); +extern void add_menus(wxMenuBar* menu, int event_preferences_changed, int event_language_change); // Change option value in config void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0); // If monospaced_font is true, the error message is displayed using html
tags, // so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser. -void show_error(wxWindow* parent, const wxString& message, bool monospaced_font = false); -void show_error(wxWindow* parent, const char* message, bool monospaced_font = false); -inline void show_error(wxWindow* parent, const std::string& message, bool monospaced_font = false) { show_error(parent, message.c_str(), monospaced_font); } -void show_error_id(int id, const std::string& message); // For Perl -void show_info(wxWindow* parent, const wxString& message, const wxString& title = wxString()); -void show_info(wxWindow* parent, const char* message, const char* title = nullptr); -inline void show_info(wxWindow* parent, const std::string& message,const std::string& title = std::string()) { show_info(parent, message.c_str(), title.c_str()); } +void show_error(wxWindow* parent, const wxString& message, bool monospaced_font = false); +void show_error(wxWindow* parent, const char* message, bool monospaced_font = false); +inline void show_error(wxWindow* parent, const std::string& message, bool monospaced_font = false) +{ + show_error(parent, message.c_str(), monospaced_font); +} +void show_error_id(int id, const std::string& message); // For Perl +void show_info(wxWindow* parent, const wxString& message, const wxString& title = wxString()); +void show_info(wxWindow* parent, const char* message, const char* title = nullptr); +inline void show_info(wxWindow* parent, const std::string& message, const std::string& title = std::string()) +{ + show_info(parent, message.c_str(), title.c_str()); +} void warning_catcher(wxWindow* parent, const wxString& message); void show_substitutions_info(const PresetsConfigSubstitutions& presets_config_substitutions); void show_substitutions_info(const ConfigSubstitutions& config_substitutions, const std::string& filename); @@ -68,13 +82,13 @@ void combochecklist_set_flags(wxComboCtrl* comboCtrl, unsigned int flags); // wxString conversions: // wxString from std::string in UTF8 -wxString from_u8(const std::string &str); +wxString from_u8(const std::string& str); // std::string in UTF8 from wxString -std::string into_u8(const wxString &str); +std::string into_u8(const wxString& str); // wxString from boost path -wxString from_path(const boost::filesystem::path &path); +wxString from_path(const boost::filesystem::path& path); // boost path from wxString -boost::filesystem::path into_path(const wxString &str); +boost::filesystem::path into_path(const wxString& str); // Display an About dialog extern void about(); diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 44dd7b8f6e..7a335c8c40 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -6,6 +6,7 @@ #include "GUI_Factories.hpp" #include "GUI_ObjectList.hpp" #include "GUI_App.hpp" +#include "GUI.hpp" #include "I18N.hpp" #include "Plater.hpp" #include "ObjectDataViewModel.hpp" @@ -14,7 +15,7 @@ #include "GLCanvas3D.hpp" #include "Selection.hpp" #include "format.hpp" -//BBS: add partplate related logic +// BBS: add partplate related logic #include "PartPlate.hpp" #include "Gizmos/GLGizmoEmboss.hpp" #include "Gizmos/GLGizmoSVG.hpp" @@ -26,110 +27,159 @@ #include "MsgDialog.hpp" #include "wx/utils.h" -namespace Slic3r -{ -namespace GUI -{ +namespace Slic3r { namespace GUI { -static PrinterTechnology printer_technology() -{ - return wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology(); -} +static PrinterTechnology printer_technology() { return wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology(); } -static int filaments_count() -{ - return wxGetApp().filaments_cnt(); -} +static int filaments_count() { return wxGetApp().filaments_cnt(); } static bool is_improper_category(const std::string& category, const int filaments_cnt, const bool is_object_settings = true) { - return category.empty() || - (filaments_cnt == 1 && (category == "Extruders" || category == "Wipe options")) || - (!is_object_settings && category == "Support material"); + return category.empty() || (filaments_cnt == 1 && (category == "Extruders" || category == "Wipe options")) || + (!is_object_settings && category == "Support material"); } - //------------------------------------- // SettingsFactory //------------------------------------- // pt_FFF -static SettingsFactory::Bundle FREQ_SETTINGS_BUNDLE_FFF = -{ - //BBS - { L("Quality"), { "layer_height" } }, - { L("Shell"), { "wall_loops", "top_shell_layers", "bottom_shell_layers"} }, - { L("Infill") , { "sparse_infill_density", "sparse_infill_pattern" } }, +static SettingsFactory::Bundle FREQ_SETTINGS_BUNDLE_FFF = { // BBS - { L("Support") , { "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap", - "support_base_pattern", "support_on_build_plate_only","support_critical_regions_only", - "support_remove_small_overhang", - "support_base_pattern_spacing", "support_expansion"}}, - //BBS - { L("Flush options") , { "flush_into_infill", "flush_into_objects", "flush_into_support"} } -}; + {L("Quality"), {"layer_height"}}, + {L("Shell"), {"wall_loops", "top_shell_layers", "bottom_shell_layers"}}, + {L("Infill"), {"sparse_infill_density", "sparse_infill_pattern"}}, + // BBS + {L("Support"), + {"enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap", "support_base_pattern", + "support_on_build_plate_only", "support_critical_regions_only", "support_remove_small_overhang", "support_base_pattern_spacing", + "support_expansion"}}, + // BBS + {L("Flush options"), {"flush_into_infill", "flush_into_objects", "flush_into_support"}}}; // pt_SLA -static SettingsFactory::Bundle FREQ_SETTINGS_BUNDLE_SLA = -{ +static SettingsFactory::Bundle FREQ_SETTINGS_BUNDLE_SLA = { // BBS: remove SLA freq settings }; -//BBS: add setting data for table -std::map> SettingsFactory::OBJECT_CATEGORY_SETTINGS= -{ - { L("Quality"), {{"layer_height", "",1}, - //{"initial_layer_print_height", "",2}, - {"seam_position", "",2}, - {"slice_closing_radius", "",3}, {"resolution", "",4}, - {"xy_hole_compensation", "",5}, {"xy_contour_compensation", "",6}, {"elefant_foot_compensation", "",7}, - {"make_overhang_printable_angle","", 8},{"make_overhang_printable_hole_size","",9}, {"wall_sequence","",10}, - {"precise_z_height", "",10} +// BBS: add setting data for table +std::map> SettingsFactory::OBJECT_CATEGORY_SETTINGS = + {{L("Quality"), + {{"layer_height", "", 1}, + //{"initial_layer_print_height", "",2}, + {"seam_position", "", 2}, + {"slice_closing_radius", "", 3}, + {"resolution", "", 4}, + {"xy_hole_compensation", "", 5}, + {"xy_contour_compensation", "", 6}, + {"elefant_foot_compensation", "", 7}, + {"make_overhang_printable_angle", "", 8}, + {"make_overhang_printable_hole_size", "", 9}, + {"wall_sequence", "", 10}, + {"precise_z_height", "", 10} - }}, - { L("Support"), {{"brim_type", "",1},{"brim_width", "",2},{"brim_object_gap", "",3},{"brim_use_efc_outline", "",4}, - {"enable_support", "",5},{"support_type", "",6},{"support_threshold_angle", "",7}, {"support_threshold_overlap", "",8}, {"support_on_build_plate_only", "",9}, - {"support_filament", "",10},{"support_interface_filament", "",11},{"support_expansion", "",12},{"support_style", "",13}, - {"tree_support_brim_width", "",14}, {"tree_support_branch_angle", "",15},{"tree_support_branch_angle_organic","",16}, {"tree_support_wall_count", "",17},{"tree_support_branch_diameter_angle", "",18},//tree support - {"support_bottom_z_distance", "",19},{"support_top_z_distance", "",20},{"support_base_pattern", "",21},{"support_base_pattern_spacing", "",22}, - {"support_interface_top_layers", "",23},{"support_interface_bottom_layers", "",24},{"support_interface_spacing", "",25},{"support_bottom_interface_spacing", "",26}, - {"support_object_xy_distance", "",27}, {"bridge_no_support", "",28},{"max_bridge_length", "",29},{"support_critical_regions_only", "",30},{"support_remove_small_overhang","",31}, - {"support_object_first_layer_gap","",32} - }}, - { L("Speed"), {{"support_speed", "",12}, {"support_interface_speed", "",13} - }} -}; + }}, + {L("Support"), + {{"brim_type", "", 1}, + {"brim_width", "", 2}, + {"brim_object_gap", "", 3}, + {"brim_use_efc_outline", "", 4}, + {"enable_support", "", 5}, + {"support_type", "", 6}, + {"support_threshold_angle", "", 7}, + {"support_threshold_overlap", "", 8}, + {"support_on_build_plate_only", "", 9}, + {"support_filament", "", 10}, + {"support_interface_filament", "", 11}, + {"support_expansion", "", 12}, + {"support_style", "", 13}, + {"tree_support_brim_width", "", 14}, + {"tree_support_branch_angle", "", 15}, + {"tree_support_branch_angle_organic", "", 16}, + {"tree_support_wall_count", "", 17}, + {"tree_support_branch_diameter_angle", "", 18}, // tree support + {"support_bottom_z_distance", "", 19}, + {"support_top_z_distance", "", 20}, + {"support_base_pattern", "", 21}, + {"support_base_pattern_spacing", "", 22}, + {"support_interface_top_layers", "", 23}, + {"support_interface_bottom_layers", "", 24}, + {"support_interface_spacing", "", 25}, + {"support_bottom_interface_spacing", "", 26}, + {"support_object_xy_distance", "", 27}, + {"bridge_no_support", "", 28}, + {"max_bridge_length", "", 29}, + {"support_critical_regions_only", "", 30}, + {"support_remove_small_overhang", "", 31}, + {"support_object_first_layer_gap", "", 32}}}, + {L("Speed"), {{"support_speed", "", 12}, {"support_interface_speed", "", 13}}}}; -std::map> SettingsFactory::PART_CATEGORY_SETTINGS= -{ - { L("Quality"), {{"ironing_type", "",8},{"ironing_flow", "",9},{"ironing_spacing", "",10},{"ironing_inset", "", 11},{"bridge_flow", "",11},{"make_overhang_printable", "",11},{"bridge_density", "", 1} - }}, - { L("Strength"), {{"wall_loops", "",1},{"top_shell_layers", L("Top Solid Layers"),1},{"top_shell_thickness", L("Top Minimum Shell Thickness"),1},{"top_surface_density", L("Top Surface Density"),1}, - {"bottom_shell_layers", L("Bottom Solid Layers"),1}, {"bottom_shell_thickness", L("Bottom Minimum Shell Thickness"),1},{"bottom_surface_density", L("Bottom Surface Density"),1}, - {"sparse_infill_density", "",1},{"sparse_infill_pattern", "",1},{"lateral_lattice_angle_1", "",1},{"lateral_lattice_angle_2", "",1},{"infill_overhang_angle", "",1},{"infill_anchor", "",1},{"infill_anchor_max", "",1},{"top_surface_pattern", "",1},{"bottom_surface_pattern", "",1}, {"internal_solid_infill_pattern", "",1}, - {"align_infill_direction_to_model", "", 1}, - {"extra_solid_infills", "", 1}, - {"infill_combination", "",1}, {"infill_combination_max_layer_height", "",1}, {"infill_wall_overlap", "",1},{"top_bottom_infill_wall_overlap", "",1}, {"solid_infill_direction", "",1}, {"infill_direction", "",1}, {"bridge_angle", "",1}, {"internal_bridge_angle", "",1}, {"minimum_sparse_infill_area", "",1} - }}, - { L("Speed"), {{"outer_wall_speed", "",1},{"inner_wall_speed", "",2},{"sparse_infill_speed", "",3},{"top_surface_speed", "",4}, {"internal_solid_infill_speed", "",5}, - {"enable_overhang_speed", "",6}, {"overhang_1_4_speed", "",7}, {"overhang_2_4_speed", "",8}, {"overhang_3_4_speed", "",9}, {"overhang_4_4_speed", "",10}, - {"bridge_speed", "",11}, {"gap_infill_speed", "",12}, {"internal_bridge_speed", "", 13} - }} -}; +std::map> SettingsFactory::PART_CATEGORY_SETTINGS = + {{L("Quality"), + {{"ironing_type", "", 8}, + {"ironing_flow", "", 9}, + {"ironing_spacing", "", 10}, + {"ironing_inset", "", 11}, + {"bridge_flow", "", 11}, + {"make_overhang_printable", "", 11}, + {"bridge_density", "", 1}}}, + {L("Strength"), + {{"wall_loops", "", 1}, + {"top_shell_layers", L("Top Solid Layers"), 1}, + {"top_shell_thickness", L("Top Minimum Shell Thickness"), 1}, + {"top_surface_density", L("Top Surface Density"), 1}, + {"bottom_shell_layers", L("Bottom Solid Layers"), 1}, + {"bottom_shell_thickness", L("Bottom Minimum Shell Thickness"), 1}, + {"bottom_surface_density", L("Bottom Surface Density"), 1}, + {"sparse_infill_density", "", 1}, + {"sparse_infill_pattern", "", 1}, + {"lateral_lattice_angle_1", "", 1}, + {"lateral_lattice_angle_2", "", 1}, + {"infill_overhang_angle", "", 1}, + {"infill_anchor", "", 1}, + {"infill_anchor_max", "", 1}, + {"top_surface_pattern", "", 1}, + {"bottom_surface_pattern", "", 1}, + {"internal_solid_infill_pattern", "", 1}, + {"align_infill_direction_to_model", "", 1}, + {"extra_solid_infills", "", 1}, + {"infill_combination", "", 1}, + {"infill_combination_max_layer_height", "", 1}, + {"infill_wall_overlap", "", 1}, + {"top_bottom_infill_wall_overlap", "", 1}, + {"solid_infill_direction", "", 1}, + {"infill_direction", "", 1}, + {"bridge_angle", "", 1}, + {"internal_bridge_angle", "", 1}, + {"minimum_sparse_infill_area", "", 1}}}, + {L("Speed"), + {{"outer_wall_speed", "", 1}, + {"inner_wall_speed", "", 2}, + {"sparse_infill_speed", "", 3}, + {"top_surface_speed", "", 4}, + {"internal_solid_infill_speed", "", 5}, + {"enable_overhang_speed", "", 6}, + {"overhang_1_4_speed", "", 7}, + {"overhang_2_4_speed", "", 8}, + {"overhang_3_4_speed", "", 9}, + {"overhang_4_4_speed", "", 10}, + {"bridge_speed", "", 11}, + {"gap_infill_speed", "", 12}, + {"internal_bridge_speed", "", 13}}}}; std::vector SettingsFactory::get_options(const bool is_part) { if (printer_technology() == ptSLA) { SLAPrintObjectConfig full_sla_config; - auto options = full_sla_config.keys(); + auto options = full_sla_config.keys(); options.erase(find(options.begin(), options.end(), "layer_height")); return options; } PrintRegionConfig reg_config; - auto options = reg_config.keys(); + auto options = reg_config.keys(); if (!is_part) { - PrintObjectConfig obj_config; + PrintObjectConfig obj_config; std::vector obj_options = obj_config.keys(); options.insert(options.end(), obj_options.begin(), obj_options.end()); } @@ -144,30 +194,34 @@ std::vector SettingsFactory::get_visible_options(const std::s //Shell "wall_loops", "top_shell_layers", "bottom_shell_layers", "top_shell_thickness", "bottom_shell_thickness", //Infill - "sparse_infill_density", "sparse_infill_pattern", "top_surface_pattern", "bottom_surface_pattern", "infill_combination", "infill_direction", "infill_wall_overlap", + "sparse_infill_density", "sparse_infill_pattern", "top_surface_pattern", "bottom_surface_pattern", "infill_combination", + "infill_direction", "infill_wall_overlap", //speed - "inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed", "top_surface_speed", "gap_infill_speed" + "inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed", "top_surface_speed", + "gap_infill_speed" }; t_config_option_keys object_options = { //Quality - "layer_height", "initial_layer_print_height", "adaptive_layer_height", "seam_position", "xy_hole_compensation", "xy_contour_compensation", "elefant_foot_compensation", "support_line_width", + "layer_height", "initial_layer_print_height", "adaptive_layer_height", "seam_position", "xy_hole_compensation", + "xy_contour_compensation", "elefant_foot_compensation", "support_line_width", //Support - "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap", "support_on_build_plate_only", "support_critical_regions_only", "enforce_support_layers", + "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap", "support_on_build_plate_only", + "support_critical_regions_only", "enforce_support_layers", //tree support "tree_support_wall_count", //support - "support_top_z_distance", "support_base_pattern", "support_base_pattern_spacing", "support_interface_top_layers", "support_interface_bottom_layers", "support_interface_spacing", "support_bottom_interface_spacing", "support_object_xy_distance", + "support_top_z_distance", "support_base_pattern", "support_base_pattern_spacing", "support_interface_top_layers", + "support_interface_bottom_layers", "support_interface_spacing", "support_bottom_interface_spacing", "support_object_xy_distance", "support_object_first_layer_gap", //adhesion "brim_type", "brim_width", "brim_object_gap", "raft_layers" };*/ - std::vector options; + std::vector options; std::map>::iterator it; it = PART_CATEGORY_SETTINGS.find(category); - if (it != PART_CATEGORY_SETTINGS.end()) - { + if (it != PART_CATEGORY_SETTINGS.end()) { options = PART_CATEGORY_SETTINGS[category]; } @@ -177,26 +231,22 @@ std::vector SettingsFactory::get_visible_options(const std::s options.insert(options.end(), OBJECT_CATEGORY_SETTINGS[category].begin(), OBJECT_CATEGORY_SETTINGS[category].end()); } - auto sort_func = [](SimpleSettingData& setting1, SimpleSettingData& setting2) { - return (setting1.priority < setting2.priority); - }; + auto sort_func = [](SimpleSettingData& setting1, SimpleSettingData& setting2) { return (setting1.priority < setting2.priority); }; std::sort(options.begin(), options.end(), sort_func); return options; } std::map> SettingsFactory::get_all_visible_options(const bool is_part) { - std::map> option_maps; + std::map> option_maps; std::map>::iterator it1, it2; option_maps = PART_CATEGORY_SETTINGS; if (!is_part) { - for (it1 = OBJECT_CATEGORY_SETTINGS.begin(); it1 != OBJECT_CATEGORY_SETTINGS.end(); it1++) - { + for (it1 = OBJECT_CATEGORY_SETTINGS.begin(); it1 != OBJECT_CATEGORY_SETTINGS.end(); it1++) { std::string category = it1->first; - it2 = PART_CATEGORY_SETTINGS.find(category); - if (it2 != PART_CATEGORY_SETTINGS.end()) - { + it2 = PART_CATEGORY_SETTINGS.find(category); + if (it2 != PART_CATEGORY_SETTINGS.end()) { std::vector& options = option_maps[category]; options.insert(options.end(), it1->second.begin(), it1->second.end()); @@ -204,8 +254,7 @@ std::map> SettingsFactory::get_all_v return (setting1.priority < setting2.priority); }; std::sort(options.begin(), options.end(), sort_func); - } - else { + } else { option_maps.insert(*it1); } } @@ -214,8 +263,9 @@ std::map> SettingsFactory::get_all_v return option_maps; } - -SettingsFactory::Bundle SettingsFactory::get_bundle(const DynamicPrintConfig* config, bool is_object_settings, bool is_layer_settings/* = false*/) +SettingsFactory::Bundle SettingsFactory::get_bundle(const DynamicPrintConfig* config, + bool is_object_settings, + bool is_layer_settings /* = false*/) { auto opt_keys = config->keys(); if (opt_keys.empty()) @@ -235,13 +285,12 @@ SettingsFactory::Bundle SettingsFactory::get_bundle(const DynamicPrintConfig* co const int filaments_cnt = wxGetApp().filaments_cnt(); Bundle bundle; - for (auto& opt_key : opt_keys) - { + for (auto& opt_key : opt_keys) { auto category = config->def()->get(opt_key)->category; if (is_improper_category(category, filaments_cnt, is_object_settings)) continue; - std::vector< std::string > new_category; + std::vector new_category; auto& cat_opt = bundle.find(category) == bundle.end() ? new_category : bundle.at(category); cat_opt.push_back(opt_key); @@ -253,23 +302,22 @@ SettingsFactory::Bundle SettingsFactory::get_bundle(const DynamicPrintConfig* co } // Fill CategoryItem -std::map SettingsFactory::CATEGORY_ICON = -{ -// settings category name related bitmap name +std::map SettingsFactory::CATEGORY_ICON = { + // settings category name related bitmap name // ptFFF - { L("Quality") , "blank2" }, - { L("Shell") , "blank_14" }, - { L("Infill") , "blank_14" }, - { L("Ironing") , "blank_14" }, - { L("Fuzzy Skin") , "menu_fuzzy_skin" }, - { L("Support") , "support" }, - { L("Speed") , "blank_14" }, - { L("Extruders") , "blank_14" }, - { L("Extrusion Width") , "blank_14" }, - { L("Wipe options") , "blank_14" }, - { L("Bed adhesion") , "blank_14" }, -// { L("Speed > Acceleration") , "time" }, - { L("Advanced") , "blank_14" }, + {L("Quality"), "blank2"}, + {L("Shell"), "blank_14"}, + {L("Infill"), "blank_14"}, + {L("Ironing"), "blank_14"}, + {L("Fuzzy Skin"), "menu_fuzzy_skin"}, + {L("Support"), "support"}, + {L("Speed"), "blank_14"}, + {L("Extruders"), "blank_14"}, + {L("Extrusion Width"), "blank_14"}, + {L("Wipe options"), "blank_14"}, + {L("Bed adhesion"), "blank_14"}, + // { L("Speed > Acceleration") , "time" }, + {L("Advanced"), "blank_14"}, // BBS: remove SLA categories }; @@ -280,57 +328,44 @@ wxBitmap SettingsFactory::get_category_bitmap(const std::string& category_name, return create_scaled_bitmap(CATEGORY_ICON.at(category_name)); } - //------------------------------------- // MenuFactory //------------------------------------- // Note: id accords to type of the sub-object (adding volume), so sequence of the menu items is important -static const constexpr std::array, 5> ADD_VOLUME_MENU_ITEMS = {{ +static const constexpr std::array, 5> ADD_VOLUME_MENU_ITEMS = {{ // menu_item Name menu_item bitmap name - {L("Add part"), "menu_add_part" }, // ~ModelVolumeType::MODEL_PART - {L("Add negative part"), "menu_add_negative" }, // ~ModelVolumeType::NEGATIVE_VOLUME - {L("Add modifier"), "menu_add_modifier"}, // ~ModelVolumeType::PARAMETER_MODIFIER - {L("Add support blocker"), "menu_support_blocker"}, // ~ModelVolumeType::SUPPORT_BLOCKER - {L("Add support enforcer"), "menu_support_enforcer"}, // ~ModelVolumeType::SUPPORT_ENFORCER + {L("Add part"), "menu_add_part"}, // ~ModelVolumeType::MODEL_PART + {L("Add negative part"), "menu_add_negative"}, // ~ModelVolumeType::NEGATIVE_VOLUME + {L("Add modifier"), "menu_add_modifier"}, // ~ModelVolumeType::PARAMETER_MODIFIER + {L("Add support blocker"), "menu_support_blocker"}, // ~ModelVolumeType::SUPPORT_BLOCKER + {L("Add support enforcer"), "menu_support_enforcer"}, // ~ModelVolumeType::SUPPORT_ENFORCER }}; // Note: id accords to type of the sub-object (adding volume), so sequence of the menu items is important -static const constexpr std::array, 3> TEXT_VOLUME_ICONS {{ -// menu_item Name menu_item bitmap name - {L("Add text"), "add_text_part"}, // ~ModelVolumeType::MODEL_PART - {L("Add negative text"), "add_text_negative" }, // ~ModelVolumeType::NEGATIVE_VOLUME - {L("Add text modifier"), "add_text_modifier"}, // ~ModelVolumeType::PARAMETER_MODIFIER +static const constexpr std::array, 3> TEXT_VOLUME_ICONS{{ + // menu_item Name menu_item bitmap name + {L("Add text"), "add_text_part"}, // ~ModelVolumeType::MODEL_PART + {L("Add negative text"), "add_text_negative"}, // ~ModelVolumeType::NEGATIVE_VOLUME + {L("Add text modifier"), "add_text_modifier"}, // ~ModelVolumeType::PARAMETER_MODIFIER }}; // Note: id accords to type of the sub-object (adding volume), so sequence of the menu items is important -static const constexpr std::array, 3> SVG_VOLUME_ICONS{{ - {L("Add SVG part"), "svg_part"}, // ~ModelVolumeType::MODEL_PART +static const constexpr std::array, 3> SVG_VOLUME_ICONS{{ + {L("Add SVG part"), "svg_part"}, // ~ModelVolumeType::MODEL_PART {L("Add negative SVG"), "svg_negative"}, // ~ModelVolumeType::NEGATIVE_VOLUME {L("Add SVG modifier"), "svg_modifier"}, // ~ModelVolumeType::PARAMETER_MODIFIER }}; -static Plater* plater() -{ - return wxGetApp().plater(); -} +static Plater* plater() { return wxGetApp().plater(); } -static ObjectList* obj_list() -{ - return wxGetApp().obj_list(); -} +static ObjectList* obj_list() { return wxGetApp().obj_list(); } -static ObjectDataViewModel* list_model() -{ - return wxGetApp().obj_list()->GetModel(); -} +static ObjectDataViewModel* list_model() { return wxGetApp().obj_list()->GetModel(); } -static const Selection& get_selection() -{ - return plater()->get_current_canvas3D(true)->get_selection(); -} +static const Selection& get_selection() { return plater()->get_current_canvas3D(true)->get_selection(); } // category -> vector ( option ; label ) -typedef std::map< std::string, std::vector< std::pair > > FullSettingsHierarchy; +typedef std::map>> FullSettingsHierarchy; static void get_full_settings_hierarchy(FullSettingsHierarchy& settings_menu, const bool is_part) { auto options = SettingsFactory::get_options(is_part); @@ -338,16 +373,15 @@ static void get_full_settings_hierarchy(FullSettingsHierarchy& settings_menu, co const int filaments_cnt = filaments_count(); DynamicPrintConfig config; - for (auto& option : options) - { - auto const opt = config.def()->get(option); - auto category = opt->category; + for (auto& option : options) { + auto const opt = config.def()->get(option); + auto category = opt->category; if (is_improper_category(category, filaments_cnt, !is_part)) continue; - const std::string& label = !opt->full_label.empty() ? opt->full_label : opt->label; - std::pair option_label(option, label); - std::vector< std::pair > new_category; + const std::string& label = !opt->full_label.empty() ? opt->full_label : opt->label; + std::pair option_label(option, label); + std::vector> new_category; auto& cat_opt_label = settings_menu.find(category) == settings_menu.end() ? new_category : settings_menu.at(category); cat_opt_label.push_back(option_label); if (cat_opt_label.size() == 1) @@ -355,7 +389,7 @@ static void get_full_settings_hierarchy(FullSettingsHierarchy& settings_menu, co } } -static wxMenu* create_settings_popupmenu(wxMenu* parent_menu, const bool is_object_settings, wxDataViewItem item/*, ModelConfig& config*/) +static wxMenu* create_settings_popupmenu(wxMenu* parent_menu, const bool is_object_settings, wxDataViewItem item /*, ModelConfig& config*/) { wxMenu* menu = new wxMenu; @@ -364,13 +398,13 @@ static wxMenu* create_settings_popupmenu(wxMenu* parent_menu, const bool is_obje auto get_selected_options_for_category = [categories, item](const wxString& category_name) { wxArrayString names; - wxArrayInt selections; + wxArrayInt selections; - std::vector< std::pair > category_options; + std::vector> category_options; for (auto& cat : categories) { if (_(cat.first) == category_name) { - ModelConfig& config = obj_list()->get_item_config(item); - auto opt_keys = config.keys(); + ModelConfig& config = obj_list()->get_item_config(item); + auto opt_keys = config.keys(); int sel = 0; for (const std::pair& pair : cat.second) { @@ -384,8 +418,7 @@ static wxMenu* create_settings_popupmenu(wxMenu* parent_menu, const bool is_obje } } - if (!category_options.empty() && - wxGetSelectedChoices(selections, _L("Select settings"), category_name, names) != -1) { + if (!category_options.empty() && wxGetSelectedChoices(selections, _L("Select settings"), category_name, names) != -1) { for (auto sel : selections) category_options[sel].second = true; } @@ -393,12 +426,14 @@ static wxMenu* create_settings_popupmenu(wxMenu* parent_menu, const bool is_obje }; for (auto cat : categories) { - append_menu_item(menu, wxID_ANY, _(cat.first), "", - [menu, item, get_selected_options_for_category](wxCommandEvent& event) { - std::vector< std::pair > category_options = get_selected_options_for_category(menu->GetLabel(event.GetId())); - obj_list()->add_category_to_settings_from_selection(category_options, item); - }, SettingsFactory::get_category_bitmap(cat.first), parent_menu, - []() { return true; }, plater()); + append_menu_item( + menu, wxID_ANY, _(cat.first), "", + [menu, item, get_selected_options_for_category](wxCommandEvent& event) { + std::vector> category_options = get_selected_options_for_category( + menu->GetLabel(event.GetId())); + obj_list()->add_category_to_settings_from_selection(category_options, item); + }, + SettingsFactory::get_category_bitmap(cat.first), parent_menu, []() { return true; }, plater()); } return menu; @@ -415,29 +450,29 @@ static void create_freq_settings_popupmenu(wxMenu* menu, const bool is_object_se if (is_improper_category(category.first, filaments_cnt, is_object_settings)) continue; - append_menu_item(menu, wxID_ANY, _(category.first), "", + append_menu_item( + menu, wxID_ANY, _(category.first), "", [menu, item, is_object_settings, bundle](wxCommandEvent& event) { - wxString category_name = menu->GetLabel(event.GetId()); - std::vector options; - for (auto& category : bundle) - if (category_name == _(category.first)) { - options = category.second; - break; - } - if (options.empty()) - return; - // Because of we couldn't edited layer_height for ItVolume from settings list, - // correct options according to the selected item type : remove "layer_height" option - if (!is_object_settings && category_name == _("Quality")) { - const auto layer_height_it = std::find(options.begin(), options.end(), "layer_height"); - if (layer_height_it != options.end()) - options.erase(layer_height_it); + wxString category_name = menu->GetLabel(event.GetId()); + std::vector options; + for (auto& category : bundle) + if (category_name == _(category.first)) { + options = category.second; + break; } + if (options.empty()) + return; + // Because of we couldn't edited layer_height for ItVolume from settings list, + // correct options according to the selected item type : remove "layer_height" option + if (!is_object_settings && category_name == _("Quality")) { + const auto layer_height_it = std::find(options.begin(), options.end(), "layer_height"); + if (layer_height_it != options.end()) + options.erase(layer_height_it); + } - obj_list()->add_category_to_settings_from_frequent(options, item); - }, - SettingsFactory::get_category_bitmap(category.first), menu, - []() { return true; }, plater()); + obj_list()->add_category_to_settings_from_frequent(options, item); + }, + SettingsFactory::get_category_bitmap(category.first), menu, []() { return true; }, plater()); } } @@ -464,64 +499,70 @@ std::vector MenuFactory::get_svg_volume_bitmaps() { std::vector volume_bmps; volume_bmps.reserve(SVG_VOLUME_ICONS.size()); - for (const auto &item : SVG_VOLUME_ICONS) + for (const auto& item : SVG_VOLUME_ICONS) volume_bmps.push_back(create_scaled_bitmap(item.second)); return volume_bmps; } void MenuFactory::append_menu_item_set_visible(wxMenu* menu) { - bool has_one_shown = false; - const Selection& selection = plater()->canvas3D()->get_selection(); + bool has_one_shown = false; + const Selection& selection = plater()->canvas3D()->get_selection(); for (unsigned int i : selection.get_volume_idxs()) { has_one_shown |= selection.get_volume(i)->visible; } - append_menu_item(menu, wxID_ANY, has_one_shown ?_L("Hide") : _L("Show"), "", - [has_one_shown](wxCommandEvent&) { plater()->set_selected_visible(!has_one_shown); }, "", nullptr, - []() { return true; }, m_parent); + append_menu_item( + menu, wxID_ANY, has_one_shown ? _L("Hide") : _L("Show"), "", + [has_one_shown](wxCommandEvent&) { plater()->set_selected_visible(!has_one_shown); }, "", nullptr, []() { return true; }, m_parent); } void MenuFactory::append_menu_item_delete(wxMenu* menu) { #ifdef __WINDOWS__ - append_menu_item(menu, wxID_ANY, _L("Delete") + "\t" + _L("Del"), _L("Delete the selected object"), - [](wxCommandEvent&) { plater()->remove_selected(); }, "menu_delete", nullptr, - []() { return plater()->can_delete(); }, m_parent); + append_menu_item( + menu, wxID_ANY, _L("Delete") + "\t" + _L("Del"), _L("Delete the selected object"), + [](wxCommandEvent&) { plater()->remove_selected(); }, "menu_delete", nullptr, []() { return plater()->can_delete(); }, m_parent); #else - append_menu_item(menu, wxID_ANY, _L("Delete") + "\t" + _L("Backspace"), _L("Delete the selected object"), - [](wxCommandEvent&) { plater()->remove_selected(); }, "", nullptr, - []() { return plater()->can_delete(); }, m_parent); + append_menu_item( + menu, wxID_ANY, _L("Delete") + "\t" + _L("Backspace"), _L("Delete the selected object"), + [](wxCommandEvent&) { plater()->remove_selected(); }, "", nullptr, []() { return plater()->can_delete(); }, m_parent); #endif } -wxMenu* MenuFactory::append_submenu_add_generic(wxMenu* menu, ModelVolumeType type) { +wxMenu* MenuFactory::append_submenu_add_generic(wxMenu* menu, ModelVolumeType type) +{ auto sub_menu = new wxMenu; if (type != ModelVolumeType::INVALID) { - append_menu_item(sub_menu, wxID_ANY, _L("Load..."), "", - [type](wxCommandEvent&) { obj_list()->load_subobject(type); }, "menu_load", menu); + append_menu_item( + sub_menu, wxID_ANY, _L("Load..."), "", [type](wxCommandEvent&) { obj_list()->load_subobject(type); }, "menu_load", menu); sub_menu->AppendSeparator(); } - append_menu_item(sub_menu, wxID_ANY, _L("Cube"), "", - [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Cube") ,type); },"menu_obj_cube", menu); + append_menu_item( + sub_menu, wxID_ANY, _L("Cube"), "", [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Cube"), type); }, + "menu_obj_cube", menu); - append_menu_item(sub_menu, wxID_ANY, _L("Cylinder"), "", - [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Cylinder"), type); },"menu_obj_cylinder", menu); + append_menu_item( + sub_menu, wxID_ANY, _L("Cylinder"), "", [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Cylinder"), type); }, + "menu_obj_cylinder", menu); - append_menu_item(sub_menu, wxID_ANY, _L("Sphere"), "", - [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Sphere"), type); },"menu_obj_sphere", menu); + append_menu_item( + sub_menu, wxID_ANY, _L("Sphere"), "", [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Sphere"), type); }, + "menu_obj_sphere", menu); - append_menu_item(sub_menu, wxID_ANY, _L("Cone"), "", - [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Cone"), type); },"menu_obj_cone", menu); + append_menu_item( + sub_menu, wxID_ANY, _L("Cone"), "", [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Cone"), type); }, + "menu_obj_cone", menu); - append_menu_item(sub_menu, wxID_ANY, _L("Disc"), "", - [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Disc"), type); },"menu_obj_disc", menu); - - append_menu_item(sub_menu, wxID_ANY, _L("Torus"), "", - [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Torus"), type); },"menu_obj_torus", menu); + append_menu_item( + sub_menu, wxID_ANY, _L("Disc"), "", [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Disc"), type); }, + "menu_obj_disc", menu); + append_menu_item( + sub_menu, wxID_ANY, _L("Torus"), "", [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Torus"), type); }, + "menu_obj_torus", menu); append_menu_item_add_text(sub_menu, type); append_menu_item_add_svg(sub_menu, type); @@ -530,11 +571,12 @@ wxMenu* MenuFactory::append_submenu_add_generic(wxMenu* menu, ModelVolumeType ty } // Orca: add submenu for adding handy models -wxMenu* MenuFactory::append_submenu_add_handy_model(wxMenu* menu, ModelVolumeType type) { +wxMenu* MenuFactory::append_submenu_add_handy_model(wxMenu* menu, ModelVolumeType type) +{ auto sub_menu = new wxMenu; - for (auto &item : {L("Orca Cube"), L("Orca Tolerance Test"), L("3DBenchy"), L("Cali Cat"), L("Autodesk FDM Test"), - L("Voron Cube"), L("Stanford Bunny"), L("Orca String Hell") }) { + for (auto& item : {L("Orca Cube"), L("Orca Tolerance Test"), L("3DBenchy"), L("Cali Cat"), L("Autodesk FDM Test"), L("Voron Cube"), + L("Stanford Bunny"), L("Orca String Hell")}) { append_menu_item( sub_menu, wxID_ANY, _(item), "", [type, item](wxCommandEvent&) { @@ -592,14 +634,15 @@ wxMenu* MenuFactory::append_submenu_add_handy_model(wxMenu* menu, ModelVolumeTyp "", menu); } - return sub_menu; } -static void append_menu_itemm_add_(const wxString& name, GLGizmosManager::EType gizmo_type, wxMenu *menu, ModelVolumeType type, bool is_submenu_item) { - auto add_ = [type, gizmo_type](const wxCommandEvent & /*unnamed*/) { - const GLCanvas3D *canvas = plater()->canvas3D(); - const GLGizmosManager &mng = canvas->get_gizmos_manager(); - GLGizmoBase *gizmo_base = mng.get_gizmo(gizmo_type); +static void append_menu_itemm_add_( + const wxString& name, GLGizmosManager::EType gizmo_type, wxMenu* menu, ModelVolumeType type, bool is_submenu_item) +{ + auto add_ = [type, gizmo_type](const wxCommandEvent& /*unnamed*/) { + const GLCanvas3D* canvas = plater()->canvas3D(); + const GLGizmosManager& mng = canvas->get_gizmos_manager(); + GLGizmoBase* gizmo_base = mng.get_gizmo(gizmo_type); ModelVolumeType volume_type = type; // no selected object means create new object @@ -608,18 +651,20 @@ static void append_menu_itemm_add_(const wxString& name, GLGizmosManager::EType auto screen_position = canvas->get_popup_menu_position(); if (gizmo_type == GLGizmosManager::Emboss) { - auto emboss = dynamic_cast(gizmo_base); + auto emboss = dynamic_cast(gizmo_base); assert(emboss != nullptr); - if (emboss == nullptr) return; + if (emboss == nullptr) + return; if (screen_position.has_value()) { emboss->create_volume(volume_type, *screen_position); } else { emboss->create_volume(volume_type); } } else if (gizmo_type == GLGizmosManager::Svg) { - auto svg = dynamic_cast(gizmo_base); + auto svg = dynamic_cast(gizmo_base); assert(svg != nullptr); - if (svg == nullptr) return; + if (svg == nullptr) + return; if (screen_position.has_value()) { svg->create_volume(volume_type, *screen_position); } else { @@ -633,17 +678,19 @@ static void append_menu_itemm_add_(const wxString& name, GLGizmosManager::EType ) { wxString item_name = wxString(is_submenu_item ? "" : _(ADD_VOLUME_MENU_ITEMS[int(type)].first) + ": ") + name; menu->AppendSeparator(); - auto def_icon_name = (gizmo_type == GLGizmosManager::Emboss) ? "menu_obj_text" : "menu_obj_svg"; - const std::string icon_name = is_submenu_item ? def_icon_name : ADD_VOLUME_MENU_ITEMS[int(type)].second; + auto def_icon_name = (gizmo_type == GLGizmosManager::Emboss) ? "menu_obj_text" : "menu_obj_svg"; + const std::string icon_name = is_submenu_item ? def_icon_name : ADD_VOLUME_MENU_ITEMS[int(type)].second; append_menu_item(menu, wxID_ANY, item_name, "", add_, icon_name, menu); } } -void MenuFactory::append_menu_item_add_text(wxMenu* menu, ModelVolumeType type, bool is_submenu_item/* = true*/){ +void MenuFactory::append_menu_item_add_text(wxMenu* menu, ModelVolumeType type, bool is_submenu_item /* = true*/) +{ append_menu_itemm_add_(_L("Text"), GLGizmosManager::Emboss, menu, type, is_submenu_item); } -void MenuFactory::append_menu_item_add_svg(wxMenu *menu, ModelVolumeType type, bool is_submenu_item /* = true*/){ +void MenuFactory::append_menu_item_add_svg(wxMenu* menu, ModelVolumeType type, bool is_submenu_item /* = true*/) +{ append_menu_itemm_add_(_L("SVG"), GLGizmosManager::Svg, menu, type, is_submenu_item); } @@ -652,7 +699,7 @@ void MenuFactory::append_menu_items_add_volume(wxMenu* menu) // Update "add" items(delete old & create new) settings popupmenu for (auto& item : ADD_VOLUME_MENU_ITEMS) { const wxString item_name = _(item.first); - int item_id = menu->FindItem(item_name); + int item_id = menu->FindItem(item_name); if (item_id != wxNOT_FOUND) menu->Destroy(item_id); @@ -661,13 +708,13 @@ void MenuFactory::append_menu_items_add_volume(wxMenu* menu) menu->Destroy(item_id); } - for (size_t type = 0; type < ADD_VOLUME_MENU_ITEMS.size(); type++) - { + for (size_t type = 0; type < ADD_VOLUME_MENU_ITEMS.size(); type++) { auto& item = ADD_VOLUME_MENU_ITEMS[type]; wxMenu* sub_menu = append_submenu_add_generic(menu, ModelVolumeType(type)); - append_submenu(menu, sub_menu, wxID_ANY, _(item.first), "", item.second, - []() { return obj_list()->is_instance_or_object_selected(); }, m_parent); + append_submenu( + menu, sub_menu, wxID_ANY, _(item.first), "", item.second, []() { return obj_list()->is_instance_or_object_selected(); }, + m_parent); } append_menu_item_layers_editing(menu); @@ -675,9 +722,13 @@ void MenuFactory::append_menu_items_add_volume(wxMenu* menu) wxMenuItem* MenuFactory::append_menu_item_layers_editing(wxMenu* menu) { - return append_menu_item(menu, wxID_ANY, _L("Height range Modifier"), "", - [](wxCommandEvent&) { obj_list()->layers_editing(); wxGetApp().params_panel()->switch_to_object(); }, "height_range_modifier", menu, - []() { return obj_list()->is_instance_or_object_selected(); }, m_parent); + return append_menu_item( + menu, wxID_ANY, _L("Height range Modifier"), "", + [](wxCommandEvent&) { + obj_list()->layers_editing(); + wxGetApp().params_panel()->switch_to_object(); + }, + "height_range_modifier", menu, []() { return obj_list()->is_instance_or_object_selected(); }, m_parent); } wxMenuItem* MenuFactory::append_menu_item_settings(wxMenu* menu_) @@ -690,14 +741,12 @@ wxMenuItem* MenuFactory::append_menu_item_settings(wxMenu* menu_) if (settings_id != wxNOT_FOUND) menu->Destroy(settings_id); - for (auto& it : FREQ_SETTINGS_BUNDLE_FFF) - { + for (auto& it : FREQ_SETTINGS_BUNDLE_FFF) { settings_id = menu->FindItem(_(it.first)); if (settings_id != wxNOT_FOUND) menu->Destroy(settings_id); } - for (auto& it : FREQ_SETTINGS_BUNDLE_SLA) - { + for (auto& it : FREQ_SETTINGS_BUNDLE_SLA) { settings_id = menu->FindItem(_(it.first)); if (settings_id != wxNOT_FOUND) menu->Destroy(settings_id); @@ -708,8 +757,8 @@ wxMenuItem* MenuFactory::append_menu_item_settings(wxMenu* menu_) // If there are selected more then one instance but not all of them // don't add settings menu items const Selection& selection = get_selection(); - if ((selection.is_multiple_full_instance() && !selection.is_single_full_object()) || - selection.is_multiple_volume() || selection.is_mixed()) // more than one volume(part) is selected on the scene + if ((selection.is_multiple_full_instance() && !selection.is_single_full_object()) || selection.is_multiple_volume() || + selection.is_mixed()) // more than one volume(part) is selected on the scene return nullptr; const auto sel_vol = obj_list()->get_selected_model_volume(); @@ -717,31 +766,30 @@ wxMenuItem* MenuFactory::append_menu_item_settings(wxMenu* menu_) return nullptr; // detect itemm for adding of the setting - ObjectList* object_list = obj_list(); - ObjectDataViewModel* obj_model = list_model(); + ObjectList* object_list = obj_list(); + ObjectDataViewModel* obj_model = list_model(); const wxDataViewItem sel_item = // when all instances in object are selected - object_list->GetSelectedItemsCount() > 1 && selection.is_single_full_object() ? - obj_model->GetItemById(selection.get_object_idx()) : - object_list->GetSelection(); + object_list->GetSelectedItemsCount() > 1 && selection.is_single_full_object() ? obj_model->GetItemById(selection.get_object_idx()) : + object_list->GetSelection(); if (!sel_item) return nullptr; // If we try to add settings for object/part from 3Dscene, // for the second try there is selected ItemSettings in ObjectList. // So, check if selected item isn't SettingsItem. And get a SettingsItem's parent item, if yes - wxDataViewItem item = obj_model->GetItemType(sel_item) & itSettings ? obj_model->GetParent(sel_item) : sel_item; - const ItemType item_type = obj_model->GetItemType(item); - const bool is_object_settings = !(item_type& itVolume || item_type & itLayer); + wxDataViewItem item = obj_model->GetItemType(sel_item) & itSettings ? obj_model->GetParent(sel_item) : sel_item; + const ItemType item_type = obj_model->GetItemType(item); + const bool is_object_settings = !(item_type & itVolume || item_type & itLayer); // Add frequently settings // BBS remvoe freq setting popupmenu // create_freq_settings_popupmenu(menu, is_object_settings, item); - //menu->SetSecondSeparator(); + // menu->SetSecondSeparator(); // Add full settings list - auto menu_item = new wxMenuItem(menu, wxID_ANY, menu_name); + auto menu_item = new wxMenuItem(menu, wxID_ANY, menu_name); menu_item->SetBitmap(create_scaled_bitmap("cog")); menu_item->SetSubMenu(create_settings_popupmenu(menu, is_object_settings, item)); @@ -750,82 +798,87 @@ wxMenuItem* MenuFactory::append_menu_item_settings(wxMenu* menu_) wxMenuItem* MenuFactory::append_menu_item_change_type(wxMenu* menu) { - return append_menu_item(menu, wxID_ANY, _L("Change type"), "", - [](wxCommandEvent&) { obj_list()->change_part_type(); }, "", menu, + return append_menu_item( + menu, wxID_ANY, _L("Change type"), "", [](wxCommandEvent&) { obj_list()->change_part_type(); }, "", menu, []() { - wxDataViewItemArray selections; - obj_list()->GetSelections(selections); - if (selections.empty()) return false; - for (const auto& it : selections) { - if (!(obj_list()->GetModel()->GetItemType(it) & itVolume)) - return false; // non-volume present -> disable - } - return true; - }, m_parent); + wxDataViewItemArray selections; + obj_list()->GetSelections(selections); + if (selections.empty()) + return false; + for (const auto& it : selections) { + if (!(obj_list()->GetModel()->GetItemType(it) & itVolume)) + return false; // non-volume present -> disable + } + return true; + }, + m_parent); } wxMenuItem* MenuFactory::append_menu_item_instance_to_object(wxMenu* menu) { - wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Set as an individual object"), "", - [](wxCommandEvent&) { obj_list()->split_instances(); }, "", menu); + wxMenuItem* menu_item = append_menu_item( + menu, wxID_ANY, _L("Set as an individual object"), "", [](wxCommandEvent&) { obj_list()->split_instances(); }, "", menu); /* New behavior logic: * 1. Split Object to several separated object, if ALL instances are selected * 2. Separate selected instances from the initial object to the separated object, * if some (not all) instances are selected */ - m_parent->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt) - { + m_parent->Bind( + wxEVT_UPDATE_UI, + [](wxUpdateUIEvent& evt) { const Selection& selection = plater()->canvas3D()->get_selection(); - evt.SetText(selection.is_single_full_object() ? - _L("Set as individual objects") : _L("Set as an individual object")); + evt.SetText(selection.is_single_full_object() ? _L("Set as individual objects") : _L("Set as an individual object")); evt.Enable(plater()->can_set_instance_to_object()); - }, menu_item->GetId()); + }, + menu_item->GetId()); return menu_item; } -void MenuFactory::append_menu_item_fill_bed(wxMenu *menu) +void MenuFactory::append_menu_item_fill_bed(wxMenu* menu) { append_menu_item( menu, wxID_ANY, _L("Fill bed with copies"), _L("Fill the remaining area of bed with copies of the selected object"), - [](wxCommandEvent &) { plater()->fill_bed_with_copies(); }, "", nullptr, []() { return plater()->can_increase_instances(); }, m_parent); + [](wxCommandEvent&) { plater()->fill_bed_with_copies(); }, "", nullptr, []() { return plater()->can_increase_instances(); }, + m_parent); } wxMenuItem* MenuFactory::append_menu_item_printable(wxMenu* menu) { // BBS: to be checked - wxMenuItem* menu_item_printable = append_menu_check_item(menu, wxID_ANY, _L("Printable"), "", - [](wxCommandEvent&) { obj_list()->toggle_printable_state(); }, menu); + wxMenuItem* menu_item_printable = + append_menu_check_item(menu, wxID_ANY, _L("Printable"), "", [](wxCommandEvent&) { obj_list()->toggle_printable_state(); }, menu); - m_parent->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt) { - ObjectList* list = obj_list(); - wxDataViewItemArray sels; - list->GetSelections(sels); - wxDataViewItem frst_item = sels[0]; - ItemType type = list->GetModel()->GetItemType(frst_item); - bool check; - if (type != itInstance && type != itObject) - check = false; - else { - int obj_idx = list->GetModel()->GetObjectIdByItem(frst_item); - int inst_idx = type == itObject ? 0 : list->GetModel()->GetInstanceIdByItem(frst_item); - check = list->object(obj_idx)->instances[inst_idx]->printable; - } + m_parent->Bind( + wxEVT_UPDATE_UI, + [](wxUpdateUIEvent& evt) { + ObjectList* list = obj_list(); + wxDataViewItemArray sels; + list->GetSelections(sels); + wxDataViewItem frst_item = sels[0]; + ItemType type = list->GetModel()->GetItemType(frst_item); + bool check; + if (type != itInstance && type != itObject) + check = false; + else { + int obj_idx = list->GetModel()->GetObjectIdByItem(frst_item); + int inst_idx = type == itObject ? 0 : list->GetModel()->GetInstanceIdByItem(frst_item); + check = list->object(obj_idx)->instances[inst_idx]->printable; + } - evt.Check(check); - plater()->set_current_canvas_as_dirty(); - - }, menu_item_printable->GetId()); + evt.Check(check); + plater()->set_current_canvas_as_dirty(); + }, + menu_item_printable->GetId()); return menu_item_printable; } void MenuFactory::append_menu_item_rename(wxMenu* menu) { - append_menu_item(menu, wxID_ANY, _L("Rename"), "", - [](wxCommandEvent&) { obj_list()->rename_item(); }, "", menu); + append_menu_item(menu, wxID_ANY, _L("Rename"), "", [](wxCommandEvent&) { obj_list()->rename_item(); }, "", menu); menu->AppendSeparator(); } @@ -835,59 +888,62 @@ wxMenuItem* MenuFactory::append_menu_item_fix_through_netfabb(wxMenu* menu) if (!is_windows10()) return nullptr; - wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Fix model"), "", - [](wxCommandEvent&) { obj_list()->fix_through_netfabb(); }, "", menu, - []() {return plater()->can_fix_through_netfabb(); }, plater()); + wxMenuItem* menu_item = append_menu_item( + menu, wxID_ANY, _L("Fix model"), "", [](wxCommandEvent&) { obj_list()->fix_through_netfabb(); }, "", menu, + []() { return plater()->can_fix_through_netfabb(); }, plater()); return menu_item; } void MenuFactory::append_menu_item_export_stl(wxMenu* menu, bool is_mulity_menu) { - append_menu_item(menu, wxID_ANY, _L("Export as one STL") + dots, "", - [](wxCommandEvent&) { plater()->export_stl(false, true); }, "", nullptr, + append_menu_item( + menu, wxID_ANY, _L("Export as one STL") + dots, "", [](wxCommandEvent&) { plater()->export_stl(false, true); }, "", nullptr, [is_mulity_menu]() { const Selection& selection = plater()->canvas3D()->get_selection(); if (is_mulity_menu) return selection.is_multiple_full_instance() || selection.is_multiple_full_object(); else return selection.is_single_full_instance() || selection.is_single_full_object(); - }, m_parent); + }, + m_parent); if (!is_mulity_menu) return; - append_menu_item(menu, wxID_ANY, _L("Export as STLs") + dots, "", - [](wxCommandEvent&) { plater()->export_stl(false, true, true); }, "", nullptr, + append_menu_item( + menu, wxID_ANY, _L("Export as STLs") + dots, "", [](wxCommandEvent&) { plater()->export_stl(false, true, true); }, "", nullptr, []() { const Selection& selection = plater()->canvas3D()->get_selection(); return selection.is_multiple_full_instance() || selection.is_multiple_full_object(); - }, m_parent); + }, + m_parent); } void MenuFactory::append_menu_item_reload_from_disk(wxMenu* menu) { - append_menu_item(menu, wxID_ANY, _L("Reload from disk"), _L("Reload the selected parts from disk"), - [](wxCommandEvent&) { plater()->reload_from_disk(); }, "", menu, - []() { return plater()->can_reload_from_disk(); }, m_parent); + append_menu_item( + menu, wxID_ANY, _L("Reload from disk"), _L("Reload the selected parts from disk"), + [](wxCommandEvent&) { plater()->reload_from_disk(); }, "", menu, []() { return plater()->can_reload_from_disk(); }, m_parent); } -void MenuFactory::append_menu_item_replace_with_stl(wxMenu *menu) +void MenuFactory::append_menu_item_replace_with_stl(wxMenu* menu) { - append_menu_item(menu, wxID_ANY, _L("Replace 3D file") + dots, _L("Replace the selected part with a new 3D file"), - [](wxCommandEvent &) { plater()->replace_with_stl(); }, "", menu, - []() { return plater()->can_replace_with_stl(); }, m_parent); + append_menu_item( + menu, wxID_ANY, _L("Replace 3D file") + dots, _L("Replace the selected part with a new 3D file"), + [](wxCommandEvent&) { plater()->replace_with_stl(); }, "", menu, []() { return plater()->can_replace_with_stl(); }, m_parent); } -void MenuFactory::append_menu_item_replace_all_with_stl(wxMenu *menu) +void MenuFactory::append_menu_item_replace_all_with_stl(wxMenu* menu) { - append_menu_item(menu, wxID_ANY, _L("Replace all with 3D files") + dots, _L("Replace all selected parts with 3D files from folder"), - [](wxCommandEvent &) { plater()->replace_all_with_stl(); }, "", menu, - []() { return plater()->can_replace_all_with_stl(); }, m_parent); + append_menu_item( + menu, wxID_ANY, _L("Replace all with 3D files") + dots, _L("Replace all selected parts with 3D files from folder"), + [](wxCommandEvent&) { plater()->replace_all_with_stl(); }, "", menu, []() { return plater()->can_replace_all_with_stl(); }, + m_parent); } void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) { // BBS - const std::vector names = { _L("Change filament"), _L("Set filament for selected items") }; + const std::vector names = {_L("Change filament"), _L("Set filament for selected items")}; // Delete old menu item for (const wxString& name : names) { const int item_id = menu->FindItem(name); @@ -904,9 +960,9 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) if (sels.IsEmpty()) return; - std::vector icons = get_extruder_color_icons(true); - wxMenu* extruder_selection_menu = new wxMenu(); - const wxString& name = sels.Count() == 1 ? names[0] : names[1]; + std::vector icons = get_extruder_color_icons(true); + wxMenu* extruder_selection_menu = new wxMenu(); + const wxString& name = sels.Count() == 1 ? names[0] : names[1]; int initial_extruder = -1; // negative value for multiple object/part selection if (sels.Count() == 1) { @@ -915,17 +971,16 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) initial_extruder = config.has("extruder") ? config.extruder() : 1; } - for (int i = 0; i <= filaments_cnt; i++) - { + for (int i = 0; i <= filaments_cnt; i++) { bool is_active_extruder = i == initial_extruder; - int icon_idx = i == 0 ? 0 : i - 1; + int icon_idx = i == 0 ? 0 : i - 1; wxString item_name = _L("Default"); if (i > 0) { auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i - 1]); if (preset == nullptr) { - item_name = wxString::Format(_L("Filament %d"), i); + item_name = wxString::Format(_L("Filament %d"), filament_index_from_one_based(i)); } else { item_name = from_u8(preset->label(false)); } @@ -937,12 +992,12 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) if (icon_idx >= 0 && icon_idx < icons.size()) { append_menu_item( - extruder_selection_menu, wxID_ANY, item_name, "", [i](wxCommandEvent &) { obj_list()->set_extruder_for_selected_items(i); }, *icons[icon_idx], menu, - [is_active_extruder]() { return !is_active_extruder; }, m_parent); + extruder_selection_menu, wxID_ANY, item_name, "", [i](wxCommandEvent&) { obj_list()->set_extruder_for_selected_items(i); }, + *icons[icon_idx], menu, [is_active_extruder]() { return !is_active_extruder; }, m_parent); } else { append_menu_item( - extruder_selection_menu, wxID_ANY, item_name, "", [i](wxCommandEvent &) { obj_list()->set_extruder_for_selected_items(i); }, "", menu, - [is_active_extruder]() { return !is_active_extruder; }, m_parent); + extruder_selection_menu, wxID_ANY, item_name, "", [i](wxCommandEvent&) { obj_list()->set_extruder_for_selected_items(i); }, + "", menu, [is_active_extruder]() { return !is_active_extruder; }, m_parent); } } @@ -951,7 +1006,8 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) void MenuFactory::append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu) { - append_menu_item(menu, wxID_ANY, _L("Scale to build volume"), _L("Scale an object to fit the build volume"), + append_menu_item( + menu, wxID_ANY, _L("Scale to build volume"), _L("Scale an object to fit the build volume"), [](wxCommandEvent&) { plater()->scale_selection_to_fit_print_volume(); }, "", menu); } @@ -963,9 +1019,9 @@ void MenuFactory::append_menu_items_flush_options(wxMenu* menu) if (item_id != wxNOT_FOUND) menu->Destroy(item_id); - bool show_flush_option_menu = false; - ObjectList* object_list = obj_list(); - const Selection& selection = get_selection(); + bool show_flush_option_menu = false; + ObjectList* object_list = obj_list(); + const Selection& selection = get_selection(); if (selection.get_object_idx() < 0) return; if (wxGetApp().plater()->get_partplate_list().get_curr_plate()->contains(selection.get_bounding_box())) { @@ -978,15 +1034,16 @@ void MenuFactory::append_menu_items_flush_options(wxMenu* menu) if (!show_flush_option_menu) return; - DynamicPrintConfig& global_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; - ModelConfig& select_object_config = object_list->object(selection.get_object_idx())->config; + DynamicPrintConfig& global_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; + ModelConfig& select_object_config = object_list->object(selection.get_object_idx())->config; wxMenu* flush_options_menu = new wxMenu(); - auto can_flush = [&global_config]() { + auto can_flush = [&global_config]() { auto option = global_config.option("enable_prime_tower"); return option ? option->getBool() : false; }; - append_menu_check_item(flush_options_menu, wxID_ANY, _L("Flush into objects' infill"), "", + append_menu_check_item( + flush_options_menu, wxID_ANY, _L("Flush into objects' infill"), "", [&select_object_config, &global_config](wxCommandEvent&) { const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][0]); if (!option) { @@ -994,16 +1051,19 @@ void MenuFactory::append_menu_items_flush_options(wxMenu* menu) } select_object_config.set_key_value(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][0], new ConfigOptionBool(!option->getBool())); wxGetApp().obj_settings()->UpdateAndShow(true); - }, menu, can_flush, + }, + menu, can_flush, [&select_object_config, &global_config]() { const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][0]); if (!option) { option = global_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][0]); } return option->getBool(); - }, m_parent); + }, + m_parent); - append_menu_check_item(flush_options_menu, wxID_ANY, _L("Flush into this object"), "", + append_menu_check_item( + flush_options_menu, wxID_ANY, _L("Flush into this object"), "", [&select_object_config, &global_config](wxCommandEvent&) { const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][1]); if (!option) { @@ -1011,16 +1071,19 @@ void MenuFactory::append_menu_items_flush_options(wxMenu* menu) } select_object_config.set_key_value(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][1], new ConfigOptionBool(!option->getBool())); wxGetApp().obj_settings()->UpdateAndShow(true); - }, menu, can_flush, + }, + menu, can_flush, [&select_object_config, &global_config]() { const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][1]); if (!option) { option = global_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][1]); } return option->getBool(); - }, m_parent); + }, + m_parent); - append_menu_check_item(flush_options_menu, wxID_ANY, _L("Flush into objects' support"), "", + append_menu_check_item( + flush_options_menu, wxID_ANY, _L("Flush into objects' support"), "", [&select_object_config, &global_config](wxCommandEvent&) { const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][2]); if (!option) { @@ -1028,18 +1091,19 @@ void MenuFactory::append_menu_items_flush_options(wxMenu* menu) } select_object_config.set_key_value(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][2], new ConfigOptionBool(!option->getBool())); wxGetApp().obj_settings()->UpdateAndShow(true); - }, menu, can_flush, + }, + menu, can_flush, [&select_object_config, &global_config]() { const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][2]); if (!option) { option = global_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][2]); } return option->getBool(); - }, m_parent); + }, + m_parent); size_t i = 0; - for (auto node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext()) - { + for (auto node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext()) { i++; wxMenuItem* item = node->GetData(); if (item->GetItemLabelText() == _L("Edit in Parameter Table")) @@ -1055,16 +1119,14 @@ void MenuFactory::append_menu_items_convert_unit(wxMenu* menu) if (obj_idxs.empty() && vol_idxs.empty()) return; - auto volume_respects_conversion = [](ModelVolume* volume, ConversionType conver_type) - { - return (conver_type == ConversionType::CONV_FROM_INCH && volume->source.is_converted_from_inches) || - (conver_type == ConversionType::CONV_TO_INCH && !volume->source.is_converted_from_inches) || - (conver_type == ConversionType::CONV_FROM_METER && volume->source.is_converted_from_meters) || - (conver_type == ConversionType::CONV_TO_METER && !volume->source.is_converted_from_meters); + auto volume_respects_conversion = [](ModelVolume* volume, ConversionType conver_type) { + return (conver_type == ConversionType::CONV_FROM_INCH && volume->source.is_converted_from_inches) || + (conver_type == ConversionType::CONV_TO_INCH && !volume->source.is_converted_from_inches) || + (conver_type == ConversionType::CONV_FROM_METER && volume->source.is_converted_from_meters) || + (conver_type == ConversionType::CONV_TO_METER && !volume->source.is_converted_from_meters); }; - auto can_append = [obj_idxs, vol_idxs, volume_respects_conversion](ConversionType conver_type) - { + auto can_append = [obj_idxs, vol_idxs, volume_respects_conversion](ConversionType conver_type) { ModelObjectPtrs objects; for (int obj_idx : obj_idxs) { ModelObject* object = obj_list()->object(obj_idx); @@ -1072,8 +1134,7 @@ void MenuFactory::append_menu_items_convert_unit(wxMenu* menu) for (ModelVolume* volume : object->volumes) if (volume_respects_conversion(volume, conver_type)) return false; - } - else { + } else { for (int vol_idx : vol_idxs) if (volume_respects_conversion(object->volumes[vol_idx], conver_type)) return false; @@ -1082,22 +1143,20 @@ void MenuFactory::append_menu_items_convert_unit(wxMenu* menu) return true; }; - std::vector> items = { - {ConversionType::CONV_FROM_INCH , _L("Convert from inches") }, - {ConversionType::CONV_TO_INCH , _L("Restore to inches") }, - {ConversionType::CONV_FROM_METER, _L("Convert from meters") }, - {ConversionType::CONV_TO_METER , _L("Restore to meters") } }; + std::vector> items = {{ConversionType::CONV_FROM_INCH, _L("Convert from inches")}, + {ConversionType::CONV_TO_INCH, _L("Restore to inches")}, + {ConversionType::CONV_FROM_METER, _L("Convert from meters")}, + {ConversionType::CONV_TO_METER, _L("Restore to meters")}}; for (auto item : items) { int menu_id = menu->FindItem(item.second); if (can_append(item.first)) { // Add menu item if it doesn't exist if (menu_id == wxNOT_FOUND) - append_menu_item(menu, wxID_ANY, item.second, item.second, - [item](wxCommandEvent&) { plater()->convert_unit(item.first); }, "", menu, + append_menu_item( + menu, wxID_ANY, item.second, item.second, [item](wxCommandEvent&) { plater()->convert_unit(item.first); }, "", menu, []() { return true; }, m_parent); - } - else if (menu_id != wxNOT_FOUND) { + } else if (menu_id != wxNOT_FOUND) { // Delete menu item menu->Destroy(menu_id); } @@ -1106,25 +1165,26 @@ void MenuFactory::append_menu_items_convert_unit(wxMenu* menu) void MenuFactory::append_menu_item_merge_to_multipart_object(wxMenu* menu) { - append_menu_item(menu, wxID_ANY, _L("Assemble"), _L("Assemble the selected objects to an object with multiple parts"), - [](wxCommandEvent&) { obj_list()->merge(true); }, "", menu, - []() { return obj_list()->can_merge_to_multipart_object(); }, m_parent); + append_menu_item( + menu, wxID_ANY, _L("Assemble"), _L("Assemble the selected objects to an object with multiple parts"), + [](wxCommandEvent&) { obj_list()->merge(true); }, "", menu, []() { return obj_list()->can_merge_to_multipart_object(); }, m_parent); } void MenuFactory::append_menu_item_merge_to_single_object(wxMenu* menu) { menu->AppendSeparator(); - append_menu_item(menu, wxID_ANY, _L("Assemble"), _L("Assemble the selected objects to an object with single part"), - [](wxCommandEvent&) { obj_list()->merge(false); }, "", menu, - []() { return obj_list()->can_merge_to_single_object(); }, m_parent); + append_menu_item( + menu, wxID_ANY, _L("Assemble"), _L("Assemble the selected objects to an object with single part"), + [](wxCommandEvent&) { obj_list()->merge(false); }, "", menu, []() { return obj_list()->can_merge_to_single_object(); }, m_parent); } void MenuFactory::append_menu_item_merge_parts_to_single_part(wxMenu* menu) { menu->AppendSeparator(); - append_menu_item(menu, wxID_ANY, _L("Mesh boolean"), _L("Mesh boolean operations including union and subtraction"), - [](wxCommandEvent&) { obj_list()->boolean/*merge_volumes*/(); }, "", menu, - []() { return obj_list()->can_mesh_boolean(); }, m_parent); + append_menu_item( + menu, wxID_ANY, _L("Mesh boolean"), _L("Mesh boolean operations including union and subtraction"), + [](wxCommandEvent&) { obj_list()->boolean /*merge_volumes*/ (); }, "", menu, []() { return obj_list()->can_mesh_boolean(); }, + m_parent); } void MenuFactory::append_menu_items_mirror(wxMenu* menu) @@ -1133,20 +1193,22 @@ void MenuFactory::append_menu_items_mirror(wxMenu* menu) if (!mirror_menu) return; - append_menu_item(mirror_menu, wxID_ANY, _L("Along X axis"), _L("Mirror along the X axis"), - [](wxCommandEvent&) { plater()->mirror(X); }, "menu_mirror_x", menu); - append_menu_item(mirror_menu, wxID_ANY, _L("Along Y axis"), _L("Mirror along the Y axis"), - [](wxCommandEvent&) { plater()->mirror(Y); }, "menu_mirror_y", menu); - append_menu_item(mirror_menu, wxID_ANY, _L("Along Z axis"), _L("Mirror along the Z axis"), - [](wxCommandEvent&) { plater()->mirror(Z); }, "menu_mirror_z", menu); + append_menu_item( + mirror_menu, wxID_ANY, _L("Along X axis"), _L("Mirror along the X axis"), [](wxCommandEvent&) { plater()->mirror(X); }, + "menu_mirror_x", menu); + append_menu_item( + mirror_menu, wxID_ANY, _L("Along Y axis"), _L("Mirror along the Y axis"), [](wxCommandEvent&) { plater()->mirror(Y); }, + "menu_mirror_y", menu); + append_menu_item( + mirror_menu, wxID_ANY, _L("Along Z axis"), _L("Mirror along the Z axis"), [](wxCommandEvent&) { plater()->mirror(Z); }, + "menu_mirror_z", menu); - append_submenu(menu, mirror_menu, wxID_ANY, _L("Mirror"), _L("Mirror object"), "", - []() { return plater()->can_mirror(); }, m_parent); + append_submenu(menu, mirror_menu, wxID_ANY, _L("Mirror"), _L("Mirror object"), "", []() { return plater()->can_mirror(); }, m_parent); } -void MenuFactory::append_menu_item_edit_text(wxMenu *menu) +void MenuFactory::append_menu_item_edit_text(wxMenu* menu) { - wxString name = _L("Edit text"); + wxString name = _L("Edit text"); auto can_edit_text = []() { if (plater() == nullptr) @@ -1157,7 +1219,7 @@ void MenuFactory::append_menu_item_edit_text(wxMenu *menu) const GLVolume* gl_volume = selection.get_first_volume(); if (gl_volume == nullptr) return false; - const ModelVolume *volume = get_model_volume(*gl_volume, selection.get_model()->objects); + const ModelVolume* volume = get_model_volume(*gl_volume, selection.get_model()->objects); if (volume == nullptr) return false; return volume->is_text(); @@ -1171,10 +1233,10 @@ void MenuFactory::append_menu_item_edit_text(wxMenu *menu) return; } - wxString description = _L("Ability to change text, font, size, ..."); - std::string icon = "cog"; - auto open_emboss = [](const wxCommandEvent &) { - GLGizmosManager &mng = plater()->get_view3D_canvas3D()->get_gizmos_manager(); + wxString description = _L("Ability to change text, font, size, ..."); + std::string icon = "cog"; + auto open_emboss = [](const wxCommandEvent&) { + GLGizmosManager& mng = plater()->get_view3D_canvas3D()->get_gizmos_manager(); if (mng.get_current_type() == GLGizmosManager::Emboss) mng.open_gizmo(GLGizmosManager::Emboss); // close() and reopen - move to be visible mng.open_gizmo(GLGizmosManager::Emboss); @@ -1182,10 +1244,10 @@ void MenuFactory::append_menu_item_edit_text(wxMenu *menu) append_menu_item(menu, wxID_ANY, name, description, open_emboss, icon, nullptr, can_edit_text, m_parent); } -void MenuFactory::append_menu_item_edit_svg(wxMenu *menu) +void MenuFactory::append_menu_item_edit_svg(wxMenu* menu) { - wxString name = _L("Edit SVG"); - auto can_edit_svg = []() { + wxString name = _L("Edit SVG"); + auto can_edit_svg = []() { if (plater() == nullptr) return false; const Selection& selection = plater()->get_selection(); @@ -1194,7 +1256,7 @@ void MenuFactory::append_menu_item_edit_svg(wxMenu *menu) const GLVolume* gl_volume = selection.get_first_volume(); if (gl_volume == nullptr) return false; - const ModelVolume *volume = get_model_volume(*gl_volume, selection.get_model()->objects); + const ModelVolume* volume = get_model_volume(*gl_volume, selection.get_model()->objects); if (volume == nullptr) return false; return volume->is_svg(); @@ -1208,10 +1270,10 @@ void MenuFactory::append_menu_item_edit_svg(wxMenu *menu) return; } - wxString description = _L("Change SVG source file, projection, size, ..."); - std::string icon = "cog"; - auto open_svg = [](const wxCommandEvent &) { - GLGizmosManager &mng = plater()->get_view3D_canvas3D()->get_gizmos_manager(); + wxString description = _L("Change SVG source file, projection, size, ..."); + std::string icon = "cog"; + auto open_svg = [](const wxCommandEvent&) { + GLGizmosManager& mng = plater()->get_view3D_canvas3D()->get_gizmos_manager(); if (mng.get_current_type() == GLGizmosManager::Svg) mng.open_gizmo(GLGizmosManager::Svg); // close() and reopen - move to be visible mng.open_gizmo(GLGizmosManager::Svg); @@ -1219,7 +1281,7 @@ void MenuFactory::append_menu_item_edit_svg(wxMenu *menu) append_menu_item(menu, wxID_ANY, name, description, open_svg, icon, nullptr, can_edit_svg, m_parent); } -void MenuFactory::append_menu_item_invalidate_cut_info(wxMenu *menu) +void MenuFactory::append_menu_item_invalidate_cut_info(wxMenu* menu) { const wxString menu_name = _L("Invalidate cut info"); @@ -1229,15 +1291,16 @@ void MenuFactory::append_menu_item_invalidate_cut_info(wxMenu *menu) menu->Destroy(menu_item_id); if (obj_list()->has_selected_cut_object()) - append_menu_item(menu, wxID_ANY, menu_name, "", [](wxCommandEvent &) { obj_list()->invalidate_cut_info_for_selection(); }, - "", menu, []() { return true; }, m_parent); + append_menu_item( + menu, wxID_ANY, menu_name, "", [](wxCommandEvent&) { obj_list()->invalidate_cut_info_for_selection(); }, "", menu, + []() { return true; }, m_parent); } MenuFactory::MenuFactory() { for (int i = 0; i < mtCount; i++) { - items_increase[i] = nullptr; - items_decrease[i] = nullptr; + items_increase[i] = nullptr; + items_decrease[i] = nullptr; items_set_number_of_copies[i] = nullptr; } } @@ -1245,37 +1308,39 @@ MenuFactory::MenuFactory() void MenuFactory::create_default_menu() { wxMenu* sub_menu_primitives = append_submenu_add_generic(&m_default_menu, ModelVolumeType::INVALID); - wxMenu* sub_menu_handy = append_submenu_add_handy_model(&m_default_menu, ModelVolumeType::INVALID); + wxMenu* sub_menu_handy = append_submenu_add_handy_model(&m_default_menu, ModelVolumeType::INVALID); #ifdef __WINDOWS__ - append_submenu(&m_default_menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "menu_add_part", - []() {return true; }, m_parent); - append_submenu(&m_default_menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "menu_add_part", - []() {return true; }, m_parent); - append_menu_item(&m_default_menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models + append_submenu(&m_default_menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "menu_add_part", []() { return true; }, m_parent); + append_submenu(&m_default_menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "menu_add_part", []() { return true; }, m_parent); + append_menu_item( + &m_default_menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models [](wxCommandEvent&) { plater()->add_file(); }, "menu_add_part", &m_default_menu, - []() {return wxGetApp().plater()->can_add_model(); }, m_parent); + []() { return wxGetApp().plater()->can_add_model(); }, m_parent); #else - append_submenu(&m_default_menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "", - []() {return true; }, m_parent); - append_submenu(&m_default_menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "", - []() {return true; }, m_parent); - append_menu_item(&m_default_menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models - [](wxCommandEvent&) { plater()->add_file(); }, "", &m_default_menu, - []() {return wxGetApp().plater()->can_add_model(); }, m_parent); + append_submenu(&m_default_menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "", []() { return true; }, m_parent); + append_submenu(&m_default_menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "", []() { return true; }, m_parent); + append_menu_item( + &m_default_menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models + [](wxCommandEvent&) { plater()->add_file(); }, "", &m_default_menu, []() { return wxGetApp().plater()->can_add_model(); }, + m_parent); #endif m_default_menu.AppendSeparator(); - append_menu_check_item(&m_default_menu, wxID_ANY, _L("Show Labels"), "", - [](wxCommandEvent&) { plater()->show_view3D_labels(!plater()->are_view3D_labels_shown()); plater()->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); }, &m_default_menu, - []() { return plater()->is_view3D_shown(); }, [this]() { return plater()->are_view3D_labels_shown(); }, m_parent); + append_menu_check_item( + &m_default_menu, wxID_ANY, _L("Show Labels"), "", + [](wxCommandEvent&) { + plater()->show_view3D_labels(!plater()->are_view3D_labels_shown()); + plater()->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); + }, + &m_default_menu, []() { return plater()->is_view3D_shown(); }, [this]() { return plater()->are_view3D_labels_shown(); }, m_parent); } void MenuFactory::create_common_object_menu(wxMenu* menu) { append_menu_item_rename(menu); append_menu_items_instance_manipulation(menu); - + // Delete menu was moved to be after +/- instace to make it more difficult to be selected by mistake. append_menu_item_delete(menu); menu->AppendSeparator(); @@ -1296,14 +1361,17 @@ void MenuFactory::create_object_menu() if (!split_menu) return; - append_menu_item(split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), - [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", &m_object_menu, - []() { return plater()->can_split(true); }, m_parent); - append_menu_item(split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), - [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", &m_object_menu, - []() { return plater()->can_split(false); }, m_parent); + append_menu_item( + split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), + [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", &m_object_menu, []() { return plater()->can_split(true); }, + m_parent); + append_menu_item( + split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), + [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", &m_object_menu, []() { return plater()->can_split(false); }, + m_parent); - append_submenu(&m_object_menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", + append_submenu( + &m_object_menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", []() { return plater()->can_split(true) || plater()->can_split(false); }, m_parent); m_object_menu.AppendSeparator(); @@ -1320,8 +1388,8 @@ void MenuFactory::create_extra_object_menu() m_object_menu.AppendSeparator(); append_menu_item_instance_to_object(&m_object_menu); m_object_menu.AppendSeparator(); - //append_menu_item_fill_bed(&m_object_menu); - // Object Clone + // append_menu_item_fill_bed(&m_object_menu); + // Object Clone append_menu_item_clone(&m_object_menu); // Object Repair append_menu_item_fix_through_netfabb(&m_object_menu); @@ -1337,15 +1405,18 @@ void MenuFactory::create_extra_object_menu() wxMenu* split_menu = new wxMenu(); if (!split_menu) return; - append_menu_item(split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), - [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", &m_object_menu, - []() { return plater()->can_split(true); }, m_parent); - append_menu_item(split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), - [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", &m_object_menu, - []() { return plater()->can_split(false); }, m_parent); + append_menu_item( + split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), + [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", &m_object_menu, []() { return plater()->can_split(true); }, + m_parent); + append_menu_item( + split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), + [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", &m_object_menu, []() { return plater()->can_split(false); }, + m_parent); - append_submenu(&m_object_menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", - []() { return plater()->can_split(true); }, m_parent); + append_submenu( + &m_object_menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", []() { return plater()->can_split(true); }, + m_parent); // Mirror append_menu_items_mirror(&m_object_menu); @@ -1383,15 +1454,15 @@ void MenuFactory::create_bbl_assemble_object_menu() void MenuFactory::create_sla_object_menu() { create_common_object_menu(&m_sla_object_menu); - append_menu_item(&m_sla_object_menu, wxID_ANY, _L("Split"), _L("Split the selected object into multiple objects"), - [](wxCommandEvent&) { plater()->split_object(); }, "", nullptr, - []() { return plater()->can_split(true); }, m_parent); + append_menu_item( + &m_sla_object_menu, wxID_ANY, _L("Split"), _L("Split the selected object into multiple objects"), + [](wxCommandEvent&) { plater()->split_object(); }, "", nullptr, []() { return plater()->can_split(true); }, m_parent); m_sla_object_menu.AppendSeparator(); // Add the automatic rotation sub-menu append_menu_item(&m_sla_object_menu, wxID_ANY, _L("Auto orientation"), _L("Auto orient the object to improve print quality"), - [](wxCommandEvent&) { plater()->optimize_rotation(); }); + [](wxCommandEvent&) { plater()->optimize_rotation(); }); } void MenuFactory::create_part_menu() @@ -1405,16 +1476,16 @@ void MenuFactory::create_part_menu() append_menu_items_mirror(menu); append_menu_item_merge_parts_to_single_part(menu); - append_menu_item(menu, wxID_ANY, _L("Split"), _L("Split the selected object into multiple parts"), - [](wxCommandEvent&) { plater()->split_volume(); }, "split_parts", nullptr, - []() { return plater()->can_split(false); }, m_parent); + append_menu_item( + menu, wxID_ANY, _L("Split"), _L("Split the selected object into multiple parts"), [](wxCommandEvent&) { plater()->split_volume(); }, + "split_parts", nullptr, []() { return plater()->can_split(false); }, m_parent); menu->AppendSeparator(); append_menu_item_change_type(menu); append_menu_items_mirror(&m_part_menu); - append_menu_item(&m_part_menu, wxID_ANY, _L("Split"), _L("Split the selected object into multiple parts"), - [](wxCommandEvent&) { plater()->split_volume(); }, "split_parts", nullptr, - []() { return plater()->can_split(false); }, m_parent); + append_menu_item( + &m_part_menu, wxID_ANY, _L("Split"), _L("Split the selected object into multiple parts"), + [](wxCommandEvent&) { plater()->split_volume(); }, "split_parts", nullptr, []() { return plater()->can_split(false); }, m_parent); m_part_menu.AppendSeparator(); append_menu_item_per_object_process(&m_part_menu); append_menu_item_per_object_settings(&m_part_menu); @@ -1466,15 +1537,16 @@ void MenuFactory::create_bbl_part_menu() if (!split_menu) return; - append_menu_item(split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), - [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", menu, - []() { return plater()->can_split(true); }, m_parent); - append_menu_item(split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), - [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", menu, - []() { return plater()->can_split(false); }, m_parent); + append_menu_item( + split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), + [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", menu, []() { return plater()->can_split(true); }, + m_parent); + append_menu_item( + split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), + [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", menu, []() { return plater()->can_split(false); }, m_parent); - append_submenu(menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", - []() { return plater()->can_split(true); }, m_parent); + append_submenu( + menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", []() { return plater()->can_split(true); }, m_parent); menu->AppendSeparator(); append_menu_item_per_object_process(menu); append_menu_item_per_object_settings(menu); @@ -1495,84 +1567,84 @@ void MenuFactory::create_bbl_assemble_part_menu() void MenuFactory::create_filament_action_menu(bool init, int active_filament_menu_id) { - wxMenu *menu = &m_filament_action_menu; + wxMenu* menu = &m_filament_action_menu; if (init) { append_menu_item( - menu, wxID_ANY, _L("Edit"), "", [](wxCommandEvent&) { - plater()->sidebar().edit_filament(); }, "", nullptr, + menu, wxID_ANY, _L("Edit"), "", [](wxCommandEvent&) { plater()->sidebar().edit_filament(); }, "", nullptr, []() { return true; }, m_parent); } if (init) { append_menu_item( - menu, wxID_ANY, _L("Delete"), _L("Delete this filament"), [](wxCommandEvent&) { - plater()->sidebar().delete_filament(-2); }, "", nullptr, + menu, wxID_ANY, _L("Delete"), _L("Delete this filament"), [](wxCommandEvent&) { plater()->sidebar().delete_filament(-2); }, "", + nullptr, []() { return plater()->sidebar().combos_filament().size() > 1 - // Orca: only show delete filament option for SEMM machines unless is BBL - && Sidebar::should_show_SEMM_buttons(); - }, m_parent); + // Orca: only show delete filament option for SEMM machines unless is BBL + && Sidebar::should_show_SEMM_buttons(); + }, + m_parent); } const int item_id = menu->FindItem(_L("Merge with")); if (item_id != wxNOT_FOUND) menu->Destroy(item_id); - wxMenu* sub_menu = new wxMenu(); - std::vector icons = get_extruder_color_icons(true); - int filaments_cnt = Sidebar::should_show_SEMM_buttons() ? icons.size() : 0; + wxMenu* sub_menu = new wxMenu(); + std::vector icons = get_extruder_color_icons(true); + int filaments_cnt = Sidebar::should_show_SEMM_buttons() ? icons.size() : 0; for (int i = 0; i < filaments_cnt; i++) { if (i == active_filament_menu_id) continue; - auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i]); - wxString item_name = preset ? from_u8(preset->label(false)) : wxString::Format(_L("Filament %d"), i + 1); + auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i]); + wxString item_name = preset ? from_u8(preset->label(false)) : + wxString::Format(_L("Filament %d"), filament_index_from_zero_based(i)); - append_menu_item(sub_menu, wxID_ANY, item_name, "", - [i](wxCommandEvent&) { plater()->sidebar().change_filament(-2, i); }, *icons[i], menu, + append_menu_item( + sub_menu, wxID_ANY, item_name, "", [i](wxCommandEvent&) { plater()->sidebar().change_filament(-2, i); }, *icons[i], menu, []() { return true; }, m_parent); } - append_submenu(menu, sub_menu, wxID_ANY, _L("Merge with"), "", "", - [filaments_cnt]() { return filaments_cnt > 1; }, m_parent); + append_submenu(menu, sub_menu, wxID_ANY, _L("Merge with"), "", "", [filaments_cnt]() { return filaments_cnt > 1; }, m_parent); } -//BBS: add part plate related logic +// BBS: add part plate related logic void MenuFactory::create_plate_menu() { wxMenu* menu = &m_plate_menu; // select objects on current plate - append_menu_item(menu, wxID_ANY, _L("Select All"), _L("select all objects on current plate"), - [](wxCommandEvent&) { - plater()->select_curr_plate_all(); - }, "", nullptr, []() { + append_menu_item( + menu, wxID_ANY, _L("Select All"), _L("select all objects on current plate"), + [](wxCommandEvent&) { plater()->select_curr_plate_all(); }, "", nullptr, + []() { PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); assert(plate); return !plate->get_objects().empty(); - }, m_parent); + }, + m_parent); // delete objects on current plate - append_menu_item(menu, wxID_ANY, _L("Delete All"), _L("delete all objects on current plate"), - [](wxCommandEvent&) { - plater()->remove_curr_plate_all(); - }, "", nullptr, []() { + append_menu_item( + menu, wxID_ANY, _L("Delete All"), _L("delete all objects on current plate"), + [](wxCommandEvent&) { plater()->remove_curr_plate_all(); }, "", nullptr, + []() { PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); assert(plate); return !plate->get_objects().empty(); - }, m_parent); + }, + m_parent); // arrange objects on current plate - append_menu_item(menu, wxID_ANY, _L("Arrange"), _L("arrange current plate"), + append_menu_item( + menu, wxID_ANY, _L("Arrange"), _L("arrange current plate"), [](wxCommandEvent&) { PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); assert(plate); plater()->set_prepare_state(Job::PREPARE_STATE_MENU); plater()->arrange(); - }, "", nullptr, - []() { - return !plater()->get_partplate_list().get_selected_plate()->get_objects().empty(); }, - m_parent); + "", nullptr, []() { return !plater()->get_partplate_list().get_selected_plate()->get_objects().empty(); }, m_parent); // reload all objects on current plate append_menu_item( @@ -1586,55 +1658,49 @@ void MenuFactory::create_plate_menu() "", nullptr, []() { return !plater()->get_partplate_list().get_selected_plate()->get_objects().empty(); }, m_parent); // orient objects on current plate - append_menu_item(menu, wxID_ANY, _L("Auto Rotate"), _L("auto rotate current plate"), + append_menu_item( + menu, wxID_ANY, _L("Auto Rotate"), _L("auto rotate current plate"), [](wxCommandEvent&) { PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); assert(plate); - //BBS TODO call auto rotate for current plate + // BBS TODO call auto rotate for current plate plater()->set_prepare_state(Job::PREPARE_STATE_MENU); plater()->orient(); - }, "", nullptr, - []() { - return !plater()->get_partplate_list().get_selected_plate()->get_objects().empty(); - }, m_parent); + }, + "", nullptr, []() { return !plater()->get_partplate_list().get_selected_plate()->get_objects().empty(); }, m_parent); // delete current plate #ifdef __WINDOWS__ - append_menu_item(menu, wxID_ANY, _L("Delete Plate"), _L("Remove the selected plate"), - [](wxCommandEvent&) { plater()->delete_plate(); }, "menu_delete", nullptr, - []() { return plater()->can_delete_plate(); }, m_parent); + append_menu_item( + menu, wxID_ANY, _L("Delete Plate"), _L("Remove the selected plate"), [](wxCommandEvent&) { plater()->delete_plate(); }, + "menu_delete", nullptr, []() { return plater()->can_delete_plate(); }, m_parent); #else - append_menu_item(menu, wxID_ANY, _L("Delete Plate"), _L("Remove the selected plate"), - [](wxCommandEvent&) { plater()->delete_plate(); }, "", nullptr, + append_menu_item( + menu, wxID_ANY, _L("Delete Plate"), _L("Remove the selected plate"), [](wxCommandEvent&) { plater()->delete_plate(); }, "", nullptr, []() { return plater()->can_delete_plate(); }, m_parent); #endif - // add shapes menu->AppendSeparator(); wxMenu* sub_menu_primitives = append_submenu_add_generic(menu, ModelVolumeType::INVALID); - wxMenu* sub_menu_handy = append_submenu_add_handy_model(menu, ModelVolumeType::INVALID); + wxMenu* sub_menu_handy = append_submenu_add_handy_model(menu, ModelVolumeType::INVALID); #ifdef __WINDOWS__ - append_submenu(menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "menu_add_part", - []() {return true; }, m_parent); - append_submenu(menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "menu_add_part", - []() {return true; }, m_parent); - append_menu_item(menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models - [](wxCommandEvent&) { plater()->add_file(); }, "menu_add_part", menu, - []() {return wxGetApp().plater()->can_add_model(); }, m_parent); + append_submenu(menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "menu_add_part", []() { return true; }, m_parent); + append_submenu(menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "menu_add_part", []() { return true; }, m_parent); + append_menu_item( + menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models + [](wxCommandEvent&) { plater()->add_file(); }, "menu_add_part", menu, []() { return wxGetApp().plater()->can_add_model(); }, + m_parent); #else - append_submenu(menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "", - []() {return true; }, m_parent); - append_submenu(menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "", - []() {return true; }, m_parent); - append_menu_item(menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models - [](wxCommandEvent&) { plater()->add_file(); }, "", menu, - []() {return wxGetApp().plater()->can_add_model(); }, m_parent); + append_submenu(menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "", []() { return true; }, m_parent); + append_submenu(menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "", []() { return true; }, m_parent); + append_menu_item( + menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models + [](wxCommandEvent&) { plater()->add_file(); }, "", menu, []() { return wxGetApp().plater()->can_add_model(); }, m_parent); #endif append_menu_item_replace_all_with_stl(menu); - return; } @@ -1643,10 +1709,10 @@ void MenuFactory::init(wxWindow* parent) m_parent = parent; create_default_menu(); - //BBS - //create_object_menu(); + // BBS + // create_object_menu(); create_sla_object_menu(); - //create_part_menu(); + // create_part_menu(); create_text_part_menu(); create_svg_part_menu(); create_extra_object_menu(); @@ -1654,7 +1720,7 @@ void MenuFactory::init(wxWindow* parent) create_bbl_assemble_object_menu(); create_bbl_assemble_part_menu(); - //BBS: add part plate related logic + // BBS: add part plate related logic create_plate_menu(); create_filament_action_menu(true, -1); @@ -1669,10 +1735,7 @@ void MenuFactory::update() update_object_menu(); } -wxMenu* MenuFactory::default_menu() -{ - return &m_default_menu; -} +wxMenu* MenuFactory::default_menu() { return &m_default_menu; } wxMenu* MenuFactory::object_menu() { @@ -1689,7 +1752,7 @@ wxMenu* MenuFactory::sla_object_menu() { append_menu_items_convert_unit(&m_sla_object_menu); append_menu_item_settings(&m_sla_object_menu); - //update_menu_items_instance_manipulation(mtObjectSLA); + // update_menu_items_instance_manipulation(mtObjectSLA); append_menu_item_edit_text(&m_sla_object_menu); append_menu_item_edit_svg(&m_object_menu); @@ -1712,7 +1775,7 @@ wxMenu* MenuFactory::text_part_menu() return &m_text_part_menu; } -wxMenu *MenuFactory::svg_part_menu() +wxMenu* MenuFactory::svg_part_menu() { append_menu_item_change_filament(&m_svg_part_menu); append_menu_item_per_object_settings(&m_svg_part_menu); @@ -1720,10 +1783,7 @@ wxMenu *MenuFactory::svg_part_menu() return &m_svg_part_menu; } -wxMenu* MenuFactory::instance_menu() -{ - return &m_instance_menu; -} +wxMenu* MenuFactory::instance_menu() { return &m_instance_menu; } wxMenu* MenuFactory::layer_menu() { @@ -1735,12 +1795,12 @@ wxMenu* MenuFactory::layer_menu() wxMenu* MenuFactory::multi_selection_menu() { - //BBS + // BBS wxDataViewItemArray sels; obj_list()->GetSelections(sels); - bool multi_volume = true; + bool multi_volume = true; bool undefined_type = false; - bool all_plates = true; + bool all_plates = true; for (const wxDataViewItem& item : sels) { Slic3r::GUI::ItemType item_type = list_model()->GetItemType(item); @@ -1769,7 +1829,7 @@ wxMenu* MenuFactory::multi_selection_menu() append_menu_item_center(menu); append_menu_item_drop(menu); append_menu_item_fix_through_netfabb(menu); - //append_menu_item_simplify(menu); + // append_menu_item_simplify(menu); append_menu_item_delete(menu); menu->AppendSeparator(); @@ -1778,31 +1838,33 @@ wxMenu* MenuFactory::multi_selection_menu() menu->AppendSeparator(); append_menu_items_convert_unit(menu); append_menu_item_replace_all_with_stl(menu); - //BBS + // BBS append_menu_item_change_filament(menu); menu->AppendSeparator(); append_menu_item_export_stl(menu, true); - } - else { + } else { append_menu_item_center(menu); append_menu_item_drop(menu); append_menu_item_fix_through_netfabb(menu); - //append_menu_item_simplify(menu); + // append_menu_item_simplify(menu); append_menu_item_delete(menu); append_menu_items_convert_unit(menu); append_menu_item_replace_all_with_stl(menu); append_menu_item_change_filament(menu); wxMenu* split_menu = new wxMenu(); if (split_menu) { - append_menu_item(split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), - [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", menu, - []() { return plater()->can_split(true); }, m_parent); - append_menu_item(split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), - [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", menu, - []() { return plater()->can_split(false); }, m_parent); + append_menu_item( + split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), + [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", menu, []() { return plater()->can_split(true); }, + m_parent); + append_menu_item( + split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), + [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", menu, []() { return plater()->can_split(false); }, + m_parent); - append_submenu(menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", - []() { return plater()->can_split(true); }, m_parent); + append_submenu( + menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", []() { return plater()->can_split(true); }, + m_parent); } append_menu_item_per_object_process(menu); menu->AppendSeparator(); @@ -1824,41 +1886,44 @@ wxMenu* MenuFactory::assemble_multi_selection_menu() wxMenu* menu = new MenuWithSeparators(); append_menu_item_set_visible(menu); - //append_menu_item_fix_through_netfabb(menu); - //append_menu_item_simplify(menu); + // append_menu_item_fix_through_netfabb(menu); + // append_menu_item_simplify(menu); append_menu_item_delete(menu); menu->AppendSeparator(); append_menu_item_change_extruder(menu); return menu; } - -//PS +// PS void MenuFactory::append_menu_items_instance_manipulation(wxMenu* menu) { MenuType type = menu == &m_object_menu ? mtObjectFFF : mtObjectSLA; - items_increase[type] = append_menu_item(menu, wxID_ANY, _L("Add instance") + "\t+", _L("Add one more instance of the selected object"), - [](wxCommandEvent&) { plater()->increase_instances(); }, "", nullptr, - []() { return plater()->can_increase_instances(); }, m_parent); - items_decrease[type] = append_menu_item(menu, wxID_ANY, _L("Remove instance") + "\t-", _L("Remove one instance of the selected object"), - [](wxCommandEvent&) { plater()->decrease_instances(); }, "", nullptr, - []() { return plater()->can_decrease_instances(); }, m_parent); - items_set_number_of_copies[type] = append_menu_item(menu, wxID_ANY, _L("Set number of instances") + dots, _L("Change the number of instances of the selected object"), - [](wxCommandEvent&) { plater()->set_number_of_copies(); }, "", nullptr, - []() { return plater()->can_increase_instances(); }, m_parent); - append_menu_item(menu, wxID_ANY, _L("Fill bed with instances") + dots, _L("Fill the remaining area of bed with instances of the selected object"), - [](wxCommandEvent&) { plater()->fill_bed_with_instances(); }, "", nullptr, - []() { return plater()->can_increase_instances(); }, m_parent); + items_increase[type] = append_menu_item( + menu, wxID_ANY, _L("Add instance") + "\t+", _L("Add one more instance of the selected object"), + [](wxCommandEvent&) { plater()->increase_instances(); }, "", nullptr, []() { return plater()->can_increase_instances(); }, + m_parent); + items_decrease[type] = append_menu_item( + menu, wxID_ANY, _L("Remove instance") + "\t-", _L("Remove one instance of the selected object"), + [](wxCommandEvent&) { plater()->decrease_instances(); }, "", nullptr, []() { return plater()->can_decrease_instances(); }, + m_parent); + items_set_number_of_copies[type] = append_menu_item( + menu, wxID_ANY, _L("Set number of instances") + dots, _L("Change the number of instances of the selected object"), + [](wxCommandEvent&) { plater()->set_number_of_copies(); }, "", nullptr, []() { return plater()->can_increase_instances(); }, + m_parent); + append_menu_item( + menu, wxID_ANY, _L("Fill bed with instances") + dots, _L("Fill the remaining area of bed with instances of the selected object"), + [](wxCommandEvent&) { plater()->fill_bed_with_instances(); }, "", nullptr, []() { return plater()->can_increase_instances(); }, + m_parent); } -wxMenu *MenuFactory::filament_action_menu(int active_filament_menu_id) { +wxMenu* MenuFactory::filament_action_menu(int active_filament_menu_id) +{ create_filament_action_menu(false, active_filament_menu_id); return &m_filament_action_menu; } - -//BBS: add partplate related logic +// BBS: add partplate related logic wxMenu* MenuFactory::plate_menu() { append_menu_item_locked(&m_plate_menu); @@ -1874,15 +1939,15 @@ wxMenu* MenuFactory::assemble_object_menu() // Delete append_menu_item_delete(menu); //// Object Repair - //append_menu_item_fix_through_netfabb(menu); + // append_menu_item_fix_through_netfabb(menu); //// Object Simplify - //append_menu_item_simplify(menu); + // append_menu_item_simplify(menu); menu->AppendSeparator(); // Set filament append_menu_item_change_extruder(menu); //// Enter per object parameters - //append_menu_item_per_object_settings(menu); + // append_menu_item_per_object_settings(menu); return menu; } @@ -1892,11 +1957,11 @@ wxMenu* MenuFactory::assemble_part_menu() append_menu_item_set_visible(menu); append_menu_item_delete(menu); - //append_menu_item_simplify(menu); + // append_menu_item_simplify(menu); menu->AppendSeparator(); append_menu_item_change_extruder(menu); - //append_menu_item_per_object_settings(menu); + // append_menu_item_per_object_settings(menu); return menu; } @@ -1908,99 +1973,80 @@ void MenuFactory::append_menu_item_clone(wxMenu* menu) // FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent? static const wxString ctrl = _L("Ctrl+"); #endif - append_menu_item(menu, wxID_ANY, _L("Clone") + "\t" + ctrl + "K", "", - [this](wxCommandEvent&) { - plater()->clone_selection(); - }, "", nullptr, - []() { - return true; - }, m_parent); + append_menu_item( + menu, wxID_ANY, _L("Clone") + "\t" + ctrl + "K", "", [this](wxCommandEvent&) { plater()->clone_selection(); }, "", nullptr, + []() { return true; }, m_parent); } void MenuFactory::append_menu_item_simplify(wxMenu* menu) { - wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Simplify Model"), "", - [](wxCommandEvent&) { obj_list()->simplify(); }, "", menu, - []() {return plater()->can_simplify(); }, m_parent); + wxMenuItem* menu_item = append_menu_item( + menu, wxID_ANY, _L("Simplify Model"), "", [](wxCommandEvent&) { obj_list()->simplify(); }, "", menu, + []() { return plater()->can_simplify(); }, m_parent); } void MenuFactory::append_menu_item_center(wxMenu* menu) { - append_menu_item(menu, wxID_ANY, _L("Center") , "", - [this](wxCommandEvent&) { - plater()->center_selection(); - }, "", nullptr, + append_menu_item( + menu, wxID_ANY, _L("Center"), "", [this](wxCommandEvent&) { plater()->center_selection(); }, "", nullptr, []() { if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D) return false; else { - Selection& selection = plater()->get_view3D_canvas3D()->get_selection(); - PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); - Vec3d model_pos = selection.get_bounding_box().center(); - Vec3d center_pos = plate->get_center_origin(); - return !( (model_pos.x() == center_pos.x()) && (model_pos.y() == center_pos.y()) ); - } //disable if model is at center / not in View3D - }, m_parent); + Selection& selection = plater()->get_view3D_canvas3D()->get_selection(); + PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); + Vec3d model_pos = selection.get_bounding_box().center(); + Vec3d center_pos = plate->get_center_origin(); + return !((model_pos.x() == center_pos.x()) && (model_pos.y() == center_pos.y())); + } // disable if model is at center / not in View3D + }, + m_parent); } void MenuFactory::append_menu_item_drop(wxMenu* menu) { - append_menu_item(menu, wxID_ANY, _L("Drop") , "", - [this](wxCommandEvent&) { - plater()->drop_selection(); - }, "", nullptr, + append_menu_item( + menu, wxID_ANY, _L("Drop"), "", [this](wxCommandEvent&) { plater()->drop_selection(); }, "", nullptr, []() { if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D) return false; else { return (plater()->get_view3D_canvas3D()->get_selection().get_bounding_box().min.z() != 0); - } //disable if model is on the bed / not in View3D - }, m_parent); + } // disable if model is on the bed / not in View3D + }, + m_parent); } void MenuFactory::append_menu_item_per_object_process(wxMenu* menu) { - const std::vector names = { _L("Edit Process Settings"), _L("Edit Process Settings") }; - append_menu_item(menu, wxID_ANY, names[0], names[1], - [](wxCommandEvent&) { - wxGetApp().obj_list()->switch_to_object_process(); - }, "", nullptr, + const std::vector names = {_L("Edit Process Settings"), _L("Edit Process Settings")}; + append_menu_item( + menu, wxID_ANY, names[0], names[1], [](wxCommandEvent&) { wxGetApp().obj_list()->switch_to_object_process(); }, "", nullptr, []() { Selection& selection = plater()->canvas3D()->get_selection(); - return selection.is_single_full_object() || - selection.is_multiple_full_object() || - selection.is_single_full_instance() || - selection.is_multiple_full_instance() || - selection.is_single_volume() || - selection.is_multiple_volume(); - }, m_parent); + return selection.is_single_full_object() || selection.is_multiple_full_object() || selection.is_single_full_instance() || + selection.is_multiple_full_instance() || selection.is_single_volume() || selection.is_multiple_volume(); + }, + m_parent); const std::vector names2 = {_L("Copy Process Settings"), _L("Copy Process Settings")}; append_menu_item( - menu, wxID_ANY, names2[0], names2[1], [](wxCommandEvent &) { - wxGetApp().obj_list()->copy_settings_to_clipboard(); - }, "", nullptr, + menu, wxID_ANY, names2[0], names2[1], [](wxCommandEvent&) { wxGetApp().obj_list()->copy_settings_to_clipboard(); }, "", nullptr, []() { - Selection &selection = plater()->canvas3D()->get_selection(); - return selection.is_single_full_object() || selection.is_single_full_instance() || - selection.is_single_volume_or_modifier(); + Selection& selection = plater()->canvas3D()->get_selection(); + return selection.is_single_full_object() || selection.is_single_full_instance() || selection.is_single_volume_or_modifier(); }, m_parent); const std::vector names3 = {_L("Paste Process Settings"), _L("Paste Process Settings")}; append_menu_item( - menu, wxID_ANY, names3[0], names3[1], [](wxCommandEvent &) { - wxGetApp().obj_list()->paste_settings_into_list(); - }, "", nullptr, - []() { - return wxGetApp().obj_list()->can_paste_settings_into_list(); - }, - m_parent); + menu, wxID_ANY, names3[0], names3[1], [](wxCommandEvent&) { wxGetApp().obj_list()->paste_settings_into_list(); }, "", nullptr, + []() { return wxGetApp().obj_list()->can_paste_settings_into_list(); }, m_parent); } void MenuFactory::append_menu_item_per_object_settings(wxMenu* menu) { - const std::vector names = { _L("Edit in Parameter Table"), _L("Edit print parameters for a single object") }; + const std::vector names = {_L("Edit in Parameter Table"), _L("Edit print parameters for a single object")}; // Delete old menu item for (const wxString& name : names) { const int item_id = menu->FindItem(name); @@ -2008,19 +2054,18 @@ void MenuFactory::append_menu_item_per_object_settings(wxMenu* menu) menu->Destroy(item_id); } - append_menu_item(menu, wxID_ANY, names[0], names[1], - [](wxCommandEvent&) { - plater()->PopupObjectTableBySelection(); - }, "", nullptr, + append_menu_item( + menu, wxID_ANY, names[0], names[1], [](wxCommandEvent&) { plater()->PopupObjectTableBySelection(); }, "", nullptr, []() { Selection& selection = plater()->canvas3D()->get_selection(); return selection.is_single_full_object() || selection.is_single_full_instance() || selection.is_single_volume(); - }, m_parent); + }, + m_parent); } void MenuFactory::append_menu_item_change_filament(wxMenu* menu) { - const std::vector names = { _L("Change Filament"), _L("Set Filament for selected items") }; + const std::vector names = {_L("Change Filament"), _L("Set Filament for selected items")}; // Delete old menu item for (const wxString& name : names) { const int item_id = menu->FindItem(name); @@ -2045,14 +2090,14 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu) std::vector icons = get_extruder_color_icons(true); if (icons.size() < filaments_cnt) { - BOOST_LOG_TRIVIAL(warning) << boost::format("Warning: icons size %1%, filaments_cnt=%2%")%icons.size()%filaments_cnt; + BOOST_LOG_TRIVIAL(warning) << boost::format("Warning: icons size %1%, filaments_cnt=%2%") % icons.size() % filaments_cnt; if (icons.size() <= 1) return; else filaments_cnt = icons.size(); } - wxMenu* extruder_selection_menu = new wxMenu(); - const wxString& name = sels.Count() == 1 ? names[0] : names[1]; + wxMenu* extruder_selection_menu = new wxMenu(); + const wxString& name = sels.Count() == 1 ? names[0] : names[1]; int initial_extruder = -1; // negative value for multiple object/part selection if (sels.Count() == 1) { @@ -2074,10 +2119,9 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu) } } - for (int i = has_modifier ? 0 : 1; i <= filaments_cnt; i++) - { + for (int i = has_modifier ? 0 : 1; i <= filaments_cnt; i++) { // BBS - //bool is_active_extruder = i == initial_extruder; + // bool is_active_extruder = i == initial_extruder; bool is_active_extruder = false; wxString item_name = _L("Default"); @@ -2085,7 +2129,7 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu) if (i > 0) { auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i - 1]); if (preset == nullptr) { - item_name = wxString::Format(_L("Filament %d"), i); + item_name = wxString::Format(_L("Filament %d"), filament_index_from_one_based(i)); } else { item_name = from_u8(preset->label(false)); } @@ -2095,18 +2139,18 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu) item_name << " (" + _L("current") + ")"; } - append_menu_item(extruder_selection_menu, wxID_ANY, item_name, "", - [i](wxCommandEvent&) { obj_list()->set_extruder_for_selected_items(i); }, i == 0 ? wxNullBitmap : *icons[i - 1], menu, - [is_active_extruder]() { return !is_active_extruder; }, m_parent); + append_menu_item( + extruder_selection_menu, wxID_ANY, item_name, "", [i](wxCommandEvent&) { obj_list()->set_extruder_for_selected_items(i); }, + i == 0 ? wxNullBitmap : *icons[i - 1], menu, [is_active_extruder]() { return !is_active_extruder; }, m_parent); } menu->Append(wxID_ANY, name, extruder_selection_menu, _L("Change Filament")); } void MenuFactory::append_menu_item_set_printable(wxMenu* menu) { - const Selection& selection = plater()->canvas3D()->get_selection(); - bool all_printable = true; - ObjectList* list = obj_list(); + const Selection& selection = plater()->canvas3D()->get_selection(); + bool all_printable = true; + ObjectList* list = obj_list(); wxDataViewItemArray sels; list->GetSelections(sels); @@ -2115,27 +2159,32 @@ void MenuFactory::append_menu_item_set_printable(wxMenu* menu) if (type != itInstance && type != itObject) continue; else { - int obj_idx = list->GetModel()->GetObjectIdByItem(item); + int obj_idx = list->GetModel()->GetObjectIdByItem(item); int inst_idx = type == itObject ? 0 : list->GetModel()->GetInstanceIdByItem(item); all_printable &= list->object(obj_idx)->instances[inst_idx]->printable; } } - wxString menu_text = _L("Printable"); - wxMenuItem* menu_item_set_printable = append_menu_check_item(menu, wxID_ANY, menu_text, "", [this, all_printable](wxCommandEvent&) { - Selection& selection = plater()->canvas3D()->get_selection(); - selection.set_printable(!all_printable); - }, menu); - m_parent->Bind(wxEVT_UPDATE_UI, [all_printable](wxUpdateUIEvent& evt) { - evt.Check(all_printable); - plater()->set_current_canvas_as_dirty(); - - }, menu_item_set_printable->GetId()); + wxString menu_text = _L("Printable"); + wxMenuItem* menu_item_set_printable = append_menu_check_item( + menu, wxID_ANY, menu_text, "", + [this, all_printable](wxCommandEvent&) { + Selection& selection = plater()->canvas3D()->get_selection(); + selection.set_printable(!all_printable); + }, + menu); + m_parent->Bind( + wxEVT_UPDATE_UI, + [all_printable](wxUpdateUIEvent& evt) { + evt.Check(all_printable); + plater()->set_current_canvas_as_dirty(); + }, + menu_item_set_printable->GetId()); } void MenuFactory::append_menu_item_locked(wxMenu* menu) { - const std::vector names = { _L("Unlock"), _L("Lock") }; + const std::vector names = {_L("Unlock"), _L("Lock")}; // Delete old menu item for (const wxString& name : names) { const int item_id = menu->FindItem(name); @@ -2147,41 +2196,45 @@ void MenuFactory::append_menu_item_locked(wxMenu* menu) assert(plate); wxString lock_text = plate->is_locked() ? names[0] : names[1]; - auto item = append_menu_item(menu, wxID_ANY, lock_text, "", + auto item = append_menu_item( + menu, wxID_ANY, lock_text, "", [plate](wxCommandEvent&) { bool lock = plate->is_locked(); plate->lock(!lock); - }, "", nullptr, []() { return true; }, m_parent); + }, + "", nullptr, []() { return true; }, m_parent); - m_parent->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt) { - PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); - assert(plate); - //bool check = plate->is_locked(); - //evt.Check(check); - plater()->set_current_canvas_as_dirty(); - }, item->GetId()); + m_parent->Bind( + wxEVT_UPDATE_UI, + [](wxUpdateUIEvent& evt) { + PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); + assert(plate); + // bool check = plate->is_locked(); + // evt.Check(check); + plater()->set_current_canvas_as_dirty(); + }, + item->GetId()); } -void MenuFactory::append_menu_item_plate_name(wxMenu *menu) +void MenuFactory::append_menu_item_plate_name(wxMenu* menu) { - wxString name= _L("Edit Plate Name"); + wxString name = _L("Edit Plate Name"); // Delete old menu item const int item_id = menu->FindItem(name); - if (item_id != wxNOT_FOUND) menu->Destroy(item_id); + if (item_id != wxNOT_FOUND) + menu->Destroy(item_id); - PartPlate *plate = plater()->get_partplate_list().get_selected_plate(); + PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); assert(plate); auto item = append_menu_item( menu, wxID_ANY, name, "", - [plate](wxCommandEvent &e) { - int hover_idx =plater()->canvas3D()->GetHoverId(); + [plate](wxCommandEvent& e) { + int hover_idx = plater()->canvas3D()->GetHoverId(); if (hover_idx == -1) { - int plate_idx=plater()->GetPlateIndexByRightMenuInLeftUI(); + int plate_idx = plater()->GetPlateIndexByRightMenuInLeftUI(); plater()->select_plate_by_hover_id(plate_idx * PartPlate::GRABBER_COUNT, false, true); - } - else - { + } else { plater()->select_plate_by_hover_id(hover_idx, false, true); } plater()->get_current_canvas3D()->post_event(SimpleEvent(EVT_GLCANVAS_PLATE_NAME_CHANGE)); @@ -2190,22 +2243,19 @@ void MenuFactory::append_menu_item_plate_name(wxMenu *menu) m_parent->Bind( wxEVT_UPDATE_UI, - [](wxUpdateUIEvent &evt) { - PartPlate *plate = plater()->get_partplate_list().get_selected_plate(); + [](wxUpdateUIEvent& evt) { + PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); assert(plate); plater()->set_current_canvas_as_dirty(); }, item->GetId()); } -void MenuFactory::update_object_menu() -{ - append_menu_items_add_volume(&m_object_menu); -} +void MenuFactory::update_object_menu() { append_menu_items_add_volume(&m_object_menu); } void MenuFactory::update_default_menu() { - for (auto& name : { _L("Add Primitive") , _L("Add Handy models"), _L("Show Labels") }) { + for (auto& name : {_L("Add Primitive"), _L("Add Handy models"), _L("Show Labels")}) { const auto menu_item_id = m_default_menu.FindItem(name); if (menu_item_id != wxNOT_FOUND) m_default_menu.Destroy(menu_item_id); @@ -2215,7 +2265,7 @@ void MenuFactory::update_default_menu() void MenuFactory::msw_rescale() { - for (MenuWithSeparators* menu : { &m_object_menu, &m_sla_object_menu, &m_part_menu, &m_default_menu }) + for (MenuWithSeparators* menu : {&m_object_menu, &m_sla_object_menu, &m_part_menu, &m_default_menu}) msw_rescale_menu(dynamic_cast(menu)); } @@ -2223,21 +2273,22 @@ void MenuFactory::msw_rescale() // For this class is used code from stackoverflow: // https://stackoverflow.com/questions/257288/is-it-possible-to-write-a-template-to-check-for-a-functions-existence // Using this code we can to inspect of an existence of IsWheelInverted() function in class T -template -class menu_has_update_def_colors +template class menu_has_update_def_colors { typedef char one; - struct two { char x[2]; }; + struct two + { + char x[2]; + }; - template static one test(decltype(&C::UpdateDefColors)); - template static two test(...); + template static one test(decltype(&C::UpdateDefColors)); + template static two test(...); public: static constexpr bool value = sizeof(test(0)) == sizeof(char); }; -template -static void update_menu_item_def_colors(T* item) +template static void update_menu_item_def_colors(T* item) { if constexpr (menu_has_update_def_colors::value) { item->UpdateDefColors(); @@ -2247,8 +2298,8 @@ static void update_menu_item_def_colors(T* item) void MenuFactory::sys_color_changed() { - for (MenuWithSeparators* menu : { &m_object_menu, &m_sla_object_menu, &m_part_menu, &m_default_menu }) { - msw_rescale_menu(dynamic_cast(menu));// msw_rescale_menu updates just icons, so use it + for (MenuWithSeparators* menu : {&m_object_menu, &m_sla_object_menu, &m_part_menu, &m_default_menu}) { + msw_rescale_menu(dynamic_cast(menu)); // msw_rescale_menu updates just icons, so use it #ifdef _WIN32 // but under MSW we have to update item's bachground color for (wxMenuItem* item : menu->GetMenuItems()) @@ -2274,6 +2325,4 @@ void MenuFactory::sys_color_changed(wxMenuBar* menubar) #endif } - -} //namespace GUI -} //namespace Slic3r +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index d8bc90fdd6..1855adcf96 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -14,7 +14,6 @@ #include "libslic3r/Model.hpp" #include "slic3r/Utils/UndoRedo.hpp" - #include namespace Slic3r::GUI { @@ -24,9 +23,11 @@ static inline void show_notification_extruders_limit_exceeded() wxGetApp() .plater() ->get_notification_manager() - ->push_notification(NotificationType::MmSegmentationExceededExtrudersLimit, NotificationManager::NotificationLevel::PrintInfoNotificationLevel, + ->push_notification(NotificationType::MmSegmentationExceededExtrudersLimit, + NotificationManager::NotificationLevel::PrintInfoNotificationLevel, GUI::format(_L("Filament count exceeds the maximum number that painting tool supports. Only the " - "first %1% filaments will be available in painting tool."), GLGizmoMmuSegmentation::EXTRUDERS_LIMIT)); + "first %1% filaments will be available in painting tool."), + GLGizmoMmuSegmentation::EXTRUDERS_LIMIT)); } void GLGizmoMmuSegmentation::on_opening() @@ -41,15 +42,12 @@ void GLGizmoMmuSegmentation::on_shutdown() m_parent.toggle_model_objects_visibility(true); } -std::string GLGizmoMmuSegmentation::on_get_name() const -{ - return _u8L("Color Painting"); -} +std::string GLGizmoMmuSegmentation::on_get_name() const { return _u8L("Color Painting"); } bool GLGizmoMmuSegmentation::on_is_selectable() const { - return (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF - && /*wxGetApp().get_mode() != comSimple && */wxGetApp().filaments_cnt() > 1); + return (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF && + /*wxGetApp().get_mode() != comSimple && */ wxGetApp().filaments_cnt() > 1); } bool GLGizmoMmuSegmentation::on_is_activable() const @@ -58,11 +56,11 @@ bool GLGizmoMmuSegmentation::on_is_activable() const return !selection.is_empty() && (selection.is_single_full_instance() || selection.is_any_volume()) && wxGetApp().filaments_cnt() > 1; } -static std::vector get_extruder_id_for_volumes(const ModelObject &model_object) +static std::vector get_extruder_id_for_volumes(const ModelObject& model_object) { std::vector extruders_idx; extruders_idx.reserve(model_object.volumes.size()); - for (const ModelVolume *model_volume : model_object.volumes) { + for (const ModelVolume* model_volume : model_object.volumes) { if (!model_volume->is_model_part()) continue; @@ -89,17 +87,17 @@ bool GLGizmoMmuSegmentation::on_init() m_shortcut_key = WXK_CONTROL_N; // FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent? - const wxString ctrl = _L("Ctrl+"); + const wxString ctrl = _L("Ctrl+"); // FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent? const wxString alt = _L("Alt+"); const wxString shift = _L("Shift+"); m_desc["clipping_of_view_caption"] = alt + _L("Mouse wheel"); - m_desc["clipping_of_view"] = _L("Section view"); - m_desc["reset_direction"] = _L("Reset direction"); - m_desc["cursor_size_caption"] = ctrl + _L("Mouse wheel"); - m_desc["cursor_size"] = _L("Pen size"); - m_desc["cursor_type"] = _L("Pen shape"); + m_desc["clipping_of_view"] = _L("Section view"); + m_desc["reset_direction"] = _L("Reset direction"); + m_desc["cursor_size_caption"] = ctrl + _L("Mouse wheel"); + m_desc["cursor_size"] = _L("Pen size"); + m_desc["cursor_type"] = _L("Pen shape"); m_desc["paint_caption"] = _L("Left mouse button"); m_desc["paint"] = _L("Paint"); @@ -112,31 +110,31 @@ bool GLGizmoMmuSegmentation::on_init() m_desc["gap_area"] = _L("Gap area"); m_desc["perform"] = _L("Perform"); - m_desc["remove_all"] = _L("Erase all painting"); - m_desc["circle"] = _L("Circle"); - m_desc["sphere"] = _L("Sphere"); - m_desc["pointer"] = _L("Triangles"); + m_desc["remove_all"] = _L("Erase all painting"); + m_desc["circle"] = _L("Circle"); + m_desc["sphere"] = _L("Sphere"); + m_desc["pointer"] = _L("Triangles"); - m_desc["filaments"] = _L("Filaments"); - m_desc["tool_type"] = _L("Tool type"); - m_desc["tool_brush"] = _L("Brush"); - m_desc["tool_smart_fill"] = _L("Smart fill"); - m_desc["tool_bucket_fill"] = _L("Bucket fill"); + m_desc["filaments"] = _L("Filaments"); + m_desc["tool_type"] = _L("Tool type"); + m_desc["tool_brush"] = _L("Brush"); + m_desc["tool_smart_fill"] = _L("Smart fill"); + m_desc["tool_bucket_fill"] = _L("Bucket fill"); m_desc["smart_fill_angle_caption"] = ctrl + _L("Mouse wheel"); - m_desc["smart_fill_angle"] = _L("Smart fill angle"); + m_desc["smart_fill_angle"] = _L("Smart fill angle"); m_desc["height_range_caption"] = ctrl + _L("Mouse wheel"); m_desc["height_range"] = _L("Height range"); - //add toggle wire frame hint - m_desc["toggle_wireframe_caption"] = alt + shift + _L("Enter"); - m_desc["toggle_wireframe"] = _L("Toggle Wireframe"); + // add toggle wire frame hint + m_desc["toggle_wireframe_caption"] = alt + shift + _L("Enter"); + m_desc["toggle_wireframe"] = _L("Toggle Wireframe"); // Filament remapping descriptions - m_desc["perform_remap"] = _L("Remap filaments"); - m_desc["remap"] = _L("Remap"); - m_desc["cancel_remap"] = _L("Cancel"); + m_desc["perform_remap"] = _L("Remap filaments"); + m_desc["remap"] = _L("Remap"); + m_desc["cancel_remap"] = _L("Cancel"); init_extruders_data(); @@ -145,8 +143,7 @@ bool GLGizmoMmuSegmentation::on_init() GLGizmoMmuSegmentation::GLGizmoMmuSegmentation(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoPainterBase(parent, icon_filename, sprite_id), m_current_tool(ImGui::CircleButtonIcon) -{ -} +{} void GLGizmoMmuSegmentation::render_painter_gizmo() { @@ -167,11 +164,12 @@ void GLGizmoMmuSegmentation::render_painter_gizmo() void GLGizmoMmuSegmentation::data_changed(bool is_serializing) { GLGizmoPainterBase::data_changed(is_serializing); - if (m_state != On || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptFFF || wxGetApp().extruders_edited_cnt() <= 1) + if (m_state != On || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptFFF || + wxGetApp().extruders_edited_cnt() <= 1) return; - ModelObject* model_object = m_c->selection_info()->model_object(); - int prev_extruders_count = int(m_extruders_colors.size()); + ModelObject* model_object = m_c->selection_info()->model_object(); + int prev_extruders_count = int(m_extruders_colors.size()); if (prev_extruders_count != wxGetApp().filaments_cnt()) { if (wxGetApp().filaments_cnt() > int(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT)) show_notification_extruders_limit_exceeded(); @@ -183,8 +181,7 @@ void GLGizmoMmuSegmentation::data_changed(bool is_serializing) } else if (wxGetApp().plater()->get_extruders_colors() != m_extruders_colors) { this->init_extruders_data(); this->update_triangle_selectors_colors(); - } - else if (model_object != nullptr && get_extruder_id_for_volumes(*model_object) != m_volumes_extruder_idxs) { + } else if (model_object != nullptr && get_extruder_id_for_volumes(*model_object) != m_volumes_extruder_idxs) { this->init_model_triangle_selectors(); } } @@ -199,38 +196,24 @@ bool GLGizmoMmuSegmentation::on_number_key_down(int number) return true; } -bool GLGizmoMmuSegmentation::on_key_down_select_tool_type(int keyCode) { - switch (keyCode) - { - case 'F': - m_current_tool = ImGui::FillButtonIcon; - break; - case 'T': - m_current_tool = ImGui::TriangleButtonIcon; - break; - case 'S': - m_current_tool = ImGui::SphereButtonIcon; - break; - case 'C': - m_current_tool = ImGui::CircleButtonIcon; - break; - case 'H': - m_current_tool = ImGui::HeightRangeIcon; - break; - case 'G': - m_current_tool = ImGui::GapFillIcon; - break; - default: - return false; - break; +bool GLGizmoMmuSegmentation::on_key_down_select_tool_type(int keyCode) +{ + switch (keyCode) { + case 'F': m_current_tool = ImGui::FillButtonIcon; break; + case 'T': m_current_tool = ImGui::TriangleButtonIcon; break; + case 'S': m_current_tool = ImGui::SphereButtonIcon; break; + case 'C': m_current_tool = ImGui::CircleButtonIcon; break; + case 'H': m_current_tool = ImGui::HeightRangeIcon; break; + case 'G': m_current_tool = ImGui::GapFillIcon; break; + default: return false; break; } return true; } -static void render_extruders_combo(const std::string& label, +static void render_extruders_combo(const std::string& label, const std::vector& extruders, - const std::vector& extruders_colors, - size_t& selection_idx) + const std::vector& extruders_colors, + size_t& selection_idx) { assert(!extruders_colors.empty()); assert(extruders_colors.size() == extruders_colors.size()); @@ -248,10 +231,13 @@ static void render_extruders_combo(const std::string& label, selection_out = extruder_idx; ImGui::SameLine(); - ImGuiStyle &style = ImGui::GetStyle(); + ImGuiStyle& style = ImGui::GetStyle(); float height = ImGui::GetTextLineHeight(); - ImGui::GetWindowDrawList()->AddRectFilled(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), ImGuiWrapper::to_ImU32(extruders_colors[extruder_idx])); - ImGui::GetWindowDrawList()->AddRect(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), IM_COL32_BLACK); + ImGui::GetWindowDrawList()->AddRectFilled(start_position, + ImVec2(start_position.x + height + height / 2, start_position.y + height), + ImGuiWrapper::to_ImU32(extruders_colors[extruder_idx])); + ImGui::GetWindowDrawList()->AddRect(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), + IM_COL32_BLACK); ImGui::SetCursorScreenPos(ImVec2(start_position.x + height + height / 2 + style.FramePadding.x, start_position.y)); ImGui::Text("%s", extruders[extruder_idx].c_str()); @@ -262,13 +248,14 @@ static void render_extruders_combo(const std::string& label, } ImVec2 backup_pos = ImGui::GetCursorScreenPos(); - ImGuiStyle &style = ImGui::GetStyle(); + ImGuiStyle& style = ImGui::GetStyle(); ImGui::SetCursorScreenPos(ImVec2(combo_pos.x + style.FramePadding.x, combo_pos.y + style.FramePadding.y)); ImVec2 p = ImGui::GetCursorScreenPos(); float height = ImGui::GetTextLineHeight(); - ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + height + height / 2, p.y + height), ImGuiWrapper::to_ImU32(extruders_colors[selection_idx])); + ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + height + height / 2, p.y + height), + ImGuiWrapper::to_ImU32(extruders_colors[selection_idx])); ImGui::GetWindowDrawList()->AddRect(p, ImVec2(p.x + height + height / 2, p.y + height), IM_COL32_BLACK); ImGui::SetCursorScreenPos(ImVec2(p.x + height + height / 2 + style.FramePadding.x, p.y)); @@ -286,11 +273,11 @@ void GLGizmoMmuSegmentation::show_tooltip_information(float caption_max, float x caption_max += m_imgui->calc_text_size(std::string_view{": "}).x + 15.f; - float scale = m_parent.get_scale(); - #ifdef WIN32 - int dpi = get_dpi_for_window(wxGetApp().GetTopWindow()); - scale *= (float) dpi / (float) DPI_DEFAULT; - #endif // WIN32 + float scale = m_parent.get_scale(); +#ifdef WIN32 + int dpi = get_dpi_for_window(wxGetApp().GetTopWindow()); + scale *= (float) dpi / (float) DPI_DEFAULT; +#endif // WIN32 ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, 0}); // ORCA: Dont add padding @@ -298,7 +285,7 @@ void GLGizmoMmuSegmentation::show_tooltip_information(float caption_max, float x if (ImGui::IsItemHovered()) { ImGui::BeginTooltip2(ImVec2(x, y)); - auto draw_text_with_caption = [this, &caption_max](const wxString &caption, const wxString &text) { + auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { m_imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption); ImGui::SameLine(caption_max); m_imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text); @@ -306,22 +293,16 @@ void GLGizmoMmuSegmentation::show_tooltip_information(float caption_max, float x std::vector tip_items; switch (m_tool_type) { - case ToolType::BRUSH: - tip_items = {"paint", "erase", "cursor_size", "clipping_of_view", "toggle_wireframe"}; - break; - case ToolType::BUCKET_FILL: - tip_items = {"paint", "erase", "smart_fill_angle", "clipping_of_view", "toggle_wireframe"}; - break; - case ToolType::SMART_FILL: - // TODO: - break; - case ToolType::GAP_FILL: - tip_items = {"gap_area", "toggle_wireframe"}; - break; - default: - break; + case ToolType::BRUSH: tip_items = {"paint", "erase", "cursor_size", "clipping_of_view", "toggle_wireframe"}; break; + case ToolType::BUCKET_FILL: tip_items = {"paint", "erase", "smart_fill_angle", "clipping_of_view", "toggle_wireframe"}; break; + case ToolType::SMART_FILL: + // TODO: + break; + case ToolType::GAP_FILL: tip_items = {"gap_area", "toggle_wireframe"}; break; + default: break; } - for (const auto &t : tip_items) draw_text_with_caption(m_desc.at(t + "_caption") + ": ", m_desc.at(t)); + for (const auto& t : tip_items) + draw_text_with_caption(m_desc.at(t + "_caption") + ": ", m_desc.at(t)); ImGui::EndTooltip(); } ImGui::PopStyleVar(2); @@ -329,84 +310,92 @@ void GLGizmoMmuSegmentation::show_tooltip_information(float caption_max, float x void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bottom_limit) { - if (!m_c->selection_info()->model_object()) return; + if (!m_c->selection_info()->model_object()) + return; const float approx_height = m_imgui->scaled(22.0f); - y = std::min(y, bottom_limit - approx_height); + y = std::min(y, bottom_limit - approx_height); GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always); wchar_t old_tool = m_current_tool; // BBS ImGuiWrapper::push_toolbar_style(m_parent.get_scale()); - GizmoImguiBegin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar); + GizmoImguiBegin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | + ImGuiWindowFlags_NoTitleBar); // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: - const float space_size = m_imgui->get_style_scaling() * 8; - const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.5f), - m_imgui->calc_text_size(m_desc.at("reset_direction")).x + m_imgui->scaled(1.5f) + ImGui::GetStyle().FramePadding.x * 2); - const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.5f); - const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.5f); - const float edge_detect_slider_left = m_imgui->calc_text_size(m_desc.at("edge_detection")).x + m_imgui->scaled(1.f); - const float gap_area_slider_left = m_imgui->calc_text_size(m_desc.at("gap_area")).x + m_imgui->scaled(1.5f) + space_size; + const float space_size = m_imgui->get_style_scaling() * 8; + const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.5f), + m_imgui->calc_text_size(m_desc.at("reset_direction")).x + m_imgui->scaled(1.5f) + + ImGui::GetStyle().FramePadding.x * 2); + const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.5f); + const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.5f); + const float edge_detect_slider_left = m_imgui->calc_text_size(m_desc.at("edge_detection")).x + m_imgui->scaled(1.f); + const float gap_area_slider_left = m_imgui->calc_text_size(m_desc.at("gap_area")).x + m_imgui->scaled(1.5f) + space_size; const float height_range_slider_left = m_imgui->calc_text_size(m_desc.at("height_range")).x + m_imgui->scaled(2.f); - const float remove_btn_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); - const float filter_btn_width = m_imgui->calc_text_size(m_desc.at("perform")).x + m_imgui->scaled(1.f); - const float remap_btn_width = m_imgui->calc_text_size(m_desc.at("perform_remap")).x + m_imgui->scaled(1.f); - const float buttons_width = remove_btn_width + filter_btn_width + remap_btn_width + m_imgui->scaled(2.f); + const float remove_btn_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); + const float filter_btn_width = m_imgui->calc_text_size(m_desc.at("perform")).x + m_imgui->scaled(1.f); + const float remap_btn_width = m_imgui->calc_text_size(m_desc.at("perform_remap")).x + m_imgui->scaled(1.f); + const float buttons_width = remove_btn_width + filter_btn_width + remap_btn_width + m_imgui->scaled(2.f); const float minimal_slider_width = m_imgui->scaled(4.f); - const float color_button_width = m_imgui->calc_text_size(std::string_view{""}).x + m_imgui->scaled(1.75f); + const float color_button_width = m_imgui->calc_text_size(std::string_view{""}).x + m_imgui->scaled(1.75f); - float caption_max = 0.f; + float caption_max = 0.f; float total_text_max = 0.f; - for (const auto &t : std::array{"paint", "erase", "cursor_size", "smart_fill_angle", "height_range", "clipping_of_view"}) { - caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); + for (const auto& t : + std::array{"paint", "erase", "cursor_size", "smart_fill_angle", "height_range", "clipping_of_view"}) { + caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); } total_text_max += caption_max + m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f); - const float circle_max_width = std::max(clipping_slider_left,cursor_slider_left); - const float height_max_width = std::max(clipping_slider_left,height_range_slider_left); + const float circle_max_width = std::max(clipping_slider_left, cursor_slider_left); + const float height_max_width = std::max(clipping_slider_left, height_range_slider_left); const float sliders_left_width = std::max(smart_fill_slider_left, - std::max(cursor_slider_left, std::max(edge_detect_slider_left, std::max(gap_area_slider_left, std::max(height_range_slider_left, - clipping_slider_left))))) + space_size; - const float slider_icon_width = m_imgui->get_slider_icon_size().x; - float window_width = minimal_slider_width + sliders_left_width + slider_icon_width; - const int max_filament_items_per_line = 8; - const float empty_button_width = m_imgui->calc_button_size("").x; - const float filament_item_width = empty_button_width + m_imgui->scaled(1.5f); + std::max(cursor_slider_left, + std::max(edge_detect_slider_left, + std::max(gap_area_slider_left, + std::max(height_range_slider_left, clipping_slider_left))))) + + space_size; + const float slider_icon_width = m_imgui->get_slider_icon_size().x; + float window_width = minimal_slider_width + sliders_left_width + slider_icon_width; + const int max_filament_items_per_line = 8; + const float empty_button_width = m_imgui->calc_button_size("").x; + const float filament_item_width = empty_button_width + m_imgui->scaled(1.5f); window_width = std::max(window_width, total_text_max); window_width = std::max(window_width, buttons_width); window_width = std::max(window_width, max_filament_items_per_line * filament_item_width + +m_imgui->scaled(0.5f)); - const float sliders_width = m_imgui->scaled(7.0f); + const float sliders_width = m_imgui->scaled(7.0f); const float drag_left_width = ImGui::GetStyle().WindowPadding.x + sliders_width - space_size; - const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; - ImDrawList * draw_list = ImGui::GetWindowDrawList(); - ImVec2 pos = ImGui::GetCursorScreenPos(); - static float color_button_high = 25.0; - draw_list->AddRectFilled({pos.x - 10.0f, pos.y - 7.0f}, {pos.x + window_width + ImGui::GetFrameHeight(), pos.y + color_button_high}, ImGui::GetColorU32(ImGuiCol_FrameBgActive, 1.0f), 5.0f); + const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + ImVec2 pos = ImGui::GetCursorScreenPos(); + static float color_button_high = 25.0; + draw_list->AddRectFilled({pos.x - 10.0f, pos.y - 7.0f}, {pos.x + window_width + ImGui::GetFrameHeight(), pos.y + color_button_high}, + ImGui::GetColorU32(ImGuiCol_FrameBgActive, 1.0f), 5.0f); float color_button = ImGui::GetCursorPos().y; m_imgui->text(m_desc.at("filaments")); - float start_pos_x = ImGui::GetCursorPos().x; - const ImVec2 max_label_size = ImGui::CalcTextSize("99", NULL, true); - const float item_spacing = m_imgui->scaled(0.8f); - size_t n_extruder_colors = std::min((size_t)EnforcerBlockerType::ExtruderMax, m_extruders_colors.size()); + float start_pos_x = ImGui::GetCursorPos().x; + const ImVec2 max_label_size = ImGui::CalcTextSize("99", NULL, true); + const float item_spacing = m_imgui->scaled(0.8f); + size_t n_extruder_colors = std::min((size_t) EnforcerBlockerType::ExtruderMax, m_extruders_colors.size()); for (int extruder_idx = 0; extruder_idx < n_extruder_colors; extruder_idx++) { - const ColorRGBA &extruder_color = m_extruders_colors[extruder_idx]; + const ColorRGBA& extruder_color = m_extruders_colors[extruder_idx]; ImVec4 color_vec = ImGuiWrapper::to_ImVec4(extruder_color); - std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx); - std::string item_text = std::to_string(extruder_idx + 1); - const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); + std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx); + std::string item_text = std::to_string(extruder_idx + 1); + const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); - const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f),0.f); + const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f), 0.f); float button_offset = start_pos_x; if (extruder_idx % max_filament_items_per_line != 0) { @@ -415,32 +404,37 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott } // draw filament background - ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; - if (m_selected_extruder_idx != extruder_idx) flags |= ImGuiColorEditFlags_NoBorder; - #ifdef __APPLE__ - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); // ORCA use orca color for selected filament border - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0); - bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); - #else - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); // ORCA use orca color for selected filament border - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0); - bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); - #endif + ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | + ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; + if (m_selected_extruder_idx != extruder_idx) + flags |= ImGuiColorEditFlags_NoBorder; +#ifdef __APPLE__ + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); // ORCA use orca color for selected filament border + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0); + bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(1); +#else + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); // ORCA use orca color for selected filament border + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0); + bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(1); +#endif color_button_high = ImGui::GetCursorPos().y - color_button - 2.0; - if (color_picked) { m_selected_extruder_idx = extruder_idx; } + if (color_picked) { + m_selected_extruder_idx = extruder_idx; + } - if (extruder_idx < 16 && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width); + if (extruder_idx < 16 && ImGui::IsItemHovered()) + m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width); // draw filament id float gray = 0.299 * extruder_color.r() + 0.587 * extruder_color.g() + 0.114 * extruder_color.b(); ImGui::SameLine(button_offset + (button_size.x - label_size.x) / 2.f); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {10.0,15.0}); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {10.0, 15.0}); if (gray * 255.f < 80.f) ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), "%s", item_text.c_str()); else @@ -448,38 +442,42 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::PopStyleVar(); } - //ImGui::NewLine(); + // ImGui::NewLine(); ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.1)); m_imgui->text(m_desc.at("tool_type")); std::array tool_ids; - tool_ids = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::TriangleButtonIcon, ImGui::HeightRangeIcon, ImGui::FillButtonIcon, ImGui::GapFillIcon }; + tool_ids = {ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::TriangleButtonIcon, + ImGui::HeightRangeIcon, ImGui::FillButtonIcon, ImGui::GapFillIcon}; std::array icons; if (m_is_dark_mode) - icons = { ImGui::CircleButtonDarkIcon, ImGui::SphereButtonDarkIcon, ImGui::TriangleButtonDarkIcon, ImGui::HeightRangeDarkIcon, ImGui::FillButtonDarkIcon, ImGui::GapFillDarkIcon }; + icons = {ImGui::CircleButtonDarkIcon, ImGui::SphereButtonDarkIcon, ImGui::TriangleButtonDarkIcon, + ImGui::HeightRangeDarkIcon, ImGui::FillButtonDarkIcon, ImGui::GapFillDarkIcon}; else - icons = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::TriangleButtonIcon, ImGui::HeightRangeIcon, ImGui::FillButtonIcon, ImGui::GapFillIcon }; - std::array tool_tips = { _L("Circle"), _L("Sphere"), _L("Triangle"), _L("Height Range"), _L("Fill"), _L("Gap Fill") }; + icons = {ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::TriangleButtonIcon, + ImGui::HeightRangeIcon, ImGui::FillButtonIcon, ImGui::GapFillIcon}; + std::array tool_tips = {_L("Circle"), _L("Sphere"), _L("Triangle"), _L("Height Range"), _L("Fill"), _L("Gap Fill")}; for (int i = 0; i < tool_ids.size(); i++) { std::string str_label = std::string(""); std::wstring btn_name = icons[i] + boost::nowide::widen(str_label); - if (i != 0) ImGui::SameLine((empty_button_width + m_imgui->scaled(1.75f)) * i + m_imgui->scaled(1.5f)); + if (i != 0) + ImGui::SameLine((empty_button_width + m_imgui->scaled(1.75f)) * i + m_imgui->scaled(1.5f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.f, 0.f, 0.f)); // ORCA Removes button background on dark mode - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f)); // ORCA Fixes icon rendered without colors while using Light theme + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.f, 0.f, 0.f)); // ORCA Removes button background on dark mode + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f)); // ORCA Fixes icon rendered without colors while using Light theme if (m_current_tool == tool_ids[i]) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.f, 0.59f, 0.53f, 0.30f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_Border, ImGuiWrapper::COL_ORCA); // ORCA use orca color for border on selected tool / brush + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, + ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.f, 0.59f, 0.53f, 0.30f)); // ORCA use orca color for selected tool / brush + ImGui::PushStyleColor(ImGuiCol_Border, ImGuiWrapper::COL_ORCA); // ORCA use orca color for border on selected tool / brush ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0); } bool btn_clicked = ImGui::Button(into_u8(btn_name).c_str()); - if (m_current_tool == tool_ids[i]) - { + if (m_current_tool == tool_ids[i]) { ImGui::PopStyleColor(4); ImGui::PopStyleVar(2); } @@ -488,7 +486,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (btn_clicked && m_current_tool != tool_ids[i]) { m_current_tool = tool_ids[i]; - for (auto &triangle_selector : m_triangle_selectors) { + for (auto& triangle_selector : m_triangle_selectors) { triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->request_update_render_data(); } @@ -508,7 +506,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (m_current_tool == ImGui::CircleButtonIcon) m_cursor_type = TriangleSelector::CursorType::CIRCLE; else - m_cursor_type = TriangleSelector::CursorType::SPHERE; + m_cursor_type = TriangleSelector::CursorType::SPHERE; m_tool_type = ToolType::BRUSH; ImGui::AlignTextToFramePadding(); @@ -524,12 +522,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (m_c->object_clipper()->get_position() == 0.f) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("clipping_of_view")); - } - else { + } else { if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this]() { - m_c->object_clipper()->set_position_by_ratio(-1., false); - }); + wxGetApp().CallAfter([this]() { m_c->object_clipper()->set_position_by_ratio(-1., false); }); } } @@ -541,7 +536,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::PushItemWidth(1.5 * slider_icon_width); bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); } + if (slider_clp_dist || b_clp_dist_input) { + m_c->object_clipper()->set_position_by_ratio(clp_dist, true); + } } else if (m_current_tool == ImGui::TriangleButtonIcon) { m_cursor_type = TriangleSelector::CursorType::POINTER; @@ -550,12 +547,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (m_c->object_clipper()->get_position() == 0.f) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("clipping_of_view")); - } - else { + } else { if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this]() { - m_c->object_clipper()->set_position_by_ratio(-1., false); - }); + wxGetApp().CallAfter([this]() { m_c->object_clipper()->set_position_by_ratio(-1., false); }); } } @@ -567,7 +561,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::PushItemWidth(1.5 * slider_icon_width); bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); } + if (slider_clp_dist || b_clp_dist_input) { + m_c->object_clipper()->set_position_by_ratio(clp_dist, true); + } } else if (m_current_tool == ImGui::FillButtonIcon) { m_cursor_type = TriangleSelector::CursorType::POINTER; @@ -577,12 +573,14 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (m_detect_geometry_edge) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc["smart_fill_angle"]); - std::string format_str = std::string("%.f") + I18N::translate_utf8("°", "Face angle threshold," - "placed after the number with no whitespace in between."); + std::string format_str = std::string("%.f") + I18N::translate_utf8("°", + "Face angle threshold," + "placed after the number with no whitespace in between."); ImGui::SameLine(sliders_left_width); ImGui::PushItemWidth(sliders_width); - if (m_imgui->bbl_slider_float_style("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data(), 1.0f, true)) - for (auto &triangle_selector : m_triangle_selectors) { + if (m_imgui->bbl_slider_float_style("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, + format_str.data(), 1.0f, true)) + for (auto& triangle_selector : m_triangle_selectors) { triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->request_update_render_data(); } @@ -597,12 +595,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (m_c->object_clipper()->get_position() == 0.f) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("clipping_of_view")); - } - else { + } else { if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this]() { - m_c->object_clipper()->set_position_by_ratio(-1., false); - }); + wxGetApp().CallAfter([this]() { m_c->object_clipper()->set_position_by_ratio(-1., false); }); } } @@ -614,7 +609,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::PushItemWidth(1.5 * slider_icon_width); bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true);} + if (slider_clp_dist || b_clp_dist_input) { + m_c->object_clipper()->set_position_by_ratio(clp_dist, true); + } } else if (m_current_tool == ImGui::HeightRangeIcon) { m_tool_type = ToolType::BRUSH; @@ -623,8 +620,11 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott m_imgui->text(m_desc["height_range"] + ":"); ImGui::SameLine(height_max_width); ImGui::PushItemWidth(sliders_width); - std::string format_str = std::string("%.2f") + I18N::translate_utf8("mm", "Height range," "Facet in [cursor z, cursor z + height] will be selected."); - m_imgui->bbl_slider_float_style("##cursor_height", &m_cursor_height, CursorHeightMin, CursorHeightMax, format_str.data(), 1.0f, true); + std::string format_str = std::string("%.2f") + I18N::translate_utf8("mm", + "Height range," + "Facet in [cursor z, cursor z + height] will be selected."); + m_imgui->bbl_slider_float_style("##cursor_height", &m_cursor_height, CursorHeightMin, CursorHeightMax, format_str.data(), 1.0f, + true); ImGui::SameLine(drag_left_width + height_max_width); ImGui::PushItemWidth(1.5 * slider_icon_width); ImGui::BBLDragFloat("##cursor_height_input", &m_cursor_height, 0.05f, 0.0f, 0.0f, "%.2f"); @@ -633,12 +633,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (m_c->object_clipper()->get_position() == 0.f) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("clipping_of_view")); - } - else { + } else { if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this]() { - m_c->object_clipper()->set_position_by_ratio(-1., false); - }); + wxGetApp().CallAfter([this]() { m_c->object_clipper()->set_position_by_ratio(-1., false); }); } } @@ -650,37 +647,40 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::PushItemWidth(1.5 * slider_icon_width); bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); } - } - else if (m_current_tool == ImGui::GapFillIcon) { - m_tool_type = ToolType::GAP_FILL; + if (slider_clp_dist || b_clp_dist_input) { + m_c->object_clipper()->set_position_by_ratio(clp_dist, true); + } + } else if (m_current_tool == ImGui::GapFillIcon) { + m_tool_type = ToolType::GAP_FILL; m_cursor_type = TriangleSelector::CursorType::POINTER; ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc["gap_area"] + ":"); ImGui::SameLine(gap_area_slider_left); ImGui::PushItemWidth(sliders_width); - std::string format_str = std::string("%.2f") + I18N::translate_utf8("", "Triangle patch area threshold,""triangle patch will be merged to neighbor if its area is less than threshold"); - m_imgui->bbl_slider_float_style("##gap_area", &TriangleSelectorPatch::gap_area, TriangleSelectorPatch::GapAreaMin, TriangleSelectorPatch::GapAreaMax, format_str.data(), 1.0f, true); + std::string format_str = std::string("%.2f") + + I18N::translate_utf8("", "Triangle patch area threshold," + "triangle patch will be merged to neighbor if its area is less than threshold"); + m_imgui->bbl_slider_float_style("##gap_area", &TriangleSelectorPatch::gap_area, TriangleSelectorPatch::GapAreaMin, + TriangleSelectorPatch::GapAreaMax, format_str.data(), 1.0f, true); ImGui::SameLine(drag_left_width + gap_area_slider_left); ImGui::PushItemWidth(1.5 * slider_icon_width); ImGui::BBLDragFloat("##gap_area_input", &TriangleSelectorPatch::gap_area, 0.05f, 0.0f, 0.0f, "%.2f"); } ImGui::Separator(); - if(m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only)){ - if(m_vertical_only){ + if (m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only)) { + if (m_vertical_only) { m_horizontal_only = false; } } - if(m_imgui->bbl_checkbox(_L("Horizontal"), m_horizontal_only)){ - if(m_horizontal_only){ + if (m_imgui->bbl_checkbox(_L("Horizontal"), m_horizontal_only)) { + if (m_horizontal_only) { m_vertical_only = false; } } ImGui::Separator(); - if (m_imgui->button(m_desc.at("perform_remap"))) { m_show_filament_remap_ui = !m_show_filament_remap_ui; if (m_show_filament_remap_ui) { @@ -690,7 +690,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott m_extruder_remap[i] = i; } } - + // Render filament swap UI if enabled if (m_show_filament_remap_ui) { ImGui::Separator(); @@ -702,7 +702,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y; show_tooltip_information(caption_max, x, get_cur_y); - float f_scale =m_parent.get_gizmos_manager().get_layout_scale(); + float f_scale = m_parent.get_gizmos_manager().get_layout_scale(); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale)); ImGui::SameLine(); @@ -725,9 +725,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (m_imgui->button(m_desc.at("remove_all"))) { Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Reset selection", UndoRedo::SnapshotType::GizmoAction); - ModelObject * mo = m_c->selection_info()->model_object(); + ModelObject* mo = m_c->selection_info()->model_object(); int idx = -1; - for (ModelVolume *mv : mo->volumes) + for (ModelVolume* mv : mo->volumes) if (mv->is_model_part()) { ++idx; m_triangle_selectors[idx]->reset(); @@ -744,22 +744,21 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGuiWrapper::pop_toolbar_style(); } - void GLGizmoMmuSegmentation::update_model_object() { - bool updated = false; - ModelObject* mo = m_c->selection_info()->model_object(); - int idx = -1; + bool updated = false; + ModelObject* mo = m_c->selection_info()->model_object(); + int idx = -1; for (ModelVolume* mv : mo->volumes) { - if (! mv->is_model_part()) + if (!mv->is_model_part()) continue; ++idx; updated |= mv->mmu_segmentation_facets.set(*m_triangle_selectors[idx].get()); } if (updated) { - const ModelObjectPtrs &mos = wxGetApp().model().objects; - size_t obj_idx = std::find(mos.begin(), mos.end(), mo) - mos.begin(); + const ModelObjectPtrs& mos = wxGetApp().model().objects; + size_t obj_idx = std::find(mos.begin(), mos.end(), mo) - mos.begin(); wxGetApp().obj_list()->update_info_items(obj_idx); wxGetApp().plater()->get_partplate_list().notify_instance_update(obj_idx, 0); m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); @@ -768,23 +767,23 @@ void GLGizmoMmuSegmentation::update_model_object() void GLGizmoMmuSegmentation::init_model_triangle_selectors() { - const ModelObject *mo = m_c->selection_info()->model_object(); + const ModelObject* mo = m_c->selection_info()->model_object(); m_triangle_selectors.clear(); m_volumes_extruder_idxs.clear(); // Don't continue when extruders colors are not initialized - if(m_extruders_colors.empty()) + if (m_extruders_colors.empty()) return; // BBS: Don't continue when model object is null if (mo == nullptr) return; - for (const ModelVolume *mv : mo->volumes) { + for (const ModelVolume* mv : mo->volumes) { if (!mv->is_model_part()) continue; - int extruder_idx = (mv->extruder_id() > 0) ? mv->extruder_id() - 1 : 0; + int extruder_idx = (mv->extruder_id() > 0) ? mv->extruder_id() - 1 : 0; std::vector ebt_colors; ebt_colors.push_back(m_extruders_colors[size_t(extruder_idx)]); ebt_colors.insert(ebt_colors.end(), m_extruders_colors.begin(), m_extruders_colors.end()); @@ -793,7 +792,7 @@ void GLGizmoMmuSegmentation::init_model_triangle_selectors() const TriangleMesh* mesh = &mv->mesh(); m_triangle_selectors.emplace_back(std::make_unique(*mesh, ebt_colors, 0.2)); // Reset of TriangleSelector is done inside TriangleSelectorMmGUI's constructor, so we don't need it to perform it again in deserialize(). - EnforcerBlockerType max_ebt = (EnforcerBlockerType)std::min(m_extruders_colors.size(), (size_t)EnforcerBlockerType::ExtruderMax); + EnforcerBlockerType max_ebt = (EnforcerBlockerType) std::min(m_extruders_colors.size(), (size_t) EnforcerBlockerType::ExtruderMax); m_triangle_selectors.back()->deserialize(mv->mmu_segmentation_facets.get_data(), false, max_ebt); m_triangle_selectors.back()->request_update_render_data(); m_triangle_selectors.back()->set_wireframe_needed(true); @@ -804,9 +803,9 @@ void GLGizmoMmuSegmentation::init_model_triangle_selectors() void GLGizmoMmuSegmentation::update_triangle_selectors_colors() { for (int i = 0; i < m_triangle_selectors.size(); i++) { - TriangleSelectorPatch* selector = dynamic_cast(m_triangle_selectors[i].get()); - int extruder_idx = m_volumes_extruder_idxs[i]; - int extruder_color_idx = std::max(0, extruder_idx - 1); + TriangleSelectorPatch* selector = dynamic_cast(m_triangle_selectors[i].get()); + int extruder_idx = m_volumes_extruder_idxs[i]; + int extruder_color_idx = std::max(0, extruder_idx - 1); std::vector ebt_colors; ebt_colors.push_back(m_extruders_colors[extruder_color_idx]); ebt_colors.insert(ebt_colors.end(), m_extruders_colors.begin(), m_extruders_colors.end()); @@ -839,10 +838,7 @@ void GLGizmoMmuSegmentation::tool_changed(wchar_t old_tool, wchar_t new_tool) } } -PainterGizmoType GLGizmoMmuSegmentation::get_painter_type() const -{ - return PainterGizmoType::MM_SEGMENTATION; -} +PainterGizmoType GLGizmoMmuSegmentation::get_painter_type() const { return PainterGizmoType::MM_SEGMENTATION; } // BBS ColorRGBA GLGizmoMmuSegmentation::get_cursor_hover_color() const @@ -859,9 +855,10 @@ void GLGizmoMmuSegmentation::on_set_state() if (get_state() == Off) { ModelObject* mo = m_c->selection_info()->model_object(); - if (mo) Slic3r::save_object_mesh(*mo); + if (mo) + Slic3r::save_object_mesh(*mo); m_parent.post_event(SimpleEvent(EVT_GLCANVAS_FORCE_UPDATE)); - if (m_current_tool == ImGui::GapFillIcon) {//exit gap fill + if (m_current_tool == ImGui::GapFillIcon) { // exit gap fill m_current_tool = ImGui::CircleButtonIcon; } } @@ -873,17 +870,18 @@ wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GL if (shift_down) action_name = _L("Remove painted color"); else { - action_name = GUI::format(_L("Painted using: Filament %1%"), m_selected_extruder_idx); + action_name = GUI::format(_L("Painted using: Filament %1%"), filament_index_from_zero_based(m_selected_extruder_idx)); } return action_name; } -void GLMmSegmentationGizmo3DScene::release_geometry() { +void GLMmSegmentationGizmo3DScene::release_geometry() +{ if (this->vertices_VBO_id) { glsafe(::glDeleteBuffers(1, &this->vertices_VBO_id)); this->vertices_VBO_id = 0; } - for(auto &triangle_indices_VBO_id : triangle_indices_VBO_ids) { + for (auto& triangle_indices_VBO_id : triangle_indices_VBO_ids) { glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id)); triangle_indices_VBO_id = 0; } @@ -930,13 +928,12 @@ void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_VBO_id)); const GLint position_id = shader->get_attrib_location("v_position"); if (position_id != -1) { - glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (GLvoid*)0)); + glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (GLvoid*) 0)); glsafe(::glEnableVertexAttribArray(position_id)); } // Render using the Vertex Buffer Objects. - if (this->triangle_indices_VBO_ids[triangle_indices_idx] != 0 && - this->triangle_indices_sizes[triangle_indices_idx] > 0) { + if (this->triangle_indices_VBO_ids[triangle_indices_idx] != 0 && this->triangle_indices_sizes[triangle_indices_idx] > 0) { glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_ids[triangle_indices_idx])); glsafe(::glDrawElements(GL_TRIANGLES, GLsizei(this->triangle_indices_sizes[triangle_indices_idx]), GL_UNSIGNED_INT, nullptr)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); @@ -995,7 +992,8 @@ void GLMmSegmentationGizmo3DScene::finalize_triangle_indices() { triangle_indices_VBO_ids.resize(this->triangle_patches.size()); triangle_indices_sizes.resize(this->triangle_patches.size()); - assert(std::all_of(triangle_indices_VBO_ids.cbegin(), triangle_indices_VBO_ids.cend(), [](const auto &ti_VBO_id) { return ti_VBO_id == 0; })); + assert(std::all_of(triangle_indices_VBO_ids.cbegin(), triangle_indices_VBO_ids.cend(), + [](const auto& ti_VBO_id) { return ti_VBO_id == 0; })); for (size_t buffer_idx = 0; buffer_idx < this->triangle_patches.size(); ++buffer_idx) { std::vector& triangle_indices = this->triangle_patches[buffer_idx].triangle_indices; @@ -1012,125 +1010,123 @@ void GLMmSegmentationGizmo3DScene::finalize_triangle_indices() void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float max_tooltip_width) { - size_t n_extr = std::min((size_t)EnforcerBlockerType::ExtruderMax, m_extruders_colors.size()); + size_t n_extr = std::min((size_t) EnforcerBlockerType::ExtruderMax, m_extruders_colors.size()); const ImVec2 max_label_size = ImGui::CalcTextSize("99", NULL, true); const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f), 0.f); - for (int src = 0; src < (int)n_extr; ++src) { - const ColorRGBA &src_col = m_extruders_colors[src]; // keep for text contrast - const ColorRGBA &dst_col = m_extruders_colors[m_extruder_remap[src]]; - ImVec4 col_vec = ImGuiWrapper::to_ImVec4(dst_col); + for (int src = 0; src < (int) n_extr; ++src) { + const ColorRGBA& src_col = m_extruders_colors[src]; // keep for text contrast + const ColorRGBA& dst_col = m_extruders_colors[m_extruder_remap[src]]; + ImVec4 col_vec = ImGuiWrapper::to_ImVec4(dst_col); - if (src) ImGui::SameLine(); + if (src) + ImGui::SameLine(); std::string btn_id = "##remap_src_" + std::to_string(src); - - ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | - ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoPicker | - ImGuiColorEditFlags_NoTooltip; - if (m_selected_extruder_idx != src) flags |= ImGuiColorEditFlags_NoBorder; - - #ifdef __APPLE__ - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0); - bool clicked = ImGui::ColorButton(btn_id.c_str(), col_vec, flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); - #else - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0); - bool clicked = ImGui::ColorButton(btn_id.c_str(), col_vec, flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); - #endif + + ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | + ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; + if (m_selected_extruder_idx != src) + flags |= ImGuiColorEditFlags_NoBorder; + +#ifdef __APPLE__ + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0); + bool clicked = ImGui::ColorButton(btn_id.c_str(), col_vec, flags, button_size); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(1); +#else + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0); + bool clicked = ImGui::ColorButton(btn_id.c_str(), col_vec, flags, button_size); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(1); +#endif // overlay destination number with proper contrast calculation std::string dst_txt = std::to_string(m_extruder_remap[src] + 1); - float gray = 0.299f * dst_col.r() + 0.587f * dst_col.g() + 0.114f * dst_col.b(); - ImVec2 txt_sz = ImGui::CalcTextSize(dst_txt.c_str()); - ImVec2 pos = ImGui::GetItemRectMin(); - ImVec2 size = ImGui::GetItemRectSize(); - + float gray = 0.299f * dst_col.r() + 0.587f * dst_col.g() + 0.114f * dst_col.b(); + ImVec2 txt_sz = ImGui::CalcTextSize(dst_txt.c_str()); + ImVec2 pos = ImGui::GetItemRectMin(); + ImVec2 size = ImGui::GetItemRectSize(); + if (gray * 255.f < 80.f) - ImGui::GetWindowDrawList()->AddText( - ImVec2(pos.x + (size.x - txt_sz.x) * 0.5f, pos.y + (size.y - txt_sz.y) * 0.5f), - IM_COL32(255,255,255,255), dst_txt.c_str()); + ImGui::GetWindowDrawList()->AddText(ImVec2(pos.x + (size.x - txt_sz.x) * 0.5f, pos.y + (size.y - txt_sz.y) * 0.5f), + IM_COL32(255, 255, 255, 255), dst_txt.c_str()); else - ImGui::GetWindowDrawList()->AddText( - ImVec2(pos.x + (size.x - txt_sz.x) * 0.5f, pos.y + (size.y - txt_sz.y) * 0.5f), - IM_COL32(0,0,0,255), dst_txt.c_str()); + ImGui::GetWindowDrawList()->AddText(ImVec2(pos.x + (size.x - txt_sz.x) * 0.5f, pos.y + (size.y - txt_sz.y) * 0.5f), + IM_COL32(0, 0, 0, 255), dst_txt.c_str()); // popup with possible destinations std::string pop_id = "popup_" + std::to_string(src); if (clicked) { // Calculate popup position centered below the current button - ImVec2 button_pos = ImGui::GetItemRectMin(); + ImVec2 button_pos = ImGui::GetItemRectMin(); ImVec2 button_size = ImGui::GetItemRectSize(); ImVec2 popup_pos(button_pos.x + button_size.x * 0.5f, button_pos.y + button_size.y); - + // Set popup styling BEFORE opening popup ImGui::SetNextWindowPos(popup_pos, ImGuiCond_Appearing, ImVec2(0.5f, -0.1f)); ImGui::SetNextWindowBgAlpha(1.0f); // Ensure full opacity ImGui::OpenPopup(pop_id.c_str()); } - + // Apply popup styling before BeginPopup using standard Orca colors ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding, 4.0f); ImGui::PushStyleVar(ImGuiStyleVar_PopupBorderSize, 1.0f); ImGui::PushStyleColor(ImGuiCol_PopupBg, m_is_dark_mode ? ImGuiWrapper::COL_WINDOW_BG_DARK : ImGuiWrapper::COL_WINDOW_BG); ImGui::PushStyleColor(ImGuiCol_Border, m_is_dark_mode ? ImVec4(0.5f, 0.5f, 0.5f, 1.0f) : ImVec4(0.6f, 0.6f, 0.6f, 1.0f)); - + if (ImGui::BeginPopup(pop_id.c_str())) { - - for (int dst = 0; dst < (int)n_extr; ++dst) { - const ColorRGBA &dst_col_popup = m_extruders_colors[dst]; - ImVec4 dst_vec = ImGuiWrapper::to_ImVec4(dst_col_popup); - if (dst) ImGui::SameLine(); + for (int dst = 0; dst < (int) n_extr; ++dst) { + const ColorRGBA& dst_col_popup = m_extruders_colors[dst]; + ImVec4 dst_vec = ImGuiWrapper::to_ImVec4(dst_col_popup); + if (dst) + ImGui::SameLine(); std::string dst_btn = "##dst_" + std::to_string(src) + "_" + std::to_string(dst); - + // Apply same styling to destination buttons - ImGuiColorEditFlags dst_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | - ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoPicker | - ImGuiColorEditFlags_NoTooltip; + ImGuiColorEditFlags dst_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | + ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; // Show border for currently selected destination filament - if (m_extruder_remap[src] != dst) dst_flags |= ImGuiColorEditFlags_NoBorder; - - #ifdef __APPLE__ - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0); - bool dst_clicked = ImGui::ColorButton(dst_btn.c_str(), dst_vec, dst_flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); - #else - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0); - bool dst_clicked = ImGui::ColorButton(dst_btn.c_str(), dst_vec, dst_flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); - #endif - + if (m_extruder_remap[src] != dst) + dst_flags |= ImGuiColorEditFlags_NoBorder; + +#ifdef __APPLE__ + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0); + bool dst_clicked = ImGui::ColorButton(dst_btn.c_str(), dst_vec, dst_flags, button_size); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(1); +#else + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0); + bool dst_clicked = ImGui::ColorButton(dst_btn.c_str(), dst_vec, dst_flags, button_size); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(1); +#endif + // overlay destination number on popup buttons std::string dst_num_txt = std::to_string(dst + 1); - float dst_gray = 0.299f * dst_col_popup.r() + 0.587f * dst_col_popup.g() + 0.114f * dst_col_popup.b(); - ImVec2 dst_txt_sz = ImGui::CalcTextSize(dst_num_txt.c_str()); - ImVec2 dst_pos = ImGui::GetItemRectMin(); - ImVec2 dst_size = ImGui::GetItemRectSize(); - + float dst_gray = 0.299f * dst_col_popup.r() + 0.587f * dst_col_popup.g() + 0.114f * dst_col_popup.b(); + ImVec2 dst_txt_sz = ImGui::CalcTextSize(dst_num_txt.c_str()); + ImVec2 dst_pos = ImGui::GetItemRectMin(); + ImVec2 dst_size = ImGui::GetItemRectSize(); + if (dst_gray * 255.f < 80.f) - ImGui::GetWindowDrawList()->AddText( - ImVec2(dst_pos.x + (dst_size.x - dst_txt_sz.x) * 0.5f, dst_pos.y + (dst_size.y - dst_txt_sz.y) * 0.5f), - IM_COL32(255,255,255,255), dst_num_txt.c_str()); + ImGui::GetWindowDrawList()->AddText(ImVec2(dst_pos.x + (dst_size.x - dst_txt_sz.x) * 0.5f, + dst_pos.y + (dst_size.y - dst_txt_sz.y) * 0.5f), + IM_COL32(255, 255, 255, 255), dst_num_txt.c_str()); else - ImGui::GetWindowDrawList()->AddText( - ImVec2(dst_pos.x + (dst_size.x - dst_txt_sz.x) * 0.5f, dst_pos.y + (dst_size.y - dst_txt_sz.y) * 0.5f), - IM_COL32(0,0,0,255), dst_num_txt.c_str()); - - if (dst_clicked) - { + ImGui::GetWindowDrawList()->AddText(ImVec2(dst_pos.x + (dst_size.x - dst_txt_sz.x) * 0.5f, + dst_pos.y + (dst_size.y - dst_txt_sz.y) * 0.5f), + IM_COL32(0, 0, 0, 255), dst_num_txt.c_str()); + + if (dst_clicked) { m_extruder_remap[src] = dst; // update the source button color immediately ImGui::CloseCurrentPopup(); @@ -1138,7 +1134,7 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float } ImGui::EndPopup(); } - + // Clean up popup styling (always pop, whether popup was open or not) ImGui::PopStyleColor(2); // PopupBg and Border ImGui::PopStyleVar(2); // PopupRounding and PopupBorderSize @@ -1161,54 +1157,54 @@ void GLGizmoMmuSegmentation::remap_filament_assignments() if (m_extruder_remap.empty()) return; - constexpr size_t MAX_EBT = (size_t)EnforcerBlockerType::ExtruderMax; + constexpr size_t MAX_EBT = (size_t) EnforcerBlockerType::ExtruderMax; EnforcerBlockerStateMap state_map; // identity mapping by default for (size_t i = 0; i <= MAX_EBT; ++i) state_map[i] = static_cast(i); - size_t n_extr = std::min(m_extruder_remap.size(), MAX_EBT); + size_t n_extr = std::min(m_extruder_remap.size(), MAX_EBT); const int start_extruder = (int) EnforcerBlockerType::Extruder1; - bool any_change = false; + bool any_change = false; for (size_t src = 0; src < n_extr; ++src) { size_t dst = m_extruder_remap[src]; if (dst != src) { - state_map[src+start_extruder] = static_cast(dst+start_extruder); + state_map[src + start_extruder] = static_cast(dst + start_extruder); if (src == 0) state_map[0] = static_cast(dst + start_extruder); - any_change = true; + any_change = true; } } if (!any_change) return; - Plater::TakeSnapshot snapshot(wxGetApp().plater(), - "Remap filament assignments", - UndoRedo::SnapshotType::GizmoAction); + Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Remap filament assignments", UndoRedo::SnapshotType::GizmoAction); - bool updated = false; - int idx = -1; - ModelObject* mo = m_c->selection_info()->model_object(); - if (!mo) return; + bool updated = false; + int idx = -1; + ModelObject* mo = m_c->selection_info()->model_object(); + if (!mo) + return; for (ModelVolume* mv : mo->volumes) { - if (!mv->is_model_part()) continue; + if (!mv->is_model_part()) + continue; ++idx; TriangleSelectorGUI* ts = m_triangle_selectors[idx].get(); - if (!ts) continue; + if (!ts) + continue; ts->remap_triangle_state(state_map); ts->request_update_render_data(true); updated = true; } if (updated) { - wxGetApp().plater()->get_notification_manager()->push_notification( - _L("Filament remapping finished.").ToStdString()); + wxGetApp().plater()->get_notification_manager()->push_notification(_L("Filament remapping finished.").ToStdString()); update_model_object(); m_parent.set_as_dirty(); } } -} // namespace Slic3r +} // namespace Slic3r::GUI From 1a3459d9d5e4db99b801d37f1afcdc430f451540 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 02:03:08 -0500 Subject: [PATCH 08/57] Honor filament index base in UI --- src/slic3r/GUI/GUI.cpp | 679 ++++---- src/slic3r/GUI/GUI.hpp | 46 +- src/slic3r/GUI/GUI_Factories.cpp | 1430 ++++++++--------- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 684 ++++---- 4 files changed, 1416 insertions(+), 1423 deletions(-) diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 90b7c46488..5e1e0c557b 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -42,64 +42,64 @@ IOPMAssertionID assertionID; void disable_screensaver() { -#if __APPLE__ - CFStringRef reasonForActivity = CFSTR("Slic3r"); - [[maybe_unused]] IOReturn success = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, - reasonForActivity, &assertionID); -// ignore result: success == kIOReturnSuccess -#elif _WIN32 + #if __APPLE__ + CFStringRef reasonForActivity = CFSTR("Slic3r"); + [[maybe_unused]]IOReturn success = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, + kIOPMAssertionLevelOn, reasonForActivity, &assertionID); + // ignore result: success == kIOReturnSuccess + #elif _WIN32 SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_CONTINUOUS); -#endif + #endif } void enable_screensaver() { -#if __APPLE__ + #if __APPLE__ IOPMAssertionRelease(assertionID); -#elif _WIN32 + #elif _WIN32 SetThreadExecutionState(ES_CONTINUOUS); -#endif + #endif } bool debugged() { -#ifdef _WIN32 + #ifdef _WIN32 return IsDebuggerPresent() == TRUE; -#else - return false; -#endif /* _WIN32 */ + #else + return false; + #endif /* _WIN32 */ } void break_to_debugger() { -#ifdef _WIN32 + #ifdef _WIN32 if (IsDebuggerPresent()) DebugBreak(); -#endif /* _WIN32 */ + #endif /* _WIN32 */ } const std::string& shortkey_ctrl_prefix() { - static const std::string str = + static const std::string str = #ifdef __APPLE__ - u8"\u2318+" // "⌘+" (Mac Command+) + u8"\u2318+" // "⌘+" (Mac Command+) #else - _u8L("Ctrl+") + _u8L("Ctrl+") #endif - ; - return str; + ; + return str; } const std::string& shortkey_alt_prefix() { - static const std::string str = + static const std::string str = #ifdef __APPLE__ - u8"\u2325+" // "⌥+" (Mac Option+) + u8"\u2325+" // "⌥+" (Mac Option+) #else - _u8L("Alt+") + _u8L("Alt+") #endif - ; - return str; + ; + return str; } bool start_filament_index_at_1() @@ -109,21 +109,28 @@ bool start_filament_index_at_1() return false; const auto& config = preset_bundle->printers.get_edited_preset().config; - const auto* opt = config.option("start_filament_index_at_1"); + const auto* opt = config.option("start_filament_index_at_1"); return opt != nullptr && opt->value; } -int filament_index_from_zero_based(int index) { return index + (start_filament_index_at_1() ? 1 : 0); } +int filament_index_from_zero_based(int index) +{ + return index + (start_filament_index_at_1() ? 1 : 0); +} -int filament_index_from_one_based(int index) { return start_filament_index_at_1() ? index : index - 1; } +int filament_index_from_one_based(int index) +{ + return start_filament_index_at_1() ? index : index - 1; +} // opt_index = 0, by the reason of zero-index in ConfigOptionVector by default (in case only one element) void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index /*= 0*/) { - try { + try{ + if (config.def()->get(opt_key)->type == coBools && config.def()->get(opt_key)->nullable) { - const auto v = boost::any_cast(value); - auto vec_new = std::make_unique(1, v); + const auto v = boost::any_cast(value); + auto vec_new = std::make_unique(1, v); if (v == ConfigOptionBoolsNullable::nil_value()) { vec_new->set_at_to_nil(0); } @@ -132,109 +139,125 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt return; } - const ConfigOptionDef* opt_def = config.def()->get(opt_key); - switch (opt_def->type) { - case coFloatOrPercent: { - std::string str = boost::any_cast(value); - bool percent = false; - if (str.back() == '%') { - str.pop_back(); - percent = true; - } + const ConfigOptionDef *opt_def = config.def()->get(opt_key); + switch (opt_def->type) { + case coFloatOrPercent:{ + std::string str = boost::any_cast(value); + bool percent = false; + if (str.back() == '%') { + str.pop_back(); + percent = true; + } + double val = std::stod(str); // locale-dependent (on purpose - the input is the actual content of the field) + config.set_key_value(opt_key, new ConfigOptionFloatOrPercent(val, percent)); + break;} + case coFloatsOrPercents:{ + std::string str = boost::any_cast(value); + bool percent = false; + if (str.back() == '%') { + str.pop_back(); + percent = true; + } double val = std::stod(str); // locale-dependent (on purpose - the input is the actual content of the field) - config.set_key_value(opt_key, new ConfigOptionFloatOrPercent(val, percent)); - break; - } - case coFloatsOrPercents: { - std::string str = boost::any_cast(value); - bool percent = false; - if (str.back() == '%') { - str.pop_back(); - percent = true; - } - double val = std::stod(str); // locale-dependent (on purpose - the input is the actual content of the field) auto vec_new = std::make_unique(val, percent); config.option(opt_key)->set_at(vec_new.get(), opt_index, opt_index); - break; - } - case coPercent: config.set_key_value(opt_key, new ConfigOptionPercent(boost::any_cast(value))); break; - case coFloat: { - double& val = config.opt_float(opt_key); - val = boost::any_cast(value); - break; - } - case coPercents: { - auto vec_new = std::make_unique(boost::any_cast(value)); - config.option(opt_key)->set_at(vec_new.get(), opt_index, opt_index); - break; - } - case coFloats: { + break;} + case coPercent: + config.set_key_value(opt_key, new ConfigOptionPercent(boost::any_cast(value))); + break; + case coFloat:{ + double& val = config.opt_float(opt_key); + val = boost::any_cast(value); + break; + } + case coPercents:{ + auto vec_new = std::make_unique (boost::any_cast(value)); + config.option(opt_key)->set_at(vec_new.get(), opt_index, opt_index); + break; + } + case coFloats:{ auto vec_new = std::make_unique(boost::any_cast(value)); - config.option(opt_key)->set_at(vec_new.get(), opt_index, opt_index); - break; - } - case coString: config.set_key_value(opt_key, new ConfigOptionString(boost::any_cast(value))); break; - case coStrings: { - if (opt_key == "compatible_prints" || opt_key == "compatible_printers") { - config.option(opt_key)->values = boost::any_cast>(value); - } else if (config.def()->get(opt_key)->gui_flags.compare("serialized") == 0) { - std::string str = boost::any_cast(value); - std::vector values{}; + config.option(opt_key)->set_at(vec_new.get(), opt_index, opt_index); + break; + } + case coString: + config.set_key_value(opt_key, new ConfigOptionString(boost::any_cast(value))); + break; + case coStrings:{ + if (opt_key == "compatible_prints" || opt_key == "compatible_printers") { + config.option(opt_key)->values = + boost::any_cast>(value); + } + else if (config.def()->get(opt_key)->gui_flags.compare("serialized") == 0) { + std::string str = boost::any_cast(value); + std::vector values {}; if (!str.empty()) { - if (str.back() == ';') - str.pop_back(); - // Split a string to multiple strings by a semi - colon.This is the old way of storing multi - string values. - // Currently used for the post_process config value only. - boost::split(values, str, boost::is_any_of(";")); - if (values.size() == 1 && values[0] == "") - values.resize(0); + if (str.back() == ';') str.pop_back(); + // Split a string to multiple strings by a semi - colon.This is the old way of storing multi - string values. + // Currently used for the post_process config value only. + boost::split(values, str, boost::is_any_of(";")); + if (values.size() == 1 && values[0] == "") + values.resize(0); } - config.option(opt_key)->values = values; - } else { + config.option(opt_key)->values = values; + } + else{ auto vec_new = std::make_unique(boost::any_cast(value)); - config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); - } - } break; - case coBool: config.set_key_value(opt_key, new ConfigOptionBool(boost::any_cast(value))); break; - case coBools: { + config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); + } + } + break; + case coBool: + config.set_key_value(opt_key, new ConfigOptionBool(boost::any_cast(value))); + break; + case coBools:{ auto vec_new = std::make_unique(boost::any_cast(value) != 0); - config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); - break; - } - case coInt: config.set_key_value(opt_key, new ConfigOptionInt(boost::any_cast(value))); break; - case coInts: { + config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); + break;} + case coInt: + config.set_key_value(opt_key, new ConfigOptionInt(boost::any_cast(value))); + break; + case coInts:{ auto vec_new = std::make_unique(boost::any_cast(value)); - config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); - } break; - case coEnum: { - auto* opt = opt_def->default_value.get()->clone(); - opt->setInt(boost::any_cast(value)); - config.set_key_value(opt_key, opt); - } break; - // BBS - case coEnums: { + config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); + } + break; + case coEnum:{ + auto *opt = opt_def->default_value.get()->clone(); + opt->setInt(boost::any_cast(value)); + config.set_key_value(opt_key, opt); + } + break; + // BBS + case coEnums:{ auto vec_new = std::make_unique(std::vector{boost::any_cast(value)}); - if (config.has(opt_key)) - config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); - } break; - case coPoint: { - config.set_key_value(opt_key, new ConfigOptionPoint(boost::any_cast(value))); - } break; - case coPoints: { - if (opt_key == "printable_area" || opt_key == "bed_exclude_area" || opt_key == "thumbnails" || - opt_key == "wrapping_exclude_area") { - config.option(opt_key)->values = boost::any_cast>(value); - break; - } + if (config.has(opt_key)) + config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); + } + break; + case coPoint:{ + config.set_key_value(opt_key, new ConfigOptionPoint(boost::any_cast(value))); + } + break; + case coPoints:{ + if (opt_key == "printable_area" || opt_key == "bed_exclude_area" || opt_key == "thumbnails" || opt_key == "wrapping_exclude_area" ) { + config.option(opt_key)->values = boost::any_cast>(value); + break; + } auto vec_new = std::make_unique(boost::any_cast(value)); - config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); - } break; - case coNone: break; - default: break; - } - } catch (const std::exception& e) { - wxLogError(format_wxstr("Internal error when changing value for %1%: %2%", opt_key, e.what())); - } + config.option(opt_key)->set_at(vec_new.get(), opt_index, 0); + } + break; + case coNone: + break; + default: + break; + } + } + catch (const std::exception &e) + { + wxLogError(format_wxstr("Internal error when changing value for %1%: %2%", opt_key, e.what())); + } } void show_error(wxWindow* parent, const wxString& message, bool monospaced_font) @@ -247,151 +270,166 @@ void show_error(wxWindow* parent, const wxString& message, bool monospaced_font) void show_error(wxWindow* parent, const char* message, bool monospaced_font) { - assert(message); - show_error(parent, wxString::FromUTF8(message), monospaced_font); + assert(message); + show_error(parent, wxString::FromUTF8(message), monospaced_font); } void show_error_id(int id, const std::string& message) { - auto* parent = id != 0 ? wxWindow::FindWindowById(id) : nullptr; - show_error(parent, message); + auto *parent = id != 0 ? wxWindow::FindWindowById(id) : nullptr; + show_error(parent, message); } void show_info(wxWindow* parent, const wxString& message, const wxString& title) { - // wxMessageDialog msg_wingow(parent, message, wxString(SLIC3R_APP_NAME " - ") + (title.empty() ? _L("Notice") : title), wxOK | - // wxICON_INFORMATION); - MessageDialog msg_wingow(parent, message, wxString(SLIC3R_APP_FULL_NAME " - ") + (title.empty() ? _L("Notice") : title), - wxOK | wxICON_INFORMATION); - msg_wingow.ShowModal(); + //wxMessageDialog msg_wingow(parent, message, wxString(SLIC3R_APP_NAME " - ") + (title.empty() ? _L("Notice") : title), wxOK | wxICON_INFORMATION); + MessageDialog msg_wingow(parent, message, wxString(SLIC3R_APP_FULL_NAME " - ") + (title.empty() ? _L("Notice") : title), wxOK | wxICON_INFORMATION); + msg_wingow.ShowModal(); } void show_info(wxWindow* parent, const char* message, const char* title) { - assert(message); - show_info(parent, wxString::FromUTF8(message), title ? wxString::FromUTF8(title) : wxString()); + assert(message); + show_info(parent, wxString::FromUTF8(message), title ? wxString::FromUTF8(title) : wxString()); } void warning_catcher(wxWindow* parent, const wxString& message) { - MessageDialog msg(parent, message, _L("Warning"), wxOK | wxICON_WARNING); - msg.ShowModal(); + MessageDialog msg(parent, message, _L("Warning"), wxOK | wxICON_WARNING); + msg.ShowModal(); } -static wxString bold(const wxString& str) { return wxString::Format("%s", str); }; +static wxString bold(const wxString& str) +{ + return wxString::Format("%s", str); +}; -static wxString bold_string(const wxString& str) { return wxString::Format("\"%s\"", str); }; +static wxString bold_string(const wxString& str) +{ + return wxString::Format("\"%s\"", str); +}; static void add_config_substitutions(const ConfigSubstitutions& conf_substitutions, wxString& changes) { - changes += ""; - for (const ConfigSubstitution& conf_substitution : conf_substitutions) { - wxString new_val; - const ConfigOptionDef* def = conf_substitution.opt_def; - if (!def) - continue; - switch (def->type) { - case coEnum: { - const std::vector& labels = def->enum_labels; - const std::vector& values = def->enum_values; - int val = conf_substitution.new_value->getInt(); + changes += "
"; + for (const ConfigSubstitution& conf_substitution : conf_substitutions) { + wxString new_val; + const ConfigOptionDef* def = conf_substitution.opt_def; + if (!def) + continue; + switch (def->type) { + case coEnum: + { + const std::vector& labels = def->enum_labels; + const std::vector& values = def->enum_values; + int val = conf_substitution.new_value->getInt(); - bool is_infill = def->opt_key == "top_surface_pattern" || def->opt_key == "bottom_surface_pattern" || - def->opt_key == "internal_solid_infill_pattern" || def->opt_key == "support_base_pattern" || - def->opt_key == "support_interface_pattern" || def->opt_key == "ironing_pattern" || - def->opt_key == "support_ironing_pattern" || def->opt_key == "sparse_infill_pattern"; + bool is_infill = def->opt_key == "top_surface_pattern" || + def->opt_key == "bottom_surface_pattern" || + def->opt_key == "internal_solid_infill_pattern" || + def->opt_key == "support_base_pattern" || + def->opt_key == "support_interface_pattern" || + def->opt_key == "ironing_pattern" || + def->opt_key == "support_ironing_pattern" || + def->opt_key == "sparse_infill_pattern"; - // Each infill doesn't use all list of infill declared in PrintConfig.hpp. - // So we should "convert" val to the correct one - if (is_infill) { - for (const auto& key_val : *def->enum_keys_map) - if ((int) key_val.second == val) { - auto it = std::find(values.begin(), values.end(), key_val.first); - if (it == values.end()) - break; - auto idx = it - values.begin(); - new_val = wxString("\"") + values[idx] + "\"" + " (" + from_u8(_utf8(labels[idx])) + ")"; - break; - } - if (new_val.IsEmpty()) { - assert(false); - new_val = _L("Undefined"); - } - } else - new_val = wxString("\"") + values[val] + "\"" + " (" + from_u8(_utf8(labels[val])) + ")"; - break; - } - case coEnums: { - const std::vector& labels = def->enum_labels; - const std::vector& values = def->enum_values; - std::string val = conf_substitution.new_value->serialize(); - new_val = wxString("\"") + from_u8(_utf8(val)) + "\""; - break; - } - case coBool: new_val = conf_substitution.new_value->getBool() ? "true" : "false"; break; - case coBools: - if (conf_substitution.new_value->nullable()) - for (const char v : static_cast(conf_substitution.new_value.get())->values) - new_val += std::string(v == ConfigOptionBoolsNullable::nil_value() ? "nil" : v ? "true" : "false") + ", "; - else - for (const char v : static_cast(conf_substitution.new_value.get())->values) - new_val += std::string(v ? "true" : "false") + ", "; - if (!new_val.empty()) - new_val.erase(new_val.begin() + new_val.size() - 2, new_val.end()); - break; - default: assert(false); - } + // Each infill doesn't use all list of infill declared in PrintConfig.hpp. + // So we should "convert" val to the correct one + if (is_infill) { + for (const auto& key_val : *def->enum_keys_map) + if ((int)key_val.second == val) { + auto it = std::find(values.begin(), values.end(), key_val.first); + if (it == values.end()) + break; + auto idx = it - values.begin(); + new_val = wxString("\"") + values[idx] + "\"" + " (" + from_u8(_utf8(labels[idx])) + ")"; + break; + } + if (new_val.IsEmpty()) { + assert(false); + new_val = _L("Undefined"); + } + } + else + new_val = wxString("\"") + values[val] + "\"" + " (" + from_u8(_utf8(labels[val])) + ")"; + break; + } + case coEnums: + { + const std::vector& labels = def->enum_labels; + const std::vector& values = def->enum_values; + std::string val = conf_substitution.new_value->serialize(); + new_val = wxString("\"") + from_u8(_utf8(val)) + "\""; + break; + } + case coBool: + new_val = conf_substitution.new_value->getBool() ? "true" : "false"; + break; + case coBools: + if (conf_substitution.new_value->nullable()) + for (const char v : static_cast(conf_substitution.new_value.get())->values) + new_val += std::string(v == ConfigOptionBoolsNullable::nil_value() ? "nil" : v ? "true" : "false") + ", "; + else + for (const char v : static_cast(conf_substitution.new_value.get())->values) + new_val += std::string(v ? "true" : "false") + ", "; + if (! new_val.empty()) + new_val.erase(new_val.begin() + new_val.size() - 2, new_val.end()); + break; + default: + assert(false); + } - changes += format_wxstr(""; - } - changes += "
\"%1%\" (%2%): ", def->opt_key, _(def->label)) + - format_wxstr(_L("%1% was replaced with %2%"), bold_string(conf_substitution.old_value), bold(new_val)) + "
"; + changes += format_wxstr("\"%1%\" (%2%): ", def->opt_key, _(def->label)) + + format_wxstr(_L("%1% was replaced with %2%"), bold_string(conf_substitution.old_value), bold(new_val)) + + ""; + } + changes += ""; } static wxString substitution_message(const wxString& changes) { - return _L("The configuration may be generated by a newer version of OrcaSlicer.") + " " + - _L("Some values have been replaced. Please check them:") + "\n" + changes + "\n"; + return + _L("The configuration may be generated by a newer version of OrcaSlicer.") + " " + + _L("Some values have been replaced. Please check them:") + "\n" + changes + "\n"; } void show_substitutions_info(const PresetsConfigSubstitutions& presets_config_substitutions) { - wxString changes; + wxString changes; - auto preset_type_name = [](Preset::Type type) { - switch (type) { - case Preset::TYPE_PRINT: return _L("Process"); - // BBS: remove TYPE_SLA_PRINT - case Preset::TYPE_FILAMENT: return _L("Filament"); - // BBS: remove TYPE_SLA_MATERIAL - case Preset::TYPE_PRINTER: return _L("Machine"); - // BBS: remove TYPE_PHYSICAL_PRINTER - default: assert(false); return wxString(); - } - }; + auto preset_type_name = [](Preset::Type type) { + switch (type) { + case Preset::TYPE_PRINT: return _L("Process"); + // BBS: remove TYPE_SLA_PRINT + case Preset::TYPE_FILAMENT: return _L("Filament"); + // BBS: remove TYPE_SLA_MATERIAL + case Preset::TYPE_PRINTER: return _L("Machine"); + // BBS: remove TYPE_PHYSICAL_PRINTER + default: assert(false); return wxString(); + } + }; - for (const PresetConfigSubstitutions& substitution : presets_config_substitutions) { - changes += "\n\n" + format_wxstr("%1% : %2%", preset_type_name(substitution.preset_type), bold_string(substitution.preset_name)); - if (!substitution.preset_file.empty()) - changes += format_wxstr(" (%1%)", substitution.preset_file); + for (const PresetConfigSubstitutions& substitution : presets_config_substitutions) { + changes += "\n\n" + format_wxstr("%1% : %2%", preset_type_name(substitution.preset_type), bold_string(substitution.preset_name)); + if (!substitution.preset_file.empty()) + changes += format_wxstr(" (%1%)", substitution.preset_file); - add_config_substitutions(substitution.substitutions, changes); - } + add_config_substitutions(substitution.substitutions, changes); + } - InfoDialog msg(nullptr, _L("Configuration package was loaded, but some values were not recognized."), substitution_message(changes), - true); - msg.ShowModal(); + InfoDialog msg(nullptr, _L("Configuration package was loaded, but some values were not recognized."), substitution_message(changes), true); + msg.ShowModal(); } void show_substitutions_info(const ConfigSubstitutions& config_substitutions, const std::string& filename) { - wxString changes = "\n"; - add_config_substitutions(config_substitutions, changes); + wxString changes = "\n"; + add_config_substitutions(config_substitutions, changes); - InfoDialog msg(nullptr, - format_wxstr(_L("Configuration file \"%1%\" was loaded, but some values were not recognized."), from_u8(filename)), - substitution_message(changes), true); - msg.ShowModal(); + InfoDialog msg(nullptr, + format_wxstr(_L("Configuration file \"%1%\" was loaded, but some values were not recognized."), from_u8(filename)), + substitution_message(changes), true); + msg.ShowModal(); } void create_combochecklist(wxComboCtrl* comboCtrl, const std::string& text, const std::string& items) @@ -402,89 +440,98 @@ void create_combochecklist(wxComboCtrl* comboCtrl, const std::string& text, cons wxCheckListBoxComboPopup* popup = new wxCheckListBoxComboPopup; if (popup != nullptr) { - // FIXME If the following line is removed, the combo box popup list will not react to mouse clicks. + // FIXME If the following line is removed, the combo box popup list will not react to mouse clicks. // On the other side, with this line the combo box popup cannot be closed by clicking on the combo button on Windows 10. comboCtrl->UseAltPopupWindow(); - int max_width = 0; + int max_width = 0; - // the following line messes up the popup size the first time it is shown on wxWidgets 3.1.3 + // the following line messes up the popup size the first time it is shown on wxWidgets 3.1.3 // comboCtrl->EnablePopupAnimation(false); #ifdef _WIN32 - popup->SetFont(comboCtrl->GetFont()); + popup->SetFont(comboCtrl->GetFont()); #endif // _WIN32 - comboCtrl->SetPopupControl(popup); - wxString title = from_u8(text); - max_width = std::max(max_width, 60 + comboCtrl->GetTextExtent(title).x); - popup->SetStringValue(title); - popup->Bind(wxEVT_CHECKLISTBOX, [popup](wxCommandEvent& evt) { popup->OnCheckListBox(evt); }); - popup->Bind(wxEVT_LISTBOX, [popup](wxCommandEvent& evt) { popup->OnListBoxSelection(evt); }); + comboCtrl->SetPopupControl(popup); + wxString title = from_u8(text); + max_width = std::max(max_width, 60 + comboCtrl->GetTextExtent(title).x); + popup->SetStringValue(title); + popup->Bind(wxEVT_CHECKLISTBOX, [popup](wxCommandEvent& evt) { popup->OnCheckListBox(evt); }); + popup->Bind(wxEVT_LISTBOX, [popup](wxCommandEvent& evt) { popup->OnListBoxSelection(evt); }); popup->Bind(wxEVT_KEY_DOWN, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); }); popup->Bind(wxEVT_KEY_UP, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); }); std::vector items_str; boost::split(items_str, items, boost::is_any_of("|"), boost::token_compress_off); - // each item must be composed by 2 parts - assert(items_str.size() % 2 == 0); + // each item must be composed by 2 parts + assert(items_str.size() %2 == 0); - for (size_t i = 0; i < items_str.size(); i += 2) { - wxString label = from_u8(items_str[i]); - max_width = std::max(max_width, 60 + popup->GetTextExtent(label).x); - popup->Append(label); - popup->Check(i / 2, items_str[i + 1] == "1"); - } + for (size_t i = 0; i < items_str.size(); i += 2) { + wxString label = from_u8(items_str[i]); + max_width = std::max(max_width, 60 + popup->GetTextExtent(label).x); + popup->Append(label); + popup->Check(i / 2, items_str[i + 1] == "1"); + } - comboCtrl->SetMinClientSize(wxSize(max_width, -1)); + comboCtrl->SetMinClientSize(wxSize(max_width, -1)); wxGetApp().UpdateDarkUI(popup); - } + } } unsigned int combochecklist_get_flags(wxComboCtrl* comboCtrl) { - unsigned int flags = 0; + unsigned int flags = 0; - wxCheckListBoxComboPopup* popup = wxDynamicCast(comboCtrl->GetPopupControl(), wxCheckListBoxComboPopup); - if (popup != nullptr) { - for (unsigned int i = 0; i < popup->GetCount(); ++i) { - if (popup->IsChecked(i)) - flags |= 1 << i; - } - } + wxCheckListBoxComboPopup* popup = wxDynamicCast(comboCtrl->GetPopupControl(), wxCheckListBoxComboPopup); + if (popup != nullptr) { + for (unsigned int i = 0; i < popup->GetCount(); ++i) { + if (popup->IsChecked(i)) + flags |= 1 << i; + } + } - return flags; + return flags; } void combochecklist_set_flags(wxComboCtrl* comboCtrl, unsigned int flags) { - wxCheckListBoxComboPopup* popup = wxDynamicCast(comboCtrl->GetPopupControl(), wxCheckListBoxComboPopup); - if (popup != nullptr) { - for (unsigned int i = 0; i < popup->GetCount(); ++i) { - popup->Check(i, (flags & (1 << i)) != 0); - } - } + wxCheckListBoxComboPopup* popup = wxDynamicCast(comboCtrl->GetPopupControl(), wxCheckListBoxComboPopup); + if (popup != nullptr) { + for (unsigned int i = 0; i < popup->GetCount(); ++i) { + popup->Check(i, (flags & (1 << i)) != 0); + } + } } -AppConfig* get_app_config() { return wxGetApp().app_config; } - -wxString from_u8(const std::string& str) { return wxString::FromUTF8(str.c_str()); } - -std::string into_u8(const wxString& str) +AppConfig* get_app_config() { - auto buffer_utf8 = str.utf8_str(); - return std::string(buffer_utf8.data()); + return wxGetApp().app_config; } -wxString from_path(const boost::filesystem::path& path) +wxString from_u8(const std::string &str) +{ + return wxString::FromUTF8(str.c_str()); +} + +std::string into_u8(const wxString &str) +{ + auto buffer_utf8 = str.utf8_str(); + return std::string(buffer_utf8.data()); +} + +wxString from_path(const boost::filesystem::path &path) { #ifdef _WIN32 - return wxString(path.string()); + return wxString(path.string()); #else - return from_u8(path.string()); + return from_u8(path.string()); #endif } -boost::filesystem::path into_path(const wxString& str) { return boost::filesystem::path(str.wx_str()); } +boost::filesystem::path into_path(const wxString &str) +{ + return boost::filesystem::path(str.wx_str()); +} void about() { @@ -494,62 +541,62 @@ void about() void login() { - // LoginDialog dlg; - // dlg.ShowModal(); + //LoginDialog dlg; + //dlg.ShowModal(); - ZUserLogin dlg; + ZUserLogin dlg; dlg.run(); } void desktop_open_datadir_folder() { - // Execute command to open a file explorer, platform dependent. - // FIXME: The const_casts aren't needed in wxWidgets 3.1, remove them when we upgrade. + // Execute command to open a file explorer, platform dependent. + // FIXME: The const_casts aren't needed in wxWidgets 3.1, remove them when we upgrade. - const auto path = data_dir(); + const auto path = data_dir(); #ifdef _WIN32 - const wxString widepath = from_u8(path); - const wchar_t* argv[] = {L"explorer", widepath.GetData(), nullptr}; - ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr); + const wxString widepath = from_u8(path); + const wchar_t *argv[] = { L"explorer", widepath.GetData(), nullptr }; + ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr); #elif __APPLE__ - const char* argv[] = {"open", path.data(), nullptr}; - ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr); + const char *argv[] = { "open", path.data(), nullptr }; + ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr); #else - const char* argv[] = {"xdg-open", path.data(), nullptr}; + const char *argv[] = { "xdg-open", path.data(), nullptr }; - // Check if we're running in an AppImage container, if so, we need to remove AppImage's env vars, - // because they may mess up the environment expected by the file manager. - // Mostly this is about LD_LIBRARY_PATH, but we remove a few more too for good measure. - if (wxGetEnv("APPIMAGE", nullptr)) { - // We're running from AppImage - wxEnvVariableHashMap env_vars; - wxGetEnvMap(&env_vars); + // Check if we're running in an AppImage container, if so, we need to remove AppImage's env vars, + // because they may mess up the environment expected by the file manager. + // Mostly this is about LD_LIBRARY_PATH, but we remove a few more too for good measure. + if (wxGetEnv("APPIMAGE", nullptr)) { + // We're running from AppImage + wxEnvVariableHashMap env_vars; + wxGetEnvMap(&env_vars); - env_vars.erase("APPIMAGE"); - env_vars.erase("APPDIR"); - env_vars.erase("LD_LIBRARY_PATH"); - env_vars.erase("LD_PRELOAD"); - env_vars.erase("UNION_PRELOAD"); + env_vars.erase("APPIMAGE"); + env_vars.erase("APPDIR"); + env_vars.erase("LD_LIBRARY_PATH"); + env_vars.erase("LD_PRELOAD"); + env_vars.erase("UNION_PRELOAD"); - wxExecuteEnv exec_env; - exec_env.env = std::move(env_vars); + wxExecuteEnv exec_env; + exec_env.env = std::move(env_vars); - wxString owd; - if (wxGetEnv("OWD", &owd)) { - // This is the original work directory from which the AppImage image was run, - // set it as CWD for the child process: - exec_env.cwd = std::move(owd); - } + wxString owd; + if (wxGetEnv("OWD", &owd)) { + // This is the original work directory from which the AppImage image was run, + // set it as CWD for the child process: + exec_env.cwd = std::move(owd); + } - ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, &exec_env); - } else { - // Looks like we're NOT running from AppImage, we'll make no changes to the environment. - ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, nullptr); - } + ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, &exec_env); + } else { + // Looks like we're NOT running from AppImage, we'll make no changes to the environment. + ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, nullptr); + } #endif } -void desktop_open_any_folder(const std::string& path) +void desktop_open_any_folder( const std::string& path ) { // Execute command to open a file explorer, platform dependent. // FIXME: The const_casts aren't needed in wxWidgets 3.1, remove them when we upgrade. @@ -562,7 +609,7 @@ void desktop_open_any_folder(const std::string& path) #else // Orca#6449: Open containing dir instead of opening the file directly. - std::string new_path = path; + std::string new_path = path; boost::filesystem::path p(new_path); if (!fs::is_directory(p)) { new_path = p.parent_path().string(); @@ -593,13 +640,13 @@ void desktop_open_any_folder(const std::string& path) exec_env.cwd = std::move(owd); } - ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, &exec_env); + ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, &exec_env); } else { // Looks like we're NOT running from AppImage, we'll make no changes to the environment. - ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, nullptr); + ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr, nullptr); } #endif } -} // namespace GUI -} // namespace Slic3r + +} } diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp index 1da42ddc2d..6a4de482d3 100644 --- a/src/slic3r/GUI/GUI.hpp +++ b/src/slic3r/GUI/GUI.hpp @@ -1,12 +1,8 @@ #ifndef slic3r_GUI_hpp_ #define slic3r_GUI_hpp_ -namespace boost { -class any; -} -namespace boost::filesystem { -class path; -} +namespace boost { class any; } +namespace boost::filesystem { class path; } #include @@ -19,7 +15,7 @@ class wxComboCtrl; class wxFileDialog; class wxTopLevelWindow; -namespace Slic3r { +namespace Slic3r { class AppConfig; class DynamicPrintConfig; @@ -32,36 +28,30 @@ void enable_screensaver(); bool debugged(); void break_to_debugger(); -// Platform specific Ctrl+/Alt+ (Windows, Linux) vs. ⌘/⌥ (OSX) prefixes +// Platform specific Ctrl+/Alt+ (Windows, Linux) vs. ⌘/⌥ (OSX) prefixes extern const std::string& shortkey_ctrl_prefix(); extern const std::string& shortkey_alt_prefix(); bool start_filament_index_at_1(); -int filament_index_from_zero_based(int index); -int filament_index_from_one_based(int index); +int filament_index_from_zero_based(int index); +int filament_index_from_one_based(int index); extern AppConfig* get_app_config(); -extern void add_menus(wxMenuBar* menu, int event_preferences_changed, int event_language_change); +extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_language_change); // Change option value in config void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0); // If monospaced_font is true, the error message is displayed using html
tags, // so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser. -void show_error(wxWindow* parent, const wxString& message, bool monospaced_font = false); -void show_error(wxWindow* parent, const char* message, bool monospaced_font = false); -inline void show_error(wxWindow* parent, const std::string& message, bool monospaced_font = false) -{ - show_error(parent, message.c_str(), monospaced_font); -} -void show_error_id(int id, const std::string& message); // For Perl -void show_info(wxWindow* parent, const wxString& message, const wxString& title = wxString()); -void show_info(wxWindow* parent, const char* message, const char* title = nullptr); -inline void show_info(wxWindow* parent, const std::string& message, const std::string& title = std::string()) -{ - show_info(parent, message.c_str(), title.c_str()); -} +void show_error(wxWindow* parent, const wxString& message, bool monospaced_font = false); +void show_error(wxWindow* parent, const char* message, bool monospaced_font = false); +inline void show_error(wxWindow* parent, const std::string& message, bool monospaced_font = false) { show_error(parent, message.c_str(), monospaced_font); } +void show_error_id(int id, const std::string& message); // For Perl +void show_info(wxWindow* parent, const wxString& message, const wxString& title = wxString()); +void show_info(wxWindow* parent, const char* message, const char* title = nullptr); +inline void show_info(wxWindow* parent, const std::string& message,const std::string& title = std::string()) { show_info(parent, message.c_str(), title.c_str()); } void warning_catcher(wxWindow* parent, const wxString& message); void show_substitutions_info(const PresetsConfigSubstitutions& presets_config_substitutions); void show_substitutions_info(const ConfigSubstitutions& config_substitutions, const std::string& filename); @@ -82,13 +72,13 @@ void combochecklist_set_flags(wxComboCtrl* comboCtrl, unsigned int flags); // wxString conversions: // wxString from std::string in UTF8 -wxString from_u8(const std::string& str); +wxString from_u8(const std::string &str); // std::string in UTF8 from wxString -std::string into_u8(const wxString& str); +std::string into_u8(const wxString &str); // wxString from boost path -wxString from_path(const boost::filesystem::path& path); +wxString from_path(const boost::filesystem::path &path); // boost path from wxString -boost::filesystem::path into_path(const wxString& str); +boost::filesystem::path into_path(const wxString &str); // Display an About dialog extern void about(); diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 7a335c8c40..79dd49901a 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -15,7 +15,7 @@ #include "GLCanvas3D.hpp" #include "Selection.hpp" #include "format.hpp" -// BBS: add partplate related logic +//BBS: add partplate related logic #include "PartPlate.hpp" #include "Gizmos/GLGizmoEmboss.hpp" #include "Gizmos/GLGizmoSVG.hpp" @@ -27,159 +27,110 @@ #include "MsgDialog.hpp" #include "wx/utils.h" -namespace Slic3r { namespace GUI { +namespace Slic3r +{ +namespace GUI +{ -static PrinterTechnology printer_technology() { return wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology(); } +static PrinterTechnology printer_technology() +{ + return wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology(); +} -static int filaments_count() { return wxGetApp().filaments_cnt(); } +static int filaments_count() +{ + return wxGetApp().filaments_cnt(); +} static bool is_improper_category(const std::string& category, const int filaments_cnt, const bool is_object_settings = true) { - return category.empty() || (filaments_cnt == 1 && (category == "Extruders" || category == "Wipe options")) || - (!is_object_settings && category == "Support material"); + return category.empty() || + (filaments_cnt == 1 && (category == "Extruders" || category == "Wipe options")) || + (!is_object_settings && category == "Support material"); } + //------------------------------------- // SettingsFactory //------------------------------------- // pt_FFF -static SettingsFactory::Bundle FREQ_SETTINGS_BUNDLE_FFF = { +static SettingsFactory::Bundle FREQ_SETTINGS_BUNDLE_FFF = +{ + //BBS + { L("Quality"), { "layer_height" } }, + { L("Shell"), { "wall_loops", "top_shell_layers", "bottom_shell_layers"} }, + { L("Infill") , { "sparse_infill_density", "sparse_infill_pattern" } }, // BBS - {L("Quality"), {"layer_height"}}, - {L("Shell"), {"wall_loops", "top_shell_layers", "bottom_shell_layers"}}, - {L("Infill"), {"sparse_infill_density", "sparse_infill_pattern"}}, - // BBS - {L("Support"), - {"enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap", "support_base_pattern", - "support_on_build_plate_only", "support_critical_regions_only", "support_remove_small_overhang", "support_base_pattern_spacing", - "support_expansion"}}, - // BBS - {L("Flush options"), {"flush_into_infill", "flush_into_objects", "flush_into_support"}}}; + { L("Support") , { "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap", + "support_base_pattern", "support_on_build_plate_only","support_critical_regions_only", + "support_remove_small_overhang", + "support_base_pattern_spacing", "support_expansion"}}, + //BBS + { L("Flush options") , { "flush_into_infill", "flush_into_objects", "flush_into_support"} } +}; // pt_SLA -static SettingsFactory::Bundle FREQ_SETTINGS_BUNDLE_SLA = { +static SettingsFactory::Bundle FREQ_SETTINGS_BUNDLE_SLA = +{ // BBS: remove SLA freq settings }; -// BBS: add setting data for table -std::map> SettingsFactory::OBJECT_CATEGORY_SETTINGS = - {{L("Quality"), - {{"layer_height", "", 1}, - //{"initial_layer_print_height", "",2}, - {"seam_position", "", 2}, - {"slice_closing_radius", "", 3}, - {"resolution", "", 4}, - {"xy_hole_compensation", "", 5}, - {"xy_contour_compensation", "", 6}, - {"elefant_foot_compensation", "", 7}, - {"make_overhang_printable_angle", "", 8}, - {"make_overhang_printable_hole_size", "", 9}, - {"wall_sequence", "", 10}, - {"precise_z_height", "", 10} +//BBS: add setting data for table +std::map> SettingsFactory::OBJECT_CATEGORY_SETTINGS= +{ + { L("Quality"), {{"layer_height", "",1}, + //{"initial_layer_print_height", "",2}, + {"seam_position", "",2}, + {"slice_closing_radius", "",3}, {"resolution", "",4}, + {"xy_hole_compensation", "",5}, {"xy_contour_compensation", "",6}, {"elefant_foot_compensation", "",7}, + {"make_overhang_printable_angle","", 8},{"make_overhang_printable_hole_size","",9}, {"wall_sequence","",10}, + {"precise_z_height", "",10} - }}, - {L("Support"), - {{"brim_type", "", 1}, - {"brim_width", "", 2}, - {"brim_object_gap", "", 3}, - {"brim_use_efc_outline", "", 4}, - {"enable_support", "", 5}, - {"support_type", "", 6}, - {"support_threshold_angle", "", 7}, - {"support_threshold_overlap", "", 8}, - {"support_on_build_plate_only", "", 9}, - {"support_filament", "", 10}, - {"support_interface_filament", "", 11}, - {"support_expansion", "", 12}, - {"support_style", "", 13}, - {"tree_support_brim_width", "", 14}, - {"tree_support_branch_angle", "", 15}, - {"tree_support_branch_angle_organic", "", 16}, - {"tree_support_wall_count", "", 17}, - {"tree_support_branch_diameter_angle", "", 18}, // tree support - {"support_bottom_z_distance", "", 19}, - {"support_top_z_distance", "", 20}, - {"support_base_pattern", "", 21}, - {"support_base_pattern_spacing", "", 22}, - {"support_interface_top_layers", "", 23}, - {"support_interface_bottom_layers", "", 24}, - {"support_interface_spacing", "", 25}, - {"support_bottom_interface_spacing", "", 26}, - {"support_object_xy_distance", "", 27}, - {"bridge_no_support", "", 28}, - {"max_bridge_length", "", 29}, - {"support_critical_regions_only", "", 30}, - {"support_remove_small_overhang", "", 31}, - {"support_object_first_layer_gap", "", 32}}}, - {L("Speed"), {{"support_speed", "", 12}, {"support_interface_speed", "", 13}}}}; + }}, + { L("Support"), {{"brim_type", "",1},{"brim_width", "",2},{"brim_object_gap", "",3},{"brim_use_efc_outline", "",4}, + {"enable_support", "",5},{"support_type", "",6},{"support_threshold_angle", "",7}, {"support_threshold_overlap", "",8}, {"support_on_build_plate_only", "",9}, + {"support_filament", "",10},{"support_interface_filament", "",11},{"support_expansion", "",12},{"support_style", "",13}, + {"tree_support_brim_width", "",14}, {"tree_support_branch_angle", "",15},{"tree_support_branch_angle_organic","",16}, {"tree_support_wall_count", "",17},{"tree_support_branch_diameter_angle", "",18},//tree support + {"support_bottom_z_distance", "",19},{"support_top_z_distance", "",20},{"support_base_pattern", "",21},{"support_base_pattern_spacing", "",22}, + {"support_interface_top_layers", "",23},{"support_interface_bottom_layers", "",24},{"support_interface_spacing", "",25},{"support_bottom_interface_spacing", "",26}, + {"support_object_xy_distance", "",27}, {"bridge_no_support", "",28},{"max_bridge_length", "",29},{"support_critical_regions_only", "",30},{"support_remove_small_overhang","",31}, + {"support_object_first_layer_gap","",32} + }}, + { L("Speed"), {{"support_speed", "",12}, {"support_interface_speed", "",13} + }} +}; -std::map> SettingsFactory::PART_CATEGORY_SETTINGS = - {{L("Quality"), - {{"ironing_type", "", 8}, - {"ironing_flow", "", 9}, - {"ironing_spacing", "", 10}, - {"ironing_inset", "", 11}, - {"bridge_flow", "", 11}, - {"make_overhang_printable", "", 11}, - {"bridge_density", "", 1}}}, - {L("Strength"), - {{"wall_loops", "", 1}, - {"top_shell_layers", L("Top Solid Layers"), 1}, - {"top_shell_thickness", L("Top Minimum Shell Thickness"), 1}, - {"top_surface_density", L("Top Surface Density"), 1}, - {"bottom_shell_layers", L("Bottom Solid Layers"), 1}, - {"bottom_shell_thickness", L("Bottom Minimum Shell Thickness"), 1}, - {"bottom_surface_density", L("Bottom Surface Density"), 1}, - {"sparse_infill_density", "", 1}, - {"sparse_infill_pattern", "", 1}, - {"lateral_lattice_angle_1", "", 1}, - {"lateral_lattice_angle_2", "", 1}, - {"infill_overhang_angle", "", 1}, - {"infill_anchor", "", 1}, - {"infill_anchor_max", "", 1}, - {"top_surface_pattern", "", 1}, - {"bottom_surface_pattern", "", 1}, - {"internal_solid_infill_pattern", "", 1}, - {"align_infill_direction_to_model", "", 1}, - {"extra_solid_infills", "", 1}, - {"infill_combination", "", 1}, - {"infill_combination_max_layer_height", "", 1}, - {"infill_wall_overlap", "", 1}, - {"top_bottom_infill_wall_overlap", "", 1}, - {"solid_infill_direction", "", 1}, - {"infill_direction", "", 1}, - {"bridge_angle", "", 1}, - {"internal_bridge_angle", "", 1}, - {"minimum_sparse_infill_area", "", 1}}}, - {L("Speed"), - {{"outer_wall_speed", "", 1}, - {"inner_wall_speed", "", 2}, - {"sparse_infill_speed", "", 3}, - {"top_surface_speed", "", 4}, - {"internal_solid_infill_speed", "", 5}, - {"enable_overhang_speed", "", 6}, - {"overhang_1_4_speed", "", 7}, - {"overhang_2_4_speed", "", 8}, - {"overhang_3_4_speed", "", 9}, - {"overhang_4_4_speed", "", 10}, - {"bridge_speed", "", 11}, - {"gap_infill_speed", "", 12}, - {"internal_bridge_speed", "", 13}}}}; +std::map> SettingsFactory::PART_CATEGORY_SETTINGS= +{ + { L("Quality"), {{"ironing_type", "",8},{"ironing_flow", "",9},{"ironing_spacing", "",10},{"ironing_inset", "", 11},{"bridge_flow", "",11},{"make_overhang_printable", "",11},{"bridge_density", "", 1} + }}, + { L("Strength"), {{"wall_loops", "",1},{"top_shell_layers", L("Top Solid Layers"),1},{"top_shell_thickness", L("Top Minimum Shell Thickness"),1},{"top_surface_density", L("Top Surface Density"),1}, + {"bottom_shell_layers", L("Bottom Solid Layers"),1}, {"bottom_shell_thickness", L("Bottom Minimum Shell Thickness"),1},{"bottom_surface_density", L("Bottom Surface Density"),1}, + {"sparse_infill_density", "",1},{"sparse_infill_pattern", "",1},{"lateral_lattice_angle_1", "",1},{"lateral_lattice_angle_2", "",1},{"infill_overhang_angle", "",1},{"infill_anchor", "",1},{"infill_anchor_max", "",1},{"top_surface_pattern", "",1},{"bottom_surface_pattern", "",1}, {"internal_solid_infill_pattern", "",1}, + {"align_infill_direction_to_model", "", 1}, + {"extra_solid_infills", "", 1}, + {"infill_combination", "",1}, {"infill_combination_max_layer_height", "",1}, {"infill_wall_overlap", "",1},{"top_bottom_infill_wall_overlap", "",1}, {"solid_infill_direction", "",1}, {"infill_direction", "",1}, {"bridge_angle", "",1}, {"internal_bridge_angle", "",1}, {"minimum_sparse_infill_area", "",1} + }}, + { L("Speed"), {{"outer_wall_speed", "",1},{"inner_wall_speed", "",2},{"sparse_infill_speed", "",3},{"top_surface_speed", "",4}, {"internal_solid_infill_speed", "",5}, + {"enable_overhang_speed", "",6}, {"overhang_1_4_speed", "",7}, {"overhang_2_4_speed", "",8}, {"overhang_3_4_speed", "",9}, {"overhang_4_4_speed", "",10}, + {"bridge_speed", "",11}, {"gap_infill_speed", "",12}, {"internal_bridge_speed", "", 13} + }} +}; std::vector SettingsFactory::get_options(const bool is_part) { if (printer_technology() == ptSLA) { SLAPrintObjectConfig full_sla_config; - auto options = full_sla_config.keys(); + auto options = full_sla_config.keys(); options.erase(find(options.begin(), options.end(), "layer_height")); return options; } PrintRegionConfig reg_config; - auto options = reg_config.keys(); + auto options = reg_config.keys(); if (!is_part) { - PrintObjectConfig obj_config; + PrintObjectConfig obj_config; std::vector obj_options = obj_config.keys(); options.insert(options.end(), obj_options.begin(), obj_options.end()); } @@ -194,34 +145,30 @@ std::vector SettingsFactory::get_visible_options(const std::s //Shell "wall_loops", "top_shell_layers", "bottom_shell_layers", "top_shell_thickness", "bottom_shell_thickness", //Infill - "sparse_infill_density", "sparse_infill_pattern", "top_surface_pattern", "bottom_surface_pattern", "infill_combination", - "infill_direction", "infill_wall_overlap", + "sparse_infill_density", "sparse_infill_pattern", "top_surface_pattern", "bottom_surface_pattern", "infill_combination", "infill_direction", "infill_wall_overlap", //speed - "inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed", "top_surface_speed", - "gap_infill_speed" + "inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed", "top_surface_speed", "gap_infill_speed" }; t_config_option_keys object_options = { //Quality - "layer_height", "initial_layer_print_height", "adaptive_layer_height", "seam_position", "xy_hole_compensation", - "xy_contour_compensation", "elefant_foot_compensation", "support_line_width", + "layer_height", "initial_layer_print_height", "adaptive_layer_height", "seam_position", "xy_hole_compensation", "xy_contour_compensation", "elefant_foot_compensation", "support_line_width", //Support - "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap", "support_on_build_plate_only", - "support_critical_regions_only", "enforce_support_layers", + "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap", "support_on_build_plate_only", "support_critical_regions_only", "enforce_support_layers", //tree support "tree_support_wall_count", //support - "support_top_z_distance", "support_base_pattern", "support_base_pattern_spacing", "support_interface_top_layers", - "support_interface_bottom_layers", "support_interface_spacing", "support_bottom_interface_spacing", "support_object_xy_distance", + "support_top_z_distance", "support_base_pattern", "support_base_pattern_spacing", "support_interface_top_layers", "support_interface_bottom_layers", "support_interface_spacing", "support_bottom_interface_spacing", "support_object_xy_distance", "support_object_first_layer_gap", //adhesion "brim_type", "brim_width", "brim_object_gap", "raft_layers" };*/ - std::vector options; + std::vector options; std::map>::iterator it; it = PART_CATEGORY_SETTINGS.find(category); - if (it != PART_CATEGORY_SETTINGS.end()) { + if (it != PART_CATEGORY_SETTINGS.end()) + { options = PART_CATEGORY_SETTINGS[category]; } @@ -231,22 +178,26 @@ std::vector SettingsFactory::get_visible_options(const std::s options.insert(options.end(), OBJECT_CATEGORY_SETTINGS[category].begin(), OBJECT_CATEGORY_SETTINGS[category].end()); } - auto sort_func = [](SimpleSettingData& setting1, SimpleSettingData& setting2) { return (setting1.priority < setting2.priority); }; + auto sort_func = [](SimpleSettingData& setting1, SimpleSettingData& setting2) { + return (setting1.priority < setting2.priority); + }; std::sort(options.begin(), options.end(), sort_func); return options; } std::map> SettingsFactory::get_all_visible_options(const bool is_part) { - std::map> option_maps; + std::map> option_maps; std::map>::iterator it1, it2; option_maps = PART_CATEGORY_SETTINGS; if (!is_part) { - for (it1 = OBJECT_CATEGORY_SETTINGS.begin(); it1 != OBJECT_CATEGORY_SETTINGS.end(); it1++) { + for (it1 = OBJECT_CATEGORY_SETTINGS.begin(); it1 != OBJECT_CATEGORY_SETTINGS.end(); it1++) + { std::string category = it1->first; - it2 = PART_CATEGORY_SETTINGS.find(category); - if (it2 != PART_CATEGORY_SETTINGS.end()) { + it2 = PART_CATEGORY_SETTINGS.find(category); + if (it2 != PART_CATEGORY_SETTINGS.end()) + { std::vector& options = option_maps[category]; options.insert(options.end(), it1->second.begin(), it1->second.end()); @@ -254,7 +205,8 @@ std::map> SettingsFactory::get_all_v return (setting1.priority < setting2.priority); }; std::sort(options.begin(), options.end(), sort_func); - } else { + } + else { option_maps.insert(*it1); } } @@ -263,9 +215,8 @@ std::map> SettingsFactory::get_all_v return option_maps; } -SettingsFactory::Bundle SettingsFactory::get_bundle(const DynamicPrintConfig* config, - bool is_object_settings, - bool is_layer_settings /* = false*/) + +SettingsFactory::Bundle SettingsFactory::get_bundle(const DynamicPrintConfig* config, bool is_object_settings, bool is_layer_settings/* = false*/) { auto opt_keys = config->keys(); if (opt_keys.empty()) @@ -285,12 +236,13 @@ SettingsFactory::Bundle SettingsFactory::get_bundle(const DynamicPrintConfig* co const int filaments_cnt = wxGetApp().filaments_cnt(); Bundle bundle; - for (auto& opt_key : opt_keys) { + for (auto& opt_key : opt_keys) + { auto category = config->def()->get(opt_key)->category; if (is_improper_category(category, filaments_cnt, is_object_settings)) continue; - std::vector new_category; + std::vector< std::string > new_category; auto& cat_opt = bundle.find(category) == bundle.end() ? new_category : bundle.at(category); cat_opt.push_back(opt_key); @@ -302,22 +254,23 @@ SettingsFactory::Bundle SettingsFactory::get_bundle(const DynamicPrintConfig* co } // Fill CategoryItem -std::map SettingsFactory::CATEGORY_ICON = { - // settings category name related bitmap name +std::map SettingsFactory::CATEGORY_ICON = +{ +// settings category name related bitmap name // ptFFF - {L("Quality"), "blank2"}, - {L("Shell"), "blank_14"}, - {L("Infill"), "blank_14"}, - {L("Ironing"), "blank_14"}, - {L("Fuzzy Skin"), "menu_fuzzy_skin"}, - {L("Support"), "support"}, - {L("Speed"), "blank_14"}, - {L("Extruders"), "blank_14"}, - {L("Extrusion Width"), "blank_14"}, - {L("Wipe options"), "blank_14"}, - {L("Bed adhesion"), "blank_14"}, - // { L("Speed > Acceleration") , "time" }, - {L("Advanced"), "blank_14"}, + { L("Quality") , "blank2" }, + { L("Shell") , "blank_14" }, + { L("Infill") , "blank_14" }, + { L("Ironing") , "blank_14" }, + { L("Fuzzy Skin") , "menu_fuzzy_skin" }, + { L("Support") , "support" }, + { L("Speed") , "blank_14" }, + { L("Extruders") , "blank_14" }, + { L("Extrusion Width") , "blank_14" }, + { L("Wipe options") , "blank_14" }, + { L("Bed adhesion") , "blank_14" }, +// { L("Speed > Acceleration") , "time" }, + { L("Advanced") , "blank_14" }, // BBS: remove SLA categories }; @@ -328,44 +281,57 @@ wxBitmap SettingsFactory::get_category_bitmap(const std::string& category_name, return create_scaled_bitmap(CATEGORY_ICON.at(category_name)); } + //------------------------------------- // MenuFactory //------------------------------------- // Note: id accords to type of the sub-object (adding volume), so sequence of the menu items is important -static const constexpr std::array, 5> ADD_VOLUME_MENU_ITEMS = {{ +static const constexpr std::array, 5> ADD_VOLUME_MENU_ITEMS = {{ // menu_item Name menu_item bitmap name - {L("Add part"), "menu_add_part"}, // ~ModelVolumeType::MODEL_PART - {L("Add negative part"), "menu_add_negative"}, // ~ModelVolumeType::NEGATIVE_VOLUME - {L("Add modifier"), "menu_add_modifier"}, // ~ModelVolumeType::PARAMETER_MODIFIER - {L("Add support blocker"), "menu_support_blocker"}, // ~ModelVolumeType::SUPPORT_BLOCKER - {L("Add support enforcer"), "menu_support_enforcer"}, // ~ModelVolumeType::SUPPORT_ENFORCER + {L("Add part"), "menu_add_part" }, // ~ModelVolumeType::MODEL_PART + {L("Add negative part"), "menu_add_negative" }, // ~ModelVolumeType::NEGATIVE_VOLUME + {L("Add modifier"), "menu_add_modifier"}, // ~ModelVolumeType::PARAMETER_MODIFIER + {L("Add support blocker"), "menu_support_blocker"}, // ~ModelVolumeType::SUPPORT_BLOCKER + {L("Add support enforcer"), "menu_support_enforcer"}, // ~ModelVolumeType::SUPPORT_ENFORCER }}; // Note: id accords to type of the sub-object (adding volume), so sequence of the menu items is important -static const constexpr std::array, 3> TEXT_VOLUME_ICONS{{ - // menu_item Name menu_item bitmap name - {L("Add text"), "add_text_part"}, // ~ModelVolumeType::MODEL_PART - {L("Add negative text"), "add_text_negative"}, // ~ModelVolumeType::NEGATIVE_VOLUME - {L("Add text modifier"), "add_text_modifier"}, // ~ModelVolumeType::PARAMETER_MODIFIER +static const constexpr std::array, 3> TEXT_VOLUME_ICONS {{ +// menu_item Name menu_item bitmap name + {L("Add text"), "add_text_part"}, // ~ModelVolumeType::MODEL_PART + {L("Add negative text"), "add_text_negative" }, // ~ModelVolumeType::NEGATIVE_VOLUME + {L("Add text modifier"), "add_text_modifier"}, // ~ModelVolumeType::PARAMETER_MODIFIER }}; // Note: id accords to type of the sub-object (adding volume), so sequence of the menu items is important -static const constexpr std::array, 3> SVG_VOLUME_ICONS{{ - {L("Add SVG part"), "svg_part"}, // ~ModelVolumeType::MODEL_PART +static const constexpr std::array, 3> SVG_VOLUME_ICONS{{ + {L("Add SVG part"), "svg_part"}, // ~ModelVolumeType::MODEL_PART {L("Add negative SVG"), "svg_negative"}, // ~ModelVolumeType::NEGATIVE_VOLUME {L("Add SVG modifier"), "svg_modifier"}, // ~ModelVolumeType::PARAMETER_MODIFIER }}; -static Plater* plater() { return wxGetApp().plater(); } +static Plater* plater() +{ + return wxGetApp().plater(); +} -static ObjectList* obj_list() { return wxGetApp().obj_list(); } +static ObjectList* obj_list() +{ + return wxGetApp().obj_list(); +} -static ObjectDataViewModel* list_model() { return wxGetApp().obj_list()->GetModel(); } +static ObjectDataViewModel* list_model() +{ + return wxGetApp().obj_list()->GetModel(); +} -static const Selection& get_selection() { return plater()->get_current_canvas3D(true)->get_selection(); } +static const Selection& get_selection() +{ + return plater()->get_current_canvas3D(true)->get_selection(); +} // category -> vector ( option ; label ) -typedef std::map>> FullSettingsHierarchy; +typedef std::map< std::string, std::vector< std::pair > > FullSettingsHierarchy; static void get_full_settings_hierarchy(FullSettingsHierarchy& settings_menu, const bool is_part) { auto options = SettingsFactory::get_options(is_part); @@ -373,15 +339,16 @@ static void get_full_settings_hierarchy(FullSettingsHierarchy& settings_menu, co const int filaments_cnt = filaments_count(); DynamicPrintConfig config; - for (auto& option : options) { - auto const opt = config.def()->get(option); - auto category = opt->category; + for (auto& option : options) + { + auto const opt = config.def()->get(option); + auto category = opt->category; if (is_improper_category(category, filaments_cnt, !is_part)) continue; - const std::string& label = !opt->full_label.empty() ? opt->full_label : opt->label; - std::pair option_label(option, label); - std::vector> new_category; + const std::string& label = !opt->full_label.empty() ? opt->full_label : opt->label; + std::pair option_label(option, label); + std::vector< std::pair > new_category; auto& cat_opt_label = settings_menu.find(category) == settings_menu.end() ? new_category : settings_menu.at(category); cat_opt_label.push_back(option_label); if (cat_opt_label.size() == 1) @@ -389,7 +356,7 @@ static void get_full_settings_hierarchy(FullSettingsHierarchy& settings_menu, co } } -static wxMenu* create_settings_popupmenu(wxMenu* parent_menu, const bool is_object_settings, wxDataViewItem item /*, ModelConfig& config*/) +static wxMenu* create_settings_popupmenu(wxMenu* parent_menu, const bool is_object_settings, wxDataViewItem item/*, ModelConfig& config*/) { wxMenu* menu = new wxMenu; @@ -398,13 +365,13 @@ static wxMenu* create_settings_popupmenu(wxMenu* parent_menu, const bool is_obje auto get_selected_options_for_category = [categories, item](const wxString& category_name) { wxArrayString names; - wxArrayInt selections; + wxArrayInt selections; - std::vector> category_options; + std::vector< std::pair > category_options; for (auto& cat : categories) { if (_(cat.first) == category_name) { - ModelConfig& config = obj_list()->get_item_config(item); - auto opt_keys = config.keys(); + ModelConfig& config = obj_list()->get_item_config(item); + auto opt_keys = config.keys(); int sel = 0; for (const std::pair& pair : cat.second) { @@ -418,7 +385,8 @@ static wxMenu* create_settings_popupmenu(wxMenu* parent_menu, const bool is_obje } } - if (!category_options.empty() && wxGetSelectedChoices(selections, _L("Select settings"), category_name, names) != -1) { + if (!category_options.empty() && + wxGetSelectedChoices(selections, _L("Select settings"), category_name, names) != -1) { for (auto sel : selections) category_options[sel].second = true; } @@ -426,14 +394,12 @@ static wxMenu* create_settings_popupmenu(wxMenu* parent_menu, const bool is_obje }; for (auto cat : categories) { - append_menu_item( - menu, wxID_ANY, _(cat.first), "", - [menu, item, get_selected_options_for_category](wxCommandEvent& event) { - std::vector> category_options = get_selected_options_for_category( - menu->GetLabel(event.GetId())); - obj_list()->add_category_to_settings_from_selection(category_options, item); - }, - SettingsFactory::get_category_bitmap(cat.first), parent_menu, []() { return true; }, plater()); + append_menu_item(menu, wxID_ANY, _(cat.first), "", + [menu, item, get_selected_options_for_category](wxCommandEvent& event) { + std::vector< std::pair > category_options = get_selected_options_for_category(menu->GetLabel(event.GetId())); + obj_list()->add_category_to_settings_from_selection(category_options, item); + }, SettingsFactory::get_category_bitmap(cat.first), parent_menu, + []() { return true; }, plater()); } return menu; @@ -450,29 +416,29 @@ static void create_freq_settings_popupmenu(wxMenu* menu, const bool is_object_se if (is_improper_category(category.first, filaments_cnt, is_object_settings)) continue; - append_menu_item( - menu, wxID_ANY, _(category.first), "", + append_menu_item(menu, wxID_ANY, _(category.first), "", [menu, item, is_object_settings, bundle](wxCommandEvent& event) { - wxString category_name = menu->GetLabel(event.GetId()); - std::vector options; - for (auto& category : bundle) - if (category_name == _(category.first)) { - options = category.second; - break; + wxString category_name = menu->GetLabel(event.GetId()); + std::vector options; + for (auto& category : bundle) + if (category_name == _(category.first)) { + options = category.second; + break; + } + if (options.empty()) + return; + // Because of we couldn't edited layer_height for ItVolume from settings list, + // correct options according to the selected item type : remove "layer_height" option + if (!is_object_settings && category_name == _("Quality")) { + const auto layer_height_it = std::find(options.begin(), options.end(), "layer_height"); + if (layer_height_it != options.end()) + options.erase(layer_height_it); } - if (options.empty()) - return; - // Because of we couldn't edited layer_height for ItVolume from settings list, - // correct options according to the selected item type : remove "layer_height" option - if (!is_object_settings && category_name == _("Quality")) { - const auto layer_height_it = std::find(options.begin(), options.end(), "layer_height"); - if (layer_height_it != options.end()) - options.erase(layer_height_it); - } - obj_list()->add_category_to_settings_from_frequent(options, item); - }, - SettingsFactory::get_category_bitmap(category.first), menu, []() { return true; }, plater()); + obj_list()->add_category_to_settings_from_frequent(options, item); + }, + SettingsFactory::get_category_bitmap(category.first), menu, + []() { return true; }, plater()); } } @@ -499,70 +465,64 @@ std::vector MenuFactory::get_svg_volume_bitmaps() { std::vector volume_bmps; volume_bmps.reserve(SVG_VOLUME_ICONS.size()); - for (const auto& item : SVG_VOLUME_ICONS) + for (const auto &item : SVG_VOLUME_ICONS) volume_bmps.push_back(create_scaled_bitmap(item.second)); return volume_bmps; } void MenuFactory::append_menu_item_set_visible(wxMenu* menu) { - bool has_one_shown = false; - const Selection& selection = plater()->canvas3D()->get_selection(); + bool has_one_shown = false; + const Selection& selection = plater()->canvas3D()->get_selection(); for (unsigned int i : selection.get_volume_idxs()) { has_one_shown |= selection.get_volume(i)->visible; } - append_menu_item( - menu, wxID_ANY, has_one_shown ? _L("Hide") : _L("Show"), "", - [has_one_shown](wxCommandEvent&) { plater()->set_selected_visible(!has_one_shown); }, "", nullptr, []() { return true; }, m_parent); + append_menu_item(menu, wxID_ANY, has_one_shown ?_L("Hide") : _L("Show"), "", + [has_one_shown](wxCommandEvent&) { plater()->set_selected_visible(!has_one_shown); }, "", nullptr, + []() { return true; }, m_parent); } void MenuFactory::append_menu_item_delete(wxMenu* menu) { #ifdef __WINDOWS__ - append_menu_item( - menu, wxID_ANY, _L("Delete") + "\t" + _L("Del"), _L("Delete the selected object"), - [](wxCommandEvent&) { plater()->remove_selected(); }, "menu_delete", nullptr, []() { return plater()->can_delete(); }, m_parent); + append_menu_item(menu, wxID_ANY, _L("Delete") + "\t" + _L("Del"), _L("Delete the selected object"), + [](wxCommandEvent&) { plater()->remove_selected(); }, "menu_delete", nullptr, + []() { return plater()->can_delete(); }, m_parent); #else - append_menu_item( - menu, wxID_ANY, _L("Delete") + "\t" + _L("Backspace"), _L("Delete the selected object"), - [](wxCommandEvent&) { plater()->remove_selected(); }, "", nullptr, []() { return plater()->can_delete(); }, m_parent); + append_menu_item(menu, wxID_ANY, _L("Delete") + "\t" + _L("Backspace"), _L("Delete the selected object"), + [](wxCommandEvent&) { plater()->remove_selected(); }, "", nullptr, + []() { return plater()->can_delete(); }, m_parent); #endif } -wxMenu* MenuFactory::append_submenu_add_generic(wxMenu* menu, ModelVolumeType type) -{ +wxMenu* MenuFactory::append_submenu_add_generic(wxMenu* menu, ModelVolumeType type) { auto sub_menu = new wxMenu; if (type != ModelVolumeType::INVALID) { - append_menu_item( - sub_menu, wxID_ANY, _L("Load..."), "", [type](wxCommandEvent&) { obj_list()->load_subobject(type); }, "menu_load", menu); + append_menu_item(sub_menu, wxID_ANY, _L("Load..."), "", + [type](wxCommandEvent&) { obj_list()->load_subobject(type); }, "menu_load", menu); sub_menu->AppendSeparator(); } - append_menu_item( - sub_menu, wxID_ANY, _L("Cube"), "", [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Cube"), type); }, - "menu_obj_cube", menu); + append_menu_item(sub_menu, wxID_ANY, _L("Cube"), "", + [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Cube") ,type); },"menu_obj_cube", menu); - append_menu_item( - sub_menu, wxID_ANY, _L("Cylinder"), "", [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Cylinder"), type); }, - "menu_obj_cylinder", menu); + append_menu_item(sub_menu, wxID_ANY, _L("Cylinder"), "", + [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Cylinder"), type); },"menu_obj_cylinder", menu); - append_menu_item( - sub_menu, wxID_ANY, _L("Sphere"), "", [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Sphere"), type); }, - "menu_obj_sphere", menu); + append_menu_item(sub_menu, wxID_ANY, _L("Sphere"), "", + [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Sphere"), type); },"menu_obj_sphere", menu); - append_menu_item( - sub_menu, wxID_ANY, _L("Cone"), "", [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Cone"), type); }, - "menu_obj_cone", menu); + append_menu_item(sub_menu, wxID_ANY, _L("Cone"), "", + [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Cone"), type); },"menu_obj_cone", menu); - append_menu_item( - sub_menu, wxID_ANY, _L("Disc"), "", [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Disc"), type); }, - "menu_obj_disc", menu); + append_menu_item(sub_menu, wxID_ANY, _L("Disc"), "", + [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Disc"), type); },"menu_obj_disc", menu); + + append_menu_item(sub_menu, wxID_ANY, _L("Torus"), "", + [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Torus"), type); },"menu_obj_torus", menu); - append_menu_item( - sub_menu, wxID_ANY, _L("Torus"), "", [type](wxCommandEvent&) { obj_list()->load_generic_subobject(L("Torus"), type); }, - "menu_obj_torus", menu); append_menu_item_add_text(sub_menu, type); append_menu_item_add_svg(sub_menu, type); @@ -571,12 +531,11 @@ wxMenu* MenuFactory::append_submenu_add_generic(wxMenu* menu, ModelVolumeType ty } // Orca: add submenu for adding handy models -wxMenu* MenuFactory::append_submenu_add_handy_model(wxMenu* menu, ModelVolumeType type) -{ +wxMenu* MenuFactory::append_submenu_add_handy_model(wxMenu* menu, ModelVolumeType type) { auto sub_menu = new wxMenu; - for (auto& item : {L("Orca Cube"), L("Orca Tolerance Test"), L("3DBenchy"), L("Cali Cat"), L("Autodesk FDM Test"), L("Voron Cube"), - L("Stanford Bunny"), L("Orca String Hell")}) { + for (auto &item : {L("Orca Cube"), L("Orca Tolerance Test"), L("3DBenchy"), L("Cali Cat"), L("Autodesk FDM Test"), + L("Voron Cube"), L("Stanford Bunny"), L("Orca String Hell") }) { append_menu_item( sub_menu, wxID_ANY, _(item), "", [type, item](wxCommandEvent&) { @@ -634,15 +593,14 @@ wxMenu* MenuFactory::append_submenu_add_handy_model(wxMenu* menu, ModelVolumeTyp "", menu); } + return sub_menu; } -static void append_menu_itemm_add_( - const wxString& name, GLGizmosManager::EType gizmo_type, wxMenu* menu, ModelVolumeType type, bool is_submenu_item) -{ - auto add_ = [type, gizmo_type](const wxCommandEvent& /*unnamed*/) { - const GLCanvas3D* canvas = plater()->canvas3D(); - const GLGizmosManager& mng = canvas->get_gizmos_manager(); - GLGizmoBase* gizmo_base = mng.get_gizmo(gizmo_type); +static void append_menu_itemm_add_(const wxString& name, GLGizmosManager::EType gizmo_type, wxMenu *menu, ModelVolumeType type, bool is_submenu_item) { + auto add_ = [type, gizmo_type](const wxCommandEvent & /*unnamed*/) { + const GLCanvas3D *canvas = plater()->canvas3D(); + const GLGizmosManager &mng = canvas->get_gizmos_manager(); + GLGizmoBase *gizmo_base = mng.get_gizmo(gizmo_type); ModelVolumeType volume_type = type; // no selected object means create new object @@ -651,20 +609,18 @@ static void append_menu_itemm_add_( auto screen_position = canvas->get_popup_menu_position(); if (gizmo_type == GLGizmosManager::Emboss) { - auto emboss = dynamic_cast(gizmo_base); + auto emboss = dynamic_cast(gizmo_base); assert(emboss != nullptr); - if (emboss == nullptr) - return; + if (emboss == nullptr) return; if (screen_position.has_value()) { emboss->create_volume(volume_type, *screen_position); } else { emboss->create_volume(volume_type); } } else if (gizmo_type == GLGizmosManager::Svg) { - auto svg = dynamic_cast(gizmo_base); + auto svg = dynamic_cast(gizmo_base); assert(svg != nullptr); - if (svg == nullptr) - return; + if (svg == nullptr) return; if (screen_position.has_value()) { svg->create_volume(volume_type, *screen_position); } else { @@ -678,19 +634,17 @@ static void append_menu_itemm_add_( ) { wxString item_name = wxString(is_submenu_item ? "" : _(ADD_VOLUME_MENU_ITEMS[int(type)].first) + ": ") + name; menu->AppendSeparator(); - auto def_icon_name = (gizmo_type == GLGizmosManager::Emboss) ? "menu_obj_text" : "menu_obj_svg"; - const std::string icon_name = is_submenu_item ? def_icon_name : ADD_VOLUME_MENU_ITEMS[int(type)].second; + auto def_icon_name = (gizmo_type == GLGizmosManager::Emboss) ? "menu_obj_text" : "menu_obj_svg"; + const std::string icon_name = is_submenu_item ? def_icon_name : ADD_VOLUME_MENU_ITEMS[int(type)].second; append_menu_item(menu, wxID_ANY, item_name, "", add_, icon_name, menu); } } -void MenuFactory::append_menu_item_add_text(wxMenu* menu, ModelVolumeType type, bool is_submenu_item /* = true*/) -{ +void MenuFactory::append_menu_item_add_text(wxMenu* menu, ModelVolumeType type, bool is_submenu_item/* = true*/){ append_menu_itemm_add_(_L("Text"), GLGizmosManager::Emboss, menu, type, is_submenu_item); } -void MenuFactory::append_menu_item_add_svg(wxMenu* menu, ModelVolumeType type, bool is_submenu_item /* = true*/) -{ +void MenuFactory::append_menu_item_add_svg(wxMenu *menu, ModelVolumeType type, bool is_submenu_item /* = true*/){ append_menu_itemm_add_(_L("SVG"), GLGizmosManager::Svg, menu, type, is_submenu_item); } @@ -699,7 +653,7 @@ void MenuFactory::append_menu_items_add_volume(wxMenu* menu) // Update "add" items(delete old & create new) settings popupmenu for (auto& item : ADD_VOLUME_MENU_ITEMS) { const wxString item_name = _(item.first); - int item_id = menu->FindItem(item_name); + int item_id = menu->FindItem(item_name); if (item_id != wxNOT_FOUND) menu->Destroy(item_id); @@ -708,13 +662,13 @@ void MenuFactory::append_menu_items_add_volume(wxMenu* menu) menu->Destroy(item_id); } - for (size_t type = 0; type < ADD_VOLUME_MENU_ITEMS.size(); type++) { + for (size_t type = 0; type < ADD_VOLUME_MENU_ITEMS.size(); type++) + { auto& item = ADD_VOLUME_MENU_ITEMS[type]; wxMenu* sub_menu = append_submenu_add_generic(menu, ModelVolumeType(type)); - append_submenu( - menu, sub_menu, wxID_ANY, _(item.first), "", item.second, []() { return obj_list()->is_instance_or_object_selected(); }, - m_parent); + append_submenu(menu, sub_menu, wxID_ANY, _(item.first), "", item.second, + []() { return obj_list()->is_instance_or_object_selected(); }, m_parent); } append_menu_item_layers_editing(menu); @@ -722,13 +676,9 @@ void MenuFactory::append_menu_items_add_volume(wxMenu* menu) wxMenuItem* MenuFactory::append_menu_item_layers_editing(wxMenu* menu) { - return append_menu_item( - menu, wxID_ANY, _L("Height range Modifier"), "", - [](wxCommandEvent&) { - obj_list()->layers_editing(); - wxGetApp().params_panel()->switch_to_object(); - }, - "height_range_modifier", menu, []() { return obj_list()->is_instance_or_object_selected(); }, m_parent); + return append_menu_item(menu, wxID_ANY, _L("Height range Modifier"), "", + [](wxCommandEvent&) { obj_list()->layers_editing(); wxGetApp().params_panel()->switch_to_object(); }, "height_range_modifier", menu, + []() { return obj_list()->is_instance_or_object_selected(); }, m_parent); } wxMenuItem* MenuFactory::append_menu_item_settings(wxMenu* menu_) @@ -741,12 +691,14 @@ wxMenuItem* MenuFactory::append_menu_item_settings(wxMenu* menu_) if (settings_id != wxNOT_FOUND) menu->Destroy(settings_id); - for (auto& it : FREQ_SETTINGS_BUNDLE_FFF) { + for (auto& it : FREQ_SETTINGS_BUNDLE_FFF) + { settings_id = menu->FindItem(_(it.first)); if (settings_id != wxNOT_FOUND) menu->Destroy(settings_id); } - for (auto& it : FREQ_SETTINGS_BUNDLE_SLA) { + for (auto& it : FREQ_SETTINGS_BUNDLE_SLA) + { settings_id = menu->FindItem(_(it.first)); if (settings_id != wxNOT_FOUND) menu->Destroy(settings_id); @@ -757,8 +709,8 @@ wxMenuItem* MenuFactory::append_menu_item_settings(wxMenu* menu_) // If there are selected more then one instance but not all of them // don't add settings menu items const Selection& selection = get_selection(); - if ((selection.is_multiple_full_instance() && !selection.is_single_full_object()) || selection.is_multiple_volume() || - selection.is_mixed()) // more than one volume(part) is selected on the scene + if ((selection.is_multiple_full_instance() && !selection.is_single_full_object()) || + selection.is_multiple_volume() || selection.is_mixed()) // more than one volume(part) is selected on the scene return nullptr; const auto sel_vol = obj_list()->get_selected_model_volume(); @@ -766,30 +718,31 @@ wxMenuItem* MenuFactory::append_menu_item_settings(wxMenu* menu_) return nullptr; // detect itemm for adding of the setting - ObjectList* object_list = obj_list(); - ObjectDataViewModel* obj_model = list_model(); + ObjectList* object_list = obj_list(); + ObjectDataViewModel* obj_model = list_model(); const wxDataViewItem sel_item = // when all instances in object are selected - object_list->GetSelectedItemsCount() > 1 && selection.is_single_full_object() ? obj_model->GetItemById(selection.get_object_idx()) : - object_list->GetSelection(); + object_list->GetSelectedItemsCount() > 1 && selection.is_single_full_object() ? + obj_model->GetItemById(selection.get_object_idx()) : + object_list->GetSelection(); if (!sel_item) return nullptr; // If we try to add settings for object/part from 3Dscene, // for the second try there is selected ItemSettings in ObjectList. // So, check if selected item isn't SettingsItem. And get a SettingsItem's parent item, if yes - wxDataViewItem item = obj_model->GetItemType(sel_item) & itSettings ? obj_model->GetParent(sel_item) : sel_item; - const ItemType item_type = obj_model->GetItemType(item); - const bool is_object_settings = !(item_type & itVolume || item_type & itLayer); + wxDataViewItem item = obj_model->GetItemType(sel_item) & itSettings ? obj_model->GetParent(sel_item) : sel_item; + const ItemType item_type = obj_model->GetItemType(item); + const bool is_object_settings = !(item_type& itVolume || item_type & itLayer); // Add frequently settings // BBS remvoe freq setting popupmenu // create_freq_settings_popupmenu(menu, is_object_settings, item); - // menu->SetSecondSeparator(); + //menu->SetSecondSeparator(); // Add full settings list - auto menu_item = new wxMenuItem(menu, wxID_ANY, menu_name); + auto menu_item = new wxMenuItem(menu, wxID_ANY, menu_name); menu_item->SetBitmap(create_scaled_bitmap("cog")); menu_item->SetSubMenu(create_settings_popupmenu(menu, is_object_settings, item)); @@ -798,87 +751,82 @@ wxMenuItem* MenuFactory::append_menu_item_settings(wxMenu* menu_) wxMenuItem* MenuFactory::append_menu_item_change_type(wxMenu* menu) { - return append_menu_item( - menu, wxID_ANY, _L("Change type"), "", [](wxCommandEvent&) { obj_list()->change_part_type(); }, "", menu, + return append_menu_item(menu, wxID_ANY, _L("Change type"), "", + [](wxCommandEvent&) { obj_list()->change_part_type(); }, "", menu, []() { - wxDataViewItemArray selections; - obj_list()->GetSelections(selections); - if (selections.empty()) - return false; - for (const auto& it : selections) { - if (!(obj_list()->GetModel()->GetItemType(it) & itVolume)) - return false; // non-volume present -> disable - } - return true; - }, - m_parent); + wxDataViewItemArray selections; + obj_list()->GetSelections(selections); + if (selections.empty()) return false; + for (const auto& it : selections) { + if (!(obj_list()->GetModel()->GetItemType(it) & itVolume)) + return false; // non-volume present -> disable + } + return true; + }, m_parent); } wxMenuItem* MenuFactory::append_menu_item_instance_to_object(wxMenu* menu) { - wxMenuItem* menu_item = append_menu_item( - menu, wxID_ANY, _L("Set as an individual object"), "", [](wxCommandEvent&) { obj_list()->split_instances(); }, "", menu); + wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Set as an individual object"), "", + [](wxCommandEvent&) { obj_list()->split_instances(); }, "", menu); /* New behavior logic: * 1. Split Object to several separated object, if ALL instances are selected * 2. Separate selected instances from the initial object to the separated object, * if some (not all) instances are selected */ - m_parent->Bind( - wxEVT_UPDATE_UI, - [](wxUpdateUIEvent& evt) { + m_parent->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt) + { const Selection& selection = plater()->canvas3D()->get_selection(); - evt.SetText(selection.is_single_full_object() ? _L("Set as individual objects") : _L("Set as an individual object")); + evt.SetText(selection.is_single_full_object() ? + _L("Set as individual objects") : _L("Set as an individual object")); evt.Enable(plater()->can_set_instance_to_object()); - }, - menu_item->GetId()); + }, menu_item->GetId()); return menu_item; } -void MenuFactory::append_menu_item_fill_bed(wxMenu* menu) +void MenuFactory::append_menu_item_fill_bed(wxMenu *menu) { append_menu_item( menu, wxID_ANY, _L("Fill bed with copies"), _L("Fill the remaining area of bed with copies of the selected object"), - [](wxCommandEvent&) { plater()->fill_bed_with_copies(); }, "", nullptr, []() { return plater()->can_increase_instances(); }, - m_parent); + [](wxCommandEvent &) { plater()->fill_bed_with_copies(); }, "", nullptr, []() { return plater()->can_increase_instances(); }, m_parent); } wxMenuItem* MenuFactory::append_menu_item_printable(wxMenu* menu) { // BBS: to be checked - wxMenuItem* menu_item_printable = - append_menu_check_item(menu, wxID_ANY, _L("Printable"), "", [](wxCommandEvent&) { obj_list()->toggle_printable_state(); }, menu); + wxMenuItem* menu_item_printable = append_menu_check_item(menu, wxID_ANY, _L("Printable"), "", + [](wxCommandEvent&) { obj_list()->toggle_printable_state(); }, menu); - m_parent->Bind( - wxEVT_UPDATE_UI, - [](wxUpdateUIEvent& evt) { - ObjectList* list = obj_list(); - wxDataViewItemArray sels; - list->GetSelections(sels); - wxDataViewItem frst_item = sels[0]; - ItemType type = list->GetModel()->GetItemType(frst_item); - bool check; - if (type != itInstance && type != itObject) - check = false; - else { - int obj_idx = list->GetModel()->GetObjectIdByItem(frst_item); - int inst_idx = type == itObject ? 0 : list->GetModel()->GetInstanceIdByItem(frst_item); - check = list->object(obj_idx)->instances[inst_idx]->printable; - } + m_parent->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt) { + ObjectList* list = obj_list(); + wxDataViewItemArray sels; + list->GetSelections(sels); + wxDataViewItem frst_item = sels[0]; + ItemType type = list->GetModel()->GetItemType(frst_item); + bool check; + if (type != itInstance && type != itObject) + check = false; + else { + int obj_idx = list->GetModel()->GetObjectIdByItem(frst_item); + int inst_idx = type == itObject ? 0 : list->GetModel()->GetInstanceIdByItem(frst_item); + check = list->object(obj_idx)->instances[inst_idx]->printable; + } - evt.Check(check); - plater()->set_current_canvas_as_dirty(); - }, - menu_item_printable->GetId()); + evt.Check(check); + plater()->set_current_canvas_as_dirty(); + + }, menu_item_printable->GetId()); return menu_item_printable; } void MenuFactory::append_menu_item_rename(wxMenu* menu) { - append_menu_item(menu, wxID_ANY, _L("Rename"), "", [](wxCommandEvent&) { obj_list()->rename_item(); }, "", menu); + append_menu_item(menu, wxID_ANY, _L("Rename"), "", + [](wxCommandEvent&) { obj_list()->rename_item(); }, "", menu); menu->AppendSeparator(); } @@ -888,62 +836,59 @@ wxMenuItem* MenuFactory::append_menu_item_fix_through_netfabb(wxMenu* menu) if (!is_windows10()) return nullptr; - wxMenuItem* menu_item = append_menu_item( - menu, wxID_ANY, _L("Fix model"), "", [](wxCommandEvent&) { obj_list()->fix_through_netfabb(); }, "", menu, - []() { return plater()->can_fix_through_netfabb(); }, plater()); + wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Fix model"), "", + [](wxCommandEvent&) { obj_list()->fix_through_netfabb(); }, "", menu, + []() {return plater()->can_fix_through_netfabb(); }, plater()); return menu_item; } void MenuFactory::append_menu_item_export_stl(wxMenu* menu, bool is_mulity_menu) { - append_menu_item( - menu, wxID_ANY, _L("Export as one STL") + dots, "", [](wxCommandEvent&) { plater()->export_stl(false, true); }, "", nullptr, + append_menu_item(menu, wxID_ANY, _L("Export as one STL") + dots, "", + [](wxCommandEvent&) { plater()->export_stl(false, true); }, "", nullptr, [is_mulity_menu]() { const Selection& selection = plater()->canvas3D()->get_selection(); if (is_mulity_menu) return selection.is_multiple_full_instance() || selection.is_multiple_full_object(); else return selection.is_single_full_instance() || selection.is_single_full_object(); - }, - m_parent); + }, m_parent); if (!is_mulity_menu) return; - append_menu_item( - menu, wxID_ANY, _L("Export as STLs") + dots, "", [](wxCommandEvent&) { plater()->export_stl(false, true, true); }, "", nullptr, + append_menu_item(menu, wxID_ANY, _L("Export as STLs") + dots, "", + [](wxCommandEvent&) { plater()->export_stl(false, true, true); }, "", nullptr, []() { const Selection& selection = plater()->canvas3D()->get_selection(); return selection.is_multiple_full_instance() || selection.is_multiple_full_object(); - }, - m_parent); + }, m_parent); } void MenuFactory::append_menu_item_reload_from_disk(wxMenu* menu) { - append_menu_item( - menu, wxID_ANY, _L("Reload from disk"), _L("Reload the selected parts from disk"), - [](wxCommandEvent&) { plater()->reload_from_disk(); }, "", menu, []() { return plater()->can_reload_from_disk(); }, m_parent); + append_menu_item(menu, wxID_ANY, _L("Reload from disk"), _L("Reload the selected parts from disk"), + [](wxCommandEvent&) { plater()->reload_from_disk(); }, "", menu, + []() { return plater()->can_reload_from_disk(); }, m_parent); } -void MenuFactory::append_menu_item_replace_with_stl(wxMenu* menu) +void MenuFactory::append_menu_item_replace_with_stl(wxMenu *menu) { - append_menu_item( - menu, wxID_ANY, _L("Replace 3D file") + dots, _L("Replace the selected part with a new 3D file"), - [](wxCommandEvent&) { plater()->replace_with_stl(); }, "", menu, []() { return plater()->can_replace_with_stl(); }, m_parent); + append_menu_item(menu, wxID_ANY, _L("Replace 3D file") + dots, _L("Replace the selected part with a new 3D file"), + [](wxCommandEvent &) { plater()->replace_with_stl(); }, "", menu, + []() { return plater()->can_replace_with_stl(); }, m_parent); } -void MenuFactory::append_menu_item_replace_all_with_stl(wxMenu* menu) +void MenuFactory::append_menu_item_replace_all_with_stl(wxMenu *menu) { - append_menu_item( - menu, wxID_ANY, _L("Replace all with 3D files") + dots, _L("Replace all selected parts with 3D files from folder"), - [](wxCommandEvent&) { plater()->replace_all_with_stl(); }, "", menu, []() { return plater()->can_replace_all_with_stl(); }, - m_parent); + append_menu_item(menu, wxID_ANY, _L("Replace all with 3D files") + dots, _L("Replace all selected parts with 3D files from folder"), + [](wxCommandEvent &) { plater()->replace_all_with_stl(); }, "", menu, + []() { return plater()->can_replace_all_with_stl(); }, m_parent); } void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) { // BBS - const std::vector names = {_L("Change filament"), _L("Set filament for selected items")}; + const std::vector names = { _L("Change filament"), _L("Set filament for selected items") }; // Delete old menu item for (const wxString& name : names) { const int item_id = menu->FindItem(name); @@ -960,9 +905,9 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) if (sels.IsEmpty()) return; - std::vector icons = get_extruder_color_icons(true); - wxMenu* extruder_selection_menu = new wxMenu(); - const wxString& name = sels.Count() == 1 ? names[0] : names[1]; + std::vector icons = get_extruder_color_icons(true); + wxMenu* extruder_selection_menu = new wxMenu(); + const wxString& name = sels.Count() == 1 ? names[0] : names[1]; int initial_extruder = -1; // negative value for multiple object/part selection if (sels.Count() == 1) { @@ -971,9 +916,10 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) initial_extruder = config.has("extruder") ? config.extruder() : 1; } - for (int i = 0; i <= filaments_cnt; i++) { + for (int i = 0; i <= filaments_cnt; i++) + { bool is_active_extruder = i == initial_extruder; - int icon_idx = i == 0 ? 0 : i - 1; + int icon_idx = i == 0 ? 0 : i - 1; wxString item_name = _L("Default"); @@ -992,12 +938,12 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) if (icon_idx >= 0 && icon_idx < icons.size()) { append_menu_item( - extruder_selection_menu, wxID_ANY, item_name, "", [i](wxCommandEvent&) { obj_list()->set_extruder_for_selected_items(i); }, - *icons[icon_idx], menu, [is_active_extruder]() { return !is_active_extruder; }, m_parent); + extruder_selection_menu, wxID_ANY, item_name, "", [i](wxCommandEvent &) { obj_list()->set_extruder_for_selected_items(i); }, *icons[icon_idx], menu, + [is_active_extruder]() { return !is_active_extruder; }, m_parent); } else { append_menu_item( - extruder_selection_menu, wxID_ANY, item_name, "", [i](wxCommandEvent&) { obj_list()->set_extruder_for_selected_items(i); }, - "", menu, [is_active_extruder]() { return !is_active_extruder; }, m_parent); + extruder_selection_menu, wxID_ANY, item_name, "", [i](wxCommandEvent &) { obj_list()->set_extruder_for_selected_items(i); }, "", menu, + [is_active_extruder]() { return !is_active_extruder; }, m_parent); } } @@ -1006,8 +952,7 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) void MenuFactory::append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu) { - append_menu_item( - menu, wxID_ANY, _L("Scale to build volume"), _L("Scale an object to fit the build volume"), + append_menu_item(menu, wxID_ANY, _L("Scale to build volume"), _L("Scale an object to fit the build volume"), [](wxCommandEvent&) { plater()->scale_selection_to_fit_print_volume(); }, "", menu); } @@ -1019,9 +964,9 @@ void MenuFactory::append_menu_items_flush_options(wxMenu* menu) if (item_id != wxNOT_FOUND) menu->Destroy(item_id); - bool show_flush_option_menu = false; - ObjectList* object_list = obj_list(); - const Selection& selection = get_selection(); + bool show_flush_option_menu = false; + ObjectList* object_list = obj_list(); + const Selection& selection = get_selection(); if (selection.get_object_idx() < 0) return; if (wxGetApp().plater()->get_partplate_list().get_curr_plate()->contains(selection.get_bounding_box())) { @@ -1034,16 +979,15 @@ void MenuFactory::append_menu_items_flush_options(wxMenu* menu) if (!show_flush_option_menu) return; - DynamicPrintConfig& global_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; - ModelConfig& select_object_config = object_list->object(selection.get_object_idx())->config; + DynamicPrintConfig& global_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; + ModelConfig& select_object_config = object_list->object(selection.get_object_idx())->config; wxMenu* flush_options_menu = new wxMenu(); - auto can_flush = [&global_config]() { + auto can_flush = [&global_config]() { auto option = global_config.option("enable_prime_tower"); return option ? option->getBool() : false; }; - append_menu_check_item( - flush_options_menu, wxID_ANY, _L("Flush into objects' infill"), "", + append_menu_check_item(flush_options_menu, wxID_ANY, _L("Flush into objects' infill"), "", [&select_object_config, &global_config](wxCommandEvent&) { const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][0]); if (!option) { @@ -1051,19 +995,16 @@ void MenuFactory::append_menu_items_flush_options(wxMenu* menu) } select_object_config.set_key_value(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][0], new ConfigOptionBool(!option->getBool())); wxGetApp().obj_settings()->UpdateAndShow(true); - }, - menu, can_flush, + }, menu, can_flush, [&select_object_config, &global_config]() { const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][0]); if (!option) { option = global_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][0]); } return option->getBool(); - }, - m_parent); + }, m_parent); - append_menu_check_item( - flush_options_menu, wxID_ANY, _L("Flush into this object"), "", + append_menu_check_item(flush_options_menu, wxID_ANY, _L("Flush into this object"), "", [&select_object_config, &global_config](wxCommandEvent&) { const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][1]); if (!option) { @@ -1071,19 +1012,16 @@ void MenuFactory::append_menu_items_flush_options(wxMenu* menu) } select_object_config.set_key_value(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][1], new ConfigOptionBool(!option->getBool())); wxGetApp().obj_settings()->UpdateAndShow(true); - }, - menu, can_flush, + }, menu, can_flush, [&select_object_config, &global_config]() { const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][1]); if (!option) { option = global_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][1]); } return option->getBool(); - }, - m_parent); + }, m_parent); - append_menu_check_item( - flush_options_menu, wxID_ANY, _L("Flush into objects' support"), "", + append_menu_check_item(flush_options_menu, wxID_ANY, _L("Flush into objects' support"), "", [&select_object_config, &global_config](wxCommandEvent&) { const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][2]); if (!option) { @@ -1091,19 +1029,18 @@ void MenuFactory::append_menu_items_flush_options(wxMenu* menu) } select_object_config.set_key_value(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][2], new ConfigOptionBool(!option->getBool())); wxGetApp().obj_settings()->UpdateAndShow(true); - }, - menu, can_flush, + }, menu, can_flush, [&select_object_config, &global_config]() { const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][2]); if (!option) { option = global_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][2]); } return option->getBool(); - }, - m_parent); + }, m_parent); size_t i = 0; - for (auto node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext()) { + for (auto node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext()) + { i++; wxMenuItem* item = node->GetData(); if (item->GetItemLabelText() == _L("Edit in Parameter Table")) @@ -1119,14 +1056,16 @@ void MenuFactory::append_menu_items_convert_unit(wxMenu* menu) if (obj_idxs.empty() && vol_idxs.empty()) return; - auto volume_respects_conversion = [](ModelVolume* volume, ConversionType conver_type) { - return (conver_type == ConversionType::CONV_FROM_INCH && volume->source.is_converted_from_inches) || - (conver_type == ConversionType::CONV_TO_INCH && !volume->source.is_converted_from_inches) || - (conver_type == ConversionType::CONV_FROM_METER && volume->source.is_converted_from_meters) || - (conver_type == ConversionType::CONV_TO_METER && !volume->source.is_converted_from_meters); + auto volume_respects_conversion = [](ModelVolume* volume, ConversionType conver_type) + { + return (conver_type == ConversionType::CONV_FROM_INCH && volume->source.is_converted_from_inches) || + (conver_type == ConversionType::CONV_TO_INCH && !volume->source.is_converted_from_inches) || + (conver_type == ConversionType::CONV_FROM_METER && volume->source.is_converted_from_meters) || + (conver_type == ConversionType::CONV_TO_METER && !volume->source.is_converted_from_meters); }; - auto can_append = [obj_idxs, vol_idxs, volume_respects_conversion](ConversionType conver_type) { + auto can_append = [obj_idxs, vol_idxs, volume_respects_conversion](ConversionType conver_type) + { ModelObjectPtrs objects; for (int obj_idx : obj_idxs) { ModelObject* object = obj_list()->object(obj_idx); @@ -1134,7 +1073,8 @@ void MenuFactory::append_menu_items_convert_unit(wxMenu* menu) for (ModelVolume* volume : object->volumes) if (volume_respects_conversion(volume, conver_type)) return false; - } else { + } + else { for (int vol_idx : vol_idxs) if (volume_respects_conversion(object->volumes[vol_idx], conver_type)) return false; @@ -1143,20 +1083,22 @@ void MenuFactory::append_menu_items_convert_unit(wxMenu* menu) return true; }; - std::vector> items = {{ConversionType::CONV_FROM_INCH, _L("Convert from inches")}, - {ConversionType::CONV_TO_INCH, _L("Restore to inches")}, - {ConversionType::CONV_FROM_METER, _L("Convert from meters")}, - {ConversionType::CONV_TO_METER, _L("Restore to meters")}}; + std::vector> items = { + {ConversionType::CONV_FROM_INCH , _L("Convert from inches") }, + {ConversionType::CONV_TO_INCH , _L("Restore to inches") }, + {ConversionType::CONV_FROM_METER, _L("Convert from meters") }, + {ConversionType::CONV_TO_METER , _L("Restore to meters") } }; for (auto item : items) { int menu_id = menu->FindItem(item.second); if (can_append(item.first)) { // Add menu item if it doesn't exist if (menu_id == wxNOT_FOUND) - append_menu_item( - menu, wxID_ANY, item.second, item.second, [item](wxCommandEvent&) { plater()->convert_unit(item.first); }, "", menu, + append_menu_item(menu, wxID_ANY, item.second, item.second, + [item](wxCommandEvent&) { plater()->convert_unit(item.first); }, "", menu, []() { return true; }, m_parent); - } else if (menu_id != wxNOT_FOUND) { + } + else if (menu_id != wxNOT_FOUND) { // Delete menu item menu->Destroy(menu_id); } @@ -1165,26 +1107,25 @@ void MenuFactory::append_menu_items_convert_unit(wxMenu* menu) void MenuFactory::append_menu_item_merge_to_multipart_object(wxMenu* menu) { - append_menu_item( - menu, wxID_ANY, _L("Assemble"), _L("Assemble the selected objects to an object with multiple parts"), - [](wxCommandEvent&) { obj_list()->merge(true); }, "", menu, []() { return obj_list()->can_merge_to_multipart_object(); }, m_parent); + append_menu_item(menu, wxID_ANY, _L("Assemble"), _L("Assemble the selected objects to an object with multiple parts"), + [](wxCommandEvent&) { obj_list()->merge(true); }, "", menu, + []() { return obj_list()->can_merge_to_multipart_object(); }, m_parent); } void MenuFactory::append_menu_item_merge_to_single_object(wxMenu* menu) { menu->AppendSeparator(); - append_menu_item( - menu, wxID_ANY, _L("Assemble"), _L("Assemble the selected objects to an object with single part"), - [](wxCommandEvent&) { obj_list()->merge(false); }, "", menu, []() { return obj_list()->can_merge_to_single_object(); }, m_parent); + append_menu_item(menu, wxID_ANY, _L("Assemble"), _L("Assemble the selected objects to an object with single part"), + [](wxCommandEvent&) { obj_list()->merge(false); }, "", menu, + []() { return obj_list()->can_merge_to_single_object(); }, m_parent); } void MenuFactory::append_menu_item_merge_parts_to_single_part(wxMenu* menu) { menu->AppendSeparator(); - append_menu_item( - menu, wxID_ANY, _L("Mesh boolean"), _L("Mesh boolean operations including union and subtraction"), - [](wxCommandEvent&) { obj_list()->boolean /*merge_volumes*/ (); }, "", menu, []() { return obj_list()->can_mesh_boolean(); }, - m_parent); + append_menu_item(menu, wxID_ANY, _L("Mesh boolean"), _L("Mesh boolean operations including union and subtraction"), + [](wxCommandEvent&) { obj_list()->boolean/*merge_volumes*/(); }, "", menu, + []() { return obj_list()->can_mesh_boolean(); }, m_parent); } void MenuFactory::append_menu_items_mirror(wxMenu* menu) @@ -1193,22 +1134,20 @@ void MenuFactory::append_menu_items_mirror(wxMenu* menu) if (!mirror_menu) return; - append_menu_item( - mirror_menu, wxID_ANY, _L("Along X axis"), _L("Mirror along the X axis"), [](wxCommandEvent&) { plater()->mirror(X); }, - "menu_mirror_x", menu); - append_menu_item( - mirror_menu, wxID_ANY, _L("Along Y axis"), _L("Mirror along the Y axis"), [](wxCommandEvent&) { plater()->mirror(Y); }, - "menu_mirror_y", menu); - append_menu_item( - mirror_menu, wxID_ANY, _L("Along Z axis"), _L("Mirror along the Z axis"), [](wxCommandEvent&) { plater()->mirror(Z); }, - "menu_mirror_z", menu); + append_menu_item(mirror_menu, wxID_ANY, _L("Along X axis"), _L("Mirror along the X axis"), + [](wxCommandEvent&) { plater()->mirror(X); }, "menu_mirror_x", menu); + append_menu_item(mirror_menu, wxID_ANY, _L("Along Y axis"), _L("Mirror along the Y axis"), + [](wxCommandEvent&) { plater()->mirror(Y); }, "menu_mirror_y", menu); + append_menu_item(mirror_menu, wxID_ANY, _L("Along Z axis"), _L("Mirror along the Z axis"), + [](wxCommandEvent&) { plater()->mirror(Z); }, "menu_mirror_z", menu); - append_submenu(menu, mirror_menu, wxID_ANY, _L("Mirror"), _L("Mirror object"), "", []() { return plater()->can_mirror(); }, m_parent); + append_submenu(menu, mirror_menu, wxID_ANY, _L("Mirror"), _L("Mirror object"), "", + []() { return plater()->can_mirror(); }, m_parent); } -void MenuFactory::append_menu_item_edit_text(wxMenu* menu) +void MenuFactory::append_menu_item_edit_text(wxMenu *menu) { - wxString name = _L("Edit text"); + wxString name = _L("Edit text"); auto can_edit_text = []() { if (plater() == nullptr) @@ -1219,7 +1158,7 @@ void MenuFactory::append_menu_item_edit_text(wxMenu* menu) const GLVolume* gl_volume = selection.get_first_volume(); if (gl_volume == nullptr) return false; - const ModelVolume* volume = get_model_volume(*gl_volume, selection.get_model()->objects); + const ModelVolume *volume = get_model_volume(*gl_volume, selection.get_model()->objects); if (volume == nullptr) return false; return volume->is_text(); @@ -1233,10 +1172,10 @@ void MenuFactory::append_menu_item_edit_text(wxMenu* menu) return; } - wxString description = _L("Ability to change text, font, size, ..."); - std::string icon = "cog"; - auto open_emboss = [](const wxCommandEvent&) { - GLGizmosManager& mng = plater()->get_view3D_canvas3D()->get_gizmos_manager(); + wxString description = _L("Ability to change text, font, size, ..."); + std::string icon = "cog"; + auto open_emboss = [](const wxCommandEvent &) { + GLGizmosManager &mng = plater()->get_view3D_canvas3D()->get_gizmos_manager(); if (mng.get_current_type() == GLGizmosManager::Emboss) mng.open_gizmo(GLGizmosManager::Emboss); // close() and reopen - move to be visible mng.open_gizmo(GLGizmosManager::Emboss); @@ -1244,10 +1183,10 @@ void MenuFactory::append_menu_item_edit_text(wxMenu* menu) append_menu_item(menu, wxID_ANY, name, description, open_emboss, icon, nullptr, can_edit_text, m_parent); } -void MenuFactory::append_menu_item_edit_svg(wxMenu* menu) +void MenuFactory::append_menu_item_edit_svg(wxMenu *menu) { - wxString name = _L("Edit SVG"); - auto can_edit_svg = []() { + wxString name = _L("Edit SVG"); + auto can_edit_svg = []() { if (plater() == nullptr) return false; const Selection& selection = plater()->get_selection(); @@ -1256,7 +1195,7 @@ void MenuFactory::append_menu_item_edit_svg(wxMenu* menu) const GLVolume* gl_volume = selection.get_first_volume(); if (gl_volume == nullptr) return false; - const ModelVolume* volume = get_model_volume(*gl_volume, selection.get_model()->objects); + const ModelVolume *volume = get_model_volume(*gl_volume, selection.get_model()->objects); if (volume == nullptr) return false; return volume->is_svg(); @@ -1270,10 +1209,10 @@ void MenuFactory::append_menu_item_edit_svg(wxMenu* menu) return; } - wxString description = _L("Change SVG source file, projection, size, ..."); - std::string icon = "cog"; - auto open_svg = [](const wxCommandEvent&) { - GLGizmosManager& mng = plater()->get_view3D_canvas3D()->get_gizmos_manager(); + wxString description = _L("Change SVG source file, projection, size, ..."); + std::string icon = "cog"; + auto open_svg = [](const wxCommandEvent &) { + GLGizmosManager &mng = plater()->get_view3D_canvas3D()->get_gizmos_manager(); if (mng.get_current_type() == GLGizmosManager::Svg) mng.open_gizmo(GLGizmosManager::Svg); // close() and reopen - move to be visible mng.open_gizmo(GLGizmosManager::Svg); @@ -1281,7 +1220,7 @@ void MenuFactory::append_menu_item_edit_svg(wxMenu* menu) append_menu_item(menu, wxID_ANY, name, description, open_svg, icon, nullptr, can_edit_svg, m_parent); } -void MenuFactory::append_menu_item_invalidate_cut_info(wxMenu* menu) +void MenuFactory::append_menu_item_invalidate_cut_info(wxMenu *menu) { const wxString menu_name = _L("Invalidate cut info"); @@ -1291,16 +1230,15 @@ void MenuFactory::append_menu_item_invalidate_cut_info(wxMenu* menu) menu->Destroy(menu_item_id); if (obj_list()->has_selected_cut_object()) - append_menu_item( - menu, wxID_ANY, menu_name, "", [](wxCommandEvent&) { obj_list()->invalidate_cut_info_for_selection(); }, "", menu, - []() { return true; }, m_parent); + append_menu_item(menu, wxID_ANY, menu_name, "", [](wxCommandEvent &) { obj_list()->invalidate_cut_info_for_selection(); }, + "", menu, []() { return true; }, m_parent); } MenuFactory::MenuFactory() { for (int i = 0; i < mtCount; i++) { - items_increase[i] = nullptr; - items_decrease[i] = nullptr; + items_increase[i] = nullptr; + items_decrease[i] = nullptr; items_set_number_of_copies[i] = nullptr; } } @@ -1308,39 +1246,37 @@ MenuFactory::MenuFactory() void MenuFactory::create_default_menu() { wxMenu* sub_menu_primitives = append_submenu_add_generic(&m_default_menu, ModelVolumeType::INVALID); - wxMenu* sub_menu_handy = append_submenu_add_handy_model(&m_default_menu, ModelVolumeType::INVALID); + wxMenu* sub_menu_handy = append_submenu_add_handy_model(&m_default_menu, ModelVolumeType::INVALID); #ifdef __WINDOWS__ - append_submenu(&m_default_menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "menu_add_part", []() { return true; }, m_parent); - append_submenu(&m_default_menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "menu_add_part", []() { return true; }, m_parent); - append_menu_item( - &m_default_menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models + append_submenu(&m_default_menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "menu_add_part", + []() {return true; }, m_parent); + append_submenu(&m_default_menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "menu_add_part", + []() {return true; }, m_parent); + append_menu_item(&m_default_menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models [](wxCommandEvent&) { plater()->add_file(); }, "menu_add_part", &m_default_menu, - []() { return wxGetApp().plater()->can_add_model(); }, m_parent); + []() {return wxGetApp().plater()->can_add_model(); }, m_parent); #else - append_submenu(&m_default_menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "", []() { return true; }, m_parent); - append_submenu(&m_default_menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "", []() { return true; }, m_parent); - append_menu_item( - &m_default_menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models - [](wxCommandEvent&) { plater()->add_file(); }, "", &m_default_menu, []() { return wxGetApp().plater()->can_add_model(); }, - m_parent); + append_submenu(&m_default_menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "", + []() {return true; }, m_parent); + append_submenu(&m_default_menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "", + []() {return true; }, m_parent); + append_menu_item(&m_default_menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models + [](wxCommandEvent&) { plater()->add_file(); }, "", &m_default_menu, + []() {return wxGetApp().plater()->can_add_model(); }, m_parent); #endif m_default_menu.AppendSeparator(); - append_menu_check_item( - &m_default_menu, wxID_ANY, _L("Show Labels"), "", - [](wxCommandEvent&) { - plater()->show_view3D_labels(!plater()->are_view3D_labels_shown()); - plater()->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); - }, - &m_default_menu, []() { return plater()->is_view3D_shown(); }, [this]() { return plater()->are_view3D_labels_shown(); }, m_parent); + append_menu_check_item(&m_default_menu, wxID_ANY, _L("Show Labels"), "", + [](wxCommandEvent&) { plater()->show_view3D_labels(!plater()->are_view3D_labels_shown()); plater()->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); }, &m_default_menu, + []() { return plater()->is_view3D_shown(); }, [this]() { return plater()->are_view3D_labels_shown(); }, m_parent); } void MenuFactory::create_common_object_menu(wxMenu* menu) { append_menu_item_rename(menu); append_menu_items_instance_manipulation(menu); - + // Delete menu was moved to be after +/- instace to make it more difficult to be selected by mistake. append_menu_item_delete(menu); menu->AppendSeparator(); @@ -1361,17 +1297,14 @@ void MenuFactory::create_object_menu() if (!split_menu) return; - append_menu_item( - split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), - [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", &m_object_menu, []() { return plater()->can_split(true); }, - m_parent); - append_menu_item( - split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), - [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", &m_object_menu, []() { return plater()->can_split(false); }, - m_parent); + append_menu_item(split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), + [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", &m_object_menu, + []() { return plater()->can_split(true); }, m_parent); + append_menu_item(split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), + [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", &m_object_menu, + []() { return plater()->can_split(false); }, m_parent); - append_submenu( - &m_object_menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", + append_submenu(&m_object_menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", []() { return plater()->can_split(true) || plater()->can_split(false); }, m_parent); m_object_menu.AppendSeparator(); @@ -1388,8 +1321,8 @@ void MenuFactory::create_extra_object_menu() m_object_menu.AppendSeparator(); append_menu_item_instance_to_object(&m_object_menu); m_object_menu.AppendSeparator(); - // append_menu_item_fill_bed(&m_object_menu); - // Object Clone + //append_menu_item_fill_bed(&m_object_menu); + // Object Clone append_menu_item_clone(&m_object_menu); // Object Repair append_menu_item_fix_through_netfabb(&m_object_menu); @@ -1405,18 +1338,15 @@ void MenuFactory::create_extra_object_menu() wxMenu* split_menu = new wxMenu(); if (!split_menu) return; - append_menu_item( - split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), - [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", &m_object_menu, []() { return plater()->can_split(true); }, - m_parent); - append_menu_item( - split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), - [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", &m_object_menu, []() { return plater()->can_split(false); }, - m_parent); + append_menu_item(split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), + [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", &m_object_menu, + []() { return plater()->can_split(true); }, m_parent); + append_menu_item(split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), + [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", &m_object_menu, + []() { return plater()->can_split(false); }, m_parent); - append_submenu( - &m_object_menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", []() { return plater()->can_split(true); }, - m_parent); + append_submenu(&m_object_menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", + []() { return plater()->can_split(true); }, m_parent); // Mirror append_menu_items_mirror(&m_object_menu); @@ -1454,15 +1384,15 @@ void MenuFactory::create_bbl_assemble_object_menu() void MenuFactory::create_sla_object_menu() { create_common_object_menu(&m_sla_object_menu); - append_menu_item( - &m_sla_object_menu, wxID_ANY, _L("Split"), _L("Split the selected object into multiple objects"), - [](wxCommandEvent&) { plater()->split_object(); }, "", nullptr, []() { return plater()->can_split(true); }, m_parent); + append_menu_item(&m_sla_object_menu, wxID_ANY, _L("Split"), _L("Split the selected object into multiple objects"), + [](wxCommandEvent&) { plater()->split_object(); }, "", nullptr, + []() { return plater()->can_split(true); }, m_parent); m_sla_object_menu.AppendSeparator(); // Add the automatic rotation sub-menu append_menu_item(&m_sla_object_menu, wxID_ANY, _L("Auto orientation"), _L("Auto orient the object to improve print quality"), - [](wxCommandEvent&) { plater()->optimize_rotation(); }); + [](wxCommandEvent&) { plater()->optimize_rotation(); }); } void MenuFactory::create_part_menu() @@ -1476,16 +1406,16 @@ void MenuFactory::create_part_menu() append_menu_items_mirror(menu); append_menu_item_merge_parts_to_single_part(menu); - append_menu_item( - menu, wxID_ANY, _L("Split"), _L("Split the selected object into multiple parts"), [](wxCommandEvent&) { plater()->split_volume(); }, - "split_parts", nullptr, []() { return plater()->can_split(false); }, m_parent); + append_menu_item(menu, wxID_ANY, _L("Split"), _L("Split the selected object into multiple parts"), + [](wxCommandEvent&) { plater()->split_volume(); }, "split_parts", nullptr, + []() { return plater()->can_split(false); }, m_parent); menu->AppendSeparator(); append_menu_item_change_type(menu); append_menu_items_mirror(&m_part_menu); - append_menu_item( - &m_part_menu, wxID_ANY, _L("Split"), _L("Split the selected object into multiple parts"), - [](wxCommandEvent&) { plater()->split_volume(); }, "split_parts", nullptr, []() { return plater()->can_split(false); }, m_parent); + append_menu_item(&m_part_menu, wxID_ANY, _L("Split"), _L("Split the selected object into multiple parts"), + [](wxCommandEvent&) { plater()->split_volume(); }, "split_parts", nullptr, + []() { return plater()->can_split(false); }, m_parent); m_part_menu.AppendSeparator(); append_menu_item_per_object_process(&m_part_menu); append_menu_item_per_object_settings(&m_part_menu); @@ -1537,16 +1467,15 @@ void MenuFactory::create_bbl_part_menu() if (!split_menu) return; - append_menu_item( - split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), - [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", menu, []() { return plater()->can_split(true); }, - m_parent); - append_menu_item( - split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), - [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", menu, []() { return plater()->can_split(false); }, m_parent); + append_menu_item(split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), + [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", menu, + []() { return plater()->can_split(true); }, m_parent); + append_menu_item(split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), + [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", menu, + []() { return plater()->can_split(false); }, m_parent); - append_submenu( - menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", []() { return plater()->can_split(true); }, m_parent); + append_submenu(menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", + []() { return plater()->can_split(true); }, m_parent); menu->AppendSeparator(); append_menu_item_per_object_process(menu); append_menu_item_per_object_settings(menu); @@ -1567,84 +1496,84 @@ void MenuFactory::create_bbl_assemble_part_menu() void MenuFactory::create_filament_action_menu(bool init, int active_filament_menu_id) { - wxMenu* menu = &m_filament_action_menu; + wxMenu *menu = &m_filament_action_menu; if (init) { append_menu_item( - menu, wxID_ANY, _L("Edit"), "", [](wxCommandEvent&) { plater()->sidebar().edit_filament(); }, "", nullptr, + menu, wxID_ANY, _L("Edit"), "", [](wxCommandEvent&) { + plater()->sidebar().edit_filament(); }, "", nullptr, []() { return true; }, m_parent); } if (init) { append_menu_item( - menu, wxID_ANY, _L("Delete"), _L("Delete this filament"), [](wxCommandEvent&) { plater()->sidebar().delete_filament(-2); }, "", - nullptr, + menu, wxID_ANY, _L("Delete"), _L("Delete this filament"), [](wxCommandEvent&) { + plater()->sidebar().delete_filament(-2); }, "", nullptr, []() { return plater()->sidebar().combos_filament().size() > 1 - // Orca: only show delete filament option for SEMM machines unless is BBL - && Sidebar::should_show_SEMM_buttons(); - }, - m_parent); + // Orca: only show delete filament option for SEMM machines unless is BBL + && Sidebar::should_show_SEMM_buttons(); + }, m_parent); } const int item_id = menu->FindItem(_L("Merge with")); if (item_id != wxNOT_FOUND) menu->Destroy(item_id); - wxMenu* sub_menu = new wxMenu(); - std::vector icons = get_extruder_color_icons(true); - int filaments_cnt = Sidebar::should_show_SEMM_buttons() ? icons.size() : 0; + wxMenu* sub_menu = new wxMenu(); + std::vector icons = get_extruder_color_icons(true); + int filaments_cnt = Sidebar::should_show_SEMM_buttons() ? icons.size() : 0; for (int i = 0; i < filaments_cnt; i++) { if (i == active_filament_menu_id) continue; - auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i]); - wxString item_name = preset ? from_u8(preset->label(false)) : - wxString::Format(_L("Filament %d"), filament_index_from_zero_based(i)); + auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i]); + wxString item_name = preset ? from_u8(preset->label(false)) : wxString::Format(_L("Filament %d"), filament_index_from_zero_based(i)); - append_menu_item( - sub_menu, wxID_ANY, item_name, "", [i](wxCommandEvent&) { plater()->sidebar().change_filament(-2, i); }, *icons[i], menu, + append_menu_item(sub_menu, wxID_ANY, item_name, "", + [i](wxCommandEvent&) { plater()->sidebar().change_filament(-2, i); }, *icons[i], menu, []() { return true; }, m_parent); } - append_submenu(menu, sub_menu, wxID_ANY, _L("Merge with"), "", "", [filaments_cnt]() { return filaments_cnt > 1; }, m_parent); + append_submenu(menu, sub_menu, wxID_ANY, _L("Merge with"), "", "", + [filaments_cnt]() { return filaments_cnt > 1; }, m_parent); } -// BBS: add part plate related logic +//BBS: add part plate related logic void MenuFactory::create_plate_menu() { wxMenu* menu = &m_plate_menu; // select objects on current plate - append_menu_item( - menu, wxID_ANY, _L("Select All"), _L("select all objects on current plate"), - [](wxCommandEvent&) { plater()->select_curr_plate_all(); }, "", nullptr, - []() { + append_menu_item(menu, wxID_ANY, _L("Select All"), _L("select all objects on current plate"), + [](wxCommandEvent&) { + plater()->select_curr_plate_all(); + }, "", nullptr, []() { PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); assert(plate); return !plate->get_objects().empty(); - }, - m_parent); + }, m_parent); // delete objects on current plate - append_menu_item( - menu, wxID_ANY, _L("Delete All"), _L("delete all objects on current plate"), - [](wxCommandEvent&) { plater()->remove_curr_plate_all(); }, "", nullptr, - []() { + append_menu_item(menu, wxID_ANY, _L("Delete All"), _L("delete all objects on current plate"), + [](wxCommandEvent&) { + plater()->remove_curr_plate_all(); + }, "", nullptr, []() { PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); assert(plate); return !plate->get_objects().empty(); - }, - m_parent); + }, m_parent); // arrange objects on current plate - append_menu_item( - menu, wxID_ANY, _L("Arrange"), _L("arrange current plate"), + append_menu_item(menu, wxID_ANY, _L("Arrange"), _L("arrange current plate"), [](wxCommandEvent&) { PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); assert(plate); plater()->set_prepare_state(Job::PREPARE_STATE_MENU); plater()->arrange(); + }, "", nullptr, + []() { + return !plater()->get_partplate_list().get_selected_plate()->get_objects().empty(); }, - "", nullptr, []() { return !plater()->get_partplate_list().get_selected_plate()->get_objects().empty(); }, m_parent); + m_parent); // reload all objects on current plate append_menu_item( @@ -1658,49 +1587,55 @@ void MenuFactory::create_plate_menu() "", nullptr, []() { return !plater()->get_partplate_list().get_selected_plate()->get_objects().empty(); }, m_parent); // orient objects on current plate - append_menu_item( - menu, wxID_ANY, _L("Auto Rotate"), _L("auto rotate current plate"), + append_menu_item(menu, wxID_ANY, _L("Auto Rotate"), _L("auto rotate current plate"), [](wxCommandEvent&) { PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); assert(plate); - // BBS TODO call auto rotate for current plate + //BBS TODO call auto rotate for current plate plater()->set_prepare_state(Job::PREPARE_STATE_MENU); plater()->orient(); - }, - "", nullptr, []() { return !plater()->get_partplate_list().get_selected_plate()->get_objects().empty(); }, m_parent); + }, "", nullptr, + []() { + return !plater()->get_partplate_list().get_selected_plate()->get_objects().empty(); + }, m_parent); // delete current plate #ifdef __WINDOWS__ - append_menu_item( - menu, wxID_ANY, _L("Delete Plate"), _L("Remove the selected plate"), [](wxCommandEvent&) { plater()->delete_plate(); }, - "menu_delete", nullptr, []() { return plater()->can_delete_plate(); }, m_parent); + append_menu_item(menu, wxID_ANY, _L("Delete Plate"), _L("Remove the selected plate"), + [](wxCommandEvent&) { plater()->delete_plate(); }, "menu_delete", nullptr, + []() { return plater()->can_delete_plate(); }, m_parent); #else - append_menu_item( - menu, wxID_ANY, _L("Delete Plate"), _L("Remove the selected plate"), [](wxCommandEvent&) { plater()->delete_plate(); }, "", nullptr, + append_menu_item(menu, wxID_ANY, _L("Delete Plate"), _L("Remove the selected plate"), + [](wxCommandEvent&) { plater()->delete_plate(); }, "", nullptr, []() { return plater()->can_delete_plate(); }, m_parent); #endif + // add shapes menu->AppendSeparator(); wxMenu* sub_menu_primitives = append_submenu_add_generic(menu, ModelVolumeType::INVALID); - wxMenu* sub_menu_handy = append_submenu_add_handy_model(menu, ModelVolumeType::INVALID); + wxMenu* sub_menu_handy = append_submenu_add_handy_model(menu, ModelVolumeType::INVALID); #ifdef __WINDOWS__ - append_submenu(menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "menu_add_part", []() { return true; }, m_parent); - append_submenu(menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "menu_add_part", []() { return true; }, m_parent); - append_menu_item( - menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models - [](wxCommandEvent&) { plater()->add_file(); }, "menu_add_part", menu, []() { return wxGetApp().plater()->can_add_model(); }, - m_parent); + append_submenu(menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "menu_add_part", + []() {return true; }, m_parent); + append_submenu(menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "menu_add_part", + []() {return true; }, m_parent); + append_menu_item(menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models + [](wxCommandEvent&) { plater()->add_file(); }, "menu_add_part", menu, + []() {return wxGetApp().plater()->can_add_model(); }, m_parent); #else - append_submenu(menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "", []() { return true; }, m_parent); - append_submenu(menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "", []() { return true; }, m_parent); - append_menu_item( - menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models - [](wxCommandEvent&) { plater()->add_file(); }, "", menu, []() { return wxGetApp().plater()->can_add_model(); }, m_parent); + append_submenu(menu, sub_menu_primitives, wxID_ANY, _L("Add Primitive"), "", "", + []() {return true; }, m_parent); + append_submenu(menu, sub_menu_handy, wxID_ANY, _L("Add Handy models"), "", "", + []() {return true; }, m_parent); + append_menu_item(menu, wxID_ANY, _L("Add Models"), "", // ORCA: Add Models + [](wxCommandEvent&) { plater()->add_file(); }, "", menu, + []() {return wxGetApp().plater()->can_add_model(); }, m_parent); #endif append_menu_item_replace_all_with_stl(menu); + return; } @@ -1709,10 +1644,10 @@ void MenuFactory::init(wxWindow* parent) m_parent = parent; create_default_menu(); - // BBS - // create_object_menu(); + //BBS + //create_object_menu(); create_sla_object_menu(); - // create_part_menu(); + //create_part_menu(); create_text_part_menu(); create_svg_part_menu(); create_extra_object_menu(); @@ -1720,7 +1655,7 @@ void MenuFactory::init(wxWindow* parent) create_bbl_assemble_object_menu(); create_bbl_assemble_part_menu(); - // BBS: add part plate related logic + //BBS: add part plate related logic create_plate_menu(); create_filament_action_menu(true, -1); @@ -1735,7 +1670,10 @@ void MenuFactory::update() update_object_menu(); } -wxMenu* MenuFactory::default_menu() { return &m_default_menu; } +wxMenu* MenuFactory::default_menu() +{ + return &m_default_menu; +} wxMenu* MenuFactory::object_menu() { @@ -1752,7 +1690,7 @@ wxMenu* MenuFactory::sla_object_menu() { append_menu_items_convert_unit(&m_sla_object_menu); append_menu_item_settings(&m_sla_object_menu); - // update_menu_items_instance_manipulation(mtObjectSLA); + //update_menu_items_instance_manipulation(mtObjectSLA); append_menu_item_edit_text(&m_sla_object_menu); append_menu_item_edit_svg(&m_object_menu); @@ -1775,7 +1713,7 @@ wxMenu* MenuFactory::text_part_menu() return &m_text_part_menu; } -wxMenu* MenuFactory::svg_part_menu() +wxMenu *MenuFactory::svg_part_menu() { append_menu_item_change_filament(&m_svg_part_menu); append_menu_item_per_object_settings(&m_svg_part_menu); @@ -1783,7 +1721,10 @@ wxMenu* MenuFactory::svg_part_menu() return &m_svg_part_menu; } -wxMenu* MenuFactory::instance_menu() { return &m_instance_menu; } +wxMenu* MenuFactory::instance_menu() +{ + return &m_instance_menu; +} wxMenu* MenuFactory::layer_menu() { @@ -1795,12 +1736,12 @@ wxMenu* MenuFactory::layer_menu() wxMenu* MenuFactory::multi_selection_menu() { - // BBS + //BBS wxDataViewItemArray sels; obj_list()->GetSelections(sels); - bool multi_volume = true; + bool multi_volume = true; bool undefined_type = false; - bool all_plates = true; + bool all_plates = true; for (const wxDataViewItem& item : sels) { Slic3r::GUI::ItemType item_type = list_model()->GetItemType(item); @@ -1829,7 +1770,7 @@ wxMenu* MenuFactory::multi_selection_menu() append_menu_item_center(menu); append_menu_item_drop(menu); append_menu_item_fix_through_netfabb(menu); - // append_menu_item_simplify(menu); + //append_menu_item_simplify(menu); append_menu_item_delete(menu); menu->AppendSeparator(); @@ -1838,33 +1779,31 @@ wxMenu* MenuFactory::multi_selection_menu() menu->AppendSeparator(); append_menu_items_convert_unit(menu); append_menu_item_replace_all_with_stl(menu); - // BBS + //BBS append_menu_item_change_filament(menu); menu->AppendSeparator(); append_menu_item_export_stl(menu, true); - } else { + } + else { append_menu_item_center(menu); append_menu_item_drop(menu); append_menu_item_fix_through_netfabb(menu); - // append_menu_item_simplify(menu); + //append_menu_item_simplify(menu); append_menu_item_delete(menu); append_menu_items_convert_unit(menu); append_menu_item_replace_all_with_stl(menu); append_menu_item_change_filament(menu); wxMenu* split_menu = new wxMenu(); if (split_menu) { - append_menu_item( - split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), - [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", menu, []() { return plater()->can_split(true); }, - m_parent); - append_menu_item( - split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), - [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", menu, []() { return plater()->can_split(false); }, - m_parent); + append_menu_item(split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into multiple objects"), + [](wxCommandEvent&) { plater()->split_object(); }, "menu_split_objects", menu, + []() { return plater()->can_split(true); }, m_parent); + append_menu_item(split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into multiple parts"), + [](wxCommandEvent&) { plater()->split_volume(); }, "menu_split_parts", menu, + []() { return plater()->can_split(false); }, m_parent); - append_submenu( - menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", []() { return plater()->can_split(true); }, - m_parent); + append_submenu(menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", + []() { return plater()->can_split(true); }, m_parent); } append_menu_item_per_object_process(menu); menu->AppendSeparator(); @@ -1886,44 +1825,41 @@ wxMenu* MenuFactory::assemble_multi_selection_menu() wxMenu* menu = new MenuWithSeparators(); append_menu_item_set_visible(menu); - // append_menu_item_fix_through_netfabb(menu); - // append_menu_item_simplify(menu); + //append_menu_item_fix_through_netfabb(menu); + //append_menu_item_simplify(menu); append_menu_item_delete(menu); menu->AppendSeparator(); append_menu_item_change_extruder(menu); return menu; } -// PS + +//PS void MenuFactory::append_menu_items_instance_manipulation(wxMenu* menu) { MenuType type = menu == &m_object_menu ? mtObjectFFF : mtObjectSLA; - items_increase[type] = append_menu_item( - menu, wxID_ANY, _L("Add instance") + "\t+", _L("Add one more instance of the selected object"), - [](wxCommandEvent&) { plater()->increase_instances(); }, "", nullptr, []() { return plater()->can_increase_instances(); }, - m_parent); - items_decrease[type] = append_menu_item( - menu, wxID_ANY, _L("Remove instance") + "\t-", _L("Remove one instance of the selected object"), - [](wxCommandEvent&) { plater()->decrease_instances(); }, "", nullptr, []() { return plater()->can_decrease_instances(); }, - m_parent); - items_set_number_of_copies[type] = append_menu_item( - menu, wxID_ANY, _L("Set number of instances") + dots, _L("Change the number of instances of the selected object"), - [](wxCommandEvent&) { plater()->set_number_of_copies(); }, "", nullptr, []() { return plater()->can_increase_instances(); }, - m_parent); - append_menu_item( - menu, wxID_ANY, _L("Fill bed with instances") + dots, _L("Fill the remaining area of bed with instances of the selected object"), - [](wxCommandEvent&) { plater()->fill_bed_with_instances(); }, "", nullptr, []() { return plater()->can_increase_instances(); }, - m_parent); + items_increase[type] = append_menu_item(menu, wxID_ANY, _L("Add instance") + "\t+", _L("Add one more instance of the selected object"), + [](wxCommandEvent&) { plater()->increase_instances(); }, "", nullptr, + []() { return plater()->can_increase_instances(); }, m_parent); + items_decrease[type] = append_menu_item(menu, wxID_ANY, _L("Remove instance") + "\t-", _L("Remove one instance of the selected object"), + [](wxCommandEvent&) { plater()->decrease_instances(); }, "", nullptr, + []() { return plater()->can_decrease_instances(); }, m_parent); + items_set_number_of_copies[type] = append_menu_item(menu, wxID_ANY, _L("Set number of instances") + dots, _L("Change the number of instances of the selected object"), + [](wxCommandEvent&) { plater()->set_number_of_copies(); }, "", nullptr, + []() { return plater()->can_increase_instances(); }, m_parent); + append_menu_item(menu, wxID_ANY, _L("Fill bed with instances") + dots, _L("Fill the remaining area of bed with instances of the selected object"), + [](wxCommandEvent&) { plater()->fill_bed_with_instances(); }, "", nullptr, + []() { return plater()->can_increase_instances(); }, m_parent); } -wxMenu* MenuFactory::filament_action_menu(int active_filament_menu_id) -{ +wxMenu *MenuFactory::filament_action_menu(int active_filament_menu_id) { create_filament_action_menu(false, active_filament_menu_id); return &m_filament_action_menu; } -// BBS: add partplate related logic + +//BBS: add partplate related logic wxMenu* MenuFactory::plate_menu() { append_menu_item_locked(&m_plate_menu); @@ -1939,15 +1875,15 @@ wxMenu* MenuFactory::assemble_object_menu() // Delete append_menu_item_delete(menu); //// Object Repair - // append_menu_item_fix_through_netfabb(menu); + //append_menu_item_fix_through_netfabb(menu); //// Object Simplify - // append_menu_item_simplify(menu); + //append_menu_item_simplify(menu); menu->AppendSeparator(); // Set filament append_menu_item_change_extruder(menu); //// Enter per object parameters - // append_menu_item_per_object_settings(menu); + //append_menu_item_per_object_settings(menu); return menu; } @@ -1957,11 +1893,11 @@ wxMenu* MenuFactory::assemble_part_menu() append_menu_item_set_visible(menu); append_menu_item_delete(menu); - // append_menu_item_simplify(menu); + //append_menu_item_simplify(menu); menu->AppendSeparator(); append_menu_item_change_extruder(menu); - // append_menu_item_per_object_settings(menu); + //append_menu_item_per_object_settings(menu); return menu; } @@ -1973,80 +1909,99 @@ void MenuFactory::append_menu_item_clone(wxMenu* menu) // FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent? static const wxString ctrl = _L("Ctrl+"); #endif - append_menu_item( - menu, wxID_ANY, _L("Clone") + "\t" + ctrl + "K", "", [this](wxCommandEvent&) { plater()->clone_selection(); }, "", nullptr, - []() { return true; }, m_parent); + append_menu_item(menu, wxID_ANY, _L("Clone") + "\t" + ctrl + "K", "", + [this](wxCommandEvent&) { + plater()->clone_selection(); + }, "", nullptr, + []() { + return true; + }, m_parent); } void MenuFactory::append_menu_item_simplify(wxMenu* menu) { - wxMenuItem* menu_item = append_menu_item( - menu, wxID_ANY, _L("Simplify Model"), "", [](wxCommandEvent&) { obj_list()->simplify(); }, "", menu, - []() { return plater()->can_simplify(); }, m_parent); + wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Simplify Model"), "", + [](wxCommandEvent&) { obj_list()->simplify(); }, "", menu, + []() {return plater()->can_simplify(); }, m_parent); } void MenuFactory::append_menu_item_center(wxMenu* menu) { - append_menu_item( - menu, wxID_ANY, _L("Center"), "", [this](wxCommandEvent&) { plater()->center_selection(); }, "", nullptr, + append_menu_item(menu, wxID_ANY, _L("Center") , "", + [this](wxCommandEvent&) { + plater()->center_selection(); + }, "", nullptr, []() { if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D) return false; else { - Selection& selection = plater()->get_view3D_canvas3D()->get_selection(); - PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); - Vec3d model_pos = selection.get_bounding_box().center(); - Vec3d center_pos = plate->get_center_origin(); - return !((model_pos.x() == center_pos.x()) && (model_pos.y() == center_pos.y())); - } // disable if model is at center / not in View3D - }, - m_parent); + Selection& selection = plater()->get_view3D_canvas3D()->get_selection(); + PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); + Vec3d model_pos = selection.get_bounding_box().center(); + Vec3d center_pos = plate->get_center_origin(); + return !( (model_pos.x() == center_pos.x()) && (model_pos.y() == center_pos.y()) ); + } //disable if model is at center / not in View3D + }, m_parent); } void MenuFactory::append_menu_item_drop(wxMenu* menu) { - append_menu_item( - menu, wxID_ANY, _L("Drop"), "", [this](wxCommandEvent&) { plater()->drop_selection(); }, "", nullptr, + append_menu_item(menu, wxID_ANY, _L("Drop") , "", + [this](wxCommandEvent&) { + plater()->drop_selection(); + }, "", nullptr, []() { if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D) return false; else { return (plater()->get_view3D_canvas3D()->get_selection().get_bounding_box().min.z() != 0); - } // disable if model is on the bed / not in View3D - }, - m_parent); + } //disable if model is on the bed / not in View3D + }, m_parent); } void MenuFactory::append_menu_item_per_object_process(wxMenu* menu) { - const std::vector names = {_L("Edit Process Settings"), _L("Edit Process Settings")}; - append_menu_item( - menu, wxID_ANY, names[0], names[1], [](wxCommandEvent&) { wxGetApp().obj_list()->switch_to_object_process(); }, "", nullptr, + const std::vector names = { _L("Edit Process Settings"), _L("Edit Process Settings") }; + append_menu_item(menu, wxID_ANY, names[0], names[1], + [](wxCommandEvent&) { + wxGetApp().obj_list()->switch_to_object_process(); + }, "", nullptr, []() { Selection& selection = plater()->canvas3D()->get_selection(); - return selection.is_single_full_object() || selection.is_multiple_full_object() || selection.is_single_full_instance() || - selection.is_multiple_full_instance() || selection.is_single_volume() || selection.is_multiple_volume(); - }, - m_parent); + return selection.is_single_full_object() || + selection.is_multiple_full_object() || + selection.is_single_full_instance() || + selection.is_multiple_full_instance() || + selection.is_single_volume() || + selection.is_multiple_volume(); + }, m_parent); const std::vector names2 = {_L("Copy Process Settings"), _L("Copy Process Settings")}; append_menu_item( - menu, wxID_ANY, names2[0], names2[1], [](wxCommandEvent&) { wxGetApp().obj_list()->copy_settings_to_clipboard(); }, "", nullptr, + menu, wxID_ANY, names2[0], names2[1], [](wxCommandEvent &) { + wxGetApp().obj_list()->copy_settings_to_clipboard(); + }, "", nullptr, []() { - Selection& selection = plater()->canvas3D()->get_selection(); - return selection.is_single_full_object() || selection.is_single_full_instance() || selection.is_single_volume_or_modifier(); + Selection &selection = plater()->canvas3D()->get_selection(); + return selection.is_single_full_object() || selection.is_single_full_instance() || + selection.is_single_volume_or_modifier(); }, m_parent); const std::vector names3 = {_L("Paste Process Settings"), _L("Paste Process Settings")}; append_menu_item( - menu, wxID_ANY, names3[0], names3[1], [](wxCommandEvent&) { wxGetApp().obj_list()->paste_settings_into_list(); }, "", nullptr, - []() { return wxGetApp().obj_list()->can_paste_settings_into_list(); }, m_parent); + menu, wxID_ANY, names3[0], names3[1], [](wxCommandEvent &) { + wxGetApp().obj_list()->paste_settings_into_list(); + }, "", nullptr, + []() { + return wxGetApp().obj_list()->can_paste_settings_into_list(); + }, + m_parent); } void MenuFactory::append_menu_item_per_object_settings(wxMenu* menu) { - const std::vector names = {_L("Edit in Parameter Table"), _L("Edit print parameters for a single object")}; + const std::vector names = { _L("Edit in Parameter Table"), _L("Edit print parameters for a single object") }; // Delete old menu item for (const wxString& name : names) { const int item_id = menu->FindItem(name); @@ -2054,18 +2009,19 @@ void MenuFactory::append_menu_item_per_object_settings(wxMenu* menu) menu->Destroy(item_id); } - append_menu_item( - menu, wxID_ANY, names[0], names[1], [](wxCommandEvent&) { plater()->PopupObjectTableBySelection(); }, "", nullptr, + append_menu_item(menu, wxID_ANY, names[0], names[1], + [](wxCommandEvent&) { + plater()->PopupObjectTableBySelection(); + }, "", nullptr, []() { Selection& selection = plater()->canvas3D()->get_selection(); return selection.is_single_full_object() || selection.is_single_full_instance() || selection.is_single_volume(); - }, - m_parent); + }, m_parent); } void MenuFactory::append_menu_item_change_filament(wxMenu* menu) { - const std::vector names = {_L("Change Filament"), _L("Set Filament for selected items")}; + const std::vector names = { _L("Change Filament"), _L("Set Filament for selected items") }; // Delete old menu item for (const wxString& name : names) { const int item_id = menu->FindItem(name); @@ -2090,14 +2046,14 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu) std::vector icons = get_extruder_color_icons(true); if (icons.size() < filaments_cnt) { - BOOST_LOG_TRIVIAL(warning) << boost::format("Warning: icons size %1%, filaments_cnt=%2%") % icons.size() % filaments_cnt; + BOOST_LOG_TRIVIAL(warning) << boost::format("Warning: icons size %1%, filaments_cnt=%2%")%icons.size()%filaments_cnt; if (icons.size() <= 1) return; else filaments_cnt = icons.size(); } - wxMenu* extruder_selection_menu = new wxMenu(); - const wxString& name = sels.Count() == 1 ? names[0] : names[1]; + wxMenu* extruder_selection_menu = new wxMenu(); + const wxString& name = sels.Count() == 1 ? names[0] : names[1]; int initial_extruder = -1; // negative value for multiple object/part selection if (sels.Count() == 1) { @@ -2119,9 +2075,10 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu) } } - for (int i = has_modifier ? 0 : 1; i <= filaments_cnt; i++) { + for (int i = has_modifier ? 0 : 1; i <= filaments_cnt; i++) + { // BBS - // bool is_active_extruder = i == initial_extruder; + //bool is_active_extruder = i == initial_extruder; bool is_active_extruder = false; wxString item_name = _L("Default"); @@ -2139,18 +2096,18 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu) item_name << " (" + _L("current") + ")"; } - append_menu_item( - extruder_selection_menu, wxID_ANY, item_name, "", [i](wxCommandEvent&) { obj_list()->set_extruder_for_selected_items(i); }, - i == 0 ? wxNullBitmap : *icons[i - 1], menu, [is_active_extruder]() { return !is_active_extruder; }, m_parent); + append_menu_item(extruder_selection_menu, wxID_ANY, item_name, "", + [i](wxCommandEvent&) { obj_list()->set_extruder_for_selected_items(i); }, i == 0 ? wxNullBitmap : *icons[i - 1], menu, + [is_active_extruder]() { return !is_active_extruder; }, m_parent); } menu->Append(wxID_ANY, name, extruder_selection_menu, _L("Change Filament")); } void MenuFactory::append_menu_item_set_printable(wxMenu* menu) { - const Selection& selection = plater()->canvas3D()->get_selection(); - bool all_printable = true; - ObjectList* list = obj_list(); + const Selection& selection = plater()->canvas3D()->get_selection(); + bool all_printable = true; + ObjectList* list = obj_list(); wxDataViewItemArray sels; list->GetSelections(sels); @@ -2159,32 +2116,27 @@ void MenuFactory::append_menu_item_set_printable(wxMenu* menu) if (type != itInstance && type != itObject) continue; else { - int obj_idx = list->GetModel()->GetObjectIdByItem(item); + int obj_idx = list->GetModel()->GetObjectIdByItem(item); int inst_idx = type == itObject ? 0 : list->GetModel()->GetInstanceIdByItem(item); all_printable &= list->object(obj_idx)->instances[inst_idx]->printable; } } - wxString menu_text = _L("Printable"); - wxMenuItem* menu_item_set_printable = append_menu_check_item( - menu, wxID_ANY, menu_text, "", - [this, all_printable](wxCommandEvent&) { - Selection& selection = plater()->canvas3D()->get_selection(); - selection.set_printable(!all_printable); - }, - menu); - m_parent->Bind( - wxEVT_UPDATE_UI, - [all_printable](wxUpdateUIEvent& evt) { - evt.Check(all_printable); - plater()->set_current_canvas_as_dirty(); - }, - menu_item_set_printable->GetId()); + wxString menu_text = _L("Printable"); + wxMenuItem* menu_item_set_printable = append_menu_check_item(menu, wxID_ANY, menu_text, "", [this, all_printable](wxCommandEvent&) { + Selection& selection = plater()->canvas3D()->get_selection(); + selection.set_printable(!all_printable); + }, menu); + m_parent->Bind(wxEVT_UPDATE_UI, [all_printable](wxUpdateUIEvent& evt) { + evt.Check(all_printable); + plater()->set_current_canvas_as_dirty(); + + }, menu_item_set_printable->GetId()); } void MenuFactory::append_menu_item_locked(wxMenu* menu) { - const std::vector names = {_L("Unlock"), _L("Lock")}; + const std::vector names = { _L("Unlock"), _L("Lock") }; // Delete old menu item for (const wxString& name : names) { const int item_id = menu->FindItem(name); @@ -2196,45 +2148,41 @@ void MenuFactory::append_menu_item_locked(wxMenu* menu) assert(plate); wxString lock_text = plate->is_locked() ? names[0] : names[1]; - auto item = append_menu_item( - menu, wxID_ANY, lock_text, "", + auto item = append_menu_item(menu, wxID_ANY, lock_text, "", [plate](wxCommandEvent&) { bool lock = plate->is_locked(); plate->lock(!lock); - }, - "", nullptr, []() { return true; }, m_parent); + }, "", nullptr, []() { return true; }, m_parent); - m_parent->Bind( - wxEVT_UPDATE_UI, - [](wxUpdateUIEvent& evt) { - PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); - assert(plate); - // bool check = plate->is_locked(); - // evt.Check(check); - plater()->set_current_canvas_as_dirty(); - }, - item->GetId()); + m_parent->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt) { + PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); + assert(plate); + //bool check = plate->is_locked(); + //evt.Check(check); + plater()->set_current_canvas_as_dirty(); + }, item->GetId()); } -void MenuFactory::append_menu_item_plate_name(wxMenu* menu) +void MenuFactory::append_menu_item_plate_name(wxMenu *menu) { - wxString name = _L("Edit Plate Name"); + wxString name= _L("Edit Plate Name"); // Delete old menu item const int item_id = menu->FindItem(name); - if (item_id != wxNOT_FOUND) - menu->Destroy(item_id); + if (item_id != wxNOT_FOUND) menu->Destroy(item_id); - PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); + PartPlate *plate = plater()->get_partplate_list().get_selected_plate(); assert(plate); auto item = append_menu_item( menu, wxID_ANY, name, "", - [plate](wxCommandEvent& e) { - int hover_idx = plater()->canvas3D()->GetHoverId(); + [plate](wxCommandEvent &e) { + int hover_idx =plater()->canvas3D()->GetHoverId(); if (hover_idx == -1) { - int plate_idx = plater()->GetPlateIndexByRightMenuInLeftUI(); + int plate_idx=plater()->GetPlateIndexByRightMenuInLeftUI(); plater()->select_plate_by_hover_id(plate_idx * PartPlate::GRABBER_COUNT, false, true); - } else { + } + else + { plater()->select_plate_by_hover_id(hover_idx, false, true); } plater()->get_current_canvas3D()->post_event(SimpleEvent(EVT_GLCANVAS_PLATE_NAME_CHANGE)); @@ -2243,19 +2191,22 @@ void MenuFactory::append_menu_item_plate_name(wxMenu* menu) m_parent->Bind( wxEVT_UPDATE_UI, - [](wxUpdateUIEvent& evt) { - PartPlate* plate = plater()->get_partplate_list().get_selected_plate(); + [](wxUpdateUIEvent &evt) { + PartPlate *plate = plater()->get_partplate_list().get_selected_plate(); assert(plate); plater()->set_current_canvas_as_dirty(); }, item->GetId()); } -void MenuFactory::update_object_menu() { append_menu_items_add_volume(&m_object_menu); } +void MenuFactory::update_object_menu() +{ + append_menu_items_add_volume(&m_object_menu); +} void MenuFactory::update_default_menu() { - for (auto& name : {_L("Add Primitive"), _L("Add Handy models"), _L("Show Labels")}) { + for (auto& name : { _L("Add Primitive") , _L("Add Handy models"), _L("Show Labels") }) { const auto menu_item_id = m_default_menu.FindItem(name); if (menu_item_id != wxNOT_FOUND) m_default_menu.Destroy(menu_item_id); @@ -2265,7 +2216,7 @@ void MenuFactory::update_default_menu() void MenuFactory::msw_rescale() { - for (MenuWithSeparators* menu : {&m_object_menu, &m_sla_object_menu, &m_part_menu, &m_default_menu}) + for (MenuWithSeparators* menu : { &m_object_menu, &m_sla_object_menu, &m_part_menu, &m_default_menu }) msw_rescale_menu(dynamic_cast(menu)); } @@ -2273,22 +2224,21 @@ void MenuFactory::msw_rescale() // For this class is used code from stackoverflow: // https://stackoverflow.com/questions/257288/is-it-possible-to-write-a-template-to-check-for-a-functions-existence // Using this code we can to inspect of an existence of IsWheelInverted() function in class T -template class menu_has_update_def_colors +template +class menu_has_update_def_colors { typedef char one; - struct two - { - char x[2]; - }; + struct two { char x[2]; }; - template static one test(decltype(&C::UpdateDefColors)); - template static two test(...); + template static one test(decltype(&C::UpdateDefColors)); + template static two test(...); public: static constexpr bool value = sizeof(test(0)) == sizeof(char); }; -template static void update_menu_item_def_colors(T* item) +template +static void update_menu_item_def_colors(T* item) { if constexpr (menu_has_update_def_colors::value) { item->UpdateDefColors(); @@ -2298,8 +2248,8 @@ template static void update_menu_item_def_colors(T* item) void MenuFactory::sys_color_changed() { - for (MenuWithSeparators* menu : {&m_object_menu, &m_sla_object_menu, &m_part_menu, &m_default_menu}) { - msw_rescale_menu(dynamic_cast(menu)); // msw_rescale_menu updates just icons, so use it + for (MenuWithSeparators* menu : { &m_object_menu, &m_sla_object_menu, &m_part_menu, &m_default_menu }) { + msw_rescale_menu(dynamic_cast(menu));// msw_rescale_menu updates just icons, so use it #ifdef _WIN32 // but under MSW we have to update item's bachground color for (wxMenuItem* item : menu->GetMenuItems()) @@ -2325,4 +2275,6 @@ void MenuFactory::sys_color_changed(wxMenuBar* menubar) #endif } -}} // namespace Slic3r::GUI + +} //namespace GUI +} //namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 1855adcf96..af7ec15772 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -14,6 +14,7 @@ #include "libslic3r/Model.hpp" #include "slic3r/Utils/UndoRedo.hpp" + #include namespace Slic3r::GUI { @@ -23,11 +24,9 @@ static inline void show_notification_extruders_limit_exceeded() wxGetApp() .plater() ->get_notification_manager() - ->push_notification(NotificationType::MmSegmentationExceededExtrudersLimit, - NotificationManager::NotificationLevel::PrintInfoNotificationLevel, + ->push_notification(NotificationType::MmSegmentationExceededExtrudersLimit, NotificationManager::NotificationLevel::PrintInfoNotificationLevel, GUI::format(_L("Filament count exceeds the maximum number that painting tool supports. Only the " - "first %1% filaments will be available in painting tool."), - GLGizmoMmuSegmentation::EXTRUDERS_LIMIT)); + "first %1% filaments will be available in painting tool."), GLGizmoMmuSegmentation::EXTRUDERS_LIMIT)); } void GLGizmoMmuSegmentation::on_opening() @@ -42,12 +41,15 @@ void GLGizmoMmuSegmentation::on_shutdown() m_parent.toggle_model_objects_visibility(true); } -std::string GLGizmoMmuSegmentation::on_get_name() const { return _u8L("Color Painting"); } +std::string GLGizmoMmuSegmentation::on_get_name() const +{ + return _u8L("Color Painting"); +} bool GLGizmoMmuSegmentation::on_is_selectable() const { - return (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF && - /*wxGetApp().get_mode() != comSimple && */ wxGetApp().filaments_cnt() > 1); + return (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF + && /*wxGetApp().get_mode() != comSimple && */wxGetApp().filaments_cnt() > 1); } bool GLGizmoMmuSegmentation::on_is_activable() const @@ -56,11 +58,11 @@ bool GLGizmoMmuSegmentation::on_is_activable() const return !selection.is_empty() && (selection.is_single_full_instance() || selection.is_any_volume()) && wxGetApp().filaments_cnt() > 1; } -static std::vector get_extruder_id_for_volumes(const ModelObject& model_object) +static std::vector get_extruder_id_for_volumes(const ModelObject &model_object) { std::vector extruders_idx; extruders_idx.reserve(model_object.volumes.size()); - for (const ModelVolume* model_volume : model_object.volumes) { + for (const ModelVolume *model_volume : model_object.volumes) { if (!model_volume->is_model_part()) continue; @@ -87,17 +89,17 @@ bool GLGizmoMmuSegmentation::on_init() m_shortcut_key = WXK_CONTROL_N; // FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent? - const wxString ctrl = _L("Ctrl+"); + const wxString ctrl = _L("Ctrl+"); // FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent? const wxString alt = _L("Alt+"); const wxString shift = _L("Shift+"); m_desc["clipping_of_view_caption"] = alt + _L("Mouse wheel"); - m_desc["clipping_of_view"] = _L("Section view"); - m_desc["reset_direction"] = _L("Reset direction"); - m_desc["cursor_size_caption"] = ctrl + _L("Mouse wheel"); - m_desc["cursor_size"] = _L("Pen size"); - m_desc["cursor_type"] = _L("Pen shape"); + m_desc["clipping_of_view"] = _L("Section view"); + m_desc["reset_direction"] = _L("Reset direction"); + m_desc["cursor_size_caption"] = ctrl + _L("Mouse wheel"); + m_desc["cursor_size"] = _L("Pen size"); + m_desc["cursor_type"] = _L("Pen shape"); m_desc["paint_caption"] = _L("Left mouse button"); m_desc["paint"] = _L("Paint"); @@ -110,31 +112,31 @@ bool GLGizmoMmuSegmentation::on_init() m_desc["gap_area"] = _L("Gap area"); m_desc["perform"] = _L("Perform"); - m_desc["remove_all"] = _L("Erase all painting"); - m_desc["circle"] = _L("Circle"); - m_desc["sphere"] = _L("Sphere"); - m_desc["pointer"] = _L("Triangles"); + m_desc["remove_all"] = _L("Erase all painting"); + m_desc["circle"] = _L("Circle"); + m_desc["sphere"] = _L("Sphere"); + m_desc["pointer"] = _L("Triangles"); - m_desc["filaments"] = _L("Filaments"); - m_desc["tool_type"] = _L("Tool type"); - m_desc["tool_brush"] = _L("Brush"); - m_desc["tool_smart_fill"] = _L("Smart fill"); - m_desc["tool_bucket_fill"] = _L("Bucket fill"); + m_desc["filaments"] = _L("Filaments"); + m_desc["tool_type"] = _L("Tool type"); + m_desc["tool_brush"] = _L("Brush"); + m_desc["tool_smart_fill"] = _L("Smart fill"); + m_desc["tool_bucket_fill"] = _L("Bucket fill"); m_desc["smart_fill_angle_caption"] = ctrl + _L("Mouse wheel"); - m_desc["smart_fill_angle"] = _L("Smart fill angle"); + m_desc["smart_fill_angle"] = _L("Smart fill angle"); m_desc["height_range_caption"] = ctrl + _L("Mouse wheel"); m_desc["height_range"] = _L("Height range"); - // add toggle wire frame hint - m_desc["toggle_wireframe_caption"] = alt + shift + _L("Enter"); - m_desc["toggle_wireframe"] = _L("Toggle Wireframe"); + //add toggle wire frame hint + m_desc["toggle_wireframe_caption"] = alt + shift + _L("Enter"); + m_desc["toggle_wireframe"] = _L("Toggle Wireframe"); // Filament remapping descriptions - m_desc["perform_remap"] = _L("Remap filaments"); - m_desc["remap"] = _L("Remap"); - m_desc["cancel_remap"] = _L("Cancel"); + m_desc["perform_remap"] = _L("Remap filaments"); + m_desc["remap"] = _L("Remap"); + m_desc["cancel_remap"] = _L("Cancel"); init_extruders_data(); @@ -143,7 +145,8 @@ bool GLGizmoMmuSegmentation::on_init() GLGizmoMmuSegmentation::GLGizmoMmuSegmentation(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoPainterBase(parent, icon_filename, sprite_id), m_current_tool(ImGui::CircleButtonIcon) -{} +{ +} void GLGizmoMmuSegmentation::render_painter_gizmo() { @@ -164,12 +167,11 @@ void GLGizmoMmuSegmentation::render_painter_gizmo() void GLGizmoMmuSegmentation::data_changed(bool is_serializing) { GLGizmoPainterBase::data_changed(is_serializing); - if (m_state != On || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptFFF || - wxGetApp().extruders_edited_cnt() <= 1) + if (m_state != On || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptFFF || wxGetApp().extruders_edited_cnt() <= 1) return; - ModelObject* model_object = m_c->selection_info()->model_object(); - int prev_extruders_count = int(m_extruders_colors.size()); + ModelObject* model_object = m_c->selection_info()->model_object(); + int prev_extruders_count = int(m_extruders_colors.size()); if (prev_extruders_count != wxGetApp().filaments_cnt()) { if (wxGetApp().filaments_cnt() > int(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT)) show_notification_extruders_limit_exceeded(); @@ -181,7 +183,8 @@ void GLGizmoMmuSegmentation::data_changed(bool is_serializing) } else if (wxGetApp().plater()->get_extruders_colors() != m_extruders_colors) { this->init_extruders_data(); this->update_triangle_selectors_colors(); - } else if (model_object != nullptr && get_extruder_id_for_volumes(*model_object) != m_volumes_extruder_idxs) { + } + else if (model_object != nullptr && get_extruder_id_for_volumes(*model_object) != m_volumes_extruder_idxs) { this->init_model_triangle_selectors(); } } @@ -196,24 +199,38 @@ bool GLGizmoMmuSegmentation::on_number_key_down(int number) return true; } -bool GLGizmoMmuSegmentation::on_key_down_select_tool_type(int keyCode) -{ - switch (keyCode) { - case 'F': m_current_tool = ImGui::FillButtonIcon; break; - case 'T': m_current_tool = ImGui::TriangleButtonIcon; break; - case 'S': m_current_tool = ImGui::SphereButtonIcon; break; - case 'C': m_current_tool = ImGui::CircleButtonIcon; break; - case 'H': m_current_tool = ImGui::HeightRangeIcon; break; - case 'G': m_current_tool = ImGui::GapFillIcon; break; - default: return false; break; +bool GLGizmoMmuSegmentation::on_key_down_select_tool_type(int keyCode) { + switch (keyCode) + { + case 'F': + m_current_tool = ImGui::FillButtonIcon; + break; + case 'T': + m_current_tool = ImGui::TriangleButtonIcon; + break; + case 'S': + m_current_tool = ImGui::SphereButtonIcon; + break; + case 'C': + m_current_tool = ImGui::CircleButtonIcon; + break; + case 'H': + m_current_tool = ImGui::HeightRangeIcon; + break; + case 'G': + m_current_tool = ImGui::GapFillIcon; + break; + default: + return false; + break; } return true; } -static void render_extruders_combo(const std::string& label, +static void render_extruders_combo(const std::string& label, const std::vector& extruders, - const std::vector& extruders_colors, - size_t& selection_idx) + const std::vector& extruders_colors, + size_t& selection_idx) { assert(!extruders_colors.empty()); assert(extruders_colors.size() == extruders_colors.size()); @@ -231,13 +248,10 @@ static void render_extruders_combo(const std::string& label, selection_out = extruder_idx; ImGui::SameLine(); - ImGuiStyle& style = ImGui::GetStyle(); + ImGuiStyle &style = ImGui::GetStyle(); float height = ImGui::GetTextLineHeight(); - ImGui::GetWindowDrawList()->AddRectFilled(start_position, - ImVec2(start_position.x + height + height / 2, start_position.y + height), - ImGuiWrapper::to_ImU32(extruders_colors[extruder_idx])); - ImGui::GetWindowDrawList()->AddRect(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), - IM_COL32_BLACK); + ImGui::GetWindowDrawList()->AddRectFilled(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), ImGuiWrapper::to_ImU32(extruders_colors[extruder_idx])); + ImGui::GetWindowDrawList()->AddRect(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), IM_COL32_BLACK); ImGui::SetCursorScreenPos(ImVec2(start_position.x + height + height / 2 + style.FramePadding.x, start_position.y)); ImGui::Text("%s", extruders[extruder_idx].c_str()); @@ -248,14 +262,13 @@ static void render_extruders_combo(const std::string& label, } ImVec2 backup_pos = ImGui::GetCursorScreenPos(); - ImGuiStyle& style = ImGui::GetStyle(); + ImGuiStyle &style = ImGui::GetStyle(); ImGui::SetCursorScreenPos(ImVec2(combo_pos.x + style.FramePadding.x, combo_pos.y + style.FramePadding.y)); ImVec2 p = ImGui::GetCursorScreenPos(); float height = ImGui::GetTextLineHeight(); - ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + height + height / 2, p.y + height), - ImGuiWrapper::to_ImU32(extruders_colors[selection_idx])); + ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + height + height / 2, p.y + height), ImGuiWrapper::to_ImU32(extruders_colors[selection_idx])); ImGui::GetWindowDrawList()->AddRect(p, ImVec2(p.x + height + height / 2, p.y + height), IM_COL32_BLACK); ImGui::SetCursorScreenPos(ImVec2(p.x + height + height / 2 + style.FramePadding.x, p.y)); @@ -273,11 +286,11 @@ void GLGizmoMmuSegmentation::show_tooltip_information(float caption_max, float x caption_max += m_imgui->calc_text_size(std::string_view{": "}).x + 15.f; - float scale = m_parent.get_scale(); -#ifdef WIN32 - int dpi = get_dpi_for_window(wxGetApp().GetTopWindow()); - scale *= (float) dpi / (float) DPI_DEFAULT; -#endif // WIN32 + float scale = m_parent.get_scale(); + #ifdef WIN32 + int dpi = get_dpi_for_window(wxGetApp().GetTopWindow()); + scale *= (float) dpi / (float) DPI_DEFAULT; + #endif // WIN32 ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, 0}); // ORCA: Dont add padding @@ -285,7 +298,7 @@ void GLGizmoMmuSegmentation::show_tooltip_information(float caption_max, float x if (ImGui::IsItemHovered()) { ImGui::BeginTooltip2(ImVec2(x, y)); - auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { + auto draw_text_with_caption = [this, &caption_max](const wxString &caption, const wxString &text) { m_imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption); ImGui::SameLine(caption_max); m_imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text); @@ -293,16 +306,22 @@ void GLGizmoMmuSegmentation::show_tooltip_information(float caption_max, float x std::vector tip_items; switch (m_tool_type) { - case ToolType::BRUSH: tip_items = {"paint", "erase", "cursor_size", "clipping_of_view", "toggle_wireframe"}; break; - case ToolType::BUCKET_FILL: tip_items = {"paint", "erase", "smart_fill_angle", "clipping_of_view", "toggle_wireframe"}; break; - case ToolType::SMART_FILL: - // TODO: - break; - case ToolType::GAP_FILL: tip_items = {"gap_area", "toggle_wireframe"}; break; - default: break; + case ToolType::BRUSH: + tip_items = {"paint", "erase", "cursor_size", "clipping_of_view", "toggle_wireframe"}; + break; + case ToolType::BUCKET_FILL: + tip_items = {"paint", "erase", "smart_fill_angle", "clipping_of_view", "toggle_wireframe"}; + break; + case ToolType::SMART_FILL: + // TODO: + break; + case ToolType::GAP_FILL: + tip_items = {"gap_area", "toggle_wireframe"}; + break; + default: + break; } - for (const auto& t : tip_items) - draw_text_with_caption(m_desc.at(t + "_caption") + ": ", m_desc.at(t)); + for (const auto &t : tip_items) draw_text_with_caption(m_desc.at(t + "_caption") + ": ", m_desc.at(t)); ImGui::EndTooltip(); } ImGui::PopStyleVar(2); @@ -310,92 +329,84 @@ void GLGizmoMmuSegmentation::show_tooltip_information(float caption_max, float x void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bottom_limit) { - if (!m_c->selection_info()->model_object()) - return; + if (!m_c->selection_info()->model_object()) return; const float approx_height = m_imgui->scaled(22.0f); - y = std::min(y, bottom_limit - approx_height); + y = std::min(y, bottom_limit - approx_height); GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always); wchar_t old_tool = m_current_tool; // BBS ImGuiWrapper::push_toolbar_style(m_parent.get_scale()); - GizmoImguiBegin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | - ImGuiWindowFlags_NoTitleBar); + GizmoImguiBegin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar); // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: - const float space_size = m_imgui->get_style_scaling() * 8; - const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.5f), - m_imgui->calc_text_size(m_desc.at("reset_direction")).x + m_imgui->scaled(1.5f) + - ImGui::GetStyle().FramePadding.x * 2); - const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.5f); - const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.5f); - const float edge_detect_slider_left = m_imgui->calc_text_size(m_desc.at("edge_detection")).x + m_imgui->scaled(1.f); - const float gap_area_slider_left = m_imgui->calc_text_size(m_desc.at("gap_area")).x + m_imgui->scaled(1.5f) + space_size; + const float space_size = m_imgui->get_style_scaling() * 8; + const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.5f), + m_imgui->calc_text_size(m_desc.at("reset_direction")).x + m_imgui->scaled(1.5f) + ImGui::GetStyle().FramePadding.x * 2); + const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.5f); + const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.5f); + const float edge_detect_slider_left = m_imgui->calc_text_size(m_desc.at("edge_detection")).x + m_imgui->scaled(1.f); + const float gap_area_slider_left = m_imgui->calc_text_size(m_desc.at("gap_area")).x + m_imgui->scaled(1.5f) + space_size; const float height_range_slider_left = m_imgui->calc_text_size(m_desc.at("height_range")).x + m_imgui->scaled(2.f); - const float remove_btn_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); - const float filter_btn_width = m_imgui->calc_text_size(m_desc.at("perform")).x + m_imgui->scaled(1.f); - const float remap_btn_width = m_imgui->calc_text_size(m_desc.at("perform_remap")).x + m_imgui->scaled(1.f); - const float buttons_width = remove_btn_width + filter_btn_width + remap_btn_width + m_imgui->scaled(2.f); + const float remove_btn_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); + const float filter_btn_width = m_imgui->calc_text_size(m_desc.at("perform")).x + m_imgui->scaled(1.f); + const float remap_btn_width = m_imgui->calc_text_size(m_desc.at("perform_remap")).x + m_imgui->scaled(1.f); + const float buttons_width = remove_btn_width + filter_btn_width + remap_btn_width + m_imgui->scaled(2.f); const float minimal_slider_width = m_imgui->scaled(4.f); - const float color_button_width = m_imgui->calc_text_size(std::string_view{""}).x + m_imgui->scaled(1.75f); + const float color_button_width = m_imgui->calc_text_size(std::string_view{""}).x + m_imgui->scaled(1.75f); - float caption_max = 0.f; + float caption_max = 0.f; float total_text_max = 0.f; - for (const auto& t : - std::array{"paint", "erase", "cursor_size", "smart_fill_angle", "height_range", "clipping_of_view"}) { - caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); + for (const auto &t : std::array{"paint", "erase", "cursor_size", "smart_fill_angle", "height_range", "clipping_of_view"}) { + caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); } total_text_max += caption_max + m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f); - const float circle_max_width = std::max(clipping_slider_left, cursor_slider_left); - const float height_max_width = std::max(clipping_slider_left, height_range_slider_left); + const float circle_max_width = std::max(clipping_slider_left,cursor_slider_left); + const float height_max_width = std::max(clipping_slider_left,height_range_slider_left); const float sliders_left_width = std::max(smart_fill_slider_left, - std::max(cursor_slider_left, - std::max(edge_detect_slider_left, - std::max(gap_area_slider_left, - std::max(height_range_slider_left, clipping_slider_left))))) + - space_size; - const float slider_icon_width = m_imgui->get_slider_icon_size().x; - float window_width = minimal_slider_width + sliders_left_width + slider_icon_width; - const int max_filament_items_per_line = 8; - const float empty_button_width = m_imgui->calc_button_size("").x; - const float filament_item_width = empty_button_width + m_imgui->scaled(1.5f); + std::max(cursor_slider_left, std::max(edge_detect_slider_left, std::max(gap_area_slider_left, std::max(height_range_slider_left, + clipping_slider_left))))) + space_size; + const float slider_icon_width = m_imgui->get_slider_icon_size().x; + float window_width = minimal_slider_width + sliders_left_width + slider_icon_width; + const int max_filament_items_per_line = 8; + const float empty_button_width = m_imgui->calc_button_size("").x; + const float filament_item_width = empty_button_width + m_imgui->scaled(1.5f); window_width = std::max(window_width, total_text_max); window_width = std::max(window_width, buttons_width); window_width = std::max(window_width, max_filament_items_per_line * filament_item_width + +m_imgui->scaled(0.5f)); - const float sliders_width = m_imgui->scaled(7.0f); + const float sliders_width = m_imgui->scaled(7.0f); const float drag_left_width = ImGui::GetStyle().WindowPadding.x + sliders_width - space_size; - const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - ImVec2 pos = ImGui::GetCursorScreenPos(); - static float color_button_high = 25.0; - draw_list->AddRectFilled({pos.x - 10.0f, pos.y - 7.0f}, {pos.x + window_width + ImGui::GetFrameHeight(), pos.y + color_button_high}, - ImGui::GetColorU32(ImGuiCol_FrameBgActive, 1.0f), 5.0f); + const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; + ImDrawList * draw_list = ImGui::GetWindowDrawList(); + ImVec2 pos = ImGui::GetCursorScreenPos(); + static float color_button_high = 25.0; + draw_list->AddRectFilled({pos.x - 10.0f, pos.y - 7.0f}, {pos.x + window_width + ImGui::GetFrameHeight(), pos.y + color_button_high}, ImGui::GetColorU32(ImGuiCol_FrameBgActive, 1.0f), 5.0f); float color_button = ImGui::GetCursorPos().y; m_imgui->text(m_desc.at("filaments")); - float start_pos_x = ImGui::GetCursorPos().x; - const ImVec2 max_label_size = ImGui::CalcTextSize("99", NULL, true); - const float item_spacing = m_imgui->scaled(0.8f); - size_t n_extruder_colors = std::min((size_t) EnforcerBlockerType::ExtruderMax, m_extruders_colors.size()); + float start_pos_x = ImGui::GetCursorPos().x; + const ImVec2 max_label_size = ImGui::CalcTextSize("99", NULL, true); + const float item_spacing = m_imgui->scaled(0.8f); + size_t n_extruder_colors = std::min((size_t)EnforcerBlockerType::ExtruderMax, m_extruders_colors.size()); for (int extruder_idx = 0; extruder_idx < n_extruder_colors; extruder_idx++) { - const ColorRGBA& extruder_color = m_extruders_colors[extruder_idx]; + const ColorRGBA &extruder_color = m_extruders_colors[extruder_idx]; ImVec4 color_vec = ImGuiWrapper::to_ImVec4(extruder_color); - std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx); - std::string item_text = std::to_string(extruder_idx + 1); - const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); + std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx); + std::string item_text = std::to_string(extruder_idx + 1); + const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); - const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f), 0.f); + const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f),0.f); float button_offset = start_pos_x; if (extruder_idx % max_filament_items_per_line != 0) { @@ -404,37 +415,32 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott } // draw filament background - ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | - ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; - if (m_selected_extruder_idx != extruder_idx) - flags |= ImGuiColorEditFlags_NoBorder; -#ifdef __APPLE__ - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); // ORCA use orca color for selected filament border - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0); - bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); -#else - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); // ORCA use orca color for selected filament border - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0); - bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); -#endif + ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; + if (m_selected_extruder_idx != extruder_idx) flags |= ImGuiColorEditFlags_NoBorder; + #ifdef __APPLE__ + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); // ORCA use orca color for selected filament border + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0); + bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(1); + #else + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); // ORCA use orca color for selected filament border + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0); + bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(1); + #endif color_button_high = ImGui::GetCursorPos().y - color_button - 2.0; - if (color_picked) { - m_selected_extruder_idx = extruder_idx; - } + if (color_picked) { m_selected_extruder_idx = extruder_idx; } - if (extruder_idx < 16 && ImGui::IsItemHovered()) - m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width); + if (extruder_idx < 16 && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width); // draw filament id float gray = 0.299 * extruder_color.r() + 0.587 * extruder_color.g() + 0.114 * extruder_color.b(); ImGui::SameLine(button_offset + (button_size.x - label_size.x) / 2.f); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {10.0, 15.0}); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {10.0,15.0}); if (gray * 255.f < 80.f) ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), "%s", item_text.c_str()); else @@ -442,42 +448,38 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::PopStyleVar(); } - // ImGui::NewLine(); + //ImGui::NewLine(); ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.1)); m_imgui->text(m_desc.at("tool_type")); std::array tool_ids; - tool_ids = {ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::TriangleButtonIcon, - ImGui::HeightRangeIcon, ImGui::FillButtonIcon, ImGui::GapFillIcon}; + tool_ids = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::TriangleButtonIcon, ImGui::HeightRangeIcon, ImGui::FillButtonIcon, ImGui::GapFillIcon }; std::array icons; if (m_is_dark_mode) - icons = {ImGui::CircleButtonDarkIcon, ImGui::SphereButtonDarkIcon, ImGui::TriangleButtonDarkIcon, - ImGui::HeightRangeDarkIcon, ImGui::FillButtonDarkIcon, ImGui::GapFillDarkIcon}; + icons = { ImGui::CircleButtonDarkIcon, ImGui::SphereButtonDarkIcon, ImGui::TriangleButtonDarkIcon, ImGui::HeightRangeDarkIcon, ImGui::FillButtonDarkIcon, ImGui::GapFillDarkIcon }; else - icons = {ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::TriangleButtonIcon, - ImGui::HeightRangeIcon, ImGui::FillButtonIcon, ImGui::GapFillIcon}; - std::array tool_tips = {_L("Circle"), _L("Sphere"), _L("Triangle"), _L("Height Range"), _L("Fill"), _L("Gap Fill")}; + icons = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::TriangleButtonIcon, ImGui::HeightRangeIcon, ImGui::FillButtonIcon, ImGui::GapFillIcon }; + std::array tool_tips = { _L("Circle"), _L("Sphere"), _L("Triangle"), _L("Height Range"), _L("Fill"), _L("Gap Fill") }; for (int i = 0; i < tool_ids.size(); i++) { std::string str_label = std::string(""); std::wstring btn_name = icons[i] + boost::nowide::widen(str_label); - if (i != 0) - ImGui::SameLine((empty_button_width + m_imgui->scaled(1.75f)) * i + m_imgui->scaled(1.5f)); + if (i != 0) ImGui::SameLine((empty_button_width + m_imgui->scaled(1.75f)) * i + m_imgui->scaled(1.5f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.f, 0.f, 0.f)); // ORCA Removes button background on dark mode - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f)); // ORCA Fixes icon rendered without colors while using Light theme + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.f, 0.f, 0.f)); // ORCA Removes button background on dark mode + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f)); // ORCA Fixes icon rendered without colors while using Light theme if (m_current_tool == tool_ids[i]) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, - ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.f, 0.59f, 0.53f, 0.30f)); // ORCA use orca color for selected tool / brush - ImGui::PushStyleColor(ImGuiCol_Border, ImGuiWrapper::COL_ORCA); // ORCA use orca color for border on selected tool / brush + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.f, 0.59f, 0.53f, 0.25f)); // ORCA use orca color for selected tool / brush + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.f, 0.59f, 0.53f, 0.30f)); // ORCA use orca color for selected tool / brush + ImGui::PushStyleColor(ImGuiCol_Border, ImGuiWrapper::COL_ORCA); // ORCA use orca color for border on selected tool / brush ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0); } bool btn_clicked = ImGui::Button(into_u8(btn_name).c_str()); - if (m_current_tool == tool_ids[i]) { + if (m_current_tool == tool_ids[i]) + { ImGui::PopStyleColor(4); ImGui::PopStyleVar(2); } @@ -486,7 +488,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (btn_clicked && m_current_tool != tool_ids[i]) { m_current_tool = tool_ids[i]; - for (auto& triangle_selector : m_triangle_selectors) { + for (auto &triangle_selector : m_triangle_selectors) { triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->request_update_render_data(); } @@ -506,7 +508,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (m_current_tool == ImGui::CircleButtonIcon) m_cursor_type = TriangleSelector::CursorType::CIRCLE; else - m_cursor_type = TriangleSelector::CursorType::SPHERE; + m_cursor_type = TriangleSelector::CursorType::SPHERE; m_tool_type = ToolType::BRUSH; ImGui::AlignTextToFramePadding(); @@ -522,9 +524,12 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (m_c->object_clipper()->get_position() == 0.f) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("clipping_of_view")); - } else { + } + else { if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this]() { m_c->object_clipper()->set_position_by_ratio(-1., false); }); + wxGetApp().CallAfter([this]() { + m_c->object_clipper()->set_position_by_ratio(-1., false); + }); } } @@ -536,9 +541,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::PushItemWidth(1.5 * slider_icon_width); bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { - m_c->object_clipper()->set_position_by_ratio(clp_dist, true); - } + if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); } } else if (m_current_tool == ImGui::TriangleButtonIcon) { m_cursor_type = TriangleSelector::CursorType::POINTER; @@ -547,9 +550,12 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (m_c->object_clipper()->get_position() == 0.f) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("clipping_of_view")); - } else { + } + else { if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this]() { m_c->object_clipper()->set_position_by_ratio(-1., false); }); + wxGetApp().CallAfter([this]() { + m_c->object_clipper()->set_position_by_ratio(-1., false); + }); } } @@ -561,9 +567,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::PushItemWidth(1.5 * slider_icon_width); bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { - m_c->object_clipper()->set_position_by_ratio(clp_dist, true); - } + if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); } } else if (m_current_tool == ImGui::FillButtonIcon) { m_cursor_type = TriangleSelector::CursorType::POINTER; @@ -573,14 +577,12 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (m_detect_geometry_edge) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc["smart_fill_angle"]); - std::string format_str = std::string("%.f") + I18N::translate_utf8("°", - "Face angle threshold," - "placed after the number with no whitespace in between."); + std::string format_str = std::string("%.f") + I18N::translate_utf8("°", "Face angle threshold," + "placed after the number with no whitespace in between."); ImGui::SameLine(sliders_left_width); ImGui::PushItemWidth(sliders_width); - if (m_imgui->bbl_slider_float_style("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, - format_str.data(), 1.0f, true)) - for (auto& triangle_selector : m_triangle_selectors) { + if (m_imgui->bbl_slider_float_style("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data(), 1.0f, true)) + for (auto &triangle_selector : m_triangle_selectors) { triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->request_update_render_data(); } @@ -595,9 +597,12 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (m_c->object_clipper()->get_position() == 0.f) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("clipping_of_view")); - } else { + } + else { if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this]() { m_c->object_clipper()->set_position_by_ratio(-1., false); }); + wxGetApp().CallAfter([this]() { + m_c->object_clipper()->set_position_by_ratio(-1., false); + }); } } @@ -609,9 +614,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::PushItemWidth(1.5 * slider_icon_width); bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { - m_c->object_clipper()->set_position_by_ratio(clp_dist, true); - } + if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true);} } else if (m_current_tool == ImGui::HeightRangeIcon) { m_tool_type = ToolType::BRUSH; @@ -620,11 +623,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott m_imgui->text(m_desc["height_range"] + ":"); ImGui::SameLine(height_max_width); ImGui::PushItemWidth(sliders_width); - std::string format_str = std::string("%.2f") + I18N::translate_utf8("mm", - "Height range," - "Facet in [cursor z, cursor z + height] will be selected."); - m_imgui->bbl_slider_float_style("##cursor_height", &m_cursor_height, CursorHeightMin, CursorHeightMax, format_str.data(), 1.0f, - true); + std::string format_str = std::string("%.2f") + I18N::translate_utf8("mm", "Height range," "Facet in [cursor z, cursor z + height] will be selected."); + m_imgui->bbl_slider_float_style("##cursor_height", &m_cursor_height, CursorHeightMin, CursorHeightMax, format_str.data(), 1.0f, true); ImGui::SameLine(drag_left_width + height_max_width); ImGui::PushItemWidth(1.5 * slider_icon_width); ImGui::BBLDragFloat("##cursor_height_input", &m_cursor_height, 0.05f, 0.0f, 0.0f, "%.2f"); @@ -633,9 +633,12 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (m_c->object_clipper()->get_position() == 0.f) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("clipping_of_view")); - } else { + } + else { if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this]() { m_c->object_clipper()->set_position_by_ratio(-1., false); }); + wxGetApp().CallAfter([this]() { + m_c->object_clipper()->set_position_by_ratio(-1., false); + }); } } @@ -647,40 +650,37 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::PushItemWidth(1.5 * slider_icon_width); bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { - m_c->object_clipper()->set_position_by_ratio(clp_dist, true); - } - } else if (m_current_tool == ImGui::GapFillIcon) { - m_tool_type = ToolType::GAP_FILL; + if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); } + } + else if (m_current_tool == ImGui::GapFillIcon) { + m_tool_type = ToolType::GAP_FILL; m_cursor_type = TriangleSelector::CursorType::POINTER; ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc["gap_area"] + ":"); ImGui::SameLine(gap_area_slider_left); ImGui::PushItemWidth(sliders_width); - std::string format_str = std::string("%.2f") + - I18N::translate_utf8("", "Triangle patch area threshold," - "triangle patch will be merged to neighbor if its area is less than threshold"); - m_imgui->bbl_slider_float_style("##gap_area", &TriangleSelectorPatch::gap_area, TriangleSelectorPatch::GapAreaMin, - TriangleSelectorPatch::GapAreaMax, format_str.data(), 1.0f, true); + std::string format_str = std::string("%.2f") + I18N::translate_utf8("", "Triangle patch area threshold,""triangle patch will be merged to neighbor if its area is less than threshold"); + m_imgui->bbl_slider_float_style("##gap_area", &TriangleSelectorPatch::gap_area, TriangleSelectorPatch::GapAreaMin, TriangleSelectorPatch::GapAreaMax, format_str.data(), 1.0f, true); ImGui::SameLine(drag_left_width + gap_area_slider_left); ImGui::PushItemWidth(1.5 * slider_icon_width); ImGui::BBLDragFloat("##gap_area_input", &TriangleSelectorPatch::gap_area, 0.05f, 0.0f, 0.0f, "%.2f"); } ImGui::Separator(); - if (m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only)) { - if (m_vertical_only) { + if(m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only)){ + if(m_vertical_only){ m_horizontal_only = false; } } - if (m_imgui->bbl_checkbox(_L("Horizontal"), m_horizontal_only)) { - if (m_horizontal_only) { + if(m_imgui->bbl_checkbox(_L("Horizontal"), m_horizontal_only)){ + if(m_horizontal_only){ m_vertical_only = false; } } ImGui::Separator(); + if (m_imgui->button(m_desc.at("perform_remap"))) { m_show_filament_remap_ui = !m_show_filament_remap_ui; if (m_show_filament_remap_ui) { @@ -690,7 +690,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott m_extruder_remap[i] = i; } } - + // Render filament swap UI if enabled if (m_show_filament_remap_ui) { ImGui::Separator(); @@ -702,7 +702,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y; show_tooltip_information(caption_max, x, get_cur_y); - float f_scale = m_parent.get_gizmos_manager().get_layout_scale(); + float f_scale =m_parent.get_gizmos_manager().get_layout_scale(); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale)); ImGui::SameLine(); @@ -725,9 +725,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (m_imgui->button(m_desc.at("remove_all"))) { Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Reset selection", UndoRedo::SnapshotType::GizmoAction); - ModelObject* mo = m_c->selection_info()->model_object(); + ModelObject * mo = m_c->selection_info()->model_object(); int idx = -1; - for (ModelVolume* mv : mo->volumes) + for (ModelVolume *mv : mo->volumes) if (mv->is_model_part()) { ++idx; m_triangle_selectors[idx]->reset(); @@ -744,21 +744,22 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGuiWrapper::pop_toolbar_style(); } + void GLGizmoMmuSegmentation::update_model_object() { - bool updated = false; - ModelObject* mo = m_c->selection_info()->model_object(); - int idx = -1; + bool updated = false; + ModelObject* mo = m_c->selection_info()->model_object(); + int idx = -1; for (ModelVolume* mv : mo->volumes) { - if (!mv->is_model_part()) + if (! mv->is_model_part()) continue; ++idx; updated |= mv->mmu_segmentation_facets.set(*m_triangle_selectors[idx].get()); } if (updated) { - const ModelObjectPtrs& mos = wxGetApp().model().objects; - size_t obj_idx = std::find(mos.begin(), mos.end(), mo) - mos.begin(); + const ModelObjectPtrs &mos = wxGetApp().model().objects; + size_t obj_idx = std::find(mos.begin(), mos.end(), mo) - mos.begin(); wxGetApp().obj_list()->update_info_items(obj_idx); wxGetApp().plater()->get_partplate_list().notify_instance_update(obj_idx, 0); m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); @@ -767,23 +768,23 @@ void GLGizmoMmuSegmentation::update_model_object() void GLGizmoMmuSegmentation::init_model_triangle_selectors() { - const ModelObject* mo = m_c->selection_info()->model_object(); + const ModelObject *mo = m_c->selection_info()->model_object(); m_triangle_selectors.clear(); m_volumes_extruder_idxs.clear(); // Don't continue when extruders colors are not initialized - if (m_extruders_colors.empty()) + if(m_extruders_colors.empty()) return; // BBS: Don't continue when model object is null if (mo == nullptr) return; - for (const ModelVolume* mv : mo->volumes) { + for (const ModelVolume *mv : mo->volumes) { if (!mv->is_model_part()) continue; - int extruder_idx = (mv->extruder_id() > 0) ? mv->extruder_id() - 1 : 0; + int extruder_idx = (mv->extruder_id() > 0) ? mv->extruder_id() - 1 : 0; std::vector ebt_colors; ebt_colors.push_back(m_extruders_colors[size_t(extruder_idx)]); ebt_colors.insert(ebt_colors.end(), m_extruders_colors.begin(), m_extruders_colors.end()); @@ -792,7 +793,7 @@ void GLGizmoMmuSegmentation::init_model_triangle_selectors() const TriangleMesh* mesh = &mv->mesh(); m_triangle_selectors.emplace_back(std::make_unique(*mesh, ebt_colors, 0.2)); // Reset of TriangleSelector is done inside TriangleSelectorMmGUI's constructor, so we don't need it to perform it again in deserialize(). - EnforcerBlockerType max_ebt = (EnforcerBlockerType) std::min(m_extruders_colors.size(), (size_t) EnforcerBlockerType::ExtruderMax); + EnforcerBlockerType max_ebt = (EnforcerBlockerType)std::min(m_extruders_colors.size(), (size_t)EnforcerBlockerType::ExtruderMax); m_triangle_selectors.back()->deserialize(mv->mmu_segmentation_facets.get_data(), false, max_ebt); m_triangle_selectors.back()->request_update_render_data(); m_triangle_selectors.back()->set_wireframe_needed(true); @@ -803,9 +804,9 @@ void GLGizmoMmuSegmentation::init_model_triangle_selectors() void GLGizmoMmuSegmentation::update_triangle_selectors_colors() { for (int i = 0; i < m_triangle_selectors.size(); i++) { - TriangleSelectorPatch* selector = dynamic_cast(m_triangle_selectors[i].get()); - int extruder_idx = m_volumes_extruder_idxs[i]; - int extruder_color_idx = std::max(0, extruder_idx - 1); + TriangleSelectorPatch* selector = dynamic_cast(m_triangle_selectors[i].get()); + int extruder_idx = m_volumes_extruder_idxs[i]; + int extruder_color_idx = std::max(0, extruder_idx - 1); std::vector ebt_colors; ebt_colors.push_back(m_extruders_colors[extruder_color_idx]); ebt_colors.insert(ebt_colors.end(), m_extruders_colors.begin(), m_extruders_colors.end()); @@ -838,7 +839,10 @@ void GLGizmoMmuSegmentation::tool_changed(wchar_t old_tool, wchar_t new_tool) } } -PainterGizmoType GLGizmoMmuSegmentation::get_painter_type() const { return PainterGizmoType::MM_SEGMENTATION; } +PainterGizmoType GLGizmoMmuSegmentation::get_painter_type() const +{ + return PainterGizmoType::MM_SEGMENTATION; +} // BBS ColorRGBA GLGizmoMmuSegmentation::get_cursor_hover_color() const @@ -855,10 +859,9 @@ void GLGizmoMmuSegmentation::on_set_state() if (get_state() == Off) { ModelObject* mo = m_c->selection_info()->model_object(); - if (mo) - Slic3r::save_object_mesh(*mo); + if (mo) Slic3r::save_object_mesh(*mo); m_parent.post_event(SimpleEvent(EVT_GLCANVAS_FORCE_UPDATE)); - if (m_current_tool == ImGui::GapFillIcon) { // exit gap fill + if (m_current_tool == ImGui::GapFillIcon) {//exit gap fill m_current_tool = ImGui::CircleButtonIcon; } } @@ -870,18 +873,17 @@ wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GL if (shift_down) action_name = _L("Remove painted color"); else { - action_name = GUI::format(_L("Painted using: Filament %1%"), filament_index_from_zero_based(m_selected_extruder_idx)); + action_name = GUI::format(_L("Painted using: Filament %1%"), filament_index_from_zero_based(m_selected_extruder_idx)); } return action_name; } -void GLMmSegmentationGizmo3DScene::release_geometry() -{ +void GLMmSegmentationGizmo3DScene::release_geometry() { if (this->vertices_VBO_id) { glsafe(::glDeleteBuffers(1, &this->vertices_VBO_id)); this->vertices_VBO_id = 0; } - for (auto& triangle_indices_VBO_id : triangle_indices_VBO_ids) { + for(auto &triangle_indices_VBO_id : triangle_indices_VBO_ids) { glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id)); triangle_indices_VBO_id = 0; } @@ -928,12 +930,13 @@ void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_VBO_id)); const GLint position_id = shader->get_attrib_location("v_position"); if (position_id != -1) { - glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (GLvoid*) 0)); + glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (GLvoid*)0)); glsafe(::glEnableVertexAttribArray(position_id)); } // Render using the Vertex Buffer Objects. - if (this->triangle_indices_VBO_ids[triangle_indices_idx] != 0 && this->triangle_indices_sizes[triangle_indices_idx] > 0) { + if (this->triangle_indices_VBO_ids[triangle_indices_idx] != 0 && + this->triangle_indices_sizes[triangle_indices_idx] > 0) { glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_ids[triangle_indices_idx])); glsafe(::glDrawElements(GL_TRIANGLES, GLsizei(this->triangle_indices_sizes[triangle_indices_idx]), GL_UNSIGNED_INT, nullptr)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); @@ -992,8 +995,7 @@ void GLMmSegmentationGizmo3DScene::finalize_triangle_indices() { triangle_indices_VBO_ids.resize(this->triangle_patches.size()); triangle_indices_sizes.resize(this->triangle_patches.size()); - assert(std::all_of(triangle_indices_VBO_ids.cbegin(), triangle_indices_VBO_ids.cend(), - [](const auto& ti_VBO_id) { return ti_VBO_id == 0; })); + assert(std::all_of(triangle_indices_VBO_ids.cbegin(), triangle_indices_VBO_ids.cend(), [](const auto &ti_VBO_id) { return ti_VBO_id == 0; })); for (size_t buffer_idx = 0; buffer_idx < this->triangle_patches.size(); ++buffer_idx) { std::vector& triangle_indices = this->triangle_patches[buffer_idx].triangle_indices; @@ -1010,123 +1012,125 @@ void GLMmSegmentationGizmo3DScene::finalize_triangle_indices() void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float max_tooltip_width) { - size_t n_extr = std::min((size_t) EnforcerBlockerType::ExtruderMax, m_extruders_colors.size()); + size_t n_extr = std::min((size_t)EnforcerBlockerType::ExtruderMax, m_extruders_colors.size()); const ImVec2 max_label_size = ImGui::CalcTextSize("99", NULL, true); const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f), 0.f); - for (int src = 0; src < (int) n_extr; ++src) { - const ColorRGBA& src_col = m_extruders_colors[src]; // keep for text contrast - const ColorRGBA& dst_col = m_extruders_colors[m_extruder_remap[src]]; - ImVec4 col_vec = ImGuiWrapper::to_ImVec4(dst_col); + for (int src = 0; src < (int)n_extr; ++src) { + const ColorRGBA &src_col = m_extruders_colors[src]; // keep for text contrast + const ColorRGBA &dst_col = m_extruders_colors[m_extruder_remap[src]]; + ImVec4 col_vec = ImGuiWrapper::to_ImVec4(dst_col); - if (src) - ImGui::SameLine(); + if (src) ImGui::SameLine(); std::string btn_id = "##remap_src_" + std::to_string(src); - - ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | - ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; - if (m_selected_extruder_idx != src) - flags |= ImGuiColorEditFlags_NoBorder; - -#ifdef __APPLE__ - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0); - bool clicked = ImGui::ColorButton(btn_id.c_str(), col_vec, flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); -#else - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0); - bool clicked = ImGui::ColorButton(btn_id.c_str(), col_vec, flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); -#endif + + ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | + ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoPicker | + ImGuiColorEditFlags_NoTooltip; + if (m_selected_extruder_idx != src) flags |= ImGuiColorEditFlags_NoBorder; + + #ifdef __APPLE__ + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0); + bool clicked = ImGui::ColorButton(btn_id.c_str(), col_vec, flags, button_size); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(1); + #else + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0); + bool clicked = ImGui::ColorButton(btn_id.c_str(), col_vec, flags, button_size); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(1); + #endif // overlay destination number with proper contrast calculation std::string dst_txt = std::to_string(m_extruder_remap[src] + 1); - float gray = 0.299f * dst_col.r() + 0.587f * dst_col.g() + 0.114f * dst_col.b(); - ImVec2 txt_sz = ImGui::CalcTextSize(dst_txt.c_str()); - ImVec2 pos = ImGui::GetItemRectMin(); - ImVec2 size = ImGui::GetItemRectSize(); - + float gray = 0.299f * dst_col.r() + 0.587f * dst_col.g() + 0.114f * dst_col.b(); + ImVec2 txt_sz = ImGui::CalcTextSize(dst_txt.c_str()); + ImVec2 pos = ImGui::GetItemRectMin(); + ImVec2 size = ImGui::GetItemRectSize(); + if (gray * 255.f < 80.f) - ImGui::GetWindowDrawList()->AddText(ImVec2(pos.x + (size.x - txt_sz.x) * 0.5f, pos.y + (size.y - txt_sz.y) * 0.5f), - IM_COL32(255, 255, 255, 255), dst_txt.c_str()); + ImGui::GetWindowDrawList()->AddText( + ImVec2(pos.x + (size.x - txt_sz.x) * 0.5f, pos.y + (size.y - txt_sz.y) * 0.5f), + IM_COL32(255,255,255,255), dst_txt.c_str()); else - ImGui::GetWindowDrawList()->AddText(ImVec2(pos.x + (size.x - txt_sz.x) * 0.5f, pos.y + (size.y - txt_sz.y) * 0.5f), - IM_COL32(0, 0, 0, 255), dst_txt.c_str()); + ImGui::GetWindowDrawList()->AddText( + ImVec2(pos.x + (size.x - txt_sz.x) * 0.5f, pos.y + (size.y - txt_sz.y) * 0.5f), + IM_COL32(0,0,0,255), dst_txt.c_str()); // popup with possible destinations std::string pop_id = "popup_" + std::to_string(src); if (clicked) { // Calculate popup position centered below the current button - ImVec2 button_pos = ImGui::GetItemRectMin(); + ImVec2 button_pos = ImGui::GetItemRectMin(); ImVec2 button_size = ImGui::GetItemRectSize(); ImVec2 popup_pos(button_pos.x + button_size.x * 0.5f, button_pos.y + button_size.y); - + // Set popup styling BEFORE opening popup ImGui::SetNextWindowPos(popup_pos, ImGuiCond_Appearing, ImVec2(0.5f, -0.1f)); ImGui::SetNextWindowBgAlpha(1.0f); // Ensure full opacity ImGui::OpenPopup(pop_id.c_str()); } - + // Apply popup styling before BeginPopup using standard Orca colors ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding, 4.0f); ImGui::PushStyleVar(ImGuiStyleVar_PopupBorderSize, 1.0f); ImGui::PushStyleColor(ImGuiCol_PopupBg, m_is_dark_mode ? ImGuiWrapper::COL_WINDOW_BG_DARK : ImGuiWrapper::COL_WINDOW_BG); ImGui::PushStyleColor(ImGuiCol_Border, m_is_dark_mode ? ImVec4(0.5f, 0.5f, 0.5f, 1.0f) : ImVec4(0.6f, 0.6f, 0.6f, 1.0f)); - + if (ImGui::BeginPopup(pop_id.c_str())) { - for (int dst = 0; dst < (int) n_extr; ++dst) { - const ColorRGBA& dst_col_popup = m_extruders_colors[dst]; - ImVec4 dst_vec = ImGuiWrapper::to_ImVec4(dst_col_popup); - if (dst) - ImGui::SameLine(); + + for (int dst = 0; dst < (int)n_extr; ++dst) { + const ColorRGBA &dst_col_popup = m_extruders_colors[dst]; + ImVec4 dst_vec = ImGuiWrapper::to_ImVec4(dst_col_popup); + if (dst) ImGui::SameLine(); std::string dst_btn = "##dst_" + std::to_string(src) + "_" + std::to_string(dst); - + // Apply same styling to destination buttons - ImGuiColorEditFlags dst_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | - ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; + ImGuiColorEditFlags dst_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | + ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoPicker | + ImGuiColorEditFlags_NoTooltip; // Show border for currently selected destination filament - if (m_extruder_remap[src] != dst) - dst_flags |= ImGuiColorEditFlags_NoBorder; - -#ifdef __APPLE__ - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0); - bool dst_clicked = ImGui::ColorButton(dst_btn.c_str(), dst_vec, dst_flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); -#else - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0); - bool dst_clicked = ImGui::ColorButton(dst_btn.c_str(), dst_vec, dst_flags, button_size); - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(1); -#endif - + if (m_extruder_remap[src] != dst) dst_flags |= ImGuiColorEditFlags_NoBorder; + + #ifdef __APPLE__ + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0); + bool dst_clicked = ImGui::ColorButton(dst_btn.c_str(), dst_vec, dst_flags, button_size); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(1); + #else + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0); + bool dst_clicked = ImGui::ColorButton(dst_btn.c_str(), dst_vec, dst_flags, button_size); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(1); + #endif + // overlay destination number on popup buttons std::string dst_num_txt = std::to_string(dst + 1); - float dst_gray = 0.299f * dst_col_popup.r() + 0.587f * dst_col_popup.g() + 0.114f * dst_col_popup.b(); - ImVec2 dst_txt_sz = ImGui::CalcTextSize(dst_num_txt.c_str()); - ImVec2 dst_pos = ImGui::GetItemRectMin(); - ImVec2 dst_size = ImGui::GetItemRectSize(); - + float dst_gray = 0.299f * dst_col_popup.r() + 0.587f * dst_col_popup.g() + 0.114f * dst_col_popup.b(); + ImVec2 dst_txt_sz = ImGui::CalcTextSize(dst_num_txt.c_str()); + ImVec2 dst_pos = ImGui::GetItemRectMin(); + ImVec2 dst_size = ImGui::GetItemRectSize(); + if (dst_gray * 255.f < 80.f) - ImGui::GetWindowDrawList()->AddText(ImVec2(dst_pos.x + (dst_size.x - dst_txt_sz.x) * 0.5f, - dst_pos.y + (dst_size.y - dst_txt_sz.y) * 0.5f), - IM_COL32(255, 255, 255, 255), dst_num_txt.c_str()); + ImGui::GetWindowDrawList()->AddText( + ImVec2(dst_pos.x + (dst_size.x - dst_txt_sz.x) * 0.5f, dst_pos.y + (dst_size.y - dst_txt_sz.y) * 0.5f), + IM_COL32(255,255,255,255), dst_num_txt.c_str()); else - ImGui::GetWindowDrawList()->AddText(ImVec2(dst_pos.x + (dst_size.x - dst_txt_sz.x) * 0.5f, - dst_pos.y + (dst_size.y - dst_txt_sz.y) * 0.5f), - IM_COL32(0, 0, 0, 255), dst_num_txt.c_str()); - - if (dst_clicked) { + ImGui::GetWindowDrawList()->AddText( + ImVec2(dst_pos.x + (dst_size.x - dst_txt_sz.x) * 0.5f, dst_pos.y + (dst_size.y - dst_txt_sz.y) * 0.5f), + IM_COL32(0,0,0,255), dst_num_txt.c_str()); + + if (dst_clicked) + { m_extruder_remap[src] = dst; // update the source button color immediately ImGui::CloseCurrentPopup(); @@ -1134,7 +1138,7 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float } ImGui::EndPopup(); } - + // Clean up popup styling (always pop, whether popup was open or not) ImGui::PopStyleColor(2); // PopupBg and Border ImGui::PopStyleVar(2); // PopupRounding and PopupBorderSize @@ -1157,54 +1161,54 @@ void GLGizmoMmuSegmentation::remap_filament_assignments() if (m_extruder_remap.empty()) return; - constexpr size_t MAX_EBT = (size_t) EnforcerBlockerType::ExtruderMax; + constexpr size_t MAX_EBT = (size_t)EnforcerBlockerType::ExtruderMax; EnforcerBlockerStateMap state_map; // identity mapping by default for (size_t i = 0; i <= MAX_EBT; ++i) state_map[i] = static_cast(i); - size_t n_extr = std::min(m_extruder_remap.size(), MAX_EBT); + size_t n_extr = std::min(m_extruder_remap.size(), MAX_EBT); const int start_extruder = (int) EnforcerBlockerType::Extruder1; - bool any_change = false; + bool any_change = false; for (size_t src = 0; src < n_extr; ++src) { size_t dst = m_extruder_remap[src]; if (dst != src) { - state_map[src + start_extruder] = static_cast(dst + start_extruder); + state_map[src+start_extruder] = static_cast(dst+start_extruder); if (src == 0) state_map[0] = static_cast(dst + start_extruder); - any_change = true; + any_change = true; } } if (!any_change) return; - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Remap filament assignments", UndoRedo::SnapshotType::GizmoAction); + Plater::TakeSnapshot snapshot(wxGetApp().plater(), + "Remap filament assignments", + UndoRedo::SnapshotType::GizmoAction); - bool updated = false; - int idx = -1; - ModelObject* mo = m_c->selection_info()->model_object(); - if (!mo) - return; + bool updated = false; + int idx = -1; + ModelObject* mo = m_c->selection_info()->model_object(); + if (!mo) return; for (ModelVolume* mv : mo->volumes) { - if (!mv->is_model_part()) - continue; + if (!mv->is_model_part()) continue; ++idx; TriangleSelectorGUI* ts = m_triangle_selectors[idx].get(); - if (!ts) - continue; + if (!ts) continue; ts->remap_triangle_state(state_map); ts->request_update_render_data(true); updated = true; } if (updated) { - wxGetApp().plater()->get_notification_manager()->push_notification(_L("Filament remapping finished.").ToStdString()); + wxGetApp().plater()->get_notification_manager()->push_notification( + _L("Filament remapping finished.").ToStdString()); update_model_object(); m_parent.set_as_dirty(); } } -} // namespace Slic3r::GUI +} // namespace Slic3r From 4ed2dc1fda0e52b1757d8ad74040d250b793883b Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 07:40:19 -0500 Subject: [PATCH 09/57] Handle missing bitmaps gracefully --- src/slic3r/GUI/wxExtensions.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 1a6037184d..3397ce8128 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -465,7 +465,7 @@ wxBitmap create_scaled_bitmap( const std::string& bmp_name_in, if (bmp == nullptr) { // Neither SVG nor PNG has been found, raise error BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Could not load bitmap: " << bmp_name; - throw Slic3r::RuntimeError("Could not load bitmap: " + bmp_name); + return wxNullBitmap; } return *bmp; @@ -485,7 +485,7 @@ wxBitmap create_scaled_bitmap2(const std::string& bmp_name_in, Slic3r::GUI::Bitm if (bmp == nullptr) { // No SVG found BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Could not load bitmap: " << bmp_name; - throw Slic3r::RuntimeError("Could not load bitmap: " + bmp_name); + return wxNullBitmap; } return *bmp; } @@ -1363,4 +1363,3 @@ void ImageTransientPopup::OnMouse(wxMouseEvent &event) - From 2ff0399446a190ed339215ad454df35dfd98d519 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 02:46:13 -1000 Subject: [PATCH 10/57] Revert "Handle missing bitmaps gracefully" --- src/slic3r/GUI/wxExtensions.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 3397ce8128..1a6037184d 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -465,7 +465,7 @@ wxBitmap create_scaled_bitmap( const std::string& bmp_name_in, if (bmp == nullptr) { // Neither SVG nor PNG has been found, raise error BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Could not load bitmap: " << bmp_name; - return wxNullBitmap; + throw Slic3r::RuntimeError("Could not load bitmap: " + bmp_name); } return *bmp; @@ -485,7 +485,7 @@ wxBitmap create_scaled_bitmap2(const std::string& bmp_name_in, Slic3r::GUI::Bitm if (bmp == nullptr) { // No SVG found BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Could not load bitmap: " << bmp_name; - return wxNullBitmap; + throw Slic3r::RuntimeError("Could not load bitmap: " + bmp_name); } return *bmp; } @@ -1363,3 +1363,4 @@ void ImageTransientPopup::OnMouse(wxMouseEvent &event) + From 992c9f30ac4e22714ae9ce6bdb1b6942f481571c Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 11:27:41 -0500 Subject: [PATCH 11/57] Store filament index setting in printer presets --- src/libslic3r/Preset.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 4e78b31b46..f752692364 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1024,7 +1024,8 @@ static std::vector s_Preset_printer_options { "use_relative_e_distances", "extruder_type", "use_firmware_retraction", "printer_notes", "grab_length", "support_object_skip_flush", "physical_extruder_map", "cooling_tube_retraction", - "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "purge_in_prime_tower", "enable_filament_ramming", + "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "start_filament_index_at_1", + "purge_in_prime_tower", "enable_filament_ramming", "z_offset", "disable_m73", "preferred_orientation", "emit_machine_limits_to_gcode", "pellet_modded_printer", "support_multi_bed_types", "default_bed_type", "bed_mesh_min","bed_mesh_max","bed_mesh_probe_distance", "adaptive_bed_mesh_margin", "enable_long_retraction_when_cut","long_retractions_when_cut","retraction_distances_when_cut", "bed_temperature_formula", "nozzle_flush_dataset" From 9623865d2b9467e92c21518520febffebdc54217 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 11:48:29 -0500 Subject: [PATCH 12/57] Refresh tool labels after filament index toggle --- src/slic3r/GUI/Tab.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 1e2a10102b..5ec2a8bf2d 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1537,6 +1537,12 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) wxGetApp().get_tab(Preset::TYPE_PRINT)->update(); } + if (opt_key == "start_filament_index_at_1") { + wxGetApp().sidebar().update_dynamic_filament_list(); + wxGetApp().sidebar().update_all_preset_comboboxes(); + wxGetApp().plater()->update(); + } + if(opt_key == "purge_in_prime_tower") wxGetApp().get_tab(Preset::TYPE_PRINT)->update(); From a7a3c1ce971717d48779d3bccf26d32956a63f12 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 12:49:43 -0500 Subject: [PATCH 13/57] Rename filament index setting and move to advanced --- src/libslic3r/Preset.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 10 +++++----- src/libslic3r/PrintConfig.hpp | 2 +- src/slic3r/GUI/GUI.cpp | 8 ++++---- src/slic3r/GUI/GUI.hpp | 2 +- src/slic3r/GUI/Tab.cpp | 5 ++--- 6 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index f752692364..8a73bb63d0 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1024,7 +1024,7 @@ static std::vector s_Preset_printer_options { "use_relative_e_distances", "extruder_type", "use_firmware_retraction", "printer_notes", "grab_length", "support_object_skip_flush", "physical_extruder_map", "cooling_tube_retraction", - "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "start_filament_index_at_1", + "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "start_filament_index_at_0", "purge_in_prime_tower", "enable_filament_ramming", "z_offset", "disable_m73", "preferred_orientation", "emit_machine_limits_to_gcode", "pellet_modded_printer", "support_multi_bed_types", "default_bed_type", "bed_mesh_min","bed_mesh_max","bed_mesh_probe_distance", "adaptive_bed_mesh_margin", "enable_long_retraction_when_cut","long_retractions_when_cut","retraction_distances_when_cut", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 894a3c00f2..06af8bc908 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4428,12 +4428,12 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(-2.)); - def = this->add("start_filament_index_at_1", coBool); - def->label = L("Start filament index at 1"); - def->tooltip = L("When enabled, filament/extruder indices are treated as 1-based (1..N) instead of 0-based (0..N-1). " - "Enable this if your firmware / macros expect filament indices starting at 1."); + def = this->add("start_filament_index_at_0", coBool); + def->label = L("Start filament index at 0"); + def->tooltip = L("When enabled, filament/extruder indices are treated as 0-based (0..N-1) instead of 1-based (1..N). " + "Disable this if your firmware / macros expect filament indices starting at 1."); def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBool(false)); + def->set_default_value(new ConfigOptionBool(true)); def = this->add("start_end_points", coPoints); def->label = L("Start end points"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index a4512a9f97..65be24be1c 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1385,7 +1385,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, purge_in_prime_tower)) ((ConfigOptionBool, enable_filament_ramming)) ((ConfigOptionBool, support_multi_bed_types)) - ((ConfigOptionBool, start_filament_index_at_1)) + ((ConfigOptionBool, start_filament_index_at_0)) // Small Area Infill Flow Compensation diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 5e1e0c557b..1bc0bae262 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -102,25 +102,25 @@ const std::string& shortkey_alt_prefix() return str; } -bool start_filament_index_at_1() +bool start_filament_index_at_0() { const auto* preset_bundle = wxGetApp().preset_bundle; if (!preset_bundle) return false; const auto& config = preset_bundle->printers.get_edited_preset().config; - const auto* opt = config.option("start_filament_index_at_1"); + const auto* opt = config.option("start_filament_index_at_0"); return opt != nullptr && opt->value; } int filament_index_from_zero_based(int index) { - return index + (start_filament_index_at_1() ? 1 : 0); + return index + (start_filament_index_at_0() ? 0 : 1); } int filament_index_from_one_based(int index) { - return start_filament_index_at_1() ? index : index - 1; + return start_filament_index_at_0() ? index - 1 : index; } // opt_index = 0, by the reason of zero-index in ConfigOptionVector by default (in case only one element) diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp index 6a4de482d3..e242519018 100644 --- a/src/slic3r/GUI/GUI.hpp +++ b/src/slic3r/GUI/GUI.hpp @@ -32,7 +32,7 @@ void break_to_debugger(); extern const std::string& shortkey_ctrl_prefix(); extern const std::string& shortkey_alt_prefix(); -bool start_filament_index_at_1(); +bool start_filament_index_at_0(); int filament_index_from_zero_based(int index); int filament_index_from_one_based(int index); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 5ec2a8bf2d..ce70205b3b 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1537,7 +1537,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) wxGetApp().get_tab(Preset::TYPE_PRINT)->update(); } - if (opt_key == "start_filament_index_at_1") { + if (opt_key == "start_filament_index_at_0") { wxGetApp().sidebar().update_dynamic_filament_list(); wxGetApp().sidebar().update_all_preset_comboboxes(); wxGetApp().plater()->update(); @@ -4917,12 +4917,11 @@ if (is_marlin_flavor) optgroup->append_single_option_line("parking_pos_retraction", "printer_multimaterial_semm_parameters#filament-parking-position"); optgroup->append_single_option_line("extra_loading_move", "printer_multimaterial_semm_parameters#extra-loading-distance"); optgroup->append_single_option_line("high_current_on_filament_swap", "printer_multimaterial_semm_parameters#high-extruder-current-on-filament-swap"); - optgroup->append_single_option_line("start_filament_index_at_1", "printer_multimaterial_semm_parameters#start_filament_index_at_1"); - optgroup = page->new_optgroup(L("Advanced"), L"param_advanced"); optgroup->append_single_option_line("machine_load_filament_time", "printer_multimaterial_advanced#filament-load-time"); optgroup->append_single_option_line("machine_unload_filament_time", "printer_multimaterial_advanced#filament-unload-time"); optgroup->append_single_option_line("machine_tool_change_time", "printer_multimaterial_advanced#tool-change-time"); + optgroup->append_single_option_line("start_filament_index_at_0", "printer_multimaterial_advanced#start-filament-index-at-0"); m_pages.insert(m_pages.end() - n_after_single_extruder_MM, page); } From 0253cf47847ce4121a83624f8855efe2fc31d52b Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 14:02:50 -0500 Subject: [PATCH 14/57] Adjust filament index display for 0-based UI --- src/slic3r/GUI/GUI_ObjectList.cpp | 37 ++++++++++++++++---------- src/slic3r/GUI/ObjectDataViewModel.cpp | 28 ++++++++++++++----- src/slic3r/GUI/wxExtensions.cpp | 6 ++--- 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 1cea62ece8..4a25a07e23 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -4,6 +4,7 @@ #include "GUI_Factories.hpp" //#include "GUI_ObjectLayers.hpp" #include "GUI_App.hpp" +#include "GUI.hpp" #include "I18N.hpp" #include "Plater.hpp" #include "BitmapComboBox.hpp" @@ -77,6 +78,14 @@ static int filaments_count() return wxGetApp().filaments_cnt(); } +static wxString format_filament_index_for_display(int extruder_id) +{ + if (extruder_id <= 0) + return wxString::Format("%d", extruder_id); + + return wxString::Format("%d", filament_index_from_one_based(extruder_id)); +} + static void take_snapshot(const std::string& snapshot_name) { Plater* plater = wxGetApp().plater(); @@ -688,11 +697,11 @@ void ObjectList::update_filament_values_for_items(const size_t filaments_count) auto object = (*m_objects)[i]; wxString extruder; if (!object->config.has("extruder") || size_t(object->config.extruder()) > filaments_count) { - extruder = "1"; + extruder = format_filament_index_for_display(1); object->config.set_key_value("extruder", new ConfigOptionInt(1)); } else { - extruder = wxString::Format("%d", object->config.extruder()); + extruder = format_filament_index_for_display(object->config.extruder()); } m_objects_model->SetExtruder(extruder, item); @@ -707,10 +716,10 @@ void ObjectList::update_filament_values_for_items(const size_t filaments_count) if (!item) continue; if (!object->volumes[id]->config.has("extruder") || size_t(object->volumes[id]->config.extruder()) > filaments_count) { - extruder = wxString::Format("%d", object->config.extruder()); + extruder = format_filament_index_for_display(object->config.extruder()); } else { - extruder = wxString::Format("%d", object->volumes[id]->config.extruder()); + extruder = format_filament_index_for_display(object->volumes[id]->config.extruder()); } m_objects_model->SetExtruder(extruder, item); @@ -737,15 +746,15 @@ void ObjectList::update_filament_values_for_items_when_delete_filament(const siz auto object = (*m_objects)[i]; wxString extruder; if (!object->config.has("extruder")) { - extruder = std::to_string(1); + extruder = format_filament_index_for_display(1); object->config.set_key_value("extruder", new ConfigOptionInt(1)); } else if (size_t(object->config.extruder()) == filament_id + 1) { - extruder = std::to_string(replace_filament_id); + extruder = format_filament_index_for_display(replace_filament_id); object->config.set_key_value("extruder", new ConfigOptionInt(replace_filament_id)); } else { int new_extruder = object->config.extruder() > filament_id ? object->config.extruder() - 1 : object->config.extruder(); - extruder = wxString::Format("%d", new_extruder); + extruder = format_filament_index_for_display(new_extruder); object->config.set_key_value("extruder", new ConfigOptionInt(new_extruder)); } m_objects_model->SetExtruder(extruder, item); @@ -787,7 +796,7 @@ void ObjectList::update_filament_values_for_items_when_delete_filament(const siz object->volumes[id]->config.set_key_value("extruder", new ConfigOptionInt(replace_filament_id)); } else { int new_extruder = object->volumes[id]->config.extruder() > filament_id ? object->volumes[id]->config.extruder() - 1 : object->volumes[id]->config.extruder(); - extruder = wxString::Format("%d", new_extruder); + extruder = format_filament_index_for_display(new_extruder); object->volumes[id]->config.set_key_value("extruder", new ConfigOptionInt(new_extruder)); } @@ -815,12 +824,12 @@ void ObjectList::update_filament_values_for_items_when_delete_filament(const siz auto& layer_range_item = *(l_iter); if (layer_range_item.second.has("extruder") && layer_range_item.second.option("extruder")->getInt() == filament_id + 1) { int new_extruder = replace_id == -1 ? 0 : (replace_id + 1); - extruder = wxString::Format("%d", new_extruder); + extruder = format_filament_index_for_display(new_extruder); layer_range_item.second.set("extruder", new_extruder); } else { int layer_filament_id = layer_range_item.second.option("extruder")->getInt(); int new_extruder = layer_filament_id > filament_id ? layer_filament_id - 1 : layer_filament_id; - extruder = wxString::Format("%d", new_extruder); + extruder = format_filament_index_for_display(new_extruder); layer_range_item.second.set("extruder", new_extruder); } m_objects_model->SetExtruder(extruder, layer_item); @@ -1608,7 +1617,7 @@ void ObjectList::extruder_editing() pos.x = GetColumn(colName)->GetWidth() + GetColumn(colPrint)->GetWidth() + GetColumn(colHeight)->GetWidth() + 5; pos.y -= GetTextExtent("m").y; - apply_extruder_selector(&m_extruder_editor, this, "1", pos, size); + apply_extruder_selector(&m_extruder_editor, this, format_filament_index_for_display(1).ToStdString(), pos, size); m_extruder_editor->SetSelection(m_objects_model->GetExtruderNumber(item)); m_extruder_editor->Show(); @@ -2772,7 +2781,7 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con int extruder_id = last_volume->config.opt_int("extruder"); object->config.set("extruder", extruder_id); } - wxString extruder = object->config.has("extruder") ? wxString::Format("%d", object->config.extruder()) : _devL("1"); + wxString extruder = object->config.has("extruder") ? format_filament_index_for_display(object->config.extruder()) : format_filament_index_for_display(1); m_objects_model->SetExtruder(extruder, obj_item); } // add settings to the object, if it has them @@ -4168,7 +4177,7 @@ void ObjectList::delete_from_model_and_list(const std::vector& it if (obj->volumes.size() == 1) { wxDataViewItem parent = m_objects_model->GetItemById(item->obj_idx); if (obj->config.has("extruder")) { - const wxString extruder = wxString::Format("%d", obj->config.extruder()); + const wxString extruder = format_filament_index_for_display(obj->config.extruder()); m_objects_model->SetExtruder(extruder, parent); } // If last volume item with warning was deleted, unmark object item @@ -6183,7 +6192,7 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) } } - const wxString extruder_str = wxString::Format("%d", new_extruder); + const wxString extruder_str = format_filament_index_for_display(new_extruder); m_objects_model->SetExtruder(extruder_str, item); } diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index a7d2f711bf..c57a20118a 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -10,6 +10,7 @@ #include "libslic3r/Model.hpp" +#include #include #include @@ -44,6 +45,14 @@ static constexpr char WarningIcon[] = "obj_warning"; static constexpr char WarningManifoldIcon[] = "obj_warning"; static constexpr char LockIcon[] = "cut_"; +static wxString format_filament_index_for_display(int extruder_id) +{ + if (extruder_id <= 0) + return wxString::Format("%d", extruder_id); + + return wxString::Format("%d", filament_index_from_one_based(extruder_id)); +} + ObjectDataViewModelNode::ObjectDataViewModelNode(PartPlate* part_plate, wxString name) : m_parent(nullptr), m_name(name), @@ -611,7 +620,7 @@ wxDataViewItem ObjectDataViewModel::AddObject(ModelObject *model_object, std::st // create object node //const wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder); - const wxString extruder_str = wxString::Format("%d", extruder); + const wxString extruder_str = format_filament_index_for_display(extruder); auto obj_node = new ObjectDataViewModelNode(name, extruder_str, plate_idx, model_object); // Add warning icon if detected auto-repaire UpdateBitmapForNode(obj_node, warning_bitmap, has_lock); @@ -678,7 +687,7 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent extruder_str = root->m_extruder; } else { - extruder_str = wxString::Format("%d", extruder); + extruder_str = format_filament_index_for_display(extruder); } const auto node = new ObjectDataViewModelNode(root, name, volume_type, is_text_volume, is_svg_volume, extruder_str, root->m_volumes_cnt); @@ -905,7 +914,7 @@ wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_ if (!parent_node) return wxDataViewItem(0); // BBS - wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder); + wxString extruder_str = extruder == 0 ? _(L("default")) : format_filament_index_for_display(extruder); // get LayerRoot node ObjectDataViewModelNode *layer_root_node; @@ -1748,7 +1757,16 @@ int ObjectDataViewModel::GetExtruderNumber(const wxDataViewItem& item) const if (!node) // happens if item.IsOk()==false return 0; - return atoi(node->m_extruder.c_str()); + const std::string extruder = node->m_extruder.ToStdString(); + char* end = nullptr; + const long value = std::strtol(extruder.c_str(), &end, 10); + if (end == extruder.c_str() || *end != '\0') + return 0; + + if (start_filament_index_at_0()) + return static_cast(value) + 1; + + return static_cast(value); } wxString ObjectDataViewModel::GetColumnType(unsigned int col) const @@ -2494,5 +2512,3 @@ void ObjectDataViewModel::UpdateCutObjectIcon(const wxDataViewItem &item, bool h } // namespace GUI } // namespace Slic3r - - diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 1a6037184d..ce8813bb38 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -790,9 +790,10 @@ void apply_extruder_selector(Slic3r::GUI::BitmapComboBox** ctrl, ++i; } + const int display_index = filament_index_from_one_based(i); (*ctrl)->Append(use_full_item_name - ? Slic3r::GUI::from_u8((boost::format("%1% %2%") % str % i).str()) - : wxString::Format("%d", i), *bmp); + ? Slic3r::GUI::from_u8((boost::format("%1% %2%") % str % display_index).str()) + : wxString::Format("%d", display_index), *bmp); ++i; } (*ctrl)->SetSelection(0); @@ -1363,4 +1364,3 @@ void ImageTransientPopup::OnMouse(wxMouseEvent &event) - From 9e79a4f2c15f7d722164c6ced3a1a140c6310560 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard Date: Fri, 16 Jan 2026 13:50:44 -1000 Subject: [PATCH 15/57] Update PrintConfig.cpp --- src/libslic3r/PrintConfig.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 06af8bc908..9cb88347ab 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4430,8 +4430,7 @@ void PrintConfigDef::init_fff_params() def = this->add("start_filament_index_at_0", coBool); def->label = L("Start filament index at 0"); - def->tooltip = L("When enabled, filament/extruder indices are treated as 0-based (0..N-1) instead of 1-based (1..N). " - "Disable this if your firmware / macros expect filament indices starting at 1."); + def->tooltip = L("When enabled, filament/extruder indices in OrcaSlicer's interface are treated as 0-based (0..N-1) instead of 1-based (1..N)."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(true)); From ebc0f9a97e6225dd833f480ce786d875a2fce535 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 14:17:22 -0500 Subject: [PATCH 16/57] Fix filament index helper reference --- src/slic3r/GUI/GUI_ObjectList.cpp | 37 ++++++++++++++++---------- src/slic3r/GUI/ObjectDataViewModel.cpp | 28 ++++++++++++++----- src/slic3r/GUI/wxExtensions.cpp | 7 +++-- 3 files changed, 48 insertions(+), 24 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 1cea62ece8..4a25a07e23 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -4,6 +4,7 @@ #include "GUI_Factories.hpp" //#include "GUI_ObjectLayers.hpp" #include "GUI_App.hpp" +#include "GUI.hpp" #include "I18N.hpp" #include "Plater.hpp" #include "BitmapComboBox.hpp" @@ -77,6 +78,14 @@ static int filaments_count() return wxGetApp().filaments_cnt(); } +static wxString format_filament_index_for_display(int extruder_id) +{ + if (extruder_id <= 0) + return wxString::Format("%d", extruder_id); + + return wxString::Format("%d", filament_index_from_one_based(extruder_id)); +} + static void take_snapshot(const std::string& snapshot_name) { Plater* plater = wxGetApp().plater(); @@ -688,11 +697,11 @@ void ObjectList::update_filament_values_for_items(const size_t filaments_count) auto object = (*m_objects)[i]; wxString extruder; if (!object->config.has("extruder") || size_t(object->config.extruder()) > filaments_count) { - extruder = "1"; + extruder = format_filament_index_for_display(1); object->config.set_key_value("extruder", new ConfigOptionInt(1)); } else { - extruder = wxString::Format("%d", object->config.extruder()); + extruder = format_filament_index_for_display(object->config.extruder()); } m_objects_model->SetExtruder(extruder, item); @@ -707,10 +716,10 @@ void ObjectList::update_filament_values_for_items(const size_t filaments_count) if (!item) continue; if (!object->volumes[id]->config.has("extruder") || size_t(object->volumes[id]->config.extruder()) > filaments_count) { - extruder = wxString::Format("%d", object->config.extruder()); + extruder = format_filament_index_for_display(object->config.extruder()); } else { - extruder = wxString::Format("%d", object->volumes[id]->config.extruder()); + extruder = format_filament_index_for_display(object->volumes[id]->config.extruder()); } m_objects_model->SetExtruder(extruder, item); @@ -737,15 +746,15 @@ void ObjectList::update_filament_values_for_items_when_delete_filament(const siz auto object = (*m_objects)[i]; wxString extruder; if (!object->config.has("extruder")) { - extruder = std::to_string(1); + extruder = format_filament_index_for_display(1); object->config.set_key_value("extruder", new ConfigOptionInt(1)); } else if (size_t(object->config.extruder()) == filament_id + 1) { - extruder = std::to_string(replace_filament_id); + extruder = format_filament_index_for_display(replace_filament_id); object->config.set_key_value("extruder", new ConfigOptionInt(replace_filament_id)); } else { int new_extruder = object->config.extruder() > filament_id ? object->config.extruder() - 1 : object->config.extruder(); - extruder = wxString::Format("%d", new_extruder); + extruder = format_filament_index_for_display(new_extruder); object->config.set_key_value("extruder", new ConfigOptionInt(new_extruder)); } m_objects_model->SetExtruder(extruder, item); @@ -787,7 +796,7 @@ void ObjectList::update_filament_values_for_items_when_delete_filament(const siz object->volumes[id]->config.set_key_value("extruder", new ConfigOptionInt(replace_filament_id)); } else { int new_extruder = object->volumes[id]->config.extruder() > filament_id ? object->volumes[id]->config.extruder() - 1 : object->volumes[id]->config.extruder(); - extruder = wxString::Format("%d", new_extruder); + extruder = format_filament_index_for_display(new_extruder); object->volumes[id]->config.set_key_value("extruder", new ConfigOptionInt(new_extruder)); } @@ -815,12 +824,12 @@ void ObjectList::update_filament_values_for_items_when_delete_filament(const siz auto& layer_range_item = *(l_iter); if (layer_range_item.second.has("extruder") && layer_range_item.second.option("extruder")->getInt() == filament_id + 1) { int new_extruder = replace_id == -1 ? 0 : (replace_id + 1); - extruder = wxString::Format("%d", new_extruder); + extruder = format_filament_index_for_display(new_extruder); layer_range_item.second.set("extruder", new_extruder); } else { int layer_filament_id = layer_range_item.second.option("extruder")->getInt(); int new_extruder = layer_filament_id > filament_id ? layer_filament_id - 1 : layer_filament_id; - extruder = wxString::Format("%d", new_extruder); + extruder = format_filament_index_for_display(new_extruder); layer_range_item.second.set("extruder", new_extruder); } m_objects_model->SetExtruder(extruder, layer_item); @@ -1608,7 +1617,7 @@ void ObjectList::extruder_editing() pos.x = GetColumn(colName)->GetWidth() + GetColumn(colPrint)->GetWidth() + GetColumn(colHeight)->GetWidth() + 5; pos.y -= GetTextExtent("m").y; - apply_extruder_selector(&m_extruder_editor, this, "1", pos, size); + apply_extruder_selector(&m_extruder_editor, this, format_filament_index_for_display(1).ToStdString(), pos, size); m_extruder_editor->SetSelection(m_objects_model->GetExtruderNumber(item)); m_extruder_editor->Show(); @@ -2772,7 +2781,7 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con int extruder_id = last_volume->config.opt_int("extruder"); object->config.set("extruder", extruder_id); } - wxString extruder = object->config.has("extruder") ? wxString::Format("%d", object->config.extruder()) : _devL("1"); + wxString extruder = object->config.has("extruder") ? format_filament_index_for_display(object->config.extruder()) : format_filament_index_for_display(1); m_objects_model->SetExtruder(extruder, obj_item); } // add settings to the object, if it has them @@ -4168,7 +4177,7 @@ void ObjectList::delete_from_model_and_list(const std::vector& it if (obj->volumes.size() == 1) { wxDataViewItem parent = m_objects_model->GetItemById(item->obj_idx); if (obj->config.has("extruder")) { - const wxString extruder = wxString::Format("%d", obj->config.extruder()); + const wxString extruder = format_filament_index_for_display(obj->config.extruder()); m_objects_model->SetExtruder(extruder, parent); } // If last volume item with warning was deleted, unmark object item @@ -6183,7 +6192,7 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) } } - const wxString extruder_str = wxString::Format("%d", new_extruder); + const wxString extruder_str = format_filament_index_for_display(new_extruder); m_objects_model->SetExtruder(extruder_str, item); } diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index a7d2f711bf..c57a20118a 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -10,6 +10,7 @@ #include "libslic3r/Model.hpp" +#include #include #include @@ -44,6 +45,14 @@ static constexpr char WarningIcon[] = "obj_warning"; static constexpr char WarningManifoldIcon[] = "obj_warning"; static constexpr char LockIcon[] = "cut_"; +static wxString format_filament_index_for_display(int extruder_id) +{ + if (extruder_id <= 0) + return wxString::Format("%d", extruder_id); + + return wxString::Format("%d", filament_index_from_one_based(extruder_id)); +} + ObjectDataViewModelNode::ObjectDataViewModelNode(PartPlate* part_plate, wxString name) : m_parent(nullptr), m_name(name), @@ -611,7 +620,7 @@ wxDataViewItem ObjectDataViewModel::AddObject(ModelObject *model_object, std::st // create object node //const wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder); - const wxString extruder_str = wxString::Format("%d", extruder); + const wxString extruder_str = format_filament_index_for_display(extruder); auto obj_node = new ObjectDataViewModelNode(name, extruder_str, plate_idx, model_object); // Add warning icon if detected auto-repaire UpdateBitmapForNode(obj_node, warning_bitmap, has_lock); @@ -678,7 +687,7 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent extruder_str = root->m_extruder; } else { - extruder_str = wxString::Format("%d", extruder); + extruder_str = format_filament_index_for_display(extruder); } const auto node = new ObjectDataViewModelNode(root, name, volume_type, is_text_volume, is_svg_volume, extruder_str, root->m_volumes_cnt); @@ -905,7 +914,7 @@ wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_ if (!parent_node) return wxDataViewItem(0); // BBS - wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder); + wxString extruder_str = extruder == 0 ? _(L("default")) : format_filament_index_for_display(extruder); // get LayerRoot node ObjectDataViewModelNode *layer_root_node; @@ -1748,7 +1757,16 @@ int ObjectDataViewModel::GetExtruderNumber(const wxDataViewItem& item) const if (!node) // happens if item.IsOk()==false return 0; - return atoi(node->m_extruder.c_str()); + const std::string extruder = node->m_extruder.ToStdString(); + char* end = nullptr; + const long value = std::strtol(extruder.c_str(), &end, 10); + if (end == extruder.c_str() || *end != '\0') + return 0; + + if (start_filament_index_at_0()) + return static_cast(value) + 1; + + return static_cast(value); } wxString ObjectDataViewModel::GetColumnType(unsigned int col) const @@ -2494,5 +2512,3 @@ void ObjectDataViewModel::UpdateCutObjectIcon(const wxDataViewItem &item, bool h } // namespace GUI } // namespace Slic3r - - diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 1a6037184d..2fecf52bd2 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -790,9 +790,10 @@ void apply_extruder_selector(Slic3r::GUI::BitmapComboBox** ctrl, ++i; } + const int display_index = Slic3r::GUI::filament_index_from_one_based(i); (*ctrl)->Append(use_full_item_name - ? Slic3r::GUI::from_u8((boost::format("%1% %2%") % str % i).str()) - : wxString::Format("%d", i), *bmp); + ? Slic3r::GUI::from_u8((boost::format("%1% %2%") % str % display_index).str()) + : wxString::Format("%d", display_index), *bmp); ++i; } (*ctrl)->SetSelection(0); @@ -1362,5 +1363,3 @@ void ImageTransientPopup::OnMouse(wxMouseEvent &event) } - - From 90b5149767bd55745cedcdc3b9ec80d049670109 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 14:35:27 -0500 Subject: [PATCH 17/57] Respect filament index setting in UI --- src/slic3r/GUI/GCodeViewer.cpp | 15 +++++++-------- src/slic3r/GUI/GLCanvas3D.cpp | 16 +++++++++------- src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 9 +++++---- src/slic3r/GUI/ImGuiWrapper.cpp | 2 +- src/slic3r/GUI/ObjColorDialog.cpp | 6 ++++-- src/slic3r/GUI/Tab.cpp | 6 ++++-- 6 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 8032a24c07..fc58572138 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -345,11 +345,11 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode break; } case libvgcode::EViewType::Tool: { - sprintf(buf, "%s %s%d", buf, _u8L("Tool: ").c_str(), vertex.extruder_id + 1); + sprintf(buf, "%s %s%d", buf, _u8L("Tool: ").c_str(), filament_index_from_zero_based(static_cast(vertex.extruder_id))); break; } case libvgcode::EViewType::ColorPrint: { - sprintf(buf, "%s %s%d", buf, _u8L("Color: ").c_str(), vertex.color_id + 1); + sprintf(buf, "%s %s%d", buf, _u8L("Color: ").c_str(), filament_index_from_zero_based(static_cast(vertex.color_id))); break; } case libvgcode::EViewType::ActualVolumetricFlowRate: { @@ -2480,7 +2480,7 @@ void GCodeViewer::render_all_plates_stats(const std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(it->first + 1), offsets[_u8L("Filament")]}); + columns_offsets.push_back({ std::to_string(filament_index_from_zero_based(static_cast(it->first))), offsets[_u8L("Filament")]}); char buf[64]; double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1.0; @@ -3562,7 +3562,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv const std::vector& used_extruders_ids = m_viewer.get_used_extruders_ids(); for (uint8_t extruder_id : used_extruders_ids) { ::sprintf(buf, imperial_units ? "%.2f in %.2f g" : "%.2f m %.2f g", model_used_filaments_m[i], model_used_filaments_g[i]); - append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), { { _u8L("Extruder") + " " + std::to_string(extruder_id + 1), offsets[0]}, {buf, offsets[1]} }); + append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), { { _u8L("Extruder") + " " + std::to_string(filament_index_from_zero_based(extruder_id)), offsets[0]}, {buf, offsets[1]} }); // append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), _u8L("Extruder") + " " + std::to_string(extruder_id + 1), // true, "", 0.0f, 0.0f, offsets, used_filaments_m[extruder_id], used_filaments_g[extruder_id]); i++; @@ -3614,7 +3614,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv for (auto extruder_idx : used_extruders_ids) { if (i < model_used_filaments_m.size() && i < model_used_filaments_g.size()) { std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(extruder_idx + 1), color_print_offsets[_u8L("Filament")]}); + columns_offsets.push_back({ std::to_string(filament_index_from_zero_based(extruder_idx)), color_print_offsets[_u8L("Filament")]}); char buf[64]; float column_sum_m = 0.0f; @@ -3990,7 +3990,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ret = std::max(ret, ImGui::CalcTextSize((_u8L("Print settings") + std::string(":")).c_str()).x); if (!m_settings_ids.filament.empty()) { for (unsigned char i : m_viewer.get_used_extruders_ids()) { - ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(i + 1) + ":").c_str()).x); + ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(filament_index_from_zero_based(static_cast(i))) + ":").c_str()).x); } } if (ret > 0.0f) @@ -4017,7 +4017,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv for (unsigned char i : m_viewer.get_used_extruders_ids()) { if (i < static_cast(m_settings_ids.filament.size()) && !m_settings_ids.filament[i].empty()) { std::string txt = _u8L("Filament"); - txt += (m_viewer.get_used_extruders_count() == 1) ? ":" : " " + std::to_string(i + 1); + txt += (m_viewer.get_used_extruders_count() == 1) ? ":" : " " + std::to_string(filament_index_from_zero_based(static_cast(i))); imgui.text(txt); ImGui::SameLine(offset); imgui.text(m_settings_ids.filament[i]); @@ -4266,4 +4266,3 @@ void GCodeViewer::render_slider(int canvas_width, int canvas_height) { } // namespace GUI } // namespace Slic3r - diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index fe9b60ea93..26327ac04f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -9492,14 +9492,15 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_area_error_infos.begin()) { text += "\n"; } - int extruder_id = error_iter->first + 1; // change extruder id to 1 based + const int extruder_index = error_iter->first; + const int extruder_id = filament_index_from_zero_based(extruder_index); std::string filaments; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { if (i > 0) { filaments += ", "; } - int filament_id = error_iter->second[i].first + 1; // change filament id to 1 based + const int filament_id = filament_index_from_zero_based(error_iter->second[i].first); int object_label_id = error_iter->second[i].second; filaments += std::to_string(filament_id); @@ -9522,7 +9523,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) } } } - std::string extruder_name = extruder_name_list[extruder_id-1]; + std::string extruder_name = extruder_name_list[extruder_index]; if (error_iter->second.size() == 1) { text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable range of the %s.")) %filaments %extruder_name %extruder_name).str(); } @@ -9538,11 +9539,12 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_height_error_infos.begin()) { text += "\n"; } - int extruder_id = error_iter->first + 1; // change extruder id to 1 based + const int extruder_index = error_iter->first; + const int extruder_id = filament_index_from_zero_based(extruder_index); std::set filament_ids; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { - int filament_id = error_iter->second[i].first + 1; // change filament id to 1 based + int filament_id = filament_index_from_zero_based(error_iter->second[i].first); int object_label_id = error_iter->second[i].second; filament_ids.insert(filament_id); for (int object_idx = 0; object_idx < (int) m_model->objects.size(); ++object_idx) { @@ -9575,7 +9577,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) } } } - std::string extruder_name = extruder_name_list[extruder_id-1]; + std::string extruder_name = extruder_name_list[extruder_index]; if (error_iter->second.size() == 1) { text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable height of the %s.")) % filaments % extruder_name % extruder_name).str(); } else { @@ -9604,7 +9606,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) const std::vector &conflict_filament = m_gcode_viewer.filament_printable_reuslt.conflict_filament; auto iter = conflict_filament.begin(); for (int filament : conflict_filament) { - warning += std::to_string(filament + 1); + warning += std::to_string(filament_index_from_zero_based(filament)); warning += " "; } text = (boost::format(_u8L("filaments %s cannot be printed directly on the surface of this plate.")) % warning).str(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index af7ec15772..f0544d8b78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -192,7 +192,7 @@ void GLGizmoMmuSegmentation::data_changed(bool is_serializing) // BBS bool GLGizmoMmuSegmentation::on_number_key_down(int number) { - int extruder_idx = number - 1; + int extruder_idx = start_filament_index_at_0() ? number : number - 1; if (extruder_idx < m_extruders_colors.size() && extruder_idx >= 0) m_selected_extruder_idx = extruder_idx; @@ -403,7 +403,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott const ColorRGBA &extruder_color = m_extruders_colors[extruder_idx]; ImVec4 color_vec = ImGuiWrapper::to_ImVec4(extruder_color); std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx); - std::string item_text = std::to_string(extruder_idx + 1); + std::string item_text = std::to_string(filament_index_from_zero_based(extruder_idx)); const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f),0.f); @@ -435,7 +435,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott color_button_high = ImGui::GetCursorPos().y - color_button - 2.0; if (color_picked) { m_selected_extruder_idx = extruder_idx; } - if (extruder_idx < 16 && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width); + if (extruder_idx < 16 && ImGui::IsItemHovered()) + m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(filament_index_from_zero_based(extruder_idx)), max_tooltip_width); // draw filament id float gray = 0.299 * extruder_color.r() + 0.587 * extruder_color.g() + 0.114 * extruder_color.b(); @@ -1047,7 +1048,7 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float #endif // overlay destination number with proper contrast calculation - std::string dst_txt = std::to_string(m_extruder_remap[src] + 1); + std::string dst_txt = std::to_string(filament_index_from_zero_based(static_cast(m_extruder_remap[src]))); float gray = 0.299f * dst_col.r() + 0.587f * dst_col.g() + 0.114f * dst_col.b(); ImVec2 txt_sz = ImGui::CalcTextSize(dst_txt.c_str()); ImVec2 pos = ImGui::GetItemRectMin(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 8bd2904c49..a1920d4810 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -3274,7 +3274,7 @@ std::tuple ImGuiWrapper::calculate_filament_group_text_size(const void ImGuiWrapper::filament_group(const std::string& filament_type, const char* hex_color, unsigned char filament_id, float align_width) { //ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); - std::string id = std::to_string(static_cast (filament_id + 1)); + std::string id = std::to_string(filament_index_from_zero_based(static_cast(filament_id))); ImDrawList* draw_list = ImGui::GetWindowDrawList(); static ImTextureID transparent; ImVec2 text_size = ImGui::CalcTextSize(filament_type.c_str()); diff --git a/src/slic3r/GUI/ObjColorDialog.cpp b/src/slic3r/GUI/ObjColorDialog.cpp index 7575777507..f237c8c66f 100644 --- a/src/slic3r/GUI/ObjColorDialog.cpp +++ b/src/slic3r/GUI/ObjColorDialog.cpp @@ -409,7 +409,8 @@ ObjColorPanel::~ObjColorPanel() { void ObjColorPanel::msw_rescale() { for (unsigned int i = 0; i < m_extruder_icon_list.size(); ++i) { - auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(i + 1), FromDIP(16), FromDIP(16)); + const int display_index = filament_index_from_zero_based(static_cast(i)); + auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(display_index), FromDIP(16), FromDIP(16)); m_extruder_icon_list[i]->SetBitmap(bitmap); } /* for (unsigned int i = 0; i < m_color_cluster_icon_list.size(); ++i) { @@ -530,7 +531,8 @@ wxBoxSizer *ObjColorPanel::create_extruder_icon_and_rgba_sizer(wxWindow *parent, { auto icon_sizer = new wxBoxSizer(wxHORIZONTAL); wxButton *icon = new wxButton(parent, wxID_ANY, {}, wxDefaultPosition, ICON_SIZE, wxBORDER_NONE | wxBU_AUTODRAW); - icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(id + 1), FromDIP(16), FromDIP(16))); + const int display_index = filament_index_from_zero_based(id); + icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(display_index), FromDIP(16), FromDIP(16))); icon->SetCanFocus(false); m_extruder_icon_list.emplace_back(icon); icon_sizer->Add(icon, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 0); // wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index ce70205b3b..70251ef1e1 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4927,7 +4927,9 @@ if (is_marlin_flavor) // Orca: build missed extruder pages for (auto extruder_idx = m_extruders_count_old; extruder_idx < m_extruders_count; ++extruder_idx) { - const wxString& page_name = (m_extruders_count > 1) ? wxString::Format("Extruder %d", int(extruder_idx + 1)) : wxString::Format("Extruder"); + const wxString& page_name = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) + : wxString::Format("Extruder"); //# build page //const wxString& page_name = wxString::Format("Extruder %d", int(extruder_idx + 1)); @@ -5057,7 +5059,7 @@ if (is_marlin_flavor) if (m_extruders_count == 1) first_extruder_title = wxString::Format("Extruder"); } else if (m_extruders_count_old == 1) { - first_extruder_title = wxString::Format("Extruder %d", 1); + first_extruder_title = wxString::Format("Extruder %d", filament_index_from_zero_based(0)); } auto & searcher = wxGetApp().sidebar().get_searcher(); for (auto &group : m_pages[n_before_extruders]->m_optgroups) { From 009c0671b14be7fb1e5f6b47aac3849ab6812032 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 14:44:20 -0500 Subject: [PATCH 18/57] Adjust filament index labels in sidebar and search --- src/slic3r/GUI/GCodeViewer.cpp | 15 +++++++-------- src/slic3r/GUI/GLCanvas3D.cpp | 16 +++++++++------- src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 9 +++++---- src/slic3r/GUI/ImGuiWrapper.cpp | 2 +- src/slic3r/GUI/ObjColorDialog.cpp | 6 ++++-- src/slic3r/GUI/Plater.cpp | 2 +- src/slic3r/GUI/Search.cpp | 3 ++- src/slic3r/GUI/Tab.cpp | 6 ++++-- 8 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 8032a24c07..fc58572138 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -345,11 +345,11 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode break; } case libvgcode::EViewType::Tool: { - sprintf(buf, "%s %s%d", buf, _u8L("Tool: ").c_str(), vertex.extruder_id + 1); + sprintf(buf, "%s %s%d", buf, _u8L("Tool: ").c_str(), filament_index_from_zero_based(static_cast(vertex.extruder_id))); break; } case libvgcode::EViewType::ColorPrint: { - sprintf(buf, "%s %s%d", buf, _u8L("Color: ").c_str(), vertex.color_id + 1); + sprintf(buf, "%s %s%d", buf, _u8L("Color: ").c_str(), filament_index_from_zero_based(static_cast(vertex.color_id))); break; } case libvgcode::EViewType::ActualVolumetricFlowRate: { @@ -2480,7 +2480,7 @@ void GCodeViewer::render_all_plates_stats(const std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(it->first + 1), offsets[_u8L("Filament")]}); + columns_offsets.push_back({ std::to_string(filament_index_from_zero_based(static_cast(it->first))), offsets[_u8L("Filament")]}); char buf[64]; double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1.0; @@ -3562,7 +3562,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv const std::vector& used_extruders_ids = m_viewer.get_used_extruders_ids(); for (uint8_t extruder_id : used_extruders_ids) { ::sprintf(buf, imperial_units ? "%.2f in %.2f g" : "%.2f m %.2f g", model_used_filaments_m[i], model_used_filaments_g[i]); - append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), { { _u8L("Extruder") + " " + std::to_string(extruder_id + 1), offsets[0]}, {buf, offsets[1]} }); + append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), { { _u8L("Extruder") + " " + std::to_string(filament_index_from_zero_based(extruder_id)), offsets[0]}, {buf, offsets[1]} }); // append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), _u8L("Extruder") + " " + std::to_string(extruder_id + 1), // true, "", 0.0f, 0.0f, offsets, used_filaments_m[extruder_id], used_filaments_g[extruder_id]); i++; @@ -3614,7 +3614,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv for (auto extruder_idx : used_extruders_ids) { if (i < model_used_filaments_m.size() && i < model_used_filaments_g.size()) { std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(extruder_idx + 1), color_print_offsets[_u8L("Filament")]}); + columns_offsets.push_back({ std::to_string(filament_index_from_zero_based(extruder_idx)), color_print_offsets[_u8L("Filament")]}); char buf[64]; float column_sum_m = 0.0f; @@ -3990,7 +3990,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ret = std::max(ret, ImGui::CalcTextSize((_u8L("Print settings") + std::string(":")).c_str()).x); if (!m_settings_ids.filament.empty()) { for (unsigned char i : m_viewer.get_used_extruders_ids()) { - ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(i + 1) + ":").c_str()).x); + ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(filament_index_from_zero_based(static_cast(i))) + ":").c_str()).x); } } if (ret > 0.0f) @@ -4017,7 +4017,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv for (unsigned char i : m_viewer.get_used_extruders_ids()) { if (i < static_cast(m_settings_ids.filament.size()) && !m_settings_ids.filament[i].empty()) { std::string txt = _u8L("Filament"); - txt += (m_viewer.get_used_extruders_count() == 1) ? ":" : " " + std::to_string(i + 1); + txt += (m_viewer.get_used_extruders_count() == 1) ? ":" : " " + std::to_string(filament_index_from_zero_based(static_cast(i))); imgui.text(txt); ImGui::SameLine(offset); imgui.text(m_settings_ids.filament[i]); @@ -4266,4 +4266,3 @@ void GCodeViewer::render_slider(int canvas_width, int canvas_height) { } // namespace GUI } // namespace Slic3r - diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index fe9b60ea93..26327ac04f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -9492,14 +9492,15 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_area_error_infos.begin()) { text += "\n"; } - int extruder_id = error_iter->first + 1; // change extruder id to 1 based + const int extruder_index = error_iter->first; + const int extruder_id = filament_index_from_zero_based(extruder_index); std::string filaments; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { if (i > 0) { filaments += ", "; } - int filament_id = error_iter->second[i].first + 1; // change filament id to 1 based + const int filament_id = filament_index_from_zero_based(error_iter->second[i].first); int object_label_id = error_iter->second[i].second; filaments += std::to_string(filament_id); @@ -9522,7 +9523,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) } } } - std::string extruder_name = extruder_name_list[extruder_id-1]; + std::string extruder_name = extruder_name_list[extruder_index]; if (error_iter->second.size() == 1) { text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable range of the %s.")) %filaments %extruder_name %extruder_name).str(); } @@ -9538,11 +9539,12 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_height_error_infos.begin()) { text += "\n"; } - int extruder_id = error_iter->first + 1; // change extruder id to 1 based + const int extruder_index = error_iter->first; + const int extruder_id = filament_index_from_zero_based(extruder_index); std::set filament_ids; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { - int filament_id = error_iter->second[i].first + 1; // change filament id to 1 based + int filament_id = filament_index_from_zero_based(error_iter->second[i].first); int object_label_id = error_iter->second[i].second; filament_ids.insert(filament_id); for (int object_idx = 0; object_idx < (int) m_model->objects.size(); ++object_idx) { @@ -9575,7 +9577,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) } } } - std::string extruder_name = extruder_name_list[extruder_id-1]; + std::string extruder_name = extruder_name_list[extruder_index]; if (error_iter->second.size() == 1) { text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable height of the %s.")) % filaments % extruder_name % extruder_name).str(); } else { @@ -9604,7 +9606,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) const std::vector &conflict_filament = m_gcode_viewer.filament_printable_reuslt.conflict_filament; auto iter = conflict_filament.begin(); for (int filament : conflict_filament) { - warning += std::to_string(filament + 1); + warning += std::to_string(filament_index_from_zero_based(filament)); warning += " "; } text = (boost::format(_u8L("filaments %s cannot be printed directly on the surface of this plate.")) % warning).str(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index af7ec15772..f0544d8b78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -192,7 +192,7 @@ void GLGizmoMmuSegmentation::data_changed(bool is_serializing) // BBS bool GLGizmoMmuSegmentation::on_number_key_down(int number) { - int extruder_idx = number - 1; + int extruder_idx = start_filament_index_at_0() ? number : number - 1; if (extruder_idx < m_extruders_colors.size() && extruder_idx >= 0) m_selected_extruder_idx = extruder_idx; @@ -403,7 +403,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott const ColorRGBA &extruder_color = m_extruders_colors[extruder_idx]; ImVec4 color_vec = ImGuiWrapper::to_ImVec4(extruder_color); std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx); - std::string item_text = std::to_string(extruder_idx + 1); + std::string item_text = std::to_string(filament_index_from_zero_based(extruder_idx)); const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f),0.f); @@ -435,7 +435,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott color_button_high = ImGui::GetCursorPos().y - color_button - 2.0; if (color_picked) { m_selected_extruder_idx = extruder_idx; } - if (extruder_idx < 16 && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width); + if (extruder_idx < 16 && ImGui::IsItemHovered()) + m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(filament_index_from_zero_based(extruder_idx)), max_tooltip_width); // draw filament id float gray = 0.299 * extruder_color.r() + 0.587 * extruder_color.g() + 0.114 * extruder_color.b(); @@ -1047,7 +1048,7 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float #endif // overlay destination number with proper contrast calculation - std::string dst_txt = std::to_string(m_extruder_remap[src] + 1); + std::string dst_txt = std::to_string(filament_index_from_zero_based(static_cast(m_extruder_remap[src]))); float gray = 0.299f * dst_col.r() + 0.587f * dst_col.g() + 0.114f * dst_col.b(); ImVec2 txt_sz = ImGui::CalcTextSize(dst_txt.c_str()); ImVec2 pos = ImGui::GetItemRectMin(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 8bd2904c49..a1920d4810 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -3274,7 +3274,7 @@ std::tuple ImGuiWrapper::calculate_filament_group_text_size(const void ImGuiWrapper::filament_group(const std::string& filament_type, const char* hex_color, unsigned char filament_id, float align_width) { //ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); - std::string id = std::to_string(static_cast (filament_id + 1)); + std::string id = std::to_string(filament_index_from_zero_based(static_cast(filament_id))); ImDrawList* draw_list = ImGui::GetWindowDrawList(); static ImTextureID transparent; ImVec2 text_size = ImGui::CalcTextSize(filament_type.c_str()); diff --git a/src/slic3r/GUI/ObjColorDialog.cpp b/src/slic3r/GUI/ObjColorDialog.cpp index 7575777507..f237c8c66f 100644 --- a/src/slic3r/GUI/ObjColorDialog.cpp +++ b/src/slic3r/GUI/ObjColorDialog.cpp @@ -409,7 +409,8 @@ ObjColorPanel::~ObjColorPanel() { void ObjColorPanel::msw_rescale() { for (unsigned int i = 0; i < m_extruder_icon_list.size(); ++i) { - auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(i + 1), FromDIP(16), FromDIP(16)); + const int display_index = filament_index_from_zero_based(static_cast(i)); + auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(display_index), FromDIP(16), FromDIP(16)); m_extruder_icon_list[i]->SetBitmap(bitmap); } /* for (unsigned int i = 0; i < m_color_cluster_icon_list.size(); ++i) { @@ -530,7 +531,8 @@ wxBoxSizer *ObjColorPanel::create_extruder_icon_and_rgba_sizer(wxWindow *parent, { auto icon_sizer = new wxBoxSizer(wxHORIZONTAL); wxButton *icon = new wxButton(parent, wxID_ANY, {}, wxDefaultPosition, ICON_SIZE, wxBORDER_NONE | wxBU_AUTODRAW); - icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(id + 1), FromDIP(16), FromDIP(16))); + const int display_index = filament_index_from_zero_based(id); + icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(display_index), FromDIP(16), FromDIP(16))); icon->SetCanFocus(false); m_extruder_icon_list.emplace_back(icon); icon_sizer->Add(icon, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 0); // wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5da3520660..e4a792ca44 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2277,7 +2277,7 @@ void Sidebar::init_filament_combo(PlaterPresetComboBox **combo, const int filame if ((filament_idx % 2) == 0) // Dont add right column item. this one create equal spacing on left, right & middle combo_and_btn_sizer->AddSpacer(FromDIP((filament_idx % 2) == 0 ? 12 : 3)); // Content Margin - (*combo)->clr_picker->SetLabel(wxString::Format("%d", filament_idx + 1)); + (*combo)->clr_picker->SetLabel(wxString::Format("%d", filament_index_from_zero_based(filament_idx))); combo_and_btn_sizer->Add((*combo)->clr_picker, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(SidebarProps::ElementSpacing()) - FromDIP(2)); // ElementSpacing - 2 (from combo box)) combo_and_btn_sizer->Add(*combo, 1, wxALL | wxEXPAND, FromDIP(2))->SetMinSize({-1, FromDIP(30)}); diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index 1aef329297..e70b861efe 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -13,6 +13,7 @@ #include "libslic3r/PrintConfig.hpp" #include "libslic3r/PresetBundle.hpp" +#include "GUI.hpp" #include "GUI_App.hpp" #include "Plater.hpp" #include "Tab.hpp" @@ -338,7 +339,7 @@ static Option create_option(const std::string &opt_key, const wxString &label, P wxString category = gc.category; if (type == Preset::TYPE_PRINTER && category.Contains("Extruder ")) { std::string opt_idx = opt_key.substr(opt_key.find("#") + 1); - category = wxString::Format("%s %d", "Extruder", atoi(opt_idx.c_str()) + 1); + category = wxString::Format("%s %d", "Extruder", GUI::filament_index_from_zero_based(std::atoi(opt_idx.c_str()))); } return Option{boost::nowide::widen(get_key(opt_key, type)), diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index ce70205b3b..70251ef1e1 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4927,7 +4927,9 @@ if (is_marlin_flavor) // Orca: build missed extruder pages for (auto extruder_idx = m_extruders_count_old; extruder_idx < m_extruders_count; ++extruder_idx) { - const wxString& page_name = (m_extruders_count > 1) ? wxString::Format("Extruder %d", int(extruder_idx + 1)) : wxString::Format("Extruder"); + const wxString& page_name = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) + : wxString::Format("Extruder"); //# build page //const wxString& page_name = wxString::Format("Extruder %d", int(extruder_idx + 1)); @@ -5057,7 +5059,7 @@ if (is_marlin_flavor) if (m_extruders_count == 1) first_extruder_title = wxString::Format("Extruder"); } else if (m_extruders_count_old == 1) { - first_extruder_title = wxString::Format("Extruder %d", 1); + first_extruder_title = wxString::Format("Extruder %d", filament_index_from_zero_based(0)); } auto & searcher = wxGetApp().sidebar().get_searcher(); for (auto &group : m_pages[n_before_extruders]->m_optgroups) { From 23fb6eaf5cad086692f77e74d3d5a001092e86d5 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 14:53:44 -0500 Subject: [PATCH 19/57] Honor filament index base in sidebar lists --- src/slic3r/GUI/GCodeViewer.cpp | 15 +++++++-------- src/slic3r/GUI/GLCanvas3D.cpp | 16 +++++++++------- src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 9 +++++---- src/slic3r/GUI/ImGuiWrapper.cpp | 2 +- src/slic3r/GUI/ObjColorDialog.cpp | 6 ++++-- src/slic3r/GUI/Plater.cpp | 9 +++++---- src/slic3r/GUI/Search.cpp | 3 ++- src/slic3r/GUI/Tab.cpp | 6 ++++-- 8 files changed, 37 insertions(+), 29 deletions(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 8032a24c07..fc58572138 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -345,11 +345,11 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode break; } case libvgcode::EViewType::Tool: { - sprintf(buf, "%s %s%d", buf, _u8L("Tool: ").c_str(), vertex.extruder_id + 1); + sprintf(buf, "%s %s%d", buf, _u8L("Tool: ").c_str(), filament_index_from_zero_based(static_cast(vertex.extruder_id))); break; } case libvgcode::EViewType::ColorPrint: { - sprintf(buf, "%s %s%d", buf, _u8L("Color: ").c_str(), vertex.color_id + 1); + sprintf(buf, "%s %s%d", buf, _u8L("Color: ").c_str(), filament_index_from_zero_based(static_cast(vertex.color_id))); break; } case libvgcode::EViewType::ActualVolumetricFlowRate: { @@ -2480,7 +2480,7 @@ void GCodeViewer::render_all_plates_stats(const std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(it->first + 1), offsets[_u8L("Filament")]}); + columns_offsets.push_back({ std::to_string(filament_index_from_zero_based(static_cast(it->first))), offsets[_u8L("Filament")]}); char buf[64]; double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1.0; @@ -3562,7 +3562,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv const std::vector& used_extruders_ids = m_viewer.get_used_extruders_ids(); for (uint8_t extruder_id : used_extruders_ids) { ::sprintf(buf, imperial_units ? "%.2f in %.2f g" : "%.2f m %.2f g", model_used_filaments_m[i], model_used_filaments_g[i]); - append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), { { _u8L("Extruder") + " " + std::to_string(extruder_id + 1), offsets[0]}, {buf, offsets[1]} }); + append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), { { _u8L("Extruder") + " " + std::to_string(filament_index_from_zero_based(extruder_id)), offsets[0]}, {buf, offsets[1]} }); // append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), _u8L("Extruder") + " " + std::to_string(extruder_id + 1), // true, "", 0.0f, 0.0f, offsets, used_filaments_m[extruder_id], used_filaments_g[extruder_id]); i++; @@ -3614,7 +3614,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv for (auto extruder_idx : used_extruders_ids) { if (i < model_used_filaments_m.size() && i < model_used_filaments_g.size()) { std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(extruder_idx + 1), color_print_offsets[_u8L("Filament")]}); + columns_offsets.push_back({ std::to_string(filament_index_from_zero_based(extruder_idx)), color_print_offsets[_u8L("Filament")]}); char buf[64]; float column_sum_m = 0.0f; @@ -3990,7 +3990,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ret = std::max(ret, ImGui::CalcTextSize((_u8L("Print settings") + std::string(":")).c_str()).x); if (!m_settings_ids.filament.empty()) { for (unsigned char i : m_viewer.get_used_extruders_ids()) { - ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(i + 1) + ":").c_str()).x); + ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(filament_index_from_zero_based(static_cast(i))) + ":").c_str()).x); } } if (ret > 0.0f) @@ -4017,7 +4017,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv for (unsigned char i : m_viewer.get_used_extruders_ids()) { if (i < static_cast(m_settings_ids.filament.size()) && !m_settings_ids.filament[i].empty()) { std::string txt = _u8L("Filament"); - txt += (m_viewer.get_used_extruders_count() == 1) ? ":" : " " + std::to_string(i + 1); + txt += (m_viewer.get_used_extruders_count() == 1) ? ":" : " " + std::to_string(filament_index_from_zero_based(static_cast(i))); imgui.text(txt); ImGui::SameLine(offset); imgui.text(m_settings_ids.filament[i]); @@ -4266,4 +4266,3 @@ void GCodeViewer::render_slider(int canvas_width, int canvas_height) { } // namespace GUI } // namespace Slic3r - diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index fe9b60ea93..26327ac04f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -9492,14 +9492,15 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_area_error_infos.begin()) { text += "\n"; } - int extruder_id = error_iter->first + 1; // change extruder id to 1 based + const int extruder_index = error_iter->first; + const int extruder_id = filament_index_from_zero_based(extruder_index); std::string filaments; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { if (i > 0) { filaments += ", "; } - int filament_id = error_iter->second[i].first + 1; // change filament id to 1 based + const int filament_id = filament_index_from_zero_based(error_iter->second[i].first); int object_label_id = error_iter->second[i].second; filaments += std::to_string(filament_id); @@ -9522,7 +9523,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) } } } - std::string extruder_name = extruder_name_list[extruder_id-1]; + std::string extruder_name = extruder_name_list[extruder_index]; if (error_iter->second.size() == 1) { text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable range of the %s.")) %filaments %extruder_name %extruder_name).str(); } @@ -9538,11 +9539,12 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_height_error_infos.begin()) { text += "\n"; } - int extruder_id = error_iter->first + 1; // change extruder id to 1 based + const int extruder_index = error_iter->first; + const int extruder_id = filament_index_from_zero_based(extruder_index); std::set filament_ids; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { - int filament_id = error_iter->second[i].first + 1; // change filament id to 1 based + int filament_id = filament_index_from_zero_based(error_iter->second[i].first); int object_label_id = error_iter->second[i].second; filament_ids.insert(filament_id); for (int object_idx = 0; object_idx < (int) m_model->objects.size(); ++object_idx) { @@ -9575,7 +9577,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) } } } - std::string extruder_name = extruder_name_list[extruder_id-1]; + std::string extruder_name = extruder_name_list[extruder_index]; if (error_iter->second.size() == 1) { text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable height of the %s.")) % filaments % extruder_name % extruder_name).str(); } else { @@ -9604,7 +9606,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) const std::vector &conflict_filament = m_gcode_viewer.filament_printable_reuslt.conflict_filament; auto iter = conflict_filament.begin(); for (int filament : conflict_filament) { - warning += std::to_string(filament + 1); + warning += std::to_string(filament_index_from_zero_based(filament)); warning += " "; } text = (boost::format(_u8L("filaments %s cannot be printed directly on the surface of this plate.")) % warning).str(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index af7ec15772..f0544d8b78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -192,7 +192,7 @@ void GLGizmoMmuSegmentation::data_changed(bool is_serializing) // BBS bool GLGizmoMmuSegmentation::on_number_key_down(int number) { - int extruder_idx = number - 1; + int extruder_idx = start_filament_index_at_0() ? number : number - 1; if (extruder_idx < m_extruders_colors.size() && extruder_idx >= 0) m_selected_extruder_idx = extruder_idx; @@ -403,7 +403,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott const ColorRGBA &extruder_color = m_extruders_colors[extruder_idx]; ImVec4 color_vec = ImGuiWrapper::to_ImVec4(extruder_color); std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx); - std::string item_text = std::to_string(extruder_idx + 1); + std::string item_text = std::to_string(filament_index_from_zero_based(extruder_idx)); const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f),0.f); @@ -435,7 +435,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott color_button_high = ImGui::GetCursorPos().y - color_button - 2.0; if (color_picked) { m_selected_extruder_idx = extruder_idx; } - if (extruder_idx < 16 && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width); + if (extruder_idx < 16 && ImGui::IsItemHovered()) + m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(filament_index_from_zero_based(extruder_idx)), max_tooltip_width); // draw filament id float gray = 0.299 * extruder_color.r() + 0.587 * extruder_color.g() + 0.114 * extruder_color.b(); @@ -1047,7 +1048,7 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float #endif // overlay destination number with proper contrast calculation - std::string dst_txt = std::to_string(m_extruder_remap[src] + 1); + std::string dst_txt = std::to_string(filament_index_from_zero_based(static_cast(m_extruder_remap[src]))); float gray = 0.299f * dst_col.r() + 0.587f * dst_col.g() + 0.114f * dst_col.b(); ImVec2 txt_sz = ImGui::CalcTextSize(dst_txt.c_str()); ImVec2 pos = ImGui::GetItemRectMin(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 8bd2904c49..a1920d4810 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -3274,7 +3274,7 @@ std::tuple ImGuiWrapper::calculate_filament_group_text_size(const void ImGuiWrapper::filament_group(const std::string& filament_type, const char* hex_color, unsigned char filament_id, float align_width) { //ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); - std::string id = std::to_string(static_cast (filament_id + 1)); + std::string id = std::to_string(filament_index_from_zero_based(static_cast(filament_id))); ImDrawList* draw_list = ImGui::GetWindowDrawList(); static ImTextureID transparent; ImVec2 text_size = ImGui::CalcTextSize(filament_type.c_str()); diff --git a/src/slic3r/GUI/ObjColorDialog.cpp b/src/slic3r/GUI/ObjColorDialog.cpp index 7575777507..f237c8c66f 100644 --- a/src/slic3r/GUI/ObjColorDialog.cpp +++ b/src/slic3r/GUI/ObjColorDialog.cpp @@ -409,7 +409,8 @@ ObjColorPanel::~ObjColorPanel() { void ObjColorPanel::msw_rescale() { for (unsigned int i = 0; i < m_extruder_icon_list.size(); ++i) { - auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(i + 1), FromDIP(16), FromDIP(16)); + const int display_index = filament_index_from_zero_based(static_cast(i)); + auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(display_index), FromDIP(16), FromDIP(16)); m_extruder_icon_list[i]->SetBitmap(bitmap); } /* for (unsigned int i = 0; i < m_color_cluster_icon_list.size(); ++i) { @@ -530,7 +531,8 @@ wxBoxSizer *ObjColorPanel::create_extruder_icon_and_rgba_sizer(wxWindow *parent, { auto icon_sizer = new wxBoxSizer(wxHORIZONTAL); wxButton *icon = new wxButton(parent, wxID_ANY, {}, wxDefaultPosition, ICON_SIZE, wxBORDER_NONE | wxBU_AUTODRAW); - icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(id + 1), FromDIP(16), FromDIP(16))); + const int display_index = filament_index_from_zero_based(id); + icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(display_index), FromDIP(16), FromDIP(16))); icon->SetCanFocus(false); m_extruder_icon_list.emplace_back(icon); icon_sizer->Add(icon, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 0); // wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5da3520660..21e8ba432f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -834,7 +834,7 @@ struct DynamicFilamentList1Based : DynamicFilamentList wxString get_value(int index) override { wxString str; - str << index+1; + str << filament_index_from_zero_based(index); return str; } int index_of(wxString value) override @@ -842,8 +842,9 @@ struct DynamicFilamentList1Based : DynamicFilamentList long n = 0; if(!value.ToLong(&n)) return -1; - --n; - return (n >= 0 && n <= items.size()) ? int(n) : -1; + if (!start_filament_index_at_0()) + --n; + return (n >= 0 && n <= static_cast(items.size())) ? int(n) : -1; } void update(bool force = false) { @@ -2277,7 +2278,7 @@ void Sidebar::init_filament_combo(PlaterPresetComboBox **combo, const int filame if ((filament_idx % 2) == 0) // Dont add right column item. this one create equal spacing on left, right & middle combo_and_btn_sizer->AddSpacer(FromDIP((filament_idx % 2) == 0 ? 12 : 3)); // Content Margin - (*combo)->clr_picker->SetLabel(wxString::Format("%d", filament_idx + 1)); + (*combo)->clr_picker->SetLabel(wxString::Format("%d", filament_index_from_zero_based(filament_idx))); combo_and_btn_sizer->Add((*combo)->clr_picker, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(SidebarProps::ElementSpacing()) - FromDIP(2)); // ElementSpacing - 2 (from combo box)) combo_and_btn_sizer->Add(*combo, 1, wxALL | wxEXPAND, FromDIP(2))->SetMinSize({-1, FromDIP(30)}); diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index 1aef329297..e70b861efe 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -13,6 +13,7 @@ #include "libslic3r/PrintConfig.hpp" #include "libslic3r/PresetBundle.hpp" +#include "GUI.hpp" #include "GUI_App.hpp" #include "Plater.hpp" #include "Tab.hpp" @@ -338,7 +339,7 @@ static Option create_option(const std::string &opt_key, const wxString &label, P wxString category = gc.category; if (type == Preset::TYPE_PRINTER && category.Contains("Extruder ")) { std::string opt_idx = opt_key.substr(opt_key.find("#") + 1); - category = wxString::Format("%s %d", "Extruder", atoi(opt_idx.c_str()) + 1); + category = wxString::Format("%s %d", "Extruder", GUI::filament_index_from_zero_based(std::atoi(opt_idx.c_str()))); } return Option{boost::nowide::widen(get_key(opt_key, type)), diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index ce70205b3b..70251ef1e1 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4927,7 +4927,9 @@ if (is_marlin_flavor) // Orca: build missed extruder pages for (auto extruder_idx = m_extruders_count_old; extruder_idx < m_extruders_count; ++extruder_idx) { - const wxString& page_name = (m_extruders_count > 1) ? wxString::Format("Extruder %d", int(extruder_idx + 1)) : wxString::Format("Extruder"); + const wxString& page_name = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) + : wxString::Format("Extruder"); //# build page //const wxString& page_name = wxString::Format("Extruder %d", int(extruder_idx + 1)); @@ -5057,7 +5059,7 @@ if (is_marlin_flavor) if (m_extruders_count == 1) first_extruder_title = wxString::Format("Extruder"); } else if (m_extruders_count_old == 1) { - first_extruder_title = wxString::Format("Extruder %d", 1); + first_extruder_title = wxString::Format("Extruder %d", filament_index_from_zero_based(0)); } auto & searcher = wxGetApp().sidebar().get_searcher(); for (auto &group : m_pages[n_before_extruders]->m_optgroups) { From ec9b610da22e31b60ce47e5720a3d5a86281d0e8 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 15:01:14 -0500 Subject: [PATCH 20/57] Update sidebar filament icon labels --- src/slic3r/GUI/GCodeViewer.cpp | 15 +++++++-------- src/slic3r/GUI/GLCanvas3D.cpp | 16 +++++++++------- src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 9 +++++---- src/slic3r/GUI/ImGuiWrapper.cpp | 2 +- src/slic3r/GUI/ObjColorDialog.cpp | 6 ++++-- src/slic3r/GUI/Plater.cpp | 9 +++++---- src/slic3r/GUI/Search.cpp | 3 ++- src/slic3r/GUI/Tab.cpp | 6 ++++-- src/slic3r/GUI/wxExtensions.cpp | 11 +++++++---- 9 files changed, 44 insertions(+), 33 deletions(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 8032a24c07..fc58572138 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -345,11 +345,11 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode break; } case libvgcode::EViewType::Tool: { - sprintf(buf, "%s %s%d", buf, _u8L("Tool: ").c_str(), vertex.extruder_id + 1); + sprintf(buf, "%s %s%d", buf, _u8L("Tool: ").c_str(), filament_index_from_zero_based(static_cast(vertex.extruder_id))); break; } case libvgcode::EViewType::ColorPrint: { - sprintf(buf, "%s %s%d", buf, _u8L("Color: ").c_str(), vertex.color_id + 1); + sprintf(buf, "%s %s%d", buf, _u8L("Color: ").c_str(), filament_index_from_zero_based(static_cast(vertex.color_id))); break; } case libvgcode::EViewType::ActualVolumetricFlowRate: { @@ -2480,7 +2480,7 @@ void GCodeViewer::render_all_plates_stats(const std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(it->first + 1), offsets[_u8L("Filament")]}); + columns_offsets.push_back({ std::to_string(filament_index_from_zero_based(static_cast(it->first))), offsets[_u8L("Filament")]}); char buf[64]; double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1.0; @@ -3562,7 +3562,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv const std::vector& used_extruders_ids = m_viewer.get_used_extruders_ids(); for (uint8_t extruder_id : used_extruders_ids) { ::sprintf(buf, imperial_units ? "%.2f in %.2f g" : "%.2f m %.2f g", model_used_filaments_m[i], model_used_filaments_g[i]); - append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), { { _u8L("Extruder") + " " + std::to_string(extruder_id + 1), offsets[0]}, {buf, offsets[1]} }); + append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), { { _u8L("Extruder") + " " + std::to_string(filament_index_from_zero_based(extruder_id)), offsets[0]}, {buf, offsets[1]} }); // append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), _u8L("Extruder") + " " + std::to_string(extruder_id + 1), // true, "", 0.0f, 0.0f, offsets, used_filaments_m[extruder_id], used_filaments_g[extruder_id]); i++; @@ -3614,7 +3614,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv for (auto extruder_idx : used_extruders_ids) { if (i < model_used_filaments_m.size() && i < model_used_filaments_g.size()) { std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(extruder_idx + 1), color_print_offsets[_u8L("Filament")]}); + columns_offsets.push_back({ std::to_string(filament_index_from_zero_based(extruder_idx)), color_print_offsets[_u8L("Filament")]}); char buf[64]; float column_sum_m = 0.0f; @@ -3990,7 +3990,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ret = std::max(ret, ImGui::CalcTextSize((_u8L("Print settings") + std::string(":")).c_str()).x); if (!m_settings_ids.filament.empty()) { for (unsigned char i : m_viewer.get_used_extruders_ids()) { - ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(i + 1) + ":").c_str()).x); + ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(filament_index_from_zero_based(static_cast(i))) + ":").c_str()).x); } } if (ret > 0.0f) @@ -4017,7 +4017,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv for (unsigned char i : m_viewer.get_used_extruders_ids()) { if (i < static_cast(m_settings_ids.filament.size()) && !m_settings_ids.filament[i].empty()) { std::string txt = _u8L("Filament"); - txt += (m_viewer.get_used_extruders_count() == 1) ? ":" : " " + std::to_string(i + 1); + txt += (m_viewer.get_used_extruders_count() == 1) ? ":" : " " + std::to_string(filament_index_from_zero_based(static_cast(i))); imgui.text(txt); ImGui::SameLine(offset); imgui.text(m_settings_ids.filament[i]); @@ -4266,4 +4266,3 @@ void GCodeViewer::render_slider(int canvas_width, int canvas_height) { } // namespace GUI } // namespace Slic3r - diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index fe9b60ea93..26327ac04f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -9492,14 +9492,15 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_area_error_infos.begin()) { text += "\n"; } - int extruder_id = error_iter->first + 1; // change extruder id to 1 based + const int extruder_index = error_iter->first; + const int extruder_id = filament_index_from_zero_based(extruder_index); std::string filaments; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { if (i > 0) { filaments += ", "; } - int filament_id = error_iter->second[i].first + 1; // change filament id to 1 based + const int filament_id = filament_index_from_zero_based(error_iter->second[i].first); int object_label_id = error_iter->second[i].second; filaments += std::to_string(filament_id); @@ -9522,7 +9523,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) } } } - std::string extruder_name = extruder_name_list[extruder_id-1]; + std::string extruder_name = extruder_name_list[extruder_index]; if (error_iter->second.size() == 1) { text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable range of the %s.")) %filaments %extruder_name %extruder_name).str(); } @@ -9538,11 +9539,12 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_height_error_infos.begin()) { text += "\n"; } - int extruder_id = error_iter->first + 1; // change extruder id to 1 based + const int extruder_index = error_iter->first; + const int extruder_id = filament_index_from_zero_based(extruder_index); std::set filament_ids; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { - int filament_id = error_iter->second[i].first + 1; // change filament id to 1 based + int filament_id = filament_index_from_zero_based(error_iter->second[i].first); int object_label_id = error_iter->second[i].second; filament_ids.insert(filament_id); for (int object_idx = 0; object_idx < (int) m_model->objects.size(); ++object_idx) { @@ -9575,7 +9577,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) } } } - std::string extruder_name = extruder_name_list[extruder_id-1]; + std::string extruder_name = extruder_name_list[extruder_index]; if (error_iter->second.size() == 1) { text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable height of the %s.")) % filaments % extruder_name % extruder_name).str(); } else { @@ -9604,7 +9606,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) const std::vector &conflict_filament = m_gcode_viewer.filament_printable_reuslt.conflict_filament; auto iter = conflict_filament.begin(); for (int filament : conflict_filament) { - warning += std::to_string(filament + 1); + warning += std::to_string(filament_index_from_zero_based(filament)); warning += " "; } text = (boost::format(_u8L("filaments %s cannot be printed directly on the surface of this plate.")) % warning).str(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index af7ec15772..f0544d8b78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -192,7 +192,7 @@ void GLGizmoMmuSegmentation::data_changed(bool is_serializing) // BBS bool GLGizmoMmuSegmentation::on_number_key_down(int number) { - int extruder_idx = number - 1; + int extruder_idx = start_filament_index_at_0() ? number : number - 1; if (extruder_idx < m_extruders_colors.size() && extruder_idx >= 0) m_selected_extruder_idx = extruder_idx; @@ -403,7 +403,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott const ColorRGBA &extruder_color = m_extruders_colors[extruder_idx]; ImVec4 color_vec = ImGuiWrapper::to_ImVec4(extruder_color); std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx); - std::string item_text = std::to_string(extruder_idx + 1); + std::string item_text = std::to_string(filament_index_from_zero_based(extruder_idx)); const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f),0.f); @@ -435,7 +435,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott color_button_high = ImGui::GetCursorPos().y - color_button - 2.0; if (color_picked) { m_selected_extruder_idx = extruder_idx; } - if (extruder_idx < 16 && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width); + if (extruder_idx < 16 && ImGui::IsItemHovered()) + m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(filament_index_from_zero_based(extruder_idx)), max_tooltip_width); // draw filament id float gray = 0.299 * extruder_color.r() + 0.587 * extruder_color.g() + 0.114 * extruder_color.b(); @@ -1047,7 +1048,7 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float #endif // overlay destination number with proper contrast calculation - std::string dst_txt = std::to_string(m_extruder_remap[src] + 1); + std::string dst_txt = std::to_string(filament_index_from_zero_based(static_cast(m_extruder_remap[src]))); float gray = 0.299f * dst_col.r() + 0.587f * dst_col.g() + 0.114f * dst_col.b(); ImVec2 txt_sz = ImGui::CalcTextSize(dst_txt.c_str()); ImVec2 pos = ImGui::GetItemRectMin(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 8bd2904c49..a1920d4810 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -3274,7 +3274,7 @@ std::tuple ImGuiWrapper::calculate_filament_group_text_size(const void ImGuiWrapper::filament_group(const std::string& filament_type, const char* hex_color, unsigned char filament_id, float align_width) { //ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); - std::string id = std::to_string(static_cast (filament_id + 1)); + std::string id = std::to_string(filament_index_from_zero_based(static_cast(filament_id))); ImDrawList* draw_list = ImGui::GetWindowDrawList(); static ImTextureID transparent; ImVec2 text_size = ImGui::CalcTextSize(filament_type.c_str()); diff --git a/src/slic3r/GUI/ObjColorDialog.cpp b/src/slic3r/GUI/ObjColorDialog.cpp index 7575777507..f237c8c66f 100644 --- a/src/slic3r/GUI/ObjColorDialog.cpp +++ b/src/slic3r/GUI/ObjColorDialog.cpp @@ -409,7 +409,8 @@ ObjColorPanel::~ObjColorPanel() { void ObjColorPanel::msw_rescale() { for (unsigned int i = 0; i < m_extruder_icon_list.size(); ++i) { - auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(i + 1), FromDIP(16), FromDIP(16)); + const int display_index = filament_index_from_zero_based(static_cast(i)); + auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(display_index), FromDIP(16), FromDIP(16)); m_extruder_icon_list[i]->SetBitmap(bitmap); } /* for (unsigned int i = 0; i < m_color_cluster_icon_list.size(); ++i) { @@ -530,7 +531,8 @@ wxBoxSizer *ObjColorPanel::create_extruder_icon_and_rgba_sizer(wxWindow *parent, { auto icon_sizer = new wxBoxSizer(wxHORIZONTAL); wxButton *icon = new wxButton(parent, wxID_ANY, {}, wxDefaultPosition, ICON_SIZE, wxBORDER_NONE | wxBU_AUTODRAW); - icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(id + 1), FromDIP(16), FromDIP(16))); + const int display_index = filament_index_from_zero_based(id); + icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(display_index), FromDIP(16), FromDIP(16))); icon->SetCanFocus(false); m_extruder_icon_list.emplace_back(icon); icon_sizer->Add(icon, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 0); // wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5da3520660..21e8ba432f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -834,7 +834,7 @@ struct DynamicFilamentList1Based : DynamicFilamentList wxString get_value(int index) override { wxString str; - str << index+1; + str << filament_index_from_zero_based(index); return str; } int index_of(wxString value) override @@ -842,8 +842,9 @@ struct DynamicFilamentList1Based : DynamicFilamentList long n = 0; if(!value.ToLong(&n)) return -1; - --n; - return (n >= 0 && n <= items.size()) ? int(n) : -1; + if (!start_filament_index_at_0()) + --n; + return (n >= 0 && n <= static_cast(items.size())) ? int(n) : -1; } void update(bool force = false) { @@ -2277,7 +2278,7 @@ void Sidebar::init_filament_combo(PlaterPresetComboBox **combo, const int filame if ((filament_idx % 2) == 0) // Dont add right column item. this one create equal spacing on left, right & middle combo_and_btn_sizer->AddSpacer(FromDIP((filament_idx % 2) == 0 ? 12 : 3)); // Content Margin - (*combo)->clr_picker->SetLabel(wxString::Format("%d", filament_idx + 1)); + (*combo)->clr_picker->SetLabel(wxString::Format("%d", filament_index_from_zero_based(filament_idx))); combo_and_btn_sizer->Add((*combo)->clr_picker, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(SidebarProps::ElementSpacing()) - FromDIP(2)); // ElementSpacing - 2 (from combo box)) combo_and_btn_sizer->Add(*combo, 1, wxALL | wxEXPAND, FromDIP(2))->SetMinSize({-1, FromDIP(30)}); diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index 1aef329297..e70b861efe 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -13,6 +13,7 @@ #include "libslic3r/PrintConfig.hpp" #include "libslic3r/PresetBundle.hpp" +#include "GUI.hpp" #include "GUI_App.hpp" #include "Plater.hpp" #include "Tab.hpp" @@ -338,7 +339,7 @@ static Option create_option(const std::string &opt_key, const wxString &label, P wxString category = gc.category; if (type == Preset::TYPE_PRINTER && category.Contains("Extruder ")) { std::string opt_idx = opt_key.substr(opt_key.find("#") + 1); - category = wxString::Format("%s %d", "Extruder", atoi(opt_idx.c_str()) + 1); + category = wxString::Format("%s %d", "Extruder", GUI::filament_index_from_zero_based(std::atoi(opt_idx.c_str()))); } return Option{boost::nowide::widen(get_key(opt_key, type)), diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index ce70205b3b..70251ef1e1 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4927,7 +4927,9 @@ if (is_marlin_flavor) // Orca: build missed extruder pages for (auto extruder_idx = m_extruders_count_old; extruder_idx < m_extruders_count; ++extruder_idx) { - const wxString& page_name = (m_extruders_count > 1) ? wxString::Format("Extruder %d", int(extruder_idx + 1)) : wxString::Format("Extruder"); + const wxString& page_name = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) + : wxString::Format("Extruder"); //# build page //const wxString& page_name = wxString::Format("Extruder %d", int(extruder_idx + 1)); @@ -5057,7 +5059,7 @@ if (is_marlin_flavor) if (m_extruders_count == 1) first_extruder_title = wxString::Format("Extruder"); } else if (m_extruders_count_old == 1) { - first_extruder_title = wxString::Format("Extruder %d", 1); + first_extruder_title = wxString::Format("Extruder %d", filament_index_from_zero_based(0)); } auto & searcher = wxGetApp().sidebar().get_searcher(); for (auto &group : m_pages[n_before_extruders]->m_optgroups) { diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 2fecf52bd2..c17b685d4f 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -548,13 +548,15 @@ std::vector get_extruder_color_icons(bool thin_icon/* = false*/) int index = 0; for (const auto &colors : readable_color_info) { - auto label = std::to_string(++index); - bool is_gradient = ctype[index-1] == "0"; + const int display_index = filament_index_from_zero_based(index); + auto label = std::to_string(display_index); + bool is_gradient = ctype[index] == "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)); } + ++index; } } else { std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); @@ -565,8 +567,10 @@ std::vector get_extruder_color_icons(bool thin_icon/* = false*/) const int icon_height = lround(2 * em); int index = 0; for (const auto &color : colors) { - auto label = std::to_string(++index); + const int display_index = filament_index_from_zero_based(index); + auto label = std::to_string(display_index); bmps.push_back(get_extruder_color_icon(color, label, icon_width, icon_height)); + ++index; } } return bmps; @@ -1362,4 +1366,3 @@ void ImageTransientPopup::OnMouse(wxMouseEvent &event) event.Skip(); } - From c37fce4938d6eec61fdbc40ff0ed99036f2f0107 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 15:09:29 -0500 Subject: [PATCH 21/57] Label filament menu items with display index --- src/slic3r/GUI/GCodeViewer.cpp | 15 +++++++-------- src/slic3r/GUI/GLCanvas3D.cpp | 16 +++++++++------- src/slic3r/GUI/GUI_Factories.cpp | 14 +++++++++----- src/slic3r/GUI/GUI_ObjectTable.cpp | 3 ++- src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 9 +++++---- src/slic3r/GUI/ImGuiWrapper.cpp | 2 +- src/slic3r/GUI/ObjColorDialog.cpp | 6 ++++-- src/slic3r/GUI/Plater.cpp | 9 +++++---- src/slic3r/GUI/Search.cpp | 3 ++- src/slic3r/GUI/Tab.cpp | 6 ++++-- src/slic3r/GUI/wxExtensions.cpp | 11 +++++++---- 11 files changed, 55 insertions(+), 39 deletions(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 8032a24c07..fc58572138 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -345,11 +345,11 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode break; } case libvgcode::EViewType::Tool: { - sprintf(buf, "%s %s%d", buf, _u8L("Tool: ").c_str(), vertex.extruder_id + 1); + sprintf(buf, "%s %s%d", buf, _u8L("Tool: ").c_str(), filament_index_from_zero_based(static_cast(vertex.extruder_id))); break; } case libvgcode::EViewType::ColorPrint: { - sprintf(buf, "%s %s%d", buf, _u8L("Color: ").c_str(), vertex.color_id + 1); + sprintf(buf, "%s %s%d", buf, _u8L("Color: ").c_str(), filament_index_from_zero_based(static_cast(vertex.color_id))); break; } case libvgcode::EViewType::ActualVolumetricFlowRate: { @@ -2480,7 +2480,7 @@ void GCodeViewer::render_all_plates_stats(const std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(it->first + 1), offsets[_u8L("Filament")]}); + columns_offsets.push_back({ std::to_string(filament_index_from_zero_based(static_cast(it->first))), offsets[_u8L("Filament")]}); char buf[64]; double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1.0; @@ -3562,7 +3562,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv const std::vector& used_extruders_ids = m_viewer.get_used_extruders_ids(); for (uint8_t extruder_id : used_extruders_ids) { ::sprintf(buf, imperial_units ? "%.2f in %.2f g" : "%.2f m %.2f g", model_used_filaments_m[i], model_used_filaments_g[i]); - append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), { { _u8L("Extruder") + " " + std::to_string(extruder_id + 1), offsets[0]}, {buf, offsets[1]} }); + append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), { { _u8L("Extruder") + " " + std::to_string(filament_index_from_zero_based(extruder_id)), offsets[0]}, {buf, offsets[1]} }); // append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), _u8L("Extruder") + " " + std::to_string(extruder_id + 1), // true, "", 0.0f, 0.0f, offsets, used_filaments_m[extruder_id], used_filaments_g[extruder_id]); i++; @@ -3614,7 +3614,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv for (auto extruder_idx : used_extruders_ids) { if (i < model_used_filaments_m.size() && i < model_used_filaments_g.size()) { std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(extruder_idx + 1), color_print_offsets[_u8L("Filament")]}); + columns_offsets.push_back({ std::to_string(filament_index_from_zero_based(extruder_idx)), color_print_offsets[_u8L("Filament")]}); char buf[64]; float column_sum_m = 0.0f; @@ -3990,7 +3990,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ret = std::max(ret, ImGui::CalcTextSize((_u8L("Print settings") + std::string(":")).c_str()).x); if (!m_settings_ids.filament.empty()) { for (unsigned char i : m_viewer.get_used_extruders_ids()) { - ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(i + 1) + ":").c_str()).x); + ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(filament_index_from_zero_based(static_cast(i))) + ":").c_str()).x); } } if (ret > 0.0f) @@ -4017,7 +4017,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv for (unsigned char i : m_viewer.get_used_extruders_ids()) { if (i < static_cast(m_settings_ids.filament.size()) && !m_settings_ids.filament[i].empty()) { std::string txt = _u8L("Filament"); - txt += (m_viewer.get_used_extruders_count() == 1) ? ":" : " " + std::to_string(i + 1); + txt += (m_viewer.get_used_extruders_count() == 1) ? ":" : " " + std::to_string(filament_index_from_zero_based(static_cast(i))); imgui.text(txt); ImGui::SameLine(offset); imgui.text(m_settings_ids.filament[i]); @@ -4266,4 +4266,3 @@ void GCodeViewer::render_slider(int canvas_width, int canvas_height) { } // namespace GUI } // namespace Slic3r - diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index fe9b60ea93..26327ac04f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -9492,14 +9492,15 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_area_error_infos.begin()) { text += "\n"; } - int extruder_id = error_iter->first + 1; // change extruder id to 1 based + const int extruder_index = error_iter->first; + const int extruder_id = filament_index_from_zero_based(extruder_index); std::string filaments; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { if (i > 0) { filaments += ", "; } - int filament_id = error_iter->second[i].first + 1; // change filament id to 1 based + const int filament_id = filament_index_from_zero_based(error_iter->second[i].first); int object_label_id = error_iter->second[i].second; filaments += std::to_string(filament_id); @@ -9522,7 +9523,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) } } } - std::string extruder_name = extruder_name_list[extruder_id-1]; + std::string extruder_name = extruder_name_list[extruder_index]; if (error_iter->second.size() == 1) { text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable range of the %s.")) %filaments %extruder_name %extruder_name).str(); } @@ -9538,11 +9539,12 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_height_error_infos.begin()) { text += "\n"; } - int extruder_id = error_iter->first + 1; // change extruder id to 1 based + const int extruder_index = error_iter->first; + const int extruder_id = filament_index_from_zero_based(extruder_index); std::set filament_ids; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { - int filament_id = error_iter->second[i].first + 1; // change filament id to 1 based + int filament_id = filament_index_from_zero_based(error_iter->second[i].first); int object_label_id = error_iter->second[i].second; filament_ids.insert(filament_id); for (int object_idx = 0; object_idx < (int) m_model->objects.size(); ++object_idx) { @@ -9575,7 +9577,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) } } } - std::string extruder_name = extruder_name_list[extruder_id-1]; + std::string extruder_name = extruder_name_list[extruder_index]; if (error_iter->second.size() == 1) { text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable height of the %s.")) % filaments % extruder_name % extruder_name).str(); } else { @@ -9604,7 +9606,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) const std::vector &conflict_filament = m_gcode_viewer.filament_printable_reuslt.conflict_filament; auto iter = conflict_filament.begin(); for (int filament : conflict_filament) { - warning += std::to_string(filament + 1); + warning += std::to_string(filament_index_from_zero_based(filament)); warning += " "; } text = (boost::format(_u8L("filaments %s cannot be printed directly on the surface of this plate.")) % warning).str(); diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 79dd49901a..36b76133d5 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -924,11 +924,12 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) wxString item_name = _L("Default"); if (i > 0) { + const int display_index = filament_index_from_one_based(i); auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i - 1]); if (preset == nullptr) { - item_name = wxString::Format(_L("Filament %d"), filament_index_from_one_based(i)); + item_name = wxString::Format(_L("Filament %d"), display_index); } else { - item_name = from_u8(preset->label(false)); + item_name = wxString::Format("%d: %s", display_index, from_u8(preset->label(false))); } } @@ -1527,8 +1528,10 @@ void MenuFactory::create_filament_action_menu(bool init, int active_filament_men if (i == active_filament_menu_id) continue; + const int display_index = filament_index_from_zero_based(i); auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i]); - wxString item_name = preset ? from_u8(preset->label(false)) : wxString::Format(_L("Filament %d"), filament_index_from_zero_based(i)); + wxString item_name = preset ? wxString::Format("%d: %s", display_index, from_u8(preset->label(false))) + : wxString::Format(_L("Filament %d"), display_index); append_menu_item(sub_menu, wxID_ANY, item_name, "", [i](wxCommandEvent&) { plater()->sidebar().change_filament(-2, i); }, *icons[i], menu, @@ -2084,11 +2087,12 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu) wxString item_name = _L("Default"); if (i > 0) { + const int display_index = filament_index_from_one_based(i); auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i - 1]); if (preset == nullptr) { - item_name = wxString::Format(_L("Filament %d"), filament_index_from_one_based(i)); + item_name = wxString::Format(_L("Filament %d"), display_index); } else { - item_name = from_u8(preset->label(false)); + item_name = wxString::Format("%d: %s", display_index, from_u8(preset->label(false))); } } diff --git a/src/slic3r/GUI/GUI_ObjectTable.cpp b/src/slic3r/GUI/GUI_ObjectTable.cpp index 35df1f460e..450c38373f 100644 --- a/src/slic3r/GUI/GUI_ObjectTable.cpp +++ b/src/slic3r/GUI/GUI_ObjectTable.cpp @@ -2846,7 +2846,8 @@ int ObjectTablePanel::init_filaments_and_colors() } //parse the filaments - m_filaments_name[i] = wxString(std::to_string(i+1) + ": " + filament_presets[i]); + const int display_index = filament_index_from_zero_based(static_cast(i)); + m_filaments_name[i] = wxString(std::to_string(display_index) + ": " + filament_presets[i]); i++; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index af7ec15772..f0544d8b78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -192,7 +192,7 @@ void GLGizmoMmuSegmentation::data_changed(bool is_serializing) // BBS bool GLGizmoMmuSegmentation::on_number_key_down(int number) { - int extruder_idx = number - 1; + int extruder_idx = start_filament_index_at_0() ? number : number - 1; if (extruder_idx < m_extruders_colors.size() && extruder_idx >= 0) m_selected_extruder_idx = extruder_idx; @@ -403,7 +403,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott const ColorRGBA &extruder_color = m_extruders_colors[extruder_idx]; ImVec4 color_vec = ImGuiWrapper::to_ImVec4(extruder_color); std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx); - std::string item_text = std::to_string(extruder_idx + 1); + std::string item_text = std::to_string(filament_index_from_zero_based(extruder_idx)); const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f),0.f); @@ -435,7 +435,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott color_button_high = ImGui::GetCursorPos().y - color_button - 2.0; if (color_picked) { m_selected_extruder_idx = extruder_idx; } - if (extruder_idx < 16 && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width); + if (extruder_idx < 16 && ImGui::IsItemHovered()) + m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(filament_index_from_zero_based(extruder_idx)), max_tooltip_width); // draw filament id float gray = 0.299 * extruder_color.r() + 0.587 * extruder_color.g() + 0.114 * extruder_color.b(); @@ -1047,7 +1048,7 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float #endif // overlay destination number with proper contrast calculation - std::string dst_txt = std::to_string(m_extruder_remap[src] + 1); + std::string dst_txt = std::to_string(filament_index_from_zero_based(static_cast(m_extruder_remap[src]))); float gray = 0.299f * dst_col.r() + 0.587f * dst_col.g() + 0.114f * dst_col.b(); ImVec2 txt_sz = ImGui::CalcTextSize(dst_txt.c_str()); ImVec2 pos = ImGui::GetItemRectMin(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 8bd2904c49..a1920d4810 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -3274,7 +3274,7 @@ std::tuple ImGuiWrapper::calculate_filament_group_text_size(const void ImGuiWrapper::filament_group(const std::string& filament_type, const char* hex_color, unsigned char filament_id, float align_width) { //ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); - std::string id = std::to_string(static_cast (filament_id + 1)); + std::string id = std::to_string(filament_index_from_zero_based(static_cast(filament_id))); ImDrawList* draw_list = ImGui::GetWindowDrawList(); static ImTextureID transparent; ImVec2 text_size = ImGui::CalcTextSize(filament_type.c_str()); diff --git a/src/slic3r/GUI/ObjColorDialog.cpp b/src/slic3r/GUI/ObjColorDialog.cpp index 7575777507..f237c8c66f 100644 --- a/src/slic3r/GUI/ObjColorDialog.cpp +++ b/src/slic3r/GUI/ObjColorDialog.cpp @@ -409,7 +409,8 @@ ObjColorPanel::~ObjColorPanel() { void ObjColorPanel::msw_rescale() { for (unsigned int i = 0; i < m_extruder_icon_list.size(); ++i) { - auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(i + 1), FromDIP(16), FromDIP(16)); + const int display_index = filament_index_from_zero_based(static_cast(i)); + auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(display_index), FromDIP(16), FromDIP(16)); m_extruder_icon_list[i]->SetBitmap(bitmap); } /* for (unsigned int i = 0; i < m_color_cluster_icon_list.size(); ++i) { @@ -530,7 +531,8 @@ wxBoxSizer *ObjColorPanel::create_extruder_icon_and_rgba_sizer(wxWindow *parent, { auto icon_sizer = new wxBoxSizer(wxHORIZONTAL); wxButton *icon = new wxButton(parent, wxID_ANY, {}, wxDefaultPosition, ICON_SIZE, wxBORDER_NONE | wxBU_AUTODRAW); - icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(id + 1), FromDIP(16), FromDIP(16))); + const int display_index = filament_index_from_zero_based(id); + icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(display_index), FromDIP(16), FromDIP(16))); icon->SetCanFocus(false); m_extruder_icon_list.emplace_back(icon); icon_sizer->Add(icon, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 0); // wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5da3520660..21e8ba432f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -834,7 +834,7 @@ struct DynamicFilamentList1Based : DynamicFilamentList wxString get_value(int index) override { wxString str; - str << index+1; + str << filament_index_from_zero_based(index); return str; } int index_of(wxString value) override @@ -842,8 +842,9 @@ struct DynamicFilamentList1Based : DynamicFilamentList long n = 0; if(!value.ToLong(&n)) return -1; - --n; - return (n >= 0 && n <= items.size()) ? int(n) : -1; + if (!start_filament_index_at_0()) + --n; + return (n >= 0 && n <= static_cast(items.size())) ? int(n) : -1; } void update(bool force = false) { @@ -2277,7 +2278,7 @@ void Sidebar::init_filament_combo(PlaterPresetComboBox **combo, const int filame if ((filament_idx % 2) == 0) // Dont add right column item. this one create equal spacing on left, right & middle combo_and_btn_sizer->AddSpacer(FromDIP((filament_idx % 2) == 0 ? 12 : 3)); // Content Margin - (*combo)->clr_picker->SetLabel(wxString::Format("%d", filament_idx + 1)); + (*combo)->clr_picker->SetLabel(wxString::Format("%d", filament_index_from_zero_based(filament_idx))); combo_and_btn_sizer->Add((*combo)->clr_picker, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(SidebarProps::ElementSpacing()) - FromDIP(2)); // ElementSpacing - 2 (from combo box)) combo_and_btn_sizer->Add(*combo, 1, wxALL | wxEXPAND, FromDIP(2))->SetMinSize({-1, FromDIP(30)}); diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index 1aef329297..e70b861efe 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -13,6 +13,7 @@ #include "libslic3r/PrintConfig.hpp" #include "libslic3r/PresetBundle.hpp" +#include "GUI.hpp" #include "GUI_App.hpp" #include "Plater.hpp" #include "Tab.hpp" @@ -338,7 +339,7 @@ static Option create_option(const std::string &opt_key, const wxString &label, P wxString category = gc.category; if (type == Preset::TYPE_PRINTER && category.Contains("Extruder ")) { std::string opt_idx = opt_key.substr(opt_key.find("#") + 1); - category = wxString::Format("%s %d", "Extruder", atoi(opt_idx.c_str()) + 1); + category = wxString::Format("%s %d", "Extruder", GUI::filament_index_from_zero_based(std::atoi(opt_idx.c_str()))); } return Option{boost::nowide::widen(get_key(opt_key, type)), diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index ce70205b3b..70251ef1e1 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4927,7 +4927,9 @@ if (is_marlin_flavor) // Orca: build missed extruder pages for (auto extruder_idx = m_extruders_count_old; extruder_idx < m_extruders_count; ++extruder_idx) { - const wxString& page_name = (m_extruders_count > 1) ? wxString::Format("Extruder %d", int(extruder_idx + 1)) : wxString::Format("Extruder"); + const wxString& page_name = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) + : wxString::Format("Extruder"); //# build page //const wxString& page_name = wxString::Format("Extruder %d", int(extruder_idx + 1)); @@ -5057,7 +5059,7 @@ if (is_marlin_flavor) if (m_extruders_count == 1) first_extruder_title = wxString::Format("Extruder"); } else if (m_extruders_count_old == 1) { - first_extruder_title = wxString::Format("Extruder %d", 1); + first_extruder_title = wxString::Format("Extruder %d", filament_index_from_zero_based(0)); } auto & searcher = wxGetApp().sidebar().get_searcher(); for (auto &group : m_pages[n_before_extruders]->m_optgroups) { diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 2fecf52bd2..c17b685d4f 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -548,13 +548,15 @@ std::vector get_extruder_color_icons(bool thin_icon/* = false*/) int index = 0; for (const auto &colors : readable_color_info) { - auto label = std::to_string(++index); - bool is_gradient = ctype[index-1] == "0"; + const int display_index = filament_index_from_zero_based(index); + auto label = std::to_string(display_index); + bool is_gradient = ctype[index] == "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)); } + ++index; } } else { std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); @@ -565,8 +567,10 @@ std::vector get_extruder_color_icons(bool thin_icon/* = false*/) const int icon_height = lround(2 * em); int index = 0; for (const auto &color : colors) { - auto label = std::to_string(++index); + const int display_index = filament_index_from_zero_based(index); + auto label = std::to_string(display_index); bmps.push_back(get_extruder_color_icon(color, label, icon_width, icon_height)); + ++index; } } return bmps; @@ -1362,4 +1366,3 @@ void ImageTransientPopup::OnMouse(wxMouseEvent &event) event.Skip(); } - From 9e5d0b910e1a23cdba628f4ab9658675b6fe7046 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 15:14:20 -0500 Subject: [PATCH 22/57] Fix namespace for filament index helpers --- src/slic3r/GUI/GCodeViewer.cpp | 15 +++++++-------- src/slic3r/GUI/GLCanvas3D.cpp | 16 +++++++++------- src/slic3r/GUI/GUI_Factories.cpp | 14 +++++++++----- src/slic3r/GUI/GUI_ObjectTable.cpp | 3 ++- src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 9 +++++---- src/slic3r/GUI/ImGuiWrapper.cpp | 2 +- src/slic3r/GUI/ObjColorDialog.cpp | 6 ++++-- src/slic3r/GUI/Plater.cpp | 9 +++++---- src/slic3r/GUI/Search.cpp | 3 ++- src/slic3r/GUI/Tab.cpp | 6 ++++-- src/slic3r/GUI/wxExtensions.cpp | 12 +++++++----- 11 files changed, 55 insertions(+), 40 deletions(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 8032a24c07..fc58572138 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -345,11 +345,11 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode break; } case libvgcode::EViewType::Tool: { - sprintf(buf, "%s %s%d", buf, _u8L("Tool: ").c_str(), vertex.extruder_id + 1); + sprintf(buf, "%s %s%d", buf, _u8L("Tool: ").c_str(), filament_index_from_zero_based(static_cast(vertex.extruder_id))); break; } case libvgcode::EViewType::ColorPrint: { - sprintf(buf, "%s %s%d", buf, _u8L("Color: ").c_str(), vertex.color_id + 1); + sprintf(buf, "%s %s%d", buf, _u8L("Color: ").c_str(), filament_index_from_zero_based(static_cast(vertex.color_id))); break; } case libvgcode::EViewType::ActualVolumetricFlowRate: { @@ -2480,7 +2480,7 @@ void GCodeViewer::render_all_plates_stats(const std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(it->first + 1), offsets[_u8L("Filament")]}); + columns_offsets.push_back({ std::to_string(filament_index_from_zero_based(static_cast(it->first))), offsets[_u8L("Filament")]}); char buf[64]; double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1.0; @@ -3562,7 +3562,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv const std::vector& used_extruders_ids = m_viewer.get_used_extruders_ids(); for (uint8_t extruder_id : used_extruders_ids) { ::sprintf(buf, imperial_units ? "%.2f in %.2f g" : "%.2f m %.2f g", model_used_filaments_m[i], model_used_filaments_g[i]); - append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), { { _u8L("Extruder") + " " + std::to_string(extruder_id + 1), offsets[0]}, {buf, offsets[1]} }); + append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), { { _u8L("Extruder") + " " + std::to_string(filament_index_from_zero_based(extruder_id)), offsets[0]}, {buf, offsets[1]} }); // append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), _u8L("Extruder") + " " + std::to_string(extruder_id + 1), // true, "", 0.0f, 0.0f, offsets, used_filaments_m[extruder_id], used_filaments_g[extruder_id]); i++; @@ -3614,7 +3614,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv for (auto extruder_idx : used_extruders_ids) { if (i < model_used_filaments_m.size() && i < model_used_filaments_g.size()) { std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(extruder_idx + 1), color_print_offsets[_u8L("Filament")]}); + columns_offsets.push_back({ std::to_string(filament_index_from_zero_based(extruder_idx)), color_print_offsets[_u8L("Filament")]}); char buf[64]; float column_sum_m = 0.0f; @@ -3990,7 +3990,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ret = std::max(ret, ImGui::CalcTextSize((_u8L("Print settings") + std::string(":")).c_str()).x); if (!m_settings_ids.filament.empty()) { for (unsigned char i : m_viewer.get_used_extruders_ids()) { - ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(i + 1) + ":").c_str()).x); + ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(filament_index_from_zero_based(static_cast(i))) + ":").c_str()).x); } } if (ret > 0.0f) @@ -4017,7 +4017,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv for (unsigned char i : m_viewer.get_used_extruders_ids()) { if (i < static_cast(m_settings_ids.filament.size()) && !m_settings_ids.filament[i].empty()) { std::string txt = _u8L("Filament"); - txt += (m_viewer.get_used_extruders_count() == 1) ? ":" : " " + std::to_string(i + 1); + txt += (m_viewer.get_used_extruders_count() == 1) ? ":" : " " + std::to_string(filament_index_from_zero_based(static_cast(i))); imgui.text(txt); ImGui::SameLine(offset); imgui.text(m_settings_ids.filament[i]); @@ -4266,4 +4266,3 @@ void GCodeViewer::render_slider(int canvas_width, int canvas_height) { } // namespace GUI } // namespace Slic3r - diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index fe9b60ea93..26327ac04f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -9492,14 +9492,15 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_area_error_infos.begin()) { text += "\n"; } - int extruder_id = error_iter->first + 1; // change extruder id to 1 based + const int extruder_index = error_iter->first; + const int extruder_id = filament_index_from_zero_based(extruder_index); std::string filaments; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { if (i > 0) { filaments += ", "; } - int filament_id = error_iter->second[i].first + 1; // change filament id to 1 based + const int filament_id = filament_index_from_zero_based(error_iter->second[i].first); int object_label_id = error_iter->second[i].second; filaments += std::to_string(filament_id); @@ -9522,7 +9523,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) } } } - std::string extruder_name = extruder_name_list[extruder_id-1]; + std::string extruder_name = extruder_name_list[extruder_index]; if (error_iter->second.size() == 1) { text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable range of the %s.")) %filaments %extruder_name %extruder_name).str(); } @@ -9538,11 +9539,12 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_height_error_infos.begin()) { text += "\n"; } - int extruder_id = error_iter->first + 1; // change extruder id to 1 based + const int extruder_index = error_iter->first; + const int extruder_id = filament_index_from_zero_based(extruder_index); std::set filament_ids; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { - int filament_id = error_iter->second[i].first + 1; // change filament id to 1 based + int filament_id = filament_index_from_zero_based(error_iter->second[i].first); int object_label_id = error_iter->second[i].second; filament_ids.insert(filament_id); for (int object_idx = 0; object_idx < (int) m_model->objects.size(); ++object_idx) { @@ -9575,7 +9577,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) } } } - std::string extruder_name = extruder_name_list[extruder_id-1]; + std::string extruder_name = extruder_name_list[extruder_index]; if (error_iter->second.size() == 1) { text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable height of the %s.")) % filaments % extruder_name % extruder_name).str(); } else { @@ -9604,7 +9606,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) const std::vector &conflict_filament = m_gcode_viewer.filament_printable_reuslt.conflict_filament; auto iter = conflict_filament.begin(); for (int filament : conflict_filament) { - warning += std::to_string(filament + 1); + warning += std::to_string(filament_index_from_zero_based(filament)); warning += " "; } text = (boost::format(_u8L("filaments %s cannot be printed directly on the surface of this plate.")) % warning).str(); diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 79dd49901a..36b76133d5 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -924,11 +924,12 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) wxString item_name = _L("Default"); if (i > 0) { + const int display_index = filament_index_from_one_based(i); auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i - 1]); if (preset == nullptr) { - item_name = wxString::Format(_L("Filament %d"), filament_index_from_one_based(i)); + item_name = wxString::Format(_L("Filament %d"), display_index); } else { - item_name = from_u8(preset->label(false)); + item_name = wxString::Format("%d: %s", display_index, from_u8(preset->label(false))); } } @@ -1527,8 +1528,10 @@ void MenuFactory::create_filament_action_menu(bool init, int active_filament_men if (i == active_filament_menu_id) continue; + const int display_index = filament_index_from_zero_based(i); auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i]); - wxString item_name = preset ? from_u8(preset->label(false)) : wxString::Format(_L("Filament %d"), filament_index_from_zero_based(i)); + wxString item_name = preset ? wxString::Format("%d: %s", display_index, from_u8(preset->label(false))) + : wxString::Format(_L("Filament %d"), display_index); append_menu_item(sub_menu, wxID_ANY, item_name, "", [i](wxCommandEvent&) { plater()->sidebar().change_filament(-2, i); }, *icons[i], menu, @@ -2084,11 +2087,12 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu) wxString item_name = _L("Default"); if (i > 0) { + const int display_index = filament_index_from_one_based(i); auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i - 1]); if (preset == nullptr) { - item_name = wxString::Format(_L("Filament %d"), filament_index_from_one_based(i)); + item_name = wxString::Format(_L("Filament %d"), display_index); } else { - item_name = from_u8(preset->label(false)); + item_name = wxString::Format("%d: %s", display_index, from_u8(preset->label(false))); } } diff --git a/src/slic3r/GUI/GUI_ObjectTable.cpp b/src/slic3r/GUI/GUI_ObjectTable.cpp index 35df1f460e..450c38373f 100644 --- a/src/slic3r/GUI/GUI_ObjectTable.cpp +++ b/src/slic3r/GUI/GUI_ObjectTable.cpp @@ -2846,7 +2846,8 @@ int ObjectTablePanel::init_filaments_and_colors() } //parse the filaments - m_filaments_name[i] = wxString(std::to_string(i+1) + ": " + filament_presets[i]); + const int display_index = filament_index_from_zero_based(static_cast(i)); + m_filaments_name[i] = wxString(std::to_string(display_index) + ": " + filament_presets[i]); i++; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index af7ec15772..f0544d8b78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -192,7 +192,7 @@ void GLGizmoMmuSegmentation::data_changed(bool is_serializing) // BBS bool GLGizmoMmuSegmentation::on_number_key_down(int number) { - int extruder_idx = number - 1; + int extruder_idx = start_filament_index_at_0() ? number : number - 1; if (extruder_idx < m_extruders_colors.size() && extruder_idx >= 0) m_selected_extruder_idx = extruder_idx; @@ -403,7 +403,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott const ColorRGBA &extruder_color = m_extruders_colors[extruder_idx]; ImVec4 color_vec = ImGuiWrapper::to_ImVec4(extruder_color); std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx); - std::string item_text = std::to_string(extruder_idx + 1); + std::string item_text = std::to_string(filament_index_from_zero_based(extruder_idx)); const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f),0.f); @@ -435,7 +435,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott color_button_high = ImGui::GetCursorPos().y - color_button - 2.0; if (color_picked) { m_selected_extruder_idx = extruder_idx; } - if (extruder_idx < 16 && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width); + if (extruder_idx < 16 && ImGui::IsItemHovered()) + m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(filament_index_from_zero_based(extruder_idx)), max_tooltip_width); // draw filament id float gray = 0.299 * extruder_color.r() + 0.587 * extruder_color.g() + 0.114 * extruder_color.b(); @@ -1047,7 +1048,7 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float #endif // overlay destination number with proper contrast calculation - std::string dst_txt = std::to_string(m_extruder_remap[src] + 1); + std::string dst_txt = std::to_string(filament_index_from_zero_based(static_cast(m_extruder_remap[src]))); float gray = 0.299f * dst_col.r() + 0.587f * dst_col.g() + 0.114f * dst_col.b(); ImVec2 txt_sz = ImGui::CalcTextSize(dst_txt.c_str()); ImVec2 pos = ImGui::GetItemRectMin(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 8bd2904c49..a1920d4810 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -3274,7 +3274,7 @@ std::tuple ImGuiWrapper::calculate_filament_group_text_size(const void ImGuiWrapper::filament_group(const std::string& filament_type, const char* hex_color, unsigned char filament_id, float align_width) { //ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); - std::string id = std::to_string(static_cast (filament_id + 1)); + std::string id = std::to_string(filament_index_from_zero_based(static_cast(filament_id))); ImDrawList* draw_list = ImGui::GetWindowDrawList(); static ImTextureID transparent; ImVec2 text_size = ImGui::CalcTextSize(filament_type.c_str()); diff --git a/src/slic3r/GUI/ObjColorDialog.cpp b/src/slic3r/GUI/ObjColorDialog.cpp index 7575777507..f237c8c66f 100644 --- a/src/slic3r/GUI/ObjColorDialog.cpp +++ b/src/slic3r/GUI/ObjColorDialog.cpp @@ -409,7 +409,8 @@ ObjColorPanel::~ObjColorPanel() { void ObjColorPanel::msw_rescale() { for (unsigned int i = 0; i < m_extruder_icon_list.size(); ++i) { - auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(i + 1), FromDIP(16), FromDIP(16)); + const int display_index = filament_index_from_zero_based(static_cast(i)); + auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(display_index), FromDIP(16), FromDIP(16)); m_extruder_icon_list[i]->SetBitmap(bitmap); } /* for (unsigned int i = 0; i < m_color_cluster_icon_list.size(); ++i) { @@ -530,7 +531,8 @@ wxBoxSizer *ObjColorPanel::create_extruder_icon_and_rgba_sizer(wxWindow *parent, { auto icon_sizer = new wxBoxSizer(wxHORIZONTAL); wxButton *icon = new wxButton(parent, wxID_ANY, {}, wxDefaultPosition, ICON_SIZE, wxBORDER_NONE | wxBU_AUTODRAW); - icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(id + 1), FromDIP(16), FromDIP(16))); + const int display_index = filament_index_from_zero_based(id); + icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(display_index), FromDIP(16), FromDIP(16))); icon->SetCanFocus(false); m_extruder_icon_list.emplace_back(icon); icon_sizer->Add(icon, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 0); // wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5da3520660..21e8ba432f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -834,7 +834,7 @@ struct DynamicFilamentList1Based : DynamicFilamentList wxString get_value(int index) override { wxString str; - str << index+1; + str << filament_index_from_zero_based(index); return str; } int index_of(wxString value) override @@ -842,8 +842,9 @@ struct DynamicFilamentList1Based : DynamicFilamentList long n = 0; if(!value.ToLong(&n)) return -1; - --n; - return (n >= 0 && n <= items.size()) ? int(n) : -1; + if (!start_filament_index_at_0()) + --n; + return (n >= 0 && n <= static_cast(items.size())) ? int(n) : -1; } void update(bool force = false) { @@ -2277,7 +2278,7 @@ void Sidebar::init_filament_combo(PlaterPresetComboBox **combo, const int filame if ((filament_idx % 2) == 0) // Dont add right column item. this one create equal spacing on left, right & middle combo_and_btn_sizer->AddSpacer(FromDIP((filament_idx % 2) == 0 ? 12 : 3)); // Content Margin - (*combo)->clr_picker->SetLabel(wxString::Format("%d", filament_idx + 1)); + (*combo)->clr_picker->SetLabel(wxString::Format("%d", filament_index_from_zero_based(filament_idx))); combo_and_btn_sizer->Add((*combo)->clr_picker, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(SidebarProps::ElementSpacing()) - FromDIP(2)); // ElementSpacing - 2 (from combo box)) combo_and_btn_sizer->Add(*combo, 1, wxALL | wxEXPAND, FromDIP(2))->SetMinSize({-1, FromDIP(30)}); diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index 1aef329297..e70b861efe 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -13,6 +13,7 @@ #include "libslic3r/PrintConfig.hpp" #include "libslic3r/PresetBundle.hpp" +#include "GUI.hpp" #include "GUI_App.hpp" #include "Plater.hpp" #include "Tab.hpp" @@ -338,7 +339,7 @@ static Option create_option(const std::string &opt_key, const wxString &label, P wxString category = gc.category; if (type == Preset::TYPE_PRINTER && category.Contains("Extruder ")) { std::string opt_idx = opt_key.substr(opt_key.find("#") + 1); - category = wxString::Format("%s %d", "Extruder", atoi(opt_idx.c_str()) + 1); + category = wxString::Format("%s %d", "Extruder", GUI::filament_index_from_zero_based(std::atoi(opt_idx.c_str()))); } return Option{boost::nowide::widen(get_key(opt_key, type)), diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index ce70205b3b..70251ef1e1 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4927,7 +4927,9 @@ if (is_marlin_flavor) // Orca: build missed extruder pages for (auto extruder_idx = m_extruders_count_old; extruder_idx < m_extruders_count; ++extruder_idx) { - const wxString& page_name = (m_extruders_count > 1) ? wxString::Format("Extruder %d", int(extruder_idx + 1)) : wxString::Format("Extruder"); + const wxString& page_name = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) + : wxString::Format("Extruder"); //# build page //const wxString& page_name = wxString::Format("Extruder %d", int(extruder_idx + 1)); @@ -5057,7 +5059,7 @@ if (is_marlin_flavor) if (m_extruders_count == 1) first_extruder_title = wxString::Format("Extruder"); } else if (m_extruders_count_old == 1) { - first_extruder_title = wxString::Format("Extruder %d", 1); + first_extruder_title = wxString::Format("Extruder %d", filament_index_from_zero_based(0)); } auto & searcher = wxGetApp().sidebar().get_searcher(); for (auto &group : m_pages[n_before_extruders]->m_optgroups) { diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 2fecf52bd2..bb54e563d1 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -548,13 +548,15 @@ std::vector get_extruder_color_icons(bool thin_icon/* = false*/) int index = 0; for (const auto &colors : readable_color_info) { - auto label = std::to_string(++index); - bool is_gradient = ctype[index-1] == "0"; + const int display_index = GUI::filament_index_from_zero_based(index); + auto label = std::to_string(display_index); + bool is_gradient = ctype[index] == "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)); } + ++index; } } else { std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); @@ -565,8 +567,10 @@ std::vector get_extruder_color_icons(bool thin_icon/* = false*/) const int icon_height = lround(2 * em); int index = 0; for (const auto &color : colors) { - auto label = std::to_string(++index); + const int display_index = GUI::filament_index_from_zero_based(index); + auto label = std::to_string(display_index); bmps.push_back(get_extruder_color_icon(color, label, icon_width, icon_height)); + ++index; } } return bmps; @@ -1361,5 +1365,3 @@ void ImageTransientPopup::OnMouse(wxMouseEvent &event) { event.Skip(); } - - From 169c00857e566fef85cf2f1fad0c271826197528 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 15:19:27 -0500 Subject: [PATCH 23/57] Fix filament index namespace in wxExtensions --- src/slic3r/GUI/GCodeViewer.cpp | 15 +++++++-------- src/slic3r/GUI/GLCanvas3D.cpp | 16 +++++++++------- src/slic3r/GUI/GUI_Factories.cpp | 14 +++++++++----- src/slic3r/GUI/GUI_ObjectTable.cpp | 3 ++- src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 9 +++++---- src/slic3r/GUI/ImGuiWrapper.cpp | 2 +- src/slic3r/GUI/ObjColorDialog.cpp | 6 ++++-- src/slic3r/GUI/Plater.cpp | 9 +++++---- src/slic3r/GUI/Search.cpp | 3 ++- src/slic3r/GUI/Tab.cpp | 6 ++++-- src/slic3r/GUI/wxExtensions.cpp | 12 +++++++----- 11 files changed, 55 insertions(+), 40 deletions(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 8032a24c07..fc58572138 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -345,11 +345,11 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode break; } case libvgcode::EViewType::Tool: { - sprintf(buf, "%s %s%d", buf, _u8L("Tool: ").c_str(), vertex.extruder_id + 1); + sprintf(buf, "%s %s%d", buf, _u8L("Tool: ").c_str(), filament_index_from_zero_based(static_cast(vertex.extruder_id))); break; } case libvgcode::EViewType::ColorPrint: { - sprintf(buf, "%s %s%d", buf, _u8L("Color: ").c_str(), vertex.color_id + 1); + sprintf(buf, "%s %s%d", buf, _u8L("Color: ").c_str(), filament_index_from_zero_based(static_cast(vertex.color_id))); break; } case libvgcode::EViewType::ActualVolumetricFlowRate: { @@ -2480,7 +2480,7 @@ void GCodeViewer::render_all_plates_stats(const std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(it->first + 1), offsets[_u8L("Filament")]}); + columns_offsets.push_back({ std::to_string(filament_index_from_zero_based(static_cast(it->first))), offsets[_u8L("Filament")]}); char buf[64]; double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1.0; @@ -3562,7 +3562,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv const std::vector& used_extruders_ids = m_viewer.get_used_extruders_ids(); for (uint8_t extruder_id : used_extruders_ids) { ::sprintf(buf, imperial_units ? "%.2f in %.2f g" : "%.2f m %.2f g", model_used_filaments_m[i], model_used_filaments_g[i]); - append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), { { _u8L("Extruder") + " " + std::to_string(extruder_id + 1), offsets[0]}, {buf, offsets[1]} }); + append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), { { _u8L("Extruder") + " " + std::to_string(filament_index_from_zero_based(extruder_id)), offsets[0]}, {buf, offsets[1]} }); // append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), _u8L("Extruder") + " " + std::to_string(extruder_id + 1), // true, "", 0.0f, 0.0f, offsets, used_filaments_m[extruder_id], used_filaments_g[extruder_id]); i++; @@ -3614,7 +3614,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv for (auto extruder_idx : used_extruders_ids) { if (i < model_used_filaments_m.size() && i < model_used_filaments_g.size()) { std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(extruder_idx + 1), color_print_offsets[_u8L("Filament")]}); + columns_offsets.push_back({ std::to_string(filament_index_from_zero_based(extruder_idx)), color_print_offsets[_u8L("Filament")]}); char buf[64]; float column_sum_m = 0.0f; @@ -3990,7 +3990,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ret = std::max(ret, ImGui::CalcTextSize((_u8L("Print settings") + std::string(":")).c_str()).x); if (!m_settings_ids.filament.empty()) { for (unsigned char i : m_viewer.get_used_extruders_ids()) { - ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(i + 1) + ":").c_str()).x); + ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(filament_index_from_zero_based(static_cast(i))) + ":").c_str()).x); } } if (ret > 0.0f) @@ -4017,7 +4017,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv for (unsigned char i : m_viewer.get_used_extruders_ids()) { if (i < static_cast(m_settings_ids.filament.size()) && !m_settings_ids.filament[i].empty()) { std::string txt = _u8L("Filament"); - txt += (m_viewer.get_used_extruders_count() == 1) ? ":" : " " + std::to_string(i + 1); + txt += (m_viewer.get_used_extruders_count() == 1) ? ":" : " " + std::to_string(filament_index_from_zero_based(static_cast(i))); imgui.text(txt); ImGui::SameLine(offset); imgui.text(m_settings_ids.filament[i]); @@ -4266,4 +4266,3 @@ void GCodeViewer::render_slider(int canvas_width, int canvas_height) { } // namespace GUI } // namespace Slic3r - diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index fe9b60ea93..26327ac04f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -9492,14 +9492,15 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_area_error_infos.begin()) { text += "\n"; } - int extruder_id = error_iter->first + 1; // change extruder id to 1 based + const int extruder_index = error_iter->first; + const int extruder_id = filament_index_from_zero_based(extruder_index); std::string filaments; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { if (i > 0) { filaments += ", "; } - int filament_id = error_iter->second[i].first + 1; // change filament id to 1 based + const int filament_id = filament_index_from_zero_based(error_iter->second[i].first); int object_label_id = error_iter->second[i].second; filaments += std::to_string(filament_id); @@ -9522,7 +9523,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) } } } - std::string extruder_name = extruder_name_list[extruder_id-1]; + std::string extruder_name = extruder_name_list[extruder_index]; if (error_iter->second.size() == 1) { text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable range of the %s.")) %filaments %extruder_name %extruder_name).str(); } @@ -9538,11 +9539,12 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_height_error_infos.begin()) { text += "\n"; } - int extruder_id = error_iter->first + 1; // change extruder id to 1 based + const int extruder_index = error_iter->first; + const int extruder_id = filament_index_from_zero_based(extruder_index); std::set filament_ids; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { - int filament_id = error_iter->second[i].first + 1; // change filament id to 1 based + int filament_id = filament_index_from_zero_based(error_iter->second[i].first); int object_label_id = error_iter->second[i].second; filament_ids.insert(filament_id); for (int object_idx = 0; object_idx < (int) m_model->objects.size(); ++object_idx) { @@ -9575,7 +9577,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) } } } - std::string extruder_name = extruder_name_list[extruder_id-1]; + std::string extruder_name = extruder_name_list[extruder_index]; if (error_iter->second.size() == 1) { text += (boost::format(_u8L("Filament %s is placed in the %s, but the generated G-code path exceeds the printable height of the %s.")) % filaments % extruder_name % extruder_name).str(); } else { @@ -9604,7 +9606,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) const std::vector &conflict_filament = m_gcode_viewer.filament_printable_reuslt.conflict_filament; auto iter = conflict_filament.begin(); for (int filament : conflict_filament) { - warning += std::to_string(filament + 1); + warning += std::to_string(filament_index_from_zero_based(filament)); warning += " "; } text = (boost::format(_u8L("filaments %s cannot be printed directly on the surface of this plate.")) % warning).str(); diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 79dd49901a..36b76133d5 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -924,11 +924,12 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) wxString item_name = _L("Default"); if (i > 0) { + const int display_index = filament_index_from_one_based(i); auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i - 1]); if (preset == nullptr) { - item_name = wxString::Format(_L("Filament %d"), filament_index_from_one_based(i)); + item_name = wxString::Format(_L("Filament %d"), display_index); } else { - item_name = from_u8(preset->label(false)); + item_name = wxString::Format("%d: %s", display_index, from_u8(preset->label(false))); } } @@ -1527,8 +1528,10 @@ void MenuFactory::create_filament_action_menu(bool init, int active_filament_men if (i == active_filament_menu_id) continue; + const int display_index = filament_index_from_zero_based(i); auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i]); - wxString item_name = preset ? from_u8(preset->label(false)) : wxString::Format(_L("Filament %d"), filament_index_from_zero_based(i)); + wxString item_name = preset ? wxString::Format("%d: %s", display_index, from_u8(preset->label(false))) + : wxString::Format(_L("Filament %d"), display_index); append_menu_item(sub_menu, wxID_ANY, item_name, "", [i](wxCommandEvent&) { plater()->sidebar().change_filament(-2, i); }, *icons[i], menu, @@ -2084,11 +2087,12 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu) wxString item_name = _L("Default"); if (i > 0) { + const int display_index = filament_index_from_one_based(i); auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i - 1]); if (preset == nullptr) { - item_name = wxString::Format(_L("Filament %d"), filament_index_from_one_based(i)); + item_name = wxString::Format(_L("Filament %d"), display_index); } else { - item_name = from_u8(preset->label(false)); + item_name = wxString::Format("%d: %s", display_index, from_u8(preset->label(false))); } } diff --git a/src/slic3r/GUI/GUI_ObjectTable.cpp b/src/slic3r/GUI/GUI_ObjectTable.cpp index 35df1f460e..450c38373f 100644 --- a/src/slic3r/GUI/GUI_ObjectTable.cpp +++ b/src/slic3r/GUI/GUI_ObjectTable.cpp @@ -2846,7 +2846,8 @@ int ObjectTablePanel::init_filaments_and_colors() } //parse the filaments - m_filaments_name[i] = wxString(std::to_string(i+1) + ": " + filament_presets[i]); + const int display_index = filament_index_from_zero_based(static_cast(i)); + m_filaments_name[i] = wxString(std::to_string(display_index) + ": " + filament_presets[i]); i++; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index af7ec15772..f0544d8b78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -192,7 +192,7 @@ void GLGizmoMmuSegmentation::data_changed(bool is_serializing) // BBS bool GLGizmoMmuSegmentation::on_number_key_down(int number) { - int extruder_idx = number - 1; + int extruder_idx = start_filament_index_at_0() ? number : number - 1; if (extruder_idx < m_extruders_colors.size() && extruder_idx >= 0) m_selected_extruder_idx = extruder_idx; @@ -403,7 +403,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott const ColorRGBA &extruder_color = m_extruders_colors[extruder_idx]; ImVec4 color_vec = ImGuiWrapper::to_ImVec4(extruder_color); std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx); - std::string item_text = std::to_string(extruder_idx + 1); + std::string item_text = std::to_string(filament_index_from_zero_based(extruder_idx)); const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f),0.f); @@ -435,7 +435,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott color_button_high = ImGui::GetCursorPos().y - color_button - 2.0; if (color_picked) { m_selected_extruder_idx = extruder_idx; } - if (extruder_idx < 16 && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width); + if (extruder_idx < 16 && ImGui::IsItemHovered()) + m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(filament_index_from_zero_based(extruder_idx)), max_tooltip_width); // draw filament id float gray = 0.299 * extruder_color.r() + 0.587 * extruder_color.g() + 0.114 * extruder_color.b(); @@ -1047,7 +1048,7 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float #endif // overlay destination number with proper contrast calculation - std::string dst_txt = std::to_string(m_extruder_remap[src] + 1); + std::string dst_txt = std::to_string(filament_index_from_zero_based(static_cast(m_extruder_remap[src]))); float gray = 0.299f * dst_col.r() + 0.587f * dst_col.g() + 0.114f * dst_col.b(); ImVec2 txt_sz = ImGui::CalcTextSize(dst_txt.c_str()); ImVec2 pos = ImGui::GetItemRectMin(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 8bd2904c49..a1920d4810 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -3274,7 +3274,7 @@ std::tuple ImGuiWrapper::calculate_filament_group_text_size(const void ImGuiWrapper::filament_group(const std::string& filament_type, const char* hex_color, unsigned char filament_id, float align_width) { //ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); - std::string id = std::to_string(static_cast (filament_id + 1)); + std::string id = std::to_string(filament_index_from_zero_based(static_cast(filament_id))); ImDrawList* draw_list = ImGui::GetWindowDrawList(); static ImTextureID transparent; ImVec2 text_size = ImGui::CalcTextSize(filament_type.c_str()); diff --git a/src/slic3r/GUI/ObjColorDialog.cpp b/src/slic3r/GUI/ObjColorDialog.cpp index 7575777507..f237c8c66f 100644 --- a/src/slic3r/GUI/ObjColorDialog.cpp +++ b/src/slic3r/GUI/ObjColorDialog.cpp @@ -409,7 +409,8 @@ ObjColorPanel::~ObjColorPanel() { void ObjColorPanel::msw_rescale() { for (unsigned int i = 0; i < m_extruder_icon_list.size(); ++i) { - auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(i + 1), FromDIP(16), FromDIP(16)); + const int display_index = filament_index_from_zero_based(static_cast(i)); + auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(display_index), FromDIP(16), FromDIP(16)); m_extruder_icon_list[i]->SetBitmap(bitmap); } /* for (unsigned int i = 0; i < m_color_cluster_icon_list.size(); ++i) { @@ -530,7 +531,8 @@ wxBoxSizer *ObjColorPanel::create_extruder_icon_and_rgba_sizer(wxWindow *parent, { auto icon_sizer = new wxBoxSizer(wxHORIZONTAL); wxButton *icon = new wxButton(parent, wxID_ANY, {}, wxDefaultPosition, ICON_SIZE, wxBORDER_NONE | wxBU_AUTODRAW); - icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(id + 1), FromDIP(16), FromDIP(16))); + const int display_index = filament_index_from_zero_based(id); + icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(display_index), FromDIP(16), FromDIP(16))); icon->SetCanFocus(false); m_extruder_icon_list.emplace_back(icon); icon_sizer->Add(icon, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 0); // wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5da3520660..21e8ba432f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -834,7 +834,7 @@ struct DynamicFilamentList1Based : DynamicFilamentList wxString get_value(int index) override { wxString str; - str << index+1; + str << filament_index_from_zero_based(index); return str; } int index_of(wxString value) override @@ -842,8 +842,9 @@ struct DynamicFilamentList1Based : DynamicFilamentList long n = 0; if(!value.ToLong(&n)) return -1; - --n; - return (n >= 0 && n <= items.size()) ? int(n) : -1; + if (!start_filament_index_at_0()) + --n; + return (n >= 0 && n <= static_cast(items.size())) ? int(n) : -1; } void update(bool force = false) { @@ -2277,7 +2278,7 @@ void Sidebar::init_filament_combo(PlaterPresetComboBox **combo, const int filame if ((filament_idx % 2) == 0) // Dont add right column item. this one create equal spacing on left, right & middle combo_and_btn_sizer->AddSpacer(FromDIP((filament_idx % 2) == 0 ? 12 : 3)); // Content Margin - (*combo)->clr_picker->SetLabel(wxString::Format("%d", filament_idx + 1)); + (*combo)->clr_picker->SetLabel(wxString::Format("%d", filament_index_from_zero_based(filament_idx))); combo_and_btn_sizer->Add((*combo)->clr_picker, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(SidebarProps::ElementSpacing()) - FromDIP(2)); // ElementSpacing - 2 (from combo box)) combo_and_btn_sizer->Add(*combo, 1, wxALL | wxEXPAND, FromDIP(2))->SetMinSize({-1, FromDIP(30)}); diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index 1aef329297..e70b861efe 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -13,6 +13,7 @@ #include "libslic3r/PrintConfig.hpp" #include "libslic3r/PresetBundle.hpp" +#include "GUI.hpp" #include "GUI_App.hpp" #include "Plater.hpp" #include "Tab.hpp" @@ -338,7 +339,7 @@ static Option create_option(const std::string &opt_key, const wxString &label, P wxString category = gc.category; if (type == Preset::TYPE_PRINTER && category.Contains("Extruder ")) { std::string opt_idx = opt_key.substr(opt_key.find("#") + 1); - category = wxString::Format("%s %d", "Extruder", atoi(opt_idx.c_str()) + 1); + category = wxString::Format("%s %d", "Extruder", GUI::filament_index_from_zero_based(std::atoi(opt_idx.c_str()))); } return Option{boost::nowide::widen(get_key(opt_key, type)), diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index ce70205b3b..70251ef1e1 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4927,7 +4927,9 @@ if (is_marlin_flavor) // Orca: build missed extruder pages for (auto extruder_idx = m_extruders_count_old; extruder_idx < m_extruders_count; ++extruder_idx) { - const wxString& page_name = (m_extruders_count > 1) ? wxString::Format("Extruder %d", int(extruder_idx + 1)) : wxString::Format("Extruder"); + const wxString& page_name = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) + : wxString::Format("Extruder"); //# build page //const wxString& page_name = wxString::Format("Extruder %d", int(extruder_idx + 1)); @@ -5057,7 +5059,7 @@ if (is_marlin_flavor) if (m_extruders_count == 1) first_extruder_title = wxString::Format("Extruder"); } else if (m_extruders_count_old == 1) { - first_extruder_title = wxString::Format("Extruder %d", 1); + first_extruder_title = wxString::Format("Extruder %d", filament_index_from_zero_based(0)); } auto & searcher = wxGetApp().sidebar().get_searcher(); for (auto &group : m_pages[n_before_extruders]->m_optgroups) { diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 2fecf52bd2..374c3f70a6 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -548,13 +548,15 @@ std::vector get_extruder_color_icons(bool thin_icon/* = false*/) int index = 0; for (const auto &colors : readable_color_info) { - auto label = std::to_string(++index); - bool is_gradient = ctype[index-1] == "0"; + const int display_index = Slic3r::GUI::filament_index_from_zero_based(index); + auto label = std::to_string(display_index); + bool is_gradient = ctype[index] == "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)); } + ++index; } } else { std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); @@ -565,8 +567,10 @@ std::vector get_extruder_color_icons(bool thin_icon/* = false*/) const int icon_height = lround(2 * em); int index = 0; for (const auto &color : colors) { - auto label = std::to_string(++index); + const int display_index = Slic3r::GUI::filament_index_from_zero_based(index); + auto label = std::to_string(display_index); bmps.push_back(get_extruder_color_icon(color, label, icon_width, icon_height)); + ++index; } } return bmps; @@ -1361,5 +1365,3 @@ void ImageTransientPopup::OnMouse(wxMouseEvent &event) { event.Skip(); } - - From e648f8ac412958db4d4aaf9382858cded9ef7ed4 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 21:31:14 -0500 Subject: [PATCH 24/57] Refresh printer tab filament index setting --- src/slic3r/GUI/Tab.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 70251ef1e1..4ad0741531 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1541,6 +1541,10 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) wxGetApp().sidebar().update_dynamic_filament_list(); wxGetApp().sidebar().update_all_preset_comboboxes(); wxGetApp().plater()->update(); + if (m_type == Preset::TYPE_PRINTER) { + if (auto* printer_tab = dynamic_cast(this)) + printer_tab->build_unregular_pages(); + } } if(opt_key == "purge_in_prime_tower") From 8cf0eef43c4bfb503fb87758fddd73c4cbc3d245 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 21:58:13 -0500 Subject: [PATCH 25/57] Refresh extruder page titles on index change --- src/slic3r/GUI/Tab.cpp | 30 +++++++++++++++++++++++------- src/slic3r/GUI/Tab.hpp | 1 + 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 70251ef1e1..7d8f3d3b39 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1541,6 +1541,10 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) wxGetApp().sidebar().update_dynamic_filament_list(); wxGetApp().sidebar().update_all_preset_comboboxes(); wxGetApp().plater()->update(); + if (m_type == Preset::TYPE_PRINTER) { + if (auto* printer_tab = dynamic_cast(this)) + printer_tab->build_unregular_pages(); + } } if(opt_key == "purge_in_prime_tower") @@ -5052,15 +5056,17 @@ if (is_marlin_flavor) } // BBS. No extra extruder page for single physical extruder machine // # remove extra pages - auto &first_extruder_title = const_cast(m_pages[n_before_extruders]->title()); if (m_extruders_count < m_extruders_count_old) { - m_pages.erase( m_pages.begin() + n_before_extruders + m_extruders_count, - m_pages.begin() + n_before_extruders + m_extruders_count_old); - if (m_extruders_count == 1) - first_extruder_title = wxString::Format("Extruder"); - } else if (m_extruders_count_old == 1) { - first_extruder_title = wxString::Format("Extruder %d", filament_index_from_zero_based(0)); + m_pages.erase(m_pages.begin() + n_before_extruders + m_extruders_count, + m_pages.begin() + n_before_extruders + m_extruders_count_old); } + for (size_t extruder_idx = 0; extruder_idx < m_extruders_count; ++extruder_idx) { + wxString page_title = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) + : wxString("Extruder"); + m_pages[n_before_extruders + extruder_idx]->set_title(page_title); + } + const wxString& first_extruder_title = m_pages[n_before_extruders]->title(); auto & searcher = wxGetApp().sidebar().get_searcher(); for (auto &group : m_pages[n_before_extruders]->m_optgroups) { group->set_config_category_and_type(first_extruder_title, m_type); @@ -7083,6 +7089,16 @@ void Page::reload_config() group->reload_config(); } +void Page::set_title(const wxString& title) +{ + if (m_title == title) + return; + + m_title = title; + if (m_page_title) + m_page_title->SetLabel(_(m_title)); +} + void Page::update_visibility(ConfigOptionMode mode, bool update_contolls_visibility) { bool ret_val = false; diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 96b35b26e1..4c70c1b142 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -86,6 +86,7 @@ public: wxBoxSizer* vsizer() const { return m_vsizer; } wxWindow* parent() const { return m_parent; } const wxString& title() const { return m_title; } + void set_title(const wxString& title); size_t iconID() const { return m_iconID; } void set_config(DynamicPrintConfig* config_in) { m_config = config_in; } void reload_config(); From 80505fbd9e1e3c64fe6b965d94aac10311d56185 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 22:25:58 -0500 Subject: [PATCH 26/57] Refresh printer extruder titles on index change --- src/slic3r/GUI/Tab.cpp | 69 +++++++++++++++++++++++++++++++++++++----- src/slic3r/GUI/Tab.hpp | 2 ++ 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 70251ef1e1..1071f49446 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1541,6 +1541,10 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) wxGetApp().sidebar().update_dynamic_filament_list(); wxGetApp().sidebar().update_all_preset_comboboxes(); wxGetApp().plater()->update(); + if (m_type == Preset::TYPE_PRINTER) { + if (auto* printer_tab = dynamic_cast(this)) + printer_tab->refresh_extruder_page_titles(boost::any_cast(value)); + } } if(opt_key == "purge_in_prime_tower") @@ -5052,15 +5056,17 @@ if (is_marlin_flavor) } // BBS. No extra extruder page for single physical extruder machine // # remove extra pages - auto &first_extruder_title = const_cast(m_pages[n_before_extruders]->title()); if (m_extruders_count < m_extruders_count_old) { - m_pages.erase( m_pages.begin() + n_before_extruders + m_extruders_count, - m_pages.begin() + n_before_extruders + m_extruders_count_old); - if (m_extruders_count == 1) - first_extruder_title = wxString::Format("Extruder"); - } else if (m_extruders_count_old == 1) { - first_extruder_title = wxString::Format("Extruder %d", filament_index_from_zero_based(0)); + m_pages.erase(m_pages.begin() + n_before_extruders + m_extruders_count, + m_pages.begin() + n_before_extruders + m_extruders_count_old); } + for (size_t extruder_idx = 0; extruder_idx < m_extruders_count; ++extruder_idx) { + wxString page_title = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) + : wxString("Extruder"); + m_pages[n_before_extruders + extruder_idx]->set_title(page_title); + } + const wxString& first_extruder_title = m_pages[n_before_extruders]->title(); auto & searcher = wxGetApp().sidebar().get_searcher(); for (auto &group : m_pages[n_before_extruders]->m_optgroups) { group->set_config_category_and_type(first_extruder_title, m_type); @@ -5084,6 +5090,45 @@ if (is_marlin_flavor) apply_searcher(); } +void TabPrinter::refresh_extruder_page_titles(bool start_at_zero) +{ + if (m_pages.empty() || m_extruders_count == 0) + return; + + size_t first_extruder_page = m_pages.size(); + for (size_t i = 0; i < m_pages.size(); ++i) { + const wxString& title = m_pages[i]->title(); + if (title == "Extruder" || title.StartsWith("Extruder ")) { + first_extruder_page = i; + break; + } + } + if (first_extruder_page >= m_pages.size()) + return; + + for (size_t extruder_idx = 0; extruder_idx < m_extruders_count; ++extruder_idx) { + const size_t page_index = first_extruder_page + extruder_idx; + if (page_index >= m_pages.size()) + break; + + wxString page_title = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", static_cast(extruder_idx) + (start_at_zero ? 0 : 1)) + : wxString("Extruder"); + m_pages[page_index]->set_title(page_title); + } + + const wxString& first_extruder_title = m_pages[first_extruder_page]->title(); + auto& searcher = wxGetApp().sidebar().get_searcher(); + for (auto& group : m_pages[first_extruder_page]->m_optgroups) { + group->set_config_category_and_type(first_extruder_title, m_type); + for (auto& opt : group->opt_map()) + searcher.add_key(opt.first + "#0", m_type, group->title, first_extruder_title); + } + + rebuild_page_tree(); + apply_searcher(); +} + // this gets executed after preset is loaded and before GUI fields are updated void TabPrinter::on_preset_loaded() { @@ -7083,6 +7128,16 @@ void Page::reload_config() group->reload_config(); } +void Page::set_title(const wxString& title) +{ + if (m_title == title) + return; + + m_title = title; + if (m_page_title) + m_page_title->SetLabel(_(m_title)); +} + void Page::update_visibility(ConfigOptionMode mode, bool update_contolls_visibility) { bool ret_val = false; diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 96b35b26e1..16cd7a25a5 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -86,6 +86,7 @@ public: wxBoxSizer* vsizer() const { return m_vsizer; } wxWindow* parent() const { return m_parent; } const wxString& title() const { return m_title; } + void set_title(const wxString& title); size_t iconID() const { return m_iconID; } void set_config(DynamicPrintConfig* config_in) { m_config = config_in; } void reload_config(); @@ -640,6 +641,7 @@ public: bool supports_printer_technology(const PrinterTechnology /* tech */) const override { return true; } void set_extruder_volume_type(int extruder_id, NozzleVolumeType type); + void refresh_extruder_page_titles(bool start_at_zero); wxSizer* create_bed_shape_widget(wxWindow* parent); void cache_extruder_cnt(const DynamicPrintConfig* config = nullptr); From 1dd21eba39aa013cd820977cdb6dcdba06cc4841 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 17:45:09 -1000 Subject: [PATCH 27/57] Remove index prefixes in change filament menu --- src/slic3r/GUI/GUI_Factories.cpp | 4 +- src/slic3r/GUI/Tab.cpp | 69 ++++++++++++++++++++++++++++---- src/slic3r/GUI/Tab.hpp | 2 + 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 36b76133d5..6e657b0549 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -929,7 +929,7 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) if (preset == nullptr) { item_name = wxString::Format(_L("Filament %d"), display_index); } else { - item_name = wxString::Format("%d: %s", display_index, from_u8(preset->label(false))); + item_name = from_u8(preset->label(false)); } } @@ -2092,7 +2092,7 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu) if (preset == nullptr) { item_name = wxString::Format(_L("Filament %d"), display_index); } else { - item_name = wxString::Format("%d: %s", display_index, from_u8(preset->label(false))); + item_name = from_u8(preset->label(false)); } } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 70251ef1e1..1071f49446 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1541,6 +1541,10 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) wxGetApp().sidebar().update_dynamic_filament_list(); wxGetApp().sidebar().update_all_preset_comboboxes(); wxGetApp().plater()->update(); + if (m_type == Preset::TYPE_PRINTER) { + if (auto* printer_tab = dynamic_cast(this)) + printer_tab->refresh_extruder_page_titles(boost::any_cast(value)); + } } if(opt_key == "purge_in_prime_tower") @@ -5052,15 +5056,17 @@ if (is_marlin_flavor) } // BBS. No extra extruder page for single physical extruder machine // # remove extra pages - auto &first_extruder_title = const_cast(m_pages[n_before_extruders]->title()); if (m_extruders_count < m_extruders_count_old) { - m_pages.erase( m_pages.begin() + n_before_extruders + m_extruders_count, - m_pages.begin() + n_before_extruders + m_extruders_count_old); - if (m_extruders_count == 1) - first_extruder_title = wxString::Format("Extruder"); - } else if (m_extruders_count_old == 1) { - first_extruder_title = wxString::Format("Extruder %d", filament_index_from_zero_based(0)); + m_pages.erase(m_pages.begin() + n_before_extruders + m_extruders_count, + m_pages.begin() + n_before_extruders + m_extruders_count_old); } + for (size_t extruder_idx = 0; extruder_idx < m_extruders_count; ++extruder_idx) { + wxString page_title = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) + : wxString("Extruder"); + m_pages[n_before_extruders + extruder_idx]->set_title(page_title); + } + const wxString& first_extruder_title = m_pages[n_before_extruders]->title(); auto & searcher = wxGetApp().sidebar().get_searcher(); for (auto &group : m_pages[n_before_extruders]->m_optgroups) { group->set_config_category_and_type(first_extruder_title, m_type); @@ -5084,6 +5090,45 @@ if (is_marlin_flavor) apply_searcher(); } +void TabPrinter::refresh_extruder_page_titles(bool start_at_zero) +{ + if (m_pages.empty() || m_extruders_count == 0) + return; + + size_t first_extruder_page = m_pages.size(); + for (size_t i = 0; i < m_pages.size(); ++i) { + const wxString& title = m_pages[i]->title(); + if (title == "Extruder" || title.StartsWith("Extruder ")) { + first_extruder_page = i; + break; + } + } + if (first_extruder_page >= m_pages.size()) + return; + + for (size_t extruder_idx = 0; extruder_idx < m_extruders_count; ++extruder_idx) { + const size_t page_index = first_extruder_page + extruder_idx; + if (page_index >= m_pages.size()) + break; + + wxString page_title = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", static_cast(extruder_idx) + (start_at_zero ? 0 : 1)) + : wxString("Extruder"); + m_pages[page_index]->set_title(page_title); + } + + const wxString& first_extruder_title = m_pages[first_extruder_page]->title(); + auto& searcher = wxGetApp().sidebar().get_searcher(); + for (auto& group : m_pages[first_extruder_page]->m_optgroups) { + group->set_config_category_and_type(first_extruder_title, m_type); + for (auto& opt : group->opt_map()) + searcher.add_key(opt.first + "#0", m_type, group->title, first_extruder_title); + } + + rebuild_page_tree(); + apply_searcher(); +} + // this gets executed after preset is loaded and before GUI fields are updated void TabPrinter::on_preset_loaded() { @@ -7083,6 +7128,16 @@ void Page::reload_config() group->reload_config(); } +void Page::set_title(const wxString& title) +{ + if (m_title == title) + return; + + m_title = title; + if (m_page_title) + m_page_title->SetLabel(_(m_title)); +} + void Page::update_visibility(ConfigOptionMode mode, bool update_contolls_visibility) { bool ret_val = false; diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 96b35b26e1..16cd7a25a5 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -86,6 +86,7 @@ public: wxBoxSizer* vsizer() const { return m_vsizer; } wxWindow* parent() const { return m_parent; } const wxString& title() const { return m_title; } + void set_title(const wxString& title); size_t iconID() const { return m_iconID; } void set_config(DynamicPrintConfig* config_in) { m_config = config_in; } void reload_config(); @@ -640,6 +641,7 @@ public: bool supports_printer_technology(const PrinterTechnology /* tech */) const override { return true; } void set_extruder_volume_type(int extruder_id, NozzleVolumeType type); + void refresh_extruder_page_titles(bool start_at_zero); wxSizer* create_bed_shape_widget(wxWindow* parent); void cache_extruder_cnt(const DynamicPrintConfig* config = nullptr); From 2fdd608381bd38ea8e3a38059d9a070c23263de7 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 18:03:27 -1000 Subject: [PATCH 28/57] Refresh object list filaments on index change --- src/slic3r/GUI/GUI_Factories.cpp | 4 +- src/slic3r/GUI/Tab.cpp | 70 ++++++++++++++++++++++++++++---- src/slic3r/GUI/Tab.hpp | 2 + 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 36b76133d5..6e657b0549 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -929,7 +929,7 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) if (preset == nullptr) { item_name = wxString::Format(_L("Filament %d"), display_index); } else { - item_name = wxString::Format("%d: %s", display_index, from_u8(preset->label(false))); + item_name = from_u8(preset->label(false)); } } @@ -2092,7 +2092,7 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu) if (preset == nullptr) { item_name = wxString::Format(_L("Filament %d"), display_index); } else { - item_name = wxString::Format("%d: %s", display_index, from_u8(preset->label(false))); + item_name = from_u8(preset->label(false)); } } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 70251ef1e1..a400b41af3 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1540,7 +1540,12 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) if (opt_key == "start_filament_index_at_0") { wxGetApp().sidebar().update_dynamic_filament_list(); wxGetApp().sidebar().update_all_preset_comboboxes(); + wxGetApp().obj_list()->update_objects_list_filament_column(wxGetApp().filaments_cnt()); wxGetApp().plater()->update(); + if (m_type == Preset::TYPE_PRINTER) { + if (auto* printer_tab = dynamic_cast(this)) + printer_tab->refresh_extruder_page_titles(boost::any_cast(value)); + } } if(opt_key == "purge_in_prime_tower") @@ -5052,15 +5057,17 @@ if (is_marlin_flavor) } // BBS. No extra extruder page for single physical extruder machine // # remove extra pages - auto &first_extruder_title = const_cast(m_pages[n_before_extruders]->title()); if (m_extruders_count < m_extruders_count_old) { - m_pages.erase( m_pages.begin() + n_before_extruders + m_extruders_count, - m_pages.begin() + n_before_extruders + m_extruders_count_old); - if (m_extruders_count == 1) - first_extruder_title = wxString::Format("Extruder"); - } else if (m_extruders_count_old == 1) { - first_extruder_title = wxString::Format("Extruder %d", filament_index_from_zero_based(0)); + m_pages.erase(m_pages.begin() + n_before_extruders + m_extruders_count, + m_pages.begin() + n_before_extruders + m_extruders_count_old); } + for (size_t extruder_idx = 0; extruder_idx < m_extruders_count; ++extruder_idx) { + wxString page_title = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) + : wxString("Extruder"); + m_pages[n_before_extruders + extruder_idx]->set_title(page_title); + } + const wxString& first_extruder_title = m_pages[n_before_extruders]->title(); auto & searcher = wxGetApp().sidebar().get_searcher(); for (auto &group : m_pages[n_before_extruders]->m_optgroups) { group->set_config_category_and_type(first_extruder_title, m_type); @@ -5084,6 +5091,45 @@ if (is_marlin_flavor) apply_searcher(); } +void TabPrinter::refresh_extruder_page_titles(bool start_at_zero) +{ + if (m_pages.empty() || m_extruders_count == 0) + return; + + size_t first_extruder_page = m_pages.size(); + for (size_t i = 0; i < m_pages.size(); ++i) { + const wxString& title = m_pages[i]->title(); + if (title == "Extruder" || title.StartsWith("Extruder ")) { + first_extruder_page = i; + break; + } + } + if (first_extruder_page >= m_pages.size()) + return; + + for (size_t extruder_idx = 0; extruder_idx < m_extruders_count; ++extruder_idx) { + const size_t page_index = first_extruder_page + extruder_idx; + if (page_index >= m_pages.size()) + break; + + wxString page_title = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", static_cast(extruder_idx) + (start_at_zero ? 0 : 1)) + : wxString("Extruder"); + m_pages[page_index]->set_title(page_title); + } + + const wxString& first_extruder_title = m_pages[first_extruder_page]->title(); + auto& searcher = wxGetApp().sidebar().get_searcher(); + for (auto& group : m_pages[first_extruder_page]->m_optgroups) { + group->set_config_category_and_type(first_extruder_title, m_type); + for (auto& opt : group->opt_map()) + searcher.add_key(opt.first + "#0", m_type, group->title, first_extruder_title); + } + + rebuild_page_tree(); + apply_searcher(); +} + // this gets executed after preset is loaded and before GUI fields are updated void TabPrinter::on_preset_loaded() { @@ -7083,6 +7129,16 @@ void Page::reload_config() group->reload_config(); } +void Page::set_title(const wxString& title) +{ + if (m_title == title) + return; + + m_title = title; + if (m_page_title) + m_page_title->SetLabel(_(m_title)); +} + void Page::update_visibility(ConfigOptionMode mode, bool update_contolls_visibility) { bool ret_val = false; diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 96b35b26e1..16cd7a25a5 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -86,6 +86,7 @@ public: wxBoxSizer* vsizer() const { return m_vsizer; } wxWindow* parent() const { return m_parent; } const wxString& title() const { return m_title; } + void set_title(const wxString& title); size_t iconID() const { return m_iconID; } void set_config(DynamicPrintConfig* config_in) { m_config = config_in; } void reload_config(); @@ -640,6 +641,7 @@ public: bool supports_printer_technology(const PrinterTechnology /* tech */) const override { return true; } void set_extruder_volume_type(int extruder_id, NozzleVolumeType type); + void refresh_extruder_page_titles(bool start_at_zero); wxSizer* create_bed_shape_widget(wxWindow* parent); void cache_extruder_cnt(const DynamicPrintConfig* config = nullptr); From 3cc7d05c7ad1d1854ff1be67029ef29f9e9df8ca Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 18:13:47 -1000 Subject: [PATCH 29/57] Fix object sidebar filament labels for zero-based indexing --- src/slic3r/GUI/GUI_Factories.cpp | 4 +- src/slic3r/GUI/GUI_ObjectList.cpp | 2 +- src/slic3r/GUI/ObjectDataViewModel.cpp | 11 ++-- src/slic3r/GUI/Tab.cpp | 70 +++++++++++++++++++++++--- src/slic3r/GUI/Tab.hpp | 2 + 5 files changed, 76 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 36b76133d5..6e657b0549 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -929,7 +929,7 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu) if (preset == nullptr) { item_name = wxString::Format(_L("Filament %d"), display_index); } else { - item_name = wxString::Format("%d: %s", display_index, from_u8(preset->label(false))); + item_name = from_u8(preset->label(false)); } } @@ -2092,7 +2092,7 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu) if (preset == nullptr) { item_name = wxString::Format(_L("Filament %d"), display_index); } else { - item_name = wxString::Format("%d: %s", display_index, from_u8(preset->label(false))); + item_name = from_u8(preset->label(false)); } } diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 4a25a07e23..06f1cad97d 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -81,7 +81,7 @@ static int filaments_count() static wxString format_filament_index_for_display(int extruder_id) { if (extruder_id <= 0) - return wxString::Format("%d", extruder_id); + return _L("default"); return wxString::Format("%d", filament_index_from_one_based(extruder_id)); } diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index c57a20118a..5423df6a53 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -48,7 +48,7 @@ static constexpr char LockIcon[] = "cut_"; static wxString format_filament_index_for_display(int extruder_id) { if (extruder_id <= 0) - return wxString::Format("%d", extruder_id); + return _L("default"); return wxString::Format("%d", filament_index_from_one_based(extruder_id)); } @@ -350,7 +350,8 @@ bool ObjectDataViewModelNode::SetValue(const wxVariant& variant, unsigned col) DataViewBitmapText data; data << variant; m_extruder_bmp = data.GetBitmap(); - m_extruder = data.GetText() == "0" ? _(L("default")) : data.GetText(); + const wxString text = data.GetText(); + m_extruder = (text == "0" && !start_filament_index_at_0()) ? _(L("default")) : text; return true; } // BBS case colSupportPaint: @@ -408,7 +409,11 @@ void ObjectDataViewModelNode::UpdateExtruderAndColorIcon(wxString extruder /*= " // update color icon size_t extruder_idx = atoi(extruder.c_str()); - if (extruder_idx == 0) { + const wxString default_label = _(L("default")); + if (start_filament_index_at_0() && extruder_idx == 0 && extruder != default_label) { + extruder_idx = 1; + } + if (extruder_idx == 0 && (!start_filament_index_at_0() || extruder == default_label)) { if (m_type & itObject); else if (m_type & itVolume && m_volume_type == ModelVolumeType::MODEL_PART) { extruder_idx = atoi(m_parent->GetExtruder().c_str()); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 70251ef1e1..a400b41af3 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1540,7 +1540,12 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) if (opt_key == "start_filament_index_at_0") { wxGetApp().sidebar().update_dynamic_filament_list(); wxGetApp().sidebar().update_all_preset_comboboxes(); + wxGetApp().obj_list()->update_objects_list_filament_column(wxGetApp().filaments_cnt()); wxGetApp().plater()->update(); + if (m_type == Preset::TYPE_PRINTER) { + if (auto* printer_tab = dynamic_cast(this)) + printer_tab->refresh_extruder_page_titles(boost::any_cast(value)); + } } if(opt_key == "purge_in_prime_tower") @@ -5052,15 +5057,17 @@ if (is_marlin_flavor) } // BBS. No extra extruder page for single physical extruder machine // # remove extra pages - auto &first_extruder_title = const_cast(m_pages[n_before_extruders]->title()); if (m_extruders_count < m_extruders_count_old) { - m_pages.erase( m_pages.begin() + n_before_extruders + m_extruders_count, - m_pages.begin() + n_before_extruders + m_extruders_count_old); - if (m_extruders_count == 1) - first_extruder_title = wxString::Format("Extruder"); - } else if (m_extruders_count_old == 1) { - first_extruder_title = wxString::Format("Extruder %d", filament_index_from_zero_based(0)); + m_pages.erase(m_pages.begin() + n_before_extruders + m_extruders_count, + m_pages.begin() + n_before_extruders + m_extruders_count_old); } + for (size_t extruder_idx = 0; extruder_idx < m_extruders_count; ++extruder_idx) { + wxString page_title = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) + : wxString("Extruder"); + m_pages[n_before_extruders + extruder_idx]->set_title(page_title); + } + const wxString& first_extruder_title = m_pages[n_before_extruders]->title(); auto & searcher = wxGetApp().sidebar().get_searcher(); for (auto &group : m_pages[n_before_extruders]->m_optgroups) { group->set_config_category_and_type(first_extruder_title, m_type); @@ -5084,6 +5091,45 @@ if (is_marlin_flavor) apply_searcher(); } +void TabPrinter::refresh_extruder_page_titles(bool start_at_zero) +{ + if (m_pages.empty() || m_extruders_count == 0) + return; + + size_t first_extruder_page = m_pages.size(); + for (size_t i = 0; i < m_pages.size(); ++i) { + const wxString& title = m_pages[i]->title(); + if (title == "Extruder" || title.StartsWith("Extruder ")) { + first_extruder_page = i; + break; + } + } + if (first_extruder_page >= m_pages.size()) + return; + + for (size_t extruder_idx = 0; extruder_idx < m_extruders_count; ++extruder_idx) { + const size_t page_index = first_extruder_page + extruder_idx; + if (page_index >= m_pages.size()) + break; + + wxString page_title = (m_extruders_count > 1) + ? wxString::Format("Extruder %d", static_cast(extruder_idx) + (start_at_zero ? 0 : 1)) + : wxString("Extruder"); + m_pages[page_index]->set_title(page_title); + } + + const wxString& first_extruder_title = m_pages[first_extruder_page]->title(); + auto& searcher = wxGetApp().sidebar().get_searcher(); + for (auto& group : m_pages[first_extruder_page]->m_optgroups) { + group->set_config_category_and_type(first_extruder_title, m_type); + for (auto& opt : group->opt_map()) + searcher.add_key(opt.first + "#0", m_type, group->title, first_extruder_title); + } + + rebuild_page_tree(); + apply_searcher(); +} + // this gets executed after preset is loaded and before GUI fields are updated void TabPrinter::on_preset_loaded() { @@ -7083,6 +7129,16 @@ void Page::reload_config() group->reload_config(); } +void Page::set_title(const wxString& title) +{ + if (m_title == title) + return; + + m_title = title; + if (m_page_title) + m_page_title->SetLabel(_(m_title)); +} + void Page::update_visibility(ConfigOptionMode mode, bool update_contolls_visibility) { bool ret_val = false; diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 96b35b26e1..16cd7a25a5 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -86,6 +86,7 @@ public: wxBoxSizer* vsizer() const { return m_vsizer; } wxWindow* parent() const { return m_parent; } const wxString& title() const { return m_title; } + void set_title(const wxString& title); size_t iconID() const { return m_iconID; } void set_config(DynamicPrintConfig* config_in) { m_config = config_in; } void reload_config(); @@ -640,6 +641,7 @@ public: bool supports_printer_technology(const PrinterTechnology /* tech */) const override { return true; } void set_extruder_volume_type(int extruder_id, NozzleVolumeType type); + void refresh_extruder_page_titles(bool start_at_zero); wxSizer* create_bed_shape_widget(wxWindow* parent); void cache_extruder_cnt(const DynamicPrintConfig* config = nullptr); From 43a676f7070f8b2f9837a28566bc2c29c252bc32 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 18:18:19 -1000 Subject: [PATCH 30/57] Revert "Fix object sidebar filament labels for zero-based indexing" --- src/slic3r/GUI/GUI_ObjectList.cpp | 2 +- src/slic3r/GUI/ObjectDataViewModel.cpp | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 06f1cad97d..4a25a07e23 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -81,7 +81,7 @@ static int filaments_count() static wxString format_filament_index_for_display(int extruder_id) { if (extruder_id <= 0) - return _L("default"); + return wxString::Format("%d", extruder_id); return wxString::Format("%d", filament_index_from_one_based(extruder_id)); } diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index 5423df6a53..c57a20118a 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -48,7 +48,7 @@ static constexpr char LockIcon[] = "cut_"; static wxString format_filament_index_for_display(int extruder_id) { if (extruder_id <= 0) - return _L("default"); + return wxString::Format("%d", extruder_id); return wxString::Format("%d", filament_index_from_one_based(extruder_id)); } @@ -350,8 +350,7 @@ bool ObjectDataViewModelNode::SetValue(const wxVariant& variant, unsigned col) DataViewBitmapText data; data << variant; m_extruder_bmp = data.GetBitmap(); - const wxString text = data.GetText(); - m_extruder = (text == "0" && !start_filament_index_at_0()) ? _(L("default")) : text; + m_extruder = data.GetText() == "0" ? _(L("default")) : data.GetText(); return true; } // BBS case colSupportPaint: @@ -409,11 +408,7 @@ void ObjectDataViewModelNode::UpdateExtruderAndColorIcon(wxString extruder /*= " // update color icon size_t extruder_idx = atoi(extruder.c_str()); - const wxString default_label = _(L("default")); - if (start_filament_index_at_0() && extruder_idx == 0 && extruder != default_label) { - extruder_idx = 1; - } - if (extruder_idx == 0 && (!start_filament_index_at_0() || extruder == default_label)) { + if (extruder_idx == 0) { if (m_type & itObject); else if (m_type & itVolume && m_volume_type == ModelVolumeType::MODEL_PART) { extruder_idx = atoi(m_parent->GetExtruder().c_str()); From e652235ddfeba405e702128536432558f639ce47 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 18:28:44 -1000 Subject: [PATCH 31/57] Fix filament indices in object list --- src/slic3r/GUI/GUI_ObjectList.cpp | 2 +- src/slic3r/GUI/ObjectDataViewModel.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 4a25a07e23..406a41dcd2 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -83,7 +83,7 @@ static wxString format_filament_index_for_display(int extruder_id) if (extruder_id <= 0) return wxString::Format("%d", extruder_id); - return wxString::Format("%d", filament_index_from_one_based(extruder_id)); + return wxString::Format("%d", filament_index_from_zero_based(extruder_id)); } static void take_snapshot(const std::string& snapshot_name) diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index c57a20118a..4c11eef20e 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -50,7 +50,7 @@ static wxString format_filament_index_for_display(int extruder_id) if (extruder_id <= 0) return wxString::Format("%d", extruder_id); - return wxString::Format("%d", filament_index_from_one_based(extruder_id)); + return wxString::Format("%d", filament_index_from_zero_based(extruder_id)); } ObjectDataViewModelNode::ObjectDataViewModelNode(PartPlate* part_plate, wxString name) : @@ -1764,7 +1764,10 @@ int ObjectDataViewModel::GetExtruderNumber(const wxDataViewItem& item) const return 0; if (start_filament_index_at_0()) - return static_cast(value) + 1; + return static_cast(value); + + if (value > 0) + return static_cast(value) - 1; return static_cast(value); } From dac2b92bd9212703dfe7890cb2fdc1bf36e77778 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 18:38:56 -1000 Subject: [PATCH 32/57] Fix filament display mapping --- src/slic3r/GUI/GUI_ObjectList.cpp | 2 +- src/slic3r/GUI/ObjectDataViewModel.cpp | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 4a25a07e23..31f04b9cb6 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -83,7 +83,7 @@ static wxString format_filament_index_for_display(int extruder_id) if (extruder_id <= 0) return wxString::Format("%d", extruder_id); - return wxString::Format("%d", filament_index_from_one_based(extruder_id)); + return wxString::Format("%d", extruder_id); } static void take_snapshot(const std::string& snapshot_name) diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index c57a20118a..5670e02528 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -50,7 +50,7 @@ static wxString format_filament_index_for_display(int extruder_id) if (extruder_id <= 0) return wxString::Format("%d", extruder_id); - return wxString::Format("%d", filament_index_from_one_based(extruder_id)); + return wxString::Format("%d", extruder_id); } ObjectDataViewModelNode::ObjectDataViewModelNode(PartPlate* part_plate, wxString name) : @@ -1763,9 +1763,6 @@ int ObjectDataViewModel::GetExtruderNumber(const wxDataViewItem& item) const if (end == extruder.c_str() || *end != '\0') return 0; - if (start_filament_index_at_0()) - return static_cast(value) + 1; - return static_cast(value); } From 05a6a5ed23485d4c2561108fa273c6b1bf3d39ce Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Fri, 16 Jan 2026 19:18:52 -1000 Subject: [PATCH 33/57] Rename zero-based filament indexing setting --- src/libslic3r/Preset.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 6 +++--- src/libslic3r/PrintConfig.hpp | 2 +- src/slic3r/GUI/GUI.cpp | 8 ++++---- src/slic3r/GUI/GUI.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 2 +- src/slic3r/GUI/Tab.cpp | 4 ++-- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 8a73bb63d0..a3a876d0f5 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1024,7 +1024,7 @@ static std::vector s_Preset_printer_options { "use_relative_e_distances", "extruder_type", "use_firmware_retraction", "printer_notes", "grab_length", "support_object_skip_flush", "physical_extruder_map", "cooling_tube_retraction", - "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "start_filament_index_at_0", + "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "zero_based_filament_indexing", "purge_in_prime_tower", "enable_filament_ramming", "z_offset", "disable_m73", "preferred_orientation", "emit_machine_limits_to_gcode", "pellet_modded_printer", "support_multi_bed_types", "default_bed_type", "bed_mesh_min","bed_mesh_max","bed_mesh_probe_distance", "adaptive_bed_mesh_margin", "enable_long_retraction_when_cut","long_retractions_when_cut","retraction_distances_when_cut", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 9cb88347ab..c5c49fcfa6 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4428,9 +4428,9 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(-2.)); - def = this->add("start_filament_index_at_0", coBool); - def->label = L("Start filament index at 0"); - def->tooltip = L("When enabled, filament/extruder indices in OrcaSlicer's interface are treated as 0-based (0..N-1) instead of 1-based (1..N)."); + def = this->add("zero_based_filament_indexing", coBool); + def->label = L("0-based_filament_indexing"); + def->tooltip = L("When enabled, 0-based filament indexing is used in OrcaSlicer's interface (0..N-1 instead of 1..N)."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(true)); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 65be24be1c..312fff87a1 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1385,7 +1385,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, purge_in_prime_tower)) ((ConfigOptionBool, enable_filament_ramming)) ((ConfigOptionBool, support_multi_bed_types)) - ((ConfigOptionBool, start_filament_index_at_0)) + ((ConfigOptionBool, zero_based_filament_indexing)) // Small Area Infill Flow Compensation diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 1bc0bae262..b27801b5d3 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -102,25 +102,25 @@ const std::string& shortkey_alt_prefix() return str; } -bool start_filament_index_at_0() +bool zero_based_filament_indexing() { const auto* preset_bundle = wxGetApp().preset_bundle; if (!preset_bundle) return false; const auto& config = preset_bundle->printers.get_edited_preset().config; - const auto* opt = config.option("start_filament_index_at_0"); + const auto* opt = config.option("zero_based_filament_indexing"); return opt != nullptr && opt->value; } int filament_index_from_zero_based(int index) { - return index + (start_filament_index_at_0() ? 0 : 1); + return index + (zero_based_filament_indexing() ? 0 : 1); } int filament_index_from_one_based(int index) { - return start_filament_index_at_0() ? index - 1 : index; + return zero_based_filament_indexing() ? index - 1 : index; } // opt_index = 0, by the reason of zero-index in ConfigOptionVector by default (in case only one element) diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp index e242519018..b27e3ca9b6 100644 --- a/src/slic3r/GUI/GUI.hpp +++ b/src/slic3r/GUI/GUI.hpp @@ -32,7 +32,7 @@ void break_to_debugger(); extern const std::string& shortkey_ctrl_prefix(); extern const std::string& shortkey_alt_prefix(); -bool start_filament_index_at_0(); +bool zero_based_filament_indexing(); int filament_index_from_zero_based(int index); int filament_index_from_one_based(int index); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index f0544d8b78..347d4a9a35 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -192,7 +192,7 @@ void GLGizmoMmuSegmentation::data_changed(bool is_serializing) // BBS bool GLGizmoMmuSegmentation::on_number_key_down(int number) { - int extruder_idx = start_filament_index_at_0() ? number : number - 1; + int extruder_idx = zero_based_filament_indexing() ? number : number - 1; if (extruder_idx < m_extruders_colors.size() && extruder_idx >= 0) m_selected_extruder_idx = extruder_idx; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 21e8ba432f..cb681cf8ea 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -842,7 +842,7 @@ struct DynamicFilamentList1Based : DynamicFilamentList long n = 0; if(!value.ToLong(&n)) return -1; - if (!start_filament_index_at_0()) + if (!zero_based_filament_indexing()) --n; return (n >= 0 && n <= static_cast(items.size())) ? int(n) : -1; } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index a400b41af3..249a9a12b0 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1537,7 +1537,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) wxGetApp().get_tab(Preset::TYPE_PRINT)->update(); } - if (opt_key == "start_filament_index_at_0") { + if (opt_key == "zero_based_filament_indexing") { wxGetApp().sidebar().update_dynamic_filament_list(); wxGetApp().sidebar().update_all_preset_comboboxes(); wxGetApp().obj_list()->update_objects_list_filament_column(wxGetApp().filaments_cnt()); @@ -4926,7 +4926,7 @@ if (is_marlin_flavor) optgroup->append_single_option_line("machine_load_filament_time", "printer_multimaterial_advanced#filament-load-time"); optgroup->append_single_option_line("machine_unload_filament_time", "printer_multimaterial_advanced#filament-unload-time"); optgroup->append_single_option_line("machine_tool_change_time", "printer_multimaterial_advanced#tool-change-time"); - optgroup->append_single_option_line("start_filament_index_at_0", "printer_multimaterial_advanced#start-filament-index-at-0"); + optgroup->append_single_option_line("zero_based_filament_indexing", "printer_multimaterial_advanced#zero-based-filament-indexing"); m_pages.insert(m_pages.end() - n_after_single_extruder_MM, page); } From ef05caddbfe2745532c6cacc06b1c3a3b3d91ac6 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Sat, 17 Jan 2026 01:21:42 -0500 Subject: [PATCH 34/57] Delete CMakeSettings.json --- CMakeSettings.json | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 CMakeSettings.json diff --git a/CMakeSettings.json b/CMakeSettings.json deleted file mode 100644 index 122c8186c3..0000000000 --- a/CMakeSettings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "configurations": [ - { - "name": "x64-Debug", - "generator": "Ninja", - "configurationType": "Debug", - "inheritEnvironments": [ "msvc_x64_x64" ], - "buildRoot": "${projectDir}\\out\\build\\${name}", - "installRoot": "${projectDir}\\out\\install\\${name}", - "cmakeCommandArgs": "", - "buildCommandArgs": "", - "ctestCommandArgs": "" - } - ] -} \ No newline at end of file From 01961ed9794e7b2a1722b0d338cace34735d0686 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard Date: Sat, 17 Jan 2026 00:48:29 -1000 Subject: [PATCH 35/57] Update PrintConfig.cpp --- src/libslic3r/PrintConfig.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index c5c49fcfa6..3e9a9cf2cf 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4428,11 +4428,11 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(-2.)); - def = this->add("zero_based_filament_indexing", coBool); - def->label = L("0-based_filament_indexing"); + def = this->add("zero_based_filament_indexing", coBool); + def->label = L("0-based filament indexing"); def->tooltip = L("When enabled, 0-based filament indexing is used in OrcaSlicer's interface (0..N-1 instead of 1..N)."); - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBool(true)); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); def = this->add("start_end_points", coPoints); def->label = L("Start end points"); From 5b9d23277e35b310791188f1dc48bb65648e0a15 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard Date: Sat, 17 Jan 2026 01:22:57 -1000 Subject: [PATCH 36/57] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5b369a47fe..a2cbc50a39 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ Build Build.bat /build*/ CMakeLists.txt.user +CMakeSettings.json **/CMakeLists.txt.autosave deps/build* MYMETA.json From dbf956037992457953edd3580341d6001398481f Mon Sep 17 00:00:00 2001 From: JonasBouchard Date: Sat, 17 Jan 2026 01:54:52 -0500 Subject: [PATCH 37/57] minor changes --- src/libslic3r/PrintConfig.hpp | 1 - src/slic3r/GUI/GCodeViewer.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 312fff87a1..e747678e1c 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1387,7 +1387,6 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, support_multi_bed_types)) ((ConfigOptionBool, zero_based_filament_indexing)) - // Small Area Infill Flow Compensation ((ConfigOptionStrings, small_area_infill_flow_compensation_model)) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index fc58572138..b74aca5e38 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -4266,3 +4266,4 @@ void GCodeViewer::render_slider(int canvas_width, int canvas_height) { } // namespace GUI } // namespace Slic3r + From 8258efbc6cd314373a1d959771067c9af8159c0b Mon Sep 17 00:00:00 2001 From: JonasBouchard Date: Sat, 17 Jan 2026 02:09:45 -0500 Subject: [PATCH 38/57] minor changes --- src/slic3r/GUI/GLCanvas3D.cpp | 3 +-- src/slic3r/GUI/GUI_Factories.cpp | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 26327ac04f..d78b9925f4 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -9492,8 +9492,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_area_error_infos.begin()) { text += "\n"; } - const int extruder_index = error_iter->first; - const int extruder_id = filament_index_from_zero_based(extruder_index); + int extruder_id = filament_index_from_zero_based(error_iter->first); std::string filaments; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 6e657b0549..4ece1d0da5 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -1530,8 +1530,7 @@ void MenuFactory::create_filament_action_menu(bool init, int active_filament_men const int display_index = filament_index_from_zero_based(i); auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i]); - wxString item_name = preset ? wxString::Format("%d: %s", display_index, from_u8(preset->label(false))) - : wxString::Format(_L("Filament %d"), display_index); + wxString item_name = preset ? wxString::Format("%d: %s", display_index, from_u8(preset->label(false))) : wxString::Format(_L("Filament %d"), display_index); append_menu_item(sub_menu, wxID_ANY, item_name, "", [i](wxCommandEvent&) { plater()->sidebar().change_filament(-2, i); }, *icons[i], menu, From df40715fc92d53389a9488c61314cd04845efb33 Mon Sep 17 00:00:00 2001 From: JonasBouchard Date: Sat, 17 Jan 2026 02:23:12 -0500 Subject: [PATCH 39/57] minor changes --- src/slic3r/GUI/ObjectDataViewModel.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index 5670e02528..0084532165 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -1758,8 +1758,8 @@ int ObjectDataViewModel::GetExtruderNumber(const wxDataViewItem& item) const return 0; const std::string extruder = node->m_extruder.ToStdString(); - char* end = nullptr; - const long value = std::strtol(extruder.c_str(), &end, 10); + char* end = nullptr; + const long value = std::strtol(extruder.c_str(), &end, 10); if (end == extruder.c_str() || *end != '\0') return 0; @@ -2509,3 +2509,5 @@ void ObjectDataViewModel::UpdateCutObjectIcon(const wxDataViewItem &item, bool h } // namespace GUI } // namespace Slic3r + + From ec19eb7c4e363446f82d261db739a060100a107b Mon Sep 17 00:00:00 2001 From: JonasBouchard Date: Sat, 17 Jan 2026 02:42:30 -0500 Subject: [PATCH 40/57] minor changes --- src/slic3r/GUI/Tab.cpp | 13 ++++--------- src/slic3r/GUI/wxExtensions.cpp | 12 +++++++----- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 249a9a12b0..59717b2623 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4922,6 +4922,7 @@ if (is_marlin_flavor) optgroup->append_single_option_line("parking_pos_retraction", "printer_multimaterial_semm_parameters#filament-parking-position"); optgroup->append_single_option_line("extra_loading_move", "printer_multimaterial_semm_parameters#extra-loading-distance"); optgroup->append_single_option_line("high_current_on_filament_swap", "printer_multimaterial_semm_parameters#high-extruder-current-on-filament-swap"); + optgroup = page->new_optgroup(L("Advanced"), L"param_advanced"); optgroup->append_single_option_line("machine_load_filament_time", "printer_multimaterial_advanced#filament-load-time"); optgroup->append_single_option_line("machine_unload_filament_time", "printer_multimaterial_advanced#filament-unload-time"); @@ -4932,9 +4933,7 @@ if (is_marlin_flavor) // Orca: build missed extruder pages for (auto extruder_idx = m_extruders_count_old; extruder_idx < m_extruders_count; ++extruder_idx) { - const wxString& page_name = (m_extruders_count > 1) - ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) - : wxString::Format("Extruder"); + const wxString& page_name = (m_extruders_count > 1) ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) : wxString::Format("Extruder"); //# build page //const wxString& page_name = wxString::Format("Extruder %d", int(extruder_idx + 1)); @@ -5062,9 +5061,7 @@ if (is_marlin_flavor) m_pages.begin() + n_before_extruders + m_extruders_count_old); } for (size_t extruder_idx = 0; extruder_idx < m_extruders_count; ++extruder_idx) { - wxString page_title = (m_extruders_count > 1) - ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) - : wxString("Extruder"); + wxString page_title = (m_extruders_count > 1) ? wxString::Format("Extruder %d", filament_index_from_zero_based(static_cast(extruder_idx))) : wxString("Extruder"); m_pages[n_before_extruders + extruder_idx]->set_title(page_title); } const wxString& first_extruder_title = m_pages[n_before_extruders]->title(); @@ -5112,9 +5109,7 @@ void TabPrinter::refresh_extruder_page_titles(bool start_at_zero) if (page_index >= m_pages.size()) break; - wxString page_title = (m_extruders_count > 1) - ? wxString::Format("Extruder %d", static_cast(extruder_idx) + (start_at_zero ? 0 : 1)) - : wxString("Extruder"); + wxString page_title = (m_extruders_count > 1) ? wxString::Format("Extruder %d", static_cast(extruder_idx) + (start_at_zero ? 0 : 1)) : wxString("Extruder"); m_pages[page_index]->set_title(page_title); } diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 374c3f70a6..3af2db9470 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -549,7 +549,7 @@ std::vector get_extruder_color_icons(bool thin_icon/* = false*/) int index = 0; for (const auto &colors : readable_color_info) { const int display_index = Slic3r::GUI::filament_index_from_zero_based(index); - auto label = std::to_string(display_index); + auto label = std::to_string(display_index); bool is_gradient = ctype[index] == "0"; if (colors.size() == 1) { bmps.push_back(get_extruder_color_icon(colors[0], label, icon_width, icon_height)); @@ -568,7 +568,7 @@ std::vector get_extruder_color_icons(bool thin_icon/* = false*/) int index = 0; for (const auto &color : colors) { const int display_index = Slic3r::GUI::filament_index_from_zero_based(index); - auto label = std::to_string(display_index); + auto label = std::to_string(display_index); bmps.push_back(get_extruder_color_icon(color, label, icon_width, icon_height)); ++index; } @@ -795,9 +795,7 @@ void apply_extruder_selector(Slic3r::GUI::BitmapComboBox** ctrl, } const int display_index = Slic3r::GUI::filament_index_from_one_based(i); - (*ctrl)->Append(use_full_item_name - ? Slic3r::GUI::from_u8((boost::format("%1% %2%") % str % display_index).str()) - : wxString::Format("%d", display_index), *bmp); + (*ctrl)->Append(use_full_item_name ? Slic3r::GUI::from_u8((boost::format("%1% %2%") % str % display_index).str()) : wxString::Format("%d", display_index), *bmp); ++i; } (*ctrl)->SetSelection(0); @@ -1365,3 +1363,7 @@ void ImageTransientPopup::OnMouse(wxMouseEvent &event) { event.Skip(); } + + + + From 1df244ae9b0c61d5c937e9bb6d73bd2d4f88baaa Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Sat, 17 Jan 2026 02:50:55 -0500 Subject: [PATCH 41/57] Fix extruder index lookup for error text --- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d78b9925f4..85e693b8f2 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -9492,7 +9492,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_area_error_infos.begin()) { text += "\n"; } - int extruder_id = filament_index_from_zero_based(error_iter->first); + const int extruder_index = error_iter->first; std::string filaments; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { From 336f41e8da2253067194aa876d72b227d05547f9 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Sat, 17 Jan 2026 02:57:19 -0500 Subject: [PATCH 42/57] Fix filament index bounds check --- src/slic3r/GUI/Plater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index cb681cf8ea..6143ff2504 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -844,7 +844,7 @@ struct DynamicFilamentList1Based : DynamicFilamentList return -1; if (!zero_based_filament_indexing()) --n; - return (n >= 0 && n <= static_cast(items.size())) ? int(n) : -1; + return (n >= 0 && n < static_cast(items.size())) ? int(n) : -1; } void update(bool force = false) { From 2614808c6fcbce8e17ae248ae84fd763ddcdc062 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Sat, 17 Jan 2026 03:53:52 -0500 Subject: [PATCH 43/57] Align plater color shortcuts with filament numbers --- src/slic3r/GUI/GLCanvas3D.cpp | 37 ++++++++++++----------------------- src/slic3r/GUI/GLCanvas3D.hpp | 2 -- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 85e693b8f2..facd2996c5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1209,7 +1209,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) m_retina_helper.reset(new RetinaHelper(canvas)); #endif // ENABLE_RETINA_GL } - m_timer_set_color.Bind(wxEVT_TIMER, &GLCanvas3D::on_set_color_timer, this); load_arrange_settings(); m_selection.set_volumes(&m_volumes.volumes); @@ -1219,8 +1218,12 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) // FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent? m_assembly_view_desc["part_selection_caption"] = _L("Alt+") + _L("Left mouse button"); m_assembly_view_desc["part_selection"] = _L("part selection"); - m_assembly_view_desc["number_key_caption"] = "1~16 " + _L("number keys"); - m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects"); + m_assembly_view_desc["number_key_caption"] = "0-9 " + _L("number keys"); + if (GUI::zero_based_filament_indexing()) { + m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects (0 selects filament 0)"); + } else { + m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects (0 selects filament 10)"); + } } GLCanvas3D::~GLCanvas3D() @@ -3397,14 +3400,8 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) break; } - // BBS: use keypad to change extruder - case '1': { - if (!m_timer_set_color.IsRunning()) { - m_timer_set_color.StartOnce(500); - break; - } - } - case '0': //Color logic for material 10 + case '0': + case '1': case '2': case '3': case '4': @@ -3413,12 +3410,11 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case '7': case '8': case '9': { - if (m_timer_set_color.IsRunning()) { - if (keyCode < '7') keyCode += 10; - m_timer_set_color.Stop(); + if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) { + const bool zero_based = GUI::zero_based_filament_indexing(); + const int extruder_id = zero_based ? (keyCode - '0') : (keyCode == '0' ? 10 : keyCode - '0'); + obj_list->set_extruder_for_selected_items(extruder_id); } - if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) - obj_list->set_extruder_for_selected_items(keyCode - '0'); break; } @@ -3956,15 +3952,6 @@ void GLCanvas3D::on_render_timer(wxTimerEvent& evt) // wxWakeUpIdle(); } -void GLCanvas3D::on_set_color_timer(wxTimerEvent& evt) -{ - auto obj_list = wxGetApp().obj_list(); - if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) - obj_list->set_extruder_for_selected_items(1); - m_timer_set_color.Stop(); -} - - void GLCanvas3D::schedule_extra_frame(int miliseconds) { // Schedule idle event right now diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 17a388c731..76bd13f222 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -528,7 +528,6 @@ private: unsigned int m_last_w, m_last_h; bool m_in_render; wxTimer m_timer; - wxTimer m_timer_set_color; LayersEditing m_layers_editing; Mouse m_mouse; GLGizmosManager m_gizmos; @@ -1027,7 +1026,6 @@ public: void on_mouse_wheel(wxMouseEvent& evt); void on_timer(wxTimerEvent& evt); void on_render_timer(wxTimerEvent& evt); - void on_set_color_timer(wxTimerEvent& evt); void on_mouse(wxMouseEvent& evt); void on_gesture(wxGestureEvent& evt); void on_paint(wxPaintEvent& evt); From ff017187b8171f84221579026a786e701d661d30 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Sat, 17 Jan 2026 04:15:13 -0500 Subject: [PATCH 44/57] Align plater color shortcuts with filament numbers --- src/slic3r/GUI/GLCanvas3D.cpp | 36 +++++++++++++++++++++++------------ src/slic3r/GUI/GLCanvas3D.hpp | 2 +- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 85e693b8f2..b93f34c35d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1219,8 +1219,12 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) // FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent? m_assembly_view_desc["part_selection_caption"] = _L("Alt+") + _L("Left mouse button"); m_assembly_view_desc["part_selection"] = _L("part selection"); - m_assembly_view_desc["number_key_caption"] = "1~16 " + _L("number keys"); - m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects"); + m_assembly_view_desc["number_key_caption"] = "0-16 " + _L("number keys"); + if (GUI::zero_based_filament_indexing()) { + m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects (0 selects filament 0)"); + } else { + m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects (0 selects filament 10)"); + } } GLCanvas3D::~GLCanvas3D() @@ -3397,14 +3401,13 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) break; } - // BBS: use keypad to change extruder case '1': { if (!m_timer_set_color.IsRunning()) { m_timer_set_color.StartOnce(500); break; } } - case '0': //Color logic for material 10 + case '0': case '2': case '3': case '4': @@ -3413,12 +3416,19 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case '7': case '8': case '9': { - if (m_timer_set_color.IsRunning()) { - if (keyCode < '7') keyCode += 10; - m_timer_set_color.Stop(); + if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) { + int display_index = keyCode - '0'; + if (m_timer_set_color.IsRunning()) { + if (keyCode < '7') + display_index += 10; + m_timer_set_color.Stop(); + } else if (!GUI::zero_based_filament_indexing() && keyCode == '0') { + display_index = 10; + } + + const int extruder_id = GUI::zero_based_filament_indexing() ? display_index + 1 : display_index; + obj_list->set_extruder_for_selected_items(extruder_id); } - if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) - obj_list->set_extruder_for_selected_items(keyCode - '0'); break; } @@ -3959,12 +3969,14 @@ void GLCanvas3D::on_render_timer(wxTimerEvent& evt) void GLCanvas3D::on_set_color_timer(wxTimerEvent& evt) { auto obj_list = wxGetApp().obj_list(); - if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) - obj_list->set_extruder_for_selected_items(1); + if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) { + const int display_index = 1; + const int extruder_id = GUI::zero_based_filament_indexing() ? display_index + 1 : display_index; + obj_list->set_extruder_for_selected_items(extruder_id); + } m_timer_set_color.Stop(); } - void GLCanvas3D::schedule_extra_frame(int miliseconds) { // Schedule idle event right now diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 17a388c731..12ba2babfe 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -1026,8 +1026,8 @@ public: void on_key(wxKeyEvent& evt); void on_mouse_wheel(wxMouseEvent& evt); void on_timer(wxTimerEvent& evt); - void on_render_timer(wxTimerEvent& evt); void on_set_color_timer(wxTimerEvent& evt); + void on_render_timer(wxTimerEvent& evt); void on_mouse(wxMouseEvent& evt); void on_gesture(wxGestureEvent& evt); void on_paint(wxPaintEvent& evt); From 12207daadae7b04242a464beb98b188124fc4e11 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Sat, 17 Jan 2026 04:28:51 -0500 Subject: [PATCH 45/57] Restore blank line in render timer --- src/slic3r/GUI/GLCanvas3D.cpp | 38 +++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 85e693b8f2..dda02937fe 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1219,8 +1219,12 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) // FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent? m_assembly_view_desc["part_selection_caption"] = _L("Alt+") + _L("Left mouse button"); m_assembly_view_desc["part_selection"] = _L("part selection"); - m_assembly_view_desc["number_key_caption"] = "1~16 " + _L("number keys"); - m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects"); + m_assembly_view_desc["number_key_caption"] = "0-16 " + _L("number keys"); + if (GUI::zero_based_filament_indexing()) { + m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects (0 selects filament 0)"); + } else { + m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects (0 selects filament 10)"); + } } GLCanvas3D::~GLCanvas3D() @@ -3397,14 +3401,13 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) break; } - // BBS: use keypad to change extruder case '1': { if (!m_timer_set_color.IsRunning()) { m_timer_set_color.StartOnce(500); break; } } - case '0': //Color logic for material 10 + case '0': case '2': case '3': case '4': @@ -3413,12 +3416,19 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case '7': case '8': case '9': { - if (m_timer_set_color.IsRunning()) { - if (keyCode < '7') keyCode += 10; - m_timer_set_color.Stop(); + if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) { + int display_index = keyCode - '0'; + if (m_timer_set_color.IsRunning()) { + if (keyCode < '7') + display_index += 10; + m_timer_set_color.Stop(); + } else if (!GUI::zero_based_filament_indexing() && keyCode == '0') { + display_index = 10; + } + + const int extruder_id = GUI::zero_based_filament_indexing() ? display_index + 1 : display_index; + obj_list->set_extruder_for_selected_items(extruder_id); } - if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) - obj_list->set_extruder_for_selected_items(keyCode - '0'); break; } @@ -3953,18 +3963,20 @@ void GLCanvas3D::on_render_timer(wxTimerEvent& evt) // no need to wake up idle // right after this event, idle event is fired // m_dirty = true; - // wxWakeUpIdle(); + } void GLCanvas3D::on_set_color_timer(wxTimerEvent& evt) { auto obj_list = wxGetApp().obj_list(); - if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) - obj_list->set_extruder_for_selected_items(1); + if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) { + const int display_index = 1; + const int extruder_id = GUI::zero_based_filament_indexing() ? display_index + 1 : display_index; + obj_list->set_extruder_for_selected_items(extruder_id); + } m_timer_set_color.Stop(); } - void GLCanvas3D::schedule_extra_frame(int miliseconds) { // Schedule idle event right now From 1684b31233c8ab5ae0e34350cbb736cc8156f97d Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Sat, 17 Jan 2026 04:42:34 -0500 Subject: [PATCH 46/57] Set owner for color timer --- src/slic3r/GUI/GLCanvas3D.cpp | 39 +++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 85e693b8f2..3d5071e31e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1205,6 +1205,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) if (m_canvas != nullptr) { m_timer.SetOwner(m_canvas); m_render_timer.SetOwner(m_canvas); + m_timer_set_color.SetOwner(m_canvas); #if ENABLE_RETINA_GL m_retina_helper.reset(new RetinaHelper(canvas)); #endif // ENABLE_RETINA_GL @@ -1219,8 +1220,12 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) // FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent? m_assembly_view_desc["part_selection_caption"] = _L("Alt+") + _L("Left mouse button"); m_assembly_view_desc["part_selection"] = _L("part selection"); - m_assembly_view_desc["number_key_caption"] = "1~16 " + _L("number keys"); - m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects"); + m_assembly_view_desc["number_key_caption"] = "0-16 " + _L("number keys"); + if (GUI::zero_based_filament_indexing()) { + m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects (0 selects filament 0)"); + } else { + m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects (0 selects filament 10)"); + } } GLCanvas3D::~GLCanvas3D() @@ -3397,14 +3402,13 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) break; } - // BBS: use keypad to change extruder case '1': { if (!m_timer_set_color.IsRunning()) { m_timer_set_color.StartOnce(500); break; } } - case '0': //Color logic for material 10 + case '0': case '2': case '3': case '4': @@ -3413,12 +3417,19 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case '7': case '8': case '9': { - if (m_timer_set_color.IsRunning()) { - if (keyCode < '7') keyCode += 10; - m_timer_set_color.Stop(); + if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) { + int display_index = keyCode - '0'; + if (m_timer_set_color.IsRunning()) { + if (keyCode < '7') + display_index += 10; + m_timer_set_color.Stop(); + } else if (!GUI::zero_based_filament_indexing() && keyCode == '0') { + display_index = 10; + } + + const int extruder_id = GUI::zero_based_filament_indexing() ? display_index + 1 : display_index; + obj_list->set_extruder_for_selected_items(extruder_id); } - if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) - obj_list->set_extruder_for_selected_items(keyCode - '0'); break; } @@ -3953,18 +3964,20 @@ void GLCanvas3D::on_render_timer(wxTimerEvent& evt) // no need to wake up idle // right after this event, idle event is fired // m_dirty = true; - // wxWakeUpIdle(); + } void GLCanvas3D::on_set_color_timer(wxTimerEvent& evt) { auto obj_list = wxGetApp().obj_list(); - if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) - obj_list->set_extruder_for_selected_items(1); + if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) { + const int display_index = 1; + const int extruder_id = GUI::zero_based_filament_indexing() ? display_index + 1 : display_index; + obj_list->set_extruder_for_selected_items(extruder_id); + } m_timer_set_color.Stop(); } - void GLCanvas3D::schedule_extra_frame(int miliseconds) { // Schedule idle event right now From 84b257329833d3bab7344d17524df05c0406a765 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Sat, 17 Jan 2026 06:11:01 -1000 Subject: [PATCH 47/57] Revert "Set owner for color-change timer and finalize number-key extruder indexing" --- src/slic3r/GUI/GLCanvas3D.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 29ca994fce..5acf69065f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1205,7 +1205,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) if (m_canvas != nullptr) { m_timer.SetOwner(m_canvas); m_render_timer.SetOwner(m_canvas); - m_timer_set_color.SetOwner(m_canvas); #if ENABLE_RETINA_GL m_retina_helper.reset(new RetinaHelper(canvas)); #endif // ENABLE_RETINA_GL From 33b85050424861c1d62cf85874da7072f28931c5 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Sat, 17 Jan 2026 06:20:17 -1000 Subject: [PATCH 48/57] Revert "Restore blank line in render timer and support zero-based filament indexing for number keys" --- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 5acf69065f..7018e5a35e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3962,7 +3962,7 @@ void GLCanvas3D::on_render_timer(wxTimerEvent& evt) // no need to wake up idle // right after this event, idle event is fired // m_dirty = true; - + // wxWakeUpIdle(); } void GLCanvas3D::on_set_color_timer(wxTimerEvent& evt) From 0bcfa1732870260f007a615adfd394484b4d5919 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Sat, 17 Jan 2026 06:21:19 -1000 Subject: [PATCH 49/57] Revert "Align plater color shortcuts with filament numbers" --- src/slic3r/GUI/GLCanvas3D.cpp | 32 ++++---------------------------- src/slic3r/GUI/GLCanvas3D.hpp | 1 - 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 7018e5a35e..facd2996c5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1218,7 +1218,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) // FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent? m_assembly_view_desc["part_selection_caption"] = _L("Alt+") + _L("Left mouse button"); m_assembly_view_desc["part_selection"] = _L("part selection"); - m_assembly_view_desc["number_key_caption"] = "0-16 " + _L("number keys"); + m_assembly_view_desc["number_key_caption"] = "0-9 " + _L("number keys"); if (GUI::zero_based_filament_indexing()) { m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects (0 selects filament 0)"); } else { @@ -3400,13 +3400,8 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) break; } - case '1': { - if (!m_timer_set_color.IsRunning()) { - m_timer_set_color.StartOnce(500); - break; - } - } case '0': + case '1': case '2': case '3': case '4': @@ -3416,16 +3411,8 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case '8': case '9': { if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) { - int display_index = keyCode - '0'; - if (m_timer_set_color.IsRunning()) { - if (keyCode < '7') - display_index += 10; - m_timer_set_color.Stop(); - } else if (!GUI::zero_based_filament_indexing() && keyCode == '0') { - display_index = 10; - } - - const int extruder_id = GUI::zero_based_filament_indexing() ? display_index + 1 : display_index; + const bool zero_based = GUI::zero_based_filament_indexing(); + const int extruder_id = zero_based ? (keyCode - '0') : (keyCode == '0' ? 10 : keyCode - '0'); obj_list->set_extruder_for_selected_items(extruder_id); } break; @@ -3965,17 +3952,6 @@ void GLCanvas3D::on_render_timer(wxTimerEvent& evt) // wxWakeUpIdle(); } -void GLCanvas3D::on_set_color_timer(wxTimerEvent& evt) -{ - auto obj_list = wxGetApp().obj_list(); - if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) { - const int display_index = 1; - const int extruder_id = GUI::zero_based_filament_indexing() ? display_index + 1 : display_index; - obj_list->set_extruder_for_selected_items(extruder_id); - } - m_timer_set_color.Stop(); -} - void GLCanvas3D::schedule_extra_frame(int miliseconds) { // Schedule idle event right now diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index dcfbcc40c8..76bd13f222 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -1025,7 +1025,6 @@ public: void on_key(wxKeyEvent& evt); void on_mouse_wheel(wxMouseEvent& evt); void on_timer(wxTimerEvent& evt); - void on_set_color_timer(wxTimerEvent& evt); void on_render_timer(wxTimerEvent& evt); void on_mouse(wxMouseEvent& evt); void on_gesture(wxGestureEvent& evt); From 5b60e38cf72727d43e529ee1b4fc2712c8f09851 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard <118275319+JonasBouchard@users.noreply.github.com> Date: Sat, 17 Jan 2026 06:37:16 -1000 Subject: [PATCH 51/57] Revert "Respect zero-based filament indexing for plater number-key shortcuts" --- src/slic3r/GUI/GLCanvas3D.cpp | 37 +++++++++++++++++++++++------------ src/slic3r/GUI/GLCanvas3D.hpp | 2 ++ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index facd2996c5..85e693b8f2 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1209,6 +1209,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) m_retina_helper.reset(new RetinaHelper(canvas)); #endif // ENABLE_RETINA_GL } + m_timer_set_color.Bind(wxEVT_TIMER, &GLCanvas3D::on_set_color_timer, this); load_arrange_settings(); m_selection.set_volumes(&m_volumes.volumes); @@ -1218,12 +1219,8 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) // FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent? m_assembly_view_desc["part_selection_caption"] = _L("Alt+") + _L("Left mouse button"); m_assembly_view_desc["part_selection"] = _L("part selection"); - m_assembly_view_desc["number_key_caption"] = "0-9 " + _L("number keys"); - if (GUI::zero_based_filament_indexing()) { - m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects (0 selects filament 0)"); - } else { - m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects (0 selects filament 10)"); - } + m_assembly_view_desc["number_key_caption"] = "1~16 " + _L("number keys"); + m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects"); } GLCanvas3D::~GLCanvas3D() @@ -3400,8 +3397,14 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) break; } - case '0': - case '1': + // BBS: use keypad to change extruder + case '1': { + if (!m_timer_set_color.IsRunning()) { + m_timer_set_color.StartOnce(500); + break; + } + } + case '0': //Color logic for material 10 case '2': case '3': case '4': @@ -3410,11 +3413,12 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case '7': case '8': case '9': { - if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) { - const bool zero_based = GUI::zero_based_filament_indexing(); - const int extruder_id = zero_based ? (keyCode - '0') : (keyCode == '0' ? 10 : keyCode - '0'); - obj_list->set_extruder_for_selected_items(extruder_id); + if (m_timer_set_color.IsRunning()) { + if (keyCode < '7') keyCode += 10; + m_timer_set_color.Stop(); } + if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) + obj_list->set_extruder_for_selected_items(keyCode - '0'); break; } @@ -3952,6 +3956,15 @@ void GLCanvas3D::on_render_timer(wxTimerEvent& evt) // wxWakeUpIdle(); } +void GLCanvas3D::on_set_color_timer(wxTimerEvent& evt) +{ + auto obj_list = wxGetApp().obj_list(); + if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) + obj_list->set_extruder_for_selected_items(1); + m_timer_set_color.Stop(); +} + + void GLCanvas3D::schedule_extra_frame(int miliseconds) { // Schedule idle event right now diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 76bd13f222..17a388c731 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -528,6 +528,7 @@ private: unsigned int m_last_w, m_last_h; bool m_in_render; wxTimer m_timer; + wxTimer m_timer_set_color; LayersEditing m_layers_editing; Mouse m_mouse; GLGizmosManager m_gizmos; @@ -1026,6 +1027,7 @@ public: void on_mouse_wheel(wxMouseEvent& evt); void on_timer(wxTimerEvent& evt); void on_render_timer(wxTimerEvent& evt); + void on_set_color_timer(wxTimerEvent& evt); void on_mouse(wxMouseEvent& evt); void on_gesture(wxGestureEvent& evt); void on_paint(wxPaintEvent& evt); From 4d6396749591e16c344e248730270b87b6571a15 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard Date: Sun, 18 Jan 2026 02:01:02 -1000 Subject: [PATCH 52/57] remove useless includes --- src/slic3r/GUI/GUI_Factories.cpp | 1 - src/slic3r/GUI/GUI_ObjectList.cpp | 1 - src/slic3r/GUI/ObjectDataViewModel.cpp | 1 - src/slic3r/GUI/Search.cpp | 1 - 4 files changed, 4 deletions(-) diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 4ece1d0da5..1ed7228cc9 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -6,7 +6,6 @@ #include "GUI_Factories.hpp" #include "GUI_ObjectList.hpp" #include "GUI_App.hpp" -#include "GUI.hpp" #include "I18N.hpp" #include "Plater.hpp" #include "ObjectDataViewModel.hpp" diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 603bc7253d..29f092c2ad 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -4,7 +4,6 @@ #include "GUI_Factories.hpp" //#include "GUI_ObjectLayers.hpp" #include "GUI_App.hpp" -#include "GUI.hpp" #include "I18N.hpp" #include "Plater.hpp" #include "BitmapComboBox.hpp" diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index 0084532165..8229a1fc80 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -10,7 +10,6 @@ #include "libslic3r/Model.hpp" -#include #include #include diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index e70b861efe..9f1b885a53 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -13,7 +13,6 @@ #include "libslic3r/PrintConfig.hpp" #include "libslic3r/PresetBundle.hpp" -#include "GUI.hpp" #include "GUI_App.hpp" #include "Plater.hpp" #include "Tab.hpp" From 6ad4f4037b336d9070bc592319edc1a7b0bf73a0 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard Date: Sun, 18 Jan 2026 02:17:15 -1000 Subject: [PATCH 53/57] minor changes --- src/libslic3r/Preset.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index a3a876d0f5..f7fb652298 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1024,8 +1024,7 @@ static std::vector s_Preset_printer_options { "use_relative_e_distances", "extruder_type", "use_firmware_retraction", "printer_notes", "grab_length", "support_object_skip_flush", "physical_extruder_map", "cooling_tube_retraction", - "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "zero_based_filament_indexing", - "purge_in_prime_tower", "enable_filament_ramming", + "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "zero_based_filament_indexing", "purge_in_prime_tower", "enable_filament_ramming", "z_offset", "disable_m73", "preferred_orientation", "emit_machine_limits_to_gcode", "pellet_modded_printer", "support_multi_bed_types", "default_bed_type", "bed_mesh_min","bed_mesh_max","bed_mesh_probe_distance", "adaptive_bed_mesh_margin", "enable_long_retraction_when_cut","long_retractions_when_cut","retraction_distances_when_cut", "bed_temperature_formula", "nozzle_flush_dataset" From 2a0115341feb1c0833e2e5bfad1c2eb74bea51b6 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard Date: Sun, 18 Jan 2026 02:18:46 -1000 Subject: [PATCH 54/57] reset .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index a2cbc50a39..5b369a47fe 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ Build Build.bat /build*/ CMakeLists.txt.user -CMakeSettings.json **/CMakeLists.txt.autosave deps/build* MYMETA.json From 993ee6c423b673a4672b67b7ff4cd4258d7f7a29 Mon Sep 17 00:00:00 2001 From: Jonas Bouchard Date: Sun, 18 Jan 2026 02:20:40 -1000 Subject: [PATCH 55/57] remove useless indentation --- src/slic3r/GUI/Tab.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 59717b2623..280f6592b3 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4922,7 +4922,7 @@ if (is_marlin_flavor) optgroup->append_single_option_line("parking_pos_retraction", "printer_multimaterial_semm_parameters#filament-parking-position"); optgroup->append_single_option_line("extra_loading_move", "printer_multimaterial_semm_parameters#extra-loading-distance"); optgroup->append_single_option_line("high_current_on_filament_swap", "printer_multimaterial_semm_parameters#high-extruder-current-on-filament-swap"); - + optgroup = page->new_optgroup(L("Advanced"), L"param_advanced"); optgroup->append_single_option_line("machine_load_filament_time", "printer_multimaterial_advanced#filament-load-time"); optgroup->append_single_option_line("machine_unload_filament_time", "printer_multimaterial_advanced#filament-unload-time"); From ded28b63b59a20e1fc3f26e1bf4c894b8d4a924b Mon Sep 17 00:00:00 2001 From: Jonas Bouchard Date: Sun, 18 Jan 2026 02:30:04 -1000 Subject: [PATCH 56/57] src/libslic3r/Preset.cpp --- src/libslic3r/Preset.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index f7fb652298..e176ee588e 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1014,7 +1014,7 @@ static std::vector s_Preset_printer_options { "nozzle_height", "master_extruder_id", "default_print_profile", "inherits", "silent_mode", - "scan_first_layer", "enable_power_loss_recovery", "wrapping_detection_layers", "wrapping_exclude_area", "machine_load_filament_time", "machine_unload_filament_time", "machine_tool_change_time", "time_cost", "machine_pause_gcode", "template_custom_gcode", + "scan_first_layer", "enable_power_loss_recovery", "wrapping_detection_layers", "wrapping_exclude_area", "machine_load_filament_time", "machine_unload_filament_time", "machine_tool_change_time", "zero_based_filament_indexing", "time_cost", "machine_pause_gcode", "template_custom_gcode", "nozzle_type", "nozzle_hrc","auxiliary_fan", "nozzle_volume","upward_compatible_machine", "z_hop_types", "travel_slope", "retract_lift_enforce","support_chamber_temp_control","support_air_filtration","printer_structure", "best_object_pos", "head_wrap_detect_zone", "host_type", "print_host", "printhost_apikey", "bbl_use_printhost", @@ -1024,7 +1024,7 @@ static std::vector s_Preset_printer_options { "use_relative_e_distances", "extruder_type", "use_firmware_retraction", "printer_notes", "grab_length", "support_object_skip_flush", "physical_extruder_map", "cooling_tube_retraction", - "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "zero_based_filament_indexing", "purge_in_prime_tower", "enable_filament_ramming", + "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "purge_in_prime_tower", "enable_filament_ramming", "z_offset", "disable_m73", "preferred_orientation", "emit_machine_limits_to_gcode", "pellet_modded_printer", "support_multi_bed_types", "default_bed_type", "bed_mesh_min","bed_mesh_max","bed_mesh_probe_distance", "adaptive_bed_mesh_margin", "enable_long_retraction_when_cut","long_retractions_when_cut","retraction_distances_when_cut", "bed_temperature_formula", "nozzle_flush_dataset" From 608f4b74b55c6024dd9086d086d28e02ec0bfcbb Mon Sep 17 00:00:00 2001 From: Jonas Bouchard Date: Sun, 18 Jan 2026 02:49:40 -1000 Subject: [PATCH 57/57] remove useless const --- src/slic3r/GUI/GLCanvas3D.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 85e693b8f2..de2381cb3a 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -9492,14 +9492,14 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_area_error_infos.begin()) { text += "\n"; } - const int extruder_index = error_iter->first; + int extruder_index = error_iter->first; std::string filaments; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { if (i > 0) { filaments += ", "; } - const int filament_id = filament_index_from_zero_based(error_iter->second[i].first); + int filament_id = filament_index_from_zero_based(error_iter->second[i].first); int object_label_id = error_iter->second[i].second; filaments += std::to_string(filament_id); @@ -9538,8 +9538,8 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) if (error_iter != m_gcode_viewer.m_gcode_check_result.print_height_error_infos.begin()) { text += "\n"; } - const int extruder_index = error_iter->first; - const int extruder_id = filament_index_from_zero_based(extruder_index); + int extruder_index = error_iter->first; + int extruder_id = filament_index_from_zero_based(extruder_index); std::set filament_ids; std::vector slice_error_object_idxs; for (size_t i = 0; i < error_iter->second.size(); ++i) { @@ -9602,7 +9602,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) break; case EWarning::FilamentUnPrintableOnFirstLayer: { std::string warning; - const std::vector &conflict_filament = m_gcode_viewer.filament_printable_reuslt.conflict_filament; + std::vector &conflict_filament = m_gcode_viewer.filament_printable_reuslt.conflict_filament; auto iter = conflict_filament.begin(); for (int filament : conflict_filament) { warning += std::to_string(filament_index_from_zero_based(filament));