Added pattern matching textbox to the ROM launcher. This works in

addition to the previously added FilterOptions (that code filtered
by filename extension, while this further filters by an actual pattern).
This is by request of several people in the AtariAge forums).


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1658 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2009-01-24 21:44:49 +00:00
parent dec6efccdd
commit 241afb6715
11 changed files with 105 additions and 18 deletions

View File

@ -35,6 +35,10 @@
* Made the ROM launcher filename filtering be case-insensitive. This fixes
a bug whereby ROMs with uppercase extensions were marked as invalid.
* Added a pattern matching textbox to the ROM launcher, used to
further filter the files shown in the listing. For now, this filters
files only (directories are not filtered, and are always shown).
* The location of EEPROM files used for AtariVox/Savekey emulation can
now be changed with the '-eepromdir' commandline argument as well as
in the UI.

View File

@ -36,7 +36,8 @@ Stephen Anthony at stephena@users.sourceforge.net.
directory named that way. Basically the same as is currently
done for ROMs.
(2) Add popup text widget to dynamically select the entries shown.
(2) Fix aliases not being followed correctly in the OSX port
(although I suspect this isn't just an OSX issue).
* More support for copy and paste.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -2033,6 +2033,16 @@
<p>ROM info viewer in 2x mode, UI sized 1400x900, large launcher font:</p>
<img src="graphics/rominfo_2x_small.png">
<p>The text box in the upper right corner can be used to narrow down the
results in the ROM listing. When this box is empty, all files are shown
(subject to the restrictions from the filtering option, explained below).
Typing characters here where show only those files that match that
pattern. For example, typing 'Activision' will show only files that
contain the word 'Activision' in their name. This is very useful for
quickly finding a group of related ROMs. Note that the search is not
case sensitive, so you don't need to worry about capital or lower-case
letters.</p>
<p>The ROM launcher also contains a context menu, selected by clicking the
right mouse button anywhere in the current window. This context menu
contains the following items:</p>

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: EditableWidget.cxx,v 1.30 2009-01-03 15:44:13 stephena Exp $
// $Id: EditableWidget.cxx,v 1.31 2009-01-24 21:44:49 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -116,22 +116,24 @@ bool EditableWidget::handleKeyDown(int ascii, int keycode, int modifiers)
case 8: // backspace
dirty = killChar(-1);
if(dirty) sendCommand(kEditChangedCmd, ascii, _id);
break;
case 127: // delete
dirty = killChar(+1);
if(dirty) sendCommand(kEditChangedCmd, ascii, _id);
break;
case 256 + 20: // left arrow
if(instance().eventHandler().kbdControl(modifiers))
dirty = specialKeys(keycode);
dirty = specialKeys(ascii, keycode);
else if(_caretPos > 0)
dirty = setCaretPos(_caretPos - 1);
break;
case 256 + 19: // right arrow
if(instance().eventHandler().kbdControl(modifiers))
dirty = specialKeys(keycode);
dirty = specialKeys(ascii, keycode);
else if(_caretPos < (int)_editString.size())
dirty = setCaretPos(_caretPos + 1);
break;
@ -147,7 +149,7 @@ bool EditableWidget::handleKeyDown(int ascii, int keycode, int modifiers)
default:
if (instance().eventHandler().kbdControl(modifiers))
{
dirty = specialKeys(keycode);
dirty = specialKeys(ascii, keycode);
}
else if (tryInsertChar((char)ascii, _caretPos))
{
@ -247,7 +249,7 @@ bool EditableWidget::adjustOffset()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool EditableWidget::specialKeys(int keycode)
bool EditableWidget::specialKeys(int ascii, int keycode)
{
bool handled = true;
@ -259,6 +261,7 @@ bool EditableWidget::specialKeys(int keycode)
case 'c':
copySelectedText();
if(handled) sendCommand(kEditChangedCmd, ascii, _id);
break;
case 'e':
@ -267,22 +270,27 @@ bool EditableWidget::specialKeys(int keycode)
case 'd':
handled = killChar(+1);
if(handled) sendCommand(kEditChangedCmd, ascii, _id);
break;
case 'k':
handled = killLine(+1);
if(handled) sendCommand(kEditChangedCmd, ascii, _id);
break;
case 'u':
handled = killLine(-1);
if(handled) sendCommand(kEditChangedCmd, ascii, _id);
break;
case 'v':
pasteSelectedText();
if(handled) sendCommand(kEditChangedCmd, ascii, _id);
break;
case 'w':
handled = killLastWord();
if(handled) sendCommand(kEditChangedCmd, ascii, _id);
break;
case 256 + 20: // left arrow

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: EditableWidget.hxx,v 1.16 2009-01-01 18:13:38 stephena Exp $
// $Id: EditableWidget.hxx,v 1.17 2009-01-24 21:44:49 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -68,7 +68,7 @@ class EditableWidget : public Widget, public CommandSender
private:
// Line editing
bool specialKeys(int keycode);
bool specialKeys(int ascii, int keycode);
bool killChar(int direction);
bool killLine(int direction);
bool killLastWord();

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: LauncherDialog.cxx,v 1.103 2009-01-24 17:32:29 stephena Exp $
// $Id: LauncherDialog.cxx,v 1.104 2009-01-24 21:44:49 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -27,6 +27,7 @@
#include "ContextMenu.hxx"
#include "DialogContainer.hxx"
#include "Dialog.hxx"
#include "EditTextWidget.hxx"
#include "FSNode.hxx"
#include "GameList.hxx"
#include "MD5.hxx"
@ -63,10 +64,11 @@ LauncherDialog::LauncherDialog(OSystem* osystem, DialogContainer* parent,
{
const GUI::Font& font = instance().launcherFont();
const int fontHeight = font.getFontHeight(),
const int fontWidth = font.getMaxCharWidth(),
fontHeight = font.getFontHeight(),
bwidth = (_w - 2 * 10 - 8 * (4 - 1)) / 4,
bheight = font.getLineHeight() + 4;
int xpos = 0, ypos = 0, lwidth = 0;
int xpos = 0, ypos = 0, lwidth = 0, lwidth2 = 0, fwidth = 0;
WidgetArray wid;
// Show game name
@ -75,16 +77,22 @@ LauncherDialog::LauncherDialog(OSystem* osystem, DialogContainer* parent,
new StaticTextWidget(this, font, xpos, ypos, lwidth, fontHeight,
"Select an item from the list ...", kTextAlignLeft);
lwidth = font.getStringWidth("XXXX items found");
xpos = _w - lwidth - 10;
lwidth2 = font.getStringWidth("XXXX items found");
xpos = _w - lwidth2 - 10;
myRomCount = new StaticTextWidget(this, font, xpos, ypos,
lwidth, fontHeight,
lwidth2, fontHeight,
"", kTextAlignRight);
// Add list with game titles
xpos = 10; ypos += fontHeight + 5;
// Add filter that can narrow the results shown in the listing
// It has to fit between both labels
fwidth = BSPF_min(15 * fontWidth, xpos - 20 - lwidth);
xpos -= fwidth + 5;
myPattern = new EditTextWidget(this, font, xpos, ypos,
fwidth, fontHeight, "");
// Add list with game titles
// Before we add the list, we need to know the size of the RomInfoWidget
xpos = 10; ypos += fontHeight + 5;
int romWidth = 0;
int romSize = instance().settings().getInt("romviewer");
if(romSize > 1 && w >= 1000 && h >= 760)
@ -98,6 +106,7 @@ LauncherDialog::LauncherDialog(OSystem* osystem, DialogContainer* parent,
myList->setNumberingMode(kListNumberingOff);
myList->setEditable(false);
wid.push_back(myList);
wid.push_back(myPattern); // Add after the list for tab order
// Add ROM info area (if enabled)
if(romWidth > 0)
@ -330,6 +339,11 @@ void LauncherDialog::loadDirListing()
continue;
}
// Skip over files that don't match the pattern in the 'pattern' textbox
if(!isDir && myPattern->getEditString() != "" &&
!matchPattern(name, myPattern->getEditString()))
continue;
myGameList->appendGame(name, files[idx].getPath(), "", isDir);
}
@ -389,6 +403,49 @@ void LauncherDialog::setListFilters()
LauncherFilterDialog::parseExts(myRomExts, exts);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool LauncherDialog::matchPattern(const string& s, const string& pattern)
{
// This method is modelled after strcasestr, which we don't use
// because it isn't guaranteed to be available everywhere
// The strcasestr uses the KMP algorithm when the comparisons
// reach a certain point, but since we'll be dealing with relatively
// short strings, I think the overhead of building a KMP table
// each time would be slower than the brute force method used here
const char* haystack = s.c_str();
const char* needle = pattern.c_str();
unsigned char b = tolower((unsigned char) *needle);
needle++;
for (;; haystack++)
{
if (*haystack == '\0') /* No match */
return false;
/* The first character matches */
if (tolower ((unsigned char) *haystack) == b)
{
const char* rhaystack = haystack + 1;
const char* rneedle = needle;
for (;; rhaystack++, rneedle++)
{
if (*rneedle == '\0') /* Found a match */
return true;
if (*rhaystack == '\0') /* No match */
return false;
/* Nothing in this round */
if (tolower ((unsigned char) *rhaystack)
!= tolower ((unsigned char) *rneedle))
break;
}
}
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void LauncherDialog::handleKeyDown(int ascii, int keycode, int modifiers)
{
@ -502,6 +559,12 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd,
handleContextMenu();
break;
case kEditAcceptCmd:
case kEditChangedCmd:
// The updateListing() method knows what to do when the text changes
updateListing();
break;
default:
Dialog::handleCommand(sender, cmd, data, 0);
}

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: LauncherDialog.hxx,v 1.41 2009-01-24 17:32:29 stephena Exp $
// $Id: LauncherDialog.hxx,v 1.42 2009-01-24 21:44:49 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -79,6 +79,7 @@ class LauncherDialog : public Dialog
void loadRomInfo();
void handleContextMenu();
void setListFilters();
bool matchPattern(const string& s, const string& pattern);
private:
ButtonWidget* myStartButton;
@ -90,7 +91,7 @@ class LauncherDialog : public Dialog
StaticTextWidget* myDirLabel;
StaticTextWidget* myDir;
StaticTextWidget* myRomCount;
EditTextWidget* myFilename;
EditTextWidget* myPattern;
GameList* myGameList;
OptionsDialog* myOptions;