1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-15 01:24:45 +02:00

Refactoring of button class to prepare for configurable button

This commit is contained in:
Ivan Savenko
2024-02-27 22:19:09 +02:00
parent 850af00303
commit 07d201502e
22 changed files with 223 additions and 207 deletions

View File

@ -102,7 +102,7 @@ void ApplyOnLobbyScreenNetPackVisitor::visitLobbyChatMessage(LobbyChatMessage &
lobby->card->chat->addNewMessage(pack.playerName + ": " + pack.message); lobby->card->chat->addNewMessage(pack.playerName + ": " + pack.message);
lobby->card->setChat(true); lobby->card->setChat(true);
if(lobby->buttonChat) if(lobby->buttonChat)
lobby->buttonChat->addTextOverlay(CGI->generaltexth->allTexts[531], FONT_SMALL, Colors::WHITE); lobby->buttonChat->setTextOverlay(CGI->generaltexth->allTexts[531], FONT_SMALL, Colors::WHITE);
} }
} }

View File

@ -35,7 +35,6 @@ class BattleInterface;
class CPicture; class CPicture;
class CFilledTexture; class CFilledTexture;
class CButton; class CButton;
class CToggleButton;
class CLabel; class CLabel;
class CMultiLineLabel; class CMultiLineLabel;
class CTextBox; class CTextBox;

View File

@ -564,8 +564,7 @@ void BattleWindow::showAlternativeActionIcon(PossiblePlayerBattleAction action)
break; break;
} }
auto anim = GH.renderHandler().loadAnimation(iconName); w->setImage(iconName);
w->setImage(anim);
w->redraw(); w->redraw();
} }

View File

@ -47,8 +47,8 @@ GlobalLobbyLoginWindow::GlobalLobbyLoginWindow()
auto buttonRegister = std::make_shared<CToggleButton>(Point(10, 40), AnimationPath::builtin("GSPBUT2"), CButton::tooltip(), 0); auto buttonRegister = std::make_shared<CToggleButton>(Point(10, 40), AnimationPath::builtin("GSPBUT2"), CButton::tooltip(), 0);
auto buttonLogin = std::make_shared<CToggleButton>(Point(146, 40), AnimationPath::builtin("GSPBUT2"), CButton::tooltip(), 0); auto buttonLogin = std::make_shared<CToggleButton>(Point(146, 40), AnimationPath::builtin("GSPBUT2"), CButton::tooltip(), 0);
buttonRegister->addTextOverlay(CGI->generaltexth->translate("vcmi.lobby.login.create"), EFonts::FONT_SMALL, Colors::YELLOW); buttonRegister->setTextOverlay(CGI->generaltexth->translate("vcmi.lobby.login.create"), EFonts::FONT_SMALL, Colors::YELLOW);
buttonLogin->addTextOverlay(CGI->generaltexth->translate("vcmi.lobby.login.login"), EFonts::FONT_SMALL, Colors::YELLOW); buttonLogin->setTextOverlay(CGI->generaltexth->translate("vcmi.lobby.login.login"), EFonts::FONT_SMALL, Colors::YELLOW);
toggleMode = std::make_shared<CToggleGroup>(nullptr); toggleMode = std::make_shared<CToggleGroup>(nullptr);
toggleMode->addToggle(0, buttonRegister); toggleMode->addToggle(0, buttonRegister);

View File

@ -50,8 +50,8 @@ GlobalLobbyServerSetup::GlobalLobbyServerSetup()
auto buttonPublic = std::make_shared<CToggleButton>(Point(10, 120), AnimationPath::builtin("GSPBUT2"), CButton::tooltip(), 0); auto buttonPublic = std::make_shared<CToggleButton>(Point(10, 120), AnimationPath::builtin("GSPBUT2"), CButton::tooltip(), 0);
auto buttonPrivate = std::make_shared<CToggleButton>(Point(146, 120), AnimationPath::builtin("GSPBUT2"), CButton::tooltip(), 0); auto buttonPrivate = std::make_shared<CToggleButton>(Point(146, 120), AnimationPath::builtin("GSPBUT2"), CButton::tooltip(), 0);
buttonPublic->addTextOverlay(CGI->generaltexth->translate("vcmi.lobby.room.public"), EFonts::FONT_SMALL, Colors::YELLOW); buttonPublic->setTextOverlay(CGI->generaltexth->translate("vcmi.lobby.room.public"), EFonts::FONT_SMALL, Colors::YELLOW);
buttonPrivate->addTextOverlay(CGI->generaltexth->translate("vcmi.lobby.room.private"), EFonts::FONT_SMALL, Colors::YELLOW); buttonPrivate->setTextOverlay(CGI->generaltexth->translate("vcmi.lobby.room.private"), EFonts::FONT_SMALL, Colors::YELLOW);
toggleRoomType = std::make_shared<CToggleGroup>(nullptr); toggleRoomType = std::make_shared<CToggleGroup>(nullptr);
toggleRoomType->addToggle(0, buttonPublic); toggleRoomType->addToggle(0, buttonPublic);
@ -61,8 +61,8 @@ GlobalLobbyServerSetup::GlobalLobbyServerSetup()
auto buttonNewGame = std::make_shared<CToggleButton>(Point(10, 170), AnimationPath::builtin("GSPBUT2"), CButton::tooltip(), 0); auto buttonNewGame = std::make_shared<CToggleButton>(Point(10, 170), AnimationPath::builtin("GSPBUT2"), CButton::tooltip(), 0);
auto buttonLoadGame = std::make_shared<CToggleButton>(Point(146, 170), AnimationPath::builtin("GSPBUT2"), CButton::tooltip(), 0); auto buttonLoadGame = std::make_shared<CToggleButton>(Point(146, 170), AnimationPath::builtin("GSPBUT2"), CButton::tooltip(), 0);
buttonNewGame->addTextOverlay(CGI->generaltexth->translate("vcmi.lobby.room.new"), EFonts::FONT_SMALL, Colors::YELLOW); buttonNewGame->setTextOverlay(CGI->generaltexth->translate("vcmi.lobby.room.new"), EFonts::FONT_SMALL, Colors::YELLOW);
buttonLoadGame->addTextOverlay(CGI->generaltexth->translate("vcmi.lobby.room.load"), EFonts::FONT_SMALL, Colors::YELLOW); buttonLoadGame->setTextOverlay(CGI->generaltexth->translate("vcmi.lobby.room.load"), EFonts::FONT_SMALL, Colors::YELLOW);
toggleGameMode = std::make_shared<CToggleGroup>(nullptr); toggleGameMode = std::make_shared<CToggleGroup>(nullptr);
toggleGameMode->addToggle(0, buttonNewGame); toggleGameMode->addToggle(0, buttonNewGame);

View File

