Browse Source

Improved style system somewhat.

Beoran 7 years ago
parent
commit
357c94ebf6

+ 2 - 52
include/store.h

@@ -3,58 +3,8 @@
 
 #include "resor.h"
 #include "xresor.h"
-
-int store_kind(int index);
-Resor *store_load_bitmap(int index,const char *vpath);
-Resor *store_load_bitmap_flags(int index,const char *vpath,int flags);
-Resor *store_load_sample(int index,const char *vpath);
-Resor *store_load_audio_stream(int index,const char *vpath,size_t buffer_count,int samples);
-Resor *store_grab_font(int index,int bmp_index,int count,int ranges[]);
-Resor *store_grab_font_from_resor(int index,Resor *resor,int count,int ranges[]);
-Resor *store_load_bitmap_font(int index,const char *vpath);
-Resor *store_load_bitmap_font_flags(int index,const char *vpath,int f);
-Resor *store_load_ttf_font(int index,const char *vpath,int h,int f);
-Resor *store_load_ttf_font_stretch(int index,const char *vpath,int w,int h,int f);
-bool store_done();
-Resor *store_put(int index,Resor *value);
-bool store_drop(int index);
-Resor *store_get(int index);
-int store_max();
-bool store_index_ok(int index);
-bool store_init();
-
-ALLEGRO_FONT    * store_get_font(int index);
-ALLEGRO_BITMAP  * store_get_bitmap(int index);
-ALLEGRO_SAMPLE  * store_get_sample(int index);
-ALLEGRO_AUDIO_STREAM * store_get_audio_stream(int index);
-
-bool store_get_bitmap_format(int index,int *value);
-bool store_get_bitmap_flags(int index,int *value);
-bool store_get_bitmap_height(int index,int *value);
-bool store_get_bitmap_width(int index,int *value);
-bool store_get_ustr_dimensions(int index,ALLEGRO_USTR *text,Rebox *value);
-bool store_get_ustr_width(int index,ALLEGRO_USTR *text,int *value);
-bool store_get_text_dimensions(int index,char *text,Rebox *value);
-bool store_get_text_width(int index,char *text,int *value);
-bool store_get_font_line_height(int index,int *value);
-bool store_get_font_descent(int index,int *value);
-bool store_get_font_ascent(int index,int *value);
-
-
-
-/* Loads "other" data and puts it in the storage. */
-Resor * 
-store_load_other(int index, const char* vpath, ResorKind kind, ResorLoader* loader, 
-                 ResorDestructor* destroy, void* extra);
-
-/* Loads a tile map and puts it in the storage. */
-Resor * store_load_tilemap(int index, const char * vpath);
-/* Returns a pointer to an "other" type of data from storage. Kind must match. */
-void * store_get_other(int index, unsigned kind);
-
-int store_get_unused_id(int minimum);
-
-
+/* Function prototypes are generated by using cproto. */
+#include "store_proto.h"
 
 
 #endif /* STORE_H_INCLUDED */ 

+ 49 - 0
include/store_proto.h

@@ -0,0 +1,49 @@
+/* src/store.c */
+_Bool store_init(void);
+_Bool store_index_ok(int index);
+int store_max(void);
+Resor *store_get(int index);
+_Bool store_drop(int index);
+Resor *store_put(int index, Resor *value);
+_Bool store_done(void);
+Resor *store_load_ttf_font_stretch(int index, const char *vpath, int w, int h, int f);
+Resor *store_load_ttf_font(int index, const char *vpath, int h, int f);
+Resor *store_load_bitmap_font_flags(int index, const char *vpath, int f);
+Resor *store_load_bitmap_font(int index, const char *vpath);
+Resor *store_grab_font_from_resor(int index, Resor *resor, int count, int ranges[]);
+Resor *store_grab_font(int index, int bmp_index, int count, int ranges[]);
+Resor *store_load_audio_stream(int index, const char *vpath, size_t buffer_count, int samples);
+Resor *store_load_sample(int index, const char *vpath);
+Resor *store_load_bitmap_flags(int index, const char *vpath, int flags);
+Resor *store_load_bitmap(int index, const char *vpath);
+Resor *store_load_other(int index, const char *vpath, ResorKind kind, ResorLoader *loader, ResorDestructor *destroy, void *extra);
+Resor *store_load_tilemap(int index, const char *vpath);
+int store_kind(int index);
+ALLEGRO_FONT *store_get_font(int index);
+ALLEGRO_BITMAP *store_get_bitmap(int index);
+ALLEGRO_SAMPLE *store_get_sample(int index);
+ALLEGRO_AUDIO_STREAM *store_get_audio_stream(int index);
+void *store_get_other(int index, unsigned kind);
+_Bool store_get_bitmap_format(int index, int *value);
+_Bool store_get_bitmap_flags(int index, int *value);
+_Bool store_get_bitmap_height(int index, int *value);
+_Bool store_get_bitmap_width(int index, int *value);
+_Bool store_get_ustr_dimensions(int index, ALLEGRO_USTR *text, Rebox *value);
+_Bool store_get_ustr_width(int index, ALLEGRO_USTR *text, int *value);
+_Bool store_get_text_dimensions(int index, char *text, Rebox *value);
+_Bool store_get_text_width(int index, char *text, int *value);
+_Bool store_get_font_ascent(int index, int *value);
+_Bool store_get_font_descent(int index, int *value);
+_Bool store_get_font_line_height(int index, int *value);
+int store_get_unused_id(int minimum);
+int store_load_ttf_font_stretch_id(int min, const char *vpath, int w, int h, int f);
+int store_load_ttf_font_id(int min, const char *vpath, int h, int f);
+int store_load_bitmap_font_flags_id(int min, const char *vpath, int f);
+int store_load_bitmap_font_id(int min, const char *vpath);
+int store_grab_font_id(int min, int from, int count, int ranges[]);
+int store_load_audio_stream_id(int min, const char *vpath, size_t buffer_count, int samples);
+int store_load_sample_id(int min, const char *vpath);
+int store_load_bitmap_flags_id(int min, const char *vpath, int flags);
+int store_load_bitmap_id(int min, const char *vpath);
+int store_load_other_id(int min, const char *vpath, ResorKind kind, ResorLoader *loader, ResorDestructor *destroy, void *extra);
+int store_load_tilemap_id(int min, const char *vpath);

