/* Function: wz_ask_parent_for_focus Asks the parent to defocus everyone but the widget that calls this function. Returns: 1 if the widget already has focus, or succesfully obtained the focus 0 if the widget cannot be focused */ int wz_ask_parent_for_focus(WZ_WIDGET* wgt) { if(wgt->flags & WZ_STATE_HAS_FOCUS) return 1; if(wgt->flags & WZ_STATE_NOTWANT_FOCUS) return 0; if(wgt->flags & WZ_STATE_DISABLED) return 0; if(wgt->flags & WZ_STATE_HIDDEN) return 0; if(wgt->parent == 0) { ALLEGRO_EVENT event; wz_craft_event(&event, WZ_TAKE_FOCUS, wgt, 0); wz_send_event(wgt, &event); } else { ALLEGRO_EVENT event; if(!(wgt->parent->flags & WZ_STATE_HAS_FOCUS)) { wz_ask_parent_for_focus(wgt->parent); } wz_craft_event(&event, WZ_WANT_FOCUS, wgt, 0); wz_send_event(wgt->parent, &event); } return 1; }
/* Function: wz_update Updates the widget tree, call this every frame Doesn't update the disabled widgets Parameters: dt - Time that has passed since the last update */ void wz_update(WZ_WIDGET* wgt, double dt) { ALLEGRO_EVENT event; wz_craft_event(&event, WZ_UPDATE, 0, 0); wz_broadcast_event(wgt, &event); wz_craft_event(&event, WZ_UPDATE_POSITION, 0, 0); wz_broadcast_event(wgt, &event); }
/* Function: wz_enable Enables/disables the widget tree Parameters: enable - pass 1 to enable the widget tree, or 0 to disable it */ void wz_enable(WZ_WIDGET* wgt, int enable) { ALLEGRO_EVENT event; wz_craft_event(&event, enable ? WZ_ENABLE : WZ_DISABLE, 0, 0); wz_broadcast_event(wgt, &event); }
/* Function: wz_show Shows/hides the widget tree Parameters: show - pass 1 to show the widget tree, or 0 to hide it */ void wz_show(WZ_WIDGET* wgt, int show) { ALLEGRO_EVENT event; wz_craft_event(&event, show ? WZ_SHOW : WZ_HIDE, 0, 0); wz_broadcast_event(wgt, &event); }
/* Function: wz_destroy Destroys the widget tree. Call it to free all of the memory used by the widget tree. */ void wz_destroy(WZ_WIDGET* wgt) { ALLEGRO_EVENT event; wz_detach(wgt); wz_craft_event(&event, WZ_DESTROY, 0, 0); wz_broadcast_event(wgt, &event); }
/* Function: wz_focus Focuses/defocuses the widget tree. This function propagates the focus down the tree. Parameters: focus - pass 1 to focus the widget tree, or 0 to defocus it */ void wz_focus(WZ_WIDGET* wgt, int focus) { if (focus) { wz_ask_parent_for_focus(wgt); } else { ALLEGRO_EVENT event; wz_craft_event(&event, WZ_LOSE_FOCUS, 0, 0); wz_broadcast_event(wgt, &event); } }
/* Title: Button Section: Internal Function: wz_button_proc See also: <wz_widget_proc> */ int wz_button_proc(WZ_WIDGET* wgt, const ALLEGRO_EVENT* event) { int ret = 1; WZ_BUTTON* but = (WZ_BUTTON*)wgt; float x, y; switch(event->type) { case WZ_LOSE_FOCUS: { ret = 0; break; } case WZ_DRAW: { if(wgt->flags & WZ_STATE_HIDDEN) { ret = 0; } else { int flags = 0; if(wgt->flags & WZ_STATE_DISABLED) flags |= WZ_STYLE_DISABLED; else if (wgt->flags & WZ_STATE_HAS_FOCUS) flags |= WZ_STYLE_FOCUSED; if(but->down) flags |= WZ_STYLE_DOWN; wgt->theme->draw_button(wgt->theme, wgt->local_x, wgt->local_y, wgt->w, wgt->h, but->text, flags); } break; } #if (ALLEGRO_SUB_VERSION > 0) case ALLEGRO_EVENT_TOUCH_MOVE: x = event->touch.x; y = event->touch.y; #endif case ALLEGRO_EVENT_MOUSE_AXES: { if(event->type == ALLEGRO_EVENT_MOUSE_AXES) { x = event->mouse.x; y = event->mouse.y; } if(wgt->flags & WZ_STATE_DISABLED) { ret = 0; } else if((event->mouse.dx != 0 || event->mouse.dy != 0) && wz_widget_rect_test(wgt, x, y) && !(wgt->flags & WZ_STATE_HAS_FOCUS)) { wz_ask_parent_for_focus(wgt); } else { ret = 0; } break; } #if (ALLEGRO_SUB_VERSION > 0) case ALLEGRO_EVENT_TOUCH_BEGIN: x = event->touch.x; y = event->touch.y; #endif case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: { if(event->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { x = event->mouse.x; y = event->mouse.y; } if(wgt->flags & WZ_STATE_DISABLED) { ret = 0; } else if(wz_widget_rect_test(wgt, x, y)) { wz_ask_parent_for_focus(wgt); but->down = 1; wgt->hold_focus = 1; } else ret = 0; break; } case ALLEGRO_EVENT_KEY_DOWN: { switch(event->keyboard.keycode) { case ALLEGRO_KEY_ENTER: { if(wgt->flags & WZ_STATE_DISABLED) { ret = 0; } else if(wgt->flags & WZ_STATE_HAS_FOCUS) { but->down = 1; } else ret = 0; break; } default: ret = 0; } break; } case ALLEGRO_EVENT_KEY_UP: { switch(event->keyboard.keycode) { case ALLEGRO_KEY_ENTER: { if(wgt->flags & WZ_STATE_DISABLED) { ret = 0; } else if(wgt->flags & WZ_STATE_HAS_FOCUS) { wz_trigger(wgt); } else ret = 0; break; } default: ret = 0; } break; } case WZ_HANDLE_SHORTCUT: { if(wgt->flags & WZ_STATE_DISABLED) { ret = 0; } else { if(!(wgt->flags & WZ_STATE_HAS_FOCUS)) { wz_ask_parent_for_focus(wgt); } wz_trigger(wgt); } break; } #if (ALLEGRO_SUB_VERSION > 0) case ALLEGRO_EVENT_TOUCH_END: x = event->touch.x; y = event->touch.y; #endif case ALLEGRO_EVENT_MOUSE_BUTTON_UP: { if(event->type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) { x = event->mouse.x; y = event->mouse.y; } if(wgt->flags & WZ_STATE_DISABLED) { ret = 0; } else if(but->down == 1) { if(wz_widget_rect_test(wgt, x, y)) wz_trigger(wgt); but->down = 0; wgt->hold_focus = 0; } else { ret = 0; } break; } case WZ_DESTROY: { if(but->own) al_ustr_free(but->text); ret = 0; break; } case WZ_SET_TEXT: { if(but->own) { al_ustr_free(but->text); but->text = al_ustr_dup((ALLEGRO_USTR*)event->user.data3); } else { but->text = (ALLEGRO_USTR*)event->user.data3; } break; } case WZ_TRIGGER: { ALLEGRO_EVENT ev; but->down = 0; wz_craft_event(&ev, WZ_BUTTON_PRESSED, wgt, 0); al_emit_user_event(wgt->source, &ev, 0); break; } default: ret = 0; } if(ret == 0) ret = wz_widget_proc(wgt, event); return ret; }
/* Title: Edit Box Section: Internal Function: wz_editbox_proc See also: <wz_widget_proc> */ int wz_editbox_proc(WZ_WIDGET* wgt, ALLEGRO_EVENT* event) { int ret = 1; WZ_EDITBOX* box = (WZ_EDITBOX*)wgt; switch (event->type) { case WZ_DRAW: { if (wgt->flags & WZ_STATE_HIDDEN) { ret = 0; } else { int size = al_ustr_size(box->text); int scroll_offset = al_ustr_offset(box->text, box->scroll_pos); ALLEGRO_USTR_INFO info; ALLEGRO_USTR* text = al_ref_ustr(&info, box->text, scroll_offset, size); int pos = box->cursor_pos - box->scroll_pos; int flags = 0; if(wgt->flags & WZ_STATE_DISABLED) flags = WZ_STYLE_DISABLED; else if(wgt->flags & WZ_STATE_HAS_FOCUS) flags = WZ_STYLE_FOCUSED; wgt->theme->draw_editbox(wgt->theme, wgt->local_x, wgt->local_y, wgt->w, wgt->h, pos, text, flags); } break; } case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: { if (wgt->flags & WZ_STATE_DISABLED) { ret = 0; } else if (event->mouse.button == 1 && wz_widget_rect_test(wgt, event->mouse.x, event->mouse.y)) { int len = al_ustr_length(box->text); ALLEGRO_USTR_INFO info; ALLEGRO_USTR* text = al_ref_ustr(&info, box->text, box->scroll_pos, len - 1); ALLEGRO_FONT* font = wgt->theme->get_font(wgt->theme, 0); wz_ask_parent_for_focus(wgt); box->cursor_pos = wz_get_text_pos(font, text, event->mouse.x - wgt->x) + box->scroll_pos; } else ret = 0; break; } #if (ALLEGRO_SUB_VERSION > 0) case ALLEGRO_EVENT_TOUCH_BEGIN: { if (wgt->flags & WZ_STATE_DISABLED) { ret = 0; } else if (wz_widget_rect_test(wgt, event->touch.x, event->touch.y)) { int len = al_ustr_length(box->text); ALLEGRO_USTR_INFO info; ALLEGRO_USTR* text = al_ref_ustr(&info, box->text, box->scroll_pos, len - 1); ALLEGRO_FONT* font = wgt->theme->get_font(wgt->theme, 0); wz_ask_parent_for_focus(wgt); box->cursor_pos = wz_get_text_pos(font, text, event->touch.x - wgt->x) + box->scroll_pos; } else ret = 0; break; } #endif case WZ_HANDLE_SHORTCUT: { wz_ask_parent_for_focus(wgt); break; } case WZ_DESTROY: { if(box->own) al_ustr_free(box->text); ret = 0; break; } case ALLEGRO_EVENT_KEY_CHAR: { int len; if(wgt->flags & WZ_STATE_DISABLED || !(wgt->flags & WZ_STATE_HAS_FOCUS)) { ret = 0; break; } else if(event->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL || event->keyboard.modifiers & ALLEGRO_KEYMOD_ALT) { ret = 0; } len = al_ustr_length(box->text); if((int)(event->keyboard.unichar) > 31 && (int)(event->keyboard.unichar) != 127) { al_ustr_insert_chr(box->text, al_ustr_offset(box->text, box->cursor_pos), event->keyboard.unichar); box->cursor_pos++; } else { switch (event->keyboard.keycode) { case ALLEGRO_KEY_BACKSPACE: { if (len > 0 && box->cursor_pos > 0) { al_ustr_remove_chr(box->text, al_ustr_offset(box->text, box->cursor_pos - 1)); box->cursor_pos--; } break; } case ALLEGRO_KEY_DELETE: { if (len > 0 && box->cursor_pos < len) { al_ustr_remove_chr(box->text, al_ustr_offset(box->text, box->cursor_pos)); } break; } case ALLEGRO_KEY_LEFT: { if (box->cursor_pos > 0) { box->cursor_pos--; } else ret = 0; break; } case ALLEGRO_KEY_RIGHT: { if (box->cursor_pos < len) { box->cursor_pos++; } else ret = 0; break; } case ALLEGRO_KEY_HOME: { box->cursor_pos = 0; break; } case ALLEGRO_KEY_END: { len = al_ustr_length(box->text); box->cursor_pos = len; break; } case ALLEGRO_KEY_ENTER: { wz_trigger(wgt); break; } default: ret = 0; } } wz_snap_editbox(box); break; } case WZ_SET_CURSOR_POS: { box->cursor_pos = event->user.data3; wz_snap_editbox(box); } case WZ_SET_TEXT: { if(box->own) { al_ustr_assign(box->text, (ALLEGRO_USTR*)event->user.data3); } else box->text = (ALLEGRO_USTR*)event->user.data3; wz_snap_editbox(box); break; } case WZ_TRIGGER: { ALLEGRO_EVENT ev; wz_craft_event(&ev, WZ_TEXT_CHANGED, wgt, 0); al_emit_user_event(wgt->source, &ev, 0); break; } case ALLEGRO_EVENT_MOUSE_AXES: { if (wgt->flags & WZ_STATE_DISABLED) { ret = 0; } if (wz_widget_rect_test(wgt, event->mouse.x, event->mouse.y)) { wz_ask_parent_for_focus(wgt); } return wz_widget_proc(wgt, event); break; } default: ret = 0; } if (ret == 0) ret = wz_widget_proc(wgt, event); return ret; }
/* Title: Widget Section: Internal Function: wz_widget_proc Callback function that handles the operations of a general widget. All widget procs call this function as their default handler. Returns: 1 if the event was handled by the widget, 0 otherwise */ int wz_widget_proc(WZ_WIDGET* wgt, ALLEGRO_EVENT* event) { int ret = 1; switch (event->type) { case WZ_HIDE: { wgt->flags |= WZ_STATE_HIDDEN; break; } case WZ_SHOW: { wgt->flags &= ~WZ_STATE_HIDDEN; break; } case WZ_DISABLE: { wgt->flags |= WZ_STATE_DISABLED; break; } case WZ_ENABLE: { wgt->flags &= ~WZ_STATE_DISABLED; break; } case WZ_UPDATE_POSITION: { if (wgt->parent) { wgt->local_x = wgt->parent->local_x + wgt->x; wgt->local_y = wgt->parent->local_y + wgt->y; } else { wgt->local_x = wgt->x; wgt->local_y = wgt->y; } break; } case WZ_DESTROY: { al_destroy_user_event_source(wgt->source); free(wgt->source); free(wgt); break; } case WZ_LOSE_FOCUS: { wgt->flags &= ~WZ_STATE_HAS_FOCUS; break; } case WZ_TAKE_FOCUS: { wz_focus(wgt, 0); wgt->flags |= WZ_STATE_HAS_FOCUS; if (wgt->first_child) wz_focus(wgt->first_child, 1); break; } case WZ_WANT_FOCUS: { WZ_WIDGET* child = wgt->first_child; while (child) { wz_focus(child, 0); child = child->next_sib; } { ALLEGRO_EVENT ev; wz_craft_event(&ev, WZ_TAKE_FOCUS, wgt, 0); child = wgt->first_child; wz_send_event((WZ_WIDGET*)event->user.data2, &ev); } break; } case ALLEGRO_EVENT_MOUSE_AXES: { if (wgt->flags & WZ_STATE_DISABLED) { ret = 0; } else if (event->mouse.dz != 0 && wgt->first_child == 0 && wgt->parent != 0) { if (event->mouse.dz > 0) { wz_ask_parent_to_focus_prev(wgt); } else { wz_ask_parent_to_focus_next(wgt); } } else { ret = 0; } break; } /* Switch through elements on Touch: case ALLEGRO_EVENT_TOUCH_BEGIN: { if (wgt->flags & WZ_STATE_DISABLED) { ret = 0; } else if (wgt->first_child == 0 && wgt->parent != 0) { wz_ask_parent_to_focus_next(wgt); } else { ret = 0; } break; } */ case ALLEGRO_EVENT_KEY_CHAR: { if(event->keyboard.keycode == wgt->shortcut.keycode && ((event->keyboard.modifiers & wgt->shortcut.modifiers) || wgt->shortcut.modifiers == 0)) { ALLEGRO_EVENT ev; wz_craft_event(&ev, WZ_HANDLE_SHORTCUT, wgt, 0); wz_send_event(wgt, &ev); } else { switch (event->keyboard.keycode) { case ALLEGRO_KEY_TAB: { if (wgt->first_child != 0) { ret = 0; } else if (event->keyboard.modifiers & 1) { wz_ask_parent_to_focus_prev(wgt); } else { wz_ask_parent_to_focus_next(wgt); } break; } case ALLEGRO_KEY_UP: { if (wgt->first_child != 0) { ret = 0; } else if (wgt->parent != 0) { wz_ask_parent_for_focus(wz_get_widget_dir(wgt, 0)); } else ret = 0; break; } case ALLEGRO_KEY_RIGHT: { if (wgt->first_child != 0) { ret = 0; } else if (wgt->parent != 0) { wz_ask_parent_for_focus(wz_get_widget_dir(wgt, 1)); } else ret = 0; break; } case ALLEGRO_KEY_DOWN: { if (wgt->first_child != 0) { ret = 0; } else if (wgt->parent != 0) { wz_ask_parent_for_focus(wz_get_widget_dir(wgt, 2)); } else ret = 0; break; } case ALLEGRO_KEY_LEFT: { if (wgt->first_child != 0) { ret = 0; } else if (wgt->parent != 0) { wz_ask_parent_for_focus(wz_get_widget_dir(wgt, 3)); } else ret = 0; break; } default: ret = 0; } } break; } default: ret = 0; } return ret; }
/* Function: wz_set_cursor_pos Sets the cursor position */ void wz_set_cursor_pos(WZ_WIDGET* wgt, int pos) { ALLEGRO_EVENT event; wz_craft_event(&event, WZ_SET_CURSOR_POS, 0, pos); wz_send_event(wgt, &event); }
/* Function: wz_set_scroll_pos Sets the scroll position Parameters: max - Pass 1 to say that pos is actually the max position, 0 otherwise */ void wz_set_scroll_pos(WZ_WIDGET* wgt, int pos, int max) { ALLEGRO_EVENT event; wz_craft_event(&event, max ? WZ_SET_SCROLL_MAX_POS : WZ_SET_SCROLL_POS, 0, pos); wz_send_event(wgt, &event); }
/* Function: wz_set_text Sets the text of a widget. The widget makes a local copy of the text. */ void wz_set_text(WZ_WIDGET* wgt, ALLEGRO_USTR* text) { ALLEGRO_EVENT event; wz_craft_event(&event, WZ_SET_TEXT, 0, (intptr_t)text); wz_send_event(wgt, &event); }
/* Function: wz_draw Draws the widget tree. Only affects the visible widgets */ void wz_draw(WZ_WIDGET* wgt) { ALLEGRO_EVENT event; wz_craft_event(&event, WZ_DRAW, 0, 0); wz_broadcast_event(wgt, &event); }
/* Function: wz_trigger Triggers a widget. What the widget does depends on the widget. Generally, it will send an event that is characteristic of the events that it usually sends. For example, triggering a button will simulate an impression of the button, causing it to send <WZ_BUTTON_PRESSED> event. */ void wz_trigger(WZ_WIDGET* wgt) { ALLEGRO_EVENT event; wz_craft_event(&event, WZ_TRIGGER, 0, 0); wz_send_event(wgt, &event); }
/* Function: wz_resize Resizes the widget tree. Parameters: factor: scaling factor */ void wz_resize(WZ_WIDGET* wgt, float factor) { ALLEGRO_EVENT event; wz_craft_event(&event, WZ_RESIZE, 0, *(intptr_t*)&factor); wz_broadcast_event(wgt, &event); }