From 516f6b5d2b84c6f4a9aa447d651f3d5e6d113f6d Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Fri, 2 Dec 2022 02:25:57 +1100 Subject: -debugger: Improved session save/restore. * Qt: Save expression for memory and disassembly views. * Qt: Made command history behave more like Cocoa. * Qt: Added expression history and made behaviour more like Cocoa. * Qt: Refactored global notifications to use signals. * Win32: Increased command/expression history size to 100 items. * Cocoa: Save state of device info viewer windows. * Qt/Win32/Cocoa: Save command/expression history. -util/xmlfile.cpp: Fixed bug where copyInto failed to copy nodes. --- scripts/src/osd/modules.lua | 8 +- src/lib/util/xmlfile.cpp | 10 +- src/osd/modules/debugger/debugqt.cpp | 87 ++------- src/osd/modules/debugger/osx/debugcommandhistory.h | 3 + .../modules/debugger/osx/debugcommandhistory.mm | 30 +++- src/osd/modules/debugger/osx/debugconsole.mm | 9 +- src/osd/modules/debugger/osx/debugwindowhandler.mm | 2 + src/osd/modules/debugger/osx/deviceinfoviewer.mm | 1 + src/osd/modules/debugger/qt/breakpointswindow.cpp | 41 ++--- src/osd/modules/debugger/qt/breakpointswindow.h | 26 +-- src/osd/modules/debugger/qt/dasmwindow.cpp | 136 ++++++++++---- src/osd/modules/debugger/qt/dasmwindow.h | 33 +--- src/osd/modules/debugger/qt/debuggerview.cpp | 40 ++++- src/osd/modules/debugger/qt/debuggerview.h | 3 + .../debugger/qt/deviceinformationwindow.cpp | 32 ++-- .../modules/debugger/qt/deviceinformationwindow.h | 26 +-- src/osd/modules/debugger/qt/deviceswindow.cpp | 26 +-- src/osd/modules/debugger/qt/deviceswindow.h | 24 +-- src/osd/modules/debugger/qt/logwindow.cpp | 24 +-- src/osd/modules/debugger/qt/logwindow.h | 22 +-- src/osd/modules/debugger/qt/mainwindow.cpp | 178 +++++++++--------- src/osd/modules/debugger/qt/mainwindow.h | 41 +---- src/osd/modules/debugger/qt/memorywindow.cpp | 198 +++++++++++++-------- src/osd/modules/debugger/qt/memorywindow.h | 42 ++--- src/osd/modules/debugger/qt/windowqt.cpp | 163 ++++++++++++++--- src/osd/modules/debugger/qt/windowqt.h | 87 +++++---- src/osd/modules/debugger/win/debugwininfo.h | 3 +- src/osd/modules/debugger/win/editwininfo.cpp | 41 ++++- src/osd/modules/debugger/win/editwininfo.h | 4 + src/osd/modules/debugger/xmlconfig.cpp | 3 + src/osd/modules/debugger/xmlconfig.h | 3 + 31 files changed, 748 insertions(+), 598 deletions(-) diff --git a/scripts/src/osd/modules.lua b/scripts/src/osd/modules.lua index cbc4734cb96..3c0da69f3c6 100644 --- a/scripts/src/osd/modules.lua +++ b/scripts/src/osd/modules.lua @@ -319,11 +319,9 @@ function qtdebuggerbuild() local version = str_to_version(_OPTIONS["gcc_version"]) if _OPTIONS["gcc"]~=nil and (string.find(_OPTIONS["gcc"], "clang") or string.find(_OPTIONS["gcc"], "asmjs")) then configuration { "gmake or ninja" } - if (version >= 30600) then - buildoptions { - "-Wno-inconsistent-missing-override", - } - end + buildoptions { + "-Wno-error=inconsistent-missing-override", + } configuration { } end diff --git a/src/lib/util/xmlfile.cpp b/src/lib/util/xmlfile.cpp index e1bd1941734..be7bab597ca 100644 --- a/src/lib/util/xmlfile.cpp +++ b/src/lib/util/xmlfile.cpp @@ -465,8 +465,14 @@ data_node *data_node::copy_into(data_node &parent) const } else { - dst = dst->get_parent(); - src = src->get_parent()->get_next_sibling(); + do + { + dst = dst->get_parent(); + src = src->get_parent(); + next = src->get_next_sibling(); + } + while (!next && (&parent != dst)); + src = next; } } } diff --git a/src/osd/modules/debugger/debugqt.cpp b/src/osd/modules/debugger/debugqt.cpp index c0dc5acb7d6..ae82137f0d8 100644 --- a/src/osd/modules/debugger/debugqt.cpp +++ b/src/osd/modules/debugger/debugqt.cpp @@ -45,7 +45,7 @@ bool winwindow_qt_filter(void *message); namespace { -class debug_qt : public osd_module, public debug_module +class debug_qt : public osd_module, public debug_module, protected osd::debugger::qt::DebuggerQt #if defined(_WIN32) && !defined(SDLMAME_WIN32) , public QAbstractNativeEventFilter #endif @@ -75,6 +75,8 @@ public: } #endif + virtual running_machine &machine() const override { return *m_machine; } + private: void configuration_load(config_type which_type, config_level level, util::xml::data_node const *parentnode); void configuration_save(config_type which_type, util::xml::data_node *parentnode); @@ -102,13 +104,8 @@ char *qtArgv[] = { qtArg0, nullptr }; void debug_qt::exit() { // If you've done a hard reset, clear out existing widgets - if (m_mainwindow) - { - m_mainwindow->setExiting(); - QApplication::closeAllWindows(); - qApp->processEvents(QEventLoop::AllEvents, 1); - m_mainwindow = nullptr; - } + emit exitDebugger(); + m_mainwindow = nullptr; } @@ -145,7 +142,7 @@ void debug_qt::wait_for_debugger(device_t &device, bool firststop) // Dialog initialization if (!m_mainwindow) { - m_mainwindow = new osd::debugger::qt::MainWindow(*m_machine); + m_mainwindow = new osd::debugger::qt::MainWindow(*this); if (m_config) { load_window_configurations(*m_config->get_first_child()); @@ -155,11 +152,7 @@ void debug_qt::wait_for_debugger(device_t &device, bool firststop) } // Ensure all top level widgets are visible & bring main window to front - foreach (QWidget *widget, QApplication::topLevelWidgets()) - { - if (widget->isWindow() && (widget->windowType() == Qt::Window)) - widget->show(); - } + emit showAllWindows(); if (firststop) { @@ -167,33 +160,13 @@ void debug_qt::wait_for_debugger(device_t &device, bool firststop) m_mainwindow->raise(); } - // Set the main window to display the proper cpu + // Set the main window to display the proper CPU m_mainwindow->setProcessor(&device); // Run our own QT event loop osd_sleep(osd_ticks_per_second() / 1000 * 50); qApp->processEvents(QEventLoop::AllEvents, 1); - // Refresh everyone if requested - if (m_mainwindow->wantsRefresh()) - { - QWidgetList allWidgets = qApp->allWidgets(); - for (int i = 0; i < allWidgets.length(); i++) - allWidgets[i]->update(); - m_mainwindow->clearRefreshFlag(); - } - - // Hide all top level widgets if requested - if (m_mainwindow->wantsHide()) - { - foreach (QWidget *widget, QApplication::topLevelWidgets()) - { - if (widget->isWindow() && (widget->windowType() == Qt::Window)) - widget->hide(); - } - m_mainwindow->clearHideFlag(); - } - #if defined(_WIN32) && !defined(SDLMAME_WIN32) winwindow_update_cursor_state(*m_machine); // make sure the cursor isn't hidden while in debugger #endif @@ -232,18 +205,7 @@ void debug_qt::configuration_save(config_type which_type, util::xml::data_node * { // We only save system configuration for now if ((config_type::SYSTEM == which_type) && parentnode) - { - // Loop over all the open windows - for (QWidget *widget : QApplication::topLevelWidgets()) - { - if (!widget->isWindow() || (widget->windowType() != Qt::Window)) - continue; - - osd::debugger::qt::WindowQt *const win = dynamic_cast(widget); - if (win) - win->saveConfiguration(*parentnode); - } - } + emit saveConfiguration(*parentnode); } @@ -251,46 +213,33 @@ void debug_qt::load_window_configurations(util::xml::data_node const &parentnode { for (util::xml::data_node const *wnode = parentnode.get_child(osd::debugger::NODE_WINDOW); wnode; wnode = wnode->get_next_sibling(osd::debugger::NODE_WINDOW)) { - std::unique_ptr cfg; osd::debugger::qt::WindowQt *win = nullptr; switch (wnode->get_attribute_int(osd::debugger::ATTR_WINDOW_TYPE, -1)) { case osd::debugger::WINDOW_TYPE_CONSOLE: - cfg = std::make_unique(); + win = m_mainwindow; break; case osd::debugger::WINDOW_TYPE_MEMORY_VIEWER: - cfg = std::make_unique(); - win = new osd::debugger::qt::MemoryWindow(*m_machine); + win = new osd::debugger::qt::MemoryWindow(*this); break; case osd::debugger::WINDOW_TYPE_DISASSEMBLY_VIEWER: - cfg = std::make_unique(); - win = new osd::debugger::qt::DasmWindow(*m_machine); + win = new osd::debugger::qt::DasmWindow(*this); break; case osd::debugger::WINDOW_TYPE_ERROR_LOG_VIEWER: - cfg = std::make_unique(); - win = new osd::debugger::qt::LogWindow(*m_machine); + win = new osd::debugger::qt::LogWindow(*this); break; case osd::debugger::WINDOW_TYPE_POINTS_VIEWER: - cfg = std::make_unique(); - win = new osd::debugger::qt::BreakpointsWindow(*m_machine); + win = new osd::debugger::qt::BreakpointsWindow(*this); break; case osd::debugger::WINDOW_TYPE_DEVICES_VIEWER: - cfg = std::make_unique(); - win = new osd::debugger::qt::DevicesWindow(*m_machine); + win = new osd::debugger::qt::DevicesWindow(*this); break; case osd::debugger::WINDOW_TYPE_DEVICE_INFO_VIEWER: - cfg = std::make_unique(); - win = new osd::debugger::qt::DeviceInformationWindow(*m_machine); + win = new osd::debugger::qt::DeviceInformationWindow(*this); break; } - if (cfg) - { - cfg->recoverFromXmlNode(*wnode); - if (win) - cfg->applyToQWidget(win); - else if (osd::debugger::WINDOW_TYPE_CONSOLE == cfg->m_type) - cfg->applyToQWidget(m_mainwindow); - } + if (win) + win->restoreConfiguration(*wnode); } } diff --git a/src/osd/modules/debugger/osx/debugcommandhistory.h b/src/osd/modules/debugger/osx/debugcommandhistory.h index f99767cb4be..cf84ddc50f2 100644 --- a/src/osd/modules/debugger/osx/debugcommandhistory.h +++ b/src/osd/modules/debugger/osx/debugcommandhistory.h @@ -32,4 +32,7 @@ - (void)reset; - (void)clear; +- (void)saveConfigurationToNode:(util::xml::data_node *)node; +- (void)restoreConfigurationFromNode:(util::xml::data_node const *)node; + @end diff --git a/src/osd/modules/debugger/osx/debugcommandhistory.mm b/src/osd/modules/debugger/osx/debugcommandhistory.mm index 74a34904ae7..5b0f05511b7 100644 --- a/src/osd/modules/debugger/osx/debugcommandhistory.mm +++ b/src/osd/modules/debugger/osx/debugcommandhistory.mm @@ -54,9 +54,9 @@ - (void)add:(NSString *)entry { if (([history count] == 0) || ![[history objectAtIndex:0] isEqualToString:entry]) { - [history insertObject:entry atIndex:0]; - while ([history count] > length) + while ([history count] >= length) [history removeLastObject]; + [history insertObject:entry atIndex:0]; } position = 0; } @@ -110,4 +110,30 @@ [history removeAllObjects]; } + +- (void)saveConfigurationToNode:(util::xml::data_node *)node { + util::xml::data_node *const hist = node->add_child(osd::debugger::NODE_WINDOW_HISTORY, nullptr); + if (hist) { + for (NSInteger i = [history count]; 0 < i; --i) + hist->add_child(osd::debugger::NODE_HISTORY_ITEM, [[history objectAtIndex:(i - 1)] UTF8String]); + } +} + + +- (void)restoreConfigurationFromNode:(util::xml::data_node const *)node { + [self clear]; + util::xml::data_node const *const hist = node->get_child(osd::debugger::NODE_WINDOW_HISTORY); + if (hist) { + util::xml::data_node const *item = hist->get_child(NODE_HISTORY_ITEM); + while (item) { + if (item->get_value() && *item->get_value()) { + while ([history count] >= length) + [history removeLastObject]; + [history insertObject:[NSString stringWithUTF8String:item->get_value()] atIndex:0]; + } + item = item->get_next_sibling(NODE_HISTORY_ITEM); + } + } +} + @end diff --git a/src/osd/modules/debugger/osx/debugconsole.mm b/src/osd/modules/debugger/osx/debugconsole.mm index f6d01375403..18fe0607bee 100644 --- a/src/osd/modules/debugger/osx/debugconsole.mm +++ b/src/osd/modules/debugger/osx/debugconsole.mm @@ -404,8 +404,11 @@ win = [[MAMEDevicesViewer alloc] initWithMachine:*machine console:self]; break; case osd::debugger::WINDOW_TYPE_DEVICE_INFO_VIEWER: - // FIXME: needs device info on init, make another variant - //win = [[MAMEDeviceInfoViewer alloc] initWithMachine:*machine console:self]; + { + // FIXME: feels like a leaky abstraction, but device is needed for init + device_t *const device = machine->root_device().subdevice(node->get_attribute_string(osd::debugger::ATTR_WINDOW_DEVICE_TAG, ":")); + win = [[MAMEDeviceInfoViewer alloc] initWithDevice:(device ? *device : machine->root_device()) machine:*machine console:self]; + } break; default: break; @@ -437,6 +440,7 @@ : NSMaxY([[[dasmSplit subviews] objectAtIndex:0] frame])); } [dasmView saveConfigurationToNode:node]; + [history saveConfigurationToNode:node]; } @@ -451,6 +455,7 @@ ofDividerAtIndex:0]; } [dasmView restoreConfigurationFromNode:node]; + [history restoreConfigurationFromNode:node]; } diff --git a/src/osd/modules/debugger/osx/debugwindowhandler.mm b/src/osd/modules/debugger/osx/debugwindowhandler.mm index ebeb1711dc4..ce824080c3d 100644 --- a/src/osd/modules/debugger/osx/debugwindowhandler.mm +++ b/src/osd/modules/debugger/osx/debugwindowhandler.mm @@ -494,6 +494,7 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo - (void)saveConfigurationToNode:(util::xml::data_node *)node { [super saveConfigurationToNode:node]; node->add_child(osd::debugger::NODE_WINDOW_EXPRESSION, [[self expression] UTF8String]); + [history saveConfigurationToNode:node]; } @@ -502,6 +503,7 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo util::xml::data_node const *const expr = node->get_child(osd::debugger::NODE_WINDOW_EXPRESSION); if (expr && expr->get_value()) [self setExpression:[NSString stringWithUTF8String:expr->get_value()]]; + [history restoreConfigurationFromNode:node]; } @end diff --git a/src/osd/modules/debugger/osx/deviceinfoviewer.mm b/src/osd/modules/debugger/osx/deviceinfoviewer.mm index e23110308ba..49ab79dedb8 100644 --- a/src/osd/modules/debugger/osx/deviceinfoviewer.mm +++ b/src/osd/modules/debugger/osx/deviceinfoviewer.mm @@ -238,6 +238,7 @@ - (void)saveConfigurationToNode:(util::xml::data_node *)node { [super saveConfigurationToNode:node]; node->set_attribute_int(osd::debugger::ATTR_WINDOW_TYPE, osd::debugger::WINDOW_TYPE_DEVICE_INFO_VIEWER); + node->set_attribute(osd::debugger::ATTR_WINDOW_DEVICE_TAG, device->tag()); } @end diff --git a/src/osd/modules/debugger/qt/breakpointswindow.cpp b/src/osd/modules/debugger/qt/breakpointswindow.cpp index c108b2b94a3..60ceae6d16f 100644 --- a/src/osd/modules/debugger/qt/breakpointswindow.cpp +++ b/src/osd/modules/debugger/qt/breakpointswindow.cpp @@ -17,8 +17,8 @@ namespace osd::debugger::qt { -BreakpointsWindow::BreakpointsWindow(running_machine &machine, QWidget *parent) : - WindowQt(machine, nullptr) +BreakpointsWindow::BreakpointsWindow(DebuggerQt &debugger, QWidget *parent) : + WindowQt(debugger, nullptr) { setWindowTitle("Debug: All Breakpoints"); @@ -83,6 +83,20 @@ BreakpointsWindow::~BreakpointsWindow() } +void BreakpointsWindow::restoreConfiguration(util::xml::data_node const &node) +{ + WindowQt::restoreConfiguration(node); + + auto const type = node.get_attribute_int(ATTR_WINDOW_POINTS_TYPE, -1); + QActionGroup *typeGroup = findChild("typegroup"); + if ((0 <= type) && (typeGroup->actions().size() > type)) + typeGroup->actions()[type]->trigger(); + + m_breakpointsView->restoreConfigurationFromNode(node); + +} + + void BreakpointsWindow::saveConfigurationToNode(util::xml::data_node &node) { WindowQt::saveConfigurationToNode(node); @@ -105,6 +119,8 @@ void BreakpointsWindow::saveConfigurationToNode(util::xml::data_node &node) break; } } + + m_breakpointsView->saveConfigurationToNode(node); } @@ -136,25 +152,4 @@ void BreakpointsWindow::typeChanged(QAction* changedTo) layout->addWidget(m_breakpointsView); } - - -//========================================================================= -// BreakpointsWindowQtConfig -//========================================================================= -void BreakpointsWindowQtConfig::applyToQWidget(QWidget* widget) -{ - WindowQtConfig::applyToQWidget(widget); - BreakpointsWindow *window = dynamic_cast(widget); - - QActionGroup *typeGroup = window->findChild("typegroup"); - typeGroup->actions()[m_bwType]->trigger(); -} - - -void BreakpointsWindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node) -{ - WindowQtConfig::recoverFromXmlNode(node); - m_bwType = node.get_attribute_int(ATTR_WINDOW_POINTS_TYPE, m_bwType); -} - } // namespace osd::debugger::qt diff --git a/src/osd/modules/debugger/qt/breakpointswindow.h b/src/osd/modules/debugger/qt/breakpointswindow.h index 262d416ceff..0a07b4facfb 100644 --- a/src/osd/modules/debugger/qt/breakpointswindow.h +++ b/src/osd/modules/debugger/qt/breakpointswindow.h @@ -17,9 +17,11 @@ class BreakpointsWindow : public WindowQt Q_OBJECT public: - BreakpointsWindow(running_machine &machine, QWidget *parent = nullptr); + BreakpointsWindow(DebuggerQt &debugger, QWidget *parent = nullptr); virtual ~BreakpointsWindow(); + virtual void restoreConfiguration(util::xml::data_node const &node) override; + protected: virtual void saveConfigurationToNode(util::xml::data_node &node) override; @@ -31,28 +33,6 @@ private: DebuggerView *m_breakpointsView; }; - -//========================================================================= -// A way to store the configuration of a window long enough to read/write. -//========================================================================= -class BreakpointsWindowQtConfig : public WindowQtConfig -{ -public: - BreakpointsWindowQtConfig() : - WindowQtConfig(WINDOW_TYPE_POINTS_VIEWER), - m_bwType(0) - { - } - - ~BreakpointsWindowQtConfig() {} - - // Settings - int m_bwType; - - void applyToQWidget(QWidget *widget); - void recoverFromXmlNode(util::xml::data_node const &node); -}; - } // namespace osd::debugger::qt #endif // MAME_DEBUGGER_QT_BREAKPOINTSWINDOW_H diff --git a/src/osd/modules/debugger/qt/dasmwindow.cpp b/src/osd/modules/debugger/qt/dasmwindow.cpp index dd7677516eb..d528be04d14 100644 --- a/src/osd/modules/debugger/qt/dasmwindow.cpp +++ b/src/osd/modules/debugger/qt/dasmwindow.cpp @@ -10,6 +10,7 @@ #include "util/xmlfile.h" +#include #include #include #include @@ -19,8 +20,9 @@ namespace osd::debugger::qt { -DasmWindow::DasmWindow(running_machine &machine, QWidget *parent) : - WindowQt(machine, nullptr) +DasmWindow::DasmWindow(DebuggerQt &debugger, QWidget *parent) : + WindowQt(debugger, nullptr), + m_inputHistory() { setWindowTitle("Debug: Disassembly View"); @@ -41,6 +43,8 @@ DasmWindow::DasmWindow(running_machine &machine, QWidget *parent) : // The input edit m_inputEdit = new QLineEdit(topSubFrame); connect(m_inputEdit, &QLineEdit::returnPressed, this, &DasmWindow::expressionSubmitted); + connect(m_inputEdit, &QLineEdit::textEdited, this, &DasmWindow::expressionEdited); + m_inputEdit->installEventFilter(this); // The cpu combo box m_cpuComboBox = new QComboBox(topSubFrame); @@ -124,6 +128,39 @@ DasmWindow::~DasmWindow() } +void DasmWindow::restoreConfiguration(util::xml::data_node const &node) +{ + WindowQt::restoreConfiguration(node); + + debug_view_disasm &dasmview = *m_dasmView->view(); + + auto const cpu = node.get_attribute_int(ATTR_WINDOW_DISASSEMBLY_CPU, m_dasmView->sourceIndex()); + if ((0 <= cpu) && (m_cpuComboBox->count() > cpu)) + m_cpuComboBox->setCurrentIndex(cpu); + + auto const rightbar = node.get_attribute_int(ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN, dasmview.right_column()); + QActionGroup *const rightBarGroup = findChild("rightbargroup"); + for (QAction *action : rightBarGroup->actions()) + { + if (action->data().toInt() == rightbar) + { + action->trigger(); + break; + } + } + + util::xml::data_node const *const expression = node.get_child(NODE_WINDOW_EXPRESSION); + if (expression && expression->get_value()) + { + m_inputEdit->setText(QString::fromUtf8(expression->get_value())); + expressionSubmitted(); + } + + m_dasmView->restoreConfigurationFromNode(node); + m_inputHistory.restoreConfigurationFromNode(node); +} + + void DasmWindow::saveConfigurationToNode(util::xml::data_node &node) { WindowQt::saveConfigurationToNode(node); @@ -134,6 +171,53 @@ void DasmWindow::saveConfigurationToNode(util::xml::data_node &node) node.set_attribute_int(ATTR_WINDOW_DISASSEMBLY_CPU, m_dasmView->sourceIndex()); node.set_attribute_int(ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN, dasmview.right_column()); node.add_child(NODE_WINDOW_EXPRESSION, dasmview.expression()); + + m_dasmView->saveConfigurationToNode(node); + m_inputHistory.saveConfigurationToNode(node); +} + + +// Used to intercept the user hitting the up arrow in the input widget +bool DasmWindow::eventFilter(QObject *obj, QEvent *event) +{ + // Only filter keypresses + if (event->type() != QEvent::KeyPress) + return QObject::eventFilter(obj, event); + + QKeyEvent const &keyEvent = *static_cast(event); + + // Catch up & down keys + if (keyEvent.key() == Qt::Key_Escape) + { + m_inputEdit->setText(QString::fromUtf8(m_dasmView->view()->expression())); + m_inputEdit->selectAll(); + m_inputHistory.reset(); + return true; + } + else if (keyEvent.key() == Qt::Key_Up) + { + QString const *const hist = m_inputHistory.previous(m_inputEdit->text()); + if (hist) + { + m_inputEdit->setText(*hist); + m_inputEdit->setSelection(hist->size(), 0); + } + return true; + } + else if (keyEvent.key() == Qt::Key_Down) + { + QString const *const hist = m_inputHistory.next(m_inputEdit->text()); + if (hist) + { + m_inputEdit->setText(*hist); + m_inputEdit->setSelection(hist->size(), 0); + } + return true; + } + else + { + return QObject::eventFilter(obj, event); + } } @@ -150,8 +234,18 @@ void DasmWindow::cpuChanged(int index) void DasmWindow::expressionSubmitted() { const QString expression = m_inputEdit->text(); - m_dasmView->view()->set_expression(expression.toLocal8Bit().data()); - m_dasmView->viewport()->update(); + m_dasmView->view()->set_expression(expression.toUtf8().data()); + m_inputEdit->selectAll(); + + // Add history + if (!expression.isEmpty()) + m_inputHistory.add(expression); +} + + +void DasmWindow::expressionEdited(QString const &text) +{ + m_inputHistory.edit(); } @@ -181,8 +275,6 @@ void DasmWindow::toggleBreakpointAtCursor(bool changedTo) m_machine.debug_view().update_all(); m_machine.debugger().refresh_display(); } - - refreshAll(); } @@ -205,8 +297,6 @@ void DasmWindow::enableBreakpointAtCursor(bool changedTo) m_machine.debugger().refresh_display(); } } - - refreshAll(); } @@ -284,34 +374,4 @@ void DasmWindow::setToCurrentCpu() } } - -//========================================================================= -// DasmWindowQtConfig -//========================================================================= - -void DasmWindowQtConfig::applyToQWidget(QWidget *widget) -{ - WindowQtConfig::applyToQWidget(widget); - DasmWindow *window = dynamic_cast(widget); - QComboBox *cpu = window->findChild("cpu"); - cpu->setCurrentIndex(m_cpu); - - QActionGroup *const rightBarGroup = window->findChild("rightbargroup"); - for (QAction *action : rightBarGroup->actions()) - { - if (action->data().toInt() == m_rightBar) - { - action->trigger(); - break; - } - } -} - -void DasmWindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node) -{ - WindowQtConfig::recoverFromXmlNode(node); - m_cpu = node.get_attribute_int(ATTR_WINDOW_DISASSEMBLY_CPU, m_cpu); - m_rightBar = node.get_attribute_int(ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN, m_rightBar); -} - } // namespace osd::debugger::qt diff --git a/src/osd/modules/debugger/qt/dasmwindow.h b/src/osd/modules/debugger/qt/dasmwindow.h index fda4db188a3..df3fc0699a8 100644 --- a/src/osd/modules/debugger/qt/dasmwindow.h +++ b/src/osd/modules/debugger/qt/dasmwindow.h @@ -22,15 +22,21 @@ class DasmWindow : public WindowQt Q_OBJECT public: - DasmWindow(running_machine &machine, QWidget *parent = nullptr); + DasmWindow(DebuggerQt &debugger, QWidget *parent = nullptr); virtual ~DasmWindow(); + virtual void restoreConfiguration(util::xml::data_node const &node) override; + protected: virtual void saveConfigurationToNode(util::xml::data_node &node) override; + // Used to intercept the user hitting the up arrow in the input widget + virtual bool eventFilter(QObject *obj, QEvent *event) override; + private slots: void cpuChanged(int index); void expressionSubmitted(); + void expressionEdited(QString const &text); void toggleBreakpointAtCursor(bool changedTo); void enableBreakpointAtCursor(bool changedTo); @@ -52,30 +58,9 @@ private: QAction *m_breakpointToggleAct; QAction *m_breakpointEnableAct; QAction *m_runToCursorAct; -}; - - -//========================================================================= -// A way to store the configuration of a window long enough to read/write. -//========================================================================= -class DasmWindowQtConfig : public WindowQtConfig -{ -public: - DasmWindowQtConfig() : - WindowQtConfig(WINDOW_TYPE_DISASSEMBLY_VIEWER), - m_cpu(0), - m_rightBar(0) - { - } - - ~DasmWindowQtConfig() {} - - // Settings - int m_cpu; - int m_rightBar; - void applyToQWidget(QWidget *widget); - void recoverFromXmlNode(util::xml::data_node const &node); + // Expression history + CommandHistory m_inputHistory; }; } // namespace osd::debugger::qt diff --git a/src/osd/modules/debugger/qt/debuggerview.cpp b/src/osd/modules/debugger/qt/debuggerview.cpp index 3d89670c3af..e50659fcf3a 100644 --- a/src/osd/modules/debugger/qt/debuggerview.cpp +++ b/src/osd/modules/debugger/qt/debuggerview.cpp @@ -3,8 +3,12 @@ #include "emu.h" #include "debuggerview.h" +#include "../xmlconfig.h" + #include "modules/lib/osdobj_common.h" +#include "xmlfile.h" + #include #include #include @@ -190,9 +194,43 @@ void DebuggerView::paintEvent(QPaintEvent *event) } } + +void DebuggerView::restoreConfigurationFromNode(util::xml::data_node const &node) +{ + if (m_view->cursor_supported()) + { + util::xml::data_node const *const selection = node.get_child(NODE_WINDOW_SELECTION); + if (selection) + { + debug_view_xy pos = m_view->cursor_position(); + m_view->set_cursor_visible(0 != selection->get_attribute_int(ATTR_SELECTION_CURSOR_VISIBLE, m_view->cursor_visible() ? 1 : 0)); + selection->get_attribute_int(ATTR_SELECTION_CURSOR_X, pos.x); + selection->get_attribute_int(ATTR_SELECTION_CURSOR_Y, pos.y); + m_view->set_cursor_position(pos); + } + } +} + + +void DebuggerView::saveConfigurationToNode(util::xml::data_node &node) +{ + if (m_view->cursor_supported()) + { + util::xml::data_node *const selection = node.add_child(NODE_WINDOW_SELECTION, nullptr); + if (selection) + { + debug_view_xy const pos = m_view->cursor_position(); + selection->set_attribute_int(ATTR_SELECTION_CURSOR_VISIBLE, m_view->cursor_visible() ? 1 : 0); + selection->set_attribute_int(ATTR_SELECTION_CURSOR_X, pos.x); + selection->set_attribute_int(ATTR_SELECTION_CURSOR_Y, pos.y); + } + } +} + + void DebuggerView::keyPressEvent(QKeyEvent* event) { - if (m_view == nullptr) + if (!m_view) return QWidget::keyPressEvent(event); Qt::KeyboardModifiers keyMods = QApplication::keyboardModifiers(); diff --git a/src/osd/modules/debugger/qt/debuggerview.h b/src/osd/modules/debugger/qt/debuggerview.h index 6a78ec7d672..f62c9de877a 100644 --- a/src/osd/modules/debugger/qt/debuggerview.h +++ b/src/osd/modules/debugger/qt/debuggerview.h @@ -29,6 +29,9 @@ public: template T *view() { return downcast(m_view); } int sourceIndex() const; + virtual void restoreConfigurationFromNode(util::xml::data_node const &node); + virtual void saveConfigurationToNode(util::xml::data_node &node); + signals: void updated(); diff --git a/src/osd/modules/debugger/qt/deviceinformationwindow.cpp b/src/osd/modules/debugger/qt/deviceinformationwindow.cpp index 83fad49e418..2e06d8fb1ed 100644 --- a/src/osd/modules/debugger/qt/deviceinformationwindow.cpp +++ b/src/osd/modules/debugger/qt/deviceinformationwindow.cpp @@ -12,8 +12,8 @@ namespace osd::debugger::qt { -DeviceInformationWindow::DeviceInformationWindow(running_machine &machine, device_t *device, QWidget *parent) : - WindowQt(machine, nullptr), +DeviceInformationWindow::DeviceInformationWindow(DebuggerQt &debugger, device_t *device, QWidget *parent) : + WindowQt(debugger, nullptr), m_device(device) { if (parent) @@ -32,6 +32,15 @@ DeviceInformationWindow::~DeviceInformationWindow() } +void DeviceInformationWindow::restoreConfiguration(util::xml::data_node const &node) +{ + WindowQt::restoreConfiguration(node); + + auto const tag = node.get_attribute_string(ATTR_WINDOW_DEVICE_TAG, ":"); + set_device(tag); +} + + void DeviceInformationWindow::saveConfigurationToNode(util::xml::data_node &node) { WindowQt::saveConfigurationToNode(node); @@ -114,23 +123,4 @@ void DeviceInformationWindow::set_device(const char *tag) fill_device_information(); } - -//========================================================================= -// DeviceInformationWindowQtConfig -//========================================================================= - -void DeviceInformationWindowQtConfig::applyToQWidget(QWidget *widget) -{ - WindowQtConfig::applyToQWidget(widget); - DeviceInformationWindow *window = dynamic_cast(widget); - window->set_device(m_device_tag.c_str()); -} - - -void DeviceInformationWindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node) -{ - WindowQtConfig::recoverFromXmlNode(node); - m_device_tag = node.get_attribute_string(ATTR_WINDOW_DEVICE_TAG, ":"); -} - } // namespace osd::debugger::qt diff --git a/src/osd/modules/debugger/qt/deviceinformationwindow.h b/src/osd/modules/debugger/qt/deviceinformationwindow.h index 68ab910fe48..e036a76e782 100644 --- a/src/osd/modules/debugger/qt/deviceinformationwindow.h +++ b/src/osd/modules/debugger/qt/deviceinformationwindow.h @@ -18,11 +18,13 @@ class DeviceInformationWindow : public WindowQt Q_OBJECT public: - DeviceInformationWindow(running_machine &machine, device_t *device = nullptr, QWidget* parent=nullptr); + DeviceInformationWindow(DebuggerQt &debugger, device_t *device = nullptr, QWidget* parent=nullptr); virtual ~DeviceInformationWindow(); void set_device(const char *tag); + virtual void restoreConfiguration(util::xml::data_node const &node) override; + protected: virtual void saveConfigurationToNode(util::xml::data_node &node) override; @@ -32,28 +34,6 @@ private: void fill_device_information(); }; - - - -//========================================================================= -// A way to store the configuration of a window long enough to read/write. -//========================================================================= -class DeviceInformationWindowQtConfig : public WindowQtConfig -{ -public: - std::string m_device_tag; - - DeviceInformationWindowQtConfig() : - WindowQtConfig(WINDOW_TYPE_DEVICE_INFO_VIEWER) - { - } - - ~DeviceInformationWindowQtConfig() {} - - void applyToQWidget(QWidget *widget); - void recoverFromXmlNode(util::xml::data_node const &node); -}; - } // namespace osd::debugger::qt #endif // MAME_DEBUGGER_QT_DEVICEINFORMATIONWINDOW_H diff --git a/src/osd/modules/debugger/qt/deviceswindow.cpp b/src/osd/modules/debugger/qt/deviceswindow.cpp index 8d51ecccf01..2c39c8cb0e8 100644 --- a/src/osd/modules/debugger/qt/deviceswindow.cpp +++ b/src/osd/modules/debugger/qt/deviceswindow.cpp @@ -113,9 +113,9 @@ int DevicesWindowModel::columnCount(const QModelIndex &parent) const -DevicesWindow::DevicesWindow(running_machine &machine, QWidget *parent) : - WindowQt(machine, nullptr), - m_devices_model(machine) +DevicesWindow::DevicesWindow(DebuggerQt &debugger, QWidget *parent) : + WindowQt(debugger, nullptr), + m_devices_model(debugger.machine()) { m_selected_device = nullptr; @@ -154,7 +154,7 @@ void DevicesWindow::currentRowChanged(const QModelIndex ¤t, const QModelIn void DevicesWindow::activated(const QModelIndex &index) { device_t *dev = static_cast(index.internalPointer()); - (new DeviceInformationWindow(m_machine, dev, this))->show(); + (new DeviceInformationWindow(m_debugger, dev, this))->show(); } @@ -165,22 +165,4 @@ void DevicesWindow::saveConfigurationToNode(util::xml::data_node &node) node.set_attribute_int(ATTR_WINDOW_TYPE, WINDOW_TYPE_DEVICES_VIEWER); } - - -//========================================================================= -// DevicesWindowQtConfig -//========================================================================= - -void DevicesWindowQtConfig::applyToQWidget(QWidget *widget) -{ - WindowQtConfig::applyToQWidget(widget); - // DevicesWindow *window = dynamic_cast(widget); -} - - -void DevicesWindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node) -{ - WindowQtConfig::recoverFromXmlNode(node); -} - } // namespace osd::debugger::qt diff --git a/src/osd/modules/debugger/qt/deviceswindow.h b/src/osd/modules/debugger/qt/deviceswindow.h index 8fe5b7a82c2..d337817fac0 100644 --- a/src/osd/modules/debugger/qt/deviceswindow.h +++ b/src/osd/modules/debugger/qt/deviceswindow.h @@ -44,7 +44,7 @@ class DevicesWindow : public WindowQt Q_OBJECT public: - DevicesWindow(running_machine &machine, QWidget *parent = nullptr); + DevicesWindow(DebuggerQt &debugger, QWidget *parent = nullptr); virtual ~DevicesWindow(); public slots: @@ -60,28 +60,6 @@ private: device_t *m_selected_device; }; - - - -//========================================================================= -// A way to store the configuration of a window long enough to read/write. -//========================================================================= -class DevicesWindowQtConfig : public WindowQtConfig -{ -public: - DevicesWindowQtConfig() : - WindowQtConfig(WINDOW_TYPE_DEVICES_VIEWER) - { - } - - ~DevicesWindowQtConfig() {} - - void buildFromQWidget(QWidget *widget); - void applyToQWidget(QWidget *widget); - void addToXmlDataNode(util::xml::data_node &node) const; - void recoverFromXmlNode(util::xml::data_node const &node); -}; - } // namespace osd::debugger::qt #endif // MAME_DEBUGGER_QT_DEVICESWINDOW_H diff --git a/src/osd/modules/debugger/qt/logwindow.cpp b/src/osd/modules/debugger/qt/logwindow.cpp index 669d25081d6..dfbe947caca 100644 --- a/src/osd/modules/debugger/qt/logwindow.cpp +++ b/src/osd/modules/debugger/qt/logwindow.cpp @@ -14,8 +14,8 @@ namespace osd::debugger::qt { -LogWindow::LogWindow(running_machine &machine, QWidget *parent) : - WindowQt(machine, nullptr) +LogWindow::LogWindow(DebuggerQt &debugger, QWidget *parent) : + WindowQt(debugger, nullptr) { setWindowTitle("Debug: Machine Log"); @@ -48,27 +48,21 @@ LogWindow::~LogWindow() } -void LogWindow::saveConfigurationToNode(util::xml::data_node &node) +void LogWindow::restoreConfiguration(util::xml::data_node const &node) { - WindowQt::saveConfigurationToNode(node); + WindowQt::restoreConfiguration(node); - node.set_attribute_int(ATTR_WINDOW_TYPE, WINDOW_TYPE_ERROR_LOG_VIEWER); + m_logView->restoreConfigurationFromNode(node); } -//========================================================================= -// LogWindowQtConfig -//========================================================================= - -void LogWindowQtConfig::applyToQWidget(QWidget *widget) +void LogWindow::saveConfigurationToNode(util::xml::data_node &node) { - WindowQtConfig::applyToQWidget(widget); -} + WindowQt::saveConfigurationToNode(node); + node.set_attribute_int(ATTR_WINDOW_TYPE, WINDOW_TYPE_ERROR_LOG_VIEWER); -void LogWindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node) -{ - WindowQtConfig::recoverFromXmlNode(node); + m_logView->saveConfigurationToNode(node); } } // namespace osd::debugger::qt diff --git a/src/osd/modules/debugger/qt/logwindow.h b/src/osd/modules/debugger/qt/logwindow.h index 813add22749..f85d490ea75 100644 --- a/src/osd/modules/debugger/qt/logwindow.h +++ b/src/osd/modules/debugger/qt/logwindow.h @@ -19,9 +19,11 @@ class LogWindow : public WindowQt Q_OBJECT public: - LogWindow(running_machine &machine, QWidget *parent = nullptr); + LogWindow(DebuggerQt &debugger, QWidget *parent = nullptr); virtual ~LogWindow(); + virtual void restoreConfiguration(util::xml::data_node const &node) override; + protected: virtual void saveConfigurationToNode(util::xml::data_node &node) override; @@ -30,24 +32,6 @@ private: DebuggerView *m_logView; }; - -//========================================================================= -// A way to store the configuration of a window long enough to read/write. -//========================================================================= -class LogWindowQtConfig : public WindowQtConfig -{ -public: - LogWindowQtConfig() : - WindowQtConfig(WINDOW_TYPE_ERROR_LOG_VIEWER) - { - } - - ~LogWindowQtConfig() {} - - void applyToQWidget(QWidget *widget); - void recoverFromXmlNode(util::xml::data_node const &node); -}; - } // namespace osd::debugger::qt #endif // MAME_DEBUGGER_QT_LOGWINDOW_H diff --git a/src/osd/modules/debugger/qt/mainwindow.cpp b/src/osd/modules/debugger/qt/mainwindow.cpp index a418a543ace..92be2c04b31 100644 --- a/src/osd/modules/debugger/qt/mainwindow.cpp +++ b/src/osd/modules/debugger/qt/mainwindow.cpp @@ -21,9 +21,8 @@ namespace osd::debugger::qt { -MainWindow::MainWindow(running_machine &machine, QWidget *parent) : - WindowQt(machine, nullptr), - m_historyIndex(0), +MainWindow::MainWindow(DebuggerQt &debugger, QWidget *parent) : + WindowQt(debugger, nullptr), m_inputHistory(), m_exiting(false) { @@ -37,6 +36,7 @@ MainWindow::MainWindow(running_machine &machine, QWidget *parent) : // The input line m_inputEdit = new QLineEdit(mainWindowFrame); connect(m_inputEdit, &QLineEdit::returnPressed, this, &MainWindow::executeCommandSlot); + connect(m_inputEdit, &QLineEdit::textEdited, this, &MainWindow::commandEditedSlot); m_inputEdit->installEventFilter(this); @@ -154,6 +154,30 @@ void MainWindow::setProcessor(device_t *processor) } +void MainWindow::restoreConfiguration(util::xml::data_node const &node) +{ + WindowQt::restoreConfiguration(node); + + debug_view_disasm &dasmview = *m_dasmFrame->view()->view(); + + restoreState(QByteArray::fromPercentEncoding(node.get_attribute_string("qtwindowstate", ""))); + + auto const rightbar = node.get_attribute_int(ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN, dasmview.right_column()); + QActionGroup *const rightBarGroup = findChild("rightbargroup"); + for (QAction *action : rightBarGroup->actions()) + { + if (action->data().toInt() == rightbar) + { + action->trigger(); + break; + } + } + + m_dasmFrame->view()->restoreConfigurationFromNode(node); + m_inputHistory.restoreConfigurationFromNode(node); +} + + void MainWindow::saveConfigurationToNode(util::xml::data_node &node) { WindowQt::saveConfigurationToNode(node); @@ -163,6 +187,9 @@ void MainWindow::saveConfigurationToNode(util::xml::data_node &node) debug_view_disasm &dasmview = *m_dasmFrame->view()->view(); node.set_attribute_int(ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN, dasmview.right_column()); node.set_attribute("qtwindowstate", saveState().toPercentEncoding().data()); + + m_dasmFrame->view()->saveConfigurationToNode(node); + m_inputHistory.saveConfigurationToNode(node); } @@ -182,46 +209,47 @@ void MainWindow::closeEvent(QCloseEvent *event) bool MainWindow::eventFilter(QObject *obj, QEvent *event) { // Only filter keypresses - QKeyEvent *keyEvent = nullptr; - if (event->type() == QEvent::KeyPress) - keyEvent = static_cast(event); - else + if (event->type() != QEvent::KeyPress) return QObject::eventFilter(obj, event); + QKeyEvent const &keyEvent = *static_cast(event); + // Catch up & down keys - if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down) + if (keyEvent.key() == Qt::Key_Escape) { - if (keyEvent->key() == Qt::Key_Up) - { - if (m_historyIndex > 0) - m_historyIndex--; - } - else if (keyEvent->key() == Qt::Key_Down) - { - if (m_historyIndex < m_inputHistory.size()) - m_historyIndex++; - } - - // Populate the input edit or clear it if you're at the end - if (m_historyIndex == m_inputHistory.size()) + m_inputEdit->clear(); + m_inputHistory.reset(); + return true; + } + else if (keyEvent.key() == Qt::Key_Up) + { + QString const *const hist = m_inputHistory.previous(m_inputEdit->text()); + if (hist) { - m_inputEdit->setText(""); + m_inputEdit->setText(*hist); + m_inputEdit->setSelection(hist->size(), 0); } - else + return true; + } + else if (keyEvent.key() == Qt::Key_Down) + { + QString const *const hist = m_inputHistory.next(m_inputEdit->text()); + if (hist) { - m_inputEdit->setText(m_inputHistory[m_historyIndex]); + m_inputEdit->setText(*hist); + m_inputEdit->setSelection(hist->size(), 0); } + return true; } - else if (keyEvent->key() == Qt::Key_Enter) + else if (keyEvent.key() == Qt::Key_Enter) { executeCommand(false); + return true; } else { return QObject::eventFilter(obj, event); } - - return true; } @@ -243,9 +271,9 @@ void MainWindow::toggleBreakpointAtCursor(bool changedTo) else command = string_format("bpclear 0x%X", bp->index()); m_machine.debugger().console().execute_command(command, true); + m_machine.debug_view().update_all(); + m_machine.debugger().refresh_display(); } - - refreshAll(); } @@ -265,10 +293,10 @@ void MainWindow::enableBreakpointAtCursor(bool changedTo) int32_t const bpindex = bp->index(); std::string command = string_format(bp->enabled() ? "bpdisable 0x%X" : "bpenable 0x%X", bpindex); m_machine.debugger().console().execute_command(command, true); + m_machine.debug_view().update_all(); + m_machine.debugger().refresh_display(); } } - - refreshAll(); } @@ -296,33 +324,35 @@ void MainWindow::executeCommandSlot() executeCommand(true); } -void MainWindow::executeCommand(bool withClear) +void MainWindow::commandEditedSlot(QString const &text) { - QString command = m_inputEdit->text(); + m_inputHistory.edit(); +} - // A blank command is a "silent step" +void MainWindow::executeCommand(bool withClear) +{ + QString const command = m_inputEdit->text(); if (command == "") { + // A blank command is a "silent step" m_machine.debugger().console().get_visible_cpu()->debug()->single_step(); - return; + m_inputHistory.reset(); } + else + { + // Send along the command + m_machine.debugger().console().execute_command(command.toUtf8().data(), true); - // Send along the command - m_machine.debugger().console().execute_command(command.toLocal8Bit().data(), true); - - // Add history & set the index to be the top of the stack - addToHistory(command); + // Add history + m_inputHistory.add(command); - // Clear out the text and reset the history pointer only if asked - if (withClear) - { - m_inputEdit->clear(); - m_historyIndex = m_inputHistory.size(); + // Clear out the text and reset the history pointer only if asked + if (withClear) + { + m_inputEdit->clear(); + m_inputHistory.edit(); + } } - - // Refresh - m_consoleView->viewport()->update(); - refreshAll(); } @@ -335,7 +365,6 @@ void MainWindow::mountImage(bool changedTo) if (!img) { m_machine.debugger().console().printf("Something is wrong with the mount menu.\n"); - refreshAll(); return; } @@ -349,7 +378,6 @@ void MainWindow::mountImage(bool changedTo) if (img->load(filename.toUtf8().data()) != image_init_result::PASS) { m_machine.debugger().console().printf("Image could not be mounted.\n"); - refreshAll(); return; } @@ -365,7 +393,6 @@ void MainWindow::mountImage(bool changedTo) parentMenuItem->setTitle(newTitle); m_machine.debugger().console().printf("Image %s mounted successfully.\n", filename.toUtf8().data()); - refreshAll(); } @@ -389,7 +416,6 @@ void MainWindow::unmountImage(bool changedTo) parentMenuItem->setTitle(newTitle); m_machine.debugger().console().printf("Image successfully unmounted.\n"); - refreshAll(); } @@ -429,21 +455,10 @@ void MainWindow::debugActClose() } -void MainWindow::addToHistory(const QString& command) +void MainWindow::debuggerExit() { - if (command == "") - return; - - // Always push back when there is no previous history - if (m_inputHistory.empty()) - { - m_inputHistory.push_back(m_inputEdit->text()); - return; - } - - // If there is previous history, make sure it's not what you just executed - if (m_inputHistory.back() != m_inputEdit->text()) - m_inputHistory.push_back(m_inputEdit->text()); + m_exiting = true; + close(); } @@ -481,35 +496,6 @@ void MainWindow::createImagesMenu() } -//========================================================================= -// MainWindowQtConfig -//========================================================================= -void MainWindowQtConfig::applyToQWidget(QWidget *widget) -{ - WindowQtConfig::applyToQWidget(widget); - MainWindow *window = dynamic_cast(widget); - window->restoreState(m_windowState); - - QActionGroup *const rightBarGroup = window->findChild("rightbargroup"); - for (QAction *action : rightBarGroup->actions()) - { - if (action->data().toInt() == m_rightBar) - { - action->trigger(); - break; - } - } -} - - -void MainWindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node) -{ - WindowQtConfig::recoverFromXmlNode(node); - const char* state = node.get_attribute_string("qtwindowstate", ""); - m_windowState = QByteArray::fromPercentEncoding(state); - m_rightBar = node.get_attribute_int(ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN, m_rightBar); -} - DasmDockWidget::~DasmDockWidget() { } diff --git a/src/osd/modules/debugger/qt/mainwindow.h b/src/osd/modules/debugger/qt/mainwindow.h index 919c016704c..762874b6aee 100644 --- a/src/osd/modules/debugger/qt/mainwindow.h +++ b/src/osd/modules/debugger/qt/mainwindow.h @@ -14,7 +14,7 @@ #include #include -#include +#include namespace osd::debugger::qt { @@ -31,21 +31,21 @@ class MainWindow : public WindowQt Q_OBJECT public: - MainWindow(running_machine &machine, QWidget *parent = nullptr); + MainWindow(DebuggerQt &debugger, QWidget *parent = nullptr); virtual ~MainWindow(); void setProcessor(device_t *processor); - void setExiting() { m_exiting = true; } + virtual void restoreConfiguration(util::xml::data_node const &node) override; protected: virtual void saveConfigurationToNode(util::xml::data_node &node) override; // Used to intercept the user clicking 'X' in the upper corner - void closeEvent(QCloseEvent *event); + virtual void closeEvent(QCloseEvent *event) override; // Used to intercept the user hitting the up arrow in the input widget - bool eventFilter(QObject *obj, QEvent *event); + virtual bool eventFilter(QObject *obj, QEvent *event) override; private slots: void toggleBreakpointAtCursor(bool changedTo); @@ -54,6 +54,7 @@ private slots: void rightBarChanged(QAction *changedTo); void executeCommandSlot(); + void commandEditedSlot(QString const &text); void mountImage(bool changedTo); void unmountImage(bool changedTo); @@ -61,12 +62,12 @@ private slots: void dasmViewUpdated(); // Closing the main window hides the debugger and runs the emulated system - void debugActClose(); + virtual void debugActClose() override; + virtual void debuggerExit() override; private: void createImagesMenu(); - void addToHistory(const QString& command); void executeCommand(bool withClear); // Widgets and docks @@ -81,8 +82,7 @@ private: QAction *m_runToCursorAct; // Terminal history - int m_historyIndex; - std::vector m_inputHistory; + CommandHistory m_inputHistory; bool m_exiting; }; @@ -158,29 +158,6 @@ private: DebuggerView *m_processorView; }; - -//========================================================================= -// A way to store the configuration of a window long enough to read/write. -//========================================================================= -class MainWindowQtConfig : public WindowQtConfig -{ -public: - MainWindowQtConfig() : - WindowQtConfig(WINDOW_TYPE_CONSOLE), - m_rightBar(0), - m_windowState() - {} - - ~MainWindowQtConfig() {} - - // Settings - int m_rightBar; - QByteArray m_windowState; - - void applyToQWidget(QWidget *widget); - void recoverFromXmlNode(util::xml::data_node const &node); -}; - } // namespace osd::debugger::qt #endif // MAME_DEBUGGER_QT_MAINWINDOW_H diff --git a/src/osd/modules/debugger/qt/memorywindow.cpp b/src/osd/modules/debugger/qt/memorywindow.cpp index 0aed1a750ce..25e38e6ab99 100644 --- a/src/osd/modules/debugger/qt/memorywindow.cpp +++ b/src/osd/modules/debugger/qt/memorywindow.cpp @@ -10,6 +10,7 @@ #include "util/xmlfile.h" #include +#include #include #include #include @@ -27,8 +28,9 @@ namespace osd::debugger::qt { -MemoryWindow::MemoryWindow(running_machine &machine, QWidget *parent) : - WindowQt(machine, nullptr) +MemoryWindow::MemoryWindow(DebuggerQt &debugger, QWidget *parent) : + WindowQt(debugger, nullptr), + m_inputHistory() { setWindowTitle("Debug: Memory View"); @@ -49,6 +51,8 @@ MemoryWindow::MemoryWindow(running_machine &machine, QWidget *parent) : // The input edit m_inputEdit = new QLineEdit(topSubFrame); connect(m_inputEdit, &QLineEdit::returnPressed, this, &MemoryWindow::expressionSubmitted); + connect(m_inputEdit, &QLineEdit::textEdited, this, &MemoryWindow::expressionEdited); + m_inputEdit->installEventFilter(this); // The memory space combo box m_memoryComboBox = new QComboBox(topSubFrame); @@ -219,6 +223,71 @@ MemoryWindow::~MemoryWindow() } +void MemoryWindow::restoreConfiguration(util::xml::data_node const &node) +{ + WindowQt::restoreConfiguration(node); + + debug_view_memory &memView = *m_memTable->view(); + + auto const region = node.get_attribute_int(ATTR_WINDOW_MEMORY_REGION, m_memTable->sourceIndex()); + if ((0 <= region) && (m_memoryComboBox->count() > region)) + m_memoryComboBox->setCurrentIndex(region); + + auto const reverse = node.get_attribute_int(ATTR_WINDOW_MEMORY_REVERSE_COLUMNS, memView.reverse() ? 1 : 0); + if (memView.reverse() != bool(reverse)) + { + memView.set_reverse(bool(reverse)); + findChild("reverse")->setChecked(bool(reverse)); + } + + auto const mode = node.get_attribute_int(ATTR_WINDOW_MEMORY_ADDRESS_MODE, memView.physical() ? 1 : 0); + QActionGroup *const addressGroup = findChild("addressgroup"); + for (QAction *action : addressGroup->actions()) + { + if (action->data().toBool() == mode) + { + action->trigger(); + break; + } + } + + auto const radix = node.get_attribute_int(ATTR_WINDOW_MEMORY_ADDRESS_RADIX, memView.address_radix()); + QActionGroup *const radixGroup = findChild("radixgroup"); + for (QAction *action : radixGroup->actions()) + { + if (action->data().toInt() == radix) + { + action->trigger(); + break; + } + } + + auto const format = node.get_attribute_int(ATTR_WINDOW_MEMORY_DATA_FORMAT, int(memView.get_data_format())); + QActionGroup *const dataFormat = findChild("dataformat"); + for (QAction *action : dataFormat->actions()) + { + if (action->data().toInt() == format) + { + action->trigger(); + break; + } + } + + auto const chunks = node.get_attribute_int(ATTR_WINDOW_MEMORY_ROW_CHUNKS, memView.chunks_per_row()); + memView.set_chunks_per_row(chunks); + + util::xml::data_node const *const expression = node.get_child(NODE_WINDOW_EXPRESSION); + if (expression && expression->get_value()) + { + m_inputEdit->setText(QString::fromUtf8(expression->get_value())); + expressionSubmitted(); + } + + m_memTable->restoreConfigurationFromNode(node); + m_inputHistory.restoreConfigurationFromNode(node); +} + + void MemoryWindow::saveConfigurationToNode(util::xml::data_node &node) { WindowQt::saveConfigurationToNode(node); @@ -233,6 +302,9 @@ void MemoryWindow::saveConfigurationToNode(util::xml::data_node &node) node.set_attribute_int(ATTR_WINDOW_MEMORY_DATA_FORMAT, int(memView.get_data_format())); node.set_attribute_int(ATTR_WINDOW_MEMORY_ROW_CHUNKS, memView.chunks_per_row()); node.add_child(NODE_WINDOW_EXPRESSION, memView.expression()); + + m_memTable->saveConfigurationToNode(node); + m_inputHistory.saveConfigurationToNode(node); } @@ -256,7 +328,7 @@ void MemoryWindow::memoryRegionChanged(int index) } } - QActionGroup *radixGroup = findChild("radixgroup"); + QActionGroup *radixGroup = findChild("radixgroup"); for (QAction *action : radixGroup->actions()) { if (action->data().toInt() == memView->address_radix()) @@ -269,21 +341,65 @@ void MemoryWindow::memoryRegionChanged(int index) } +// Used to intercept the user hitting the up arrow in the input widget +bool MemoryWindow::eventFilter(QObject *obj, QEvent *event) +{ + // Only filter keypresses + if (event->type() != QEvent::KeyPress) + return QObject::eventFilter(obj, event); + + QKeyEvent const &keyEvent = *static_cast(event); + + // Catch up & down keys + if (keyEvent.key() == Qt::Key_Escape) + { + m_inputEdit->setText(QString::fromUtf8(m_memTable->view()->expression())); + m_inputEdit->selectAll(); + m_inputHistory.reset(); + return true; + } + else if (keyEvent.key() == Qt::Key_Up) + { + QString const *const hist = m_inputHistory.previous(m_inputEdit->text()); + if (hist) + { + m_inputEdit->setText(*hist); + m_inputEdit->setSelection(hist->size(), 0); + } + return true; + } + else if (keyEvent.key() == Qt::Key_Down) + { + QString const *const hist = m_inputHistory.next(m_inputEdit->text()); + if (hist) + { + m_inputEdit->setText(*hist); + m_inputEdit->setSelection(hist->size(), 0); + } + return true; + } + else + { + return QObject::eventFilter(obj, event); + } +} + + void MemoryWindow::expressionSubmitted() { const QString expression = m_inputEdit->text(); - m_memTable->view()->set_expression(expression.toLocal8Bit().data()); + m_memTable->view()->set_expression(expression.toUtf8().data()); + m_inputEdit->selectAll(); - // Make the cursor pop - m_memTable->view()->set_cursor_visible(true); + // Add history + if (!expression.isEmpty()) + m_inputHistory.add(expression); +} - // Check where the cursor is and adjust the scroll accordingly - debug_view_xy cursorPosition = m_memTable->view()->cursor_position(); - // TODO: check if the region is already visible? - m_memTable->verticalScrollBar()->setValue(cursorPosition.y); - m_memTable->update(); - m_memTable->viewport()->update(); +void MemoryWindow::expressionEdited(QString const &text) +{ + m_inputHistory.edit(); } @@ -430,62 +546,4 @@ void DebuggerMemView::copyLastPc() QApplication::clipboard()->setText(m_lastPc); } - -//========================================================================= -// MemoryWindowQtConfig -//========================================================================= - -void MemoryWindowQtConfig::applyToQWidget(QWidget *widget) -{ - WindowQtConfig::applyToQWidget(widget); - MemoryWindow *window = dynamic_cast(widget); - QComboBox *memoryRegion = window->findChild("memoryregion"); - memoryRegion->setCurrentIndex(m_memoryRegion); - - QAction *reverse = window->findChild("reverse"); - if (m_reverse) - reverse->trigger(); - - QActionGroup *const addressGroup = window->findChild("addressgroup"); - for (QAction *action : addressGroup->actions()) - { - if (action->data().toBool() == m_addressMode) - { - action->trigger(); - break; - } - } - - QActionGroup *const radixGroup = window->findChild("radixgroup"); - for (QAction *action : radixGroup->actions()) - { - if (action->data().toInt() == m_addressRadix) - { - action->trigger(); - break; - } - } - - QActionGroup *const dataFormat = window->findChild("dataformat"); - for (QAction *action : dataFormat->actions()) - { - if (action->data().toInt() == m_dataFormat) - { - action->trigger(); - break; - } - } -} - - -void MemoryWindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node) -{ - WindowQtConfig::recoverFromXmlNode(node); - m_memoryRegion = node.get_attribute_int(ATTR_WINDOW_MEMORY_REGION, m_memoryRegion); - m_reverse = node.get_attribute_int(ATTR_WINDOW_MEMORY_REVERSE_COLUMNS, m_reverse); - m_addressMode = node.get_attribute_int(ATTR_WINDOW_MEMORY_ADDRESS_MODE, m_addressMode); - m_addressRadix = node.get_attribute_int(ATTR_WINDOW_MEMORY_ADDRESS_RADIX, m_addressRadix); - m_dataFormat = node.get_attribute_int(ATTR_WINDOW_MEMORY_DATA_FORMAT, m_dataFormat); -} - } // namespace osd::debugger::qt diff --git a/src/osd/modules/debugger/qt/memorywindow.h b/src/osd/modules/debugger/qt/memorywindow.h index 131afa3e027..ed5c5b30cb0 100644 --- a/src/osd/modules/debugger/qt/memorywindow.h +++ b/src/osd/modules/debugger/qt/memorywindow.h @@ -25,15 +25,22 @@ class MemoryWindow : public WindowQt Q_OBJECT public: - MemoryWindow(running_machine &machine, QWidget *parent = nullptr); + MemoryWindow(DebuggerQt &debugger, QWidget *parent = nullptr); virtual ~MemoryWindow(); + virtual void restoreConfiguration(util::xml::data_node const &node) override; + protected: virtual void saveConfigurationToNode(util::xml::data_node &node) override; + // Used to intercept the user hitting the up arrow in the input widget + virtual bool eventFilter(QObject *obj, QEvent *event) override; + private slots: void memoryRegionChanged(int index); void expressionSubmitted(); + void expressionEdited(QString const &text); + void formatChanged(QAction *changedTo); void addressChanged(QAction *changedTo); void radixChanged(QAction *changedTo); @@ -49,6 +56,9 @@ private: QLineEdit *m_inputEdit; QComboBox *m_memoryComboBox; DebuggerMemView *m_memTable; + + // Expression history + CommandHistory m_inputHistory; }; @@ -76,36 +86,6 @@ private: QString m_lastPc; }; - -//========================================================================= -// A way to store the configuration of a window long enough to read/write. -//========================================================================= -class MemoryWindowQtConfig : public WindowQtConfig -{ -public: - MemoryWindowQtConfig() : - WindowQtConfig(WINDOW_TYPE_MEMORY_VIEWER), - m_reverse(0), - m_addressMode(0), - m_addressRadix(0), - m_dataFormat(0), - m_memoryRegion(0) - { - } - - ~MemoryWindowQtConfig() {} - - // Settings - int m_reverse; - int m_addressMode; - int m_addressRadix; - int m_dataFormat; - int m_memoryRegion; - - void applyToQWidget(QWidget *widget); - void recoverFromXmlNode(util::xml::data_node const &node); -}; - } // namespace osd::debugger::qt #endif // MAME_DEBUGGER_QT_MEMORYWINDOW_H diff --git a/src/osd/modules/debugger/qt/windowqt.cpp b/src/osd/modules/debugger/qt/windowqt.cpp index 7538f1bc11f..783c5a24393 100644 --- a/src/osd/modules/debugger/qt/windowqt.cpp +++ b/src/osd/modules/debugger/qt/windowqt.cpp @@ -20,21 +20,24 @@ namespace osd::debugger::qt { -bool WindowQt::s_refreshAll = false; -bool WindowQt::s_hideAll = false; - - // Since all debug windows are intended to be top-level, this inherited // constructor is always called with a nullptr parent. The passed-in parent widget, // however, is often used to place each child window & the code to do this can // be found in most of the inherited classes. -WindowQt::WindowQt(running_machine &machine, QWidget *parent) : +WindowQt::WindowQt(DebuggerQt &debugger, QWidget *parent) : QMainWindow(parent), - m_machine(machine) + m_debugger(debugger), + m_machine(debugger.machine()) { setAttribute(Qt::WA_DeleteOnClose, true); + // Subscribe to signals + connect(&debugger, &DebuggerQt::exitDebugger, this, &WindowQt::debuggerExit); + connect(&debugger, &DebuggerQt::hideAllWindows, this, &WindowQt::hide); + connect(&debugger, &DebuggerQt::showAllWindows, this, &WindowQt::show); + connect(&debugger, &DebuggerQt::saveConfiguration, this, &WindowQt::saveConfiguration); + // The Debug menu bar QAction *debugActOpenMemory = new QAction("New &Memory Window", this); debugActOpenMemory->setShortcut(QKeySequence("Ctrl+M")); @@ -133,9 +136,10 @@ WindowQt::~WindowQt() { } + void WindowQt::debugActOpenMemory() { - MemoryWindow *foo = new MemoryWindow(m_machine, this); + MemoryWindow *foo = new MemoryWindow(m_debugger, this); // A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon // foo->setWindowFlags(Qt::Dialog); // foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint); @@ -145,7 +149,7 @@ void WindowQt::debugActOpenMemory() void WindowQt::debugActOpenDasm() { - DasmWindow *foo = new DasmWindow(m_machine, this); + DasmWindow *foo = new DasmWindow(m_debugger, this); // A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon // foo->setWindowFlags(Qt::Dialog); // foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint); @@ -155,7 +159,7 @@ void WindowQt::debugActOpenDasm() void WindowQt::debugActOpenLog() { - LogWindow *foo = new LogWindow(m_machine, this); + LogWindow *foo = new LogWindow(m_debugger, this); // A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon // foo->setWindowFlags(Qt::Dialog); // foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint); @@ -165,7 +169,7 @@ void WindowQt::debugActOpenLog() void WindowQt::debugActOpenPoints() { - BreakpointsWindow *foo = new BreakpointsWindow(m_machine, this); + BreakpointsWindow *foo = new BreakpointsWindow(m_debugger, this); // A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon // foo->setWindowFlags(Qt::Dialog); // foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint); @@ -175,7 +179,7 @@ void WindowQt::debugActOpenPoints() void WindowQt::debugActOpenDevices() { - DevicesWindow *foo = new DevicesWindow(m_machine, this); + DevicesWindow *foo = new DevicesWindow(m_debugger, this); // A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon // foo->setWindowFlags(Qt::Dialog); // foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint); @@ -191,7 +195,7 @@ void WindowQt::debugActRun() void WindowQt::debugActRunAndHide() { m_machine.debugger().console().get_visible_cpu()->debug()->go(); - hideAll(); + m_debugger.hideAll(); } void WindowQt::debugActRunToNextCpu() @@ -245,6 +249,27 @@ void WindowQt::debugActQuit() m_machine.schedule_exit(); } +void WindowQt::debuggerExit() +{ + close(); +} + + +void WindowQt::restoreConfiguration(util::xml::data_node const &node) +{ + QPoint p(geometry().topLeft()); + p.setX(node.get_attribute_int(ATTR_WINDOW_POSITION_X, p.x())); + p.setY(node.get_attribute_int(ATTR_WINDOW_POSITION_Y, p.y())); + + QSize s(size()); + s.setWidth(node.get_attribute_int(ATTR_WINDOW_WIDTH, s.width())); + s.setHeight(node.get_attribute_int(ATTR_WINDOW_HEIGHT, s.height())); + + // TODO: sanity checks, restrict to screen area + + setGeometry(p.x(), p.y(), s.width(), s.height()); +} + void WindowQt::saveConfiguration(util::xml::data_node &parentnode) { @@ -263,23 +288,115 @@ void WindowQt::saveConfigurationToNode(util::xml::data_node &node) } -//========================================================================= -// WindowQtConfig -//========================================================================= +CommandHistory::CommandHistory() : + m_history(), + m_current(), + m_position(-1) +{ +} + + +CommandHistory::~CommandHistory() +{ +} + + +void CommandHistory::add(QString const &entry) +{ + if (m_history.empty() || (m_history.front() != entry)) + { + while (m_history.size() >= CAPACITY) + m_history.pop_back(); + m_history.push_front(entry); + } + m_position = 0; +} + + +QString const *CommandHistory::previous(QString const ¤t) +{ + if ((m_position + 1) < m_history.size()) + { + if (0 > m_position) + m_current = std::make_unique(current); + return &m_history[++m_position]; + } + else + { + return nullptr; + } +} + + +QString const *CommandHistory::next(QString const ¤t) +{ + if (0 < m_position) + { + return &m_history[--m_position]; + } + else if (!m_position && m_current && (m_history.front() != *m_current)) + { + --m_position; + return m_current.get(); + } + else + { + return nullptr; + } +} + + +void CommandHistory::edit() +{ + if (!m_position) + --m_position; +} + + +void CommandHistory::reset() +{ + m_position = -1; + m_current.reset(); +} + + +void CommandHistory::clear() +{ + m_position = -1; + m_current.reset(); + m_history.clear(); +} + -void WindowQtConfig::applyToQWidget(QWidget *widget) +void CommandHistory::restoreConfigurationFromNode(util::xml::data_node const &node) { - widget->setGeometry(m_position.x(), m_position.y(), m_size.x(), m_size.y()); + clear(); + util::xml::data_node const *const historynode = node.get_child(NODE_WINDOW_HISTORY); + if (historynode) + { + util::xml::data_node const *itemnode = historynode->get_child(NODE_HISTORY_ITEM); + while (itemnode) + { + if (itemnode->get_value() && *itemnode->get_value()) + { + while (m_history.size() >= CAPACITY) + m_history.pop_back(); + m_history.push_front(QString::fromUtf8(itemnode->get_value())); + } + itemnode = itemnode->get_next_sibling(NODE_HISTORY_ITEM); + } + } } -void WindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node) +void CommandHistory::saveConfigurationToNode(util::xml::data_node &node) { - m_size.setX(node.get_attribute_int(ATTR_WINDOW_WIDTH, m_size.x())); - m_size.setY(node.get_attribute_int(ATTR_WINDOW_HEIGHT, m_size.y())); - m_position.setX(node.get_attribute_int(ATTR_WINDOW_POSITION_X, m_position.x())); - m_position.setY(node.get_attribute_int(ATTR_WINDOW_POSITION_Y, m_position.y())); - m_type = node.get_attribute_int(ATTR_WINDOW_TYPE, m_type); + util::xml::data_node *const historynode = node.add_child(NODE_WINDOW_HISTORY, nullptr); + if (historynode) + { + for (auto it = m_history.crbegin(); m_history.crend() != it; ++it) + historynode->add_child(NODE_HISTORY_ITEM, it->toUtf8().data()); + } } } // namespace osd::debugger::qt diff --git a/src/osd/modules/debugger/qt/windowqt.h b/src/osd/modules/debugger/qt/windowqt.h index ceea280e016..8085f9a63bf 100644 --- a/src/osd/modules/debugger/qt/windowqt.h +++ b/src/osd/modules/debugger/qt/windowqt.h @@ -9,30 +9,45 @@ #include +#include +#include + namespace osd::debugger::qt { //============================================================ -// The Qt window that everyone derives from. +// The Qt debugger module interface //============================================================ -class WindowQt : public QMainWindow +class DebuggerQt : public QObject { Q_OBJECT public: - WindowQt(running_machine &machine, QWidget *parent = nullptr); - virtual ~WindowQt(); + virtual ~DebuggerQt() { } - // The interface to an all-window refresh - void refreshAll() { s_refreshAll = true; } - bool wantsRefresh() { return s_refreshAll; } - void clearRefreshFlag() { s_refreshAll = false; } + virtual running_machine &machine() const = 0; - void hideAll() { s_hideAll = true; } - bool wantsHide() { return s_hideAll; } - void clearHideFlag() { s_hideAll = false; } + void hideAll() { emit hideAllWindows(); } +signals: + void exitDebugger(); + void hideAllWindows(); + void showAllWindows(); void saveConfiguration(util::xml::data_node &parentnode); +}; + + +//============================================================ +// The Qt window that everyone derives from. +//============================================================ +class WindowQt : public QMainWindow +{ + Q_OBJECT + +public: + virtual ~WindowQt(); + + virtual void restoreConfiguration(util::xml::data_node const &node); protected slots: void debugActOpenMemory(); @@ -52,38 +67,46 @@ protected slots: void debugActHardReset(); virtual void debugActClose(); void debugActQuit(); + virtual void debuggerExit(); +private slots: + void saveConfiguration(util::xml::data_node &parentnode); protected: + WindowQt(DebuggerQt &debugger, QWidget *parent = nullptr); + virtual void saveConfigurationToNode(util::xml::data_node &node); + DebuggerQt &m_debugger; running_machine &m_machine; - - static bool s_refreshAll; - static bool s_hideAll; }; -//========================================================================= -// A way to store the configuration of a window long enough to read/write. -//========================================================================= -class WindowQtConfig +//============================================================ +// Command history helper +//============================================================ +class CommandHistory { public: - WindowQtConfig(int type) : - m_type(type), - m_size(800, 600), - m_position(120, 120) - {} - virtual ~WindowQtConfig() {} - - // Settings - int m_type; - QPoint m_size; - QPoint m_position; - - virtual void applyToQWidget(QWidget *widget); - virtual void recoverFromXmlNode(util::xml::data_node const &node); + CommandHistory(); + ~CommandHistory(); + + void add(QString const &entry); + QString const *previous(QString const ¤t); + QString const *next(QString const ¤t); + void edit(); + void reset(); + void clear(); + + void restoreConfigurationFromNode(util::xml::data_node const &node); + void saveConfigurationToNode(util::xml::data_node &node); + +private: + static inline constexpr unsigned CAPACITY = 100U; + + std::deque m_history; + std::unique_ptr m_current; + int m_position; }; } // namespace osd::debugger::qt diff --git a/src/osd/modules/debugger/win/debugwininfo.h b/src/osd/modules/debugger/win/debugwininfo.h index 1fa5e79796f..f6f37c86955 100644 --- a/src/osd/modules/debugger/win/debugwininfo.h +++ b/src/osd/modules/debugger/win/debugwininfo.h @@ -20,7 +20,6 @@ namespace osd::debugger::win { class debugwin_info : protected debugbase_info { public: - debugwin_info(debugger_windows_interface &debugger, bool is_main_console, LPCSTR title, WNDPROC handler); virtual ~debugwin_info(); bool is_valid() const { return m_wnd != nullptr; } @@ -121,6 +120,8 @@ protected: ID_DEVICE_OPTIONS // always keep this at the end }; + debugwin_info(debugger_windows_interface &debugger, bool is_main_console, LPCSTR title, WNDPROC handler); + bool is_main_console() const { return m_is_main_console; } HWND window() const { return m_wnd; } uint32_t minwidth() const { return m_minwidth; } diff --git a/src/osd/modules/debugger/win/editwininfo.cpp b/src/osd/modules/debugger/win/editwininfo.cpp index e5e48746f7f..e8c7fbf92e6 100644 --- a/src/osd/modules/debugger/win/editwininfo.cpp +++ b/src/osd/modules/debugger/win/editwininfo.cpp @@ -12,6 +12,8 @@ #include "debugviewinfo.h" #include "uimetrics.h" +#include "xmlfile.h" + #include "strconv.h" #include "winutil.h" @@ -25,7 +27,7 @@ constexpr DWORD EDIT_BOX_STYLE = WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL; constexpr DWORD EDIT_BOX_STYLE_EX = 0; constexpr int MAX_EDIT_STRING = 256; -constexpr int HISTORY_LENGTH = 20; +constexpr int HISTORY_LENGTH = 100; } // anonymous namespace @@ -107,6 +109,43 @@ void editwin_info::draw_contents(HDC dc) } +void editwin_info::restore_configuration_from_node(util::xml::data_node const &node) +{ + m_history.clear(); + m_last_history = 0; + util::xml::data_node const *const hist = node.get_child(NODE_WINDOW_HISTORY); + if (hist) + { + util::xml::data_node const *item = hist->get_child(NODE_HISTORY_ITEM); + while (item) + { + if (item->get_value() && *item->get_value()) + { + while (m_history.size() >= HISTORY_LENGTH) + m_history.pop_back(); + m_history.emplace_front(osd::text::to_tstring(item->get_value())); + } + item = item->get_next_sibling(NODE_HISTORY_ITEM); + } + } + + debugwin_info::restore_configuration_from_node(node); +} + + +void editwin_info::save_configuration_to_node(util::xml::data_node &node) +{ + debugwin_info::save_configuration_to_node(node); + + util::xml::data_node *const hist = node.add_child(NODE_WINDOW_HISTORY, nullptr); + if (hist) + { + for (auto it = m_history.crbegin(); m_history.crend() != it; ++it) + hist->add_child(NODE_HISTORY_ITEM, osd::text::from_tstring(*it).c_str()); + } +} + + LRESULT editwin_info::edit_proc(UINT message, WPARAM wparam, LPARAM lparam) { // handle a few messages diff --git a/src/osd/modules/debugger/win/editwininfo.h b/src/osd/modules/debugger/win/editwininfo.h index 6a18172b5c6..e2c0ce3c4b8 100644 --- a/src/osd/modules/debugger/win/editwininfo.h +++ b/src/osd/modules/debugger/win/editwininfo.h @@ -30,6 +30,8 @@ public: virtual bool set_default_focus() override; + virtual void restore_configuration_from_node(util::xml::data_node const &node) override; + protected: constexpr static DWORD COMBO_BOX_STYLE = WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL; constexpr static DWORD COMBO_BOX_STYLE_EX = 0; @@ -41,6 +43,8 @@ protected: virtual void draw_contents(HDC dc) override; + virtual void save_configuration_to_node(util::xml::data_node &node) override; + private: typedef std::deque > history_deque; diff --git a/src/osd/modules/debugger/xmlconfig.cpp b/src/osd/modules/debugger/xmlconfig.cpp index 9cdd34fc5da..7e702938bf8 100644 --- a/src/osd/modules/debugger/xmlconfig.cpp +++ b/src/osd/modules/debugger/xmlconfig.cpp @@ -12,6 +12,9 @@ char const *const NODE_WINDOW_SPLITS = "splits"; char const *const NODE_WINDOW_SELECTION = "selection"; char const *const NODE_WINDOW_SCROLL = "scroll"; char const *const NODE_WINDOW_EXPRESSION = "expression"; +char const *const NODE_WINDOW_HISTORY = "history"; + +char const *const NODE_HISTORY_ITEM = "item"; char const *const ATTR_DEBUGGER_SAVE_WINDOWS = "savewindows"; diff --git a/src/osd/modules/debugger/xmlconfig.h b/src/osd/modules/debugger/xmlconfig.h index a83f6ae960a..ae5cdf8393c 100644 --- a/src/osd/modules/debugger/xmlconfig.h +++ b/src/osd/modules/debugger/xmlconfig.h @@ -28,6 +28,9 @@ extern char const *const NODE_WINDOW_SPLITS; extern char const *const NODE_WINDOW_SELECTION; extern char const *const NODE_WINDOW_SCROLL; extern char const *const NODE_WINDOW_EXPRESSION; +extern char const *const NODE_WINDOW_HISTORY; + +extern char const *const NODE_HISTORY_ITEM; extern char const *const ATTR_DEBUGGER_SAVE_WINDOWS; -- cgit v1.2.3