+ 7 - 2
include/ui.h

@@ -8,11 +8,16 @@ struct ui_state {
   zori_id screen;
   zori_id console;
   
+  int mouse_image;
+  int keyjoy_image;
+  
   /* main page/menu */
   struct ui_state_main {
     zori_id page;
     zori_id menu;
     
+    int background_image;
+    
     /* menu buttons */
     struct ui_state_main_buttons { 
       zori_id resume;
@@ -23,7 +28,8 @@ struct ui_state {
   
   /* HUD page and widgets */
   struct ui_state_hud {
-    zori_id page;    
+    zori_id page;
+    zori_id dialog;
   } hud;
   
   /* Settings page and widgets */
@@ -38,7 +44,6 @@ struct ui_state {
 void ui_setup(void);
 void ui_state_init(struct ui_state * ui, zori_display * display, zori_font * font);
 
-
 #endif
 
 

+ 124 - 22
include/zori/zori.h

@@ -152,7 +152,7 @@ enum zori_custom_event_type {
   /** Update event, called at regular intervals to update the state of the UI.*/
   ZORI_EVENT_UPDATE,
   /** First draw pass. */
-  ZORI_EVENT_DRAW,  
+  ZORI_EVENT_DRAW,
   /** Second draw pass for cursors. */
   ZORI_EVENT_OVERDRAW,
   /** Cleanup event. */
@@ -299,37 +299,135 @@ static inline void * zori_event_set_data(union zori_event * event, void * data)
 }
 
 /* Style flags */
-enum zori_style_flag {
+enum zori_graphic_style_flag {
   ZORI_STYLE_FLAG_BORDER = 1,
   ZORI_STYLE_FLAG_FILL   = 2,
   ZORI_STYLE_FLAG_DEFAULT= (ZORI_STYLE_FLAG_BORDER | ZORI_STYLE_FLAG_FILL),
 };
 
-/* A graphic is a color, image, and style flags applied to a part of the GUI. */
-struct zori_graphic_style {
+/* Font flags, from ALLEGRO font flags. */
+enum zori_font_style_flag { 
+  ZORI_FONT_ALIGN_LEFT    = ALLEGRO_ALIGN_LEFT, 
+  ZORI_FONT_ALIGN_CENTRE  = ALLEGRO_ALIGN_CENTRE, 
+  ZORI_FONT_ALIGN_RIGHT   = ALLEGRO_ALIGN_RIGHT, 
+  ZORI_FONT_ALIGN_INTEGER = ALLEGRO_ALIGN_INTEGER, 
+};
+
+/* Bitmap flags from allegro bitmap flags. */
+enum zori_bitmap_flag {
+  ZORI_BITMAP_FLIP_HORIZONTAL = ALLEGRO_FLIP_HORIZONTAL,
+  ZORI_BITMAP_FLIP_VERTICAL   = ALLEGRO_FLIP_VERTICAL,
+};
+
+/**
+ * For style: not all combinations make sense. How to improve this?
+ * 
+ * What is available in CSS 1:
+ * 
+ * font : font of the text (with many sub details in CCS not relevant here).
+ * color: text color of an element
+ * background-color: background color of an element.
+ * background-image: background image of an element.
+ * background-repeat: determines how/if the image is repeated.
+ * background-attachment: fixed with regard to the canvas.
+ * background-position: initial position of the background image.
+ * word-spacing: text spacing
+ * letter-spacing: text spacing
+ * text-decoration: text decoration (underline, overline, etc)
+ * vertical-align: vertical alignment, top, center, bottom based on the parent. 
+ * text-transform: 
+ * text-align: text alignment, left, right, centered.
+ * text-indent: Text indentation.
+ * line-height: Height of a line of text.
+ * margin: sizes of the margin 
+ * padding: sizes of the padding
+ * border-width: sizes of the border
+ * border-color: color of the border
+ * border-style: style of the border (per side)
+ * border: border style, general of per side
+ * width: width of the box
+ * height: height of the box
+ * float: floating
+ * clear: float control
+ * display: display type (visual, block, hiden, none, etc)
+ * white-space: white space display.
+ * list-style: list styling with type, image and position of the image.
+ * 
+ * Squeezing it down to the essential, we retain:
+ * 
+ * text.font    : Font for texts.
+ * text.color   : Color for texts.
+ * text.flags   : Style flags, merges horizontal alignment, decoration, etc.
+ * 
+ * back.color   : Background color.
+ * back.image   : Background image.
+ * back.flags   : Style flags, solid background, no background, etc.
+ * back.radius  : Size of corner for image_scale9 algorithm.
+ * 
+ * border.color : Border color.
+ * border.size  : Border size (thickness).
+ * border.flags : Border style flags.
+ * border.radius: Rounded corners radius.
+ * 
+ * cursor.color   : Text cursor color.
+ * 
+ * mouse.back     : Mouse cursor background information.
+ * mouse.border   : Mouse cursor border.
+ * keyjoy.back    : Keyjoy cursor background information.
+ * keyjoy.border  : Keyjoy cursor border.
+ * 
+ * 
+ * width, height, margins and padding are not considered style but positioning.
+ * The keyjoy and mouse cursor and a border are only available 
+ * per-screen.
+ * 
+ * The text cursor has a color only. 
+ * 
+ * 1. Text can have a font, a color and font flags (centered, etc)
+ * 2. A rectangle / container / widget can have a background image combined
+ * with a background color it can have draw flags for the background image and 
+ * for the color (fill or not). Furthermore it can have a border color. 
+ * Possibly (through not suupported now) would be a background 
+ * 
+ * 
+ */
+
+
+/* The style of the backgrounbd of a widget. */
+struct zori_background_style {
   zori_color       color;
-  zori_bitmap    * bitmap;
-  int              style_flags;
+  zori_bitmap    * image;
+  int              flags;
+  int              radius;
 };
 
+
+/* The style of the border of a widget.  */
+struct zori_border_style {
+  zori_color       color;
+  zori_bitmap    * image;
+  int              flags;
+  int              radius;
+  int              size;
+};
+
+
 /* A text style has all elements needed to style a piece of text. I consists of the text color, font and font flags flags applied to a part of the GUI.
  */
 struct zori_text_style {
   zori_color       color;
   zori_font      * font;
-  int              font_flags;
+  int              flags;
 };
 
-/* A style is a set of style parts for different parts of the GUI. */
+/* A style is a set of style elements for a widget or cursor. */
 struct zori_style {
-  struct zori_graphic_style fore;
-  struct zori_graphic_style back;
-  struct zori_graphic_style border;
-  struct zori_graphic_style hover;
-  struct zori_graphic_style mark;
-  struct zori_text_style    text;
+  struct zori_background_style back;
+  struct zori_border_style     border;
+  struct zori_text_style       text;
 };
 
+
 struct zori_widget;
 
 /* Event handler results. */
@@ -406,16 +504,18 @@ typedef uint32_t zori_widget_type;
 #define ZORI_WIDGET_TYPE(A, B, C, D) ((zori_widget_type)((A<<24) | (B<<16) | (C<<8) | D))
 
 /* Mouse or keyboard/joystick cursor. */
-struct zori_cursor { 
-  zori_point           p; 
-  struct zori_widget * hover;
-  struct zori_widget * focus;
-  zori_bitmap        * bitmap;
-  enum zori_flag       flags;
-  struct zori_style     style;
+struct zori_cursor {
+  zori_point                p;
+  struct zori_widget      * hover;
+  struct zori_widget      * focus;
+  zori_bitmap             * bitmap;
+  enum zori_flag            flags;
+  /* Style of the cursor itself. */
+  struct zori_style         style;
+  /* Style for the element marked or hovered if that element responds to it. */
+  struct zori_style         target_style;
 };
 
-
 /* Support multiple cursors...  */
 struct zori_cursors { 
   struct zori_cursor mouse;
@@ -621,6 +721,8 @@ int zori_handle_system_event(zori_system_event *sysev);
 void zori_update(double dt);
 int zori_result(zori_id id);
 
+/* Use generated header file for function prototypes. */
+#include "zori_proto.h"
 
 
 #endif

+ 69 - 0
include/zori/zori_proto.h

@@ -0,0 +1,69 @@
+/* src/zori/zori.c */
+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);
+struct zori_root *zori_get_root(void);
+struct zori_widget *zori_get_root_widget(void);
+struct zori_widget *zori_get_widget(zori_id id);
+zori_id zori_get_unused_id(void);
+zori_id zori_initialize_root(void);
+zori_id zori_start(struct zori_style *default_style);
+zori_id zori_set_margins(zori_id id, int left, int top, int right, int bottom);
+zori_id zori_set_margin(zori_id id, int size);
+zori_id zori_set_paddings(zori_id id, int left, int top, int right, int bottom);
+zori_id zori_set_padding(zori_id id, int size);
+zori_font *zori_text_font(zori_id id);
+void zori_destroy_root(void);
+zori_id zori_shutdown(void);
+zori_id zori_set_style(zori_id id, struct zori_style *style);
+zori_id zori_get_style(zori_id id, struct zori_style *style);
+zori_id zori_set_background_color(zori_id id, zori_color color);
+zori_id zori_set_background_bitmap(zori_id id, zori_bitmap *bitmap);
+zori_id zori_set_foreground_color(zori_id id, zori_color color);
+zori_id zori_set_foreground_bitmap(zori_id id, zori_bitmap *bitmap);
+zori_id zori_set_border_color(zori_id id, zori_color color);
+zori_id zori_set_border_bitmap(zori_id id, zori_bitmap *bitmap);
+zori_id zori_set_text_font_flags(zori_id id, int flags);
+void zori_draw_all(void);
+int zori_handle_system_event(zori_system_event *sysev);
+void zori_update(double dt);
+int zori_result(zori_id id);
+int zori_get_result(zori_id id, struct zori_result *result);
+/* src/zori/zori.c */
+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);
+struct zori_root *zori_get_root(void);
+struct zori_widget *zori_get_root_widget(void);
+struct zori_widget *zori_get_widget(zori_id id);
+zori_id zori_get_unused_id(void);
+zori_id zori_initialize_root(void);
+zori_id zori_start(struct zori_style *default_style);
+zori_id zori_set_margins(zori_id id, int left, int top, int right, int bottom);
+zori_id zori_set_margin(zori_id id, int size);
+zori_id zori_set_paddings(zori_id id, int left, int top, int right, int bottom);
+zori_id zori_set_padding(zori_id id, int size);
+zori_font *zori_text_font(zori_id id);
+void zori_destroy_root(void);
+zori_id zori_shutdown(void);
+zori_id zori_set_style(zori_id id, struct zori_style *style);
+zori_id zori_get_style(zori_id id, struct zori_style *style);
+zori_id zori_set_background_color(zori_id id, zori_color color);
+zori_id zori_set_background_bitmap(zori_id id, zori_bitmap *bitmap);
+zori_id zori_set_foreground_color(zori_id id, zori_color color);
+zori_id zori_set_foreground_bitmap(zori_id id, zori_bitmap *bitmap);
+zori_id zori_set_border_color(zori_id id, zori_color color);
+zori_id zori_set_border_bitmap(zori_id id, zori_bitmap *bitmap);
+zori_id zori_set_text_font(zori_id id, zori_font *font);
+zori_id zori_set_text_font_flags(zori_id id, int flags);
+void zori_draw_all(void);
+int zori_handle_system_event(zori_system_event *sysev);
+void zori_update(double dt);
+int zori_result(zori_id id);
+int zori_get_result(zori_id id, struct zori_result *result);

+ 1 - 0
src/resor.c

@@ -433,3 +433,4 @@ bool resor_get_bitmap_format(Resor * self, int * value) {
 
 
 
+  

+ 54 - 4
src/ui.c

@@ -2,11 +2,13 @@
 #include "image.h"
 #include "store.h"
 #include "zori.h"
+#include "zori_style.h"
 #include "zori_screen.h"
 #include "zori_console.h"
 #include "zori_button.h"
 #include "zori_page.h"
 #include "zori_menu.h"
+#include "draw.h"
 #include "monolog.h"
 #include "ui.h"
 
@@ -40,6 +42,17 @@ char INTRO_TEXT2[] = "Something happened, and I was changed!";
 zori_id ui_state_make_sub_menu(zori_id parent, int x, int y, int w, int bh); 
 
 
+/* Set up HUD. */
+void ui_state_init_hud(struct ui_state * ui,
+  zori_display * display, zori_font * font) {
+    Rebox box;
+    
+  ui->hud.page = zori_new_page(-1, ui->screen);
+  LOG_NOTE("HUD page: %d\n", ui->hud.page);
+  box = rebox_make(10, 300, 620, 200);
+  ui->hud.dialog = zori_new_longtext(-1, ui->hud.page, box, INTRO_TEXT);
+}
+
 /* Set up Zori GUI. */
 
 void ui_state_init(struct ui_state * ui, 
@@ -52,7 +65,9 @@ zori_font * font
   memset(&style, 0, sizeof(style));
   style.text.font  = font;
   style.text.color = color_rgb(255,255,255);
-  style.back.color = color_rgba(64,0,0, 191);
+  style.text.flags = ZORI_FONT_ALIGN_CENTRE;
+  style.back.color = color_rgba(0, 16, 64, 128);
+  
   if ( !ZORI_ID_OK_P(zori_start(&style)) ) {
     LOG_ERROR( "Out of memory when allocating GUI.");
     return;
@@ -63,6 +78,27 @@ zori_font * font
     return;
   }
   
+  ui->main.background_image = store_load_bitmap_id(1000,  "/image/background/eruta_mainmenu.png");
+  ui->mouse_image = store_load_bitmap_id(1001, "image/gin/fountain-pen_32.png");
+  ui->keyjoy_image = store_load_bitmap_id(1002, "image/gin/fountain-pen_32.png");
+  
+  
+  
+  if (ui->main.background_image < 0) {
+    LOG_ERROR( "Cannot load main menu background.");
+  }
+  
+  if (ui->mouse_image < 0) {
+    LOG_ERROR( "Cannot load mouse cursor image.");
+  }
+  
+  if (ui->keyjoy_image < 0) {
+    LOG_ERROR( "Cannot load keyjoy cursor image.");
+  }
+  
+  draw_convert_average_to_alpha(store_get_bitmap(ui->mouse_image), al_map_rgb(255,255,255));
+  draw_convert_average_to_alpha(store_get_bitmap(ui->keyjoy_image), al_map_rgb(255,255,255));
+  
   ui->screen = zori_new_screen(-1, display);
   
   if (!ZORI_ID_OK_P(ui->screen)) {
@@ -70,30 +106,44 @@ zori_font * font
     return;
   }
   
+  
+  
   ui->main.page = zori_new_page(-1, ui->screen);
   LOG_NOTE("Main page: %d\n", ui->main.page);
-  box = rebox_make(280, 80, 140, 240);  
+  box = rebox_make(280, 140, 140, 240); 
   ui->main.menu = zori_new_menu(-1, ui->main.page, &box);
+  zori_set_background_bitmap(ui->main.page, 
+                            store_get_bitmap(ui->main.background_image));
   
   LOG_NOTE("Main menu: %d\n", ui->main.menu);
   
+  zori_set_text_font_flags(ui->main.menu, ZORI_FONT_ALIGN_CENTRE);
   
   {
-    Rebox box = rebox_make(300, 100, 100, 60);
+    Rebox box = rebox_make(300, 160, 100, 60);
     ui->main.button.resume = zori_new_button(-1, ui->main.menu, &box, "Continue");
+    // zori_set_text_font_flags(ui->main.button.resume, ZORI_FONT_ALIGN_CENTRE);
     LOG_NOTE("Button: %d\n", ui->main.button.resume);
   }
   {
-    Rebox box = rebox_make(300, 200, 100, 60);
+    Rebox box = rebox_make(300, 260, 100, 60);
     ui->main.button.new = zori_new_button(-1, ui->main.menu, &box, "New");
+    zori_set_text_font_flags(ui->main.button.new, ZORI_FONT_ALIGN_RIGHT);
     LOG_NOTE("Button: %d\n", ui->main.button.new);
   }
   
+  ui_state_init_hud(ui, display, font);
+  
 }
 
 
 void ui_handle_main_menu(struct ui_state * ui, int selected) {
   LOG_NOTE("Main menu selected: %d\n", selected);
+  if (selected == ui->main.button.resume) {
+    LOG_NOTE("Resume");
+  } else if (selected == ui->main.button.new) {
+    LOG_NOTE("New");
+  }
 }
 
 void ui_state_update(struct ui_state * ui, 

+ 65 - 5
src/zori/zori.c

@@ -213,13 +213,73 @@ 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);
+zori_id zori_set_style(zori_id id, struct zori_style * style) {
+  struct zori_widget * widget = zori_get_widget(id);
+  if ((!widget) || (!style)) return ZORI_ID_ERROR;
+  widget->style = *style;
+  return widget->id;
+}
+
+/* Gets the whole style of a widget. */
+zori_id zori_get_style(zori_id id, struct zori_style * style) {
+  struct zori_widget * widget = zori_get_widget(id);
+  if ((!widget) || (!style)) return ZORI_ID_ERROR;
+  *style = widget->style;
+  return widget->id;
+}
+
 
 /* Sets the background color of the widget. */
-zori_id zori_set_background_color(zori_id id, zori_color color);
+zori_id zori_set_background_color(zori_id id, zori_color color) {
+  struct zori_widget * widget = zori_get_widget(id);
+  if (!widget) return ZORI_ID_ERROR;
+  widget->style.back.color = color;
+  return widget->id;
+}
+
+/* Sets the background bitmap of the widget. */
+zori_id zori_set_background_bitmap(zori_id id, zori_bitmap * bitmap) {
+  struct zori_widget * widget = zori_get_widget(id);
+  if (!widget) return ZORI_ID_ERROR;
+  widget->style.back.image = bitmap;
+  return widget->id;
+}
+
+
+/* Sets the border color of the widget. */
+zori_id zori_set_border_color(zori_id id, zori_color color) {
+  struct zori_widget * widget = zori_get_widget(id);
+  if (!widget) return ZORI_ID_ERROR;
+  widget->style.border.color = color;
+  return widget->id;
+}
+
+/* Sets the border bitmap of the widget. */
+zori_id zori_set_border_bitmap(zori_id id, zori_bitmap * bitmap) {
+  struct zori_widget * widget = zori_get_widget(id);
+  if (!widget) return ZORI_ID_ERROR;
+  widget->style.border.image = bitmap;
+  return widget->id;
+}
+
+
+/* Sets the text font of the widget. */
+zori_id zori_set_text_font(zori_id id, zori_font * font) {
+  struct zori_widget * widget = zori_get_widget(id);
+  if (!widget) return ZORI_ID_ERROR;
+  widget->style.text.font = font;
+  return widget->id;
+}
+
+
+/* Sets the text font flags of the widget. */
+zori_id zori_set_text_font_flags(zori_id id, int flags) {
+  struct zori_widget * widget = zori_get_widget(id);
+  if (!widget) return ZORI_ID_ERROR;
+  widget->style.text.flags = flags;
+  return widget->id;
+}
 
-/* 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);
@@ -243,7 +303,7 @@ void zori_draw_all(void) {
 /* Dispatches system events throughout the GUI.  */
 int zori_handle_system_event(zori_system_event * sysev) {
   /* All events are passed on to the console regardless if it is active. 
-   * Otherwise, the events go into the system. */
+   * Otherwise, theget events go into the system. */
   if (!the_zori_root) {
     return ZORI_ID_EINVAL;
   } 

+ 16 - 14
src/zori/zori_button.c

@@ -28,10 +28,19 @@ int zori_button_on_mouse_axes(union zori_event * event) {
 
 /** Handles a mouse click or activation and set the 
  * button and it's parent's result. */
-int zori_button_activate(struct zori_widget * widget) {
-  
-  
-  
+int zori_button_on_ia(union zori_event * event) { 
+    struct zori_widget * widget = event->any.widget;
+    struct zori_button * button = zori_widget_to_button(widget);
+    struct zori_widget * parent = widget->parent;
+    
+    zori_widget_set_int_result(widget, widget->id);
+    LOG_NOTE("Button clicked: %d, result %d.\n", widget->id, widget->result.ready);
+    
+    /* If the parent is a menu, also set it's result. */
+    if (zori_widget_is_type(parent, ZORI_WIDGET_TYPE_MENU)) {
+      zori_widget_set_int_result(parent, widget->id);
+    }
+    return zori_widget_raise_action_event(widget);
 }
 
 
@@ -39,19 +48,11 @@ int zori_button_activate(struct zori_widget * widget) {
 /** 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);
-    struct zori_widget * parent = widget->parent;
     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_set_int_result(widget, widget->id);
-      LOG_NOTE("Button clicked: %d, result %d.\n", widget->id, widget->result.ready);
-      
-      /* If the parent is a menu, also set it's result. */
-      if (zori_widget_is_type(parent, ZORI_WIDGET_TYPE_MENU)) {
-        zori_widget_set_int_result(parent, widget->id);
-      }
-      return zori_widget_raise_action_event(widget);
+      LOG_NOTE("Mouse clicked: %p!\n", widget);
+      return zori_widget_raise_internal_action_event(widget);
     }
     return ZORI_HANDLE_PASS;
 }
@@ -80,6 +81,7 @@ 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 },
+  { ZORI_INTERNAL_EVENT_ACTION          , zori_button_on_ia            , NULL },
   { -1, NULL, NULL }
 };
 

+ 11 - 2
src/zori/zori_caption.c

@@ -40,14 +40,23 @@ zori_caption_draw(
   const struct zori_caption * caption, 
   const zori_rebox * box, 
   const struct zori_style * style) {
-  
+ 
   if (caption->text) {
     zori_font * font = style->text.font;
     zori_color color = style->text.color;
     float x = box->at.x;
     float y = box->at.y;
     float w = box->size.x;
-    al_draw_multiline_ustr(font, color, x, y, w, -1,  ALLEGRO_ALIGN_LEFT, caption->text);
+    if (style->text.flags & ZORI_FONT_ALIGN_CENTRE) {
+      x = x + (w / 2);
+    }
+    
+    if (style->text.flags & ZORI_FONT_ALIGN_RIGHT) {
+      x = x + w;
+    }
+    
+    al_draw_multiline_ustr(font, color, x, y, w, -1,  style->text.flags, 
+                           caption->text);
   }
 }
 

+ 4 - 3
src/zori/zori_longtext.c

@@ -36,6 +36,7 @@ struct zori_longtext *
 zori_longtext_set_cstr(struct zori_longtext * longtext, const char * cstr) {
   const USTR * ustr; 
   USTR_INFO info;
+  if (!cstr) cstr = "EMPTY!!!";
   ustr = ustr_refcstr(&info, cstr);
   return zori_longtext_set(longtext, ustr);
 }
@@ -172,7 +173,7 @@ int zori_longtext_longtext_at_end(struct zori_longtext * longtext) {
 static BeVec
 zori_longtext_calculate_text_position(struct zori_longtext * longtext) {
   BeVec result;
-  int flags = longtext->widget.style.text.font_flags;
+  int flags = longtext->widget.style.text.flags;
   result.x  = longtext->widget.inner.at.x;
   result.y  = longtext->widget.inner.at.y;
 
@@ -189,7 +190,7 @@ void zori_longtext_draw_text(struct zori_longtext * longtext) {
   int flags;
   BeVec pos = zori_longtext_calculate_text_position(longtext);
   font      = zori_widget_font(&longtext->widget);
-  flags     = longtext->widget.style.text.font_flags | ALLEGRO_ALIGN_INTEGER;
+  flags     = longtext->widget.style.text.flags | ALLEGRO_ALIGN_INTEGER;
   zori_color shadow = longtext->widget.style.back.color;
   zori_color fore   = longtext->widget.style.text.color;
   
@@ -216,7 +217,7 @@ static bool zori_longtext_draw_custom_partial_text(int line_num, const char *lin
   BeVec pos;
   
   font      = zori_widget_font(&longtext->widget);
-  flags     = longtext->widget.style.text.font_flags | ALLEGRO_ALIGN_INTEGER;
+  flags     = longtext->widget.style.text.flags | ALLEGRO_ALIGN_INTEGER;
   pos       = zori_longtext_calculate_text_position(longtext);
  
 

+ 24 - 4
src/zori/zori_page.c

@@ -9,24 +9,44 @@ struct zori_page * zori_widget_to_page(struct zori_widget * widget) {
   return ZORI_CONTAINER_OF(widget, struct zori_page, widget);
 }
 
+int zori_page_on_draw(union zori_event * event) {
+  struct zori_widget * widget = event->any.widget;
+  struct zori_page   * page   = zori_widget_to_page(widget);
+  struct zori_style  * style  = &widget->style;
+  if (style->back.image) {
+    al_draw_bitmap(style->back.image, 0, 0, 0);
+  } 
+  
+  if (style->back.flags & ZORI_STYLE_FLAG_FILL) {
+    al_clear_to_color(style->back.color);
+  }
+  
+  return ZORI_HANDLE_PASS;
+}
+
+
+struct zori_handler zori_page_handlers[] = {
+  { ZORI_EVENT_DRAW                     , zori_page_on_draw          , NULL },
+  { -1, NULL, NULL }
+};
+
+
 struct zori_page * zori_page_new(zori_id id, struct zori_widget * parent) {
   struct zori_page * page = NULL;
   if (!parent) return NULL;
   page = calloc(1, sizeof(*page));
   if (!page) return NULL;
   zori_widget_initall(&page->widget, ZORI_WIDGET_TYPE_PAGE, id, parent, 
-                      NULL, NULL, NULL, 0); 
+                      NULL, NULL, ZORI_ARRAY_AND_AMOUNT(zori_page_handlers)); 
   return page;
 }
 
 
 zori_id zori_new_page(zori_id id, zori_id parent_id) {
-  struct zori_widget * parent = zori_get_widget(parent_id);  
+  struct zori_widget * parent = zori_get_widget(parent_id);
   struct zori_page   * page   = zori_page_new(id, parent);
   if (!page) return ZORI_ID_ENOMEM;
   return page->widget.id;
 }
 
 
-
-

+ 58 - 6
src/zori/zori_screen.c

@@ -13,6 +13,12 @@ struct zori_screen * zori_widget_to_screen(struct zori_widget * widget) {
   return ZORI_CONTAINER_OF(widget, struct zori_screen, widget);
 }
 
+struct zori_screen * zori_get_screen(zori_id id) {
+  struct zori_widget * widget = zori_get_widget(id);
+  return zori_widget_to_screen(widget);
+}
+
+
 
 /** Handles a mouse axis event and then pass it on to the active page. */
 int zori_screen_on_mouse_axes(union zori_event * event) { 
@@ -52,8 +58,8 @@ void zori_draw_cursor(const struct zori_cursor * cursor) {
     y2 = y1 + 24 - 8;
     x3 = x1 + 24 - 8;
     y3 = y1 + 24 + 8;  
-    al_draw_filled_triangle(x1, y1, x2, y2, x3, y3, style->fore.color);
-    al_draw_triangle(x1, y1, x2, y2, x3, y3, style->back.color, 1.0);
+    al_draw_filled_triangle(x1, y1, x2, y2, x3, y3, style->back.color);
+    al_draw_triangle(x1, y1, x2, y2, x3, y3, style->border.color, style->border.size);
   }
 };
 
@@ -91,10 +97,16 @@ zori_screen_init(struct zori_screen * screen, zori_display * display) {
   screen->cursors.keyjoy.p.y = - 64;
   /* Copy the styles, but set them a bit different */
   
-  screen->cursors.keyjoy.style = screen->widget.style;
-  screen->cursors.mouse.style  = screen->widget.style;
-  screen->cursors.keyjoy.style.back.color = al_map_rgb(0,0,255);
-  screen->cursors.keyjoy.style.fore.color = al_map_rgb(255,255,0);
+  screen->cursors.keyjoy.style              = screen->widget.style;
+  screen->cursors.mouse.style               = screen->widget.style;
+  screen->cursors.keyjoy.target_style       = screen->widget.style;
+  screen->cursors.mouse.target_style        = screen->widget.style;
+  
+  screen->cursors.keyjoy.style.back.color   = al_map_rgb(0, 0, 255);
+  screen->cursors.keyjoy.style.border.color = al_map_rgb(255, 255, 0);
+  
+  screen->cursors.keyjoy.target_style.back.color  = al_map_rgb(0, 191, 0);
+  screen->cursors.mouse.target_style.back.color   = al_map_rgb(31, 191, 32);
   
   
   screen->display     = display; 
@@ -155,6 +167,46 @@ zori_id zori_screen_go(zori_id screen_id, zori_id page_id, void * data) {
   }
 }
 
+struct zori_cursor * zori_cursor_set_style(struct zori_cursor * cursor, 
+ struct zori_style style) {
+  if (!cursor) return NULL;
+  cursor->style = style;
+  return cursor;
+}
+
+
+struct zori_screen * zori_screen_set_keyjoy_cursor_style(struct zori_screen * screen, struct zori_style style) {
+  if (!screen) {
+    return NULL;
+  }
+  zori_cursor_set_style(&screen->cursors.keyjoy, style);  
+  return screen;
+}
+
+struct zori_screen * zori_screen_set_mouse_cursor_style(struct zori_screen * screen, struct zori_style style) {
+  if (!screen) {
+    return NULL;
+  }
+  zori_cursor_set_style(&screen->cursors.mouse, style);  
+  return screen;
+}
+
+
+zori_id zori_set_keyjoy_cursor_style(zori_id id, struct zori_style style) {
+  struct zori_screen * screen  = zori_get_screen(id);
+  if (!zori_screen_set_keyjoy_cursor_style(screen, style)) {
+    return ZORI_ID_EINVAL;
+  } 
+  return id;
+}
+
+zori_id zori_set_mouse_cursor_style(zori_id id, struct zori_style style) {
+  struct zori_screen * screen  = zori_get_screen(id);
+  if (!zori_screen_set_mouse_cursor_style(screen, style)) {
+    return ZORI_ID_EINVAL;
+  } 
+  return id;
+}
 
 
 

+ 27 - 6
src/zori/zori_style.c

@@ -13,18 +13,15 @@ zori_id zori_initialize_default_style(void) {
  
   the_default_style->text.font      = al_create_builtin_font();  
   the_default_style->text.color     = al_color_name("white");
-  the_default_style->text.font_flags= ALLEGRO_ALIGN_LEFT;
+  the_default_style->text.flags     = ALLEGRO_ALIGN_LEFT;
   the_default_style->border.color   = al_color_name("white");  
   the_default_style->back.color     = al_color_name("green");
-  the_default_style->fore.color     = al_color_name("white");  
-  the_default_style->mark.color     = al_color_name("lightgreen");
-  the_default_style->hover.color    = al_color_name("yellowgreen");  
-
+    
   return ZORI_ID_OK;
 }
 
 
-/** Returns the golbal default style */
+/** Returns the global default style */
 struct zori_style * zori_get_default_style() {
   return the_default_style;
 }
@@ -34,3 +31,27 @@ void zori_destroy_default_style(void) {
   free(the_default_style);
   the_default_style = NULL;
 } 
+
+
+/* Fills in a background style part. */
+struct zori_background_style *  zori_background_style_init(
+struct zori_background_style * bs, zori_color color, zori_bitmap * bitmap, int corner_radius, int flags) {
+  if (!bs) return NULL;  
+  bs->color         = color;
+  bs->image         = bitmap;
+  bs->flags         = flags;
+  bs->radius        = corner_radius;
+  return bs;
+};
+
+/* Fills in a text style part. */
+struct zori_text_style *  zori_text_style_init(struct zori_text_style * ts, 
+zori_color color, zori_font * font, int flags) {
+  if (!ts) return NULL;
+  ts->color      = color;
+  ts->font       = font;
+  ts->flags      = flags;
+  return ts;
+};
+
+ 

+ 179 - 35
src/zori/zori_widget.c

@@ -7,6 +7,30 @@
 #include "draw.h"
 
 
+bool zori_widget_is_type(struct zori_widget * widget, zori_widget_type type) {
+  if(!widget) return false;
+  return (type) == widget->type; 
+}
+
+bool zori_widget_is_type_predicate(struct zori_widget * widget, void * extra) {
+  zori_widget_type * type_ptr = extra;
+  if(!type_ptr) return false;
+  return zori_widget_is_type(widget, (*type_ptr)); 
+}
+
+struct zori_widget * 
+  zori_widget_get_parent_of_type(struct zori_widget * widget,  
+  zori_widget_type type) {
+  return zori_widget_find_parent(widget, zori_widget_is_type_predicate, &type);
+}
+
+
+struct zori_screen * zori_widget_get_screen(struct zori_widget * widget) {  
+  struct zori_widget * screen_widget = zori_widget_get_parent_of_type(widget, ZORI_WIDGET_TYPE_SCREEN);
+  return zori_widget_to_screen(screen_widget);
+}
+
+
 /** Returns whether or not a widget will even handle an event in the first place.
  * For example, a hidden widget won't draw, and a disabled widget won't 
  * accept any system events, and a NULL widget doesn't accept events at all.. */
@@ -153,6 +177,22 @@ struct zori_handler * zori_widget_add_handlers
   return handlers + amount - 1;
 }
 
+/* Gets the style to use for a marked widget. Looks up a screen widget and then 
+ * looks for the cursor t determine this. */
+struct zori_style * zori_widget_get_mark_style(struct zori_widget * widget) {
+    struct zori_screen * screen = zori_widget_get_screen(widget);
+    if (!screen) return &widget->style;
+    return &(screen->cursors.keyjoy.target_style);
+}
+
+/* Gets the style to use for a hovered widget. Looks up a screen widget and then 
+ * looks for the cursor t determine this. */
+struct zori_style * zori_widget_get_hover_style(struct zori_widget * widget) {
+    struct zori_screen * screen = zori_widget_get_screen(widget);
+    if (!screen) return &widget->style;
+    return &(screen->cursors.mouse.target_style);
+} 
+
 
 
 void zori_widget_free(struct zori_widget * widget);
@@ -218,32 +258,27 @@ zori_widget_margin_(struct zori_widget * widget, int size) {
 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.bitmap;
-    zori_color color = style->back.color;
-    struct zori_graphic_style * graphic_style =  & style->back;
     dx = rebox_x(&widget->box);
     dy = rebox_y(&widget->box);
     dw = rebox_w(&widget->box);
     dh = rebox_h(&widget->box);
     
     if (zori_widget_hover(widget)) {
-      graphic_style = &style->hover;  
+      style = zori_widget_get_hover_style(widget);
     }
     
     if (zori_widget_marked(widget)) {
-      graphic_style = &style->mark;
-    }
-    
-    if (graphic_style->bitmap) {
-      background = graphic_style->bitmap;
+      style = zori_widget_get_mark_style(widget);
     }
     
-    color = graphic_style->color;
-
-    if (background) {
+    if (style->back.image) {
+      zori_bitmap * background  = style->back.image;
       image_blitscale9(background, dx, dy, dw, dh, -1, -1);
     } else {
-      draw_frame(dx, dy, dw, dh, 3, style->border.color, color);
+      zori_color fillco = style->back.color;
+      zori_color bordco = style->border.color;
+      int thick         = style->border.size;
+      draw_frame(dx, dy, dw, dh, thick, bordco, fillco);
     }
 }
 
@@ -433,6 +468,8 @@ struct zori_widget * zori_widget_init
       if (!widget->style.text.font) {
         widget->style.text.font = default_style->text.font;
       }
+    } else if (parent) {
+      widget->style = parent->style;
     } else {
       widget->style = *default_style;
     }
@@ -492,28 +529,6 @@ zori_widget_find_parent(struct zori_widget * widget,
   return NULL;
 }
 
-bool zori_widget_is_type(struct zori_widget * widget, zori_widget_type type) {
-  if(!widget) return false;
-  return (type) == widget->type; 
-}
-
-bool zori_widget_is_type_predicate(struct zori_widget * widget, void * extra) {
-  zori_widget_type * type_ptr = extra;
-  if(!type_ptr) return false;
-  return zori_widget_is_type(widget, (*type_ptr)); 
-}
-
-struct zori_widget * 
-  zori_widget_get_parent_of_type(struct zori_widget * widget,  
-  zori_widget_type type) {
-  return zori_widget_find_parent(widget, zori_widget_is_type_predicate, &type);
-}
-
-
-struct zori_screen * zori_widget_get_screen(struct zori_widget * widget) {  
-  struct zori_widget * screen_widget = zori_widget_get_parent_of_type(widget, ZORI_WIDGET_TYPE_SCREEN);
-  return zori_widget_to_screen(screen_widget);
-}
 
 
 int zori_mark_widget(struct zori_widget * widget) {
@@ -555,3 +570,132 @@ zori_id zori_widget_set_closed_result(struct zori_widget * widget, int value) {
   return ZORI_ID_EINVAL;
 }
 
+
+zori_id zori_set_mark_style(zori_id id, struct zori_style style) {
+  struct zori_widget * widget = zori_get_widget(id);
+  struct zori_screen * screen = zori_widget_get_screen(widget);
+  if (screen) {
+      screen->cursors.keyjoy.style = style;
+      return id;
+  } else {
+    return ZORI_ID_EINVAL;
+  }
+}
+
+zori_id zori_set_hover_style(zori_id id, struct zori_style style) {
+  struct zori_widget * widget = zori_get_widget(id);
+  struct zori_screen * screen = zori_widget_get_screen(widget);
+  if (screen) {
+      screen->cursors.mouse.style = style;
+      return id;
+  } else {
+    return ZORI_ID_EINVAL;
+  }
+}
+
+
+/* Moves the widget by the offset (dx, dy). Does not move it's children.  */
+void zori_widget_move_self_by(struct zori_widget * widget, int dx, int dy) {
+  int index, stop;
+  
+  widget->box.at.x    += dx;
+  widget->box.at.y    += dy;
+  widget->inner.at.x  += dx;
+  widget->inner.at.y  += dy;
+  widget->outer.at.x  += dx;
+  widget->outer.at.y  += dy;
+}
+
+/* Moves resizes the widget by (dw, dh). Does not resize it's children.  
+ * Margin and paddding are resized also by dw and dh;
+ */
+void zori_widget_resize_self_by(struct zori_widget * widget, int dw, int dh) {
+  int index, stop;
+  
+  widget->box.size.x    += dw;
+  widget->box.size.y    += dh;
+  widget->inner.size.x  += dw;
+  widget->inner.size.y  += dh;
+  widget->outer.size.x  += dw;
+  widget->outer.size.y  += dh;
+}
+
+
+/* Moves the widget by the offset (dx, dy). It's children will be moved as well recursively
+ * keeping the offset */
+void zori_widget_move_by(struct zori_widget * widget, int dx, int dy) {
+  int index, stop;
+  
+  zori_widget_move_self_by(widget, dx, dy);
+  
+  stop = zori_widget_count_children(widget);
+  for (index= 0 ; index < stop; index ++) {
+    struct zori_widget * child = zori_widget_get_child(widget, index);
+    zori_widget_move_by(child, dx, dy); 
+  }
+}
+
+/* Moves the widget to (x, y). It's children will be moved as well recursively
+ * keeping the offset */
+void zori_widget_move_to(struct zori_widget * widget, int x, int y) {
+  int dx = widget->box.at.x - x;
+  int dy = widget->box.at.y - y;
+  zori_widget_move_by(widget, dx, dy);
+}
+
+
+/* Moves the widget to (x, y). Doesn't move children. */
+void zori_widget_move_self_to(struct zori_widget * widget, int x, int y) {
+  int dx = widget->box.at.x - x;
+  int dy = widget->box.at.y - y;
+  zori_widget_move_self_by(widget, dx, dy);
+}
+
+/* Resizes the widget to (w, h). Doesn't resize children. Margins and padding will be 
+ * resized accordingly. */
+void zori_widget_resize_self_to(struct zori_widget * widget, int w, int h) {
+  int dw = widget->box.size.x - w;
+  int dh = widget->box.size.y - h;
+  zori_widget_resize_self_by(widget, dw, dh);
+}
+
+
+/* Makes the widget fit itself to all direct children.
+ * Does not resize nor move the children.
+ */
+
+void zori_widget_fit_to_children(struct zori_widget * widget) {
+  int index, stop;
+  int min_x = 640;
+  int min_y = 480;
+  int min_w = 0;
+  int min_h = 0;
+  
+  
+  struct zori_screen * screen = zori_widget_get_screen(widget);
+  if (screen) {
+    min_x = screen->widget.box.size.x;
+    min_y = screen->widget.box.size.y;    
+  } 
+  
+  stop = zori_widget_count_children(widget);
+  for (index= 0 ; index < stop; index ++) {
+    struct zori_widget * child = zori_widget_get_child(widget, index);
+    if (child->outer.at.x < min_x) {
+      min_x = child->outer.at.x;
+    }
+    if (child->outer.at.y < min_y) {
+      min_y = child->outer.at.y;
+    }
+    if ((child->outer.size.x) > min_w) {
+      min_w = child->outer.size.x;
+    }
+    if ((child->outer.size.y) > min_h) {
+      min_h = child->outer.size.y;
+    }
+  }
+  
+  zori_widget_move_self_to(widget, min_x, min_y);
+  zori_widget_resize_self_to(widget, min_w, min_h);
+}
+