Sol on Immediate Mode GUIs (IMGUI)

05 - Scrollbar

Source code for this chapter

A scrollbar is one of those widgets which require a bit more state data to function, in order to show the currently scrolled state. We'll go through the scrollbar function (slider, here) in three steps, like we did with the button.

// Simple scroll bar IMGUI widget
int slider(int id, int x, int y, int max, int &value)
{
  // Calculate mouse cursor's relative y offset
  int ypos = ((256 - 16) * value) / max;

  // Check for hotness
  if (regionhit(x+8, y+8, 16, 255))
  {
    uistate.hotitem = id;
    if (uistate.activeitem == 0 && uistate.mousedown)
      uistate.activeitem = id;
  }

Note that like before, the widget is rather simplified. It's always 256 pixels tall to begin with, and the 'thumb' of the slider is not proportional to the scrollable information, as in Windows 3.0.

First we calculate the mouse's relative Y offset to the widget. This is actually only needed if the value of the widget changes.

The 'hotness' check is exactly the same as with the button, except that the 'live' area of the slider is a bit smaller than the widget itself is.

// Render the scrollbar
drawrect(x, y, 32, 256+16, 0x777777);

if (uistate.activeitem == id || uistate.hotitem == id)
{
  drawrect(x+8, y+8 + ypos, 16, 16, 0xffffff);
}
else
{
  drawrect(x+8, y+8 + ypos, 16, 16, 0xaaaaaa);
}

The rendering of the simple slider is, as can be expected, rather simple. The 'thumb' changes color if the slider is active or hot.

// Update widget value
  if (uistate.activeitem == id)
  {
    int mousepos = uistate.mousey - (y + 8);
    if (mousepos < 0) mousepos = 0;
    if (mousepos > 255) mousepos = 255;
    int v = (mousepos * max) / 255;
    if (v != value)
    {
      value = v;
      return 1;
    }
  }
  
  return 0;
}

The slider doesn't care if the cursor stays on top of the widget when it moves, and keeps changing the value until the mouse button is released. If the value changes, the change is reported to the caller; otherwise, we're returning zero.

The value is scaled from the widget size to the maximum value given as a parameter.

To test this function out, the render function gets a bunch of new lines (before the call to imgui_finish()):

int slidervalue = bgcolor & 0xff;
if (slider(GEN_ID, 500, 40, 255, slidervalue))
{
  bgcolor = (bgcolor & 0xffff00) | slidervalue;
}

slidervalue = ((bgcolor >> 10) & 0x3f);
if (slider(GEN_ID, 550, 40, 63, slidervalue))
{
  bgcolor = (bgcolor & 0xff00ff) | (slidervalue << 10);
}

slidervalue = ((bgcolor >> 20) & 0xf);
if (slider(GEN_ID, 600, 40, 15, slidervalue))
{
  bgcolor = (bgcolor & 0x00ffff) | (slidervalue << 20);
}

The above code lets you change the b, g, and r values of the background color. The shifting trickery is added to show that you can have different ranges of values as well.

Next we'll look into the keyboard issue that we've been avoiding so far.

Next: 06 - Keyboard

Any comments etc. can be emailed to me.