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

@@ -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