memoryscannerwindow.cpp (19754B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> and contributors. 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #include "memoryscannerwindow.h" 5 #include "cheatcodeeditordialog.h" 6 #include "common/assert.h" 7 #include "common/string_util.h" 8 #include "core/bus.h" 9 #include "core/cpu_core.h" 10 #include "core/host.h" 11 #include "core/system.h" 12 #include "qthost.h" 13 #include "qtutils.h" 14 #include <QtCore/QFileInfo> 15 #include <QtGui/QColor> 16 #include <QtWidgets/QFileDialog> 17 #include <QtWidgets/QInputDialog> 18 #include <QtWidgets/QMenu> 19 #include <QtWidgets/QMessageBox> 20 #include <QtWidgets/QTreeWidgetItemIterator> 21 #include <array> 22 #include <utility> 23 24 static constexpr std::array<const char*, 6> s_size_strings = { 25 {TRANSLATE_NOOP("MemoryScannerWindow", "Byte"), TRANSLATE_NOOP("MemoryScannerWindow", "Halfword"), 26 TRANSLATE_NOOP("MemoryScannerWindow", "Word"), TRANSLATE_NOOP("MemoryScannerWindow", "Signed Byte"), 27 TRANSLATE_NOOP("MemoryScannerWindow", "Signed Halfword"), TRANSLATE_NOOP("MemoryScannerWindow", "Signed Word")}}; 28 29 static QString formatHexValue(u32 value, u8 size) 30 { 31 return QStringLiteral("0x%1").arg(static_cast<uint>(value), size, 16, QChar('0')); 32 } 33 34 static QString formatHexAndDecValue(u32 value, u8 size, bool is_signed) 35 { 36 37 if (is_signed) 38 { 39 u32 value_raw = value; 40 if (size == 2) 41 value_raw &= 0xFF; 42 else if (size == 4) 43 value_raw &= 0xFFFF; 44 return QStringLiteral("0x%1 (%2)") 45 .arg(static_cast<u32>(value_raw), size, 16, QChar('0')) 46 .arg(static_cast<int>(value)); 47 } 48 else 49 return QStringLiteral("0x%1 (%2)").arg(static_cast<u32>(value), size, 16, QChar('0')).arg(static_cast<uint>(value)); 50 } 51 52 static QString formatCheatCode(u32 address, u32 value, const MemoryAccessSize size) 53 { 54 55 if (size == MemoryAccessSize::Byte && address <= 0x00200000) 56 return QStringLiteral("CHEAT CODE: %1 %2") 57 .arg(static_cast<u32>(address) + 0x30000000, 8, 16, QChar('0')) 58 .toUpper() 59 .arg(static_cast<u16>(value), 4, 16, QChar('0')) 60 .toUpper(); 61 else if (size == MemoryAccessSize::HalfWord && address <= 0x001FFFFE) 62 return QStringLiteral("CHEAT CODE: %1 %2") 63 .arg(static_cast<u32>(address) + 0x80000000, 8, 16, QChar('0')) 64 .toUpper() 65 .arg(static_cast<u16>(value), 4, 16, QChar('0')) 66 .toUpper(); 67 else if (size == MemoryAccessSize::Word && address <= 0x001FFFFC) 68 return QStringLiteral("CHEAT CODE: %1 %2") 69 .arg(static_cast<u32>(address) + 0x90000000, 8, 16, QChar('0')) 70 .toUpper() 71 .arg(static_cast<u32>(value), 8, 16, QChar('0')) 72 .toUpper(); 73 else 74 return QStringLiteral("OUTSIDE RAM RANGE. POKE %1 with %2") 75 .arg(static_cast<u32>(address), 8, 16, QChar('0')) 76 .toUpper() 77 .arg(static_cast<u16>(value), 8, 16, QChar('0')) 78 .toUpper(); 79 } 80 81 static QString formatValue(u32 value, bool is_signed) 82 { 83 if (is_signed) 84 return QString::number(static_cast<int>(value)); 85 else 86 return QString::number(static_cast<uint>(value)); 87 } 88 89 MemoryScannerWindow::MemoryScannerWindow() : QWidget() 90 { 91 m_ui.setupUi(this); 92 connectUi(); 93 94 m_ui.cheatEngineAddress->setText(tr("Address of RAM for HxD Usage: 0x%1").arg(reinterpret_cast<qulonglong>(Bus::g_unprotected_ram), 16, 16, QChar('0'))); 95 } 96 97 MemoryScannerWindow::~MemoryScannerWindow() = default; 98 99 void MemoryScannerWindow::connectUi() 100 { 101 m_ui.scanStartAddress->setText(formatHexValue(m_scanner.GetStartAddress(), 8)); 102 m_ui.scanEndAddress->setText(formatHexValue(m_scanner.GetEndAddress(), 8)); 103 104 connect(m_ui.scanValue, &QLineEdit::textChanged, this, &MemoryScannerWindow::updateScanValue); 105 connect(m_ui.scanValueBase, QOverload<int>::of(&QComboBox::currentIndexChanged), 106 [this](int index) { updateScanValue(); }); 107 connect(m_ui.scanSize, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) { 108 m_scanner.SetSize(static_cast<MemoryAccessSize>(index)); 109 m_scanner.ResetSearch(); 110 updateResults(); 111 }); 112 connect(m_ui.scanValueSigned, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) { 113 m_scanner.SetValueSigned(index == 0); 114 m_scanner.ResetSearch(); 115 updateResults(); 116 }); 117 connect(m_ui.scanOperator, QOverload<int>::of(&QComboBox::currentIndexChanged), 118 [this](int index) { m_scanner.SetOperator(static_cast<MemoryScan::Operator>(index)); }); 119 connect(m_ui.scanStartAddress, &QLineEdit::textChanged, [this](const QString& value) { 120 uint address; 121 if (value.startsWith(QStringLiteral("0x")) && value.length() > 2) 122 address = value.mid(2).toUInt(nullptr, 16); 123 else 124 address = value.toUInt(nullptr, 16); 125 m_scanner.SetStartAddress(static_cast<PhysicalMemoryAddress>(address)); 126 }); 127 connect(m_ui.scanEndAddress, &QLineEdit::textChanged, [this](const QString& value) { 128 uint address; 129 if (value.startsWith(QStringLiteral("0x")) && value.length() > 2) 130 address = value.mid(2).toUInt(nullptr, 16); 131 else 132 address = value.toUInt(nullptr, 16); 133 m_scanner.SetEndAddress(static_cast<PhysicalMemoryAddress>(address)); 134 }); 135 connect(m_ui.scanPresetRange, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) { 136 if (index == 0) 137 { 138 m_ui.scanStartAddress->setText(formatHexValue(0, 8)); 139 m_ui.scanEndAddress->setText(formatHexValue(Bus::g_ram_size, 8)); 140 } 141 else if (index == 1) 142 { 143 m_ui.scanStartAddress->setText(formatHexValue(CPU::SCRATCHPAD_ADDR, 8)); 144 m_ui.scanEndAddress->setText(formatHexValue(CPU::SCRATCHPAD_ADDR + CPU::SCRATCHPAD_SIZE, 8)); 145 } 146 else 147 { 148 m_ui.scanStartAddress->setText(formatHexValue(Bus::BIOS_BASE, 8)); 149 m_ui.scanEndAddress->setText(formatHexValue(Bus::BIOS_BASE + Bus::BIOS_SIZE, 8)); 150 } 151 }); 152 connect(m_ui.scanNewSearch, &QPushButton::clicked, [this]() { 153 m_scanner.Search(); 154 updateResults(); 155 }); 156 connect(m_ui.scanSearchAgain, &QPushButton::clicked, [this]() { 157 m_scanner.SearchAgain(); 158 updateResults(); 159 }); 160 connect(m_ui.scanResetSearch, &QPushButton::clicked, [this]() { 161 m_scanner.ResetSearch(); 162 updateResults(); 163 }); 164 connect(m_ui.scanAddWatch, &QPushButton::clicked, this, &MemoryScannerWindow::addToWatchClicked); 165 connect(m_ui.scanAddManualAddress, &QPushButton::clicked, this, &MemoryScannerWindow::addManualWatchAddressClicked); 166 connect(m_ui.scanRemoveWatch, &QPushButton::clicked, this, &MemoryScannerWindow::removeWatchClicked); 167 connect(m_ui.scanTable, &QTableWidget::currentItemChanged, this, &MemoryScannerWindow::scanCurrentItemChanged); 168 connect(m_ui.watchTable, &QTableWidget::currentItemChanged, this, &MemoryScannerWindow::watchCurrentItemChanged); 169 connect(m_ui.scanTable, &QTableWidget::itemChanged, this, &MemoryScannerWindow::scanItemChanged); 170 connect(m_ui.watchTable, &QTableWidget::itemChanged, this, &MemoryScannerWindow::watchItemChanged); 171 172 m_update_timer = new QTimer(this); 173 connect(m_update_timer, &QTimer::timeout, this, &MemoryScannerWindow::updateScanUi); 174 175 connect(g_emu_thread, &EmuThread::systemStarted, this, &MemoryScannerWindow::onSystemStarted); 176 connect(g_emu_thread, &EmuThread::systemDestroyed, this, &MemoryScannerWindow::onSystemDestroyed); 177 178 if (QtHost::IsSystemValid()) 179 onSystemStarted(); 180 else 181 enableUi(false); 182 } 183 184 void MemoryScannerWindow::enableUi(bool enabled) 185 { 186 const bool has_results = (m_scanner.GetResultCount() > 0); 187 188 m_ui.scanValue->setEnabled(enabled); 189 m_ui.scanValueBase->setEnabled(enabled); 190 m_ui.scanValueSigned->setEnabled(enabled); 191 m_ui.scanSize->setEnabled(enabled); 192 m_ui.scanOperator->setEnabled(enabled); 193 m_ui.scanStartAddress->setEnabled(enabled); 194 m_ui.scanEndAddress->setEnabled(enabled); 195 m_ui.scanPresetRange->setEnabled(enabled); 196 m_ui.scanResultCount->setEnabled(enabled); 197 m_ui.scanNewSearch->setEnabled(enabled); 198 m_ui.scanSearchAgain->setEnabled(enabled && has_results); 199 m_ui.scanResetSearch->setEnabled(enabled && has_results); 200 m_ui.scanAddWatch->setEnabled(enabled && !m_ui.scanTable->selectedItems().empty()); 201 m_ui.watchTable->setEnabled(enabled); 202 m_ui.scanAddManualAddress->setEnabled(enabled); 203 m_ui.scanRemoveWatch->setEnabled(enabled && !m_ui.watchTable->selectedItems().empty()); 204 } 205 206 void MemoryScannerWindow::showEvent(QShowEvent* event) 207 { 208 QWidget::showEvent(event); 209 resizeColumns(); 210 } 211 212 void MemoryScannerWindow::closeEvent(QCloseEvent* event) 213 { 214 QWidget::closeEvent(event); 215 emit closed(); 216 } 217 218 void MemoryScannerWindow::resizeEvent(QResizeEvent* event) 219 { 220 QWidget::resizeEvent(event); 221 resizeColumns(); 222 } 223 224 void MemoryScannerWindow::resizeColumns() 225 { 226 QtUtils::ResizeColumnsForTableView(m_ui.scanTable, {-1, 130, 130}); 227 QtUtils::ResizeColumnsForTableView(m_ui.watchTable, {-1, 100, 100, 100, 40}); 228 } 229 230 int MemoryScannerWindow::getSelectedResultIndexFirst() const 231 { 232 QList<QTableWidgetSelectionRange> sel = m_ui.scanTable->selectedRanges(); 233 if (sel.isEmpty()) 234 return -1; 235 236 return sel.front().topRow(); 237 } 238 239 int MemoryScannerWindow::getSelectedResultIndexLast() const 240 { 241 QList<QTableWidgetSelectionRange> sel = m_ui.scanTable->selectedRanges(); 242 if (sel.isEmpty()) 243 return -1; 244 245 return sel.front().bottomRow(); 246 } 247 248 int MemoryScannerWindow::getSelectedWatchIndexFirst() const 249 { 250 QList<QTableWidgetSelectionRange> sel = m_ui.watchTable->selectedRanges(); 251 if (sel.isEmpty()) 252 return -1; 253 254 return sel.front().topRow(); 255 } 256 257 int MemoryScannerWindow::getSelectedWatchIndexLast() const 258 { 259 QList<QTableWidgetSelectionRange> sel = m_ui.watchTable->selectedRanges(); 260 if (sel.isEmpty()) 261 return -1; 262 263 return sel.front().bottomRow(); 264 } 265 266 void MemoryScannerWindow::onSystemStarted() 267 { 268 if (!m_update_timer->isActive()) 269 m_update_timer->start(SCAN_INTERVAL); 270 271 enableUi(true); 272 } 273 274 void MemoryScannerWindow::onSystemDestroyed() 275 { 276 if (m_update_timer->isActive()) 277 m_update_timer->stop(); 278 279 enableUi(false); 280 } 281 282 void MemoryScannerWindow::addToWatchClicked() 283 { 284 const int indexFirst = getSelectedResultIndexFirst(); 285 const int indexLast = getSelectedResultIndexLast(); 286 if (indexFirst < 0) 287 return; 288 289 for (int index = indexFirst; index <= indexLast; index++) 290 { 291 const MemoryScan::Result& res = m_scanner.GetResults()[static_cast<u32>(index)]; 292 m_watch.AddEntry(fmt::format("0x{:08x}", res.address), res.address, m_scanner.GetSize(), m_scanner.GetValueSigned(), 293 false); 294 updateWatch(); 295 } 296 } 297 298 void MemoryScannerWindow::addManualWatchAddressClicked() 299 { 300 std::optional<unsigned> address = QtUtils::PromptForAddress(this, windowTitle(), tr("Enter manual address:"), false); 301 if (!address.has_value()) 302 return; 303 304 QStringList items; 305 for (const char* title : s_size_strings) 306 items.append(tr(title)); 307 308 bool ok = false; 309 QString selected_item(QInputDialog::getItem(this, windowTitle(), tr("Select data size:"), items, 0, false, &ok)); 310 int index = items.indexOf(selected_item); 311 if (index < 0 || !ok) 312 return; 313 314 if (index == 1 || index == 4) 315 address.value() &= 0xFFFFFFFE; 316 else if (index == 2 || index == 5) 317 address.value() &= 0xFFFFFFFC; 318 319 m_watch.AddEntry(fmt::format("0x{:08x}", address.value()), address.value(), static_cast<MemoryAccessSize>(index % 3), 320 (index > 3), false); 321 updateWatch(); 322 } 323 324 void MemoryScannerWindow::removeWatchClicked() 325 { 326 const int indexFirst = getSelectedWatchIndexFirst(); 327 const int indexLast = getSelectedWatchIndexLast(); 328 if (indexFirst < 0) 329 return; 330 331 for (int index = indexLast; index >= indexFirst; index--) 332 { 333 m_watch.RemoveEntry(static_cast<u32>(index)); 334 updateWatch(); 335 } 336 } 337 338 void MemoryScannerWindow::scanCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous) 339 { 340 m_ui.scanAddWatch->setEnabled((current != nullptr)); 341 } 342 343 void MemoryScannerWindow::watchCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous) 344 { 345 m_ui.scanRemoveWatch->setEnabled((current != nullptr)); 346 } 347 348 void MemoryScannerWindow::scanItemChanged(QTableWidgetItem* item) 349 { 350 const u32 index = static_cast<u32>(item->row()); 351 switch (item->column()) 352 { 353 case 1: 354 { 355 bool value_ok = false; 356 if (m_scanner.GetValueSigned()) 357 { 358 int value = item->text().toInt(&value_ok); 359 if (value_ok) 360 m_scanner.SetResultValue(index, static_cast<u32>(value)); 361 } 362 else 363 { 364 uint value = item->text().toUInt(&value_ok); 365 if (value_ok) 366 m_scanner.SetResultValue(index, static_cast<u32>(value)); 367 } 368 } 369 break; 370 371 default: 372 break; 373 } 374 } 375 376 void MemoryScannerWindow::watchItemChanged(QTableWidgetItem* item) 377 { 378 const u32 index = static_cast<u32>(item->row()); 379 if (index >= m_watch.GetEntryCount()) 380 return; 381 382 switch (item->column()) 383 { 384 case 4: 385 { 386 m_watch.SetEntryFreeze(index, (item->checkState() == Qt::Checked)); 387 } 388 break; 389 390 case 0: 391 { 392 m_watch.SetEntryDescription(index, item->text().toStdString()); 393 } 394 break; 395 396 case 3: 397 { 398 const MemoryWatchList::Entry& entry = m_watch.GetEntry(index); 399 bool value_ok = false; 400 if (entry.is_signed) 401 { 402 int value = item->text().toInt(&value_ok); 403 if (value_ok) 404 m_watch.SetEntryValue(index, static_cast<u32>(value)); 405 } 406 else 407 { 408 uint value; 409 if (item->text()[1] == 'x' || item->text()[1] == 'X') 410 value = item->text().toUInt(&value_ok, 16); 411 else 412 value = item->text().toUInt(&value_ok); 413 if (value_ok) 414 m_watch.SetEntryValue(index, static_cast<u32>(value)); 415 } 416 } 417 break; 418 419 default: 420 break; 421 } 422 } 423 424 void MemoryScannerWindow::updateScanValue() 425 { 426 QString value = m_ui.scanValue->text(); 427 if (value.startsWith(QStringLiteral("0x"))) 428 value.remove(0, 2); 429 430 bool ok = false; 431 uint uint_value = value.toUInt(&ok, (m_ui.scanValueBase->currentIndex() > 0) ? 16 : 10); 432 if (ok) 433 m_scanner.SetValue(uint_value); 434 } 435 436 void MemoryScannerWindow::updateResults() 437 { 438 QSignalBlocker sb(m_ui.scanTable); 439 m_ui.scanTable->setRowCount(0); 440 441 int row = 0; 442 const MemoryScan::ResultVector& results = m_scanner.GetResults(); 443 for (const MemoryScan::Result& res : results) 444 { 445 if (row == MAX_DISPLAYED_SCAN_RESULTS) 446 break; 447 448 m_ui.scanTable->insertRow(row); 449 450 QTableWidgetItem* address_item = new QTableWidgetItem(formatHexValue(res.address, 8)); 451 address_item->setFlags(address_item->flags() & ~(Qt::ItemIsEditable)); 452 m_ui.scanTable->setItem(row, 0, address_item); 453 454 QTableWidgetItem* value_item; 455 if (m_ui.scanValueBase->currentIndex() == 0) 456 value_item = new QTableWidgetItem(formatValue(res.value, m_scanner.GetValueSigned())); 457 else if (m_scanner.GetSize() == MemoryAccessSize::Byte) 458 value_item = new QTableWidgetItem(formatHexValue(res.value, 2)); 459 else if (m_scanner.GetSize() == MemoryAccessSize::HalfWord) 460 value_item = new QTableWidgetItem(formatHexValue(res.value, 4)); 461 else 462 value_item = new QTableWidgetItem(formatHexValue(res.value, 8)); 463 m_ui.scanTable->setItem(row, 1, value_item); 464 465 QTableWidgetItem* previous_item; 466 if (m_ui.scanValueBase->currentIndex() == 0) 467 previous_item = new QTableWidgetItem(formatValue(res.last_value, m_scanner.GetValueSigned())); 468 else if (m_scanner.GetSize() == MemoryAccessSize::Byte) 469 previous_item = new QTableWidgetItem(formatHexValue(res.last_value, 2)); 470 else if (m_scanner.GetSize() == MemoryAccessSize::HalfWord) 471 previous_item = new QTableWidgetItem(formatHexValue(res.last_value, 4)); 472 else 473 previous_item = new QTableWidgetItem(formatHexValue(res.last_value, 8)); 474 475 previous_item->setFlags(address_item->flags() & ~(Qt::ItemIsEditable)); 476 m_ui.scanTable->setItem(row, 2, previous_item); 477 row++; 478 } 479 480 m_ui.scanResultCount->setText((row < static_cast<int>(results.size())) ? 481 tr("%1 (only showing first %2)").arg(results.size()).arg(row) : 482 QString::number(m_scanner.GetResultCount())); 483 484 m_ui.scanResetSearch->setEnabled(!results.empty()); 485 m_ui.scanSearchAgain->setEnabled(!results.empty()); 486 m_ui.scanAddWatch->setEnabled(false); 487 } 488 489 void MemoryScannerWindow::updateResultsValues() 490 { 491 QSignalBlocker sb(m_ui.scanTable); 492 493 int row = 0; 494 for (const MemoryScan::Result& res : m_scanner.GetResults()) 495 { 496 if (res.value_changed) 497 { 498 QTableWidgetItem* item = m_ui.scanTable->item(row, 1); 499 if (m_ui.scanValueBase->currentIndex() == 0) 500 item->setText(formatValue(res.value, m_scanner.GetValueSigned())); 501 else if (m_scanner.GetSize() == MemoryAccessSize::Byte) 502 item->setText(formatHexValue(res.value, 2)); 503 else if (m_scanner.GetSize() == MemoryAccessSize::HalfWord) 504 item->setText(formatHexValue(res.value, 4)); 505 else 506 item->setText(formatHexValue(res.value, 8)); 507 item->setForeground(Qt::red); 508 } 509 510 row++; 511 if (row == MAX_DISPLAYED_SCAN_RESULTS) 512 break; 513 } 514 } 515 516 void MemoryScannerWindow::updateWatch() 517 { 518 m_watch.UpdateValues(); 519 520 QSignalBlocker sb(m_ui.watchTable); 521 m_ui.watchTable->setRowCount(0); 522 523 const MemoryWatchList::EntryVector& entries = m_watch.GetEntries(); 524 if (!entries.empty()) 525 { 526 int row = 0; 527 for (const MemoryWatchList::Entry& res : entries) 528 { 529 m_ui.watchTable->insertRow(row); 530 531 QTableWidgetItem* description_item = new QTableWidgetItem(formatCheatCode(res.address, res.value, res.size)); 532 m_ui.watchTable->setItem(row, 0, description_item); 533 534 QTableWidgetItem* address_item = new QTableWidgetItem(formatHexValue(res.address, 8)); 535 address_item->setFlags(address_item->flags() & ~(Qt::ItemIsEditable)); 536 m_ui.watchTable->setItem(row, 1, address_item); 537 538 QTableWidgetItem* size_item = 539 new QTableWidgetItem(tr(s_size_strings[static_cast<u32>(res.size) + (res.is_signed ? 3 : 0)])); 540 size_item->setFlags(address_item->flags() & ~(Qt::ItemIsEditable)); 541 m_ui.watchTable->setItem(row, 2, size_item); 542 543 QTableWidgetItem* value_item; 544 if (res.size == MemoryAccessSize::Byte) 545 value_item = new QTableWidgetItem(formatHexAndDecValue(res.value, 2, res.is_signed)); 546 else if (res.size == MemoryAccessSize::HalfWord) 547 value_item = new QTableWidgetItem(formatHexAndDecValue(res.value, 4, res.is_signed)); 548 else 549 value_item = new QTableWidgetItem(formatHexAndDecValue(res.value, 8, res.is_signed)); 550 551 m_ui.watchTable->setItem(row, 3, value_item); 552 553 QTableWidgetItem* freeze_item = new QTableWidgetItem(); 554 freeze_item->setFlags(freeze_item->flags() | (Qt::ItemIsEditable | Qt::ItemIsUserCheckable)); 555 freeze_item->setCheckState(res.freeze ? Qt::Checked : Qt::Unchecked); 556 m_ui.watchTable->setItem(row, 4, freeze_item); 557 558 row++; 559 } 560 } 561 562 m_ui.scanSaveWatch->setEnabled(!entries.empty()); 563 m_ui.scanRemoveWatch->setEnabled(false); 564 } 565 566 void MemoryScannerWindow::updateWatchValues() 567 { 568 QSignalBlocker sb(m_ui.watchTable); 569 int row = 0; 570 for (const MemoryWatchList::Entry& res : m_watch.GetEntries()) 571 { 572 if (res.changed) 573 { 574 if (m_ui.scanValueBase->currentIndex() == 0) 575 m_ui.watchTable->item(row, 3)->setText(formatValue(res.value, res.is_signed)); 576 else if (m_scanner.GetSize() == MemoryAccessSize::Byte) 577 m_ui.watchTable->item(row, 3)->setText(formatHexValue(res.value, 2)); 578 else if (m_scanner.GetSize() == MemoryAccessSize::HalfWord) 579 m_ui.watchTable->item(row, 3)->setText(formatHexValue(res.value, 4)); 580 else 581 m_ui.watchTable->item(row, 3)->setText(formatHexValue(res.value, 8)); 582 } 583 row++; 584 } 585 } 586 587 void MemoryScannerWindow::updateScanUi() 588 { 589 m_scanner.UpdateResultsValues(); 590 m_watch.UpdateValues(); 591 592 updateResultsValues(); 593 updateWatchValues(); 594 }