mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-03-06 14:27:43 +00:00
Implement flexbox and badges.
This commit is contained in:
parent
efe928852f
commit
aaf5d0209b
es-core/src
themes/rbsimple-DE
|
@ -148,13 +148,12 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>> The
|
||||||
{"zIndex", FLOAT}}},
|
{"zIndex", FLOAT}}},
|
||||||
{"badges",
|
{"badges",
|
||||||
{{"pos", NORMALIZED_PAIR},
|
{{"pos", NORMALIZED_PAIR},
|
||||||
{"size", NORMALIZED_PAIR},
|
|
||||||
{"origin", NORMALIZED_PAIR},
|
{"origin", NORMALIZED_PAIR},
|
||||||
{"direction", STRING},
|
{"direction", STRING},
|
||||||
{"wrap", STRING},
|
|
||||||
{"justifyContent", STRING},
|
|
||||||
{"align", STRING},
|
{"align", STRING},
|
||||||
{"margin", NORMALIZED_PAIR},
|
{"itemsPerLine", FLOAT},
|
||||||
|
{"itemMargin", NORMALIZED_PAIR},
|
||||||
|
{"itemWidth", FLOAT},
|
||||||
{"slots", STRING},
|
{"slots", STRING},
|
||||||
{"customBadgeIcon", PATH},
|
{"customBadgeIcon", PATH},
|
||||||
{"visible", BOOLEAN},
|
{"visible", BOOLEAN},
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
#include "resources/TextureResource.h"
|
#include "resources/TextureResource.h"
|
||||||
|
|
||||||
BadgesComponent::BadgesComponent(Window* window)
|
BadgesComponent::BadgesComponent(Window* window)
|
||||||
: FlexboxComponent(window, NUM_SLOTS)
|
: FlexboxComponent(window)
|
||||||
{
|
{
|
||||||
// Define the slots.
|
// Define the slots.
|
||||||
setSlots({SLOT_FAVORITE, SLOT_COMPLETED, SLOT_KIDS, SLOT_BROKEN});
|
mSlots = {SLOT_FAVORITE, SLOT_COMPLETED, SLOT_KIDS, SLOT_BROKEN};
|
||||||
|
|
||||||
mBadgeIcons = std::map<std::string, std::string>();
|
mBadgeIcons = std::map<std::string, std::string>();
|
||||||
mBadgeIcons[SLOT_FAVORITE] = ":/graphics/badge_favorite.png";
|
mBadgeIcons[SLOT_FAVORITE] = ":/graphics/badge_favorite.png";
|
||||||
|
@ -39,21 +39,12 @@ BadgesComponent::BadgesComponent(Window* window)
|
||||||
ImageComponent mImageBroken = ImageComponent(window);
|
ImageComponent mImageBroken = ImageComponent(window);
|
||||||
mImageBroken.setImage(mBadgeIcons[SLOT_BROKEN], false, false);
|
mImageBroken.setImage(mBadgeIcons[SLOT_BROKEN], false, false);
|
||||||
mImageComponents.insert({SLOT_BROKEN, mImageBroken});
|
mImageComponents.insert({SLOT_BROKEN, mImageBroken});
|
||||||
|
|
||||||
// TODO: Should be dependent on the direction property.
|
|
||||||
mSize = glm::vec2{64.0f * NUM_SLOTS, 64.0f};
|
|
||||||
|
|
||||||
// Trigger initial layout computation.
|
|
||||||
onSizeChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BadgesComponent::setValue(const std::string& value)
|
void BadgesComponent::setValue(const std::string& value)
|
||||||
{
|
{
|
||||||
std::vector<std::string> slots = {};
|
mChildren.clear();
|
||||||
|
|
||||||
if (!value.empty()) {
|
if (!value.empty()) {
|
||||||
// Interpret the value and iteratively fill slots. The value is a space separated list of
|
|
||||||
// strings.
|
|
||||||
std::string temp;
|
std::string temp;
|
||||||
std::istringstream ss(value);
|
std::istringstream ss(value);
|
||||||
while (std::getline(ss, temp, ' ')) {
|
while (std::getline(ss, temp, ' ')) {
|
||||||
|
@ -61,19 +52,17 @@ void BadgesComponent::setValue(const std::string& value)
|
||||||
temp == SLOT_BROKEN))
|
temp == SLOT_BROKEN))
|
||||||
LOG(LogError) << "Badge slot '" << temp << "' is invalid.";
|
LOG(LogError) << "Badge slot '" << temp << "' is invalid.";
|
||||||
else
|
else
|
||||||
slots.push_back(temp);
|
mChildren.push_back(&mImageComponents.find(temp)->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setSlots(slots);
|
|
||||||
onSizeChanged();
|
onSizeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string BadgesComponent::getValue() const
|
std::string BadgesComponent::getValue() const
|
||||||
{
|
{
|
||||||
const std::vector<std::string> slots = getSlots();
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
for (auto& slot : slots)
|
for (auto& slot : mSlots)
|
||||||
ss << slot << ' ';
|
ss << slot << ' ';
|
||||||
std::string r = ss.str();
|
std::string r = ss.str();
|
||||||
r.pop_back();
|
r.pop_back();
|
||||||
|
@ -92,8 +81,7 @@ void BadgesComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool imgChanged = false;
|
bool imgChanged = false;
|
||||||
const std::vector<std::string> slots = getSlots();
|
for (auto& slot : mSlots) {
|
||||||
for (auto& slot : slots) {
|
|
||||||
if (properties & PATH && elem->has(slot)) {
|
if (properties & PATH && elem->has(slot)) {
|
||||||
mBadgeIcons[slot] = elem->get<std::string>(slot);
|
mBadgeIcons[slot] = elem->get<std::string>(slot);
|
||||||
mImageComponents.find(slot)->second.setImage(mBadgeIcons[slot]);
|
mImageComponents.find(slot)->second.setImage(mBadgeIcons[slot]);
|
||||||
|
|
|
@ -40,6 +40,7 @@ public:
|
||||||
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::vector<std::string> mSlots;
|
||||||
std::map<std::string, std::string> mBadgeIcons;
|
std::map<std::string, std::string> mBadgeIcons;
|
||||||
std::map<std::string, ImageComponent> mImageComponents;
|
std::map<std::string, ImageComponent> mImageComponents;
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,213 +14,136 @@
|
||||||
#include "ThemeData.h"
|
#include "ThemeData.h"
|
||||||
#include "resources/TextureResource.h"
|
#include "resources/TextureResource.h"
|
||||||
|
|
||||||
FlexboxComponent::FlexboxComponent(Window* window, unsigned int assumeChildren)
|
FlexboxComponent::FlexboxComponent(Window* window)
|
||||||
: GuiComponent(window)
|
: GuiComponent(window)
|
||||||
, mDirection(DEFAULT_DIRECTION)
|
, mDirection(DEFAULT_DIRECTION)
|
||||||
, mWrap(DEFAULT_WRAP)
|
|
||||||
, mJustifyContent(DEFAULT_JUSTIFY_CONTENT)
|
|
||||||
, mAlign(DEFAULT_ALIGN)
|
, mAlign(DEFAULT_ALIGN)
|
||||||
, mAssumeChildren(assumeChildren)
|
, mItemsPerLine(DEFAULT_ITEMS_PER_LINE)
|
||||||
|
, mItemWidth(DEFAULT_ITEM_SIZE_X)
|
||||||
{
|
{
|
||||||
|
// Initialize item margins.
|
||||||
// Initialize contents of the flexbox.
|
mItemMargin = glm::vec2{DEFAULT_MARGIN_X, DEFAULT_MARGIN_Y};
|
||||||
mSlots = std::vector<std::string>();
|
|
||||||
mComponents = std::map<std::string, GuiComponent>();
|
|
||||||
|
|
||||||
// Initialize flexbox layout.
|
|
||||||
mVertices = std::map<std::string, glm::vec4>();
|
|
||||||
|
|
||||||
// TODO: Should be dependent on the direction property.
|
|
||||||
mSize = glm::vec2{64.0f * mAssumeChildren, 64.0f};
|
|
||||||
|
|
||||||
// TODO: Add definition for default value.
|
|
||||||
mMargin = glm::vec2{10.0f, 10.0f};
|
|
||||||
|
|
||||||
// Calculate flexbox layout.
|
// Calculate flexbox layout.
|
||||||
updateVertices();
|
computeLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlexboxComponent::onSizeChanged()
|
// Getters/Setters for rendering options.
|
||||||
|
void FlexboxComponent::setDirection(std::string value)
|
||||||
{
|
{
|
||||||
// TODO: Should be dependent on the direction property.
|
mDirection = value;
|
||||||
if (mSize.y == 0.0f)
|
computeLayout();
|
||||||
mSize.y = mSize.x / mAssumeChildren;
|
|
||||||
else if (mSize.x == 0.0f)
|
|
||||||
mSize.x = mSize.y * mAssumeChildren;
|
|
||||||
|
|
||||||
updateVertices();
|
|
||||||
}
|
}
|
||||||
|
std::string FlexboxComponent::getDirection() { return mDirection; }
|
||||||
void FlexboxComponent::updateVertices()
|
void FlexboxComponent::setAlign(std::string value)
|
||||||
{
|
{
|
||||||
// The maximum number of components to be displayed.
|
mAlign = value;
|
||||||
const float numSlots = mAssumeChildren;
|
computeLayout();
|
||||||
|
}
|
||||||
|
std::string FlexboxComponent::getAlign() { return mAlign; }
|
||||||
|
void FlexboxComponent::setItemsPerLine(unsigned int value)
|
||||||
|
{
|
||||||
|
mItemsPerLine = value;
|
||||||
|
computeLayout();
|
||||||
|
}
|
||||||
|
unsigned int FlexboxComponent::getItemsPerLine() { return mItemsPerLine; }
|
||||||
|
void FlexboxComponent::setItemMargin(glm::vec2 value)
|
||||||
|
{
|
||||||
|
mItemMargin = value;
|
||||||
|
computeLayout();
|
||||||
|
}
|
||||||
|
glm::vec2 FlexboxComponent::getItemMargin() { return mItemMargin; }
|
||||||
|
void FlexboxComponent::setItemWidth(float value)
|
||||||
|
{
|
||||||
|
mItemWidth = value;
|
||||||
|
computeLayout();
|
||||||
|
}
|
||||||
|
float FlexboxComponent::getItemWidth() { return mItemWidth; }
|
||||||
|
|
||||||
// The available size to draw in.
|
void FlexboxComponent::onSizeChanged() { computeLayout(); }
|
||||||
const auto size = getSize();
|
|
||||||
|
|
||||||
// Compute the number of rows and columns and the item max dimensions.
|
void FlexboxComponent::computeLayout()
|
||||||
int rows;
|
{
|
||||||
int columns;
|
// Start placing items in the top-left;
|
||||||
float itemWidth;
|
float anchorX = 0;
|
||||||
float itemHeight;
|
float anchorY = 0;
|
||||||
if (mDirection == DIRECTION_ROW) {
|
float anchorOriginX = 0;
|
||||||
if (mWrap != WRAP_NOWRAP) {
|
float anchorOriginY = 0;
|
||||||
// Suppose we have i rows, what would be the average area of an icon? Compute for a
|
|
||||||
// small number of rows.
|
|
||||||
std::vector<float> areas;
|
|
||||||
for (int i = 1; i < 10; i++) {
|
|
||||||
|
|
||||||
float area = size.x * size.y;
|
// Translation directions when placing items.
|
||||||
|
glm::vec2 directionLine = {1, 0};
|
||||||
|
glm::vec2 directionRow = {0, 1};
|
||||||
|
|
||||||
// Number of vertical gaps.
|
// Change direction.
|
||||||
int verticalGaps = i - 1;
|
if (mDirection == DIRECTION_COLUMN) {
|
||||||
|
directionLine = {0, 1};
|
||||||
// Area of vertical gaps.
|
directionRow = {1, 0};
|
||||||
area -= verticalGaps * mMargin.y * size.x;
|
|
||||||
|
|
||||||
// Height per item.
|
|
||||||
float iHeight = (size.y - verticalGaps * mMargin.y) / i;
|
|
||||||
|
|
||||||
// Width per item. (Approximation)
|
|
||||||
// TODO: this is an approximation!
|
|
||||||
// Solve: area - (iHeight * (iWidth + mMargin.x) * numSlots) + mMargin.x * iHeight =
|
|
||||||
// 0;
|
|
||||||
float iWidth = ((area + mMargin.x * iHeight) / (iHeight * numSlots)) - mMargin.x;
|
|
||||||
|
|
||||||
// Average area available per badge
|
|
||||||
float avgArea = iHeight * iWidth;
|
|
||||||
|
|
||||||
// Push to the areas array.
|
|
||||||
areas.push_back(avgArea);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the number of rows based on what results in the largest area per badge
|
// Set children sizes.
|
||||||
// based on available space.
|
glm::vec2 maxItemSize = {0.0f, 0.0f};
|
||||||
rows = std::max_element(areas.begin(), areas.end()) - areas.begin() + 1;
|
for (auto i : mChildren) {
|
||||||
|
auto oldSize = i->getSize();
|
||||||
|
if (oldSize.x == 0)
|
||||||
|
oldSize.x = DEFAULT_ITEM_SIZE_X;
|
||||||
|
glm::vec2 newSize = {mItemWidth, oldSize.y * (mItemWidth / oldSize.x)};
|
||||||
|
i->setSize(newSize);
|
||||||
|
maxItemSize = {std::max(maxItemSize.x, newSize.x), std::max(maxItemSize.y, newSize.y)};
|
||||||
|
}
|
||||||
|
|
||||||
// Obtain final item dimensions.
|
// Pre-compute layout parameters;
|
||||||
itemHeight = (size.y - (rows - 1) * mMargin.y) / rows;
|
int n = mChildren.size();
|
||||||
itemWidth = areas[rows - 1] / itemHeight;
|
int nLines = std::max(1, (int)std::ceil(n / std::max(1, (int)mItemsPerLine)));
|
||||||
|
float lineWidth =
|
||||||
|
(mDirection == "row" ? (maxItemSize.y + mItemMargin.y) : (maxItemSize.x + mItemMargin.x));
|
||||||
|
float anchorXStart = anchorX;
|
||||||
|
float anchorYStart = anchorY;
|
||||||
|
|
||||||
// Compute number of columns.
|
// Iterate through the children.
|
||||||
if (rows == 1)
|
for (int i = 0; i < n; i++) {
|
||||||
columns = mAssumeChildren;
|
GuiComponent* child = mChildren[i];
|
||||||
else
|
auto size = child->getSize();
|
||||||
columns = std::round((size.x + mMargin.x) / (itemWidth + mMargin.x));
|
|
||||||
|
// Top-left anchor position.
|
||||||
|
float x = anchorX - anchorOriginX * size.x;
|
||||||
|
float y = anchorY - anchorOriginY * size.y;
|
||||||
|
|
||||||
|
// Apply item margin.
|
||||||
|
x += mItemMargin.x * (directionLine.x >= 0.0f ? 1.0f : -1.0f);
|
||||||
|
y += mItemMargin.y * (directionLine.y >= 0.0f ? 1.0f : -1.0f);
|
||||||
|
|
||||||
|
// Apply alignment
|
||||||
|
if (mAlign == ITEM_ALIGN_END) {
|
||||||
|
x += directionLine.x == 0 ? (maxItemSize.x - size.x) : 0;
|
||||||
|
y += directionLine.y == 0 ? (maxItemSize.y - size.y) : 0;
|
||||||
|
}
|
||||||
|
else if (mAlign == ITEM_ALIGN_CENTER) {
|
||||||
|
x += directionLine.x == 0 ? (maxItemSize.x - size.x) / 2 : 0;
|
||||||
|
y += directionLine.y == 0 ? (maxItemSize.y - size.y) / 2 : 0;
|
||||||
|
}
|
||||||
|
else if (mAlign == ITEM_ALIGN_STRETCH && mDirection == "row") {
|
||||||
|
child->setSize(child->getSize().x, maxItemSize.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store final item position.
|
||||||
|
child->setPosition(getPosition().x + x, getPosition().y + y);
|
||||||
|
|
||||||
|
// Translate anchor.
|
||||||
|
if ((i + 1) % std::max(1, (int)mItemsPerLine) != 0) {
|
||||||
|
// Translate on same line.
|
||||||
|
anchorX += (size.x + mItemMargin.x) * directionLine.x;
|
||||||
|
anchorY += (size.y + mItemMargin.y) * directionLine.y;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rows = 1;
|
// Translate to first position of next line.
|
||||||
columns = mAssumeChildren;
|
if (directionRow.x == 0) {
|
||||||
itemHeight = size.y;
|
anchorY += lineWidth * directionRow.y;
|
||||||
itemWidth = size.x / (mAssumeChildren + (mAssumeChildren - 1) * mMargin.x);
|
anchorX = anchorXStart;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO: Add computation for column direction.
|
anchorX += lineWidth * directionRow.x;
|
||||||
|
anchorY = anchorYStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the exact positions and sizes of the components.
|
|
||||||
mVertices.clear();
|
|
||||||
if (mDirection == DIRECTION_ROW) {
|
|
||||||
|
|
||||||
// Start row.
|
|
||||||
int row = mWrap == WRAP_REVERSE ? rows : 1;
|
|
||||||
int item = 0;
|
|
||||||
|
|
||||||
// Iterate through all the rows.
|
|
||||||
for (int c = 0; c < rows && item < mSlots.size(); c++) {
|
|
||||||
|
|
||||||
// Pre-compute dimensions of all items in this row.
|
|
||||||
std::vector<float> widths;
|
|
||||||
std::vector<float> heights;
|
|
||||||
int itemTemp = item;
|
|
||||||
for (int column = 0; column < columns && itemTemp < mSlots.size(); column++) {
|
|
||||||
glm::vec componentSize = mComponents.find(mSlots[itemTemp])->second.getSize();
|
|
||||||
float aspectRatioTexture = componentSize.x / componentSize.y;
|
|
||||||
float aspectRatioItemSpace = itemWidth / itemHeight;
|
|
||||||
if (aspectRatioTexture > aspectRatioItemSpace) {
|
|
||||||
widths.push_back(itemWidth);
|
|
||||||
heights.push_back(itemWidth / aspectRatioTexture);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
widths.push_back(itemHeight * aspectRatioTexture);
|
|
||||||
heights.push_back(itemHeight);
|
|
||||||
}
|
|
||||||
itemTemp++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate through the columns.
|
|
||||||
float xpos = 0;
|
|
||||||
for (int column = 0; column < columns && item < mSlots.size(); column++) {
|
|
||||||
|
|
||||||
// We always go from left to right.
|
|
||||||
// Here we compute the coordinates of the items.
|
|
||||||
|
|
||||||
// Compute final badge x position.
|
|
||||||
float x;
|
|
||||||
float totalWidth =
|
|
||||||
std::accumulate(widths.begin(), widths.end(), decltype(widths)::value_type(0)) +
|
|
||||||
(widths.size() - 1) * mMargin.x;
|
|
||||||
if (mJustifyContent == "start") {
|
|
||||||
x = xpos;
|
|
||||||
xpos += widths[column] + mMargin.x;
|
|
||||||
}
|
|
||||||
else if (mJustifyContent == "end") {
|
|
||||||
if (column == 0)
|
|
||||||
xpos += size.x - totalWidth;
|
|
||||||
x = xpos;
|
|
||||||
xpos += widths[column] + mMargin.x;
|
|
||||||
}
|
|
||||||
else if (mJustifyContent == "center") {
|
|
||||||
if (column == 0)
|
|
||||||
xpos += (size.x - totalWidth) / 2;
|
|
||||||
x = xpos;
|
|
||||||
xpos += widths[column] + mMargin.x;
|
|
||||||
}
|
|
||||||
else if (mJustifyContent == "space-between") {
|
|
||||||
float gapSize = (size.x - totalWidth) / (widths.size() - 1);
|
|
||||||
x = xpos;
|
|
||||||
xpos += widths[column] + gapSize;
|
|
||||||
}
|
|
||||||
else if (mJustifyContent == "space-around") {
|
|
||||||
float gapSize = (size.x - totalWidth) / (widths.size() - 1);
|
|
||||||
xpos += gapSize / 2;
|
|
||||||
x = xpos;
|
|
||||||
xpos += widths[column] + gapSize / 2;
|
|
||||||
}
|
|
||||||
else if (mJustifyContent == "space-evenly") {
|
|
||||||
float gapSize = (size.x - totalWidth) / (widths.size() + 1);
|
|
||||||
xpos += gapSize;
|
|
||||||
x = xpos;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute final badge y position.
|
|
||||||
float y = row * itemHeight;
|
|
||||||
if (mAlign == "end") {
|
|
||||||
y += itemHeight - heights[column];
|
|
||||||
}
|
|
||||||
else if (mAlign == "center") {
|
|
||||||
y += (itemHeight - heights[column]) / 2;
|
|
||||||
}
|
|
||||||
if (mAlign == "stretch") {
|
|
||||||
heights[column] = itemHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(LogError) << "Computed Final Item Position. Row: " << row
|
|
||||||
<< ", Column: " << column << ", Item: " << item << ", pos: (" << x
|
|
||||||
<< ", " << y << "), size: (" << widths[column] << ", "
|
|
||||||
<< heights[column] << ")";
|
|
||||||
|
|
||||||
// Store the item's layout.
|
|
||||||
mVertices[mSlots[item]] = {x, y, widths[column], heights[column]};
|
|
||||||
|
|
||||||
// Increment item;
|
|
||||||
item++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate the row.
|
|
||||||
mWrap == WRAP_REVERSE ? row-- : row++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,17 +153,6 @@ void FlexboxComponent::render(const glm::mat4& parentTrans)
|
||||||
if (!isVisible())
|
if (!isVisible())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Render all the child components.
|
|
||||||
for (unsigned int i = 0; i < mSlots.size(); i++) {
|
|
||||||
glm::vec4 v = mVertices[mSlots[i]];
|
|
||||||
auto c = mComponents.find(mSlots[i])->second;
|
|
||||||
glm::vec2 oldSize = c.getSize();
|
|
||||||
c.setPosition(v.x, v.y);
|
|
||||||
c.setSize(v.z, v.w);
|
|
||||||
c.render(parentTrans);
|
|
||||||
c.setSize(oldSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderChildren(parentTrans);
|
renderChildren(parentTrans);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,6 +163,10 @@ void FlexboxComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
{
|
{
|
||||||
using namespace ThemeFlags;
|
using namespace ThemeFlags;
|
||||||
|
|
||||||
|
glm::vec2 scale{getParent() ? getParent()->getSize() :
|
||||||
|
glm::vec2{static_cast<float>(Renderer::getScreenWidth()),
|
||||||
|
static_cast<float>(Renderer::getScreenHeight())}};
|
||||||
|
|
||||||
// TODO: How to do this without explicit 'badges' property?
|
// TODO: How to do this without explicit 'badges' property?
|
||||||
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "badges");
|
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "badges");
|
||||||
if (!elem)
|
if (!elem)
|
||||||
|
@ -259,15 +175,18 @@ void FlexboxComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
if (properties & DIRECTION && elem->has("direction"))
|
if (properties & DIRECTION && elem->has("direction"))
|
||||||
mDirection = elem->get<std::string>("direction");
|
mDirection = elem->get<std::string>("direction");
|
||||||
|
|
||||||
if (elem->has("wrap"))
|
|
||||||
mWrap = elem->get<std::string>("wrap");
|
|
||||||
|
|
||||||
if (elem->has("justifyContent"))
|
|
||||||
mJustifyContent = elem->get<std::string>("justifyContent");
|
|
||||||
|
|
||||||
if (elem->has("align"))
|
if (elem->has("align"))
|
||||||
mAlign = elem->get<std::string>("align");
|
mAlign = elem->get<std::string>("align");
|
||||||
|
|
||||||
|
if (elem->has("itemsPerLine"))
|
||||||
|
mItemsPerLine = elem->get<float>("itemsPerLine");
|
||||||
|
|
||||||
|
if (elem->has("itemMargin"))
|
||||||
|
mItemMargin = elem->get<glm::vec2>("itemMargin");
|
||||||
|
|
||||||
|
if (elem->has("itemWidth"))
|
||||||
|
mItemWidth = elem->get<float>("itemWidth") * scale.x;
|
||||||
|
|
||||||
GuiComponent::applyTheme(theme, view, element, properties);
|
GuiComponent::applyTheme(theme, view, element, properties);
|
||||||
|
|
||||||
// Trigger layout computation.
|
// Trigger layout computation.
|
||||||
|
|
|
@ -13,73 +13,60 @@
|
||||||
#include "GuiComponent.h"
|
#include "GuiComponent.h"
|
||||||
#include "renderers/Renderer.h"
|
#include "renderers/Renderer.h"
|
||||||
|
|
||||||
|
// Definitions for the option values.
|
||||||
#define DIRECTION_ROW "row"
|
#define DIRECTION_ROW "row"
|
||||||
#define DIRECTION_COLUMN "column"
|
#define DIRECTION_COLUMN "column"
|
||||||
#define WRAP_WRAP "wrap"
|
|
||||||
#define WRAP_NOWRAP "nowrap"
|
|
||||||
#define WRAP_REVERSE "wrap-reverse"
|
|
||||||
#define JUSTIFY_CONTENT_START "start"
|
|
||||||
#define JUSTIFY_CONTENT_END "end"
|
|
||||||
#define JUSTIFY_CONTENT_CENTER "center"
|
|
||||||
#define JUSTIFY_CONTENT_SPACE_BETWEEN "space-between"
|
|
||||||
#define JUSTIFY_CONTENT_SPACE_AROUND "space-around"
|
|
||||||
#define JUSTIFY_CONTENT_SPACE_EVENLY "space-evenly"
|
|
||||||
#define ITEM_ALIGN_START "start"
|
#define ITEM_ALIGN_START "start"
|
||||||
#define ITEM_ALIGN_END "end"
|
#define ITEM_ALIGN_END "end"
|
||||||
#define ITEM_ALIGN_CENTER "center"
|
#define ITEM_ALIGN_CENTER "center"
|
||||||
#define ITEM_ALIGN_STRETCH "stretch"
|
#define ITEM_ALIGN_STRETCH "stretch"
|
||||||
|
|
||||||
|
// Default values.
|
||||||
#define DEFAULT_DIRECTION DIRECTION_ROW
|
#define DEFAULT_DIRECTION DIRECTION_ROW
|
||||||
#define DEFAULT_WRAP WRAP_WRAP
|
|
||||||
#define DEFAULT_JUSTIFY_CONTENT JUSTIFY_CONTENT_START
|
|
||||||
#define DEFAULT_ALIGN ITEM_ALIGN_CENTER
|
#define DEFAULT_ALIGN ITEM_ALIGN_CENTER
|
||||||
#define DEFAULT_MARGIN_X = 10.0f
|
#define DEFAULT_ITEMS_PER_LINE 4
|
||||||
#define DEFAULT_MARGIN_Y = 10.0f
|
#define DEFAULT_MARGIN_X 10.0f
|
||||||
|
#define DEFAULT_MARGIN_Y 10.0f
|
||||||
|
#define DEFAULT_ITEM_SIZE_X 64.0f
|
||||||
|
#define DEFAULT_ITEM_SIZE_Y 64.0f
|
||||||
|
|
||||||
class TextureResource;
|
class TextureResource;
|
||||||
|
|
||||||
class FlexboxComponent : public GuiComponent
|
class FlexboxComponent : public GuiComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FlexboxComponent(Window* window, unsigned int assumeChildren = 0);
|
FlexboxComponent(Window* window);
|
||||||
|
|
||||||
void render(const glm::mat4& parentTrans) override;
|
// Getters/Setters for rendering options.
|
||||||
|
void setDirection(std::string value);
|
||||||
|
std::string getDirection();
|
||||||
|
void setAlign(std::string value);
|
||||||
|
std::string getAlign();
|
||||||
|
void setItemsPerLine(unsigned int value);
|
||||||
|
unsigned int getItemsPerLine();
|
||||||
|
void setItemMargin(glm::vec2 value);
|
||||||
|
glm::vec2 getItemMargin();
|
||||||
|
void setItemWidth(float value);
|
||||||
|
float getItemWidth();
|
||||||
|
|
||||||
void onSizeChanged() override;
|
void onSizeChanged() override;
|
||||||
|
void render(const glm::mat4& parentTrans) override;
|
||||||
void setDirection(int direction);
|
|
||||||
|
|
||||||
int getDirection();
|
|
||||||
|
|
||||||
void setSlots(std::vector<std::string>);
|
|
||||||
|
|
||||||
std::vector<std::string> getSlots() const;
|
|
||||||
|
|
||||||
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme,
|
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
const std::string& view,
|
const std::string& view,
|
||||||
const std::string& element,
|
const std::string& element,
|
||||||
unsigned int properties) override;
|
unsigned int properties) override;
|
||||||
|
|
||||||
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Calculate flexbox layout.
|
// Calculate flexbox layout.
|
||||||
void updateVertices();
|
void computeLayout();
|
||||||
|
|
||||||
// Storage for the flexbox components positions and sizes.
|
|
||||||
std::map<std::string, glm::vec4> mVertices;
|
|
||||||
|
|
||||||
// The components of the flexbox.
|
|
||||||
std::map<std::string, GuiComponent> mComponents;
|
|
||||||
|
|
||||||
// Named map of the components of the flexbox.
|
|
||||||
std::vector<std::string> mSlots;
|
|
||||||
|
|
||||||
|
// Rendering options.
|
||||||
std::string mDirection;
|
std::string mDirection;
|
||||||
std::string mWrap;
|
|
||||||
std::string mJustifyContent;
|
|
||||||
std::string mAlign;
|
std::string mAlign;
|
||||||
glm::vec2 mMargin;
|
unsigned int mItemsPerLine;
|
||||||
unsigned int mAssumeChildren;
|
glm::vec2 mItemMargin;
|
||||||
|
float mItemWidth;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ES_APP_COMPONENTS_FLEXBOX_COMPONENT_H
|
#endif // ES_APP_COMPONENTS_FLEXBOX_COMPONENT_H
|
||||||
|
|
|
@ -237,15 +237,17 @@ based on: 'recalbox-multi' by the Recalbox community
|
||||||
<alignment>right</alignment>
|
<alignment>right</alignment>
|
||||||
</text>
|
</text>
|
||||||
<badges name="md_badges">
|
<badges name="md_badges">
|
||||||
<pos>0.873 0.212</pos>
|
<pos>0.8125 0.65</pos>
|
||||||
<size>0.1 0.3</size>
|
|
||||||
<origin>0 0</origin>
|
<origin>0 0</origin>
|
||||||
|
|
||||||
|
<!-- flexbox properties -->
|
||||||
<direction>row</direction>
|
<direction>row</direction>
|
||||||
<wrap>wrap</wrap> <!-- wrap | nowrap | wrap-reverse -->
|
<align>start</align>
|
||||||
<justifyContent>start
|
<itemsPerLine>2</itemsPerLine>
|
||||||
</justifyContent> <!-- start | end | center | space-between | space-around | space-evenly -->
|
<itemMargin>10 5</itemMargin>
|
||||||
<align>start</align> <!-- start | end | center | stretch -->
|
<itemWidth>.05</itemWidth>
|
||||||
<margin>20 10</margin>
|
|
||||||
|
<!-- badges properties -->
|
||||||
<slots>favorite completed kidgame broken</slots>
|
<slots>favorite completed kidgame broken</slots>
|
||||||
<customBadgeIcon badge="favorite">:/graphics/badge_favorite.png</customBadgeIcon>
|
<customBadgeIcon badge="favorite">:/graphics/badge_favorite.png</customBadgeIcon>
|
||||||
<customBadgeIcon badge="completed">:/graphics/badge_completed.png</customBadgeIcon>
|
<customBadgeIcon badge="completed">:/graphics/badge_completed.png</customBadgeIcon>
|
||||||
|
|
Loading…
Reference in a new issue