@ -396,7 +396,7 @@ std::shared_ptr<CToggleButton> InterfaceObjectConfigurable::buildToggleButton(co
{ {
for(const auto & item : config["items"].Vector()) for(const auto & item : config["items"].Vector())
{ {
button->addOverlay(buildWidget(item)); button->setOverlay(buildWidget(item));
} }
} }
if(!config["selected"].isNull()) if(!config["selected"].isNull())
@ -422,7 +422,7 @@ std::shared_ptr<CButton> InterfaceObjectConfigurable::buildButton(const JsonNode
{ {
for(const auto & item : config["items"].Vector()) for(const auto & item : config["items"].Vector())
{ {
button->addOverlay(buildWidget(item)); button->setOverlay(buildWidget(item));
} }
} }
if(!config["imageOrder"].isNull()) if(!config["imageOrder"].isNull())
@ -589,7 +589,7 @@ std::shared_ptr<ComboBox> InterfaceObjectConfigurable::buildComboBox(const JsonN
{ {
for(const auto & item : config["items"].Vector()) for(const auto & item : config["items"].Vector())
{ {
result->addOverlay(buildWidget(item)); result->setOverlay(buildWidget(item));
} }
} }
if(!config["imageOrder"].isNull()) if(!config["imageOrder"].isNull())

View File

@ -126,7 +126,7 @@ CBonusSelection::CBonusSelection()
tabExtraOptions->recreate(true); tabExtraOptions->recreate(true);
tabExtraOptions->setEnabled(false); tabExtraOptions->setEnabled(false);
buttonExtraOptions = std::make_shared<CButton>(Point(643, 431), AnimationPath::builtin("GSPBUT2.DEF"), CGI->generaltexth->zelp[46], [this]{ tabExtraOptions->setEnabled(!tabExtraOptions->isActive()); GH.windows().totalRedraw(); }, EShortcut::NONE); buttonExtraOptions = std::make_shared<CButton>(Point(643, 431), AnimationPath::builtin("GSPBUT2.DEF"), CGI->generaltexth->zelp[46], [this]{ tabExtraOptions->setEnabled(!tabExtraOptions->isActive()); GH.windows().totalRedraw(); }, EShortcut::NONE);
buttonExtraOptions->addTextOverlay(CGI->generaltexth->translate("vcmi.optionsTab.extraOptions.hover"), FONT_SMALL, Colors::WHITE); buttonExtraOptions->setTextOverlay(CGI->generaltexth->translate("vcmi.optionsTab.extraOptions.hover"), FONT_SMALL, Colors::WHITE);
} }
} }
@ -306,7 +306,7 @@ void CBonusSelection::createBonusesIcons()
auto anim = GH.renderHandler().createAnimation(); auto anim = GH.renderHandler().createAnimation();
anim->setCustom(picName, 0); anim->setCustom(picName, 0);
bonusButton->setImage(anim); //TODO: bonusButton->setImage(anim);
if(CSH->campaignBonus == i) if(CSH->campaignBonus == i)
bonusButton->setBorderColor(Colors::BRIGHT_YELLOW); bonusButton->setBorderColor(Colors::BRIGHT_YELLOW);
groupBonuses->addToggle(i, bonusButton); groupBonuses->addToggle(i, bonusButton);

View File

@ -61,7 +61,7 @@ CLobbyScreen::CLobbyScreen(ESelectionScreen screenType)
}; };
buttonChat = std::make_shared<CButton>(Point(619, 80), AnimationPath::builtin("GSPBUT2.DEF"), CGI->generaltexth->zelp[48], std::bind(&CLobbyScreen::toggleChat, this), EShortcut::LOBBY_HIDE_CHAT); buttonChat = std::make_shared<CButton>(Point(619, 80), AnimationPath::builtin("GSPBUT2.DEF"), CGI->generaltexth->zelp[48], std::bind(&CLobbyScreen::toggleChat, this), EShortcut::LOBBY_HIDE_CHAT);
buttonChat->addTextOverlay(CGI->generaltexth->allTexts[532], FONT_SMALL, Colors::WHITE); buttonChat->setTextOverlay(CGI->generaltexth->allTexts[532], FONT_SMALL, Colors::WHITE);
switch(screenType) switch(screenType)
{ {
@ -171,18 +171,18 @@ void CLobbyScreen::toggleMode(bool host)
return; return;
auto buttonColor = host ? Colors::WHITE : Colors::ORANGE; auto buttonColor = host ? Colors::WHITE : Colors::ORANGE;
buttonSelect->addTextOverlay(CGI->generaltexth->allTexts[500], FONT_SMALL, buttonColor); buttonSelect->setTextOverlay(CGI->generaltexth->allTexts[500], FONT_SMALL, buttonColor);
buttonOptions->addTextOverlay(CGI->generaltexth->allTexts[501], FONT_SMALL, buttonColor); buttonOptions->setTextOverlay(CGI->generaltexth->allTexts[501], FONT_SMALL, buttonColor);
if (buttonTurnOptions) if (buttonTurnOptions)
buttonTurnOptions->addTextOverlay(CGI->generaltexth->translate("vcmi.optionsTab.turnOptions.hover"), FONT_SMALL, buttonColor); buttonTurnOptions->setTextOverlay(CGI->generaltexth->translate("vcmi.optionsTab.turnOptions.hover"), FONT_SMALL, buttonColor);
if (buttonExtraOptions) if (buttonExtraOptions)
buttonExtraOptions->addTextOverlay(CGI->generaltexth->translate("vcmi.optionsTab.extraOptions.hover"), FONT_SMALL, buttonColor); buttonExtraOptions->setTextOverlay(CGI->generaltexth->translate("vcmi.optionsTab.extraOptions.hover"), FONT_SMALL, buttonColor);
if(buttonRMG) if(buttonRMG)
{ {
buttonRMG->addTextOverlay(CGI->generaltexth->allTexts[740], FONT_SMALL, buttonColor); buttonRMG->setTextOverlay(CGI->generaltexth->allTexts[740], FONT_SMALL, buttonColor);
buttonRMG->block(!host); buttonRMG->block(!host);
} }
buttonSelect->block(!host); buttonSelect->block(!host);
@ -206,9 +206,9 @@ void CLobbyScreen::toggleChat()
{ {
card->toggleChat(); card->toggleChat();
if(card->showChat) if(card->showChat)
buttonChat->addTextOverlay(CGI->generaltexth->allTexts[531], FONT_SMALL, Colors::WHITE); buttonChat->setTextOverlay(CGI->generaltexth->allTexts[531], FONT_SMALL, Colors::WHITE);
else else
buttonChat->addTextOverlay(CGI->generaltexth->allTexts[532], FONT_SMALL, Colors::WHITE); buttonChat->setTextOverlay(CGI->generaltexth->allTexts[532], FONT_SMALL, Colors::WHITE);
} }
void CLobbyScreen::updateAfterStateChange() void CLobbyScreen::updateAfterStateChange()

View File

@ -917,7 +917,7 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry(const PlayerSettings & S, con
CGI->generaltexth->zelp[180], CGI->generaltexth->zelp[180],
std::bind(&OptionsTab::onSetPlayerClicked, &parentTab, *s) std::bind(&OptionsTab::onSetPlayerClicked, &parentTab, *s)
); );
flag->hoverable = true; flag->setHoverable(true);
flag->block(CSH->isGuest()); flag->block(CSH->isGuest());
} }
else else

View File

