mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
Integrated hotkeys with InterfaceObjectConfigurable
This commit is contained in:
parent
dea10e6091
commit
6c637dd8e6
@ -51,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");
|
||||
@ -190,19 +194,7 @@ void BattleWindow::keyPressed(EShortcut key)
|
||||
owner.openingEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
if(key == EShortcut::BATTLE_TOGGLE_QUEUE)
|
||||
{
|
||||
toggleQueueVisibility();
|
||||
}
|
||||
else if(key == EShortcut::BATTLE_USE_CREATURE_SPELL)
|
||||
{
|
||||
owner.actionsController->enterCreatureCastingMode();
|
||||
}
|
||||
else if(key == EShortcut::GLOBAL_CANCEL)
|
||||
{
|
||||
owner.actionsController->endCastingSpell();
|
||||
}
|
||||
InterfaceObjectConfigurable::keyPressed(key);
|
||||
}
|
||||
|
||||
void BattleWindow::clickRight(tribool down, bool previousState)
|
||||
@ -538,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()
|
||||
|
@ -201,19 +201,19 @@ std::pair<std::string, std::string> InterfaceObjectConfigurable::readHintText(co
|
||||
return result;
|
||||
}
|
||||
|
||||
EShortcut InterfaceObjectConfigurable::readKeycode(const JsonNode & config) const
|
||||
EShortcut InterfaceObjectConfigurable::readHotkey(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Reading keycode");
|
||||
logGlobal->debug("Reading hotkey");
|
||||
|
||||
if(config.getType() != JsonNode::JsonType::DATA_STRING)
|
||||
{
|
||||
logGlobal->error("Invalid keycode format in interface configuration! Expected string!", config.String());
|
||||
logGlobal->error("Invalid hotket format in interface configuration! Expected string!", config.String());
|
||||
return EShortcut::NONE;
|
||||
}
|
||||
|
||||
EShortcut result = GH.shortcutsHandler().findShortcut(config.String());
|
||||
if (result == EShortcut::NONE)
|
||||
logGlobal->error("Invalid keycode '%s' in interface configuration!", config.String());
|
||||
logGlobal->error("Invalid hotkey '%s' in interface configuration!", config.String());
|
||||
return result;;
|
||||
}
|
||||
|
||||
@ -320,11 +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_STRING)
|
||||
button->assignedKey = readKeycode(config["hotkey"]);
|
||||
{
|
||||
button->assignedKey = readHotkey(config["hotkey"]);
|
||||
|
||||
auto target = shortcuts.find(button->assignedKey);
|
||||
if (target != shortcuts.end())
|
||||
{
|
||||
button->addCallback(target->second.callback);
|
||||
target->second.assignedToButton = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return button;
|
||||
}
|
||||
@ -430,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(key);
|
||||
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();
|
||||
}
|
||||
|
@ -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;
|
||||
EShortcut 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;
|
||||
};
|
||||
|
@ -124,6 +124,7 @@ enum class EShortcut
|
||||
BATTLE_CONSOLE_DOWN,
|
||||
BATTLE_TACTICS_NEXT,
|
||||
BATTLE_TACTICS_END,
|
||||
BATTLE_SELECT_ACTION, // Alternative actions toggle
|
||||
|
||||
// Town screen
|
||||
TOWN_OPEN_TAVERN,
|
||||
|
@ -126,6 +126,7 @@ std::vector<EShortcut> ShortcutHandler::translateKeycode(SDL_Keycode key) const
|
||||
{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 },
|
||||
@ -255,6 +256,7 @@ EShortcut ShortcutHandler::findShortcut(const std::string & identifier ) const
|
||||
{"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 },
|
||||
|
@ -21,7 +21,6 @@
|
||||
"position": {"x": 4, "y": 560},
|
||||
"image": "icm003",
|
||||
"help": "core.help.381",
|
||||
"callback": "options",
|
||||
"hotkey": "globalOptions"
|
||||
},
|
||||
|
||||
@ -31,7 +30,6 @@
|
||||
"position": {"x": 55, "y": 560},
|
||||
"image": "icm001",
|
||||
"help": "core.help.379",
|
||||
"callback": "surrender",
|
||||
"hotkey": "battleSurrender"
|
||||
},
|
||||
|
||||
@ -41,7 +39,6 @@
|
||||
"position": {"x": 106, "y": 560},
|
||||
"image": "icm002",
|
||||
"help": "core.help.380",
|
||||
"callback": "flee",
|
||||
"hotkey": "battleRetreat"
|
||||
},
|
||||
|
||||
@ -51,7 +48,6 @@
|
||||
"position": {"x": 157, "y": 560},
|
||||
"image": "icm004",
|
||||
"help": "core.help.382",
|
||||
"callback": "autofight",
|
||||
"hotkey": "battleAutocombat"
|
||||
},
|
||||
|
||||
@ -61,7 +57,6 @@
|
||||
"position": {"x": 646, "y": 560},
|
||||
"image": "icm005",
|
||||
"help": "core.help.385",
|
||||
"callback": "spellbook",
|
||||
"hotkey": "battleCastSpell"
|
||||
},
|
||||
|
||||
@ -71,7 +66,6 @@
|
||||
"position": {"x": 697, "y": 560},
|
||||
"image": "icm006",
|
||||
"help": "core.help.386",
|
||||
"callback": "wait",
|
||||
"hotkey": "battleWait"
|
||||
},
|
||||
|
||||
@ -81,7 +75,6 @@
|
||||
"position": {"x": 748, "y": 560},
|
||||
"image": "icm007",
|
||||
"help": "core.help.387",
|
||||
"callback": "defence",
|
||||
"hotkey": "battleDefend"
|
||||
},
|
||||
|
||||
@ -90,7 +83,6 @@
|
||||
"name": "consoleUp",
|
||||
"position": {"x": 625, "y": 560},
|
||||
"image": "ComSlide",
|
||||
"callback": "consoleUp",
|
||||
"imageOrder": [0, 1, 0, 0],
|
||||
"hotkey": "battleConsoleUp"
|
||||
},
|
||||
@ -100,7 +92,6 @@
|
||||
"name": "consoleDown",
|
||||
"position": {"x": 625, "y": 579},
|
||||
"image": "ComSlide",
|
||||
"callback": "consoleDown",
|
||||
"imageOrder": [2, 3, 2, 2],
|
||||
"hotkey": "battleConsoleDown"
|
||||
},
|
||||
@ -117,7 +108,6 @@
|
||||
"name": "tacticNext",
|
||||
"position": {"x": 213, "y": 560},
|
||||
"image": "icm011",
|
||||
"callback": "tacticNext",
|
||||
"hotkey": "battleTacticsNext"
|
||||
},
|
||||
|
||||
@ -126,7 +116,6 @@
|
||||
"name": "tacticEnd",
|
||||
"position": {"x": 419, "y": 560},
|
||||
"image": "icm012",
|
||||
"callback": "tacticEnd",
|
||||
"hotkey": "battleTacticsEnd"
|
||||
}
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user