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

High resolution dragging mode for float sliders? #180

Open
unpacklo opened this issue Apr 1, 2015 · 36 comments
Open

High resolution dragging mode for float sliders? #180

unpacklo opened this issue Apr 1, 2015 · 36 comments

Comments

@unpacklo
Copy link

unpacklo commented Apr 1, 2015

I was wondering if imgui already supports some method of high resolution dragging on sliders?

An issue I encounter frequently is having a slider which might have a large range and the default dragging increments are very high (or alternatively, the window is sized so that the slider is quite small so the dragging precision drops dramatically). Most of the time this is OK, but sometimes I want to move at much smaller increments and the sliding mechanism is much more natural than having to type in values directly.

One such thing I've seen somewhere (don't remember where) is allowing the user to hold a modifier key (such as control or alt) while dragging which enables the high resolution dragging mode and the slider then starts to move at a smaller increment.

I think this would be a really useful feature if imgui doesn't already have it! Let me know what you think.

-Dale Kim

@ocornut
Copy link
Owner

ocornut commented Apr 1, 2015

Yes, I am very unhappy with the current sliders so they will be replaced!
Basically we need to rework the slider to not use absolute positioning but a system of relative increment (which will then allow speed scaling via modifiers). It will also allow them to fit in much tighter space, the slider can be removed all together and just be the size of a button displaying the value.
Other ideas include using a rotating system like AntTweakBar did. This is why I started adding dragging primitives but I didn't get around to rewrite either widgets instead of sliders yet.
Btw slider won't go away they still have use, but they shouldn't be the most common widget.

@ocornut
Copy link
Owner

ocornut commented Apr 2, 2015

OK I'm working on this now.
I also made it that when you CTRL+Click on it changes into a text input box.

The tricky part is defining the API entry point(s) for potentially desired options without cluttering:

  • Specify step size.
  • Specify fast and slow steps.
  • How does step size relate to mouse movement? Do we have a separate global setting that define what's a step in mouse coordinate?
  • Optional +/- buttons (are they actually useful ?)
  • Optional min/max
  • Handle logarithmic edit curves

I'm not sure yet how to handle those possibility. Obviously a function with 8 parameters is probably not the right way to go.

@ocornut
Copy link
Owner

ocornut commented Apr 2, 2015

Also what would be a good name for this widget. DragFloat() ?
Maybe min/max can come via an different name:

DragFloat() vs DragFloatRange() ?

@unpacklo
Copy link
Author

unpacklo commented Apr 2, 2015

Is it necessary to specify the fast step? My thinking on this was that it works just like the current sliders. You would then only need to specify a slow step. It also seems like we could make this optional as well and default to some fraction of the fast/normal step, but I feel like this could fail at some number ranges (I'm not familiar with how you're computing the final slider values).

I think +/- buttons wouldn't be necessary. Maybe it makes it more obvious that you can move at some specific step, but seems like the finer resolution dragging slider would cover the same cases.

As for naming, well, that's the hardest of them all! DragFloat() doesn't seem too bad too me. Are you thinking of replacing SliderFloat() outright or have these be two separate widgets living side-by-side?

@ocornut
Copy link
Owner

ocornut commented Apr 2, 2015

My idea for steps is that the default, maybe -1.0f would automatically be like *100 and *0.01 when modifiers are held. So it's ok to have them if they are final parameters I suppose. Or fast could be the inverse the slow. But yes I agree they not be so necessary by default. Especially with CTRL+Click always available.

Won't replace the slider no, but will launch a giant lobbying/marketing campaign to advise people to use the new widget.

@ocornut
Copy link
Owner

ocornut commented Apr 3, 2015

The slow/fast factors could also be part of the imgui state, so by default they don't show in the simple API (and you can always have a helper to push/pop them for you).

@ocornut
Copy link
Owner

ocornut commented Apr 3, 2015

Proposal

