#ifndef zori_H_INCLUDED #define zori_H_INCLUDED #include #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 /* 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 int zori_id; typedef ALLEGRO_USTR zori_string; /* 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 /* 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) ((sizeof(A))/(sizeof(*A))) /** Macro that expands to the amount of elemnts in the array and the array * itself, in that order. */ #define ZORI_AMOUNT_AND_ARRAY(A) ZORI_ARRAY_AMOUNT(A), (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) \ ((TYPE *)(((char *)(PTR)) - offsetof(TYPE, MEMBER))) /** 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'), ZORI_EVENT_UPDATE, /** First draw pass. */ ZORI_EVENT_DRAW, /** Second draw pass for cursors. */ ZORI_EVENT_OVERDRAW, ZORI_EVENT_DONE, ZORI_EVENT_FREE, ZORI_EVENT_ACTION, }; 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; }; /** 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; }; /* 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 * image; 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_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 even needds 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 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, }; /* 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; /* 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; }; /* 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_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_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_id id, struct zori_widget *parent, zori_rebox *box, struct zori_style *style, size_t amount, struct zori_handler *handlers); void zori_draw_all(void); int zori_widget_visible(struct zori_widget *widget); int zori_widget_active(struct zori_widget *widget); 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); void zori_widget_drawroundframe(struct zori_widget *self); typedef int (zori_console_command)(struct zori_widget *, const char * command, void * data); /* A console is a console for command-line interaction and error display. When it's active it captures all input (as long as it's active) */ struct zori_console { struct zori_widget widget; USTRList text; int count; int max; int start; int charw; int cursor; char * buf; USTR * input; zori_console_command * command; // called when a command has been entered, if set. void * command_data; // command data. }; struct zori_console *zori_widget_console(struct zori_widget *widget); int zori_console_docommand(struct zori_console *self, const char *text); int zori_console_addstr(struct zori_console *self, const char *str); int zori_console_addustr(struct zori_console *self, const ALLEGRO_USTR *ustr); int zori_console_puts(struct zori_console *self, const char *str); int zori_console_vprintf(struct zori_console *self, const char *format, va_list args); int zori_console_printf(struct zori_console *self, const char *format, ...); int zori_console_draw(union zori_event *zevent); void zori_console_active_(struct zori_console *self, int active); int zori_console_active(struct zori_console *self); int zori_console_scroll(struct zori_console *self, int direction); int zori_console_handle_keychar(union zori_event *zevent); int zori_console_handle_keydown(union zori_event *zevent); int zori_console_handle_mouseaxes(union zori_event *zevent); int zori_console_handle_ignore(union zori_event *zevent); int zori_console_handle(struct zori_widget *widget, zori_system_event *sevent); int zori_console_done(struct zori_widget *widget); int zori_console_free(struct zori_widget *widget); struct zori_console *zori_console_alloc(void); struct zori_console *zori_console_initall(struct zori_console *self, int id, zori_rebox *bounds, struct zori_style *style); struct zori_console *zori_console_new(int id, zori_rebox *bounds, struct zori_style *style); int zori_handle_system_event(zori_system_event * sysev); #endif