From 07411e795c7df493996db649102ce6c9be95798c Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 22 Apr 2020 15:46:23 +0200 Subject: [PATCH] Search: Implemented SearchDialog. Search window on Plater: set flag SelectAll for search line --- src/slic3r/GUI/ImGuiWrapper.cpp | 2 +- src/slic3r/GUI/KBShortcutsDialog.cpp | 1 + src/slic3r/GUI/MainFrame.cpp | 5 + src/slic3r/GUI/Plater.cpp | 21 ++ src/slic3r/GUI/Plater.hpp | 1 + src/slic3r/GUI/Search.cpp | 322 ++++++++++++++------------- src/slic3r/GUI/Search.hpp | 75 ++++--- src/slic3r/GUI/Tab.cpp | 7 +- src/slic3r/GUI/Tab.hpp | 2 +- 9 files changed, 241 insertions(+), 195 deletions(-) diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 435dfbe60..f9437ed61 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -640,7 +640,7 @@ void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, co // The press on Esc key invokes editing of InputText (removes last changes) // So we should save previous value... std::string str = search_str; - ImGui::InputTextEx("", NULL, search_str, 20, search_size, 0, NULL, NULL); + ImGui::InputTextEx("", NULL, search_str, 20, search_size, ImGuiInputTextFlags_AutoSelectAll, NULL, NULL); edited = ImGui::IsItemEdited(); if (edited) view_params.hovered_id = -1; diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index 79a6cad20..9f31d23d8 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -134,6 +134,7 @@ void KBShortcutsDialog::fill_shortcuts() { ctrl + "C", L("Copy to clipboard") }, { ctrl + "V", L("Paste from clipboard") }, { "F5", L("Reload plater from disk") }, + { ctrl + "F", L("Search") }, // Window { ctrl + "1", L("Select Plater Tab") }, { ctrl + "2", L("Select Print Settings Tab") }, diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index c4a6f09b7..5ea137f01 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -732,6 +732,11 @@ void MainFrame::init_menubar() append_menu_item(editMenu, wxID_ANY, _(L("Re&load from disk")) + sep + "F5", _(L("Reload the plater from disk")), [this](wxCommandEvent&) { m_plater->reload_all_from_disk(); }, "", nullptr, [this]() {return !m_plater->model().objects.empty(); }, this); + + editMenu->AppendSeparator(); + append_menu_item(editMenu, wxID_ANY, _(L("Searc&h")) + "\t" + GUI::shortkey_ctrl_prefix() + "F", + _(L("Find option")), [this](wxCommandEvent&) { m_plater->search(m_tabpanel->GetCurrentPage() == m_plater); }, + "search", nullptr, [this]() {return true; }, this); } // Window menu diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index f79ebec27..5263dd64d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -5713,6 +5713,27 @@ void Plater::paste_from_clipboard() p->view3D->get_canvas3d()->get_selection().paste_from_clipboard(); } +void Plater::search(bool plater_is_active) +{ + if (plater_is_active) { + wxKeyEvent evt; +#ifdef __APPLE__ + evt.m_keyCode = 'f'; +#else /* __APPLE__ */ + evt.m_keyCode = WXK_CONTROL_F; +#endif /* __APPLE__ */ + evt.SetControlDown(true); + canvas3D()->on_char(evt); + } + else + { + wxPoint pos = this->ClientToScreen(wxPoint(0, 0)); + pos.x += em_unit(this) * 40; + pos.y += em_unit(this) * 4; + p->sidebar->get_searcher().search_dialog->Popup(pos); + } +} + void Plater::msw_rescale() { p->preview->msw_rescale(); diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 33a279ed6..52903525a 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -284,6 +284,7 @@ public: void copy_selection_to_clipboard(); void paste_from_clipboard(); + void search(bool plater_is_active); bool can_delete() const; bool can_delete_all() const; diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index eb62b8a3f..9ef8aa0d0 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -281,6 +281,17 @@ bool OptionsSearcher::search(const std::string& search, bool force/* = false*/) return true; } +OptionsSearcher::OptionsSearcher() +{ + search_dialog = new SearchDialog(this); +} + +OptionsSearcher::~OptionsSearcher() +{ + if (search_dialog) + search_dialog->Destroy(); +} + void OptionsSearcher::init(std::vector input_values) { options.clear(); @@ -499,200 +510,195 @@ void SearchCtrl::OnLeftUpInTextCtrl(wxEvent &event) //------------------------------------------ -// PopupSearchList +// SearchDialog //------------------------------------------ -PopupSearchList::PopupSearchList(wxWindow* parent) : - wxPopupTransientWindow(parent, /*wxSTAY_ON_TOP*/wxWANTS_CHARS | wxBORDER_NONE) +SearchDialog::SearchDialog(OptionsSearcher* searcher) + : GUI::DPIDialog(NULL, wxID_ANY, _L("Search"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), + searcher(searcher) { - panel = new wxPanel(this, wxID_ANY); + SetFont(GUI::wxGetApp().normal_font()); + wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); + SetBackgroundColour(bgr_clr); - text = new wxTextCtrl(panel, 1); - list = new wxListBox(panel, 2, wxDefaultPosition, wxSize(GUI::wxGetApp().em_unit() * 40, -1)); - check = new wxCheckBox(panel, 3, "Group"); + default_string = _L("Type here to search"); + int border = 10; + + search_line = new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize); + + // wxWANTS_CHARS style is neede for process Enter key press + search_list = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(em_unit() * 40, em_unit() * 30), 0, NULL, wxWANTS_CHARS); + + wxBoxSizer* check_sizer = new wxBoxSizer(wxHORIZONTAL); + + check_type = new wxCheckBox(this, wxID_ANY, _L("Type")); + check_category = new wxCheckBox(this, wxID_ANY, _L("Category")); + check_group = new wxCheckBox(this, wxID_ANY, _L("Group")); + + wxStdDialogButtonSizer* cancel_btn = this->CreateStdDialogButtonSizer(wxCANCEL); + + check_sizer->Add(check_type, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, border); + check_sizer->Add(check_category, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, border); + check_sizer->Add(check_group, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, border); + check_sizer->AddStretchSpacer(border); + check_sizer->Add(cancel_btn, 0, wxALIGN_CENTER_VERTICAL); wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); - text->Bind(wxEVT_MOUSE_CAPTURE_CHANGED, [](wxEvent& e) { - int i = 0; }); + topSizer->Add(search_line, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border); + topSizer->Add(search_list, 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border); + topSizer->Add(check_sizer, 0, wxEXPAND | wxALL, border); -// text->Bind(wxEVT_LEFT_DOWN, [this](wxEvent& e) { - text->Bind(wxEVT_LEFT_UP, [this](wxEvent& e) { - text->SetValue("mrrrrrty"); - }); + search_line->Bind(wxEVT_TEXT, &SearchDialog::OnInputText, this); + search_line->Bind(wxEVT_LEFT_UP, &SearchDialog::OnLeftUpInTextCtrl, this); + // process wxEVT_KEY_DOWN to navigate inside search_list, if ArrowUp/Down was pressed + search_line->Bind(wxEVT_KEY_DOWN,&SearchDialog::OnKeyDown, this); - text->Bind(wxEVT_MOTION, [this](wxMouseEvent& evt) - { - wxPoint pt = wxGetMousePosition() - text->GetScreenPosition(); - long pos; - text->HitTest(pt, &pos); + search_list->Bind(wxEVT_MOTION, &SearchDialog::OnMouseMove, this); + search_list->Bind(wxEVT_LEFT_UP, &SearchDialog::OnMouseClick, this); + search_list->Bind(wxEVT_KEY_DOWN,&SearchDialog::OnKeyDown, this); - if (pos == wxTE_HT_UNKNOWN) - return; + check_type ->Bind(wxEVT_CHECKBOX, &SearchDialog::OnCheck, this); + check_category->Bind(wxEVT_CHECKBOX, &SearchDialog::OnCheck, this); + check_group ->Bind(wxEVT_CHECKBOX, &SearchDialog::OnCheck, this); - list->SetSelection(wxNOT_FOUND); - text->SetSelection(0, pos); - }); + this->Bind(wxEVT_LISTBOX, &SearchDialog::OnSelect, this); - text->Bind(wxEVT_TEXT, [this](wxCommandEvent& e) - { - text->SetSelection(0, 3); - }); - - this->Bind(wxEVT_KEY_DOWN, [this](wxKeyEvent& event) { - int key = event.GetKeyCode(); - - // change selected item in the list - if (key == WXK_UP || key == WXK_DOWN) - { - int selection = list->GetSelection(); - - if (key == WXK_UP && selection > 0) - selection--; - if (key == WXK_DOWN && selection < int(list->GetCount() - 1)) - selection++; - - list->Select(selection); - } - else - event.Skip(); // !Needed to have EVT_CHAR generated as well - }); - - this->Bind(wxEVT_CHAR, [this](wxKeyEvent& e) { - int key = e.GetKeyCode(); - wxChar symbol = e.GetUnicodeKey(); - search_str += symbol; - - text->SetValue(search_str); - }); - - - list->Append("One"); - list->Append("Two"); - list->Append("Three"); - - list->Bind(wxEVT_LISTBOX, [this](wxCommandEvent& evt) - { - int selection = list->GetSelection(); - }); - - list->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent& evt) - { - int selection = list->GetSelection(); - list->SetSelection(wxNOT_FOUND); - - wxCommandEvent event(wxEVT_LISTBOX, list->GetId()); - event.SetInt(selection); - event.SetEventObject(this); - ProcessEvent(event); - - Dismiss(); - }); - - list->Bind(wxEVT_MOTION, [this](wxMouseEvent& evt) - { - wxPoint pt = wxGetMousePosition() - list->GetScreenPosition(); - int selection = list->HitTest(pt); - list->Select(selection); - }); - - list->Bind(wxEVT_KEY_DOWN, [this](wxKeyEvent& event) { - int key = event.GetKeyCode(); - - // change selected item in the list - if (key == WXK_UP || key == WXK_DOWN) - { - int selection = list->GetSelection(); - - if (key == WXK_UP && selection > 0) - selection--; - if (key == WXK_DOWN && selection < int(list->GetCount() - 1)) - selection++; - - list->Select(selection); - } - // send wxEVT_LISTBOX event if "Enter" was pushed - else if (key == WXK_NUMPAD_ENTER || key == WXK_RETURN) - { - int selection = list->GetSelection(); - - wxCommandEvent event(wxEVT_LISTBOX, list->GetId()); - event.SetInt(selection); - event.SetEventObject(this); - ProcessEvent(event); - - Dismiss(); - } - else - event.Skip(); // !Needed to have EVT_CHAR generated as well - }); - - topSizer->Add(text, 0, wxEXPAND | wxALL, 2); - topSizer->Add(list, 0, wxEXPAND | wxALL, 2); - topSizer->Add(check, 0, wxEXPAND | wxALL, 2); - - panel->SetSizer(topSizer); - - topSizer->Fit(panel); - SetClientSize(panel->GetSize()); + SetSizer(topSizer); + topSizer->SetSizeHints(this); } -void PopupSearchList::Popup(wxWindow* WXUNUSED(focus)) +void SearchDialog::Popup(wxPoint position /*= wxDefaultPosition*/) { - wxPopupTransientWindow::Popup(); + const std::string& line = searcher->search_string(); + search_line->SetValue(line.empty() ? default_string : from_u8(line)); + search_line->SetFocus(); + search_line->SelectAll(); + + update_list(); + + const OptionViewParameters& params = searcher->view_params; + check_type->SetValue(params.type); + check_category->SetValue(params.category); + check_group->SetValue(params.group); + + this->SetPosition(position); + this->ShowModal(); } -void PopupSearchList::OnDismiss() +void SearchDialog::ProcessSelection(int selection) { - wxPopupTransientWindow::OnDismiss(); + if (selection < 0) + return; + + GUI::wxGetApp().sidebar().jump_to_option(selection); + this->EndModal(wxID_CLOSE); } -bool PopupSearchList::ProcessLeftDown(wxMouseEvent& event) +void SearchDialog::OnInputText(wxCommandEvent&) { - return wxPopupTransientWindow::ProcessLeftDown(event); -} -bool PopupSearchList::Show(bool show) -{ - return wxPopupTransientWindow::Show(show); + search_line->SetInsertionPointEnd(); + + wxString input_string = search_line->GetValue(); + if (input_string == default_string) + input_string.Clear(); + + GUI::wxGetApp().sidebar().get_search_line() = into_u8(input_string); + + GUI::wxGetApp().sidebar().search_and_apply_tab_search_lines(); + + update_list(); } -void PopupSearchList::OnSize(wxSizeEvent& event) +void SearchDialog::OnLeftUpInTextCtrl(wxEvent& event) { + if (search_line->GetValue() == default_string) + search_line->SetValue(""); + event.Skip(); } -void PopupSearchList::OnSetFocus(wxFocusEvent& event) +void SearchDialog::OnMouseMove(wxMouseEvent& event) { - event.Skip(); + wxPoint pt = wxGetMousePosition() - search_list->GetScreenPosition(); + int selection = search_list->HitTest(pt); + search_list->Select(selection); } -void PopupSearchList::OnKillFocus(wxFocusEvent& event) +void SearchDialog::OnMouseClick(wxMouseEvent&) { - event.Skip(); + int selection = search_list->GetSelection(); + search_list->SetSelection(wxNOT_FOUND); + + wxCommandEvent event(wxEVT_LISTBOX, search_list->GetId()); + event.SetInt(selection); + event.SetEventObject(search_list); + ProcessEvent(event); } - -//------------------------------------------ -// SearchCtrl -//------------------------------------------ - -SearchButton::SearchButton(wxWindow* parent) : - ScalableButton(parent, wxID_ANY, "search") +void SearchDialog::OnSelect(wxCommandEvent& event) { - popup_win = new PopupSearchList(parent); - this->Bind(wxEVT_BUTTON, &SearchButton::PopupSearch, this); + int selection = event.GetSelection(); + ProcessSelection(selection); } - -void SearchButton::PopupSearch(wxCommandEvent& e) + +void SearchDialog::update_list() { -// popup_win->update_list(wxGetApp().sidebar().get_search_list().filters); - wxPoint pos = this->ClientToScreen(wxPoint(0, 0)); - wxSize sz = wxSize(GUI::wxGetApp().em_unit()*40, -1); - pos.x -= sz.GetWidth(); - pos.y += this->GetSize().y; - popup_win->Position(pos, sz); - popup_win->Popup(); - e.Skip(); + search_list->Clear(); + + const std::vector& filters = searcher->found_options(); + for (const FoundOption& item : filters) + search_list->Append(item.label); +} + +void SearchDialog::OnKeyDown(wxKeyEvent& event) +{ + int key = event.GetKeyCode(); + + // change selected item in the list + if (key == WXK_UP || key == WXK_DOWN) + { + int selection = search_list->GetSelection(); + + if (key == WXK_UP && selection > 0) + selection--; + if (key == WXK_DOWN && selection < int(search_list->GetCount() - 1)) + selection++; + + search_list->Select(selection); + // This function could be called from search_line, + // So, for the next correct navigation, set focus on the search_list + search_list->SetFocus(); + } + // process "Enter" pressed + else if (key == WXK_NUMPAD_ENTER || key == WXK_RETURN) + ProcessSelection(search_list->GetSelection()); + else + event.Skip(); // !Needed to have EVT_CHAR generated as well +} + +void SearchDialog::OnCheck(wxCommandEvent& event) +{ + OptionViewParameters& params = searcher->view_params; + params.type = check_type->GetValue(); + params.category = check_category->GetValue(); + params.group = check_group->GetValue(); + + searcher->search(searcher->search_string(), true); + update_list(); +} + +void SearchDialog::on_dpi_changed(const wxRect& suggested_rect) +{ + const int& em = em_unit(); + + msw_buttons_rescale(this, em, { wxID_CANCEL }); + + const wxSize& size = wxSize(40 * em, 30 * em); + SetMinSize(size); + + Fit(); + Refresh(); } diff --git a/src/slic3r/GUI/Search.hpp b/src/slic3r/GUI/Search.hpp index 7933527af..e7c1f6f58 100644 --- a/src/slic3r/GUI/Search.hpp +++ b/src/slic3r/GUI/Search.hpp @@ -10,9 +10,10 @@ #include -#include #include +#include +#include "GUI_Utils.hpp" #include "Preset.hpp" #include "wxExtensions.hpp" @@ -21,6 +22,8 @@ namespace Slic3r { namespace Search{ +class SearchDialog; + struct InputInfo { DynamicPrintConfig* config {nullptr}; @@ -112,6 +115,11 @@ class OptionsSearcher public: OptionViewParameters view_params; + SearchDialog* search_dialog { nullptr }; + + OptionsSearcher(); + ~OptionsSearcher(); + void init(std::vector input_values); void apply(DynamicPrintConfig *config, Preset::Type type, @@ -127,6 +135,7 @@ public: const std::vector& found_options() { return found; } const GroupAndCategory& get_group_and_category (const std::string& opt_key) { return groups_and_categories[opt_key]; } + const std::string& search_string() { return search_line; } }; @@ -187,44 +196,46 @@ public: }; +//------------------------------------------ +// SearchDialog +//------------------------------------------ -class PopupSearchList : public wxPopupTransientWindow +class SearchDialog : public GUI::DPIDialog { - wxString search_str; + wxString search_str; + wxString default_string; + + wxTextCtrl* search_line { nullptr }; + wxListBox* search_list { nullptr }; + wxCheckBox* check_type { nullptr }; + wxCheckBox* check_category { nullptr }; + wxCheckBox* check_group { nullptr }; + + OptionsSearcher* searcher; + + void update_list(); + + void OnInputText(wxCommandEvent& event); + void OnLeftUpInTextCtrl(wxEvent& event); + + void OnMouseMove(wxMouseEvent& event); + void OnMouseClick(wxMouseEvent& event); + void OnSelect(wxCommandEvent& event); + void OnKeyDown(wxKeyEvent& event); + + void OnCheck(wxCommandEvent& event); + public: - PopupSearchList(wxWindow* parent); - ~PopupSearchList() {} + SearchDialog(OptionsSearcher* searcher); + ~SearchDialog() {} - // wxPopupTransientWindow virtual methods are all overridden to log them - void Popup(wxWindow* focus = NULL) wxOVERRIDE; - void OnDismiss() wxOVERRIDE; - bool ProcessLeftDown(wxMouseEvent& event) wxOVERRIDE; - bool Show(bool show = true) wxOVERRIDE; + void Popup(wxPoint position = wxDefaultPosition); + void ProcessSelection(int selection); -private: - wxWindow* panel; - - wxTextCtrl* text {nullptr}; - wxListBox* list{ nullptr }; - wxCheckBox* check {nullptr}; - - void OnSize(wxSizeEvent& event); - void OnSetFocus(wxFocusEvent& event); - void OnKillFocus(wxFocusEvent& event); +protected: + void on_dpi_changed(const wxRect& suggested_rect) override; }; -class SearchButton : public ScalableButton -{ - PopupSearchList* popup_win{ nullptr }; - - void PopupSearch(wxCommandEvent& event); -public: - SearchButton(wxWindow* parent); - ~SearchButton() {} -}; - - - } // Search namespace } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 1dc25ed2f..9be89005a 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -160,8 +160,6 @@ void Tab::create_preset_tab() // search combox m_search = new Search::SearchCtrl(panel); - // search combox - m_search_btn = new Search::SearchButton(panel); auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); @@ -184,10 +182,12 @@ void Tab::create_preset_tab() m_btn_delete_preset->Disable(); add_scaled_button(panel, &m_question_btn, "question"); - m_question_btn->SetToolTip(_(L("Hover the cursor over buttons to find more information \n" "or click this button."))); + add_scaled_button(panel, &m_search_btn, "search"); + m_question_btn->SetToolTip(_L("Find option")); + // Determine the theme color of OS (dark or light) auto luma = wxGetApp().get_colour_approx_luma(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); // Bitmaps to be shown on the "Revert to system" aka "Lock to system" button next to each input field. @@ -218,6 +218,7 @@ void Tab::create_preset_tab() } } })); + m_search_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent) { wxGetApp().plater()->search(false); }); // Colors for ui "decoration" m_sys_label_clr = wxGetApp().get_label_clr_sys(); diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 3b9717ccb..90eb2b6bb 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -123,7 +123,7 @@ protected: const wxString m_title; PresetBitmapComboBox* m_presets_choice; Search::SearchCtrl* m_search; - Search::SearchButton* m_search_btn; + ScalableButton* m_search_btn; ScalableButton* m_btn_save_preset; ScalableButton* m_btn_delete_preset; ScalableButton* m_btn_hide_incompatible_presets;