| 2698 | // Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT) |
| 2699 | template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE> |
| 2700 | 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) |
| 2701 | { |
| 2702 | // We special-case the extents because otherwise our logarithmic fudging can lead to "mathematically correct" |
| 2703 | // but non-intuitive behaviors like a fully-left slider not actually reaching the minimum value. Also generally simpler. |
| 2704 | if (t <= 0.0f || v_min == v_max) |
| 2705 | return v_min; |
| 2706 | if (t >= 1.0f) |
| 2707 | return v_max; |
| 2708 | |
| 2709 | TYPE result = (TYPE)0; |
| 2710 | if (is_logarithmic) |
| 2711 | { |
| 2712 | // Fudge min/max to avoid getting silly results close to zero |
| 2713 | FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min; |
| 2714 | FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max; |
| 2715 | |
| 2716 | const bool flipped = v_max < v_min; // Check if range is "backwards" |
| 2717 | if (flipped) |
| 2718 | ImSwap(v_min_fudged, v_max_fudged); |
| 2719 | |
| 2720 | // Awkward special case - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon) |
| 2721 | if ((v_max == 0.0f) && (v_min < 0.0f)) |
| 2722 | v_max_fudged = -logarithmic_zero_epsilon; |
| 2723 | |
| 2724 | float t_with_flip = flipped ? (1.0f - t) : t; // t, but flipped if necessary to account for us flipping the range |
| 2725 | |
| 2726 | if ((v_min * v_max) < 0.0f) // Range crosses zero, so we have to do this in two parts |
| 2727 | { |
| 2728 | float zero_point_center = (-(float)ImMin(v_min, v_max)) / ImAbs((float)v_max - (float)v_min); // The zero point in parametric space |
| 2729 | float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize; |
| 2730 | float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize; |
| 2731 | if (t_with_flip >= zero_point_snap_L && t_with_flip <= zero_point_snap_R) |
| 2732 | result = (TYPE)0.0f; // Special case to make getting exactly zero possible (the epsilon prevents it otherwise) |
| 2733 | else if (t_with_flip < zero_point_center) |
| 2734 | result = (TYPE)-(logarithmic_zero_epsilon * ImPow(-v_min_fudged / logarithmic_zero_epsilon, (FLOATTYPE)(1.0f - (t_with_flip / zero_point_snap_L)))); |
| 2735 | else |
| 2736 | result = (TYPE)(logarithmic_zero_epsilon * ImPow(v_max_fudged / logarithmic_zero_epsilon, (FLOATTYPE)((t_with_flip - zero_point_snap_R) / (1.0f - zero_point_snap_R)))); |
| 2737 | } |
| 2738 | else if ((v_min < 0.0f) || (v_max < 0.0f)) // Entirely negative slider |
| 2739 | result = (TYPE)-(-v_max_fudged * ImPow(-v_min_fudged / -v_max_fudged, (FLOATTYPE)(1.0f - t_with_flip))); |
| 2740 | else |
| 2741 | result = (TYPE)(v_min_fudged * ImPow(v_max_fudged / v_min_fudged, (FLOATTYPE)t_with_flip)); |
| 2742 | } |
| 2743 | else |
| 2744 | { |
| 2745 | // Linear slider |
| 2746 | const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); |
| 2747 | if (is_floating_point) |
| 2748 | { |
| 2749 | result = ImLerp(v_min, v_max, t); |
| 2750 | } |
| 2751 | else if (t < 1.0) |
| 2752 | { |
| 2753 | // - For integer values we want the clicking position to match the grab box so we round above |
| 2754 | // This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property.. |
| 2755 | // - 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 |
| 2756 | // range is going to be imprecise anyway, with this check we at least make the edge values matches expected limits. |
| 2757 | FLOATTYPE v_new_off_f = (SIGNEDTYPE)(v_max - v_min) * t; |