#include "UserPresetsDialog.hpp" #include "I18N.hpp" #include "GUI_App.hpp" #include #include namespace Slic3r { namespace GUI { UserPresetsDialog::UserPresetsDialog(wxWindow *parent) : DPIDialog(parent, wxID_ANY, _L("Management user presets")) { SetBackgroundColour(*wxWHITE); SetMinSize({FromDIP(788), -1}); m_tab_ctrl = new TabCtrl(this, wxID_ANY); m_tab_ctrl->SetFont(Label::Body_14); m_tab_ctrl->AppendItem(""); m_tab_ctrl->AppendItem(""); m_tab_ctrl->AppendItem(""); m_tab_ctrl->SelectItem(0); m_tab_ctrl->Bind(wxEVT_TAB_SEL_CHANGED, [this] (auto & evt) { on_collection_changed(evt.GetInt()); }); m_switch_button = new SwitchButton(this); m_switch_button->SetFont(Label::Body_13); m_switch_button->SetMaxSize({FromDIP(182), -1}); m_switch_button->SetLabels(" " + _L("Custom filaments") + " ", _L("Others")); m_switch_button->Bind(wxEVT_TOGGLEBUTTON, [this](auto &evt) { evt.Skip(); on_collection_changed(m_collection); }); m_search = new TextInput(this, "", "", "im_text_search"); m_search->SetSize({FromDIP(568), FromDIP(24)}); m_search->SetCornerRadius(FromDIP(12)); m_search->Bind(wxEVT_TEXT, [this](auto &evt) { on_search(evt.GetString()); }); m_empty_panel = new wxPanel(this); m_empty_panel->SetMinSize({-1, FromDIP(360)}); m_empty_panel->SetMaxSize({-1, FromDIP(360)}); m_empty_panel->SetForegroundColour(wxColor("#A0A0A0")); { wxSizer *sizer = new wxBoxSizer(wxVERTICAL); wxStaticBitmap *bitmap = new wxStaticBitmap(m_empty_panel, wxID_ANY, create_scaled_bitmap(wxGetApp().dark_mode() ? "preset_empty_dark" : "preset_empty", this, 150)); sizer->Add(bitmap, 0, wxALIGN_CENTER | wxTOP, FromDIP(70)); Label *label = new Label(m_empty_panel, _L("No content")); label->SetBackgroundColour(this->GetBackgroundColour()); label->SetForegroundColour(m_empty_panel->GetForegroundColour()); sizer->Add(label, 0, wxALIGN_CENTER); m_empty_panel->SetSizer(sizer); m_empty_panel->Hide(); } m_scrolled = new wxScrolledWindow(this); m_scrolled->SetBackgroundColour("#F8F8F8"); m_scrolled->SetScrollbars(0, 100, 1, 2); m_scrolled->SetScrollRate(0, 5); m_scrolled->SetMinSize({-1, FromDIP(360)}); m_scrolled->SetMaxSize({-1, FromDIP(360)}); { wxSizer *sizer = new wxBoxSizer(wxHORIZONTAL); wxSizer *sizerLeft = new wxBoxSizer(wxVERTICAL); auto line = new StaticLine(m_scrolled, true); wxSizer *sizerRight = new wxBoxSizer(wxVERTICAL); sizer->Add(sizerLeft, 1, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(20)); sizer->Add(line, 0, wxEXPAND); sizer->Add(sizerRight, 1, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(20)); m_scrolled->SetSizer(sizer); } m_check_all = new CheckBox(this); auto label = new Label(this, _L("Select All")); m_label_check_count = new Label(this); m_label_check_count->SetForegroundColour("#6B6B6B"); m_button_delete = new Button(this, _L("Delete")); m_button_delete->SetBorderColorNormal(wxColor("#D01B1B")); m_button_delete->SetTextColorNormal(wxColor("#D01B1B")); m_check_all->Bind(wxEVT_TOGGLEBUTTON, [this](auto &evt) { on_all_checked(evt.IsChecked(), true); }); label->Bind(wxEVT_LEFT_UP, [this](auto &evt) { bool checked = !m_check_all->GetValue(); m_check_all->SetValue(checked); on_all_checked(checked, true); }); m_button_delete->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](auto &evt) { delete_checked(); }); wxSizer *sizer_bottom = new wxBoxSizer(wxHORIZONTAL); sizer_bottom->Add(m_check_all, 0, wxALIGN_CENTER | wxLEFT, FromDIP(20)); sizer_bottom->Add(label, 0, wxALIGN_CENTER | wxLEFT, FromDIP(8)); sizer_bottom->Add(m_label_check_count, 1, wxALIGN_CENTER | wxLEFT, FromDIP(8)); sizer_bottom->Add(m_button_delete, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, FromDIP(20)); wxSizer *sizer = new wxBoxSizer(wxVERTICAL); SetSizer(sizer); sizer->Add(m_tab_ctrl, 0, wxALIGN_CENTER | wxALL, FromDIP(20)); sizer->Add(m_switch_button, 0, wxALIGN_CENTER | wxBOTTOM, FromDIP(10)); sizer->Add(m_search, 0, wxALIGN_CENTER | wxBOTTOM, FromDIP(10)); sizer->Add(m_scrolled, 1, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(20)); sizer->Add(m_empty_panel, 1, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(20)); sizer->Add(sizer_bottom, 0, wxEXPAND | wxALL, FromDIP(20)); wxGetApp().UpdateDlgDarkUI(this); m_switch_button->Rescale(); init_preset_list(); update_preset_counts(); on_collection_changed(0); Layout(); Fit(); CenterOnParent(); } void UserPresetsDialog::init_preset_list() { auto bundle = wxGetApp().preset_bundle; for (PresetCollection *collection : {(PresetCollection *) &bundle->printers, &bundle->filaments, &bundle->prints}) { std::vector presets; for (auto &preset : *collection) { if (!preset.is_user()) continue; if (collection->type() == Preset::TYPE_FILAMENT) { if (preset.base_id.empty()) { auto id = preset.filament_id; m_filament_names[id] = preset.alias; m_filament_presets[id].emplace_back(preset.name); continue; } } presets.push_back(preset.name); } m_presets.emplace_back(std::move(presets)); } } void UserPresetsDialog::create_preset_list(wxWindow *parent) { if (is_filament_list()) { for (auto &filament : m_filament_presets) m_filament_sizers.emplace(filament.first, create_filament_group(parent, filament)); } else { auto &presets = m_presets[m_collection]; for (auto &preset : presets) m_preset_sizers.emplace(preset, create_preset_line(m_scrolled, preset)); } } wxSizer *UserPresetsDialog::create_preset_line(wxWindow *parent, std::string const &preset) { wxSizer *vsizer = new wxBoxSizer(wxVERTICAL); wxSizer *hsizer = new wxBoxSizer(wxHORIZONTAL); auto check = new CheckBox(parent); auto label = new Label(parent, from_u8(preset), wxST_ELLIPSIZE_END); auto line = new StaticLine(parent); label->SetMaxSize({FromDIP(268), -1}); label->SetToolTip(label->GetLabel()); check->Bind(wxEVT_TOGGLEBUTTON, [this, preset](auto &evt) { evt.Skip(); on_preset_checked(preset, evt.IsChecked(), true); }); label->Bind(wxEVT_LEFT_UP, [this, preset, check](auto &evt) { bool checked = !check->GetValue(); check->SetValue(checked); on_preset_checked(preset, checked, true); }); hsizer->Add(check, 0, wxALIGN_CENTER | wxRIGHT | wxTOP | wxBOTTOM, FromDIP(6)); hsizer->Add(label, 1, wxALIGN_CENTER); vsizer->Add(hsizer, 0, wxEXPAND); vsizer->Add(line, 0, wxEXPAND); return vsizer; } wxSizer *UserPresetsDialog::create_filament_group(wxWindow *parent, std::pair> const &filament) { wxSizer * vsizer = new wxBoxSizer(wxVERTICAL); wxSizer * hsizer = new wxBoxSizer(wxHORIZONTAL); auto check = new CheckBox(parent); auto label = new Label(parent, from_u8(m_filament_names[filament.first]), wxST_ELLIPSIZE_END); auto line = new StaticLine(parent); label->SetMaxSize({-1, FromDIP(268)}); label->SetToolTip(label->GetLabel()); check->Bind(wxEVT_TOGGLEBUTTON, [this, filament = filament.first](auto &evt) { evt.Skip(); on_filament_checked(filament, evt.IsChecked(), true); }); label->Bind(wxEVT_LEFT_UP, [this, filament = filament.first, check](auto &evt) { bool checked = !check->GetValue(); check->SetValue(checked); on_filament_checked(filament, checked, true); }); hsizer->Add(check, 0, wxALIGN_CENTER | wxRIGHT | wxTOP | wxBOTTOM, FromDIP(6)); hsizer->Add(label, 1, wxALIGN_CENTER); vsizer->Add(hsizer, 0, wxEXPAND); vsizer->Add(line, 0, wxEXPAND); for (auto preset : filament.second) { auto sizer3 = create_preset_line(parent, preset); m_preset_sizers.emplace(preset, sizer3); vsizer->Add(sizer3, 0, wxEXPAND | wxLEFT, FromDIP(20)); } return vsizer; } void UserPresetsDialog::layout_preset_list(bool delete_old) { wxSizer *sizer = m_scrolled->GetSizer(); wxSizer *sizerLeft = sizer->GetItem(size_t(0))->GetSizer(); wxSizer *sizerRight = sizer->GetItem(size_t(2))->GetSizer(); if (delete_old) { sizerLeft->Clear(true); sizerRight->Clear(true); } else { while (!sizerLeft->IsEmpty()) sizerLeft->Detach(0); while (!sizerRight->IsEmpty()) sizerRight->Detach(0); } sizer = sizerLeft; if (is_filament_list()) { size_t total = (std::accumulate(m_filament_presets.begin(), m_filament_presets.end(), 0, [](size_t t, auto &filament) { return t + filament.second.size() + 1; }) - m_hiden_sizers.size()); for (auto &filament : m_filament_presets) { auto sizer2 = m_filament_sizers[filament.first]; if (m_hiden_sizers.count(sizer2) > 0) continue; size_t count = 1 + std::count_if(filament.second.begin(), filament.second.end(), [this](auto & preset) { return m_hiden_sizers.count(m_preset_sizers[preset]) == 0; }); if (sizer == sizerLeft) { size_t diff = std::abs(int(total - count * 2)); if (diff > std::abs(int(total))) sizer = sizerRight; else total -= count * 2; } sizer->Add(sizer2, 0, wxEXPAND); } } else { auto & presets = m_presets[m_collection]; size_t total = (presets.size() - m_hiden_sizers.size() + 1) / 2; for (auto &preset : presets) { auto sizer2 = m_preset_sizers[preset]; if (m_hiden_sizers.count(sizer2) > 0) continue; sizer->Add(sizer2, 0, wxEXPAND); if (--total == 0) sizer = sizerRight; } } bool is_empty = sizerLeft->IsEmpty() && sizerRight->IsEmpty(); m_scrolled->Show(!is_empty); m_empty_panel->Show(is_empty); m_scrolled->Layout(); m_empty_panel->Layout(); } void UserPresetsDialog::on_dpi_changed(const wxRect &suggested_rect) { SetMinSize({FromDIP(788), -1}); m_tab_ctrl->Rescale(); m_switch_button->SetMaxSize({FromDIP(182), -1}); m_switch_button->Rescale(); m_search->SetSize({FromDIP(568), FromDIP(24)}); m_search->SetCornerRadius(FromDIP(12)); m_scrolled->SetMinSize({-1, FromDIP(320)}); m_scrolled->SetMaxSize({-1, FromDIP(320)}); for (auto sizer : m_preset_sizers) { auto *label = dynamic_cast