2011-03-06 21:41:41 +00:00
|
|
|
|
using System;
|
2011-03-07 02:47:13 +00:00
|
|
|
|
using System.Drawing;
|
2011-03-06 21:41:41 +00:00
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
namespace BizHawk.MultiClient
|
|
|
|
|
{
|
2011-03-07 17:03:39 +00:00
|
|
|
|
public class MemoryViewer : Panel
|
2011-03-06 21:41:41 +00:00
|
|
|
|
{
|
2011-03-07 02:47:13 +00:00
|
|
|
|
public VScrollBar vScrollBar1;
|
2011-03-07 17:03:39 +00:00
|
|
|
|
public Label info;
|
|
|
|
|
|
2011-03-07 02:47:13 +00:00
|
|
|
|
MemoryDomain Domain = new MemoryDomain("NULL", 1, Endian.Little, addr => 0, (a, v) => { });
|
|
|
|
|
Font font = new Font("Courier New", 10);
|
2011-03-07 17:51:54 +00:00
|
|
|
|
public Brush regBrush = Brushes.Black;
|
|
|
|
|
public Brush highlightBrush = Brushes.LightBlue;
|
2011-03-07 02:47:13 +00:00
|
|
|
|
int RowsVisible = 0;
|
2011-03-07 03:33:25 +00:00
|
|
|
|
int DataSize = 1;
|
2011-03-07 04:40:51 +00:00
|
|
|
|
public bool BigEndian = false;
|
2011-03-07 03:33:25 +00:00
|
|
|
|
string Header = "";
|
2011-03-07 02:47:13 +00:00
|
|
|
|
|
2011-03-07 17:51:54 +00:00
|
|
|
|
int addressHighlighted = -1;
|
2011-03-07 17:03:39 +00:00
|
|
|
|
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;
|
|
|
|
|
|
2011-03-06 21:41:41 +00:00
|
|
|
|
public MemoryViewer()
|
|
|
|
|
{
|
|
|
|
|
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
|
|
|
|
SetStyle(ControlStyles.UserPaint, true);
|
|
|
|
|
SetStyle(ControlStyles.DoubleBuffer, true);
|
2011-03-07 03:04:50 +00:00
|
|
|
|
this.Paint += new System.Windows.Forms.PaintEventHandler(this.MemoryViewer_Paint);
|
2011-03-07 17:03:39 +00:00
|
|
|
|
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.MemoryViewer_MouseMove);
|
|
|
|
|
this.MouseClick += new System.Windows.Forms.MouseEventHandler(this.MemoryViewer_MouseClick);
|
|
|
|
|
|
2011-03-07 02:47:13 +00:00
|
|
|
|
this.vScrollBar1 = new VScrollBar();
|
|
|
|
|
Point n = new Point(this.Size);
|
2011-03-07 17:03:39 +00:00
|
|
|
|
this.vScrollBar1.Location = new System.Drawing.Point(n.X-16, n.Y-this.Height+7);
|
2011-03-07 03:04:50 +00:00
|
|
|
|
this.vScrollBar1.Height = this.Height-8;
|
2011-03-07 02:47:13 +00:00
|
|
|
|
this.vScrollBar1.Width = 16;
|
|
|
|
|
this.vScrollBar1.Visible = true;
|
|
|
|
|
this.vScrollBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
|
|
|
|
| System.Windows.Forms.AnchorStyles.Right)));
|
|
|
|
|
this.vScrollBar1.LargeChange = 16;
|
|
|
|
|
this.vScrollBar1.Name = "vScrollBar1";
|
|
|
|
|
this.vScrollBar1.TabIndex = 0;
|
|
|
|
|
this.vScrollBar1.Scroll += new System.Windows.Forms.ScrollEventHandler(this.vScrollBar1_Scroll);
|
|
|
|
|
this.Controls.Add(this.vScrollBar1);
|
2011-03-07 17:03:39 +00:00
|
|
|
|
|
|
|
|
|
//Debugging control
|
|
|
|
|
this.info = new Label();
|
|
|
|
|
this.info.Text = "";
|
|
|
|
|
this.info.Font = new Font("Courier New", 8);
|
|
|
|
|
this.info.Location = new System.Drawing.Point(n.X / 2, 1);
|
|
|
|
|
this.info.Height = 11;
|
|
|
|
|
this.Controls.Add(this.info);
|
2011-03-07 02:47:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 03:04:50 +00:00
|
|
|
|
//protected unsafe override void OnPaint(PaintEventArgs e)
|
|
|
|
|
private void Display(Graphics g)
|
2011-03-07 02:47:13 +00:00
|
|
|
|
{
|
|
|
|
|
unchecked
|
|
|
|
|
{
|
|
|
|
|
int row = 0;
|
|
|
|
|
int rowX = 8;
|
|
|
|
|
int rowY = 16;
|
|
|
|
|
int rowYoffset = 20;
|
2011-03-07 03:15:16 +00:00
|
|
|
|
string rowStr = "";
|
|
|
|
|
int addr = 0;
|
2011-03-07 17:03:39 +00:00
|
|
|
|
addrOffset = (GetNumDigits(Domain.Size) % 4) * 9 ;
|
|
|
|
|
g.DrawLine(new Pen(regBrush), this.Left + 38 + addrOffset, this.Top, this.Left + 38 + addrOffset, this.Bottom - 40);
|
2011-03-07 03:04:50 +00:00
|
|
|
|
g.DrawLine(new Pen(regBrush), this.Left, 34, this.Right - 16, 34);
|
2011-03-07 17:51:54 +00:00
|
|
|
|
|
|
|
|
|
if (addressHighlighted >= 0) //&& visible (determine this)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
int left = ((addressHighlighted % 16) * 24) + 60 + addrOffset;
|
|
|
|
|
int top = ((addressHighlighted / 16) * 16) + 36;
|
|
|
|
|
Rectangle rect = new Rectangle(left, top, 24, 16);
|
|
|
|
|
g.DrawRectangle(new Pen(highlightBrush), rect);
|
|
|
|
|
g.FillRectangle(highlightBrush, rect);
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 02:47:13 +00:00
|
|
|
|
for (int i = 0; i < RowsVisible; i++)
|
|
|
|
|
{
|
|
|
|
|
row = i + vScrollBar1.Value;
|
2011-03-07 04:40:51 +00:00
|
|
|
|
rowStr = String.Format("{0:X" + GetNumDigits(Domain.Size) + "}", row * 16) + " "; //TODO: fix offsets on vertical line & digits if > 4
|
2011-03-07 03:33:25 +00:00
|
|
|
|
switch (DataSize)
|
2011-03-07 02:47:13 +00:00
|
|
|
|
{
|
2011-03-07 03:33:25 +00:00
|
|
|
|
default:
|
|
|
|
|
case 1:
|
2011-03-07 04:31:58 +00:00
|
|
|
|
Header = " 0 1 2 3 4 5 6 7 8 9 A B C D E F";
|
2011-03-07 03:33:25 +00:00
|
|
|
|
for (int j = 0; j < 16; j++)
|
|
|
|
|
{
|
|
|
|
|
addr = (row * 16) + j;
|
|
|
|
|
if (addr < Domain.Size)
|
2011-03-07 04:31:58 +00:00
|
|
|
|
rowStr += String.Format("{0:X2}", Domain.PeekByte(addr)) + " ";
|
2011-03-07 03:33:25 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
2011-03-07 04:31:58 +00:00
|
|
|
|
Header = " 0 2 4 6 8 A C E";
|
|
|
|
|
for (int j = 0; j < 16; j+=2)
|
|
|
|
|
{
|
|
|
|
|
addr = (row * 16) + j;
|
|
|
|
|
if (addr < Domain.Size)
|
|
|
|
|
rowStr += String.Format("{0:X4}", MakeValue(addr, DataSize, BigEndian)) + " ";
|
|
|
|
|
}
|
2011-03-07 03:33:25 +00:00
|
|
|
|
break;
|
|
|
|
|
case 4:
|
2011-03-07 05:10:33 +00:00
|
|
|
|
Header = " 0 4 8 C";
|
|
|
|
|
for (int j = 0; j < 16; j += 4)
|
|
|
|
|
{
|
|
|
|
|
addr = (row * 16) + j;
|
|
|
|
|
if (addr < Domain.Size)
|
|
|
|
|
rowStr += String.Format("{0:X8}", MakeValue(addr, DataSize, BigEndian)) + " ";
|
|
|
|
|
}
|
2011-03-07 03:33:25 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2011-03-07 02:47:13 +00:00
|
|
|
|
}
|
2011-03-07 17:03:39 +00:00
|
|
|
|
g.DrawString(Domain.Name, font, regBrush, new Point(1, 1));
|
|
|
|
|
g.DrawString(Header, font, regBrush, new Point(rowX + addrOffset, rowY));
|
2011-03-07 03:15:16 +00:00
|
|
|
|
if (row * 16 < Domain.Size)
|
|
|
|
|
g.DrawString(rowStr, font, regBrush, new Point(rowX, (rowY * (i + 1)) + rowYoffset));
|
2011-03-07 02:47:13 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 04:31:58 +00:00
|
|
|
|
private int MakeValue(int addr, int size, bool Bigendian)
|
|
|
|
|
{
|
|
|
|
|
int x = 0;
|
|
|
|
|
if (size == 1 || size == 2 || size == 4)
|
|
|
|
|
{
|
|
|
|
|
switch (size)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
x = Domain.PeekByte(addr);
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
2011-03-07 05:10:33 +00:00
|
|
|
|
x = MakeWord(addr, Bigendian);
|
2011-03-07 04:31:58 +00:00
|
|
|
|
break;
|
2011-03-07 05:10:33 +00:00
|
|
|
|
case 4:
|
|
|
|
|
x = (MakeWord(addr, Bigendian) * 65536) +
|
|
|
|
|
MakeWord(addr + 2, Bigendian);
|
2011-03-07 04:31:58 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return 0; //fail
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 05:10:33 +00:00
|
|
|
|
private int MakeWord(int addr, bool endian)
|
|
|
|
|
{
|
|
|
|
|
if (endian)
|
|
|
|
|
return Domain.PeekByte(addr) + (Domain.PeekByte(addr + 1) * 255);
|
|
|
|
|
else
|
|
|
|
|
return (Domain.PeekByte(addr) * 255) + Domain.PeekByte(addr + 1);
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 02:47:13 +00:00
|
|
|
|
public void ResetScrollBar()
|
|
|
|
|
{
|
|
|
|
|
vScrollBar1.Value = 0;
|
2011-03-07 03:23:05 +00:00
|
|
|
|
SetUpScrollBar();
|
2011-03-07 02:47:13 +00:00
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetUpScrollBar()
|
|
|
|
|
{
|
|
|
|
|
RowsVisible = this.Height / 16;
|
|
|
|
|
int totalRows = Domain.Size / 16;
|
|
|
|
|
int MaxRows = (totalRows - RowsVisible) + 17;
|
|
|
|
|
|
|
|
|
|
if (MaxRows > 0)
|
|
|
|
|
{
|
|
|
|
|
vScrollBar1.Visible = true;
|
|
|
|
|
if (vScrollBar1.Value > MaxRows)
|
|
|
|
|
vScrollBar1.Value = MaxRows;
|
|
|
|
|
vScrollBar1.Maximum = MaxRows;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
vScrollBar1.Visible = false;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetMemoryDomain(MemoryDomain d)
|
|
|
|
|
{
|
|
|
|
|
Domain = d;
|
2011-03-07 17:03:39 +00:00
|
|
|
|
maxRow = Domain.Size / 2;
|
2011-03-07 02:47:13 +00:00
|
|
|
|
SetUpScrollBar();
|
|
|
|
|
vScrollBar1.Value = 0;
|
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string GetMemoryDomainStr()
|
|
|
|
|
{
|
|
|
|
|
return Domain.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
this.SetUpScrollBar();
|
|
|
|
|
this.Refresh();
|
2011-03-06 21:41:41 +00:00
|
|
|
|
}
|
2011-03-07 03:04:50 +00:00
|
|
|
|
|
|
|
|
|
private void MemoryViewer_Paint(object sender, PaintEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
Display(e.Graphics);
|
|
|
|
|
}
|
2011-03-07 04:31:58 +00:00
|
|
|
|
|
|
|
|
|
public void SetDataSize(int size)
|
|
|
|
|
{
|
|
|
|
|
if (size == 1 || size == 2 || size == 4)
|
|
|
|
|
DataSize = size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int GetDataSize()
|
|
|
|
|
{
|
|
|
|
|
return DataSize;
|
|
|
|
|
}
|
2011-03-07 04:40:51 +00:00
|
|
|
|
|
|
|
|
|
private int GetNumDigits(Int32 i)
|
|
|
|
|
{
|
2011-03-07 04:51:41 +00:00
|
|
|
|
if (i <= 0x10000) return 4;
|
|
|
|
|
if (i <= 0x1000000) return 6;
|
2011-03-07 04:40:51 +00:00
|
|
|
|
else return 8;
|
|
|
|
|
}
|
2011-03-07 17:03:39 +00:00
|
|
|
|
|
2011-03-07 17:51:54 +00:00
|
|
|
|
private void SetAddressOver(int x, int y)
|
2011-03-07 17:03:39 +00:00
|
|
|
|
{
|
2011-03-07 17:51:54 +00:00
|
|
|
|
//info.Text = e.X.ToString() + "," + e.Y.ToString(); //Debug
|
2011-03-07 17:03:39 +00:00
|
|
|
|
|
|
|
|
|
//Determine row - 32 pix header, 16 pix width
|
|
|
|
|
//Scroll value determines the first row
|
|
|
|
|
int row = vScrollBar1.Value;
|
2011-03-07 17:51:54 +00:00
|
|
|
|
row += (y - 36) / 16;
|
2011-03-07 17:03:39 +00:00
|
|
|
|
//info.Text += " " + row.ToString(); //Debug
|
|
|
|
|
|
|
|
|
|
//Determine colums - 60 + addrOffset left padding
|
|
|
|
|
//24 pixel wide addresses (when 1 byte)
|
2011-03-07 17:51:54 +00:00
|
|
|
|
int column = (x - (60 + addrOffset)) / 24;
|
2011-03-07 17:03:39 +00:00
|
|
|
|
//info.Text += " " + column.ToString(); //Debug
|
|
|
|
|
//TODO: 2 & 4 byte views
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (row >= 0 && row <= maxRow && column >= 0 && column < 16)
|
|
|
|
|
{
|
|
|
|
|
addressOver = row * 16 + column;
|
|
|
|
|
info.Text = String.Format("{0:X4}", addressOver);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
addressOver = -1;
|
|
|
|
|
info.Text = "";
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-03-07 17:51:54 +00:00
|
|
|
|
|
|
|
|
|
private void MemoryViewer_MouseMove(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
SetAddressOver(e.X, e.Y);
|
|
|
|
|
}
|
2011-03-07 17:03:39 +00:00
|
|
|
|
|
|
|
|
|
private void MemoryViewer_MouseClick(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
2011-03-07 17:51:54 +00:00
|
|
|
|
SetAddressOver(e.X, e.Y);
|
|
|
|
|
if (addressOver >= 0)
|
|
|
|
|
addressHighlighted = addressOver;
|
|
|
|
|
else
|
|
|
|
|
addressHighlighted = -1;
|
2011-03-07 17:03:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int GetPointedAddress()
|
|
|
|
|
{
|
|
|
|
|
if (addressOver >= 0)
|
|
|
|
|
return addressOver;
|
|
|
|
|
else
|
2011-03-07 17:51:54 +00:00
|
|
|
|
return -1; //Negative = no address pointed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int GetHighlightedAddress()
|
|
|
|
|
{
|
|
|
|
|
if (addressHighlighted >= 0)
|
|
|
|
|
return addressHighlighted;
|
|
|
|
|
else
|
|
|
|
|
return -1; //Negative = no address highlighted
|
2011-03-07 17:03:39 +00:00
|
|
|
|
}
|
2011-03-06 21:41:41 +00:00
|
|
|
|
}
|
|
|
|
|
}
|