Entering an uppercase char (ie, hold Shift) on the first character in

file listings now selects among directories; use lowercase to select among
files (fixes #160).

Refactored relevant code from ListWidget to FileListWidget, where it more
properly belongs.

Updates to docs (new info, typo's, etc).
This commit is contained in:
Stephen Anthony 2019-08-23 22:08:06 -02:30
parent 7ee9573646
commit 2540d0d803
10 changed files with 87 additions and 97 deletions

View File

@ -26,8 +26,8 @@
* Added automatic controller detection. * Added automatic controller detection.
* Controllers can be changed during emulation (no ROM reload required * Controllers can be changed during emulation (no ROM reload required
anymore) anymore).
* Removed superfluous controller option 'PADDLES_IDIR'. * Removed superfluous controller option 'PADDLES_IDIR'.
@ -47,9 +47,9 @@
down the mouse button (Time Machine, debugger step/trace/frame advance, down the mouse button (Time Machine, debugger step/trace/frame advance,
etc.) etc.)
* Added option to configure mouse double click speed * Added option to configure mouse double click speed.
* Added option to configure controller input repeat speed * Added option to configure controller input repeat speed.
* Added 'HiDPI' mode, which scales the UI by 2x when enabled. This is * Added 'HiDPI' mode, which scales the UI by 2x when enabled. This is
meant for 4k and above monitors, but can actually be used at any meant for 4k and above monitors, but can actually be used at any
@ -76,11 +76,15 @@
* Enhanced 'Command' menu to display current state and more commands. * Enhanced 'Command' menu to display current state and more commands.
* Added option to save and load all TimeMachine states at once * Added option to save and load all TimeMachine states at once.
* Added option to change pitch of Pitfall II music * Added option to change pitch of Pitfall II music.
* Fixed bug when starting ROMs via MacOS finder * In file listings, you can now select directories by holding 'Shift' on
the first character entered. Entering characters in lowercase still
selects files, as before.
* Fixed bug when starting ROMs via MacOS finder.
* Added various developer options for oddball TIAs: * Added various developer options for oddball TIAs:
- stuffed player, missiles and ball move - stuffed player, missiles and ball move
@ -89,9 +93,9 @@
* Disabled some developer options for 'Player settings'. * Disabled some developer options for 'Player settings'.
* Improved breakpoints to now consider the banks * Improved breakpoints to now consider the banks.
* Improved debugger's TIA display and zoom windows * Improved debugger's TIA display and zoom windows.
* Improved hotkeys, now many emulation keys work in debugger too. * Improved hotkeys, now many emulation keys work in debugger too.
@ -100,7 +104,7 @@
* Reworked ROM properties database, making it load faster in certain * Reworked ROM properties database, making it load faster in certain
cases. Related to this, completely removed 'Display_Height' stuff. cases. Related to this, completely removed 'Display_Height' stuff.
(TODO: Stella.pro cleanup, doc) (TODO: Stella.pro cleanup, doc).
* Updated internal ROM properties database to ROM-Hunter version 15 * Updated internal ROM properties database to ROM-Hunter version 15
(thanks go to RomHunter for his tireless research in this area). (thanks go to RomHunter for his tireless research in this area).
@ -114,12 +118,6 @@
* Fixed not working 7800 pause key. * Fixed not working 7800 pause key.
* Added support for CDFJ bankswitching type.
* Allow the DPC+ scheme to not enable playfield 'jitter' effect for
certain older DPC+ driver versions; this allows 'Epic Adventure' ROM
to finally work in Stella.
* Enhanced UA bankswitching to support certain Brazilian carts. * Enhanced UA bankswitching to support certain Brazilian carts.
* Auto-detection of bankswitch scheme by file extension now includes * Auto-detection of bankswitch scheme by file extension now includes

View File

@ -576,7 +576,7 @@
These settings are optional, and can be left at the defaults if you won't be using These settings are optional, and can be left at the defaults if you won't be using
snapshots in the ROM launcher.</p> snapshots in the ROM launcher.</p>
<p>you can start emulation by selecting a ROM and pressing 'Enter' or clicking 'Select', <p>You can start emulation by selecting a ROM and pressing 'Enter' or clicking 'Select',
or double-clicking a ROM. Note that some games require you to 'Reset' the console or double-clicking a ROM. Note that some games require you to 'Reset' the console
before you start playing. In this case, you need to hit the virtual reset switch, before you start playing. In this case, you need to hit the virtual reset switch,
which by default is the F2 key. Also, some games may require that you press the which by default is the F2 key. Also, some games may require that you press the
@ -590,6 +590,12 @@
listing can be narrowed down, showing only the ROMs that match the pattern listing can be narrowed down, showing only the ROMs that match the pattern
you enter.</p> you enter.</p>
<p>While the file listing is in focus, you can type some characters, and the listing
will 'jump' to the file that matches what you typed. This is case-insensitive. Hold
down the Shift key on the first character to select directories instead. The delay
between successive keypresses being treated as part of one word is controlled by the
'listdelay' option; see <b>User Interface Settings</b> to change this setting.</p>
<p> <p>
<h3><b><u>Command Menu</u></b></h3> <h3><b><u>Command Menu</u></b></h3>
@ -2313,8 +2319,8 @@
<tr> <tr>
<td><pre>-listdelay &lt;delay&gt;</pre></td> <td><pre>-listdelay &lt;delay&gt;</pre></td>
<td>Set the amount of time to wait between treating successive <td>Set the amount of time to wait between treating successive
keypresses as a single word in list widgets (value can range keypresses as a single word in file listings (value can range
from 300-1000). Use '0' to disable list-skipping completely,</td> from 300-1000). Use '0' to disable list-skipping completely.</td>
</tr> </tr>
<tr> <tr>
@ -2817,7 +2823,7 @@
<tr><td>Theme</td><td>Theme to use for UI elements (see examples)</td><td>-uipalette</td></tr> <tr><td>Theme</td><td>Theme to use for UI elements (see examples)</td><td>-uipalette</td></tr>
<tr><td>Dialogs position</td><td>Position of dialogs with Stella window</td><td>-dialogpos</td></tr> <tr><td>Dialogs position</td><td>Position of dialogs with Stella window</td><td>-dialogpos</td></tr>
<tr><td>HiDPI mode</td><td>Scales the UI by a factor of two when enabled</td><td>-hidpi</td></tr> <tr><td>HiDPI mode</td><td>Scales the UI by a factor of two when enabled</td><td>-hidpi</td></tr>
<tr><td>List input delay</td><td>Maximum delay between keypresses in list-widgets before a search string resets. </td><td>-listdelay</td></tr> <tr><td>List input delay</td><td>Maximum delay between keypresses in filelist-widgets before a search string resets. </td><td>-listdelay</td></tr>
<tr><td>Mouse wheel scroll</td><td>Number of lines a mouse scroll will move in list-widgets</td><td>-mwheel</td></tr> <tr><td>Mouse wheel scroll</td><td>Number of lines a mouse scroll will move in list-widgets</td><td>-mwheel</td></tr>
<tr><td>Double-click speed</td><td>Speed of mouse double-clicks</td><td>-mdouble</td></tr> <tr><td>Double-click speed</td><td>Speed of mouse double-clicks</td><td>-mdouble</td></tr>
<tr><td>Controller repeat delay</td><td>Delay before controller input repeats</td><td>-ctrldelay</td></tr> <tr><td>Controller repeat delay</td><td>Delay before controller input repeats</td><td>-ctrldelay</td></tr>

View File

@ -55,7 +55,7 @@
#include "DialogContainer.hxx" #include "DialogContainer.hxx"
#include "Launcher.hxx" #include "Launcher.hxx"
#include "TimeMachine.hxx" #include "TimeMachine.hxx"
#include "ListWidget.hxx" #include "FileListWidget.hxx"
#include "ScrollBarWidget.hxx" #include "ScrollBarWidget.hxx"
#endif #endif
@ -104,7 +104,7 @@ void EventHandler::initialize()
#ifdef GUI_SUPPORT #ifdef GUI_SUPPORT
// Set quick select delay when typing characters in listwidgets // Set quick select delay when typing characters in listwidgets
ListWidget::setQuickSelectDelay(myOSystem.settings().getInt("listdelay")); FileListWidget::setQuickSelectDelay(myOSystem.settings().getInt("listdelay"));
// Set number of lines a mousewheel will scroll // Set number of lines a mousewheel will scroll
ScrollBarWidget::setWheelLines(myOSystem.settings().getInt("mwheel")); ScrollBarWidget::setWheelLines(myOSystem.settings().getInt("mwheel"));
@ -1446,7 +1446,7 @@ int EventHandler::getActionListIndex(int idx, Event::Group group) const
default: default:
return -1; return -1;
}; }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -23,7 +23,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CheckListWidget::CheckListWidget(GuiObject* boss, const GUI::Font& font, CheckListWidget::CheckListWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h) int x, int y, int w, int h)
: ListWidget(boss, font, x, y, w, h, false) // disable quick select : ListWidget(boss, font, x, y, w, h)
{ {
int ypos = _y + 2; int ypos = _y + 2;

View File

@ -15,8 +15,11 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================ //============================================================================
#include <cctype>
#include "ScrollBarWidget.hxx" #include "ScrollBarWidget.hxx"
#include "FileListWidget.hxx" #include "FileListWidget.hxx"
#include "TimerManager.hxx"
#include "bspf.hxx" #include "bspf.hxx"
@ -25,7 +28,8 @@ FileListWidget::FileListWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h) int x, int y, int w, int h)
: StringListWidget(boss, font, x, y, w, h), : StringListWidget(boss, font, x, y, w, h),
_fsmode(FilesystemNode::ListMode::All), _fsmode(FilesystemNode::ListMode::All),
_selected(0) _selected(0),
_quickSelectTime(0)
{ {
// This widget is special, in that it catches signals and redirects them // This widget is special, in that it catches signals and redirects them
setTarget(this); setTarget(this);
@ -108,6 +112,42 @@ void FileListWidget::reload()
setLocation(_node, selected().getName()); setLocation(_node, selected().getName());
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FileListWidget::handleText(char text)
{
// Quick selection mode: Go to first list item starting with this key
// (or a substring accumulated from the last couple key presses).
// Only works in a useful fashion if the list entries are sorted.
uInt64 time = TimerManager::getTicks() / 1000;
if(_quickSelectTime < time)
{
if(std::isupper(text))
{
// Select directories when the first character is uppercase
_quickSelectStr = " [";
_quickSelectStr.push_back(text);
}
else
_quickSelectStr = text;
}
else
_quickSelectStr += text;
_quickSelectTime = time + _QUICK_SELECT_DELAY;
int selectedItem = 0;
for(const auto& i: _list)
{
if(BSPF::startsWithIgnoreCase(i, _quickSelectStr))
break;
selectedItem++;
}
if(selectedItem > 0)
setSelected(selectedItem);
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FileListWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) void FileListWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
{ {
@ -149,3 +189,6 @@ void FileListWidget::handleCommand(CommandSender* sender, int cmd, int data, int
sendCommand(cmd, data, id); sendCommand(cmd, data, id);
setTarget(this); setTarget(this);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt64 FileListWidget::_QUICK_SELECT_DELAY = 300;

View File

@ -79,6 +79,8 @@ class FileListWidget : public StringListWidget
} }
const FilesystemNode& currentDir() const { return _node; } const FilesystemNode& currentDir() const { return _node; }
static void setQuickSelectDelay(uInt64 time) { _QUICK_SELECT_DELAY = time; }
private: private:
/** Very similar to setDirectory(), but also updates the history */ /** Very similar to setDirectory(), but also updates the history */
void setLocation(const FilesystemNode& node, string select = EmptyString); void setLocation(const FilesystemNode& node, string select = EmptyString);
@ -86,6 +88,7 @@ class FileListWidget : public StringListWidget
/** Descend into currently selected directory */ /** Descend into currently selected directory */
void selectDirectory(); void selectDirectory();
bool handleText(char text) override;
void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
private: private:
@ -97,6 +100,10 @@ class FileListWidget : public StringListWidget
Common::FixedStack<string> _history; Common::FixedStack<string> _history;
uInt32 _selected; uInt32 _selected;
string _quickSelectStr;
uInt64 _quickSelectTime;
static uInt64 _QUICK_SELECT_DELAY;
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported
FileListWidget() = delete; FileListWidget() = delete;

View File

@ -15,31 +15,25 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================ //============================================================================
#include <cctype>
#include <algorithm>
#include "OSystem.hxx" #include "OSystem.hxx"
#include "Widget.hxx" #include "Widget.hxx"
#include "ScrollBarWidget.hxx" #include "ScrollBarWidget.hxx"
#include "Dialog.hxx" #include "Dialog.hxx"
#include "FrameBuffer.hxx" #include "FrameBuffer.hxx"
#include "StellaKeys.hxx" #include "StellaKeys.hxx"
#include "TimerManager.hxx"
#include "EventHandler.hxx" #include "EventHandler.hxx"
#include "ListWidget.hxx" #include "ListWidget.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ListWidget::ListWidget(GuiObject* boss, const GUI::Font& font, ListWidget::ListWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h, bool quickSelect) int x, int y, int w, int h)
: EditableWidget(boss, font, x, y, 16, 16), : EditableWidget(boss, font, x, y, 16, 16),
_rows(0), _rows(0),
_cols(0), _cols(0),
_currentPos(0), _currentPos(0),
_selectedItem(-1), _selectedItem(-1),
_highlightedItem(-1), _highlightedItem(-1),
_editMode(false), _editMode(false)
_quickSelect(quickSelect),
_quickSelectTime(0)
{ {
_flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG | Widget::FLAG_RETAIN_FOCUS; _flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG | Widget::FLAG_RETAIN_FOCUS;
_bgcolor = kWidColor; _bgcolor = kWidColor;
@ -253,53 +247,8 @@ int ListWidget::findItem(int x, int y) const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool ListWidget::handleText(char text) bool ListWidget::handleText(char text)
{ {
bool handled = true; // Class EditableWidget handles all text editing related key presses for us
int oldSelectedItem = _selectedItem; return _editMode ? EditableWidget::handleText(text) : true;
if (!_editMode && _quickSelect)
{
// Quick selection mode: Go to first list item starting with this key
// (or a substring accumulated from the last couple key presses).
// Only works in a useful fashion if the list entries are sorted.
// TODO: Maybe this should be off by default, and instead we add a
// method "enableQuickSelect()" or so ?
uInt64 time = TimerManager::getTicks() / 1000;
if (_quickSelectTime < time)
_quickSelectStr = text;
else
_quickSelectStr += text;
_quickSelectTime = time + _QUICK_SELECT_DELAY;
// FIXME: This is bad slow code (it scans the list linearly each time a
// key is pressed); it could be much faster. Only of importance if we have
// quite big lists to deal with -- so for now we can live with this lazy
// implementation :-)
int newSelectedItem = 0;
for(const auto& i: _list)
{
if(BSPF::startsWithIgnoreCase(i, _quickSelectStr))
{
_selectedItem = newSelectedItem;
break;
}
newSelectedItem++;
}
}
else if (_editMode)
{
// Class EditableWidget handles all text editing related key presses for us
handled = EditableWidget::handleText(text);
}
if (_selectedItem != oldSelectedItem)
{
_scrollBar->draw();
scrollToSelected();
sendCommand(ListWidget::kSelectionChangedCmd, _selectedItem, _id);
}
return handled;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -521,6 +470,3 @@ void ListWidget::abortEditMode()
// Reset to normal data entry // Reset to normal data entry
EditableWidget::abortEditMode(); EditableWidget::abortEditMode();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt64 ListWidget::_QUICK_SELECT_DELAY = 300;

View File

@ -42,7 +42,7 @@ class ListWidget : public EditableWidget
public: public:
ListWidget(GuiObject* boss, const GUI::Font& font, ListWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h, bool quickSelect); int x, int y, int w, int h);
virtual ~ListWidget() = default; virtual ~ListWidget() = default;
int rows() const { return _rows; } int rows() const { return _rows; }
@ -64,8 +64,6 @@ class ListWidget : public EditableWidget
// Account for the extra width of embedded scrollbar // Account for the extra width of embedded scrollbar
int getWidth() const override; int getWidth() const override;
static void setQuickSelectDelay(uInt64 time) { _QUICK_SELECT_DELAY = time; }
protected: protected:
void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleMouseDown(int x, int y, MouseButton b, int clickCount) override;
void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; void handleMouseUp(int x, int y, MouseButton b, int clickCount) override;
@ -106,13 +104,6 @@ class ListWidget : public EditableWidget
ScrollBarWidget* _scrollBar; ScrollBarWidget* _scrollBar;
StringList _list; StringList _list;
string _backupString;
bool _quickSelect;
string _quickSelectStr;
uInt64 _quickSelectTime;
private:
static uInt64 _QUICK_SELECT_DELAY;
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported

View File

@ -25,8 +25,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StringListWidget::StringListWidget(GuiObject* boss, const GUI::Font& font, StringListWidget::StringListWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h, bool hilite) int x, int y, int w, int h, bool hilite)
: ListWidget(boss, font, x, y, w, h, : ListWidget(boss, font, x, y, w, h),
boss->instance().settings().getInt("listdelay") >= 300),
_hilite(hilite) _hilite(hilite)
{ {
_bgcolorlo = kDlgColor; _bgcolorlo = kDlgColor;

View File

@ -21,7 +21,7 @@
#include "OSystem.hxx" #include "OSystem.hxx"
#include "FrameBuffer.hxx" #include "FrameBuffer.hxx"
#include "FBSurface.hxx" #include "FBSurface.hxx"
#include "ListWidget.hxx" #include "FileListWidget.hxx"
#include "PopUpWidget.hxx" #include "PopUpWidget.hxx"
#include "ScrollBarWidget.hxx" #include "ScrollBarWidget.hxx"
#include "EditTextWidget.hxx" #include "EditTextWidget.hxx"
@ -396,7 +396,7 @@ void UIDialog::saveConfig()
// Listwidget quick delay // Listwidget quick delay
settings.setValue("listdelay", myListDelaySlider->getValue()); settings.setValue("listdelay", myListDelaySlider->getValue());
ListWidget::setQuickSelectDelay(myListDelaySlider->getValue()); FileListWidget::setQuickSelectDelay(myListDelaySlider->getValue());
// Mouse wheel lines // Mouse wheel lines
settings.setValue("mwheel", myWheelLinesSlider->getValue()); settings.setValue("mwheel", myWheelLinesSlider->getValue());