Merge branch 'master' into feature/filesystem

This commit is contained in:
Stephen Anthony 2022-08-14 11:40:30 -02:30
commit d6b88336cf
7 changed files with 144 additions and 133 deletions

View File

@ -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)
{

View File

@ -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);
}
}

View File

@ -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);

View File

@ -15,8 +15,8 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include <regex>
#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 <name.png> or <name_#.png> (# 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)

View File

@ -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:

View File

@ -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<float>(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<float>(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();
}

View File

@ -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