bool     DragFloat(const char* label, float* v, float v_step = 1.0f, float v_min = -FLT_MAX, float v_max = FLT_MAX, const char* display = "%.3f");
bool     DragInt(const char* label, int* v, int v_step = 1, int v_min = INT_MIN, int v_max = INT_MAX, const char* display = "%.0f");

With global state to adjust slow/fast step ratios.
Note that I think I'll be renaming 'display_format' parameter to 'display' to emphasis the fact that you can include prefix/suffix there.

DragFloat("", &f, 0, 1.0f, 10000.0f, "%.3f coins")

@unpacklo
Copy link
Author

unpacklo commented Apr 3, 2015

I was actually going to suggest exactly this as a way to reduce the number of parameters. As long as the default step sizes are intuitive, I definitely think this is the way to go.

On Apr 3, 2015, at 3:19 AM, omar notifications@github.com wrote:

The slow/fast factors could also be part of the imgui state, so by default they don't show in the simple API (and you can always have a helper to push/pop them for you).


Reply to this email directly or view it on GitHub.

@ocornut
Copy link
Owner

ocornut commented Apr 3, 2015

I currently have two variants of each (uncommited)

bool DragFloat(const char* label, float* v, float v_step = 1.0f, float v_min = -FLT_MAX, float v_max = FLT_MAX, const char* display_format = "%.3f");
bool DragFloat(const char* label, float* v, float v_step, const char* display_format);

May not be very useful but this is easily specify the display format without the min/max.

@heroboy
Copy link
Contributor

heroboy commented Apr 3, 2015

I suggest you can look at the Unity's FloatField

The mouse can drag the lable of the input field to change the float value. I think this is very easy to use.

@ocornut
Copy link
Owner

ocornut commented Apr 3, 2015

Yes, I suppose that's very similar.

The difference are:

  • in DragFloat() the label is optional (you can use "##something" for no visible label)
  • because of that the dragging can't happen when clicking on the label, it happens clicking on the value
  • so ctrl+clicking to switch to text input

@ocornut
Copy link
Owner

ocornut commented Apr 3, 2015

Committed a first version that you can try.
Not totally happy with it yet and will likely change the behavior some more.

// Widgets: Drags (tip: ctrl+click on a drag box to input text)
bool DragFloat(const char* label, float* v, float v_step = 1.0f, float v_min = -FLT_MAX, float v_max = FLT_MAX, const char* display_format = "%.3f");
bool DragFloat(const char* label, float* v, float v_step, const char* display_format);
bool DragInt(const char* label, int* v, int v_step = 1, int v_min = -0x7fffffff-1, int v_max = 0x7fffffff, const char* display_format = "%.0f");
bool DragInt(const char* label, int* v, int v_step, const char* display_format = "%.0f");
  • The step slow/fast ratio are not exposed yet. I used SHIFT for fast (like Unity) and ALT for slow.
  • I made the ColorEdit widget use them by default. Slow stepping doesn't work because the integer rounding. It needs to be handled differently.
  • No handling of logarithmic curve yet.

Let me know how that works.

ocornut added a commit that referenced this issue Apr 3, 2015
ocornut added a commit that referenced this issue Apr 3, 2015
@ocornut
Copy link
Owner

ocornut commented Apr 3, 2015

(
Side topic:
I'm experimenting with generalizing frame coloring when hovering any widget or when active, the same way DragFloat() does.
It works but however raise a few problems:

  • making the state so visible puts a little more burden to the programmer - in situation when one programatically manipulate the focus it can be distracted to see flickering colors.
  • the colors are bad
    So I may keep it as in until the interface visual are redesigned.

)

Also need to spend some time redesigning ShowTestWindow before there's too many things in there. I don't want to remove anything (in fact we should add more examples) but the presentation may need to change.

@unpacklo
Copy link
Author

unpacklo commented Apr 3, 2015

I just tried them out and it's a decent first version. It did take me a second to realize that only horizontal mouse movement affected it. Would probably help to have a unique graphic for this widget to make it easily identifiable that it's a DragFloat.

I also found myself wanting to see the widget as a normal slider if the DragFloat was bounded so I can have some context as to what the extremes are and where I am in relation to them. It might just be because I'm so used to working with the sliders. We use imgui right now to handle live editing of some game data, and in theory, a lot of our float values can be "unbounded". However, for all practical purposes, they fall within a reasonable range so they work OK with sliders.

The case that would be solved better with these DragFloats are those where the range is bounded only on one side. We do have quite a few of these (like specifying time durations) and we've had to force them into the sliders and place arbitrary limits on either the min or the max and just size them accordingly to the most common ranges.

@ocornut
Copy link
Owner

ocornut commented Apr 3, 2015

Very good points. I can see a case for drawing the visual marker, but also use range as reference while being able to get out of the range if you need. May have to redesign and break the current DragFloat() interface.

I'm starting to understand why you suggested they could replace sliders altogether.

@unpacklo
Copy link
Author

unpacklo commented Apr 3, 2015

Ah, yes, sorry I wasn't more clear!

The way I originally envisioned it was that the current sliders would just be modified to be able to step at a much smaller increment when you hit another key while fiddling with the slider. Nevertheless, we would still find the DragFloat or something like it very useful for the case of bounding on only one side of the number line.

It's actually kind of a pain right now when we implement our data editing gui and have a float to expose. Usually there's a clear bound on min or max, but not always both, so we need to spend some time fiddling around to see what a good range is and hope that we set the range well enough for the tuning work. We're not always right, so sometimes we get requests to resize the range.

Something that might be worth looking into is looking at #76 and see if maybe we can kill a few birds with one mega stone? Might be too much in one widget... but customizable ranges + a high resolution mode would solve a few issues we're seeing!

@heroboy
Copy link
Contributor

heroboy commented Apr 7, 2015

After tried,I feel the "step/pixel" movement speed is too hard to set value accurately.Maybe add a speed parameter?
And I think the min max parameters are not necessary, because sometimes I want clamp and sometimes I want wrap(e.g. for angle).

@ocornut
Copy link
Owner

ocornut commented Apr 12, 2015

OK it looks like I may need to rewrite that (and rewrite Slider as well) to latch the initial value on press and go relative from there when clicking on the little box, including speed scale and non-linear curve shenanigans. From there we can use the bounds as visual reference but allow the user to get past them, it's a matter of figuring out the right API after the feature is coded in.

ocornut added a commit that referenced this issue Apr 12, 2015
@ocornut
Copy link
Owner

ocornut commented Apr 12, 2015

@heroboy have you tried holding ALT to slow down the speed ?

ocornut added a commit that referenced this issue Apr 12, 2015
@ocornut
Copy link
Owner

ocornut commented Apr 12, 2015

Fixed commit below, didn't commit the right hunks (my github ui acts weird?)
I also renamed v_step to v_speed, which is a more accurate name.

@ocornut
Copy link
Owner

ocornut commented Apr 12, 2015

Unsure how to visualize the current value of a drag box similarly to a slider, while uniquely identifying them.

It got me thinking. I was wondering if slider could just be changed to function like DragFloat(), that is, clicking is never setting an absolute value.

Pros: is that slider/drag just become the same thing, and we can have API variants of options to : have no bounds, have bounds but allow to go past them, etc.

Cons: can't set an absolute value in one click, drag is generally slower (even if it's more flexible and precise). Need to decide on a default speed for sliders (e.g. 1 pixel is 1/200 of the input range).

@ocornut
Copy link
Owner

ocornut commented Apr 12, 2015

I made DragFloat() support power curves while applying relative changes and working on both sides of zero. Perhaps someone who is more competent at maths or floating-point issues can review this and tell me if it's total rubbish or if there are edge cases to be wary about:

