Browse Source

Work on GUI subsystem, move console to it's own C file.

Beoran 7 years ago
parent
commit
7d875c99c7

+ 2 - 12
include/rebox.h

@@ -14,13 +14,6 @@ struct Rebox_ {
 };
 
 
-/* This file was generated with:
-'cfunctions -c -aoff -n -w rebox_proto src/rebox.c' */
-#ifndef CFH_REBOX_PROTO
-#define CFH_REBOX_PROTO
-
-/* From 'src/rebox.c': */
-
 Rebox rebox_make (int x , int y , int w , int h );
 
 Rebox * rebox_initbounds (Rebox * self , Rebox bounds );
@@ -67,12 +60,9 @@ double rebox_delta_x (Rebox * self , Rebox * other );
 
 double rebox_delta_y (Rebox * self , Rebox * other );
 
-#endif /* CFH_REBOX_PROTO */
+int rebox_coordinates_inside_p(Rebox * self, double x, double y);
 
+int rebox_point_inside_p(Rebox * self, Point * point);
 
 
 #endif
-
-
-
-

+ 26 - 50
include/zori/zori.h

@@ -15,10 +15,13 @@
 /* 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_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. */
@@ -32,8 +35,11 @@ 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)
@@ -53,11 +59,11 @@ typedef ALLEGRO_USTR zori_string;
 
 
 /** Macro for the number of elements of an array .*/
-#define ZORI_ARRAY_AMOUNT(A) ((sizeof(A))/(sizeof(*A)))
+#define ZORI_ARRAY_AMOUNT(A) ((size_t)(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 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)
@@ -256,6 +262,10 @@ enum zori_flag {
   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 actovation by the keyjoy cursor */
+  ZORI_FLAG_MARKED      = 1 << 3,
 };
 
 
@@ -435,10 +445,15 @@ 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);
+struct zori_widget *zori_widget_initall(struct zori_widget *widget, 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_active(struct zori_widget *widget);
+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);
@@ -448,50 +463,11 @@ 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.
-};
+int zori_xy_inside_widget_p(struct zori_widget * widget, double x, double y);
 
 
+void zori_widget_drawroundframe(struct zori_widget *self);
 
-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);
 

+ 1 - 1
include/zori/zori_button.h

@@ -5,7 +5,7 @@
 
 struct zori_button {
     struct zori_widget widget;
-    zori_string      * caption;
+    zori_string      * text;
     int                align;
 };
 

+ 41 - 0
include/zori/zori_console.h

@@ -1,6 +1,47 @@
 #ifndef zori_console_H_INCLUDED
 #define zori_console_H_INCLUDED
 
+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);
+
 
 
 #endif

+ 1 - 1
include/zori/zori_widget.h

@@ -1,7 +1,7 @@
 #ifndef zori_widget_H_INCLUDED
 #define zori_widget_H_INCLUDED
 
-
+void zori_widget_draw_background(struct zori_widget * widget);
 
 #endif
 

+ 13 - 0
src/rebox.c

@@ -127,8 +127,21 @@ Point rebox_center_(Rebox * self, Point center) {
   return rebox_at_(self, at);
 }
 
