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