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