From 4ee8ee8cd72648f6db0a1ae56fd4a6f529e8cc9d Mon Sep 17 00:00:00 2001 From: stephena Date: Fri, 10 Jun 2005 17:46:07 +0000 Subject: [PATCH] Made the Debugger dialog use a TabWidget again, instead of it being another Dialog. This was necessary since it seems Dialogs can't contain other dialogs in the GUI core. Added keyboard navigation to the TabWidget class. For now, it's only enabled for the Debugger. Ctrl-Tab/Shift-Ctrl-Tab switches to the next/previous tab (respectively), and Tab/Shift-Tab switches to the next/previous widget in the current tab. There's still a bit of work to do, but the infrastructure is there. That's it, I'm taking the night off, because this deceptively simple concept has taken about a day to implement ... git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@479 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba --- stella/src/build/makefile | 8 +- stella/src/emucore/OSystem.cxx | 5 +- stella/src/gui/DebuggerDialog.cxx | 193 +++++++---------- stella/src/gui/DebuggerDialog.hxx | 21 +- stella/src/gui/Dialog.cxx | 10 +- stella/src/gui/Dialog.hxx | 5 +- stella/src/gui/GuiObject.hxx | 7 +- stella/src/gui/GuiUtils.hxx | 17 +- stella/src/gui/LauncherDialog.cxx | 3 +- stella/src/gui/ListWidget.cxx | 9 +- .../{PromptDialog.cxx => PromptWidget.cxx} | 120 +++++------ .../{PromptDialog.hxx => PromptWidget.hxx} | 28 +-- stella/src/gui/ScrollBarWidget.cxx | 23 +-- stella/src/gui/ScrollBarWidget.hxx | 3 +- stella/src/gui/TabWidget.cxx | 123 ++++++++++- stella/src/gui/TabWidget.hxx | 9 +- stella/src/gui/Widget.cxx | 194 +++++++++++++++++- stella/src/gui/Widget.hxx | 28 ++- 18 files changed, 519 insertions(+), 287 deletions(-) rename stella/src/gui/{PromptDialog.cxx => PromptWidget.cxx} (86%) rename stella/src/gui/{PromptDialog.hxx => PromptWidget.hxx} (80%) diff --git a/stella/src/build/makefile b/stella/src/build/makefile index bf0090300..668f688aa 100644 --- a/stella/src/build/makefile +++ b/stella/src/build/makefile @@ -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: makefile,v 1.89 2005-06-09 04:31:44 urchlay Exp $ +## $Id: makefile,v 1.90 2005-06-10 17:46:05 stephena Exp $ ##============================================================================ ##============================================================================ @@ -160,7 +160,7 @@ GUI_OBJS = Font.o Menu.o Launcher.o Debugger.o \ EventMappingDialog.o GameInfoDialog.o HelpDialog.o AboutDialog.o \ LauncherDialog.o LauncherOptionsDialog.o BrowserDialog.o GameList.o \ ProgressDialog.o \ - DebuggerDialog.o PromptDialog.o + DebuggerDialog.o PromptWidget.o CORE_OBJS = Booster.o Cart.o Cart2K.o Cart3F.o Cart4K.o CartAR.o CartDPC.o \ CartE0.o CartE7.o CartF4.o CartF4SC.o CartF6.o CartF6SC.o \ @@ -453,8 +453,8 @@ ProgressDialog.o: $(GUI)/ProgressDialog.cxx $(GUI)/ProgressDialog.hxx DebuggerDialog.o: $(GUI)/DebuggerDialog.cxx $(GUI)/DebuggerDialog.hxx $(CXX) -c $(FLAGS) $(OPTIONS) $(LDFLAGS) $(GUI)/DebuggerDialog.cxx -PromptDialog.o: $(GUI)/PromptDialog.cxx $(GUI)/PromptDialog.hxx - $(CXX) -c $(FLAGS) $(OPTIONS) $(LDFLAGS) $(GUI)/PromptDialog.cxx +PromptWidget.o: $(GUI)/PromptWidget.cxx $(GUI)/PromptWidget.hxx + $(CXX) -c $(FLAGS) $(OPTIONS) $(LDFLAGS) $(GUI)/PromptWidget.cxx DebuggerParser.o: $(COMMON)/DebuggerParser.cxx $(COMMON)/DebuggerParser.hxx $(CXX) -c $(FLAGS) $(OPTIONS) $(LDFLAGS) $(COMMON)/DebuggerParser.cxx diff --git a/stella/src/emucore/OSystem.cxx b/stella/src/emucore/OSystem.cxx index 5221b657a..b2dcda4fc 100644 --- a/stella/src/emucore/OSystem.cxx +++ b/stella/src/emucore/OSystem.cxx @@ -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: OSystem.cxx,v 1.23 2005-06-08 18:45:08 stephena Exp $ +// $Id: OSystem.cxx,v 1.24 2005-06-10 17:46:06 stephena Exp $ //============================================================================ #include @@ -88,6 +88,9 @@ OSystem::OSystem() #ifdef DEVELOPER_SUPPORT myFeatures += "Debugger"; #endif + + // When we first start Stella, no GUI widget is active + GuiObject::resetActiveWidget(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/stella/src/gui/DebuggerDialog.cxx b/stella/src/gui/DebuggerDialog.cxx index 6bd9371db..1f05f6e67 100644 --- a/stella/src/gui/DebuggerDialog.cxx +++ b/stella/src/gui/DebuggerDialog.cxx @@ -13,149 +13,110 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: DebuggerDialog.cxx,v 1.6 2005-06-09 20:09:22 stephena Exp $ +// $Id: DebuggerDialog.cxx,v 1.7 2005-06-10 17:46:06 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ -#include "DialogContainer.hxx" -#include "PromptDialog.hxx" +#include "TabWidget.hxx" +#include "ListWidget.hxx" +#include "PromptWidget.hxx" #include "DebuggerDialog.hxx" -enum { - kPromptCmd = 'PRMT', - kCpuCmd = 'CPU ', - kRamCmd = 'RAM ', - kRomCmd = 'ROM ', - kTiaCmd = 'TIA ', - kCodeCmd = 'CODE' -}; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DebuggerDialog::DebuggerDialog(OSystem* osystem, DialogContainer* parent, int x, int y, int w, int h) : Dialog(osystem, parent, x, y, w, h), - myPromptDialog(NULL), - myCpuDialog(NULL), - myRamDialog(NULL), - myRomDialog(NULL), - myTiaDialog(NULL), - myCodeDialog(NULL) + myTab(NULL) { - const int border = 5; - const int space = 5; - const int width = 40; - int xpos = border; + const int vBorder = 4; + int yoffset; - // Add a row of buttons for the various debugger operations - new ButtonWidget(this, xpos, border, width, 16, "Prompt", kPromptCmd, 0); - xpos += space + width; - new ButtonWidget(this, xpos, border, width, 16, "CPU", kCpuCmd, 0); - xpos += space + width; - new ButtonWidget(this, xpos, border, width, 16, "RAM", kRamCmd, 0); - xpos += space + width; - new ButtonWidget(this, xpos, border, width, 16, "ROM", kRomCmd, 0); - xpos += space + width; - new ButtonWidget(this, xpos, border, width, 16, "TIA", kTiaCmd, 0); - xpos += space + width; - new ButtonWidget(this, xpos, border, width, 16, "Code", kCodeCmd, 0); - xpos += space + width; + // The tab widget + myTab = new TabWidget(this, 0, vBorder, _w, _h - vBorder - 1); - const int xoff = border; - const int yoff = border + 16 + 2; + // 1) The Prompt/console tab + myTab->addTab("Prompt"); + yoffset = vBorder; - // Create the debugger dialog boxes - myPromptDialog = new PromptDialog(osystem, parent, x + xoff, y + yoff, - w - xoff - 2, h - yoff - 3); + PromptWidget* prompt = new PromptWidget(myTab, 2, 2, + _w - vBorder, _h - 25); + myTab->setActiveWidget(0, prompt); + + // 2) The CPU tab + myTab->addTab("CPU"); + yoffset = vBorder; + +///////////////////// FIXME - just testing, will be removed + ListWidget* myList = new ListWidget(myTab, 10, 24, 100, _h - 24 - 26 - 10 - 10); + myList->setEditable(false); + myList->setNumberingMode(kListNumberingOff); + + StringList l; + for (int i = 0; i < 10; ++i) + l.push_back("TESTING!!!"); + myList->setList(l); + + ListWidget* myList2 = new ListWidget(myTab, 150, 24, 100, _h - 24 - 26 - 10 - 10); + myList2->setEditable(false); + myList2->setNumberingMode(kListNumberingOff); + + StringList l2; + for (int i = 0; i < 10; ++i) + l2.push_back("TESTING AGAIN!!!"); + myList2->setList(l2); + + ListWidget* myList3 = new ListWidget(myTab, 300, 24, 100, _h - 24 - 26 - 10 - 10); + myList3->setEditable(false); + myList3->setNumberingMode(kListNumberingOff); + + StringList l3; + for (int i = 0; i < 10; ++i) + l3.push_back("CPU_TESTING!!!"); + myList3->setList(l3); + + myTab->setActiveWidget(1, myList); +///////////////////////////// + + // 3) The RAM tab + myTab->addTab("RAM"); + yoffset = vBorder; + + + // 4) The ROM tab + myTab->addTab("ROM"); + yoffset = vBorder; + + + // 5) The TIA tab + myTab->addTab("TIA"); + yoffset = vBorder; + + + // 6) The RAM tab + myTab->addTab("Code"); + yoffset = vBorder; + + + + + // Set active tab to prompt + myTab->setActiveTab(0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DebuggerDialog::~DebuggerDialog() { - delete myPromptDialog; -/* - delete myCpuDialog; - delete myRamDialog; - delete myRomDialog; - delete myTiaDialog; - delete myCodeDialog; -*/ -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void DebuggerDialog::addButtons(GuiObject* boss) -{ - // This is a terrible hack, but it does seem to work ... - const int border = 5; - const int space = 5; - const int width = 40; - int xpos = border; - - // Add a row of buttons for the various debugger operations - new ButtonWidget(boss, xpos, border, width, 16, "Prompt", kPromptCmd, 0); - xpos += space + width; - new ButtonWidget(boss, xpos, border, width, 16, "CPU", kCpuCmd, 0); - xpos += space + width; - new ButtonWidget(boss, xpos, border, width, 16, "RAM", kRamCmd, 0); - xpos += space + width; - new ButtonWidget(boss, xpos, border, width, 16, "ROM", kRomCmd, 0); - xpos += space + width; - new ButtonWidget(boss, xpos, border, width, 16, "TIA", kTiaCmd, 0); - xpos += space + width; - new ButtonWidget(boss, xpos, border, width, 16, "Code", kCodeCmd, 0); - xpos += space + width; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::loadConfig() { - // Auto-select the command prompt - parent()->addDialog(myPromptDialog); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void DebuggerDialog::handleCommand(CommandSender* sender, int cmd, int data) +void DebuggerDialog::handleKeyDown(int ascii, int keycode, int modifiers) { - switch (cmd) - { - case kPromptCmd: - parent()->reStack(); - parent()->addDialog(myPromptDialog); - break; - - case kCpuCmd: - parent()->reStack(); -// parent()->addDialog(myCpuDialog); - cerr << "kCpuCmd\n"; - break; - - case kRamCmd: - parent()->reStack(); -// parent()->addDialog(myRamDialog); - cerr << "kRamCmd\n"; - break; - - case kRomCmd: - parent()->reStack(); -// parent()->addDialog(myRomDialog); - cerr << "kRomCmd\n"; - break; - - case kTiaCmd: - parent()->reStack(); -// parent()->addDialog(myTiaDialog); - cerr << "kTiaCmd\n"; - break; - - case kCodeCmd: - parent()->reStack(); -// parent()->addDialog(myCodeDialog); - cerr << "kCodeCmd\n"; - break; - - default: - Dialog::handleCommand(sender, cmd, data); - break; - } + myTab->handleKeyDown(ascii, keycode, modifiers); } diff --git a/stella/src/gui/DebuggerDialog.hxx b/stella/src/gui/DebuggerDialog.hxx index 3c856d3bb..71d18aa3e 100644 --- a/stella/src/gui/DebuggerDialog.hxx +++ b/stella/src/gui/DebuggerDialog.hxx @@ -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: DebuggerDialog.hxx,v 1.4 2005-06-09 19:04:59 stephena Exp $ +// $Id: DebuggerDialog.hxx,v 1.5 2005-06-10 17:46:06 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -24,12 +24,7 @@ class OSystem; class DialogContainer; -class PromptDialog; -class CpuDialog; -class RamDialog; -class RomDialog; -class TiaDialog; -class CodeDialog; +class TabWidget; #include "Dialog.hxx" @@ -41,18 +36,10 @@ class DebuggerDialog : public Dialog ~DebuggerDialog(); virtual void loadConfig(); - virtual void handleCommand(CommandSender* sender, int cmd, int data); - - void addButtons(GuiObject* boss); + virtual void handleKeyDown(int ascii, int keycode, int modifiers); protected: - // The debugger dialogs - PromptDialog* myPromptDialog; - CpuDialog* myCpuDialog; - RamDialog* myRamDialog; - RomDialog* myRomDialog; - TiaDialog* myTiaDialog; - CodeDialog* myCodeDialog; + TabWidget* myTab; }; #endif diff --git a/stella/src/gui/Dialog.cxx b/stella/src/gui/Dialog.cxx index 338ec0554..806b93555 100644 --- a/stella/src/gui/Dialog.cxx +++ b/stella/src/gui/Dialog.cxx @@ -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: Dialog.cxx,v 1.18 2005-05-26 18:56:58 stephena Exp $ +// $Id: Dialog.cxx,v 1.19 2005-06-10 17:46:06 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -280,14 +280,6 @@ void Dialog::handleJoyUp(int stick, int button) _focusedWidget->handleJoyUp(stick, button); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Dialog::handleTickle() -{ - // Focused widget receives tickle notifications - if(_focusedWidget && _focusedWidget->getFlags() & WIDGET_WANT_TICKLE) - _focusedWidget->handleTickle(); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleCommand(CommandSender* sender, int cmd, int data) { diff --git a/stella/src/gui/Dialog.hxx b/stella/src/gui/Dialog.hxx index 34ea28b78..59a421d90 100644 --- a/stella/src/gui/Dialog.hxx +++ b/stella/src/gui/Dialog.hxx @@ -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: Dialog.hxx,v 1.15 2005-05-26 15:43:44 stephena Exp $ +// $Id: Dialog.hxx,v 1.16 2005-06-10 17:46:06 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -35,7 +35,7 @@ class DialogContainer; This is the base class for all dialog boxes. @author Stephen Anthony - @version $Id: Dialog.hxx,v 1.15 2005-05-26 15:43:44 stephena Exp $ + @version $Id: Dialog.hxx,v 1.16 2005-06-10 17:46:06 stephena Exp $ */ class Dialog : public GuiObject { @@ -61,7 +61,6 @@ class Dialog : public GuiObject virtual void draw(); void releaseFocus(); - virtual void handleTickle(); // Called periodically (in every guiloop() ) virtual void handleKeyDown(int ascii, int keycode, int modifiers); virtual void handleKeyUp(int ascii, int keycode, int modifiers); virtual void handleMouseDown(int x, int y, int button, int clickCount); diff --git a/stella/src/gui/GuiObject.hxx b/stella/src/gui/GuiObject.hxx index 53a369511..2cd86d8b9 100644 --- a/stella/src/gui/GuiObject.hxx +++ b/stella/src/gui/GuiObject.hxx @@ -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: GuiObject.hxx,v 1.9 2005-05-21 16:12:13 stephena Exp $ +// $Id: GuiObject.hxx,v 1.10 2005-06-10 17:46:06 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -33,7 +33,7 @@ class Widget; This is the base class for all GUI objects/widgets. @author Stephen Anthony - @version $Id: GuiObject.hxx,v 1.9 2005-05-21 16:12:13 stephena Exp $ + @version $Id: GuiObject.hxx,v 1.10 2005-06-10 17:46:06 stephena Exp $ */ class GuiObject : public CommandReceiver { @@ -68,6 +68,8 @@ class GuiObject : public CommandReceiver virtual bool isVisible() const = 0; virtual void draw() = 0; + static void resetActiveWidget() { _activeWidget = NULL; } + protected: OSystem* myOSystem; DialogContainer* myParent; @@ -76,6 +78,7 @@ class GuiObject : public CommandReceiver int _w, _h; Widget* _firstWidget; + static Widget* _activeWidget; protected: virtual void releaseFocus() = 0; diff --git a/stella/src/gui/GuiUtils.hxx b/stella/src/gui/GuiUtils.hxx index 375e89390..3f85e7e4e 100644 --- a/stella/src/gui/GuiUtils.hxx +++ b/stella/src/gui/GuiUtils.hxx @@ -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: GuiUtils.hxx,v 1.9 2005-06-07 01:14:39 stephena Exp $ +// $Id: GuiUtils.hxx,v 1.10 2005-06-10 17:46:06 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -29,7 +29,7 @@ Probably not very neat, but at least it works ... @author Stephen Anthony - @version $Id: GuiUtils.hxx,v 1.9 2005-06-07 01:14:39 stephena Exp $ + @version $Id: GuiUtils.hxx,v 1.10 2005-06-10 17:46:06 stephena Exp $ */ #define kLineHeight 12 @@ -48,12 +48,13 @@ enum OverlayColor { // The commands generated by various widgets enum { - kOKCmd = 'OK ', - kCloseCmd = 'CLOS', - kNextCmd = 'NEXT', - kPrevCmd = 'PREV', - kDefaultsCmd = 'DEFA', - kSetPositionCmd = 'SETP', + kOKCmd = 'OK ', + kCloseCmd = 'CLOS', + kNextCmd = 'NEXT', + kPrevCmd = 'PREV', + kDefaultsCmd = 'DEFA', + kSetPositionCmd = 'SETP', + kActiveWidgetCmd = 'ACTW', kRendererChanged, kAspectRatioChanged, kFrameRateChanged, diff --git a/stella/src/gui/LauncherDialog.cxx b/stella/src/gui/LauncherDialog.cxx index 64e7326e2..5cb93dbfc 100644 --- a/stella/src/gui/LauncherDialog.cxx +++ b/stella/src/gui/LauncherDialog.cxx @@ -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.20 2005-06-08 18:45:09 stephena Exp $ +// $Id: LauncherDialog.cxx,v 1.21 2005-06-10 17:46:06 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -97,6 +97,7 @@ LauncherDialog::LauncherDialog(OSystem* osystem, DialogContainer* parent, myList = new ListWidget(this, 10, 24, _w - 20, _h - 24 - 26 - 10 - 10); myList->setEditable(false); myList->setNumberingMode(kListNumberingOff); + myList->clearFlags(WIDGET_TAB_NAVIGATE); // Add note textwidget to show any notes for the currently selected ROM new StaticTextWidget(this, 20, _h - 43, 30, 16, "Note:", kTextAlignLeft); diff --git a/stella/src/gui/ListWidget.cxx b/stella/src/gui/ListWidget.cxx index 69ba76e81..bd5b55f9a 100644 --- a/stella/src/gui/ListWidget.cxx +++ b/stella/src/gui/ListWidget.cxx @@ -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: ListWidget.cxx,v 1.13 2005-06-09 20:09:23 stephena Exp $ +// $Id: ListWidget.cxx,v 1.14 2005-06-10 17:46:06 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -36,7 +36,8 @@ ListWidget::ListWidget(GuiObject* boss, int x, int y, int w, int h) : Widget(boss, x, y, w - kScrollBarWidth, h), CommandSender(boss) { - _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS; + _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | + WIDGET_TAB_NAVIGATE; _type = kListWidget; _numberingMode = kListNumberingOne; _entriesPerPage = (_h - 2) / kLineHeight; @@ -138,6 +139,10 @@ void ListWidget::handleMouseDown(int x, int y, int button, int clickCount) { if (isEnabled()) { + // A click indicated this widget has been selected + // It should receive focus (because it has the WIDGET_TAB_NAVIGATE property) + receivedFocus(); + int oldSelectedItem = _selectedItem; _selectedItem = (y - 1) / kLineHeight + _currentPos; if (_selectedItem > (int)_list.size() - 1) diff --git a/stella/src/gui/PromptDialog.cxx b/stella/src/gui/PromptWidget.cxx similarity index 86% rename from stella/src/gui/PromptDialog.cxx rename to stella/src/gui/PromptWidget.cxx index c4f45d127..cbd1f00ca 100644 --- a/stella/src/gui/PromptDialog.cxx +++ b/stella/src/gui/PromptWidget.cxx @@ -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: PromptDialog.cxx,v 1.9 2005-06-09 20:09:23 stephena Exp $ +// $Id: PromptWidget.cxx,v 1.1 2005-06-10 17:46:06 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -26,7 +26,7 @@ #include "Debugger.hxx" #include "DebuggerDialog.hxx" -#include "PromptDialog.hxx" +#include "PromptWidget.hxx" #define PROMPT "> " @@ -39,10 +39,14 @@ */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PromptDialog::PromptDialog(OSystem* osystem, DialogContainer* parent, - int x, int y, int w, int h) - : Dialog(osystem, parent, x, y, w, h) +PromptWidget::PromptWidget(GuiObject* boss, int x, int y, int w, int h) + : Widget(boss, x, y, w - kScrollBarWidth, h), + CommandSender(boss) { + _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | + WIDGET_TAB_NAVIGATE; + _type = kPromptWidget; + _kConsoleCharWidth = instance()->consoleFont().getMaxCharWidth(); _kConsoleLineHeight = instance()->consoleFont().getFontHeight() + 2; @@ -58,7 +62,8 @@ PromptDialog::PromptDialog(OSystem* osystem, DialogContainer* parent, _firstLineInBuffer = 0; // Add scrollbar - _scrollBar = new ScrollBarWidget(this, _w - kScrollBarWidth - 1, 0, kScrollBarWidth, _h); + _scrollBar = new ScrollBarWidget(boss, _x + _w, _y, kScrollBarWidth, _h); + _scrollBar->setTarget(this); // Init History @@ -74,27 +79,19 @@ PromptDialog::PromptDialog(OSystem* osystem, DialogContainer* parent, string version = string("Stella version ") + STELLA_VERSION + "\n"; print(version.c_str()); print("Debugger is ready\n"); + print(PROMPT); + _promptStartPos = _promptEndPos = _currentPos; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PromptDialog::~PromptDialog() +PromptWidget::~PromptWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::loadConfig() +void PromptWidget::drawWidget(bool hilite) { - if (_promptStartPos == -1) - { - print(PROMPT); - _promptStartPos = _promptEndPos = _currentPos; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::drawDialog() -{ - FrameBuffer& fb = instance()->frameBuffer(); + FrameBuffer& fb = _boss->instance()->frameBuffer(); // Fill the background fb.fillRect(_x, _y, _w, _h, kBGColor); @@ -127,15 +124,24 @@ void PromptDialog::drawDialog() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::handleMouseWheel(int x, int y, int direction) +void PromptWidget::handleMouseDown(int x, int y, int button, int clickCount) +{ +return; + _scrollBar->handleMouseDown(x, y, button, clickCount); +cerr << "PromptWidget::handleMouseDown\n"; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PromptWidget::handleMouseWheel(int x, int y, int direction) { _scrollBar->handleMouseWheel(x, y, direction); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::handleKeyDown(int ascii, int keycode, int modifiers) +bool PromptWidget::handleKeyDown(int ascii, int keycode, int modifiers) { int i; + bool handled = true; switch (keycode) { @@ -185,34 +191,6 @@ void PromptDialog::handleKeyDown(int ascii, int keycode, int modifiers) instance()->frameBuffer().refresh(); break; -#if 0 // FIXME - this may not be included in the 2.0 release - case 9: // tab - { - if (_completionCallbackProc) - { - int len = _currentPos - _promptStartPos; - assert(len >= 0); - char *str = new char[len + 1]; - - // Copy the user input to str - for (i = 0; i < len; i++) - str[i] = buffer(_promptStartPos + i); - str[len] = '\0'; - - char *completion = 0; - if ((*_completionCallbackProc)(this, str, completion, _callbackRefCon)) - { - insertIntoPrompt(completion); - scrollToCurrent(); - draw(); - instance()->frameBuffer().refresh(); - delete[] completion; - } - delete[] str; - } - break; - } -#endif case 127: killChar(+1); draw(); @@ -317,12 +295,16 @@ void PromptDialog::handleKeyDown(int ascii, int keycode, int modifiers) putchar(ascii); scrollToCurrent(); } + else + handled = false; break; } + + return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::insertIntoPrompt(const char* str) +void PromptWidget::insertIntoPrompt(const char* str) { unsigned int l = strlen(str); @@ -337,7 +319,7 @@ void PromptDialog::insertIntoPrompt(const char* str) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::handleCommand(CommandSender* sender, int cmd, int data) +void PromptWidget::handleCommand(CommandSender* sender, int cmd, int data) { switch (cmd) { @@ -354,7 +336,7 @@ void PromptDialog::handleCommand(CommandSender* sender, int cmd, int data) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::specialKeys(int keycode) +void PromptWidget::specialKeys(int keycode) { bool handled = false; @@ -399,7 +381,7 @@ void PromptDialog::specialKeys(int keycode) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::killChar(int direction) +void PromptWidget::killChar(int direction) { if(direction == -1) // Delete previous character (backspace) { @@ -431,7 +413,7 @@ void PromptDialog::killChar(int direction) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::killLine(int direction) +void PromptWidget::killLine(int direction) { if(direction == -1) // erase from current position to beginning of line { @@ -450,7 +432,7 @@ void PromptDialog::killLine(int direction) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::killLastWord() +void PromptWidget::killLastWord() { int cnt = 0; bool space = true; @@ -476,7 +458,7 @@ void PromptDialog::killLastWord() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::addToHistory(const char *str) +void PromptWidget::addToHistory(const char *str) { strcpy(_history[_historyIndex], str); _historyIndex = (_historyIndex + 1) % kHistorySize; @@ -487,7 +469,7 @@ void PromptDialog::addToHistory(const char *str) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::historyScroll(int direction) +void PromptWidget::historyScroll(int direction) { if (_historySize == 0) return; @@ -534,7 +516,7 @@ void PromptDialog::historyScroll(int direction) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::nextLine() +void PromptWidget::nextLine() { int line = _currentPos / _lineWidth; if (line == _scrollLine) @@ -548,7 +530,7 @@ void PromptDialog::nextLine() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Call this (at least) when the current line changes or when a new line is added -void PromptDialog::updateScrollBuffer() +void PromptWidget::updateScrollBuffer() { int lastchar = MAX(_promptEndPos, _currentPos); int line = lastchar / _lineWidth; @@ -571,7 +553,7 @@ void PromptDialog::updateScrollBuffer() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int PromptDialog::printf(const char *format, ...) +int PromptWidget::printf(const char *format, ...) { va_list argptr; @@ -582,7 +564,7 @@ int PromptDialog::printf(const char *format, ...) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int PromptDialog::vprintf(const char *format, va_list argptr) +int PromptWidget::vprintf(const char *format, va_list argptr) { char buf[2048]; @@ -596,7 +578,7 @@ int PromptDialog::vprintf(const char *format, va_list argptr) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::putchar(int c) +void PromptWidget::putchar(int c) { putcharIntern(c); @@ -605,7 +587,7 @@ void PromptDialog::putchar(int c) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::putcharIntern(int c) +void PromptWidget::putcharIntern(int c) { if (c == '\n') nextLine(); @@ -622,13 +604,13 @@ void PromptDialog::putcharIntern(int c) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::print(string str) // laziness/convenience method +void PromptWidget::print(string str) // laziness/convenience method { print(str.c_str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::print(const char *str) +void PromptWidget::print(const char *str) { while (*str) putcharIntern(*str++); @@ -638,9 +620,9 @@ void PromptDialog::print(const char *str) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::drawCaret() +void PromptWidget::drawCaret() { - FrameBuffer& fb = instance()->frameBuffer(); + FrameBuffer& fb = _boss->instance()->frameBuffer(); int line = _currentPos / _lineWidth; @@ -654,11 +636,11 @@ void PromptDialog::drawCaret() char c = buffer(_currentPos); fb.fillRect(x, y, _kConsoleCharWidth, _kConsoleLineHeight, kTextColor); - fb.drawChar(instance()->consoleFont(), c, x, y + 2, kBGColor); + fb.drawChar(_boss->instance()->consoleFont(), c, x, y + 2, kBGColor); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptDialog::scrollToCurrent() +void PromptWidget::scrollToCurrent() { int line = _promptEndPos / _lineWidth; diff --git a/stella/src/gui/PromptDialog.hxx b/stella/src/gui/PromptWidget.hxx similarity index 80% rename from stella/src/gui/PromptDialog.hxx rename to stella/src/gui/PromptWidget.hxx index a72143c90..871513f9c 100644 --- a/stella/src/gui/PromptDialog.hxx +++ b/stella/src/gui/PromptWidget.hxx @@ -13,21 +13,23 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: PromptDialog.hxx,v 1.7 2005-06-09 20:09:23 stephena Exp $ +// $Id: PromptWidget.hxx,v 1.1 2005-06-10 17:46:06 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ -#ifndef PROMPT_DIALOG_HXX -#define PROMPT_DIALOG_HXX +#ifndef PROMPT_WIDGET_HXX +#define PROMPT_WIDGET_HXX -class CommandSender; -class DialogContainer; class ScrollBarWidget; #include -#include "Dialog.hxx" + +#include "GuiObject.hxx" +#include "Widget.hxx" +#include "Command.hxx" +#include "bspf.hxx" enum { kBufferSize = 32768, @@ -36,12 +38,11 @@ enum { kHistorySize = 20 }; -class PromptDialog : public Dialog +class PromptWidget : public Widget, public CommandSender { public: - PromptDialog(OSystem* osystem, DialogContainer* parent, - int x, int y, int w, int h); - virtual ~PromptDialog(); + PromptWidget(GuiObject* boss, int x, int y, int w, int h); + virtual ~PromptWidget(); public: int printf(const char *format, ...); @@ -52,7 +53,7 @@ class PromptDialog : public Dialog protected: inline char &buffer(int idx) { return _buffer[idx % kBufferSize]; } - void drawDialog(); + void drawWidget(bool hilite); void drawCaret(); void putcharIntern(int c); void insertIntoPrompt(const char *str); @@ -72,11 +73,10 @@ class PromptDialog : public Dialog void addToHistory(const char *str); void historyScroll(int direction); - private: + void handleMouseDown(int x, int y, int button, int clickCount); void handleMouseWheel(int x, int y, int direction); - void handleKeyDown(int ascii, int keycode, int modifiers); + bool handleKeyDown(int ascii, int keycode, int modifiers); void handleCommand(CommandSender* sender, int cmd, int data); - void loadConfig(); protected: char _buffer[kBufferSize]; diff --git a/stella/src/gui/ScrollBarWidget.cxx b/stella/src/gui/ScrollBarWidget.cxx index d5c1d4671..3c86e9b8c 100644 --- a/stella/src/gui/ScrollBarWidget.cxx +++ b/stella/src/gui/ScrollBarWidget.cxx @@ -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: ScrollBarWidget.cxx,v 1.5 2005-05-21 16:12:13 stephena Exp $ +// $Id: ScrollBarWidget.cxx,v 1.6 2005-06-10 17:46:06 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -192,27 +192,6 @@ void ScrollBarWidget::handleMouseMoved(int x, int y, int button) } } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ScrollBarWidget::handleTickle() { -/* - // FIXME/TODO - this code is supposed to allow for "click-repeat" (like key repeat), - // i.e. if you click on one of the arrows and keep clicked, it will scroll - // continuously. However, just like key repeat, this requires two delays: - // First an "initial" delay that has to pass before repeating starts (otherwise - // it is near to impossible to achieve single clicks). Secondly, a repeat delay - // that determines how often per second a click is simulated. - int old_pos = _currentPos; - - if (_draggingPart == kUpArrowPart) - _currentPos--; - else if (_draggingPart == kDownArrowPart) - _currentPos++; - - // Make sure that _currentPos is still inside the bounds - checkBounds(old_pos); -*/ -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ScrollBarWidget::checkBounds(int old_pos) { diff --git a/stella/src/gui/ScrollBarWidget.hxx b/stella/src/gui/ScrollBarWidget.hxx index e7b20c0d5..f36cfde3d 100644 --- a/stella/src/gui/ScrollBarWidget.hxx +++ b/stella/src/gui/ScrollBarWidget.hxx @@ -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: ScrollBarWidget.hxx,v 1.2 2005-05-13 18:28:06 stephena Exp $ +// $Id: ScrollBarWidget.hxx,v 1.3 2005-06-10 17:46:06 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -49,7 +49,6 @@ class ScrollBarWidget : public Widget, public CommandSender virtual void handleMouseMoved(int x, int y, int button); virtual void handleMouseEntered(int button) { setFlags(WIDGET_HILITED); } virtual void handleMouseLeft(int button) { clearFlags(WIDGET_HILITED); _part = kNoPart; draw(); } - virtual void handleTickle(); // FIXME - this should be private, but then we also have to add accessors // for _numEntries, _entriesPerPage and _currentPos. This again leads to the question: diff --git a/stella/src/gui/TabWidget.cxx b/stella/src/gui/TabWidget.cxx index 0e89a4207..9ce0d9bc6 100644 --- a/stella/src/gui/TabWidget.cxx +++ b/stella/src/gui/TabWidget.cxx @@ -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: TabWidget.cxx,v 1.3 2005-06-08 18:45:09 stephena Exp $ +// $Id: TabWidget.cxx,v 1.4 2005-06-10 17:46:06 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -35,6 +35,9 @@ enum { kTabPadding = 3 }; +// +Widget* GuiObject::_activeWidget; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TabWidget::TabWidget(GuiObject *boss, int x, int y, int w, int h) : Widget(boss, x, y, w, h), @@ -54,6 +57,7 @@ TabWidget::~TabWidget() { delete _tabs[i].firstWidget; _tabs[i].firstWidget = 0; + // _tabs[i].activeWidget is deleted elsewhere } _tabs.clear(); } @@ -71,6 +75,7 @@ int TabWidget::addTab(const string& title) Tab newTab; newTab.title = title; newTab.firstWidget = NULL; + newTab.activeWidget = NULL; _tabs.push_back(newTab); @@ -102,13 +107,74 @@ void TabWidget::setActiveTab(int tabID) _tabs[_activeTab].firstWidget = _firstWidget; _activeTab = tabID; - _firstWidget = _tabs[tabID].firstWidget; - _boss->draw(); + _firstWidget = _tabs[tabID].firstWidget; + // If a widget has been activated elsewhere and it belongs to the + // current view, use it. Otherwise use the default. + if(_activeWidget && isWidgetInChain(_firstWidget, _activeWidget)) + _tabs[tabID].activeWidget = _activeWidget; + else + _activeWidget = _tabs[tabID].activeWidget; + + // Make sure this widget receives focus, and that the other widgets + // in the tabview lose focus + if(_activeWidget) + _activeWidget->receivedFocus(); + + _boss->draw(); _boss->instance()->frameBuffer().refresh(); } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TabWidget::cycleTab(int direction) +{ + int tabID = _activeTab; + + // Don't do anything if no tabs have been defined + if(tabID == -1) + return; + + if(direction == -1) // Go to the previous tab, wrap around at beginning + { + tabID--; + if(tabID == -1) + tabID = (int)_tabs.size() - 1; + } + else if(direction == 1) // Go to the next tab, wrap around at end + { + tabID++; + if(tabID == (int)_tabs.size()) + tabID = 0; + } + + // Finally, select the active tab + setActiveTab(tabID); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TabWidget::cycleWidget(int direction) +{ + // Don't do anything if no tabs have been defined + if(_activeTab == -1) + return; + + if(direction == -1) + Widget::setPrevInChain(_tabs[_activeTab].firstWidget, + _tabs[_activeTab].activeWidget); + else if(direction == +1) + Widget::setNextInChain(_tabs[_activeTab].firstWidget, + _tabs[_activeTab].activeWidget); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TabWidget::setActiveWidget(int tabID, Widget* widID) +{ + assert(0 <= tabID && tabID < (int)_tabs.size()); + _tabs[tabID].activeWidget = widID; + widID->receivedFocus(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::handleMouseDown(int x, int y, int button, int clickCount) { @@ -132,10 +198,53 @@ void TabWidget::handleMouseDown(int x, int y, int button, int clickCount) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TabWidget::handleKeyDown(int ascii, int keycode, int modifiers) { - // TODO: maybe there should be a way to switch between tabs - // using the keyboard? E.g. Alt-Shift-Left/Right-Arrow or something - // like that. - return Widget::handleKeyDown(ascii, keycode, modifiers); + // Test for TAB character + // Ctrl-Tab selects next tab + // Shift-Ctrl-Tab selects previous tab + // Tab sets next widget in current tab + // Shift-Tab sets previous widget in current tab + if(keycode == 9) // tab key + { + if(_boss->instance()->eventHandler().kbdControl(modifiers)) + { + if(_boss->instance()->eventHandler().kbdShift(modifiers)) + cycleTab(-1); + else + cycleTab(+1); + } + else if(_boss->instance()->eventHandler().kbdShift(modifiers)) + cycleWidget(-1); + else + cycleWidget(+1); + + return true; + } + else if (_activeWidget) + return _activeWidget->handleKeyDown(ascii, keycode, modifiers); + else + return Widget::handleKeyDown(ascii, keycode, modifiers); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TabWidget::handleCommand(CommandSender* sender, int cmd, int data) +{ + switch(cmd) + { + case kActiveWidgetCmd: + if(_activeWidget && isWidgetInChain(_firstWidget, _activeWidget)) + { + _tabs[_activeTab].activeWidget = _activeWidget; + Widget::setFocusForChain(_firstWidget, _activeWidget); + + // Make sure the changes are shown onscreen + _boss->instance()->frameBuffer().refresh(); + } + break; + + default: + sendCommand(cmd, data); + break; + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/stella/src/gui/TabWidget.hxx b/stella/src/gui/TabWidget.hxx index ca3d9141a..12a659dd6 100644 --- a/stella/src/gui/TabWidget.hxx +++ b/stella/src/gui/TabWidget.hxx @@ -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: TabWidget.hxx,v 1.3 2005-06-02 21:37:33 stephena Exp $ +// $Id: TabWidget.hxx,v 1.4 2005-06-10 17:46:07 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -33,6 +33,7 @@ class TabWidget : public Widget, public CommandSender struct Tab { string title; Widget* firstWidget; + Widget* activeWidget; }; typedef GUI::Array TabList; @@ -53,15 +54,18 @@ class TabWidget : public Widget, public CommandSender //void removeTab(int tabID); // Setting the active tab: void setActiveTab(int tabID); + void cycleTab(int direction); + void cycleWidget(int direction); // setActiveTab changes the value of _firstWidget. This means Widgets added afterwards // will be added to the active tab. + void setActiveWidget(int tabID, Widget* widID); virtual void handleMouseDown(int x, int y, int button, int clickCount); virtual bool handleKeyDown(int ascii, int keycode, int modifiers); + virtual void handleCommand(CommandSender* sender, int cmd, int data); protected: virtual void drawWidget(bool hilite); - virtual Widget *findWidget(int x, int y); protected: @@ -72,7 +76,6 @@ class TabWidget : public Widget, public CommandSender private: void box(int x, int y, int width, int height, OverlayColor colorA, OverlayColor colorB, bool omitBottom); - }; #endif diff --git a/stella/src/gui/Widget.cxx b/stella/src/gui/Widget.cxx index f3910646c..c484a3ac0 100644 --- a/stella/src/gui/Widget.cxx +++ b/stella/src/gui/Widget.cxx @@ -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: Widget.cxx,v 1.12 2005-06-08 18:45:09 stephena Exp $ +// $Id: Widget.cxx,v 1.13 2005-06-10 17:46:07 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -29,6 +29,8 @@ #include "GuiUtils.hxx" #include "Widget.hxx" +//FIXMEstatic int COUNT = 0; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Widget::Widget(GuiObject* boss, int x, int y, int w, int h) : GuiObject(boss->instance(), boss->parent(), x, y, w, h), @@ -106,6 +108,33 @@ void Widget::draw() } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Widget::receivedFocus() +{ + if(_hasFocus) + return; + + _hasFocus = true; + receivedFocusWidget(); + + // Only signal a new active widget if the widget has defined that capability + // We only care about widgets with WIDGET_TAB_NAVIGATE property + if(getFlags() & WIDGET_TAB_NAVIGATE) + { + _activeWidget = this; + _boss->handleCommand(NULL, kActiveWidgetCmd, 0); + } +} +/* FIXME +void Widget::lostFocus() +{ + _hasFocus = false; + lostFocusWidget(); + +if(getFlags() & WIDGET_TAB_NAVIGATE) + cerr << "lost focus: " << this << endl; +} +*/ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Widget* Widget::findWidgetInChain(Widget *w, int x, int y) { @@ -123,6 +152,169 @@ Widget* Widget::findWidgetInChain(Widget *w, int x, int y) return w; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool Widget::isWidgetInChain(Widget* w, Widget* find) +{ + bool found = false; + + while(w) + { + // Stop as soon as we find the widget + if(w == find) + { + found = true; + break; + } + w = w->_next; + } + + return found; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Widget::setFocusForChain(Widget* w, Widget* hasFocus) +{ + if(!hasFocus) + return; + + while(w) + { + if(w != hasFocus) + w->lostFocus(); + + w = w->_next; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Widget::setPrevInChain(Widget* start, Widget* hasFocus) +{ + if(!start) + return; + + // We search the array in circular fashion until the 'end' is reached + Widget* w = hasFocus; + Widget* active = NULL; + + if(w) // start from 'hasFocus' + { + w = w->_next; + while(w) + { + if(w->getFlags() & WIDGET_TAB_NAVIGATE) + { + active = w; + break; + } + w = w->_next; + } + + // If we haven't found an active widget by now, start searching from + // the beginning of the list + if(!active) + { + w = start; + while(w != hasFocus) + { + if(w->getFlags() & WIDGET_TAB_NAVIGATE) + { + active = w; + break; + } + w = w->_next; + } + } + } + else // start from the beginning, since no widget currently has focus + { + w = start; + while(w) + { + if(w->getFlags() & WIDGET_TAB_NAVIGATE) + { + active = w; + break; + } + w = w->_next; + } + } + + // At this point, we *should* have an active widget + if(active) + active->receivedFocus(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Widget::setNextInChain(Widget* start, Widget* hasFocus) +{ + if(!start) + return; +// FIXME - get this working +cerr << "--------------------------------\nWidget list:\n"; + Widget* w1 = start; + while(w1) + { + if(w1->getFlags() & WIDGET_TAB_NAVIGATE) + { + cerr << w1 << endl; + } + w1 = w1->_next; + } +cerr << "\n--------------------------------\n"; + + + // We search the array in circular fashion until the 'end' is reached + Widget* w = hasFocus; + Widget* active = NULL; + + if(w) // start from 'hasFocus' + { + w = w->_next; + while(w) + { + if(w->getFlags() & WIDGET_TAB_NAVIGATE) + { + active = w; + break; + } + w = w->_next; + } + + // If we haven't found an active widget by now, start searching from + // the beginning of the list + if(!active) + { + w = start; + while(w != hasFocus) + { + if(w->getFlags() & WIDGET_TAB_NAVIGATE) + { + active = w; + break; + } + w = w->_next; + } + } + } + else // start from the beginning, since no widget currently has focus + { + w = start; + while(w) + { + if(w->getFlags() & WIDGET_TAB_NAVIGATE) + { + active = w; + break; + } + w = w->_next; + } + } + + // At this point, we *should* have an active widget + if(active) + active->receivedFocus(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StaticTextWidget::StaticTextWidget(GuiObject *boss, int x, int y, int w, int h, const string& text, TextAlignment align) diff --git a/stella/src/gui/Widget.hxx b/stella/src/gui/Widget.hxx index bfbb64c79..378e63a8a 100644 --- a/stella/src/gui/Widget.hxx +++ b/stella/src/gui/Widget.hxx @@ -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: Widget.hxx,v 1.14 2005-06-08 18:45:09 stephena Exp $ +// $Id: Widget.hxx,v 1.15 2005-06-10 17:46:07 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -29,6 +29,7 @@ class Dialog; #include "OSystem.hxx" #include "FrameBuffer.hxx" #include "GuiObject.hxx" +#include "GuiUtils.hxx" #include "bspf.hxx" enum { @@ -38,7 +39,7 @@ enum { WIDGET_BORDER = 1 << 3, WIDGET_INV_BORDER = 1 << 4, WIDGET_CLEARBG = 1 << 5, - WIDGET_WANT_TICKLE = 1 << 7, + WIDGET_TAB_NAVIGATE = 1 << 7, WIDGET_TRACK_MOUSE = 1 << 8, WIDGET_RETAIN_FOCUS = 1 << 9 }; @@ -52,7 +53,8 @@ enum { kListWidget = 'LIST', kScrollBarWidget = 'SCRB', kPopUpWidget = 'POPU', - kTabWidget = 'TABW' + kTabWidget = 'TABW', + kPromptWidget = 'PROM' }; enum { @@ -64,7 +66,7 @@ enum { This is the base class for all widgets. @author Stephen Anthony - @version $Id: Widget.hxx,v 1.14 2005-06-08 18:45:09 stephena Exp $ + @version $Id: Widget.hxx,v 1.15 2005-06-10 17:46:07 stephena Exp $ */ class Widget : public GuiObject { @@ -87,11 +89,11 @@ class Widget : public GuiObject virtual bool handleKeyUp(int ascii, int keycode, int modifiers) { return false; } virtual void handleJoyDown(int stick, int button) {} virtual void handleJoyUp(int stick, int button) {} - virtual void handleTickle() {} void draw(); - void receivedFocus() { _hasFocus = true; receivedFocusWidget(); } + void receivedFocus(); void lostFocus() { _hasFocus = false; lostFocusWidget(); } + virtual bool wantsFocus() { return false; }; void setFlags(int flags) { _flags |= flags; @@ -136,6 +138,20 @@ class Widget : public GuiObject public: static Widget* findWidgetInChain(Widget* start, int x, int y); + + /** Determine if 'find' is in the chain pointed to by 'start' */ + static bool isWidgetInChain(Widget* start, Widget* find); + + /** Widget 'hasFocus' has focus, make all other widgets in chain lose focus */ + static void setFocusForChain(Widget* start, Widget* hasFocus); + + /** Select previous widget in chain with WIDGET_TAB_NOTIFY property to have + focus, starting from 'hasFocus' */ + static void setPrevInChain(Widget* start, Widget* hasFocus); + + /** Select next widget in chain with WIDGET_TAB_NOTIFY property to have + focus, starting from 'hasFocus' */ + static void setNextInChain(Widget* start, Widget* hasFocus); };