From aacf0365baa617a7c7b43c7d601c8d8925dafdba Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 27 Aug 2020 08:53:14 +0200 Subject: [PATCH 1/8] initial commit --- docs/debugger.html | 34 +++---- src/debugger/DebuggerParser.cxx | 11 +- src/debugger/gui/DebuggerDialog.cxx | 152 +++++++++++++++++++++++++++- src/debugger/gui/DebuggerDialog.hxx | 32 +++++- src/gui/BrowserDialog.cxx | 112 ++++++++++++++++---- src/gui/BrowserDialog.hxx | 2 +- src/gui/Dialog.cxx | 4 +- src/gui/Dialog.hxx | 12 +-- 8 files changed, 308 insertions(+), 51 deletions(-) diff --git a/docs/debugger.html b/docs/debugger.html index 781d05bf5..7e51a0333 100644 --- a/docs/debugger.html +++ b/docs/debugger.html @@ -74,7 +74,7 @@
  • Detailed Cartridge Extended RAM Information
  • -
  • Distella Configuration Files
  • +
  • DiStella Configuration Files
  • Tutorial: How to hack a ROM
  • @@ -119,14 +119,14 @@ feature that no other 2600 debugger has; it's completely cross-platform.<
  • Rewind previous advance operations and undo rewinds.
  • -
  • Supports Distella 'configuration directives', which may be used to +
  • Supports DiStella 'configuration directives', which may be used to override automatic code/data determination in the disassembly. For now, the following directives are supported: CODE, GFX, PGFX, COL, PCOL, BCOL, AUD, DATA, ROW. These directives can be entered at the debugger prompt, or be (automatically) loaded and saved in configuration files.
  • Extensive disassembly support, both from the emulation core and with help - from Distella. Where possible, the disassembly differentiates between code, + from DiStella. Where possible, the disassembly differentiates between code, player and playfield graphics, colors and audio (ie, addresses stored in GRPx, PFx, COLUxx, AUDxx) and data (addresses used as an operand of a command). Code sections are also @@ -294,7 +294,7 @@ more convenient.
  • "<rom_filename>.cfg"
    This file is described in - Distella Configuration Files. + DiStella Configuration Files.

  • @@ -917,7 +917,7 @@ Type "help 'cmd'" to see extended information about the given command.

    c - Carry Flag: set (0 or 1), or toggle (no arg) cheat - Use a cheat code (see manual for cheat types) clearbreaks - Clear all breakpoints - clearconfig - Clear Distella config directives [bank xx] + clearconfig - Clear DiStella config directives [bank xx] clearsavestateifs - Clear all savestate points cleartraps - Clear all traps clearwatches - Clear all watches @@ -954,11 +954,11 @@ clearsavestateifs - Clear all savestate points joy1fire - Set joystick 1 fire button to value <x> (0 or 1), or toggle (no arg) jump - Scroll disassembly to address xx listbreaks - List breakpoints - listconfig - List Distella config directives [bank xx] + listconfig - List DiStella config directives [bank xx] listfunctions - List user-defined functions listsavestateifs - List savestate points listtraps - List traps - loadconfig - Load Distella config file + loadconfig - Load DiStella config file loadallstates - Load all emulator states loadstate - Load emulator state xx (0-9) n - Negative Flag: set (0 or 1), or toggle (no arg) @@ -979,12 +979,12 @@ clearsavestateifs - Clear all savestate points s - Set Stack Pointer to value xx save - Save breaks, watches, traps and functions to file xx saveaccess - Save access counters to CSV file - saveconfig - Save Distella config file (with default name) - savedis - Save Distella disassembly (with default name) + saveconfig - Save DiStella config file (with default name) + savedis - Save DiStella disassembly (with default name) saverom - Save (possibly patched) ROM (with default name) saveses - Save console session (with default name) savesnap - Save current TIA image to PNG file - saveallstatea - Save all emulator states + saveallstates - Save all emulator states savestate - Save emulator state xx (valid args 0-9) savestateif - Create savestate on <condition> scanline - Advance emulation by <xx> scanlines (default=1) @@ -1333,11 +1333,11 @@ file is loaded, the disassembly will have labels. Even without a symbol file, th differentiate between code, graphics, data and unused bytes. There are actually two levels of disassembly in Stella. First, the emulation core tracks accesses as a game is running, making for very accurate results. This is known as a dynamic analysis. -Second, the built-in Distella code does a static analysis, which tentatively fills +Second, the built-in DiStella code does a static analysis, which tentatively fills in sections that the dynamic disassembler missed (usually because the addresses haven't been accessed at runtime yet).

    As such, code can be marked in two ways (absolute, when done by the emulation core), -and tentative (when done by Distella, and the emulation core hasn't accessed it yet). +and tentative (when done by DiStella, and the emulation core hasn't accessed it yet). Such 'tentative' code is marked with the '*' symbol, indicating that it has the potential to be accessed as code sometime during the program run. This gives very useful information, since it can indicate areas toggled by an option in the game (ie, when a player dies, @@ -1363,7 +1363,7 @@ by the break command, not the conditional "bre (which makes sense: conditional breaks can break on any condition, the Program Counter isn't necessarily involved).

  • Labels: Any labels assigned to the given address, either generated -automatically by Distella, read from a DASM symbol file or custom +automatically by DiStella, read from a DASM symbol file or custom labels created by the user. If 'Show PC addresses' (see ROM Disassembly Settings) is enabled, the address will be shown in grey.
  • @@ -1377,7 +1377,7 @@ Note that only code, graphics or data will show bytes and can be edited.

    At this point, we should explain the various 'types' that the disassembler can use. These are known as 'directives', and partly correspond to configuration -options from the standalone Distella program. They are listed in order of +options from the standalone DiStella program. They are listed in order of decreasing hierarchy:

    @@ -1504,7 +1504,7 @@ matches the address of the disassembly line where the mouse was clicked.
  • Disassemble @ current line: Disassemble from the disassembly line where the mouse was clicked. This allows to fill gaps in the disassembly and is most useful for bankswitched ROMs.
  • -
  • Show tentative code: Allow Distella to do a static analysis/disassembly.
  • +
  • Show tentative code: Allow DiStella to do a static analysis/disassembly.
  • Show PC addresses: Show Program Counter addresses as labels (where there isn't already a defined label).
  • @@ -1512,7 +1512,7 @@ isn't already a defined label).
  • Show GFX as binary: Switch between displaying/editing GFX and PGFX sections in either binary or hexidecimal.
  • -
  • Use address relocation: Corresponds to the Distella '-r' option +
  • Use address relocation: Corresponds to the DiStella '-r' option (Relocate calls out of address range).
    Note: The code will continue to run fine, but the ROM image will be altered.
  • @@ -1587,7 +1587,7 @@ the RAM in the DPC scheme is not viewable by the 6507, so its addresses start fr
    -

    Distella Configuration Files

    +

    DiStella Configuration Files

    As mentioned in ROM Disassembly, Stella supports the following directives: CODE, GFX, PGFX, COL, PCOL, BCOL, AUD, DATA, ROW. While the debugger will try to automatically mark address space with the appropriate directive, there are times when it will fail. There are diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 73f09268f..97c302392 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -35,6 +35,7 @@ #include "PromptWidget.hxx" #include "RomWidget.hxx" #include "ProgressDialog.hxx" +#include "BrowserDialog.hxx" #include "TimerManager.hxx" #include "Vec.hxx" @@ -1828,14 +1829,20 @@ void DebuggerParser::executeS() // "save" void DebuggerParser::executeSave() { - commandResult << saveScriptFile(argStrings[0]); + if(argCount && argStrings[0] == "?") + debugger.myDialog->showBrowser(DebuggerDialog::svScript); + else + commandResult << saveScriptFile(argStrings[0]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "saveaccess" void DebuggerParser::executeSaveAccess() { - commandResult << debugger.cartDebug().saveAccessFile(); + if(argCount && argStrings[0] == "?") + debugger.myDialog->showBrowser(DebuggerDialog::svAccess); + else + commandResult << debugger.cartDebug().saveAccessFile(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx index be9ad7515..9c51f567b 100644 --- a/src/debugger/gui/DebuggerDialog.cxx +++ b/src/debugger/gui/DebuggerDialog.cxx @@ -37,19 +37,20 @@ #include "DataGridOpsWidget.hxx" #include "EditTextWidget.hxx" #include "MessageBox.hxx" -#include "Debugger.hxx" -#include "DebuggerParser.hxx" +#include "debugger.hxx" +#include "debuggerParser.hxx" #include "ConsoleFont.hxx" #include "ConsoleBFont.hxx" #include "ConsoleMediumFont.hxx" #include "ConsoleMediumBFont.hxx" #include "StellaMediumFont.hxx" #include "OptionsDialog.hxx" +#include "BrowserDialog.hxx" #include "StateManager.hxx" #include "FrameManager.hxx" #include "OSystem.hxx" #include "Console.hxx" -#include "DebuggerDialog.hxx" +#include "debuggerDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DebuggerDialog::DebuggerDialog(OSystem& osystem, DialogContainer& parent, @@ -256,6 +257,43 @@ void DebuggerDialog::handleCommand(CommandSender* sender, int cmd, loadConfig(); break; + case kSvScriptCmd: + execSave("save"); + break; + + case kSvSessionCmd: + execSave("saveses"); + break; + + case kSvConfigCmd: + execSave("saveconfig"); + break; + + case kSvDisCmd: + execSave("savedis"); + break; + + case kSvAccessCmd: + execSave("saveaccess"); + break; + + case kSvRomCmd: + execSave("saverom"); + break; + + case kSvStateCmd: + execSave("savestate"); + break; + + + case kSvAllStatesCmd: + execSave("saveallstates"); + break; + + case kSvSnapCmd: + execSave("savesnap"); // TODO: param + break; + case RomWidget::kInvalidateListing: // Only do a full redraw if the disassembly tab is actually showing myRom->invalidate(myRomTab->getActiveTab() == 0); @@ -408,6 +446,114 @@ void DebuggerDialog::createFont() } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void DebuggerDialog::showBrowser(BrowserType type) +{ + int cmd; + string title; + string key; + string defaultPath; + + switch(type) + { + case BrowserType::svScript: + cmd = kSvScriptCmd; + title = "workbench"; + key = "dbg.savepath"; + defaultPath = instance().defaultSaveDir().getPath() + "commands.script"; + break; + + case BrowserType::svSession: + cmd = kSvSessionCmd; + title = "session"; + key = "dbg.savesessionpath"; + break; + + case BrowserType::svConfig: + cmd = kSvConfigCmd; + title = "DiStella config"; + key = "dbg.saveconfigpath"; + break; + + case BrowserType::svDis: + cmd = kSvDisCmd; + title = "disassembly"; + key = "dbg.savedispath"; + break; + + case BrowserType::svAccess: + cmd = kSvAccessCmd; + title = "access counters"; + key = "dbg.saveaccesspath"; + break; + + case BrowserType::svRom: + cmd = kSvRomCmd; + title = "ROM"; + key = "dbg.saverompath"; + break; + + case BrowserType::svState: + cmd = kSvStateCmd; + title = "state"; + key = "dbg.savestatepath"; + break; + + case BrowserType::svAllStates: + cmd = kSvAllStatesCmd; + title = "all states"; + key = "dbg.savestatepath"; + break; + + case BrowserType::svSnap: + cmd = kSvSnapCmd; + title = "snapshot"; + key = "snapsavedir"; + break; + + default: + cmd = 0; + break; + } + + if(cmd) + { + //TODO: default path (path and filename) + string path = instance().settings().getString(key); + + createBrowser("Save " + title + " as"); + + if(path.empty()) + path = defaultPath; + + //myBrowser->show(instance().defaultSaveDir().getPath(), + // BrowserDialog::FileSave, cmd); + myBrowser->show(path, BrowserDialog::FileSave, cmd); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void DebuggerDialog::execSave(const string& command) +{ + FilesystemNode dir(myBrowser->getResult()); + + instance().debugger().parser().run(command + " " + dir.getShortPath()); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void DebuggerDialog::createBrowser(const string& title) +{ + uInt32 w = 0, h = 0; + getDynamicBounds(w, h); + + // Create file browser dialog + if(!myBrowser || uInt32(myBrowser->getWidth()) != w || + uInt32(myBrowser->getHeight()) != h) + myBrowser = make_unique(this, instance().frameBuffer().font(), w, h, title); + else + myBrowser->setTitle(title); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::showFatalMessage(const string& msg) { diff --git a/src/debugger/gui/DebuggerDialog.hxx b/src/debugger/gui/DebuggerDialog.hxx index 0affa5160..76fb869bb 100644 --- a/src/debugger/gui/DebuggerDialog.hxx +++ b/src/debugger/gui/DebuggerDialog.hxx @@ -34,6 +34,7 @@ class TiaZoomWidget; class CartDebugWidget; class CartRamWidget; class OptionsDialog; +class BrowserDialog; namespace GUI { class MessageBox; @@ -54,6 +55,17 @@ class DebuggerDialog : public Dialog kMediumFontMinW = 1160, kMediumFontMinH = 770, kLargeFontMinW = 1160, kLargeFontMinH = 870 }; + enum BrowserType { + svScript, // save + svSession, // saveses + svConfig, // saveconfig + svDis, // savedis + svAccess, // saveaccess + svRom, // saverom + svState, // savestate + svAllStates, // saveallstates + svSnap // savesnap + }; DebuggerDialog(OSystem& osystem, DialogContainer& parent, int x, int y, int w, int h); @@ -74,6 +86,7 @@ class DebuggerDialog : public Dialog void showFatalMessage(const string& msg); void saveConfig() override; + void showBrowser(BrowserType type); private: void center() override { positionAt(0); } @@ -113,11 +126,23 @@ class DebuggerDialog : public Dialog kDDSAdvCmd = 'DDsv', kDDRewindCmd = 'DDrw', kDDUnwindCmd = 'DDuw', - kDDRunCmd = 'DDex', + kDDRunCmd = 'DDex', kDDExitFatalCmd = 'DDer', - kDDOptionsCmd = 'DDop' + kDDOptionsCmd = 'DDop', + kSvScriptCmd = 'SvSc', + kSvSessionCmd = 'SvSs', + kSvConfigCmd = 'SvCn', + kSvDisCmd = 'SvDs', + kSvAccessCmd = 'SvAc', + kSvRomCmd = 'SvRm', + kSvStateCmd = 'SvSt', + kSvAllStatesCmd = 'SvAs', + kSvSnapCmd = 'SvSn' }; + void execSave(const string& command); + void createBrowser(const string& title); + TabWidget *myTab{nullptr}, *myRomTab{nullptr}; PromptWidget* myPrompt{nullptr}; @@ -135,7 +160,8 @@ class DebuggerDialog : public Dialog ButtonWidget* myUnwindButton{nullptr}; unique_ptr myFatalError; - unique_ptr myOptions; + unique_ptr myOptions; + unique_ptr myBrowser; unique_ptr myLFont; // used for labels unique_ptr myNFont; // used for normal text diff --git a/src/gui/BrowserDialog.cxx b/src/gui/BrowserDialog.cxx index 544ff4518..49a311763 100644 --- a/src/gui/BrowserDialog.cxx +++ b/src/gui/BrowserDialog.cxx @@ -74,7 +74,7 @@ BrowserDialog::BrowserDialog(GuiObject* boss, const GUI::Font& font, _type = new StaticTextWidget(this, font, xpos, ypos + 2, "Name "); _selected = new EditTextWidget(this, font, xpos + _type->getWidth(), ypos, _w - _type->getWidth() - 2 * xpos, lineHeight, ""); - _selected->setEditable(false); + addFocusWidget(_selected); // Buttons _goUpButton = new ButtonWidget(this, font, xpos, _h - buttonHeight - VBORDER, @@ -112,45 +112,71 @@ void BrowserDialog::show(const string& startpath, BrowserDialog::ListMode mode, int cmd, const string& ext) { +#ifdef BSPF_WINDOWS + #define PATH_SEPARATOR '\\' +#else + #define PATH_SEPARATOR '/' +#endif _cmd = cmd; _mode = mode; + string fileName; + + // Set start path + if(_mode != Directories) + { + // split startpath into path and filename + FilesystemNode fs = FilesystemNode(startpath); + fileName = fs.getName(); + string directory = fs.isDirectory() ? "" : fs.getParent().getPath(); + + _fileList->setDirectory(FilesystemNode(directory), fileName); + } + else + { + _fileList->setDirectory(FilesystemNode(startpath)); + } switch(_mode) { case FileLoad: _fileList->setListMode(FilesystemNode::ListMode::All); - _fileList->setNameFilter([&ext](const FilesystemNode& node) { + _fileList->setNameFilter([ext](const FilesystemNode& node) { return BSPF::endsWithIgnoreCase(node.getName(), ext); }); _selected->setEditable(false); + _selected->setEnabled(false); _selected->clearFlags(Widget::FLAG_INVISIBLE); _type->clearFlags(Widget::FLAG_INVISIBLE); + _okWidget->setLabel("Load"); + updateUI(true); break; case FileSave: _fileList->setListMode(FilesystemNode::ListMode::All); - _fileList->setNameFilter([&ext](const FilesystemNode& node) { + _fileList->setNameFilter([ext](const FilesystemNode& node) { return BSPF::endsWithIgnoreCase(node.getName(), ext); }); - _selected->setEditable(false); // FIXME - disable user input for now + _selected->setEditable(true); + _selected->setEnabled(true); _selected->clearFlags(Widget::FLAG_INVISIBLE); _type->clearFlags(Widget::FLAG_INVISIBLE); + _okWidget->setLabel("Save"); + _selected->setText(fileName); + updateUI(false); break; case Directories: _fileList->setListMode(FilesystemNode::ListMode::DirectoriesOnly); _fileList->setNameFilter([](const FilesystemNode&) { return true; }); _selected->setEditable(false); + _selected->setEnabled(false); _selected->setFlags(Widget::FLAG_INVISIBLE); _type->setFlags(Widget::FLAG_INVISIBLE); + _okWidget->setLabel("Choose"); + updateUI(true); break; } - // Set start path - _fileList->setDirectory(FilesystemNode(startpath)); - - updateUI(); - // Finally, open the dialog after it has been fully updated open(); } @@ -159,13 +185,17 @@ void BrowserDialog::show(const string& startpath, const FilesystemNode& BrowserDialog::getResult() const { if(_mode == FileLoad || _mode == FileSave) - return _fileList->selected(); + { + static FilesystemNode node(_fileList->currentDir().getShortPath() + _selected->getText()); + + return node; + } else return _fileList->currentDir(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void BrowserDialog::updateUI() +void BrowserDialog::updateUI(bool fileSelected) { // Only hilite the 'up' button if there's a parent directory _goUpButton->setEnabled(_fileList->currentDir().hasParent()); @@ -174,13 +204,56 @@ void BrowserDialog::updateUI() _currentPath->setText(_fileList->currentDir().getShortPath()); // Enable/disable OK button based on current mode - bool enable = _mode == Directories || !_fileList->selected().isDirectory(); + //bool enable = true; + //switch(_mode) + //{ + // case Directories: + // enable = true; + // break; + + // case FileLoad: + // if(_fileList->selected().isDirectory()) + // { + // enable = false; + // _selected->setText(""); + // } + // else + // { + // enable = fileSelected && !_selected->getText().empty(); + // _selected->setText(_fileList->getSelectedString()); + // } + // break; + + // case FileSave: + // if(_fileList->selected().isDirectory()) + // { + // enable = false; + // _selected->setText(""); + // } + // else + // { + // enable = fileSelected && !_selected->getText().empty(); // TODO + // _selected->setText(_fileList->getSelectedString()); + // } + // break; + + // default: + // break; + //} + //_okWidget->setEnabled(enable); + + bool enable = _mode == Directories + || (!_fileList->selected().isDirectory() && fileSelected) + || (!_selected->getText().empty() && !fileSelected); _okWidget->setEnabled(enable); - if(!_fileList->selected().isDirectory()) - _selected->setText(_fileList->getSelectedString()); - else - _selected->setText(""); + if(fileSelected) + { + if(!_fileList->selected().isDirectory()) + _selected->setText(_fileList->getSelectedString()); + else + _selected->setText(""); + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -205,8 +278,13 @@ void BrowserDialog::handleCommand(CommandSender* sender, int cmd, _fileList->setDirectory(FilesystemNode(instance().baseDir())); break; + case EditableWidget::kChangedCmd: + Dialog::handleCommand(sender, cmd, data, 0); + updateUI(false); + break; + case FileListWidget::ItemChanged: - updateUI(); + updateUI(true); break; default: diff --git a/src/gui/BrowserDialog.hxx b/src/gui/BrowserDialog.hxx index 253e183b7..75a84c7c3 100644 --- a/src/gui/BrowserDialog.hxx +++ b/src/gui/BrowserDialog.hxx @@ -52,7 +52,7 @@ class BrowserDialog : public Dialog, public CommandSender private: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - void updateUI(); + void updateUI(bool fileSelected); private: enum { diff --git a/src/gui/Dialog.cxx b/src/gui/Dialog.cxx index 85c95349f..7c1d7ecd5 100644 --- a/src/gui/Dialog.cxx +++ b/src/gui/Dialog.cxx @@ -684,7 +684,7 @@ bool Dialog::handleNavEvent(Event::Type e, bool repeated) if(_okWidget && _okWidget->isEnabled() && !repeated) { // Receiving 'OK' is the same as getting the 'Select' event - _okWidget->handleEvent(Event::UISelect); + //_okWidget->handleEvent(Event::UISelect); return true; } break; @@ -693,7 +693,7 @@ bool Dialog::handleNavEvent(Event::Type e, bool repeated) if(_cancelWidget && _cancelWidget->isEnabled() && !repeated) { // Receiving 'Cancel' is the same as getting the 'Select' event - _cancelWidget->handleEvent(Event::UISelect); + //_cancelWidget->handleEvent(Event::UISelect); return true; } else if(_processCancel) diff --git a/src/gui/Dialog.hxx b/src/gui/Dialog.hxx index 1f6bbec60..001dafcc0 100644 --- a/src/gui/Dialog.hxx +++ b/src/gui/Dialog.hxx @@ -73,9 +73,9 @@ class Dialog : public GuiObject void addToFocusList(WidgetArray& list, TabWidget* w, int tabId); void addBGroupToFocusList(WidgetArray& list) { _buttonGroup = list; } void addTabWidget(TabWidget* w); - void addDefaultWidget(Widget* w) { _defaultWidget = w; } - void addOKWidget(Widget* w) { _okWidget = w; } - void addCancelWidget(Widget* w) { _cancelWidget = w; } + void addDefaultWidget(ButtonWidget* w) { _defaultWidget = w; } + void addOKWidget(ButtonWidget* w) { _okWidget = w; } + void addCancelWidget(ButtonWidget* w) { _cancelWidget = w; } void setFocus(Widget* w); /** Returns the base surface associated with this dialog. */ @@ -192,9 +192,9 @@ class Dialog : public GuiObject Widget* _mouseWidget{nullptr}; Widget* _focusedWidget{nullptr}; Widget* _dragWidget{nullptr}; - Widget* _defaultWidget{nullptr}; - Widget* _okWidget{nullptr}; - Widget* _cancelWidget{nullptr}; + ButtonWidget* _defaultWidget{nullptr}; + ButtonWidget* _okWidget{nullptr}; + ButtonWidget* _cancelWidget{nullptr}; bool _visible{false}; bool _onTop{true}; From ad7e15139dd91916aa9dec91bcf255194cd485f8 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Wed, 2 Sep 2020 17:50:48 -0230 Subject: [PATCH 2/8] Fix compile errors. --- src/debugger/gui/DebuggerDialog.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx index 9c51f567b..17716b634 100644 --- a/src/debugger/gui/DebuggerDialog.cxx +++ b/src/debugger/gui/DebuggerDialog.cxx @@ -37,8 +37,8 @@ #include "DataGridOpsWidget.hxx" #include "EditTextWidget.hxx" #include "MessageBox.hxx" -#include "debugger.hxx" -#include "debuggerParser.hxx" +#include "Debugger.hxx" +#include "DebuggerParser.hxx" #include "ConsoleFont.hxx" #include "ConsoleBFont.hxx" #include "ConsoleMediumFont.hxx" @@ -50,7 +50,7 @@ #include "FrameManager.hxx" #include "OSystem.hxx" #include "Console.hxx" -#include "debuggerDialog.hxx" +#include "DebuggerDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DebuggerDialog::DebuggerDialog(OSystem& osystem, DialogContainer& parent, From 31e50aa8d17e9f3f0f9e5ce9fbf4180f55158407 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 23 Dec 2020 23:07:00 +0100 Subject: [PATCH 3/8] added file browser to GameInfoDialog export code cleanup updated docs --- docs/graphics/options_gameinfo_cartridge.png | Bin 3454 -> 3456 bytes docs/graphics/options_gameinfo_console.png | Bin 2801 -> 2804 bytes docs/graphics/options_gameinfo_controller.png | Bin 4494 -> 4496 bytes docs/graphics/options_gameinfo_emulation.png | Bin 3630 -> 3632 bytes docs/graphics/options_gameinfo_highscores.png | Bin 3565 -> 3567 bytes docs/index.html | 2 +- src/debugger/gui/DataGridOpsWidget.cxx | 2 +- src/debugger/gui/DebuggerDialog.cxx | 2 + src/emucore/FSNode.cxx | 1 - src/gui/BrowserDialog.cxx | 133 +++++++----------- src/gui/BrowserDialog.hxx | 4 +- src/gui/GameInfoDialog.cxx | 37 ++++- src/gui/GameInfoDialog.hxx | 7 +- src/gui/RomAuditDialog.cxx | 2 + src/gui/SnapshotDialog.cxx | 2 + src/gui/UIDialog.cxx | 2 + 16 files changed, 99 insertions(+), 95 deletions(-) diff --git a/docs/graphics/options_gameinfo_cartridge.png b/docs/graphics/options_gameinfo_cartridge.png index da6f4fdc4409cf8582a8356dc9d02f4c6b16dc32..772f1334bec9d0d080a8d7f05832b8b5c70cf179 100644 GIT binary patch delta 389 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 delta 2451 zcmZ8iX;hO}8jgY!XwXlqNEyn=Y5vDqApZV4JR>S zux-putyhZ!V6d;S4#&{$c+LXdC+)uZt{&r^37cw#FX_F5;FDTJKy5; z8jZl^bYdQ@X!Ga31@Sw3lnUTK014pBC!IQZm)6MOfzKBQLJJ1ll((;0hX_u6B6F$71TL0dD71{$3{DC}`@%D>?OCVEwZ zc?!3A>OO#P%PUm1=g+KU9qb1e|1crs{5;R|-UYF%c8t`<1=L|p7BX%+wWA`GcFKF0 z&oWJWVEIdbuv?-d**%))$6?|Txo|Jj-{E&}P;*B3vwXzW#ion4l5m3RK9X+{>e=Hx zfb`wM{&{yWo7RPy+rttTtSNKRa}+TAgYS>i+!yfl;Jehbd3-{uOqg)8$wMvW1GQDS z-A;F(#-y|r4E-Zh*~K#Y30yc4{fJFA6k%$&^zUUCHD@FGea&vB7;e1qg-_d^9xSJH1ffOpE%5;vUPPD{9rDfEoN9i=Z1@kPr%`@!J zrNDnQSkkCb|5b-Q;0QVt?*Vs1^HQ7?h4?Hn(r1mq{_U4qfnZKAHu@0w(nu)atB)~~ zxRWB0hfd-Z?qp5lwV3Bmnio~TV?84Iog~Fyt9aM-T!(d&mlK%@qdR!$NN!3E-6O0@y& zYruG@o@MQcG8unOx9O^DC~vY4dtBSG#R!aNpKrdcM5~JdVMFD=dyrq zNlI8;DQ}3x`)tKCw&2IN&TjgTv%kETZlbD2f-N;P$wbVNr7YR3Mk-fII}{>VE;Fp~ z>=0y@M9hTDXVb3g^RbVP@W}*ZE11_ri1-@&JnVHv&r{^ve}`ooZI>#wFQ;znR`ED4z7lNxar=+ov9GY_jmKFR!H`H94IW({*`zd{E%(jhW6%mELAyJ!5z9ISYlFu{}rgm+1=!z?ExI%Mf@{SRk3xyQlxHqH7hs z{4lwffVRGD@o`meKGb5N=&u(fAHt4midY{KPBy4B^=;1@ghh5JFo#Au{h)VVXWoKd1C$$v$ya|P;QJ(Y#*To9~Y(F4O!|8U?un zV;Gd#6BQ)UoH^DKWEsz8^N?w}d+{&V4P*SRv3Y#n#sSx$bsNS+USQDmK243LW1p%h zCCxvu6-#M?w!@nKX~;xlU*fF`1BEm&*+OC0e81KKkXFfZLg)k)Qtr_eDXpmAk>{68 z4Vv|n@Q^KyuHz63bM2*2qcC2DX*%+#`=O59z$Q*0)KD2P)uastEKnX8kJ)Ca(dIh< z=-bP3N*U0bDp2Dg2ML!hH1E9AcxjO2SA>dt6-{3IUwW`@RX1R%*c>k3G9g85)KB20 zpI7->CF;mT-0q1ui*y}Tjr1Ospp9(@7DxoY$rauBFW>av9Px&k(wXkAdXV%Xi*h^P zddUETh0uP0*X^y*$x5m_dCOp8&5Zq@EiB&PCK5YK*TG`Gg`}XNDfB z=a^{dEz9$qW#$X7n&*mLP3;JURfv+U4tMik@)Y0h diff --git a/docs/graphics/options_gameinfo_controller.png b/docs/graphics/options_gameinfo_controller.png index 6b8740424429ef7e86ba52c72c8694754293d8cb..63b5548a3f776df9c2c73d0de8bc05c365f08d5d 100644 GIT binary patch delta 2814 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 s(*N8TbyND6+qO|y?WiNM)?_YI(~cpxmRyRt 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 diff --git a/docs/graphics/options_gameinfo_emulation.png b/docs/graphics/options_gameinfo_emulation.png index 8da3b8c42aeaea886f842f82b68aa9a2f21f044c..b67ca95f7561b2b22a036d3bff944dfa8f057578 100644 GIT binary patch delta 3256 zcmZWrc{J4PA0}yT=sVIvHP&lxrAW4BXk-_%XejWFL?S{)8`k!kL1{G91iT*TqCygfuI5gsp4(t&t?*BGt}4rbnnH?)3r5|SJ_rmosd z~?A(B~#Hw5Oq+-CiskX*Ill3)| z_X20j;2^J$gpG%hwYzo`#Gq=0{_AM1$GscgX#n5Cc{Fu>3K|M|+SP)rhGdwsr;| zJw~*{xh!b;y4+~sYq~Z=`@X+8n=nE#c*TNv?pq5LqJA+DR?no<4(;& zmitLlL#>lRr+lk(kBEYL3ApY_@rN;!0(1_fJpH|3-trJD`Zn-euOiT$lIurOY9ZnU zfqvDj9s$iUnXtWzxczJ6(@urG&4FPnBeDa83r6@f#<3hK82h9Zt2lGH6fCl zpq9iG64l*KxDly$v*!>DyhP|SF-=Lh(kSJ z569LYXRNlLK{eGQxpp{au*62a1D*$ckScaW=#43xAqKd7qb|&kd+*tD**PNyGTyuA-HlbeUoD+hg*2aWQEOF{++eT=7%uD&hC2hgCJ5Z6v6y-R*l0qE`OyqzN2C<`TAK`6S^uakIUw?KKX@-_Jx^TL|6WQ? z_>l9-V3NwSR-W?^o51k`Ev9R;h35|-ks{_xsfg<+f?Vm^wi@T7tcxeN>c5SZAA?i zHw~b;EY6H1xJ1@5)jv+(ShpC{e7p8vI{Z~+Lg8YuRuz~b3qROL$ErQ?LVvHIPL#*F z*a2bC;CS-c8~FV`aXOZ6Pqvn#s_63N3(-ni5l3da`qMEMknk5RSv_B>+w}*3oMXtB z^DEMb46SEb(ASra9l|6Zl!;!7>JCHQUhpbgO0Flj@@@jt#k$rRsuds|!BarQ8#DtgYt|AX{b0mW zlyFHQ$slSeBg%c| zSKDOne5>_nRa)m{)iC7*3QiSFySWc>Dj~jap&A)a?A zuq}~SaqZ&h_H@&wkMd$~2TGVlILYD+E;lnx-Zev*Ub1^rG^3R_Cpl<%0aVa3K;LP{ zE=~JVJ7~{G`FM-eZ2+*n+dZSoW%(lc`JgS8Wa_tm$?h|*Q<7^HIC<(HVEv|z`?rJ+ z_73aL`!+_yiQjm%Rv{Fkf?X@*FwxXx#BVqL>yi)KJ`z9#57v{Q3lcYy#Ci-PEy z{AHy-Jyp4Ra%tsw#v!=gO<-mk9XvPvf}%2a^>Ve9mxOdmB;KB`gi_6EINdVok#J7D zPdc(8f-pFZfja_PKU&D(PPD34sdFNe(9zIQ&zh&BSy`UWr+PvW6Q_0G(G*5u#1`qp z6B7ZbYEKPaDg3P`hUm=LzLaQg#Arlh{0@^#vTZD3v$&TH;+19-w5gFKWV^)589Bd! z$iJDE@JIxVzy8<|szt$WieBpQSbl8?JjkB1LQlOax_5bQ)pf9HGRVu)q6V@C(e022 z)DxG?qwi}DK4E5Y`EOHC)pBr62zs?-f$ntSN}9|p#|PZhNRf1C_2c~t^B+ctF^F4!9!8d-PnMO>1vZO5Id}f*5l~Dy(#|E<+1Afb|>bsnZHN7wPvIj-VRoMgJI^TeB#df%mvQJ6OLsJ;b*2R?N9hL z(O6eDw#SP=Ecqikj;7C_Fbfu92z<5foB*7h@!{imI!0;yM+!T$fpq&k+aL1aMfTC|T*+3}VL9 zf8=N+6Hen?xep*1mA_Kv&-H&4Xv{}8dVv2Q6cQ5!$6tDCsjmEPWdHs<5I3va=ZSwj z^-OO34Z3kQfgY3Heo_ohA{_W9seYce>36SExul_;qi$xKL9bc%?nTToAW@n&ei78MGB?&V_G?>zfAQ?HLvHHg$RNwBxEmkJDyn4n;3 z*$$uM31&w_sE1_R)Ae^9$Q#NFk|*wDRFRba(!gwZwce*`n?%@vVXs$A$qXvJnU1Bc#N>&L^}oGbU<613c!Jq>@Z|F z@8w4o^5I4bh4>WPwI#eWI#q*zmQ$ArtUd6{1?6{IV@Pb>Pkf;NMJhA09}?Uw WU&}ej#rcuI&M`B#GNKqbh5ZMxDPINv delta 3254 zcmYk7c{tQv8^=dtNc|>MgMJJ}mO{ysp%C(v7KtnsV|ge`WsIdPW2(WBZ6r&^zBIO` zCKL)UW2fxfh+*tBB+XdH@Yef2@AG!9b6w~BbIx^N-~03Z-fut(NJIlP2n3+Ul!OlAWt#1rE*&bHtE zY(QFZ2zFpnAhoha5$!4?n_t>hPKs)sI<3(%5p1YZv#e_BFmc;-!Dpf|XtR){U-`+g zIaxO!AV|C=@Bv|BRxV)5M-tvORTOtGajsYPuZZ@yA4*0^rl+czukDsN@q_rrM!5vW zpcSc{s>mzgdPXe=?UF<+2Sq ztEaBkP&SDOiU=xvj=w)_RO#geYw22vQeZnhqCK1%xR#FdX}kHJ9_e8dT0B~HxF&$S z6!g$a9bJd5`c|;nxLUu03oQ9@38OEmA&7~kM@oW?vn~UD6)gfTa54NZ2I#^BtG<;= zHlwW+pu&L;nI|CeDM*}m1F}a8*7QXFCh8Yjt_FbqK<4)6_RVLUZ)H0^ed7K+^_TVh z0gpF?KhVjfbPl9TCX)dAEO^#%9AP)%m!wcQzW1X7Nxf*IZc*t&YGMfiW2J~b&dId& z_pB_9R~SDwgJ`YjUhl{pZ5_YLKi*-;abWa~HAJfu{X8rGoTLxohlNr66={Qz9joRS zn19607e%c6V9%@$B%zvR%yy33Gb{4cXn%c`tA>;+f0=vm!B<^)qOIG7WkAA-tV414 zPR_2(B~{uG&wp_LYVeXOKYIKpX*P8IS;oey`Ia17=oB|ZcV{x65b{x!O$rV1ss`l% z^P1baO&kh}#FH*Q={Rs-JxcqSGpsvNmJRE+j<_}e6Navk#}Gaqq`Z)RC*?rm=Y%GX z6P=CcQ2G6?rg3(#B0SZZ8v>b24IOx!-yAh;f9L`wc)!;k~(+o?e4h z%WKywO9Z@T9;e}&*H#Zw$?Yl7;xnrM!*ZJPh2b9=bdwc^*XAz!8{>3dZw5^9LQ9`_ zyH%(I5xVvM9R^C=S(yx|N=@spPgJk|fH{s*y-vw)X7~Syp^FT;t2_6j92tKCutHVk8A4m(cRQr#*yA5QvWG^5~54Xl9r;10B`kE za3^kwdd8m4(rDT$XR^>jUf635X335KcDeKxQ?_0cNFz>YKwY*O`v`kiJx;?SPdt|s zvw3L{nntYq>jXtYG-UWYOetGAqPsx1eAYl5;%>OT$+QZeqe@ucT`N#6gV*Y>&908;gGh+5zuS=kox9T%Zv0%2SqCr*WXr3F?h1S1!THmg*~h z%R{Rt-wClg%#`gh8`hj$8x*%LuAiplbfR(<&BF(4ZMIAd$2YPRDK_6KZ${a?7hL|w z5o@UjnBIZ$TtP|PFOOs{RW1d~FW<%vcqcFVBYt-K*MrqXeorKJPoaV_)Av1iPHk zkZKgb8{_3(*vx&Hml1^eSo43Z)>8erza>wzcX{UehK?!CTjwM*$9z1V)Jm&88pps0U1Z|1uhP8()i z)jNuLR0+1X&2YNgPT1LXzs^Rd;pp-@r^JiGEXN!!VsAvzx{i3t77vSKMW7{ZEKE6g zcPrWikv`*a*Qr5;3ngJmffhxuj&;J@h*y{SIgd)#Tn^vq@F7h4*KB^{btC2Dn7t8 zi-5bq>?)y{1V(wqJjDRJDKqTj?gF z<*vH5UPf$ULUg{1<_o-%UscH-AUx&zP_w~(9td==Dm+^yWn1rilkP>7*h%g!xstDj z^G42=dJ+dqnpIeGKD^1#w_4?*KzVZjm!!REH$ApdHYfo_xF7<2{A2J?W$co{!LhNh zW_R}N_gvlZLH1|5b_m7F5NCf}aQ{eZmouPtwyN1t*IG3GbrBhJmaI*!LLX+YqrCeM zjoP1`ge+Gd{EdxpFkTP}#EU?MaZcNqz1$@HE^sm`={spjE}N`REm*SQv=|6sE}+Uo z%ArG2ti}hLcThtnsxr}}5&`x);n*Ud_?+tjs)zFSDW3_IcW_oYVeO{5{8C+y-Yn-+ zZ4Cv6=h^rMqz>2U3T;=SoTc05V#hk810}x0xKo`{Eq{ima|}bqvao#b;$=n9IQLkp zS3=C;W9Po~dlAiVyY(!G!$Hr76b(SaO}l+pl#Ck7K2&Vjcdopvb;wMIQi{GM>9%l3 zN=W7ELKFEwTa3Q0HI3tdVKrXS%3JPWbT9WFhHB}RZMV1GD>54m!B4#U&a1fr+ceVf zE03|%i6K)?0*h_ul1BUZl{NHnlJ6|mw;07xR_N}D0`f%jrSXouyI##rj!pKKW5k$Y z%7CT%(*am@vBv7-I<7(S`vIZs)4*wtO34DWCe1WxvT$>fKjGdgYu)~0j&?Kid{{=4 z|sjLYB)jQSPTC?Vh;GATJ2P}s!lC<(grce~LrP(sa7OW72FZz#+ zc!od@1)=f&_^7@O4n8chwrO!!U}N6+&6%1!+Exn3iRpViAD&f}Um{Wfx3wPNndr@L zJ^49T9xDCU@UDl!+h@LKBsw2lQrAQM-3A5ipBDM0Z)d$nOw~MkO@H6)ADfMTs*OW_ OE)!$Za}+~|C;tZ9-uZQQiXqJ zt1K%TF@*T0?EdPf?5}d)G^@q$Q1#cihO6)ey!eA0Yl_eCN)_>S;XB4hk2b;Y6W&;Z zFI-sxv#a_)Oo0>8gHCtwa=WOWU1 z()LBkf9eZR8$C0*w#V;k@jI2AIjU-W-ATmw9fmIt#irlhi}0_r@U>04dVI#1asCN@ z#`(MM`X2oHwl7+r!&i;B0^d|!XZ7(r-1+4Z-(>x&o?lluw0>8Cug|O)zG*->e%SUE zJ`-=)#`sm|{h-O$w|&`(xt?G3-@WV6ap$*QS!UAd@A|qe{>;lB>-@IoXTf#P<`=yz zm*xD|{Dhwt-SH7V;S>J;@E44c&&#swasF0C_|UKj9~u_nL&Itwzh!-V{2vvaXk~P{ Rvbg{N002ovPDHLkV1i0+$t(Z> delta 369 zcmV-%0gnFf8|@pAa1Ox$01m+cxRGn^000eJv3?p1e^*1s;v{GdSK;@Jb^Wztslq?A zRhHF^7(#qgc7OF#_E))Yn$^SaQ1#bo4Oig{c<~20(iETJRVw1^!gq|19&3W%Cw#F6 zUpTS?W>@uzc*lh2SRY65rCZ7by+}E}^g)x@2p?}{7`|#N0>)Oo0>8gHCtwa=WOWTM zYWt#WfAs~Zjh>l&TjO`N_?=45991>G?j&OT4#$@VW7F^NCHU7__}U^}Jw9X1IR6Ac z>-=4JeFuJh+ZS!m;j6}5fp03Vv-8Cug|O)zG*-y{IKmS ze6~G))p

    - +
    Allow all 4 directions ...Allow all 4 joystick directions to be pressed simultaneously-joyallow4
    Use modifier key combosEnable using modifier keys in keyboard actions-modcombo
    Swap Stelladaptor portsSwap the order of the detected Stelladaptors/2600-daptors (see Advanced Configuration - Stelladaptor/2600-daptor Support)-saport
    Joystick databaseShow all joysticks that Stella knows about, with the option to remove them 
    Joystick DatabaseShow all joysticks that Stella knows about, with the option to remove them 
    Erase EEPROMErase the whole AtariVox/SaveKey flash memory 
    AtariVox serial portDescribed in further detail in Advanced Configuration - AtariVox/SaveKey Support -avoxport
    diff --git a/src/debugger/gui/DataGridOpsWidget.cxx b/src/debugger/gui/DataGridOpsWidget.cxx index 2a62ec60c..e4bf5d247 100644 --- a/src/debugger/gui/DataGridOpsWidget.cxx +++ b/src/debugger/gui/DataGridOpsWidget.cxx @@ -34,7 +34,7 @@ DataGridOpsWidget::DataGridOpsWidget(GuiObject* boss, const GUI::Font& font, _zeroButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight, "0", kDGZeroCmd); _zeroButton->setToolTip("Zero currently selected value"); - + ypos += bheight + space; _invButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight, "Inv", kDGInvertCmd); diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx index 87481234c..8abf382d4 100644 --- a/src/debugger/gui/DebuggerDialog.cxx +++ b/src/debugger/gui/DebuggerDialog.cxx @@ -489,6 +489,8 @@ void DebuggerDialog::createBrowser(const string& title) { uInt32 w = 0, h = 0; getDynamicBounds(w, h); + if(w > uInt32(_font.getMaxCharWidth() * 80)) + w = _font.getMaxCharWidth() * 80; // Create file browser dialog if(!myBrowser || uInt32(myBrowser->getWidth()) != w || diff --git a/src/emucore/FSNode.cxx b/src/emucore/FSNode.cxx index d9de7e0a5..212828379 100644 --- a/src/emucore/FSNode.cxx +++ b/src/emucore/FSNode.cxx @@ -59,7 +59,6 @@ FilesystemNode& FilesystemNode::operator/=(const string& path) } return *this; -#undef PATH_SEPARATOR } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/BrowserDialog.cxx b/src/gui/BrowserDialog.cxx index 25b35aee1..3b1ee48a7 100644 --- a/src/gui/BrowserDialog.cxx +++ b/src/gui/BrowserDialog.cxx @@ -81,14 +81,19 @@ BrowserDialog::BrowserDialog(GuiObject* boss, const GUI::Font& font, buttonWidth, buttonHeight, "Go up", kGoUpCmd); addFocusWidget(_goUpButton); - _basedirButton = - new ButtonWidget(this, font, _goUpButton->getRight() + BUTTON_GAP, _h - buttonHeight - VBORDER, - buttonWidth, buttonHeight, "Base Dir", kBaseDirCmd); - addFocusWidget(_basedirButton); + b = new ButtonWidget(this, font, _goUpButton->getRight() + BUTTON_GAP, _h - buttonHeight - VBORDER, + buttonWidth, buttonHeight, "Base Dir", kBaseDirCmd); + b->setToolTip("Go to Stella's base directory."); + addFocusWidget(b); + + b = new ButtonWidget(this, font, b->getRight() + BUTTON_GAP, _h - buttonHeight - VBORDER, + buttonWidth, buttonHeight, "Home Dir", kHomeDirCmd); + b->setToolTip("Go to user's home directory."); + addFocusWidget(b); #ifndef BSPF_MACOS b = new ButtonWidget(this, font, _w - (2 * buttonWidth + BUTTON_GAP + HBORDER), _h - buttonHeight - VBORDER, - buttonWidth, buttonHeight, "Choose", kChooseCmd); + buttonWidth, buttonHeight, "OK", kChooseCmd); addFocusWidget(b); addOKWidget(b); b = new ButtonWidget(this, font, _w - (buttonWidth + HBORDER), _h - buttonHeight - VBORDER, @@ -101,7 +106,7 @@ BrowserDialog::BrowserDialog(GuiObject* boss, const GUI::Font& font, addFocusWidget(b); addCancelWidget(b); b = new ButtonWidget(this, font, _w - (buttonWidth + HBORDER), _h - buttonHeight - VBORDER, - buttonWidth, buttonHeight, "Choose", kChooseCmd); + buttonWidth, buttonHeight, "OK", kChooseCmd); addFocusWidget(b); addOKWidget(b); #endif @@ -115,7 +120,9 @@ void BrowserDialog::show(const string& startpath, _mode = mode; _cmd = cmd; _cancelCmd = cancelCmd; - string fileName; + string directory;// = EmptyString; + string fileName;// = EmptyString; + bool fileSelected = true; // Set start path if(_mode != Directories) @@ -123,13 +130,7 @@ void BrowserDialog::show(const string& startpath, // split startpath into path and filename FilesystemNode fs = FilesystemNode(startpath); fileName = fs.getName(); - string directory = fs.isDirectory() ? "" : fs.getParent().getPath(); - - _fileList->setDirectory(FilesystemNode(directory), fileName); - } - else - { - _fileList->setDirectory(FilesystemNode(startpath)); + directory = fs.isDirectory() ? "" : fs.getParent().getPath(); } switch(_mode) @@ -144,7 +145,6 @@ void BrowserDialog::show(const string& startpath, _selected->clearFlags(Widget::FLAG_INVISIBLE); _type->clearFlags(Widget::FLAG_INVISIBLE); _okWidget->setLabel("Load"); - updateUI(true); break; case FileSave: @@ -158,7 +158,7 @@ void BrowserDialog::show(const string& startpath, _type->clearFlags(Widget::FLAG_INVISIBLE); _okWidget->setLabel("Save"); _selected->setText(fileName); - updateUI(false); + fileSelected = false; break; case Directories: @@ -168,11 +168,17 @@ void BrowserDialog::show(const string& startpath, _selected->setEnabled(false); _selected->setFlags(Widget::FLAG_INVISIBLE); _type->setFlags(Widget::FLAG_INVISIBLE); - _okWidget->setLabel("Choose"); - updateUI(true); + _okWidget->setLabel("OK"); break; } + // Set start path + if(_mode != Directories) + _fileList->setDirectory(FilesystemNode(directory), fileName); + else + _fileList->setDirectory(FilesystemNode(startpath)); + updateUI(fileSelected); + // Finally, open the dialog after it has been fully updated open(); } @@ -182,76 +188,15 @@ const FilesystemNode& BrowserDialog::getResult() const { if(_mode == FileLoad || _mode == FileSave) { - static FilesystemNode node(_fileList->currentDir().getShortPath() + _selected->getText()); + static FilesystemNode node; - return node; + return node + = FilesystemNode(_fileList->currentDir().getShortPath() + _selected->getText()); } else return _fileList->currentDir(); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void BrowserDialog::updateUI(bool fileSelected) -{ - // Only hilite the 'up' button if there's a parent directory - _goUpButton->setEnabled(_fileList->currentDir().hasParent()); - - // Update the path display - _currentPath->setText(_fileList->currentDir().getShortPath()); - - // Enable/disable OK button based on current mode - //bool enable = true; - //switch(_mode) - //{ - // case Directories: - // enable = true; - // break; - - // case FileLoad: - // if(_fileList->selected().isDirectory()) - // { - // enable = false; - // _selected->setText(""); - // } - // else - // { - // enable = fileSelected && !_selected->getText().empty(); - // _selected->setText(_fileList->getSelectedString()); - // } - // break; - - // case FileSave: - // if(_fileList->selected().isDirectory()) - // { - // enable = false; - // _selected->setText(""); - // } - // else - // { - // enable = fileSelected && !_selected->getText().empty(); // TODO - // _selected->setText(_fileList->getSelectedString()); - // } - // break; - - // default: - // break; - //} - //_okWidget->setEnabled(enable); - - bool enable = _mode == Directories - || (!_fileList->selected().isDirectory() && fileSelected) - || (!_selected->getText().empty() && !fileSelected); - _okWidget->setEnabled(enable); - - if(fileSelected) - { - if(!_fileList->selected().isDirectory()) - _selected->setText(_fileList->getSelectedString()); - else - _selected->setText(""); - } -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void BrowserDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) @@ -281,6 +226,10 @@ void BrowserDialog::handleCommand(CommandSender* sender, int cmd, _fileList->setDirectory(FilesystemNode(instance().baseDir())); break; + case kHomeDirCmd: + _fileList->setDirectory(FilesystemNode(instance().defaultSaveDir())); + break; + case EditableWidget::kChangedCmd: Dialog::handleCommand(sender, cmd, data, 0); updateUI(false); @@ -295,3 +244,23 @@ void BrowserDialog::handleCommand(CommandSender* sender, int cmd, break; } } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void BrowserDialog::updateUI(bool fileSelected) +{ + // Only hilite the 'up' button if there's a parent directory + _goUpButton->setEnabled(_fileList->currentDir().hasParent()); + + // Update the path display + _currentPath->setText(_fileList->currentDir().getShortPath()); + + // Enable/disable OK button based on current mode and status + bool enable = true; + + if(_mode != Directories) + enable = !_selected->getText().empty(); + _okWidget->setEnabled(enable); + + if(fileSelected && !_fileList->selected().isDirectory()) + _selected->setText(_fileList->getSelectedString()); +} diff --git a/src/gui/BrowserDialog.hxx b/src/gui/BrowserDialog.hxx index 9ee401ad6..1038398c0 100644 --- a/src/gui/BrowserDialog.hxx +++ b/src/gui/BrowserDialog.hxx @@ -58,7 +58,8 @@ class BrowserDialog : public Dialog, public CommandSender enum { kChooseCmd = 'CHOS', kGoUpCmd = 'GOUP', - kBaseDirCmd = 'BADR' + kBaseDirCmd = 'BADR', + kHomeDirCmd = 'HODR' }; int _cmd{0}; @@ -69,7 +70,6 @@ class BrowserDialog : public Dialog, public CommandSender StaticTextWidget* _type{nullptr}; EditTextWidget* _selected{nullptr}; ButtonWidget* _goUpButton{nullptr}; - ButtonWidget* _basedirButton{nullptr}; BrowserDialog::ListMode _mode{Directories}; diff --git a/src/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx index 3700caf5f..fc2c08c47 100644 --- a/src/gui/GameInfoDialog.cxx +++ b/src/gui/GameInfoDialog.cxx @@ -29,6 +29,7 @@ #include "Paddles.hxx" #include "PopUpWidget.hxx" #include "PropsSet.hxx" +#include "BrowserDialog.hxx" #include "QuadTariDialog.hxx" #include "TabWidget.hxx" #include "TIAConstants.hxx" @@ -92,7 +93,7 @@ GameInfoDialog::GameInfoDialog( myTab->setActiveTab(0); // Add Defaults, OK and Cancel buttons - addDefaultsExtraOKCancelBGroup(wid, font, "Export", kExportPressed); + addDefaultsExtraOKCancelBGroup(wid, font, "Export" + ELLIPSIS, kExportPressed); _extraWidget->setToolTip("Export the current ROM's properties\n" "into the default directory."); addBGroupToFocusList(wid); @@ -660,12 +661,27 @@ void GameInfoDialog::addHighScoresTab() addToFocusList(wid, myTab, tabID); } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GameInfoDialog::~GameInfoDialog() { } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void GameInfoDialog::createBrowser(const string& title) +{ + uInt32 w = 0, h = 0; + getDynamicBounds(w, h); + if(w > uInt32(_font.getMaxCharWidth() * 80)) + w = _font.getMaxCharWidth() * 80; + + // Create file browser dialog + if(!myBrowser || uInt32(myBrowser->getWidth()) != w || + uInt32(myBrowser->getHeight()) != h) + myBrowser = make_unique(this, _font, w, h, title); + else + myBrowser->setTitle(title); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GameInfoDialog::loadConfig() { @@ -1350,16 +1366,14 @@ void GameInfoDialog::exportCurrentPropertiesToDisk() try { - FilesystemNode propfile = instance().defaultSaveDir(); - propfile /= myGameFile.getNameWithExt(".pro"); + FilesystemNode propfile(myBrowser->getResult().getShortPath()); propfile.write(out); - instance().frameBuffer().showTextMessage("Properties exported to " + - propfile.getShortPath()); + instance().frameBuffer().showTextMessage("ROM properties exported"); } catch(...) { - instance().frameBuffer().showTextMessage("Error exporting properties"); + instance().frameBuffer().showTextMessage("Error exporting ROM properties"); } } @@ -1379,6 +1393,15 @@ void GameInfoDialog::handleCommand(CommandSender* sender, int cmd, break; case kExportPressed: + // This dialog is resizable under certain conditions, so we need + // to re-create it as necessary + createBrowser("Export properties as"); + + myBrowser->show(instance().defaultSaveDir().getPath() + myGameFile.getNameWithExt(".pro"), + BrowserDialog::FileSave, kExportChosen); + break; + + case kExportChosen: exportCurrentPropertiesToDisk(); break; diff --git a/src/gui/GameInfoDialog.hxx b/src/gui/GameInfoDialog.hxx index c217bd689..d3af6775e 100644 --- a/src/gui/GameInfoDialog.hxx +++ b/src/gui/GameInfoDialog.hxx @@ -27,6 +27,7 @@ class RadioButtonGroup; class TabWidget; class SliderWidget; class QuadTariDialog; +class BrowserDialog; #include "Dialog.hxx" #include "Command.hxx" @@ -78,6 +79,7 @@ class GameInfoDialog : public Dialog, public CommandSender void setAddressVal(EditTextWidget* address, EditTextWidget* val, bool isBCD = true, bool zeroBased = false, uInt8 maxVal = 255); void exportCurrentPropertiesToDisk(); + void createBrowser(const string& title); private: TabWidget* myTab{nullptr}; @@ -168,6 +170,8 @@ class GameInfoDialog : public Dialog, public CommandSender StaticTextWidget* myHighScoreNotesLabel{nullptr}; EditTextWidget* myHighScoreNotes{nullptr}; + unique_ptr myBrowser; + enum { kVCenterChanged = 'Vcch', kPhosphorChanged = 'PPch', @@ -180,7 +184,8 @@ class GameInfoDialog : public Dialog, public CommandSender kHiScoresChanged = 'HSch', kPXCenterChanged = 'Pxch', kPYCenterChanged = 'Pych', - kExportPressed = 'GIsp' + kExportPressed = 'Expr', + kExportChosen = 'Exch' }; // Game properties for currently loaded ROM diff --git a/src/gui/RomAuditDialog.cxx b/src/gui/RomAuditDialog.cxx index 65b4d0c33..60b627f8d 100644 --- a/src/gui/RomAuditDialog.cxx +++ b/src/gui/RomAuditDialog.cxx @@ -223,6 +223,8 @@ void RomAuditDialog::createBrowser(const string& title) { uInt32 w = 0, h = 0; getDynamicBounds(w, h); + if(w > uInt32(_font.getMaxCharWidth() * 80)) + w = _font.getMaxCharWidth() * 80; // Create file browser dialog if(!myBrowser || uInt32(myBrowser->getWidth()) != w || diff --git a/src/gui/SnapshotDialog.cxx b/src/gui/SnapshotDialog.cxx index 80af8ec1d..c983c1d5b 100644 --- a/src/gui/SnapshotDialog.cxx +++ b/src/gui/SnapshotDialog.cxx @@ -183,6 +183,8 @@ void SnapshotDialog::createBrowser(const string& title) { uInt32 w = 0, h = 0; getDynamicBounds(w, h); + if(w > uInt32(_font.getMaxCharWidth() * 80)) + w = _font.getMaxCharWidth() * 80; // Create file browser dialog if(!myBrowser || uInt32(myBrowser->getWidth()) != w || diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index beb6f576d..6ba10d9f8 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -706,6 +706,8 @@ void UIDialog::createBrowser(const string& title) { uInt32 w = 0, h = 0; getDynamicBounds(w, h); + if(w > uInt32(_font.getMaxCharWidth() * 80)) + w = _font.getMaxCharWidth() * 80; // Create file browser dialog if(!myBrowser || uInt32(myBrowser->getWidth()) != w || From b9cb829390719f38e6e177a2b68a87ce1fffeedc Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 24 Dec 2020 11:48:15 +0100 Subject: [PATCH 4/8] added "userdir" settings which can be used to overwrite default save (and load) directories --- src/debugger/CartDebug.cxx | 6 +-- src/debugger/DebuggerParser.cxx | 8 ++-- src/debugger/gui/DebuggerDialog.cxx | 2 +- src/emucore/OSystem.cxx | 16 +++++++ src/emucore/OSystem.hxx | 7 ++- src/emucore/Settings.cxx | 4 ++ src/gui/BrowserDialog.cxx | 66 ++++++++++++++++++++++++----- src/gui/BrowserDialog.hxx | 3 +- src/gui/GameInfoDialog.cxx | 2 +- src/gui/SnapshotDialog.cxx | 2 +- src/gui/Widget.cxx | 30 +++++++++++++ src/gui/Widget.hxx | 4 ++ 12 files changed, 127 insertions(+), 23 deletions(-) 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; } From 6356d56c58402de62281fce281ca66cf6bc027d1 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 24 Dec 2020 12:24:23 +0100 Subject: [PATCH 5/8] refactored directory names, removed default load dir updated docs --- Changes.txt | 2 ++ docs/index.html | 10 ++++++++++ src/debugger/CartDebug.cxx | 6 +++--- src/debugger/DebuggerParser.cxx | 8 ++++---- src/debugger/gui/DebuggerDialog.cxx | 2 +- src/emucore/OSystem.cxx | 28 ++++++++++++---------------- src/emucore/OSystem.hxx | 13 ++++++------- src/emucore/Settings.cxx | 17 ++++++++--------- src/gui/BrowserDialog.cxx | 2 +- src/gui/GameInfoDialog.cxx | 2 +- src/gui/LoggerDialog.cxx | 2 +- src/gui/SnapshotDialog.cxx | 2 +- src/gui/UIDialog.cxx | 2 +- 13 files changed, 51 insertions(+), 45 deletions(-) diff --git a/Changes.txt b/Changes.txt index 2f733a6e3..32a133633 100644 --- a/Changes.txt +++ b/Changes.txt @@ -32,6 +32,8 @@ * Added sound to Time Machine playback. + * Added browser dialogs for user saved files. + * Extended global hotkeys for input devices & ports settings. * Increased sample size for CDFJ+. diff --git a/docs/index.html b/docs/index.html index 359a8bfed..5657ce955 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3189,6 +3189,16 @@ Make the start path follow ROM launcher navigation. + +
    -userdir <dir>
    + Set the path to save user files to. + + + +
    -saveuserdir <0|1>
    + Update the user path when navigating in browser. + +
    -maxres <WxH>
    Useful for developers, this sets the maximum size of window that diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index b91e5dc26..47d3212ab 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.userSaveDir().getPath() + path = myOSystem.userDir().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.userSaveDir().getPath() + path = myOSystem.userDir().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.userSaveDir().getPath() + path = myOSystem.userDir().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 2c02c53dd..488fb68f6 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.userSaveDir().getPath() + file; + file = debugger.myOSystem.userDir().getPath() + file; FilesystemNode node(file); @@ -1144,7 +1144,7 @@ void DebuggerParser::executeDump() else { ostringstream file; - file << debugger.myOSystem.userSaveDir() + file << debugger.myOSystem.userDir() << 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.userSaveDir().getPath() + file); + node = FilesystemNode(debugger.myOSystem.userDir().getPath() + file); if (argCount == 2) { execPrefix = argStrings[1]; @@ -1910,7 +1910,7 @@ void DebuggerParser::executeSaveses() { ostringstream filename; auto timeinfo = BSPF::localTime(); - filename << debugger.myOSystem.userSaveDir() + filename << debugger.myOSystem.userDir() << 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 e258aca08..24b2ed4bf 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().userSaveDir().getPath() + defaultName; + const string path = instance().userDir().getPath() + defaultName; myBrowser->show(path, BrowserDialog::FileSave, cmd, kBdCancelCmd); } } diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index c9fb0070b..72ec65814 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -217,8 +217,8 @@ void OSystem::loadConfig(const Settings::Options& options) { // Get base directory and config file from derived class // It will decide whether it can override its default location - string baseDir, cfgFile, defSaveDir, defLoadDir; - getBaseDirAndConfig(baseDir, cfgFile, defSaveDir, defLoadDir, + string baseDir, cfgFile, homeDir, unused; + getBaseDirAndConfig(baseDir, cfgFile, homeDir, unused, ourOverrideBaseDirWithApp, ourOverrideBaseDir); // Get fully-qualified pathnames, and make directories when needed @@ -228,13 +228,9 @@ void OSystem::loadConfig(const Settings::Options& options) if(!cfgFile.empty()) myConfigFile = FilesystemNode(cfgFile); - myDefaultSaveDir = FilesystemNode(defSaveDir); - if(!myDefaultSaveDir.isDirectory()) - myDefaultSaveDir.makeDir(); - - myDefaultLoadDir = FilesystemNode(defLoadDir); - if(!myDefaultLoadDir.isDirectory()) - myDefaultLoadDir.makeDir(); + myHomeDir = FilesystemNode(homeDir); + if(!myHomeDir.isDirectory()) + myHomeDir.makeDir(); #ifdef SQLITE_SUPPORT mySettingsDb = make_shared(myBaseDir.getPath(), "settings"); @@ -249,10 +245,10 @@ void OSystem::loadConfig(const Settings::Options& 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(); + userDir = homeDir; + myUserDir = FilesystemNode(userDir); + if(!myUserDir.isDirectory()) + myUserDir.makeDir(); Logger::instance().setLogParameters(mySettings->getInt("loglevel"), mySettings->getBool("logtoconsole")); @@ -303,7 +299,7 @@ void OSystem::setConfigPaths() #ifdef PNG_SUPPORT const string& ssSaveDir = mySettings->getString("snapsavedir"); if(ssSaveDir == EmptyString) - mySnapshotSaveDir = defaultSaveDir(); + mySnapshotSaveDir = userDir(); else mySnapshotSaveDir = FilesystemNode(ssSaveDir); if(!mySnapshotSaveDir.isDirectory()) @@ -311,7 +307,7 @@ void OSystem::setConfigPaths() const string& ssLoadDir = mySettings->getString("snaploaddir"); if(ssLoadDir == EmptyString) - mySnapshotLoadDir = defaultLoadDir(); + mySnapshotLoadDir = userDir(); else mySnapshotLoadDir = FilesystemNode(ssLoadDir); if(!mySnapshotLoadDir.isDirectory()) @@ -346,7 +342,7 @@ void OSystem::setUserDir(const string& path) { mySettings->setValue("userdir", path); - myUserSaveDir = FilesystemNode(path); + myUserDir = FilesystemNode(path); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/OSystem.hxx b/src/emucore/OSystem.hxx index 1ac973976..0ce5aef4b 100644 --- a/src/emucore/OSystem.hxx +++ b/src/emucore/OSystem.hxx @@ -318,12 +318,11 @@ class OSystem const FilesystemNode& romFile() const { return myRomFile; } /** - The default locations for saving and loading various files that - don't already have a specific location. + The default and user defined locations for saving and loading various + files that don't already have a specific location. */ - const FilesystemNode& defaultSaveDir() const { return myDefaultSaveDir; } - const FilesystemNode& defaultLoadDir() const { return myDefaultLoadDir; } - const FilesystemNode& userSaveDir() const { return myUserSaveDir; } + const FilesystemNode& homeDir() const { return myHomeDir; } + const FilesystemNode& userDir() const { return myUserDir; } /** Open the given ROM and return an array containing its contents. @@ -556,8 +555,8 @@ class OSystem private: FilesystemNode myBaseDir, myStateDir, mySnapshotSaveDir, mySnapshotLoadDir, - myNVRamDir, myCfgDir, myDefaultSaveDir, myDefaultLoadDir, - myUserSaveDir; + myNVRamDir, myCfgDir, myHomeDir, + myUserDir; FilesystemNode myCheatFile, myConfigFile, myPaletteFile, myPropertiesFile; FilesystemNode myRomFile; string myRomMD5; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 8068b29a9..f9d8e459e 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -528,14 +528,14 @@ void Settings::usage() const << endl << " -saveonexit emulation\n" - << " -autoslot <1|0> Automatically change to next save slot when\n" + << " -autoslot <0|1> Automatically change to next save slot when\n" << " state saving\n" << endl << " -rominfo Display detailed information for the given ROM\n" << " -listrominfo Display contents of stella.pro, one line per ROM\n" << " entry\n" << endl - << " -exitlauncher <1|0> On exiting a ROM, go back to the ROM launcher\n" + << " -exitlauncher <0|1> On exiting a ROM, go back to the ROM launcher\n" << " -launcherpos Sets the window position in windowed EOM launcher mode\n" << " -launcherdisplay Sets the display for the ROM launcher\n" << " -launcherres The resolution to use in ROM launcher mode\n" @@ -544,11 +544,14 @@ void Settings::usage() const << " medium|large|\n" << " large12|large14|\n" << " large16>\n" - << " -launcherroms <1|0> Show only ROMs in the launcher (vs. all files)\n" - << " -launchersubdirs <1|0> Show files from subdirectories too\n" << " -romviewer Show ROM info viewer at given zoom level in ROM\n" << " launcher (use 0 for off)\n" - << " -followlauncher <0|1> Default ROM path follows launcher navigation\n" + << " -launcherroms <1|0> Show only ROMs in the launcher (vs. all files)\n" + << " -launchersubdirs <0|1> Show files from subdirectories too\n" + << " -romdir Set the path where the ROM launcher will start\n" + << " -followlauncher <0|1> Default ROM path follows launcher navigation\n" + << " -userdir Set the path to save user files to\n" + << " -saveuserdir <0|1> Update user path when navigating in browser\n" << " -lastrom Last played ROM, automatically selected in\n" << " launcher\n" << " -romloadcount Number of ROM to load next from multicard\n" @@ -572,10 +575,6 @@ void Settings::usage() const << " -ctrlrate Rate per second of repeated controller input in\n" << " UI\n" << " -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 026c16b2f..d401ed8cb 100644 --- a/src/gui/BrowserDialog.cxx +++ b/src/gui/BrowserDialog.cxx @@ -271,7 +271,7 @@ void BrowserDialog::handleCommand(CommandSender* sender, int cmd, break; case kHomeDirCmd: - _fileList->setDirectory(FilesystemNode(instance().defaultSaveDir())); + _fileList->setDirectory(FilesystemNode(instance().homeDir())); break; case EditableWidget::kChangedCmd: diff --git a/src/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx index 4273ce6fc..7710e9fa1 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().userSaveDir().getPath() + myGameFile.getNameWithExt(".pro"), + myBrowser->show(instance().userDir().getPath() + myGameFile.getNameWithExt(".pro"), BrowserDialog::FileSave, kExportChosen); break; diff --git a/src/gui/LoggerDialog.cxx b/src/gui/LoggerDialog.cxx index 3f94e093e..83929464e 100644 --- a/src/gui/LoggerDialog.cxx +++ b/src/gui/LoggerDialog.cxx @@ -116,7 +116,7 @@ void LoggerDialog::saveConfig() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LoggerDialog::saveLogFile() { - FilesystemNode node = instance().defaultSaveDir(); + FilesystemNode node = instance().userDir(); node /= "stella.log"; try diff --git a/src/gui/SnapshotDialog.cxx b/src/gui/SnapshotDialog.cxx index 1f3edc36f..69ad94936 100644 --- a/src/gui/SnapshotDialog.cxx +++ b/src/gui/SnapshotDialog.cxx @@ -131,7 +131,7 @@ void SnapshotDialog::saveConfig() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SnapshotDialog::setDefaults() { - mySnapSavePath->setText(instance().userSaveDir().getShortPath()); + mySnapSavePath->setText(instance().userDir().getShortPath()); mySnapInterval->setValue(2); mySnapName->setState(false); mySnapSingle->setState(false); diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index 6ba10d9f8..b5b8fb72c 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -515,7 +515,7 @@ void UIDialog::setDefaults() myLauncherHeightSlider->setValue(h); myLauncherFontPopup->setSelected("medium", ""); myRomViewerSize->setValue(35); - mySnapLoadPath->setText(instance().defaultLoadDir().getShortPath()); + mySnapLoadPath->setText(instance().userDir().getShortPath()); myLauncherExitWidget->setState(false); break; } From dfee0703246478c53affe6aadba4bafcff3da241 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 24 Dec 2020 14:50:26 +0100 Subject: [PATCH 6/8] fixed a saveses bug renamed browser titles --- src/debugger/DebuggerParser.cxx | 13 ++++++++----- src/debugger/gui/DebuggerDialog.cxx | 8 ++++---- src/gui/GameInfoDialog.cxx | 2 +- src/gui/RomAuditDialog.cxx | 2 +- src/gui/SnapshotDialog.cxx | 2 +- src/gui/UIDialog.cxx | 4 ++-- 6 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 488fb68f6..3c8bdac5b 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -1144,8 +1144,7 @@ void DebuggerParser::executeDump() else { ostringstream file; - file << debugger.myOSystem.userDir() - << debugger.myOSystem.console().properties().get(PropType::Cart_Name) << "_dbg_"; + file << debugger.myOSystem.userDir() << cartName() << "_dbg_"; if(execDepth > 0) { file << execPrefix; @@ -1910,8 +1909,7 @@ void DebuggerParser::executeSaveses() { ostringstream filename; auto timeinfo = BSPF::localTime(); - filename << debugger.myOSystem.userDir() - << std::put_time(&timeinfo, "session_%F_%H-%M-%S.txt"); + filename << std::put_time(&timeinfo, "session_%F_%H-%M-%S.txt"); if(argCount && argStrings[0] == "?") { @@ -1920,7 +1918,12 @@ void DebuggerParser::executeSaveses() } else { - FilesystemNode file(filename.str()); + ostringstream path; + if(argCount) + path << argStrings[0]; + else + path << debugger.myOSystem.userDir() << filename.str(); + FilesystemNode file(path.str()); if(debugger.prompt().saveBuffer(file)) commandResult << "saved " + file.getShortPath() + " OK"; diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx index 24b2ed4bf..4403009b8 100644 --- a/src/debugger/gui/DebuggerDialog.cxx +++ b/src/debugger/gui/DebuggerDialog.cxx @@ -434,12 +434,12 @@ void DebuggerDialog::showBrowser(BrowserType type, const string& defaultName) { case BrowserType::svAccess: cmd = kSvAccessCmd; - title = "access counters"; + title = "Access Counters"; break; case BrowserType::svDis: cmd = kSvDisCmd; - title = "disassembly"; + title = "Disassembly"; break; case BrowserType::svRom: @@ -449,12 +449,12 @@ void DebuggerDialog::showBrowser(BrowserType type, const string& defaultName) case BrowserType::svScript: cmd = kSvScriptCmd; - title = "workbench"; + title = "Workbench"; break; case BrowserType::svSession: cmd = kSvSessionCmd; - title = "session"; + title = "Session"; break; default: diff --git a/src/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx index 7710e9fa1..9a0cb3fe7 100644 --- a/src/gui/GameInfoDialog.cxx +++ b/src/gui/GameInfoDialog.cxx @@ -1395,7 +1395,7 @@ void GameInfoDialog::handleCommand(CommandSender* sender, int cmd, case kExportPressed: // This dialog is resizable under certain conditions, so we need // to re-create it as necessary - createBrowser("Export properties as"); + createBrowser("Export Properties as"); myBrowser->show(instance().userDir().getPath() + myGameFile.getNameWithExt(".pro"), BrowserDialog::FileSave, kExportChosen); diff --git a/src/gui/RomAuditDialog.cxx b/src/gui/RomAuditDialog.cxx index 60b627f8d..de7f3f5cd 100644 --- a/src/gui/RomAuditDialog.cxx +++ b/src/gui/RomAuditDialog.cxx @@ -198,7 +198,7 @@ void RomAuditDialog::handleCommand(CommandSender* sender, int cmd, break; case kChooseAuditDirCmd: - createBrowser("Select ROM directory to audit"); + createBrowser("Select ROM Directory to Audit"); myBrowser->show(myRomPath->getText(), BrowserDialog::Directories, kAuditDirChosenCmd); break; diff --git a/src/gui/SnapshotDialog.cxx b/src/gui/SnapshotDialog.cxx index 69ad94936..28067213c 100644 --- a/src/gui/SnapshotDialog.cxx +++ b/src/gui/SnapshotDialog.cxx @@ -156,7 +156,7 @@ void SnapshotDialog::handleCommand(CommandSender* sender, int cmd, case kChooseSnapSaveDirCmd: // This dialog is resizable under certain conditions, so we need // to re-create it as necessary - createBrowser("Select snapshot save directory"); + createBrowser("Select Snapshot Save Directory"); myBrowser->show(mySnapSavePath->getText(), BrowserDialog::Directories, kSnapSaveDirChosenCmd); break; diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index b5b8fb72c..65c7d927b 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -586,7 +586,7 @@ void UIDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) case kChooseRomDirCmd: // This dialog is resizable under certain conditions, so we need // to re-create it as necessary - createBrowser("Select ROM directory"); + createBrowser("Select ROM Directory"); myBrowser->show(myRomPath->getText(), BrowserDialog::Directories, LauncherDialog::kRomDirChosenCmd); break; @@ -602,7 +602,7 @@ void UIDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) case kChooseSnapLoadDirCmd: // This dialog is resizable under certain conditions, so we need // to re-create it as necessary - createBrowser("Select snapshot load directory"); + createBrowser("Select ROM Info Viewer Image Directory"); myBrowser->show(mySnapLoadPath->getText(), BrowserDialog::Directories, kSnapLoadDirChosenCmd); break; From b976bd95ca0eff50a7a0f067b1a8b16c9b55e278 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 25 Dec 2020 09:15:58 +0100 Subject: [PATCH 7/8] enhanced and cleaned up OS specific path code improved mouse double click marking added file list resizing in browser dialog --- src/common/bspf.hxx | 11 +++++++++++ src/emucore/OSystem.cxx | 7 +++---- src/emucore/OSystem.hxx | 7 +++---- src/gui/BrowserDialog.cxx | 12 ++++++------ src/gui/EditableWidget.cxx | 12 ++++++------ src/gui/ListWidget.cxx | 11 +++++++++++ src/gui/ListWidget.hxx | 1 + src/libretro/OSystemLIBRETRO.cxx | 6 +++--- src/libretro/OSystemLIBRETRO.hxx | 7 +++---- src/macos/OSystemMACOS.cxx | 9 +++------ src/macos/OSystemMACOS.hxx | 7 +++---- src/unix/OSystemUNIX.cxx | 10 ++++------ src/unix/OSystemUNIX.hxx | 7 +++---- src/unix/r77/OSystemR77.cxx | 4 ++-- src/unix/r77/OSystemR77.hxx | 7 +++---- src/windows/OSystemWINDOWS.cxx | 15 +++++++++------ src/windows/OSystemWINDOWS.hxx | 7 +++---- 17 files changed, 77 insertions(+), 63 deletions(-) diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index 4a17719ad..44d649869 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -336,6 +336,17 @@ namespace BSPF } #endif } + + inline bool isWhiteSpace(const char s) + { + const string WHITESPACES = " ,.;:+-*&/\\'"; + + for(size_t i = 0; i < WHITESPACES.length(); ++i) + if(s == WHITESPACES[i]) + return true; + + return false; + } } // namespace BSPF #endif diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 72ec65814..f920537b5 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -217,8 +217,8 @@ void OSystem::loadConfig(const Settings::Options& options) { // Get base directory and config file from derived class // It will decide whether it can override its default location - string baseDir, cfgFile, homeDir, unused; - getBaseDirAndConfig(baseDir, cfgFile, homeDir, unused, + string baseDir, cfgFile, homeDir; + getBaseDirAndConfig(baseDir, cfgFile, homeDir, ourOverrideBaseDirWithApp, ourOverrideBaseDir); // Get fully-qualified pathnames, and make directories when needed @@ -239,10 +239,9 @@ void OSystem::loadConfig(const Settings::Options& options) #endif mySettings->setRepository(createSettingsRepository()); - mySettings->load(options); - // TODO: check if affected by '-baseDir'and 'basedirinapp' params + // userDir is NOT affected by '-baseDir'and '-basedirinapp' params string userDir = mySettings->getString("userdir"); if(userDir.empty()) userDir = homeDir; diff --git a/src/emucore/OSystem.hxx b/src/emucore/OSystem.hxx index 0ce5aef4b..484bf8861 100644 --- a/src/emucore/OSystem.hxx +++ b/src/emucore/OSystem.hxx @@ -463,8 +463,7 @@ class OSystem @param basedir The base directory for all configuration files @param cfgfile The fully qualified pathname of the config file (including the base directory) - @param savedir The default directory to save various other files - @param loaddir The default directory to load various other files + @param homedir The default directory to store various other files @param useappdir A hint that the base dir should be set to the app directory; not all ports can do this, so they are free to ignore it @@ -473,8 +472,8 @@ class OSystem they are free to ignore it */ virtual void getBaseDirAndConfig(string& basedir, string& cfgfile, - string& savedir, string& loaddir, - bool useappdir, const string& usedir) = 0; + string& homedir, + bool useappdir, const string& usedir) = 0; protected: // Pointer to the EventHandler object diff --git a/src/gui/BrowserDialog.cxx b/src/gui/BrowserDialog.cxx index d401ed8cb..d56b8558d 100644 --- a/src/gui/BrowserDialog.cxx +++ b/src/gui/BrowserDialog.cxx @@ -126,9 +126,9 @@ void BrowserDialog::show(const string& startpath, const string& ext) { const int fontWidth = _font.getMaxCharWidth(), - //fontHeight = _font.getFontHeight(), - HBORDER = fontWidth * 1.25; - //VGAP = fontHeight / 4; + fontHeight = _font.getFontHeight(), + HBORDER = fontWidth * 1.25, + VGAP = fontHeight / 4; _mode = mode; _cmd = cmd; @@ -153,7 +153,7 @@ 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()); + _fileList->setHeight(_selected->getTop() - VGAP * 2 - _fileList->getTop()); _currentPath->setWidth(_savePathBox->getLeft() - _currentPath->getLeft() - fontWidth); _savePathBox->setEnabled(true); @@ -172,7 +172,7 @@ 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()); + _fileList->setHeight(_selected->getTop() - VGAP * 2 - _fileList->getTop()); _currentPath->setWidth(_savePathBox->getLeft() - _currentPath->getLeft() - fontWidth); _savePathBox->setEnabled(true); @@ -192,7 +192,7 @@ void BrowserDialog::show(const string& startpath, _fileList->setListMode(FilesystemNode::ListMode::DirectoriesOnly); _fileList->setNameFilter([](const FilesystemNode&) { return true; }); // TODO: scrollbar affected too! - //_fileList->setHeight(_selected->getBottom() - _fileList->getTop()); + _fileList->setHeight(_selected->getBottom() - _fileList->getTop()); _currentPath->setWidth(_savePathBox->getRight() - _currentPath->getLeft()); _savePathBox->setEnabled(false); diff --git a/src/gui/EditableWidget.cxx b/src/gui/EditableWidget.cxx index 0a76bd7d1..2b37a0ba2 100644 --- a/src/gui/EditableWidget.cxx +++ b/src/gui/EditableWidget.cxx @@ -657,7 +657,7 @@ bool EditableWidget::killWord(int direction) { while(currentPos > 0) { - if(_editString[currentPos - 1] == ' ') + if(BSPF::isWhiteSpace(_editString[currentPos - 1])) { if(!space) break; @@ -673,7 +673,7 @@ bool EditableWidget::killWord(int direction) { while(currentPos < int(_editString.size())) { - if(currentPos && _editString[currentPos - 1] == ' ') + if(currentPos && BSPF::isWhiteSpace(_editString[currentPos - 1])) { if(!space) break; @@ -709,7 +709,7 @@ bool EditableWidget::moveWord(int direction, bool select) { while (currentPos > 0) { - if (_editString[currentPos - 1] == ' ') + if (BSPF::isWhiteSpace(_editString[currentPos - 1])) { if (!space) break; @@ -728,7 +728,7 @@ bool EditableWidget::moveWord(int direction, bool select) { while (currentPos < int(_editString.size())) { - if (currentPos && _editString[currentPos - 1] == ' ') + if (currentPos && BSPF::isWhiteSpace(_editString[currentPos - 1])) { if (!space) break; @@ -754,14 +754,14 @@ bool EditableWidget::markWord() while(_caretPos + _selectSize < int(_editString.size())) { - if(_editString[_caretPos + _selectSize] == ' ') + if(BSPF::isWhiteSpace(_editString[_caretPos + _selectSize])) break; _selectSize++; } while(_caretPos > 0) { - if(_editString[_caretPos - 1] == ' ') + if(BSPF::isWhiteSpace(_editString[_caretPos - 1])) break; _caretPos--; _selectSize++; diff --git a/src/gui/ListWidget.cxx b/src/gui/ListWidget.cxx index a8c0c37da..ae2551e8f 100644 --- a/src/gui/ListWidget.cxx +++ b/src/gui/ListWidget.cxx @@ -56,6 +56,17 @@ ListWidget::ListWidget(GuiObject* boss, const GUI::Font& font, _w = w - 1; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void ListWidget::setHeight(int h) +{ + Widget::setHeight(h); + if(_useScrollbar) + _scrollBar->setHeight(h); + + _rows = (h - 2) / _lineHeight; + recalc(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::setSelected(int item) { diff --git a/src/gui/ListWidget.hxx b/src/gui/ListWidget.hxx index 1fba03f01..25ea1906f 100644 --- a/src/gui/ListWidget.hxx +++ b/src/gui/ListWidget.hxx @@ -47,6 +47,7 @@ class ListWidget : public EditableWidget int rows() const { return _rows; } int currentPos() const { return _currentPos; } + void setHeight(int h) override; int getSelected() const { return _selectedItem; } void setSelected(int item); diff --git a/src/libretro/OSystemLIBRETRO.cxx b/src/libretro/OSystemLIBRETRO.cxx index 02844de63..4d1578f69 100644 --- a/src/libretro/OSystemLIBRETRO.cxx +++ b/src/libretro/OSystemLIBRETRO.cxx @@ -26,8 +26,8 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystemLIBRETRO::getBaseDirAndConfig(string& basedir, string& cfgfile, - string& savedir, string& loaddir, - bool useappdir, const string& usedir) + string& homedir, + bool useappdir, const string& usedir) { - loaddir = savedir = cfgfile = basedir = "." + slash; + basedir = cfgfile = homedir = "." + slash; } diff --git a/src/libretro/OSystemLIBRETRO.hxx b/src/libretro/OSystemLIBRETRO.hxx index 60b1fc4e5..0fdadb8af 100644 --- a/src/libretro/OSystemLIBRETRO.hxx +++ b/src/libretro/OSystemLIBRETRO.hxx @@ -41,8 +41,7 @@ class OSystemLIBRETRO : public OSystem @param basedir The base directory for all configuration files @param cfgfile The fully qualified pathname of the config file (including the base directory) - @param savedir The default directory to save various other files - @param loaddir The default directory to load various other files + @param homedir The default directory to store various other files @param useappdir A hint that the base dir should be set to the app directory; not all ports can do this, so they are free to ignore it @@ -51,8 +50,8 @@ class OSystemLIBRETRO : public OSystem they are free to ignore it */ void getBaseDirAndConfig(string& basedir, string& cfgfile, - string& savedir, string& loaddir, - bool useappdir, const string& usedir) override; + string& homedir, + bool useappdir, const string& usedir) override; }; #endif diff --git a/src/macos/OSystemMACOS.cxx b/src/macos/OSystemMACOS.cxx index 9d933da8b..0ba22279e 100644 --- a/src/macos/OSystemMACOS.cxx +++ b/src/macos/OSystemMACOS.cxx @@ -21,8 +21,8 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystemMACOS::getBaseDirAndConfig(string& basedir, string& cfgfile, - string& savedir, string& loaddir, - bool useappdir, const string& usedir) + string& homedir, + bool useappdir, const string& usedir) { basedir = "~/Library/Application Support/Stella/"; @@ -31,14 +31,11 @@ void OSystemMACOS::getBaseDirAndConfig(string& basedir, string& cfgfile, if(useappdir) cout << "ERROR: base dir in app folder not supported" << endl; else if(usedir != "") - { basedir = FilesystemNode(usedir).getPath(); - savedir = loaddir = basedir; - } #endif FilesystemNode desktop("~/Desktop/"); - savedir = loaddir = desktop.isDirectory() ? desktop.getShortPath() : "~/"; + homedir = desktop.isDirectory() ? desktop.getShortPath() : "~/"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/macos/OSystemMACOS.hxx b/src/macos/OSystemMACOS.hxx index 89d6638c1..1bfedb011 100644 --- a/src/macos/OSystemMACOS.hxx +++ b/src/macos/OSystemMACOS.hxx @@ -41,8 +41,7 @@ class OSystemMACOS : public OSystem @param basedir The base directory for all configuration files @param cfgfile The fully qualified pathname of the config file (including the base directory) - @param savedir The default directory to save various other files - @param loaddir The default directory to load various other files + @param homedir The default directory to store various other files @param useappdir A hint that the base dir should be set to the app directory; not all ports can do this, so they are free to ignore it @@ -51,8 +50,8 @@ class OSystemMACOS : public OSystem they are free to ignore it */ void getBaseDirAndConfig(string& basedir, string& cfgfile, - string& savedir, string& loaddir, - bool useappdir, const string& usedir) override; + string& homedir, + bool useappdir, const string& usedir) override; protected: virtual shared_ptr createSettingsRepository() override; diff --git a/src/unix/OSystemUNIX.cxx b/src/unix/OSystemUNIX.cxx index 6b6ec4df3..2156e0975 100644 --- a/src/unix/OSystemUNIX.cxx +++ b/src/unix/OSystemUNIX.cxx @@ -23,23 +23,21 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystemUNIX::getBaseDirAndConfig(string& basedir, string& cfgfile, - string& savedir, string& loaddir, - bool useappdir, const string& usedir) + string& homedir, + bool useappdir, const string& usedir) { // Use XDG_CONFIG_HOME if defined, otherwise use the default string configDir = BSPF::getenv("XDG_CONFIG_HOME"); + if(configDir == EmptyString) configDir = "~/.config"; basedir = configDir + "/stella"; - savedir = loaddir = "~/"; + homedir = "~/"; // Check to see if basedir overrides are active if(useappdir) cout << "ERROR: base dir in app folder not supported" << endl; else if(usedir != "") - { basedir = FilesystemNode(usedir).getPath(); - savedir = loaddir = basedir; - } // (Currently) non-documented alternative for using version-specific // config file diff --git a/src/unix/OSystemUNIX.hxx b/src/unix/OSystemUNIX.hxx index b562a3c3d..e9309787e 100644 --- a/src/unix/OSystemUNIX.hxx +++ b/src/unix/OSystemUNIX.hxx @@ -41,8 +41,7 @@ class OSystemUNIX : public OSystem @param basedir The base directory for all configuration files @param cfgfile The fully qualified pathname of the config file (including the base directory) - @param savedir The default directory to save various other files - @param loaddir The default directory to load various other files + @param homedir The default directory to store various other files @param useappdir A hint that the base dir should be set to the app directory; not all ports can do this, so they are free to ignore it @@ -51,8 +50,8 @@ class OSystemUNIX : public OSystem they are free to ignore it */ void getBaseDirAndConfig(string& basedir, string& cfgfile, - string& savedir, string& loaddir, - bool useappdir, const string& usedir) override; + string& homedir, + bool useappdir, const string& usedir) override; private: // Following constructors and assignment operators not supported diff --git a/src/unix/r77/OSystemR77.cxx b/src/unix/r77/OSystemR77.cxx index dd692b24f..50da2b086 100644 --- a/src/unix/r77/OSystemR77.cxx +++ b/src/unix/r77/OSystemR77.cxx @@ -19,8 +19,8 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystemR77::getBaseDirAndConfig(string& basedir, string& cfgfile, - string& savedir, string& loaddir, bool, const string&) + string& homeDir, bool, const string&) { - basedir = savedir = loaddir = "/mnt/stella"; + basedir = homeDir = "/mnt/stella"; cfgfile = "/mnt/stella/stellarc"; } diff --git a/src/unix/r77/OSystemR77.hxx b/src/unix/r77/OSystemR77.hxx index 58d80d80e..fc7f4efa4 100644 --- a/src/unix/r77/OSystemR77.hxx +++ b/src/unix/r77/OSystemR77.hxx @@ -43,8 +43,7 @@ class OSystemR77 : public OSystem @param basedir The base directory for all configuration files @param cfgfile The fully qualified pathname of the config file (including the base directory) - @param savedir The default directory to save various other files - @param loaddir The default directory to load various other files + @param homedir The default directory to store various other files @param useappdir A hint that the base dir should be set to the app directory; not all ports can do this, so they are free to ignore it @@ -53,8 +52,8 @@ class OSystemR77 : public OSystem they are free to ignore it */ void getBaseDirAndConfig(string& basedir, string& cfgfile, - string& savedir, string& loaddir, - bool useappdir, const string& usedir) override; + string& homedir, + bool useappdir, const string& usedir) override; private: // Following constructors and assignment operators not supported diff --git a/src/windows/OSystemWINDOWS.cxx b/src/windows/OSystemWINDOWS.cxx index d1df4f55c..f7b6787fb 100644 --- a/src/windows/OSystemWINDOWS.cxx +++ b/src/windows/OSystemWINDOWS.cxx @@ -23,11 +23,12 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystemWINDOWS::getBaseDirAndConfig(string& basedir, string& cfgfile, - string& savedir, string& loaddir, - bool useappdir, const string& usedir) + string& homedir, + bool useappdir, const string& usedir) { HomeFinder homefinder; FilesystemNode appdata(homefinder.getAppDataPath()); + if(appdata.isDirectory()) { basedir = appdata.getShortPath(); @@ -35,8 +36,9 @@ void OSystemWINDOWS::getBaseDirAndConfig(string& basedir, string& cfgfile, basedir += '\\'; basedir += "Stella\\"; } - FilesystemNode defaultLoadSaveDir(homefinder.getDesktopPath()); - savedir = loaddir = defaultLoadSaveDir.getShortPath(); + + FilesystemNode defaultHomeDir(homefinder.getDesktopPath()); + homedir = defaultHomeDir.getShortPath(); // Check to see if basedir overrides are active if(useappdir) @@ -44,12 +46,13 @@ void OSystemWINDOWS::getBaseDirAndConfig(string& basedir, string& cfgfile, char filename[MAX_PATH]; GetModuleFileNameA(NULL, filename, sizeof(filename)); FilesystemNode appdir(filename); + appdir = appdir.getParent(); if(appdir.isDirectory()) - savedir = loaddir = basedir = appdir.getPath(); + basedir = appdir.getPath(); } else if(usedir != "") - savedir = loaddir = basedir = FilesystemNode(usedir).getPath(); + basedir = FilesystemNode(usedir).getPath(); cfgfile = basedir + "stella.ini"; } diff --git a/src/windows/OSystemWINDOWS.hxx b/src/windows/OSystemWINDOWS.hxx index 4995f9f51..b938c3719 100644 --- a/src/windows/OSystemWINDOWS.hxx +++ b/src/windows/OSystemWINDOWS.hxx @@ -41,8 +41,7 @@ class OSystemWINDOWS : public OSystem @param basedir The base directory for all configuration files @param cfgfile The fully qualified pathname of the config file (including the base directory) - @param savedir The default directory to save various other files - @param loaddir The default directory to load various other files + @param homedir The default directory to store various other files @param useappdir A hint that the base dir should be set to the app directory; not all ports can do this, so they are free to ignore it @@ -51,8 +50,8 @@ class OSystemWINDOWS : public OSystem they are free to ignore it */ void getBaseDirAndConfig(string& basedir, string& cfgfile, - string& savedir, string& loaddir, - bool useappdir, const string& usedir) override; + string& homedir, + bool useappdir, const string& usedir) override; private: // Following constructors and assignment operators not supported From 717a678a035b399ad2ad22926a52b97e456ec4c6 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 25 Dec 2020 09:38:37 +0100 Subject: [PATCH 8/8] minor doc updates --- docs/index.html | 2 +- src/debugger/DebuggerParser.cxx | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/index.html b/docs/index.html index 5657ce955..aa200a645 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3191,7 +3191,7 @@
    -userdir <dir>
    - Set the path to save user files to. + Set the path to save user files (property exports, debugger saves) to. diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 3c8bdac5b..0d35b5e30 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -681,7 +681,7 @@ string DebuggerParser::saveScriptFile(string file) if(file.find_last_of('.') == string::npos) file += ".script"; - // Use default path if no path is provided + // Use user dir if no path is provided if(file.find_first_of(FilesystemNode::PATH_SEPARATOR) == string::npos) file = debugger.myOSystem.userDir().getPath() + file; @@ -2669,9 +2669,10 @@ std::array DebuggerParser::commands = { { "dump", "Dump data at address [to yy] [1: memory; 2: CPU state; 4: input regs]", "Example:\n" - " dump f000 - dumps 128 bytes @ f000\n" + " dump f000 - dumps 128 bytes from f000\n" " dump f000 f0ff - dumps all bytes from f000 to f0ff\n" - " dump f000 f0ff 7 - dumps all bytes from f000 to f0ff, CPU state and input registers into a file", + " dump f000 f0ff 7 - dumps all bytes from f000 to f0ff,\n" + " CPU state and input registers into a file in user dir", true, false, { Parameters::ARG_WORD, Parameters::ARG_MULTI_BYTE }, @@ -3095,7 +3096,8 @@ std::array DebuggerParser::commands = { { { "save", "Save breaks, watches, traps and functions to file xx", - "Example: save commands.script, save ?", + "Example: save commands.script, save ?\n" + "NOTE: saves to user dir by default", true, false, { Parameters::ARG_FILE, Parameters::ARG_END_ARGS }, @@ -3106,7 +3108,7 @@ std::array DebuggerParser::commands = { { "saveaccess", "Save the access counters to CSV file", "Example: saveaccess, saveaccess ?\n" - "NOTE: saves to default save location without ? parameter", + "NOTE: saves to user dir by default", false, false, { Parameters::ARG_FILE, Parameters::ARG_END_ARGS }, @@ -3127,7 +3129,7 @@ std::array DebuggerParser::commands = { { "savedis", "Save Distella disassembly", "Example: savedis, savedis ?\n" - "NOTE: saves to default save location without ? parameter", + "NOTE: saves to user dir by default", false, false, { Parameters::ARG_FILE, Parameters::ARG_END_ARGS }, @@ -3138,7 +3140,7 @@ std::array DebuggerParser::commands = { { "saverom", "Save (possibly patched) ROM", "Example: saverom, saverom ?\n" - "NOTE: saves to default save location without ? parameter", + "NOTE: saves to user dir by default", false, false, { Parameters::ARG_FILE, Parameters::ARG_END_ARGS }, @@ -3149,7 +3151,7 @@ std::array DebuggerParser::commands = { { "saveses", "Save console session", "Example: saveses, saveses ?\n" - "NOTE: saves to default save location without ? parameter", + "NOTE: saves to user dir by default", false, false, { Parameters::ARG_FILE, Parameters::ARG_END_ARGS },