summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/debugger/qt/debuggerview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/modules/debugger/qt/debuggerview.cpp')
-rw-r--r--src/osd/modules/debugger/qt/debuggerview.cpp431
1 files changed, 286 insertions, 145 deletions
diff --git a/src/osd/modules/debugger/qt/debuggerview.cpp b/src/osd/modules/debugger/qt/debuggerview.cpp
index 7dc16c0a3de..6a184dcfcca 100644
--- a/src/osd/modules/debugger/qt/debuggerview.cpp
+++ b/src/osd/modules/debugger/qt/debuggerview.cpp
@@ -1,80 +1,96 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
#include "emu.h"
-#include <QtWidgets/QScrollBar>
-#include <QtWidgets/QApplication>
-#include <QtGui/QPainter>
-#include <QtGui/QKeyEvent>
-
#include "debuggerview.h"
+#include "../xmlconfig.h"
+
#include "modules/lib/osdobj_common.h"
+#include "xmlfile.h"
+
+#include <QtCore/QMimeData>
+#include <QtGui/QClipboard>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QPainter>
+#include <QtWidgets/QApplication>
+#include <QtWidgets/QScrollBar>
-DebuggerView::DebuggerView(const debug_view_type& type,
- running_machine* machine,
- QWidget* parent) :
+
+namespace osd::debugger::qt {
+
+DebuggerView::DebuggerView(
+ debug_view_type type,
+ running_machine &machine,
+ QWidget *parent) :
QAbstractScrollArea(parent),
- m_preferBottom(false),
+ m_machine(machine),
m_view(nullptr),
- m_machine(machine)
+ m_preferBottom(false)
{
- // I like setting the font per-view since it doesn't override the menuing fonts.
- const char *const selectedFont(downcast<osd_options &>(m_machine->options()).debugger_font());
- const float selectedFontSize(downcast<osd_options &>(m_machine->options()).debugger_font_size());
+ // I like setting the font per-view since it doesn't override the menu fonts.
+ const char *const selectedFont(downcast<osd_options &>(m_machine.options()).debugger_font());
+ const float selectedFontSize(downcast<osd_options &>(m_machine.options()).debugger_font_size());
QFont viewFontRequest((!*selectedFont || !strcmp(selectedFont, OSDOPTVAL_AUTO)) ? "Courier New" : selectedFont);
viewFontRequest.setFixedPitch(true);
viewFontRequest.setStyleHint(QFont::TypeWriter);
viewFontRequest.setPointSize((selectedFontSize <= 0) ? 11 : selectedFontSize);
setFont(viewFontRequest);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
- m_view = m_machine->debug_view().alloc_view(type,
- DebuggerView::debuggerViewUpdate,
- this);
+ m_view = m_machine.debug_view().alloc_view(
+ type,
+ DebuggerView::debuggerViewUpdate,
+ this);
- connect(verticalScrollBar(), &QScrollBar::valueChanged,
- this, &DebuggerView::verticalScrollSlot);
- connect(horizontalScrollBar(), &QScrollBar::valueChanged,
- this, &DebuggerView::horizontalScrollSlot);
+ connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &DebuggerView::verticalScrollSlot);
+ connect(horizontalScrollBar(), &QScrollBar::valueChanged, this, &DebuggerView::horizontalScrollSlot);
}
DebuggerView::~DebuggerView()
{
- if (m_machine && m_view)
- m_machine->debug_view().free_view(*m_view);
+ if (m_view)
+ m_machine.debug_view().free_view(*m_view);
+}
+
+
+int DebuggerView::sourceIndex() const
+{
+ if (m_view)
+ {
+ debug_view_source const *const source = m_view->source();
+ if (source)
+ return m_view->source_index(*source);
+ }
+ return -1;
}
-void DebuggerView::paintEvent(QPaintEvent* event)
+
+void DebuggerView::paintEvent(QPaintEvent *event)
{
// Tell the MAME debug view how much real estate is available
QFontMetrics actualFont = fontMetrics();
- const double fontWidth = actualFont.width(QString(100, '_')) / 100.;
- const int fontHeight = std::max(1, actualFont.lineSpacing());
- m_view->set_visible_size(debug_view_xy(width()/fontWidth, height()/fontHeight));
-
+ double const fontWidth = actualFont.horizontalAdvance(QString(100, '_')) / 100.;
+ int const fontHeight = std::max(1, actualFont.lineSpacing());
+ int const contentWidth = width() - verticalScrollBar()->width();
+ int const lineWidth = contentWidth / fontWidth;
+ bool const fullWidth = lineWidth >= m_view->total_size().x;
+ int const contentHeight = height() - (fullWidth ? 0 : horizontalScrollBar()->height());
+ m_view->set_visible_size(debug_view_xy(lineWidth, contentHeight / fontHeight));
// Handle the scroll bars
- const int horizontalScrollCharDiff = m_view->total_size().x - m_view->visible_size().x;
- const int horizontalScrollSize = horizontalScrollCharDiff < 0 ? 0 : horizontalScrollCharDiff;
- horizontalScrollBar()->setRange(0, horizontalScrollSize);
-
- // If the horizontal scroll bar appears, make sure to adjust the vertical scrollbar accordingly
- const int verticalScrollAdjust = horizontalScrollSize > 0 ? 1 : 0;
+ int const horizontalScrollCharDiff = m_view->total_size().x - m_view->visible_size().x;
+ horizontalScrollBar()->setRange(0, (std::max)(0, horizontalScrollCharDiff));
+ horizontalScrollBar()->setPageStep(lineWidth - 1);
- const int verticalScrollCharDiff = m_view->total_size().y - m_view->visible_size().y;
- const int verticalScrollSize = verticalScrollCharDiff < 0 ? 0 : verticalScrollCharDiff+verticalScrollAdjust;
- bool atEnd = false;
- if (verticalScrollBar()->value() == verticalScrollBar()->maximum())
- {
- atEnd = true;
- }
+ int const verticalScrollCharDiff = m_view->total_size().y - m_view->visible_size().y;
+ int const verticalScrollSize = (std::max)(0, verticalScrollCharDiff);
+ bool const atEnd = verticalScrollBar()->value() == verticalScrollBar()->maximum();
verticalScrollBar()->setRange(0, verticalScrollSize);
+ verticalScrollBar()->setPageStep((contentHeight / fontHeight) - 1);
if (m_preferBottom && atEnd)
- {
verticalScrollBar()->setValue(verticalScrollSize);
- }
-
// Draw the viewport widget
QPainter painter(viewport());
@@ -87,84 +103,130 @@ void DebuggerView::paintEvent(QPaintEvent* event)
bgBrush.setStyle(Qt::SolidPattern);
painter.setPen(QPen(QColor(0,0,0)));
- size_t viewDataOffset = 0;
- const debug_view_xy& visibleCharDims = m_view->visible_size();
- const debug_view_char* viewdata = m_view->viewdata();
- for (int y = 0; y < visibleCharDims.y; y++)
+ const debug_view_xy visibleCharDims = m_view->visible_size();
+ const debug_view_char *viewdata = m_view->viewdata();
+ for (int y = 0; y < visibleCharDims.y; y++, viewdata += visibleCharDims.x)
{
int width = 1;
- for (int x = 0; x < visibleCharDims.x; viewDataOffset += width, x += width)
+ for (int x = 0; x < visibleCharDims.x; x += width)
{
- const unsigned char textAttr = viewdata[viewDataOffset].attrib;
+ const unsigned char textAttr = viewdata[x].attrib;
// Text color handling
QColor fgColor(0,0,0);
QColor bgColor(255,255,255);
- if(textAttr & DCA_VISITED)
- {
+ if (textAttr & DCA_VISITED)
bgColor.setRgb(0xc6, 0xe2, 0xff);
- }
- if(textAttr & DCA_ANCILLARY)
- {
+
+ if (textAttr & DCA_ANCILLARY)
bgColor.setRgb(0xe0, 0xe0, 0xe0);
- }
- if(textAttr & DCA_SELECTED)
- {
+
+ if (textAttr & DCA_SELECTED)
bgColor.setRgb(0xff, 0x80, 0x80);
- }
- if(textAttr & DCA_CURRENT)
- {
+
+ if (textAttr & DCA_CURRENT)
bgColor.setRgb(0xff, 0xff, 0x00);
- }
+
if ((textAttr & DCA_SELECTED) && (textAttr & DCA_CURRENT))
- {
bgColor.setRgb(0xff,0xc0,0x80);
- }
- if(textAttr & DCA_CHANGED)
- {
+
+ if (textAttr & DCA_CHANGED)
fgColor.setRgb(0xff, 0x00, 0x00);
- }
- if(textAttr & DCA_INVALID)
- {
+
+ if (textAttr & DCA_INVALID)
fgColor.setRgb(0x00, 0x00, 0xff);
- }
- if(textAttr & DCA_DISABLED)
+
+ if (textAttr & DCA_DISABLED)
{
- fgColor.setRgb((fgColor.red() + bgColor.red()) >> 1,
- (fgColor.green() + bgColor.green()) >> 1,
- (fgColor.blue() + bgColor.blue()) >> 1);
+ fgColor.setRgb(
+ (fgColor.red() + bgColor.red()) >> 1,
+ (fgColor.green() + bgColor.green()) >> 1,
+ (fgColor.blue() + bgColor.blue()) >> 1);
}
- if(textAttr & DCA_COMMENT)
- {
+
+ if (textAttr & DCA_COMMENT)
fgColor.setRgb(0x00, 0x80, 0x00);
- }
bgBrush.setColor(bgColor);
painter.setBackground(bgBrush);
painter.setPen(QPen(fgColor));
- QString text(QChar(viewdata[viewDataOffset].byte));
- for (width = 1; x + width < visibleCharDims.x; width++)
+ QString text(QChar(viewdata[x].byte));
+ for (width = 1; (x + width) < visibleCharDims.x; width++)
{
- if (textAttr != viewdata[viewDataOffset + width].attrib)
+ if (textAttr != viewdata[x + width].attrib)
break;
- text.append(QChar(viewdata[viewDataOffset + width].byte));
+ text.append(QChar(viewdata[x + width].byte));
}
// Your characters are not guaranteed to take up the entire length x fontWidth x fontHeight, so fill before.
- painter.fillRect(x*fontWidth, y*fontHeight, width*fontWidth, fontHeight, bgBrush);
+ painter.fillRect(
+ x * fontWidth,
+ y * fontHeight,
+ ((x + width) < visibleCharDims.x) ? (width * fontWidth) : (contentWidth - (x * fontWidth)),
+ fontHeight,
+ bgBrush);
+
+ if (((y + 1) == visibleCharDims.y) && (contentHeight > (visibleCharDims.y * fontHeight)))
+ {
+ if (textAttr & DCA_ANCILLARY)
+ bgColor.setRgb(0xe0, 0xe0, 0xe0);
+ else
+ bgColor.setRgb(0xff, 0xff, 0xff);
+ bgBrush.setColor(bgColor);
+ painter.fillRect(
+ x * fontWidth,
+ visibleCharDims.y * fontHeight,
+ ((x + width) < visibleCharDims.x) ? (width * fontWidth) : (contentWidth - (x * fontWidth)),
+ contentHeight - (visibleCharDims.y * fontHeight),
+ bgBrush);
+ }
// There is a touchy interplay between font height, drawing difference, visible position, etc
// Fonts don't get drawn "down and to the left" like boxes, so some wiggling is needed.
- painter.drawText(x*fontWidth, (y*fontHeight + (fontHeight*0.80)), text);
+ painter.drawText(x * fontWidth, (y * fontHeight + (fontHeight * 0.80)), text);
+ }
+ }
+}
+
+
+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();
@@ -173,52 +235,54 @@ void DebuggerView::keyPressEvent(QKeyEvent* event)
int keyPress = -1;
switch (event->key())
{
- case Qt::Key_Up:
- keyPress = DCH_UP;
- break;
- case Qt::Key_Down:
- keyPress = DCH_DOWN;
- break;
- case Qt::Key_Left:
- keyPress = DCH_LEFT;
- if (ctrlDown) keyPress = DCH_CTRLLEFT;
- break;
- case Qt::Key_Right:
- keyPress = DCH_RIGHT;
- if (ctrlDown) keyPress = DCH_CTRLRIGHT;
- break;
- case Qt::Key_PageUp:
- keyPress = DCH_PUP;
- break;
- case Qt::Key_PageDown:
- keyPress = DCH_PDOWN;
- break;
- case Qt::Key_Home:
- keyPress = DCH_HOME;
- if (ctrlDown) keyPress = DCH_CTRLHOME;
- break;
- case Qt::Key_End:
- keyPress = DCH_END;
- if (ctrlDown) keyPress = DCH_CTRLEND;
- break;
- case Qt::Key_0: keyPress = '0'; break;
- case Qt::Key_1: keyPress = '1'; break;
- case Qt::Key_2: keyPress = '2'; break;
- case Qt::Key_3: keyPress = '3'; break;
- case Qt::Key_4: keyPress = '4'; break;
- case Qt::Key_5: keyPress = '5'; break;
- case Qt::Key_6: keyPress = '6'; break;
- case Qt::Key_7: keyPress = '7'; break;
- case Qt::Key_8: keyPress = '8'; break;
- case Qt::Key_9: keyPress = '9'; break;
- case Qt::Key_A: keyPress = 'a'; break;
- case Qt::Key_B: keyPress = 'b'; break;
- case Qt::Key_C: keyPress = 'c'; break;
- case Qt::Key_D: keyPress = 'd'; break;
- case Qt::Key_E: keyPress = 'e'; break;
- case Qt::Key_F: keyPress = 'f'; break;
- default:
- return QWidget::keyPressEvent(event);
+ case Qt::Key_Up:
+ keyPress = DCH_UP;
+ break;
+ case Qt::Key_Down:
+ keyPress = DCH_DOWN;
+ break;
+ case Qt::Key_Left:
+ keyPress = DCH_LEFT;
+ if (ctrlDown)
+ keyPress = DCH_CTRLLEFT;
+ break;
+ case Qt::Key_Right:
+ keyPress = DCH_RIGHT;
+ if (ctrlDown)
+ keyPress = DCH_CTRLRIGHT;
+ break;
+ case Qt::Key_PageUp:
+ keyPress = DCH_PUP;
+ break;
+ case Qt::Key_PageDown:
+ keyPress = DCH_PDOWN;
+ break;
+ case Qt::Key_Home:
+ keyPress = DCH_HOME;
+ if (ctrlDown) keyPress = DCH_CTRLHOME;
+ break;
+ case Qt::Key_End:
+ keyPress = DCH_END;
+ if (ctrlDown) keyPress = DCH_CTRLEND;
+ break;
+ case Qt::Key_0: keyPress = '0'; break;
+ case Qt::Key_1: keyPress = '1'; break;
+ case Qt::Key_2: keyPress = '2'; break;
+ case Qt::Key_3: keyPress = '3'; break;
+ case Qt::Key_4: keyPress = '4'; break;
+ case Qt::Key_5: keyPress = '5'; break;
+ case Qt::Key_6: keyPress = '6'; break;
+ case Qt::Key_7: keyPress = '7'; break;
+ case Qt::Key_8: keyPress = '8'; break;
+ case Qt::Key_9: keyPress = '9'; break;
+ case Qt::Key_A: keyPress = 'a'; break;
+ case Qt::Key_B: keyPress = 'b'; break;
+ case Qt::Key_C: keyPress = 'c'; break;
+ case Qt::Key_D: keyPress = 'd'; break;
+ case Qt::Key_E: keyPress = 'e'; break;
+ case Qt::Key_F: keyPress = 'f'; break;
+ default:
+ return QWidget::keyPressEvent(event);
}
m_view->set_cursor_visible(true);
@@ -232,26 +296,65 @@ void DebuggerView::keyPressEvent(QKeyEvent* event)
}
-void DebuggerView::mousePressEvent(QMouseEvent* event)
+void DebuggerView::mousePressEvent(QMouseEvent *event)
{
- if (m_view == nullptr)
+ if (!m_view)
return;
+ QFontMetrics actualFont = fontMetrics();
+ const double fontWidth = actualFont.horizontalAdvance(QString(100, '_')) / 100.;
+ const int fontHeight = std::max(1, actualFont.lineSpacing());
+
+ debug_view_xy const topLeft = m_view->visible_position();
+ debug_view_xy const visibleCharDims = m_view->visible_size();
+ debug_view_xy clickViewPosition;
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ const QPointF mousePosition = event->position();
+#else
+ const QPointF mousePosition = event->localPos();
+#endif
+ clickViewPosition.x = (std::min)(int(topLeft.x + (mousePosition.x() / fontWidth)), topLeft.x + visibleCharDims.x - 1);
+ clickViewPosition.y = (std::min)(int(topLeft.y + (mousePosition.y() / fontHeight)), topLeft.y + visibleCharDims.y - 1);
+
if (event->button() == Qt::LeftButton)
{
- QFontMetrics actualFont = fontMetrics();
- const double fontWidth = actualFont.width(QString(100, '_')) / 100.;
- const int fontHeight = std::max(1, actualFont.lineSpacing());
-
- debug_view_xy topLeft = m_view->visible_position();
- debug_view_xy clickViewPosition;
- clickViewPosition.x = topLeft.x + (event->x() / fontWidth);
- clickViewPosition.y = topLeft.y + (event->y() / fontHeight);
m_view->process_click(DCK_LEFT_CLICK, clickViewPosition);
-
- viewport()->update();
- update();
}
+ else if (event->button() == Qt::MiddleButton)
+ {
+ m_view->process_click(DCK_MIDDLE_CLICK, clickViewPosition);
+ }
+ else if (event->button() == Qt::RightButton)
+ {
+ if (m_view->cursor_supported())
+ {
+ m_view->set_cursor_position(clickViewPosition);
+ m_view->set_cursor_visible(true);
+ }
+ }
+
+ viewport()->update();
+ update();
+}
+
+
+void DebuggerView::contextMenuEvent(QContextMenuEvent *event)
+{
+ QMenu *const menu = new QMenu(this);
+ addItemsToContextMenu(menu);
+ menu->popup(event->globalPos());
+}
+
+
+void DebuggerView::addItemsToContextMenu(QMenu *menu)
+{
+ QAction *const copyAct = new QAction("Copy Visible", menu);
+ QAction *const pasteAct = new QAction("Paste", menu);
+ pasteAct->setEnabled(QApplication::clipboard()->mimeData()->hasText());
+ connect(copyAct, &QAction::triggered, this, &DebuggerView::copyVisibleSlot);
+ connect(pasteAct, &QAction::triggered, this, &DebuggerView::pasteSlot);
+ menu->addAction(copyAct);
+ menu->addAction(pasteAct);
}
@@ -267,13 +370,51 @@ void DebuggerView::horizontalScrollSlot(int value)
}
-void DebuggerView::debuggerViewUpdate(debug_view& debugView, void* osdPrivate)
+void DebuggerView::copyVisibleSlot()
{
- // Get a handle to the DebuggerView being updated & redraw
- DebuggerView* dView = (DebuggerView*)osdPrivate;
+ // get visible text
+ debug_view_xy const visarea = m_view->visible_size();
+ debug_view_char const *viewdata = m_view->viewdata();
+ if (!viewdata)
+ return;
+
+ // turn into a plain string, trimming trailing whitespace
+ std::string text;
+ for (uint32_t row = 0; row < visarea.y; row++, viewdata += visarea.x)
+ {
+ std::string::size_type const start = text.length();
+ for (uint32_t col = 0; col < visarea.x; ++col)
+ text += wchar_t(viewdata[col].byte);
+ std::string::size_type const nonblank = text.find_last_not_of("\t\n\v\r ");
+ if (nonblank != std::string::npos)
+ text.resize((std::max)(start, nonblank + 1));
+ text += "\n";
+ }
+
+ // copy to the clipboard
+ QApplication::clipboard()->setText(text.c_str());
+}
+
+
+void DebuggerView::pasteSlot()
+{
+ for (QChar ch : QApplication::clipboard()->text())
+ {
+ if ((32 <= ch.unicode()) && (127 >= ch.unicode()))
+ m_view->process_char(ch.unicode());
+ }
+}
+
+
+void DebuggerView::debuggerViewUpdate(debug_view &debugView, void *osdPrivate)
+{
+ // Get a handle to the DebuggerView being updated and redraw
+ DebuggerView *dView = reinterpret_cast<DebuggerView *>(osdPrivate);
dView->verticalScrollBar()->setValue(dView->view()->visible_position().y);
dView->horizontalScrollBar()->setValue(dView->view()->visible_position().x);
dView->viewport()->update();
dView->update();
emit dView->updated();
}
+
+} // namespace osd::debugger::qt