ES-DE/es-core/src/components/DateTimeComponent.cpp
2023-08-06 23:51:53 +02:00

242 lines
8.4 KiB
C++

// SPDX-License-Identifier: MIT
//
// EmulationStation Desktop Edition
// DateTimeComponent.cpp
//
// Provides the date and time, in absolute (actual date) or relative
// (delta from current date and time) form.
// Used by the gamelist views.
//
#include "components/DateTimeComponent.h"
#include "Log.h"
#include "Settings.h"
#include "utils/StringUtil.h"
DateTimeComponent::DateTimeComponent()
: mDisplayRelative {false}
{
// ISO 8601 date format.
setFormat("%Y-%m-%d");
}
DateTimeComponent::DateTimeComponent(const std::string& text,
const std::shared_ptr<Font>& font,
unsigned int color,
Alignment horizontalAlignment,
glm::vec3 pos,
glm::vec2 size,
unsigned int bgcolor)
: TextComponent {text, font, color, horizontalAlignment, ALIGN_CENTER, pos, size, bgcolor}
, mDisplayRelative {false}
{
// ISO 8601 date format.
setFormat("%Y-%m-%d");
}
void DateTimeComponent::setValue(const std::string& val)
{
mTime = val;
onTextChanged();
}
std::string DateTimeComponent::getValue() const
{
// Return time value as a string.
return mTime;
}
void DateTimeComponent::setFormat(const std::string& format)
{
mFormat = format;
onTextChanged();
}
void DateTimeComponent::setDisplayRelative(bool displayRelative)
{
mDisplayRelative = displayRelative;
onTextChanged();
}
void DateTimeComponent::onTextChanged()
{
mText = getDisplayString();
TextComponent::onTextChanged();
}
std::string DateTimeComponent::getDisplayString() const
{
if (mDisplayRelative) {
// Workaround to handle Unix epoch for different time zones.
if (mTime.getTime() < 82800) {
if (mDefaultValue == "")
return "never";
else
return mDefaultValue;
}
Utils::Time::DateTime now {Utils::Time::now()};
Utils::Time::Duration dur {now.getTime() - mTime.getTime()};
std::string buf;
if (dur.getDays() > 0)
buf = std::to_string(dur.getDays()) + " day" + // Line break.
(dur.getDays() > 1 ? "s" : "") + " ago";
else if (dur.getHours() > 0)
buf = std::to_string(dur.getHours()) + " hour" + // Line break.
(dur.getHours() > 1 ? "s" : "") + " ago";
else if (dur.getMinutes() > 0)
buf = std::to_string(dur.getMinutes()) + " minute" + // Line break.
(dur.getMinutes() > 1 ? "s" : "") + " ago";
else
buf = std::to_string(dur.getSeconds()) + " second" + // Line break.
(dur.getSeconds() > 1 || dur.getSeconds() == 0 ? "s" : "") + " ago";
return std::string(buf);
}
if (mTime.getTime() == 0) {
if (mDefaultValue == "")
return "unknown";
else
return mDefaultValue;
}
return Utils::Time::timeToString(mTime.getTime(), mFormat);
}
void DateTimeComponent::render(const glm::mat4& parentTrans)
{
// Render the component.
TextComponent::render(parentTrans);
}
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);
using namespace ThemeFlags;
const ThemeData::ThemeElement* elem {theme->getElement(view, element, "datetime")};
if (!elem)
return;
if (properties & ThemeFlags::POSITION && elem->has("stationary")) {
const std::string& stationary {elem->get<std::string>("stationary")};
if (stationary == "never")
mStationary = Stationary::NEVER;
else if (stationary == "always")
mStationary = Stationary::ALWAYS;
else if (stationary == "withinView")
mStationary = Stationary::WITHIN_VIEW;
else if (stationary == "betweenViews")
mStationary = Stationary::BETWEEN_VIEWS;
else
LOG(LogWarning) << "DateTimeComponent: Invalid theme configuration, property "
"\"stationary\" for element \""
<< 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"));
setRenderBackground(false);
if (properties & COLOR && elem->has("backgroundColor")) {
setBackgroundColor(elem->get<unsigned int>("backgroundColor"));
setRenderBackground(true);
}
if (properties & ALIGNMENT && elem->has("horizontalAlignment")) {
const std::string& horizontalAlignment {elem->get<std::string>("horizontalAlignment")};
if (horizontalAlignment == "left")
setHorizontalAlignment(ALIGN_LEFT);
else if (horizontalAlignment == "center")
setHorizontalAlignment(ALIGN_CENTER);
else if (horizontalAlignment == "right")
setHorizontalAlignment(ALIGN_RIGHT);
else
LOG(LogWarning) << "DateTimeComponent: Invalid theme configuration, property "
"\"horizontalAlignment\" for element \""
<< element.substr(9) << "\" defined as \"" << horizontalAlignment
<< "\"";
}
if (properties & ALIGNMENT && elem->has("verticalAlignment")) {
const std::string& verticalAlignment {elem->get<std::string>("verticalAlignment")};
if (verticalAlignment == "top")
setVerticalAlignment(ALIGN_TOP);
else if (verticalAlignment == "center")
setVerticalAlignment(ALIGN_CENTER);
else if (verticalAlignment == "bottom")
setVerticalAlignment(ALIGN_BOTTOM);
else
LOG(LogWarning) << "DateTimeComponent: Invalid theme configuration, property "
"\"verticalAlignment\" for element \""
<< element.substr(9) << "\" defined as \"" << verticalAlignment << "\"";
}
if (properties & METADATA && elem->has("metadata")) {
mThemeMetadata = "";
const std::string& metadata {elem->get<std::string>("metadata")};
if (metadata == "releasedate" || metadata == "lastplayed") {
if (elem->has("defaultValue")) {
const std::string& defaultValue {elem->get<std::string>("defaultValue")};
if (defaultValue == ":space:")
mDefaultValue = " ";
else
mDefaultValue = defaultValue;
}
mThemeMetadata = metadata;
}
else {
LOG(LogWarning) << "DateTimeComponent: Invalid theme configuration, property "
"\"metadata\" for element \""
<< element.substr(9) << "\" defined as \"" << metadata << "\"";
}
}
if (mThemeMetadata == "lastplayed")
setDisplayRelative(true);
if (elem->has("displayRelative"))
setDisplayRelative(elem->get<bool>("displayRelative"));
if (properties & LETTER_CASE && elem->has("letterCase")) {
const std::string& letterCase {elem->get<std::string>("letterCase")};
if (letterCase == "uppercase") {
setUppercase(true);
}
else if (letterCase == "lowercase") {
setLowercase(true);
}
else if (letterCase == "capitalize") {
setCapitalize(true);
}
else if (letterCase != "none") {
LOG(LogWarning) << "DateTimeComponent: Invalid theme configuration, property "
"\"letterCase\" for element \""
<< element.substr(9) << "\" defined as \"" << letterCase << "\"";
}
}
float maxHeight {0.0f};
if (elem->has("size")) {
const glm::vec2 size {elem->get<glm::vec2>("size")};
if (size.x != 0.0f && size.y != 0.0f)
maxHeight = mSize.y * 2.0f;
}
if (properties & LINE_SPACING && elem->has("lineSpacing"))
setLineSpacing(glm::clamp(elem->get<float>("lineSpacing"), 0.5f, 3.0f));
setFont(Font::getFromTheme(elem, properties, mFont, maxHeight, false));
}