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.
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
,
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
)
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);
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
)
75 if ((jd
= gui_harray(id
)) && (kd
= gui_harray(jd
)))
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
)
93 if ((jd
= gui_harray(id
)))
95 gui_label(jd
, text
, GUI_SML
, 0, 0);
97 gui_start(jd
, _("Back"), GUI_SML
, token
, 0);
103 void conf_select(int id
, const char *text
, int token
, int value
,
104 const struct conf_option
*opts
, int num
)
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
)
143 void common_paint(int id
, float st
)
148 void common_timer(int id
, float 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
)
167 int active
= gui_active();
168 return common_action(gui_token(active
), gui_value(active
));
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
)
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);
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
)
213 void conf_common_paint(int id
, float t
)
215 video_push_persp((float) config_get_d(CONFIG_VIEW_FOV
), 0.1f
, FAR_DIST
);
224 /*---------------------------------------------------------------------------*/
228 VIDEO_FULLSCREEN
= GUI_LAST
,
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
);
248 audio_play(AUD_MENU
, 1.0f
);
253 goto_state(video_back
);
257 case VIDEO_FULLSCREEN
:
258 goto_state(&st_null
);
259 r
= video_mode(val
, w
, h
);
260 goto_state(&st_video
);
264 goto_state(&st_display
);
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
);
274 case VIDEO_BACKGROUND
:
275 goto_state(&st_null
);
276 config_set_d(CONFIG_BACKGROUND
, val
);
277 goto_state(&st_video
);
281 goto_state(&st_null
);
282 config_set_d(CONFIG_SHADOW
, val
);
283 goto_state(&st_video
);
286 case VIDEO_RESOLUTION
:
287 goto_state(&st_resol
);
291 goto_state(&st_null
);
292 config_set_d(CONFIG_VSYNC
, val
);
293 r
= video_mode(f
, w
, h
);
294 goto_state(&st_video
);
298 goto_state(&st_null
);
299 config_set_d(CONFIG_HMD
, val
);
300 r
= video_mode(f
, w
, h
);
301 goto_state(&st_video
);
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
);
315 static int video_gui(void)
317 static const struct conf_option multisample_opts
[] = {
326 if ((id
= gui_vstack(0)))
328 char resolution
[sizeof ("12345678 x 12345678")];
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
,
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
);
365 conf_toggle(id
, _("HMD"), VIDEO_HMD
,
366 config_get_d(CONFIG_HMD
), _("On"), 1, _("Off"), 0);
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
));
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);
392 static int video_enter(struct state
*st
, struct state
*prev
)
397 conf_common_init(video_action
);
401 /*---------------------------------------------------------------------------*/
405 DISPLAY_SELECT
= GUI_LAST
408 static struct state
*display_back
;
410 static int display_action(int tok
, int val
)
414 audio_play(AUD_MENU
, 1.0f
);
419 goto_state(display_back
);
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
);
439 static int display_gui(void)
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);
463 static int display_enter(struct state
*st
, struct state
*prev
)
468 conf_common_init(display_action
);
469 return display_gui();
472 /*---------------------------------------------------------------------------*/
480 static const struct mode modes
[] = {
501 RESOL_MODE
= GUI_LAST
504 static struct state
*resol_back
;
506 static int resol_action(int tok
, int val
)
510 audio_play(AUD_MENU
, 1.0f
);
515 goto_state(resol_back
);
520 goto_state(&st_null
);
521 r
= video_mode(config_get_d(CONFIG_FULLSCREEN
),
524 goto_state(&st_resol
);
531 static int resol_gui(void)
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
--)
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
&&
569 gui_layout(id
, 0, 0);
575 static int resol_enter(struct state
*st
, struct state
*prev
)
580 conf_common_init(resol_action
);
584 /*---------------------------------------------------------------------------*/
593 LANG_DEFAULT
= GUI_LAST
,
597 static struct state
*lang_back
;
599 static int lang_action(int tok
, int val
)
603 struct lang_desc
*desc
;
605 audio_play(AUD_MENU
, 1.0f
);
610 goto_state(lang_back
);
616 goto_state(&st_lang
);
621 goto_state(&st_lang
);
625 /* HACK: Reload resources to load the localized font. */
626 goto_state(&st_null
);
627 config_set_s(CONFIG_LANGUAGE
, "");
629 goto_state(&st_lang
);
633 desc
= LANG_GET(langs
, val
);
634 goto_state(&st_null
);
635 config_set_s(CONFIG_LANGUAGE
, desc
->code
);
637 goto_state(&st_lang
);
644 static int lang_gui(void)
646 const int step
= (first
== 0 ? LANG_STEP
- 1 : LANG_STEP
);
651 if ((id
= gui_vstack(0)))
653 if ((jd
= gui_hstack(id
)))
655 gui_label(jd
, _("Language"), GUI_SML
, 0, 0);
658 gui_navig(jd
, array_len(langs
), first
, LANG_STEP
);
663 if (step
< LANG_STEP
)
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
);
678 lang_id
= gui_state(id
, " ", GUI_SML
, LANG_SELECT
, i
);
680 gui_set_hilite(lang_id
, (strcmp(config_get_s(CONFIG_LANGUAGE
),
683 /* Set font and rebuild texture. */
685 gui_set_font(lang_id
, desc
->font
);
686 gui_set_label(lang_id
, lang_name(desc
));
690 gui_label(id
, " ", GUI_SML
, 0, 0);
694 gui_layout(id
, 0, 0);
700 static int lang_enter(struct state
*st
, struct state
*prev
)
704 langs
= lang_dir_scan();
711 conf_common_init(lang_action
);
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
);
723 conf_common_leave(st
, next
, id
);
726 /*---------------------------------------------------------------------------*/
728 struct state st_video
= {
741 struct state st_display
= {
754 struct state st_resol
= {
767 struct state st_lang
= {
780 /*---------------------------------------------------------------------------*/