1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 12:32:20 +02:00
Beef/IDE/src/ui/MemoryPanel.bf
2021-02-25 10:14:22 -08:00

1225 lines
45 KiB
Beef

using System;
using System.Collections;
using System.Text;
using System.Threading.Tasks;
using System.Globalization;
using System.Reflection;
using Beefy;
using Beefy.widgets;
using Beefy.theme;
using Beefy.gfx;
using Beefy.theme.dark;
using Beefy.events;
using Beefy.utils;
using IDE.Debugger;
namespace IDE.ui
{
public class MemoryVarListView : DarkListView
{
MemoryPanel mMemoryPanel;
public this(MemoryPanel panel)
{
mMemoryPanel = panel;
//mHeaderImageIdx = DarkTheme.ImageIdx.COUNT;
//mHeaderLabelYOfs = 2 - panel.mVarListViewStartY;
}
public override void Draw(Graphics g)
{
g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.EditBox), 0, GS!(mMemoryPanel.mBinaryDataWidget.mColumnHeaderHeight) + GS!(mHeaderLabelYOfs) - GS!(1), mWidth, mHeight - GS!(mMemoryPanel.mBinaryDataWidget.mColumnHeaderHeight));
base.Draw(g);
}
}
public class MemoryRepListView : DarkListView
{
[AllowDuplicates]
public enum RepType
{
// integer types (dual signed/unsigned reps)
Address,
Int8,
Int16,
Int32,
Int64,
Float,
Double,
AddrSymbol,
ValSymbol,
COUNT,
INTCOUNT = (int32)RepType.Float
}
MemoryPanel mMemoryPanel;
DarkEditWidget mEditWidget;
ListViewItem mEditingItem;
RepType mEditingRepType;
bool mEditRepTypeIsAlt;
bool mEditSubmitting;
DebugManager.IntDisplayType[] mIntRepTypeDisplayTypes = new DebugManager.IntDisplayType[(int32)RepType.INTCOUNT] ~ delete _;
DebugManager.IntDisplayType[] mIntRepTypeDisplayTypesAlt = new DebugManager.IntDisplayType[(int32)RepType.INTCOUNT] ~ delete _;
DebugManager.IntDisplayType mDefaultDisplayType = DebugManager.IntDisplayType.Default;
const int32 kLockSize = 256; // are you really going to be typing strings longer than this in here? Yeah I didn't think so.
public static void GetRepTypeDescription(RepType repType, String outRepType)
{
/*FieldInfo fi = repType.GetType().GetField(repType.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if ((attributes != null) && (attributes.Length > 0))
return attributes[0].Description;
return repType.ToString();*/
repType.ToString(outRepType);
}
public this(MemoryPanel panel)
{
mMemoryPanel = panel;
//mShowColumnGrid = true;
//mShowLineGrid = true;
mLabelX = GS!(6);
for (int32 i=0; i<mIntRepTypeDisplayTypes.Count; ++i)
{
mIntRepTypeDisplayTypes[i] = DebugManager.IntDisplayType.Default;
mIntRepTypeDisplayTypesAlt[i] = DebugManager.IntDisplayType.Default;
}
}
/*protected override void DrawColumnGridColumn(Graphics g, float x, float y, float height, uint32 color)
{
float yBase = 0;
var baseItem = GetRoot().GetChildAtIndex(0);
if (baseItem != null)
{
float xBase;
baseItem.SelfToOtherTranslate(this, 0, 0, out xBase, out yBase);
}
float yLimit = yBase + (int32)RepType.INTCOUNT * mFont.GetLineSpacing();
float useHeight = height;
if ((y + useHeight) > yLimit)
useHeight = yLimit - y;
base.DrawColumnGridColumn(g, x, y, useHeight, color);
}*/
public override void Draw(Graphics g)
{
//g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.Window), 0, mMemoryPanel.mBinaryDataWidget.mColumnHeaderHeight + mHeaderLabelYOfs - 1, mWidth, mHeight - mMemoryPanel.mBinaryDataWidget.mColumnHeaderHeight);
base.Draw(g);
}
public void InitRows()
{
VertScrollTo(0);
GetRoot().Clear();
for (int32 i=0; i<(int32)RepType.COUNT; ++i)
{
RepType repType = (RepType)i;
var listViewItem = GetRoot().CreateChildItem();
listViewItem.mOnMouseDown.Add(new (theEvent) => OnRepListValueClicked(theEvent, repType, 0));
String repName = scope String();
GetRepTypeDescription(repType, repName);
listViewItem.Label = repName;
var subItem = listViewItem.CreateSubItem(1);
subItem.Label = "";
subItem.mOnMouseDown.Add(new (theEvent) => OnRepListValueClicked(theEvent, repType, 1));
if (i<(int32)RepType.INTCOUNT)
{
subItem = listViewItem.CreateSubItem(2);
subItem.Label = "";
subItem.mOnMouseDown.Add(new (theEvent) => OnRepListValueClicked(theEvent, repType, 2));
}
}
}
public void ZomgRandomFloatTest()
{
/*Random rng = new Random((int)DateTime.Now.ToBinary());
byte[] srcFltBytes = new byte[4];
for (int i=0; i<100000; ++i)
{
int exponent;
do
{
rng.NextBytes(srcFltBytes);
//srcFltBytes[3] &= 0x80; srcFltBytes[2] &= 0x7f; // denormal test
exponent = ((srcFltBytes[3] & 0x7f) << 1) | ((srcFltBytes[2] >> 7) & 1);
//System.Diagnostics.Trace.Assert(exponent == 0); // denormal test
} while (/*exponent == 0 || */exponent == 0xFF); // skip zero/denormal/inf/nan for now
float srcF = System.BitConverter.ToSingle(srcFltBytes, 0);
string srcS = srcF.ToString("G10");
if (!srcS.Contains('.'))
srcS += ".0";
string evalResultStr = MemoryPanel.EvalExpression(srcS);
if (evalResultStr == null)
System.Diagnostics.Trace.Assert(false, "Could not eval expression");
float dstF;
if (!float.TryParse(evalResultStr, out dstF))
System.Diagnostics.Trace.Assert(false, "Could not parse float");
string dstS = dstF.ToString("G10");
if (!dstS.Contains('.'))
dstS += ".0";
System.Diagnostics.Trace.Assert(srcS == dstS);
System.Diagnostics.Trace.Assert(srcF == dstF);
}*/
}
public void ZomgRandomDoubleTest()
{
/*Random rng = new Random((int)DateTime.Now.ToBinary());
byte[] srcFltBytes = new byte[8];
for (int i=0; i<100000; ++i)
{
int exponent;
do
{
rng.NextBytes(srcFltBytes);
//srcFltBytes[7] &= 0x80; srcFltBytes[6] &= 0x0f; // denormal test
exponent = ((int)(srcFltBytes[7] & 0x7f) << 4) | ((srcFltBytes[6] >> 4) & 0x0f);
//System.Diagnostics.Trace.Assert(exponent == 0); // denormal test
} while (exponent == 0 || exponent == 0x7FF); // skip zero/denormal/inf/nan for now
double srcF = System.BitConverter.ToDouble(srcFltBytes, 0);
string srcS = srcF.ToString("G18");
if (!srcS.Contains('.'))
srcS += ".0";
string evalResultStr = MemoryPanel.EvalExpression(srcS);
if (evalResultStr == null)
System.Diagnostics.Trace.Assert(false, "Could not eval expression");
double dstF;
if (!double.TryParse(evalResultStr, out dstF))
System.Diagnostics.Trace.Assert(false, "Could not parse float");
string dstS = dstF.ToString("G18");
if (!dstS.Contains('.'))
dstS += ".0";
System.Diagnostics.Trace.Assert(srcS == dstS);
System.Diagnostics.Trace.Assert(srcF == dstF);
}*/
}
public void UpdateRepStrings()
{
//ZomgRandomFloatTest();
//ZomgRandomDoubleTest();
var lockRange = mMemoryPanel.mBinaryDataWidget.GetLockedRangeAtCursor(kLockSize);
if (lockRange == null)
{
for (int32 i=0; i<GetRoot().GetChildCount(); ++i)
{
GetRoot().GetChildAtIndex(i).GetSubItem(1).Label = "";
if (i<(int32)RepType.INTCOUNT)
GetRoot().GetChildAtIndex(i).GetSubItem(2).Label = "";
}
}
else
{
defer delete lockRange;
{
for (int32 i=0; i<GetRoot().GetChildCount(); ++i)
{
String s = scope String();
String altS = scope String();
bool hasAltS = false;
DebugManager.IntDisplayType intDisplayType = DebugManager.IntDisplayType.Default;
DebugManager.IntDisplayType altIntDisplayType = DebugManager.IntDisplayType.Default;
if (i < (int32)RepType.INTCOUNT)
{
intDisplayType = mIntRepTypeDisplayTypes[i];
altIntDisplayType = mIntRepTypeDisplayTypesAlt[i];
}
if (intDisplayType == DebugManager.IntDisplayType.Default)
intDisplayType = mDefaultDisplayType;
if (altIntDisplayType == DebugManager.IntDisplayType.Default)
altIntDisplayType = mDefaultDisplayType;
int32 intBase, altIntBase;
String intBasePrefix = null, altIntBasePrefix = null;
switch(intDisplayType)
{
case DebugManager.IntDisplayType.Hexadecimal: intBase = 16; intBasePrefix = "0x"; break;
case DebugManager.IntDisplayType.Binary: intBase = 2; intBasePrefix = "0b"; break;
default: intBase = 10; break;
}
switch(altIntDisplayType)
{
case DebugManager.IntDisplayType.Hexadecimal: altIntBase = 16; altIntBasePrefix = "0x"; break;
case DebugManager.IntDisplayType.Binary: altIntBase = 2; altIntBasePrefix = "0b"; break;
default: altIntBase = 10; break;
}
switch((RepType)i)
{
case RepType.Address:
s.AppendF("0x{:A}", (uint64)lockRange.mBaseOffset);
case RepType.Int8:
hasAltS = true;
(*(int8*)lockRange.mData.CArray()).ToString(s, (intBase == 10) ? "" : "X2", null);
((UInt64)*(uint8*)lockRange.mData.CArray()).ToString(altS, (altIntBase == 10) ? "" : "X2", null);
case RepType.Int16:
hasAltS = true;
(*(int16*)lockRange.mData.CArray()).ToString(s, (intBase == 10) ? "" : "X4", null);
((UInt64)*(uint16*)lockRange.mData.CArray()).ToString(altS, (altIntBase == 10) ? "" : "X4", null);
case RepType.Int32:
hasAltS = true;
(*(int32*)lockRange.mData.CArray()).ToString(s, (intBase == 10) ? "" : "X8", null);
((UInt64)*(uint32*)lockRange.mData.CArray()).ToString(altS, (altIntBase == 10) ? "" : "X8", null);
case RepType.Int64:
hasAltS = true;
(*(int64*)lockRange.mData.CArray()).ToString(s, (intBase == 10) ? "" : "X16", null);
((UInt64)*(uint64*)lockRange.mData.CArray()).ToString(altS, (altIntBase == 10) ? "" : "X16", null);
case RepType.Float:
(*(float*)lockRange.mData.CArray()).ToString(s);
case RepType.Double:
(*(double*)lockRange.mData.CArray()).ToString(s);
case RepType.AddrSymbol:
gApp.mDebugger.GetAddressSymbolName(lockRange.mBaseOffset, true, s);
case RepType.ValSymbol:
int addr = 0;
if (gApp.mDebugger.GetAddrSize() == 8)
addr = (.)*(uint64*)lockRange.mData.CArray();
else
addr = (.)*(uint32*)lockRange.mData.CArray();
gApp.mDebugger.GetAddressSymbolName(addr, true, s);
/*case RepType.StringA:
fallthrough;
case RepType.StringW:
{
{
uint8* buf = lockRange.mData.CArray();
int bufOfs = 0;
{
if ((RepType)i == RepType.StringA)
{
while (bufOfs < kLockSize)
{
char8 c = *(char8*)(buf + bufOfs);
if (c == 0)
break;
s.Append(c);
bufOfs++;
}
}
else
{
while (bufOfs < kLockSize)
{
char16 c = *(char16*)(buf + bufOfs);
if (c == 0)
break;
s.Append(c);
bufOfs++;
}
}
}
}
}
break;*/
default: break;
}
if (i < (int)RepType.INTCOUNT)
{
if (intBasePrefix != null)
s.Insert(0, intBasePrefix);
if (!altS.IsEmpty && altIntBasePrefix != null)
altS.Insert(0, altIntBasePrefix);
}
GetRoot().GetChildAtIndex(i).GetSubItem(1).Label = s;
if (hasAltS)
GetRoot().GetChildAtIndex(i).GetSubItem(2).Label = altS;
}
}
}
}
public void OnRepListValueClicked(MouseEvent theEvent, RepType repType, int32 column)
{
ListViewItem clickedItem = (ListViewItem)theEvent.mSender;
ListViewItem item = (ListViewItem)clickedItem.GetSubItem(0);
GetRoot().SelectItemExclusively(item);
SetFocus();
if ((theEvent.mBtn == 0) && (theEvent.mBtnCount > 1))
{
if ((column == 1) || (column == 2))
{
EditItem(clickedItem, repType, column);
}
}
else if (theEvent.mBtn == 1)
{
ShowRightClickMenu(theEvent, repType, column);
}
}
private void EditItem(ListViewItem item, RepType repType, int32 column)
{
ListViewItem subItem = (ListViewItem)item.GetSubItem(column);
mEditWidget = new DarkEditWidget();
String editVal = subItem.mLabel;
mEditWidget.SetText(editVal);
mEditWidget.Content.SelectAll();
mEditSubmitting = true; // Default to submitting on lost focus
mEditingItem = item;
mEditingRepType = repType;
mEditRepTypeIsAlt = (column == 2);
float x;
float y;
subItem.SelfToOtherTranslate(this, 0, 0, out x, out y);
x = subItem.LabelX - 4;
float width = Math.Max(mWidth - x - 20, 50);
mEditWidget.Resize(x, y, width, 20);
AddWidget(mEditWidget);
mEditWidget.mOnLostFocus.Add(new => HandleEditLostFocus);
mEditWidget.mOnSubmit.Add(new => HandleRenameSubmit);
mEditWidget.mOnCancel.Add(new => HandleRenameCancel);
WidgetWindow.sOnMouseWheel.Add(new => HandleMouseWheel);
mEditWidget.SetFocus();
}
void ShowRightClickMenu(MouseEvent theEvent, RepType repType, int32 column)
{
if ((int32)repType >= (int32)RepType.INTCOUNT)
return;
bool isAlt = (column == 2);
Menu menu = new Menu();
delegate void(String, bool) addSubMenu = scope (label, useRepType) => {
Menu subMenu = menu.AddItem(label);
for (DebugManager.IntDisplayType i = default; i < DebugManager.IntDisplayType.COUNT; i++)
{
var toType = i;
Menu subMenuItem = subMenu.AddItem(ToStackString!(i));
DebugManager.IntDisplayType curDisplayType = (useRepType) ? (isAlt ? mIntRepTypeDisplayTypesAlt[(int32)repType] : mIntRepTypeDisplayTypes[(int32)repType]) : mDefaultDisplayType;
if (curDisplayType == i)
subMenuItem.mIconImage = DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.Check);
subMenuItem.mOnMenuItemSelected.Add(new (iMenu) =>
{
if (useRepType)
{
if (isAlt)
mIntRepTypeDisplayTypesAlt[(int)repType] = toType;
else
mIntRepTypeDisplayTypes[(int)repType] = toType;
}
else
mDefaultDisplayType = toType;
UpdateRepStrings();
});
}
};
addSubMenu("Item Display", true);
addSubMenu("Default Display", false);
float x, y;
theEvent.GetRootCoords(out x, out y);
MenuWidget menuWidget = ThemeFactory.mDefault.CreateMenuWidget(menu);
menuWidget.Init(mWidgetWindow.mRootWidget, x, y);
}
void HandleMouseWheel(MouseEvent evt)
{
HandleEditLostFocus(mEditWidget);
}
void HandleEditLostFocus(Widget widget)
{
if (mEditWidget == null)
return;
if (mEditSubmitting)
{
String editText = scope String();
mEditWidget.GetText(editText);
String expr = scope String();
editText.Append(", d");
if (!MemoryPanel.EvalExpression(editText, expr))
expr = editText;
bool markDirty = false;
var lockRange = mMemoryPanel.mBinaryDataWidget.GetLockedRangeAtCursor(kLockSize);
if (lockRange != null)
{
defer delete lockRange;
switch(mEditingRepType)
{
case RepType.Address:
if (uint64.Parse(expr, .HexNumber) case .Ok(let val))
{
mMemoryPanel.mBinaryDataWidget.SelectRange((int)val, 1);
}
case RepType.Int8:
// Check mEditRepTypeIsAlt?
if (int32.Parse(expr) case .Ok(let val))
{
*((int8*)lockRange.mData.CArray()) = (.)val;
}
case RepType.Int16:
if (int32.Parse(expr) case .Ok(let val))
{
*((int16*)lockRange.mData.CArray()) = (.)val;
}
case RepType.Int32:
if (int32.Parse(expr) case .Ok(let val))
{
*((int32*)lockRange.mData.CArray()) = (.)val;
}
case RepType.Int64:
if (int64.Parse(expr) case .Ok(let val))
{
*((int64*)lockRange.mData.CArray()) = (.)val;
}
case RepType.Float:
if (float.Parse(expr) case .Ok(let val))
{
*((float*)lockRange.mData.CArray()) = (.)val;
}
case RepType.Double:
if (double.Parse(expr) case .Ok(let val))
{
*((double*)lockRange.mData.CArray()) = (.)val;
}
/*case RepType.StringA:
case RepType.StringW:
{
unsafe
{
//fixed (byte* buf = lockRange.mData)
{
IntPtr ptr;
int len;
if (mEditingRepType == RepType.StringA)
{
ptr = (IntPtr)System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(expr);
len = expr.Length + 1;
}
else
{
ptr = (IntPtr)System.Runtime.InteropServices.Marshal.StringToHGlobalUni(expr);
len = (expr.Length + 1) * 2;
}
len = Math.Min(len, lockRange.mData.Length);
repBytes = new byte[len];
System.Runtime.InteropServices.Marshal.Copy(ptr, repBytes, 0, len);
System.Runtime.InteropServices.Marshal.FreeHGlobal(ptr);
}
}
}
break;*/
default: break;
}
lockRange.mModified = true;
markDirty = true;
}
if (markDirty)
{
mMemoryPanel.MarkViewDirty();
UpdateRepStrings();
}
}
EditWidget editWidget = (EditWidget)widget;
editWidget.mOnLostFocus.Remove(scope => HandleEditLostFocus, true);
editWidget.mOnSubmit.Remove(scope => HandleRenameSubmit, true);
editWidget.mOnCancel.Remove(scope => HandleRenameCancel, true);
WidgetWindow.sOnMouseWheel.Remove(scope => HandleMouseWheel, true);
editWidget.RemoveSelf();
gApp.DeferDelete(editWidget);
mEditWidget = null;
if (mWidgetWindow.mFocusWidget == null)
SetFocus();
//if ((mHasFocus) && (mEditingItem.mParent != null))
// GetRoot().SelectItemExclusively(mEditingItem);
mEditingItem = null;
mEditingRepType = RepType.COUNT;
mEditRepTypeIsAlt = false;
mEditSubmitting = false;
}
void HandleRenameCancel(EditEvent theEvent)
{
mEditSubmitting = false;
HandleEditLostFocus((EditWidget)theEvent.mSender);
}
delegate bool TryParseHandler<T>(String expr, out T val);
delegate uint8[] GetBytesHandler<T>(T val);
uint8[] ParseType<T>(String expr, TryParseHandler<T> parseHandler, GetBytesHandler<T> getBytesHandler)
{
T val;
if (parseHandler(expr, out val))
return getBytesHandler(val);
return null;
}
void HandleRenameSubmit(EditEvent theEvent)
{
mEditSubmitting = true;
HandleEditLostFocus((EditWidget)theEvent.mSender);
}
public override void DrawAll(Graphics g)
{
base.DrawAll(g);
}
}
public class MemoryContentProvider : IBinaryDataContentProvider
{
public bool IsReadOnly { get { return false; } }
public uint8[] ReadBinaryData(int offset, int32 size)
{
uint8[] result = new uint8[(int32)size];
IDEApp.sApp.mDebugger.ReadMemory(offset, (int)size, result);
return result;
}
public void WriteBinaryData(uint8[] data, int offset)
{
IDEApp.sApp.mDebugger.WriteMemory(offset, (int)data.Count, data);
}
}
public class MemoryPanel : Panel
{
public BinaryDataWidget mBinaryDataWidget;
//public DarkEditWidget mAddressEditWidget;
//public WatchRefreshButton mWatchRefreshButton;
public MemoryVarListView mVarListView;
public MemoryRepListView mRepListView;
public DockingProxy mVarListViewDockingProxy;
public DockingProxy mRepListViewDockingProxy;
public DarkDockingFrame mDockingFrame;
//public TabbedView mTabbedView;
public MemoryContentProvider mProvider ~ delete _;
public String mLastAddressExpr = new String() ~ delete _;
public String mLastAddressValue = new String() ~ delete _;
public float mVarListViewStartY = 0;//5;
public bool mMemoryViewDirty = true;
public bool mAutoExprRefresh = true;
public bool mDisabled;
public int32 mDisabledTicks;
//public int mCallStackUpdateCnt;
public Dictionary<ListViewItem, BinaryDataWidget.TrackedExpression> mListViewItemToTrackedExprMap = new Dictionary<ListViewItem,BinaryDataWidget.TrackedExpression>() ~ delete _;
public this()
{
mProvider = new MemoryContentProvider();
mBinaryDataWidget = new BinaryDataWidget(mProvider);
mBinaryDataWidget.InitScrollbar();
mBinaryDataWidget.mScrollbarInsets.mTop -= 1;
mBinaryDataWidget.UpdateScrollbar();
mBinaryDataWidget.TrackedExpressionsUpdated.Add(new => OnTrackedExpressionsUpdated);
mBinaryDataWidget.OnKeyCursorUpdated.Add(new => OnBinaryDataKeyCursorUpdated);
mBinaryDataWidget.OnActiveWidthChanged.Add(new => OnBinaryDataActiveWidthChanged);
mBinaryDataWidget.mOnGotoAddress.Add(new => GotoAddress);
/*mAddressEditWidget = new DarkEditWidget();
mAddressEditWidget.SetText(mLastAddressExpr);
mAddressEditWidget.Resize(20, 0, 80, 20);
mAddressEditWidget.mLostFocusHandler.Add(new => OnAddressEditLostFocus);
mAddressEditWidget.mSubmitHandler.Add(new => OnAddressEditSubmit);
mAddressEditWidget.mCancelHandler.Add(new => OnAddressEditCancel);
mAddressEditWidget.mContentChangedHandler.Add(new => OnAddressEditContentChanged);
mWatchRefreshButton = new WatchRefreshButton();
mWatchRefreshButton.Resize(0, 0, 20, 20);
mWatchRefreshButton.mMouseDownHandler.Add(new (evt) => ToggleAutoExprRefresh());*/
mVarListView = new MemoryVarListView(this);
//mVarListView.Resize(mBinaryDataWidget.GetActiveWidth(), mVarListViewStartY, 200, 10);
//mVarListView.mIconX = 4;
//mVarListView.mOpenButtonX = 4;
//mVarListView.mLabelX = 26;
//mVarListView.mChildIndent = 16;
//mVarListView.mHiliteOffset = -2;
mVarListView.InitScrollbars(true, true);
mVarListView.mHorzScrollbar.mPageSize = 100;
mVarListView.mHorzScrollbar.mContentSize = 500;
mVarListView.mVertScrollbar.mPageSize = 100;
mVarListView.mVertScrollbar.mContentSize = 500;
mVarListView.UpdateScrollbars();
mVarListView.mOnMouseDown.Add(new (evt) => { mVarListView.GetRoot().SelectItem(null); mBinaryDataWidget.DeselectRange(); });
ListViewColumn column = mVarListView.AddColumn(GS!(200), "Name");
column.mMinWidth = 100;
column = mVarListView.AddColumn(80, "Pinned");
//column = mVarListView.AddColumn(200, "Type");
mVarListViewDockingProxy = new DockingProxy(mVarListView);
mVarListViewDockingProxy.SetRequestedSize(GS!(300), GS!(300));
mRepListView = new MemoryRepListView(this);
//mRepListView.Resize(mBinaryDataWidget.GetActiveWidth(), mVarListViewStartY, 200, 10);
//mVarListView.mIconX = 4;
//mVarListView.mOpenButtonX = 4;
//mVarListView.mLabelX = 26;
//mVarListView.mChildIndent = 16;
//mVarListView.mHiliteOffset = -2;
mRepListView.InitScrollbars(true, true);
mRepListView.mHorzScrollbar.mPageSize = 100;
mRepListView.mHorzScrollbar.mContentSize = 500;
mRepListView.mVertScrollbar.mPageSize = 100;
mRepListView.mVertScrollbar.mContentSize = 500;
mRepListView.UpdateScrollbars();
mRepListView.InitRows();
mRepListView.mOnMouseDown.Add(new (evt) => { mRepListView.GetRoot().SelectItem(null); });
column = mRepListView.AddColumn(GS!(80), "Type");
column.mMinWidth = GS!(25);
column = mRepListView.AddColumn(GS!(100), "Value");
column.mMinWidth = GS!(50);
column = mRepListView.AddColumn(GS!(100), "Value (Unsigned)");
column.mMinWidth = GS!(50);
mRepListViewDockingProxy = new DockingProxy(mRepListView);
mRepListViewDockingProxy.SetRequestedSize(GS!(300), GS!(300));
mDockingFrame = (DarkDockingFrame)ThemeFactory.mDefault.CreateDockingFrame();
mDockingFrame.mDrawBkg = false;
mDockingFrame.Resize(mBinaryDataWidget.GetActiveWidth() + GS!(200), mVarListViewStartY, GS!(200), GS!(10));
//mTabbedView = ThemeFactory.mDefault.CreateTabbedView();
//mTabbedView.SetRequestedSize(150, 150);
//AddWidget(mBinaryDataWidget);
//AddWidget(mAddressEditWidget);
//AddWidget(mWatchRefreshButton);
//AddWidget(mVarListView);
AddWidget(mDockingFrame);
//mDockingFrame.AddDockedWidget(mTabbedView, null, DockingFrame.WidgetAlign.Bottom, false);
mBinaryDataWidget.mIsFillWidget = true;
mDockingFrame.AddDockedWidget(mVarListViewDockingProxy, null, DockingFrame.WidgetAlign./*Left*/Top);
mDockingFrame.AddDockedWidget(mRepListViewDockingProxy, null, DockingFrame.WidgetAlign./*Left*/Top);
mDockingFrame.AddDockedWidget(mBinaryDataWidget, null, .Left);
//RebuildUI();
}
void ToggleAutoExprRefresh()
{
mAutoExprRefresh = !mAutoExprRefresh;
AddressExprUpdated();
//mAddressEditWidget.SetText(mAutoExprRefresh ? mLastAddressExpr : mLastAddressValue);
}
public override void Draw(Graphics g)
{
base.Draw(g);
/*if (mAutoExprRefresh)
{
using (g.PushColor(0x80FFFF00))
{
g.FillRect(mWatchRefreshButton.mX, mWatchRefreshButton.mY, mWatchRefreshButton.mWidth, mWatchRefreshButton.mHeight);
}
}*/
}
public void GotoAddress()
{
GoToAddressDialog aDialog = new GoToAddressDialog();
aDialog.Init(this);
aDialog.PopupWindow(mWidgetWindow);
}
static bool EvalRawIntegerExpression(String expr, out int position)
{
position = 0;
String parseStr = expr;
bool parsed = false;
if (parseStr.StartsWith("0x"))
{
//parseStr = scope String(parseStr, 2);
switch (UInt64.Parse(parseStr, NumberStyles.HexNumber, CultureInfo.CurrentCulture))
{
case .Ok(let value):
position = (.)value;
parsed = true;
case .Err:
}
}
else
{
//TODO: ThrowUnimplemented();
//parsed = ulong.TryParse(parseStr, out position);
}
return parsed;
}
public static bool EvalExpression(String expr, String result)
{
String evalResultStr = scope String();
IDEApp.sApp.mDebugger.Evaluate(expr, evalResultStr, -1, -1, DebugManager.EvalExpressionFlags.FullPrecision);
if (evalResultStr.StartsWith("!"))
{
// even if evaluation fails, we can still use a raw value
int position = 0;
if (EvalRawIntegerExpression(expr, out position))
{
result.Set(expr);
return true;
}
else
{
//CDH TODO indicate error somehow? maybe turn box red?
}
}
else
{
var lines = scope List<StringView>(evalResultStr.Split('\n'));
if (lines.Count > 0)
{
String valStr = scope String(lines[0]);
if (valStr.Contains(' '))
{
var tempSplit = scope List<StringView>(valStr.Split( ' '));
valStr.Set(tempSplit[0]);
}
result.Set(valStr);
return true;
}
}
return false;
}
void AddressExprUpdated()
{
int position = 0;
if (mAutoExprRefresh && (mLastAddressExpr.Length > 0))
{
String evalResultStr = scope String();
if (EvalExpression(mLastAddressExpr, evalResultStr))
mLastAddressValue.Set(evalResultStr);
}
if (EvalRawIntegerExpression(mLastAddressValue, out position))
{
mBinaryDataWidget.ResetPosition(position);
}
else
{
String evalResultStr = scope String();
if (EvalExpression(mLastAddressValue, evalResultStr))
mLastAddressValue.Set(evalResultStr);
if (EvalRawIntegerExpression(mLastAddressValue, out position))
mBinaryDataWidget.ResetPosition(position);
}
}
/*void OnAddressEditLostFocus(Widget widget)
{
}
void OnAddressEditSubmit(EditEvent theEvent)
{
if (mAutoExprRefresh)
{
mLastAddressExpr.Clear();
mAddressEditWidget.GetText(mLastAddressExpr);
}
else
{
mLastAddressValue.Clear();
mAddressEditWidget.GetText(mLastAddressValue);
}
AddressExprUpdated();
mAddressEditWidget.SetText(mAutoExprRefresh ? mLastAddressExpr : mLastAddressValue);
}
void OnAddressEditCancel(EditEvent theEvent)
{
AddressExprUpdated();
mAddressEditWidget.SetText(mAutoExprRefresh ? mLastAddressExpr : mLastAddressValue);
}
void OnAddressEditContentChanged(EditEvent theEvent)
{
}*/
void OnTrackedExpressionsUpdated(List<BinaryDataWidget.TrackedExpression> trackedExpressions)
{
mVarListView.VertScrollTo(0);
mVarListView.GetRoot().Clear();
//IDEApp.sApp.mDebugger.CheckCallStack();
mListViewItemToTrackedExprMap.Clear();
//var sortedExprs = trackedExpressions.OrderBy(te => te.mMemStart).ToList();
List<BinaryDataWidget.TrackedExpression> sortedExprs = scope .(trackedExpressions.GetEnumerator());
sortedExprs.Sort(scope (lhs, rhs) => lhs.mMemStart <=> rhs.mMemStart);
for (var te in sortedExprs)
{
if (te.mIsReg)
continue; // this list is just for variables for now (regs are their own thing)
if (!te.mIsVisible)
continue;
var listViewItem = mVarListView.GetRoot().CreateChildItem();
listViewItem.mOnMouseDown.Add(new (theEvent) => OnVarListValueClicked(theEvent, 0));
listViewItem.Label = te.mDisplayName;
listViewItem.IconImageColor = te.mDisplayColor;
listViewItem.IconImage = DarkTheme.sDarkTheme.GetImage(.UIBoneJoint);
var subItem = listViewItem.CreateSubItem(1);
subItem.Label = mBinaryDataWidget.mPinnedTrackedExprs.Contains(te.mDisplayName) ? "Yes" : "No";//stackSize.ToString() ;
subItem.mOnMouseDown.Add(new (theEvent) => OnVarListValueClicked(theEvent, 1));
//subItem.mMouseDownHandler += mMemoryPanel.ValueClicked;
//subItem = listViewItem.CreateSubItem(2);
//subItem.mLabel = "TBD";//"C++";
//subItem.mMouseDownHandler += mMemoryPanel.ValueClicked;
mListViewItemToTrackedExprMap[listViewItem] = te;
}
#unwarn
mVarListView.Resized();
mVarListView.UpdateListSize();
//mCallStackUpdateCnt = 0;
//for (int childIdx = 0; childIdx < mVarListView.GetRoot().GetChildCount(); childIdx++)
//{
//var checkListViewItem = mVarListView.GetRoot().GetChildAtIndex(childIdx);
//}
//mVarListView.GetRoot().SelectItemExclusively(listViewItem);
//SetFocus();
//listViewItem.Update();
//mMemoryViewDirty = false;
UpdateIcons();
}
public void OnBinaryDataKeyCursorUpdated()
{
mRepListView.UpdateRepStrings();
}
public void OnBinaryDataActiveWidthChanged()
{
//ResizeChildren();
}
public void OnVarListValueClicked(MouseEvent theEvent, int32 column)
{
ListViewItem clickedItem = (ListViewItem)theEvent.mSender;
ListViewItem item = (ListViewItem)clickedItem.GetSubItem(0);
mVarListView.GetRoot().SelectItemExclusively(item);
SetFocus();
var result = mListViewItemToTrackedExprMap.GetValue(item);
BinaryDataWidget.TrackedExpression te;
if (result case .Ok(out te))
{
mBinaryDataWidget.SelectRange(te.mCurValue, te.mSize);
if ((theEvent.mBtn == 0) && (theEvent.mBtnCount > 1))
{
if (column == 1)
{
ListViewItem subItem = (ListViewItem)clickedItem.GetSubItem(1);
String* entryPtr;
if (mBinaryDataWidget.mPinnedTrackedExprs.Add(te.mDisplayName, out entryPtr))
{
*entryPtr = new String(te.mDisplayName);
subItem.Label = "Yes";
}
else
{
String oldStr = *entryPtr;
mBinaryDataWidget.mPinnedTrackedExprs.Remove(te.mDisplayName);
delete oldStr;
subItem.Label = "No";
}
}
/*
for (int childIdx = 1; childIdx < mVarListView.GetRoot().GetChildCount(); childIdx++)
{
var checkListViewItem = mVarListView.GetRoot().GetChildAtIndex(childIdx);
//checkListViewItem.IconImage = null;
}
*/
//int selectedIdx = item.mVirtualIdx;
//IDEApp.sApp.ShowPCLocation(selectedIdx);
//IDEApp.sApp.mDebugger.mSelectedCallStackIdx = selectedIdx;
//IDEApp.sApp.mWatchPanel.MarkWatchesDirty();
}
}
UpdateIcons();
}
void UpdateIcons()
{
int itemCount = mVarListView.GetRoot().GetChildCount();
for (int callStackIdx = 0; callStackIdx < itemCount; callStackIdx++)
{
//var listViewItem = mVarListView.GetRoot().GetChildAtIndex(callStackIdx);
/*
if (callStackIdx == 0)
{
if (callStackIdx == IDEApp.sApp.mDebugger.mSelectedCallStackIdx)
listViewItem.IconImage = DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.LinePointer);
else if (IDEApp.sApp.mDebugger.GetRunState() == DebugManager.RunState.Breakpoint)
listViewItem.IconImage = DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.RedDot);
else
listViewItem.IconImage = null;
}
else if (callStackIdx == IDEApp.sApp.mDebugger.mSelectedCallStackIdx)
listViewItem.IconImage = DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.EditCircle);
*/
}
}
public override void Serialize(StructuredData data)
{
base.Serialize(data);
data.Add("Type", "MemoryPanel");
if (mBinaryDataWidget.mAutoResizeType == .Manual)
data.Add("Columns", mBinaryDataWidget.mBytesPerDisplayLine);
else
data.Add("AutoResize", mBinaryDataWidget.mAutoResizeType);
data.Add("RequestedWidth", mDockingFrame.mDockedWidgets[1].mRequestedWidth);
}
public override bool Deserialize(StructuredData data)
{
if (!base.Deserialize(data))
return false;
mBinaryDataWidget.mAutoResizeType = data.GetEnum<BinaryDataWidget.AutoResizeType>("AutoResize");
if (mBinaryDataWidget.mAutoResizeType == .Manual)
{
mBinaryDataWidget.mBytesPerDisplayLine = data.GetInt("Columns");
if (mBinaryDataWidget.mBytesPerDisplayLine == 0)
{
mBinaryDataWidget.mAutoResizeType = .Auto_Mul8;
mBinaryDataWidget.mBytesPerDisplayLine = 16;
}
}
float requestedSize = data.GetFloat("RequestedWidth");
if (requestedSize != 0)
mDockingFrame.mDockedWidgets[1].mRequestedWidth = requestedSize;
return true;
}
void ResizeChildren()
{
//var varListStartX = mBinaryDataWidget.GetActiveWidth() + GS!(20);
//mBinaryDataWidget.Resize(0, 0, varListStartX, mHeight);
//mDockingFrame.Resize(varListStartX, GS!(mVarListViewStartY), Math.Max(GS!(50), mWidth - varListStartX), mHeight - GS!(mVarListViewStartY));
mDockingFrame.Resize(0, 0, mWidth, mHeight);
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
ResizeChildren();
}
public void MarkViewDirty()
{
mListViewItemToTrackedExprMap.Clear();
mBinaryDataWidget.ClearData(true);
if (mAutoExprRefresh)
AddressExprUpdated();
mMemoryViewDirty = true;
}
public override void LostFocus()
{
base.LostFocus();
mVarListView.GetRoot().SelectItemExclusively(null);
}
public override void Update()
{
base.Update();
if (!IDEApp.sApp.mDebugger.mIsRunning)
{
mVarListView.GetRoot().Clear();
mBinaryDataWidget.ClearData(false);
mListViewItemToTrackedExprMap.Clear();
}
else if ((IDEApp.sApp.mExecutionPaused) && (mMemoryViewDirty) && (!mDisabled))
{
//mBinaryDataWidget.ClearData();
//mMemoryViewDirty = false;
/*
mVarListView.VertScrollTo(0);
mVarListView.GetRoot().Clear();
//IDEApp.sApp.mDebugger.CheckCallStack();
var listViewItem = (VirtualListViewItem)mVarListView.GetRoot().CreateChildItem();
listViewItem.mVirtualHeadItem = listViewItem;
listViewItem.mVirtualCount = 5;//IDEApp.sApp.mDebugger.GetCallStackCount();
mVarListView.PopulateVirtualItem(listViewItem);
mVarListView.Resized();
mVarListView.UpdateListSize();
//mCallStackUpdateCnt = 0;
//for (int childIdx = 0; childIdx < mVarListView.GetRoot().GetChildCount(); childIdx++)
//{
//var checkListViewItem = mVarListView.GetRoot().GetChildAtIndex(childIdx);
//}
//mVarListView.GetRoot().SelectItemExclusively(listViewItem);
//SetFocus();
listViewItem.Update();
mMemoryViewDirty = false;
UpdateIcons();
*/
}
else if (!mDisabled)
{
mBinaryDataWidget.ClearData(true);
/*
if ((mListView.GetRoot().GetChildCount() > 0) && (IDEApp.sApp.mUpdateBatchStart))
{
mCallStackUpdateCnt++;
var listViewItem = (VirtualListViewItem)mListView.GetRoot().GetChildAtIndex(0);
IDEApp.sApp.mDebugger.CheckCallStack();
listViewItem.mVirtualCount = IDEApp.sApp.mDebugger.GetCallStackCount();
if (mCallStackUpdateCnt <= 2)
UpdateIcons();
}
*/
}
else
{
mDisabledTicks++;
if (mDisabledTicks == 40)
{
mVarListView.GetRoot().Clear();
//mBinaryDataWidget.ClearData(false);
mBinaryDataWidget.ClearTrackedExprs(true);
mListViewItemToTrackedExprMap.Clear();
MarkDirty();
}
// This animates memory while we're paused
/*if ((mDisabledTicks >= 40) && (mDisabledTicks % 30 == 0))
{
mBinaryDataWidget.ClearData(false);
MarkDirty();
}*/
}
}
public void SetDisabled(bool disabled)
{
mDisabled = disabled;
mBinaryDataWidget.mMouseVisible = !disabled;
mBinaryDataWidget.mGotoButton.mDisabled = disabled;
mRepListView.mMouseVisible = !disabled;
if (disabled)
{
if (!gApp.mDebugger.mIsRunning)
mBinaryDataWidget.mCurPosition = 0;
mRepListView.GetRoot().SelectItem(null);
mRepListView.UpdateRepStrings();
}
//mMouseVisible = !disabled;
mDisabledTicks = 0;
}
public override void DrawAll(Graphics g)
{
base.DrawAll(g);
}
public override void MouseClicked(float x, float y, float origX, float origY, int32 btn)
{
base.MouseClicked(x, y, origX, origY, btn);
if (btn == 1) //
{
if (mBinaryDataWidget != null)
mBinaryDataWidget.ShowMenu(x, y);
}
}
}
}