20130313
[gdash.git] / src / settings.cpp
blobcf0e410f6cbb61e75f5d3c504c9338ed4c4abc0e
1 /*
2 * Copyright (c) 2007-2013, Czirkos Zoltan http://code.google.com/p/gdash/
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include "config.h"
19 #include <glib/gi18n.h>
20 #include <glib.h>
21 #include <map>
23 #include "settings.hpp"
24 #include "misc/logger.hpp"
25 #include "misc/printf.hpp"
26 #include "misc/util.hpp"
27 #include "cave/gamerender.hpp"
28 #include "gfx/pixbuffactory.hpp"
29 #include "input/gameinputhandler.hpp"
31 #ifdef HAVE_SDL
32 #include <SDL.h>
33 #endif
35 #ifdef HAVE_GTK
36 #include <gdk/gdkkeysyms.h>
37 #endif
40 #define SETTINGS_INI_FILE "gdash.ini"
41 #define SETTINGS_GDASH_GROUP "GDash"
43 /* possible languages. */
44 /* they are not translated, so every language name is show in that language itself. */
45 const char *gd_languages_names[]={N_("System default"), "English", "Deutsch", "Magyar", NULL};
47 /* this should correspond to the above one. */
48 #ifdef G_OS_WIN32
49 /* locale names used in windows. */
50 static const char *language_locale_default[]= { "", NULL, };
51 static const char *language_locale_en[]= { "English", NULL, };
52 static const char *language_locale_de[]= { "German", NULL, };
53 static const char *language_locale_hu[]= { "Hungarian", NULL, };
54 /* these will be used on windows for a putenv to trick gtk. */
55 /* on linux, the setlocale call works correctly, and this is not needed. */
56 static const char *languages_for_env[]={ NULL, "en", "de", "hu" };
57 #else
58 /* locale names used in unix. */
59 /* anyone, a better solution for this? */
60 static const char *language_locale_default[]=
61 { "", NULL, };
62 static const char *language_locale_en[]=
63 { "en_US.UTF-8", "en_US.UTF8", "en_US.ISO8859-15", "en_US.ISO8859-1", "en_US.US-ASCII", "en_US", "en", NULL, };
64 static const char *language_locale_de[]=
65 { "de_DE.UTF-8", "de_DE.UTF8", "de_DE.ISO8859-15", "de_DE.ISO8859-1", "de_DE",
66 "de_AT.UTF-8", "de_AT.UTF8", "de_AT.ISO8859-15", "de_AT.ISO8859-1", "de_AT",
67 "de_CH.UTF-8", "de_CH.UTF8", "de_CH.ISO8859-15", "de_CH.ISO8859-1", "de_CH",
68 "de", NULL, };
69 static const char *language_locale_hu[]=
70 { "hu_HU.UTF-8", "hu_HU.ISO8859-2", "hu_HU", "hu", NULL, };
71 #endif /* ifdef g_os_win32 else */
73 /* put the locales to be tried in an array - same for windows and unix */
74 static const char **language_locale[]={
75 language_locale_default,
76 language_locale_en,
77 language_locale_de,
78 language_locale_hu,
82 static std::map<char const *, int *> settings_integers;
83 static std::map<char const *, bool *> settings_bools;
84 static std::map<char const *, std::string *> settings_strings;
87 /* universal settings */
88 std::string gd_username;
89 std::string gd_theme;
90 bool gd_no_invisible_outbox=false;
91 bool gd_all_caves_selectable=false;
92 bool gd_import_as_all_caves_selectable=false;
93 bool gd_use_bdcff_highscore=false;
94 int gd_pal_emu_scanline_shade=80;
95 bool gd_fine_scroll=false;
96 bool gd_particle_effects=true;
97 bool gd_show_story=true;
98 bool gd_show_name_of_game=true;
99 int gd_status_bar_colors=GD_STATUS_BAR_ORIGINAL;
101 /* palette settings */
102 int gd_c64_palette=0;
103 int gd_c64dtv_palette=0;
104 int gd_atari_palette=0;
105 int gd_preferred_palette=GdColor::TypeRGB;
106 /* editor settings */
107 bool gd_game_view=true; /* show animated cells instead of arrows & ... */
108 bool gd_colored_objects=true; /* show objects with different color */
109 bool gd_show_object_list=true; /* show object list */
110 bool gd_show_test_label=true; /* show a label with some variables, for testing */
111 int gd_editor_window_width=800; /* window size */
112 int gd_editor_window_height=520; /* window size */
113 bool gd_fast_uncover_in_test = true;
115 /* preferences */
116 int gd_language=0;
117 bool gd_show_preview=true;
119 /* graphics */
120 bool gd_fullscreen = false;
121 int gd_cell_scale_game=GD_SCALING_2X;
122 bool gd_pal_emulation_game=false;
123 int gd_cell_scale_editor=GD_SCALING_ORIGINAL;
124 bool gd_pal_emulation_editor=false;
126 /* html output option */
127 /* CURRENTLY ONLY FROM THE COMMAND LINE */
128 char *gd_html_stylesheet_filename=NULL;
129 char *gd_html_favicon_filename=NULL;
131 /* GTK keyboard settings */
132 #ifdef HAVE_GTK /* only if having gtk */
133 int gd_gtk_key_left=GDK_Left;
134 int gd_gtk_key_right=GDK_Right;
135 int gd_gtk_key_up=GDK_Up;
136 int gd_gtk_key_down=GDK_Down;
137 int gd_gtk_key_fire_1=GDK_Control_L;
138 int gd_gtk_key_fire_2=GDK_Control_R;
139 int gd_gtk_key_suicide=GDK_s;
140 int gd_gtk_key_fast_forward=GDK_f;
141 int gd_gtk_key_status_bar=GDK_Shift_L;
142 int gd_gtk_key_restart_level=GDK_Escape;
143 #endif /* only if having gtk */
145 /* SDL settings */
146 #ifdef HAVE_SDL
147 int gd_sdl_key_left=SDLK_LEFT;
148 int gd_sdl_key_right=SDLK_RIGHT;
149 int gd_sdl_key_up=SDLK_UP;
150 int gd_sdl_key_down=SDLK_DOWN;
151 int gd_sdl_key_fire_1=SDLK_LCTRL;
152 int gd_sdl_key_fire_2=SDLK_RCTRL;
153 int gd_sdl_key_suicide=SDLK_s;
154 int gd_sdl_key_fast_forward=SDLK_f;
155 int gd_sdl_key_status_bar=SDLK_LSHIFT;
156 int gd_sdl_key_restart_level=SDLK_ESCAPE;
157 #endif /* use_sdl */
159 /* sound settings */
160 #ifdef HAVE_SDL
161 bool gd_sound_enabled=true;
162 bool gd_sound_16bit_mixing=true;
163 bool gd_sound_44khz_mixing=true;
164 bool gd_sound_stereo=true;
165 bool gd_classic_sound=false;
166 int gd_sound_chunks_volume_percent=50;
167 int gd_sound_music_volume_percent=50;
168 #endif /* if gd_sound */
171 /* some directories the game uses */
172 const char *gd_user_config_dir;
173 const char *gd_system_data_dir;
174 const char *gd_system_caves_dir;
175 const char *gd_system_music_dir;
177 std::vector<std::string> gd_sound_dirs, gd_themes_dirs, gd_fonts_dirs;
179 /* command line parameters */
180 int gd_param_license=0;
181 char **gd_param_cavenames=NULL;
184 static void set_page_numbers(Setting *settings) {
185 int page = -1;
186 for (size_t i = 0; settings[i].name != NULL; ++i) {
187 if (settings[i].type == TypePage)
188 page++;
189 settings[i].page = page;
194 Setting *gd_get_game_settings_array() {
195 static Setting settings_static[] = {
196 { TypePage, _("Game") },
197 { TypeStringv, _("Language"), &gd_language, false, gd_languages_names, _("The language of the application. Changing this setting requires a restart!") },
198 { TypeBoolean, _("All caves selectable"), &gd_all_caves_selectable, false, NULL, _("All caves and intermissions can be selected at game start.") },
199 { TypeBoolean, _("Import as all selectable"), &gd_import_as_all_caves_selectable, false, NULL, _("Original, C64 games are imported not with A, E, I, M caves selectable, but all caves (ABCD, EFGH... excluding intermissions). This does not affect BDCFF caves.") },
200 { TypeBoolean, _("Use BDCFF highscore"), &gd_use_bdcff_highscore, false, NULL, _("Use BDCFF highscores. GDash saves highscores in its own configuration directory and also in the *.bd files. However, it prefers loading them from the configuration directory; as the *.bd files might be read-only. You can enable this setting to let GDash load them from the *.bd files. This can be selected for a specific file in the file open dialog, too.") },
201 { TypeBoolean, _("Show story"), &gd_show_story, false, NULL, _("If the cave has a story, it will be shown when the cave is first started.") },
202 { TypeBoolean, _("Game name at uncover"), &gd_show_name_of_game, false, NULL, _("Show the name of the game when uncovering a cave.") },
203 { TypeBoolean, _("No invisible outbox"), &gd_no_invisible_outbox, false, NULL, _("Show invisible outboxes as visible (blinking) ones.") },
205 { TypePage, _("Game graphics") },
206 { TypeTheme, _("Theme"), NULL, false },
207 { TypeStringv, _("Scale"), &gd_cell_scale_game, true, gd_scaling_name, _("Scaling factor and method.") },
208 { TypeBoolean, _("PAL emulation"), &gd_pal_emulation_game, true, NULL, _("Use PAL emulated graphics, i.e. lines are striped, and colors are distorted like on a TV.") },
209 { TypePercent, _(" PAL scanline shade"), &gd_pal_emu_scanline_shade, true, NULL, _("Darker rows for PAL emulation.") },
210 { TypeBoolean, _("Particle effects"), &gd_particle_effects, false, NULL, _("Particle effects during play.") },
211 { TypeBoolean, _("Fine scrolling"), &gd_fine_scroll, false, NULL, _("50 frames per second scrolling.") },
212 { TypeStringv, _("Status bar colors"), &gd_status_bar_colors, false, gd_status_bar_colors_get_names(), _("Preferred status bar color scheme. Only affects the colors, not the status bar layout.") },
213 { TypeStringv, _(" C64 palette"), &gd_c64_palette, false, GdColor::get_c64_palette_names(), _("The color palette for games imported from C64 files.") },
214 { TypeStringv, _(" C64DTV palette"), &gd_c64dtv_palette, false, GdColor::get_c64dtv_palette_names(), _("The color palette for imported C64 DTV games.") },
215 { TypeStringv, _(" Atari palette"), &gd_atari_palette, false, GdColor::get_atari_palette_names(), _("The color palette for imported Atari games.") },
216 { TypeStringv, _(" Preferred palette"), &gd_preferred_palette, false, GdColor::get_palette_types_names(), _("New caves and random colored caves use this palette.") },
218 { TypePage, _("Editor graphics") },
219 { TypeStringv, _("Scale"), &gd_cell_scale_editor, true, gd_scaling_name, _("Scaling factor and method.") },
220 { TypeBoolean, _("PAL emulation"), &gd_pal_emulation_editor, true, NULL, _("Use PAL emulated graphics, i.e. lines are striped, and colors are distorted like on a TV.") },
221 { TypeBoolean, _("Animated view"), &gd_game_view, false, NULL, _("Show simplified view of cave in the editor.") },
222 { TypeBoolean, _("Colored objects"), &gd_colored_objects, false, NULL, _("Cave objects are colored, to make them different from random cave elements.") },
223 { TypeBoolean, _("Object list"), &gd_show_object_list, false, NULL, _("Show objects list sidebar in the editor.") },
224 { TypeBoolean, _("Fast uncover"), &gd_fast_uncover_in_test, false, NULL, _("Fast uncovering and covering of cave in editor cave test.") },
226 #ifdef HAVE_SDL
227 { TypePage, _("Sound") },
228 { TypeBoolean, _("Sound"), &gd_sound_enabled, true, NULL, _("Play sounds and music in the program.") },
229 { TypeBoolean, _("Classic sounds only"), &gd_classic_sound, true, NULL, _("Play only classic sounds taken from the original game.") },
230 { TypeBoolean, _("Stereo sounds"), &gd_sound_stereo, true, NULL, _("If you enable stereo sounds, you will hear the direction of sounds in the caves.") },
231 { TypeBoolean, _("16-bit mixing"), &gd_sound_16bit_mixing, true, NULL, _("Use 16-bit mixing of sounds. Try changing this setting if sound is clicky.") },
232 { TypeBoolean, _("44kHz mixing"), &gd_sound_44khz_mixing, true, NULL, _("Use 44kHz mixing of sounds. Try changing this setting if sound is clicky.") },
233 #endif
235 /* end */
236 { TypeBoolean, NULL },
239 set_page_numbers(settings_static);
241 return settings_static;
246 Setting *gd_get_keyboard_settings_array(GameInputHandler *gih) {
247 static Setting settings_static[] = {
248 { TypePage, _("Keyboard") },
249 { TypeKey, _("Key left"), &gih->get_key_variable(GameInputHandler::KeyLeft), false },
250 { TypeKey, _("Key right"), &gih->get_key_variable(GameInputHandler::KeyRight), false },
251 { TypeKey, _("Key up"), &gih->get_key_variable(GameInputHandler::KeyUp), false },
252 { TypeKey, _("Key down"), &gih->get_key_variable(GameInputHandler::KeyDown), false },
253 { TypeKey, _("Key snap"), &gih->get_key_variable(GameInputHandler::KeyFire1), false },
254 { TypeKey, _("Key snap (alt.)"), &gih->get_key_variable(GameInputHandler::KeyFire2), false },
255 { TypeKey, _("Key suicide"), &gih->get_key_variable(GameInputHandler::KeySuicide), false },
256 { TypeKey, _("Key fast forward"), &gih->get_key_variable(GameInputHandler::KeyFastForward), false },
257 { TypeKey, _("Key status bar"), &gih->get_key_variable(GameInputHandler::KeyStatusBar), false },
258 { TypeKey, _("Key restart level"), &gih->get_key_variable(GameInputHandler::KeyRestartLevel), false },
259 /* end */
260 { TypeBoolean, NULL },
263 set_page_numbers(settings_static);
265 return settings_static;
271 /* gets boolean value from key file; returns def if not found or unreadable */
272 static bool keyfile_get_bool_with_default(GKeyFile *keyfile, const char *group, const char *key, bool def) {
273 GError *error=NULL;
274 gboolean result;
276 result=g_key_file_get_boolean(keyfile, group, key, &error);
277 if (!error)
278 return result!=FALSE;
279 gd_message(error->message);
280 g_error_free(error);
281 return def;
284 /* gets integer value from key file; returns def if not found or unreadable */
285 static int keyfile_get_integer_with_default(GKeyFile *keyfile, const char *group, const char *key, int def) {
286 GError *error=NULL;
287 int result=g_key_file_get_integer(keyfile, group, key, &error);
288 if (!error)
289 return result;
290 gd_message(error->message);
291 g_error_free(error);
292 return def;
295 static std::string keyfile_get_string(GKeyFile *keyfile, const char *group, const char *key) {
296 if (!g_key_file_has_key(keyfile, group, key, NULL))
297 return "";
299 GError *error=NULL;
300 char *result=g_key_file_get_string(keyfile, group, key, &error);
301 if (result) {
302 std::string ret(result);
303 g_free(result);
304 return ret;
306 gd_message(error->message);
307 g_error_free(error);
308 return "";
312 void gd_settings_init() {
313 gd_username = g_get_real_name();
314 settings_bools["no_invisible_outbox"] = &gd_no_invisible_outbox;
315 settings_bools["all_caves_selectable"] = &gd_all_caves_selectable;
316 settings_bools["import_as_all_caves_selectable"] = &gd_import_as_all_caves_selectable;
317 settings_bools["use_bdcff_highscore"] = &gd_use_bdcff_highscore;
318 settings_bools["fine_scroll"] = &gd_fine_scroll;
319 settings_bools["particle_effects"] = &gd_particle_effects;
320 settings_bools["show_story"] = &gd_show_story;
321 settings_bools["show_name_of_game"] = &gd_show_name_of_game;
322 settings_integers["pal_emu_scanline_shade"] = &gd_pal_emu_scanline_shade;
323 settings_integers["status_bar_colors"] = &gd_status_bar_colors;
324 settings_integers["c64_palette"] = &gd_c64_palette;
325 settings_integers["c64dtv_palette"] = &gd_c64dtv_palette;
326 settings_integers["atari_palette"] = &gd_atari_palette;
327 settings_integers["preferred_palette"] = &gd_preferred_palette;
328 settings_strings["username"] = &gd_username;
329 settings_strings["theme"] = &gd_theme;
331 settings_bools["game_view"] = &gd_game_view;
332 settings_bools["colored_objects"] = &gd_colored_objects;
333 settings_bools["show_object_list"] = &gd_show_object_list;
334 settings_bools["show_test_label"] = &gd_show_test_label;
335 settings_bools["show_preview"] = &gd_show_preview;
336 settings_bools["pal_emulation_game"] = &gd_pal_emulation_game;
337 settings_bools["pal_emulation_editor"] = &gd_pal_emulation_editor;
338 settings_bools["fast_uncover_in_test"] = &gd_fast_uncover_in_test;
339 settings_integers["editor_window_width"] = &gd_editor_window_width;
340 settings_integers["editor_window_height"] = &gd_editor_window_height;
341 settings_integers["language"] = &gd_language;
342 settings_integers["cell_scale_game"] = &gd_cell_scale_game;
343 settings_integers["cell_scale_editor"] = &gd_cell_scale_editor;
344 settings_bools["fullscreen"] = &gd_fullscreen;
346 #ifdef HAVE_GTK
347 settings_integers["gtk_key_left"] = &gd_gtk_key_left;
348 settings_integers["gtk_key_right"] = &gd_gtk_key_right;
349 settings_integers["gtk_key_up"] = &gd_gtk_key_up;
350 settings_integers["gtk_key_down"] = &gd_gtk_key_down;
351 settings_integers["gtk_key_fire_1"] = &gd_gtk_key_fire_1;
352 settings_integers["gtk_key_fire_2"] = &gd_gtk_key_fire_2;
353 settings_integers["gtk_key_suicide"] = &gd_gtk_key_suicide;
354 settings_integers["gtk_key_fast_forward"] = &gd_gtk_key_fast_forward;
355 settings_integers["gtk_key_status_bar"] = &gd_gtk_key_status_bar;
356 settings_integers["gtk_key_restart_level"] = &gd_gtk_key_restart_level;
357 #endif
359 #ifdef HAVE_SDL /* only if having sdl */
360 settings_integers["sdl_key_left"] = &gd_sdl_key_left;
361 settings_integers["sdl_key_right"] = &gd_sdl_key_right;
362 settings_integers["sdl_key_up"] = &gd_sdl_key_up;
363 settings_integers["sdl_key_down"] = &gd_sdl_key_down;
364 settings_integers["sdl_key_fire_1"] = &gd_sdl_key_fire_1;
365 settings_integers["sdl_key_fire_2"] = &gd_sdl_key_fire_2;
366 settings_integers["sdl_key_suicide"] = &gd_sdl_key_suicide;
367 settings_integers["sdl_key_fast_forward"] = &gd_sdl_key_fast_forward;
368 settings_integers["sdl_key_status_bar"] = &gd_sdl_key_status_bar;
369 settings_integers["sdl_key_restart_level"] = &gd_sdl_key_restart_level;
370 #endif /* use_sdl */
372 #ifdef HAVE_SDL
373 settings_bools["sound"] = &gd_sound_enabled;
374 settings_bools["sound_16bit_mixing"] = &gd_sound_16bit_mixing;
375 settings_bools["sound_44khz_mixing"] = &gd_sound_44khz_mixing;
376 settings_bools["sound_stereo"] = &gd_sound_stereo;
377 settings_bools["classic_sound"] = &gd_classic_sound;
378 settings_integers["sound_chunks_volume_percent"] = &gd_sound_chunks_volume_percent;
379 settings_integers["sound_music_volume_percent"] = &gd_sound_music_volume_percent;
380 #endif
384 static void add_dirs(std::vector<std::string>& dirs, const char *specific) {
385 // user's own config
386 dirs.push_back(gd_tostring_free(g_build_path(G_DIR_SEPARATOR_S, gd_user_config_dir, specific, NULL)));
387 dirs.push_back(gd_tostring_free(g_build_path(G_DIR_SEPARATOR_S, gd_user_config_dir, NULL)));
388 // system-wide gdash config
389 dirs.push_back(gd_tostring_free(g_build_path(G_DIR_SEPARATOR_S, gd_system_data_dir, specific, NULL)));
390 dirs.push_back(gd_tostring_free(g_build_path(G_DIR_SEPARATOR_S, gd_system_data_dir, NULL)));
391 // for testing: actual directory
392 dirs.push_back(gd_tostring_free(g_build_path(G_DIR_SEPARATOR_S, ".", specific, NULL)));
393 dirs.push_back(gd_tostring_free(g_build_path(G_DIR_SEPARATOR_S, ".", NULL)));
396 /* sets up directiories and loads translations */
397 void gd_settings_init_dirs() {
398 #ifdef G_OS_WIN32
399 /* on win32, use the glib function. */
400 gd_system_data_dir=g_win32_get_package_installation_directory (NULL, NULL);
401 #else
402 /* on linux, this is a defined, built-in string, $perfix/share/locale */
403 gd_system_data_dir=PKGDATADIR;
404 #endif
405 gd_system_caves_dir=g_build_path(G_DIR_SEPARATOR_S, gd_system_data_dir, "caves", NULL);
406 gd_system_music_dir=g_build_path(G_DIR_SEPARATOR_S, gd_system_data_dir, "music", NULL);
407 gd_user_config_dir=g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), PACKAGE, NULL);
409 add_dirs(gd_sound_dirs, "sound");
410 add_dirs(gd_themes_dirs, "themes");
411 add_dirs(gd_fonts_dirs, "fonts");
414 /* set locale from the gdash setting variable. */
415 /* only bother setting the locale cleverly when we are in the gtk version. */
416 /* for sdl version, not really matters. */
417 /* if no gtk, just set the system default locale. */
418 void gd_settings_set_locale() {
419 if (gd_language<0 || gd_language>=int(G_N_ELEMENTS(language_locale)))
420 gd_language=0; /* switch to default, if out of bounds. */
422 /* on windows, we put the LANGUAGE variable into the environment. that seems to be the only
423 thing gtk+ acts upon. we also set the locale below. */
424 #ifdef G_OS_WIN32
425 g_assert(G_N_ELEMENTS(language_locale)==G_N_ELEMENTS(languages_for_env));
426 if (languages_for_env[gd_language]) {
427 g_setenv("LANGUAGE", languages_for_env[gd_language], TRUE);
429 #endif
431 /* try to set the locale. */
432 int i=0;
433 char *result=NULL;
434 while (result==NULL && language_locale[gd_language][i]!=NULL) {
435 result = setlocale(LC_ALL, language_locale[gd_language][i]);
436 i++;
438 if (result == NULL) {
439 /* failed to set */
440 gd_message(CPrintf("Failed to set language to '%s'. Switching to system default locale.") % gd_languages_names[gd_language]);
441 setlocale(LC_ALL, "");
445 /* sets up directiories and loads translations */
446 /* also instructs gettext to give all strings as utf8, as gtk uses that */
447 void gd_settings_init_translation() {
448 /* different directories storing the translation files on unix and win32. */
449 /* gdash (and gtk) always uses utf8, so convert translated strings to utf8 if needed. */
450 #ifdef G_OS_WIN32
451 bindtextdomain("gtk20-properties", gd_system_data_dir);
452 bind_textdomain_codeset("gtk20-properties", "UTF-8");
453 bindtextdomain("gtk20", gd_system_data_dir);
454 bind_textdomain_codeset("gtk20", "UTF-8");
455 bindtextdomain("glib20", gd_system_data_dir);
456 bind_textdomain_codeset("glib20", "UTF-8");
457 bindtextdomain(PACKAGE, gd_system_data_dir); /* gdash */
458 bind_textdomain_codeset(PACKAGE, "UTF-8");
459 #else
460 bindtextdomain(PACKAGE, LOCALEDIR); /* gdash */
461 bind_textdomain_codeset(PACKAGE, "UTF-8");
462 #endif
463 textdomain(PACKAGE); /* set default textdomain to gdash */
467 /* load settings from .config/gdash/gdash.ini */
468 void gd_load_settings() {
469 GError *error=NULL;
470 gchar *data;
471 gsize length;
473 char *filename=g_build_path(G_DIR_SEPARATOR_S, gd_user_config_dir, SETTINGS_INI_FILE, NULL);
474 if (!g_file_get_contents(filename, &data, &length, &error)) {
475 /* no ini file found */
476 gd_message(CPrintf("%s: %s") % filename % error->message);
477 g_error_free(error);
478 return;
480 g_free(filename);
482 /* if zero length file, also return */
483 if (length==0)
484 return;
486 GKeyFile *ini=g_key_file_new();
487 gboolean success=g_key_file_load_from_data(ini, data, length, G_KEY_FILE_NONE, &error);
488 g_free(data);
489 if (!success) {
490 gd_message(CPrintf("INI file contents error: %s") % error->message);
491 g_error_free(error);
492 return;
495 /* load the settings */
496 for (std::map<char const *, int *>::const_iterator it = settings_integers.begin(); it != settings_integers.end(); ++it) {
497 char const *key = it->first;
498 int &var = *it->second;
499 var = keyfile_get_integer_with_default(ini, SETTINGS_GDASH_GROUP, key, var);
501 for (std::map<char const *, bool *>::const_iterator it = settings_bools.begin(); it != settings_bools.end(); ++it) {
502 char const *key = it->first;
503 bool &var = *it->second;
504 var = keyfile_get_bool_with_default(ini, SETTINGS_GDASH_GROUP, key, var);
506 for (std::map<char const *, std::string *>::const_iterator it = settings_strings.begin(); it != settings_strings.end(); ++it) {
507 char const *key = it->first;
508 std::string &var = *it->second;
509 var = keyfile_get_string(ini, SETTINGS_GDASH_GROUP, key);
512 /* check settings */
513 if (gd_cell_scale_game<0 || gd_cell_scale_game>=GD_SCALING_MAX)
514 gd_cell_scale_game=GD_SCALING_ORIGINAL;
515 if (gd_cell_scale_editor<0 || gd_cell_scale_editor>=GD_SCALING_MAX)
516 gd_cell_scale_editor=GD_SCALING_ORIGINAL;
517 if (gd_preferred_palette<0 || gd_preferred_palette>=int(GdColor::Invalid))
518 gd_preferred_palette=GdColor::TypeRGB;
519 if (gd_status_bar_colors<0 || gd_status_bar_colors > int(GD_STATUS_BAR_MAX))
520 gd_status_bar_colors=GD_STATUS_BAR_ORIGINAL;
522 g_key_file_free(ini);
526 /* save settings to .config/gdash.ini */
527 void gd_save_settings() {
528 GKeyFile *ini=g_key_file_new();
530 /* save them */
531 for (std::map<char const *, int *>::const_iterator it = settings_integers.begin(); it != settings_integers.end(); ++it) {
532 char const *key = it->first;
533 int &var = *it->second;
534 g_key_file_set_integer(ini, SETTINGS_GDASH_GROUP, key, var);
536 for (std::map<char const *, bool *>::const_iterator it = settings_bools.begin(); it != settings_bools.end(); ++it) {
537 char const *key = it->first;
538 bool &var = *it->second;
539 g_key_file_set_boolean(ini, SETTINGS_GDASH_GROUP, key, (gboolean) var);
541 for (std::map<char const *, std::string *>::const_iterator it = settings_strings.begin(); it != settings_strings.end(); ++it) {
542 char const *key = it->first;
543 std::string &var = *it->second;
544 g_key_file_set_string(ini, SETTINGS_GDASH_GROUP, key, var.c_str());
547 GError *error=NULL;
548 /* convert to string and free */
549 gchar *data=g_key_file_to_data(ini, NULL, &error);
550 g_key_file_free(ini);
551 if (error) {
552 /* this is highly unlikely - why would g_key_file_to_data report error? docs do not mention. */
553 gd_warning(CPrintf("Unable to save settings: %s") % error->message);
554 g_error_free(error);
555 g_free(data);
556 return;
559 char *filename=g_build_path(G_DIR_SEPARATOR_S, gd_user_config_dir, SETTINGS_INI_FILE, NULL);
560 g_mkdir_with_parents(gd_user_config_dir, 0700);
561 g_file_set_contents(filename, data, -1, &error);
562 g_free(filename);
563 if (error) {
564 /* error saving the file */
565 gd_warning(CPrintf("Unable to save settings: %s") % error->message);
566 g_error_free(error);
567 g_free(data);
568 return;
570 g_free(data);
573 GOptionContext *gd_option_context_new() {
574 GOptionEntry const entries[]={
575 {"license", 'L', 0, G_OPTION_ARG_NONE, &gd_param_license, N_("Show license and quit")},
576 {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &gd_param_cavenames, N_("Cave names")},
577 {NULL}
579 GOptionContext *context=g_option_context_new(_("[FILE NAME]"));
580 g_option_context_set_help_enabled(context, TRUE);
581 g_option_context_add_main_entries(context, entries, PACKAGE); /* gdash parameters */
583 return context;