diff --git a/src/gui/FileListWidget.cxx b/src/gui/FileListWidget.cxx index 7c3cfae4e..610965d10 100644 --- a/src/gui/FileListWidget.cxx +++ b/src/gui/FileListWidget.cxx @@ -314,7 +314,7 @@ bool FileListWidget::handleKeyDown(StellaKey key, StellaMod mod) { handled = true; #ifdef DEBUG_BUILD - cerr << " " << mod << ", " << key << endl; + cerr << " FileListWidget::handleKeyDown " << mod << ", " << key << endl; #endif switch(key) { diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index cb82087a7..16564fb19 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -476,7 +476,7 @@ void LauncherDialog::tick() reload(); if(myPendingRomInfo && myRomInfoTime < TimerManager::getTicks() / 1000) - loadRomInfo(true); + loadPendingRomInfo(); Dialog::tick(); } @@ -515,7 +515,7 @@ void LauncherDialog::loadConfig() } Dialog::setFocus(getFocusList()[mySelectedItem]); - if(myRomInfoWidget) + if(myRomImageWidget && myRomInfoWidget) { myRomImageWidget->reloadProperties(currentNode()); myRomInfoWidget->reloadProperties(currentNode()); @@ -551,10 +551,7 @@ void LauncherDialog::updateUI() << (myShortCount ? " items" : " items found"); myRomCount->setLabel(buf.str()); - // Update ROM info UI item, delayed - myRomInfoTime = TimerManager::getTicks() / 1000 + 250; // TODO: define delay - myPendingRomInfo = true; - loadRomInfo(false); + loadRomInfo(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -673,23 +670,41 @@ void LauncherDialog::setRomInfoFont(const Common::Size& area) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void LauncherDialog::loadRomInfo(bool complete) +void LauncherDialog::loadRomInfo() { - myPendingRomInfo = !complete; + if(!myRomImageWidget || !myRomInfoWidget) + return; - if(!myRomImageWidget || !myROMInfoFont) + // Update ROM info UI item, delayed + myRomInfoTime = TimerManager::getTicks() / 1000 + 250; // TODO: define pending load delay + myPendingRomInfo = true; + + const string& md5 = selectedRomMD5(); + if(md5 != EmptyString) + { + myRomImageWidget->setProperties(currentNode(), md5, false); + myRomInfoWidget->setProperties(currentNode(), md5, false); + } + else + { + myRomImageWidget->clearProperties(); + myRomInfoWidget->clearProperties(); + } +} + +// -------------------------------------- +void LauncherDialog::loadPendingRomInfo() +{ + myPendingRomInfo = false; + + if(!myRomImageWidget || !myRomInfoWidget) return; const string& md5 = selectedRomMD5(); if(md5 != EmptyString) { - myRomImageWidget->setProperties(currentNode(), md5, complete); - myRomInfoWidget->setProperties(currentNode(), md5); // TODO: skip controller detector? - } - else if(!complete) - { - myRomImageWidget->clearProperties(); - myRomInfoWidget->clearProperties(); + myRomImageWidget->setProperties(currentNode(), md5); + myRomInfoWidget->setProperties(currentNode(), md5); } } diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index a1297ced8..e645f4a3f 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -146,7 +146,8 @@ class LauncherDialog : public Dialog, CommandSender void setRomInfoFont(const Common::Size& area); void loadRom(); - void loadRomInfo(bool complete); + void loadRomInfo(); + void loadPendingRomInfo(); void openSettings(); void openGameProperties(); void openContextMenu(int x = -1, int y = -1); diff --git a/src/gui/RomImageWidget.cxx b/src/gui/RomImageWidget.cxx index 23a513902..a1368f369 100644 --- a/src/gui/RomImageWidget.cxx +++ b/src/gui/RomImageWidget.cxx @@ -15,8 +15,8 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include #include "EventHandler.hxx" -#include "FrameBuffer.hxx" #include "Dialog.hxx" #include "FBSurface.hxx" #include "Font.hxx" @@ -24,7 +24,6 @@ #include "PNGLibrary.hxx" #include "Props.hxx" #include "PropsSet.hxx" -#include "bspf.hxx" #include "RomImageWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -40,7 +39,7 @@ RomImageWidget::RomImageWidget(GuiObject* boss, const GUI::Font& font, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void RomImageWidget::setProperties(const FSNode& node, const string& md5, bool complete) +void RomImageWidget::setProperties(const FSNode& node, const string& md5, bool full) { myHaveProperties = true; @@ -52,7 +51,7 @@ void RomImageWidget::setProperties(const FSNode& node, const string& md5, bool c // Decide whether the information should be shown immediately if(instance().eventHandler().state() == EventHandlerState::LAUNCHER) - parseProperties(node, complete); + parseProperties(node, full); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -74,11 +73,11 @@ void RomImageWidget::reloadProperties(const FSNode& node) // by saving a different image or through a change in video renderer, // so we reload the properties if(myHaveProperties) - parseProperties(node, true); + parseProperties(node); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void RomImageWidget::parseProperties(const FSNode& node, bool complete) +void RomImageWidget::parseProperties(const FSNode& node, bool full) { if(myNavSurface == nullptr) { @@ -112,47 +111,49 @@ void RomImageWidget::parseProperties(const FSNode& node, bool complete) }); } - // Initialize to empty properties entry - mySurfaceErrorMsg = ""; - mySurfaceIsValid = false; - -#ifdef PNG_SUPPORT - // TODO: RETRON_77 - - // Get a valid filename representing a snapshot file for this rom and load the snapshot - myImageList.clear(); - myImageIdx = 0; - - if(complete) +#ifdef PNG_SUPPORT + if(!full) { - // Try to load snapshots by property name and ROM file name - getImageList(myProperties.get(PropType::Cart_Name), node.getNameWithExt()); + myImageIdx = 0; + myImageList.clear(); + mySurfaceErrorMsg = ""; - if(myImageList.size()) - mySurfaceIsValid = loadPng(myImageList[0].getPath()); + // 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 first snapshot by property name + string fileName = path + myProperties.get(PropType::Cart_Name) + ".png"; + + mySurfaceIsValid = loadPng(fileName); + if(!mySurfaceIsValid) + { + // 2. If none exists, try to load first snapshot by ROM file name + fileName = path + node.getNameWithExt("png"); + mySurfaceIsValid = loadPng(fileName); + } + if(mySurfaceIsValid) + myImageList.emplace_back(fileName); + else + // 3. If no ROM snapshots exist, try to load a default snapshot + mySurfaceIsValid = loadPng(path + "default_snapshot.png"); } else { - const string& path = instance().snapshotLoadDir().getPath(); - string filename = path + myProperties.get(PropType::Cart_Name) + ".png"; + const string& oldFileName = myImageList.size() ? myImageList[0].getPath() : ""; - mySurfaceIsValid = loadPng(filename); - if(!mySurfaceIsValid) + // Try to find all snapshots by property and ROM file name + myImageList.clear(); + getImageList(myProperties.get(PropType::Cart_Name), node.getNameWithExt()); + + // The first file found before must not be the first file now, if files by + // property *and* ROM name are found + if(myImageList.size() && myImageList[0].getPath() != oldFileName) { - filename = path + node.getNameWithExt("png"); - mySurfaceIsValid = loadPng(filename); + mySurfaceErrorMsg = ""; + mySurfaceIsValid = loadPng(myImageList[0].getPath()); } - if(mySurfaceIsValid) - myImageList.emplace_back(filename); } - - if(!mySurfaceIsValid) - { - // If no ROM snapshots exist, try to load a default snapshot - mySurfaceIsValid = loadPng(instance().snapshotLoadDir().getPath() + "default_snapshot.png"); - } - #else + mySurfaceIsValid = false; mySurfaceErrorMsg = "PNG image loading not supported"; #endif if(mySurface) @@ -174,29 +175,21 @@ bool RomImageWidget::changeImage(int direction) #ifdef PNG_SUPPORT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool RomImageWidget::getImageList(const string& propname, const string& filename) +bool RomImageWidget::getImageList(const string& propName, const string& romName) { - // TODO: search for consecutive digits and letters instead of getChildren - //std::ifstream in(filename, std::ios_base::binary); - //if(!in.is_open()) - // loadImageERROR("No snapshot found"); - // or use a timer before updating the images + const std::regex symbols{R"([-[\]{}()*+?.,\^$|#])"}; // \s + const string rgxPropName = std::regex_replace(propName, symbols, R"(\$&)"); + const string rgxRomName = std::regex_replace(romName, symbols, R"(\$&)"); + // Look for or (# is a number) + const std::regex rgx("^(" + rgxPropName + "|" + rgxRomName + ")(_\\d+){0,1}\\.png$"); - const string pngPropName = propname + ".png"; - const string pngFileName = filename + ".png"; FSNode::NameFilter filter = ([&](const FSNode& node) { - const string& nodeName = node.getName(); - return - (nodeName == pngPropName || nodeName == pngFileName || - (nodeName.find(propname + " #") == 0 && - nodeName.find(".png") == nodeName.length() - 4) || - (nodeName.find(filename + " #") == 0 && - nodeName.find(".png") == nodeName.length() - 4)); + return std::regex_match(node.getName(), rgx); } ); - // Find all images matching the filename and the extension + // Find all images matching the given names and the extension FSNode node(instance().snapshotLoadDir().getPath()); node.getChildren(myImageList, FSNode::ListMode::FilesOnly, filter, false, false); @@ -212,12 +205,12 @@ bool RomImageWidget::getImageList(const string& propname, const string& filename } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool RomImageWidget::loadPng(const string& filename) +bool RomImageWidget::loadPng(const string& fileName) { try { VariantList comments; - instance().png().loadImage(filename, *mySurface, comments); + instance().png().loadImage(fileName, *mySurface, comments); // Scale surface to available image area const Common::Rect& src = mySurface->srcRect(); @@ -271,7 +264,7 @@ void RomImageWidget::drawWidget(bool hilite) FBSurface& s = dialog().surface(); const int yoff = myImageHeight; - s.fillRect(_x+1, _y+1, _w-2, _h-1, _bgcolor); + s.fillRect(_x+1, _y+1, _w-2, _h-2, _bgcolor); s.frameRect(_x, _y, _w, myImageHeight, kColor); if(!myHaveProperties) diff --git a/src/gui/RomImageWidget.hxx b/src/gui/RomImageWidget.hxx index 5cc0f1dc0..941f5d978 100644 --- a/src/gui/RomImageWidget.hxx +++ b/src/gui/RomImageWidget.hxx @@ -22,7 +22,6 @@ class FBSurface; class Properties; #include "Widget.hxx" -#include "bspf.hxx" class RomImageWidget : public Widget, public CommandSender { @@ -36,7 +35,7 @@ class RomImageWidget : public Widget, public CommandSender return font.getFontHeight() * 9 / 8; } - void setProperties(const FSNode& node, const string& md5, bool complete); + void setProperties(const FSNode& node, const string& md5, bool full = true); void clearProperties(); void reloadProperties(const FSNode& node); bool changeImage(int direction = 1); @@ -49,10 +48,10 @@ class RomImageWidget : public Widget, public CommandSender #endif private: - void parseProperties(const FSNode& node, bool complete); + void parseProperties(const FSNode& node, bool full = true); #ifdef PNG_SUPPORT - bool getImageList(const string& propname, const string& filename); - bool loadPng(const string& filename); + bool getImageList(const string& propName, const string& romName); + bool loadPng(const string& fileName); #endif private: diff --git a/src/gui/RomInfoWidget.cxx b/src/gui/RomInfoWidget.cxx index 3638b19dd..a9366feb6 100644 --- a/src/gui/RomInfoWidget.cxx +++ b/src/gui/RomInfoWidget.cxx @@ -16,7 +16,6 @@ //============================================================================ #include "EventHandler.hxx" -#include "FrameBuffer.hxx" #include "Dialog.hxx" #include "FBSurface.hxx" #include "Font.hxx" @@ -40,7 +39,7 @@ RomInfoWidget::RomInfoWidget(GuiObject* boss, const GUI::Font& font, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void RomInfoWidget::setProperties(const FSNode& node, const string& md5) +void RomInfoWidget::setProperties(const FSNode& node, const string& md5, bool full) { myHaveProperties = true; @@ -52,7 +51,7 @@ void RomInfoWidget::setProperties(const FSNode& node, const string& md5) // Decide whether the information should be shown immediately if(instance().eventHandler().state() == EventHandlerState::LAUNCHER) - parseProperties(node); + parseProperties(node, full); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -77,7 +76,7 @@ void RomInfoWidget::reloadProperties(const FSNode& node) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void RomInfoWidget::parseProperties(const FSNode& node) +void RomInfoWidget::parseProperties(const FSNode& node, bool full) { // Initialize to empty properties entry myRomInfo.clear(); @@ -97,63 +96,68 @@ void RomInfoWidget::parseProperties(const FSNode& node) myRomInfo.push_back("Rarity: " + value); if((value = myProperties.get(PropType::Cart_Note)) != EmptyString) myRomInfo.push_back("Note: " + value); - const bool swappedPorts = myProperties.get(PropType::Console_SwapPorts) == "YES"; - - // Load the image for controller and bankswitch type auto detection - string left = myProperties.get(PropType::Controller_Left); - string right = myProperties.get(PropType::Controller_Right); - const Controller::Type leftType = Controller::getType(left); - const Controller::Type rightType = Controller::getType(right); - string bsDetected = myProperties.get(PropType::Cart_Type); - bool isPlusCart = false; - size_t size = 0; - try + + if(full) { - ByteBuffer image; - string md5 = ""; + const bool swappedPorts = myProperties.get(PropType::Console_SwapPorts) == "YES"; - if(node.exists() && !node.isDirectory() && - (image = instance().openROM(node, md5, size)) != nullptr) + // Load the image for controller and bankswitch type auto detection + string left = myProperties.get(PropType::Controller_Left); + string right = myProperties.get(PropType::Controller_Right); + const Controller::Type leftType = Controller::getType(left); + const Controller::Type rightType = Controller::getType(right); + string bsDetected = myProperties.get(PropType::Cart_Type); + bool isPlusCart = false; + size_t size = 0; + try { - Logger::debug(myProperties.get(PropType::Cart_Name) + ":"); - left = ControllerDetector::detectName(image, size, leftType, + ByteBuffer image; + string md5 = ""; + + if(node.exists() && !node.isDirectory() && + (image = instance().openROM(node, md5, size)) != nullptr) + { + Logger::debug(myProperties.get(PropType::Cart_Name) + ":"); + left = ControllerDetector::detectName(image, size, leftType, !swappedPorts ? Controller::Jack::Left : Controller::Jack::Right, - instance().settings()); - right = ControllerDetector::detectName(image, size, rightType, + instance().settings()); + right = ControllerDetector::detectName(image, size, rightType, !swappedPorts ? Controller::Jack::Right : Controller::Jack::Left, - instance().settings()); - if (bsDetected == "AUTO") - bsDetected = Bankswitch::typeToName(CartDetector::autodetectType(image, size)); + instance().settings()); + if(bsDetected == "AUTO") + bsDetected = Bankswitch::typeToName(CartDetector::autodetectType(image, size)); - isPlusCart = CartDetector::isProbablyPlusROM(image, size); + isPlusCart = CartDetector::isProbablyPlusROM(image, size); + } } - } - catch(const runtime_error&) - { - // Do nothing; we simply don't update the controllers if openROM - // failed for any reason - left = right = ""; - } - if(left != "" && right != "") - myRomInfo.push_back("Controllers: " + (left + " (left), " + right + " (right)")); - - if(bsDetected != "") - { - ostringstream buf; - - // Display actual ROM size in developer mode - if(instance().settings().getBool("dev.settings")) + catch(const runtime_error&) { - buf << " - "; - if(size < 1_KB) - buf << size << "B"; - else - buf << (std::round(size / static_cast(1_KB))) << "K"; + // Do nothing; we simply don't update the controllers if openROM + // failed for any reason + left = right = ""; + } + if(left != "" && right != "") + myRomInfo.push_back("Controllers: " + (left + " (left), " + right + " (right)")); + + if(bsDetected != "") + { + ostringstream buf; + + // Display actual ROM size in developer mode + if(instance().settings().getBool("dev.settings")) + { + buf << " - "; + if(size < 1_KB) + buf << size << "B"; + else + buf << (std::round(size / static_cast(1_KB))) << "K"; + } + myRomInfo.push_back("Type: " + Bankswitch::typeToDesc(Bankswitch::nameToType(bsDetected)) + + (isPlusCart ? " - PlusROM" : "") + + buf.str()); } - myRomInfo.push_back("Type: " + Bankswitch::typeToDesc(Bankswitch::nameToType(bsDetected)) - + (isPlusCart ? " - PlusROM" : "") - + buf.str()); } + setDirty(); } diff --git a/src/gui/RomInfoWidget.hxx b/src/gui/RomInfoWidget.hxx index 06cb977c9..a98fe5c0d 100644 --- a/src/gui/RomInfoWidget.hxx +++ b/src/gui/RomInfoWidget.hxx @@ -22,7 +22,6 @@ class FBSurface; class Properties; #include "Widget.hxx" -#include "bspf.hxx" class RomInfoWidget : public Widget, public CommandSender { @@ -36,7 +35,7 @@ class RomInfoWidget : public Widget, public CommandSender int x, int y, int w, int h); ~RomInfoWidget() override = default; - void setProperties(const FSNode& node, const string& md5); + void setProperties(const FSNode& node, const string& md5, bool full = true); void clearProperties(); void reloadProperties(const FSNode& node); @@ -47,7 +46,7 @@ class RomInfoWidget : public Widget, public CommandSender void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; private: - void parseProperties(const FSNode& node); + void parseProperties(const FSNode& node, bool full = true); private: // Some ROM properties info, as well as 'tEXt' chunks from the PNG image