+/* Returns TRUE if the coordinates x and y are inside self, FALSE if not. */
+int rebox_coordinates_inside_p(Rebox * self, double x, double y) {
+  if (x < self->at.x) return FALSE;
+  if (y < self->at.y) return FALSE;
+  if (x > rebox_br_x(self)) return FALSE;
+  if (y > rebox_br_y(self)) return FALSE;
+  return TRUE;
+}
 
 
+/* Returns TRUE if the point is inside self, FALSE if not. */
+int rebox_point_inside_p(Rebox * self, Point * point) {
+  return rebox_coordinates_inside_p(self, point->x, point->y);
+}
+
 /* Returns TRUE if box 2 if other is wholly inside self, FALSE if not. */
 int rebox_inside_p(Rebox * self, Rebox * other) {
   if (other->at.x < self->at.x) return FALSE;

+ 1 - 1
src/state.c

@@ -21,7 +21,7 @@
 #include "store.h"
 #include "zori.h"
 #include "zori_screen.h"
-
+#include "zori_console.h"
 
 /* Sub data struct for the particular GUI state */
 struct GuiState {

+ 35 - 494
src/zori/zori.c

@@ -1,5 +1,6 @@
 
 #include "zori.h"
+#include "zori_console.h"
 #include "miao.h"
 #include <allegro5/allegro_color.h>
 #include "str.h"
@@ -404,7 +405,7 @@ zori_id zori_shutdown() {
 struct zori_widget * 
 zori_widget_initall(struct zori_widget * widget, int id,
 struct zori_widget * parent, zori_rebox * box, struct zori_style * style, 
-size_t amount, struct zori_handler * handlers) {
+struct zori_handler * handlers, size_t amount) {
   if (zori_widget_init(widget, id, parent, box, style)) {
     zori_widget_add_handlers(widget, handlers, amount);
   }
@@ -507,6 +508,39 @@ int zori_widget_visible_(struct zori_widget * widget, int set)  {
 }
 
 
+int zori_widget_hover(struct zori_widget * widget)  {
+  return widget && ((widget->flags & ZORI_FLAG_HOVERED) != ZORI_FLAG_HOVERED);
+}
+
+int zori_widget_hover_(struct zori_widget * widget, int set)  {
+  if (set) {  
+    widget->flags = widget->flags & (~ZORI_FLAG_HOVERED);
+  } else {
+    widget->flags = widget->flags | ZORI_FLAG_HOVERED;
+  }
+  return zori_widget_hover(widget);
+}
+
+int zori_widget_marked(struct zori_widget * widget)  {
+  return widget && ((widget->flags & ZORI_FLAG_MARKED) != ZORI_FLAG_MARKED);
+}
+
+int zori_widget_marked_(struct zori_widget * widget, int set)  {
+  if (set) {  
+    widget->flags = widget->flags & (~ZORI_FLAG_MARKED);
+  } else {
+    widget->flags = widget->flags | ZORI_FLAG_MARKED;
+  }
+  return zori_widget_hover(widget);
+}
+
+
+int zori_xy_inside_widget_p(struct zori_widget * widget, double x, double y) {
+    return (rebox_coordinates_inside_p(&widget->box, x, y));
+}
+
+
+
 /* Updates the state of the UI. Pass in the time passed since last update. */
 void zori_update(double dt) 
 {
@@ -547,499 +581,6 @@ int zori_widget_y(struct zori_widget * widget) {
 }
 
 
-/* Helper struct that keeps track of the BYTE positions within 
-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;
-};
-
-
-/* Creates a temporary ustr as per al_ref_ustr but with 
- 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)
-                     );
-}
-
-
-
-/* Creates a temporary ustr that refers ustr but respecds the bounds of the 
-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 ' ': /* Found a space, here the word ends, include the space. */
-        self->stop_char = now_char;
-        return self;
-      case '\n': /* A newline ends a word, include the newline. */
-        self->stop_char = now_char;
-        return self;
-      default: /* Other characters mean the word is not finished yet. */
-        break;
-    }
-    /* XXX: Should handle the case for languages that use no spaces, 
-    * by checking with al_get_ustr_width but it's not a pressing matter yet.
-    */
-    ch = ustr_getnext(ustr, &now_char); 
-  } 
-  // no word found, just set end here and be done. 
-  self->stop_char = now_char;
-  /* return nULL to signify end */
-  return NULL;
-}
-
-
-/** Prints a ustring, since puts or printf print too much some
- 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;
-}
-
-
-/** Gets the positions of the next line of text fort he given Unicode string 
-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) { 
-      /* XXX: handle case of text overflow by bluntly retuning the word as is.
-      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;
-    }
-    // If we get here, the word way still end on a newline character 
-    // check this case. XXX: It works like this because 
-    // stop_char is a bit wonky... it points at the first character of the 
-    // next word in this case...
-    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;
-  }
-  /* if we get here, the whole string fits. */
-  self->start_char = self->from_char;
-  self->stop_char  = wordinfo.stop_char;
-  /* Return NULL to tell caller text has been completely split up. */
-  return NULL;
-}
-
-
-
-#define ZORI_WIDGET_BORDER 3 
-
-/** Draws a rounded frame as background for a widget. */
-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));
-}
-
-
-/** Skips the text info to the next word or line of text. Must be called 
-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;
-}
-
-
-
-/* Converts a widget to a console. Only works if the pointer is wrapped correctly,
- 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);
-}
-
-
-/** Sets the console's command function and data. */
-void zori_console_command_(struct zori_console * self, zori_console_command * command, void * data) {
-  self->command      = command;
-  self->command_data = data;
-}
-
-/** Let the console perform a command if possible. returns nonzero on error,
-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);
-}
-
-
-
-/** Adds a line of text to the console. */
-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) { // remove last node(s)
-    ustrlist_droplast(&self->text);
-  }
-  return ustrlist_size(&self->text);
-}
-
-/** Adds a line of text to the console. */
-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) { // remove last node(s)
-    ustrlist_droplast(&self->text);
-  }
-  return ustrlist_size(&self->text);
-}
-
-
-/** Puts a string on the console .*/
-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);
-    // don't forget to skip to next line!!!
-    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
-
-/** Prints a formatted string on the console, truncaded to 1024 characters.  */
-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);
-}
-
-/** Prints a formatted string on the console, truncaded to 1024 characters.  */
-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;
-}
-
-
-/** Draws a console. */
-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); */
-  /* skip start lines (to allow scrolling backwards) */
-  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);
-  }
-  // draw input string
-  if (self->input) { 
-    zori_font_drawstr(font, color, x, y + high - linehigh, 0, self->input);
-  }
-  // Draw cursor
-  linew = al_get_ustr_width(font, self->input);
-  al_draw_line(x + linew, y + high - linehigh, x + linew, y + high, color, 1);
-  // draw start for debugging
-  al_draw_textf(font, color, x, y, 0, "start: %d, size: %d", self->start, 
-                ustrlist_size(&self->text));
-  return ZORI_HANDLE_PASS;
-}
-
-/** Activates or deactivates the console. */
-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);
-}
-
-/** Returns nonzero if console is active zero if not. */
-int zori_console_active(struct zori_console * self) {
-  if(!self) return 0;
-  return zori_widget_active(&self->widget);
-}
-
-/** scrolls the console 1 step in the given direction. */
-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++;
-  /* Clamp start between 0 and size of list. */
-  self->start = bad_clampi(self->start, 0, ustrlist_size(&self->text));
-  return ZORI_HANDLE_DONE;
-}
-
-
-
-/* Key input event handler for console. */
-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) {
-    // ignore the start-console key
-    case ALLEGRO_KEY_F1:
-    case ALLEGRO_KEY_F3:
-      return ZORI_HANDLE_DONE;
-    case ALLEGRO_KEY_PGUP: return zori_console_scroll(self, 1);
-    case ALLEGRO_KEY_PGDN: return zori_console_scroll(self, -1);
-    case ALLEGRO_KEY_BACKSPACE:
-      // remove last character typed.
-      ustr_remove_chr(self->input, ustr_offset(self->input, -1));
-      return ZORI_HANDLE_DONE;
-    break;    
-    case ALLEGRO_KEY_ENTER: {
-      const char * command = ustr_c(self->input);
-      // execute command
-      if(zori_console_docommand(self, command)) { 
-        zori_console_puts(self, "Error in running comand");
-        zori_console_puts(self, command);
-      }
-      ustr_truncate(self->input, 0);
-      // empty string by truncating it
-      return ZORI_HANDLE_DONE;
-      }
-    default:
-    break;
-  }
-  
-  ustr_appendch(self->input, ch);
-  return ZORI_HANDLE_DONE;
-}
-
-
-/* Key down event handler for console. */
-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); 
-      /* disable console if F1 is pressed. 
-       * Note: this shouldnever happen if react is set up well.
-       */ 
-      return ZORI_HANDLE_DONE;
-    default:
-    break;
-  }
-  return ZORI_HANDLE_IGNORE;
-}
-
-/* Mouse axe event handler for console */
-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;
-  // only capture mouse scroll wheel...
-  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_DONE;
-}
-
-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 }
-};
-
-
-/** Let the console handle allegro events. Returns 0 if event was consumed,
-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);
-}
-
-
-/** Cleans up a console. */
-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_DONE;
-}
-
-
-/** Deallocates a console. */
-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_DONE;
-}
-
-/** Allocates a console. */
-struct zori_console * zori_console_alloc() {
-  return calloc(1 , sizeof(struct zori_console));
-}
-
-/* Amount of lines of display the console hat o keep track of. */
-#define ZORI_CONSOLE_MAX 200
-
-/** Initializes a console. */
-struct zori_console * zori_console_initall(struct zori_console * self, int id, zori_rebox * bounds, struct zori_style * style) {
-  if(!self) return NULL;
-  /* Allow only a single console. */
-  if (the_zori_root->console) return NULL;
-  if(!zori_widget_initall(&self->widget, id, &the_zori_root->widget, bounds, style, 7, zori_console_actions)) { 
-    return NULL;
-  }
-  ustrlist_init(&self->text);
-  // ustrlist_shiftcstr(&self->text, "empty line");
-  zori_widget_active_(&self->widget, FALSE);
-  self->count = 0;
-  // max MUST be at least 2, 3 to see anything...
-  self->max   = ZORI_CONSOLE_MAX;
-  self->start = 0;
-  self->charw = 80; 
-  self->buf   = calloc(self->charw + 1, 1);
-   // one extra for NULL at end . 
-  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;
-  /* Ony one console may be active. */
-  the_zori_root->console = self;
-  return self;
-}
-
-/** Initializes a new console. */
-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;
-}
-
-
-
 
 
 

