Add missing credit for Esperanto translation
[neverball.git] / share / st_common.c
blobc03dec7763552d2104d3d9bea66e75b6a54cbab2
1 /*
2 * Copyright (C) 2013 Neverball authors
4 * NEVERBALL is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
15 #include <SDL.h>
18 #include "config.h"
19 #include "audio.h"
20 #include "video.h"
21 #include "geom.h"
22 #include "lang.h"
23 #include "gui.h"
25 #include "st_common.h"
27 #define AUD_MENU "snd/menu.ogg"
29 /*---------------------------------------------------------------------------*/
32 * Conf screen GUI helpers.
35 void conf_slider(int id, const char *text,
36 int token, int value,
37 int *ids, int num)
39 int jd, kd, i;
41 if ((jd = gui_harray(id)) && (kd = gui_harray(jd)))
43 /* A series of empty buttons forms a "slider". */
45 for (i = num - 1; i >= 0; i--)
47 ids[i] = gui_state(kd, NULL, GUI_SML, token, i);
49 gui_set_hilite(ids[i], (i == value));
52 gui_label(jd, text, GUI_SML, 0, 0);
56 int conf_state(int id, const char *label, const char *text, int token)
58 int jd, kd, rd = 0;
60 if ((jd = gui_harray(id)) && (kd = gui_harray(jd)))
62 rd = gui_state(kd, text, GUI_SML, token, 0);
63 gui_label(jd, label, GUI_SML, 0, 0);
66 return rd;
69 void conf_toggle(int id, const char *label, int token, int value,
70 const char *text1, int value1,
71 const char *text0, int value0)
73 int jd, kd;
75 if ((jd = gui_harray(id)) && (kd = gui_harray(jd)))
77 int btn0, btn1;
79 btn0 = gui_state(kd, text0, GUI_SML, token, value0);
80 btn1 = gui_state(kd, text1, GUI_SML, token, value1);
82 gui_set_hilite(btn0, (value == value0));
83 gui_set_hilite(btn1, (value == value1));
85 gui_label(jd, label, GUI_SML, 0, 0);
89 void conf_header(int id, const char *text, int token)
91 int jd;
93 if ((jd = gui_harray(id)))
95 gui_label(jd, text, GUI_SML, 0, 0);
96 gui_space(jd);
97 gui_start(jd, _("Back"), GUI_SML, token, 0);
100 gui_space(id);
103 void conf_select(int id, const char *text, int token, int value,
104 const struct conf_option *opts, int num)
106 int jd, kd, ld;
107 int i;
109 if ((jd = gui_harray(id)) && (kd = gui_harray(jd)))
111 for (i = 0; i < num; i++)
113 ld = gui_state(kd, _(opts[i].text), GUI_SML,
114 token, opts[i].value);
116 gui_set_hilite(ld, (opts[i].value == value));
119 gui_label(jd, text, GUI_SML, 0, 0);
123 /*---------------------------------------------------------------------------*/
126 * Code shared by most screens (not just conf screens).
128 * FIXME This probably makes ball/st_shared.c obsolete.
131 static int (*common_action)(int tok, int val);
133 void common_init(int (*action_fn)(int, int))
135 common_action = action_fn;
138 void common_leave(struct state *st, struct state *next, int id)
140 gui_delete(id);
143 void common_paint(int id, float st)
145 gui_paint(id);
148 void common_timer(int id, float dt)
150 gui_timer(id, dt);
153 void common_point(int id, int x, int y, int dx, int dy)
155 gui_pulse(gui_point(id, x, y), 1.2f);
158 void common_stick(int id, int a, float v, int bump)
160 gui_pulse(gui_stick(id, a, v, bump), 1.2f);
163 int common_click(int b, int d)
165 if (gui_click(b, d))
167 int active = gui_active();
168 return common_action(gui_token(active), gui_value(active));
170 return 1;
173 int common_keybd(int c, int d)
175 return (d && c == KEY_EXIT) ? common_action(GUI_BACK, 0) : 1;
178 int common_buttn(int b, int d)
180 if (d)
182 int active = gui_active();
184 if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
185 return common_action(gui_token(active), gui_value(active));
186 if (config_tst_d(CONFIG_JOYSTICK_BUTTON_B, b))
187 return common_action(GUI_BACK, 0);
189 return 1;
192 /*---------------------------------------------------------------------------*/
195 * Code shared by conf screens.
198 void conf_common_init(int (*action_fn)(int, int))
200 back_init("back/gui.png");
201 audio_music_fade_to(0.5f, "bgm/inter.ogg");
203 common_init(action_fn);
206 void conf_common_leave(struct state *st, struct state *next, int id)
208 back_free();
210 gui_delete(id);
213 void conf_common_paint(int id, float t)
215 video_push_persp((float) config_get_d(CONFIG_VIEW_FOV), 0.1f, FAR_DIST);
217 back_draw_easy();
219 video_pop_matrix();
221 gui_paint(id);
224 /*---------------------------------------------------------------------------*/
226 enum
228 VIDEO_FULLSCREEN = GUI_LAST,
229 VIDEO_DISPLAY,
230 VIDEO_RESOLUTION,
231 VIDEO_REFLECTION,
232 VIDEO_BACKGROUND,
233 VIDEO_SHADOW,
234 VIDEO_VSYNC,
235 VIDEO_HMD,
236 VIDEO_MULTISAMPLE
239 static struct state *video_back;
241 static int video_action(int tok, int val)
243 int f = config_get_d(CONFIG_FULLSCREEN);
244 int w = config_get_d(CONFIG_WIDTH);
245 int h = config_get_d(CONFIG_HEIGHT);
246 int r = 1;
248 audio_play(AUD_MENU, 1.0f);
250 switch (tok)
252 case GUI_BACK:
253 goto_state(video_back);
254 video_back = NULL;
255 break;
257 case VIDEO_FULLSCREEN:
258 goto_state(&st_null);
259 r = video_mode(val, w, h);
260 goto_state(&st_video);
261 break;
263 case VIDEO_DISPLAY:
264 goto_state(&st_display);
265 break;
267 case VIDEO_REFLECTION:
268 goto_state(&st_null);
269 config_set_d(CONFIG_REFLECTION, val);
270 r = video_mode(f, w, h);
271 goto_state(&st_video);
272 break;
274 case VIDEO_BACKGROUND:
275 goto_state(&st_null);
276 config_set_d(CONFIG_BACKGROUND, val);
277 goto_state(&st_video);
278 break;
280 case VIDEO_SHADOW:
281 goto_state(&st_null);
282 config_set_d(CONFIG_SHADOW, val);
283 goto_state(&st_video);
284 break;
286 case VIDEO_RESOLUTION:
287 goto_state(&st_resol);
288 break;
290 case VIDEO_VSYNC:
291 goto_state(&st_null);
292 config_set_d(CONFIG_VSYNC, val);
293 r = video_mode(f, w, h);
294 goto_state(&st_video);
295 break;
297 case VIDEO_HMD:
298 goto_state(&st_null);
299 config_set_d(CONFIG_HMD, val);
300 r = video_mode(f, w, h);
301 goto_state(&st_video);
302 break;
304 case VIDEO_MULTISAMPLE:
305 goto_state(&st_null);
306 config_set_d(CONFIG_MULTISAMPLE, val);
307 r = video_mode(f, w, h);
308 goto_state(&st_video);
309 break;
312 return r;
315 static int video_gui(void)
317 static const struct conf_option multisample_opts[] = {
318 { N_("Off"), 0 },
319 { N_("2x"), 2 },
320 { N_("4x"), 4 },
321 { N_("8x"), 8 },
324 int id, jd;
326 if ((id = gui_vstack(0)))
328 char resolution[sizeof ("12345678 x 12345678")];
329 const char *display;
330 int dpy = config_get_d(CONFIG_DISPLAY);
332 sprintf(resolution, "%d x %d",
333 config_get_d(CONFIG_WIDTH),
334 config_get_d(CONFIG_HEIGHT));
336 if (!(display = SDL_GetDisplayName(dpy)))
337 display = _("Unknown Display");
339 conf_header(id, _("Graphics"), GUI_BACK);
341 if ((jd = conf_state(id, _("Display"), "Longest Name", VIDEO_DISPLAY)))
343 gui_set_trunc(jd, TRUNC_TAIL);
344 gui_set_label(jd, display);
347 conf_toggle(id, _("Fullscreen"), VIDEO_FULLSCREEN,
348 config_get_d(CONFIG_FULLSCREEN), _("On"), 1, _("Off"), 0);
350 if ((jd = conf_state (id, _("Resolution"), resolution,
351 VIDEO_RESOLUTION)))
354 * Because we always use the desktop display mode, disable
355 * display mode switching in fullscreen.
358 if (config_get_d(CONFIG_FULLSCREEN))
360 gui_set_state(jd, GUI_NONE, 0);
361 gui_set_color(jd, gui_gry, gui_gry);
364 #if ENABLE_HMD
365 conf_toggle(id, _("HMD"), VIDEO_HMD,
366 config_get_d(CONFIG_HMD), _("On"), 1, _("Off"), 0);
367 #endif
369 gui_space(id);
371 conf_toggle(id, _("V-Sync"), VIDEO_VSYNC,
372 config_get_d(CONFIG_VSYNC), _("On"), 1, _("Off"), 0);
373 conf_select(id, _("Antialiasing"), VIDEO_MULTISAMPLE,
374 config_get_d(CONFIG_MULTISAMPLE),
375 multisample_opts, ARRAYSIZE(multisample_opts));
377 gui_space(id);
379 conf_toggle(id, _("Reflection"), VIDEO_REFLECTION,
380 config_get_d(CONFIG_REFLECTION), _("On"), 1, _("Off"), 0);
381 conf_toggle(id, _("Background"), VIDEO_BACKGROUND,
382 config_get_d(CONFIG_BACKGROUND), _("On"), 1, _("Off"), 0);
383 conf_toggle(id, _("Shadow"), VIDEO_SHADOW,
384 config_get_d(CONFIG_SHADOW), _("On"), 1, _("Off"), 0);
386 gui_layout(id, 0, 0);
389 return id;
392 static int video_enter(struct state *st, struct state *prev)
394 if (!video_back)
395 video_back = prev;
397 conf_common_init(video_action);
398 return video_gui();
401 /*---------------------------------------------------------------------------*/
403 enum
405 DISPLAY_SELECT = GUI_LAST
408 static struct state *display_back;
410 static int display_action(int tok, int val)
412 int r = 1;
414 audio_play(AUD_MENU, 1.0f);
416 switch (tok)
418 case GUI_BACK:
419 goto_state(display_back);
420 display_back = NULL;
421 break;
423 case DISPLAY_SELECT:
424 if (val != config_get_d(CONFIG_DISPLAY))
426 goto_state(&st_null);
427 config_set_d(CONFIG_DISPLAY, val);
428 r = video_mode(config_get_d(CONFIG_FULLSCREEN),
429 config_get_d(CONFIG_WIDTH),
430 config_get_d(CONFIG_HEIGHT));
431 goto_state(&st_display);
433 break;
436 return r;
439 static int display_gui(void)
441 int id, jd;
443 int i, n = SDL_GetNumVideoDisplays();
445 if ((id = gui_vstack(0)))
447 conf_header(id, _("Display"), GUI_BACK);
449 for (i = 0; i < n; i++)
451 const char *name = SDL_GetDisplayName(i);
453 jd = gui_state(id, name, GUI_SML, DISPLAY_SELECT, i);
454 gui_set_hilite(jd, (i == config_get_d(CONFIG_DISPLAY)));
457 gui_layout(id, 0, 0);
460 return id;
463 static int display_enter(struct state *st, struct state *prev)
465 if (!display_back)
466 display_back = prev;
468 conf_common_init(display_action);
469 return display_gui();
472 /*---------------------------------------------------------------------------*/
474 struct mode
476 int w;
477 int h;
480 static const struct mode modes[] = {
481 { 2560, 1440 },
482 { 1920, 1200 },
483 { 1920, 1080 },
484 { 1680, 1050 },
485 { 1600, 1200 },
486 { 1600, 900 },
487 { 1440, 900 },
488 { 1366, 768 },
489 { 1280, 1024 },
490 { 1280, 800 },
491 { 1280, 720 },
492 { 1024, 768 },
493 { 800, 600 },
494 { 640, 480 },
495 { 480, 320 },
496 { 320, 240 }
499 enum
501 RESOL_MODE = GUI_LAST
504 static struct state *resol_back;
506 static int resol_action(int tok, int val)
508 int r = 1;
510 audio_play(AUD_MENU, 1.0f);
512 switch (tok)
514 case GUI_BACK:
515 goto_state(resol_back);
516 resol_back = NULL;
517 break;
519 case RESOL_MODE:
520 goto_state(&st_null);
521 r = video_mode(config_get_d(CONFIG_FULLSCREEN),
522 modes[val].w,
523 modes[val].h);
524 goto_state(&st_resol);
525 break;
528 return r;
531 static int resol_gui(void)
533 int id, jd, kd;
535 if ((id = gui_vstack(0)))
537 const int W = config_get_d(CONFIG_WIDTH);
538 const int H = config_get_d(CONFIG_HEIGHT);
540 int i, j, n = ARRAYSIZE(modes);
542 char buff[sizeof ("1234567890 x 1234567890")] = "";
544 conf_header(id, _("Resolution"), GUI_BACK);
546 for (i = 0; i < n; i += 4)
548 if ((jd = gui_harray(id)))
550 for (j = 3; j >= 0; j--)
552 int m = i + j;
554 if (m < n)
556 sprintf(buff, "%d x %d", modes[m].w, modes[m].h);
557 kd = gui_state(jd, buff, GUI_SML, RESOL_MODE, m);
558 gui_set_hilite(kd, (modes[m].w == W &&
559 modes[m].h == H));
561 else
563 gui_space(jd);
569 gui_layout(id, 0, 0);
572 return id;
575 static int resol_enter(struct state *st, struct state *prev)
577 if (!resol_back)
578 resol_back = prev;
580 conf_common_init(resol_action);
581 return resol_gui();
584 /*---------------------------------------------------------------------------*/
586 #define LANG_STEP 10
588 static Array langs;
589 static int first;
591 enum
593 LANG_DEFAULT = GUI_LAST,
594 LANG_SELECT
597 static struct state *lang_back;
599 static int lang_action(int tok, int val)
601 int r = 1;
603 struct lang_desc *desc;
605 audio_play(AUD_MENU, 1.0f);
607 switch (tok)
609 case GUI_BACK:
610 goto_state(lang_back);
611 lang_back = NULL;
612 break;
614 case GUI_PREV:
615 first -= LANG_STEP;
616 goto_state(&st_lang);
617 break;
619 case GUI_NEXT:
620 first += LANG_STEP;
621 goto_state(&st_lang);
622 break;
624 case LANG_DEFAULT:
625 /* HACK: Reload resources to load the localized font. */
626 goto_state(&st_null);
627 config_set_s(CONFIG_LANGUAGE, "");
628 lang_init();
629 goto_state(&st_lang);
630 break;
632 case LANG_SELECT:
633 desc = LANG_GET(langs, val);
634 goto_state(&st_null);
635 config_set_s(CONFIG_LANGUAGE, desc->code);
636 lang_init();
637 goto_state(&st_lang);
638 break;
641 return r;
644 static int lang_gui(void)
646 const int step = (first == 0 ? LANG_STEP - 1 : LANG_STEP);
648 int id, jd;
649 int i;
651 if ((id = gui_vstack(0)))
653 if ((jd = gui_hstack(id)))
655 gui_label(jd, _("Language"), GUI_SML, 0, 0);
656 gui_space(jd);
657 gui_space(jd);
658 gui_navig(jd, array_len(langs), first, LANG_STEP);
661 gui_space(id);
663 if (step < LANG_STEP)
665 int default_id;
666 default_id = gui_state(id, _("Default"), GUI_SML, LANG_DEFAULT, 0);
667 gui_set_hilite(default_id, !*config_get_s(CONFIG_LANGUAGE));
670 for (i = first; i < first + step; i++)
672 if (i < array_len(langs))
674 struct lang_desc *desc = LANG_GET(langs, i);
676 int lang_id;
678 lang_id = gui_state(id, " ", GUI_SML, LANG_SELECT, i);
680 gui_set_hilite(lang_id, (strcmp(config_get_s(CONFIG_LANGUAGE),
681 desc->code) == 0));
683 /* Set font and rebuild texture. */
685 gui_set_font(lang_id, desc->font);
686 gui_set_label(lang_id, lang_name(desc));
688 else
690 gui_label(id, " ", GUI_SML, 0, 0);
694 gui_layout(id, 0, 0);
697 return id;
700 static int lang_enter(struct state *st, struct state *prev)
702 if (!langs)
704 langs = lang_dir_scan();
705 first = 0;
708 if (!lang_back)
709 lang_back = prev;
711 conf_common_init(lang_action);
712 return lang_gui();
715 void lang_leave(struct state *st, struct state *next, int id)
717 if (!(next == &st_lang || next == &st_null))
719 lang_dir_free(langs);
720 langs = NULL;
723 conf_common_leave(st, next, id);
726 /*---------------------------------------------------------------------------*/
728 struct state st_video = {
729 video_enter,
730 conf_common_leave,
731 conf_common_paint,
732 common_timer,
733 common_point,
734 common_stick,
735 NULL,
736 common_click,
737 common_keybd,
738 common_buttn
741 struct state st_display = {
742 display_enter,
743 conf_common_leave,
744 conf_common_paint,
745 common_timer,
746 common_point,
747 common_stick,
748 NULL,
749 common_click,
750 common_keybd,
751 common_buttn
754 struct state st_resol = {
755 resol_enter,
756 conf_common_leave,
757 conf_common_paint,
758 common_timer,
759 common_point,
760 common_stick,
761 NULL,
762 common_click,
763 common_keybd,
764 common_buttn
767 struct state st_lang = {
768 lang_enter,
769 lang_leave,
770 conf_common_paint,
771 common_timer,
772 common_point,
773 common_stick,
774 NULL,
775 common_click,
776 common_keybd,
777 common_buttn
780 /*---------------------------------------------------------------------------*/