1 #include <i18n.h>
2 #include "engine.h"
3 #include "optionsMenu.h"
4 #include "hotkeyMenu.h"
5 #include "main.h"
6 #include "preferenceManager.h"
7 
8 #include "gui/gui2_autolayout.h"
9 #include "gui/gui2_overlay.h"
10 #include "gui/gui2_button.h"
11 #include "gui/gui2_togglebutton.h"
12 #include "gui/gui2_selector.h"
13 #include "gui/gui2_label.h"
14 #include "gui/gui2_slider.h"
15 #include "gui/gui2_listbox.h"
16 #include "gui/gui2_keyvaluedisplay.h"
17 
OptionsMenu()18 OptionsMenu::OptionsMenu()
19 {
20     P<WindowManager> windowManager = engine->getObject("windowManager");
21 
22     new GuiOverlay(this, "", colorConfig.background);
23     (new GuiOverlay(this, "", sf::Color::White))->setTextureTiled("gui/BackgroundCrosses");
24 
25     // Initialize autolayout columns.
26     left_container = new GuiAutoLayout(this, "OPTIONS_LEFT_CONTAINER", GuiAutoLayout::LayoutVerticalTopToBottom);
27     left_container->setPosition(50, 50, ATopLeft)->setSize(300, GuiElement::GuiSizeMax);
28 
29     right_container = new GuiAutoLayout(this, "OPTIONS_RIGHT_CONTAINER", GuiAutoLayout::LayoutVerticalTopToBottom);
30     right_container->setPosition(-50, 50, ATopRight)->setSize(600, GuiElement::GuiSizeMax);
31 
32     // Options pager
33     options_pager = new GuiSelector(left_container, "OPTIONS_PAGER", [this](int index, string value)
34     {
35         graphics_page->setVisible(index == 0);
36         audio_page->setVisible(index == 1);
37         interface_page->setVisible(index == 2);
38     });
39     options_pager->setOptions({tr("Graphics options"), tr("Audio options"), tr("Interface options")})->setSelectionIndex(0)->setSize(GuiElement::GuiSizeMax, 50);
40 
41     graphics_page = new GuiAutoLayout(left_container, "OPTIONS_GRAPHICS", GuiAutoLayout::LayoutVerticalTopToBottom);
42     graphics_page->setPosition(0, 0, ATopLeft)->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax)->show();
43     audio_page = new GuiAutoLayout(left_container, "OPTIONS_AUDIO", GuiAutoLayout::LayoutVerticalTopToBottom);
44     audio_page->setPosition(0, 0, ATopLeft)->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax)->hide();
45     interface_page = new GuiAutoLayout(left_container, "OPTIONS_INTERFACE", GuiAutoLayout::LayoutVerticalTopToBottom);
46     interface_page->setPosition(0, 0, ATopLeft)->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax)->hide();
47 
48     // Graphics options
49     // Fullscreen toggle.
50     (new GuiButton(graphics_page, "FULLSCREEN_TOGGLE", tr("Fullscreen toggle"), []()
51     {
52         P<WindowManager> windowManager = engine->getObject("windowManager");
53         windowManager->setFullscreen(!windowManager->isFullscreen());
54     }))->setSize(GuiElement::GuiSizeMax, 50);
55 
56     // FSAA configuration.
57     int fsaa = std::max(1, windowManager->getFSAA());
58     int fsaa_index = 0;
59 
60     // Convert selector index to an FSAA amount.
61     switch(fsaa)
62     {
63         case 8: fsaa_index = 3; break;
64         case 4: fsaa_index = 2; break;
65         case 2: fsaa_index = 1; break;
66         default: fsaa_index = 0; break;
67     }
68 
69     // FSAA selector.
70     (new GuiSelector(graphics_page, "FSAA", [](int index, string value)
71     {
72         P<WindowManager> windowManager = engine->getObject("windowManager");
73         static const int fsaa[] = { 0, 2, 4, 8 };
74         windowManager->setFSAA(fsaa[index]);
75     }))->setOptions({"FSAA: off", "FSAA: 2x", "FSAA: 4x", "FSAA: 8x"})->setSelectionIndex(fsaa_index)->setSize(GuiElement::GuiSizeMax, 50);
76 
77     // Audio optionss
78     // Sound volume slider.
79     sound_volume_slider = new GuiSlider(audio_page, "SOUND_VOLUME_SLIDER", 0.0f, 100.0f, soundManager->getMasterSoundVolume(), [this](float volume)
80     {
81         soundManager->setMasterSoundVolume(volume);
82         sound_volume_overlay_label->setText(tr("Sound Volume: {volume}%").format({{"volume", string(int(soundManager->getMasterSoundVolume()))}}));
83     });
84     sound_volume_slider->setSize(GuiElement::GuiSizeMax, 50);
85 
86     // Override overlay label.
87     sound_volume_overlay_label = new GuiLabel(sound_volume_slider, "SOUND_VOLUME_SLIDER_LABEL", tr("Sound Volume: {volume}%").format({{"volume", string(int(soundManager->getMasterSoundVolume()))}}), 30);
88     sound_volume_overlay_label->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax);
89 
90     // Music playback state.
91     (new GuiLabel(audio_page, "MUSIC_PLAYBACK_LABEL", tr("Music Playback"), 30))->addBackground()->setSize(GuiElement::GuiSizeMax, 50);
92 
93     // Determine when music is enabled.
94     int music_enabled_index = PreferencesManager::get("music_enabled", "2").toInt();
95     (new GuiSelector(audio_page, "MUSIC_ENABLED", [](int index, string value)
96     {
97         // 0: Always off
98         // 1: Always on
99         // 2: On if main screen, off otherwise (default)
100         PreferencesManager::set("music_enabled", string(index));
101     }))->setOptions({tr("Disabled"), tr("Enabled"), tr("Main Screen only")})->setSelectionIndex(music_enabled_index)->setSize(GuiElement::GuiSizeMax, 50);
102 
103     // Music volume slider.
104     music_volume_slider = new GuiSlider(audio_page, "MUSIC_VOLUME_SLIDER", 0.0f, 100.0f, soundManager->getMusicVolume(), [this](float volume)
105     {
106         soundManager->setMusicVolume(volume);
107         music_volume_overlay_label->setText(tr("Music Volume: {volume}%").format({{"volume", string(int(soundManager->getMusicVolume()))}}));
108     });
109     music_volume_slider->setSize(GuiElement::GuiSizeMax, 50);
110 
111     // Override overlay label.
112     music_volume_overlay_label = new GuiLabel(music_volume_slider, "MUSIC_VOLUME_SLIDER_LABEL", tr("Music Volume: {volume}%").format({{"volume", string(int(soundManager->getMusicVolume()))}}), 30);
113     music_volume_overlay_label->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax);
114 
115     // Engine playback state.
116     (new GuiLabel(audio_page, "IMPULSE_SOUND_LABEL", tr("Impulse Engine sound"), 30))->addBackground()->setSize(GuiElement::GuiSizeMax, 50);
117 
118     // Determine when engine sound effects are enabled.
119     int impulse_enabled_index = PreferencesManager::get("impulse_sound_enabled", "2").toInt();
120     (new GuiSelector(audio_page, "ENGINE_ENABLED", [](int index, string value)
121     {
122         // 0: Always off
123         // 1: Always on
124         // 2: On if main screen, off otherwise (default)
125         PreferencesManager::set("impulse_sound_enabled", string(index));
126     }))->setOptions({tr("Disabled"), tr("Enabled"), tr("Main Screen only")})->setSelectionIndex(impulse_enabled_index)->setSize(GuiElement::GuiSizeMax, 50);
127 
128     // Impulse engine volume slider.
129     impulse_volume_slider = new GuiSlider(audio_page, "IMPULSE_VOLUME_SLIDER", 0.0f, 100.0f, PreferencesManager::get("impulse_sound_volume", "50").toInt(), [this](float volume)
130     {
131         PreferencesManager::set("impulse_sound_volume", volume);
132         impulse_volume_overlay_label->setText(tr("Impulse Volume: {volume}%").format({{"volume", string(PreferencesManager::get("impulse_sound_volume", "50").toInt())}}));
133     });
134     impulse_volume_slider->setSize(GuiElement::GuiSizeMax, 50);
135 
136     // Override overlay label.
137     impulse_volume_overlay_label = new GuiLabel(impulse_volume_slider, "IMPULSE_VOLUME_SLIDER_LABEL", tr("Impulse Volume: {volume}%").format({{"volume", string(PreferencesManager::get("impulse_sound_volume", "50").toInt())}}), 30);
138     impulse_volume_overlay_label->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax);
139 
140     // Interface options
141     // Helms rotation lock.
142     (new GuiToggleButton(interface_page, "HEMS_RADAR_LOCK", tr("Helms Radar Lock"), [](bool value)
143     {
144         PreferencesManager::set("helms_radar_lock", value ? "1" : "");
145         PreferencesManager::set("tactical_radar_lock", value ? "1" : "");
146         PreferencesManager::set("single_pilot_radar_lock", value ? "1" : "");
147     }))->setValue(PreferencesManager::get("helms_radar_lock", "0") == "1")->setSize(GuiElement::GuiSizeMax, 50);
148 
149     // Weapons rotation lock.
150     (new GuiToggleButton(interface_page, "WEAPONS_RADAR_LOCK", tr("Weapons Radar Lock"), [](bool value)
151     {
152         PreferencesManager::set("weapons_radar_lock", value ? "1" : "");
153     }))->setValue(PreferencesManager::get("weapons_radar_lock", "0") == "1")->setSize(GuiElement::GuiSizeMax, 50);
154 
155     // Science rotation lock.
156     (new GuiToggleButton(interface_page, "SCIENCE_RADAR_LOCK", tr("Science Radar Lock"), [](bool value)
157     {
158         PreferencesManager::set("science_radar_lock", value ? "1" : "");
159         PreferencesManager::set("operations_radar_lock", value ? "1" : "");
160     }))->setValue(PreferencesManager::get("science_radar_lock", "0") == "1")->setSize(GuiElement::GuiSizeMax, 50);
161 
162     // Control configuration
163     (new GuiLabel(interface_page, "CONTROL_OPTIONS_LABEL", tr("Control Options"), 30))->addBackground()->setSize(GuiElement::GuiSizeMax, 50);
164 
165     // Keyboard config (hotkeys/keybindings)
166     (new GuiButton(interface_page, "CONFIGURE_KEYBOARD", tr("Configure Keyboard"), [this]()
167     {
168         new HotkeyMenu();
169         destroy();
170     }))->setSize(GuiElement::GuiSizeMax, 50);
171 
172     //Select the language
173     (new GuiLabel(interface_page, "LANGUAGE_OPTIONS_LABEL", tr("Language (applies on back)"), 30))->addBackground()->setSize(GuiElement::GuiSizeMax, 50);
174 
175     std::vector<string> languages = findResources("locale/main.*.po");
176 
177     for(string &language : languages)
178     {
179         //strip extension
180         language = language.substr(language.find(".") + 1, language.rfind("."));
181     }
182     std::sort(languages.begin(), languages.end());
183 
184     int default_index = 0;
185     auto default_elem = std::find(languages.begin(), languages.end(), PreferencesManager::get("language", "en"));
186     if(default_elem != languages.end())
187     {
188         default_index =  default_elem - languages.begin();
189     }
190 
191     (new GuiSelector(interface_page, "LANGUAGE_SELECTOR", [](int index, string value)
192     {
193         i18n::reset();
194         i18n::load("locale/main." + value + ".po");
195         PreferencesManager::set("language", value);
196     }))->setOptions(languages)->setSelectionIndex(default_index)->setSize(GuiElement::GuiSizeMax, 50);
197 
198 
199     // Right column, auto layout. Draw first element 50px from top.
200     // Music preview jukebox.
201 
202     // Draw list of available music. Grabs every ogg file in the
203     // resources/music folder and lists them by filename.
204     std::vector<string> ambient_music_filenames = findResources("music/ambient/*.ogg");
205     std::sort(ambient_music_filenames.begin(), ambient_music_filenames.end());
206     std::vector<string> combat_music_filenames = findResources("music/combat/*.ogg");
207     std::sort(combat_music_filenames.begin(), combat_music_filenames.end());
208 
209     (new GuiLabel(right_container, "PREVIEW_LABEL", tr("Preview Soundtracks"), 30))->addBackground()->setSize(GuiElement::GuiSizeMax, 50);
210 
211     GuiListbox* music_list = new GuiListbox(right_container, "MUSIC_PLAY", [this](int index, string value)
212     {
213         soundManager->playMusic(value);
214     });
215 
216     for(string filename : ambient_music_filenames)
217         music_list->addEntry(filename.substr(filename.rfind("/") + 1, filename.rfind(".")), filename);
218     for(string filename : combat_music_filenames)
219         music_list->addEntry(filename.substr(filename.rfind("/") + 1, filename.rfind(".")), filename);
220 
221     music_list->setSize(GuiElement::GuiSizeMax, 750);
222 
223     // Bottom GUI.
224     // Back button.
225     (new GuiButton(this, "BACK", tr("button", "Back"), [this]()
226     {
227         // Close this menu, stop the music, and return to the main menu.
228         destroy();
229         soundManager->stopMusic();
230         returnToMainMenu();
231     }))->setPosition(50, -50, ABottomLeft)->setSize(150, 50);
232     // Save options button.
233     (new GuiButton(this, "SAVE_OPTIONS", tr("options", "Save"), [this]()
234     {
235         if (getenv("HOME"))
236             PreferencesManager::save(string(getenv("HOME")) + "/.emptyepsilon/options.ini");
237         else
238             PreferencesManager::save("options.ini");
239     }))->setPosition(200, -50, ABottomLeft)->setSize(150, 50);
240 }
241 
onKey(sf::Event::KeyEvent key,int unicode)242 void OptionsMenu::onKey(sf::Event::KeyEvent key, int unicode)
243 {
244     switch(key.code)
245     {
246     //TODO: This is more generic code and is duplicated.
247     case sf::Keyboard::Escape:
248     case sf::Keyboard::Home:
249         destroy();
250         soundManager->stopMusic();
251         returnToMainMenu();
252         break;
253     default:
254         break;
255     }
256 }
257