stk-code_catmod/src/states_screens/options_screen_input.cpp
2018-03-23 20:20:09 +08:00

366 lines
13 KiB
C++

// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009-2015 Marianne Gagnon
//
// This program 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.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "states_screens/options_screen_input.hpp"
#include "graphics/irr_driver.hpp"
#include "guiengine/CGUISpriteBank.hpp"
#include "guiengine/screen.hpp"
#include "guiengine/widget.hpp"
#include "guiengine/widgets/button_widget.hpp"
#include "guiengine/widgets/list_widget.hpp"
#include "guiengine/widgets/ribbon_widget.hpp"
#include "input/device_manager.hpp"
#include "input/gamepad_device.hpp"
#include "input/input_manager.hpp"
#include "io/file_manager.hpp"
#include "states_screens/options_screen_device.hpp"
#include "states_screens/options_screen_audio.hpp"
#include "states_screens/options_screen_video.hpp"
#include "states_screens/options_screen_ui.hpp"
#include "states_screens/dialogs/add_device_dialog.hpp"
#include "states_screens/dialogs/multitouch_settings_dialog.hpp"
#include "states_screens/state_manager.hpp"
#include "states_screens/user_screen.hpp"
#include "utils/string_utils.hpp"
#include "utils/translation.hpp"
#include <iostream>
#include <sstream>
#include <set>
#include <algorithm>
using namespace GUIEngine;
// -----------------------------------------------------------------------------
OptionsScreenInput::OptionsScreenInput() : Screen("options_input.stkgui")
{
} // OptionsScreenInput
// -----------------------------------------------------------------------------
void OptionsScreenInput::loadedFromFile()
{
video::ITexture* icon1 = irr_driver->getTexture( file_manager->getAsset(FileManager::GUI,"keyboard.png" ));
video::ITexture* icon2 = irr_driver->getTexture( file_manager->getAsset(FileManager::GUI,"gamepad.png" ));
video::ITexture* icon3 = irr_driver->getTexture( file_manager->getAsset(FileManager::GUI,"gamepad_off.png"));
m_icon_bank = new irr::gui::STKModifiedSpriteBank( GUIEngine::getGUIEnv() );
m_icon_bank->addTextureAsSprite(icon1);
m_icon_bank->addTextureAsSprite(icon2);
m_icon_bank->addTextureAsSprite(icon3);
// scale icons depending on screen resolution. the numbers below are a bit arbitrary
const int screen_width = irr_driver->getFrameSize().Width;
const float scale = 0.3f + 0.2f*std::max(0, screen_width - 640)/564.0f;
m_icon_bank->setScale(scale);
} // loadFromFile
// -----------------------------------------------------------------------------
void OptionsScreenInput::buildDeviceList()
{
GUIEngine::ListWidget* devices = this->getWidget<GUIEngine::ListWidget>("devices");
assert( devices != NULL );
assert( m_icon_bank != NULL );
devices->setIcons(m_icon_bank);
DeviceManager* device_manager = input_manager->getDeviceManager();
const int keyboard_config_count = device_manager->getKeyboardConfigAmount();
for (int i=0; i<keyboard_config_count; i++)
{
KeyboardConfig *config = device_manager->getKeyboardConfig(i);
std::ostringstream kbname;
kbname << "keyboard" << i;
const std::string internal_name = kbname.str();
if (config->isGamePadAndroid())
{
// since irrLicht's list widget has the nasty tendency to put the
// icons very close to the text, I'm adding spaces to compensate.
devices->addItem(internal_name, (core::stringw(" ") +
_("Gamepad")).c_str(), 1 /* icon */);
}
else
{
// since irrLicht's list widget has the nasty tendency to put the
// icons very close to the text, I'm adding spaces to compensate.
devices->addItem(internal_name, (core::stringw(" ") +
_("Keyboard %i", i)).c_str(), 0 /* icon */);
}
}
const int gpad_config_count = device_manager->getGamePadConfigAmount();
for (int i = 0; i < gpad_config_count; i++)
{
GamepadConfig *config = device_manager->getGamepadConfig(i);
// Don't display the configuration if a matching device is not available
if (config->isPlugged())
{
// since irrLicht's list widget has the nasty tendency to put the
// icons very close to the text, I'm adding spaces to compensate.
irr::core::stringw name = (" " + config->getName()).c_str();
if (config->getNumberOfDevices() > 1)
{
name += core::stringw(L" (x");
name += config->getNumberOfDevices();
name += core::stringw(L")");
}
std::ostringstream gpname;
gpname << "gamepad" << i;
const std::string internal_name = gpname.str();
const int icon = (config->isEnabled() ? 1 : 2);
devices->addItem(internal_name, name, icon);
} // if config->isPlugged
} // for i<gpad_config_count
MultitouchDevice* touch_device = device_manager->getMultitouchDevice();
if (touch_device != NULL)
{
devices->addItem("touch_device", (core::stringw(" ") +
_("Touch Device")).c_str(), 1);
}
} // buildDeviceList
// -----------------------------------------------------------------------------
void OptionsScreenInput::init()
{
Screen::init();
RibbonWidget* tabBar = this->getWidget<RibbonWidget>("options_choice");
assert(tabBar != NULL);
tabBar->select( "tab_controls", PLAYER_ID_GAME_MASTER );
tabBar->getRibbonChildren()[0].setTooltip( _("Graphics") );
tabBar->getRibbonChildren()[1].setTooltip( _("Audio") );
tabBar->getRibbonChildren()[2].setTooltip( _("User Interface") );
tabBar->getRibbonChildren()[3].setTooltip( _("Players") );
/*
DynamicRibbonWidget* devices = this->getWidget<DynamicRibbonWidget>("devices");
assert( devices != NULL );
*/
buildDeviceList();
//devices->updateItemDisplay();
/*
// trigger displaying bindings for default selected device
const std::string name2("devices");
eventCallback(devices, name2, PLAYER_ID_GAME_MASTER);
*/
// Disable adding keyboard configurations
bool in_game = StateManager::get()->getGameState() == GUIEngine::INGAME_MENU;
getWidget<ButtonWidget>("add_device")->setActive(!in_game);
} // init
// -----------------------------------------------------------------------------
void OptionsScreenInput::rebuildDeviceList()
{
/*
DynamicRibbonWidget* devices = this->getWidget<DynamicRibbonWidget>("devices");
assert( devices != NULL );
devices->clearItems();
buildDeviceList();
devices->updateItemDisplay();
*/
ListWidget* devices = this->getWidget<ListWidget>("devices");
assert( devices != NULL );
devices->clear();
buildDeviceList();
} // rebuildDeviceList
// -----------------------------------------------------------------------------
void OptionsScreenInput::eventCallback(Widget* widget, const std::string& name, const int playerID)
{
//const std::string& screen_name = this->getName();
if (name == "options_choice")
{
std::string selection = ((RibbonWidget*)widget)->getSelectionIDString(PLAYER_ID_GAME_MASTER);
Screen *screen = NULL;
if (selection == "tab_audio")
screen = OptionsScreenAudio::getInstance();
else if (selection == "tab_video")
screen = OptionsScreenVideo::getInstance();
else if (selection == "tab_players")
screen = TabbedUserScreen::getInstance();
//else if (selection == "tab_controls")
// screen = OptionsScreenInput::getInstance();
else if (selection == "tab_ui")
screen = OptionsScreenUI::getInstance();
if(screen)
StateManager::get()->replaceTopMostScreen(screen);
}
else if (name == "add_device")
{
new AddDeviceDialog();
}
else if (name == "back")
{
StateManager::get()->escapePressed();
}
else if (name == "devices")
{
ListWidget* devices = this->getWidget<ListWidget>("devices");
assert(devices != NULL);
const std::string& selection = devices->getSelectionInternalName();
if (selection.find("gamepad") != std::string::npos)
{
int i = -1, read = 0;
read = sscanf( selection.c_str(), "gamepad%i", &i );
if (read == 1 && i != -1)
{
OptionsScreenDevice::getInstance()->setDevice( input_manager->getDeviceManager()->getGamepadConfig(i) );
StateManager::get()->replaceTopMostScreen(OptionsScreenDevice::getInstance());
//updateInputButtons( input_manager->getDeviceList()->getGamepadConfig(i) );
}
else
{
Log::error("OptionsScreenInput", "Cannot read internal gamepad input device ID: %s",
selection.c_str());
}
}
else if (selection.find("keyboard") != std::string::npos)
{
int i = -1, read = 0;
read = sscanf( selection.c_str(), "keyboard%i", &i );
if (read == 1 && i != -1)
{
// updateInputButtons( input_manager->getDeviceList()->getKeyboardConfig(i) );
OptionsScreenDevice::getInstance()
->setDevice( input_manager->getDeviceManager()->getKeyboardConfig(i) );
StateManager::get()->replaceTopMostScreen(OptionsScreenDevice::getInstance());
}
else
{
Log::error("OptionsScreenInput", "Cannot read internal keyboard input device ID: %s",
selection.c_str());
}
}
else if (selection.find("touch_device") != std::string::npos)
{
// Don't edit multitouch settings during a race, because it needs
// to re-create all buttons to take an effect
if (StateManager::get()->getGameState() != GUIEngine::INGAME_MENU)
{
new MultitouchSettingsDialog(0.8f, 0.9f);
}
}
else
{
Log::error("OptionsScreenInput", "Cannot read internal input device ID: %s", selection.c_str());
}
}
} // eventCallback
// -----------------------------------------------------------------------------
void OptionsScreenInput::unloaded()
{
delete m_icon_bank;
m_icon_bank = NULL;
} // unloaded
// -----------------------------------------------------------------------------
void OptionsScreenInput::filterInput(Input::InputType type,
int deviceID,
int btnID,
int axisDir,
int value)
{
if (type == Input::IT_STICKMOTION || type == Input::IT_STICKBUTTON)
{
GamePadDevice* gamepad = input_manager->getDeviceManager()->getGamePadFromIrrID(deviceID);
if (gamepad != NULL && gamepad->getConfiguration() != NULL)
{
//printf("'%s'\n", gamepad->getConfiguration()->getName().c_str());
ListWidget* devices = this->getWidget<ListWidget>("devices");
assert(devices != NULL);
std::string internal_name;
const int gpad_config_count = input_manager->getDeviceManager()->getGamePadConfigAmount();
for (int i = 0; i < gpad_config_count; i++)
{
GamepadConfig *config = input_manager->getDeviceManager()->getGamepadConfig(i);
// Don't display the configuration if a matching device is not available
if (config == gamepad->getConfiguration())
{
std::ostringstream gpname;
gpname << "gamepad" << i;
internal_name = gpname.str();
}
}
if (internal_name.size() > 0 && abs(value) > Input::MAX_VALUE/2)
{
devices->markItemRed(internal_name.c_str());
m_highlights[internal_name] = 0.25f;
}
}
}
}
// -----------------------------------------------------------------------------
void OptionsScreenInput::onUpdate(float dt)
{
std::map<std::string, float>::iterator it;
for (it = m_highlights.begin(); it != m_highlights.end();)
{
it->second -= dt;
if (it->second < 0.0f)
{
ListWidget* devices = this->getWidget<ListWidget>("devices");
assert(devices != NULL);
devices->markItemRed(it->first.c_str(), false);
m_highlights.erase(it++);
}
else
{
it++;
}
}
//m_highlights[internal_name]
} // onUpdate