To write your own primitive widget, you need to
setup(EZ_Widget *widget); computeSize(EZ_Widget *widget, int *w, int *h); freeData(EZ_Widget *widget); draw(EZ_Widget *widget); eventHandle(EZ_Widget *widget, XEvent *event)
setup
is invoked whenever an instance
of your widget is created. You should include here
the widget or widget class initialization code
and the code for parsing private resources.
Primitive widgets are implemented internally through
the RawXWindow
widget. The widget data structure
provides an array of 10 EZ_UnknownDataType
for you
to hook up private data to your widget.
computeSize
is invoked by the geometry manager to
figure out the minimal size of your widget.
freeData
is invoked by EZ_DestroyWidget
to clean up widget private data.
draw
is invoked whenever there are needs to repaint the
widget window.
evehtHandle
is the
default widget event handler.
EZ_RegisterPrimitiveWidget
to register
your widget. This function returns an integer identifier.
After a widget has been registered, it can be instantiatd
by calling EZ_CreateWidgetXrm
with type the
returned identifier.
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);
/*********************************************************************/
int Locator_TYPE;
/*********************************************************************/
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);
LocatorType = EZ_RegisterPrimitiveWidget("locator", "Locator",
LocatorSetup, LocatorComputeSize,
LocatorDraw, LocatorFreeData, LocatorEventHandle);
locator = EZ_CreateWidgetXrm(LocatorType, NULL,
"aLocator", "ALocator",
0);
EZ_DisplayWidget(locator);
EZ_EventMainLoop();
}
/**********************************************************************/
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);
void EZ_GetWidgetBorder(EZ_Widget *widget, int *bwidth, int *btype));
void EZ_GetWidgetDimension(EZ_Widget *widget, int *w, int *h);
void EZ_GetWidgetMinDimension(EZ_Widget *widget, int *w, int *h);
void EZ_GetWidgetPosition(EZ_Widget *widget, int *x, int *y);
void EZ_GetWidgetGeometry(EZ_Widget *widget, int *x,int *y, int *w, int *h);
int EZ_GetBackgroundTileGC(EZ_Widget *widget, GC *gc, unsigned long *pv,
int highlight, int force_highlight);
int EZ_GetBackgroundGC(EZ_Widget *widget, GC *gc, unsigned long *pv,
int highlight, int force_highlight);
int EZ_GetDarkBrightNormalBDGC(EZ_Widget *widget, GC *dark,
GC *bright, GC *normal);
void EZ_GetWidgetTileOrigin(EZ_Widget *widget, int *x, int *y);
int EZ_GetWidgetOrientation(EZ_Widget *widget);
Window EZ_GetWidgetWindow(EZ_Widget *widget);
EZ_Widget *EZ_GetParentWidget(EZ_Widget *widget);
EZ_Widget *EZ_GetChildrenWidget(EZ_Widget *widget);
EZ_Widget *EZ_GetSiblingWidget(EZ_Widget *widget);
unsigned long EZ_GetForegroundPV(EZ_Widget *widget);
EZ_Bitmap *EZ_GetWidgetPixmap(EZ_Widget *widget);
void EZ_GetBrightBDpv(EZ_Widget *widget, unsigned long *pv);
void EZ_GetDarkBDpv(EZ_Widget *widget, unsigned long *pv);
XFontStruct *EZ_GetWidgetFont(EZ_Widget *widget);
Display *EZ_GetDisplay(void);
void EZ_GetDisplayInfo(Display **dpy, int *scrn, Visual **vis, int *depth);
void EZ_GetDisplaySize(int *w, int *h);
GC EZ_GetGC(unsigned long mask, GCValues gcvalues);
void EZ_FreeGC(GC gc);
int EZ_RegisterPrimitiveWidget(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));
EZ_GetGC
.
EZ_CreateWidget
to instantiate the registered widget.