Files
OrcaSlicer/src/slic3r/GUI/Widgets/CheckList.cpp
yw4z b4aa070c40 MultiChooseDialog & CheckList class & improvements for Profile Dependencies (#9971)
* init

* fix

* fix

* update

* update

* update

* Update Tab.cpp

* Update CheckList.cpp
2026-05-18 19:46:47 +08:00

225 lines
7.5 KiB
C++

#include "CheckList.hpp"
#include "slic3r/GUI/GUI_App.hpp"
CheckList::CheckList(
wxWindow* parent,
const wxArrayString& choices,
long scroll_style
)
: wxWindow(parent, wxID_ANY)
, m_search(this, "search", 16)
, m_menu(this, "filter", 16)
, m_first_load(true)
{
Freeze();
w_sizer = new wxBoxSizer(wxVERTICAL);
f_sizer = new wxBoxSizer(wxHORIZONTAL);
f_bar = new wxPanel(this, wxID_ANY);
f_bar->SetBackgroundColour(parent->GetBackgroundColour());
m_filter_box = new TextInput(f_bar, "", "", "", wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
m_filter_box->SetIcon(m_search.bmp());
m_filter_box->SetMinSize(FromDIP(wxSize(200,24)));
m_filter_box->SetSize(FromDIP(wxSize(-1,24)));
m_filter_box->SetFocus();
m_filter_ctrl = m_filter_box->GetTextCtrl();
m_filter_ctrl->SetFont(Label::Body_13);
m_filter_ctrl->SetSize(wxSize(-1, FromDIP(16))); // Centers text vertically
m_filter_ctrl->SetHint(_L("Type to filter..."));
m_filter_ctrl->Bind(wxEVT_TEXT, [this](auto &e) {Filter(m_filter_ctrl->GetValue());});
m_filter_ctrl->Bind(wxEVT_TEXT_ENTER, [this](auto &e) {Filter(m_filter_ctrl->GetValue());});
m_filter_ctrl->Bind(wxEVT_SET_FOCUS, [this](auto &e) {Filter(m_filter_ctrl->GetValue());e.Skip();});
m_filter_ctrl->Bind(wxEVT_KILL_FOCUS, [this](auto &e) {Filter(m_filter_ctrl->GetValue());e.Skip();});
f_sizer->Add(m_filter_box, 1, wxEXPAND);
Bind(wxEVT_SET_FOCUS, [this](auto &e) {m_filter_box->SetFocus();});
fb_sizer = new wxBoxSizer(wxHORIZONTAL);
auto create_btn = [this] (wxString title, bool select){
auto btn = new wxStaticText(f_bar, wxID_ANY, title);
btn->SetForegroundColour("#009687");
btn->SetCursor(wxCURSOR_HAND);
btn->SetFont(Label::Body_13);
btn->Bind(wxEVT_LEFT_DOWN, [this, select](wxMouseEvent &e) {SelectAll(select);});
fb_sizer->Add(btn, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, FromDIP(10));
};
f_sizer->Add(fb_sizer,0 ,wxALIGN_CENTER_VERTICAL);
create_btn(_L("All") , true);
create_btn(_L("None"), false);
m_menu_button = new wxStaticBitmap(f_bar, wxID_ANY, m_menu.bmp());
m_menu_button->SetCursor(wxCURSOR_HAND);
m_menu_button->Bind(wxEVT_LEFT_DOWN, &CheckList::ShowMenu, this);
f_sizer->Add(m_menu_button,0 ,wxLEFT | wxALIGN_CENTER_VERTICAL, FromDIP(10));
f_bar->SetSizerAndFit(f_sizer);
w_sizer->Add(f_bar, 0, wxEXPAND);
auto spacer = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, FromDIP(3)));
spacer->SetBackgroundColour(parent->GetBackgroundColour());
w_sizer->Add(spacer, 0, wxEXPAND);
s_sizer = new wxBoxSizer(wxVERTICAL);
m_scroll_area = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, scroll_style);
m_scroll_area->SetScrollRate(0, 10);
m_scroll_area->SetSizer(s_sizer);
m_scroll_area->SetBackgroundColour(parent->GetBackgroundColour());
m_scroll_area->Bind(wxEVT_RIGHT_DOWN, &CheckList::ShowMenu, this);
m_scroll_area->DisableFocusFromKeyboard();
m_info = new wxStaticText(m_scroll_area, wxID_ANY, "");
m_info->SetFont(Label::Body_13);
s_sizer->Add(m_info, 1, wxALIGN_CENTER_HORIZONTAL | wxALL, FromDIP(10));
m_info->Hide();
m_info_nonsel = _L("No selected items...");
m_info_allsel = _L("All items selected...");
m_info_empty = _L("No matching items...");
SetBackgroundColour(StateColor::darkModeColorFor("#DBDBDB")); // draws border on wxScrolledWindow
w_sizer->Add(m_scroll_area, 1, wxEXPAND | wxALL, FromDIP(1)); // 1 for border
s_sizer->Layout();
m_list_size = choices.size();
m_checks.reserve(m_list_size);
auto margin = FromDIP(2);
wxCheckBox* cb;
for (size_t i = 0; i < m_list_size; ++i){
cb = new wxCheckBox(m_scroll_area, wxID_ANY, choices[i]);
m_checks.emplace_back(cb);
s_sizer->Add(cb, 0, wxALL, margin);
}
m_scroll_area->FitInside();
s_sizer->Layout();
SetSizer(w_sizer);
Layout();
Thaw();
}
void CheckList::SetSelections(wxArrayInt sel_array){
if(!m_first_load){
for (size_t i = 0; i < m_list_size; ++i)
Check(i, false);
m_first_load = false;
}
for (int i : sel_array)
Check(i, true);
}
wxArrayInt CheckList::GetSelections()
{
wxArrayInt checks;
for (size_t i = 0; i < m_list_size; ++i)
if (m_checks[i]->GetValue())
checks.push_back(i);
return checks;
}
void CheckList::Check(int i, bool checked)
{
if (i > -1 && i < m_list_size)
m_checks[i]->SetValue(checked);
}
void CheckList::SelectAll(bool value)
{
for (size_t i = 0; i < m_list_size; ++i)
Check(i, value);
}
void CheckList::SelectVisible(bool value)
{
auto filter = m_filter_ctrl->GetValue().Lower();
if((!value && filter == "::unsel") || (value && filter == "::sel"))
m_filter_ctrl->SetValue("");
for (size_t i = 0; i < m_list_size; ++i)
if(m_checks[i]->IsShown())
Check(i, value);
}
bool CheckList::IsChecked(int i)
{
if (i > -1 && i < m_list_size)
return false;
return m_checks[i]->GetValue();
}
void CheckList::Filter(const wxString& filterText)
{
Freeze();
auto filter = filterText.Lower();
auto c_text = m_filter_ctrl->GetValue().Lower();
if(filter == "::sel" || filter == "::nonsel"){
if(c_text != filter){ // not text input
m_filter_ctrl->SetValue(filter);
m_filter_ctrl->SetSelection(0,-1);
}
fb_sizer->Show(false);
if (filter == "::sel")
for (auto& cb : m_checks) cb->Show(cb->GetValue());
else
for (auto& cb : m_checks) cb->Show(!cb->GetValue());
}
else{
bool clear = filterText.IsEmpty();
fb_sizer->Show(clear);
for (auto& cb : m_checks)
cb->Show(clear || cb->GetLabel().Lower().Contains(filter));
}
m_info->Show();
for (size_t i = 0; i < m_list_size; ++i) {
if (m_checks[i]->IsShown()){
m_info->Hide();
break;
}
}
if (m_info->IsShown())
m_info->SetLabel(filter == "::sel" ? m_info_nonsel : filter == "::nonsel" ? m_info_allsel : m_info_empty);
m_scroll_area->FitInside();
f_sizer->Layout();
Thaw();
}
void CheckList::ShowMenu(wxMouseEvent &evt)
{
bool filtering = !m_filter_ctrl->GetValue().IsEmpty();
bool list_empty = m_info->IsShown();
wxMenu m;
m.Append(wxID_FILE1, _L("Select All" ))->Enable(!filtering);
m.Append(wxID_FILE2, _L("Deselect All"))->Enable(!filtering);
m.AppendSeparator();
m.Append(wxID_FILE3, _L("Select visible" ))->Enable(!list_empty && filtering);
m.Append(wxID_FILE4, _L("Deselect visible"))->Enable(!list_empty && filtering);
m.AppendSeparator();
m.Append(wxID_FILE5, _L("Filter selected" ));
m.Append(wxID_FILE6, _L("Filter nonSelected"));
m.Bind(wxEVT_MENU, [this](wxCommandEvent& e) {
switch (e.GetId()){
case wxID_FILE1: SelectAll(true) ; break;
case wxID_FILE2: SelectAll(false) ; break;
case wxID_FILE3: SelectVisible(true) ; break;
case wxID_FILE4: SelectVisible(false); break;
case wxID_FILE5: Filter("::sel") ; break;
case wxID_FILE6: Filter("::nonsel") ; break;
default: break;
}
},wxID_FILE1, wxID_FILE6);
wxWindow* src = dynamic_cast<wxWindow*>(evt.GetEventObject());
if (!src) return;
wxPoint screen_pos = src->ClientToScreen(evt.GetPosition());
wxPoint local_pos = ScreenToClient(screen_pos);
PopupMenu(&m, local_pos);
}