duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

memoryviewwidget.cpp (6778B)


      1 #include "memoryviewwidget.h"
      2 #include <QtGui/QPainter>
      3 #include <QtWidgets/QScrollBar>
      4 #include <cstring>
      5 
      6 MemoryViewWidget::MemoryViewWidget(QWidget* parent /* = nullptr */, size_t address_offset /* = 0 */,
      7                                    const void* data_ptr /* = nullptr */, size_t data_size /* = 0 */)
      8   : QAbstractScrollArea(parent)
      9 {
     10   m_bytes_per_line = 16;
     11 
     12   updateMetrics();
     13 
     14   connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &MemoryViewWidget::adjustContent);
     15   connect(horizontalScrollBar(), &QScrollBar::valueChanged, this, &MemoryViewWidget::adjustContent);
     16 
     17   if (data_ptr)
     18     setData(address_offset, data_ptr, data_size);
     19 }
     20 
     21 MemoryViewWidget::~MemoryViewWidget() = default;
     22 
     23 int MemoryViewWidget::addressWidth() const
     24 {
     25   return (8 * m_char_width) + m_char_width;
     26 }
     27 
     28 int MemoryViewWidget::hexWidth() const
     29 {
     30   return (m_bytes_per_line * 4) * m_char_width;
     31 }
     32 
     33 int MemoryViewWidget::asciiWidth() const
     34 {
     35   return (m_bytes_per_line * 2 + 1) * m_char_width;
     36 }
     37 
     38 void MemoryViewWidget::updateMetrics()
     39 {
     40   const QFontMetrics fm(fontMetrics());
     41   m_char_width = fm.horizontalAdvance(QChar('0'));
     42   m_char_height = fm.height();
     43 }
     44 
     45 void MemoryViewWidget::setData(size_t address_offset, const void* data_ptr, size_t data_size)
     46 {
     47   m_data = data_ptr;
     48   m_data_size = data_size;
     49   m_address_offset = address_offset;
     50   adjustContent();
     51 }
     52 
     53 void MemoryViewWidget::setHighlightRange(size_t start, size_t end)
     54 {
     55   m_highlight_start = start;
     56   m_highlight_end = end;
     57   viewport()->update();
     58 }
     59 
     60 void MemoryViewWidget::clearHighlightRange()
     61 {
     62   m_highlight_start = 0;
     63   m_highlight_end = 0;
     64   viewport()->update();
     65 }
     66 
     67 void MemoryViewWidget::scrolltoOffset(size_t offset)
     68 {
     69   const unsigned row = static_cast<unsigned>(offset / m_bytes_per_line);
     70   verticalScrollBar()->setSliderPosition(static_cast<int>(row));
     71   horizontalScrollBar()->setSliderPosition(0);
     72 }
     73 
     74 void MemoryViewWidget::scrollToAddress(size_t address)
     75 {
     76   const unsigned row = static_cast<unsigned>((address - m_start_offset) / m_bytes_per_line);
     77   verticalScrollBar()->setSliderPosition(static_cast<int>(row));
     78   horizontalScrollBar()->setSliderPosition(0);
     79 }
     80 
     81 void MemoryViewWidget::setFont(const QFont& font)
     82 {
     83   QAbstractScrollArea::setFont(font);
     84   updateMetrics();
     85 }
     86 
     87 void MemoryViewWidget::resizeEvent(QResizeEvent*)
     88 {
     89   adjustContent();
     90 }
     91 
     92 template<typename T>
     93 static bool RangesOverlap(T x1, T x2, T y1, T y2)
     94 {
     95   return (x2 >= y1 && x1 < y2);
     96 }
     97 
     98 void MemoryViewWidget::paintEvent(QPaintEvent*)
     99 {
    100   QPainter painter(viewport());
    101   painter.setFont(font());
    102   if (!m_data)
    103     return;
    104 
    105   const QColor highlight_color(100, 100, 0);
    106   const int offsetX = horizontalScrollBar()->value();
    107 
    108   int y = m_char_height;
    109   QString address;
    110 
    111   painter.setPen(viewport()->palette().color(QPalette::WindowText));
    112 
    113   y += m_char_height;
    114 
    115   const unsigned num_rows = static_cast<unsigned>(m_end_offset - m_start_offset) / m_bytes_per_line;
    116   for (unsigned row = 0; row <= num_rows; row++)
    117   {
    118     const size_t data_offset = m_start_offset + (row * m_bytes_per_line);
    119     const unsigned row_address = static_cast<unsigned>(m_address_offset + data_offset);
    120     const int draw_x = m_char_width / 2 - offsetX;
    121     if (RangesOverlap(data_offset, data_offset + m_bytes_per_line, m_highlight_start, m_highlight_end))
    122       painter.fillRect(0, y - m_char_height + 3, addressWidth(), m_char_height, highlight_color);
    123 
    124     const QString address_text(QString::asprintf("%08X", row_address));
    125     painter.drawText(draw_x, y, address_text);
    126     y += m_char_height;
    127   }
    128 
    129   int x;
    130   int lx = addressWidth();
    131   painter.drawLine(lx - offsetX, 0, lx - offsetX, height());
    132   y = m_char_height;
    133 
    134   // hex data
    135   const int HEX_CHAR_WIDTH = 4 * m_char_width;
    136 
    137   x = lx - offsetX;
    138   for (unsigned col = 0; col < m_bytes_per_line; col++)
    139   {
    140     if ((col % 2) != 0)
    141       painter.fillRect(x, 0, HEX_CHAR_WIDTH, height(), viewport()->palette().color(QPalette::AlternateBase));
    142 
    143     x += HEX_CHAR_WIDTH;
    144   }
    145 
    146   y = m_char_height;
    147   x = lx - offsetX + m_char_width;
    148   for (unsigned col = 0; col < m_bytes_per_line; col++)
    149   {
    150     painter.drawText(x, y, QString::asprintf("%02X", col));
    151     x += HEX_CHAR_WIDTH;
    152   }
    153 
    154   painter.drawLine(0, y + 3, width(), y + 3);
    155   y += m_char_height;
    156 
    157   size_t offset = m_start_offset;
    158   for (unsigned row = 0; row <= num_rows; row++)
    159   {
    160     x = lx - offsetX + m_char_width;
    161     for (unsigned col = 0; col < m_bytes_per_line && offset < m_data_size; col++, offset++)
    162     {
    163       unsigned char value;
    164       std::memcpy(&value, static_cast<const unsigned char*>(m_data) + offset, sizeof(value));
    165       if (offset >= m_highlight_start && offset < m_highlight_end)
    166         painter.fillRect(x - m_char_width, y - m_char_height + 3, HEX_CHAR_WIDTH, m_char_height, highlight_color);
    167 
    168       painter.drawText(x, y, QString::asprintf("%02X", value));
    169       x += HEX_CHAR_WIDTH;
    170     }
    171     y += m_char_height;
    172   }
    173 
    174   lx = addressWidth() + hexWidth();
    175   painter.drawLine(lx - offsetX, 0, lx - offsetX, height());
    176 
    177   lx += m_char_width;
    178 
    179   y = m_char_height;
    180   x = (lx - offsetX);
    181   for (unsigned col = 0; col < m_bytes_per_line; col++)
    182   {
    183     const QChar ch = (col < 0xA) ? (static_cast<QChar>('0' + col)) : (static_cast<QChar>('A' + (col - 0xA)));
    184     painter.drawText(x, y, ch);
    185     x += 2 * m_char_width;
    186   }
    187 
    188   y += m_char_height;
    189 
    190   offset = m_start_offset;
    191   for (unsigned row = 0; row <= num_rows; row++)
    192   {
    193     x = lx - offsetX;
    194     for (unsigned col = 0; col < m_bytes_per_line && offset < m_data_size; col++, offset++)
    195     {
    196       unsigned char value;
    197       std::memcpy(&value, static_cast<const unsigned char*>(m_data) + offset, sizeof(value));
    198       if (offset >= m_highlight_start && offset < m_highlight_end)
    199         painter.fillRect(x, y - m_char_height + 3, 2 * m_char_width, m_char_height, highlight_color);
    200 
    201       if (!std::isprint(value))
    202         value = '.';
    203       painter.drawText(x, y, static_cast<QChar>(value));
    204       x += 2 * m_char_width;
    205     }
    206     y += m_char_height;
    207   }
    208 }
    209 
    210 void MemoryViewWidget::adjustContent()
    211 {
    212   if (!m_data)
    213   {
    214     setEnabled(false);
    215     return;
    216   }
    217 
    218   setEnabled(true);
    219 
    220   int w = addressWidth() + hexWidth() + asciiWidth();
    221   horizontalScrollBar()->setRange(0, w - viewport()->width());
    222   horizontalScrollBar()->setPageStep(viewport()->width());
    223 
    224   m_rows_visible = viewport()->height() / m_char_height;
    225   int val = verticalScrollBar()->value();
    226   m_start_offset = (size_t)val * m_bytes_per_line;
    227   m_end_offset = m_start_offset + m_rows_visible * m_bytes_per_line - 1;
    228   if (m_end_offset >= m_data_size)
    229     m_end_offset = m_data_size - 1;
    230 
    231   const int lineCount = static_cast<int>(m_data_size / m_bytes_per_line);
    232   verticalScrollBar()->setRange(0, lineCount - m_rows_visible);
    233   verticalScrollBar()->setPageStep(m_rows_visible);
    234 
    235   viewport()->update();
    236 }