naev 0.12.5
options.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include "physfs.h"
11#include <ctype.h>
12#include <libgen.h>
13
14#include "naev.h"
16
17#include "options.h"
18
19#include "array.h"
20#include "background.h"
21#include "colour.h"
22#include "conf.h"
23#include "dialogue.h"
24#include "difficulty.h"
25#include "input.h"
26#include "log.h"
27#include "music.h"
28#include "ndata.h"
29#include "nebula.h"
30#include "nfile.h"
31#include "nstring.h"
32#include "pause.h"
33#include "player.h"
34#include "plugin.h"
35#include "render.h"
36#include "sound.h"
37#include "toolkit.h"
38
39#define BUTTON_WIDTH 120
40#define BUTTON_HEIGHT 30
41
42#define OPT_WIN_GAMEPLAY 0
43#define OPT_WIN_ACCESSIBILITY 1
44#define OPT_WIN_VIDEO 2
45#define OPT_WIN_AUDIO 3
46#define OPT_WIN_INPUT 4
47#define OPT_WIN_PLUGINS 5
48#define OPT_WINDOWS 6
49
50#define AUTONAV_RESET_DIST_MAX 10e3
51#define LANG_CODE_START \
52 7
53
54
55static unsigned int opt_wid = 0;
56static unsigned int *opt_windows;
57static const char *opt_names[] = {
58 N_( "Gameplay" ), N_( "Accessibility" ), N_( "Video" ),
59 N_( "Audio" ), N_( "Input" ), N_( "Plugins" ),
60};
61static_assert( ( sizeof( opt_names ) / sizeof( opt_names[0] ) ) == OPT_WINDOWS,
62 "Options windows mismatch!" );
63static const glColour *cHeader = &cFontGrey;
64
65static int opt_restart = 0;
66static PlayerConf_t local_conf;
67
68/*
69 * External stuff.
70 */
71static KeySemanticType opt_selectedKeybind;
72static int opt_lastKeyPress = 0;
73
74/*
75 * prototypes
76 */
77/* Misc. */
78static void opt_close( unsigned int wid, const char *name );
79static void opt_needRestart( void );
80/* Gameplay. */
81static char **lang_list( int *n );
82static void opt_gameplay( unsigned int wid );
83static void opt_setMapOverlayOpacity( unsigned int wid, const char *str );
84static void opt_OK( unsigned int wid, const char *str );
85static int opt_gameplaySave( unsigned int wid, const char *str );
86static void opt_gameplayDefaults( unsigned int wid, const char *str );
87static void opt_gameplayUpdate( unsigned int wid, const char *str );
88/* Accessibility. */
89static void opt_accessibility( unsigned int wid );
90static int opt_accessibilitySave( unsigned int wid, const char *str );
91static void opt_accessibilityDefaults( unsigned int wid, const char *str );
92static void opt_setBGBrightness( unsigned int wid, const char *str );
93static void opt_setNebuNonuniformity( unsigned int wid, const char *str );
94static void opt_setSaturation( unsigned int wid, const char *str );
95static void opt_setJumpBrightness( unsigned int wid, const char *str );
96static void opt_setColourblindCorrect( unsigned int wid, const char *str );
97static void opt_setColourblindSimulate( unsigned int wid, const char *str );
98static void opt_listColourblind( unsigned int wid, const char *str );
99static void opt_setGameSpeed( unsigned int wid, const char *str );
100/* Video. */
101static void opt_video( unsigned int wid );
102static void opt_videoRes( unsigned int wid, const char *str );
103static int opt_videoSave( unsigned int wid, const char *str );
104static void opt_videoDefaults( unsigned int wid, const char *str );
105static void opt_getVideoMode( int *w, int *h, int *fullscreen );
106static void opt_setGammaCorrection( unsigned int wid, const char *str );
107static void opt_setScalefactor( unsigned int wid, const char *str );
108static void opt_setZoomFar( unsigned int wid, const char *str );
109static void opt_setZoomNear( unsigned int wid, const char *str );
110static void opt_checkHealth( unsigned int wid, const char *str );
111static void opt_checkRestart( unsigned int wid, const char *str );
112/* Audio. */
113static void opt_audio( unsigned int wid );
114static int opt_audioSave( unsigned int wid, const char *str );
115static void opt_audioDefaults( unsigned int wid, const char *str );
116static void opt_audioUpdate( unsigned int wid );
117static void opt_audioLevelStr( char *buf, int max, int type, double pos );
118static void opt_setAudioLevel( unsigned int wid, const char *str );
119static void opt_setEngineLevel( unsigned int wid, const char *str );
120static void opt_beep( unsigned int wid, const char *str );
121/* Keybind menu. */
122static void opt_keybinds( unsigned int wid );
123static void menuKeybinds_getDim( unsigned int wid, int *w, int *h, int *lw,
124 int *lh, int *bw, int *bh );
125static void menuKeybinds_genList( unsigned int wid );
126static void menuKeybinds_update( unsigned int wid, const char *name );
127static void opt_keyDefaults( unsigned int wid, const char *str );
128/* Setting keybindings. */
129static int opt_setKeyEvent( unsigned int wid, SDL_Event *event );
130static void opt_setKey( unsigned int wid, const char *str );
131static void opt_unsetKey( unsigned int wid, const char *str );
132/* Plugins menu. */
133static void opt_plugins( unsigned int wid );
134static void opt_plugins_regenList( unsigned int wid );
135static void opt_plugins_add( unsigned int wid, const char *name );
136static void opt_plugins_update( unsigned int wid, const char *name );
137
141void opt_menu( void )
142{
143 int w, h;
144 const char **names;
145
146 /* Save current configuration over. */
147 conf_copy( &local_conf, &conf );
148
149 /* Dimensions. */
150 w = 680;
151 h = 525;
152
153 /* Create window and tabs. */
154 opt_wid = window_create( "wdwOptions", _( "Options" ), -1, -1, w, h );
155 window_setCancel( opt_wid, opt_close );
156
157 /* Create tabbed window. */
158 names = calloc( 1, sizeof( opt_names ) );
159 for ( size_t i = 0; i < sizeof( opt_names ) / sizeof( opt_names[0] ); i++ )
160 names[i] = _( opt_names[i] );
161 opt_windows = window_addTabbedWindow( opt_wid, -1, -1, -1, -1, "tabOpt",
162 OPT_WINDOWS, (const char **)names, 0 );
163 free( names );
164
165 /* Common stuff. */
166 for ( int i = 0; i < OPT_WINDOWS; i++ ) {
167 unsigned int wid = opt_windows[i];
168 window_addButton( wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnClose",
169 _( "OK" ), opt_OK );
170 window_addText( opt_windows[i], 20, 10,
171 w - 20 - 3 * ( BUTTON_WIDTH + 20 ), BUTTON_HEIGHT + 10, 0,
172 "txtRestart", NULL, NULL, NULL );
173 }
174
175 /* Load tabs. */
176 opt_gameplay( opt_windows[OPT_WIN_GAMEPLAY] );
177 opt_accessibility( opt_windows[OPT_WIN_ACCESSIBILITY] );
178 opt_video( opt_windows[OPT_WIN_VIDEO] );
179 opt_audio( opt_windows[OPT_WIN_AUDIO] );
180 opt_keybinds( opt_windows[OPT_WIN_INPUT] );
181 opt_plugins( opt_windows[OPT_WIN_PLUGINS] );
182
183 /* Set as need restart if needed. */
184 if ( opt_restart )
186}
187
191static void opt_OK( unsigned int wid, const char *str )
192{
193 int ret, prompted_restart;
194
195 prompted_restart = opt_restart;
196 ret = 0;
197 ret |= opt_gameplaySave( opt_windows[OPT_WIN_GAMEPLAY], str );
198 ret |= opt_accessibilitySave( opt_windows[OPT_WIN_ACCESSIBILITY], str );
199 ret |= opt_audioSave( opt_windows[OPT_WIN_AUDIO], str );
200 ret |= opt_videoSave( opt_windows[OPT_WIN_VIDEO], str );
201
202 if ( opt_restart && !prompted_restart )
203 dialogue_msg( _( "Warning" ), "#r%s#0",
204 _( "Restart Naev for changes to take effect." ) );
205
206 /* Close window if no errors occurred. */
207 if ( !ret ) {
208 /* Save current configuration over. */
209 conf_copy( &local_conf, &conf );
210 opt_close( wid, str );
211 }
212}
213
217static void opt_close( unsigned int wid, const char *name )
218{
219 (void)wid;
220 (void)name;
221
222 /* Load old config again. */
223 conf_copy( &conf, &local_conf );
224
225 /* At this point, set sound levels as defined in the config file.
226 * This ensures that sound volumes are reset on "Cancel". */
227 sound_volume( conf.sound );
228 music_volume( conf.music );
229 render_setGamma( conf.gamma_correction );
230
231 window_destroy( opt_wid );
232 opt_wid = 0;
233
234 /* Free config. */
235 conf_free( &local_conf );
236}
237
241void opt_resize( void )
242{
243 int w, h, fullscreen;
244 char buf[16];
245
246 /* Nothing to do if not open. */
247 if ( !opt_wid )
248 return;
249
250 /* Update the resolution input widget. */
251 opt_getVideoMode( &w, &h, &fullscreen );
252 snprintf( buf, sizeof( buf ), "%dx%d", w, h );
253 window_setInput( opt_windows[OPT_WIN_VIDEO], "inpRes", buf );
254}
255
256/*
257 * Gets the list of languages available. Options look like "[ 81%] de".
258 */
259static char **lang_list( int *n )
260{
261 char **ls;
263 const char *syslang = gettext_getSystemLanguage();
264 double syscoverage = gettext_languageCoverage( syslang );
265
266 /* Default English only. */
267 ls = malloc( sizeof( char * ) * 128 );
268 SDL_asprintf( &ls[0], _( "system (%s[%3.0f%%] %s#0)" ),
269 ( syscoverage < 0.8 ) ? "#r" : "", 100. * syscoverage,
270 syslang );
271 *n = 1;
272
273 /* Try to open the available languages. */
274 for ( int i = 0; i < array_size( opts ); i++ ) {
275 char **item = &ls[( *n )++];
276 SDL_asprintf( item, "%s[%3.0f%%] %s",
277 ( opts[i].coverage < 0.8 ) ? "#r" : "",
278 100. * opts[i].coverage, opts[i].language );
279 free( opts[i].language );
280 }
281 array_free( opts );
282
283 qsort( &ls[1], *n - 1, sizeof( char * ), strsort_reverse );
284 return ls;
285}
286
290static void opt_gameplay( unsigned int wid )
291{
292 (void)wid;
293 char buf[STRMAX];
294 int cw;
295 int w, h, y, x, by, l, n, i, p;
296 const char *s;
297 char **ls, **diff_text, **diff_alt;
298 const Difficulty *difficulty, *cur_difficulty;
299
300 /* Get size. */
301 window_dimWindow( wid, &w, &h );
302
303 /* Close button */
304 window_addButton( wid, -20 - 1 * ( BUTTON_WIDTH + 20 ), 20, BUTTON_WIDTH,
305 BUTTON_HEIGHT, "btnCancel", _( "Cancel" ), opt_close );
306 window_addButton( wid, -20 - 2 * ( BUTTON_WIDTH + 20 ), 20, BUTTON_WIDTH,
307 BUTTON_HEIGHT, "btnDefaults", _( "Defaults" ),
309
310 /* Information. */
311 cw = ( w - 40 );
312 x = 20;
313 y = -35;
314 window_addText( wid, x, y, cw, 20, 1, "txtVersion", NULL, NULL,
315 naev_version( 1 ) );
316 y -= 20;
317
318 snprintf( buf, sizeof( buf ), "#n%s#0%s (%s)", _( "Platform Info: " ),
319 SDL_GetPlatform(), HOST );
320 window_addText( wid, x, y, cw, 20, 1, "txtPlatInfo", NULL, NULL, buf );
321 y -= 20;
322
323 snprintf( buf, sizeof( buf ), "#n%s#0%s" CONF_FILE, _( "Config Path: " ),
325 window_addText( wid, x, y, cw, 20, 1, "txtConfPath", NULL, NULL, buf );
326 y -= 40;
327 by = y;
328
329 /* Language support. */
330 cw = ( w - 60 ) / 2 - 40;
331 y = by;
332 x = 20;
333 s = _( "Language:" );
334 l = gl_printWidthRaw( NULL, s );
335 window_addText( wid, x, y, l, 20, 0, "txtLanguage", NULL, NULL, s );
336 ls = lang_list( &n );
337 i = 0;
338 if ( conf.language != NULL ) {
339 for ( i = 1; i < n; i++ )
340 if ( strcmp( conf.language, &ls[i][LANG_CODE_START] ) == 0 )
341 break;
342 if ( i >= n )
343 i = 0;
344 }
345 window_addList( wid, x + l + 20, y, cw - l - 50, 100, "lstLanguage", ls, n,
346 i, NULL, NULL );
347 y -= 110;
348
349 /* Game difficulty. */
350 difficulty = difficulty_getAll();
351 n = array_size( difficulty );
352 diff_text = malloc( sizeof( char *) * n );
353 diff_alt = malloc( sizeof( char *) * n );
354 p = 0;
355 if ( player.p == NULL )
356 difficulty_setLocal( NULL );
357 cur_difficulty = difficulty_cur();
358 for ( i = 0; i < n; i++ ) {
359 const Difficulty *d = &difficulty[i];
360 diff_text[i] = strdup( _( d->name ) );
361 diff_alt[i] = difficulty_display( d );
362 if ( strcmp( d->name, cur_difficulty->name ) == 0 )
363 p = i;
364 }
365 if ( player.p != NULL )
366 s = _( "Difficulty (this save):" );
367 else
368 s = _( "Difficulty (global):" );
369 window_addText( wid, x, y, cw, 20, 0, "txtDifficulty", NULL, NULL, s );
370 y -= 20;
371 window_addList( wid, x, y, cw, 100, "lstDifficulty", diff_text, n, p, NULL,
372 NULL );
373 toolkit_setListAltText( wid, "lstDifficulty", diff_alt );
374 y -= 110;
375
376 /* Compilation flags. */
377 window_addText( wid, x, y, cw, 20, 0, "txtCompile", NULL, cHeader,
378 _( "Compilation Flags:" ) );
379 y -= 20;
380 window_addText( wid, x, y, cw, h + y - 20, 0, "txtFlags", NULL, &cFontOrange,
381 ""
382#if DEBUGGING
383#if DEBUG_PARANOID
384 "Debug Paranoid\n"
385#else /* DEBUG_PARANOID */
386 "Debug\n"
387#endif /* DEBUG_PARANOID */
388#endif /* DEBUGGING */
389#if HAVE_LUAJIT
390 "Using LuaJIT\n"
391#endif /* HAVE_LUAJIT */
392 );
393
394 /*y -= window_getTextHeight(wid, "txtFlags") + 10; */
395
396 /* Options. */
397 x = 20 + cw + 20;
398 y = by;
399 cw += 80;
400
401 window_addText( wid, x, y, cw, 20, 0, "txtSettings", NULL, cHeader,
402 _( "Settings:" ) );
403 y -= 25;
404
405 window_addCheckbox( wid, x, y, cw, 20, "chkZoomManual",
406 _( "Enable manual zoom control" ), NULL,
407 conf.zoom_manual );
408 y -= 25;
409 window_addCheckbox( wid, x, y, cw, 20, "chkDoubletap",
410 _( "Enable double-tap afterburn/cooldown" ), NULL,
411 conf.doubletap_sens );
412 y -= 25;
413 window_addCheckbox( wid, x, y, cw, 20, "chkMouseFly",
414 _( "Enable mouse-flying (toggle with middle click)" ),
415 NULL, conf.mouse_fly );
416 y -= 25;
417 window_addCheckbox( wid, x, y, cw, 20, "chkMouseAccel",
418 _( "Enable mouse-flying accel control" ), NULL,
419 conf.mouse_accel );
420 y -= 40;
421 s = _( "Visible Messages" );
422 l = gl_printWidthRaw( NULL, s );
423 window_addText( wid, x, y, l, 20, 1, "txtSMSG", NULL, NULL, s );
424 window_addInput( wid, -50, y, 40, 20, "inpMSG", 4, 1, NULL );
425 // y -= 30;
426
427 /* Update. */
428 opt_gameplayUpdate( wid, NULL );
429}
430
434static int opt_gameplaySave( unsigned int wid, const char *str )
435{
436 (void)str;
437 int f, p, newlang;
438 const char *vmsg, *s;
439 const Difficulty *difficulty;
440
441 /* List. */
442 p = toolkit_getListPos( wid, "lstLanguage" );
443 s = ( p == 0 ) ? NULL : toolkit_getList( wid, "lstLanguage" );
444 newlang = ( ( s != NULL ) != ( conf.language != NULL ) ) ||
445 ( ( s != NULL ) &&
446 ( strcmp( &s[LANG_CODE_START], conf.language ) != 0 ) );
447 if ( newlang ) {
448 free( conf.language );
449 conf.language = ( s == NULL ) ? NULL : strdup( &s[LANG_CODE_START] );
450 LOG( "conf.language set to %s", conf.language );
451 /* Apply setting going forward; advise restart to regen other text. */
452 gettext_setLanguage( conf.language );
454
455 /* Probably have to reload some fonts or it'll hate us. */
456 gl_freeFont( NULL );
459 gl_fontInit( &gl_defFont, _( FONT_DEFAULT_PATH ), conf.font_size_def,
460 FONT_PATH_PREFIX, 0 ); /* initializes default font to size */
461 gl_fontInit( &gl_smallFont, _( FONT_DEFAULT_PATH ), conf.font_size_small,
462 FONT_PATH_PREFIX, 0 ); /* small font */
463 gl_fontInit( &gl_defFontMono, _( FONT_MONOSPACE_PATH ),
464 conf.font_size_def, FONT_PATH_PREFIX, 0 );
465 }
466
467 /* Save the difficulty mode. */
468 difficulty = difficulty_getAll();
469 p = toolkit_getListPos( wid, "lstDifficulty" );
470 difficulty = &difficulty[p];
471 if ( player.p == NULL ) { /* Setting global difficulty. */
472 free( conf.difficulty );
473 if ( difficulty->def ) {
474 conf.difficulty = NULL; /* Don't save default. */
475 difficulty_setGlobal( NULL );
476 } else {
477 conf.difficulty = strdup( difficulty->name );
478 difficulty_setGlobal( difficulty );
479 }
480 } else { /* Local difficulty. */
481 free( player.difficulty );
482 if ( difficulty == difficulty_get( NULL ) ) {
483 player.difficulty = NULL;
484 difficulty_setLocal( NULL );
485 } else {
486 player.difficulty = strdup( difficulty->name );
487 difficulty_setLocal( difficulty );
488 }
489 }
490 /* Apply difficulty to player ship. */
491 if ( player.p != NULL )
492 pilot_calcStats( player.p ); /* TODO apply to all player's ships. */
493
494 /* Checkboxes. */
495 f = window_checkboxState( wid, "chkDoubletap" );
496 if ( ( conf.doubletap_sens != 0 ) != f )
497 conf.doubletap_sens = ( f != 0 ) * 250;
498
499 conf.zoom_manual = window_checkboxState( wid, "chkZoomManual" );
500 conf.mouse_accel = window_checkboxState( wid, "chkMouseAccel" );
501 conf.mouse_fly = window_checkboxState( wid, "chkMouseFly" );
502
503 /* Get rid of mouse if disabled. */
504 if ( !conf.mouse_fly )
505 player_rmFlag( PLAYER_MFLY );
506
507 /* Input boxes. */
508 vmsg = window_getInput( wid, "inpMSG" );
509 conf.mesg_visible = atoi( vmsg );
510 if ( conf.mesg_visible == 0 )
511 conf.mesg_visible = INPUT_MESSAGES_DEFAULT;
512
513 return 0;
514}
515
519static void opt_gameplayDefaults( unsigned int wid, const char *str )
520{
521 (void)str;
522 char vmsg[16];
523
524 /* Restore. */
525 /* Checkboxes. */
526 window_checkboxSet( wid, "chkZoomManual", MANUAL_ZOOM_DEFAULT );
527 window_checkboxSet( wid, "chkDoubletap", DOUBLETAP_SENSITIVITY_DEFAULT );
528 window_checkboxSet( wid, "chkMouseFly", MOUSE_FLY_DEFAULT );
529 window_checkboxSet( wid, "chkMouseAccel", MOUSE_ACCEL_DEFAULT );
530
531 /* Input boxes. */
532 snprintf( vmsg, sizeof( vmsg ), "%d", INPUT_MESSAGES_DEFAULT );
533 window_setInput( wid, "inpMSG", vmsg );
534}
535
539static void opt_gameplayUpdate( unsigned int wid, const char *str )
540{
541 (void)str;
542 char vmsg[16];
543
544 /* Checkboxes. */
545 window_checkboxSet( wid, "chkZoomManual", conf.zoom_manual );
546 window_checkboxSet( wid, "chkDoubletap", conf.doubletap_sens );
547 window_checkboxSet( wid, "chkMouseFly", conf.mouse_fly );
548 window_checkboxSet( wid, "chkMouseAccel", conf.mouse_accel );
549
550 /* Input boxes. */
551 snprintf( vmsg, sizeof( vmsg ), "%d", conf.mesg_visible );
552 window_setInput( wid, "inpMSG", vmsg );
553}
554
558static void menuKeybinds_getDim( unsigned int wid, int *w, int *h, int *lw,
559 int *lh, int *bw, int *bh )
560{
561 /* Get window dimensions. */
562 window_dimWindow( wid, w, h );
563
564 /* Get button dimensions. */
565 if ( bw != NULL )
566 *bw = BUTTON_WIDTH;
567 if ( bh != NULL )
568 *bh = BUTTON_HEIGHT;
569
570 /* Get list dimensions. */
571 if ( lw != NULL )
572 *lw = *w - 40 - 2 * ( BUTTON_WIDTH + 20 );
573 if ( lh != NULL )
574 *lh = *h - 90;
575}
576
580static void opt_keybinds( unsigned int wid )
581{
582 int w, h, lw, bw, bh;
583
584 /* Get dimensions. */
585 menuKeybinds_getDim( wid, &w, &h, &lw, NULL, &bw, &bh );
586
587 /* Restore defaults button. */
588 window_addButton( wid, -20 - 1 * ( BUTTON_WIDTH + 20 ), 20, BUTTON_WIDTH,
589 BUTTON_HEIGHT, "btnDefaults", _( "Defaults" ),
591 /* Set button. */
592 window_addButton( wid, -20, 20 + 1 * ( BUTTON_HEIGHT + 20 ), bw, bh,
593 "btnSet", _( "Set Key" ), opt_setKey );
594
595 /* Text stuff. */
596 window_addText( wid, -20, -40, w - ( 20 + lw + 20 + 20 ), 30, 1, "txtName",
597 NULL, cHeader, NULL );
598 window_addText( wid, -20, -90, w - ( 20 + lw + 20 + 20 ), h - 170 - 3 * bh,
599 0, "txtDesc", NULL, NULL, NULL );
600
601 /* Generate the list. */
603}
604
610static void menuKeybinds_genList( unsigned int wid )
611{
612 int p;
613 char **str, mod_text[64];
614 KeybindType type;
615 SDL_Keymod mod;
616 int w, h;
617 int lw, lh;
618 int regen, pos, off;
619
620 /* Get dimensions. */
621 menuKeybinds_getDim( wid, &w, &h, &lw, &lh, NULL, NULL );
622
623 /* Create the list. */
624 str = malloc( sizeof( char * ) * KST_END );
625 for ( int j = 0; j < KST_END; j++ ) {
626 SDL_Keycode key;
627 const char *short_desc = input_getKeybindName( j );
628 int l = 128; /* GCC deduces 68 because we have a format string "%s <%s%c>"
629 * where "char mod_text[64]" is one of the "%s" args.
630 * (that plus brackets plus %c + null gets to 68.
631 * Just set to 128 as it's a power of two. */
632 str[j] = malloc( l );
633 key = input_getKeybind( j, &type, &mod );
634 switch ( type ) {
635 case KEYBIND_KEYBOARD:
636 /* Generate mod text. */
637 if ( mod == NMOD_ANY )
638 snprintf( mod_text, sizeof( mod_text ), _( "any+" ) );
639 else {
640 p = 0;
641 mod_text[0] = '\0';
642 if ( mod & NMOD_SHIFT )
643 p += scnprintf( &mod_text[p], sizeof( mod_text ) - p,
644 _( "shift+" ) );
645 if ( mod & NMOD_CTRL )
646 p += scnprintf( &mod_text[p], sizeof( mod_text ) - p,
647 _( "ctrl+" ) );
648 if ( mod & NMOD_ALT )
649 p += scnprintf( &mod_text[p], sizeof( mod_text ) - p,
650 _( "alt+" ) );
651 if ( mod & NMOD_META )
652 p += scnprintf( &mod_text[p], sizeof( mod_text ) - p,
653 _( "meta+" ) );
654 (void)p;
655 }
656
657 /* Print key. Special-case ASCII letters (use uppercase, unlike
658 * SDL_GetKeyName.). */
659 if ( key < 0x100 && isalpha( key ) )
660 snprintf( str[j], l, "%s <%s%c>", short_desc, mod_text,
661 toupper( key ) );
662 else
663 snprintf( str[j], l, "%s <%s%s>", short_desc, mod_text,
664 pgettext_var( "keyname", SDL_GetKeyName( key ) ) );
665 break;
666 case KEYBIND_JAXISPOS:
667 snprintf( str[j], l, "%s <ja+%d>", short_desc, key );
668 break;
669 case KEYBIND_JAXISNEG:
670 snprintf( str[j], l, "%s <ja-%d>", short_desc, key );
671 break;
672 case KEYBIND_JBUTTON:
673 snprintf( str[j], l, "%s <jb%d>", short_desc, key );
674 break;
675 case KEYBIND_JHAT_UP:
676 snprintf( str[j], l, "%s <jh%d-up>", short_desc, key );
677 break;
678 case KEYBIND_JHAT_DOWN:
679 snprintf( str[j], l, "%s <jh%d-down>", short_desc, key );
680 break;
681 case KEYBIND_JHAT_LEFT:
682 snprintf( str[j], l, "%s <jh%d-left>", short_desc, key );
683 break;
684 case KEYBIND_JHAT_RIGHT:
685 snprintf( str[j], l, "%s <jh%d-right>", short_desc, key );
686 break;
687 default:
688 snprintf( str[j], l, "%s", short_desc );
689 break;
690 }
691 }
692
693 regen = widget_exists( wid, "lstKeybinds" );
694 if ( regen ) {
695 pos = toolkit_getListPos( wid, "lstKeybinds" );
696 off = toolkit_getListOffset( wid, "lstKeybinds" );
697 window_destroyWidget( wid, "lstKeybinds" );
698 }
699
700 window_addList( wid, 20, -40, lw, lh, "lstKeybinds", str, KST_END, 0,
702
703 if ( regen ) {
704 toolkit_setListPos( wid, "lstKeybinds", pos );
705 toolkit_setListOffset( wid, "lstKeybinds", off );
706 }
707}
708
715static void menuKeybinds_update( unsigned int wid, const char *name )
716{
717 (void)name;
718 int selected;
719 KeySemanticType keybind;
720 const char *desc;
721 SDL_Keycode key;
722 KeybindType type;
723 SDL_Keymod mod;
724 char buf[STRMAX_SHORT];
725 char binding[64];
726
727 /* Get the keybind. */
728 selected = toolkit_getListPos( wid, "lstKeybinds" );
729
730 /* Remove the excess. */
731 keybind = selected;
732 opt_selectedKeybind = keybind;
733 window_modifyText( wid, "txtName", input_getKeybindName( keybind ) );
734
735 /* Get information. */
736 desc = input_getKeybindDescription( keybind );
737 key = input_getKeybind( keybind, &type, &mod );
738
739 /* Create the text. */
740 switch ( type ) {
741 case KEYBIND_NULL:
742 snprintf( binding, sizeof( binding ), _( "Not bound" ) );
743 break;
744 case KEYBIND_KEYBOARD:
745 /* Print key. Special-case ASCII letters (use uppercase, unlike
746 * SDL_GetKeyName.). */
747 if ( key < 0x100 && isalpha( key ) )
748 snprintf( binding, sizeof( binding ), _( "keyboard: %s%s%c" ),
749 ( mod != KMOD_NONE ) ? input_modToText( mod ) : "",
750 ( mod != KMOD_NONE ) ? " + " : "", toupper( key ) );
751 else
752 snprintf( binding, sizeof( binding ), _( "keyboard: %s%s%s" ),
753 ( mod != KMOD_NONE ) ? input_modToText( mod ) : "",
754 ( mod != KMOD_NONE ) ? " + " : "",
755 pgettext_var( "keyname", SDL_GetKeyName( key ) ) );
756 break;
757 case KEYBIND_JAXISPOS:
758 snprintf( binding, sizeof( binding ), _( "joy axis pos: <%d>" ), key );
759 break;
760 case KEYBIND_JAXISNEG:
761 snprintf( binding, sizeof( binding ), _( "joy axis neg: <%d>" ), key );
762 break;
763 case KEYBIND_JBUTTON:
764 snprintf( binding, sizeof( binding ), _( "joy button: <%d>" ), key );
765 break;
766 case KEYBIND_JHAT_UP:
767 snprintf( binding, sizeof( binding ), _( "joy hat up: <%d>" ), key );
768 break;
769 case KEYBIND_JHAT_DOWN:
770 snprintf( binding, sizeof( binding ), _( "joy hat down: <%d>" ), key );
771 break;
772 case KEYBIND_JHAT_LEFT:
773 snprintf( binding, sizeof( binding ), _( "joy hat left: <%d>" ), key );
774 break;
775 case KEYBIND_JHAT_RIGHT:
776 snprintf( binding, sizeof( binding ), _( "joy hat right:<%d>" ), key );
777 break;
778 }
779
780 /* Update text. */
781 snprintf( buf, sizeof( buf ), "%s\n\n%s\n", desc, binding );
782 window_modifyText( wid, "txtDesc", buf );
783}
784
788static void opt_keyDefaults( unsigned int wid, const char *str )
789{
790 (void)str;
791 const char *title, *caption;
792 char *ret;
793 int ind;
794
795 const int n = 3;
796 const char *opts[] = { _( "WASD" ), _( "Arrow Keys" ), _( "Cancel" ) };
797
798 title = _( "Restore Defaults" );
799 caption = _( "Which layout do you want to use?" );
800
801 dialogue_makeChoice( title, caption, n );
802
803 for ( int i = 0; i < n; i++ )
804 dialogue_addChoice( title, caption, opts[i] );
805
806 ret = dialogue_runChoice();
807 if ( ret == NULL )
808 return;
809
810 /* Find the index of the matched option. */
811 ind = 0;
812 for ( int i = 0; i < n; i++ )
813 if ( strcmp( ret, opts[i] ) == 0 ) {
814 ind = i;
815 break;
816 }
817 free( ret );
818
819 if ( ind == 2 )
820 return;
821
822 /* Restore defaults. */
823 input_setDefault( ( ind == 0 ) ? 1 : 0 );
824
825 /* Regenerate list widget. */
827
828 /* Alert user it worked. */
829 dialogue_msgRaw( _( "Defaults Restored" ),
830 _( "Keybindings restored to defaults." ) );
831}
832
833static void opt_setEngineLevel( unsigned int wid, const char *str )
834{
835 char buf[32];
836 double vol = window_getFaderValue( wid, str );
837 const char *label = _( "Engine Volume" );
838 double logvol = 1. / pow( 2., ( 1. - vol ) * 8. );
839 conf.engine_vol = vol;
840 if ( sound_disabled )
841 snprintf( buf, sizeof( buf ), _( "%s: %s" ), label, _( "Muted" ) );
842 else {
843 const double magic =
844 -48. / log( 0.00390625 ); /* -48 dB minimum divided by logarithm of
845 volume floor. */
846 snprintf( buf, sizeof( buf ), _( "%s: %.2f (%.0f dB)" ), label, vol,
847 log( logvol ) * magic );
848 }
849 window_modifyText( wid, "txtEngine", buf );
850}
851
858static void opt_setAudioLevel( unsigned int wid, const char *str )
859{
860 char buf[32], *widget;
861 double vol = window_getFaderValue( wid, str );
862 if ( strcmp( str, "fadSound" ) == 0 ) {
863 sound_volume( vol );
864 widget = "txtSound";
865 opt_audioLevelStr( buf, sizeof( buf ), 0, vol );
866 } else {
867 music_volume( vol );
868 widget = "txtMusic";
869 opt_audioLevelStr( buf, sizeof( buf ), 1, vol );
870 }
871
872 window_modifyText( wid, widget, buf );
873}
874
883static void opt_audioLevelStr( char *buf, int max, int type, double pos )
884{
885 const char *str = type ? _( "Music Volume" ) : _( "Sound Volume" );
886 double vol = type ? music_getVolumeLog() : sound_getVolumeLog();
887
888 if ( vol == 0. )
889 snprintf( buf, max, _( "%s: %s" ), str, _( "Muted" ) );
890 else {
891 const double magic =
892 -48. / log( 0.00390625 ); /* -48 dB minimum divided by logarithm of
893 volume floor. */
894 snprintf( buf, max, _( "%s: %.2f (%.0f dB)" ), str, pos,
895 log( vol ) * magic );
896 }
897}
898
902static void opt_audio( unsigned int wid )
903{
904 (void)wid;
905 int cw, w, h, y, x;
906
907 /* Get size. */
908 window_dimWindow( wid, &w, &h );
909
910 /* Close button */
911 window_addButton( wid, -20 - 1 * ( BUTTON_WIDTH + 20 ), 20, BUTTON_WIDTH,
912 BUTTON_HEIGHT, "btnCancel", _( "Cancel" ), opt_close );
913 window_addButton( wid, -20 - 2 * ( BUTTON_WIDTH + 20 ), 20, BUTTON_WIDTH,
914 BUTTON_HEIGHT, "btnDefaults", _( "Defaults" ),
916
917 cw = ( w - 60 ) / 2;
918 x = 20;
919 y = -60;
920 window_addCheckbox( wid, x, y, cw, 20, "chkNosound",
921 _( "Disable all sound/music" ), NULL, conf.nosound );
922 y -= 30;
923
924 window_addCheckbox( wid, x, y, cw, 20, "chkEFX", _( "EFX (More CPU)" ), NULL,
925 conf.al_efx );
926
927 /* Sound levels. */
928 x = 20 + cw + 20;
929 y = -60;
930 window_addText( wid, x, y, cw - 40, 20, 0, "txtSVolume", NULL, cHeader,
931 _( "Volume Levels:" ) );
932 y -= 30;
933
934 /* Sound fader. */
935 window_addText( wid, x, y, cw, 20, 1, "txtSound", NULL, NULL, NULL );
936 y -= 20;
937 window_addFader( wid, x, y, cw, 20, "fadSound", 0., 1., sound_getVolume(),
939 window_faderScrollDone( wid, "fadSound", opt_beep );
940 y -= 30;
941
942 /* Music fader. */
943 window_addText( wid, x, y, cw, 20, 1, "txtMusic", NULL, NULL, NULL );
944 y -= 20;
945 window_addFader( wid, x, y, cw, 20, "fadMusic", 0., 1., music_getVolume(),
947 y -= 30;
948
949 /* Engine fader. */
950 window_addText( wid, x, y, cw, 20, 1, "txtEngine", NULL, NULL, NULL );
951 y -= 20;
952 window_addFader( wid, x, y, cw, 20, "fadEngine", 0., 1., conf.engine_vol,
953 opt_setEngineLevel );
954 opt_setEngineLevel( wid, "fadEngine" );
955
956 opt_audioUpdate( wid );
957}
958
959static void opt_beep( unsigned int wid, const char *str )
960{
961 (void)wid;
962 (void)str;
964}
965
969static int opt_audioSave( unsigned int wid, const char *str )
970{
971 (void)str;
972 int f;
973
974 f = window_checkboxState( wid, "chkNosound" );
975 if ( conf.nosound != f ) {
976 conf.nosound = f;
978 }
979
980 f = window_checkboxState( wid, "chkEFX" );
981 if ( conf.al_efx != f ) {
982 conf.al_efx = f;
984 }
985
986 /* Faders. */
987 conf.sound = window_getFaderValue( wid, "fadSound" );
988 conf.music = window_getFaderValue( wid, "fadMusic" );
989 conf.engine_vol = window_getFaderValue( wid, "fadEngine" );
990
991 return 0;
992}
993
997static void opt_audioDefaults( unsigned int wid, const char *str )
998{
999 (void)str;
1000
1001 /* Set defaults. */
1002 /* Faders. */
1003 window_faderValue( wid, "fadSound", SOUND_VOLUME_DEFAULT );
1004 window_faderValue( wid, "fadMusic", MUSIC_VOLUME_DEFAULT );
1005 window_faderValue( wid, "fadEngine", ENGINE_VOLUME_DEFAULT );
1006
1007 /* Checkboxes. */
1008 window_checkboxSet( wid, "chkNosound", MUTE_SOUND_DEFAULT );
1009 window_checkboxSet( wid, "chkEFX", USE_EFX_DEFAULT );
1010}
1011
1015static void opt_audioUpdate( unsigned int wid )
1016{
1017 /* Checkboxes. */
1018 window_checkboxSet( wid, "chkNosound", conf.nosound );
1019 window_checkboxSet( wid, "chkEFX", conf.al_efx );
1020
1021 /* Faders. */
1022 window_faderValue( wid, "fadSound", conf.sound );
1023 window_faderValue( wid, "fadMusic", conf.music );
1024 window_faderValue( wid, "fadEngine", conf.engine_vol );
1025}
1026
1030static int opt_setKeyEvent( unsigned int wid, SDL_Event *event )
1031{
1032 unsigned int parent;
1033 KeybindType type;
1034 int key, test_key_event;
1035 SDL_Keymod mod;
1036 KeySemanticType boundkey;
1037
1038 /* See how to handle it. */
1039 switch ( event->type ) {
1040 case SDL_KEYDOWN:
1041 key = event->key.keysym.sym;
1042 /* If control key make player hit twice. */
1043 test_key_event = ( key == SDLK_NUMLOCKCLEAR ) ||
1044 ( key == SDLK_CAPSLOCK ) || ( key == SDLK_SCROLLLOCK ) ||
1045 ( key == SDLK_RSHIFT ) || ( key == SDLK_LSHIFT ) ||
1046 ( key == SDLK_RCTRL ) || ( key == SDLK_LCTRL ) ||
1047 ( key == SDLK_RALT ) || ( key == SDLK_LALT ) ||
1048 ( key == SDLK_RGUI ) || ( key == SDLK_LGUI );
1049 if ( test_key_event && ( opt_lastKeyPress != key ) ) {
1050 opt_lastKeyPress = key;
1051 return 0;
1052 }
1053 type = KEYBIND_KEYBOARD;
1054 if ( window_checkboxState( wid, "chkAny" ) )
1055 mod = NMOD_ANY;
1056 else {
1057 SDL_Keymod ev_mod = event->key.keysym.mod;
1058 mod = 0;
1059 if ( ev_mod & ( KMOD_LSHIFT | KMOD_RSHIFT ) )
1060 mod |= NMOD_SHIFT;
1061 if ( ev_mod & ( KMOD_LCTRL | KMOD_RCTRL ) )
1062 mod |= NMOD_CTRL;
1063 if ( ev_mod & ( KMOD_LALT | KMOD_RALT ) )
1064 mod |= NMOD_ALT;
1065 if ( ev_mod & ( KMOD_LGUI | KMOD_RGUI ) )
1066 mod |= NMOD_META;
1067 }
1068 /* Set key. */
1069 opt_lastKeyPress = key;
1070 break;
1071
1072 case SDL_JOYAXISMOTION:
1073 if ( event->jaxis.value > 0 )
1074 type = KEYBIND_JAXISPOS;
1075 else if ( event->jaxis.value < 0 )
1076 type = KEYBIND_JAXISNEG;
1077 else
1078 return 0; /* Not handled. */
1079 key = event->jaxis.axis;
1080 mod = NMOD_ANY;
1081 break;
1082
1083 case SDL_JOYBUTTONDOWN:
1084 type = KEYBIND_JBUTTON;
1085 key = event->jbutton.button;
1086 mod = NMOD_ANY;
1087 break;
1088
1089 case SDL_JOYHATMOTION:
1090 switch ( event->jhat.value ) {
1091 case SDL_HAT_UP:
1092 type = KEYBIND_JHAT_UP;
1093 break;
1094 case SDL_HAT_DOWN:
1095 type = KEYBIND_JHAT_DOWN;
1096 break;
1097 case SDL_HAT_LEFT:
1098 type = KEYBIND_JHAT_LEFT;
1099 break;
1100 case SDL_HAT_RIGHT:
1101 type = KEYBIND_JHAT_RIGHT;
1102 break;
1103 default:
1104 return 0; /* Not handled. */
1105 }
1106 key = event->jhat.hat;
1107 mod = NMOD_ANY;
1108 break;
1109
1110 /* Not handled. */
1111 default:
1112 return 0;
1113 }
1114
1115 /* Warn if already bound. */
1116 boundkey = input_keyAlreadyBound( type, key, mod );
1117 if ( ( boundkey >= 0 ) && ( boundkey < KST_END ) &&
1118 ( boundkey != opt_selectedKeybind ) )
1120 _( "Key '#b%s#0' overlaps with key '#b%s#0' that was just set. "
1121 "You may want to correct this." ),
1122 input_getKeybindName( boundkey ),
1124
1125 /* Set keybinding. */
1126 input_setKeybind( opt_selectedKeybind, type, key, mod );
1127
1128 /* Close window. */
1129 window_close( wid, NULL );
1130
1131 /* Update parent window. */
1132 parent = window_getParent( wid );
1133 menuKeybinds_genList( parent );
1134
1135 return 0;
1136}
1137
1141static void opt_setKey( unsigned int wid, const char *str )
1142{
1143 (void)wid;
1144 (void)str;
1145 unsigned int new_wid;
1146 int w, h;
1147
1148 /* Reset key. */
1149 opt_lastKeyPress = 0;
1150
1151 /* Create new window. */
1152 w = 20 + 2 * ( BUTTON_WIDTH + 20 );
1153 h = 20 + BUTTON_HEIGHT + 20 + 20 + 80 + 40;
1154 new_wid = window_create( "wdwSetKey", _( "Set Keybinding" ), -1, -1, w, h );
1156 window_setParent( new_wid, wid );
1157
1158 /* Set text. */
1159 window_addText(
1160 new_wid, 20, -40, w - 40, 60, 0, "txtInfo", NULL, NULL,
1161 _( "To use a modifier key hit that key twice in a row, otherwise it "
1162 "will register as a modifier. To set with any modifier click the "
1163 "checkbox." ) );
1164
1165 /* Create button to cancel. */
1166 window_addButton( new_wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnCancel",
1167 _( "Cancel" ), window_close );
1168
1169 /* Button to unset. */
1170 window_addButton( new_wid, 20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnUnset",
1171 _( "Unset" ), opt_unsetKey );
1172
1173 /* Checkbox to set any modifier. */
1174 window_addCheckbox( new_wid, -20, 20 + BUTTON_HEIGHT + 20, w - 40, 20,
1175 "chkAny", _( "Set any modifier" ), NULL, 0 );
1176}
1177
1181static void opt_unsetKey( unsigned int wid, const char *str )
1182{
1183 (void)str;
1184 unsigned int parent;
1185
1186 /* Unsets the keybind. */
1187 input_setKeybind( opt_selectedKeybind, KEYBIND_NULL, 0, 0 );
1188
1189 /* Close window. */
1190 window_close( wid, NULL );
1191
1192 /* Update parent window. */
1193 parent = window_getParent( wid );
1194 menuKeybinds_genList( parent );
1195}
1196
1200static void opt_accessibility( unsigned int wid )
1201{
1202 int cw, w, h, y, x;
1203 const char *colourblind_types[] = {
1204 _( "Protanopia" ), _( "Deuteranopia" ), _( "Tritanopia" ),
1205 _( "Rod Monochromacy" ), _( "Cone Monochromacy" ),
1206 };
1207 int ntypes = sizeof( colourblind_types ) / sizeof( colourblind_types[0] );
1208 char **types = malloc( ntypes * sizeof( char *) );
1209 for ( int i = 0; i < ntypes; i++ )
1210 types[i] = strdup( colourblind_types[i] );
1211
1212 /* Get size. */
1213 window_dimWindow( wid, &w, &h );
1214
1215 /* Close button */
1216 window_addButton( wid, -20 - 1 * ( BUTTON_WIDTH + 20 ), 20, BUTTON_WIDTH,
1217 BUTTON_HEIGHT, "btnCancel", _( "Cancel" ), opt_close );
1218 window_addButton( wid, -20 - 2 * ( BUTTON_WIDTH + 20 ), 20, BUTTON_WIDTH,
1219 BUTTON_HEIGHT, "btnDefaults", _( "Defaults" ),
1221
1222 /* Resolution bits. */
1223 cw = ( w - 60 ) / 2;
1224 x = 20;
1225 y = -40;
1226
1227 /* Video. */
1228 window_addText( wid, x, y, 100, 20, 0, "txtSVideo", NULL, cHeader,
1229 _( "Video:" ) );
1230 y -= 20;
1231 window_addText( wid, x, y - 3, cw - 20, 20, 0, "txtSaturation", NULL, NULL,
1232 NULL );
1233 y -= 20;
1234 window_addFader( wid, x + 20, y, cw - 60, 20, "fadSaturation", 0., 1.,
1235 conf.nebu_saturation, opt_setSaturation );
1236 opt_setSaturation( wid, "fadSaturation" );
1237 y -= 30;
1238 window_addText( wid, x, y - 3, cw - 20, 20, 0, "txtNebuNonuniformity", NULL,
1239 NULL, NULL );
1240 y -= 20;
1241 window_addFader( wid, x + 20, y, cw - 60, 20, "fadNebuNonuniformity", 0., 1.,
1242 conf.nebu_nonuniformity, opt_setNebuNonuniformity );
1243 opt_setNebuNonuniformity( wid, "fadNebuNonuniformity" );
1244 y -= 30;
1245 window_addText( wid, x, y - 3, cw - 20, 20, 0, "txtBGBrightness", NULL, NULL,
1246 NULL );
1247 y -= 20;
1248 window_addFader( wid, x + 20, y, cw - 60, 20, "fadBGBrightness", 0., 1.,
1249 conf.bg_brightness, opt_setBGBrightness );
1250 opt_setBGBrightness( wid, "fadBGBrightness" );
1251 y -= 30;
1252 window_addText( wid, x, y - 3, cw - 20, 20, 0, "txtJumpBrightness", NULL,
1253 NULL, NULL );
1254 y -= 20;
1255 window_addFader( wid, x + 20, y, cw - 60, 20, "fadJumpBrightness", 0., 1.,
1256 conf.jump_brightness, opt_setJumpBrightness );
1257 opt_setJumpBrightness( wid, "fadJumpBrightness" );
1258 y -= 30;
1259
1260 /* Second column. */
1261 x = 20 + cw + 20;
1262 y = -40;
1263
1264 window_addText( wid, x, y - 3, cw - 20, 20, 0, "txtColourblind", NULL, NULL,
1265 _( "Colourblind type:" ) );
1266 y -= 25;
1267 window_addList( wid, x, y, cw, 100, "lstColourblind", (char **)types, ntypes,
1268 conf.colourblind_type, opt_listColourblind, NULL );
1269 y -= 115;
1270 window_addText( wid, x, y - 3, cw - 20, 20, 0, "txtColourblindCorrect", NULL,
1271 NULL, NULL );
1272 y -= 20;
1273 window_addFader( wid, x + 20, y, cw - 60, 20, "fadColourblindCorrect", 0.,
1274 1., conf.colourblind_correct, opt_setColourblindCorrect );
1275 opt_setColourblindCorrect( wid, "fadColourblindCorrect" );
1276 y -= 30;
1277 window_addText( wid, x, y - 3, cw - 20, 20, 0, "txtColourblindSimulate",
1278 NULL, NULL, NULL );
1279 y -= 20;
1280 window_addFader( wid, x + 20, y, cw - 60, 20, "fadColourblindSimulate", 0.,
1281 1., conf.colourblind_sim, opt_setColourblindSimulate );
1282 opt_setColourblindSimulate( wid, "fadColourblindSimulate" );
1283 y -= 50;
1284
1285 window_addText( wid, x, y, cw - 20, 20, 0, "txtSGameplay", NULL, cHeader,
1286 _( "Gamplay:" ) );
1287 y -= 20;
1288 window_addCheckbox( wid, x, y, cw - 20, 20, "chkPuzzleSkip",
1289 _( "Allow skipping puzzles" ), NULL, conf.puzzle_skip );
1290 y -= 30;
1291 window_addText( wid, x, y - 3, cw - 20, 20, 0, "txtGameSpeed", NULL, NULL,
1292 NULL );
1293 y -= 20;
1294 window_addFader( wid, x + 20, y, cw - 60, 20, "fadGameSpeed", 0.1, 1.,
1295 conf.game_speed, opt_setGameSpeed );
1296 opt_setGameSpeed( wid, "fadGameSpeed" );
1297}
1298
1299static int opt_accessibilitySave( unsigned int wid, const char *str )
1300{
1301 (void)wid;
1302 (void)str;
1303
1304 /* Checkboxes need saving. */
1305 conf.puzzle_skip = window_checkboxState( wid, "chkPuzzleSkip" );
1306
1307 /* Colourblind and faders are handled in their respective functions. */
1308 return 0;
1309}
1310
1314static void opt_accessibilityDefaults( unsigned int wid, const char *str )
1315{
1316 (void)str;
1317
1318 /* Faders. */
1319 window_faderSetBoundedValue( wid, "fadNebuNonuniformity",
1320 NEBU_NONUNIFORMITY_DEFAULT );
1321 window_faderSetBoundedValue( wid, "fadBGBrightness", BG_BRIGHTNESS_DEFAULT );
1322 window_faderSetBoundedValue( wid, "fadJumpBrightness",
1323 JUMP_BRIGHTNESS_DEFAULT );
1324 window_faderSetBoundedValue( wid, "fadColourblindCorrect",
1325 COLOURBLIND_CORRECT_DEFAULT );
1326 window_faderSetBoundedValue( wid, "fadColourblindSimulate",
1327 COLOURBLIND_CORRECT_DEFAULT );
1328
1329 /* Checkboxes. */
1330 window_checkboxSet( wid, "chkPuzzleSkip", PUZZLE_SKIP_DEFAULT );
1331
1332 /* Reset colorblind if needed. */
1334}
1335
1339static void opt_video( unsigned int wid )
1340{
1341 int i, j, nres, res_def;
1342 char buf[16];
1343 int cw, w, h, y, x, l;
1344 char **res;
1345 const char *s;
1346
1347 /* Get size. */
1348 window_dimWindow( wid, &w, &h );
1349
1350 /* Close button */
1351 window_addButton( wid, -20 - 1 * ( BUTTON_WIDTH + 20 ), 20, BUTTON_WIDTH,
1352 BUTTON_HEIGHT, "btnCancel", _( "Cancel" ), opt_close );
1353 window_addButton( wid, -20 - 2 * ( BUTTON_WIDTH + 20 ), 20, BUTTON_WIDTH,
1354 BUTTON_HEIGHT, "btnDefaults", _( "Defaults" ),
1356
1357 /* Resolution bits. */
1358 cw = ( w - 60 ) / 2;
1359 x = 20;
1360 y = -40;
1361 window_addText( wid, x, y, 100, 20, 0, "txtSRes", NULL, cHeader,
1362 _( "Resolution:" ) );
1363 y -= 30;
1364 window_addInput( wid, x, y, 100, 20, "inpRes", 16, 1, NULL );
1365 window_setInputFilter( wid, "inpRes", INPUT_FILTER_RESOLUTION );
1366 window_addCheckbox( wid, x + 20 + 100, y, 100, 20, "chkFullscreen",
1367 _( "Fullscreen" ), NULL, conf.fullscreen );
1368 y -= 30;
1369 SDL_DisplayMode mode;
1370 int k;
1371 int display_index = SDL_GetWindowDisplayIndex( gl_screen.window );
1372 int n = SDL_GetNumDisplayModes( display_index );
1373 j = 1;
1374 for ( i = 0; i < n; i++ ) {
1375 SDL_GetDisplayMode( display_index, i, &mode );
1376 if ( ( mode.w == conf.width ) && ( mode.h == conf.height ) )
1377 j = 0;
1378 }
1379 res = malloc( sizeof( char *) * ( i + j ) );
1380 nres = 0;
1381 res_def = 0;
1382 if ( j ) {
1383 SDL_asprintf( &res[0], "%dx%d", conf.width, conf.height );
1384 nres = 1;
1385 }
1386 for ( i = 0; i < n; i++ ) {
1387 SDL_GetDisplayMode( display_index, i, &mode );
1388 SDL_asprintf( &res[nres], "%dx%d", mode.w, mode.h );
1389
1390 /* Make sure doesn't already exist. */
1391 for ( k = 0; k < nres; k++ )
1392 if ( strcmp( res[k], res[nres] ) == 0 )
1393 break;
1394 if ( k < nres ) {
1395 free( res[nres] );
1396 continue;
1397 }
1398
1399 /* Add as default if necessary and increment. */
1400 if ( ( mode.w == conf.width ) && ( mode.h == conf.height ) )
1401 res_def = i;
1402 nres++;
1403 }
1404 window_addList( wid, x, y, 140, 100, "lstRes", res, nres, -1, opt_videoRes,
1405 NULL );
1406 y -= 110;
1407 window_addText( wid, x, y - 3, 130, 20, 0, "txtScale", NULL, NULL, NULL );
1408 window_addFader( wid, x + 140, y, cw - 160, 20, "fadScale", log( 1. ),
1409 log( 3. ), log( conf.scalefactor ), opt_setScalefactor );
1410 opt_setScalefactor( wid, "fadScale" );
1411 y -= 30;
1412 window_addText( wid, x, y - 3, 130, 20, 0, "txtZoomFar", NULL, NULL, NULL );
1413 window_addFader( wid, x + 140, y, cw - 160, 20, "fadZoomFar", log1p( 0.1 ),
1414 log1p( 2.0 ), log1p( conf.zoom_far ), opt_setZoomFar );
1415 y -= 30;
1416 window_addText( wid, x, y - 3, 130, 20, 0, "txtZoomNear", NULL, NULL, NULL );
1417 window_addFader( wid, x + 140, y, cw - 160, 20, "fadZoomNear", log1p( 0.1 ),
1418 log1p( 2.0 ), log1p( conf.zoom_near ), opt_setZoomNear );
1419 opt_setZoomFar( wid, "fadZoomFar" );
1420 opt_setZoomNear( wid, "fadZoomNear" );
1421 y -= 30;
1422 window_addText( wid, x, y - 3, 130, 20, 0, "txtGammaCorrection", NULL, NULL,
1423 NULL );
1424 window_addFader( wid, x + 140, y, cw - 160, 20, "fadGammaCorrection",
1425 -log( 3. ), log( 3. ), log( conf.gamma_correction ),
1427 opt_setGammaCorrection( wid, "fadGammaCorrection" );
1428 y -= 40;
1429
1430 /* FPS stuff. */
1431 window_addText( wid, x, y, 100, 20, 0, "txtFPSTitle", NULL, cHeader,
1432 _( "FPS Control:" ) );
1433 y -= 25;
1434 s = _( "FPS Limit" );
1435 l = gl_printWidthRaw( NULL, s );
1436 window_addText( wid, x, y, l, 20, 1, "txtSFPS", NULL, NULL, s );
1437 window_addInput( wid, x + l + 20, y, 40, 20, "inpFPS", 4, 1, NULL );
1438 toolkit_setListPos( wid, "lstRes", res_def );
1439 window_setInputFilter( wid, "inpFPS", INPUT_FILTER_NUMBER );
1440 snprintf( buf, sizeof( buf ), "%d", conf.fps_max );
1441 window_setInput( wid, "inpFPS", buf );
1442 window_addCheckbox( wid, x + l + 20 + 40 + 20, y, cw, 20, "chkFPS",
1443 _( "Show FPS" ), NULL, conf.fps_show );
1444
1445 /* Sets inpRes to current resolution, must be after lstRes is added. */
1446 opt_resize();
1447
1448 /* OpenGL options. */
1449 x = 20 + cw + 20;
1450 y = -40;
1451 window_addText( wid, x, y, 100, 20, 0, "txtSGL", NULL, cHeader,
1452 _( "OpenGL:" ) );
1453 y -= 20;
1454 window_addCheckbox( wid, x, y, cw, 20, "chkLowMemory",
1455 _( "Optimize for low memory systems" ), opt_checkRestart,
1456 conf.low_memory );
1457 y -= 25;
1458 window_addCheckbox( wid, x, y, cw, 20, "chkVSync", _( "Vertical Sync" ),
1459 opt_checkRestart, conf.vsync );
1460 y -= 40;
1461
1462 /* Features. */
1463 window_addText( wid, x, y, 100, 20, 0, "txtSFeatures", NULL, cHeader,
1464 _( "Features:" ) );
1465 y -= 20;
1466 window_addCheckbox( wid, x, y, cw, 20, "chkMinimize",
1467 _( "Minimize on focus loss" ), NULL, conf.minimize );
1468 y -= 25;
1469 window_addCheckbox( wid, x, y, cw, 20, "chkHealth",
1470 _( "Health bars for pilots" ), opt_checkHealth,
1471 conf.healthbars );
1472 y -= 30;
1473 window_addText( wid, x, y - 3, cw - 20, 20, 0, "txtMOpacity", NULL, NULL,
1474 NULL );
1475 y -= 20;
1476 window_addFader( wid, x + 20, y, cw - 60, 20, "fadMapOverlayOpacity", 0., 1.,
1477 conf.map_overlay_opacity, opt_setMapOverlayOpacity );
1478 opt_setMapOverlayOpacity( wid, "fadMapOverlayOpacity" );
1479 y -= 40;
1480
1481 /* GUI */
1482 window_addText( wid, x, y, 100, 20, 0, "txtSGUI", NULL, cHeader,
1483 _( "GUI:" ) );
1484 y -= 20;
1485 window_addCheckbox( wid, x, y, cw, 20, "chkBigIcons", _( "Bigger icons" ),
1486 NULL, conf.big_icons );
1487}
1488
1492static void opt_needRestart( void )
1493{
1494 const char *s = _( "#rRestart Naev for changes to take effect.#0" );
1495 opt_restart = 1;
1496
1497 /* Modify widgets. */
1498 for ( int i = 0; i < OPT_WINDOWS; i++ )
1499 window_modifyText( opt_windows[i], "txtRestart", s );
1500}
1501
1505static void opt_videoRes( unsigned int wid, const char *str )
1506{
1507 const char *buf = toolkit_getList( wid, str );
1508 window_setInput( wid, "inpRes", buf );
1509}
1510
1514static int opt_videoSave( unsigned int wid, const char *str )
1515{
1516 (void)str;
1517 const char *inp;
1518 int ret, w, h, f, fullscreen;
1519
1520 /* Handle resolution. */
1521 inp = window_getInput( wid, "inpRes" );
1522 ret = sscanf( inp, " %d %*[^0-9] %d", &w, &h );
1523 if ( ret != 2 || w <= 0 || h <= 0 ) {
1525 _( "Height/Width invalid. Should be formatted like 1024x768." ) );
1526 return 1;
1527 }
1528
1529 /* Fullscreen. */
1530 fullscreen = window_checkboxState( wid, "chkFullscreen" );
1531
1532 /* Only change if necessary or it causes some flicker. */
1533 if ( ( conf.width != w ) || ( conf.height != h ) ||
1534 ( fullscreen != conf.fullscreen ) ) {
1535 ret = opt_setVideoMode( w, h, fullscreen, 1 );
1536 window_checkboxSet( wid, "chkFullscreen", conf.fullscreen );
1537 if ( ret != 0 )
1538 return ret;
1539 }
1540
1541 /* FPS. */
1542 conf.fps_show = window_checkboxState( wid, "chkFPS" );
1543 inp = window_getInput( wid, "inpFPS" );
1544 conf.fps_max = atoi( inp );
1545
1546 /* OpenGL. */
1547 f = window_checkboxState( wid, "chkLowMemory" );
1548 if ( conf.low_memory != f ) {
1549 conf.low_memory = f;
1551 }
1552 f = window_checkboxState( wid, "chkVSync" );
1553 if ( conf.vsync != f ) {
1554 conf.vsync = f;
1556 }
1557
1558 /* Features. */
1559 f = window_checkboxState( wid, "chkMinimize" );
1560 if ( conf.minimize != f ) {
1561 conf.minimize = f;
1562 SDL_SetHint( SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS,
1563 conf.minimize ? "1" : "0" );
1564 }
1565
1566 /* GUI. */
1567 conf.big_icons = window_checkboxState( wid, "chkBigIcons" );
1568
1569 /* Reload background. */
1570 background_load( cur_system->background );
1571
1572 return 0;
1573}
1574
1578static void opt_setColourblindCorrect( unsigned int wid, const char *str )
1579{
1580 char buf[STRMAX_SHORT];
1581 conf.colourblind_correct = window_getFaderValue( wid, str );
1582 if ( conf.colourblind_correct > 0. )
1583 snprintf( buf, sizeof( buf ), _( "Colourblind correction: %.2f" ),
1584 conf.colourblind_correct );
1585 else
1586 snprintf( buf, sizeof( buf ), _( "Colourblind correction: off" ) );
1587 window_modifyText( wid, "txtColourblindCorrect", buf );
1589}
1590
1594static void opt_setColourblindSimulate( unsigned int wid, const char *str )
1595{
1596 char buf[STRMAX_SHORT];
1597 conf.colourblind_sim = window_getFaderValue( wid, str );
1598 if ( conf.colourblind_sim > 0. )
1599 snprintf( buf, sizeof( buf ), _( "Colourblind simulation: %.2f" ),
1600 conf.colourblind_sim );
1601 else
1602 snprintf( buf, sizeof( buf ), _( "Colourblind simulation: off" ) );
1603 window_modifyText( wid, "txtColourblindSimulate", buf );
1605}
1606
1610static void opt_listColourblind( unsigned int wid, const char *str )
1611{
1612 conf.colourblind_type = toolkit_getListPos( wid, str );
1614}
1615
1619static void opt_checkHealth( unsigned int wid, const char *str )
1620{
1621 int f = window_checkboxState( wid, str );
1622 conf.healthbars = f;
1623}
1624
1628static void opt_checkRestart( unsigned int wid, const char *str )
1629{
1630 (void)wid;
1631 (void)str;
1633}
1634
1646int opt_setVideoMode( int w, int h, int fullscreen, int confirm )
1647{
1648 int old_conf_w, old_conf_h, old_conf_f, status;
1649 int old_w, old_h, old_f, old_exp, new_w, new_h, new_f;
1650 int changed_size, maximized;
1651
1652 opt_getVideoMode( &old_w, &old_h, &old_f );
1653 old_conf_w = conf.width;
1654 old_conf_h = conf.height;
1655 old_conf_f = conf.fullscreen;
1656 old_exp = conf.explicit_dim;
1657 conf.width = w;
1658 conf.height = h;
1659 conf.fullscreen = fullscreen;
1660 conf.explicit_dim =
1661 conf.explicit_dim || ( w != old_conf_w ) || ( h != old_conf_h );
1662
1663 status = gl_setupFullscreen();
1664 if ( status == 0 && !fullscreen && ( w != old_w || h != old_h ) ) {
1665 SDL_SetWindowSize( gl_screen.window, w, h );
1666 SDL_SetWindowPosition( gl_screen.window, SDL_WINDOWPOS_CENTERED,
1667 SDL_WINDOWPOS_CENTERED );
1668 }
1669 naev_resize();
1670
1671 opt_getVideoMode( &new_w, &new_h, &new_f );
1672 changed_size = ( new_w != old_w ) || ( new_h != old_h );
1673 maximized = !new_f && ( SDL_GetWindowFlags( gl_screen.window ) &
1674 SDL_WINDOW_MAXIMIZED );
1675
1676 if ( confirm && !changed_size && maximized )
1677 dialogue_alertRaw( _( "Resolution can't be changed while maximized." ) );
1678 if ( confirm && ( ( status != 0 ) || ( new_f != fullscreen ) ) )
1680
1681 if ( confirm && ( ( status != 0 ) || changed_size || ( new_f != old_f ) ) &&
1682 !dialogue_YesNo( _( "Keep Video Settings" ),
1683 _( "Do you want to keep running at %dx%d %s?" ), new_w,
1684 new_h,
1685 new_f ? _( "fullscreen" ) : _( "windowed" ) ) ) {
1686
1687 opt_setVideoMode( old_conf_w, old_conf_h, old_conf_f, 0 );
1688 conf.explicit_dim = old_exp;
1689
1690 dialogue_msg( _( "Video Settings Restored" ),
1691 _( "Resolution reset to %dx%d %s." ), old_w, old_h,
1692 conf.fullscreen ? _( "fullscreen" ) : _( "windowed" ) );
1693
1694 return 1;
1695 }
1696
1697 return 0;
1698}
1699
1710static void opt_getVideoMode( int *w, int *h, int *fullscreen )
1711{
1712 SDL_DisplayMode mode;
1713 /* Warning: this test may be inadequate depending on our setup.
1714 * Example (Wayland): if I called SDL_SetWindowDisplayMode with an impossibly
1715 * large size, then SDL_SetWindowFullscreen, I see a window on my desktop
1716 * whereas SDL2 window flags report a fullscreen mode. Mitigation: be strict
1717 * about how the setup is done in opt_setVideoMode / gl_setupFullscreen, and
1718 * never bypass them. */
1719 *fullscreen =
1720 ( SDL_GetWindowFlags( gl_screen.window ) & SDL_WINDOW_FULLSCREEN ) != 0;
1721 if ( *fullscreen && conf.modesetting ) {
1722 SDL_GetWindowDisplayMode( gl_screen.window, &mode );
1723 *w = mode.w;
1724 *h = mode.h;
1725 } else
1726 SDL_GetWindowSize( gl_screen.window, w, h );
1727}
1728
1732static void opt_videoDefaults( unsigned int wid, const char *str )
1733{
1734 (void)str;
1735 char buf[16];
1736
1737 /* Restore settings. */
1738 /* Inputs. */
1739 snprintf( buf, sizeof( buf ), "%dx%d", RESOLUTION_W_DEFAULT,
1740 RESOLUTION_H_DEFAULT );
1741 window_setInput( wid, "inpRes", buf );
1742 snprintf( buf, sizeof( buf ), "%d", FPS_MAX_DEFAULT );
1743 window_setInput( wid, "inpFPS", buf );
1744
1745 /* Checkboxes. */
1746 window_checkboxSet( wid, "chkFullscreen", FULLSCREEN_DEFAULT );
1747 window_checkboxSet( wid, "chkVSync", VSYNC_DEFAULT );
1748 window_checkboxSet( wid, "chkFPS", SHOW_FPS_DEFAULT );
1749 window_checkboxSet( wid, "chkMinimize", MINIMIZE_DEFAULT );
1750 window_checkboxSet( wid, "chkBigIcons", BIG_ICONS_DEFAULT );
1751
1752 /* Faders. */
1753 window_faderSetBoundedValue( wid, "fadScale", log( SCALE_FACTOR_DEFAULT ) );
1754 window_faderSetBoundedValue( wid, "fadZoomFar", log1p( ZOOM_FAR_DEFAULT ) );
1755 window_faderSetBoundedValue( wid, "fadZoomNear",
1756 log1p( ZOOM_NEAR_DEFAULT ) );
1757 window_faderSetBoundedValue(
1758 wid, "fadGammaCorrection",
1759 log( GAMMA_CORRECTION_DEFAULT ) /* a.k.a. 0. */ );
1760 window_faderSetBoundedValue( wid, "fadMapOverlayOpacity",
1761 MAP_OVERLAY_OPACITY_DEFAULT );
1762}
1763
1770static void opt_setScalefactor( unsigned int wid, const char *str )
1771{
1772 char buf[STRMAX_SHORT];
1773 double scale = window_getFaderValue( wid, str );
1774 // scale = round(scale * 10.) / 10.;
1775 conf.scalefactor = exp( scale );
1776 snprintf( buf, sizeof( buf ), _( "Scaling: %.1fx" ), conf.scalefactor );
1777 window_modifyText( wid, "txtScale", buf );
1778 if ( FABS( conf.scalefactor - local_conf.scalefactor ) > 1e-4 )
1780}
1781
1788static void opt_setZoomFar( unsigned int wid, const char *str )
1789{
1790 char buf[STRMAX_SHORT];
1791 double scale = window_getFaderValue( wid, str );
1792 // scale = round(scale * 10.) / 10.;
1793 conf.zoom_far = expm1( scale );
1794 snprintf( buf, sizeof( buf ), _( "Far Zoom: %.1fx" ), conf.zoom_far );
1795 window_modifyText( wid, "txtZoomFar", buf );
1796 if ( conf.zoom_far > conf.zoom_near ) {
1797 window_faderSetBoundedValue( wid, "fadZoomNear", log1p( conf.zoom_far ) );
1798 opt_setZoomNear( wid, "fadZoomNear" );
1799 }
1800 if ( FABS( conf.zoom_far - local_conf.zoom_far ) > 1e-4 )
1802}
1803
1810static void opt_setZoomNear( unsigned int wid, const char *str )
1811{
1812 char buf[STRMAX_SHORT];
1813 double scale = window_getFaderValue( wid, str );
1814 // scale = round(scale * 10.) / 10.;
1815 conf.zoom_near = expm1( scale );
1816 snprintf( buf, sizeof( buf ), _( "Near Zoom: %.1fx" ), conf.zoom_near );
1817 window_modifyText( wid, "txtZoomNear", buf );
1818 if ( conf.zoom_near < conf.zoom_far ) {
1819 window_faderSetBoundedValue( wid, "fadZoomFar", log1p( conf.zoom_near ) );
1820 opt_setZoomFar( wid, "fadZoomFar" );
1821 }
1822 if ( FABS( conf.zoom_near - local_conf.zoom_near ) > 1e-4 )
1824}
1825
1832static void opt_setGammaCorrection( unsigned int wid, const char *str )
1833{
1834 char buf[STRMAX_SHORT];
1835 double scale = window_getFaderValue( wid, str );
1836 conf.gamma_correction = exp( scale );
1837 snprintf( buf, sizeof( buf ), _( "Gamma: %.1f" ), conf.gamma_correction );
1838 window_modifyText( wid, "txtGammaCorrection", buf );
1839 render_setGamma( conf.gamma_correction );
1840}
1841
1848static void opt_setBGBrightness( unsigned int wid, const char *str )
1849{
1850 char buf[STRMAX_SHORT];
1851 double fad = window_getFaderValue( wid, str );
1852 conf.bg_brightness = fad;
1853 snprintf( buf, sizeof( buf ), _( "BG (Stars, etc.) brightness: %.0f%%" ),
1854 100. * fad );
1855 window_modifyText( wid, "txtBGBrightness", buf );
1856}
1857
1858static void opt_setSaturation( unsigned int wid, const char *str )
1859{
1860 char buf[STRMAX_SHORT];
1861 double fad = window_getFaderValue( wid, str );
1862 conf.nebu_saturation = fad;
1863
1864 nebu_updateColour();
1865
1866 /* Update text. */
1867 snprintf( buf, sizeof( buf ), _( "Nebula saturation: %.0f%%" ), 100. * fad );
1868 window_modifyText( wid, "txtSaturation", buf );
1869}
1870
1877static void opt_setNebuNonuniformity( unsigned int wid, const char *str )
1878{
1879 char buf[STRMAX_SHORT];
1880 double fad = window_getFaderValue( wid, str );
1881 conf.nebu_nonuniformity = fad;
1882 snprintf( buf, sizeof( buf ), _( "Nebula non-uniformity: %.0f%%" ),
1883 100. * fad );
1884 window_modifyText( wid, "txtNebuNonuniformity", buf );
1885}
1886
1893static void opt_setJumpBrightness( unsigned int wid, const char *str )
1894{
1895 char buf[STRMAX_SHORT];
1896 double fad = window_getFaderValue( wid, str );
1897 conf.jump_brightness = fad;
1898 snprintf( buf, sizeof( buf ), _( "Jump brightness: %.0f%%" ), 100. * fad );
1899 window_modifyText( wid, "txtJumpBrightness", buf );
1900}
1901
1902static void opt_setGameSpeed( unsigned int wid, const char *str )
1903{
1904 char buf[STRMAX_SHORT];
1905 double prevspeed = conf.game_speed;
1906 conf.game_speed = window_getFaderValue( wid, str );
1907 player.speed *= conf.game_speed / prevspeed;
1908 pause_setSpeed( player.speed );
1909 snprintf( buf, sizeof( buf ), _( "Game speed: %.0f%%" ),
1910 100. * conf.game_speed );
1911 window_modifyText( wid, "txtGameSpeed", buf );
1912}
1913
1920static void opt_setMapOverlayOpacity( unsigned int wid, const char *str )
1921{
1922 char buf[STRMAX_SHORT];
1923 double fad = window_getFaderValue( wid, str );
1924 conf.map_overlay_opacity = fad;
1925 snprintf( buf, sizeof( buf ), _( "Map Overlay Opacity: %.0f%%" ),
1926 100. * fad );
1927 window_modifyText( wid, "txtMOpacity", buf );
1928}
1929
1933static void opt_plugins( unsigned int wid )
1934{
1935 int w, h, lw, bw;
1936 char buf[STRMAX_SHORT];
1937
1938 /* Get dimensions. */
1939 bw = BUTTON_WIDTH;
1940 window_dimWindow( wid, &w, &h );
1941 lw = w - 40 - 2 * ( bw + 20 );
1942
1943 /* Text stuff. */
1944 snprintf( buf, sizeof( buf ), "#n%s#0%s%s", _( "Plugins Directory: " ),
1945 PHYSFS_getRealDir( "plugins" ), "plugins" );
1946 window_addText( wid, 20, -30, w - 40, 30, 1, "txtPath", NULL, NULL, buf );
1947 window_addText( wid, -20, -70, w - ( 20 + lw + 20 + 20 ), h - 100, 0,
1948 "txtDesc", NULL, NULL, NULL );
1949
1950 opt_plugins_regenList( wid );
1951
1952 /* Add buttons. */
1953 /*
1954 window_addButton( wid, -20 - 1 * ( BUTTON_WIDTH + 20 ), 20, BUTTON_WIDTH,
1955 BUTTON_HEIGHT, "btnManager", _( "Manager" ),
1956 opt_keyDefaults );
1957 window_addButton( wid, -20 - 1 * ( BUTTON_WIDTH + 20 ), 20 + 1 *
1958 (BUTTON_HEIGHT+20), BUTTON_WIDTH, BUTTON_HEIGHT, "btnDisable", _( "Disable
1959 Plugin" ), opt_setKey );
1960 */
1961 // window_addButton( wid, -20 - 1 * ( BUTTON_WIDTH + 20 ), 20 + 1 * (
1962 // BUTTON_HEIGHT + 20 ), BUTTON_WIDTH,
1963 window_addButton( wid, -20 - 1 * ( BUTTON_WIDTH + 20 ), 20, BUTTON_WIDTH,
1964 BUTTON_HEIGHT, "btnPluginAdd", _( "Add Plugin" ),
1965 opt_plugins_add );
1966}
1967
1968static void opt_plugins_regenList( unsigned int wid )
1969{
1970 int w, h, lw, lh, bw, n, p;
1971 char **str;
1972 const plugin_t *plgs = plugin_list();
1973
1974 /* Get dimensions. */
1975 bw = BUTTON_WIDTH;
1976 window_dimWindow( wid, &w, &h );
1977 lw = w - 40 - 2 * ( bw + 20 );
1978 lh = h - 130;
1979
1980 p = 0;
1981 if ( widget_exists( wid, "lstPlugins" ) ) {
1982 p = toolkit_getListPos( wid, "lstPlugins" );
1983 window_destroyWidget( wid, "lstPlugins" );
1984 }
1985
1986 n = array_size( plgs );
1987 if ( n <= 0 ) {
1988 str = malloc( sizeof( char *) * 1 );
1989 str[0] = strdup( _( "No Plugins Found" ) );
1990 n = 1;
1991 } else {
1992 str = malloc( sizeof( char * ) * n );
1993 for ( int i = 0; i < n; i++ )
1994 str[i] = strdup( plugin_name( &plgs[i] ) );
1995 }
1996 window_addList( wid, 20, -70, lw, lh, "lstPlugins", str, n, p,
1997 opt_plugins_update, NULL );
1998}
1999
2000static void opt_plugins_add_callback( void *userdata,
2001 const char *const *filelist, int filter )
2002{
2003 (void)filter;
2004 unsigned int wid = *(unsigned int *)userdata;
2005 const plugin_t *plgs;
2006 char buf[STRMAX], buf_susp[STRMAX], path[PATH_MAX], *fname;
2007 int suspicious = 0;
2008 const plugin_t *plg_susp = NULL;
2009
2010 if ( filelist == NULL ) {
2011 WARN( _( "Error calling %s: %s" ), "SDL_ShowOpenFileDialog",
2012 SDL_GetError() );
2013 return;
2014 } else if ( filelist[0] == NULL ) {
2015 /* Cancelled by user. */
2016 return;
2017 }
2018
2019 /* Check to see if valid. */
2020 plugin_t *plg = plugin_test( filelist[0] );
2021 if ( plg == NULL ) {
2022 dialogue_alert( _( "'%s' is not a valid plugin!" ), filelist[0] );
2023 return;
2024 }
2025 /* See if overlaps. */
2026 plgs = plugin_list();
2027 for ( int i = 0; i < array_size( plgs ); i++ ) {
2028 if ( strcmp( plugin_name( &plgs[i] ), plugin_name( plg ) ) == 0 ) {
2029 suspicious = 1;
2030 plg_susp = &plgs[i];
2031 snprintf( buf_susp, sizeof( buf_susp ),
2032 _( "#nName:#0 %s\n"
2033 "#nAuthor:#0 %s\n"
2034 "#nVersion:#0 %s\n"
2035 "#nDescription:#0 %s" ),
2036 plugin_name( plg_susp ), plg_susp->author, plg_susp->version,
2037 plg_susp->description );
2038 break;
2039 }
2040 }
2041
2042 /* New plugin path. */
2043 fname = strdup( filelist[0] );
2044 nfile_concatPaths( path, sizeof( path ), plugin_dir(), basename( fname ) );
2045 free( fname );
2046
2047 /* Get plugin details. */
2048 snprintf( buf, sizeof( buf ),
2049 _( "#nName:#0 %s\n"
2050 "#nAuthor:#0 %s\n"
2051 "#nVersion:#0 %s\n"
2052 "#nDescription:#0 %s" ),
2053 plugin_name( plg ), plg->author, plg->version, plg->description );
2054
2055 /* Check to see if definately add. */
2056 if ( nfile_fileExists( path ) ) {
2057 if ( suspicious ) {
2058 if ( !dialogue_YesNo(
2059 _( "Update plugin?" ),
2060 _( "Are you sure you want to update the plugin '%s'? This "
2061 "will require a restart to take full "
2062 "effect.\n\n#nNew Plugin Details#0\n%s\n\n#nOld Plugin "
2063 "Details#0\n%s" ),
2064 plugin_name( plg ), buf, buf_susp ) ) {
2065 plugin_free( plg );
2066 free( plg );
2067 return;
2068 }
2069 } else {
2070 fname = strdup( filelist[0] );
2071 if ( !dialogue_YesNo(
2072 _( "Overwrite plugin?" ),
2073 _( "Are you sure you want to add '%s' to your list of active "
2074 "plugins? This will overwrite a plugin with the same file "
2075 "name (%s), but not same plug in name. This will require a "
2076 "restart to take full "
2077 "effect.\n\n#nNew Plugin Details#0\n%s" ),
2078 plugin_name( plg ), basename( fname ), buf ) ) {
2079 plugin_free( plg );
2080 free( plg );
2081 free( fname );
2082 return;
2083 }
2084 free( fname );
2085 }
2086 } else if ( !suspicious ) {
2087 if ( !dialogue_YesNo(
2088 _( "Add plugin?" ),
2089 _( "Are you sure you want to add '%s' to your list of active "
2090 "plugins? This will require a restart to take full "
2091 "effect.\n\n#nNew Plugin Details#0\n%s" ),
2092 plugin_name( plg ), buf ) ) {
2093 plugin_free( plg );
2094 free( plg );
2095 return;
2096 }
2097 } else {
2098 if ( !dialogue_YesNo(
2099 _( "Add plugin?" ),
2100 _( "Are you sure you want to add '%s' to your list of active "
2101 "plugins? #rThis plugin has the same name as one of your "
2102 "existing plugins and make cause issues#0. This will require "
2103 "a restart to take full effect.\n\n#nNew Plugin "
2104 "Details#0\n%s\n\n#nSame name Plugin Details#0\n%s" ),
2105 plugin_name( plg ), buf, buf_susp ) ) {
2106 plugin_free( plg );
2107 free( plg );
2108 return;
2109 }
2110 }
2111
2112 /* Copy file over. */
2113 if ( nfile_copyIfExists( filelist[0], path ) ) {
2114 dialogue_alert( _( "Failed to copy '%s' to '%s'!" ), filelist[0], path );
2115 plugin_free( plg );
2116 free( plg );
2117 return;
2118 }
2119
2120 /* Insert plugin. */
2121 plugin_insert( plg );
2122 free( plg );
2124 opt_plugins_regenList( wid );
2125}
2126static void opt_plugins_add( unsigned int wid, const char *name )
2127{
2128 (void)name;
2129 const SDL_DialogFileFilter filter[] = {
2130 { .name = _( "Naev Plugin File" ), .pattern = "zip" },
2131 { NULL, NULL },
2132 };
2133 /* Open dialogue to load the diff. */
2134 SDL_ShowOpenFileDialog( opt_plugins_add_callback, &wid, gl_screen.window,
2135 filter, conf.dev_data_dir, 0 );
2136}
2137
2138static void opt_plugins_update( unsigned int wid, const char *name )
2139{
2140 char buf[STRMAX];
2141 const plugin_t *plg, *plgs;
2142 int pos = toolkit_getListPos( wid, name );
2143 int l = 0;
2144
2145 plgs = plugin_list();
2146 if ( array_size( plgs ) <= 0 )
2147 return;
2148 plg = &plgs[pos];
2149 l += scnprintf( &buf[l], sizeof( buf ) - l, "#n%s#0\n",
2150 p_( "plugins", "Name:" ) );
2151 l += scnprintf( &buf[l], sizeof( buf ) - l, " %s\n",
2152 _( plugin_name( plg ) ) );
2153 l += scnprintf( &buf[l], sizeof( buf ) - l, "#n%s#0\n",
2154 p_( "plugins", "Author(s):" ) );
2155 l += scnprintf( &buf[l], sizeof( buf ) - l, " %s\n", _( plg->author ) );
2156 l += scnprintf( &buf[l], sizeof( buf ) - l, "#n%s#0\n",
2157 p_( "plugins", "Version:" ) );
2158 l += scnprintf( &buf[l], sizeof( buf ) - l, " %s\n", plg->version );
2159 l += scnprintf( &buf[l], sizeof( buf ) - l, "#n%s#0\n",
2160 p_( "plugins", "Description:" ) );
2161 l +=
2162 scnprintf( &buf[l], sizeof( buf ) - l, " %s\n", _( plg->description ) );
2163 if ( plg->total_conversion )
2164 /*l +=*/scnprintf( &buf[l], sizeof( buf ) - l, "#g%s#0",
2165 _( "Total Conversion" ) );
2166
2167 window_modifyText( wid, "txtDesc", buf );
2168}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
int background_load(const char *name)
Loads a background script by name.
Definition background.c:502
#define BUTTON_HEIGHT
Definition board.c:28
#define BUTTON_WIDTH
Definition board.c:27
char * dialogue_runChoice(void)
Run the dialog and return the clicked string.
Definition dialogue.c:817
void dialogue_alert(const char *fmt,...)
Displays an alert popup with only an ok button and a message.
Definition dialogue.c:130
void dialogue_msg(const char *caption, const char *fmt,...)
Opens a dialogue window with an ok button and a message.
Definition dialogue.c:227
void dialogue_addChoice(const char *caption, const char *msg, const char *opt)
Add a choice to the dialog.
Definition dialogue.c:796
void dialogue_alertRaw(const char *msg)
Displays an alert popup with only an ok button and a message.
Definition dialogue.c:149
void dialogue_makeChoice(const char *caption, const char *msg, int opts)
Create the choice dialog. Need to add choices with below method.
Definition dialogue.c:773
void dialogue_msgRaw(const char *caption, const char *msg)
Opens a dialogue window with an ok button and a fixed message.
Definition dialogue.c:269
int dialogue_YesNo(const char *caption, const char *fmt,...)
Runs a dialogue with both yes and no options.
Definition dialogue.c:352
glFont gl_smallFont
Definition font.c:159
int gl_printWidthRaw(const glFont *ft_font, const char *text)
Gets the width that it would take to print some text.
Definition font.c:984
glFont gl_defFont
Definition font.c:158
void gl_freeFont(glFont *font)
Frees a loaded font. Caution: its glFontStash still has a slot in avail_fonts. At the time of writing...
Definition font.c:1881
int gl_fontInit(glFont *font, const char *fname, const unsigned int h, const char *prefix, unsigned int flags)
Initializes a font.
Definition font.c:1670
glFont gl_defFontMono
Definition font.c:160
double gettext_languageCoverage(const char *lang)
Return the fraction of strings which have a translation into the given language.
Definition gettext.c:312
void gettext_setLanguage(const char *lang)
Set the translation language.
Definition gettext.c:135
const char * pgettext_var(const char *msgctxt, const char *msgid)
Definition gettext.c:346
LanguageOption * gettext_languageOptions(void)
List the available languages, with completeness statistics.
Definition gettext.c:289
const char * gettext_getSystemLanguage(void)
Gets the current system language as detected by Naev.
Definition gettext.c:110
SDL_Keycode input_getKeybind(KeySemanticType keybind, KeybindType *type, SDL_Keymod *mod)
Gets the value of a keybind.
Definition input.c:525
KeySemanticType input_keyAlreadyBound(KeybindType type, SDL_Keycode key, SDL_Keymod mod)
Checks to see if a key is already bound.
Definition input.c:639
void input_setDefault(int wasd)
Sets the default input keys.
Definition input.c:267
const char * input_getKeybindName(KeySemanticType keybind)
Gets the name of the keybinding.
Definition input.c:693
void input_setKeybind(KeySemanticType keybind, KeybindType type, SDL_Keycode key, SDL_Keymod mod)
Binds key of type type to action keybind.
Definition input.c:502
const char * input_getKeybindDescription(KeySemanticType keybind)
Gets the description of the keybinding.
Definition input.c:708
const char * input_modToText(SDL_Keymod mod)
Gets the human readable version of mod.
Definition input.c:611
double music_getVolumeLog(void)
Gets the current music volume (logarithmic).
Definition music.c:233
double music_getVolume(void)
Gets the current music volume (linear).
Definition music.c:223
int music_volume(double vol)
Sets the music volume from a linear value.
Definition music.c:195
void naev_resize(void)
Wrapper for gl_resize that handles non-GL reinitialization.
Definition naev.c:874
Header file with generic functions and naev-specifics.
const char * naev_version(int long_version)
Returns the version in a human readable string.
#define FABS(x)
Definition naev.h:34
#define PATH_MAX
Definition naev.h:57
int nfile_copyIfExists(const char *file1, const char *file2)
Copy a file, if it exists.
Definition nfile.c:378
const char * nfile_configPath(void)
Gets Naev's config path (for user preferences such as conf.lua)
Definition nfile.c:113
int nfile_fileExists(const char *path)
Checks to see if a file exists.
Definition nfile.c:329
int scnprintf(char *text, size_t maxlen, const char *fmt,...)
Like snprintf(), but returns the number of characters ACTUALLY "printed" into the buffer....
Definition nstring.c:102
int strsort_reverse(const void *p1, const void *p2)
Order-reversed version of strsort().
Definition nstring.c:91
void gl_colourblind(void)
Enables or disables the colourblind shader.
Definition opengl.c:878
glInfo gl_screen
Definition opengl.c:47
int gl_setupFullscreen(void)
Tries to apply the configured display mode to the window.
Definition opengl.c:340
static void opt_gameplay(unsigned int wid)
Opens the gameplay menu.
Definition options.c:290
int opt_setVideoMode(int w, int h, int fullscreen, int confirm)
Applies new video-mode options.
Definition options.c:1646
static void opt_listColourblind(unsigned int wid, const char *str)
Handles the colourblind mode change.
Definition options.c:1610
static void opt_keyDefaults(unsigned int wid, const char *str)
Restores the key defaults.
Definition options.c:788
static void opt_accessibilityDefaults(unsigned int wid, const char *str)
Sets video defaults.
Definition options.c:1314
static void menuKeybinds_getDim(unsigned int wid, int *w, int *h, int *lw, int *lh, int *bw, int *bh)
Gets the keybind menu dimensions.
Definition options.c:558
#define LANG_CODE_START
Definition options.c:51
static void opt_needRestart(void)
Marks that needs restart.
Definition options.c:1492
static void opt_checkRestart(unsigned int wid, const char *str)
Basically flags for needing a restart.
Definition options.c:1628
static void opt_getVideoMode(int *w, int *h, int *fullscreen)
Detects the video-mode options corresponding to the gl_screen we have set up.
Definition options.c:1710
static void opt_checkHealth(unsigned int wid, const char *str)
Handles the health bar checkbox.
Definition options.c:1619
static void opt_setAudioLevel(unsigned int wid, const char *str)
Callback to set the sound or music level.
Definition options.c:858
static void opt_audioUpdate(unsigned int wid)
Updates the gameplay options.
Definition options.c:1015
static void opt_setZoomNear(unsigned int wid, const char *str)
Callback to set the far zoom.
Definition options.c:1810
void opt_resize(void)
Handles resize events for the options menu.
Definition options.c:241
static void opt_setNebuNonuniformity(unsigned int wid, const char *str)
Callback to set the nebula non-uniformity parameter.
Definition options.c:1877
static void opt_setJumpBrightness(unsigned int wid, const char *str)
Callback to set the background brightness.
Definition options.c:1893
static void opt_OK(unsigned int wid, const char *str)
Saves all options and closes the options screen.
Definition options.c:191
static void opt_videoDefaults(unsigned int wid, const char *str)
Sets video defaults.
Definition options.c:1732
static void opt_audioDefaults(unsigned int wid, const char *str)
Sets the audio defaults.
Definition options.c:997
static void opt_setBGBrightness(unsigned int wid, const char *str)
Callback to set the background brightness.
Definition options.c:1848
static void opt_keybinds(unsigned int wid)
Opens the keybindings menu.
Definition options.c:580
static void menuKeybinds_genList(unsigned int wid)
Generates the keybindings list.
Definition options.c:610
static int opt_lastKeyPress
Definition options.c:72
static void opt_plugins(unsigned int wid)
Opens the keybindings menu.
Definition options.c:1933
static void opt_accessibility(unsigned int wid)
Initializes the accessibility window.
Definition options.c:1200
static void opt_setColourblindSimulate(unsigned int wid, const char *str)
Handles the colourblind correction.
Definition options.c:1594
static int opt_videoSave(unsigned int wid, const char *str)
Saves the video settings.
Definition options.c:1514
static void opt_audioLevelStr(char *buf, int max, int type, double pos)
Sets the sound or music volume string based on level.
Definition options.c:883
static void opt_unsetKey(unsigned int wid, const char *str)
Unsets the key.
Definition options.c:1181
static void opt_video(unsigned int wid)
Initializes the video window.
Definition options.c:1339
static void opt_setMapOverlayOpacity(unsigned int wid, const char *str)
Callback to set autonav abort threshold.
Definition options.c:1920
void opt_menu(void)
Creates the options menu thingy.
Definition options.c:141
static KeySemanticType opt_selectedKeybind
Definition options.c:71
static void opt_setKey(unsigned int wid, const char *str)
Rebinds a key.
Definition options.c:1141
static void opt_audio(unsigned int wid)
Opens the audio settings menu.
Definition options.c:902
static void opt_close(unsigned int wid, const char *name)
Closes the options screen without saving.
Definition options.c:217
static void menuKeybinds_update(unsigned int wid, const char *name)
Updates the keybindings menu.
Definition options.c:715
static void opt_gameplayUpdate(unsigned int wid, const char *str)
Updates the gameplay options.
Definition options.c:539
static void opt_setColourblindCorrect(unsigned int wid, const char *str)
Handles the colourblind correction.
Definition options.c:1578
static void opt_gameplayDefaults(unsigned int wid, const char *str)
Sets the default gameplay options.
Definition options.c:519
static void opt_setGammaCorrection(unsigned int wid, const char *str)
Callback to set the gamma correction value (reciprocal of exponent).
Definition options.c:1832
static int opt_setKeyEvent(unsigned int wid, SDL_Event *event)
Tries to set the key from an event.
Definition options.c:1030
static int opt_gameplaySave(unsigned int wid, const char *str)
Saves the gameplay options.
Definition options.c:434
static void opt_videoRes(unsigned int wid, const char *str)
Callback when resolution changes.
Definition options.c:1505
static int opt_audioSave(unsigned int wid, const char *str)
Saves the audio stuff.
Definition options.c:969
static void opt_setScalefactor(unsigned int wid, const char *str)
Callback to set the scaling factor.
Definition options.c:1770
static void opt_setZoomFar(unsigned int wid, const char *str)
Callback to set the far zoom.
Definition options.c:1788
void pause_setSpeed(double mod)
Adjusts the game's dt modifier.
Definition pause.c:61
void pilot_calcStats(Pilot *pilot)
Recalculates the pilot's stats based on his outfits.
int snd_target
Definition player.c:103
Player_t player
Definition player.c:77
void player_soundPlayGUI(int sound, int once)
Plays a GUI sound (unaffected by time accel).
Definition player.c:947
plugin_t * plugin_test(const char *filename)
Tests to see if a file is a plugin and loads information.
Definition plugin.c:37
void plugin_insert(plugin_t *plg)
Inserts a plugin to the list, but does not properly enable it (requires restart).
Definition plugin.c:291
const char * plugin_name(const plugin_t *plg)
Tries to tget the name of a plugin.
Definition plugin.c:315
const char * plugin_dir(void)
Gets the plugin directory.
Definition plugin.c:196
void plugin_free(plugin_t *plg)
Frees a previously allocated plugin.
Definition plugin.c:325
const plugin_t * plugin_list(void)
Returns the list of all the plugins.
Definition plugin.c:396
static const double d[]
Definition rng.c:263
double sound_getVolumeLog(void)
Gets the current sound volume (logarithmic).
Definition sound.c:1304
double sound_getVolume(void)
Gets the current sound volume (linear).
Definition sound.c:1291
int sound_disabled
Definition sound.c:130
int sound_volume(const double vol)
Sets the volume.
Definition sound.c:1268
StarSystem * cur_system
Definition space.c:110
char * name
Definition difficulty.h:9
Struct containing player options.
Definition conf.h:94
char * author
Definition plugin.h:8
char * version
Definition plugin.h:9
int total_conversion
Definition plugin.h:18
char * description
Definition plugin.h:10
unsigned int window_create(const char *name, const char *displayname, const int x, const int y, const int w, const int h)
Creates a window.
Definition toolkit.c:688
unsigned int window_getParent(unsigned int wid)
Gets the window's parent.
Definition toolkit.c:804
void window_dimWindow(unsigned int wid, int *w, int *h)
Gets the dimensions of a window.
Definition toolkit.c:370
void window_setCancel(unsigned int wid, void(*cancel)(unsigned int, const char *))
Sets the default cancel function of the window.
Definition toolkit.c:868
void window_destroyWidget(unsigned int wid, const char *wgtname)
Destroys a widget in a window.
Definition toolkit.c:1167
void window_setParent(unsigned int wid, unsigned int parent)
Sets a window as a window's parent.
Definition toolkit.c:787
int widget_exists(unsigned int wid, const char *wgtname)
Checks to see if a widget exists.
Definition toolkit.c:1144
void window_close(unsigned int wid, const char *str)
Helper function to automatically close the window calling it.
Definition toolkit.c:1028
void window_destroy(unsigned int wid)
Kills the window.
Definition toolkit.c:1039
void window_handleEvents(unsigned int wid, int(*eventhandler)(unsigned int, SDL_Event *))
Sets the event handler for the window.
Definition toolkit.c:979