@@ -1108,10 +1108,11 @@ struct ImGuiState
1108
1108
ImGuiWindow* FocusedWindow; // Will catch keyboard inputs
1109
1109
ImGuiWindow* HoveredWindow; // Will catch mouse inputs
1110
1110
ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only)
1111
- ImGuiID HoveredId;
1112
- ImGuiID ActiveId;
1111
+ ImGuiID HoveredId; // Hovered widget
1112
+ ImGuiID ActiveId; // Active widget
1113
1113
ImGuiID ActiveIdPreviousFrame;
1114
1114
bool ActiveIdIsAlive;
1115
+ bool ActiveIdIsJustActivated; // Set when
1115
1116
bool ActiveIdIsFocusedOnly; // Set only by active widget. Denote focus but no active interaction.
1116
1117
ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. Only valid if ActiveID is the "#MOVE" identifier of a window.
1117
1118
float SettingsDirtyTimer;
@@ -1144,6 +1145,7 @@ struct ImGuiState
1144
1145
ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc.
1145
1146
ImGuiStorage ColorEditModeStorage; // for user selection
1146
1147
ImGuiID ActiveComboID;
1148
+ float DragCurrentValue;
1147
1149
ImVec2 DragLastMouseDelta;
1148
1150
float DragSpeedScaleSlow;
1149
1151
float DragSpeedScaleFast;
@@ -1182,6 +1184,7 @@ struct ImGuiState
1182
1184
ActiveId = 0;
1183
1185
ActiveIdPreviousFrame = 0;
1184
1186
ActiveIdIsAlive = false;
1187
+ ActiveIdIsJustActivated = false;
1185
1188
ActiveIdIsFocusedOnly = false;
1186
1189
MovedWindow = NULL;
1187
1190
SettingsDirtyTimer = 0.0f;
@@ -1199,6 +1202,7 @@ struct ImGuiState
1199
1202
1200
1203
ScalarAsInputTextId = 0;
1201
1204
ActiveComboID = 0;
1205
+ DragCurrentValue = 0.0f;
1202
1206
DragLastMouseDelta = ImVec2(0.0f, 0.0f);
1203
1207
DragSpeedScaleSlow = 0.01f;
1204
1208
DragSpeedScaleFast = 10.0f;
@@ -1314,6 +1318,7 @@ static void SetActiveId(ImGuiID id)
1314
1318
ImGuiState& g = *GImGui;
1315
1319
g.ActiveId = id;
1316
1320
g.ActiveIdIsFocusedOnly = false;
1321
+ g.ActiveIdIsJustActivated = true;
1317
1322
}
1318
1323
1319
1324
static void RegisterAliveId(ImGuiID id)
@@ -1935,6 +1940,7 @@ void ImGui::NewFrame()
1935
1940
SetActiveId(0);
1936
1941
g.ActiveIdPreviousFrame = g.ActiveId;
1937
1942
g.ActiveIdIsAlive = false;
1943
+ g.ActiveIdIsJustActivated = false;
1938
1944
if (!g.ActiveId)
1939
1945
g.MovedWindow = NULL;
1940
1946
@@ -5055,7 +5061,7 @@ static bool SliderFloatAsInputText(const char* label, float* v, ImGuiID id, int
5055
5061
}
5056
5062
5057
5063
// Parse display precision back from the display format string
5058
- static void ParseFormat(const char* fmt, int& decimal_precision)
5064
+ static inline void ParseFormat(const char* fmt, int& decimal_precision)
5059
5065
{
5060
5066
while ((fmt = strchr(fmt, '%')) != NULL)
5061
5067
{
@@ -5073,6 +5079,21 @@ static void ParseFormat(const char* fmt, int& decimal_precision)
5073
5079
}
5074
5080
}
5075
5081
5082
+ static inline float RoundScalar(float value, int decimal_precision)
5083
+ {
5084
+ // Round past decimal precision
5085
+ // 0: 1, 1: 0.1, 2: 0.01, etc.
5086
+ // So when our value is 1.99999 with a precision of 0.001 we'll end up rounding to 2.0
5087
+ // FIXME: Investigate better rounding methods
5088
+ const float min_step = 1.0f / powf(10.0f, (float)decimal_precision);
5089
+ const float remainder = fmodf(value, min_step);
5090
+ if (remainder <= min_step*0.5f)
5091
+ value -= remainder;
5092
+ else
5093
+ value += (min_step - remainder);
5094
+ return value;
5095
+ }
5096
+
5076
5097
static bool SliderBehavior(const ImRect& frame_bb, const ImRect& slider_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, bool horizontal)
5077
5098
{
5078
5099
ImGuiState& g = *GImGui;
@@ -5151,14 +5172,7 @@ static bool SliderBehavior(const ImRect& frame_bb, const ImRect& slider_bb, ImGu
5151
5172
}
5152
5173
5153
5174
// Round past decimal precision
5154
- // 0->1, 1->0.1, 2->0.01, etc.
5155
- // So when our value is 1.99999 with a precision of 0.001 we'll end up rounding to 2.0
5156
- const float min_step = 1.0f / powf(10.0f, (float)decimal_precision);
5157
- const float remainder = fmodf(new_value, min_step);
5158
- if (remainder <= min_step*0.5f)
5159
- new_value -= remainder;
5160
- else
5161
- new_value += (min_step - remainder);
5175
+ new_value = RoundScalar(new_value, decimal_precision);
5162
5176
5163
5177
if (*v != new_value)
5164
5178
{
@@ -5464,7 +5478,7 @@ bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const
5464
5478
}
5465
5479
5466
5480
// FIXME-WIP: Work in progress. May change API / behavior.
5467
- static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_step , float v_min, float v_max)
5481
+ static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed , float v_min, float v_max, int decimal_precision )
5468
5482
{
5469
5483
ImGuiState& g = *GImGui;
5470
5484
ImGuiWindow* window = GetCurrentWindow();
@@ -5481,23 +5495,34 @@ static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, flo
5481
5495
{
5482
5496
if (g.IO.MouseDown[0])
5483
5497
{
5484
- const ImVec2 mouse_drag_delta = ImGui::GetMouseDragDelta(0);
5498
+ if (g.ActiveIdIsJustActivated)
5499
+ {
5500
+ // Lock current value on click
5501
+ g.DragCurrentValue = *v;
5502
+ g.DragLastMouseDelta = ImVec2(0.f, 0.f);
5503
+ }
5485
5504
5505
+ const ImVec2 mouse_drag_delta = ImGui::GetMouseDragDelta(0, 1.0f);
5486
5506
if (fabsf(mouse_drag_delta.x - g.DragLastMouseDelta.x) > 0.0f)
5487
5507
{
5488
- float step = v_step ;
5508
+ float step = v_speed ;
5489
5509
if (g.IO.KeyShift && g.DragSpeedScaleFast >= 0.0f)
5490
- step = v_step * g.DragSpeedScaleFast;
5510
+ step = v_speed * g.DragSpeedScaleFast;
5491
5511
if (g.IO.KeyAlt && g.DragSpeedScaleSlow >= 0.0f)
5492
- step = v_step * g.DragSpeedScaleSlow;
5512
+ step = v_speed * g.DragSpeedScaleSlow;
5493
5513
5494
- *v += (mouse_drag_delta.x - g.DragLastMouseDelta.x) * step;
5514
+ g.DragCurrentValue += (mouse_drag_delta.x - g.DragLastMouseDelta.x) * step;
5515
+ g.DragLastMouseDelta.x = mouse_drag_delta.x;
5495
5516
5496
5517
if (v_min < v_max)
5497
- *v = ImClamp(*v , v_min, v_max);
5518
+ g.DragCurrentValue = ImClamp(g.DragCurrentValue , v_min, v_max);
5498
5519
5499
- g.DragLastMouseDelta.x = mouse_drag_delta.x;
5500
- value_changed = true;
5520
+ float new_value = RoundScalar(g.DragCurrentValue, decimal_precision);
5521
+ if (*v != new_value)
5522
+ {
5523
+ *v = new_value;
5524
+ value_changed = true;
5525
+ }
5501
5526
}
5502
5527
}
5503
5528
else
@@ -5509,7 +5534,7 @@ static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, flo
5509
5534
return value_changed;
5510
5535
}
5511
5536
5512
- bool ImGui::DragFloat(const char* label, float *v, float v_step , float v_min, float v_max, const char* display_format)
5537
+ bool ImGui::DragFloat(const char* label, float *v, float v_speed , float v_min, float v_max, const char* display_format)
5513
5538
{
5514
5539
ImGuiState& g = *GImGui;
5515
5540
ImGuiWindow* window = GetCurrentWindow();
@@ -5548,7 +5573,6 @@ bool ImGui::DragFloat(const char* label, float *v, float v_step, float v_min, fl
5548
5573
{
5549
5574
SetActiveId(id);
5550
5575
FocusWindow(window);
5551
- g.DragLastMouseDelta = ImVec2(0.f, 0.f);
5552
5576
5553
5577
if (tab_focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0])
5554
5578
{
@@ -5562,7 +5586,7 @@ bool ImGui::DragFloat(const char* label, float *v, float v_step, float v_min, fl
5562
5586
ItemSize(total_bb, style.FramePadding.y);
5563
5587
5564
5588
// Actual drag behavior
5565
- const bool value_changed = DragScalarBehavior(frame_bb, id, v, v_step , v_min, v_max);
5589
+ const bool value_changed = DragScalarBehavior(frame_bb, id, v, v_speed , v_min, v_max, decimal_precision );
5566
5590
5567
5591
// Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
5568
5592
char value_buf[64];
@@ -5576,12 +5600,13 @@ bool ImGui::DragFloat(const char* label, float *v, float v_step, float v_min, fl
5576
5600
return value_changed;
5577
5601
}
5578
5602
5579
- bool ImGui::DragInt(const char* label, int* v, int v_step, int v_min, int v_max, const char* display_format)
5603
+ // NB: v_speed is float to allow adjusting the drag speed with more precision
5604
+ bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* display_format)
5580
5605
{
5581
5606
if (!display_format)
5582
5607
display_format = "%.0f";
5583
5608
float v_f = (float)*v;
5584
- bool value_changed = ImGui::DragFloat(label, &v_f, (float)v_step , (float)v_min, (float)v_max, display_format);
5609
+ bool value_changed = ImGui::DragFloat(label, &v_f, v_speed , (float)v_min, (float)v_max, display_format);
5585
5610
*v = (int)v_f;
5586
5611
return value_changed;
5587
5612
}
@@ -7029,7 +7054,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha)
7029
7054
ImGui::SameLine(0, (int)style.ItemInnerSpacing.x);
7030
7055
if (n + 1 == components)
7031
7056
ImGui::PushItemWidth(w_item_last);
7032
- value_changed |= ImGui::DragInt(ids[n], &i[n], 1, 0, 255, fmt[n]);
7057
+ value_changed |= ImGui::DragInt(ids[n], &i[n], 1.0f , 0, 255, fmt[n]);
7033
7058
}
7034
7059
ImGui::PopItemWidth();
7035
7060
ImGui::PopItemWidth();
0 commit comments