/*
* Copyright 2010-2013 OpenXcom Developers.
*
* This file is part of OpenXcom.
*
* OpenXcom is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenXcom is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenXcom. If not, see .
*/
#include "OptionsControlsState.h"
#include
#include "../Engine/Game.h"
#include "../Engine/Options.h"
#include "../Resource/ResourcePack.h"
#include "../Engine/Language.h"
#include "../Engine/Palette.h"
#include "../Interface/TextButton.h"
#include "../Interface/Window.h"
#include "../Interface/Text.h"
#include "../Interface/TextList.h"
#include "../Engine/Action.h"
#include "../Engine/Logger.h"
namespace OpenXcom
{
// Welp time for some ugly static code becuase C++
// is too much of a derp to initialize class arrays.
KeyOption OptionsControlsState::_controlsGeneral[] =
{{"keyOk", "STR_OK", SDLK_UNKNOWN},
{"keyCancel", "STR_CANCEL", SDLK_UNKNOWN},
{"keyScreenshot", "STR_SCREENSHOT", SDLK_UNKNOWN},
{"keyFps", "STR_FPS_COUNTER", SDLK_UNKNOWN}};
KeyOption OptionsControlsState::_controlsGeo[] =
{{"keyGeoLeft", "STR_ROTATE_LEFT", SDLK_UNKNOWN},
{"keyGeoRight", "STR_ROTATE_RIGHT", SDLK_UNKNOWN},
{"keyGeoUp", "STR_ROTATE_UP", SDLK_UNKNOWN},
{"keyGeoDown", "STR_ROTATE_DOWN", SDLK_UNKNOWN},
{"keyGeoZoomIn", "STR_ZOOM_IN", SDLK_UNKNOWN},
{"keyGeoZoomOut", "STR_ZOOM_OUT", SDLK_UNKNOWN},
{"keyGeoSpeed1", "STR_5_SECS", SDLK_UNKNOWN},
{"keyGeoSpeed2", "STR_1_MIN", SDLK_UNKNOWN},
{"keyGeoSpeed3", "STR_5_MINS", SDLK_UNKNOWN},
{"keyGeoSpeed4", "STR_30_MINS", SDLK_UNKNOWN},
{"keyGeoSpeed5", "STR_1_HOUR", SDLK_UNKNOWN},
{"keyGeoSpeed6", "STR_1_DAY", SDLK_UNKNOWN},
{"keyGeoIntercept", "STR_INTERCEPT", SDLK_UNKNOWN},
{"keyGeoBases", "STR_BASES", SDLK_UNKNOWN},
{"keyGeoGraphs", "STR_GRAPHS", SDLK_UNKNOWN},
{"keyGeoUfopedia", "STR_UFOPAEDIA_UC", SDLK_UNKNOWN},
{"keyGeoOptions", "STR_OPTIONS_UC", SDLK_UNKNOWN},
{"keyGeoFunding", "STR_FUNDING_UC", SDLK_UNKNOWN},
{"keyGeoToggleDetail", "STR_TOGGLE_COUNTRY_DETAIL", SDLK_UNKNOWN},
{"keyGeoToggleRadar", "STR_TOGGLE_RADAR_RANGES", SDLK_UNKNOWN},
{"keyQuickSave", "STR_QUICK_SAVE", SDLK_UNKNOWN},
{"keyQuickLoad", "STR_QUICK_LOAD", SDLK_UNKNOWN}};
KeyOption OptionsControlsState::_controlsBattle[] =
{{"keyBattleLeft", "STR_SCROLL_LEFT", SDLK_UNKNOWN},
{"keyBattleRight", "STR_SCROLL_RIGHT", SDLK_UNKNOWN},
{"keyBattleUp", "STR_SCROLL_UP", SDLK_UNKNOWN},
{"keyBattleDown", "STR_SCROLL_DOWN", SDLK_UNKNOWN},
{"keyBattleLevelUp", "STR_VIEW_LEVEL_ABOVE", SDLK_UNKNOWN},
{"keyBattleLevelDown", "STR_VIEW_LEVEL_BELOW", SDLK_UNKNOWN},
{"keyBattleCenterUnit", "STR_CENTER_SELECTED_UNIT", SDLK_UNKNOWN},
{"keyBattlePrevUnit", "STR_PREVIOUS_UNIT", SDLK_UNKNOWN},
{"keyBattleNextUnit", "STR_NEXT_UNIT", SDLK_UNKNOWN},
{"keyBattleDeselectUnit", "STR_DESELECT_UNIT", SDLK_UNKNOWN},
{"keyBattleInventory", "STR_INVENTORY", SDLK_UNKNOWN},
{"keyBattleMap", "STR_MINIMAP", SDLK_UNKNOWN},
{"keyBattleOptions", "STR_OPTIONS", SDLK_UNKNOWN},
{"keyBattleEndTurn", "STR_END_TURN", SDLK_UNKNOWN},
{"keyBattleAbort", "STR_ABORT_MISSION", SDLK_UNKNOWN},
{"keyBattleStats", "STR_UNIT_STATS", SDLK_UNKNOWN},
{"keyBattleKneel", "STR_KNEEL", SDLK_UNKNOWN},
{"keyBattleReload", "STR_RELOAD", SDLK_UNKNOWN},
{"keyBattlePersonalLighting", "STR_TOGGLE_PERSONAL_LIGHTING", SDLK_UNKNOWN},
{"keyBattleReserveNone", "STR_DONT_RESERVE_TUS", SDLK_UNKNOWN},
{"keyBattleReserveSnap", "STR_RESERVE_TUS_FOR_SNAP_SHOT", SDLK_UNKNOWN},
{"keyBattleReserveAimed", "STR_RESERVE_TUS_FOR_AIMED_SHOT", SDLK_UNKNOWN},
{"keyBattleReserveAuto", "STR_RESERVE_TUS_FOR_AUTO_SHOT", SDLK_UNKNOWN},
{"keyBattleReserveKneel", "STR_RESERVE_TUS_FOR_KNEEL", SDLK_UNKNOWN},
{"keyBattleZeroTUs", "STR_EXPEND_ALL_TIME_UNITS", SDLK_UNKNOWN},
{"keyBattleCenterEnemy1", "STR_CENTER_ON_ENEMY_1", SDLK_UNKNOWN},
{"keyBattleCenterEnemy2", "STR_CENTER_ON_ENEMY_2", SDLK_UNKNOWN},
{"keyBattleCenterEnemy3", "STR_CENTER_ON_ENEMY_3", SDLK_UNKNOWN},
{"keyBattleCenterEnemy4", "STR_CENTER_ON_ENEMY_4", SDLK_UNKNOWN},
{"keyBattleCenterEnemy5", "STR_CENTER_ON_ENEMY_5", SDLK_UNKNOWN},
{"keyBattleCenterEnemy6", "STR_CENTER_ON_ENEMY_6", SDLK_UNKNOWN},
{"keyBattleCenterEnemy7", "STR_CENTER_ON_ENEMY_7", SDLK_UNKNOWN},
{"keyBattleCenterEnemy8", "STR_CENTER_ON_ENEMY_8", SDLK_UNKNOWN},
{"keyBattleCenterEnemy9", "STR_CENTER_ON_ENEMY_9", SDLK_UNKNOWN},
{"keyBattleCenterEnemy10", "STR_CENTER_ON_ENEMY_10", SDLK_UNKNOWN},
{"keyBattleVoxelView", "STR_SAVE_VOXEL_VIEW", SDLK_UNKNOWN}};
/**
* Initializes all the elements in the Controls screen.
* @param game Pointer to the core game.
*/
OptionsControlsState::OptionsControlsState(Game *game) : State(game), _selected(-1), _selKey(0)
{
_countGeneral = 4;
_countGeo = 20;
_countBattle = 36;
if (Options::getInt("autosave") == 1)
_countGeo += 2; // You can tune quick save/load hotkeys only if you choose autosave in the advanced options.
// Create objects
_window = new Window(this, 320, 200, 0, 0, POPUP_BOTH);
_btnOk = new TextButton(148, 16, 8, 176);
_btnCancel = new TextButton(148, 16, 164, 176);
_txtTitle = new Text(310, 16, 5, 8);
_lstControls = new TextList(288, 136, 8, 30);
add(_window);
add(_btnOk);
add(_btnCancel);
add(_txtTitle);
add(_lstControls);
centerAllSurfaces();
// Set up objects
_window->setColor(Palette::blockOffset(8)+5);
_window->setBackground(game->getResourcePack()->getSurface("BACK01.SCR"));
_btnOk->setColor(Palette::blockOffset(8)+5);
_btnOk->setText(_game->getLanguage()->getString("STR_OK"));
_btnOk->onMouseClick((ActionHandler)&OptionsControlsState::btnOkClick);
_btnOk->onKeyboardPress((ActionHandler)&OptionsControlsState::btnOkClick, (SDLKey)Options::getInt("keyOk"));
_btnCancel->setColor(Palette::blockOffset(8)+5);
_btnCancel->setText(_game->getLanguage()->getString("STR_CANCEL_UC"));
_btnCancel->onMouseClick((ActionHandler)&OptionsControlsState::btnCancelClick);
_btnCancel->onKeyboardPress((ActionHandler)&OptionsControlsState::btnCancelClick, (SDLKey)Options::getInt("keyCancel"));
_txtTitle->setColor(Palette::blockOffset(15)-1);
_txtTitle->setBig();
_txtTitle->setAlign(ALIGN_CENTER);
_txtTitle->setText(_game->getLanguage()->getString("STR_CONTROLS"));
_lstControls->setColor(Palette::blockOffset(8)+10);
_lstControls->setArrowColor(Palette::blockOffset(8)+5);
_lstControls->setColumns(2, 168, 120);
_lstControls->setSelectable(true);
_lstControls->setBackground(_window);
_lstControls->setMargin(8);
_lstControls->onMouseClick((ActionHandler)&OptionsControlsState::lstControlsClick, 0);
_lstControls->onKeyboardPress((ActionHandler)&OptionsControlsState::lstControlsKeyPress);
_lstControls->focus();
_lstControls->addRow(2, _game->getLanguage()->getString("STR_GENERAL").c_str(), L"");
_lstControls->setCellColor(0, 0, Palette::blockOffset(15)-1);
addControls(_controlsGeneral, _countGeneral);
_lstControls->addRow(2, L"", L"");
_lstControls->addRow(2, _game->getLanguage()->getString("STR_GEOSCAPE").c_str(), L"");
_lstControls->setCellColor(_countGeneral + 2, 0, Palette::blockOffset(15)-1);
addControls(_controlsGeo, _countGeo);
_lstControls->addRow(2, L"", L"");
_lstControls->addRow(2, _game->getLanguage()->getString("STR_BATTLESCAPE").c_str(), L"");
_lstControls->setCellColor(_countGeneral + 2 + _countGeo + 2, 0, Palette::blockOffset(15)-1);
addControls(_controlsBattle, _countBattle);
}
/**
*
*/
OptionsControlsState::~OptionsControlsState()
{
}
/**
* Uppercases all the words in a string.
* @param str Source string.
* @return Destination string.
*/
std::string OptionsControlsState::ucWords(std::string str)
{
if (!str.empty())
{
str[0] = toupper(str[0]);
}
for (size_t i = str.find_first_of(' '); i != std::string::npos; i = str.find_first_of(' ', i+1))
{
if (str.length() > i+1)
str[i+1] = toupper(str[i+1]);
else
break;
}
return str;
}
/**
* Adds a bunch of controls to the list.
* @param keys Array of controls.
* @param count Number of controls.
*/
void OptionsControlsState::addControls(KeyOption keys[], int count)
{
for (int i = 0; i < count; ++i)
{
keys[i].key = (SDLKey)Options::getInt(keys[i].option);
std::wstring name = _game->getLanguage()->getString(keys[i].name);
std::wstring key = Language::utf8ToWstr(ucWords(SDL_GetKeyName(keys[i].key)));
if (keys[i].key == SDLK_UNKNOWN)
key = L"";
_lstControls->addRow(2, name.c_str(), key.c_str());
}
}
/**
* Saves the controls.
* @param action Pointer to an action.
*/
void OptionsControlsState::btnOkClick(Action *)
{
for (int i = 0; i < _countGeneral; ++i)
{
Options::setInt(_controlsGeneral[i].option, _controlsGeneral[i].key);
}
for (int i = 0; i < _countGeo; ++i)
{
Options::setInt(_controlsGeo[i].option, _controlsGeo[i].key);
}
for (int i = 0; i < _countBattle; ++i)
{
Options::setInt(_controlsBattle[i].option, _controlsBattle[i].key);
}
Options::save();
_game->popState();
}
/**
* Returns to the previous screen.
* @param action Pointer to an action.
*/
void OptionsControlsState::btnCancelClick(Action *)
{
_game->popState();
}
/**
* Select a control for setting.
* @param action Pointer to an action.
*/
void OptionsControlsState::lstControlsClick(Action *action)
{
if (_selected != -1)
{
int selected = _selected;
_lstControls->setCellColor(_selected, 0, Palette::blockOffset(8)+10);
_lstControls->setCellColor(_selected, 1, Palette::blockOffset(8)+10);
_selected = -1;
_selKey = 0;
if (selected == _lstControls->getSelectedRow())
return;
}
_selected = _lstControls->getSelectedRow();
if (_selected > 0 && _selected <= _countGeneral)
{
_selKey = &_controlsGeneral[_selected - 1];
}
else if (_selected > _countGeneral + 2 && _selected <= _countGeneral + 2 + _countGeo)
{
_selKey = &_controlsGeo[_selected - 1 - _countGeneral - 2];
}
else if (_selected > _countGeneral + 2 + _countGeo + 2 && _selected <= _countGeneral + 2 + _countGeo + 2 + _countBattle)
{
_selKey = &_controlsBattle[_selected - 1 - _countGeneral - 2 - _countGeo - 2];
}
else
{
_selected = -1;
_selKey = 0;
return;
}
if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
{
_lstControls->setCellColor(_selected, 0, Palette::blockOffset(8)+5);
_lstControls->setCellColor(_selected, 1, Palette::blockOffset(8)+5);
}
else if (action->getDetails()->button.button == SDL_BUTTON_RIGHT)
{
_lstControls->setCellText(_selected, 1, L"");
_selKey->key = SDLK_UNKNOWN;
_selected = -1;
_selKey = 0;
}
}
/**
* Change selected control.
* @param action Pointer to an action.
*/
void OptionsControlsState::lstControlsKeyPress(Action *action)
{
if (_selected != -1)
{
SDLKey key = action->getDetails()->key.keysym.sym;
if (key != 0)
{
_selKey->key = key;
std::wstring name = Language::utf8ToWstr(ucWords(SDL_GetKeyName(_selKey->key)));
_lstControls->setCellText(_selected, 1, name);
}
_lstControls->setCellColor(_selected, 0, Palette::blockOffset(8)+10);
_lstControls->setCellColor(_selected, 1, Palette::blockOffset(8)+10);
_selected = -1;
_selKey = 0;
}
}
}