1 #ifndef VG_SETTINGS_MENU_H
2 #define VG_SETTINGS_MENU_H
7 #ifdef VG_GAME_SETTINGS
8 static void vg_game_settings_gui( ui_rect panel
) ;
9 static void vg_game_settings_init(void);
12 struct ui_enum_opt vg_settings_vsync_enum
[] = {
18 struct ui_enum_opt vg_settings_quality_enum
[] = {
19 { 0, "High Quality" },
21 { 2, "Absolute Minimum" },
24 struct ui_enum_opt vg_settings_screen_mode_enum
[] = {
25 { 0, "Fullscreen (desktop)" },
26 { 1, "Fullscreen (native)" },
27 { 2, "Floating Window" }
30 struct ui_enum_opt vg_settings_dsp_enum
[] = {
36 struct vg_setting_ranged_i32
{
37 i32 new_value
, *actual_value
, min
, max
;
43 struct vg_setting_enum
{
44 i32 new_value
, *actual_value
;
46 struct ui_enum_opt
*options
;
50 vsync
, quality
, screenmode
, audio_devices
, dsp
;
51 i32 temp_audio_choice
;
53 static vg_settings
= {
54 .fps_limit
= { .label
= "Fps Limit",
55 .min
=24, .max
=300, .actual_value
= &vg
.fps_limit
},
56 .vsync
= { .label
= "Vsync",
57 .actual_value
= &vg
.vsync
,
58 .options
= vg_settings_vsync_enum
, .option_count
= 3 },
59 .quality
= { .label
= "Graphic Quality",
60 .actual_value
= &vg
.quality_profile
,
61 .options
= vg_settings_quality_enum
, .option_count
= 3 },
62 .screenmode
= { .label
= "Type",
63 .actual_value
= &vg
.screen_mode
,
64 .options
= vg_settings_screen_mode_enum
, .option_count
=3 },
65 .audio_devices
= { .label
= "Audio Device",
66 .actual_value
= &vg_settings
.temp_audio_choice
,
67 .options
= NULL
, .option_count
= 0 },
68 .dsp
= { .label
= "Audio effects (reverb etc.)",
69 .actual_value
= &vg_audio
.dsp_enabled
,
70 .options
= vg_settings_dsp_enum
, .option_count
=2 },
73 static void vg_settings_ui_draw_diff( ui_rect orig
){
75 ui_split( orig
, k_ui_axis_v
, -32, 0, l
, r
);
76 ui_text( r
, "*", 1, k_ui_align_middle_center
, ui_colour(k_ui_blue
) );
80 * ------------------------------------------------------------------------- */
82 static void vg_settings_ui_int( char *buf
, u32 len
){
83 for( u32 i
=0, j
=0; i
<len
; i
++ ){
84 if( ((buf
[i
] >= '0') && (buf
[i
] <= '9')) || (buf
[i
] == '\0') )
89 struct ui_textbox_callbacks
static vg_settings_ui_int_callbacks
= {
90 .change
= vg_settings_ui_int
93 static bool vg_settings_ranged_i32_valid( struct vg_setting_ranged_i32
*prop
){
94 if( prop
->new_value
< prop
->min
) return 0;
95 if( prop
->new_value
> prop
->max
) return 0;
99 static bool vg_settings_ranged_i32_diff( struct vg_setting_ranged_i32
*prop
){
100 if( prop
->new_value
!= *prop
->actual_value
) return 1;
104 static bool vg_settings_ui_ranged_i32( struct vg_setting_ranged_i32
*prop
,
107 rect_copy( rect
, orig
);
109 ui_textbox( rect
, prop
->label
, prop
->buf
, sizeof(prop
->buf
),
110 1, 0, &vg_settings_ui_int_callbacks
);
111 prop
->new_value
= atoi( prop
->buf
);
113 if( vg_settings_ranged_i32_diff( prop
) )
114 vg_settings_ui_draw_diff( orig
);
116 bool valid
= vg_settings_ranged_i32_valid( prop
);
119 ui_split( orig
, k_ui_axis_h
, -1, 0, _null
, line
);
122 ui_fill( line
, ui_colour( k_ui_red
) );
128 static void ui_settings_ranged_i32_init( struct vg_setting_ranged_i32
*prop
){
130 vg_strnull( &tmp
, prop
->buf
, sizeof(prop
->buf
) );
131 vg_strcati32( &tmp
, *prop
->actual_value
);
132 prop
->new_value
= *prop
->actual_value
;
136 * ------------------------------------------------------------------------- */
138 static bool vg_settings_enum_diff( struct vg_setting_enum
*prop
){
139 if( prop
->new_value
!= *prop
->actual_value
) return 1;
143 static bool vg_settings_enum( struct vg_setting_enum
*prop
, ui_rect rect
){
145 rect_copy( rect
, orig
);
147 ui_enum( rect
, prop
->label
,
148 prop
->options
, prop
->option_count
, &prop
->new_value
);
150 if( vg_settings_enum_diff( prop
) )
151 vg_settings_ui_draw_diff( orig
);
156 static void ui_settings_enum_init( struct vg_setting_enum
*prop
){
157 prop
->new_value
= *prop
->actual_value
;
162 static void vg_settings_ui_header( ui_rect inout_panel
, const char *name
){
164 ui_standard_widget( inout_panel
, rect
, 2 );
165 ui_text( rect
, name
, 1, k_ui_align_middle_center
, ui_colour(k_ui_fg
+3) );
169 static bool vg_settings_apply_button( ui_rect inout_panel
, bool validated
){
171 ui_px height
= (vg_ui
.font
->glyph_height
+ 18) * k_ui_scale
;
172 ui_split( inout_panel
, k_ui_axis_h
, -height
, k_ui_padding
,
173 inout_panel
, last_row
);
175 const char *string
= "Apply";
177 if( ui_button( last_row
, string
) == 1 )
182 ui_standard_widget( last_row
, rect
, 1 );
183 ui_fill( rect
, ui_colour( k_ui_bg
+1 ) );
184 ui_outline( rect
, -1, ui_colour( k_ui_red
), 0 );
186 ui_rect t
= { 0,0, ui_text_line_width( string
), 14 };
187 ui_rect_center( rect
, t
);
188 ui_text( t
, string
, 1, k_ui_align_left
, ui_colour(k_ui_fg
+3) );
194 static void vg_settings_video_apply(void){
195 if( vg_settings_enum_diff( &vg_settings
.screenmode
) ){
196 vg
.screen_mode
= vg_settings
.screenmode
.new_value
;
198 if( (vg
.screen_mode
== 0) || (vg
.screen_mode
== 1) ){
199 SDL_DisplayMode video_mode
;
200 if( SDL_GetDesktopDisplayMode( 0, &video_mode
) ){
201 vg_error("SDL_GetDesktopDisplayMode failed: %s\n", SDL_GetError());
204 //vg.display_refresh_rate = video_mode.refresh_rate;
205 vg
.window_x
= video_mode
.w
;
206 vg
.window_y
= video_mode
.h
;
208 SDL_SetWindowSize( vg
.window
, vg
.window_x
, vg
.window_y
);
211 if( vg
.screen_mode
== 0 )
212 SDL_SetWindowFullscreen( vg
.window
, SDL_WINDOW_FULLSCREEN_DESKTOP
);
213 if( vg
.screen_mode
== 1 )
214 SDL_SetWindowFullscreen( vg
.window
, SDL_WINDOW_FULLSCREEN
);
215 if( vg
.screen_mode
== 2 ){
216 SDL_SetWindowFullscreen( vg
.window
, 0 );
217 SDL_SetWindowSize( vg
.window
, 1280, 720 );
218 SDL_SetWindowPosition( vg
.window
, 16, 16 );
219 SDL_SetWindowMinimumSize( vg
.window
, 1280, 720 );
220 SDL_SetWindowMaximumSize( vg
.window
, 4096, 4096 );
224 vg
.fps_limit
= vg_settings
.fps_limit
.new_value
;
225 vg
.quality_profile
= vg_settings
.quality
.new_value
;
226 vg
.vsync
= vg_settings
.vsync
.new_value
;
229 static void aaaaaaaaaaaaaaaaa( ui_rect r
);
230 static void vg_settings_video_gui( ui_rect panel
){
233 ui_standard_widget( panel
, rq
, 1 );
234 vg_settings_enum( &vg_settings
.quality
, rq
);
238 if( vg
.vsync_feature
== k_vsync_feature_error
){
239 ui_info( panel
, "There was an error activating vsync feature." );
244 vg_settings_ui_header( panel
, "Frame Timing" );
246 ui_standard_widget( panel
, duo
, 1 );
247 ui_split_ratio( duo
, k_ui_axis_v
, 0.5f
, 16, d0
, d1
);
249 vg_settings_enum( &vg_settings
.vsync
, d0
);
250 validated
&= vg_settings_ui_ranged_i32( &vg_settings
.fps_limit
, d1
);
252 ui_standard_widget( panel
, duo
, 10 );
253 aaaaaaaaaaaaaaaaa( duo
);
256 vg_settings_ui_header( panel
, "Window Specification" );
258 ui_standard_widget( panel
, duo
, 1 );
259 vg_settings_enum( &vg_settings
.screenmode
, duo
);
261 if( vg_settings_apply_button( panel
, validated
) )
262 vg_settings_video_apply();
265 static void vg_settings_audio_apply(void){
266 if( vg_settings_enum_diff( &vg_settings
.audio_devices
) ){
267 if( vg_audio
.sdl_output_device
){
268 vg_info( "Closing audio device %d\n", vg_audio
.sdl_output_device
);
269 SDL_CloseAudioDevice( vg_audio
.sdl_output_device
);
272 vg_strfree( &vg_audio
.device_choice
);
274 if( vg_settings
.audio_devices
.new_value
== -1 ){ }
275 else if( vg_settings
.audio_devices
.new_value
== -2 ){
276 vg_fatal_error( "Programming error\n" );
279 struct ui_enum_opt
*selected
= NULL
, *oi
;
281 for( int i
=0; i
<vg_settings
.audio_devices
.option_count
; i
++ ){
282 oi
= &vg_settings
.audio_devices
.options
[i
];
284 if( oi
->value
== vg_settings
.audio_devices
.new_value
){
290 vg_strnull( &vg_audio
.device_choice
, NULL
, -1 );
291 vg_strcat( &vg_audio
.device_choice
, oi
->alias
);
294 vg_audio_device_init();
295 *vg_settings
.audio_devices
.actual_value
=
296 vg_settings
.audio_devices
.new_value
;
300 if( vg_settings_enum_diff( &vg_settings
.dsp
) ){
301 *vg_settings
.dsp
.actual_value
=
302 vg_settings
.dsp
.new_value
;
308 static void vg_settings_audio_gui( ui_rect panel
){
310 ui_standard_widget( panel
, rq
, 1 );
311 vg_settings_enum( &vg_settings
.audio_devices
, rq
);
313 ui_standard_widget( panel
, rq
, 1 );
314 vg_settings_enum( &vg_settings
.dsp
, rq
);
316 if( vg_settings_apply_button( panel
, 1 ) )
317 vg_settings_audio_apply();
320 static void vg_settings_open(void){
321 vg
.settings_open
= 1;
323 ui_settings_ranged_i32_init( &vg_settings
.fps_limit
);
324 ui_settings_enum_init( &vg_settings
.vsync
);
325 ui_settings_enum_init( &vg_settings
.quality
);
326 ui_settings_enum_init( &vg_settings
.screenmode
);
328 /* Create audio options */
329 int count
= SDL_GetNumAudioDevices( 0 );
331 struct ui_enum_opt
*options
= malloc( sizeof(struct ui_enum_opt
)*(count
+1) );
332 vg_settings
.audio_devices
.options
= options
;
333 vg_settings
.audio_devices
.option_count
= count
+1;
335 struct ui_enum_opt
*o0
= &options
[0];
336 o0
->alias
= "OS Default";
339 for( int i
=0; i
<count
; i
++ ){
340 struct ui_enum_opt
*oi
= &options
[i
+1];
342 const char *device_name
= SDL_GetAudioDeviceName( i
, 0 );
343 int len
= strlen(device_name
);
345 oi
->alias
= malloc( len
+1 );
346 memcpy( (void *)oi
->alias
, device_name
, len
+1 );
350 if( vg_audio
.device_choice
.buffer
){
351 vg_settings
.temp_audio_choice
= -2;
353 for( int i
=0; i
<count
; i
++ ){
354 struct ui_enum_opt
*oi
= &options
[i
+1];
355 if( !strcmp( oi
->alias
, vg_audio
.device_choice
.buffer
) ){
356 vg_settings
.temp_audio_choice
= oi
->value
;
362 vg_settings
.temp_audio_choice
= -1;
365 ui_settings_enum_init( &vg_settings
.audio_devices
);
366 ui_settings_enum_init( &vg_settings
.dsp
);
368 #ifdef VG_GAME_SETTINGS
369 vg_game_settings_init();
373 static void vg_settings_close(void){
374 vg
.settings_open
= 0;
376 struct ui_enum_opt
*options
= vg_settings
.audio_devices
.options
;
377 for( int i
=1; i
< vg_settings
.audio_devices
.option_count
; i
++ )
378 free( (void *)options
[i
].alias
);
379 free( vg_settings
.audio_devices
.options
);
382 static void vg_settings_gui(void){
384 ui_rect screen
= { 0, 0, vg
.window_x
, vg
.window_y
};
385 ui_rect window
= { 0, 0, 1000, 700 };
386 ui_rect_center( screen
, window
);
387 vg_ui
.wants_mouse
= 1;
389 ui_fill( window
, ui_colour( k_ui_bg
+1 ) );
390 ui_outline( window
, 1, ui_colour( k_ui_bg
+7 ), 0 );
392 ui_rect title
, panel
;
393 ui_split( window
, k_ui_axis_h
, 28, 0, title
, panel
);
394 ui_fill( title
, ui_colour( k_ui_bg
+7 ) );
395 ui_text( title
, "Settings", 1, k_ui_align_middle_center
,
396 ui_colourcont(k_ui_bg
+7) );
399 ui_split( title
, k_ui_axis_v
, title
[2]-title
[3], 2, title
, quit_button
);
401 if( ui_button_text( quit_button
, "X", 1 ) == 1 ){
406 ui_rect_pad( panel
, (ui_px
[2]){ 8, 8 } );
408 const char *opts
[] = { "video", "audio",
409 #ifdef VG_GAME_SETTINGS
415 ui_tabs( panel
, panel
, opts
, vg_list_size(opts
), &page
);
418 vg_settings_video_gui( panel
);
421 vg_settings_audio_gui( panel
);
423 #ifdef VG_GAME_SETTINGS
425 vg_game_settings_gui( panel
);
429 static int cmd_vg_settings_toggle( int argc
, const char *argv
[] ){
434 #endif /* VG_SETTINGS_MENU_H */