Drawing a slider or a scrollbar is similar to drawing a progress bar, in that you need to express the slider’s current position as a percentage of its client rectangle, giving you the position at which to draw the “pointer” (or, for a scrollbar, the elevator). You’ll have to make some slight modifications for horizontal vs. vertical controls - I got around these by implementing a base class, gui_slider, which contained all of the common code, and all of the member variables, and then implementing two specific derivatives, gui_slider_horz and gui_slider_vert, which handled the differences in drawing and clicking logic.
As for processing mouse clicks, I opted for the easy way when I created my sliders. If a mouse click occurs in the client area of a scrollbar, I automatically scroll directly to that position. In my sliders, you can’t click in the “shaft” and move the position by a page at a time - you jump directly to where you clicked. This was a decision I made primarily because it was easy, but also because I dislike the default Windows behavior of paging.
As for the scrollbar / slider logic, you’ve got the same basic setup as a progress bar - min, max, and current positions. Unlike a progress bar, however, the user can change the current position by clicking in the control.
Now, scrollbars. I decided, for my GUI, that scrollbars are just sliders with two buttons tacked onto either side. These two buttons (the up/down or left/right arrows) move the elevator one position. This method eliminated a lot of code duplication between the pushbutton class and the scrollbars, and I would highly recommend that you take a look at doing something similar.
Now that we’ve got scrollbars, we can tackle the most complex control of them all… the listbox.
The Listbox Control
Resign yourself to this now - the listbox control is where you’re going to be spending the most time.
// represents a column in our listbox
class gui_listbox_column {
public:
gui_listbox_column() {}
virtual ~gui_listbox_column() {}
virtual void draw(uti_rectangle& where);
void setname(const char *name) { m_name = name; }
uti_string getname(void) { return(m_name); }
int getwidth(void) { return(m_width); }
void setwidth(int w) { m_width = w; }
private:
uti_string m_name;
int m_width;
};
// an item in our listbox
class gui_listbox_item {
public:
gui_listbox_item() { m_isselected = 0; m_indent = 0; }
virtual ~gui_listbox_item() {}
virtual drawitem(int colnum, uti_rectangle& where);
void clearallcolumns(void); // boring
void setindent(int i) { m_indent = i; }
int getindent(void) { return(m_indent); }
void settext(int colnum, const char *text); // boring
uti_string gettext(int colnum = 0); // boring
void setitemdata(UL itemdata) { m_itemdata = itemdata; }
UL getitemdata(void) { return(m_itemdata); }
void setselected(int s = 1) { m_isselected = s; }
int getselected(void) { return(m_isselected); }
private:
int m_isselected;
int m_indent; // # of pixels to indent this item
UL m_itemdata;
uti_pointerarray m_coltext;
};
// the listbox itself
class gui_fancylistbox: public gui_window {
public:
gui_fancylistbox() { m_multiselect = 0; }
virtual ~gui_fancylistbox() { clear(); }
int getselected(int iter = 0);
virtual int wm_command(gui_window *win, int cmd, int param);
virtual int wm_paint(coord x, coord y);
virtual int wm_lbuttondown(coord x, coord y);
gui_fancyscrollbar_horz& gethscroll(void) { return(m_hscroll); }