ComponentList now only scrolls if content > size.

ComponentList now has a default input handler behavior (forward to
rightmost component in row).
ComponentList now updates the currently selected row.
GuiSettingsMenu has been redone to use the new
MenuComponent/ComponentList scheme.
GuiMenu refactored slightly to be less needlessly ridiculous.
This commit is contained in:
Aloshi 2014-03-02 12:36:23 -06:00
parent fdbbf96d5e
commit e97dd8ff36
6 changed files with 167 additions and 220 deletions

View file

@ -31,6 +31,8 @@ void ComponentList::onSizeChanged()
updateElementSize(it->data); updateElementSize(it->data);
updateElementPosition(it->data); updateElementPosition(it->data);
} }
onCursorChanged(mScrollVelocity != 0 ? CURSOR_SCROLLING : CURSOR_STOPPED);
} }
bool ComponentList::input(InputConfig* config, Input input) bool ComponentList::input(InputConfig* config, Input input)
@ -39,8 +41,19 @@ bool ComponentList::input(InputConfig* config, Input input)
return false; return false;
// give it to the current row's input handler // give it to the current row's input handler
if(mEntries.at(mCursor).data.input_handler && mEntries.at(mCursor).data.input_handler(config, input)) if(mEntries.at(mCursor).data.input_handler)
{
if(mEntries.at(mCursor).data.input_handler(config, input))
return true; 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 // input handler didn't consume the input - try to scroll
if(config->isMappedTo("up", input)) if(config->isMappedTo("up", input))
@ -57,6 +70,13 @@ bool ComponentList::input(InputConfig* config, Input input)
void ComponentList::update(int deltaTime) void ComponentList::update(int deltaTime)
{ {
listUpdate(deltaTime); listUpdate(deltaTime);
if(size())
{
// update our currently selected row
for(auto it = mEntries.at(mCursor).data.elements.begin(); it != mEntries.at(mCursor).data.elements.end(); it++)
it->component->update(deltaTime);
}
} }
void ComponentList::onCursorChanged(const CursorState& state) void ComponentList::onCursorChanged(const CursorState& state)
@ -69,12 +89,17 @@ void ComponentList::onCursorChanged(const CursorState& state)
mSelectorBarOffset += getRowHeight(mEntries.at(i).data); mSelectorBarOffset += getRowHeight(mEntries.at(i).data);
} }
// move the camera to scroll
const float totalHeight = getTotalRowHeight();
if(totalHeight > mSize.y())
{
mCameraOffset = mSelectorBarOffset - (mSize.y() / 2); mCameraOffset = mSelectorBarOffset - (mSize.y() / 2);
if(mCameraOffset < 0) if(mCameraOffset < 0)
mCameraOffset = 0; mCameraOffset = 0;
else if(mCameraOffset + mSize.y() > getTotalRowHeight()) else if(mCameraOffset + mSize.y() > totalHeight)
mCameraOffset = getTotalRowHeight() - mSize.y(); mCameraOffset = totalHeight - mSize.y();
}
} }
void ComponentList::render(const Eigen::Affine3f& parentTrans) void ComponentList::render(const Eigen::Affine3f& parentTrans)

View file

@ -14,12 +14,30 @@ struct ComponentListElement
struct ComponentListRow struct ComponentListRow
{ {
std::vector<ComponentListElement> elements; std::vector<ComponentListElement> elements;
// The input handler is called when the user enters any input while this row is highlighted (including up/down).
// Return false to let the list try to use it or true if the input has been consumed.
// If no input handler is supplied (input_handler == nullptr), the default behavior is to forward the input to
// the rightmost element in the currently selected row.
std::function<bool(InputConfig*, Input)> input_handler; std::function<bool(InputConfig*, Input)> input_handler;
inline void addElement(const std::shared_ptr<GuiComponent>& component, bool resize_width) inline void addElement(const std::shared_ptr<GuiComponent>& component, bool resize_width)
{ {
elements.push_back(ComponentListElement(component, resize_width)); elements.push_back(ComponentListElement(component, resize_width));
} }
// Utility method for making an input handler for "when the users presses A on this, do func."
inline void makeAcceptInputHandler(const std::function<void()>& func)
{
input_handler = [func](InputConfig* config, Input input) -> bool {
if(config->isMappedTo("a", input) && input.value != 0)
{
func();
return true;
}
return false;
};
}
}; };
class ComponentList : public IList<ComponentListRow, void*> class ComponentList : public IList<ComponentListRow, void*>

