EZ
Up Prev Next Contents


5.1 Write Primitive Widgets

To write your own primitive widget, you need to

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

5.1.1 Example: Locator

In this section, we implement the locator widget, a widget selects the mouse pointer coordinates in a rectangular area, scaled to [0,1]x[0,1].

Our locator has one private resources, value, which takes a pair of float point values in the range between 0.0 and 1.0.

We implement two interface routines for our locator. ez_GetLocatorXY and ez_SetLocatorXY. The first one returns the coordinates of the locator and the second one sets the coordinates of the locator.

Our locator will handle ButtonPress and KeyPress events. It also support MotionCallbacks, private event handlers and drag and drop.

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

void ez_GetLocatorXY (EZ_Widget *widget, float *x, float *y);
void ez_SetLocatorXY (EZ_Widget *widget, float x,  float y);
/*********************************************************************/

#define Locator_TYPE    65537 
static void LocatorSetup       (EZ_Widget *widget);
static void LocatorFreeData    (EZ_Widget *widget);
static void LocatorComputeSize (EZ_Widget *widget, int *w, int *h);
static void LocatorDraw        (EZ_Widget *widget);
static void LocatorEventHandle (EZ_Widget *widget, XEvent *event);
/*********************************************************************/

static void LocatorSetup(EZ_Widget *widget)
{
  /* this procedure is invoked when a new LOCATOR widget
   * is created. We initialize the locator through 
   * resources and create a gc for rendering the crosshair.
   *      
   * primitive widgets are implemented using the RAW_XWINDOW
   * widget. The RAW_XWINDOW widget data structure has
   * an array of 10 EZ_UnknownDataType reserved for 
   * us to hook up private data. 
   */
  EZ_UnknownDataType  *data = EZ_GetRawXWinPrivateData(widget);
  unsigned long       mask  = 0L;  
  XGCValues           gcvalues;
  char                *value;   /* tmp return for resource */

  /* data is an array of 10 EZ_UnknownDataTypes */
  data[0].f = 0.5;
  data[1].f = 0.5;
  /* parse private resources */
  if(EZ_GetWidgetResource(widget, "value", &value))
    {
      float   x,y;      
      if(sscanf(value, "%f %f", &x, &y) == 2)
        {
          if( x >= 0.0 && x <= 1.0) data[0].f = x;
          if( y >= 0.0 && y <= 1.0) data[1].f = y;
        }
    }
  data[2].p = (void *)EZ_GetGC(mask, &gcvalues);
}
/***************************************************************/

static void LocatorFreeData(EZ_Widget *widget) 
{
  /* this procedure is called when a LOCATOR widget is
   * destroyed. We free the GC allocated for this widget 
   */
  EZ_UnknownDataType  *data = EZ_GetRawXWinPrivateData(widget);
  GC gc = (GC)data[2].p;
  /* for gc created by EZ_GetGC, you must use EZ_FreeGC to free it ! */
  EZ_FreeGC(gc); 
}
/***************************************************************/

static void LocatorComputeSize(EZ_Widget *widget, int *w, int *h)
{
  /* this procedure is invoked by the geometry manager to
   * figure out the minimal size of LOCATOR.
   */
  *w =100; *h =100;  
}
/***************************************************************/

