From 15ecfc18872a4b5c06b0b63c1149dbd3a7df7a9c Mon Sep 17 00:00:00 2001 From: Thomas Jentzsch Date: Wed, 10 Aug 2022 20:59:02 +0200 Subject: [PATCH] added multiple image searching and switching --- src/common/bspf.hxx | 59 ++++++++++++++++++++++++++++ src/gui/RomImageWidget.cxx | 79 ++++++++++++++++++++++++++++++-------- src/gui/RomImageWidget.hxx | 22 ++++++++--- 3 files changed, 139 insertions(+), 21 deletions(-) diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index 1e77ae7d2..403f8a436 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -319,6 +319,65 @@ namespace BSPF return false; } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + inline size_t matchWithJoker(const string& str, const string& pattern) + { + if(str.length() >= pattern.length()) + { + // optimize a bit + if(pattern.find('?') != string::npos) + { + for(size_t pos = 0; pos < str.length() - pattern.length() + 1; ++pos) + { + bool found = true; + + for(size_t i = 0; found && i < pattern.length(); ++i) + if(pattern[i] != str[pos + i] && pattern[i] != '?') + found = false; + + if(found) + return pos; + } + } + else + return str.find(pattern); + } + return string::npos; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + inline bool matchWithWildcards(const string& str, const string& pattern) + { + string pat = pattern; + + // remove leading and trailing '*' + size_t i = 0; + while(pat[i++] == '*'); + pat = pat.substr(i - 1); + + i = pat.length(); + while(pat[--i] == '*'); + pat.erase(i + 1); + + // Search for first '*' + const size_t pos = pat.find('*'); + + if(pos != string::npos) + { + // '*' found, split pattern into left and right part, search recursively + const string leftPat = pat.substr(0, pos); + const string rightPat = pat.substr(pos + 1); + const size_t posLeft = matchWithJoker(str, leftPat); + + if(posLeft != string::npos) + return matchWithWildcards(str.substr(pos + posLeft), rightPat); + else + return false; + } + // no further '*' found + return matchWithJoker(str, pat) != string::npos; + } + // Modify 'str', replacing all occurrences of 'from' with 'to' inline void replaceAll(string& str, const string& from, const string& to) { diff --git a/src/gui/RomImageWidget.cxx b/src/gui/RomImageWidget.cxx index a1832304c..1b383969b 100644 --- a/src/gui/RomImageWidget.cxx +++ b/src/gui/RomImageWidget.cxx @@ -24,6 +24,7 @@ #include "PNGLibrary.hxx" #include "Props.hxx" #include "PropsSet.hxx" +#include "bspf.hxx" #include "RomImageWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -99,20 +100,26 @@ void RomImageWidget::parseProperties(const FSNode& node) mySurfaceIsValid = false; #ifdef PNG_SUPPORT + // TODO: RETRON_77 + // Get a valid filename representing a snapshot file for this rom and load the snapshot const string& path = instance().snapshotLoadDir().getPath(); - // 1. Try to load snapshot by property name - mySurfaceIsValid = loadPng(path + myProperties.get(PropType::Cart_Name) + ".png"); + // 1. Try to load snapshots by property name + if(getImageList(path + myProperties.get(PropType::Cart_Name))) + mySurfaceIsValid = loadPng(myImageList[0].getPath()); + //mySurfaceIsValid = loadPng(path + myProperties.get(PropType::Cart_Name) + ".png"); if(!mySurfaceIsValid) { - // 2. If no snapshot with property name exists, try to load snapshot image by filename - mySurfaceIsValid = loadPng(path + node.getNameWithExt("") + ".png"); + // 2. If no snapshots with property name exists, try to load snapshot images by filename + if(getImageList(path + node.getNameWithExt(""))) + mySurfaceIsValid = loadPng(myImageList[0].getPath()); + //mySurfaceIsValid = loadPng(path + node.getNameWithExt("") + ".png"); if(!mySurfaceIsValid) { - // 3. If no ROM snapshot exists, try to load a default snapshot + // 3. If no ROM snapshots exist, try to load a default snapshot mySurfaceIsValid = loadPng(path + "default_snapshot.png"); } } @@ -126,6 +133,22 @@ void RomImageWidget::parseProperties(const FSNode& node) } #ifdef PNG_SUPPORT +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool RomImageWidget::getImageList(const string& filename) +{ + FSNode::NameFilter filter = ([&](const FSNode& node) { + return (!node.isDirectory() && + (node.getPath() == filename + ".png" || + BSPF::matchWithWildcards(node.getPath(), filename + "#*.png"))); + }); + + FSNode node(instance().snapshotLoadDir().getPath()); + + myImageList.clear(); + node.getChildren(myImageList, FSNode::ListMode::FilesOnly, filter, false, false); + return myImageList.size() > 0; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RomImageWidget::loadPng(const string& filename) { @@ -139,6 +162,7 @@ bool RomImageWidget::loadPng(const string& filename) instance().frameBuffer().hidpiScaleFactor(); mySurface->setDstSize(static_cast(src.w() * scale), static_cast(src.h() * scale)); + setDirty(); return true; } catch(const runtime_error& e) @@ -149,17 +173,32 @@ bool RomImageWidget::loadPng(const string& filename) } #endif +#ifdef PNG_SUPPORT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//void RomImageWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) -//{ -// if(isEnabled() && isHighlighted() -// && x >= 0 && x < _w -// && y >= static_cast(_h) + _font.getFontHeight() / 2 && y < _h) -// { -// clearFlags(Widget::FLAG_HILITED); // avoid double clicks and opened URLs -// sendCommand(kClickedCmd, 0, _id); -// } -//} +void RomImageWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) +{ + if(isEnabled() && x >= 0 && x < _w && y >= 0 && y < _h) + { + if(x < _w/2) + { + if(myImageIdx) + { + loadPng(myImageList[--myImageIdx].getPath()); + } + } + else if(myImageIdx < myImageList.size()) + { + loadPng(myImageList[++myImageIdx].getPath()); + } + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void RomImageWidget::handleMouseMoved(int x, int y) +{ + myMouseX = x; +} +#endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomImageWidget::drawWidget(bool hilite) @@ -195,5 +234,15 @@ void RomImageWidget::drawWidget(bool hilite) s.drawString(_font, mySurfaceErrorMsg, x, y, _w - 10, _textcolor); } +#ifdef PNG_SUPPORT + if(isHighlighted()) + { + // TODO: need another surface + const int xOfs = myMouseX < _w / 2 ? 10 : _w - 50; + + s.line(xOfs, _h / 2 - 10, xOfs + 20, _h / 2, kBtnTextColorHi); + } +#endif + clearDirty(); } diff --git a/src/gui/RomImageWidget.hxx b/src/gui/RomImageWidget.hxx index bc6c8826f..0af65822e 100644 --- a/src/gui/RomImageWidget.hxx +++ b/src/gui/RomImageWidget.hxx @@ -26,11 +26,6 @@ class Properties; class RomImageWidget : public Widget, public CommandSender { - public: - //enum { - // kClickedCmd = 'RIcl' - //}; - public: RomImageWidget(GuiObject *boss, const GUI::Font& font, int x, int y, int w, int h); @@ -42,11 +37,15 @@ class RomImageWidget : public Widget, public CommandSender protected: void drawWidget(bool hilite) override; - //void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; +#ifdef PNG_SUPPORT + void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; + void handleMouseMoved(int x, int y) override; +#endif private: void parseProperties(const FSNode& node); #ifdef PNG_SUPPORT + bool getImageList(const string& filename); bool loadPng(const string& filename); #endif @@ -66,6 +65,17 @@ class RomImageWidget : public Widget, public CommandSender // Indicates if an error occurred in creating/displaying the surface string mySurfaceErrorMsg; +#ifdef PNG_SUPPORT + // Contains the list of image names for the current ROM + FSList myImageList; + + // Index of currently displayed image + int myImageIdx{0}; + + // Current x-position of the mouse + int myMouseX{0}; +#endif + private: // Following constructors and assignment operators not supported RomImageWidget() = delete;