diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx
index 228c8456c..b91e5dc26 100644
--- a/src/debugger/CartDebug.cxx
+++ b/src/debugger/CartDebug.cxx
@@ -1352,7 +1352,7 @@ string CartDebug::saveDisassembly(string path)
if(path.empty())
- path = myOSystem.defaultSaveDir().getPath()
+ path = myOSystem.userSaveDir().getPath()
+ myConsole.properties().get(PropType::Cart_Name) + ".asm";
else
// Append default extension when missing
@@ -1380,7 +1380,7 @@ string CartDebug::saveDisassembly(string path)
string CartDebug::saveRom(string path)
{
if(path.empty())
- path = myOSystem.defaultSaveDir().getPath()
+ path = myOSystem.userSaveDir().getPath()
+ myConsole.properties().get(PropType::Cart_Name) + ".a26";
else
// Append default extension when missing
@@ -1406,7 +1406,7 @@ string CartDebug::saveAccessFile(string path)
try
{
if(path.empty())
- path = myOSystem.defaultSaveDir().getPath()
+ path = myOSystem.userSaveDir().getPath()
+ myConsole.properties().get(PropType::Cart_Name) + ".csv";
else
// Append default extension when missing
diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx
index 448eb73c9..2c02c53dd 100644
--- a/src/debugger/DebuggerParser.cxx
+++ b/src/debugger/DebuggerParser.cxx
@@ -683,7 +683,7 @@ string DebuggerParser::saveScriptFile(string file)
// Use default path if no path is provided
if(file.find_first_of(FilesystemNode::PATH_SEPARATOR) == string::npos)
- file = debugger.myOSystem.defaultSaveDir().getPath() + file;
+ file = debugger.myOSystem.userSaveDir().getPath() + file;
FilesystemNode node(file);
@@ -1144,7 +1144,7 @@ void DebuggerParser::executeDump()
else
{
ostringstream file;
- file << debugger.myOSystem.defaultSaveDir()
+ file << debugger.myOSystem.userSaveDir()
<< debugger.myOSystem.console().properties().get(PropType::Cart_Name) << "_dbg_";
if(execDepth > 0)
{
@@ -1240,7 +1240,7 @@ void DebuggerParser::executeExec()
file += ".script";
FilesystemNode node(file);
if (!node.exists())
- node = FilesystemNode(debugger.myOSystem.defaultSaveDir().getPath() + file);
+ node = FilesystemNode(debugger.myOSystem.userSaveDir().getPath() + file);
if (argCount == 2) {
execPrefix = argStrings[1];
@@ -1910,7 +1910,7 @@ void DebuggerParser::executeSaveses()
{
ostringstream filename;
auto timeinfo = BSPF::localTime();
- filename << debugger.myOSystem.defaultSaveDir()
+ filename << debugger.myOSystem.userSaveDir()
<< std::put_time(&timeinfo, "session_%F_%H-%M-%S.txt");
if(argCount && argStrings[0] == "?")
diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx
index 8abf382d4..e258aca08 100644
--- a/src/debugger/gui/DebuggerDialog.cxx
+++ b/src/debugger/gui/DebuggerDialog.cxx
@@ -466,7 +466,7 @@ void DebuggerDialog::showBrowser(BrowserType type, const string& defaultName)
{
createBrowser("Save " + title + " as");
- const string path = instance().defaultSaveDir().getPath() + defaultName;
+ const string path = instance().userSaveDir().getPath() + defaultName;
myBrowser->show(path, BrowserDialog::FileSave, cmd, kBdCancelCmd);
}
}
diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx
index 6d9ab16f0..c9fb0070b 100644
--- a/src/emucore/OSystem.cxx
+++ b/src/emucore/OSystem.cxx
@@ -246,6 +246,14 @@ void OSystem::loadConfig(const Settings::Options& options)
mySettings->load(options);
+ // TODO: check if affected by '-baseDir'and 'basedirinapp' params
+ string userDir = mySettings->getString("userdir");
+ if(userDir.empty())
+ userDir = defSaveDir;
+ myUserSaveDir = FilesystemNode(userDir);
+ if(!myUserSaveDir.isDirectory())
+ myUserSaveDir.makeDir();
+
Logger::instance().setLogParameters(mySettings->getInt("loglevel"),
mySettings->getBool("logtoconsole"));
Logger::debug("Loading config options ...");
@@ -333,6 +341,14 @@ void OSystem::setConfigPaths()
#endif
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void OSystem::setUserDir(const string& path)
+{
+ mySettings->setValue("userdir", path);
+
+ myUserSaveDir = FilesystemNode(path);
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool OSystem::checkUserPalette(bool outputError) const
{
diff --git a/src/emucore/OSystem.hxx b/src/emucore/OSystem.hxx
index f335055f4..1ac973976 100644
--- a/src/emucore/OSystem.hxx
+++ b/src/emucore/OSystem.hxx
@@ -323,6 +323,7 @@ class OSystem
*/
const FilesystemNode& defaultSaveDir() const { return myDefaultSaveDir; }
const FilesystemNode& defaultLoadDir() const { return myDefaultLoadDir; }
+ const FilesystemNode& userSaveDir() const { return myUserSaveDir; }
/**
Open the given ROM and return an array containing its contents.
@@ -427,6 +428,9 @@ class OSystem
static void overrideBaseDir(const string& path) { ourOverrideBaseDir = path; }
static void overrideBaseDirWithApp() { ourOverrideBaseDirWithApp = true; }
+ // Update the path of the user directory
+ void setUserDir(const string& path);
+
public:
//////////////////////////////////////////////////////////////////////
// The following methods are system-specific and can be overrided in
@@ -552,7 +556,8 @@ class OSystem
private:
FilesystemNode myBaseDir, myStateDir, mySnapshotSaveDir, mySnapshotLoadDir,
- myNVRamDir, myCfgDir, myDefaultSaveDir, myDefaultLoadDir;
+ myNVRamDir, myCfgDir, myDefaultSaveDir, myDefaultLoadDir,
+ myUserSaveDir;
FilesystemNode myCheatFile, myConfigFile, myPaletteFile, myPropertiesFile;
FilesystemNode myRomFile; string myRomMD5;
diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx
index 185b72c5c..8068b29a9 100644
--- a/src/emucore/Settings.cxx
+++ b/src/emucore/Settings.cxx
@@ -135,6 +135,8 @@ Settings::Settings()
// Config files and paths
setPermanent("romdir", "");
+ setPermanent("userdir", "");
+ setPermanent("saveuserdir", "false");
// ROM browser options
setPermanent("exitlauncher", "false");
@@ -572,6 +574,8 @@ void Settings::usage() const
<< " -basic_settings <0|1> Display only a basic settings dialog\n"
<< " -romdir
Set the directory where the ROM launcher will\n"
<< " start\n"
+ << " -userdir The directory to save user files to\n"
+ << " -saveuserdir <1|0> Update user directory when navigating in browser\n"
<< " -avoxport The name of the serial port where an AtariVox is\n"
<< " connected\n"
<< " -holdreset Start the emulator with the Game Reset switch\n"
diff --git a/src/gui/BrowserDialog.cxx b/src/gui/BrowserDialog.cxx
index 3b1ee48a7..026c16b2f 100644
--- a/src/gui/BrowserDialog.cxx
+++ b/src/gui/BrowserDialog.cxx
@@ -61,8 +61,13 @@ BrowserDialog::BrowserDialog(GuiObject* boss, const GUI::Font& font,
_currentPath = new EditTextWidget(this, font, xpos + t->getWidth(), ypos,
_w - t->getWidth() - 2 * xpos, lineHeight);
_currentPath->setEditable(false);
+
+ xpos = _w - (HBORDER + _font.getStringWidth("Save") + CheckboxWidget::prefixSize(_font));
+ _savePathBox = new CheckboxWidget(this, font, xpos, ypos + 2, "Save");
+ _savePathBox->setToolTip("Check to save current path as default.");
+
// Add file list
- ypos += lineHeight + VGAP * 2;
+ xpos = HBORDER; ypos += lineHeight + VGAP * 2;
_fileList = new FileListWidget(this, font, xpos, ypos, _w - 2 * xpos,
_h - selectHeight - buttonHeight - ypos - VBORDER * 2);
_fileList->setEditable(false);
@@ -71,9 +76,9 @@ BrowserDialog::BrowserDialog(GuiObject* boss, const GUI::Font& font,
// Add currently selected item
ypos += _fileList->getHeight() + VGAP * 2;
- _type = new StaticTextWidget(this, font, xpos, ypos + 2, "Name ");
- _selected = new EditTextWidget(this, font, xpos + _type->getWidth(), ypos,
- _w - _type->getWidth() - 2 * xpos, lineHeight, "");
+ _name = new StaticTextWidget(this, font, xpos, ypos + 2, "Name ");
+ _selected = new EditTextWidget(this, font, xpos + _name->getWidth(), ypos,
+ _w - _name->getWidth() - 2 * xpos, lineHeight, "");
addFocusWidget(_selected);
// Buttons
@@ -110,6 +115,9 @@ BrowserDialog::BrowserDialog(GuiObject* boss, const GUI::Font& font,
addFocusWidget(b);
addOKWidget(b);
#endif
+
+ // add last to avoid focus problems
+ addFocusWidget(_savePathBox);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -117,6 +125,11 @@ void BrowserDialog::show(const string& startpath,
BrowserDialog::ListMode mode, int cmd, int cancelCmd,
const string& ext)
{
+ const int fontWidth = _font.getMaxCharWidth(),
+ //fontHeight = _font.getFontHeight(),
+ HBORDER = fontWidth * 1.25;
+ //VGAP = fontHeight / 4;
+
_mode = mode;
_cmd = cmd;
_cancelCmd = cancelCmd;
@@ -140,10 +153,17 @@ void BrowserDialog::show(const string& startpath,
_fileList->setNameFilter([ext](const FilesystemNode& node) {
return BSPF::endsWithIgnoreCase(node.getName(), ext);
});
+ //_fileList->setHeight(_selected->getTop() - VGAP * 2 - _fileList->getTop());
+
+ _currentPath->setWidth(_savePathBox->getLeft() - _currentPath->getLeft() - fontWidth);
+ _savePathBox->setEnabled(true);
+ _savePathBox->clearFlags(Widget::FLAG_INVISIBLE);
+ _savePathBox->setState(instance().settings().getBool("saveuserdir"));
+
+ _name->clearFlags(Widget::FLAG_INVISIBLE);
+ _selected->clearFlags(Widget::FLAG_INVISIBLE);
_selected->setEditable(false);
_selected->setEnabled(false);
- _selected->clearFlags(Widget::FLAG_INVISIBLE);
- _type->clearFlags(Widget::FLAG_INVISIBLE);
_okWidget->setLabel("Load");
break;
@@ -152,22 +172,36 @@ void BrowserDialog::show(const string& startpath,
_fileList->setNameFilter([ext](const FilesystemNode& node) {
return BSPF::endsWithIgnoreCase(node.getName(), ext);
});
+ //_fileList->setHeight(_selected->getTop() - VGAP * 2 - _fileList->getTop());
+
+ _currentPath->setWidth(_savePathBox->getLeft() - _currentPath->getLeft() - fontWidth);
+ _savePathBox->setEnabled(true);
+ _savePathBox->clearFlags(Widget::FLAG_INVISIBLE);
+ _savePathBox->setState(instance().settings().getBool("saveuserdir"));
+
+ _name->clearFlags(Widget::FLAG_INVISIBLE);
+ _selected->clearFlags(Widget::FLAG_INVISIBLE);
_selected->setEditable(true);
_selected->setEnabled(true);
- _selected->clearFlags(Widget::FLAG_INVISIBLE);
- _type->clearFlags(Widget::FLAG_INVISIBLE);
- _okWidget->setLabel("Save");
_selected->setText(fileName);
+ _okWidget->setLabel("Save");
fileSelected = false;
break;
case Directories:
_fileList->setListMode(FilesystemNode::ListMode::DirectoriesOnly);
_fileList->setNameFilter([](const FilesystemNode&) { return true; });
+ // TODO: scrollbar affected too!
+ //_fileList->setHeight(_selected->getBottom() - _fileList->getTop());
+
+ _currentPath->setWidth(_savePathBox->getRight() - _currentPath->getLeft());
+ _savePathBox->setEnabled(false);
+ _savePathBox->setFlags(Widget::FLAG_INVISIBLE);
+
+ _name->setFlags(Widget::FLAG_INVISIBLE);
+ _selected->setFlags(Widget::FLAG_INVISIBLE);
_selected->setEditable(false);
_selected->setEnabled(false);
- _selected->setFlags(Widget::FLAG_INVISIBLE);
- _type->setFlags(Widget::FLAG_INVISIBLE);
_okWidget->setLabel("OK");
break;
}
@@ -177,6 +211,7 @@ void BrowserDialog::show(const string& startpath,
_fileList->setDirectory(FilesystemNode(directory), fileName);
else
_fileList->setDirectory(FilesystemNode(startpath));
+
updateUI(fileSelected);
// Finally, open the dialog after it has been fully updated
@@ -207,6 +242,15 @@ void BrowserDialog::handleCommand(CommandSender* sender, int cmd,
case FileListWidget::ItemActivated:
// Send a signal to the calling class that a selection has been made
// Since we aren't derived from a widget, we don't have a 'data' or 'id'
+ if(_mode != Directories)
+ {
+ // TODO: check if affected by '-baseDir'and 'basedirinapp' params
+ bool savePath = _savePathBox->getState();
+
+ instance().settings().setValue("saveuserdir", savePath);
+ if(savePath)
+ instance().setUserDir(_fileList->currentDir().getShortPath());
+ }
if(_cmd) sendCommand(_cmd, -1, -1);
close();
break;
diff --git a/src/gui/BrowserDialog.hxx b/src/gui/BrowserDialog.hxx
index 1038398c0..8d4b5c2a6 100644
--- a/src/gui/BrowserDialog.hxx
+++ b/src/gui/BrowserDialog.hxx
@@ -67,9 +67,10 @@ class BrowserDialog : public Dialog, public CommandSender
FileListWidget* _fileList{nullptr};
EditTextWidget* _currentPath{nullptr};
- StaticTextWidget* _type{nullptr};
+ StaticTextWidget* _name{nullptr};
EditTextWidget* _selected{nullptr};
ButtonWidget* _goUpButton{nullptr};
+ CheckboxWidget* _savePathBox{nullptr};
BrowserDialog::ListMode _mode{Directories};
diff --git a/src/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx
index fc2c08c47..4273ce6fc 100644
--- a/src/gui/GameInfoDialog.cxx
+++ b/src/gui/GameInfoDialog.cxx
@@ -1397,7 +1397,7 @@ void GameInfoDialog::handleCommand(CommandSender* sender, int cmd,
// to re-create it as necessary
createBrowser("Export properties as");
- myBrowser->show(instance().defaultSaveDir().getPath() + myGameFile.getNameWithExt(".pro"),
+ myBrowser->show(instance().userSaveDir().getPath() + myGameFile.getNameWithExt(".pro"),
BrowserDialog::FileSave, kExportChosen);
break;
diff --git a/src/gui/SnapshotDialog.cxx b/src/gui/SnapshotDialog.cxx
index c983c1d5b..1f3edc36f 100644
--- a/src/gui/SnapshotDialog.cxx
+++ b/src/gui/SnapshotDialog.cxx
@@ -131,7 +131,7 @@ void SnapshotDialog::saveConfig()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SnapshotDialog::setDefaults()
{
- mySnapSavePath->setText(instance().defaultSaveDir().getShortPath());
+ mySnapSavePath->setText(instance().userSaveDir().getShortPath());
mySnapInterval->setValue(2);
mySnapName->setState(false);
mySnapSingle->setState(false);
diff --git a/src/gui/Widget.cxx b/src/gui/Widget.cxx
index 2d4a4c135..d568c14cb 100644
--- a/src/gui/Widget.cxx
+++ b/src/gui/Widget.cxx
@@ -203,6 +203,36 @@ void Widget::setPos(const Common::Point& pos)
}
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void Widget::setWidth(int w)
+{
+ setSize(w, _h);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void Widget::setHeight(int h)
+{
+ setSize(_w, h);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void Widget::setSize(int w, int h)
+{
+ setSize(Common::Point(w, h));
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void Widget::setSize(const Common::Point& pos)
+{
+ if(pos != Common::Point(_w, _h))
+ {
+ _w = pos.x;
+ _h = pos.y;
+ // we have to redraw the whole dialog!
+ dialog().setDirty();
+ }
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Widget::handleMouseEntered()
{
diff --git a/src/gui/Widget.hxx b/src/gui/Widget.hxx
index d62f28e21..e9144f57d 100644
--- a/src/gui/Widget.hxx
+++ b/src/gui/Widget.hxx
@@ -57,6 +57,10 @@ class Widget : public GuiObject
virtual void setPosY(int y);
virtual void setPos(int x, int y);
virtual void setPos(const Common::Point& pos);
+ void setWidth(int w) override;
+ void setHeight(int h) override;
+ virtual void setSize(int w, int h);
+ virtual void setSize(const Common::Point& pos);
virtual bool handleText(char text) { return false; }
virtual bool handleKeyDown(StellaKey key, StellaMod mod) { return false; }