2020-09-21 17:17:34 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2020-06-28 16:39:18 +00:00
|
|
|
//
|
2020-09-21 17:17:34 +00:00
|
|
|
// EmulationStation Desktop Edition
|
2020-06-28 16:39:18 +00:00
|
|
|
// GridTileComponent.cpp
|
|
|
|
//
|
|
|
|
// X*Y grid.
|
|
|
|
//
|
|
|
|
|
2018-04-07 19:23:10 +00:00
|
|
|
#include "GridTileComponent.h"
|
|
|
|
|
2019-07-06 14:50:50 +00:00
|
|
|
#include "animations/LambdaAnimation.h"
|
2018-04-07 19:23:10 +00:00
|
|
|
#include "resources/TextureResource.h"
|
|
|
|
#include "ThemeData.h"
|
|
|
|
|
|
|
|
GridTileComponent::GridTileComponent(Window* window) : GuiComponent(window), mBackground(window)
|
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
mDefaultProperties.mSize = getDefaultTileSize();
|
|
|
|
mDefaultProperties.mPadding = Vector2f(16.0f, 16.0f);
|
|
|
|
mDefaultProperties.mImageColor = 0xAAAAAABB;
|
|
|
|
mDefaultProperties.mBackgroundImage = ":/graphics/frame.png";
|
|
|
|
mDefaultProperties.mBackgroundCornerSize = Vector2f(16 ,16);
|
|
|
|
mDefaultProperties.mBackgroundCenterColor = 0xAAAAEEFF;
|
|
|
|
mDefaultProperties.mBackgroundEdgeColor = 0xAAAAEEFF;
|
|
|
|
|
|
|
|
mSelectedProperties.mSize = getSelectedTileSize();
|
|
|
|
mSelectedProperties.mPadding = mDefaultProperties.mPadding;
|
|
|
|
mSelectedProperties.mImageColor = 0xFFFFFFFF;
|
|
|
|
mSelectedProperties.mBackgroundImage = mDefaultProperties.mBackgroundImage;
|
|
|
|
mSelectedProperties.mBackgroundCornerSize = mDefaultProperties.mBackgroundCornerSize;
|
|
|
|
mSelectedProperties.mBackgroundCenterColor = 0xFFFFFFFF;
|
|
|
|
mSelectedProperties.mBackgroundEdgeColor = 0xFFFFFFFF;
|
|
|
|
|
|
|
|
mImage = std::make_shared<ImageComponent>(mWindow);
|
|
|
|
mImage->setOrigin(0.5f, 0.5f);
|
|
|
|
|
|
|
|
mBackground.setOrigin(0.5f, 0.5f);
|
|
|
|
|
|
|
|
addChild(&mBackground);
|
|
|
|
addChild(&(*mImage));
|
|
|
|
|
|
|
|
mSelectedZoomPercent = 0;
|
|
|
|
|
|
|
|
setSelected(false, false);
|
|
|
|
setVisible(true);
|
2018-04-07 19:23:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GridTileComponent::render(const Transform4x4f& parentTrans)
|
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
Transform4x4f trans = getTransform() * parentTrans;
|
2018-04-07 19:23:10 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
if (mVisible)
|
|
|
|
renderChildren(trans);
|
2018-04-07 19:23:10 +00:00
|
|
|
}
|
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
// Update all the tile properties to the new status (selected or default).
|
2019-07-06 14:50:50 +00:00
|
|
|
void GridTileComponent::update(int deltaTime)
|
2018-04-07 19:23:10 +00:00
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
GuiComponent::update(deltaTime);
|
2019-07-06 14:50:50 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
calcCurrentProperties();
|
2018-04-07 19:23:10 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
mBackground.setImagePath(mCurrentProperties.mBackgroundImage);
|
2018-04-07 19:23:10 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
mImage->setColorShift(mCurrentProperties.mImageColor);
|
|
|
|
mBackground.setCenterColor(mCurrentProperties.mBackgroundCenterColor);
|
|
|
|
mBackground.setEdgeColor(mCurrentProperties.mBackgroundEdgeColor);
|
2018-04-07 19:23:10 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
resize();
|
2018-04-07 19:23:10 +00:00
|
|
|
}
|
|
|
|
|
2019-10-08 02:25:39 +00:00
|
|
|
void applyThemeToProperties(const ThemeData::ThemeElement* elem, GridTileProperties* properties)
|
2018-04-07 19:23:10 +00:00
|
|
|
{
|
2020-11-17 22:06:54 +00:00
|
|
|
Vector2f screen = Vector2f(static_cast<float>(Renderer::getScreenWidth()),
|
|
|
|
static_cast<float>(Renderer::getScreenHeight()));
|
2018-04-07 19:23:10 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
if (elem->has("size"))
|
|
|
|
properties->mSize = elem->get<Vector2f>("size") * screen;
|
2018-04-07 19:23:10 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
if (elem->has("padding"))
|
|
|
|
properties->mPadding = elem->get<Vector2f>("padding");
|
2018-04-07 19:23:10 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
if (elem->has("imageColor"))
|
|
|
|
properties->mImageColor = elem->get<unsigned int>("imageColor");
|
2018-05-10 20:26:29 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
if (elem->has("backgroundImage"))
|
|
|
|
properties->mBackgroundImage = elem->get<std::string>("backgroundImage");
|
2018-04-07 19:23:10 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
if (elem->has("backgroundCornerSize"))
|
|
|
|
properties->mBackgroundCornerSize = elem->get<Vector2f>("backgroundCornerSize");
|
2018-04-07 19:23:10 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
if (elem->has("backgroundColor")) {
|
|
|
|
properties->mBackgroundCenterColor = elem->get<unsigned int>("backgroundColor");
|
|
|
|
properties->mBackgroundEdgeColor = elem->get<unsigned int>("backgroundColor");
|
|
|
|
}
|
2018-05-10 20:26:29 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
if (elem->has("backgroundCenterColor"))
|
|
|
|
properties->mBackgroundCenterColor = elem->get<unsigned int>("backgroundCenterColor");
|
2018-05-10 20:26:29 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
if (elem->has("backgroundEdgeColor"))
|
|
|
|
properties->mBackgroundEdgeColor = elem->get<unsigned int>("backgroundEdgeColor");
|
2019-07-06 14:50:50 +00:00
|
|
|
}
|
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
void GridTileComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|
|
|
const std::string& view, const std::string& /*element*/, unsigned int /*properties*/)
|
2019-07-06 14:50:50 +00:00
|
|
|
{
|
2020-11-17 22:06:54 +00:00
|
|
|
Vector2f screen = Vector2f(static_cast<float>(Renderer::getScreenWidth()),
|
|
|
|
static_cast<float>(Renderer::getScreenHeight()));
|
2020-06-28 16:39:18 +00:00
|
|
|
|
|
|
|
// Apply theme to the default gridtile.
|
|
|
|
const ThemeData::ThemeElement* elem = theme->getElement(view, "default", "gridtile");
|
|
|
|
if (elem)
|
|
|
|
applyThemeToProperties(elem, &mDefaultProperties);
|
|
|
|
|
|
|
|
// Apply theme to the selected gridtile. Note that some of the default gridtile
|
|
|
|
// properties have influence on the selected gridtile properties.
|
|
|
|
// See THEMES.md for more informations.
|
|
|
|
elem = theme->getElement(view, "selected", "gridtile");
|
|
|
|
|
|
|
|
mSelectedProperties.mSize = getSelectedTileSize();
|
|
|
|
mSelectedProperties.mPadding = mDefaultProperties.mPadding;
|
|
|
|
mSelectedProperties.mBackgroundImage = mDefaultProperties.mBackgroundImage;
|
|
|
|
mSelectedProperties.mBackgroundCornerSize = mDefaultProperties.mBackgroundCornerSize;
|
|
|
|
|
|
|
|
if (elem)
|
|
|
|
applyThemeToProperties(elem, &mSelectedProperties);
|
2018-04-07 19:23:10 +00:00
|
|
|
}
|
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
// Made this a static function because the ImageGridComponent needs to know the default tile
|
|
|
|
// max size to calculate the grid dimension before it instantiates the GridTileComponents.
|
2018-04-07 19:23:10 +00:00
|
|
|
Vector2f GridTileComponent::getDefaultTileSize()
|
|
|
|
{
|
2020-11-17 22:06:54 +00:00
|
|
|
Vector2f screen = Vector2f(static_cast<float>(Renderer::getScreenWidth()),
|
|
|
|
static_cast<float>(Renderer::getScreenHeight()));
|
2018-04-07 19:23:10 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
return screen * 0.22f;
|
2018-04-07 19:23:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Vector2f GridTileComponent::getSelectedTileSize() const
|
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
return mDefaultProperties.mSize * 1.2f;
|
2018-04-07 19:23:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool GridTileComponent::isSelected() const
|
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
return mSelected;
|
2018-04-07 19:23:10 +00:00
|
|
|
}
|
|
|
|
|
2019-07-06 14:50:50 +00:00
|
|
|
void GridTileComponent::reset()
|
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
setImage("");
|
2019-07-06 14:50:50 +00:00
|
|
|
}
|
|
|
|
|
2018-04-07 19:23:10 +00:00
|
|
|
void GridTileComponent::setImage(const std::string& path)
|
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
mImage->setImage(path);
|
2018-06-08 09:29:52 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
// Resize now to prevent flickering images when scrolling.
|
|
|
|
resize();
|
2018-04-07 19:23:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GridTileComponent::setImage(const std::shared_ptr<TextureResource>& texture)
|
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
mImage->setImage(texture);
|
2018-04-07 19:23:10 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
// Resize now to prevent flickering images when scrolling.
|
|
|
|
resize();
|
2018-04-07 19:23:10 +00:00
|
|
|
}
|
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
void GridTileComponent::setSelected(bool selected, bool allowAnimation,
|
|
|
|
Vector3f* pPosition, bool force)
|
2018-04-07 19:23:10 +00:00
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
if (mSelected == selected && !force)
|
|
|
|
return;
|
|
|
|
|
|
|
|
mSelected = selected;
|
|
|
|
|
|
|
|
if (selected) {
|
|
|
|
if (pPosition == nullptr || !allowAnimation) {
|
|
|
|
cancelAnimation(3);
|
|
|
|
|
|
|
|
this->setSelectedZoom(1);
|
|
|
|
mAnimPosition = Vector3f(0, 0, 0);
|
|
|
|
|
|
|
|
resize();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mAnimPosition = Vector3f(pPosition->x(), pPosition->y(), pPosition->z());
|
|
|
|
|
|
|
|
auto func = [this](float t) {
|
|
|
|
t -= 1; // Cubic ease out.
|
|
|
|
float pct = Math::lerp(0, 1, t*t*t + 1);
|
|
|
|
this->setSelectedZoom(pct);
|
|
|
|
};
|
|
|
|
|
|
|
|
cancelAnimation(3);
|
|
|
|
setAnimation(new LambdaAnimation(func, 250), 0, [this] {
|
|
|
|
this->setSelectedZoom(1);
|
|
|
|
mAnimPosition = Vector3f(0, 0, 0);
|
|
|
|
}, false, 3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If (!selected).
|
|
|
|
else {
|
|
|
|
if (!allowAnimation) {
|
|
|
|
cancelAnimation(3);
|
|
|
|
this->setSelectedZoom(0);
|
|
|
|
|
|
|
|
resize();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this->setSelectedZoom(1);
|
|
|
|
|
|
|
|
auto func = [this](float t) {
|
|
|
|
t -= 1; // Cubic ease out.
|
|
|
|
float pct = Math::lerp(0, 1, t*t*t + 1);
|
2020-12-29 11:54:24 +00:00
|
|
|
this->setSelectedZoom(1.0f - pct);
|
2020-06-28 16:39:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
cancelAnimation(3);
|
|
|
|
setAnimation(new LambdaAnimation(func, 250), 0, [this] {
|
|
|
|
this->setSelectedZoom(0);
|
|
|
|
}, false, 3);
|
|
|
|
}
|
|
|
|
}
|
2019-07-06 14:50:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GridTileComponent::setSelectedZoom(float percent)
|
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
if (mSelectedZoomPercent == percent)
|
|
|
|
return;
|
2019-07-06 14:50:50 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
mSelectedZoomPercent = percent;
|
|
|
|
resize();
|
2018-04-07 19:23:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GridTileComponent::setVisible(bool visible)
|
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
mVisible = visible;
|
2018-04-07 19:23:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GridTileComponent::resize()
|
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
calcCurrentProperties();
|
2019-07-06 14:50:50 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
mImage->setMaxSize(mCurrentProperties.mSize - mCurrentProperties.mPadding * 2);
|
|
|
|
mBackground.setCornerSize(mCurrentProperties.mBackgroundCornerSize);
|
|
|
|
mBackground.fitTo(mCurrentProperties.mSize - mBackground.getCornerSize() * 2);
|
2019-07-06 14:50:50 +00:00
|
|
|
}
|
2018-04-07 19:23:10 +00:00
|
|
|
|
2019-07-06 14:50:50 +00:00
|
|
|
unsigned int mixColors(unsigned int first, unsigned int second, float percent)
|
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
unsigned char alpha0 = (first >> 24) & 0xFF;
|
|
|
|
unsigned char blue0 = (first >> 16) & 0xFF;
|
|
|
|
unsigned char green0 = (first >> 8) & 0xFF;
|
|
|
|
unsigned char red0 = first & 0xFF;
|
|
|
|
|
|
|
|
unsigned char alpha1 = (second >> 24) & 0xFF;
|
|
|
|
unsigned char blue1 = (second >> 16) & 0xFF;
|
|
|
|
unsigned char green1 = (second >> 8) & 0xFF;
|
|
|
|
unsigned char red1 = second & 0xFF;
|
|
|
|
|
2020-11-17 22:06:54 +00:00
|
|
|
unsigned char alpha = static_cast<unsigned char>(alpha0 * (1.0 - percent) + alpha1 * percent);
|
|
|
|
unsigned char blue = static_cast<unsigned char>(blue0 * (1.0 - percent) + blue1 * percent);
|
|
|
|
unsigned char green = static_cast<unsigned char>(green0 * (1.0 - percent) + green1 * percent);
|
|
|
|
unsigned char red = static_cast<unsigned char>(red0 * (1.0 - percent) + red1 * percent);
|
2020-06-28 16:39:18 +00:00
|
|
|
|
|
|
|
return (alpha << 24) | (blue << 16) | (green << 8) | red;
|
2018-04-07 19:23:10 +00:00
|
|
|
}
|
|
|
|
|
2019-07-06 14:50:50 +00:00
|
|
|
void GridTileComponent::calcCurrentProperties()
|
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
mCurrentProperties = mSelected ? mSelectedProperties : mDefaultProperties;
|
|
|
|
|
2020-12-29 11:54:24 +00:00
|
|
|
float zoomPercentInverse = 1.0f - mSelectedZoomPercent;
|
2020-06-28 16:39:18 +00:00
|
|
|
|
|
|
|
if (mSelectedZoomPercent != 0.0f && mSelectedZoomPercent != 1.0f) {
|
|
|
|
if (mDefaultProperties.mSize != mSelectedProperties.mSize)
|
|
|
|
mCurrentProperties.mSize = mDefaultProperties.mSize * zoomPercentInverse +
|
|
|
|
mSelectedProperties.mSize * mSelectedZoomPercent;
|
|
|
|
|
|
|
|
if (mDefaultProperties.mPadding != mSelectedProperties.mPadding)
|
|
|
|
mCurrentProperties.mPadding = mDefaultProperties.mPadding * zoomPercentInverse +
|
|
|
|
mSelectedProperties.mPadding * mSelectedZoomPercent;
|
|
|
|
|
|
|
|
if (mDefaultProperties.mImageColor != mSelectedProperties.mImageColor)
|
|
|
|
mCurrentProperties.mImageColor = mixColors(mDefaultProperties.mImageColor,
|
|
|
|
mSelectedProperties.mImageColor, mSelectedZoomPercent);
|
|
|
|
|
|
|
|
if (mDefaultProperties.mBackgroundCornerSize != mSelectedProperties.mBackgroundCornerSize)
|
|
|
|
mCurrentProperties.mBackgroundCornerSize = mDefaultProperties.mBackgroundCornerSize *
|
|
|
|
zoomPercentInverse + mSelectedProperties.mBackgroundCornerSize *
|
|
|
|
mSelectedZoomPercent;
|
|
|
|
|
|
|
|
if (mDefaultProperties.mBackgroundCenterColor != mSelectedProperties.mBackgroundCenterColor)
|
|
|
|
mCurrentProperties.mBackgroundCenterColor =
|
|
|
|
mixColors(mDefaultProperties.mBackgroundCenterColor,
|
|
|
|
mSelectedProperties.mBackgroundCenterColor, mSelectedZoomPercent);
|
|
|
|
|
|
|
|
if (mDefaultProperties.mBackgroundEdgeColor != mSelectedProperties.mBackgroundEdgeColor)
|
|
|
|
mCurrentProperties.mBackgroundEdgeColor =
|
|
|
|
mixColors(mDefaultProperties.mBackgroundEdgeColor,
|
|
|
|
mSelectedProperties.mBackgroundEdgeColor, mSelectedZoomPercent);
|
|
|
|
}
|
2019-07-06 14:50:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Vector3f GridTileComponent::getBackgroundPosition()
|
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
return mBackground.getPosition() + mPosition;
|
2019-07-06 14:50:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<TextureResource> GridTileComponent::getTexture()
|
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
if (mImage != nullptr)
|
|
|
|
return mImage->getTexture();
|
2019-07-06 14:50:50 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
return nullptr;
|
2019-07-06 14:50:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
void GridTileComponent::forceSize(Vector2f size, float selectedZoom)
|
2018-04-07 19:23:10 +00:00
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
mDefaultProperties.mSize = size;
|
|
|
|
mSelectedProperties.mSize = size * selectedZoom;
|
2019-10-08 02:25:39 +00:00
|
|
|
}
|