+ 101 - 0
src/zori/zori_button.c

@@ -1,9 +1,110 @@
 
+#include "zori.h"
+#include "zori_widget.h"
 #include "zori_button.h"
 
+struct zori_button * zori_widget_to_button(struct zori_widget * widget) {
+  return ZORI_CONTAINER_OF(widget, struct zori_button, widget);
+}
 
 
+/** Handles a mouse axis event and pass it on.  */
+int zori_button_on_mouse_axes(union zori_event * event) { 
+    struct zori_widget * widget = event->any.widget;
+    struct zori_button * button = zori_widget_to_button(widget);
+    float x = event->sys.ev->mouse.x;
+    float y = event->sys.ev->mouse.y;
+    if (zori_xy_inside_widget_p(widget, x, y)) {
+      zori_widget_hover_(widget, TRUE);
+    } else {
+      zori_widget_hover_(widget, FALSE);
+    } 
+    
+    return ZORI_HANDLE_PASS;
+}
 
+/** Handles a mouse click event and pass it on.  */
+int zori_button_on_mouse_click(union zori_event * event) { 
+    struct zori_widget * widget = event->any.widget;
+    struct zori_button * button = zori_widget_to_button(widget);
+    float x = event->sys.ev->mouse.x;
+    float y = event->sys.ev->mouse.y;
+    if (zori_xy_inside_widget_p(widget, x, y)) {
+      return zori_widget_raise_action_event(widget);
+    } 
+    return ZORI_HANDLE_PASS;
+}
 
 
+void zori_draw_button(struct zori_button * button) {
+  float x, y, w, h;
+  struct zori_style * style = &button->widget.style; 
+  x = rebox_x(&button->widget.box) + 5;
+  y = rebox_y(&button->widget.box) + 5;
+  w = rebox_w(&button->widget.box) - 10;
+  h = rebox_h(&button->widget.box) - 10;
+  
+  zori_widget_draw_background(&button->widget);
+  if (button->text) {
+    zori_font * font = style->text.font;
+    zori_color color = style->text.color;
+    al_draw_multiline_ustr(font, color, x, y, w, -1,  ALLEGRO_ALIGN_LEFT, button->text);
+  }
+  
+};
+ 
+int zori_button_on_draw(union zori_event * event) {
+  struct zori_button * button = zori_widget_to_button(event->any.widget);
+  zori_draw_button(button);
+  return ZORI_HANDLE_PASS;
+}
+
+
+struct zori_handler zori_button_handlers[] = {
+  { ZORI_SYSTEM_EVENT_MOUSE_BUTTON_DOWN , zori_button_on_mouse_click   , NULL },
+  { ZORI_SYSTEM_EVENT_MOUSE_AXES        , zori_button_on_mouse_axes    , NULL },
+  { ZORI_EVENT_DRAW                     , zori_button_on_draw          , NULL },
+  { -1, NULL, NULL }
+};
+
+
+struct zori_button * 
+zori_button_text_(struct zori_button * button, zori_string * text) {
+  if (button->text) {
+    al_ustr_free(button->text);
+    button->text = NULL;
+  }
+  if (text) {
+    button->text = al_ustr_dup(text);
+  }
+  return button;
+}
+
+struct zori_button * 
+zori_button_init(struct zori_button * button, zori_string * text) {
+  button->text        = NULL; 
+  return zori_button_text_(button, text); 
+}
+
+struct zori_button * zori_button_new(zori_id id, zori_id parent, 
+  zori_box * box, zori_string * text) {
+  struct zori_button * button = NULL;
+  button = calloc(1, sizeof(*button));
+  if (!button) return NULL;
+  zori_widget_initall(&button->widget, id, zori_get_widget(parent), 
+                      box, NULL, ZORI_ARRAY_AND_AMOUNT(zori_button_handlers)); 
+  if (!zori_button_init(button, text)) {
+    free(button);
+    button = NULL;
+  }
+  return button;
+}
+
+
+zori_id zori_new_button(zori_id id, zori_id parent, zori_box * box, zori_string * text) {
+  struct zori_button * button = zori_button_new(id, parent, box, text);
+  if (!button) return ZORI_ID_ENOMEM;
+  return button->widget.id;
+}
+
 

