diff --git a/Source/Project64-core/Settings.cpp b/Source/Project64-core/Settings.cpp
index f487df6b7..abaedb785 100644
--- a/Source/Project64-core/Settings.cpp
+++ b/Source/Project64-core/Settings.cpp
@@ -350,7 +350,6 @@ void CSettings::AddHowToHandleSetting(const char * BaseDirectory)
AddHandler(Debugger_WriteBPExists, new CSettingTypeTempBool(false));
AddHandler(Debugger_ReadBPExists, new CSettingTypeTempBool(false));
AddHandler(Debugger_WaitingForStep, new CSettingTypeTempBool(false));
- AddHandler(Debugger_AutoRefreshMemoryView, new CSettingTypeApplication("Debugger", "Auto Refresh Memory View", true));
AddHandler(Debugger_CPULoggingEnabled, new CSettingTypeApplication("Debugger", "Enable CPU Logging", false));
AddHandler(Debugger_CPULogBufferSize, new CSettingTypeApplication("Debugger", "CPU Log Buffer Size", (uint32_t)1024));
AddHandler(Debugger_ExceptionBreakpoints, new CSettingTypeApplication("Debugger", "Exception Breakpoints", (uint32_t)0));
diff --git a/Source/Project64-core/Settings/SettingsID.h b/Source/Project64-core/Settings/SettingsID.h
index 0992da1a2..0ecdd7971 100644
--- a/Source/Project64-core/Settings/SettingsID.h
+++ b/Source/Project64-core/Settings/SettingsID.h
@@ -260,7 +260,6 @@ enum SettingID
Debugger_WriteBPExists,
Debugger_ReadBPExists,
Debugger_WaitingForStep,
- Debugger_AutoRefreshMemoryView,
Debugger_CPULoggingEnabled,
Debugger_CPULogBufferSize,
Debugger_ExceptionBreakpoints,
diff --git a/Source/Project64/Project64.vcxproj b/Source/Project64/Project64.vcxproj
index 769c032f2..3794474f6 100644
--- a/Source/Project64/Project64.vcxproj
+++ b/Source/Project64/Project64.vcxproj
@@ -99,6 +99,7 @@
+
@@ -131,6 +132,7 @@
+
@@ -166,6 +168,7 @@
+
@@ -201,6 +204,7 @@
+
diff --git a/Source/Project64/Project64.vcxproj.filters b/Source/Project64/Project64.vcxproj.filters
index 3c6f1726f..81e4cb585 100644
--- a/Source/Project64/Project64.vcxproj.filters
+++ b/Source/Project64/Project64.vcxproj.filters
@@ -237,6 +237,12 @@
Source Files\User Interface Source\Settings Source
+
+ Source Files\User Interface Source\WTL Controls Source
+
+
+ Source Files\User Interface Source\Debugger Source
+
@@ -455,6 +461,12 @@
Header Files\User Interface Headers\Settings Header
+
+ Header Files\User Interface Headers\WTL Controls Headers
+
+
+ Header Files\User Interface Headers\Debugger Headers
+
diff --git a/Source/Project64/UserInterface/Debugger/DebugMMU.cpp b/Source/Project64/UserInterface/Debugger/DebugMMU.cpp
new file mode 100644
index 000000000..ee817e9b0
--- /dev/null
+++ b/Source/Project64/UserInterface/Debugger/DebugMMU.cpp
@@ -0,0 +1,304 @@
+#include
+
+#include "DebugMMU.h"
+#include
+
+uint32_t* CDebugMMU::PAddrWordPtr(uint32_t paddr)
+{
+ if (g_MMU == NULL)
+ {
+ return NULL;
+ }
+
+ paddr = paddr & ~3;
+
+ // RDRAM & DMEM/IMEM
+ if ((paddr < g_MMU->RdramSize()) ||
+ (paddr >= 0x04000000 && paddr <= 0x04001FFF))
+ {
+ return (uint32_t*)(g_MMU->Rdram() + paddr);
+ }
+
+ // 64DD buffer
+ if (paddr >= 0x05000000 && paddr <= 0x050004FF)
+ {
+ // todo
+ return NULL;
+ }
+
+ // Cartridge Domain 1 (Address 1) (64DD IPL ROM)
+ if (paddr >= 0x06000000 && paddr <= 0x06FFFFFF)
+ {
+ uint32_t iplRomOffset = paddr - 0x06000000;
+
+ if (g_DDRom != NULL && iplRomOffset < g_DDRom->GetRomSize())
+ {
+ return (uint32_t*)(g_MMU->Rdram() + paddr);
+ }
+ return NULL;
+ }
+
+ // Cartridge Domain 2 (Address 2) (SRAM/FlashRAM)
+ if (paddr >= 0x08000000 && paddr < 0x08FFFFFF)
+ {
+ // stored in a file
+ return NULL;
+ }
+
+ // Cartridge ROM
+ if (paddr >= 0x10000000 && paddr <= 0x15FFFFFF)
+ {
+ uint32_t cartRomOffset = paddr - 0x10000000;
+ if (g_Rom != NULL && cartRomOffset < g_Rom->GetRomSize())
+ {
+ return (uint32_t*)(g_Rom->GetRomAddress() + cartRomOffset);
+ }
+ return false;
+ }
+
+ // PIF ROM
+ if (paddr >= 0x1FC00000 && paddr <= 0x1FC007BF)
+ {
+ return NULL;
+ }
+
+ // PIF RAM
+ if (paddr >= 0x1FC007C0 && paddr <= 0x1FC007FF)
+ {
+ uint32_t pifRamOffset = paddr - 0x1FC007C0;
+ return (uint32_t*)(g_MMU->PifRam() + pifRamOffset);
+ }
+
+ switch (paddr)
+ {
+ case 0x03F00000: return &g_Reg->RDRAM_CONFIG_REG;
+ case 0x03F00004: return &g_Reg->RDRAM_DEVICE_ID_REG;
+ case 0x03F00008: return &g_Reg->RDRAM_DELAY_REG;
+ case 0x03F0000C: return &g_Reg->RDRAM_MODE_REG;
+ case 0x03F00010: return &g_Reg->RDRAM_REF_INTERVAL_REG;
+ case 0x03F00014: return &g_Reg->RDRAM_REF_ROW_REG;
+ case 0x03F00018: return &g_Reg->RDRAM_RAS_INTERVAL_REG;
+ case 0x03F0001C: return &g_Reg->RDRAM_MIN_INTERVAL_REG;
+ case 0x03F00020: return &g_Reg->RDRAM_ADDR_SELECT_REG;
+ case 0x03F00024: return &g_Reg->RDRAM_DEVICE_MANUF_REG;
+ case 0x04040010: return &g_Reg->SP_STATUS_REG;
+ case 0x04040014: return &g_Reg->SP_DMA_FULL_REG;
+ case 0x04040018: return &g_Reg->SP_DMA_BUSY_REG;
+ case 0x0404001C: return &g_Reg->SP_SEMAPHORE_REG;
+ case 0x04080000: return &g_Reg->SP_PC_REG;
+ case 0x0410000C: return &g_Reg->DPC_STATUS_REG;
+ case 0x04100010: return &g_Reg->DPC_CLOCK_REG;
+ case 0x04100014: return &g_Reg->DPC_BUFBUSY_REG;
+ case 0x04100018: return &g_Reg->DPC_PIPEBUSY_REG;
+ case 0x0410001C: return &g_Reg->DPC_TMEM_REG;
+ case 0x04300000: return &g_Reg->MI_MODE_REG;
+ case 0x04300004: return &g_Reg->MI_VERSION_REG;
+ case 0x04300008: return &g_Reg->MI_INTR_REG;
+ case 0x0430000C: return &g_Reg->MI_INTR_MASK_REG;
+ case 0x04400000: return &g_Reg->VI_STATUS_REG;
+ case 0x04400004: return &g_Reg->VI_ORIGIN_REG;
+ case 0x04400008: return &g_Reg->VI_WIDTH_REG;
+ case 0x0440000C: return &g_Reg->VI_INTR_REG;
+ case 0x04400010: return &g_Reg->VI_V_CURRENT_LINE_REG;
+ case 0x04400014: return &g_Reg->VI_BURST_REG;
+ case 0x04400018: return &g_Reg->VI_V_SYNC_REG;
+ case 0x0440001C: return &g_Reg->VI_H_SYNC_REG;
+ case 0x04400020: return &g_Reg->VI_LEAP_REG;
+ case 0x04400024: return &g_Reg->VI_H_START_REG;
+ case 0x04400028: return &g_Reg->VI_V_START_REG;
+ case 0x0440002C: return &g_Reg->VI_V_BURST_REG;
+ case 0x04400030: return &g_Reg->VI_X_SCALE_REG;
+ case 0x04400034: return &g_Reg->VI_Y_SCALE_REG;
+ case 0x04600000: return &g_Reg->PI_DRAM_ADDR_REG;
+ case 0x04600004: return &g_Reg->PI_CART_ADDR_REG;
+ case 0x04600008: return &g_Reg->PI_RD_LEN_REG;
+ case 0x0460000C: return &g_Reg->PI_WR_LEN_REG;
+ case 0x04600010: return &g_Reg->PI_STATUS_REG;
+ case 0x04600014: return &g_Reg->PI_DOMAIN1_REG;
+ case 0x04600018: return &g_Reg->PI_BSD_DOM1_PWD_REG;
+ case 0x0460001C: return &g_Reg->PI_BSD_DOM1_PGS_REG;
+ case 0x04600020: return &g_Reg->PI_BSD_DOM1_RLS_REG;
+ case 0x04600024: return &g_Reg->PI_DOMAIN2_REG;
+ case 0x04600028: return &g_Reg->PI_BSD_DOM2_PWD_REG;
+ case 0x0460002C: return &g_Reg->PI_BSD_DOM2_PGS_REG;
+ case 0x04600030: return &g_Reg->PI_BSD_DOM2_RLS_REG;
+ case 0x04700000: return &g_Reg->RI_MODE_REG;
+ case 0x04700004: return &g_Reg->RI_CONFIG_REG;
+ case 0x04700008: return &g_Reg->RI_CURRENT_LOAD_REG;
+ case 0x0470000C: return &g_Reg->RI_SELECT_REG;
+ case 0x04700010: return &g_Reg->RI_REFRESH_REG;
+ case 0x04700014: return &g_Reg->RI_LATENCY_REG;
+ case 0x04700018: return &g_Reg->RI_RERROR_REG;
+ case 0x0470001C: return &g_Reg->RI_WERROR_REG;
+ case 0x04800018: return &g_Reg->SI_STATUS_REG;
+ case 0x05000500: return &g_Reg->ASIC_DATA;
+ case 0x05000504: return &g_Reg->ASIC_MISC_REG;
+ case 0x05000508: return &g_Reg->ASIC_STATUS;
+ case 0x0500050C: return &g_Reg->ASIC_CUR_TK;
+ case 0x05000510: return &g_Reg->ASIC_BM_STATUS;
+ case 0x05000514: return &g_Reg->ASIC_ERR_SECTOR;
+ case 0x05000518: return &g_Reg->ASIC_SEQ_STATUS;
+ case 0x0500051C: return &g_Reg->ASIC_CUR_SECTOR;
+ case 0x05000520: return &g_Reg->ASIC_HARD_RESET;
+ case 0x05000524: return &g_Reg->ASIC_C1_S0;
+ case 0x05000528: return &g_Reg->ASIC_HOST_SECBYTE;
+ case 0x0500052C: return &g_Reg->ASIC_C1_S2;
+ case 0x05000530: return &g_Reg->ASIC_SEC_BYTE;
+ case 0x05000534: return &g_Reg->ASIC_C1_S4;
+ case 0x05000538: return &g_Reg->ASIC_C1_S6;
+ case 0x0500053C: return &g_Reg->ASIC_CUR_ADDR;
+ case 0x05000540: return &g_Reg->ASIC_ID_REG;
+ case 0x05000544: return &g_Reg->ASIC_TEST_REG;
+ case 0x05000548: return &g_Reg->ASIC_TEST_PIN_SEL;
+ }
+
+ return NULL;
+}
+
+bool CDebugMMU::DebugLW_PAddr(uint32_t paddr, uint32_t& value)
+{
+ if (g_MMU == NULL)
+ {
+ return false;
+ }
+
+ uint32_t* ptr = PAddrWordPtr(paddr);
+
+ if (ptr != NULL)
+ {
+ value = *ptr;
+ return true;
+ }
+
+ if (paddr >= 0x08000000 && paddr < 0x08FFFFFF) // Cartridge Domain 2 (Address 2)
+ {
+ uint32_t saveOffset = paddr & 0x000FFFFF;
+
+ if (g_System->m_SaveUsing == SaveChip_Sram && saveOffset <= 0x7FFF) // sram
+ {
+ uint8_t tmp[4] = "";
+ CSram *sram = g_MMU->GetSram();
+ sram->DmaFromSram(tmp, paddr - 0x08000000, 4);
+ value = tmp[3] << 24 | tmp[2] << 16 | tmp[1] << 8 | tmp[0];
+ return true;
+ }
+ else if (g_System->m_SaveUsing == SaveChip_FlashRam && saveOffset == 0) // flash ram status
+ {
+ CFlashram* flashRam = g_MMU->GetFlashram();
+ value = flashRam->ReadFromFlashStatus(0x08000000);
+ return true;
+ }
+ }
+
+ if (paddr == 0x04500004)
+ {
+ if (g_System->bFixedAudio())
+ {
+ value = g_Audio->GetLength();
+ }
+ else
+ {
+ CAudioPlugin* audioPlg = g_Plugins->Audio();
+ value = (audioPlg->AiReadLength != NULL) ? audioPlg->AiReadLength() : 0;
+ }
+ return true;
+ }
+
+ if (paddr == 0x0450000C)
+ {
+ value = g_System->bFixedAudio() ? g_Audio->GetStatus() : g_Reg->AI_STATUS_REG;
+ return true;
+ }
+
+ return false;
+}
+
+bool CDebugMMU::DebugLW_VAddr(uint32_t vaddr, uint32_t& value)
+{
+ if (vaddr <= 0x7FFFFFFF || vaddr >= 0xC0000000) // KUSEG, KSEG2 (TLB)
+ {
+ if (g_MMU == NULL)
+ {
+ return false;
+ }
+
+ return g_MMU->LW_VAddr(vaddr, value);
+ }
+
+ uint32_t paddr = vaddr & 0x1FFFFFFF;
+ return DebugLW_PAddr(paddr, value);
+}
+
+bool CDebugMMU::DebugLB_PAddr(uint32_t vaddr, uint8_t& value)
+{
+ uint32_t word;
+ if (!DebugLW_PAddr(vaddr & ~3, word))
+ {
+ return false;
+ }
+ value = (word >> (24 - (vaddr & 3) * 8)) & 0xFF;
+ return true;
+}
+
+bool CDebugMMU::DebugLB_VAddr(uint32_t vaddr, uint8_t& value)
+{
+ uint32_t word;
+ if (!DebugLW_VAddr(vaddr & ~3, word))
+ {
+ return false;
+ }
+ value = (word >> (24 - (vaddr & 3) * 8)) & 0xFF;
+ return true;
+}
+
+bool CDebugMMU::DebugSB_PAddr(uint32_t paddr, uint8_t value)
+{
+ bool bWriteToRom = false;
+
+ if (paddr >= 0x10000000 && paddr <= 0x1FBFFFFF)
+ {
+ uint32_t romOffset = paddr - 0x10000000;
+ if (romOffset > g_Rom->GetRomSize())
+ {
+ return false;
+ }
+ bWriteToRom = true;
+ }
+
+ int nbyte = 3 - (paddr & 3);
+ uint8_t* ptr = (uint8_t*)PAddrWordPtr(paddr & ~3);
+
+ if (ptr == NULL)
+ {
+ return false;
+ }
+
+ if (bWriteToRom)
+ {
+ ProtectMemory(g_Rom->GetRomAddress(), g_Rom->GetRomSize(), MEM_READWRITE);
+ }
+
+ ptr[nbyte] = value;
+
+ if (bWriteToRom)
+ {
+ ProtectMemory(g_Rom->GetRomAddress(), g_Rom->GetRomSize(), MEM_READONLY);
+ }
+ return true;
+}
+
+bool CDebugMMU::DebugSB_VAddr(uint32_t vaddr, uint8_t value)
+{
+ if (vaddr <= 0x7FFFFFFF || vaddr >= 0xC0000000) // KUSEG, KSEG2 (TLB)
+ {
+ if (g_MMU == NULL)
+ {
+ return false;
+ }
+
+ return g_MMU->SB_VAddr(vaddr, value);
+ }
+
+ uint32_t paddr = vaddr & 0x1FFFFFFF;
+ return DebugSB_PAddr(paddr, value);
+}
diff --git a/Source/Project64/UserInterface/Debugger/DebugMMU.h b/Source/Project64/UserInterface/Debugger/DebugMMU.h
new file mode 100644
index 000000000..857a32340
--- /dev/null
+++ b/Source/Project64/UserInterface/Debugger/DebugMMU.h
@@ -0,0 +1,15 @@
+#pragma once
+#include
+
+class CDebugMMU
+{
+private:
+ uint32_t* PAddrWordPtr(uint32_t paddr);
+public:
+ bool DebugLW_PAddr(uint32_t paddr, uint32_t& value);
+ bool DebugLW_VAddr(uint32_t vaddr, uint32_t& value);
+ bool DebugLB_PAddr(uint32_t paddr, uint8_t& value);
+ bool DebugLB_VAddr(uint32_t vaddr, uint8_t& value);
+ bool DebugSB_PAddr(uint32_t paddr, uint8_t value);
+ bool DebugSB_VAddr(uint32_t vaddr, uint8_t value);
+};
\ No newline at end of file
diff --git a/Source/Project64/UserInterface/Debugger/Debugger-ViewMemory.cpp b/Source/Project64/UserInterface/Debugger/Debugger-ViewMemory.cpp
index fc7a87ea2..dceabfc7d 100644
--- a/Source/Project64/UserInterface/Debugger/Debugger-ViewMemory.cpp
+++ b/Source/Project64/UserInterface/Debugger/Debugger-ViewMemory.cpp
@@ -12,23 +12,49 @@
#include
#include
+#include
+
#include "DebuggerUI.h"
#include "Symbols.h"
#include "DMALog.h"
-CDebugMemoryView* CDebugMemoryView::_this = NULL;
-HHOOK CDebugMemoryView::hWinMessageHook = NULL;
+CDebugMemoryView::jump_item_t CDebugMemoryView::JumpItems[] = {
+ { 0x80000000, 0x00000000, 0x0800000, "RDRAM" },
+ { 0xA3F00000, 0x03F00000, 0x0000028, "RDRAM Registers" },
+ { 0xA4000000, 0x04000000, 0x0001000, "SP DMEM" },
+ { 0xA4001000, 0x04001000, 0x0001000, "SP IMEM" },
+ { 0xA4040000, 0x04040000, 0x0000020, "SP Registers" },
+ { 0xA4080000, 0x04080000, 0x0000004, "SP PC Register" },
+ { 0xA4100000, 0x04100000, 0x0000020, "DP Control Registers" },
+ { 0xA4300000, 0x04300000, 0x0000010, "MI Registers" },
+ { 0xA4400000, 0x04400000, 0x0000038, "VI Registers" },
+ { 0xA4500000, 0x04500000, 0x0000018, "AI Registers" },
+ { 0xA4600000, 0x04600000, 0x0000034, "PI Registers" },
+ { 0xA4700000, 0x04700000, 0x0000020, "RI Registers" },
+ { 0xA4800000, 0x04800000, 0x0000010, "SI Registers" },
+ { 0xA5000500, 0x05000500, 0x000004C, "DD Registers" },
+ { 0xA8000000, 0xA8000000, 0x0000000, "Cartridge Save Data" },
+ { 0xB0000000, 0x10000000, 0xFC00000, "Cartridge ROM" },
+ { 0xBFC00000, 0x1FC00000, 0x00007C0, "PIF ROM" },
+ { 0xBFC007C0, 0x1FC007C0, 0x0000040, "PIF RAM" },
+ { 0, NULL}
+};
CDebugMemoryView::CDebugMemoryView(CDebuggerUI * debugger) :
CDebugDialog(debugger),
- m_MemoryList(NULL)
+ CDialogResize(),
+ CToolTipDialog(),
+ m_Breakpoints(NULL),
+ m_WriteTargetColorStride(0),
+ m_ReadTargetColorStride(0),
+ m_SymbolColorStride(0),
+ m_SymbolColorPhase(0),
+ m_bIgnoreAddressInput(false),
+ m_HotAddress(0),
+ m_bVirtualMemory(true),
+ m_ContextMenuAddress(0),
+ m_bSafeEditMode(false)
{
- if (m_MemoryList == NULL)
- {
- m_MemoryList = new CListCtrl;
- m_MemoryList->RegisterClass();
- }
-
m_Breakpoints = m_Debugger->Breakpoints();
}
@@ -36,16 +62,258 @@ CDebugMemoryView::~CDebugMemoryView()
{
}
+void CDebugMemoryView::ShowAddress(uint32_t address, bool bVirtual)
+{
+ if (m_hWnd == NULL)
+ {
+ return;
+ }
+
+ SendMessage(WM_SHOWADDRESS, (WPARAM)address, (LPARAM)bVirtual);
+}
+
+bool CDebugMemoryView::GetByte(uint32_t address, uint8_t* value)
+{
+ if (m_bVirtualMemory)
+ {
+ return m_Debugger->DebugLB_VAddr(address, *value);
+ }
+ else
+ {
+ return m_Debugger->DebugLB_PAddr(address, *value);
+ }
+}
+
+bool CDebugMemoryView::SetByte(uint32_t address, uint8_t value)
+{
+ if (m_bVirtualMemory)
+ {
+ return m_Debugger->DebugSB_VAddr(address, value);
+ }
+ else
+ {
+ return m_Debugger->DebugSB_PAddr(address, value);
+ }
+}
+
+void CDebugMemoryView::CopyTextToClipboard(const char* text)
+{
+ size_t length = strlen(text);
+ HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, length + 1);
+ strcpy((char*)GlobalLock(hMem), text);
+ GlobalUnlock(hMem);
+ OpenClipboard();
+ EmptyClipboard();
+ SetClipboardData(CF_TEXT, hMem);
+ CloseClipboard();
+}
+
+void CDebugMemoryView::CopyBytesToClipboard(uint32_t startAddress, uint32_t endAddress, bool bHex, bool bIncludeAddresses, bool bRowAddresses)
+{
+ uint32_t baseAddress = m_HexEditCtrl.GetBaseAddress();
+ int groupSize = m_HexEditCtrl.GetNumBytesPerGroup();
+ int rowSize = m_HexEditCtrl.GetNumBytesPerRow();
+
+ stdstr str = "";
+
+ for (uint32_t address = startAddress; address <= endAddress; address++)
+ {
+ int offsetFromBase = address - baseAddress;
+ int offsetFromSelStart = address - startAddress;
+
+ uint8_t value;
+ GetByte(address, &value);
+
+ if (bIncludeAddresses)
+ {
+ if ((bRowAddresses && offsetFromBase % rowSize == 0) ||
+ (!bRowAddresses && offsetFromBase % groupSize == 0) ||
+ (offsetFromSelStart == 0))
+ {
+ str += stdstr_f("%08X: ", address);
+ }
+ }
+
+ if (bHex)
+ {
+ str += stdstr_f("%02X", value);
+ }
+ else
+ {
+ str += CHexEditCtrl::ByteAscii(value);
+ }
+
+ if ((offsetFromBase + 1) % rowSize == 0 || (bIncludeAddresses && !bRowAddresses && (offsetFromBase + 1) % groupSize == 0))
+ {
+ str += "\r\n";
+ }
+ else if (bHex && (offsetFromBase + 1) % groupSize == 0)
+ {
+ str += " ";
+ }
+ }
+
+ CopyTextToClipboard(str.Trim(" \r\n").c_str());
+}
+
+void CDebugMemoryView::CopyGameSharkCodeToClipboard(uint32_t startAddress, uint32_t endAddress)
+{
+ stdstr str = "";
+
+ if (startAddress & 1)
+ {
+ uint8_t value = 0;
+ GetByte(startAddress, &value);
+ str += stdstr_f("%08X %04X\r\n", startAddress, value);
+ startAddress++;
+ }
+
+ for (uint32_t address = startAddress; address < endAddress; address += 2)
+ {
+ uint8_t value0 = 0, value1 = 0;
+ GetByte(address + 0, &value0);
+ GetByte(address + 1, &value1);
+ str += stdstr_f("%08X %02X%02X\r\n", address | 0x01000000, value0, value1);
+ }
+
+ if (!(endAddress & 1))
+ {
+ uint8_t value = 0;
+ GetByte(endAddress, &value);
+ str += stdstr_f("%08X %04X\r\n", endAddress, value);
+ }
+
+ CopyTextToClipboard(str.Trim("\n").c_str());
+}
+
+void CDebugMemoryView::FillRange(uint32_t startAddress, uint32_t endAddress, uint8_t value)
+{
+ for (uint32_t address = startAddress; address <= endAddress; address++)
+ {
+ SetByte(address, value);
+ }
+}
+
+void CDebugMemoryView::FollowPointer(bool bContextMenuAddress)
+{
+ uint32_t address;
+
+ if (bContextMenuAddress)
+ {
+ address = m_ContextMenuAddress - (m_ContextMenuAddress % 4);
+ }
+ else
+ {
+ address = m_HexEditCtrl.GetCaretAddress();
+ address -= (address % 4);
+ }
+
+ address += (m_bVirtualMemory ? 0 : 0x80000000);
+
+ uint32_t pointer;
+ if (m_Debugger->DebugLW_VAddr(address, pointer))
+ {
+ OpenNewTab(pointer, m_bVirtualMemory, 4, true, true);
+ }
+}
+
+
+void CDebugMemoryView::JumpToSelection(void)
+{
+ uint32_t startAddress, endAddress;
+ bool bHaveSelection = m_HexEditCtrl.GetSelectionRange(&startAddress, &endAddress);
+ uint32_t targetAddress = bHaveSelection ? startAddress : m_HexEditCtrl.GetCaretAddress();
+ m_MemAddr.SetValue(targetAddress, false, true);
+}
+
+bool CDebugMemoryView::GetSafeEditValue(uint32_t address, uint8_t* value)
+{
+ if (m_SafeEditQueue.size() == 0)
+ {
+ return false;
+ }
+
+ for(size_t i = m_SafeEditQueue.size(); i-- > 0;)
+ {
+ edit_t edit = m_SafeEditQueue[i];
+ if (address >= edit.startAddress && address <= edit.endAddress)
+ {
+ *value = edit.value;
+ return true;
+ }
+ }
+ return false;
+}
+
+void CDebugMemoryView::ApplySafeEdits(void)
+{
+ for (size_t i = 0; i < m_SafeEditQueue.size(); i++)
+ {
+ edit_t edit = m_SafeEditQueue[i];
+ if (edit.type == SE_FILL)
+ {
+ FillRange(edit.startAddress, edit.endAddress, edit.value);
+ }
+ }
+
+ m_SafeEditQueue.clear();
+}
+
+void CDebugMemoryView::SetupJumpMenu(bool bVirtual)
+{
+ m_CmbJump.SetRedraw(FALSE);
+ m_CmbJump.ResetContent();
+
+ for (int i = 0;; i++)
+ {
+ jump_item_t* item = &JumpItems[i];
+
+ if (item->caption == NULL)
+ {
+ break;
+ }
+
+ m_CmbJump.AddString(stdstr_f("%08X %s", bVirtual ? item->vaddr : item->paddr, item->caption).c_str());
+ }
+
+ m_CmbJump.SetRedraw(TRUE);
+}
+
+int CDebugMemoryView::GetJumpItemIndex(uint32_t address, bool bVirtual)
+{
+ for (int nItem = 0;; nItem++)
+ {
+ if (JumpItems[nItem].caption == NULL)
+ {
+ break;
+ }
+
+ uint32_t start = bVirtual ? JumpItems[nItem].vaddr : JumpItems[nItem].paddr;
+ uint32_t end = start + JumpItems[nItem].size - 1;
+
+ if (address >= start && address <= end)
+ {
+ return nItem;
+ }
+ }
+ return -1;
+}
+
LRESULT CDebugMemoryView::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
+ DlgResize_Init(false, true);
DlgSavePos_Init(DebuggerUI_MemoryPos);
+ DlgToolTip_Init();
+
+ m_HexEditCtrl.Attach(GetDlgItem(IDC_HEXEDIT));
+ m_TabCtrl.Attach(GetDlgItem(IDC_MEMTABS));
+ m_MemAddr.Attach(GetDlgItem(IDC_ADDR_EDIT));
+ m_VirtualCheckbox.Attach(GetDlgItem(IDC_CHK_VADDR));
+ m_StatusBar.Attach(GetDlgItem(IDC_STATUSBAR));
+ m_CmbJump.Attach(GetDlgItem(IDC_CMB_JUMP));
m_SymbolColorStride = 0;
m_SymbolColorPhase = 0;
- m_DataStartLoc = (DWORD)-1;
- m_CompareStartLoc = (DWORD)-1;
- memset(m_CompareData, 0, sizeof(m_CompareData));
- memset(m_CompareValid, 0, sizeof(m_CompareValid));
HWND hScrlBar = GetDlgItem(IDC_SCRL_BAR);
if (hScrlBar)
@@ -61,227 +329,574 @@ LRESULT CDebugMemoryView::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM
::SetScrollInfo(hScrlBar, SB_CTL, &si, TRUE);
}
- m_MemAddr.Attach(GetDlgItem(IDC_ADDR_EDIT));
m_MemAddr.SetDisplayType(CEditNumber32::DisplayHex);
m_MemAddr.SetValue(0x80000000, false, true);
- SendDlgItemMessage(IDC_CHK_VADDR, BM_SETCHECK, BST_CHECKED, 0);
+ m_VirtualCheckbox.SetCheck(BST_CHECKED);
- if (m_MemoryList == NULL)
- {
- m_MemoryList = new CListCtrl;
- m_MemoryList->RegisterClass();
- }
- m_MemoryList->SubclassWindow(GetDlgItem(IDC_MEM_DETAILS));
- m_MemoryList->ShowHeader(false);
- m_MemoryList->SetSortEnabled(FALSE);
- m_MemoryList->AddColumn(_T("Address"), 90);
- m_MemoryList->AddColumn(_T("1"), 20);
- m_MemoryList->AddColumn(_T("2"), 20);
- m_MemoryList->AddColumn(_T("3"), 20);
- m_MemoryList->AddColumn(_T("4"), 20);
- m_MemoryList->AddColumn(_T("-"), 10);
- m_MemoryList->AddColumn(_T("5"), 20);
- m_MemoryList->AddColumn(_T("6"), 20);
- m_MemoryList->AddColumn(_T("7"), 20);
- m_MemoryList->AddColumn(_T("8"), 20);
- m_MemoryList->AddColumn(_T("-"), 10);
- m_MemoryList->AddColumn(_T("9"), 20);
- m_MemoryList->AddColumn(_T("10"), 20);
- m_MemoryList->AddColumn(_T("11"), 20);
- m_MemoryList->AddColumn(_T("12"), 20);
- m_MemoryList->AddColumn(_T("-"), 10);
- m_MemoryList->AddColumn(_T("13"), 20);
- m_MemoryList->AddColumn(_T("14"), 20);
- m_MemoryList->AddColumn(_T("15"), 20);
- m_MemoryList->AddColumn(_T("16"), 35);
- m_MemoryList->AddColumn(_T("Memory Ascii"), 140);
- ::SetWindowLongPtr(m_MemoryList->m_hWnd, GWL_EXSTYLE, WS_EX_CLIENTEDGE);
- RefreshMemory(false);
- int height = m_MemoryList->GetTotalHeight();
+ float dpiScale = CClientDC(m_hWnd).GetDeviceCaps(LOGPIXELSX) / 96.0f;
- RECT MemoryListRect = { 0 };
- ::GetClientRect(GetDlgItem(IDC_MEM_DETAILS), &MemoryListRect);
+ int statusPaneWidths[MEMSB_NUM_PANES] = {
+ (int)(MEMSB_HOTADDR_W * dpiScale),
+ (int)(MEMSB_BLOCK_W * dpiScale),
+ (int)(MEMSB_BLOCKLEN_W * dpiScale),
+ (int)(MEMSB_DMAINFO_W * dpiScale),
+ (int)(MEMSB_SAFEMODE_W * dpiScale)
+ };
- if (height > MemoryListRect.bottom)
- {
- RECT MemoryListWindow = { 0 };
- GetWindowRect(&MemoryListWindow);
- SetWindowPos(NULL, 0, 0, MemoryListWindow.right - MemoryListWindow.left, (MemoryListWindow.bottom - MemoryListWindow.top) + (height - MemoryListRect.bottom), SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOZORDER);
+ m_StatusBar.SetParts(MEMSB_NUM_PANES, statusPaneWidths);
- RECT DlgItemRect = { 0 };
+ SetupJumpMenu(true);
+ m_CmbJump.SetCurSel(0);
+
+ AddTab(0x80000000, true, 4);
- ::GetWindowRect(GetDlgItem(IDC_MEM_DETAILS), &DlgItemRect);
- ::SetWindowPos(GetDlgItem(IDC_MEM_DETAILS), NULL, 0, 0, DlgItemRect.right - DlgItemRect.left, (DlgItemRect.bottom - DlgItemRect.top) + (height - MemoryListRect.bottom), SWP_NOMOVE);
-
- ::GetWindowRect(GetDlgItem(IDC_SCRL_BAR), &DlgItemRect);
- ::SetWindowPos(GetDlgItem(IDC_SCRL_BAR), NULL, 0, 0, DlgItemRect.right - DlgItemRect.left, (DlgItemRect.bottom - DlgItemRect.top) + (height - MemoryListRect.bottom), SWP_NOMOVE);
- }
-
- m_SymInfo.Attach(GetDlgItem(IDC_SYM_INFO));
- m_DMAInfo.Attach(GetDlgItem(IDC_DMA_INFO));
-
- m_bAutoRefreshEnabled = g_Settings->LoadBool(Debugger_AutoRefreshMemoryView);
- SendDlgItemMessage(IDC_CHK_AUTOREFRESH, BM_SETCHECK, m_bAutoRefreshEnabled ? BST_CHECKED : BST_UNCHECKED, 0);
-
- _this = this;
-
- DWORD dwThreadID = ::GetCurrentThreadId();
- hWinMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)HookProc, NULL, dwThreadID);
+ m_HexEditCtrl.Draw();
LoadWindowPos();
WindowCreated();
- m_AutoRefreshThread = CreateThread(NULL, 0, AutoRefreshProc, (void*)this, 0, NULL);
-
return TRUE;
}
-DWORD WINAPI CDebugMemoryView::AutoRefreshProc(void* _self)
-{
- CDebugMemoryView* self = (CDebugMemoryView*)_self;
- while (true)
- {
- if (self->m_bAutoRefreshEnabled)
- {
- self->RefreshMemory(true);
- }
- Sleep(100);
- }
-}
-
-void CDebugMemoryView::OnExitSizeMove()
-{
- SaveWindowPos(0);
-}
-
-void CDebugMemoryView::InterceptMouseWheel(WPARAM wParam, LPARAM /*lParam*/)
-{
- uint32_t newAddress = m_DataStartLoc - ((short)HIWORD(wParam) / WHEEL_DELTA) * 16;
-
- m_DataStartLoc = newAddress;
-
- m_MemAddr.SetValue(m_DataStartLoc, false, true);
-}
-
-LRESULT CALLBACK CDebugMemoryView::HookProc(int nCode, WPARAM wParam, LPARAM lParam)
-{
- MSG *pMsg = (MSG*)lParam;
-
- if (pMsg->message == WM_MOUSEWHEEL)
- {
- _this->InterceptMouseWheel(pMsg->wParam, pMsg->lParam);
- }
-
- if (nCode < 0)
- {
- return CallNextHookEx(hWinMessageHook, nCode, wParam, lParam);
- }
-
- return 0;
-}
-
LRESULT CDebugMemoryView::OnDestroy(void)
{
- if (m_AutoRefreshThread != NULL)
- {
- TerminateThread(m_AutoRefreshThread, 0);
- CloseHandle(m_AutoRefreshThread);
- }
- if (m_MemoryList)
- {
- m_MemoryList->UnsubclassWindow();
- delete m_MemoryList;
- m_MemoryList = NULL;
- }
+ m_HexEditCtrl.Detach();
m_MemAddr.Detach();
- m_SymInfo.Detach();
- m_DMAInfo.Detach();
- UnhookWindowsHookEx(hWinMessageHook);
+ m_VirtualCheckbox.Detach();
+ m_TabCtrl.Detach();
+ m_StatusBar.Detach();
+ m_CmbJump.Detach();
return 0;
}
+LRESULT CDebugMemoryView::OnShowAddress(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
+{
+ uint32_t address = (uint32_t)wParam;
+ bool bVirtual = (lParam != 0);
+ m_CmbJump.SetCurSel(GetJumpItemIndex(address, bVirtual));
+ OpenNewTab(address, bVirtual, 4, true, true);
+ return FALSE;
+}
+
+void CDebugMemoryView::OnExitSizeMove()
+{
+ SaveWindowPos(true);
+}
+
LRESULT CDebugMemoryView::OnClicked(WORD /*wNotifyCode*/, WORD wID, HWND, BOOL& /*bHandled*/)
{
switch (wID)
{
- case IDC_REFRSH_MEM:
- RefreshMemory(true);
- break;
case IDC_CHK_VADDR:
- RefreshMemory(false);
- break;
- case IDC_DUMP_MEM:
- m_Debugger->OpenMemoryDump();
- break;
- case IDC_SEARCH_MEM:
- m_Debugger->OpenMemorySearch();
+ m_bVirtualMemory = (m_VirtualCheckbox.GetCheck() == BST_CHECKED);
+ SetupJumpMenu(m_bVirtualMemory);
+ UpdateCurrentTab(m_MemAddr.GetValue());
break;
case IDC_SYMBOLS_BTN:
m_Debugger->OpenSymbolsWindow();
break;
- case IDC_CHK_AUTOREFRESH:
- m_bAutoRefreshEnabled = (SendMessage(GetDlgItem(IDC_CHK_AUTOREFRESH), BM_GETSTATE, 0, 0) & BST_CHECKED) != 0;
- g_Settings->SaveBool(Debugger_AutoRefreshMemoryView, m_bAutoRefreshEnabled);
- break;
case IDCANCEL:
EndDialog(0);
break;
case ID_POPUPMENU_TOGGLERBP:
- m_Breakpoints->RBPToggle(m_CtxMenuAddr);
- RefreshMemory(true);
+ m_Breakpoints->RBPToggle(m_ContextMenuAddress);
break;
case ID_POPUPMENU_TOGGLEWBP:
- m_Breakpoints->WBPToggle(m_CtxMenuAddr);
- RefreshMemory(true);
+ m_Breakpoints->WBPToggle(m_ContextMenuAddress);
break;
case ID_POPUPMENU_CLEARALLBPS:
m_Breakpoints->RBPClear();
m_Breakpoints->WBPClear();
- RefreshMemory(true);
break;
case ID_POPUPMENU_TOGGLELOCK:
- m_Breakpoints->ToggleMemLock(m_CtxMenuAddr);
- RefreshMemory(true);
+ m_Breakpoints->ToggleMemLock(m_ContextMenuAddress);
break;
case ID_POPUPMENU_CLEARLOCKS:
m_Breakpoints->ClearMemLocks();
- RefreshMemory(true);
+ break;
+ case ID_POPUPMENU_JUMPHERE:
+ JumpToSelection();
+ break;
+ case ID_POPUPMENU_FOLLOWPOINTER:
+ FollowPointer();
break;
case ID_POPUPMENU_VIEWDISASM:
- m_Debugger->Debug_ShowCommandsLocation(m_CtxMenuAddr, true);
+ m_Debugger->Debug_ShowCommandsLocation(m_ContextMenuAddress, true);
break;
case ID_POPUPMENU_ADDSYMBOL:
- m_AddSymbolDlg.DoModal(m_Debugger, m_CtxMenuAddr);
+ m_AddSymbolDlg.DoModal(m_Debugger, m_ContextMenuAddress);
break;
- case ID_POPUPMENU_COPY_WORD:
- CopyNumber(m_CtxMenuAddr, sizeof(uint32_t));
+ case ID_POPUPMENU_COPY:
+ m_HexEditCtrl.Copy();
break;
- case ID_POPUPMENU_COPY_HALFWORD:
- CopyNumber(m_CtxMenuAddr, sizeof(uint16_t));
+ case ID_POPUPMENU_COPYGAMESHARKCODE:
+ {
+ uint32_t startAddress, endAddress;
+ m_HexEditCtrl.GetSelectionRange(&startAddress, &endAddress);
+ CopyGameSharkCodeToClipboard(startAddress, endAddress);
+ }
break;
- case ID_POPUPMENU_COPY_BYTE:
- CopyNumber(m_CtxMenuAddr, sizeof(uint8_t));
+ case ID_POPUPMENU_COPYDATAWITHGROUPADDRESSES:
+ {
+ uint32_t startAddress, endAddress;
+ m_HexEditCtrl.GetSelectionRange(&startAddress, &endAddress);
+ CopyBytesToClipboard(startAddress, endAddress, m_HexEditCtrl.GetFocusedColumn() == HX_COL_HEXDATA, true, false);
+ }
+ break;
+ case ID_POPUPMENU_COPYDATAWITHROWADDRESSES:
+ {
+ uint32_t startAddress, endAddress;
+ m_HexEditCtrl.GetSelectionRange(&startAddress, &endAddress);
+ CopyBytesToClipboard(startAddress, endAddress, m_HexEditCtrl.GetFocusedColumn() == HX_COL_HEXDATA, true, true);
+ }
+ break;
+ case ID_POPUPMENU_PASTE:
+ m_HexEditCtrl.Paste();
+ break;
+ case ID_POPUPMENU_SAFEMODE:
+ m_HexEditCtrl.SendMessage(WM_KEYDOWN, VK_INSERT, 0);
+ break;
+ case ID_POPUPMENU_ZEROFILL:
+ m_HexEditCtrl.SendMessage(WM_KEYDOWN, VK_DELETE, 0);
+ break;
+ case ID_POPUPMENU_BYTEGROUPSIZE_1:
+ m_HexEditCtrl.SetByteGroupSize(1);
+ break;
+ case ID_POPUPMENU_BYTEGROUPSIZE_2:
+ m_HexEditCtrl.SetByteGroupSize(2);
+ break;
+ case ID_POPUPMENU_BYTEGROUPSIZE_4:
+ m_HexEditCtrl.SetByteGroupSize(4);
+ break;
+ case ID_POPUPMENU_BYTEGROUPSIZE_8:
+ m_HexEditCtrl.SetByteGroupSize(8);
+ break;
+ case ID_POPUPMENU_DUMP:
+ m_Debugger->OpenMemoryDump();
+ break;
+ case ID_POPUPMENU_SEARCH:
+ m_Debugger->OpenMemorySearch();
break;
}
return FALSE;
}
-LRESULT CDebugMemoryView::OnMemoryRightClicked(LPNMHDR lpNMHDR)
+void CDebugMemoryView::OnAddrChanged(UINT /*Code*/, int /*id*/, HWND /*ctl*/)
{
- uint32_t address;
- bool bData = GetItemAddress(lpNMHDR, address);
-
- if (!bData)
+ if (m_bIgnoreAddressInput)
{
- return 0;
+ m_bIgnoreAddressInput = false;
+ return;
}
- m_CtxMenuAddr = address;
+ uint32_t address = m_MemAddr.GetValue();
+ m_HexEditCtrl.SetBaseAddress(address);
+ UpdateCurrentTab(address);
+}
+
+void CDebugMemoryView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)
+{
+ if (pScrollBar != GetDlgItem(IDC_SCRL_BAR))
+ {
+ return;
+ }
+
+ uint32_t address = m_MemAddr.GetValue();
+ int numBytesPerRow = m_HexEditCtrl.GetNumBytesPerRow();
+ int numVisibleBytes = m_HexEditCtrl.GetNumVisibleBytes();
+
+ switch (nSBCode)
+ {
+ case SB_LINEDOWN:
+ m_MemAddr.SetValue(address < 0xFFFFFFEF ? address + numBytesPerRow : 0xFFFFFFFF, false, true);
+ break;
+ case SB_LINEUP:
+ m_MemAddr.SetValue(address > (uint32_t)numBytesPerRow ? address - numBytesPerRow : 0, false, true);
+ break;
+ case SB_PAGEDOWN:
+ m_MemAddr.SetValue(address < 0xFFFFFEFF ? address + numVisibleBytes : 0xFFFFFFFF, false, true);
+ break;
+ case SB_PAGEUP:
+ m_MemAddr.SetValue(address >(uint32_t)numVisibleBytes ? address - numVisibleBytes : 0, false, true);
+ break;
+ case SB_THUMBPOSITION:
+ m_MemAddr.SetValue((DWORD)nPos << 0x10, false, true);
+ break;
+ default:
+ break;
+ }
+
+ m_CmbJump.SetCurSel(GetJumpItemIndex(address, m_bVirtualMemory));
+}
+
+LRESULT CDebugMemoryView::OnHxCtrlKeyPressed(LPNMHDR lpNMHDR)
+{
+ NMHXCTRLKEYPRESSED* nmck = reinterpret_cast(lpNMHDR);
+ uint32_t address = m_HexEditCtrl.GetCaretAddress();
+
+ if (nmck->nChar >= '1' && nmck->nChar <= '9')
+ {
+ int nBytes = nmck->nChar - '0';
+ m_HexEditCtrl.SetByteGroupSize(nBytes);
+ return FALSE;
+ }
+
+ switch (nmck->nChar)
+ {
+ case 'G':
+ {
+ JumpToSelection();
+ }
+ break;
+ case 'W':
+ m_Breakpoints->WBPToggle(address);
+ break;
+ case 'R':
+ m_Breakpoints->RBPToggle(address);
+ break;
+ case 'E':
+ m_Breakpoints->ToggleMemLock(address);
+ break;
+ case 'Q':
+ m_Breakpoints->WBPClear();
+ m_Breakpoints->RBPClear();
+ m_Breakpoints->ClearMemLocks();
+ break;
+ case 'F':
+ // todo put selection in the textbox
+ m_Debugger->OpenMemorySearch();
+ break;
+ case 'S':
+ // todo set start and end addrs to selection
+ m_Debugger->OpenMemoryDump();
+ break;
+ case 'T':
+ OpenDuplicateTab();
+ break;
+ case 'Z':
+ if (m_SafeEditQueue.size() != 0)
+ {
+ m_SafeEditQueue.pop_back();
+ }
+ break;
+ case VK_F4:
+ CloseCurrentTab();
+ break;
+ case VK_SPACE:
+ FollowPointer(false);
+ break;
+ case VK_TAB:
+ {
+ int curSel = m_TabCtrl.GetCurSel();
+ if (m_TabCtrl.SetCurSel(curSel + 1) == -1)
+ {
+ m_TabCtrl.SetCurSel(0);
+ }
+ TabSelChanged();
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+LRESULT CDebugMemoryView::OnHxSetNibble(LPNMHDR lpNMHDR)
+{
+ if (g_MMU == NULL)
+ {
+ return FALSE;
+ }
+
+ NMHXSETNIBBLE* nmsn = reinterpret_cast(lpNMHDR);
+
+ uint8_t curValue;
+ bool bValid = GetByte(nmsn->address, &curValue);
+
+ if (!bValid)
+ {
+ return false;
+ }
+
+ uint8_t mask = (nmsn->bLoNibble ? 0xF0 : 0x0F);
+ uint8_t newValue = (curValue & mask) | (nmsn->value << (nmsn->bLoNibble ? 0 : 4));
+
+ if (nmsn->bInsert)
+ {
+ if (GetSafeEditValue(nmsn->address, &curValue))
+ {
+ newValue = (curValue & mask) | (nmsn->value << (nmsn->bLoNibble ? 0 : 4));
+ }
+
+ m_SafeEditQueue.push_back({ SE_FILL, nmsn->address, nmsn->address, newValue });
+ }
+ else
+ {
+ SetByte(nmsn->address, newValue);
+ }
+
+ return FALSE;
+}
+
+LRESULT CDebugMemoryView::OnHxSetByte(LPNMHDR lpNMHDR)
+{
+ NMHXSETBYTE* nmsb = reinterpret_cast(lpNMHDR);
+
+ if (g_MMU == NULL)
+ {
+ return FALSE;
+ }
+
+ if (nmsb->bInsert)
+ {
+ m_SafeEditQueue.push_back({ SE_FILL, nmsb->address, nmsb->address, nmsb->value });
+ }
+ else
+ {
+ SetByte(nmsb->address, nmsb->value);
+ }
+ return FALSE;
+}
+
+LRESULT CDebugMemoryView::OnHxFillRange(LPNMHDR lpNMHDR)
+{
+ NMHXFILLRANGE* nmfr = reinterpret_cast(lpNMHDR);
+
+ if (nmfr->bInsert)
+ {
+ m_SafeEditQueue.push_back({ SE_FILL, nmfr->startAddress, nmfr->endAddress, nmfr->value });
+ return FALSE;
+ }
+
+ FillRange(nmfr->startAddress, nmfr->endAddress, nmfr->value);
+ return FALSE;
+}
+
+LRESULT CDebugMemoryView::OnHxInsertModeChanged(LPNMHDR /*lpNMHDR*/)
+{
+ m_SafeEditQueue.clear();
+ m_bSafeEditMode = m_HexEditCtrl.GetInsertMode();
+ m_StatusBar.SetText(MEMSB_SAFEMODE, m_bSafeEditMode ? "Safe mode" : "");
+ return FALSE;
+}
+
+LRESULT CDebugMemoryView::OnHxSelectionChanged(LPNMHDR /*lpNMHDR*/)
+{
+ uint32_t startAddress, endAddress;
+ bool bHaveSelection = m_HexEditCtrl.GetSelectionRange(&startAddress, &endAddress);
+
+ stdstr strBlock, strLength;
+
+ if (bHaveSelection)
+ {
+ strBlock = stdstr_f("%08X:%08X", startAddress, endAddress);
+ strLength = stdstr_f("%X", endAddress - startAddress + 1);
+ m_StatusBar.SetText(MEMSB_BLOCK, strBlock.c_str());
+ m_StatusBar.SetText(MEMSB_BLOCKLEN, strLength.c_str());
+ }
+ else
+ {
+ strBlock = stdstr_f("%08X", startAddress);
+ m_StatusBar.SetText(MEMSB_BLOCK, strBlock.c_str());
+ m_StatusBar.SetText(MEMSB_BLOCKLEN, "");
+ }
+
+ uint32_t romAddr, offset;
+ DMALOGENTRY* entry = m_Debugger->DMALog()->GetEntryByRamAddress(startAddress, &romAddr, &offset);
+ m_StatusBar.SetText(MEMSB_DMAINFO, entry != NULL ? "Have DMA" : "");
+
+ return FALSE;
+}
+
+LRESULT CDebugMemoryView::OnHxGroupSizeChanged(LPNMHDR /*lpNMHDR*/)
+{
+ int groupSize = m_HexEditCtrl.GetNumBytesPerGroup();
+
+ int nItem = m_TabCtrl.GetCurSel();
+
+ if (nItem == -1)
+ {
+ return FALSE;
+ }
+
+ m_TabData[nItem].numBytesPerGroup = groupSize;
+ return FALSE;
+}
+
+LRESULT CDebugMemoryView::OnHxEnterPressed(LPNMHDR /*lpNMHDR*/)
+{
+ ApplySafeEdits();
+ return FALSE;
+}
+
+LRESULT CDebugMemoryView::OnHxRedrawStarted(LPNMHDR /*lpNMHDR*/)
+{
+ m_SymbolColorPhase = 0;
+ return FALSE;
+}
+
+LRESULT CDebugMemoryView::OnHxGetByteInfo(LPNMHDR lpNMHDR)
+{
+ NMHXGETBYTEINFO *nmgbi = reinterpret_cast(lpNMHDR);
+
+ bool bHaveWriteTarget = false, bHaveReadTarget = false;
+ uint32_t cpuReadWriteAddress = 0;
+ int cpuReadWriteNumBytes = 0;
+
+ if (g_Settings->LoadBool(Debugger_SteppingOps))
+ {
+ COpInfo opInfo(R4300iOp::m_Opcode);
+ if (opInfo.IsStoreCommand())
+ {
+ cpuReadWriteAddress = opInfo.GetLoadStoreAddress();
+ cpuReadWriteNumBytes = opInfo.NumBytesToStore();
+ bHaveWriteTarget = true;
+ }
+ else if (opInfo.IsLoadCommand())
+ {
+ cpuReadWriteAddress = opInfo.GetLoadStoreAddress();
+ cpuReadWriteNumBytes = opInfo.NumBytesToLoad();
+ bHaveReadTarget = true;
+ }
+ }
+
+ for (uint32_t i = 0; i < nmgbi->numBytes; i++)
+ {
+ uint32_t address = nmgbi->address + i;
+ uint32_t paddress = address;
+ HXBYTEINFO* oldByte = &nmgbi->oldBytes[i];
+ HXBYTEINFO* newByte = &nmgbi->newBytes[i];
+
+ newByte->bkColor = BKCOLOR_DEFAULT;
+ newByte->color = COLOR_DEFAULT;
+
+ if (m_bVirtualMemory && (g_MMU == NULL || !g_MMU->TranslateVaddr(address, paddress)))
+ {
+ newByte->bValid = false;
+ continue;
+ }
+
+ newByte->bValid = GetByte(address, &newByte->value);
+
+ if (!newByte->bValid)
+ {
+ continue;
+ }
+
+ // always use virtual addresses for breakpoint & symbol info
+ // todo should be the other way around
+ uint32_t vaddress = m_bVirtualMemory ? address : address + 0x80000000;
+
+ CSymbols::EnterCriticalSection();
+ CSymbolEntry* symbol = CSymbols::GetEntryByAddress(vaddress);
+
+ if (symbol != NULL)
+ {
+ m_SymbolColorStride = symbol->TypeSize();
+ m_SymbolColorPhase = m_SymbolColorPhase ? 0 : 1;
+ }
+
+ CSymbols::LeaveCriticalSection();
+
+ if (bHaveWriteTarget && address == cpuReadWriteAddress)
+ {
+ m_WriteTargetColorStride = cpuReadWriteNumBytes;
+ }
+ else if (bHaveReadTarget && address == cpuReadWriteAddress)
+ {
+ m_ReadTargetColorStride = cpuReadWriteNumBytes;
+ }
+
+ bool bLocked = m_Breakpoints->MemLockExists(vaddress, 1);
+ bool bReadBP = m_Breakpoints->ReadBPExists8(vaddress) == CBreakpoints::BP_SET;
+ bool bWriteBP = m_Breakpoints->WriteBPExists8(vaddress) == CBreakpoints::BP_SET;
+
+ if (bLocked)
+ {
+ newByte->bkColor = BKCOLOR_LOCKED;
+ newByte->color = COLOR_BP;
+ }
+ else if (bReadBP && bWriteBP)
+ {
+ newByte->bkColor = BKCOLOR_RWBP;
+ newByte->color = COLOR_BP;
+ }
+ else if (bReadBP)
+ {
+ newByte->bkColor = BKCOLOR_RBP;
+ newByte->color = COLOR_BP;
+ }
+ else if (bWriteBP)
+ {
+ newByte->bkColor = BKCOLOR_WBP;
+ newByte->color = COLOR_BP;
+ }
+ else if (m_ReadTargetColorStride > 0)
+ {
+ newByte->bkColor = BKCOLOR_CPUREAD;
+ }
+ else if (m_WriteTargetColorStride > 0)
+ {
+ newByte->bkColor = BKCOLOR_CPUWRITE;
+ }
+ else if (m_SymbolColorStride > 0)
+ {
+ newByte->bkColor = m_SymbolColorPhase ? BKCOLOR_SYMBOL0 : BKCOLOR_SYMBOL1;
+ }
+
+ if (g_Rom != NULL && paddress >= 0x10000000 && paddress < 0x10000000 + g_Rom->GetRomSize())
+ {
+ newByte->color = COLOR_READONLY;
+ }
+
+ if (!nmgbi->bIgnoreDiff && oldByte->value != newByte->value)
+ {
+ newByte->color = COLOR_CHANGED;
+ }
+
+ if (m_SymbolColorStride > 0)
+ {
+ m_SymbolColorStride--;
+ }
+
+ if (m_ReadTargetColorStride > 0)
+ {
+ m_ReadTargetColorStride--;
+ }
+
+ if (m_WriteTargetColorStride > 0)
+ {
+ m_WriteTargetColorStride--;
+ }
+
+ uint8_t safeEditValue;
+ if (GetSafeEditValue(address, &safeEditValue))
+ {
+ newByte->bValid = true;
+ newByte->value = safeEditValue;
+ newByte->bkColor = RGB(0xFF, 0xCC, 0xFF);
+ newByte->color = RGB(0xFF, 0x00, 0xFF);
+ }
+
+ newByte->bHidden = false;
+ }
+
+ return FALSE;
+}
+
+LRESULT CDebugMemoryView::OnHxRightClick(LPNMHDR lpNMHDR)
+{
+ NMHXRCLICK *nmrc = reinterpret_cast(lpNMHDR);
+
+ m_ContextMenuAddress = nmrc->address;
HMENU hMenu = LoadMenu(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_MEM_BP_POPUP));
HMENU hPopupMenu = GetSubMenu(hMenu, 0);
+ bool bHaveLock = m_Breakpoints->MemLockExists(m_ContextMenuAddress, 1);
+ bool bHaveReadBP = (m_Breakpoints->ReadBPExists8(m_ContextMenuAddress) != CBreakpoints::BPSTATE::BP_NOT_SET);
+ bool bHaveWriteBP = (m_Breakpoints->WriteBPExists8(m_ContextMenuAddress) != CBreakpoints::BPSTATE::BP_NOT_SET);
+
if (m_Breakpoints->ReadMem().size() == 0 && m_Breakpoints->WriteMem().size() == 0)
{
EnableMenuItem(hPopupMenu, ID_POPUPMENU_CLEARALLBPS, MF_DISABLED | MF_GRAYED);
@@ -291,539 +906,349 @@ LRESULT CDebugMemoryView::OnMemoryRightClicked(LPNMHDR lpNMHDR)
EnableMenuItem(hPopupMenu, ID_POPUPMENU_CLEARLOCKS, MF_DISABLED | MF_GRAYED);
}
+ CheckMenuItem(hPopupMenu, ID_POPUPMENU_TOGGLELOCK, bHaveLock ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hPopupMenu, ID_POPUPMENU_TOGGLERBP, bHaveReadBP ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hPopupMenu, ID_POPUPMENU_TOGGLEWBP, bHaveWriteBP ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hPopupMenu, ID_POPUPMENU_SAFEMODE, m_bSafeEditMode ? MF_CHECKED : MF_UNCHECKED);
+
POINT mouse;
GetCursorPos(&mouse);
-
TrackPopupMenu(hPopupMenu, TPM_LEFTALIGN, mouse.x, mouse.y, 0, m_hWnd, NULL);
-
DestroyMenu(hMenu);
-
- return 0;
+ return FALSE;
}
-LRESULT CDebugMemoryView::OnHotItemChanged(LPNMHDR lpNMHDR)
+LRESULT CDebugMemoryView::OnHxHotAddrChanged(LPNMHDR /*lpNMHDR*/)
{
- uint32_t address;
- bool bData = GetItemAddress(lpNMHDR, address);
-
- if (!bData)
- {
- return 0;
- }
+ m_HotAddress = m_HexEditCtrl.GetHotAddress();
+ stdstr strAddrInfo = "";
CSymbols::EnterCriticalSection();
+
+ CSymbolEntry* foundSymbol = NULL;
+ int numSymbols = CSymbols::GetCount();
- CSymbolEntry* lpSymbol = CSymbols::GetEntryByAddress(address);
-
- stdstr symbolInfo;
-
- if (lpSymbol != NULL)
+ for (int i = 0; i < numSymbols; i++)
{
- char* desc = lpSymbol->m_Description;
- desc = desc ? desc : "";
- symbolInfo = stdstr_f("%08X: %s %s // %s", address, lpSymbol->TypeName(), lpSymbol->m_Name, desc);
+ CSymbolEntry* symbol = CSymbols::GetEntryByIndex(i);
+ if (m_HotAddress >= symbol->m_Address && m_HotAddress < symbol->m_Address + symbol->TypeSize())
+ {
+ foundSymbol = symbol;
+ break;
+ }
+ }
+
+ if (foundSymbol != NULL)
+ {
+ strAddrInfo += stdstr_f("%08X %s %s", foundSymbol->m_Address, foundSymbol->TypeName(), foundSymbol->m_Name);
}
else
{
- symbolInfo = stdstr_f("%08X", address);
+ strAddrInfo += stdstr_f("%08X\n", m_HotAddress);
}
+ m_StatusBar.SetText(MEMSB_HOTADDR, strAddrInfo.c_str());
+
CSymbols::LeaveCriticalSection();
-
- m_SymInfo.SetWindowTextA(symbolInfo.c_str());
-
- uint32_t romAddr, offset;
- DMALOGENTRY* lpEntry = m_Debugger->DMALog()->GetEntryByRamAddress(address, &romAddr, &offset);
-
- stdstr dmaInfo;
-
- if (lpEntry != NULL)
- {
- dmaInfo = stdstr_f("Last DMA: %08X -> %08X [%X] (%08X, +%X) ", lpEntry->romAddr, lpEntry->ramAddr, lpEntry->length, romAddr, offset);
- }
- else
- {
- dmaInfo = stdstr_f("Last DMA: ?");
- }
-
- m_DMAInfo.SetWindowTextA(dmaInfo.c_str());
-
- return 0;
+ return FALSE;
}
-LRESULT CDebugMemoryView::OnMemoryModified(LPNMHDR lpNMHDR)
+LRESULT CDebugMemoryView::OnHxBaseAddrChanged(LPNMHDR /*lpNMHDR*/)
{
- uint32_t Pos = 0;
- bool bData = GetItemOffset(lpNMHDR, Pos);
-
- if (!bData)
- {
- return 0;
- }
-
- CListNotify *pListNotify = reinterpret_cast(lpNMHDR);
- int LineNumber = pListNotify->m_nItem;
-
- LPCSTR strValue = m_MemoryList->GetItemText(pListNotify->m_nItem, pListNotify->m_nSubItem);
- unsigned long long Value = strtoull(strValue, NULL, 16);
-
- if (m_CurrentData[Pos] == Value)
- {
- return 0;
- }
-
- if (m_CompareStartLoc != m_DataStartLoc ||
- m_CompareVAddrr != m_DataVAddrr)
- {
- // copy current data for change comparison
- m_CompareStartLoc = m_DataStartLoc;
- m_CompareVAddrr = m_DataVAddrr;
- memcpy(m_CompareData, m_CurrentData, sizeof(m_CurrentData));
- memcpy(m_CompareValid, m_DataValid, sizeof(m_CompareValid));
- }
-
- m_CompareData[Pos] = m_CurrentData[Pos];
- m_CurrentData[Pos] = (BYTE)Value;
-
- //sb
- __except_try()
- {
- if (m_DataVAddrr)
- {
- if (!g_MMU->SB_VAddr(m_DataStartLoc + Pos, (BYTE)Value))
- {
- WriteTrace(TraceUserInterface, TraceError, "failed to store at %X", m_DataStartLoc + Pos);
- }
- }
- else
- {
- if (!g_MMU->SB_PAddr(m_DataStartLoc + Pos, (BYTE)Value))
- {
- WriteTrace(TraceUserInterface, TraceError, "failed to store at %X", m_DataStartLoc + Pos);
- }
- }
- uint32_t PhysicalAddress = m_DataStartLoc + Pos;
- if (!m_DataVAddrr || g_MMU->TranslateVaddr(PhysicalAddress, PhysicalAddress))
- {
- if (PhysicalAddress > 0x10000000 && (PhysicalAddress - 0x10000000) < g_Rom->GetRomSize())
- {
- uint8_t * ROM = g_Settings->LoadBool(Game_LoadRomToMemory) ? g_MMU->Rdram() + 0x10000000: g_Rom->GetRomAddress();
- ProtectMemory(ROM, g_Rom->GetRomSize(), MEM_READWRITE);
- ROM[(PhysicalAddress - 0x10000000) ^ 3] = (uint8_t)Value;
- ProtectMemory(ROM, g_Rom->GetRomSize(), MEM_READONLY);
- }
- }
- if (g_Recompiler != NULL)
- {
- g_Recompiler->ClearRecompCode_Phys(PhysicalAddress & ~0xFFF, 0x1000, CRecompiler::Remove_MemViewer);
- }
- }
- __except_catch()
- {
- g_Notify->FatalError(GS(MSG_UNKNOWN_MEM_ACTION));
- }
- Insert_MemoryLineDump(LineNumber);
-
- return 0;
+ // address was updated from the control
+ uint32_t address = m_HexEditCtrl.GetBaseAddress();
+ m_bIgnoreAddressInput = true;
+ m_MemAddr.SetValue(address, false, true);
+ m_CmbJump.SetCurSel(GetJumpItemIndex(address, m_bVirtualMemory));
+ UpdateCurrentTab(address);
+ return FALSE;
}
-void CDebugMemoryView::OnAddrChanged(UINT /*Code*/, int /*id*/, HWND /*ctl*/)
+LRESULT CDebugMemoryView::OnHxCopy(LPNMHDR /*lpNMHDR*/)
{
- RefreshMemory(false);
+ HXCOLUMN column = m_HexEditCtrl.GetFocusedColumn();
+ uint32_t startAddress, endAddress;
+ m_HexEditCtrl.GetSelectionRange(&startAddress, &endAddress);
+ CopyBytesToClipboard(startAddress, endAddress, column == HX_COL_HEXDATA);
+ return FALSE;
}
-void CDebugMemoryView::OnVScroll(int request, short Pos, HWND ctrl)
+LRESULT CDebugMemoryView::OnHxPaste(LPNMHDR lpNMHDR)
{
- if (ctrl != GetDlgItem(IDC_SCRL_BAR))
- {
- return;
- }
- DWORD Location = m_MemAddr.GetValue();
- switch (request)
- {
- case SB_LINEDOWN:
- m_MemAddr.SetValue(Location < 0xFFFFFFEF ? Location + 0x10 : 0xFFFFFFFF, false, true);
- break;
- case SB_LINEUP:
- m_MemAddr.SetValue(Location > 0x10 ? Location - 0x10 : 0, false, true);
- break;
- case SB_PAGEDOWN:
- m_MemAddr.SetValue(Location < 0xFFFFFEFF ? Location + 0x100 : 0xFFFFFFFF, false, true);
- break;
- case SB_PAGEUP:
- m_MemAddr.SetValue(Location > 0x100 ? Location - 0x100 : 0, false, true);
- break;
- case SB_THUMBPOSITION:
- m_MemAddr.SetValue((DWORD)Pos << 0x10, false, true);
- break;
- default:
- break;
- }
-}
+ NMHXPASTE *nmp = reinterpret_cast(lpNMHDR);
-LRESULT CDebugMemoryView::OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
-{
- WORD type = LOWORD(wParam);
-
- if (type == WA_INACTIVE)
+ if (g_MMU == NULL)
{
return FALSE;
}
- RefreshMemory(false);
+ OpenClipboard();
+ HANDLE hData = GetClipboardData(CF_TEXT);
+ char* text = (char*)GlobalLock(hData);
+ int retDataLength = 0;
+
+ if (nmp->column == HX_COL_HEXDATA)
+ {
+ char* data = NULL;
+ // todo move this function to some utility class
+ int length = CMemoryScanner::ParseHexString(NULL, text);
+
+ if (length != 0)
+ {
+ data = (char*)malloc(length);
+ CMemoryScanner::ParseHexString(data, text);
+
+ for (int i = 0; i < length; i++)
+ {
+ SetByte(nmp->address + i, data[i]);
+ }
+
+ free(data);
+ }
+
+ retDataLength = length;
+ }
+ else if (nmp->column == HX_COL_ASCII)
+ {
+ size_t length = strlen(text);
+ for (size_t i = 0; i < length; i++)
+ {
+ SetByte(nmp->address + i, text[i]);
+ }
+
+ retDataLength = length;
+ }
+
+ GlobalUnlock(hData);
+ CloseClipboard();
+
+ return retDataLength;
+}
+
+
+LRESULT CDebugMemoryView::OnTabSelChange(LPNMHDR /*lpNMHDR*/)
+{
+ TabSelChanged();
+ return FALSE;
+}
+
+void CDebugMemoryView::TabSelChanged(void)
+{
+ TCITEM item = { 0 };
+ item.mask = TCIF_PARAM;
+
+ int nItem = m_TabCtrl.GetCurSel();
+
+ if (m_TabCtrl.GetItem(nItem, &item))
+ {
+ tab_info_t tabInfo = m_TabData[nItem];
+ uint32_t address = tabInfo.address;
+
+ m_MemAddr.SetValue(address, false, true);
+
+ if (m_bVirtualMemory != tabInfo.bVirtual)
+ {
+ m_bVirtualMemory = tabInfo.bVirtual;
+ m_VirtualCheckbox.SetCheck(m_bVirtualMemory ? BST_CHECKED : BST_UNCHECKED);
+ SetupJumpMenu(m_bVirtualMemory);
+ }
+
+ m_CmbJump.SetCurSel(GetJumpItemIndex(address, m_bVirtualMemory));
+ m_HexEditCtrl.SetByteGroupSize(tabInfo.numBytesPerGroup);
+ }
+}
+
+int CDebugMemoryView::AddTab(uint32_t address, bool bVirtual, int numBytesPerGroup)
+{
+ char szAddress[12];
+ sprintf(szAddress, "%08X", address);
+ m_TabData.push_back({ address, bVirtual, numBytesPerGroup });
+ return m_TabCtrl.AddItem(TCIF_TEXT | TCIF_PARAM, szAddress, 0, (LPARAM)address);
+}
+
+int CDebugMemoryView::InsertTab(int nItem, uint32_t address, bool bVirtual, int numBytesPerGroup)
+{
+ m_TabData.insert(m_TabData.begin() + nItem + 1, { address, bVirtual, numBytesPerGroup });
+ m_TabCtrl.SetRedraw(FALSE);
+ m_TabCtrl.DeleteAllItems();
+ for (size_t i = 0; i < m_TabData.size(); i++)
+ {
+ m_TabCtrl.AddItem(TCIF_TEXT, stdstr_f("%08X", m_TabData[i].address).c_str(), 0, 0);
+ }
+ m_TabCtrl.SetRedraw(TRUE);
+ return nItem + 1;
+}
+
+void CDebugMemoryView::DeleteTab(int nItem)
+{
+ m_TabData.erase(m_TabData.begin() + nItem);
+ m_TabCtrl.DeleteItem(nItem);
+}
+
+void CDebugMemoryView::UpdateCurrentTab(uint32_t address)
+{
+ char szAddress[12];
+ sprintf(szAddress, "%08X", address);
+
+ int nItem = m_TabCtrl.GetCurSel();
+
+ if (nItem == -1)
+ {
+ return;
+ }
+
+ TCITEM item = { 0 };
+ item.mask = TCIF_TEXT;
+ item.pszText = szAddress;
+
+ m_TabCtrl.SetRedraw(FALSE);
+ m_TabCtrl.SetItem(nItem, &item);
+ m_TabData[nItem].address = address;
+ m_TabData[nItem].bVirtual = m_bVirtualMemory;
+ m_TabCtrl.SetRedraw(TRUE);
+}
+
+void CDebugMemoryView::OpenNewTab(uint32_t address, bool bVirtual, int numBytesPerGroup, bool bInsert, bool bOpenExisting)
+{
+ int nItem;
+
+ if (bOpenExisting)
+ {
+ for (size_t i = 0; i < m_TabData.size(); i++)
+ {
+ if (m_TabData[i].address == address && m_TabData[i].bVirtual == bVirtual)
+ {
+ m_TabCtrl.SetCurSel(i);
+ TabSelChanged();
+ return;
+ }
+ }
+ }
+
+ if (bInsert)
+ {
+ int nCurSelItem = m_TabCtrl.GetCurSel();
+ nItem = InsertTab(nCurSelItem, address, bVirtual, numBytesPerGroup);
+ }
+ else
+ {
+ nItem = AddTab(address, bVirtual, numBytesPerGroup);
+ }
+
+ m_TabCtrl.SetCurSel(nItem);
+ TabSelChanged();
+}
+
+void CDebugMemoryView::OpenDuplicateTab(void)
+{
+ int nItem = m_TabCtrl.GetCurSel();
+ tab_info_t tabInfo = m_TabData[nItem];
+ int nItemNew = InsertTab(nItem, tabInfo.address, tabInfo.bVirtual, tabInfo.numBytesPerGroup);
+ m_TabCtrl.SetCurSel(nItemNew);
+ TabSelChanged();
+}
+
+void CDebugMemoryView::CloseTab(int nItem)
+{
+ int itemCount = m_TabCtrl.GetItemCount();
+ int nSelItem = m_TabCtrl.GetCurSel();
+
+ if (itemCount < 2 || nItem == -1)
+ {
+ return;
+ }
+
+ if (nItem == nSelItem)
+ {
+ if (nItem == m_TabCtrl.GetItemCount() - 1)
+ {
+ // last tab
+ m_TabCtrl.SetCurSel(nItem - 1);
+ }
+ else if (nItem == nSelItem)
+ {
+ m_TabCtrl.SetCurSel(nItem + 1);
+ }
+
+ TabSelChanged();
+ }
+
+ DeleteTab(nItem);
+}
+
+void CDebugMemoryView::CloseCurrentTab(void)
+{
+ CloseTab(m_TabCtrl.GetCurSel());
+}
+
+LRESULT CDebugMemoryView::OnTabDblClick(LPNMHDR /*lpNMHDR*/)
+{
+ OpenDuplicateTab();
+ return FALSE;
+}
+
+LRESULT CDebugMemoryView::OnTabRClick(LPNMHDR lpNMHDR)
+{
+ NMMTRCLICK *nmrc = reinterpret_cast(lpNMHDR);
+ CloseTab(nmrc->nItem);
+ return FALSE;
+}
+
+LRESULT CDebugMemoryView::OnStatusBarClick(LPNMHDR lpNMHDR)
+{
+ NMMOUSE *nmm = reinterpret_cast(lpNMHDR);
+
+ uint32_t startAddress, endAddress;
+ bool bHaveSelection = m_HexEditCtrl.GetSelectionRange(&startAddress, &endAddress);
+
+ if (nmm->dwItemSpec == MEMSB_DMAINFO)
+ {
+ uint32_t romAddress, blockOffset;
+ DMALOGENTRY* entry = m_Debugger->DMALog()->GetEntryByRamAddress(startAddress, &romAddress, &blockOffset);
+
+ if (entry == NULL)
+ {
+ return FALSE;
+ }
+
+ stdstr strDmaTitle = stdstr_f("DMA Information for 0x%08X", startAddress);
+ stdstr strDmaInfo = stdstr_f("Block:\nROM 0x%08X -> RAM 0x%08X ( 0x%X bytes )\n\nROM address of byte:\n0x%08X ( 0x%08X + 0x%08X )",
+ entry->romAddr, entry->ramAddr, entry->length, romAddress, entry->romAddr, blockOffset);
+ MessageBox(strDmaInfo.c_str(), strDmaTitle.c_str(), MB_OK);
+ }
+ else if (nmm->dwItemSpec == MEMSB_BLOCK)
+ {
+ stdstr strAddrRange;
+
+ if (bHaveSelection)
+ {
+ strAddrRange = stdstr_f("%08X:%08X", startAddress, endAddress);
+ }
+ else
+ {
+ strAddrRange = stdstr_f("%08X", startAddress);
+ }
+
+ CopyTextToClipboard(strAddrRange.c_str());
+ }
return FALSE;
}
-void CDebugMemoryView::ShowAddress(DWORD Address, bool VAddr)
+void CDebugMemoryView::OnJumpComboSelChange(UINT /*uNotifyCode*/, int /*nID*/, CWindow /*wndCtl*/)
{
- if (m_hWnd == NULL)
- {
- return;
- }
+ int nItem = m_CmbJump.GetCurSel();
+ uint32_t address;
- SendDlgItemMessage(IDC_CHK_VADDR, BM_SETCHECK, VAddr ? BST_CHECKED : BST_UNCHECKED, 0);
- m_MemAddr.SetValue(Address, false, true);
- RefreshMemory(true);
-}
-
-void CDebugMemoryView::Insert_MemoryLineDump(int LineNumber)
-{
- if (m_MemoryList == NULL || m_MemoryList->GetColumnCount() == 0)
+ if (m_bVirtualMemory)
{
- return;
- }
- char Output[20], Hex[60], Ascii[20], AsciiAddOn[15];
- sprintf(Output, "0x%08X", m_DataStartLoc + (LineNumber << 4));
- if (m_MemoryList->GetItemCount() <= LineNumber)
- {
- HFONT hFont = (HFONT)GetStockObject(ANSI_FIXED_FONT);
- m_MemoryList->AddItemAt(LineNumber, Output);
- for (int i = 0; i < m_MemoryList->GetColumnCount(); i++)
- {
- m_MemoryList->SetItemFont(LineNumber, i, hFont);
- if (i == 5 || i == 10 || i == 15)
- {
- m_MemoryList->SetItemText(LineNumber, i, "-");
- }
- }
+ address = JumpItems[nItem].vaddr;
}
else
{
- if (strcmp(Output, m_MemoryList->GetItemText(LineNumber, 0)) != 0)
- {
- m_MemoryList->SetItemText(LineNumber, 0, Output);
- }
- }
-
- Hex[0] = 0;
- Ascii[0] = 0;
- int CompareStartPos = m_DataStartLoc - m_CompareStartLoc;
-
- for (int i = 0, col = 1; i < 0x10; i++, col++)
- {
- int Pos = ((LineNumber << 4) + i);
- if (m_DataValid[Pos])
- {
- int ComparePos = CompareStartPos + Pos;
- bool Changed = false;
-
- if (ComparePos >= 0 && ComparePos < MemoryToDisplay &&
- m_DataVAddrr == m_CompareVAddrr &&
- m_DataValid[ComparePos] &&
- m_CurrentData[Pos] != m_CompareData[ComparePos])
- {
- Changed = true;
- }
-
- sprintf(Hex, "%02X", m_CurrentData[Pos]);
-
- m_MemoryList->SetItemText(LineNumber, col, Hex);
- m_MemoryList->SetItemFormat(LineNumber, col, ITEM_FORMAT_EDIT, ITEM_FLAGS_EDIT_HEX);
- m_MemoryList->SetItemMaxEditLen(LineNumber, col, 2);
-
- uint32_t vaddr = 0x80000000 | (m_DataStartLoc + Pos);
-
- COLORREF bgColor, fgColor, fgHiColor;
- SelectColors(vaddr, Changed, bgColor, fgColor, fgHiColor);
-
- m_MemoryList->SetItemColours(LineNumber, col, bgColor, fgColor);
- m_MemoryList->SetItemHighlightColours(LineNumber, col, fgHiColor);
-
- if (m_CurrentData[Pos] < 30)
- {
- strcat(Ascii, ".");
- }
- else
- {
- sprintf(AsciiAddOn, "%c", m_CurrentData[Pos]);
- strcat(Ascii, AsciiAddOn);
- }
- }
- else
- {
- m_MemoryList->SetItemText(LineNumber, col, "**");
- m_MemoryList->SetItemFormat(LineNumber, col, ITEM_FORMAT_NONE, ITEM_FLAGS_NONE);
- m_MemoryList->SetItemColours(LineNumber, col, GetSysColor(COLOR_WINDOW), GetSysColor(COLOR_WINDOWTEXT));
- strcat(Ascii, "*");
- }
- if (i != 0xF)
- {
- if ((i & 3) == 3)
- {
- col += 1;
- }
- }
- }
-
- if (strcmp(Ascii, m_MemoryList->GetItemText(LineNumber, 20)) != 0)
- {
- m_MemoryList->SetItemText(LineNumber, 20, Ascii);
+ address = JumpItems[nItem].paddr;
}
-}
-
-void CDebugMemoryView::RefreshMemory(bool ResetCompare)
-{
- m_SymbolColorPhase = 0;
-
- if (g_MMU == NULL)
- {
- return;
- }
-
- if (m_MemoryList && m_MemoryList->GetHasEditItem())
- {
- m_MemoryList->SetFocus();
- }
-
- DWORD NewAddress = m_MemAddr.GetValue();
- if (NewAddress != m_DataStartLoc)
- {
- HWND hScrlBar = GetDlgItem(IDC_SCRL_BAR);
- if (hScrlBar)
- {
- SCROLLINFO si;
-
- si.cbSize = sizeof(si);
- si.fMask = SIF_POS;
- si.nPos = NewAddress >> 0x10;
- ::SetScrollInfo(hScrlBar, SB_CTL, &si, TRUE);
- }
- }
-
- if (ResetCompare)
- {
- // copy current data for change comparison
- m_CompareStartLoc = m_DataStartLoc;
- m_CompareVAddrr = m_DataVAddrr;
- memcpy(m_CompareData, m_CurrentData, sizeof(m_CurrentData));
- memcpy(m_CompareValid, m_DataValid, sizeof(m_CompareValid));
- }
-
- m_DataStartLoc = m_MemAddr.GetValue();
- if (m_DataStartLoc > 0xFFFFFF00) { m_DataStartLoc = 0xFFFFFF00; }
- int WritePos = 0;
-
- m_DataVAddrr = (SendDlgItemMessage(IDC_CHK_VADDR, BM_GETCHECK, 0, 0) & BST_CHECKED) != 0;
-
- if ((m_DataStartLoc & 3) != 0)
- {
- MIPS_WORD word;
- bool ValidData = true;
-
- if (m_DataVAddrr)
- {
- if (!m_Debugger->DebugLW_VAddr(m_DataStartLoc & ~3, word.UW))
- {
- ValidData = false;
- }
- }
- else
- {
- if (!m_Debugger->DebugLW_PAddr(m_DataStartLoc & ~3, word.UW))
- {
- ValidData = false;
- }
- }
-
- int Offset = (m_DataStartLoc & 3);
- for (int i = 0; i < (4 - Offset); i++)
- {
- if (WritePos >= MemoryToDisplay)
- {
- break;
- }
- m_DataValid[WritePos + i] = ValidData;
- if (ValidData)
- {
- m_CurrentData[WritePos + i] = word.UB[3 - (i + Offset)];
- }
- }
- WritePos = 4 - Offset;
- }
-
- for (DWORD Pos = ((m_DataStartLoc + 3) & ~3); Pos < (m_DataStartLoc + MemoryToDisplay); WritePos += 4, Pos += 4)
- {
- MIPS_WORD word;
- bool ValidData = true;
-
- if (m_DataVAddrr)
- {
- if (!m_Debugger->DebugLW_VAddr(Pos, word.UW))
- {
- ValidData = false;
- }
- }
- else
- {
- if (!m_Debugger->DebugLW_PAddr(Pos, word.UW))
- {
- ValidData = false;
- }
- }
-
- for (int i = 0; i < 4; i++)
- {
- if ((WritePos + i) >= MemoryToDisplay)
- {
- break;
- }
- m_DataValid[WritePos + i] = ValidData;
- if (ValidData)
- {
- m_CurrentData[WritePos + i] = word.UB[3 - i];
- }
- }
- }
-
- for (int count = 0; count < 16; count++)
- {
- Insert_MemoryLineDump(count);
- }
-}
-
-bool CDebugMemoryView::GetItemOffset(LPNMHDR lpNMHDR, uint32_t &offset)
-{
- CListNotify *pListNotify = reinterpret_cast(lpNMHDR);
-
- int nRow = pListNotify->m_nItem;
- int nCol = pListNotify->m_nSubItem - 1;
-
- if (nCol < 0 || (nCol % 5) == 4)
- {
- return false;
- }
-
- offset = (nRow * 0x10) + (nCol / 5) * 4 + (nCol % 5);
-
- return true;
-}
-
-bool CDebugMemoryView::GetItemAddress(LPNMHDR lpNMHDR, uint32_t &address)
-{
- uint32_t offset;
- bool bData = GetItemOffset(lpNMHDR, offset);
-
- if (!bData)
- {
- return false;
- }
-
- address = 0x80000000 | (m_DataStartLoc + offset);
-
- return true;
-}
-
-void CDebugMemoryView::SelectColors(uint32_t vaddr, bool changed, COLORREF& bgColor, COLORREF& fgColor, COLORREF& fgHiColor)
-{
- CSymbols::EnterCriticalSection();
- CSymbolEntry* lpSymbol = CSymbols::GetEntryByAddress(vaddr);
-
- if (lpSymbol != NULL)
- {
- m_SymbolColorStride = lpSymbol->TypeSize();
- m_SymbolColorPhase = m_SymbolColorPhase ? 0 : 1;
- }
-
- CSymbols::LeaveCriticalSection();
-
- bool bLocked = m_Breakpoints->MemLockExists(vaddr, 1);
- bool bHaveReadBP = m_Breakpoints->ReadBPExists8(vaddr) == CBreakpoints::BP_SET;
- bool bHaveWriteBP = m_Breakpoints->WriteBPExists8(vaddr) == CBreakpoints::BP_SET;
-
- fgHiColor = RGB(0x00, 0x00, 0x00);
-
- if (bLocked)
- {
- bgColor = RGB(0xDD, 0xAA, 0xAA);
- }
- else if (bHaveReadBP && bHaveWriteBP)
- {
- bgColor = RGB(0xAA, 0xDD, 0xDD);
- }
- else if (bHaveReadBP)
- {
- bgColor = RGB(0xDD, 0xDD, 0xAA);
- }
- else if (bHaveWriteBP)
- {
- bgColor = RGB(0xAA, 0xAA, 0xDD);
- }
- else if (m_SymbolColorStride > 0)
- {
- bgColor = m_SymbolColorPhase ? RGB(0xD0, 0xF0, 0xD0) : RGB(0xAA, 0xCC, 0xAA);
- }
- else
- {
- bgColor = GetSysColor(COLOR_WINDOW);
- fgHiColor = (changed ? RGB(255, 0, 0) : GetSysColor(COLOR_HIGHLIGHTTEXT));
- fgColor = (changed ? RGB(255, 0, 0) : GetSysColor(COLOR_WINDOWTEXT));
- }
-
- if (m_SymbolColorStride > 0)
- {
- m_SymbolColorStride--;
- }
-}
-
-void CDebugMemoryView::CopyNumber(uint32_t address, int numBytes)
-{
- stdstr str;
-
- uint32_t u32;
- uint16_t u16;
- uint8_t u8;
-
- switch (numBytes)
- {
- case 4:
- address &= ~3;
- g_MMU->LW_VAddr(address, u32);
- str = stdstr_f("%08X", u32);
- break;
- case 2:
- address &= ~1;
- g_MMU->LH_VAddr(address, u16);
- str = stdstr_f("%04X", u16);
- break;
- case 1:
- g_MMU->LB_VAddr(address, u8);
- str = stdstr_f("%02X", u8);
- break;
- default:
- return;
- }
-
- if (str.length() == 0)
- {
- return;
- }
-
- HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, str.length() + 1);
- str.copy((char*)GlobalLock(hMem), str.length() + 1);
- GlobalUnlock(hMem);
- OpenClipboard();
- EmptyClipboard();
- SetClipboardData(CF_TEXT, hMem);
- CloseClipboard();
+
+ m_MemAddr.SetValue(address, false, true);
+ m_HexEditCtrl.SetFocus();
}
diff --git a/Source/Project64/UserInterface/Debugger/Debugger-ViewMemory.h b/Source/Project64/UserInterface/Debugger/Debugger-ViewMemory.h
index 3d0b26f01..36e59e88b 100644
--- a/Source/Project64/UserInterface/Debugger/Debugger-ViewMemory.h
+++ b/Source/Project64/UserInterface/Debugger/Debugger-ViewMemory.h
@@ -11,9 +11,78 @@
#pragma once
#include "Debugger-AddSymbol.h"
+#include
+#include
+
+typedef struct
+{
+ NMHDR nmh;
+ int nItem;
+} NMMTRCLICK;
+
+enum
+{
+ MTCN_RCLICK
+};
+
+class CMemTabCtrl :
+ public CWindowImpl
+{
+private:
+ int m_nItemRClick;
+
+public:
+ CMemTabCtrl() :
+ m_nItemRClick(-1)
+ {
+ }
+
+ BOOL Attach(HWND hWndNew)
+ {
+ return SubclassWindow(hWndNew);
+ }
+
+private:
+ void OnLButtonDblClk(UINT /*nFlags*/, CPoint /*point*/)
+ {
+ NMHDR nmh = { m_hWnd, (UINT_PTR)::GetDlgCtrlID(m_hWnd), NM_DBLCLK };
+ ::SendMessage(::GetParent(m_hWnd), WM_NOTIFY, NM_DBLCLK, (LPARAM)&nmh);
+ }
+
+ void OnRButtonDown(UINT /*nFlags*/, CPoint point)
+ {
+ TCHITTESTINFO ht = { point, 0};
+ int nItem = ::SendMessage(m_hWnd, TCM_HITTEST, 0, (LPARAM)&ht);
+ if (nItem != -1)
+ {
+ m_nItemRClick = nItem;
+ }
+ }
+
+ void OnRButtonUp(UINT /*nFlags*/, CPoint point)
+ {
+ TCHITTESTINFO ht = { point, 0 };
+ int nItem = ::SendMessage(m_hWnd, TCM_HITTEST, 0, (LPARAM)&ht);
+ if (nItem != -1 && nItem == m_nItemRClick)
+ {
+ NMMTRCLICK nmrc = { { m_hWnd, (UINT_PTR)::GetDlgCtrlID(m_hWnd), MTCN_RCLICK }, nItem };
+ ::SendMessage(::GetParent(m_hWnd), WM_NOTIFY, MTCN_RCLICK, (LPARAM)&nmrc);
+ }
+ m_nItemRClick = -1;
+ }
+
+ BEGIN_MSG_MAP_EX(CMemTabCtrl)
+ MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
+ MSG_WM_RBUTTONDOWN(OnRButtonDown)
+ MSG_WM_RBUTTONUP(OnRButtonUp)
+ MSG_WM_RBUTTONDBLCLK(OnRButtonDown)
+ END_MSG_MAP()
+};
class CDebugMemoryView :
- public CDebugDialog < CDebugMemoryView >
+ public CDebugDialog,
+ public CDialogResize,
+ public CToolTipDialog
{
public:
enum { IDD = IDD_Debugger_Memory };
@@ -21,74 +90,201 @@ public:
CDebugMemoryView(CDebuggerUI * debugger);
virtual ~CDebugMemoryView(void);
- void ShowAddress(DWORD Address, bool VAddr);
+ void ShowAddress(uint32_t address, bool bVirtual);
private:
+ enum
+ {
+ WM_SHOWADDRESS = WM_USER + 1
+ };
+
+ enum
+ {
+ COLOR_DEFAULT = RGB(0, 0, 0),
+ COLOR_READONLY = RGB(0, 100, 0),
+ BKCOLOR_DEFAULT = RGB(255, 255, 255),
+ COLOR_CHANGED = RGB(255, 0, 0),
+ BKCOLOR_HOT = RGB(240, 240, 240),
+ BKCOLOR_LOCKED = RGB(100, 100, 0),
+ COLOR_BP = RGB(255, 255, 255),
+ BKCOLOR_RWBP = RGB(100, 0, 100),
+ BKCOLOR_RBP = RGB(0, 0, 100),
+ BKCOLOR_WBP = RGB(100, 0, 0),
+ BKCOLOR_CPUREAD = RGB(200, 200, 255),
+ BKCOLOR_CPUWRITE = RGB(255, 200, 200),
+ BKCOLOR_SYMBOL0 = RGB(208, 240, 208),
+ BKCOLOR_SYMBOL1 = RGB(176, 208, 176),
+ BKCOLOR_SAFEEDIT = RGB(255, 230, 255),
+ COLOR_SAFEEDIT = RGB(255, 0, 255)
+ };
+
+ enum
+ {
+ MEMSB_HOTADDR,
+ MEMSB_BLOCK,
+ MEMSB_BLOCKLEN,
+ MEMSB_DMAINFO,
+ MEMSB_SAFEMODE,
+ MEMSB_NUM_PANES
+ };
+
+ enum
+ {
+ MEMSB_HOTADDR_W = 160,
+ MEMSB_BLOCK_W = 120 + MEMSB_HOTADDR_W,
+ MEMSB_BLOCKLEN_W = 60 + MEMSB_BLOCK_W,
+ MEMSB_DMAINFO_W = 60 + MEMSB_BLOCKLEN_W,
+ MEMSB_SAFEMODE_W = -1
+ };
+
+ enum edit_type_t
+ {
+ SE_FILL,
+ //SE_DATA
+ };
+
+ typedef struct
+ {
+ edit_type_t type;
+ uint32_t startAddress;
+ uint32_t endAddress;
+ uint8_t value;
+ //uint8_t* data;
+ } edit_t;
+
+ typedef struct
+ {
+ uint32_t vaddr;
+ uint32_t paddr;
+ uint32_t size;
+ const char* caption;
+ } jump_item_t;
+
+ typedef struct
+ {
+ uint32_t address;
+ bool bVirtual;
+ int numBytesPerGroup;
+ } tab_info_t;
+
+ static jump_item_t JumpItems[];
+ static int GetJumpItemIndex(uint32_t address, bool bVirtual);
+
+ CHexEditCtrl m_HexEditCtrl;
+ CEditNumber32 m_MemAddr;
+ CAddSymbolDlg m_AddSymbolDlg;
+ CButton m_VirtualCheckbox;
+ CMemTabCtrl m_TabCtrl;
+ CStatusBarCtrl m_StatusBar;
+ CComboBox m_CmbJump;
+
+ std::vector m_TabData;
+ CBreakpoints* m_Breakpoints;
+
+ int m_WriteTargetColorStride;
+ int m_ReadTargetColorStride;
+ int m_SymbolColorStride;
+ int m_SymbolColorPhase;
+ uint32_t m_ContextMenuAddress;
+ uint32_t m_HotAddress;
+ bool m_bIgnoreAddressInput;
+ bool m_bVirtualMemory;
+
+ bool m_bSafeEditMode;
+ std::vector m_SafeEditQueue;
+
+ bool GetByte(uint32_t address, uint8_t* value);
+ bool SetByte(uint32_t address, uint8_t value);
+ void SetupJumpMenu(bool bVirtual);
+ bool GetSafeEditValue(uint32_t address, uint8_t* value);
+ void ApplySafeEdits(void);
+ void CopyTextToClipboard(const char* text);
+ void CopyBytesToClipboard(uint32_t startAddress, uint32_t endAddress, bool bHex, bool bIncludeAddresses = false, bool bRowAddresses = false);
+ void CopyGameSharkCodeToClipboard(uint32_t startAddress, uint32_t endAddress);
+ void FillRange(uint32_t startAddress, uint32_t endAddress, uint8_t value);
+ void FollowPointer(bool bContextMenuAddress = true);
+ void JumpToSelection(void);
+ int AddTab(uint32_t address, bool bVirtual, int numBytesPerGroup);
+ int InsertTab(int nItem, uint32_t address, bool bVirtual, int numBytesPerGroup);
+ void DeleteTab(int index);
+ void UpdateCurrentTab(uint32_t address);
+ void OpenNewTab(uint32_t address, bool bVirtual, int numBytesPerGroup, bool bInsert = false, bool bOpenExisting = false);
+ void OpenDuplicateTab(void);
+ void CloseTab(int nItem);
+ void CloseCurrentTab(void);
+ void TabSelChanged(void);
+
+ LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
+ LRESULT OnShowAddress(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
+ LRESULT OnClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
+ void OnAddrChanged(UINT Code, int id, HWND ctl);
+ void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar);
+ void OnExitSizeMove(void);
+ LRESULT OnDestroy(void);
+ LRESULT OnHxGetByteInfo(LPNMHDR lpNMHDR);
+ LRESULT OnHxSetNibble(LPNMHDR lpNMHDR);
+ LRESULT OnHxSetByte(LPNMHDR lpNMHDR);
+ LRESULT OnHxRightClick(LPNMHDR lpNMHDR);
+ LRESULT OnHxEnterPressed(LPNMHDR lpNMHDR);
+ LRESULT OnHxRedrawStarted(LPNMHDR lpNMHDR);
+ LRESULT OnHxBaseAddrChanged(LPNMHDR lpNMHDR);
+ LRESULT OnHxHotAddrChanged(LPNMHDR lpNMHDR);
+ LRESULT OnHxCopy(LPNMHDR lpNMHDR);
+ LRESULT OnHxPaste(LPNMHDR lpNMHDR);
+ LRESULT OnHxCtrlKeyPressed(LPNMHDR lpNMHDR);
+ LRESULT OnHxFillRange(LPNMHDR lpNMHDR);
+ LRESULT OnHxInsertModeChanged(LPNMHDR lpNMHDR);
+ LRESULT OnHxSelectionChanged(LPNMHDR lpNMHDR);
+ LRESULT OnHxGroupSizeChanged(LPNMHDR lpNMHDR);
+ LRESULT OnTabSelChange(LPNMHDR lpNMHDR);
+ LRESULT OnTabDblClick(LPNMHDR lpNMHDR);
+ LRESULT OnTabRClick(LPNMHDR lpNMHDR);
+ LRESULT OnStatusBarClick(LPNMHDR lpNMHDR);
+ void OnJumpComboSelChange(UINT uNotifyCode, int nID, CWindow wndCtl);
+
BEGIN_MSG_MAP_EX(CDebugMemoryView)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
+ MESSAGE_HANDLER(WM_SHOWADDRESS, OnShowAddress)
COMMAND_CODE_HANDLER(BN_CLICKED, OnClicked)
COMMAND_HANDLER_EX(IDC_ADDR_EDIT, EN_CHANGE, OnAddrChanged)
- NOTIFY_HANDLER_EX(IDC_MEM_DETAILS, LCN_MODIFIED, OnMemoryModified)
- NOTIFY_HANDLER_EX(IDC_MEM_DETAILS, LCN_RIGHTCLICK, OnMemoryRightClicked)
- NOTIFY_HANDLER_EX(IDC_MEM_DETAILS, LCN_HOTITEMCHANGED, OnHotItemChanged)
- MESSAGE_HANDLER(WM_ACTIVATE, OnActivate)
MSG_WM_EXITSIZEMOVE(OnExitSizeMove)
MSG_WM_DESTROY(OnDestroy)
MSG_WM_VSCROLL(OnVScroll)
+ COMMAND_HANDLER_EX(IDC_CMB_JUMP, CBN_SELCHANGE, OnJumpComboSelChange)
+ NOTIFY_HANDLER_EX(IDC_STATUSBAR, NM_CLICK, OnStatusBarClick)
+ NOTIFY_HANDLER_EX(IDC_MEMTABS, NM_DBLCLK, OnTabDblClick)
+ NOTIFY_HANDLER_EX(IDC_MEMTABS, TCN_SELCHANGE, OnTabSelChange)
+ NOTIFY_HANDLER_EX(IDC_MEMTABS, MTCN_RCLICK, OnTabRClick)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_GETBYTEINFO, OnHxGetByteInfo)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_SETNIBBLE, OnHxSetNibble)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_SETBYTE, OnHxSetByte)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_RCLICK, OnHxRightClick)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_HOTADDRCHANGED, OnHxHotAddrChanged)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_REDRAWSTARTED, OnHxRedrawStarted)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_BASEADDRCHANGED, OnHxBaseAddrChanged)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_HOTADDRCHANGED, OnHxHotAddrChanged)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_PASTE, OnHxPaste)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_CTRLKEYPRESSED, OnHxCtrlKeyPressed)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_FILLRANGE, OnHxFillRange)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_COPY, OnHxCopy)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_INSERTMODECHANGED, OnHxInsertModeChanged)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_ENTERPRESSED, OnHxEnterPressed)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_SELCHANGED, OnHxSelectionChanged)
+ NOTIFY_HANDLER_EX(IDC_HEXEDIT, HXN_GROUPSIZECHANGED, OnHxGroupSizeChanged)
+ CHAIN_MSG_MAP(CDialogResize)
END_MSG_MAP()
- LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
- LRESULT OnClicked(WORD wNotifyCode, WORD wID, HWND /*hWndCtl*/, BOOL& bHandled);
- void OnAddrChanged(UINT Code, int id, HWND ctl);
- void OnVScroll(int request, short Pos, HWND ctrl);
- void OnExitSizeMove(void);
- LRESULT OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
- LRESULT OnMemoryModified(LPNMHDR lpNMHDR);
- LRESULT OnMemoryRightClicked(LPNMHDR lpNMHDR);
- LRESULT OnHotItemChanged(LPNMHDR lpNMHDR);
- LRESULT OnDestroy(void);
+ BEGIN_DLGRESIZE_MAP(CDebugMemoryView)
+ DLGRESIZE_CONTROL(IDC_CMB_JUMP, DLSZ_MOVE_X)
+ DLGRESIZE_CONTROL(IDC_STATUSBAR, DLSZ_SIZE_X | DLSZ_MOVE_Y)
+ DLGRESIZE_CONTROL(IDC_HEXEDIT, DLSZ_SIZE_X | DLSZ_SIZE_Y)
+ DLGRESIZE_CONTROL(IDC_MEMTABS, DLSZ_SIZE_X)
+ DLGRESIZE_CONTROL(IDC_SCRL_BAR, DLSZ_MOVE_X | DLSZ_SIZE_Y)
+ END_DLGRESIZE_MAP()
- void Insert_MemoryLineDump(int LineNumber);
- void RefreshMemory(bool ResetCompare);
+ BEGIN_TOOLTIP_MAP()
+ TOOLTIP(IDC_SYMBOLS_BTN, "Symbols...")
+ TOOLTIP(IDC_CHK_VADDR, "Checked = Use virtual address space (CPU), Unchecked = Use physical address space (RCP)")
+ END_TOOLTIP_MAP()
+};
- HANDLE m_AutoRefreshThread;
- static DWORD WINAPI AutoRefreshProc(void* _self);
-
- void SelectColors(uint32_t address, bool changed, COLORREF& bgColor, COLORREF& fgColor, COLORREF& fgHiColor);
- bool GetItemOffset(LPNMHDR lpNMHDR, uint32_t &offset);
- bool GetItemAddress(LPNMHDR lpNMHDR, uint32_t &address);
-
- void CopyNumber(uint32_t address, int numBytes);
-
- enum { MemoryToDisplay = 0x100 };
-
- static CDebugMemoryView* _this;
- static HHOOK hWinMessageHook;
- static LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam);
-
- void InterceptMouseWheel(WPARAM wParam, LPARAM lParam);
-
- CEditNumber32 m_MemAddr;
- CListCtrl * m_MemoryList;
- CAddSymbolDlg m_AddSymbolDlg;
- CStatic m_SymInfo;
- CStatic m_DMAInfo;
-
- bool m_bAutoRefreshEnabled;
-
- CBreakpoints* m_Breakpoints;
-
- int m_SymbolColorStride;
- int m_SymbolColorPhase;
- DWORD m_CtxMenuAddr;
-
- DWORD m_DataStartLoc;
- bool m_DataVAddrr;
- BYTE m_CurrentData[MemoryToDisplay];
- bool m_DataValid[MemoryToDisplay];
-
- DWORD m_CompareStartLoc;
- bool m_CompareVAddrr;
- BYTE m_CompareData[MemoryToDisplay];
- bool m_CompareValid[MemoryToDisplay];
-};
\ No newline at end of file
diff --git a/Source/Project64/UserInterface/Debugger/Debugger.cpp b/Source/Project64/UserInterface/Debugger/Debugger.cpp
index 37889575e..6882787d4 100644
--- a/Source/Project64/UserInterface/Debugger/Debugger.cpp
+++ b/Source/Project64/UserInterface/Debugger/Debugger.cpp
@@ -233,10 +233,6 @@ void CDebuggerUI::OpenMemoryDump()
void CDebuggerUI::OpenMemoryWindow(void)
{
- if (g_MMU == NULL)
- {
- return;
- }
if (m_MemoryView == NULL)
{
m_MemoryView = new CDebugMemoryView(this);
@@ -462,192 +458,6 @@ CCPULog* CDebuggerUI::CPULog()
return m_CPULog;
}
-// thread safe LW_PAddr
-// does not trigger application breakpoint if paddr is invalid
-bool CDebuggerUI::DebugLW_PAddr(uint32_t paddr, uint32_t& value)
-{
- if (g_MMU == NULL)
- {
- return false;
- }
-
- if ((paddr < g_MMU->RdramSize()) || // RDRAM
- (paddr >= 0x04000000 && paddr <= 0x04001FFF)) // DMEM/IMEM
- {
- value = *(uint32_t*)(g_MMU->Rdram() + paddr);
- return true;
- }
- else if (paddr >= 0x05000000 && paddr <= 0x050004FF) // 64DD buffer
- {
- // todo
- return false;
- }
- else if (paddr >= 0x06000000 && paddr <= 0x06FFFFFF) // Cartridge Domain 1 (Address 1) (64DD IPL ROM)
- {
- uint32_t iplRomOffset = paddr - 0x06000000;
-
- if (g_DDRom != NULL && iplRomOffset < g_DDRom->GetRomSize())
- {
- value = *(uint32_t*)(g_MMU->Rdram() + paddr);
- return true;
- }
- }
- else if (paddr >= 0x08000000 && paddr < 0x08FFFFFF) // Cartridge Domain 2 (Address 2)
- {
- uint32_t saveOffset = paddr & 0x000FFFFF;
-
- if (g_System->m_SaveUsing == SaveChip_Sram && saveOffset <= 0x7FFF) // sram
- {
- uint8_t tmp[4] = "";
- CSram *sram = g_MMU->GetSram();
- sram->DmaFromSram(tmp, paddr - 0x08000000, 4);
- value = tmp[3] << 24 | tmp[2] << 16 | tmp[1] << 8 | tmp[0];
- return true;
- }
- else if (g_System->m_SaveUsing == SaveChip_FlashRam && saveOffset == 0) // flash ram status
- {
- CFlashram* flashRam = g_MMU->GetFlashram();
- value = flashRam->ReadFromFlashStatus(0x08000000);
- return true;
- }
- }
- else if (paddr >= 0x10000000 && paddr <= 0x15FFFFFF) // Cartridge ROM
- {
- uint32_t cartRomOffset = paddr - 0x10000000;
- if (g_Rom != NULL && paddr < g_Rom->GetRomSize())
- {
- value = *(uint32_t*)(g_Rom->GetRomAddress() + cartRomOffset);
- return true;
- }
- }
- else if (paddr >= 0x1FC00000 && paddr <= 0x1FC007BF) // PIF ROM
- {
- return false;
- }
- else if (paddr >= 0x1FC007C0 && paddr <= 0x1FC007FF) // PIF RAM
- {
- uint32_t pifRamOffset = paddr - 0x1FC007C0;
- value = *(uint32_t*)(g_MMU->PifRam() + pifRamOffset);
- return true;
- }
-
- // note: write-only registers are excluded
- switch (paddr)
- {
- case 0x03F00000: value = g_Reg->RDRAM_CONFIG_REG; return true;
- case 0x03F00004: value = g_Reg->RDRAM_DEVICE_ID_REG; return true;
- case 0x03F00008: value = g_Reg->RDRAM_DELAY_REG; return true;
- case 0x03F0000C: value = g_Reg->RDRAM_MODE_REG; return true;
- case 0x03F00010: value = g_Reg->RDRAM_REF_INTERVAL_REG; return true;
- case 0x03F00014: value = g_Reg->RDRAM_REF_ROW_REG; return true;
- case 0x03F00018: value = g_Reg->RDRAM_RAS_INTERVAL_REG; return true;
- case 0x03F0001C: value = g_Reg->RDRAM_MIN_INTERVAL_REG; return true;
- case 0x03F00020: value = g_Reg->RDRAM_ADDR_SELECT_REG; return true;
- case 0x03F00024: value = g_Reg->RDRAM_DEVICE_MANUF_REG; return true;
- case 0x04040010: value = g_Reg->SP_STATUS_REG; return true;
- case 0x04040014: value = g_Reg->SP_DMA_FULL_REG; return true;
- case 0x04040018: value = g_Reg->SP_DMA_BUSY_REG; return true;
- case 0x0404001C: value = g_Reg->SP_SEMAPHORE_REG; return true;
- case 0x04080000: value = g_Reg->SP_PC_REG; return true;
- case 0x0410000C: value = g_Reg->DPC_STATUS_REG; return true;
- case 0x04100010: value = g_Reg->DPC_CLOCK_REG; return true;
- case 0x04100014: value = g_Reg->DPC_BUFBUSY_REG; return true;
- case 0x04100018: value = g_Reg->DPC_PIPEBUSY_REG; return true;
- case 0x0410001C: value = g_Reg->DPC_TMEM_REG; return true;
- case 0x04300000: value = g_Reg->MI_MODE_REG; return true;
- case 0x04300004: value = g_Reg->MI_VERSION_REG; return true;
- case 0x04300008: value = g_Reg->MI_INTR_REG; return true;
- case 0x0430000C: value = g_Reg->MI_INTR_MASK_REG; return true;
- case 0x04400000: value = g_Reg->VI_STATUS_REG; return true;
- case 0x04400004: value = g_Reg->VI_ORIGIN_REG; return true;
- case 0x04400008: value = g_Reg->VI_WIDTH_REG; return true;
- case 0x0440000C: value = g_Reg->VI_INTR_REG; return true;
- case 0x04400010: value = g_Reg->VI_V_CURRENT_LINE_REG; return true;
- case 0x04400014: value = g_Reg->VI_BURST_REG; return true;
- case 0x04400018: value = g_Reg->VI_V_SYNC_REG; return true;
- case 0x0440001C: value = g_Reg->VI_H_SYNC_REG; return true;
- case 0x04400020: value = g_Reg->VI_LEAP_REG; return true;
- case 0x04400024: value = g_Reg->VI_H_START_REG; return true;
- case 0x04400028: value = g_Reg->VI_V_START_REG; return true;
- case 0x0440002C: value = g_Reg->VI_V_BURST_REG; return true;
- case 0x04400030: value = g_Reg->VI_X_SCALE_REG; return true;
- case 0x04400034: value = g_Reg->VI_Y_SCALE_REG; return true;
- case 0x04600000: value = g_Reg->PI_DRAM_ADDR_REG; return true;
- case 0x04600004: value = g_Reg->PI_CART_ADDR_REG; return true;
- case 0x04600008: value = g_Reg->PI_RD_LEN_REG; return true;
- case 0x0460000C: value = g_Reg->PI_WR_LEN_REG; return true;
- case 0x04600010: value = g_Reg->PI_STATUS_REG; return true;
- case 0x04600014: value = g_Reg->PI_DOMAIN1_REG; return true;
- case 0x04600018: value = g_Reg->PI_BSD_DOM1_PWD_REG; return true;
- case 0x0460001C: value = g_Reg->PI_BSD_DOM1_PGS_REG; return true;
- case 0x04600020: value = g_Reg->PI_BSD_DOM1_RLS_REG; return true;
- case 0x04600024: value = g_Reg->PI_DOMAIN2_REG; return true;
- case 0x04600028: value = g_Reg->PI_BSD_DOM2_PWD_REG; return true;
- case 0x0460002C: value = g_Reg->PI_BSD_DOM2_PGS_REG; return true;
- case 0x04600030: value = g_Reg->PI_BSD_DOM2_RLS_REG; return true;
- case 0x04700000: value = g_Reg->RI_MODE_REG; return true;
- case 0x04700004: value = g_Reg->RI_CONFIG_REG; return true;
- case 0x04700008: value = g_Reg->RI_CURRENT_LOAD_REG; return true;
- case 0x0470000C: value = g_Reg->RI_SELECT_REG; return true;
- case 0x04700010: value = g_Reg->RI_REFRESH_REG; return true;
- case 0x04700014: value = g_Reg->RI_LATENCY_REG; return true;
- case 0x04700018: value = g_Reg->RI_RERROR_REG; return true;
- case 0x0470001C: value = g_Reg->RI_WERROR_REG; return true;
- case 0x04800018: value = g_Reg->SI_STATUS_REG; return true;
- case 0x05000500: value = g_Reg->ASIC_DATA; return true;
- case 0x05000504: value = g_Reg->ASIC_MISC_REG; return true;
- case 0x05000508: value = g_Reg->ASIC_STATUS; return true;
- case 0x0500050C: value = g_Reg->ASIC_CUR_TK; return true;
- case 0x05000510: value = g_Reg->ASIC_BM_STATUS; return true;
- case 0x05000514: value = g_Reg->ASIC_ERR_SECTOR; return true;
- case 0x05000518: value = g_Reg->ASIC_SEQ_STATUS; return true;
- case 0x0500051C: value = g_Reg->ASIC_CUR_SECTOR; return true;
- case 0x05000520: value = g_Reg->ASIC_HARD_RESET; return true;
- case 0x05000524: value = g_Reg->ASIC_C1_S0; return true;
- case 0x05000528: value = g_Reg->ASIC_HOST_SECBYTE; return true;
- case 0x0500052C: value = g_Reg->ASIC_C1_S2; return true;
- case 0x05000530: value = g_Reg->ASIC_SEC_BYTE; return true;
- case 0x05000534: value = g_Reg->ASIC_C1_S4; return true;
- case 0x05000538: value = g_Reg->ASIC_C1_S6; return true;
- case 0x0500053C: value = g_Reg->ASIC_CUR_ADDR; return true;
- case 0x05000540: value = g_Reg->ASIC_ID_REG; return true;
- case 0x05000544: value = g_Reg->ASIC_TEST_REG; return true;
- case 0x05000548: value = g_Reg->ASIC_TEST_PIN_SEL; return true;
- case 0x04500004:
- if (g_System->bFixedAudio())
- {
- value = g_Audio->GetLength();
- }
- else
- {
- CAudioPlugin* audioPlg = g_Plugins->Audio();
- value = (audioPlg->AiReadLength != NULL) ? audioPlg->AiReadLength() : 0;
- }
- return true;
- case 0x0450000C:
- value = g_System->bFixedAudio() ? g_Audio->GetStatus() : g_Reg->AI_STATUS_REG;
- return true;
- }
-
- return false;
-}
-
-bool CDebuggerUI::DebugLW_VAddr(uint32_t vaddr, uint32_t& value)
-{
- if (vaddr <= 0x7FFFFFFF || vaddr >= 0xC0000000) // KUSEG, KSEG2 (TLB)
- {
- if (g_MMU == NULL)
- {
- return false;
- }
-
- return g_MMU->LW_VAddr(vaddr, value);
- }
-
- uint32_t paddr = vaddr & 0x1FFFFFFF;
- return DebugLW_PAddr(paddr, value);
-}
-
// CDebugger implementation
void CDebuggerUI::TLBChanged()
diff --git a/Source/Project64/UserInterface/Debugger/MemoryScanner.cpp b/Source/Project64/UserInterface/Debugger/MemoryScanner.cpp
index e7957bfc8..6e0207598 100644
--- a/Source/Project64/UserInterface/Debugger/MemoryScanner.cpp
+++ b/Source/Project64/UserInterface/Debugger/MemoryScanner.cpp
@@ -989,9 +989,9 @@ bool CMemoryScanner::NextScan()
int CMemoryScanner::HexDigitVal(char c)
{
- if (c >= '0' && c < '9') return (c - '0');
- if (c >= 'A' && c < 'F') return (c - 'A') + 0x0A;
- if (c >= 'a' && c < 'f') return (c - 'a') + 0x0A;
+ if (c >= '0' && c <= '9') return (c - '0');
+ if (c >= 'A' && c <= 'F') return (c - 'A') + 0x0A;
+ if (c >= 'a' && c <= 'f') return (c - 'a') + 0x0A;
return 0;
}
diff --git a/Source/Project64/UserInterface/Debugger/debugger.h b/Source/Project64/UserInterface/Debugger/debugger.h
index 20e23ca83..89836b177 100644
--- a/Source/Project64/UserInterface/Debugger/debugger.h
+++ b/Source/Project64/UserInterface/Debugger/debugger.h
@@ -12,6 +12,7 @@
#include
#include
#include
+#include "DebugMMU.h"
class CDumpMemory;
class CDebugMemoryView;
@@ -33,7 +34,8 @@ class CScriptSystem;
class CDebuggerUI :
public CDebugger,
- public CDebugSettings
+ public CDebugSettings,
+ public CDebugMMU
{
public:
CDebuggerUI();
@@ -88,8 +90,8 @@ public:
static void GameNameChanged(CDebuggerUI * _this);
static void SteppingOpsChanged(CDebuggerUI * _this);
- bool DebugLW_PAddr(uint32_t vaddr, uint32_t& value);
- bool DebugLW_VAddr(uint32_t vaddr, uint32_t& value);
+ //bool DebugLW_PAddr(uint32_t vaddr, uint32_t& value);
+ //bool DebugLW_VAddr(uint32_t vaddr, uint32_t& value);
protected:
void TLBChanged(void);
diff --git a/Source/Project64/UserInterface/MainMenu.cpp b/Source/Project64/UserInterface/MainMenu.cpp
index de7e3ca79..c66139546 100644
--- a/Source/Project64/UserInterface/MainMenu.cpp
+++ b/Source/Project64/UserInterface/MainMenu.cpp
@@ -1252,7 +1252,6 @@ void CMainMenu::FillOutMenu(HMENU hMenu)
Item.Reset(SUB_MENU, EMPTY_STRING, EMPTY_STDSTR, &DebugR4300Menu, L"&R4300i");
DebugMenu.push_back(Item);
Item.Reset(SUB_MENU, EMPTY_STRING, EMPTY_STDSTR, &DebugMemoryMenu, L"Memory");
- Item.SetItemEnabled(CPURunning);
DebugMenu.push_back(Item);
DebugMenu.push_back(MENU_ITEM(SPLITER));
Item.Reset(SUB_MENU, EMPTY_STRING, EMPTY_STDSTR, &DebugProfileMenu, L"Profile");
diff --git a/Source/Project64/UserInterface/UIResources.rc b/Source/Project64/UserInterface/UIResources.rc
index f20c5839f..727d35b84 100644
--- a/Source/Project64/UserInterface/UIResources.rc
+++ b/Source/Project64/UserInterface/UIResources.rc
@@ -509,24 +509,19 @@ BEGIN
COMBOBOX IDC_LANG_SEL,105,77,112,120,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
END
-IDD_Debugger_Memory DIALOGEX 0, 0, 435, 204
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+IDD_Debugger_Memory DIALOGEX 0, 0, 321, 199
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION "Memory"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
- EDITTEXT IDC_ADDR_EDIT,35,5,49,12,ES_AUTOHSCROLL
- LTEXT "Address:",IDC_STATIC,4,6,29,11
- CONTROL "Is VAddr?",IDC_CHK_VADDR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,111,7,46,8
- PUSHBUTTON "Dump",IDC_DUMP_MEM,319,4,54,13
- PUSHBUTTON "Search",IDC_SEARCH_MEM,377,4,54,13
- SCROLLBAR IDC_SCRL_BAR,421,23,11,154,SBS_VERT
- PUSHBUTTON "Refresh",IDC_REFRSH_MEM,161,4,54,13
- CONTROL "Mem Details",IDC_MEM_DETAILS,"ListCtrl",WS_TABSTOP,4,23,416,154
- PUSHBUTTON "...",IDC_SYMBOLS_BTN,86,4,21,13
- LTEXT "",IDC_SYM_INFO,8,198,418,8
- LTEXT "",IDC_DMA_INFO,8,208,415,8
- GROUPBOX "",IDC_STATIC,4,190,428,30
- CONTROL "Auto",IDC_CHK_AUTOREFRESH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,220,7,31,8
+ EDITTEXT IDC_ADDR_EDIT,5,20,49,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_SYMBOLS_BTN,58,20,21,13
+ CONTROL "Virtual",IDC_CHK_VADDR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,83,20,40,13
+ CONTROL "HexEdit",IDC_HEXEDIT,"HexEditCtrl",WS_TABSTOP,0,36,310,147
+ SCROLLBAR IDC_SCRL_BAR,310,36,11,147,SBS_VERT
+ CONTROL "",IDC_MEMTABS,"SysTabControl32",TCS_FOCUSNEVER,0,3,319,13
+ COMBOBOX IDC_CMB_JUMP,194,20,123,12,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ CONTROL "",IDC_STATUSBAR,"msctls_statusbar32",WS_TABSTOP,0,188,321,11
END
IDD_Debugger_Search DIALOGEX 0, 0, 357, 257
@@ -1597,8 +1592,7 @@ BEGIN
IDD_Debugger_Memory, DIALOG
BEGIN
- RIGHTMARGIN, 431
- BOTTOMMARGIN, 203
+ BOTTOMMARGIN, 196
END
IDD_Debugger_Search, DIALOG
@@ -1954,23 +1948,39 @@ IDR_MEM_BP_POPUP MENU
BEGIN
POPUP "PopupMenu"
BEGIN
- MENUITEM "Toggle read breakpoint", ID_POPUPMENU_TOGGLERBP
- MENUITEM "Toggle write breakpoint", ID_POPUPMENU_TOGGLEWBP
- MENUITEM "Clear all breakpoints", ID_POPUPMENU_CLEARALLBPS
+ MENUITEM "Read breakpoint\tCtrl+R", ID_POPUPMENU_TOGGLERBP
+ MENUITEM "Write breakpoint\tCtrl+W", ID_POPUPMENU_TOGGLEWBP
+ MENUITEM "Lock value\tCtrl+E", ID_POPUPMENU_TOGGLELOCK
MENUITEM SEPARATOR
- MENUITEM "Toggle lock", ID_POPUPMENU_TOGGLELOCK
- MENUITEM "Clear locks", ID_POPUPMENU_CLEARLOCKS
+ MENUITEM "Clear breakpoints\tCtrl+Q", ID_POPUPMENU_CLEARALLBPS
+ MENUITEM "Clear locks\tCtrl+Q", ID_POPUPMENU_CLEARLOCKS
MENUITEM SEPARATOR
- MENUITEM "View disassembly...", ID_POPUPMENU_VIEWDISASM
+ MENUITEM "Jump here\tCtrl+G", ID_POPUPMENU_JUMPHERE
+ MENUITEM "Follow pointer\tCtrl+Space", ID_POPUPMENU_FOLLOWPOINTER
+ MENUITEM SEPARATOR
+ POPUP "Byte group size"
+ BEGIN
+ MENUITEM "1\tCtrl+1", ID_POPUPMENU_BYTEGROUPSIZE_1
+ MENUITEM "2\tCtrl+2", ID_POPUPMENU_BYTEGROUPSIZE_2
+ MENUITEM "4\tCtrl+4", ID_POPUPMENU_BYTEGROUPSIZE_4
+ MENUITEM "8\tCtrl+8", ID_POPUPMENU_BYTEGROUPSIZE_8
+ END
+ MENUITEM "Safe mode\tINS", ID_POPUPMENU_SAFEMODE
MENUITEM SEPARATOR
MENUITEM "Add symbol...", ID_POPUPMENU_ADDSYMBOL
+ MENUITEM "View disassembly...", ID_POPUPMENU_VIEWDISASM
+ MENUITEM "Dump...\tCtrl+S", ID_POPUPMENU_DUMP
+ MENUITEM "Search...\tCtrl+F", ID_POPUPMENU_SEARCH
MENUITEM SEPARATOR
- POPUP "Copy"
+ POPUP "Copy special"
BEGIN
- MENUITEM "Word", ID_POPUPMENU_COPY_WORD
- MENUITEM "Halfword", ID_POPUPMENU_COPY_HALFWORD
- MENUITEM "Byte", ID_POPUPMENU_COPY_BYTE
+ MENUITEM "Data with group addresses", ID_POPUPMENU_COPYDATAWITHGROUPADDRESSES
+ MENUITEM "Data with row addresses", ID_POPUPMENU_COPYDATAWITHROWADDRESSES
+ MENUITEM "GameShark code", ID_POPUPMENU_COPYGAMESHARKCODE
END
+ MENUITEM "Copy\tCtrl+C", ID_POPUPMENU_COPY
+ MENUITEM "Paste\tCtrl+V", ID_POPUPMENU_PASTE
+ MENUITEM "Zero-fill\tDEL", ID_POPUPMENU_ZEROFILL
END
END
diff --git a/Source/Project64/UserInterface/WTLControls/HexEditCtrl.cpp b/Source/Project64/UserInterface/WTLControls/HexEditCtrl.cpp
new file mode 100644
index 000000000..e1497bb0d
--- /dev/null
+++ b/Source/Project64/UserInterface/WTLControls/HexEditCtrl.cpp
@@ -0,0 +1,1747 @@
+#include "stdafx.h"
+#include "HexEditCtrl.h"
+#include
+
+CHexEditCtrl::CHexEditCtrl(void) :
+ m_BaseAddress(0x80000000),
+ m_DrawnBaseAddress(0xFFFFFFFF),
+ m_SelStartAddress(0),
+ m_SelEndAddress(0),
+ m_SelStartCellSide(HX_LEFT),
+ m_SelEndCellSide(HX_LEFT),
+ m_bInsertMode(false),
+ m_CaretAddress(0),
+ m_bCaretLoNibble(false),
+ m_bCaretVisible(false),
+ m_bHaveCaret(false),
+ m_bShowHotAddress(false),
+ m_HotAddress(0),
+ m_Font(NULL),
+ m_BackBMP(NULL),
+ m_BackDC(NULL),
+ m_CharWidth(0),
+ m_CharHeight(0),
+ m_FocusedColumn(HX_COL_NONE),
+ m_hCursorIBeam(NULL),
+ m_hCursorDefault(NULL),
+ m_DragScrollDelta(0),
+ m_AddressColumnRect({0}),
+ m_HexDataColumnRect({0}),
+ m_AsciiColumnRect({0}),
+ m_bDblClicked(false),
+ m_bLButtonDown(false),
+ m_bMouseDragging(false),
+ m_bLayoutChanged(false),
+ m_OldBytes(NULL),
+ m_NewBytes(NULL),
+ m_NumBytesPerGroup(4),
+ m_NumByteGroupsPerRow(0),
+ m_NumVisibleRows(0),
+ m_NumVisibleBytes(0),
+ m_RealSelStartAddress(0),
+ m_RealSelEndAddress(0),
+ m_bHaveRealSel(false)
+{
+ WNDCLASS wc;
+ if (!GetClassInfo(GetModuleHandle(NULL), _T("HexEditCtrl"), &wc))
+ {
+ GetWndClassInfo().m_wc.lpfnWndProc = m_pfnSuperWindowProc;
+ GetWndClassInfo().Register(&m_pfnSuperWindowProc);
+ }
+}
+
+CHexEditCtrl::~CHexEditCtrl(void)
+{
+}
+
+int CALLBACK CHexEditCtrl::HaveFontCb(CONST LOGFONTA *lplf, CONST TEXTMETRICA *lptm, DWORD FontType, LPARAM lParam)
+{
+ const char* name = (const char*)lParam;
+ if (strcmp(lplf->lfFaceName, name) == 0)
+ {
+ return 0;
+ }
+ return 1;
+}
+
+bool CHexEditCtrl::HaveFont(HDC hdc, const char* name)
+{
+ if (EnumFonts(hdc, name, HaveFontCb, (LPARAM)name) == 0)
+ {
+ return true;
+ }
+ return false;
+}
+
+BOOL CHexEditCtrl::Attach(HWND hWnd)
+{
+ if (m_hWnd != NULL)
+ {
+ return FALSE;
+ }
+
+ if (!CWindowImpl::SubclassWindow(hWnd))
+ {
+ return FALSE;
+ }
+
+ CRect wndRc;
+ if (!GetWindowRect(&wndRc))
+ {
+ return FALSE;
+ }
+
+ HDC hdc = GetDC();
+ HBITMAP hOldBMP;
+ HFONT hOldFont;
+
+ m_BackDC = CreateCompatibleDC(hdc);
+ m_BackBMP = CreateCompatibleBitmap(hdc, wndRc.Width(), wndRc.Height());
+ hOldBMP = (HBITMAP)SelectObject(m_BackDC, m_BackBMP);
+ DeleteObject(hOldBMP);
+
+ m_hCursorIBeam = LoadCursor(NULL, IDC_IBEAM);
+ m_hCursorDefault = LoadCursor(NULL, IDC_ARROW);
+
+ float dpiScale = ::GetDeviceCaps(hdc, LOGPIXELSX) / 96.0f;
+
+ if (HaveFont(hdc, "Consolas"))
+ {
+ m_Font = CreateFont((int)(14 * dpiScale), 0, 0, 0,
+ FW_DONTCARE,
+ FALSE,
+ FALSE,
+ FALSE,
+ DEFAULT_CHARSET,
+ OUT_DEFAULT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY,
+ FF_DONTCARE | FIXED_PITCH,
+ "Consolas");
+ }
+ else
+ {
+ m_Font = (HFONT)GetStockObject(ANSI_FIXED_FONT);
+ }
+
+ hOldFont = (HFONT)SelectObject(m_BackDC, m_Font);
+ DeleteObject(hOldFont);
+
+ TEXTMETRIC tm;
+ GetTextMetrics(m_BackDC, &tm);
+ m_CharHeight = tm.tmHeight;
+ m_CharWidth = tm.tmAveCharWidth;
+
+ UpdateLayoutInfo();
+ ReallocByteBuffers();
+
+ CRect clrRc(0, 0, wndRc.Width(), wndRc.Height());
+ HBRUSH hbrush = CreateSolidBrush(BKCOLOR_DEFAULT);
+ FillRect(m_BackDC, clrRc, hbrush);
+ DeleteObject(hbrush);
+
+ SetTimer(TIMER_ID_AUTO_REFRESH, 20, NULL);
+ SetTimer(TIMER_ID_DRAG_SCROLL, 50, NULL);
+
+ ReleaseDC(hdc);
+
+ return TRUE;
+}
+
+HWND CHexEditCtrl::Detach(void)
+{
+ if (m_hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ KillTimer(TIMER_ID_AUTO_REFRESH);
+ KillTimer(TIMER_ID_DRAG_SCROLL);
+
+ if (m_BackBMP != NULL)
+ {
+ DeleteObject(m_BackBMP);
+ m_BackBMP = NULL;
+ }
+
+ if (m_BackDC != NULL)
+ {
+ DeleteObject(m_BackDC);
+ m_BackDC = NULL;
+ }
+
+ if (m_Font != NULL)
+ {
+ DeleteObject(m_Font);
+ m_Font = NULL;
+ }
+
+ if (m_NewBytes != NULL)
+ {
+ free(m_NewBytes);
+ m_NewBytes = NULL;
+ }
+
+ if (m_OldBytes != NULL)
+ {
+ free(m_OldBytes);
+ m_OldBytes = NULL;
+ }
+
+ return CWindowImpl::UnsubclassWindow();
+}
+
+void CHexEditCtrl::Draw(void)
+{
+ Notify(HXN_REDRAWSTARTED);
+
+ int startCellIndex = 0;
+ uint32_t startAddress = m_BaseAddress;
+ int numBytesToUpdate = m_NumVisibleBytes;
+ bool bIgnoreDiff = false;
+
+ if (m_BaseAddress != m_DrawnBaseAddress)
+ {
+ m_bShowHotAddress = false;
+ int64_t addrDelta = (int64_t)m_BaseAddress - (int64_t)m_DrawnBaseAddress;
+
+ // scroll optimization
+ if ((addrDelta % m_NumBytesPerRow) == 0 && abs(addrDelta) < (m_NumVisibleBytes - m_NumBytesPerRow))
+ {
+ int rowDelta = (int)(addrDelta / m_NumBytesPerRow);
+ int numBytesScrolled = abs(rowDelta) * m_NumBytesPerRow;
+ int numBytesToShift = (m_NumVisibleBytes - numBytesScrolled) - m_NumBytesPerRow;
+ int shiftSrcIndex = 0, shiftDstIndex = 0;
+
+ numBytesToUpdate = numBytesScrolled + m_NumBytesPerRow;
+
+ CRect rcScrollArea;
+ rcScrollArea.left = m_HexDataColumnRect.left;
+ rcScrollArea.right = m_AsciiColumnRect.right;
+ rcScrollArea.top = m_HexDataColumnRect.top;
+ rcScrollArea.bottom = m_HexDataColumnRect.bottom;
+
+ if (rowDelta > 0)
+ {
+ rcScrollArea.bottom -= m_CharHeight;
+ startCellIndex = m_NumVisibleBytes - numBytesToUpdate;
+ shiftSrcIndex = 0 + numBytesScrolled;
+ shiftDstIndex = 0;
+ }
+ else if (rowDelta < 0)
+ {
+ rcScrollArea.top += m_CharHeight;
+ startCellIndex = 0;
+ shiftSrcIndex = 0 + m_NumBytesPerRow;
+ shiftDstIndex = shiftSrcIndex + numBytesScrolled;
+ }
+
+ startAddress = m_BaseAddress + startCellIndex;
+
+ memmove(&m_OldBytes[shiftDstIndex], &m_OldBytes[shiftSrcIndex], numBytesToShift * sizeof(HXBYTEINFO));
+ memmove(&m_NewBytes[shiftDstIndex], &m_NewBytes[shiftSrcIndex], numBytesToShift * sizeof(HXBYTEINFO));
+
+ ScrollDC(m_BackDC, 0, -rowDelta * m_CharHeight, &rcScrollArea, &rcScrollArea, NULL, NULL);
+ InvalidateRect(&rcScrollArea, false);
+ }
+
+ DrawAddressColumn();
+ DrawHeader();
+
+ m_DrawnBaseAddress = m_BaseAddress;
+ bIgnoreDiff = true;
+ }
+
+ if (m_bLayoutChanged)
+ {
+ bIgnoreDiff = true;
+ m_bLayoutChanged = false;
+ }
+
+ int numOverflowBytes = 0;
+
+ if (startAddress + numBytesToUpdate < startAddress)
+ {
+ numOverflowBytes = (startAddress + numBytesToUpdate);
+ }
+
+ for (int i = 0; i < numOverflowBytes; i++)
+ {
+ m_NewBytes[numBytesToUpdate - numOverflowBytes + i].bHidden = true;
+ }
+
+ NotifyGetByteInfo(startAddress, numBytesToUpdate - numOverflowBytes, bIgnoreDiff, &m_OldBytes[startCellIndex], &m_NewBytes[startCellIndex]);
+
+ std::unordered_map drawnByteRects;
+
+ for (int i = 0; i < numBytesToUpdate; i++)
+ {
+ uint32_t address = startAddress + i;
+
+ HXBYTEINFO* oldByte = &m_OldBytes[startCellIndex + i];
+ HXBYTEINFO* newByte = &m_NewBytes[startCellIndex + i];
+
+ if (IsSelected(address))
+ {
+ // override owner-provided colors if selected
+ if (newByte->bkColor != BKCOLOR_DEFAULT)
+ {
+ // blend owner color with selection color if bkcolor isn't default
+ newByte->bkColor = BlendColor(BKCOLOR_SEL_FOCUSED, newByte->bkColor);
+ newByte->color = COLOR_SEL_FOCUSED;
+ }
+ else
+ {
+ newByte->bkColor = BKCOLOR_SEL_FOCUSED;
+ newByte->color = COLOR_SEL_FOCUSED;
+ }
+ }
+
+ if (address == m_HotAddress && m_bShowHotAddress && !m_bMouseDragging)
+ {
+ newByte->bkColor = BlendColor(BKCOLOR_HOT, newByte->bkColor);
+ }
+
+ // redraw cell if value or colors have changed
+ if (*newByte != *oldByte)
+ {
+ CRect rcHex, rcAscii;
+ GetHexCellPos(startCellIndex + i, &rcHex);
+ GetAsciiCellPos(startCellIndex + i, &rcAscii);
+
+ // check if a similar HXBYTEINFO has already been drawn
+ std::unordered_map::const_iterator drawnByte = drawnByteRects.find(*newByte);
+
+ if (drawnByte != drawnByteRects.end())
+ {
+ HXRECTPAIR src = drawnByte->second;
+ BitBlt(m_BackDC, rcHex.left, rcHex.top, src.rcHex.Width(), src.rcHex.Height(),
+ m_BackDC, src.rcHex.left, src.rcHex.top, SRCCOPY);
+ BitBlt(m_BackDC, rcAscii.left, rcAscii.top, src.rcAscii.Width(), src.rcAscii.Height(),
+ m_BackDC, src.rcAscii.left, src.rcAscii.top, SRCCOPY);
+ InvalidateRect(&rcHex, false);
+ InvalidateRect(&rcAscii, false);
+ }
+ else if (newByte->bHidden)
+ {
+ HXRECTPAIR rectPair;
+ Text(rcHex.left, rcHex.top, " ", BKCOLOR_DEFAULT, BKCOLOR_DEFAULT, &rectPair.rcHex);
+ Text(rcAscii.left, rcAscii.top, " ", BKCOLOR_DEFAULT, BKCOLOR_DEFAULT, &rectPair.rcAscii);
+ drawnByteRects[*newByte] = rectPair;
+ }
+ else
+ {
+ COLORREF hexBkColor = newByte->bkColor;
+ COLORREF hexColor = newByte->color;
+ COLORREF asciiBkColor = newByte->bkColor;
+ COLORREF asciiColor = newByte->color;
+
+ if (IsSelected(address))
+ {
+ if (m_FocusedColumn == HX_COL_ASCII)
+ {
+ hexBkColor = BKCOLOR_SEL_UNFOCUSED;
+ hexColor = COLOR_SEL_UNFOCUSED;
+ }
+ else
+ {
+ asciiBkColor = BKCOLOR_SEL_UNFOCUSED;
+ asciiColor = COLOR_SEL_UNFOCUSED;
+ }
+ }
+
+ HXRECTPAIR rectPair;
+
+ if (newByte->bValid)
+ {
+ char szHexByte[4], szAsciiByte[2];
+ sprintf(szHexByte, "%02X", newByte->value);
+ sprintf(szAsciiByte, "%c", ByteAscii(newByte->value));
+ Text(rcHex.left, rcHex.top, szHexByte, hexBkColor, hexColor, &rectPair.rcHex);
+ Text(rcAscii.left, rcAscii.top, szAsciiByte, asciiBkColor, asciiColor, &rectPair.rcAscii);
+ }
+ else
+ {
+ Text(rcHex.left, rcHex.top, "**", hexBkColor, hexColor, &rectPair.rcHex);
+ Text(rcAscii.left, rcAscii.top, ".", asciiBkColor, asciiColor, &rectPair.rcAscii);
+ }
+
+ drawnByteRects[*newByte] = rectPair;
+ }
+ }
+
+ *oldByte = *newByte;
+ }
+
+ UpdateCaretUI(false);
+}
+
+void CHexEditCtrl::HitTest(int x, int y, HXHITTEST* pht)
+{
+ memset(pht, 0, sizeof(HXHITTEST));
+ pht->column = HX_COL_NONE;
+
+ CPoint pt(x, y);
+
+ if (PtInRect(&m_AddressColumnRect, pt))
+ {
+ pht->column = HX_COL_ADDRESS;
+ }
+
+ int headerHeight = m_CharHeight;
+
+ // clamp row
+ int row = (y - headerHeight) / m_CharHeight;
+ row = max(0, row);
+ row = min(m_NumVisibleRows - 1, row);
+
+ uint32_t rowAddress = SatAdd32(m_BaseAddress, row * m_NumBytesPerRow);
+
+ if (x >= m_HexDataColumnRect.left && x < m_HexDataColumnRect.right)
+ {
+ if (PtInRect(&m_HexDataColumnRect, pt))
+ {
+ pht->column = HX_COL_HEXDATA;
+ }
+
+ int groupWidth = (m_NumBytesPerGroup * m_CharWidth * 2) + (m_CharWidth * 1);
+ int nGroup = (x - m_HexDataColumnRect.left) / groupWidth;
+ int groupX = m_HexDataColumnRect.left + nGroup * groupWidth;
+ int groupCharIdx = (x - groupX) / (m_CharWidth);
+ uint32_t address = SatAdd32(rowAddress, nGroup * m_NumBytesPerGroup + groupCharIdx / 2);
+ pht->hexAddress = address;
+ pht->hexCellSide = (groupCharIdx & 1) ? HX_RIGHT : HX_LEFT; // todo fix for wrap
+ pht->asciiAddress = address; // approximate
+ pht->asciiCellSide = HX_LEFT;
+ }
+ else if (x >= m_AsciiColumnRect.left && x < m_AsciiColumnRect.right)
+ {
+ if (PtInRect(&m_AsciiColumnRect, pt))
+ {
+ pht->column = HX_COL_ASCII;
+ }
+
+ int asciiX = x - m_AsciiColumnRect.left;
+ int idx = (asciiX / m_CharWidth);
+ pht->asciiAddress = SatAdd32(rowAddress, idx);
+ pht->asciiCellSide = ((asciiX % m_CharWidth) > (m_CharWidth / 2)) ? HX_RIGHT : HX_LEFT;
+ pht->hexAddress = SatAdd32(rowAddress, (m_NumBytesPerRow - 1)); // approximate
+ pht->hexCellSide = HX_RIGHT;
+ }
+ else if (x < m_HexDataColumnRect.left)
+ {
+ // approximate
+ pht->hexAddress = rowAddress;
+ pht->hexCellSide = HX_LEFT;
+ pht->asciiAddress = rowAddress;
+ pht->asciiCellSide = HX_LEFT;
+ }
+ else if (x >= m_AsciiColumnRect.right)
+ {
+ // approximate
+ pht->hexAddress = SatAdd32(rowAddress, (m_NumBytesPerRow - 1));
+ pht->hexCellSide = HX_RIGHT;
+ pht->asciiAddress = SatAdd32(rowAddress, (m_NumBytesPerRow - 1));
+ pht->asciiCellSide = HX_RIGHT;
+ }
+}
+
+bool CHexEditCtrl::UpdateCaretUI(bool bEnsureVisible, bool bTop)
+{
+ if (bEnsureVisible)
+ {
+ EnsureCaretAddressVisible(bTop);
+ }
+
+ if (!m_bHaveCaret)
+ {
+ return false;
+ }
+
+ if (!IsCaretAddressVisible())
+ {
+ HideCaret();
+ return false;
+ }
+
+ ShowCaret();
+ int index = m_CaretAddress - m_BaseAddress;
+ CRect rcCell;
+
+ int xoffs = 0;
+
+ if (m_FocusedColumn == HX_COL_ASCII)
+ {
+ if ((int)((m_RealSelEndAddress - m_BaseAddress) % m_NumBytesPerRow) == m_NumBytesPerRow - 1)
+ {
+ // left-to-right selection ends on the end of a row
+ index--;
+ xoffs = m_CharWidth;
+ }
+
+ GetAsciiCellPos(index, &rcCell);
+ SetCaretPos(rcCell.left + xoffs, rcCell.top);
+ }
+ else
+ {
+ if (GetSelDirection() > 0)
+ {
+ if ((int)((m_RealSelEndAddress - m_BaseAddress) % m_NumBytesPerRow) == m_NumBytesPerRow - 1)
+ {
+ // left-to-right selection ends on the end of a row
+ index--;
+ xoffs = m_CharWidth * 2;
+ }
+ else if ((int)((m_RealSelEndAddress - m_BaseAddress) % m_NumBytesPerGroup) == m_NumBytesPerGroup - 1)
+ {
+ // left-to-right selection ends on the end of a group
+ xoffs = -m_CharWidth;
+ }
+ }
+
+ GetHexCellPos(index, &rcCell);
+ SetCaretPos(rcCell.left + (m_bCaretLoNibble ? m_CharWidth : 0) + xoffs, rcCell.top);
+ }
+
+ return true;
+}
+
+void CHexEditCtrl::Text(int x, int y, const char *text, COLORREF bg, COLORREF fg, CRect *rcOut)
+{
+ size_t length = strlen(text);
+ int calcWidth = length * m_CharWidth;
+
+ CRect rc(x, y, 0, 0);
+ COLORREF orgBg = ::SetBkColor(m_BackDC, bg);
+ COLORREF orgFg = ::SetTextColor(m_BackDC, fg);
+ ::DrawText(m_BackDC, text, -1, &rc, DT_TOP | DT_NOPREFIX | DT_CALCRECT);
+ rc.right = rc.left + calcWidth; // just in case
+ ::DrawText(m_BackDC, text, -1, &rc, DT_TOP | DT_NOPREFIX);
+ InvalidateRect(&rc, false);
+ ::SetBkColor(m_BackDC, orgBg);
+ ::SetBkColor(m_BackDC, orgFg);
+
+ *rcOut = rc;
+}
+
+void CHexEditCtrl::UpdateRealSelection(void)
+{
+ uint32_t start = m_SelStartAddress;
+ uint32_t end = m_SelEndAddress;
+ bool bHaveSel = true;
+
+ if (start < end)
+ {
+ if (m_SelEndCellSide == HX_LEFT) end--;
+ if (m_SelStartCellSide == HX_RIGHT) start++;
+ }
+ else if (end < start)
+ {
+ if (start - end == 1)
+ {
+ if (m_SelStartCellSide == HX_LEFT && m_SelEndCellSide == HX_RIGHT)
+ {
+ bHaveSel = false;
+ }
+ }
+
+ if (m_SelStartCellSide == HX_LEFT) start--;
+ if (m_SelEndCellSide == HX_RIGHT) end++;
+
+ swap(start, end);
+ }
+ else if(start == end)
+ {
+ if (m_SelStartCellSide == m_SelEndCellSide)
+ {
+ bHaveSel = false;
+ }
+ }
+
+ if (m_RealSelStartAddress != start ||
+ m_RealSelEndAddress != end ||
+ m_bHaveRealSel != bHaveSel)
+ {
+ m_bHaveRealSel = bHaveSel;
+ m_RealSelStartAddress = start;
+ m_RealSelEndAddress = end;
+ Notify(HXN_SELCHANGED);
+ }
+}
+
+bool CHexEditCtrl::IsSelected(uint32_t address)
+{
+ return m_bHaveRealSel && (address >= m_RealSelStartAddress && address <= m_RealSelEndAddress);
+}
+
+void CHexEditCtrl::DrawAddressColumn()
+{
+ int headerHeight = m_CharHeight;
+ for (int nRow = 0; nRow < m_NumVisibleRows; nRow++)
+ {
+ CRect rcAddress;
+ uint32_t rowAddress = m_BaseAddress + (nRow * m_NumBytesPerRow);
+ int y = headerHeight + nRow * m_CharHeight;
+
+ if (rowAddress >= m_BaseAddress)
+ {
+ Text(0, y, stdstr_f(" %08X ", rowAddress).c_str(), BKCOLOR_ADDR, COLOR_ADDR, &rcAddress);
+ }
+ else
+ {
+ // wrapped
+ Text(0, y, " ", BKCOLOR_ADDR, COLOR_ADDR, &rcAddress);
+ }
+ }
+}
+
+void CHexEditCtrl::DrawHeader()
+{
+ CRect rcClient;
+ GetClientRect(&rcClient);
+ CRect rcHeader = { 0, 0, rcClient.Width(), m_CharHeight };
+ HBRUSH br = CreateSolidBrush(BKCOLOR_ADDR);
+ FillRect(m_BackDC, &rcHeader, br);
+ DeleteObject(br);
+
+ int groupWidth = m_NumBytesPerGroup * m_CharWidth * 2 + m_CharWidth;
+
+ for (int nGroup = 0; nGroup < m_NumByteGroupsPerRow; nGroup++)
+ {
+ int groupX = m_HexDataColumnRect.left + nGroup * groupWidth;
+ int offs = nGroup * m_NumBytesPerGroup;
+ CRect dummy;
+ Text(groupX, 0, stdstr_f("%02X", offs).c_str(), BKCOLOR_ADDR, COLOR_ADDR, &dummy);
+ }
+
+ InvalidateRect(&rcHeader, false);
+}
+
+void CHexEditCtrl::GetHexCellPos(int index, CRect* rc)
+{
+ int nRow = index / m_NumBytesPerRow;
+ int rowOffs = (index % m_NumBytesPerRow);
+ int nGroup = rowOffs / m_NumBytesPerGroup;
+ int byteOffs = rowOffs % m_NumBytesPerGroup;
+
+ int addrColumnWidth = (m_CharWidth * 11);
+ int byteWidth = (m_CharWidth * 2);
+ int hexGroupWidth = (byteWidth * m_NumBytesPerGroup) + (m_CharWidth * 1);
+
+ int headerHeight = m_CharHeight;
+
+ rc->left = addrColumnWidth + (nGroup * hexGroupWidth) + (byteOffs * byteWidth);
+ rc->top = headerHeight + nRow * m_CharHeight;
+ rc->right = rc->left + m_CharWidth * 2;
+ rc->bottom = rc->top + m_CharHeight;
+}
+
+void CHexEditCtrl::GetAsciiCellPos(int index, CRect* rc)
+{
+ int nRow = index / m_NumBytesPerRow;
+ int rowOffs = (index % m_NumBytesPerRow);
+
+ int addrColumnWidth = (m_CharWidth * 11);
+ int byteWidth = (m_CharWidth * 2);
+ int hexGroupWidth = (byteWidth * m_NumBytesPerGroup) + (m_CharWidth * 1);
+ int hexColumnWidth = (m_NumByteGroupsPerRow * hexGroupWidth);
+ int asciiColumnX = 0 + addrColumnWidth + hexColumnWidth;
+ int headerHeight = m_CharHeight;
+
+ rc->left = asciiColumnX + (rowOffs * m_CharWidth);
+ rc->top = headerHeight + nRow * m_CharHeight;
+ rc->right = rc->left + m_CharWidth;
+ rc->bottom = rc->top + m_CharHeight;
+}
+
+char CHexEditCtrl::ByteAscii(uint8_t value)
+{
+ if (value <= 0x1F)
+ {
+ return '.';
+ }
+
+ if (value >= 0x20 && value <= 0x7E)
+ {
+ return (char)value;
+ }
+
+ switch (value)
+ {
+ case 0x7F:
+ case 0x81:
+ case 0x8D:
+ case 0x8F:
+ case 0x90:
+ case 0x9D:
+ // undefined in windows-1252
+ return '.';
+ }
+
+ return (char)value;
+}
+
+uint8_t CHexEditCtrl::HexCharValue(char c)
+{
+ if (!isxdigit(c))
+ {
+ return 0;
+ }
+
+ if (c >= '0' && c <= '9') return (c - '0');
+ if (c >= 'A' && c <= 'F') return (c - 'A') + 0x0A;
+ if (c >= 'a' && c <= 'f') return (c - 'a') + 0x0A;
+
+ return 0;
+}
+
+void CHexEditCtrl::CaretIncrementNibble(void)
+{
+ if (!m_bCaretLoNibble)
+ {
+ m_bCaretLoNibble = true;
+ }
+ else
+ {
+ m_bCaretLoNibble = false;
+ m_CaretAddress++;
+ }
+}
+
+void CHexEditCtrl::CaretDecrementNibble(void)
+{
+ if (m_bCaretLoNibble)
+ {
+ m_bCaretLoNibble = false;
+ }
+ else
+ {
+ m_bCaretLoNibble = true;
+ m_CaretAddress--;
+ }
+}
+
+void CHexEditCtrl::OnTimer(UINT_PTR nIDEvent)
+{
+ if (nIDEvent == TIMER_ID_AUTO_REFRESH)
+ {
+ Draw();
+ }
+ else if (nIDEvent == TIMER_ID_DRAG_SCROLL)
+ {
+ if (m_DragScrollDelta != 0)
+ {
+ int numBytesToScroll = m_DragScrollDelta * m_NumBytesPerRow;
+ int64_t newCaretAddress = (int64_t)m_CaretAddress + numBytesToScroll;
+
+ if (newCaretAddress < 0 && m_BaseAddress == 0)
+ {
+ return;
+ }
+
+ else if (newCaretAddress > UINT_MAX)
+ {
+ return;
+ }
+
+ m_CaretAddress = SatAdd32(m_CaretAddress, numBytesToScroll);
+ m_SelEndAddress = SatAdd32(m_SelEndAddress, numBytesToScroll);
+
+ UpdateRealSelection();
+ UpdateCaretUI(true);
+ }
+ }
+}
+
+void CHexEditCtrl::OnPaint(CDCHandle dc)
+{
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(&ps);
+ CRect rc = ps.rcPaint;
+
+ BitBlt(hdc,
+ rc.left, rc.top,
+ rc.Width(), rc.Height(),
+ m_BackDC,
+ rc.left, rc.top,
+ SRCCOPY);
+
+ EndPaint(&ps);
+}
+
+void CHexEditCtrl::OnRButtonDown(UINT /*nFlags*/, CPoint point)
+{
+ SetFocus();
+
+ HXHITTEST ht;
+ HitTest(point.x, point.y, &ht);
+
+ if (ht.column == HX_COL_HEXDATA)
+ {
+ if (!IsSelected(ht.hexAddress))
+ {
+ m_CaretAddress = ht.hexAddress;
+ m_bCaretLoNibble = HX_LEFT;
+ CancelSelection();
+ }
+ }
+ else if (ht.column == HX_COL_ASCII)
+ {
+ if (!IsSelected(ht.asciiAddress))
+ {
+ m_CaretAddress = ht.asciiAddress;
+ CancelSelection();
+ }
+ }
+}
+
+void CHexEditCtrl::OnRButtonUp(UINT /*nFlags*/, CPoint point)
+{
+ HXHITTEST ht;
+ HitTest(point.x, point.y, &ht);
+
+ if (ht.column == HX_COL_HEXDATA)
+ {
+ NotifyRightClick(ht.hexAddress);
+ }
+ else if (ht.column == HX_COL_ASCII)
+ {
+ NotifyRightClick(ht.asciiAddress);
+ }
+}
+
+void CHexEditCtrl::OnLButtonDown(UINT nFlags, CPoint point)
+{
+ m_bLButtonDown = true;
+
+ SetFocus();
+
+ HXHITTEST ht;
+ HitTest(point.x, point.y, &ht);
+
+ m_FocusedColumn = ht.column;
+
+ if (m_FocusedColumn == HX_COL_HEXDATA)
+ {
+ m_CaretAddress = ht.hexAddress;
+ m_bCaretLoNibble = (ht.hexCellSide == HX_RIGHT);
+
+ if (nFlags & MK_SHIFT)
+ {
+ m_SelEndAddress = ht.hexAddress;
+ m_SelEndCellSide = ht.hexCellSide;
+ UpdateRealSelection();
+
+ if (GetSelDirection() > 0)
+ {
+ m_CaretAddress = m_RealSelEndAddress + 1;
+ }
+ else
+ {
+ m_CaretAddress = m_RealSelStartAddress;
+ }
+ m_bCaretLoNibble = false;
+ }
+ else
+ {
+ m_SelStartAddress = ht.hexAddress;
+ m_SelEndAddress = ht.hexAddress;
+ m_SelStartCellSide = ht.hexCellSide;
+ m_SelEndCellSide = ht.hexCellSide;
+ UpdateRealSelection();
+ }
+ }
+ else if (m_FocusedColumn == HX_COL_ASCII)
+ {
+ m_CaretAddress = ht.asciiAddress;
+
+ if (nFlags & MK_SHIFT)
+ {
+ m_SelEndAddress = ht.asciiAddress;
+ }
+ else
+ {
+ m_CaretAddress = ht.asciiAddress;
+ m_SelStartCellSide = ht.asciiCellSide;
+ m_SelEndCellSide = ht.asciiCellSide;
+ m_SelStartAddress = ht.asciiAddress;
+ m_SelEndAddress = ht.asciiAddress;
+ if (ht.asciiCellSide)
+ {
+ m_CaretAddress++;
+ }
+ }
+
+ UpdateRealSelection();
+ }
+
+ UpdateCaretUI(false);
+ Draw();
+
+ SetCapture();
+}
+
+void CHexEditCtrl::OnLButtonDblClk(UINT /*nFlags*/, CPoint point)
+{
+ m_bDblClicked = true;
+
+ HXHITTEST ht;
+ HitTest(point.x, point.y, &ht);
+
+ if (m_FocusedColumn == HX_COL_HEXDATA)
+ {
+ // select word
+ uint32_t offset = (ht.hexAddress - m_BaseAddress);
+ uint32_t wordOffset = offset - (offset % m_NumBytesPerGroup);
+ uint32_t wordAddress = m_BaseAddress + wordOffset;
+ m_SelStartAddress = wordAddress;
+ m_SelEndAddress = wordAddress + (m_NumBytesPerGroup - 1);
+ m_SelStartCellSide = HX_LEFT;
+ m_SelEndCellSide = HX_RIGHT;
+ m_CaretAddress = m_SelEndAddress + 1;
+ m_bCaretLoNibble = false;
+ UpdateRealSelection();
+ UpdateCaretUI(false);
+ }
+ if (m_FocusedColumn == HX_COL_ASCII)
+ {
+ // select row
+ uint32_t offset = (ht.asciiAddress - m_BaseAddress);
+ uint32_t rowOffset = (ht.asciiAddress - m_BaseAddress) - (offset % m_NumBytesPerRow);
+ uint32_t rowAddress = m_BaseAddress + rowOffset;
+ m_SelStartAddress = rowAddress;
+ m_SelEndAddress = rowAddress + (m_NumBytesPerRow - 1);
+ m_SelStartCellSide = HX_LEFT;
+ m_SelEndCellSide = HX_RIGHT;
+ m_CaretAddress = m_SelEndAddress + 1;
+ UpdateRealSelection();
+ UpdateCaretUI(false);
+ }
+}
+
+void CHexEditCtrl::OnLButtonUp(UINT /*nFlags*/, CPoint point)
+{
+ m_bLButtonDown = false;
+ m_bMouseDragging = false;
+
+ if (m_DragScrollDelta != 0)
+ {
+ m_bDblClicked = false;
+ m_DragScrollDelta = 0;
+ ReleaseCapture();
+ return;
+ }
+
+ HXHITTEST ht;
+ HitTest(point.x, point.y, &ht);
+
+ if (m_bDblClicked)
+ {
+ m_bDblClicked = false;
+ return;
+ }
+
+ ReleaseCapture();
+}
+
+void CHexEditCtrl::OnMouseMove(UINT /*nFlags*/, CPoint point)
+{
+ if (m_bLButtonDown)
+ {
+ m_bMouseDragging = true;
+ }
+
+ HXHITTEST ht;
+ HitTest(point.x, point.y, &ht);
+
+ if (ht.column == HX_COL_NONE || ht.column == HX_COL_ADDRESS)
+ {
+ m_bShowHotAddress = false;
+ }
+ else
+ {
+ m_bShowHotAddress = true;
+
+ if (ht.column == HX_COL_HEXDATA)
+ {
+ if (m_HotAddress != ht.hexAddress)
+ {
+ m_HotAddress = ht.hexAddress;
+ Notify(HXN_HOTADDRCHANGED);
+ }
+ }
+ else if (ht.column == HX_COL_ASCII)
+ {
+ if (m_HotAddress != ht.asciiAddress)
+ {
+ m_HotAddress = ht.asciiAddress;
+ Notify(HXN_HOTADDRCHANGED);
+ }
+ }
+ }
+
+ if (!m_bLButtonDown)
+ {
+ return;
+ }
+
+ m_DragScrollDelta = 0;
+
+ if (point.y > m_HexDataColumnRect.bottom)
+ {
+ m_DragScrollDelta = 1 + (point.y - m_HexDataColumnRect.bottom) / m_CharHeight;
+ }
+ else if (point.y < m_HexDataColumnRect.top)
+ {
+ m_DragScrollDelta = -1 + (point.y - m_HexDataColumnRect.top) / m_CharHeight;
+ }
+
+ if (m_FocusedColumn == HX_COL_HEXDATA)
+ {
+ m_CaretAddress = ht.hexAddress;
+ m_SelEndAddress = ht.hexAddress;
+ m_SelEndCellSide = ht.hexCellSide;
+ m_bCaretLoNibble = (ht.hexCellSide == HX_RIGHT);
+
+ if (m_SelEndAddress - m_SelStartAddress == 1 &&
+ m_SelStartCellSide == HX_RIGHT &&
+ m_SelEndCellSide == HX_LEFT)
+ {
+ m_SelStartCellSide = HX_LEFT;
+ }
+
+ if (GetSelDirection() != 0 && m_SelEndCellSide == HX_RIGHT)
+ {
+ m_bCaretLoNibble = false;
+ m_CaretAddress++;
+ }
+ }
+ else if (m_FocusedColumn == HX_COL_ASCII)
+ {
+ m_CaretAddress = ht.asciiAddress;
+ m_SelEndAddress = ht.asciiAddress;
+ m_SelEndCellSide = ht.asciiCellSide;
+
+ if (GetSelDirection() != 0 && m_SelEndCellSide == HX_RIGHT)
+ {
+ m_CaretAddress++;
+ }
+ }
+
+ UpdateRealSelection();
+}
+
+BOOL CHexEditCtrl::OnMouseWheel(UINT /*nFlags*/, short zDelta, CPoint /*pt*/)
+{
+ m_BaseAddress = SatAdd32(m_BaseAddress, -(zDelta / 120) * m_NumBytesPerRow);
+ Notify(HXN_BASEADDRCHANGED);
+ return FALSE;
+}
+
+void CHexEditCtrl::OnSetFocus(CWindow /*wndOld*/)
+{
+ ::CreateCaret(m_hWnd, NULL, 2, m_CharHeight);
+ m_bHaveCaret = true;
+ UpdateCaretUI(false);
+}
+
+void CHexEditCtrl::OnKillFocus(CWindow /*wndFocus*/)
+{
+ m_bCaretVisible = false;
+ m_bHaveCaret = false;
+ ::DestroyCaret();
+}
+
+UINT CHexEditCtrl::OnGetDlgCode(LPMSG /*lpMsg*/)
+{
+ return DLGC_WANTALLKEYS;
+}
+
+void CHexEditCtrl::OnChar(UINT nChar, UINT /*nRepCnt*/, UINT /*nFlags*/)
+{
+ if (::GetKeyState(VK_CONTROL) & 0x8000)
+ {
+ return;
+ }
+
+ if (nChar == VK_BACK || nChar == VK_TAB || nChar == VK_RETURN)
+ {
+ return;
+ }
+
+ if (m_FocusedColumn == HX_COL_HEXDATA)
+ {
+ if (isxdigit(nChar))
+ {
+ int selDirection = GetSelDirection();
+
+ if (selDirection < 0)
+ {
+ m_CaretAddress = m_SelEndAddress;
+ m_bCaretLoNibble = false;
+ }
+ else if (selDirection > 0)
+ {
+ m_CaretAddress = m_SelStartAddress;
+ m_bCaretLoNibble = false;
+ }
+
+ NotifySetNibble(m_CaretAddress, m_bCaretLoNibble, HexCharValue((char)nChar));
+
+ CancelSelection();
+ CaretIncrementNibble();
+ UpdateCaretUI(true);
+ }
+ }
+ else if (m_FocusedColumn == HX_COL_ASCII)
+ {
+ int selDirection = GetSelDirection();
+ if (selDirection < 0)
+ {
+ m_CaretAddress = m_SelEndAddress;
+ }
+ else if(selDirection > 0)
+ {
+ m_CaretAddress = m_SelStartAddress;
+ }
+
+ NotifySetByte(m_CaretAddress, (uint8_t)nChar);
+
+ CancelSelection();
+ m_CaretAddress++;
+ UpdateCaretUI(true);
+ }
+}
+
+void CHexEditCtrl::Paste(bool bAdvanceCaret)
+{
+ uint32_t targetAddress = m_bHaveRealSel ? m_RealSelStartAddress : m_CaretAddress;
+ int retLength = NotifyPaste(targetAddress);
+
+ if (retLength != 0)
+ {
+ if (bAdvanceCaret)
+ {
+ m_CaretAddress = targetAddress + retLength;
+ UpdateCaretUI(true);
+ }
+ CancelSelection();
+ }
+}
+
+void CHexEditCtrl::Copy(void)
+{
+ if (m_bHaveRealSel)
+ {
+ Notify(HXN_COPY);
+ }
+}
+
+void CHexEditCtrl::SetBaseAddress(uint32_t address)
+{
+ if (m_BaseAddress != address)
+ {
+ m_BaseAddress = address;
+ Draw();
+ }
+}
+
+uint32_t CHexEditCtrl::GetCaretAddress(void)
+{
+ return m_CaretAddress;
+}
+
+uint32_t CHexEditCtrl::GetHotAddress(void)
+{
+ return m_HotAddress;
+}
+
+uint32_t CHexEditCtrl::GetBaseAddress(void)
+{
+ return m_BaseAddress;
+}
+
+int CHexEditCtrl::GetNumBytesPerRow(void)
+{
+ return m_NumBytesPerRow;
+}
+
+int CHexEditCtrl::GetNumVisibleBytes(void)
+{
+ return m_NumVisibleBytes;
+}
+
+int CHexEditCtrl::GetNumBytesPerGroup(void)
+{
+ return m_NumBytesPerGroup;
+}
+
+bool CHexEditCtrl::GetSelectionRange(uint32_t* startAddress, uint32_t* endAddress)
+{
+ *startAddress = m_RealSelStartAddress;
+ *endAddress = m_RealSelEndAddress;
+ return m_bHaveRealSel;
+}
+
+bool CHexEditCtrl::GetInsertMode(void)
+{
+ return m_bInsertMode;
+}
+
+HXCOLUMN CHexEditCtrl::GetFocusedColumn(void)
+{
+ return m_FocusedColumn;
+}
+
+void CHexEditCtrl::OnKeyDown(UINT nChar, UINT /*nRepCnt*/, UINT /*nFlags*/)
+{
+ if (nChar != VK_CONTROL && (GetKeyState(VK_CONTROL) & 0x8000))
+ {
+ NotifyCtrlKeyPressed(nChar);
+
+ if (nChar == 'V')
+ {
+ Paste();
+ }
+ else if (nChar == 'B')
+ {
+ Paste(false);
+ }
+ else if (nChar == 'C')
+ {
+ Copy();
+ }
+ else if (nChar == 'X')
+ {
+ Copy();
+ if (m_bHaveRealSel)
+ {
+ NotifyFillRange(m_RealSelStartAddress, m_RealSelEndAddress, 0);
+ m_CaretAddress = m_RealSelStartAddress;
+ m_bCaretLoNibble = false;
+ CancelSelection();
+ }
+ }
+ else if (nChar == 'A')
+ {
+ SelectAllVisible();
+ }
+ }
+
+
+ if (nChar == VK_DOWN)
+ {
+ m_CaretAddress = SatAdd32(m_CaretAddress, m_NumBytesPerRow);
+
+ if (GetKeyState(VK_SHIFT) & 0x8000)
+ {
+ m_SelEndAddress += m_NumBytesPerRow;
+ if (m_bCaretLoNibble)
+ {
+ m_SelStartCellSide = HX_LEFT;
+ m_SelEndCellSide = HX_LEFT;
+ m_bCaretLoNibble = false;
+ }
+ UpdateRealSelection();
+ }
+ else
+ {
+ CancelSelection();
+ }
+
+ UpdateCaretUI(true);
+ }
+ else if (nChar == VK_UP)
+ {
+ m_CaretAddress -= m_NumBytesPerRow;
+
+ if (GetKeyState(VK_SHIFT) & 0x8000)
+ {
+ m_SelEndAddress -= m_NumBytesPerRow;
+ if (m_bCaretLoNibble)
+ {
+ m_SelStartCellSide = HX_LEFT;
+ m_SelEndCellSide = HX_LEFT;
+ m_bCaretLoNibble = false;
+ }
+ UpdateRealSelection();
+ }
+ else
+ {
+ CancelSelection();
+ }
+
+ UpdateCaretUI(true);
+ }
+ else if (nChar == VK_RIGHT)
+ {
+ if (m_FocusedColumn == HX_COL_HEXDATA)
+ {
+ if (GetKeyState(VK_SHIFT) & 0x8000)
+ {
+ if (m_SelStartAddress == m_SelEndAddress &&
+ m_SelStartCellSide == HX_RIGHT &&
+ m_SelEndCellSide == HX_RIGHT)
+ {
+ m_SelStartCellSide = HX_LEFT;
+ m_SelEndCellSide = HX_RIGHT;
+ }
+ else
+ {
+ m_SelEndAddress++;
+ }
+
+ m_bCaretLoNibble = false;
+ m_CaretAddress++;
+ UpdateRealSelection();
+ }
+ else if (GetKeyState(VK_CONTROL) & 0x8000)
+ {
+ CaretIncrementNibble();
+ CancelSelection();
+ }
+ else
+ {
+ m_bCaretLoNibble = false;
+ m_CaretAddress++;
+ m_SelStartAddress = m_CaretAddress;
+ m_SelEndAddress = m_CaretAddress;
+ m_SelStartCellSide = HX_LEFT;
+ m_SelEndCellSide = HX_LEFT;
+ CancelSelection();
+ }
+ }
+ else if (m_FocusedColumn == HX_COL_ASCII)
+ {
+ m_CaretAddress++;
+
+ if (GetKeyState(VK_SHIFT))
+ {
+ m_SelEndCellSide = HX_LEFT;
+ m_SelEndAddress = m_CaretAddress;
+ UpdateRealSelection();
+ }
+ else
+ {
+ CancelSelection();
+ }
+ }
+
+ UpdateCaretUI(true);
+ }
+ else if (nChar == VK_LEFT)
+ {
+ if (m_FocusedColumn == HX_COL_HEXDATA)
+ {
+ if(GetKeyState(VK_SHIFT) & 0x8000)
+ {
+ m_SelEndCellSide = HX_LEFT;
+ m_SelEndAddress--;
+ if (m_bCaretLoNibble)
+ {
+ m_SelStartCellSide = HX_LEFT;
+ }
+ m_CaretAddress--;
+ m_bCaretLoNibble = false;
+ UpdateRealSelection();
+ }
+ else if (GetKeyState(VK_CONTROL) & 0x8000)
+ {
+ CaretDecrementNibble();
+ CancelSelection();
+ }
+ else
+ {
+ if (m_bCaretLoNibble)
+ {
+ CaretDecrementNibble();
+ }
+ else
+ {
+ m_CaretAddress--;
+ }
+
+ CancelSelection();
+ }
+ }
+ else if (m_FocusedColumn == HX_COL_ASCII)
+ {
+ m_CaretAddress--;
+
+ if (GetKeyState(VK_SHIFT))
+ {
+ m_SelEndCellSide = HX_LEFT;
+ m_SelEndAddress = m_CaretAddress;
+ UpdateRealSelection();
+ }
+ else
+ {
+ CancelSelection();
+ }
+ }
+
+ UpdateCaretUI(true);
+ }
+ else if (nChar == VK_NEXT || nChar == VK_PRIOR) // page down, page up
+ {
+ int delta = (nChar == VK_NEXT) ? m_NumVisibleBytes : -m_NumVisibleBytes;
+
+ if (IsCaretAddressVisible())
+ {
+ m_BaseAddress += delta;
+ m_CaretAddress += delta;
+ Notify(HXN_BASEADDRCHANGED);
+ }
+ else
+ {
+ m_CaretAddress += delta;
+ UpdateCaretUI(true, true);
+ }
+
+ CancelSelection();
+ }
+ else if (nChar == VK_INSERT)
+ {
+ m_bInsertMode = !m_bInsertMode;
+ Notify(HXN_INSERTMODECHANGED);
+ }
+ else if (nChar == VK_RETURN)
+ {
+ Notify(HXN_ENTERPRESSED);
+ }
+ else if (nChar == VK_HOME)
+ {
+ UpdateCaretUI(true);
+ }
+ else if (nChar == VK_BACK)
+ {
+ if (m_bHaveRealSel)
+ {
+ NotifyFillRange(m_RealSelStartAddress, m_RealSelEndAddress, 0);
+ CancelSelection();
+ m_CaretAddress = m_RealSelStartAddress;
+ UpdateCaretUI(true);
+ }
+ else
+ {
+ if (m_FocusedColumn == HX_COL_HEXDATA)
+ {
+ uint32_t address = m_CaretAddress + (m_bCaretLoNibble ? 0 : -1);
+ NotifySetNibble(address, !m_bCaretLoNibble, 0);
+ CaretDecrementNibble();
+ UpdateCaretUI(true);
+ }
+ else if (m_FocusedColumn == HX_COL_ASCII)
+ {
+ NotifySetByte(m_CaretAddress - 1, 0);
+ m_CaretAddress--;
+ UpdateCaretUI(true);
+ }
+ }
+ }
+ else if (nChar == VK_DELETE)
+ {
+ if (m_FocusedColumn == HX_COL_HEXDATA || m_FocusedColumn == HX_COL_ASCII)
+ {
+ if (!m_bHaveRealSel)
+ {
+ NotifySetByte(m_CaretAddress, 0);
+ }
+ else
+ {
+ NotifyFillRange(m_RealSelStartAddress, m_RealSelEndAddress, 0);
+ }
+ }
+ }
+}
+
+int CHexEditCtrl::GetSelDirection(void)
+{
+ if (m_SelStartAddress < m_SelEndAddress) return 1; // right
+ if (m_SelStartAddress > m_SelEndAddress) return -1; // left
+ if (m_SelStartCellSide == m_SelEndCellSide) return 0; // no selection
+ if (m_SelStartCellSide == HX_LEFT && m_SelEndCellSide == HX_RIGHT) return 1; // right (single byte)
+ if (m_SelStartCellSide == HX_RIGHT && m_SelEndCellSide == HX_LEFT) return -1; // left (single byte)
+ return 0;
+}
+
+void CHexEditCtrl::CancelSelection(void)
+{
+ m_SelStartAddress = m_CaretAddress;
+ m_SelEndAddress = m_CaretAddress;
+ m_SelStartCellSide = m_bCaretLoNibble ? HX_RIGHT : HX_LEFT;
+ m_SelEndCellSide = m_bCaretLoNibble ? HX_RIGHT : HX_LEFT;
+ UpdateRealSelection();
+}
+
+void CHexEditCtrl::SelectAllVisible(void)
+{
+ uint32_t lastVisibleByteAddress = (m_BaseAddress + m_NumVisibleBytes) - 1;
+ m_SelStartAddress = m_BaseAddress;
+ m_SelStartCellSide = HX_LEFT;
+ m_SelEndAddress = lastVisibleByteAddress;
+ m_SelEndCellSide = HX_RIGHT;
+ m_CaretAddress = lastVisibleByteAddress + 1;
+ m_bCaretLoNibble = false;
+ UpdateRealSelection();
+}
+
+bool CHexEditCtrl::IsCaretAddressVisible(void)
+{
+ return m_CaretAddress >= m_BaseAddress && m_CaretAddress <= SatAdd32(m_BaseAddress, m_NumVisibleBytes);
+}
+
+uint32_t CHexEditCtrl::LineAddress(uint32_t address)
+{
+ return address - ((address - (m_BaseAddress % m_NumBytesPerRow)) % m_NumBytesPerRow);
+}
+
+void CHexEditCtrl::EnsureCaretAddressVisible(bool bTop)
+{
+ uint32_t oldBaseAddress = m_BaseAddress;
+ uint32_t caretLineAddress = LineAddress(m_CaretAddress);
+ uint32_t lastVisibleLineAddress = m_BaseAddress + (m_NumVisibleBytes - m_NumBytesPerRow);
+
+ if (bTop || caretLineAddress < m_BaseAddress)
+ {
+ m_BaseAddress = caretLineAddress;
+ }
+ else if (caretLineAddress >= lastVisibleLineAddress + m_NumBytesPerRow)
+ {
+ m_BaseAddress = SatAdd32(m_BaseAddress, caretLineAddress - lastVisibleLineAddress);
+ }
+
+ if (oldBaseAddress != m_BaseAddress)
+ {
+ Notify(HXN_BASEADDRCHANGED);
+ }
+}
+
+LRESULT CHexEditCtrl::Notify(UINT code)
+{
+ UINT_PTR nID = ::GetDlgCtrlID(m_hWnd);
+ NMHDR nmh = { m_hWnd, nID, code };
+ return ::SendMessage(GetParent(), WM_NOTIFY, (WPARAM)nID, (LPARAM)&nmh);
+}
+
+LRESULT CHexEditCtrl::NotifySetByte(uint32_t address, uint8_t value)
+{
+ UINT_PTR nID = ::GetDlgCtrlID(m_hWnd);
+ NMHXSETBYTE nmsb = { { m_hWnd, nID, HXN_SETBYTE }, m_bInsertMode, address, value };
+ return ::SendMessage(GetParent(), WM_NOTIFY, (WPARAM)nID, (LPARAM)&nmsb);
+}
+
+LRESULT CHexEditCtrl::NotifySetNibble(uint32_t address, bool bLoNibble, uint8_t value)
+{
+ UINT_PTR nID = ::GetDlgCtrlID(m_hWnd);
+ NMHXSETNIBBLE nmsn = { { m_hWnd, nID, HXN_SETNIBBLE }, m_bInsertMode, address, bLoNibble, value };
+ return ::SendMessage(GetParent(), WM_NOTIFY, (WPARAM)nID, (LPARAM)&nmsn);
+}
+
+LRESULT CHexEditCtrl::NotifyFillRange(uint32_t startAddress, uint32_t endAddress, uint8_t value)
+{
+ UINT_PTR nID = ::GetDlgCtrlID(m_hWnd);
+ NMHXFILLRANGE nmfr = { { m_hWnd, nID, HXN_FILLRANGE }, m_bInsertMode, startAddress, endAddress, value };
+ return ::SendMessage(GetParent(), WM_NOTIFY, (WPARAM)nID, (LPARAM)&nmfr);
+}
+
+LRESULT CHexEditCtrl::NotifyCtrlKeyPressed(int nChar)
+{
+ UINT_PTR nID = ::GetDlgCtrlID(m_hWnd);
+ NMHXCTRLKEYPRESSED nmck = { { m_hWnd, nID, HXN_CTRLKEYPRESSED }, nChar };
+ return ::SendMessage(GetParent(), WM_NOTIFY, (WPARAM)nID, (LPARAM)&nmck);
+}
+
+LRESULT CHexEditCtrl::NotifyPaste(uint32_t address)
+{
+ UINT_PTR nID = ::GetDlgCtrlID(m_hWnd);
+ NMHXPASTE nmp = { { m_hWnd, nID, HXN_PASTE }, address, m_FocusedColumn };
+ return ::SendMessage(GetParent(), WM_NOTIFY, (WPARAM)nID, (LPARAM)&nmp);
+}
+
+LRESULT CHexEditCtrl::NotifyRightClick(uint32_t address)
+{
+ UINT_PTR nID = ::GetDlgCtrlID(m_hWnd);
+ NMHXRCLICK nmrc = { { m_hWnd, nID, HXN_RCLICK }, address };
+ return ::SendMessage(GetParent(), WM_NOTIFY, (WPARAM)nID, (LPARAM)&nmrc);
+}
+
+LRESULT CHexEditCtrl::NotifyGetByteInfo(uint32_t address, size_t numBytes, bool bIgnoreDiff, HXBYTEINFO* oldBytes, HXBYTEINFO* newBytes)
+{
+ UINT_PTR nID = ::GetDlgCtrlID(m_hWnd);
+ NMHXGETBYTEINFO nmgbi = { { m_hWnd, nID, HXN_GETBYTEINFO }, address, numBytes, bIgnoreDiff, oldBytes, newBytes };
+ return ::SendMessage(GetParent(), WM_NOTIFY, nmgbi.nmh.idFrom, (LPARAM)&nmgbi);
+}
+
+BOOL CHexEditCtrl::OnSetCursor(CWindow /*wnd*/, UINT /*nHitTest*/, UINT /*message*/)
+{
+ CPoint point(::GetMessagePos());
+ ScreenToClient(&point);
+
+ HXHITTEST ht;
+ HitTest(point.x, point.y, &ht);
+
+ if (ht.column == HX_COL_HEXDATA || ht.column == HX_COL_ASCII)
+ {
+ SetCursor(m_hCursorIBeam);
+ }
+ else
+ {
+ SetCursor(m_hCursorDefault);
+ }
+ return FALSE;
+}
+
+void CHexEditCtrl::ShowCaret(void)
+{
+ if (!m_bCaretVisible)
+ {
+ ::ShowCaret(m_hWnd);
+ m_bCaretVisible = true;
+ }
+}
+
+void CHexEditCtrl::HideCaret(void)
+{
+ if (m_bCaretVisible)
+ {
+ ::HideCaret(m_hWnd);
+ m_bCaretVisible = false;
+ }
+}
+
+uint32_t CHexEditCtrl::SatAdd32(uint32_t a, int b)
+{
+ int64_t c = (int64_t)a + b;
+ if (c > UINT_MAX)
+ {
+ return UINT_MAX;
+ }
+ if (c < 0)
+ {
+ return 0;
+ }
+ return (uint32_t)c;
+}
+
+uint32_t CHexEditCtrl::SatAdd32(uint32_t a, uint32_t b)
+{
+ uint32_t c = a + b;
+ if (c < a)
+ {
+ return (uint32_t)-1;
+ }
+ return c;
+}
+
+COLORREF CHexEditCtrl::BlendColor(COLORREF c1, COLORREF c2)
+{
+ int r1 = GetRValue(c1);
+ int g1 = GetGValue(c1);
+ int b1 = GetBValue(c1);
+ int r2 = GetRValue(c2);
+ int g2 = GetGValue(c2);
+ int b2 = GetBValue(c2);
+ return RGB((r1+r2*2)/3, (g1+g2*2)/3, (b1+b2*2)/3);
+}
+
+void CHexEditCtrl::UpdateLayoutInfo(void)
+{
+ CRect clientRect;
+ GetClientRect(&clientRect);
+
+ int addressColumnWidth = 11 * m_CharWidth;
+ int byteWidth = m_CharWidth * 2;
+ int byteGroupWidth = (m_NumBytesPerGroup * byteWidth) + (m_CharWidth * 1);
+ int asciiGroupWidth = (m_NumBytesPerGroup * m_CharWidth);
+ int headerHeight = m_CharHeight;
+
+ m_NumByteGroupsPerRow = (clientRect.Width() - addressColumnWidth) / (byteGroupWidth + asciiGroupWidth);
+ m_NumBytesPerRow = m_NumByteGroupsPerRow * m_NumBytesPerGroup;
+ m_NumVisibleRows = (clientRect.Height() - headerHeight) / m_CharHeight;
+ m_NumVisibleBytes = m_NumVisibleRows * m_NumBytesPerRow;
+
+ int hexDataColumnWidth = m_NumByteGroupsPerRow * byteGroupWidth;
+ int asciiColumnWidth = m_NumBytesPerRow * m_CharWidth;
+
+ int addressColumnLeft = 0;
+ int addressColumnRight = addressColumnLeft + addressColumnWidth;
+ int hexDataColumnLeft = addressColumnRight;
+ int hexDataColumnRight = hexDataColumnLeft + hexDataColumnWidth;
+ int asciiColumnLeft = hexDataColumnRight;
+ int asciiColumnRight = asciiColumnLeft + asciiColumnWidth;
+
+ int columnsTop = 0 + headerHeight;
+ int columnsBottom = columnsTop + m_NumVisibleRows * m_CharHeight;
+
+ m_AddressColumnRect = { addressColumnLeft, columnsTop, addressColumnRight, columnsBottom };
+ m_HexDataColumnRect = { hexDataColumnLeft, columnsTop, hexDataColumnRight, columnsBottom };
+ m_AsciiColumnRect = { asciiColumnLeft, columnsTop, asciiColumnRight, columnsBottom };
+
+ m_bLayoutChanged = true;
+}
+
+void CHexEditCtrl::ReallocByteBuffers(void)
+{
+ m_NewBytes = (HXBYTEINFO*)realloc(m_NewBytes, m_NumVisibleBytes * sizeof(HXBYTEINFO));
+ m_OldBytes = (HXBYTEINFO*)realloc(m_OldBytes, m_NumVisibleBytes * sizeof(HXBYTEINFO));
+
+ for (int i = 0; i < m_NumVisibleBytes; i++)
+ {
+ m_NewBytes[i] = { 0 };
+ m_OldBytes[i] = { 0 };
+ }
+}
+
+void CHexEditCtrl::OnWindowPosChanged(LPWINDOWPOS /*lpWndPos*/)
+{
+ int oldNumRows = m_NumVisibleRows;
+ int oldNumGroups = m_NumByteGroupsPerRow;
+
+ UpdateLayoutInfo();
+
+ if (oldNumRows != m_NumVisibleRows || oldNumGroups != m_NumByteGroupsPerRow)
+ {
+ ReallocByteBuffers();
+
+ CRect rc;
+ GetClientRect(&rc);
+ m_BackBMP = CreateCompatibleBitmap(m_BackDC, rc.Width(), rc.Height());
+ HBITMAP hOldBMP = (HBITMAP)SelectObject(m_BackDC, m_BackBMP);
+ DeleteObject(hOldBMP);
+
+ CRect clrRc(0, 0, rc.Width(), rc.Height());
+ HBRUSH hbrush = CreateSolidBrush(BKCOLOR_DEFAULT);
+ FillRect(m_BackDC, clrRc, hbrush);
+ DeleteObject(hbrush);
+
+ Draw();
+ DrawAddressColumn();
+ DrawHeader();
+ }
+}
+
+void CHexEditCtrl::SetByteGroupSize(int nBytes)
+{
+ m_NumBytesPerGroup = nBytes;
+ Notify(HXN_GROUPSIZECHANGED);
+
+ UpdateLayoutInfo();
+ ReallocByteBuffers();
+
+ CRect rc;
+ GetClientRect(&rc);
+ CRect clrRc(0, 0, rc.Width(), rc.Height());
+ HBRUSH hbrush = CreateSolidBrush(BKCOLOR_DEFAULT);
+ FillRect(m_BackDC, clrRc, hbrush);
+ DeleteObject(hbrush);
+
+ Draw();
+ DrawAddressColumn();
+ DrawHeader();
+
+ int addressColumnWidth = 11 * m_CharWidth;
+ int headerHeight = m_CharHeight;
+ CRect rcInv = { addressColumnWidth, headerHeight, rc.Width(), rc.Height() };
+ InvalidateRect(&rcInv, true);
+}
diff --git a/Source/Project64/UserInterface/WTLControls/HexEditCtrl.h b/Source/Project64/UserInterface/WTLControls/HexEditCtrl.h
new file mode 100644
index 000000000..4870a2620
--- /dev/null
+++ b/Source/Project64/UserInterface/WTLControls/HexEditCtrl.h
@@ -0,0 +1,309 @@
+#pragma once
+#include
+
+enum
+{
+ HXN_REDRAWSTARTED,
+ HXN_GETBYTEINFO,
+ HXN_SETBYTE,
+ HXN_SETNIBBLE,
+ HXN_FILLRANGE,
+ HXN_RCLICK,
+ HXN_INSERTMODECHANGED,
+ HXN_HOTADDRCHANGED,
+ HXN_BASEADDRCHANGED,
+ HXN_GROUPSIZECHANGED,
+ HXN_SELCHANGED,
+ HXN_CTRLKEYPRESSED,
+ HXN_ENTERPRESSED,
+ HXN_COPY,
+ HXN_PASTE,
+};
+
+enum HXCOLUMN
+{
+ HX_COL_NONE = -1,
+ HX_COL_ADDRESS,
+ HX_COL_HEXDATA,
+ HX_COL_ASCII
+};
+
+typedef struct HXBYTEINFO_S
+{
+ bool bHidden;
+ bool bValid;
+ uint8_t value;
+ COLORREF color;
+ COLORREF bkColor;
+
+ bool operator==(const HXBYTEINFO_S& b) const
+ {
+ return memcmp(this, &b, sizeof(HXBYTEINFO_S)) == 0;
+ }
+
+ bool operator!=(const HXBYTEINFO_S& b) const
+ {
+ return memcmp(this, &b, sizeof(HXBYTEINFO_S)) != 0;
+ }
+} HXBYTEINFO;
+
+template<>
+struct std::hash
+{
+ std::size_t operator()(const HXBYTEINFO& k) const
+ {
+ return (size_t)(k.bValid * 0xFFFFFFFF) ^ (k.value * 0x1010101) ^ k.color ^ k.bkColor;
+ }
+};
+
+typedef struct
+{
+ NMHDR nmh;
+ uint32_t address;
+ size_t numBytes;
+ bool bIgnoreDiff;
+ HXBYTEINFO* oldBytes;
+ HXBYTEINFO* newBytes;
+} NMHXGETBYTEINFO;
+
+typedef struct
+{
+ NMHDR nmh;
+ bool bInsert;
+ uint32_t address;
+ uint8_t value;
+} NMHXSETBYTE;
+
+typedef struct
+{
+ NMHDR nmh;
+ bool bInsert;
+ uint32_t address;
+ bool bLoNibble;
+ uint8_t value;
+} NMHXSETNIBBLE;
+
+typedef struct
+{
+ NMHDR nmh;
+ bool bInsert;
+ uint32_t startAddress;
+ uint32_t endAddress;
+ uint8_t value;
+} NMHXFILLRANGE;
+
+typedef struct
+{
+ NMHDR nmh;
+ uint32_t address;
+ uint32_t length;
+ uint8_t* data;
+} NMHXSETBYTES;
+
+typedef struct
+{
+ NMHDR nmh;
+ uint32_t address;
+} NMHXRCLICK;
+
+typedef struct
+{
+ NMHDR nmh;
+ uint32_t address;
+ HXCOLUMN column;
+} NMHXPASTE;
+
+typedef struct
+{
+ NMHDR nmh;
+ int nChar;
+} NMHXCTRLKEYPRESSED;
+
+class CHexEditCtrl :
+ public CWindowImpl
+{
+public:
+ CHexEditCtrl(void);
+ ~CHexEditCtrl(void);
+ DECLARE_WND_CLASS(_T("HexEditCtrl"))
+ BOOL Attach(HWND hWnd);
+ HWND Detach(void);
+
+ static char ByteAscii(uint8_t value);
+ static uint8_t HexCharValue(char c);
+ static int CALLBACK HaveFontCb(CONST LOGFONTA *lplf, CONST TEXTMETRICA *lptm, DWORD FontType, LPARAM lParam);
+ static bool HaveFont(HDC hdc, const char* name);
+
+ void Draw(void);
+
+ void Copy(void);
+ void Paste(bool bAdvanceCaret = true);
+
+ void SetBaseAddress(uint32_t address);
+ void SetByteGroupSize(int nBytes);
+
+ uint32_t GetBaseAddress(void);
+ uint32_t GetCaretAddress(void);
+ uint32_t GetHotAddress(void);
+ int GetNumBytesPerGroup(void);
+ int GetNumBytesPerRow(void);
+ int GetNumVisibleBytes(void);
+ bool GetSelectionRange(uint32_t* startAddress, uint32_t* endAddress);
+ HXCOLUMN GetFocusedColumn(void);
+ bool GetInsertMode(void);
+
+private:
+ enum HXCELLSIDE
+ {
+ HX_LEFT,
+ HX_RIGHT
+ };
+
+ enum
+ {
+ TIMER_ID_AUTO_REFRESH,
+ TIMER_ID_DRAG_SCROLL
+ };
+
+ enum
+ {
+ BKCOLOR_DEFAULT = RGB(255, 255, 255),
+ BKCOLOR_ADDR = RGB(220, 220, 220),
+ COLOR_ADDR = RGB(40, 40, 40),
+ BKCOLOR_SEL_FOCUSED = RGB(51, 153, 255),
+ COLOR_SEL_FOCUSED = RGB(255, 255, 255),
+ BKCOLOR_SEL_UNFOCUSED = RGB(200, 200, 200),
+ COLOR_SEL_UNFOCUSED = RGB(0, 0, 0),
+ BKCOLOR_HOT = RGB(140, 140, 140)
+ };
+
+ typedef struct
+ {
+ HXCOLUMN column;
+ uint32_t asciiAddress;
+ HXCELLSIDE asciiCellSide;
+ uint32_t hexAddress;
+ HXCELLSIDE hexCellSide;
+ } HXHITTEST;
+
+ typedef struct
+ {
+ CRect rcHex;
+ CRect rcAscii;
+ } HXRECTPAIR;
+
+ uint32_t m_BaseAddress;
+ uint32_t m_DrawnBaseAddress;
+ uint32_t m_SelStartAddress;
+ HXCELLSIDE m_SelStartCellSide;
+ uint32_t m_SelEndAddress;
+ HXCELLSIDE m_SelEndCellSide;
+ uint32_t m_RealSelStartAddress;
+ uint32_t m_RealSelEndAddress;
+ bool m_bHaveRealSel;
+ bool m_bInsertMode;
+ bool m_bHaveCaret;
+ bool m_bCaretVisible;
+ uint32_t m_CaretAddress;
+ bool m_bCaretLoNibble;
+ bool m_bShowHotAddress;
+ uint32_t m_HotAddress;
+ HXCOLUMN m_FocusedColumn;
+ HFONT m_Font;
+ HBITMAP m_BackBMP;
+ HDC m_BackDC;
+ HCURSOR m_hCursorIBeam;
+ HCURSOR m_hCursorDefault;
+ int m_DragScrollDelta;
+ bool m_bDblClicked;
+ bool m_bLButtonDown;
+ bool m_bMouseDragging;
+ bool m_bLayoutChanged;
+ int m_CharWidth;
+ int m_CharHeight;
+ CRect m_AddressColumnRect;
+ CRect m_HexDataColumnRect;
+ CRect m_AsciiColumnRect;
+ int m_NumBytesPerGroup;
+ int m_NumByteGroupsPerRow;
+ int m_NumBytesPerRow;
+ int m_NumVisibleRows;
+ int m_NumVisibleBytes;
+ HXBYTEINFO* m_NewBytes;
+ HXBYTEINFO* m_OldBytes;
+
+ static COLORREF BlendColor(COLORREF c1, COLORREF c2);
+ static uint32_t SatAdd32(uint32_t a, uint32_t b);
+ static uint32_t SatAdd32(uint32_t a, int b);
+
+ void DrawAddressColumn(void);
+ void DrawHeader(void);
+ void Text(int x, int y, const char *text, COLORREF bg, COLORREF fg, CRect* rcOut);
+ bool IsSelected(uint32_t address);
+ int GetSelDirection(void);
+ void CancelSelection(void);
+ void SelectAllVisible(void);
+ void UpdateRealSelection(void);
+
+ uint32_t LineAddress(uint32_t address);
+
+ void GetHexCellPos(int index, CRect* rc);
+ void GetAsciiCellPos(int index, CRect* rc);
+ void HitTest(int x, int y, HXHITTEST* pht);
+
+ void ShowCaret(void);
+ void HideCaret(void);
+ void CaretIncrementNibble(void);
+ void CaretDecrementNibble(void);
+ bool UpdateCaretUI(bool bEnsureVisible, bool bTop = false);
+ void EnsureCaretAddressVisible(bool bTop = false);
+ bool IsCaretAddressVisible(void);
+
+ void UpdateLayoutInfo(void);
+ void ReallocByteBuffers(void);
+
+ LRESULT Notify(UINT code);
+ LRESULT NotifyGetByteInfo(uint32_t address, size_t numBytes, bool bIgnoreDiff, HXBYTEINFO* oldBytes, HXBYTEINFO* newBytes);
+ LRESULT NotifySetByte(uint32_t address, uint8_t value);
+ LRESULT NotifySetNibble(uint32_t address, bool bLoNibble, uint8_t value);
+ LRESULT NotifyFillRange(uint32_t startAddress, uint32_t endAddress, uint8_t value);
+ LRESULT NotifyCtrlKeyPressed(int nChar);
+ LRESULT NotifyPaste(uint32_t address);
+ LRESULT NotifyRightClick(uint32_t address);
+
+ void OnLButtonDown(UINT nFlags, CPoint point);
+ void OnLButtonDblClk(UINT nFlags, CPoint point);
+ void OnLButtonUp(UINT nFlags, CPoint point);
+ void OnRButtonDown(UINT nFlags, CPoint point);
+ void OnRButtonUp(UINT nFlags, CPoint point);
+ void OnMouseMove(UINT nFlags, CPoint point);
+ BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
+ void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
+ void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
+ void OnSetFocus(CWindow wndOld);
+ void OnKillFocus(CWindow wndFocus);
+ void OnTimer(UINT_PTR nIDEvent);
+ UINT OnGetDlgCode(LPMSG lpMsg);
+ void OnPaint(CDCHandle dc);
+ BOOL OnSetCursor(CWindow wnd, UINT nHitTest, UINT message);
+ void OnWindowPosChanged(LPWINDOWPOS lpWndPos);
+
+ BEGIN_MSG_MAP_EX(CHexEditCtrl)
+ MSG_WM_RBUTTONDOWN(OnRButtonDown)
+ MSG_WM_LBUTTONDOWN(OnLButtonDown)
+ MSG_WM_LBUTTONUP(OnLButtonUp)
+ MSG_WM_RBUTTONUP(OnRButtonUp)
+ MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
+ MSG_WM_MOUSEMOVE(OnMouseMove)
+ MSG_WM_MOUSEWHEEL(OnMouseWheel)
+ MSG_WM_KEYDOWN(OnKeyDown)
+ MSG_WM_CHAR(OnChar)
+ MSG_WM_SETFOCUS(OnSetFocus)
+ MSG_WM_KILLFOCUS(OnKillFocus)
+ MSG_WM_TIMER(OnTimer)
+ MSG_WM_GETDLGCODE(OnGetDlgCode)
+ MSG_WM_PAINT(OnPaint)
+ MSG_WM_SETCURSOR(OnSetCursor)
+ MSG_WM_WINDOWPOSCHANGED(OnWindowPosChanged)
+ END_MSG_MAP()
+};
diff --git a/Source/Project64/UserInterface/resource.h b/Source/Project64/UserInterface/resource.h
index 08b0cd062..3fc3dd405 100644
--- a/Source/Project64/UserInterface/resource.h
+++ b/Source/Project64/UserInterface/resource.h
@@ -91,10 +91,8 @@
#define RSP_ABOUT 1006
#define IDC_ASSIGN 1006
#define IDC_BTN_CHOOSE_FILE 1006
-#define IDC_DUMP_MEM 1006
#define IDC_INFO_FILENAME 1007
#define IDC_BTN_RDRAM 1007
-#define IDC_REFRSH_MEM 1007
#define IDC_INFO_ROMNAME 1008
#define IDC_RESET_PAGE 1008
#define IDC_INFO_CARTID 1009
@@ -194,7 +192,6 @@
#define IDC_DIRECT_READ 1057
#define IDC_DMA_READ 1058
#define IDC_CONT_PAK 1059
-#define IDC_SEARCH_MEM 1059
#define IDC_BTN_ROM 1061
#define IDC_TEXTURE_OTHER 1062
#define IDC_TEXTURE_DIR 1063
@@ -202,7 +199,6 @@
#define IDC_TEXTURE_DEFAULT 1064
#define IDC_LST_RESULTS 1064
#define IDC_SELECT_TEXTURE_DIR 1065
-#define IDC_MEM_DETAILS 1065
#define IDC_PLUGIN_OTHER 1066
#define IDC_PLUGIN_DIR 1067
#define IDC_PLUGIN_DEFAULT 1068
@@ -508,9 +504,7 @@
#define IDC_COP0_17_EDIT 1332
#define IDC_COP0_18_EDIT 1333
#define IDC_FILTER_STATIC 1339
-#define IDC_SYM_INFO 1348
#define IDC_BLOCK_INFO 1350
-#define IDC_DMA_INFO 1351
#define IDC_BACK_BTN 1352
#define IDC_FORWARD_BTN 1353
#define IDC_PC_EDIT 1354
@@ -604,7 +598,6 @@
#define IDC_DD44_EDIT 1443
#define IDC_DD48_EDIT 1444
#define IDC_ROM_FIXEDAUDIO 1445
-#define IDC_CHK_AUTOREFRESH 1446
#define IDC_SHOW_FILE_EXTENSIONS 1447
#define IDC_ENHANCEMENTLIST 1450
#define IDC_OVERCLOCK 1451
@@ -718,6 +711,10 @@
#define IDC_CHK_FP_CO 1566
#define IDC_CHK_FP_CU 1567
#define IDC_CHK_FP_CI 1568
+#define IDC_HEXEDIT 1569
+#define IDC_MEMTABS 1571
+#define IDC_STATUSBAR 1572
+#define IDC_CMB_JUMP 1573
#define ID_POPUPMENU_PLAYGAMEWITHDISK 40008
#define ID_POPUPMENU_ADDSYMBOL 40013
#define ID_POPUPMENU_VIEWDISASM 40017
@@ -757,9 +754,21 @@
#define ID_RESULTS_ADDALLTOWATCHLIST 40080
#define ID_WATCHLIST_CHANGE_ADDRESS 40082
#define ID_WATCHLIST_CHANGE_ADDRESSBY 40084
-#define ID_POPUPMENU_COPY_WORD 40089
-#define ID_POPUPMENU_COPY_HALFWORD 40090
-#define ID_POPUPMENU_COPY_BYTE 40091
+#define ID_POPUPMENU_PASTE 40092
+#define ID_POPUPMENU_COPY 40093
+#define ID_POPUPMENU_FOLLOWPOINTER 40095
+#define ID_POPUPMENU_ZEROFILL 40097
+#define ID_POPUPMENU_BYTEGROUPSIZE_1 40103
+#define ID_POPUPMENU_BYTEGROUPSIZE_2 40104
+#define ID_POPUPMENU_BYTEGROUPSIZE_4 40105
+#define ID_POPUPMENU_BYTEGROUPSIZE_8 40106
+#define ID_POPUPMENU_SAFEMODE 40107
+#define ID_POPUPMENU_DUMP 40108
+#define ID_POPUPMENU_SEARCH 40109
+#define ID_POPUPMENU_JUMPHERE 40113
+#define ID_POPUPMENU_COPYGAMESHARKCODE 40118
+#define ID_POPUPMENU_COPYDATAWITHROWADDRESSES 40119
+#define ID_POPUPMENU_COPYDATAWITHGROUPADDRESSES 40120
#define ID_POPUPMENU_ROMDIRECTORY 40137
#define ID_POPUPMENU_REFRESHROMLIST 40138
#define ID_POPUPMENU_PLAYGAME 40152
@@ -777,8 +786,8 @@
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 219
-#define _APS_NEXT_COMMAND_VALUE 40092
-#define _APS_NEXT_CONTROL_VALUE 1569
+#define _APS_NEXT_COMMAND_VALUE 40121
+#define _APS_NEXT_CONTROL_VALUE 1574
#define _APS_NEXT_SYMED_VALUE 102
#endif
#endif