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 }