ArcdpsExtension
 
Loading...
Searching...
No Matches
Widgets.h
Go to the documentation of this file.
1#pragma once
2
3#include "arcdps_structs.h"
5
6#include <algorithm>
7#include <format>
8#include <functional>
9#include <imgui/imgui.h>
10#include <imgui/imgui_internal.h>
11#include <map>
12#include <ranges>
13
14namespace ImGuiEx {
15 bool Spinner(const char* label, float radius, float thickness, const ImU32& color);
16 bool SpinnerAligned(const char* label, float radius, float thickness, const ImU32& color, Alignment alignment);
17 void AlignedTextColumn(Alignment alignment, const char* text, ...);
18 void TableHeader(const char* label, bool show_label, ImTextureID texture, Alignment alignment = Alignment::Left);
19 void AlignedProgressBar(float fraction, const ImVec2& size_arg, const char* overlay, Alignment alignment);
20 bool BeginMenu(const char* label, bool enabled, bool& hovered);
21 void BeginMenuChild(const char* child_str_id, const char* menu_label, std::function<void()> draw_func);
22 void BeginMenu(const char* menu_label, std::function<void()> draw_func);
23 bool BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags, ImGuiHoveredFlags hovered_flags);
24 void MenuItemTableColumnVisibility(ImGuiTable* table, int columnIdx);
25 bool TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags, void* icon);
26
32 bool BeginTable(const char* str_id, int column, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f, ImGuiWindowFlags child_window_flags = 0);
33
43 // returns true if the window moved
44 bool WindowReposition(ImGuiWindow* window, Position position, const ImVec2& cornerVector, CornerPosition cornerPosition, ImGuiID fromWindowID, CornerPosition anchorPanelCornerPosition, CornerPosition selfPanelCornerPosition);
45
49 template<typename E>
50 requires std::is_enum_v<E>
51 bool Selectable(E& storage, E value) {
52 const bool selected = ImGui::Selectable(to_string(value).c_str());
53 if (selected) {
54 storage = value;
55 }
56 return selected;
57 }
58
62 template<typename E, std::ranges::range R>
63 requires(std::is_enum_v<E> && std::same_as<std::ranges::range_value_t<R>, E>)
64 bool EnumCombo(const char* label, E& storage, const R& values, const std::map<E, std::function<const std::string&()>>& pPopupText = {}) {
65 if (ImGui::BeginCombo(label, to_string(storage).c_str())) {
66 bool selected = false;
67 for (const E& val : values) {
68 if (ImGuiEx::Selectable(storage, val)) {
69 selected = true;
70 }
71
72 if (ImGui::IsItemHovered()) {
73 if (const auto& iterator = pPopupText.find(val); iterator != pPopupText.end()) {
74 const auto& second = iterator->second();
75 ImGui::SetTooltip("%s", second.c_str());
76 }
77 }
78 }
79
80 ImGui::EndCombo();
81
82 return selected;
83 }
84
85 return false;
86 }
87
88 template<typename E>
89 requires(std::is_enum_v<E>)
90 bool EnumCombo(const char* label, E& storage, const std::initializer_list<E>& values, const std::map<E, std::function<const std::string&()>>& pPopupText = {}) {
91 if (ImGui::BeginCombo(label, to_string(storage).c_str())) {
92 bool selected = false;
93 for (const E& val : values) {
94 if (ImGuiEx::Selectable(storage, val)) {
95 selected = true;
96 }
97
98 if (ImGui::IsItemHovered()) {
99 if (const auto& iterator = pPopupText.find(val); iterator != pPopupText.end()) {
100 ImGui::SetTooltip("%s", iterator->second().c_str());
101 }
102 }
103 }
104
105 ImGui::EndCombo();
106
107 return selected;
108 }
109
110 return false;
111 }
112
119 template<typename E>
120 requires std::is_enum_v<E>
121 bool EnumCombo(const char* label, E& storage, E lastElement, const std::map<uint64_t, std::function<const std::string&()>>& pPopupText = {}) {
122 if (ImGui::BeginCombo(label, to_string(storage).c_str())) {
123 bool selected = false;
124 for (uint64_t i = 0; i < static_cast<uint64_t>(lastElement); ++i) {
125 if (ImGuiEx::Selectable(storage, static_cast<E>(i))) {
126 selected = true;
127 }
128
129 if (ImGui::IsItemHovered()) {
130 if (const auto& iterator = pPopupText.find(i); iterator != pPopupText.end()) {
131 ImGui::SetTooltip("%s", iterator->second().c_str());
132 }
133 }
134 }
135
136 ImGui::EndCombo();
137
138 return selected;
139 }
140 return false;
141 }
142
143 template<typename E>
144 requires std::is_enum_v<E>
145 bool EnumRadioButton(int& buttonStorage, E value) {
146 return ImGui::RadioButton(to_string(value).c_str(), &buttonStorage, static_cast<int>(value));
147 }
148
149 template<typename E>
150 requires std::is_enum_v<E>
151 bool EnumRadioButton(int& buttonStorage, E value, E& storage) {
152 bool res = EnumRadioButton(buttonStorage, value);
153 if (res) {
154 storage = value;
155 }
156
157 return res;
158 }
159
160 // FIXME: This would work nicely if it was a public template, e.g. 'template<T> RadioButton(const char* label, T* v, T v_button)', but I'm not sure how we would expose it..
161 // I have fixed it, don't know what the problem is with this ... --knox
162 template<typename T>
163 bool RadioButton(const char* label, T& v, T v_button) {
164 const bool pressed = ImGui::RadioButton(label, v == v_button);
165 if (pressed)
166 v = v_button;
167 return pressed;
168 }
169
170 template<class... Args>
171 void TextColored(const ImVec4& col, const std::string& fmt, Args&&... args) {
172 ImGui::PushStyleColor(ImGuiCol_Text, col);
173 ImGui::TextEx(std::vformat(fmt, std::make_format_args(args...)).c_str(), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
174 ImGui::PopStyleColor();
175 }
176
177#ifdef _WIN32
189 void KeyInput(const char* label, const char* id, char* buffer, size_t bufSize, WPARAM& keyContainer, const char* notSetText);
190#endif
191
192
193 // This code is derived from an issue in the ImGui github repo: https://github.com/ocornut/imgui/issues/1658#issuecomment-886171438
194 // Therefore the original code is licensed under the same license as ImGui (MIT)
195 //
196 // returns if the value was changed.
197 // `pPopupOpen` returns if the popup is open
198 template<std::ranges::viewable_range T, typename ValueType = std::ranges::views::all_t<T>>
199 // template<std::ranges::common_range T, typename ValueType = std::ranges::range_value_t<T>>
200 bool FilteredCombo(const char* pLabel, const T& pContainer, ValueType& pCurrent, bool* pPopupOpen = nullptr) {
201 // this is breaking the overloaded to_string functions (in theory it should work, but it doesn't :( )
202 // using std::to_string;
203
204 ImGuiContext& g = *GImGui;
205
206 ImGuiWindow* window = ImGui::GetCurrentWindow();
207 if (window->SkipItems)
208 return false;
209
210 static char searchInputBuffer[256] = {0};
211
212 std::string popupName = std::format("###FilteredCombo_popup_name_{}", pLabel);
213
214 // Display items
215 // FIXME-OPT: Use clipper (but we need to disable it on the appearing frame to make sure our call to SetItemDefaultFocus() is processed)
216 bool valueChanged = false;
217
218 const float expectedWidth = ImGui::CalcItemWidth();
219 bool isNewOpen = false;
220 float frameHeight = ImGui::GetFrameHeight();
221 ImVec2 size(frameHeight, frameHeight);
222 ImVec2 CursorPos = window->DC.CursorPos;
223 ImVec2 pos = CursorPos + ImVec2(expectedWidth - frameHeight, 0);
224 const ImRect bb(pos, pos + size);
225
226 float ButtonTextAlignX = g.Style.ButtonTextAlign.x;
227 g.Style.ButtonTextAlign.x = 0;
228 if (ImGui::Button(std::format("{}###FilteredCombo_button_label_{}", to_string(pCurrent), pLabel).c_str(), ImVec2(expectedWidth, 0))) {
229 ImGui::OpenPopup(popupName.c_str());
230 isNewOpen = true;
231 memset(searchInputBuffer, 0, sizeof searchInputBuffer);
232 }
233 g.Style.ButtonTextAlign.x = ButtonTextAlignX;
234 // bool hovered = ImGui::IsItemHovered();
235 // bool active = ImGui::IsItemActivated();
236 // bool pressed = ImGui::IsItemClicked();
237
238 // Render
239 //const ImU32 bg_col = GetColorU32((active && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
240 //RenderFrame(bb.Min, bb.Max, bg_col, true, g.Style.FrameRounding);
241 const ImU32 textColor = ImGui::GetColorU32(ImGuiCol_Text);
242 ImGui::RenderArrow(window->DrawList, bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSize) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), textColor, ImGuiDir_Down);
243
244 ImVec2 item_max = ImGui::GetItemRectMax();
245 ImGui::SetNextWindowPos({CursorPos.x, item_max.y});
246 ImGui::SetNextWindowSize({ImGui::GetItemRectSize().x, 0});
247
248 if (ImGui::BeginPopup(popupName.c_str())) {
249 using CacheVectorType = std::tuple<double, ValueType>;
250 static std::vector<CacheVectorType> valueCache;
251
252 if (pPopupOpen != nullptr) {
253 *pPopupOpen = true;
254 }
255
256 ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4) ImColor(240, 240, 240, 255));
257 ImGui::PushStyleColor(ImGuiCol_Text, (ImVec4) ImColor(0, 0, 0, 255));
258 ImGui::PushItemWidth(-FLT_MIN);
259
260 // Filter input
261 if (isNewOpen) {
262 ImGui::SetKeyboardFocusHere();
263 for (const auto& val : pContainer) {
264 valueCache.emplace_back(1, val);
265 }
266 }
267 if (ImGui::InputText("###FilteredCombo_InputText", searchInputBuffer, sizeof searchInputBuffer)) {
268 // input changed, recalculate fuzzy values
269 valueCache.clear();
270 if (searchInputBuffer[0] == '\0') {
271 for (const auto& val : pContainer) {
272 valueCache.emplace_back(1, val);
273 }
274 } else {
275 for (const auto& val : pContainer) {
276 const auto& valStr = to_string(val);
277 double ratio = rapidfuzz::fuzz::ratio(valStr, searchInputBuffer);
278 if (ratio >= 0.5)
279 valueCache.emplace_back(ratio, val);
280 }
281
282 std::ranges::sort(valueCache, [](const CacheVectorType& val1, const CacheVectorType& val2) {
283 return std::get<0>(val1) > std::get<0>(val2);
284 });
285 }
286 }
287
288 // Search Icon, you can use it if you load IconsFontAwesome5 https://github.com/juliettef/IconFontCppHeaders
289 //const ImVec2 label_size = CalcTextSize(ICON_FA_SEARCH, NULL, true);
290 //const ImVec2 search_icon_pos(ImGui::GetItemRectMax().x - label_size.x - style.ItemInnerSpacing.x * 2, window->DC.CursorPos.y + style.FramePadding.y + g.FontSize * 0.1f);
291 //RenderText(search_icon_pos, ICON_FA_SEARCH);
292
293 ImGui::PopStyleColor(2);
294
295 if (ImGui::ListBoxHeader("###FilteredCombo_ItemList")) {
296 for (const auto& value : valueCache) {
297 const auto& val = std::get<1>(value);
298 const bool itemSelected = (val == pCurrent);
299 if (ImGui::Selectable(to_string(val).c_str(), itemSelected)) {
300 valueChanged = true;
301 pCurrent = val;
302 ImGui::CloseCurrentPopup();
303 }
304 if (itemSelected)
305 ImGui::SetItemDefaultFocus();
306 }
307 ImGui::ListBoxFooter();
308 }
309 ImGui::PopItemWidth();
310 ImGui::EndPopup();
311 }
312
313
314 if (valueChanged)
315 ImGui::MarkItemEdited(g.CurrentWindow->DC.LastItemId);
316
317 return valueChanged;
318 }
319
320 // template<typename T, typename ValueType>
321 // requires std::ranges::common_range<T> && (!std::ranges::viewable_range<T>)
322 // bool test(const char* pLabel, const T& pContainer, ValueType& pCurrent, bool* pPopupOpen = nullptr) {
323 // return FilteredCombo(pLabel, std::ranges::views::all(pContainer), pCurrent, pPopupOpen);
324 // }
325 template<std::ranges::common_range T, typename ValueType = std::ranges::range_value_t<T>>
326 requires(!std::ranges::viewable_range<T>)
327 bool FilteredCombo(const char* pLabel, const T& pContainer, ValueType& pCurrent, bool* pPopupOpen = nullptr) {
328 return FilteredCombo(pLabel, std::ranges::views::all(pContainer), pCurrent, pPopupOpen);
329 }
330} // namespace ImGuiEx
std::string to_string(Alignment alignment)
Definition arcdps_structs.cpp:6
CornerPosition
Definition arcdps_structs.h:81
Position
Definition arcdps_structs.h:73
Alignment
Definition arcdps_structs.h:64
double ratio(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, double score_cutoff=0)
calculates a simple ratio between two strings
Definition rapidfuzz_amalgamated.hpp:4383
Definition KeyInput.cpp:46
void KeyInput(const char *label, const char *id, char *buffer, size_t bufSize, WPARAM &keyContainer, const char *notSetText)
Definition Widgets.cpp:1197
void TableHeader(const char *label, bool show_label, ImTextureID texture, Alignment alignment)
Definition Widgets.cpp:128
void BeginMenuChild(const char *child_str_id, const char *menu_label, std::function< void()> draw_func)
Definition Widgets.cpp:556
bool BeginTable(const char *str_id, int columns_count, ImGuiTableFlags flags, const ImVec2 &outer_size, float inner_width, ImGuiWindowFlags child_window_flags)
Definition Widgets.cpp:1189
bool Selectable(E &storage, E value)
Definition Widgets.h:51
bool SpinnerAligned(const char *label, float radius, float thickness, const ImU32 &color, Alignment alignment)
Definition Widgets.cpp:57
bool TableIsMouseHoveringCurrentRow()
Definition Widgets.cpp:618
bool FilteredCombo(const char *pLabel, const T &pContainer, ValueType &pCurrent, bool *pPopupOpen=nullptr)
Definition Widgets.h:200
bool EnumRadioButton(int &buttonStorage, E value)
Definition Widgets.h:145
bool RadioButton(const char *label, T &v, T v_button)
Definition Widgets.h:163
bool BeginMenu(const char *label, bool enabled, bool &hoveredPar)
Definition Widgets.cpp:401
bool WindowReposition(ImGuiWindow *window, Position position, const ImVec2 &cornerVector, CornerPosition cornerPosition, ImGuiID fromWindowID, CornerPosition anchorPanelCornerPosition, CornerPosition selfPanelCornerPosition)
Definition Widgets.cpp:624
void AlignedTextColumn(Alignment alignment, const char *text,...)
Definition Widgets.cpp:86
bool EnumCombo(const char *label, E &storage, const R &values, const std::map< E, std::function< const std::string &()> > &pPopupText={})
Definition Widgets.h:64
void TextColored(const ImVec4 &col, const std::string &fmt, Args &&... args)
Definition Widgets.h:171
ImRect TableGetCurrentRowRect()
Definition Widgets.cpp:610
void AlignedProgressBar(float fraction, const ImVec2 &size_arg, const char *overlay, Alignment alignment)
Definition Widgets.cpp:323
bool TreeNodeEx(const char *label, ImGuiTreeNodeFlags flags, void *icon)
Definition Widgets.cpp:921
bool Spinner(const char *label, float radius, float thickness, const ImU32 &color)
Definition Widgets.cpp:19
void MenuItemTableColumnVisibility(ImGuiTable *table, int columnIdx)
Definition Widgets.cpp:599
bool BeginPopupContextWindow(const char *str_id, ImGuiPopupFlags popup_flags, ImGuiHoveredFlags hovered_flags)
Definition Widgets.cpp:586
IMGUI_API bool InputText(const char *label, std::string *str, ImGuiInputTextFlags flags=0, ImGuiInputTextCallback callback=NULL, void *user_data=NULL)
Definition imgui_stdlib.cpp:36