From a4b7cc4eb9a238252c7d60bc9859ce65d7db96dd Mon Sep 17 00:00:00 2001
From: "p.kosyh"
Date: Mon, 11 Oct 2010 11:35:56 +0000
Subject: [PATCH] hack the theme
---
src/sdl-instead/game.c | 130 +++++---
src/sdl-instead/game.h | 6 +
src/sdl-instead/instead.c | 10 +
src/sdl-instead/menu.c | 4 +
src/sdl-instead/themes.c | 188 +++++++++--
src/sdl-instead/themes.h | 4 +
src/sdl-instead/util.c | 2 +-
src/sdl-instead/util.h | 2 +
theme-hack.diff | 684 ++++++++++++++++++++++++++++++++++++++
9 files changed, 944 insertions(+), 86 deletions(-)
create mode 100644 theme-hack.diff
diff --git a/src/sdl-instead/game.c b/src/sdl-instead/game.c
index cae667e..1d6fe43 100644
--- a/src/sdl-instead/game.c
+++ b/src/sdl-instead/game.c
@@ -10,6 +10,7 @@ char game_cwd[PATH_MAX];
char *curgame_dir = NULL;
int game_own_theme = 0;
+int game_theme_changed = 0;
static int game_pic_w = 0;
static int game_pic_h = 0;
@@ -462,10 +463,8 @@ static int inv_enabled(void)
return (game_theme.inv_mode != INV_MODE_DISABLED);
}
-int game_apply_theme(void)
+int game_vidmode(void)
{
- layout_t lay;
- textbox_t box;
int w = opt_mode[0];
int h = opt_mode[1];
@@ -476,15 +475,23 @@ int game_apply_theme(void)
}
if (game_theme_init(w, h))
return -1;
-
- memset(objs, 0, sizeof(struct el) * el_max);
if (gfx_set_mode(game_theme.w, game_theme.h, opt_fs)) {
opt_mode[0] = opt_mode[1] = -1; opt_fs = 0; /* safe options */
return -1;
}
+
if (game_theme_optimize())
return -1;
+ return 0;
+}
+
+int game_apply_theme(void)
+{
+ layout_t lay;
+ textbox_t box;
+
+ memset(objs, 0, sizeof(struct el) * el_max);
gfx_bg(game_theme.bgcol);
game_clear(0, 0, game_theme.w, game_theme.h);
gfx_flip();
@@ -502,7 +509,6 @@ int game_apply_theme(void)
txt_box_set(box, lay);
el_set(el_scene, elt_box, game_theme.win_x, 0, box);
-
if (inv_enabled()) {
lay = txt_layout(game_theme.inv_font, INV_ALIGN(game_theme.inv_mode),
game_theme.inv_w, game_theme.inv_h);
@@ -684,6 +690,34 @@ int counter_fn(int interval, void *p)
return interval;
}
+int game_use_theme(void)
+{
+ game_theme_changed = 0;
+ game_own_theme = 0;
+
+ if (game_default_theme()) {
+ fprintf(stderr, "Can't load default theme.\n");
+ return -1;
+ }
+
+ if (curgame_dir && !access(dirpath(THEME_FILE), R_OK)) {
+ game_own_theme = 1;
+ }
+ if (game_own_theme && opt_owntheme) {
+ if (theme_load(dirpath(THEME_FILE)))
+ return -1;
+ } else if (curtheme_dir && strcmp(DEFAULT_THEME, curtheme_dir)) {
+ game_theme_load(curtheme_dir);
+ }
+ if (game_vidmode())
+ return -1;
+ if (game_apply_theme()) {
+ game_theme_select(DEFAULT_THEME);
+ return -1;
+ }
+ return 0;
+}
+
int game_init(const char *name)
{
getdir(game_cwd, sizeof(game_cwd));
@@ -698,29 +732,12 @@ int game_init(const char *name)
snd_init(opt_hz);
game_change_vol(0, opt_vol);
- if (game_default_theme()) {
- fprintf(stderr, "Can't load default theme.\n");
- return -1;
- }
-
if (game_select(name))
return -1;
-
- if (curgame_dir && !access(dirpath(THEME_FILE), R_OK)) {
- game_own_theme = 1;
- }
-
- if (game_own_theme && opt_owntheme) {
- if (theme_load(dirpath(THEME_FILE)))
- return -1;
- } else if (curtheme_dir && strcmp(DEFAULT_THEME, curtheme_dir)) {
- game_theme_load(curtheme_dir);
- }
- if (game_apply_theme()) {
- game_theme_select(DEFAULT_THEME);
+ if (game_use_theme())
return -1;
- }
+
timer_han = gfx_add_timer(HZ, counter_fn, NULL);
if (!curgame_dir) {
@@ -760,10 +777,35 @@ void free_last(void)
sounds_free();
}
-void game_done(int err)
+void game_release_theme(void)
{
int i;
+ mouse_reset(1);
+ game_cursor(CURSOR_OFF);
+ if (el_img(el_spic))
+ gfx_free_image(el_img(el_spic));
+ for (i = 0; i < el_max; i++) {
+ struct el *o;
+ o = el(i);
+ if (o->type == elt_layout && o->p.p) {
+ txt_layout_free(o->p.lay);
+ } else if (o->type == elt_box && o->p.p) {
+ txt_layout_free(txt_box_layout(o->p.box));
+ txt_box_free(o->p.box);
+ }
+ o->p.p = NULL;
+ o->drawn = 0;
+ }
+ if (menu)
+ gfx_free_image(menu);
+ if (menubg)
+ gfx_free_image(menubg);
+ menu = menubg = NULL;
+}
+
+void game_done(int err)
+{
gfx_del_timer(timer_han);
timer_han = NULL;
@@ -774,33 +816,8 @@ void game_done(int err)
if (menu_shown)
menu_toggle();
- mouse_reset(1);
- game_cursor(CURSOR_OFF);
- if (el_img(el_spic))
- gfx_free_image(el_img(el_spic));
-
- for (i = 0; i < el_max; i++) {
- struct el *o;
- o = el(i);
-// if (o->type == elt_image && o->p.p) {
-// if (!o->clone)
-// gfx_free_image(o->p.img);
-// } else
- if (o->type == elt_layout && o->p.p) {
- txt_layout_free(o->p.lay);
- } else if (o->type == elt_box && o->p.p) {
- txt_layout_free(txt_box_layout(o->p.box));
- txt_box_free(o->p.box);
- }
- o->p.p = NULL;
- o->drawn = 0;
- }
+ game_release_theme();
free_last();
- if (menu)
- gfx_free_image(menu);
- if (menubg)
- gfx_free_image(menubg);
- menu = menubg = NULL;
game_theme_free();
input_clear();
snd_done();
@@ -1446,6 +1463,9 @@ int game_cmd(char *cmd)
fading = check_fading();
+ if (game_theme_changed == 2 && opt_owntheme && !fading)
+ fading = 1; /* one frame at least */
+
if (fading) { /* take old screen */
game_cursor(CURSOR_CLEAR);
img_t offscreen = gfx_new(game_theme.w, game_theme.h);
@@ -1453,6 +1473,12 @@ int game_cmd(char *cmd)
gfx_draw(oldscreen, 0, 0);
}
+ if (game_theme_changed == 2 && opt_owntheme) {
+ game_theme_update();
+ game_theme_changed = 1;
+ new_place = 1;
+ }
+
if (new_place)
el_clear(el_title);
diff --git a/src/sdl-instead/game.h b/src/sdl-instead/game.h
index 3c67f23..a502ec7 100644
--- a/src/sdl-instead/game.h
+++ b/src/sdl-instead/game.h
@@ -9,6 +9,7 @@
#define HZ 100
extern int game_running;
+extern int game_theme_changed;
extern int nosound_sw;
extern int alsa_sw;
@@ -29,10 +30,15 @@ extern char *game_tmp_path(void);
extern int game_theme_select(const char *name);
extern int game_init(const char *game);
+extern int game_vidmode(void);
+
extern int game_loop(void);
extern void game_done(int err);
extern int game_load_theme(const char *path);
+extern int game_apply_theme(void);
+extern int game_use_theme(void);
+extern void game_release_theme(void);
extern void game_music_player(void);
extern void game_stop_mus(int ms);
diff --git a/src/sdl-instead/instead.c b/src/sdl-instead/instead.c
index 8e21d1a..447653f 100644
--- a/src/sdl-instead/instead.c
+++ b/src/sdl-instead/instead.c
@@ -498,6 +498,15 @@ static int luaB_set_timer(lua_State *L) {
return 0;
}
+extern struct parser cmd_parser[];
+static int luaB_theme_var(lua_State *L) {
+ const char *var = luaL_optstring(L, 1, NULL);
+ const char *val = luaL_optstring(L, 2, NULL);
+ process_cmd(var, val, cmd_parser);
+ game_theme_changed = 2;
+ return 0;
+}
+
static const luaL_Reg base_funcs[] = {
{"doencfile", luaB_doencfile},
{"dofile", luaB_dofile},
@@ -507,6 +516,7 @@ static const luaL_Reg base_funcs[] = {
{"get_gamepath", luaB_get_gamepath},
{"get_steadpath", luaB_get_steadpath},
{"set_timer", luaB_set_timer},
+ {"theme_var", luaB_theme_var},
{NULL, NULL}
};
diff --git a/src/sdl-instead/menu.c b/src/sdl-instead/menu.c
index 045cf04..814669f 100644
--- a/src/sdl-instead/menu.c
+++ b/src/sdl-instead/menu.c
@@ -509,6 +509,10 @@ int game_menu_act(const char *a)
unlink (s);
game_select(curgame_dir);
game_menu_box(0, NULL);
+ if (game_theme_changed) {
+ game_release_theme();
+ game_use_theme();
+ }
// instead_eval("game:ini()"); instead_clear();
game_cmd("look");
custom_theme_warn();
diff --git a/src/sdl-instead/themes.c b/src/sdl-instead/themes.c
index 562c2a2..0a690fc 100644
--- a/src/sdl-instead/themes.c
+++ b/src/sdl-instead/themes.c
@@ -17,6 +17,29 @@ static int parse_gfx_mode(const char *v, void *data)
return 0;
}
+static int out_gfx_mode(const void *v, char **out)
+{
+ char *o;
+ switch (*((int*)v)) {
+ case GFX_MODE_FIXED:
+ o = strdup("fixed");
+ break;
+ case GFX_MODE_EMBEDDED:
+ o = strdup("embedded");
+ break;
+ case GFX_MODE_FLOAT:
+ o = strdup("float");
+ break;
+ default:
+ o = strdup("");
+ break;
+ }
+ if (!o)
+ return -1;
+ *out = 0;
+ return 0;
+}
+
static int parse_inv_mode(const char *v, void *data)
{
int *i = (int *)data;
@@ -39,12 +62,52 @@ static int parse_inv_mode(const char *v, void *data)
return 0;
}
+static int out_inv_mode(const void *v, char **out)
+{
+ char *o;
+ int m = *((int*)v);
+ o = malloc(64);
+ if (!o)
+ return -1;
+ if (m == INV_MODE_DISABLED) {
+ sprintf(o, "disabled");
+ *out = o;
+ return 0;
+ }
+
+ if (m & INV_MODE_VERT) {
+ sprintf(o, "vertical");
+ } else if (m & INV_MODE_HORIZ) {
+ sprintf(o, "vertical");
+ }
+ if ((m & INV_ALIGN_SET(ALIGN_CENTER)) == INV_ALIGN_SET(ALIGN_CENTER)) {
+ strcat(o, "-center");
+ } else if ((m & INV_ALIGN_SET(ALIGN_LEFT)) == INV_ALIGN_SET(ALIGN_LEFT)) {
+ strcat(o, "-left");
+ } else if ((m & INV_ALIGN_SET(ALIGN_RIGHT)) == INV_ALIGN_SET(ALIGN_RIGHT)) {
+ strcat(o, "-right");
+ }
+ *out = o;
+ return 0;
+}
+
static int parse_color(const char *v, void *data)
{
color_t *c = (color_t *)data;
return gfx_parse_color(v, c);
}
+static int out_color(const void *v, char **out)
+{
+ char *o;
+ color_t *c = (color_t *)v;
+ o = malloc(16);
+ if (!o)
+ return -1;
+ sprintf(o, "#%02x%02x%02x", c->r, c->g, c->b);
+ return 0;
+}
+
static int parse_include(const char *v, void *data)
{
int rc;
@@ -70,7 +133,7 @@ struct parser cmd_parser[] = {
{ "scr.gfx.cursor.y", parse_int, &game_theme.cur_y },
{ "scr.gfx.use", parse_full_path, &game_theme.use_name }, /* compat */
{ "scr.gfx.cursor.use", parse_full_path, &game_theme.use_name },
- { "scr.gfx.pad", parse_int, &game_theme.pad },
+ { "scr.gfx.pad", parse_int, &game_theme.pad },
{ "scr.gfx.x", parse_int, &game_theme.gfx_x },
{ "scr.gfx.y", parse_int, &game_theme.gfx_y },
{ "scr.gfx.w", parse_int, &game_theme.max_scene_w },
@@ -79,8 +142,8 @@ struct parser cmd_parser[] = {
{ "win.x", parse_int, &game_theme.win_x },
{ "win.y", parse_int, &game_theme.win_y },
- { "win.w", parse_int, &game_theme.win_w },
- { "win.h", parse_int, &game_theme.win_h },
+ { "win.w", parse_int, &game_theme.win_w },
+ { "win.h", parse_int, &game_theme.win_h },
{ "win.fnt.name", parse_full_path, &game_theme.font_name },
{ "win.fnt.size", parse_int, &game_theme.font_size },
/* compat mode directive */
@@ -94,12 +157,12 @@ struct parser cmd_parser[] = {
{ "inv.x", parse_int, &game_theme.inv_x },
{ "inv.y", parse_int, &game_theme.inv_y },
- { "inv.w", parse_int, &game_theme.inv_w },
- { "inv.h", parse_int, &game_theme.inv_h },
+ { "inv.w", parse_int, &game_theme.inv_w },
+ { "inv.h", parse_int, &game_theme.inv_h },
{ "inv.mode", parse_inv_mode, &game_theme.inv_mode },
- { "inv.horiz", parse_inv_mode, &game_theme.inv_mode },
+ { "inv.horiz", parse_inv_mode, &game_theme.inv_mode },
- { "inv.col.fg", parse_color, &game_theme.icol },
+ { "inv.col.fg", parse_color, &game_theme.icol },
{ "inv.col.link", parse_color, &game_theme.ilcol },
{ "inv.col.alink", parse_color, &game_theme.iacol },
{ "inv.fnt.name", parse_full_path, &game_theme.inv_font_name },
@@ -113,7 +176,7 @@ struct parser cmd_parser[] = {
{ "menu.col.alink", parse_color, &game_theme.menu_alink },
{ "menu.col.alpha", parse_int, &game_theme.menu_alpha },
{ "menu.col.border", parse_color, &game_theme.border_col },
- { "menu.bw", parse_int, &game_theme.border_w },
+ { "menu.bw", parse_int, &game_theme.border_w},
{ "menu.fnt.name", parse_full_path, &game_theme.menu_font_name },
{ "menu.fnt.size", parse_int, &game_theme.menu_font_size },
{ "menu.gfx.button", parse_full_path, &game_theme.menu_button_name },
@@ -128,6 +191,10 @@ struct parser cmd_parser[] = {
{ NULL, },
};
+int theme_setvar()
+{
+}
+
struct game_theme game_theme = {
.scale = 1.0f,
.w = 800,
@@ -163,6 +230,7 @@ struct game_theme game_theme = {
.xoff = 0,
.yoff = 0,
};
+struct game_theme game_theme_unscaled;
static void free_theme_strings(void)
@@ -251,7 +319,6 @@ static int game_theme_scale(int w, int h)
t->yoff = 0;
return 0;
}
-
xs = (float)w / (float)t->w;
ys = (float)h / (float)t->h;
@@ -298,19 +365,9 @@ static int game_theme_scale(int w, int h)
return 0;
}
-static int theme_gfx_scale(void)
+static int theme_bg_scale(void)
{
struct game_theme *t = &game_theme;
- if (theme_img_scale(&t->a_up) ||
- theme_img_scale(&t->a_down) ||
- theme_img_scale(&t->inv_a_up) ||
- theme_img_scale(&t->inv_a_down) ||
- theme_img_scale(&t->use) ||
- theme_img_scale(&t->cursor) ||
- theme_img_scale(&t->menu_button) ||
- theme_img_scale(&t->bg))
- return -1;
-
if (t->bg) {
img_t screen, pic;
int xoff = (t->w - gfx_img_w(t->bg))/2;
@@ -357,12 +414,10 @@ int game_theme_optimize(void)
return 0;
}
-int game_theme_init(int w, int h)
+static int game_theme_update_gfx(void)
{
struct game_theme *t = &game_theme;
-
- game_theme_scale(w, h);
-
+
if (t->font_name) {
fnt_free(t->font);
if (!(t->font = fnt_load(t->font_name, FONT_SZ(t->font_size))))
@@ -381,30 +436,36 @@ int game_theme_init(int w, int h)
goto err;
}
-
if (t->a_up_name) {
gfx_free_image(t->a_up);
if (!(t->a_up = gfx_load_image(t->a_up_name)))
goto err;
+ if (theme_img_scale(&t->a_up))
+ goto err;
}
if (t->a_down_name) {
gfx_free_image(t->a_down);
if (!(t->a_down = gfx_load_image(t->a_down_name)))
goto err;
+ if (theme_img_scale(&t->a_down))
+ goto err;
}
if (t->inv_a_up_name) {
gfx_free_image(t->inv_a_up);
if (!(t->inv_a_up = gfx_load_image(t->inv_a_up_name)))
goto err;
+ if (theme_img_scale(&t->inv_a_up))
+ goto err;
}
-
if (t->inv_a_down_name) {
gfx_free_image(t->inv_a_down);
if (!(t->inv_a_down = gfx_load_image(t->inv_a_down_name)))
goto err;
+ if (theme_img_scale(&t->inv_a_down))
+ goto err;
}
if (t->bg_name) {
@@ -412,24 +473,34 @@ int game_theme_init(int w, int h)
t->bg = NULL;
if (t->bg_name[0] && !(t->bg = gfx_load_image(t->bg_name)))
goto err;
+ if (theme_img_scale(&t->bg))
+ goto err;
+ if (theme_bg_scale())
+ goto err;
}
if (t->use_name) {
gfx_free_image(t->use);
if (!(t->use = gfx_load_image(t->use_name)))
goto err;
+ if (theme_img_scale(&t->use))
+ goto err;
}
if (t->cursor_name) {
gfx_free_image(t->cursor);
if (!(t->cursor = gfx_load_image(t->cursor_name)))
goto err;
+ if (theme_img_scale(&t->cursor))
+ goto err;
}
if (t->menu_button_name) {
gfx_free_image(t->menu_button);
if (!(t->menu_button = gfx_load_image(t->menu_button_name)))
goto err;
+ if (theme_img_scale(&t->menu_button))
+ goto err;
}
if (t->click_name) {
@@ -444,18 +515,69 @@ int game_theme_init(int w, int h)
fprintf(stderr,"Can't init theme. Not all required elements are defined.\n");
goto err;
}
-
- if (theme_gfx_scale()) {
- fprintf(stderr, "Can't scale theme.\n");
- goto err;
- }
return 0;
err:
- fprintf(stderr, "Can not init theme!\n");
- game_theme_free();
return -1;
}
+int game_theme_init(int w, int h)
+{
+ memcpy(&game_theme_unscaled, &game_theme, sizeof(game_theme));
+ game_theme_scale(w, h);
+ if (game_theme_update_gfx()) {
+ fprintf(stderr, "Can not init theme!\n");
+ game_theme_free();
+ return -1;
+ }
+ return 0;
+}
+
+int game_theme_update(void)
+{
+ int w, h;
+
+ w = game_theme.w;
+ h = game_theme.h;
+
+ game_release_theme();
+
+ game_theme.scale = game_theme_unscaled.scale;
+ game_theme.w = game_theme_unscaled.w;
+ game_theme.h = game_theme_unscaled.h;
+ game_theme.pad = game_theme_unscaled.pad;
+ game_theme.win_x = game_theme_unscaled.win_x;
+ game_theme.win_y = game_theme_unscaled.win_y;
+ game_theme.win_w = game_theme_unscaled.win_w;
+ game_theme.win_h = game_theme_unscaled.win_h;
+ game_theme.font_size = game_theme_unscaled.font_size;
+ game_theme.gfx_x = game_theme_unscaled.gfx_x;
+ game_theme.gfx_y = game_theme_unscaled.gfx_y;
+ game_theme.max_scene_w = game_theme_unscaled.max_scene_w;
+ game_theme.max_scene_h = game_theme_unscaled.max_scene_h;
+ game_theme.inv_x = game_theme_unscaled.inv_x;
+ game_theme.inv_y = game_theme_unscaled.inv_y;
+ game_theme.inv_w = game_theme_unscaled.inv_w;
+ game_theme.inv_h = game_theme_unscaled.inv_h;
+ game_theme.inv_font_size = game_theme_unscaled.inv_font_size;
+ game_theme.menu_font_size = game_theme_unscaled.menu_font_size;
+ game_theme.menu_button_x = game_theme_unscaled.menu_button_x;
+ game_theme.menu_button_y = game_theme_unscaled.menu_button_y;
+ game_theme.xoff = game_theme_unscaled.xoff;
+ game_theme.yoff = game_theme_unscaled.yoff;
+
+ game_theme_scale(w, h);
+
+ if (game_theme_update_gfx()) {
+ fprintf(stderr, "Can not update theme!\n");
+ return -1;
+ }
+
+ if (game_apply_theme()) {
+ fprintf(stderr, "Can not apply theme!\n");
+ return -1;
+ }
+ return 0;
+}
static int theme_parse(const char *path)
{
diff --git a/src/sdl-instead/themes.h b/src/sdl-instead/themes.h
index eca2316..13c7167 100644
--- a/src/sdl-instead/themes.h
+++ b/src/sdl-instead/themes.h
@@ -103,6 +103,8 @@ extern int themes_nr;
extern char *curtheme_dir;
extern struct game_theme game_theme;
+extern struct game_theme game_theme_unscaled;
+
extern int game_default_theme(void);
extern int game_theme_select(const char *name);
@@ -112,6 +114,8 @@ extern int game_theme_load(const char *name);
extern int game_theme_free(void);
extern int game_theme_init(int w, int h);
extern int game_theme_optimize(void);
+extern int game_theme_update(void);
+
extern int theme_load(const char *name);
extern char *game_local_themes_path(void);
extern int theme_img_scale(img_t *p);
diff --git a/src/sdl-instead/util.c b/src/sdl-instead/util.c
index 0a282c8..38174b8 100644
--- a/src/sdl-instead/util.c
+++ b/src/sdl-instead/util.c
@@ -51,7 +51,7 @@ char *strip(char *s)
return s;
}
-static int process_cmd(char *n, char *v, struct parser *cmd_parser)
+int process_cmd(char *n, char *v, struct parser *cmd_parser)
{
int i;
n = strip(n);
diff --git a/src/sdl-instead/util.h b/src/sdl-instead/util.h
index 0698cf7..4677a39 100644
--- a/src/sdl-instead/util.h
+++ b/src/sdl-instead/util.h
@@ -23,6 +23,8 @@ extern int parse_esc_string(const char *v, void *data);
extern int parse_string(const char *v, void *data);
extern int parse_int(const char *v, void *data);
extern int parse_full_path(const char *v, void *data);
+extern int process_cmd(char *n, char *v, struct parser *cmd_parser);
+
extern char *encode_esc_string(const char *v);
extern char *find_in_esc(const char *l, const char *s);
#ifdef _HAVE_ICONV
diff --git a/theme-hack.diff b/theme-hack.diff
new file mode 100644
index 0000000..3a50d0f
--- /dev/null
+++ b/theme-hack.diff
@@ -0,0 +1,684 @@
+Index: src/sdl-instead/util.c
+===================================================================
+--- src/sdl-instead/util.c (revision 1286)
++++ src/sdl-instead/util.c (working copy)
+@@ -51,7 +51,7 @@
+ return s;
+ }
+
+-static int process_cmd(char *n, char *v, struct parser *cmd_parser)
++int process_cmd(char *n, char *v, struct parser *cmd_parser)
+ {
+ int i;
+ n = strip(n);
+Index: src/sdl-instead/util.h
+===================================================================
+--- src/sdl-instead/util.h (revision 1286)
++++ src/sdl-instead/util.h (working copy)
+@@ -23,6 +23,8 @@
+ extern int parse_string(const char *v, void *data);
+ extern int parse_int(const char *v, void *data);
+ extern int parse_full_path(const char *v, void *data);
++extern int process_cmd(char *n, char *v, struct parser *cmd_parser);
++
+ extern char *encode_esc_string(const char *v);
+ extern char *find_in_esc(const char *l, const char *s);
+ #ifdef _HAVE_ICONV
+Index: src/sdl-instead/themes.c
+===================================================================
+--- src/sdl-instead/themes.c (revision 1286)
++++ src/sdl-instead/themes.c (working copy)
+@@ -17,6 +17,29 @@
+ return 0;
+ }
+
++static int out_gfx_mode(const void *v, char **out)
++{
++ char *o;
++ switch (*((int*)v)) {
++ case GFX_MODE_FIXED:
++ o = strdup("fixed");
++ break;
++ case GFX_MODE_EMBEDDED:
++ o = strdup("embedded");
++ break;
++ case GFX_MODE_FLOAT:
++ o = strdup("float");
++ break;
++ default:
++ o = strdup("");
++ break;
++ }
++ if (!o)
++ return -1;
++ *out = 0;
++ return 0;
++}
++
+ static int parse_inv_mode(const char *v, void *data)
+ {
+ int *i = (int *)data;
+@@ -39,12 +62,52 @@
+ return 0;
+ }
+
++static int out_inv_mode(const void *v, char **out)
++{
++ char *o;
++ int m = *((int*)v);
++ o = malloc(64);
++ if (!o)
++ return -1;
++ if (m == INV_MODE_DISABLED) {
++ sprintf(o, "disabled");
++ *out = o;
++ return 0;
++ }
++
++ if (m & INV_MODE_VERT) {
++ sprintf(o, "vertical");
++ } else if (m & INV_MODE_HORIZ) {
++ sprintf(o, "vertical");
++ }
++ if ((m & INV_ALIGN_SET(ALIGN_CENTER)) == INV_ALIGN_SET(ALIGN_CENTER)) {
++ strcat(o, "-center");
++ } else if ((m & INV_ALIGN_SET(ALIGN_LEFT)) == INV_ALIGN_SET(ALIGN_LEFT)) {
++ strcat(o, "-left");
++ } else if ((m & INV_ALIGN_SET(ALIGN_RIGHT)) == INV_ALIGN_SET(ALIGN_RIGHT)) {
++ strcat(o, "-right");
++ }
++ *out = o;
++ return 0;
++}
++
+ static int parse_color(const char *v, void *data)
+ {
+ color_t *c = (color_t *)data;
+ return gfx_parse_color(v, c);
+ }
+
++static int out_color(const void *v, char **out)
++{
++ char *o;
++ color_t *c = (color_t *)v;
++ o = malloc(16);
++ if (!o)
++ return -1;
++ sprintf(o, "#%02x%02x%02x", c->r, c->g, c->b);
++ return 0;
++}
++
+ static int parse_include(const char *v, void *data)
+ {
+ int rc;
+@@ -70,7 +133,7 @@
+ { "scr.gfx.cursor.y", parse_int, &game_theme.cur_y },
+ { "scr.gfx.use", parse_full_path, &game_theme.use_name }, /* compat */
+ { "scr.gfx.cursor.use", parse_full_path, &game_theme.use_name },
+- { "scr.gfx.pad", parse_int, &game_theme.pad },
++ { "scr.gfx.pad", parse_int, &game_theme.pad },
+ { "scr.gfx.x", parse_int, &game_theme.gfx_x },
+ { "scr.gfx.y", parse_int, &game_theme.gfx_y },
+ { "scr.gfx.w", parse_int, &game_theme.max_scene_w },
+@@ -79,8 +142,8 @@
+
+ { "win.x", parse_int, &game_theme.win_x },
+ { "win.y", parse_int, &game_theme.win_y },
+- { "win.w", parse_int, &game_theme.win_w },
+- { "win.h", parse_int, &game_theme.win_h },
++ { "win.w", parse_int, &game_theme.win_w },
++ { "win.h", parse_int, &game_theme.win_h },
+ { "win.fnt.name", parse_full_path, &game_theme.font_name },
+ { "win.fnt.size", parse_int, &game_theme.font_size },
+ /* compat mode directive */
+@@ -94,12 +157,12 @@
+
+ { "inv.x", parse_int, &game_theme.inv_x },
+ { "inv.y", parse_int, &game_theme.inv_y },
+- { "inv.w", parse_int, &game_theme.inv_w },
+- { "inv.h", parse_int, &game_theme.inv_h },
++ { "inv.w", parse_int, &game_theme.inv_w },
++ { "inv.h", parse_int, &game_theme.inv_h },
+ { "inv.mode", parse_inv_mode, &game_theme.inv_mode },
+- { "inv.horiz", parse_inv_mode, &game_theme.inv_mode },
++ { "inv.horiz", parse_inv_mode, &game_theme.inv_mode },
+
+- { "inv.col.fg", parse_color, &game_theme.icol },
++ { "inv.col.fg", parse_color, &game_theme.icol },
+ { "inv.col.link", parse_color, &game_theme.ilcol },
+ { "inv.col.alink", parse_color, &game_theme.iacol },
+ { "inv.fnt.name", parse_full_path, &game_theme.inv_font_name },
+@@ -113,7 +176,7 @@
+ { "menu.col.alink", parse_color, &game_theme.menu_alink },
+ { "menu.col.alpha", parse_int, &game_theme.menu_alpha },
+ { "menu.col.border", parse_color, &game_theme.border_col },
+- { "menu.bw", parse_int, &game_theme.border_w },
++ { "menu.bw", parse_int, &game_theme.border_w},
+ { "menu.fnt.name", parse_full_path, &game_theme.menu_font_name },
+ { "menu.fnt.size", parse_int, &game_theme.menu_font_size },
+ { "menu.gfx.button", parse_full_path, &game_theme.menu_button_name },
+@@ -128,6 +191,10 @@
+ { NULL, },
+ };
+
++int theme_setvar()
++{
++}
++
+ struct game_theme game_theme = {
+ .scale = 1.0f,
+ .w = 800,
+@@ -163,6 +230,7 @@
+ .xoff = 0,
+ .yoff = 0,
+ };
++struct game_theme game_theme_unscaled;
+
+
+ static void free_theme_strings(void)
+@@ -251,7 +319,6 @@
+ t->yoff = 0;
+ return 0;
+ }
+-
+ xs = (float)w / (float)t->w;
+ ys = (float)h / (float)t->h;
+
+@@ -298,19 +365,9 @@
+ return 0;
+ }
+
+-static int theme_gfx_scale(void)
++static int theme_bg_scale(void)
+ {
+ struct game_theme *t = &game_theme;
+- if (theme_img_scale(&t->a_up) ||
+- theme_img_scale(&t->a_down) ||
+- theme_img_scale(&t->inv_a_up) ||
+- theme_img_scale(&t->inv_a_down) ||
+- theme_img_scale(&t->use) ||
+- theme_img_scale(&t->cursor) ||
+- theme_img_scale(&t->menu_button) ||
+- theme_img_scale(&t->bg))
+- return -1;
+-
+ if (t->bg) {
+ img_t screen, pic;
+ int xoff = (t->w - gfx_img_w(t->bg))/2;
+@@ -357,12 +414,10 @@
+ return 0;
+ }
+
+-int game_theme_init(int w, int h)
++static int game_theme_update_gfx(void)
+ {
+ struct game_theme *t = &game_theme;
+-
+- game_theme_scale(w, h);
+-
++
+ if (t->font_name) {
+ fnt_free(t->font);
+ if (!(t->font = fnt_load(t->font_name, FONT_SZ(t->font_size))))
+@@ -381,30 +436,36 @@
+ goto err;
+ }
+
+-
+ if (t->a_up_name) {
+ gfx_free_image(t->a_up);
+ if (!(t->a_up = gfx_load_image(t->a_up_name)))
+ goto err;
++ if (theme_img_scale(&t->a_up))
++ goto err;
+ }
+
+ if (t->a_down_name) {
+ gfx_free_image(t->a_down);
+ if (!(t->a_down = gfx_load_image(t->a_down_name)))
+ goto err;
++ if (theme_img_scale(&t->a_down))
++ goto err;
+ }
+
+ if (t->inv_a_up_name) {
+ gfx_free_image(t->inv_a_up);
+ if (!(t->inv_a_up = gfx_load_image(t->inv_a_up_name)))
+ goto err;
++ if (theme_img_scale(&t->inv_a_up))
++ goto err;
+ }
+
+-
+ if (t->inv_a_down_name) {
+ gfx_free_image(t->inv_a_down);
+ if (!(t->inv_a_down = gfx_load_image(t->inv_a_down_name)))
+ goto err;
++ if (theme_img_scale(&t->inv_a_down))
++ goto err;
+ }
+
+ if (t->bg_name) {
+@@ -412,24 +473,34 @@
+ t->bg = NULL;
+ if (t->bg_name[0] && !(t->bg = gfx_load_image(t->bg_name)))
+ goto err;
++ if (theme_img_scale(&t->bg))
++ goto err;
++ if (theme_bg_scale())
++ goto err;
+ }
+
+ if (t->use_name) {
+ gfx_free_image(t->use);
+ if (!(t->use = gfx_load_image(t->use_name)))
+ goto err;
++ if (theme_img_scale(&t->use))
++ goto err;
+ }
+
+ if (t->cursor_name) {
+ gfx_free_image(t->cursor);
+ if (!(t->cursor = gfx_load_image(t->cursor_name)))
+ goto err;
++ if (theme_img_scale(&t->cursor))
++ goto err;
+ }
+
+ if (t->menu_button_name) {
+ gfx_free_image(t->menu_button);
+ if (!(t->menu_button = gfx_load_image(t->menu_button_name)))
+ goto err;
++ if (theme_img_scale(&t->menu_button))
++ goto err;
+ }
+
+ if (t->click_name) {
+@@ -444,19 +515,70 @@
+ fprintf(stderr,"Can't init theme. Not all required elements are defined.\n");
+ goto err;
+ }
+-
+- if (theme_gfx_scale()) {
+- fprintf(stderr, "Can't scale theme.\n");
+- goto err;
+- }
+ return 0;
+ err:
+- fprintf(stderr, "Can not init theme!\n");
+- game_theme_free();
+ return -1;
+ }
+
++int game_theme_init(int w, int h)
++{
++ memcpy(&game_theme_unscaled, &game_theme, sizeof(game_theme));
++ game_theme_scale(w, h);
++ if (game_theme_update_gfx()) {
++ fprintf(stderr, "Can not init theme!\n");
++ game_theme_free();
++ return -1;
++ }
++ return 0;
++}
+
++int game_theme_update(void)
++{
++ int w, h;
++
++ w = game_theme.w;
++ h = game_theme.h;
++
++ game_release_theme();
++
++ game_theme.scale = game_theme_unscaled.scale;
++ game_theme.w = game_theme_unscaled.w;
++ game_theme.h = game_theme_unscaled.h;
++ game_theme.pad = game_theme_unscaled.pad;
++ game_theme.win_x = game_theme_unscaled.win_x;
++ game_theme.win_y = game_theme_unscaled.win_y;
++ game_theme.win_w = game_theme_unscaled.win_w;
++ game_theme.win_h = game_theme_unscaled.win_h;
++ game_theme.font_size = game_theme_unscaled.font_size;
++ game_theme.gfx_x = game_theme_unscaled.gfx_x;
++ game_theme.gfx_y = game_theme_unscaled.gfx_y;
++ game_theme.max_scene_w = game_theme_unscaled.max_scene_w;
++ game_theme.max_scene_h = game_theme_unscaled.max_scene_h;
++ game_theme.inv_x = game_theme_unscaled.inv_x;
++ game_theme.inv_y = game_theme_unscaled.inv_y;
++ game_theme.inv_w = game_theme_unscaled.inv_w;
++ game_theme.inv_h = game_theme_unscaled.inv_h;
++ game_theme.inv_font_size = game_theme_unscaled.inv_font_size;
++ game_theme.menu_font_size = game_theme_unscaled.menu_font_size;
++ game_theme.menu_button_x = game_theme_unscaled.menu_button_x;
++ game_theme.menu_button_y = game_theme_unscaled.menu_button_y;
++ game_theme.xoff = game_theme_unscaled.xoff;
++ game_theme.yoff = game_theme_unscaled.yoff;
++
++ game_theme_scale(w, h);
++
++ if (game_theme_update_gfx()) {
++ fprintf(stderr, "Can not update theme!\n");
++ return -1;
++ }
++
++ if (game_apply_theme()) {
++ fprintf(stderr, "Can not apply theme!\n");
++ return -1;
++ }
++ return 0;
++}
++
+ static int theme_parse(const char *path)
+ {
+ if (parse_ini(path, cmd_parser)) {
+Index: src/sdl-instead/instead.c
+===================================================================
+--- src/sdl-instead/instead.c (revision 1286)
++++ src/sdl-instead/instead.c (working copy)
+@@ -498,6 +498,15 @@
+ return 0;
+ }
+
++extern struct parser cmd_parser[];
++static int luaB_theme_var(lua_State *L) {
++ const char *var = luaL_optstring(L, 1, NULL);
++ const char *val = luaL_optstring(L, 2, NULL);
++ process_cmd(var, val, cmd_parser);
++ game_theme_changed = 2;
++ return 0;
++}
++
+ static const luaL_Reg base_funcs[] = {
+ {"doencfile", luaB_doencfile},
+ {"dofile", luaB_dofile},
+@@ -507,6 +516,7 @@
+ {"get_gamepath", luaB_get_gamepath},
+ {"get_steadpath", luaB_get_steadpath},
+ {"set_timer", luaB_set_timer},
++ {"theme_var", luaB_theme_var},
+ {NULL, NULL}
+ };
+
+Index: src/sdl-instead/themes.h
+===================================================================
+--- src/sdl-instead/themes.h (revision 1286)
++++ src/sdl-instead/themes.h (working copy)
+@@ -103,6 +103,8 @@
+ extern char *curtheme_dir;
+
+ extern struct game_theme game_theme;
++extern struct game_theme game_theme_unscaled;
++
+ extern int game_default_theme(void);
+ extern int game_theme_select(const char *name);
+
+@@ -112,6 +114,8 @@
+ extern int game_theme_free(void);
+ extern int game_theme_init(int w, int h);
+ extern int game_theme_optimize(void);
++extern int game_theme_update(void);
++
+ extern int theme_load(const char *name);
+ extern char *game_local_themes_path(void);
+ extern int theme_img_scale(img_t *p);
+Index: src/sdl-instead/menu.c
+===================================================================
+--- src/sdl-instead/menu.c (revision 1286)
++++ src/sdl-instead/menu.c (working copy)
+@@ -509,6 +509,10 @@
+ unlink (s);
+ game_select(curgame_dir);
+ game_menu_box(0, NULL);
++ if (game_theme_changed) {
++ game_release_theme();
++ game_use_theme();
++ }
+ // instead_eval("game:ini()"); instead_clear();
+ game_cmd("look");
+ custom_theme_warn();
+Index: src/sdl-instead/game.c
+===================================================================
+--- src/sdl-instead/game.c (revision 1286)
++++ src/sdl-instead/game.c (working copy)
+@@ -10,6 +10,7 @@
+ char *curgame_dir = NULL;
+
+ int game_own_theme = 0;
++int game_theme_changed = 0;
+
+ static int game_pic_w = 0;
+ static int game_pic_h = 0;
+@@ -462,10 +463,8 @@
+ return (game_theme.inv_mode != INV_MODE_DISABLED);
+ }
+
+-int game_apply_theme(void)
++int game_vidmode(void)
+ {
+- layout_t lay;
+- textbox_t box;
+ int w = opt_mode[0];
+ int h = opt_mode[1];
+
+@@ -476,15 +475,23 @@
+ }
+ if (game_theme_init(w, h))
+ return -1;
+-
+- memset(objs, 0, sizeof(struct el) * el_max);
+
+ if (gfx_set_mode(game_theme.w, game_theme.h, opt_fs)) {
+ opt_mode[0] = opt_mode[1] = -1; opt_fs = 0; /* safe options */
+ return -1;
+ }
++
+ if (game_theme_optimize())
+ return -1;
++ return 0;
++}
++
++int game_apply_theme(void)
++{
++ layout_t lay;
++ textbox_t box;
++
++ memset(objs, 0, sizeof(struct el) * el_max);
+ gfx_bg(game_theme.bgcol);
+ game_clear(0, 0, game_theme.w, game_theme.h);
+ gfx_flip();
+@@ -502,7 +509,6 @@
+ txt_box_set(box, lay);
+ el_set(el_scene, elt_box, game_theme.win_x, 0, box);
+
+-
+ if (inv_enabled()) {
+ lay = txt_layout(game_theme.inv_font, INV_ALIGN(game_theme.inv_mode),
+ game_theme.inv_w, game_theme.inv_h);
+@@ -684,43 +690,54 @@
+ return interval;
+ }
+
+-int game_init(const char *name)
++int game_use_theme(void)
+ {
+- getdir(game_cwd, sizeof(game_cwd));
+- unix_path(game_cwd);
++ game_theme_changed = 0;
++ game_own_theme = 0;
+
+- if (name)
+- game_err_msg(NULL);
+-
+- if (gfx_video_init() || input_init())
+- return -1;
+-
+- snd_init(opt_hz);
+- game_change_vol(0, opt_vol);
+-
+ if (game_default_theme()) {
+ fprintf(stderr, "Can't load default theme.\n");
+ return -1;
+ }
+
+- if (game_select(name))
+- return -1;
+-
+ if (curgame_dir && !access(dirpath(THEME_FILE), R_OK)) {
+ game_own_theme = 1;
+ }
+-
+ if (game_own_theme && opt_owntheme) {
+ if (theme_load(dirpath(THEME_FILE)))
+ return -1;
+ } else if (curtheme_dir && strcmp(DEFAULT_THEME, curtheme_dir)) {
+ game_theme_load(curtheme_dir);
+ }
+-
++ if (game_vidmode())
++ return -1;
+ if (game_apply_theme()) {
+ game_theme_select(DEFAULT_THEME);
+ return -1;
+ }
++ return 0;
++}
++
++int game_init(const char *name)
++{
++ getdir(game_cwd, sizeof(game_cwd));
++ unix_path(game_cwd);
++
++ if (name)
++ game_err_msg(NULL);
++
++ if (gfx_video_init() || input_init())
++ return -1;
++
++ snd_init(opt_hz);
++ game_change_vol(0, opt_vol);
++
++ if (game_select(name))
++ return -1;
++
++ if (game_use_theme())
++ return -1;
++
+ timer_han = gfx_add_timer(HZ, counter_fn, NULL);
+
+ if (!curgame_dir) {
+@@ -760,32 +777,17 @@
+ sounds_free();
+ }
+
+-void game_done(int err)
++void game_release_theme(void)
+ {
+ int i;
+-
+- gfx_del_timer(timer_han);
+- timer_han = NULL;
+-
+- if (opt_autosave && curgame_dir && !err)
+- game_save(0);
+- setdir(game_cwd);
+-// cfg_save();
+-
+- if (menu_shown)
+- menu_toggle();
+ mouse_reset(1);
+- game_cursor(CURSOR_OFF);
++ game_cursor(CURSOR_OFF);
+ if (el_img(el_spic))
+ gfx_free_image(el_img(el_spic));
+
+ for (i = 0; i < el_max; i++) {
+ struct el *o;
+ o = el(i);
+-// if (o->type == elt_image && o->p.p) {
+-// if (!o->clone)
+-// gfx_free_image(o->p.img);
+-// } else
+ if (o->type == elt_layout && o->p.p) {
+ txt_layout_free(o->p.lay);
+ } else if (o->type == elt_box && o->p.p) {
+@@ -795,12 +797,27 @@
+ o->p.p = NULL;
+ o->drawn = 0;
+ }
+- free_last();
+ if (menu)
+ gfx_free_image(menu);
+ if (menubg)
+ gfx_free_image(menubg);
+ menu = menubg = NULL;
++}
++
++void game_done(int err)
++{
++ gfx_del_timer(timer_han);
++ timer_han = NULL;
++
++ if (opt_autosave && curgame_dir && !err)
++ game_save(0);
++ setdir(game_cwd);
++// cfg_save();
++
++ if (menu_shown)
++ menu_toggle();
++ game_release_theme();
++ free_last();
+ game_theme_free();
+ input_clear();
+ snd_done();
+@@ -1446,6 +1463,9 @@
+
+ fading = check_fading();
+
++ if (game_theme_changed == 2 && opt_owntheme && !fading)
++ fading = 1; /* one frame at least */
++
+ if (fading) { /* take old screen */
+ game_cursor(CURSOR_CLEAR);
+ img_t offscreen = gfx_new(game_theme.w, game_theme.h);
+@@ -1453,6 +1473,12 @@
+ gfx_draw(oldscreen, 0, 0);
+ }
+
++ if (game_theme_changed == 2 && opt_owntheme) {
++ game_theme_update();
++ game_theme_changed = 1;
++ new_place = 1;
++ }
++
+ if (new_place)
+ el_clear(el_title);
+
+Index: src/sdl-instead/game.h
+===================================================================
+--- src/sdl-instead/game.h (revision 1286)
++++ src/sdl-instead/game.h (working copy)
+@@ -9,6 +9,7 @@
+ #define HZ 100
+
+ extern int game_running;
++extern int game_theme_changed;
+
+ extern int nosound_sw;
+ extern int alsa_sw;
+@@ -29,10 +30,15 @@
+ extern int game_theme_select(const char *name);
+
+ extern int game_init(const char *game);
++extern int game_vidmode(void);
++
+ extern int game_loop(void);
+ extern void game_done(int err);
+
+ extern int game_load_theme(const char *path);
++extern int game_apply_theme(void);
++extern int game_use_theme(void);
++extern void game_release_theme(void);
+
+ extern void game_music_player(void);
+ extern void game_stop_mus(int ms);