From 7607aea018a603fac69aa2ce373eacce757dcb03 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 22 Jul 2020 19:33:03 +0200 Subject: [PATCH] Drags, Sliders: Removed power features. Old entry points will pass-through if power=1.0f, otherwise assert + safe fallback. Remove 3 redirection functions (#3361, #1823, #1316, #642) --- docs/CHANGELOG.txt | 32 +++++ imgui.cpp | 8 ++ imgui.h | 27 ++-- imgui_internal.h | 19 +-- imgui_widgets.cpp | 311 +++++++++++++-------------------------------- 5 files changed, 148 insertions(+), 249 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 989f8079f..5348ad15e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,32 @@ HOW TO UPDATE? VERSION 1.78 WIP (In Progress) ----------------------------------------------------------------------- +Breaking Changes: + +- Obsoleted use of the trailing 'float power=1.0f' parameter for those functions: [@Shironekoben, @ocornut] + - DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN() + - SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN() + - VSliderFloat(), VSliderScalar() + Replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags). + The type of those flags are ImGuiDragFlags and ImGuiSliderFlags (underlying int storage). + Worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. + In short, when calling those functions: + - If you omitted the 'power' parameter (likely!), you are not affected. + - If you set the 'power' parameter to 1.0f (same as previous default value): + - Your compiler may warn on float>int conversion. + - Everything else will work. + - You can replace the 1.0f value with 0 to fix the warning, and be technically correct. + - If you set the 'power' parameter to >1.0f (to enable non-linear editing): + - Your compiler may warn on float>int conversion. + - Code will assert at runtime for IM_ASSERT(power == 1.0f) with the following assert description: + "Call Drag function with ImGuiDragFlags_Logarithmic instead of using the old 'float power' function!". + - In case asserts are disabled, the code will not crash and enable the _Logarithmic flag. + - You can replace the >1.0f value with ImGuiDragFlags_Logarithmic or ImGuiSliderFlags_Logarithmic + to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f. + See https://github.com/ocornut/imgui/issues/3361 for all details. + Kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). + For those three the 'float power=1.0f' version were removed directly as they were most unlikely ever used. + Other Changes: - Nav: Fixed clicking on void (behind any windows) from not clearing the focused window. @@ -42,6 +68,12 @@ Other Changes: flag being cleared accordingly. (bug introduced in 1.77 WIP on 2020/06/16) (#3344, #2880) - Window: Fixed clicking over an item which hovering has been disabled (e.g inhibited by a popup) from marking the window as moved. +- Drag, Slider: Added ImGuiDragFlags and ImGuiSliderFlags parameters. + For float functions they replace the old trailing 'float power=1.0' parameter. + (See #3361 and the "Breaking Changes" block above for all details). +- Drag, Slider: Added ImGuiDragFlags_Logarithmic/ImGuiSliderFlags_Logarithmic flags to + enable logarithmic editing (generally more precision around zero), as a replacement to the old + 'float power' parameter which was obsoleted. (#1823, #1316, #642) [@Shironekoben, @AndrewBelt] - DragFloatRange2, DragIntRange2: Fixed an issue allowing to drag out of bounds when both min and max value are on the same value. (#1441) - InputText, ImDrawList: Fixed assert triggering when drawing single line of text with more diff --git a/imgui.cpp b/imgui.cpp index a9aabfdb0..197ce1f92 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -372,6 +372,14 @@ CODE When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar(). + replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags). + worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. in short, when calling those functions: + - if you omitted the 'power' parameter (likely!), you are not affected. + - if you set the 'power' parameter to 1.0f (same as previous default value): 1/ your compiler may warn on float>int conversion, 2/ everything else will work. 3/ you can replace the 1.0f value with 0 to fix the warning, and be technically correct. + - if you set the 'power' parameter to >1.0f (to enable non-linear editing): 1/ your compiler may warn on float>int conversion, 2/ code will assert at runtime, 3/ in case asserts are disabled, the code will not crash and enable the _Logarithmic flag. 4/ you can replace the >1.0f value with ImGuiDragFlags_Logarithmic or ImGuiSliderFlags_Logarithmic flag to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f. + see https://github.com/ocornut/imgui/issues/3361 for all details. + kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version were removed directly as they were most unlikely ever used. - 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems. - 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete). - 2020/06/15 (1.77) - removed CalcItemRectClosestPoint() entry point which was made obsolete and asserting in December 2017. diff --git a/imgui.h b/imgui.h index dc62afc0f..59eb6d043 100644 --- a/imgui.h +++ b/imgui.h @@ -60,7 +60,7 @@ Index of this file: // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) #define IMGUI_VERSION "1.78 WIP" -#define IMGUI_VERSION_NUM 17703 +#define IMGUI_VERSION_NUM 17704 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) // Define attributes of all API symbols declarations (e.g. for DLL under Windows) @@ -467,6 +467,8 @@ namespace ImGui // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). // - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits. // - Use v_max = FLT_MAX / INT_MAX etc to avoid clamping to a maximum, same with v_min = -FLT_MAX / INT_MIN to avoid clamping to a minimum. + // - Legacy: Pre-1.78 there are DragXXX() function signatures that takes a final `float power=1.0f' argument instead of the `ImGuiDragFlags flags=0' argument. + // If you get a warning converting a float to ImGuiDragFlags, read https://github.com/ocornut/imgui/issues/3361 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* format = "%.3f", ImGuiDragFlags flags = 0); // If v_min >= v_max we have no bound IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiDragFlags flags = 0); IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiDragFlags flags = 0); @@ -483,6 +485,8 @@ namespace ImGui // Widgets: Sliders // - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped and can go off-bounds. // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. + // - Legacy: Pre-1.78 there are SliderXXX() function signatures that takes a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument. + // If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361 IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); @@ -1703,23 +1707,20 @@ struct ImGuiPayload #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS namespace ImGui { - // OBSOLETED in 1.78 (from July 2020) + // OBSOLETED in 1.78 (from August 2020) // Old drag/sliders functions that took a 'float power = 1.0' argument instead of flags - IMGUI_API bool DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power); - IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power); - IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power); - IMGUI_API bool DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power); - IMGUI_API bool DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, float power); IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power); IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power); - IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power); - IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power); - IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power); - IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power); + static inline bool DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); } + static inline bool DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); } + static inline bool DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); } + static inline bool DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); } IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power); IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format, float power); - IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, float power); - IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power); + static inline bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power) { return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); } + static inline bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); } + static inline bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); } + static inline bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); } // OBSOLETED in 1.77 (from June 2020) static inline bool OpenPopupOnItemClick(const char* str_id = NULL, ImGuiMouseButton mb = 1) { return OpenPopupContextItem(str_id, mb); } // Passing a mouse button to ImGuiPopupFlags is legal static inline bool BeginPopupContextWindow(const char* str_id, ImGuiMouseButton mb, bool over_items) { return BeginPopupContextWindow(str_id, mb | (over_items ? 0 : ImGuiPopupFlags_NoOpenOverItems)); } diff --git a/imgui_internal.h b/imgui_internal.h index c2d58a185..95ce67c09 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1979,27 +1979,20 @@ namespace ImGui // Widgets low-level behaviors IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); - IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, float power, ImGuiDragFlags flags); - IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb); + IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiDragFlags flags); + IMGUI_API bool 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); IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f); IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextItemOpen() data, if any. May return true when logging IMGUI_API void TreePushOverrideID(ImGuiID id); - // Internal implementations for some of the exposed functions (use the non-internal versions instead) - IMGUI_API bool DragScalarInternal(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, float power = 1.0f, ImGuiDragFlags flags = 0); - IMGUI_API bool DragScalarNInternal(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, float power = 1.0f, ImGuiDragFlags flags = 0); - IMGUI_API bool DragFloatRange2Internal(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format = NULL, const char* format_max = NULL, float power = 1.0f, ImGuiDragFlags flags = 0); - IMGUI_API bool SliderScalarInternal(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, float power = 1.0f, ImGuiSliderFlags flags = 0); - IMGUI_API bool SliderScalarNInternal(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min = NULL, const void* v_max = NULL, const char* format = NULL, float power = 1.0f, ImGuiSliderFlags flags = 0); - IMGUI_API bool VSliderScalarInternal(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, float power = 1.0f, ImGuiSliderFlags flags = 0); // Template functions are instantiated in imgui_widgets.cpp for a finite number of types. // To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036). // e.g. " extern template IMGUI_API float RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, float v); " - template IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, float power, ImGuiDragFlags flags); - template IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb); - template IMGUI_API float SliderCalcRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, float power, float linear_zero_pos, float logarithmic_zero_epsilon, ImGuiSliderFlags flags); - template IMGUI_API T SliderCalcValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, float power, float linear_zero_pos, float logarithmic_zero_epsilon, ImGuiSliderFlags flags); + template IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, ImGuiDragFlags flags); + template IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb); + template IMGUI_API float SliderCalcRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, float logarithmic_zero_epsilon, ImGuiSliderFlags flags); + template IMGUI_API T SliderCalcValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, float logarithmic_zero_epsilon, ImGuiSliderFlags flags); template IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v); // Data type helpers diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6de8ce12d..65021bbaa 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1997,14 +1997,13 @@ TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, // This is called by DragBehavior() when the widget is active (held by mouse or being manipulated with Nav controls) template -bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiDragFlags flags) +bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, ImGuiDragFlags flags) { ImGuiContext& g = *GImGui; const ImGuiAxis axis = (flags & ImGuiDragFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); const bool is_clamped = (v_min < v_max); const bool is_logarithmic = (flags & ImGuiDragFlags_Logarithmic) && is_decimal; - const bool is_power = (power != 1.0f && !is_logarithmic && is_decimal && is_clamped && (v_max - v_min < FLT_MAX)); const bool is_locked = (v_min > v_max); if (is_locked) return false; @@ -2043,8 +2042,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const // 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)); - bool is_drag_direction_change_with_power = is_power && ((adjust_delta < 0 && g.DragCurrentAccum > 0) || (adjust_delta > 0 && g.DragCurrentAccum < 0)); - if (is_just_activated || is_already_past_limits_and_pushing_outward || is_drag_direction_change_with_power) + if (is_just_activated || is_already_past_limits_and_pushing_outward) { g.DragCurrentAccum = 0.0f; g.DragCurrentAccumDirty = false; @@ -2069,20 +2067,11 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision); // Convert to parametric space, apply delta, convert back - // We pass 0.0f as linear_zero_pos because we know we are never in power mode here and so don't need it - float v_old_parametric = SliderCalcRatioFromValueT(data_type, v_cur, v_min, v_max, power, /*linear_zero_pos*/ 0.0f, logarithmic_zero_epsilon, flags); + float v_old_parametric = SliderCalcRatioFromValueT(data_type, v_cur, v_min, v_max, logarithmic_zero_epsilon, flags); float v_new_parametric = v_old_parametric + g.DragCurrentAccum; - v_cur = SliderCalcValueFromRatioT(data_type, v_new_parametric, v_min, v_max, power, /*linear_zero_pos*/ 0.0f, logarithmic_zero_epsilon, flags); + v_cur = SliderCalcValueFromRatioT(data_type, v_new_parametric, v_min, v_max, logarithmic_zero_epsilon, flags); v_old_ref_for_accum_remainder = v_old_parametric; } - else if (is_power) - { - // Offset + round to user desired precision, with a curve on the v_min..v_max range to get more precision on one side of the range - FLOATTYPE v_old_norm_curved = ImPow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power); - FLOATTYPE v_new_norm_curved = v_old_norm_curved + (g.DragCurrentAccum / (v_max - v_min)); - v_cur = v_min + (SIGNEDTYPE)ImPow(ImSaturate((float)v_new_norm_curved), power) * (v_max - v_min); - v_old_ref_for_accum_remainder = v_old_norm_curved; - } else { v_cur += (SIGNEDTYPE)g.DragCurrentAccum; @@ -2096,15 +2085,9 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const if (is_logarithmic) { // Convert to parametric space, apply delta, convert back - // We pass 0.0f as linear_zero_pos because we know we are never in power mode here and so don't need it - float v_new_parametric = SliderCalcRatioFromValueT(data_type, v_cur, v_min, v_max, power, /*linear_zero_pos*/ 0.0f, logarithmic_zero_epsilon, flags); + float v_new_parametric = SliderCalcRatioFromValueT(data_type, v_cur, v_min, v_max, logarithmic_zero_epsilon, flags); g.DragCurrentAccum -= (float)(v_new_parametric - v_old_ref_for_accum_remainder); } - else if (is_power) - { - FLOATTYPE v_cur_norm_curved = ImPow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power); - g.DragCurrentAccum -= (float)(v_cur_norm_curved - v_old_ref_for_accum_remainder); - } else { g.DragCurrentAccum -= (float)((SIGNEDTYPE)v_cur - (SIGNEDTYPE)*v); @@ -2130,9 +2113,10 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const return true; } -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, float power, ImGuiDragFlags flags) +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, ImGuiDragFlags flags) { - IM_ASSERT((flags == 1 || (flags & ImGuiDragFlags_InvalidMask_) == 0) && "Invalid ImGuiDragFlags flags! Has a power term been mistakenly cast to flags?"); + // Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert. + IM_ASSERT((flags == 1 || (flags & ImGuiDragFlags_InvalidMask_) == 0) && "Invalid ImGuiDragFlags flags! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiDragFlags_Logarithmic flags instead."); ImGuiContext& g = *GImGui; if (g.ActiveId == id) @@ -2149,32 +2133,30 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v switch (data_type) { - case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS8*) p_min : IM_S8_MIN, p_max ? *(const ImS8*)p_max : IM_S8_MAX, format, power, flags); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } - case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU8*) p_min : IM_U8_MIN, p_max ? *(const ImU8*)p_max : IM_U8_MAX, format, power, flags); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } - case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS16*)p_min : IM_S16_MIN, p_max ? *(const ImS16*)p_max : IM_S16_MAX, format, power, flags); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } - case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU16*)p_min : IM_U16_MIN, p_max ? *(const ImU16*)p_max : IM_U16_MAX, format, power, flags); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } - case ImGuiDataType_S32: return DragBehaviorT(data_type, (ImS32*)p_v, v_speed, p_min ? *(const ImS32* )p_min : IM_S32_MIN, p_max ? *(const ImS32* )p_max : IM_S32_MAX, format, power, flags); - case ImGuiDataType_U32: return DragBehaviorT(data_type, (ImU32*)p_v, v_speed, p_min ? *(const ImU32* )p_min : IM_U32_MIN, p_max ? *(const ImU32* )p_max : IM_U32_MAX, format, power, flags); - case ImGuiDataType_S64: return DragBehaviorT(data_type, (ImS64*)p_v, v_speed, p_min ? *(const ImS64* )p_min : IM_S64_MIN, p_max ? *(const ImS64* )p_max : IM_S64_MAX, format, power, flags); - case ImGuiDataType_U64: return DragBehaviorT(data_type, (ImU64*)p_v, v_speed, p_min ? *(const ImU64* )p_min : IM_U64_MIN, p_max ? *(const ImU64* )p_max : IM_U64_MAX, format, power, flags); - case ImGuiDataType_Float: return DragBehaviorT(data_type, (float*)p_v, v_speed, p_min ? *(const float* )p_min : -FLT_MAX, p_max ? *(const float* )p_max : FLT_MAX, format, power, flags); - case ImGuiDataType_Double: return DragBehaviorT(data_type, (double*)p_v, v_speed, p_min ? *(const double*)p_min : -DBL_MAX, p_max ? *(const double*)p_max : DBL_MAX, format, power, flags); + case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS8*) p_min : IM_S8_MIN, p_max ? *(const ImS8*)p_max : IM_S8_MAX, format, flags); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } + case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU8*) p_min : IM_U8_MIN, p_max ? *(const ImU8*)p_max : IM_U8_MAX, format, flags); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } + case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS16*)p_min : IM_S16_MIN, p_max ? *(const ImS16*)p_max : IM_S16_MAX, format, flags); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } + case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU16*)p_min : IM_U16_MIN, p_max ? *(const ImU16*)p_max : IM_U16_MAX, format, flags); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } + case ImGuiDataType_S32: return DragBehaviorT(data_type, (ImS32*)p_v, v_speed, p_min ? *(const ImS32* )p_min : IM_S32_MIN, p_max ? *(const ImS32* )p_max : IM_S32_MAX, format, flags); + case ImGuiDataType_U32: return DragBehaviorT(data_type, (ImU32*)p_v, v_speed, p_min ? *(const ImU32* )p_min : IM_U32_MIN, p_max ? *(const ImU32* )p_max : IM_U32_MAX, format, flags); + case ImGuiDataType_S64: return DragBehaviorT(data_type, (ImS64*)p_v, v_speed, p_min ? *(const ImS64* )p_min : IM_S64_MIN, p_max ? *(const ImS64* )p_max : IM_S64_MAX, format, flags); + case ImGuiDataType_U64: return DragBehaviorT(data_type, (ImU64*)p_v, v_speed, p_min ? *(const ImU64* )p_min : IM_U64_MIN, p_max ? *(const ImU64* )p_max : IM_U64_MAX, format, flags); + case ImGuiDataType_Float: return DragBehaviorT(data_type, (float*)p_v, v_speed, p_min ? *(const float* )p_min : -FLT_MAX, p_max ? *(const float* )p_max : FLT_MAX, format, flags); + case ImGuiDataType_Double: return DragBehaviorT(data_type, (double*)p_v, v_speed, p_min ? *(const double*)p_min : -DBL_MAX, p_max ? *(const double*)p_max : DBL_MAX, format, flags); case ImGuiDataType_COUNT: break; } IM_ASSERT(0); return false; } -// Internal implementation - see below for entry points -bool ImGui::DragScalarInternal(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power, ImGuiDragFlags flags) +// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max are optional. +// Read code of e.g. DragFloat(), DragInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. +bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiDragFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; - if (power != 1.0f) - IM_ASSERT(p_min != NULL && p_max != NULL); // When using a power curve the drag needs to have known bounds - ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); @@ -2225,7 +2207,7 @@ bool ImGui::DragScalarInternal(const char* label, ImGuiDataType data_type, void* RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); // Drag behavior - const bool value_changed = DragBehavior(id, data_type, p_data, v_speed, p_min, p_max, format, power, flags); + const bool value_changed = DragBehavior(id, data_type, p_data, v_speed, p_min, p_max, format, flags); if (value_changed) MarkItemEdited(id); @@ -2241,15 +2223,7 @@ bool ImGui::DragScalarInternal(const char* label, ImGuiDataType data_type, void* return value_changed; } -// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max are optional. -// Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. -bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiDragFlags flags) -{ - return DragScalarInternal(label, data_type, p_data, v_speed, p_min, p_max, format, 1.0f, flags); -} - -// Internal implementation - see below for entry points -bool ImGui::DragScalarNInternal(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power, ImGuiDragFlags flags) +bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiDragFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -2266,7 +2240,7 @@ bool ImGui::DragScalarNInternal(const char* label, ImGuiDataType data_type, void PushID(i); if (i > 0) SameLine(0, g.Style.ItemInnerSpacing.x); - value_changed |= DragScalarInternal("", data_type, p_data, v_speed, p_min, p_max, format, power, flags); + value_changed |= DragScalar("", data_type, p_data, v_speed, p_min, p_max, format, flags); PopID(); PopItemWidth(); p_data = (void*)((char*)p_data + type_size); @@ -2284,11 +2258,6 @@ bool ImGui::DragScalarNInternal(const char* label, ImGuiDataType data_type, void return value_changed; } -bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiDragFlags flags) -{ - return DragScalarNInternal(label, data_type, p_data, components, v_speed, p_min, p_max, format, 1.0f, flags); -} - bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, ImGuiDragFlags flags) { return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, flags); @@ -2309,8 +2278,7 @@ bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, flags); } -// Internal implementation -bool ImGui::DragFloatRange2Internal(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, float power, ImGuiDragFlags flags) +bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, ImGuiDragFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -2324,14 +2292,14 @@ bool ImGui::DragFloatRange2Internal(const char* label, float* v_current_min, flo float min = (v_min >= v_max) ? -FLT_MAX : v_min; float max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max); if (min == max) { min = FLT_MAX; max = -FLT_MAX; } // Lock edit - bool value_changed = DragScalarInternal("##min", ImGuiDataType_Float, v_current_min, v_speed, &min, &max, format, power, flags); + bool value_changed = DragScalar("##min", ImGuiDataType_Float, v_current_min, v_speed, &min, &max, format, flags); PopItemWidth(); SameLine(0, g.Style.ItemInnerSpacing.x); min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min); max = (v_min >= v_max) ? FLT_MAX : v_max; if (min == max) { min = FLT_MAX; max = -FLT_MAX; } // Lock edit - value_changed |= DragScalarInternal("##max", ImGuiDataType_Float, v_current_max, v_speed, &min, &max, format_max ? format_max : format, power, flags); + value_changed |= DragScalar("##max", ImGuiDataType_Float, v_current_max, v_speed, &min, &max, format_max ? format_max : format, flags); PopItemWidth(); SameLine(0, g.Style.ItemInnerSpacing.x); @@ -2341,11 +2309,6 @@ bool ImGui::DragFloatRange2Internal(const char* label, float* v_current_min, flo return value_changed; } -bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, ImGuiDragFlags flags) -{ - return DragFloatRange2Internal(label, v_current_min, v_current_max, v_speed, v_min, v_max, format, format_max, 1.0f, flags); -} - // NB: v_speed is float to allow adjusting the drag speed with more precision bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format, ImGuiDragFlags flags) { @@ -2401,40 +2364,29 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -// Obsolete versions with power parameter +// Obsolete versions with power parameter. See https://github.com/ocornut/imgui/issues/3361 for details. bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power) { - return DragScalarInternal(label, data_type, p_data, v_speed, p_min, p_max, format, power, ImGuiDragFlags_None); + ImGuiDragFlags drag_flags = ImGuiDragFlags_None; + if (power != 1.0f) + { + IM_ASSERT(power == 1.0f && "Call function with ImGuiDragFlags_Logarithmic flags instead of using the old 'float power' function!"); + IM_ASSERT(p_min != NULL && p_max != NULL); // When using a power curve the drag needs to have known bounds + drag_flags |= ImGuiDragFlags_Logarithmic; // Fallback for non-asserting paths + } + return DragScalar(label, data_type, p_data, v_speed, p_min, p_max, format, drag_flags); } bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power) { - return DragScalarNInternal(label, data_type, p_data, components, v_speed, p_min, p_max, format, power); -} - -bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power) -{ - return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); -} - -bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power) -{ - return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); -} - -bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power) -{ - return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); -} - -bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power) -{ - return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); -} - -bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, float power) -{ - return DragFloatRange2Internal(label, v_current_min, v_current_max, v_speed, v_min, v_max, format, format_max, power); + ImGuiDragFlags drag_flags = ImGuiDragFlags_None; + if (power != 1.0f) + { + IM_ASSERT(power == 1.0f && "Call function with ImGuiDragFlags_Logarithmic flags instead of using the old 'float power' function!"); + IM_ASSERT(p_min != NULL && p_max != NULL); // When using a power curve the drag needs to have known bounds + drag_flags |= ImGuiDragFlags_Logarithmic; // Fallback for non-asserting paths + } + return DragScalarN(label, data_type, p_data, components, v_speed, p_min, p_max, format, drag_flags); } #endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS @@ -2462,13 +2414,12 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu // Convert a value v in the output space of a slider into a parametric position on the slider itself (the logical opposite of SliderCalcValueFromRatioT) template -float ImGui::SliderCalcRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, float power, float linear_zero_pos, float logarithmic_zero_epsilon, ImGuiSliderFlags flags) +float ImGui::SliderCalcRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, float logarithmic_zero_epsilon, ImGuiSliderFlags flags) { if (v_min == v_max) return 0.0f; const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) && (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double); - const bool is_power = (power != 1.0f) && (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) && (!is_logarithmic); const TYPE v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min); if (is_logarithmic) { @@ -2510,19 +2461,6 @@ float ImGui::SliderCalcRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_m return flipped ? (1.0f - result) : result; } - else if (is_power) - { - if (v_clamped < 0.0f) - { - const float f = 1.0f - (float)((v_clamped - v_min) / (ImMin((TYPE)0, v_max) - v_min)); - return (1.0f - ImPow(f, 1.0f / power)) * linear_zero_pos; - } - else - { - const float f = (float)((v_clamped - ImMax((TYPE)0, v_min)) / (v_max - ImMax((TYPE)0, v_min))); - return linear_zero_pos + ImPow(f, 1.0f / power) * (1.0f - linear_zero_pos); - } - } // Linear slider return (float)((FLOATTYPE)(v_clamped - v_min) / (FLOATTYPE)(v_max - v_min)); @@ -2530,14 +2468,13 @@ float ImGui::SliderCalcRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_m // Convert a parametric position on a slider into a value v in the output space (the logical opposite of SliderCalcRatioFromValueT) template -TYPE ImGui::SliderCalcValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, float power, float linear_zero_pos, float logarithmic_zero_epsilon, ImGuiSliderFlags flags) +TYPE ImGui::SliderCalcValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, float logarithmic_zero_epsilon, ImGuiSliderFlags flags) { if (v_min == v_max) return (TYPE)0.0f; const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) && (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double); - const bool is_power = (power != 1.0f) && (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) && (!is_logarithmic); TYPE result; if (is_logarithmic) @@ -2580,28 +2517,6 @@ TYPE ImGui::SliderCalcValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_m result = (TYPE)(v_min_fudged * ImPow(v_max_fudged / v_min_fudged, (FLOATTYPE)t_with_flip)); } } - else if (is_power) - { - // Account for power curve scale on both sides of the zero - if (t < linear_zero_pos) - { - // Negative: rescale to the negative range before powering - float a = 1.0f - (t / linear_zero_pos); - a = ImPow(a, power); - result = ImLerp(ImMin(v_max, (TYPE)0), v_min, a); - } - else - { - // Positive: rescale to the positive range before powering - float a; - if (ImFabs(linear_zero_pos - 1.0f) > 1.e-6f) - a = (t - linear_zero_pos) / (1.0f - linear_zero_pos); - else - a = t; - a = ImPow(a, power); - result = ImLerp(ImMax(v_min, (TYPE)0), v_max, a); - } - } else { // Linear slider @@ -2628,7 +2543,7 @@ TYPE ImGui::SliderCalcValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_m // FIXME: Move some of the code into SliderBehavior(). Current responsibility is larger than what the equivalent DragBehaviorT<> does, we also do some rendering, etc. template -bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb) +bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb) { ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; @@ -2636,7 +2551,6 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) && is_decimal; - const bool is_power = (power != 1.0f) && is_decimal && (!is_logarithmic); const float grab_padding = 2.0f; const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f; @@ -2649,21 +2563,6 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f; const float slider_usable_pos_max = bb.Max[axis] - grab_padding - grab_sz * 0.5f; - // For power curve sliders that cross over sign boundary we want the curve to be symmetric around 0.0f - float linear_zero_pos; // 0.0->1.0f - if (is_power && v_min * v_max < 0.0f) - { - // Different sign - const FLOATTYPE linear_dist_min_to_0 = ImPow(v_min >= 0 ? (FLOATTYPE)v_min : -(FLOATTYPE)v_min, (FLOATTYPE)1.0f / power); - const FLOATTYPE linear_dist_max_to_0 = ImPow(v_max >= 0 ? (FLOATTYPE)v_max : -(FLOATTYPE)v_max, (FLOATTYPE)1.0f / power); - linear_zero_pos = (float)(linear_dist_min_to_0 / (linear_dist_min_to_0 + linear_dist_max_to_0)); - } - else - { - // Same sign - linear_zero_pos = v_min < 0.0f ? 1.0f : 0.0f; - } - float logarithmic_zero_epsilon = 0.0f; // Only valid when is_logarithmic is true if (is_logarithmic) { @@ -2703,9 +2602,9 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ } else if (delta != 0.0f) { - clicked_t = SliderCalcRatioFromValueT(data_type, *v, v_min, v_max, power, linear_zero_pos, logarithmic_zero_epsilon, flags); + clicked_t = SliderCalcRatioFromValueT(data_type, *v, v_min, v_max, logarithmic_zero_epsilon, flags); const int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 0; - if ((decimal_precision > 0) || is_power) + if (decimal_precision > 0) { delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds if (IsNavInputDown(ImGuiNavInput_TweakSlow)) @@ -2730,7 +2629,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ if (set_new_value) { - TYPE v_new = SliderCalcValueFromRatioT(data_type, clicked_t, v_min, v_max, power, linear_zero_pos, logarithmic_zero_epsilon, flags); + TYPE v_new = SliderCalcValueFromRatioT(data_type, clicked_t, v_min, v_max, logarithmic_zero_epsilon, flags); // Round to user desired precision based on format string v_new = RoundScalarWithFormatT(format, data_type, v_new); @@ -2751,7 +2650,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ else { // Output grab position so it can be displayed by the caller - float grab_t = SliderCalcRatioFromValueT(data_type, *v, v_min, v_max, power, linear_zero_pos, logarithmic_zero_epsilon, flags); + float grab_t = SliderCalcRatioFromValueT(data_type, *v, v_min, v_max, logarithmic_zero_epsilon, flags); if (axis == ImGuiAxis_Y) grab_t = 1.0f - grab_t; const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); @@ -2767,9 +2666,10 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ // For 32-bit and larger types, slider bounds are limited to half the natural type range. // So e.g. an integer Slider between INT_MAX-10 and INT_MAX will fail, but an integer Slider between INT_MAX/2-10 and INT_MAX/2 will be ok. // It would be possible to lift that limitation with some work but it doesn't seem to be worth it for sliders. -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, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb) +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) { - IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flag! Has a power term been mistakenly cast to 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 flag! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); ImGuiContext& g = *GImGui; if (g.CurrentWindow->DC.ItemFlags & ImGuiItemFlags_ReadOnly) @@ -2777,36 +2677,37 @@ bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type switch (data_type) { - case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)p_min, *(const ImS8*)p_max, format, power, flags, out_grab_bb); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } - case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU8*)p_min, *(const ImU8*)p_max, format, power, flags, out_grab_bb); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } - case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS16*)p_min, *(const ImS16*)p_max, format, power, flags, out_grab_bb); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } - case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU16*)p_min, *(const ImU16*)p_max, format, power, flags, out_grab_bb); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } + case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)p_min, *(const ImS8*)p_max, format, flags, out_grab_bb); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } + case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU8*)p_min, *(const ImU8*)p_max, format, flags, out_grab_bb); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } + case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS16*)p_min, *(const ImS16*)p_max, format, flags, out_grab_bb); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } + case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU16*)p_min, *(const ImU16*)p_max, format, flags, out_grab_bb); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } case ImGuiDataType_S32: IM_ASSERT(*(const ImS32*)p_min >= IM_S32_MIN / 2 && *(const ImS32*)p_max <= IM_S32_MAX / 2); - return SliderBehaviorT(bb, id, data_type, (ImS32*)p_v, *(const ImS32*)p_min, *(const ImS32*)p_max, format, power, flags, out_grab_bb); + return SliderBehaviorT(bb, id, data_type, (ImS32*)p_v, *(const ImS32*)p_min, *(const ImS32*)p_max, format, flags, out_grab_bb); case ImGuiDataType_U32: IM_ASSERT(*(const ImU32*)p_max <= IM_U32_MAX / 2); - return SliderBehaviorT(bb, id, data_type, (ImU32*)p_v, *(const ImU32*)p_min, *(const ImU32*)p_max, format, power, flags, out_grab_bb); + return SliderBehaviorT(bb, id, data_type, (ImU32*)p_v, *(const ImU32*)p_min, *(const ImU32*)p_max, format, flags, out_grab_bb); case ImGuiDataType_S64: IM_ASSERT(*(const ImS64*)p_min >= IM_S64_MIN / 2 && *(const ImS64*)p_max <= IM_S64_MAX / 2); - return SliderBehaviorT(bb, id, data_type, (ImS64*)p_v, *(const ImS64*)p_min, *(const ImS64*)p_max, format, power, flags, out_grab_bb); + return SliderBehaviorT(bb, id, data_type, (ImS64*)p_v, *(const ImS64*)p_min, *(const ImS64*)p_max, format, flags, out_grab_bb); case ImGuiDataType_U64: IM_ASSERT(*(const ImU64*)p_max <= IM_U64_MAX / 2); - return SliderBehaviorT(bb, id, data_type, (ImU64*)p_v, *(const ImU64*)p_min, *(const ImU64*)p_max, format, power, flags, out_grab_bb); + return SliderBehaviorT(bb, id, data_type, (ImU64*)p_v, *(const ImU64*)p_min, *(const ImU64*)p_max, format, flags, out_grab_bb); case ImGuiDataType_Float: IM_ASSERT(*(const float*)p_min >= -FLT_MAX / 2.0f && *(const float*)p_max <= FLT_MAX / 2.0f); - return SliderBehaviorT(bb, id, data_type, (float*)p_v, *(const float*)p_min, *(const float*)p_max, format, power, flags, out_grab_bb); + return SliderBehaviorT(bb, id, data_type, (float*)p_v, *(const float*)p_min, *(const float*)p_max, format, flags, out_grab_bb); case ImGuiDataType_Double: IM_ASSERT(*(const double*)p_min >= -DBL_MAX / 2.0f && *(const double*)p_max <= DBL_MAX / 2.0f); - return SliderBehaviorT(bb, id, data_type, (double*)p_v, *(const double*)p_min, *(const double*)p_max, format, power, flags, out_grab_bb); + return SliderBehaviorT(bb, id, data_type, (double*)p_v, *(const double*)p_min, *(const double*)p_max, format, flags, out_grab_bb); case ImGuiDataType_COUNT: break; } IM_ASSERT(0); return false; } -// Internal implementation -bool ImGui::SliderScalarInternal(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power, ImGuiSliderFlags flags) +// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a slider, they are all required. +// Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. +bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -2863,7 +2764,7 @@ bool ImGui::SliderScalarInternal(const char* label, ImGuiDataType data_type, voi // Slider behavior ImRect grab_bb; - const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, power, flags, &grab_bb); + const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, flags, &grab_bb); if (value_changed) MarkItemEdited(id); @@ -2883,14 +2784,8 @@ bool ImGui::SliderScalarInternal(const char* label, ImGuiDataType data_type, voi return value_changed; } -// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a slider, they are all required. -// Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. -bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) -{ - return SliderScalarInternal(label, data_type, p_data, p_min, p_max, format, 1.0f, flags); -} - -bool ImGui::SliderScalarNInternal(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags) +// Add multiple sliders on 1 line for compact edition of multiple components +bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, ImGuiSliderFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -2907,7 +2802,7 @@ bool ImGui::SliderScalarNInternal(const char* label, ImGuiDataType data_type, vo PushID(i); if (i > 0) SameLine(0, g.Style.ItemInnerSpacing.x); - value_changed |= SliderScalarInternal("", data_type, v, v_min, v_max, format, power, flags); + value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, flags); PopID(); PopItemWidth(); v = (void*)((char*)v + type_size); @@ -2925,12 +2820,6 @@ bool ImGui::SliderScalarNInternal(const char* label, ImGuiDataType data_type, vo return value_changed; } -// Add multiple sliders on 1 line for compact edition of multiple components -bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, ImGuiSliderFlags flags) -{ - return SliderScalarNInternal(label, data_type, v, components, v_min, v_max, format, 1.0f, flags); -} - bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) { return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, flags); @@ -2981,8 +2870,7 @@ bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const return SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format, flags); } -// Internal implementation -bool ImGui::VSliderScalarInternal(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power, ImGuiSliderFlags flags) +bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -3022,7 +2910,7 @@ bool ImGui::VSliderScalarInternal(const char* label, const ImVec2& size, ImGuiDa // Slider behavior ImRect grab_bb; - const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, power, flags | ImGuiSliderFlags_Vertical, &grab_bb); + const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, flags | ImGuiSliderFlags_Vertical, &grab_bb); if (value_changed) MarkItemEdited(id); @@ -3041,11 +2929,6 @@ bool ImGui::VSliderScalarInternal(const char* label, const ImVec2& size, ImGuiDa return value_changed; } -bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) -{ - return VSliderScalarInternal(label, size, data_type, p_data, p_min, p_max, format, 1.0f, flags); -} - bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) { return VSliderScalar(label, size, ImGuiDataType_Float, v, &v_min, &v_max, format, flags); @@ -3058,45 +2941,27 @@ bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -// Obsolete versions with power parameter +// Obsolete versions with power parameter. See https://github.com/ocornut/imgui/issues/3361 for details. bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power) { - return SliderScalarInternal(label, data_type, p_data, p_min, p_max, format, power); + ImGuiSliderFlags slider_flags = ImGuiSliderFlags_None; + if (power != 1.0f) + { + IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!"); + slider_flags |= ImGuiSliderFlags_Logarithmic; // Fallback for non-asserting paths + } + return SliderScalar(label, data_type, p_data, p_min, p_max, format, slider_flags); } bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, float power) { - return SliderScalarNInternal(label, data_type, v, components, v_min, v_max, format, power); -} - -bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power) -{ - return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); -} - -bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power) -{ - return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); -} - -bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power) -{ - return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); -} - -bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power) -{ - return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); -} - -bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power) -{ - return VSliderScalarInternal(label, size, data_type, p_data, p_min, p_max, format, power); -} - -bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, float power) -{ - return VSliderScalar(label, size, ImGuiDataType_Float, v, &v_min, &v_max, format, power); + ImGuiSliderFlags slider_flags = ImGuiSliderFlags_None; + if (power != 1.0f) + { + IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!"); + slider_flags |= ImGuiSliderFlags_Logarithmic; // Fallback for non-asserting paths + } + return SliderScalarN(label, data_type, v, components, v_min, v_max, format, slider_flags); } #endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS