Internals: SliderBehaviorT: Minor refactor, clearer 0.0/1.0 early out. Should be no-op from user's point of view.

ScaleValueFromRatioT() had early 0.0/1.0 ratio tests, shifting most of function by one indent.
This commit is contained in:
ocornut 2022-06-20 16:44:49 +02:00
parent 90e8404a77
commit f27af1b20a

View File

@ -2615,7 +2615,6 @@ float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, T
v_max_fudged = -logarithmic_zero_epsilon; v_max_fudged = -logarithmic_zero_epsilon;
float result; float result;
if (v_clamped <= v_min_fudged) if (v_clamped <= v_min_fudged)
result = 0.0f; // Workaround for values that are in-range but below our fudge result = 0.0f; // Workaround for values that are in-range but below our fudge
else if (v_clamped >= v_max_fudged) else if (v_clamped >= v_max_fudged)
@ -2639,35 +2638,32 @@ float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, T
return flipped ? (1.0f - result) : result; return flipped ? (1.0f - result) : result;
} }
else
{
// Linear slider // Linear slider
return (float)((FLOATTYPE)(SIGNEDTYPE)(v_clamped - v_min) / (FLOATTYPE)(SIGNEDTYPE)(v_max - v_min)); return (float)((FLOATTYPE)(SIGNEDTYPE)(v_clamped - v_min) / (FLOATTYPE)(SIGNEDTYPE)(v_max - v_min));
} }
}
// Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT) // Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT)
template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE> template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize)
{ {
if (v_min == v_max) // We special-case the extents because otherwise our logarithmic fudging can lead to "mathematically correct"
// but non-intuitive behaviors like a fully-left slider not actually reaching the minimum value. Also generally simpler.
if (t <= 0.0f || v_min == v_max)
return v_min; return v_min;
const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); if (t >= 1.0f)
return v_max;
TYPE result; TYPE result = (TYPE)0;
if (is_logarithmic) if (is_logarithmic)
{ {
// We special-case the extents because otherwise our fudging can lead to "mathematically correct" but non-intuitive behaviors like a fully-left slider not actually reaching the minimum value
if (t <= 0.0f)
result = v_min;
else if (t >= 1.0f)
result = v_max;
else
{
bool flipped = v_max < v_min; // Check if range is "backwards"
// Fudge min/max to avoid getting silly results close to zero // Fudge min/max to avoid getting silly results close to zero
FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min; FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min;
FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max; FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max;
const bool flipped = v_max < v_min; // Check if range is "backwards"
if (flipped) if (flipped)
ImSwap(v_min_fudged, v_max_fudged); ImSwap(v_min_fudged, v_max_fudged);
@ -2694,36 +2690,29 @@ TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, T
else else
result = (TYPE)(v_min_fudged * ImPow(v_max_fudged / v_min_fudged, (FLOATTYPE)t_with_flip)); result = (TYPE)(v_min_fudged * ImPow(v_max_fudged / v_min_fudged, (FLOATTYPE)t_with_flip));
} }
}
else else
{ {
// Linear slider // Linear slider
const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
if (is_floating_point) if (is_floating_point)
{ {
result = ImLerp(v_min, v_max, t); result = ImLerp(v_min, v_max, t);
} }
else else if (t < 1.0)
{ {
// - For integer values we want the clicking position to match the grab box so we round above // - For integer values we want the clicking position to match the grab box so we round above
// This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property.. // This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property..
// - Not doing a *1.0 multiply at the end of a range as it tends to be lossy. While absolute aiming at a large s64/u64 // - Not doing a *1.0 multiply at the end of a range as it tends to be lossy. While absolute aiming at a large s64/u64
// range is going to be imprecise anyway, with this check we at least make the edge values matches expected limits. // range is going to be imprecise anyway, with this check we at least make the edge values matches expected limits.
if (t < 1.0)
{
FLOATTYPE v_new_off_f = (SIGNEDTYPE)(v_max - v_min) * t; FLOATTYPE v_new_off_f = (SIGNEDTYPE)(v_max - v_min) * t;
result = (TYPE)((SIGNEDTYPE)v_min + (SIGNEDTYPE)(v_new_off_f + (FLOATTYPE)(v_min > v_max ? -0.5 : 0.5))); result = (TYPE)((SIGNEDTYPE)v_min + (SIGNEDTYPE)(v_new_off_f + (FLOATTYPE)(v_min > v_max ? -0.5 : 0.5)));
} }
else
{
result = v_max;
}
}
} }
return result; return result;
} }
// FIXME: Move more of the code into SliderBehavior() // FIXME: Try to move more of the code into shared SliderBehavior()
template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE> template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
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) 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)
{ {
@ -2733,11 +2722,12 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0; const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0;
const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
const SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max);
const float grab_padding = 2.0f; // Calculate bounds
const float grab_padding = 2.0f; // FIXME: Should be part of style.
const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f; const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f;
float grab_sz = style.GrabMinSize; float grab_sz = style.GrabMinSize;
SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max);
if (!is_floating_point && v_range >= 0) // v_range < 0 may happen on integer overflows if (!is_floating_point && v_range >= 0) // v_range < 0 may happen on integer overflows
grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit
grab_sz = ImMin(grab_sz, slider_sz); grab_sz = ImMin(grab_sz, slider_sz);
@ -2770,7 +2760,8 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
else else
{ {
const float mouse_abs_pos = g.IO.MousePos[axis]; const float mouse_abs_pos = g.IO.MousePos[axis];
clicked_t = (slider_usable_sz > 0.0f) ? ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f) : 0.0f; if (slider_usable_sz > 0.0f)
clicked_t = ImSaturate((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz);
if (axis == ImGuiAxis_Y) if (axis == ImGuiAxis_Y)
clicked_t = 1.0f - clicked_t; clicked_t = 1.0f - clicked_t;
set_new_value = true; set_new_value = true;