+ 497 - 1
src/zori/zori_console.c

@@ -1,8 +1,504 @@
-
+#include "zori.h"
 #include "zori_console.h"
 
 
 
+/* Helper struct that keeps track of the BYTE positions within 
+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;
+};
+
+
+/* Creates a temporary ustr as per al_ref_ustr but with 
+ 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)
+                     );
+}
+
+
+
+/* Creates a temporary ustr that refers ustr but respecds the bounds of the 
+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 ' ': /* Found a space, here the word ends, include the space. */
+        self->stop_char = now_char;
+        return self;
+      case '\n': /* A newline ends a word, include the newline. */
+        self->stop_char = now_char;
+        return self;
+      default: /* Other characters mean the word is not finished yet. */
+        break;
+    }
+    /* XXX: Should handle the case for languages that use no spaces, 
+    * by checking with al_get_ustr_width but it's not a pressing matter yet.
+    */
+    ch = ustr_getnext(ustr, &now_char); 
+  } 
+  // no word found, just set end here and be done. 
+  self->stop_char = now_char;
+  /* return nULL to signify end */
+  return NULL;
+}
+
+
+/** Prints a ustring, since puts or printf print too much some
+ 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;
+}
+
+
+/** Gets the positions of the next line of text fort he given Unicode string 
+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) { 
+      /* XXX: handle case of text overflow by bluntly retuning the word as is.
+      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;
+    }
+    // If we get here, the word way still end on a newline character 
+    // check this case. XXX: It works like this because 
+    // stop_char is a bit wonky... it points at the first character of the 
+    // next word in this case...
+    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;
+  }
+  /* if we get here, the whole string fits. */
+  self->start_char = self->from_char;
+  self->stop_char  = wordinfo.stop_char;
+  /* Return NULL to tell caller text has been completely split up. */
+  return NULL;
+}
+
+
+
+#define ZORI_WIDGET_BORDER 3 
+
+/** Draws a rounded frame as background for a widget. */
+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));
+}
+
+
+/** Skips the text info to the next word or line of text. Must be called 
+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;
+}
+
+
+
+/* Converts a widget to a console. Only works if the pointer is wrapped correctly,
+ 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);
+}
+
+
+/** Sets the console's command function and data. */
+void zori_console_command_(struct zori_console * self, zori_console_command * command, void * data) {
+  self->command      = command;
+  self->command_data = data;
+}
+
+/** Let the console perform a command if possible. returns nonzero on error,
+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);
+}
+
+
+
+/** Adds a line of text to the console. */
+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) { // remove last node(s)
+    ustrlist_droplast(&self->text);
+  }
+  return ustrlist_size(&self->text);
+}
+
+/** Adds a line of text to the console. */
+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) { // remove last node(s)
+    ustrlist_droplast(&self->text);
+  }
+  return ustrlist_size(&self->text);
+}
+
+
+/** Puts a string on the console .*/
+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);
+    // don't forget to skip to next line!!!
+    zori_textinfo_next(&info);
+  }
+  uline = zori_textinfo_refustr(&info, &uinfo, ustr);
+  zori_console_addustr(self, uline);
+  ustr_free(ustr);
+  return lines;
+} 
+
+#define ZORI_CONSOLE_VPRINTF_MAX 1024
+
+/** Prints a formatted string on the console, truncaded to 1024 characters.  */
+int zori_console_vprintf(struct zori_console * self, const char * format, va_list args) {
+  char buffer[ZORI_CONSOLE_VPRINTF_MAX] = { '\0' };
+  vsnprintf(buffer, sizeof(buffer), format, args);
+  return zori_console_puts(self, buffer);
+}
+
+/** Prints a formatted string on the console, truncaded to 1024 characters.  */
+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;
+}
+
+
+/** Draws a console. */
+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); */
+  /* skip start lines (to allow scrolling backwards) */
+  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);
+  }
+  // draw input string
+  if (self->input) { 
+    zori_font_drawstr(font, color, x, y + high - linehigh, 0, self->input);
+  }
+  // Draw cursor
+  linew = al_get_ustr_width(font, self->input);
+  al_draw_line(x + linew, y + high - linehigh, x + linew, y + high, color, 1);
+  // draw start for debugging
+  al_draw_textf(font, color, x, y, 0, "start: %d, size: %d", self->start, 
+                ustrlist_size(&self->text));
+  return ZORI_HANDLE_PASS;
+}
+
+/** Activates or deactivates the console. */
+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);
+}
+
+/** Returns nonzero if console is active zero if not. */
+int zori_console_active(struct zori_console * self) {
+  if(!self) return 0;
+  return zori_widget_active(&self->widget);
+}
+
+/** scrolls the console 1 step in the given direction. */
+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++;
+  /* Clamp start between 0 and size of list. */
+  self->start = bad_clampi(self->start, 0, ustrlist_size(&self->text));
+  return ZORI_HANDLE_DONE;
+}
+
+
+
+/* Key input event handler for console. */
+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) {
+    // ignore the start-console key
+    case ALLEGRO_KEY_F1:
+    case ALLEGRO_KEY_F3:
+      return ZORI_HANDLE_DONE;
+    case ALLEGRO_KEY_PGUP: return zori_console_scroll(self, 1);
+    case ALLEGRO_KEY_PGDN: return zori_console_scroll(self, -1);
+    case ALLEGRO_KEY_BACKSPACE:
+      // remove last character typed.
+      ustr_remove_chr(self->input, ustr_offset(self->input, -1));
+      return ZORI_HANDLE_DONE;
+    break;    
+    case ALLEGRO_KEY_ENTER: {
+      const char * command = ustr_c(self->input);
+      // execute command
+      if(zori_console_docommand(self, command)) { 
+        zori_console_puts(self, "Error in running comand");
+        zori_console_puts(self, command);
+      }
+      ustr_truncate(self->input, 0);
+      // empty string by truncating it
+      return ZORI_HANDLE_DONE;
+      }
+    default:
+    break;
+  }
+  
+  ustr_appendch(self->input, ch);
+  return ZORI_HANDLE_DONE;
+}
+
+
+/* Key down event handler for console. */
+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); 
+      /* disable console if F1 is pressed. 
+       * Note: this shouldnever happen if react is set up well.
+       */ 
+      return ZORI_HANDLE_DONE;
+    default:
+    break;
+  }
+  return ZORI_HANDLE_IGNORE;
+}
+
+/* Mouse axe event handler for console */
+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;
+  // only capture mouse scroll wheel...
+  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_DONE;
+}
+
+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 }
+};
+
+
+/** Let the console handle allegro events. Returns 0 if event was consumed,
+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);
+}
+
+
+/** Cleans up a console. */
+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_DONE;
+}
+
+
+/** Deallocates a console. */
+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_DONE;
+}
+
+/** Allocates a console. */
+struct zori_console * zori_console_alloc() {
+  return calloc(1 , sizeof(struct zori_console));
+}
+
+/* Amount of lines of display the console hat o keep track of. */
+#define ZORI_CONSOLE_MAX 200
+
+/** Initializes a console. */
+struct zori_console * zori_console_initall(struct zori_console * self, int id, zori_rebox * bounds, struct zori_style * style) {
+  struct zori_root * root = zori_get_root();
+  
+  if(!self) return NULL;
+  /* Allow only a single console. */
+  if (root->console) return NULL;
+  if(!zori_widget_initall(&self->widget, id, &root->widget, bounds, style,  ZORI_ARRAY_AND_AMOUNT(zori_console_actions) ) ) { 
+    return NULL;
+  }
+  ustrlist_init(&self->text);
+  // ustrlist_shiftcstr(&self->text, "empty line");
+  zori_widget_active_(&self->widget, FALSE);
+  zori_widget_visible_(&self->widget, FALSE);
+  self->count = 0;
+  // max MUST be at least 2, 3 to see anything...
+  self->max   = ZORI_CONSOLE_MAX;
+  self->start = 0;
+  self->charw = 80; 
+  self->buf   = calloc(self->charw + 1, 1);
+   // one extra for NULL at end . 
+  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;
+  /* Ony one console may be active. */
+  root->console = self;
+  return self;
+}
+
+/** Initializes a new console. */
+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;
+}
+
+
+
 
 
 

