First pass at converting LauncherDialog to use FileListWidget, similar to BrowserDialog.

- FileListWidget is a newer development, and LauncherDialog duplicates some (but not all) of its functionality
- Similarly, BrowserDialog has some functionality that LauncherDialog does not
- We will implement all required functionality in FileListWidget, and have both classes use it.

BrowserDialog is currently slightly broken; not all functionality is reimplemented yet.
This commit is contained in:
Stephen Anthony 2019-06-21 14:51:55 -02:30
parent d7e9c95fb0
commit 786f3b2a49
4 changed files with 139 additions and 138 deletions

View File

@ -18,6 +18,8 @@
#include "ScrollBarWidget.hxx" #include "ScrollBarWidget.hxx"
#include "FileListWidget.hxx" #include "FileListWidget.hxx"
#include "Bankswitch.hxx"
#include "MD5.hxx"
#include "bspf.hxx" #include "bspf.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -25,7 +27,7 @@ FileListWidget::FileListWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h) int x, int y, int w, int h)
: StringListWidget(boss, font, x, y, w, h), : StringListWidget(boss, font, x, y, w, h),
_fsmode(FilesystemNode::ListMode::All), _fsmode(FilesystemNode::ListMode::All),
_extension("") _selectedPos(0)
{ {
// This widget is special, in that it catches signals and redirects them // This widget is special, in that it catches signals and redirects them
setTarget(this); 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) 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: case ListWidget::kSelectionChangedCmd:
cmd = ItemChanged; cmd = ItemChanged;
_selected = FilesystemNode(_gameList.path(data)); _selected = FilesystemNode(_gameList.path(data));
_selectedPos = data;
break; break;
case ListWidget::kActivatedCmd: case ListWidget::kActivatedCmd:
@ -116,7 +139,6 @@ void FileListWidget::handleCommand(CommandSender* sender, int cmd, int data, int
} }
else else
cmd = ItemActivated; cmd = ItemActivated;
break; break;
default: default:

View File

