Skip to content

Commit

Permalink
Drags: added ImGuisliderFlags_WrapAround flag for DragInt(), DragFloa…
Browse files Browse the repository at this point in the history
…t() etc. (#7749)
  • Loading branch information
ocornut committed Jun 28, 2024
1 parent c7df9c7 commit 0403096
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 18 deletions.
1 change: 1 addition & 0 deletions docs/CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Other changes:
Added corresponding ImGuiCol_TabSelectedOverline and ImGuiCol_TabDimmedSelectedOverline colors.
- Tables: added TableGetHoveredColumn() to public API, as an alternative to testing for
'TableGetColumnFlags(column) & ImGuiTableColumnFlags_IsHovered' on each column. (#3740)
- Drags: added ImGuisliderFlags_WrapAround flag for DragInt(), DragFloat() etc. (#7749)
- Drag and Drop: BeginDragDropSource() with ImGuiDragDropFlags_SourceExtern sets
active id so a multi-frame extern source doesn't interfere with hovered widgets. (#143)
- Drag and Drop: BeginDragDropSource() with ImGuiDragDropFlags_SourceExtern does not assume
Expand Down
5 changes: 3 additions & 2 deletions imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -1732,8 +1732,9 @@ enum ImGuiSliderFlags_
ImGuiSliderFlags_None = 0,
ImGuiSliderFlags_AlwaysClamp = 1 << 4, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.
ImGuiSliderFlags_Logarithmic = 1 << 5, // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits.
ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits)
ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget
ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits).
ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget.
ImGuisliderFlags_WrapAround = 1 << 8, // Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions for now.
ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed.

// Obsolete names
Expand Down
12 changes: 8 additions & 4 deletions imgui_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -720,18 +720,19 @@ static void ShowDemoWindowWidgets()

{
IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat");
static int i1 = 50, i2 = 42;
static int i1 = 50, i2 = 42, i3 = 128;
ImGui::DragInt("drag int", &i1, 1);
ImGui::SameLine(); HelpMarker(
"Click and drag to edit value.\n"
"Hold SHIFT/ALT for faster/slower edit.\n"
"Double-click or CTRL+click to input value.");

ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp);
ImGui::DragInt("drag int wrap 100..200", &i3, 1, 100, 200, "%d", ImGuisliderFlags_WrapAround);

static float f1 = 1.00f, f2 = 0.0067f;
ImGui::DragFloat("drag float", &f1, 0.005f);
ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
//ImGui::DragFloat("drag wrap -1..1", &f3, 0.005f, -1.0f, 1.0f, NULL, ImGuisliderFlags_WrapAround);
}

ImGui::SeparatorText("Sliders");
Expand Down Expand Up @@ -2145,6 +2146,8 @@ static void ShowDemoWindowWidgets()
ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput);
ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget.");
ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuisliderFlags_WrapAround);
ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)");

// Drags
static float drag_f = 0.5f;
Expand All @@ -2159,9 +2162,10 @@ static void ShowDemoWindowWidgets()
// Sliders
static float slider_f = 0.5f;
static int slider_i = 50;
const ImGuiSliderFlags flags_for_sliders = flags & ~ImGuisliderFlags_WrapAround;
ImGui::Text("Underlying float value: %f", slider_f);
ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags);
ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags);
ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags_for_sliders);
ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags_for_sliders);

ImGui::TreePop();
}
Expand Down
37 changes: 25 additions & 12 deletions imgui_widgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2305,12 +2305,13 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
{
ImGuiContext& g = *GImGui;
const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
const bool is_clamped = (v_min < v_max);
const bool is_bounded = (v_min < v_max);
const bool is_wrapped = is_bounded && (flags & ImGuisliderFlags_WrapAround);
const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0;
const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);

// Default tweak speed
if (v_speed == 0.0f && is_clamped && (v_max - v_min < FLT_MAX))
if (v_speed == 0.0f && is_bounded && (v_max - v_min < FLT_MAX))
v_speed = (float)((v_max - v_min) * g.DragSpeedDefaultRatio);

// Inputs accumulates into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings
Expand Down Expand Up @@ -2344,8 +2345,8 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const

// Clear current value on activation
// Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300.
bool is_just_activated = g.ActiveIdIsJustActivated;
bool is_already_past_limits_and_pushing_outward = is_clamped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f));
const bool is_just_activated = g.ActiveIdIsJustActivated;
const bool is_already_past_limits_and_pushing_outward = is_bounded && !is_wrapped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f));
if (is_just_activated || is_already_past_limits_and_pushing_outward)
{
g.DragCurrentAccum = 0.0f;
Expand Down Expand Up @@ -2403,13 +2404,24 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
if (v_cur == (TYPE)-0)
v_cur = (TYPE)0;

// Clamp values (+ handle overflow/wrap-around for integer types)
if (*v != v_cur && is_clamped)
if (*v != v_cur && is_bounded)
{
if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_floating_point))
v_cur = v_min;
if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_floating_point))
v_cur = v_max;
if (is_wrapped)
{
// Wrap values
if (v_cur < v_min)
v_cur += v_max - v_min + (is_floating_point ? 0 : 1);
if (v_cur > v_max)
v_cur -= v_max - v_min + (is_floating_point ? 0 : 1);
}
else
{
// Clamp values + handle overflow/wrap-around for integer types.
if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_floating_point))
v_cur = v_min;
if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_floating_point))
v_cur = v_max;
}
}

// Apply result
Expand All @@ -2422,7 +2434,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags)
{
// Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert.
IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead.");
IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead.");

ImGuiContext& g = *GImGui;
if (g.ActiveId == id)
Expand Down Expand Up @@ -3015,7 +3027,8 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb)
{
// Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert.
IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flag! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead.");
IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead.");
IM_ASSERT((flags & ImGuisliderFlags_WrapAround) == 0); // Not supported by SliderXXX(), only by DragXXX()

switch (data_type)
{
Expand Down

0 comments on commit 0403096

Please sign in to comment.