diff --git a/src/gui/FileListWidget.cxx b/src/gui/FileListWidget.cxx index 5361232de..2d778a4fd 100644 --- a/src/gui/FileListWidget.cxx +++ b/src/gui/FileListWidget.cxx @@ -18,6 +18,8 @@ #include "ScrollBarWidget.hxx" #include "FileListWidget.hxx" +#include "Bankswitch.hxx" +#include "MD5.hxx" #include "bspf.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -25,7 +27,7 @@ FileListWidget::FileListWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h) : StringListWidget(boss, font, x, y, w, h), _fsmode(FilesystemNode::ListMode::All), - _extension("") + _selectedPos(0) { // This widget is special, in that it catches signals and redirects them setTarget(this); @@ -90,6 +92,26 @@ void FileListWidget::selectParent() } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FileListWidget::reload() +{ + if(_node.exists()) + setLocation(_node, _gameList.name(_selectedPos)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const string& FileListWidget::selectedMD5() +{ + if(_selected.isDirectory() || !Bankswitch::isValidRomName(_selected)) + return EmptyString; + + // Make sure we have a valid md5 for this ROM + if(_gameList.md5(_selectedPos) == "") + _gameList.setMd5(_selectedPos, MD5::hash(_selected)); + + return _gameList.md5(_selectedPos); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FileListWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { @@ -102,6 +124,7 @@ void FileListWidget::handleCommand(CommandSender* sender, int cmd, int data, int case ListWidget::kSelectionChangedCmd: cmd = ItemChanged; _selected = FilesystemNode(_gameList.path(data)); + _selectedPos = data; break; case ListWidget::kActivatedCmd: @@ -116,7 +139,6 @@ void FileListWidget::handleCommand(CommandSender* sender, int cmd, int data, int } else cmd = ItemActivated; - break; default: diff --git a/src/gui/FileListWidget.hxx b/src/gui/FileListWidget.hxx index 033cd7702..501fad3ac 100644 --- a/src/gui/FileListWidget.hxx +++ b/src/gui/FileListWidget.hxx @@ -35,7 +35,7 @@ class CommandSender; Note that for the current implementation, the ItemActivated signal is not sent when activating a directory (instead the code descends into - the directory). This may be changed in a future revision. + the directory). */ class FileListWidget : public StringListWidget { @@ -60,20 +60,31 @@ class FileListWidget : public StringListWidget /** Select parent directory (if applicable) */ void selectParent(); + /** Reload current location (file or directory) */ + void reload(); + /** Gets current node(s) */ const FilesystemNode& selected() const { return _selected; } const FilesystemNode& currentDir() const { return _node; } - protected: + /** Gets MD5sum of the current node, if it is a file, and caches the result. + Otherwise, does nothing. + + @return MD5sum of selected file, else EmptyString + */ + const string& selectedMD5(); + + private: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: FilesystemNode::ListMode _fsmode; FilesystemNode _node, _selected; - string _extension; - GameList _gameList; + string _extension; + uInt32 _selectedPos; + private: // Following constructors and assignment operators not supported FileListWidget() = delete; diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index 3fe1c8796..d4cb564e6 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -16,15 +16,14 @@ //============================================================================ #include "bspf.hxx" -#include "Bankswitch.hxx" #include "BrowserDialog.hxx" #include "ContextMenu.hxx" #include "DialogContainer.hxx" #include "Dialog.hxx" #include "EditTextWidget.hxx" +#include "FileListWidget.hxx" #include "FSNode.hxx" #include "GameList.hxx" -#include "MD5.hxx" #include "OptionsDialog.hxx" #include "GlobalPropsDialog.hxx" #include "StellaSettingsDialog.hxx" @@ -38,12 +37,18 @@ #include "PropsSet.hxx" #include "RomInfoWidget.hxx" #include "Settings.hxx" -#include "StringListWidget.hxx" #include "Widget.hxx" #include "Font.hxx" #include "Version.hxx" #include "LauncherDialog.hxx" +/** + TODO: + - show all files / only ROMs + - connect to 'matchPattern' + - history of selected folders/files +*/ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, int x, int y, int w, int h) @@ -142,9 +147,10 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, romWidth = 365; int listWidth = _w - (romWidth > 0 ? romWidth+8 : 0) - 20; - myList = new StringListWidget(this, font, xpos, ypos, - listWidth, _h - 43 - bheight - fontHeight - lineHeight); + myList = new FileListWidget(this, font, xpos, ypos, + listWidth, _h - 43 - bheight - fontHeight - lineHeight); myList->setEditable(false); + myList->setFileListMode(FilesystemNode::ListMode::All); wid.push_back(myList); // Add ROM info area (if enabled) @@ -211,10 +217,6 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, else mySelectedItem = 2; - // Create a game list, which contains all the information about a ROM that - // the launcher needs - myGameList = make_unique(); - addToFocusList(wid); // Create context menu for ROM list options @@ -236,31 +238,27 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const string& LauncherDialog::selectedRom() +const string& LauncherDialog::selectedRom() const { - int item = myList->getSelected(); - if(item < 0) - return EmptyString; - - return myGameList->path(item); + return currentNode().getPath(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& LauncherDialog::selectedRomMD5() { - int item = myList->getSelected(); - if(item < 0) - return EmptyString; + return myList->selectedMD5(); +} - const FilesystemNode node(myGameList->path(item)); - if(node.isDirectory() || !Bankswitch::isValidRomName(node)) - return EmptyString; +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const FilesystemNode& LauncherDialog::currentNode() const +{ + return myList->selected(); +} - // Make sure we have a valid md5 for this ROM - if(myGameList->md5(item) == "") - myGameList->setMd5(item, MD5::hash(node)); - - return myGameList->md5(item); +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void LauncherDialog::reload() +{ + myList->reload(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -276,26 +274,43 @@ void LauncherDialog::loadConfig() // has been called (and we should reload the list) if(myList->getList().empty()) { - if(myPrevDirButton) - myPrevDirButton->setEnabled(false); - myCurrentNode = FilesystemNode(romdir == "" ? "~" : romdir); - if(!(myCurrentNode.exists() && myCurrentNode.isDirectory())) - myCurrentNode = FilesystemNode("~"); + FilesystemNode node(romdir == "" ? "~" : romdir); + if(!(node.exists() && node.isDirectory())) + node = FilesystemNode("~"); - updateListing(); + myList->setLocation(node); + updateUI(instance().settings().getString("lastrom")); } Dialog::setFocus(getFocusList()[mySelectedItem]); if(myRomInfoWidget) - { - int item = myList->getSelected(); - if(item < 0) return; - const FilesystemNode node(myGameList->path(item)); - - myRomInfoWidget->reloadProperties(node); - } + myRomInfoWidget->reloadProperties(currentNode()); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void LauncherDialog::updateUI(const string& nameToSelect) +{ + // Only hilite the 'up' button if there's a parent directory + if(myPrevDirButton) + myPrevDirButton->setEnabled(myList->currentDir().hasParent()); + + // Show current directory + myDir->setText(myList->currentDir().getShortPath()); + + // Indicate how many files were found + ostringstream buf; + buf << (myList->getList().size() - 1) << " items found"; + myRomCount->setLabel(buf.str()); + + // Restore last selection + if(nameToSelect != "") + myList->setSelected(nameToSelect); + + // Update ROM info UI item + loadRomInfo(); +} + +#if 0 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::updateListing(const string& nameToSelect) { @@ -365,26 +380,22 @@ void LauncherDialog::loadDirListing() // Sort the list by rom name (since that's what we see in the listview) myGameList->sortByName(); } +#endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::loadRomInfo() { - if(!myRomInfoWidget) return; - int item = myList->getSelected(); - if(item < 0) return; + if(!myRomInfoWidget) + return; - const FilesystemNode node(myGameList->path(item)); - if(!node.isDirectory() && Bankswitch::isValidRomName(node)) + const string& md5 = selectedRomMD5(); + if(md5 != EmptyString) { - // Make sure we have a valid md5 for this ROM - if(myGameList->md5(item) == "") - myGameList->setMd5(item, MD5::hash(node)); - // Get the properties for this entry Properties props; - instance().propSet().getMD5WithInsert(node, myGameList->md5(item), props); + instance().propSet().getMD5WithInsert(currentNode(), md5, props); - myRomInfoWidget->setProperties(props, node); + myRomInfoWidget->setProperties(props, currentNode()); } else myRomInfoWidget->clearProperties(); @@ -396,13 +407,9 @@ void LauncherDialog::handleContextMenu() const string& cmd = myMenu->getSelectedTag().toString(); if(cmd == "override") - { myGlobalProps->open(); - } else if(cmd == "reload") - { - updateListing(); - } + reload(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -459,7 +466,7 @@ void LauncherDialog::handleKeyDown(StellaKey key, StellaMod mod) // Grab the key before passing it to the actual dialog and check for // Control-R (reload ROM listing) if(StellaModTest::isControl(mod) && key == KBDK_R) - updateListing(); + reload(); else #if defined(RETRON77) // handle keys used by R77 @@ -554,14 +561,16 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd, { case kAllfilesCmd: showOnlyROMs(myAllFiles ? !myAllFiles->getState() : true); - updateListing(); + reload(); break; case kLoadROMCmd: - case ListWidget::kActivatedCmd: - case ListWidget::kDoubleClickedCmd: + case FileListWidget::ItemActivated: { - startGame(); + if(currentNode().isDirectory()) + myList->setLocation(currentNode()); + else + loadRom(); break; } @@ -570,13 +579,11 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd, break; case kPrevDirCmd: - case ListWidget::kPrevDirCmd: - myCurrentNode = myCurrentNode.getParent(); - updateListing(myNodeNames.empty() ? "" : myNodeNames.pop()); + myList->selectParent(); break; - case ListWidget::kSelectionChangedCmd: - loadRomInfo(); + case FileListWidget::ItemChanged: + updateUI(); break; case kQuitCmd: @@ -585,72 +592,37 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd, break; case kRomDirChosenCmd: - myCurrentNode = FilesystemNode(instance().settings().getString("romdir")); - if(!(myCurrentNode.exists() && myCurrentNode.isDirectory())) - myCurrentNode = FilesystemNode("~"); - updateListing(); - break; - - case kReloadRomDirCmd: - updateListing(); + { + FilesystemNode node(instance().settings().getString("romdir")); + if(!(node.exists() && node.isDirectory())) + node = FilesystemNode("~"); + myList->setLocation(node); break; + } case ContextMenu::kItemSelectedCmd: handleContextMenu(); break; - case EditableWidget::kAcceptCmd: - case EditableWidget::kChangedCmd: - // The updateListing() method knows what to do when the text changes - updateListing(); - break; - default: Dialog::handleCommand(sender, cmd, data, 0); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void LauncherDialog::startGame() +void LauncherDialog::loadRom() { - int item = myList->getSelected(); - if(item >= 0) + const string& result = instance().createConsole(currentNode(), myList->selectedMD5()); + if(result == EmptyString) { - const FilesystemNode romnode(myGameList->path(item)); + instance().settings().setValue("lastrom", myList->getSelectedString()); - // Directory's should be selected (ie, enter them and redisplay) - if(romnode.isDirectory()) - { - string dirname = ""; - if(myGameList->name(item) == " [..]") - { - myCurrentNode = myCurrentNode.getParent(); - if(!myNodeNames.empty()) - dirname = myNodeNames.pop(); - } - else - { - myCurrentNode = romnode; - myNodeNames.push(myGameList->name(item)); - } - updateListing(dirname); - } - else - { - const string& result = - instance().createConsole(romnode, myGameList->md5(item)); - if(result == EmptyString) - { - instance().settings().setValue("lastrom", myList->getSelectedString()); - - // If romdir has never been set, set it now based on the selected rom - if(instance().settings().getString("romdir") == EmptyString) - instance().settings().setValue("romdir", romnode.getParent().getShortPath()); - } - else - instance().frameBuffer().showMessage(result, MessagePosition::MiddleCenter, true); - } + // If romdir has never been set, set it now based on the selected rom + if(instance().settings().getString("romdir") == EmptyString) + instance().settings().setValue("romdir", currentNode().getParent().getShortPath()); } + else + instance().frameBuffer().showMessage(result, MessagePosition::MiddleCenter, true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index eb563ce9f..c076b879d 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -22,7 +22,6 @@ class ButtonWidget; class CommandSender; class ContextMenu; class DialogContainer; -class GameList; class BrowserDialog; class OptionsDialog; class GlobalPropsDialog; @@ -30,9 +29,9 @@ class StellaSettingsDialog; class OSystem; class Properties; class EditTextWidget; +class FileListWidget; class RomInfoWidget; class StaticTextWidget; -class StringListWidget; namespace GUI { class MessageBox; } @@ -49,8 +48,7 @@ class LauncherDialog : public Dialog enum { kAllfilesCmd = 'lalf', // show all files (or ROMs only) kLoadROMCmd = 'STRT', // load currently selected ROM - kRomDirChosenCmd = 'romc', // rom dir chosen - kReloadRomDirCmd = 'rdrl', // reload the current listing + kRomDirChosenCmd = 'romc' // rom dir chosen }; public: @@ -59,30 +57,32 @@ class LauncherDialog : public Dialog virtual ~LauncherDialog() = default; /** - Get path for the currently selected file + Get path for the currently selected file. @return path if a valid ROM file, else the empty string */ - const string& selectedRom(); + const string& selectedRom() const; /** - Get MD5sum for the currently selected file + Get MD5sum for the currently selected file. + If the MD5 hasn't already been calculated, it will be + calculated (and cached) for future use. @return md5sum if a valid ROM file, else the empty string */ const string& selectedRomMD5(); /** - Get node for the currently selected directory + Get node for the currently selected directory. @return FilesystemNode currently active */ - const FilesystemNode& currentNode() const { return myCurrentNode; } + const FilesystemNode& currentNode() const; /** Reload the current listing */ - void reload() { updateListing(); } + void reload(); private: void center() override { positionAt(0); } @@ -93,20 +93,18 @@ class LauncherDialog : public Dialog Event::Type getJoyAxisEvent(int stick, int axis, int value, int button) override; void loadConfig() override; - void updateListing(const string& nameToSelect = ""); + void updateUI(const string& nameToSelect = ""); - void loadDirListing(); + void loadRom(); void loadRomInfo(); void handleContextMenu(); void showOnlyROMs(bool state); bool matchPattern(const string& s, const string& pattern) const; - void startGame(); void openSettings(); private: unique_ptr myOptionsDialog; unique_ptr myStellaSettingsDialog; - unique_ptr myGameList; unique_ptr myMenu; unique_ptr myGlobalProps; unique_ptr myRomDir; @@ -116,7 +114,7 @@ class LauncherDialog : public Dialog ButtonWidget* myOptionsButton; ButtonWidget* myQuitButton; - StringListWidget* myList; + FileListWidget* myList; StaticTextWidget* myDirLabel; EditTextWidget* myDir; StaticTextWidget* myRomCount; @@ -126,8 +124,6 @@ class LauncherDialog : public Dialog RomInfoWidget* myRomInfoWidget; int mySelectedItem; - FilesystemNode myCurrentNode; - Common::FixedStack myNodeNames; bool myShowOnlyROMs; bool myUseMinimalUI;