The last control that this tutorial will cover is a scroll bar, which ImGui calls "sliders". Unlike all the other widgets that I have shown you, the slider is fairly unique in how it is implemented, and it isn't immediately obvious as to how it works. I'll do my best to explain it, but be prepared to sit down and get your hands dirty with experimenting.
First, we need to create something for the Slider to actually scroll. Perhaps the simplest thing to use for this is a TextFrame, so lets go ahead and use one of those:
cImGuiTextFrameData textFrameData;
textFrameData.mFont.mvSize = cVector2f(35, 35);
textFrameData.mColorBase = cColor(0, 0, 0, 0);
ImGui_DoTextFrameExt(
"This is paragraph 1.\nThis is paragraph 2.\nThis is paragraph 3.\nThis is paragraph 4.\nThis is paragraph 5.\nThis is paragraph 6.\nThis is paragraph 7.\nThis is paragraph 8.\nThis is paragraph 9.\nThis is paragraph 10.\nThis is paragraph 11.\nThis is paragraph 12.\nThis is paragraph 13.\nThis is paragraph 14.\nThis is paragraph 15.\nThis is paragraph 16.\nThis is paragraph 17.\nThis is paragraph 18.\nThis is paragraph 19.\nThis is paragraph 20.",
0,
10,
0,
textFrameData,
cVector3f(600, 95, 0),
cVector2f(300, 550));
This shouldn't be anything new. The text that I put in the TextFrame is just the same text repeated 20 times, other than a number to identify the lines of text from each other.
(If you are wondering, the text "\n" is called an escape character. This particular escape character tells the text that anywhere there is a "\n" in the text, that means it should perform the equivalent of hitting the enter key and start a new paragraph.)
If we were to run our code now, we would see this:
As you can see, the text is too long to properly contain within the TextFrame's size limits. In order to display it properly, we need to add a Slider. In order to do this, we are going to have to get a bit technical.
the first thing we are going to need to do is create another state variable. This is because the Slider uses a value that determines its slide position. Like the CheckBox and the ToggleButton, this value needs to be saved outside of the function so it doesn't get erased after the OnGui run is complete. Add this line to the ImGui_IsFirstRun code block:
ImGui_SetStateFloat("Slider_OffsetValue", 0.0f);
We haven't bothered with it up to this point, but the function
ImGui_DoTextFrameExt actually returns a float value. This value represents the number of lines of text that doesn't fit in the TextFrame's view. We are going to need that value, so let's store it.
Next, we will do a quick check to see if a Slider is even necessary. All we need to do is to check the value that we got from the ImGui_DoTextFrameExt function and see if it is greater than 0. If not, then all the text within that frame is visible and we don't need to bother with a Slider.
Now we get to the meat of this thing - the Slider code. First, let's take a look at the function signature for the function that creates a Slider:
float ImGui_DoSliderVerticalExt(
const tString &in asName,
float afDefaultValue,
float afMin,
float afMax,
float afStepSize,
const cImGuiSliderData &in aData,
const cVector3f &in avPos=cVector3f_Zero,
const cVector2f &in avSize=cVector2f_MinusOne)
So first off, we have the name of the Slider widget. This is fairly self-explanatory, so we won't bother with it.
Second is afDefaultValue. This is the value that says what the current position for the Slider is (in terms of lines of text).
Third is afMin. This value sets the minimum scroll position of the Slider. This should be 0 to let the Slider be able to scroll to the top of the TextFrame, unless you are doing something specific with your GUI implementation.
Fourth is afMax. This value sets the maximum scroll position of the Slider. This should be set to the value that we got from ImGui_DoTextFrameExt, as that will let it scroll to the bottom of the TextFrame, unless you don't want it to be able to for some reason.
Fifth is afStepSize. This means how far that each scroll of the Slider will advance when it moves. Typically, if you want the Slider to scroll smoothly, set it to a small value like 0.01 . If you want the Slider to snap to each line of text, then use 1. Or you can set it to something else entirely, if you want a particular look and feel to your GUI.
The rest of the parameters are familiar - the
cImGuiSliderData that provides the visual ImGui data to the Slider, and the position and size of the Slider.
The
ImGui_DoSliderVerticalExt returns a value as well. In this case, it returns its current scroll position. This value is necessary to store as well, as we will need to use it to offset the TextFrame by the appropriate amount.
Now that that is out of the way, let's show what the complete code for the TextFrame-Slider combo looks like:
cImGuiTextFrameData textFrameData;
textFrameData.mFont.mvSize = cVector2f(35, 35);
textFrameData.mColorBase = cColor(0, 0, 0, 0);
float offsetValue = ImGui_GetStateFloat("Slider_OffsetValue");
float overlapLineCount = ImGui_DoTextFrameExt(
"This is paragraph 1.\nThis is paragraph 2.\nThis is paragraph 3.\nThis is paragraph 4.\nThis is paragraph 5.\nThis is paragraph 6.\nThis is paragraph 7.\nThis is paragraph 8.\nThis is paragraph 9.\nThis is paragraph 10.\nThis is paragraph 11.\nThis is paragraph 12.\nThis is paragraph 13.\nThis is paragraph 14.\nThis is paragraph 15.\nThis is paragraph 16.\nThis is paragraph 17.\nThis is paragraph 18.\nThis is paragraph 19.\nThis is paragraph 20.",
0,
10,
offsetValue,
textFrameData,
cVector3f(600, 95, 0),
cVector2f(300, 550));
if (overlapLineCount > 0)
{
cImGuiSliderData sliderData = ImGui_GetDefaultSliderVertical();
offsetValue = overlapLineCount - ImGui_DoSliderVerticalExt(
"slider",
overlapLineCount - offsetValue,
0,
overlapLineCount,
0.01,
sliderData,
cVector3f(900, 95, 0),
cVector2f(75, 550));
ImGui_SetStateFloat("Slider_OffsetValue", offsetValue);
}
That's quite a mouthful, so let's go through it in chunks.
First is the creation of the
cImGuiTextFrameData. This hasn't changed from before, so let's skip it.
Next we retrieve the value from the state variable "Slider_OffsetValue". We need to do this because both the TextFrame and the Slider will need access to this value, so it's better to retrieve it and store it in a temporary variable to avoid having to retrieve it multiple times. (This increases the efficiency of the code as well as making it more readable.)
Next we do our ImGui_DoTextFrameExt. It's mostly the same, but there is one key difference: the use of our offsetValue in the fourth parameter. This parameter is responsible for telling the TextFrame what the text offset of the frame is, which correlates to the position of the Slider. Basically, what this means is if the offsetValue says that the TextFrame should be scrolled down by two lines, then the TextFrame will do so. We also store the return value of the function in another temporary variable called "overlapLineCount", which tells us how many lines are cut off of the top or bottom of the frame.
After our check to make sure a Slider is necessary, we create our Slider data. Unlike what I did with earlier widgets, I am merely resorting to using SOMA's default Slider data rather than create my own. The reason for this is because the cImGuiSliderData contains a fair amount of fields that need to be set, but there is rarely a case in which we would need them to be different than the default data anyway.
Then we have the ImGui_GetDefaultSliderVertical function. As the name suggests, this function creates a vertical Slider widget. We've already covered what the different parameters do, so instead I will just explain the craziness that I am doing with the return value. The offsetValue stores how many lines the TextFrame should be offset by, but the function returns its current position. For whatever reason, the position value is based on the bottom of the Slider being 0, which is inverted from what the TextFrame needs (bottom of the Slider being max offset). So in order to get the value we need, we have to subtract this value from our maximum offset, which happens to be the overlapLineCount that we have stored.
Finally, we store the resulting value into our state variable.
(As you might suspect from the name of the Slider function, there is also a corresponding
horizontal Slider widget as well. It acts the same as the vertical Slider, so I won't be covering it in detail in this tutorial.)
Now let's see this code in action:
This has been quite a mouthful of a tutorial, but hopefully you now know how to use 4 more widgets for making your terminal GUIs more diverse and interesting. In the next tutorial, we make things a bit more intriguing by covering how you can use terminals to affect other objects on a level.