Rather crappy documentation
In ROWS, all widgets are derived from the base widget, which provides the most basic facilities that a widget requires (which is just about none). This makes a widget a fairly general entity under ROWS. It need not be associated with a window, have a bounding box or anything. All widgets are derived from ROWS_widget.
A derived widget should provide a few standard calls to allow it to be created in a standard way:
<widgetname>_create(void)
- this is called by the user
program to create the top-level widget. It is not called to initialise the
widgets that it is derived from. This call should return a ROWS_widget
structure, which it does by calling its _initialise
routine, and
passing its own heirarchical level as the parameter (thus making itself the
topmost widget)
<widgetname>_initialise(int top_level)
- this is called to
initialise a widget. It must be called before any widget data structures can
be initialised, and it returns a ROWS_widget, obtained by calling the
_initialise
routine of the widget it is derived from. A usual
routine might look a bit like:
static int foo_level = -1; /* Our level in the widget heirarchy */ static int foo_type = -1; /* A unique identifier */ ROWS_widget *foo_initialise(int top_level) { ROWS_widget *widget; _p_foo_widget_data **private; /* A structure describing our private data */ /* Pretty standard initialisation */ if (foo_level==-1) foo_level = bar_next_identifier(); if (foo_type==-1) foo_type = ROWS_widget_next_type(); widget = bar_initialise(top_level); /* This widget is derived from 'bar' */ ROWS_widget_set_ID(us, foo_level, foo_type); /* Private initialisation */ private = (_p_foo_widget_data **) ROWS_widget_private(widget, foo_level); (*private) = ROWS_alloc(sizeof(_p_foo_widget_data)); (*private)->amount_of_sheep = 2; /* Return a widget type */ return widget; }
Note that top_level is the heirarchical level of the topmost widget (ie our widget would pass foo_level to foo_initialise in its _create statement):
ROWS_widget *foo_create(void) { if (foo_level==-1) foo_level = bar_next_identifier(); return foo_initialise(foo_level); }
I think it goes without saying that neither the type identifier or the heirarchical level of the widget could ever be negative. (I guess you might run into problems if you get a heirarchy more than 32768 deep on some systems, but I suspect you'd be more worried about how much memory your program uses :)
Also of note is that the 'private' data (a void ** type) contains both a reference to your private data (*private), but also to the widget it is derived from (functions are provided to allow you to convert between widget types)
<widgetname>_next_identifier(void)
should return the
heirarchical level above the one your widget is in. If for any reason, you
don't want people to derive widgets from yours, leave this call out or make
it return an error message. The general form is:
int foo_next_identifier(void) { if (foo_level==-1) foo_level = bar_next_identifier(); return foo_level+1; }
That shouldn't be too hard. Problems here might result in over or under-allocation of private space for widgets, and there isn't much scope for checking for errors...
ROWS_widget_private()
) should be
used as a type definition (ie typedef void ** foo) so that each widget has
its own type. The pointer not only points to the 'real' private data for the
widget, but also a structure containing information about this widget and the
widgets it has been derived from. This means that you can cast any widget
into any of the widgets it is derived from (or indeed, has been derived from
it), so you should supply a call to allow people to do this:
foo foo_cast(void **widget) { return ROWS_widget_cast_misc(widget, foo_level, foo_type); }
Note that this performs type-checking while performing the cast, so it will produce a (moderately) helpful error message if you try to cast a button into a text box or something similarily silly. If the widget hasn't been typed properly, you'll get a warning, and if you pass an invalid pointer you'll probably get a segmentation fault... Also note that I don't verify that foo_level and so on are set up correctly. Strictly speaking, I should have done, but if you haven't created a widget of a certain type yet, you certainly shouldn't be casting to it (so the default, -1, values of these will cause an error)
Disclaimer: the code given here may or may not work