mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-04-10 19:15:13 +00:00
Added a clock element and a corresponding menu entry
This commit is contained in:
parent
c86044a6a4
commit
21110810e4
|
@ -947,6 +947,17 @@ void GuiMenu::openUIOptions()
|
|||
}
|
||||
});
|
||||
|
||||
// Display clock.
|
||||
auto displayClock = std::make_shared<SwitchComponent>();
|
||||
displayClock->setState(Settings::getInstance()->getBool("DisplayClock"));
|
||||
s->addWithLabel(_("DISPLAY CLOCK"), displayClock);
|
||||
s->addSaveFunc([displayClock, s] {
|
||||
if (displayClock->getState() != Settings::getInstance()->getBool("DisplayClock")) {
|
||||
Settings::getInstance()->setBool("DisplayClock", displayClock->getState());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
||||
// Blur background when the menu is open.
|
||||
auto menuBlurBackground = std::make_shared<SwitchComponent>();
|
||||
if (mRenderer->getScreenRotation() == 90 || mRenderer->getScreenRotation() == 270) {
|
||||
|
|
|
@ -88,6 +88,11 @@ void GamelistView::onShow()
|
|||
for (auto& video : mStaticVideoComponents)
|
||||
video->stopVideoPlayer();
|
||||
|
||||
mWindow->passClockComponents(&mClockComponents);
|
||||
|
||||
for (auto& clock : mClockComponents)
|
||||
clock->update(500);
|
||||
|
||||
mLastUpdated = nullptr;
|
||||
GuiComponent::onShow();
|
||||
|
||||
|
@ -353,9 +358,20 @@ void GamelistView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
|||
mHelpComponents.emplace_back(std::make_unique<HelpComponent>());
|
||||
mHelpComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
||||
}
|
||||
else if (element.second.type == "clock") {
|
||||
mClockComponents.emplace_back(std::make_unique<DateTimeComponent>());
|
||||
mClockComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mClockComponents.empty()) {
|
||||
// Apply a default clock if the theme does not contain any configuration for it.
|
||||
mClockComponents.emplace_back(std::make_unique<DateTimeComponent>());
|
||||
mClockComponents.back()->applyTheme(theme, "gamelist", "clock_default", ThemeFlags::ALL);
|
||||
mClockComponents.back()->update(1000);
|
||||
}
|
||||
|
||||
if (mPrimary == nullptr) {
|
||||
mTextList = std::make_unique<TextListComponent<FileData*>>();
|
||||
mPrimary = mTextList.get();
|
||||
|
|
|
@ -135,6 +135,7 @@ private:
|
|||
std::vector<std::unique_ptr<TextComponent>> mContainerTextComponents;
|
||||
std::vector<std::unique_ptr<TextComponent>> mGamelistInfoComponents;
|
||||
std::vector<std::unique_ptr<HelpComponent>> mHelpComponents;
|
||||
std::vector<std::unique_ptr<DateTimeComponent>> mClockComponents;
|
||||
};
|
||||
|
||||
#endif // ES_APP_VIEWS_GAMELIST_VIEW_H
|
||||
|
|
|
@ -246,6 +246,10 @@ std::vector<HelpPrompt> SystemView::getHelpPrompts()
|
|||
void SystemView::onCursorChanged(const CursorState& state)
|
||||
{
|
||||
mWindow->passHelpComponents(nullptr);
|
||||
mWindow->passClockComponents(&mSystemElements[mPrimary->getCursor()].clockComponents);
|
||||
|
||||
for (auto& clock : mSystemElements[mPrimary->getCursor()].clockComponents)
|
||||
clock->update(1000);
|
||||
|
||||
// Reset horizontally scrolling text.
|
||||
for (auto& text : mSystemElements[mPrimary->getCursor()].gameCountComponents)
|
||||
|
@ -727,9 +731,22 @@ void SystemView::populate()
|
|||
elements.helpComponents.back()->applyTheme(theme, "system", element.first,
|
||||
ThemeFlags::ALL);
|
||||
}
|
||||
else if (element.second.type == "clock") {
|
||||
elements.clockComponents.emplace_back(std::make_unique<DateTimeComponent>());
|
||||
elements.clockComponents.back()->applyTheme(theme, "system", element.first,
|
||||
ThemeFlags::ALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (elements.clockComponents.empty()) {
|
||||
// Apply a default clock if the theme does not contain any configuration for it.
|
||||
elements.clockComponents.emplace_back(std::make_unique<DateTimeComponent>());
|
||||
elements.clockComponents.back()->applyTheme(theme, "system", "clock_default",
|
||||
ThemeFlags::ALL);
|
||||
elements.clockComponents.back()->update(1000);
|
||||
}
|
||||
|
||||
std::stable_sort(
|
||||
elements.children.begin(), elements.children.end(),
|
||||
[](GuiComponent* a, GuiComponent* b) { return b->getZIndex() > a->getZIndex(); });
|
||||
|
@ -894,6 +911,8 @@ void SystemView::populate()
|
|||
else
|
||||
mWindow->passHelpComponents(&mSystemElements[mPrimary->getCursor()].helpComponents);
|
||||
|
||||
mWindow->passClockComponents(&mSystemElements[mPrimary->getCursor()].clockComponents);
|
||||
|
||||
mFadeTransitions = (static_cast<ViewTransitionAnimation>(Settings::getInstance()->getInt(
|
||||
"TransitionsSystemToSystem")) == ViewTransitionAnimation::FADE);
|
||||
}
|
||||
|
|
|
@ -138,6 +138,7 @@ private:
|
|||
std::vector<std::unique_ptr<DateTimeComponent>> dateTimeComponents;
|
||||
std::vector<std::unique_ptr<RatingComponent>> ratingComponents;
|
||||
std::vector<std::unique_ptr<HelpComponent>> helpComponents;
|
||||
std::vector<std::unique_ptr<DateTimeComponent>> clockComponents;
|
||||
};
|
||||
|
||||
Renderer* mRenderer;
|
||||
|
|
|
@ -222,6 +222,7 @@ void Settings::setDefaults()
|
|||
mBoolMap["ScreensaverVideoBlur"] = {false, false};
|
||||
|
||||
mBoolMap["ThemeVariantTriggers"] = {true, true};
|
||||
mBoolMap["DisplayClock"] = {false, false};
|
||||
mBoolMap["MenuBlurBackground"] = {true, true};
|
||||
mBoolMap["FoldersOnTop"] = {true, true};
|
||||
mBoolMap["FavoritesFirst"] = {true, true};
|
||||
|
|
|
@ -572,6 +572,23 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
|
|||
{"opacity", FLOAT},
|
||||
{"opacityDimmed", FLOAT},
|
||||
{"customButtonIcon", PATH}}},
|
||||
{"clock",
|
||||
{{"pos", NORMALIZED_PAIR},
|
||||
{"size", NORMALIZED_PAIR},
|
||||
{"origin", NORMALIZED_PAIR},
|
||||
{"rotation", FLOAT},
|
||||
{"rotationOrigin", NORMALIZED_PAIR},
|
||||
{"fontPath", PATH},
|
||||
{"fontSize", FLOAT},
|
||||
{"horizontalAlignment", STRING},
|
||||
{"verticalAlignment", STRING},
|
||||
{"color", COLOR},
|
||||
{"backgroundColor", COLOR},
|
||||
{"backgroundMargins", NORMALIZED_PAIR},
|
||||
{"backgroundCornerRadius", FLOAT},
|
||||
{"lineSpacing", FLOAT},
|
||||
{"format", STRING},
|
||||
{"opacity", FLOAT}}},
|
||||
{"sound",
|
||||
{{"path", PATH}}}};
|
||||
// clang-format on
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
Window::Window() noexcept
|
||||
: mRenderer {Renderer::getInstance()}
|
||||
, mHelpComponents {nullptr}
|
||||
, mClockComponents {nullptr}
|
||||
, mSplashTextPositions {0.0f, 0.0f, 0.0f, 0.0f}
|
||||
, mBackgroundOverlayOpacity {1.0f}
|
||||
, mScreensaver {nullptr}
|
||||
|
@ -442,6 +443,11 @@ void Window::update(int deltaTime)
|
|||
if (mScreensaver && mRenderScreensaver)
|
||||
mScreensaver->update(deltaTime);
|
||||
|
||||
if (mClockComponents != nullptr) {
|
||||
for (auto& clockComponent : *mClockComponents)
|
||||
clockComponent->update(deltaTime);
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
if (Settings::getInstance()->getBool("InputTouchOverlay"))
|
||||
InputOverlay::getInstance().update(deltaTime);
|
||||
|
@ -630,6 +636,11 @@ void Window::render()
|
|||
}
|
||||
}
|
||||
|
||||
if (mClockComponents != nullptr) {
|
||||
for (auto& clockComponent : *mClockComponents)
|
||||
clockComponent->render(trans);
|
||||
}
|
||||
|
||||
// Render the quick list scrolling overlay, which is triggered in IList.
|
||||
if (mListScrollOpacity != 0.0f) {
|
||||
mRenderer->setMatrix(mRenderer->getIdentity());
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "HelpPrompt.h"
|
||||
#include "InputConfig.h"
|
||||
#include "Settings.h"
|
||||
#include "components/DateTimeComponent.h"
|
||||
#include "components/HelpComponent.h"
|
||||
#include "components/ImageComponent.h"
|
||||
#include "components/TextComponent.h"
|
||||
|
@ -173,6 +174,11 @@ public:
|
|||
mHelpComponents = helpComponents;
|
||||
}
|
||||
|
||||
void passClockComponents(std::vector<std::unique_ptr<DateTimeComponent>>* clockComponents)
|
||||
{
|
||||
mClockComponents = clockComponents;
|
||||
}
|
||||
|
||||
private:
|
||||
Window() noexcept;
|
||||
~Window();
|
||||
|
@ -191,6 +197,7 @@ private:
|
|||
Renderer* mRenderer;
|
||||
std::vector<std::unique_ptr<HelpComponent>>* mHelpComponents;
|
||||
std::unique_ptr<HelpComponent> mHelp;
|
||||
std::vector<std::unique_ptr<DateTimeComponent>>* mClockComponents;
|
||||
std::unique_ptr<ImageComponent> mBackgroundOverlay;
|
||||
std::unique_ptr<ImageComponent> mSplash;
|
||||
std::unique_ptr<TextComponent> mSplashTextScanning;
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
#include "utils/StringUtil.h"
|
||||
|
||||
DateTimeComponent::DateTimeComponent()
|
||||
: mDisplayRelative {false}
|
||||
: mClockAccumulator {0}
|
||||
, mClockMode {false}
|
||||
, mDisplayRelative {false}
|
||||
{
|
||||
// ISO 8601 date format.
|
||||
setFormat("%Y-%m-%d");
|
||||
|
@ -32,6 +34,8 @@ DateTimeComponent::DateTimeComponent(const std::string& text,
|
|||
: TextComponent {text, font, color, horizontalAlignment, ALIGN_CENTER, glm::vec2 {1, 0},
|
||||
pos, size, bgcolor}
|
||||
, mRenderer {Renderer::getInstance()}
|
||||
, mClockAccumulator {0}
|
||||
, mClockMode {false}
|
||||
, mDisplayRelative {false}
|
||||
{
|
||||
// ISO 8601 date format.
|
||||
|
@ -70,6 +74,10 @@ void DateTimeComponent::onTextChanged()
|
|||
|
||||
std::string DateTimeComponent::getDisplayString() const
|
||||
{
|
||||
if (mClockMode)
|
||||
return (Utils::Time::timeToString(Utils::Time::DateTime {Utils::Time::now()}.getTime(),
|
||||
mFormat));
|
||||
|
||||
if (mDisplayRelative) {
|
||||
// Workaround to handle Unix epoch for different time zones.
|
||||
if (mTime.getTime() < 82800) {
|
||||
|
@ -116,8 +124,29 @@ std::string DateTimeComponent::getDisplayString() const
|
|||
return Utils::Time::timeToString(mTime.getTime(), mFormat);
|
||||
}
|
||||
|
||||
void DateTimeComponent::update(int deltaTime)
|
||||
{
|
||||
if (!mClockMode || (mClockMode && !Settings::getInstance()->getBool("DisplayClock")))
|
||||
return;
|
||||
|
||||
mClockAccumulator += deltaTime;
|
||||
|
||||
if (mClockAccumulator >= 500) {
|
||||
mClockAccumulator = 0;
|
||||
mTime = Utils::Time::now();
|
||||
const std::string newTime {Utils::Time::timeToString(mTime, mFormat)};
|
||||
// The setValue() function with its text cache rebuild is an expensive operation so we only
|
||||
// call this when the actual date/time string needs updating.
|
||||
if (newTime != mText)
|
||||
setValue(newTime);
|
||||
}
|
||||
}
|
||||
|
||||
void DateTimeComponent::render(const glm::mat4& parentTrans)
|
||||
{
|
||||
if (mClockMode && !Settings::getInstance()->getBool("DisplayClock"))
|
||||
return;
|
||||
|
||||
// Render the component.
|
||||
TextComponent::render(parentTrans);
|
||||
}
|
||||
|
@ -130,7 +159,25 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
using namespace ThemeFlags;
|
||||
GuiComponent::applyTheme(theme, view, element, properties);
|
||||
|
||||
const ThemeData::ThemeElement* elem {theme->getElement(view, element, "datetime")};
|
||||
std::string elementType {"datetime"};
|
||||
std::string componentName {"DateTimeComponent"};
|
||||
|
||||
if (element.substr(0, 6) == "clock_") {
|
||||
mClockMode = true;
|
||||
elementType = "clock";
|
||||
componentName = "ClockComponent";
|
||||
// Apply default clock settings as the theme may not define any configuration for it.
|
||||
setFont(Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT));
|
||||
const glm::vec2 scale {
|
||||
getParent() ? getParent()->getSize() :
|
||||
glm::vec2 {Renderer::getScreenWidth(), Renderer::getScreenHeight()}};
|
||||
setPosition(0.008f * scale.x, 0.012f * scale.y);
|
||||
mSize.y = mFont->getLetterHeight();
|
||||
setColor(0xFFFFFFFF);
|
||||
setFormat("%H:%M");
|
||||
}
|
||||
|
||||
const ThemeData::ThemeElement* elem {theme->getElement(view, element, elementType)};
|
||||
if (!elem)
|
||||
return;
|
||||
|
||||
|
@ -150,9 +197,6 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
<< element.substr(9) << "\" defined as \"" << stationary << "\"";
|
||||
}
|
||||
|
||||
if (elem->has("format"))
|
||||
setFormat(elem->get<std::string>("format"));
|
||||
|
||||
if (properties & COLOR && elem->has("color"))
|
||||
setColor(elem->get<unsigned int>("color"));
|
||||
|
||||
|
@ -182,10 +226,11 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
else if (horizontalAlignment == "right")
|
||||
setHorizontalAlignment(ALIGN_RIGHT);
|
||||
else
|
||||
LOG(LogWarning) << "DateTimeComponent: Invalid theme configuration, property "
|
||||
LOG(LogWarning) << componentName
|
||||
<< ": Invalid theme configuration, property "
|
||||
"\"horizontalAlignment\" for element \""
|
||||
<< element.substr(9) << "\" defined as \"" << horizontalAlignment
|
||||
<< "\"";
|
||||
<< element.substr(elementType == "clock" ? 6 : 9) << "\" defined as \""
|
||||
<< horizontalAlignment << "\"";
|
||||
}
|
||||
|
||||
if (properties & ALIGNMENT && elem->has("verticalAlignment")) {
|
||||
|
@ -197,9 +242,11 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
else if (verticalAlignment == "bottom")
|
||||
setVerticalAlignment(ALIGN_BOTTOM);
|
||||
else
|
||||
LOG(LogWarning) << "DateTimeComponent: Invalid theme configuration, property "
|
||||
LOG(LogWarning) << componentName
|
||||
<< ": Invalid theme configuration, property "
|
||||
"\"verticalAlignment\" for element \""
|
||||
<< element.substr(9) << "\" defined as \"" << verticalAlignment << "\"";
|
||||
<< element.substr(elementType == "clock" ? 6 : 9) << "\" defined as \""
|
||||
<< verticalAlignment << "\"";
|
||||
}
|
||||
|
||||
if (properties & METADATA && elem->has("metadata")) {
|
||||
|
@ -240,7 +287,8 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
setCapitalize(true);
|
||||
}
|
||||
else if (letterCase != "none") {
|
||||
LOG(LogWarning) << "DateTimeComponent: Invalid theme configuration, property "
|
||||
LOG(LogWarning) << componentName
|
||||
<< ": Invalid theme configuration, property "
|
||||
"\"letterCase\" for element \""
|
||||
<< element.substr(9) << "\" defined as \"" << letterCase << "\"";
|
||||
}
|
||||
|
@ -265,4 +313,9 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
|
||||
setFont(Font::getFromTheme(elem, properties, mFont, maxHeight));
|
||||
mSize = glm::round(mSize);
|
||||
|
||||
if (elem->has("format"))
|
||||
setFormat(elem->get<std::string>("format"));
|
||||
else if (mClockMode)
|
||||
setFormat("%H:%M");
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
glm::vec2 size = {0.0f, 0.0f},
|
||||
unsigned int bgcolor = 0x00000000);
|
||||
|
||||
void update(int deltaTime) override;
|
||||
void render(const glm::mat4& parentTrans) override;
|
||||
|
||||
void setValue(const std::string& val) override;
|
||||
|
@ -49,9 +50,11 @@ private:
|
|||
std::string getDisplayString() const;
|
||||
|
||||
Renderer* mRenderer;
|
||||
int mClockAccumulator;
|
||||
std::string mDefaultValue;
|
||||
Utils::Time::DateTime mTime;
|
||||
std::string mFormat;
|
||||
bool mClockMode;
|
||||
bool mDisplayRelative;
|
||||
};
|
||||
|
||||
|
|
|
@ -187,7 +187,7 @@ namespace Utils
|
|||
#else
|
||||
localtime_r(&time, &timeStruct);
|
||||
#endif
|
||||
char buf[256] = {'\0'};
|
||||
char buf[256] {'\0'};
|
||||
char* s = buf;
|
||||
|
||||
while (*f) {
|
||||
|
@ -197,7 +197,7 @@ namespace Utils
|
|||
switch (*f++) {
|
||||
// Year, including century [1970,xxxx]
|
||||
case 'Y': {
|
||||
const int year = timeStruct.tm_year + 1900;
|
||||
const int year {timeStruct.tm_year + 1900};
|
||||
*s++ = static_cast<char>((year - (year % 1000)) / 1000) + '0';
|
||||
*s++ = static_cast<char>(((year % 1000) - (year % 100)) / 100) + '0';
|
||||
*s++ = static_cast<char>(((year % 100) - (year % 10)) / 10) + '0';
|
||||
|
@ -206,7 +206,7 @@ namespace Utils
|
|||
|
||||
// Month number [00,11]
|
||||
case 'm': {
|
||||
const int mon = timeStruct.tm_mon + 1;
|
||||
const int mon {timeStruct.tm_mon + 1};
|
||||
*s++ = static_cast<char>(mon / 10) + '0';
|
||||
*s++ = static_cast<char>(mon % 10) + '0';
|
||||
} break;
|
||||
|
|
Loading…
Reference in a new issue