[Scummvm-devel] New GUI code

Max Horn fingolfin at marblehorse.org
Thu Jul 4 08:10:06 CEST 2002


As most (all? :-) of you will agree, the current GUI code in ScummVM 
is quite crappy.... we just had quite some discussion about this in 
#scummvm and decided to scrap it and rewrite it from scratch 
(possibly keeping a future GUI that allows in-game selection of the 
game to play and other nice stuff). Both me and Endy wanted to start 
working on it, so I figure it's better if we first agree on what it 
should be like .

So here are my thoughts to it. First some important requirements I'd 
like to be met:


* Properly seperate the logic of each dialog into seperate 
classes/functions (the current GUI mixes them all into the same code)

* OOP based: one class "Dialog", from which we derive 
"SaveLoadDialog", "OptionDialog" which carries the control logic for 
each dialog

* Seperate the view logic (how to draw a button if it is clicked?) 
from the control logic (what happens if the button is clicked?). This 
can be achieved by having a lightweight Widget class (and subclasses) 
that perform the drawing and some other common things (like a 
CheckBoxWidget would simply toggle itself when clicked).

* proper nesting of dialogs must be possible. That probably involves 
a "dialog stack" of some kind but overall shouldn't be too hard

* small memory footprint should be kept in mind

* everything still should be simple to use and extend. Like, don't 
force us to subclass Widget whenever we want to add a new button; 
instead, the ButtonWidget class should be designed flexible enough to 
easily allow for most uses w/o any additional subclass.


OK, and here is how I envision how this could be done:


Each Dialog contains "Widget" objects (that's not really much 
different from what we have). There are different Widget subclasses, 
for various purposes (ButtonWidget, CheckBoxWidget, StaticTextWidget, 
SliderWidget, etc.). They all share some API, but also can have class 
specific API.

All widgets share some properties:
  * can have an ID assigned to it, that can be used by the parent 
dialog to identify the widget (e.g. distinguish OK from Cancel 
button).
  * knows how to draw itself
  * has a method to respond to clicks on it (which can just do nothing 
by default)
  * a "boss"/"owner"/"parent", probably just always the dialog it is 
contained in.
  * a set of flags, to be defined, but among them: dis/enabled. others 
could be: wantPeriodicTickle, wantKeyboardEvents, etc.

Widgets can have some own intelligence: e.g. a CheckBoxWidget, when 
clicked, may toggle itself. A ButtonWidget can have a command ID (an 
Uint32), and when it's clicked, it will send this ID to its boss. 
Making this Uint32 allows us to use human readable constants, like 
'SAVE' or 'LOAD' for the command IDs
OTOH a widget can be "dumb", e.g. a StaticTextWidget does nothing 
when it is clicked

Widget also can request to be be periodically notified, e.g. so they 
can animate.

Event handling is starts in the Gui class. It will first determine 
the top most dialog. Then depending on the event it calls the 
handleClick/handleKey method of that top dialog.

These methods in turn provide default implementation: handleClick() 
by default just determines the widget that was clicked and calsl the 
handleClick method of that. That will be sufficient for 99% of all 
uses but can be customized if necessary this way. handleKey() will by 
default only handle "hot keys", or if there is an active edit field, 
pass the key to that edit field instead.

This could amount to classes similar to these:

class Widget;

class Dialog {
   Widget *_firstWidget;
public:
   void handleIdle(); // Called periodically

   void handleClick(int x, int y, char button) // left/middle/right
   {
     Widget *w = findWidget(x,y);
     if (w)
       w->handleClick(button);
   }
   void handleKey(char key, int modifiers); // modifiers = alt/shift/ctrl etc.
   void handleCommand(uint32 cmd);
protected:
   Widget* findWidget(int x, int y); // Find the widget at pos x,y if any
}

typedef enum {
   WIDGET_ENABLED,
   WIDGET_WANT_TICKLE,
} WidgetFlags;

class Widget {
   Dialog  *_boss;
   Widget  *_next;
   int16 _x,_y;
   uint16 _w,_h;
   uint16 _id;
   uint8 _hotkey;
   WidgetFlags _flags;
public:
   Widget(Dialog *boss, int x, int y, int w, int h);
   void handleClick(char button);
   void draw();
};

class ButtonWidget : public Widget {
   uint32  _cmd;
public:
   void setCmd(uint32 cmd);
   void handleClick(char button) { if (_flags & WIDGET_ENABLED) 
boss->handleCommand(_cmd); }
}


Cheers,

Max
-- 
-----------------------------------------------
Max Horn
Software Developer

email: <mailto:max at quendi.de>
phone: (+49) 6151-494890




More information about the Scummvm-devel mailing list