Commit an early non-functional prototype of the new widget code. Feel free to modify as you see fit.
git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@4761 4a71c877-e1ca-e34f-864e-861f7616d084master
parent
2ffc569a35
commit
f8eb466d16
|
@ -0,0 +1,9 @@
|
||||||
|
#include "geom.h"
|
||||||
|
|
||||||
|
bool pointInRect(point p, rect r)
|
||||||
|
{
|
||||||
|
return (r.topLeft.x < p.x
|
||||||
|
&& r.bottomRight.x > p.x
|
||||||
|
&& r.topLeft.y < p.y
|
||||||
|
&& r.bottomRight.y > p.y);
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef GEOM_H_
|
||||||
|
#define GEOM_H_
|
||||||
|
|
||||||
|
// TODO: Make this cross platform (MSVC)
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A point
|
||||||
|
*/
|
||||||
|
typedef struct _point point;
|
||||||
|
|
||||||
|
struct _point
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A rectangle
|
||||||
|
*/
|
||||||
|
typedef struct _rect rect;
|
||||||
|
|
||||||
|
struct _rect
|
||||||
|
{
|
||||||
|
point topLeft;
|
||||||
|
point bottomRight;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Method signatures
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see if the point p is inside of the rectangle r.
|
||||||
|
*
|
||||||
|
* @param point p
|
||||||
|
* @param rect r
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
bool pointInRect(point p, rect r);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /*GEOM_H_*/
|
|
@ -0,0 +1,104 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
|
const int defaultSize = 4;
|
||||||
|
|
||||||
|
vector *vectorCreate(destroyCallback cb)
|
||||||
|
{
|
||||||
|
vector *v = malloc(sizeof(vector));
|
||||||
|
|
||||||
|
if (v == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
v->mem = calloc(defaultSize, sizeof(void *));
|
||||||
|
|
||||||
|
if (v->mem == NULL)
|
||||||
|
{
|
||||||
|
free(v);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
v->size = defaultSize;
|
||||||
|
v->head = 0;
|
||||||
|
v->destroy = cb;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vectorDestroy(vector *v)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < vectorSize(v); i++)
|
||||||
|
{
|
||||||
|
v->destroy(v->mem[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(v->mem);
|
||||||
|
free(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *vectorAdd(vector *v, void *object)
|
||||||
|
{
|
||||||
|
if (v->head + 1 > v->size)
|
||||||
|
{
|
||||||
|
void **newMem = realloc(v->mem, 2 * v->size * sizeof(void *));
|
||||||
|
|
||||||
|
if (newMem == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
v->size *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
v->mem[v->head++] = object;
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *vectorAt(vector *v, int index)
|
||||||
|
{
|
||||||
|
return (index <= vectorSize(v)) ? v->mem[index] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *vectorSetAt(vector *v, int index, void *object)
|
||||||
|
{
|
||||||
|
if (index >= v->head)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the current element at index
|
||||||
|
v->destroy(v->mem[index]);
|
||||||
|
|
||||||
|
// Replace the item
|
||||||
|
v->mem[index] = object;
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vectorRemoveAt(vector *v, int index)
|
||||||
|
{
|
||||||
|
if (index >= v->head)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the element using the provided callback
|
||||||
|
v->destroy(v->mem[index]);
|
||||||
|
|
||||||
|
memmove(&v->mem[index], &v->mem[index + 1],
|
||||||
|
(v->head - index) * sizeof(void *));
|
||||||
|
|
||||||
|
v->head--;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vectorSize(vector *v)
|
||||||
|
{
|
||||||
|
return v->head;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef VECTOR_H_
|
||||||
|
#define VECTOR_H_
|
||||||
|
|
||||||
|
typedef struct _vector vector;
|
||||||
|
typedef void (*destroyCallback) (void *object);
|
||||||
|
|
||||||
|
struct _vector
|
||||||
|
{
|
||||||
|
void **mem;
|
||||||
|
int size;
|
||||||
|
int head;
|
||||||
|
destroyCallback destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
vector *vectorCreate(destroyCallback destroyCb);
|
||||||
|
|
||||||
|
void vectorDestroy(vector *v);
|
||||||
|
|
||||||
|
void *vectorAdd(vector *v, void *object);
|
||||||
|
|
||||||
|
void *vectorAt(vector *v, int index);
|
||||||
|
|
||||||
|
void *vectorSetAt(vector *v, int index, void *object);
|
||||||
|
|
||||||
|
void vectorRemoveAt(vector *v, int index);
|
||||||
|
|
||||||
|
int vectorSize(vector *v);
|
||||||
|
|
||||||
|
#endif /*VECTOR_H_*/
|
|
@ -0,0 +1,484 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "widget.h"
|
||||||
|
|
||||||
|
static widgetVtbl vtbl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Forward declarations
|
||||||
|
*/
|
||||||
|
static void widgetDrawChildren(widget *self, cairo_t *cr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares the widget classes vtable.
|
||||||
|
*/
|
||||||
|
static void widgetInitVtbl(widget *self)
|
||||||
|
{
|
||||||
|
static bool initialised = false;
|
||||||
|
|
||||||
|
if (!initialised)
|
||||||
|
{
|
||||||
|
vtbl.addChild = widgetAddChildImpl;
|
||||||
|
vtbl.removeChild = widgetRemoveChildImpl;
|
||||||
|
|
||||||
|
vtbl.fireCallbacks = widgetFireCallbacksImpl;
|
||||||
|
vtbl.addEventHandler = widgetAddEventHandlerImpl;
|
||||||
|
vtbl.removeEventHandler = widgetRemoveEventHandlerImpl;
|
||||||
|
vtbl.handleEvent = widgetHandleEventImpl;
|
||||||
|
|
||||||
|
vtbl.focus = widgetFocusImpl;
|
||||||
|
vtbl.blur = widgetBlurImpl;
|
||||||
|
|
||||||
|
vtbl.enable = widgetEnableImpl;
|
||||||
|
vtbl.disable = widgetDisableImpl;
|
||||||
|
|
||||||
|
vtbl.doDraw = NULL;
|
||||||
|
|
||||||
|
vtbl.destroy = widgetDestroyImpl;
|
||||||
|
|
||||||
|
initialised = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the classes vtable
|
||||||
|
self->vtbl = &vtbl;
|
||||||
|
|
||||||
|
// Do any overloading of inherited methods here
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Widget class constructor
|
||||||
|
*/
|
||||||
|
void widgetInit(widget *self, const char *id)
|
||||||
|
{
|
||||||
|
// Prepare our vtable
|
||||||
|
widgetInitVtbl(self);
|
||||||
|
|
||||||
|
// Prepare our container
|
||||||
|
self->children = vectorCreate((destroyCallback) widgetDestroy);
|
||||||
|
|
||||||
|
// Prepare our events table
|
||||||
|
self->eventVtbl = vectorCreate(free);
|
||||||
|
|
||||||
|
// Copy the ID of the widget
|
||||||
|
self->id = strdup(id);
|
||||||
|
|
||||||
|
// Default parent is none
|
||||||
|
self->parent = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Widget class destructor (virtual).
|
||||||
|
*/
|
||||||
|
void widgetDestroyImpl(widget *self)
|
||||||
|
{
|
||||||
|
// Release the container
|
||||||
|
vectorDestroy(self->children);
|
||||||
|
|
||||||
|
// Release the event handler table
|
||||||
|
vectorDestroy(self->eventVtbl);
|
||||||
|
|
||||||
|
// Free the ID
|
||||||
|
free(self->id);
|
||||||
|
|
||||||
|
// Free ourself
|
||||||
|
free(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draws and widget and its child widgets
|
||||||
|
*/
|
||||||
|
void widgetDraw(widget *self, cairo_t *cr)
|
||||||
|
{
|
||||||
|
// Draw ourself
|
||||||
|
widgetDoDraw(self, cr);
|
||||||
|
|
||||||
|
// Draw our children
|
||||||
|
widgetDrawChildren(self, cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draws the child widgets of self.
|
||||||
|
*/
|
||||||
|
static void widgetDrawChildren(widget *self, cairo_t *cr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Draw our children
|
||||||
|
for (i = 0; i < vectorSize(self->children); i++)
|
||||||
|
{
|
||||||
|
widget *child = WIDGET(vectorAt(self->children, i));
|
||||||
|
cairo_matrix_t current;
|
||||||
|
|
||||||
|
// Translate such that (0,0) is the location of the widget
|
||||||
|
cairo_get_matrix(cr, ¤t);
|
||||||
|
cairo_translate(cr, child->bounds.topLeft.x, child->bounds.topLeft.y);
|
||||||
|
|
||||||
|
widgetDraw(child, cr);
|
||||||
|
|
||||||
|
// Restore the matrix
|
||||||
|
cairo_set_matrix(cr, ¤t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
widget *widgetGetRoot(widget *self)
|
||||||
|
{
|
||||||
|
// If we are the root widget, return early
|
||||||
|
if (self->parent == NULL)
|
||||||
|
{
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
// Otherwise search the hierarchy
|
||||||
|
else
|
||||||
|
{
|
||||||
|
widget *current;
|
||||||
|
|
||||||
|
for (current = self->parent; current->parent; current = current->parent);
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
widget *widgetFindById(widget *self, const char *id)
|
||||||
|
{
|
||||||
|
// See if we have that ID
|
||||||
|
if (strcmp(self->id, id) == 0)
|
||||||
|
{
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
// Try our children
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < vectorSize(self->children); i++)
|
||||||
|
{
|
||||||
|
// Get the child widget
|
||||||
|
widget *child = vectorAt(self->children, i);
|
||||||
|
|
||||||
|
// Call its findById method
|
||||||
|
widget *match = widgetFindById(child, id);
|
||||||
|
|
||||||
|
// If it matched, return
|
||||||
|
if (match)
|
||||||
|
{
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we found nothing return NULL
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool widgetAddChildImpl(widget *self, widget *child)
|
||||||
|
{
|
||||||
|
// FIXME: We need to do some arbitration
|
||||||
|
|
||||||
|
// Add the widget
|
||||||
|
vectorAdd(self->children, child);
|
||||||
|
|
||||||
|
// Set ourself as its parent
|
||||||
|
child->parent = self;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void widgetRemoveChildImpl(widget *self, widget *child)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < vectorSize(self->children); i++)
|
||||||
|
{
|
||||||
|
// If the child is the to-be-removed widget, remove it
|
||||||
|
if (vectorAt(self->children, i) == child)
|
||||||
|
{
|
||||||
|
// vectorRemoveAt will take care of calling the widgets destructor
|
||||||
|
vectorRemoveAt(self->children, i);
|
||||||
|
}
|
||||||
|
// See if it is one of its children
|
||||||
|
else
|
||||||
|
{
|
||||||
|
widgetRemoveChild(vectorAt(self->children, i), child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int widgetAddEventHandlerImpl(widget *self, eventType type, callback handler)
|
||||||
|
{
|
||||||
|
eventTableEntry *entry = malloc(sizeof(eventTableEntry));
|
||||||
|
|
||||||
|
entry->type = type;
|
||||||
|
entry->callback = handler;
|
||||||
|
|
||||||
|
// Add the handler to the table
|
||||||
|
vectorAdd(self->eventVtbl, entry);
|
||||||
|
|
||||||
|
// Offset = size - 1
|
||||||
|
return vectorSize(self->eventVtbl) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void widgetRemoveEventHandlerImpl(widget *self, int id)
|
||||||
|
{
|
||||||
|
vectorRemoveAt(self->eventVtbl, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool widgetFireCallbacksImpl(widget *self, event *evt)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < vectorSize(self->eventVtbl); i++)
|
||||||
|
{
|
||||||
|
eventTableEntry *handler = vectorAt(self->eventVtbl, i);
|
||||||
|
|
||||||
|
if (handler->type == evt->type)
|
||||||
|
{
|
||||||
|
handler->callback(self, evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXIME
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void widgetEnableImpl(widget *self)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// First make sure our parent is enabled
|
||||||
|
if (self->parent && !self->parent->isEnabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable ourself
|
||||||
|
self->isEnabled = true;
|
||||||
|
|
||||||
|
// Enable all of our children
|
||||||
|
for (i = 0; i < vectorSize(self->children); i++)
|
||||||
|
{
|
||||||
|
widgetEnable(WIDGET(vectorAt(self->children, i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void widgetDisableImpl(widget *self)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// If we are currently disabled, return
|
||||||
|
if (!self->isEnabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable ourself
|
||||||
|
self->isEnabled = false;
|
||||||
|
|
||||||
|
// Disable our children
|
||||||
|
for (i = 0; i < vectorSize(self->children); i++)
|
||||||
|
{
|
||||||
|
widgetDisable(WIDGET(vectorAt(self->children, i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void widgetFocusImpl(widget *self)
|
||||||
|
{
|
||||||
|
// Check that we are not currently focused
|
||||||
|
if (self->hasFocus)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Blur any of our currently focused child widgets
|
||||||
|
for (i = 0; i < vectorSize(self->children); i++)
|
||||||
|
{
|
||||||
|
widget *child = vectorAt(self->children, i);
|
||||||
|
|
||||||
|
if (child->hasFocus)
|
||||||
|
{
|
||||||
|
widgetBlur(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a parent, focus it
|
||||||
|
if (self->parent)
|
||||||
|
{
|
||||||
|
widgetFocus(self->parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Focus ourself
|
||||||
|
self->hasFocus = true;
|
||||||
|
|
||||||
|
// Fire our on-focus callbacks
|
||||||
|
event evt;
|
||||||
|
evt.type = EVT_FOCUS;
|
||||||
|
widgetFireCallbacks(self, &evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void widgetBlurImpl(widget *self)
|
||||||
|
{
|
||||||
|
widget *current;
|
||||||
|
|
||||||
|
// First blur any focused child widgets
|
||||||
|
while ((current = widgetGetCurrentlyFocused(self)) != self)
|
||||||
|
{
|
||||||
|
widgetBlur(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blur ourself
|
||||||
|
self->hasFocus = false;
|
||||||
|
|
||||||
|
// Fire off the on-blur callbacks
|
||||||
|
event evt;
|
||||||
|
evt.type = EVT_BLUR;
|
||||||
|
widgetFireCallbacks(self, &evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
widget *widgetGetCurrentlyFocused(widget *self)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!self->hasFocus)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < vectorSize(self->children); i++)
|
||||||
|
{
|
||||||
|
widget *child = vectorAt(self->children, i);
|
||||||
|
|
||||||
|
if (child->hasFocus)
|
||||||
|
{
|
||||||
|
return widgetGetCurrentlyFocused(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// None of our children are focused, return ourself
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool widgetHandleEventImpl(widget *self, event *evt)
|
||||||
|
{
|
||||||
|
switch (evt->type)
|
||||||
|
{
|
||||||
|
case EVT_MOUSE_MOVE:
|
||||||
|
{
|
||||||
|
eventMouse evtMouse = *((eventMouse *) evt);
|
||||||
|
bool newHasMouse = pointInRect(evtMouse.loc, self->bounds);
|
||||||
|
|
||||||
|
// If we have just `got' the mouse
|
||||||
|
if (newHasMouse && !self->hasMouse)
|
||||||
|
{
|
||||||
|
// Generate a EVT_MOUSE_ENTER event
|
||||||
|
evtMouse.event.type = EVT_MOUSE_ENTER;
|
||||||
|
|
||||||
|
// Fire the event handler
|
||||||
|
widgetFireCallbacks(self, (event *) &evtMouse);
|
||||||
|
}
|
||||||
|
// If we have just lost the mouse
|
||||||
|
else if (!newHasMouse && self->hasMouse)
|
||||||
|
{
|
||||||
|
// Generate a EVT_MOUSE_LEAVE event
|
||||||
|
evtMouse.event.type = EVT_MOUSE_LEAVE;
|
||||||
|
|
||||||
|
// Fire the handler
|
||||||
|
widgetFireCallbacks(self, (event *) &evtMouse);
|
||||||
|
}
|
||||||
|
// We had and still have the mouse
|
||||||
|
else if (newHasMouse && self->hasMouse)
|
||||||
|
{
|
||||||
|
// Pass the event as-is
|
||||||
|
widgetFireCallbacks(self, (event *) &evtMouse);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the status of the mouse
|
||||||
|
self->hasMouse = newHasMouse;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool widgetAddChild(widget *self, widget *child)
|
||||||
|
{
|
||||||
|
return WIDGET_GET_VTBL(self)->addChild(self, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
void widgetRemoveChild(widget *self, widget *child)
|
||||||
|
{
|
||||||
|
WIDGET_GET_VTBL(self)->removeChild(self, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
int widgetAddEventHandler(widget *self, eventType type, callback handler)
|
||||||
|
{
|
||||||
|
return WIDGET_GET_VTBL(self)->addEventHandler(self, type, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void widgetRemoveEventHandler(widget *self, int id)
|
||||||
|
{
|
||||||
|
WIDGET_GET_VTBL(self)->removeEventHandler(self, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool widgetFireCallbacks(widget *self, event *evt)
|
||||||
|
{
|
||||||
|
return WIDGET_GET_VTBL(self)->fireCallbacks(self, evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void widgetEnable(widget *self)
|
||||||
|
{
|
||||||
|
WIDGET_GET_VTBL(self)->enable(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
void widgetDisable(widget *self)
|
||||||
|
{
|
||||||
|
WIDGET_GET_VTBL(self)->disable(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
void widgetFocus(widget *self)
|
||||||
|
{
|
||||||
|
WIDGET_GET_VTBL(self)->focus(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
void widgetBlur(widget *self)
|
||||||
|
{
|
||||||
|
WIDGET_GET_VTBL(self)->blur(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
void widgetDoDraw(widget *self, cairo_t *cr)
|
||||||
|
{
|
||||||
|
WIDGET_GET_VTBL(self)->doDraw(self, cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool widgetHandleEvent(widget *self, event *evt)
|
||||||
|
{
|
||||||
|
return WIDGET_GET_VTBL(self)->handleEvent(self, evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void widgetDestroy(widget *self)
|
||||||
|
{
|
||||||
|
return WIDGET_GET_VTBL(self)->destroy(self);
|
||||||
|
}
|
|
@ -0,0 +1,348 @@
|
||||||
|
#ifndef WIDGET_H_
|
||||||
|
#define WIDGET_H_
|
||||||
|
|
||||||
|
#include <cairo.h>
|
||||||
|
|
||||||
|
#include "vector.h"
|
||||||
|
#include "geom.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Forward declarations
|
||||||
|
*/
|
||||||
|
typedef struct _widget widget;
|
||||||
|
typedef struct _widgetVtbl widgetVtbl;
|
||||||
|
|
||||||
|
typedef enum _eventType eventType;
|
||||||
|
typedef enum _mouseButton mouseButton;
|
||||||
|
|
||||||
|
typedef struct _event event;
|
||||||
|
typedef struct _eventMouse eventMouse;
|
||||||
|
typedef struct _eventMouseBtn eventMouseBtn;
|
||||||
|
typedef struct _eventKey eventKey;
|
||||||
|
typedef struct _eventMisc eventMisc;
|
||||||
|
|
||||||
|
typedef bool (*callback) (widget *widget, event *evt);
|
||||||
|
|
||||||
|
typedef struct _eventTableEntry eventTableEntry;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The valid event types
|
||||||
|
*/
|
||||||
|
enum _eventType
|
||||||
|
{
|
||||||
|
// Mouse events
|
||||||
|
EVT_MOUSE_DOWN,
|
||||||
|
EVT_MOUSE_UP,
|
||||||
|
EVT_MOUSE_CLICK,
|
||||||
|
|
||||||
|
EVT_MOUSE_ENTER,
|
||||||
|
EVT_MOUSE_MOVE,
|
||||||
|
EVT_MOUSE_LEAVE,
|
||||||
|
|
||||||
|
// Keyboard events
|
||||||
|
EVT_KEY_DOWN,
|
||||||
|
EVT_KEY_UP,
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
EVT_FOCUS,
|
||||||
|
EVT_BLUR
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The possible mouse states as understood by the events system
|
||||||
|
*/
|
||||||
|
enum _mouseButton
|
||||||
|
{
|
||||||
|
BUTTON_LEFT,
|
||||||
|
BUTTON_RIGHT,
|
||||||
|
BUTTON_OTHER
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Event structures
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The 'base' event structure. All events can be cast to this
|
||||||
|
*/
|
||||||
|
struct _event
|
||||||
|
{
|
||||||
|
// The time at which the event took place
|
||||||
|
int time;
|
||||||
|
|
||||||
|
// The type of the event
|
||||||
|
eventType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The event structure used for mouse motion events
|
||||||
|
*/
|
||||||
|
struct _eventMouse
|
||||||
|
{
|
||||||
|
event event;
|
||||||
|
|
||||||
|
// Location of the event
|
||||||
|
point loc;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The event structure used for mouse button events
|
||||||
|
*/
|
||||||
|
struct _eventMouseBtn
|
||||||
|
{
|
||||||
|
event event;
|
||||||
|
|
||||||
|
// Location
|
||||||
|
point loc;
|
||||||
|
|
||||||
|
// Button pressed
|
||||||
|
mouseButton button;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The event structure used for keyboard events
|
||||||
|
*/
|
||||||
|
struct _eventKey
|
||||||
|
{
|
||||||
|
event event;
|
||||||
|
|
||||||
|
// The key which was pressed
|
||||||
|
int key;
|
||||||
|
|
||||||
|
// Active modifier keys
|
||||||
|
bool ctrl;
|
||||||
|
bool shift;
|
||||||
|
bool alt;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct _eventMisc
|
||||||
|
{
|
||||||
|
event event;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Event table structure
|
||||||
|
*/
|
||||||
|
struct _eventTableEntry
|
||||||
|
{
|
||||||
|
eventType type;
|
||||||
|
callback callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The widget classes virtual method table.
|
||||||
|
*/
|
||||||
|
struct _widgetVtbl
|
||||||
|
{
|
||||||
|
bool (*handleEvent) (widget *self, event *evt);
|
||||||
|
|
||||||
|
bool (*addChild) (widget *self, widget *child);
|
||||||
|
void (*removeChild) (widget *self, widget *child);
|
||||||
|
|
||||||
|
bool (*fireCallbacks) (widget *self, event *evt);
|
||||||
|
int (*addEventHandler) (widget *self, eventType type, callback handler);
|
||||||
|
void (*removeEventHandler) (widget *self, int id);
|
||||||
|
|
||||||
|
void (*focus) (widget *self);
|
||||||
|
void (*blur) (widget *self);
|
||||||
|
|
||||||
|
void (*enable) (widget *self);
|
||||||
|
void (*disable) (widget *self);
|
||||||
|
|
||||||
|
void (*doDraw) (widget *self, cairo_t *cr);
|
||||||
|
|
||||||
|
void (*destroy) (widget *self);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct _widget
|
||||||
|
{
|
||||||
|
//--------------------------------------
|
||||||
|
// Private/protected members
|
||||||
|
//--------------------------------------
|
||||||
|
widgetVtbl *vtbl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The list of registered event handlers.
|
||||||
|
*/
|
||||||
|
vector *eventVtbl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The child widgets of ourself.
|
||||||
|
*/
|
||||||
|
vector *children;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The widgets parent widget.
|
||||||
|
*/
|
||||||
|
widget *parent;
|
||||||
|
|
||||||
|
//--------------------------------------
|
||||||
|
// Public members
|
||||||
|
//--------------------------------------
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The id of the widget
|
||||||
|
*/
|
||||||
|
char *id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arbitary user-defined data
|
||||||
|
*/
|
||||||
|
void *pUserData;
|
||||||
|
int userData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The origin and size of the widget
|
||||||
|
*/
|
||||||
|
rect bounds;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the widget currently has keyboard focus
|
||||||
|
*/
|
||||||
|
bool hasFocus;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the mouse is currently over the widget
|
||||||
|
*/
|
||||||
|
bool hasMouse;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the widget is currently enabled or not
|
||||||
|
*/
|
||||||
|
bool isEnabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper macros
|
||||||
|
*/
|
||||||
|
#define WIDGET(self) ((widget *) (self))
|
||||||
|
#define WIDGET_GET_VTBL(self) ((WIDGET(self))->vtbl)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Protected methods
|
||||||
|
*/
|
||||||
|
void widgetInit(widget *instance, const char *id);
|
||||||
|
void widgetDestroyImpl(widget *instance);
|
||||||
|
bool widgetAddChildImpl(widget *self, widget *child);
|
||||||
|
void widgetRemoveChildImpl(widget *self, widget *child);
|
||||||
|
bool widgetFireCallbacksImpl(widget *self, event *evt);
|
||||||
|
int widgetAddEventHandlerImpl(widget *self, eventType type, callback handler);
|
||||||
|
void widgetRemoveEventHandlerImpl(widget *self, int id);
|
||||||
|
void widgetEnableImpl(widget *self);
|
||||||
|
void widgetDisableImpl(widget *self);
|
||||||
|
void widgetFocusImpl(widget *self);
|
||||||
|
void widgetBlurImpl(widget *self);
|
||||||
|
|
||||||
|
bool widgetHandleEventImpl(widget *instance, event *evt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Public methods
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the widget along with its child widgets.
|
||||||
|
*/
|
||||||
|
void widgetDraw(widget *self, cairo_t *cr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively searches the child widgets of self for a widget whose ->id is
|
||||||
|
* id. If no widget with such an id exists NULL is returned.
|
||||||
|
*/
|
||||||
|
widget *widgetFindById(widget *self, const char *id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transverses up the hierarchy until it finds parent-less widget (known as
|
||||||
|
* the root widget). A pointer to this widget is returned.
|
||||||
|
*/
|
||||||
|
widget *windgetGetRoot(widget *self);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool widgetAddChild(widget *self, widget *child);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void widgetRemoveChild(widget *self, widget *child);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int widgetAddEventHandler(widget *self, eventType type, callback handler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void widgetRemoveEventHandler(widget *self, int id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables the current widget along with all of its child widgets. If the
|
||||||
|
* widget is currently enabled but one or more of its child widgets are not
|
||||||
|
* then they will also be enabled.
|
||||||
|
*
|
||||||
|
* If, however, the parent widget is disabled then this method is effectively
|
||||||
|
* a no-op.
|
||||||
|
*/
|
||||||
|
void widgetEnable(widget *self);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables the current widget along with all of its child widgets. If the
|
||||||
|
* widget is currently disabled then this method is a no-op.
|
||||||
|
*/
|
||||||
|
void widgetDisable(widget *self);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the widget and frees *all* memory associated with it.
|
||||||
|
*/
|
||||||
|
void widgetDestroy(widget *self);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a pointer to the widget furthest down the hierarchy which currently
|
||||||
|
* has focus. If self does not currently have focus then NULL is returned.
|
||||||
|
* Should none of self's child widgets have focus (but it does) then self is
|
||||||
|
* returned.
|
||||||
|
*/
|
||||||
|
widget *widgetGetCurrentlyFocused(widget *self);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the widget is capable of holding keyboard focus and does not currently
|
||||||
|
* hold it then this method should bring the widget into focus.
|
||||||
|
*
|
||||||
|
* This method will call the blur() method of the root widget first.
|
||||||
|
*/
|
||||||
|
void widgetFocus(widget *self);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blurs the current widget (removes keyboard focus from it) and fires the
|
||||||
|
* EVT_BLUR event handlers for affected widgets.
|
||||||
|
*/
|
||||||
|
void widgetBlur(widget *self);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool widgetHandleEvent(widget *self, event *evt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool widgetFireCallbacks(widget *self, event *evt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Protected methods
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void widgetDoDraw(widget *self, cairo_t *cr);
|
||||||
|
|
||||||
|
#endif /*WIDGET_H_*/
|
Loading…
Reference in New Issue