From 59c7809ee1719cf35194adc21679d3a5ca5057ee Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 18 May 2026 14:09:24 +0800 Subject: [PATCH] Make sure settings tab are still marked as modified even if modified variant is not currently selected --- src/libslic3r/PrintConfig.hpp | 11 + src/slic3r/GUI/Tab.cpp | 362 +++++++++++++++++++++--- src/slic3r/GUI/Tab.hpp | 18 +- src/slic3r/GUI/Widgets/SwitchButton.cpp | 330 ++++++++++----------- src/slic3r/GUI/Widgets/SwitchButton.hpp | 109 +++---- 5 files changed, 572 insertions(+), 258 deletions(-) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index cdde293cfa..f9e224449b 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -430,6 +430,17 @@ enum FilamentMapMode { extern std::string get_extruder_variant_string(ExtruderType extruder_type, NozzleVolumeType nozzle_volume_type); +static std::set get_valid_nozzle_volume_type() { + std::set type; + for (int i = 0; i <= nvtMaxNozzleVolumeType; ++i) { + auto t = static_cast(i); + // TODO: Orca: Support hybrid + //if (t == nvtHybrid) continue; + type.insert(t); + } + return type; +} + std::string get_nozzle_volume_type_string(NozzleVolumeType nozzle_volume_type); static std::string bed_type_to_gcode_string(const BedType type) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index b16280f8f5..a2d342ec75 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -88,6 +88,15 @@ static void validate_custom_gcode_cb(Tab* tab, const wxString& title, const t_co static const std::vector plate_keys = { "curr_bed_type", "skirt_start_angle", "first_layer_print_sequence", "first_layer_sequence_choice", "other_layers_print_sequence", "other_layers_sequence_choice", "print_sequence", "spiral_mode"}; +static std::pair extruder_variant_keys[]{ + {}, // invalid + {"print_extruder_id", "print_extruder_variant"}, // Preset::TYPE_PRINT + {}, // invalid + {"", "filament_extruder_variant"}, // Preset::TYPE_FILAMENT filament don't use id anymore + {}, // invalid + {"printer_extruder_id", "printer_extruder_variant"}, // Preset::TYPE_PRINTER +}; + void Tab::Highlighter::set_timer_owner(wxEvtHandler* owner, int timerid/* = wxID_ANY*/) { m_timer.SetOwner(owner, timerid); @@ -487,12 +496,21 @@ void Tab::create_preset_tab() m_main_sizer->Add(m_tabctrl, 0, wxEXPAND | wxALL, 0 ); if (dynamic_cast(this) || dynamic_cast(this)) { - m_extruder_switch = new SwitchButton(panel); + m_extruder_switch = new MultiSwitchButton(panel); m_extruder_switch->SetMaxSize({em_unit(this) * 24, -1}); - m_extruder_switch->SetLabels(_L("Left"), _L("Right")); - m_extruder_switch->Bind(wxEVT_TOGGLEBUTTON, [this] (auto & evt) { + m_extruder_switch->Bind(wxCUSTOMEVT_MULTISWITCH_SELECTION, [this](auto &evt) { evt.Skip(); - switch_excluder(evt.GetInt()); + int selection = evt.GetInt(); + + int extruder_id; + NozzleVolumeType nozzle_type; + parse_extruder_selection(selection, extruder_id, nozzle_type); + int extruder_count = m_preset_bundle->get_printer_extruder_count(); + m_actual_nozzle_volumes.resize(extruder_count, NozzleVolumeType::nvtStandard); + if (extruder_id >= 0 && extruder_id < m_preset_bundle->get_printer_extruder_count()) + m_actual_nozzle_volumes[extruder_id] = nozzle_type; + + switch_excluder(extruder_id); reload_config(); update_changed_ui(); }); @@ -557,6 +575,79 @@ void Tab::create_preset_tab() m_completed = true; } +void Tab::parse_extruder_selection(int selection, int &extruder_id, NozzleVolumeType &nozzle_type) +{ + auto nozzle_volumes = m_preset_bundle->project_config.option("nozzle_volume_type"); + int extruder_nums = m_preset_bundle->get_printer_extruder_count(); + + int current_index = 0; + + for (int i = 0; i < extruder_nums; ++i) { + NozzleVolumeType volume_type = NozzleVolumeType(nozzle_volumes->values[i]); + + // TODO: Orca: Support hybrid + //if (volume_type == NozzleVolumeType::nvtHybrid) { + // if (selection == current_index) { + // extruder_id = i; + // nozzle_type = NozzleVolumeType::nvtStandard; + // return; + // } else if (selection == current_index + 1) { + // extruder_id = i; + // nozzle_type = NozzleVolumeType::nvtHighFlow; + // return; + // } + // current_index += 2; + //} else { + if (selection == current_index) { + extruder_id = i; + nozzle_type = volume_type; + return; + } + current_index += 1; + //} + } + + extruder_id = 0; + nozzle_type = NozzleVolumeType::nvtStandard; +} + +int Tab::calculate_selection_index_for_extruder(int extruder_id, NozzleVolumeType nozzle_type) +{ + auto nozzle_volumes = m_preset_bundle->project_config.option("nozzle_volume_type"); + int extruder_nums = m_preset_bundle->get_printer_extruder_count(); + + int index = 0; + + for (int i = 0; i < extruder_nums; ++i) { + if (i == extruder_id) { + // TODO: Orca: Support hybrid + NozzleVolumeType volume_type = NozzleVolumeType(nozzle_volumes->values[i]); + /*if (volume_type == NozzleVolumeType::nvtHybrid) { + return nozzle_type == NozzleVolumeType::nvtHighFlow ? index + 1 : index; + } else*/ { + return index; + } + } + + NozzleVolumeType volume_type = NozzleVolumeType(nozzle_volumes->values[i]); + index += /*(volume_type == NozzleVolumeType::nvtHybrid) ? 2 :*/ 1; + } + + return 0; +} + +int Tab::get_current_active_extruder() +{ + if (m_extruder_switch && m_extruder_switch->IsThisEnabled()) { + int selection = m_extruder_switch->GetSelection(); + int extruder_id; + NozzleVolumeType nozzle_type; + parse_extruder_selection(selection, extruder_id, nozzle_type); + return extruder_id; + } + return 0; +} + void Tab::add_scaled_button(wxWindow* parent, ScalableButton** btn, const std::string& icon_name, @@ -917,7 +1008,8 @@ void Tab::update_changed_ui() } update_custom_dirty(dirty_options, nonsys_options); - + update_all_extruder_options_status(); + filter_diff_option(dirty_options); filter_diff_option(nonsys_options); @@ -936,6 +1028,7 @@ void Tab::update_changed_ui() } decorate(); + update_extruder_switch_colors(); wxTheApp->CallAfter([this]() { if (parent()) //To avoid a crash, parent should be exist for a moment of a tree updating @@ -951,6 +1044,168 @@ void add_correct_opts_to_options_list(const std::string &opt_key, std::mapget_printer_extruder_count(); + auto extruders = m_preset_bundle->printers.get_edited_preset().config.option("extruder_type"); + auto nozzle_volumes = m_preset_bundle->project_config.option("nozzle_volume_type"); + + std::set all_config_indices; + for (int extruder_id = 0; extruder_id < extruder_count; ++extruder_id) { + for (auto nozzle_type : get_valid_nozzle_volume_type()) { + auto variant_keys = extruder_variant_keys[m_type >= Preset::TYPE_COUNT ? Preset::TYPE_PRINT : m_type]; + int config_index = m_config->get_index_for_extruder( + extruder_id + 1, + variant_keys.first, + ExtruderType(extruders->values[extruder_id]), + nozzle_type, + variant_keys.second + ); + if (config_index >= 0) { + all_config_indices.insert(config_index); + } + } + } + + auto dirty_options = m_presets->current_dirty_options(true); + auto nonsys_options = m_presets->current_different_from_parent_options(true); + auto filter_extruder_options = [](const std::vector& options) { + std::vector filtered_options; + for (const auto& opt : options) { + if (opt.find('#') != std::string::npos) { + filtered_options.push_back(opt); + } + } + return filtered_options; + }; + + auto filtered_dirty_options = filter_extruder_options(dirty_options); + auto filtered_nonsys_options = filter_extruder_options(nonsys_options); + + for (int config_index : all_config_indices) { + int status_value = m_opt_status_value; + for (const auto &opt_key : filtered_dirty_options) { + m_all_extruder_options_status[opt_key] = status_value & ~osInitValue; + } + for (const auto &opt_key : filtered_nonsys_options) { + auto iter = m_all_extruder_options_status.find(opt_key); + if (iter != m_all_extruder_options_status.end()) { + iter->second &= ~osSystemValue; + } else { + m_all_extruder_options_status[opt_key] = status_value & ~osSystemValue; + } + } + } +} + +void Tab::update_extruder_switch_colors() +{ + if (!m_extruder_switch && !m_variant_combo) { + return; + } + + auto options = generate_extruder_options(); + auto extruders = m_preset_bundle->printers.get_edited_preset().config.option("extruder_type"); + + for (size_t switch_index = 0; switch_index < options.size(); ++switch_index) { + int selection = m_extruder_switch ? m_extruder_switch->GetSelection() : (m_variant_combo ? m_variant_combo->GetSelection() : 0); + if (switch_index == selection) continue; + + bool sys_extruder = true; + bool modified_extruder = false; + std::vector pages_to_check; + + if (m_active_page) { + if (m_active_page->title() == "Speed" || m_active_page->title() == "Motion ability" || m_active_page->title() == "Filament" || + m_active_page->title() == "Setting Overrides" || m_active_page->title() == "Multimaterial") { + for (auto page_ptr : m_pages) { + if (page_ptr.get() == m_active_page) { + pages_to_check.push_back(page_ptr); + break; + } + } + } + } + if (pages_to_check.empty()) { + continue; + } + check_extruder_options_status(switch_index, sys_extruder, modified_extruder, pages_to_check); + + StateColor default_color(std::make_pair(0x6B6B6B, (int) StateColor::NotChecked), std::make_pair(0xFFFFFE, (int) StateColor::Normal)); + StateColor color = modified_extruder ? StateColor(m_modified_label_clr) : default_color; + + if (m_extruder_switch) + m_extruder_switch->SetButtonTextColor(switch_index, color); + if (m_variant_combo) { + Button *btn = m_variant_combo->GetButton(switch_index); + if (btn) { + m_variant_combo->SetButtonTextColor(switch_index, color); + } + } + } +} + +void Tab::check_extruder_options_status(int index, bool &sys_extruder, bool &modified_extruder, const std::vector& pages_to_check) +{ + int config_index = index; + if (m_type == Preset::TYPE_PRINT || m_type == Preset::TYPE_PRINTER) { + int extruder_id; + NozzleVolumeType nozzle_type; + parse_extruder_selection(index, extruder_id, nozzle_type); + + auto extruders = m_preset_bundle->printers.get_edited_preset().config.option("extruder_type"); + auto variant_keys = extruder_variant_keys[m_type >= Preset::TYPE_COUNT ? Preset::TYPE_PRINT : m_type]; + config_index = m_config->get_index_for_extruder( + extruder_id + 1, + variant_keys.first, + ExtruderType(extruders->values[extruder_id]), + nozzle_type, + variant_keys.second + ); + } + + for (auto page : pages_to_check) { + /*if (page->title() != "Speed" && page->title() != "Motion ability" && page->title() != "Filament" && page->title() != "Setting Overrides" && page->title() != "Multimaterial") { + continue; + }*/ + for (auto group : page->m_optgroups) { + for (const auto &kvp : group->opt_map()) { + std::string base_opt_key = kvp.second.first; + // For filament tab, common options will not change color when edited + if (m_type == Preset::TYPE_FILAMENT && kvp.second.second == -1) { + continue; + } + std::string target_opt_key = base_opt_key + "#" + std::to_string(config_index); + + auto status_iter = m_all_extruder_options_status.find(target_opt_key); + if (status_iter != m_all_extruder_options_status.end()) { + bool found_modified_for_this_config = false; + const bool deep_compare = (m_type == Preset::TYPE_PRINTER || m_type == Preset::TYPE_PRINT || m_type == Preset::TYPE_FILAMENT || m_type == Preset::TYPE_SLA_MATERIAL || + m_type == Preset::TYPE_MODEL); + auto original_dirty_options = m_presets->current_dirty_options(deep_compare); + for (const std::string &orig_opt : original_dirty_options) { + if (orig_opt == target_opt_key) { + found_modified_for_this_config = true; + break; + } + } + + if (found_modified_for_this_config) { + sys_extruder = (status_iter->second & osSystemValue) != 0; + modified_extruder |= (status_iter->second & osInitValue) == 0; + + if (!sys_extruder && modified_extruder) { return; } + } + } + } + } + } +} void Tab::init_options_list() { if (!m_options_list.empty()) @@ -1076,6 +1331,13 @@ void Tab::update_changed_tree_ui() get_sys_and_mod_flags("compatible_printers", sys_page, modified_page); } } + if (page->title() == "Speed" || page->title() == "Motion ability" || page->title() == "Filament" || page->title() == "Setting Overrides" || page->title() == "Multimaterial") { + auto options = generate_extruder_options(); + for (size_t switch_index = 0; switch_index < options.size(); ++switch_index) { + std::vector pages_to_check = { page }; + check_extruder_options_status(switch_index, sys_page, modified_page, pages_to_check); + } + } for (auto group : page->m_optgroups) { if (!sys_page && modified_page) @@ -1292,9 +1554,9 @@ void Tab::msw_rescale() bmp->msw_rescale(); if (m_mode_view) - { m_mode_view->Rescale(); - } + if (m_extruder_switch) + m_extruder_switch->Rescale(); if (m_variant_combo) m_variant_combo->Rescale(); @@ -5372,7 +5634,7 @@ void TabPrinter::toggle_options() auto get_index_for_extruder = [this, &extruders, &nozzle_volumes](int extruder_id, int stride = 1) { return m_config->get_index_for_extruder(extruder_id + 1, "printer_extruder_id", - ExtruderType(extruders->values[extruder_id]), NozzleVolumeType(nozzle_volumes->values[extruder_id]), "printer_extruder_variant", stride); + ExtruderType(extruders->values[extruder_id]), get_actual_nozzle_volume_type(extruder_id), "printer_extruder_variant", stride); }; //BBS: whether the preset is Bambu Lab printer @@ -6460,7 +6722,11 @@ bool Tab::tree_sel_change_delayed(wxCommandEvent& event) // update_undo_buttons(); this->OnActivate(); m_parent->set_active_tab(this); - GetParent()->Layout(); + wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo; + if (variant_ctrl) { + m_main_sizer->Show(variant_ctrl, variant_ctrl->IsThisEnabled() && !m_active_page->m_opt_id_map.empty() && !m_active_page->title().StartsWith("Extruder ")); + GetParent()->Layout(); + } m_page_view->Thaw(); return false; @@ -6471,11 +6737,9 @@ bool Tab::tree_sel_change_delayed(wxCommandEvent& event) return false; m_active_page = page; - if (m_extruder_switch) { - m_main_sizer->Show(m_extruder_switch, m_extruder_switch->IsEnabled() && !m_active_page->m_opt_id_map.empty() && !m_active_page->title().StartsWith("Extruder")); - GetParent()->Layout(); - } else if (m_variant_combo) { - m_main_sizer->Show(m_variant_combo, m_variant_combo->IsEnabled() && !m_active_page->m_opt_id_map.empty()); + wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo; + if (variant_ctrl) { + m_main_sizer->Show(variant_ctrl, variant_ctrl->IsThisEnabled() && !m_active_page->m_opt_id_map.empty() && !m_active_page->title().StartsWith("Extruder")); GetParent()->Layout(); } @@ -7303,21 +7567,24 @@ void Tab::update_extruder_variants(int extruder_id) int extruder_nums = m_preset_bundle->get_printer_extruder_count(); nozzle_volumes->values.resize(extruder_nums); if (extruder_nums == 2) { - auto nozzle_volumes_def = m_preset_bundle->project_config.def()->get("nozzle_volume_type"); - wxString left, right; - for (size_t i = 0; i < nozzle_volumes_def->enum_labels.size(); ++i) { - if (nozzle_volumes->values[0] == i) left = _L(nozzle_volumes_def->enum_labels[i]); - if (nozzle_volumes->values[1] == i) right = _L(nozzle_volumes_def->enum_labels[i]); + auto options = generate_extruder_options(); + m_extruder_switch->SetOptions(options); + + int selection_index; + if (extruder_id >= 0) { + NozzleVolumeType current_nozzle_type = get_actual_nozzle_volume_type(extruder_id); + selection_index = calculate_selection_index_for_extruder(extruder_id, current_nozzle_type); + } else { + selection_index = m_extruder_switch->GetSelection(); + if (selection_index < 0) { + selection_index = 0; + } } - m_extruder_switch->SetLabels(wxString::Format(_L("Left: %s"), left), wxString::Format(_L("Right: %s"), right)); - m_extruder_switch->SetValue(extruder_id == 1); + + m_extruder_switch->SetSelection(selection_index); m_extruder_switch->Enable(true); - assert(m_extruder_switch->IsEnabled()); } else { m_extruder_switch->Enable(false); - m_main_sizer->Show(m_extruder_switch, false); - GetParent()->Layout(); - return; } } else if (m_variant_combo) { if (extruder_id >= 0) @@ -7333,29 +7600,43 @@ void Tab::update_extruder_variants(int extruder_id) m_variant_combo->Enable(options.size() > 1); } switch_excluder(extruder_id); - if (m_extruder_switch) { - m_main_sizer->Show(m_extruder_switch, m_active_page && !m_active_page->m_opt_id_map.empty()); - GetParent()->Layout(); - } else if (m_variant_combo) { - m_main_sizer->Show(m_variant_combo, m_variant_combo->IsEnabled() && m_active_page && !m_active_page->m_opt_id_map.empty()); + wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo; + if (variant_ctrl) { + m_main_sizer->Show(variant_ctrl, variant_ctrl->IsThisEnabled() && m_active_page && !m_active_page->m_opt_id_map.empty() && !m_active_page->title().StartsWith("Extruder ")); GetParent()->Layout(); } } +NozzleVolumeType Tab::get_actual_nozzle_volume_type(int extruder_id) +{ + int extruder_count = m_preset_bundle->get_printer_extruder_count(); + auto nozzle_volumes = m_preset_bundle->project_config.option("nozzle_volume_type"); + if (extruder_count == 1) { + if (extruder_id < 0) + return NozzleVolumeType::nvtStandard; + + return NozzleVolumeType(nozzle_volumes->values[extruder_id]); + } + + if (extruder_id < 0 || extruder_id >= extruder_count) + return NozzleVolumeType::nvtStandard; + + if (m_actual_nozzle_volumes.size() != static_cast(extruder_count)) + m_actual_nozzle_volumes.resize(extruder_count, NozzleVolumeType::nvtStandard); + + return m_actual_nozzle_volumes[extruder_id]; +} + void Tab::switch_excluder(int extruder_id) { Preset & printer_preset = m_preset_bundle->printers.get_edited_preset(); auto nozzle_volumes = m_preset_bundle->project_config.option("nozzle_volume_type"); auto extruders = printer_preset.config.option("extruder_type"); - std::pair variant_keys[]{ - {}, {"print_extruder_id", "print_extruder_variant"}, // Preset::TYPE_PRINT - {}, {"", "filament_extruder_variant"}, // Preset::TYPE_FILAMENT filament don't use id anymore - {}, {"printer_extruder_id", "printer_extruder_variant"}, // Preset::TYPE_PRINTER - }; + if (!m_variant_combo && (extruder_id >= (int)nozzle_volumes->size() || extruder_id >= (int)extruders->size())) extruder_id = 0; if (m_extruder_switch && m_type != Preset::TYPE_PRINTER) { - int current_extruder = m_extruder_switch->GetValue() ? 1 : 0; + int current_extruder = get_current_active_extruder(); if (extruder_id == -1) extruder_id = current_extruder; else if (extruder_id != current_extruder) @@ -7370,15 +7651,16 @@ void Tab::switch_excluder(int extruder_id) return; } auto get_index_for_extruder = - [this, &extruders, &nozzle_volumes, variant_keys = variant_keys[m_type >= Preset::TYPE_COUNT ? Preset::TYPE_PRINT : m_type]](int extruder_id, int stride = 1) { + [this, &extruders, &nozzle_volumes, variant_keys = extruder_variant_keys[m_type >= Preset::TYPE_COUNT ? Preset::TYPE_PRINT : m_type]](int extruder_id, int stride = 1) { return m_config->get_index_for_extruder(extruder_id + 1, variant_keys.first, - ExtruderType(extruders->values[extruder_id]), NozzleVolumeType(nozzle_volumes->values[extruder_id]), variant_keys.second, stride); + ExtruderType(extruders->values[extruder_id]), get_actual_nozzle_volume_type(extruder_id), variant_keys.second, stride); }; auto index = m_variant_combo ? extruder_id : get_index_for_extruder(extruder_id == -1 ? 0 : extruder_id); if (index < 0) return; - if (m_variant_combo) - m_variant_combo->SetClientData(reinterpret_cast(static_cast(index))); + if (m_extruder_switch) m_extruder_switch->SetClientData(reinterpret_cast(static_cast(index))); + if (m_variant_combo) m_variant_combo->SetClientData(reinterpret_cast(static_cast(index))); + wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo; for (auto page : m_pages) { bool is_extruder = false; if (m_type == Preset::TYPE_PRINTER) { diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index ec9cfb2db3..1d6002aaf0 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -251,6 +251,7 @@ protected: std::vector m_dependent_tabs; enum OptStatus { osSystemValue = 1, osInitValue = 2 }; std::map m_options_list; + std::map m_all_extruder_options_status; int m_opt_status_value = 0; bool m_is_modified_values{ false }; @@ -307,8 +308,9 @@ public: int m_update_cnt = 0; ModeSwitchButton *m_mode_view = nullptr; - SwitchButton *m_extruder_switch = nullptr; - MultiSwitchButton *m_variant_combo = nullptr; + MultiSwitchButton * m_extruder_switch = nullptr; + MultiSwitchButton * m_variant_combo = nullptr; + std::vector m_actual_nozzle_volumes; public: // BBS @@ -361,8 +363,11 @@ public: void decorate(); void update_changed_ui(); void get_sys_and_mod_flags(const std::string& opt_key, bool& sys_page, bool& modified_page); - void update_changed_tree_ui(); + void update_changed_tree_ui(); void update_undo_buttons(); + void update_extruder_switch_colors(); + void update_all_extruder_options_status(); + void check_extruder_options_status(int index, bool &sys_extruder, bool &modified_extruder, const std::vector& pages_to_check); void on_roll_back_value(const bool to_sys = false); @@ -431,7 +436,12 @@ public: void update_extruder_variants(int extruder_id = -1); void switch_excluder(int extruder_id = -1); - std::vector generate_extruder_options(); + void parse_extruder_selection(int selection, int &extruder_id, NozzleVolumeType &nozzle_type); + int calculate_selection_index_for_extruder(int extruder_id, NozzleVolumeType nozzle_type); + int get_current_active_extruder(); + + std::vector generate_extruder_options(); + NozzleVolumeType get_actual_nozzle_volume_type(int extruder_id); protected: void create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, const std::string& path, widget_t widget); diff --git a/src/slic3r/GUI/Widgets/SwitchButton.cpp b/src/slic3r/GUI/Widgets/SwitchButton.cpp index 0ff70d4a77..3f56c39577 100644 --- a/src/slic3r/GUI/Widgets/SwitchButton.cpp +++ b/src/slic3r/GUI/Widgets/SwitchButton.cpp @@ -395,6 +395,171 @@ void ModeSwitchButton::update_tooltip() SetToolTip(m_tooltips[m_selection]); } +SwitchBoard::SwitchBoard(wxWindow *parent, wxString leftL, wxString right, wxSize size) + : wxWindow(parent, wxID_ANY, wxDefaultPosition, size) +{ +#ifdef __WINDOWS__ + SetDoubleBuffered(true); +#endif //__WINDOWS__ + + SetBackgroundColour(*wxWHITE); + leftLabel = leftL; + rightLabel = right; + + SetMinSize(size); + SetMaxSize(size); + + Bind(wxEVT_PAINT, &SwitchBoard::paintEvent, this); + Bind(wxEVT_LEFT_DOWN, &SwitchBoard::on_left_down, this); + + Bind(wxEVT_ENTER_WINDOW, [this](auto &e) { SetCursor(wxCURSOR_HAND); }); + Bind(wxEVT_LEAVE_WINDOW, [this](auto &e) { SetCursor(wxCURSOR_ARROW); }); +} + +void SwitchBoard::updateState(wxString target) +{ + if (target.empty()) { + if (!switch_left && !switch_right) { + return; + } + + switch_left = false; + switch_right = false; + } else { + if (target == "left") { + if (switch_left && !switch_right) { + return; + } + + switch_left = true; + switch_right = false; + } else if (target == "right") { + if (!switch_left && switch_right) { + return; + } + + switch_left = false; + switch_right = true; + } + } + + Refresh(); +} + +void SwitchBoard::paintEvent(wxPaintEvent &evt) +{ + wxPaintDC dc(this); + render(dc); +} + +void SwitchBoard::render(wxDC &dc) +{ +#ifdef __WXMSW__ + wxSize size = GetSize(); + wxMemoryDC memdc; + wxBitmap bmp(size.x, size.y); + memdc.SelectObject(bmp); + memdc.Blit({0, 0}, size, &dc, {0, 0}); + + { + wxGCDC dc2(memdc); + doRender(dc2); + } + + memdc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#else + doRender(dc); +#endif +} + +void SwitchBoard::doRender(wxDC &dc) +{ + wxColour disable_color = wxColour(0xCECECE); + + dc.SetPen(*wxTRANSPARENT_PEN); + + if (is_enable) {dc.SetBrush(wxBrush(0xeeeeee)); + } else {dc.SetBrush(disable_color);} + dc.DrawRoundedRectangle(0, 0, GetSize().x, GetSize().y, 8); + + /*left*/ + if (switch_left) { + is_enable ? dc.SetBrush(wxBrush(wxColour(0, 150, 136))) : dc.SetBrush(disable_color); + dc.DrawRoundedRectangle(0, 0, GetSize().x / 2, GetSize().y, 8); + } + + if (switch_left) { + dc.SetTextForeground(*wxWHITE); + } else { + dc.SetTextForeground(0x333333); + } + + dc.SetFont(::Label::Body_13); + Slic3r::GUI::WxFontUtils::get_suitable_font_size(0.6 * GetSize().GetHeight(), dc); + + auto left_txt_size = dc.GetTextExtent(leftLabel); + dc.DrawText(leftLabel, wxPoint((GetSize().x / 2 - left_txt_size.x) / 2, (GetSize().y - left_txt_size.y) / 2)); + + /*right*/ + if (switch_right) { + if (is_enable) {dc.SetBrush(wxBrush(wxColour(0, 150, 136))); + } else {dc.SetBrush(disable_color);} + dc.DrawRoundedRectangle(GetSize().x / 2, 0, GetSize().x / 2, GetSize().y, 8); + } + + auto right_txt_size = dc.GetTextExtent(rightLabel); + if (switch_right) { + dc.SetTextForeground(*wxWHITE); + } else { + dc.SetTextForeground(0x333333); + } + dc.DrawText(rightLabel, wxPoint((GetSize().x / 2 - right_txt_size.x) / 2 + GetSize().x / 2, (GetSize().y - right_txt_size.y) / 2)); + +} + +void SwitchBoard::on_left_down(wxMouseEvent &evt) +{ + if (!is_enable) { + return; + } + int index = -1; + auto pos = ClientToScreen(evt.GetPosition()); + auto rect = ClientToScreen(wxPoint(0, 0)); + + if (pos.x > 0 && pos.x < rect.x + GetSize().x / 2) { + switch_left = true; + switch_right = false; + index = 1; + } else { + switch_left = false; + switch_right = true; + index = 0; + } + + if (auto_disable_when_switch) + { + is_enable = false;// make it disable while switching + } + Refresh(); + + wxCommandEvent event(wxCUSTOMEVT_SWITCH_POS); + event.SetInt(index); + wxPostEvent(this, event); +} + +bool SwitchBoard::Enable(bool enable /* = true */) +{ + if (is_enable == enable) + { + return false; + } + + is_enable = enable; + Refresh(); + return true; +} + MultiSwitchButton::MultiSwitchButton(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style) : StaticBox(parent, id, pos, size, style) , m_bg_color(StateColor( @@ -580,168 +745,3 @@ bool MultiSwitchButton::send_selection_event() GetEventHandler()->ProcessEvent(evt); return true; } - -SwitchBoard::SwitchBoard(wxWindow *parent, wxString leftL, wxString right, wxSize size) - : wxWindow(parent, wxID_ANY, wxDefaultPosition, size) -{ -#ifdef __WINDOWS__ - SetDoubleBuffered(true); -#endif //__WINDOWS__ - - SetBackgroundColour(*wxWHITE); - leftLabel = leftL; - rightLabel = right; - - SetMinSize(size); - SetMaxSize(size); - - Bind(wxEVT_PAINT, &SwitchBoard::paintEvent, this); - Bind(wxEVT_LEFT_DOWN, &SwitchBoard::on_left_down, this); - - Bind(wxEVT_ENTER_WINDOW, [this](auto &e) { SetCursor(wxCURSOR_HAND); }); - Bind(wxEVT_LEAVE_WINDOW, [this](auto &e) { SetCursor(wxCURSOR_ARROW); }); -} - -void SwitchBoard::updateState(wxString target) -{ - if (target.empty()) { - if (!switch_left && !switch_right) { - return; - } - - switch_left = false; - switch_right = false; - } else { - if (target == "left") { - if (switch_left && !switch_right) { - return; - } - - switch_left = true; - switch_right = false; - } else if (target == "right") { - if (!switch_left && switch_right) { - return; - } - - switch_left = false; - switch_right = true; - } - } - - Refresh(); -} - -void SwitchBoard::paintEvent(wxPaintEvent &evt) -{ - wxPaintDC dc(this); - render(dc); -} - -void SwitchBoard::render(wxDC &dc) -{ -#ifdef __WXMSW__ - wxSize size = GetSize(); - wxMemoryDC memdc; - wxBitmap bmp(size.x, size.y); - memdc.SelectObject(bmp); - memdc.Blit({0, 0}, size, &dc, {0, 0}); - - { - wxGCDC dc2(memdc); - doRender(dc2); - } - - memdc.SelectObject(wxNullBitmap); - dc.DrawBitmap(bmp, 0, 0); -#else - doRender(dc); -#endif -} - -void SwitchBoard::doRender(wxDC &dc) -{ - wxColour disable_color = wxColour(0xCECECE); - - dc.SetPen(*wxTRANSPARENT_PEN); - - if (is_enable) {dc.SetBrush(wxBrush(0xeeeeee)); - } else {dc.SetBrush(disable_color);} - dc.DrawRoundedRectangle(0, 0, GetSize().x, GetSize().y, 8); - - /*left*/ - if (switch_left) { - is_enable ? dc.SetBrush(wxBrush(wxColour(0, 150, 136))) : dc.SetBrush(disable_color); - dc.DrawRoundedRectangle(0, 0, GetSize().x / 2, GetSize().y, 8); - } - - if (switch_left) { - dc.SetTextForeground(*wxWHITE); - } else { - dc.SetTextForeground(0x333333); - } - - dc.SetFont(::Label::Body_13); - Slic3r::GUI::WxFontUtils::get_suitable_font_size(0.6 * GetSize().GetHeight(), dc); - - auto left_txt_size = dc.GetTextExtent(leftLabel); - dc.DrawText(leftLabel, wxPoint((GetSize().x / 2 - left_txt_size.x) / 2, (GetSize().y - left_txt_size.y) / 2)); - - /*right*/ - if (switch_right) { - if (is_enable) {dc.SetBrush(wxBrush(wxColour(0, 150, 136))); - } else {dc.SetBrush(disable_color);} - dc.DrawRoundedRectangle(GetSize().x / 2, 0, GetSize().x / 2, GetSize().y, 8); - } - - auto right_txt_size = dc.GetTextExtent(rightLabel); - if (switch_right) { - dc.SetTextForeground(*wxWHITE); - } else { - dc.SetTextForeground(0x333333); - } - dc.DrawText(rightLabel, wxPoint((GetSize().x / 2 - right_txt_size.x) / 2 + GetSize().x / 2, (GetSize().y - right_txt_size.y) / 2)); - -} - -void SwitchBoard::on_left_down(wxMouseEvent &evt) -{ - if (!is_enable) { - return; - } - int index = -1; - auto pos = ClientToScreen(evt.GetPosition()); - auto rect = ClientToScreen(wxPoint(0, 0)); - - if (pos.x > 0 && pos.x < rect.x + GetSize().x / 2) { - switch_left = true; - switch_right = false; - index = 1; - } else { - switch_left = false; - switch_right = true; - index = 0; - } - - if (auto_disable_when_switch) - { - is_enable = false;// make it disable while switching - } - Refresh(); - - wxCommandEvent event(wxCUSTOMEVT_SWITCH_POS); - event.SetInt(index); - wxPostEvent(this, event); -} - -bool SwitchBoard::Enable(bool enable /* = true */) -{ - if (is_enable == enable) - { - return false; - } - - is_enable = enable; - Refresh(); - return true; -} diff --git a/src/slic3r/GUI/Widgets/SwitchButton.hpp b/src/slic3r/GUI/Widgets/SwitchButton.hpp index 301287460a..e364e64656 100644 --- a/src/slic3r/GUI/Widgets/SwitchButton.hpp +++ b/src/slic3r/GUI/Widgets/SwitchButton.hpp @@ -8,12 +8,11 @@ #include #include #include +#include "Button.hpp" wxDECLARE_EVENT(wxCUSTOMEVT_SWITCH_POS, wxCommandEvent); wxDECLARE_EVENT(wxCUSTOMEVT_MULTISWITCH_SELECTION, wxCommandEvent); -class Button; - class SwitchButton : public wxBitmapToggleButton { public: @@ -81,53 +80,6 @@ private: wxString m_tooltips[3]; }; -class MultiSwitchButton : public StaticBox -{ -public: - MultiSwitchButton(wxWindow *parent = nullptr, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition, - const wxSize &size = wxDefaultSize, long style = 0); - ~MultiSwitchButton(); - - int AppendOption(const wxString &option, void *clientData = nullptr); - void SetOptions(const std::vector &options); - void DeleteAllOptions(); - - unsigned int GetCount() const; - - int GetSelection() const; - void SetSelection(int index); - wxString GetSelectedText() const; - - wxString GetOptionText(unsigned int index) const; - void SetOptionText(unsigned int index, const wxString &text); - - void *GetOptionData(unsigned int index) const; - void SetOptionData(unsigned int index, void *clientData); - - void SetBackgroundColor(const StateColor &color); - void SetTextColor(const StateColor &color); - void SetButtonCornerRadius(double radius); - void SetButtonPadding(const wxSize &padding); - - void Rescale(); - -protected: - void button_clicked(wxCommandEvent &event); - void update_button_styles(); - - bool send_selection_event(); - -private: - std::vector