1
\$\begingroup\$

I'm making a simple UI system for a small game and i'm having some difficulty to implement a Scrollbar.

At the moment i'm having two major problems that i need some help to solve:

. Calculating the "Value" property of the Scrollbar when the current position of the Thumb on the Track is changed.

. Calculating the "Minimum" and "Maximum" properties to limit the position of the Thumb on the Track.

Below is part of the code that i currently have. Please, look at the commented blocks.

public int Minimum  { get; set; }
public int Maximum  { get; set; }

public int Value    { get; set; }

public void Update()
{
    // Calculate the Scrollbar Thumb height:
    var viewable_ratio = ViewportHeight / ContentHeight;
    var scrollbar_area = ViewportHeight - ( ArrowHeight * 2 );
    
    this.ThumbHeight = scrollbar_area * viewable_ratio;
    
    // Calculate the Scrollbar Thumb step:
    var track_space = ContentHeight  - ViewportHeight;
    var thumb_space = ViewportHeight - ThumbHeight;
    
    this.ThumbStep = track_space / thumb_space;
    
    // TODO: Calculate the "Minimum" and "Maximum" values.
    this.Minimum = ???
    this.Maximum = ???
    
    Point mouse = Input.MousePosition();
    
    if(Thumb.Rectangle.Contains(mouse) && Input.MouseDown(0))
    {
        int x = Thumb.Position.x;
        int y = ( mouse.y - Thumb.Position.y );
        
        Thumb.Position = new Point(x, y);
        
        if(Thumb.Position.y < Minimum) Thumb.Position.y = Minimum;
        if(Thumb.Position.y > Maximum) Thumb.Position.y = Maximum;
        
        // TODO: Set the "Value" property to the correct value when the Thumb is moved.
        this.Value = ???
        this.Content.Position.y = this.Value;
    }
}

The "Value" property is used to scroll the Content and represent his position in the Scrollbar.

The "Minimum" and "Maximum" properties are used to not let the Thumb move outside of the Track.

Could someone please provide a direct answer with the math to calculate the scrollbar Value, Minimum and Maximum properties?

Thanks in advance!

\$\endgroup\$
1
  • \$\begingroup\$ It looks like that comment was meant to be part of your question. If so, please click the "edit" button, not the "add comment" button. \$\endgroup\$ Commented Aug 16, 2021 at 14:27

1 Answer 1

1
\$\begingroup\$

I'm going to give values to Minimum, Maximum and Value from the way you want to use them.

We start with this code, where you use Minimum and Maximum:

if(Thumb.Position.y < Minimum) Thumb.Position.y = Minimum;
if(Thumb.Position.y > Maximum) Thumb.Position.y = Maximum;

It appears that Minimum and Maximum should be actual positions on screen. In that case your Minimum is going to be ArrowHeight, and your Maximum is going to be ViewportHeight - ArrowHeight - this.ThumbHeight.


As per Value, you want to use it like this:

this.Content.Position.y = this.Value;

We need to transform Thumb.Position to a get the value that this.Content.Position.y should have… What do we know?

  • When Thumb.Position.y is Minimum, this.Content.Position.y should be 0.
  • When Thumb.Position.y is Maximum, this.Content.Position.y should be ViewportHeight - ContentHeight a.k.a -track_space.
  • It is a linear transformation. I.e. this.Content.Position.y = Thumb.Position.y * factor + offset.

I'm assuming that the positive y goes downwards, and thus when you scroll down, you need give a negative position to the content so it moves upwards.

Thus, we have two unknowns: factor and offset. And two linear equations:

Minimum * factor + offset = 0

Maximum * factor + offset = -track_space

Solve the system. If my assumptions are wrong, you should still be able to come up with an equation system to solve.

I'm feeling substitution:

Minimum * factor + offset = 0

=>

offset = -Minimum * factor

=>

Maximum * factor + -Minimum * factor = -track_space

=>

factor * (Maximum - Minimum) = -track_space

=>

factor = -track_space / (Maximum - Minimum)

=>

factor = track_space / (Minimum - Maximum)

And thus:

var factor = track_space / (Minimum - Maximum);
var offset = -Minimum * factor;
this.Value = Thumb.Position.y * factor + offset;
this.Content.Position.y = this.Value;

By the way, if I understand correctly, you are checking if the user is clicking on the Thumb:

if(Thumb.Rectangle.Contains(mouse) && Input.MouseDown(0))
{
   ...
}

And moving it:

int x = Thumb.Position.x;
int y = ( mouse.y - Thumb.Position.y );
        
Thumb.Position = new Point(x, y);

Which means that just clicking on the Thumb will make it move.

However, I believe that if the user is just clicking there you should do nothing! Instead you need to handle drag. And change Thumb.Position according to that drag.

\$\endgroup\$
1
  • \$\begingroup\$ Hello, thank you so much for answering my question, it took me a while to understand everything but i think my problem is solved now. Thank you again! \$\endgroup\$ Commented Aug 16, 2021 at 16:21

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.