## 6.2 Write Composite Widgets

To make your composite widget available to `EZ_CreateWidget`, you need to

- {select a default class name and a default instance name for your widget.}

- {Provide a creation function, of the following type

      EZ_Widget *create(EZ_Widget *parent, char *inst_name, char *class_name);

  }

- {call `EZ_RegisterCompositeWidget` to register your widget.}

- {write interface routines as needed.}

After a widget has been registered, it can be instantiatd by calling `EZ_CreateWidgetXrm` with the registered type.

### 6.2.1 Example: Counter

In this section, we implement a counter widget. Our counter has three private resources, `value` (an integer), `increment` (a pair of integers) and `counterWidth` (an integer specifies the width of the counter label).

We implement two interface procedures; `ez_GetCounter` and `ez_SetCounter`.

    /************************* Counter Widget *******************************/
    #include "EZ.h"

    int  ez_GetCounter (EZ_Widget *widget);
    void ez_SetCounter (EZ_Widget *widget, int value);
    /*********************************************************************/

    int Counter_TYPE;

    /*********************************************************************/
    static EZ_Widget *CounterCreate(EZ_Widget *parent, char *iname, char *cname);
    /*********************************************************************/
    typedef struct counter_ {
      EZ_Widget   *frame,  *label;
      EZ_Widget   *btnLL, *btnL, *btnR, *btnRR;
      int         type, value;
      int         increment1, increment2;
    } ez_counter;
    /*********************************************************************/

    int  ez_GetCounter(EZ_Widget *widget)
    {
      /* return counter value */
      ez_counter *ptr = (ez_counter *)EZ_GetWidgetPtrData(widget);
      return(ptr->value);
    }
    /*********************************************************************/

    void  ez_SetCounter(EZ_Widget *widget, int value)
    {
      /* set counter value and update display */
      ez_counter *ptr = (ez_counter *)EZ_GetWidgetPtrData(widget);
      if(ptr->value != value)
        {
          char str[64];
          ptr->value = value;
          sprintf(str, "%d", value);
          EZ_ConfigureWidget(ptr->label, EZ_LABEL_STRING, str, 0);
          if(EZ_WidgetIsViewable(ptr->label)) EZ_DrawWidget(ptr->label);
        }
    }
    /*********************************************************************/

    static void btnEHandle(EZ_Widget *btn, void *data, int etype, XEvent *xev)
    {
      /* the arrow buttons are labels, this event handler replaces
       * the default event handler
       */
      switch(xev->type)
        {
        case Expose:      EZ_DrawWidget(btn); break;
        case EnterNotify: EZ_HighlightWidget(btn, 1); break;
        case LeaveNotify: EZ_HighlightWidget(btn, 0); break;
        case ButtonPress:
          {
            if(xev->xbutton.button == EZ_Btn1)
              {
                Display    *dpy = EZ_GetDisplay();
                XEvent     xevent;
                ez_counter *ptr = (ez_counter *)data;
                int        whichBtn = EZ_GetWidgetIntData(btn);
                int        nnn = 10;
                int        increment, done = 0;

                switch(whichBtn)
                  {
                  case -2: increment = - ptr->increment2; break;
                  case -1: increment = - ptr->increment1; break;
                  case  1: increment =   ptr->increment1; break;
                  case  2: increment =   ptr->increment2; break;
                  default: break;
                  }
                /* wait for btn release */
                while( !done )
                  {
                    /* increment counter */
                    ez_SetCounter(btn, ptr->value + increment);
                    XSync(dpy, False);

                    if(--nnn > 0) EZ_SitForALittleBit(30000 * nnn);
                    else EZ_SitForALittleBit(30000);

                    while(XPending(dpy))
                      {
                        XNextEvent(dpy, &xevent);
                        if(xevent.type == ButtonRelease && xevent.xbutton.button == EZ_Btn1) done = 1;
                        if(xevent.type == Expose)
                          {
                            EZ_WidgetDispatchEvent(&xevent);
                            EZ_RemoveEvent(&xevent);
                          }
                        if(done) break;
                      }
                  }
              }
          }
        break;
        case KeyPress:  /* may be ... */
          break;
        default:
          break;
        }
      xev->type = 0;  /* disable the default event handler */
    }
    /*********************************************************************/
    static void freeCounter(EZ_Widget *w, void *data) { free(data);}
    /*********************************************************************/
    static EZ_Widget *CounterCreate(EZ_Widget *parent, char *iname, char *cname)
    {
      ez_counter *record = (ez_counter *)malloc(sizeof(ez_counter));
      memset(record, 0, sizeof(ez_counter));

      record->value = 0; record->increment1 = 1;  record->increment2 = 10;

      record->frame = EZ_CreateWidgetXrm(EZ_WIDGET_FRAME,        parent,
                                         iname, cname,
                                         EZ_PADX,                0,
                                         EZ_PADY,                0,
                                         EZ_IPADX,               2,
                                         EZ_HEIGHT,              0,
                                         EZ_FILL_MODE,           EZ_FILL_BOTH,
                                         EZ_DESTROY_CALLBACK,    freeCounter, record,
                                         EZ_CLIENT_PTR_DATA,     record,
                                         0);
      record->btnLL =    EZ_CreateWidget(EZ_WIDGET_LABEL,        record->frame,
                                         EZ_ARROW_LABEL,         EZ_DOUBLE_LEFT_TRIANGLE,
                                         EZ_CLIENT_PTR_DATA,     record,
                                         EZ_CLIENT_INT_DATA,     -2,
                                         EZ_EVENT_HANDLER,       btnEHandle, record,
                                         EZ_BORDER_WIDTH,        2,
                                         EZ_BORDER_TYPE,         EZ_BORDER_RAISED,
                                         EZ_WIDTH,                0,
                                         0);
      record->btnL =     EZ_CreateWidget(EZ_WIDGET_LABEL,        record->frame,
                                         EZ_ARROW_LABEL,         EZ_LEFT_TRIANGLE,
                                         EZ_CLIENT_PTR_DATA,     record,
                                         EZ_CLIENT_INT_DATA,     -1,
                                         EZ_EVENT_HANDLER,       btnEHandle, record,
                                         EZ_BORDER_WIDTH,        2,
                                         EZ_BORDER_TYPE,         EZ_BORDER_RAISED,
                                         EZ_WIDTH,                0,
                                         0);
      record->label = EZ_CreateWidgetXrm(EZ_WIDGET_LABEL,        record->frame,
                                         "counter", "Counter",
                                         EZ_BORDER_TYPE,         EZ_BORDER_SUNKEN,
                                         EZ_BORDER_WIDTH,        2,
                                         EZ_WIDTH,               80,
                                         EZ_LABEL_POSITION,      EZ_CENTER,
                                         EZ_CLIENT_PTR_DATA,     record,
                                         EZ_PROPAGATE,           False,
                                         0);
      record->btnR =    EZ_CreateWidget(EZ_WIDGET_LABEL,        record->frame,
                                        EZ_ARROW_LABEL,          EZ_RIGHT_TRIANGLE,
                                        EZ_CLIENT_PTR_DATA,      record,
                                        EZ_CLIENT_INT_DATA,      1,
                                        EZ_EVENT_HANDLER,        btnEHandle, record,
                                        EZ_BORDER_WIDTH,         2,
                                        EZ_BORDER_TYPE,          EZ_BORDER_RAISED,
                                        EZ_WIDTH,                0,
                                        0);
      record->btnRR =   EZ_CreateWidget(EZ_WIDGET_LABEL,        record->frame,
                                        EZ_ARROW_LABEL,          EZ_DOUBLE_RIGHT_TRIANGLE,
                                        EZ_CLIENT_PTR_DATA,      record,
                                        EZ_CLIENT_INT_DATA,      2,
                                        EZ_EVENT_HANDLER,        btnEHandle, record,
                                        EZ_BORDER_WIDTH,         2,
                                        EZ_BORDER_TYPE,          EZ_BORDER_RAISED,
                                        EZ_WIDTH,                0,
                                        0);

      /* set up: parse resources 'value', 'increment' and 'counterWidth */
      {
        char str[64], *value; int a, b;
        if(EZ_GetWidgetResource(record->frame, "value", &value))
          if(sscanf(value, "%d", &a) == 1) record->value = a;
        if(EZ_GetWidgetResource(record->frame, "increment", &value))
          if(sscanf(value, "%d %d", &a, &b) == 2)
            { record->increment1 = a;  record->increment2 = b;}
        if(EZ_GetWidgetResource(record->frame, "counterWidth", &value))
          if(sscanf(value, "%d", &a) == 1 && a > 0)
            { EZ_ConfigureWidget(record->label, EZ_WIDTH,  a, 0); }

        sprintf(str, "%d", record->value);
        EZ_ConfigureWidget(record->label, EZ_LABEL_STRING, str, 0);
      }
      return(record->frame);
    }
    /*********************************************************************/
    /* TEST */
    main(int ac, char **av)
    {
      EZ_Widget *counter;

      EZ_Initialize(ac,av,0);
      Counter_TYPE = EZ_RegisterCompositeWidget("counter", "Counter",
                                 CounterCreate);
      counter  = EZ_CreateWidgetXrm(Counter_TYPE,    NULL,
                                    "counter1",      "Counter1",
                                    0);
      EZ_DisplayWidget(counter);
      EZ_EventMainLoop();
    }
    /*********************************************************************/

HTML Documentation Maintainance:`Arturo Espinosa <arturo@nuclecu.unam.mx>`