1 /*
2    Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3    Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY.
11 
12    See the COPYING file for more details.
13 */
14 
15 /**
16  *  @file
17  *  Get and set user-preferences.
18  */
19 
20 #define GETTEXT_DOMAIN "wesnoth-lib"
21 
22 #include "preferences/general.hpp"
23 
24 #include "config.hpp"
25 #include "credentials.hpp"
26 #include "filesystem.hpp"
27 #include "game_config.hpp"
28 #include "hotkey/hotkey_item.hpp"
29 #include "lexical_cast.hpp"
30 #include "log.hpp"
31 #include "sdl/point.hpp"
32 #include "serialization/parser.hpp"
33 #include "sound.hpp"
34 #include "utils/general.hpp"
35 #include "video.hpp" // non_interactive()
36 
37 #include <sys/stat.h> // for setting the permissions of the preferences file
38 #ifndef _WIN32
39 #include <unistd.h>
40 #endif
41 
42 static lg::log_domain log_config("config");
43 #define ERR_CFG LOG_STREAM(err , log_config)
44 
45 static lg::log_domain log_filesystem("filesystem");
46 #define ERR_FS LOG_STREAM(err, log_filesystem)
47 
48 namespace {
49 
50 bool no_preferences_save = false;
51 
52 bool fps = false;
53 
54 config prefs;
55 }
56 
57 namespace preferences {
58 
59 /*
60  * Stores all the static, default values for certain game preferences. The values
61  * are kept here for easy modification without a lengthy rebuild.
62  *
63  * Add any variables of similar type here.
64  */
65 const int min_window_width  = 800;
66 const int min_window_height = 600;
67 
68 const int def_window_width  = 1280;
69 const int def_window_height = 720;
70 
71 const int min_font_scaling  = 80;
72 const int max_font_scaling  = 150;
73 
74 const SCALING_ALGORITHM default_scaling_algorithm = SCALING_ALGORITHM::XBRZ_NN;
75 
76 class prefs_event_handler : public events::sdl_handler {
77 public:
handle_event(const SDL_Event &)78 	virtual void handle_event(const SDL_Event &) {}
79 	virtual void handle_window_event(const SDL_Event &event);
prefs_event_handler()80 	prefs_event_handler() :	sdl_handler(false) {}
81 };
82 
83 prefs_event_handler event_handler_;
84 
base_manager()85 base_manager::base_manager()
86 {
87 	event_handler_.join_global();
88 
89 	try{
90 #ifdef DEFAULT_PREFS_PATH
91 		filesystem::scoped_istream stream = filesystem::istream_file(filesystem::get_default_prefs_file(),false);
92 		read(prefs, *stream);
93 
94 		config user_prefs;
95 		stream = filesystem::istream_file(filesystem::get_prefs_file());
96 		read(user_prefs, *stream);
97 
98 		prefs.merge_with(user_prefs);
99 #else
100 		filesystem::scoped_istream stream = filesystem::istream_file(filesystem::get_prefs_file(),false);
101 		read(prefs, *stream);
102 #endif
103 	} catch(const config::error& e) {
104 		ERR_CFG << "Error loading preference, message: "
105 				<< e.what()
106 				<< std::endl;
107 	}
108 	preferences::load_credentials();
109 }
110 
~base_manager()111 base_manager::~base_manager()
112 {
113 	event_handler_.leave_global();
114 
115 	try {
116 		if (no_preferences_save) return;
117 
118 		// Set the 'hidden' preferences.
119 		prefs["scroll_threshold"] = mouse_scroll_threshold();
120 
121 		write_preferences();
122 	} catch (...) {}
123 }
124 
125 /*
126  * Hook for setting window state variables on window resize and maximize
127  * events. Since there is no fullscreen window event, that setter is called
128  * from the CVideo function instead.
129  */
handle_window_event(const SDL_Event & event)130 void prefs_event_handler::handle_window_event(const SDL_Event& event)
131 {
132 
133 	// Safety check to make sure this is a window event
134 	if (event.type != SDL_WINDOWEVENT) return;
135 
136 	switch(event.window.event) {
137 	case SDL_WINDOWEVENT_RESIZED:
138 		_set_resolution(point(event.window.data1,event.window.data2));
139 
140 		break;
141 
142 	case SDL_WINDOWEVENT_MAXIMIZED:
143 		_set_maximized(true);
144 
145 		break;
146 
147 	case SDL_WINDOWEVENT_RESTORED:
148 		_set_maximized(fullscreen() || false);
149 
150 		break;
151 	}
152 }
153 
write_preferences()154 void write_preferences()
155 {
156 #ifndef _WIN32
157     bool prefs_file_existed = access(filesystem::get_prefs_file().c_str(), F_OK) == 0;
158 #endif
159 
160 	try {
161 		filesystem::scoped_ostream prefs_file = filesystem::ostream_file(filesystem::get_prefs_file());
162 		write(*prefs_file, prefs);
163 	} catch(const filesystem::io_exception&) {
164 		ERR_FS << "error writing to preferences file '" << filesystem::get_prefs_file() << "'" << std::endl;
165 	}
166 
167 	preferences::save_credentials();
168 
169 #ifndef _WIN32
170     if(!prefs_file_existed) {
171 
172         if(chmod(filesystem::get_prefs_file().c_str(), 0600) == -1) {
173 			ERR_FS << "error setting permissions of preferences file '" << filesystem::get_prefs_file() << "'" << std::endl;
174         }
175 
176     }
177 #endif
178 }
179 
set(const std::string & key,bool value)180 void set(const std::string &key, bool value)
181 {
182 	prefs[key] = value;
183 }
184 
set(const std::string & key,int value)185 void set(const std::string &key, int value)
186 {
187 	prefs[key] = value;
188 }
189 
set(const std::string & key,char const * value)190 void set(const std::string &key, char const *value)
191 {
192 	prefs[key] = value;
193 }
194 
set(const std::string & key,const std::string & value)195 void set(const std::string &key, const std::string &value)
196 {
197 	prefs[key] = value;
198 }
199 
set(const std::string & key,const config::attribute_value & value)200 void set(const std::string &key, const config::attribute_value &value)
201 {
202 	prefs[key] = value;
203 }
204 
clear(const std::string & key)205 void clear(const std::string& key)
206 {
207 	prefs.recursive_clear_value(key);
208 }
209 
set_child(const std::string & key,const config & val)210 void set_child(const std::string& key, const config& val) {
211 	prefs.clear_children(key);
212 	prefs.add_child(key, val);
213 }
214 
get_child(const std::string & key)215 const config &get_child(const std::string& key)
216 {
217 	return prefs.child(key);
218 }
219 
erase(const std::string & key)220 void erase(const std::string& key) {
221 	prefs.remove_attribute(key);
222 }
223 
have_setting(const std::string & key)224 bool have_setting(const std::string& key) {
225 	return prefs.has_attribute(key);
226 }
227 
get(const std::string & key)228 std::string get(const std::string& key) {
229 	return prefs[key];
230 }
231 
get(const std::string & key,const std::string & def)232 std::string get(const std::string& key, const std::string& def) {
233 	return prefs[key].empty() ? def : prefs[key];
234 }
235 
get(const std::string & key,bool def)236 bool get(const std::string &key, bool def)
237 {
238 	return prefs[key].to_bool(def);
239 }
240 
get_as_attribute(const std::string & key)241 config::attribute_value get_as_attribute(const std::string &key)
242 {
243 	return prefs[key];
244 }
245 
disable_preferences_save()246 void disable_preferences_save() {
247 	no_preferences_save = true;
248 }
249 
get_prefs()250 config* get_prefs(){
251 	config* pointer = &prefs;
252 	return pointer;
253 }
254 
255 
show_allied_orb()256 bool show_allied_orb() {
257 	return get("show_ally_orb", game_config::show_ally_orb);
258 }
set_show_allied_orb(bool show_orb)259 void set_show_allied_orb(bool show_orb) {
260 	prefs["show_ally_orb"] = show_orb;
261 }
262 
show_enemy_orb()263 bool show_enemy_orb() {
264 	return get("show_enemy_orb", game_config::show_enemy_orb);
265 }
set_show_enemy_orb(bool show_orb)266 void set_show_enemy_orb(bool show_orb) {
267 	prefs["show_enemy_orb"] = show_orb;
268 }
269 
show_moved_orb()270 bool show_moved_orb() {
271 	return get("show_moved_orb", game_config::show_moved_orb);
272 }
set_show_moved_orb(bool show_orb)273 void set_show_moved_orb(bool show_orb) {
274 	prefs["show_moved_orb"] = show_orb;
275 }
276 
show_unmoved_orb()277 bool show_unmoved_orb() {
278 	return get("show_unmoved_orb", game_config::show_unmoved_orb);
279 }
set_show_unmoved_orb(bool show_orb)280 void set_show_unmoved_orb(bool show_orb) {
281 	prefs["show_unmoved_orb"] = show_orb;
282 }
283 
show_partial_orb()284 bool show_partial_orb() {
285 	return get("show_partial_orb", game_config::show_partial_orb);
286 }
set_show_partial_orb(bool show_orb)287 void set_show_partial_orb(bool show_orb) {
288 	prefs["show_partial_orb"] = show_orb;
289 }
290 
291 
fix_orb_color_name(const std::string & color)292 static std::string fix_orb_color_name(const std::string& color) {
293 	if (color.substr(0,4) == "orb_") {
294 		if(color[4] >= '0' && color[4] <= '9') {
295 			return color.substr(5);
296 		} else {
297 			return color.substr(4);
298 		}
299 	}
300 	return color;
301 }
302 
allied_color()303 std::string allied_color() {
304 	std::string ally_color = get("ally_orb_color");
305 	if (ally_color.empty())
306 		return game_config::colors::ally_orb_color;
307 	return fix_orb_color_name(ally_color);
308 }
set_allied_color(const std::string & color_id)309 void set_allied_color(const std::string& color_id) {
310 	prefs["ally_orb_color"] = color_id;
311 }
312 
core_id()313 std::string core_id() {
314 	std::string core_id = get("core");
315 	if (core_id.empty())
316 		return "default";
317 	return core_id;
318 }
set_core_id(const std::string & core_id)319 void set_core_id(const std::string& core_id) {
320 	prefs["core"] = core_id;
321 }
322 
enemy_color()323 std::string enemy_color() {
324 	std::string enemy_color = get("enemy_orb_color");
325 	if (enemy_color.empty())
326 		return game_config::colors::enemy_orb_color;
327 	return fix_orb_color_name(enemy_color);
328 }
set_enemy_color(const std::string & color_id)329 void set_enemy_color(const std::string& color_id) {
330 	prefs["enemy_orb_color"] = color_id;
331 }
332 
moved_color()333 std::string moved_color() {
334 	std::string moved_color = get("moved_orb_color");
335 	if (moved_color.empty())
336 		return game_config::colors::moved_orb_color;
337 	return fix_orb_color_name(moved_color);
338 }
set_moved_color(const std::string & color_id)339 void set_moved_color(const std::string& color_id) {
340 	prefs["moved_orb_color"] = color_id;
341 }
342 
unmoved_color()343 std::string unmoved_color() {
344 	std::string unmoved_color = get("unmoved_orb_color");
345 	if (unmoved_color.empty())
346 		return game_config::colors::unmoved_orb_color;
347 	return fix_orb_color_name(unmoved_color);
348 }
set_unmoved_color(const std::string & color_id)349 void set_unmoved_color(const std::string& color_id) {
350 	prefs["unmoved_orb_color"] = color_id;
351 }
352 
partial_color()353 std::string partial_color() {
354 	std::string partmoved_color = get("partial_orb_color");
355 	if (partmoved_color.empty())
356 		return game_config::colors::partial_orb_color;
357 	return fix_orb_color_name(partmoved_color);
358 }
set_partial_color(const std::string & color_id)359 void set_partial_color(const std::string& color_id) {
360 	prefs["partial_orb_color"] = color_id;
361 }
362 
scroll_to_action()363 bool scroll_to_action()
364 {
365 	return get("scroll_to_action", true);
366 }
367 
set_scroll_to_action(bool ison)368 void set_scroll_to_action(bool ison)
369 {
370 	prefs["scroll_to_action"] = ison;
371 }
372 
resolution()373 point resolution()
374 {
375 	const unsigned x_res = prefs["xresolution"].to_unsigned();
376 	const unsigned y_res = prefs["yresolution"].to_unsigned();
377 
378 	// Either resolution was unspecified, return default.
379 	if(x_res == 0 || y_res == 0) {
380 		return point(def_window_width, def_window_height);
381 	}
382 
383 	return point(
384 		std::max<unsigned>(x_res, min_window_width),
385 		std::max<unsigned>(y_res, min_window_height)
386 	);
387 }
388 
maximized()389 bool maximized()
390 {
391 	return get("maximized", !fullscreen());
392 }
393 
fullscreen()394 bool fullscreen()
395 {
396 	return get("fullscreen", true);
397 }
398 
_set_resolution(const point & res)399 void _set_resolution(const point& res)
400 {
401 	preferences::set("xresolution", std::to_string(res.x));
402 	preferences::set("yresolution", std::to_string(res.y));
403 }
404 
_set_maximized(bool ison)405 void _set_maximized(bool ison)
406 {
407 	prefs["maximized"] = ison;
408 }
409 
_set_fullscreen(bool ison)410 void _set_fullscreen(bool ison)
411 {
412 	prefs["fullscreen"] = ison;
413 }
414 
turbo()415 bool turbo()
416 {
417 	if(CVideo::get_singleton().non_interactive()) {
418 		return true;
419 	}
420 
421 	return get("turbo", false);
422 }
423 
_set_turbo(bool ison)424 void _set_turbo(bool ison)
425 {
426 	prefs["turbo"] = ison;
427 }
428 
turbo_speed()429 double turbo_speed()
430 {
431 	return prefs["turbo_speed"].to_double(2.0);
432 }
433 
save_turbo_speed(const double speed)434 void save_turbo_speed(const double speed)
435 {
436 	prefs["turbo_speed"] = speed;
437 }
438 
font_scaling()439 int font_scaling()
440 {
441 	// Clip at 80 because if it's too low it'll cause crashes
442 	return std::max<int>(std::min<int>(prefs["font_scale"].to_int(100), max_font_scaling), min_font_scaling);
443 }
444 
set_font_scaling(int scale)445 void set_font_scaling(int scale)
446 {
447 	prefs["font_scale"] = utils::clamp(scale, min_font_scaling, max_font_scaling);
448 }
449 
font_scaled(int size)450 int font_scaled(int size)
451 {
452 	return (size * font_scaling()) / 100;
453 }
454 
idle_anim()455 bool idle_anim()
456 {
457 	return  get("idle_anim", true);
458 }
459 
_set_idle_anim(const bool ison)460 void _set_idle_anim(const bool ison)
461 {
462 	prefs["idle_anim"] = ison;
463 }
464 
idle_anim_rate()465 int idle_anim_rate()
466 {
467 	return prefs["idle_anim_rate"];
468 }
469 
_set_idle_anim_rate(const int rate)470 void _set_idle_anim_rate(const int rate)
471 {
472 	prefs["idle_anim_rate"] = rate;
473 }
474 
language()475 std::string language()
476 {
477 	return prefs["locale"];
478 }
479 
set_language(const std::string & s)480 void set_language(const std::string& s)
481 {
482 	preferences::set("locale", s);
483 }
484 
gui_theme()485 std::string gui_theme()
486 {
487 	return prefs["gui2_theme"];
488 }
489 
set_gui_theme(const std::string & s)490 void set_gui_theme(const std::string& s)
491 {
492 	preferences::set("gui2_theme", s);
493 }
494 
ellipses()495 bool ellipses()
496 {
497 	return get("show_side_colors", false);
498 }
499 
set_ellipses(bool ison)500 void set_ellipses(bool ison)
501 {
502 	preferences::set("show_side_colors",  ison);
503 }
504 
grid()505 bool grid()
506 {
507 	return get("grid", false);
508 }
509 
_set_grid(bool ison)510 void _set_grid(bool ison)
511 {
512 	preferences::set("grid", ison);
513 }
514 
sound_buffer_size()515 size_t sound_buffer_size()
516 {
517 	// Sounds don't sound good on Windows unless the buffer size is 4k,
518 	// but this seems to cause crashes on other systems...
519 	#ifdef _WIN32
520 		const size_t buf_size = 4096;
521 	#else
522 		const size_t buf_size = 1024;
523 	#endif
524 
525 	return prefs["sound_buffer_size"].to_int(buf_size);
526 }
527 
save_sound_buffer_size(const size_t size)528 void save_sound_buffer_size(const size_t size)
529 {
530 	#ifdef _WIN32
531 		const char* buf_size = "4096";
532 	#else
533 		const char* buf_size = "1024";
534 	#endif
535 
536 	const std::string new_size = lexical_cast_default<std::string>(size, buf_size);
537 	if (get("sound_buffer_size") == new_size)
538 		return;
539 
540 	preferences::set("sound_buffer_size", new_size);
541 
542 	sound::reset_sound();
543 }
544 
music_volume()545 int music_volume()
546 {
547 	return prefs["music_volume"].to_int(100);
548 }
549 
set_music_volume(int vol)550 void set_music_volume(int vol)
551 {
552 	if(music_volume() == vol) {
553 		return;
554 	}
555 
556 	prefs["music_volume"] = vol;
557 	sound::set_music_volume(music_volume());
558 }
559 
sound_volume()560 int sound_volume()
561 {
562 	return prefs["sound_volume"].to_int(100);
563 }
564 
set_sound_volume(int vol)565 void set_sound_volume(int vol)
566 {
567 	if(sound_volume() == vol) {
568 		return;
569 	}
570 
571 	prefs["sound_volume"] = vol;
572 	sound::set_sound_volume(sound_volume());
573 }
574 
bell_volume()575 int bell_volume()
576 {
577 	return prefs["bell_volume"].to_int(100);
578 }
579 
set_bell_volume(int vol)580 void set_bell_volume(int vol)
581 {
582 	if(bell_volume() == vol) {
583 		return;
584 	}
585 
586 	prefs["bell_volume"] = vol;
587 	sound::set_bell_volume(bell_volume());
588 }
589 
UI_volume()590 int UI_volume()
591 {
592 	return prefs["UI_volume"].to_int(100);
593 }
594 
set_UI_volume(int vol)595 void set_UI_volume(int vol)
596 {
597 	if(UI_volume() == vol) {
598 		return;
599 	}
600 
601 	prefs["UI_volume"] = vol;
602 	sound::set_UI_volume(UI_volume());
603 }
604 
turn_bell()605 bool turn_bell()
606 {
607 	return get("turn_bell", true);
608 }
609 
set_turn_bell(bool ison)610 bool set_turn_bell(bool ison)
611 {
612 	if(!turn_bell() && ison) {
613 		preferences::set("turn_bell", true);
614 		if(!music_on() && !sound_on() && !UI_sound_on()) {
615 			if(!sound::init_sound()) {
616 				preferences::set("turn_bell", false);
617 				return false;
618 			}
619 		}
620 	} else if(turn_bell() && !ison) {
621 		preferences::set("turn_bell", false);
622 		sound::stop_bell();
623 		if(!music_on() && !sound_on() && !UI_sound_on())
624 			sound::close_sound();
625 	}
626 	return true;
627 }
628 
UI_sound_on()629 bool UI_sound_on()
630 {
631 	return get("UI_sound", true);
632 }
633 
set_UI_sound(bool ison)634 bool set_UI_sound(bool ison)
635 {
636 	if(!UI_sound_on() && ison) {
637 		preferences::set("UI_sound", true);
638 		if(!music_on() && !sound_on() && !turn_bell()) {
639 			if(!sound::init_sound()) {
640 				preferences::set("UI_sound", false);
641 				return false;
642 			}
643 		}
644 	} else if(UI_sound_on() && !ison) {
645 		preferences::set("UI_sound", false);
646 		sound::stop_UI_sound();
647 		if(!music_on() && !sound_on() && !turn_bell())
648 			sound::close_sound();
649 	}
650 	return true;
651 }
652 
message_bell()653 bool message_bell()
654 {
655 	return get("message_bell", true);
656 }
657 
sound_on()658 bool sound_on()
659 {
660 	return get("sound", true);
661 }
662 
set_sound(bool ison)663 bool set_sound(bool ison) {
664 	if(!sound_on() && ison) {
665 		preferences::set("sound", true);
666 		if(!music_on() && !turn_bell() && !UI_sound_on()) {
667 			if(!sound::init_sound()) {
668 				preferences::set("sound", false);
669 				return false;
670 			}
671 		}
672 	} else if(sound_on() && !ison) {
673 		preferences::set("sound", false);
674 		sound::stop_sound();
675 		if(!music_on() && !turn_bell() && !UI_sound_on())
676 			sound::close_sound();
677 	}
678 	return true;
679 }
680 
music_on()681 bool music_on()
682 {
683 	return get("music", true);
684 }
685 
set_music(bool ison)686 bool set_music(bool ison) {
687 	if(!music_on() && ison) {
688 		preferences::set("music", true);
689 		if(!sound_on() && !turn_bell() && !UI_sound_on()) {
690 			if(!sound::init_sound()) {
691 				preferences::set("music", false);
692 				return false;
693 			}
694 		}
695 		else
696 			sound::play_music();
697 	} else if(music_on() && !ison) {
698 		preferences::set("music", false);
699 		if(!sound_on() && !turn_bell() && !UI_sound_on())
700 			sound::close_sound();
701 		else
702 			sound::stop_music();
703 	}
704 	return true;
705 }
706 
stop_music_in_background()707 bool stop_music_in_background()
708 {
709 	return get("stop_music_in_background", false);
710 }
711 
set_stop_music_in_background(bool ison)712 void set_stop_music_in_background(bool ison)
713 {
714 	preferences::set("stop_music_in_background", ison);
715 }
716 
717 namespace {
718 	double scroll = 0.2;
719 }
720 
joystick_support_enabled()721 bool joystick_support_enabled()
722 {
723 	return get("joystick_support_enabled", false);
724 }
725 
joystick_mouse_deadzone()726 int joystick_mouse_deadzone()
727 {
728 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_scroll_deadzone"), 1500), 0, 16000);
729 	return value;
730 }
731 
joystick_num_mouse_xaxis()732 int joystick_num_mouse_xaxis()
733 {
734 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_num_scroll_xaxis"), 0), -1, 3);
735 	return value;
736 }
737 
joystick_mouse_xaxis_num()738 int joystick_mouse_xaxis_num()
739 {
740 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_scroll_xaxis_num"), 0), 0, 7);
741 	return value;
742 }
743 
joystick_num_mouse_yaxis()744 int joystick_num_mouse_yaxis()
745 {
746 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_num_scroll_yaxis"), 0), -1, 3);
747 	return value;
748 }
749 
joystick_mouse_yaxis_num()750 int joystick_mouse_yaxis_num()
751 {
752 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_scroll_yaxis_num"), 1), 0, 7);
753 	return value;
754 }
755 
joystick_scroll_deadzone()756 int joystick_scroll_deadzone()
757 {
758 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_scroll_deadzone"), 1500), 0, 16000);
759 	return value;
760 }
761 
joystick_cursor_deadzone()762 int joystick_cursor_deadzone()
763 {
764 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_cursor_deadzone"), 1500), 0, 16000);
765 	return value;
766 }
767 
joystick_thrusta_deadzone()768 int joystick_thrusta_deadzone()
769 {
770 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_thrusta_deadzone"), 1500), 0, 16000);
771 	return value;
772 }
773 
joystick_thrustb_deadzone()774 int joystick_thrustb_deadzone()
775 {
776 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_thrustb_deadzone"), 1500), 0, 16000);
777 	return value;
778 }
779 
joystick_cursor_threshold()780 int joystick_cursor_threshold()
781 {
782 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_cursor_threshold"), 10000), 0, 16000);
783 	return value;
784 }
785 
joystick_num_scroll_xaxis()786 int joystick_num_scroll_xaxis()
787 {
788 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_num_scroll_xaxis"), 0), -1, 3);
789 	return value;
790 }
791 
joystick_scroll_xaxis_num()792 int joystick_scroll_xaxis_num()
793 {
794 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_scroll_xaxis_num"), 0), 0, 7);
795 	return value;
796 }
797 
joystick_num_scroll_yaxis()798 int joystick_num_scroll_yaxis()
799 {
800 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_num_scroll_yaxis"), 0), -1, 3);
801 	return value;
802 }
803 
joystick_scroll_yaxis_num()804 int joystick_scroll_yaxis_num()
805 {
806 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_scroll_yaxis_num"), 1), 0, 7);
807 	return value;
808 }
809 
joystick_num_cursor_xaxis()810 int joystick_num_cursor_xaxis()
811 {
812 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_num_cursor_xaxis"), 0), -1, 3);
813 	return value;
814 }
815 
joystick_cursor_xaxis_num()816 int joystick_cursor_xaxis_num()
817 {
818 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_cursor_xaxis_num"), 3), 0, 7);
819 	return value;
820 }
821 
joystick_num_cursor_yaxis()822 int joystick_num_cursor_yaxis()
823 {
824 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_num_cursor_yaxis"), 0), -1, 3);
825 	return value;
826 }
827 
joystick_cursor_yaxis_num()828 int joystick_cursor_yaxis_num()
829 {
830 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_cursor_yaxis_num"), 4), 0, 7);
831 	return value;
832 }
833 
joystick_num_thrusta_axis()834 int joystick_num_thrusta_axis()
835 {
836 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_num_thrusta_axis"), 0), -1, 3);
837 	return value;
838 }
839 
joystick_thrusta_axis_num()840 int joystick_thrusta_axis_num()
841 {
842 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_thrusta_axis_num"), 2), 0, 7);
843 	return value;
844 }
845 
joystick_num_thrustb_axis()846 int joystick_num_thrustb_axis()
847 {
848 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_num_thrustb_axis"), 0), -1, 3);
849 	return value;
850 }
851 
joystick_thrustb_axis_num()852 int joystick_thrustb_axis_num()
853 {
854 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("joystick_thrustb_axis_num"), 2), 0, 7);
855 	return value;
856 }
857 
858 
scroll_speed()859 int scroll_speed()
860 {
861 	const int value = utils::clamp<int>(lexical_cast_default<int>(get("scroll"), 50), 1, 100);
862 	scroll = value/100.0;
863 
864 	return value;
865 }
866 
set_scroll_speed(const int new_speed)867 void set_scroll_speed(const int new_speed)
868 {
869 	prefs["scroll"] = new_speed;
870 	scroll = new_speed / 100.0;
871 }
872 
middle_click_scrolls()873 bool middle_click_scrolls()
874 {
875 	return get("middle_click_scrolls", true);
876 }
877 
mouse_scroll_enabled()878 bool mouse_scroll_enabled()
879 {
880 	return get("mouse_scrolling", true);
881 }
882 
enable_mouse_scroll(bool value)883 void enable_mouse_scroll(bool value)
884 {
885 	set("mouse_scrolling", value);
886 }
887 
mouse_scroll_threshold()888 int mouse_scroll_threshold()
889 {
890 	return prefs["scroll_threshold"].to_int(10);
891 }
892 
animate_map()893 bool animate_map()
894 {
895 	return preferences::get("animate_map", true);
896 }
897 
animate_water()898 bool animate_water()
899 {
900 	return preferences::get("animate_water", true);
901 }
902 
minimap_movement_coding()903 bool minimap_movement_coding()
904 {
905 	return preferences::get("minimap_movement_coding", true);
906 }
907 
toggle_minimap_movement_coding()908 void toggle_minimap_movement_coding()
909 {
910 	set("minimap_movement_coding", !minimap_movement_coding());
911 }
912 
minimap_terrain_coding()913 bool minimap_terrain_coding()
914 {
915 	return preferences::get("minimap_terrain_coding", true);
916 }
917 
toggle_minimap_terrain_coding()918 void toggle_minimap_terrain_coding()
919 {
920 	set("minimap_terrain_coding", !minimap_terrain_coding());
921 }
922 
minimap_draw_units()923 bool minimap_draw_units()
924 {
925 	return preferences::get("minimap_draw_units", true);
926 }
927 
toggle_minimap_draw_units()928 void toggle_minimap_draw_units()
929 {
930 	set("minimap_draw_units", !minimap_draw_units());
931 }
932 
minimap_draw_villages()933 bool minimap_draw_villages()
934 {
935 	return preferences::get("minimap_draw_villages", true);
936 }
937 
toggle_minimap_draw_villages()938 void toggle_minimap_draw_villages()
939 {
940 	set("minimap_draw_villages", !minimap_draw_villages());
941 }
942 
minimap_draw_terrain()943 bool minimap_draw_terrain()
944 {
945 	return preferences::get("minimap_draw_terrain", true);
946 }
947 
toggle_minimap_draw_terrain()948 void toggle_minimap_draw_terrain()
949 {
950 	set("minimap_draw_terrain", !minimap_draw_terrain());
951 }
952 
set_animate_map(bool value)953 void set_animate_map(bool value)
954 {
955 	set("animate_map", value);
956 }
957 
set_animate_water(bool value)958 void set_animate_water(bool value)
959 {
960 	set("animate_water", value);
961 }
962 
show_fps()963 bool show_fps()
964 {
965 	return fps;
966 }
967 
set_show_fps(bool value)968 void set_show_fps(bool value)
969 {
970 	fps = value;
971 }
972 
draw_delay()973 int draw_delay()
974 {
975 	return prefs["draw_delay"].to_int(-1);
976 }
977 
set_draw_delay(int value)978 void set_draw_delay(int value)
979 {
980 	prefs["draw_delay"] = value;
981 }
982 
use_color_cursors()983 bool use_color_cursors()
984 {
985 	return get("color_cursors", true);
986 }
987 
_set_color_cursors(bool value)988 void _set_color_cursors(bool value)
989 {
990 	preferences::set("color_cursors", value);
991 }
992 
load_hotkeys()993 void load_hotkeys()
994 {
995 	hotkey::load_hotkeys(prefs, false);
996 }
997 
save_hotkeys()998 void save_hotkeys()
999 {
1000 	hotkey::save_hotkeys(prefs);
1001 }
1002 
clear_hotkeys()1003 void clear_hotkeys()
1004 {
1005 	hotkey::reset_default_hotkeys();
1006 	prefs.clear_children("hotkey");
1007 }
1008 
add_alias(const std::string & alias,const std::string & command)1009 void add_alias(const std::string &alias, const std::string &command)
1010 {
1011 	config &alias_list = prefs.child_or_add("alias");
1012 	alias_list[alias] = command;
1013 }
1014 
1015 
get_alias()1016 const config &get_alias()
1017 {
1018 	return get_child("alias");
1019 }
1020 
sample_rate()1021 unsigned int sample_rate()
1022 {
1023 	return prefs["sample_rate"].to_int(44100);
1024 }
1025 
save_sample_rate(const unsigned int rate)1026 void save_sample_rate(const unsigned int rate)
1027 {
1028 	if (sample_rate() == rate)
1029 		return;
1030 
1031 	prefs["sample_rate"] = static_cast<int>(rate);
1032 
1033 	// If audio is open, we have to re set sample rate
1034 	sound::reset_sound();
1035 }
1036 
confirm_load_save_from_different_version()1037 bool confirm_load_save_from_different_version()
1038 {
1039 	return get("confirm_load_save_from_different_version", true);
1040 }
1041 
use_twelve_hour_clock_format()1042 bool use_twelve_hour_clock_format()
1043 {
1044 	return get("use_twelve_hour_clock_format", false);
1045 }
1046 
disable_auto_moves()1047 bool disable_auto_moves()
1048 {
1049 	return get("disable_auto_moves", false);
1050 }
1051 
set_disable_auto_moves(bool value)1052 void set_disable_auto_moves(bool value)
1053 {
1054 	preferences::set("disable_auto_moves", value);
1055 }
1056 
disable_loadingscreen_animation()1057 bool disable_loadingscreen_animation()
1058 {
1059 	return get("disable_loadingscreen_animation", false);
1060 }
1061 
set_disable_loadingscreen_animation(bool value)1062 void set_disable_loadingscreen_animation(bool value)
1063 {
1064 	set("disable_loadingscreen_animation", value);
1065 }
1066 
damage_prediction_allow_monte_carlo_simulation()1067 bool damage_prediction_allow_monte_carlo_simulation()
1068 {
1069 	return get("damage_prediction_allow_monte_carlo_simulation", true);
1070 }
1071 
set_damage_prediction_allow_monte_carlo_simulation(bool value)1072 void set_damage_prediction_allow_monte_carlo_simulation(bool value)
1073 {
1074 	set("damage_prediction_allow_monte_carlo_simulation", value);
1075 }
1076 
1077 } // end namespace preferences
1078