Created
May 16, 2012 14:15
-
-
Save airways/2710671 to your computer and use it in GitHub Desktop.
Base widget methods for Allegro 5 (source unknown)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "widget.h" | |
//total event controllers | |
#define MAX_EVENT_CONTROLLERS 10 | |
//event controller | |
typedef struct EVENT_CONTROLLER | |
{ | |
ALGUI_EVENT_CONTROLLER_PROC proc; | |
void *data; | |
} EVENT_CONTROLLER; | |
//event controllers | |
static EVENT_CONTROLLER event_controllers[MAX_EVENT_CONTROLLERS] = | |
{ | |
{ algui_default_event_controller_proc, 0 } | |
}; | |
static int current_event_controller = 0; | |
//return min from two integers | |
static int min_(int x, int y) | |
{ | |
return x < y ? x : y; | |
} | |
//return max from two integers | |
static int max_(int x, int y) | |
{ | |
return x > y ? x : y; | |
} | |
//send the message 'SET_PREFERRED_SIZE' to children first, then to parents. | |
static void set_preferred_size(ALGUI_WIDGET *wgt) | |
{ | |
ALGUI_WIDGET *child; | |
if (wgt->geometry_altered_in_tree) | |
{ | |
wgt->geometry_altered_in_tree = 0; | |
for(child = wgt->first; child; child = child->next) | |
{ | |
set_preferred_size(child); | |
wgt->geometry_altered |= child->geometry_altered; | |
wgt->geometry_altered_in_tree |= | |
child->geometry_altered | child->geometry_altered_in_tree; | |
} | |
} | |
if (wgt->geometry_altered) | |
{ | |
int w = wgt->width, h = wgt->height; | |
algui_send_message(wgt, ALGUI_MSG_SET_PREFERRED_SIZE, NULL); | |
wgt->geometry_altered = wgt->width != w || wgt->height != h; | |
} | |
} | |
//sends the message 'DO LAYOUT' to parents first, then to children. | |
static void do_layout(ALGUI_WIDGET *wgt) | |
{ | |
ALGUI_WIDGET *child; | |
if (wgt->geometry_altered) | |
{ | |
algui_send_message(wgt, ALGUI_MSG_DO_LAYOUT, NULL); | |
} | |
if (wgt->geometry_altered_in_tree) | |
{ | |
wgt->geometry_altered_in_tree = 0; | |
for(child = wgt->first; child; child = child->next) | |
{ | |
do_layout(child); | |
} | |
} | |
} | |
//recursively draws widgets | |
static void draw_widget( | |
ALGUI_WIDGET *wgt, | |
ALLEGRO_BITMAP *parent, | |
int cl, | |
int ct, | |
int cr, | |
int cb, | |
int reconstruct_bitmap) | |
{ | |
ALGUI_WIDGET *child; | |
//reconstruct the widget's bitmap if the geometry is altered | |
reconstruct_bitmap |= wgt->geometry_altered || wgt->bitmap == NULL; | |
wgt->geometry_altered = 0; | |
//reconstruct the widget's bitmap, if needed | |
if (reconstruct_bitmap) | |
{ | |
al_destroy_bitmap(wgt->bitmap); | |
wgt->bitmap = al_create_sub_bitmap( | |
parent, | |
wgt->x, | |
wgt->y, | |
wgt->width, | |
wgt->height); | |
} | |
//clip the output to the parent | |
cl = max_(cl, wgt->x); | |
ct = max_(ct, wgt->y); | |
//cr = min_(cr, wgt->x + wgt->width - 1); | |
//cb = min_(cb, wgt->y + wgt->height - 1); | |
//make the clipping local to the widget | |
cl -= wgt->x; | |
ct -= wgt->y; | |
//cr -= wgt->x; | |
//cb -= wgt->y; | |
//cr = wgt->width; | |
//cb = wgt->height; | |
//paint widget only if widget is visible | |
if (wgt->visible) | |
{ | |
//set the target bitmap and clipping to the one used by the widget | |
al_set_target_bitmap(wgt->bitmap); | |
//al_set_clipping_rectangle(cl, ct, wgt->width, wgt->height); | |
//paint the widget | |
algui_send_message(wgt, ALGUI_MSG_PAINT, NULL); | |
} | |
//paint the children | |
for(child = wgt->first; child; child = child->next) | |
{ | |
draw_widget(child, wgt->bitmap, cl, ct, wgt->width, wgt->height, reconstruct_bitmap); | |
} | |
} | |
//visit the tree and apply the given function to each widget | |
static void visit_tree(ALGUI_WIDGET *wgt, void (*proc)(ALGUI_WIDGET *)) | |
{ | |
ALGUI_WIDGET *child; | |
proc(wgt); | |
for(child = wgt->first; child; child = child->next) | |
{ | |
visit_tree(child, proc); | |
} | |
} | |
//sets the enabled tree flag | |
static void set_enabled_tree_proc(ALGUI_WIDGET *wgt) | |
{ | |
wgt->enabled_tree = wgt->enabled && (!wgt->parent || wgt->parent->enabled_tree); | |
} | |
//sets the enabled tree flag. | |
static void set_enabled_tree(ALGUI_WIDGET *wgt) | |
{ | |
visit_tree(wgt, set_enabled_tree_proc); | |
} | |
//resets the flags of the widget | |
static void reset_flags_proc(ALGUI_WIDGET *wgt) | |
{ | |
set_enabled_tree_proc(wgt); | |
wgt->geometry_altered = 1; | |
wgt->geometry_altered_in_tree = 1; | |
wgt->has_focus = 0; | |
wgt->has_mouse = 0; | |
} | |
//resets the flags of each widget in the tree. | |
static void reset_flags(ALGUI_WIDGET *wgt) | |
{ | |
visit_tree(wgt, reset_flags_proc); | |
} | |
//removes a widget from its parent | |
static void remove_widget(ALGUI_WIDGET *par, ALGUI_WIDGET *child) | |
{ | |
//remove from tree | |
ALGUI_WIDGET *prev = child->prev; | |
ALGUI_WIDGET *next = child->next; | |
if (prev) prev->next = next; else par->first = next; | |
if (next) next->prev = prev; else par->last = prev; | |
child->parent = child->prev = child->next = NULL; | |
//set the enabled tree flag of the child tree | |
reset_flags(child); | |
//mark the parent for geometry management | |
algui_mark_widget_for_geometry_management(par); | |
} | |
//remove focus from widget | |
static int lose_focus(ALGUI_WIDGET *wgt) | |
{ | |
wgt->has_focus = 0; | |
return 1; | |
} | |
//set focus to widget | |
static int get_focus(ALGUI_WIDGET *wgt) | |
{ | |
//the widget already has the input focus | |
if (wgt->has_focus) return 1; | |
//remove the focus from the previous focus owner | |
ALGUI_WIDGET *root = algui_get_root_widget(wgt); | |
ALGUI_WIDGET *prev_focus = algui_get_focus_widget(root); | |
if (prev_focus && !algui_send_message(prev_focus, ALGUI_MSG_LOSE_FOCUS, NULL)) | |
{ | |
return 0; | |
} | |
//set the focus to the widget | |
wgt->has_focus = 1; | |
return 1; | |
} | |
//send key down event to widget with focus | |
static int key_down(ALGUI_WIDGET *wgt, ALLEGRO_EVENT *ev) | |
{ | |
ALGUI_WIDGET *focus = algui_get_focus_widget(wgt); | |
if (focus && !focus->enabled_tree) | |
{ | |
return 0; | |
} | |
return algui_send_message(focus, ALGUI_MSG_KEY_DOWN, ev); | |
} | |
//send key up event to widget with focus | |
static int key_up(ALGUI_WIDGET *wgt, ALLEGRO_EVENT *ev) | |
{ | |
ALGUI_WIDGET *focus = algui_get_focus_widget(wgt); | |
if (!focus || !focus->enabled_tree) | |
{ | |
return 0; | |
} | |
return algui_send_message(focus, ALGUI_MSG_KEY_UP, ev); | |
} | |
//unused key char | |
static int unused_key_char(ALGUI_WIDGET *wgt, ALLEGRO_EVENT *ev) | |
{ | |
//the widget must be enabled | |
if (!wgt->enabled_tree) | |
{ | |
return 0; | |
} | |
//if the widget processes the unused key char, stop | |
if (algui_send_message(wgt, ALGUI_MSG_UNUSED_KEY_CHAR, ev)) | |
{ | |
return 1; | |
} | |
//pass the event to children | |
ALGUI_WIDGET *child; | |
for(child = wgt->first; child; child = child->next) | |
{ | |
if (unused_key_char(child, ev)) | |
{ | |
return 1; | |
} | |
} | |
//unused key not processed | |
return 0; | |
} | |
//send key char event to widget with focus; | |
//if that fails, broadcast the unused char message to all widgets. | |
static int key_char(ALGUI_WIDGET *wgt, ALLEGRO_EVENT *ev) | |
{ | |
ALGUI_WIDGET *focus = algui_get_focus_widget(wgt); | |
//if there is an enabled focus widget, send it the message | |
if (focus && | |
focus->enabled_tree && | |
algui_send_message(wgt, ALGUI_MSG_KEY_CHAR, ev)) | |
{ | |
return 1; | |
} | |
return unused_key_char(wgt, ev); | |
} | |
//find the widget with the mouse flag set | |
static ALGUI_WIDGET *old_mouse_widget(ALGUI_WIDGET *wgt) | |
{ | |
if (wgt->has_mouse) return wgt; | |
ALGUI_WIDGET *child, *res; | |
for(child = wgt->last; child; child = child->prev) | |
{ | |
res = old_mouse_widget(child); | |
if (res) return res; | |
} | |
return NULL; | |
} | |
//find the widget under the given coordinates | |
static ALGUI_WIDGET *new_mouse_widget(ALGUI_WIDGET *wgt, int x, int y) | |
{ | |
x -= wgt->x; | |
y -= wgt->y; | |
if (!wgt->visible || x < 0 || x >= wgt->width || y < 0 || y >= wgt->height) | |
{ | |
return NULL; | |
} | |
ALGUI_WIDGET *child, *res; | |
for(child = wgt->last; child; child = child->prev) | |
{ | |
res = new_mouse_widget(child, x, y); | |
if (res) return res; | |
} | |
return wgt; | |
} | |
//maps an event's mouse coordinates to the coordinate space of a widget | |
static void map_event_coords_to_widget(ALGUI_WIDGET *wgt, ALLEGRO_EVENT *ev) | |
{ | |
algui_map_coords( | |
NULL, | |
ev->mouse.x, | |
ev->mouse.y, | |
wgt, | |
&ev->mouse.x, | |
&ev->mouse.y); | |
} | |
//handle mouse move | |
static int mouse_move(ALGUI_WIDGET *wgt, ALLEGRO_EVENT *ev) | |
{ | |
int processed = 0; | |
int mouse_x = ev->mouse.x; | |
int mouse_y = ev->mouse.y; | |
//find the previous and new mouse widgets | |
ALGUI_WIDGET *old_mouse = old_mouse_widget(wgt); | |
ALGUI_WIDGET *new_mouse = new_mouse_widget(wgt, ev->mouse.x, ev->mouse.y); | |
//if the mouse didn't change widgets, then send a mouse move | |
if (new_mouse == old_mouse) | |
{ | |
if (new_mouse && new_mouse->enabled_tree) | |
{ | |
map_event_coords_to_widget(new_mouse, ev); | |
processed |= algui_send_message(new_mouse, ALGUI_MSG_MOUSE_MOVE, ev); | |
ev->mouse.x = mouse_x; | |
ev->mouse.y = mouse_y; | |
} | |
} | |
//else send mouse enter/leave | |
else | |
{ | |
if (old_mouse && old_mouse->enabled_tree) | |
{ | |
old_mouse->has_mouse = 0; | |
map_event_coords_to_widget(old_mouse, ev); | |
processed |= algui_send_message(old_mouse, ALGUI_MSG_MOUSE_LEAVE, ev); | |
ev->mouse.x = mouse_x; | |
ev->mouse.y = mouse_y; | |
} | |
if (new_mouse && new_mouse->enabled_tree) | |
{ | |
new_mouse->has_mouse = 1; | |
map_event_coords_to_widget(new_mouse, ev); | |
processed |= algui_send_message(new_mouse, ALGUI_MSG_MOUSE_ENTER, ev); | |
ev->mouse.x = mouse_x; | |
ev->mouse.y = mouse_y; | |
} | |
} | |
return processed; | |
} | |
//handles the mouse wheel event | |
static int mouse_wheel(ALGUI_WIDGET *wgt, ALLEGRO_EVENT *ev) | |
{ | |
ALGUI_WIDGET *focus = algui_get_focus_widget(wgt); | |
if (!focus || !focus->enabled_tree) | |
{ | |
return 0; | |
} | |
int mouse_x = ev->mouse.x; | |
int mouse_y = ev->mouse.y; | |
map_event_coords_to_widget(focus, ev); | |
int res = algui_send_message(focus, ALGUI_MSG_MOUSE_WHEEL, ev); | |
ev->mouse.x = mouse_x; | |
ev->mouse.y = mouse_y; | |
return res; | |
} | |
//handle the mouse axes event | |
static int mouse_axes(ALGUI_WIDGET *wgt, ALLEGRO_EVENT *ev) | |
{ | |
int processed = 0; | |
//handle move | |
if (ev->mouse.dx || ev->mouse.dy) | |
{ | |
processed |= mouse_move(wgt, ev); | |
} | |
//handle wheel | |
if (ev->mouse.dw || ev->mouse.dz) | |
{ | |
processed |= mouse_wheel(wgt, ev); | |
} | |
return processed; | |
} | |
//mouse button | |
static int mouse_button( | |
ALGUI_WIDGET *wgt, | |
ALLEGRO_EVENT *ev, | |
int left_msg, | |
int right_msg, | |
int middle_msg) | |
{ | |
ALGUI_WIDGET *new_mouse = new_mouse_widget(wgt, ev->mouse.x, ev->mouse.y); | |
if (!new_mouse || !new_mouse->enabled_tree) | |
{ | |
return 0; | |
} | |
int res; | |
int mouse_x = ev->mouse.x; | |
int mouse_y = ev->mouse.y; | |
map_event_coords_to_widget(new_mouse, ev); | |
new_mouse->has_mouse = 1; | |
switch (ev->mouse.button) | |
{ | |
case 1: | |
res = algui_send_message(new_mouse, left_msg, ev); | |
break; | |
case 2: | |
res = algui_send_message(new_mouse, right_msg, ev); | |
break; | |
case 3: | |
res = algui_send_message(new_mouse, middle_msg, ev); | |
break; | |
default: | |
res = 0; | |
} | |
ev->mouse.x = mouse_x; | |
ev->mouse.y = mouse_y; | |
return res; | |
} | |
//mouse button down | |
static int mouse_button_down(ALGUI_WIDGET *wgt, ALLEGRO_EVENT *ev) | |
{ | |
return mouse_button( | |
wgt, | |
ev, | |
ALGUI_MSG_LEFT_BUTTON_DOWN, | |
ALGUI_MSG_RIGHT_BUTTON_DOWN, | |
ALGUI_MSG_MIDDLE_BUTTON_DOWN); | |
} | |
//mouse button down | |
static int mouse_button_up(ALGUI_WIDGET *wgt, ALLEGRO_EVENT *ev) | |
{ | |
return mouse_button( | |
wgt, | |
ev, | |
ALGUI_MSG_LEFT_BUTTON_UP, | |
ALGUI_MSG_RIGHT_BUTTON_UP, | |
ALGUI_MSG_MIDDLE_BUTTON_UP); | |
} | |
//handle mouse enter | |
static int mouse_enter(ALGUI_WIDGET *wgt, ALLEGRO_EVENT *ev) | |
{ | |
ALGUI_WIDGET *new_mouse = new_mouse_widget(wgt, ev->mouse.x, ev->mouse.y); | |
if (!new_mouse || !new_mouse->enabled_tree) | |
{ | |
return 0; | |
} | |
int mouse_x = ev->mouse.x; | |
int mouse_y = ev->mouse.y; | |
map_event_coords_to_widget(new_mouse, ev); | |
new_mouse->has_mouse = 1; | |
int res = algui_send_message(new_mouse, ALGUI_MSG_MOUSE_ENTER, ev); | |
ev->mouse.x = mouse_x; | |
ev->mouse.y = mouse_y; | |
return res; | |
} | |
//handle mouse leave | |
static int mouse_leave(ALGUI_WIDGET *wgt, ALLEGRO_EVENT *ev) | |
{ | |
ALGUI_WIDGET *old_mouse = old_mouse_widget(wgt); | |
if (!old_mouse || !old_mouse->enabled_tree) | |
{ | |
return 0; | |
} | |
int mouse_x = ev->mouse.x; | |
int mouse_y = ev->mouse.y; | |
map_event_coords_to_widget(old_mouse, ev); | |
old_mouse->has_mouse = 0; | |
int res = algui_send_message(old_mouse, ALGUI_MSG_MOUSE_LEAVE, ev); | |
ev->mouse.x = mouse_x; | |
ev->mouse.y = mouse_y; | |
return res; | |
} | |
//handle a timer message | |
static int timer(ALGUI_WIDGET *wgt, ALLEGRO_EVENT *ev) | |
{ | |
if (!wgt->enabled_tree) | |
{ | |
return 0; | |
} | |
int processed = algui_send_message(wgt, ALGUI_MSG_TIMER, ev); | |
ALGUI_WIDGET *child; | |
for(child = wgt->first; child; child = child->next) | |
{ | |
processed |= timer(child, ev); | |
} | |
return processed; | |
} | |
//handle a display expose message | |
static int display_expose(ALGUI_WIDGET *wgt, ALLEGRO_EVENT *ev) | |
{ | |
algui_draw_widget_rect( | |
wgt, | |
ev->display.x - wgt->x, | |
ev->display.y - wgt->y, | |
ev->display.width, | |
ev->display.height); | |
return 1; | |
} | |
/****************************************************************************** | |
PUBLIC | |
******************************************************************************/ | |
//the default widget procedure. | |
int algui_default_widget_proc(ALGUI_WIDGET *wgt, int msg, void *data) | |
{ | |
switch (msg) | |
{ | |
case ALGUI_MSG_GET_FOCUS: | |
return get_focus(wgt); | |
case ALGUI_MSG_LOSE_FOCUS: | |
return lose_focus(wgt); | |
} | |
return 0; | |
} | |
//sends a message to a widget. | |
int algui_send_message(ALGUI_WIDGET *wgt, int msg, void *data) | |
{ | |
if(wgt) | |
{ | |
return wgt->proc(wgt, msg, data); | |
} else { | |
return 0; | |
} | |
} | |
//initializes a widget structure to default values. | |
void algui_init_widget(ALGUI_WIDGET *wgt) | |
{ | |
wgt->proc = algui_default_widget_proc; | |
wgt->parent = NULL; | |
wgt->prev = NULL; | |
wgt->next = NULL; | |
wgt->first = NULL; | |
wgt->last = NULL; | |
wgt->x = 0; | |
wgt->y = 0; | |
wgt->width = 0; | |
wgt->height = 0; | |
wgt->bitmap = NULL; | |
wgt->name = NULL; | |
wgt->visible = 1; | |
wgt->enabled = 1; | |
wgt->enabled_tree = 1; | |
wgt->geometry_altered = 1; | |
wgt->geometry_altered_in_tree = 1; | |
wgt->has_focus = 0; | |
wgt->has_mouse = 0; | |
} | |
//destroys each widget in the widget tree. | |
void algui_destroy_widget(ALGUI_WIDGET *wgt) | |
{ | |
// ALGUI_WIDGET *child; | |
//remove and destroy children | |
while(wgt->last) | |
{ | |
ALGUI_WIDGET *child = wgt->last; | |
remove_widget(wgt, child); | |
algui_destroy_widget(child); | |
} | |
//send the widget the cleanup message. | |
algui_send_message(wgt, ALGUI_MSG_CLEANUP, NULL); | |
//free memory | |
al_free(wgt); | |
} | |
//returns the root widget of the tree the given widget belongs. | |
ALGUI_WIDGET *algui_get_root_widget(ALGUI_WIDGET *wgt) | |
{ | |
for(; wgt->parent; wgt = wgt->parent); | |
return wgt; | |
} | |
//inserts a widget into another widget. | |
int algui_insert_widget( | |
ALGUI_WIDGET *par, | |
ALGUI_WIDGET *child, | |
ALGUI_WIDGET *next) | |
{ | |
ALGUI_WIDGET *prev; | |
//check parameters | |
if (child->parent || child == par || (next && next->parent != par)) | |
{ | |
return 0; | |
} | |
prev = next ? next->prev : par->last; | |
//insert widget | |
if (prev) prev->next = child; else par->first = child; | |
if (next) next->prev = child; else par->last = child; | |
child->parent = par; | |
child->prev = prev; | |
child->next = next; | |
//reset the flags in the child tree | |
reset_flags(child); | |
//flag the parent widget as having altered geometry so as that geometry is | |
//negotiated later | |
algui_mark_widget_for_geometry_management(par); | |
//success | |
return 1; | |
} | |
//Same as 'algui_insert_widget(par, child, NULL). | |
int algui_add_widget(ALGUI_WIDGET *par, ALGUI_WIDGET *child) | |
{ | |
return algui_insert_widget(par, child, NULL); | |
} | |
//detaches a widget from its parent, if there is one. | |
void algui_detach_widget(ALGUI_WIDGET *wgt) | |
{ | |
if (wgt->parent) remove_widget(wgt->parent, wgt); | |
} | |
//sets the position and size of a widget. | |
void algui_set_widget_geometry( | |
ALGUI_WIDGET *wgt, | |
int x, | |
int y, | |
int width, | |
int height) | |
{ | |
//limit position to sensible values | |
if (width < 0) width = 0; | |
if (height < 0) height = 0; | |
//check for change | |
if (x == wgt->x && | |
y == wgt->y && | |
width == wgt->width && | |
height == wgt->height) | |
{ | |
return; | |
} | |
//set new position | |
wgt->x = x; | |
wgt->y = y; | |
wgt->width = width; | |
wgt->height = height; | |
//flag the parent widget as having altered geometry so as that geometry is | |
//negotiated later | |
algui_mark_widget_for_geometry_management(wgt); | |
} | |
//flags the widget as needing geometry management. | |
void algui_mark_widget_for_geometry_management(ALGUI_WIDGET *wgt) | |
{ | |
ALGUI_WIDGET *par; | |
//if the widget is already flagged, do nothing else | |
if (wgt->geometry_altered) return; | |
//flag the widget | |
wgt->geometry_altered = 1; | |
//flag non-flagged ancestors, in order to limit calculations | |
//only to those widgets that are affected by the change | |
for(par = wgt->parent; | |
par && !par->geometry_altered_in_tree; | |
par = par->parent) | |
{ | |
par->geometry_altered_in_tree = 1; | |
} | |
} | |
//sets a widget visible or invisible. | |
void algui_set_widget_visible(ALGUI_WIDGET *wgt, int visible) | |
{ | |
if (visible == wgt->visible) return; | |
wgt->visible = visible; | |
if (wgt->parent) | |
{ | |
algui_mark_widget_for_geometry_management(wgt->parent); | |
} | |
} | |
//sets a widget enabled or disabled. | |
void algui_set_widget_enabled(ALGUI_WIDGET *wgt, int enabled) | |
{ | |
if (enabled == wgt->enabled) return; | |
wgt->enabled = enabled; | |
set_enabled_tree(wgt); | |
algui_mark_widget_for_geometry_management(wgt); | |
} | |
//draws part of a widget and its children. | |
void algui_draw_widget_rect(ALGUI_WIDGET *wgt, int x, int y, int width, int height) | |
{ | |
ALLEGRO_BITMAP *target; | |
int cx, cy, cw, ch; | |
//store the current target and clipping locally | |
target = al_get_target_bitmap(); | |
al_get_clipping_rectangle(&cx, &cy, &cw, &ch); | |
//manage the widget's geometry | |
set_preferred_size(wgt); | |
do_layout(wgt); | |
//make the given rectangle relative to the widget's target bitmap | |
x += wgt->x; | |
y += wgt->y; | |
//draw the widgets | |
draw_widget( | |
wgt, | |
target, | |
max_(x, 0), | |
max_(y, 0), | |
min_(x + width - 1 , al_get_bitmap_width(target) - 1), | |
min_(y + height - 1, al_get_bitmap_height(target) - 1), | |
0); | |
//restore the current target and clipping | |
al_set_target_bitmap(target); | |
al_set_clipping_rectangle(cx, cy, cw, ch); | |
} | |
//draws a widget and its children. | |
void algui_draw_widget(ALGUI_WIDGET *wgt) | |
{ | |
algui_draw_widget_rect(wgt, 0, 0, wgt->width, wgt->height); | |
} | |
//finds the widget in the tree that has the input focus. | |
ALGUI_WIDGET *algui_get_focus_widget(ALGUI_WIDGET *wgt) | |
{ | |
ALGUI_WIDGET *child, *res; | |
if (wgt->has_focus) return wgt; | |
for(child = wgt->first; child; child = child->next) | |
{ | |
res = algui_get_focus_widget(child); | |
if (res) return res; | |
} | |
return NULL; | |
} | |
//sends the message ALGUI_MSG_GET_FOCUS to the given widget. | |
int algui_set_focus_widget(ALGUI_WIDGET *wgt) | |
{ | |
return algui_send_message(wgt, ALGUI_MSG_GET_FOCUS, NULL); | |
} | |
//the default event controller procedure. | |
int algui_default_event_controller_proc( | |
ALGUI_WIDGET *root, | |
ALLEGRO_EVENT *event, | |
void *data) | |
{ | |
switch (event->type) | |
{ | |
case ALLEGRO_EVENT_JOYSTICK_AXIS: | |
//TODO | |
break; | |
case ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN: | |
//TODO | |
break; | |
case ALLEGRO_EVENT_JOYSTICK_BUTTON_UP: | |
//TODO | |
break; | |
case ALLEGRO_EVENT_KEY_DOWN: | |
return key_down(root, event); | |
case ALLEGRO_EVENT_KEY_UP: | |
return key_up(root, event); | |
case ALLEGRO_EVENT_KEY_CHAR: | |
return key_char(root, event); | |
case ALLEGRO_EVENT_MOUSE_AXES: | |
return mouse_axes(root, event); | |
case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: | |
return mouse_button_down(root, event); | |
case ALLEGRO_EVENT_MOUSE_BUTTON_UP: | |
return mouse_button_up(root, event); | |
case ALLEGRO_EVENT_MOUSE_WARPED: | |
return mouse_axes(root, event); | |
case ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY: | |
return mouse_enter(root, event); | |
case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY: | |
return mouse_leave(root, event); | |
case ALLEGRO_EVENT_TIMER: | |
return timer(root, event); | |
case ALLEGRO_EVENT_DISPLAY_EXPOSE: | |
return display_expose(root, event); | |
} | |
//event not processed | |
return 0; | |
} | |
//returns the current event controller. | |
ALGUI_EVENT_CONTROLLER_PROC algui_get_event_controller(void **data) | |
{ | |
if (current_event_controller < 0) | |
{ | |
if (data) *data = NULL; | |
return NULL; | |
} | |
if (data) *data = event_controllers[current_event_controller].proc; | |
return event_controllers[current_event_controller].proc; | |
} | |
//pushes an event controller in the event controller stack. | |
int algui_push_event_controller(ALGUI_EVENT_CONTROLLER_PROC proc, void *data) | |
{ | |
if (current_event_controller == MAX_EVENT_CONTROLLERS - 1) | |
{ | |
return 0; | |
} | |
++current_event_controller; | |
event_controllers[current_event_controller].proc = proc; | |
event_controllers[current_event_controller].data = data; | |
return 1; | |
} | |
//pops the current event controller. | |
int algui_pop_event_controller() | |
{ | |
if (current_event_controller < 0) | |
{ | |
return 0; | |
} | |
--current_event_controller; | |
return 1; | |
} | |
//dispatches the given ALLEGRO event to the appropriate widget, | |
int algui_dispatch_event(ALGUI_WIDGET *root, ALLEGRO_EVENT *event) | |
{ | |
if (current_event_controller < 0) | |
{ | |
return 0; | |
} | |
return event_controllers[current_event_controller].proc( | |
root, | |
event, | |
event_controllers[current_event_controller].data); | |
} | |
//map coordinates from one widget to another. | |
void algui_map_coords( | |
ALGUI_WIDGET *src, | |
int srcx, | |
int srcy, | |
ALGUI_WIDGET *dst, | |
int *dstx, | |
int *dsty) | |
{ | |
ALGUI_WIDGET *temp; | |
for(temp = src; temp; temp = temp->parent) | |
{ | |
srcx += temp->x; | |
srcy += temp->y; | |
} | |
for(temp = dst; temp; temp = temp->parent) | |
{ | |
srcx -= temp->x; | |
srcy -= temp->y; | |
} | |
*dstx = srcx; | |
*dsty = srcy; | |
} | |
void _hide(ALGUI_WIDGET *wgt) | |
{ | |
wgt->visible = 0; | |
} | |
void hide(ALGUI_WIDGET *wgt) | |
{ | |
visit_tree(wgt, _hide); | |
} | |
void _show(ALGUI_WIDGET *wgt) | |
{ | |
wgt->visible = 1; | |
} | |
void show(ALGUI_WIDGET *wgt) | |
{ | |
visit_tree(wgt, _show); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment