mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-22 06:05:38 +00:00
Code cleanup and code documentation. Only cosmetic changes in this commit.
This commit is contained in:
parent
b7feedd287
commit
709e6b996e
|
@ -7,7 +7,7 @@
|
|||
// Improved and extended by the RetroPie community.
|
||||
// Desktop Edition fork by Leon Styhre.
|
||||
//
|
||||
// The line length limit is 100 characters.
|
||||
// The line length limit is 100 characters and the tab width is 4 spaces.
|
||||
//
|
||||
// main.cpp
|
||||
//
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// SystemView.cpp
|
||||
//
|
||||
// Main system view.
|
||||
//
|
||||
|
||||
#include "views/SystemView.h"
|
||||
|
||||
#include "animations/LambdaAnimation.h"
|
||||
|
@ -10,13 +16,16 @@
|
|||
#include "Window.h"
|
||||
#include "Sound.h"
|
||||
|
||||
// buffer values for scrolling velocity (left, stopped, right)
|
||||
// Buffer values for scrolling velocity (left, stopped, right).
|
||||
const int logoBuffersLeft[] = { -5, -2, -1 };
|
||||
const int logoBuffersRight[] = { 1, 2, 5 };
|
||||
|
||||
SystemView::SystemView(Window* window) : IList<SystemViewData, SystemData*>(window, LIST_SCROLL_STYLE_SLOW, LIST_ALWAYS_LOOP),
|
||||
mViewNeedsReload(true),
|
||||
mSystemInfo(window, "SYSTEM INFO", Font::get(FONT_SIZE_SMALL), 0x33333300, ALIGN_CENTER)
|
||||
SystemView::SystemView(
|
||||
Window* window)
|
||||
: IList<SystemViewData, SystemData*>
|
||||
(window, LIST_SCROLL_STYLE_SLOW, LIST_ALWAYS_LOOP),
|
||||
mViewNeedsReload(true),
|
||||
mSystemInfo(window, "SYSTEM INFO", Font::get(FONT_SIZE_SMALL), 0x33333300, ALIGN_CENTER)
|
||||
{
|
||||
mCamOffset = 0;
|
||||
mExtrasCamOffset = 0;
|
||||
|
@ -30,28 +39,27 @@ void SystemView::populate()
|
|||
{
|
||||
mEntries.clear();
|
||||
|
||||
for(auto it = SystemData::sSystemVector.cbegin(); it != SystemData::sSystemVector.cend(); it++)
|
||||
{
|
||||
for (auto it = SystemData::sSystemVector.cbegin();
|
||||
it != SystemData::sSystemVector.cend(); it++) {
|
||||
const std::shared_ptr<ThemeData>& theme = (*it)->getTheme();
|
||||
|
||||
if(mViewNeedsReload)
|
||||
if (mViewNeedsReload)
|
||||
getViewElements(theme);
|
||||
|
||||
if((*it)->isVisible())
|
||||
{
|
||||
if ((*it)->isVisible()) {
|
||||
Entry e;
|
||||
e.name = (*it)->getName();
|
||||
e.object = *it;
|
||||
|
||||
// make logo
|
||||
// Make logo.
|
||||
const ThemeData::ThemeElement* logoElem = theme->getElement("system", "logo", "image");
|
||||
if(logoElem)
|
||||
{
|
||||
if (logoElem) {
|
||||
std::string path = logoElem->get<std::string>("path");
|
||||
std::string defaultPath = logoElem->has("default") ? logoElem->get<std::string>("default") : "";
|
||||
if((!path.empty() && ResourceManager::getInstance()->fileExists(path))
|
||||
|| (!defaultPath.empty() && ResourceManager::getInstance()->fileExists(defaultPath)))
|
||||
{
|
||||
std::string defaultPath = logoElem->has("default") ?
|
||||
logoElem->get<std::string>("default") : "";
|
||||
if ((!path.empty() && ResourceManager::getInstance()->fileExists(path)) ||
|
||||
(!defaultPath.empty() &&
|
||||
ResourceManager::getInstance()->fileExists(defaultPath))) {
|
||||
ImageComponent* logo = new ImageComponent(mWindow, false, false);
|
||||
logo->setMaxSize(mCarousel.logoSize * mCarousel.logoScale);
|
||||
logo->applyTheme(theme, "system", "logo", ThemeFlags::PATH | ThemeFlags::COLOR);
|
||||
|
@ -59,37 +67,39 @@ void SystemView::populate()
|
|||
e.data.logo = std::shared_ptr<GuiComponent>(logo);
|
||||
}
|
||||
}
|
||||
if (!e.data.logo)
|
||||
{
|
||||
// no logo in theme; use text
|
||||
TextComponent* text = new TextComponent(mWindow,
|
||||
if (!e.data.logo) {
|
||||
// No logo in theme; use text.
|
||||
TextComponent* text = new TextComponent(
|
||||
mWindow,
|
||||
(*it)->getName(),
|
||||
Font::get(FONT_SIZE_LARGE),
|
||||
0x000000FF,
|
||||
ALIGN_CENTER);
|
||||
text->setSize(mCarousel.logoSize * mCarousel.logoScale);
|
||||
text->applyTheme((*it)->getTheme(), "system", "logoText", ThemeFlags::FONT_PATH | ThemeFlags::FONT_SIZE | ThemeFlags::COLOR | ThemeFlags::FORCE_UPPERCASE | ThemeFlags::LINE_SPACING | ThemeFlags::TEXT);
|
||||
text->applyTheme((*it)->getTheme(), "system", "logoText",
|
||||
ThemeFlags::FONT_PATH | ThemeFlags::FONT_SIZE | ThemeFlags::COLOR |
|
||||
ThemeFlags::FORCE_UPPERCASE | ThemeFlags::LINE_SPACING | ThemeFlags::TEXT);
|
||||
e.data.logo = std::shared_ptr<GuiComponent>(text);
|
||||
|
||||
if (mCarousel.type == VERTICAL || mCarousel.type == VERTICAL_WHEEL)
|
||||
{
|
||||
if (mCarousel.type == VERTICAL || mCarousel.type == VERTICAL_WHEEL) {
|
||||
text->setHorizontalAlignment(mCarousel.logoAlignment);
|
||||
text->setVerticalAlignment(ALIGN_CENTER);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
text->setHorizontalAlignment(ALIGN_CENTER);
|
||||
text->setVerticalAlignment(mCarousel.logoAlignment);
|
||||
}
|
||||
}
|
||||
|
||||
if (mCarousel.type == VERTICAL || mCarousel.type == VERTICAL_WHEEL)
|
||||
{
|
||||
if (mCarousel.type == VERTICAL || mCarousel.type == VERTICAL_WHEEL) {
|
||||
if (mCarousel.logoAlignment == ALIGN_LEFT)
|
||||
e.data.logo->setOrigin(0, 0.5);
|
||||
else if (mCarousel.logoAlignment == ALIGN_RIGHT)
|
||||
e.data.logo->setOrigin(1.0, 0.5);
|
||||
else
|
||||
e.data.logo->setOrigin(0.5, 0.5);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (mCarousel.logoAlignment == ALIGN_TOP)
|
||||
e.data.logo->setOrigin(0.5, 0);
|
||||
else if (mCarousel.logoAlignment == ALIGN_BOTTOM)
|
||||
|
@ -100,29 +110,30 @@ void SystemView::populate()
|
|||
|
||||
Vector2f denormalized = mCarousel.logoSize * e.data.logo->getOrigin();
|
||||
e.data.logo->setPosition(denormalized.x(), denormalized.y(), 0.0);
|
||||
// delete any existing extras
|
||||
// Delete any existing extras.
|
||||
for (auto extra : e.data.backgroundExtras)
|
||||
delete extra;
|
||||
e.data.backgroundExtras.clear();
|
||||
|
||||
// make background extras
|
||||
// Make background extras.
|
||||
e.data.backgroundExtras = ThemeData::makeExtras((*it)->getTheme(), "system", mWindow);
|
||||
|
||||
// sort the extras by z-index
|
||||
std::stable_sort(e.data.backgroundExtras.begin(), e.data.backgroundExtras.end(), [](GuiComponent* a, GuiComponent* b) {
|
||||
// Sort the extras by z-index.
|
||||
std::stable_sort(e.data.backgroundExtras.begin(), e.data.backgroundExtras.end(),
|
||||
[](GuiComponent* a, GuiComponent* b) {
|
||||
return b->getZIndex() > a->getZIndex();
|
||||
});
|
||||
|
||||
this->add(e);
|
||||
}
|
||||
}
|
||||
if (mEntries.size() == 0)
|
||||
{
|
||||
// Something is wrong, there is not a single system to show, check if UI mode is not full
|
||||
if (!UIModeController::getInstance()->isUIModeFull())
|
||||
{
|
||||
if (mEntries.size() == 0) {
|
||||
// Something is wrong, there is not a single system to show, check if UI mode is not full.
|
||||
if (!UIModeController::getInstance()->isUIModeFull()) {
|
||||
Settings::getInstance()->setString("UIMode", "Full");
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, "The selected UI mode has nothing to show,\n returning to UI mode: FULL", "OK", nullptr));
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow,
|
||||
"The selected UI mode has nothing to show,\n returning to UI mode: FULL", "OK",
|
||||
nullptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +142,7 @@ void SystemView::goToSystem(SystemData* system, bool animate)
|
|||
{
|
||||
setCursor(system);
|
||||
|
||||
if(!animate)
|
||||
if (!animate)
|
||||
finishAnimation(0);
|
||||
}
|
||||
|
||||
|
@ -140,27 +151,23 @@ bool SystemView::input(InputConfig* config, Input input)
|
|||
auto it = SystemData::sSystemVector.cbegin();
|
||||
const std::shared_ptr<ThemeData>& theme = (*it)->getTheme();
|
||||
|
||||
if(input.value != 0)
|
||||
{
|
||||
if(config->getDeviceId() == DEVICE_KEYBOARD && input.value && input.id == SDLK_r && SDL_GetModState() & KMOD_LCTRL && Settings::getInstance()->getBool("Debug"))
|
||||
{
|
||||
if (input.value != 0) {
|
||||
if (config->getDeviceId() == DEVICE_KEYBOARD && input.value && input.id == SDLK_r &&
|
||||
SDL_GetModState() & KMOD_LCTRL && Settings::getInstance()->getBool("Debug")) {
|
||||
LOG(LogInfo) << " Reloading all";
|
||||
ViewController::get()->reloadAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (mCarousel.type)
|
||||
{
|
||||
switch (mCarousel.type) {
|
||||
case VERTICAL:
|
||||
case VERTICAL_WHEEL:
|
||||
if (config->isMappedLike("up", input))
|
||||
{
|
||||
if (config->isMappedLike("up", input)) {
|
||||
NavigationSounds::getInstance()->playThemeNavigationSound(SYSTEMBROWSESOUND);
|
||||
listInput(-1);
|
||||
return true;
|
||||
}
|
||||
if (config->isMappedLike("down", input))
|
||||
{
|
||||
if (config->isMappedLike("down", input)) {
|
||||
NavigationSounds::getInstance()->playThemeNavigationSound(SYSTEMBROWSESOUND);
|
||||
listInput(1);
|
||||
return true;
|
||||
|
@ -169,14 +176,12 @@ bool SystemView::input(InputConfig* config, Input input)
|
|||
case HORIZONTAL:
|
||||
case HORIZONTAL_WHEEL:
|
||||
default:
|
||||
if (config->isMappedLike("left", input))
|
||||
{
|
||||
if (config->isMappedLike("left", input)) {
|
||||
NavigationSounds::getInstance()->playThemeNavigationSound(SYSTEMBROWSESOUND);
|
||||
listInput(-1);
|
||||
return true;
|
||||
}
|
||||
if (config->isMappedLike("right", input))
|
||||
{
|
||||
if (config->isMappedLike("right", input)) {
|
||||
NavigationSounds::getInstance()->playThemeNavigationSound(SYSTEMBROWSESOUND);
|
||||
listInput(1);
|
||||
return true;
|
||||
|
@ -184,29 +189,29 @@ bool SystemView::input(InputConfig* config, Input input)
|
|||
break;
|
||||
}
|
||||
|
||||
if(config->isMappedTo("a", input))
|
||||
{
|
||||
if (config->isMappedTo("a", input)) {
|
||||
stopScrolling();
|
||||
ViewController::get()->goToGameList(getSelected());
|
||||
NavigationSounds::getInstance()->playThemeNavigationSound(SELECTSOUND);
|
||||
return true;
|
||||
}
|
||||
if (config->isMappedTo("x", input))
|
||||
{
|
||||
// get random system
|
||||
// go to system
|
||||
if (config->isMappedTo("x", input)) {
|
||||
// Get random system.
|
||||
// Go to system.
|
||||
NavigationSounds::getInstance()->playThemeNavigationSound(SYSTEMBROWSESOUND);
|
||||
setCursor(SystemData::getRandomSystem());
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
if(config->isMappedLike("left", input) ||
|
||||
}
|
||||
else {
|
||||
if (config->isMappedLike("left", input) ||
|
||||
config->isMappedLike("right", input) ||
|
||||
config->isMappedLike("up", input) ||
|
||||
config->isMappedLike("down", input))
|
||||
listInput(0);
|
||||
if(!UIModeController::getInstance()->isUIModeKid() && config->isMappedTo("select", input) && Settings::getInstance()->getBool("ScreenSaverControls"))
|
||||
{
|
||||
if (!UIModeController::getInstance()->isUIModeKid() &&
|
||||
config->isMappedTo("select", input) &&
|
||||
Settings::getInstance()->getBool("ScreenSaverControls")) {
|
||||
mWindow->startScreenSaver();
|
||||
mWindow->renderScreenSaver();
|
||||
return true;
|
||||
|
@ -224,7 +229,7 @@ void SystemView::update(int deltaTime)
|
|||
|
||||
void SystemView::onCursorChanged(const CursorState& /*state*/)
|
||||
{
|
||||
// update help style
|
||||
// Update help style.
|
||||
updateHelpPrompts();
|
||||
|
||||
float startPos = mCamOffset;
|
||||
|
@ -232,18 +237,18 @@ void SystemView::onCursorChanged(const CursorState& /*state*/)
|
|||
float posMax = (float)mEntries.size();
|
||||
float target = (float)mCursor;
|
||||
|
||||
// what's the shortest way to get to our target?
|
||||
// it's one of these...
|
||||
// What's the shortest way to get to our target?
|
||||
// It's one of these...
|
||||
|
||||
float endPos = target; // directly
|
||||
float endPos = target; // Directly.
|
||||
float dist = abs(endPos - startPos);
|
||||
|
||||
if(abs(target + posMax - startPos) < dist)
|
||||
endPos = target + posMax; // loop around the end (0 -> max)
|
||||
if(abs(target - posMax - startPos) < dist)
|
||||
endPos = target - posMax; // loop around the start (max - 1 -> -1)
|
||||
if (abs(target + posMax - startPos) < dist)
|
||||
endPos = target + posMax; // Loop around the end (0 -> max).
|
||||
if (abs(target - posMax - startPos) < dist)
|
||||
endPos = target - posMax; // Loop around the start (max - 1 -> -1).
|
||||
|
||||
// animate mSystemInfo's opacity (fade out, wait, fade back in)
|
||||
// Animate mSystemInfo's opacity (fade out, wait, fade back in).
|
||||
|
||||
cancelAnimation(1);
|
||||
cancelAnimation(2);
|
||||
|
@ -253,14 +258,13 @@ void SystemView::onCursorChanged(const CursorState& /*state*/)
|
|||
const float infoStartOpacity = mSystemInfo.getOpacity() / 255.f;
|
||||
|
||||
Animation* infoFadeOut = new LambdaAnimation(
|
||||
[infoStartOpacity, this] (float t)
|
||||
{
|
||||
[infoStartOpacity, this] (float t) {
|
||||
mSystemInfo.setOpacity((unsigned char)(Math::lerp(infoStartOpacity, 0.f, t) * 255));
|
||||
}, (int)(infoStartOpacity * (goFast ? 10 : 150)));
|
||||
|
||||
unsigned int gameCount = getSelected()->getDisplayedGameCount();
|
||||
|
||||
// also change the text after we've fully faded out
|
||||
// Also change the text after we've fully faded out.
|
||||
setAnimation(infoFadeOut, 0, [this, gameCount] {
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -273,72 +277,69 @@ void SystemView::onCursorChanged(const CursorState& /*state*/)
|
|||
}, false, 1);
|
||||
|
||||
Animation* infoFadeIn = new LambdaAnimation(
|
||||
[this](float t)
|
||||
{
|
||||
[this](float t) {
|
||||
mSystemInfo.setOpacity((unsigned char)(Math::lerp(0.f, 1.f, t) * 255));
|
||||
}, goFast ? 10 : 300);
|
||||
|
||||
// wait 600ms to fade in
|
||||
// Wait 600ms to fade in.
|
||||
setAnimation(infoFadeIn, goFast ? 0 : 2000, nullptr, false, 2);
|
||||
|
||||
// no need to animate transition, we're not going anywhere (probably mEntries.size() == 1)
|
||||
if(endPos == mCamOffset && endPos == mExtrasCamOffset)
|
||||
// No need to animate transition, we're not going anywhere (probably mEntries.size() == 1).
|
||||
if (endPos == mCamOffset && endPos == mExtrasCamOffset)
|
||||
return;
|
||||
|
||||
Animation* anim;
|
||||
bool move_carousel = Settings::getInstance()->getBool("MoveCarousel");
|
||||
if(transition_style == "fade")
|
||||
{
|
||||
if (transition_style == "fade") {
|
||||
float startExtrasFade = mExtrasFadeOpacity;
|
||||
anim = new LambdaAnimation(
|
||||
[this, startExtrasFade, startPos, endPos, posMax, move_carousel](float t)
|
||||
{
|
||||
[this, startExtrasFade, startPos, endPos, posMax, move_carousel](float t) {
|
||||
t -= 1;
|
||||
float f = Math::lerp(startPos, endPos, t*t*t + 1);
|
||||
if(f < 0)
|
||||
if (f < 0)
|
||||
f += posMax;
|
||||
if(f >= posMax)
|
||||
if (f >= posMax)
|
||||
f -= posMax;
|
||||
|
||||
this->mCamOffset = move_carousel ? f : endPos;
|
||||
|
||||
t += 1;
|
||||
if(t < 0.3f)
|
||||
if (t < 0.3f)
|
||||
this->mExtrasFadeOpacity = Math::lerp(0.0f, 1.0f, t / 0.3f + startExtrasFade);
|
||||
else if(t < 0.7f)
|
||||
else if (t < 0.7f)
|
||||
this->mExtrasFadeOpacity = 1.0f;
|
||||
else
|
||||
this->mExtrasFadeOpacity = Math::lerp(1.0f, 0.0f, (t - 0.7f) / 0.3f);
|
||||
|
||||
if(t > 0.5f)
|
||||
if (t > 0.5f)
|
||||
this->mExtrasCamOffset = endPos;
|
||||
|
||||
}, 500);
|
||||
} else if (transition_style == "slide") {
|
||||
// slide
|
||||
}
|
||||
else if (transition_style == "slide") {
|
||||
// Slide.
|
||||
anim = new LambdaAnimation(
|
||||
[this, startPos, endPos, posMax, move_carousel](float t)
|
||||
{
|
||||
[this, startPos, endPos, posMax, move_carousel](float t) {
|
||||
t -= 1;
|
||||
float f = Math::lerp(startPos, endPos, t*t*t + 1);
|
||||
if(f < 0)
|
||||
if (f < 0)
|
||||
f += posMax;
|
||||
if(f >= posMax)
|
||||
if (f >= posMax)
|
||||
f -= posMax;
|
||||
|
||||
this->mCamOffset = move_carousel ? f : endPos;
|
||||
this->mExtrasCamOffset = f;
|
||||
}, 500);
|
||||
} else {
|
||||
// instant
|
||||
}
|
||||
else {
|
||||
// Instant.
|
||||
anim = new LambdaAnimation(
|
||||
[this, startPos, endPos, posMax, move_carousel ](float t)
|
||||
{
|
||||
[this, startPos, endPos, posMax, move_carousel ](float t) {
|
||||
t -= 1;
|
||||
float f = Math::lerp(startPos, endPos, t*t*t + 1);
|
||||
if(f < 0)
|
||||
if (f < 0)
|
||||
f += posMax;
|
||||
if(f >= posMax)
|
||||
if (f >= posMax)
|
||||
f -= posMax;
|
||||
|
||||
this->mCamOffset = move_carousel ? f : endPos;
|
||||
|
@ -346,14 +347,13 @@ void SystemView::onCursorChanged(const CursorState& /*state*/)
|
|||
}, move_carousel ? 500 : 1);
|
||||
}
|
||||
|
||||
|
||||
setAnimation(anim, 0, nullptr, false, 0);
|
||||
}
|
||||
|
||||
void SystemView::render(const Transform4x4f& parentTrans)
|
||||
{
|
||||
if(size() == 0)
|
||||
return; // nothing to render
|
||||
if (size() == 0)
|
||||
return; // Nothing to render.
|
||||
|
||||
Transform4x4f trans = getTransform() * parentTrans;
|
||||
|
||||
|
@ -365,7 +365,8 @@ void SystemView::render(const Transform4x4f& parentTrans)
|
|||
|
||||
if (mCarousel.zIndex > mSystemInfo.getZIndex()) {
|
||||
renderInfoBar(trans);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
renderCarousel(trans);
|
||||
}
|
||||
|
||||
|
@ -373,7 +374,8 @@ void SystemView::render(const Transform4x4f& parentTrans)
|
|||
|
||||
if (mCarousel.zIndex > mSystemInfo.getZIndex()) {
|
||||
renderCarousel(trans);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
renderInfoBar(trans);
|
||||
}
|
||||
|
||||
|
@ -390,7 +392,8 @@ std::vector<HelpPrompt> SystemView::getHelpPrompts()
|
|||
prompts.push_back(HelpPrompt("a", "select"));
|
||||
prompts.push_back(HelpPrompt("x", "random"));
|
||||
|
||||
if (!UIModeController::getInstance()->isUIModeKid() && Settings::getInstance()->getBool("ScreenSaverControls"))
|
||||
if (!UIModeController::getInstance()->isUIModeKid() &&
|
||||
Settings::getInstance()->getBool("ScreenSaverControls"))
|
||||
prompts.push_back(HelpPrompt("select", "launch screensaver"));
|
||||
|
||||
return prompts;
|
||||
|
@ -420,40 +423,46 @@ void SystemView::getViewElements(const std::shared_ptr<ThemeData>& theme)
|
|||
if (!theme->hasView("system"))
|
||||
return;
|
||||
|
||||
const ThemeData::ThemeElement* carouselElem = theme->getElement("system", "systemcarousel", "carousel");
|
||||
const ThemeData::ThemeElement* carouselElem = theme->
|
||||
getElement("system", "systemcarousel", "carousel");
|
||||
if (carouselElem)
|
||||
getCarouselFromTheme(carouselElem);
|
||||
|
||||
const ThemeData::ThemeElement* sysInfoElem = theme->getElement("system", "systemInfo", "text");
|
||||
const ThemeData::ThemeElement* sysInfoElem = theme->
|
||||
getElement("system", "systemInfo", "text");
|
||||
if (sysInfoElem)
|
||||
mSystemInfo.applyTheme(theme, "system", "systemInfo", ThemeFlags::ALL);
|
||||
|
||||
mViewNeedsReload = false;
|
||||
}
|
||||
|
||||
// Render system carousel
|
||||
// Render system carousel.
|
||||
void SystemView::renderCarousel(const Transform4x4f& trans)
|
||||
{
|
||||
// background box behind logos
|
||||
// Background box behind logos.
|
||||
Transform4x4f carouselTrans = trans;
|
||||
carouselTrans.translate(Vector3f(mCarousel.pos.x(), mCarousel.pos.y(), 0.0));
|
||||
carouselTrans.translate(Vector3f(mCarousel.origin.x() * mCarousel.size.x() * -1, mCarousel.origin.y() * mCarousel.size.y() * -1, 0.0f));
|
||||
carouselTrans.translate(Vector3f(mCarousel.origin.x() * mCarousel.size.x() * -1,
|
||||
mCarousel.origin.y() * mCarousel.size.y() * -1, 0.0f));
|
||||
|
||||
Vector2f clipPos(carouselTrans.translation().x(), carouselTrans.translation().y());
|
||||
Renderer::pushClipRect(Vector2i((int)clipPos.x(), (int)clipPos.y()), Vector2i((int)mCarousel.size.x(), (int)mCarousel.size.y()));
|
||||
Renderer::pushClipRect(Vector2i((int)clipPos.x(), (int)clipPos.y()),
|
||||
Vector2i((int)mCarousel.size.x(), (int)mCarousel.size.y()));
|
||||
|
||||
Renderer::setMatrix(carouselTrans);
|
||||
Renderer::drawRect(0.0f, 0.0f, mCarousel.size.x(), mCarousel.size.y(), mCarousel.color, mCarousel.colorEnd, mCarousel.colorGradientHorizontal);
|
||||
Renderer::drawRect(0.0f, 0.0f, mCarousel.size.x(), mCarousel.size.y(),
|
||||
mCarousel.color, mCarousel.colorEnd, mCarousel.colorGradientHorizontal);
|
||||
|
||||
// draw logos
|
||||
Vector2f logoSpacing(0.0, 0.0); // NB: logoSpacing will include the size of the logo itself as well!
|
||||
// Draw logos.
|
||||
// NB: logoSpacing will also include the size of the logo itself!
|
||||
Vector2f logoSpacing(0.0, 0.0);
|
||||
float xOff = 0.0;
|
||||
float yOff = 0.0;
|
||||
|
||||
switch (mCarousel.type)
|
||||
{
|
||||
switch (mCarousel.type) {
|
||||
case VERTICAL_WHEEL:
|
||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.f - (mCamOffset * logoSpacing[1]);
|
||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.f -
|
||||
(mCamOffset * logoSpacing[1]);
|
||||
if (mCarousel.logoAlignment == ALIGN_LEFT)
|
||||
xOff = mCarousel.logoSize.x() / 10.f;
|
||||
else if (mCarousel.logoAlignment == ALIGN_RIGHT)
|
||||
|
@ -462,8 +471,10 @@ void SystemView::renderCarousel(const Transform4x4f& trans)
|
|||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2.f;
|
||||
break;
|
||||
case VERTICAL:
|
||||
logoSpacing[1] = ((mCarousel.size.y() - (mCarousel.logoSize.y() * mCarousel.maxLogoCount)) / (mCarousel.maxLogoCount)) + mCarousel.logoSize.y();
|
||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.f - (mCamOffset * logoSpacing[1]);
|
||||
logoSpacing[1] = ((mCarousel.size.y() - (mCarousel.logoSize.y() *
|
||||
mCarousel.maxLogoCount)) / (mCarousel.maxLogoCount)) + mCarousel.logoSize.y();
|
||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.f -
|
||||
(mCamOffset * logoSpacing[1]);
|
||||
|
||||
if (mCarousel.logoAlignment == ALIGN_LEFT)
|
||||
xOff = mCarousel.logoSize.x() / 10.f;
|
||||
|
@ -473,7 +484,8 @@ void SystemView::renderCarousel(const Transform4x4f& trans)
|
|||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2;
|
||||
break;
|
||||
case HORIZONTAL_WHEEL:
|
||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2 - (mCamOffset * logoSpacing[1]);
|
||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2 -
|
||||
(mCamOffset * logoSpacing[1]);
|
||||
if (mCarousel.logoAlignment == ALIGN_TOP)
|
||||
yOff = mCarousel.logoSize.y() / 10;
|
||||
else if (mCarousel.logoAlignment == ALIGN_BOTTOM)
|
||||
|
@ -483,8 +495,10 @@ void SystemView::renderCarousel(const Transform4x4f& trans)
|
|||
break;
|
||||
case HORIZONTAL:
|
||||
default:
|
||||
logoSpacing[0] = ((mCarousel.size.x() - (mCarousel.logoSize.x() * mCarousel.maxLogoCount)) / (mCarousel.maxLogoCount)) + mCarousel.logoSize.x();
|
||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2.f - (mCamOffset * logoSpacing[0]);
|
||||
logoSpacing[0] = ((mCarousel.size.x() - (mCarousel.logoSize.x() *
|
||||
mCarousel.maxLogoCount)) / (mCarousel.maxLogoCount)) + mCarousel.logoSize.x();
|
||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2.f -
|
||||
(mCamOffset * logoSpacing[0]);
|
||||
|
||||
if (mCarousel.logoAlignment == ALIGN_TOP)
|
||||
yOff = mCarousel.logoSize.y() / 10.f;
|
||||
|
@ -498,18 +512,17 @@ void SystemView::renderCarousel(const Transform4x4f& trans)
|
|||
int center = (int)(mCamOffset);
|
||||
int logoCount = Math::min(mCarousel.maxLogoCount, (int)mEntries.size());
|
||||
|
||||
// Adding texture loading buffers depending on scrolling speed and status
|
||||
// Adding texture loading buffers depending on scrolling speed and status.
|
||||
int bufferIndex = getScrollingVelocity() + 1;
|
||||
int bufferLeft = logoBuffersLeft[bufferIndex];
|
||||
int bufferRight = logoBuffersRight[bufferIndex];
|
||||
if (logoCount == 1)
|
||||
{
|
||||
if (logoCount == 1) {
|
||||
bufferLeft = 0;
|
||||
bufferRight = 0;
|
||||
}
|
||||
|
||||
for (int i = center - logoCount / 2 + bufferLeft; i <= center + logoCount / 2 + bufferRight; i++)
|
||||
{
|
||||
for (int i = center - logoCount / 2 + bufferLeft;
|
||||
i <= center + logoCount / 2 + bufferRight; i++) {
|
||||
int index = i;
|
||||
while (index < 0)
|
||||
index += (int)mEntries.size();
|
||||
|
@ -546,25 +559,25 @@ void SystemView::renderInfoBar(const Transform4x4f& trans)
|
|||
mSystemInfo.render(trans);
|
||||
}
|
||||
|
||||
// Draw background extras
|
||||
// Draw background extras.
|
||||
void SystemView::renderExtras(const Transform4x4f& trans, float lower, float upper)
|
||||
{
|
||||
int extrasCenter = (int)mExtrasCamOffset;
|
||||
|
||||
// Adding texture loading buffers depending on scrolling speed and status
|
||||
// Adding texture loading buffers depending on scrolling speed and status.
|
||||
int bufferIndex = getScrollingVelocity() + 1;
|
||||
|
||||
Renderer::pushClipRect(Vector2i::Zero(), Vector2i((int)mSize.x(), (int)mSize.y()));
|
||||
|
||||
for (int i = extrasCenter + logoBuffersLeft[bufferIndex]; i <= extrasCenter + logoBuffersRight[bufferIndex]; i++)
|
||||
{
|
||||
for (int i = extrasCenter + logoBuffersLeft[bufferIndex]; i <= extrasCenter +
|
||||
logoBuffersRight[bufferIndex]; i++) {
|
||||
int index = i;
|
||||
while (index < 0)
|
||||
index += (int)mEntries.size();
|
||||
while (index >= (int)mEntries.size())
|
||||
index -= (int)mEntries.size();
|
||||
|
||||
//Only render selected system when not showing
|
||||
// Only render selected system when not showing.
|
||||
if (mShowing || index == mCursor)
|
||||
{
|
||||
Transform4x4f extrasTrans = trans;
|
||||
|
@ -573,8 +586,9 @@ void SystemView::renderExtras(const Transform4x4f& trans, float lower, float upp
|
|||
else
|
||||
extrasTrans.translate(Vector3f(0, (i - mExtrasCamOffset) * mSize.y(), 0));
|
||||
|
||||
Renderer::pushClipRect(Vector2i((int)extrasTrans.translation()[0], (int)extrasTrans.translation()[1]),
|
||||
Vector2i((int)mSize.x(), (int)mSize.y()));
|
||||
Renderer::pushClipRect(Vector2i((int)extrasTrans.translation()[0],
|
||||
(int)extrasTrans.translation()[1]),
|
||||
Vector2i((int)mSize.x(), (int)mSize.y()));
|
||||
SystemViewData data = mEntries.at(index).data;
|
||||
for (unsigned int j = 0; j < data.backgroundExtras.size(); j++) {
|
||||
GuiComponent *extra = data.backgroundExtras[j];
|
||||
|
@ -590,19 +604,18 @@ void SystemView::renderExtras(const Transform4x4f& trans, float lower, float upp
|
|||
|
||||
void SystemView::renderFade(const Transform4x4f& trans)
|
||||
{
|
||||
// fade extras if necessary
|
||||
if (mExtrasFadeOpacity)
|
||||
{
|
||||
// Fade extras if necessary.
|
||||
if (mExtrasFadeOpacity) {
|
||||
unsigned int fadeColor = 0x00000000 | (unsigned char)(mExtrasFadeOpacity * 255);
|
||||
Renderer::setMatrix(trans);
|
||||
Renderer::drawRect(0.0f, 0.0f, mSize.x(), mSize.y(), fadeColor, fadeColor);
|
||||
}
|
||||
}
|
||||
|
||||
// Populate the system carousel with the legacy values
|
||||
// Populate the system carousel with the legacy values.
|
||||
void SystemView::getDefaultElements(void)
|
||||
{
|
||||
// Carousel
|
||||
// Carousel.
|
||||
mCarousel.type = HORIZONTAL;
|
||||
mCarousel.logoAlignment = ALIGN_CENTER;
|
||||
mCarousel.size.x() = mSize.x();
|
||||
|
@ -623,7 +636,7 @@ void SystemView::getDefaultElements(void)
|
|||
mCarousel.maxLogoCount = 3;
|
||||
mCarousel.zIndex = 40;
|
||||
|
||||
// System Info Bar
|
||||
// System Info Bar.
|
||||
mSystemInfo.setSize(mSize.x(), mSystemInfo.getFont()->getLetterHeight()*2.2f);
|
||||
mSystemInfo.setPosition(0, (mCarousel.pos.y() + mCarousel.size.y() - 0.2f));
|
||||
mSystemInfo.setBackgroundColor(0xDDDDDDD8);
|
||||
|
@ -636,8 +649,7 @@ void SystemView::getDefaultElements(void)
|
|||
|
||||
void SystemView::getCarouselFromTheme(const ThemeData::ThemeElement* elem)
|
||||
{
|
||||
if (elem->has("type"))
|
||||
{
|
||||
if (elem->has("type")) {
|
||||
if (!(elem->get<std::string>("type").compare("vertical")))
|
||||
mCarousel.type = VERTICAL;
|
||||
else if (!(elem->get<std::string>("type").compare("vertical_wheel")))
|
||||
|
@ -653,8 +665,7 @@ void SystemView::getCarouselFromTheme(const ThemeData::ThemeElement* elem)
|
|||
mCarousel.pos = elem->get<Vector2f>("pos") * mSize;
|
||||
if (elem->has("origin"))
|
||||
mCarousel.origin = elem->get<Vector2f>("origin");
|
||||
if (elem->has("color"))
|
||||
{
|
||||
if (elem->has("color")) {
|
||||
mCarousel.color = elem->get<unsigned int>("color");
|
||||
mCarousel.colorEnd = mCarousel.color;
|
||||
}
|
||||
|
@ -674,8 +685,7 @@ void SystemView::getCarouselFromTheme(const ThemeData::ThemeElement* elem)
|
|||
mCarousel.logoRotation = elem->get<float>("logoRotation");
|
||||
if (elem->has("logoRotationOrigin"))
|
||||
mCarousel.logoRotationOrigin = elem->get<Vector2f>("logoRotationOrigin");
|
||||
if (elem->has("logoAlignment"))
|
||||
{
|
||||
if (elem->has("logoAlignment")) {
|
||||
if (!(elem->get<std::string>("logoAlignment").compare("left")))
|
||||
mCarousel.logoAlignment = ALIGN_LEFT;
|
||||
else if (!(elem->get<std::string>("logoAlignment").compare("right")))
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// SystemView.h
|
||||
//
|
||||
// Main system view.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_APP_VIEWS_SYSTEM_VIEW_H
|
||||
#define ES_APP_VIEWS_SYSTEM_VIEW_H
|
||||
|
@ -11,22 +17,19 @@
|
|||
class AnimatedImageComponent;
|
||||
class SystemData;
|
||||
|
||||
enum CarouselType : unsigned int
|
||||
{
|
||||
enum CarouselType : unsigned int {
|
||||
HORIZONTAL = 0,
|
||||
VERTICAL = 1,
|
||||
VERTICAL_WHEEL = 2,
|
||||
HORIZONTAL_WHEEL = 3
|
||||
};
|
||||
|
||||
struct SystemViewData
|
||||
{
|
||||
struct SystemViewData {
|
||||
std::shared_ptr<GuiComponent> logo;
|
||||
std::vector<GuiComponent*> backgroundExtras;
|
||||
};
|
||||
|
||||
struct SystemViewCarousel
|
||||
{
|
||||
struct SystemViewCarousel {
|
||||
CarouselType type;
|
||||
Vector2f pos;
|
||||
Vector2f size;
|
||||
|
@ -38,7 +41,7 @@ struct SystemViewCarousel
|
|||
unsigned int color;
|
||||
unsigned int colorEnd;
|
||||
bool colorGradientHorizontal;
|
||||
int maxLogoCount; // number of logos shown on the carousel
|
||||
int maxLogoCount; // Number of logos shown on the carousel.
|
||||
Vector2f logoSize;
|
||||
float zIndex;
|
||||
};
|
||||
|
@ -79,7 +82,7 @@ private:
|
|||
SystemViewCarousel mCarousel;
|
||||
TextComponent mSystemInfo;
|
||||
|
||||
// unit is list index
|
||||
// Unit is list index.
|
||||
float mCamOffset;
|
||||
float mExtrasCamOffset;
|
||||
float mExtrasFadeOpacity;
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
//
|
||||
// UIModeController.cpp
|
||||
//
|
||||
// Handling of application user interface modes (full, kiosk and kid).
|
||||
// This includes switching the mode when the UI mode passkey was used.
|
||||
//
|
||||
|
||||
#include "UIModeController.h"
|
||||
|
||||
#include "utils/StringUtil.h"
|
||||
|
@ -25,8 +32,8 @@ UIModeController::UIModeController()
|
|||
void UIModeController::monitorUIMode()
|
||||
{
|
||||
std::string uimode = Settings::getInstance()->getString("UIMode");
|
||||
if (uimode != mCurrentUIMode) // UIMODE HAS CHANGED
|
||||
{
|
||||
// UI mode was changed.
|
||||
if (uimode != mCurrentUIMode) {
|
||||
mCurrentUIMode = uimode;
|
||||
ViewController::get()->ReloadAndGoToStart();
|
||||
}
|
||||
|
@ -34,26 +41,18 @@ void UIModeController::monitorUIMode()
|
|||
|
||||
bool UIModeController::listen(InputConfig * config, Input input)
|
||||
{
|
||||
// Reads the current input to listen for the passkey
|
||||
// sequence to unlock the UI mode. The progress is saved in mPassKeyCounter
|
||||
// Reads the current input to listen for the passkey sequence to unlock
|
||||
// the UI mode. The progress is saved in mPassKeyCounter.
|
||||
if (Settings::getInstance()->getBool("Debug"))
|
||||
{
|
||||
logInput(config, input);
|
||||
}
|
||||
|
||||
if ((Settings::getInstance()->getString("UIMode") == "Full") || !isValidInput(config, input))
|
||||
{
|
||||
return false; // Already unlocked, or invalid input, nothing to do here.
|
||||
}
|
||||
|
||||
|
||||
if (!inputIsMatch(config, input))
|
||||
{
|
||||
mPassKeyCounter = 0; // current input is incorrect, reset counter
|
||||
}
|
||||
mPassKeyCounter = 0; // Current input is incorrect, reset counter.
|
||||
|
||||
if (mPassKeyCounter == (int)mPassKeySequence.length())
|
||||
{
|
||||
if (mPassKeyCounter == (int)mPassKeySequence.length()) {
|
||||
unlockUIMode();
|
||||
return true;
|
||||
}
|
||||
|
@ -62,11 +61,9 @@ bool UIModeController::listen(InputConfig * config, Input input)
|
|||
|
||||
bool UIModeController::inputIsMatch(InputConfig * config, Input input)
|
||||
{
|
||||
for (auto valstring : mInputVals)
|
||||
{
|
||||
for (auto valstring : mInputVals) {
|
||||
if (config->isMappedLike(valstring, input) &&
|
||||
(mPassKeySequence[mPassKeyCounter] == valstring[0]))
|
||||
{
|
||||
(mPassKeySequence[mPassKeyCounter] == valstring[0])) {
|
||||
mPassKeyCounter++;
|
||||
return true;
|
||||
}
|
||||
|
@ -74,10 +71,11 @@ bool UIModeController::inputIsMatch(InputConfig * config, Input input)
|
|||
return false;
|
||||
}
|
||||
|
||||
// When we have reached the end of the list, trigger UI_mode unlock
|
||||
// When we have reached the end of the list, trigger UI_mode unlock.
|
||||
void UIModeController::unlockUIMode()
|
||||
{
|
||||
LOG(LogDebug) << " UIModeController::listen(): Passkey sequence completed, switching UIMode to full";
|
||||
LOG(LogDebug) <<
|
||||
" UIModeController::listen(): Passkey sequence completed, switching UIMode to full";
|
||||
Settings::getInstance()->setString("UIMode", "Full");
|
||||
Settings::getInstance()->saveFile();
|
||||
mPassKeyCounter = 0;
|
||||
|
@ -102,26 +100,24 @@ bool UIModeController::isUIModeKiosk()
|
|||
|
||||
std::string UIModeController::getFormattedPassKeyStr()
|
||||
{
|
||||
// supported sequence-inputs: u (up), d (down), l (left), r (right), a, b, x, y
|
||||
// Supported sequence-inputs: u (up), d (down), l (left), r (right), a, b, x, y.
|
||||
|
||||
std::string out = "";
|
||||
for (auto c : mPassKeySequence)
|
||||
{
|
||||
out += (out == "") ? "" : ", "; // add a comma after the first entry
|
||||
for (auto c : mPassKeySequence) {
|
||||
out += (out == "") ? "" : ", "; // Add a comma after the first entry.
|
||||
|
||||
switch (c)
|
||||
{
|
||||
switch (c) {
|
||||
case 'u':
|
||||
out += Utils::String::unicode2Chars(0x2191); // arrow pointing up
|
||||
out += Utils::String::unicode2Chars(0x2191); // Arrow pointing up.
|
||||
break;
|
||||
case 'd':
|
||||
out += Utils::String::unicode2Chars(0x2193); // arrow pointing down
|
||||
out += Utils::String::unicode2Chars(0x2193); // Arrow pointing down.
|
||||
break;
|
||||
case 'l':
|
||||
out += Utils::String::unicode2Chars(0x2190); // arrow pointing left
|
||||
out += Utils::String::unicode2Chars(0x2190); // Arrow pointing left.
|
||||
break;
|
||||
case 'r':
|
||||
out += Utils::String::unicode2Chars(0x2192); // arrow pointing right
|
||||
out += Utils::String::unicode2Chars(0x2192); // Arrow pointing right.
|
||||
break;
|
||||
case 'a':
|
||||
out += "A";
|
||||
|
@ -140,29 +136,26 @@ std::string UIModeController::getFormattedPassKeyStr()
|
|||
return out;
|
||||
}
|
||||
|
||||
|
||||
void UIModeController::logInput(InputConfig * config, Input input)
|
||||
{
|
||||
std::string mapname = "";
|
||||
std::vector<std::string> maps = config->getMappedTo(input);
|
||||
for( auto mn : maps)
|
||||
{
|
||||
|
||||
for (auto mn : maps) {
|
||||
mapname += mn;
|
||||
mapname += ", ";
|
||||
}
|
||||
LOG(LogDebug) << "UIModeController::logInput( " << config->getDeviceName() <<" ):" << input.string() << ", isMappedTo= " << mapname << ", value=" << input.value;
|
||||
|
||||
LOG(LogDebug) << "UIModeController::logInput( " << config->getDeviceName() <<
|
||||
" ):" << input.string() << ", isMappedTo= " << mapname << ", value=" << input.value;
|
||||
}
|
||||
|
||||
bool UIModeController::isValidInput(InputConfig * config, Input input)
|
||||
{
|
||||
if((config->getMappedTo(input).size() == 0) || // not a mapped input, so ignore.
|
||||
(input.type == TYPE_HAT) || // ignore all HAT inputs
|
||||
(!input.value)) // not a key-down event
|
||||
{
|
||||
if ((config->getMappedTo(input).size() == 0) || // Not a mapped input, so ignore..
|
||||
(input.type == TYPE_HAT) || // Ignore all hat inputs.
|
||||
(!input.value)) // Not a key-down event.
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
//
|
||||
// UIModeController.h
|
||||
//
|
||||
// Handling of application user interface modes (full, kiosk and kid).
|
||||
// This includes switching the mode when the UI mode passkey was used.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_APP_VIEWS_UI_MODE_CONTROLLER_H
|
||||
#define ES_APP_VIEWS_UI_MODE_CONTROLLER_H
|
||||
|
@ -11,11 +18,13 @@ class ViewController;
|
|||
|
||||
struct Input;
|
||||
|
||||
class UIModeController {
|
||||
class UIModeController
|
||||
{
|
||||
public:
|
||||
static UIModeController* getInstance();
|
||||
|
||||
// Monitor input for UI mode change, returns true (consumes input) when UI mode change is triggered.
|
||||
// Monitor input for UI mode change, returns true (consumes input) when a UI mode
|
||||
// change is triggered.
|
||||
bool listen(InputConfig* config, Input input);
|
||||
|
||||
// Get the current Passphrase as a (unicode) formatted, comma-separated, string.
|
||||
|
@ -28,22 +37,24 @@ public:
|
|||
bool isUIModeKid();
|
||||
bool isUIModeKiosk();
|
||||
inline std::vector<std::string> getUIModes() { return mUIModes; };
|
||||
|
||||
private:
|
||||
UIModeController();
|
||||
bool inputIsMatch(InputConfig * config, Input input);
|
||||
bool isValidInput(InputConfig * config, Input input);
|
||||
void logInput(InputConfig * config, Input input);
|
||||
|
||||
// Return UI mode to 'FULL'
|
||||
// Return UI mode to 'full'.
|
||||
void unlockUIMode();
|
||||
|
||||
static UIModeController * sInstance;
|
||||
const std::vector<std::string> mUIModes = { "Full", "Kiosk", "Kid" };
|
||||
|
||||
// default passkeyseq = "uuddlrlrba", as defined in the setting 'UIMode_passkey'.
|
||||
// Default passkeyseq = "uuddlrlrba", as defined in the setting 'UIMode_passkey'.
|
||||
std::string mPassKeySequence;
|
||||
int mPassKeyCounter;
|
||||
const std::vector<std::string> mInputVals = { "up", "down", "left", "right", "a", "b", "x", "y" };
|
||||
const std::vector<std::string> mInputVals =
|
||||
{ "up", "down", "left", "right", "a", "b", "x", "y" };
|
||||
std::string mCurrentUIMode;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
//
|
||||
// ComponentGrid.cpp
|
||||
//
|
||||
// Providing basic layout of other components in an X*Y grid.
|
||||
//
|
||||
|
||||
#include "components/ComponentGrid.h"
|
||||
|
||||
#include "Settings.h"
|
||||
|
||||
using namespace GridFlags;
|
||||
|
||||
ComponentGrid::ComponentGrid(Window* window, const Vector2i& gridDimensions) : GuiComponent(window),
|
||||
mGridSize(gridDimensions), mCursor(0, 0)
|
||||
ComponentGrid::ComponentGrid(
|
||||
Window* window,
|
||||
const Vector2i& gridDimensions)
|
||||
: GuiComponent(window),
|
||||
mGridSize(gridDimensions),
|
||||
mCursor(0, 0)
|
||||
{
|
||||
assert(gridDimensions.x() > 0 && gridDimensions.y() > 0);
|
||||
|
||||
|
@ -13,9 +23,9 @@ ComponentGrid::ComponentGrid(Window* window, const Vector2i& gridDimensions) : G
|
|||
|
||||
mColWidths = new float[gridDimensions.x()];
|
||||
mRowHeights = new float[gridDimensions.y()];
|
||||
for(int x = 0; x < gridDimensions.x(); x++)
|
||||
for (int x = 0; x < gridDimensions.x(); x++)
|
||||
mColWidths[x] = 0;
|
||||
for(int y = 0; y < gridDimensions.y(); y++)
|
||||
for (int y = 0; y < gridDimensions.y(); y++)
|
||||
mRowHeights[y] = 0;
|
||||
}
|
||||
|
||||
|
@ -27,16 +37,15 @@ ComponentGrid::~ComponentGrid()
|
|||
|
||||
float ComponentGrid::getColWidth(int col)
|
||||
{
|
||||
if(mColWidths[col] != 0)
|
||||
if (mColWidths[col] != 0)
|
||||
return mColWidths[col] * mSize.x();
|
||||
|
||||
// calculate automatic width
|
||||
// Calculate automatic width.
|
||||
float freeWidthPerc = 1;
|
||||
int between = 0;
|
||||
for(int x = 0; x < mGridSize.x(); x++)
|
||||
{
|
||||
freeWidthPerc -= mColWidths[x]; // if it's 0 it won't do anything
|
||||
if(mColWidths[x] == 0)
|
||||
for (int x = 0; x < mGridSize.x(); x++) {
|
||||
freeWidthPerc -= mColWidths[x]; // If it's 0 it won't do anything.
|
||||
if (mColWidths[x] == 0)
|
||||
between++;
|
||||
}
|
||||
|
||||
|
@ -45,16 +54,15 @@ float ComponentGrid::getColWidth(int col)
|
|||
|
||||
float ComponentGrid::getRowHeight(int row)
|
||||
{
|
||||
if(mRowHeights[row] != 0)
|
||||
if (mRowHeights[row] != 0)
|
||||
return mRowHeights[row] * mSize.y();
|
||||
|
||||
// calculate automatic height
|
||||
// Calculate automatic height.
|
||||
float freeHeightPerc = 1;
|
||||
int between = 0;
|
||||
for(int y = 0; y < mGridSize.y(); y++)
|
||||
{
|
||||
freeHeightPerc -= mRowHeights[y]; // if it's 0 it won't do anything
|
||||
if(mRowHeights[y] == 0)
|
||||
for (int y = 0; y < mGridSize.y(); y++) {
|
||||
freeHeightPerc -= mRowHeights[y]; // If it's 0 it won't do anything.
|
||||
if (mRowHeights[y] == 0)
|
||||
between++;
|
||||
}
|
||||
|
||||
|
@ -67,7 +75,7 @@ void ComponentGrid::setColWidthPerc(int col, float width, bool update)
|
|||
assert(col >= 0 && col < mGridSize.x());
|
||||
mColWidths[col] = width;
|
||||
|
||||
if(update)
|
||||
if (update)
|
||||
onSizeChanged();
|
||||
}
|
||||
|
||||
|
@ -77,12 +85,18 @@ void ComponentGrid::setRowHeightPerc(int row, float height, bool update)
|
|||
assert(row >= 0 && row < mGridSize.y());
|
||||
mRowHeights[row] = height;
|
||||
|
||||
if(update)
|
||||
if (update)
|
||||
onSizeChanged();
|
||||
}
|
||||
|
||||
void ComponentGrid::setEntry(const std::shared_ptr<GuiComponent>& comp, const Vector2i& pos, bool canFocus, bool resize, const Vector2i& size,
|
||||
unsigned int border, GridFlags::UpdateType updateType)
|
||||
void ComponentGrid::setEntry(
|
||||
const std::shared_ptr<GuiComponent>& comp,
|
||||
const Vector2i& pos,
|
||||
bool canFocus,
|
||||
bool resize,
|
||||
const Vector2i& size,
|
||||
unsigned int border,
|
||||
GridFlags::UpdateType updateType)
|
||||
{
|
||||
assert(pos.x() >= 0 && pos.x() < mGridSize.x() && pos.y() >= 0 && pos.y() < mGridSize.y());
|
||||
assert(comp != nullptr);
|
||||
|
@ -93,8 +107,7 @@ void ComponentGrid::setEntry(const std::shared_ptr<GuiComponent>& comp, const Ve
|
|||
|
||||
addChild(comp.get());
|
||||
|
||||
if(!cursorValid() && canFocus)
|
||||
{
|
||||
if (!cursorValid() && canFocus) {
|
||||
auto origCursor = mCursor;
|
||||
mCursor = pos;
|
||||
onCursorMoved(origCursor, mCursor);
|
||||
|
@ -106,10 +119,8 @@ void ComponentGrid::setEntry(const std::shared_ptr<GuiComponent>& comp, const Ve
|
|||
|
||||
bool ComponentGrid::removeEntry(const std::shared_ptr<GuiComponent>& comp)
|
||||
{
|
||||
for(auto it = mCells.cbegin(); it != mCells.cend(); it++)
|
||||
{
|
||||
if(it->component == comp)
|
||||
{
|
||||
for (auto it = mCells.cbegin(); it != mCells.cend(); it++) {
|
||||
if (it->component == comp) {
|
||||
removeChild(comp.get());
|
||||
mCells.erase(it);
|
||||
return true;
|
||||
|
@ -121,25 +132,25 @@ bool ComponentGrid::removeEntry(const std::shared_ptr<GuiComponent>& comp)
|
|||
|
||||
void ComponentGrid::updateCellComponent(const GridEntry& cell)
|
||||
{
|
||||
// size
|
||||
// Size.
|
||||
Vector2f size(0, 0);
|
||||
for(int x = cell.pos.x(); x < cell.pos.x() + cell.dim.x(); x++)
|
||||
for (int x = cell.pos.x(); x < cell.pos.x() + cell.dim.x(); x++)
|
||||
size[0] += getColWidth(x);
|
||||
for(int y = cell.pos.y(); y < cell.pos.y() + cell.dim.y(); y++)
|
||||
for (int y = cell.pos.y(); y < cell.pos.y() + cell.dim.y(); y++)
|
||||
size[1] += getRowHeight(y);
|
||||
|
||||
if(cell.resize)
|
||||
if (cell.resize)
|
||||
cell.component->setSize(size);
|
||||
|
||||
// position
|
||||
// find top left corner
|
||||
// Position.
|
||||
// Find top left corner.
|
||||
Vector3f pos(0, 0, 0);
|
||||
for(int x = 0; x < cell.pos.x(); x++)
|
||||
for (int x = 0; x < cell.pos.x(); x++)
|
||||
pos[0] += getColWidth(x);
|
||||
for(int y = 0; y < cell.pos.y(); y++)
|
||||
for (int y = 0; y < cell.pos.y(); y++)
|
||||
pos[1] += getRowHeight(y);
|
||||
|
||||
// center component
|
||||
// Center component.
|
||||
pos[0] = pos.x() + (size.x() - cell.component->getSize().x()) / 2;
|
||||
pos[1] = pos.y() + (size.y() - cell.component->getSize().y()) / 2;
|
||||
|
||||
|
@ -155,49 +166,44 @@ void ComponentGrid::updateSeparators()
|
|||
|
||||
Vector2f pos;
|
||||
Vector2f size;
|
||||
for(auto it = mCells.cbegin(); it != mCells.cend(); it++)
|
||||
{
|
||||
if(!it->border && !drawAll)
|
||||
for (auto it = mCells.cbegin(); it != mCells.cend(); it++) {
|
||||
if (!it->border && !drawAll)
|
||||
continue;
|
||||
|
||||
// find component position + size
|
||||
// Find component position + size.
|
||||
pos = Vector2f(0, 0);
|
||||
size = Vector2f(0, 0);
|
||||
for(int x = 0; x < it->pos.x(); x++)
|
||||
for (int x = 0; x < it->pos.x(); x++)
|
||||
pos[0] += getColWidth(x);
|
||||
for(int y = 0; y < it->pos.y(); y++)
|
||||
for (int y = 0; y < it->pos.y(); y++)
|
||||
pos[1] += getRowHeight(y);
|
||||
for(int x = it->pos.x(); x < it->pos.x() + it->dim.x(); x++)
|
||||
for (int x = it->pos.x(); x < it->pos.x() + it->dim.x(); x++)
|
||||
size[0] += getColWidth(x);
|
||||
for(int y = it->pos.y(); y < it->pos.y() + it->dim.y(); y++)
|
||||
for (int y = it->pos.y(); y < it->pos.y() + it->dim.y(); y++)
|
||||
size[1] += getRowHeight(y);
|
||||
|
||||
if(it->border & BORDER_TOP || drawAll)
|
||||
{
|
||||
mLines.push_back( { { pos.x(), pos.y() }, { 0.0f, 0.0f }, color } );
|
||||
mLines.push_back( { { pos.x() + size.x(), pos.y() }, { 0.0f, 0.0f }, color } );
|
||||
if (it->border & BORDER_TOP || drawAll) {
|
||||
mLines.push_back( { { pos.x(), pos.y() }, { 0.0f, 0.0f }, color } );
|
||||
mLines.push_back( { { pos.x() + size.x(), pos.y() }, { 0.0f, 0.0f }, color } );
|
||||
}
|
||||
if(it->border & BORDER_BOTTOM || drawAll)
|
||||
{
|
||||
mLines.push_back( { { pos.x(), pos.y() + size.y() }, { 0.0f, 0.0f }, color } );
|
||||
mLines.push_back( { { pos.x() + size.x(), mLines.back().pos.y() }, { 0.0f, 0.0f }, color } );
|
||||
if (it->border & BORDER_BOTTOM || drawAll) {
|
||||
mLines.push_back( { { pos.x(), pos.y() + size.y() }, { 0.0f, 0.0f }, color } );
|
||||
mLines.push_back( { { pos.x() + size.x(), mLines.back().pos.y() }, { 0.0f, 0.0f }, color } );
|
||||
}
|
||||
if(it->border & BORDER_LEFT || drawAll)
|
||||
{
|
||||
mLines.push_back( { { pos.x(), pos.y() }, { 0.0f, 0.0f }, color } );
|
||||
mLines.push_back( { { pos.x(), pos.y() + size.y() }, { 0.0f, 0.0f }, color } );
|
||||
if (it->border & BORDER_LEFT || drawAll) {
|
||||
mLines.push_back( { { pos.x(), pos.y() }, { 0.0f, 0.0f }, color } );
|
||||
mLines.push_back( { { pos.x(), pos.y() + size.y() }, { 0.0f, 0.0f }, color } );
|
||||
}
|
||||
if(it->border & BORDER_RIGHT || drawAll)
|
||||
{
|
||||
mLines.push_back( { { pos.x() + size.x(), pos.y() }, { 0.0f, 0.0f }, color } );
|
||||
mLines.push_back( { { mLines.back().pos.x(), pos.y() + size.y() }, { 0.0f, 0.0f }, color } );
|
||||
if (it->border & BORDER_RIGHT || drawAll) {
|
||||
mLines.push_back( { { pos.x() + size.x(), pos.y() }, { 0.0f, 0.0f }, color } );
|
||||
mLines.push_back( { { mLines.back().pos.x(), pos.y() + size.y() }, { 0.0f, 0.0f }, color } );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentGrid::onSizeChanged()
|
||||
{
|
||||
for(auto it = mCells.cbegin(); it != mCells.cend(); it++)
|
||||
for (auto it = mCells.cbegin(); it != mCells.cend(); it++)
|
||||
updateCellComponent(*it);
|
||||
|
||||
updateSeparators();
|
||||
|
@ -207,14 +213,13 @@ const ComponentGrid::GridEntry* ComponentGrid::getCellAt(int x, int y) const
|
|||
{
|
||||
assert(x >= 0 && x < mGridSize.x() && y >= 0 && y < mGridSize.y());
|
||||
|
||||
for(auto it = mCells.cbegin(); it != mCells.cend(); it++)
|
||||
{
|
||||
for (auto it = mCells.cbegin(); it != mCells.cend(); it++) {
|
||||
int xmin = it->pos.x();
|
||||
int xmax = xmin + it->dim.x();
|
||||
int ymin = it->pos.y();
|
||||
int ymax = ymin + it->dim.y();
|
||||
|
||||
if(x >= xmin && y >= ymin && x < xmax && y < ymax)
|
||||
if (x >= xmin && y >= ymin && x < xmax && y < ymax)
|
||||
return &(*it);
|
||||
}
|
||||
|
||||
|
@ -224,41 +229,34 @@ const ComponentGrid::GridEntry* ComponentGrid::getCellAt(int x, int y) const
|
|||
bool ComponentGrid::input(InputConfig* config, Input input)
|
||||
{
|
||||
const GridEntry* cursorEntry = getCellAt(mCursor);
|
||||
if(cursorEntry && cursorEntry->component->input(config, input))
|
||||
if (cursorEntry && cursorEntry->component->input(config, input))
|
||||
return true;
|
||||
|
||||
if(!input.value)
|
||||
if (!input.value)
|
||||
return false;
|
||||
|
||||
if(config->isMappedLike("down", input))
|
||||
{
|
||||
if (config->isMappedLike("down", input))
|
||||
return moveCursor(Vector2i(0, 1));
|
||||
}
|
||||
if(config->isMappedLike("up", input))
|
||||
{
|
||||
|
||||
if (config->isMappedLike("up", input))
|
||||
return moveCursor(Vector2i(0, -1));
|
||||
}
|
||||
if(config->isMappedLike("left", input))
|
||||
{
|
||||
|
||||
if (config->isMappedLike("left", input))
|
||||
return moveCursor(Vector2i(-1, 0));
|
||||
}
|
||||
if(config->isMappedLike("right", input))
|
||||
{
|
||||
|
||||
if (config->isMappedLike("right", input))
|
||||
return moveCursor(Vector2i(1, 0));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ComponentGrid::resetCursor()
|
||||
{
|
||||
if(!mCells.size())
|
||||
if (!mCells.size())
|
||||
return;
|
||||
|
||||
for(auto it = mCells.cbegin(); it != mCells.cend(); it++)
|
||||
{
|
||||
if(it->canFocus)
|
||||
{
|
||||
for (auto it = mCells.cbegin(); it != mCells.cend(); it++) {
|
||||
if (it->canFocus) {
|
||||
Vector2i origCursor = mCursor;
|
||||
mCursor = it->pos;
|
||||
onCursorMoved(origCursor, mCursor);
|
||||
|
@ -272,51 +270,42 @@ bool ComponentGrid::moveCursor(Vector2i dir)
|
|||
assert(dir.x() || dir.y());
|
||||
|
||||
const Vector2i origCursor = mCursor;
|
||||
|
||||
const GridEntry* currentCursorEntry = getCellAt(mCursor);
|
||||
|
||||
Vector2i searchAxis(dir.x() == 0, dir.y() == 0);
|
||||
|
||||
while(mCursor.x() >= 0 && mCursor.y() >= 0 && mCursor.x() < mGridSize.x() && mCursor.y() < mGridSize.y())
|
||||
{
|
||||
while (mCursor.x() >= 0 && mCursor.y() >= 0 && mCursor.x() < mGridSize.x() &&
|
||||
mCursor.y() < mGridSize.y()) {
|
||||
mCursor = mCursor + dir;
|
||||
|
||||
Vector2i curDirPos = mCursor;
|
||||
|
||||
const GridEntry* cursorEntry;
|
||||
//spread out on search axis+
|
||||
while(mCursor.x() < mGridSize.x() && mCursor.y() < mGridSize.y()
|
||||
&& mCursor.x() >= 0 && mCursor.y() >= 0)
|
||||
{
|
||||
|
||||
// Spread out on search axis+
|
||||
while (mCursor.x() < mGridSize.x() && mCursor.y() < mGridSize.y()
|
||||
&& mCursor.x() >= 0 && mCursor.y() >= 0) {
|
||||
cursorEntry = getCellAt(mCursor);
|
||||
if(cursorEntry && cursorEntry->canFocus && cursorEntry != currentCursorEntry)
|
||||
{
|
||||
if (cursorEntry && cursorEntry->canFocus && cursorEntry != currentCursorEntry) {
|
||||
onCursorMoved(origCursor, mCursor);
|
||||
return true;
|
||||
}
|
||||
|
||||
mCursor += searchAxis;
|
||||
}
|
||||
|
||||
//now again on search axis-
|
||||
// Now again on search axis-
|
||||
mCursor = curDirPos;
|
||||
while(mCursor.x() >= 0 && mCursor.y() >= 0
|
||||
&& mCursor.x() < mGridSize.x() && mCursor.y() < mGridSize.y())
|
||||
{
|
||||
while (mCursor.x() >= 0 && mCursor.y() >= 0
|
||||
&& mCursor.x() < mGridSize.x() && mCursor.y() < mGridSize.y()) {
|
||||
cursorEntry = getCellAt(mCursor);
|
||||
if(cursorEntry && cursorEntry->canFocus && cursorEntry != currentCursorEntry)
|
||||
{
|
||||
|
||||
if (cursorEntry && cursorEntry->canFocus && cursorEntry != currentCursorEntry) {
|
||||
onCursorMoved(origCursor, mCursor);
|
||||
return true;
|
||||
}
|
||||
|
||||
mCursor -= searchAxis;
|
||||
}
|
||||
|
||||
mCursor = curDirPos;
|
||||
}
|
||||
|
||||
//failed to find another focusable element in this direction
|
||||
// Failed to find another focusable element in this direction.
|
||||
mCursor = origCursor;
|
||||
return false;
|
||||
}
|
||||
|
@ -324,14 +313,14 @@ bool ComponentGrid::moveCursor(Vector2i dir)
|
|||
void ComponentGrid::onFocusLost()
|
||||
{
|
||||
const GridEntry* cursorEntry = getCellAt(mCursor);
|
||||
if(cursorEntry)
|
||||
if (cursorEntry)
|
||||
cursorEntry->component->onFocusLost();
|
||||
}
|
||||
|
||||
void ComponentGrid::onFocusGained()
|
||||
{
|
||||
const GridEntry* cursorEntry = getCellAt(mCursor);
|
||||
if(cursorEntry)
|
||||
if (cursorEntry)
|
||||
cursorEntry->component->onFocusGained();
|
||||
}
|
||||
|
||||
|
@ -343,11 +332,12 @@ bool ComponentGrid::cursorValid()
|
|||
|
||||
void ComponentGrid::update(int deltaTime)
|
||||
{
|
||||
// update ALL THE THINGS
|
||||
// Update ALL THE THINGS.
|
||||
const GridEntry* cursorEntry = getCellAt(mCursor);
|
||||
for(auto it = mCells.cbegin(); it != mCells.cend(); it++)
|
||||
for (auto it = mCells.cbegin(); it != mCells.cend(); it++)
|
||||
{
|
||||
if(it->updateType == UPDATE_ALWAYS || (it->updateType == UPDATE_WHEN_SELECTED && cursorEntry == &(*it)))
|
||||
if (it->updateType == UPDATE_ALWAYS ||
|
||||
(it->updateType == UPDATE_WHEN_SELECTED && cursorEntry == &(*it)))
|
||||
it->component->update(deltaTime);
|
||||
}
|
||||
}
|
||||
|
@ -358,9 +348,8 @@ void ComponentGrid::render(const Transform4x4f& parentTrans)
|
|||
|
||||
renderChildren(trans);
|
||||
|
||||
// draw cell separators
|
||||
if(mLines.size())
|
||||
{
|
||||
// Draw cell separators.
|
||||
if (mLines.size()) {
|
||||
Renderer::setMatrix(trans);
|
||||
Renderer::bindTexture(0);
|
||||
Renderer::drawLines(&mLines[0], mLines.size());
|
||||
|
@ -370,18 +359,18 @@ void ComponentGrid::render(const Transform4x4f& parentTrans)
|
|||
void ComponentGrid::textInput(const char* text)
|
||||
{
|
||||
const GridEntry* selectedEntry = getCellAt(mCursor);
|
||||
if(selectedEntry != NULL && selectedEntry->canFocus)
|
||||
if (selectedEntry != NULL && selectedEntry->canFocus)
|
||||
selectedEntry->component->textInput(text);
|
||||
}
|
||||
|
||||
void ComponentGrid::onCursorMoved(Vector2i from, Vector2i to)
|
||||
{
|
||||
const GridEntry* cell = getCellAt(from);
|
||||
if(cell)
|
||||
if (cell)
|
||||
cell->component->onFocusLost();
|
||||
|
||||
cell = getCellAt(to);
|
||||
if(cell)
|
||||
if (cell)
|
||||
cell->component->onFocusGained();
|
||||
|
||||
updateHelpPrompts();
|
||||
|
@ -389,10 +378,8 @@ void ComponentGrid::onCursorMoved(Vector2i from, Vector2i to)
|
|||
|
||||
void ComponentGrid::setCursorTo(const std::shared_ptr<GuiComponent>& comp)
|
||||
{
|
||||
for(auto it = mCells.cbegin(); it != mCells.cend(); it++)
|
||||
{
|
||||
if(it->component == comp)
|
||||
{
|
||||
for (auto it = mCells.cbegin(); it != mCells.cend(); it++) {
|
||||
if (it->component == comp) {
|
||||
Vector2i oldCursor = mCursor;
|
||||
mCursor = it->pos;
|
||||
onCursorMoved(oldCursor, mCursor);
|
||||
|
@ -400,7 +387,7 @@ void ComponentGrid::setCursorTo(const std::shared_ptr<GuiComponent>& comp)
|
|||
}
|
||||
}
|
||||
|
||||
// component not found!!
|
||||
// Component not found!!
|
||||
assert(false);
|
||||
}
|
||||
|
||||
|
@ -408,32 +395,30 @@ std::vector<HelpPrompt> ComponentGrid::getHelpPrompts()
|
|||
{
|
||||
std::vector<HelpPrompt> prompts;
|
||||
const GridEntry* e = getCellAt(mCursor);
|
||||
if(e)
|
||||
if (e)
|
||||
prompts = e->component->getHelpPrompts();
|
||||
|
||||
bool canScrollVert = mGridSize.y() > 1;
|
||||
bool canScrollHoriz = mGridSize.x() > 1;
|
||||
for(auto it = prompts.cbegin(); it != prompts.cend(); it++)
|
||||
{
|
||||
if(it->first == "up/down/left/right")
|
||||
{
|
||||
for (auto it = prompts.cbegin(); it != prompts.cend(); it++) {
|
||||
if (it->first == "up/down/left/right") {
|
||||
canScrollHoriz = false;
|
||||
canScrollVert = false;
|
||||
break;
|
||||
}else if(it->first == "up/down")
|
||||
{
|
||||
}
|
||||
else if (it->first == "up/down") {
|
||||
canScrollVert = false;
|
||||
}else if(it->first == "left/right")
|
||||
{
|
||||
}
|
||||
else if (it->first == "left/right") {
|
||||
canScrollHoriz = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(canScrollHoriz && canScrollVert)
|
||||
if (canScrollHoriz && canScrollVert)
|
||||
prompts.push_back(HelpPrompt("up/down/left/right", "choose"));
|
||||
else if(canScrollHoriz)
|
||||
else if (canScrollHoriz)
|
||||
prompts.push_back(HelpPrompt("left/right", "choose"));
|
||||
else if(canScrollVert)
|
||||
else if (canScrollVert)
|
||||
prompts.push_back(HelpPrompt("up/down", "choose"));
|
||||
|
||||
return prompts;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// ComponentGrid.h
|
||||
//
|
||||
// Providing basic layout of other components in an X*Y grid.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_CORE_COMPONENTS_COMPONENT_GRID_H
|
||||
#define ES_CORE_COMPONENTS_COMPONENT_GRID_H
|
||||
|
@ -8,15 +14,13 @@
|
|||
|
||||
namespace GridFlags
|
||||
{
|
||||
enum UpdateType
|
||||
{
|
||||
enum UpdateType {
|
||||
UPDATE_ALWAYS,
|
||||
UPDATE_WHEN_SELECTED,
|
||||
UPDATE_NEVER
|
||||
};
|
||||
|
||||
enum Border : unsigned int
|
||||
{
|
||||
enum Border : unsigned int {
|
||||
BORDER_NONE = 0,
|
||||
|
||||
BORDER_TOP = 1,
|
||||
|
@ -35,8 +39,14 @@ public:
|
|||
|
||||
bool removeEntry(const std::shared_ptr<GuiComponent>& comp);
|
||||
|
||||
void setEntry(const std::shared_ptr<GuiComponent>& comp, const Vector2i& pos, bool canFocus, bool resize = true,
|
||||
const Vector2i& size = Vector2i(1, 1), unsigned int border = GridFlags::BORDER_NONE, GridFlags::UpdateType updateType = GridFlags::UPDATE_ALWAYS);
|
||||
void setEntry(
|
||||
const std::shared_ptr<GuiComponent>& comp,
|
||||
const Vector2i& pos,
|
||||
bool canFocus,
|
||||
bool resize = true,
|
||||
const Vector2i& size = Vector2i(1, 1),
|
||||
unsigned int border = GridFlags::BORDER_NONE,
|
||||
GridFlags::UpdateType updateType = GridFlags::UPDATE_ALWAYS);
|
||||
|
||||
void textInput(const char* text) override;
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
|
@ -50,8 +60,11 @@ public:
|
|||
float getColWidth(int col);
|
||||
float getRowHeight(int row);
|
||||
|
||||
void setColWidthPerc(int col, float width, bool update = true); // if update is false, will not call an onSizeChanged() which triggers a (potentially costly) repositioning + resizing of every element
|
||||
void setRowHeightPerc(int row, float height, bool update = true); // if update is false, will not call an onSizeChanged() which triggers a (potentially costly) repositioning + resizing of every element
|
||||
// If update is false, will not call an onSizeChanged() which triggers
|
||||
// a (potentially costly) repositioning + resizing of every element.
|
||||
void setColWidthPerc(int col, float width, bool update = true);
|
||||
// Dito.
|
||||
void setRowHeightPerc(int row, float height, bool update = true);
|
||||
|
||||
bool moveCursor(Vector2i dir);
|
||||
void setCursorTo(const std::shared_ptr<GuiComponent>& comp);
|
||||
|
@ -84,7 +97,8 @@ private:
|
|||
|
||||
GridEntry(const Vector2i& p = Vector2i::Zero(), const Vector2i& d = Vector2i::Zero(),
|
||||
const std::shared_ptr<GuiComponent>& cmp = nullptr, bool f = false, bool r = true,
|
||||
GridFlags::UpdateType u = GridFlags::UPDATE_ALWAYS, unsigned int b = GridFlags::BORDER_NONE) :
|
||||
GridFlags::UpdateType u = GridFlags::UPDATE_ALWAYS, unsigned int b =
|
||||
GridFlags::BORDER_NONE) :
|
||||
pos(p), dim(d), component(cmp), canFocus(f), resize(r), updateType(u), border(b)
|
||||
{};
|
||||
|
||||
|
@ -99,12 +113,13 @@ private:
|
|||
|
||||
std::vector<Renderer::Vertex> mLines;
|
||||
|
||||
// Update position & size
|
||||
// Update position & size.
|
||||
void updateCellComponent(const GridEntry& cell);
|
||||
void updateSeparators();
|
||||
|
||||
const GridEntry* getCellAt(int x, int y) const;
|
||||
inline const GridEntry* getCellAt(const Vector2i& pos) const { return getCellAt(pos.x(), pos.y()); }
|
||||
inline const GridEntry* getCellAt(const Vector2i& pos) const
|
||||
{ return getCellAt(pos.x(), pos.y()); }
|
||||
|
||||
Vector2i mGridSize;
|
||||
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
//
|
||||
// ComponentList.cpp
|
||||
//
|
||||
// Used to lay out and navigate lists in GUI menus.
|
||||
//
|
||||
|
||||
#include "components/ComponentList.h"
|
||||
|
||||
#define TOTAL_HORIZONTAL_PADDING_PX 20
|
||||
|
||||
ComponentList::ComponentList(Window* window) : IList<ComponentListRow, void*>(window, LIST_SCROLL_STYLE_SLOW, LIST_NEVER_LOOP)
|
||||
ComponentList::ComponentList(Window* window) : IList<ComponentListRow,
|
||||
void*>(window, LIST_SCROLL_STYLE_SLOW, LIST_NEVER_LOOP)
|
||||
{
|
||||
mSelectorBarOffset = 0;
|
||||
mCameraOffset = 0;
|
||||
|
@ -18,14 +25,14 @@ void ComponentList::addRow(const ComponentListRow& row, bool setCursorHere)
|
|||
|
||||
this->add(e);
|
||||
|
||||
for(auto it = mEntries.back().data.elements.cbegin(); it != mEntries.back().data.elements.cend(); it++)
|
||||
for (auto it = mEntries.back().data.elements.cbegin();
|
||||
it != mEntries.back().data.elements.cend(); it++)
|
||||
addChild(it->component.get());
|
||||
|
||||
updateElementSize(mEntries.back().data);
|
||||
updateElementPosition(mEntries.back().data);
|
||||
|
||||
if(setCursorHere)
|
||||
{
|
||||
if (setCursorHere) {
|
||||
mCursor = (int)mEntries.size() - 1;
|
||||
onCursorChanged(CURSOR_STOPPED);
|
||||
}
|
||||
|
@ -33,8 +40,7 @@ void ComponentList::addRow(const ComponentListRow& row, bool setCursorHere)
|
|||
|
||||
void ComponentList::onSizeChanged()
|
||||
{
|
||||
for(auto it = mEntries.cbegin(); it != mEntries.cend(); it++)
|
||||
{
|
||||
for (auto it = mEntries.cbegin(); it != mEntries.cend(); it++) {
|
||||
updateElementSize(it->data);
|
||||
updateElementPosition(it->data);
|
||||
}
|
||||
|
@ -54,38 +60,33 @@ void ComponentList::onFocusGained()
|
|||
|
||||
bool ComponentList::input(InputConfig* config, Input input)
|
||||
{
|
||||
if(size() == 0)
|
||||
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))
|
||||
// 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
|
||||
}
|
||||
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))
|
||||
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))
|
||||
{
|
||||
// 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))
|
||||
{
|
||||
else if (config->isMappedLike("down", input))
|
||||
return listInput(input.value != 0 ? 1 : 0);
|
||||
|
||||
}else if(config->isMappedLike("leftshoulder", input))
|
||||
{
|
||||
else if (config->isMappedLike("leftshoulder", input))
|
||||
return listInput(input.value != 0 ? -6 : 0);
|
||||
}else if(config->isMappedLike("rightshoulder", input)){
|
||||
else if (config->isMappedLike("rightshoulder", input))
|
||||
return listInput(input.value != 0 ? 6 : 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -94,36 +95,33 @@ void ComponentList::update(int deltaTime)
|
|||
{
|
||||
listUpdate(deltaTime);
|
||||
|
||||
if(size())
|
||||
{
|
||||
// update our currently selected row
|
||||
for(auto it = mEntries.at(mCursor).data.elements.cbegin(); it != mEntries.at(mCursor).data.elements.cend(); it++)
|
||||
if (size()) {
|
||||
// Update our currently selected row.
|
||||
for (auto it = mEntries.at(mCursor).data.elements.cbegin();
|
||||
it != mEntries.at(mCursor).data.elements.cend(); it++)
|
||||
it->component->update(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentList::onCursorChanged(const CursorState& state)
|
||||
{
|
||||
// update the selector bar position
|
||||
// in the future this might be animated
|
||||
// Update the selector bar position.
|
||||
// In the future this might be animated.
|
||||
mSelectorBarOffset = 0;
|
||||
for(int i = 0; i < mCursor; i++)
|
||||
{
|
||||
for (int i = 0; i < mCursor; i++)
|
||||
mSelectorBarOffset += getRowHeight(mEntries.at(i).data);
|
||||
}
|
||||
|
||||
updateCameraOffset();
|
||||
|
||||
// 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++)
|
||||
// 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();
|
||||
|
||||
mEntries.at(mCursor).data.elements.back().component->onFocusGained();
|
||||
}
|
||||
|
||||
if(mCursorChangedCallback)
|
||||
if (mCursorChangedCallback)
|
||||
mCursorChangedCallback(state);
|
||||
|
||||
updateHelpPrompts();
|
||||
|
@ -131,110 +129,109 @@ void ComponentList::onCursorChanged(const CursorState& state)
|
|||
|
||||
void ComponentList::updateCameraOffset()
|
||||
{
|
||||
// move the camera to scroll
|
||||
// Move the camera to scroll.
|
||||
const float totalHeight = getTotalRowHeight();
|
||||
if(totalHeight > mSize.y())
|
||||
{
|
||||
float target = mSelectorBarOffset + getRowHeight(mEntries.at(mCursor).data)/2 - (mSize.y() / 2);
|
||||
if (totalHeight > mSize.y()) {
|
||||
float target = mSelectorBarOffset + getRowHeight(mEntries.at(mCursor).data)/2 -
|
||||
(mSize.y() / 2);
|
||||
|
||||
// clamp it
|
||||
// Clamp it.
|
||||
mCameraOffset = 0;
|
||||
unsigned int i = 0;
|
||||
while(mCameraOffset < target && i < mEntries.size())
|
||||
{
|
||||
while (mCameraOffset < target && i < mEntries.size()) {
|
||||
mCameraOffset += getRowHeight(mEntries.at(i).data);
|
||||
i++;
|
||||
}
|
||||
|
||||
if(mCameraOffset < 0)
|
||||
if (mCameraOffset < 0)
|
||||
mCameraOffset = 0;
|
||||
else if(mCameraOffset + mSize.y() > totalHeight)
|
||||
else if (mCameraOffset + mSize.y() > totalHeight)
|
||||
mCameraOffset = totalHeight - mSize.y();
|
||||
}else{
|
||||
}
|
||||
else {
|
||||
mCameraOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentList::render(const Transform4x4f& parentTrans)
|
||||
{
|
||||
if(!size())
|
||||
if (!size())
|
||||
return;
|
||||
|
||||
Transform4x4f trans = parentTrans * getTransform();
|
||||
|
||||
// clip everything to be inside our bounds
|
||||
// Clip everything to be inside our bounds.
|
||||
Vector3f dim(mSize.x(), mSize.y(), 0);
|
||||
dim = trans * dim - trans.translation();
|
||||
Renderer::pushClipRect(Vector2i((int)trans.translation().x(), (int)trans.translation().y()),
|
||||
Vector2i((int)Math::round(dim.x()), (int)Math::round(dim.y() + 1)));
|
||||
|
||||
// scroll the camera
|
||||
// Scroll the camera.
|
||||
trans.translate(Vector3f(0, -Math::round(mCameraOffset), 0));
|
||||
|
||||
// draw our entries
|
||||
// Draw our entries.
|
||||
std::vector<GuiComponent*> drawAfterCursor;
|
||||
bool drawAll;
|
||||
for(unsigned int i = 0; i < mEntries.size(); i++)
|
||||
{
|
||||
for (unsigned int i = 0; i < mEntries.size(); i++) {
|
||||
auto& entry = mEntries.at(i);
|
||||
drawAll = !mFocused || i != (unsigned int)mCursor;
|
||||
for(auto it = entry.data.elements.cbegin(); it != entry.data.elements.cend(); it++)
|
||||
{
|
||||
if(drawAll || it->invert_when_selected)
|
||||
{
|
||||
for (auto it = entry.data.elements.cbegin(); it != entry.data.elements.cend(); it++) {
|
||||
if (drawAll || it->invert_when_selected)
|
||||
it->component->render(trans);
|
||||
}else{
|
||||
else
|
||||
drawAfterCursor.push_back(it->component.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// custom rendering
|
||||
// Custom rendering.
|
||||
Renderer::setMatrix(trans);
|
||||
|
||||
// draw selector bar
|
||||
if(mFocused)
|
||||
{
|
||||
// inversion: src * (1 - dst) + dst * 0 = where src = 1
|
||||
// need a function that goes roughly 0x777777 -> 0xFFFFFF
|
||||
// Draw selector bar.
|
||||
if (mFocused) {
|
||||
// Inversion: src * (1 - dst) + dst * 0 = where src = 1
|
||||
// Need a function that goes roughly 0x777777 -> 0xFFFFFF
|
||||
// and 0xFFFFFF -> 0x777777
|
||||
// (1 - dst) + 0x77
|
||||
|
||||
const float selectedRowHeight = getRowHeight(mEntries.at(mCursor).data);
|
||||
Renderer::drawRect(0.0f, mSelectorBarOffset, mSize.x(), selectedRowHeight, 0xFFFFFFFF, 0xFFFFFFFF, false, Renderer::Blend::ONE_MINUS_DST_COLOR, Renderer::Blend::ZERO);
|
||||
Renderer::drawRect(0.0f, mSelectorBarOffset, mSize.x(), selectedRowHeight, 0x777777FF, 0x777777FF, false, Renderer::Blend::ONE, Renderer::Blend::ONE);
|
||||
Renderer::drawRect(0.0f, mSelectorBarOffset, mSize.x(), selectedRowHeight,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, false, Renderer::Blend::ONE_MINUS_DST_COLOR,
|
||||
Renderer::Blend::ZERO);
|
||||
Renderer::drawRect(0.0f, mSelectorBarOffset, mSize.x(), selectedRowHeight,
|
||||
0x777777FF, 0x777777FF, false, Renderer::Blend::ONE,
|
||||
Renderer::Blend::ONE);
|
||||
|
||||
// hack to draw 2px dark on left/right of the bar
|
||||
Renderer::drawRect(0.0f, mSelectorBarOffset, 2.0f, selectedRowHeight, 0x878787FF, 0x878787FF);
|
||||
Renderer::drawRect(mSize.x() - 2.0f, mSelectorBarOffset, 2.0f, selectedRowHeight, 0x878787FF, 0x878787FF);
|
||||
// Hack to draw 2px dark on left/right of the bar.
|
||||
Renderer::drawRect(0.0f, mSelectorBarOffset, 2.0f, selectedRowHeight,
|
||||
0x878787FF, 0x878787FF);
|
||||
Renderer::drawRect(mSize.x() - 2.0f, mSelectorBarOffset, 2.0f, selectedRowHeight,
|
||||
0x878787FF, 0x878787FF);
|
||||
|
||||
for(auto it = drawAfterCursor.cbegin(); it != drawAfterCursor.cend(); it++)
|
||||
for (auto it = drawAfterCursor.cbegin(); it != drawAfterCursor.cend(); it++)
|
||||
(*it)->render(trans);
|
||||
|
||||
// reset matrix if one of these components changed it
|
||||
if(drawAfterCursor.size())
|
||||
// Reset matrix if one of these components changed it.
|
||||
if (drawAfterCursor.size())
|
||||
Renderer::setMatrix(trans);
|
||||
}
|
||||
|
||||
// draw separators
|
||||
// Draw separators.
|
||||
float y = 0;
|
||||
for(unsigned int i = 0; i < mEntries.size(); i++)
|
||||
{
|
||||
for (unsigned int i = 0; i < mEntries.size(); i++) {
|
||||
Renderer::drawRect(0.0f, y, mSize.x(), 1.0f, 0xC6C7C6FF, 0xC6C7C6FF);
|
||||
y += getRowHeight(mEntries.at(i).data);
|
||||
}
|
||||
Renderer::drawRect(0.0f, y, mSize.x(), 1.0f, 0xC6C7C6FF, 0xC6C7C6FF);
|
||||
|
||||
Renderer::drawRect(0.0f, y, mSize.x(), 1.0f, 0xC6C7C6FF, 0xC6C7C6FF);
|
||||
Renderer::popClipRect();
|
||||
}
|
||||
|
||||
float ComponentList::getRowHeight(const ComponentListRow& row) const
|
||||
{
|
||||
// returns the highest component height found in the row
|
||||
// Returns the highest component height found in the row.
|
||||
float height = 0;
|
||||
for(unsigned int i = 0; i < row.elements.size(); i++)
|
||||
{
|
||||
if(row.elements.at(i).component->getSize().y() > height)
|
||||
for (unsigned int i = 0; i < row.elements.size(); i++) {
|
||||
if (row.elements.at(i).component->getSize().y() > height)
|
||||
height = row.elements.at(i).component->getSize().y();
|
||||
}
|
||||
|
||||
|
@ -244,10 +241,8 @@ float ComponentList::getRowHeight(const ComponentListRow& row) const
|
|||
float ComponentList::getTotalRowHeight() const
|
||||
{
|
||||
float height = 0;
|
||||
for(auto it = mEntries.cbegin(); it != mEntries.cend(); it++)
|
||||
{
|
||||
for (auto it = mEntries.cbegin(); it != mEntries.cend(); it++)
|
||||
height += getRowHeight(it->data);
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
@ -255,20 +250,17 @@ float ComponentList::getTotalRowHeight() const
|
|||
void ComponentList::updateElementPosition(const ComponentListRow& row)
|
||||
{
|
||||
float yOffset = 0;
|
||||
for(auto it = mEntries.cbegin(); it != mEntries.cend() && &it->data != &row; it++)
|
||||
{
|
||||
for (auto it = mEntries.cbegin(); it != mEntries.cend() && &it->data != &row; it++)
|
||||
yOffset += getRowHeight(it->data);
|
||||
}
|
||||
|
||||
// assumes updateElementSize has already been called
|
||||
// Assumes updateElementSize has already been called.
|
||||
float rowHeight = getRowHeight(row);
|
||||
|
||||
float x = TOTAL_HORIZONTAL_PADDING_PX / 2;
|
||||
for(unsigned int i = 0; i < row.elements.size(); i++)
|
||||
{
|
||||
for (unsigned int i = 0; i < row.elements.size(); i++) {
|
||||
const auto comp = row.elements.at(i).component;
|
||||
|
||||
// center vertically
|
||||
// Center vertically.
|
||||
comp->setPosition(x, (rowHeight - comp->getSize().y()) / 2 + yOffset);
|
||||
x += comp->getSize().x();
|
||||
}
|
||||
|
@ -279,25 +271,22 @@ void ComponentList::updateElementSize(const ComponentListRow& row)
|
|||
float width = mSize.x() - TOTAL_HORIZONTAL_PADDING_PX;
|
||||
std::vector< std::shared_ptr<GuiComponent> > resizeVec;
|
||||
|
||||
for(auto it = row.elements.cbegin(); it != row.elements.cend(); it++)
|
||||
{
|
||||
if(it->resize_width)
|
||||
for (auto it = row.elements.cbegin(); it != row.elements.cend(); it++) {
|
||||
if (it->resize_width)
|
||||
resizeVec.push_back(it->component);
|
||||
else
|
||||
width -= it->component->getSize().x();
|
||||
}
|
||||
|
||||
// redistribute the "unused" width equally among the components with resize_width set to true
|
||||
// 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++)
|
||||
{
|
||||
for (auto it = resizeVec.cbegin(); it != resizeVec.cend(); it++)
|
||||
(*it)->setSize(width, (*it)->getSize().y());
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentList::textInput(const char* text)
|
||||
{
|
||||
if(!size())
|
||||
if (!size())
|
||||
return;
|
||||
|
||||
mEntries.at(mCursor).data.elements.back().component->textInput(text);
|
||||
|
@ -305,24 +294,21 @@ void ComponentList::textInput(const char* text)
|
|||
|
||||
std::vector<HelpPrompt> ComponentList::getHelpPrompts()
|
||||
{
|
||||
if(!size())
|
||||
if (!size())
|
||||
return std::vector<HelpPrompt>();
|
||||
|
||||
std::vector<HelpPrompt> prompts = mEntries.at(mCursor).data.elements.back().component->getHelpPrompts();
|
||||
std::vector<HelpPrompt> prompts =
|
||||
mEntries.at(mCursor).data.elements.back().component->getHelpPrompts();
|
||||
|
||||
if(size() > 1)
|
||||
{
|
||||
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")
|
||||
{
|
||||
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)
|
||||
if (addMovePrompt)
|
||||
prompts.push_back(HelpPrompt("up/down", "choose"));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,23 @@
|
|||
//
|
||||
// ComponentList.h
|
||||
//
|
||||
// Used to lay out and navigate lists in GUI menus.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_CORE_COMPONENTS_COMPONENT_LIST_H
|
||||
#define ES_CORE_COMPONENTS_COMPONENT_LIST_H
|
||||
|
||||
#include "IList.h"
|
||||
|
||||
struct ComponentListElement
|
||||
{
|
||||
ComponentListElement(const std::shared_ptr<GuiComponent>& cmp = nullptr, bool resize_w = true, bool inv = true)
|
||||
: component(cmp), resize_width(resize_w), invert_when_selected(inv) { };
|
||||
struct ComponentListElement {
|
||||
ComponentListElement(
|
||||
const std::shared_ptr<GuiComponent>& cmp = nullptr,
|
||||
bool resize_w = true,
|
||||
bool inv = true)
|
||||
: component(cmp),
|
||||
resize_width(resize_w),
|
||||
invert_when_selected(inv) {};
|
||||
|
||||
std::shared_ptr<GuiComponent> component;
|
||||
bool resize_width;
|
||||
|
@ -18,23 +28,24 @@ struct ComponentListRow
|
|||
{
|
||||
std::vector<ComponentListElement> elements;
|
||||
|
||||
// The input handler is called when the user enters any input while this row is highlighted (including up/down).
|
||||
// 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.
|
||||
// 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;
|
||||
|
||||
inline void addElement(const std::shared_ptr<GuiComponent>& component, bool resize_width, bool invert_when_selected = true)
|
||||
inline void addElement(const std::shared_ptr<GuiComponent>& component,
|
||||
bool resize_width, bool invert_when_selected = true)
|
||||
{
|
||||
elements.push_back(ComponentListElement(component, resize_width, invert_when_selected));
|
||||
}
|
||||
|
||||
// Utility method for making an input handler for "when the users presses A on this, do func."
|
||||
// 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)
|
||||
{
|
||||
if(config->isMappedTo("a", input) && input.value != 0) {
|
||||
func();
|
||||
return true;
|
||||
}
|
||||
|
@ -66,8 +77,10 @@ public:
|
|||
float getTotalRowHeight() const;
|
||||
inline float getRowHeight(int row) const { return getRowHeight(mEntries.at(row).data); }
|
||||
|
||||
inline void setCursorChangedCallback(const std::function<void(CursorState state)>& callback) { mCursorChangedCallback = callback; };
|
||||
inline const std::function<void(CursorState state)>& getCursorChangedCallback() const { return mCursorChangedCallback; };
|
||||
inline void setCursorChangedCallback(const std::function<void(CursorState state)>& callback)
|
||||
{ mCursorChangedCallback = callback; };
|
||||
inline const std::function<void(CursorState state)>& getCursorChangedCallback() const
|
||||
{ return mCursorChangedCallback; };
|
||||
|
||||
protected:
|
||||
void onCursorChanged(const CursorState& state) override;
|
||||
|
|
|
@ -1,16 +1,32 @@
|
|||
//
|
||||
// DateTimeComponent.cpp
|
||||
//
|
||||
// Date and time component.
|
||||
//
|
||||
|
||||
#include "components/DateTimeComponent.h"
|
||||
|
||||
#include "utils/StringUtil.h"
|
||||
#include "Log.h"
|
||||
#include "Settings.h"
|
||||
|
||||
DateTimeComponent::DateTimeComponent(Window* window) : TextComponent(window), mDisplayRelative(false)
|
||||
DateTimeComponent::DateTimeComponent(Window* window)
|
||||
: TextComponent(window), mDisplayRelative(false)
|
||||
{
|
||||
setFormat("%m/%d/%Y");
|
||||
}
|
||||
|
||||
DateTimeComponent::DateTimeComponent(Window* window, const std::string& text, const std::shared_ptr<Font>& font, unsigned int color, Alignment align,
|
||||
Vector3f pos, Vector2f size, unsigned int bgcolor) : TextComponent(window, text, font, color, align, pos, size, bgcolor), mDisplayRelative(false)
|
||||
DateTimeComponent::DateTimeComponent(
|
||||
Window* window,
|
||||
const std::string& text,
|
||||
const std::shared_ptr<Font>& font,
|
||||
unsigned int color,
|
||||
Alignment align,
|
||||
Vector3f pos,
|
||||
Vector2f size,
|
||||
unsigned int bgcolor)
|
||||
: TextComponent(window, text, font, color, align, pos, size, bgcolor),
|
||||
mDisplayRelative(false)
|
||||
{
|
||||
setFormat("%m/%d/%Y");
|
||||
}
|
||||
|
@ -41,14 +57,13 @@ void DateTimeComponent::setDisplayRelative(bool displayRelative)
|
|||
void DateTimeComponent::onTextChanged()
|
||||
{
|
||||
mText = getDisplayString();
|
||||
|
||||
TextComponent::onTextChanged();
|
||||
}
|
||||
|
||||
std::string DateTimeComponent::getDisplayString() const
|
||||
{
|
||||
if (mDisplayRelative) {
|
||||
//relative time
|
||||
// Relative time.
|
||||
if(mTime.getTime() == 0)
|
||||
return "never";
|
||||
|
||||
|
@ -81,7 +96,8 @@ void DateTimeComponent::render(const Transform4x4f& parentTrans)
|
|||
}
|
||||
|
||||
|
||||
void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties)
|
||||
void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||
const std::string& view, const std::string& element, unsigned int properties)
|
||||
{
|
||||
GuiComponent::applyTheme(theme, view, element, properties);
|
||||
|
||||
|
@ -106,8 +122,7 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, cons
|
|||
setRenderBackground(true);
|
||||
}
|
||||
|
||||
if(properties & ALIGNMENT && elem->has("alignment"))
|
||||
{
|
||||
if(properties & ALIGNMENT && elem->has("alignment")) {
|
||||
std::string str = elem->get<std::string>("alignment");
|
||||
if(str == "left")
|
||||
setHorizontalAlignment(ALIGN_LEFT);
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// DateTimeComponent.h
|
||||
//
|
||||
// Date and time component.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_CORE_COMPONENTS_DATE_TIME_COMPONENT_H
|
||||
#define ES_CORE_COMPONENTS_DATE_TIME_COMPONENT_H
|
||||
|
@ -12,8 +18,15 @@ class DateTimeComponent : public TextComponent
|
|||
{
|
||||
public:
|
||||
DateTimeComponent(Window* window);
|
||||
DateTimeComponent(Window* window, const std::string& text, const std::shared_ptr<Font>& font, unsigned int color = 0x000000FF, Alignment align = ALIGN_LEFT,
|
||||
Vector3f pos = Vector3f::Zero(), Vector2f size = Vector2f::Zero(), unsigned int bgcolor = 0x00000000);
|
||||
DateTimeComponent(
|
||||
Window* window,
|
||||
const std::string& text,
|
||||
const std::shared_ptr<Font>& font,
|
||||
unsigned int color = 0x000000FF,
|
||||
Alignment align = ALIGN_LEFT,
|
||||
Vector3f pos = Vector3f::Zero(),
|
||||
Vector2f size = Vector2f::Zero(),
|
||||
unsigned int bgcolor = 0x00000000);
|
||||
|
||||
void render(const Transform4x4f& parentTrans) override;
|
||||
|
||||
|
@ -23,7 +36,8 @@ public:
|
|||
void setFormat(const std::string& format);
|
||||
void setDisplayRelative(bool displayRelative);
|
||||
|
||||
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties) override;
|
||||
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view,
|
||||
const std::string& element, unsigned int properties) override;
|
||||
|
||||
protected:
|
||||
void onTextChanged() override;
|
||||
|
|
|
@ -1,11 +1,26 @@
|
|||
//
|
||||
// DateTimeEditComponent.cpp
|
||||
//
|
||||
// Date and time edit component.
|
||||
//
|
||||
|
||||
#include "components/DateTimeEditComponent.h"
|
||||
|
||||
#include "resources/Font.h"
|
||||
#include "utils/StringUtil.h"
|
||||
|
||||
DateTimeEditComponent::DateTimeEditComponent(Window* window, DisplayMode dispMode) : GuiComponent(window),
|
||||
mEditing(false), mEditIndex(0), mDisplayMode(dispMode), mRelativeUpdateAccumulator(0),
|
||||
mColor(0x777777FF), mFont(Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT)), mUppercase(false), mAutoSize(true)
|
||||
DateTimeEditComponent::DateTimeEditComponent(
|
||||
Window* window,
|
||||
DisplayMode dispMode)
|
||||
: GuiComponent(window),
|
||||
mEditing(false),
|
||||
mEditIndex(0),
|
||||
mDisplayMode(dispMode),
|
||||
mRelativeUpdateAccumulator(0),
|
||||
mColor(0x777777FF),
|
||||
mFont(Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT)),
|
||||
mUppercase(false),
|
||||
mAutoSize(true)
|
||||
{
|
||||
updateTextCache();
|
||||
}
|
||||
|
@ -18,22 +33,19 @@ void DateTimeEditComponent::setDisplayMode(DisplayMode mode)
|
|||
|
||||
bool DateTimeEditComponent::input(InputConfig* config, Input input)
|
||||
{
|
||||
if(input.value == 0)
|
||||
if (input.value == 0)
|
||||
return false;
|
||||
|
||||
if(config->isMappedTo("a", input))
|
||||
{
|
||||
if(mDisplayMode != DISP_RELATIVE_TO_NOW) //don't allow editing for relative times
|
||||
if (config->isMappedTo("a", input)) {
|
||||
if (mDisplayMode != DISP_RELATIVE_TO_NOW) // Don't allow editing for relative times.
|
||||
mEditing = !mEditing;
|
||||
|
||||
if(mEditing)
|
||||
{
|
||||
//started editing
|
||||
if (mEditing) {
|
||||
// Started editing.
|
||||
mTimeBeforeEdit = mTime;
|
||||
|
||||
//initialize to now if unset
|
||||
if(mTime.getTime() == Utils::Time::NOT_A_DATE_TIME)
|
||||
{
|
||||
// Initialize to now if unset.
|
||||
if (mTime.getTime() == Utils::Time::NOT_A_DATE_TIME) {
|
||||
mTime = Utils::Time::now();
|
||||
updateTextCache();
|
||||
}
|
||||
|
@ -42,10 +54,8 @@ bool DateTimeEditComponent::input(InputConfig* config, Input input)
|
|||
return true;
|
||||
}
|
||||
|
||||
if(mEditing)
|
||||
{
|
||||
if(config->isMappedTo("b", input))
|
||||
{
|
||||
if (mEditing) {
|
||||
if (config->isMappedTo("b", input)) {
|
||||
mEditing = false;
|
||||
mTime = mTimeBeforeEdit;
|
||||
updateTextCache();
|
||||
|
@ -53,47 +63,45 @@ bool DateTimeEditComponent::input(InputConfig* config, Input input)
|
|||
}
|
||||
|
||||
int incDir = 0;
|
||||
if(config->isMappedLike("up", input) || config->isMappedLike("leftshoulder", input))
|
||||
if (config->isMappedLike("up", input) || config->isMappedLike("leftshoulder", input))
|
||||
incDir = 1;
|
||||
else if(config->isMappedLike("down", input) || config->isMappedLike("rightshoulder", input))
|
||||
else if (config->isMappedLike("down", input) || config->isMappedLike("rightshoulder", input))
|
||||
incDir = -1;
|
||||
|
||||
if(incDir != 0)
|
||||
{
|
||||
if (incDir != 0) {
|
||||
tm new_tm = mTime;
|
||||
|
||||
if(mEditIndex == 0)
|
||||
{
|
||||
if (mEditIndex == 0) {
|
||||
new_tm.tm_mon += incDir;
|
||||
|
||||
if(new_tm.tm_mon > 11)
|
||||
if (new_tm.tm_mon > 11)
|
||||
new_tm.tm_mon = 0;
|
||||
else if(new_tm.tm_mon < 0)
|
||||
else if (new_tm.tm_mon < 0)
|
||||
new_tm.tm_mon = 11;
|
||||
|
||||
}
|
||||
else if(mEditIndex == 1)
|
||||
{
|
||||
const int days_in_month = Utils::Time::daysInMonth(new_tm.tm_year + 1900, new_tm.tm_mon + 1);
|
||||
else if (mEditIndex == 1) {
|
||||
const int days_in_month =
|
||||
Utils::Time::daysInMonth(new_tm.tm_year + 1900, new_tm.tm_mon + 1);
|
||||
new_tm.tm_mday += incDir;
|
||||
|
||||
if(new_tm.tm_mday > days_in_month)
|
||||
if (new_tm.tm_mday > days_in_month)
|
||||
new_tm.tm_mday = 1;
|
||||
else if(new_tm.tm_mday < 1)
|
||||
else if (new_tm.tm_mday < 1)
|
||||
new_tm.tm_mday = days_in_month;
|
||||
|
||||
}
|
||||
else if(mEditIndex == 2)
|
||||
{
|
||||
else if (mEditIndex == 2) {
|
||||
new_tm.tm_year += incDir;
|
||||
|
||||
if(new_tm.tm_year < 0)
|
||||
if (new_tm.tm_year < 0)
|
||||
new_tm.tm_year = 0;
|
||||
}
|
||||
|
||||
//validate day
|
||||
const int days_in_month = Utils::Time::daysInMonth(new_tm.tm_year + 1900, new_tm.tm_mon + 1);
|
||||
if(new_tm.tm_mday > days_in_month)
|
||||
// Validate day.
|
||||
const int days_in_month =
|
||||
Utils::Time::daysInMonth(new_tm.tm_year + 1900, new_tm.tm_mon + 1);
|
||||
if (new_tm.tm_mday > days_in_month)
|
||||
new_tm.tm_mday = days_in_month;
|
||||
|
||||
mTime = new_tm;
|
||||
|
@ -102,18 +110,16 @@ bool DateTimeEditComponent::input(InputConfig* config, Input input)
|
|||
return true;
|
||||
}
|
||||
|
||||
if(config->isMappedLike("right", input))
|
||||
{
|
||||
if (config->isMappedLike("right", input)) {
|
||||
mEditIndex++;
|
||||
if(mEditIndex >= (int)mCursorBoxes.size())
|
||||
if (mEditIndex >= (int)mCursorBoxes.size())
|
||||
mEditIndex--;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(config->isMappedLike("left", input))
|
||||
{
|
||||
if (config->isMappedLike("left", input)) {
|
||||
mEditIndex--;
|
||||
if(mEditIndex < 0)
|
||||
if (mEditIndex < 0)
|
||||
mEditIndex++;
|
||||
return true;
|
||||
}
|
||||
|
@ -124,11 +130,9 @@ bool DateTimeEditComponent::input(InputConfig* config, Input input)
|
|||
|
||||
void DateTimeEditComponent::update(int deltaTime)
|
||||
{
|
||||
if(mDisplayMode == DISP_RELATIVE_TO_NOW)
|
||||
{
|
||||
if (mDisplayMode == DISP_RELATIVE_TO_NOW) {
|
||||
mRelativeUpdateAccumulator += deltaTime;
|
||||
if(mRelativeUpdateAccumulator > 1000)
|
||||
{
|
||||
if (mRelativeUpdateAccumulator > 1000) {
|
||||
mRelativeUpdateAccumulator = 0;
|
||||
updateTextCache();
|
||||
}
|
||||
|
@ -141,9 +145,8 @@ void DateTimeEditComponent::render(const Transform4x4f& parentTrans)
|
|||
{
|
||||
Transform4x4f trans = parentTrans * getTransform();
|
||||
|
||||
if(mTextCache)
|
||||
{
|
||||
// vertically center
|
||||
if (mTextCache) {
|
||||
// Vertically center.
|
||||
Vector3f off(0, (mSize.y() - mTextCache->metrics.size.y()) / 2, 0);
|
||||
trans.translate(off);
|
||||
|
||||
|
@ -154,13 +157,11 @@ void DateTimeEditComponent::render(const Transform4x4f& parentTrans)
|
|||
mTextCache->setColor((mColor & 0xFFFFFF00) | getOpacity());
|
||||
font->renderTextCache(mTextCache.get());
|
||||
|
||||
if(mEditing)
|
||||
{
|
||||
if(mEditIndex >= 0 && (unsigned int)mEditIndex < mCursorBoxes.size())
|
||||
{
|
||||
if (mEditing) {
|
||||
if (mEditIndex >= 0 && (unsigned int)mEditIndex < mCursorBoxes.size())
|
||||
Renderer::drawRect(mCursorBoxes[mEditIndex][0], mCursorBoxes[mEditIndex][1],
|
||||
mCursorBoxes[mEditIndex][2], mCursorBoxes[mEditIndex][3], 0x00000022, 0x00000022);
|
||||
}
|
||||
mCursorBoxes[mEditIndex][2], mCursorBoxes[mEditIndex][3],
|
||||
0x00000022, 0x00000022);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -178,14 +179,12 @@ std::string DateTimeEditComponent::getValue() const
|
|||
|
||||
DateTimeEditComponent::DisplayMode DateTimeEditComponent::getCurrentDisplayMode() const
|
||||
{
|
||||
/*if(mEditing)
|
||||
{
|
||||
if(mDisplayMode == DISP_RELATIVE_TO_NOW)
|
||||
{
|
||||
//TODO: if time component == 00:00:00, return DISP_DATE, else return DISP_DATE_TIME
|
||||
return DISP_DATE;
|
||||
}
|
||||
}*/
|
||||
// if (mEditing) {
|
||||
// if (mDisplayMode == DISP_RELATIVE_TO_NOW) {
|
||||
// // TODO: if time component == 00:00:00, return DISP_DATE, else return DISP_DATE_TIME.
|
||||
// return DISP_DATE;
|
||||
// }
|
||||
// }
|
||||
|
||||
return mDisplayMode;
|
||||
}
|
||||
|
@ -193,20 +192,20 @@ DateTimeEditComponent::DisplayMode DateTimeEditComponent::getCurrentDisplayMode(
|
|||
std::string DateTimeEditComponent::getDisplayString(DisplayMode mode) const
|
||||
{
|
||||
std::string fmt;
|
||||
switch(mode)
|
||||
{
|
||||
case DISP_DATE:
|
||||
switch (mode) {
|
||||
case DISP_DATE: {
|
||||
fmt = "%m/%d/%Y";
|
||||
break;
|
||||
case DISP_DATE_TIME:
|
||||
if(mTime.getTime() == 0)
|
||||
}
|
||||
case DISP_DATE_TIME: {
|
||||
if (mTime.getTime() == 0)
|
||||
return "unknown";
|
||||
fmt = "%m/%d/%Y %H:%M:%S";
|
||||
break;
|
||||
case DISP_RELATIVE_TO_NOW:
|
||||
{
|
||||
//relative time
|
||||
if(mTime.getTime() == 0)
|
||||
}
|
||||
case DISP_RELATIVE_TO_NOW: {
|
||||
// Relative time.
|
||||
if (mTime.getTime() == 0)
|
||||
return "never";
|
||||
|
||||
Utils::Time::DateTime now(Utils::Time::now());
|
||||
|
@ -214,14 +213,16 @@ std::string DateTimeEditComponent::getDisplayString(DisplayMode mode) const
|
|||
|
||||
char buf[64];
|
||||
|
||||
if(dur.getDays() > 0)
|
||||
if (dur.getDays() > 0)
|
||||
sprintf(buf, "%d day%s ago", dur.getDays(), (dur.getDays() > 1) ? "s" : "");
|
||||
else if(dur.getHours() > 0)
|
||||
else if (dur.getHours() > 0)
|
||||
sprintf(buf, "%d hour%s ago", dur.getHours(), (dur.getHours() > 1) ? "s" : "");
|
||||
else if(dur.getMinutes() > 0)
|
||||
sprintf(buf, "%d minute%s ago", dur.getMinutes(), (dur.getMinutes() > 1) ? "s" : "");
|
||||
else if (dur.getMinutes() > 0)
|
||||
sprintf(buf, "%d minute%s ago", dur.getMinutes(),
|
||||
(dur.getMinutes() > 1) ? "s" : "");
|
||||
else
|
||||
sprintf(buf, "%d second%s ago", dur.getSeconds(), (dur.getSeconds() > 1) ? "s" : "");
|
||||
sprintf(buf, "%d second%s ago", dur.getSeconds(),
|
||||
(dur.getSeconds() > 1) ? "s" : "");
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
|
@ -233,7 +234,7 @@ std::string DateTimeEditComponent::getDisplayString(DisplayMode mode) const
|
|||
|
||||
std::shared_ptr<Font> DateTimeEditComponent::getFont() const
|
||||
{
|
||||
if(mFont)
|
||||
if (mFont)
|
||||
return mFont;
|
||||
|
||||
return Font::get(FONT_SIZE_MEDIUM);
|
||||
|
@ -242,50 +243,51 @@ std::shared_ptr<Font> DateTimeEditComponent::getFont() const
|
|||
void DateTimeEditComponent::updateTextCache()
|
||||
{
|
||||
DisplayMode mode = getCurrentDisplayMode();
|
||||
const std::string dispString = mUppercase ? Utils::String::toUpper(getDisplayString(mode)) : getDisplayString(mode);
|
||||
const std::string dispString = mUppercase ?
|
||||
Utils::String::toUpper(getDisplayString(mode)) : getDisplayString(mode);
|
||||
std::shared_ptr<Font> font = getFont();
|
||||
mTextCache = std::unique_ptr<TextCache>(font->buildTextCache(dispString, 0, 0, mColor));
|
||||
|
||||
if(mAutoSize)
|
||||
{
|
||||
if (mAutoSize) {
|
||||
mSize = mTextCache->metrics.size;
|
||||
|
||||
mAutoSize = false;
|
||||
if(getParent())
|
||||
if (getParent())
|
||||
getParent()->onSizeChanged();
|
||||
}
|
||||
|
||||
//set up cursor positions
|
||||
// Set up cursor positions.
|
||||
mCursorBoxes.clear();
|
||||
|
||||
if(dispString.empty() || mode == DISP_RELATIVE_TO_NOW)
|
||||
if (dispString.empty() || mode == DISP_RELATIVE_TO_NOW)
|
||||
return;
|
||||
|
||||
//month
|
||||
// Month.
|
||||
Vector2f start(0, 0);
|
||||
Vector2f end = font->sizeText(dispString.substr(0, 2));
|
||||
Vector2f diff = end - start;
|
||||
mCursorBoxes.push_back(Vector4f(start[0], start[1], diff[0], diff[1]));
|
||||
|
||||
//day
|
||||
// Day.
|
||||
start[0] = font->sizeText(dispString.substr(0, 3)).x();
|
||||
end = font->sizeText(dispString.substr(0, 5));
|
||||
diff = end - start;
|
||||
mCursorBoxes.push_back(Vector4f(start[0], start[1], diff[0], diff[1]));
|
||||
|
||||
//year
|
||||
// Year.
|
||||
start[0] = font->sizeText(dispString.substr(0, 6)).x();
|
||||
end = font->sizeText(dispString.substr(0, 10));
|
||||
diff = end - start;
|
||||
mCursorBoxes.push_back(Vector4f(start[0], start[1], diff[0], diff[1]));
|
||||
|
||||
//if mode == DISP_DATE_TIME do times too but I don't wanna do the logic for editing times because no one will ever use it so screw it
|
||||
// The logic for handling time for 'mode = DISP_DATE_TIME' is missing, but
|
||||
// nobody will use it anyway so it's not implemented.
|
||||
}
|
||||
|
||||
void DateTimeEditComponent::setColor(unsigned int color)
|
||||
{
|
||||
mColor = color;
|
||||
if(mTextCache)
|
||||
if (mTextCache)
|
||||
mTextCache->setColor(color);
|
||||
}
|
||||
|
||||
|
@ -307,26 +309,28 @@ void DateTimeEditComponent::setUppercase(bool uppercase)
|
|||
updateTextCache();
|
||||
}
|
||||
|
||||
void DateTimeEditComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties)
|
||||
void DateTimeEditComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||
const std::string& view, const std::string& element, unsigned int properties)
|
||||
{
|
||||
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "datetime");
|
||||
if(!elem)
|
||||
|
||||
if (!elem)
|
||||
return;
|
||||
|
||||
// We set mAutoSize BEFORE calling GuiComponent::applyTheme because it calls
|
||||
// setSize(), which will call updateTextCache(), which will reset mSize if
|
||||
// mAutoSize == true, ignoring the theme's value.
|
||||
if(properties & ThemeFlags::SIZE)
|
||||
if (properties & ThemeFlags::SIZE)
|
||||
mAutoSize = !elem->has("size");
|
||||
|
||||
GuiComponent::applyTheme(theme, view, element, properties);
|
||||
|
||||
using namespace ThemeFlags;
|
||||
|
||||
if(properties & COLOR && elem->has("color"))
|
||||
if (properties & COLOR && elem->has("color"))
|
||||
setColor(elem->get<unsigned int>("color"));
|
||||
|
||||
if(properties & FORCE_UPPERCASE && elem->has("forceUppercase"))
|
||||
if (properties & FORCE_UPPERCASE && elem->has("forceUppercase"))
|
||||
setUppercase(elem->get<bool>("forceUppercase"));
|
||||
|
||||
setFont(Font::getFromTheme(elem, properties, mFont));
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// DateTimeEditComponent.h
|
||||
//
|
||||
// Date and time edit component.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_CORE_COMPONENTS_DATE_TIME_EDIT_COMPONENT_H
|
||||
#define ES_CORE_COMPONENTS_DATE_TIME_EDIT_COMPONENT_H
|
||||
|
@ -11,8 +17,7 @@ class TextCache;
|
|||
class DateTimeEditComponent : public GuiComponent
|
||||
{
|
||||
public:
|
||||
enum DisplayMode
|
||||
{
|
||||
enum DisplayMode{
|
||||
DISP_DATE,
|
||||
DISP_DATE_TIME,
|
||||
DISP_RELATIVE_TO_NOW
|
||||
|
@ -31,15 +36,21 @@ public:
|
|||
// Set how the point in time will be displayed:
|
||||
// * DISP_DATE - only display the date.
|
||||
// * DISP_DATE_TIME - display both the date and the time on that date.
|
||||
// * DISP_RELATIVE_TO_NOW - intelligently display the point in time relative to right now (e.g. "5 secs ago", "3 minutes ago", "1 day ago". Automatically updates as time marches on.
|
||||
// * DISP_RELATIVE_TO_NOW - intelligently display the point in time relative to
|
||||
// right now (e.g. "5 secs ago", "3 minutes ago", "1 day ago".
|
||||
// Automatically updates as time marches on.
|
||||
// The initial value is DISP_DATE.
|
||||
void setDisplayMode(DisplayMode mode);
|
||||
|
||||
void setColor(unsigned int color); // Text color.
|
||||
void setFont(std::shared_ptr<Font> font); // Font to display with. Default is Font::get(FONT_SIZE_MEDIUM).
|
||||
void setUppercase(bool uppercase); // Force text to be uppercase when in DISP_RELATIVE_TO_NOW mode.
|
||||
// Text color.
|
||||
void setColor(unsigned int color);
|
||||
// Font to use. Default is Font::get(FONT_SIZE_MEDIUM).
|
||||
void setFont(std::shared_ptr<Font> font);
|
||||
// Force text to be uppercase when in DISP_RELATIVE_TO_NOW mode.
|
||||
void setUppercase(bool uppercase);
|
||||
|
||||
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties) override;
|
||||
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view,
|
||||
const std::string& element, unsigned int properties) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Font> getFont() const;
|
||||
|
@ -64,7 +75,6 @@ private:
|
|||
unsigned int mColor;
|
||||
std::shared_ptr<Font> mFont;
|
||||
bool mUppercase;
|
||||
|
||||
bool mAutoSize;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// MenuComponent.cpp
|
||||
//
|
||||
// Basic component for building a menu.
|
||||
//
|
||||
|
||||
#include "components/MenuComponent.h"
|
||||
|
||||
#include "components/ButtonComponent.h"
|
||||
|
@ -8,22 +14,27 @@
|
|||
|
||||
#define TITLE_HEIGHT (mTitle->getFont()->getLetterHeight() + TITLE_VERT_PADDING)
|
||||
|
||||
MenuComponent::MenuComponent(Window* window, const char* title, const std::shared_ptr<Font>& titleFont) : GuiComponent(window),
|
||||
mBackground(window), mGrid(window, Vector2i(1, 3))
|
||||
MenuComponent::MenuComponent(
|
||||
Window* window,
|
||||
const char* title,
|
||||
const std::shared_ptr<Font>& titleFont)
|
||||
: GuiComponent(window),
|
||||
mBackground(window),
|
||||
mGrid(window, Vector2i(1, 3))
|
||||
{
|
||||
addChild(&mBackground);
|
||||
addChild(&mGrid);
|
||||
|
||||
mBackground.setImagePath(":/frame.png");
|
||||
|
||||
// set up title
|
||||
// Set up title.
|
||||
mTitle = std::make_shared<TextComponent>(mWindow);
|
||||
mTitle->setHorizontalAlignment(ALIGN_CENTER);
|
||||
mTitle->setColor(0x555555FF);
|
||||
setTitle(title, titleFont);
|
||||
mGrid.setEntry(mTitle, Vector2i(0, 0), false);
|
||||
|
||||
// set up list which will never change (externally, anyway)
|
||||
// Set up list which will never change (externally, anyway).
|
||||
mList = std::make_shared<ComponentList>(mWindow);
|
||||
mGrid.setEntry(mList, Vector2i(0, 1), true);
|
||||
|
||||
|
@ -40,10 +51,10 @@ MenuComponent::~MenuComponent()
|
|||
|
||||
void MenuComponent::save()
|
||||
{
|
||||
if(!mSaveFuncs.size())
|
||||
if (!mSaveFuncs.size())
|
||||
return;
|
||||
|
||||
for(auto it = mSaveFuncs.cbegin(); it != mSaveFuncs.cend(); it++)
|
||||
for (auto it = mSaveFuncs.cbegin(); it != mSaveFuncs.cend(); it++)
|
||||
(*it)();
|
||||
|
||||
Settings::getInstance()->saveFile();
|
||||
|
@ -57,21 +68,20 @@ void MenuComponent::setTitle(const char* title, const std::shared_ptr<Font>& fon
|
|||
|
||||
float MenuComponent::getButtonGridHeight() const
|
||||
{
|
||||
return (mButtonGrid ? mButtonGrid->getSize().y() : Font::get(FONT_SIZE_MEDIUM)->getHeight() + BUTTON_GRID_VERT_PADDING);
|
||||
return (mButtonGrid ? mButtonGrid->getSize().y()
|
||||
: Font::get(FONT_SIZE_MEDIUM)->getHeight() + BUTTON_GRID_VERT_PADDING);
|
||||
}
|
||||
|
||||
void MenuComponent::updateSize()
|
||||
{
|
||||
const float maxHeight = Renderer::getScreenHeight() * 0.75f;
|
||||
float height = TITLE_HEIGHT + mList->getTotalRowHeight() + getButtonGridHeight() + 2;
|
||||
if(height > maxHeight)
|
||||
{
|
||||
if (height > maxHeight) {
|
||||
height = TITLE_HEIGHT + getButtonGridHeight();
|
||||
int i = 0;
|
||||
while(i < mList->size())
|
||||
{
|
||||
while (i < mList->size()) {
|
||||
float rowHeight = mList->getRowHeight(i);
|
||||
if(height + rowHeight < maxHeight)
|
||||
if (height + rowHeight < maxHeight)
|
||||
height += rowHeight;
|
||||
else
|
||||
break;
|
||||
|
@ -79,7 +89,8 @@ void MenuComponent::updateSize()
|
|||
}
|
||||
}
|
||||
|
||||
float width = (float)Math::min((int)Renderer::getScreenHeight(), (int)(Renderer::getScreenWidth() * 0.90f));
|
||||
float width = (float)Math::min((int)Renderer::getScreenHeight(),
|
||||
(int)(Renderer::getScreenWidth() * 0.90f));
|
||||
setSize(width, height);
|
||||
}
|
||||
|
||||
|
@ -87,29 +98,30 @@ void MenuComponent::onSizeChanged()
|
|||
{
|
||||
mBackground.fitTo(mSize, Vector3f::Zero(), Vector2f(-32, -32));
|
||||
|
||||
// update grid row/col sizes
|
||||
// Update grid row/col sizes.
|
||||
mGrid.setRowHeightPerc(0, TITLE_HEIGHT / mSize.y());
|
||||
mGrid.setRowHeightPerc(2, getButtonGridHeight() / mSize.y());
|
||||
|
||||
mGrid.setSize(mSize);
|
||||
}
|
||||
|
||||
void MenuComponent::addButton(const std::string& name, const std::string& helpText, const std::function<void()>& callback)
|
||||
void MenuComponent::addButton(const std::string& name,
|
||||
const std::string& helpText, const std::function<void()>& callback)
|
||||
{
|
||||
mButtons.push_back(std::make_shared<ButtonComponent>(mWindow, Utils::String::toUpper(name), helpText, callback));
|
||||
mButtons.push_back(std::make_shared<ButtonComponent>
|
||||
(mWindow,Utils::String::toUpper(name), helpText, callback));
|
||||
updateGrid();
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void MenuComponent::updateGrid()
|
||||
{
|
||||
if(mButtonGrid)
|
||||
if (mButtonGrid)
|
||||
mGrid.removeEntry(mButtonGrid);
|
||||
|
||||
mButtonGrid.reset();
|
||||
|
||||
if(mButtons.size())
|
||||
{
|
||||
if (mButtons.size()) {
|
||||
mButtonGrid = makeButtonGrid(mWindow, mButtons);
|
||||
mGrid.setEntry(mButtonGrid, Vector2i(0, 2), true, false);
|
||||
}
|
||||
|
@ -120,23 +132,26 @@ std::vector<HelpPrompt> MenuComponent::getHelpPrompts()
|
|||
return mGrid.getHelpPrompts();
|
||||
}
|
||||
|
||||
std::shared_ptr<ComponentGrid> makeButtonGrid(Window* window, const std::vector< std::shared_ptr<ButtonComponent> >& buttons)
|
||||
std::shared_ptr<ComponentGrid> makeButtonGrid(Window* window,
|
||||
const std::vector< std::shared_ptr<ButtonComponent> >& buttons)
|
||||
{
|
||||
std::shared_ptr<ComponentGrid> buttonGrid = std::make_shared<ComponentGrid>(window, Vector2i((int)buttons.size(), 2));
|
||||
std::shared_ptr<ComponentGrid> buttonGrid = std::make_shared<ComponentGrid>
|
||||
(window, Vector2i((int)buttons.size(), 2));
|
||||
|
||||
float buttonGridWidth = (float)BUTTON_GRID_HORIZ_PADDING * buttons.size(); // initialize to padding
|
||||
for(int i = 0; i < (int)buttons.size(); i++)
|
||||
{
|
||||
// Initialize to padding.
|
||||
float buttonGridWidth = (float)BUTTON_GRID_HORIZ_PADDING * buttons.size();
|
||||
for (int i = 0; i < (int)buttons.size(); i++) {
|
||||
buttonGrid->setEntry(buttons.at(i), Vector2i(i, 0), true, false);
|
||||
buttonGridWidth += buttons.at(i)->getSize().x();
|
||||
}
|
||||
for(unsigned int i = 0; i < buttons.size(); i++)
|
||||
{
|
||||
buttonGrid->setColWidthPerc(i, (buttons.at(i)->getSize().x() + BUTTON_GRID_HORIZ_PADDING) / buttonGridWidth);
|
||||
}
|
||||
for (unsigned int i = 0; i < buttons.size(); i++)
|
||||
buttonGrid->setColWidthPerc(i, (buttons.at(i)->getSize().x() +
|
||||
BUTTON_GRID_HORIZ_PADDING) / buttonGridWidth);
|
||||
|
||||
buttonGrid->setSize(buttonGridWidth, buttons.at(0)->getSize().y() + BUTTON_GRID_VERT_PADDING + 2);
|
||||
buttonGrid->setRowHeightPerc(1, 2 / buttonGrid->getSize().y()); // spacer row to deal with dropshadow to make buttons look centered
|
||||
buttonGrid->setSize(buttonGridWidth, buttons.at(0)->getSize().y() +
|
||||
BUTTON_GRID_VERT_PADDING + 2);
|
||||
// Spacer row to deal with dropshadow to make buttons look centered.
|
||||
buttonGrid->setRowHeightPerc(1, 2 / buttonGrid->getSize().y());
|
||||
|
||||
return buttonGrid;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// MenuComponent.h
|
||||
//
|
||||
// Basic component for building a menu.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_CORE_COMPONENTS_MENU_COMPONENT_H
|
||||
#define ES_CORE_COMPONENTS_MENU_COMPONENT_H
|
||||
|
@ -11,7 +17,8 @@
|
|||
class ButtonComponent;
|
||||
class ImageComponent;
|
||||
|
||||
std::shared_ptr<ComponentGrid> makeButtonGrid(Window* window, const std::vector< std::shared_ptr<ButtonComponent> >& buttons);
|
||||
std::shared_ptr<ComponentGrid> makeButtonGrid(Window* window,
|
||||
const std::vector< std::shared_ptr<ButtonComponent> >& buttons);
|
||||
std::shared_ptr<ImageComponent> makeArrow(Window* window);
|
||||
|
||||
#define TITLE_VERT_PADDING (Renderer::getScreenHeight()*0.0637f)
|
||||
|
@ -19,25 +26,30 @@ std::shared_ptr<ImageComponent> makeArrow(Window* window);
|
|||
class MenuComponent : public GuiComponent
|
||||
{
|
||||
public:
|
||||
MenuComponent(Window* window, const char* title, const std::shared_ptr<Font>& titleFont = Font::get(FONT_SIZE_LARGE));
|
||||
MenuComponent(Window* window, const char* title,
|
||||
const std::shared_ptr<Font>& titleFont = Font::get(FONT_SIZE_LARGE));
|
||||
virtual ~MenuComponent(); // just calls save();
|
||||
|
||||
void save();
|
||||
void onSizeChanged() override;
|
||||
|
||||
inline void addRow(const ComponentListRow& row, bool setCursorHere = false) { mList->addRow(row, setCursorHere); updateSize(); }
|
||||
inline void addRow(const ComponentListRow& row, bool setCursorHere = false)
|
||||
{ mList->addRow(row, setCursorHere); updateSize(); }
|
||||
|
||||
inline void addWithLabel(const std::string& label, const std::shared_ptr<GuiComponent>& comp, bool setCursorHere = false, bool invert_when_selected = true)
|
||||
inline void addWithLabel(const std::string& label, const std::shared_ptr<GuiComponent>& comp,
|
||||
bool setCursorHere = false, bool invert_when_selected = true)
|
||||
{
|
||||
ComponentListRow row;
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(label), Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow,
|
||||
Utils::String::toUpper(label), Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.addElement(comp, false, invert_when_selected);
|
||||
addRow(row, setCursorHere);
|
||||
}
|
||||
|
||||
inline void addSaveFunc(const std::function<void()>& func) { mSaveFuncs.push_back(func); };
|
||||
|
||||
void addButton(const std::string& label, const std::string& helpText, const std::function<void()>& callback);
|
||||
void addButton(const std::string& label, const std::string& helpText,
|
||||
const std::function<void()>& callback);
|
||||
|
||||
void setTitle(const char* title, const std::shared_ptr<Font>& font);
|
||||
|
||||
|
|
|
@ -1,8 +1,19 @@
|
|||
//
|
||||
// SwitchComponent.cpp
|
||||
//
|
||||
// Basic switch used in the menus.
|
||||
//
|
||||
|
||||
#include "SwitchComponent.h"
|
||||
|
||||
#include "resources/Font.h"
|
||||
|
||||
SwitchComponent::SwitchComponent(Window* window, bool state) : GuiComponent(window), mImage(window), mState(state)
|
||||
SwitchComponent::SwitchComponent(
|
||||
Window* window,
|
||||
bool state)
|
||||
: GuiComponent(window),
|
||||
mImage(window),
|
||||
mState(state)
|
||||
{
|
||||
mImage.setImage(":/off.svg");
|
||||
mImage.setResize(0, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight());
|
||||
|
@ -16,8 +27,7 @@ void SwitchComponent::onSizeChanged()
|
|||
|
||||
bool SwitchComponent::input(InputConfig* config, Input input)
|
||||
{
|
||||
if(config->isMappedTo("a", input) && input.value)
|
||||
{
|
||||
if(config->isMappedTo("a", input) && input.value) {
|
||||
mState = !mState;
|
||||
onStateChanged();
|
||||
return true;
|
||||
|
@ -29,9 +39,7 @@ bool SwitchComponent::input(InputConfig* config, Input input)
|
|||
void SwitchComponent::render(const Transform4x4f& parentTrans)
|
||||
{
|
||||
Transform4x4f trans = parentTrans * getTransform();
|
||||
|
||||
mImage.render(trans);
|
||||
|
||||
renderChildren(trans);
|
||||
}
|
||||
|
||||
|
@ -54,12 +62,9 @@ std::string SwitchComponent::getValue() const
|
|||
void SwitchComponent::setValue(const std::string& statestring)
|
||||
{
|
||||
if (statestring == "true")
|
||||
{
|
||||
mState = true;
|
||||
}else
|
||||
{
|
||||
else
|
||||
mState = false;
|
||||
}
|
||||
onStateChanged();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// SwitchComponent.h
|
||||
//
|
||||
// Basic switch used in the menus.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_CORE_COMPONENTS_SWITCH_COMPONENT_H
|
||||
#define ES_CORE_COMPONENTS_SWITCH_COMPONENT_H
|
||||
|
@ -5,8 +11,7 @@
|
|||
#include "components/ImageComponent.h"
|
||||
#include "GuiComponent.h"
|
||||
|
||||
// A very simple "on/off" switch.
|
||||
// Should hopefully be switched to use images instead of text in the future.
|
||||
// A simple "on/off" switch.
|
||||
class SwitchComponent : public GuiComponent
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// TextEditComponent.cpp
|
||||
//
|
||||
// Component for editing text fields in menus.
|
||||
//
|
||||
|
||||
#include "components/TextEditComponent.h"
|
||||
|
||||
#include "resources/Font.h"
|
||||
|
@ -7,17 +13,20 @@
|
|||
#define TEXT_PADDING_VERT 2
|
||||
|
||||
#define CURSOR_REPEAT_START_DELAY 500
|
||||
#define CURSOR_REPEAT_SPEED 28 // lower is faster
|
||||
#define CURSOR_REPEAT_SPEED 28 // Lower is faster.
|
||||
|
||||
TextEditComponent::TextEditComponent(Window* window) : GuiComponent(window),
|
||||
mBox(window, ":/textinput_ninepatch.png"), mFocused(false),
|
||||
mScrollOffset(0.0f, 0.0f), mCursor(0), mEditing(false), mFont(Font::get(FONT_SIZE_MEDIUM, FONT_PATH_LIGHT)),
|
||||
mCursorRepeatDir(0)
|
||||
TextEditComponent::TextEditComponent(
|
||||
Window* window)
|
||||
: GuiComponent(window),
|
||||
mBox(window, ":/textinput_ninepatch.png"),
|
||||
mFocused(false),
|
||||
mScrollOffset(0.0f, 0.0f),
|
||||
mCursor(0), mEditing(false),
|
||||
mFont(Font::get(FONT_SIZE_MEDIUM, FONT_PATH_LIGHT)),
|
||||
mCursorRepeatDir(0)
|
||||
{
|
||||
addChild(&mBox);
|
||||
|
||||
onFocusLost();
|
||||
|
||||
setSize(4096, mFont->getHeight() + TEXT_PADDING_VERT);
|
||||
}
|
||||
|
||||
|
@ -36,7 +45,7 @@ void TextEditComponent::onFocusLost()
|
|||
void TextEditComponent::onSizeChanged()
|
||||
{
|
||||
mBox.fitTo(mSize, Vector3f::Zero(), Vector2f(-34, -32 - TEXT_PADDING_VERT));
|
||||
onTextChanged(); // wrap point probably changed
|
||||
onTextChanged(); // Wrap point probably changed.
|
||||
}
|
||||
|
||||
void TextEditComponent::setValue(const std::string& val)
|
||||
|
@ -52,18 +61,16 @@ std::string TextEditComponent::getValue() const
|
|||
|
||||
void TextEditComponent::textInput(const char* text)
|
||||
{
|
||||
if(mEditing)
|
||||
{
|
||||
if (mEditing) {
|
||||
mCursorRepeatDir = 0;
|
||||
if(text[0] == '\b')
|
||||
{
|
||||
if(mCursor > 0)
|
||||
{
|
||||
if (text[0] == '\b') {
|
||||
if (mCursor > 0) {
|
||||
size_t newCursor = Utils::String::prevCursor(mText, mCursor);
|
||||
mText.erase(mText.begin() + newCursor, mText.begin() + mCursor);
|
||||
mCursor = (unsigned int)newCursor;
|
||||
}
|
||||
}else{
|
||||
}
|
||||
else {
|
||||
mText.insert(mCursor, text);
|
||||
mCursor += (unsigned int)strlen(text);
|
||||
}
|
||||
|
@ -89,80 +96,73 @@ void TextEditComponent::stopEditing()
|
|||
|
||||
bool TextEditComponent::input(InputConfig* config, Input input)
|
||||
{
|
||||
bool const cursor_left = (config->getDeviceId() != DEVICE_KEYBOARD && config->isMappedLike("left", input)) ||
|
||||
(config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_LEFT);
|
||||
bool const cursor_right = (config->getDeviceId() != DEVICE_KEYBOARD && config->isMappedLike("right", input)) ||
|
||||
(config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_RIGHT);
|
||||
bool const cursor_left = (config->getDeviceId() != DEVICE_KEYBOARD &&
|
||||
config->isMappedLike("left", input)) || (config->getDeviceId() == DEVICE_KEYBOARD &&
|
||||
input.id == SDLK_LEFT);
|
||||
bool const cursor_right = (config->getDeviceId() != DEVICE_KEYBOARD &&
|
||||
config->isMappedLike("right", input)) || (config->getDeviceId() == DEVICE_KEYBOARD &&
|
||||
input.id == SDLK_RIGHT);
|
||||
|
||||
if(input.value == 0)
|
||||
{
|
||||
if(cursor_left || cursor_right)
|
||||
if (input.value == 0) {
|
||||
if (cursor_left || cursor_right)
|
||||
mCursorRepeatDir = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if((config->isMappedTo("a", input) || (config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_RETURN)) && mFocused && !mEditing)
|
||||
{
|
||||
if ((config->isMappedTo("a", input) || (config->getDeviceId() == DEVICE_KEYBOARD &&
|
||||
input.id == SDLK_RETURN)) && mFocused && !mEditing) {
|
||||
startEditing();
|
||||
return true;
|
||||
}
|
||||
|
||||
if(mEditing)
|
||||
{
|
||||
if(config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_RETURN)
|
||||
{
|
||||
if(isMultiline())
|
||||
{
|
||||
if (mEditing) {
|
||||
if (config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_RETURN) {
|
||||
if (isMultiline())
|
||||
textInput("\n");
|
||||
}else{
|
||||
else
|
||||
stopEditing();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if((config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_ESCAPE) || (config->getDeviceId() != DEVICE_KEYBOARD && config->isMappedTo("b", input)))
|
||||
{
|
||||
if ((config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_ESCAPE) ||
|
||||
(config->getDeviceId() != DEVICE_KEYBOARD && config->isMappedTo("b", input))) {
|
||||
stopEditing();
|
||||
return true;
|
||||
}
|
||||
|
||||
if(config->getDeviceId() != DEVICE_KEYBOARD && config->isMappedLike("up", input))
|
||||
{
|
||||
// TODO
|
||||
}else if(config->getDeviceId() != DEVICE_KEYBOARD && config->isMappedLike("down", input))
|
||||
{
|
||||
// TODO
|
||||
}else if(cursor_left || cursor_right)
|
||||
{
|
||||
if (config->getDeviceId() != DEVICE_KEYBOARD && config->isMappedLike("up", input)) {
|
||||
// TODO.
|
||||
}
|
||||
else if (config->getDeviceId() != DEVICE_KEYBOARD && config->isMappedLike("down", input)) {
|
||||
// TODO.
|
||||
}
|
||||
else if (cursor_left || cursor_right) {
|
||||
mCursorRepeatDir = cursor_left ? -1 : 1;
|
||||
mCursorRepeatTimer = -(CURSOR_REPEAT_START_DELAY - CURSOR_REPEAT_SPEED);
|
||||
moveCursor(mCursorRepeatDir);
|
||||
} else if(config->getDeviceId() == DEVICE_KEYBOARD)
|
||||
{
|
||||
switch(input.id)
|
||||
{
|
||||
case SDLK_HOME:
|
||||
setCursor(0);
|
||||
break;
|
||||
}
|
||||
else if (config->getDeviceId() == DEVICE_KEYBOARD) {
|
||||
switch (input.id) {
|
||||
case SDLK_HOME:
|
||||
setCursor(0);
|
||||
break;
|
||||
|
||||
case SDLK_END:
|
||||
setCursor(std::string::npos);
|
||||
break;
|
||||
case SDLK_END:
|
||||
setCursor(std::string::npos);
|
||||
break;
|
||||
|
||||
case SDLK_DELETE:
|
||||
if(mCursor < mText.length())
|
||||
{
|
||||
// Fake as Backspace one char to the right
|
||||
moveCursor(1);
|
||||
textInput("\b");
|
||||
}
|
||||
break;
|
||||
case SDLK_DELETE:
|
||||
if (mCursor < mText.length()) {
|
||||
// Fake as Backspace one char to the right.
|
||||
moveCursor(1);
|
||||
textInput("\b");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//consume all input when editing text
|
||||
// Consume all input when editing text.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -177,12 +177,11 @@ void TextEditComponent::update(int deltaTime)
|
|||
|
||||
void TextEditComponent::updateCursorRepeat(int deltaTime)
|
||||
{
|
||||
if(mCursorRepeatDir == 0)
|
||||
if (mCursorRepeatDir == 0)
|
||||
return;
|
||||
|
||||
mCursorRepeatTimer += deltaTime;
|
||||
while(mCursorRepeatTimer >= CURSOR_REPEAT_SPEED)
|
||||
{
|
||||
while (mCursorRepeatTimer >= CURSOR_REPEAT_SPEED) {
|
||||
moveCursor(mCursorRepeatDir);
|
||||
mCursorRepeatTimer -= CURSOR_REPEAT_SPEED;
|
||||
}
|
||||
|
@ -196,7 +195,7 @@ void TextEditComponent::moveCursor(int amt)
|
|||
|
||||
void TextEditComponent::setCursor(size_t pos)
|
||||
{
|
||||
if(pos == std::string::npos)
|
||||
if (pos == std::string::npos)
|
||||
mCursor = (unsigned int)mText.length();
|
||||
else
|
||||
mCursor = (int)pos;
|
||||
|
@ -206,36 +205,34 @@ void TextEditComponent::setCursor(size_t pos)
|
|||
|
||||
void TextEditComponent::onTextChanged()
|
||||
{
|
||||
std::string wrappedText = (isMultiline() ? mFont->wrapText(mText, getTextAreaSize().x()) : mText);
|
||||
mTextCache = std::unique_ptr<TextCache>(mFont->buildTextCache(wrappedText, 0, 0, 0x77777700 | getOpacity()));
|
||||
std::string wrappedText = (isMultiline() ?
|
||||
mFont->wrapText(mText, getTextAreaSize().x()) : mText);
|
||||
mTextCache = std::unique_ptr<TextCache>
|
||||
(mFont->buildTextCache(wrappedText, 0, 0, 0x77777700 | getOpacity()));
|
||||
|
||||
if(mCursor > (int)mText.length())
|
||||
if (mCursor > (int)mText.length())
|
||||
mCursor = (unsigned int)mText.length();
|
||||
}
|
||||
|
||||
void TextEditComponent::onCursorChanged()
|
||||
{
|
||||
if(isMultiline())
|
||||
{
|
||||
Vector2f textSize = mFont->getWrappedTextCursorOffset(mText, getTextAreaSize().x(), mCursor);
|
||||
if (isMultiline()) {
|
||||
Vector2f textSize = mFont->
|
||||
getWrappedTextCursorOffset(mText, getTextAreaSize().x(), mCursor);
|
||||
|
||||
if(mScrollOffset.y() + getTextAreaSize().y() < textSize.y() + mFont->getHeight()) //need to scroll down?
|
||||
{
|
||||
if (mScrollOffset.y() + getTextAreaSize().y() < textSize.y() +
|
||||
mFont->getHeight()) // Need to scroll down?
|
||||
mScrollOffset[1] = textSize.y() - getTextAreaSize().y() + mFont->getHeight();
|
||||
}else if(mScrollOffset.y() > textSize.y()) //need to scroll up?
|
||||
{
|
||||
else if (mScrollOffset.y() > textSize.y()) // Need to scroll up?
|
||||
mScrollOffset[1] = textSize.y();
|
||||
}
|
||||
}else{
|
||||
}
|
||||
else {
|
||||
Vector2f cursorPos = mFont->sizeText(mText.substr(0, mCursor));
|
||||
|
||||
if(mScrollOffset.x() + getTextAreaSize().x() < cursorPos.x())
|
||||
{
|
||||
if (mScrollOffset.x() + getTextAreaSize().x() < cursorPos.x())
|
||||
mScrollOffset[0] = cursorPos.x() - getTextAreaSize().x();
|
||||
}else if(mScrollOffset.x() > cursorPos.x())
|
||||
{
|
||||
else if (mScrollOffset.x() > cursorPos.x())
|
||||
mScrollOffset[0] = cursorPos.x();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,40 +241,40 @@ void TextEditComponent::render(const Transform4x4f& parentTrans)
|
|||
Transform4x4f trans = getTransform() * parentTrans;
|
||||
renderChildren(trans);
|
||||
|
||||
// text + cursor rendering
|
||||
// offset into our "text area" (padding)
|
||||
// Text + cursor rendering.
|
||||
// Offset into our "text area" (padding).
|
||||
trans.translation() += Vector3f(getTextAreaPos().x(), getTextAreaPos().y(), 0);
|
||||
|
||||
Vector2i clipPos((int)trans.translation().x(), (int)trans.translation().y());
|
||||
Vector3f dimScaled = trans * Vector3f(getTextAreaSize().x(), getTextAreaSize().y(), 0); // use "text area" size for clipping
|
||||
Vector2i clipDim((int)(dimScaled.x() - trans.translation().x()), (int)(dimScaled.y() - trans.translation().y()));
|
||||
// Use "text area" size for clipping.
|
||||
Vector3f dimScaled = trans * Vector3f(getTextAreaSize().x(), getTextAreaSize().y(), 0);
|
||||
Vector2i clipDim((int)(dimScaled.x() - trans.translation().x()), (int)(dimScaled.y() -
|
||||
trans.translation().y()));
|
||||
Renderer::pushClipRect(clipPos, clipDim);
|
||||
|
||||
trans.translate(Vector3f(-mScrollOffset.x(), -mScrollOffset.y(), 0));
|
||||
Renderer::setMatrix(trans);
|
||||
|
||||
if(mTextCache)
|
||||
{
|
||||
if (mTextCache)
|
||||
mFont->renderTextCache(mTextCache.get());
|
||||
}
|
||||
|
||||
// pop the clip early to allow the cursor to be drawn outside of the "text area"
|
||||
// Pop the clip early to allow the cursor to be drawn outside of the "text area".
|
||||
Renderer::popClipRect();
|
||||
|
||||
// draw cursor
|
||||
if(mEditing)
|
||||
{
|
||||
// Draw cursor.
|
||||
if (mEditing) {
|
||||
Vector2f cursorPos;
|
||||
if(isMultiline())
|
||||
{
|
||||
if (isMultiline()) {
|
||||
cursorPos = mFont->getWrappedTextCursorOffset(mText, getTextAreaSize().x(), mCursor);
|
||||
}else{
|
||||
}
|
||||
else {
|
||||
cursorPos = mFont->sizeText(mText.substr(0, mCursor));
|
||||
cursorPos[1] = 0;
|
||||
}
|
||||
|
||||
float cursorHeight = mFont->getHeight() * 0.8f;
|
||||
Renderer::drawRect(cursorPos.x(), cursorPos.y() + (mFont->getHeight() - cursorHeight) / 2, 2.0f, cursorHeight, 0x000000FF, 0x000000FF);
|
||||
Renderer::drawRect(cursorPos.x(), cursorPos.y() + (mFont->getHeight() -
|
||||
cursorHeight) / 2, 2.0f, cursorHeight, 0x000000FF, 0x000000FF);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,11 +296,11 @@ Vector2f TextEditComponent::getTextAreaSize() const
|
|||
std::vector<HelpPrompt> TextEditComponent::getHelpPrompts()
|
||||
{
|
||||
std::vector<HelpPrompt> prompts;
|
||||
if(mEditing)
|
||||
{
|
||||
if (mEditing) {
|
||||
prompts.push_back(HelpPrompt("up/down/left/right", "move cursor"));
|
||||
prompts.push_back(HelpPrompt("b", "stop editing"));
|
||||
}else{
|
||||
}
|
||||
else {
|
||||
prompts.push_back(HelpPrompt("a", "edit"));
|
||||
}
|
||||
return prompts;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// TextEditComponent.h
|
||||
//
|
||||
// Component for editing text fields in menus.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_CORE_COMPONENTS_TEXT_EDIT_COMPONENT_H
|
||||
#define ES_CORE_COMPONENTS_TEXT_EDIT_COMPONENT_H
|
||||
|
@ -51,7 +57,7 @@ private:
|
|||
std::string mText;
|
||||
bool mFocused;
|
||||
bool mEditing;
|
||||
unsigned int mCursor; // cursor position in characters
|
||||
unsigned int mCursor; // Cursor position in characters.
|
||||
|
||||
int mCursorRepeatTimer;
|
||||
int mCursorRepeatDir;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// TextListComponent.h
|
||||
//
|
||||
// Used for displaying and navigating the gamelists.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_APP_COMPONENTS_TEXT_LIST_COMPONENT_H
|
||||
#define ES_APP_COMPONENTS_TEXT_LIST_COMPONENT_H
|
||||
|
@ -11,13 +17,12 @@
|
|||
|
||||
class TextCache;
|
||||
|
||||
struct TextListData
|
||||
{
|
||||
struct TextListData {
|
||||
unsigned int colorId;
|
||||
std::shared_ptr<TextCache> textCache;
|
||||
};
|
||||
|
||||
//A graphical list. Supports multiple colors for rows and scrolling.
|
||||
// A graphical list. Supports multiple colors for rows and scrolling.
|
||||
template <typename T>
|
||||
class TextListComponent : public IList<TextListData, T>
|
||||
{
|
||||
|
@ -41,12 +46,12 @@ public:
|
|||
bool input(InputConfig* config, Input input) override;
|
||||
void update(int deltaTime) override;
|
||||
void render(const Transform4x4f& parentTrans) override;
|
||||
void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties) override;
|
||||
void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view,
|
||||
const std::string& element, unsigned int properties) override;
|
||||
|
||||
void add(const std::string& name, const T& obj, unsigned int colorId);
|
||||
|
||||
enum Alignment
|
||||
{
|
||||
enum Alignment {
|
||||
ALIGN_LEFT,
|
||||
ALIGN_CENTER,
|
||||
ALIGN_RIGHT
|
||||
|
@ -54,19 +59,20 @@ public:
|
|||
|
||||
inline void setAlignment(Alignment align) { mAlignment = align; }
|
||||
|
||||
inline void setCursorChangedCallback(const std::function<void(CursorState state)>& func) { mCursorChangedCallback = func; }
|
||||
inline void setCursorChangedCallback(const std::function<void(CursorState state)>& func)
|
||||
{ mCursorChangedCallback = func; }
|
||||
|
||||
inline void setFont(const std::shared_ptr<Font>& font)
|
||||
{
|
||||
mFont = font;
|
||||
for(auto it = mEntries.begin(); it != mEntries.end(); it++)
|
||||
for (auto it = mEntries.begin(); it != mEntries.end(); it++)
|
||||
it->data.textCache.reset();
|
||||
}
|
||||
|
||||
inline void setUppercase(bool /*uppercase*/)
|
||||
{
|
||||
mUppercase = true;
|
||||
for(auto it = mEntries.begin(); it != mEntries.end(); it++)
|
||||
for (auto it = mEntries.begin(); it != mEntries.end(); it++)
|
||||
it->data.textCache.reset();
|
||||
}
|
||||
|
||||
|
@ -74,7 +80,8 @@ public:
|
|||
inline void setSelectorOffsetY(float selectorOffsetY) { mSelectorOffsetY = selectorOffsetY; }
|
||||
inline void setSelectorColor(unsigned int color) { mSelectorColor = color; }
|
||||
inline void setSelectorColorEnd(unsigned int color) { mSelectorColorEnd = color; }
|
||||
inline void setSelectorColorGradientHorizontal(bool horizontal) { mSelectorColorGradientHorizontal = horizontal; }
|
||||
inline void setSelectorColorGradientHorizontal(bool horizontal)
|
||||
{ mSelectorColorGradientHorizontal = horizontal; }
|
||||
inline void setSelectedColor(unsigned int color) { mSelectedColor = color; }
|
||||
inline void setColor(unsigned int id, unsigned int color) { mColors[id] = color; }
|
||||
inline void setLineSpacing(float lineSpacing) { mLineSpacing = lineSpacing; }
|
||||
|
@ -141,90 +148,99 @@ void TextListComponent<T>::render(const Transform4x4f& parentTrans)
|
|||
|
||||
std::shared_ptr<Font>& font = mFont;
|
||||
|
||||
if(size() == 0)
|
||||
if (size() == 0)
|
||||
return;
|
||||
|
||||
const float entrySize = Math::max(font->getHeight(1.0), (float)font->getSize()) * mLineSpacing;
|
||||
|
||||
int startEntry = 0;
|
||||
|
||||
//number of entries that can fit on the screen simultaniously
|
||||
// Number of entries that can fit on the screen simultaniously.
|
||||
int screenCount = (int)(mSize.y() / entrySize + 0.5f);
|
||||
|
||||
if(size() >= screenCount)
|
||||
if (size() >= screenCount)
|
||||
{
|
||||
startEntry = mCursor - screenCount/2;
|
||||
if(startEntry < 0)
|
||||
if (startEntry < 0)
|
||||
startEntry = 0;
|
||||
if(startEntry >= size() - screenCount)
|
||||
if (startEntry >= size() - screenCount)
|
||||
startEntry = size() - screenCount;
|
||||
}
|
||||
|
||||
float y = 0;
|
||||
|
||||
int listCutoff = startEntry + screenCount;
|
||||
if(listCutoff > size())
|
||||
if (listCutoff > size())
|
||||
listCutoff = size();
|
||||
|
||||
// draw selector bar
|
||||
if(startEntry < listCutoff)
|
||||
{
|
||||
// Draw selector bar.
|
||||
if (startEntry < listCutoff) {
|
||||
if (mSelectorImage.hasImage()) {
|
||||
mSelectorImage.setPosition(0.f, (mCursor - startEntry)*entrySize + mSelectorOffsetY, 0.f);
|
||||
mSelectorImage.setPosition(0.f,
|
||||
(mCursor - startEntry)*entrySize + mSelectorOffsetY, 0.f);
|
||||
mSelectorImage.render(trans);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Renderer::setMatrix(trans);
|
||||
Renderer::drawRect(0.0f, (mCursor - startEntry)*entrySize + mSelectorOffsetY, mSize.x(),
|
||||
mSelectorHeight, mSelectorColor, mSelectorColorEnd, mSelectorColorGradientHorizontal);
|
||||
Renderer::drawRect(
|
||||
0.0f,
|
||||
(mCursor - startEntry)*entrySize +
|
||||
mSelectorOffsetY,
|
||||
mSize.x(),
|
||||
mSelectorHeight,
|
||||
mSelectorColor,
|
||||
mSelectorColorEnd,
|
||||
mSelectorColorGradientHorizontal);
|
||||
}
|
||||
}
|
||||
|
||||
// clip to inside margins
|
||||
// Clip to inside margins.
|
||||
Vector3f dim(mSize.x(), mSize.y(), 0);
|
||||
dim = trans * dim - trans.translation();
|
||||
Renderer::pushClipRect(Vector2i((int)(trans.translation().x() + mHorizontalMargin), (int)trans.translation().y()),
|
||||
Vector2i((int)(dim.x() - mHorizontalMargin*2), (int)dim.y()));
|
||||
Renderer::pushClipRect(Vector2i((int)(trans.translation().x() + mHorizontalMargin),
|
||||
(int)trans.translation().y()), Vector2i((int)(dim.x() - mHorizontalMargin*2),
|
||||
(int)dim.y()));
|
||||
|
||||
for(int i = startEntry; i < listCutoff; i++)
|
||||
{
|
||||
for (int i = startEntry; i < listCutoff; i++) {
|
||||
typename IList<TextListData, T>::Entry& entry = mEntries.at((unsigned int)i);
|
||||
|
||||
unsigned int color;
|
||||
if(mCursor == i && mSelectedColor)
|
||||
if (mCursor == i && mSelectedColor)
|
||||
color = mSelectedColor;
|
||||
else
|
||||
color = mColors[entry.data.colorId];
|
||||
|
||||
if(!entry.data.textCache)
|
||||
entry.data.textCache = std::unique_ptr<TextCache>(font->buildTextCache(mUppercase ? Utils::String::toUpper(entry.name) : entry.name, 0, 0, 0x000000FF));
|
||||
if (!entry.data.textCache)
|
||||
entry.data.textCache = std::unique_ptr<TextCache>
|
||||
(font->buildTextCache(mUppercase ?
|
||||
Utils::String::toUpper(entry.name) : entry.name, 0, 0, 0x000000FF));
|
||||
|
||||
entry.data.textCache->setColor(color);
|
||||
|
||||
Vector3f offset(0, y, 0);
|
||||
|
||||
switch(mAlignment)
|
||||
{
|
||||
switch (mAlignment) {
|
||||
case ALIGN_LEFT:
|
||||
offset[0] = mHorizontalMargin;
|
||||
break;
|
||||
case ALIGN_CENTER:
|
||||
offset[0] = (int)((mSize.x() - entry.data.textCache->metrics.size.x()) / 2);
|
||||
if(offset[0] < mHorizontalMargin)
|
||||
if (offset[0] < mHorizontalMargin)
|
||||
offset[0] = mHorizontalMargin;
|
||||
break;
|
||||
case ALIGN_RIGHT:
|
||||
offset[0] = (mSize.x() - entry.data.textCache->metrics.size.x());
|
||||
offset[0] -= mHorizontalMargin;
|
||||
if(offset[0] < mHorizontalMargin)
|
||||
if (offset[0] < mHorizontalMargin)
|
||||
offset[0] = mHorizontalMargin;
|
||||
break;
|
||||
}
|
||||
|
||||
// render text
|
||||
// Render text.
|
||||
Transform4x4f drawTrans = trans;
|
||||
|
||||
// currently selected item text might be scrolling
|
||||
if((mCursor == i) && (mMarqueeOffset > 0))
|
||||
// Currently selected item text might be scrolling.
|
||||
if ((mCursor == i) && (mMarqueeOffset > 0))
|
||||
drawTrans.translate(offset - Vector3f((float)mMarqueeOffset, 0, 0));
|
||||
else
|
||||
drawTrans.translate(offset);
|
||||
|
@ -232,10 +248,9 @@ void TextListComponent<T>::render(const Transform4x4f& parentTrans)
|
|||
Renderer::setMatrix(drawTrans);
|
||||
font->renderTextCache(entry.data.textCache.get());
|
||||
|
||||
// render currently selected item text again if
|
||||
// marquee is scrolled far enough for it to repeat
|
||||
if((mCursor == i) && (mMarqueeOffset2 < 0))
|
||||
{
|
||||
// Render currently selected item text again if marquee is
|
||||
// scrolled far enough for it to repeat.
|
||||
if ((mCursor == i) && (mMarqueeOffset2 < 0)) {
|
||||
drawTrans = trans;
|
||||
drawTrans.translate(offset - Vector3f((float)mMarqueeOffset2, 0, 0));
|
||||
Renderer::setMatrix(drawTrans);
|
||||
|
@ -246,47 +261,40 @@ void TextListComponent<T>::render(const Transform4x4f& parentTrans)
|
|||
}
|
||||
|
||||
Renderer::popClipRect();
|
||||
|
||||
listRenderTitleOverlay(trans);
|
||||
|
||||
GuiComponent::renderChildren(trans);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool TextListComponent<T>::input(InputConfig* config, Input input)
|
||||
{
|
||||
if(size() > 0)
|
||||
{
|
||||
if(input.value != 0)
|
||||
{
|
||||
if(config->isMappedLike("down", input))
|
||||
{
|
||||
if (size() > 0) {
|
||||
if (input.value != 0) {
|
||||
if (config->isMappedLike("down", input)) {
|
||||
listInput(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(config->isMappedLike("up", input))
|
||||
{
|
||||
if (config->isMappedLike("up", input)) {
|
||||
listInput(-1);
|
||||
return true;
|
||||
}
|
||||
if(config->isMappedLike("rightshoulder", input))
|
||||
{
|
||||
if (config->isMappedLike("rightshoulder", input)) {
|
||||
listInput(10);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(config->isMappedLike("leftshoulder", input))
|
||||
{
|
||||
if (config->isMappedLike("leftshoulder", input)) {
|
||||
listInput(-10);
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
if(config->isMappedLike("down", input) || config->isMappedLike("up", input) ||
|
||||
config->isMappedLike("rightshoulder", input) || config->isMappedLike("leftshoulder", input))
|
||||
{
|
||||
}
|
||||
else {
|
||||
if (config->isMappedLike("down", input) ||
|
||||
config->isMappedLike("up", input) ||
|
||||
config->isMappedLike("rightshoulder", input) ||
|
||||
config->isMappedLike("leftshoulder", input))
|
||||
stopScrolling();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,20 +306,18 @@ void TextListComponent<T>::update(int deltaTime)
|
|||
{
|
||||
listUpdate(deltaTime);
|
||||
|
||||
if(!isScrolling() && size() > 0)
|
||||
{
|
||||
// always reset the marquee offsets
|
||||
if (!isScrolling() && size() > 0) {
|
||||
// Always reset the marquee offsets.
|
||||
mMarqueeOffset = 0;
|
||||
mMarqueeOffset2 = 0;
|
||||
|
||||
// if we're not scrolling and this object's text goes outside our size, marquee it!
|
||||
// If we're not scrolling and this object's text goes outside our size, marquee it!
|
||||
const float textLength = mFont->sizeText(mEntries.at((unsigned int)mCursor).name).x();
|
||||
const float limit = mSize.x() - mHorizontalMargin * 2;
|
||||
|
||||
if(textLength > limit)
|
||||
{
|
||||
// loop
|
||||
// pixels per second ( based on nes-mini font at 1920x1080 to produce a speed of 200 )
|
||||
if (textLength > limit) {
|
||||
// Loop.
|
||||
// Pixels per second (based on nes-mini font at 1920x1080 to produce a speed of 200).
|
||||
const float speed = mFont->sizeText("ABCDEFGHIJKLMNOPQRSTUVWXYZ").x() * 0.247f;
|
||||
const float delay = 3000;
|
||||
const float scrollLength = textLength;
|
||||
|
@ -321,12 +327,13 @@ void TextListComponent<T>::update(int deltaTime)
|
|||
const int maxTime = (int)(delay + scrollTime + returnTime);
|
||||
|
||||
mMarqueeTime += deltaTime;
|
||||
while(mMarqueeTime > maxTime)
|
||||
while (mMarqueeTime > maxTime)
|
||||
mMarqueeTime -= maxTime;
|
||||
|
||||
mMarqueeOffset = (int)(Math::Scroll::loop(delay, scrollTime + returnTime, (float)mMarqueeTime, scrollLength + returnLength));
|
||||
mMarqueeOffset = (int)(Math::Scroll::loop(delay, scrollTime + returnTime,
|
||||
(float)mMarqueeTime, scrollLength + returnLength));
|
||||
|
||||
if(mMarqueeOffset > (scrollLength - (limit - returnLength)))
|
||||
if (mMarqueeOffset > (scrollLength - (limit - returnLength)))
|
||||
mMarqueeOffset2 = (int)(mMarqueeOffset - (scrollLength + returnLength));
|
||||
}
|
||||
}
|
||||
|
@ -334,7 +341,7 @@ void TextListComponent<T>::update(int deltaTime)
|
|||
GuiComponent::update(deltaTime);
|
||||
}
|
||||
|
||||
//list management stuff
|
||||
// List management stuff.
|
||||
template <typename T>
|
||||
void TextListComponent<T>::add(const std::string& name, const T& obj, unsigned int color)
|
||||
{
|
||||
|
@ -354,92 +361,89 @@ void TextListComponent<T>::onCursorChanged(const CursorState& state)
|
|||
mMarqueeOffset2 = 0;
|
||||
mMarqueeTime = 0;
|
||||
|
||||
if(mCursorChangedCallback)
|
||||
if (mCursorChangedCallback)
|
||||
mCursorChangedCallback(state);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties)
|
||||
void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||
const std::string& view, const std::string& element, unsigned int properties)
|
||||
{
|
||||
GuiComponent::applyTheme(theme, view, element, properties);
|
||||
|
||||
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "textlist");
|
||||
if(!elem)
|
||||
if (!elem)
|
||||
return;
|
||||
|
||||
using namespace ThemeFlags;
|
||||
if(properties & COLOR)
|
||||
{
|
||||
if(elem->has("selectorColor"))
|
||||
{
|
||||
if (properties & COLOR) {
|
||||
if (elem->has("selectorColor")) {
|
||||
setSelectorColor(elem->get<unsigned int>("selectorColor"));
|
||||
setSelectorColorEnd(elem->get<unsigned int>("selectorColor"));
|
||||
}
|
||||
if (elem->has("selectorColorEnd"))
|
||||
setSelectorColorEnd(elem->get<unsigned int>("selectorColorEnd"));
|
||||
if (elem->has("selectorGradientType"))
|
||||
setSelectorColorGradientHorizontal(!(elem->get<std::string>("selectorGradientType").compare("horizontal")));
|
||||
if(elem->has("selectedColor"))
|
||||
setSelectorColorGradientHorizontal(!(elem->get<std::string>
|
||||
("selectorGradientType").compare("horizontal")));
|
||||
if (elem->has("selectedColor"))
|
||||
setSelectedColor(elem->get<unsigned int>("selectedColor"));
|
||||
if(elem->has("primaryColor"))
|
||||
if (elem->has("primaryColor"))
|
||||
setColor(0, elem->get<unsigned int>("primaryColor"));
|
||||
if(elem->has("secondaryColor"))
|
||||
if (elem->has("secondaryColor"))
|
||||
setColor(1, elem->get<unsigned int>("secondaryColor"));
|
||||
}
|
||||
|
||||
setFont(Font::getFromTheme(elem, properties, mFont));
|
||||
const float selectorHeight = Math::max(mFont->getHeight(1.0), (float)mFont->getSize()) * mLineSpacing;
|
||||
const float selectorHeight = Math::max(mFont->getHeight(1.0),
|
||||
(float)mFont->getSize()) * mLineSpacing;
|
||||
setSelectorHeight(selectorHeight);
|
||||
|
||||
if(properties & ALIGNMENT)
|
||||
{
|
||||
if(elem->has("alignment"))
|
||||
{
|
||||
if (properties & ALIGNMENT) {
|
||||
if (elem->has("alignment")) {
|
||||
const std::string& str = elem->get<std::string>("alignment");
|
||||
if(str == "left")
|
||||
if (str == "left")
|
||||
setAlignment(ALIGN_LEFT);
|
||||
else if(str == "center")
|
||||
else if (str == "center")
|
||||
setAlignment(ALIGN_CENTER);
|
||||
else if(str == "right")
|
||||
else if (str == "right")
|
||||
setAlignment(ALIGN_RIGHT);
|
||||
else
|
||||
LOG(LogError) << "Unknown TextListComponent alignment \"" << str << "\"!";
|
||||
}
|
||||
if(elem->has("horizontalMargin"))
|
||||
{
|
||||
mHorizontalMargin = elem->get<float>("horizontalMargin") * (this->mParent ? this->mParent->getSize().x() : (float)Renderer::getScreenWidth());
|
||||
if (elem->has("horizontalMargin")) {
|
||||
mHorizontalMargin = elem->get<float>("horizontalMargin") *
|
||||
(this->mParent ? this->mParent->getSize().x() :
|
||||
(float)Renderer::getScreenWidth());
|
||||
}
|
||||
}
|
||||
|
||||
if(properties & FORCE_UPPERCASE && elem->has("forceUppercase"))
|
||||
if (properties & FORCE_UPPERCASE && elem->has("forceUppercase"))
|
||||
setUppercase(elem->get<bool>("forceUppercase"));
|
||||
|
||||
if(properties & LINE_SPACING)
|
||||
{
|
||||
if(elem->has("lineSpacing"))
|
||||
if (properties & LINE_SPACING) {
|
||||
if (elem->has("lineSpacing"))
|
||||
setLineSpacing(elem->get<float>("lineSpacing"));
|
||||
if(elem->has("selectorHeight"))
|
||||
{
|
||||
if (elem->has("selectorHeight"))
|
||||
setSelectorHeight(elem->get<float>("selectorHeight") * Renderer::getScreenHeight());
|
||||
}
|
||||
if(elem->has("selectorOffsetY"))
|
||||
{
|
||||
if (elem->has("selectorOffsetY")) {
|
||||
float scale = this->mParent ? this->mParent->getSize().y() : (float)Renderer::getScreenHeight();
|
||||
setSelectorOffsetY(elem->get<float>("selectorOffsetY") * scale);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
setSelectorOffsetY(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
if (elem->has("selectorImagePath"))
|
||||
{
|
||||
if (elem->has("selectorImagePath")) {
|
||||
std::string path = elem->get<std::string>("selectorImagePath");
|
||||
bool tile = elem->has("selectorImageTile") && elem->get<bool>("selectorImageTile");
|
||||
mSelectorImage.setImage(path, tile);
|
||||
mSelectorImage.setSize(mSize.x(), mSelectorHeight);
|
||||
mSelectorImage.setColorShift(mSelectorColor);
|
||||
mSelectorImage.setColorShiftEnd(mSelectorColorEnd);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
mSelectorImage.setImage("");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue