Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SliderInt/Float Doesn't Handle Max == Min Correctly. #919

Closed
skl131313 opened this issue Nov 24, 2016 · 16 comments
Closed

SliderInt/Float Doesn't Handle Max == Min Correctly. #919

skl131313 opened this issue Nov 24, 2016 · 16 comments

Comments

@skl131313
Copy link

skl131313 commented Nov 24, 2016

The SliderInt implementation is just a SliderFloat, so the problem exists there as well. If you set min and max to the same value, then the outputted value will be outside the bounds of "min" and "max" when the user attempts to move the slider. It appears it might be because of a division by zero (exists in a few other places as well). Which causes the result to be NaN, which is then converted to an integer in SliderInt.

@ocornut
Copy link
Owner

ocornut commented Nov 27, 2016

It is illegal to pass a null range to SliderInt / SliderFloat. What would you expect it to happens appart from erroring/asserting?

Early 1.0-era version of imgui supported it by disabling the actual slider behavior but that code-path got removed while cleaning up.

@ocornut
Copy link
Owner

ocornut commented Nov 27, 2016

@sprinkle131313 Could you provide a repro for the outputted value will be outside the bounds of "min" and "max". Afaik, the code you linked only affects the position of the drawn sliders but values assignments looks right to me:
new_value = ImLerp(v_min, v_max, clicked_t);

ocornut added a commit that referenced this issue Nov 27, 2016
@skl131313
Copy link
Author

skl131313 commented Nov 28, 2016

@ocornut
Not sure if it is considered a null range. The bounds is inclusive for the range. I'm using the slider as the index for an array. So to allow for it to exist for an array of size 1, min and max have to be equal. Using the range [0, 1] would allow the values 0 and 1 to be valid. But only 0 is actually valid. On the other hand [0, 1) would be the range I need and in that case [0, 0) is a null range. But [0, 0] has a value.

Ah I linked to the master and it changed before you looked at the link. Here it does max - min, which can lead to division by zero.

To reproduce it, just create a SliderInt where min and max are 0 or equal, then in the UI click the slider and drag left/right quickly trying to change the value.

ocornut added a commit that referenced this issue Nov 28, 2016
…o be consistent with other widget behaviors (#919)
@ocornut
Copy link
Owner

ocornut commented Nov 28, 2016

You are right that it makes sense namely for integer.

That code you linked doesn't affect the value itself, which is why I am reacting to your "the outputted value" comment. I guess because my test bed doesn't throw an exception on divide-by-zero I don't see that affect and the grab is invisible (which may be desirable).

I made the display works (and it makes more senses for integers).
And reverted a change from yesterday that prevented the value from being written if with a v_min==v_max range. It does now write to the write when interacting with the slider, which is consistent with other widgets behaviors. So if your range is [1,1] and your value is 2 it'll stay 2 until you click.

@ocornut
Copy link
Owner

ocornut commented Nov 28, 2016

Confusion lies in the fact that I don't think " then the outputted value will be outside the bounds of "min" and "max" when the user attempts to move the slider " was ever true.

@skl131313
Copy link
Author

skl131313 commented Nov 28, 2016

Yah your right, my mistake. A division of zero was happening but I didn't look closely enough to find the right place.

If max == min, then this value will be zero

Which leads to a division by zero here. Causing normalized_pos to be NaN. Which ends up propagating to new_value. It then compares the old value with NaN, which is true as it can't be equal.

It doesn't seem to happen all the time, it might be under a certain condition. Clicking rapidly and moving slowly seems to cause as well as click-holding and moving the mouse rapidly left/right.

@ocornut
Copy link
Owner

ocornut commented Nov 28, 2016

Yah your right, my mistake. A division of zero was happening but I didn't look closely enough to find the right place.
If max == min, then this value will be zero

I don't understand your statement, if you look at the code it doesn't appear to read like what you say.

(There is one bug, which I'm fixing now, happening for integers if v_min is > v_max if (v_min - v_max)==-1, but that feature was introduced yesterday.)

@ocornut
Copy link
Owner

ocornut commented Nov 28, 2016

I don't think there is any issue left but as you imply so let me know if there's anything I can check.

@skl131313
Copy link
Author

Not sure what is happening then but it is definitely being set to NaN.

debug

@ocornut
Copy link
Owner

ocornut commented Nov 29, 2016

Oh but you are still using the old code. I made commits to fix the issues.

@skl131313
Copy link
Author

skl131313 commented Nov 29, 2016

Just tried the master branch code, the bug still seems to exist. Ok that might explain why it seems to happen randomly. It's when mouse_abs_pos is equal to slider_usable_pos_min. That then becomes zero divided by zero, when slider_usable_sz is also zero.

imgui/imgui.cpp

Line 6519 in ca9a918

float clicked_t = ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f);

@ocornut
Copy link
Owner

ocornut commented Nov 29, 2016

Neither mouse_abs_pos or slider_usable_pos_min or the values deriving from them (such as clicked_t) are used as denominator in a division.

slider_usable_sz being zero however is a problem.
I think I understand your problem.
You may have set the style value of style.GrabMinSize to a rather large value, or at least larger than your style.WindowMinSize and you are getting into a situation with a very small window where (slider_sz < style.GrabMinSize) which indeed would lead to a division per zero.

Could you share your style information and what your windows look like?

ocornut added a commit that referenced this issue Nov 29, 2016
…ng bigger than slider width can lead to a division by zero (#919)
@skl131313
Copy link
Author

Sorry my confusion was thinking that division by zero caused a NaN to occur, but division by zero just causes the value to become infinite, which clamping solves for that issue. The Problem occurs with a NaN which happens with a division of zero by zero (0.0f / 0,0f).

I am using all default values from the example, so GrabMinSize is the default.

slider_usable_sz is zero because only a lower limit is defined for the slider. Which is style.GrabMinSize. There is no upper limit for the slider grabber size, other than the size of the entire slider. This is why it becomes zero, because there is only 1 valid value, it takes up the entire slider.

bug

@ocornut
Copy link
Owner

ocornut commented Nov 29, 2016

Ah that makes sense, thanks. It looks like it solved itself (and some other edges cases) with the previous few commits.

Now although slider_usable_sz will still be zero (that is correct) we will always set clicked_t to == 0.0 as per the commit pushed an hour ago. So the slider grab will light up but moving will always write the initial value.

Looks like this is a solved case? Sorry it took that long!

@skl131313
Copy link
Author

Yah it's fixed now, it's no problem as long as it gets fixed eventually. Thanks for taking the time to fix it.

@erwincoumans
Copy link
Contributor

erwincoumans commented Jan 31, 2021

I just ran into this issue, while moving the slider (mouse down) the value becomes 0, while min=2 and max=2.

                    int test=2;
                    if(ImGui::SliderInt("Test",&test,2,2,0,ImGuiSliderFlags_ClampOnInput))
                    {
                        std::cout << std::to_string(test) <<std::endl;
                    }

Clicking on the slider makes the value 0, while the lower and upper is 2.

The code responsible happens here:

//clicked_t = 0
//v_min = 2
//v_max = 2
//v_new  = 0...

if (set_new_value)
        {
            TYPE v_new = ScaleValueFromRatioT<TYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);

and then

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)
        return (TYPE)0.0f;

Can't we clamp the v_new to be in range v_min, v_max there, or return v_min or v_max, so the values stays in range while dragging?

if (v_min == v_max)
        return (TYPE)v_min;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants