Please help me with a gui slider (closed)

Hello all,

I have made a slider that works really smoothly.
It sits in a slider track gui box that is set to stretch to allow for window resizing. Both slider and track are children of a root gui box, that is also set to stretch. Sliding is confined to the x-axis and all pivots are set to west.
There is still a small problem: I’d like the dragging to stop when the mouse leaves the slider or maybe a slightly larger area around it – as if it was released.
But the parenting leads to problems with the coordinates, especially when the window is stretched and so the mouse keeps dragging when it is no longer over the slider.

I have tried for some time now to solve this, searched the forum, looked at several examples and extensions.
So far, my calculations are not quite working. Could someone please give me a hint to get my maths right?

I think it’s hard to say what goes wrong if you don’t share any code to review (or possibly a small project)

1 Like

Hi @Mathias_Westerdahl,

thank you.
there is nothing really going wrong, it is just that I cannot get the relationship between action.x, action.y/action.screen_x, action.screen_y and the slider’s position right to be able to detect the mouse leaving the slider area and set dragging to false.
I have an appointment now, when I am back, I’ll make a small sample project for posting.

Brigitte

Good evening, @Mathias_Westerdahl,

I have extracted my slider code from my project and prepared a small demo.
slidertest.zip (3.1 KB)

If someone could have a look, this would be super. I really just need a little hint how to make slider and mouse stay together so I can do the rest of the calculations myself.

Brigitte

If you set the adjust mode of a gui node to stretch, the visible size will adjust to the window, but its coordinates will still be the same. So the coordinates of the rightmost side will still be the width of the slidetrack (so 960), and not the size of the window. Use that one instead of window_width (which you don’t need to track at all here).
Also, if you stretch the slidertrack, you should stretch the slider too. The current mismatch of the nodes makes it also look wrong if you decrease the width of the window.
So:

  • Set the Adjust Mode of “slider” to Stretch instead of Fit.
  • Instead of
    limit_right = window_width - slider_size.x
    use
    limit_right = gui.get_size(gui.get_node("slidertrack")).x - slider_size.x

(By the way, if you ever actually need the width of the window, you can just use
local width, height = window.get_size()
instead, no need for that callback here.)

1 Like

Hi there @Halfstar,

Thank you for taking a look at my demo! You are right, I don’t need the window listener and that the slider should stretch as well.
Sadly, when I use
limit_right = gui.get_size(gui.get_node("slidertrack")).x - slider_size.x,
and then increase the width of the window, the slider does not slide to the end but stops at 760 px. I have to use my old line limit_right = window_width - slider_size.x to continue the drag until the end.
In both cases, the mouse also drags when it is not over the slider, the cheeky thing.
I also noticed just now that the right limit does not work once the window is resized vertically, too.
Oh, those vexed coordinates! Will do some calculations today.

Cheers

Brigitte

Isn’t that how a slider should work? The slider button is 200px long, and the left edge will stop at 760px, so that the right edge will hit the end at 960px. That’s how I’d expect a slider to work. Isn’t that why you put the -slider_size.x in there?

Hi again @Halfstar,

what I would like to achieve is a slider that reacts to window resizing and slides all the way to the end of the window. So when the window is eg. 1400 px wide, the slider should stop at 1400 minus its own width (since the pivot is west). And I would like the mouse only to drag when it is in the slider’s box.

Cheers

Brigitte

UPDATE:
have now managed to stop the mouse from dragging when it is below/above the slider’s box.

		if dragging then
			-- do not drag when mouse is below or above the slider's box
			if action.screen_y <= (window_height / 2) + (slider_size.y / 2) and
			action.screen_y >= (window_height / 2) - (slider_size.y / 2) then
				if #actions_array > 1 then
					previous_move = actions_array[#actions_array - 1]
					current_move = actions_array[#actions_array]
					moved_distance = current_move - previous_move
				end
				slider_pos.x = slider_pos.x + moved_distance
				boundary_check()
				gui.set_position(slider, vmath.vector3(slider_pos.x, 0, 0))
			end
		end

Hi once more,
this is more complex than I thought it would be, once more, I’ve been fiddling with the code all day long.
I don’t not want to steal too much time and effort from you folks, so I will put this thread on hold now and will revive it once I found a solution myself.

Cheers and a good evening to all of you

Brigitte

Hello, I am back with a shiny new slider demo project. It no longer uses gui.pick_node because this leads to slightly jerky movement.
A root box houses a slider, an imagebox with 6 images, a footer with a button. This slider moves smoothly and drags the imagebox along.

Initial setup:

Root node, slider, imagebox and footer are set to stretch. The images and the button must retain their aspect ratio, so they are set to fit.
This leads to two problems I just cannot manage to solve myself, so I need to ask for help:

When the window is wider, the imagebox moves too fast and its speed needs adjusting. I am unable to find the value needed to achieve this.

When the window is taller, the footer is very far below the images and the button is too small:

Is there a way to solve these isssues without having to write a custom scaling module?

Here is the demo:
SlidertestSmooth.zip (3.7 KB)

So, if any of you have a bit of time, could you please have a glance at my code?

Thanks a lot in advance

Brigitte

Right, I think I found a solution for the problem with the taller window:
I have added a window callback that sets the stretched boxes to fit when the aspect ratio gets smaller and stretches them when the aspect ratio gets larger.
Edited demo-file:
SlidertestSmoothNew.zip (3.9 KB)
Seems to work:

This leaves me with the problem of adjusting the speed of the imagebox when the aspect ratio gets larger. And with this one, I am sure, I need your help. I have tried and tried and tried and would be very grateful for a hint.

Brigitte

How are you moving the items now?

Is it not enough to calculate a value between 0.0 and 1.0 based on where the scrollbar is currently located, and use this value to position the items (or probably a parent node) so that when the value is 0.0 you start from the first item and when the value is 1.0 you end with the last value.

1 Like

Hello @britzl,

aha, I took a different approach, so maybe therein lies the problem.
first, I filled an array of action.x values: table.insert(actions_array, action.x).
then, I used this array to calculate the distance moved when dragging is true:

			if #actions_array > 1 then
				previous_move = actions_array[#actions_array - 1]
				current_move = actions_array[#actions_array]
				moved_distance = current_move - previous_move
			end

and moved the slider this distance:
slider_pos.x = slider_pos.x + moved_distance
gui.set_position(slider, vmath.vector3(slider_pos.x, slider_pos.y, 0))
to move the imagebox (the parent of the images), I introduced a speedfactor, that establishes a relationship between the slider’s size and the size of the imagebox (when the slider moves, the imagebox moves proportionally):
speedfactor_images = ((imagebox_size.x - project_width)/(project_width - slider_size.x))
and moved the imagebox:
gui.set_position(imagebox, vmath.vector3(-slider_pos.x * speedfactor_images, imagebox_pos.y, 0)).
And this speedfactor is needs adjusting once the aspect ratio is larger than the initial one. Since the imagebox is set to stretch, but the images are set to fit, both are out of sync when the aspect ratio gets larger: initially, the end of the last image is the end of the imagebox as well. With a wide window, the imagebox gets stretched more and its end is moved away from the end of the last image.
Will immediately try out your way of moving the items.
Many thanks for this hint!

Cheers

Brigitte

I’d simplify this:

  1. Set a flag when action.pressed is true on your slider
  2. Get the current mouse/finger position on each on_input until action.released
  3. Use the horizontal (x) component of the position to position the slider on the screen
  4. Use the horizontal (x) component of the position to calculate a value between 0.0 (left edge of screen) and 1.0 (right edge of screen)
  5. Use this normalized value to decide how to position the items
2 Likes

Hi again @britzl,
this really is much simpler than my code, sounds good - thank you!

This flag is already in place, so I’ll work through steps 2 - 5 now. I need to be off in a short while and will report back later.

Brigitte

Hello again @britzl,

These are the results of me thinking about your suggestion:

Step 1:

“on your slider” means using gui.pick_node, am I right?
If so, I’d rather avoid it, because the slider jumps to the mouse position when the dragging starts and the movement of the slider isn’t as smooth as I would like it to be. Right now, I just track the mouse movement irrespective if the mouse is on the slider or not and move slider and imagebox. This has the nice side-effect that I can drag the images directly and so imitate kind of a swipe.

Step 2 and 3: understood

Step 4:

I suppose this is not a static value and that you mean this: divide 1.0 by the actual window widht to get this value.

Step 5:

I think I shall use action.x and the value above and use both to get a position for the indiviual images. But how do these two values go together? Cluelessness attack, sorry!

Brigitte

The action.x and action.y value you get from on_input() should still be within the original coordinate space as defined in by display width and height in game.project.

Here’s a sample project with my own implementation of a slider with a similar layout as in your screenshot:

slider-example.zip (4.1 KB)

Original aspect ratio. Slider handle (grey box) at the top to the far right (red box with white box inside is the last item):

Narrow screen:

Wide screen:

2 Likes

Good morning @britzl,

this is a cool slider, thank you so much for preparing it for me.
It is the translating bit that got me, I will study your code closely and get my head around this. Also, I will need to think about the selfs you used instead of local vars for the slider. Will get there.
One last tiny question, then I leave you in peace:
When using gui.pick_node on a node, the node jumps to the position of the click, which looks a bit jerky. Is there a way to avoid this?

Thanks again for helping me along!

Brigitte

Since it’s a gui script it is unlikely to have multiple instances running at the same time, so using local functions would work equally well.

Yes, if you calculate the offset/difference between the click position and slider position you can then apply this offset when you set the position of the slider.

1 Like

That’s it , why didn’t I think of this myself?
Thank you very, very much for solving my slider/image drag problem. I’ve learned a lot from you.
I can close the thread now and proceed with my project.

Cheers

Brigitte

1 Like