static void LocatorDraw(EZ_Widget *widget)
{
  int focus_pad = 0;   /* kbd focus highlight padding */
  int border    = 0;   /* border style */
  int bwidth    = 0;   /* border width */
  int padx, pady;      /* XY padding, not used */
  int width, height;   /* widget window width and height */
  Display  *dpy;       /* the display */
  Window   win;        /* widget window */
  int      depth;      /* depth of visual */
  int      tile;       /* is bg tiled ? */
  int      x, y, tmp, tmp2;
  Pixmap   pixmap;
  GC       gc;
  unsigned long pv;
  EZ_UnknownDataType  *data = EZ_GetRawXWinPrivateData(widget);

  EZ_GetWidgetPaddings(widget, &padx, &pady, &focus_pad); /* get all paddings       */
  EZ_GetWidgetBorder(widget, &bwidth, &border);           /* border characteristics */
  EZ_GetWidgetDimension(widget, &width, &height);         /* widget size            */
  dpy = EZ_GetDisplay();              /* display   */
  depth = EZ_GetDepth();             /*   visual    */
  win = EZ_GetWidgetWindow(widget); /* widget window */
  tmp = focus_pad + bwidth;        
  tmp2 = tmp + tmp;

  /* draw into a tmp pixmap, copy to the widget window when done */
  pixmap = XCreatePixmap(dpy, win, width, height, depth); 

  /* fill the background */
  EZ_GetBackgroundTileGC(widget, &gc, &pv, 0,0);  
  XFillRectangle(dpy, pixmap, gc, 0, 0, width, height);

  /* fix kbd focus highlight border */
  EZ_FixFocusHighlightBorder(widget, pixmap, width, height, focus_pad);
  
  /* render the foreground, the crosshair */
  gc = (GC)data[2].p;
  pv = EZ_GetForegroundPV(widget);
  XSetForeground(dpy, gc, pv);	

  x = tmp + (int)((width - tmp2) * data[0].f + 0.5);
  y = tmp + (int)((height- tmp2) * data[1].f + 0.5);
  
  XDrawLine(dpy, pixmap, gc, x, tmp, x, height -tmp); 
  XDrawLine(dpy, pixmap, gc, tmp, y, width - tmp,y);

  /* render the widget border */
  EZ_DrawRectBorder(widget, pixmap);

  /* and finally  ... */
  XCopyArea(dpy,pixmap,win, gc,0,0,width,height,0,0); 
  XFreePixmap(dpy, pixmap); 
}
/***************************************************************/

