1 /*
2  * Copyright (C) 2011-2013 Me and My Shadow
3  *
4  * This file is part of Me and My Shadow.
5  *
6  * Me and My Shadow is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Me and My Shadow is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Me and My Shadow.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "Functions.h"
21 #include "GameState.h"
22 #include "OptionsMenu.h"
23 #include "ThemeManager.h"
24 #include "GUIListBox.h"
25 #include "GUISlider.h"
26 #include "InputManager.h"
27 #include "LevelPackManager.h"
28 #include "StatisticsManager.h"
29 #include "MusicManager.h"
30 #include "SoundManager.h"
31 #include <iostream>
32 #include <sstream>
33 
34 #include "libs/tinyformat/tinyformat.h"
35 #include "libs/tinygettext/tinygettext.hpp"
36 #include "libs/findlocale/findlocale.h"
37 
38 using namespace std;
39 
40 /////////////////////////OPTIONS_MENU//////////////////////////////////
41 
42 //Some variables for the options.
43 static bool fullscreen,internet,fade,quickrec;
44 static string themeName,languageName;
45 static int lastLang,lastRes;
46 
47 static bool useProxy;
48 static string internetProxy;
49 
50 static bool restartFlag;
51 
52 static SDL_Point currentRes;
53 static vector<SDL_Point> resolutionList;
54 
Options(ImageManager & imageManager,SDL_Renderer & renderer)55 Options::Options(ImageManager& imageManager,SDL_Renderer& renderer){
56 	//Render the title.
57 	title = titleTextureFromText(renderer, _("Settings"), objThemes.getTextColor(false), SCREEN_WIDTH);
58 
59 	//Initialize variables.
60 	lastJumpSound=0;
61 	clearIconHower=false;
62 	section = 2;
63 	section2 = 1;
64 
65     //Load icon image and tooltip text.
66     clearIcon=imageManager.loadTexture(getDataPath()+"gfx/menu/clear-progress.png",renderer);
67     /// TRANSLATORS: Used for button which clear any level progress like unlocked levels and highscores.
68     clearTooltip=textureFromText(renderer, *fontText, _("Clear Progress"), objThemes.getTextColor(true));
69 
70 	//Set some default settings.
71 	fullscreen=getSettings()->getBoolValue("fullscreen");
72 	languageName=getSettings()->getValue("lang");
73 	themeName=processFileName(getSettings()->getValue("theme"));
74 	internet=getSettings()->getBoolValue("internet");
75 	internetProxy=getSettings()->getValue("internet-proxy");
76 	useProxy=!internetProxy.empty();
77 	fade=getSettings()->getBoolValue("fading");
78 	quickrec=getSettings()->getBoolValue("quickrecord");
79 
80 	//Set the restartFlag false.
81 	restartFlag=false;
82 
83 	//Now create the gui.
84     createGUI(imageManager,renderer);
85 }
86 
~Options()87 Options::~Options(){
88 	//Delete the GUI.
89 	if(GUIObjectRoot){
90 		delete GUIObjectRoot;
91 		GUIObjectRoot=NULL;
92 	}
93 }
94 
createGUI(ImageManager & imageManager,SDL_Renderer & renderer)95 void Options::createGUI(ImageManager& imageManager,SDL_Renderer& renderer){
96 	//Variables for positioning
97 	const int columnW=SCREEN_WIDTH*0.3;
98 	const int column1X=SCREEN_WIDTH*0.15;
99 	const int column2X=SCREEN_WIDTH*0.55;
100 	const int lineHeight=40;
101 
102 	//Create the root element of the GUI.
103 	if(GUIObjectRoot){
104 		delete GUIObjectRoot;
105 		GUIObjectRoot=NULL;
106 	}
107     GUIObjectRoot=new GUIObject(imageManager,renderer,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
108 
109 	//Single line list for different tabs.
110     GUISingleLineListBox* listBox=new GUISingleLineListBox(imageManager,renderer,(SCREEN_WIDTH-500)/2,104,500,32);
111 	listBox->addItem(_("General"));
112 	listBox->addItem(_("Controls"));
113 	listBox->value=0;
114 	listBox->name="lstTabs";
115 	listBox->eventCallback=this;
116 	GUIObjectRoot->addChild(listBox);
117 
118 	//Create general tab.
119     tabGeneral=new GUIObject(imageManager,renderer,0,150,SCREEN_WIDTH,SCREEN_HEIGHT);
120 	GUIObjectRoot->addChild(tabGeneral);
121 
122 	//Now we create GUIObjects for every option.
123     GUIObject* obj=new GUILabel(imageManager,renderer,column1X,0,columnW,36,_("Music"));
124 	tabGeneral->addChild(obj);
125 
126     musicSlider=new GUISlider(imageManager,renderer,column2X,0,columnW,36,atoi(getSettings()->getValue("music").c_str()),0,128,15);
127 	musicSlider->name="sldMusic";
128 	musicSlider->eventCallback=this;
129 	tabGeneral->addChild(musicSlider);
130 
131     obj=new GUILabel(imageManager,renderer,column1X,lineHeight,columnW,36,_("Sound"));
132 	tabGeneral->addChild(obj);
133 
134     soundSlider=new GUISlider(imageManager,renderer,column2X,lineHeight,columnW,36,atoi(getSettings()->getValue("sound").c_str()),0,128,15);
135 	soundSlider->name="sldSound";
136 	soundSlider->eventCallback=this;
137 	tabGeneral->addChild(soundSlider);
138 
139     obj=new GUILabel(imageManager,renderer,column1X,2*lineHeight,columnW,36,_("Resolution"));
140 	obj->name="lstResolution";
141 	tabGeneral->addChild(obj);
142 
143 	//Create list with many different resolutions.
144     resolutions = new GUISingleLineListBox(imageManager,renderer,column2X,2*lineHeight,columnW,36);
145 	resolutions->value=-1;
146 
147 	//Only get the resolution list if it hasn't been done before.
148 	if(resolutionList.empty()){
149 		resolutionList=getResolutionList();
150 	}
151 
152 	//Get current resolution from config file. Thus it can be user defined.
153 	currentRes.x=atoi(getSettings()->getValue("width").c_str());
154 	currentRes.y=atoi(getSettings()->getValue("height").c_str());
155 
156 	for(int i=0; i<(int)resolutionList.size();i++){
157 		//Create a string from width and height and then add it to list.
158 		ostringstream out;
159 		out << resolutionList[i].x << "x" << resolutionList[i].y;
160 		resolutions->addItem(out.str());
161 
162 		//Check if current resolution matches, select it.
163 		if(resolutionList[i].x==currentRes.x && resolutionList[i].y==currentRes.y){
164 			resolutions->value=i;
165 		}
166 	}
167 
168 	//Add current resolution if it isn't already in the list.
169 	if(resolutions->value==-1){
170 		ostringstream out;
171 		out << currentRes.x << "x" << currentRes.y;
172 		resolutions->addItem(out.str());
173 		resolutions->value=resolutions->item.size()-1;
174 	}
175 	lastRes=resolutions->value;
176 
177 	tabGeneral->addChild(resolutions);
178 
179     obj=new GUILabel(imageManager,renderer,column1X,3*lineHeight,columnW,36,_("Language"));
180 	tabGeneral->addChild(obj);
181 
182 	//Create GUI list with available languages.
183     langs = new GUISingleLineListBox(imageManager,renderer,column2X,3*lineHeight,columnW,36);
184 	langs->name="lstLanguages";
185 
186 	/// TRANSLATORS: as detect user's language automatically
187 	langs->addItem("",_("Auto-Detect"));
188 	langs->addItem("en","English");
189 
190 	//Get a list of every available language.
191 	set<tinygettext::Language> languages = dictionaryManager->get_languages();
192 	for (set<tinygettext::Language>::iterator s0 = languages.begin(); s0 != languages.end(); ++s0){
193 		//If language in loop is the same in config file, then select it
194 		if(getSettings()->getValue("lang")==s0->str()){
195 			lastLang=distance(languages.begin(),s0)+2;
196 		}
197 		//Add language in loop to list and listbox.
198 		langs->addItem(s0->str(),s0->get_name());
199 	}
200 
201 	//If Auto or English are selected.
202 	if(getSettings()->getValue("lang")==""){
203 		lastLang=0;
204 	}else if(getSettings()->getValue("lang")=="en"){
205 		lastLang=1;
206 	}
207 
208 	langs->value=lastLang;
209 	tabGeneral->addChild(langs);
210 
211     obj=new GUILabel(imageManager,renderer,column1X,4*lineHeight,columnW,36,_("Theme"));
212 	obj->name="theme";
213 	tabGeneral->addChild(obj);
214 
215 	//Create the theme option gui element.
216     theme=new GUISingleLineListBox(imageManager,renderer,column2X,4*lineHeight,columnW,36);
217 	theme->name="lstTheme";
218 
219 	//Vector containing the theme locations and names.
220 	vector<pair<string,string> > themes;
221 	vector<string> v=enumAllDirs(getUserPath(USER_DATA)+"themes/");
222 	for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
223 		string location=getUserPath(USER_DATA)+"themes/"+*i;
224 		themes.push_back(pair<string,string>(location,*i));
225 	}
226 	vector<string> v2=enumAllDirs(getDataPath()+"themes/");
227 	for(vector<string>::iterator i=v2.begin(); i!=v2.end(); ++i){
228 		string location=getDataPath()+"themes/"+*i;
229 		themes.push_back(pair<string,string>(location,*i));
230 	}
231 
232 	//Try to find the configured theme so we can display it.
233 	int value=-1;
234 	for(vector<pair<string,string> >::iterator i=themes.begin(); i!=themes.end(); ++i){
235 		if(i->first==themeName) {
236 			value=i-themes.begin();
237 		}
238 	}
239 	theme->addItems(themes);
240 	if(value==-1)
241 		value=theme->item.size()-1;
242 	theme->value=value;
243 	//NOTE: We call the event handling method to correctly set the themename.
244     GUIEventCallback_OnEvent(imageManager,renderer,"lstTheme",theme,GUIEventChange);
245 	theme->eventCallback=this;
246 	tabGeneral->addChild(theme);
247 
248 	//Proxy settings.
249     obj=new GUILabel(imageManager,renderer,column1X,5*lineHeight,columnW,36,_("Internet proxy"));
250 	obj->name="chkProxy";
251 	obj->eventCallback=this;
252 	tabGeneral->addChild(obj);
253     obj=new GUITextBox(imageManager,renderer,column2X,5*lineHeight,columnW,36,internetProxy.c_str());
254 	obj->name="txtProxy";
255 	obj->eventCallback=this;
256 	tabGeneral->addChild(obj);
257 
258     obj=new GUICheckBox(imageManager,renderer,column1X,6*lineHeight,columnW,36,_("Fullscreen"),fullscreen?1:0);
259 	obj->name="chkFullscreen";
260 	obj->eventCallback=this;
261 	tabGeneral->addChild(obj);
262 
263 	obj = new GUICheckBox(imageManager, renderer, column1X, 7 * lineHeight, columnW, 36, _("Quick record"), quickrec ? 1 : 0);
264 	obj->name = "chkQuickRec";
265 	obj->eventCallback = this;
266 	tabGeneral->addChild(obj);
267 
268     obj=new GUICheckBox(imageManager,renderer,column2X,6*lineHeight,columnW,36,_("Internet"),internet?1:0);
269 	obj->name="chkInternet";
270 	obj->eventCallback=this;
271 	tabGeneral->addChild(obj);
272 
273     obj=new GUICheckBox(imageManager,renderer,column2X,7*lineHeight,columnW,36,_("Fade transition"),fade?1:0);
274 	obj->name="chkFade";
275 	obj->eventCallback=this;
276 	tabGeneral->addChild(obj);
277 
278 	//Create the controls tab.
279     tabControls=inputMgr.showConfig(imageManager,renderer,SCREEN_HEIGHT-210);
280 	tabControls->top=140;
281 	tabControls->visible=false;
282 	GUIObjectRoot->addChild(tabControls);
283 
284 	//Save original keys.
285 	for(int i=0;i<INPUTMGR_MAX;i++){
286 		tmpKeys[i]=inputMgr.getKeyCode((InputManagerKeys)i,false);
287 		tmpAlternativeKeys[i]=inputMgr.getKeyCode((InputManagerKeys)i,true);
288 	}
289 
290 	//Create buttons.
291 	cmdBack = new GUIButton(imageManager, renderer, SCREEN_WIDTH*0.3, SCREEN_HEIGHT - 60, -1, 36, _("Cancel"), 0, true, true, GUIGravityCenter);
292 	cmdBack->name = "cmdBack";
293 	cmdBack->eventCallback = this;
294 	GUIObjectRoot->addChild(cmdBack);
295 
296 	cmdSave = new GUIButton(imageManager, renderer, SCREEN_WIDTH*0.7, SCREEN_HEIGHT - 60, -1, 36, _("Save Changes"), 0, true, true, GUIGravityCenter);
297 	cmdSave->name = "cmdSave";
298 	cmdSave->eventCallback = this;
299 	GUIObjectRoot->addChild(cmdSave);
300 }
301 
convertInt(int i)302 static string convertInt(int i){
303 	stringstream ss;
304 	ss << i;
305 	return ss.str();
306 }
307 
GUIEventCallback_OnEvent(ImageManager & imageManager,SDL_Renderer & renderer,std::string name,GUIObject * obj,int eventType)308 void Options::GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType){
309 	//Check what type of event it was.
310 	if(eventType==GUIEventClick){
311 		if(name=="cmdBack"){
312 			//Reset the key changes.
313 			for(int i=0;i<INPUTMGR_MAX;i++){
314 				inputMgr.setKeyCode((InputManagerKeys)i,tmpKeys[i],false);
315 				inputMgr.setKeyCode((InputManagerKeys)i,tmpAlternativeKeys[i],true);
316 			}
317 
318 			//Reset the music volume.
319 			getMusicManager()->setVolume(atoi(getSettings()->getValue("music").c_str()));
320 			Mix_Volume(-1,atoi(getSettings()->getValue("sound").c_str()));
321 
322 			//And goto the main menu.
323 			setNextState(STATE_MENU);
324 		}else if(name=="cmdSave"){
325 			//Save is pressed thus save
326 			char s[64];
327 			sprintf(s,"%d",soundSlider->value);
328 			getSettings()->setValue("sound",s);
329 			sprintf(s,"%d",musicSlider->value);
330 			getSettings()->setValue("music",s);
331 			getMusicManager()->setEnabled(musicSlider->value>0);
332 			Mix_Volume(-1,soundSlider->value);
333 			getSettings()->setValue("fullscreen",fullscreen?"1":"0");
334 			getSettings()->setValue("internet",internet?"1":"0");
335 			getSettings()->setValue("theme",themeName);
336 			getSettings()->setValue("fading",fade?"1":"0");
337 			getSettings()->setValue("quickrecord",quickrec?"1":"0");
338 			//Before loading the theme remove the previous one from the stack.
339 			objThemes.removeTheme();
340             loadTheme(imageManager,renderer,themeName);
341 			if(!useProxy)
342 				internetProxy.clear();
343 			getSettings()->setValue("internet-proxy",internetProxy);
344 			getSettings()->setValue("lang",langs->getName());
345 
346 			//Is resolution from the list or is it user defined in config file
347 			if(resolutions->value<(int)resolutionList.size()){
348 				getSettings()->setValue("width",convertInt(resolutionList[resolutions->value].x));
349 				getSettings()->setValue("height",convertInt(resolutionList[resolutions->value].y));
350 			}else{
351 				getSettings()->setValue("width",convertInt(currentRes.x));
352 				getSettings()->setValue("height",convertInt(currentRes.y));
353 			}
354 
355 			//Save the key configuration.
356 			inputMgr.saveConfig();
357 
358 			//Save the settings.
359 			saveSettings();
360 
361 			//Before we return check if some .
362             if(restartFlag || resolutions->value!=lastRes){
363 				//The resolution changed so we need to recreate the screen.
364 				if(!createScreen()){
365 					//Screen creation failed so set to safe settings.
366 					getSettings()->setValue("fullscreen","0");
367 					getSettings()->setValue("width",convertInt(resolutionList[lastRes].x));
368 					getSettings()->setValue("height",convertInt(resolutionList[lastRes].y));
369 
370 					if(!createScreen()){
371 						//Everything fails so quit.
372 						setNextState(STATE_EXIT);
373 						return;
374 					}
375 				}
376 
377 				//The screen is created, now load the (menu) theme.
378                 if(!loadTheme(imageManager,renderer,"")){
379 					//Loading the theme failed so quit.
380 					setNextState(STATE_EXIT);
381 					return;
382                 }
383             }
384 
385 			if(langs->value!=lastLang){
386 				//We set the language.
387 				language=langs->getName();
388 
389 				if (language.empty()) {
390 					// The language is set to auto-detect.
391 					FL_Locale *locale;
392 					FL_FindLocale(&locale, FL_MESSAGES);
393 
394 					language = locale->lang;
395 					if (locale->country != NULL){
396 						language += string("_") + string(locale->country);
397 					}
398 					if (locale->variant != NULL){
399 						language += string("@") + string(locale->variant);
400 					}
401 
402 					FL_FreeLocale(&locale);
403 				}
404 
405 				dictionaryManager->set_language(tinygettext::Language::from_name(language));
406 
407 #ifdef WIN32
408 				//Some ad-hoc fix for Windows since it accepts "zh-CN" but not "zh_CN"
409 				std::string language2;
410 				for (auto c : language) {
411 					if (isalnum(c)) language2.push_back(c);
412 					else if (c == '_') language2.push_back('-');
413 					else break;
414 				}
415 				const char* languagePtr = language2.c_str();
416 #else
417 				const char* languagePtr = language.c_str();
418 #endif
419 
420 				tfm::setLocale(languagePtr);
421 				setlocale(LC_TIME, languagePtr);
422 
423 				getLevelPackManager()->updateLanguage();
424 
425 				//And reload the font.
426 				if(!loadFonts()){
427 					//Loading failed so quit.
428 					setNextState(STATE_EXIT);
429 					return;
430 				}
431 			}
432 
433 			//Now return to the main menu.
434 			setNextState(STATE_MENU);
435 		}else if(name=="chkFullscreen"){
436 			fullscreen=obj->value?true:false;
437 
438 			//Check if fullscreen changed.
439 			if(fullscreen==getSettings()->getBoolValue("fullscreen")){
440 				//We disable the restart message flag.
441 				restartFlag=false;
442 			}else{
443 				//We set the restart message flag.
444 				restartFlag=true;
445 			}
446 
447 		}else if(name=="chkInternet"){
448 			internet=obj->value?true:false;
449 		}else if(name=="chkProxy"){
450 			useProxy=obj->value?true:false;
451 		}else if(name=="chkFade"){
452 			fade=obj->value?true:false;
453 		}else if(name=="chkQuickRec"){
454 			quickrec=obj->value?true:false;
455 		}
456 	}
457 	if(name=="lstTheme"){
458 		if(theme!=NULL && theme->value>=0 && theme->value<(int)theme->item.size()){
459 			//Convert the themeName to contain %DATA%, etc...
460 			themeName=compressFileName(theme->item[theme->value].first);
461 		}
462 	}else if(name=="txtProxy"){
463 		internetProxy=obj->caption;
464 
465 		//Check if the internetProxy field is empty.
466 		useProxy=!internetProxy.empty();
467 	}else if(name=="sldMusic"){
468 		getMusicManager()->setEnabled(musicSlider->value>0);
469 		getMusicManager()->setVolume(musicSlider->value);
470 	}else if(name=="sldSound"){
471 		Mix_Volume(-1,soundSlider->value);
472 		if(lastJumpSound==0){
473 			getSoundManager()->playSound("jump");
474 			lastJumpSound=15;
475 		}
476 	}
477 	if(name=="lstTabs"){
478 		if(obj->value==0){
479 			tabGeneral->visible=true;
480 			tabControls->visible=false;
481 		}else{
482 			tabGeneral->visible=false;
483 			tabControls->visible=true;
484 		}
485 	}
486 }
487 
handleEvents(ImageManager & imageManager,SDL_Renderer & renderer)488 void Options::handleEvents(ImageManager& imageManager, SDL_Renderer& renderer){
489 	//Check keyboard navigation.
490 	if (tabGeneral && tabGeneral->visible) {
491 		if (inputMgr.isKeyDownEvent(INPUTMGR_TAB)) {
492 			isKeyboardOnly = true;
493 			section = (section == 2) ? 3 : 2;
494 
495 			//Update selection.
496 			if (section == 2) {
497 				tabGeneral->selectNextControl(1, -1);
498 			} else {
499 				tabGeneral->setSelectedControl(-1);
500 			}
501 		}
502 		if (section == 2) {
503 			tabGeneral->handleKeyboardNavigationEvents(imageManager, renderer, UpDownFocus | ReturnControls | LeftRightControls);
504 		} else if (section == 3) {
505 			if (inputMgr.isKeyDownEvent(INPUTMGR_DOWN) || inputMgr.isKeyDownEvent(INPUTMGR_RIGHT)) {
506 				isKeyboardOnly = true;
507 				section2++;
508 				if (section2 > 3) section2 = 1;
509 			} else if (inputMgr.isKeyDownEvent(INPUTMGR_UP) || inputMgr.isKeyDownEvent(INPUTMGR_LEFT)) {
510 				isKeyboardOnly = true;
511 				section2--;
512 				if (section2 < 1) section2 = 3;
513 			}
514 			if (isKeyboardOnly && inputMgr.isKeyDownEvent(INPUTMGR_SELECT) && section == 3) {
515 				if (section2 == 1) {
516 					GUIEventCallback_OnEvent(imageManager, renderer, cmdBack->name, cmdBack, GUIEventClick);
517 				} else if (section2 == 2) {
518 					GUIEventCallback_OnEvent(imageManager, renderer, cmdSave->name, cmdSave, GUIEventClick);
519 				}
520 			}
521 		}
522 	}
523 
524 	//Process mouse event only when it's not keyboard only mode.
525 	if (!isKeyboardOnly) {
526 		//Get the x and y location of the mouse.
527 		int x, y;
528 		SDL_GetMouseState(&x, &y);
529 
530 		//Check icon.
531 		if (event.type == SDL_MOUSEMOTION || event.type == SDL_MOUSEBUTTONDOWN){
532 			if (y >= SCREEN_HEIGHT - 56 && y < SCREEN_HEIGHT - 8 && x >= SCREEN_WIDTH - 56)
533 				clearIconHower = true;
534 			else
535 				clearIconHower = false;
536 		}
537 	}
538 
539 	//Update highlight on keyboard only mode.
540 	if (isKeyboardOnly) {
541 		cmdBack->state = (section == 3 && section2 == 1) ? 1 : 0;
542 		cmdSave->state = (section == 3 && section2 == 2) ? 1 : 0;
543 		clearIconHower = (section == 3 && section2 == 3);
544 	}
545 
546 	if ((isKeyboardOnly ? inputMgr.isKeyDownEvent(INPUTMGR_SELECT) :
547 		(event.type == SDL_MOUSEBUTTONUP && event.button.button == SDL_BUTTON_LEFT)) && clearIconHower)
548 	{
549         if(msgBox(imageManager,renderer,_("Do you really want to reset level progress?"),MsgBoxYesNo,_("Warning"))==MsgBoxYes){
550 			//We delete the progress folder.
551 #ifdef WIN32
552 			removeDirectory((getUserPath()+"progress").c_str());
553 			createDirectory((getUserPath()+"progress").c_str());
554 #else
555 			removeDirectory((getUserPath(USER_DATA)+"/progress").c_str());
556 			createDirectory((getUserPath(USER_DATA)+"/progress").c_str());
557 #endif
558 			//Reset statistics.
559 			statsMgr.reloadCompletedLevelsAndAchievements();
560 		}
561 	}
562 
563 	//Check if we need to quit, if so enter the exit state.
564 	if(event.type==SDL_QUIT){
565 		setNextState(STATE_EXIT);
566 	}
567 
568 	//Check if the escape button is pressed, if so go back to the main menu.
569 	if (inputMgr.isKeyDownEvent(INPUTMGR_ESCAPE) && (tabControls == NULL || !tabControls->visible)) {
570 		setNextState(STATE_MENU);
571 	}
572 }
573 
logic(ImageManager &,SDL_Renderer &)574 void Options::logic(ImageManager&, SDL_Renderer&){
575 	//Increase the lastJumpSound variable if needed.
576 	if(lastJumpSound!=0){
577 		lastJumpSound--;
578 	}
579 }
580 
render(ImageManager &,SDL_Renderer & renderer)581 void Options::render(ImageManager&, SDL_Renderer& renderer){
582 	//Draw background.
583     objThemes.getBackground(true)->draw(renderer);
584 	objThemes.getBackground(true)->updateAnimation();
585 
586 	//Now render the title.
587     drawTitleTexture(SCREEN_WIDTH, *title, renderer);
588 
589 	//Check if an icon is selected/highlighted and draw tooltip
590 	if(clearIconHower){
591         const SDL_Rect texSize = rectFromTexture(*clearTooltip);
592         drawGUIBox(-2,SCREEN_HEIGHT-texSize.h-2,texSize.w+4,texSize.h+4,renderer,0xFFFFFFFF);
593         applyTexture(0,SCREEN_HEIGHT-texSize.h,clearTooltip,renderer);
594 	}
595 
596 	//Draw border of icon if it's keyboard only mode.
597 	if (isKeyboardOnly && clearIconHower) {
598 		drawGUIBox(SCREEN_WIDTH - 52, SCREEN_HEIGHT - 52, 40, 40, renderer, 0xFFFFFF40);
599 	}
600 
601 	//Draw icon.
602     applyTexture(SCREEN_WIDTH-48,SCREEN_HEIGHT-48,*clearIcon,renderer);
603 
604 	//NOTE: The rendering of the GUI is done in Main.
605 }
606 
resize(ImageManager & imageManager,SDL_Renderer & renderer)607 void Options::resize(ImageManager& imageManager, SDL_Renderer& renderer){
608 	//Recreate the gui to fit the new resolution.
609     createGUI(imageManager,renderer);
610 }
611