Skip to content

Commit f5ad362

Browse files
committed
DragFloat() latch value internally, allows finer control, honor precision settings, slow step with integer works #180
1 parent 0dc3d07 commit f5ad362

File tree

2 files changed

+53
-28
lines changed

2 files changed

+53
-28
lines changed

imgui.cpp

+51-26
Original file line numberDiff line numberDiff line change
@@ -1108,10 +1108,11 @@ struct ImGuiState
11081108
ImGuiWindow* FocusedWindow; // Will catch keyboard inputs
11091109
ImGuiWindow* HoveredWindow; // Will catch mouse inputs
11101110
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
11131113
ImGuiID ActiveIdPreviousFrame;
11141114
bool ActiveIdIsAlive;
1115+
bool ActiveIdIsJustActivated; // Set when
11151116
bool ActiveIdIsFocusedOnly; // Set only by active widget. Denote focus but no active interaction.
11161117
ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. Only valid if ActiveID is the "#MOVE" identifier of a window.
11171118
float SettingsDirtyTimer;
@@ -1144,6 +1145,7 @@ struct ImGuiState
11441145
ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc.
11451146
ImGuiStorage ColorEditModeStorage; // for user selection
11461147
ImGuiID ActiveComboID;
1148+
float DragCurrentValue;
11471149
ImVec2 DragLastMouseDelta;
11481150
float DragSpeedScaleSlow;
11491151
float DragSpeedScaleFast;
@@ -1182,6 +1184,7 @@ struct ImGuiState
11821184
ActiveId = 0;
11831185
ActiveIdPreviousFrame = 0;
11841186
ActiveIdIsAlive = false;
1187+
ActiveIdIsJustActivated = false;
11851188
ActiveIdIsFocusedOnly = false;
11861189
MovedWindow = NULL;
11871190
SettingsDirtyTimer = 0.0f;
@@ -1199,6 +1202,7 @@ struct ImGuiState
11991202

12001203
ScalarAsInputTextId = 0;
12011204
ActiveComboID = 0;
1205+
DragCurrentValue = 0.0f;
12021206
DragLastMouseDelta = ImVec2(0.0f, 0.0f);
12031207
DragSpeedScaleSlow = 0.01f;
12041208
DragSpeedScaleFast = 10.0f;
@@ -1314,6 +1318,7 @@ static void SetActiveId(ImGuiID id)
13141318
ImGuiState& g = *GImGui;
13151319
g.ActiveId = id;
13161320
g.ActiveIdIsFocusedOnly = false;
1321+
g.ActiveIdIsJustActivated = true;
13171322
}
13181323

13191324
static void RegisterAliveId(ImGuiID id)
@@ -1935,6 +1940,7 @@ void ImGui::NewFrame()
19351940
SetActiveId(0);
19361941
g.ActiveIdPreviousFrame = g.ActiveId;
19371942
g.ActiveIdIsAlive = false;
1943+
g.ActiveIdIsJustActivated = false;
19381944
if (!g.ActiveId)
19391945
g.MovedWindow = NULL;
19401946

@@ -5055,7 +5061,7 @@ static bool SliderFloatAsInputText(const char* label, float* v, ImGuiID id, int
50555061
}
50565062

50575063
// 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)
50595065
{
50605066
while ((fmt = strchr(fmt, '%')) != NULL)
50615067
{
@@ -5073,6 +5079,21 @@ static void ParseFormat(const char* fmt, int& decimal_precision)
50735079
}
50745080
}
50755081

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+
50765097
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)
50775098
{
50785099
ImGuiState& g = *GImGui;
@@ -5151,14 +5172,7 @@ static bool SliderBehavior(const ImRect& frame_bb, const ImRect& slider_bb, ImGu
51515172
}
51525173

51535174
// 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);
51625176

51635177
if (*v != new_value)
51645178
{
@@ -5464,7 +5478,7 @@ bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const
54645478
}
54655479

54665480
// 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)
54685482
{
54695483
ImGuiState& g = *GImGui;
54705484
ImGuiWindow* window = GetCurrentWindow();
@@ -5481,23 +5495,34 @@ static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, flo
54815495
{
54825496
if (g.IO.MouseDown[0])
54835497
{
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+
}
54855504

5505+
const ImVec2 mouse_drag_delta = ImGui::GetMouseDragDelta(0, 1.0f);
54865506
if (fabsf(mouse_drag_delta.x - g.DragLastMouseDelta.x) > 0.0f)
54875507
{
5488-
float step = v_step;
5508+
float step = v_speed;
54895509
if (g.IO.KeyShift && g.DragSpeedScaleFast >= 0.0f)
5490-
step = v_step * g.DragSpeedScaleFast;
5510+
step = v_speed * g.DragSpeedScaleFast;
54915511
if (g.IO.KeyAlt && g.DragSpeedScaleSlow >= 0.0f)
5492-
step = v_step * g.DragSpeedScaleSlow;
5512+
step = v_speed * g.DragSpeedScaleSlow;
54935513

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;
54955516

54965517
if (v_min < v_max)
5497-
*v = ImClamp(*v, v_min, v_max);
5518+
g.DragCurrentValue = ImClamp(g.DragCurrentValue, v_min, v_max);
54985519

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+
}
55015526
}
55025527
}
55035528
else
@@ -5509,7 +5534,7 @@ static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, flo
55095534
return value_changed;
55105535
}
55115536

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)
55135538
{
55145539
ImGuiState& g = *GImGui;
55155540
ImGuiWindow* window = GetCurrentWindow();
@@ -5548,7 +5573,6 @@ bool ImGui::DragFloat(const char* label, float *v, float v_step, float v_min, fl
55485573
{
55495574
SetActiveId(id);
55505575
FocusWindow(window);
5551-
g.DragLastMouseDelta = ImVec2(0.f, 0.f);
55525576

55535577
if (tab_focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0])
55545578
{
@@ -5562,7 +5586,7 @@ bool ImGui::DragFloat(const char* label, float *v, float v_step, float v_min, fl
55625586
ItemSize(total_bb, style.FramePadding.y);
55635587

55645588
// 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);
55665590

55675591
// Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
55685592
char value_buf[64];
@@ -5576,12 +5600,13 @@ bool ImGui::DragFloat(const char* label, float *v, float v_step, float v_min, fl
55765600
return value_changed;
55775601
}
55785602

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)
55805605
{
55815606
if (!display_format)
55825607
display_format = "%.0f";
55835608
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);
55855610
*v = (int)v_f;
55865611
return value_changed;
55875612
}
@@ -7029,7 +7054,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha)
70297054
ImGui::SameLine(0, (int)style.ItemInnerSpacing.x);
70307055
if (n + 1 == components)
70317056
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]);
70337058
}
70347059
ImGui::PopItemWidth();
70357060
ImGui::PopItemWidth();

imgui.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,8 @@ namespace ImGui
316316

317317
// Widgets: Drags (tip: ctrl+click on a drag box to input text)
318318
// ImGui 1.38+ work-in-progress, may change name or API.
319-
IMGUI_API bool DragFloat(const char* label, float* v, float v_step = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f"); // If v_max >= v_max we have no bound
320-
IMGUI_API bool DragInt(const char* label, int* v, float v_step = 1.0f, int v_min = 0, int v_max = 0, const char* display_format = "%.0f"); // If v_max >= v_max we have no bound
319+
IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f"); // If v_max >= v_max we have no bound
320+
IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* display_format = "%.0f"); // If v_max >= v_max we have no bound
321321

322322
// Widgets: Input
323323
IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL);

0 commit comments

Comments
 (0)