diff --git a/src/common/Array.hxx b/src/common/Array.hxx index 313bd861b..bff81fa54 100644 --- a/src/common/Array.hxx +++ b/src/common/Array.hxx @@ -33,8 +33,8 @@ template class Array { protected: - int _capacity; - int _size; + uInt32 _capacity; + uInt32 _size; T *_data; public: @@ -48,7 +48,7 @@ class Array _size = array._size; _capacity = _size + 128; _data = new T[_capacity]; - for(int i = 0; i < _size; i++) + for(uInt32 i = 0; i < _size; i++) _data[i] = array._data[i]; } @@ -58,7 +58,7 @@ class Array delete [] _data; } - void reserve(int capacity) + void reserve(uInt32 capacity) { if(capacity <= _capacity) return; @@ -74,11 +74,11 @@ class Array void push_back(const Array& array) { ensureCapacity(_size + array._size); - for(int i = 0; i < array._size; i++) + for(uInt32 i = 0; i < array._size; i++) _data[_size++] = array._data[i]; } - void insert_at(int idx, const T& element) + void insert_at(uInt32 idx, const T& element) { assert(idx >= 0 && idx <= _size); ensureCapacity(_size + 1); @@ -87,30 +87,30 @@ class Array // usually isn't correct (specifically, for any class which has a non-default // copy behaviour. E.g. the String class uses a refCounter which has to be // updated whenever a String is copied. - for(int i = _size; i > idx; i--) + for(uInt32 i = _size; i > idx; i--) _data[i] = _data[i-1]; _data[idx] = element; _size++; } - T remove_at(int idx) + T remove_at(uInt32 idx) { assert(idx >= 0 && idx < _size); T tmp = _data[idx]; - for(int i = idx; i < _size - 1; i++) + for(uInt32 i = idx; i < _size - 1; i++) _data[i] = _data[i+1]; _size--; return tmp; } - T& operator [](int idx) + T& operator [](uInt32 idx) { assert(idx >= 0 && idx < _size); return _data[idx]; } - const T& operator [](int idx) const + const T& operator [](uInt32 idx) const { assert(idx >= 0 && idx < _size); return _data[idx]; @@ -123,14 +123,14 @@ class Array _size = array._size; _capacity = _size + 128; _data = new T[_capacity]; - for(int i = 0; i < _size; i++) + for(uInt32 i = 0; i < _size; i++) _data[i] = array._data[i]; return *this; } - unsigned int size() const { return _size; } - unsigned int capacity() const { return _capacity; } + uInt32 size() const { return _size; } + uInt32 capacity() const { return _capacity; } void clear(bool fullerase = true) { @@ -172,7 +172,7 @@ class Array } protected: - void ensureCapacity(int new_len) + void ensureCapacity(uInt32 new_len) { if (new_len <= _capacity) return; @@ -184,7 +184,7 @@ class Array if (old_data) { // Copy old data - for (int i = 0; i < _size; i++) + for (uInt32 i = 0; i < _size; i++) _data[i] = old_data[i]; delete [] old_data; } diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx index f7772e83a..680b4643f 100644 --- a/src/debugger/gui/DebuggerDialog.cxx +++ b/src/debugger/gui/DebuggerDialog.cxx @@ -47,6 +47,7 @@ DebuggerDialog::DebuggerDialog(OSystem* osystem, DialogContainer* parent, int x, int y, int w, int h) : Dialog(osystem, parent, x, y, w, h, true), // use base surface myTab(NULL), + myRomTab(NULL), myFatalError(NULL) { addTiaArea(); @@ -72,7 +73,9 @@ void DebuggerDialog::loadConfig() myTiaZoom->loadConfig(); myCpu->loadConfig(); myRam->loadConfig(); - myRom->loadConfig(); + + myRomTab->loadConfig(); +// myRom->loadConfig(); myMessageBox->setEditString(""); } @@ -176,12 +179,14 @@ void DebuggerDialog::addTiaArea() void DebuggerDialog::addTabArea() { const GUI::Rect& r = instance().debugger().getTabBounds(); - const int vBorder = 4; // The tab widget + // Since there are two tab widgets in this dialog, we specifically + // assign an ID of 0 myTab = new TabWidget(this, instance().consoleFont(), r.left, r.top + vBorder, r.width(), r.height() - vBorder); + myTab->setID(0); addTabWidget(myTab); const int widWidth = r.width() - vBorder; @@ -193,28 +198,28 @@ void DebuggerDialog::addTabArea() myPrompt = new PromptWidget(myTab, instance().consoleFont(), 2, 2, widWidth, widHeight); myTab->setParentWidget(tabID, myPrompt); - addToFocusList(myPrompt->getFocusList(), tabID); + addToFocusList(myPrompt->getFocusList(), myTab, tabID); // The TIA tab tabID = myTab->addTab("TIA"); TiaWidget* tia = new TiaWidget(myTab, instance().consoleFont(), 2, 2, widWidth, widHeight); myTab->setParentWidget(tabID, tia); - addToFocusList(tia->getFocusList(), tabID); + addToFocusList(tia->getFocusList(), myTab, tabID); // The input/output tab (includes RIOT and INPTx from TIA) tabID = myTab->addTab("I/O"); RiotWidget* riot = new RiotWidget(myTab, instance().consoleFont(), 2, 2, widWidth, widHeight); myTab->setParentWidget(tabID, riot); - addToFocusList(riot->getFocusList(), tabID); + addToFocusList(riot->getFocusList(), myTab, tabID); // The Audio tab tabID = myTab->addTab("Audio"); AudioWidget* aud = new AudioWidget(myTab, instance().consoleFont(), 2, 2, widWidth, widHeight); myTab->setParentWidget(tabID, aud); - addToFocusList(aud->getFocusList(), tabID); + addToFocusList(aud->getFocusList(), myTab, tabID); myTab->setActiveTab(0); } @@ -248,6 +253,8 @@ void DebuggerDialog::addStatusArea() void DebuggerDialog::addRomArea() { const GUI::Rect& r = instance().debugger().getRomBounds(); + const int vBorder = 4; + int xpos, ypos; xpos = r.left + 10; ypos = 10; @@ -289,14 +296,45 @@ void DebuggerDialog::addRomArea() bwidth, bheight, "<", kDDRewindCmd); myRewindButton->clearFlags(WIDGET_ENABLED); - xpos = r.left + 10; ypos += myRam->getHeight() + 5; - myRom = new RomWidget(this, instance().consoleFont(), xpos, ypos); - addToFocusList(myRom->getFocusList()); - // Add the DataGridOpsWidget to any widgets which contain a // DataGridWidget which we want controlled myCpu->setOpsWidget(ops); myRam->setOpsWidget(ops); + + //////////////////////////////////////////////////////////////////// + // Disassembly area + + xpos = r.left + vBorder; ypos += myRam->getHeight() + 5; + const int tabWidth = r.width() - vBorder; + const int tabHeight = r.height() - ypos; + int tabID; + + // Since there are two tab widgets in this dialog, we specifically + // assign an ID of 1 + myRomTab = new TabWidget( + this, instance().consoleFont(), xpos, ypos, tabWidth, tabHeight); + myRomTab->setID(1); + addTabWidget(myRomTab); + + // The main disassembly tab + tabID = myRomTab->addTab(" Disassembly "); + myRom = new RomWidget(myRomTab, instance().consoleFont(), + 2, 2, tabWidth - 1, + tabHeight - myRomTab->getTabHeight() - 2); + myRomTab->setParentWidget(tabID, myRom); + addToFocusList(myRom->getFocusList(), myRomTab, tabID); + + // The 'cart-specific' information tab + tabID = myRomTab->addTab(instance().console().cartridge().name()); +#if 0 + myRom = new RomWidget(myRomTab, instance().consoleFont(), + 2, 2, tabWidth - 1, + tabHeight - myRomTab->getTabHeight() - 2); + myRomTab->setParentWidget(tabID, myRom); + addToFocusList(myRom->getFocusList(), myRomTab, tabID); +#endif + + myRomTab->setActiveTab(0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/debugger/gui/DebuggerDialog.hxx b/src/debugger/gui/DebuggerDialog.hxx index c3a536a98..29c277c6a 100644 --- a/src/debugger/gui/DebuggerDialog.hxx +++ b/src/debugger/gui/DebuggerDialog.hxx @@ -72,7 +72,7 @@ class DebuggerDialog : public Dialog kDDExitFatalCmd = 'DDer' }; - TabWidget* myTab; + TabWidget *myTab, *myRomTab; PromptWidget* myPrompt; TiaInfoWidget* myTiaInfo; diff --git a/src/debugger/gui/RomWidget.cxx b/src/debugger/gui/RomWidget.cxx index 7e808857f..f1a537025 100644 --- a/src/debugger/gui/RomWidget.cxx +++ b/src/debugger/gui/RomWidget.cxx @@ -38,8 +38,9 @@ #include "RomWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -RomWidget::RomWidget(GuiObject* boss, const GUI::Font& font, int x, int y) - : Widget(boss, font, x, y, 16, 16), +RomWidget::RomWidget(GuiObject* boss, const GUI::Font& font, + int x, int y, int w, int h) + : Widget(boss, font, x, y, w, h), CommandSender(boss), myListIsDirty(true), myCurrentBank(-1) @@ -85,18 +86,12 @@ RomWidget::RomWidget(GuiObject* boss, const GUI::Font& font, int x, int y) // Create rom listing xpos = x; ypos += myBank->getHeight() + 4; - const GUI::Rect& dialog = instance().debugger().getDialogBounds(); - int w = dialog.width() - x - 5, h = dialog.height() - ypos - 3; - myRomList = new RomListWidget(boss, font, xpos, ypos, w, h); + myRomList = new RomListWidget(boss, font, xpos, ypos, _w - 4, _h - ypos - 2); myRomList->setTarget(this); myRomList->myMenu->setTarget(this); addFocusWidget(myRomList); - // Calculate real dimensions - _w = myRomList->getWidth(); - _h = myRomList->getHeight(); - // Create dialog box for save ROM (get name) StringList label; label.push_back("Filename: "); diff --git a/src/debugger/gui/RomWidget.hxx b/src/debugger/gui/RomWidget.hxx index 64d22a609..4de51a043 100644 --- a/src/debugger/gui/RomWidget.hxx +++ b/src/debugger/gui/RomWidget.hxx @@ -39,7 +39,7 @@ class StringList; class RomWidget : public Widget, public CommandSender { public: - RomWidget(GuiObject* boss, const GUI::Font& font, int x, int y); + RomWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h); virtual ~RomWidget(); void invalidate(bool forcereload = true) diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 44a2c3ea8..8bebe1cdc 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -163,11 +163,6 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props) // Reset the system to its power-on state mySystem->reset(); -#ifdef DEBUGGER_SUPPORT - myOSystem->createDebugger(*this); - m6502->attach(myOSystem->debugger()); -#endif - // Finally, add remaining info about the console myConsoleInfo.CartName = myProperties.get(Cartridge_Name); myConsoleInfo.CartMD5 = myProperties.get(Cartridge_MD5); @@ -920,6 +915,15 @@ void Console::toggleFixedColors() const myOSystem->frameBuffer().showMessage("Fixed debug colors disabled"); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Console::addDebugger() +{ +#ifdef DEBUGGER_SUPPORT + myOSystem->createDebugger(*this); + mySystem->m6502().attach(myOSystem->debugger()); +#endif +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Console::ourNTSCPalette[256] = { 0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0, diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index bc8652ab6..6ad707677 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -170,6 +170,11 @@ class Console : public Serializable */ const ConsoleInfo& about() const { return myConsoleInfo; } + /** + Set up the console to use the debugger. + */ + void addDebugger(); + public: /** Overloaded assignment operator diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 122caf064..e9e8a2975 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -50,9 +50,8 @@ FrameBuffer::FrameBuffer(OSystem* osystem) myInitializedCount(0), myPausedCount(0) { - myMsg.surface = myStatsMsg.surface = NULL; - myMsg.surfaceID = myStatsMsg.surfaceID = -1; - myMsg.enabled = myStatsMsg.enabled = false; + myMsg.surface = myStatsMsg.surface = NULL; + myMsg.enabled = myStatsMsg.enabled = false; // Load NTSC filter settings myNTSCFilter.loadConfig(myOSystem->settings()); @@ -175,13 +174,13 @@ FBInitStatus FrameBuffer::initialize(const string& title, if(myStatsMsg.surface == NULL) { - myStatsMsg.surfaceID = allocateSurface(myStatsMsg.w, myStatsMsg.h); - myStatsMsg.surface = surface(myStatsMsg.surfaceID); + uInt32 surfaceID = allocateSurface(myStatsMsg.w, myStatsMsg.h); + myStatsMsg.surface = surface(surfaceID); } if(myMsg.surface == NULL) { - myMsg.surfaceID = allocateSurface(640, myOSystem->font().getFontHeight()+10); - myMsg.surface = surface(myMsg.surfaceID); + uInt32 surfaceID = allocateSurface(640, myOSystem->font().getFontHeight()+10); + myMsg.surface = surface(surfaceID); } // Finally, show some information about the framebuffer, @@ -586,22 +585,22 @@ void FrameBuffer::toggleScanlineInterpolation() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int FrameBuffer::allocateSurface(int w, int h, bool useBase) +uInt32 FrameBuffer::allocateSurface(int w, int h, bool useBase) { // Create a new surface FBSurface* surface = createSurface(w, h, useBase); // Add it to the list - mySurfaceList.insert(make_pair(int(mySurfaceList.size()), surface)); + mySurfaceList.insert(make_pair(mySurfaceList.size(), surface)); // Return a reference to it return mySurfaceList.size() - 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FBSurface* FrameBuffer::surface(int id) const +FBSurface* FrameBuffer::surface(uInt32 id) const { - map::const_iterator iter = mySurfaceList.find(id); + map::const_iterator iter = mySurfaceList.find(id); return iter != mySurfaceList.end() ? iter->second : NULL; } @@ -614,7 +613,7 @@ void FrameBuffer::resetSurfaces(FBSurface* tiasurface) // Any derived FrameBuffer classes that call this method should be // aware of these restrictions, and act accordingly - map::iterator iter; + map::iterator iter; for(iter = mySurfaceList.begin(); iter != mySurfaceList.end(); ++iter) iter->second->free(); if(tiasurface) diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index d6382e28f..b1484ac81 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -173,7 +173,7 @@ class FrameBuffer @return A unique ID used to identify this surface */ - int allocateSurface(int w, int h, bool useBase = false); + uInt32 allocateSurface(int w, int h, bool useBase = false); /** Retrieve the surface associated with the given ID. @@ -181,7 +181,7 @@ class FrameBuffer @param id The ID for the surface to retrieve. @return A pointer to a valid surface object, or NULL. */ - FBSurface* surface(int id) const; + FBSurface* surface(uInt32 id) const; /** Returns the current dimensions of the framebuffer image. @@ -633,7 +633,6 @@ class FrameBuffer MessagePosition position; uInt32 color; FBSurface* surface; - int surfaceID; bool enabled; }; Message myMsg; @@ -645,7 +644,7 @@ class FrameBuffer VideoModeList* myCurrentModeList; // Holds a reference to all the surfaces that have been created - map mySurfaceList; + map mySurfaceList; // Holds static strings for the remap menu (emulation and menu events) static GraphicsMode ourGraphicsModes[GFX_NumModes]; diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 6b979db11..2e7850b4f 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -531,6 +531,9 @@ bool OSystem::createConsole(const FilesystemNode& rom, const string& md5sum, myConsole = openConsole(myRomFile, myRomMD5, type, id); if(myConsole) { + #ifdef DEBUGGER_SUPPORT + myConsole->addDebugger(); + #endif #ifdef CHEATCODE_SUPPORT myCheatManager->loadCheats(myRomMD5); #endif diff --git a/src/gui/Dialog.cxx b/src/gui/Dialog.cxx index 2b8b20c75..c89f9d6a5 100644 --- a/src/gui/Dialog.cxx +++ b/src/gui/Dialog.cxx @@ -46,31 +46,26 @@ Dialog::Dialog(OSystem* instance, DialogContainer* parent, _cancelWidget(0), _visible(false), _isBase(isBase), - _ourTab(NULL), - _surface(NULL), - _focusID(0), - _surfaceID(-1) + _surface(0), + _tabID(0) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Dialog::~Dialog() { - for(unsigned int i = 0; i < _ourFocusList.size(); ++i) - _ourFocusList[i].focusList.clear(); + _myFocus.list.clear(); + _myTabList.clear(); delete _firstWidget; _firstWidget = NULL; - _ourButtonGroup.clear(); + _buttonGroup.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::open() { - _result = 0; - _visible = true; - // Make sure we have a valid surface to draw into // Technically, this shouldn't be needed until drawDialog(), but some // dialogs cause drawing to occur within loadConfig() @@ -80,11 +75,10 @@ void Dialog::open() // However, this policy is left entirely to the framebuffer // We suggest the hint here, but specific framebuffers are free to // ignore it - _surface = instance().frameBuffer().surface(_surfaceID); if(_surface == NULL) { - _surfaceID = instance().frameBuffer().allocateSurface(_w, _h, _isBase); - _surface = instance().frameBuffer().surface(_surfaceID); + uInt32 surfaceID = instance().frameBuffer().allocateSurface(_w, _h, _isBase); + _surface = instance().frameBuffer().surface(surfaceID); } center(); @@ -92,7 +86,9 @@ void Dialog::open() // (Re)-build the focus list to use for the widgets which are currently // onscreen - buildFocusWidgetList(_focusID); + buildCurrentFocusList(); + + _visible = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -135,43 +131,75 @@ void Dialog::releaseFocus() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::addFocusWidget(Widget* w) { - // All focusable widgets should retain focus - if(w) - w->setFlags(WIDGET_RETAIN_FOCUS); + if(!w) + return; - if(_ourFocusList.size() == 0) - { - Focus f; - f.focusedWidget = 0; - _ourFocusList.push_back(f); - } - _ourFocusList[0].focusedWidget = w; - _ourFocusList[0].focusList.push_back(w); + // All focusable widgets should retain focus + w->setFlags(WIDGET_RETAIN_FOCUS); + + _myFocus.widget = w; + _myFocus.list.push_back(w); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Dialog::addToFocusList(WidgetArray& list, int id) +void Dialog::addToFocusList(WidgetArray& list) { // All focusable widgets should retain focus - for(unsigned int i = 0; i < list.size(); ++i) + for(uInt32 i = 0; i < list.size(); ++i) list[i]->setFlags(WIDGET_RETAIN_FOCUS); - id++; // Arrays start at 0, not -1. - - // Make sure the array is large enough - while((int)_ourFocusList.size() <= id) - { - Focus f; - f.focusedWidget = NULL; - _ourFocusList.push_back(f); - } - - _ourFocusList[id].focusList.push_back(list); - if(id == 0 && _ourFocusList.size() > 0) - _focusList = _ourFocusList[0].focusList; + _myFocus.list.push_back(list); + _focusList = _myFocus.list; if(list.size() > 0) - _ourFocusList[id].focusedWidget = list[0]; + _myFocus.widget = list[0]; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Dialog::addToFocusList(WidgetArray& list, TabWidget* w, int tabId) +{ + // Only add the list if the tab actually exists + if(!w || w->getID() < 0 || (uInt32)w->getID() >= _myTabList.size()) + return; + + assert(w == _myTabList[w->getID()].widget); + + // All focusable widgets should retain focus + for(uInt32 i = 0; i < list.size(); ++i) + list[i]->setFlags(WIDGET_RETAIN_FOCUS); + + // First get the appropriate focus list + FocusList& focus = _myTabList[w->getID()].focus; + + // Now insert in the correct place in that focus list + uInt32 id = tabId; + if(id < focus.size()) + focus[id].list.push_back(list); + else + { + // Make sure the array is large enough + while(focus.size() <= id) + focus.push_back(Focus()); + + focus[id].list.push_back(list); + } + + if(list.size() > 0) + focus[id].widget = list[0]; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Dialog::addTabWidget(TabWidget* w) +{ + if(!w || w->getID() < 0) + return; + + // Make sure the array is large enough + uInt32 id = w->getID(); + while(_myTabList.size() < id) + _myTabList.push_back(TabFocus()); + + _myTabList.push_back(TabFocus(w)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -183,51 +211,66 @@ void Dialog::setFocus(Widget* w) { // Redraw widgets for new focus _focusedWidget = Widget::setFocusForChain(this, getFocusList(), w, 0); + +cerr << "set focus for " << _focusedWidget << endl; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Dialog::buildFocusWidgetList(int id) +void Dialog::buildCurrentFocusList(int tabID) { // Yes, this is hideously complex. That's the price we pay for // tab navigation ... + _focusList.clear(); - // Remember which item previously had focus, but only if it belongs - // to this focus list - if(_focusID < (int)_ourFocusList.size() && - Widget::isWidgetInChain(_ourFocusList[_focusID].focusList, _focusedWidget)) - _ourFocusList[_focusID].focusedWidget = _focusedWidget; - - _focusID = id; - - // Create a focuslist for items currently onscreen - // We do this by starting with any dialog focus list (at index 0 in the - // focus lists, then appending the list indicated by 'id'. - if(_focusID < (int)_ourFocusList.size()) + // Remember which tab item previously had focus, if applicable + // This only applies if this method was called for a tab change + Widget* tabFocusWidget = 0; + if(tabID >= 0 && tabID < (int)_myTabList.size()) { - _focusList.clear(); - _focusList.push_back(_ourFocusList[0].focusList); +cerr << "save tab, move to next\n"; + // Save focus in previously selected tab column, + // and get focus for new tab column + TabFocus& tabfocus = _myTabList[tabID]; + tabfocus.saveCurrentFocus(_focusedWidget); + tabFocusWidget = tabfocus.getNewFocus(); - // Append extra focus list - if(_focusID > 0) - _focusList.push_back(_ourFocusList[_focusID].focusList); - - // Add button group at end of current focus list - // We do it this way for TabWidget, so that buttons are scanned - // *after* the widgets in the current tab - if(_ourButtonGroup.size() > 0) - _focusList.push_back(_ourButtonGroup); - - // Only update _focusedWidget if it doesn't belong to the main focus list - // HACK - figure out how to properly deal with only one focus-able widget - // in a tab -- TabWidget is the spawn of the devil - if(_focusList.size() == 1) - _focusedWidget = _focusList[0]; - else if(!Widget::isWidgetInChain(_ourFocusList[0].focusList, _focusedWidget)) - _focusedWidget = _ourFocusList[_focusID].focusedWidget; + _tabID = tabID; } - else - _focusedWidget = 0; + + // Special case for dialogs containing only one tab widget, with all items + // arranged in separate tabs + bool containsSingleTab = _myFocus.list.size() == 1 && _myTabList.size() == 1; + + // A dialog containing only one tabwidget should be added first + if(containsSingleTab) + { + _focusList.push_back(_myFocus.list); + _focusedWidget = _focusList[0]; + } + + // Now add appropriate items from tablist (if present) + for(uInt32 id = 0; id < _myTabList.size(); ++id) + _myTabList[id].appendFocusList(_focusList); + + // Add remaining items from main focus list + if(!containsSingleTab) + _focusList.push_back(_myFocus.list); + + // Add button group at end of current focus list + // We do it this way for TabWidget, so that buttons are scanned + // *after* the widgets in the current tab + if(_buttonGroup.size() > 0) + _focusList.push_back(_buttonGroup); + + // Finally, the moment we've all been waiting for :) + // Set the actual focus widget + if(tabFocusWidget) +{cerr << "tab focus changed\n"; + _focusedWidget = tabFocusWidget; +} + else if(!_focusedWidget && _focusList.size() > 0) + _focusedWidget = _focusList[0]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -295,20 +338,14 @@ void Dialog::handleKeyDown(StellaKey key, StellaMod mod, char ascii) // not ascii?? if(instance().eventHandler().kbdShift(mod)) { - if(key == KBDK_LEFT && _ourTab) // left arrow - { - _ourTab->cycleTab(-1); + if(key == KBDK_LEFT && cycleTab(-1)) return; - } - else if(key == KBDK_RIGHT && _ourTab) // right arrow - { - _ourTab->cycleTab(+1); + else if(key == KBDK_RIGHT && cycleTab(+1)) return; - } - else if(key == KBDK_TAB) // tab + else if(key == KBDK_TAB) e = Event::UINavPrev; } - else if(key == KBDK_TAB) // tab + else if(key == KBDK_TAB) e = Event::UINavNext; // Check the keytable now, since we might get one of the above events, @@ -338,22 +375,19 @@ void Dialog::handleKeyUp(StellaKey key, StellaMod mod, char ascii) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleMouseDown(int x, int y, int button, int clickCount) { - Widget* w; - w = findWidget(x, y); + Widget* w = findWidget(x, y); _dragWidget = w; - setFocus(w); if(w) - w->handleMouseDown(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), button, clickCount); + w->handleMouseDown(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), + button, clickCount); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleMouseUp(int x, int y, int button, int clickCount) { - Widget* w; - if(_focusedWidget) { // Lose focus on mouseup unless the widget requested to retain the focus @@ -361,10 +395,10 @@ void Dialog::handleMouseUp(int x, int y, int button, int clickCount) releaseFocus(); } - w = _dragWidget; - + Widget* w = _dragWidget; if(w) - w->handleMouseUp(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), button, clickCount); + w->handleMouseUp(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), + button, clickCount); _dragWidget = 0; } @@ -372,16 +406,14 @@ void Dialog::handleMouseUp(int x, int y, int button, int clickCount) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleMouseWheel(int x, int y, int direction) { - Widget* w; - // This may look a bit backwards, but I think it makes more sense for // the mouse wheel to primarily affect the widget the mouse is at than // the widget that happens to be focused. - w = findWidget(x, y); + Widget* w = findWidget(x, y); if(!w) w = _focusedWidget; - if (w) + if(w) w->handleMouseWheel(x, y, direction); } @@ -389,13 +421,13 @@ void Dialog::handleMouseWheel(int x, int y, int direction) void Dialog::handleMouseMoved(int x, int y, int button) { Widget* w; - + if(_focusedWidget && !_dragWidget) { w = _focusedWidget; int wx = w->getAbsX() - _x; int wy = w->getAbsY() - _y; - + // We still send mouseEntered/Left messages to the focused item // (but to no other items). bool mouseInFocusedWidget = (x >= wx && x < wx + w->_w && y >= wy && y < wy + w->_h); @@ -441,7 +473,8 @@ bool Dialog::handleMouseClicks(int x, int y, int button) Widget* w = findWidget(x, y); if(w) - return w->handleMouseClicks(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), button); + return w->handleMouseClicks(x - (w->getAbsX() - _x), + y - (w->getAbsY() - _y), button); else return false; } @@ -554,14 +587,40 @@ bool Dialog::handleNavEvent(Event::Type e) return false; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool Dialog::cycleTab(int direction) +{ +cerr << "cycle " << (direction < 0 ? "left" : "right") << ", tabID = " << _tabID << endl; + + if(_tabID >= 0 && _tabID < (int)_myTabList.size()) + { + _myTabList[_tabID].widget->cycleTab(direction); + return true; + } + return false; + +#if 0 + if(key == KBDK_LEFT && _ourTab) // left arrow + { + _ourTab->cycleTab(-1); + return; + } + else if(key == KBDK_RIGHT && _ourTab) // right arrow + { + _ourTab->cycleTab(+1); + return; + } +#endif +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case kTabChangedCmd: - // Add this focus list for the given tab to the global focus list - buildFocusWidgetList(++data); + if(_visible) + buildCurrentFocusList(id); break; case kCloseCmd: @@ -580,7 +639,7 @@ Widget* Dialog::findWidget(int x, int y) return Widget::findWidgetInChain(_firstWidget, x, y); } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::addOKCancelBGroup(WidgetArray& wid, const GUI::Font& font, const string& okText, const string& cancelText) { @@ -614,3 +673,72 @@ void Dialog::addOKCancelBGroup(WidgetArray& wid, const GUI::Font& font, addOKWidget(b); #endif } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Dialog::Focus::Focus(Widget* w) + : widget(w) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Dialog::Focus::~Focus() +{ + list.clear(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Dialog::TabFocus::TabFocus(TabWidget* w) + : widget(w), + currentTab(0) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Dialog::TabFocus::~TabFocus() +{ + focus.clear(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Dialog::TabFocus::appendFocusList(WidgetArray& list) +{ + uInt32 active = widget->getActiveTab(); + + if(active >= 0 && active < focus.size()) + list.push_back(focus[active].list); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Dialog::TabFocus::saveCurrentFocus(Widget* w) +{ +#if 1 + if(currentTab >= 0 && currentTab < focus.size()) + { + cerr << "chain len = " << focus[currentTab].list.size() << endl; + + if(Widget::isWidgetInChain(focus[currentTab].list, w)) + { + cerr << "saving widget\n"; + focus[currentTab].widget = w; + } + else + cerr << "not in chain\n"; +} + +#else + if(currentTab >= 0 && currentTab < focus.size() && + Widget::isWidgetInChain(focus[currentTab].list, w)) +{cerr << "saving widget\n"; + focus[currentTab].widget = w; +} +#endif +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Widget* Dialog::TabFocus::getNewFocus() +{ + currentTab = widget->getActiveTab(); + + return (currentTab >= 0 && currentTab < focus.size()) ? + focus[currentTab].widget : 0; +} diff --git a/src/gui/Dialog.hxx b/src/gui/Dialog.hxx index 710722c9a..9540ab4c8 100644 --- a/src/gui/Dialog.hxx +++ b/src/gui/Dialog.hxx @@ -45,12 +45,6 @@ class Dialog : public GuiObject { friend class DialogContainer; - struct Focus { - Widget* focusedWidget; - WidgetArray focusList; - }; - typedef Common::Array FocusList; - public: Dialog(OSystem* instance, DialogContainer* parent, int x, int y, int w, int h, bool isBase = false); @@ -69,10 +63,11 @@ class Dialog : public GuiObject virtual void setDefaults() {} void addFocusWidget(Widget* w); - void addToFocusList(WidgetArray& list, int id = -1); - void addBGroupToFocusList(WidgetArray& list) { _ourButtonGroup = list; } + void addToFocusList(WidgetArray& list); + void addToFocusList(WidgetArray& list, TabWidget* w, int tabId); + void addBGroupToFocusList(WidgetArray& list) { _buttonGroup = list; } void redrawFocus(); - void addTabWidget(TabWidget* w) { _ourTab = w; } + void addTabWidget(TabWidget* w); void addOKWidget(Widget* w) { _okWidget = w; } void addCancelWidget(Widget* w) { _cancelWidget = w; } void setFocus(Widget* w); @@ -102,12 +97,10 @@ class Dialog : public GuiObject const string& okText = "", const string& cancelText = ""); - void setResult(int result) { _result = result; } - int getResult() const { return _result; } - private: - void buildFocusWidgetList(int id); + void buildCurrentFocusList(int tabID = -1); bool handleNavEvent(Event::Type e); + bool cycleTab(int direction); protected: Widget* _mouseWidget; @@ -119,14 +112,36 @@ class Dialog : public GuiObject bool _isBase; private: - FocusList _ourFocusList; - TabWidget* _ourTab; - WidgetArray _ourButtonGroup; + struct Focus { + Widget* widget; + WidgetArray list; + + Focus(Widget* w = 0); + virtual ~Focus(); + }; + typedef Common::Array FocusList; + + struct TabFocus { + TabWidget* widget; + FocusList focus; + uInt32 currentTab; + + TabFocus(TabWidget* w = 0); + virtual ~TabFocus(); + + void appendFocusList(WidgetArray& list); + void saveCurrentFocus(Widget* w); + Widget* getNewFocus(); + }; + typedef Common::Array TabFocusList; + + Focus _myFocus; // focus for base dialog + TabFocusList _myTabList; // focus for each tab (if any) + + WidgetArray _buttonGroup; FBSurface* _surface; - int _result; - int _focusID; - int _surfaceID; + int _tabID; }; #endif diff --git a/src/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx index 6e3821e08..ac4822882 100644 --- a/src/gui/GameInfoDialog.cxx +++ b/src/gui/GameInfoDialog.cxx @@ -178,7 +178,7 @@ GameInfoDialog::GameInfoDialog( wid.push_back(myType); // Add items for tab 0 - addToFocusList(wid, tabID); + addToFocusList(wid, myTab, tabID); // 2) Console properties @@ -216,7 +216,7 @@ GameInfoDialog::GameInfoDialog( wid.push_back(myTVType); // Add items for tab 1 - addToFocusList(wid, tabID); + addToFocusList(wid, myTab, tabID); // 3) Controller properties @@ -326,7 +326,7 @@ GameInfoDialog::GameInfoDialog( wid.push_back(myMouseY); // Add items for tab 2 - addToFocusList(wid, tabID); + addToFocusList(wid, myTab, tabID); // 4) Display properties @@ -389,7 +389,7 @@ GameInfoDialog::GameInfoDialog( myPPBlendLabel->setFlags(WIDGET_CLEARBG); // Add items for tab 3 - addToFocusList(wid, tabID); + addToFocusList(wid, myTab, tabID); // Activate the first tab diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index 8fcbc12b9..ea219f2f5 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -67,7 +67,7 @@ InputDialog::InputDialog(OSystem* osystem, DialogContainer* parent, myTab->getHeight() - ypos, actions, kEmulationMode); myTab->setParentWidget(tabID, myEmulEventMapper); - addToFocusList(myEmulEventMapper->getFocusList(), tabID); + addToFocusList(myEmulEventMapper->getFocusList(), myTab, tabID); // 2) Event mapper for UI actions tabID = myTab->addTab("UI Events"); @@ -78,7 +78,7 @@ InputDialog::InputDialog(OSystem* osystem, DialogContainer* parent, myTab->getHeight() - ypos, actions, kMenuMode); myTab->setParentWidget(tabID, myMenuEventMapper); - addToFocusList(myMenuEventMapper->getFocusList(), tabID); + addToFocusList(myMenuEventMapper->getFocusList(), myTab, tabID); // 3) Devices & ports addDevicePortTab(font); @@ -197,7 +197,7 @@ void InputDialog::addDevicePortTab(const GUI::Font& font) wid.push_back(myMouseControl); // Add items for virtual device ports - addToFocusList(wid, tabID); + addToFocusList(wid, myTab, tabID); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/Rect.hxx b/src/gui/Rect.hxx index 7b4ce3771..0befcef84 100644 --- a/src/gui/Rect.hxx +++ b/src/gui/Rect.hxx @@ -164,6 +164,12 @@ struct Rect void moveTo(const Point & p) { moveTo(p.x, p.y); } + + friend ostream& operator<<(ostream& os, const Rect& r) { + os << "x=" << r.x() << ", y=" << r.y() + << ", w=" << r.width() << ", h=" << r.height(); + return os; + } }; } // End of namespace GUI diff --git a/src/gui/TabWidget.cxx b/src/gui/TabWidget.cxx index daac02d5a..12e5c1699 100644 --- a/src/gui/TabWidget.cxx +++ b/src/gui/TabWidget.cxx @@ -39,6 +39,8 @@ TabWidget::TabWidget(GuiObject* boss, const GUI::Font& font, _activeTab(-1), _firstTime(true) { + _id = 0; // For dialogs with multiple tab widgets, they should specifically + // call ::setID to differentiate among them _flags = WIDGET_ENABLED | WIDGET_CLEARBG; _type = kTabWidget; _bgcolor = kDlgColor; @@ -112,7 +114,7 @@ void TabWidget::setActiveTab(int tabID, bool show) // Let parent know about the tab change if(show) - sendCommand(kTabChangedCmd, _activeTab, -1); + sendCommand(kTabChangedCmd, _activeTab, _id); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index 939e1a105..7ebc99cf4 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -156,7 +156,7 @@ UIDialog::UIDialog(OSystem* osystem, DialogContainer* parent, kTextAlignLeft); // Add items for tab 0 - addToFocusList(wid, tabID); + addToFocusList(wid, myTab, tabID); ////////////////////////////////////////////////////////// // 2) Debugger options @@ -211,7 +211,7 @@ UIDialog::UIDialog(OSystem* osystem, DialogContainer* parent, } // Add items for tab 1 - addToFocusList(wid, tabID); + addToFocusList(wid, myTab, tabID); ////////////////////////////////////////////////////////// // 3) Misc. options @@ -263,7 +263,7 @@ UIDialog::UIDialog(OSystem* osystem, DialogContainer* parent, ypos += lineHeight + 4; // Add items for tab 2 - addToFocusList(wid, tabID); + addToFocusList(wid, myTab, tabID); // Activate the first tab myTab->setActiveTab(0); diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index 9cfa0d548..141a2c3be 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -236,7 +236,7 @@ VideoDialog::VideoDialog(OSystem* osystem, DialogContainer* parent, ypos += lineHeight + 4; // Add items for tab 0 - addToFocusList(wid, tabID); + addToFocusList(wid, myTab, tabID); ////////////////////////////////////////////////////////// // 2) TV effects options @@ -326,7 +326,7 @@ VideoDialog::VideoDialog(OSystem* osystem, DialogContainer* parent, CREATE_CLONE_BUTTON(Custom, "Revert"); // Add items for tab 2 - addToFocusList(wid, tabID); + addToFocusList(wid, myTab, tabID); // Activate the first tab myTab->setActiveTab(0); diff --git a/src/macosx/SerialPortMACOSX.cxx b/src/macosx/SerialPortMACOSX.cxx index b14ad3d26..e44b196b7 100644 --- a/src/macosx/SerialPortMACOSX.cxx +++ b/src/macosx/SerialPortMACOSX.cxx @@ -39,6 +39,7 @@ SerialPortMACOSX::SerialPortMACOSX() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SerialPortMACOSX::~SerialPortMACOSX() { + closePort(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -65,7 +66,10 @@ bool SerialPortMACOSX::openPort(const string& device) void SerialPortMACOSX::closePort() { if(myHandle) + { close(myHandle); + myHandle = 0; + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/win32/SerialPortWin32.cxx b/src/win32/SerialPortWin32.cxx index 848ad3180..43f72b680 100644 --- a/src/win32/SerialPortWin32.cxx +++ b/src/win32/SerialPortWin32.cxx @@ -49,7 +49,10 @@ bool SerialPortWin32::openPort(const string& device) FillMemory(&dcb, sizeof(dcb), 0); dcb.DCBlength = sizeof(dcb); if(!BuildCommDCB("19200,n,8,1", &dcb)) + { + closePort() return false; + } memset(&dcb, 0, sizeof(DCB)); dcb.BaudRate = CBR_19200;