@ -364,9 +364,9 @@ void RandomMapTab::setMapGenOptions(std::shared_ptr<CMapGenOptions> opts)
if(auto w = widget<CButton>("templateButton")) if(auto w = widget<CButton>("templateButton"))
{ {
if(tmpl) if(tmpl)
w->addTextOverlay(tmpl->getName(), EFonts::FONT_SMALL, Colors::WHITE); w->setTextOverlay(tmpl->getName(), EFonts::FONT_SMALL, Colors::WHITE);
else else
w->addTextOverlay(readText(variables["randomTemplate"]), EFonts::FONT_SMALL, Colors::WHITE); w->setTextOverlay(readText(variables["randomTemplate"]), EFonts::FONT_SMALL, Colors::WHITE);
} }
for(auto r : VLC->roadTypeHandler->objects) for(auto r : VLC->roadTypeHandler->objects)
{ {
@ -388,9 +388,9 @@ void RandomMapTab::setTemplate(const CRmgTemplate * tmpl)
if(auto w = widget<CButton>("templateButton")) if(auto w = widget<CButton>("templateButton"))
{ {
if(tmpl) if(tmpl)
w->addTextOverlay(tmpl->getName(), EFonts::FONT_SMALL, Colors::WHITE); w->setTextOverlay(tmpl->getName(), EFonts::FONT_SMALL, Colors::WHITE);
else else
w->addTextOverlay(readText(variables["randomTemplate"]), EFonts::FONT_SMALL, Colors::WHITE); w->setTextOverlay(readText(variables["randomTemplate"]), EFonts::FONT_SMALL, Colors::WHITE);
} }
updateMapInfoByHost(); updateMapInfoByHost();
} }
@ -532,11 +532,11 @@ TeamAlignmentsWidget::TeamAlignmentsWidget(RandomMapTab & randomMapTab):
assert(button); assert(button);
if(sel == teamId) if(sel == teamId)
{ {
button->addOverlay(buildWidget(variables["flagsAnimation"])); button->setOverlay(buildWidget(variables["flagsAnimation"]));
} }
else else
{ {
button->addOverlay(nullptr); button->setOverlay(nullptr);
} }
button->addCallback([this](bool) button->addCallback([this](bool)
{ {

View File

@ -217,7 +217,7 @@ SelectionTab::SelectionTab(ESelectionScreen Type)
if(enableUiEnhancements) if(enableUiEnhancements)
{ {
buttonsSortBy.push_back(std::make_shared<CButton>(Point(371, 85), AnimationPath::builtin("lobby/selectionTabSortDate"), CButton::tooltip("", CGI->generaltexth->translate("vcmi.lobby.sortDate")), std::bind(&SelectionTab::sortBy, this, ESortBy::_changeDate))); buttonsSortBy.push_back(std::make_shared<CButton>(Point(371, 85), AnimationPath::builtin("lobby/selectionTabSortDate"), CButton::tooltip("", CGI->generaltexth->translate("vcmi.lobby.sortDate")), std::bind(&SelectionTab::sortBy, this, ESortBy::_changeDate)));
buttonsSortBy.back()->setAnimateLonelyFrame(true); //TODO: buttonsSortBy.back()->setAnimateLonelyFrame(true);
} }
iconsMapFormats = GH.renderHandler().loadAnimation(AnimationPath::builtin("SCSELC.DEF")); iconsMapFormats = GH.renderHandler().loadAnimation(AnimationPath::builtin("SCSELC.DEF"));

View File

@ -66,7 +66,7 @@ CCampaignScreen::CCampaignScreen(const JsonNode & config, std::string name)
if(!config[name]["exitbutton"].isNull()) if(!config[name]["exitbutton"].isNull())
{ {
buttonBack = createExitButton(config[name]["exitbutton"]); buttonBack = createExitButton(config[name]["exitbutton"]);
buttonBack->hoverable = true; buttonBack->setHoverable(true);
} }
for(const JsonNode & node : config[name]["items"].Vector()) for(const JsonNode & node : config[name]["items"].Vector())

View File

@ -260,7 +260,7 @@ CMenuEntry::CMenuEntry(CMenuScreen * parent, const JsonNode & config)
for(const JsonNode & node : config["buttons"].Vector()) for(const JsonNode & node : config["buttons"].Vector())
{ {
buttons.push_back(createButton(parent, node)); buttons.push_back(createButton(parent, node));
buttons.back()->hoverable = true; buttons.back()->setHoverable(true);
buttons.back()->setRedrawParent(true); buttons.back()->setRedrawParent(true);
} }
} }

View File

@ -30,30 +30,25 @@
#include "../../lib/CConfigHandler.h" #include "../../lib/CConfigHandler.h"
#include "../../lib/CGeneralTextHandler.h" #include "../../lib/CGeneralTextHandler.h"
void CButton::update() void ButtonBase::update()
{ {
if (overlay) if (overlay)
{ {
Point targetPos = Rect::createCentered( pos, overlay->pos.dimensions()).topLeft(); Point targetPos = Rect::createCentered( pos, overlay->pos.dimensions()).topLeft();
if (state == PRESSED) if (state == EButtonState::PRESSED)
overlay->moveTo(targetPos + Point(1,1)); overlay->moveTo(targetPos + Point(1,1));
else else
overlay->moveTo(targetPos); overlay->moveTo(targetPos);
} }
int newPos = stateToIndex[int(state)]; int newPos = stateToIndex[int(state)];
if(animateLonelyFrame)
{
if(state == PRESSED)
image->moveBy(Point(1,1));
else
image->moveBy(Point(-1,-1));
}
if (newPos < 0) if (newPos < 0)
newPos = 0; newPos = 0;
if (state == HIGHLIGHTED && image->size() < 4) // checkbox - has only have two frames: normal and pressed/highlighted
// hero movement speed buttons: only three frames: normal, pressed and blocked/highlighted
if (state == EButtonState::HIGHLIGHTED && image->size() < 4)
newPos = (int)image->size()-1; newPos = (int)image->size()-1;
image->setFrame(newPos); image->setFrame(newPos);
@ -71,14 +66,14 @@ void CButton::addCallback(const std::function<void()> & callback)
this->callback += callback; this->callback += callback;
} }
void CButton::addTextOverlay(const std::string & Text, EFonts font, ColorRGBA color) void ButtonBase::setTextOverlay(const std::string & Text, EFonts font, ColorRGBA color)
{ {
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
addOverlay(std::make_shared<CLabel>(pos.w/2, pos.h/2, font, ETextAlignment::CENTER, color, Text)); setOverlay(std::make_shared<CLabel>(pos.w/2, pos.h/2, font, ETextAlignment::CENTER, color, Text));
update(); update();
} }
void CButton::addOverlay(std::shared_ptr<CIntObject> newOverlay) void ButtonBase::setOverlay(std::shared_ptr<CIntObject> newOverlay)
{ {
overlay = newOverlay; overlay = newOverlay;
if(overlay) if(overlay)
@ -90,17 +85,23 @@ void CButton::addOverlay(std::shared_ptr<CIntObject> newOverlay)
update(); update();
} }
void CButton::addImage(const AnimationPath & filename) void ButtonBase::setImage(const AnimationPath & defName, bool playerColoredButton)
{ {
imageNames.push_back(filename); OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
image = std::make_shared<CAnimImage>(defName, vstd::to_underlying(getState()));
pos = image->pos;
if (playerColoredButton)
image->playerColored(LOCPLINT->playerID);
} }
void CButton::addHoverText(ButtonState state, std::string text) void CButton::addHoverText(EButtonState state, std::string text)
{ {
hoverTexts[state] = text; hoverTexts[vstd::to_underlying(state)] = text;
} }
void CButton::setImageOrder(int state1, int state2, int state3, int state4) void ButtonBase::setImageOrder(int state1, int state2, int state3, int state4)
{ {
stateToIndex[0] = state1; stateToIndex[0] = state1;
stateToIndex[1] = state2; stateToIndex[1] = state2;
@ -109,44 +110,65 @@ void CButton::setImageOrder(int state1, int state2, int state3, int state4)
update(); update();
} }
void CButton::setAnimateLonelyFrame(bool agreement) //TODO:
//void CButton::setAnimateLonelyFrame(bool agreement)
//{
// animateLonelyFrame = agreement;
//}
void ButtonBase::setStateImpl(EButtonState newState)
{ {
animateLonelyFrame = agreement;
}
void CButton::setState(ButtonState newState)
{
if (state == newState)
return;
if (newState == BLOCKED)
removeUsedEvents(LCLICK | SHOW_POPUP | HOVER | KEYBOARD);
else
addUsedEvents(LCLICK | SHOW_POPUP | HOVER | KEYBOARD);
state = newState; state = newState;
update(); update();
} }
CButton::ButtonState CButton::getState() void CButton::setState(EButtonState newState)
{
if (getState() == newState)
return;
if (newState == EButtonState::BLOCKED)
removeUsedEvents(LCLICK | SHOW_POPUP | HOVER | KEYBOARD);
else
addUsedEvents(LCLICK | SHOW_POPUP | HOVER | KEYBOARD);
setStateImpl(newState);
}
EButtonState ButtonBase::getState()
{ {
return state; return state;
} }
bool CButton::isBlocked() bool CButton::isBlocked()
{ {
return state == BLOCKED; return getState() == EButtonState::BLOCKED;
} }
bool CButton::isHighlighted() bool CButton::isHighlighted()
{ {
return state == HIGHLIGHTED; return getState() == EButtonState::HIGHLIGHTED;
}
void CButton::setHoverable(bool on)
{
hoverable = on;
}
void CButton::setSoundDisabled(bool on)
{
soundDisabled = on;
}
void CButton::setActOnDown(bool on)
{
actOnDown = on;
} }
void CButton::block(bool on) void CButton::block(bool on)
{ {
if(on || state == BLOCKED) //dont change button state if unblock requested, but it's not blocked if(on || getState() == EButtonState::BLOCKED) //dont change button state if unblock requested, but it's not blocked
setState(on ? BLOCKED : NORMAL); setState(on ? EButtonState::BLOCKED : EButtonState::NORMAL);
} }
void CButton::onButtonClicked() void CButton::onButtonClicked()
@ -169,14 +191,14 @@ void CButton::clickPressed(const Point & cursorPosition)
if(isBlocked()) if(isBlocked())
return; return;
if (getState() != PRESSED) if (getState() != EButtonState::PRESSED)
{ {
if (!soundDisabled) if (!soundDisabled)
{ {
CCS->soundh->playSound(soundBase::button); CCS->soundh->playSound(soundBase::button);
GH.input().hapticFeedback(); GH.input().hapticFeedback();
} }
setState(PRESSED); setState(EButtonState::PRESSED);
if (actOnDown) if (actOnDown)
onButtonClicked(); onButtonClicked();
@ -185,12 +207,12 @@ void CButton::clickPressed(const Point & cursorPosition)
void CButton::clickReleased(const Point & cursorPosition) void CButton::clickReleased(const Point & cursorPosition)
{ {
if (getState() == PRESSED) if (getState() == EButtonState::PRESSED)
{ {
if(hoverable && isHovered()) if(hoverable && isHovered())
setState(HIGHLIGHTED); setState(EButtonState::HIGHLIGHTED);
else else
setState(NORMAL); setState(EButtonState::NORMAL);
if (!actOnDown) if (!actOnDown)
onButtonClicked(); onButtonClicked();
@ -199,12 +221,12 @@ void CButton::clickReleased(const Point & cursorPosition)
void CButton::clickCancel(const Point & cursorPosition) void CButton::clickCancel(const Point & cursorPosition)
{ {
if (getState() == PRESSED) if (getState() == EButtonState::PRESSED)
{ {
if(hoverable && isHovered()) if(hoverable && isHovered())
setState(HIGHLIGHTED); setState(EButtonState::HIGHLIGHTED);
else else
setState(NORMAL); setState(EButtonState::NORMAL);
} }
} }
@ -219,17 +241,17 @@ void CButton::hover (bool on)
if(hoverable && !isBlocked()) if(hoverable && !isBlocked())
{ {
if(on) if(on)
setState(HIGHLIGHTED); setState(EButtonState::HIGHLIGHTED);
else else
setState(NORMAL); setState(EButtonState::NORMAL);
} }
/*if(pressedL && on) // WTF is this? When this is used? /*if(pressedL && on) // WTF is this? When this is used?
setState(PRESSED);*/ setState(PRESSED);*/
std::string name = hoverTexts[getState()].empty() std::string name = hoverTexts[vstd::to_underlying(getState())].empty()
? hoverTexts[0] ? hoverTexts[0]
: hoverTexts[getState()]; : hoverTexts[vstd::to_underlying(getState())];
if(!name.empty() && !isBlocked()) //if there is no name, there is nothing to display also if(!name.empty() && !isBlocked()) //if there is no name, there is nothing to display also
{ {
@ -240,55 +262,30 @@ void CButton::hover (bool on)
} }
} }
ButtonBase::ButtonBase(Point position, const AnimationPath & defName, EShortcut key, bool playerColoredButton)
: CKeyShortcut(key)
, stateToIndex({0, 1, 2, 3})
, state(EButtonState::NORMAL)
{
pos.x += position.x;
pos.y += position.y;
setImage(defName);
}
CButton::CButton(Point position, const AnimationPath &defName, const std::pair<std::string, std::string> &help, CFunctionList<void()> Callback, EShortcut key, bool playerColoredButton): CButton::CButton(Point position, const AnimationPath &defName, const std::pair<std::string, std::string> &help, CFunctionList<void()> Callback, EShortcut key, bool playerColoredButton):
CKeyShortcut(key), ButtonBase(position, defName, key, playerColoredButton),
callback(Callback) callback(Callback)
{ {
defActions = 255-DISPOSE; defActions = 255-DISPOSE;
addUsedEvents(LCLICK | SHOW_POPUP | HOVER | KEYBOARD); addUsedEvents(LCLICK | SHOW_POPUP | HOVER | KEYBOARD);
stateToIndex[0] = 0;
stateToIndex[1] = 1;
stateToIndex[2] = 2;
stateToIndex[3] = 3;
state=NORMAL;
currentImage = -1;
hoverable = actOnDown = soundDisabled = false; hoverable = actOnDown = soundDisabled = false;
hoverTexts[0] = help.first; hoverTexts[0] = help.first;
helpBox=help.second; helpBox=help.second;
pos.x += position.x;
pos.y += position.y;
if (!defName.empty())
{
imageNames.push_back(defName);
setIndex(0);
if (playerColoredButton)
image->playerColored(LOCPLINT->playerID);
}
} }
void CButton::setIndex(size_t index) void ButtonBase::setPlayerColor(PlayerColor player)
{
if (index == currentImage || index>=imageNames.size())
return;
currentImage = index;
auto anim = GH.renderHandler().loadAnimation(imageNames[index]);
setImage(anim);
}
void CButton::setImage(std::shared_ptr<CAnimation> anim, int animFlags)
{
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
image = std::make_shared<CAnimImage>(anim, getState(), 0, 0, 0, animFlags);
pos = image->pos;
}
void CButton::setPlayerColor(PlayerColor player)
{ {
if (image && image->isPlayerColored()) if (image && image->isPlayerColored())
image->playerColored(player); image->playerColored(player);
@ -353,6 +350,11 @@ void CToggleBase::setSelected(bool on)
callback(on); callback(on);
} }
bool CToggleBase::isSelected() const
{
return selected;
}
bool CToggleBase::canActivate() bool CToggleBase::canActivate()
{ {
if (selected && !allowDeselection) if (selected && !allowDeselection)
@ -365,29 +367,33 @@ void CToggleBase::addCallback(std::function<void(bool)> function)
callback += function; callback += function;
} }
void CToggleBase::setAllowDeselection(bool on)
{
allowDeselection = on;
}
CToggleButton::CToggleButton(Point position, const AnimationPath &defName, const std::pair<std::string, std::string> &help, CToggleButton::CToggleButton(Point position, const AnimationPath &defName, const std::pair<std::string, std::string> &help,
CFunctionList<void(bool)> callback, EShortcut key, bool playerColoredButton): CFunctionList<void(bool)> callback, EShortcut key, bool playerColoredButton):
CButton(position, defName, help, 0, key, playerColoredButton), CButton(position, defName, help, 0, key, playerColoredButton),
CToggleBase(callback) CToggleBase(callback)
{ {
allowDeselection = true;
} }
void CToggleButton::doSelect(bool on) void CToggleButton::doSelect(bool on)
{ {
if (on) if (on)
{ {
setState(HIGHLIGHTED); setState(EButtonState::HIGHLIGHTED);
} }
else else
{ {
setState(NORMAL); setState(EButtonState::NORMAL);
} }
} }
void CToggleButton::setEnabled(bool enabled) void CToggleButton::setEnabled(bool enabled)
{ {
setState(enabled ? NORMAL : BLOCKED); setState(enabled ? EButtonState::NORMAL : EButtonState::BLOCKED);
} }
void CToggleButton::clickPressed(const Point & cursorPosition) void CToggleButton::clickPressed(const Point & cursorPosition)
@ -403,7 +409,7 @@ void CToggleButton::clickPressed(const Point & cursorPosition)
{ {
CCS->soundh->playSound(soundBase::button); CCS->soundh->playSound(soundBase::button);
GH.input().hapticFeedback(); GH.input().hapticFeedback();
setState(PRESSED); setState(EButtonState::PRESSED);
} }
} }
@ -416,13 +422,13 @@ void CToggleButton::clickReleased(const Point & cursorPosition)
if(isBlocked()) if(isBlocked())
return; return;
if (getState() == PRESSED && canActivate()) if (getState() == EButtonState::PRESSED && canActivate())
{ {
onButtonClicked(); onButtonClicked();
setSelected(!selected); setSelected(!isSelected());
} }
else else
doSelect(selected); // restore doSelect(isSelected()); // restore
} }
void CToggleButton::clickCancel(const Point & cursorPosition) void CToggleButton::clickCancel(const Point & cursorPosition)
@ -434,7 +440,7 @@ void CToggleButton::clickCancel(const Point & cursorPosition)
if(isBlocked()) if(isBlocked())
return; return;
doSelect(selected); doSelect(isSelected());
} }
void CToggleGroup::addCallback(std::function<void(int)> callback) void CToggleGroup::addCallback(std::function<void(int)> callback)
@ -455,7 +461,7 @@ void CToggleGroup::addToggle(int identifier, std::shared_ptr<CToggleBase> button
} }
button->addCallback([=] (bool on) { if (on) selectionChanged(identifier);}); button->addCallback([=] (bool on) { if (on) selectionChanged(identifier);});
button->allowDeselection = false; button->setAllowDeselection(false);
if(buttons.count(identifier)>0) if(buttons.count(identifier)>0)
logAnim->error("Duplicated toggle button id %d", identifier); logAnim->error("Duplicated toggle button id %d", identifier);

