1 /*
2  * Copyright 2010-2014 OpenXcom Developers.
3  *
4  * This file is part of OpenXcom.
5  *
6  * OpenXcom 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  * OpenXcom 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 OpenXcom.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include "OptionsVideoState.h"
20 #include "../Engine/Game.h"
21 #include "../Resource/ResourcePack.h"
22 #include "../Engine/Language.h"
23 #include "../Engine/Palette.h"
24 #include "../Interface/TextButton.h"
25 #include "../Engine/Action.h"
26 #include "../Interface/Window.h"
27 #include "../Interface/Text.h"
28 #include "../Interface/TextEdit.h"
29 #include "../Interface/ToggleTextButton.h"
30 #include "../Engine/Options.h"
31 #include "../Engine/Screen.h"
32 #include "../Interface/ArrowButton.h"
33 #include "../Engine/CrossPlatform.h"
34 #include "../Engine/Logger.h"
35 #include "../Interface/ComboBox.h"
36 
37 namespace OpenXcom
38 {
39 
40 const std::string OptionsVideoState::GL_EXT = "OpenGL.shader";
41 const std::string OptionsVideoState::GL_FOLDER = "Shaders/";
42 const std::string OptionsVideoState::GL_STRING = "*";
43 
44 /**
45  * Initializes all the elements in the Video Options screen.
46  * @param game Pointer to the core game.
47  * @param origin Game section that originated this state.
48  */
OptionsVideoState(Game * game,OptionsOrigin origin)49 OptionsVideoState::OptionsVideoState(Game *game, OptionsOrigin origin) : OptionsBaseState(game, origin)
50 {
51 	setCategory(_btnVideo);
52 
53 	// Create objects
54 	_displaySurface = new InteractiveSurface(110, 32, 94, 18);
55 	_txtDisplayResolution = new Text(114, 9, 94, 8);
56 	_txtDisplayWidth = new TextEdit(this, 40, 17, 94, 26);
57 	_txtDisplayX = new Text(16, 17, 132, 26);
58 	_txtDisplayHeight = new TextEdit(this, 40, 17, 144, 26);
59 	_btnDisplayResolutionUp = new ArrowButton(ARROW_BIG_UP, 14, 14, 186, 18);
60 	_btnDisplayResolutionDown = new ArrowButton(ARROW_BIG_DOWN, 14, 14, 186, 36);
61 
62 	_txtLanguage = new Text(114, 9, 94, 52);
63 	_cbxLanguage = new ComboBox(this, 104, 16, 94, 62);
64 
65 	_txtFilter = new Text(114, 9, 206, 52);
66 	_cbxFilter = new ComboBox(this, 104, 16, 206, 62);
67 
68 	_txtMode = new Text(114, 9, 206, 22);
69 	_cbxDisplayMode = new ComboBox(this, 104, 16, 206, 32);
70 
71 	_txtGeoScale = new Text(114, 9, 94, 82);
72 	_cbxGeoScale = new ComboBox(this, 104, 16, 94, 92);
73 
74 	_txtBattleScale = new Text(114, 9, 94, 112);
75 	_cbxBattleScale = new ComboBox(this, 104, 16, 94, 122);
76 
77 	_txtOptions = new Text(114, 9, 206, 82);
78 	_btnLetterbox = new ToggleTextButton(104, 16, 206, 92);
79 	_btnLockMouse = new ToggleTextButton(104, 16, 206, 110);
80 
81 	// Get available fullscreen modes
82 	_res = SDL_ListModes(NULL, SDL_FULLSCREEN);
83 	if (_res != (SDL_Rect**)-1 && _res != (SDL_Rect**)0)
84 	{
85 		int i;
86 		_resCurrent = -1;
87 		for (i = 0; _res[i]; ++i)
88 		{
89 			if (_resCurrent == -1 &&
90 				((_res[i]->w == Options::displayWidth && _res[i]->h <= Options::displayHeight) || _res[i]->w < Options::displayWidth))
91 			{
92 				_resCurrent = i;
93 			}
94 		}
95 		_resAmount = i;
96 	}
97 	else
98 	{
99 		_resCurrent = -1;
100 		_resAmount = 0;
101 		_btnDisplayResolutionDown->setVisible(false);
102 		_btnDisplayResolutionUp->setVisible(false);
103 		Log(LOG_WARNING) << "Couldn't get display resolutions";
104 	}
105 
106 	add(_displaySurface);
107 	add(_txtDisplayResolution);
108 	add(_txtDisplayWidth);
109 	add(_txtDisplayX);
110 	add(_txtDisplayHeight);
111 	add(_btnDisplayResolutionUp);
112 	add(_btnDisplayResolutionDown);
113 
114 	add(_txtLanguage);
115 	add(_txtFilter);
116 
117 	add(_txtMode);
118 
119 	add(_txtOptions);
120 	add(_btnLetterbox);
121 	add(_btnLockMouse);
122 
123 
124     add(_cbxFilter);
125 	add(_cbxDisplayMode);
126 
127 	add(_txtBattleScale);
128 	add(_cbxBattleScale);
129 
130 	add(_txtGeoScale);
131 	add(_cbxGeoScale);
132 
133     add(_cbxLanguage);
134 	centerAllSurfaces();
135 
136 	// Set up objects
137 	_txtDisplayResolution->setColor(Palette::blockOffset(8)+10);
138 	_txtDisplayResolution->setText(tr("STR_DISPLAY_RESOLUTION"));
139 
140 	_displaySurface->setTooltip("STR_DISPLAY_RESOLUTION_DESC");
141 	_displaySurface->onMouseIn((ActionHandler)&OptionsVideoState::txtTooltipIn);
142 	_displaySurface->onMouseOut((ActionHandler)&OptionsVideoState::txtTooltipOut);
143 
144 	_txtDisplayWidth->setColor(Palette::blockOffset(15)-1);
145 	_txtDisplayWidth->setAlign(ALIGN_CENTER);
146 	_txtDisplayWidth->setBig();
147 	_txtDisplayWidth->setNumerical(true);
148 	_txtDisplayWidth->onChange((ActionHandler)&OptionsVideoState::txtDisplayWidthChange);
149 
150 	_txtDisplayX->setColor(Palette::blockOffset(15)-1);
151 	_txtDisplayX->setAlign(ALIGN_CENTER);
152 	_txtDisplayX->setBig();
153 	_txtDisplayX->setText(L"x");
154 
155 	_txtDisplayHeight->setColor(Palette::blockOffset(15)-1);
156 	_txtDisplayHeight->setAlign(ALIGN_CENTER);
157 	_txtDisplayHeight->setBig();
158 	_txtDisplayHeight->setNumerical(true);
159 	_txtDisplayHeight->onChange((ActionHandler)&OptionsVideoState::txtDisplayHeightChange);
160 
161 	std::wostringstream ssW, ssH;
162 	ssW << Options::displayWidth;
163 	ssH << Options::displayHeight;
164 	_txtDisplayWidth->setText(ssW.str());
165 	_txtDisplayHeight->setText(ssH.str());
166 
167 	_btnDisplayResolutionUp->setColor(Palette::blockOffset(15)-1);
168 	_btnDisplayResolutionUp->onMouseClick((ActionHandler)&OptionsVideoState::btnDisplayResolutionUpClick);
169 
170 	_btnDisplayResolutionDown->setColor(Palette::blockOffset(15)-1);
171 	_btnDisplayResolutionDown->onMouseClick((ActionHandler)&OptionsVideoState::btnDisplayResolutionDownClick);
172 
173 	_txtMode->setColor(Palette::blockOffset(8)+10);
174 	_txtMode->setText(tr("STR_DISPLAY_MODE"));
175 
176 	_txtOptions->setColor(Palette::blockOffset(8)+10);
177 	_txtOptions->setText(tr("STR_DISPLAY_OPTIONS"));
178 
179 	_btnLetterbox->setColor(Palette::blockOffset(15)-1);
180 	_btnLetterbox->setText(tr("STR_LETTERBOXED"));
181 	_btnLetterbox->setPressed(Options::keepAspectRatio);
182 	_btnLetterbox->onMouseClick((ActionHandler)&OptionsVideoState::btnLetterboxClick);
183 	_btnLetterbox->setTooltip("STR_LETTERBOXED_DESC");
184 	_btnLetterbox->onMouseIn((ActionHandler)&OptionsVideoState::txtTooltipIn);
185 	_btnLetterbox->onMouseOut((ActionHandler)&OptionsVideoState::txtTooltipOut);
186 
187 	_btnLockMouse->setColor(Palette::blockOffset(15)-1);
188 	_btnLockMouse->setText(tr("STR_LOCK_MOUSE"));
189 	_btnLockMouse->setPressed(Options::captureMouse == SDL_GRAB_ON);
190 	_btnLockMouse->onMouseClick((ActionHandler)&OptionsVideoState::btnLockMouseClick);
191 	_btnLockMouse->setTooltip("STR_LOCK_MOUSE_DESC");
192 	_btnLockMouse->onMouseIn((ActionHandler)&OptionsVideoState::txtTooltipIn);
193 	_btnLockMouse->onMouseOut((ActionHandler)&OptionsVideoState::txtTooltipOut);
194 
195 	_txtLanguage->setColor(Palette::blockOffset(8)+10);
196 	_txtLanguage->setText(tr("STR_DISPLAY_LANGUAGE"));
197 
198 	std::vector<std::wstring> names;
199 	Language::getList(_langs, names);
200     _cbxLanguage->setColor(Palette::blockOffset(15)-1);
201 	_cbxLanguage->setOptions(names);
202 	for (size_t i = 0; i < names.size(); ++i)
203 	{
204 		if (_langs[i] == Options::language)
205 		{
206 			_cbxLanguage->setSelected(i);
207 			break;
208 		}
209 	}
210     _cbxLanguage->onChange((ActionHandler)&OptionsVideoState::cbxLanguageChange);
211 	_cbxLanguage->setTooltip("STR_DISPLAY_LANGUAGE_DESC");
212 	_cbxLanguage->onMouseIn((ActionHandler)&OptionsVideoState::txtTooltipIn);
213 	_cbxLanguage->onMouseOut((ActionHandler)&OptionsVideoState::txtTooltipOut);
214 
215 	std::vector<std::wstring> filterNames;
216 	filterNames.push_back(tr("STR_DISABLED"));
217 	filterNames.push_back(L"Scale");
218 	filterNames.push_back(L"HQX");
219 	_filters.push_back("");
220 	_filters.push_back("");
221 	_filters.push_back("");
222 
223 #ifndef __NO_OPENGL
224 	std::vector<std::string> filters = CrossPlatform::getFolderContents(CrossPlatform::getDataFolder(GL_FOLDER), GL_EXT);
225 	for (std::vector<std::string>::iterator i = filters.begin(); i != filters.end(); ++i)
226 	{
227 		std::string file = (*i);
228 		std::string path = GL_FOLDER + file;
229 		std::string name = file.substr(0, file.length() - GL_EXT.length() - 1) + GL_STRING;
230 		filterNames.push_back(Language::fsToWstr(name));
231 		_filters.push_back(path);
232 	}
233 #endif
234 
235 	size_t selFilter = 0;
236 	if (Screen::isOpenGLEnabled())
237 	{
238 #ifndef __NO_OPENGL
239 		std::string path = Options::useOpenGLShader;
240 		for (size_t i = 0; i < _filters.size(); ++i)
241 		{
242 			if (_filters[i] == path)
243 			{
244 				selFilter = i;
245 			}
246 		}
247 #endif
248 	}
249 	else if (Options::useScaleFilter)
250 	{
251 		selFilter = 1;
252 	}
253 	else if (Options::useHQXFilter)
254 	{
255 		selFilter = 2;
256 	}
257 
258 	_txtFilter->setColor(Palette::blockOffset(8)+10);
259 	_txtFilter->setText(tr("STR_DISPLAY_FILTER"));
260 
261     _cbxFilter->setColor(Palette::blockOffset(15)-1);
262 	_cbxFilter->setOptions(filterNames);
263 	_cbxFilter->setSelected(selFilter);
264 	_cbxFilter->onChange((ActionHandler)&OptionsVideoState::cbxFilterChange);
265 	_cbxFilter->setTooltip("STR_DISPLAY_FILTER_DESC");
266 	_cbxFilter->onMouseIn((ActionHandler)&OptionsVideoState::txtTooltipIn);
267 	_cbxFilter->onMouseOut((ActionHandler)&OptionsVideoState::txtTooltipOut);
268 
269 
270 	std::vector<std::string> displayModes;
271 	displayModes.push_back("STR_WINDOWED");
272 	displayModes.push_back("STR_FULLSCREEN");
273 	displayModes.push_back("STR_BORDERLESS");
274 	displayModes.push_back("STR_RESIZABLE");
275 
276 	int displayMode = 0;
277 	if (Options::fullscreen)
278 		displayMode = 1;
279 	else if (Options::borderless)
280 		displayMode = 2;
281 	else if (Options::allowResize)
282 		displayMode = 3;
283 
284 	_cbxDisplayMode->setColor(Palette::blockOffset(15)-1);
285 	_cbxDisplayMode->setOptions(displayModes);
286 	_cbxDisplayMode->setSelected(displayMode);
287 	_cbxDisplayMode->onChange((ActionHandler)&OptionsVideoState::updateDisplayMode);
288 	_cbxDisplayMode->setTooltip("STR_DISPLAY_MODE_DESC");
289 	_cbxDisplayMode->onMouseIn((ActionHandler)&OptionsVideoState::txtTooltipIn);
290 	_cbxDisplayMode->onMouseOut((ActionHandler)&OptionsVideoState::txtTooltipOut);
291 
292 	_txtGeoScale->setColor(Palette::blockOffset(8)+10);
293 	_txtGeoScale->setText(tr("STR_GEOSCAPE_SCALE"));
294 
295 	std::vector<std::string> scales;
296 	scales.push_back("STR_ORIGINAL");
297 	scales.push_back("STR_1.5X");
298 	scales.push_back("STR_2X");
299 	scales.push_back("STR_THIRD_DISPLAY");
300 	scales.push_back("STR_HALF_DISPLAY");
301 	scales.push_back("STR_FULL_DISPLAY");
302 
303 	_cbxGeoScale->setColor(Palette::blockOffset(15)-1);
304 	_cbxGeoScale->setOptions(scales);
305 	_cbxGeoScale->setSelected(Options::geoscapeScale);
306 	_cbxGeoScale->onChange((ActionHandler)&OptionsVideoState::updateGeoscapeScale);
307 	_cbxGeoScale->setTooltip("STR_GEOSCAPESCALE_SCALE_DESC");
308 	_cbxGeoScale->onMouseIn((ActionHandler)&OptionsVideoState::txtTooltipIn);
309 	_cbxGeoScale->onMouseOut((ActionHandler)&OptionsVideoState::txtTooltipOut);
310 
311 	_txtBattleScale->setColor(Palette::blockOffset(8)+10);
312 	_txtBattleScale->setText(tr("STR_BATTLESCAPE_SCALE"));
313 
314 	_cbxBattleScale->setColor(Palette::blockOffset(15)-1);
315 	_cbxBattleScale->setOptions(scales);
316 	_cbxBattleScale->setSelected(Options::battlescapeScale);
317 	_cbxBattleScale->onChange((ActionHandler)&OptionsVideoState::updateBattlescapeScale);
318 	_cbxBattleScale->setTooltip("STR_BATTLESCAPE_SCALE_DESC");
319 	_cbxBattleScale->onMouseIn((ActionHandler)&OptionsVideoState::txtTooltipIn);
320 	_cbxBattleScale->onMouseOut((ActionHandler)&OptionsVideoState::txtTooltipOut);
321 
322 }
323 
324 /**
325  *
326  */
~OptionsVideoState()327 OptionsVideoState::~OptionsVideoState()
328 {
329 
330 }
331 
332 /**
333  * Selects a bigger display resolution.
334  * @param action Pointer to an action.
335  */
btnDisplayResolutionUpClick(Action *)336 void OptionsVideoState::btnDisplayResolutionUpClick(Action *)
337 {
338 	if (_resAmount == 0)
339 		return;
340 	if (_resCurrent <= 0)
341 	{
342 		_resCurrent = _resAmount-1;
343 	}
344 	else
345 	{
346 		_resCurrent--;
347 	}
348 	updateDisplayResolution();
349 }
350 
351 /**
352  * Selects a smaller display resolution.
353  * @param action Pointer to an action.
354  */
btnDisplayResolutionDownClick(Action *)355 void OptionsVideoState::btnDisplayResolutionDownClick(Action *)
356 {
357 	if (_resAmount == 0)
358 		return;
359 	if (_resCurrent >= _resAmount-1)
360 	{
361 		_resCurrent = 0;
362 	}
363 	else
364 	{
365 		_resCurrent++;
366 	}
367 	updateDisplayResolution();
368 }
369 
370 /**
371  * Updates the display resolution based on the selection.
372  */
updateDisplayResolution()373 void OptionsVideoState::updateDisplayResolution()
374 {
375 	std::wostringstream ssW, ssH;
376 	ssW << (int)_res[_resCurrent]->w;
377 	ssH << (int)_res[_resCurrent]->h;
378 	_txtDisplayWidth->setText(ssW.str());
379 	_txtDisplayHeight->setText(ssH.str());
380 
381 	Options::newDisplayWidth = _res[_resCurrent]->w;
382 	Options::newDisplayHeight = _res[_resCurrent]->h;
383 }
384 /**
385  * Changes the Display Width option.
386  * @param action Pointer to an action.
387  */
txtDisplayWidthChange(Action *)388 void OptionsVideoState::txtDisplayWidthChange(Action *)
389 {
390 	std::wstringstream ss;
391 	int width = 0;
392 	ss << std::dec << _txtDisplayWidth->getText();
393 	ss >> std::dec >> width;
394 	Options::newDisplayWidth = width;
395 	// Update resolution mode
396 	if (_res != (SDL_Rect**)-1 && _res != (SDL_Rect**)0)
397 	{
398 		int i;
399 		_resCurrent = -1;
400 		for (i = 0; _res[i]; ++i)
401 		{
402 			if (_resCurrent == -1 &&
403 				((_res[i]->w == Options::newDisplayWidth && _res[i]->h <= Options::newDisplayHeight) || _res[i]->w < Options::newDisplayWidth))
404 			{
405 				_resCurrent = i;
406 			}
407 		}
408 	}
409 }
410 
411 /**
412  * Changes the Display Height option.
413  * @param action Pointer to an action.
414  */
txtDisplayHeightChange(Action *)415 void OptionsVideoState::txtDisplayHeightChange(Action *)
416 {
417 	std::wstringstream ss;
418 	int height = 0;
419 	ss << std::dec << _txtDisplayHeight->getText();
420 	ss >> std::dec >> height;
421 	Options::newDisplayHeight = height;
422 	// Update resolution mode
423 	if (_res != (SDL_Rect**)-1 && _res != (SDL_Rect**)0)
424 	{
425 		int i;
426 		_resCurrent = -1;
427 		for (i = 0; _res[i]; ++i)
428 		{
429 			if (_resCurrent == -1 &&
430 				((_res[i]->w == Options::newDisplayWidth && _res[i]->h <= Options::newDisplayHeight) || _res[i]->w < Options::newDisplayWidth))
431 			{
432 				_resCurrent = i;
433 			}
434 		}
435 	}
436 }
437 
438 /**
439  * Changes the Language option.
440  * @param action Pointer to an action.
441  */
cbxLanguageChange(Action *)442 void OptionsVideoState::cbxLanguageChange(Action *)
443 {
444 	Options::language = _langs[_cbxLanguage->getSelected()];
445 }
446 
447 /**
448  * Changes the Filter options.
449  * @param action Pointer to an action.
450  */
cbxFilterChange(Action *)451 void OptionsVideoState::cbxFilterChange(Action *)
452 {
453 	switch (_cbxFilter->getSelected())
454 	{
455 	case 0:
456 		Options::newOpenGL = false;
457 		Options::newScaleFilter = false;
458 		Options::newHQXFilter = false;
459 		break;
460 	case 1:
461 		Options::newOpenGL = false;
462 		Options::newScaleFilter = true;
463 		Options::newHQXFilter = false;
464 		break;
465 	case 2:
466 		Options::newOpenGL = false;
467 		Options::newScaleFilter = false;
468 		Options::newHQXFilter = true;
469 		break;
470 	default:
471 		Options::newOpenGL = true;
472 		Options::newScaleFilter = false;
473 		Options::newHQXFilter = false;
474 		Options::newOpenGLShader = _filters[_cbxFilter->getSelected()];
475 		break;
476 	}
477 }
478 
479 /**
480  * Changes the Display Mode options.
481  * @param action Pointer to an action.
482  */
updateDisplayMode(Action *)483 void OptionsVideoState::updateDisplayMode(Action *)
484 {
485 	switch(_cbxDisplayMode->getSelected())
486 	{
487 	case 0:
488 		Options::fullscreen = false;
489 		Options::borderless = false;
490 		Options::allowResize = false;
491 		break;
492 	case 1:
493 		Options::fullscreen = true;
494 		Options::borderless = false;
495 		Options::allowResize = false;
496 		break;
497 	case 2:
498 		Options::fullscreen = false;
499 		Options::borderless = true;
500 		Options::allowResize = false;
501 		break;
502 	case 3:
503 		Options::fullscreen = false;
504 		Options::borderless = false;
505 		Options::allowResize = true;
506 		break;
507 	default:
508 		break;
509 	}
510 }
511 
512 /**
513  * Changes the Letterboxing option.
514  * @param action Pointer to an action.
515  */
btnLetterboxClick(Action *)516 void OptionsVideoState::btnLetterboxClick(Action *)
517 {
518 	Options::keepAspectRatio = _btnLetterbox->getPressed();
519 }
520 
521 /**
522  * Changes the Lock Mouse option.
523  * @param action Pointer to an action.
524  */
btnLockMouseClick(Action *)525 void OptionsVideoState::btnLockMouseClick(Action *)
526 {
527 	Options::captureMouse = (SDL_GrabMode)_btnLockMouse->getPressed();
528 	SDL_WM_GrabInput(Options::captureMouse);
529 }
530 
531 /**
532  * Changes the geoscape scale.
533  * @param action Pointer to an action.
534  */
updateGeoscapeScale(Action *)535 void OptionsVideoState::updateGeoscapeScale(Action *)
536 {
537 	Options::newGeoscapeScale = _cbxGeoScale->getSelected();
538 }
539 
540 /**
541  * Updates the Battlescape scale.
542  * @param action Pointer to an action.
543  */
updateBattlescapeScale(Action *)544 void OptionsVideoState::updateBattlescapeScale(Action *)
545 {
546 	Options::newBattlescapeScale = _cbxBattleScale->getSelected();
547 }
548 
549 /**
550  * Updates the scale.
551  * @param dX delta of X;
552  * @param dY delta of Y;
553  */
resize(int & dX,int & dY)554 void OptionsVideoState::resize(int &dX, int &dY)
555 {
556 	OptionsBaseState::resize(dX, dY);
557 	std::wostringstream ss;
558 	ss << Options::displayWidth;
559 	_txtDisplayWidth->setText(ss.str());
560 	ss.str(L"");
561 	ss << Options::displayHeight;
562 	_txtDisplayHeight->setText(ss.str());
563 }
564 
565 /**
566  * Takes care of any events from the core game engine.
567  * @param action Pointer to an action.
568  */
handle(Action * action)569 void OptionsVideoState::handle(Action *action)
570 {
571 	State::handle(action);
572 	if (action->getDetails()->key.keysym.sym == SDLK_g && (SDL_GetModState() & KMOD_CTRL) != 0)
573 	{
574 		_btnLockMouse->setPressed(Options::captureMouse == SDL_GRAB_ON);
575 	}
576 }
577 }
578