Both user changes and scraper changes are now color marked in the metadata editor.

User changes are marked with blue and scraper changes with red.
This commit is contained in:
Leon Styhre 2020-07-15 17:44:27 +02:00
parent 1b65eaac2e
commit 70d0057295
15 changed files with 174 additions and 58 deletions

View file

@ -8,7 +8,7 @@ v1.0.0
* Many quality of life improvements and removal of GUI inconsistencies * Many quality of life improvements and removal of GUI inconsistencies
* New game media file logic using a media directory with files matching the ROM names instead of pointing to the media files in gamelist.xml * New game media file logic using a media directory with files matching the ROM names instead of pointing to the media files in gamelist.xml
* Updated scraper to support additional media files, detailed configuration of what to scrape, semi-automatic mode etc. * Updated scraper to support additional media files, detailed configuration of what to scrape, semi-automatic mode etc.
* For single-game scraping, any values updated by the scraper are now highlighted using a different font color in the metadata editor * In the metadata editor, any values updated by the single-game scraper or by the user are now highlighted using a different font color
* Gamelist sorting now working as expected and is persistent throughout the application session * Gamelist sorting now working as expected and is persistent throughout the application session
* Full navigation sound support, configurable per theme * Full navigation sound support, configurable per theme
* New default theme rbsimple-DE bundled with the software, this theme is largely based on recalbox-multi by the Recalbox community * New default theme rbsimple-DE bundled with the software, this theme is largely based on recalbox-multi by the Recalbox community
@ -37,7 +37,7 @@ v1.0.0
### Bug fixes ### Bug fixes
* Metadata editor insisted that changes were made although nothing was updated * Metadata editor insisted that changes were made although nothing was updated
Note: The editor will still ask for save confirmations after automatically rounding fractional game ratings to half-star values Note: The editor will still ask for save confirmations after automatically rounding fractional game ratings to half-star values, but any time such a rounding has taken place, the rating stars will be colored green in the metadata editor to nofity the user
* Game images were sometimes scaled incorrectly * Game images were sometimes scaled incorrectly
* Non-transparent favorite icons were not rendered correctly * Non-transparent favorite icons were not rendered correctly
* Restart and power-off menu entries not working * Restart and power-off menu entries not working

View file