static void LocatorEventHandle(EZ_Widget *widget, XEvent *event)
{
  if(event->type == Expose) LocatorDraw(widget);
  else if(event->type == ButtonPress || event->type == KeyPress)
    {
      int padx, pady, focus_pad=0;                /* paddings  */
      int border = 0, bwidth = 0, bwpad, bwpad2;  /* border .. */
      int x,y, width, height;                     /* dimension */
      Display *dpy = EZ_GetDisplay();             /* display   */
      XEvent xevent;
      float save_x, save_y;
      EZ_UnknownDataType  *data = EZ_GetRawXWinPrivateData(widget);

      if(event->type == ButtonPress)
        {
          if(event->xbutton.button == EZ_Btn1)
            {
              /* get paddings and  dimension */
              EZ_GetWidgetPaddings(widget, &padx, &pady, &focus_pad);
              EZ_GetWidgetBorder(widget, &bwidth, &border);
              EZ_GetWidgetDimension(widget, &width, &height);
              bwpad = focus_pad + bwidth;
              bwpad2 = bwpad + bwpad;
              x = event->xbutton.x;
              y = event->xbutton.y;
              save_x = data[0].f;
              save_y = data[1].f;
              while(1)
                {
                  /* loop and wait for ButtonRelease. Invoke
                   * private event handlers on other events. Handle
                   * MotionNotify events and execute MotionCallbacks
                   * if needed.
                   */
                  if(x >= 0)
                    {
                      data[0].f = (float)(x-bwpad)/(float)(width  - bwpad2);
                      data[1].f = (float)(y-bwpad)/(float)(height - bwpad2);
                      if(data[0].f < 0.0) data[0].f = 0.0; else if(data[0].f > 1.0) data[0].f=1.0;
                      if(data[1].f < 0.0) data[1].f = 0.0; else if(data[1].f > 1.0) data[1].f=1.0;
                      LocatorDraw(widget);
                      /* if locator has changed it state, invoke motion callbacks */
                      if(save_x != data[0].f || save_y != data[1].f)
                        EZ_CallWidgetMotionCallbacks(widget);
                    }
                  XNextEvent(dpy, &xevent);
              
                  /* tricky! We want to give private EHandlers a chance  */
                  if(EZ_FilterEvent(&xevent)) EZ_InvokePrivateEventHandler(&xevent);
                  if(xevent.type == Expose) 
                    {
                      EZ_WidgetDispatchEvent(&xevent);
                      EZ_RemoveEvent(&xevent);
                    }
                  if(xevent.type == MotionNotify)
                    {
                      x = xevent.xmotion.x;
                      y = xevent.xmotion.y;
                      while(XCheckTypedEvent(dpy, MotionNotify, &xevent));
                    }
                  else if(xevent.type == ButtonRelease && xevent.xbutton.button == Button1)
                    break;
                  else x = -1111;
                }
            } 
          else if(event->xbutton.button == EZ_Btn3) 
            {
              EZ_HandleDnDEvents(widget, event);
            }
        }
      else /* key press */
        {
          char              tmpbuffer[8];
          int               buffersize = 8, xmove_unit, ymove_unit, count;
          KeySym            keysym;
          XComposeStatus    compose; 

          count = XLookupString(&(event->xkey), tmpbuffer, buffersize, &keysym, &compose);
          tmpbuffer[count] = '\0';
          xmove_unit = 0;
          ymove_unit = 0;

          switch(keysym)
            {
            case XK_Left: case XK_b:  case XK_h: case XK_B:  case XK_H:  
#ifdef XK_KP_Left
            case XK_KP_Left:
#endif
              if(event->xkey.state & ShiftMask)        xmove_unit = -4;
              else if(event->xkey.state & Mod1Mask)    xmove_unit = -10 ;
              else if(event->xkey.state & ControlMask) xmove_unit = -20;
              else xmove_unit = -1;
              break;
            case XK_Right: case XK_f: case XK_l: case XK_F: case XK_L:  
#ifdef XK_KP_Right
            case XK_KP_Right:
#endif
              if(event->xkey.state & ShiftMask)         xmove_unit = 4;
              else if(event->xkey.state & Mod1Mask)     xmove_unit = 10 ;
              else if(event->xkey.state & ControlMask)  xmove_unit = 20;
              else xmove_unit = 1;
              break;
            case XK_Up: case XK_k:  case XK_p: case XK_K:  case XK_P: 
#ifdef XK_KP_Up
            case XK_KP_Up:
#endif
              if(event->xkey.state & ShiftMask)         ymove_unit = -4;
              else if(event->xkey.state & Mod1Mask)     ymove_unit = -10 ;
              else if(event->xkey.state & ControlMask)  ymove_unit = -20;
              else ymove_unit = -1;
              break;
            case XK_Down: case XK_n: case XK_j: case XK_N: case XK_J:  
#ifdef XK_KP_Down
            case XK_KP_Down:
#endif
              if(event->xkey.state & ShiftMask)         ymove_unit = 4;
              else if(event->xkey.state & Mod1Mask)     ymove_unit = 10 ;
              else if(event->xkey.state & ControlMask)  ymove_unit = 20;
              else ymove_unit = 1;
              break;
            default:
              break;
            }
              
          if(xmove_unit | ymove_unit)
            {
              data[0].f += (xmove_unit) * 0.01;
              data[1].f += (ymove_unit) * 0.01;
              if(data[0].f < 0.0) data[0].f = 0.0; else if(data[0].f > 1.0) data[0].f=1.0;
              if(data[1].f < 0.0) data[1].f = 0.0; else if(data[1].f > 1.0) data[1].f=1.0;
              LocatorDraw(widget);
              EZ_CallWidgetMotionCallbacks(widget);
            }
          /* normally there are too many KeyPress events ... */
          while(XCheckTypedEvent(dpy, KeyPress, &xevent));
        }
    }
}
/**********************************************************************/

void ez_GetLocatorXY(EZ_Widget *widget, float *x, float *y)
{
  /* return the coordinates of the locator */
  EZ_UnknownDataType  *data = EZ_GetRawXWinPrivateData(widget);
  *x = data[0].f;  *y = data[1].f; 
}
/**********************************************************************/

void ez_SetLocatorXY(EZ_Widget *widget, float x, float y)
{
  /* set the location of the locator */
  EZ_UnknownDataType  *data = EZ_GetRawXWinPrivateData(widget);
  if(x < 0.0) x = 0.0; else if(x > 1.0) x = 1.0;
  if(y < 0.0) y = 0.0; else if(y > 1.0) y = 1.0;
  if(x != data[0].f || y != data[1].f)
    {
      data[0].f = x;
      data[1].f = y;
      if(EZ_WidgetIsViewable(widget)) EZ_DrawWidget(widget);
      EZ_CallWidgetMotionCallbacks(widget);
    }
}
/**********************************************************************/
/* TEST */
main(int ac, char **av)
{
  EZ_Widget *locator;
  EZ_Initialize(ac, av, 0);
  EZ_RegisterPrimitiveWidget(Locator_TYPE, "locator", "Locator",
                             LocatorSetup, LocatorComputeSize,
		             LocatorDraw, LocatorFreeData, LocatorEventHandle);
  locator = EZ_CreateWidgetXrm(LocatorType, NULL, 
                               "aLocator", "ALocator",
                               0);
  EZ_DisplayWidget(locator);
  EZ_EventMainLoop();
}
/**********************************************************************/

