From 27aac2411d2226f43a7016489ee7cc430fe31590 Mon Sep 17 00:00:00 2001 From: Grinch_ Date: Sun, 18 Sep 2022 01:30:36 +0600 Subject: [PATCH] Add clipping support to DataList --- src/utils/resourcestore.cpp | 54 +++++++++++-- src/utils/resourcestore.h | 12 ++- src/utils/widget.cpp | 154 ++++++++++++++++-------------------- src/utils/widget.h | 5 +- 4 files changed, 130 insertions(+), 95 deletions(-) diff --git a/src/utils/resourcestore.cpp b/src/utils/resourcestore.cpp index 7ac3dfb..c72d6ec 100644 --- a/src/utils/resourcestore.cpp +++ b/src/utils/resourcestore.cpp @@ -16,6 +16,7 @@ ResourceStore::ResourceStore(const char* text, eResourceType type, ImVec2 imageS { m_Categories.push_back(std::string(k.str())); } + UpdateSearchList(); } } @@ -28,13 +29,9 @@ ResourceStore::ResourceStore(const char* text, eResourceType type, ImVec2 imageS Maybe enabling a dx9 flag fixes this? Switch to initScriptsEvent */ - Events::processScriptsEvent += [text, this]() + Events::initGameEvent += [text, this]() { - if (!m_bTexturesLoaded) - { - LoadTextureResource(text); - m_bTexturesLoaded = true; - } + LoadTextureResource(text); }; } } @@ -147,4 +144,49 @@ void ResourceStore::LoadTextureResource(std::string&& name) } while ( pEndDic != (RwTexDictionary*)&pRwTexDictionary->texturesInDict ); } +} + +void ResourceStore::UpdateSearchList(bool favourites) +{ + m_nSearchList.clear(); + if (favourites) + { + for (auto [key, val] : *m_pData->GetTable("Favourites")) + { + std::string label = std::string(key.str()); + if (m_Filter.PassFilter(label.c_str())) + { + std::string data = val.value_or("Unkonwn"); + m_nSearchList.push_back({std::move(std::string("Favourites")), std::move(label), std::move(data)}); + } + } + } + else + { + for (auto [cat, table] : m_pData->Items()) + { + // Don't show favourites in "All" + if (m_Selected == "All" && cat == "Favourites") + { + continue; + } + if (cat.str() == m_Selected || m_Selected == "All") + { + if (!table.as_table()) + { + return; + } + for (auto [key, val] : *table.as_table()->as_table()) + { + std::string label = std::string(key.str()); + if (m_Filter.PassFilter(label.c_str())) + { + std::string data = val.value_or("Unkonwn"); + m_nSearchList.push_back({std::move(std::string(cat.str())), std::move(label), std::move(data)}); + } + } + } + } + } + m_nSearchList.shrink_to_fit(); } \ No newline at end of file diff --git a/src/utils/resourcestore.h b/src/utils/resourcestore.h index 5d81b04..967122a 100644 --- a/src/utils/resourcestore.h +++ b/src/utils/resourcestore.h @@ -52,6 +52,11 @@ enum eResourceType class ResourceStore { private: + struct SearchLookup + { + std::string cat, key, val; + }; + // Loads a image texture from it's path void LoadTextureResource(std::string&& path); @@ -61,13 +66,14 @@ public: std::string m_Selected = "All"; std::string m_FileName; std::unique_ptr m_pData; - std::vector> m_ImagesList; - ImVec2 m_ImageSize; + std::vector m_nSearchList; eResourceType m_Type; - bool m_bTexturesLoaded = false; + ImVec2 m_ImageSize; + std::vector> m_ImagesList; ResourceStore(const char* text, eResourceType type = TYPE_IMAGE, ImVec2 imageSize = ImVec2(64, 64)); RwTexture* FindRwTextureByName(const std::string& name); IDirect3DTexture9** FindTextureByName(const std::string& name); + void UpdateSearchList(bool favourites = false); }; \ No newline at end of file diff --git a/src/utils/widget.cpp b/src/utils/widget.cpp index 675c1b7..0fe1dfa 100644 --- a/src/utils/widget.cpp +++ b/src/utils/widget.cpp @@ -59,10 +59,9 @@ void Widget::Tooltip(const char* text) } } -void Widget::Filter(const char* label, ImGuiTextFilter& filter, const char* hint) +bool Widget::Filter(const char* label, ImGuiTextFilter& filter, const char* hint) { - filter.Draw(label); - + bool state = filter.Draw(label); if (strlen(filter.InputBuf) == 0) { ImDrawList* drawlist = ImGui::GetWindowDrawList(); @@ -73,6 +72,61 @@ void Widget::Filter(const char* label, ImGuiTextFilter& filter, const char* hint drawlist->AddText(min, ImGui::GetColorU32(ImGuiCol_TextDisabled), hint); } + return state; +} + +void Widget::DrawClippedList(ResourceStore& data, fArg3_t clickFunc, bool favourites, bool isEditItem) +{ + // Category box + ImGui::PushItemWidth(favourites ? ImGui::GetWindowContentRegionWidth() : + (ImGui::GetWindowContentRegionWidth() - ImGui::GetStyle().ItemSpacing.x)/2); + + if (!favourites) + { + if (ListBox("##Categories", data.m_Categories, data.m_Selected)) + { + data.UpdateSearchList(favourites); + } + ImGui::SameLine(); + } + + if (Filter("##Filter", data.m_Filter, TEXT("Window.Search"))) + { + data.UpdateSearchList(favourites); + } + ImGui::PopItemWidth(); + + ImGui::Spacing(); + ImGui::BeginChild(1); + + ImGuiListClipper clipper(data.m_nSearchList.size(), ImGui::GetTextLineHeight()); + while (clipper.Step()) + { + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; ++i) + { + std::string &label = data.m_nSearchList[i].key; + std::string &cat = data.m_nSearchList[i].cat; + std::string &val = data.m_nSearchList[i].val; + if (isEditItem) + { +#ifdef GTASA + Widget::EditStat(label.c_str(), std::stoi(val)); +#endif + } + else + { + if (ImGui::MenuItem(label.c_str()) && clickFunc != nullptr) + { + clickFunc(cat, label, val); + } + } + + if (ImGui::IsItemClicked(1)) + { + contextMenu = {cat, label, val, true}; + } + } + } } void Widget::DataList(ResourceStore& data, fArg3_t clickFunc, fArgNone_t addFunc, bool isEditItem) @@ -88,55 +142,7 @@ void Widget::DataList(ResourceStore& data, fArg3_t clickFunc, fArgNone_t addFunc if (ImGui::BeginTabItem(TEXT("Window.Search"))) { ImGui::Spacing(); - // Category box - ImGui::PushItemWidth((ImGui::GetWindowContentRegionWidth() - ImGui::GetStyle().ItemSpacing.x)/2); - Widget::ListBox("##Categories", data.m_Categories, data.m_Selected); - ImGui::SameLine(); - Filter("##Filter", data.m_Filter, TEXT("Window.Search")); - ImGui::PopItemWidth(); - - ImGui::Spacing(); - ImGui::BeginChild(1); - for (auto [k, v] : data.m_pData->Items()) - { - // Don't show favourites in "All" - if (data.m_Selected == "All" && k == "Favourites") - { - continue; - } - - if (k.str() == data.m_Selected || data.m_Selected == "All") - { - for (auto [k2, v2] : v.as_table()->ref()) - { - std::string key = std::string(k2.str()); - if (data.m_Filter.PassFilter(key.c_str())) - { - std::string root = std::string(k.str()); - std::string val = v2.value_or("Unkonwn"); - - if (isEditItem) - { -#ifdef GTASA - Widget::EditStat(key.c_str(), std::stoi(val)); -#endif - } - else - { - if (ImGui::MenuItem(key.c_str()) && clickFunc != nullptr) - { - clickFunc(root, key, val); - } - } - - if (ImGui::IsItemClicked(1)) - { - contextMenu = {root, key, val, true}; - } - } - } - } - } + DrawClippedList(data, clickFunc, false, isEditItem); if (contextMenu.show) { if (ImGui::BeginPopupContextWindow()) @@ -156,6 +162,7 @@ void Widget::DataList(ResourceStore& data, fArg3_t clickFunc, fArgNone_t addFunc data.m_pData->RemoveKey("Custom", contextMenu.key.c_str()); data.m_pData->RemoveKey("Favourites", contextMenu.key.c_str()); data.m_pData->Save(); + data.UpdateSearchList(); Util::SetMessage(TEXT("Window.RemoveEntry")); } else @@ -174,42 +181,14 @@ void Widget::DataList(ResourceStore& data, fArg3_t clickFunc, fArgNone_t addFunc ImGui::EndChild(); ImGui::EndTabItem(); } + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) + { + data.UpdateSearchList(); + } if (ImGui::BeginTabItem(TEXT("Window.FavouritesTab"))) { ImGui::Spacing(); - ImGui::PushItemWidth(ImGui::GetWindowContentRegionWidth()); - Filter("##Filter", data.m_Filter, TEXT("Window.Search")); - ImGui::PopItemWidth(); - ImGui::Spacing(); - ImGui::BeginChild(1); - for (auto [k, v] : *data.m_pData->GetTable("Favourites")) - { - std::string key = std::string(k.str()); - if (data.m_Filter.PassFilter(key.c_str())) - { - std::string val = v.value_or("Unkonwn"); - - if (isEditItem) - { -#ifdef GTASA - Widget::EditStat(key.c_str(), std::stoi(val)); -#endif - } - else - { - if (ImGui::MenuItem(key.c_str()) && clickFunc != nullptr) - { - std::string str = "Favourites"; - clickFunc(str, key, val); - } - } - - if (ImGui::IsItemClicked(1)) - { - contextMenu = {std::string("Favourites"), key, val, true}; - } - } - } + DrawClippedList(data, clickFunc, true, isEditItem); if (data.m_pData->GetTable("Favourites")->size() == 0) { Widget::TextCentered(TEXT("Menu.FavouritesNone")); @@ -224,6 +203,7 @@ void Widget::DataList(ResourceStore& data, fArg3_t clickFunc, fArgNone_t addFunc { data.m_pData->RemoveKey("Favourites", contextMenu.key.c_str()); data.m_pData->Save(); + data.UpdateSearchList(true); Util::SetMessage(TEXT("Menu.FavouritesRemoveText")); } if (ImGui::MenuItem(TEXT("Menu.Close"))) @@ -237,6 +217,10 @@ void Widget::DataList(ResourceStore& data, fArg3_t clickFunc, fArgNone_t addFunc ImGui::EndChild(); ImGui::EndTabItem(); } + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) + { + data.UpdateSearchList(true); + } if (addFunc) { if (ImGui::BeginTabItem(TEXT("Window.AddNew"))) diff --git a/src/utils/widget.h b/src/utils/widget.h index 5b6e8f2..6ceaa13 100644 --- a/src/utils/widget.h +++ b/src/utils/widget.h @@ -43,6 +43,9 @@ public: // Draws DataStore data in the interface static void DataList(ResourceStore& data, fArg3_t clickFunc = nullptr, fArgNone_t addFunc = nullptr, bool isEditItem = false); + // Draws listed data, used in DataList + static void DrawClippedList(ResourceStore& data, fArg3_t clickFunc = nullptr, bool favourites = false, bool isEditItem = false); + // Draws a dropdown editor for memory address template static void EditAddr(const char* label, uint address, int min = 0, int def = 0, int max = 100); @@ -62,7 +65,7 @@ public: #endif // ImGui::TextFilter with hint support - static void Filter(const char* label, ImGuiTextFilter& filter, const char* hint); + static bool Filter(const char* label, ImGuiTextFilter& filter, const char* hint); // Input widgets with increment & decrement buttons static bool InputFloat(const char* label, float *val, float change = 1.0f, float min = -1.0f, float max = -1.0f);