imgui_spinner.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #pragma once
  2. #include "imgui_internal.h"
  3. #include <cmath>
  4. //https://github.com/ocornut/imgui/issues/1901
  5. namespace ImGui
  6. {
  7. bool inline BufferingBar(const char *label, float value, const ImVec2 &size_arg,
  8. const ImU32 &bg_col = ImGui::GetColorU32(ImGuiCol_FrameBg),
  9. const ImU32 &fg_col = ImGui::GetColorU32(ImGuiCol_PlotHistogram))
  10. {
  11. ImGuiWindow *window = GetCurrentWindow();
  12. if (window->SkipItems)
  13. return false;
  14. ImGuiContext &g = *GImGui;
  15. const ImGuiStyle &style = g.Style;
  16. const ImGuiID id = window->GetID(label);
  17. ImVec2 pos = window->DC.CursorPos;
  18. ImVec2 size = size_arg;
  19. size.x -= style.FramePadding.x * 2;
  20. const ImRect bb(pos, ImVec2(pos.x + size.x, pos.y + size.y));
  21. ItemSize(bb, style.FramePadding.y);
  22. if (!ItemAdd(bb, id))
  23. return false;
  24. // Render
  25. const float circleStart = size.x * 0.7f;
  26. const float circleEnd = size.x;
  27. const float circleWidth = circleEnd - circleStart;
  28. window->DrawList->AddRectFilled(bb.Min, ImVec2(pos.x + circleStart, bb.Max.y), bg_col);
  29. window->DrawList->AddRectFilled(bb.Min, ImVec2(pos.x + circleStart * value, bb.Max.y), fg_col);
  30. const float t = g.Time;
  31. const float r = size.y / 2;
  32. const float speed = 1.5f;
  33. const float a = speed * 0;
  34. const float b = speed * 0.333f;
  35. const float c = speed * 0.666f;
  36. const float o1 = (circleWidth + r) * (t + a - speed * (int)((t + a) / speed)) / speed;
  37. const float o2 = (circleWidth + r) * (t + b - speed * (int)((t + b) / speed)) / speed;
  38. const float o3 = (circleWidth + r) * (t + c - speed * (int)((t + c) / speed)) / speed;
  39. window->DrawList->AddCircleFilled(ImVec2(pos.x + circleEnd - o1, bb.Min.y + r), r, bg_col);
  40. window->DrawList->AddCircleFilled(ImVec2(pos.x + circleEnd - o2, bb.Min.y + r), r, bg_col);
  41. window->DrawList->AddCircleFilled(ImVec2(pos.x + circleEnd - o3, bb.Min.y + r), r, bg_col);
  42. }
  43. bool inline Spinner(const char *label, float radius, int thickness, const ImU32 &color =
  44. ImGui::GetColorU32(ImGuiCol_PlotHistogram))
  45. {
  46. ImGuiWindow *window = GetCurrentWindow();
  47. if (window->SkipItems)
  48. return false;
  49. ImGuiContext &g = *GImGui;
  50. const ImGuiStyle &style = g.Style;
  51. const ImGuiID id = window->GetID(label);
  52. ImVec2 pos = window->DC.CursorPos;
  53. ImVec2 size((radius) * 2, (radius + style.FramePadding.y) * 2);
  54. const ImRect bb(pos, ImVec2(pos.x + size.x, pos.y + size.y));
  55. ItemSize(bb, style.FramePadding.y);
  56. if (!ItemAdd(bb, id))
  57. return false;
  58. // Render
  59. window->DrawList->PathClear();
  60. int num_segments = 30;
  61. int start = std::abs(ImSin(g.Time * 1.8f) * (num_segments - 5));
  62. const float a_min = IM_PI * 2.0f * ((float)start) / (float)num_segments;
  63. const float a_max = IM_PI * 2.0f * ((float)num_segments - 3) / (float)num_segments;
  64. const ImVec2 centre = ImVec2(pos.x + radius, pos.y + radius + style.FramePadding.y);
  65. for (int i = 0; i < num_segments; i++)
  66. {
  67. const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
  68. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a + g.Time * 8) * radius,
  69. centre.y + ImSin(a + g.Time * 8) * radius));
  70. }
  71. window->DrawList->PathStroke(color, false, thickness);
  72. }
  73. //todo refactor colors
  74. void inline LoadingIndicatorCircle(const char *label, const float indicator_radius,
  75. const int circle_count, const float speed,
  76. const ImU32 &bg_col = ImGui::GetColorU32(ImGuiCol_FrameBg),
  77. const ImU32 &fg_col = ImGui::GetColorU32(ImGuiCol_PlotHistogram)
  78. )
  79. {
  80. ImGuiWindow *window = GetCurrentWindow();
  81. if (window->SkipItems)
  82. {
  83. return;
  84. }
  85. ImGuiContext &g = *GImGui;
  86. const ImGuiID id = window->GetID(label);
  87. auto style = ImGui::GetStyle();
  88. const ImVec2 pos = window->DC.CursorPos;
  89. const float circle_radius = indicator_radius / 10.0f;
  90. const ImRect bb(pos, ImVec2(pos.x + indicator_radius * 2.0f,
  91. pos.y + indicator_radius * 2.0f));
  92. ItemSize(bb, style.FramePadding.y);
  93. if (!ItemAdd(bb, id))
  94. {
  95. return;
  96. }
  97. const float t = g.Time;
  98. const auto degree_offset = 2.0f * IM_PI / circle_count;
  99. for (int i = 0; i < circle_count; ++i)
  100. {
  101. const auto x = indicator_radius * std::sin(degree_offset * i);
  102. const auto y = indicator_radius * std::cos(degree_offset * i);
  103. const auto growth = std::max(0.0f, std::sin(t * speed - i * degree_offset));
  104. auto main_color = ColorConvertU32ToFloat4(fg_col);
  105. auto backdrop_color = ColorConvertU32ToFloat4(bg_col);
  106. ImVec4 color;
  107. color.x = main_color.x * growth + backdrop_color.x * (1.0f - growth);
  108. color.y = main_color.y * growth + backdrop_color.y * (1.0f - growth);
  109. color.z = main_color.z * growth + backdrop_color.z * (1.0f - growth);
  110. color.w = 1.0f;
  111. window->DrawList->AddCircleFilled(ImVec2(pos.x + indicator_radius + x,
  112. pos.y + indicator_radius - y),
  113. circle_radius + growth * circle_radius,
  114. GetColorU32(color));
  115. }
  116. }
  117. }