Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
106 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

  Contents

 Introduction
 GUI Controls
 We'll Need

 Breaking It Down
 Static Controls
 Pushbuttons
 Carets and The
 Textbox Control

 Progress Bars
 Sliders and
 Scrollbars

 Listbox Control
 Conclusion

 Printable version

 


  The Series

 Part I
 Part II
 Part III
 Part IV

 

The Listbox Control

Resign yourself to this now - the listbox control is where you're going to be spending the most time.

Popup : Source Listing 1

The listbox is by far the most complex control you'll make… but that's only because it's the most versatile. A good listbox control, capable of multiple columns, indenting, and multi-selection will prove practically indispensable in your game's GUI. Stop and think for a moment about all the places that listboxes are used in the average game, and you'll quickly see my point.

I tackled my listbox control by splitting it up into two separate controls: a multi-column "report-style" list control, and an icon list control, which creates a view similar to what you'd see when selecting "large icons" in an explorer window.

The icon list control was fairly easy to do. It kept track of a list of static icons (again, code reuse), all the same size. I divided the listbox width by the width of the icons, which gave me the number of columns available. (If it turned out that my listbox was smaller than the largest icon, I assume I have only one column, and let the rendering system take care of clipping the icons so that they don't overrun my client area). Once I had the number of columns, I calculated how many rows I'd need by dividing the total number of icons by the number of columns. This told me how to setup my included scrollbar.

Note that these values will have to be recalculated whenever the control is resized. For this reason, I set up a wm_sizechanged() message that calcall() would call whenever the client area of a window was modified.

The report-style list control was a little more complex. I first created two helper classes, gui_listbox_column and gui_listbox_item, which contained all of the information about a given item and column in the list.

gui_listbox_column is the simpler of the two classes. The main listbox class keeps, as a member variable, a dynamic array of gui_listbox_columns, which represent the columns in the listbox right now. gui_listbox_column contains all of the information needed for a column in our list box, including the name of the column, the alignment of the column, whether it's shown or hidden, its size, etc.

The main listbox class also keeps a dynamic array of gui_listbox_items. The gui_listbox_item class contains everything related to a particular row (or item) in our report-style listbox. By far the most important data member of this class is the array of strings, representing the data for each column. I also decided to let each item store an additional 32-bits of data with it, via the m_itemdata member. This technique is similar to how Windows allows you to store 32-bits of data by calling SetItemData() and GetItemData() for your listbox items. This feature is important because it allows clients of the listbox to store a pointer with each item - usually a pointer to the specific class associated with the item, so that it's readily available later.

As for drawing the columns and items… I decided that I'd like to have absolute control over how each individual item/column in the listbox was drawn. Towards this end, I decided to have the listbox draw its items and columns by repeatedly calling two virtual functions, gui_listbox_item::draw() and gui_listbox_column::draw(). Each function took a rectangle understood to be the location on the screen where the column or item was supposed to be drawn. The default implementations of these draw() functions just spit out the text associated with that particular column and subitem in that rectangle; however, I could now easily derive and override draw() for items or columns that required a unique appearance. This technique has seemed to work for me so far, but I haven't concentrated enough on it to claim that it's the best and right way to do it.

Drawing the items required a little more work than the columns, however. Items had to be drawn with or without a highlight, depending on whether they were selected or not. Not a big deal, but important to remember.

Then there's the issue of scrollbars. My report-view listbox contained two members, m_horzscrollbar and m_vertscrollbar, both GUI scrollbars. Whenever the size of the listbox was changed (wm_sizechanged()), it took a peek at the width and height of the data it had, and either displayed or hid the scrollbars as appropriate.


Next : Conclusion