mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-21 21:55:38 +00:00
Added ComponentListComponent for laying out elements in a grid and
navigating through them. Added SliderComponent for selecting from a range of values. Added SwitchComponent for selecting an "ON" or "OFF" value.
This commit is contained in:
parent
e8465baaba
commit
1534cec865
|
@ -133,7 +133,10 @@ set(ES_HEADERS
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/Window.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/XMLReader.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/AnimationComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ComponentListComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SliderComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextListComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ThemeComponent.h
|
||||
|
@ -143,6 +146,7 @@ set(ES_HEADERS
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiGameList.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiInputConfig.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiMenu.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiSettingsMenu.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pugiXML/pugiconfig.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pugiXML/pugixml.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/data/Resources.h
|
||||
|
@ -169,7 +173,10 @@ set(ES_SOURCES
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/Window.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/XMLReader.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/AnimationComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ComponentListComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SliderComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ThemeComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiBox.cpp
|
||||
|
@ -178,6 +185,7 @@ set(ES_SOURCES
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiGameList.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiInputConfig.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiMenu.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiSettingsMenu.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pugiXML/pugixml.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/data/logo/ES_logo_16.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/data/logo/ES_logo_32.cpp
|
||||
|
|
|
@ -13,6 +13,9 @@ GuiComponent::~GuiComponent()
|
|||
|
||||
if(mParent)
|
||||
mParent->removeChild(this);
|
||||
|
||||
for(unsigned int i = 0; i < getChildCount(); i++)
|
||||
getChild(i)->setParent(NULL);
|
||||
}
|
||||
|
||||
bool GuiComponent::input(InputConfig* config, Input input)
|
||||
|
@ -83,13 +86,15 @@ Vector2i GuiComponent::getOffset()
|
|||
|
||||
void GuiComponent::setOffset(Vector2i offset)
|
||||
{
|
||||
mOffset = offset;
|
||||
setOffset(offset.x, offset.y);
|
||||
onOffsetChanged();
|
||||
}
|
||||
|
||||
void GuiComponent::setOffset(int x, int y)
|
||||
{
|
||||
mOffset.x = x;
|
||||
mOffset.y = y;
|
||||
onOffsetChanged();
|
||||
}
|
||||
|
||||
Vector2u GuiComponent::getSize()
|
||||
|
|
|
@ -29,10 +29,11 @@ public:
|
|||
//Called when the Renderer deinitializes. Passes to children.
|
||||
virtual void deinit();
|
||||
|
||||
Vector2i getGlobalOffset();
|
||||
virtual Vector2i getGlobalOffset();
|
||||
Vector2i getOffset();
|
||||
void setOffset(Vector2i offset);
|
||||
void setOffset(int x, int y);
|
||||
virtual void onOffsetChanged() {};
|
||||
|
||||
Vector2u getSize();
|
||||
|
||||
|
|
312
src/components/ComponentListComponent.cpp
Normal file
312
src/components/ComponentListComponent.cpp
Normal file
|
@ -0,0 +1,312 @@
|
|||
#include "ComponentListComponent.h"
|
||||
#include "../Log.h"
|
||||
#include "../Renderer.h"
|
||||
|
||||
#define INITIAL_CELL_SIZE 12
|
||||
|
||||
ComponentListComponent::ComponentListComponent(Window* window, Vector2u gridDimensions) : GuiComponent(window), mGrid(NULL), mColumnWidths(NULL), mRowHeights(NULL)
|
||||
{
|
||||
mEntries.reserve(gridDimensions.x*gridDimensions.y);
|
||||
makeCells(gridDimensions);
|
||||
}
|
||||
|
||||
void ComponentListComponent::makeCells(Vector2u size)
|
||||
{
|
||||
if(mGrid)
|
||||
delete[] mGrid;
|
||||
if(mColumnWidths)
|
||||
delete[] mColumnWidths;
|
||||
if(mRowHeights)
|
||||
delete[] mRowHeights;
|
||||
|
||||
mGridSize = size;
|
||||
mGrid = new ComponentEntry*[size.x * size.y];
|
||||
std::fill(mGrid, mGrid + (size.x * size.y), (ComponentEntry*)NULL);
|
||||
|
||||
mColumnWidths = new unsigned int[size.x];
|
||||
std::fill(mColumnWidths, mColumnWidths + size.x, INITIAL_CELL_SIZE);
|
||||
|
||||
mRowHeights = new unsigned int[size.y];
|
||||
std::fill(mRowHeights, mRowHeights + size.y, INITIAL_CELL_SIZE);
|
||||
|
||||
updateSize();
|
||||
resetCursor();
|
||||
}
|
||||
|
||||
void ComponentListComponent::setEntry(Vector2u pos, Vector2u size, GuiComponent* component, bool canFocus, AlignmentType align,
|
||||
Vector2<bool> autoFit, UpdateBehavior updateType)
|
||||
{
|
||||
if(pos.x > mGridSize.x || pos.y > mGridSize.y)
|
||||
{
|
||||
LOG(LogError) << "Tried to set entry beyond grid size!";
|
||||
return;
|
||||
}
|
||||
|
||||
if(component == NULL)
|
||||
{
|
||||
LOG(LogError) << "Tried to add NULL component to ComponentList!";
|
||||
return;
|
||||
}
|
||||
|
||||
ComponentEntry entry(Rect(pos.x, pos.y, size.x, size.y), component, updateType, canFocus, align);
|
||||
|
||||
mEntries.push_back(entry);
|
||||
|
||||
for(unsigned int y = pos.y; y < pos.y + size.y; y++)
|
||||
{
|
||||
for(unsigned int x = pos.x; x < pos.x + size.x; x++)
|
||||
{
|
||||
setCell(x, y, &mEntries.back());
|
||||
}
|
||||
}
|
||||
|
||||
if(component->getParent() != NULL)
|
||||
LOG(LogError) << "ComponentListComponent ruining an existing parent-child relationship! Call a social worker!";
|
||||
component->setParent(this);
|
||||
|
||||
if(!cursorValid() && canFocus)
|
||||
mCursor = (Vector2i)pos;
|
||||
|
||||
//update the column width and row height
|
||||
if(autoFit.x && getColumnWidth(pos.x) < component->getSize().x)
|
||||
setColumnWidth(pos.x, component->getSize().x);
|
||||
if(autoFit.y && getRowHeight(pos.y) < component->getSize().y)
|
||||
setRowHeight(pos.y, component->getSize().y);
|
||||
|
||||
component->setOffset(getCellOffset(pos));
|
||||
}
|
||||
|
||||
void ComponentListComponent::setRowHeight(int row, unsigned int size)
|
||||
{
|
||||
mRowHeights[row] = size;
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void ComponentListComponent::setColumnWidth(int col, unsigned int size)
|
||||
{
|
||||
mColumnWidths[col] = size;
|
||||
updateSize();
|
||||
}
|
||||
|
||||
unsigned int ComponentListComponent::getRowHeight(int row) { return mRowHeights[row]; }
|
||||
unsigned int ComponentListComponent::getColumnWidth(int col) { return mColumnWidths[col]; }
|
||||
|
||||
Vector2i ComponentListComponent::getCellOffset(Vector2u pos)
|
||||
{
|
||||
Vector2i offset;
|
||||
|
||||
for(unsigned int y = 0; y < pos.y; y++)
|
||||
offset.y += getRowHeight(y);
|
||||
|
||||
for(unsigned int x = 0; x < pos.x; x++)
|
||||
offset.x += getColumnWidth(x);
|
||||
|
||||
ComponentEntry* entry = getCell(pos.x, pos.y);
|
||||
|
||||
Vector2u gridSize;
|
||||
for(unsigned int x = pos.x; x < pos.x + entry->box.size.x; x++)
|
||||
gridSize.x += getColumnWidth(x);
|
||||
for(unsigned int y = pos.y; y < pos.y + entry->box.size.y; y++)
|
||||
gridSize.y += getRowHeight(y);
|
||||
|
||||
//if AlignCenter, add half of cell width - half of control width
|
||||
if(entry->alignment == AlignCenter)
|
||||
offset.x += gridSize.x / 2 - entry->component->getSize().x / 2;
|
||||
|
||||
//if AlignRight, add cell width - control width
|
||||
if(entry->alignment == AlignRight)
|
||||
offset.x += gridSize.x - entry->component->getSize().x;
|
||||
|
||||
//always center on the Y axis
|
||||
offset.y += gridSize.y / 2 - entry->component->getSize().y / 2;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void ComponentListComponent::setCell(unsigned int x, unsigned int y, ComponentEntry* entry)
|
||||
{
|
||||
if(x < 0 || y < 0 || x >= mGridSize.x || y >= mGridSize.y)
|
||||
{
|
||||
LOG(LogError) << "Invalid setCell - position " << x << ", " << y << " out of bounds!";
|
||||
return;
|
||||
}
|
||||
|
||||
mGrid[y * mGridSize.x + x] = entry;
|
||||
}
|
||||
|
||||
ComponentListComponent::ComponentEntry* ComponentListComponent::getCell(unsigned int x, unsigned int y)
|
||||
{
|
||||
if(x < 0 || y < 0 || x >= mGridSize.x || y >= mGridSize.y)
|
||||
{
|
||||
LOG(LogError) << "Invalid getCell - position " << x << ", " << y << " out of bounds!";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mGrid[y * mGridSize.x + x];
|
||||
}
|
||||
|
||||
void ComponentListComponent::updateSize()
|
||||
{
|
||||
mSize = Vector2u(0, 0);
|
||||
for(unsigned int x = 0; x < mGridSize.x; x++)
|
||||
mSize.x += getColumnWidth(x);
|
||||
for(unsigned int y = 0; y < mGridSize.y; y++)
|
||||
mSize.y += getRowHeight(y);
|
||||
}
|
||||
|
||||
void ComponentListComponent::updateComponentOffsets()
|
||||
{
|
||||
for(auto iter = mEntries.begin(); iter != mEntries.end(); iter++)
|
||||
{
|
||||
iter->component->setOffset(getCellOffset((Vector2u)iter->box.pos));
|
||||
}
|
||||
}
|
||||
|
||||
bool ComponentListComponent::input(InputConfig* config, Input input)
|
||||
{
|
||||
if(cursorValid() && getCell(mCursor.x, mCursor.y)->component->input(config, input))
|
||||
return true;
|
||||
|
||||
if(!input.value)
|
||||
return false;
|
||||
|
||||
if(config->isMappedTo("down", input))
|
||||
{
|
||||
moveCursor(Vector2i(0, 1));
|
||||
return true;
|
||||
}
|
||||
if(config->isMappedTo("up", input))
|
||||
{
|
||||
moveCursor(Vector2i(0, -1));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ComponentListComponent::resetCursor()
|
||||
{
|
||||
if(mEntries.size() == 0)
|
||||
{
|
||||
mCursor = Vector2i(-1, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
mCursor = mEntries.at(0).box.pos;
|
||||
}
|
||||
|
||||
void ComponentListComponent::moveCursor(Vector2i dir)
|
||||
{
|
||||
if(dir.x != 0 && dir.y != 0)
|
||||
{
|
||||
LOG(LogError) << "Invalid cursor move dir!";
|
||||
return;
|
||||
}
|
||||
|
||||
if(!cursorValid())
|
||||
{
|
||||
resetCursor();
|
||||
if(!cursorValid())
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2i origCursor = mCursor;
|
||||
|
||||
Vector2i searchAxis(dir.x == 0, dir.y == 0);
|
||||
|
||||
while(mCursor.x >= 0 && mCursor.y >= 0 && mCursor.x < (int)mGridSize.x && mCursor.y < (int)mGridSize.y)
|
||||
{
|
||||
mCursor = mCursor + dir;
|
||||
|
||||
Vector2i curDirPos = mCursor;
|
||||
|
||||
//spread out on search axis+
|
||||
while(mCursor.x < (int)mGridSize.x && mCursor.y < (int)mGridSize.y)
|
||||
{
|
||||
if(cursorValid() && getCell(mCursor.x, mCursor.y)->canFocus)
|
||||
return;
|
||||
|
||||
mCursor += searchAxis;
|
||||
}
|
||||
|
||||
//now again on search axis-
|
||||
mCursor = curDirPos;
|
||||
while(mCursor.x >= 0 && mCursor.y >= 0)
|
||||
{
|
||||
if(cursorValid() && getCell(mCursor.x, mCursor.y)->canFocus)
|
||||
return;
|
||||
|
||||
mCursor -= searchAxis;
|
||||
}
|
||||
}
|
||||
|
||||
//failed to find another focusable element in this direction
|
||||
mCursor = origCursor;
|
||||
}
|
||||
|
||||
bool ComponentListComponent::cursorValid()
|
||||
{
|
||||
if(mCursor.x < 0 || mCursor.y < 0 || mCursor.x >= (int)mGridSize.x || mCursor.y >= (int)mGridSize.y)
|
||||
return false;
|
||||
|
||||
return getCell(mCursor.x, mCursor.y) != NULL;
|
||||
}
|
||||
|
||||
void ComponentListComponent::update(int deltaTime)
|
||||
{
|
||||
for(auto iter = mEntries.begin(); iter != mEntries.end(); iter++)
|
||||
{
|
||||
if(iter->updateType == UpdateAlways)
|
||||
{
|
||||
iter->component->update(deltaTime);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(iter->updateType == UpdateFocused && cursorValid() && getCell(mCursor.x, mCursor.y)->component == iter->component)
|
||||
{
|
||||
iter->component->update(deltaTime);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentListComponent::onRender()
|
||||
{
|
||||
Renderer::drawRect(0, 0, getSize().x, getSize().y, 0xFFFFFFAA);
|
||||
|
||||
for(auto iter = mEntries.begin(); iter != mEntries.end(); iter++)
|
||||
{
|
||||
iter->component->render();
|
||||
}
|
||||
|
||||
//draw cell outlines
|
||||
/*Vector2i pos;
|
||||
for(unsigned int x = 0; x < mGridSize.x; x++)
|
||||
{
|
||||
for(unsigned int y = 0; y < mGridSize.y; y++)
|
||||
{
|
||||
Renderer::drawRect(pos.x, pos.y, getColumnWidth(x), 2, 0x000000AA);
|
||||
Renderer::drawRect(pos.x, pos.y, 2, getRowHeight(y), 0x000000AA);
|
||||
Renderer::drawRect(pos.x + getColumnWidth(x), pos.y, 2, getRowHeight(y), 0x000000AA);
|
||||
Renderer::drawRect(pos.x, pos.y + getRowHeight(y) - 2, getColumnWidth(x), 2, 0x000000AA);
|
||||
|
||||
pos.y += getRowHeight(y);
|
||||
}
|
||||
|
||||
pos.y = 0;
|
||||
pos.x += getColumnWidth(x);
|
||||
}*/
|
||||
|
||||
//draw cursor
|
||||
if(cursorValid())
|
||||
{
|
||||
ComponentEntry* entry = getCell(mCursor.x, mCursor.y);
|
||||
Renderer::drawRect(entry->component->getOffset().x, entry->component->getOffset().y, 4, 4, 0xFF0000FF);
|
||||
Renderer::drawRect(entry->component->getOffset().x, entry->component->getOffset().y, entry->component->getSize().x, entry->component->getSize().y, 0x0000AA88);
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentListComponent::onOffsetChanged()
|
||||
{
|
||||
updateComponentOffsets();
|
||||
}
|
129
src/components/ComponentListComponent.h
Normal file
129
src/components/ComponentListComponent.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
#pragma once
|
||||
|
||||
#include "../GuiComponent.h"
|
||||
|
||||
class ComponentListComponent : public GuiComponent
|
||||
{
|
||||
public:
|
||||
ComponentListComponent(Window* window, Vector2u gridDimensions);
|
||||
|
||||
enum UpdateBehavior
|
||||
{
|
||||
UpdateAlways, UpdateFocused
|
||||
};
|
||||
|
||||
enum AlignmentType
|
||||
{
|
||||
AlignLeft, AlignRight, AlignCenter
|
||||
};
|
||||
|
||||
void setEntry(Vector2u pos, Vector2u size, GuiComponent* component, bool canFocus, AlignmentType align, Vector2<bool> autoFit, UpdateBehavior updateType = UpdateAlways);
|
||||
|
||||
void onOffsetChanged() override;
|
||||
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
void update(int deltaTime) override;
|
||||
void onRender() override;
|
||||
|
||||
void setColumnWidth(int col, unsigned int size);
|
||||
void setRowHeight(int row, unsigned int size);
|
||||
|
||||
void resetCursor();
|
||||
bool cursorValid();
|
||||
|
||||
private:
|
||||
class ComponentEntry
|
||||
{
|
||||
public:
|
||||
Rect box;
|
||||
GuiComponent* component;
|
||||
UpdateBehavior updateType;
|
||||
AlignmentType alignment;
|
||||
bool canFocus;
|
||||
|
||||
ComponentEntry() : component(NULL), updateType(UpdateAlways), canFocus(true), alignment(AlignCenter) {};
|
||||
ComponentEntry(Rect b, GuiComponent* comp, UpdateBehavior update, bool focus, AlignmentType align) : box(b), component(comp), updateType(update), canFocus(focus), alignment(align) {};
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return component != NULL;
|
||||
}
|
||||
};
|
||||
|
||||
//Offset we render components by (for scrolling).
|
||||
Vector2i mComponentOffset;
|
||||
|
||||
Vector2u mGridSize;
|
||||
ComponentEntry** mGrid;
|
||||
std::vector<ComponentEntry> mEntries;
|
||||
void makeCells(Vector2u size);
|
||||
void setCell(unsigned int x, unsigned int y, ComponentEntry* entry);
|
||||
ComponentEntry* getCell(unsigned int x, unsigned int y);
|
||||
|
||||
Vector2u mSelectedCellIndex;
|
||||
|
||||
unsigned int getColumnWidth(int col);
|
||||
unsigned int getRowHeight(int row);
|
||||
|
||||
unsigned int* mColumnWidths;
|
||||
unsigned int* mRowHeights;
|
||||
|
||||
Vector2i getCellOffset(Vector2u gridPos);
|
||||
void updateSize();
|
||||
|
||||
void moveCursor(Vector2i dir);
|
||||
Vector2i mCursor;
|
||||
|
||||
void updateComponentOffsets();
|
||||
};
|
||||
|
||||
//ability to define a list of components in terms of a grid
|
||||
|
||||
//input
|
||||
//pass to selected component
|
||||
// if returns true, stop
|
||||
// else, process:
|
||||
// if input == up/down
|
||||
// scroll to prev/next selectable component in grid Y
|
||||
// if input == left/right
|
||||
// scroll to prev/next selectable component in grid X
|
||||
// if input == accept
|
||||
// call registered function?
|
||||
|
||||
//entry struct/class
|
||||
// GuiComponent* component - component to work with
|
||||
// bool canFocus - can we pass input to this? (necessary for labels to not be selectable)
|
||||
// Function* selectFunc?
|
||||
// UpdateBehavior update - how to handle updates (all the time or only when focused)
|
||||
|
||||
//update
|
||||
//animate component offset to display selected component within the bounds
|
||||
//pass update to all entries with appropriate update behavior
|
||||
|
||||
//render
|
||||
//clip rect to our size
|
||||
//render a "selected" effect behind component with focus somehow
|
||||
// an edge filter would be cool, but we can't really do that without shader support
|
||||
// a transparent rect will work for now, but it's kind of ugly...maybe a GuiBox
|
||||
//glTranslatef by our render offset
|
||||
// doesn't handle getGlobalOffset for our components...would need parenting for that
|
||||
|
||||
//methods
|
||||
//List::setEntry(Vector2i gridPos, GuiComponent* component, bool canFocus, AlignmentType align,
|
||||
// Function* selectFunc = NULL, UpdateBehavior updateType = UpdateAlways);
|
||||
|
||||
//example of setting up the SettingsMenu list:
|
||||
//ComponentListComponent list;
|
||||
//int row = 0;
|
||||
//TextComponent* label = new TextComponent(Vector2i(0, 0), "Debug:", font, lblColor, etc);
|
||||
//
|
||||
//list.setEntry(Vector2i(-1, row), label, false, AlignRight);
|
||||
//list.setEntry(Vector2i(0, row++), &mDebugSwitch, true, AlignLeft);
|
||||
//...
|
||||
//list.setEntry(Rect(-1, row, 2, 1), &mSaveButton, true, AlignCenter);
|
||||
|
||||
//example of setting up GameGrid list:
|
||||
//ComponentListComponent list;
|
||||
//for(int y = 0; y < yMax; y++)
|
||||
// for(int x = 0; x < xMax; x++)
|
||||
// list.setEntry(Vector2i(x, y), getGameImage(x, y), true, AlignCenter, &this->onSelectGame);
|
|
@ -5,6 +5,7 @@
|
|||
#include "../SystemData.h"
|
||||
#include "GuiGameList.h"
|
||||
#include "../Settings.h"
|
||||
#include "GuiSettingsMenu.h"
|
||||
|
||||
GuiMenu::GuiMenu(Window* window, GuiGameList* parent) : GuiComponent(window)
|
||||
{
|
||||
|
@ -52,6 +53,10 @@ void GuiMenu::executeCommand(std::string command)
|
|||
//reload the game list
|
||||
SystemData::loadConfig();
|
||||
mParent->setSystemId(0);
|
||||
}else if(command == "es_settings")
|
||||
{
|
||||
mWindow->pushGui(new GuiSettingsMenu(mWindow));
|
||||
delete this;
|
||||
}else{
|
||||
if(system(command.c_str()) != 0)
|
||||
{
|
||||
|
@ -69,6 +74,9 @@ void GuiMenu::populateList()
|
|||
//the method is GuiList::addObject(std::string displayString, std::string commandString, unsigned int displayHexColor);
|
||||
//the list will automatically adjust as items are added to it, this should be the only area you need to change
|
||||
//if you want to do something special within ES, override your command in the executeComand() method
|
||||
|
||||
mList->addObject("Settings", "es_settings", 0x0000FFFF);
|
||||
|
||||
mList->addObject("Restart", "sudo shutdown -r now", 0x0000FFFF);
|
||||
mList->addObject("Shutdown", "sudo shutdown -h now", 0x0000FFFF);
|
||||
|
||||
|
|
70
src/components/GuiSettingsMenu.cpp
Normal file
70
src/components/GuiSettingsMenu.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include "GuiSettingsMenu.h"
|
||||
#include "../Renderer.h"
|
||||
#include "../Settings.h"
|
||||
#include "SliderComponent.h"
|
||||
|
||||
GuiSettingsMenu::GuiSettingsMenu(Window* window) : GuiComponent(window),
|
||||
mList(window, Vector2u(2, 3)),
|
||||
mDrawFramerateSwitch(window)
|
||||
{
|
||||
addChild(&mList);
|
||||
|
||||
mList.setOffset(Renderer::getScreenWidth() / 4, 0);
|
||||
|
||||
TextComponent* label = new TextComponent(mWindow);
|
||||
label->setText("Draw Framerate: ");
|
||||
label->setColor(0x0000FFFF);
|
||||
mList.setEntry(Vector2u(0, 0), Vector2u(1, 1), label, false, ComponentListComponent::AlignRight, Vector2<bool>(true, true));
|
||||
mLabels.push_back(label);
|
||||
|
||||
//drawFramerate switch
|
||||
mList.setEntry(Vector2u(1, 0), Vector2u(1, 1), &mDrawFramerateSwitch, true, ComponentListComponent::AlignCenter, Vector2<bool>(true, true));
|
||||
|
||||
label = new TextComponent(mWindow);
|
||||
label->setText("Volume: ");
|
||||
label->setColor(0x0000FFFF);
|
||||
mList.setEntry(Vector2u(0, 1), Vector2u(1, 1), label, false, ComponentListComponent::AlignRight, Vector2<bool>(true, true));
|
||||
|
||||
//volume slider
|
||||
SliderComponent* slider = new SliderComponent(mWindow, 0, 1);
|
||||
mList.setEntry(Vector2u(1, 1), Vector2u(1, 1), slider, true, ComponentListComponent::AlignCenter, Vector2<bool>(true, true));
|
||||
|
||||
label = new TextComponent(mWindow);
|
||||
label->setText("B TO CLOSE");
|
||||
label->setColor(0x00FF00FF);
|
||||
mList.setEntry(Vector2u(0, 2), Vector2u(2, 1), label, true, ComponentListComponent::AlignCenter, Vector2<bool>(false, true));
|
||||
mLabels.push_back(label);
|
||||
|
||||
mList.setOffset(Renderer::getScreenWidth() / 2 - mList.getSize().x / 2, 0);
|
||||
|
||||
loadStates();
|
||||
}
|
||||
|
||||
GuiSettingsMenu::~GuiSettingsMenu()
|
||||
{
|
||||
for(auto iter = mLabels.begin(); iter != mLabels.end(); iter++)
|
||||
{
|
||||
delete *iter;
|
||||
}
|
||||
}
|
||||
|
||||
bool GuiSettingsMenu::input(InputConfig* config, Input input)
|
||||
{
|
||||
//let our children (read: list) go first
|
||||
if(GuiComponent::input(config, input))
|
||||
return true;
|
||||
|
||||
if(config->isMappedTo("b", input) && input.value)
|
||||
{
|
||||
delete this;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GuiSettingsMenu::loadStates()
|
||||
{
|
||||
Settings* s = Settings::getInstance();
|
||||
mDrawFramerateSwitch.setState(s->getBool("DRAWFRAMERATE"));
|
||||
}
|
29
src/components/GuiSettingsMenu.h
Normal file
29
src/components/GuiSettingsMenu.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef _SETTINGSMENU_H_
|
||||
#define _SETTINGSMENU_H_
|
||||
|
||||
#include "../GuiComponent.h"
|
||||
#include "ComponentListComponent.h"
|
||||
#include <vector>
|
||||
#include "SwitchComponent.h"
|
||||
#include "TextComponent.h"
|
||||
|
||||
class GuiSettingsMenu : public GuiComponent
|
||||
{
|
||||
public:
|
||||
GuiSettingsMenu(Window* window);
|
||||
~GuiSettingsMenu();
|
||||
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
|
||||
private:
|
||||
void loadStates();
|
||||
void applyStates();
|
||||
|
||||
ComponentListComponent mList;
|
||||
|
||||
SwitchComponent mDrawFramerateSwitch;
|
||||
|
||||
std::vector<GuiComponent*> mLabels;
|
||||
};
|
||||
|
||||
#endif
|
77
src/components/SliderComponent.cpp
Normal file
77
src/components/SliderComponent.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include "SliderComponent.h"
|
||||
#include <assert.h>
|
||||
#include "../Renderer.h"
|
||||
|
||||
SliderComponent::SliderComponent(Window* window, float min, float max) : GuiComponent(window),
|
||||
mMin(min), mMax(max), mMoveRate(0)
|
||||
{
|
||||
assert((min - max) != 0);
|
||||
|
||||
mValue = (max + min) / 2;
|
||||
|
||||
//calculate move scale
|
||||
mMoveScale = (max - min) * 0.0007f;
|
||||
|
||||
setSize(Vector2u(128, 32));
|
||||
}
|
||||
|
||||
bool SliderComponent::input(InputConfig* config, Input input)
|
||||
{
|
||||
if(config->isMappedTo("left", input))
|
||||
{
|
||||
if(input.value)
|
||||
mMoveRate = -1;
|
||||
else
|
||||
mMoveRate = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
if(config->isMappedTo("right", input))
|
||||
{
|
||||
if(input.value)
|
||||
mMoveRate = 1;
|
||||
else
|
||||
mMoveRate = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return GuiComponent::input(config, input);
|
||||
}
|
||||
|
||||
void SliderComponent::update(int deltaTime)
|
||||
{
|
||||
mValue += mMoveRate * deltaTime * mMoveScale;
|
||||
|
||||
if(mValue < mMin)
|
||||
mValue = mMin;
|
||||
if(mValue > mMax)
|
||||
mValue = mMax;
|
||||
|
||||
GuiComponent::update(deltaTime);
|
||||
}
|
||||
|
||||
void SliderComponent::onRender()
|
||||
{
|
||||
//render line
|
||||
const int lineWidth = 2;
|
||||
Renderer::drawRect(0, mSize.y / 2 - lineWidth / 2, mSize.x, lineWidth, 0x000000CC);
|
||||
|
||||
//render left end
|
||||
const int capWidth = (int)(mSize.x * 0.03f);
|
||||
Renderer::drawRect(0, 0, capWidth, mSize.y, 0x000000CC);
|
||||
|
||||
//render right end
|
||||
Renderer::drawRect(mSize.x - capWidth, 0, capWidth, mSize.y, 0x000000CC);
|
||||
|
||||
//render our value
|
||||
const int lineLength = mSize.x - capWidth;
|
||||
Renderer::drawRect((int)(((mValue + mMin) / mMax) * lineLength), 0, capWidth, mSize.y, 0x0000FFFF);
|
||||
|
||||
GuiComponent::onRender();
|
||||
}
|
||||
|
||||
void SliderComponent::setSize(Vector2u size)
|
||||
{
|
||||
mSize = size;
|
||||
}
|
25
src/components/SliderComponent.h
Normal file
25
src/components/SliderComponent.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "../GuiComponent.h"
|
||||
|
||||
class SliderComponent : public GuiComponent
|
||||
{
|
||||
public:
|
||||
SliderComponent(Window* window, float min, float max);
|
||||
|
||||
void setValue(float val);
|
||||
float getValue();
|
||||
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
void update(int deltaTime) override;
|
||||
void onRender() override;
|
||||
|
||||
void setSize(Vector2u size);
|
||||
|
||||
private:
|
||||
float mMin, mMax;
|
||||
float mValue;
|
||||
float mMoveScale;
|
||||
|
||||
float mMoveRate;
|
||||
};
|
43
src/components/SwitchComponent.cpp
Normal file
43
src/components/SwitchComponent.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include "SwitchComponent.h"
|
||||
#include "../Renderer.h"
|
||||
#include "../Font.h"
|
||||
|
||||
SwitchComponent::SwitchComponent(Window* window, bool state) : GuiComponent(window), mState(state)
|
||||
{
|
||||
//mSize = Vector2u((unsigned int)(Renderer::getScreenWidth() * 0.05),
|
||||
// (unsigned int)(Renderer::getScreenHeight() * 0.05));
|
||||
|
||||
Renderer::getDefaultFont(Renderer::MEDIUM)->sizeText("OFF", (int*)&mSize.x, (int*)&mSize.y);
|
||||
}
|
||||
|
||||
bool SwitchComponent::input(InputConfig* config, Input input)
|
||||
{
|
||||
if(config->isMappedTo("a", input) && input.value)
|
||||
{
|
||||
mState = !mState;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SwitchComponent::onRender()
|
||||
{
|
||||
Renderer::pushClipRect(getGlobalOffset(), getSize());
|
||||
|
||||
Renderer::drawText(mState ? "ON" : "OFF", 0, 0, mState ? 0x00FF00FF : 0xFF0000FF, Renderer::getDefaultFont(Renderer::MEDIUM));
|
||||
|
||||
Renderer::popClipRect();
|
||||
|
||||
GuiComponent::onRender();
|
||||
}
|
||||
|
||||
bool SwitchComponent::getState()
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
void SwitchComponent::setState(bool state)
|
||||
{
|
||||
mState = state;
|
||||
}
|
18
src/components/SwitchComponent.h
Normal file
18
src/components/SwitchComponent.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "../GuiComponent.h"
|
||||
|
||||
class SwitchComponent : public GuiComponent
|
||||
{
|
||||
public:
|
||||
SwitchComponent(Window* window, bool state = false);
|
||||
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
void onRender() override;
|
||||
|
||||
bool getState();
|
||||
void setState(bool state);
|
||||
|
||||
private:
|
||||
bool mState;
|
||||
};
|
|
@ -2,12 +2,12 @@
|
|||
#include "../Renderer.h"
|
||||
#include "../Log.h"
|
||||
|
||||
TextComponent::TextComponent(Window* window) : GuiComponent(window), mFont(NULL), mColor(0x000000FF)
|
||||
TextComponent::TextComponent(Window* window) : GuiComponent(window), mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true)
|
||||
{
|
||||
}
|
||||
|
||||
TextComponent::TextComponent(Window* window, const std::string& text, Font* font, Vector2i pos, Vector2u size) : GuiComponent(window),
|
||||
mFont(NULL), mColor(0x000000FF)
|
||||
mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true)
|
||||
{
|
||||
setText(text);
|
||||
setFont(font);
|
||||
|
@ -22,12 +22,22 @@ void TextComponent::setBox(Vector2i pos, Vector2u size)
|
|||
|
||||
void TextComponent::setExtent(Vector2u size)
|
||||
{
|
||||
mSize = size;
|
||||
if(size == Vector2u(0, 0))
|
||||
{
|
||||
mAutoCalcExtent = true;
|
||||
calculateExtent();
|
||||
}else{
|
||||
mAutoCalcExtent = false;
|
||||
mSize = size;
|
||||
}
|
||||
}
|
||||
|
||||
void TextComponent::setFont(Font* font)
|
||||
{
|
||||
mFont = font;
|
||||
|
||||
if(mAutoCalcExtent)
|
||||
calculateExtent();
|
||||
}
|
||||
|
||||
void TextComponent::setColor(unsigned int color)
|
||||
|
@ -38,6 +48,9 @@ void TextComponent::setColor(unsigned int color)
|
|||
void TextComponent::setText(const std::string& text)
|
||||
{
|
||||
mText = text;
|
||||
|
||||
if(mAutoCalcExtent)
|
||||
calculateExtent();
|
||||
}
|
||||
|
||||
void TextComponent::onRender()
|
||||
|
@ -49,7 +62,7 @@ void TextComponent::onRender()
|
|||
return;
|
||||
}
|
||||
|
||||
Renderer::pushClipRect(getOffset(), getSize());
|
||||
Renderer::pushClipRect(getGlobalOffset(), getSize());
|
||||
|
||||
Renderer::drawWrappedText(mText, 0, 0, mSize.x, mColor, font);
|
||||
|
||||
|
@ -57,3 +70,15 @@ void TextComponent::onRender()
|
|||
|
||||
GuiComponent::onRender();
|
||||
}
|
||||
|
||||
void TextComponent::calculateExtent()
|
||||
{
|
||||
Font* font = (mFont ? mFont : Renderer::getDefaultFont(Renderer::MEDIUM));
|
||||
if(font == NULL)
|
||||
{
|
||||
LOG(LogError) << "TextComponent can't get a valid font!";
|
||||
return;
|
||||
}
|
||||
|
||||
font->sizeText(mText, (int*)&mSize.x, (int*)&mSize.y);
|
||||
}
|
||||
|
|
|
@ -12,15 +12,18 @@ public:
|
|||
|
||||
void setFont(Font* font);
|
||||
void setBox(Vector2i pos, Vector2u size);
|
||||
void setExtent(Vector2u size);
|
||||
void setExtent(Vector2u size); //Use Vector2u(0, 0) to automatically generate extent.
|
||||
void setText(const std::string& text);
|
||||
void setColor(unsigned int color);
|
||||
|
||||
void onRender();
|
||||
|
||||
private:
|
||||
void calculateExtent();
|
||||
|
||||
unsigned int mColor;
|
||||
Font* mFont;
|
||||
bool mAutoCalcExtent;
|
||||
std::string mText;
|
||||
};
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#define MARQUEE_RATE 3
|
||||
|
||||
//A graphical list. Supports multiple colors for rows and scrolling.
|
||||
//TODO - add truncation to text rendering if name exceeds a maximum width (a trailing elipses, perhaps). Marquee would be nice too.
|
||||
template <typename T>
|
||||
class TextListComponent : public GuiComponent
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue