Enigma  3.2.0
A Simple, Reliable and Efficient Encryption Tool
ImGuiWidgets.hpp
Go to the documentation of this file.
1 #pragma once
2 #ifndef ENIGMA_IMGUI_WIDGETS_H
3 #define ENIGMA_IMGUI_WIDGETS_H
4 
7 #include <Core/Core.hpp>
9 #include <Utility/SizeUtils.hpp>
10 #include <imgui.h>
11 #include <imgui_internal.h>
12 
14 
15 class ImGuiWidgets final {
16  ENIGMA_STATIC_CLASS(ImGuiWidgets);
17 
18  public:
25  std::string *Str;
26  ImGuiInputTextCallback ChainCallback;
28  };
29  static int InputTextCallback(ImGuiInputTextCallbackData *data) {
30  InputTextCallback_UserData *user_data = static_cast<InputTextCallback_UserData *>(data->UserData);
31  if (data->EventFlag == static_cast<decltype(data->EventFlag)>(ImGuiInputTextFlags_CallbackResize)) {
32  // Resize string callback
33  // If for some reason we refuse the new length (BufTextLen) and/or capacity (BufSize) we need to set them back to what we want.
34  std::string *str = user_data->Str;
35  IM_ASSERT(data->Buf == str->c_str());
36  str->resize(data->BufTextLen);
37  data->Buf = (char *) str->c_str();
38  } else if (user_data->ChainCallback) {
39  // Forward to user callback, if any
40  data->UserData = user_data->ChainCallbackUserData;
41  return user_data->ChainCallback(data);
42  }
43  return 0;
44  }
45 
47  static bool InputText(const char *label, std::string *str, const float width, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void *user_data = nullptr) {
48  IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
49  flags |= ImGuiInputTextFlags_CallbackResize;
50 
51  InputTextCallback_UserData cb_user_data;
52  cb_user_data.Str = str;
53  cb_user_data.ChainCallback = callback;
54  cb_user_data.ChainCallbackUserData = user_data;
55  ImGui::PushItemWidth(width);
56  return ImGui::InputText(label, (char *) str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
57  }
58 
60  static bool InputTextMultiline(const char *label, std::string *str, const ImVec2& size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void *user_data = nullptr) {
61  IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
62  flags |= ImGuiInputTextFlags_CallbackResize;
63 
64  InputTextCallback_UserData cb_user_data;
65  cb_user_data.Str = str;
66  cb_user_data.ChainCallback = callback;
67  cb_user_data.ChainCallbackUserData = user_data;
68  return ImGui::InputTextMultiline(label, (char *) str->c_str(), str->capacity() + 1, size, flags, InputTextCallback, &cb_user_data);
69  }
70 
72  static bool InputTextWithHint(const char *label, const char *hint, std::string *str, const float width, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void *user_data = nullptr) {
73  IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
74  flags |= ImGuiInputTextFlags_CallbackResize;
75 
76  InputTextCallback_UserData cb_user_data;
77  cb_user_data.Str = str;
78  cb_user_data.ChainCallback = callback;
79  cb_user_data.ChainCallbackUserData = user_data;
80  ImGui::PushItemWidth(width);
81  return ImGui::InputTextWithHint(label, hint, (char *) str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
82  }
83 
84 #if 0
85  static int InputTextCallback(ImGuiInputTextCallbackData* data)
86  {
87  if (data->EventFlag == static_cast<decltype(data->EventFlag)>(ImGuiInputTextFlags_CallbackResize))
88  {
89  // Resize string callback
90  std::string* str = (std::string*)data->UserData;
91  IM_ASSERT(data->Buf == str->c_str());
92  str->resize(data->BufTextLen);
93  data->Buf = (char*)str->c_str();
94  }
95  return 0;
96  }
97  static bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0)
98  {
99  flags |= ImGuiInputTextFlags_CallbackResize;
100  return ImGui::InputTextMultiline(label, (char*)str->c_str(), str->capacity() + 1, size, flags, ImGuiWidgets::InputTextCallback, (void*)str);
101  }
102  static bool InputText(const char* label, std::string* str, const float width, ImGuiInputTextFlags flags = 0)
103  {
104  ImGui::PushItemWidth(width);
105  flags |= ImGuiInputTextFlags_CallbackResize;
106  bool ret = ImGui::InputText(label, (char*)str->c_str(), str->capacity() + 1, flags, ImGuiWidgets::InputTextCallback, (void*)str);
107  ImGui::PopItemWidth();
108  return ret;
109  }
110  static bool InputTextWithHint(const char* label, const char* hint, std::string* str, const float width, ImGuiInputTextFlags flags = 0)
111  {
112  ImGui::PushItemWidth(width);
113  flags |= ImGuiInputTextFlags_CallbackResize;
114  bool ret = ImGui::InputTextWithHint(label, hint, (char*)str->c_str(), str->capacity() + 1, flags, ImGuiWidgets::InputTextCallback, (void*)str);
115  ImGui::PopItemWidth();
116  return ret;
117 
118  }
119 #endif
121 
122 
124  static bool Button(const char *text,
125  const ImVec2& size = ImVec2(0.0f, 0.0f),
126  const ImVec4& color = Constants::Colors::BUTTON_COLOR,
127  const ImVec4& color_hover = Constants::Colors::BUTTON_COLOR_HOVER,
128  const ImVec4& color_active = Constants::Colors::BUTTON_COLOR_ACTIVE) {
129  ImGui::PushStyleColor(ImGuiCol_Button, color); // buttons color idle
130  ImGui::PushStyleColor(ImGuiCol_ButtonHovered, color_hover); // buttons color hover
131  ImGui::PushStyleColor(ImGuiCol_ButtonActive, color_active); // buttons color pressed
132  bool pressed_or_selected = ImGui::Button(text, size);
133  ImGui::PopStyleColor(3);
134 
135  return pressed_or_selected;
136  }
137 
139  static bool BackButton(const char *str_id,
140  const ImVec2& size = ImVec2(0.0f, 0.0f),
141  const ImVec4& color = Constants::Colors::BACK_BUTTON_COLOR,
142  const ImVec4& color_hover = Constants::Colors::BACK_BUTTON_COLOR_HOVER,
143  const ImVec4& color_active = Constants::Colors::BACK_BUTTON_COLOR_ACTIVE) {
144  ImGui::PushStyleColor(ImGuiCol_Button, color); // buttons color idle
145  ImGui::PushStyleColor(ImGuiCol_ButtonHovered, color_hover); // buttons color hover
146  ImGui::PushStyleColor(ImGuiCol_ButtonActive, color_active); // buttons color pressed
147  bool pressed_or_selected = ImGui::ArrowButtonEx(str_id, ImGuiDir_Left, size);
148  ImGui::PopStyleColor(3);
149 
150  return pressed_or_selected;
151  }
152 
154 
160  static bool LoadingSpinner(const char *label, float radius, float thickness, const ImU32 color) {
161  ImGuiWindow *window = ImGui::GetCurrentWindow();
162  if (window->SkipItems)
163  return false;
164 
165  ImGuiContext& g = *GImGui;
166  const ImGuiStyle& style = g.Style;
167  const ImGuiID id = window->GetID(label);
168 
169  ImVec2 pos = window->DC.CursorPos;
170  ImVec2 size((radius) * 2, (radius + style.FramePadding.y) * 2);
171 
172  const ImRect bb(pos, ImVec2(pos.x + size.x, pos.y + size.y));
173  ImGui::ItemSize(bb, style.FramePadding.y);
174  if (!ImGui::ItemAdd(bb, id))
175  return false;
176 
177  // Render
178  window->DrawList->PathClear();
179 
180  int num_segments = 30;
181  int start = (int) std::abs(sinf((float) g.Time * 1.8f) * (num_segments - 5));
182 
183  const float a_min = IM_PI * 2.0f * ((float) start) / (float) num_segments;
184  const float a_max = IM_PI * 2.0f * ((float) num_segments - 3) / (float) num_segments;
185 
186  const ImVec2 centre = ImVec2(pos.x + radius, pos.y + radius + style.FramePadding.y);
187 
188  for (int i = 0; i < num_segments; i++) {
189  const float a = a_min + ((float) i / (float) num_segments) * (a_max - a_min);
190  window->DrawList->PathLineTo(ImVec2(centre.x + cosf(a + (float) g.Time * 8.0f) * radius,
191  centre.y + sinf(a + (float) g.Time * 8.0f) * radius));
192  }
193 
194  window->DrawList->PathStroke(color, false, thickness);
195 
196  return true;
197  }
198 
204  static bool LoadingBar(const char *label, float value, const ImVec2& size_arg, const ImU32 bg_col, const ImU32 fg_col) {
205  ImGuiWindow *window = ImGui::GetCurrentWindow();
206  if (window->SkipItems)
207  return false;
208 
209  ImGuiContext& g = *GImGui;
210  const ImGuiStyle& style = g.Style;
211  const ImGuiID id = window->GetID(label);
212 
213  ImVec2 pos = window->DC.CursorPos;
214  ImVec2 size = size_arg;
215  size.x -= style.FramePadding.x * 2;
216 
217  const ImRect bb(pos, ImVec2(pos.x + size.x, pos.y + size.y));
218  ImGui::ItemSize(bb, style.FramePadding.y);
219  if (!ImGui::ItemAdd(bb, id))
220  return false;
221 
222  // Render
223  const float circleStart = size.x * 0.7f;
224  const float circleEnd = size.x;
225  const float circleWidth = circleEnd - circleStart;
226 
227  window->DrawList->AddRectFilled(bb.Min, ImVec2(pos.x + circleStart, bb.Max.y), bg_col);
228  window->DrawList->AddRectFilled(bb.Min, ImVec2(pos.x + circleStart * value, bb.Max.y), fg_col);
229 
230  const float t = static_cast<float>(g.Time);
231  const float r = size.y / 2;
232  const float speed = 1.5f;
233 
234  const float a = speed * 0;
235  const float b = speed * 0.333f;
236  const float c = speed * 0.666f;
237 
238  const float o1 = (circleWidth + r) * (t + a - speed * (int) ((t + a) / speed)) / speed;
239  const float o2 = (circleWidth + r) * (t + b - speed * (int) ((t + b) / speed)) / speed;
240  const float o3 = (circleWidth + r) * (t + c - speed * (int) ((t + c) / speed)) / speed;
241 
242  window->DrawList->AddCircleFilled(ImVec2(pos.x + circleEnd - o1, bb.Min.y + r), r, bg_col);
243  window->DrawList->AddCircleFilled(ImVec2(pos.x + circleEnd - o2, bb.Min.y + r), r, bg_col);
244  window->DrawList->AddCircleFilled(ImVec2(pos.x + circleEnd - o3, bb.Min.y + r), r, bg_col);
245 
246  return true;
247  }
248 
250 
257  static void LoadingDialog(const char *text, const ImVec2& spinner_position, const float spinner_radius, const float spinner_thickness, const ImVec4& spinner_color,
258  const float container_width = (float) Application::getInstance()->GetWindow()->GetWidth(),
259  const float container_height = (float) Application::getInstance()->GetWindow()->GetHeight()) {
260  static constexpr auto popup_id = "loadingDialog";
261 
262  const auto& [win_w, win_h] = Application::getInstance()->GetWindow()->GetSize();
263  static ImFont* const& font_ubuntu_regular_20 = ResourceManager::getFont("Ubuntu-Regular-20");
264 
265  ImGui::OpenPopup(popup_id, ImGuiPopupFlags_AnyPopup);
266  static constexpr const auto popup_window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground;
267  if (ImGui::BeginPopupModal(popup_id, nullptr, popup_window_flags)) {
268  ImGui::SetWindowSize(ImVec2(container_width, container_height)); // set spinner container's size same size as window (to centerize it)
269  ImGui::SetWindowPos(ImVec2(0.0f, 0.0f)); // top left
270 
271  static const std::uint32_t COLOR = ImGui::GetColorU32(spinner_color); // 0xrrggbbaa
272  ImGui::SetCursorPos(spinner_position);
273  ImGuiWidgets::LoadingSpinner("##spinner", spinner_radius, spinner_thickness, COLOR);
274  ImGui::PushFont(font_ubuntu_regular_20); // text font
275  const auto text_size = ImGui::CalcTextSize(text);
276  ImGui::SetCursorPosX((win_w - text_size.x) / 2.0f);
277  ImGui::TextWrapped("%s",text);
278  ImGui::PopFont();
279  ImGui::EndPopup();
280  }
281  }
283 
289  class Image {
290  public:
291  explicit Image(const char *file_name) {
292  // Load from file
293  byte *buffer = stbi_load(file_name, &m_width, &m_height, nullptr, 4);
294  ENIGMA_ASSERT(buffer, std::string("Failed to read image from ") + file_name);
295 
296  // Create a OpenGL texture identifier
297  glAssert(glGenTextures(1, &m_id));
298  glAssert(glBindTexture(GL_TEXTURE_2D, m_id));
299 
300  // Setup filtering parameters for display
301  glAssert(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
302  glAssert(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
303  glAssert(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); // This is required on WebGL for non power-of-two textures
304  glAssert(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); // Same
305 
306  // Upload pixels into texture
307 #if defined(GL_UNPACK_ROW_LENGTH) && !defined(__EMSCRIPTEN__)
308  glAssert(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
309 #endif
310  ENIGMA_INFO("Storing texture #{0} {1} to GPU Memory", m_id, SizeUtils::FriendlySize((std::size_t) m_width * (std::size_t) m_height * sizeof(byte)));
311 
312  glAssert(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer));
313 
314  // at this point the buffer is uploaded to the gpu, no need to keep in the memory
315  stbi_image_free(buffer);
316  }
317 
318  ~Image() {
319  ENIGMA_INFO("Deleting texture #{0} from GPU Memory", m_id);
320  glAssert(glDeleteTextures(1, &m_id));
321  }
322 
323  void Draw(const ImVec2& position, const float width, const float height) {
324  ImGui::SetCursorPos(position);
325  ImGui::Image((void *) (std::intptr_t) m_id, ImVec2(width, height));
326  }
327 
328  public:
329  std::int32_t GetWidth() const noexcept { return m_width; };
330  std::int32_t GetHeight() const noexcept { return m_height; };
331  GLuint GetID() const noexcept { return m_id; };
332 
333  private:
334  GLuint m_id{}; // OpenGL texture id
335  std::int32_t m_width{};
336  std::int32_t m_height{};
337  };
338 };
339 
341 
342 #endif // !ENIGMA_IMGUI_WIDGETS_H
#define ENIGMA_INFO(...)
Definition: Logger.hpp:41
#define NS_ENIGMA_BEGIN
Enable/Disable Assertions.
Definition: Macros.hpp:13
#define NS_ENIGMA_END
Definition: Macros.hpp:14
#define ENIGMA_ASSERT(x,...)
Asserts.
Definition: Macros.hpp:38
#define glAssert(call)
glAssert to handle opengl calls errors (for opengl versions less than 4.3 with no error callback func...
Definition: OpenGLUtils.hpp:67
const std::unique_ptr< Window > & GetWindow() const noexcept
Definition: Application.hpp:72
static Application * getInstance() noexcept
Definition: Application.hpp:69
Image(const char *file_name)
std::int32_t GetHeight() const noexcept
std::int32_t GetWidth() const noexcept
void Draw(const ImVec2 &position, const float width, const float height)
GLuint GetID() const noexcept
static bool LoadingBar(const char *label, float value, const ImVec2 &size_arg, const ImU32 bg_col, const ImU32 fg_col)
static bool InputTextMultiline(const char *label, std::string *str, const ImVec2 &size, ImGuiInputTextFlags flags=0, ImGuiInputTextCallback callback=nullptr, void *user_data=nullptr)
static bool InputText(const char *label, std::string *str, const float width, ImGuiInputTextFlags flags=0, ImGuiInputTextCallback callback=nullptr, void *user_data=nullptr)
static void LoadingDialog(const char *text, const ImVec2 &spinner_position, const float spinner_radius, const float spinner_thickness, const ImVec4 &spinner_color, const float container_width=(float) Application::getInstance() ->GetWindow() ->GetWidth(), const float container_height=(float) Application::getInstance() ->GetWindow() ->GetHeight())
static bool Button(const char *text, const ImVec2 &size=ImVec2(0.0f, 0.0f), const ImVec4 &color=Constants::Colors::BUTTON_COLOR, const ImVec4 &color_hover=Constants::Colors::BUTTON_COLOR_HOVER, const ImVec4 &color_active=Constants::Colors::BUTTON_COLOR_ACTIVE)
static bool InputTextWithHint(const char *label, const char *hint, std::string *str, const float width, ImGuiInputTextFlags flags=0, ImGuiInputTextCallback callback=nullptr, void *user_data=nullptr)
static bool BackButton(const char *str_id, const ImVec2 &size=ImVec2(0.0f, 0.0f), const ImVec4 &color=Constants::Colors::BACK_BUTTON_COLOR, const ImVec4 &color_hover=Constants::Colors::BACK_BUTTON_COLOR_HOVER, const ImVec4 &color_active=Constants::Colors::BACK_BUTTON_COLOR_ACTIVE)
static int InputTextCallback(ImGuiInputTextCallbackData *data)
static bool LoadingSpinner(const char *label, float radius, float thickness, const ImU32 color)
static std::string FriendlySize(const std::size_t bytes) noexcept
Definition: SizeUtils.hpp:19
static const ImVec4 BACK_BUTTON_COLOR_ACTIVE
Definition: Constants.hpp:139
static const ImVec4 BACK_BUTTON_COLOR_HOVER
Definition: Constants.hpp:138
static const ImVec4 BUTTON_COLOR_ACTIVE
Definition: Constants.hpp:133
static const ImVec4 BACK_BUTTON_COLOR
Definition: Constants.hpp:137
static const ImVec4 BUTTON_COLOR_HOVER
Definition: Constants.hpp:132
static const ImVec4 BUTTON_COLOR
Definition: Constants.hpp:131