float v_cur = g.DragCurrentValue;
float delta = (mouse_drag_delta.x - g.DragLastMouseDelta.x) * speed;
if (fabsf(power - 1.0f) > 0.001f)
{
    // Logarithmic curve on both side of 0.0
    float v0_abs = v_cur >= 0.0f ? v_cur : -v_cur;
    float v0_sign = v_cur >= 0.0f ? 1.0f : -1.0f;
    float v1 = powf(v0_abs, 1.0f / power) + (delta * v0_sign);
    float v1_abs = v1 >= 0.0f ? v1 : -v1;
    float v1_sign = v1 >= 0.0f ? 1.0f : -1.0f;          // Crossed sign line
    v_cur = powf(v1_abs, power) * v0_sign * v1_sign;    // Reapply sign
}
else
{
    v_cur += delta;
}

@heroboy
Copy link
Contributor

heroboy commented Apr 13, 2015

I tried use ALT to slow down, but it is not what I want. It just decrease the change amount. To set a value,fox example 1.00 (not 0.99,not 1.01), I must move mouse very carefully.

@heroboy
Copy link
Contributor

heroboy commented Apr 13, 2015

I have use a horizontal slider on IOS. It use cursor y position to determine the speed. When the cursor move away the slider in y axis, you need move more distance to change the value. It's very interesting. You may reference this one to improve the float slider?

@extrawurst
Copy link
Contributor

To set a value,fox example 1.00 (not 0.99,not 1.01), I must move mouse very carefully.

@heroboy To set a specific value you simply type it in.

I like the DragFloat widget as it is, especially now that you can specify the speed.

@heroboy
Copy link
Contributor

heroboy commented Apr 13, 2015

@extrawurst I want set value to 1.00,2.00,3.00,.... sequentially. I think what I want is snap

@extrawurst
Copy link
Contributor

@heroboy sounds like you want is DragInt...

@ocornut
Copy link
Owner

ocornut commented Apr 13, 2015

Or you can use a format of %.0f to snap float to integer values (whiles using actual floats)
But I agree the iOS behavior is interesting. Will think about it.

@unpacklo
Copy link
Author

iOS behavior could be nice, I'd have to try it with mouse + keyboard to know for sure. Even on iOS, I don't find the dragging resolution being tied to vertical distance from the dragging element to be that great (but better than nothing). Being locked to the horizontal axis and having no regard for the vertical component is useful in dragging; most of the time I kind of throw my mouse over to get to values quickly and having the resolution constantly change on me seems like it would be annoying.

@extrawurst
Copy link
Contributor

One thing I would like to see in this new widget is: The support that unity brings for similar dragSliders to wrap the mouse pos around to enable infinite dragging, this is really usefull!
"wrapping" as in "leaving the window on the left warps the cursor to the right of the window"

@ocornut
Copy link
Owner

ocornut commented Apr 20, 2015

Btw I have released 1.38 as is. Established that the missing desired features (e.g. bounds for clamp different from bounds for display) won't break the current API. They may have to be a different API.

@unpacklo
Copy link
Author

We just bumped up to 1.38 today in our game, and though we aren't using the drag floats yet, things are looking good! Will try to find some places to use these and let you know of anything we find as a result...

@videovse
Copy link

Hello!
Is it possible to disable in project (for some reasons) this feature : CTRL+click slider for text input?

@ocornut
Copy link
Owner

ocornut commented Jul 13, 2017

@CaptNemo999

Is it possible to disable in project (for some reasons) this feature : CTRL+click slider for text input?

No it isn't at the moment. Curious as to why you would need to disable it?

@videovse
Copy link

videovse commented Jul 13, 2017

Ok, don't worry. Thank you for your answer.
I use float slider as time slider line in video player (as you can see in QuickTime player for example). It's not what one expected from video player - to show text input if user accidentally click it with CTRL.
By the way - excellent work, thank you!

@ocornut
Copy link
Owner

ocornut commented Jul 13, 2017 via email

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

5 participants