SEAL's object style of programming

Seal was programmed in a object programming style. It's not in OOP (object oriented programing) as Uniforms, but in simple C that use structures and pointers to this structures. Main structure is the t_object structure. Each structure in Seal has a pointer type to structure defined by p_(name of object). For example t_object has the pointer type p_object. It looks like this:
     typedef struct t_object *p_object;

The object (structure) t_object is a object that can group other objects that inherit functions and variables from it. When you want to make new object with additional functions you simply type:
     typedef struct t_hallo *p_hallo;
     typedef struct t_hallo {


           struct t_object  obclass;

           /* ...additional functions */

     } t_hallo;

     #define HALLO(o) (p_hallo(o))

Note: The name "obclass" is not important. You may use your own name, and all of Seal's objects will use this name for the inherited structure, BUT YOU MUST DECLARE IT BEFORE ALL OTHER DATA!


When you want to make an object that inherits functions/variables from the t_button structure and make some additional functions, declare this:

     typedef struct t_newbutton *p_newbutton;
     typedef struct t_newbutton {


           struct t_button  obclass;

           /* ...your additional data */

     } t_newbutton;

     #define NEWBUTTON(o) ((p_newbutton)(o))


You may see that NEWBUTTON, HALLO, OBJECT, VIEW, BUTTON, ... are only definitions that replace conversions of types. By this conversion you can use data from t_newbutton in function e.g. void draw ( p_object o ).

When you build a new object you allocate memory that contains size also from t_button structure. So you can use functions from this structure, but you must talk to compiler it's OK, I have a memory for this operation. When you build your new structure obclass you must make your new initialization function such as:

     p_newbutton newbutton_init ( p_newbutton o, t_rect r, l_text title ) {

          if ( !o ) return NULL;

          clear_type(o, sizeof(t_newbutton));

                /* clear_type() is same as memset(o, NULL, sizeof(t_newbutton)) */

          button_init(BUTTON(o), r, title, 0, 0);

                /* You must call initialization function that initialize
                   functions and variables in obclass structure. You can also 
                   call this like button_init(&(o->obclass), r, title, 0, 0), 
                   but it's better to use the standard macro. */

      /* Declaration of your object: */

      VIEW(o)->draw = &newbutton_draw;

                /* This redeclares the function draw() from the t_view structure 
                   in your new draw function. This structure is on one of these 
                   new objects:

                     t_object  OBJECT(o)-> 
                       |
                     t_view   VIEW(o)->
                       |
                     t_button  BUTTON(o)->

                   You can use all functions/variables from these structures. */

     return o;
};


Now you can create an instance of this object by calling:

     p_newbutton b = newbutton_init(malloc(sizeof(t_newbutton)),
                                    r,
                                    "Hello button");


Where malloc(sizeof(t_newbutton)) allocates memory for the new object, r is the rectangular area where it will be placed on it's parent and "Hello button" is the title of the new button.

Then we can insert the new button(b) to the desktop object with the function:

     p_object insert ( p_object dst, p_object son ); 

                 /* This is found in the t_object structure. */


     OBJECT(desktop)->insert(OBJECT(desktop), OBJECT(b));




Example:

An example of a button structure which only redefines some functions that are used in t_object, t_view and t_button structures:

     void  new_trans_ev(p_object o, p_event event) 
     {
         RETVIEW(o, event);   /* This will be explained later. */

         button_translate_event(o, event);
     };



     void  draw(p_view o) 
     {
         button_draw(o); 

            /* Call old draw button's function. You can't use o->draw(o);
               because you will call this function again and then you'll
               cause a stack overflow. */
     };



     void  draw_state(p_button o, l_int press) 
     {
         button_draw_state(o, press);
     };



     p_button o = button_init(malloc(sizeof(t_button)),
                              r,
                              "Hello world",
                              0,
                              0);

     OBJECT(o)->translate_event = &new_trans_ev;
     VIEW(o)->draw = &new_draw;
     BUTTON(o)->draw_state = &new_draw_state;