1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-06 09:09:40 +02:00

Implemented configurable buttons. Replaced 'animateLonelyFrame' logic.

This commit is contained in:
Ivan Savenko
2024-02-28 22:24:19 +02:00
parent 07d201502e
commit 0051ffa7a9
9 changed files with 140 additions and 41 deletions

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,7 +0,0 @@
{
"basepath" : "lobby/",
"images" :
[
{ "frame" : 0, "file" : "selectionTabSortDate.png"}
]
}

View File

@@ -216,8 +216,9 @@ SelectionTab::SelectionTab(ESelectionScreen Type)
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)));
//TODO: buttonsSortBy.back()->setAnimateLonelyFrame(true);
auto sortByDate = std::make_shared<CButton>(Point(371, 85), AnimationPath::builtin("selectionTabSortDate"), CButton::tooltip("", CGI->generaltexth->translate("vcmi.lobby.sortDate")), std::bind(&SelectionTab::sortBy, this, ESortBy::_changeDate));
sortByDate->setOverlay(std::make_shared<CPicture>(ImagePath::builtin("lobby/selectionTabSortDate")));
buttonsSortBy.push_back(sortByDate);
}
iconsMapFormats = GH.renderHandler().loadAnimation(AnimationPath::builtin("SCSELC.DEF"));

View File

@@ -22,6 +22,7 @@
#include "../gui/CGuiHandler.h"
#include "../gui/MouseButton.h"
#include "../gui/Shortcut.h"
#include "../gui/InterfaceObjectConfigurable.h"
#include "../windows/InfoWindows.h"
#include "../render/CAnimation.h"
#include "../render/Canvas.h"
@@ -29,6 +30,7 @@
#include "../../lib/CConfigHandler.h"
#include "../../lib/CGeneralTextHandler.h"
#include "../../lib/filesystem/Filesystem.h"
void ButtonBase::update()
{
@@ -42,15 +44,14 @@ void ButtonBase::update()
overlay->moveTo(targetPos);
}
int newPos = stateToIndex[int(state)];
if (newPos < 0)
newPos = 0;
// 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;
image->setFrame(newPos);
if (image)
{
// 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)
image->setFrame(image->size()-1);
image->setFrame(stateToIndex[vstd::to_underlying(state)]);
}
if (isActive())
redraw();
@@ -89,6 +90,7 @@ void ButtonBase::setImage(const AnimationPath & defName, bool playerColoredButto
{
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
configurable.reset();
image = std::make_shared<CAnimImage>(defName, vstd::to_underlying(getState()));
pos = image->pos;
@@ -96,6 +98,41 @@ void ButtonBase::setImage(const AnimationPath & defName, bool playerColoredButto
image->playerColored(LOCPLINT->playerID);
}
const JsonNode & ButtonBase::getCurrentConfig() const
{
if (!config)
throw std::runtime_error("No config found in button!");
static constexpr std::array stateToConfig = {
"normal",
"pressed",
"blocked",
"highlighted"
};
std::string key = stateToConfig[vstd::to_underlying(getState())];
const JsonNode & value = (*config)[key];
if (value.isNull())
throw std::runtime_error("No config found in button for state " + key + "!");
return value;
}
void ButtonBase::setConfigurable(const JsonPath & jsonName, bool playerColoredButton)
{
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
config = std::make_unique<JsonNode>(jsonName);
image.reset();
configurable = std::make_shared<InterfaceObjectConfigurable>(getCurrentConfig());
pos = configurable->pos;
if (playerColoredButton)
image->playerColored(LOCPLINT->playerID);
}
void CButton::addHoverText(EButtonState state, std::string text)
{
hoverTexts[vstd::to_underlying(state)] = text;
@@ -110,15 +147,24 @@ void ButtonBase::setImageOrder(int state1, int state2, int state3, int state4)
update();
}
//TODO:
//void CButton::setAnimateLonelyFrame(bool agreement)
//{
// animateLonelyFrame = agreement;
//}
void ButtonBase::setStateImpl(EButtonState newState)
{
state = newState;
if (configurable)
{
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
configurable = std::make_shared<InterfaceObjectConfigurable>(getCurrentConfig());
pos = configurable->pos;
if (overlay)
{
// Force overlay on top
removeChild(overlay.get());
addChild(overlay.get());
}
}
update();
}
@@ -135,7 +181,7 @@ void CButton::setState(EButtonState newState)
setStateImpl(newState);
}
EButtonState ButtonBase::getState()
EButtonState ButtonBase::getState() const
{
return state;
}
@@ -270,9 +316,21 @@ ButtonBase::ButtonBase(Point position, const AnimationPath & defName, EShortcut
pos.x += position.x;
pos.y += position.y;
setImage(defName);
JsonPath jsonConfig = defName.toType<EResType::JSON>().addPrefix("CONFIG/WIDGETS/BUTTONS/");
if (CResourceHandler::get()->existsResource(jsonConfig))
{
setConfigurable(jsonConfig, playerColoredButton);
return;
}
else
{
setImage(defName, playerColoredButton);
return;
}
}
ButtonBase::~ButtonBase() = default;
CButton::CButton(Point position, const AnimationPath &defName, const std::pair<std::string, std::string> &help, CFunctionList<void()> Callback, EShortcut key, bool playerColoredButton):
ButtonBase(position, defName, key, playerColoredButton),
callback(Callback)

View File

@@ -19,8 +19,7 @@ class Rect;
VCMI_LIB_NAMESPACE_END
class CAnimImage;
class CLabel;
class CAnimation;
class InterfaceObjectConfigurable;
enum class EButtonState
{
@@ -33,7 +32,9 @@ enum class EButtonState
class ButtonBase : public CKeyShortcut
{
std::shared_ptr<CAnimImage> image; //image for this button
std::shared_ptr<InterfaceObjectConfigurable> configurable; //image for this button
std::shared_ptr<CIntObject> overlay;//object-overlay, can be null
std::unique_ptr<JsonNode> config;
std::array<int, 4> stateToIndex; // mapping of button state to index of frame in animation
@@ -41,16 +42,20 @@ class ButtonBase : public CKeyShortcut
void update();//to refresh button after image or text change
const JsonNode & getCurrentConfig() const;
protected:
ButtonBase(Point position, const AnimationPath & defName, EShortcut key, bool playerColoredButton);
~ButtonBase();
void setStateImpl(EButtonState state);
EButtonState getState();
EButtonState getState() const;
public:
/// Appearance modifiers
void setPlayerColor(PlayerColor player);
void setImage(const AnimationPath & defName, bool playerColoredButton = false);
void setConfigurable(const JsonPath & jsonName, 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

View File

@@ -1332,14 +1332,12 @@ void CCastleInterface::recreateIcons()
hall = std::make_shared<CTownInfo>(80, 413, town, true);
fort = std::make_shared<CTownInfo>(122, 413, town, false);
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());
//TODO: fastTownHall->setAnimateLonelyFrame(true);
fastTownHall = std::make_shared<CButton>(Point(80, 413), AnimationPath::builtin("castleInterfaceQuickAccess"), CButton::tooltip(), [&](){ builds->enterTownHall(); });
fastTownHall->setOverlay(std::make_shared<CAnimImage>(AnimationPath::builtin("ITMTL"), town->hallLevel()));
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->setImageOrder(imageIndex, imageIndex, imageIndex, imageIndex);
//TODO: fastArmyPurchase->setAnimateLonelyFrame(true);
fastArmyPurchase = std::make_shared<CButton>(Point(122, 413), AnimationPath::builtin("castleInterfaceQuickAccess"), CButton::tooltip(), [&](){ builds->enterToTheQuickRecruitmentWindow(); });
fastArmyPurchase->setOverlay(std::make_shared<CAnimImage>(AnimationPath::builtin("itmcl"), imageIndex));
fastMarket = std::make_shared<LRClickableArea>(Rect(163, 410, 64, 42), [&]()
{

View File

@@ -821,13 +821,13 @@ CTownItem::CTownItem(const CGTownInstance * Town)
available.push_back(std::make_shared<CCreaInfo>(Point(48+37*(int)i, 78), town, (int)i, true, false));
}
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());
//TODO: fastTownHall->setAnimateLonelyFrame(true);
fastTownHall = std::make_shared<CButton>(Point(69, 31), AnimationPath::builtin("castleInterfaceQuickAccessz"), CButton::tooltip(), [&]() { std::make_shared<CCastleBuildings>(town)->enterTownHall(); });
fastTownHall->setOverlay(std::make_shared<CAnimImage>(AnimationPath::builtin("ITMTL"), town->hallLevel()));
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->setImageOrder(imageIndex, imageIndex, imageIndex, imageIndex);
//TODO: fastArmyPurchase->setAnimateLonelyFrame(true);
fastArmyPurchase = std::make_shared<CButton>(Point(111, 31), AnimationPath::builtin("castleInterfaceQuickAccessz"), CButton::tooltip(), [&]() { std::make_shared<CCastleBuildings>(town)->enterToTheQuickRecruitmentWindow(); });
fastArmyPurchase->setOverlay(std::make_shared<CAnimImage>(AnimationPath::builtin("itmcl"), imageIndex));
fastTavern = std::make_shared<LRClickableArea>(Rect(5, 6, 58, 64), [&]()
{
if(town->builtBuildings.count(BuildingID::TAVERN))

View File

@@ -0,0 +1,22 @@
{
"normal" : {
"width": 38,
"height": 38,
"items" : []
},
"pressed" : {
"width": 38,
"height": 38,
"items" : []
},
"blocked" : {
"width": 38,
"height": 38,
"items" : []
},
"highlighted" : {
"width": 38,
"height": 38,
"items" : []
},
}

View File

@@ -0,0 +1,22 @@
{
"normal" : {
"width": 18,
"height": 31,
"items" : []
},
"pressed" : {
"width": 18,
"height": 31,
"items" : []
},
"blocked" : {
"width": 18,
"height": 31,
"items" : []
},
"highlighted" : {
"width": 18,
"height": 31,
"items" : []
},
}