From 3b88dc26886fa15a17423ed6123270532aa7be89 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 20 Apr 2020 17:37:03 +0200 Subject: [PATCH] Search: Implemented cursor movement inside SearchWindow on Plater --- src/slic3r/GUI/GLCanvas3D.cpp | 9 ++- src/slic3r/GUI/GLCanvas3D.hpp | 1 + src/slic3r/GUI/ImGuiWrapper.cpp | 105 ++++++++++++++++++++++++++++++-- src/slic3r/GUI/ImGuiWrapper.hpp | 2 +- src/slic3r/GUI/Search.hpp | 3 +- 5 files changed, 110 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index fff0ae21a..64338ce30 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4497,14 +4497,17 @@ bool GLCanvas3D::_render_search_list(float pos_x) const strcpy(s, search_line.empty() ? _u8L("Type here to search").c_str() : search_line.c_str()); imgui->search_list(ImVec2(45 * em, 30 * em), &search_string_getter, s, - sidebar.get_searcher().category, sidebar.get_searcher().group, + sidebar.get_searcher().category, sidebar.get_searcher().group, + m_imgui_search_hovered_pos, selected, edited, check_changed); search_line = s; delete [] s; - if (edited) + if (edited) { sidebar.search_and_apply_tab_search_lines(); + m_imgui_search_hovered_pos = -1; + } if (check_changed) { if (search_line == _u8L("Type here to search")) @@ -5065,7 +5068,7 @@ bool GLCanvas3D::_init_main_toolbar() _deactivate_search_toolbar_item(); } }; - item.left.action_callback = GLToolbarItem::Default_Action_Callback; + item.left.action_callback = [this]() { m_imgui_search_hovered_pos = -1; }; //GLToolbarItem::Default_Action_Callback; item.visibility_callback = GLToolbarItem::Default_Visibility_Callback; item.enabling_callback = GLToolbarItem::Default_Enabling_Callback; if (!m_main_toolbar.add_item(item)) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 60f62636d..2f92012f5 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -505,6 +505,7 @@ private: #endif // ENABLE_RENDER_STATISTICS mutable int m_imgui_undo_redo_hovered_pos{ -1 }; + mutable size_t m_imgui_search_hovered_pos{ size_t(-1) }; int m_selected_extruder; Labels m_labels; diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index a9b51874a..dd071a86d 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -539,8 +539,69 @@ static bool selectable(const char* label, bool selected, ImGuiSelectableFlags fl return pressed; } +// Scroll so that the hovered item is at the top of the window +static void scroll_y(int hover_id) +{ + if (hover_id < 0) + return; + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + float item_size_y = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; + float item_delta = 0.5 * item_size_y; + + float item_top = item_size_y * hover_id; + float item_bottom = item_top + item_size_y; + + float win_top = window->Scroll.y; + float win_bottom = window->Scroll.y + window->Size.y; + + if (item_bottom + item_delta >= win_bottom) + ImGui::SetScrollY(win_top + item_size_y); + else if (item_top - item_delta <= win_top) + ImGui::SetScrollY(win_top - item_size_y); +} + +// Scroll up for one item +static void scroll_up() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + float item_size_y = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; + float win_top = window->Scroll.y; + + ImGui::SetScrollY(win_top - item_size_y); +} + +// Scroll down for one item +static void scroll_down() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + float item_size_y = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; + float win_top = window->Scroll.y; + + ImGui::SetScrollY(win_top + item_size_y); +} + +// Use this function instead of ImGui::IsKeyPressed. +// ImGui::IsKeyPressed is related for *GImGui.IO.KeysDownDuration[user_key_index] +// And after first key pressing IsKeyPressed() return "true" always even if key wasn't pressed +static void process_key_down(ImGuiKey imgui_key, std::function f) +{ + if (ImGui::IsKeyDown(ImGui::GetKeyIndex(imgui_key))) + { + f(); + // set KeysDown to false to avoid redundant key down processing + ImGuiContext& g = *GImGui; + g.IO.KeysDown[ImGui::GetKeyIndex(imgui_key)] = false; + } +} + void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, const char**), char* search_str, - bool& category, bool& group, size_t& selected, bool& edited, bool& check_changed) + bool& category, bool& group, size_t& hovered_id, size_t& selected, bool& edited, bool& check_changed) { // ImGui::ListBoxHeader("", size); { @@ -581,30 +642,64 @@ void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, co ImGui::InputTextEx("", NULL, search_str, 20, search_size, 0, NULL, NULL); edited = ImGui::IsItemEdited(); - if (ImGui::IsItemDeactivated() && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape))) { + process_key_down(ImGuiKey_Escape, [&selected, search_str, str]() { // use 9999 to mark selection as a Esc key selected = 9999; // ... and when Esc key was pressed, than revert search_str value strcpy(search_str, str.c_str()); - } + }); ImGui::BeginChildFrame(id, frame_bb.GetSize()); } size_t i = 0; const char* item_text; + int mouse_hovered = -1; + while (items_getter(i, &item_text)) { - selectable(item_text, false); + selectable(item_text, i == hovered_id); - if (ImGui::IsItemHovered()) + if (ImGui::IsItemHovered()) { ImGui::SetTooltip("%s", item_text); + hovered_id = size_t(-1); + mouse_hovered = i; + } if (ImGui::IsItemClicked()) selected = i; i++; } + scroll_y(mouse_hovered); + + // process Up/DownArrows and Enter + process_key_down(ImGuiKey_UpArrow, [&hovered_id, mouse_hovered]() { + if (mouse_hovered > 0) + scroll_up(); + else { + if (hovered_id > 0 && hovered_id != size_t(-1)) + --hovered_id; + scroll_y(hovered_id); + } + }); + + process_key_down(ImGuiKey_DownArrow, [&hovered_id, mouse_hovered, i]() { + if (mouse_hovered > 0) + scroll_down(); + else { + if (hovered_id == size_t(-1)) + hovered_id = 0; + else if (hovered_id < size_t(i - 1)) + ++hovered_id; + scroll_y(hovered_id); + } + }); + + process_key_down(ImGuiKey_Enter, [&selected, hovered_id]() { + selected = hovered_id; + }); + ImGui::ListBoxFooter(); // add checkboxes for show/hide Categories and Groups diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 781d2a25f..781b6ae4f 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -75,7 +75,7 @@ public: bool combo(const wxString& label, const std::vector& options, int& selection); // Use -1 to not mark any option as selected bool undo_redo_list(const ImVec2& size, const bool is_undo, bool (*items_getter)(const bool, int, const char**), int& hovered, int& selected); void search_list(const ImVec2& size, bool (*items_getter)(int, const char**), char* search_str, - bool& category, bool& group, size_t& selected, bool& edited, bool& check_changed); + bool& category, bool& group, size_t& hovered_id, size_t& selected, bool& edited, bool& check_changed); void disabled_begin(bool disabled); void disabled_end(); diff --git a/src/slic3r/GUI/Search.hpp b/src/slic3r/GUI/Search.hpp index 0d020d8d8..b58d7f7a6 100644 --- a/src/slic3r/GUI/Search.hpp +++ b/src/slic3r/GUI/Search.hpp @@ -10,6 +10,8 @@ #include +#include + #include "Preset.hpp" #include "wxExtensions.hpp" @@ -175,7 +177,6 @@ public: }; -#include class PopupSearchList : public wxPopupTransientWindow {