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
|
|
|
// ComponentList.cpp
|
2020-06-06 14:48:05 +00:00
|
|
|
//
|
2020-06-21 12:25:28 +00:00
|
|
|
// Used to lay out and navigate lists in GUI menus.
|
2020-06-06 14:48:05 +00:00
|
|
|
//
|
|
|
|
|
2014-06-20 01:30:09 +00:00
|
|
|
#include "components/ComponentList.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
|
2021-01-13 18:45:56 +00:00
|
|
|
#define TOTAL_HORIZONTAL_PADDING_PX 20.0f
|
2014-03-01 21:02:44 +00:00
|
|
|
|
2021-07-07 18:31:46 +00:00
|
|
|
ComponentList::ComponentList(Window* window)
|
|
|
|
: IList<ComponentListRow, void*>(window, LIST_SCROLL_STYLE_SLOW, LIST_NEVER_LOOP)
|
2014-03-01 21:02:44 +00:00
|
|
|
{
|
2021-07-02 15:44:27 +00:00
|
|
|
// Adjust the padding relative to the aspect ratio and screen resolution to make it look
|
|
|
|
// coherent regardless of screen type. The 1.778 aspect ratio value is the 16:9 reference.
|
|
|
|
float aspectValue = 1.778f / Renderer::getScreenAspectRatio();
|
2021-07-07 18:31:46 +00:00
|
|
|
mHorizontalPadding =
|
|
|
|
TOTAL_HORIZONTAL_PADDING_PX * aspectValue * Renderer::getScreenWidthModifier();
|
2021-07-02 15:44:27 +00:00
|
|
|
|
|
|
|
mSelectorBarOffset = 0.0f;
|
|
|
|
mCameraOffset = 0.0f;
|
2020-06-21 12:25:28 +00:00
|
|
|
mFocused = false;
|
2014-03-01 21:02:44 +00:00
|
|
|
}
|
|
|
|
|
2014-03-06 19:45:03 +00:00
|
|
|
void ComponentList::addRow(const ComponentListRow& row, bool setCursorHere)
|
2014-03-01 21:02:44 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
IList<ComponentListRow, void*>::Entry e;
|
|
|
|
e.name = "";
|
2020-06-28 16:39:18 +00:00
|
|
|
e.object = nullptr;
|
2020-06-21 12:25:28 +00:00
|
|
|
e.data = row;
|
2014-03-01 21:02:44 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
this->add(e);
|
2014-03-01 21:02:44 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
for (auto it = mEntries.back().data.elements.cbegin();
|
2021-07-07 18:31:46 +00:00
|
|
|
it != mEntries.back().data.elements.cend(); it++)
|
2020-06-21 12:25:28 +00:00
|
|
|
addChild(it->component.get());
|
2014-03-01 21:02:44 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
updateElementSize(mEntries.back().data);
|
|
|
|
updateElementPosition(mEntries.back().data);
|
2014-03-06 19:45:03 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (setCursorHere) {
|
2020-11-17 22:06:54 +00:00
|
|
|
mCursor = static_cast<int>(mEntries.size()) - 1;
|
2020-06-21 12:25:28 +00:00
|
|
|
onCursorChanged(CURSOR_STOPPED);
|
|
|
|
}
|
2014-03-01 21:02:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ComponentList::onSizeChanged()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
for (auto it = mEntries.cbegin(); it != mEntries.cend(); it++) {
|
|
|
|
updateElementSize(it->data);
|
|
|
|
updateElementPosition(it->data);
|
|
|
|
}
|
2014-03-02 18:36:23 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
updateCameraOffset();
|
2014-03-01 21:02:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ComponentList::input(InputConfig* config, Input input)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (size() == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Give it to the current row's input handler.
|
|
|
|
if (mEntries.at(mCursor).data.input_handler) {
|
|
|
|
if (mEntries.at(mCursor).data.input_handler(config, input))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// No input handler assigned, do the default, which is to give it
|
|
|
|
// to the rightmost element in the row.
|
|
|
|
auto& row = mEntries.at(mCursor).data;
|
|
|
|
if (row.elements.size()) {
|
|
|
|
if (row.elements.back().component->input(config, input))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Input handler didn't consume the input - try to scroll.
|
|
|
|
if (config->isMappedLike("up", input)) {
|
|
|
|
return listInput(input.value != 0 ? -1 : 0);
|
|
|
|
}
|
|
|
|
else if (config->isMappedLike("down", input)) {
|
|
|
|
return listInput(input.value != 0 ? 1 : 0);
|
|
|
|
}
|
|
|
|
else if (config->isMappedLike("leftshoulder", input)) {
|
|
|
|
return listInput(input.value != 0 ? -6 : 0);
|
|
|
|
}
|
|
|
|
else if (config->isMappedLike("rightshoulder", input)) {
|
|
|
|
return listInput(input.value != 0 ? 6 : 0);
|
|
|
|
}
|
|
|
|
else if (config->isMappedLike("lefttrigger", input)) {
|
2020-08-02 13:04:43 +00:00
|
|
|
if (input.value != 0) {
|
|
|
|
mSelectorBarOffset = 0;
|
|
|
|
return listFirstRow();
|
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
else if (config->isMappedLike("righttrigger", input)) {
|
2020-08-02 13:04:43 +00:00
|
|
|
if (input.value != 0) {
|
2020-12-29 11:54:24 +00:00
|
|
|
mSelectorBarOffset = mEntries.size() - 1.0f;
|
2020-08-02 13:04:43 +00:00
|
|
|
return listLastRow();
|
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2014-03-01 21:02:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ComponentList::update(int deltaTime)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
listUpdate(deltaTime);
|
|
|
|
|
|
|
|
if (size()) {
|
|
|
|
// Update our currently selected row.
|
|
|
|
for (auto it = mEntries.at(mCursor).data.elements.cbegin();
|
2021-07-07 18:31:46 +00:00
|
|
|
it != mEntries.at(mCursor).data.elements.cend(); it++)
|
2020-06-21 12:25:28 +00:00
|
|
|
it->component->update(deltaTime);
|
|
|
|
}
|
2014-03-01 21:02:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ComponentList::onCursorChanged(const CursorState& state)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
// Update the selector bar position.
|
|
|
|
// In the future this might be animated.
|
|
|
|
mSelectorBarOffset = 0;
|
|
|
|
for (int i = 0; i < mCursor; i++)
|
|
|
|
mSelectorBarOffset += getRowHeight(mEntries.at(i).data);
|
2014-03-02 16:41:02 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
updateCameraOffset();
|
2014-03-24 22:55:36 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// This is terribly inefficient but we don't know what we came from so...
|
|
|
|
if (size()) {
|
|
|
|
for (auto it = mEntries.cbegin(); it != mEntries.cend(); it++)
|
|
|
|
it->data.elements.back().component->onFocusLost();
|
2017-05-18 10:16:57 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
mEntries.at(mCursor).data.elements.back().component->onFocusGained();
|
|
|
|
}
|
2014-03-24 22:55:36 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (mCursorChangedCallback)
|
|
|
|
mCursorChangedCallback(state);
|
2014-03-24 22:55:36 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
updateHelpPrompts();
|
2014-03-24 22:55:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ComponentList::updateCameraOffset()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
// Move the camera to scroll.
|
|
|
|
const float totalHeight = getTotalRowHeight();
|
2021-08-16 16:25:01 +00:00
|
|
|
if (totalHeight > mSize.y) {
|
|
|
|
float target =
|
|
|
|
mSelectorBarOffset + getRowHeight(mEntries.at(mCursor).data) / 2.0f - (mSize.y / 2.0f);
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2021-01-29 16:59:05 +00:00
|
|
|
// Clamp the camera to prevent a fraction of a row from being displayed.
|
|
|
|
mCameraOffset = 0.0f;
|
2020-06-21 12:25:28 +00:00
|
|
|
unsigned int i = 0;
|
|
|
|
while (mCameraOffset < target && i < mEntries.size()) {
|
|
|
|
mCameraOffset += getRowHeight(mEntries.at(i).data);
|
2021-08-16 16:25:01 +00:00
|
|
|
if (mCameraOffset > totalHeight - mSize.y)
|
2021-01-29 16:59:05 +00:00
|
|
|
break;
|
2020-06-21 12:25:28 +00:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2021-08-16 16:25:01 +00:00
|
|
|
if (mCameraOffset < 0.0f)
|
|
|
|
mCameraOffset = 0.0f;
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
else {
|
2021-08-16 16:25:01 +00:00
|
|
|
mCameraOffset = 0.0f;
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
2014-03-01 21:02:44 +00:00
|
|
|
}
|
|
|
|
|
2021-08-15 17:30:31 +00:00
|
|
|
void ComponentList::render(const glm::mat4& parentTrans)
|
2014-03-01 21:02:44 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!size())
|
|
|
|
return;
|
|
|
|
|
2021-08-15 17:30:31 +00:00
|
|
|
glm::mat4 trans = parentTrans * getTransform();
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
// Clip everything to be inside our bounds.
|
2021-08-16 16:25:01 +00:00
|
|
|
glm::vec3 dim(mSize.x, mSize.y, 0.0f);
|
2021-08-15 17:30:31 +00:00
|
|
|
dim.x = (trans[0].x * dim.x + trans[3].x) - trans[3].x;
|
|
|
|
dim.y = (trans[1].y * dim.y + trans[3].y) - trans[3].y;
|
|
|
|
|
2021-07-07 18:31:46 +00:00
|
|
|
Renderer::pushClipRect(
|
2021-08-15 17:30:31 +00:00
|
|
|
Vector2i(static_cast<int>(std::round(trans[3].x)),
|
|
|
|
static_cast<int>(std::round(trans[3].y))),
|
|
|
|
Vector2i(static_cast<int>(std::round(dim.x)), static_cast<int>(std::round(dim.y))));
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
// Scroll the camera.
|
2021-08-15 17:30:31 +00:00
|
|
|
trans = glm::translate(trans, glm::vec3(0.0f, -std::round(mCameraOffset), 0.0f));
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
// Draw our entries.
|
|
|
|
std::vector<GuiComponent*> drawAfterCursor;
|
|
|
|
bool drawAll;
|
|
|
|
for (unsigned int i = 0; i < mEntries.size(); i++) {
|
|
|
|
auto& entry = mEntries.at(i);
|
2020-11-17 22:06:54 +00:00
|
|
|
drawAll = !mFocused || i != static_cast<unsigned int>(mCursor);
|
2020-06-21 12:25:28 +00:00
|
|
|
for (auto it = entry.data.elements.cbegin(); it != entry.data.elements.cend(); it++) {
|
|
|
|
if (drawAll || it->invert_when_selected) {
|
|
|
|
// For the row where the cursor is at, we want to remove any hue from the
|
2020-11-08 12:03:45 +00:00
|
|
|
// font or image before inverting, as it would otherwise lead to an ugly
|
|
|
|
// inverted color (e.g. red inverting to a green hue).
|
2021-07-07 18:31:46 +00:00
|
|
|
if (i == mCursor && it->component->getValue() != "") {
|
2020-11-08 12:03:45 +00:00
|
|
|
// Check if we're dealing with text or an image component.
|
|
|
|
bool isTextComponent = true;
|
2020-06-21 12:25:28 +00:00
|
|
|
unsigned int origColor = it->component->getColor();
|
2020-11-08 12:03:45 +00:00
|
|
|
if (origColor == 0) {
|
|
|
|
origColor = it->component->getColorShift();
|
|
|
|
isTextComponent = false;
|
|
|
|
}
|
|
|
|
// Check if the color is neutral.
|
2020-06-21 12:25:28 +00:00
|
|
|
unsigned char byteRed = origColor >> 24 & 0xFF;
|
|
|
|
unsigned char byteGreen = origColor >> 16 & 0xFF;
|
|
|
|
unsigned char byteBlue = origColor >> 8 & 0xFF;
|
|
|
|
// If it's neutral, just proceed with normal rendering.
|
|
|
|
if (byteRed == byteGreen && byteGreen == byteBlue) {
|
|
|
|
it->component->render(trans);
|
|
|
|
}
|
|
|
|
else {
|
2020-11-08 12:03:45 +00:00
|
|
|
if (isTextComponent)
|
|
|
|
it->component->setColor(DEFAULT_INVERTED_TEXTCOLOR);
|
|
|
|
else
|
|
|
|
it->component->setColorShift(DEFAULT_INVERTED_IMAGECOLOR);
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
it->component->render(trans);
|
|
|
|
// Revert to the original color after rendering.
|
2020-11-08 12:03:45 +00:00
|
|
|
if (isTextComponent)
|
|
|
|
it->component->setColor(origColor);
|
|
|
|
else
|
|
|
|
it->component->setColorShift(origColor);
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
it->component->render(trans);
|
|
|
|
}
|
|
|
|
}
|
2020-07-15 15:44:27 +00:00
|
|
|
else {
|
2020-06-21 12:25:28 +00:00
|
|
|
drawAfterCursor.push_back(it->component.get());
|
2020-07-15 15:44:27 +00:00
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Custom rendering.
|
|
|
|
Renderer::setMatrix(trans);
|
|
|
|
|
2020-12-29 11:54:24 +00:00
|
|
|
float opacity = mOpacity / 255.0f;
|
2020-09-12 17:17:26 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Draw selector bar.
|
|
|
|
if (mFocused) {
|
|
|
|
const float selectedRowHeight = getRowHeight(mEntries.at(mCursor).data);
|
2020-09-12 17:17:26 +00:00
|
|
|
|
|
|
|
if (opacity == 1) {
|
2021-08-16 16:25:01 +00:00
|
|
|
Renderer::drawRect(0.0f, mSelectorBarOffset, mSize.x, selectedRowHeight, 0xFFFFFFFF,
|
2021-07-07 18:31:46 +00:00
|
|
|
0xFFFFFFFF, false, opacity, trans,
|
|
|
|
Renderer::Blend::ONE_MINUS_DST_COLOR, Renderer::Blend::ZERO);
|
2020-09-12 17:17:26 +00:00
|
|
|
|
2021-08-16 16:25:01 +00:00
|
|
|
Renderer::drawRect(0.0f, mSelectorBarOffset, mSize.x, selectedRowHeight, 0x777777FF,
|
2021-07-07 18:31:46 +00:00
|
|
|
0x777777FF, false, opacity, trans, Renderer::Blend::ONE,
|
|
|
|
Renderer::Blend::ONE);
|
2020-09-12 17:17:26 +00:00
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
for (auto it = drawAfterCursor.cbegin(); it != drawAfterCursor.cend(); it++)
|
|
|
|
(*it)->render(trans);
|
|
|
|
|
|
|
|
// Reset matrix if one of these components changed it.
|
|
|
|
if (drawAfterCursor.size())
|
|
|
|
Renderer::setMatrix(trans);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw separators.
|
|
|
|
float y = 0;
|
|
|
|
for (unsigned int i = 0; i < mEntries.size(); i++) {
|
2021-08-16 16:25:01 +00:00
|
|
|
Renderer::drawRect(0.0f, y, mSize.x, 1.0f * Renderer::getScreenHeightModifier(), 0xC6C7C6FF,
|
|
|
|
0xC6C7C6FF, false, opacity, trans);
|
2020-06-21 12:25:28 +00:00
|
|
|
y += getRowHeight(mEntries.at(i).data);
|
|
|
|
}
|
|
|
|
|
2021-08-16 16:25:01 +00:00
|
|
|
Renderer::drawRect(0.0f, y, mSize.x, 1.0f * Renderer::getScreenHeightModifier(), 0xC6C7C6FF,
|
2021-07-07 18:31:46 +00:00
|
|
|
0xC6C7C6FF, false, opacity, trans);
|
2020-06-21 12:25:28 +00:00
|
|
|
Renderer::popClipRect();
|
2014-03-01 21:02:44 +00:00
|
|
|
}
|
|
|
|
|
2014-03-02 16:41:02 +00:00
|
|
|
float ComponentList::getRowHeight(const ComponentListRow& row) const
|
2014-03-01 21:02:44 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
// Returns the highest component height found in the row.
|
|
|
|
float height = 0;
|
|
|
|
for (unsigned int i = 0; i < row.elements.size(); i++) {
|
2021-08-16 16:25:01 +00:00
|
|
|
if (row.elements.at(i).component->getSize().y > height)
|
|
|
|
height = row.elements.at(i).component->getSize().y;
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return height;
|
2014-03-01 21:02:44 +00:00
|
|
|
}
|
|
|
|
|
2014-03-02 16:41:02 +00:00
|
|
|
float ComponentList::getTotalRowHeight() const
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
float height = 0;
|
|
|
|
for (auto it = mEntries.cbegin(); it != mEntries.cend(); it++)
|
|
|
|
height += getRowHeight(it->data);
|
2014-03-02 16:41:02 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
return height;
|
2014-03-02 16:41:02 +00:00
|
|
|
}
|
|
|
|
|
2014-03-01 21:02:44 +00:00
|
|
|
void ComponentList::updateElementPosition(const ComponentListRow& row)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
float yOffset = 0;
|
|
|
|
for (auto it = mEntries.cbegin(); it != mEntries.cend() && &it->data != &row; it++)
|
|
|
|
yOffset += getRowHeight(it->data);
|
2014-03-01 21:02:44 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Assumes updateElementSize has already been called.
|
|
|
|
float rowHeight = getRowHeight(row);
|
2021-07-02 15:44:27 +00:00
|
|
|
float x = mHorizontalPadding / 2.0f;
|
2014-03-01 21:02:44 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
for (unsigned int i = 0; i < row.elements.size(); i++) {
|
|
|
|
const auto comp = row.elements.at(i).component;
|
2014-03-01 21:02:44 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Center vertically.
|
2021-08-16 16:25:01 +00:00
|
|
|
comp->setPosition(x, (rowHeight - comp->getSize().y) / 2.0f + yOffset);
|
|
|
|
x += comp->getSize().x;
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
2014-03-01 21:02:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ComponentList::updateElementSize(const ComponentListRow& row)
|
|
|
|
{
|
2021-08-16 16:25:01 +00:00
|
|
|
float width = mSize.x - mHorizontalPadding;
|
2021-03-27 09:26:13 +00:00
|
|
|
std::vector<std::shared_ptr<GuiComponent>> resizeVec;
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
for (auto it = row.elements.cbegin(); it != row.elements.cend(); it++) {
|
|
|
|
if (it->resize_width)
|
|
|
|
resizeVec.push_back(it->component);
|
|
|
|
else
|
2021-08-16 16:25:01 +00:00
|
|
|
width -= it->component->getSize().x;
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Redistribute the "unused" width equally among the components with resize_width set to true.
|
|
|
|
width = width / resizeVec.size();
|
|
|
|
for (auto it = resizeVec.cbegin(); it != resizeVec.cend(); it++)
|
2021-08-16 16:25:01 +00:00
|
|
|
(*it)->setSize(width, (*it)->getSize().y);
|
2014-03-01 21:02:44 +00:00
|
|
|
}
|
2014-03-13 19:09:50 +00:00
|
|
|
|
2020-12-16 22:59:00 +00:00
|
|
|
void ComponentList::textInput(const std::string& text)
|
2014-03-21 02:47:45 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!size())
|
|
|
|
return;
|
2014-03-21 02:47:45 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
mEntries.at(mCursor).data.elements.back().component->textInput(text);
|
2014-03-21 02:47:45 +00:00
|
|
|
}
|
|
|
|
|
2014-03-13 19:09:50 +00:00
|
|
|
std::vector<HelpPrompt> ComponentList::getHelpPrompts()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!size())
|
|
|
|
return std::vector<HelpPrompt>();
|
|
|
|
|
|
|
|
std::vector<HelpPrompt> prompts =
|
2021-07-07 18:31:46 +00:00
|
|
|
mEntries.at(mCursor).data.elements.back().component->getHelpPrompts();
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
if (size() > 1) {
|
|
|
|
bool addMovePrompt = true;
|
|
|
|
for (auto it = prompts.cbegin(); it != prompts.cend(); it++) {
|
|
|
|
if (it->first == "up/down" || it->first == "up/down/left/right") {
|
|
|
|
addMovePrompt = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (addMovePrompt)
|
|
|
|
prompts.push_back(HelpPrompt("up/down", "choose"));
|
|
|
|
}
|
|
|
|
|
|
|
|
return prompts;
|
2014-03-13 19:09:50 +00:00
|
|
|
}
|
2014-03-22 01:12:57 +00:00
|
|
|
|
|
|
|
bool ComponentList::moveCursor(int amt)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
bool ret = listInput(amt);
|
|
|
|
listInput(0);
|
|
|
|
return ret;
|
2014-03-22 01:12:57 +00:00
|
|
|
}
|