Added more complete support for in-GUI navigation with a joystick

for those dialogs that don't emulate the mouse (currently the Launcher
and Command dialogs).  Moving a joystick axis in such dialogs now repeats
the event until the axis is released (similar to key repeat).  Also,
the number of events is based on how long the axis is held.  So the
longer the axis is pressed, the faster events will be generated.

The LauncherDialog now handles its own joystick axis events, which
are described as follows:
 - Axis up/down (on any stick) move up and down through the game list.
 - Axis left/right moves between the 4 buttons on the bottom (play,
   options, reload, quit).
 - The buttons are now highlighted to indicate that they're focusable.
   So the cursor keys can also be used to move between them.

Still TODO is deal with analog joystick axis events.  The analog nature
of these types of joysticks should really be ignored by the GUI.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@935 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2006-01-04 01:24:17 +00:00
parent 2f16788aaa
commit adc6354943
14 changed files with 258 additions and 91 deletions

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: EventHandler.cxx,v 1.138 2005-12-29 21:16:26 stephena Exp $ // $Id: EventHandler.cxx,v 1.139 2006-01-04 01:24:17 stephena Exp $
//============================================================================ //============================================================================
#include <sstream> #include <sstream>
@ -175,6 +175,8 @@ void EventHandler::reset(State state)
setPaddleSpeed(1, myOSystem->settings().getInt("p2speed")); setPaddleSpeed(1, myOSystem->settings().getInt("p2speed"));
setPaddleSpeed(2, myOSystem->settings().getInt("p3speed")); setPaddleSpeed(2, myOSystem->settings().getInt("p3speed"));
setPaddleSpeed(3, myOSystem->settings().getInt("p4speed")); setPaddleSpeed(3, myOSystem->settings().getInt("p4speed"));
myEventStreamer->reset();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: EventStreamer.cxx,v 1.3 2005-12-29 21:16:28 stephena Exp $ // $Id: EventStreamer.cxx,v 1.4 2006-01-04 01:24:17 stephena Exp $
//============================================================================ //============================================================================
#include "bspf.hxx" #include "bspf.hxx"
@ -44,6 +44,16 @@ EventStreamer::~EventStreamer()
myStreamWriter.close(); myStreamWriter.close();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventStreamer::reset()
{
cerr << "EventStreamer::reset()\n";
myEventWriteFlag = false;
myEventReadFlag = false;
myFrameCounter = -1;
myEventPos = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool EventStreamer::startRecording() bool EventStreamer::startRecording()
{ {
@ -57,10 +67,8 @@ bool EventStreamer::startRecording()
return false; return false;
myEventHistory.clear(); myEventHistory.clear();
myEventWriteFlag = true; reset();
myEventReadFlag = false; return myEventWriteFlag = true;
return myEventWriteFlag;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -97,6 +105,7 @@ bool EventStreamer::stopRecording()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool EventStreamer::loadRecording() bool EventStreamer::loadRecording()
{ {
cerr << "EventStreamer::loadRecording()\n";
string eventfile = /*myOSystem->baseDir() + BSPF_PATH_SEPARATOR +*/ "test.inp"; string eventfile = /*myOSystem->baseDir() + BSPF_PATH_SEPARATOR +*/ "test.inp";
if(!myStreamReader.open(eventfile)) if(!myStreamReader.open(eventfile))
return false; return false;
@ -128,10 +137,8 @@ bool EventStreamer::loadRecording()
return false; return false;
} }
myEventWriteFlag = false; reset();
myEventReadFlag = myEventHistory.size() > 0; myEventReadFlag = myEventHistory.size() > 0;
myFrameCounter = -1;
myEventPos = 0;
return true; return true;
} }

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: EventStreamer.hxx,v 1.2 2005-12-29 01:25:07 stephena Exp $ // $Id: EventStreamer.hxx,v 1.3 2006-01-04 01:24:17 stephena Exp $
//============================================================================ //============================================================================
#ifndef EVENTSTREAMER_HXX #ifndef EVENTSTREAMER_HXX
@ -48,7 +48,7 @@ class OSystem;
the correct order at the correct time. the correct order at the correct time.
@author Stephen Anthony @author Stephen Anthony
@version $Id: EventStreamer.hxx,v 1.2 2005-12-29 01:25:07 stephena Exp $ @version $Id: EventStreamer.hxx,v 1.3 2006-01-04 01:24:17 stephena Exp $
*/ */
class EventStreamer class EventStreamer
{ {
@ -99,6 +99,11 @@ class EventStreamer
*/ */
void nextFrame(); void nextFrame();
/**
Reset to base state (not saving or loading an eventstream)
*/
void reset();
private: private:
private: private:

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: CommandDialog.cxx,v 1.5 2005-12-19 02:19:49 stephena Exp $ // $Id: CommandDialog.cxx,v 1.6 2006-01-04 01:24:17 stephena Exp $
// //
// Based on code from ScummVM - Scumm Interpreter // Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project // Copyright (C) 2002-2004 The ScummVM project
@ -26,35 +26,6 @@
#include "CommandDialog.hxx" #include "CommandDialog.hxx"
#include "EventHandler.hxx" #include "EventHandler.hxx"
enum {
kSelectCmd = 'Csel',
kResetCmd = 'Cres',
kColorCmd = 'Ccol',
kBWCmd = 'Cbwt',
kLeftDiffACmd = 'Clda',
kLeftDiffBCmd = 'Cldb',
kRightDiffACmd = 'Crda',
kRightDiffBCmd = 'Crdb',
kSaveStateCmd = 'Csst',
kStateSlotCmd = 'Ccst',
kLoadStateCmd = 'Clst',
kSnapshotCmd = 'Csnp',
kFormatCmd = 'Cfmt',
kPaletteCmd = 'Cpal',
kReloadRomCmd = 'Crom',
kExitCmd = 'Clex'
};
enum {
kUpArrow = 256+17,
kDownArrow = 256+18,
kLeftArrow = 256+20,
kRightArrow = 256+19,
kNumRows = 4,
kNumCols = 4
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CommandDialog::CommandDialog(OSystem* osystem, DialogContainer* parent) CommandDialog::CommandDialog(OSystem* osystem, DialogContainer* parent)
: Dialog(osystem, parent, 0, 0, 16, 16), : Dialog(osystem, parent, 0, 0, 16, 16),
@ -180,7 +151,7 @@ void CommandDialog::handleKeyDown(int ascii, int keycode, int modifiers)
// Only detect the cursor keys, otherwise pass to base class // Only detect the cursor keys, otherwise pass to base class
switch(ascii) switch(ascii)
{ {
case kUpArrow: case kCursorUp:
if (row > 0) if (row > 0)
--row; --row;
else if(col > 0) else if(col > 0)
@ -190,7 +161,7 @@ void CommandDialog::handleKeyDown(int ascii, int keycode, int modifiers)
} }
break; break;
case kDownArrow: case kCursorDown:
if (row < kNumRows - 1) if (row < kNumRows - 1)
++row; ++row;
else if(col < kNumCols - 1) else if(col < kNumCols - 1)
@ -200,7 +171,7 @@ void CommandDialog::handleKeyDown(int ascii, int keycode, int modifiers)
} }
break; break;
case kLeftArrow: case kCursorLeft:
if (col > 0) if (col > 0)
--col; --col;
else if(row > 0) else if(row > 0)
@ -210,7 +181,7 @@ void CommandDialog::handleKeyDown(int ascii, int keycode, int modifiers)
} }
break; break;
case kRightArrow: case kCursorRight:
if (col < kNumCols - 1) if (col < kNumCols - 1)
++col; ++col;
else if(row < kNumRows - 1) else if(row < kNumRows - 1)
@ -245,16 +216,16 @@ void CommandDialog::handleJoyAxis(int stick, int axis, int value)
if(axis % 2 == 0) // x-direction if(axis % 2 == 0) // x-direction
{ {
if(value < 0) if(value < 0)
key = kLeftArrow; key = kCursorLeft;
else if(value > 0) else if(value > 0)
key = kRightArrow; key = kCursorRight;
} }
else // y-direction else // y-direction
{ {
if(value < 0) if(value < 0)
key = kUpArrow; key = kCursorUp;
else if(value > 0) else if(value > 0)
key = kDownArrow; key = kCursorDown;
} }
if(key != -1) if(key != -1)

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: CommandDialog.hxx,v 1.3 2005-12-24 22:09:36 stephena Exp $ // $Id: CommandDialog.hxx,v 1.4 2006-01-04 01:24:17 stephena Exp $
// //
// Based on code from ScummVM - Scumm Interpreter // Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project // Copyright (C) 2002-2004 The ScummVM project
@ -44,6 +44,30 @@ class CommandDialog : public Dialog
private: private:
int mySelectedItem; int mySelectedItem;
enum {
kSelectCmd = 'Csel',
kResetCmd = 'Cres',
kColorCmd = 'Ccol',
kBWCmd = 'Cbwt',
kLeftDiffACmd = 'Clda',
kLeftDiffBCmd = 'Cldb',
kRightDiffACmd = 'Crda',
kRightDiffBCmd = 'Crdb',
kSaveStateCmd = 'Csst',
kStateSlotCmd = 'Ccst',
kLoadStateCmd = 'Clst',
kSnapshotCmd = 'Csnp',
kFormatCmd = 'Cfmt',
kPaletteCmd = 'Cpal',
kReloadRomCmd = 'Crom',
kExitCmd = 'Clex'
};
enum {
kNumRows = 4,
kNumCols = 4
};
}; };
#endif #endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: DialogContainer.cxx,v 1.22 2005-12-24 22:50:53 stephena Exp $ // $Id: DialogContainer.cxx,v 1.23 2006-01-04 01:24:17 stephena Exp $
//============================================================================ //============================================================================
#include "OSystem.hxx" #include "OSystem.hxx"
@ -72,6 +72,31 @@ void DialogContainer::updateTime(uInt32 time)
myClickRepeatTime = myTime + kClickRepeatSustainDelay; myClickRepeatTime = myTime + kClickRepeatSustainDelay;
} }
if(myCurrentAxisDown.stick != -1 && myAxisRepeatTime < myTime)
{
// The longer an axis event is enabled, the faster it should change
// We do this by decreasing the amount of time between consecutive axis events
// After a certain threshold, send 10 events at a time (this is necessary
// since at some point, we'd like to process more eventss than the
// current framerate allows)
myCurrentAxisDown.count++;
int interval = myCurrentAxisDown.count / 40 + 1;
myAxisRepeatTime = myTime + kAxisRepeatSustainDelay / interval;
if(interval > 3)
{
for(int i = 0; i < 10; ++i)
activeDialog->handleJoyAxis(myCurrentAxisDown.stick, myCurrentAxisDown.axis,
myCurrentAxisDown.value);
myAxisRepeatTime = myTime + kAxisRepeatSustainDelay / 3;
}
else
{
activeDialog->handleJoyAxis(myCurrentAxisDown.stick, myCurrentAxisDown.axis,
myCurrentAxisDown.value);
myAxisRepeatTime = myTime + kAxisRepeatSustainDelay / interval;
}
}
// Update joy to mouse events // Update joy to mouse events
handleJoyMouse(time); handleJoyMouse(time);
} }
@ -270,10 +295,6 @@ void DialogContainer::handleJoyAxisEvent(int stick, int axis, int value)
// Send the event to the dialog box on the top of the stack // Send the event to the dialog box on the top of the stack
Dialog* activeDialog = myDialogStack.top(); Dialog* activeDialog = myDialogStack.top();
if(activeDialog->wantsEvents())
activeDialog->handleJoyAxis(stick, axis, value);
else
{
if(value > JOY_DEADZONE) if(value > JOY_DEADZONE)
value -= JOY_DEADZONE; value -= JOY_DEADZONE;
else if(value < -JOY_DEADZONE ) else if(value < -JOY_DEADZONE )
@ -281,6 +302,26 @@ void DialogContainer::handleJoyAxisEvent(int stick, int axis, int value)
else else
value = 0; value = 0;
if(activeDialog->wantsEvents())
{
// Only stop firing events if it's the current key
if(myCurrentAxisDown.stick == stick && value == 0)
{
myCurrentAxisDown.stick = myCurrentAxisDown.axis = -1;
myCurrentAxisDown.count = 0;
}
else
{
// Now account for repeated axis events (press and hold)
myCurrentAxisDown.stick = stick;
myCurrentAxisDown.axis = axis;
myCurrentAxisDown.value = value;
myAxisRepeatTime = myTime + kAxisRepeatInitialDelay;
}
activeDialog->handleJoyAxis(stick, axis, value);
}
else
{
if(axis % 2 == 0) // x-direction if(axis % 2 == 0) // x-direction
{ {
if(value != 0) if(value != 0)
@ -309,6 +350,8 @@ void DialogContainer::handleJoyAxisEvent(int stick, int axis, int value)
ourJoyMouse.y_down_count = 0; ourJoyMouse.y_down_count = 0;
} }
} }
myCurrentAxisDown.stick = myCurrentAxisDown.axis = -1;
myCurrentAxisDown.count = 0;
} }
} }
@ -413,6 +456,9 @@ void DialogContainer::reset()
myLastClick.time = 0; myLastClick.time = 0;
myLastClick.count = 0; myLastClick.count = 0;
myCurrentAxisDown.stick = myCurrentAxisDown.axis = -1;
myCurrentAxisDown.count = 0;
int oldX = ourJoyMouse.x, oldY = ourJoyMouse.y; int oldX = ourJoyMouse.x, oldY = ourJoyMouse.y;
if(ourJoyMouse.x > ourJoyMouse.x_max) if(ourJoyMouse.x > ourJoyMouse.x_max)
ourJoyMouse.x = ourJoyMouse.x_max; ourJoyMouse.x = ourJoyMouse.x_max;

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: DialogContainer.hxx,v 1.12 2005-12-24 22:50:53 stephena Exp $ // $Id: DialogContainer.hxx,v 1.13 2006-01-04 01:24:17 stephena Exp $
//============================================================================ //============================================================================
#ifndef DIALOG_CONTAINER_HXX #ifndef DIALOG_CONTAINER_HXX
@ -37,7 +37,7 @@ typedef FixedStack<Dialog *> DialogStack;
a stack, and handles their events. a stack, and handles their events.
@author Stephen Anthony @author Stephen Anthony
@version $Id: DialogContainer.hxx,v 1.12 2005-12-24 22:50:53 stephena Exp $ @version $Id: DialogContainer.hxx,v 1.13 2006-01-04 01:24:17 stephena Exp $
*/ */
class DialogContainer class DialogContainer
{ {
@ -158,7 +158,9 @@ class DialogContainer
kKeyRepeatInitialDelay = 400, kKeyRepeatInitialDelay = 400,
kKeyRepeatSustainDelay = 50, kKeyRepeatSustainDelay = 50,
kClickRepeatInitialDelay = kKeyRepeatInitialDelay, kClickRepeatInitialDelay = kKeyRepeatInitialDelay,
kClickRepeatSustainDelay = kKeyRepeatSustainDelay kClickRepeatSustainDelay = kKeyRepeatSustainDelay,
kAxisRepeatInitialDelay = kKeyRepeatInitialDelay,
kAxisRepeatSustainDelay = kKeyRepeatSustainDelay
}; };
// Indicates the most current time (in milliseconds) as set by updateTime() // Indicates the most current time (in milliseconds) as set by updateTime()
@ -183,6 +185,15 @@ class DialogContainer
} myCurrentMouseDown; } myCurrentMouseDown;
uInt32 myClickRepeatTime; uInt32 myClickRepeatTime;
// For continuous events (joyaxisDown)
struct {
int stick;
int axis;
int value;
int count;
} myCurrentAxisDown;
uInt32 myAxisRepeatTime;
// Position and time of last mouse click (used to detect double clicks) // Position and time of last mouse click (used to detect double clicks)
struct { struct {
int x, y; // Position of mouse when the click occured int x, y; // Position of mouse when the click occured

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: GuiObject.hxx,v 1.16 2005-12-09 01:16:13 stephena Exp $ // $Id: GuiObject.hxx,v 1.17 2006-01-04 01:24:17 stephena Exp $
// //
// Based on code from ScummVM - Scumm Interpreter // Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project // Copyright (C) 2002-2004 The ScummVM project
@ -32,11 +32,22 @@ class Widget;
typedef Common::Array<Widget*> WidgetArray; typedef Common::Array<Widget*> WidgetArray;
enum {
kCursorUp = 256+17,
kCursorDown = 256+18,
kCursorRight = 256+19,
kCursorLeft = 256+20,
kCursorHome = 256+22,
kCursorEnd = 256+23,
kCursorPgUp = 256+24,
kCursorPgDn = 256+25
};
/** /**
This is the base class for all GUI objects/widgets. This is the base class for all GUI objects/widgets.
@author Stephen Anthony @author Stephen Anthony
@version $Id: GuiObject.hxx,v 1.16 2005-12-09 01:16:13 stephena Exp $ @version $Id: GuiObject.hxx,v 1.17 2006-01-04 01:24:17 stephena Exp $
*/ */
class GuiObject : public CommandReceiver class GuiObject : public CommandReceiver
{ {

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: LauncherDialog.cxx,v 1.34 2005-12-18 18:37:03 stephena Exp $ // $Id: LauncherDialog.cxx,v 1.35 2006-01-04 01:24:17 stephena Exp $
// //
// Based on code from ScummVM - Scumm Interpreter // Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project // Copyright (C) 2002-2004 The ScummVM project
@ -53,10 +53,12 @@ LauncherDialog::LauncherDialog(OSystem* osystem, DialogContainer* parent,
myQuitButton(NULL), myQuitButton(NULL),
myList(NULL), myList(NULL),
myGameList(NULL), myGameList(NULL),
myProgressBar(NULL) myProgressBar(NULL),
mySelectedItem(0)
{ {
const GUI::Font& font = instance()->font(); const GUI::Font& font = instance()->font();
const int fontHeight = font.getFontHeight(); const int fontHeight = font.getFontHeight();
WidgetArray wid;
// Show game name // Show game name
new StaticTextWidget(this, 10, 8, 200, fontHeight, new StaticTextWidget(this, 10, 8, 200, fontHeight,
@ -74,31 +76,49 @@ LauncherDialog::LauncherDialog(OSystem* osystem, DialogContainer* parent,
#ifndef MAC_OSX #ifndef MAC_OSX
myStartButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Play", kStartCmd, 'S'); myStartButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Play", kStartCmd, 'S');
myStartButton->setEditable(true);
wid.push_back(myStartButton);
xpos += space + width; xpos += space + width;
myOptionsButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Options", kOptionsCmd, 'O'); myOptionsButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Options", kOptionsCmd, 'O');
myOptionsButton->setEditable(true);
wid.push_back(myOptionsButton);
xpos += space + width; xpos += space + width;
myReloadButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Reload", kReloadCmd, 'R'); myReloadButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Reload", kReloadCmd, 'R');
myReloadButton->setEditable(true);
wid.push_back(myReloadButton);
xpos += space + width; xpos += space + width;
myQuitButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Quit", kQuitCmd, 'Q'); myQuitButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Quit", kQuitCmd, 'Q');
myQuitButton->setEditable(true);
wid.push_back(myQuitButton);
xpos += space + width; xpos += space + width;
#else #else
myQuitButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Quit", kQuitCmd, 'Q'); myQuitButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Quit", kQuitCmd, 'Q');
myQuitButton->setEditable(true);
wid.push_back(myQuitButton);
xpos += space + width; xpos += space + width;
myOptionsButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Options", kOptionsCmd, 'O'); myOptionsButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Options", kOptionsCmd, 'O');
myOptionsButton->setEditable(true);
wid.push_back(myOptionsButton);
xpos += space + width; xpos += space + width;
myReloadButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Reload", kReloadCmd, 'R'); myReloadButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Reload", kReloadCmd, 'R');
myReloadButton->setEditable(true);
wid.push_back(myReloadButton);
xpos += space + width; xpos += space + width;
myStartButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Start", kStartCmd, 'Q'); myStartButton = new ButtonWidget(this, xpos, _h - 24, width, 16, "Start", kStartCmd, 'Q');
myStartButton->setEditable(true);
wid.push_back(myStartButton);
xpos += space + width; xpos += space + width;
#endif #endif
// Add list with game titles // Add list with game titles
// The list isn't added to focus objects, but is instead made 'sticky'
// This means it will act as if it were focused (wrt how it's drawn), but
// won't actually be able to lose focus
myList = new StringListWidget(this, instance()->font(), myList = new StringListWidget(this, instance()->font(),
10, 24, _w - 20, _h - 24 - 26 - 10 - 10); 10, 24, _w - 20, _h - 24 - 26 - 10 - 10);
myList->setNumberingMode(kListNumberingOff); myList->setNumberingMode(kListNumberingOff);
myList->setEditable(false); myList->setEditable(false);
myList->setFlags(WIDGET_NODRAW_FOCUS); myList->setFlags(WIDGET_STICKY_FOCUS);
addFocusWidget(myList);
// Add note textwidget to show any notes for the currently selected ROM // Add note textwidget to show any notes for the currently selected ROM
new StaticTextWidget(this, 20, _h - 43, 30, fontHeight, "Note:", kTextAlignLeft); new StaticTextWidget(this, 20, _h - 43, 30, fontHeight, "Note:", kTextAlignLeft);
@ -113,6 +133,8 @@ LauncherDialog::LauncherDialog(OSystem* osystem, DialogContainer* parent,
// Create a game list, which contains all the information about a ROM that // Create a game list, which contains all the information about a ROM that
// the launcher needs // the launcher needs
myGameList = new GameList(); myGameList = new GameList();
addToFocusList(wid);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -336,6 +358,62 @@ string LauncherDialog::MD5FromFile(const string& path)
return md5; return md5;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void LauncherDialog::handleKeyDown(int ascii, int keycode, int modifiers)
{
// Only detect the cursor keys, otherwise pass to base class
switch(ascii)
{
case kCursorLeft:
mySelectedItem--;
if(mySelectedItem < 0) mySelectedItem = 3;
Dialog::setFocus(getFocusList()[mySelectedItem]);
break;
case kCursorRight:
mySelectedItem++;
if(mySelectedItem > 3) mySelectedItem = 0;
Dialog::setFocus(getFocusList()[mySelectedItem]);
break;
case ' ': // Used to activate currently focused button
Dialog::handleKeyDown(ascii, keycode, modifiers);
break;
default:
if(!myList->handleKeyDown(ascii, keycode, modifiers))
Dialog::handleKeyDown(ascii, keycode, modifiers);
break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void LauncherDialog::handleJoyAxis(int stick, int axis, int value)
{
// We make the (hopefully) valid assumption that all joysticks
// treat axis the same way. Eventually, we may need to remap
// these actions of this assumption is invalid.
// TODO - make this work better with analog axes ...
int key = -1;
if(axis % 2 == 0) // x-direction
{
if(value < 0)
key = kCursorLeft;
else if(value > 0)
key = kCursorRight;
}
else // y-direction
{
if(value < 0)
key = kCursorUp;
else if(value > 0)
key = kCursorDown;
}
if(key != -1)
handleKeyDown(key, 0, 0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void LauncherDialog::handleCommand(CommandSender* sender, int cmd, void LauncherDialog::handleCommand(CommandSender* sender, int cmd,
int data, int id) int data, int id)

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: LauncherDialog.hxx,v 1.13 2005-08-22 18:17:10 stephena Exp $ // $Id: LauncherDialog.hxx,v 1.14 2006-01-04 01:24:17 stephena Exp $
// //
// Based on code from ScummVM - Scumm Interpreter // Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project // Copyright (C) 2002-2004 The ScummVM project
@ -36,10 +36,6 @@ class OSystem;
#include "bspf.hxx" #include "bspf.hxx"
enum { enum {
kStartCmd = 'STRT',
kOptionsCmd = 'OPTI',
kReloadCmd = 'RELO',
kQuitCmd = 'QUIT',
kChooseRomDirCmd = 'roms', // rom select kChooseRomDirCmd = 'roms', // rom select
kChooseSnapDirCmd = 'snps', // snap select kChooseSnapDirCmd = 'snps', // snap select
kRomDirChosenCmd = 'romc', // rom chosen kRomDirChosenCmd = 'romc', // rom chosen
@ -53,12 +49,16 @@ class LauncherDialog : public Dialog
int x, int y, int w, int h); int x, int y, int w, int h);
~LauncherDialog(); ~LauncherDialog();
protected:
virtual void handleKeyDown(int ascii, int keycode, int modifiers);
virtual void handleJoyAxis(int stick, int axis, int value);
virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id);
protected:
void updateListing(bool fullReload = false); void updateListing(bool fullReload = false);
void loadConfig(); void loadConfig();
virtual bool wantsEvents() { return true; }
protected: protected:
ButtonWidget* myStartButton; ButtonWidget* myStartButton;
ButtonWidget* myOptionsButton; ButtonWidget* myOptionsButton;
@ -79,6 +79,16 @@ class LauncherDialog : public Dialog
void loadListFromCache(); void loadListFromCache();
void createListCache(); void createListCache();
string MD5FromFile(const string& path); string MD5FromFile(const string& path);
private:
int mySelectedItem;
enum {
kStartCmd = 'STRT',
kOptionsCmd = 'OPTI',
kReloadCmd = 'RELO',
kQuitCmd = 'QUIT'
};
}; };
#endif #endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: ListWidget.cxx,v 1.37 2005-12-21 19:31:18 stephena Exp $ // $Id: ListWidget.cxx,v 1.38 2006-01-04 01:24:17 stephena Exp $
// //
// Based on code from ScummVM - Scumm Interpreter // Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project // Copyright (C) 2002-2004 The ScummVM project
@ -287,33 +287,33 @@ bool ListWidget::handleKeyDown(int ascii, int keycode, int modifiers)
} }
break; break;
case 256+17: // up arrow case kCursorUp:
if (_selectedItem > 0) if (_selectedItem > 0)
_selectedItem--; _selectedItem--;
break; break;
case 256+18: // down arrow case kCursorDown:
if (_selectedItem < (int)_list.size() - 1) if (_selectedItem < (int)_list.size() - 1)
_selectedItem++; _selectedItem++;
break; break;
case 256+24: // pageup case kCursorPgUp:
_selectedItem -= _rows - 1; _selectedItem -= _rows - 1;
if (_selectedItem < 0) if (_selectedItem < 0)
_selectedItem = 0; _selectedItem = 0;
break; break;
case 256+25: // pagedown case kCursorPgDn:
_selectedItem += _rows - 1; _selectedItem += _rows - 1;
if (_selectedItem >= (int)_list.size() ) if (_selectedItem >= (int)_list.size() )
_selectedItem = _list.size() - 1; _selectedItem = _list.size() - 1;
break; break;
case 256+22: // home case kCursorHome:
_selectedItem = 0; _selectedItem = 0;
break; break;
case 256+23: // end case kCursorEnd:
_selectedItem = _list.size() - 1; _selectedItem = _list.size() - 1;
break; break;

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: ListWidget.hxx,v 1.14 2005-09-30 18:17:29 stephena Exp $ // $Id: ListWidget.hxx,v 1.15 2006-01-04 01:24:17 stephena Exp $
// //
// Based on code from ScummVM - Scumm Interpreter // Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project // Copyright (C) 2002-2004 The ScummVM project
@ -70,7 +70,7 @@ class ListWidget : public EditableWidget
virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id);
virtual GUI::Rect getRect() const; virtual GUI::Rect getRect() const;
virtual bool wantsFocus() { return true; } virtual bool wantsFocus() { return !isSticky(); }
void startEditMode(); void startEditMode();
void endEditMode(); void endEditMode();

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: StringListWidget.cxx,v 1.2 2005-08-23 18:32:51 stephena Exp $ // $Id: StringListWidget.cxx,v 1.3 2006-01-04 01:24:17 stephena Exp $
// //
// Based on code from ScummVM - Scumm Interpreter // Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project // Copyright (C) 2002-2004 The ScummVM project
@ -67,7 +67,7 @@ void StringListWidget::drawWidget(bool hilite)
// Draw the selected item inverted, on a highlighted background. // Draw the selected item inverted, on a highlighted background.
if (_selectedItem == pos) if (_selectedItem == pos)
{ {
if (_hasFocus && !_editMode) if ((_hasFocus && !_editMode) || isSticky())
fb.fillRect(_x + 1, _y + 1 + kLineHeight * i, _w - 1, kLineHeight, kTextColorHi); fb.fillRect(_x + 1, _y + 1 + kLineHeight * i, _w - 1, kLineHeight, kTextColorHi);
else else
fb.frameRect(_x + 1, _y + 1 + kLineHeight * i, _w - 1, kLineHeight, kTextColorHi); fb.frameRect(_x + 1, _y + 1 + kLineHeight * i, _w - 1, kLineHeight, kTextColorHi);

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: Widget.hxx,v 1.43 2005-12-24 22:09:36 stephena Exp $ // $Id: Widget.hxx,v 1.44 2006-01-04 01:24:17 stephena Exp $
// //
// Based on code from ScummVM - Scumm Interpreter // Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project // Copyright (C) 2002-2004 The ScummVM project
@ -44,8 +44,9 @@ enum {
WIDGET_TRACK_MOUSE = 1 << 6, WIDGET_TRACK_MOUSE = 1 << 6,
WIDGET_RETAIN_FOCUS = 1 << 7, WIDGET_RETAIN_FOCUS = 1 << 7,
WIDGET_NODRAW_FOCUS = 1 << 8, WIDGET_NODRAW_FOCUS = 1 << 8,
WIDGET_WANTS_TAB = 1 << 9, WIDGET_STICKY_FOCUS = 1 << 9,
WIDGET_WANTS_EVENTS = 1 << 10 WIDGET_WANTS_TAB = 1 << 10,
WIDGET_WANTS_EVENTS = 1 << 11
}; };
enum { enum {
@ -73,7 +74,7 @@ enum {
This is the base class for all widgets. This is the base class for all widgets.
@author Stephen Anthony @author Stephen Anthony
@version $Id: Widget.hxx,v 1.43 2005-12-24 22:09:36 stephena Exp $ @version $Id: Widget.hxx,v 1.44 2006-01-04 01:24:17 stephena Exp $
*/ */
class Widget : public GuiObject class Widget : public GuiObject
{ {
@ -115,6 +116,7 @@ class Widget : public GuiObject
bool isEnabled() const { return _flags & WIDGET_ENABLED; } bool isEnabled() const { return _flags & WIDGET_ENABLED; }
bool isVisible() const { return !(_flags & WIDGET_INVISIBLE); } bool isVisible() const { return !(_flags & WIDGET_INVISIBLE); }
bool isSticky() const { return _flags & WIDGET_STICKY_FOCUS; }
bool wantsEvents() const { return _flags & WIDGET_WANTS_EVENTS; } bool wantsEvents() const { return _flags & WIDGET_WANTS_EVENTS; }
void setID(int id) { _id = id; } void setID(int id) { _id = id; }