+ 1 - 1
src/zori/zori_page.c

@@ -12,7 +12,7 @@ struct zori_page * zori_page_new(zori_id id, struct zori_widget * parent) {
   page = calloc(1, sizeof(*page));
   if (!page) return NULL;
   zori_widget_initall(&page->widget, id, parent, 
-                      NULL, NULL, 0, NULL); 
+                      NULL, NULL, NULL, 0); 
   return page;
 }
 

+ 5 - 1
src/zori/zori_screen.c

@@ -75,6 +75,10 @@ struct zori_handler zori_screen_handlers[] = {
 struct zori_screen * 
 zori_screen_init(struct zori_screen * screen, zori_display * display) {
   memset(&screen->cursors, 0, sizeof(screen->cursors));
+  /* the keyjoy cursor is hidden off-screen to begin with. */
+  screen->cursors.keyjoy.p.x = - 64;
+  screen->cursors.keyjoy.p.y = - 64;
+  
   screen->display     = display; 
   screen->active_page = NULL; 
   return screen;
@@ -90,7 +94,7 @@ struct zori_screen * zori_screen_new(zori_id id, zori_display * display) {
   box.size.x = al_get_display_width(display);
   box.size.y = al_get_display_height(display);
   zori_widget_initall(&screen->widget, id, &zori_get_root()->widget, 
-                      &box, NULL, ZORI_AMOUNT_AND_ARRAY(zori_screen_handlers)); 
+                      &box, NULL, ZORI_ARRAY_AND_AMOUNT(zori_screen_handlers)); 
   if (!zori_screen_init(screen, display)) {
     free(screen);
     screen = NULL;

+ 25 - 7
src/zori/zori_widget.c

@@ -1,9 +1,27 @@
-
+#include "zori.h"
 #include "zori_widget.h"
-
-
-
-
-
-
+#include "draw.h"
+
+
+
+
+
+/* Draws a widget's frame based on it's style. If the background bitmap is set 
+ * then that is used, otherwise,  the background color is used, including a border
+ * if needed. */
+void zori_widget_draw_background(struct zori_widget * widget) {
+    float dx, dy, dw, dh;
+    struct zori_style * style = &widget->style;
+    zori_bitmap * background  = style->back.image;
+    dx = rebox_x(&widget->box);
+    dy = rebox_y(&widget->box);
+    dw = rebox_w(&widget->box);
+    dh = rebox_h(&widget->box);
+    
+    if (background) {
+      image_blitscale9(background, dx, dy, dw, dh, -1, -1);
+    } else {
+      draw_frame(dx, dy, dw, dh, 3, style->border.color, style->back.color);
+    }
+}