From d7bc642161753213adc9f983568d449e7d45021c Mon Sep 17 00:00:00 2001 From: "andres.delikat" Date: Mon, 22 Aug 2011 02:48:12 +0000 Subject: [PATCH] Hex Editor - complete refactoring, no longer uses the MemoryViewer object, instead it uses a regular groupbox and a label that contains the memory viewing contents. At the default size (16 rows in view) there is barely any perceived slowdown (about a 10fps boost) on my system. Still some todo's for restoring functionality (such as mouse events) --- .../tools/HexEditor.Designer.cs | 65 ++- BizHawk.MultiClient/tools/HexEditor.cs | 428 ++++++++++++++++-- 2 files changed, 442 insertions(+), 51 deletions(-) diff --git a/BizHawk.MultiClient/tools/HexEditor.Designer.cs b/BizHawk.MultiClient/tools/HexEditor.Designer.cs index 97941867a1..a3d364c779 100644 --- a/BizHawk.MultiClient/tools/HexEditor.Designer.cs +++ b/BizHawk.MultiClient/tools/HexEditor.Designer.cs @@ -55,9 +55,12 @@ this.pokeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.freezeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.addToRamWatchToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.MemoryViewer = new BizHawk.MultiClient.MemoryViewer(); + this.MemoryViewerBox = new System.Windows.Forms.GroupBox(); + this.vScrollBar1 = new System.Windows.Forms.VScrollBar(); + this.AddressesLabel = new System.Windows.Forms.Label(); this.menuStrip1.SuspendLayout(); this.ViewerContextMenuStrip.SuspendLayout(); + this.MemoryViewerBox.SuspendLayout(); this.SuspendLayout(); // // menuStrip1 @@ -68,7 +71,7 @@ this.settingsToolStripMenuItem}); this.menuStrip1.Location = new System.Drawing.Point(0, 0); this.menuStrip1.Name = "menuStrip1"; - this.menuStrip1.Size = new System.Drawing.Size(547, 24); + this.menuStrip1.Size = new System.Drawing.Size(584, 24); this.menuStrip1.TabIndex = 1; this.menuStrip1.Text = "menuStrip1"; // @@ -263,27 +266,46 @@ this.addToRamWatchToolStripMenuItem.Text = "&Add to Ram Watch"; this.addToRamWatchToolStripMenuItem.Click += new System.EventHandler(this.addToRamWatchToolStripMenuItem_Click); // - // MemoryViewer + // MemoryViewerBox // - this.MemoryViewer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) + this.MemoryViewerBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.MemoryViewerBox.Controls.Add(this.vScrollBar1); + this.MemoryViewerBox.Controls.Add(this.AddressesLabel); + this.MemoryViewerBox.Location = new System.Drawing.Point(12, 27); + this.MemoryViewerBox.MaximumSize = new System.Drawing.Size(600, 1024); + this.MemoryViewerBox.Name = "MemoryViewerBox"; + this.MemoryViewerBox.Size = new System.Drawing.Size(558, 277); + this.MemoryViewerBox.TabIndex = 2; + this.MemoryViewerBox.TabStop = false; + // + // vScrollBar1 + // + this.vScrollBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Right))); - this.MemoryViewer.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; - this.MemoryViewer.ContextMenuStrip = this.ViewerContextMenuStrip; - this.MemoryViewer.Location = new System.Drawing.Point(12, 37); - this.MemoryViewer.Name = "MemoryViewer"; - this.MemoryViewer.Size = new System.Drawing.Size(519, 230); - this.MemoryViewer.TabIndex = 0; - this.MemoryViewer.Text = "RAM"; - this.MemoryViewer.Paint += new System.Windows.Forms.PaintEventHandler(this.MemoryViewer_Paint); - this.MemoryViewer.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.MemoryViewer_MouseDoubleClick); + this.vScrollBar1.LargeChange = 16; + this.vScrollBar1.Location = new System.Drawing.Point(539, 8); + this.vScrollBar1.Name = "vScrollBar1"; + this.vScrollBar1.Size = new System.Drawing.Size(16, 266); + this.vScrollBar1.TabIndex = 1; + this.vScrollBar1.Scroll += new System.Windows.Forms.ScrollEventHandler(this.vScrollBar1_Scroll); + // + // AddressesLabel + // + this.AddressesLabel.AutoSize = true; + this.AddressesLabel.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.AddressesLabel.Location = new System.Drawing.Point(6, 16); + this.AddressesLabel.Name = "AddressesLabel"; + this.AddressesLabel.Size = new System.Drawing.Size(28, 14); + this.AddressesLabel.TabIndex = 0; + this.AddressesLabel.Text = "RAM"; // // HexEditor // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(547, 279); - this.Controls.Add(this.MemoryViewer); + this.ClientSize = new System.Drawing.Size(584, 316); + this.Controls.Add(this.MemoryViewerBox); this.Controls.Add(this.menuStrip1); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MainMenuStrip = this.menuStrip1; @@ -291,18 +313,20 @@ this.Text = "HexEditor"; this.Load += new System.EventHandler(this.HexEditor_Load); this.Resize += new System.EventHandler(this.HexEditor_Resize); + this.ResizeEnd += new System.EventHandler(this.HexEditor_ResizeEnd); this.menuStrip1.ResumeLayout(false); this.menuStrip1.PerformLayout(); this.ViewerContextMenuStrip.ResumeLayout(false); + this.MemoryViewerBox.ResumeLayout(false); + this.MemoryViewerBox.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); } #endregion - - private MemoryViewer MemoryViewer; - private System.Windows.Forms.MenuStrip menuStrip1; + + private System.Windows.Forms.MenuStrip menuStrip1; private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem dumpToFileToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; @@ -327,5 +351,8 @@ private System.Windows.Forms.ToolStripMenuItem saveWindowsSettingsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem freezeAddressToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; + private System.Windows.Forms.GroupBox MemoryViewerBox; + private System.Windows.Forms.Label AddressesLabel; + private System.Windows.Forms.VScrollBar vScrollBar1; } } \ No newline at end of file diff --git a/BizHawk.MultiClient/tools/HexEditor.cs b/BizHawk.MultiClient/tools/HexEditor.cs index cbb0c27858..357765e846 100644 --- a/BizHawk.MultiClient/tools/HexEditor.cs +++ b/BizHawk.MultiClient/tools/HexEditor.cs @@ -13,6 +13,8 @@ namespace BizHawk.MultiClient { public partial class HexEditor : Form { + //Refactoring still TODO: hook up mouse events, tweak addressover, proper visiable row calculations in setupscrollbar + //TODO: //Find text box - autohighlights matches, and shows total matches //Users can customize background, & text colors @@ -27,12 +29,32 @@ namespace BizHawk.MultiClient int defaultWidth; int defaultHeight; List domainMenuItems = new List(); + int RowsVisible = 0; + int DataSize = 1; + public bool BigEndian = false; + string Header = ""; + int NumDigits = 4; + char[] nibbles = { 'G', 'G', 'G', 'G' }; //G = off 0-9 & A-F are acceptable values + int addressHighlighted = -1; + int addressOver = -1; + int addrOffset = 0; //If addresses are > 4 digits, this offset is how much the columns are moved to the right + int maxRow = 0; + MemoryDomain Domain = new MemoryDomain("NULL", 1024, Endian.Little, addr => { return 0; }, (a, v) => { v = 0; }); + string info = ""; + int row = 0; + int addr = 0; + const int rowX = 1; + const int rowY = 4; + const int rowYoffset = 20; + Font font = new Font("Courier New", 8); public HexEditor() { InitializeComponent(); + SetHeader(); Closing += (o, e) => SaveConfigSettings(); + AddressesLabel.Font = font; } public void SaveConfigSettings() @@ -71,21 +93,145 @@ namespace BizHawk.MultiClient public void UpdateValues() { if (!this.IsHandleCreated || this.IsDisposed) return; - MemoryViewer.BlazingFast = true; - MemoryViewer.Refresh(); - MemoryViewer.BlazingFast = false; + + GenerateMemoryViewString(); + //MemoryViewer.BlazingFast = true; + //MemoryViewer.Refresh(); + //MemoryViewer.BlazingFast = false; + } + + private void GenerateMemoryViewString() + { + unchecked + { + row = 0; + addr = 0; + + StringBuilder rowStr = new StringBuilder(""); + addrOffset = (NumDigits % 4) * 9; + + + rowStr.Append(Domain.Name + " " + info + '\n'); + rowStr.Append(Header + '\n'); + + for (int i = 0; i < RowsVisible; i++) + { + row = i + vScrollBar1.Value; + if (row * 16 >= Domain.Size) + break; + rowStr.AppendFormat("{0:X" + NumDigits + "} ", row * 16); + switch (DataSize) + { + default: + case 1: + addr = (row * 16); + for (int j = 0; j < 16; j++) + { + if (addr + j < Domain.Size) + rowStr.AppendFormat("{0:X2} ", Domain.PeekByte(addr + j)); + } + rowStr.Append(" | "); + for (int k = 0; k < 16; k++) + { + rowStr.Append(Remap(Domain.PeekByte(addr + k))); + } + rowStr.AppendLine(); + break; + case 2: + addr = (row * 16); + for (int j = 0; j < 16; j += 2) + { + if (addr + j < Domain.Size) + rowStr.AppendFormat("{0:X4} ", MakeValue(addr + j, DataSize, BigEndian)); + } + rowStr.AppendLine(); + rowStr.Append(" | "); + for (int k = 0; k < 16; k++) + { + rowStr.Append(Remap(Domain.PeekByte(addr + k))); + } + break; + case 4: + addr = (row * 16); + for (int j = 0; j < 16; j += 4) + { + if (addr < Domain.Size) + rowStr.AppendFormat("{0:X8} ", MakeValue(addr + j, DataSize, BigEndian)); + } + rowStr.AppendLine(); + rowStr.Append(" | "); + for (int k = 0; k < 16; k++) + { + rowStr.Append(Remap(Domain.PeekByte(addr + k))); + } + break; + + } + + } + AddressesLabel.Text = rowStr.ToString(); + } + } + + static char Remap(byte val) + { + unchecked + { + if (val < ' ') return '.'; + else if (val >= 0x80) return '.'; + else return (char)val; + } + } + + private int MakeValue(int addr, int size, bool Bigendian) + { + unchecked + { + int x = 0; + if (size == 1 || size == 2 || size == 4) + { + switch (size) + { + case 1: + x = Domain.PeekByte(addr); + break; + case 2: + x = MakeWord(addr, Bigendian); + break; + case 4: + x = (MakeWord(addr, Bigendian) * 65536) + + MakeWord(addr + 2, Bigendian); + break; + } + return x; + } + else + return 0; //fail + } + } + + private int MakeWord(int addr, bool endian) + { + unchecked + { + if (endian) + return Domain.PeekByte(addr) + (Domain.PeekByte(addr + 1) * 255); + else + return (Domain.PeekByte(addr) * 255) + Domain.PeekByte(addr + 1); + } } public void Restart() { if (!this.IsHandleCreated || this.IsDisposed) return; SetMemoryDomainMenu(); //Calls update routines - MemoryViewer.ResetScrollBar(); + ResetScrollBar(); } private void restoreWindowSizeToolStripMenuItem_Click(object sender, EventArgs e) { this.Size = new System.Drawing.Size(defaultWidth, defaultHeight); + SetUpScrollBar(); } private void autoloadToolStripMenuItem_Click(object sender, EventArgs e) @@ -95,8 +241,8 @@ namespace BizHawk.MultiClient private void optionsToolStripMenuItem_DropDownOpened(object sender, EventArgs e) { - enToolStripMenuItem.Checked = MemoryViewer.BigEndian; - switch (MemoryViewer.GetDataSize()) + enToolStripMenuItem.Checked = BigEndian; + switch (DataSize) { default: case 1: @@ -116,7 +262,7 @@ namespace BizHawk.MultiClient break; } - if (MemoryViewer.GetHighlightedAddress() >= 0) + if (GetHighlightedAddress() >= 0) { addToRamWatchToolStripMenuItem1.Enabled = true; freezeAddressToolStripMenuItem.Enabled = true; @@ -128,21 +274,30 @@ namespace BizHawk.MultiClient } } + public void SetMemoryDomain(MemoryDomain d) + { + Domain = d; + maxRow = Domain.Size / 2; + SetUpScrollBar(); + vScrollBar1.Value = 0; + Refresh(); + } + private void SetMemoryDomain(int pos) { if (pos < Global.Emulator.MemoryDomains.Count) //Sanity check { - MemoryViewer.SetMemoryDomain(Global.Emulator.MemoryDomains[pos]); + SetMemoryDomain(Global.Emulator.MemoryDomains[pos]); } UpdateDomainString(); - MemoryViewer.ResetScrollBar(); + ResetScrollBar(); } private void UpdateDomainString() { - string memoryDomain = MemoryViewer.GetMemoryDomainStr(); + string memoryDomain = Domain.ToString(); string systemID = Global.Emulator.SystemId; - MemoryViewer.Text = systemID + " " + memoryDomain; + MemoryViewerBox.Text = systemID + " " + memoryDomain; } private void SetMemoryDomainMenu() @@ -175,39 +330,138 @@ namespace BizHawk.MultiClient private void goToAddressToolStripMenuItem_Click(object sender, EventArgs e) { - MemoryViewer.GoToSpecifiedAddress(); + GoToSpecifiedAddress(); + } + + private int GetNumDigits(Int32 i) + { + unchecked + { + if (i <= 0x10000) return 4; + if (i <= 0x1000000) return 6; + else return 8; + } + } + + public void GoToSpecifiedAddress() + { + InputPrompt i = new InputPrompt(); + i.Text = "Go to Address"; + i.SetMessage("Enter a hexadecimal value"); + Global.Sound.StopSound(); + i.ShowDialog(); + Global.Sound.StartSound(); + + if (i.UserOK) + { + if (InputValidate.IsValidHexNumber(i.UserText)) + { + GoToAddress(int.Parse(i.UserText, NumberStyles.HexNumber)); + } + } + } + + private void ClearNibbles() + { + for (int x = 0; x < 4; x++) + nibbles[x] = 'G'; } public void GoToAddress(int address) { - MemoryViewer.GoToAddress(address); + if (address < 0) + address = 0; + + if (address >= Domain.Size) + address = Domain.Size - 1; + + SetHighlighted(address); + ClearNibbles(); + //Refresh(); } + public void SetHighlighted(int addr) + { + if (addr < 0) + addr = 0; + if (addr >= Domain.Size) + addr = Domain.Size - 1; + + if (!IsVisible(addr)) + { + int v = (addr / 16) - RowsVisible + 1; + if (v < 0) + v = 0; + //vScrollBar1.Value = v; + } + addressHighlighted = addr; + addressOver = addr; + info = String.Format("{0:X4}", addressOver); + Refresh(); + } + + public bool IsVisible(int addr) + { + unchecked + { + int row = addr >> 4; + + //if (row >= vScrollBar1.Value && row < (RowsVisible + vScrollBar1.Value)) + return true; + //else + // return false; + } + } private void HexEditor_Resize(object sender, EventArgs e) { - MemoryViewer.SetUpScrollBar(); - MemoryViewer.Refresh(); + //MemoryViewer.SetUpScrollBar(); + //MemoryViewer.Refresh(); + } + + private void SetHeader() + { + switch (DataSize) + { + case 1: + Header = " 0 1 2 3 4 5 6 7 8 9 A B C D E F"; + break; + case 2: + Header = " 0 2 4 6 8 A C E"; + break; + case 4: + Header = " 0 4 8 C"; + break; + } + NumDigits = GetNumDigits(Domain.Size); + } + + public void SetDataSize(int size) + { + if (size == 1 || size == 2 || size == 4) + DataSize = size; + + SetHeader(); } private void byteToolStripMenuItem_Click(object sender, EventArgs e) { - MemoryViewer.SetDataSize(1); + SetDataSize(1); } private void byteToolStripMenuItem1_Click(object sender, EventArgs e) { - MemoryViewer.SetDataSize(2); + SetDataSize(2); } private void byteToolStripMenuItem2_Click(object sender, EventArgs e) { - MemoryViewer.SetDataSize(4); + SetDataSize(4); } private void enToolStripMenuItem_Click(object sender, EventArgs e) { - MemoryViewer.BigEndian ^= true; + BigEndian ^= true; } private void MemoryViewer_Paint(object sender, PaintEventArgs e) @@ -218,13 +472,13 @@ namespace BizHawk.MultiClient private void AddToRamWatch() { //Add to RAM Watch - int address = MemoryViewer.GetHighlightedAddress(); + int address = GetHighlightedAddress(); if (address >= 0) { Watch w = new Watch(); w.address = address; - switch (MemoryViewer.GetDataSize()) + switch (DataSize) { default: case 1: @@ -238,7 +492,7 @@ namespace BizHawk.MultiClient break; } - w.bigendian = MemoryViewer.BigEndian; + w.bigendian = BigEndian; w.signed = asigned.HEX; Global.MainForm.LoadRamWatch(); @@ -253,7 +507,7 @@ namespace BizHawk.MultiClient private void pokeToolStripMenuItem_Click(object sender, EventArgs e) { - int p = MemoryViewer.GetPointedAddress(); + int p = GetPointedAddress(); if (p >= 0) { InputPrompt i = new InputPrompt(); @@ -266,13 +520,41 @@ namespace BizHawk.MultiClient if (InputValidate.IsValidHexNumber(i.UserText)) { int value = int.Parse(i.UserText, NumberStyles.HexNumber); - MemoryViewer.HighlightPointed(); - MemoryViewer.PokeHighlighted(value); + HighlightPointed(); + PokeHighlighted(value); } } } } + public int GetPointedAddress() + { + if (addressOver >= 0) + return addressOver; + else + return -1; //Negative = no address pointed + } + + public void HighlightPointed() + { + if (addressOver >= 0) + { + addressHighlighted = addressOver; + } + else + addressHighlighted = -1; + ClearNibbles(); + this.Focus(); + this.Refresh(); + } + + public void PokeHighlighted(int value) + { + //TODO: 2 byte & 4 byte + if (addressHighlighted >= 0) + Domain.PokeByte(addressHighlighted, (byte)value); + } + private void addToRamWatchToolStripMenuItem_Click(object sender, EventArgs e) { AddToRamWatch(); @@ -299,17 +581,25 @@ namespace BizHawk.MultiClient FreezeAddress(); } + public int GetHighlightedAddress() + { + if (addressHighlighted >= 0) + return addressHighlighted; + else + return -1; //Negative = no address highlighted + } + private void FreezeAddress() { - int address = MemoryViewer.GetHighlightedAddress(); + int address = GetHighlightedAddress(); if (address >= 0) { Cheat c = new Cheat(); c.address = address; - c.value = MemoryViewer.GetPointedValue(); - c.domain = MemoryViewer.GetDomain(); + c.value = Domain.PeekByte(addressOver); + c.domain = Domain; //TODO: multibyte - switch (MemoryViewer.GetDataSize()) + switch (DataSize) { default: case 1: @@ -335,7 +625,7 @@ namespace BizHawk.MultiClient { for (int x = 0; x < domainMenuItems.Count; x++) { - if (MemoryViewer.GetDomain().Name == domainMenuItems[x].Text) + if (Domain.Name == domainMenuItems[x].Text) domainMenuItems[x].Checked = true; else domainMenuItems[x].Checked = false; @@ -361,11 +651,11 @@ namespace BizHawk.MultiClient { string str = ""; - for (int x = 0; x < MemoryViewer.GetDomain().Size / 16; x++) + for (int x = 0; x < Domain.Size / 16; x++) { for (int y = 0; y < 16; y++) { - str += String.Format("{0:X2} ", MemoryViewer.GetDomain().PeekByte((x * 16) + y)); + str += String.Format("{0:X2} ", Domain.PeekByte((x * 16) + y)); } str += "\r\n"; } @@ -398,5 +688,79 @@ namespace BizHawk.MultiClient return file; } + public void ResetScrollBar() + { + vScrollBar1.Value = 0; + SetUpScrollBar(); + Refresh(); + } + + public void SetUpScrollBar() + { + int height = font.Height + 3; + RowsVisible = ((MemoryViewerBox.Height - height - 5) / height); + int totalRows = Domain.Size / 16; + int MaxRows = (totalRows - RowsVisible) + 16; + + if (MaxRows > 0) + { + vScrollBar1.Visible = true; + if (vScrollBar1.Value > MaxRows) + vScrollBar1.Value = MaxRows; + vScrollBar1.Maximum = MaxRows; + } + else + vScrollBar1.Visible = false; + + } + + private void vScrollBar1_Scroll(object sender, ScrollEventArgs e) + { + this.SetUpScrollBar(); + UpdateValues(); + } + + private void MemoryViewer_MouseMove(object sender, MouseEventArgs e) + { + SetAddressOver(e.X, e.Y); + } + + private void MemoryViewer_MouseClick(object sender, MouseEventArgs e) + { + SetAddressOver(e.X, e.Y); + if (addressOver == addressHighlighted && addressOver >= 0) + { + addressHighlighted = -1; + this.Refresh(); + } + else + HighlightPointed(); + } + + private void SetAddressOver(int x, int y) + { + //Scroll value determines the first row + int row = vScrollBar1.Value; + row += (y - 36) / (font.Height - 1); + int column = (x - (49 + addrOffset)) / 20; + + //TODO: 2 & 4 byte views + + if (row >= 0 && row <= maxRow && column >= 0 && column < 16) + { + addressOver = row * 16 + column; + info = String.Format("{0:X4}", addressOver); + } + else + { + addressOver = -1; + info = ""; + } + } + + private void HexEditor_ResizeEnd(object sender, EventArgs e) + { + SetUpScrollBar(); + } } }