View file

@ -10,97 +10,68 @@
GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "Main Menu") GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "Main Menu")
{ {
struct MenuEntry setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
{ mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2, (mSize.y() - mMenu.getSize().y()) / 2);
const char* name;
unsigned int color;
bool add_arrow;
std::function<void()> func;
MenuEntry(const char* n, unsigned int c, bool a, std::function<void()> f) : name(n), color(c), add_arrow(a), func(f) {}; // populate our list
}; addEntry("GENERAL SETTINGS", 0x777777FF, true,
std::vector<MenuEntry> entries;
entries.push_back(
MenuEntry("GENERAL SETTINGS", 0x777777FF, true,
[this] { mWindow->pushGui(new GuiSettingsMenu(mWindow)); } [this] { mWindow->pushGui(new GuiSettingsMenu(mWindow)); }
)
); );
entries.push_back(
MenuEntry("SCRAPE NOW", 0x777777FF, true, addEntry("SCRAPE NOW", 0x777777FF, true,
[this] { mWindow->pushGui(new GuiScraperStart(mWindow)); } [this] { mWindow->pushGui(new GuiScraperStart(mWindow)); }
)
); );
addEntry("RESTART SYSTEM", 0x990000FF, false,
entries.push_back(
MenuEntry("RESTART SYSTEM", 0x990000FF, false,
[this] { [this] {
mWindow->pushGui(new GuiMsgBoxYesNo(mWindow, "Do you really want to restart the system?", mWindow->pushGui(new GuiMsgBoxYesNo(mWindow, "Do you really want to restart the system?",
[] { [] {
if(system("sudo shutdown -r now") != 0) if(system("sudo shutdown -r now") != 0)
LOG(LogWarning) << "Restart terminated with non-zero result!"; LOG(LogWarning) << "Restart terminated with non-zero result!";
}));
}) })
);}
); );
entries.push_back( addEntry("SHUTDOWN SYSTEM", 0x990000FF, false,
MenuEntry("SHUTDOWN SYSTEM", 0x990000FF, false,
[this] { [this] {
mWindow->pushGui(new GuiMsgBoxYesNo(mWindow, "Do you really want to shutdown the system?", mWindow->pushGui(new GuiMsgBoxYesNo(mWindow, "Do you really want to shutdown the system?",
[] { [] {
if(system("sudo shutdown -h now") != 0) if(system("sudo shutdown -h now") != 0)
LOG(LogWarning) << "Shutdown terminated with non-zero result!"; LOG(LogWarning) << "Shutdown terminated with non-zero result!";
})); }));
}) }
); );
if(!Settings::getInstance()->getBool("DONTSHOWEXIT")) if(!Settings::getInstance()->getBool("DONTSHOWEXIT"))
{ {
entries.push_back( addEntry("EXIT EMULATIONSTATION", 0x990000FF, false,
MenuEntry("EXIT EMULATIONSTATION", 0x990000FF, false,
[] { [] {
SDL_Event ev; SDL_Event ev;
ev.type = SDL_QUIT; ev.type = SDL_QUIT;
SDL_PushEvent(&ev); SDL_PushEvent(&ev);
}) }
); );
} }
setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); addChild(&mMenu);
mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2, (mSize.y() - mMenu.getSize().y()) / 2); }
void GuiMenu::addEntry(const char* name, unsigned int color, bool add_arrow, const std::function<void()>& func)
{
std::shared_ptr<Font> font = Font::get(FONT_SIZE_LARGE); std::shared_ptr<Font> font = Font::get(FONT_SIZE_LARGE);
// populate the list // populate the list
ComponentListRow row; ComponentListRow row;
row.addElement(std::make_shared<TextComponent>(mWindow, name, font, color), true);
for(unsigned int i = 0; i < entries.size(); i++) if(add_arrow)
{ row.addElement(std::make_shared<TextComponent>(mWindow, ">", font, color), false);
row.elements.clear();
row.addElement(std::make_shared<TextComponent>(mWindow, entries[i].name, font, entries[i].color), true);
if(entries[i].add_arrow) row.makeAcceptInputHandler(func);
row.addElement(std::make_shared<TextComponent>(mWindow, ">", font, entries[i].color), false);
std::function<void()>& execFunc = entries[i].func;
row.input_handler = [execFunc](InputConfig* config, Input input) -> bool
{
if(config->isMappedTo("a", input) && input.value != 0)
{
execFunc();
return true;
}
return false;
};
mMenu.addRow(row); mMenu.addRow(row);
} }
addChild(&mMenu);
}
bool GuiMenu::input(InputConfig* config, Input input) bool GuiMenu::input(InputConfig* config, Input input)
{ {
if((config->isMappedTo("b", input) || config->isMappedTo("menu", input)) && input.value != 0) if((config->isMappedTo("b", input) || config->isMappedTo("menu", input)) && input.value != 0)

View file

@ -12,5 +12,7 @@ public:
bool input(InputConfig* config, Input input) override; bool input(InputConfig* config, Input input) override;
private: private:
void addEntry(const char* name, unsigned int color, bool add_arrow, const std::function<void()>& func);
MenuComponent mMenu; MenuComponent mMenu;
}; };

View file

@ -2,120 +2,88 @@
#include "../Renderer.h" #include "../Renderer.h"
#include "../Settings.h" #include "../Settings.h"
#include "../VolumeControl.h" #include "../VolumeControl.h"
#include "../Log.h"
#include "../scrapers/TheArchiveScraper.h" #include "../scrapers/TheArchiveScraper.h"
#include "../scrapers/GamesDBScraper.h" #include "../scrapers/GamesDBScraper.h"
GuiSettingsMenu::GuiSettingsMenu(Window* window) : GuiComponent(window), GuiSettingsMenu::GuiSettingsMenu(Window* window) : GuiComponent(window),
mList(window, Eigen::Vector2i(2, 8)), mMenu(mWindow, "Settings")
mBox(mWindow, ":/frame.png", 0x444444FF),
mDrawFramerateSwitch(window),
mVolumeSlider(window, 0, 100, 1, "%"),
mDisableSoundsSwitch(window, false),
mScraperOptList(window),
mScrapeRatingsSwitch(window),
mDimSlider(window, 0, 60, 1, "s"),
mDisableHelpSwitch(window),
mSaveButton(window)
{ {
loadStates(); setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
addChild(&mBox); // center menu
addChild(&mList); mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2, (mSize.y() - mMenu.getSize().y()) / 2);
mList.setPosition(Renderer::getScreenWidth() / 4.0f, 0);
using namespace Eigen; using namespace Eigen;
//drawFramerate label Settings* s = Settings::getInstance();
TextComponent* label = new TextComponent(mWindow);
label->setText("Draw Framerate: ");
label->setColor(0x0000FFFF);
mList.setEntry(Vector2i(0, 0), Vector2i(1, 1), label, false, ComponentGrid::AlignRight, Matrix<bool, 1, 2>(true, true));
mLabels.push_back(label);
//drawFramerate switch // framerate
mList.setEntry(Vector2i(1, 0), Vector2i(1, 1), &mDrawFramerateSwitch, true, ComponentGrid::AlignCenter, Matrix<bool, 1, 2>(true, true)); auto framerate = std::make_shared<SwitchComponent>(mWindow);
framerate->setState(s->getBool("DRAWFRAMERATE"));
addSetting("Draw framerate:", framerate,
[framerate] { Settings::getInstance()->setBool("DRAWFRAMERATE", framerate->getState()); });
//volume label // volume
label = new TextComponent(mWindow); auto volume = std::make_shared<SliderComponent>(mWindow, 0.f, 100.f, 1.f, "%");
label->setText("System volume: "); volume->setValue((float)VolumeControl::getInstance()->getVolume());
label->setColor(0x0000FFFF); addSetting("System volume:", volume,
mLabels.push_back(label); [volume] { VolumeControl::getInstance()->setVolume((int)volume->getValue()); });
mList.setEntry(Vector2i(0, 1), Vector2i(1, 1), label, false, ComponentGrid::AlignRight, Matrix<bool, 1, 2>(true, true));
//volume slider
mList.setEntry(Vector2i(1, 1), Vector2i(1, 1), &mVolumeSlider, true, ComponentGrid::AlignCenter, Matrix<bool, 1, 2>(true, true));
// disable sounds // disable sounds
label = new TextComponent(mWindow); auto sound_disable = std::make_shared<SwitchComponent>(mWindow);
label->setText("Disable sounds: "); sound_disable->setState(s->getBool("DISABLESOUNDS"));
label->setColor(0x0000FFFF); addSetting("Disable sound:", sound_disable,
mLabels.push_back(label); [sound_disable] { Settings::getInstance()->setBool("DISABLESOUNDS", sound_disable->getState()); });
mList.setEntry(Vector2i(0, 2), Vector2i(1, 1), label, false, ComponentGrid::AlignRight, Matrix<bool, 1, 2>(true, true));
mList.setEntry(Vector2i(1, 2), Vector2i(1, 1), &mDisableSoundsSwitch, true, ComponentGrid::AlignCenter, Matrix<bool, 1, 2>(true, true)); // scraper
auto scraper_list = std::make_shared< OptionListComponent< std::shared_ptr<Scraper> > >(mWindow, false);
//scraper label
label = new TextComponent(mWindow);
label->setText("Scraper: ");
label->setColor(0x0000FFFF);
mLabels.push_back(label);
mList.setEntry(Vector2i(0, 3), Vector2i(1, 1), label, false, ComponentGrid::AlignRight);
//fill scraper list
std::vector< std::shared_ptr<Scraper> > scrapers; std::vector< std::shared_ptr<Scraper> > scrapers;
scrapers.push_back(std::shared_ptr<Scraper>(new GamesDBScraper())); scrapers.push_back(std::make_shared<GamesDBScraper>());
scrapers.push_back(std::shared_ptr<Scraper>(new TheArchiveScraper())); scrapers.push_back(std::make_shared<TheArchiveScraper>());
mScraperOptList.populate(scrapers, [&] (const std::shared_ptr<Scraper>& s) { scraper_list->populate(scrapers, [&] (const std::shared_ptr<Scraper>& sc) {
return mScraperOptList.makeEntry(s->getName(), s, s->getName() == Settings::getInstance()->getScraper()->getName()); return scraper_list->makeEntry(sc->getName(), sc, sc->getName() == Settings::getInstance()->getScraper()->getName());
});
addSetting("Scraper:", scraper_list,
[scraper_list] {
if(scraper_list->getSelected().size() > 0)
Settings::getInstance()->setScraper(scraper_list->getSelected()[0]->object);
}); });
mList.setEntry(Vector2i(1, 3), Vector2i(1, 1), &mScraperOptList, true, ComponentGrid::AlignCenter); // scrape ratings
auto scrape_ratings = std::make_shared<SwitchComponent>(mWindow);
scrape_ratings->setState(s->getBool("ScrapeRatings"));
addSetting("Scrape ratings?", scrape_ratings,
[scrape_ratings] { Settings::getInstance()->setBool("ScrapeRatings", scrape_ratings->getState()); });
//scrape ratings label // dim time
label = new TextComponent(mWindow); auto dim_time = std::make_shared<SliderComponent>(mWindow, 0.f, 1200.f, 30.f, "s");
label->setText("Scrape ratings? "); dim_time->setValue((float)(s->getInt("DIMTIME") / 1000));
label->setColor(0x0000FFFF); addSetting("Dim screen after:", dim_time,
mLabels.push_back(label); [dim_time] { Settings::getInstance()->setInt("DIMTIME", (int)(dim_time->getValue() * 1000)); });
mList.setEntry(Vector2i(0, 4), Vector2i(1, 1), label, false, ComponentGrid::AlignRight);
mList.setEntry(Vector2i(1, 4), Vector2i(1, 1), &mScrapeRatingsSwitch, true, ComponentGrid::AlignCenter); // disable help
auto disable_help = std::make_shared<SwitchComponent>(mWindow);
// dim time label disable_help->setState(s->getBool("DISABLEHELP"));
label = new TextComponent(mWindow); addSetting("Disable help:", disable_help,
label->setText("Dim after: "); [disable_help] { Settings::getInstance()->setBool("DISABLEHELP", disable_help->getState()); });
label->setColor(0x0000FFFF);
mLabels.push_back(label);
mList.setEntry(Vector2i(0, 5), Vector2i(1, 1), label, false, ComponentGrid::AlignRight);
mList.setEntry(Vector2i(1, 5), Vector2i(1, 1), &mDimSlider, true, ComponentGrid::AlignCenter);
// disable help switch
label = new TextComponent(mWindow);
label->setText("Disable help: ");
label->setColor(0x0000FFFF);
mLabels.push_back(label);
mList.setEntry(Vector2i(0, 6), Vector2i(1, 1), label, false, ComponentGrid::AlignRight);
mList.setEntry(Vector2i(1, 6), Vector2i(1, 1), &mDisableHelpSwitch, true, ComponentGrid::AlignCenter);
// save button // save button
mSaveButton.setText("SAVE", "apply & save", 0x00FF00FF); ComponentListRow row;
mSaveButton.setPressedFunc([this] () { applyStates(); delete this; }); row.addElement(std::make_shared<TextComponent>(mWindow, "SAVE", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
mList.setEntry(Vector2i(0, 7), Vector2i(2, 1), &mSaveButton, true, ComponentGrid::AlignCenter, Matrix<bool, 1, 2>(false, true)); row.makeAcceptInputHandler(std::bind(&GuiSettingsMenu::save, this));
mMenu.addRow(row);
//center list addChild(&mMenu);
mList.setPosition(Renderer::getScreenWidth() / 2 - mList.getSize().x() / 2, Renderer::getScreenHeight() / 2 - mList.getSize().y() / 2);
//set up borders/background
mBox.fitTo(mList.getSize(), mList.getPosition(), Eigen::Vector2f(8, 8));
} }
GuiSettingsMenu::~GuiSettingsMenu() void GuiSettingsMenu::addSetting(const char* label, const std::shared_ptr<GuiComponent>& comp, const std::function<void()>& saveFunc)
{ {
for(auto iter = mLabels.begin(); iter != mLabels.end(); iter++) ComponentListRow row;
{ row.addElement(std::make_shared<TextComponent>(mWindow, label, Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
delete *iter; row.addElement(comp, false);
} mApplyFuncs.push_back(saveFunc);
mMenu.addRow(row);
} }
bool GuiSettingsMenu::input(InputConfig* config, Input input) bool GuiSettingsMenu::input(InputConfig* config, Input input)
@ -125,7 +93,7 @@ bool GuiSettingsMenu::input(InputConfig* config, Input input)
return true; return true;
//cancel if b is pressed //cancel if b is pressed
if(config->isMappedTo("b", input) && input.value) if(config->isMappedTo("b", input) && input.value != 0)
{ {
delete this; delete this;
return true; return true;
@ -134,46 +102,21 @@ bool GuiSettingsMenu::input(InputConfig* config, Input input)
return false; return false;
} }
void GuiSettingsMenu::loadStates() void GuiSettingsMenu::save()
{ {
Settings* s = Settings::getInstance(); LOG(LogInfo) << "saving";
mDrawFramerateSwitch.setState(s->getBool("DRAWFRAMERATE"));
mVolumeSlider.setValue((float)VolumeControl::getInstance()->getVolume()); for(auto it = mApplyFuncs.begin(); it != mApplyFuncs.end(); it++)
(*it)();
mDisableSoundsSwitch.setState(s->getBool("DISABLESOUNDS")); Settings::getInstance()->saveFile();
mScrapeRatingsSwitch.setState(s->getBool("ScrapeRatings")); delete this;
mDimSlider.setValue((float)(s->getInt("DIMTIME") / 1000));
mDisableHelpSwitch.setState(s->getBool("DISABLEHELP"));
}
void GuiSettingsMenu::applyStates()
{
Settings* s = Settings::getInstance();
s->setBool("DRAWFRAMERATE", mDrawFramerateSwitch.getState());
VolumeControl::getInstance()->setVolume((int)mVolumeSlider.getValue());
s->setBool("DISABLESOUNDS", mDisableSoundsSwitch.getState());
if(mScraperOptList.getSelected().size() > 0)
s->setScraper(mScraperOptList.getSelected()[0]->object);
s->setBool("ScrapeRatings", mScrapeRatingsSwitch.getState());
s->setInt("DIMTIME", (int)(mDimSlider.getValue() * 1000));
s->setBool("DISABLEHELP", mDisableHelpSwitch.getState());
s->saveFile();
} }
std::vector<HelpPrompt> GuiSettingsMenu::getHelpPrompts() std::vector<HelpPrompt> GuiSettingsMenu::getHelpPrompts()
{ {
std::vector<HelpPrompt> prompts = mList.getHelpPrompts(); std::vector<HelpPrompt> prompts = mMenu.getHelpPrompts();
prompts.push_back(HelpPrompt("b", "discard changes")); prompts.push_back(HelpPrompt("b", "discard changes"));
return prompts; return prompts;
} }

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "../GuiComponent.h" #include "../GuiComponent.h"
#include "../components/ComponentGrid.h" #include "../components/MenuComponent.h"
#include "../components/SwitchComponent.h" #include "../components/SwitchComponent.h"
#include "../components/SliderComponent.h" #include "../components/SliderComponent.h"
#include "../components/TextComponent.h" #include "../components/TextComponent.h"
@ -14,28 +14,16 @@ class GuiSettingsMenu : public GuiComponent
{ {
public: public:
GuiSettingsMenu(Window* window); GuiSettingsMenu(Window* window);
~GuiSettingsMenu();
bool input(InputConfig* config, Input input) override; bool input(InputConfig* config, Input input) override;
std::vector<HelpPrompt> getHelpPrompts() override; std::vector<HelpPrompt> getHelpPrompts() override;
private: private:
void loadStates(); void addSetting(const char* label, const std::shared_ptr<GuiComponent>& comp, const std::function<void()>& saveFunc);
void applyStates(); void save();
ComponentGrid mList; std::vector< std::function<void()> > mApplyFuncs;
NinePatchComponent mBox; MenuComponent mMenu;
SwitchComponent mDrawFramerateSwitch;
SliderComponent mVolumeSlider;
SwitchComponent mDisableSoundsSwitch;
OptionListComponent< std::shared_ptr<Scraper> > mScraperOptList;
SwitchComponent mScrapeRatingsSwitch;
SliderComponent mDimSlider;
SwitchComponent mDisableHelpSwitch;
ButtonComponent mSaveButton;
std::vector<GuiComponent*> mLabels;
}; };