forked from hoffstadt/DearPyGui
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmvLoadingIndicatorCustom.cpp
More file actions
165 lines (128 loc) · 7.3 KB
/
mvLoadingIndicatorCustom.cpp
File metadata and controls
165 lines (128 loc) · 7.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include "mvLoadingIndicatorCustom.h"
#include <utility>
#include <cmath>
#include <imgui_internal.h>
// Posted by @alexsr here: https://github.com/ocornut/imgui/issues/1901
// Sligthly modified to provide default behaviour with default args
void LoadingIndicatorCircle(const char* label, float indicatorRadiusFactor,
const ImVec4* pOptionalMainColor, const ImVec4* pOptionalBackdropColor,
int circle_count, const float speed) {
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems) {
return;
}
ImGuiContext& g = *GImGui;
const ImGuiID id = window->GetID(label);
const ImGuiStyle& style = ImGui::GetStyle();
if (circle_count <= 0) circle_count = 12;
if (indicatorRadiusFactor <= 0.f) indicatorRadiusFactor = 1.f;
if (!pOptionalMainColor || pOptionalMainColor->w < 0) pOptionalMainColor = &style.Colors[ImGuiCol_Button];
if (!pOptionalBackdropColor || pOptionalBackdropColor->w < 0) pOptionalBackdropColor = &style.Colors[ImGuiCol_ButtonHovered];
const float lineHeight = ImGui::GetTextLineHeight(); // or GetTextLineHeight() or GetTextLineHeightWithSpacing() ?
float indicatorRadiusPixels = indicatorRadiusFactor * lineHeight * 0.5f;
const ImVec2 pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
const float circle_radius = indicatorRadiusPixels / 8.f;
indicatorRadiusPixels -= 2.0f * circle_radius;
const ImRect bb(pos, ImVec2(pos.x + indicatorRadiusPixels * 2.f + 4.f * circle_radius,
pos.y + indicatorRadiusPixels * 2.f + 4.f * circle_radius));
ImGui::ItemSize(bb, 0.0f);
if (!ImGui::ItemAdd(bb, id, nullptr, ImGuiItemFlags_NoNav)) {
return;
}
const float base_num_segments = circle_radius * 1.f;
const double t = g.Time;
const float degree_offset = 2.0f * IM_PI / circle_count;
for (int i = 0; i < circle_count; ++i) {
const float sinx = -ImSin(degree_offset * i);
const float cosx = ImCos(degree_offset * i);
const float growth = ImMax(0.0f, ImSin((float)(t * (double)(speed * 3.0f) - (double)(i * degree_offset))));
ImVec4 color;
color.x = pOptionalMainColor->x * growth + pOptionalBackdropColor->x * (1.0f - growth);
color.y = pOptionalMainColor->y * growth + pOptionalBackdropColor->y * (1.0f - growth);
color.z = pOptionalMainColor->z * growth + pOptionalBackdropColor->z * (1.0f - growth);
color.w = pOptionalMainColor->w * growth + pOptionalBackdropColor->w * (1.0f - growth);
float grown_circle_radius = circle_radius * (1.0f + growth);
int num_segments = (int)(base_num_segments * grown_circle_radius);
if (num_segments < 4) num_segments = 4;
window->DrawList->AddCircleFilled(ImVec2(pos.x + 2.f * circle_radius + indicatorRadiusPixels * (1.0f + sinx),
pos.y + 2.f * circle_radius + indicatorRadiusPixels * (1.0f + cosx)),
grown_circle_radius,
ImGui::GetColorU32(color), num_segments);
}
}
// Posted by @zfedoran here: https://github.com/ocornut/imgui/issues/1901
// Sligthly modified to provide default behaviour with default args
void LoadingIndicatorCircle2(const char* label, float indicatorRadiusFactor, float indicatorRadiusThicknessFactor, const ImVec4* pOptionalColor) {
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems)
return;
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
if (indicatorRadiusFactor <= 0.f) indicatorRadiusFactor = 1.f;
if (indicatorRadiusThicknessFactor <= 0.f) indicatorRadiusThicknessFactor = 1.f;
if (!pOptionalColor || pOptionalColor->w < 0) pOptionalColor = &style.Colors[ImGuiCol_Button];
const ImU32 color = ImGui::GetColorU32(*pOptionalColor);
const float lineHeight = ImGui::GetTextLineHeight(); // or GetTextLineHeight() or GetTextLineHeightWithSpacing() ?
float indicatorRadiusPixels = indicatorRadiusFactor * lineHeight * 0.5f;
float indicatorThicknessPixels = indicatorRadiusThicknessFactor * indicatorRadiusPixels * 0.6f;
if (indicatorThicknessPixels > indicatorThicknessPixels * 0.4f) indicatorThicknessPixels = indicatorThicknessPixels * 0.4f;
indicatorRadiusPixels -= indicatorThicknessPixels;
ImVec2 pos = window->DC.CursorPos;
ImVec2 size(indicatorRadiusPixels * 2.f, (indicatorRadiusPixels + style.FramePadding.y) * 2.f);
const ImRect bb(pos, ImVec2(pos.x + size.x, pos.y + size.y));
ImGui::ItemSize(bb, style.FramePadding.y);
if (!ImGui::ItemAdd(bb, id))
return;
// Render
window->DrawList->PathClear();
//int num_segments = indicatorRadiusPixels/8.f;
//if (num_segments<4) num_segments=4;
int num_segments = 30;
int start = abs((int)(ImSin(g.Time * 1.8f) * (num_segments - 5)));
const float a_min = IM_PI * 2.0f * ((float)start) / (float)num_segments;
const float a_max = IM_PI * 2.0f * ((float)num_segments - 3) / (float)num_segments;
const ImVec2 centre = ImVec2(pos.x + indicatorRadiusPixels, pos.y + indicatorRadiusPixels + style.FramePadding.y);
for (int i = 0; i < num_segments; i++) {
const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a + g.Time * 8) * indicatorRadiusPixels,
centre.y + ImSin(a + g.Time * 8) * indicatorRadiusPixels));
}
window->DrawList->PathStroke(color, false, indicatorThicknessPixels);
}
// A corrected version of LoadingIndicatorCircle2 that calculates sizes/positions properly.
void LoadingIndicatorRing(const char* label, float size, float thickness, float speed, const ImVec4* pOptionalColor) {
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems)
return;
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
if (!pOptionalColor || pOptionalColor->w < 0) pOptionalColor = &style.Colors[ImGuiCol_Button];
const ImU32 color = ImGui::GetColorU32(*pOptionalColor);
float radius = size * 0.5f;
const ImVec2 pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
const ImRect bb(pos, ImVec2(pos.x + size, pos.y + size));
ImGui::ItemSize(bb, 0.0f);
if (!ImGui::ItemAdd(bb, id, nullptr, ImGuiItemFlags_NoNav))
return;
// Render
window->DrawList->PathClear();
//int num_segments = radius/8.f;
//if (num_segments<4) num_segments=4;
int num_segments = 30;
float t = g.Time * speed;
// With this formula it looks very close to the original LoadingIndicatorCircle2
// but does not have visual artifacts (jitter of the ring tail when it slows down).
float start = 0.5f * (1 - ImSin(t*3.0f)) * (num_segments - 5);
const float a_min = IM_PI * 2.0f * start / (float)num_segments;
const float a_max = IM_PI * 2.0f * ((float)num_segments - 2) / (float)num_segments;
const ImVec2 centre = ImVec2(pos.x + radius, pos.y + radius);
radius -= thickness * 0.5f;
for (int i = 0; i < num_segments; i++) {
const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a + t * 8) * radius,
centre.y + ImSin(a + t * 8) * radius));
}
window->DrawList->PathStroke(color, false, thickness);
}