|
@@ -2,6 +2,8 @@
|
|
|
#include "zori.h"
|
|
|
#include "miao.h"
|
|
|
#include <allegro5/allegro_color.h>
|
|
|
+#include "str.h"
|
|
|
+#include "draw.h"
|
|
|
|
|
|
|
|
|
* Pardon the pun name, but Zori is the submodule that handles the user
|
|
@@ -112,16 +114,59 @@ struct zori_handler * zori_handlers_search(struct zori_handlers * me, zori_even
|
|
|
key.data = NULL;
|
|
|
if (!me) return NULL;
|
|
|
result = miao_bsearch(me, zori_handler_compare, &key);
|
|
|
- return result;
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
|
|
|
-int zori_handlers_handle(struct zori_handlers * me, struct zori_event * event, struct zori_widget * widget) {
|
|
|
- struct zori_handler * handler = zori_handlers_search(me, event->sysev.type);
|
|
|
+int zori_handlers_handle(struct zori_handlers * me, union zori_event * event) {
|
|
|
+ struct zori_handler * handler = zori_handlers_search(me, event->type);
|
|
|
if (!handler) return 0;
|
|
|
+ event->any.data = handler->data;
|
|
|
return handler->handler(event);
|
|
|
}
|
|
|
|
|
|
+int zori_widget_raise_system_event
|
|
|
+(struct zori_widget * widget, zori_system_event * sysev) {
|
|
|
+ union zori_event event;
|
|
|
+ event.sys.any.type = sysev->type;
|
|
|
+ event.sys.any.widget = widget;
|
|
|
+ event.sys.sysev = sysev;
|
|
|
+ return zori_handlers_handle(&widget->handlers, &event);
|
|
|
+}
|
|
|
+
|
|
|
+int zori_widget_raise_draw_event(struct zori_widget * widget) {
|
|
|
+ union zori_event event;
|
|
|
+ event.draw.any.type = ZORI_EVENT_DRAW;
|
|
|
+ event.draw.any.widget = widget;
|
|
|
+ return zori_handlers_handle(&widget->handlers, &event);
|
|
|
+}
|
|
|
+
|
|
|
+int zori_widget_raise_done_event(struct zori_widget * widget) {
|
|
|
+ union zori_event event;
|
|
|
+ event.done.any.type = ZORI_EVENT_DONE;
|
|
|
+ event.done.any.widget = widget;
|
|
|
+ return zori_handlers_handle(&widget->handlers, &event);
|
|
|
+}
|
|
|
+
|
|
|
+int zori_widget_raise_free_event(struct zori_widget * widget) {
|
|
|
+ union zori_event event;
|
|
|
+ event.free.any.type = ZORI_EVENT_FREE;
|
|
|
+ event.free.any.widget = widget;
|
|
|
+ return zori_handlers_handle(&widget->handlers, &event);
|
|
|
+}
|
|
|
+
|
|
|
+int zori_widget_raise_update_event
|
|
|
+(struct zori_widget * widget, double dt) {
|
|
|
+ union zori_event event;
|
|
|
+ event.update.any.type = ZORI_EVENT_DONE;
|
|
|
+ event.update.any.widget = widget;
|
|
|
+ event.update.dt = dt;
|
|
|
+ return zori_handlers_handle(&widget->handlers, &event);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
static struct zori_root * the_zori_root = NULL;
|
|
|
|
|
|
static struct zori_style * the_default_style = NULL;
|
|
@@ -136,9 +181,8 @@ int zori_widget_compare(const void * v1, const void * v2) {
|
|
|
|
|
|
|
|
|
struct zori_widget * zori_get_widget(zori_id id) {
|
|
|
- struct zori_widget key = {0};
|
|
|
- key.id = id;
|
|
|
- return miao_bsearch(the_zori_root->widgets, zori_widget_compare, &key);
|
|
|
+ if (!the_zori_registry) return NULL;
|
|
|
+ return zori_registry_lookup(the_zori_registry, id);
|
|
|
}
|
|
|
|
|
|
zori_id zori_get_unused_id(void) {
|
|
@@ -149,10 +193,28 @@ zori_id zori_get_unused_id(void) {
|
|
|
if (id == INT_MAX) { return ZORI_ID_ERROR; }
|
|
|
found = zori_get_widget(id);
|
|
|
} while(found);
|
|
|
-
|
|
|
return id;
|
|
|
}
|
|
|
|
|
|
+struct zori_handler * zori_widget_add_handler
|
|
|
+(struct zori_widget * widget, zori_event_type type, zori_handler_func * handler, void * data) {
|
|
|
+ if ((!widget) || (!handler)) return NULL;
|
|
|
+
|
|
|
+ return zori_handlers_add(&widget->handlers, type, handler, data);
|
|
|
+}
|
|
|
+
|
|
|
+struct zori_handler * zori_widget_add_handlers
|
|
|
+(struct zori_widget * widget, struct zori_handler * handlers, size_t amount) {
|
|
|
+ size_t i;
|
|
|
+ for (i = 0; i < amount; i++) {
|
|
|
+ struct zori_handler * handler = handlers + i;
|
|
|
+ if (!zori_widget_add_handler(widget, handler->type, handler->handler, handler->data)) return NULL;
|
|
|
+ }
|
|
|
+ return handlers + amount - 1;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
zori_id zori_start(struct zori_style * default_style) {
|
|
|
if (the_zori_root) return ZORI_ID_OK;
|
|
|
the_zori_root = calloc(1, sizeof(*the_zori_root));
|
|
@@ -166,7 +228,7 @@ zori_id zori_start(struct zori_style * default_style) {
|
|
|
the_default_style->text.font = al_create_builtin_font();
|
|
|
the_default_style->text.color = al_color_name("white");
|
|
|
the_default_style->border.color = al_color_name("white");
|
|
|
- the_default_style->back.color = al_color_name("green");
|
|
|
+ the_default_style->back.color = al_color_name("green");
|
|
|
|
|
|
if (default_style) {
|
|
|
the_zori_root->widget.style = *default_style;
|
|
@@ -174,40 +236,73 @@ zori_id zori_start(struct zori_style * default_style) {
|
|
|
the_zori_root->widget.style = *the_default_style;
|
|
|
}
|
|
|
|
|
|
- miao_init(the_zori_root->widgets);
|
|
|
the_zori_root->widget.id = 0;
|
|
|
zori_registry_add(the_zori_registry, the_zori_root->widget.id, &the_zori_root->widget);
|
|
|
-
|
|
|
-
|
|
|
- * miao_push(the_zori_root->widgets, &the_zori_root->widget);
|
|
|
- * miao_qsort(the_zori_root->widgets, zori_widget_compare);
|
|
|
- */
|
|
|
-
|
|
|
-
|
|
|
return the_zori_root->widget.id;
|
|
|
}
|
|
|
|
|
|
void zori_widget_free(struct zori_widget * widget);
|
|
|
|
|
|
struct zori_widget * zori_widget_done(struct zori_widget * widget) {
|
|
|
+ size_t index;
|
|
|
struct zori_widget * aid, * next;
|
|
|
if (!widget) return widget;
|
|
|
|
|
|
- if (widget->child) {
|
|
|
-
|
|
|
- aid = widget->child;
|
|
|
- while (aid) {
|
|
|
- next = aid->sibling;
|
|
|
- zori_widget_free(aid);
|
|
|
- aid = next;
|
|
|
- }
|
|
|
+ for (index = 0; index < miao_size(&widget->children); index ++) {
|
|
|
+ struct zori_widget * child = miao_unsafe_get(&widget->children, index);
|
|
|
+ zori_widget_free(child);
|
|
|
}
|
|
|
+
|
|
|
+ miao_done(&widget->handlers);
|
|
|
+ miao_done(&widget->children);
|
|
|
+
|
|
|
return widget;
|
|
|
}
|
|
|
|
|
|
void zori_widget_free(struct zori_widget * widget) {
|
|
|
-
|
|
|
- return free(zori_widget_done(widget));
|
|
|
+ if (widget) {
|
|
|
+ zori_registry_remove(the_zori_registry, widget->id);
|
|
|
+ }
|
|
|
+ zori_widget_done(widget);
|
|
|
+ free(widget);
|
|
|
+}
|
|
|
+
|
|
|
+struct zori_widget *
|
|
|
+zori_widget_add_child(struct zori_widget * parent, struct zori_widget * child) {
|
|
|
+ if (parent) {
|
|
|
+ miao_push((&parent->children), child);
|
|
|
+ child->parent = child;
|
|
|
+ }
|
|
|
+ return child;
|
|
|
+}
|
|
|
+
|
|
|
+struct zori_widget * zori_widget_init
|
|
|
+ ( struct zori_widget * widget,
|
|
|
+ struct zori_widget * parent, zori_rebox * box, struct zori_style * style) {
|
|
|
+
|
|
|
+ miao_init(&widget->children);
|
|
|
+ miao_init(&widget->handlers);
|
|
|
+ widget->z = 0;
|
|
|
+ widget->flags = 0;
|
|
|
+ widget->id = zori_get_unused_id();
|
|
|
+
|
|
|
+ if (style) {
|
|
|
+ widget->style = *style;
|
|
|
+ if (!widget->style.text.font) {
|
|
|
+ widget->style.text.font = the_default_style->text.font;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ widget->style = *the_default_style;
|
|
|
+ }
|
|
|
+ if (box) {
|
|
|
+ widget->box = *box;
|
|
|
+ } else if (parent) {
|
|
|
+ widget->box = parent->box;
|
|
|
+ } else {
|
|
|
+ widget->box = rebox_make(0, 0, 200, 100);
|
|
|
+ }
|
|
|
+ zori_widget_add_child(parent, widget);
|
|
|
+ return widget;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -215,17 +310,32 @@ void zori_widget_free(struct zori_widget * widget) {
|
|
|
* negative on error.
|
|
|
*/
|
|
|
zori_id zori_shutdown() {
|
|
|
- miao_done(the_zori_registry);
|
|
|
- free(the_zori_registry);
|
|
|
- the_zori_registry = NULL;
|
|
|
- free(the_default_style);
|
|
|
- the_default_style = NULL;
|
|
|
assert((void *)(&the_zori_root->widget) == (void *)the_zori_root);
|
|
|
zori_widget_free(&the_zori_root->widget);
|
|
|
the_zori_root = NULL;
|
|
|
+ free(the_default_style);
|
|
|
+ the_default_style = NULL;
|
|
|
+
|
|
|
+ miao_done(the_zori_registry);
|
|
|
+ free(the_zori_registry);
|
|
|
+ the_zori_registry = NULL;
|
|
|
+
|
|
|
+
|
|
|
return ZORI_ID_OK;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+struct zori_widget *
|
|
|
+zori_widget_initall(struct zori_widget * widget,
|
|
|
+struct zori_widget * parent, zori_rebox * box, struct zori_style * style,
|
|
|
+size_t amount, struct zori_handler * handlers) {
|
|
|
+ if (zori_widget_init(widget, parent, box, style)) {
|
|
|
+ zori_widget_add_handlers(widget, handlers, amount);
|
|
|
+ }
|
|
|
+ return widget;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
|
|
|
* you create after zori_start. */
|
|
|
zori_id zori_new_screen(zori_display * display);
|
|
@@ -267,18 +377,55 @@ zori_id zori_new_button_widget(zori_id parent, zori_rebox box, char * text);
|
|
|
|
|
|
zori_id zori_new_conversation_widget(zori_id parent, zori_rebox box, char * text);
|
|
|
|
|
|
+
|
|
|
+void zori_draw_widget(struct zori_widget * widget) {
|
|
|
+ size_t index;
|
|
|
+ if (widget && zori_widget_visible(widget)) {
|
|
|
+ zori_widget_raise_draw_event(widget);
|
|
|
+ for (index = 0; index < miao_size(&widget->children); index++) {
|
|
|
+ struct zori_widget * child = miao_unsafe_get(&widget->children, index);
|
|
|
+ zori_draw_widget(child);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
void zori_draw_all(void) {
|
|
|
+ zori_draw_widget(&the_zori_root->widget);
|
|
|
+}
|
|
|
|
|
|
+int zori_widget_visible(struct zori_widget * widget) {
|
|
|
+ return widget && ((widget->flags & ZORI_FLAG_HIDDEN) != ZORI_FLAG_HIDDEN);
|
|
|
}
|
|
|
|
|
|
+int zori_widget_active(struct zori_widget * widget) {
|
|
|
+ return widget && ((widget->flags & ZORI_FLAG_DISABLED) != ZORI_FLAG_DISABLED);
|
|
|
+}
|
|
|
+
|
|
|
+int zori_widget_active_(struct zori_widget * widget, int set) {
|
|
|
+ if (set) {
|
|
|
+ widget->flags = widget->flags & (~ZORI_FLAG_DISABLED);
|
|
|
+ } else {
|
|
|
+ widget->flags = widget->flags | ZORI_FLAG_DISABLED;
|
|
|
+ }
|
|
|
+ return zori_widget_active(widget);
|
|
|
+}
|
|
|
+
|
|
|
+int zori_widget_visible_(struct zori_widget * widget, int set) {
|
|
|
+ if (set) {
|
|
|
+ widget->flags = widget->flags & (~ZORI_FLAG_HIDDEN);
|
|
|
+ } else {
|
|
|
+ widget->flags = widget->flags | ZORI_FLAG_HIDDEN;
|
|
|
+ }
|
|
|
+ return zori_widget_active(widget);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
void zori_update(double dt)
|
|
|
{
|
|
|
- struct zori_event event;
|
|
|
- event.sysev.type = ZORI_EVENT_UPDATE;
|
|
|
- event.sysev.user.data1 = (intptr_t)&dt;
|
|
|
- zori_handlers_handle(&the_zori_root->widget.handlers, &event, &the_zori_root->widget);
|
|
|
+ zori_widget_raise_update_event(&the_zori_root->widget, dt);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -286,6 +433,521 @@ zori_id zori_register(zori_id id, zori_event_type type, zori_handler_func handl
|
|
|
|
|
|
|
|
|
|
|
|
+zori_font * zori_widget_font(struct zori_widget * widget) {
|
|
|
+ return widget->style.text.font;
|
|
|
+}
|
|
|
+
|
|
|
+zori_color zori_widget_forecolor(struct zori_widget * widget) {
|
|
|
+ return widget->style.text.color;
|
|
|
+}
|
|
|
+
|
|
|
+zori_color zori_widget_backcolor(struct zori_widget * widget) {
|
|
|
+ return widget->style.back.color;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int zori_widget_h(struct zori_widget * widget) {
|
|
|
+ return widget->box.size.y;
|
|
|
+}
|
|
|
+
|
|
|
+int zori_widget_w(struct zori_widget * widget) {
|
|
|
+ return widget->box.size.x;
|
|
|
+}
|
|
|
+
|
|
|
+int zori_widget_x(struct zori_widget * widget) {
|
|
|
+ return widget->box.at.x;
|
|
|
+}
|
|
|
+
|
|
|
+int zori_widget_y(struct zori_widget * widget) {
|
|
|
+ return widget->box.at.y;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+a c string or USTR where a line or word starts or ends with a given maxwidth. */
|
|
|
+struct zori_textinfo {
|
|
|
+ int from_char;
|
|
|
+ int start_char;
|
|
|
+ int stop_char;
|
|
|
+ int maxwidth;
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ start and stop as code positions, not byte positions. */
|
|
|
+static const USTR *
|
|
|
+ustrinfo_newref(
|
|
|
+ USTR_INFO * uinfo, const USTR * ustr, int start, int stop) {
|
|
|
+ return ustr_refustr(uinfo, ustr,
|
|
|
+ ustr_offset(ustr, start),
|
|
|
+ ustr_offset(ustr, stop)
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+textinfo (start_char and enc_char) */
|
|
|
+const USTR * zori_textinfo_refustr(struct zori_textinfo * self,
|
|
|
+ USTR_INFO * uinfo,
|
|
|
+ const USTR * ustr) {
|
|
|
+ return ustrinfo_newref(uinfo, ustr, self->start_char, self->stop_char);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+struct zori_textinfo *
|
|
|
+zori_textinfo_wordfromtext(struct zori_textinfo * self, USTR * ustr, zori_font * font) {
|
|
|
+ int found;
|
|
|
+ int start_pos;
|
|
|
+ int end_pos;
|
|
|
+ int now_char;
|
|
|
+ int end_char;
|
|
|
+ int len;
|
|
|
+ int ch;
|
|
|
+ if(!self) return NULL;
|
|
|
+ now_char = self->from_char;
|
|
|
+ self->start_char = now_char;
|
|
|
+ ch = ustr_getnext(ustr, &now_char);
|
|
|
+ while (ch > 0) {
|
|
|
+ switch(ch) {
|
|
|
+ case ' ':
|
|
|
+ self->stop_char = now_char;
|
|
|
+ return self;
|
|
|
+ case '\n':
|
|
|
+ self->stop_char = now_char;
|
|
|
+ return self;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ * by checking with al_get_ustr_width but it's not a pressing matter yet.
|
|
|
+ */
|
|
|
+ ch = ustr_getnext(ustr, &now_char);
|
|
|
+ }
|
|
|
+
|
|
|
+ self->stop_char = now_char;
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ times for a refstring.*/
|
|
|
+static int ustr_print(USTR * word) {
|
|
|
+ size_t index;
|
|
|
+ for(index = 0; index < ustr_length(word) ; index++) {
|
|
|
+ putchar(ustr_get(word, index));
|
|
|
+ }
|
|
|
+ return index;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+and store them in the given info. If the info's from is set to 0 or less,
|
|
|
+the first line is assumed, otherwise, the line will be started from "from".
|
|
|
+Uses the given font to determine the width of the text as it is built.
|
|
|
+*/
|
|
|
+struct zori_textinfo *
|
|
|
+zori_textinfo_linefromtext(struct zori_textinfo * self, USTR * ustr, zori_font * font) {
|
|
|
+ struct zori_textinfo wordinfo;
|
|
|
+ USTR_INFO lineuinfo;
|
|
|
+ const USTR * line;
|
|
|
+
|
|
|
+ USTR_INFO worduinfo = { 0, 0, 0};
|
|
|
+ const USTR * word;
|
|
|
+ int ch;
|
|
|
+ int index;
|
|
|
+ int width;
|
|
|
+ int last_stop;
|
|
|
+ self->start_char = self->from_char;
|
|
|
+ wordinfo.from_char = self->from_char;
|
|
|
+
|
|
|
+ while(zori_textinfo_wordfromtext(&wordinfo, ustr, font)) {
|
|
|
+ word = zori_textinfo_refustr(&wordinfo, &worduinfo, ustr);
|
|
|
+ line = ustrinfo_newref(&lineuinfo, ustr, self->start_char, wordinfo.stop_char);
|
|
|
+ width = al_get_ustr_width(font, line);
|
|
|
+ if (width > self->maxwidth) {
|
|
|
+
|
|
|
+ Should split single word based on length too.
|
|
|
+ There is overflow if this is still the first word as see from wordinfo_start_char.
|
|
|
+ */
|
|
|
+ if (wordinfo.start_char == self->start_char) {
|
|
|
+ self->stop_char = wordinfo.stop_char;
|
|
|
+ } else {
|
|
|
+ self->stop_char = wordinfo.start_char;
|
|
|
+ }
|
|
|
+ return self;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ ch = ustr_get(ustr, wordinfo.stop_char - 1);
|
|
|
+ if (ch == '\n') {
|
|
|
+ self->start_char = self->from_char;
|
|
|
+ self->stop_char = wordinfo.stop_char - 1;
|
|
|
+ return self;
|
|
|
+ }
|
|
|
+ wordinfo.from_char = wordinfo.stop_char;
|
|
|
+ }
|
|
|
+
|
|
|
+ self->start_char = self->from_char;
|
|
|
+ self->stop_char = wordinfo.stop_char;
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#define ZORI_WIDGET_BORDER 3
|
|
|
+
|
|
|
+
|
|
|
+void zori_widget_drawroundframe(struct zori_widget * self) {
|
|
|
+ if(!self) return;
|
|
|
+ draw_roundframe(zori_widget_x(self), zori_widget_y(self),
|
|
|
+ zori_widget_w(self), zori_widget_h(self),
|
|
|
+ ZORI_WIDGET_BORDER,
|
|
|
+ zori_widget_forecolor(self), zori_widget_backcolor(self));
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+when looping over zori_textinfo_linefromtext. */
|
|
|
+struct zori_textinfo * zori_textinfo_next(struct zori_textinfo * self) {
|
|
|
+ if(!self) return NULL;
|
|
|
+ self->from_char = self->stop_char + 1;
|
|
|
+ self->start_char = self->from_char;
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ by a console. */
|
|
|
+struct zori_console * zori_widget_console(struct zori_widget * widget) {
|
|
|
+ if (!widget) return NULL;
|
|
|
+ return ZORI_CONTAINER_OF(widget, struct zori_console, widget);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+void zori_console_command_(struct zori_console * self, zori_console_command * command, void * data) {
|
|
|
+ self->command = command;
|
|
|
+ self->command_data = data;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+zero if OK. */
|
|
|
+int zori_console_docommand(struct zori_console * self, const char * text) {
|
|
|
+ if(!self) return -1;
|
|
|
+ if(!self->command) return -2;
|
|
|
+ return self->command(&self->widget, text, self->command_data);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+int zori_console_addstr(struct zori_console * self, const char * str) {
|
|
|
+ if(!self) return -1;
|
|
|
+ if(!ustrlist_shiftcstr(&self->text, str)) {
|
|
|
+ return -3;
|
|
|
+ }
|
|
|
+ while(ustrlist_size(&self->text) >= self->max) {
|
|
|
+ ustrlist_droplast(&self->text);
|
|
|
+ }
|
|
|
+ return ustrlist_size(&self->text);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int zori_console_addustr(struct zori_console * self, const USTR * ustr) {
|
|
|
+ if(!self) return -1;
|
|
|
+ if(!ustrlist_shiftustr(&self->text, ustr)) {
|
|
|
+ return -3;
|
|
|
+ }
|
|
|
+ while(ustrlist_size(&self->text) >= self->max) {
|
|
|
+ ustrlist_droplast(&self->text);
|
|
|
+ }
|
|
|
+ return ustrlist_size(&self->text);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+int zori_console_puts(struct zori_console * self, const char * str) {
|
|
|
+ int index;
|
|
|
+ int size = strlen(str);
|
|
|
+ int leftsize = size;
|
|
|
+ int lines = 0;
|
|
|
+ USTR_INFO uinfo;
|
|
|
+ struct zori_textinfo info = { 0, 0, 0, 0};
|
|
|
+ info.maxwidth = zori_widget_w(&self->widget) - 10;
|
|
|
+ USTR * ustr;
|
|
|
+ const USTR * uline;
|
|
|
+ ustr = ustr_new(str);
|
|
|
+ while(zori_textinfo_linefromtext(&info, ustr, self->widget.style.text.font)) {
|
|
|
+ uline = zori_textinfo_refustr(&info, &uinfo, ustr);
|
|
|
+ zori_console_addustr(self, uline);
|
|
|
+
|
|
|
+ zori_textinfo_next(&info);
|
|
|
+ }
|
|
|
+ uline = zori_textinfo_refustr(&info, &uinfo, ustr);
|
|
|
+ zori_console_addustr(self, uline);
|
|
|
+ ustr_free(ustr);
|
|
|
+ return lines;
|
|
|
+}
|
|
|
+
|
|
|
+#define BBCONSOLE_VPRINTF_MAX 1024
|
|
|
+
|
|
|
+
|
|
|
+int zori_console_vprintf(struct zori_console * self, const char * format, va_list args) {
|
|
|
+ char buffer[BBCONSOLE_VPRINTF_MAX] = { '\0' };
|
|
|
+ vsnprintf(buffer, BBCONSOLE_VPRINTF_MAX, format, args);
|
|
|
+ return zori_console_puts(self, buffer);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int zori_console_printf(struct zori_console * self, const char * format, ...) {
|
|
|
+ int result;
|
|
|
+ va_list args;
|
|
|
+ va_start(args, format);
|
|
|
+ result = zori_console_vprintf(self, format, args);
|
|
|
+ va_end(args);
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+int zori_console_draw(union zori_event * zevent) {
|
|
|
+ struct zori_console * self ;
|
|
|
+ zori_font * font ;
|
|
|
+ zori_color color ;
|
|
|
+ USTRListNode * now;
|
|
|
+ int high, linehigh, index, x, y, skip;
|
|
|
+ int linew;
|
|
|
+ struct zori_widget * widget = zevent->any.widget;
|
|
|
+
|
|
|
+ if (!zori_widget_visible(widget)) return ZORI_HANDLE_IGNORE;
|
|
|
+
|
|
|
+ self = zori_widget_console(widget);
|
|
|
+ font = zori_widget_font(widget);
|
|
|
+ color = zori_widget_forecolor(widget);
|
|
|
+
|
|
|
+ zori_widget_drawroundframe(widget);
|
|
|
+ high = zori_widget_h(widget) - 10;
|
|
|
+ x = zori_widget_x(widget) + 5;
|
|
|
+ y = zori_widget_y(widget) - 5;
|
|
|
+ linehigh = zori_font_lineheight(font);
|
|
|
+
|
|
|
+ now = ustrlist_head(&self->text);
|
|
|
+
|
|
|
+ now = ustrlist_skipnode(&self->text, self->start);
|
|
|
+
|
|
|
+ for (index = high-(linehigh*2); index > 0; index -= linehigh) {
|
|
|
+ USTR * textstr;
|
|
|
+ if(!now) break;
|
|
|
+ textstr = ustrlistnode_ustr(now);
|
|
|
+ if(textstr) {
|
|
|
+ zori_font_drawstr(font, color, x, y + index, 0, textstr);
|
|
|
+ }
|
|
|
+ now = ustrlistnode_next(now);
|
|
|
+ }
|
|
|
+
|
|
|
+ zori_font_drawstr(font, color, x, y + high - linehigh, 0, self->input);
|
|
|
+
|
|
|
+ linew = al_get_ustr_width(font, self->input);
|
|
|
+ al_draw_line(x + linew, y + high - linehigh, x + linew, y + high, color, 1);
|
|
|
+
|
|
|
+ al_draw_textf(font, color, x, y, 0, "start: %d, size: %d", self->start,
|
|
|
+ ustrlist_size(&self->text));
|
|
|
+ return ZORI_HANDLE_OK;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void zori_console_active_(struct zori_console * self, int active) {
|
|
|
+ if(!self) return;
|
|
|
+ zori_widget_active_(&self->widget, active);
|
|
|
+ zori_widget_visible_(&self->widget, active);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int zori_console_active(struct zori_console * self) {
|
|
|
+ if(!self) return 0;
|
|
|
+ return zori_widget_active(&self->widget);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int zori_console_scroll(struct zori_console * self, int direction) {
|
|
|
+ if((!self) || (!direction)) return FALSE;
|
|
|
+ if(direction < 0) self->start--;
|
|
|
+ if(direction > 0) self->start++;
|
|
|
+
|
|
|
+ self->start = bad_clampi(self->start, 0, ustrlist_size(&self->text));
|
|
|
+ return ZORI_HANDLE_OK;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+int zori_console_handle_keychar(union zori_event * zevent) {
|
|
|
+ struct zori_console * self = zori_widget_console(zori_event_widget(zevent));
|
|
|
+ zori_system_event * event = zori_event_system_event(zevent);
|
|
|
+ int ch = event->keyboard.unichar;
|
|
|
+ int kc = event->keyboard.keycode;
|
|
|
+ switch(kc) {
|
|
|
+
|
|
|
+ case ALLEGRO_KEY_F1:
|
|
|
+ case ALLEGRO_KEY_F3:
|
|
|
+ return ZORI_HANDLE_OK;
|
|
|
+ case ALLEGRO_KEY_PGUP: return zori_console_scroll(self, 1);
|
|
|
+ case ALLEGRO_KEY_PGDN: return zori_console_scroll(self, -1);
|
|
|
+ case ALLEGRO_KEY_BACKSPACE:
|
|
|
+
|
|
|
+ ustr_remove_chr(self->input, ustr_offset(self->input, -1));
|
|
|
+ return ZORI_HANDLE_OK;
|
|
|
+ break;
|
|
|
+ case ALLEGRO_KEY_ENTER: {
|
|
|
+ const char * command = ustr_c(self->input);
|
|
|
+
|
|
|
+ if(zori_console_docommand(self, command)) {
|
|
|
+ zori_console_puts(self, "Error in running comand");
|
|
|
+ zori_console_puts(self, command);
|
|
|
+ }
|
|
|
+ ustr_truncate(self->input, 0);
|
|
|
+
|
|
|
+ return ZORI_HANDLE_OK;
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ ustr_appendch(self->input, ch);
|
|
|
+ return ZORI_HANDLE_OK;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+int zori_console_handle_keydown(union zori_event * zevent) {
|
|
|
+ struct zori_console * self = zori_widget_console(zori_event_widget(zevent));
|
|
|
+ zori_system_event * event = zori_event_system_event(zevent);
|
|
|
+ int ch = event->keyboard.unichar;
|
|
|
+ int kc = event->keyboard.keycode;
|
|
|
+ switch(kc) {
|
|
|
+ case ALLEGRO_KEY_F1:
|
|
|
+ case ALLEGRO_KEY_F3:
|
|
|
+ zori_console_active_(self, false);
|
|
|
+
|
|
|
+ * Note: this shouldnever happen if react is set up well.
|
|
|
+ */
|
|
|
+ return ZORI_HANDLE_OK;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return ZORI_HANDLE_IGNORE;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int zori_console_handle_mouseaxes(union zori_event * zevent) {
|
|
|
+ struct zori_console * self = zori_widget_console(zori_event_widget(zevent));
|
|
|
+ zori_system_event * event = zori_event_system_event(zevent);
|
|
|
+ int z = event->mouse.dz;
|
|
|
+
|
|
|
+ if(z == 0) return ZORI_HANDLE_IGNORE;
|
|
|
+ if(z < 0) return zori_console_scroll(self, -1);
|
|
|
+ if(z > 0) return zori_console_scroll(self, +1);
|
|
|
+ return ZORI_HANDLE_OK;
|
|
|
+}
|
|
|
+
|
|
|
+int zori_console_handle_ignore(union zori_event * zevent) {
|
|
|
+ return ZORI_HANDLE_IGNORE;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static struct zori_handler zori_console_actions[] = {
|
|
|
+ { ZORI_SYSTEM_EVENT_KEY_DOWN , zori_console_handle_keydown , NULL },
|
|
|
+ { ZORI_SYSTEM_EVENT_KEY_UP , zori_console_handle_ignore , NULL },
|
|
|
+ { ZORI_SYSTEM_EVENT_KEY_CHAR , zori_console_handle_keychar , NULL },
|
|
|
+ { ZORI_SYSTEM_EVENT_MOUSE_AXES, zori_console_handle_mouseaxes , NULL },
|
|
|
+ { ZORI_EVENT_DRAW , zori_console_draw , NULL },
|
|
|
+ { ZORI_EVENT_DONE , zori_console_handle_ignore , NULL },
|
|
|
+ { ZORI_EVENT_FREE , zori_console_handle_ignore , NULL },
|
|
|
+ { -1, NULL, NULL }
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+positive if not, and negative on error. */
|
|
|
+
|
|
|
+int zori_console_handle(struct zori_widget * widget, zori_system_event * sevent) {
|
|
|
+ union zori_event zevent;
|
|
|
+ if (!widget) return ZORI_HANDLE_ERROR;
|
|
|
+ if (!zori_widget_active(widget)) return ZORI_HANDLE_IGNORE;
|
|
|
+ return zori_widget_raise_system_event(widget, sevent);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+int zori_console_done(struct zori_widget * widget) {
|
|
|
+ struct zori_console * self = zori_widget_console(widget);
|
|
|
+ if(!self) return ZORI_HANDLE_IGNORE;
|
|
|
+ free(self->buf);
|
|
|
+ self->buf = NULL;
|
|
|
+ ustr_free(self->input);
|
|
|
+ self->input = NULL;
|
|
|
+ ustrlist_done(&self->text);
|
|
|
+ return ZORI_HANDLE_OK;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+int zori_console_free(struct zori_widget * widget) {
|
|
|
+ struct zori_console * self = zori_widget_console(widget);
|
|
|
+ zori_console_done(&self->widget);
|
|
|
+ free(self);
|
|
|
+ return ZORI_HANDLE_OK;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+struct zori_console * zori_console_alloc() {
|
|
|
+ return calloc(1 , sizeof(struct zori_console));
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#define ZORI_CONSOLE_MAX 200
|
|
|
+
|
|
|
+
|
|
|
+struct zori_console * zori_console_initall(struct zori_console * self, int id, zori_rebox * bounds, struct zori_style * style) {
|
|
|
+ if(!self) return NULL;
|
|
|
+ if(!zori_widget_initall(&self->widget, &the_zori_root->widget, bounds, style, 7, zori_console_actions)) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ ustrlist_init(&self->text);
|
|
|
+
|
|
|
+ zori_widget_active_(&self->widget, FALSE);
|
|
|
+ self->count = 0;
|
|
|
+
|
|
|
+ self->max = ZORI_CONSOLE_MAX;
|
|
|
+ self->start = 0;
|
|
|
+ self->charw = 80;
|
|
|
+ self->buf = calloc(self->charw + 1, 1);
|
|
|
+
|
|
|
+ if (!self->buf) { zori_console_done(&self->widget); return NULL; }
|
|
|
+ self->input = ustr_new("");
|
|
|
+ self->cursor= 0;
|
|
|
+ if (!self->input) { zori_console_done(&self->widget); return NULL; }
|
|
|
+ self->command = NULL;
|
|
|
+ self->command_data = NULL;
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+struct zori_console * zori_console_new(int id, zori_rebox * bounds, struct zori_style * style) {
|
|
|
+ struct zori_console * self = zori_console_alloc();
|
|
|
+ if(!zori_console_initall(self, id, bounds, style)) {
|
|
|
+ zori_console_free(&self->widget);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
|
|
|
|