Commit e8a4ffc2 by beoran

Working on new gui system on the C side.

parent 7ca340cd
......@@ -28,3 +28,5 @@ build
doc/nd
doc/nd_project
*.geany
*.log
......@@ -20,17 +20,19 @@ include(CheckCXXSourceCompiles)
if(CMAKE_COMPILER_IS_GNUCC)
set(COMPILER_GCC 1)
set(CMAKE_C_FLAGS "-W -Wall -wunused -Wno-unused -Wno-unknown-pragmas -g -std=c99 -ffast-math -fsanitize=address -fstrict-aliasing -Wstrict-aliasing=2")
set(CMAKE_C_FLAGS "-W -Wall -Wno-unused -Wno-unknown-pragmas -g3 -gdwarf-2 -std=c99 -ffast-math -fsanitize=address -fstrict-aliasing -Wstrict-aliasing=2")
# set(CMAKE_LD_FLAGS "-pg")
# always use gnu99, debugging, all warnings except unused and unknown pragmas.
# when compiling with gnu compiler.
# Warn about alisasing because otherwise aliasing problems it may not be detected.
else(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_C_FLAGS "-W -Wall -Wno-unused -Wno-unknown-pragmas -g -std=c99 -ffast-math -fstrict-aliasing -Wstrict-aliasing=2")
endif(CMAKE_COMPILER_IS_GNUCC)
# or for PCC
# set(CMAKE_C_FLAGS "-fpic -fPIC")
set(CMAKE_C_FLAGS "-W -Wall -Wno-unused -Wno-unknown-pragmas -g -std=c99 -ffast-math -fstrict-aliasing -Wstrict-aliasing=2")
find_package(Mruby REQUIRED)
......
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.0" orientation="orthogonal" renderorder="right-down" width="100" height="100" tilewidth="32" tileheight="32" backgroundcolor="#55aaff" nextobjectid="11">
<tileset firstgid="1" name="town" tilewidth="32" tileheight="32">
<tileset firstgid="1" name="town" tilewidth="32" tileheight="32" tilecount="225" columns="15">
<image source="tiles_village_1000.png" width="480" height="480"/>
<terraintypes>
<terrain name="Grass" tile="-1"/>
</terraintypes>
<tile id="0">
<properties>
<property name="blend" value="20"/>
......@@ -15,7 +18,7 @@
<property name="blendmask" value="0"/>
</properties>
</tile>
<tile id="2">
<tile id="2" terrain="0,0,0,0">
<properties>
<property name="blend" value="17"/>
<property name="blendmask" value="2"/>
......@@ -153,7 +156,7 @@
</tile>
</tileset>
<imagelayer name="background">
<image source="../image/background/bluesky2.jpg"/>
<image source="../image/background/bluesky2.jpg" width="640" height="240"/>
<properties>
<property name="parallax" value="1"/>
</properties>
......@@ -367,18 +370,18 @@
</data>
</layer>
<objectgroup name="object_0">
<object id="1" name="start" type="start" gid="35" x="96" y="128">
<object id="1" name="start" type="start" gid="35" x="96" y="128" width="32" height="32">
<properties>
<property name="script" value="particle_burst(3, 4, 10)"/>
</properties>
</object>
<object id="2" name="warp_1" type="warp" gid="35" x="416" y="416">
<object id="2" name="warp_1" type="warp" gid="35" x="416" y="416" width="32" height="32">
<properties>
<property name="id" value="1"/>
<property name="to" value="2"/>
</properties>
</object>
<object id="3" name="warp_2" type="warp" gid="35" x="448" y="1312">
<object id="3" name="warp_2" type="warp" gid="35" x="448" y="1312" width="32" height="32">
<properties>
<property name="id" value="2"/>
<property name="to" value="1"/>
......@@ -391,7 +394,7 @@
<polyline points="0,0 -277,271"/>
</object>
<object id="6" type="foe" x="320" y="448" width="32" height="32"/>
<object id="7" type="foe" gid="42" x="192" y="448"/>
<object id="7" type="foe" gid="42" x="192" y="448" width="32" height="32"/>
</objectgroup>
<layer name="layer_2" width="100" height="100">
<data encoding="csv">
......
......@@ -43,7 +43,7 @@
#define miao_pop(ARR, DEFAULT) (((ARR)->n > 0) ? miao_unsafe_pop(ARR) : DEFAULT)
#define miao_pop_ptr(ARR) (((ARR)->n > 0) ? miao_unsafe_pop_ptr(ARR) : NULL)
#define miao_unsafe_push(ARR, VAL) ((ARR)->n++, (ARR)->a[(ARR)->n] = (VAL))
#define miao_unsafe_push(ARR, VAL) ((ARR)->n++, (ARR)->a[(ARR)->n] = (VAL), &(VAL))
#define miao_push(ARR, VAL) \
(miao_grow(ARR, ((ARR)->n + 1)) ? miao_unsafe_push(ARR, VAL) : NULL)
......@@ -109,5 +109,22 @@
} \
} while(0);
#define miao_delete(ARR, INDEX) \
( miao_out_of_bounds(ARR, ((size_t)INDEX)) ? 0 : \
/* Copy over everything from index + 1 */ \
(memmove(ARR->a + INDEX, ARR->a + INDEX + 1, \
(ARR->n - INDEX - 1) * sizeof(ARR->n) ) , \
(1 + ARR->n--)) \
)
#define miao_index_of(ARR, ENTRY) ( (ENTRY) - ((ARR)->a) )
#define miao_delete_entry(ARR, ENTRY) \
( miao_delete(ARR, miao_index_of(ARR, ENTRY)) )
#define miao_delete_bsearch(ARR, COMPARE, ENTRY) \
( ARR->aux = miao_bsearch(ARR, COMPARE, ENTRY) , \
ARR->aux ? miao_delete_entry(ARR, ARR->aux) : 0 )
#endif
......@@ -6,9 +6,9 @@
#include "miao.h"
/* Typedefs for possible later portability. */
typedef ALLEGRO_COLOR zori_color ;
typedef ALLEGRO_BITMAP zori_bitmap ;
typedef ALLEGRO_FONT zori_font ;
typedef ALLEGRO_COLOR zori_color;
typedef ALLEGRO_BITMAP zori_bitmap;
typedef ALLEGRO_FONT zori_font;
typedef ALLEGRO_EVENT zori_system_event;
typedef ALLEGRO_EVENT_TYPE zori_event_type;
......@@ -25,6 +25,27 @@ typedef int zori_id;
#define ZORI_ID_EINVAL ((zori_id)(-3))
/* Macro: ZORI_CONTAINER_OF(PTR, TYPE, MEMBER)
This macro returns, for the given pointer, a pointer to a containing struct
of type TYPE, in which PTR is a member named MEMBER.
This enables cool ways of type genericity and extension in plain C.
It does not run afoul of strict aliasing since it passes over a char * pointer
and a pointer of a containing struct or union.
*/
#define ZORI_CONTAINER_OF(PTR, TYPE, MEMBER) \
((TYPE *)(((char *)(PTR)) - offsetof(TYPE, MEMBER)))
/** Custom event types, used in conjunction with Allegro event types. */
enum zori_custom_event_type {
ZORI_EVENT_CUSTOM = ALLEGRO_GET_EVENT_TYPE('z', 'o', 'r', 'i'),
ZORI_EVENT_UPDATE,
ZORI_EVENT_DRAW,
};
struct zori_widget;
struct zori_event {
......@@ -44,12 +65,14 @@ struct zori_style {
struct zori_stylepart fore;
struct zori_stylepart back;
struct zori_stylepart text;
struct zori_stylepart border;
};
struct zori_widget;
typedef int zori_handler_func(struct zori_event * event);
/* A single event handler */
struct zori_handler {
zori_event_type type;
zori_handler_func * handler;
......@@ -57,15 +80,28 @@ struct zori_handler {
};
/* System event handlers. */
/* A dynamic array of event handlers event handlers. */
struct zori_handlers miao_of_type(struct zori_handler);
/*
struct zori_handlers {
size_t size;
struct zori_handler * handlers;
/* An entry in a widget registry. */
struct zori_registry_entry {
zori_id id;
struct zori_widget * widget;
};
/* A widget registry as a dynamic array of entries. */
struct zori_registry miao_of_type(struct zori_registry_entry);
/* Generic flags for several zori structs. */
enum zori_flag {
/* The object is not visible, though it may still be interacted with.*/
ZORI_FLAG_HIDDEN = 1 << 0,
/* The object cannot be interacted with, though it is still visible. */
ZORI_FLAG_DISABLED = 1 << 1,
/* The object is both hidden and disabled. */
ZORI_FLAG_DEACTIVATED = ZORI_FLAG_HIDDEN | ZORI_FLAG_DISABLED,
};
*/
/* Mouse or keyboard/joystick cursor. */
......@@ -74,6 +110,7 @@ struct zori_cursor {
struct zori_widget * hover;
struct zori_widget * focus;
zori_bitmap * bitmap;
enum zori_flag flags;
};
......@@ -121,38 +158,118 @@ struct zori_widget {
struct zori_widget * parent;
struct zori_widget * child;
struct zori_widget * sibling;
/* Flags. */
enum zori_flag flags;
};
/* An array of widget pointers. */
struct zori_widget_array {
struct zori_widget * array;
size_t size;
};
struct zori_widget_array miao_of_type(struct zori_widget *);
/* Root level widget. */
struct zori_root {
/* forward declaration. */
struct zori_screen;
/*
* Root level widget, my spread out over several displays.
* In Zori, there can only be a single root level widget active.
* It's ID is always 0;
*/
struct zori_root {
/* A root is a widget. */
struct zori_widget widget;
/* It also manages the cursors*/
struct zori_cursors cursors;
/* It has an array of all widgets it manages. */
/* It has an array of all GUI widgets it manages. */
struct zori_widget_array * widgets;
/* It is linked to a particular display. */
zori_display * display;
/* Current active screen widget if any. */
struct zori_screen * active_screen;
};
/* Forward declaration of a page. */
struct zori_page;
/* The top level widget for a single display. */
struct zori_screen {
/* A screen is a widget. */
struct zori_widget widget;
/* It also manages the cursors. */
struct zori_cursors cursors;
/* Display this screen is on. */
zori_display * display;
/* The GUI page that is active on this screen if any. */
struct zori_page * active_page;
};
/* In Zori, the GUI is paginated. This means that on any
* screen, only a single GUI page can be active. The intent is to
* support different GUI modes such as startup screen, status view,
* settings, HUD, and so on between which can be switched easily. */
struct zori_page {
/* A page is a widget. */
struct zori_widget widget;
};
/* Initializes Zori and creates a top level widget. Returns 0 on success
* or negative on error. The style will be copied and set as default
* if it is not NULL. Otherwise a built-in style will be used.
* Not that ZORI will NOT clean up any images or fonts it uses by itself.
*/
zori_id zori_start(struct zori_style * default_style);
/* Shut down Zori and destroys all widgets. Return 0 on succes or
* negative on error.
*/
zori_id zori_shutdown();
/* Creates a new screen widget. Normally this should be the first widget
* you create after zori_start. */
zori_id zori_new_screen(zori_display * display);
/* Creates a new page widget on the given screen. The page is not
* made the active page, unless if it is the first one created. */
zori_id zori_new_page(zori_id screen);
/* Activates the page on it's display. All other pages are dectivated and
* hidden. */
zori_id zori_activate_page(zori_id page);
/* Creates a new generic widget on the given screen with the given
* dimensions. */
zori_id zori_new(zori_id screen, zori_rebox * box);
/* Sets the flags of a widget. */
zori_id zori_set_flags(zori_id widget, enum zori_flag flags);
/* Sets the whole style of a widget. */
zori_id zori_set_style(zori_id id, struct zori_style * style);
/* Sets the background color of the widget. */
zori_id zori_set_background_color(zori_id id, zori_color color);
/* Sets the foreground color of the widget. */
zori_id zori_set_foreground_color(zori_id id, zori_color color);
zori_id zori_new_root_widget(const struct zori_style * style);
zori_id zori_new_frame_widget(zori_id parent);
/* Creates a new frame widget. */
zori_id zori_new_frame_widget(zori_id parent, zori_rebox box);
zori_id zori_register(zori_id id, zori_event_type type, zori_handler_func handler, void * extra);
/* Creates a new (vertical) menu widget. */
zori_id zori_new_menu_widget(zori_id parent, zori_rebox box, char * text);
/* Creates a new button widget. */
zori_id zori_new_button_widget(zori_id parent, zori_rebox box, char * text);
/* Creates a new conversation widget. */
zori_id zori_new_conversation_widget(zori_id parent, zori_rebox box, char * text);
/* Draws the whole UI and all visible parts. */
void zori_draw_all(void);
/* Updates the state of the UI. Pass in the time passed since last update. */
void zori_update(double dt);
/* Registers an event handler for a widget. */
zori_id zori_register(zori_id id, zori_event_type type, zori_handler_func handler, void * extra);
......
......@@ -20,6 +20,7 @@
#include "monolog.h"
#include "callrb.h"
#include "store.h"
#include "zori.h"
/* The data struct contains all global state and other data of the application.
*/
......@@ -226,6 +227,8 @@ void state_free(State * self) {
self->area = NULL;
/* Disable the active tile map */
state_active_map_id_(self, -1);
/* Disable gui. */
zori_shutdown();
rh_free(self->ruby);
bbconsole_free((BBWidget *)self->console, NULL);
......@@ -622,6 +625,18 @@ State * state_init(State * self, BOOL fullscreen) {
if(!self->camera) {
return state_errmsg_(self, "Out of memory when allocating camera.");
}
/* Set up Zori GUI. */
{
struct zori_style style;
memset(&style, 0, sizeof(style));
style.text.font = self->font;
style.text.color = color_rgb(255,255,255);
style.back.color = color_rgba(64,0,0, 191);
if ( !ZORI_ID_OK_P(zori_start(&style)) ) {
return state_errmsg_(self, "Out of memory when allocating GUI.");
}
}
/* Set up console. */
{
Style style = { color_rgb(255,255,255), color_rgba(64,0,0, 191),
......@@ -731,7 +746,7 @@ void state_draw(State * self) {
/* Draw UI scene graph */
if (self->show_graph) {
scegra_draw();
zori_draw_all();
}
/* Draw the particles from the particle engine. */
// alpsshower_draw(&shower, state_camera(state));
......@@ -775,6 +790,8 @@ void state_update(State * self) {
// effect immediately.
scegra_update(state_frametime(self));
zori_update(state_frametime(self));
}
......
#include "zori.h"
#include "miao.h"
#include <allegro5/allegro_color.h>
/*
* Pardon the pun name, but Zori is the submodule that handles the user
* interface and the menus.
*/
/* registry functionality */
/** Compare registry entries. */
int zori_registry_entry_compare(const void * v1, const void * v2) {
const struct zori_registry_entry * entry1 = v1;
const struct zori_registry_entry * entry2 = v2;
return (entry2->id - entry1->id);
}
/** Initialize the registry. */
zori_id zori_registry_init(struct zori_registry * registry) {
miao_init(registry);
return ZORI_ID_OK;
}
/** Add an entry to the registry. */
zori_id
zori_registry_add(struct zori_registry * registry, zori_id id,
struct zori_widget * widget) {
struct zori_registry_entry entry = { id, widget };
if (miao_push(registry, entry)) {
miao_qsort(registry, zori_registry_entry_compare);
return ZORI_ID_OK;
}
return ZORI_ID_ENOMEM;
}
/** Look up an entry in the registry. */
struct zori_registry_entry *
zori_registry_lookup_entry(struct zori_registry * registry, zori_id id) {
struct zori_registry_entry key = { id, NULL };
return miao_bsearch(registry, zori_registry_entry_compare, &key);
}
/** Look up a widget in the registry. */
struct zori_widget *
zori_registry_lookup(struct zori_registry * registry, zori_id id) {
struct zori_widget * result = NULL;
struct zori_registry_entry * entry = NULL;
entry = zori_registry_lookup_entry(registry, id);
if (entry) {
result = entry->widget;
}
return result;
}
/** Remove an entry from the registry. */
zori_id
zori_registry_remove(struct zori_registry * registry, zori_id id) {
struct zori_registry_entry * entry = NULL;
entry = zori_registry_lookup_entry(registry, id);
if (entry) {
miao_delete_entry(registry, entry);
}
return ZORI_ID_OK;
}
/** Handler functionality */
int zori_handler_compare(const void * v1, const void * v2) {
const struct zori_handler * h1 = v1;
const struct zori_handler * h2 = v2;
......@@ -57,12 +122,170 @@ int zori_handlers_handle(struct zori_handlers * me, struct zori_event * event,
return handler->handler(event);
}
struct zori_root zori_the_root = {0};
static struct zori_root * the_zori_root = NULL;
static struct zori_style * the_default_style = NULL;
static struct zori_registry * the_zori_registry = NULL;
int zori_widget_compare(const void * v1, const void * v2) {
const struct zori_widget * w1 = v1, * w2 = v2;
return (w2->id - w1->id);
}
struct zori_widget * zori_get_widget(zori_id id) {
struct zori_widget key = {0};
key.id = id;
return miao_bsearch(the_zori_root->widgets, zori_widget_compare, &key);
}
zori_id zori_get_unused_id(void) {
zori_id id = -1;
struct zori_widget * found;
do {
id++;
if (id == INT_MAX) { return ZORI_ID_ERROR; }
found = zori_get_widget(id);
} while(found);
return id;
}
zori_id zori_start(struct zori_style * default_style) {
if (the_zori_root) return ZORI_ID_OK;
the_zori_root = calloc(1, sizeof(*the_zori_root));
if (!the_zori_root) return ZORI_ID_ENOMEM;
the_default_style = calloc(1, sizeof(*the_default_style));
if (!the_default_style) return ZORI_ID_ENOMEM;
the_zori_registry = calloc(1, sizeof(*the_zori_registry));
if (!the_zori_registry) return ZORI_ID_ENOMEM;
the_default_style->text.font = al_create_builtin_font();
the_default_style->text.color = al_color_name("white");
the_default_style->border.color = al_color_name("white");
the_default_style->back.color = al_color_name("green");
if (default_style) {
the_zori_root->widget.style = *default_style;
} else {
the_zori_root->widget.style = *the_default_style;
}
miao_init(the_zori_root->widgets);
the_zori_root->widget.id = 0;
zori_registry_add(the_zori_registry, the_zori_root->widget.id, &the_zori_root->widget);
/*
* miao_push(the_zori_root->widgets, &the_zori_root->widget);
* miao_qsort(the_zori_root->widgets, zori_widget_compare);
*/
return the_zori_root->widget.id;
}
void zori_widget_free(struct zori_widget * widget);
struct zori_widget * zori_widget_done(struct zori_widget * widget) {
struct zori_widget * aid, * next;
if (!widget) return widget;
if (widget->child) {
/* Free all children. */
aid = widget->child;
while (aid) {
next = aid->sibling;
zori_widget_free(aid);
aid = next;
}
}
return widget;
}
void zori_widget_free(struct zori_widget * widget) {
/* XXX remove from widget registry too... */
return free(zori_widget_done(widget));
}
int zori_init() {
return 0;
/* Shut down Zori and destroys all widgets. Return 0 on succes or
* negative on error.
*/
zori_id zori_shutdown() {
miao_done(the_zori_registry);
free(the_zori_registry);
the_zori_registry = NULL;
free(the_default_style);
the_default_style = NULL;
assert((void *)(&the_zori_root->widget) == (void *)the_zori_root);
zori_widget_free(&the_zori_root->widget);
the_zori_root = NULL;
return ZORI_ID_OK;
}
/* Creates a new screen widget. Normally this should be the first widget
* you create after zori_start. */
zori_id zori_new_screen(zori_display * display);
/* Creates a new page widget on the given screen. The page is not
* made the active page, unless if it is the first one created. */
zori_id zori_new_page(zori_id screen);
/* Activates the page on it's display. All other pages are dectivated and
* hidden. */
zori_id zori_activate_page(zori_id page);
/* Creates a new generic widget on the given screen with the given
* dimensions. */
zori_id zori_new(zori_id screen, zori_rebox * box);
/* Sets the flags of a widget. */
zori_id zori_set_flags(zori_id widget, enum zori_flag flags);
/* Sets the whole style of a widget. */
zori_id zori_set_style(zori_id id, struct zori_style * style);
/* Sets the background color of the widget. */
zori_id zori_set_background_color(zori_id id, zori_color color);
/* Sets the foreground color of the widget. */
zori_id zori_set_foreground_color(zori_id id, zori_color color);
/* Creates a new frame widget. */
zori_id zori_new_frame_widget(zori_id parent, zori_rebox box);
/* Creates a new (vertical) menu widget. */
zori_id zori_new_menu_widget(zori_id parent, zori_rebox box, char * text);
/* Creates a new button widget. */
zori_id zori_new_button_widget(zori_id parent, zori_rebox box, char * text);
/* Creates a new conversation widget. */
zori_id zori_new_conversation_widget(zori_id parent, zori_rebox box, char * text);
/* Draws the whole UI and all visible parts. */
void zori_draw_all(void) {
}
/* Updates the state of the UI. Pass in the time passed since last update. */
void zori_update(double dt)
{
struct zori_event event;
event.sysev.type = ZORI_EVENT_UPDATE;
event.sysev.user.data1 = (intptr_t)&dt;
zori_handlers_handle(&the_zori_root->widget.handlers, &event, &the_zori_root->widget);
}
/* Registers an event handler for a widget. */
zori_id zori_register(zori_id id, zori_event_type type, zori_handler_func handler, void * extra);
......
# Install script for directory: /home/bjorn/src/eruta/test
# Install script for directory: /home/bjorn/src/eruta-bs/test
# Set the install prefix
IF(NOT DEFINED CMAKE_INSTALL_PREFIX)
......
......@@ -22,17 +22,17 @@ int foo_compare(const void * v1, const void * v2)
}
int foo_each_ptr(size_t i, const struct foo * f, FILE * extra) {
fprintf(extra, "%u => %s\n", i, f->s);
fprintf(extra, "%u => %s\n", (unsigned int)i, f->s);
return 0;
}
int foo_each(size_t i, struct foo f, FILE * extra) {
fprintf(extra, "%u => %s\n", i, f.s);
fprintf(extra, "%u => %s\n", (unsigned int)i, f.s);
return 0;
}
struct foo * foo_each_ptr_with_result(size_t i, struct foo * f, char * extra) {
printf("%u => %s\n", i, f->s);
printf("%u => %s\n", (unsigned int)i, f->s);
return f;
}
......@@ -41,7 +41,7 @@ int foo_check_ptr(const struct foo * f, char * extra) {
}
struct foo foo_each_with_result(size_t i, struct foo f, char * extra) {
printf("%u => %s\n", i, f.s);
printf("%u => %s\n", (unsigned int)i, f.s);
return f;
}
......@@ -101,9 +101,47 @@ TEST_FUNC(miao) {
TEST_ZERO(miao_size(a));
TEST_DONE();
}
TEST_FUNC(miao_delete) {
struct foo f1, f2 , f3;
struct foo * e1, * e2, *e3;
struct foo_array a[1];
struct foo_array d[1];
miao_init(a);
e1 = miao_push_ptr(a);
e1->s = "0 zero";
e1 = miao_push_ptr(a);
e1->s = "1 one";
e1 = miao_push_ptr(a);
e1->s = "2 two";
e1 = miao_push_ptr(a);
e1->s = "3 three";
e1 = miao_push_ptr(a);
e1->s = "4 four";
e1 = miao_push_ptr(a);
e1->s = "5 five";
miao_qsort(a, foo_compare);
miao_each_with_result(a, foo_each_with_result, f3, foo_check, "foo");
f1.s = "3 three";
e1 = miao_bsearch(a, foo_compare, &f1);
TEST_NOTNULL(e1);
TEST_INTNEQ(0, miao_delete_entry(a, e1));
TEST_INTEQ(5, miao_size(a));
miao_each_with_result(a, foo_each_with_result, f3, foo_check, "foo");
f1.s = "2 two";
TEST_INTNEQ(0, miao_delete_bsearch(a, foo_compare, &f1));
TEST_INTEQ(4, miao_size(a));
miao_each_with_result(a, foo_each_with_result, f3, foo_check, "foo");
TEST_DONE();
}
int main(void) {
TEST_INIT();
TEST_RUN(miao_delete);
TEST_RUN(miao);
TEST_REPORT();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment