1. Technology

An SDL GUI for Empire Tutorial Five

Adding a clickable listbox

By

Screenshot of Empire Controls

This is another tutorial about developing the Empire game. If you've found this article first, please see part one. Here's more information about the Empire Game.

In the previous SDL Gui tutorial 4 I added animation to the button.

Latest Code

  • Download Source Code File (Zip).
  • Download binaries (All Exe + SDL dlls + graphic files etc) zipped up. Just unzip everything into one folder. It should run. You shouldn't need SDL installed unless you are developing it.

To remind you, I originally stated back in the tutorial An SDL GUI for Empire the list of controls I wanted. Here's the list and the state of implementation.

  • A plain panel. (Done)
  • A simple button. Something you click to do something. (Done)
  • A check box. Something you can tick or untick. (Done)
  • A text label.(Done)
  • A clickable list box. We'll keep it simple so no scrolling.
  • A popup box asking a question.
  • A Text entry box.
  • A clickable text command.
  • Display an image (not technically a control but make it optionally clickable).

Plus I'd like to add a vertically scrolling message area. It's not a GUI control as such but still quite useful.

So just under half done. time to pick up the pace. This time I'd like to implement a clickable list box. This comes in useful for simple menus, displaying any number of lines of text with each line clickable and can also be displayed over the map for a right click menu.

Clickable List Box.

The menu is going to be a vertical set of text lines so rather than having a fixed height we'll set that to 0 and use a parameter to set the maximum number of lines and the height will be calculated from that. An optional border would be nice.

Constructing the list box is a two stage process. First is create the sdllistbox through a addlistbox then add each individual list item. The list items will be another control type, sdllistitem which is added on the end of a single linked list with the head pointer contained in the sdllistbox. By using a list of items each being a control we can have each item clickable with its own click handler and also animated.

The struct for the listbox and listitem are:

struct sdllistitem {
    sdlbase;
    pchar itemtext;
    int index;
    struct sdllistitem * nextitem;
};

struct sdllistbox {
    sdlbase;
    pchar listtitle;
    int rowheight;
    int numcontrols;
    int border;
    int backcolor;
    struct sdllistitem * nextitem; /* list of menu items */
};

sdlbase is a C macro that defines common elements in each sdl gui component. This is documented in SDL GUI Tutorial 2 that includes such fields as the enum controltype, x, y, width, height, color plus function pointers that provide indirection to functions to draw the control, free it up, click event handlers and for some controls, a pre-click.

Bundling all that into one macro meant the specialization of each individual control (in C++ parlance) was handled using the extra fields and the functionality provided indirectly through the function pointers.

Even though the listbox has a linked list of items, the same addcontrol is used to add the listbox and the listitems. All the listitems are displayed within the listbox, so there's no need to handle the individual x and y for each listitem. So long as the listbox is responsible for rendering all the listitems (and the pRender in each listitem is set to NULL), it simplifies drawing the control.

The only adjustment has to be in addlistitem. All the controls, though added relative to the panel (or in the case of list items relative to the listbiox) have their x,y coordinates transformed to on screen x and y by adding panelx and panely (the top left coordinate of the panel) to them. As the listitems don't require explicit coordinates, the coordinates are picked up from the listbox and thus have to subtract panelx and panely before addcontrol is called which immediately adds them back!

Code to Create a Listbox

This is taken from the source files. Each event handler (menu1, menu2 etc) sets a global variable clicknum which if it's non zero is displayed in the text area below the map. It just shows that clicking the list items works.

listbox = (struct sdllistbox *)addlistbox(20,160,"Click 1, 2 or 3",gray, twhite,3,1);
addlistitem(listbox,"Item 1", twhite,menu1);
addlistitem(listbox,"Item 2", twhite,menu2);
addlistitem(listbox,"Item 3", twhite,menu3);

ListBox Details

Although each listitem can have its own color, all use the same font and so each row in the box is located vertically below the previous row + rowheight + 2. To make sure that each listitem can be clickable when its added, the coordinates are worked out relative to the row above using the listbox fields rowheight and numcontrols.

The click mechanism for all controls is done by checking the x,y coordinates against every clickable control rectangle on screen so as each listitem is added to the listbox, the listbox-numcontrolsnumber of controls is incremented and multiplied by listbox->rowheight.

Control Clickability

In previous versions, I had the various controls process clicks unless they were the esdlpanel type but obviously this needs a better methodology when a edsllistbox is hosting esdlitems. The panel, label and listbox don't have any way to process clicks by design but controls hosted within their rectangles obviously need to be clicked and it needed a change to accomodate this.

The change was to add a field clickable to the sdlbase and make this enabled by default and disabled for controls such as panels, lixtboxes and labels. Then in the CheckControlClickAt methods, the search to find the control clicked on would ignore non clickables. It's a simple solution compared to the likes of Windows where multiple processes overlap and the Z order has to be heeded as well.

To simplify this I used an array canclick[], indexed off the controltype to initialize the clickable field in addcontrol. To ensure that such initializations didn't get bypassed I reworked initsdlguilib so that the panel was also initialized via a call to addcontrol and added code to ensure it didn't get added to the end of the list of controis.

Listbox Animation

This version didn't have animated listitems but before the next published tutorial, I'll add it and update this article and the source code.

That completes this tutorial. This is dragging on, so we'll skip the remaining controls for the moment and in the next tutorial concentrate on setting up the starting positions and game initialization.

  1. About.com
  2. Technology
  3. C / C++ / C#
  4. Programming Games
  5. An SDL GUI for Empire Tutorial Five

©2014 About.com. All rights reserved.