From f1702a5c3604f685a3b35ea0e83d29bdbbd90f70 Mon Sep 17 00:00:00 2001 From: "xun.zhang" Date: Fri, 29 Nov 2024 17:37:07 +0800 Subject: [PATCH] ENH: refine ui logic with filament group 1. Add filament group pop up when slice 2. Add more filament modes in filament dialog 3. Add capsule button jira:NONE Signed-off-by: xun.zhang Change-Id: I8bc3a2e08696e406b89e550a0335a1a36728ee65 --- bbl/i18n/list.txt | 4 +- resources/images/capsule_tag_off.svg | 3 + resources/images/capsule_tag_on.svg | 4 + resources/images/flush_mode_panel_icon.svg | 7 + resources/images/map_mode_off.svg | 3 + resources/images/map_mode_off_hovered.svg | 3 + resources/images/map_mode_on.svg | 4 + resources/images/map_mode_on_hovered.svg | 4 + resources/images/match_mode_panel_icon.svg | 3 + src/libslic3r/AppConfig.cpp | 12 + src/slic3r/CMakeLists.txt | 6 + src/slic3r/GUI/CapsuleButton.cpp | 117 +++++++ src/slic3r/GUI/CapsuleButton.hpp | 28 ++ src/slic3r/GUI/DragDropPanel.cpp | 37 ++- src/slic3r/GUI/DragDropPanel.hpp | 3 + src/slic3r/GUI/FilamentGroupPopup.cpp | 318 +++++++++++++++++++ src/slic3r/GUI/FilamentGroupPopup.hpp | 54 ++++ src/slic3r/GUI/FilamentMapDialog.cpp | 339 ++++++++------------- src/slic3r/GUI/FilamentMapDialog.hpp | 53 ++-- src/slic3r/GUI/FilamentMapPanel.cpp | 324 ++++++++++++++++++++ src/slic3r/GUI/FilamentMapPanel.hpp | 89 ++++++ src/slic3r/GUI/GCodeViewer.cpp | 2 +- src/slic3r/GUI/MainFrame.cpp | 62 +++- src/slic3r/GUI/MainFrame.hpp | 5 + src/slic3r/GUI/Plater.cpp | 20 +- src/slic3r/GUI/Plater.hpp | 1 + src/slic3r/GUI/Preferences.cpp | 8 + 27 files changed, 1255 insertions(+), 258 deletions(-) create mode 100644 resources/images/capsule_tag_off.svg create mode 100644 resources/images/capsule_tag_on.svg create mode 100644 resources/images/flush_mode_panel_icon.svg create mode 100644 resources/images/map_mode_off.svg create mode 100644 resources/images/map_mode_off_hovered.svg create mode 100644 resources/images/map_mode_on.svg create mode 100644 resources/images/map_mode_on_hovered.svg create mode 100644 resources/images/match_mode_panel_icon.svg create mode 100644 src/slic3r/GUI/CapsuleButton.cpp create mode 100644 src/slic3r/GUI/CapsuleButton.hpp create mode 100644 src/slic3r/GUI/FilamentGroupPopup.cpp create mode 100644 src/slic3r/GUI/FilamentGroupPopup.hpp create mode 100644 src/slic3r/GUI/FilamentMapPanel.cpp create mode 100644 src/slic3r/GUI/FilamentMapPanel.hpp diff --git a/bbl/i18n/list.txt b/bbl/i18n/list.txt index 920971a51..1b1a3fd4b 100644 --- a/bbl/i18n/list.txt +++ b/bbl/i18n/list.txt @@ -172,4 +172,6 @@ src/slic3r/GUI/SendMultiMachinePage.cpp src/slic3r/GUI/MultiMachinePage.cpp src/slic3r/GUI/MultiMachineManagerPage.cpp src/slic3r/GUI/MultiTaskManagerPage.cpp -src/slic3r/GUI/MultiMachine.cpp \ No newline at end of file +src/slic3r/GUI/MultiMachine.cpp +src/slic3r/GUI/FilamentMapDialog.cpp +src/slic3r/GUI/FilamentGroupPopup.cpp \ No newline at end of file diff --git a/resources/images/capsule_tag_off.svg b/resources/images/capsule_tag_off.svg new file mode 100644 index 000000000..2127760b7 --- /dev/null +++ b/resources/images/capsule_tag_off.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/capsule_tag_on.svg b/resources/images/capsule_tag_on.svg new file mode 100644 index 000000000..39726becb --- /dev/null +++ b/resources/images/capsule_tag_on.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/flush_mode_panel_icon.svg b/resources/images/flush_mode_panel_icon.svg new file mode 100644 index 000000000..2e9cfc710 --- /dev/null +++ b/resources/images/flush_mode_panel_icon.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/map_mode_off.svg b/resources/images/map_mode_off.svg new file mode 100644 index 000000000..5400ff63e --- /dev/null +++ b/resources/images/map_mode_off.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/map_mode_off_hovered.svg b/resources/images/map_mode_off_hovered.svg new file mode 100644 index 000000000..78e2beb06 --- /dev/null +++ b/resources/images/map_mode_off_hovered.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/map_mode_on.svg b/resources/images/map_mode_on.svg new file mode 100644 index 000000000..df1c78b77 --- /dev/null +++ b/resources/images/map_mode_on.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/map_mode_on_hovered.svg b/resources/images/map_mode_on_hovered.svg new file mode 100644 index 000000000..eb5bf9cd1 --- /dev/null +++ b/resources/images/map_mode_on_hovered.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/match_mode_panel_icon.svg b/resources/images/match_mode_panel_icon.svg new file mode 100644 index 000000000..01fc724da --- /dev/null +++ b/resources/images/match_mode_panel_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index d3e37c272..cbf5f4fd4 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -265,6 +265,18 @@ void AppConfig::set_defaults() set_bool("auto_calculate_when_filament_change", true); } + if (get("ignore_ext_filament_in_filament_map").empty()){ + set_bool("ignore_ext_filament_in_filament_map", false); + } + + if (get("pop_up_filament_map_mode").empty()){ + set_bool("pop_up_filament_map_mode", true); + } + + if (get("prefered_filament_map_mode").empty()){ + set("prefered_filament_map_mode",ConfigOptionEnum::get_enum_names()[FilamentMapMode::fmmAutoForFlush]); + } + if (get("show_home_page").empty()) { set_bool("show_home_page", true); } diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 58e9186b5..03ae50a22 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -286,6 +286,10 @@ set(SLIC3R_GUI_SOURCES GUI/Field.hpp GUI/DragDropPanel.cpp GUI/DragDropPanel.hpp + GUI/CapsuleButton.cpp + GUI/CapsuleButton.hpp + GUI/FilamentMapPanel.cpp + GUI/FilamentMapPanel.hpp GUI/FilamentMapDialog.cpp GUI/FilamentMapDialog.hpp GUI/OptionsGroup.cpp @@ -406,6 +410,8 @@ set(SLIC3R_GUI_SOURCES GUI/InstanceCheck.hpp GUI/Search.cpp GUI/Search.hpp + GUI/FilamentGroupPopup.hpp + GUI/FilamentGroupPopup.cpp GUI/NotificationManager.cpp GUI/NotificationManager.hpp GUI/UnsavedChangesDialog.cpp diff --git a/src/slic3r/GUI/CapsuleButton.cpp b/src/slic3r/GUI/CapsuleButton.cpp new file mode 100644 index 000000000..ed544e982 --- /dev/null +++ b/src/slic3r/GUI/CapsuleButton.cpp @@ -0,0 +1,117 @@ +#include "GUI_App.hpp" +#include "CapsuleButton.hpp" +#include "wx/graphics.h" +#include "Widgets/Label.hpp" +#include "wx/dcgraph.h" + +namespace Slic3r { namespace GUI { +CapsuleButton::CapsuleButton(wxWindow *parent, wxWindowID id, const wxString &label, bool selected) : wxPanel(parent, id) +{ + SetBackgroundColour(*wxWHITE); + SetBackgroundStyle(wxBG_STYLE_PAINT); + + m_hovered = false; + m_selected = selected; + + auto sizer = new wxBoxSizer(wxHORIZONTAL); + + std::string icon_name = selected ? "capsule_tag_on" : "capsule_tag_off"; + auto bmp = create_scaled_bitmap(icon_name, nullptr, FromDIP(16)); + + m_btn = new wxBitmapButton(this, wxID_ANY, bmp, wxDefaultPosition, wxDefaultSize, wxNO_BORDER); + m_btn->SetBackgroundColour(*wxWHITE); + + m_label = new Label(this, label); + + sizer->AddSpacer(FromDIP(8)); + sizer->Add(m_btn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, FromDIP(6)); + sizer->AddSpacer(FromDIP(8)); + sizer->Add(m_label, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, FromDIP(6)); + sizer->AddSpacer(FromDIP(8)); + + SetSizer(sizer); + Layout(); + Fit(); + + auto forward_click_to_parent = [this](auto &event) { + wxCommandEvent click_event(wxEVT_BUTTON, GetId()); + click_event.SetEventObject(this); + this->ProcessEvent(click_event); + }; + + m_btn->Bind(wxEVT_LEFT_DOWN, forward_click_to_parent); + m_label->Bind(wxEVT_LEFT_DOWN, forward_click_to_parent); + this->Bind(wxEVT_LEFT_DOWN, forward_click_to_parent); + + Bind(wxEVT_PAINT, &CapsuleButton::OnPaint, this); + Bind(wxEVT_ENTER_WINDOW, &CapsuleButton::OnEnterWindow, this); + Bind(wxEVT_LEAVE_WINDOW, &CapsuleButton::OnLeaveWindow, this); + + GUI::wxGetApp().UpdateDarkUIWin(this); +} +void CapsuleButton::OnPaint(wxPaintEvent &event) +{ + wxAutoBufferedPaintDC dc(this); + wxGraphicsContext *gc = wxGraphicsContext::Create(dc); + + if (gc) { + dc.Clear(); + wxRect rect = GetClientRect(); + gc->SetBrush(wxTransparentColour); + gc->DrawRoundedRectangle(0, 0, rect.width, rect.height, 0); + wxColour bg_color = m_selected ? wxColour("#EBF9F0") : wxColour("#FFFFFF"); + wxColour border_color = m_hovered || m_selected ? wxColour("#00AE42") : wxColour("#CECECE"); + int cornerRadius = 5; + gc->SetBrush(wxBrush(bg_color)); + gc->SetPen(wxPen(border_color, 2)); + gc->DrawRoundedRectangle(1, 1, rect.width - 2, rect.height - 2, cornerRadius); + delete gc; + } +} +void CapsuleButton::Select(bool selected) +{ + m_selected = selected; + UpdateStatus(); + Refresh(); +} + +void CapsuleButton::OnEnterWindow(wxMouseEvent &event) +{ + if (!m_hovered) { + m_hovered = true; + UpdateStatus(); + Refresh(); + } + event.Skip(); +} + +void CapsuleButton::OnLeaveWindow(wxMouseEvent &event) +{ + if (m_hovered) { + wxPoint pos = this->ScreenToClient(wxGetMousePosition()); + if (this->GetClientRect().Contains(pos)) return; + m_hovered = false; + UpdateStatus(); + Refresh(); + } + event.Skip(); +} + +void CapsuleButton::UpdateStatus() +{ + const wxColour selected_color = wxColour("#EBF9F0"); + const wxColour normal_color = wxColour("#FFFFFF"); + + std::string icon_name = m_selected ? "capsule_tag_on" : "capsule_tag_off"; + auto bmp = create_scaled_bitmap(icon_name, nullptr, FromDIP(16)); + m_btn->SetBitmap(bmp); + + if (m_selected) { + m_label->SetBackgroundColour(selected_color); + m_btn->SetBackgroundColour(selected_color); + } else { + m_label->SetBackgroundColour(normal_color); + m_btn->SetBackgroundColour(normal_color); + } +} +}} // namespace Slic3r::GUI \ No newline at end of file diff --git a/src/slic3r/GUI/CapsuleButton.hpp b/src/slic3r/GUI/CapsuleButton.hpp new file mode 100644 index 000000000..87d516752 --- /dev/null +++ b/src/slic3r/GUI/CapsuleButton.hpp @@ -0,0 +1,28 @@ +#ifndef CAPSULE_BUTTON_HPP +#define CAPSULE_BUTTON_HPP + +#include "GUI.hpp" +#include "wxExtensions.hpp" + +namespace Slic3r { namespace GUI { +class CapsuleButton : public wxPanel +{ +public: + CapsuleButton(wxWindow *parent, wxWindowID id, const wxString &label, bool selected); + void Select(bool selected); +protected: + void OnPaint(wxPaintEvent &event); +private: + void OnEnterWindow(wxMouseEvent &event); + void OnLeaveWindow(wxMouseEvent &event); + void UpdateStatus(); + + wxBitmapButton *m_btn; + Label *m_label; + + bool m_hovered; + bool m_selected; +}; +}} // namespace Slic3r::GUI + +#endif \ No newline at end of file diff --git a/src/slic3r/GUI/DragDropPanel.cpp b/src/slic3r/GUI/DragDropPanel.cpp index f3b60cf91..c7f110200 100644 --- a/src/slic3r/GUI/DragDropPanel.cpp +++ b/src/slic3r/GUI/DragDropPanel.cpp @@ -1,4 +1,5 @@ #include "DragDropPanel.hpp" +#include "Widgets/Label.hpp" #include namespace Slic3r { namespace GUI { @@ -9,6 +10,27 @@ struct CustomData unsigned char r, g, b; }; + +wxColor Hex2Color(const std::string& str) +{ + if (str.empty() || (str.length() != 9 && str.length() != 7) || str[0] != '#') + throw std::invalid_argument("Invalid hex color format"); + + auto hexToByte = [](const std::string& hex)->unsigned char + { + unsigned int byte; + std::istringstream(hex) >> std::hex >> byte; + return static_cast(byte); + }; + auto r = hexToByte(str.substr(1, 2)); + auto g = hexToByte(str.substr(3, 2)); + auto b = hexToByte(str.substr(5, 2)); + unsigned char a = 255; + if (str.size() == 9) + a = hexToByte(str.substr(7, 2)); + return wxColor(r, g, b, a); +} + // Custom data object used to store information that needs to be backed up during drag and drop class ColorDataObject : public wxCustomDataObject { @@ -150,21 +172,24 @@ DragDropPanel::DragDropPanel(wxWindow *parent, const wxString &label, bool is_au auto title_sizer = new wxBoxSizer(wxHORIZONTAL); title_panel->SetSizer(title_sizer); - wxStaticText *staticText = new wxStaticText(this, wxID_ANY, label); - staticText->SetBackgroundColour(0xEEEEEE); - title_sizer->Add(staticText, 0, wxALIGN_CENTER | wxALL, FromDIP(5)); + Label* static_text = new Label(this, label); + static_text->SetFont(Label::Head_13); + static_text->SetBackgroundColour(0xEEEEEE); + + title_sizer->Add(static_text, 0, wxALIGN_CENTER | wxALL, FromDIP(5)); m_sizer->Add(title_panel, 0, wxEXPAND); m_sizer->AddSpacer(20); - m_grid_item_sizer = new wxGridSizer(0, 5, FromDIP(10), 0); // row = 0, col = 3, 10 10 is space - m_sizer->Add(m_grid_item_sizer); + m_grid_item_sizer = new wxGridSizer(0, 6, FromDIP(5),FromDIP(5)); // row = 0, col = 3, 10 10 is space + m_sizer->Add(m_grid_item_sizer, 1, wxEXPAND); // set droptarget auto drop_target = new ColorDropTarget(this); SetDropTarget(drop_target); SetSizer(m_sizer); + Layout(); Fit(); } @@ -172,7 +197,7 @@ void DragDropPanel::AddColorBlock(const wxColour &color, int filament_id, bool u { ColorPanel *panel = new ColorPanel(this, color, filament_id); panel->SetMinSize(wxSize(FromDIP(32), FromDIP(40))); - m_grid_item_sizer->Add(panel, 0, wxALIGN_CENTER | wxLEFT, FromDIP(10)); + m_grid_item_sizer->Add(panel, 0, wxALIGN_CENTER); m_filament_blocks.push_back(panel); if (update_ui) { m_filament_blocks.front()->Refresh(); // FIX BUG: STUDIO-8467 diff --git a/src/slic3r/GUI/DragDropPanel.hpp b/src/slic3r/GUI/DragDropPanel.hpp index 3bcb6ecf6..51e41e04b 100644 --- a/src/slic3r/GUI/DragDropPanel.hpp +++ b/src/slic3r/GUI/DragDropPanel.hpp @@ -11,6 +11,9 @@ namespace Slic3r { namespace GUI { + +wxColor Hex2Color(const std::string& str); + class ColorPanel; class DragDropPanel : public wxPanel { diff --git a/src/slic3r/GUI/FilamentGroupPopup.cpp b/src/slic3r/GUI/FilamentGroupPopup.cpp new file mode 100644 index 000000000..1cd65efa5 --- /dev/null +++ b/src/slic3r/GUI/FilamentGroupPopup.cpp @@ -0,0 +1,318 @@ +#include "FilamentGroupPopup.hpp" +#include "FilamentMapDialog.hpp" +#include "GUI_App.hpp" +#include "MsgDialog.hpp" +#include "I18N.hpp" +#include "wx/dcgraph.h" + +namespace Slic3r { namespace GUI { + +static const wxString AutoForFlushLabel = _L("Filament-Saving Mode"); +static const wxString AutoForMatchLabel = _L("Convenient Mode"); +static const wxString ManualLabel = _L("Manual Mode"); + +static const wxString AutoForFlushDesp = _L("(Arrage after slicing)"); +static const wxString AutoForMatchDesp = _L("(Arrange before slicing)"); +static const wxString ManualDesp = ""; + +static const wxString AutoForFlushDetail = _L("Disregrad the filaments in AMS. Optimize filament usage " + "by calculating the best allocation for the left and right " + "nozzles. Arrange the filaments according on the printer according to " + "the slicing results."); +static const wxString AutoForMatchDetail = _L("Based on the current filaments in the AMS, allocate the " + "filaments to the left and right nozzles."); +static const wxString ManualDetail = _L("Mannully allocate the filaments for the left and right nozzles."); + +static bool is_multi_extruder() +{ + const auto &preset_bundle = wxGetApp().preset_bundle; + const auto &full_config = preset_bundle->full_config(); + const auto nozzle_diameters = full_config.option("nozzle_diameter"); + return nozzle_diameters->size() > 1; +} + +FilamentMapMode get_prefered_map_mode() +{ + const static std::map enum_keys_map = ConfigOptionEnum::get_enum_values(); + auto &app_config = wxGetApp().app_config; + std::string mode_str = app_config->get("prefered_filament_map_mode"); + auto iter = enum_keys_map.find(mode_str); + if (iter == enum_keys_map.end()) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("Could not get prefered_filament_map_mode from app config, use AutoForFlsuh mode"); + return FilamentMapMode::fmmAutoForFlush; + } + return FilamentMapMode(iter->second); +} + +static void set_prefered_map_mode(FilamentMapMode mode) +{ + const static std::vector enum_values = ConfigOptionEnum::get_enum_names(); + auto &app_config = wxGetApp().app_config; + std::string mode_str; + if (mode < enum_values.size()) mode_str = enum_values[mode]; + + if (mode_str.empty()) BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("Set empty prefered_filament_map_mode to app config"); + app_config->set("prefered_filament_map_mode", mode_str); +} + +static bool get_pop_up_remind_flag() +{ + auto &app_config = wxGetApp().app_config; + return app_config->get_bool("pop_up_filament_map_mode"); +} + +static void set_pop_up_remind_flag(bool remind) +{ + auto &app_config = wxGetApp().app_config; + app_config->set_bool("pop_up_filament_map_mode", remind); +} + +bool is_pop_up_required() +{ + FilamentMapMode mode = get_prefered_map_mode(); + bool is_manual_mode_ = FilamentMapMode::fmmManual == mode; + bool is_multi_extruder_ = is_multi_extruder(); + return is_multi_extruder_ && is_manual_mode_; +} + +FilamentGroupPopup::FilamentGroupPopup(wxWindow *parent) : PopupWindow(parent, wxBORDER_NONE) +{ + wxBoxSizer *top_sizer = new wxBoxSizer(wxVERTICAL); + const int horizontal_margin = FromDIP(16); + const int vertical_margin = FromDIP(15); + const int vertical_padding = FromDIP(12); + const int ratio_spacing = FromDIP(4); + + const wxColor background_color = wxColor(255, 255, 255); + SetBackgroundColour(background_color); + + radio_btns.resize(ButtonType::btCount); + button_labels.resize(ButtonType::btCount); + button_desps.resize(ButtonType::btCount); + detail_infos.resize(ButtonType::btCount); + std::vector btn_texts = {AutoForFlushLabel, AutoForMatchLabel, ManualLabel}; + std::vector btn_desps = {AutoForFlushDesp, AutoForMatchDesp, ManualDesp}; + std::vector mode_details = {AutoForFlushDetail, AutoForMatchDetail, ManualDetail}; + + top_sizer->AddSpacer(vertical_margin); + + auto checked_bmp = create_scaled_bitmap("map_mode_on", nullptr, 16); + auto unchecked_bmp = create_scaled_bitmap("map_mode_off", nullptr, 16); + + for (size_t idx = 0; idx < ButtonType::btCount; ++idx) { + wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL); + radio_btns[idx] = new wxBitmapButton(this, idx, unchecked_bmp, wxDefaultPosition, wxDefaultSize, wxNO_BORDER); + radio_btns[idx]->SetBackgroundColour(background_color); + + button_labels[idx] = new wxStaticText(this, wxID_ANY, btn_texts[idx]); + button_labels[idx]->SetBackgroundColour(background_color); + button_labels[idx]->SetForegroundColour(wxColor("#262E30")); + button_labels[idx]->SetFont(Label::Head_14); + + button_desps[idx] = new wxStaticText(this, wxID_ANY, btn_desps[idx]); + button_desps[idx]->SetBackgroundColour(background_color); + button_desps[idx]->SetForegroundColour(wxColor("#262E30")); + button_desps[idx]->SetFont(Label::Body_14); + + button_sizer->Add(radio_btns[idx], 0, wxALIGN_CENTER_VERTICAL); + button_sizer->AddSpacer(ratio_spacing); + button_sizer->Add(button_labels[idx], 0, wxALIGN_CENTER_VERTICAL); + button_sizer->Add(button_desps[idx], 0, wxALIGN_CENTER_VERTICAL); + + wxBoxSizer *label_sizer = new wxBoxSizer(wxHORIZONTAL); + + detail_infos[idx] = new wxStaticText(this, wxID_ANY, mode_details[idx]); + detail_infos[idx]->SetBackgroundColour(background_color); + detail_infos[idx]->SetForegroundColour(wxColor("#6B6B6B")); + detail_infos[idx]->SetFont(Label::Body_12); + detail_infos[idx]->Wrap(FromDIP(320)); + + label_sizer->AddSpacer(radio_btns[idx]->GetRect().width + ratio_spacing); + label_sizer->Add(detail_infos[idx], 1, wxEXPAND | wxALIGN_CENTER_VERTICAL); + + top_sizer->Add(button_sizer, 0, wxLEFT | wxRIGHT, horizontal_margin); + top_sizer->Add(label_sizer, 0, wxLEFT | wxRIGHT, horizontal_margin); + top_sizer->AddSpacer(vertical_padding); + + radio_btns[idx]->Bind(wxEVT_BUTTON, [this, idx](wxCommandEvent &event) { + event.SetInt(idx); + OnRadioBtn(event); + }); + + radio_btns[idx]->Bind(wxEVT_ENTER_WINDOW, [this, idx](wxMouseEvent &) { UpdateButtonStatus(idx); }); + + radio_btns[idx]->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent &) { UpdateButtonStatus(); }); + + button_labels[idx]->Bind(wxEVT_LEFT_UP, [this, idx](wxMouseEvent &) { + wxCommandEvent event; + event.SetInt(idx); + OnRadioBtn(event); + }); + + button_labels[idx]->Bind(wxEVT_ENTER_WINDOW, [this, idx](wxMouseEvent &) { UpdateButtonStatus(idx); }); + button_labels[idx]->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent &) { UpdateButtonStatus(); }); + } + + { + wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL); + + wiki_link = new wxStaticText(this, wxID_ANY, _L("More info on wiki")); + wiki_link->SetBackgroundColour(background_color); + wiki_link->SetForegroundColour(wxColor("#00AE42")); + wiki_link->SetFont(Label::Body_12.Underlined()); + wiki_link->SetCursor(wxCursor(wxCURSOR_HAND)); + wiki_link->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent &) { wxLaunchDefaultBrowser("http//:example.com"); }); + + remind_checkbox = new wxCheckBox(this, wxID_ANY, _L("Don't remind me again")); + remind_checkbox->SetBackgroundColour(background_color); + remind_checkbox->SetForegroundColour(wxColor("#6B6B6B")); + remind_checkbox->SetFont(Label::Body_12); + remind_checkbox->Bind(wxEVT_CHECKBOX, &FilamentGroupPopup::OnRemindBtn, this); + + button_sizer->Add(wiki_link, 0, wxLEFT, horizontal_margin); + button_sizer->AddStretchSpacer(); + button_sizer->Add(remind_checkbox, 0, wxRIGHT, horizontal_margin); + + top_sizer->Add(button_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, horizontal_margin); + } + + top_sizer->AddSpacer(vertical_margin); + SetSizerAndFit(top_sizer); + + m_mode = get_prefered_map_mode(); + m_timer = new wxTimer(this); + + GUI::wxGetApp().UpdateDarkUIWin(this); + + Bind(wxEVT_TIMER, &FilamentGroupPopup::OnTimer, this); + Bind(wxEVT_ENTER_WINDOW, &FilamentGroupPopup::OnEnterWindow, this); + Bind(wxEVT_LEAVE_WINDOW, &FilamentGroupPopup::OnLeaveWindow, this); +} + +void FilamentGroupPopup::DrawRoundedCorner(int radius) +{ +#ifdef __WIN32__ + HWND hwnd = GetHWND(); + if (hwnd) { + HRGN hrgn = CreateRoundRectRgn(0, 0, GetRect().GetWidth(), GetRect().GetHeight(), radius, radius); + SetWindowRgn(hwnd, hrgn, TRUE); + + SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); + SetLayeredWindowAttributes(hwnd, 0, 0, LWA_COLORKEY); + } +#else + wxClientDC dc(this); + wxGraphicsContext *gc = wxGraphicsContext::Create(dc); + if (gc) { + gc->SetBrush(*wxWHITE_BRUSH); + gc->SetPen(*wxTRANSPARENT_PEN); + wxRect rect(0, 0, GetSize().GetWidth(), GetSize().GetHeight()); + wxGraphicsPath path = wxGraphicsRenderer::GetDefaultRenderer()->CreatePath(); + path.AddRoundedRectangle(0, 0, rect.width, rect.height, radius); + gc->DrawPath(path); + delete gc; + } +#endif +} + +void FilamentGroupPopup::Init(bool connect_status) +{ + radio_btns[ButtonType::btForMatch]->Enable(connect_status); + button_labels[ButtonType::btForMatch]->Enable(connect_status); + + m_mode = get_prefered_map_mode(); + + wxCheckBoxState check_state = get_pop_up_remind_flag() ? wxCheckBoxState::wxCHK_UNCHECKED : wxCheckBoxState::wxCHK_CHECKED; + remind_checkbox->Set3StateValue(check_state); + + UpdateButtonStatus(); +} + +void FilamentGroupPopup::tryPopup(bool connect_status) +{ + auto canPopup = [this]() { + bool is_multi_extruder_ = is_multi_extruder(); + bool pop_up_flag = get_pop_up_remind_flag(); + return is_multi_extruder_ && pop_up_flag; + }; + + if (canPopup()) { + DrawRoundedCorner(16); + Init(connect_status); + ResetTimer(); + PopupWindow::Popup(); + } +} + +void FilamentGroupPopup::tryClose() { StartTimer(); } + +void FilamentGroupPopup::StartTimer() { m_timer->StartOnce(300); } + +void FilamentGroupPopup::ResetTimer() +{ + if (m_timer->IsRunning()) { m_timer->Stop(); } +} + +void FilamentGroupPopup::OnRadioBtn(wxCommandEvent &event) +{ + m_mode = mode_list.at(event.GetInt()); + + set_prefered_map_mode(m_mode); + + UpdateButtonStatus(m_mode); +} + +void FilamentGroupPopup::OnRemindBtn(wxCommandEvent &event) +{ + bool is_checked = remind_checkbox->IsChecked(); + set_pop_up_remind_flag(!is_checked); + + if (is_checked) { + MessageDialog dialog(nullptr, _L("No further pop up.You can go to \"Preferences\" to reopen the pop up."), _L("Tips"), wxICON_INFORMATION | wxOK); + dialog.ShowModal(); + Dismiss(); + } +} + +void FilamentGroupPopup::OnTimer(wxTimerEvent &event) { Dismiss(); } + +void FilamentGroupPopup::OnLeaveWindow(wxMouseEvent &) +{ + wxPoint pos = this->ScreenToClient(wxGetMousePosition()); + if (this->GetClientRect().Contains(pos)) return; + StartTimer(); +} + +void FilamentGroupPopup::OnEnterWindow(wxMouseEvent &) { ResetTimer(); } + +void FilamentGroupPopup::UpdateButtonStatus(int hover_idx) +{ + auto checked_bmp = create_scaled_bitmap("map_mode_on", nullptr, 16); + auto unchecked_bmp = create_scaled_bitmap("map_mode_off", nullptr, 16); + auto checked_hover_bmp = create_scaled_bitmap("map_mode_on_hovered", nullptr); + auto unchecked_hover_bmp = create_scaled_bitmap("map_mode_off_hovered", nullptr); + + for (int i = 0; i < ButtonType::btCount; ++i) { + // process checked and unchecked status + if (mode_list.at(i) == m_mode) { + if (i == hover_idx) + radio_btns[i]->SetBitmap(checked_hover_bmp); + else + radio_btns[i]->SetBitmap(checked_bmp); + button_labels[i]->SetFont(Label::Head_14); + } else { + if (i == hover_idx) + radio_btns[i]->SetBitmap(unchecked_hover_bmp); + else + radio_btns[i]->SetBitmap(unchecked_bmp); + button_labels[i]->SetFont(Label::Body_14); + } + } + + if (m_mode == FilamentMapMode::fmmAutoForMatch) + remind_checkbox->Enable(false); + else + remind_checkbox->Enable(true); +} + +}} // namespace Slic3r::GUI \ No newline at end of file diff --git a/src/slic3r/GUI/FilamentGroupPopup.hpp b/src/slic3r/GUI/FilamentGroupPopup.hpp new file mode 100644 index 000000000..6486b2c32 --- /dev/null +++ b/src/slic3r/GUI/FilamentGroupPopup.hpp @@ -0,0 +1,54 @@ +#ifndef FILAMENT_GROUP_HOVER_HPP +#define FILAMENT_GROUP_HOVER_HPP + +#include +#include +#include "wxExtensions.hpp" +#include "Widgets/PopupWindow.hpp" + +namespace Slic3r { namespace GUI { + +bool is_pop_up_required(); +FilamentMapMode get_prefered_map_mode(); + +class FilamentGroupPopup : public PopupWindow +{ +public: + FilamentGroupPopup(wxWindow *parent); + void tryPopup(bool connect_status); + void tryClose(); + + FilamentMapMode GetSelectedMode() const { return m_mode; } + +private: + void StartTimer(); + void ResetTimer(); + + void OnRadioBtn(wxCommandEvent &event); + void OnLeaveWindow(wxMouseEvent &); + void OnEnterWindow(wxMouseEvent &); + void OnTimer(wxTimerEvent &event); + void OnRemindBtn(wxCommandEvent &event); + + void Init(bool connect_status); + void UpdateButtonStatus(int hover_idx = -1); + void DrawRoundedCorner(int radius); + +private: + enum ButtonType { btForFlush, btForMatch, btManual, btCount }; + + const std::vector mode_list = {fmmAutoForFlush, fmmAutoForMatch, fmmManual}; + + FilamentMapMode m_mode; + wxTimer *m_timer; + + std::vector radio_btns; + std::vector button_labels; + std::vector button_desps; + std::vector detail_infos; + + wxStaticText *wiki_link; + wxCheckBox *remind_checkbox; +}; +}} // namespace Slic3r::GUI +#endif \ No newline at end of file diff --git a/src/slic3r/GUI/FilamentMapDialog.cpp b/src/slic3r/GUI/FilamentMapDialog.cpp index 2ee92c966..af5a8ebe8 100644 --- a/src/slic3r/GUI/FilamentMapDialog.cpp +++ b/src/slic3r/GUI/FilamentMapDialog.cpp @@ -3,210 +3,118 @@ #include "Widgets/Button.hpp" #include "Widgets/SwitchButton.hpp" #include "I18N.hpp" +#include "GUI_App.hpp" +#include "CapsuleButton.hpp" +#include "SelectMachine.hpp" namespace Slic3r { namespace GUI { -const wxString manual_tips = _L("we will slice according to this grouping method:"); - -const wxString manual_below_tips = _L("Tips:\n" - "You can drag the filaments to change which extruder they are assigned to.\n" - "But your filament arrangement may not be the most filament-efficient."); - -const wxString auto_tips = _L("Automatic filament grouping will be performed to reduce flushing consumption\n" - "and filament changes during the slicing process.\n" - "The recommended results will be displayed below after slicing:"); - -const wxString auto_tips_with_result = _L("Automatic filament grouping will be performed to reduce flushing consumption\n" - "and filament changes during the slicing process.\n" - "The recommended results are shown below:"); - -wxColour hex_to_color(const std::string &hex) -{ - if ((hex.length() != 7 && hex.length() != 9) || hex[0] != '#') { - throw std::invalid_argument("Invalid hex color format"); - } - - unsigned int r, g, b, a = 255; - std::stringstream ss; - - // r - ss << std::hex << hex.substr(1, 2); - ss >> r; - ss.clear(); - ss.str(""); - - // g - ss << std::hex << hex.substr(3, 2); - ss >> g; - ss.clear(); - ss.str(""); - - // b - ss << std::hex << hex.substr(5, 2); - ss >> b; - - // a - if (hex.length() == 9) { - ss.clear(); - ss.str(""); - ss << std::hex << hex.substr(7, 2); - ss >> a; - } - - return wxColour(r, g, b, a); -} - -FilamentMapDialog::FilamentMapDialog(wxWindow *parent, - const DynamicPrintConfig *config, - const std::vector &filament_map, - const std::vector &extruders, - bool is_auto, - bool has_auto_result -) +FilamentMapDialog::FilamentMapDialog(wxWindow *parent, + const std::vector &filament_color, + const std::vector &filament_map, + const std::vector &filaments, + const FilamentMapMode mode, + bool show_default) : wxDialog(parent, wxID_ANY, _L("Filament arrangement method of plate"), wxDefaultPosition, wxSize(2000, 1500)) - , m_config(config) + , m_filament_color(filament_color) , m_filament_map(filament_map) - , m_has_auto_result(has_auto_result) { SetBackgroundColour(*wxWHITE); + SetMinSize(wxSize(FromDIP(550), -1)); + SetMaxSize(wxSize(FromDIP(550), -1)); + + if (mode < fmmManual) + m_page_type = PageType::ptAuto; + else if (mode == fmmManual) + m_page_type = PageType::ptManual; + else + m_page_type = PageType::ptDefault; + wxBoxSizer *main_sizer = new wxBoxSizer(wxVERTICAL); + main_sizer->AddSpacer(FromDIP(22)); - m_mode_switch_btn = new SwitchButton(this); - m_mode_switch_btn->SetMaxSize({em_unit(this) * 12, -1}); - m_mode_switch_btn->SetLabels(_L("Customize"), _L("Auto")); - m_mode_switch_btn->Bind(wxEVT_TOGGLEBUTTON, &FilamentMapDialog::on_switch_mode, this); - m_mode_switch_btn->SetValue(is_auto); - main_sizer->Add(m_mode_switch_btn, 0, wxCENTER | wxALL, 10); + wxBoxSizer *mode_sizer = new wxBoxSizer(wxHORIZONTAL); - m_tip_text = new wxStaticText(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); - main_sizer->Add(m_tip_text, 0, wxALIGN_LEFT | wxLEFT, 15); + m_auto_btn = new CapsuleButton(this, PageType::ptAuto, _L("Auto"), false); + m_manual_btn = new CapsuleButton(this, PageType::ptManual, _L("Custom"), false); + if (show_default) + m_default_btn = new CapsuleButton(this, PageType::ptDefault, _L("Default"), true); + else + m_default_btn = nullptr; - m_extruder_panel_sizer = new wxBoxSizer(wxHORIZONTAL); + const int button_padding = FromDIP(2); + mode_sizer->AddStretchSpacer(); + mode_sizer->Add(m_auto_btn, 1, wxALIGN_CENTER | wxLEFT | wxRIGHT, button_padding); + mode_sizer->Add(m_manual_btn, 1, wxALIGN_CENTER | wxLEFT | wxRIGHT, button_padding); + if (show_default) mode_sizer->Add(m_default_btn, 1, wxALIGN_CENTER | wxLEFT | wxRIGHT, button_padding); + mode_sizer->AddStretchSpacer(); - m_manual_left_panel = new DragDropPanel(this, wxT("Left nozzle:"), false); - m_manual_right_panel = new DragDropPanel(this, wxT("Right nozzle:"), false); + main_sizer->Add(mode_sizer, 0, wxEXPAND); + main_sizer->AddSpacer(FromDIP(24)); - std::vector filament_color = config->option("filament_colour")->values; - for (size_t i = 0; i < filament_map.size(); ++i) { - auto iter = std::find(extruders.begin(), extruders.end(), i + 1); - if (iter == extruders.end()) - continue; + auto panel_sizer = new wxBoxSizer(wxHORIZONTAL); + FilamentMapMode default_auto_mode = (mode < FilamentMapMode::fmmManual ? mode : FilamentMapMode::fmmAutoForFlush); + m_manual_map_panel = new FilamentMapManualPanel(this, m_filament_color, filaments, filament_map); + m_auto_map_panel = new FilamentMapAutoPanel(this, default_auto_mode); + if (show_default) + m_default_map_panel = new FilamentMapDefaultPanel(this); + else + m_default_map_panel = nullptr; - if (filament_map[i] == 1) { - m_manual_left_panel->AddColorBlock(hex_to_color(filament_color[i]), i + 1); - } - else if (filament_map[i] == 2) { - m_manual_right_panel->AddColorBlock(hex_to_color(filament_color[i]), i + 1); - } - else { - assert(false); - } - } + panel_sizer->Add(m_manual_map_panel, 0, wxALIGN_CENTER | wxEXPAND); + panel_sizer->Add(m_auto_map_panel, 0, wxALIGN_CENTER | wxEXPAND); + if (show_default) panel_sizer->Add(m_default_map_panel, 0, wxALIGN_CENTER | wxEXPAND); + main_sizer->Add(panel_sizer, 0, wxEXPAND); - m_switch_filament_btn = new ScalableButton(this, wxID_ANY, "switch_filament_maps"); - m_switch_filament_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_switch_filaments, this); - m_switch_filament_btn->SetCanFocus(false); - // just for placeholder for auto - m_switch_filament_btn_auto = new ScalableButton(this, wxID_ANY, "switch_filament_maps"); - m_switch_filament_btn_auto->Enable(false); - - m_extruder_panel_sizer->Add(m_manual_left_panel, 1, wxEXPAND | wxALL, 5); - m_extruder_panel_sizer->Add(m_switch_filament_btn, 0, wxALIGN_CENTER_VERTICAL | wxALL, 1); - m_extruder_panel_sizer->Add(m_manual_right_panel, 1, wxEXPAND | wxALL, 5); - m_manual_left_panel->Layout(); - m_manual_left_panel->Fit(); - m_manual_right_panel->Layout(); - m_manual_right_panel->Fit(); - - m_auto_left_panel = new DragDropPanel(this, wxT("Left nozzle:"), true); - m_auto_right_panel = new DragDropPanel(this, wxT("Right nozzle:"), true); - - for (size_t i = 0; i < filament_map.size(); ++i) { - auto iter = std::find(extruders.begin(), extruders.end(), i + 1); - if (iter == extruders.end()) continue; - - if (filament_map[i] == 1) { - m_auto_left_panel->AddColorBlock(hex_to_color(filament_color[i]), i + 1); - } else if (filament_map[i] == 2) { - m_auto_right_panel->AddColorBlock(hex_to_color(filament_color[i]), i + 1); - } else { - assert(false); - } - } - - m_extruder_panel_sizer->Add(m_auto_left_panel, 1, wxEXPAND | wxALL, 5); - m_extruder_panel_sizer->Add(m_switch_filament_btn_auto, 0, wxALIGN_CENTER_VERTICAL | wxALL, 1); - m_extruder_panel_sizer->Add(m_auto_right_panel, 1, wxEXPAND | wxALL, 5); - m_auto_left_panel->Layout(); - m_auto_left_panel->Fit(); - m_auto_right_panel->Layout(); - m_auto_right_panel->Fit(); - - main_sizer->Add(m_extruder_panel_sizer, 1, wxEXPAND | wxALL, 10); - - m_below_tip_text = new wxStaticText(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); - m_below_tip_text->SetLabel(manual_below_tips); - main_sizer->Add(m_below_tip_text, 0, wxALIGN_LEFT | wxLEFT, 15); - - if (is_auto) { - m_manual_left_panel->Hide(); - m_manual_right_panel->Hide(); - m_switch_filament_btn->Hide(); - m_below_tip_text->Hide(); - if (m_has_auto_result) { - m_tip_text->SetLabel(auto_tips_with_result); - } - else { - m_auto_left_panel->Hide(); - m_auto_right_panel->Hide(); - m_switch_filament_btn_auto->Hide(); - m_tip_text->SetLabel(auto_tips); - } - } - else { - m_auto_left_panel->Hide(); - m_auto_right_panel->Hide(); - m_switch_filament_btn_auto->Hide(); - m_tip_text->SetLabel(manual_tips); - m_below_tip_text->Show(); - } - - wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL); - Button * ok_btn = new Button(this, _L("OK")); - Button * cancel_btn = new Button(this, _L("Cancel")); - button_sizer->Add(ok_btn, 0, wxALL, 5); - button_sizer->Add(cancel_btn, 0, wxALL, 5); + wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL); + m_ok_btn = new Button(this, _L("OK")); + m_cancel_btn = new Button(this, _L("Cancel")); + button_sizer->Add(m_ok_btn, 0, wxALL, 5); + button_sizer->Add(m_cancel_btn, 0, wxALL, 5); main_sizer->Add(button_sizer, 0, wxALIGN_CENTER | wxALL, 10); - ok_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_ok, this); - cancel_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_cancle, this); + m_ok_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_ok, this); + m_cancel_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_cancle, this); + + m_auto_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_switch_mode, this); + m_manual_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_switch_mode, this); + if (show_default) m_default_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_switch_mode, this); SetSizer(main_sizer); Layout(); Fit(); CenterOnParent(); + GUI::wxGetApp().UpdateDarkUIWin(this); } -bool FilamentMapDialog::is_auto() const +FilamentMapMode FilamentMapDialog::get_mode() { - if (m_mode_switch_btn->GetValue()) { - return true; - } - return false; + if (m_page_type == PageType::ptAuto) + return m_auto_map_panel->GetMode(); + if (m_page_type == PageType::ptManual) + return fmmManual; + return fmmDefault; +} + +int FilamentMapDialog::ShowModal() +{ + update_panel_status(m_page_type); + return wxDialog::ShowModal(); } void FilamentMapDialog::on_ok(wxCommandEvent &event) { - if (!is_auto()) { - std::vector left_filaments = m_manual_left_panel->GetAllFilaments(); - std::vector right_filaments = m_manual_right_panel->GetAllFilaments(); + if (m_page_type == PageType::ptManual) { + std::vector left_filaments = m_manual_map_panel->GetLeftFilaments(); + std::vector right_filaments = m_manual_map_panel->GetRightFilaments(); for (int i = 0; i < m_filament_map.size(); ++i) { if (std::find(left_filaments.begin(), left_filaments.end(), i + 1) != left_filaments.end()) { m_filament_map[i] = 1; - } else if (std::find(right_filaments.begin(), right_filaments.end(), i + 1) != right_filaments.end()) { + } + else if (std::find(right_filaments.begin(), right_filaments.end(), i + 1) != right_filaments.end()) { m_filament_map[i] = 2; } } @@ -215,63 +123,62 @@ void FilamentMapDialog::on_ok(wxCommandEvent &event) EndModal(wxID_OK); } -void FilamentMapDialog::on_cancle(wxCommandEvent &event) +void FilamentMapDialog::on_cancle(wxCommandEvent &event) { EndModal(wxID_CANCEL); } + +void FilamentMapDialog::update_panel_status(PageType page) { - EndModal(wxID_CANCEL); + if (page == PageType::ptDefault) { + if (m_default_btn && m_default_map_panel) { + m_default_btn->Select(true); + m_default_map_panel->Show(); + } + + m_manual_btn->Select(false); + m_manual_map_panel->Hide(); + + m_auto_btn->Select(false); + m_auto_map_panel->Hide(); + } + if (page == PageType::ptManual) { + if (m_default_btn && m_default_map_panel) { + m_default_btn->Select(false); + m_default_map_panel->Hide(); + } + m_manual_btn->Select(true); + m_manual_map_panel->Show(); + + m_auto_btn->Select(false); + m_auto_map_panel->Hide(); + } + if (page == PageType::ptAuto) { + if (m_default_btn && m_default_map_panel) { + m_default_btn->Select(false); + m_default_map_panel->Hide(); + } + m_manual_btn->Select(false); + m_manual_map_panel->Hide(); + + m_auto_btn->Select(true); + m_auto_map_panel->Show(); + } + Layout(); + Fit(); } void FilamentMapDialog::on_switch_mode(wxCommandEvent &event) { - bool value = dynamic_cast(event.GetEventObject())->GetValue(); - if (value) { // auto - m_manual_left_panel->Hide(); - m_manual_right_panel->Hide(); - m_switch_filament_btn->Hide(); - m_below_tip_text->Hide(); - if (m_has_auto_result) { - m_auto_left_panel->Show(); - m_auto_right_panel->Show(); - m_switch_filament_btn_auto->Show(); - m_tip_text->SetLabel(auto_tips_with_result); - } - else { - m_auto_left_panel->Hide(); - m_auto_right_panel->Hide(); - m_switch_filament_btn_auto->Hide(); - m_tip_text->SetLabel(auto_tips); - } - } else { // manual - m_manual_left_panel->Show(); - m_manual_right_panel->Show(); - m_switch_filament_btn->Show(); - m_below_tip_text->Show(); + int win_id = event.GetId(); + m_page_type = PageType(win_id); - m_auto_left_panel->Hide(); - m_auto_right_panel->Hide(); - m_switch_filament_btn_auto->Hide(); - - m_tip_text->SetLabel(manual_tips); - } - Layout(); - Fit(); + update_panel_status(m_page_type); event.Skip(); } -void FilamentMapDialog::on_switch_filaments(wxCommandEvent &event) +void FilamentMapDialog::set_modal_btn_labels(const wxString &ok_label, const wxString &cancel_label) { - std::vector left_blocks = m_manual_left_panel->get_filament_blocks(); - std::vector right_blocks = m_manual_right_panel->get_filament_blocks(); - - for (ColorPanel* block : left_blocks) { - m_manual_right_panel->AddColorBlock(block->GetColor(), block->GetFilamentId(), false); - m_manual_left_panel->RemoveColorBlock(block, false); - } - for (auto block : right_blocks) { - m_manual_left_panel->AddColorBlock(block->GetColor(), block->GetFilamentId(), false); - m_manual_right_panel->RemoveColorBlock(block, false); - } - Layout(); - Fit(); + m_ok_btn->SetLabel(ok_label); + m_cancel_btn->SetLabel(cancel_label); } + }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/FilamentMapDialog.hpp b/src/slic3r/GUI/FilamentMapDialog.hpp index d1f883fa4..abdc19f17 100644 --- a/src/slic3r/GUI/FilamentMapDialog.hpp +++ b/src/slic3r/GUI/FilamentMapDialog.hpp @@ -2,10 +2,13 @@ #define slic3r_FilamentMapDialog_hpp_ #include "GUI.hpp" +#include "FilamentMapPanel.hpp" #include #include #include #include +#include "SelectMachine.hpp" +#include "CapsuleButton.hpp" class SwitchButton; class ScalableButton; @@ -17,42 +20,52 @@ class DynamicPrintConfig; namespace GUI { class DragDropPanel; + class FilamentMapDialog : public wxDialog { + enum PageType { + ptAuto, + ptManual, + ptDefault + }; public: FilamentMapDialog(wxWindow *parent, - const DynamicPrintConfig *config, + const std::vector& filament_color, const std::vector &filament_map, - const std::vector &extruders, - bool is_auto, - bool has_auto_result + const std::vector &filaments, + const FilamentMapMode mode, + bool show_default=true ); - bool is_auto() const; + FilamentMapMode get_mode(); const std::vector& get_filament_maps() const { return m_filament_map; } + int ShowModal(); + void set_modal_btn_labels(const wxString& left_label, const wxString& right_label); private: void on_ok(wxCommandEvent &event); void on_cancle(wxCommandEvent &event); void on_switch_mode(wxCommandEvent &event); - void on_switch_filaments(wxCommandEvent &event); + + void update_panel_status(PageType page); + + private: + FilamentMapManualPanel* m_manual_map_panel; + FilamentMapAutoPanel* m_auto_map_panel; + FilamentMapDefaultPanel* m_default_map_panel; + + CapsuleButton* m_auto_btn; + CapsuleButton* m_manual_btn; + CapsuleButton* m_default_btn; + + Button* m_ok_btn; + Button* m_cancel_btn; + + PageType m_page_type; private: - wxStaticText * m_tip_text; - wxStaticText * m_below_tip_text; - SwitchButton * m_mode_switch_btn; - wxBoxSizer * m_extruder_panel_sizer; - DragDropPanel* m_manual_left_panel; - DragDropPanel* m_manual_right_panel; - DragDropPanel* m_auto_left_panel; - DragDropPanel* m_auto_right_panel; - ScalableButton* m_switch_filament_btn; - ScalableButton* m_switch_filament_btn_auto; // for placeholder - -private: - const DynamicPrintConfig* m_config; std::vector m_filament_map; - bool m_has_auto_result; + std::vector m_filament_color; }; }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/FilamentMapPanel.cpp b/src/slic3r/GUI/FilamentMapPanel.cpp new file mode 100644 index 000000000..2f150efeb --- /dev/null +++ b/src/slic3r/GUI/FilamentMapPanel.cpp @@ -0,0 +1,324 @@ +#include "FilamentMapPanel.hpp" +#include "GUI_App.hpp" +#include "wx/graphics.h" + +namespace Slic3r { namespace GUI { +FilamentMapManualPanel::FilamentMapManualPanel(wxWindow *parent, + const std::vector &color, + const std::vector &filament_list, + const std::vector &filament_map) + : wxPanel(parent), m_filament_map(filament_map), m_filament_color(color), m_filament_list(filament_list) +{ + SetBackgroundColour(wxColor(255, 255, 255)); + + auto top_sizer = new wxBoxSizer(wxVERTICAL); + + m_description = new Label(this, _L("We will slice according to this grouping method:")); + top_sizer->Add(m_description, 0, wxALIGN_LEFT | wxLEFT, FromDIP(15)); + top_sizer->AddSpacer(FromDIP(8)); + + auto drag_sizer = new wxBoxSizer(wxHORIZONTAL); + + m_left_panel = new DragDropPanel(this, wxT("Left Nozzle:"), false); + m_right_panel = new DragDropPanel(this, wxT("Right Nozzle:"), false); + m_switch_btn = new ScalableButton(this, wxID_ANY, "switch_filament_maps"); + + for (size_t idx = 0; idx < m_filament_map.size(); ++idx) { + auto iter = std::find(m_filament_list.begin(), m_filament_list.end(), idx + 1); + if (iter == m_filament_list.end()) continue; + wxColor color = Hex2Color(m_filament_color[idx]); + if (m_filament_map[idx] == 1) { + m_left_panel->AddColorBlock(color, idx + 1); + } else { + assert(m_filament_map[idx] == 2); + m_right_panel->AddColorBlock(color, idx + 1); + } + } + drag_sizer->Add(m_left_panel, 1, wxALIGN_CENTER | wxEXPAND | wxLEFT, FromDIP(20)); + drag_sizer->AddSpacer(FromDIP(7)); + drag_sizer->Add(m_switch_btn, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, FromDIP(1)); + drag_sizer->AddSpacer(FromDIP(7)); + drag_sizer->Add(m_right_panel, 1, wxALIGN_CENTER | wxEXPAND | wxRIGHT, FromDIP(20)); + + top_sizer->Add(drag_sizer, 0, wxALIGN_CENTER|wxEXPAND); + + m_tips = new Label(this, _L("Tips: You can drag the filaments to change which extruder they are assigned to.\n" + "But your filament arrangement may not be the most filament-efficient.")); + m_tips->SetFont(Label::Body_14); + m_tips->SetForegroundColour(wxColour("#6B6B6B")); + top_sizer->AddSpacer(FromDIP(8)); + top_sizer->Add(m_tips, 0, wxALIGN_LEFT | wxLEFT, FromDIP(15)); + + m_switch_btn->Bind(wxEVT_BUTTON, &FilamentMapManualPanel::OnSwitchFilament, this); + + SetSizer(top_sizer); + Layout(); + Fit(); + GUI::wxGetApp().UpdateDarkUIWin(this); +} + +void FilamentMapManualPanel::OnSwitchFilament(wxCommandEvent &) +{ + auto left_blocks = m_left_panel->get_filament_blocks(); + auto right_blocks = m_right_panel->get_filament_blocks(); + + for (auto &block : left_blocks) { + m_right_panel->AddColorBlock(block->GetColor(), block->GetFilamentId(), false); + m_left_panel->RemoveColorBlock(block, false); + } + + for (auto &block : right_blocks) { + m_left_panel->AddColorBlock(block->GetColor(), block->GetFilamentId(), false); + m_right_panel->RemoveColorBlock(block, false); + } + + Layout(); + Fit(); +} + +void FilamentMapManualPanel::Hide() +{ + m_left_panel->Hide(); + m_right_panel->Hide(); + m_switch_btn->Hide(); + wxPanel::Hide(); +} + +void FilamentMapManualPanel::Show() +{ + m_left_panel->Show(); + m_right_panel->Show(); + m_switch_btn->Show(); + wxPanel::Show(); +} + +GUI::FilamentMapBtnPanel::FilamentMapBtnPanel(wxWindow *parent, const wxString &label, const wxString &detail, const std::string &icon) : wxPanel(parent) +{ + SetBackgroundColour(*wxWHITE); + SetBackgroundStyle(wxBG_STYLE_PAINT); + m_hover = false; + + const int horizontal_margin = FromDIP(12); + + auto sizer = new wxBoxSizer(wxVERTICAL); + + auto bmp = create_scaled_bitmap(icon, nullptr, 20); + m_btn = new wxBitmapButton(this, wxID_ANY, bmp, wxDefaultPosition, wxDefaultSize, wxNO_BORDER); + m_btn->SetBackgroundColour(*wxWHITE); + + m_label = new wxStaticText(this, wxID_ANY, label); + m_label->SetFont(Label::Head_14); + + auto label_sizer = new wxBoxSizer(wxHORIZONTAL); + label_sizer->AddStretchSpacer(); + label_sizer->Add(m_btn, 0, wxALIGN_CENTER|wxEXPAND); + label_sizer->Add(m_label, 0, wxALIGN_CENTER|wxEXPAND); + label_sizer->AddStretchSpacer(); + + sizer->AddSpacer(FromDIP(32)); + sizer->Add(label_sizer, 0, wxALIGN_CENTER | wxEXPAND); + sizer->AddSpacer(FromDIP(24)); + + auto detail_sizer = new wxBoxSizer(wxHORIZONTAL); + m_detail = new Label(this, detail); + m_detail->SetFont(Label::Body_12); + m_detail->SetForegroundColour(wxColour("#6B6B6B")); + m_detail->Wrap(FromDIP(180)); + + detail_sizer->AddStretchSpacer(); + detail_sizer->Add(m_detail, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, horizontal_margin); + detail_sizer->AddStretchSpacer(); + + sizer->Add(detail_sizer, 0, wxALIGN_CENTER | wxEXPAND); + sizer->AddSpacer(FromDIP(10)); + + SetSizer(sizer); + Layout(); + Fit(); + + GUI::wxGetApp().UpdateDarkUIWin(this); + + auto forward_click_to_parent = [this](wxMouseEvent &event) { + wxCommandEvent click_event(wxEVT_LEFT_DOWN, GetId()); + click_event.SetEventObject(this); + this->ProcessEvent(click_event); + }; + + m_btn->Bind(wxEVT_LEFT_DOWN, forward_click_to_parent); + m_label->Bind(wxEVT_LEFT_DOWN, forward_click_to_parent); + m_detail->Bind(wxEVT_LEFT_DOWN, forward_click_to_parent); + + Bind(wxEVT_PAINT, &FilamentMapBtnPanel::OnPaint, this); + Bind(wxEVT_ENTER_WINDOW, &FilamentMapBtnPanel::OnEnterWindow, this); + Bind(wxEVT_LEAVE_WINDOW, &FilamentMapBtnPanel::OnLeaveWindow, this); +} + +void FilamentMapBtnPanel::OnPaint(wxPaintEvent &event) +{ + wxAutoBufferedPaintDC dc(this); + wxGraphicsContext *gc = wxGraphicsContext::Create(dc); + + if (gc) { + dc.Clear(); + wxRect rect = GetClientRect(); + gc->SetBrush(wxTransparentColour); + gc->DrawRoundedRectangle(0, 0, rect.width, rect.height, 0); + wxColour bg_color = m_selected ? wxColour("#EBF9F0") : wxColour("#FFFFFF"); + wxColour border_color = m_hover || m_selected ? wxColour("#00AE42") : wxColour("#CECECE"); + int cornerRadius = 8; + gc->SetBrush(wxBrush(bg_color)); + gc->SetPen(wxPen(border_color, 2)); + gc->DrawRoundedRectangle(1, 1, rect.width - 2, rect.height - 2, cornerRadius); + delete gc; + } +} + +void FilamentMapBtnPanel::UpdateStatus() +{ + const wxColour selected_color = wxColour("#EBF9F0"); + const wxColour normal_color = wxColour("#FFFFFF"); + if (m_selected) { + m_btn->SetBackgroundColour(selected_color); + m_label->SetBackgroundColour(selected_color); + m_detail->SetBackgroundColour(selected_color); + } else { + m_btn->SetBackgroundColour(normal_color); + m_label->SetBackgroundColour(normal_color); + m_detail->SetBackgroundColour(normal_color); + } +} + +void FilamentMapBtnPanel::OnEnterWindow(wxMouseEvent &event) +{ + if (!m_hover) { + m_hover = true; + UpdateStatus(); + Refresh(); + event.Skip(); + } +} + +void FilamentMapBtnPanel::OnLeaveWindow(wxMouseEvent &event) +{ + if (m_hover) { + wxPoint pos = this->ScreenToClient(wxGetMousePosition()); + if (this->GetClientRect().Contains(pos)) return; + m_hover = false; + UpdateStatus(); + Refresh(); + event.Skip(); + } +} + +void FilamentMapBtnPanel::Select(bool selected) +{ + m_selected = selected; + UpdateStatus(); + Refresh(); +} + +void GUI::FilamentMapBtnPanel::Hide() +{ + m_btn->Hide(); + m_label->Hide(); + m_detail->Hide(); + wxPanel::Hide(); +} +void GUI::FilamentMapBtnPanel::Show() +{ + m_btn->Show(); + m_label->Show(); + m_detail->Show(); + wxPanel::Show(); +} + +FilamentMapAutoPanel::FilamentMapAutoPanel(wxWindow *parent, FilamentMapMode mode) : wxPanel(parent) +{ + static const wxString AutoForFlushDetail = _L("Disregrad the filaments in AMS. Optimize filament usage " + "by calculating the best allocation for the left and right " + "nozzles. Arrange the filaments according on the printer according to " + "the slicing results."); + static const wxString AutoForMatchDetail = _L("Based on the current filaments in the AMS, allocate the " + "filaments to the left and right nozzles."); + auto sizer = new wxBoxSizer(wxHORIZONTAL); + m_flush_panel = new FilamentMapBtnPanel(this, _L("Material-Saving Mode"), AutoForFlushDetail, "flush_mode_panel_icon"); + m_match_panel = new FilamentMapBtnPanel(this, _L("Convenient Mode"), AutoForMatchDetail,"match_mode_panel_icon"); + + sizer->AddStretchSpacer(); + sizer->Add(m_flush_panel, 1, wxEXPAND); + sizer->AddSpacer(FromDIP(12)); + sizer->Add(m_match_panel, 1, wxEXPAND); + sizer->AddStretchSpacer(); + + m_flush_panel->Bind(wxEVT_LEFT_DOWN, [this](auto &event) { this->OnModeSwitch(FilamentMapMode::fmmAutoForFlush); }); + + m_match_panel->Bind(wxEVT_LEFT_DOWN, [this](auto &event) { this->OnModeSwitch(FilamentMapMode::fmmAutoForMatch); }); + + m_mode = mode; + UpdateStatus(); + + SetSizerAndFit(sizer); + Layout(); + GUI::wxGetApp().UpdateDarkUIWin(this); +} +void FilamentMapAutoPanel::Hide() +{ + m_flush_panel->Hide(); + m_match_panel->Hide(); + wxPanel::Hide(); +} + +void FilamentMapAutoPanel::Show() +{ + m_flush_panel->Show(); + m_match_panel->Show(); + wxPanel::Show(); +} + +void FilamentMapAutoPanel::UpdateStatus() +{ + if (m_mode == fmmAutoForFlush) { + m_flush_panel->Select(true); + m_match_panel->Select(false); + } else { + m_flush_panel->Select(false); + m_match_panel->Select(true); + } +} + +void FilamentMapAutoPanel::OnModeSwitch(FilamentMapMode mode) +{ + m_mode = mode; + UpdateStatus(); +} + +FilamentMapDefaultPanel::FilamentMapDefaultPanel(wxWindow *parent) : wxPanel(parent) +{ + auto sizer = new wxBoxSizer(wxHORIZONTAL); + + m_label = new Label(this, _L("The material allocation for the current disk follows the global settings.")); + m_label->SetFont(Label::Body_14); + m_label->SetBackgroundColour(*wxWHITE); + + sizer->AddStretchSpacer(); + sizer->Add(m_label, 1, wxEXPAND|wxALIGN_CENTER); + sizer->AddStretchSpacer(); + + SetSizerAndFit(sizer); + Layout(); + GUI::wxGetApp().UpdateDarkUIWin(this); +} + +void FilamentMapDefaultPanel::Hide() +{ + m_label->Hide(); + wxPanel::Hide(); +} + +void FilamentMapDefaultPanel::Show() +{ + m_label->Show(); + wxPanel::Show(); +} + +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/FilamentMapPanel.hpp b/src/slic3r/GUI/FilamentMapPanel.hpp new file mode 100644 index 000000000..8f7826013 --- /dev/null +++ b/src/slic3r/GUI/FilamentMapPanel.hpp @@ -0,0 +1,89 @@ + +#ifndef FILAMENT_MAP_PANEL_HPP +#define FILAMENT_MAP_PANEL_HPP + +#include "GUI.hpp" +#include "DragDropPanel.hpp" +#include "Widgets/SwitchButton.hpp" + +namespace Slic3r { namespace GUI { + +class FilamentMapManualPanel : public wxPanel +{ +public: + FilamentMapManualPanel(wxWindow *parent, const std::vector &color, const std::vector &filament_list, const std::vector &filament_map); + + std::vector GetFilamentMaps() const { return m_filament_map; } + std::vector GetLeftFilaments() const { return m_left_panel->GetAllFilaments(); } + std::vector GetRightFilaments() const { return m_right_panel->GetAllFilaments(); } + + void Hide(); + void Show(); + +private: + void OnSwitchFilament(wxCommandEvent &); + DragDropPanel *m_left_panel; + DragDropPanel *m_right_panel; + + Label *m_description; + Label *m_tips; + + ScalableButton *m_switch_btn; + + std::vector m_filament_map; + std::vector m_filament_list; + std::vector m_filament_color; +}; + +class FilamentMapBtnPanel : public wxPanel +{ +public: + FilamentMapBtnPanel(wxWindow *parent, const wxString &label, const wxString &detail, const std::string &icon_path); + void Hide(); + void Show(); + void Select(bool selected); +protected: + void OnPaint(wxPaintEvent &event); +private: + void OnEnterWindow(wxMouseEvent &event); + void OnLeaveWindow(wxMouseEvent &evnet); + + void UpdateStatus(); + + wxBitmapButton *m_btn; + wxStaticText *m_label; + Label *m_detail; + bool m_hover{false}; + bool m_selected{false}; +}; + +class FilamentMapAutoPanel : public wxPanel +{ +public: + FilamentMapAutoPanel(wxWindow *parent, FilamentMapMode mode); + void Hide(); + void Show(); + FilamentMapMode GetMode() const { return m_mode; } + +private: + void OnModeSwitch(FilamentMapMode mode); + void UpdateStatus(); + + FilamentMapBtnPanel *m_flush_panel; + FilamentMapBtnPanel *m_match_panel; + FilamentMapMode m_mode; +}; + +class FilamentMapDefaultPanel : public wxPanel +{ +public: + FilamentMapDefaultPanel(wxWindow *parent); + void Hide(); + void Show(); + +private: + Label *m_label; +}; +}} // namespace Slic3r::GUI + +#endif \ No newline at end of file diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 7b87b957b..0269191f1 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -4626,7 +4626,7 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding) Plater *plater = wxGetApp().plater(); wxCommandEvent evt(EVT_OPEN_FILAMENT_MAP_SETTINGS_DIALOG); evt.SetEventObject(plater); - evt.SetInt(0b0010); //0010 means from gcode view, manual mode + evt.SetInt(1); // 1 means from gcode viewer wxPostEvent(plater, evt); } } diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 8c7afd289..32b3fb186 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -60,6 +60,7 @@ #include "ConfigWizard.hpp" #include "Widgets/WebView.hpp" #include "DailyTips.hpp" +#include "FilamentMapDialog.hpp" #ifdef _WIN32 #include @@ -1593,6 +1594,8 @@ wxBoxSizer* MainFrame::create_side_tools() sizer->Layout(); + m_filament_group_popup = new FilamentGroupPopup(m_slice_btn); + m_slice_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) { m_plater->reset_check_status(); @@ -1602,14 +1605,62 @@ wxBoxSizer* MainFrame::create_side_tools() //this->m_plater->select_view_3D("Preview"); m_plater->exit_gizmo(); m_plater->update(true, true); - if (m_slice_select == eSliceAll) - wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_ALL)); - else - wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_PLATE)); - this->m_tabpanel->SetSelection(tpPreview); + bool slice = true; + + auto full_config = wxGetApp().preset_bundle->full_config(); + std::vectorg_filament_map = full_config.option("filament_map")->values; + FilamentMapMode g_filament_map_mode = get_prefered_map_mode(); + if (is_pop_up_required()) { + auto filament_colors = full_config.option("filament_colour")->values; + g_filament_map.resize(filament_colors.size()); + std::vector filament_lists(filament_colors.size()); + std::iota(filament_lists.begin(), filament_lists.end(), 1); + + FilamentMapDialog filament_dlg(this, + filament_colors, + g_filament_map, + filament_lists, + FilamentMapMode::fmmManual, + false + ); + auto ret = filament_dlg.ShowModal(); + if (ret == wxID_OK) { + g_filament_map_mode = filament_dlg.get_mode(); + g_filament_map = filament_dlg.get_filament_maps(); + } + else { + slice = false; + } + } + + if (slice) { + m_plater->set_global_filament_map_mode(g_filament_map_mode); + if (g_filament_map_mode == FilamentMapMode::fmmManual) + m_plater->set_global_filament_map(g_filament_map); + if (m_slice_select == eSliceAll) + wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_ALL)); + else + wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_PLATE)); + this->m_tabpanel->SetSelection(tpPreview); + } }); + m_slice_btn->Bind(wxEVT_ENTER_WINDOW, [this](wxMouseEvent& event) { + m_filament_group_popup->SetSize(wxSize(FromDIP(380),-1)); + wxPoint pos = m_slice_btn->ClientToScreen(wxPoint(0, 0)); + pos.y += m_slice_btn->GetRect().height * 1.25; + pos.x -= (m_slice_option_btn->GetRect().width + m_filament_group_popup->GetRect().width * 0.6); + + m_filament_group_popup->SetPosition(pos); + m_filament_group_popup->tryPopup(m_plater->check_ams_status()); + }); + + m_slice_btn->Bind(wxEVT_LEAVE_WINDOW, [this](auto& event) { + m_filament_group_popup->tryClose(); + }); + + m_print_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) { //this->m_plater->select_view_3D("Preview"); @@ -3868,6 +3919,7 @@ void MainFrame::technology_changed() m_menubar->SetMenuLabel(id, pt == ptSLA ? _omitL("Material Settings") : _L("Filament Settings")); } + // // Called after the Preferences dialog is closed and the program settings are saved. // Update the UI based on the current preferences. diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 4e24d31c3..452be1f54 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -27,6 +27,8 @@ #include "UnsavedChangesDialog.hpp" #include "Widgets/SideButton.hpp" #include "Widgets/SideMenuPopup.hpp" +#include "FilamentGroupPopup.hpp" + // BBS #include "BBLTopbar.hpp" @@ -339,6 +341,7 @@ public: void technology_changed(); + //BBS void load_url(wxString url); void load_printer_url(wxString url); @@ -391,6 +394,8 @@ public: SideButton* m_slice_option_btn{ nullptr }; SideButton* m_print_btn{ nullptr }; SideButton* m_print_option_btn{ nullptr }; + + FilamentGroupPopup* m_filament_group_popup{ nullptr }; mutable bool m_slice_enable{ true }; mutable bool m_print_enable{ true }; bool get_enable_slice_status(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 40b539316..dc779d6f7 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -15352,9 +15352,9 @@ void Plater::open_platesettings_dialog(wxCommandEvent& evt) { void Plater::open_filament_map_setting_dialog(wxCommandEvent &evt) { PartPlate* curr_plate = p->partplate_list.get_curr_plate(); - int value = evt.GetInt(); - bool is_auto = value & 1; //0000 means manual, 0001 means auto - bool need_slice = value & (1 << 1); //0010 means from gcode view, 0000 means not from gcode view + int value = evt.GetInt(); //1 means from gcode view + bool force_manual = value == 1; // If from gcode view, should display manual page + bool need_slice = value ==1; // If from gcode view, should slice const auto& project_config = wxGetApp().preset_bundle->project_config; auto filament_colors = config()->option("filament_colour")->values; @@ -15363,20 +15363,22 @@ void Plater::open_filament_map_setting_dialog(wxCommandEvent &evt) if (plate_filament_maps.size() != filament_colors.size()) // refine it later, save filament map to app config plate_filament_maps.resize(filament_colors.size(), 1); + FilamentMapMode display_mode = force_manual ? FilamentMapMode::fmmManual : plate_filament_map_mode; + FilamentMapDialog filament_dlg(this, - config(), + filament_colors, plate_filament_maps, curr_plate->get_extruders(true), - plate_filament_map_mode < FilamentMapMode::fmmManual, - false + display_mode, + true ); if (filament_dlg.ShowModal() == wxID_OK) { std::vector new_filament_maps = filament_dlg.get_filament_maps(); - std::vector old_filament_maps = plate_filament_maps; + std::vector old_filament_maps = curr_plate->get_filament_maps(); FilamentMapMode old_map_mode = plate_filament_map_mode; - FilamentMapMode new_map_mode = filament_dlg.is_auto() ? fmmAutoForFlush : fmmManual; + FilamentMapMode new_map_mode = filament_dlg.get_mode(); bool need_invalidate = (old_map_mode != new_map_mode || old_filament_maps != new_filament_maps); @@ -15575,7 +15577,7 @@ int Plater::select_plate_by_hover_id(int hover_id, bool right_click, bool isModi if (!ret) { PartPlate * curr_plate = p->partplate_list.get_curr_plate(); wxCommandEvent evt(EVT_OPEN_FILAMENT_MAP_SETTINGS_DIALOG); - evt.SetInt(curr_plate->get_filament_map_mode() < FilamentMapMode::fmmManual ? 1 : 0); + evt.SetInt(0); // 0 means not from gcodeviewer evt.SetEventObject(this); wxPostEvent(this, evt); } else { diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 907b9e619..7c3dfb536 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -446,6 +446,7 @@ public: void on_filaments_delete(size_t extruders_count, size_t filament_id, int replace_filament_id = -1); // BBS void on_bed_type_change(BedType bed_type,bool is_gcode_file = false); + bool update_filament_colors_in_full_config(); void config_change_notification(const DynamicPrintConfig &config, const std::string& key); void on_config_change(const DynamicPrintConfig &config); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 73dc492a7..0c8e0d8cb 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -1242,6 +1242,10 @@ wxWindow* PreferencesDialog::create_general_page() auto item_darkmode = create_item_darkmode_checkbox(_L("Enable dark mode"), page,_L("Enable dark mode"), 50, "dark_color_mode"); #endif + auto title_filament_group = create_item_title(_L("Filament Group"), page, _L("Filament Group")); + auto item_ignore_ext_filament = create_item_checkbox(_L("Ignore ext filament when auto grouping."), page, _L("Ignore ext filament when auto grouping"), 50, "ignore_ext_filament_when_group"); + auto item_pop_filament_group_mode = create_item_checkbox(_L("Pop up to select filament map mode."), page, _L("Pop up to select filament map mode"), 50, "pop_up_filament_map_mode"); + auto title_user_experience = create_item_title(_L("User Experience"), page, _L("User Experience")); auto item_priv_policy = create_item_checkbox(_L("Join Customer Experience Improvement Program."), page, "", 50, "privacyuse"); wxHyperlinkCtrl* hyperlink = new wxHyperlinkCtrl(page, wxID_ANY, _L("What data would be collected?"), "https://bambulab.com/en/policies/privacy"); @@ -1312,6 +1316,10 @@ wxWindow* PreferencesDialog::create_general_page() sizer_page->Add(item_darkmode, 0, wxEXPAND, FromDIP(3)); #endif + sizer_page->Add(title_filament_group, 0, wxTOP | wxEXPAND, FromDIP(20)); + sizer_page->Add(item_ignore_ext_filament, 0, wxEXPAND, FromDIP(3)); + sizer_page->Add(item_pop_filament_group_mode, 0, wxEXPAND, FromDIP(3)); + sizer_page->Add(title_user_experience, 0, wxTOP | wxEXPAND, FromDIP(20)); sizer_page->Add(item_priv_policy, 0, wxTOP, FromDIP(3));