2020-09-21 17:17:34 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2020-06-06 14:48:05 +00:00
|
|
|
//
|
2020-09-21 17:17:34 +00:00
|
|
|
// EmulationStation Desktop Edition
|
2020-06-21 12:25:28 +00:00
|
|
|
// MenuComponent.cpp
|
2020-06-06 14:48:05 +00:00
|
|
|
//
|
2020-06-21 12:25:28 +00:00
|
|
|
// Basic component for building a menu.
|
2020-06-06 14:48:05 +00:00
|
|
|
//
|
|
|
|
|
2014-06-20 01:30:09 +00:00
|
|
|
#include "components/MenuComponent.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
|
2020-06-06 11:10:33 +00:00
|
|
|
#include "Settings.h"
|
2021-07-07 18:31:46 +00:00
|
|
|
#include "components/ButtonComponent.h"
|
2014-03-12 03:00:08 +00:00
|
|
|
|
2022-10-24 22:43:27 +00:00
|
|
|
#define BUTTON_GRID_VERT_PADDING Font::get(FONT_SIZE_MEDIUM)->getLetterHeight() * 0.915f
|
|
|
|
#define BUTTON_GRID_HORIZ_PADDING Font::get(FONT_SIZE_MEDIUM)->getLetterHeight() * 0.283f
|
2014-03-12 23:24:34 +00:00
|
|
|
|
2023-02-07 17:51:04 +00:00
|
|
|
#define TITLE_HEIGHT \
|
|
|
|
(mTitle->getFont()->getLetterHeight() + (Renderer::getIsVerticalOrientation() ? \
|
|
|
|
Renderer::getScreenWidth() * 0.0637f : \
|
|
|
|
Renderer::getScreenHeight() * 0.0637f))
|
2014-04-19 19:15:44 +00:00
|
|
|
|
2022-01-19 17:01:54 +00:00
|
|
|
MenuComponent::MenuComponent(std::string title, const std::shared_ptr<Font>& titleFont)
|
2023-02-07 17:51:04 +00:00
|
|
|
: mRenderer {Renderer::getInstance()}
|
|
|
|
, mGrid {glm::ivec2 {2, 4}}
|
2022-01-16 17:18:28 +00:00
|
|
|
, mNeedsSaving {false}
|
2017-08-30 00:47:04 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
addChild(&mBackground);
|
|
|
|
addChild(&mGrid);
|
2014-03-12 03:00:08 +00:00
|
|
|
|
2021-01-14 21:56:49 +00:00
|
|
|
mBackground.setImagePath(":/graphics/frame.svg");
|
2014-03-01 21:02:44 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Set up title.
|
2022-01-19 17:01:54 +00:00
|
|
|
mTitle = std::make_shared<TextComponent>();
|
2020-06-21 12:25:28 +00:00
|
|
|
mTitle->setHorizontalAlignment(ALIGN_CENTER);
|
2023-05-07 20:56:24 +00:00
|
|
|
mTitle->setColor(mMenuColorTitle);
|
2020-06-21 12:25:28 +00:00
|
|
|
setTitle(title, titleFont);
|
2022-01-16 11:09:55 +00:00
|
|
|
mGrid.setEntry(mTitle, glm::ivec2 {0, 0}, false, true, glm::ivec2 {2, 2});
|
2014-03-01 21:02:44 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Set up list which will never change (externally, anyway).
|
2022-01-19 17:01:54 +00:00
|
|
|
mList = std::make_shared<ComponentList>();
|
2022-01-16 11:09:55 +00:00
|
|
|
mGrid.setEntry(mList, glm::ivec2 {0, 2}, true, true, glm::ivec2 {2, 1});
|
2021-10-10 16:15:37 +00:00
|
|
|
|
|
|
|
// Set up scroll indicators.
|
2022-01-19 17:01:54 +00:00
|
|
|
mScrollUp = std::make_shared<ImageComponent>();
|
|
|
|
mScrollDown = std::make_shared<ImageComponent>();
|
2021-10-10 16:15:37 +00:00
|
|
|
|
|
|
|
mScrollUp->setResize(0.0f, mTitle->getFont()->getLetterHeight() / 2.0f);
|
|
|
|
mScrollUp->setOrigin(0.0f, -0.35f);
|
|
|
|
|
|
|
|
mScrollDown->setResize(0.0f, mTitle->getFont()->getLetterHeight() / 2.0f);
|
|
|
|
mScrollDown->setOrigin(0.0f, 0.35f);
|
|
|
|
|
2023-02-15 22:58:50 +00:00
|
|
|
mScrollIndicator = std::make_shared<ScrollIndicatorComponent>(mList, mScrollUp, mScrollDown);
|
|
|
|
|
2022-01-16 11:09:55 +00:00
|
|
|
mGrid.setEntry(mScrollUp, glm::ivec2 {1, 0}, false, false, glm::ivec2 {1, 1});
|
|
|
|
mGrid.setEntry(mScrollDown, glm::ivec2 {1, 1}, false, false, glm::ivec2 {1, 1});
|
2014-03-01 21:02:44 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
updateGrid();
|
|
|
|
updateSize();
|
2014-03-12 23:24:34 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
mGrid.resetCursor();
|
2014-03-01 21:02:44 +00:00
|
|
|
}
|
|
|
|
|
2020-06-06 11:10:33 +00:00
|
|
|
MenuComponent::~MenuComponent()
|
|
|
|
{
|
2021-07-07 18:31:46 +00:00
|
|
|
// Save when destroyed.
|
2020-06-21 12:25:28 +00:00
|
|
|
save();
|
2020-06-06 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MenuComponent::save()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!mSaveFuncs.size())
|
|
|
|
return;
|
2020-06-06 11:10:33 +00:00
|
|
|
|
2021-11-17 16:48:49 +00:00
|
|
|
for (auto it = mSaveFuncs.cbegin(); it != mSaveFuncs.cend(); ++it)
|
2020-06-21 12:25:28 +00:00
|
|
|
(*it)();
|
2020-06-06 11:10:33 +00:00
|
|
|
|
2020-11-05 17:18:11 +00:00
|
|
|
if (mNeedsSaving) {
|
|
|
|
Settings::getInstance()->saveFile();
|
|
|
|
mNeedsSaving = false;
|
|
|
|
}
|
2020-06-06 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
2020-11-06 19:27:41 +00:00
|
|
|
void MenuComponent::setTitle(std::string title, const std::shared_ptr<Font>& font)
|
2014-04-19 19:15:44 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
mTitle->setText(Utils::String::toUpper(title));
|
|
|
|
mTitle->setFont(font);
|
2014-04-19 19:15:44 +00:00
|
|
|
}
|
|
|
|
|
2014-03-21 16:54:48 +00:00
|
|
|
float MenuComponent::getButtonGridHeight() const
|
|
|
|
{
|
2021-08-16 16:25:01 +00:00
|
|
|
return (mButtonGrid ? mButtonGrid->getSize().y :
|
2022-10-24 22:43:27 +00:00
|
|
|
Font::get(FONT_SIZE_MEDIUM)->getSize() * 1.5f + BUTTON_GRID_VERT_PADDING);
|
2014-03-21 16:54:48 +00:00
|
|
|
}
|
|
|
|
|
2014-03-12 23:24:34 +00:00
|
|
|
void MenuComponent::updateSize()
|
|
|
|
{
|
2023-02-07 17:51:04 +00:00
|
|
|
const float maxHeight {mRenderer->getScreenHeight() *
|
|
|
|
(mRenderer->getIsVerticalOrientation() ? 0.70f : 0.80f)};
|
2022-09-02 18:52:49 +00:00
|
|
|
float height {TITLE_HEIGHT + mList->getTotalRowHeight() + getButtonGridHeight() +
|
2023-02-07 17:51:04 +00:00
|
|
|
(2.0f * mRenderer->getScreenResolutionModifier())};
|
2020-06-21 12:25:28 +00:00
|
|
|
if (height > maxHeight) {
|
|
|
|
height = TITLE_HEIGHT + getButtonGridHeight();
|
2022-09-02 18:52:49 +00:00
|
|
|
int i {0};
|
2020-06-21 12:25:28 +00:00
|
|
|
while (i < mList->size()) {
|
2021-01-29 16:59:05 +00:00
|
|
|
// Add the separator height to the row height so that it also gets properly rendered.
|
2023-02-07 17:51:04 +00:00
|
|
|
float rowHeight {mList->getRowHeight(i) + mRenderer->getScreenResolutionModifier()};
|
2020-06-21 12:25:28 +00:00
|
|
|
if (height + rowHeight < maxHeight)
|
|
|
|
height += rowHeight;
|
|
|
|
else
|
|
|
|
break;
|
2021-11-17 16:48:49 +00:00
|
|
|
++i;
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-10 16:29:48 +00:00
|
|
|
float width {std::min(mRenderer->getScreenHeight() * 1.05f,
|
|
|
|
mRenderer->getScreenWidth() *
|
|
|
|
(mRenderer->getIsVerticalOrientation() ? 0.94f : 0.90f))};
|
2020-06-21 12:25:28 +00:00
|
|
|
setSize(width, height);
|
2014-03-12 23:24:34 +00:00
|
|
|
}
|
|
|
|
|
2014-03-01 21:02:44 +00:00
|
|
|
void MenuComponent::onSizeChanged()
|
|
|
|
{
|
2023-04-30 14:49:51 +00:00
|
|
|
mBackground.fitTo(mSize);
|
2014-03-04 22:48:33 +00:00
|
|
|
|
2021-05-23 08:40:11 +00:00
|
|
|
// Update grid row/column sizes.
|
2021-10-10 16:15:37 +00:00
|
|
|
mGrid.setRowHeightPerc(0, TITLE_HEIGHT / mSize.y / 2.0f);
|
|
|
|
mGrid.setRowHeightPerc(1, TITLE_HEIGHT / mSize.y / 2.0f);
|
|
|
|
mGrid.setRowHeightPerc(3, getButtonGridHeight() / mSize.y);
|
|
|
|
|
2021-10-14 20:38:30 +00:00
|
|
|
mGrid.setColWidthPerc(1, 0.055f);
|
2017-08-30 00:47:04 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
mGrid.setSize(mSize);
|
2022-06-03 16:27:46 +00:00
|
|
|
|
|
|
|
// Limit the title size to reserve space for the scroll indicators.
|
|
|
|
float indicatorsSize {mSize.x * 0.09f};
|
|
|
|
|
|
|
|
glm::vec2 titleSize {mTitle->getSize()};
|
|
|
|
mTitle->setSize(titleSize.x - indicatorsSize, titleSize.y);
|
|
|
|
|
|
|
|
glm::vec3 titlePos {mTitle->getPosition()};
|
2022-10-25 18:39:12 +00:00
|
|
|
mTitle->setPosition(titlePos.x + indicatorsSize / 2.0f, titlePos.y, titlePos.z);
|
2014-03-12 03:00:08 +00:00
|
|
|
}
|
|
|
|
|
2020-06-06 14:48:05 +00:00
|
|
|
void MenuComponent::addButton(const std::string& name,
|
2021-07-07 18:31:46 +00:00
|
|
|
const std::string& helpText,
|
|
|
|
const std::function<void()>& callback)
|
2014-03-12 03:00:08 +00:00
|
|
|
{
|
2022-01-19 17:01:54 +00:00
|
|
|
mButtons.push_back(
|
|
|
|
std::make_shared<ButtonComponent>(Utils::String::toUpper(name), helpText, callback));
|
2020-06-21 12:25:28 +00:00
|
|
|
updateGrid();
|
|
|
|
updateSize();
|
2014-03-12 03:00:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MenuComponent::updateGrid()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (mButtonGrid)
|
|
|
|
mGrid.removeEntry(mButtonGrid);
|
2014-03-01 21:02:44 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
mButtonGrid.reset();
|
2014-03-18 21:05:56 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (mButtons.size()) {
|
2022-01-19 17:01:54 +00:00
|
|
|
mButtonGrid = makeButtonGrid(mButtons);
|
2022-01-16 11:09:55 +00:00
|
|
|
mGrid.setEntry(mButtonGrid, glm::ivec2 {0, 3}, true, false, glm::ivec2 {2, 1});
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
2014-03-01 21:02:44 +00:00
|
|
|
}
|
2014-03-13 19:09:50 +00:00
|
|
|
|
2023-05-07 20:56:24 +00:00
|
|
|
std::shared_ptr<ComponentGrid> MenuComponent::makeButtonGrid(
|
2022-01-19 17:01:54 +00:00
|
|
|
const std::vector<std::shared_ptr<ButtonComponent>>& buttons)
|
2014-03-15 17:18:50 +00:00
|
|
|
{
|
2022-09-02 18:52:49 +00:00
|
|
|
std::shared_ptr<ComponentGrid> buttonGrid {
|
|
|
|
std::make_shared<ComponentGrid>(glm::ivec2 {static_cast<int>(buttons.size()), 2})};
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2021-01-13 18:45:56 +00:00
|
|
|
// Initialize to padding.
|
2022-09-02 18:52:49 +00:00
|
|
|
float buttonGridWidth {BUTTON_GRID_HORIZ_PADDING * buttons.size()};
|
2021-11-11 18:51:42 +00:00
|
|
|
|
2021-11-17 16:48:49 +00:00
|
|
|
for (int i = 0; i < static_cast<int>(buttons.size()); ++i) {
|
2022-01-16 11:09:55 +00:00
|
|
|
buttonGrid->setEntry(buttons.at(i), glm::ivec2 {i, 0}, true, false);
|
2021-08-16 16:25:01 +00:00
|
|
|
buttonGridWidth += buttons.at(i)->getSize().x;
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
2021-11-17 16:48:49 +00:00
|
|
|
for (unsigned int i = 0; i < buttons.size(); ++i)
|
2021-11-11 18:51:42 +00:00
|
|
|
buttonGrid->setColWidthPerc(i, (buttons.at(i)->getSize().x + BUTTON_GRID_HORIZ_PADDING) /
|
|
|
|
buttonGridWidth);
|
2021-07-07 18:31:46 +00:00
|
|
|
|
|
|
|
buttonGrid->setSize(buttonGridWidth,
|
2021-11-11 18:51:42 +00:00
|
|
|
buttons.at(0)->getSize().y + BUTTON_GRID_VERT_PADDING + 2.0f);
|
2020-06-21 12:25:28 +00:00
|
|
|
// Spacer row to deal with dropshadow to make buttons look centered.
|
2021-08-16 16:25:01 +00:00
|
|
|
buttonGrid->setRowHeightPerc(1, 2.0f / buttonGrid->getSize().y);
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
return buttonGrid;
|
2014-03-15 17:18:50 +00:00
|
|
|
}
|
2014-03-22 21:02:25 +00:00
|
|
|
|
2023-05-07 20:56:24 +00:00
|
|
|
std::shared_ptr<ImageComponent> MenuComponent::makeArrow()
|
2014-03-22 21:02:25 +00:00
|
|
|
{
|
2022-01-19 17:01:54 +00:00
|
|
|
auto bracket = std::make_shared<ImageComponent>();
|
2022-10-24 22:43:27 +00:00
|
|
|
bracket->setResize(0, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight());
|
2022-08-30 18:26:48 +00:00
|
|
|
bracket->setImage(":/graphics/arrow.svg");
|
2023-05-07 20:56:24 +00:00
|
|
|
bracket->setColorShift(mMenuColorPrimary);
|
2020-06-21 12:25:28 +00:00
|
|
|
return bracket;
|
2014-03-22 21:02:25 +00:00
|
|
|
}
|