5.1.2 Help Functions

In this section, we list the functions that are useful for writing primitive widgets.

void EZ_GetWidgetPaddings(EZ_Widget *widget, int *padx, int *pady, int *focusPd);

return the paddings of a widget.

void EZ_GetWidgetBorder(EZ_Widget *widget, int *bwidth, int *btype));

return the border characteristics.

void EZ_GetWidgetDimension(EZ_Widget *widget, int *w, int *h);

return the dimension of a widget.

void EZ_GetWidgetMinDimension(EZ_Widget *widget, int *w, int *h);

return the minimal dimension of a widget.

void EZ_GetWidgetPosition(EZ_Widget *widget, int *x, int *y);

return the location of a widget.

void EZ_GetWidgetGeometry(EZ_Widget *widget, int *x,int *y, int *w, int *h);

return the geometry of a widget.

int EZ_GetBackgroundTileGC(EZ_Widget *widget, GC *gc, unsigned long *pv, int highlight, int force_highlight);

get background GC, return 1 if tile is used (with tile origin properly set).

int EZ_GetBackgroundGC(EZ_Widget *widget, GC *gc, unsigned long *pv, int highlight, int force_highlight);

get background GC, return 1 if tile is used (with tile origin unspecified).

int EZ_GetDarkBrightNormalBDGC(EZ_Widget *widget, GC *dark, GC *bright, GC *normal);

get border GCs, return 1 if tile is used (with tile origin unspecified).

void EZ_GetWidgetTileOrigin(EZ_Widget *widget, int *x, int *y);

if bg tile is used, return the tile origin.

int EZ_GetWidgetOrientation(EZ_Widget *widget);

return the orientation of a widget.

Window EZ_GetWidgetWindow(EZ_Widget *widget);

return the widget window.

EZ_Widget *EZ_GetParentWidget(EZ_Widget *widget);

return the parent widget.

EZ_Widget *EZ_GetChildrenWidget(EZ_Widget *widget);

return the first child, other children are siblings of the first child.

EZ_Widget *EZ_GetSiblingWidget(EZ_Widget *widget);

return the sibling widget.

unsigned long EZ_GetForegroundPV(EZ_Widget *widget);

return the pixel value of the foreground color.

EZ_Bitmap *EZ_GetWidgetPixmap(EZ_Widget *widget);

return the label pixmap of a widget.

void EZ_GetBrightBDpv(EZ_Widget *widget, unsigned long *pv);

return the pixel value of the bright side of the border.

void EZ_GetDarkBDpv(EZ_Widget *widget, unsigned long *pv);

return the pixel value of the dark side of the border.

XFontStruct *EZ_GetWidgetFont(EZ_Widget *widget);

return widget font.

Display *EZ_GetDisplay(void);

return the display.

void EZ_GetDisplayInfo(Display **dpy, int *scrn, Visual **vis, int *depth);

return info about current display.

void EZ_GetDisplaySize(int *w, int *h);

return the display screen size.

GC EZ_GetGC(unsigned long mask, GCValues gcvalues);

create and return a GC.

void EZ_FreeGC(GC gc);

free a GC created by EZ_GetGC.

void EZ_RegisterPrimitiveWidget(int type, char *iname, char *cname, void (*Setup)(EZ_Widget *widget), void (*ComputeSize)(EZ_Widget *widget, int *w, int *h), void (*DrawWidget)(EZ_Widget *widget), void (*FreeData)(EZ_Widget *widget), void (*EventHandle)(EZ_Widget *widget, XEvent *event));

register a primitive widget to EZwgl.


Up Prev Next Contents

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