View File

@ -22,64 +22,77 @@ class CAnimImage;
class CLabel; class CLabel;
class CAnimation; class CAnimation;
/// Typical Heroes 3 button which can be inactive or active and can enum class EButtonState
/// hold further information if you right-click it
class CButton : public CKeyShortcut
{ {
CFunctionList<void()> callback;
public:
enum ButtonState
{
NORMAL=0, NORMAL=0,
PRESSED=1, PRESSED=1,
BLOCKED=2, BLOCKED=2,
HIGHLIGHTED=3 HIGHLIGHTED=3 // used for: highlighted state for selectable buttons, hovered state for hoverable buttons (e.g. main menu)
}; };
protected:
std::vector<AnimationPath> imageNames;//store list of images that can be used by this button
size_t currentImage;
ButtonState state;//current state of button from enum class ButtonBase : public CKeyShortcut
{
std::shared_ptr<CAnimImage> image; //image for this button
std::shared_ptr<CIntObject> overlay;//object-overlay, can be null
std::array<int, 4> stateToIndex; // mapping of button state to index of frame in animation std::array<int, 4> stateToIndex; // mapping of button state to index of frame in animation
EButtonState state;//current state of button from enum
void update();//to refresh button after image or text change
protected:
ButtonBase(Point position, const AnimationPath & defName, EShortcut key, bool playerColoredButton);
void setStateImpl(EButtonState state);
EButtonState getState();
public:
/// Appearance modifiers
void setPlayerColor(PlayerColor player);
void setImage(const AnimationPath & defName, bool playerColoredButton = false);
void setImageOrder(int state1, int state2, int state3, int state4);
/// adds overlay on top of button image. Only one overlay can be active at once
void setOverlay(std::shared_ptr<CIntObject> newOverlay);
void setTextOverlay(const std::string & Text, EFonts font, ColorRGBA color);
};
/// Typical Heroes 3 button which can be inactive or active and can
/// hold further information if you right-click it
class CButton : public ButtonBase
{
CFunctionList<void()> callback;
std::array<std::string, 4> hoverTexts; //texts for statusbar, if empty - first entry will be used std::array<std::string, 4> hoverTexts; //texts for statusbar, if empty - first entry will be used
std::optional<ColorRGBA> borderColor; // mapping of button state to border color std::optional<ColorRGBA> borderColor; // mapping of button state to border color
std::string helpBox; //for right-click help std::string helpBox; //for right-click help
std::shared_ptr<CAnimImage> image; //image for this button bool actOnDown; //runs when mouse is pressed down over it, not when up
std::shared_ptr<CIntObject> overlay;//object-overlay, can be null bool hoverable; //if true, button will be highlighted when hovered (e.g. main menu)
bool animateLonelyFrame = false; bool soundDisabled;
protected: protected:
void onButtonClicked(); // calls callback void onButtonClicked(); // calls callback
void update();//to refresh button after image or text change
// internal method to change state. Public change can be done only via block() // internal method to change state. Public change can be done only via block()
void setState(ButtonState newState); void setState(EButtonState newState);
ButtonState getState();
public: public:
bool actOnDown,//runs when mouse is pressed down over it, not when up
hoverable,//if true, button will be highlighted when hovered (e.g. main menu)
soundDisabled;
// sets the same border color for all button states. // sets the same border color for all button states.
void setBorderColor(std::optional<ColorRGBA> borderColor); void setBorderColor(std::optional<ColorRGBA> borderColor);
/// adds one more callback to on-click actions /// adds one more callback to on-click actions
void addCallback(const std::function<void()> & callback); void addCallback(const std::function<void()> & callback);
/// adds overlay on top of button image. Only one overlay can be active at once void addHoverText(EButtonState state, std::string text);
void addOverlay(std::shared_ptr<CIntObject> newOverlay);
void addTextOverlay(const std::string & Text, EFonts font, ColorRGBA color);
void addImage(const AnimationPath & filename);
void addHoverText(ButtonState state, std::string text);
void setImageOrder(int state1, int state2, int state3, int state4);
void setAnimateLonelyFrame(bool agreement);
void block(bool on); void block(bool on);
void setHoverable(bool on);
void setSoundDisabled(bool on);
void setActOnDown(bool on);
/// State modifiers /// State modifiers
bool isBlocked(); bool isBlocked();
bool isHighlighted(); bool isHighlighted();
@ -88,11 +101,6 @@ public:
CButton(Point position, const AnimationPath & defName, const std::pair<std::string, std::string> & help, CButton(Point position, const AnimationPath & defName, const std::pair<std::string, std::string> & help,
CFunctionList<void()> Callback = 0, EShortcut key = {}, bool playerColoredButton = false ); CFunctionList<void()> Callback = 0, EShortcut key = {}, bool playerColoredButton = false );
/// Appearance modifiers
void setIndex(size_t index);
void setImage(std::shared_ptr<CAnimation> anim, int animFlags=0);
void setPlayerColor(PlayerColor player);
/// CIntObject overrides /// CIntObject overrides
void showPopupWindow(const Point & cursorPosition) override; void showPopupWindow(const Point & cursorPosition) override;
void clickPressed(const Point & cursorPosition) override; void clickPressed(const Point & cursorPosition) override;
@ -110,10 +118,13 @@ public:
class CToggleBase class CToggleBase
{ {
CFunctionList<void(bool)> callback; CFunctionList<void(bool)> callback;
protected:
bool selected; bool selected;
/// if set to false - button can not be deselected normally
bool allowDeselection;
protected:
// internal method for overrides // internal method for overrides
virtual void doSelect(bool on); virtual void doSelect(bool on);
@ -121,9 +132,6 @@ protected:
bool canActivate(); bool canActivate();
public: public:
/// if set to false - button can not be deselected normally
bool allowDeselection;
CToggleBase(CFunctionList<void(bool)> callback); CToggleBase(CFunctionList<void(bool)> callback);
virtual ~CToggleBase(); virtual ~CToggleBase();
@ -133,6 +141,10 @@ public:
/// Changes selection to "on" without calling callback /// Changes selection to "on" without calling callback
void setSelectedSilent(bool on); void setSelectedSilent(bool on);
bool isSelected() const;
void setAllowDeselection(bool on);
void addCallback(std::function<void(bool)> callback); void addCallback(std::function<void(bool)> callback);
/// Set whether the toggle is currently enabled for user to use, this is only inplemented in ToggleButton, not for other toggles yet. /// Set whether the toggle is currently enabled for user to use, this is only inplemented in ToggleButton, not for other toggles yet.

View File

@ -168,10 +168,11 @@ ComboBox::ComboBox(Point position, const AnimationPath & defName, const std::pai
void ComboBox::setItem(const void * item) void ComboBox::setItem(const void * item)
{ {
auto w = std::dynamic_pointer_cast<CLabel>(overlay); // TODO:
//auto w = std::dynamic_pointer_cast<CLabel>(overlay);
if( w && getItemText) //if( w && getItemText)
addTextOverlay(getItemText(0, item), w->font, w->color); // setTextOverlay(getItemText(0, item), w->font, w->color);
if(onSetItem) if(onSetItem)
onSetItem(item); onSetItem(item);

View File

@ -206,10 +206,10 @@ CSlider::CSlider(Point position, int totalw, const std::function<void(int)> & Mo
right = std::make_shared<CButton>(Point(), AnimationPath::builtin(getOrientation() == Orientation::HORIZONTAL ? "SCNRBRT.DEF" : "SCNRBDN.DEF"), CButton::tooltip()); right = std::make_shared<CButton>(Point(), AnimationPath::builtin(getOrientation() == Orientation::HORIZONTAL ? "SCNRBRT.DEF" : "SCNRBDN.DEF"), CButton::tooltip());
slider = std::make_shared<CButton>(Point(), AnimationPath::builtin("SCNRBSL.DEF"), CButton::tooltip()); slider = std::make_shared<CButton>(Point(), AnimationPath::builtin("SCNRBSL.DEF"), CButton::tooltip());
} }
slider->actOnDown = true; slider->setActOnDown(true);
slider->soundDisabled = true; slider->setSoundDisabled(true);
left->soundDisabled = true; left->setSoundDisabled(true);
right->soundDisabled = true; right->setSoundDisabled(true);
if (getOrientation() == Orientation::HORIZONTAL) if (getOrientation() == Orientation::HORIZONTAL)
right->moveBy(Point(totalw - right->pos.w, 0)); right->moveBy(Point(totalw - right->pos.w, 0));

View File

@ -1334,12 +1334,12 @@ void CCastleInterface::recreateIcons()
fastTownHall = std::make_shared<CButton>(Point(80, 413), AnimationPath::builtin("ITMTL.def"), CButton::tooltip(), [&](){ builds->enterTownHall(); }); fastTownHall = std::make_shared<CButton>(Point(80, 413), AnimationPath::builtin("ITMTL.def"), CButton::tooltip(), [&](){ builds->enterTownHall(); });
fastTownHall->setImageOrder(town->hallLevel(), town->hallLevel(), town->hallLevel(), town->hallLevel()); fastTownHall->setImageOrder(town->hallLevel(), town->hallLevel(), town->hallLevel(), town->hallLevel());
fastTownHall->setAnimateLonelyFrame(true); //TODO: fastTownHall->setAnimateLonelyFrame(true);
int imageIndex = town->fortLevel() == CGTownInstance::EFortLevel::NONE ? 3 : town->fortLevel() - 1; int imageIndex = town->fortLevel() == CGTownInstance::EFortLevel::NONE ? 3 : town->fortLevel() - 1;
fastArmyPurchase = std::make_shared<CButton>(Point(122, 413), AnimationPath::builtin("itmcl.def"), CButton::tooltip(), [&](){ builds->enterToTheQuickRecruitmentWindow(); }); fastArmyPurchase = std::make_shared<CButton>(Point(122, 413), AnimationPath::builtin("itmcl.def"), CButton::tooltip(), [&](){ builds->enterToTheQuickRecruitmentWindow(); });
fastArmyPurchase->setImageOrder(imageIndex, imageIndex, imageIndex, imageIndex); fastArmyPurchase->setImageOrder(imageIndex, imageIndex, imageIndex, imageIndex);
fastArmyPurchase->setAnimateLonelyFrame(true); //TODO: fastArmyPurchase->setAnimateLonelyFrame(true);
fastMarket = std::make_shared<LRClickableArea>(Rect(163, 410, 64, 42), [&]() fastMarket = std::make_shared<LRClickableArea>(Rect(163, 410, 64, 42), [&]()
{ {

View File

@ -340,7 +340,7 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
}; };
auto upgradeBtn = std::make_shared<CButton>(Point(221 + (int)buttonIndex * 40, 5), AnimationPath::builtin("stackWindow/upgradeButton"), CGI->generaltexth->zelp[446], onClick); auto upgradeBtn = std::make_shared<CButton>(Point(221 + (int)buttonIndex * 40, 5), AnimationPath::builtin("stackWindow/upgradeButton"), CGI->generaltexth->zelp[446], onClick);
upgradeBtn->addOverlay(std::make_shared<CAnimImage>(AnimationPath::builtin("CPRSMALL"), VLC->creh->objects[upgradeInfo.info.newID[buttonIndex]]->getIconIndex())); upgradeBtn->setOverlay(std::make_shared<CAnimImage>(AnimationPath::builtin("CPRSMALL"), VLC->creh->objects[upgradeInfo.info.newID[buttonIndex]]->getIconIndex()));
if(buttonsToCreate == 1) // single upgrade avaialbe if(buttonsToCreate == 1) // single upgrade avaialbe
upgradeBtn->assignedKey = EShortcut::RECRUITMENT_UPGRADE; upgradeBtn->assignedKey = EShortcut::RECRUITMENT_UPGRADE;
@ -366,7 +366,7 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
std::string tooltipText = "vcmi.creatureWindow." + btnIDs[buttonIndex]; std::string tooltipText = "vcmi.creatureWindow." + btnIDs[buttonIndex];
parent->switchButtons[buttonIndex] = std::make_shared<CButton>(Point(302 + (int)buttonIndex*40, 5), AnimationPath::builtin("stackWindow/upgradeButton"), CButton::tooltipLocalized(tooltipText), onSwitch); parent->switchButtons[buttonIndex] = std::make_shared<CButton>(Point(302 + (int)buttonIndex*40, 5), AnimationPath::builtin("stackWindow/upgradeButton"), CButton::tooltipLocalized(tooltipText), onSwitch);
parent->switchButtons[buttonIndex]->addOverlay(std::make_shared<CAnimImage>(AnimationPath::builtin("stackWindow/switchModeIcons"), buttonIndex)); parent->switchButtons[buttonIndex]->setOverlay(std::make_shared<CAnimImage>(AnimationPath::builtin("stackWindow/switchModeIcons"), buttonIndex));
} }
parent->switchButtons[parent->activeTab]->disable(); parent->switchButtons[parent->activeTab]->disable();
} }

View File

@ -89,7 +89,7 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
{ {
questlogButton = std::make_shared<CButton>(Point(314, 429), AnimationPath::builtin("hsbtns4.def"), CButton::tooltip(heroscrn[0]), [=](){ LOCPLINT->showQuestLog(); }, EShortcut::ADVENTURE_QUEST_LOG); questlogButton = std::make_shared<CButton>(Point(314, 429), AnimationPath::builtin("hsbtns4.def"), CButton::tooltip(heroscrn[0]), [=](){ LOCPLINT->showQuestLog(); }, EShortcut::ADVENTURE_QUEST_LOG);
backpackButton = std::make_shared<CButton>(Point(424, 429), AnimationPath::builtin("buttons/backpack"), CButton::tooltipLocalized("vcmi.heroWindow.openBackpack"), [=](){ createBackpackWindow(); }, EShortcut::HERO_BACKPACK); backpackButton = std::make_shared<CButton>(Point(424, 429), AnimationPath::builtin("buttons/backpack"), CButton::tooltipLocalized("vcmi.heroWindow.openBackpack"), [=](){ createBackpackWindow(); }, EShortcut::HERO_BACKPACK);
backpackButton->addOverlay(std::make_shared<CPicture>(ImagePath::builtin("buttons/backpackButtonIcon"))); backpackButton->setOverlay(std::make_shared<CPicture>(ImagePath::builtin("buttons/backpackButtonIcon")));
dismissButton = std::make_shared<CButton>(Point(534, 429), AnimationPath::builtin("hsbtns2.def"), CButton::tooltip(heroscrn[28]), [=](){ dismissCurrent(); }, EShortcut::HERO_DISMISS); dismissButton = std::make_shared<CButton>(Point(534, 429), AnimationPath::builtin("hsbtns2.def"), CButton::tooltip(heroscrn[28]), [=](){ dismissCurrent(); }, EShortcut::HERO_DISMISS);
} }
else else
@ -197,9 +197,9 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded)
specName->setText(curHero->type->getSpecialtyNameTranslated()); specName->setText(curHero->type->getSpecialtyNameTranslated());
tacticsButton = std::make_shared<CToggleButton>(Point(539, 483), AnimationPath::builtin("hsbtns8.def"), std::make_pair(heroscrn[26], heroscrn[31]), 0, EShortcut::HERO_TOGGLE_TACTICS); tacticsButton = std::make_shared<CToggleButton>(Point(539, 483), AnimationPath::builtin("hsbtns8.def"), std::make_pair(heroscrn[26], heroscrn[31]), 0, EShortcut::HERO_TOGGLE_TACTICS);
tacticsButton->addHoverText(CButton::HIGHLIGHTED, CGI->generaltexth->heroscrn[25]); tacticsButton->addHoverText(EButtonState::HIGHLIGHTED, CGI->generaltexth->heroscrn[25]);
dismissButton->addHoverText(CButton::NORMAL, boost::str(boost::format(CGI->generaltexth->heroscrn[16]) % curHero->getNameTranslated() % curHero->getClassNameTranslated())); dismissButton->addHoverText(EButtonState::NORMAL, boost::str(boost::format(CGI->generaltexth->heroscrn[16]) % curHero->getNameTranslated() % curHero->getClassNameTranslated()));
portraitArea->hoverText = boost::str(boost::format(CGI->generaltexth->allTexts[15]) % curHero->getNameTranslated() % curHero->getClassNameTranslated()); portraitArea->hoverText = boost::str(boost::format(CGI->generaltexth->allTexts[15]) % curHero->getNameTranslated() % curHero->getClassNameTranslated());
portraitArea->text = curHero->getBiographyTranslated(); portraitArea->text = curHero->getBiographyTranslated();
portraitImage->setFrame(curHero->getIconIndex()); portraitImage->setFrame(curHero->getIconIndex());

View File

@ -823,11 +823,11 @@ CTownItem::CTownItem(const CGTownInstance * Town)
fastTownHall = std::make_shared<CButton>(Point(69, 31), AnimationPath::builtin("ITMTL.def"), CButton::tooltip(), [&]() { std::make_shared<CCastleBuildings>(town)->enterTownHall(); }); fastTownHall = std::make_shared<CButton>(Point(69, 31), AnimationPath::builtin("ITMTL.def"), CButton::tooltip(), [&]() { std::make_shared<CCastleBuildings>(town)->enterTownHall(); });
fastTownHall->setImageOrder(town->hallLevel(), town->hallLevel(), town->hallLevel(), town->hallLevel()); fastTownHall->setImageOrder(town->hallLevel(), town->hallLevel(), town->hallLevel(), town->hallLevel());
fastTownHall->setAnimateLonelyFrame(true); //TODO: fastTownHall->setAnimateLonelyFrame(true);
int imageIndex = town->fortLevel() == CGTownInstance::EFortLevel::NONE ? 3 : town->fortLevel() - 1; int imageIndex = town->fortLevel() == CGTownInstance::EFortLevel::NONE ? 3 : town->fortLevel() - 1;
fastArmyPurchase = std::make_shared<CButton>(Point(111, 31), AnimationPath::builtin("itmcl.def"), CButton::tooltip(), [&]() { std::make_shared<CCastleBuildings>(town)->enterToTheQuickRecruitmentWindow(); }); fastArmyPurchase = std::make_shared<CButton>(Point(111, 31), AnimationPath::builtin("itmcl.def"), CButton::tooltip(), [&]() { std::make_shared<CCastleBuildings>(town)->enterToTheQuickRecruitmentWindow(); });
fastArmyPurchase->setImageOrder(imageIndex, imageIndex, imageIndex, imageIndex); fastArmyPurchase->setImageOrder(imageIndex, imageIndex, imageIndex, imageIndex);
fastArmyPurchase->setAnimateLonelyFrame(true); //TODO: fastArmyPurchase->setAnimateLonelyFrame(true);
fastTavern = std::make_shared<LRClickableArea>(Rect(5, 6, 58, 64), [&]() fastTavern = std::make_shared<LRClickableArea>(Rect(5, 6, 58, 64), [&]()
{ {
if(town->builtBuildings.count(BuildingID::TAVERN)) if(town->builtBuildings.count(BuildingID::TAVERN))
@ -976,7 +976,7 @@ CHeroItem::CHeroItem(const CGHeroInstance * Hero)
std::string overlay = CGI->generaltexth->overview[8+it]; std::string overlay = CGI->generaltexth->overview[8+it];
auto button = std::make_shared<CToggleButton>(Point(364+(int)it*112, 46), AnimationPath::builtin("OVBUTN3"), CButton::tooltip(hover, overlay), 0); auto button = std::make_shared<CToggleButton>(Point(364+(int)it*112, 46), AnimationPath::builtin("OVBUTN3"), CButton::tooltip(hover, overlay), 0);
button->addTextOverlay(CGI->generaltexth->allTexts[stringID[it]], FONT_SMALL, Colors::YELLOW); button->setTextOverlay(CGI->generaltexth->allTexts[stringID[it]], FONT_SMALL, Colors::YELLOW);
artButtons->addToggle((int)it, button); artButtons->addToggle((int)it, button);
} }
artButtons->addCallback(std::bind(&CTabbedInt::setActive, artsTabs, _1)); artButtons->addCallback(std::bind(&CTabbedInt::setActive, artsTabs, _1));

View File

@ -481,24 +481,24 @@ CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj, const std::func
if(LOCPLINT->cb->getResourceAmount(EGameResID::GOLD) < GameConstants::HERO_GOLD_COST) //not enough gold if(LOCPLINT->cb->getResourceAmount(EGameResID::GOLD) < GameConstants::HERO_GOLD_COST) //not enough gold
{ {
recruit->addHoverText(CButton::NORMAL, CGI->generaltexth->tavernInfo[0]); //Cannot afford a Hero recruit->addHoverText(EButtonState::NORMAL, CGI->generaltexth->tavernInfo[0]); //Cannot afford a Hero
recruit->block(true); recruit->block(true);
} }
else if(LOCPLINT->cb->howManyHeroes(true) >= CGI->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_TOTAL_CAP)) else if(LOCPLINT->cb->howManyHeroes(true) >= CGI->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_TOTAL_CAP))
{ {
//Cannot recruit. You already have %d Heroes. //Cannot recruit. You already have %d Heroes.
recruit->addHoverText(CButton::NORMAL, boost::str(boost::format(CGI->generaltexth->tavernInfo[1]) % LOCPLINT->cb->howManyHeroes(true))); recruit->addHoverText(EButtonState::NORMAL, boost::str(boost::format(CGI->generaltexth->tavernInfo[1]) % LOCPLINT->cb->howManyHeroes(true)));
recruit->block(true); recruit->block(true);
} }
else if(LOCPLINT->cb->howManyHeroes(false) >= CGI->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP)) else if(LOCPLINT->cb->howManyHeroes(false) >= CGI->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP))
{ {
//Cannot recruit. You already have %d Heroes. //Cannot recruit. You already have %d Heroes.
recruit->addHoverText(CButton::NORMAL, boost::str(boost::format(CGI->generaltexth->tavernInfo[1]) % LOCPLINT->cb->howManyHeroes(false))); recruit->addHoverText(EButtonState::NORMAL, boost::str(boost::format(CGI->generaltexth->tavernInfo[1]) % LOCPLINT->cb->howManyHeroes(false)));
recruit->block(true); recruit->block(true);
} }
else if(dynamic_cast<const CGTownInstance *>(TavernObj) && dynamic_cast<const CGTownInstance *>(TavernObj)->visitingHero) else if(dynamic_cast<const CGTownInstance *>(TavernObj) && dynamic_cast<const CGTownInstance *>(TavernObj)->visitingHero)
{ {
recruit->addHoverText(CButton::NORMAL, CGI->generaltexth->tavernInfo[2]); //Cannot recruit. You already have a Hero in this town. recruit->addHoverText(EButtonState::NORMAL, CGI->generaltexth->tavernInfo[2]); //Cannot recruit. You already have a Hero in this town.
recruit->block(true); recruit->block(true);
} }
else else
@ -586,7 +586,7 @@ void CTavernWindow::show(Canvas & to)
//Recruit %s the %s //Recruit %s the %s
if (!recruit->isBlocked()) if (!recruit->isBlocked())
recruit->addHoverText(CButton::NORMAL, boost::str(boost::format(CGI->generaltexth->tavernInfo[3]) % sel->h->getNameTranslated() % sel->h->getClassNameTranslated())); recruit->addHoverText(EButtonState::NORMAL, boost::str(boost::format(CGI->generaltexth->tavernInfo[3]) % sel->h->getNameTranslated() % sel->h->getClassNameTranslated()));
} }
@ -880,10 +880,10 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
std::bind(moveArtifacts, [this](bool equipped, bool baclpack) -> void {controller.moveArtifacts(false, equipped, baclpack);})); std::bind(moveArtifacts, [this](bool equipped, bool baclpack) -> void {controller.moveArtifacts(false, equipped, baclpack);}));
backpackButtonLeft = std::make_shared<CButton>(Point(325, 518), AnimationPath::builtin("buttons/backpack"), CButton::tooltipLocalized("vcmi.heroWindow.openBackpack"), backpackButtonLeft = std::make_shared<CButton>(Point(325, 518), AnimationPath::builtin("buttons/backpack"), CButton::tooltipLocalized("vcmi.heroWindow.openBackpack"),
std::bind(openBackpack, heroInst[0])); std::bind(openBackpack, heroInst[0]));
backpackButtonLeft->addOverlay(std::make_shared<CPicture>(ImagePath::builtin("buttons/backpackButtonIcon"))); backpackButtonLeft->setOverlay(std::make_shared<CPicture>(ImagePath::builtin("buttons/backpackButtonIcon")));
backpackButtonRight = std::make_shared<CButton>(Point(419, 518), AnimationPath::builtin("buttons/backpack"), CButton::tooltipLocalized("vcmi.heroWindow.openBackpack"), backpackButtonRight = std::make_shared<CButton>(Point(419, 518), AnimationPath::builtin("buttons/backpack"), CButton::tooltipLocalized("vcmi.heroWindow.openBackpack"),
std::bind(openBackpack, heroInst[1])); std::bind(openBackpack, heroInst[1]));
backpackButtonRight->addOverlay(std::make_shared<CPicture>(ImagePath::builtin("buttons/backpackButtonIcon"))); backpackButtonRight->setOverlay(std::make_shared<CPicture>(ImagePath::builtin("buttons/backpackButtonIcon")));
auto leftHeroBlock = heroInst[0]->tempOwner != LOCPLINT->cb->getPlayerID(); auto leftHeroBlock = heroInst[0]->tempOwner != LOCPLINT->cb->getPlayerID();
auto rightHeroBlock = heroInst[1]->tempOwner != LOCPLINT->cb->getPlayerID(); auto rightHeroBlock = heroInst[1]->tempOwner != LOCPLINT->cb->getPlayerID();
@ -1355,9 +1355,7 @@ CHillFortWindow::CHillFortWindow(const CGHeroInstance * visitor, const CGObjectI
for(int i = 0; i < slotsCount; i++) for(int i = 0; i < slotsCount; i++)
{ {
upgrade[i] = std::make_shared<CButton>(Point(107 + i * 76, 171), AnimationPath(), CButton::tooltip(getTextForSlot(SlotID(i))), [=](){ makeDeal(SlotID(i)); }, vstd::next(EShortcut::SELECT_INDEX_1, i)); upgrade[i] = std::make_shared<CButton>(Point(107 + i * 76, 171), AnimationPath::builtin("APHLF1R"), 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(AnimationPath::builtin(image));
for(int j : {0,1}) for(int j : {0,1})
{ {
@ -1366,9 +1364,7 @@ CHillFortWindow::CHillFortWindow(const CGHeroInstance * visitor, const CGObjectI
} }
} }
upgradeAll = std::make_shared<CButton>(Point(30, 231), AnimationPath(), CButton::tooltip(CGI->generaltexth->allTexts[432]), [&](){ makeDeal(SlotID(slotsCount));}, EShortcut::RECRUITMENT_UPGRADE_ALL); upgradeAll = std::make_shared<CButton>(Point(30, 231), AnimationPath::builtin("APHLF4R"), CButton::tooltip(CGI->generaltexth->allTexts[432]), [&](){ makeDeal(SlotID(slotsCount));}, EShortcut::RECRUITMENT_UPGRADE_ALL);
for(auto image : { "APHLF4R.DEF", "APHLF4Y.DEF", "APHLF4G.DEF" })
upgradeAll->addImage(AnimationPath::builtin(image));
quit = std::make_shared<CButton>(Point(294, 275), AnimationPath::builtin("IOKAY.DEF"), CButton::tooltip(), std::bind(&CHillFortWindow::close, this), EShortcut::GLOBAL_ACCEPT); quit = std::make_shared<CButton>(Point(294, 275), AnimationPath::builtin("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)); statusbar = CGStatusBar::create(std::make_shared<CPicture>(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
@ -1384,6 +1380,9 @@ bool CHillFortWindow::holdsGarrison(const CArmedInstance * army)
void CHillFortWindow::updateGarrisons() void CHillFortWindow::updateGarrisons()
{ {
constexpr std::array slotImages = { "APHLF1R.DEF", "APHLF1Y.DEF", "APHLF1G.DEF" };
constexpr std::array allImages = { "APHLF4R.DEF", "APHLF4Y.DEF", "APHLF4G.DEF" };
std::array<TResources, slotsCount> costs;// costs [slot ID] [resource ID] = resource count for upgrade std::array<TResources, slotsCount> costs;// costs [slot ID] [resource ID] = resource count for upgrade
TResources totalSum; // totalSum[resource ID] = value TResources totalSum; // totalSum[resource ID] = value
@ -1404,9 +1403,9 @@ void CHillFortWindow::updateGarrisons()
} }
currState[i] = newState; currState[i] = newState;
upgrade[i]->setIndex(currState[i] == -1 ? 0 : currState[i]); upgrade[i]->setImage(AnimationPath::builtin(currState[i] == -1 ? slotImages[0] : slotImages[currState[i]]));
upgrade[i]->block(currState[i] == -1); upgrade[i]->block(currState[i] == -1);
upgrade[i]->addHoverText(CButton::NORMAL, getTextForSlot(SlotID(i))); upgrade[i]->addHoverText(EButtonState::NORMAL, getTextForSlot(SlotID(i)));
} }
//"Upgrade all" slot //"Upgrade all" slot
@ -1426,7 +1425,7 @@ void CHillFortWindow::updateGarrisons()
} }
currState[slotsCount] = newState; currState[slotsCount] = newState;
upgradeAll->setIndex(newState); upgradeAll->setImage(AnimationPath::builtin(allImages[newState]));
garr->recreateSlots(); garr->recreateSlots();