#ifndef WIDGET_H_ #define WIDGET_H_ #include #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, void *userData); 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_WHEEL_UP, BUTTON_WHELL_DOWN, 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, this should be used for text-input &c int unicode; // The keycode of the key which was pressed int keycode; // Active modifier keys bool ctrl; bool shift; bool alt; }; /* * */ struct _eventMisc { event event; }; /* * Event table structure */ struct _eventTableEntry { eventType type; callback callback; void *userData; }; /* * 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 *userData); 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 *userData); 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. * * @param self The widget to be drawn. * @param cr The cairo context the widget should draw itself on. */ 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. * * @param self The widget to start the search from. * @param id The id of the desired widget. * @return A pointer to the widget if found, NULL otherwise. */ 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. * * @param self The widget to find the root widget of. * @return A pointer to the root widget. */ widget *windgetGetRoot(widget *self); /** * Attempts to add child as a child widget of self. The exact location of the * widget (as well as its dimensions) are decided during an arbitration process * between the self and the child. * * @param self The widget to add the child widget to. * @param child The widget to be added. * @return true if child was successfully added, false otherwise. */ bool widgetAddChild(widget *self, widget *child); /** * Attempts to remove child from the list of child widgets. If the child widget * is found anywhere in the hierarchy it is removed and its destructor called. * * A convenient way of using this methid is as follows: * widgetRemoveChild(self, widgetFindById(self, "id_to_remove")); * * @param self The widget to remove child from. * @param child The child widget to remove. */ void widgetRemoveChild(widget *self, widget *child); /** * Adds handler to self's event handler table, registering it to respond to * events of type. An unique id is assigned to the event when it is added. This * id can be used at a later date to widgetRemoveEventHandler to remove the * event. * * The userData pointer is passed verbatim to handler via the userData * parameter. If no user data is required then NULL can be passed. * * It is perfectly legal for there to be multiple event handlers installed for * a single event type. When this is the case the event handlers are fired in * the order in which they were added. * * @param self The widget to add the event handler to. * @param type The type of event that handler should respond to. * @param handler The function to call when the event type fires. * @return The id of the newly added event. */ int widgetAddEventHandler(widget *self, eventType type, callback handler, void *userData); /** * Removes the event from the events table at offset id. * * @param self The widget to remove the event handler from. * @param id The id of the event to be removed. */ 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. * * @param self The widget to enable. */ 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. * * @param self The widget to disable. */ void widgetDisable(widget *self); /** * Destroys the widget and frees *all* memory associated with it. * * @param self The widget to destroy. */ 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. * * @param self The widget to get the further down focused child of. * @return A pointer to the widget, or NULL if self is not focused. */ widget *widgetGetCurrentlyFocused(widget *self); /** * If the widget is capable of holding keyboard focus and does not currently * hold it then this method will bring it into focus. Should ->parent not be * focused then widgetFocus(self->parent) will be called to focus it. * * This method will also blur any widgets which will no longer be in focus as a * result of self being focued. In addition it takes responsibility for firing * the EVT_FOCUS callbacks for self. * * @param self The widget to focus. */ void widgetFocus(widget *self); /** c * Blurs the current widget (removes keyboard focus from it). Before self is * blurred any child widget with focus is blurred first. Finally the EVT_BLUR * event handlers for self are fired. * * @param self The widget to blur. */ void widgetBlur(widget *self); /** * TODO */ bool widgetHandleEvent(widget *self, event *evt); /* * Protected methods */ /** * A protected `pure virtual' method which is called to draw the widget. The * cairo translation matrix is set-up such that (0,0) is the top-left of the * widget. * * @param self The widget that should draw itself. * @param cr The context to draw the widget to. */ void widgetDoDraw(widget *self, cairo_t *cr); /** * Fires all of the event handlers registered for evt->type on the widger self. * * @param self The widget to fire the callbacks on. * @param evt The event to fire the callbacks for. */ bool widgetFireCallbacks(widget *self, event *evt); #endif /*WIDGET_H_*/