@ -46,8 +46,7 @@ GuiMetaDataEd::GuiMetaDataEd(
mMetaDataDecl(mdd), mMetaDataDecl(mdd),
mMetaData(md), mMetaData(md),
mSavedCallback(saveCallback), mSavedCallback(saveCallback),
mDeleteFunc(deleteFunc), mDeleteFunc(deleteFunc)
mMetadataUpdated(false)
{ {
addChild(&mBackground); addChild(&mBackground);
addChild(&mGrid); addChild(&mGrid);
@ -70,6 +69,7 @@ GuiMetaDataEd::GuiMetaDataEd(
// Populate list. // Populate list.
for (auto iter = mdd.cbegin(); iter != mdd.cend(); iter++) { for (auto iter = mdd.cbegin(); iter != mdd.cend(); iter++) {
std::shared_ptr<GuiComponent> ed; std::shared_ptr<GuiComponent> ed;
std::string originalValue;
// Don't add statistics. // Don't add statistics.
if (iter->isStatistic) if (iter->isStatistic)
@ -99,6 +99,7 @@ GuiMetaDataEd::GuiMetaDataEd(
switch (iter->type) { switch (iter->type) {
case MD_BOOL: { case MD_BOOL: {
ed = std::make_shared<SwitchComponent>(window); ed = std::make_shared<SwitchComponent>(window);
ed->setChangedColor(ICONCOLOR_USERMARKED);
row.addElement(ed, false, true); row.addElement(ed, false, true);
break; break;
} }
@ -107,7 +108,8 @@ GuiMetaDataEd::GuiMetaDataEd(
spacer->setSize(Renderer::getScreenWidth() * 0.0025f, 0); spacer->setSize(Renderer::getScreenWidth() * 0.0025f, 0);
row.addElement(spacer, false); row.addElement(spacer, false);
ed = std::make_shared<RatingComponent>(window); ed = std::make_shared<RatingComponent>(window, true);
ed->setChangedColor(ICONCOLOR_USERMARKED);
const float height = lbl->getSize().y() * 0.71f; const float height = lbl->getSize().y() * 0.71f;
ed->setSize(0, height); ed->setSize(0, height);
row.addElement(ed, false, true); row.addElement(ed, false, true);
@ -123,6 +125,7 @@ GuiMetaDataEd::GuiMetaDataEd(
row.addElement(spacer, false); row.addElement(spacer, false);
ed = std::make_shared<DateTimeEditComponent>(window); ed = std::make_shared<DateTimeEditComponent>(window);
ed->setChangedColor(TEXTCOLOR_USERMARKED);
row.addElement(ed, false); row.addElement(ed, false);
// Pass input to the actual DateTimeEditComponent instead of the spacer. // Pass input to the actual DateTimeEditComponent instead of the spacer.
@ -130,12 +133,14 @@ GuiMetaDataEd::GuiMetaDataEd(
std::placeholders::_1, std::placeholders::_2); std::placeholders::_1, std::placeholders::_2);
break; break;
} }
case MD_TIME: { // Not in use as 'lastplayed' is flagged as statistics and these are skipped.
ed = std::make_shared<DateTimeEditComponent>(window, // Let's still keep the code because it may be needed in the future.
DateTimeEditComponent::DISP_RELATIVE_TO_NOW); // case MD_TIME: {
row.addElement(ed, false); // ed = std::make_shared<DateTimeEditComponent>(window,
break; // DateTimeEditComponent::DISP_RELATIVE_TO_NOW);
} // row.addElement(ed, false);
// break;
// }
case MD_LAUNCHCOMMAND: { case MD_LAUNCHCOMMAND: {
ed = std::make_shared<TextComponent>(window, "", ed = std::make_shared<TextComponent>(window, "",
Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT); Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT);
@ -152,8 +157,17 @@ GuiMetaDataEd::GuiMetaDataEd(
bool multiLine = false; bool multiLine = false;
const std::string title = iter->displayPrompt; const std::string title = iter->displayPrompt;
auto updateVal = [ed](const std::string& newVal) {
ed->setValue(newVal); }; // OK callback (apply new value to ed). originalValue = mMetaData->get(iter->key);
// OK callback (apply new value to ed).
auto updateVal = [ed, originalValue](const std::string& newVal) {
ed->setValue(newVal);
if (newVal == originalValue)
ed->setColor(DEFAULT_TEXTCOLOR);
else
ed->setColor(TEXTCOLOR_USERMARKED);
};
std::string staticTextString = "Default value from es_systems.cfg:"; std::string staticTextString = "Default value from es_systems.cfg:";
std::string defaultLaunchCommand = scraperParams.system-> std::string defaultLaunchCommand = scraperParams.system->
@ -186,8 +200,17 @@ GuiMetaDataEd::GuiMetaDataEd(
bool multiLine = iter->type == MD_MULTILINE_STRING; bool multiLine = iter->type == MD_MULTILINE_STRING;
const std::string title = iter->displayPrompt; const std::string title = iter->displayPrompt;
originalValue = mMetaData->get(iter->key);
// OK callback (apply new value to ed). // OK callback (apply new value to ed).
auto updateVal = [ed](const std::string& newVal) { ed->setValue(newVal); }; auto updateVal = [ed, originalValue](const std::string& newVal) {
ed->setValue(newVal);
if (newVal == originalValue)
ed->setColor(DEFAULT_TEXTCOLOR);
else
ed->setColor(TEXTCOLOR_USERMARKED);
};
row.makeAcceptInputHandler([this, title, ed, updateVal, multiLine] { row.makeAcceptInputHandler([this, title, ed, updateVal, multiLine] {
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), title, mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), title,
ed->getValue(), updateVal, multiLine, "APPLY", "APPLY CHANGES?")); ed->getValue(), updateVal, multiLine, "APPLY", "APPLY CHANGES?"));
@ -217,8 +240,8 @@ GuiMetaDataEd::GuiMetaDataEd(
if (mDeleteFunc) { if (mDeleteFunc) {
auto deleteFileAndSelf = [&] { mDeleteFunc(); delete this; }; auto deleteFileAndSelf = [&] { mDeleteFunc(); delete this; };
auto deleteBtnFunc = [this, deleteFileAndSelf] { mWindow->pushGui( auto deleteBtnFunc = [this, deleteFileAndSelf] {
new GuiMsgBox(mWindow, getHelpStyle(), mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
"THIS WILL DELETE THE ACTUAL GAME FILE(S)!\nARE YOU SURE?", "THIS WILL DELETE THE ACTUAL GAME FILE(S)!\nARE YOU SURE?",
"YES", deleteFileAndSelf, "NO", nullptr)); }; "YES", deleteFileAndSelf, "NO", nullptr)); };
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "DELETE", buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "DELETE",
@ -303,19 +326,20 @@ void GuiMetaDataEd::fetchDone(const ScraperSearchResult& result)
metadata->set(key, mEditors[i]->getValue()); metadata->set(key, mEditors[i]->getValue());
} }
mMetadataUpdated = GuiScraperSearch::saveMetadata(result, *metadata); GuiScraperSearch::saveMetadata(result, *metadata);
// Update the list with the scraped metadata values. // Update the list with the scraped metadata values.
for (unsigned int i = 0; i < mEditors.size(); i++) { for (unsigned int i = 0; i < mEditors.size(); i++) {
const std::string& key = mMetaDataDecl.at(i).key; const std::string& key = mMetaDataDecl.at(i).key;
if (mEditors.at(i)->getValue() != metadata->get(key)) { if (mEditors.at(i)->getValue() != metadata->get(key)) {
if (key == "rating") { if (key == "rating")
mEditors.at(i)->setColorShift(0xDD2222FF); mEditors.at(i)->setOriginalColor(ICONCOLOR_SCRAPERMARKED);
} else
else { mEditors.at(i)->setColor(TEXTCOLOR_SCRAPERMARKED);
mEditors.at(i)->setColor(0x994444FF);
}
} }
// Save all the keys, except the following which can't be scraped.
if (key != "favorite" && key != "completed" && key != "broken" &&
key != "hidden" && key != "kidgame")
mEditors.at(i)->setValue(metadata->get(key)); mEditors.at(i)->setValue(metadata->get(key));
} }
@ -325,7 +349,7 @@ void GuiMetaDataEd::fetchDone(const ScraperSearchResult& result)
void GuiMetaDataEd::close() void GuiMetaDataEd::close()
{ {
// Find out if the user made any changes. // Find out if the user made any changes.
bool dirty = mMetadataUpdated; bool metadataUpdated = false;
for (unsigned int i = 0; i < mEditors.size(); i++) { for (unsigned int i = 0; i < mEditors.size(); i++) {
const std::string& key = mMetaDataDecl.at(i).key; const std::string& key = mMetaDataDecl.at(i).key;
std::string mMetaDataValue = mMetaData->get(key); std::string mMetaDataValue = mMetaData->get(key);
@ -337,7 +361,7 @@ void GuiMetaDataEd::close()
mMetaDataValue = "19700101T010000"; mMetaDataValue = "19700101T010000";
if (mMetaDataValue != mEditorsValue) { if (mMetaDataValue != mEditorsValue) {
dirty = true; metadataUpdated = true;
break; break;
} }
} }
@ -358,7 +382,7 @@ void GuiMetaDataEd::close()
std::function<void()> closeFunc; std::function<void()> closeFunc;
closeFunc = [this] { delete this; }; closeFunc = [this] { delete this; };
if (dirty) { if (metadataUpdated) {
// Changes were made, ask if the user wants to save them. // Changes were made, ask if the user wants to save them.
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
"SAVE CHANGES?", "SAVE CHANGES?",

View file

@ -61,7 +61,6 @@ private:
std::function<void()> mSavedCallback; std::function<void()> mSavedCallback;
std::function<void()> mDeleteFunc; std::function<void()> mDeleteFunc;
bool mMetadataUpdated;
bool mMediaFilesUpdated; bool mMediaFilesUpdated;
}; };

View file

@ -16,6 +16,14 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#define DEFAULT_TEXTCOLOR 0x777777FF
#define DEFAULT_INVERTED_TEXTCOLOR 0x444444FF
#define DEFAULT_COLORSHIFT 0xFFFFFFFF
#define ICONCOLOR_SCRAPERMARKED 0xFF5555FF
#define ICONCOLOR_USERMARKED 0x5555FFFF
#define TEXTCOLOR_SCRAPERMARKED 0x992222FF
#define TEXTCOLOR_USERMARKED 0x222299FF
class Animation; class Animation;
class AnimationController; class AnimationController;
class Font; class Font;
@ -132,6 +140,8 @@ public:
virtual void setOpacity(unsigned char opacity); virtual void setOpacity(unsigned char opacity);
virtual void setColor(unsigned int color); virtual void setColor(unsigned int color);
virtual void setColorShift(unsigned int color); virtual void setColorShift(unsigned int color);
virtual void setOriginalColor(unsigned int color) { mColorOriginalValue = color; };
virtual void setChangedColor(unsigned int color) { mColorChangedValue = color; };
virtual unsigned int getColor() const; virtual unsigned int getColor() const;
const Transform4x4f& getTransform(); const Transform4x4f& getTransform();
@ -177,6 +187,9 @@ protected:
unsigned char mColorOpacity; unsigned char mColorOpacity;
unsigned int mColorShift; unsigned int mColorShift;
unsigned int mColorShiftEnd; unsigned int mColorShiftEnd;
unsigned int mColorOriginalValue;
unsigned int mColorChangedValue;
Window* mWindow; Window* mWindow;
GuiComponent* mParent; GuiComponent* mParent;

View file

@ -203,15 +203,20 @@ void ComponentList::render(const Transform4x4f& parentTrans)
it->component->render(trans); it->component->render(trans);
} }
else { else {
// If there is a hue, average the brightness values to make // Note: I've disabled this code as it's overly complicated,
// an equivalent gray value before inverting the text. // instead we're now using a simple constant which should be
// This is not the proper way to do a BW conversion as the RGB values // good enough. Let's keep the code though if needed in the
// should not be evenly distributed, but it's definitely good enough // future for some reason.
// for this situation. // // If there is a hue, average the brightness values to make
unsigned char byteAverage = (byteRed + byteGreen + byteBlue) / 3; // // an equivalent gray value before inverting the text.
unsigned int averageColor = byteAverage << 24 | byteAverage << 16 | // // This is not the proper way to do a BW conversion as the RGB values
byteAverage << 8 | 0xFF; // // should not be evenly distributed, but it's definitely good enough
it->component->setColor(averageColor); // // for this situation.
// unsigned char byteAverage = (byteRed + byteGreen + byteBlue) / 3;
// unsigned int averageColor = byteAverage << 24 | byteAverage << 16 |
// byteAverage << 8 | 0xFF;
// it->component->setColor(averageColor);
it->component->setColor(DEFAULT_INVERTED_TEXTCOLOR);
it->component->render(trans); it->component->render(trans);
// Revert to the original color after rendering. // Revert to the original color after rendering.
it->component->setColor(origColor); it->component->setColor(origColor);
@ -221,10 +226,11 @@ void ComponentList::render(const Transform4x4f& parentTrans)
it->component->render(trans); it->component->render(trans);
} }
} }
else else {
drawAfterCursor.push_back(it->component.get()); drawAfterCursor.push_back(it->component.get());
} }
} }
}
// Custom rendering. // Custom rendering.
Renderer::setMatrix(trans); Renderer::setMatrix(trans);

View file

@ -41,7 +41,7 @@ struct ComponentListRow
elements.push_back(ComponentListElement(component, resize_width, invert_when_selected)); 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 function for making an input handler for "when the users presses A on this, do func".
inline void makeAcceptInputHandler(const std::function<void()>& func) inline void makeAcceptInputHandler(const std::function<void()>& func)
{ {
input_handler = [func](InputConfig* config, Input input) -> bool { input_handler = [func](InputConfig* config, Input input) -> bool {

View file

@ -107,6 +107,12 @@ bool DateTimeEditComponent::input(InputConfig* config, Input input)
mTime = new_tm; mTime = new_tm;
// Change the color of the text to reflect the changes.
if (mTime == mOriginalValue)
setColor(mColorOriginalValue);
else
setColor(mColorChangedValue);
updateTextCache(); updateTextCache();
return true; return true;
} }
@ -170,6 +176,7 @@ void DateTimeEditComponent::render(const Transform4x4f& parentTrans)
void DateTimeEditComponent::setValue(const std::string& val) void DateTimeEditComponent::setValue(const std::string& val)
{ {
mTime = val; mTime = val;
mOriginalValue = val;
updateTextCache(); updateTextCache();
} }

View file

@ -46,6 +46,10 @@ public:
// Text color. // Text color.
void setColor(unsigned int color) override; void setColor(unsigned int color) override;
// Font to use. Default is Font::get(FONT_SIZE_MEDIUM). // Font to use. Default is Font::get(FONT_SIZE_MEDIUM).
void setOriginalColor(unsigned int color) override { mColorOriginalValue = color; };
void setChangedColor(unsigned int color) override { mColorChangedValue = color; };
void setFont(std::shared_ptr<Font> font); void setFont(std::shared_ptr<Font> font);
// Force text to be uppercase when in DISP_RELATIVE_TO_NOW mode. // Force text to be uppercase when in DISP_RELATIVE_TO_NOW mode.
void setUppercase(bool uppercase); void setUppercase(bool uppercase);
@ -76,6 +80,10 @@ private:
std::vector<Vector4f> mCursorBoxes; std::vector<Vector4f> mCursorBoxes;
unsigned int mColor; unsigned int mColor;
Utils::Time::DateTime mOriginalValue;
unsigned int mColorOriginalValue;
unsigned int mColorChangedValue;
std::shared_ptr<Font> mFont; std::shared_ptr<Font> mFont;
bool mUppercase; bool mUppercase;
bool mAutoSize; bool mAutoSize;

View file

@ -363,7 +363,6 @@ void ImageComponent::render(const Transform4x4f& parentTrans)
// 'jump' in when it finally loads. // 'jump' in when it finally loads.
fadeIn(mTexture->bind()); fadeIn(mTexture->bind());
Renderer::drawTriangleStrips(&mVertices[0], 4); Renderer::drawTriangleStrips(&mVertices[0], 4);
} }
else { else {
LOG(LogError) << "Image texture is not initialized!"; LOG(LogError) << "Image texture is not initialized!";

View file

@ -11,8 +11,16 @@
#include "Settings.h" #include "Settings.h"
#include "ThemeData.h" #include "ThemeData.h"
RatingComponent::RatingComponent(Window* window) : GuiComponent(window), RatingComponent::RatingComponent(
mColorShift(0xFFFFFFFF), mColorShiftEnd(0xFFFFFFFF), mUnfilledColor(0xFFFFFFFF) Window* window,
bool colorizeChanges)
: GuiComponent(window),
mColorShift(DEFAULT_COLORSHIFT),
mColorShiftEnd(DEFAULT_COLORSHIFT),
mUnfilledColor(DEFAULT_COLORSHIFT),
mColorizeChanges(colorizeChanges),
mColorOriginalValue(DEFAULT_COLORSHIFT),
mColorChangedValue(DEFAULT_COLORSHIFT)
{ {
mFilledTexture = TextureResource::get(":/graphics/star_filled.svg", true); mFilledTexture = TextureResource::get(":/graphics/star_filled.svg", true);
mUnfilledTexture = TextureResource::get(":/graphics/star_unfilled.svg", true); mUnfilledTexture = TextureResource::get(":/graphics/star_unfilled.svg", true);
@ -30,6 +38,26 @@ void RatingComponent::setValue(const std::string& value)
else { else {
// Round up to the closest .1 value, i.e. to the closest half-icon. // Round up to the closest .1 value, i.e. to the closest half-icon.
mValue = Math::ceilf(stof(value) / 0.1) / 10; mValue = Math::ceilf(stof(value) / 0.1) / 10;
mOriginalValue = static_cast<int>(mValue * 10);
// If the argument to colorize the rating icons has been passed, set the
// color shift accordingly.
if (mColorizeChanges) {
if (static_cast<int>(mValue * 10) == mOriginalValue)
setColorShift(mColorOriginalValue);
else
setColorShift(mColorChangedValue);
}
// For the special situation where there is a fractional rating in the gamelist.xml
// file that has been rounded to a half-star rating, render the rating icons green.
// This should only happen if an external scraper has been used or if the file has
// been manually edited.
if (mColorizeChanges && mValue != stof(value)) {
mOriginalValue = ICONCOLOR_USERMARKED;
setColorShift(0x449944FF);
}
if (mValue > 1.0f) if (mValue > 1.0f)
mValue = 1.0f; mValue = 1.0f;
else if (mValue < 0.0f) else if (mValue < 0.0f)
@ -102,9 +130,10 @@ void RatingComponent::updateVertices()
mVertices[6] = { { fw, 0.0f }, { numStars, 1.0f }, color }; mVertices[6] = { { fw, 0.0f }, { numStars, 1.0f }, color };
mVertices[7] = { { fw, h }, { numStars, 0.0f }, color }; mVertices[7] = { { fw, h }, { numStars, 0.0f }, color };
// Round vertices.
// Disabled as it caused subtle but strange rendering errors where // Disabled this code as it caused subtle but strange rendering errors
// the icons changed size slightly when changing rating scores. // where the icons changed size slightly when changing rating scores.
// // Round vertices.
// for (int i = 0; i < 8; ++i) // for (int i = 0; i < 8; ++i)
// mVertices[i].pos.round(); // mVertices[i].pos.round();
} }
@ -162,6 +191,14 @@ bool RatingComponent::input(InputConfig* config, Input input)
if (mValue > 1.05f) if (mValue > 1.05f)
mValue = 0.0f; mValue = 0.0f;
// If the argument to colorize the rating icons has been passed,
// set the color shift accordingly.
if (mColorizeChanges) {
if (static_cast<int>(mValue * 10) == mOriginalValue)
setColorShift(mColorOriginalValue);
else
setColorShift(mColorChangedValue);
}
updateVertices(); updateVertices();
} }

View file

@ -24,7 +24,7 @@ class TextureResource;
class RatingComponent : public GuiComponent class RatingComponent : public GuiComponent
{ {
public: public:
RatingComponent(Window* window); RatingComponent(Window* window, bool colorizeChanges = false);
std::string getValue() const override; std::string getValue() const 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.
@ -40,6 +40,9 @@ public:
// Multiply all pixels in the image by this color when rendering. // Multiply all pixels in the image by this color when rendering.
void setColorShift(unsigned int color) override; void setColorShift(unsigned int color) override;
void setOriginalColor(unsigned int color) override { mColorOriginalValue = color; };
void setChangedColor(unsigned int color) override { mColorChangedValue = color; };
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, virtual void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view,
const std::string& element, unsigned int properties) override; const std::string& element, unsigned int properties) override;
@ -52,6 +55,9 @@ private:
void updateColors(); void updateColors();
float mValue; float mValue;
int mOriginalValue;
unsigned int mColorOriginalValue;
unsigned int mColorChangedValue;
Renderer::Vertex mVertices[8]; Renderer::Vertex mVertices[8];
@ -61,6 +67,8 @@ private:
std::shared_ptr<TextureResource> mFilledTexture; std::shared_ptr<TextureResource> mFilledTexture;
std::shared_ptr<TextureResource> mUnfilledTexture; std::shared_ptr<TextureResource> mUnfilledTexture;
bool mColorizeChanges;
}; };
#endif // ES_APP_COMPONENTS_RATING_COMPONENT_H #endif // ES_APP_COMPONENTS_RATING_COMPONENT_H

View file

@ -13,7 +13,9 @@ SwitchComponent::SwitchComponent(
bool state) bool state)
: GuiComponent(window), : GuiComponent(window),
mImage(window), mImage(window),
mState(state) mState(state),
mColorOriginalValue(DEFAULT_COLORSHIFT),
mColorChangedValue(DEFAULT_COLORSHIFT)
{ {
mImage.setImage(":/graphics/off.svg"); mImage.setImage(":/graphics/off.svg");
mImage.setResize(0, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()); mImage.setResize(0, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight());
@ -65,12 +67,20 @@ void SwitchComponent::setValue(const std::string& statestring)
mState = true; mState = true;
else else
mState = false; mState = false;
mOriginalValue = mState;
onStateChanged(); onStateChanged();
} }
void SwitchComponent::onStateChanged() void SwitchComponent::onStateChanged()
{ {
mImage.setImage(mState ? ":/graphics/on.svg" : ":/graphics/off.svg"); mImage.setImage(mState ? ":/graphics/on.svg" : ":/graphics/off.svg");
// Change the color of the switch to reflect the changes.
if (mState == mOriginalValue)
mImage.setColorShift(mColorOriginalValue);
else
mImage.setColorShift(mColorChangedValue);
} }
std::vector<HelpPrompt> SwitchComponent::getHelpPrompts() std::vector<HelpPrompt> SwitchComponent::getHelpPrompts()

View file

@ -26,6 +26,9 @@ public:
std::string getValue() const override; std::string getValue() const override;
void setValue(const std::string& statestring) override; void setValue(const std::string& statestring) override;
void setOriginalColor(unsigned int color) override { mColorOriginalValue = color; };
void setChangedColor(unsigned int color) override { mColorChangedValue = color; };
virtual std::vector<HelpPrompt> getHelpPrompts() override; virtual std::vector<HelpPrompt> getHelpPrompts() override;
private: private:
@ -33,6 +36,9 @@ private:
ImageComponent mImage; ImageComponent mImage;
bool mState; bool mState;
bool mOriginalValue;
unsigned int mColorOriginalValue;
unsigned int mColorChangedValue;
}; };
#endif // ES_CORE_COMPONENTS_SWITCH_COMPONENT_H #endif // ES_CORE_COMPONENTS_SWITCH_COMPONENT_H

View file

@ -88,10 +88,9 @@ void TextComponent::setRenderBackground(bool render)
// Scale the opacity. // Scale the opacity.
void TextComponent::setOpacity(unsigned char opacity) void TextComponent::setOpacity(unsigned char opacity)
{ {
// This method is mostly called to do fading in-out of the Text component element. // This function is mostly called to do fading in-out of the Text component element.
// Therefore, we assume here that opacity is a fractional value (expressed as an int 0-255), // Therefore, we assume here that opacity is a fractional value (expressed as an int 0-255),
// of the opacity originally set with setColor() or setBackgroundColor(). // of the opacity originally set with setColor() or setBackgroundColor().
unsigned char o = (unsigned char)((float)opacity / 255.f * (float) mColorOpacity); unsigned char o = (unsigned char)((float)opacity / 255.f * (float) mColorOpacity);
mColor = (mColor & 0xFFFFFF00) | (unsigned char) o; mColor = (mColor & 0xFFFFFF00) | (unsigned char) o;