1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-29 21:56:54 +02:00

Merge pull request #2078 from IvanSavenko/shortcuts

Basic shortcuts system
This commit is contained in:
Ivan Savenko 2023-05-01 21:45:52 +03:00 committed by GitHub
commit 916b41d9a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 1061 additions and 627 deletions

View File

@ -174,7 +174,7 @@ TSubgoal CollectRes::whatToDoToTrade()
const IMarket * m = markets.back();
//attempt trade at back (best prices)
int howManyCanWeBuy = 0;
for (auto i = EGameResID::WOOD; i <= EGameResID::GOLD; vstd::advance(i, 1))
for (GameResID i = EGameResID::WOOD; i <= EGameResID::GOLD; ++i)
{
if (GameResID(i) == resID)
continue;

View File

@ -543,10 +543,12 @@ namespace vstd
});
}
/// Increments value by specific delta
/// similar to std::next but works with other types, e.g. enum class
template<typename T>
void advance(T &obj, int change)
T next(const T &obj, int change)
{
obj = (T)(((int)obj) + change);
return static_cast<T>(static_cast<ptrdiff_t>(obj) + change);
}
template <typename Container>

View File

@ -31,6 +31,7 @@ set(client_SRCS
gui/CursorHandler.cpp
gui/InterfaceObjectConfigurable.cpp
gui/NotificationHandler.cpp
gui/ShortcutHandler.cpp
lobby/CBonusSelection.cpp
lobby/CCampaignInfoScreen.cpp
@ -159,6 +160,8 @@ set(client_HEADERS
gui/InterfaceObjectConfigurable.h
gui/MouseButton.h
gui/NotificationHandler.h
gui/Shortcut.h
gui/ShortcutHandler.h
gui/TextAlignment.h
lobby/CBonusSelection.h

View File

@ -33,6 +33,7 @@
#include "../gui/CursorHandler.h"
#include "../render/IImage.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../widgets/TextControls.h"
#include "../widgets/Buttons.h"
#include "../windows/settings/SettingsMainWindow.h"
@ -95,7 +96,7 @@ CAdventureMapInterface::CAdventureMapInterface():
gems.push_back(std::make_shared<CAnimImage>(ADVOPT.gemG[g], 0, 0, ADVOPT.gemX[g], ADVOPT.gemY[g]));
}
auto makeButton = [&](int textID, std::function<void()> callback, config::ButtonInfo info, int key) -> std::shared_ptr<CButton>
auto makeButton = [&](int textID, std::function<void()> callback, config::ButtonInfo info, EShortcut key) -> std::shared_ptr<CButton>
{
auto button = std::make_shared<CButton>(Point(info.x, info.y), info.defName, CGI->generaltexth->zelp[textID], callback, key, info.playerColoured);
for(auto image : info.additionalDefs)
@ -103,16 +104,16 @@ CAdventureMapInterface::CAdventureMapInterface():
return button;
};
kingOverview = makeButton(293, std::bind(&CAdventureMapInterface::fshowOverview,this), ADVOPT.kingOverview, SDLK_k);
underground = makeButton(294, std::bind(&CAdventureMapInterface::fswitchLevel,this), ADVOPT.underground, SDLK_u);
questlog = makeButton(295, std::bind(&CAdventureMapInterface::fshowQuestlog,this), ADVOPT.questlog, SDLK_q);
sleepWake = makeButton(296, std::bind(&CAdventureMapInterface::fsleepWake,this), ADVOPT.sleepWake, SDLK_w);
moveHero = makeButton(297, std::bind(&CAdventureMapInterface::fmoveHero,this), ADVOPT.moveHero, SDLK_m);
spellbook = makeButton(298, std::bind(&CAdventureMapInterface::fshowSpellbok,this), ADVOPT.spellbook, SDLK_c);
advOptions = makeButton(299, std::bind(&CAdventureMapInterface::fadventureOPtions,this), ADVOPT.advOptions, SDLK_a);
sysOptions = makeButton(300, std::bind(&CAdventureMapInterface::fsystemOptions,this), ADVOPT.sysOptions, SDLK_o);
nextHero = makeButton(301, std::bind(&CAdventureMapInterface::fnextHero,this), ADVOPT.nextHero, SDLK_h);
endTurn = makeButton(302, std::bind(&CAdventureMapInterface::fendTurn,this), ADVOPT.endTurn, SDLK_e);
kingOverview = makeButton(293, std::bind(&CAdventureMapInterface::fshowOverview,this), ADVOPT.kingOverview, EShortcut::ADVENTURE_KINGDOM_OVERVIEW);
underground = makeButton(294, std::bind(&CAdventureMapInterface::fswitchLevel,this), ADVOPT.underground, EShortcut::ADVENTURE_TOGGLE_MAP_LEVEL);
questlog = makeButton(295, std::bind(&CAdventureMapInterface::fshowQuestlog,this), ADVOPT.questlog, EShortcut::ADVENTURE_QUEST_LOG);
sleepWake = makeButton(296, std::bind(&CAdventureMapInterface::fsleepWake,this), ADVOPT.sleepWake, EShortcut::ADVENTURE_TOGGLE_SLEEP);
moveHero = makeButton(297, std::bind(&CAdventureMapInterface::fmoveHero,this), ADVOPT.moveHero, EShortcut::ADVENTURE_MOVE_HERO);
spellbook = makeButton(298, std::bind(&CAdventureMapInterface::fshowSpellbok,this), ADVOPT.spellbook, EShortcut::ADVENTURE_CAST_SPELL);
advOptions = makeButton(299, std::bind(&CAdventureMapInterface::fadventureOPtions,this), ADVOPT.advOptions, EShortcut::ADVENTURE_GAME_OPTIONS);
sysOptions = makeButton(300, std::bind(&CAdventureMapInterface::fsystemOptions,this), ADVOPT.sysOptions, EShortcut::GLOBAL_OPTIONS);
nextHero = makeButton(301, std::bind(&CAdventureMapInterface::fnextHero,this), ADVOPT.nextHero, EShortcut::ADVENTURE_NEXT_HERO);
endTurn = makeButton(302, std::bind(&CAdventureMapInterface::fendTurn,this), ADVOPT.endTurn, EShortcut::ADVENTURE_END_TURN);
int panelSpaceBottom = GH.screenDimensions().y - resdatabar->pos.h - 4;
@ -139,7 +140,7 @@ CAdventureMapInterface::CAdventureMapInterface():
worldViewBackConfig.y = 343 + 195;
worldViewBackConfig.playerColoured = false;
panelWorldView->addChildToPanel(
makeButton(288, std::bind(&CAdventureMapInterface::fworldViewBack,this), worldViewBackConfig, SDLK_ESCAPE), ACTIVATE | DEACTIVATE);
makeButton(288, std::bind(&CAdventureMapInterface::fworldViewBack,this), worldViewBackConfig, EShortcut::GLOBAL_CANCEL), ACTIVATE | DEACTIVATE);
config::ButtonInfo worldViewPuzzleConfig = config::ButtonInfo();
worldViewPuzzleConfig.defName = "VWPUZ.DEF";
@ -148,7 +149,7 @@ CAdventureMapInterface::CAdventureMapInterface():
worldViewPuzzleConfig.playerColoured = false;
panelWorldView->addChildToPanel( // no help text for this one
std::make_shared<CButton>(Point(worldViewPuzzleConfig.x, worldViewPuzzleConfig.y), worldViewPuzzleConfig.defName, std::pair<std::string, std::string>(),
std::bind(&CPlayerInterface::showPuzzleMap,LOCPLINT), SDLK_p, worldViewPuzzleConfig.playerColoured), ACTIVATE | DEACTIVATE);
std::bind(&CPlayerInterface::showPuzzleMap,LOCPLINT), EShortcut::ADVENTURE_VIEW_PUZZLE, worldViewPuzzleConfig.playerColoured), ACTIVATE | DEACTIVATE);
config::ButtonInfo worldViewScale1xConfig = config::ButtonInfo();
worldViewScale1xConfig.defName = "VWMAG1.DEF";
@ -156,7 +157,7 @@ CAdventureMapInterface::CAdventureMapInterface():
worldViewScale1xConfig.y = 23 + 195;
worldViewScale1xConfig.playerColoured = false;
panelWorldView->addChildToPanel( // help text is wrong for this button
makeButton(291, std::bind(&CAdventureMapInterface::fworldViewScale1x,this), worldViewScale1xConfig, SDLK_1), ACTIVATE | DEACTIVATE);
makeButton(291, std::bind(&CAdventureMapInterface::fworldViewScale1x,this), worldViewScale1xConfig, EShortcut::SELECT_INDEX_1), ACTIVATE | DEACTIVATE);
config::ButtonInfo worldViewScale2xConfig = config::ButtonInfo();
worldViewScale2xConfig.defName = "VWMAG2.DEF";
@ -164,7 +165,7 @@ CAdventureMapInterface::CAdventureMapInterface():
worldViewScale2xConfig.y = 23 + 195;
worldViewScale2xConfig.playerColoured = false;
panelWorldView->addChildToPanel( // help text is wrong for this button
makeButton(291, std::bind(&CAdventureMapInterface::fworldViewScale2x,this), worldViewScale2xConfig, SDLK_2), ACTIVATE | DEACTIVATE);
makeButton(291, std::bind(&CAdventureMapInterface::fworldViewScale2x,this), worldViewScale2xConfig, EShortcut::SELECT_INDEX_2), ACTIVATE | DEACTIVATE);
config::ButtonInfo worldViewScale4xConfig = config::ButtonInfo();
worldViewScale4xConfig.defName = "VWMAG4.DEF";
@ -172,7 +173,7 @@ CAdventureMapInterface::CAdventureMapInterface():
worldViewScale4xConfig.y = 23 + 195;
worldViewScale4xConfig.playerColoured = false;
panelWorldView->addChildToPanel( // help text is wrong for this button
makeButton(291, std::bind(&CAdventureMapInterface::fworldViewScale4x,this), worldViewScale4xConfig, SDLK_4), ACTIVATE | DEACTIVATE);
makeButton(291, std::bind(&CAdventureMapInterface::fworldViewScale4x,this), worldViewScale4xConfig, EShortcut::SELECT_INDEX_4), ACTIVATE | DEACTIVATE);
config::ButtonInfo worldViewUndergroundConfig = config::ButtonInfo();
worldViewUndergroundConfig.defName = "IAM010.DEF";
@ -180,7 +181,7 @@ CAdventureMapInterface::CAdventureMapInterface():
worldViewUndergroundConfig.x = GH.screenDimensions().x - 115;
worldViewUndergroundConfig.y = 343 + 195;
worldViewUndergroundConfig.playerColoured = true;
worldViewUnderground = makeButton(294, std::bind(&CAdventureMapInterface::fswitchLevel,this), worldViewUndergroundConfig, SDLK_u);
worldViewUnderground = makeButton(294, std::bind(&CAdventureMapInterface::fswitchLevel,this), worldViewUndergroundConfig, EShortcut::ADVENTURE_TOGGLE_MAP_LEVEL);
panelWorldView->addChildColorableButton(worldViewUnderground);
onCurrentPlayerChanged(LOCPLINT->playerID);
@ -392,7 +393,6 @@ void CAdventureMapInterface::updateButtons()
{
bool state = LOCPLINT->localState->isHeroSleeping(hero);
sleepWake->setIndex(state ? 1 : 0, true);
sleepWake->assignedKeys = {state ? SDLK_w : SDLK_z};
sleepWake->redraw();
}
}
@ -607,17 +607,20 @@ void CAdventureMapInterface::centerOnObject(const CGObjectInstance * obj)
terrain->onCenteredObject(obj);
}
void CAdventureMapInterface::keyPressed(const SDL_Keycode & key)
void CAdventureMapInterface::keyPressed(EShortcut key)
{
if (state != EGameState::MAKING_TURN)
return;
//fake mouse use to trigger onTileHovered()
GH.fakeMouseMove();
const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero(); //selected hero
const CGTownInstance *t = LOCPLINT->localState->getCurrentTown(); //selected town
switch(key)
{
case SDLK_g:
case EShortcut::ADVENTURE_THIEVES_GUILD:
if(GH.topInt()->type & BLOCK_ADV_HOTKEYS)
return;
@ -634,40 +637,40 @@ void CAdventureMapInterface::keyPressed(const SDL_Keycode & key)
LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithTavern"));
}
return;
case SDLK_i:
case EShortcut::ADVENTURE_VIEW_SCENARIO:
if(isActive())
CAdventureOptions::showScenarioInfo();
return;
case SDLK_s:
case EShortcut::GAME_SAVE_GAME:
if(isActive())
GH.pushIntT<CSavingScreen>();
return;
case SDLK_l:
case EShortcut::GAME_LOAD_GAME:
if(isActive())
LOCPLINT->proposeLoadingGame();
return;
case SDLK_d:
case EShortcut::ADVENTURE_DIG_GRAIL:
{
if(h && isActive() && LOCPLINT->makingTurn)
LOCPLINT->tryDiggging(h);
return;
}
case SDLK_p:
case EShortcut::ADVENTURE_VIEW_PUZZLE:
if(isActive())
LOCPLINT->showPuzzleMap();
return;
case SDLK_v:
case EShortcut::ADVENTURE_VIEW_WORLD:
if(isActive())
LOCPLINT->viewWorldMap();
return;
case SDLK_r:
case EShortcut::GAME_RESTART_GAME:
if(isActive() && GH.isKeyboardCtrlDown())
{
LOCPLINT->showYesNoDialog(CGI->generaltexth->translate("vcmi.adventureMap.confirmRestartGame"),
[](){ GH.pushUserEvent(EUserEvent::RESTART_GAME); }, nullptr);
}
return;
case SDLK_SPACE: //space - try to revisit current object with selected hero
case EShortcut::ADVENTURE_VISIT_OBJECT: //space - try to revisit current object with selected hero
{
if(!isActive())
return;
@ -677,7 +680,7 @@ void CAdventureMapInterface::keyPressed(const SDL_Keycode & key)
}
}
return;
case SDLK_RETURN:
case EShortcut::ADVENTURE_VIEW_SELECTED:
{
if(!isActive() || !LOCPLINT->localState->getCurrentArmy())
return;
@ -687,7 +690,7 @@ void CAdventureMapInterface::keyPressed(const SDL_Keycode & key)
LOCPLINT->openTownWindow(t);
return;
}
case SDLK_ESCAPE:
case EShortcut::GLOBAL_CANCEL:
{
//FIXME: this case is never executed since AdvMapInt is disabled while in spellcasting mode
if(!isActive() || GH.topInt().get() != this || !spellBeingCasted)
@ -696,7 +699,7 @@ void CAdventureMapInterface::keyPressed(const SDL_Keycode & key)
abortCastingMode();
return;
}
case SDLK_t:
case EShortcut::GAME_OPEN_MARKETPLACE:
{
//act on key down if marketplace windows is not already opened
if(GH.topInt()->type & BLOCK_ADV_HOTKEYS)
@ -720,77 +723,55 @@ void CAdventureMapInterface::keyPressed(const SDL_Keycode & key)
else //if not - complain
LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithMarket"));
}
else if(isActive()) //no ctrl, advmapint is on the top => switch to town
case EShortcut::ADVENTURE_NEXT_TOWN:
if(isActive() && !GH.isKeyboardCtrlDown()) //no ctrl, advmapint is on the top => switch to town
{
townList->selectNext();
}
return;
}
case SDLK_LALT:
case SDLK_RALT:
{
//fake mouse use to trigger onTileHovered()
GH.fakeMouseMove();
return;
}
default:
{
auto direction = keyToMoveDirection(key);
if (!direction)
return;
if(!h || !isActive())
return;
if (CGI->mh->hasOngoingAnimations())
return;
if(*direction == Point(0,0))
{
centerOnObject(h);
return;
}
int3 dst = h->visitablePos() + int3(direction->x, direction->y, 0);
if (!CGI->mh->isInMap((dst)))
return;
if ( !LOCPLINT->localState->setPath(h, dst))
return;
const CGPath & path = LOCPLINT->localState->getPath(h);
if (path.nodes.size() > 2)
onHeroChanged(h);
else
if(!path.nodes[0].turns)
LOCPLINT->moveHero(h, path);
}
return;
case EShortcut::ADVENTURE_MOVE_HERO_SW: return hotkeyMoveHeroDirectional({-1, +1});
case EShortcut::ADVENTURE_MOVE_HERO_SS: return hotkeyMoveHeroDirectional({ 0, +1});
case EShortcut::ADVENTURE_MOVE_HERO_SE: return hotkeyMoveHeroDirectional({+1, +1});
case EShortcut::ADVENTURE_MOVE_HERO_WW: return hotkeyMoveHeroDirectional({-1, 0});
case EShortcut::ADVENTURE_MOVE_HERO_EE: return hotkeyMoveHeroDirectional({+1, 0});
case EShortcut::ADVENTURE_MOVE_HERO_NW: return hotkeyMoveHeroDirectional({-1, -1});
case EShortcut::ADVENTURE_MOVE_HERO_NN: return hotkeyMoveHeroDirectional({ 0, -1});
case EShortcut::ADVENTURE_MOVE_HERO_NE: return hotkeyMoveHeroDirectional({+1, -1});
}
}
std::optional<Point> CAdventureMapInterface::keyToMoveDirection(const SDL_Keycode & key)
void CAdventureMapInterface::hotkeyMoveHeroDirectional(Point direction)
{
switch (key) {
case SDLK_DOWN: return Point( 0, +1);
case SDLK_LEFT: return Point(-1, 0);
case SDLK_RIGHT: return Point(+1, 0);
case SDLK_UP: return Point( 0, -1);
const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero(); //selected hero
case SDLK_KP_1: return Point(-1, +1);
case SDLK_KP_2: return Point( 0, +1);
case SDLK_KP_3: return Point(+1, +1);
case SDLK_KP_4: return Point(-1, 0);
case SDLK_KP_5: return Point( 0, 0);
case SDLK_KP_6: return Point(+1, 0);
case SDLK_KP_7: return Point(-1, -1);
case SDLK_KP_8: return Point( 0, -1);
case SDLK_KP_9: return Point(+1, -1);
if(!h || !isActive())
return;
if (CGI->mh->hasOngoingAnimations())
return;
if(direction == Point(0,0))
{
centerOnObject(h);
return;
}
return std::nullopt;
int3 dst = h->visitablePos() + int3(direction.x, direction.y, 0);
if (!CGI->mh->isInMap((dst)))
return;
if ( !LOCPLINT->localState->setPath(h, dst))
return;
const CGPath & path = LOCPLINT->localState->getPath(h);
if (path.nodes.size() > 2)
onHeroChanged(h);
else
if(!path.nodes[0].turns)
LOCPLINT->moveHero(h, path);
}
void CAdventureMapInterface::onSelectionChanged(const CArmedInstance *sel)

View File

@ -116,6 +116,8 @@ private:
void fnextHero();
void fendTurn();
void hotkeyMoveHeroDirectional(Point direction);
bool isActive();
void adjustActiveness(bool aiTurnStart); //should be called every time at AI/human turn transition; blocks GUI during AI turn
@ -130,7 +132,7 @@ private:
const CGObjectInstance *getActiveObject(const int3 &tile);
std::optional<Point> keyToMoveDirection(const SDL_Keycode & key);
std::optional<Point> keyToMoveDirection(EShortcut key);
void endingTurn();
@ -149,7 +151,7 @@ protected:
void show(SDL_Surface * to) override;
void showAll(SDL_Surface * to) override;
void keyPressed(const SDL_Keycode & key) override;
void keyPressed(EShortcut key) override;
public:
CAdventureMapInterface();

View File

@ -17,6 +17,7 @@
#include "../lobby/CCampaignInfoScreen.h"
#include "../lobby/CScenarioInfoScreen.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../widgets/Buttons.h"
#include "../../CCallback.h"
@ -27,19 +28,18 @@ CAdventureOptions::CAdventureOptions()
{
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
viewWorld = std::make_shared<CButton>(Point(24, 23), "ADVVIEW.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_v);
viewWorld = std::make_shared<CButton>(Point(24, 23), "ADVVIEW.DEF", CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_WORLD);
viewWorld->addCallback( [] { LOCPLINT->viewWorldMap(); });
exit = std::make_shared<CButton>(Point(204, 313), "IOK6432.DEF", CButton::tooltip(), std::bind(&CAdventureOptions::close, this), SDLK_RETURN);
exit->assignedKeys.insert(SDLK_ESCAPE);
exit = std::make_shared<CButton>(Point(204, 313), "IOK6432.DEF", CButton::tooltip(), std::bind(&CAdventureOptions::close, this), EShortcut::GLOBAL_RETURN);
scenInfo = std::make_shared<CButton>(Point(24, 198), "ADVINFO.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_i);
scenInfo = std::make_shared<CButton>(Point(24, 198), "ADVINFO.DEF", CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_SCENARIO);
scenInfo->addCallback(CAdventureOptions::showScenarioInfo);
puzzle = std::make_shared<CButton>(Point(24, 81), "ADVPUZ.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_p);
puzzle = std::make_shared<CButton>(Point(24, 81), "ADVPUZ.DEF", CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_VIEW_PUZZLE);
puzzle->addCallback(std::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT));
dig = std::make_shared<CButton>(Point(24, 139), "ADVDIG.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_d);
dig = std::make_shared<CButton>(Point(24, 139), "ADVDIG.DEF", CButton::tooltip(), [&](){ close(); }, EShortcut::ADVENTURE_DIG_GRAIL);
if(const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero())
dig->addCallback(std::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h));
else

View File

@ -17,6 +17,7 @@
#include "../PlayerLocalState.h"
#include "../ClientCommandManager.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../render/Colors.h"
#include "../../CCallback.h"
@ -108,30 +109,29 @@ void CInGameConsole::print(const std::string & txt)
GH.totalRedraw(); // FIXME: ingame console has no parent widget set
}
void CInGameConsole::keyPressed (const SDL_Keycode & key)
void CInGameConsole::keyPressed (EShortcut key)
{
if (LOCPLINT->cingconsole != this)
return;
if(!captureAllKeys && key != SDLK_TAB)
if(!captureAllKeys && key != EShortcut::GAME_ACTIVATE_CONSOLE)
return; //because user is not entering any text
switch(key)
{
case SDLK_TAB:
case SDLK_ESCAPE:
{
if(captureAllKeys)
{
endEnteringText(false);
}
else if(SDLK_TAB == key)
{
startEnteringText();
}
break;
}
case SDLK_RETURN: //enter key
case EShortcut::GLOBAL_CANCEL:
if(captureAllKeys)
endEnteringText(false);
break;
case EShortcut::GAME_ACTIVATE_CONSOLE:
if(captureAllKeys)
endEnteringText(false);
else
startEnteringText();
break;
case EShortcut::GLOBAL_ACCEPT:
{
if(!enteredText.empty() && captureAllKeys)
{
@ -145,7 +145,7 @@ void CInGameConsole::keyPressed (const SDL_Keycode & key)
}
break;
}
case SDLK_BACKSPACE:
case EShortcut::GLOBAL_BACKSPACE:
{
if(enteredText.size() > 1)
{
@ -155,7 +155,7 @@ void CInGameConsole::keyPressed (const SDL_Keycode & key)
}
break;
}
case SDLK_UP: //up arrow
case EShortcut::MOVE_UP:
{
if(previouslyEntered.empty())
break;
@ -174,7 +174,7 @@ void CInGameConsole::keyPressed (const SDL_Keycode & key)
}
break;
}
case SDLK_DOWN: //down arrow
case EShortcut::MOVE_DOWN:
{
if(prevEntDisp != -1 && prevEntDisp+1 < previouslyEntered.size())
{
@ -190,10 +190,6 @@ void CInGameConsole::keyPressed (const SDL_Keycode & key)
}
break;
}
default:
{
break;
}
}
}

View File

@ -47,7 +47,7 @@ public:
void tick(uint32_t msPassed) override;
void show(SDL_Surface * to) override;
void showAll(SDL_Surface * to) override;
void keyPressed(const SDL_Keycode & key) override;
void keyPressed(EShortcut key) override;
void textInputed(const std::string & enteredText) override;
void textEdited(const std::string & enteredText) override;

View File

@ -80,7 +80,7 @@ std::string CResDataBar::buildDateString()
void CResDataBar::draw(SDL_Surface * to)
{
//TODO: all this should be labels, but they require proper text update on change
for (auto i=GameResID(EGameResID::WOOD); i <= GameResID(EGameResID::GOLD); vstd::advance(i, 1))
for (GameResID i=EGameResID::WOOD; i <= GameResID(EGameResID::GOLD); ++i)
{
std::string text = std::to_string(LOCPLINT->cb->getResourceAmount(i));

View File

@ -243,7 +243,7 @@ std::set<BattleHex> BattleFieldController::getMovementRangeForHoveredStack()
if (!owner.stacksController->getActiveStack())
return result;
if (!settings["battle"]["movementHighlightOnHover"].Bool())
if (!settings["battle"]["movementHighlightOnHover"].Bool() && !GH.isKeyboardShiftDown())
return result;
auto hoveredHex = getHoveredHex();

View File

@ -24,6 +24,7 @@
#include "../CVideoHandler.h"
#include "../gui/CursorHandler.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../render/Canvas.h"
#include "../render/IImage.h"
#include "../widgets/Buttons.h"
@ -406,12 +407,12 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
background->colorize(owner.playerID);
pos = center(background->pos);
exit = std::make_shared<CButton>(Point(384, 505), "iok6432.def", std::make_pair("", ""), [&](){ bExitf();}, SDLK_RETURN);
exit = std::make_shared<CButton>(Point(384, 505), "iok6432.def", std::make_pair("", ""), [&](){ bExitf();}, EShortcut::GLOBAL_ACCEPT);
exit->setBorderColor(Colors::METALLIC_GOLD);
if(allowReplay)
{
repeat = std::make_shared<CButton>(Point(24, 505), "icn6432.def", std::make_pair("", ""), [&](){ bRepeatf();}, SDLK_ESCAPE);
repeat = std::make_shared<CButton>(Point(24, 505), "icn6432.def", std::make_pair("", ""), [&](){ bRepeatf();}, EShortcut::GLOBAL_CANCEL);
repeat->setBorderColor(Colors::METALLIC_GOLD);
labels.push_back(std::make_shared<CLabel>(232, 520, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->translate("vcmi.battleResultsWindow.applyResultsLabel")));
}

View File

@ -21,6 +21,7 @@
#include "../CMusicHandler.h"
#include "../gui/CursorHandler.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../windows/CSpellWindow.h"
#include "../widgets/Buttons.h"
#include "../widgets/Images.h"
@ -50,19 +51,23 @@ BattleWindow::BattleWindow(BattleInterface & owner):
const JsonNode config(ResourceID("config/widgets/BattleWindow.json"));
addCallback("options", std::bind(&BattleWindow::bOptionsf, this));
addCallback("surrender", std::bind(&BattleWindow::bSurrenderf, this));
addCallback("flee", std::bind(&BattleWindow::bFleef, this));
addCallback("autofight", std::bind(&BattleWindow::bAutofightf, this));
addCallback("spellbook", std::bind(&BattleWindow::bSpellf, this));
addCallback("wait", std::bind(&BattleWindow::bWaitf, this));
addCallback("defence", std::bind(&BattleWindow::bDefencef, this));
addCallback("consoleUp", std::bind(&BattleWindow::bConsoleUpf, this));
addCallback("consoleDown", std::bind(&BattleWindow::bConsoleDownf, this));
addCallback("tacticNext", std::bind(&BattleWindow::bTacticNextStack, this));
addCallback("tacticEnd", std::bind(&BattleWindow::bTacticPhaseEnd, this));
addCallback("alternativeAction", std::bind(&BattleWindow::bSwitchActionf, this));
addShortcut(EShortcut::GLOBAL_OPTIONS, std::bind(&BattleWindow::bOptionsf, this));
addShortcut(EShortcut::BATTLE_SURRENDER, std::bind(&BattleWindow::bSurrenderf, this));
addShortcut(EShortcut::BATTLE_RETREAT, std::bind(&BattleWindow::bFleef, this));
addShortcut(EShortcut::BATTLE_AUTOCOMBAT, std::bind(&BattleWindow::bAutofightf, this));
addShortcut(EShortcut::BATTLE_CAST_SPELL, std::bind(&BattleWindow::bSpellf, this));
addShortcut(EShortcut::BATTLE_WAIT, std::bind(&BattleWindow::bWaitf, this));
addShortcut(EShortcut::BATTLE_DEFEND, std::bind(&BattleWindow::bDefencef, this));
addShortcut(EShortcut::BATTLE_CONSOLE_UP, std::bind(&BattleWindow::bConsoleUpf, this));
addShortcut(EShortcut::BATTLE_CONSOLE_DOWN, std::bind(&BattleWindow::bConsoleDownf, this));
addShortcut(EShortcut::BATTLE_TACTICS_NEXT, std::bind(&BattleWindow::bTacticNextStack, this));
addShortcut(EShortcut::BATTLE_TACTICS_END, std::bind(&BattleWindow::bTacticPhaseEnd, this));
addShortcut(EShortcut::BATTLE_SELECT_ACTION, std::bind(&BattleWindow::bSwitchActionf, this));
addShortcut(EShortcut::BATTLE_TOGGLE_QUEUE, [this](){ this->toggleQueueVisibility();});
addShortcut(EShortcut::BATTLE_USE_CREATURE_SPELL, [this](){ this->owner.actionsController->enterCreatureCastingMode(); });
addShortcut(EShortcut::GLOBAL_CANCEL, [this](){ this->owner.actionsController->endCastingSpell(); });
build(config);
console = widget<BattleConsole>("console");
@ -182,43 +187,14 @@ void BattleWindow::deactivate()
LOCPLINT->cingconsole->deactivate();
}
void BattleWindow::keyPressed(const SDL_Keycode & key)
void BattleWindow::keyPressed(EShortcut key)
{
if (owner.openingPlaying())
{
owner.openingEnd();
return;
}
if(key == SDLK_q)
{
toggleQueueVisibility();
}
else if(key == SDLK_f)
{
owner.actionsController->enterCreatureCastingMode();
}
else if(key == SDLK_ESCAPE)
{
owner.actionsController->endCastingSpell();
}
else if(GH.isKeyboardShiftDown())
{
// save and activate setting
Settings movementHighlightOnHover = settings.write["battle"]["movementHighlightOnHover"];
movementHighlightOnHoverCache = movementHighlightOnHover->Bool();
movementHighlightOnHover->Bool() = true;
}
}
void BattleWindow::keyReleased(const SDL_Keycode & key)
{
if(!GH.isKeyboardShiftDown())
{
// set back to initial state
Settings movementHighlightOnHover = settings.write["battle"]["movementHighlightOnHover"];
movementHighlightOnHover->Bool() = movementHighlightOnHoverCache;
}
InterfaceObjectConfigurable::keyPressed(key);
}
void BattleWindow::clickRight(tribool down, bool previousState)
@ -554,40 +530,18 @@ void BattleWindow::blockUI(bool on)
bool canWait = owner.stacksController->getActiveStack() ? !owner.stacksController->getActiveStack()->waitedThisTurn : false;
if(auto w = widget<CButton>("options"))
w->block(on);
if(auto w = widget<CButton>("flee"))
w->block(on || !owner.curInt->cb->battleCanFlee());
if(auto w = widget<CButton>("surrender"))
w->block(on || owner.curInt->cb->battleGetSurrenderCost() < 0);
if(auto w = widget<CButton>("cast"))
w->block(on || owner.tacticsMode || !canCastSpells);
if(auto w = widget<CButton>("wait"))
w->block(on || owner.tacticsMode || !canWait);
if(auto w = widget<CButton>("defence"))
w->block(on || owner.tacticsMode);
if(auto w = widget<CButton>("alternativeAction"))
w->block(on || owner.tacticsMode);
if(auto w = widget<CButton>("autofight"))
w->block(owner.actionsController->spellcastingModeActive());
auto btactEnd = widget<CButton>("tacticEnd");
auto btactNext = widget<CButton>("tacticNext");
if(owner.tacticsMode && btactEnd && btactNext)
{
btactNext->block(on);
btactEnd->block(on);
}
else
{
auto bConsoleUp = widget<CButton>("consoleUp");
auto bConsoleDown = widget<CButton>("consoleDown");
if(bConsoleUp && bConsoleDown)
{
bConsoleUp->block(on);
bConsoleDown->block(on);
}
}
setShortcutBlocked(EShortcut::GLOBAL_OPTIONS, on);
setShortcutBlocked(EShortcut::BATTLE_RETREAT, on || !owner.curInt->cb->battleCanFlee());
setShortcutBlocked(EShortcut::BATTLE_SURRENDER, on || owner.curInt->cb->battleGetSurrenderCost() < 0);
setShortcutBlocked(EShortcut::BATTLE_CAST_SPELL, on || owner.tacticsMode || !canCastSpells);
setShortcutBlocked(EShortcut::BATTLE_WAIT, on || owner.tacticsMode || !canWait);
setShortcutBlocked(EShortcut::BATTLE_DEFEND, on || owner.tacticsMode);
setShortcutBlocked(EShortcut::BATTLE_SELECT_ACTION, on || owner.tacticsMode);
setShortcutBlocked(EShortcut::BATTLE_AUTOCOMBAT, owner.actionsController->spellcastingModeActive());
setShortcutBlocked(EShortcut::BATTLE_TACTICS_END, on && owner.tacticsMode);
setShortcutBlocked(EShortcut::BATTLE_TACTICS_NEXT, on && owner.tacticsMode);
setShortcutBlocked(EShortcut::BATTLE_CONSOLE_DOWN, on && !owner.tacticsMode);
setShortcutBlocked(EShortcut::BATTLE_CONSOLE_UP, on && !owner.tacticsMode);
}
std::optional<uint32_t> BattleWindow::getQueueHoveredUnitId()

View File

@ -84,8 +84,7 @@ public:
void activate() override;
void deactivate() override;
void keyPressed(const SDL_Keycode & key) override;
void keyReleased(const SDL_Keycode& key) override;
void keyPressed(EShortcut key) override;
void clickRight(tribool down, bool previousState) override;
void show(SDL_Surface *to) override;
void showAll(SDL_Surface *to) override;
@ -98,9 +97,5 @@ public:
/// Set possible alternative options. If more than 1 - the last will be considered as default option
void setAlternativeActions(const std::list<PossiblePlayerBattleAction> &);
private:
/// used to save the state of this setting on toggle.
bool movementHighlightOnHoverCache;
};

View File

@ -13,6 +13,7 @@
#include "CIntObject.h"
#include "CursorHandler.h"
#include "ShortcutHandler.h"
#include "../CGameInfo.h"
#include "../render/Colors.h"
@ -27,6 +28,7 @@
#include <SDL_render.h>
#include <SDL_timer.h>
#include <SDL_events.h>
#include <SDL_keycode.h>
#ifdef VCMI_APPLE
#include <dispatch/dispatch.h>
@ -93,6 +95,7 @@ void CGuiHandler::processLists(const ui16 activityFlag, std::function<void (std:
void CGuiHandler::init()
{
shortcutsHandlerInstance = std::make_unique<ShortcutHandler>();
mainFPSmng = new CFramerateManager();
mainFPSmng->init(settings["video"]["targetfps"].Integer());
isPointerRelativeMode = settings["general"]["userRelativePointer"].Bool();
@ -356,6 +359,10 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
if(current.type == SDL_KEYDOWN || current.type == SDL_KEYUP)
{
SDL_KeyboardEvent key = current.key;
if (key.repeat != 0)
return; // ignore periodic event resends
if(current.type == SDL_KEYDOWN && key.keysym.sym >= SDLK_F1 && key.keysym.sym <= SDLK_F15 && settings["session"]["spectate"].Bool())
{
//TODO: we need some central place for all interface-independent hotkeys
@ -397,32 +404,35 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
return;
}
//translate numpad keys
if(key.keysym.sym == SDLK_KP_ENTER)
{
key.keysym.sym = SDLK_RETURN;
key.keysym.scancode = SDL_SCANCODE_RETURN;
}
auto shortcutsVector = shortcutsHandler().translateKeycode(key.keysym.sym);
bool keysCaptured = false;
for(auto i = keyinterested.begin(); i != keyinterested.end() && continueEventHandling; i++)
{
if((*i)->captureThisKey(key.keysym.sym))
for (EShortcut shortcut : shortcutsVector)
{
keysCaptured = true;
break;
if((*i)->captureThisKey(shortcut))
{
keysCaptured = true;
break;
}
}
}
std::list<CIntObject*> miCopy = keyinterested;
for(auto i = miCopy.begin(); i != miCopy.end() && continueEventHandling; i++)
if(vstd::contains(keyinterested,*i) && (!keysCaptured || (*i)->captureThisKey(key.keysym.sym)))
{
for (EShortcut shortcut : shortcutsVector)
{
if (key.state == SDL_PRESSED && key.repeat == 0) // function like key_DOWN, and not like a periodic key_Pressed check
(**i).keyPressed(key.keysym.sym);
if (key.state == SDL_RELEASED)
(**i).keyReleased(key.keysym.sym);
if(vstd::contains(keyinterested,*i) && (!keysCaptured || (*i)->captureThisKey(shortcut)))
{
if (key.state == SDL_PRESSED)
(**i).keyPressed(shortcut);
if (key.state == SDL_RELEASED)
(**i).keyReleased(shortcut);
}
}
}
}
else if(current.type == SDL_MOUSEMOTION)
{
@ -704,6 +714,10 @@ CGuiHandler::~CGuiHandler()
delete terminate_cond;
}
ShortcutHandler & CGuiHandler::shortcutsHandler()
{
return *shortcutsHandlerInstance;
}
void CGuiHandler::moveCursorToPosition(const Point & position)
{
@ -770,69 +784,6 @@ void CGuiHandler::drawFPSCounter()
graphics->fonts[FONT_BIG]->renderTextLeft(screen, fps, Colors::YELLOW, Point(10, 10));
}
SDL_Keycode CGuiHandler::arrowToNum(SDL_Keycode key)
{
switch(key)
{
case SDLK_DOWN:
return SDLK_KP_2;
case SDLK_UP:
return SDLK_KP_8;
case SDLK_LEFT:
return SDLK_KP_4;
case SDLK_RIGHT:
return SDLK_KP_6;
default:
throw std::runtime_error("Wrong key!");
}
}
SDL_Keycode CGuiHandler::numToDigit(SDL_Keycode key)
{
#define REMOVE_KP(keyName) case SDLK_KP_ ## keyName : return SDLK_ ## keyName;
switch(key)
{
REMOVE_KP(0)
REMOVE_KP(1)
REMOVE_KP(2)
REMOVE_KP(3)
REMOVE_KP(4)
REMOVE_KP(5)
REMOVE_KP(6)
REMOVE_KP(7)
REMOVE_KP(8)
REMOVE_KP(9)
REMOVE_KP(PERIOD)
REMOVE_KP(MINUS)
REMOVE_KP(PLUS)
REMOVE_KP(EQUALS)
case SDLK_KP_MULTIPLY:
return SDLK_ASTERISK;
case SDLK_KP_DIVIDE:
return SDLK_SLASH;
case SDLK_KP_ENTER:
return SDLK_RETURN;
default:
return SDLK_UNKNOWN;
}
#undef REMOVE_KP
}
bool CGuiHandler::isNumKey(SDL_Keycode key, bool number)
{
if(number)
return key >= SDLK_KP_1 && key <= SDLK_KP_0;
else
return (key >= SDLK_KP_1 && key <= SDLK_KP_0) || key == SDLK_KP_MINUS || key == SDLK_KP_PLUS || key == SDLK_KP_EQUALS;
}
bool CGuiHandler::isArrowKey(SDL_Keycode key)
{
return key == SDLK_UP || key == SDLK_DOWN || key == SDLK_LEFT || key == SDLK_RIGHT;
}
bool CGuiHandler::amIGuiThread()
{
return inGuiThread.get() && *inGuiThread;

View File

@ -12,8 +12,6 @@
#include "MouseButton.h"
#include "../../lib/Point.h"
#include <SDL_keycode.h>
VCMI_LIB_NAMESPACE_BEGIN
template <typename T> struct CondSh;
@ -24,6 +22,7 @@ VCMI_LIB_NAMESPACE_END
union SDL_Event;
struct SDL_MouseMotionEvent;
class ShortcutHandler;
class CFramerateManager;
class IStatusBar;
class CIntObject;
@ -79,6 +78,8 @@ private:
std::vector<std::shared_ptr<IShowActivatable>> disposed;
std::unique_ptr<ShortcutHandler> shortcutsHandlerInstance;
std::atomic<bool> continueEventHandling;
using CIntObjectList = std::list<CIntObject *>;
@ -113,6 +114,8 @@ public:
/// returns current position of mouse cursor, relative to vcmi window
const Point & getCursorPosition() const;
ShortcutHandler & shortcutsHandler();
Point screenDimensions() const;
/// returns true if at least one mouse button is pressed
@ -173,10 +176,6 @@ public:
void breakEventHandling(); //current event won't be propagated anymore
void drawFPSCounter(); // draws the FPS to the upper left corner of the screen
static SDL_Keycode arrowToNum(SDL_Keycode key); //converts arrow key to according numpad key
static SDL_Keycode numToDigit(SDL_Keycode key);//converts numpad digit key to normal digit key
static bool isNumKey(SDL_Keycode key, bool number = true); //checks if key is on numpad (numbers - check only for numpad digits)
static bool isArrowKey(SDL_Keycode key);
static bool amIGuiThread();
static void pushUserEvent(EUserEvent usercode);
static void pushUserEvent(EUserEvent usercode, void * userdata);

View File

@ -11,6 +11,7 @@
#include "CIntObject.h"
#include "CGuiHandler.h"
#include "Shortcut.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../windows/CMessage.h"
#include "../CMT.h"
@ -305,28 +306,23 @@ const Rect & CIntObject::center(const Point & p, bool propagate)
return pos;
}
bool CIntObject::captureThisKey(const SDL_Keycode & key)
bool CIntObject::captureThisKey(EShortcut key)
{
return captureAllKeys;
}
CKeyShortcut::CKeyShortcut()
: assignedKey(EShortcut::NONE)
{}
CKeyShortcut::CKeyShortcut(int key)
CKeyShortcut::CKeyShortcut(EShortcut key)
: assignedKey(key)
{
if (key != SDLK_UNKNOWN)
assignedKeys.insert(key);
}
CKeyShortcut::CKeyShortcut(std::set<int> Keys)
:assignedKeys(Keys)
{}
void CKeyShortcut::keyPressed(const SDL_Keycode & key)
void CKeyShortcut::keyPressed(EShortcut key)
{
if(vstd::contains(assignedKeys,key)
|| vstd::contains(assignedKeys, CGuiHandler::numToDigit(key)))
if( assignedKey == key && assignedKey != EShortcut::NONE)
{
bool prev = mouseState(MouseButton::LEFT);
updateMouseState(MouseButton::LEFT, true);
@ -335,10 +331,9 @@ void CKeyShortcut::keyPressed(const SDL_Keycode & key)
}
}
void CKeyShortcut::keyReleased(const SDL_Keycode & key)
void CKeyShortcut::keyReleased(EShortcut key)
{
if(vstd::contains(assignedKeys,key)
|| vstd::contains(assignedKeys, CGuiHandler::numToDigit(key)))
if( assignedKey == key && assignedKey != EShortcut::NONE)
{
bool prev = mouseState(MouseButton::LEFT);
updateMouseState(MouseButton::LEFT, false);

View File

@ -16,8 +16,7 @@
struct SDL_Surface;
class CGuiHandler;
class CPicture;
using SDL_Keycode = int32_t;
enum class EShortcut;
using boost::logic::tribool;
@ -111,9 +110,9 @@ public:
//keyboard handling
bool captureAllKeys; //if true, only this object should get info about pressed keys
virtual void keyPressed(const SDL_Keycode & key){}
virtual void keyReleased(const SDL_Keycode & key){}
virtual bool captureThisKey(const SDL_Keycode & key); //allows refining captureAllKeys against specific events (eg. don't capture ENTER)
virtual void keyPressed(EShortcut key){}
virtual void keyReleased(EShortcut key){}
virtual bool captureThisKey(EShortcut key); //allows refining captureAllKeys against specific events (eg. don't capture ENTER)
virtual void textInputed(const std::string & enteredText){};
virtual void textEdited(const std::string & enteredText){};
@ -190,12 +189,11 @@ public:
class CKeyShortcut : public virtual CIntObject
{
public:
std::set<int> assignedKeys;
EShortcut assignedKey;
CKeyShortcut();
CKeyShortcut(int key);
CKeyShortcut(std::set<int> Keys);
void keyPressed(const SDL_Keycode & key) override;
void keyReleased(const SDL_Keycode & key) override;
CKeyShortcut(EShortcut key);
void keyPressed(EShortcut key) override;
void keyReleased(EShortcut key) override;
};

View File

@ -15,6 +15,8 @@
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../gui/CGuiHandler.h"
#include "../gui/ShortcutHandler.h"
#include "../gui/Shortcut.h"
#include "../widgets/CComponent.h"
#include "../widgets/Buttons.h"
#include "../widgets/MiscWidgets.h"
@ -25,18 +27,6 @@
#include "../../lib/CGeneralTextHandler.h"
static std::map<std::string, int> KeycodeMap{
{"up", SDLK_UP},
{"down", SDLK_DOWN},
{"left", SDLK_LEFT},
{"right", SDLK_RIGHT},
{"space", SDLK_SPACE},
{"escape", SDLK_ESCAPE},
{"backspace", SDLK_BACKSPACE},
{"enter", SDLK_RETURN}
};
InterfaceObjectConfigurable::InterfaceObjectConfigurable(const JsonNode & config, int used, Point offset):
InterfaceObjectConfigurable(used, offset)
{
@ -211,27 +201,20 @@ std::pair<std::string, std::string> InterfaceObjectConfigurable::readHintText(co
return result;
}
int InterfaceObjectConfigurable::readKeycode(const JsonNode & config) const
EShortcut InterfaceObjectConfigurable::readHotkey(const JsonNode & config) const
{
logGlobal->debug("Reading keycode");
if(config.getType() == JsonNode::JsonType::DATA_INTEGER)
return config.Integer();
if(config.getType() == JsonNode::JsonType::DATA_STRING)
logGlobal->debug("Reading hotkey");
if(config.getType() != JsonNode::JsonType::DATA_STRING)
{
auto s = config.String();
if(s.size() == 1) //keyboard symbol
return s[0];
if (KeycodeMap.count(s))
return KeycodeMap[s];
logGlobal->error("Invalid keycode '%s' in interface configuration!", config.String());
return SDLK_UNKNOWN;
logGlobal->error("Invalid hotket format in interface configuration! Expected string!", config.String());
return EShortcut::NONE;
}
logGlobal->error("Invalid keycode format in interface configuration! Expected string or integer!", config.String());
return SDLK_UNKNOWN;
EShortcut result = GH.shortcutsHandler().findShortcut(config.String());
if (result == EShortcut::NONE)
logGlobal->error("Invalid hotkey '%s' in interface configuration!", config.String());
return result;;
}
std::shared_ptr<CPicture> InterfaceObjectConfigurable::buildPicture(const JsonNode & config) const
@ -337,16 +320,27 @@ std::shared_ptr<CButton> InterfaceObjectConfigurable::buildButton(const JsonNode
button->setImageOrder(imgOrder[0].Integer(), imgOrder[1].Integer(), imgOrder[2].Integer(), imgOrder[3].Integer());
}
if(!config["callback"].isNull())
button->addCallback(std::bind(callbacks.at(config["callback"].String()), 0));
{
std::string callbackName = config["callback"].String();
if (callbacks.count(callbackName) > 0)
button->addCallback(std::bind(callbacks.at(callbackName), 0));
else
logGlobal->error("Invalid callback '%s' in widget", callbackName );
}
if(!config["hotkey"].isNull())
{
if(config["hotkey"].getType() == JsonNode::JsonType::DATA_VECTOR)
if(config["hotkey"].getType() == JsonNode::JsonType::DATA_STRING)
{
for(auto k : config["hotkey"].Vector())
button->assignedKeys.insert(readKeycode(k));
button->assignedKey = readHotkey(config["hotkey"]);
auto target = shortcuts.find(button->assignedKey);
if (target != shortcuts.end())
{
button->addCallback(target->second.callback);
target->second.assignedToButton = true;
}
}
else
button->assignedKeys.insert(readKeycode(config["hotkey"]));
}
return button;
}
@ -452,3 +446,41 @@ std::shared_ptr<CIntObject> InterfaceObjectConfigurable::buildWidget(JsonNode co
logGlobal->error("Builder with type %s is not registered", type);
return nullptr;
}
void InterfaceObjectConfigurable::setShortcutBlocked(EShortcut shortcut, bool isBlocked)
{
auto target = shortcuts.find(shortcut);
if (target == shortcuts.end())
return;
target->second.blocked = isBlocked;
for (auto & entry : widgets)
{
auto button = std::dynamic_pointer_cast<CButton>(entry.second);
if (button && button->assignedKey == shortcut)
button->block(isBlocked);
}
}
void InterfaceObjectConfigurable::addShortcut(EShortcut shortcut, std::function<void()> callback)
{
assert(shortcuts.count(shortcut) == 0);
shortcuts[shortcut].callback = callback;
}
void InterfaceObjectConfigurable::keyPressed(EShortcut key)
{
auto target = shortcuts.find(key);
if (target == shortcuts.end())
return;
if (target->second.assignedToButton)
return; // will be handled by button instance
if (target->second.blocked)
return;
target->second.callback();
}

View File

@ -35,7 +35,14 @@ public:
InterfaceObjectConfigurable(const JsonNode & config, int used=0, Point offset=Point());
protected:
/// Set blocked status for all buttons assotiated with provided shortcut
void setShortcutBlocked(EShortcut shortcut, bool isBlocked);
/// Registers provided callback to be called whenever specified shortcut is triggered
void addShortcut(EShortcut shortcut, std::function<void()> callback);
void keyPressed(EShortcut key) override;
using BuilderFunction = std::function<std::shared_ptr<CIntObject>(const JsonNode &)>;
void registerBuilder(const std::string &, BuilderFunction);
@ -64,7 +71,7 @@ protected:
EFonts readFont(const JsonNode &) const;
std::string readText(const JsonNode &) const;
std::pair<std::string, std::string> readHintText(const JsonNode &) const;
int readKeycode(const JsonNode &) const;
EShortcut readHotkey(const JsonNode &) const;
//basic widgets
std::shared_ptr<CPicture> buildPicture(const JsonNode &) const;
@ -82,9 +89,16 @@ protected:
std::shared_ptr<CIntObject> buildWidget(JsonNode config) const;
private:
struct ShortcutState
{
std::function<void()> callback;
mutable bool assignedToButton = false;
bool blocked = false;
};
int unnamedObjectId = 0;
std::map<std::string, BuilderFunction> builders;
std::map<std::string, std::shared_ptr<CIntObject>> widgets;
std::map<std::string, std::function<void(int)>> callbacks;
std::map<EShortcut, ShortcutState> shortcuts;
};

156
client/gui/Shortcut.h Normal file
View File

@ -0,0 +1,156 @@
/*
* Shortcut.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
enum class EShortcut
{
NONE,
// Global hotkeys that are available in multiple dialogs
GLOBAL_ACCEPT, // Return - Accept query
GLOBAL_CANCEL, // Escape - Cancel query
GLOBAL_RETURN, // Enter, Escape - Close current window and return to previous view
GLOBAL_FULLSCREEN, // F4 - TODO: remove hardcoded check for key
GLOBAL_OPTIONS, // 'O' - Open System Options dialog
GLOBAL_BACKSPACE, // Backspace - erase last symbol in text input
GLOBAL_MOVE_FOCUS, // Tab - move focus to next text input
// Movement hotkeys, usually - for moving through lists with slider
MOVE_LEFT,
MOVE_RIGHT,
MOVE_UP,
MOVE_DOWN,
MOVE_FIRST,
MOVE_LAST,
MOVE_PAGE_UP,
MOVE_PAGE_DOWN,
// Element selection - for multiple choice dialog popups
SELECT_INDEX_1,
SELECT_INDEX_2,
SELECT_INDEX_3,
SELECT_INDEX_4,
SELECT_INDEX_5,
SELECT_INDEX_6,
SELECT_INDEX_7,
SELECT_INDEX_8,
// Main menu hotkeys - for navigation between main menu windows
MAIN_MENU_NEW_GAME,
MAIN_MENU_LOAD_GAME,
MAIN_MENU_HIGH_SCORES,
MAIN_MENU_CREDITS,
MAIN_MENU_BACK,
MAIN_MENU_QUIT,
MAIN_MENU_SINGLEPLAYER,
MAIN_MENU_MULTIPLAYER,
MAIN_MENU_CAMPAIGN,
MAIN_MENU_TUTORIAL,
MAIN_MENU_CAMPAIGN_SOD,
MAIN_MENU_CAMPAIGN_ROE,
MAIN_MENU_CAMPAIGN_AB,
MAIN_MENU_CAMPAIGN_CUSTOM,
// Game lobby / scenario selection
LOBBY_BEGIN_GAME, // b, Return
LOBBY_LOAD_GAME, // l, Return
LOBBY_SAVE_GAME, // s, Return
LOBBY_RANDOM_MAP, // Open random map tab
LOBBY_HIDE_CHAT,
LOBBY_ADDITIONAL_OPTIONS, // Open additional options tab
LOBBY_SELECT_SCENARIO, // Open map list tab
// In-game hotkeys, require game state but may be available in windows other than adventure map
GAME_END_TURN,
GAME_LOAD_GAME,
GAME_SAVE_GAME,
GAME_RESTART_GAME,
GAME_TO_MAIN_MENU,
GAME_QUIT_GAME,
GAME_OPEN_MARKETPLACE,
GAME_OPEN_THIEVES_GUILD,
GAME_ACTIVATE_CONSOLE, // Tab, activates in-game console
// Adventure map screen
ADVENTURE_GAME_OPTIONS, // 'o', Open CAdventureOptions window
ADVENTURE_TOGGLE_GRID, // F6, Toggles map grid
ADVENTURE_TOGGLE_SLEEP, // z,w, Toggles hero sleep status
ADVENTURE_MOVE_HERO, // Moves hero alongside set path
ADVENTURE_VISIT_OBJECT, // Revisits object hero is standing on
ADVENTURE_VIEW_SELECTED,// Open window with currently selected hero/town
ADVENTURE_NEXT_TOWN,
ADVENTURE_NEXT_HERO,
ADVENTURE_NEXT_OBJECT, // TODO: context-sensitive next object - select next hero/town, depending on current selection
ADVENTURE_FIRST_TOWN, // TODO: select first available town in the list
ADVENTURE_FIRST_HERO, // TODO: select first available hero in the list
ADVENTURE_VIEW_SCENARIO,// View Scenario Information window
ADVENTURE_DIG_GRAIL,
ADVENTURE_VIEW_PUZZLE,
ADVENTURE_VIEW_WORLD,
ADVENTURE_TOGGLE_MAP_LEVEL,
ADVENTURE_KINGDOM_OVERVIEW,
ADVENTURE_QUEST_LOG,
ADVENTURE_CAST_SPELL,
ADVENTURE_END_TURN,
ADVENTURE_THIEVES_GUILD,
// Move hero one tile in specified direction. Bound to cursors & numpad buttons
ADVENTURE_MOVE_HERO_SW,
ADVENTURE_MOVE_HERO_SS,
ADVENTURE_MOVE_HERO_SE,
ADVENTURE_MOVE_HERO_WW,
ADVENTURE_MOVE_HERO_EE,
ADVENTURE_MOVE_HERO_NW,
ADVENTURE_MOVE_HERO_NN,
ADVENTURE_MOVE_HERO_NE,
// Battle screen
BATTLE_TOGGLE_QUEUE,
BATTLE_USE_CREATURE_SPELL,
BATTLE_SURRENDER,
BATTLE_RETREAT,
BATTLE_AUTOCOMBAT,
BATTLE_CAST_SPELL,
BATTLE_WAIT,
BATTLE_DEFEND,
BATTLE_CONSOLE_UP,
BATTLE_CONSOLE_DOWN,
BATTLE_TACTICS_NEXT,
BATTLE_TACTICS_END,
BATTLE_SELECT_ACTION, // Alternative actions toggle
// Town screen
TOWN_OPEN_TAVERN,
TOWN_SWAP_ARMIES, // Swap garrisoned and visiting armies
// Creature & creature recruitment screen
RECRUITMENT_MAX, // Set number of creatures to recruit to max
RECRUITMENT_MIN, // Set number of creatures to recruit to min (1)
RECRUITMENT_UPGRADE, // Upgrade current creature
RECRUITMENT_UPGRADE_ALL, // Upgrade all creatures (Hill Fort / Skeleton Transformer)
// Kingdom Overview window
KINGDOM_HEROES_TAB,
KINGDOM_TOWNS_TAB,
// Hero screen
HERO_DISMISS,
HERO_COMMANDER,
HERO_LOOSE_FORMATION,
HERO_TIGHT_FORMATION,
HERO_TOGGLE_TACTICS, // b
// Spellbook screen
SPELLBOOK_TAB_ADVENTURE,
SPELLBOOK_TAB_COMBAT,
AFTER_LAST
};

View File

@ -0,0 +1,362 @@
/*
* ShortcutHandler.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "ShortcutHandler.h"
#include "Shortcut.h"
#include <SDL_keycode.h>
std::vector<EShortcut> ShortcutHandler::translateKeycode(SDL_Keycode key) const
{
static const std::multimap<SDL_Keycode, EShortcut> keyToShortcut = {
{SDLK_RETURN, EShortcut::GLOBAL_ACCEPT },
{SDLK_KP_ENTER, EShortcut::GLOBAL_ACCEPT },
{SDLK_ESCAPE, EShortcut::GLOBAL_CANCEL },
{SDLK_RETURN, EShortcut::GLOBAL_RETURN },
{SDLK_KP_ENTER, EShortcut::GLOBAL_RETURN },
{SDLK_ESCAPE, EShortcut::GLOBAL_RETURN },
{SDLK_F4, EShortcut::GLOBAL_FULLSCREEN },
{SDLK_BACKSPACE, EShortcut::GLOBAL_BACKSPACE },
{SDLK_TAB, EShortcut::GLOBAL_MOVE_FOCUS },
{SDLK_o, EShortcut::GLOBAL_OPTIONS },
{SDLK_LEFT, EShortcut::MOVE_LEFT },
{SDLK_RIGHT, EShortcut::MOVE_RIGHT },
{SDLK_UP, EShortcut::MOVE_UP },
{SDLK_DOWN, EShortcut::MOVE_DOWN },
{SDLK_HOME, EShortcut::MOVE_FIRST },
{SDLK_END, EShortcut::MOVE_LAST },
{SDLK_PAGEUP, EShortcut::MOVE_PAGE_UP },
{SDLK_PAGEDOWN, EShortcut::MOVE_PAGE_DOWN },
{SDLK_1, EShortcut::SELECT_INDEX_1 },
{SDLK_2, EShortcut::SELECT_INDEX_2 },
{SDLK_3, EShortcut::SELECT_INDEX_3 },
{SDLK_4, EShortcut::SELECT_INDEX_4 },
{SDLK_5, EShortcut::SELECT_INDEX_5 },
{SDLK_6, EShortcut::SELECT_INDEX_6 },
{SDLK_7, EShortcut::SELECT_INDEX_7 },
{SDLK_8, EShortcut::SELECT_INDEX_8 },
{SDLK_n, EShortcut::MAIN_MENU_NEW_GAME },
{SDLK_l, EShortcut::MAIN_MENU_LOAD_GAME },
{SDLK_h, EShortcut::MAIN_MENU_HIGH_SCORES },
{SDLK_c, EShortcut::MAIN_MENU_CREDITS },
{SDLK_q, EShortcut::MAIN_MENU_QUIT },
{SDLK_b, EShortcut::MAIN_MENU_BACK },
{SDLK_s, EShortcut::MAIN_MENU_SINGLEPLAYER },
{SDLK_m, EShortcut::MAIN_MENU_MULTIPLAYER },
{SDLK_c, EShortcut::MAIN_MENU_CAMPAIGN },
{SDLK_t, EShortcut::MAIN_MENU_TUTORIAL },
{SDLK_s, EShortcut::MAIN_MENU_CAMPAIGN_SOD },
{SDLK_r, EShortcut::MAIN_MENU_CAMPAIGN_ROE },
{SDLK_a, EShortcut::MAIN_MENU_CAMPAIGN_AB },
{SDLK_c, EShortcut::MAIN_MENU_CAMPAIGN_CUSTOM },
{SDLK_b, EShortcut::LOBBY_BEGIN_GAME },
{SDLK_RETURN, EShortcut::LOBBY_BEGIN_GAME },
{SDLK_KP_ENTER, EShortcut::LOBBY_BEGIN_GAME },
{SDLK_l, EShortcut::LOBBY_LOAD_GAME },
{SDLK_RETURN, EShortcut::LOBBY_LOAD_GAME },
{SDLK_KP_ENTER, EShortcut::LOBBY_LOAD_GAME },
{SDLK_s, EShortcut::LOBBY_SAVE_GAME },
{SDLK_r, EShortcut::LOBBY_RANDOM_MAP },
{SDLK_h, EShortcut::LOBBY_HIDE_CHAT },
{SDLK_a, EShortcut::LOBBY_ADDITIONAL_OPTIONS },
{SDLK_s, EShortcut::LOBBY_SELECT_SCENARIO },
{SDLK_e, EShortcut::GAME_END_TURN },
{SDLK_l, EShortcut::GAME_LOAD_GAME },
{SDLK_s, EShortcut::GAME_SAVE_GAME },
{SDLK_r, EShortcut::GAME_RESTART_GAME },
{SDLK_m, EShortcut::GAME_TO_MAIN_MENU },
{SDLK_q, EShortcut::GAME_QUIT_GAME },
{SDLK_t, EShortcut::GAME_OPEN_MARKETPLACE },
{SDLK_g, EShortcut::GAME_OPEN_THIEVES_GUILD },
{SDLK_TAB, EShortcut::GAME_ACTIVATE_CONSOLE },
{SDLK_o, EShortcut::ADVENTURE_GAME_OPTIONS },
{SDLK_F6, EShortcut::ADVENTURE_TOGGLE_GRID },
{SDLK_z, EShortcut::ADVENTURE_TOGGLE_SLEEP },
{SDLK_w, EShortcut::ADVENTURE_TOGGLE_SLEEP },
{SDLK_m, EShortcut::ADVENTURE_MOVE_HERO },
{SDLK_SPACE, EShortcut::ADVENTURE_VISIT_OBJECT },
{SDLK_KP_1, EShortcut::ADVENTURE_MOVE_HERO_SW },
{SDLK_KP_2, EShortcut::ADVENTURE_MOVE_HERO_SS },
{SDLK_KP_3, EShortcut::ADVENTURE_MOVE_HERO_SE },
{SDLK_KP_4, EShortcut::ADVENTURE_MOVE_HERO_WW },
{SDLK_KP_6, EShortcut::ADVENTURE_MOVE_HERO_EE },
{SDLK_KP_7, EShortcut::ADVENTURE_MOVE_HERO_NW },
{SDLK_KP_8, EShortcut::ADVENTURE_MOVE_HERO_NN },
{SDLK_KP_9, EShortcut::ADVENTURE_MOVE_HERO_NE },
{SDLK_DOWN, EShortcut::ADVENTURE_MOVE_HERO_SS },
{SDLK_LEFT, EShortcut::ADVENTURE_MOVE_HERO_WW },
{SDLK_RIGHT, EShortcut::ADVENTURE_MOVE_HERO_EE },
{SDLK_UP, EShortcut::ADVENTURE_MOVE_HERO_NN },
{SDLK_RETURN, EShortcut::ADVENTURE_VIEW_SELECTED },
{SDLK_KP_ENTER, EShortcut::ADVENTURE_VIEW_SELECTED },
// {SDLK_, EShortcut::ADVENTURE_NEXT_OBJECT },
{SDLK_t, EShortcut::ADVENTURE_NEXT_TOWN },
{SDLK_h, EShortcut::ADVENTURE_NEXT_HERO },
// {SDLK_, EShortcut::ADVENTURE_FIRST_TOWN },
// {SDLK_, EShortcut::ADVENTURE_FIRST_HERO },
{SDLK_i, EShortcut::ADVENTURE_VIEW_SCENARIO },
{SDLK_d, EShortcut::ADVENTURE_DIG_GRAIL },
{SDLK_p, EShortcut::ADVENTURE_VIEW_PUZZLE },
{SDLK_v, EShortcut::ADVENTURE_VIEW_WORLD },
{SDLK_u, EShortcut::ADVENTURE_TOGGLE_MAP_LEVEL},
{SDLK_k, EShortcut::ADVENTURE_KINGDOM_OVERVIEW},
{SDLK_q, EShortcut::ADVENTURE_QUEST_LOG },
{SDLK_c, EShortcut::ADVENTURE_CAST_SPELL },
{SDLK_e, EShortcut::ADVENTURE_END_TURN },
{SDLK_g, EShortcut::ADVENTURE_THIEVES_GUILD },
{SDLK_q, EShortcut::BATTLE_TOGGLE_QUEUE },
{SDLK_c, EShortcut::BATTLE_USE_CREATURE_SPELL },
{SDLK_s, EShortcut::BATTLE_SURRENDER },
{SDLK_r, EShortcut::BATTLE_RETREAT },
{SDLK_a, EShortcut::BATTLE_AUTOCOMBAT },
{SDLK_c, EShortcut::BATTLE_CAST_SPELL },
{SDLK_w, EShortcut::BATTLE_WAIT },
{SDLK_d, EShortcut::BATTLE_DEFEND },
{SDLK_SPACE, EShortcut::BATTLE_DEFEND },
{SDLK_UP, EShortcut::BATTLE_CONSOLE_UP },
{SDLK_DOWN, EShortcut::BATTLE_CONSOLE_DOWN },
{SDLK_SPACE, EShortcut::BATTLE_TACTICS_NEXT },
{SDLK_RETURN, EShortcut::BATTLE_TACTICS_END },
{SDLK_KP_ENTER, EShortcut::BATTLE_TACTICS_END },
{SDLK_s, EShortcut::BATTLE_SELECT_ACTION },
{SDLK_t, EShortcut::TOWN_OPEN_TAVERN },
{SDLK_SPACE, EShortcut::TOWN_SWAP_ARMIES },
{SDLK_END, EShortcut::RECRUITMENT_MAX },
{SDLK_HOME, EShortcut::RECRUITMENT_MIN },
{SDLK_u, EShortcut::RECRUITMENT_UPGRADE },
{SDLK_a, EShortcut::RECRUITMENT_UPGRADE_ALL },
{SDLK_u, EShortcut::RECRUITMENT_UPGRADE_ALL },
{SDLK_h, EShortcut::KINGDOM_HEROES_TAB },
{SDLK_t, EShortcut::KINGDOM_TOWNS_TAB },
{SDLK_d, EShortcut::HERO_DISMISS },
{SDLK_c, EShortcut::HERO_COMMANDER },
{SDLK_l, EShortcut::HERO_LOOSE_FORMATION },
{SDLK_t, EShortcut::HERO_TIGHT_FORMATION },
{SDLK_b, EShortcut::HERO_TOGGLE_TACTICS },
{SDLK_a, EShortcut::SPELLBOOK_TAB_ADVENTURE },
{SDLK_c, EShortcut::SPELLBOOK_TAB_COMBAT }
};
auto range = keyToShortcut.equal_range(key);
// FIXME: some code expects calls to keyPressed / captureThisKey even without defined hotkeys
if (range.first == range.second)
return {EShortcut::NONE};
std::vector<EShortcut> result;
for (auto it = range.first; it != range.second; ++it)
result.push_back(it->second);
return result;
}
EShortcut ShortcutHandler::findShortcut(const std::string & identifier ) const
{
static const std::map<std::string, EShortcut> shortcutNames = {
{"globalAccept", EShortcut::GLOBAL_ACCEPT },
{"globalCancel", EShortcut::GLOBAL_CANCEL },
{"globalReturn", EShortcut::GLOBAL_RETURN },
{"globalFullscreen", EShortcut::GLOBAL_FULLSCREEN },
{"globalOptions", EShortcut::GLOBAL_OPTIONS },
{"globalBackspace", EShortcut::GLOBAL_BACKSPACE },
{"globalMoveFocus", EShortcut::GLOBAL_MOVE_FOCUS },
{"moveLeft", EShortcut::MOVE_LEFT },
{"moveRight", EShortcut::MOVE_RIGHT },
{"moveUp", EShortcut::MOVE_UP },
{"moveDown", EShortcut::MOVE_DOWN },
{"moveFirst", EShortcut::MOVE_FIRST },
{"moveLast", EShortcut::MOVE_LAST },
{"movePageUp", EShortcut::MOVE_PAGE_UP },
{"movePageDown", EShortcut::MOVE_PAGE_DOWN },
{"selectIndex1", EShortcut::SELECT_INDEX_1 },
{"selectIndex2", EShortcut::SELECT_INDEX_2 },
{"selectIndex3", EShortcut::SELECT_INDEX_3 },
{"selectIndex4", EShortcut::SELECT_INDEX_4 },
{"selectIndex5", EShortcut::SELECT_INDEX_5 },
{"selectIndex6", EShortcut::SELECT_INDEX_6 },
{"selectIndex7", EShortcut::SELECT_INDEX_7 },
{"selectIndex8", EShortcut::SELECT_INDEX_8 },
{"mainMenuNewGame", EShortcut::MAIN_MENU_NEW_GAME },
{"mainMenuLoadGame", EShortcut::MAIN_MENU_LOAD_GAME },
{"mainMenuHighScores", EShortcut::MAIN_MENU_HIGH_SCORES },
{"mainMenuCredits", EShortcut::MAIN_MENU_CREDITS },
{"mainMenuQuit", EShortcut::MAIN_MENU_QUIT },
{"mainMenuBack", EShortcut::MAIN_MENU_BACK },
{"mainMenuSingleplayer", EShortcut::MAIN_MENU_SINGLEPLAYER },
{"mainMenuMultiplayer", EShortcut::MAIN_MENU_MULTIPLAYER },
{"mainMenuCampaign", EShortcut::MAIN_MENU_CAMPAIGN },
{"mainMenuTutorial", EShortcut::MAIN_MENU_TUTORIAL },
{"mainMenuCampaignSod", EShortcut::MAIN_MENU_CAMPAIGN_SOD },
{"mainMenuCampaignRoe", EShortcut::MAIN_MENU_CAMPAIGN_ROE },
{"mainMenuCampaignAb", EShortcut::MAIN_MENU_CAMPAIGN_AB },
{"mainMenuCampaignCustom", EShortcut::MAIN_MENU_CAMPAIGN_CUSTOM },
{"lobbyBeginGame", EShortcut::LOBBY_BEGIN_GAME },
{"lobbyLoadGame", EShortcut::LOBBY_LOAD_GAME },
{"lobbySaveGame", EShortcut::LOBBY_SAVE_GAME },
{"lobbyRandomMap", EShortcut::LOBBY_RANDOM_MAP },
{"lobbyHideChat", EShortcut::LOBBY_HIDE_CHAT },
{"lobbyAdditionalOptions", EShortcut::LOBBY_ADDITIONAL_OPTIONS },
{"lobbySelectScenario", EShortcut::LOBBY_SELECT_SCENARIO },
{"gameEndTurn", EShortcut::GAME_END_TURN },
{"gameLoadGame", EShortcut::GAME_LOAD_GAME },
{"gameSaveGame", EShortcut::GAME_SAVE_GAME },
{"gameRestartGame", EShortcut::GAME_RESTART_GAME },
{"gameMainMenu", EShortcut::GAME_TO_MAIN_MENU },
{"gameQuitGame", EShortcut::GAME_QUIT_GAME },
{"gameOpenMarketplace", EShortcut::GAME_OPEN_MARKETPLACE },
{"gameOpenThievesGuild", EShortcut::GAME_OPEN_THIEVES_GUILD },
{"gameActivateConsole", EShortcut::GAME_ACTIVATE_CONSOLE },
{"adventureGameOptions", EShortcut::ADVENTURE_GAME_OPTIONS },
{"adventureToggleGrid", EShortcut::ADVENTURE_TOGGLE_GRID },
{"adventureToggleSleep", EShortcut::ADVENTURE_TOGGLE_SLEEP },
{"adventureMoveHero", EShortcut::ADVENTURE_MOVE_HERO },
{"adventureVisitObject", EShortcut::ADVENTURE_VISIT_OBJECT },
{"adventureMoveHeroSW", EShortcut::ADVENTURE_MOVE_HERO_SW },
{"adventureMoveHeroSS", EShortcut::ADVENTURE_MOVE_HERO_SS },
{"adventureMoveHeroSE", EShortcut::ADVENTURE_MOVE_HERO_SE },
{"adventureMoveHeroWW", EShortcut::ADVENTURE_MOVE_HERO_WW },
{"adventureMoveHeroEE", EShortcut::ADVENTURE_MOVE_HERO_EE },
{"adventureMoveHeroNW", EShortcut::ADVENTURE_MOVE_HERO_NW },
{"adventureMoveHeroNN", EShortcut::ADVENTURE_MOVE_HERO_NN },
{"adventureMoveHeroNE", EShortcut::ADVENTURE_MOVE_HERO_NE },
{"adventureViewSelected", EShortcut::ADVENTURE_VIEW_SELECTED },
{"adventureNextObject", EShortcut::ADVENTURE_NEXT_OBJECT },
{"adventureNextTown", EShortcut::ADVENTURE_NEXT_TOWN },
{"adventureNextHero", EShortcut::ADVENTURE_NEXT_HERO },
{"adventureFirstTown", EShortcut::ADVENTURE_FIRST_TOWN },
{"adventureFirstHero", EShortcut::ADVENTURE_FIRST_HERO },
{"adventureViewScenario", EShortcut::ADVENTURE_VIEW_SCENARIO },
{"adventureDigGrail", EShortcut::ADVENTURE_DIG_GRAIL },
{"adventureViewPuzzle", EShortcut::ADVENTURE_VIEW_PUZZLE },
{"adventureViewWorld", EShortcut::ADVENTURE_VIEW_WORLD },
{"adventureToggleMapLevel", EShortcut::ADVENTURE_TOGGLE_MAP_LEVEL},
{"adventureKingdomOverview", EShortcut::ADVENTURE_KINGDOM_OVERVIEW},
{"adventureQuestLog", EShortcut::ADVENTURE_QUEST_LOG },
{"adventureCastSpell", EShortcut::ADVENTURE_CAST_SPELL },
{"adventureEndTurn", EShortcut::ADVENTURE_END_TURN },
{"adventureThievesGuild", EShortcut::ADVENTURE_THIEVES_GUILD },
{"battleToggleQueue", EShortcut::BATTLE_TOGGLE_QUEUE },
{"battleUseCreatureSpell", EShortcut::BATTLE_USE_CREATURE_SPELL },
{"battleSurrender", EShortcut::BATTLE_SURRENDER },
{"battleRetreat", EShortcut::BATTLE_RETREAT },
{"battleAutocombat", EShortcut::BATTLE_AUTOCOMBAT },
{"battleCastSpell", EShortcut::BATTLE_CAST_SPELL },
{"battleWait", EShortcut::BATTLE_WAIT },
{"battleDefend", EShortcut::BATTLE_DEFEND },
{"battleConsoleUp", EShortcut::BATTLE_CONSOLE_UP },
{"battleConsoleDown", EShortcut::BATTLE_CONSOLE_DOWN },
{"battleTacticsNext", EShortcut::BATTLE_TACTICS_NEXT },
{"battleTacticsEnd", EShortcut::BATTLE_TACTICS_END },
{"battleSelectAction", EShortcut::BATTLE_SELECT_ACTION },
{"townOpenTavern", EShortcut::TOWN_OPEN_TAVERN },
{"townSwapArmies", EShortcut::TOWN_SWAP_ARMIES },
{"recruitmentMax", EShortcut::RECRUITMENT_MAX },
{"recruitmentMin", EShortcut::RECRUITMENT_MIN },
{"recruitmentUpgrade", EShortcut::RECRUITMENT_UPGRADE },
{"recruitmentUpgradeAll", EShortcut::RECRUITMENT_UPGRADE_ALL },
{"kingdomHeroesTab", EShortcut::KINGDOM_HEROES_TAB },
{"kingdomTownsTab", EShortcut::KINGDOM_TOWNS_TAB },
{"heroDismiss", EShortcut::HERO_DISMISS },
{"heroCommander", EShortcut::HERO_COMMANDER },
{"heroLooseFormation", EShortcut::HERO_LOOSE_FORMATION },
{"heroTightFormation", EShortcut::HERO_TIGHT_FORMATION },
{"heroToggleTactics", EShortcut::HERO_TOGGLE_TACTICS },
{"spellbookTabAdventure", EShortcut::SPELLBOOK_TAB_ADVENTURE },
{"spellbookTabCombat", EShortcut::SPELLBOOK_TAB_COMBAT }
};
if (shortcutNames.count(identifier))
return shortcutNames.at(identifier);
return EShortcut::NONE;
}

View File

@ -0,0 +1,24 @@
/*
* ShortcutHandler.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
enum class EShortcut;
using SDL_Keycode = int32_t;
class ShortcutHandler
{
public:
/// returns list of shortcuts assigned to provided SDL keycode
std::vector<EShortcut> translateKeycode(SDL_Keycode key) const;
/// attempts to find shortcut by its unique identifier. Returns EShortcut::NONE on failure
EShortcut findShortcut(const std::string & identifier ) const;
};

View File

@ -33,6 +33,7 @@
#include "../render/IImage.h"
#include "../render/CAnimation.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../../lib/filesystem/Filesystem.h"
#include "../../lib/CGeneralTextHandler.h"
@ -67,9 +68,9 @@ CBonusSelection::CBonusSelection()
panelBackground = std::make_shared<CPicture>("CAMPBRF.BMP", 456, 6);
buttonStart = std::make_shared<CButton>(Point(475, 536), "CBBEGIB.DEF", CButton::tooltip(), std::bind(&CBonusSelection::startMap, this), SDLK_RETURN);
buttonRestart = std::make_shared<CButton>(Point(475, 536), "CBRESTB.DEF", CButton::tooltip(), std::bind(&CBonusSelection::restartMap, this), SDLK_RETURN);
buttonBack = std::make_shared<CButton>(Point(624, 536), "CBCANCB.DEF", CButton::tooltip(), std::bind(&CBonusSelection::goBack, this), SDLK_ESCAPE);
buttonStart = std::make_shared<CButton>(Point(475, 536), "CBBEGIB.DEF", CButton::tooltip(), std::bind(&CBonusSelection::startMap, this), EShortcut::GLOBAL_ACCEPT);
buttonRestart = std::make_shared<CButton>(Point(475, 536), "CBRESTB.DEF", CButton::tooltip(), std::bind(&CBonusSelection::restartMap, this), EShortcut::GLOBAL_ACCEPT);
buttonBack = std::make_shared<CButton>(Point(624, 536), "CBCANCB.DEF", CButton::tooltip(), std::bind(&CBonusSelection::goBack, this), EShortcut::GLOBAL_CANCEL);
campaignName = std::make_shared<CLabel>(481, 28, FONT_BIG, ETextAlignment::TOPLEFT, Colors::YELLOW, CSH->si->getCampaignName());

View File

@ -17,6 +17,7 @@
#include "../CServerHandler.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../widgets/Buttons.h"
#include "../windows/InfoWindows.h"
@ -40,17 +41,17 @@ CLobbyScreen::CLobbyScreen(ESelectionScreen screenType)
{
tabSel->callOnSelect = std::bind(&IServerAPI::setMapInfo, CSH, _1, nullptr);
buttonSelect = std::make_shared<CButton>(Point(411, 80), "GSPBUTT.DEF", CGI->generaltexth->zelp[45], 0, SDLK_s);
buttonSelect = std::make_shared<CButton>(Point(411, 80), "GSPBUTT.DEF", CGI->generaltexth->zelp[45], 0, EShortcut::LOBBY_SELECT_SCENARIO);
buttonSelect->addCallback([&]()
{
toggleTab(tabSel);
CSH->setMapInfo(tabSel->getSelectedMapInfo());
});
buttonOptions = std::make_shared<CButton>(Point(411, 510), "GSPBUTT.DEF", CGI->generaltexth->zelp[46], std::bind(&CLobbyScreen::toggleTab, this, tabOpt), SDLK_a);
buttonOptions = std::make_shared<CButton>(Point(411, 510), "GSPBUTT.DEF", CGI->generaltexth->zelp[46], std::bind(&CLobbyScreen::toggleTab, this, tabOpt), EShortcut::LOBBY_ADDITIONAL_OPTIONS);
};
buttonChat = std::make_shared<CButton>(Point(619, 83), "GSPBUT2.DEF", CGI->generaltexth->zelp[48], std::bind(&CLobbyScreen::toggleChat, this), SDLK_h);
buttonChat = std::make_shared<CButton>(Point(619, 83), "GSPBUT2.DEF", CGI->generaltexth->zelp[48], std::bind(&CLobbyScreen::toggleChat, this), EShortcut::LOBBY_HIDE_CHAT);
buttonChat->addTextOverlay(CGI->generaltexth->allTexts[532], FONT_SMALL);
switch(screenType)
@ -60,7 +61,7 @@ CLobbyScreen::CLobbyScreen(ESelectionScreen screenType)
tabOpt = std::make_shared<OptionsTab>();
tabRand = std::make_shared<RandomMapTab>();
tabRand->mapInfoChanged += std::bind(&IServerAPI::setMapInfo, CSH, _1, _2);
buttonRMG = std::make_shared<CButton>(Point(411, 105), "GSPBUTT.DEF", CGI->generaltexth->zelp[47], 0, SDLK_r);
buttonRMG = std::make_shared<CButton>(Point(411, 105), "GSPBUTT.DEF", CGI->generaltexth->zelp[47], 0, EShortcut::LOBBY_RANDOM_MAP);
buttonRMG->addCallback([&]()
{
toggleTab(tabRand);
@ -69,30 +70,28 @@ CLobbyScreen::CLobbyScreen(ESelectionScreen screenType)
card->iconDifficulty->addCallback(std::bind(&IServerAPI::setDifficulty, CSH, _1));
buttonStart = std::make_shared<CButton>(Point(411, 535), "SCNRBEG.DEF", CGI->generaltexth->zelp[103], std::bind(&CLobbyScreen::startScenario, this, true), SDLK_b);
buttonStart = std::make_shared<CButton>(Point(411, 535), "SCNRBEG.DEF", CGI->generaltexth->zelp[103], std::bind(&CLobbyScreen::startScenario, this, true), EShortcut::LOBBY_BEGIN_GAME);
initLobby();
break;
}
case ESelectionScreen::loadGame:
{
tabOpt = std::make_shared<OptionsTab>();
buttonStart = std::make_shared<CButton>(Point(411, 535), "SCNRLOD.DEF", CGI->generaltexth->zelp[103], std::bind(&CLobbyScreen::startScenario, this, true), SDLK_l);
buttonStart = std::make_shared<CButton>(Point(411, 535), "SCNRLOD.DEF", CGI->generaltexth->zelp[103], std::bind(&CLobbyScreen::startScenario, this, true), EShortcut::LOBBY_LOAD_GAME);
initLobby();
break;
}
case ESelectionScreen::campaignList:
tabSel->callOnSelect = std::bind(&IServerAPI::setMapInfo, CSH, _1, nullptr);
buttonStart = std::make_shared<CButton>(Point(411, 535), "SCNRLOD.DEF", CButton::tooltip(), std::bind(&CLobbyScreen::startCampaign, this), SDLK_b);
buttonStart = std::make_shared<CButton>(Point(411, 535), "SCNRLOD.DEF", CButton::tooltip(), std::bind(&CLobbyScreen::startCampaign, this), EShortcut::LOBBY_BEGIN_GAME);
break;
}
buttonStart->assignedKeys.insert(SDLK_RETURN);
buttonBack = std::make_shared<CButton>(Point(581, 535), "SCNRBACK.DEF", CGI->generaltexth->zelp[105], [&]()
{
CSH->sendClientDisconnecting();
close();
}, SDLK_ESCAPE);
}, EShortcut::GLOBAL_CANCEL);
}
CLobbyScreen::~CLobbyScreen()

View File

@ -15,6 +15,7 @@
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../widgets/Buttons.h"
#include "../widgets/TextControls.h"
@ -39,8 +40,7 @@ CSavingScreen::CSavingScreen()
tabSel->toggleMode();
tabSel->callOnSelect = std::bind(&CSavingScreen::changeSelection, this, _1);
buttonStart = std::make_shared<CButton>(Point(411, 535), "SCNRSAV.DEF", CGI->generaltexth->zelp[103], std::bind(&CSavingScreen::saveGame, this), SDLK_s);
buttonStart->assignedKeys.insert(SDLK_RETURN);
buttonStart = std::make_shared<CButton>(Point(411, 535), "SCNRSAV.DEF", CGI->generaltexth->zelp[103], std::bind(&CSavingScreen::saveGame, this), EShortcut::LOBBY_SAVE_GAME);
}
const CMapInfo * CSavingScreen::getMapInfo()

View File

@ -15,6 +15,7 @@
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../widgets/Buttons.h"
#include "../../CCallback.h"
@ -43,7 +44,7 @@ CScenarioInfoScreen::CScenarioInfoScreen()
card->changeSelection();
card->iconDifficulty->setSelected(getCurrentDifficulty());
buttonBack = std::make_shared<CButton>(Point(584, 535), "SCNRBACK.DEF", CGI->generaltexth->zelp[105], [=](){ close();}, SDLK_ESCAPE);
buttonBack = std::make_shared<CButton>(Point(584, 535), "SCNRBACK.DEF", CGI->generaltexth->zelp[105], [=](){ close();}, EShortcut::GLOBAL_CANCEL);
}
CScenarioInfoScreen::~CScenarioInfoScreen()

View File

@ -25,6 +25,7 @@
#include "../CPlayerInterface.h"
#include "../CServerHandler.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../mainmenu/CMainMenu.h"
#include "../widgets/CComponent.h"
#include "../widgets/Buttons.h"
@ -84,7 +85,7 @@ CSelectionBase::CSelectionBase(ESelectionScreen type)
}
pos = background->center();
card = std::make_shared<InfoCard>();
buttonBack = std::make_shared<CButton>(Point(581, 535), "SCNRBACK.DEF", CGI->generaltexth->zelp[105], [=](){ close();}, SDLK_ESCAPE);
buttonBack = std::make_shared<CButton>(Point(581, 535), "SCNRBACK.DEF", CGI->generaltexth->zelp[105], [=](){ close();}, EShortcut::GLOBAL_CANCEL);
}
void CSelectionBase::toggleTab(std::shared_ptr<CIntObject> tab)
@ -318,9 +319,9 @@ CChatBox::CChatBox(const Rect & rect)
chatHistory->label->color = Colors::GREEN;
}
void CChatBox::keyPressed(const SDL_Keycode & key)
void CChatBox::keyPressed(EShortcut key)
{
if(key == SDLK_RETURN && inputBox->getText().size())
if(key == EShortcut::GLOBAL_ACCEPT && inputBox->getText().size())
{
CSH->sendMessage(inputBox->getText());
inputBox->setText("");

View File

@ -120,7 +120,7 @@ public:
CChatBox(const Rect & rect);
void keyPressed(const SDL_Keycode & key) override;
void keyPressed(EShortcut key) override;
void addNewMessage(const std::string & text);
};

View File

@ -17,6 +17,7 @@
#include "../CPlayerInterface.h"
#include "../CServerHandler.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../widgets/CComponent.h"
#include "../widgets/Buttons.h"
#include "../widgets/MiscWidgets.h"
@ -281,27 +282,27 @@ void SelectionTab::clickLeft(tribool down, bool previousState)
}
}
void SelectionTab::keyPressed(const SDL_Keycode & key)
void SelectionTab::keyPressed(EShortcut key)
{
int moveBy = 0;
switch(key)
{
case SDLK_UP:
case EShortcut::MOVE_UP:
moveBy = -1;
break;
case SDLK_DOWN:
case EShortcut::MOVE_DOWN:
moveBy = +1;
break;
case SDLK_PAGEUP:
case EShortcut::MOVE_PAGE_UP:
moveBy = -(int)listItems.size() + 1;
break;
case SDLK_PAGEDOWN:
case EShortcut::MOVE_PAGE_DOWN:
moveBy = +(int)listItems.size() - 1;
break;
case SDLK_HOME:
case EShortcut::MOVE_FIRST:
select(-slider->getValue());
return;
case SDLK_END:
case EShortcut::MOVE_LAST:
select((int)curItems.size() - slider->getValue());
return;
default:

View File

@ -66,7 +66,7 @@ public:
void toggleMode();
void clickLeft(tribool down, bool previousState) override;
void keyPressed(const SDL_Keycode & key) override;
void keyPressed(EShortcut key) override;
void onDoubleClick() override;

View File

@ -19,6 +19,7 @@
#include "../CPlayerInterface.h"
#include "../CServerHandler.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../widgets/CComponent.h"
#include "../widgets/Buttons.h"
#include "../widgets/MiscWidgets.h"
@ -77,7 +78,7 @@ std::shared_ptr<CButton> CCampaignScreen::createExitButton(const JsonNode & butt
if(!button["help"].isNull() && button["help"].Float() > 0)
help = CGI->generaltexth->zelp[(size_t)button["help"].Float()];
return std::make_shared<CButton>(Point((int)button["x"].Float(), (int)button["y"].Float()), button["name"].String(), help, [=](){ close();}, (int)button["hotkey"].Float());
return std::make_shared<CButton>(Point((int)button["x"].Float(), (int)button["y"].Float()), button["name"].String(), help, [=](){ close();}, EShortcut::GLOBAL_CANCEL);
}
CCampaignScreen::CCampaignButton::CCampaignButton(const JsonNode & config)

View File

@ -19,6 +19,8 @@
#include "../gui/CursorHandler.h"
#include "../windows/GUIClasses.h"
#include "../gui/CGuiHandler.h"
#include "../gui/ShortcutHandler.h"
#include "../gui/Shortcut.h"
#include "../widgets/CComponent.h"
#include "../widgets/Buttons.h"
#include "../widgets/MiscWidgets.h"
@ -230,7 +232,9 @@ std::shared_ptr<CButton> CMenuEntry::createButton(CMenuScreen * parent, const Js
if(posy < 0)
posy = pos.h + posy;
auto result = std::make_shared<CButton>(Point(posx, posy), button["name"].String(), help, command, (int)button["hotkey"].Float());
EShortcut shortcut = GH.shortcutsHandler().findShortcut(button["shortcut"].String());
auto result = std::make_shared<CButton>(Point(posx, posy), button["name"].String(), help, command, shortcut);
if (button["center"].Bool())
result->moveBy(Point(-result->pos.w/2, -result->pos.h/2));
@ -382,7 +386,7 @@ CMultiMode::CMultiMode(ESelectionScreen ScreenType)
buttonHotseat = std::make_shared<CButton>(Point(373, 78), "MUBHOT.DEF", CGI->generaltexth->zelp[266], std::bind(&CMultiMode::hostTCP, this));
buttonHost = std::make_shared<CButton>(Point(373, 78 + 57 * 1), "MUBHOST.DEF", CButton::tooltip("Host TCP/IP game", ""), std::bind(&CMultiMode::hostTCP, this));
buttonJoin = std::make_shared<CButton>(Point(373, 78 + 57 * 2), "MUBJOIN.DEF", CButton::tooltip("Join TCP/IP game", ""), std::bind(&CMultiMode::joinTCP, this));
buttonCancel = std::make_shared<CButton>(Point(373, 424), "MUBCANC.DEF", CGI->generaltexth->zelp[288], [=](){ close();}, SDLK_ESCAPE);
buttonCancel = std::make_shared<CButton>(Point(373, 424), "MUBCANC.DEF", CGI->generaltexth->zelp[288], [=](){ close();}, EShortcut::GLOBAL_CANCEL);
}
void CMultiMode::hostTCP()
@ -422,8 +426,8 @@ CMultiPlayers::CMultiPlayers(const std::string & firstPlayer, ESelectionScreen S
inputNames[i]->cb += std::bind(&CMultiPlayers::onChange, this, _1);
}
buttonOk = std::make_shared<CButton>(Point(95, 338), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], std::bind(&CMultiPlayers::enterSelectionScreen, this), SDLK_RETURN);
buttonCancel = std::make_shared<CButton>(Point(205, 338), "MUBCANC.DEF", CGI->generaltexth->zelp[561], [=](){ close();}, SDLK_ESCAPE);
buttonOk = std::make_shared<CButton>(Point(95, 338), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], std::bind(&CMultiPlayers::enterSelectionScreen, this), EShortcut::GLOBAL_ACCEPT);
buttonCancel = std::make_shared<CButton>(Point(205, 338), "MUBCANC.DEF", CGI->generaltexth->zelp[561], [=](){ close();}, EShortcut::GLOBAL_CANCEL);
statusBar = CGStatusBar::create(std::make_shared<CPicture>(background->getSurface(), Rect(7, 381, 348, 18), 7, 381));
inputNames[0]->setText(firstPlayer, true);
@ -471,14 +475,14 @@ CSimpleJoinScreen::CSimpleJoinScreen(bool host)
inputAddress->cb += std::bind(&CSimpleJoinScreen::onChange, this, _1);
inputPort->cb += std::bind(&CSimpleJoinScreen::onChange, this, _1);
inputPort->filters += std::bind(&CTextInput::numberFilter, _1, _2, 0, 65535);
buttonOk = std::make_shared<CButton>(Point(26, 142), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], std::bind(&CSimpleJoinScreen::connectToServer, this), SDLK_RETURN);
buttonOk = std::make_shared<CButton>(Point(26, 142), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], std::bind(&CSimpleJoinScreen::connectToServer, this), EShortcut::GLOBAL_ACCEPT);
inputAddress->giveFocus();
}
inputAddress->setText(host ? CServerHandler::localhostAddress : CSH->getHostAddress(), true);
inputPort->setText(std::to_string(CSH->getHostPort()), true);
buttonCancel = std::make_shared<CButton>(Point(142, 142), "MUBCANC.DEF", CGI->generaltexth->zelp[561], std::bind(&CSimpleJoinScreen::leaveScreen, this), SDLK_ESCAPE);
buttonCancel = std::make_shared<CButton>(Point(142, 142), "MUBCANC.DEF", CGI->generaltexth->zelp[561], std::bind(&CSimpleJoinScreen::leaveScreen, this), EShortcut::GLOBAL_CANCEL);
statusBar = CGStatusBar::create(std::make_shared<CPicture>(background->getSurface(), Rect(7, 186, 218, 18), 7, 186));
}

View File

@ -19,6 +19,7 @@
#include "../battle/BattleInterface.h"
#include "../battle/BattleInterfaceClasses.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../windows/InfoWindows.h"
#include "../render/CAnimation.h"
#include "../renderSDL/SDL_Extensions.h"
@ -223,7 +224,7 @@ void CButton::hover (bool on)
}
}
CButton::CButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help, CFunctionList<void()> Callback, int key, bool playerColoredButton):
CButton::CButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help, CFunctionList<void()> Callback, EShortcut key, bool playerColoredButton):
CKeyShortcut(key),
callback(Callback)
{
@ -345,7 +346,7 @@ void CToggleBase::addCallback(std::function<void(bool)> function)
}
CToggleButton::CToggleButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help,
CFunctionList<void(bool)> callback, int key, bool playerColoredButton):
CFunctionList<void(bool)> callback, EShortcut key, bool playerColoredButton):
CButton(position, defName, help, 0, key, playerColoredButton),
CToggleBase(callback)
{
@ -800,37 +801,37 @@ void CSlider::wheelScrolled(bool down, bool in)
moveTo(value + 3 * (positive ? +scrollStep : -scrollStep));
}
void CSlider::keyPressed(const SDL_Keycode & key)
void CSlider::keyPressed(EShortcut key)
{
int moveDest = value;
switch(key)
{
case SDLK_UP:
case EShortcut::MOVE_UP:
if (!horizontal)
moveDest = value - scrollStep;
break;
case SDLK_LEFT:
case EShortcut::MOVE_LEFT:
if (horizontal)
moveDest = value - scrollStep;
break;
case SDLK_DOWN:
case EShortcut::MOVE_DOWN:
if (!horizontal)
moveDest = value + scrollStep;
break;
case SDLK_RIGHT:
case EShortcut::MOVE_RIGHT:
if (horizontal)
moveDest = value + scrollStep;
break;
case SDLK_PAGEUP:
case EShortcut::MOVE_PAGE_UP:
moveDest = value - capacity + scrollStep;
break;
case SDLK_PAGEDOWN:
case EShortcut::MOVE_PAGE_DOWN:
moveDest = value + capacity - scrollStep;
break;
case SDLK_HOME:
case EShortcut::MOVE_FIRST:
moveDest = 0;
break;
case SDLK_END:
case EShortcut::MOVE_LAST:
moveDest = amount - capacity;
break;
default:

View File

@ -101,7 +101,7 @@ public:
/// Constructor
CButton(Point position, const std::string & defName, const std::pair<std::string, std::string> & help,
CFunctionList<void()> Callback = 0, int key=0, bool playerColoredButton = false );
CFunctionList<void()> Callback = 0, EShortcut key = {}, bool playerColoredButton = false );
/// Appearance modifiers
void setIndex(size_t index, bool playerColoredButton=false);
@ -157,7 +157,7 @@ class CToggleButton : public CButton, public CToggleBase
public:
CToggleButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help,
CFunctionList<void(bool)> Callback = 0, int key=0, bool playerColoredButton = false );
CFunctionList<void(bool)> Callback = 0, EShortcut key = {}, bool playerColoredButton = false );
void clickLeft(tribool down, bool previousState) override;
// bring overrides into scope
@ -276,7 +276,7 @@ public:
void addCallback(std::function<void(int)> callback);
void keyPressed(const SDL_Keycode & key) override;
void keyPressed(EShortcut key) override;
void wheelScrolled(bool down, bool in) override;
void clickLeft(tribool down, bool previousState) override;
void mouseMoved (const Point & cursorPosition) override;

View File

@ -11,6 +11,7 @@
#include "CArtifactHolder.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "CComponent.h"

View File

@ -12,6 +12,7 @@
#include "../gui/CGuiHandler.h"
#include "../gui/CursorHandler.h"
#include "../gui/Shortcut.h"
#include "Buttons.h"
@ -82,8 +83,8 @@ void CArtifactsOfHeroBase::init(
artPlace->leftClickCallback = lClickCallback;
artPlace->rightClickCallback = rClickCallback;
}
leftBackpackRoll = std::make_shared<CButton>(Point(379, 364), "hsbtns3.def", CButton::tooltip(), [scrollHandler]() { scrollHandler(-1); }, SDLK_LEFT);
rightBackpackRoll = std::make_shared<CButton>(Point(632, 364), "hsbtns5.def", CButton::tooltip(), [scrollHandler]() { scrollHandler(+1); }, SDLK_RIGHT);
leftBackpackRoll = std::make_shared<CButton>(Point(379, 364), "hsbtns3.def", CButton::tooltip(), [scrollHandler]() { scrollHandler(-1); }, EShortcut::MOVE_LEFT);
rightBackpackRoll = std::make_shared<CButton>(Point(632, 364), "hsbtns5.def", CButton::tooltip(), [scrollHandler]() { scrollHandler(+1); }, EShortcut::MOVE_RIGHT);
leftBackpackRoll->block(true);
rightBackpackRoll->block(true);
}

View File

@ -19,6 +19,7 @@
#include "../gui/CGuiHandler.h"
#include "../gui/CursorHandler.h"
#include "../gui/TextAlignment.h"
#include "../gui/Shortcut.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../windows/CMessage.h"
#include "../windows/InfoWindows.h"
@ -488,11 +489,12 @@ CComponentBox::CComponentBox(std::vector<std::shared_ptr<CSelectableComponent>>
assert(!components.empty());
int key = SDLK_1;
auto key = EShortcut::SELECT_INDEX_1;
for(auto & comp : _components)
{
comp->onSelect = std::bind(&CComponentBox::selectionChanged, this, comp);
comp->assignedKeys.insert(key++);
comp->assignedKey = key;
key = vstd::next(key, 1);
}
selectionChanged(_components.front());
}

View File

@ -200,7 +200,7 @@ void CMinorResDataBar::showAll(SDL_Surface * to)
{
CIntObject::showAll(to);
for (EGameResID i=EGameResID::WOOD; i<=EGameResID::GOLD; vstd::advance(i, 1))
for (GameResID i=EGameResID::WOOD; i<=EGameResID::GOLD; ++i)
{
std::string text = std::to_string(LOCPLINT->cb->getResourceAmount(i));

View File

@ -15,6 +15,7 @@
#include "../CPlayerInterface.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../windows/CMessage.h"
#include "../adventureMap/CInGameConsole.h"
#include "../renderSDL/SDL_Extensions.h"
@ -555,12 +556,12 @@ void CTextInput::clickLeft(tribool down, bool previousState)
giveFocus();
}
void CTextInput::keyPressed(const SDL_Keycode & key)
void CTextInput::keyPressed(EShortcut key)
{
if(!focus)
return;
if(key == SDLK_TAB)
if(key == EShortcut::GLOBAL_MOVE_FOCUS)
{
moveFocus();
GH.breakEventHandling();
@ -571,9 +572,7 @@ void CTextInput::keyPressed(const SDL_Keycode & key)
switch(key)
{
case SDLK_DELETE: // have index > ' ' so it won't be filtered out by default section
return;
case SDLK_BACKSPACE:
case EShortcut::GLOBAL_BACKSPACE:
if(!newText.empty())
{
TextOperations::trimRightUnicode(newText);
@ -608,9 +607,9 @@ void CTextInput::setText(const std::string & nText, bool callCb)
cb(text);
}
bool CTextInput::captureThisKey(const SDL_Keycode & key)
bool CTextInput::captureThisKey(EShortcut key)
{
if(key == SDLK_RETURN || key == SDLK_KP_ENTER || key == SDLK_ESCAPE)
if(key == EShortcut::GLOBAL_RETURN)
return false;
return true;

View File

@ -225,9 +225,9 @@ public:
CTextInput(const Rect & Pos, std::shared_ptr<IImage> srf);
void clickLeft(tribool down, bool previousState) override;
void keyPressed(const SDL_Keycode & key) override;
void keyPressed(EShortcut key) override;
bool captureThisKey(const SDL_Keycode & key) override;
bool captureThisKey(EShortcut key) override;
void textInputed(const std::string & enteredText) override;
void textEdited(const std::string & enteredText) override;

View File

@ -21,6 +21,7 @@
#include "../CPlayerInterface.h"
#include "../PlayerLocalState.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../widgets/MiscWidgets.h"
#include "../widgets/CComponent.h"
#include "../widgets/Buttons.h"
@ -1184,8 +1185,7 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst
income = std::make_shared<CLabel>(195, 443, FONT_SMALL, ETextAlignment::CENTER);
icon = std::make_shared<CAnimImage>("ITPT", 0, 0, 15, 387);
exit = std::make_shared<CButton>(Point(744, 544), "TSBTNS", CButton::tooltip(CGI->generaltexth->tcommands[8]), [&](){close();}, SDLK_RETURN);
exit->assignedKeys.insert(SDLK_ESCAPE);
exit = std::make_shared<CButton>(Point(744, 544), "TSBTNS", CButton::tooltip(CGI->generaltexth->tcommands[8]), [&](){close();}, EShortcut::GLOBAL_RETURN);
exit->setImageOrder(4, 5, 6, 7);
auto split = std::make_shared<CButton>(Point(744, 382), "TSBTNS", CButton::tooltip(CGI->generaltexth->tcommands[3]), [&]()
@ -1308,20 +1308,20 @@ void CCastleInterface::recreateIcons()
}
void CCastleInterface::keyPressed(const SDL_Keycode & key)
void CCastleInterface::keyPressed(EShortcut key)
{
switch(key)
{
case SDLK_UP:
case EShortcut::MOVE_UP:
townlist->selectPrev();
break;
case SDLK_DOWN:
case EShortcut::MOVE_DOWN:
townlist->selectNext();
break;
case SDLK_SPACE:
case EShortcut::TOWN_SWAP_ARMIES:
heroes->swapArmies();
break;
case SDLK_t:
case EShortcut::TOWN_OPEN_TAVERN:
if(town->hasBuilt(BuildingID::TAVERN))
LOCPLINT->showTavernWindow(town);
break;
@ -1420,8 +1420,7 @@ CHallInterface::CHallInterface(const CGTownInstance * Town):
statusbar = CGStatusBar::create(statusbarBackground);
title = std::make_shared<CLabel>(399, 12, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, town->town->buildings.at(BuildingID(town->hallLevel()+BuildingID::VILLAGE_HALL))->getNameTranslated());
exit = std::make_shared<CButton>(Point(748, 556), "TPMAGE1.DEF", CButton::tooltip(CGI->generaltexth->hcommands[8]), [&](){close();}, SDLK_RETURN);
exit->assignedKeys.insert(SDLK_ESCAPE);
exit = std::make_shared<CButton>(Point(748, 556), "TPMAGE1.DEF", CButton::tooltip(CGI->generaltexth->hcommands[8]), [&](){close();}, EShortcut::GLOBAL_RETURN);
auto & boxList = town->town->clientInfo.hallSlots;
boxes.resize(boxList.size());
@ -1486,11 +1485,11 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin
std::string tooltipYes = boost::str(boost::format(CGI->generaltexth->allTexts[595]) % building->getNameTranslated());
std::string tooltipNo = boost::str(boost::format(CGI->generaltexth->allTexts[596]) % building->getNameTranslated());
buy = std::make_shared<CButton>(Point(45, 446), "IBUY30", CButton::tooltip(tooltipYes), [&](){ buyFunc(); }, SDLK_RETURN);
buy = std::make_shared<CButton>(Point(45, 446), "IBUY30", CButton::tooltip(tooltipYes), [&](){ buyFunc(); }, EShortcut::GLOBAL_ACCEPT);
buy->setBorderColor(Colors::METALLIC_GOLD);
buy->block(state!=7 || LOCPLINT->playerID != town->tempOwner);
cancel = std::make_shared<CButton>(Point(290, 445), "ICANCEL", CButton::tooltip(tooltipNo), [&](){ close();}, SDLK_ESCAPE);
cancel = std::make_shared<CButton>(Point(290, 445), "ICANCEL", CButton::tooltip(tooltipNo), [&](){ close();}, EShortcut::GLOBAL_CANCEL);
cancel->setBorderColor(Colors::METALLIC_GOLD);
}
}
@ -1596,8 +1595,7 @@ CFortScreen::CFortScreen(const CGTownInstance * town):
title = std::make_shared<CLabel>(400, 12, FONT_BIG, ETextAlignment::CENTER, Colors::WHITE, fortBuilding->getNameTranslated());
std::string text = boost::str(boost::format(CGI->generaltexth->fcommands[6]) % fortBuilding->getNameTranslated());
exit = std::make_shared<CButton>(Point(748, 556), "TPMAGE1", CButton::tooltip(text), [&](){ close(); }, SDLK_RETURN);
exit->assignedKeys.insert(SDLK_ESCAPE);
exit = std::make_shared<CButton>(Point(748, 556), "TPMAGE1", CButton::tooltip(text), [&](){ close(); }, EShortcut::GLOBAL_RETURN);
std::vector<Point> positions =
{
@ -1785,8 +1783,7 @@ CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner,std::string imagem)
auto statusbarBackground = std::make_shared<CPicture>(background->getSurface(), barRect, 7, 556);
statusbar = CGStatusBar::create(statusbarBackground);
exit = std::make_shared<CButton>(Point(748, 556), "TPMAGE1.DEF", CButton::tooltip(CGI->generaltexth->allTexts[593]), [&](){ close(); }, SDLK_RETURN);
exit->assignedKeys.insert(SDLK_ESCAPE);
exit = std::make_shared<CButton>(Point(748, 556), "TPMAGE1.DEF", CButton::tooltip(CGI->generaltexth->allTexts[593]), [&](){ close(); }, EShortcut::GLOBAL_RETURN);
static const std::vector<std::vector<Point> > positions =
{
@ -1866,10 +1863,10 @@ CBlacksmithDialog::CBlacksmithDialog(bool possible, CreatureID creMachineID, Art
std::to_string(aid.toArtifact(CGI->artifacts())->getPrice()));
std::string text = boost::str(boost::format(CGI->generaltexth->allTexts[595]) % creature->getNameSingularTranslated());
buy = std::make_shared<CButton>(Point(42, 312), "IBUY30.DEF", CButton::tooltip(text), [&](){ close(); }, SDLK_RETURN);
buy = std::make_shared<CButton>(Point(42, 312), "IBUY30.DEF", CButton::tooltip(text), [&](){ close(); }, EShortcut::GLOBAL_ACCEPT);
text = boost::str(boost::format(CGI->generaltexth->allTexts[596]) % creature->getNameSingularTranslated());
cancel = std::make_shared<CButton>(Point(224, 312), "ICANCEL.DEF", CButton::tooltip(text), [&](){ close(); }, SDLK_ESCAPE);
cancel = std::make_shared<CButton>(Point(224, 312), "ICANCEL.DEF", CButton::tooltip(text), [&](){ close(); }, EShortcut::GLOBAL_CANCEL);
if(possible)
buy->addCallback([=](){ LOCPLINT->cb->buyArtifact(LOCPLINT->cb->getHero(hid),aid); });

View File

@ -246,7 +246,7 @@ public:
void castleTeleport(int where);
void townChange();
void keyPressed(const SDL_Keycode & key) override;
void keyPressed(EShortcut key) override;
void close();
void addBuilding(BuildingID bid);

View File

@ -22,6 +22,7 @@
#include "../widgets/TextControls.h"
#include "../widgets/ObjectLists.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../../CCallback.h"
@ -284,7 +285,7 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
{
LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[12], onDismiss, nullptr);
};
dismiss = std::make_shared<CButton>(Point(5, 5),"IVIEWCR2.DEF", CGI->generaltexth->zelp[445], onClick, SDLK_d);
dismiss = std::make_shared<CButton>(Point(5, 5),"IVIEWCR2.DEF", CGI->generaltexth->zelp[445], onClick, EShortcut::HERO_DISMISS);
}
if(parent->info->upgradeInfo && !parent->info->commander)
@ -321,14 +322,12 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[314], resComps);
}
};
auto upgradeBtn = std::make_shared<CButton>(Point(221 + (int)buttonIndex * 40, 5), "stackWindow/upgradeButton", CGI->generaltexth->zelp[446], onClick, SDLK_1);
auto upgradeBtn = std::make_shared<CButton>(Point(221 + (int)buttonIndex * 40, 5), "stackWindow/upgradeButton", CGI->generaltexth->zelp[446], onClick);
upgradeBtn->addOverlay(std::make_shared<CAnimImage>("CPRSMALL", VLC->creh->objects[upgradeInfo.info.newID[buttonIndex]]->getIconIndex()));
if(buttonsToCreate == 1) // single upgrade avaialbe
{
upgradeBtn->assignedKeys.insert(SDLK_u);
}
upgradeBtn->assignedKey = EShortcut::RECRUITMENT_UPGRADE;
upgrade[buttonIndex] = upgradeBtn;
}
@ -356,8 +355,7 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
parent->switchButtons[parent->activeTab]->disable();
}
exit = std::make_shared<CButton>(Point(382, 5), "hsbtns.def", CGI->generaltexth->zelp[447], [=](){ parent->close(); }, SDLK_RETURN);
exit->assignedKeys.insert(SDLK_ESCAPE);
exit = std::make_shared<CButton>(Point(382, 5), "hsbtns.def", CGI->generaltexth->zelp[447], [=](){ parent->close(); }, EShortcut::GLOBAL_RETURN);
}
CStackWindow::CommanderMainSection::CommanderMainSection(CStackWindow * owner, int yOffset)
@ -457,8 +455,8 @@ CStackWindow::CommanderMainSection::CommanderMainSection(CStackWindow * owner, i
abilities = std::make_shared<CListBox>(onCreate, Point(38, 3+pos.h), Point(63, 0), 6, abilitiesCount);
leftBtn = std::make_shared<CButton>(Point(10, pos.h + 6), "hsbtns3.def", CButton::tooltip(), [=](){ abilities->moveToPrev(); }, SDLK_LEFT);
rightBtn = std::make_shared<CButton>(Point(411, pos.h + 6), "hsbtns5.def", CButton::tooltip(), [=](){ abilities->moveToNext(); }, SDLK_RIGHT);
leftBtn = std::make_shared<CButton>(Point(10, pos.h + 6), "hsbtns3.def", CButton::tooltip(), [=](){ abilities->moveToPrev(); }, EShortcut::MOVE_LEFT);
rightBtn = std::make_shared<CButton>(Point(411, pos.h + 6), "hsbtns5.def", CButton::tooltip(), [=](){ abilities->moveToNext(); }, EShortcut::MOVE_RIGHT);
if(abilitiesCount <= 6)
{

View File

@ -19,6 +19,7 @@
#include "../gui/CGuiHandler.h"
#include "../gui/TextAlignment.h"
#include "../gui/Shortcut.h"
#include "../widgets/MiscWidgets.h"
#include "../widgets/CComponent.h"
#include "../widgets/TextControls.h"
@ -119,22 +120,21 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
statusbar = CGStatusBar::create(7, 559, "ADROLLVR.bmp", 660);
quitButton = std::make_shared<CButton>(Point(609, 516), "hsbtns.def", CButton::tooltip(heroscrn[17]), [=](){ close(); }, SDLK_RETURN);
quitButton->assignedKeys.insert(SDLK_ESCAPE);
quitButton = std::make_shared<CButton>(Point(609, 516), "hsbtns.def", CButton::tooltip(heroscrn[17]), [=](){ close(); }, EShortcut::GLOBAL_RETURN);
dismissLabel = std::make_shared<CTextBox>(CGI->generaltexth->jktexts[8], Rect(370, 430, 65, 35), 0, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE);
dismissButton = std::make_shared<CButton>(Point(454, 429), "hsbtns2.def", CButton::tooltip(heroscrn[28]), [=](){ dismissCurrent(); }, SDLK_d);
dismissButton = std::make_shared<CButton>(Point(454, 429), "hsbtns2.def", CButton::tooltip(heroscrn[28]), [=](){ dismissCurrent(); }, EShortcut::HERO_DISMISS);
questlogLabel = std::make_shared<CTextBox>(CGI->generaltexth->jktexts[9], Rect(510, 430, 65, 35), 0, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE);
questlogButton = std::make_shared<CButton>(Point(314, 429), "hsbtns4.def", CButton::tooltip(heroscrn[0]), [=](){ LOCPLINT->showQuestLog(); }, SDLK_q);
questlogButton = std::make_shared<CButton>(Point(314, 429), "hsbtns4.def", CButton::tooltip(heroscrn[0]), [=](){ LOCPLINT->showQuestLog(); }, EShortcut::ADVENTURE_QUEST_LOG);
formations = std::make_shared<CToggleGroup>(0);
formations->addToggle(0, std::make_shared<CToggleButton>(Point(481, 483), "hsbtns6.def", std::make_pair(heroscrn[23], heroscrn[29]), 0, SDLK_t));
formations->addToggle(1, std::make_shared<CToggleButton>(Point(481, 519), "hsbtns7.def", std::make_pair(heroscrn[24], heroscrn[30]), 0, SDLK_l));
formations->addToggle(0, std::make_shared<CToggleButton>(Point(481, 483), "hsbtns6.def", std::make_pair(heroscrn[23], heroscrn[29]), 0, EShortcut::HERO_TIGHT_FORMATION));
formations->addToggle(1, std::make_shared<CToggleButton>(Point(481, 519), "hsbtns7.def", std::make_pair(heroscrn[24], heroscrn[30]), 0, EShortcut::HERO_LOOSE_FORMATION));
if(hero->commander)
{
commanderButton = std::make_shared<CButton>(Point(317, 18), "buttons/commander", CButton::tooltipLocalized("vcmi.heroWindow.openCommander"), [&](){ commanderWindow(); }, SDLK_c);
commanderButton = std::make_shared<CButton>(Point(317, 18), "buttons/commander", CButton::tooltipLocalized("vcmi.heroWindow.openCommander"), [&](){ commanderWindow(); }, EShortcut::HERO_COMMANDER);
}
//right list of heroes
@ -224,7 +224,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded)
specImage->setFrame(curHero->type->imageIndex);
specName->setText(curHero->type->getSpecialtyNameTranslated());
tacticsButton = std::make_shared<CToggleButton>(Point(539, 483), "hsbtns8.def", std::make_pair(heroscrn[26], heroscrn[31]), 0, SDLK_b);
tacticsButton = std::make_shared<CToggleButton>(Point(539, 483), "hsbtns8.def", std::make_pair(heroscrn[26], heroscrn[31]), 0, EShortcut::HERO_TOGGLE_TACTICS);
tacticsButton->addHoverText(CButton::HIGHLIGHTED, CGI->generaltexth->heroscrn[25]);
dismissButton->addHoverText(CButton::NORMAL, boost::str(boost::format(CGI->generaltexth->heroscrn[16]) % curHero->getNameTranslated() % curHero->type->heroClass->getNameTranslated()));

View File

@ -17,6 +17,7 @@
#include "../CPlayerInterface.h"
#include "../adventureMap/CResDataBar.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../widgets/CComponent.h"
#include "../widgets/TextControls.h"
#include "../widgets/MiscWidgets.h"
@ -613,15 +614,14 @@ void CKingdomInterface::generateButtons()
//Main control buttons
btnHeroes = std::make_shared<CButton>(Point(748, 28+footerPos), "OVBUTN1.DEF", CButton::tooltip(CGI->generaltexth->overview[11], CGI->generaltexth->overview[6]),
std::bind(&CKingdomInterface::activateTab, this, 0), SDLK_h);
std::bind(&CKingdomInterface::activateTab, this, 0), EShortcut::KINGDOM_HEROES_TAB);
btnHeroes->block(true);
btnTowns = std::make_shared<CButton>(Point(748, 64+footerPos), "OVBUTN6.DEF", CButton::tooltip(CGI->generaltexth->overview[12], CGI->generaltexth->overview[7]),
std::bind(&CKingdomInterface::activateTab, this, 1), SDLK_t);
std::bind(&CKingdomInterface::activateTab, this, 1), EShortcut::KINGDOM_TOWNS_TAB);
btnExit = std::make_shared<CButton>(Point(748,99+footerPos), "OVBUTN1.DEF", CButton::tooltip(CGI->generaltexth->allTexts[600]),
std::bind(&CKingdomInterface::close, this), SDLK_RETURN);
btnExit->assignedKeys.insert(SDLK_ESCAPE);
std::bind(&CKingdomInterface::close, this), EShortcut::GLOBAL_RETURN);
btnExit->setImageOrder(3, 4, 5, 6);
//Object list control buttons

View File

@ -16,6 +16,7 @@
#include "../adventureMap/CResDataBar.h"
#include "../gui/CGuiHandler.h"
#include "../gui/TextAlignment.h"
#include "../gui/Shortcut.h"
#include "../mapView/MapView.h"
#include "../widgets/Buttons.h"
#include "../widgets/Images.h"
@ -35,8 +36,7 @@ CPuzzleWindow::CPuzzleWindow(const int3 & GrailPos, double discoveredRatio)
CCS->soundh->playSound(soundBase::OBELISK);
quitb = std::make_shared<CButton>(Point(670, 538), "IOK6432.DEF", CButton::tooltip(CGI->generaltexth->allTexts[599]), std::bind(&CPuzzleWindow::close, this), SDLK_RETURN);
quitb->assignedKeys.insert(SDLK_ESCAPE);
quitb = std::make_shared<CButton>(Point(670, 538), "IOK6432.DEF", CButton::tooltip(CGI->generaltexth->allTexts[599]), std::bind(&CPuzzleWindow::close, this), EShortcut::GLOBAL_RETURN);
quitb->setBorderColor(Colors::METALLIC_GOLD);
mapView = std::make_shared<PuzzleMapView>(Point(8,9), Point(591, 544), grailPos);

View File

@ -14,6 +14,7 @@
#include "../CPlayerInterface.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../widgets/CComponent.h"
#include "../adventureMap/CAdventureMapInterface.h"
#include "../widgets/Buttons.h"
@ -127,7 +128,7 @@ CQuestLog::CQuestLog (const std::vector<QuestInfo> & Quests)
minimap = std::make_shared<CQuestMinimap>(Rect(12, 12, 169, 169));
// TextBox have it's own 4 pixel padding from top at least for English. To achieve 10px from both left and top only add 6px margin
description = std::make_shared<CTextBox>("", Rect(205, 18, 385, DESCRIPTION_HEIGHT_MAX), CSlider::BROWN, FONT_MEDIUM, ETextAlignment::TOPLEFT, Colors::WHITE);
ok = std::make_shared<CButton>(Point(539, 398), "IOKAY.DEF", CGI->generaltexth->zelp[445], std::bind(&CQuestLog::close, this), SDLK_RETURN);
ok = std::make_shared<CButton>(Point(539, 398), "IOKAY.DEF", CGI->generaltexth->zelp[445], std::bind(&CQuestLog::close, this), EShortcut::GLOBAL_ACCEPT);
// Both button and lable are shifted to -2px by x and y to not make them actually look like they're on same line with quests list and ok button
hideCompleteButton = std::make_shared<CToggleButton>(Point(10, 396), "sysopchk.def", CButton::tooltipLocalized("vcmi.questLog.hideComplete"), std::bind(&CQuestLog::toggleComplete, this, _1));
hideCompleteLabel = std::make_shared<CLabel>(46, 398, FONT_MEDIUM, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->translate("vcmi.questLog.hideComplete.hover"));

View File

@ -23,6 +23,7 @@
#include "../battle/BattleInterface.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../widgets/MiscWidgets.h"
#include "../widgets/CComponent.h"
#include "../widgets/TextControls.h"
@ -409,27 +410,24 @@ void CSpellWindow::turnPageRight()
CCS->videoh->openAndPlayVideo("PGTRNRGH.SMK", pos.x+13, pos.y+15);
}
void CSpellWindow::keyPressed(const SDL_Keycode & key)
void CSpellWindow::keyPressed(EShortcut key)
{
if(key == SDLK_ESCAPE || key == SDLK_RETURN)
switch(key)
{
fexitb();
return;
}
else
{
switch(key)
{
case SDLK_LEFT:
case EShortcut::GLOBAL_RETURN:
fexitb();
break;
case EShortcut::MOVE_LEFT:
fLcornerb();
break;
case SDLK_RIGHT:
case EShortcut::MOVE_RIGHT:
fRcornerb();
break;
case SDLK_UP:
case SDLK_DOWN:
case EShortcut::MOVE_UP:
case EShortcut::MOVE_DOWN:
{
bool down = key == SDLK_DOWN;
bool down = key == EShortcut::MOVE_DOWN;
static const int schoolsOrder[] = { 0, 3, 1, 2, 4 };
int index = -1;
while(schoolsOrder[++index] != selectedTab);
@ -439,38 +437,12 @@ void CSpellWindow::keyPressed(const SDL_Keycode & key)
selectSchool(schoolsOrder[index]);
break;
}
case SDLK_c:
case EShortcut::SPELLBOOK_TAB_COMBAT:
fbattleSpellsb();
break;
case SDLK_a:
case EShortcut::SPELLBOOK_TAB_ADVENTURE:
fadvSpellsb();
break;
default://to get rid of warnings
break;
}
//alt + 1234567890-= casts spell from 1 - 12 slot
if(GH.isKeyboardAltDown())
{
SDL_Keycode hlpKey = key;
if(CGuiHandler::isNumKey(hlpKey, false))
{
if(hlpKey == SDLK_KP_PLUS)
hlpKey = SDLK_EQUALS;
else
hlpKey = CGuiHandler::numToDigit(hlpKey);
}
static const SDL_Keycode spellSelectors[] = {SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5, SDLK_6, SDLK_7, SDLK_8, SDLK_9, SDLK_0, SDLK_MINUS, SDLK_EQUALS};
int index = -1;
while(++index < std::size(spellSelectors) && spellSelectors[index] != hlpKey);
if(index >= std::size(spellSelectors))
return;
//try casting spell
spellAreas[index]->clickLeft(false, true);
}
}
}

View File

@ -112,7 +112,7 @@ public:
void selectSchool(int school); //schools: 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic, 4 - all schools
int pagesWithinCurrentTab();
void keyPressed(const SDL_Keycode & key) override;
void keyPressed(EShortcut key) override;
void show(SDL_Surface * to) override;
};

View File

@ -15,6 +15,7 @@
#include "../widgets/Images.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../gui/TextAlignment.h"
#include "../gui/Shortcut.h"
#include "../widgets/Buttons.h"
#include "../widgets/TextControls.h"
#include "../windows/InfoWindows.h"
@ -711,8 +712,7 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket * Market, const CGHeroInsta
initItems(false);
initItems(true);
ok = std::make_shared<CButton>(Point(516, 520), "IOK6432.DEF", CGI->generaltexth->zelp[600], [&](){ close(); }, SDLK_RETURN);
ok->assignedKeys.insert(SDLK_ESCAPE);
ok = std::make_shared<CButton>(Point(516, 520), "IOK6432.DEF", CGI->generaltexth->zelp[600], [&](){ close(); }, EShortcut::GLOBAL_RETURN);
deal = std::make_shared<CButton>(Point(307, 520), "TPMRKB.DEF", CGI->generaltexth->zelp[595], [&](){ makeDeal(); } );
deal->block(true);
@ -1153,8 +1153,7 @@ CAltarWindow::CAltarWindow(const IMarket * Market, const CGHeroInstance * Hero,
statusBar = CGStatusBar::create(std::make_shared<CPicture>(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
ok = std::make_shared<CButton>(Point(516, 520), "IOK6432.DEF", CGI->generaltexth->zelp[568], [&](){ close();}, SDLK_RETURN);
ok->assignedKeys.insert(SDLK_ESCAPE);
ok = std::make_shared<CButton>(Point(516, 520), "IOK6432.DEF", CGI->generaltexth->zelp[568], [&](){ close();}, EShortcut::GLOBAL_RETURN);
deal = std::make_shared<CButton>(Point(269, 520), "ALTSACR.DEF", CGI->generaltexth->zelp[585], std::bind(&CAltarWindow::makeDeal,this));

View File

@ -15,6 +15,7 @@
#include "CCreatureWindow.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../gui/TextAlignment.h"
#include "../widgets/Buttons.h"
#include "../widgets/TextControls.h"
@ -32,12 +33,12 @@ void CreaturePurchaseCard::initButtons()
void CreaturePurchaseCard::initMaxButton()
{
maxButton = std::make_shared<CButton>(Point(pos.x + 52, pos.y + 180), "QuickRecruitmentWindow/QuickRecruitmentAllButton.def", CButton::tooltip(), std::bind(&CSlider::moveToMax,slider), SDLK_LSHIFT);
maxButton = std::make_shared<CButton>(Point(pos.x + 52, pos.y + 180), "QuickRecruitmentWindow/QuickRecruitmentAllButton.def", CButton::tooltip(), std::bind(&CSlider::moveToMax,slider), EShortcut::RECRUITMENT_MAX);
}
void CreaturePurchaseCard::initMinButton()
{
minButton = std::make_shared<CButton>(Point(pos.x, pos.y + 180), "QuickRecruitmentWindow/QuickRecruitmentNoneButton.def", CButton::tooltip(), std::bind(&CSlider::moveToMin,slider), SDLK_LCTRL);
minButton = std::make_shared<CButton>(Point(pos.x, pos.y + 180), "QuickRecruitmentWindow/QuickRecruitmentNoneButton.def", CButton::tooltip(), std::bind(&CSlider::moveToMin,slider), EShortcut::RECRUITMENT_MIN);
}
void CreaturePurchaseCard::initCreatureSwitcherButton()

View File

@ -28,6 +28,7 @@
#include "../gui/CGuiHandler.h"
#include "../gui/CursorHandler.h"
#include "../gui/TextAlignment.h"
#include "../gui/Shortcut.h"
#include "../widgets/CComponent.h"
#include "../widgets/MiscWidgets.h"
@ -210,9 +211,9 @@ CRecruitmentWindow::CRecruitmentWindow(const CGDwelling * Dwelling, int Level, c
slider = std::make_shared<CSlider>(Point(176,279),135,std::bind(&CRecruitmentWindow::sliderMoved,this, _1),0,0,0,true);
maxButton = std::make_shared<CButton>(Point(134, 313), "IRCBTNS.DEF", CGI->generaltexth->zelp[553], std::bind(&CSlider::moveToMax, slider), SDLK_m);
buyButton = std::make_shared<CButton>(Point(212, 313), "IBY6432.DEF", CGI->generaltexth->zelp[554], std::bind(&CRecruitmentWindow::buy, this), SDLK_RETURN);
cancelButton = std::make_shared<CButton>(Point(290, 313), "ICN6432.DEF", CGI->generaltexth->zelp[555], std::bind(&CRecruitmentWindow::close, this), SDLK_ESCAPE);
maxButton = std::make_shared<CButton>(Point(134, 313), "IRCBTNS.DEF", CGI->generaltexth->zelp[553], std::bind(&CSlider::moveToMax, slider), EShortcut::RECRUITMENT_MAX);
buyButton = std::make_shared<CButton>(Point(212, 313), "IBY6432.DEF", CGI->generaltexth->zelp[554], std::bind(&CRecruitmentWindow::buy, this), EShortcut::GLOBAL_ACCEPT);
cancelButton = std::make_shared<CButton>(Point(290, 313), "ICN6432.DEF", CGI->generaltexth->zelp[555], std::bind(&CRecruitmentWindow::close, this), EShortcut::GLOBAL_CANCEL);
title = std::make_shared<CLabel>(243, 32, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW);
availableValue = std::make_shared<CLabel>(205, 253, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
@ -313,8 +314,8 @@ CSplitWindow::CSplitWindow(const CCreature * creature, std::function<void(int, i
int leftMax = total - rightMin;
int rightMax = total - leftMin;
ok = std::make_shared<CButton>(Point(20, 263), "IOK6432", CButton::tooltip(), std::bind(&CSplitWindow::apply, this), SDLK_RETURN);
cancel = std::make_shared<CButton>(Point(214, 263), "ICN6432", CButton::tooltip(), std::bind(&CSplitWindow::close, this), SDLK_ESCAPE);
ok = std::make_shared<CButton>(Point(20, 263), "IOK6432", CButton::tooltip(), std::bind(&CSplitWindow::apply, this), EShortcut::GLOBAL_ACCEPT);
cancel = std::make_shared<CButton>(Point(214, 263), "ICN6432", CButton::tooltip(), std::bind(&CSplitWindow::close, this), EShortcut::GLOBAL_CANCEL);
int sliderPosition = total - leftMin - rightMin;
@ -403,7 +404,7 @@ CLevelWindow::CLevelWindow(const CGHeroInstance * hero, PrimarySkill::PrimarySki
}
portrait = std::make_shared<CAnimImage>("PortraitsLarge", hero->portrait, 0, 170, 66);
ok = std::make_shared<CButton>(Point(297, 413), "IOKAY", CButton::tooltip(), std::bind(&CLevelWindow::close, this), SDLK_RETURN);
ok = std::make_shared<CButton>(Point(297, 413), "IOKAY", CButton::tooltip(), std::bind(&CLevelWindow::close, this), EShortcut::GLOBAL_ACCEPT);
//%s has gained a level.
mainTitle = std::make_shared<CLabel>(192, 33, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, boost::str(boost::format(CGI->generaltexth->allTexts[444]) % hero->getNameTranslated()));
@ -459,9 +460,9 @@ CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj)
rumor = std::make_shared<CTextBox>(rumorText, Rect(32, 190, 330, 68), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
statusbar = CGStatusBar::create(std::make_shared<CPicture>(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
cancel = std::make_shared<CButton>(Point(310, 428), "ICANCEL.DEF", CButton::tooltip(CGI->generaltexth->tavernInfo[7]), std::bind(&CTavernWindow::close, this), SDLK_ESCAPE);
recruit = std::make_shared<CButton>(Point(272, 355), "TPTAV01.DEF", CButton::tooltip(), std::bind(&CTavernWindow::recruitb, this), SDLK_RETURN);
thiefGuild = std::make_shared<CButton>(Point(22, 428), "TPTAV02.DEF", CButton::tooltip(CGI->generaltexth->tavernInfo[5]), std::bind(&CTavernWindow::thievesguildb, this), SDLK_t);
cancel = std::make_shared<CButton>(Point(310, 428), "ICANCEL.DEF", CButton::tooltip(CGI->generaltexth->tavernInfo[7]), std::bind(&CTavernWindow::close, this), EShortcut::GLOBAL_CANCEL);
recruit = std::make_shared<CButton>(Point(272, 355), "TPTAV01.DEF", CButton::tooltip(), std::bind(&CTavernWindow::recruitb, this), EShortcut::GLOBAL_ACCEPT);
thiefGuild = std::make_shared<CButton>(Point(22, 428), "TPTAV02.DEF", CButton::tooltip(CGI->generaltexth->tavernInfo[5]), std::bind(&CTavernWindow::thievesguildb, this), EShortcut::ADVENTURE_THIEVES_GUILD);
if(LOCPLINT->cb->getResourceAmount(EGameResID::GOLD) < GameConstants::HERO_GOLD_COST) //not enough gold
{
@ -982,7 +983,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
luck[b] = std::make_shared<MoraleLuckBox>(false, Rect(Point(212 + 490 * b, 39), Point(32, 32)), true);
}
quit = std::make_shared<CButton>(Point(732, 567), "IOKAY.DEF", CGI->generaltexth->zelp[600], std::bind(&CExchangeWindow::close, this), SDLK_RETURN);
quit = std::make_shared<CButton>(Point(732, 567), "IOKAY.DEF", CGI->generaltexth->zelp[600], std::bind(&CExchangeWindow::close, this), EShortcut::GLOBAL_ACCEPT);
if(queryID.getNum() > 0)
quit->addCallback([=](){ LOCPLINT->cb->selectionMade(0, queryID); });
@ -1098,11 +1099,11 @@ CShipyardWindow::CShipyardWindow(const TResources & cost, int state, BoatId boat
goldPic = std::make_shared<CAnimImage>("RESOURCE",GameResID(EGameResID::GOLD), 0, 100, 244);
woodPic = std::make_shared<CAnimImage>("RESOURCE", GameResID(EGameResID::WOOD), 0, 196, 244);
quit = std::make_shared<CButton>(Point(224, 312), "ICANCEL", CButton::tooltip(CGI->generaltexth->allTexts[599]), std::bind(&CShipyardWindow::close, this), SDLK_ESCAPE);
build = std::make_shared<CButton>(Point(42, 312), "IBUY30", CButton::tooltip(CGI->generaltexth->allTexts[598]), std::bind(&CShipyardWindow::close, this), SDLK_RETURN);
quit = std::make_shared<CButton>(Point(224, 312), "ICANCEL", CButton::tooltip(CGI->generaltexth->allTexts[599]), std::bind(&CShipyardWindow::close, this), EShortcut::GLOBAL_CANCEL);
build = std::make_shared<CButton>(Point(42, 312), "IBUY30", CButton::tooltip(CGI->generaltexth->allTexts[598]), std::bind(&CShipyardWindow::close, this), EShortcut::GLOBAL_ACCEPT);
build->addCallback(onBuy);
for(auto i = EGameResID::WOOD; i <= EGameResID::GOLD; vstd::advance(i, 1))
for(GameResID i = EGameResID::WOOD; i <= EGameResID::GOLD; ++i)
{
if(cost[i] > LOCPLINT->cb->getResourceAmount(i))
{
@ -1202,9 +1203,9 @@ CTransformerWindow::CTransformerWindow(const IMarket * _market, const CGHeroInst
}
}
all = std::make_shared<CButton>(Point(146, 416), "ALTARMY.DEF", CGI->generaltexth->zelp[590], [&](){ addAll(); }, SDLK_a);
convert = std::make_shared<CButton>(Point(269, 416), "ALTSACR.DEF", CGI->generaltexth->zelp[591], [&](){ makeDeal(); }, SDLK_RETURN);
cancel = std::make_shared<CButton>(Point(392, 416), "ICANCEL.DEF", CGI->generaltexth->zelp[592], [&](){ close(); },SDLK_ESCAPE);
all = std::make_shared<CButton>(Point(146, 416), "ALTARMY.DEF", CGI->generaltexth->zelp[590], [&](){ addAll(); }, EShortcut::RECRUITMENT_UPGRADE_ALL);
convert = std::make_shared<CButton>(Point(269, 416), "ALTSACR.DEF", CGI->generaltexth->zelp[591], [&](){ makeDeal(); }, EShortcut::GLOBAL_ACCEPT);
cancel = std::make_shared<CButton>(Point(392, 416), "ICANCEL.DEF", CGI->generaltexth->zelp[592], [&](){ close(); },EShortcut::GLOBAL_CANCEL);
statusbar = CGStatusBar::create(std::make_shared<CPicture>(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
titleLeft = std::make_shared<CLabel>(153, 29,FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[485]);//holding area
@ -1321,7 +1322,7 @@ CUniversityWindow::CUniversityWindow(const CGHeroInstance * _hero, const IMarket
for(int i=0; i<goods.size(); i++)//prepare clickable items
items.push_back(std::make_shared<CItem>(this, goods[i], 54+i*104, 234));
cancel = std::make_shared<CButton>(Point(200, 313), "IOKAY.DEF", CGI->generaltexth->zelp[632], [&](){ close(); }, SDLK_RETURN);
cancel = std::make_shared<CButton>(Point(200, 313), "IOKAY.DEF", CGI->generaltexth->zelp[632], [&](){ close(); }, EShortcut::GLOBAL_ACCEPT);
statusbar = CGStatusBar::create(std::make_shared<CPicture>(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
}
@ -1359,10 +1360,10 @@ CUnivConfirmWindow::CUnivConfirmWindow(CUniversityWindow * owner_, int SKILL, bo
boost::replace_first(text, "%s", CGI->skillh->getByIndex(SKILL)->getNameTranslated());
boost::replace_first(text, "%d", "2000");
confirm = std::make_shared<CButton>(Point(148, 299), "IBY6432.DEF", CButton::tooltip(hoverText, text), [=](){makeDeal(SKILL);}, SDLK_RETURN);
confirm = std::make_shared<CButton>(Point(148, 299), "IBY6432.DEF", CButton::tooltip(hoverText, text), [=](){makeDeal(SKILL);}, EShortcut::GLOBAL_ACCEPT);
confirm->block(!available);
cancel = std::make_shared<CButton>(Point(252,299), "ICANCEL.DEF", CGI->generaltexth->zelp[631], [&](){ close(); }, SDLK_ESCAPE);
cancel = std::make_shared<CButton>(Point(252,299), "ICANCEL.DEF", CGI->generaltexth->zelp[631], [&](){ close(); }, EShortcut::GLOBAL_CANCEL);
statusbar = CGStatusBar::create(std::make_shared<CPicture>(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
}
@ -1382,7 +1383,7 @@ CGarrisonWindow::CGarrisonWindow(const CArmedInstance * up, const CGHeroInstance
auto split = std::make_shared<CButton>(Point(88, 314), "IDV6432.DEF", CButton::tooltip(CGI->generaltexth->tcommands[3], ""), [&](){ garr->splitClick(); } );
garr->addSplitBtn(split);
}
quit = std::make_shared<CButton>(Point(399, 314), "IOK6432.DEF", CButton::tooltip(CGI->generaltexth->tcommands[8], ""), [&](){ close(); }, SDLK_RETURN);
quit = std::make_shared<CButton>(Point(399, 314), "IOK6432.DEF", CButton::tooltip(CGI->generaltexth->tcommands[8], ""), [&](){ close(); }, EShortcut::GLOBAL_ACCEPT);
std::string titleText;
if(down->tempOwner == up->tempOwner)
@ -1432,7 +1433,7 @@ CHillFortWindow::CHillFortWindow(const CGHeroInstance * visitor, const CGObjectI
for(int i = 0; i < slotsCount; i++)
{
upgrade[i] = std::make_shared<CButton>(Point(107 + i * 76, 171), "", CButton::tooltip(getTextForSlot(SlotID(i))), [=](){ makeDeal(SlotID(i)); }, SDLK_1 + i);
upgrade[i] = std::make_shared<CButton>(Point(107 + i * 76, 171), "", CButton::tooltip(getTextForSlot(SlotID(i))), [=](){ makeDeal(SlotID(i)); }, vstd::next(EShortcut::SELECT_INDEX_1, i));
for(auto image : { "APHLF1R.DEF", "APHLF1Y.DEF", "APHLF1G.DEF" })
upgrade[i]->addImage(image);
@ -1443,11 +1444,11 @@ CHillFortWindow::CHillFortWindow(const CGHeroInstance * visitor, const CGObjectI
}
}
upgradeAll = std::make_shared<CButton>(Point(30, 231), "", CButton::tooltip(CGI->generaltexth->allTexts[432]), [&](){ makeDeal(SlotID(slotsCount));}, SDLK_0);
upgradeAll = std::make_shared<CButton>(Point(30, 231), "", CButton::tooltip(CGI->generaltexth->allTexts[432]), [&](){ makeDeal(SlotID(slotsCount));}, EShortcut::RECRUITMENT_UPGRADE_ALL);
for(auto image : { "APHLF4R.DEF", "APHLF4Y.DEF", "APHLF4G.DEF" })
upgradeAll->addImage(image);
quit = std::make_shared<CButton>(Point(294, 275), "IOKAY.DEF", CButton::tooltip(), std::bind(&CHillFortWindow::close, this), SDLK_RETURN);
quit = std::make_shared<CButton>(Point(294, 275), "IOKAY.DEF", CButton::tooltip(), std::bind(&CHillFortWindow::close, this), EShortcut::GLOBAL_ACCEPT);
statusbar = CGStatusBar::create(std::make_shared<CPicture>(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
garr = std::make_shared<CGarrisonInt>(108, 60, 18, Point(), hero, nullptr);
@ -1623,8 +1624,7 @@ CThievesGuildWindow::CThievesGuildWindow(const CGObjectInstance * _owner):
SThievesGuildInfo tgi; //info to be displayed
LOCPLINT->cb->getThievesGuildInfo(tgi, owner);
exitb = std::make_shared<CButton>(Point(748, 556), "TPMAGE1", CButton::tooltip(CGI->generaltexth->allTexts[600]), [&](){ close();}, SDLK_RETURN);
exitb->assignedKeys.insert(SDLK_ESCAPE);
exitb = std::make_shared<CButton>(Point(748, 556), "TPMAGE1", CButton::tooltip(CGI->generaltexth->allTexts[600]), [&](){ close();}, EShortcut::GLOBAL_RETURN);
statusbar = CGStatusBar::create(3, 555, "TStatBar.bmp", 742);
resdatabar = std::make_shared<CMinorResDataBar>();
@ -1820,7 +1820,7 @@ void CObjectListWindow::init(std::shared_ptr<CIntObject> titleWidget_, std::stri
title = std::make_shared<CLabel>(152, 27, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, _title);
descr = std::make_shared<CLabel>(145, 133, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, _descr);
exit = std::make_shared<CButton>( Point(228, 402), "ICANCEL.DEF", CButton::tooltip(), std::bind(&CObjectListWindow::exitPressed, this), SDLK_ESCAPE);
exit = std::make_shared<CButton>( Point(228, 402), "ICANCEL.DEF", CButton::tooltip(), std::bind(&CObjectListWindow::exitPressed, this), EShortcut::GLOBAL_CANCEL);
if(titleWidget)
{
@ -1833,7 +1833,7 @@ void CObjectListWindow::init(std::shared_ptr<CIntObject> titleWidget_, std::stri
Point(14, 151), Point(0, 25), 9, items.size(), 0, 1, Rect(262, -32, 256, 256) );
list->type |= REDRAW_PARENT;
ok = std::make_shared<CButton>(Point(15, 402), "IOKAY.DEF", CButton::tooltip(), std::bind(&CObjectListWindow::elementSelected, this), SDLK_RETURN);
ok = std::make_shared<CButton>(Point(15, 402), "IOKAY.DEF", CButton::tooltip(), std::bind(&CObjectListWindow::elementSelected, this), EShortcut::GLOBAL_ACCEPT);
ok->block(!list->size());
}
@ -1881,28 +1881,28 @@ void CObjectListWindow::changeSelection(size_t which)
selected = which;
}
void CObjectListWindow::keyPressed (const SDL_Keycode & key)
void CObjectListWindow::keyPressed (EShortcut key)
{
int sel = static_cast<int>(selected);
switch(key)
{
break; case SDLK_UP:
break; case EShortcut::MOVE_UP:
sel -=1;
break; case SDLK_DOWN:
break; case EShortcut::MOVE_DOWN:
sel +=1;
break; case SDLK_PAGEUP:
break; case EShortcut::MOVE_PAGE_UP:
sel -=9;
break; case SDLK_PAGEDOWN:
break; case EShortcut::MOVE_PAGE_DOWN:
sel +=9;
break; case SDLK_HOME:
break; case EShortcut::MOVE_FIRST:
sel = 0;
break; case SDLK_END:
break; case EShortcut::MOVE_LAST:
sel = static_cast<int>(items.size());
break; default:

View File

@ -194,7 +194,7 @@ public:
std::shared_ptr<CIntObject> genItem(size_t index);
void elementSelected();//call callback and close this window
void changeSelection(size_t which);
void keyPressed(const SDL_Keycode & key) override;
void keyPressed(EShortcut key) override;
};
class CTavernWindow : public CStatusbarWindow

View File

@ -26,6 +26,7 @@
#include "../windows/CMessage.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../gui/CursorHandler.h"
#include "../gui/Shortcut.h"
#include "../../CCallback.h"
@ -79,9 +80,6 @@ CSelWindow::CSelWindow(const std::string &Text, PlayerColor player, int charperl
text = std::make_shared<CTextBox>(Text, Rect(0, 0, 250, 100), 0, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE);
buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter
buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape
if (buttons.size() > 1 && askID.getNum() >= 0) //cancel button functionality
{
buttons.back()->addCallback([askID]() {
@ -96,8 +94,8 @@ CSelWindow::CSelWindow(const std::string &Text, PlayerColor player, int charperl
addChild(comps[i].get());
components.push_back(comps[i]);
comps[i]->onSelect = std::bind(&CSelWindow::selectionChange,this,i);
if(i<9)
comps[i]->assignedKeys.insert(SDLK_1+i);
if(i<8)
comps[i]->assignedKey = vstd::next(EShortcut::SELECT_INDEX_1,i);
}
CMessage::drawIWindow(this, Text, player);
}
@ -137,10 +135,13 @@ CInfoWindow::CInfoWindow(std::string Text, PlayerColor player, const TCompsInfo
text->resize(text->label->textSize);
}
if(buttons.size())
if(buttons.size() == 1)
buttons.front()->assignedKey = EShortcut::GLOBAL_RETURN;
if(buttons.size() == 2)
{
buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter
buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape
buttons.front()->assignedKey = EShortcut::GLOBAL_ACCEPT;
buttons.back()->assignedKey = EShortcut::GLOBAL_CANCEL;
}
for(auto & comp : comps)

View File

@ -14,6 +14,7 @@
#include "../widgets/Buttons.h"
#include "../widgets/CreatureCostBox.h"
#include "../gui/CGuiHandler.h"
#include "../gui/Shortcut.h"
#include "../../CCallback.h"
#include "../../lib/ResourceSet.h"
#include "../../lib/CCreatureHandler.h"
@ -29,20 +30,19 @@ void QuickRecruitmentWindow::setButtons()
void QuickRecruitmentWindow::setCancelButton()
{
cancelButton = std::make_shared<CButton>(Point((pos.w / 2) + 48, 418), "ICN6432.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_ESCAPE);
cancelButton = std::make_shared<CButton>(Point((pos.w / 2) + 48, 418), "ICN6432.DEF", CButton::tooltip(), [&](){ close(); }, EShortcut::GLOBAL_CANCEL);
cancelButton->setImageOrder(0, 1, 2, 3);
}
void QuickRecruitmentWindow::setBuyButton()
{
buyButton = std::make_shared<CButton>(Point((pos.w / 2) - 32, 418), "IBY6432.DEF", CButton::tooltip(), [&](){ purchaseUnits(); }, SDLK_RETURN);
cancelButton->assignedKeys.insert(SDLK_ESCAPE);
buyButton = std::make_shared<CButton>(Point((pos.w / 2) - 32, 418), "IBY6432.DEF", CButton::tooltip(), [&](){ purchaseUnits(); }, EShortcut::GLOBAL_ACCEPT);
buyButton->setImageOrder(0, 1, 2, 3);
}
void QuickRecruitmentWindow::setMaxButton()
{
maxButton = std::make_shared<CButton>(Point((pos.w/2)-112, 418), "IRCBTNS.DEF", CButton::tooltip(), [&](){ maxAllCards(cards); }, SDLK_m);
maxButton = std::make_shared<CButton>(Point((pos.w/2)-112, 418), "IRCBTNS.DEF", CButton::tooltip(), [&](){ maxAllCards(cards); }, EShortcut::RECRUITMENT_MAX);
maxButton->setImageOrder(0, 1, 2, 3);
}

View File

@ -2,7 +2,7 @@
"roe" :
{
"images" : [ {"x": 0, "y": 0, "name":"CAMPBACK"} ],
"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN", "hotkey" : 27},
"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN" },
"items":
[
{ "x":90, "y":72, "file":"DATA/GOOD1.H3C", "image":"CAMPGD1S", "video":"CGOOD1", "open": true },
@ -22,7 +22,7 @@
{"x": 34, "y": 417, "name":"CAMP1FWX"},//one campaign have special inactive image
{"x": 385, "y": 401, "name":"CAMPNOSC"},//and the last one is not present
],
"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN", "hotkey" : 27},
"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN" },
"items":
[
{ "x":90, "y":72, "file":"DATA/AB.H3C", "image":"CAMP1AB7", "video":"C1ab7", "open": true },
@ -36,7 +36,7 @@
"sod":
{
"images" : [ {"x": 0, "y": 0, "name":"CAMPBKX2"} ],
"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN", "hotkey" : 27},
"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN" },
"items":
[
{ "x":90, "y":72, "file":"DATA/GEM.H3C", "image":"CAMPNB1", "video":"NEW", "open": true },
@ -47,18 +47,18 @@
{ "x":34, "y":417, "file":"DATA/FINAL.H3C", "image":"CAMPUA1", "video":"UNHOLY", "open": true },
{ "x":404, "y":414, "file":"DATA/SECRET.H3C", "image":"CAMPSP1", "video":"SPECTRE", "open": true }
]
},
"wog" :
{
/// wog campaigns, currently has no assigned button in campaign screen and thus unused
"images" : [ {"x": 0, "y": 0, "name":"CAMPZALL"} ],
"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN", "hotkey" : 27},
"items":
[
{ "x":90, "y":72, "file":"DATA/ZC1.H3C", "image":"CAMPZ01", "open": true},
{ "x":539, "y":72, "file":"DATA/ZC2.H3C", "image":"CAMPZ02", "open": true},
{ "x":43, "y":245, "file":"DATA/ZC3.H3C", "image":"CAMPZ03", "open": true},
{ "x":311, "y":242, "file":"DATA/ZC4.H3C", "image":"CAMPZ04", "open": true}
]
}
// "wog" :
// {
// /// wog campaigns, currently has no assigned button in campaign screen and thus unused
// "images" : [ {"x": 0, "y": 0, "name":"CAMPZALL"} ],
// "exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN", "hotkey" : 27},
// "items":
// [
// { "x":90, "y":72, "file":"DATA/ZC1.H3C", "image":"CAMPZ01", "open": true},
// { "x":539, "y":72, "file":"DATA/ZC2.H3C", "image":"CAMPZ02", "open": true},
// { "x":43, "y":245, "file":"DATA/ZC3.H3C", "image":"CAMPZ03", "open": true},
// { "x":311, "y":242, "file":"DATA/ZC4.H3C", "image":"CAMPZ04", "open": true}
// ]
// }
}

View File

@ -17,22 +17,22 @@
"name" : "main",
"buttons":
[
{"x": 644, "y": 70, "center" : true, "name":"MMENUNG", "hotkey" : 110, "help": 3, "command": "to new"},
{"x": 645, "y": 192, "center" : true, "name":"MMENULG", "hotkey" : 108, "help": 4, "command": "to load"},
{"x": 643, "y": 296, "center" : true, "name":"MMENUHS", "hotkey" : 104, "help": 5, "command": "highscores"},
{"x": 643, "y": 414, "center" : true, "name":"MMENUCR", "hotkey" : 99, "help": 6, "command": "to credits"},
{"x": 643, "y": 520, "center" : true, "name":"MMENUQT", "hotkey" : 27, "help": 7, "command": "exit"}
{"x": 644, "y": 70, "center" : true, "name":"MMENUNG", "shortcut" : "mainMenuNew", "help": 3, "command": "to new"},
{"x": 645, "y": 192, "center" : true, "name":"MMENULG", "shortcut" : "mainMenuLoad", "help": 4, "command": "to load"},
{"x": 643, "y": 296, "center" : true, "name":"MMENUHS", "shortcut" : "mainMenuScores", "help": 5, "command": "highscores"},
{"x": 643, "y": 414, "center" : true, "name":"MMENUCR", "shortcut" : "mainMenuCredits", "help": 6, "command": "to credits"},
{"x": 643, "y": 520, "center" : true, "name":"MMENUQT", "shortcut" : "mainMenuQuit", "help": 7, "command": "exit"}
]
},
{
"name" : "new",
"buttons":
[
{"x": 649, "y": 65, "center" : true, "name":"GTSINGL", "hotkey" : 115, "help": 10, "command": "start single"},
{"x": 649, "y": 180, "center" : true, "name":"GTMULTI", "hotkey" : 109, "help": 12, "command": "start multi"},
{"x": 646, "y": 298, "center" : true, "name":"GTCAMPN", "hotkey" : 99, "help": 11, "command": "to campaign"},
{"x": 647, "y": 412, "center" : true, "name":"GTTUTOR", "hotkey" : 116, "help": 13, "command": "start tutorial"},
{"x": 645, "y": 517, "center" : true, "name":"GTBACK", "hotkey" : 27, "help": 14, "command": "to main"}
{"x": 649, "y": 65, "center" : true, "name":"GTSINGL", "shortcut" : "mainMenuSingleplayer", "help": 10, "command": "start single"},
{"x": 649, "y": 180, "center" : true, "name":"GTMULTI", "shortcut" : "mainMenuMultiplayer", "help": 12, "command": "start multi"},
{"x": 646, "y": 298, "center" : true, "name":"GTCAMPN", "shortcut" : "mainMenuCampaign", "help": 11, "command": "to campaign"},
{"x": 647, "y": 412, "center" : true, "name":"GTTUTOR", "shortcut" : "mainMenuTutorial", "help": 13, "command": "start tutorial"},
{"x": 645, "y": 517, "center" : true, "name":"GTBACK", "shortcut" : "mainMenuBack", "help": 14, "command": "to main"}
],
"images": [ {"x": 114, "y": 312, "name":"NEWGAME"} ]
},
@ -40,11 +40,11 @@
"name" : "load",
"buttons":
[
{"x": 649, "y": 65, "center" : true, "name":"GTSINGL", "hotkey" : 115, "help": 10, "command": "load single"},
{"x": 649, "y": 180, "center" : true, "name":"GTMULTI", "hotkey" : 109, "help": 12, "command": "load multi"},
{"x": 646, "y": 298, "center" : true, "name":"GTCAMPN", "hotkey" : 99, "help": 11, "command": "load campaign"},
{"x": 647, "y": 412, "center" : true, "name":"GTTUTOR", "hotkey" : 116, "help": 13, "command": "load tutorial"},
{"x": 645, "y": 517, "center" : true, "name":"GTBACK", "hotkey" : 27, "help": 14, "command": "to main"}
{"x": 649, "y": 65, "center" : true, "name":"GTSINGL", "shortcut" : "mainMenuSingleplayer", "help": 10, "command": "load single"},
{"x": 649, "y": 180, "center" : true, "name":"GTMULTI", "shortcut" : "mainMenuMultiplayer", "help": 12, "command": "load multi"},
{"x": 646, "y": 298, "center" : true, "name":"GTCAMPN", "shortcut" : "mainMenuCampaign", "help": 11, "command": "load campaign"},
{"x": 647, "y": 412, "center" : true, "name":"GTTUTOR", "shortcut" : "mainMenuTutorial", "help": 13, "command": "load tutorial"},
{"x": 645, "y": 517, "center" : true, "name":"GTBACK", "shortcut" : "mainMenuBack", "help": 14, "command": "to main"}
],
"images": [ {"x": 114, "y": 312, "name":"LOADGAME"} ]
},
@ -52,11 +52,11 @@
"name" : "campaign",
"buttons":
[
{"x": 634, "y": 67, "center" : true, "name":"CSSSOD", "hotkey" : 119, "command": "campaigns sod"},
{"x": 637, "y": 181, "center" : true, "name":"CSSROE", "hotkey" : 114, "command": "campaigns roe"},
{"x": 638, "y": 301, "center" : true, "name":"CSSARM", "hotkey" : 97, "command": "campaigns ab"},
{"x": 638, "y": 413, "center" : true, "name":"CSSCUS", "hotkey" : 99, "command": "start campaign"},
{"x": 639, "y": 518, "center" : true, "name":"CSSEXIT", "hotkey" : 27, "command": "to new"}
{"x": 634, "y": 67, "center" : true, "name":"CSSSOD", "shortcut" : "mainMenuCampaignSod", "command": "campaigns sod"},
{"x": 637, "y": 181, "center" : true, "name":"CSSROE", "shortcut" : "mainMenuCampaignRoe", "command": "campaigns roe"},
{"x": 638, "y": 301, "center" : true, "name":"CSSARM", "shortcut" : "mainMenuCampaignAb", "command": "campaigns ab"},
{"x": 638, "y": 413, "center" : true, "name":"CSSCUS", "shortcut" : "mainMenuCampaign", "command": "start campaign"},
{"x": 639, "y": 518, "center" : true, "name":"CSSEXIT", "shortcut" : "mainMenuBack", "command": "to new"}
],
}
]

View File

@ -21,8 +21,7 @@
"position": {"x": 4, "y": 560},
"image": "icm003",
"help": "core.help.381",
"callback": "options",
"hotkey": "o"
"hotkey": "globalOptions"
},
{
@ -31,8 +30,7 @@
"position": {"x": 55, "y": 560},
"image": "icm001",
"help": "core.help.379",
"callback": "surrender",
"hotkey": "s"
"hotkey": "battleSurrender"
},
{
@ -41,8 +39,7 @@
"position": {"x": 106, "y": 560},
"image": "icm002",
"help": "core.help.380",
"callback": "flee",
"hotkey": "r"
"hotkey": "battleRetreat"
},
{
@ -51,8 +48,7 @@
"position": {"x": 157, "y": 560},
"image": "icm004",
"help": "core.help.382",
"callback": "autofight",
"hotkey": "a"
"hotkey": "battleAutocombat"
},
{
@ -61,8 +57,7 @@
"position": {"x": 646, "y": 560},
"image": "icm005",
"help": "core.help.385",
"callback": "spellbook",
"hotkey": "c"
"hotkey": "battleCastSpell"
},
{
@ -71,8 +66,7 @@
"position": {"x": 697, "y": 560},
"image": "icm006",
"help": "core.help.386",
"callback": "wait",
"hotkey": "w"
"hotkey": "battleWait"
},
{
@ -81,8 +75,7 @@
"position": {"x": 748, "y": 560},
"image": "icm007",
"help": "core.help.387",
"callback": "defence",
"hotkey": ["d", "space"]
"hotkey": "battleDefend"
},
{
@ -90,9 +83,8 @@
"name": "consoleUp",
"position": {"x": 625, "y": 560},
"image": "ComSlide",
"callback": "consoleUp",
"imageOrder": [0, 1, 0, 0],
"hotkey": "up"
"hotkey": "battleConsoleUp"
},
{
@ -100,9 +92,8 @@
"name": "consoleDown",
"position": {"x": 625, "y": 579},
"image": "ComSlide",
"callback": "consoleDown",
"imageOrder": [2, 3, 2, 2],
"hotkey": "down"
"hotkey": "battleConsoleDown"
},
{
@ -117,8 +108,7 @@
"name": "tacticNext",
"position": {"x": 213, "y": 560},
"image": "icm011",
"callback": "tacticNext",
"hotkey": "space"
"hotkey": "battleTacticsNext"
},
{
@ -126,8 +116,7 @@
"name": "tacticEnd",
"position": {"x": 419, "y": 560},
"image": "icm012",
"callback": "tacticEnd",
"hotkey": "enter"
"hotkey": "battleTacticsEnd"
}
]
}

View File

@ -47,7 +47,6 @@
"image": "settingsWindow/button32",
"help": "vcmi.systemOptions.resolutionButton",
"callback": "setGameResolution",
"hotkey": "g",
"items":
[
{

View File

@ -103,7 +103,7 @@
"imageOrder": [1, 0, 2, 3],
"help": "core.help.321",
"callback": "loadGame",
"hotkey": "l"
"hotkey": "gameLoadGame"
},
{
"name": "saveButton",
@ -113,7 +113,7 @@
"imageOrder": [1, 0, 2, 3],
"help": "core.help.322",
"callback": "saveGame",
"hotkey": "s"
"hotkey": "gameSaveGame"
},
{
"name": "restartButton",
@ -123,7 +123,7 @@
"imageOrder": [1, 0, 2, 3],
"help": "core.help.323",
"callback": "restartGame",
"hotkey": "r"
"hotkey": "gameRestartGame"
},
{
"name": "mainMenuButton",
@ -133,7 +133,7 @@
"imageOrder": [1, 0, 2, 3],
"help": "core.help.320",
"callback": "returnToMainMenu",
"hotkey": "m"
"hotkey": "gameMainMenu"
},
{
"name": "quitButton",
@ -143,7 +143,7 @@
"imageOrder": [1, 0, 2, 3],
"help": "core.help.324",
"callback": "quitGame",
"hotkey": "q"
"hotkey": "gameQuitGame"
},
{
"name": "closeSettingsButton",
@ -153,7 +153,7 @@
"imageOrder": [1, 0, 2, 3],
"help": "core.help.325",
"callback": "closeWindow",
"hotkey": ["escape", "backspace"]
"hotkey": "globalReturn"
}
]
}

View File

@ -149,7 +149,7 @@ void ResourceSet::nziterator::advance()
{
do
{
vstd::advance(cur.resType, +1);
++cur.resType;
} while(cur.resType < GameConstants::RESOURCE_QUANTITY && !(cur.resVal=rs[cur.resType]));
if(cur.resType >= GameConstants::RESOURCE_QUANTITY)

View File

@ -163,7 +163,7 @@ bool CQuest::checkQuest(const CGHeroInstance * h) const
case MISSION_ARMY:
return checkMissionArmy(this, h);
case MISSION_RESOURCES:
for(auto i = EGameResID::WOOD; i <= EGameResID::GOLD; vstd::advance(i, +1)) //including Mithril ?
for(GameResID i = EGameResID::WOOD; i <= EGameResID::GOLD; ++i) //including Mithril ?
{ //Quest has no direct access to callback
if(CGHeroInstance::cb->getResource(h->tempOwner, i) < static_cast<int>(m7resources[i]))
return false;

View File

@ -7029,7 +7029,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
///Give resources to player
TResources resources;
resources[EGameResID::GOLD] = 100000;
for (auto i = EGameResID::WOOD; i < EGameResID::GOLD; vstd::advance(i, 1))
for (GameResID i = EGameResID::WOOD; i < EGameResID::GOLD; ++i)
resources[i] = 100;
giveResources(player, resources);