@ -35,7 +35,7 @@ class CommandSender;
Note that for the current implementation, the ItemActivated signal is Note that for the current implementation, the ItemActivated signal is
not sent when activating a directory (instead the code descends into 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 class FileListWidget : public StringListWidget
{ {
@ -60,20 +60,31 @@ class FileListWidget : public StringListWidget
/** Select parent directory (if applicable) */ /** Select parent directory (if applicable) */
void selectParent(); void selectParent();
/** Reload current location (file or directory) */
void reload();
/** Gets current node(s) */ /** Gets current node(s) */
const FilesystemNode& selected() const { return _selected; } const FilesystemNode& selected() const { return _selected; }
const FilesystemNode& currentDir() const { return _node; } 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; void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
private: private:
FilesystemNode::ListMode _fsmode; FilesystemNode::ListMode _fsmode;
FilesystemNode _node, _selected; FilesystemNode _node, _selected;
string _extension;
GameList _gameList; GameList _gameList;
string _extension;
uInt32 _selectedPos;
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported
FileListWidget() = delete; FileListWidget() = delete;

View File

@ -16,15 +16,14 @@
//============================================================================ //============================================================================
#include "bspf.hxx" #include "bspf.hxx"
#include "Bankswitch.hxx"
#include "BrowserDialog.hxx" #include "BrowserDialog.hxx"
#include "ContextMenu.hxx" #include "ContextMenu.hxx"
#include "DialogContainer.hxx" #include "DialogContainer.hxx"
#include "Dialog.hxx" #include "Dialog.hxx"
#include "EditTextWidget.hxx" #include "EditTextWidget.hxx"
#include "FileListWidget.hxx"
#include "FSNode.hxx" #include "FSNode.hxx"
#include "GameList.hxx" #include "GameList.hxx"
#include "MD5.hxx"
#include "OptionsDialog.hxx" #include "OptionsDialog.hxx"
#include "GlobalPropsDialog.hxx" #include "GlobalPropsDialog.hxx"
#include "StellaSettingsDialog.hxx" #include "StellaSettingsDialog.hxx"
@ -38,12 +37,18 @@
#include "PropsSet.hxx" #include "PropsSet.hxx"
#include "RomInfoWidget.hxx" #include "RomInfoWidget.hxx"
#include "Settings.hxx" #include "Settings.hxx"
#include "StringListWidget.hxx"
#include "Widget.hxx" #include "Widget.hxx"
#include "Font.hxx" #include "Font.hxx"
#include "Version.hxx" #include "Version.hxx"
#include "LauncherDialog.hxx" #include "LauncherDialog.hxx"
/**
TODO:
- show all files / only ROMs
- connect to 'matchPattern'
- history of selected folders/files
*/
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent,
int x, int y, int w, int h) int x, int y, int w, int h)
@ -142,9 +147,10 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent,
romWidth = 365; romWidth = 365;
int listWidth = _w - (romWidth > 0 ? romWidth+8 : 0) - 20; int listWidth = _w - (romWidth > 0 ? romWidth+8 : 0) - 20;
myList = new StringListWidget(this, font, xpos, ypos, myList = new FileListWidget(this, font, xpos, ypos,
listWidth, _h - 43 - bheight - fontHeight - lineHeight); listWidth, _h - 43 - bheight - fontHeight - lineHeight);
myList->setEditable(false); myList->setEditable(false);
myList->setFileListMode(FilesystemNode::ListMode::All);
wid.push_back(myList); wid.push_back(myList);
// Add ROM info area (if enabled) // Add ROM info area (if enabled)
@ -211,10 +217,6 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent,
else else
mySelectedItem = 2; mySelectedItem = 2;
// Create a game list, which contains all the information about a ROM that
// the launcher needs
myGameList = make_unique<GameList>();
addToFocusList(wid); addToFocusList(wid);
// Create context menu for ROM list options // 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(); return currentNode().getPath();
if(item < 0)
return EmptyString;
return myGameList->path(item);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string& LauncherDialog::selectedRomMD5() const string& LauncherDialog::selectedRomMD5()
{ {
int item = myList->getSelected(); return myList->selectedMD5();
if(item < 0) }
return EmptyString;
const FilesystemNode node(myGameList->path(item)); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if(node.isDirectory() || !Bankswitch::isValidRomName(node)) const FilesystemNode& LauncherDialog::currentNode() const
return EmptyString; {
return myList->selected();
}
// Make sure we have a valid md5 for this ROM // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if(myGameList->md5(item) == "") void LauncherDialog::reload()
myGameList->setMd5(item, MD5::hash(node)); {
myList->reload();
return myGameList->md5(item);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -276,26 +274,43 @@ void LauncherDialog::loadConfig()
// has been called (and we should reload the list) // has been called (and we should reload the list)
if(myList->getList().empty()) if(myList->getList().empty())
{ {
if(myPrevDirButton) FilesystemNode node(romdir == "" ? "~" : romdir);
myPrevDirButton->setEnabled(false); if(!(node.exists() && node.isDirectory()))
myCurrentNode = FilesystemNode(romdir == "" ? "~" : romdir); node = FilesystemNode("~");
if(!(myCurrentNode.exists() && myCurrentNode.isDirectory()))
myCurrentNode = FilesystemNode("~");
updateListing(); myList->setLocation(node);
updateUI(instance().settings().getString("lastrom"));
} }
Dialog::setFocus(getFocusList()[mySelectedItem]); Dialog::setFocus(getFocusList()[mySelectedItem]);
if(myRomInfoWidget) if(myRomInfoWidget)
{ myRomInfoWidget->reloadProperties(currentNode());
int item = myList->getSelected();
if(item < 0) return;
const FilesystemNode node(myGameList->path(item));
myRomInfoWidget->reloadProperties(node);
}
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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) 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) // Sort the list by rom name (since that's what we see in the listview)
myGameList->sortByName(); myGameList->sortByName();
} }
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void LauncherDialog::loadRomInfo() void LauncherDialog::loadRomInfo()
{ {
if(!myRomInfoWidget) return; if(!myRomInfoWidget)
int item = myList->getSelected(); return;
if(item < 0) return;
const FilesystemNode node(myGameList->path(item)); const string& md5 = selectedRomMD5();
if(!node.isDirectory() && Bankswitch::isValidRomName(node)) 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 // Get the properties for this entry
Properties props; 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 else
myRomInfoWidget->clearProperties(); myRomInfoWidget->clearProperties();
@ -396,13 +407,9 @@ void LauncherDialog::handleContextMenu()
const string& cmd = myMenu->getSelectedTag().toString(); const string& cmd = myMenu->getSelectedTag().toString();
if(cmd == "override") if(cmd == "override")
{
myGlobalProps->open(); myGlobalProps->open();
}
else if(cmd == "reload") else if(cmd == "reload")
{ reload();
updateListing();
}
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -459,7 +466,7 @@ void LauncherDialog::handleKeyDown(StellaKey key, StellaMod mod)
// Grab the key before passing it to the actual dialog and check for // Grab the key before passing it to the actual dialog and check for
// Control-R (reload ROM listing) // Control-R (reload ROM listing)
if(StellaModTest::isControl(mod) && key == KBDK_R) if(StellaModTest::isControl(mod) && key == KBDK_R)
updateListing(); reload();
else else
#if defined(RETRON77) #if defined(RETRON77)
// handle keys used by R77 // handle keys used by R77
@ -554,14 +561,16 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd,
{ {
case kAllfilesCmd: case kAllfilesCmd:
showOnlyROMs(myAllFiles ? !myAllFiles->getState() : true); showOnlyROMs(myAllFiles ? !myAllFiles->getState() : true);
updateListing(); reload();
break; break;
case kLoadROMCmd: case kLoadROMCmd:
case ListWidget::kActivatedCmd: case FileListWidget::ItemActivated:
case ListWidget::kDoubleClickedCmd:
{ {
startGame(); if(currentNode().isDirectory())
myList->setLocation(currentNode());
else
loadRom();
break; break;
} }
@ -570,13 +579,11 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd,
break; break;
case kPrevDirCmd: case kPrevDirCmd:
case ListWidget::kPrevDirCmd: myList->selectParent();
myCurrentNode = myCurrentNode.getParent();
updateListing(myNodeNames.empty() ? "" : myNodeNames.pop());
break; break;
case ListWidget::kSelectionChangedCmd: case FileListWidget::ItemChanged:
loadRomInfo(); updateUI();
break; break;
case kQuitCmd: case kQuitCmd:
@ -585,72 +592,37 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd,
break; break;
case kRomDirChosenCmd: case kRomDirChosenCmd:
myCurrentNode = FilesystemNode(instance().settings().getString("romdir")); {
if(!(myCurrentNode.exists() && myCurrentNode.isDirectory())) FilesystemNode node(instance().settings().getString("romdir"));
myCurrentNode = FilesystemNode("~"); if(!(node.exists() && node.isDirectory()))
updateListing(); node = FilesystemNode("~");
break; myList->setLocation(node);
case kReloadRomDirCmd:
updateListing();
break; break;
}
case ContextMenu::kItemSelectedCmd: case ContextMenu::kItemSelectedCmd:
handleContextMenu(); handleContextMenu();
break; break;
case EditableWidget::kAcceptCmd:
case EditableWidget::kChangedCmd:
// The updateListing() method knows what to do when the text changes
updateListing();
break;
default: default:
Dialog::handleCommand(sender, cmd, data, 0); Dialog::handleCommand(sender, cmd, data, 0);
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void LauncherDialog::startGame() void LauncherDialog::loadRom()
{ {
int item = myList->getSelected(); const string& result = instance().createConsole(currentNode(), myList->selectedMD5());
if(item >= 0) 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 romdir has never been set, set it now based on the selected rom
if(romnode.isDirectory()) if(instance().settings().getString("romdir") == EmptyString)
{ instance().settings().setValue("romdir", currentNode().getParent().getShortPath());
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);
}
} }
else
instance().frameBuffer().showMessage(result, MessagePosition::MiddleCenter, true);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -22,7 +22,6 @@ class ButtonWidget;
class CommandSender; class CommandSender;
class ContextMenu; class ContextMenu;
class DialogContainer; class DialogContainer;
class GameList;
class BrowserDialog; class BrowserDialog;
class OptionsDialog; class OptionsDialog;
class GlobalPropsDialog; class GlobalPropsDialog;
@ -30,9 +29,9 @@ class StellaSettingsDialog;
class OSystem; class OSystem;
class Properties; class Properties;
class EditTextWidget; class EditTextWidget;
class FileListWidget;
class RomInfoWidget; class RomInfoWidget;
class StaticTextWidget; class StaticTextWidget;
class StringListWidget;
namespace GUI { namespace GUI {
class MessageBox; class MessageBox;
} }
@ -49,8 +48,7 @@ class LauncherDialog : public Dialog
enum { enum {
kAllfilesCmd = 'lalf', // show all files (or ROMs only) kAllfilesCmd = 'lalf', // show all files (or ROMs only)
kLoadROMCmd = 'STRT', // load currently selected ROM kLoadROMCmd = 'STRT', // load currently selected ROM
kRomDirChosenCmd = 'romc', // rom dir chosen kRomDirChosenCmd = 'romc' // rom dir chosen
kReloadRomDirCmd = 'rdrl', // reload the current listing
}; };
public: public:
@ -59,30 +57,32 @@ class LauncherDialog : public Dialog
virtual ~LauncherDialog() = default; 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 @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 @return md5sum if a valid ROM file, else the empty string
*/ */
const string& selectedRomMD5(); const string& selectedRomMD5();
/** /**
Get node for the currently selected directory Get node for the currently selected directory.
@return FilesystemNode currently active @return FilesystemNode currently active
*/ */
const FilesystemNode& currentNode() const { return myCurrentNode; } const FilesystemNode& currentNode() const;
/** /**
Reload the current listing Reload the current listing
*/ */
void reload() { updateListing(); } void reload();
private: private:
void center() override { positionAt(0); } void center() override { positionAt(0); }
@ -93,20 +93,18 @@ class LauncherDialog : public Dialog
Event::Type getJoyAxisEvent(int stick, int axis, int value) override; Event::Type getJoyAxisEvent(int stick, int axis, int value) override;
void loadConfig() override; void loadConfig() override;
void updateListing(const string& nameToSelect = ""); void updateUI(const string& nameToSelect = "");
void loadDirListing(); void loadRom();
void loadRomInfo(); void loadRomInfo();
void handleContextMenu(); void handleContextMenu();
void showOnlyROMs(bool state); void showOnlyROMs(bool state);
bool matchPattern(const string& s, const string& pattern) const; bool matchPattern(const string& s, const string& pattern) const;
void startGame();
void openSettings(); void openSettings();
private: private:
unique_ptr<OptionsDialog> myOptionsDialog; unique_ptr<OptionsDialog> myOptionsDialog;
unique_ptr<StellaSettingsDialog> myStellaSettingsDialog; unique_ptr<StellaSettingsDialog> myStellaSettingsDialog;
unique_ptr<GameList> myGameList;
unique_ptr<ContextMenu> myMenu; unique_ptr<ContextMenu> myMenu;
unique_ptr<GlobalPropsDialog> myGlobalProps; unique_ptr<GlobalPropsDialog> myGlobalProps;
unique_ptr<BrowserDialog> myRomDir; unique_ptr<BrowserDialog> myRomDir;
@ -116,7 +114,7 @@ class LauncherDialog : public Dialog
ButtonWidget* myOptionsButton; ButtonWidget* myOptionsButton;
ButtonWidget* myQuitButton; ButtonWidget* myQuitButton;
StringListWidget* myList; FileListWidget* myList;
StaticTextWidget* myDirLabel; StaticTextWidget* myDirLabel;
EditTextWidget* myDir; EditTextWidget* myDir;
StaticTextWidget* myRomCount; StaticTextWidget* myRomCount;
@ -126,8 +124,6 @@ class LauncherDialog : public Dialog
RomInfoWidget* myRomInfoWidget; RomInfoWidget* myRomInfoWidget;
int mySelectedItem; int mySelectedItem;
FilesystemNode myCurrentNode;
Common::FixedStack<string> myNodeNames;
bool myShowOnlyROMs; bool myShowOnlyROMs;
bool myUseMinimalUI; bool myUseMinimalUI;