123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606 |
- #ifndef zori_H_INCLUDED
- #define zori_H_INCLUDED
- /*
- * ZORI is a a GUI subsystem for use with Allegro 5 that handles
- * the user interface of Eruta.
- *
- * ZORI is a classic retained-mode GUI system that has an additional
- * pseudo-direct mode API. ZORI uses a handler system where events are handled
- * by call back functions which can be installed as specific handlers that are
- * activated on certain events. But, in the spirit of direct mode GUI's, all
- * widgets also keep state flags and value flags that can be used to see if they
- * have been activated and that can be inspected in a direct-mode GUI fashion.
- * With ZORI you can have your retained mode GUI pie and also eat it in direct
- * mode.
- *
- * In ZORI, there is only one top-level widget, the root, however, every widget
- * can contain any amount of child widgets. One level below the root widget are
- * the screen widgets which are intent to handle the GUI on one physical screen
- * or display. Every GUI page can have different "pages", but only one page
- * should be active per screen. The idea is that a GUI page represents a single
- * GUI mode such as the main menu, the settings menu, the in game menu, etc,
- * where you definitely want only one to be active at any given time.
- *
- * The box model used in Zori will be as follows (XXX implement this):
- * ......................................
- * .margin .
- * . +-------------border-----------+ .
- * . | padding | .
- * . | .......................... | .
- * . | . . | .
- * . | . contents . | .
- * . | . . | .
- * . | .......................... | .
- * . | padding | .
- * . +------------------------------+ .
- * .margin .
- * ......................................
- *
- * The padding determines the minimal distance between the border or the
- * parent widget and it's contents and/or child widgets.
- *
- * The border's thickness is only relevant for visual effects.
- * It does not change the layout. The border is effectively "inside"
- * the padding and/or contents of the widget and is unrelated to the padding.
- *
- * The margin of a widget determines how closely that widget may be packed
- * to it's sibling widgets.
- *
- * The work in UI is divided between the top-level widgets,
- * namely the root and the page, and the other widgets.
- * The root and the page handle everything that depends on and/or may influence
- * several widgets at once, such as event dispatching but also setting the
- * focus, determining which widget is being hovered, or dragged, etc.
- * The latter functions change the state of several widgets, so they
- * are handled on the level of the container widgets.
- * The zori_widget and the other concrete widgets handle the individual
- * state and actions of the various widgets individually.
- *
- *
- *
- *
- */
- #include <stdbool.h>
- #include "eruta.h"
- #include "rebox.h"
- #include "miao.h"
- #include "str.h"
- /* Defines for C11/C99/C89 portability */
- #ifndef inline
- #define inline inline
- #endif
- /* Macros for possible later system library portability. */
- #define ZORI_EVENT_TYPE_IS_USER(T) ALLEGRO_EVENT_TYPE_IS_USER(T)
- #define ZORI_SYSTEM_EVENT_KEY_DOWN ALLEGRO_EVENT_KEY_DOWN
- #define ZORI_SYSTEM_EVENT_KEY_UP ALLEGRO_EVENT_KEY_UP
- #define ZORI_SYSTEM_EVENT_KEY_CHAR ALLEGRO_EVENT_KEY_CHAR
- #define ZORI_SYSTEM_EVENT_MOUSE_AXES ALLEGRO_EVENT_MOUSE_AXES
- #define ZORI_SYSTEM_EVENT_MOUSE_AXES ALLEGRO_EVENT_MOUSE_AXES
- #define ZORI_SYSTEM_EVENT_MOUSE_BUTTON_DOWN ALLEGRO_EVENT_MOUSE_BUTTON_DOWN
- #define ZORI_SYSTEM_EVENT_MOUSE_BUTTON_UP ALLEGRO_EVENT_MOUSE_BUTTON_UP
- /* Typedefs for possible later system library portability. */
- typedef ALLEGRO_COLOR zori_color;
- typedef ALLEGRO_BITMAP zori_bitmap;
- typedef ALLEGRO_FONT zori_font;
- typedef ALLEGRO_EVENT zori_system_event;
- typedef ALLEGRO_EVENT_TYPE zori_event_type;
- typedef ALLEGRO_DISPLAY zori_display;
- typedef Point zori_point;
- typedef Rebox zori_rebox;
- typedef Rebox zori_box;
- typedef int zori_id;
- typedef ALLEGRO_USTR zori_string;
- typedef ALLEGRO_USTR zori_text;
- /* Macros for possible portability. */
- #define zori_font_lineheight(FONT) al_get_font_line_height(FONT)
- #define zori_font_drawstr(FONT, COLOR, X, Y, ATTR, TEXT) al_draw_ustr(FONT, COLOR, X, Y, ATTR, TEXT)
- /* Default sizes of a widget. */
- #define ZORI_WIDGET_DEFAULT_W 640
- #define ZORI_WIDGET_DEFAULT_H 480
- /* Defaut padding and margin. */
- #define ZORI_PADDING_DEFAULT 4
- #define ZORI_MARGIN_DEFAULT 0
- /* Zori ID's. */
- #define ZORI_ID_OK_P(ID) ((ID) > -1)
- #define ZORI_ID_OK ((zori_id)(0))
- #define ZORI_ID_ERROR ((zori_id)(-1))
- #define ZORI_ID_ENOMEM ((zori_id)(-2))
- #define ZORI_ID_EINVAL ((zori_id)(-3))
- /** Macro for the number of elements of an array .*/
- #define ZORI_ARRAY_AMOUNT(A) ((size_t)(sizeof(A))/(sizeof(*A)))
- /** Macro that expands to the the array itself, and the amount of elements
- * in that array, in that order. Only works on a statically sized array. */
- #define ZORI_ARRAY_AND_AMOUNT(A) (A), ZORI_ARRAY_AMOUNT(A)
-
- /* Macro: ZORI_CONTAINER_OF(PTR, TYPE, MEMBER)
- This macro returns, for the given pointer, a pointer to a containing struct
- of type TYPE, in which PTR is a member named MEMBER.
- This enables cool ways of type genericity and extension in plain C.
- It should not run afoul of strict aliasing since it passes over a char * pointer
- and a pointer of a containing struct or union.
- */
- #define ZORI_CONTAINER_OF(PTR, TYPE, MEMBER) \
- ((PTR) ? ((TYPE *)(((char *)(PTR)) - offsetof(TYPE, MEMBER))) : NULL)
- /** Custom event types, used in conjunction with Allegro event types. */
- enum zori_custom_event_type {
- ZORI_EVENT_CUSTOM = ALLEGRO_GET_EVENT_TYPE('z', 'o', 'r', 'i'),
- /** Update event, called at regular intervals to update the state of the UI.*/
- ZORI_EVENT_UPDATE,
- /** First draw pass. */
- ZORI_EVENT_DRAW,
- /** Second draw pass for cursors. */
- ZORI_EVENT_OVERDRAW,
- /** Cleanup event. */
- ZORI_EVENT_DONE,
- /** Destruction event. */
- ZORI_EVENT_FREE,
- /** Activation event, such as a button being clicked or a menu being opened. */
- ZORI_EVENT_ACTION,
- /** Close event, such as a menu being closed. Not for cleanup.*/
- ZORI_EVENT_CLOSE,
- /** Child added event to ease setup. */
- ZORI_EVENT_NEW_CHILD,
- };
- struct zori_widget;
- /* Common fields for an event. */
- struct zori_any_event {
- /* Type of the event, possibly copied from sysev. */
- zori_event_type type;
- /* Widget the event is sent to. */
- struct zori_widget * widget;
- /* Data specified in the handler. */
- void * data;
- };
- /* System event, that is coming from the underlying library used, e.g. Allegro. */
- struct zori_sys_event {
- struct zori_any_event any;
- zori_system_event * ev;
- };
- /* Update event, when UI has to update (animations, etc). */
- struct zori_update_event {
- struct zori_any_event any;
- double dt;
- };
- /* Draw event when the UI has to draw itself. */
- struct zori_draw_event {
- struct zori_any_event any;
- };
- /* Cleanup event. */
- struct zori_done_event {
- struct zori_any_event any;
- };
- /* Cleanup event. */
- struct zori_free_event {
- struct zori_any_event any;
- };
- /* Action event. */
- struct zori_action_event {
- struct zori_any_event any;
- };
- /* Close event. */
- struct zori_close_event {
- struct zori_any_event any;
- /* The widget that was closed and that sent this message to it's parent. */
- struct zori_widget * from;
- };
- /* New child event. */
- struct zori_new_child_event {
- struct zori_any_event any;
- /* The widget that was added as a child and that sent this message to it's parent. */
- struct zori_widget * child;
- };
- /** An event that ZORI can handle. The union is cunningly overlaid so
- * that the type field and the any field can be used in all cases. */
- union zori_event {
- /* Type of the event, possibly copied from sysev. */
- zori_event_type type;
- struct zori_any_event any;
- struct zori_sys_event sys;
- struct zori_draw_event draw;
- struct zori_update_event update;
- struct zori_done_event done;
- struct zori_free_event free;
- struct zori_action_event action;
- struct zori_close_event close;
- struct zori_new_child_event new_child;
- };
- /* Helper functions to get widget from an event. */
- static inline struct zori_widget *
- zori_event_widget(union zori_event * event) {
- if (!event) return NULL;
- return event->any.widget;
- }
- /* Helper functions to get data from an event. */
- static inline void * zori_event_data(union zori_event * event) {
- if (!event) return NULL;
- return event->any.data;
- }
- /* Helper function that checks if an event is a sys_event. */
- static inline bool zori_event_is_sys_event(union zori_event * event) {
- if (!event) return false;
- return (!ALLEGRO_EVENT_TYPE_IS_USER(event->type));
- }
- /* Helper functions to get system event from an event. Type checks the type. */
- static inline zori_system_event * zori_event_system_event(union zori_event * event) {
- if (!event) return NULL;
- if (!zori_event_is_sys_event(event)) return NULL;
- return event->sys.ev;
- }
- /* Helper functions to set widget for an event. */
- static inline struct zori_widget *
- zori_event_set_widget(union zori_event * event, struct zori_widget * widget) {
- if (!event) return NULL;
- return event->any.widget = widget;
- }
- /* Helper functions to set data for an event. */
- static inline void * zori_event_set_data(union zori_event * event, void * data) {
- if (!event) return NULL;
- return event->any.data = data;
- }
- /* A style part is a color, image and font applied to a part of the GUI. */
- struct zori_stylepart {
- zori_color color;
- zori_bitmap * bitmap;
- zori_font * font;
- };
- /* A style is a set of style parts for different parts of the GUI. */
- struct zori_style {
- struct zori_stylepart fore;
- struct zori_stylepart back;
- struct zori_stylepart text;
- struct zori_stylepart border;
- struct zori_stylepart hover;
- struct zori_stylepart mark;
- };
- struct zori_widget;
- /* Event handler results. */
- enum zori_handle_result {
- ZORI_HANDLE_ERROR = -1, /* An error ocurred, stop propagating to children.*/
- ZORI_HANDLE_DONE = 0, /* The event was handled and consumed, no need to propagate to children automatically (widget may re-send event manually to children.)*/
- ZORI_HANDLE_IGNORE = 1, /* Event wasn't handled, propagate to children. */
- ZORI_HANDLE_PASS = 2, /* Event was handled, but needs to be propagated.*/
- };
- /* Returns whether or not a event needs to be propagated based on the
- * result of a handler. */
- static int zori_propagate_event_p(enum zori_handle_result result) {
- switch(result) {
- case ZORI_HANDLE_ERROR: return 0;
- case ZORI_HANDLE_DONE: return 0;
- case ZORI_HANDLE_IGNORE: return !0;
- case ZORI_HANDLE_PASS: return !0;
- default: return !0;
- }
- }
- typedef enum zori_handle_result (zori_handler_func)(union zori_event * event);
- /* A single event handler */
- struct zori_handler {
- zori_event_type type;
- zori_handler_func * handler;
- void * data;
- };
- /* A dynamic array of event handlers event handlers. */
- struct zori_handlers miao_of_type(struct zori_handler);
- /* An entry in a widget registry. */
- struct zori_registry_entry {
- zori_id id;
- struct zori_widget * widget;
- };
- /* A widget registry as a dynamic array of entries. */
- struct zori_registry miao_of_type(struct zori_registry_entry);
- /* Generic state flags for several zori structs. */
- enum zori_flag {
- /* The object is not visible, though it may still be interacted with.*/
- ZORI_FLAG_HIDDEN = 1 << 0,
- /* The object cannot be interacted with, though it is still visible. */
- ZORI_FLAG_DISABLED = 1 << 1,
- /* The object is both hidden and disabled. */
- ZORI_FLAG_DEACTIVATED = ZORI_FLAG_HIDDEN | ZORI_FLAG_DISABLED,
- /* The object is being hovered by the mouse cursor. */
- ZORI_FLAG_HOVERED = 1 << 2,
- /* The object is "marked" for activation by the keyjoy cursor */
- ZORI_FLAG_MARKED = 1 << 3,
- };
- /* Typedef for the type of a widget.
- * Not an enum since every widget may define this itself.
- */
- typedef uint32_t zori_widget_type;
- /* Generic widget types. */
- #define ZORI_WIDGET_TYPE_NONE ((zori_widget_type)(0))
- /* Macro to help generate widget types. */
- #define ZORI_WIDGET_TYPE(A, B, C, D) ((zori_widget_type)((A<<24) | (B<<16) | (C<<8) | D))
- /* Mouse or keyboard/joystick cursor. */
- struct zori_cursor {
- zori_point p;
- struct zori_widget * hover;
- struct zori_widget * focus;
- zori_bitmap * bitmap;
- enum zori_flag flags;
- };
- /* Support multiple cursors... */
- struct zori_cursors {
- struct zori_cursor mouse;
- struct zori_cursor keyjoy;
- };
- /*
- on_enter
- on_enter(data = {})
- on_event(*args)
- on_event(*data)
- on_key_down(*args)
- on_leave(name=nil)
- on_mouse_axes(t, x, y, z, w, dx, dy, dz, dw)
- on_mouse_button_down(t, x, y, z, w, b)
- on_mouse_button_up(t, x, y, z, w, b)
- on_mouse_in(x, y, from)
- on_mouse_out(x, y, to)
- on_resize
- */
- struct zori_widget;
- struct zori_widget_list miao_of_type(struct zori_widget *);
- struct zori_widget {
- /* ID of the widget, used in most external API's. */
- zori_id id;
-
- /* Root level widget under which this widget is active. */
- struct zori_widget * root;
-
- /* Position and size of the widget. */
- zori_rebox box;
-
- /* Outer rectangle of the widget, with the margin added. */
- zori_rebox outer;
-
- /* Inner rectangle of the widget, with the padding removed. */
- zori_rebox inner;
-
- /* Z ordering. */
- int z;
-
- /* Style. */
- struct zori_style style;
-
- /* Handlers. */
- struct zori_handlers handlers;
-
- /* Related widgets. */
- struct zori_widget * parent;
- struct zori_widget_list children;
-
- /* Flags. */
- enum zori_flag flags;
-
- /* Type of the widget. */
- zori_widget_type type;
-
- /* Generic "result", of last operation on widget, normally zero. */
- int result;
- };
- /* An array of widget pointers. */
- struct zori_widget_array miao_of_type(struct zori_widget *);
- /* Forward declarations. */
- struct zori_screen;
- struct zori_console;
- /*
- * Root level widget, my spread out over several displays.
- * In Zori, there can only be a single root level widget active.
- * It's ID is always 0;
- */
- struct zori_root {
- /* A root is a widget. */
- struct zori_widget widget;
- /* Current active screen widget if any. */
- struct zori_screen * active_screen;
- /* Current active console if any. */
- struct zori_console * console;
- };
- /* Forward declaration of a page. */
- struct zori_page;
- struct zori_root * zori_get_root(void);
- /* Initializes Zori and creates a top level widget. Returns 0 on success
- * or negative on error. The style will be copied and set as default
- * if it is not NULL. Otherwise a built-in style will be used.
- * Not that ZORI will NOT clean up any images or fonts it uses by itself.
- */
- zori_id zori_start(struct zori_style * default_style);
- /* Shut down Zori and destroys all widgets. Return 0 on succes or
- * negative on error.
- */
- zori_id zori_shutdown();
- /* Creates a new screen widget. Normally this should be the first widget
- * you create after zori_start. */
- /* Activates the page on it's display. All other pages are dectivated and
- * hidden. */
- zori_id zori_activate_page(zori_id page);
- /* Creates a new generic widget on the given screen with the given
- * dimensions. */
- zori_id zori_new(zori_id screen, zori_rebox * box);
- /* Sets the flags of a widget. */
- zori_id zori_set_flags(zori_id widget, enum zori_flag flags);
- /* Sets the whole style of a widget. */
- zori_id zori_set_style(zori_id id, struct zori_style * style);
- /* Sets the background color of the widget. */
- zori_id zori_set_background_color(zori_id id, zori_color color);
- /* Sets the foreground color of the widget. */
- zori_id zori_set_foreground_color(zori_id id, zori_color color);
- /* Creates a new frame widget. */
- zori_id zori_new_frame_widget(zori_id parent, zori_rebox box);
- /* Creates a new (vertical) menu widget. */
- zori_id zori_new_menu_widget(zori_id parent, zori_rebox box, char * text);
- /* Creates a new button widget. */
- zori_id zori_new_button_widget(zori_id parent, zori_rebox box, char * text);
- /* Creates a new conversation widget. */
- zori_id zori_new_conversation_widget(zori_id parent, zori_rebox box, char * text);
- /* Draws the whole UI and all visible parts. */
- void zori_draw_all(void);
- /* Updates the state of the UI. Pass in the time passed since last update. */
- void zori_update(double dt);
- /* Registers an event handler for a widget. */
- zori_id zori_register(zori_id id, zori_event_type type, zori_handler_func handler, void * extra);
- int zori_registry_entry_compare(const void *v1, const void *v2);
- zori_id zori_registry_init(struct zori_registry *registry);
- zori_id zori_registry_add(struct zori_registry *registry, zori_id id, struct zori_widget *widget);
- struct zori_registry_entry *zori_registry_lookup_entry(struct zori_registry *registry, zori_id id);
- struct zori_widget *zori_registry_lookup(struct zori_registry *registry, zori_id id);
- zori_id zori_registry_remove(struct zori_registry *registry, zori_id id);
- int zori_handler_compare(const void *v1, const void *v2);
- struct zori_handler *zori_handlers_add(struct zori_handlers *me, zori_event_type type, zori_handler_func *handler, void *data);
- void zori_handlers_done(struct zori_handlers *me);
- void zori_handlers_init(struct zori_handlers *me);
- struct zori_handler *zori_handlers_search(struct zori_handlers *me, zori_event_type type);
- int zori_handlers_handle(struct zori_handlers *me, union zori_event *event);
- int zori_widget_raise_system_event(struct zori_widget *widget, zori_system_event *sysev);
- int zori_widget_raise_draw_event(struct zori_widget *widget);
- int zori_widget_raise_done_event(struct zori_widget *widget);
- int zori_widget_raise_free_event(struct zori_widget *widget);
- int zori_widget_raise_update_event(struct zori_widget *widget, double dt);
- int zori_widget_raise_action_event(struct zori_widget *widget);
- int zori_widget_raise_close_event(struct zori_widget *widget, struct zori_widget * from);
- int zori_widget_compare(const void *v1, const void *v2);
- struct zori_widget *zori_get_widget(zori_id id);
- zori_id zori_get_unused_id(void);
- struct zori_handler *zori_widget_add_handler(struct zori_widget *widget, zori_event_type type, zori_handler_func *handler, void *data);
- struct zori_handler *zori_widget_add_handlers(struct zori_widget *widget, struct zori_handler *handlers, size_t amount);
- zori_id zori_start(struct zori_style *default_style);
- struct zori_widget *zori_widget_done(struct zori_widget *widget);
- void zori_widget_free(struct zori_widget *widget);
- struct zori_widget *zori_widget_add_child(struct zori_widget *parent, struct zori_widget *child);
- struct zori_widget *zori_widget_init(struct zori_widget *widget, zori_widget_type type, zori_id id, struct zori_widget *parent, zori_rebox *box, struct zori_style *style);
- zori_id zori_shutdown(void);
- struct zori_widget *zori_widget_initall(struct zori_widget *widget, zori_widget_type type, zori_id id, struct zori_widget *parent, zori_rebox *box, struct zori_style *style, struct zori_handler *handlers, size_t amount);
- void zori_draw_all(void);
- int zori_widget_visible(struct zori_widget *widget);
- int zori_widget_visible_(struct zori_widget *widget, int set);
- int zori_widget_active(struct zori_widget *widget);
- int zori_widget_active_(struct zori_widget *widget, int set);
- int zori_widget_hover(struct zori_widget *widget);
- int zori_widget_hover_(struct zori_widget *widget, int set);
- int zori_widget_marked(struct zori_widget *widget);
- int zori_widget_marked_(struct zori_widget *widget, int set);
- int zori_widget_active_(struct zori_widget *widget, int set);
- void zori_update(double dt);
- zori_font *zori_widget_font(struct zori_widget *widget);
- zori_color zori_widget_forecolor(struct zori_widget *widget);
- zori_color zori_widget_backcolor(struct zori_widget *widget);
- int zori_widget_h(struct zori_widget *widget);
- int zori_widget_w(struct zori_widget *widget);
- int zori_widget_x(struct zori_widget *widget);
- int zori_widget_y(struct zori_widget *widget);
- int zori_xy_inside_widget_p(struct zori_widget * widget, double x, double y);
- void zori_widget_drawroundframe(struct zori_widget *self);
- int zori_handle_system_event(zori_system_event * sysev);
- int zori_result(int zori_id);
- int zori_mark_widget(struct zori_widget * widget);
- #endif
|