Changed to ISO 8601 date format and tidied up the scraper search screen.

This commit is contained in:
Leon Styhre 2020-06-06 22:04:05 +02:00
parent 709e6b996e
commit f5376defe0
10 changed files with 132 additions and 81 deletions

View file

@ -379,8 +379,10 @@ void GuiScraperSearch::updateInfoPane()
// Metadata.
if (Settings::getInstance()->getBool("ScrapeRatings") &&
Settings::getInstance()->getString("Scraper") != "TheGamesDB")
Settings::getInstance()->getString("Scraper") != "TheGamesDB") {
mMD_Rating->setValue(Utils::String::toUpper(res.mdl.get("rating")));
mMD_Rating->setOpacity(255);
}
mMD_ReleaseDate->setValue(Utils::String::toUpper(res.mdl.get("releasedate")));
mMD_Developer->setText(Utils::String::toUpper(res.mdl.get("developer")));
mMD_Publisher->setText(Utils::String::toUpper(res.mdl.get("publisher")));
@ -395,9 +397,11 @@ void GuiScraperSearch::updateInfoPane()
// Metadata.
if (Settings::getInstance()->getBool("ScrapeRatings") &&
Settings::getInstance()->getString("Scraper") != "TheGamesDB")
Settings::getInstance()->getString("Scraper") != "TheGamesDB") {
mMD_Rating->setValue("");
mMD_ReleaseDate->setValue("");
mMD_Rating->setOpacity(0);
}
mMD_ReleaseDate->setValue("99990101T000000");
mMD_Developer->setText("");
mMD_Publisher->setText("");
mMD_Genre->setText("");

View file

@ -2,7 +2,7 @@
// UIModeController.cpp
//
// Handling of application user interface modes (full, kiosk and kid).
// This includes switching the mode when the UI mode passkey was used.
// This includes switching the mode when the UI mode passkey is used.
//
#include "UIModeController.h"

View file

@ -2,7 +2,7 @@
// UIModeController.h
//
// Handling of application user interface modes (full, kiosk and kid).
// This includes switching the mode when the UI mode passkey was used.
// This includes switching the mode when the UI mode passkey is used.
//
#pragma once

View file

@ -1,7 +1,7 @@
//
// ComponentGrid.cpp
//
// Providing basic layout of other components in an X*Y grid.
// Provides basic layout of components in an X*Y grid.
//
#include "components/ComponentGrid.h"

View file

@ -1,7 +1,7 @@
//
// ComponentGrid.h
//
// Providing basic layout of other components in an X*Y grid.
// Provides basic layout of components in an X*Y grid.
//
#pragma once

View file

