Added a scaleInwards property to the grid element to contain scaling within the element boundaries

This commit is contained in:
Leon Styhre 2023-04-12 23:06:13 +02:00
parent 6cfa888b4d
commit 88df22cb61
2 changed files with 104 additions and 48 deletions

View file

@ -209,6 +209,7 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"itemSize", NORMALIZED_PAIR}, {"itemSize", NORMALIZED_PAIR},
{"itemScale", FLOAT}, {"itemScale", FLOAT},
{"itemSpacing", NORMALIZED_PAIR}, {"itemSpacing", NORMALIZED_PAIR},
{"scaleInwards", BOOLEAN},
{"fractionalRows", BOOLEAN}, {"fractionalRows", BOOLEAN},
{"itemTransitions", STRING}, {"itemTransitions", STRING},
{"rowTransitions", STRING}, {"rowTransitions", STRING},

View file

@ -151,6 +151,7 @@ private:
glm::vec2 mItemSize; glm::vec2 mItemSize;
float mItemScale; float mItemScale;
glm::vec2 mItemSpacing; glm::vec2 mItemSpacing;
bool mScaleInwards;
bool mFractionalRows; bool mFractionalRows;
bool mInstantItemTransitions; bool mInstantItemTransitions;
bool mInstantRowTransitions; bool mInstantRowTransitions;
@ -222,6 +223,7 @@ GridComponent<T>::GridComponent()
mRenderer->getScreenHeight() * 0.25f}} mRenderer->getScreenHeight() * 0.25f}}
, mItemScale {1.05f} , mItemScale {1.05f}
, mItemSpacing {0.0f, 0.0f} , mItemSpacing {0.0f, 0.0f}
, mScaleInwards {false}
, mFractionalRows {false} , mFractionalRows {false}
, mInstantItemTransitions {false} , mInstantItemTransitions {false}
, mInstantRowTransitions {false} , mInstantRowTransitions {false}
@ -500,8 +502,10 @@ template <typename T> void GridComponent<T>::calculateLayout()
mVerticalMargin = 0.0f; mVerticalMargin = 0.0f;
} }
else { else {
mHorizontalMargin = ((mItemSize.x * mItemScale) - mItemSize.x) / 2.0f; mHorizontalMargin =
mVerticalMargin = ((mItemSize.y * mItemScale) - mItemSize.y) / 2.0f; ((mItemSize.x * (mScaleInwards ? 1.0f : mItemScale)) - mItemSize.x) / 2.0f;
mVerticalMargin =
((mItemSize.y * (mScaleInwards ? 1.0f : mItemScale)) - mItemSize.y) / 2.0f;
} }
int columnCount {0}; int columnCount {0};
@ -702,43 +706,54 @@ template <typename T> void GridComponent<T>::render(const glm::mat4& parentTrans
trans[3].y -= (mItemSize.y + mItemSpacing.y) * mScrollPos; trans[3].y -= (mItemSize.y + mItemSpacing.y) * mScrollPos;
auto selectorRenderFunc = [this, &trans](std::vector<size_t>::const_iterator it, auto calculateOffsetPos = [this](const glm::vec3& itemPos, const glm::vec2& origin,
const float scale, const float opacity, const float scale,
const bool cursorEntry, const bool lastCursorEntry) { const float relativeScale) -> const glm::vec2 {
const float sizeX {mItemSize.x * scale * relativeScale};
const float sizeY {mItemSize.y * scale * relativeScale};
glm::vec2 position {0.0f, 0.0f};
position.x = itemPos.x - (mItemSize.x / 2.0f);
position.x -= ((mItemSize.x * scale) - mItemSize.x) * origin.x;
position.x += ((mItemSize.x * scale) - sizeX) / 2.0f;
position.y = itemPos.y - (mItemSize.y / 2.0f);
position.y -= ((mItemSize.y * scale) - mItemSize.y) * origin.y;
position.y += ((mItemSize.y * scale) - sizeY) / 2.0f;
return position;
};
auto selectorRenderFunc = [this, &trans, calculateOffsetPos](
std::vector<size_t>::const_iterator it, const glm::vec3& itemPos,
const float scale, glm::vec2 origin, glm::vec2 offset,
const float opacity) {
if (mSelectorImage == nullptr && !mHasSelectorColor)
return;
const glm::vec2 position {
calculateOffsetPos(itemPos, origin, scale, mSelectorRelativeScale)};
if (mSelectorImage != nullptr) { if (mSelectorImage != nullptr) {
mSelectorImage->setPosition(mEntries.at(*it).data.item->getPosition()); mSelectorImage->setOrigin(0.0f, 0.0f);
mSelectorImage->setPosition(position.x, position.y);
mSelectorImage->setScale(scale); mSelectorImage->setScale(scale);
mSelectorImage->setOpacity(opacity); mSelectorImage->setOpacity(opacity);
mSelectorImage->render(trans); mSelectorImage->render(trans);
} }
else if (mHasSelectorColor) { else if (mHasSelectorColor) {
// If a selector color is set but no selector image, then render a rectangle. // If a selector color is set but no selector image, then render a rectangle.
const float sizeX {mItemSize.x * (cursorEntry || lastCursorEntry ? scale : 1.0f) * const float sizeX {mItemSize.x * scale * mSelectorRelativeScale};
mSelectorRelativeScale}; const float sizeY {mItemSize.y * scale * mSelectorRelativeScale};
const float sizeY {mItemSize.y * (cursorEntry || lastCursorEntry ? scale : 1.0f) *
mSelectorRelativeScale};
float posX {mEntries.at(*it).data.item->getPosition().x - mItemSize.x * 0.5f};
float posY {mEntries.at(*it).data.item->getPosition().y - mItemSize.y * 0.5f};
if (cursorEntry || lastCursorEntry) {
posX -= ((mItemSize.x * scale * mSelectorRelativeScale) - mItemSize.x) / 2.0f;
posY -= ((mItemSize.y * scale * mSelectorRelativeScale) - mItemSize.y) / 2.0f;
}
else {
posX -= ((mItemSize.x * mSelectorRelativeScale) - mItemSize.x) / 2.0f;
posY -= ((mItemSize.y * mSelectorRelativeScale) - mItemSize.y) / 2.0f;
}
mRenderer->setMatrix(trans); mRenderer->setMatrix(trans);
mRenderer->drawRect(posX, posY, sizeX, sizeY, mSelectorColor, mSelectorColorEnd, mRenderer->drawRect(position.x, position.y, sizeX, sizeY, mSelectorColor,
mSelectorColorGradientHorizontal, opacity); mSelectorColorEnd, mSelectorColorGradientHorizontal, opacity);
} }
}; };
for (auto it = renderEntries.cbegin(); it != renderEntries.cend(); ++it) { for (auto it = renderEntries.cbegin(); it != renderEntries.cend(); ++it) {
float metadataOpacity {1.0f}; float metadataOpacity {1.0f};
bool cursorEntry {false}; bool cursorEntry {false};
bool lastCursorEntry {false};
if constexpr (std::is_same_v<T, FileData*>) { if constexpr (std::is_same_v<T, FileData*>) {
// If a game is marked as hidden, lower the opacity a lot. // If a game is marked as hidden, lower the opacity a lot.
@ -765,7 +780,6 @@ template <typename T> void GridComponent<T>::render(const glm::mat4& parentTrans
dimming = glm::mix(mUnfocusedItemDimming, 1.0f, mTransitionFactor); dimming = glm::mix(mUnfocusedItemDimming, 1.0f, mTransitionFactor);
} }
else if (*it == static_cast<size_t>(mLastCursor)) { else if (*it == static_cast<size_t>(mLastCursor)) {
lastCursorEntry = true;
scale = glm::mix(mItemScale, 1.0f, mTransitionFactor); scale = glm::mix(mItemScale, 1.0f, mTransitionFactor);
opacity = glm::mix(1.0f * metadataOpacity, mUnfocusedItemOpacity * metadataOpacity, opacity = glm::mix(1.0f * metadataOpacity, mUnfocusedItemOpacity * metadataOpacity,
mTransitionFactor); mTransitionFactor);
@ -775,11 +789,56 @@ template <typename T> void GridComponent<T>::render(const glm::mat4& parentTrans
dimming = glm::mix(1.0f, mUnfocusedItemDimming, mTransitionFactor); dimming = glm::mix(1.0f, mUnfocusedItemDimming, mTransitionFactor);
} }
const glm::vec3 itemPos {mEntries.at(*it).data.item->getPosition()};
glm::vec2 originInwards {0.5f, 0.5f};
glm::vec2 offsetInwards {0.0f, 0.0f};
if (mScaleInwards && scale != 1.0f) {
if (static_cast<int>(*it) < mColumns) {
// First row.
originInwards.y = 0.0f;
offsetInwards.y = mItemSize.y / 2.0f;
}
if ((itemPos.y + (mItemSize.y / 2.0f) * mItemScale) > mSize.y) {
// Scaled image won't fit vertically at the bottom.
originInwards.y = 1.0f;
offsetInwards.y = -(mItemSize.y / 2.0f);
}
if (static_cast<int>(*it) % mColumns == 0) {
// Leftmost column.
originInwards.x = 0.0f;
offsetInwards.x = mItemSize.x / 2.0f;
}
if (static_cast<int>(*it) % mColumns == mColumns - 1) {
// Rightmost column.
originInwards.x = 1.0f;
offsetInwards.x = -(mItemSize.x / 2.0f);
}
const glm::vec2 position {
calculateOffsetPos(itemPos, originInwards, scale,
(mEntries.at(*it).data.imagePath.empty() &&
mEntries.at(*it).data.defaultImagePath.empty() ?
mTextRelativeScale :
mImageRelativeScale))};
mEntries.at(*it).data.item->setOrigin(0.0f, 0.0f);
mEntries.at(*it).data.item->setPosition(position.x, position.y);
}
if (cursorEntry && mSelectorLayer == SelectorLayer::BOTTOM) if (cursorEntry && mSelectorLayer == SelectorLayer::BOTTOM)
selectorRenderFunc(it, scale, opacity, cursorEntry, lastCursorEntry); selectorRenderFunc(it, itemPos, scale, originInwards, offsetInwards, opacity);
glm::vec2 backgroundPos {
calculateOffsetPos(itemPos, originInwards, scale, mBackgroundRelativeScale)};
if (mBackgroundImage != nullptr) { if (mBackgroundImage != nullptr) {
mBackgroundImage->setPosition(mEntries.at(*it).data.item->getPosition()); if (mScaleInwards && scale != 1.0f) {
mBackgroundImage->setOrigin(0.0f, 0.0f);
mBackgroundImage->setPosition(backgroundPos.x, backgroundPos.y);
}
else {
mBackgroundImage->setPosition(mEntries.at(*it).data.item->getPosition());
}
mBackgroundImage->setScale(scale); mBackgroundImage->setScale(scale);
mBackgroundImage->setOpacity(opacity); mBackgroundImage->setOpacity(opacity);
if (mHasUnfocusedItemSaturation) if (mHasUnfocusedItemSaturation)
@ -787,32 +846,20 @@ template <typename T> void GridComponent<T>::render(const glm::mat4& parentTrans
if (mUnfocusedItemDimming != 1.0f) if (mUnfocusedItemDimming != 1.0f)
mBackgroundImage->setDimming(dimming); mBackgroundImage->setDimming(dimming);
mBackgroundImage->render(trans); mBackgroundImage->render(trans);
if (mScaleInwards && scale != 1.0f)
mBackgroundImage->setOrigin(0.5f, 0.5f);
} }
else if (mHasBackgroundColor) { else if (mHasBackgroundColor) {
// If a background color is set but no background image, then render a rectangle. // If a background color is set but no background image, then render a rectangle.
const float sizeX {mItemSize.x * (cursorEntry || lastCursorEntry ? scale : 1.0f) * const float sizeX {mItemSize.x * scale * mBackgroundRelativeScale};
mBackgroundRelativeScale}; const float sizeY {mItemSize.y * scale * mBackgroundRelativeScale};
const float sizeY {mItemSize.y * (cursorEntry || lastCursorEntry ? scale : 1.0f) *
mBackgroundRelativeScale};
float posX {mEntries.at(*it).data.item->getPosition().x - mItemSize.x * 0.5f};
float posY {mEntries.at(*it).data.item->getPosition().y - mItemSize.y * 0.5f};
if (cursorEntry || lastCursorEntry) {
posX -= ((mItemSize.x * scale * mBackgroundRelativeScale) - mItemSize.x) / 2.0f;
posY -= ((mItemSize.y * scale * mBackgroundRelativeScale) - mItemSize.y) / 2.0f;
}
else {
posX -= ((mItemSize.x * mBackgroundRelativeScale) - mItemSize.x) / 2.0f;
posY -= ((mItemSize.y * mBackgroundRelativeScale) - mItemSize.y) / 2.0f;
}
mRenderer->setMatrix(trans); mRenderer->setMatrix(trans);
mRenderer->drawRect(posX, posY, sizeX, sizeY, mBackgroundColor, mBackgroundColorEnd, mRenderer->drawRect(backgroundPos.x, backgroundPos.y, sizeX, sizeY, mBackgroundColor,
mBackgroundColorGradientHorizontal, opacity); mBackgroundColorEnd, mBackgroundColorGradientHorizontal, opacity);
} }
if (cursorEntry && mSelectorLayer == SelectorLayer::MIDDLE) if (cursorEntry && mSelectorLayer == SelectorLayer::MIDDLE)
selectorRenderFunc(it, scale, opacity, cursorEntry, lastCursorEntry); selectorRenderFunc(it, itemPos, scale, originInwards, offsetInwards, opacity);
mEntries.at(*it).data.item->setScale(scale); mEntries.at(*it).data.item->setScale(scale);
mEntries.at(*it).data.item->setOpacity(opacity); mEntries.at(*it).data.item->setOpacity(opacity);
@ -857,7 +904,12 @@ template <typename T> void GridComponent<T>::render(const glm::mat4& parentTrans
mEntries.at(*it).data.item->setOpacity(1.0f); mEntries.at(*it).data.item->setOpacity(1.0f);
if (cursorEntry && mSelectorLayer == SelectorLayer::TOP) if (cursorEntry && mSelectorLayer == SelectorLayer::TOP)
selectorRenderFunc(it, scale, opacity, cursorEntry, lastCursorEntry); selectorRenderFunc(it, itemPos, scale, originInwards, offsetInwards, opacity);
if (mScaleInwards && scale != 1.0f) {
mEntries.at(*it).data.item->setOrigin(0.5f, 0.5f);
mEntries.at(*it).data.item->setPosition(itemPos);
}
} }
mRenderer->popClipRect(); mRenderer->popClipRect();
@ -959,6 +1011,9 @@ void GridComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
if (elem->has("imageRelativeScale")) if (elem->has("imageRelativeScale"))
mImageRelativeScale = glm::clamp(elem->get<float>("imageRelativeScale"), 0.2f, 1.0f); mImageRelativeScale = glm::clamp(elem->get<float>("imageRelativeScale"), 0.2f, 1.0f);
mScaleInwards =
(mItemScale > 1.0f && elem->has("scaleInwards") && elem->get<bool>("scaleInwards"));
if (elem->has("imageFit")) { if (elem->has("imageFit")) {
const std::string& imageFit {elem->get<std::string>("imageFit")}; const std::string& imageFit {elem->get<std::string>("imageFit")};
if (imageFit == "contain") { if (imageFit == "contain") {