diff --git a/src/slic3r/GUI/Auxiliary.cpp b/src/slic3r/GUI/Auxiliary.cpp index 95244436a3..13ca173eb6 100644 --- a/src/slic3r/GUI/Auxiliary.cpp +++ b/src/slic3r/GUI/Auxiliary.cpp @@ -869,11 +869,11 @@ void AuxiliaryPanel::init_tabpanel() m_assembly_panel = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::ASSEMBLY_GUIDE); m_others_panel = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::OTHERS); - m_tabpanel->AddPage(m_designer_panel, _L("Basic Info"), "", true); - m_tabpanel->AddPage(m_pictures_panel, _L("Pictures"), "", false); - m_tabpanel->AddPage(m_bill_of_materials_panel, _L("Bill of Materials"), "", false); - m_tabpanel->AddPage(m_assembly_panel, _L("Assembly Guide"), "", false); - m_tabpanel->AddPage(m_others_panel, _L("Others"), "", false); + m_tabpanel->AddPage(m_designer_panel, _L("Basic Info"), true); + m_tabpanel->AddPage(m_pictures_panel, _L("Pictures"), false); + m_tabpanel->AddPage(m_bill_of_materials_panel, _L("Bill of Materials"), false); + m_tabpanel->AddPage(m_assembly_panel, _L("Assembly Guide"), false); + m_tabpanel->AddPage(m_others_panel, _L("Others"), false); } wxWindow *AuxiliaryPanel::create_side_tools() diff --git a/src/slic3r/GUI/CalibrationPanel.cpp b/src/slic3r/GUI/CalibrationPanel.cpp index b006509adf..bdc79c1c8e 100644 --- a/src/slic3r/GUI/CalibrationPanel.cpp +++ b/src/slic3r/GUI/CalibrationPanel.cpp @@ -488,7 +488,6 @@ void CalibrationPanel::init_tabpanel() { selected = true; m_tabpanel->AddPage(m_cali_panels[i], get_calibration_type_name(m_cali_panels[i]->get_calibration_mode()), - "", selected); } diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 01c698c62c..d6dbd4e596 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -1018,8 +1018,8 @@ void MainFrame::update_layout() { const int home_idx = m_tabpanel->FindPageByName(TAB_ID_HOME); const size_t prepare_pos = (home_idx == wxNOT_FOUND) ? 0 : static_cast(home_idx) + 1; - m_tabpanel->InsertPage(prepare_pos, TAB_ID_PREPARE, m_plater, _L("Prepare"), std::string("tab_3d_active"), std::string("tab_3d_active"), false); - m_tabpanel->InsertPage(prepare_pos + 1, TAB_ID_PREVIEW, m_plater, _L("Preview"), std::string("tab_preview_active"), std::string("tab_preview_active"), false); + m_tabpanel->InsertPage(prepare_pos, m_plater, _L("Prepare"), false, Notebook::PAGE_PREPARE); + m_tabpanel->InsertPage(prepare_pos + 1, m_plater, _L("Preview"), false, Notebook::PAGE_PREVIEW); } m_main_sizer->Add(m_tabpanel, 1, wxEXPAND | wxTOP, 0); @@ -1315,7 +1315,7 @@ void MainFrame::init_tabpanel() { select_tab(TAB_ID_HOME); m_webview->load_url(url); }); - m_tabpanel->AddPage(TAB_ID_HOME, m_webview, "", "tab_home_active", "tab_home_active", false); + m_tabpanel->AddPage(m_webview, "", false, Notebook::PAGE_HOME); m_param_panel = new ParamsPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL); } @@ -1330,7 +1330,7 @@ void MainFrame::init_tabpanel() { //BBS add pages m_monitor = new MonitorPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); m_monitor->SetBackgroundColour(*wxWHITE); - m_tabpanel->AddPage(TAB_ID_MONITOR, m_monitor, _L("Device"), std::string("tab_monitor_active"), std::string("tab_monitor_active"), false); + m_tabpanel->AddPage(m_monitor, _L("Device"), false, Notebook::PAGE_MONITOR); m_printer_view = new PrinterWebView(m_tabpanel); Bind(EVT_LOAD_PRINTER_URL, [this](LoadPrinterViewEvent &evt) { @@ -1345,16 +1345,16 @@ void MainFrame::init_tabpanel() { m_multi_machine = new MultiMachinePage(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); m_multi_machine->SetBackgroundColour(*wxWHITE); // TODO: change the bitmap - m_tabpanel->AddPage(TAB_ID_MULTI_DEVICE, m_multi_machine, _L("Multi-device"), std::string("tab_multi_active"), std::string("tab_multi_active"), false); + m_tabpanel->AddPage(m_multi_machine, _L("Multi-device"), false, Notebook::PAGE_MULTI_DEVICE); } m_project = new ProjectPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); m_project->SetBackgroundColour(*wxWHITE); - m_tabpanel->AddPage(TAB_ID_PROJECT, m_project, _L("Project"), std::string("tab_auxiliary_active"), std::string("tab_auxiliary_active"), false); + m_tabpanel->AddPage(m_project, _L("Project"), false, Notebook::PAGE_PROJECT); m_calibration = new CalibrationPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); m_calibration->SetBackgroundColour(*wxWHITE); - m_tabpanel->AddPage(TAB_ID_CALIBRATION, m_calibration, _L("Calibration"), std::string("tab_calibration_active"), std::string("tab_calibration_active"), false); + m_tabpanel->AddPage(m_calibration, _L("Calibration"), false, Notebook::PAGE_CALIBRATION); // Plugin pages are appended after the built-in tabs; their ids are namespaced // (plugin..) so they can't collide with the built-in TAB_ID_* constants. @@ -1397,7 +1397,7 @@ void MainFrame::show_device(bool bBBLPrinter) { { const int preview_idx = m_tabpanel->FindPageByName(TAB_ID_PREVIEW); const size_t monitor_pos = (preview_idx == wxNOT_FOUND) ? m_tabpanel->GetPageCount() : static_cast(preview_idx) + 1; - m_tabpanel->InsertPage(monitor_pos, TAB_ID_MONITOR, m_monitor, _L("Device"), std::string("tab_monitor_active"), std::string("tab_monitor_active")); + m_tabpanel->InsertPage(monitor_pos, m_monitor, _L("Device"), false, Notebook::PAGE_MONITOR); } if (wxGetApp().is_enable_multi_machine()) { @@ -1410,8 +1410,7 @@ void MainFrame::show_device(bool bBBLPrinter) { { const int monitor_idx = m_tabpanel->FindPageByName(TAB_ID_MONITOR); const size_t multi_pos = (monitor_idx == wxNOT_FOUND) ? m_tabpanel->GetPageCount() : static_cast(monitor_idx) + 1; - m_tabpanel->InsertPage(multi_pos, TAB_ID_MULTI_DEVICE, m_multi_machine, _L("Multi-device"), std::string("tab_multi_active"), - std::string("tab_multi_active"), false); + m_tabpanel->InsertPage(multi_pos, m_multi_machine, _L("Multi-device"), false, Notebook::PAGE_MULTI_DEVICE); } } if (!m_calibration) { @@ -1422,8 +1421,7 @@ void MainFrame::show_device(bool bBBLPrinter) { // Calibration is always appended last (AddPage), so it lands after whichever of Monitor/Multi-device // actually got inserted above — no longer position-sensitive now that insertion position is computed // from FindPageByName rather than a fixed TabPosition index. - m_tabpanel->AddPage(TAB_ID_CALIBRATION, m_calibration, _L("Calibration"), std::string("tab_calibration_active"), - std::string("tab_calibration_active"), false); + m_tabpanel->AddPage(m_calibration, _L("Calibration"), false, Notebook::PAGE_CALIBRATION); #ifdef _MSW_DARK_MODE wxGetApp().UpdateDarkUIWin(this); @@ -1459,8 +1457,7 @@ void MainFrame::show_device(bool bBBLPrinter) { { const int preview_idx = m_tabpanel->FindPageByName(TAB_ID_PREVIEW); const size_t monitor_pos = (preview_idx == wxNOT_FOUND) ? m_tabpanel->GetPageCount() : static_cast(preview_idx) + 1; - m_tabpanel->InsertPage(monitor_pos, TAB_ID_MONITOR, m_printer_view, _L("Device"), std::string("tab_monitor_active"), - std::string("tab_monitor_active")); + m_tabpanel->InsertPage(monitor_pos, m_printer_view, _L("Device"), false, Notebook::PAGE_MONITOR); } } fit_tab_labels(); // ORCA on printer change diff --git a/src/slic3r/GUI/Monitor.cpp b/src/slic3r/GUI/Monitor.cpp index 068bcf7e6d..4c26268a21 100644 --- a/src/slic3r/GUI/Monitor.cpp +++ b/src/slic3r/GUI/Monitor.cpp @@ -186,17 +186,17 @@ void MonitorPanel::init_tabpanel() //m_status_add_machine_panel = new AddMachinePanel(m_tabpanel); m_status_info_panel = new StatusPanel(m_tabpanel); - m_tabpanel->AddPage(m_status_info_panel, _L("Status"), "", true); + m_tabpanel->AddPage(m_status_info_panel, _L("Status"), true); m_media_file_panel = new MediaFilePanel(m_tabpanel); - m_tabpanel->AddPage(m_media_file_panel, _L("Storage"), "", false); - //m_tabpanel->AddPage(m_media_file_panel, _L("Internal Storage"), "", false); + m_tabpanel->AddPage(m_media_file_panel, _L("Storage"), false); + //m_tabpanel->AddPage(m_media_file_panel, _L("Internal Storage"), false); m_upgrade_panel = new UpgradePanel(m_tabpanel); - m_tabpanel->AddPage(m_upgrade_panel, _CTX(L_CONTEXT("Update", "Firmware"), "Firmware"), "", false); + m_tabpanel->AddPage(m_upgrade_panel, _CTX(L_CONTEXT("Update", "Firmware"), "Firmware"), false); m_hms_panel = new HMSPanel(m_tabpanel); - m_tabpanel->AddPage(m_hms_panel, _L("Assistant(HMS)"), "", false); + m_tabpanel->AddPage(m_hms_panel, _L("Assistant(HMS)"), false); std::string network_ver = Slic3r::NetworkAgent::get_version(); if (!network_ver.empty()) { diff --git a/src/slic3r/GUI/MultiMachinePage.cpp b/src/slic3r/GUI/MultiMachinePage.cpp index b9b71ad670..88d03007b9 100644 --- a/src/slic3r/GUI/MultiMachinePage.cpp +++ b/src/slic3r/GUI/MultiMachinePage.cpp @@ -86,9 +86,9 @@ void MultiMachinePage::init_tabpanel() m_cloud_task_manager = new CloudTaskManagerPage(m_tabpanel); m_machine_manager = new MultiMachineManagerPage(m_tabpanel); - m_tabpanel->AddPage(m_machine_manager, _L("Device"), "", true); - m_tabpanel->AddPage(m_local_task_manager, _L("Task Sending"), "", false); - m_tabpanel->AddPage(m_cloud_task_manager, _L("Task Sent"), "", false); + m_tabpanel->AddPage(m_machine_manager, _L("Device"), true); + m_tabpanel->AddPage(m_local_task_manager, _L("Task Sending"), false); + m_tabpanel->AddPage(m_cloud_task_manager, _L("Task Sent"), false); } void MultiMachinePage::init_timer() diff --git a/src/slic3r/GUI/Notebook.cpp b/src/slic3r/GUI/Notebook.cpp index 4c6430f99c..847996aba9 100644 --- a/src/slic3r/GUI/Notebook.cpp +++ b/src/slic3r/GUI/Notebook.cpp @@ -132,7 +132,6 @@ void ButtonsListCtrl::SetSelection(int sel) StateColor text_color = StateColor( std::pair{wxColour(254,254, 254), (int) StateColor::Normal} ); - m_pageButtons[m_selection]->SetSelected(false); m_pageButtons[m_selection]->SetTextColor(text_color); } @@ -152,17 +151,20 @@ void ButtonsListCtrl::SetSelection(int sel) StateColor text_color = StateColor( std::pair{wxColour(254, 254, 254), (int) StateColor::Normal} ); - m_pageButtons[m_selection]->SetSelected(true); m_pageButtons[m_selection]->SetTextColor(text_color); Refresh(); } -bool ButtonsListCtrl::InsertPage(size_t n, const wxString &text, bool bSelect /* = false*/, const std::string &bmp_name /* = ""*/, const std::string &inactive_bmp_name) +bool ButtonsListCtrl::InsertPage(size_t n, const wxString &text, bool bSelect /* = false*/, const std::string &bmp_name /* = ""*/, int imageId /* = wxBookCtrlBase::NO_IMAGE */) { Button * btn = new Button(this, text.empty() ? text : " " + text, bmp_name, wxNO_BORDER); btn->SetCornerRadius(0); + if (bmp_name.empty() && m_imageList != nullptr && imageId != wxBookCtrlBase::NO_IMAGE && imageId >= 0 && + imageId < m_imageList->GetImageCount()) + btn->SetIcon(m_imageList->GetBitmap(imageId)); + int em = em_unit(this); //BBS set size for button btn->SetMinSize({(text.empty() ? 40 : 136) * em / 10, 36 * em / 10}); @@ -175,8 +177,6 @@ bool ButtonsListCtrl::InsertPage(size_t n, const wxString &text, bool bSelect /* StateColor text_color = StateColor( std::pair{wxColour(254,254, 254), (int) StateColor::Normal}); btn->SetTextColor(text_color); - btn->SetInactiveIcon(inactive_bmp_name); - btn->SetSelected(false); btn->Bind(wxEVT_BUTTON, [this, btn](wxCommandEvent& event) { if (auto it = std::find(m_pageButtons.begin(), m_pageButtons.end(), btn); it != m_pageButtons.end()) { auto sel = it - m_pageButtons.begin(); @@ -232,6 +232,23 @@ bool ButtonsListCtrl::SetPageImage(size_t n, const std::string& bmp_name) const return true; } +bool ButtonsListCtrl::SetPageImage(size_t n, int imageId) +{ + if (n >= m_pageButtons.size()) + return false; + + if (imageId == wxBookCtrlBase::NO_IMAGE) { + m_pageButtons[n]->SetIcon(wxBitmap()); + return true; + } + + if (m_imageList == nullptr || imageId < 0 || imageId >= m_imageList->GetImageCount()) + return false; + + m_pageButtons[n]->SetIcon(m_imageList->GetBitmap(imageId)); + return true; +} + void ButtonsListCtrl::SetPageText(size_t n, const wxString& strText) { Button* btn = m_pageButtons[n]; diff --git a/src/slic3r/GUI/Notebook.hpp b/src/slic3r/GUI/Notebook.hpp index a82be7be56..859ada37a5 100644 --- a/src/slic3r/GUI/Notebook.hpp +++ b/src/slic3r/GUI/Notebook.hpp @@ -3,8 +3,11 @@ //#ifdef _WIN32 +#include #include +#include #include +#include #include class ScalableButton; @@ -24,9 +27,11 @@ public: void SetSelection(int sel); void UpdateMode(); void Rescale(); - bool InsertPage(size_t n, const wxString &text, bool bSelect = false, const std::string &bmp_name = "", const std::string &inactive_bmp_name = ""); + bool InsertPage(size_t n, const wxString &text, bool bSelect = false, const std::string &bmp_name = "", int imageId = wxBookCtrlBase::NO_IMAGE); void RemovePage(size_t n); bool SetPageImage(size_t n, const std::string& bmp_name) const; + bool SetPageImage(size_t n, int imageId); + void SetImageList(wxImageList* imageList) { m_imageList = imageList; } void SetPageText(size_t n, const wxString& strText); void SetCompact(size_t n, bool compact); // ORCA wxString GetPageText(size_t n) const; @@ -41,11 +46,22 @@ private: int m_btn_margin; int m_line_margin; std::vector m_pageLabels; // ORCA + wxImageList* m_imageList{nullptr}; }; class Notebook : public wxBookCtrlBase { public: + // Negative values below wxBookCtrlBase::NO_IMAGE are reserved for the built-in + // tabs. Nonnegative values are wxImageList indices supplied by plugin pages. + static constexpr int PAGE_HOME = -2; + static constexpr int PAGE_PREPARE = -3; + static constexpr int PAGE_PREVIEW = -4; + static constexpr int PAGE_MONITOR = -5; + static constexpr int PAGE_MULTI_DEVICE = -6; + static constexpr int PAGE_PROJECT = -7; + static constexpr int PAGE_CALIBRATION = -8; + Notebook(wxWindow * parent, wxWindowID winid = wxID_ANY, const wxPoint & pos = wxDefaultPosition, @@ -104,7 +120,7 @@ public: // by this control) and show it immediately. bool ShowNewPage(wxWindow * page) { - return AddPage(wxString(), page, wxString(), "", ""); + return AddPage(page, wxString(), false, NO_IMAGE); } @@ -136,16 +152,10 @@ public: // Implement base class pure virtual methods. - // adds a new page to the control - bool AddPage(const wxString& id, - wxWindow* page, - const wxString& text, - const std::string& bmp_name, - const std::string& inactive_bmp_name, - bool bSelect = false) + bool AddPage(wxWindow* page, const wxString& text, bool bSelect = false, int imageId = NO_IMAGE) override { DoInvalidateBestSize(); - return InsertPage(GetPageCount(), id, page, text, bmp_name, inactive_bmp_name, bSelect); + return InsertPage(GetPageCount(), page, text, bSelect, imageId); } // Page management @@ -154,12 +164,38 @@ public: const wxString & text, bool bSelect = false, int imageId = NO_IMAGE) override + { + wxString page_name; + std::string bmp_name; + const bool is_fixed_page = get_fixed_page_info(imageId, page_name, bmp_name); + const int stored_image_id = is_fixed_page ? NO_IMAGE : imageId; + + if (!wxBookCtrlBase::InsertPage(n, page, text, bSelect, stored_image_id)) + return false; + + m_pageNames.insert(m_pageNames.begin() + n, page_name); + m_pageImageIds.insert(m_pageImageIds.begin() + n, stored_image_id); + GetBtnsListCtrl()->InsertPage(n, text, bSelect, bmp_name, stored_image_id); + + if (!DoSetSelectionAfterInsertion(n, bSelect)) + page->Hide(); + + return true; + } + + bool InsertPage(size_t n, + const wxString& id, + wxWindow* page, + const wxString& text, + int imageId, + bool bSelect = false) { if (!wxBookCtrlBase::InsertPage(n, page, text, bSelect, imageId)) return false; - m_pageNames.insert(m_pageNames.begin() + n, wxString()); - GetBtnsListCtrl()->InsertPage(n, text, bSelect); + m_pageNames.insert(m_pageNames.begin() + n, id); + m_pageImageIds.insert(m_pageImageIds.begin() + n, imageId); + GetBtnsListCtrl()->InsertPage(n, text, bSelect, "", imageId); if (!DoSetSelectionAfterInsertion(n, bSelect)) page->Hide(); @@ -172,14 +208,14 @@ public: wxWindow * page, const wxString & text, const std::string& bmp_name = "", - const std::string& inactive_bmp_name = "", bool bSelect = false) { if (!wxBookCtrlBase::InsertPage(n, page, text, bSelect)) return false; m_pageNames.insert(m_pageNames.begin() + n, id); - GetBtnsListCtrl()->InsertPage(n, text, bSelect, bmp_name, inactive_bmp_name); + m_pageImageIds.insert(m_pageImageIds.begin() + n, NO_IMAGE); + GetBtnsListCtrl()->InsertPage(n, text, bSelect, bmp_name); // wxBookCtrlBase::InsertPage() only inserts into the page list and sizes the // new page to the current page's rect — it never touches visibility. A freshly @@ -222,8 +258,7 @@ public: return DoSetSelection(n); } - // Neither labels nor images are supported but we still store the labels - // just in case the user code attaches some importance to them. + // Labels are stored by the custom button list; page images use the wx image-list IDs below. virtual bool SetPageText(size_t n, const wxString & strText) override { wxCHECK_MSG(n < GetPageCount(), false, wxS("Invalid page")); @@ -239,14 +274,27 @@ public: return GetBtnsListCtrl()->GetPageText(n); } - virtual bool SetPageImage(size_t WXUNUSED(n), int WXUNUSED(imageId)) override + virtual bool SetPageImage(size_t n, int imageId) override { - return false; + if (n >= m_pageImageIds.size()) + return false; + + if (!GetBtnsListCtrl()->SetPageImage(n, imageId)) + return false; + + m_pageImageIds[n] = imageId; + return true; } - virtual int GetPageImage(size_t WXUNUSED(n)) const override + virtual int GetPageImage(size_t n) const override { - return NO_IMAGE; + return n < m_pageImageIds.size() ? m_pageImageIds[n] : NO_IMAGE; + } + + void SetImageList(wxImageList* imageList) + { + m_imageList = imageList; + GetBtnsListCtrl()->SetImageList(imageList); } bool SetPageImage(size_t n, const std::string& bmp_name) @@ -271,6 +319,7 @@ public: virtual bool DeleteAllPages() override { m_pageNames.clear(); + m_pageImageIds.clear(); return wxBookCtrlBase::DeleteAllPages(); } @@ -431,6 +480,7 @@ protected: if (win) { m_pageNames.erase(m_pageNames.begin() + page); + m_pageImageIds.erase(m_pageImageIds.begin() + page); GetBtnsListCtrl()->RemovePage(page); DoSetSelectionAfterRemoval(page); } @@ -454,9 +504,47 @@ protected: } private: + static bool get_fixed_page_info(int imageId, wxString& page_name, std::string& bmp_name) + { + switch (imageId) { + case PAGE_HOME: + page_name = wxS("home"); + bmp_name = "tab_home_active"; + return true; + case PAGE_PREPARE: + page_name = wxS("prepare"); + bmp_name = "tab_3d_active"; + return true; + case PAGE_PREVIEW: + page_name = wxS("preview"); + bmp_name = "tab_preview_active"; + return true; + case PAGE_MONITOR: + page_name = wxS("monitor"); + bmp_name = "tab_monitor_active"; + return true; + case PAGE_MULTI_DEVICE: + page_name = wxS("multi_device"); + bmp_name = "tab_multi_active"; + return true; + case PAGE_PROJECT: + page_name = wxS("project"); + bmp_name = "tab_auxiliary_active"; + return true; + case PAGE_CALIBRATION: + page_name = wxS("calibration"); + bmp_name = "tab_calibration_active"; + return true; + default: + return false; + } + } + void Init(); std::vector m_pageNames; // index-parallel to wxBookCtrlBase::m_pages + std::vector m_pageImageIds; // index-parallel to wxBookCtrlBase::m_pages + wxImageList* m_imageList{nullptr}; wxShowEffect m_showEffect, m_hideEffect; diff --git a/src/slic3r/GUI/Tabbook.hpp b/src/slic3r/GUI/Tabbook.hpp index 0cea1b8326..7f10e9dd8d 100644 --- a/src/slic3r/GUI/Tabbook.hpp +++ b/src/slic3r/GUI/Tabbook.hpp @@ -108,7 +108,7 @@ public: // by this control) and show it immediately. bool ShowNewPage(wxWindow * page) { - return AddPage(page, wxString(), ""/*true *//* select it */); + return AddPage(page, wxString()); } // Set effect to use for showing/hiding pages. @@ -139,14 +139,13 @@ public: // Implement base class pure virtual methods. - // adds a new page to the control bool AddPage(wxWindow* page, const wxString& text, - const std::string& bmp_name, - bool bSelect = false) + bool bSelect = false, + int imageId = NO_IMAGE) override { DoInvalidateBestSize(); - return InsertNewPage(GetPageCount(), page, text, bmp_name, bSelect); + return InsertPage(GetPageCount(), page, text, bSelect, imageId); } //// Page management @@ -167,23 +166,6 @@ public: return true; } - bool InsertNewPage(size_t n, - wxWindow * page, - const wxString & text, - const std::string& bmp_name = "", - bool bSelect = false) - { - if (!wxBookCtrlBase::InsertPage(n, page, text, bSelect)) - return false; - - GetBtnsListCtrl()->InsertPage(n, text, bSelect, bmp_name); - - if (bSelect) - SetSelection(n); - - return true; - } - bool RemovePage(size_t n) { if (!wxBookCtrlBase::RemovePage(n)) diff --git a/src/slic3r/GUI/Widgets/Button.cpp b/src/slic3r/GUI/Widgets/Button.cpp index e236c84e67..1a8cbefbce 100644 --- a/src/slic3r/GUI/Widgets/Button.cpp +++ b/src/slic3r/GUI/Widgets/Button.cpp @@ -95,14 +95,11 @@ void Button::SetIcon(const wxString& icon) } } -void Button::SetInactiveIcon(const wxString &icon) +void Button::SetIcon(const wxBitmap& icon) { - if (!icon.IsEmpty()) { - // BBS set button icon default size to 20 - this->inactive_icon = ScalableBitmap(this, icon.ToStdString(), this->active_icon.px_cnt()); - } else { - this->inactive_icon = ScalableBitmap(); - } + this->active_icon = ScalableBitmap(); + this->active_icon.bmp() = icon; + messureSize(); Refresh(); } @@ -260,9 +257,6 @@ void Button::Rescale() if (this->active_icon.bmp().IsOk()) this->active_icon.msw_rescale(); - if (this->inactive_icon.bmp().IsOk()) - this->inactive_icon.msw_rescale(); - messureSize(); if(m_has_style) @@ -293,11 +287,7 @@ void Button::render(wxDC& dc) wxSize szIcon; wxSize textSize = this->textSize.GetSize(); - ScalableBitmap icon; - if (m_selected || ((states & (int)StateColor::State::Hovered) != 0)) - icon = active_icon; - else - icon = inactive_icon; + ScalableBitmap icon = active_icon; wxSize padding = this->paddingSize; int spacing = 5; // Wrap text diff --git a/src/slic3r/GUI/Widgets/Button.hpp b/src/slic3r/GUI/Widgets/Button.hpp index bc093b512a..fdc511ec7c 100644 --- a/src/slic3r/GUI/Widgets/Button.hpp +++ b/src/slic3r/GUI/Widgets/Button.hpp @@ -34,12 +34,10 @@ class Button : public StaticBox wxSize minSize; // set by outer wxSize paddingSize; ScalableBitmap active_icon; - ScalableBitmap inactive_icon; StateColor text_color; bool pressedDown = false; - bool m_selected = true; bool canFocus = true; bool isCenter = true; bool vertical = false; @@ -61,8 +59,7 @@ public: bool SetFont(const wxFont& font) override; void SetIcon(const wxString& icon); - - void SetInactiveIcon(const wxString& icon); + void SetIcon(const wxBitmap& icon); void SetMinSize(const wxSize& size) override; void SetMaxSize(const wxSize& size) override; @@ -75,8 +72,6 @@ public: void SetTextColorNormal(wxColor const &color); - void SetSelected(bool selected = true) { m_selected = selected; } - bool Enable(bool enable = true) override; void EnableTooltipEvenDisabled();// The tip will be shown even if the button is disabled diff --git a/src/slic3r/plugin/host/PluginPages.cpp b/src/slic3r/plugin/host/PluginPages.cpp index 3e7d534810..3b9b1498ee 100644 --- a/src/slic3r/plugin/host/PluginPages.cpp +++ b/src/slic3r/plugin/host/PluginPages.cpp @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include @@ -204,6 +206,11 @@ void PluginPages::initialize(Notebook* parent) if (m_parent == nullptr) return; + // Keep image-list indices stable for the lifetime of this notebook. Removing an image + // would shift every later index, so deregistration only removes the page. + m_image_list = std::make_unique(20, 20, true, 0); + m_parent->SetImageList(m_image_list.get()); + for (const auto& capability : PluginManager::instance().get_plugin_capabilities("", PluginCapabilityType::Pages)) { if (capability) on_cap_register(capability->identity()); @@ -214,6 +221,9 @@ void PluginPages::shutdown() { while (!m_pages.empty()) remove_page(m_pages.begin()->first); + if (m_parent != nullptr) + m_parent->SetImageList(nullptr); + m_image_list.reset(); m_parent = nullptr; } @@ -235,6 +245,15 @@ void PluginPages::on_cap_register(const PluginCapabilityId& id) if (!capability) return; + std::string icon; + try { + icon = capability->get_icon(); + } catch (const std::exception& error) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " Failed to get icon for plugin " << id.plugin_key << ": " << error.what(); + } catch (...) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " Failed to get icon for plugin " << id.plugin_key; + } + auto* page = new PluginPage(m_parent, std::move(capability)); if (!page->is_valid()) { page->Destroy(); @@ -242,8 +261,29 @@ void PluginPages::on_cap_register(const PluginCapabilityId& id) } const wxString title = wxString::FromUTF8(id.name); - const wxString page_id = wxString::FromUTF8("plugin." + id.plugin_key + "." + id.name); - if (!m_parent->AddPage(page_id, page, title, "tab_auxiliary_active", "tab_auxiliary_active", false)) { + + int image_id = wxBookCtrlBase::NO_IMAGE; + if (!icon.empty() && m_image_list) { + try { + boost::filesystem::path icon_path(icon); + const std::string extension = icon_path.extension().string(); + if (extension == ".svg" || extension == ".png") + icon_path.replace_extension(); + + const wxBitmap bitmap = create_scaled_bitmap(icon_path.string(), m_parent, 20); + if (bitmap.IsOk()) + image_id = m_image_list->Add(bitmap); + } catch (const std::exception& error) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " Failed to load icon for plugin " << id.plugin_key << ": " << error.what(); + } catch (...) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " Failed to load icon for plugin " << id.plugin_key; + } + } + + page->set_icon_image_id(image_id); + if (!m_parent->AddPage(page, title, false, image_id)) { + if (image_id != wxBookCtrlBase::NO_IMAGE && m_image_list && image_id == m_image_list->GetImageCount() - 1) + m_image_list->Remove(image_id); page->Destroy(); return; } @@ -285,12 +325,39 @@ void PluginPages::remove_page(const PluginCapabilityId& id) return; PluginPage* page = it->second; + const int removed_image_id = page->get_icon_image_id(); page->detach_capability(); if (m_parent != nullptr) { const int index = m_parent->FindPage(page); if (index != wxNOT_FOUND) m_parent->RemovePage(static_cast(index)); } + + if (m_image_list && removed_image_id != wxBookCtrlBase::NO_IMAGE && + removed_image_id >= 0 && removed_image_id < m_image_list->GetImageCount()) { + m_image_list->Remove(removed_image_id); + + // wxImageList IDs are positional. Removing one shifts all later images down by + // one, so update both the page state and the notebook button for those pages. + for (const auto& [other_id, other_page] : m_pages) { + if (other_id == id) + continue; + + const int other_image_id = other_page->get_icon_image_id(); + if (other_image_id <= removed_image_id) + continue; + + const int updated_image_id = other_image_id - 1; + other_page->set_icon_image_id(updated_image_id); + + if (m_parent != nullptr) { + const int other_index = m_parent->FindPage(other_page); + if (other_index != wxNOT_FOUND) + m_parent->SetPageImage(static_cast(other_index), updated_image_id); + } + } + } + page->Destroy(); m_pages.erase(it); } diff --git a/src/slic3r/plugin/host/PluginPages.hpp b/src/slic3r/plugin/host/PluginPages.hpp index bf70305201..d925f2eb32 100644 --- a/src/slic3r/plugin/host/PluginPages.hpp +++ b/src/slic3r/plugin/host/PluginPages.hpp @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include @@ -29,16 +31,20 @@ public: void on_new_window(wxWebViewEvent& event); void on_script_message(wxWebViewEvent& event); void push_message(const std::string& message); + void set_icon_image_id(int id) { m_icon_image_id = id; } + int get_icon_image_id() const { return m_icon_image_id; } private: void load_plugin_content(); wxString bootstrap_url() const; wxString web_base_url() const; - wxWebView* m_browser{nullptr}; - std::shared_ptr m_cap; - std::shared_ptr> m_lifetime; - bool m_content_loaded{false}; + wxWebView* m_browser{nullptr}; + std::shared_ptr m_cap; + std::shared_ptr> m_lifetime; + bool m_content_loaded{false}; + + int m_icon_image_id = wxBookCtrlBase::NO_IMAGE; }; class PluginPages @@ -47,7 +53,7 @@ public: PluginPages() = default; ~PluginPages(); - PluginPages(const PluginPages&) = delete; + PluginPages(const PluginPages&) = delete; PluginPages& operator=(const PluginPages&) = delete; void initialize(Notebook* parent); @@ -63,7 +69,9 @@ private: void remove_page(const PluginCapabilityId& id); std::map m_pages; - Notebook* m_parent{nullptr}; + Notebook* m_parent{nullptr}; + + std::unique_ptr m_image_list; }; } // namespace Slic3r diff --git a/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapability.cpp b/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapability.cpp index fc5d4a03b8..e009f4426f 100644 --- a/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapability.cpp +++ b/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapability.cpp @@ -23,6 +23,7 @@ void PagesPluginCapability::RegisterBindings(pybind11::module_& module) .def(py::init<>()) .def("get_type", &PagesPluginCapability::get_type) .def("get_ui", &PagesPluginCapability::get_ui) + .def("get_icon", &PagesPluginCapability::get_icon) .def("on_message", &PagesPluginCapability::on_message) .def( "post_message", diff --git a/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapability.hpp b/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapability.hpp index e833d7dbf4..978492006c 100644 --- a/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapability.hpp +++ b/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapability.hpp @@ -18,6 +18,7 @@ public: virtual std::string get_ui() = 0; virtual void on_message(std::string message) { (void) message; } + virtual std::string get_icon() { return {}; } void post_message(std::string message); void set_message_sender(std::function sender); diff --git a/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapabilityTrampoline.hpp b/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapabilityTrampoline.hpp index 71eb5c5bcc..3fb476c228 100644 --- a/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapabilityTrampoline.hpp +++ b/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapabilityTrampoline.hpp @@ -13,6 +13,17 @@ class PyPagesPluginCapabilityTrampoline : public PyPluginCommonTrampoline::PyPluginCommonTrampoline; + std::string get_icon() override + { + ORCA_PY_OVERRIDE_AUDITED( + ::Slic3r::PluginAuditManager::AuditMode::Loading, + [] {}, + PYBIND11_OVERRIDE, + std::string, + PagesPluginCapability, + get_icon); + } + std::string get_ui() override { ORCA_PY_OVERRIDE_AUDITED(