@ -1,7 +1,9 @@
//
// DateTimeComponent.cpp
//
// Date and time component.
// 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"
@ -13,7 +15,8 @@
DateTimeComponent::DateTimeComponent(Window* window)
: TextComponent(window), mDisplayRelative(false)
{
setFormat("%m/%d/%Y");
// ISO 8601 date format.
setFormat("%Y-%m-%d");
}
DateTimeComponent::DateTimeComponent(
@ -28,7 +31,8 @@ DateTimeComponent::DateTimeComponent(
: TextComponent(window, text, font, color, align, pos, size, bgcolor),
mDisplayRelative(false)
{
setFormat("%m/%d/%Y");
// ISO 8601 date format.
setFormat("%Y-%m-%d");
}
void DateTimeComponent::setValue(const std::string& val)
@ -95,7 +99,6 @@ void DateTimeComponent::render(const Transform4x4f& parentTrans)
TextComponent::render(parentTrans);
}
void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
const std::string& view, const std::string& element, unsigned int properties)
{

View file

@ -1,7 +1,9 @@
//
// DateTimeComponent.h
//
// Date and time component.
// Provides the date and time, in absolute (actual date) or relative
// (delta from current date and time) form.
// Used by the gamelist views.
//
#pragma once
@ -13,7 +15,7 @@
class ThemeData;
// Used to display date times.
// Used to display date and time.
class DateTimeComponent : public TextComponent
{
public:

View file

@ -63,15 +63,22 @@ 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("rightshoulder", input))
incDir = 1;
else if (config->isMappedLike("down", input) || config->isMappedLike("rightshoulder", input))
else if (config->isMappedLike("down", input) || config->isMappedLike("leftshoulder", input))
incDir = -1;
if (incDir != 0) {
tm new_tm = mTime;
// ISO 8601 date format.
if (mEditIndex == 0) {
new_tm.tm_year += incDir;
if (new_tm.tm_year < 0)
new_tm.tm_year = 0;
}
else if (mEditIndex == 1) {
new_tm.tm_mon += incDir;
if (new_tm.tm_mon > 11)
@ -80,7 +87,7 @@ bool DateTimeEditComponent::input(InputConfig* config, Input input)
new_tm.tm_mon = 11;
}
else if (mEditIndex == 1) {
else if (mEditIndex == 2) {
const int days_in_month =
Utils::Time::daysInMonth(new_tm.tm_year + 1900, new_tm.tm_mon + 1);
new_tm.tm_mday += incDir;
@ -91,12 +98,6 @@ bool DateTimeEditComponent::input(InputConfig* config, Input input)
new_tm.tm_mday = days_in_month;
}
else if (mEditIndex == 2) {
new_tm.tm_year += incDir;
if (new_tm.tm_year < 0)
new_tm.tm_year = 0;
}
// Validate day.
const int days_in_month =
@ -191,16 +192,21 @@ DateTimeEditComponent::DisplayMode DateTimeEditComponent::getCurrentDisplayMode(
std::string DateTimeEditComponent::getDisplayString(DisplayMode mode) const
{
// ISO 8601 date format.
std::string fmt;
switch (mode) {
case DISP_DATE: {
fmt = "%m/%d/%Y";
if (mTime.getTime() == 0)
// The extra blankspaces are for visual alignment.
return "unknown ";
fmt = "%Y-%m-%d";
break;
}
case DISP_DATE_TIME: {
if (mTime.getTime() == 0)
return "unknown";
fmt = "%m/%d/%Y %H:%M:%S";
// The extra blankspaces are for visual alignment.
return "unknown ";
fmt = "%Y-%m-%d %H:%M:%S";
break;
}
case DISP_RELATIVE_TO_NOW: {
@ -243,8 +249,18 @@ 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);
std::string dispString;
// Hack to set date string to blank instead of 'unknown'.
// The calling function simply needs to set this string using setValue().
if (mTime.getIsoString() == "99990101T000000") {
dispString = "";
}
else {
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));
@ -256,32 +272,35 @@ void DateTimeEditComponent::updateTextCache()
getParent()->onSizeChanged();
}
if (dispString == "unknown " || dispString == "")
return;
// Set up cursor positions.
mCursorBoxes.clear();
if (dispString.empty() || mode == DISP_RELATIVE_TO_NOW)
return;
// Month.
// Year.
Vector2f start(0, 0);
Vector2f end = font->sizeText(dispString.substr(0, 2));
Vector2f end = font->sizeText(dispString.substr(0, 4));
Vector2f diff = end - start;
mCursorBoxes.push_back(Vector4f(start[0], start[1], diff[0], diff[1]));
// Day.
start[0] = font->sizeText(dispString.substr(0, 3)).x();
end = font->sizeText(dispString.substr(0, 5));
// Month.
start[0] = font->sizeText(dispString.substr(0, 5)).x();
end = font->sizeText(dispString.substr(0, 7));
diff = end - start;
mCursorBoxes.push_back(Vector4f(start[0], start[1], diff[0], diff[1]));
// Year.
start[0] = font->sizeText(dispString.substr(0, 6)).x();
// Day.
start[0] = font->sizeText(dispString.substr(0, 8)).x();
end = font->sizeText(dispString.substr(0, 10));
diff = end - start;
mCursorBoxes.push_back(Vector4f(start[0], start[1], diff[0], diff[1]));
// The logic for handling time for 'mode = DISP_DATE_TIME' is missing, but
// nobody will use it anyway so it's not implemented.
// nobody will use it anyway so it's not worthwhile implementing.
}
void DateTimeEditComponent::setColor(unsigned int color)

View file

@ -1,29 +1,38 @@
//
// RatingComponent.cpp
//
// Game rating icons.
// Used by gamelist views, metadata editor and scraper.
//
#include "components/RatingComponent.h"
#include "resources/TextureResource.h"
#include "ThemeData.h"
RatingComponent::RatingComponent(Window* window) : GuiComponent(window), mColorShift(0xFFFFFFFF), mUnfilledColor(0xFFFFFFFF)
RatingComponent::RatingComponent(Window* window) : GuiComponent(window),
mColorShift(0xFFFFFFFF), mUnfilledColor(0xFFFFFFFF)
{
mFilledTexture = TextureResource::get(":/star_filled.svg", true);
mUnfilledTexture = TextureResource::get(":/star_unfilled.svg", true);
mValue = 0.5f;
mSize = Vector2f(64 * NUM_RATING_STARS, 64);
mHideRatingComponent = false;
updateVertices();
updateColors();
}
void RatingComponent::setValue(const std::string& value)
{
if(value.empty())
{
if (value.empty()) {
mValue = 0.0f;
}else{
// Round up to the closest .1 value, i.e. to the closest half-star
}
else {
// Round up to the closest .1 value, i.e. to the closest half-icon.
mValue = Math::ceilf(stof(value) / 0.1) / 10;
if(mValue > 1.0f)
if (mValue > 1.0f)
mValue = 1.0f;
else if(mValue < 0.0f)
else if (mValue < 0.0f)
mValue = 0.0f;
}
@ -32,8 +41,8 @@ void RatingComponent::setValue(const std::string& value)
std::string RatingComponent::getValue() const
{
// do not use std::to_string here as it will use the current locale
// and that sometimes encodes decimals as commas
// Do not use std::to_string here as it will use the current locale
// and that sometimes encodes decimals as commas.
std::stringstream ss;
ss << mValue;
return ss.str();
@ -41,6 +50,12 @@ std::string RatingComponent::getValue() const
void RatingComponent::setOpacity(unsigned char opacity)
{
// Completely hide component if opacity if set to zero.
if (opacity == 0)
mHideRatingComponent = true;
else
mHideRatingComponent = false;
mOpacity = opacity;
mColorShift = (mColorShift >> 8 << 8) | mOpacity;
updateColors();
@ -49,25 +64,24 @@ void RatingComponent::setOpacity(unsigned char opacity)
void RatingComponent::setColorShift(unsigned int color)
{
mColorShift = color;
// Grab the opacity from the color shift because we may need to apply it if
// fading textures in
// Grab the opacity from the color shift because we may need
// to apply it if fading in textures.
mOpacity = color & 0xff;
updateColors();
}
void RatingComponent::onSizeChanged()
{
if(mSize.y() == 0)
if (mSize.y() == 0)
mSize[1] = mSize.x() / NUM_RATING_STARS;
else if(mSize.x() == 0)
else if (mSize.x() == 0)
mSize[0] = mSize.y() * NUM_RATING_STARS;
if(mSize.y() > 0)
{
if (mSize.y() > 0) {
size_t heightPx = (size_t)Math::round(mSize.y());
if (mFilledTexture)
mFilledTexture->rasterizeAt(heightPx, heightPx);
if(mUnfilledTexture)
if (mUnfilledTexture)
mUnfilledTexture->rasterizeAt(heightPx, heightPx);
}
@ -77,7 +91,7 @@ void RatingComponent::onSizeChanged()
void RatingComponent::updateVertices()
{
const float numStars = NUM_RATING_STARS;
const float h = getSize().y(); // is the same as a single star's width
const float h = getSize().y(); // Ss the same as a single star's width.
const float w = getSize().y() * mValue * numStars;
const float fw = getSize().y() * numStars;
const unsigned int color = Renderer::convertColor(mColorShift);
@ -92,16 +106,18 @@ void RatingComponent::updateVertices()
mVertices[6] = { { fw, 0.0f }, { numStars, 1.0f }, color };
mVertices[7] = { { fw, h }, { numStars, 0.0f }, color };
// round vertices
for(int i = 0; i < 8; ++i)
mVertices[i].pos.round();
// Round vertices.
// Disabled as it caused subtle but strange rendering errors where
// the icons changed size slightly when changing rating scores.
// for (int i = 0; i < 8; ++i)
// mVertices[i].pos.round();
}
void RatingComponent::updateColors()
{
const unsigned int color = Renderer::convertColor(mColorShift);
for(int i = 0; i < 8; ++i)
for (int i = 0; i < 8; ++i)
mVertices[i].col = color;
}
@ -110,14 +126,16 @@ void RatingComponent::render(const Transform4x4f& parentTrans)
if (!isVisible() || mFilledTexture == nullptr || mUnfilledTexture == nullptr)
return;
// If set to true, hide rating component.
if (mHideRatingComponent)
return;
Transform4x4f trans = parentTrans * getTransform();
Renderer::setMatrix(trans);
if (mUnfilledTexture->bind())
{
if (mUnfilledColor != mColorShift)
{
if (mUnfilledTexture->bind()) {
if (mUnfilledColor != mColorShift) {
const unsigned int color = Renderer::convertColor(mUnfilledColor);
for (int i = 0; i < 8; ++i)
mVertices[i].col = color;
@ -130,9 +148,7 @@ void RatingComponent::render(const Transform4x4f& parentTrans)
updateColors();
}
if (mFilledTexture->bind())
{
if (mFilledTexture->bind()) {
Renderer::drawTriangleStrips(&mVertices[0], 4);
Renderer::bindTexture(0);
}
@ -142,10 +158,9 @@ void RatingComponent::render(const Transform4x4f& parentTrans)
bool RatingComponent::input(InputConfig* config, Input input)
{
if(config->isMappedTo("a", input) && input.value != 0)
{
if (config->isMappedTo("a", input) && input.value != 0) {
mValue += (1.f/2) / NUM_RATING_STARS;
if(mValue > 1.05f)
if (mValue > 1.05f)
mValue = 0.0f;
updateVertices();
@ -154,30 +169,27 @@ bool RatingComponent::input(InputConfig* config, Input input)
return GuiComponent::input(config, input);
}
void RatingComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties)
void RatingComponent::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, "rating");
if(!elem)
if (!elem)
return;
bool imgChanged = false;
if(properties & PATH && elem->has("filledPath"))
{
if (properties & PATH && elem->has("filledPath")) {
mFilledTexture = TextureResource::get(elem->get<std::string>("filledPath"), true);
imgChanged = true;
}
if(properties & PATH && elem->has("unfilledPath"))
{
if (properties & PATH && elem->has("unfilledPath")) {
mUnfilledTexture = TextureResource::get(elem->get<std::string>("unfilledPath"), true);
imgChanged = true;
}
if (properties & COLOR)
{
if (properties & COLOR) {
if (elem->has("color"))
setColorShift(elem->get<unsigned int>("color"));
@ -187,7 +199,7 @@ void RatingComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const
mUnfilledColor = mColorShift;
}
if(imgChanged)
if (imgChanged)
onSizeChanged();
}

View file

@ -1,3 +1,10 @@
//
// RatingComponent.h
//
// Game rating icons.
// Used by gamelist views, metadata editor and scraper.
//
#pragma once
#ifndef ES_APP_COMPONENTS_RATING_COMPONENT_H
#define ES_APP_COMPONENTS_RATING_COMPONENT_H
@ -13,14 +20,15 @@ class TextureResource;
// setSize(x, y) works a little differently than you might expect:
// * (0, y != 0) - x will be automatically calculated (5*y).
// * (x != 0, 0) - y will be automatically calculated (x/5).
// * (x != 0, y != 0) - you better be sure x = y*5
// * (x != 0, y != 0) - you better be sure x = y*5.
class RatingComponent : public GuiComponent
{
public:
RatingComponent(Window* window);
std::string getValue() const override;
void setValue(const std::string& value) override; // Should be a normalized float (in the range [0..1]) - if it's not, it will be clamped.
// Should be a normalized float (in the range [0..1]) - if it's not, it will be clamped.
void setValue(const std::string& value) override;
bool input(InputConfig* config, Input input) override;
void render(const Transform4x4f& parentTrans);
@ -32,7 +40,8 @@ public:
// Multiply all pixels in the image by this color when rendering.
void setColorShift(unsigned int color);
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;
virtual std::vector<HelpPrompt> getHelpPrompts() override;
@ -46,6 +55,8 @@ private:
unsigned int mColorShift;
unsigned int mUnfilledColor;
// If set to true, the rating component is hidden.
bool mHideRatingComponent;
std::shared_ptr<TextureResource> mFilledTexture;
std::shared_ptr<TextureResource> mUnfilledTexture;