mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-10 20:42:21 +02:00
3009 lines
105 KiB
Beef
3009 lines
105 KiB
Beef
using System;
|
|
using System.Collections;
|
|
using System.Diagnostics;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
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 enum WatchResultType
|
|
{
|
|
None = 0,
|
|
Value = 1,
|
|
Int = 2,
|
|
Float = 4,
|
|
MM128 = 8,
|
|
Object = 0x10,
|
|
Interface = 0x20,
|
|
Pointer = 0x40,
|
|
TypeClass = 0x80,
|
|
TypeValueType = 0x100,
|
|
Namespace = 0x200,
|
|
Text = 0x400,
|
|
RawText = 0x800
|
|
}
|
|
|
|
public class WatchEntry
|
|
{
|
|
public bool mIsDeleted;
|
|
public bool mIsAppendAlloc;
|
|
public bool mIsStackAlloc;
|
|
public WatchResultType mResultType;
|
|
public DebugManager.Language mLanguage = .NotSet;
|
|
|
|
public String mName ~ delete _;
|
|
public String mEvalStr ~ delete _;
|
|
public bool mCanEdit;
|
|
public String mEditInitialize ~ delete _;
|
|
public bool mHadValue;
|
|
public bool mHasValue;
|
|
public bool mIsNewExpression;
|
|
public bool mIsPending;
|
|
public int mMemoryBreakpointAddr;
|
|
public int32 mHadStepCount;
|
|
public String mReferenceId ~ delete _;
|
|
public String mResultTypeStr ~ delete _;
|
|
public String mAction ~ delete _;
|
|
public List<String> mWarnings ~ DeleteContainerAndItems!(_);
|
|
|
|
public int32 mSeriesFirstVersion = -1;
|
|
public int32 mSeriesVersion = -1;
|
|
|
|
public bool IsConstant
|
|
{
|
|
get
|
|
{
|
|
if (mEvalStr.IsEmpty)
|
|
return true;
|
|
if (mEvalStr[0].IsNumber)
|
|
return true;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public bool ParseCmd(List<StringView> cmd)
|
|
{
|
|
switch (scope String(cmd[0]))
|
|
{
|
|
case ":type":
|
|
switch (scope String(cmd[1]))
|
|
{
|
|
case "object":
|
|
mResultType |= WatchResultType.Object;
|
|
return true;
|
|
case "pointer":
|
|
mResultType |= WatchResultType.Pointer;
|
|
return true;
|
|
case "class":
|
|
mResultType |= WatchResultType.TypeClass;
|
|
return true;
|
|
case "valuetype":
|
|
mResultType |= WatchResultType.TypeValueType;
|
|
return true;
|
|
case "namespace":
|
|
mResultType |= WatchResultType.Namespace;
|
|
return true;
|
|
case "int":
|
|
mResultType |= WatchResultType.Int;
|
|
return true;
|
|
case "interface":
|
|
mResultType |= WatchResultType.Interface;
|
|
return true;
|
|
case "float":
|
|
mResultType |= WatchResultType.Float;
|
|
return true;
|
|
case "mm128":
|
|
mResultType |= WatchResultType.MM128;
|
|
return true;
|
|
}
|
|
break;
|
|
case ":appendAlloc":
|
|
mIsAppendAlloc = true;
|
|
return true;
|
|
case ":stack":
|
|
mIsStackAlloc = true;
|
|
return true;
|
|
case ":deleted":
|
|
mIsDeleted = true;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public interface IWatchOwner
|
|
{
|
|
WatchListView GetWatchListView();
|
|
void UpdateWatch(WatchListViewItem watchEntry);
|
|
void SetupListViewItem(WatchListViewItem listViewItem, String name, String evalStr);
|
|
}
|
|
|
|
public class WatchListView : IDEListView
|
|
{
|
|
public IWatchOwner mWatchOwner;
|
|
public static int32 sCurDynReferenceId;
|
|
|
|
public this(IWatchOwner IWatchOwner)
|
|
{
|
|
mWatchOwner = IWatchOwner;
|
|
}
|
|
|
|
protected override ListViewItem CreateListViewItem()
|
|
{
|
|
if (mWatchOwner == null) // For root node, mWatchOwner not set yet
|
|
return new IDEListViewItem();
|
|
|
|
WatchListViewItem anItem = new WatchListViewItem(mWatchOwner, this);
|
|
return anItem;
|
|
}
|
|
|
|
public override void MouseDown(float x, float y, int32 btn, int32 btnCount)
|
|
{
|
|
base.MouseDown(x, y, btn, btnCount);
|
|
if (var watchPanel = mParent as WatchPanel)
|
|
{
|
|
watchPanel.SetFocus();
|
|
}
|
|
}
|
|
}
|
|
|
|
public class ExpressionEditWidgetContent : SourceEditWidgetContent
|
|
{
|
|
public this()
|
|
{
|
|
SetFont(DarkTheme.sDarkTheme.mSmallFont, false, false);
|
|
mTextInsets.Set(GS!(-1), GS!(2), 0, GS!(2));
|
|
}
|
|
|
|
public override void Draw(Graphics g)
|
|
{
|
|
base.Draw(g);
|
|
|
|
ExpressionEditWidget watchEditWidget = (ExpressionEditWidget)mEditWidget;
|
|
|
|
if (watchEditWidget.mErrorEnd != 0)
|
|
{
|
|
var text = scope String();
|
|
watchEditWidget.GetText(text);
|
|
if (watchEditWidget.mErrorStart < text.Length)
|
|
{
|
|
float indent = mTextInsets.mLeft;
|
|
float strStarts = indent + g.mFont.GetWidth(scope String(text, 0, watchEditWidget.mErrorStart));
|
|
float strEnds = indent + g.mFont.GetWidth(scope String(text, 0, Math.Min(watchEditWidget.mErrorEnd, text.Length)));
|
|
using (g.PushColor(0xFFFF4040))
|
|
IDEApp.sApp.DrawSquiggle(g, strStarts, GS!(2), strEnds - strStarts);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override float GetLineHeight(int line)
|
|
{
|
|
return GS!(21);
|
|
}
|
|
}
|
|
|
|
public class ExpressionEditWidget : DarkEditWidget
|
|
{
|
|
public int32 mErrorStart;
|
|
public int32 mErrorEnd;
|
|
int32 mLastTextVersionId;
|
|
public bool mIsAddress;
|
|
public bool mIsSymbol;
|
|
public int mEvalAtAddress;
|
|
public DebugManager.Language mLanguage;
|
|
public String mExprPre ~ delete _;
|
|
public String mExprPost ~ delete _;
|
|
public String mLastError ~ delete _;
|
|
public bool mIgnoreErrors;
|
|
public String mExpectingType;
|
|
//public AutoComplete mAutoComplete;
|
|
|
|
public this()
|
|
: base(new ExpressionEditWidgetContent())
|
|
{
|
|
var editWidgetContent = (ExpressionEditWidgetContent)mEditWidgetContent;
|
|
editWidgetContent.mOnGenerateAutocomplete = new (keyChar, options) =>
|
|
{
|
|
if ((editWidgetContent.mAutoComplete?.mIsDocumentationPass).GetValueOrDefault())
|
|
return;
|
|
UpdateText(keyChar, true);
|
|
};
|
|
editWidgetContent.mScrollToStartOnLostFocus = true;
|
|
mScrollContentInsets.Set(GS!(4), GS!(3), GS!(1), GS!(3));
|
|
|
|
mOnKeyDown.Add(new => EditKeyDownHandler);
|
|
}
|
|
|
|
public override void Resize(float x, float y, float width, float height)
|
|
{
|
|
base.Resize(x, y, width, height);
|
|
if (height <= GS!(24))
|
|
mScrollContentInsets.Set(GS!(2), GS!(3), GS!(1), GS!(3));
|
|
else
|
|
mScrollContentInsets.Set(GS!(4), GS!(3), GS!(1), GS!(3));
|
|
}
|
|
|
|
void EditKeyDownHandler(KeyDownEvent evt)
|
|
{
|
|
if (evt.mKeyCode == .Escape)
|
|
{
|
|
var editWidgetContent = (ExpressionEditWidgetContent)mEditWidgetContent;
|
|
if (editWidgetContent.mAutoComplete != null)
|
|
{
|
|
editWidgetContent.mAutoComplete.Close();
|
|
evt.mHandled = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ResizeAround(float targetX, float targetY, float width)
|
|
{
|
|
Resize(targetX - GS!(1), targetY - GS!(1), width + GS!(2), GS!(23));
|
|
}
|
|
|
|
public override void LostFocus()
|
|
{
|
|
base.LostFocus();
|
|
//var sourceEditWidgetContent = (SourceEditWidgetContent)mEditWidgetContent;
|
|
//TODO: This was causing autocomplete to close when you clicked on the scroll thumb. Why did we need this?
|
|
//if (sourceEditWidgetContent.mAutoComplete != null)
|
|
//sourceEditWidgetContent.mAutoComplete.Close();
|
|
}
|
|
|
|
public override void KeyDown(KeyCode keyCode, bool isRepeat)
|
|
{
|
|
/*if ((keyCode == KeyCode.Escape) && (mAutoComplete != null))
|
|
{
|
|
mAutoComplete.Close();
|
|
return;
|
|
}*/
|
|
|
|
base.KeyDown(keyCode, isRepeat);
|
|
}
|
|
|
|
public virtual EditSelection GetCurExprRange()
|
|
{
|
|
return EditSelection(0, Content.mData.mTextLength);
|
|
}
|
|
|
|
public virtual void SetAutoCompleteInfo(String autoCompleteInfo, int textOffset)
|
|
{
|
|
var editWidgetContent = (ExpressionEditWidgetContent)mEditWidgetContent;
|
|
editWidgetContent.mAutoComplete.SetInfo(autoCompleteInfo, true, (.)textOffset);
|
|
}
|
|
|
|
public AutoComplete GetAutoComplete()
|
|
{
|
|
var editWidgetContent = (ExpressionEditWidgetContent)mEditWidgetContent;
|
|
if (editWidgetContent.mAutoComplete == null)
|
|
{
|
|
editWidgetContent.mAutoComplete = new AutoComplete(this);
|
|
editWidgetContent.mAutoComplete.mOnAutoCompleteInserted.Add(new () => UpdateText(0, true));
|
|
editWidgetContent.mAutoComplete.mOnClosed.Add(new () => { editWidgetContent.mAutoComplete = null; });
|
|
}
|
|
return editWidgetContent.mAutoComplete;
|
|
}
|
|
|
|
public bool IsShowingAutoComplete()
|
|
{
|
|
let autoComplete = GetAutoComplete();
|
|
if (autoComplete == null)
|
|
return false;
|
|
return autoComplete.IsShowing();
|
|
}
|
|
|
|
public virtual void UpdateText(char32 keyChar, bool doAutoComplete)
|
|
{
|
|
scope AutoBeefPerf("ExpressionEditWidget.UpdateText");
|
|
|
|
if ((keyChar == 0) && (doAutoComplete))
|
|
return; // Is documentation pass
|
|
|
|
DeleteAndNullify!(mLastError);
|
|
|
|
var editWidgetContent = (ExpressionEditWidgetContent)mEditWidgetContent;
|
|
|
|
let exprRange = GetCurExprRange();
|
|
if (exprRange.Length == 0)
|
|
{
|
|
if (editWidgetContent.mAutoComplete != null)
|
|
editWidgetContent.mAutoComplete.Close();
|
|
mErrorStart = 0;
|
|
mErrorEnd = 0;
|
|
return;
|
|
}
|
|
|
|
String text = scope String();
|
|
|
|
int32 cursorOfs = 0;
|
|
if (mExprPre != null)
|
|
{
|
|
text.Append(mExprPre);
|
|
cursorOfs = (.)mExprPre.Length;
|
|
}
|
|
editWidgetContent.ExtractString(exprRange.MinPos, exprRange.Length, text);
|
|
if (mExprPost != null)
|
|
text.Append(mExprPost);
|
|
|
|
String val = scope String();
|
|
if (mEvalAtAddress != (int)0)
|
|
IDEApp.sApp.mDebugger.EvaluateAtAddress(text, mEvalAtAddress, val, mEditWidgetContent.CursorTextPos - 1 - exprRange.mStartPos + cursorOfs);
|
|
else if (mIsAddress)
|
|
{
|
|
gApp.mDebugger.Evaluate(text, val, mEditWidgetContent.CursorTextPos - 1 - exprRange.mStartPos + cursorOfs, -1, .MemoryWatch);
|
|
}
|
|
else if (mIsSymbol)
|
|
{
|
|
gApp.mDebugger.Evaluate(text, val, mEditWidgetContent.CursorTextPos - 1 - exprRange.mStartPos + cursorOfs, -1, .Symbol);
|
|
}
|
|
else
|
|
gApp.DebugEvaluate(mExpectingType, text, val, mEditWidgetContent.CursorTextPos - 1 - exprRange.mStartPos + cursorOfs);
|
|
|
|
var vals = scope List<StringView>(val.Split('\n'));
|
|
|
|
if (doAutoComplete)
|
|
{
|
|
int32 idx = (int32)val.IndexOf(":autocomplete\n");
|
|
if (idx != -1)
|
|
{
|
|
GetAutoComplete();
|
|
var autoCompleteInfo = scope String(256);
|
|
autoCompleteInfo.Append(val, idx + ":autocomplete\n".Length);
|
|
SetAutoCompleteInfo(autoCompleteInfo, exprRange.mStartPos - cursorOfs);
|
|
}
|
|
else if (editWidgetContent.mAutoComplete != null)
|
|
editWidgetContent.mAutoComplete.Close();
|
|
}
|
|
|
|
mErrorStart = 0;
|
|
mErrorEnd = 0;
|
|
String result = scope String(vals[0]);
|
|
if ((result.StartsWith("!", StringComparison.Ordinal)) && (!mIgnoreErrors))
|
|
{
|
|
result.Remove(0, 1);
|
|
var errorVals = scope List<StringView>(result.Split('\t'));
|
|
if (errorVals.Count > 1)
|
|
{
|
|
mErrorStart = int32.Parse(scope String(errorVals[0])).Get() + exprRange.mStartPos - cursorOfs;
|
|
mErrorEnd = mErrorStart + int32.Parse(scope String(errorVals[1])).Get();
|
|
mLastError = new String(errorVals[2]);
|
|
|
|
if ((mErrorEnd > 0) && (mErrorStart < text.Length) && (mErrorEnd <= text.Length))
|
|
mLastError.Append(": ", scope String(text, mErrorStart, mErrorEnd - mErrorStart));
|
|
}
|
|
else
|
|
{
|
|
mLastError = new String(errorVals[0]);
|
|
}
|
|
}
|
|
|
|
mLastTextVersionId = mEditWidgetContent.mData.mCurTextVersionId;
|
|
}
|
|
|
|
public override void RemovedFromParent(Widget previousParent, WidgetWindow previousWidgetWindow)
|
|
{
|
|
base.RemovedFromParent(previousParent, previousWidgetWindow);
|
|
|
|
var editWidgetContent = (ExpressionEditWidgetContent)mEditWidgetContent;
|
|
if (editWidgetContent.mAutoComplete != null)
|
|
editWidgetContent.mAutoComplete.Close();
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
base.Update();
|
|
|
|
if (mLastTextVersionId != mEditWidgetContent.mData.mCurTextVersionId)
|
|
{
|
|
mLastTextVersionId = mEditWidgetContent.mData.mCurTextVersionId;
|
|
UpdateText(0, false);
|
|
}
|
|
}
|
|
|
|
public override void DrawAll(Graphics g)
|
|
{
|
|
base.DrawAll(g);
|
|
if (Content.mIsReadOnly)
|
|
{
|
|
using (g.PushColor(0x60404040))
|
|
g.FillRect(0, 0, mWidth, mHeight);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*class RefCounted
|
|
{
|
|
int32 mRefCount = 1;
|
|
|
|
public this()
|
|
{
|
|
//Debug.WriteLine("RefCount (this) {0} {1}", this, mRefCount);
|
|
}
|
|
|
|
public ~this()
|
|
{
|
|
//Debug.WriteLine("RefCount (~this) {0} {1}", this, mRefCount);
|
|
Debug.Assert(mRefCount == 0);
|
|
}
|
|
|
|
public void AddRef()
|
|
{
|
|
mRefCount++;
|
|
//Debug.WriteLine("RefCount (AddRef) {0} {1}", this, mRefCount);
|
|
}
|
|
|
|
public void Release()
|
|
{
|
|
//Debug.WriteLine("RefCount (Release) {0} {1}", this, mRefCount - 1);
|
|
if (--mRefCount == 0)
|
|
delete this;
|
|
}
|
|
}*/
|
|
|
|
public class WatchSeriesInfo : RefCounted
|
|
{
|
|
public String mDisplayTemplate ~ delete _;
|
|
public String mEvalTemplate ~ delete _;
|
|
public int32 mStartMemberIdx;
|
|
public int mStartIdx;
|
|
public int mCount;
|
|
public int mCurCount; // When counting up unsized series
|
|
public int32 mShowPages;
|
|
public int32 mShowPageSize;
|
|
public String mAddrs ~ delete _;
|
|
public int32 mAddrsEntrySize;
|
|
public String mContinuationData ~ delete _;
|
|
public DarkButton mMoreButton;
|
|
public DarkButton mLessButton;
|
|
public static int32 sIdx;
|
|
public int32 mSeriesVersion = ++sIdx;
|
|
public int32 mSeriesFirstVersion = mSeriesVersion;
|
|
}
|
|
|
|
public class WatchRefreshButton : ButtonWidget
|
|
{
|
|
public override void Draw(Graphics g)
|
|
{
|
|
base.Draw(g);
|
|
g.Draw(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.RefreshArrows));
|
|
}
|
|
}
|
|
|
|
public class ActionButton : ButtonWidget
|
|
{
|
|
public override void Draw(Graphics g)
|
|
{
|
|
base.Draw(g);
|
|
if (mX < mParent.mWidth - GS!(10))
|
|
g.Draw(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.GotoButton));
|
|
}
|
|
}
|
|
|
|
public class WatchStringEditWidgetContent : DarkEditWidgetContent
|
|
{
|
|
public WatchStringEdit mWatchStringEdit;
|
|
|
|
public this()
|
|
{
|
|
mHiliteColor = 0xFF384858;
|
|
mUnfocusedHiliteColor = 0x80384858;
|
|
}
|
|
|
|
public override bool AllowChar(char32 theChar)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public override void KeyDown(KeyCode keyCode, bool isRepeat)
|
|
{
|
|
base.KeyDown(keyCode, isRepeat);
|
|
if (keyCode == KeyCode.Escape)
|
|
DarkTooltipManager.CloseTooltip();
|
|
}
|
|
|
|
public override void RecalcSize()
|
|
{
|
|
base.RecalcSize();
|
|
if (mWatchStringEdit.mMoreButton != null)
|
|
mHeight += GS!(32);
|
|
}
|
|
|
|
public override void CursorToEnd()
|
|
{
|
|
base.CursorToEnd();
|
|
|
|
if (mWatchStringEdit.mMoreButton != null)
|
|
{
|
|
mEditWidget.VertScrollTo(mEditWidget.mVertPos.mDest + GS!(32));
|
|
mEditWidget.HorzScrollTo(0);
|
|
}
|
|
}
|
|
|
|
public override uint32 GetSelectionColor(uint8 flags)
|
|
{
|
|
bool hasFocus = mEditWidget.mHasFocus;
|
|
if ((mWatchStringEdit != null) && (mWatchStringEdit.mQuickFind != null))
|
|
hasFocus |= mWatchStringEdit.mQuickFind.mFindEditWidget.mHasFocus;
|
|
|
|
if ((flags & (uint8)SourceElementFlags.Find_Matches) != 0)
|
|
{
|
|
return 0x50FFE0B0;
|
|
}
|
|
|
|
return hasFocus ? mHiliteColor : mUnfocusedHiliteColor;
|
|
}
|
|
|
|
public override void DrawSectionFlagsOver(Graphics g, float x, float y, float width, uint8 flags)
|
|
{
|
|
if ((flags & (uint8)SourceElementFlags.Find_Matches) != 0)
|
|
{
|
|
using (g.PushColor(0x34FFE0B0))
|
|
g.FillRect(x, y, width, mFont.GetLineSpacing());
|
|
|
|
DrawSectionFlagsOver(g, x, y, width, (uint8)(flags & ~(uint8)SourceElementFlags.Find_Matches));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class WatchStringEditWidget : DarkEditWidget
|
|
{
|
|
public this(WatchStringEditWidgetContent content) : base(content)
|
|
{
|
|
|
|
}
|
|
|
|
public override void DrawAll(Graphics g)
|
|
{
|
|
using (g.PushColor(0xD0FFFFFF))
|
|
base.DrawAll(g);
|
|
}
|
|
}
|
|
|
|
public class WatchStringEdit : Widget
|
|
{
|
|
public const int cWordWrapMax = 512*1024;
|
|
public const int cMoreBlockSize = 1024*1024;
|
|
|
|
public WatchStringEditWidget mEditWidget;
|
|
public String mEvalString = new String() ~ delete _;
|
|
public String mOrigContent ~ delete _;
|
|
public int mMaxShowSize = cMoreBlockSize;
|
|
public DarkButton mMoreButton;
|
|
public QuickFind mQuickFind;
|
|
public DarkTabbedView.DarkTabMenuButton mMenuButton;
|
|
public bool mViewWhiteSpace;
|
|
|
|
public this(String text, String evalStr)
|
|
{
|
|
scope AutoBeefPerf("WatchStringEdit.this");
|
|
|
|
let editWidgetContent = new WatchStringEditWidgetContent();
|
|
editWidgetContent.mWatchStringEdit = this;
|
|
|
|
mEditWidget = new WatchStringEditWidget(editWidgetContent);
|
|
mEditWidget.Content.mIsMultiline = true;
|
|
mEditWidget.Content.mIsReadOnly = true;
|
|
mEditWidget.Content.mWordWrap = text.Length < cWordWrapMax;
|
|
mEditWidget.Content.mAllowMaximalScroll = false;
|
|
|
|
bool needsStrCleaning = false;
|
|
|
|
for (let c in text.RawChars)
|
|
if (c <= '\x02')
|
|
needsStrCleaning = true;
|
|
if (needsStrCleaning)
|
|
{
|
|
mOrigContent = new String(text);
|
|
String cleanedStr = scope String()..Append(text);
|
|
for (let c in cleanedStr.RawChars)
|
|
{
|
|
if (c <= '\x02')
|
|
@c.Current = '\x03';
|
|
}
|
|
mEditWidget.SetText(cleanedStr);
|
|
}
|
|
else
|
|
mEditWidget.SetText(text);
|
|
|
|
AddWidget(mEditWidget);
|
|
|
|
if (text.Length >= mMaxShowSize)
|
|
{
|
|
ShowMoreButton();
|
|
}
|
|
|
|
if (evalStr != null)
|
|
mEvalString.Set(evalStr);
|
|
|
|
mMenuButton = new DarkTabbedView.DarkTabMenuButton();
|
|
AddWidget(mMenuButton);
|
|
|
|
mMenuButton.mOnMouseDown.Add(new (evt) =>
|
|
{
|
|
float x = mMenuButton.mX + GS!(14);
|
|
float y = mMenuButton.mY + GS!(6);
|
|
|
|
Menu menu = new Menu();
|
|
var menuItem = menu.AddItem("Show Whitespace");
|
|
if (mViewWhiteSpace)
|
|
menuItem.mIconImage = DarkTheme.sDarkTheme.GetImage(.Check);
|
|
menuItem.mOnMenuItemSelected.Add(new (menu) =>
|
|
{
|
|
mViewWhiteSpace = !mViewWhiteSpace;
|
|
var darkEditWidgetContent = (DarkEditWidgetContent)mEditWidget.Content;
|
|
darkEditWidgetContent.mViewWhiteSpaceColor = mViewWhiteSpace ? SourceEditWidgetContent.sTextColors[(int)SourceElementType.VisibleWhiteSpace] : 0;
|
|
});
|
|
|
|
MenuWidget menuWidget = DarkTheme.sDarkTheme.CreateMenuWidget(menu);
|
|
menuWidget.Init(this, x, y, .AllowScrollable);
|
|
|
|
menu.mOnMenuClosed.Add(new (menu, itemSelected) =>
|
|
{
|
|
if (DarkTooltipManager.sTooltip != null)
|
|
DarkTooltipManager.sTooltip.mAutoCloseDelay = 90;
|
|
});
|
|
//menuWidget.mWidgetWindow.mOnWindowClosed.Add(new => MenuClosed);
|
|
});
|
|
}
|
|
|
|
public void ShowQuickFind(bool isReplace)
|
|
{
|
|
if (mQuickFind != null)
|
|
{
|
|
mQuickFind.Close();
|
|
delete mQuickFind;
|
|
}
|
|
mQuickFind = new QuickFind(this, mEditWidget, isReplace);
|
|
mWidgetWindow.SetFocus(mQuickFind.mFindEditWidget);
|
|
RehupSize();
|
|
}
|
|
|
|
public void FindNext(int32 dir)
|
|
{
|
|
if (mQuickFind == null)
|
|
return;
|
|
mQuickFind.FindNext(dir, false);
|
|
}
|
|
|
|
void ShowMore()
|
|
{
|
|
mMoreButton.RemoveSelf();
|
|
gApp.DeferDelete(mMoreButton);
|
|
mMoreButton = null;
|
|
|
|
mMaxShowSize *= 2;
|
|
|
|
String str = scope String();
|
|
String evalStr = scope:: String();
|
|
evalStr.AppendF("{0}, rawStr, maxcount={1}", mEvalString, mMaxShowSize);
|
|
// We purposely don't add mResultTypeStr here because the parse fails on std::basic_string and we know this will never be needed for an short enum name anyway
|
|
gApp.DebugEvaluate(null, evalStr, str);
|
|
|
|
mEditWidget.SetText(str);
|
|
|
|
if (str.Length >= mMaxShowSize)
|
|
{
|
|
ShowMoreButton();
|
|
mEditWidget.Content.RecalcSize();
|
|
}
|
|
}
|
|
|
|
void ShowMoreButton()
|
|
{
|
|
let editWidgetContent = (WatchStringEditWidgetContent)mEditWidget.Content;
|
|
var contentHeight = mEditWidget.Content.GetLineCount() * editWidgetContent.mFont.GetLineSpacing();
|
|
mMoreButton = (DarkButton)DarkTheme.sDarkTheme.CreateButton(editWidgetContent, "More", mX + GS!(4), contentHeight + GS!(4), GS!(68), GS!(20));
|
|
mMoreButton.mOnMouseClick.Add(new (evt) =>
|
|
{
|
|
ShowMore();
|
|
});
|
|
}
|
|
|
|
public override void DrawAll(Graphics g)
|
|
{
|
|
g.SetFont(DarkTheme.sDarkTheme.mSmallFont);
|
|
var editWidgetContent = mEditWidget.Content;
|
|
int cursorTextPos = mEditWidget.Content.CursorTextPos;
|
|
|
|
int line;
|
|
int lineChar;
|
|
mEditWidget.Content.GetLineCharAtIdx(mEditWidget.Content.CursorTextPos, out line, out lineChar);
|
|
var textY = mHeight - GS!(16);
|
|
|
|
String textPosString = scope String();
|
|
if (mEditWidget.Content.HasSelection())
|
|
{
|
|
var selection = mEditWidget.Content.mSelection;
|
|
textPosString.AppendF("Start {0} Len {1}", selection.Value.MinPos, selection.Value.MaxPos - selection.Value.MinPos);
|
|
}
|
|
else
|
|
{
|
|
textPosString.AppendF("Index {0}", cursorTextPos);
|
|
}
|
|
|
|
int lineStart;
|
|
int lineEnd;
|
|
editWidgetContent.GetLinePosition(line, out lineStart, out lineEnd);
|
|
|
|
int col = 0;
|
|
int checkTextPos = lineStart;
|
|
while (checkTextPos < cursorTextPos)
|
|
{
|
|
let c32 = editWidgetContent.mData.GetChar32(ref checkTextPos);
|
|
if (!c32.IsCombiningMark)
|
|
col++;
|
|
}
|
|
|
|
String charStr = null;
|
|
checkTextPos = cursorTextPos;
|
|
while (true)
|
|
{
|
|
bool isFirst = checkTextPos == cursorTextPos;
|
|
char32 c32;
|
|
int encodeLen;
|
|
if (mOrigContent != null)
|
|
{
|
|
if (checkTextPos >= mOrigContent.Length)
|
|
break;
|
|
(c32, encodeLen) = mOrigContent.GetChar32(checkTextPos);
|
|
}
|
|
else
|
|
{
|
|
if (checkTextPos >= editWidgetContent.mData.mTextLength)
|
|
break;
|
|
(c32, encodeLen) = editWidgetContent.GetChar32(checkTextPos);
|
|
}
|
|
if ((c32 == 0) || ((!c32.IsCombiningMark) && (!isFirst)))
|
|
break;
|
|
|
|
if (charStr == null)
|
|
charStr = scope:: String(" ");
|
|
|
|
if (encodeLen > 1)
|
|
{
|
|
charStr.AppendF("\\u{{{0:X}}} ", (int64)c32);
|
|
}
|
|
|
|
for (int ofs < encodeLen)
|
|
{
|
|
if (mOrigContent != null)
|
|
charStr.AppendF("\\x{0:X2}", (uint8)mOrigContent[checkTextPos + ofs]);
|
|
else
|
|
charStr.AppendF("\\x{0:X2}", (int64)editWidgetContent.mData.mText[checkTextPos + ofs].mChar);
|
|
}
|
|
|
|
checkTextPos += encodeLen;
|
|
}
|
|
if (charStr != null)
|
|
{
|
|
textPosString.Append(charStr);
|
|
}
|
|
|
|
g.DrawString(textPosString, 16, textY, .Left, mWidth - GS!(140), .Ellipsis);
|
|
g.DrawString(StackStringFormat!("Ln {0}", line + 1), mWidth - GS!(130), textY);
|
|
g.DrawString(StackStringFormat!("Col {0}", col + 1), mWidth - GS!(70), textY);
|
|
|
|
//using (g.PushColor(0xD0FFFFFF))
|
|
base.DrawAll(g);
|
|
}
|
|
|
|
public override void Resize(float x, float y, float width, float height)
|
|
{
|
|
base.Resize(x, y, width, height);
|
|
|
|
mEditWidget.Resize(0, 0, width, height - GS!(16));
|
|
if (mQuickFind != null)
|
|
mQuickFind.ResizeSelf();
|
|
|
|
mMenuButton.Resize(width - GS!(26), height - GS!(12), GS!(16), GS!(16));
|
|
}
|
|
|
|
public float GetWantHeight(float wantWidth)
|
|
{
|
|
mEditWidget.Resize(0, 0, wantWidth, mEditWidget.mHeight);
|
|
mEditWidget.Content.RecalcSize();
|
|
return mEditWidget.mScrollContent.mHeight + mEditWidget.mScrollContentInsets.mTop + mEditWidget.mScrollContentInsets.mBottom + GS!(20);
|
|
}
|
|
|
|
public bool Close()
|
|
{
|
|
if (mQuickFind != null)
|
|
{
|
|
mQuickFind.Close();
|
|
DeleteAndNullify!(mQuickFind);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
protected override void RemovedFromWindow()
|
|
{
|
|
base.RemovedFromWindow();
|
|
}
|
|
}
|
|
|
|
public class WatchListViewItem : IDEListViewItem
|
|
{
|
|
public IWatchOwner mWatchOwner;
|
|
public WatchEntry mWatchEntry ~ delete _;
|
|
public bool mFailed;
|
|
public int32 mErrorStart;
|
|
public int32 mErrorEnd;
|
|
|
|
public WatchSeriesInfo mWatchSeriesInfo;
|
|
//public bool mOwnsWatchSeriesInfo;
|
|
public int32 mSeriesMemberIdx;
|
|
|
|
public WatchListViewItem mPrevPlaceholder;
|
|
public int32 mPlaceholderStartIdx;
|
|
public bool mIsPlaceholder;
|
|
public bool mDisabled = false;
|
|
public bool mAllowRefresh = false;
|
|
public bool mValueChanged = false;
|
|
bool mWantRemoveSelf;
|
|
|
|
public WatchRefreshButton mWatchRefreshButton;
|
|
public ActionButton mActionButton;
|
|
public String mTextAction ~ delete _;
|
|
public bool mMustUpdateBeforeEvaluate;
|
|
|
|
public override bool Selected
|
|
{
|
|
get
|
|
{
|
|
return base.Selected;
|
|
}
|
|
|
|
set
|
|
{
|
|
/*if (value)
|
|
mParent.UpdateAll();*/
|
|
base.Selected = value;
|
|
}
|
|
}
|
|
|
|
public bool Failed
|
|
{
|
|
get
|
|
{
|
|
return ((WatchListViewItem)GetSubItem(1)).mFailed;
|
|
}
|
|
}
|
|
|
|
public this(IWatchOwner watchOwner, IDEListView listView)
|
|
{
|
|
mWatchOwner = watchOwner;
|
|
}
|
|
|
|
public ~this()
|
|
{
|
|
if (mWatchSeriesInfo != null)
|
|
{
|
|
mWatchSeriesInfo.ReleaseRef();
|
|
}
|
|
}
|
|
|
|
public virtual WatchListViewItem GetWatchListViewItemParent()
|
|
{
|
|
return mParentItem as WatchListViewItem;
|
|
}
|
|
|
|
protected bool WatchIsString()
|
|
{
|
|
var mainWatchListViewItem = (WatchListViewItem)GetSubItem(0);
|
|
if ((mainWatchListViewItem.mWatchEntry.mResultType == WatchResultType.TypeClass) || (mainWatchListViewItem.mWatchEntry.mResultType == WatchResultType.TypeValueType))
|
|
return false;
|
|
String resultTypeStr = mainWatchListViewItem.mWatchEntry.mResultTypeStr;
|
|
return (resultTypeStr == "System.String") ||
|
|
(resultTypeStr == "std::string") ||
|
|
(resultTypeStr == "char8*") ||
|
|
(resultTypeStr == "const char8*");
|
|
}
|
|
|
|
public override bool WantsTooltip(float mouseX, float mouseY)
|
|
{
|
|
if (mColumnIdx == 1)
|
|
{
|
|
//if (WatchIsString())
|
|
return true;
|
|
}
|
|
|
|
return base.WantsTooltip(mouseX, mouseY);
|
|
}
|
|
|
|
public override void ShowTooltip(float mouseX, float mouseY)
|
|
{
|
|
scope AutoBeefPerf("WatchPanel.ShowTooltip");
|
|
|
|
if (mColumnIdx != 1)
|
|
{
|
|
base.ShowTooltip(mouseX, mouseY);
|
|
return;
|
|
}
|
|
|
|
var mainWatchListViewItem = (WatchListViewItem)GetSubItem(0);
|
|
|
|
String evalStr = null;
|
|
String str = scope String();
|
|
if (mColumnIdx == 1)
|
|
{
|
|
evalStr = scope:: String();
|
|
evalStr.AppendF("{0}, rawStr, maxcount={1}", mainWatchListViewItem.mWatchEntry.mEvalStr, WatchStringEdit.cMoreBlockSize);
|
|
// We purposely don't add mResultTypeStr here because the parse fails on std::basic_string and we know this will never be needed for an short enum name anyway
|
|
gApp.DebugEvaluate(null, evalStr, str);
|
|
if ((str.Length == 0) || (str.StartsWith("!")))
|
|
{
|
|
if (!base.WantsTooltip(mouseX, mouseY))
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (str.Length > 0)
|
|
{
|
|
if (DarkTooltipManager.IsTooltipShown(this))
|
|
return;
|
|
|
|
//Profiler.StartSampling();
|
|
|
|
float x = 8;
|
|
if (mColumnIdx == 0)
|
|
x = LabelX + GS!(8);
|
|
|
|
//string str = "This is a really long string, I want to see if we can do a scrollable mouseover view of this string. We can even see if we can\nembed\r\nsome lines...";
|
|
//str = "Hey\nDef\nEfg\nzzap";
|
|
|
|
|
|
if (str.Length == 0)
|
|
return;
|
|
|
|
float parentX;
|
|
float parentY;
|
|
SelfToOtherTranslate(mListView.mScrollContentContainer, x, 0, out parentX, out parentY);
|
|
float wantWidth = Math.Max(GS!(320), mListView.mScrollContentContainer.mWidth - parentX - GS!(8));
|
|
|
|
var watchStringEdit = new WatchStringEdit(str, evalStr);
|
|
let ewc = watchStringEdit.mEditWidget.Content;
|
|
|
|
float wantHeight = watchStringEdit.GetWantHeight(wantWidth - GS!(6) * 2);
|
|
|
|
float maxHeight = GS!(78);
|
|
if (!ewc.mWordWrap)
|
|
maxHeight += GS!(20);
|
|
if (wantHeight > maxHeight + 0.5f)
|
|
{
|
|
watchStringEdit.mEditWidget.InitScrollbars(!ewc.mWordWrap, true);
|
|
wantHeight = maxHeight;
|
|
}
|
|
|
|
wantHeight += GS!(6) * 2;
|
|
var tooltip = DarkTooltipManager.ShowTooltip("", this, x, mSelfHeight + mBottomPadding, wantWidth, wantHeight, true, true);
|
|
if (tooltip != null)
|
|
{
|
|
tooltip.mRelWidgetMouseInsets = new Insets(0, 0, GS!(-8), 0);
|
|
tooltip.mAllowMouseInsideSelf = true;
|
|
tooltip.AddWidget(watchStringEdit);
|
|
tooltip.mOnResized.Add(new (widget) => watchStringEdit.Resize(GS!(6), GS!(6), widget.mWidth - GS!(6) * 2, widget.mHeight - GS!(6) * 2));
|
|
tooltip.mOnResized(tooltip);
|
|
tooltip.mWidgetWindow.mOnWindowKeyDown.Add(new => gApp.[Friend]SysKeyDown);
|
|
tooltip.mOnKeyDown.Add(new (evt) =>
|
|
{
|
|
if ((evt.mKeyCode == .Escape) && (!watchStringEdit.Close()))
|
|
evt.mHandled = true;
|
|
});
|
|
}
|
|
|
|
//Profiler.StopSampling();
|
|
|
|
return;
|
|
}
|
|
|
|
base.ShowTooltip(mouseX, mouseY);
|
|
}
|
|
|
|
public void AddRefreshButton()
|
|
{
|
|
int columnIdx = 2;
|
|
if ((mWatchRefreshButton == null) && (mColumnIdx == 0) && (columnIdx < mSubItems.Count))
|
|
{
|
|
mWatchRefreshButton = new WatchRefreshButton();
|
|
mWatchRefreshButton.Resize(GS!(-16), 0, GS!(20), GS!(20));
|
|
mWatchRefreshButton.mOnMouseDown.Add(new (evt) => RefreshWatch());
|
|
var typeSubItem = GetSubItem(columnIdx);
|
|
typeSubItem.AddWidget(mWatchRefreshButton);
|
|
mListView.mListSizeDirty = true;
|
|
}
|
|
}
|
|
|
|
public void AddActionButton()
|
|
{
|
|
if ((mActionButton == null) && (mColumnIdx == 0))
|
|
{
|
|
if (mWatchEntry.mAction == "ShowCodeAddr 0x'00000000")
|
|
return;
|
|
if (mWatchEntry.mAction == "ShowCodeAddr 0x00000000")
|
|
return;
|
|
|
|
mActionButton = new ActionButton();
|
|
//var darkListView = (DarkListView)mListView;
|
|
mActionButton.mOnMouseDown.Add(new (evt) =>
|
|
{
|
|
gApp.PerformAction(mWatchEntry.mAction);
|
|
});
|
|
var typeSubItem = (WatchListViewItem)GetSubItem(1);
|
|
typeSubItem.AddWidget(mActionButton);
|
|
mActionButton.Resize(typeSubItem.Font.GetWidth(typeSubItem.mLabel) + 8, 0, 20, 20);
|
|
mListView.mListSizeDirty = true;
|
|
}
|
|
}
|
|
|
|
public override void RehupScale(float oldScale, float newScale)
|
|
{
|
|
base.RehupScale(oldScale, newScale);
|
|
if (mActionButton != null)
|
|
{
|
|
//var darkListView = (DarkListView)mListView;
|
|
var typeSubItem = (WatchListViewItem)GetSubItem(1);
|
|
mActionButton.Resize(typeSubItem.Font.GetWidth(typeSubItem.mLabel) + 8, 0, 20, 20);
|
|
}
|
|
}
|
|
|
|
public void SetDisabled(bool disabled, bool allowRefresh)
|
|
{
|
|
if ((mDisabled == disabled) && (mAllowRefresh == allowRefresh))
|
|
return;
|
|
mDisabled = disabled;
|
|
mAllowRefresh = allowRefresh;
|
|
|
|
if ((mDisabled) && (allowRefresh))
|
|
{
|
|
AddRefreshButton();
|
|
}
|
|
else if (mWatchRefreshButton != null)
|
|
{
|
|
Widget.RemoveAndDelete(mWatchRefreshButton);
|
|
mWatchRefreshButton = null;
|
|
}
|
|
|
|
if (mOpenButton != null)
|
|
mOpenButton.mAllowOpen = (!disabled) || (mOpenButton.mIsOpen);
|
|
|
|
if (mChildItems != null)
|
|
{
|
|
for (WatchListViewItem childItem in mChildItems)
|
|
childItem.SetDisabled(disabled, allowRefresh);
|
|
}
|
|
}
|
|
|
|
public override float ResizeComponents(float xOffset)
|
|
{
|
|
float retVal = base.ResizeComponents(xOffset);
|
|
if ((mColumnIdx == 1) && (((WatchListViewItem)GetSubItem(0)).mWatchRefreshButton != null))
|
|
mTextAreaLengthOffset = -16;
|
|
else
|
|
mTextAreaLengthOffset = 0;
|
|
return retVal;
|
|
}
|
|
|
|
void RefreshWatch()
|
|
{
|
|
var parentWatchListViewItem = mParentItem as WatchListViewItem;
|
|
if (parentWatchListViewItem != null)
|
|
{
|
|
parentWatchListViewItem.RefreshWatch();
|
|
return;
|
|
}
|
|
|
|
mWatchEntry.mIsNewExpression = true;
|
|
mWatchOwner.UpdateWatch(this);
|
|
}
|
|
|
|
public override void DrawAll(Graphics g)
|
|
{
|
|
if (mParentItem.mChildAreaHeight == 0)
|
|
return;
|
|
|
|
if (mMustUpdateBeforeEvaluate)
|
|
{
|
|
Update();
|
|
}
|
|
|
|
if (!IsVisible(g))
|
|
return;
|
|
|
|
if ((mWatchEntry != null) && (!mWatchEntry.mHasValue))
|
|
{
|
|
if (mParentItem.mChildAreaHeight > 0)
|
|
{
|
|
var parentWatchListViewItem = mParentItem as WatchListViewItem;
|
|
|
|
if ((!mDisabled) || (parentWatchListViewItem == null) || (mWatchEntry.mIsNewExpression))
|
|
{
|
|
mWatchOwner.UpdateWatch(this);
|
|
}
|
|
else if (mColumnIdx == 0)
|
|
{
|
|
var valSubItem = GetSubItem(1);
|
|
if (valSubItem.Label == "")
|
|
valSubItem.Label = "???";
|
|
}
|
|
}
|
|
}
|
|
|
|
base.DrawAll(g);
|
|
}
|
|
|
|
public bool IsBold
|
|
{
|
|
get
|
|
{
|
|
var headItem = (WatchListViewItem)GetSubItem(0);
|
|
return (mValueChanged) && (!headItem.mDisabled) && (!mFailed);
|
|
}
|
|
}
|
|
|
|
public Font Font
|
|
{
|
|
get
|
|
{
|
|
return IsBold ? DarkTheme.sDarkTheme.mSmallBoldFont : DarkTheme.sDarkTheme.mSmallFont;
|
|
}
|
|
}
|
|
|
|
public override void Draw(Graphics g)
|
|
{
|
|
uint32 color = Color.White;
|
|
var headItem = (WatchListViewItem)GetSubItem(0);
|
|
var valueItem = (WatchListViewItem)GetSubItem(1);
|
|
if (headItem.mDisabled)
|
|
color = 0x80FFFFFF;
|
|
else if (mFailed)
|
|
color = 0xFFFF4040;
|
|
|
|
var watchListView = (WatchListView)mListView;
|
|
if (IsBold)
|
|
watchListView.mFont = DarkTheme.sDarkTheme.mSmallBoldFont;
|
|
using (g.PushColor(color))
|
|
{
|
|
base.Draw(g);
|
|
}
|
|
watchListView.mFont = DarkTheme.sDarkTheme.mSmallFont;
|
|
|
|
if ((this == headItem) && (mWatchEntry.mResultType != WatchResultType.None))
|
|
{
|
|
DarkTheme.ImageIdx imageIdx = .IconValue;
|
|
if (mWatchEntry.mMemoryBreakpointAddr != 0)
|
|
{
|
|
imageIdx = .RedDot;
|
|
}
|
|
else if (mWatchEntry.mResultType.HasFlag(WatchResultType.Object))
|
|
{
|
|
if (mWatchEntry.mIsDeleted)
|
|
imageIdx = .IconObjectDeleted;
|
|
else
|
|
imageIdx = .IconObject;
|
|
}
|
|
else if (mWatchEntry.mResultType.HasFlag(WatchResultType.TypeClass))
|
|
{
|
|
imageIdx = .Type_Class;
|
|
}
|
|
else if (mWatchEntry.mResultType.HasFlag(WatchResultType.Interface))
|
|
{
|
|
imageIdx = .Interface;
|
|
}
|
|
else if (mWatchEntry.mResultType.HasFlag(WatchResultType.TypeValueType))
|
|
{
|
|
imageIdx = .IconValue;
|
|
}
|
|
else if (mWatchEntry.mResultType.HasFlag(WatchResultType.Namespace))
|
|
{
|
|
imageIdx = .Namespace;
|
|
}
|
|
else if (mWatchEntry.mResultType.HasFlag(WatchResultType.Pointer))
|
|
{
|
|
imageIdx = .IconPointer;
|
|
}
|
|
|
|
if (valueItem.mFailed)
|
|
imageIdx = .IconError;
|
|
|
|
var listView = (WatchListView)mListView;
|
|
using (g.PushColor(headItem.mDisabled ? 0x80FFFFFF : Color.White))
|
|
{
|
|
g.Draw(DarkTheme.sDarkTheme.GetImage(imageIdx), listView.mLabelX - GS!(22), 0);
|
|
|
|
if (mWatchEntry.mIsAppendAlloc)
|
|
g.Draw(DarkTheme.sDarkTheme.GetImage(.IconObjectAppend), listView.mLabelX - GS!(22), 0);
|
|
if (mWatchEntry.mIsStackAlloc)
|
|
g.Draw(DarkTheme.sDarkTheme.GetImage(.IconObjectStack), listView.mLabelX - GS!(22), 0);
|
|
}
|
|
}
|
|
|
|
if (mErrorEnd != 0)
|
|
{
|
|
float labelX = 44;
|
|
String subStr = scope String();
|
|
subStr.Append(mLabel, 0, Math.Min(mErrorStart, mLabel.Length));
|
|
float strStarts = labelX + g.mFont.GetWidth(subStr);
|
|
subStr.Clear();
|
|
subStr.Append(mLabel, 0, Math.Min(mErrorEnd, mLabel.Length));
|
|
float strEnds = labelX + g.mFont.GetWidth(subStr);
|
|
strEnds = Math.Min(mListView.mColumns[0].mWidth - LabelX + labelX, strEnds);
|
|
using (g.PushColor(0xFFFF4040))
|
|
IDEApp.sApp.DrawSquiggle(g, strStarts, GS!(2), strEnds - strStarts);
|
|
}
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
mMustUpdateBeforeEvaluate = false;
|
|
|
|
if ((mWatchEntry != null) && (mWatchEntry.mIsPending))
|
|
{
|
|
if (!gApp.mDebugger.mIsRunning)
|
|
{
|
|
mWatchEntry.mIsPending = false;
|
|
}
|
|
else
|
|
{
|
|
gApp.mDebugger.EvaluateContinueKeep();
|
|
if (gApp.mDebugger.GetRunState() == .DebugEval_Done)
|
|
{
|
|
mWatchOwner.UpdateWatch(this);
|
|
}
|
|
}
|
|
}
|
|
var watchListView = (WatchListView)mListView;
|
|
if (mParentItem.mChildAreaHeight != 0)
|
|
{
|
|
float itemHeight = watchListView.mFont.GetLineSpacing();
|
|
int32 addrSize = IDEApp.sApp.mDebugger.GetAddrSize() * 2;
|
|
int32 dbgContinuationCount = 0;
|
|
|
|
if ((mWatchSeriesInfo != null) && (addrSize != 0) && (mSeriesMemberIdx == 0))
|
|
{
|
|
/*Stopwatch sw = new Stopwatch();
|
|
sw.Start();*/
|
|
|
|
/*float ofsX;
|
|
float ofsY;
|
|
mParent.SelfToOtherTranslate(mListView, 0, 0, out ofsX, out ofsY);*/
|
|
|
|
float ofsX;
|
|
float ofsY;
|
|
mParent.SelfToOtherTranslate(mListView, 0, 0, out ofsX, out ofsY);
|
|
ofsY -= (float)mListView.mVertPos.mDest + mListView.mScrollContent.mY;
|
|
|
|
int32 curMemberIdx = mWatchSeriesInfo.mStartMemberIdx;
|
|
WatchListViewItem prevWatchListViewItem = null;
|
|
WatchListViewItem nextWatchListViewItem = (WatchListViewItem)mParentItem.mChildItems[curMemberIdx];
|
|
|
|
int entryAddrSize = addrSize * mWatchSeriesInfo.mAddrsEntrySize;
|
|
int addrsCount = 0;
|
|
if (mWatchSeriesInfo.mAddrs != null)
|
|
addrsCount = mWatchSeriesInfo.mAddrs.Length / entryAddrSize;
|
|
|
|
int totalCount = mWatchSeriesInfo.mCount;
|
|
if ((totalCount == -1) && (mWatchSeriesInfo.mContinuationData != null))
|
|
{
|
|
//int wantNewCount = Math.Min(idx + 32, mWatchSeriesInfo.mCount) - addrsCount;
|
|
bool continuationDone = false;
|
|
if (BFApp.sApp.mIsUpdateBatchStart)
|
|
{
|
|
String continuationResult = scope String();
|
|
IDEApp.sApp.mDebugger.GetCollectionContinuation(mWatchSeriesInfo.mContinuationData, 256, continuationResult);
|
|
var continuationResultVals = scope List<StringView>(continuationResult.Split('\n'));
|
|
String extraAddrs = scope String(continuationResultVals[0]);
|
|
mWatchSeriesInfo.mAddrs.Append(extraAddrs);
|
|
if (continuationResultVals.Count > 1)
|
|
{
|
|
delete mWatchSeriesInfo.mContinuationData;
|
|
mWatchSeriesInfo.mContinuationData = new String(continuationResultVals[1]);
|
|
}
|
|
if (extraAddrs.Length == 0)
|
|
continuationDone = true;
|
|
|
|
dbgContinuationCount++;
|
|
}
|
|
|
|
addrsCount = mWatchSeriesInfo.mAddrs.Length / entryAddrSize;
|
|
totalCount = addrsCount;
|
|
if (continuationDone)
|
|
{
|
|
// We finally have the count
|
|
mWatchSeriesInfo.mCount = totalCount;
|
|
}
|
|
}
|
|
mWatchSeriesInfo.mCurCount = totalCount;
|
|
|
|
int showCount = Math.Min(totalCount, mWatchSeriesInfo.mShowPages * mWatchSeriesInfo.mShowPageSize);
|
|
|
|
float curY = mY;
|
|
float prevY = curY;
|
|
float lastBottomPadding = 0;
|
|
for (int32 idx = 0; idx < showCount; idx++)
|
|
ShowBlock:
|
|
{
|
|
WatchListViewItem curWatchListViewItem = null;
|
|
|
|
if ((nextWatchListViewItem != null) && (idx == nextWatchListViewItem.mSeriesMemberIdx))
|
|
{
|
|
curWatchListViewItem = nextWatchListViewItem;
|
|
curMemberIdx++;
|
|
if (curMemberIdx < mParentItem.mChildItems.Count)
|
|
{
|
|
nextWatchListViewItem = (WatchListViewItem)mParentItem.mChildItems[curMemberIdx];
|
|
if (nextWatchListViewItem.mWatchSeriesInfo == null)
|
|
nextWatchListViewItem = null;
|
|
if (nextWatchListViewItem != null)
|
|
lastBottomPadding = nextWatchListViewItem.mBottomPadding;
|
|
}
|
|
else
|
|
nextWatchListViewItem = null;
|
|
}
|
|
|
|
bool wantsFillIn = (curY + ofsY + itemHeight >= 0) && (curY + ofsY < mListView.mHeight);
|
|
bool wantsDelete = !wantsFillIn;
|
|
bool forceDelete = false;
|
|
bool forceFillIn = false;
|
|
|
|
if (mDisabled)
|
|
{
|
|
wantsFillIn = false;
|
|
wantsDelete = false;
|
|
}
|
|
|
|
if ((curWatchListViewItem != null) && (idx > 0) && (curWatchListViewItem.mWatchEntry.mSeriesFirstVersion != mWatchSeriesInfo.mSeriesFirstVersion))
|
|
{
|
|
// This logic gets invoked for Beef array views....
|
|
forceDelete = true;
|
|
wantsFillIn = true;
|
|
}
|
|
|
|
if ((curWatchListViewItem != null) && (idx > 0) && (curWatchListViewItem.mWatchEntry.mSeriesVersion != mWatchSeriesInfo.mSeriesVersion))
|
|
{
|
|
forceFillIn = true;
|
|
}
|
|
|
|
if ((forceDelete) ||
|
|
((wantsDelete) && (idx != 0) && (curWatchListViewItem != null) && (curWatchListViewItem.mChildAreaHeight == 0) && (!curWatchListViewItem.mIsSelected)))
|
|
{
|
|
if (curWatchListViewItem == nextWatchListViewItem)
|
|
nextWatchListViewItem = null;
|
|
|
|
curMemberIdx--;
|
|
mParentItem.RemoveChildItem(curWatchListViewItem);
|
|
curWatchListViewItem = null;
|
|
}
|
|
|
|
if (((curWatchListViewItem == null) && (wantsFillIn)) ||
|
|
(forceFillIn))
|
|
{
|
|
prevWatchListViewItem.mBottomPadding = (curY - prevWatchListViewItem.mY) - prevWatchListViewItem.mSelfHeight - prevWatchListViewItem.mChildAreaHeight;
|
|
if (curWatchListViewItem == null)
|
|
curWatchListViewItem = (WatchListViewItem)mParentItem.CreateChildItemAtIndex(curMemberIdx);
|
|
curWatchListViewItem.mX = mX;
|
|
if (curWatchListViewItem.mWatchSeriesInfo == null)
|
|
{
|
|
curWatchListViewItem.mVisible = false;
|
|
mWatchSeriesInfo.AddRef();
|
|
curWatchListViewItem.mWatchSeriesInfo = mWatchSeriesInfo;
|
|
curWatchListViewItem.mSeriesMemberIdx = idx;
|
|
}
|
|
else
|
|
{
|
|
Debug.Assert(curWatchListViewItem.mWatchSeriesInfo == mWatchSeriesInfo);
|
|
Debug.Assert(curWatchListViewItem.mSeriesMemberIdx == idx);
|
|
}
|
|
|
|
Object[] formatParams = scope Object[mWatchSeriesInfo.mAddrsEntrySize + 1];
|
|
formatParams[0] = idx;
|
|
|
|
if (mWatchSeriesInfo.mAddrs != null)
|
|
{
|
|
if (idx >= addrsCount)
|
|
{
|
|
int wantNewCount = Math.Min(idx + 32, mWatchSeriesInfo.mCount) - addrsCount;
|
|
String continuationResult = scope String();
|
|
IDEApp.sApp.mDebugger.GetCollectionContinuation(mWatchSeriesInfo.mContinuationData, (int32)wantNewCount, continuationResult);
|
|
if (!continuationResult.IsEmpty)
|
|
{
|
|
var continuationResultVals = scope List<StringView>(continuationResult.Split('\n'));
|
|
mWatchSeriesInfo.mAddrs.Append(scope String(continuationResultVals[0]));
|
|
mWatchSeriesInfo.mContinuationData.Set(scope String(continuationResultVals[1]));
|
|
addrsCount = mWatchSeriesInfo.mAddrs.Length / entryAddrSize;
|
|
dbgContinuationCount++;
|
|
}
|
|
}
|
|
|
|
for (int32 i = 0; i < mWatchSeriesInfo.mAddrsEntrySize; i++)
|
|
{
|
|
if (idx >= addrsCount)
|
|
{
|
|
formatParams[i + 1] = "?";
|
|
}
|
|
else
|
|
{
|
|
var str = scope:ShowBlock String();
|
|
str.Append(mWatchSeriesInfo.mAddrs, idx * entryAddrSize + (i * addrSize), addrSize);
|
|
formatParams[i + 1] = str;
|
|
}
|
|
}
|
|
}
|
|
|
|
var dispStr = scope String();
|
|
dispStr.AppendF(mWatchSeriesInfo.mDisplayTemplate, params formatParams);
|
|
var evalStr = scope String();
|
|
evalStr.AppendF(mWatchSeriesInfo.mEvalTemplate, params formatParams);
|
|
|
|
watchListView.mWatchOwner.SetupListViewItem(curWatchListViewItem, dispStr, evalStr);
|
|
curWatchListViewItem.mWatchEntry.mSeriesFirstVersion = mWatchSeriesInfo.mSeriesFirstVersion;
|
|
curWatchListViewItem.mWatchEntry.mSeriesVersion = mWatchSeriesInfo.mSeriesVersion;
|
|
if (!forceFillIn)
|
|
curMemberIdx++;
|
|
}
|
|
|
|
|
|
if (prevWatchListViewItem != null)
|
|
{
|
|
if (mDisabled)
|
|
prevWatchListViewItem.mBottomPadding = 0;
|
|
else
|
|
prevWatchListViewItem.mBottomPadding = (curY - prevY) - prevWatchListViewItem.mSelfHeight - prevWatchListViewItem.mChildAreaHeight;
|
|
}
|
|
|
|
if (curWatchListViewItem != null)
|
|
prevY = curY;
|
|
|
|
curY += itemHeight;
|
|
if (curWatchListViewItem != null)
|
|
{
|
|
curY += curWatchListViewItem.mChildAreaHeight;
|
|
prevWatchListViewItem = curWatchListViewItem;
|
|
}
|
|
}
|
|
|
|
if (totalCount > mWatchSeriesInfo.mShowPageSize)
|
|
{
|
|
if (mWatchSeriesInfo.mMoreButton == null)
|
|
{
|
|
mWatchSeriesInfo.mMoreButton = (DarkButton)DarkTheme.sDarkTheme.CreateButton(mParent, "More", mX + GS!(26), 0, GS!(68), GS!(20));
|
|
mWatchSeriesInfo.mMoreButton.mOnMouseClick.Add(new (evt) =>
|
|
{
|
|
if (mWatchSeriesInfo.mMoreButton.mDisabled)
|
|
return;
|
|
mWatchSeriesInfo.mShowPages = (int32)Math.Min(mWatchSeriesInfo.mShowPages + 1, 1 + (mWatchSeriesInfo.mCurCount + mWatchSeriesInfo.mShowPageSize - 1) / mWatchSeriesInfo.mShowPageSize);
|
|
mWatchSeriesInfo.mMoreButton.mVisible = false;
|
|
mWatchSeriesInfo.mLessButton.mVisible = false;
|
|
});
|
|
mWatchSeriesInfo.mMoreButton.mOnDeleted.Add(new (widget) =>
|
|
{ NOP!(); });
|
|
mWatchSeriesInfo.mLessButton = (DarkButton)DarkTheme.sDarkTheme.CreateButton(mParent, "Less", mX + GS!(26 + 68 + 2), 0, GS!(68), GS!(20));
|
|
mWatchSeriesInfo.mLessButton.mOnMouseClick.Add(new (evt) => { mWatchSeriesInfo.mShowPages = Math.Max(1, mWatchSeriesInfo.mShowPages - 1); });
|
|
}
|
|
|
|
float xOfs = 16;
|
|
|
|
float absX;
|
|
float absY;
|
|
SelfToOtherTranslate(mListView, xOfs, 0, out absX, out absY);
|
|
|
|
float btnX = mX + xOfs;
|
|
float buttonAreaWidth = (mListView.mColumns[0].mWidth + mListView.mColumns[1].mWidth - absX * 2);
|
|
float btnWidth = (buttonAreaWidth - 4) / 2;
|
|
curY += 3;
|
|
|
|
btnWidth = 62;
|
|
|
|
mWatchSeriesInfo.mMoreButton.mVisible = !mDisabled;
|
|
mWatchSeriesInfo.mMoreButton.mDisabled = showCount >= totalCount;
|
|
mWatchSeriesInfo.mMoreButton.Resize(btnX, curY, btnWidth, 20);
|
|
|
|
mWatchSeriesInfo.mLessButton.mVisible = !mDisabled;
|
|
mWatchSeriesInfo.mLessButton.mVisible = mWatchSeriesInfo.mShowPages > 1;
|
|
mWatchSeriesInfo.mLessButton.Resize(btnX + btnWidth + 2, curY, btnWidth, 20);
|
|
|
|
curY += 21;
|
|
}
|
|
else
|
|
{
|
|
if (mWatchSeriesInfo.mMoreButton != null)
|
|
{
|
|
Widget.RemoveAndDelete(mWatchSeriesInfo.mMoreButton);
|
|
mWatchSeriesInfo.mMoreButton = null;
|
|
Widget.RemoveAndDelete(mWatchSeriesInfo.mLessButton);
|
|
mWatchSeriesInfo.mLessButton = null;
|
|
}
|
|
}
|
|
|
|
if (prevWatchListViewItem != null)
|
|
{
|
|
if (mDisabled)
|
|
prevWatchListViewItem.mBottomPadding = 0;
|
|
else
|
|
prevWatchListViewItem.mBottomPadding = (curY - prevY) - prevWatchListViewItem.mSelfHeight - prevWatchListViewItem.mChildAreaHeight;
|
|
|
|
if (prevWatchListViewItem.mBottomPadding != lastBottomPadding)
|
|
mListView.mListSizeDirty = true;
|
|
}
|
|
|
|
while (curMemberIdx < mParentItem.mChildItems.Count)
|
|
{
|
|
var curWatchListViewItem = (WatchListViewItem)mParentItem.mChildItems[curMemberIdx];
|
|
if (curWatchListViewItem.mWatchSeriesInfo == null)
|
|
break;
|
|
if (curWatchListViewItem == this)
|
|
{
|
|
mWantRemoveSelf = true;
|
|
return;
|
|
}
|
|
mParentItem.RemoveChildItem(curWatchListViewItem);
|
|
/*if (mParentItem == null)
|
|
return;*/
|
|
}
|
|
|
|
/*sw.Stop();
|
|
int elapsedMs = (int)sw.ElapsedMilliseconds;
|
|
if (elapsedMs > 50)
|
|
{
|
|
Console.WriteLine("WatchPanel Update: {0}ms Cont:{1}", elapsedMs, dbgContinuationCount);
|
|
}*/
|
|
}
|
|
}
|
|
|
|
base.Update();
|
|
}
|
|
|
|
public override void UpdateAll()
|
|
{
|
|
base.UpdateAll();
|
|
if (mWantRemoveSelf)
|
|
mParentItem.RemoveChildItem(this);
|
|
}
|
|
}
|
|
|
|
public class WatchPanel : Panel, IWatchOwner
|
|
{
|
|
public WatchListView mListView;
|
|
|
|
public WatchListViewItem mSelectedParentItem;
|
|
bool mCancelingEdit;
|
|
bool mWatchesDirty;
|
|
bool mHadStep;
|
|
bool mClearHadStep;
|
|
bool mDisabled = true;
|
|
bool mIsAuto;
|
|
int32 mDisabledTicks;
|
|
bool mDeselectOnFocusLost = true;
|
|
|
|
public WatchListViewItem mEditingItem;
|
|
public ExpressionEditWidget mEditWidget;
|
|
|
|
public this(bool isAuto)
|
|
{
|
|
mIsAuto = isAuto;
|
|
mListView = new WatchListView(this);
|
|
mListView.mShowGridLines = true;
|
|
mListView.InitScrollbars(true, true);
|
|
mListView.mHorzScrollbar.mPageSize = GS!(100);
|
|
mListView.mHorzScrollbar.mContentSize = GS!(500);
|
|
mListView.mVertScrollbar.mPageSize = GS!(100);
|
|
mListView.mVertScrollbar.mContentSize = GS!(500);
|
|
mListView.UpdateScrollbars();
|
|
AddWidget(mListView);
|
|
|
|
mListView.mOnMouseClick.Add(new => ListViewClicked);
|
|
mListView.mOnMouseDown.Add(new => ListViewMouseDown);
|
|
mListView.mOnItemMouseClicked.Add(new => ValueClicked);
|
|
mListView.mOnItemMouseDown.Add(new => ValueMouseDown);
|
|
|
|
ListViewColumn column = mListView.AddColumn(GS!(200), "Name");
|
|
column.mMinWidth = GS!(40);
|
|
column = mListView.AddColumn(GS!(200), "Value");
|
|
column.mMinWidth = GS!(40);
|
|
column = mListView.AddColumn(GS!(200), "Type");
|
|
|
|
mListView.mOnDragEnd.Add(new => HandleDragEnd);
|
|
mListView.mOnDragUpdate.Add(new => HandleDragUpdate);
|
|
|
|
SetScaleData();
|
|
|
|
//RebuildUI();
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
mListView.GetRoot().Clear();
|
|
}
|
|
|
|
void SetScaleData()
|
|
{
|
|
mListView.mIconX = GS!(4);
|
|
mListView.mOpenButtonX = GS!(4);
|
|
mListView.mLabelX = GS!(44);
|
|
mListView.mChildIndent = GS!(16);
|
|
mListView.mHiliteOffset = GS!(-2);
|
|
}
|
|
|
|
public override void RehupScale(float oldScale, float newScale)
|
|
{
|
|
base.RehupScale(oldScale, newScale);
|
|
SetScaleData();
|
|
}
|
|
|
|
public void Serialize(StructuredData data, bool includeItems)
|
|
{
|
|
data.Add("Type", mIsAuto ? "AutoWatchPanel" : "WatchPanel");
|
|
|
|
IDEUtils.SerializeListViewState(data, mListView);
|
|
|
|
if (includeItems && !mIsAuto)
|
|
{
|
|
using (data.CreateArray("Items"))
|
|
{
|
|
var childItems = mListView.GetRoot().mChildItems;
|
|
if (childItems != null)
|
|
{
|
|
for (WatchListViewItem watchListViewItem in childItems)
|
|
{
|
|
var watchEntry = watchListViewItem.mWatchEntry;
|
|
data.Add(watchEntry.mEvalStr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void Serialize(StructuredData data)
|
|
{
|
|
base.Serialize(data);
|
|
Serialize(data, true);
|
|
}
|
|
|
|
public override bool Deserialize(StructuredData data)
|
|
{
|
|
base.Deserialize(data);
|
|
|
|
IDEUtils.DeserializeListViewState(data, mListView);
|
|
for (let itemKey in data.Enumerate("Items"))
|
|
{
|
|
//for (int32 watchIdx = 0; watchIdx < data.Count; watchIdx++)
|
|
//for (var watchKV in data)
|
|
{
|
|
String watchEntry = scope String();
|
|
//data.GetString(watchIdx, watchEntry);
|
|
data.GetCurString(watchEntry);
|
|
AddWatch(watchEntry);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public override void FocusForKeyboard()
|
|
{
|
|
var root = mListView.GetRoot();
|
|
if (root.GetChildCount() > 0)
|
|
{
|
|
var lastItem = root.GetChildAtIndex(root.GetChildCount() - 1);
|
|
root.SelectItemExclusively(lastItem);
|
|
mListView.EnsureItemVisible(lastItem, false);
|
|
}
|
|
}
|
|
|
|
static void CompactChildExpression(WatchListViewItem listViewItem, String outExpr)
|
|
{
|
|
var parentItem = listViewItem.GetWatchListViewItemParent();
|
|
if (parentItem == null)
|
|
{
|
|
outExpr.Append(listViewItem.mWatchEntry.mEvalStr);
|
|
return;
|
|
}
|
|
String parentEvalStr = scope String();
|
|
CompactChildExpression(parentItem, parentEvalStr);
|
|
String evalStr = listViewItem.mWatchEntry.mEvalStr;
|
|
String compactEvalStr = scope String();
|
|
IDEApp.sApp.mDebugger.CompactChildExpression(evalStr, parentEvalStr, compactEvalStr);
|
|
outExpr.Set(compactEvalStr);
|
|
}
|
|
|
|
void HandleDragUpdate(DragEvent evt)
|
|
{
|
|
var dragKind = evt.mDragKind;
|
|
evt.mDragKind = .None;
|
|
if (mIsAuto)
|
|
return;
|
|
|
|
var dragSource = evt.mSender as WatchListViewItem;
|
|
var dragTarget = evt.mDragTarget as WatchListViewItem;
|
|
if (dragSource == null)
|
|
return;
|
|
if (dragTarget == null)
|
|
return;
|
|
if (dragSource.mLabel == "")
|
|
return;
|
|
while (dragTarget.mParentItem != mListView.GetRoot())
|
|
{
|
|
// Check for if we're dragging after the last open child item. If so, treat it as if we're dragging to after the topmost parent
|
|
/*if ((evt.mDragTargetDir != 1) || (dragTarget != dragTarget.mParentItem.mChildItems[dragTarget.mParentItem.mChildItems.Count - 1]))
|
|
return;*/
|
|
evt.mDragKind = .After;
|
|
dragTarget = (WatchListViewItem)dragTarget.mParentItem;
|
|
evt.mDragTarget = dragTarget;
|
|
return;
|
|
}
|
|
if ((dragTarget.mLabel == "") && (dragKind == .After))
|
|
dragKind = .Before;
|
|
if (dragKind == .None)
|
|
return;
|
|
evt.mDragKind = dragKind;
|
|
}
|
|
|
|
void HandleDragEnd(DragEvent theEvent)
|
|
{
|
|
if (theEvent.mDragKind == .None)
|
|
return;
|
|
|
|
if (theEvent.mDragTarget is IDEListViewItem)
|
|
{
|
|
var source = (WatchListViewItem)theEvent.mSender;
|
|
var target = (WatchListViewItem)theEvent.mDragTarget;
|
|
|
|
if (source.mListView == target.mListView)
|
|
{
|
|
if (source == target)
|
|
return;
|
|
|
|
if (source.mParentItem == mListView.GetRoot())
|
|
{
|
|
// We're dragging a top-level item into a new position
|
|
source.mParentItem.RemoveChildItem(source, false);
|
|
if (theEvent.mDragKind == .Before) // Before
|
|
target.mParentItem.InsertChild(source, target);
|
|
else if (theEvent.mDragKind == .After) // After
|
|
target.mParentItem.AddChild(source, target);
|
|
}
|
|
else
|
|
{
|
|
String compactEvalStr = scope String();
|
|
CompactChildExpression(source, compactEvalStr);
|
|
|
|
var rootItem = mListView.GetRoot();
|
|
int idx = rootItem.mChildItems.IndexOf(target);
|
|
if (theEvent.mDragKind == .After)
|
|
idx++;
|
|
var listViewItem = (WatchListViewItem)rootItem.CreateChildItemAtIndex(idx);
|
|
listViewItem.mVisible = false;
|
|
SetupListViewItem(listViewItem, compactEvalStr, compactEvalStr);
|
|
rootItem.SelectItemExclusively(listViewItem);
|
|
mListView.EnsureItemVisible(listViewItem, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
WatchListView IWatchOwner.GetWatchListView()
|
|
{
|
|
return mListView;
|
|
}
|
|
|
|
public void SetupListViewItem(WatchListViewItem listViewItem, String name, String evalStr)
|
|
{
|
|
WatchEntry watchEntry = new WatchEntry();
|
|
watchEntry.mName = new String(name);
|
|
watchEntry.mEvalStr = new String(evalStr ?? name);
|
|
|
|
listViewItem.Label = name;
|
|
listViewItem.AllowDragging = true;
|
|
listViewItem.mOpenOnDoubleClick = false;
|
|
|
|
var subViewItem = (DarkListViewItem)listViewItem.GetOrCreateSubItem(1);
|
|
subViewItem.Label = "";
|
|
subViewItem.AllowDragging = true;
|
|
|
|
subViewItem = (DarkListViewItem)listViewItem.GetOrCreateSubItem(2);
|
|
subViewItem.Label = "";
|
|
subViewItem.AllowDragging = true;
|
|
|
|
delete listViewItem.mWatchEntry;
|
|
listViewItem.mWatchEntry = watchEntry;
|
|
}
|
|
|
|
public WatchListViewItem AddWatchItem(String name)
|
|
{
|
|
// This is the public interface to AddWatch, which uses the first available blank watch slot or appends a new one if necessary
|
|
var rootItem = mListView.GetRoot();
|
|
int childCount = mListView.GetRoot().GetChildCount();
|
|
for (int iChild=0; iChild<childCount; ++iChild)
|
|
{
|
|
if (rootItem.GetChildAtIndex(iChild).mLabel.Length > 0)
|
|
continue;
|
|
|
|
rootItem.RemoveChildItem(rootItem.GetChildAtIndex(iChild));
|
|
|
|
var listViewItem = (WatchListViewItem)rootItem.CreateChildItemAtIndex(iChild);
|
|
listViewItem.mVisible = false;
|
|
SetupListViewItem(listViewItem, name, null);
|
|
rootItem.SelectItemExclusively(listViewItem);
|
|
mListView.EnsureItemVisible(listViewItem, true);
|
|
|
|
return listViewItem;
|
|
}
|
|
|
|
return AddWatch(name);
|
|
}
|
|
|
|
WatchListViewItem AddWatch(String name, String evalStr = null, ListViewItem parentItem = null)
|
|
{
|
|
MarkDirty();
|
|
|
|
var useParentItem = parentItem;
|
|
if (useParentItem == null)
|
|
useParentItem = mListView.GetRoot();
|
|
var listViewItem = (WatchListViewItem)useParentItem.CreateChildItem();
|
|
listViewItem.mVisible = false;
|
|
|
|
SetupListViewItem(listViewItem, name, evalStr);
|
|
|
|
if ((parentItem != null) && (parentItem.Selected))
|
|
{
|
|
// If the parentItem is selected and the next item after the parentItem is selected then we may have a selection span
|
|
// so we want to expand that selection to the newly-created item
|
|
|
|
int parentIdx = parentItem.mParentItem.GetIndexOfChild(parentItem);
|
|
if (parentIdx + 1 < parentItem.mParentItem.mChildItems.Count)
|
|
{
|
|
let nextItem = parentItem.mParentItem.mChildItems[parentIdx + 1];
|
|
if (nextItem.Selected)
|
|
{
|
|
if ((parentItem.mChildItems.Count == 1) || (parentItem.mChildItems[parentItem.mChildItems.Count - 2].Selected))
|
|
listViewItem.Selected = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return listViewItem;
|
|
}
|
|
|
|
public void SetDisabled(bool disabled)
|
|
{
|
|
MarkDirty();
|
|
mDisabled = disabled;
|
|
mMouseVisible = !disabled;
|
|
mDisabledTicks = 0;
|
|
if (!gApp.mDebugger.mIsRunning)
|
|
mDisabledTicks = 9999; // Show immediately grey
|
|
}
|
|
|
|
public override void DrawAll(Graphics g)
|
|
{
|
|
bool showDisabled = (mDisabled) && (mDisabledTicks > 40);
|
|
using (g.PushColor(showDisabled ? 0x80FFFFFF : Color.White))
|
|
base.DrawAll(g);
|
|
}
|
|
|
|
public void MarkWatchesDirty(bool hadStep, bool clearHadStep = false)
|
|
{
|
|
MarkDirty();
|
|
mWatchesDirty = true;
|
|
if (hadStep)
|
|
mHadStep = true;
|
|
if (clearHadStep)
|
|
mClearHadStep = true;
|
|
}
|
|
|
|
public override void Resize(float x, float y, float width, float height)
|
|
{
|
|
base.Resize(x, y, width, height);
|
|
mListView.Resize(0, 0, width, height);
|
|
}
|
|
|
|
void HandleRenameCancel(EditEvent theEvent)
|
|
{
|
|
mCancelingEdit = true;
|
|
bool removedItem;
|
|
DoHandleEditLostFocus((EditWidget)theEvent.mSender, out removedItem);
|
|
if ((mHasFocus) && (!removedItem))
|
|
{
|
|
Update();
|
|
/*var lastItem = mListView.GetRoot().mChildItems[mListView.GetRoot().mChildItems.Count - 1];
|
|
lastItem.Focused = true;*/
|
|
}
|
|
}
|
|
|
|
void HandleRenameSubmit(EditEvent theEvent)
|
|
{
|
|
var watchEditWidgetContent = (ExpressionEditWidgetContent)mEditWidget.Content;
|
|
if ((watchEditWidgetContent.mAutoComplete != null) && (watchEditWidgetContent.mAutoComplete.HasSelection()))
|
|
watchEditWidgetContent.mAutoComplete.InsertSelection((char8)0);
|
|
HandleEditLostFocus((EditWidget)theEvent.mSender);
|
|
}
|
|
|
|
|
|
void HandleEditLostFocus(Widget widget)
|
|
{
|
|
bool removedItem;
|
|
DoHandleEditLostFocus(widget, out removedItem);
|
|
}
|
|
|
|
void HandleEditKeyDown(KeyDownEvent evt)
|
|
{
|
|
if (((evt.mKeyCode == .Tab) || (evt.mKeyCode == .F2)) &&
|
|
(evt.mKeyFlags == 0))
|
|
{
|
|
if (!mEditWidget.IsShowingAutoComplete())
|
|
{
|
|
let valueItem = (WatchListViewItem)mEditingItem.GetSubItem(1);
|
|
if (!valueItem.Label.IsEmpty)
|
|
{
|
|
EditEvent editEvent = scope .();
|
|
editEvent.mSender = evt.mSender;
|
|
HandleRenameCancel(editEvent);
|
|
EditListViewItem(valueItem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DoHandleEditLostFocus(Widget widget, out bool removedItem)
|
|
{
|
|
removedItem = false;
|
|
EditWidget editWidget = (EditWidget)widget;
|
|
editWidget.mOnLostFocus.Remove(scope => HandleEditLostFocus, true);
|
|
editWidget.mOnSubmit.Remove(scope => HandleRenameSubmit, true);
|
|
editWidget.mOnCancel.Remove(scope => HandleRenameCancel, true);
|
|
editWidget.mOnKeyDown.Remove(scope => HandleEditKeyDown, true);
|
|
WidgetWindow.sOnMouseWheel.Remove(scope => HandleMouseWheel, true);
|
|
|
|
if (!mEditWidget.Content.HasUndoData())
|
|
mCancelingEdit = true;
|
|
|
|
String newValue = scope String();
|
|
editWidget.GetText(newValue);
|
|
newValue.Trim();
|
|
|
|
WatchListViewItem listViewItem = (WatchListViewItem)mEditingItem;
|
|
int32 column = listViewItem.mColumnIdx;
|
|
|
|
if (column == 0)
|
|
{
|
|
var trimmedLabel = scope String(listViewItem.mLabel);
|
|
trimmedLabel.Trim();
|
|
|
|
if (trimmedLabel != newValue)
|
|
{
|
|
var watchEntry = listViewItem.mWatchEntry;
|
|
watchEntry.mIsNewExpression = true;
|
|
|
|
if (!mCancelingEdit)
|
|
listViewItem.Label = newValue;
|
|
|
|
if (listViewItem.mLabel.Length > 0)
|
|
{
|
|
String.NewOrSet!(watchEntry.mName, listViewItem.mLabel);
|
|
String.NewOrSet!(watchEntry.mEvalStr, watchEntry.mName);
|
|
IDEApp.sApp.mMemoryPanel.MarkViewDirty();
|
|
gApp.MarkWatchesDirty();
|
|
}
|
|
else
|
|
{
|
|
mListView.GetRoot().RemoveChildItem(listViewItem);
|
|
removedItem = true;
|
|
}
|
|
}
|
|
}
|
|
else if ((column == 1) && (newValue.Length > 0) && (!mCancelingEdit))
|
|
{
|
|
var headListViewItem = (WatchListViewItem)listViewItem.GetSubItem(0);
|
|
String evalStr = scope String(headListViewItem.mWatchEntry.mEvalStr, ", assign=", newValue);
|
|
String val = scope String();
|
|
gApp.DebugEvaluate(headListViewItem.mWatchEntry.mResultTypeStr, evalStr, val, -1, .NotSet, .AllowSideEffects | .AllowCalls);
|
|
headListViewItem.mWatchEntry.mIsNewExpression = true;
|
|
//IDEApp.sApp.OutputLine(val);
|
|
|
|
if (val.StartsWith("!", StringComparison.Ordinal))
|
|
{
|
|
String errorString = scope String();
|
|
errorString.Append(val, 1);
|
|
var errorVals = scope List<StringView>(errorString.Split('\t'));
|
|
if (errorVals.Count == 3)
|
|
{
|
|
int32 errorStart = int32.Parse(scope String(errorVals[0]));
|
|
int32 errorEnd = errorStart + int32.Parse(scope String(errorVals[1])).Get();
|
|
if (errorEnd > evalStr.Length)
|
|
errorEnd = (int32)evalStr.Length;
|
|
errorString.Set(errorVals[2]);
|
|
if ((errorEnd > 0) && (errorStart < evalStr.Length) && (!errorString.Contains(':')))
|
|
{
|
|
String appendStr = scope String();
|
|
appendStr.Append(evalStr, errorStart, errorEnd - errorStart);
|
|
errorString.Append(": ", appendStr);
|
|
}
|
|
}
|
|
IDEApp.sApp.Fail(errorString);
|
|
}
|
|
|
|
IDEApp.sApp.mMemoryPanel.MarkViewDirty();
|
|
gApp.MarkWatchesDirty();
|
|
}
|
|
|
|
editWidget.RemoveSelf();
|
|
BFApp.sApp.DeferDelete(editWidget);
|
|
mEditWidget = null;
|
|
|
|
if (mWidgetWindow.mFocusWidget == null)
|
|
SetFocus();
|
|
if ((mHasFocus) && (!removedItem))
|
|
listViewItem.GetSubItem(0).Focused = true;
|
|
}
|
|
|
|
public void EditListViewItem(WatchListViewItem listViewItem)
|
|
{
|
|
if (mEditWidget != null)
|
|
return;
|
|
|
|
if ((listViewItem.mColumnIdx == 0) && (mIsAuto))
|
|
return;
|
|
|
|
if ((listViewItem.mColumnIdx == 0) && (listViewItem.mParentItem.mParentItem != null))
|
|
return;
|
|
|
|
//mListView.UpdateContentPosition();
|
|
mListView.UpdateListSize();
|
|
|
|
var headListViewItem = (WatchListViewItem)listViewItem.GetSubItem(0);
|
|
if ((listViewItem.mColumnIdx > 0) && (headListViewItem.mWatchEntry != null) && (!headListViewItem.mWatchEntry.mCanEdit))
|
|
{
|
|
if (headListViewItem.mActionButton != null)
|
|
headListViewItem.mActionButton.mOnMouseDown(null);
|
|
|
|
return;
|
|
}
|
|
|
|
mCancelingEdit = false;
|
|
|
|
ExpressionEditWidget editWidget = new ExpressionEditWidget();
|
|
mEditWidget = editWidget;
|
|
String editVal = listViewItem.mLabel;
|
|
if ((listViewItem.mColumnIdx > 0) && (headListViewItem.mWatchEntry.mEditInitialize != null))
|
|
editVal = headListViewItem.mWatchEntry.mEditInitialize;
|
|
editWidget.mExpectingType = headListViewItem.mWatchEntry.mResultTypeStr;
|
|
editWidget.SetText(editVal);
|
|
editWidget.Content.SelectAll();
|
|
editWidget.Content.ClearUndoData();
|
|
|
|
float x;
|
|
float y;
|
|
listViewItem.SelfToOtherTranslate(mListView, 0, 0, out x, out y);
|
|
|
|
mEditingItem = (WatchListViewItem)listViewItem;
|
|
|
|
bool isEmpty = (mEditingItem.mWatchEntry != null) && (mEditingItem.mWatchEntry.mEvalStr.IsEmpty);
|
|
|
|
float width;
|
|
if (isEmpty)
|
|
{
|
|
x = GS!(4);
|
|
width = mListView.mScrollContentContainer.mWidth - GS!(8);
|
|
}
|
|
else
|
|
{
|
|
x = listViewItem.LabelX - GS!(4);
|
|
width = listViewItem.LabelWidth + GS!(6);
|
|
|
|
if (listViewItem.mColumnIdx == mListView.mColumns.Count - 1)
|
|
width = mListView.mWidth - x - GS!(20);
|
|
else
|
|
width = Math.Min(width, mListView.mWidth - x - GS!(20));
|
|
}
|
|
|
|
//editWidget.Resize(x - GS!(1), y - GS!(3), width, GS!(28));
|
|
editWidget.ResizeAround(x, y, width);
|
|
mListView.AddWidget(editWidget);
|
|
|
|
editWidget.mOnLostFocus.Add(new => HandleEditLostFocus);
|
|
editWidget.mOnSubmit.Add(new => HandleRenameSubmit);
|
|
editWidget.mOnCancel.Add(new => HandleRenameCancel);
|
|
editWidget.mOnKeyDown.Add(new => HandleEditKeyDown);
|
|
WidgetWindow.sOnMouseWheel.Add(new => HandleMouseWheel);
|
|
editWidget.SetFocus();
|
|
}
|
|
|
|
void HandleMouseWheel(MouseEvent evt)
|
|
{
|
|
HandleEditLostFocus(mEditWidget);
|
|
}
|
|
|
|
public override void LostFocus()
|
|
{
|
|
base.LostFocus();
|
|
if (mDeselectOnFocusLost)
|
|
mListView.GetRoot().SelectItemExclusively(null);
|
|
}
|
|
|
|
void ValueClicked(ListViewItem item, float x, float y, int32 btnNum)
|
|
{
|
|
if ((btnNum == 1) && (!mDisabled))
|
|
{
|
|
DarkListViewItem widget = (DarkListViewItem)item;
|
|
float clickX = x;
|
|
float clickY = widget.mHeight + GS!(2);
|
|
widget.SelfToOtherTranslate(mListView.GetRoot(), clickX, clickY, var aX, var aY);
|
|
ShowRightClickMenu(mListView, aX, aY);
|
|
}
|
|
}
|
|
|
|
void ListViewItemMouseDown(WatchListViewItem clickedItem, int32 btnCount)
|
|
{
|
|
if (mDisabled)
|
|
return;
|
|
|
|
WatchListViewItem item = (WatchListViewItem)clickedItem.GetSubItem(0);
|
|
|
|
mListView.GetRoot().SelectItem(item, true);
|
|
SetFocus();
|
|
|
|
if ((mIsAuto) && (clickedItem.mColumnIdx == 0))
|
|
return;
|
|
|
|
if (clickedItem.mColumnIdx > 1)
|
|
return;
|
|
|
|
if (clickedItem.mColumnIdx > 0)
|
|
{
|
|
if (item.mDisabled)
|
|
return;
|
|
}
|
|
|
|
if ((btnCount > 1) ||
|
|
((clickedItem.mLabel.Length == 0) && (clickedItem.mColumnIdx == 0)))
|
|
EditListViewItem(clickedItem);
|
|
}
|
|
|
|
void ValueMouseDown(ListViewItem item, float x, float y, int32 btnNum, int32 btnCount)
|
|
{
|
|
WatchListViewItem clickedItem = (WatchListViewItem)item;
|
|
if (btnNum == 0)
|
|
ListViewItemMouseDown(clickedItem, btnCount);
|
|
else
|
|
{
|
|
if (!clickedItem.GetSubItem(0).Selected)
|
|
ListViewItemMouseDown(clickedItem, 1);
|
|
}
|
|
}
|
|
|
|
void ClearWatchValues(ListViewItem parentListViewItem)
|
|
{
|
|
if (parentListViewItem.mParentItem != null)
|
|
{
|
|
var watch = ((WatchListViewItem)parentListViewItem).mWatchEntry;
|
|
watch.mHasValue = false;
|
|
if (mHadStep)
|
|
watch.mHadStepCount++;
|
|
if (mClearHadStep)
|
|
watch.mHadStepCount = 0;
|
|
}
|
|
|
|
if (parentListViewItem.mChildItems != null)
|
|
{
|
|
for (var listViewItem in parentListViewItem.mChildItems)
|
|
{
|
|
ClearWatchValues(listViewItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
void IWatchOwner.UpdateWatch(WatchListViewItem listViewItem)
|
|
{
|
|
if (mDisabled)
|
|
return;
|
|
|
|
bool isTopLevel = listViewItem.mParentItem == mListView.GetRoot();
|
|
listViewItem.mErrorStart = 0;
|
|
listViewItem.mErrorEnd = 0;
|
|
|
|
var watch = listViewItem.mWatchEntry;
|
|
bool wasNewExpression = watch.mIsNewExpression;
|
|
String val = scope String();
|
|
if (watch.mIsPending)
|
|
{
|
|
IDEApp.sApp.mDebugger.EvaluateContinue(val);
|
|
}
|
|
else if (watch.mEvalStr.Length > 0)
|
|
{
|
|
String evalStr = scope String(watch.mEvalStr);
|
|
if ((watch.mReferenceId != null) && (watch.mReferenceId.StartsWith("0", StringComparison.Ordinal)))
|
|
evalStr.Append(",refid=", watch.mReferenceId);
|
|
//gApp.DebugEvaluate(watch.mResultTypeStr, evalStr, val, -1, watch.mIsNewExpression, watch.mIsNewExpression);
|
|
//TODO: Why did we have the mResultTypeStr in there?
|
|
DebugManager.EvalExpressionFlags flags = default;
|
|
if (watch.mIsNewExpression)
|
|
flags |= .AllowSideEffects | .AllowCalls;
|
|
gApp.DebugEvaluate(null, evalStr, val, -1, watch.mLanguage, flags);
|
|
watch.mIsNewExpression = false;
|
|
}
|
|
watch.mIsPending = false;
|
|
|
|
var valViews = scope List<StringView>(val.Split('\n'));
|
|
|
|
var vals = scope List<String>();
|
|
for (var strView in valViews)
|
|
vals.Add(scope:: String(strView));
|
|
|
|
var valueSubItem = (WatchListViewItem)listViewItem.GetSubItem(1);
|
|
if (vals[0].StartsWith("!", StringComparison.Ordinal))
|
|
{
|
|
if ((vals[0] == "!pending") || (vals[0] == "!Not paused"))
|
|
{
|
|
watch.mIsPending = true;
|
|
return;
|
|
}
|
|
|
|
var errStr = scope String(vals[0]);
|
|
errStr.Remove(0);
|
|
bool hadSideEffects = vals[0] == "!sideeffects";
|
|
bool hadPropertyEval = vals[0] == "!property";
|
|
|
|
if ((!wasNewExpression) && (isTopLevel))
|
|
{
|
|
if (((!valueSubItem.mFailed) && (watch.mHadValue)) || (hadSideEffects) || (hadPropertyEval))
|
|
{
|
|
watch.mHasValue = true;
|
|
listViewItem.SetDisabled(true, hadSideEffects);
|
|
return;
|
|
}
|
|
}
|
|
|
|
listViewItem.SetDisabled(false, false);
|
|
var errorVals = scope List<StringView>(errStr.Split('\t'));
|
|
|
|
if (errorVals.Count > 1)
|
|
{
|
|
listViewItem.mErrorStart = int32.Parse(scope String(errorVals[0]));
|
|
listViewItem.mErrorEnd = listViewItem.mErrorStart + int32.Parse(scope String(errorVals[1])).Get();
|
|
valueSubItem.Label = errorVals[2];
|
|
}
|
|
else
|
|
valueSubItem.Label = errorVals[0];
|
|
valueSubItem.mFailed = true;
|
|
watch.mHadStepCount = 0;
|
|
}
|
|
else
|
|
{
|
|
listViewItem.SetDisabled(false, false);
|
|
String newVal = vals[0];
|
|
|
|
if (watch.mHadStepCount == 1)
|
|
valueSubItem.mValueChanged = (newVal != valueSubItem.mLabel) || (valueSubItem.mFailed);
|
|
else if (watch.mHadStepCount > 1)
|
|
valueSubItem.mValueChanged = false;
|
|
watch.mHadStepCount = 0;
|
|
valueSubItem.Label = newVal;
|
|
valueSubItem.mFailed = false;
|
|
}
|
|
|
|
var typeSubItem = (WatchListViewItem)listViewItem.GetSubItem(2);
|
|
if (vals.Count > 1)
|
|
{
|
|
String.NewOrSet!(watch.mResultTypeStr, vals[1]);
|
|
typeSubItem.Label = vals[1];
|
|
}
|
|
else
|
|
{
|
|
DeleteAndNullify!(watch.mResultTypeStr);
|
|
typeSubItem.Label = "";
|
|
}
|
|
|
|
int cmdStringCount = Math.Max(0, vals.Count - 2);
|
|
int memberCount = 0;
|
|
|
|
watch.mMemoryBreakpointAddr = 0;
|
|
watch.mResultType = WatchResultType.Value;
|
|
watch.mIsDeleted = false;
|
|
watch.mIsAppendAlloc = false;
|
|
watch.mIsStackAlloc = false;
|
|
watch.mLanguage = .NotSet;
|
|
DeleteAndNullify!(watch.mEditInitialize);
|
|
DeleteAndNullify!(watch.mAction);
|
|
watch.mCanEdit = false;
|
|
watch.mAction = null;
|
|
|
|
if (listViewItem.mActionButton != null)
|
|
{
|
|
Widget.RemoveAndDelete(listViewItem.mActionButton);
|
|
listViewItem.mActionButton = null;
|
|
}
|
|
|
|
WatchSeriesInfo watchSeriesInfo = null;
|
|
for (int32 memberIdx = 0; memberIdx < cmdStringCount; memberIdx++)
|
|
{
|
|
var memberVals = scope List<StringView>(vals[memberIdx + 2].Split('\t'));
|
|
var memberVals0 = scope String(memberVals[0]);
|
|
|
|
if (memberVals0.StartsWith(":"))
|
|
{
|
|
if (memberVals0 == ":canEdit")
|
|
{
|
|
watch.mCanEdit = true;
|
|
if (memberVals.Count > 1)
|
|
String.NewOrSet!(watch.mEditInitialize, scope String(memberVals[1]));
|
|
}
|
|
if (memberVals0 == ":editVal")
|
|
{
|
|
String.NewOrSet!(watch.mEditInitialize, scope String(memberVals[1]));
|
|
}
|
|
else if (memberVals0 == ":break")
|
|
{
|
|
watch.mMemoryBreakpointAddr = (int)Int64.Parse(memberVals[1], .HexNumber);
|
|
}
|
|
else if (memberVals0 == ":sideeffects")
|
|
{
|
|
listViewItem.AddRefreshButton();
|
|
IDEApp.sApp.RefreshWatches();
|
|
CheckClearDirtyWatches();
|
|
watch.mHasValue = true;
|
|
}
|
|
else if (memberVals0 == ":referenceId")
|
|
{
|
|
String.NewOrSet!(watch.mReferenceId, scope String(memberVals[1]));
|
|
}
|
|
else if (memberVals0 == ":repeat")
|
|
{
|
|
int startIdx = Int.Parse(scope String(memberVals[1]));
|
|
int count = Int.Parse(scope String(memberVals[2]));
|
|
int maxShow = Int.Parse(scope String(memberVals[3]));
|
|
|
|
String displayStr = scope String(memberVals[4]);
|
|
String evalStr = scope String(memberVals[5]);
|
|
|
|
if (count == 0)
|
|
continue;
|
|
|
|
Object[] formatParams = scope Object[1 + memberVals.Count - 6];
|
|
formatParams[0] = startIdx;
|
|
for (int32 i = 6; i < memberVals.Count; i++)
|
|
formatParams[1 + i - 6] = scope:: String(memberVals[i]);
|
|
|
|
watchSeriesInfo = new WatchSeriesInfo();
|
|
watchSeriesInfo.mStartMemberIdx = (int32)memberCount;
|
|
watchSeriesInfo.mDisplayTemplate = new String(displayStr);
|
|
watchSeriesInfo.mEvalTemplate = new String(evalStr);
|
|
watchSeriesInfo.mStartIdx = startIdx;
|
|
watchSeriesInfo.mCount = count;
|
|
watchSeriesInfo.mShowPageSize = (int32)maxShow;
|
|
watchSeriesInfo.mShowPages = 1;
|
|
|
|
WatchListViewItem memberItem;
|
|
if (memberCount >= listViewItem.GetChildCount())
|
|
memberItem = AddWatch("", "", listViewItem);
|
|
else
|
|
{
|
|
memberItem = (WatchListViewItem)listViewItem.GetChildAtIndex(memberCount);
|
|
if (memberItem.mWatchSeriesInfo != null)
|
|
{
|
|
var prevWatchSeriesInfo = memberItem.mWatchSeriesInfo;
|
|
watchSeriesInfo.mShowPages = prevWatchSeriesInfo.mShowPages;
|
|
watchSeriesInfo.mMoreButton = prevWatchSeriesInfo.mMoreButton;
|
|
watchSeriesInfo.mLessButton = prevWatchSeriesInfo.mLessButton;
|
|
|
|
// Only keep the series ID if it's the same display and evaluation -
|
|
// This keeps expanded items expanded when single stepping, but will cause them to refresh and close
|
|
// when we are actually evaluating a different value with the same name in a different context
|
|
if ((prevWatchSeriesInfo.mEvalTemplate == watchSeriesInfo.mEvalTemplate) && (prevWatchSeriesInfo.mDisplayTemplate == watchSeriesInfo.mDisplayTemplate))
|
|
watchSeriesInfo.mSeriesFirstVersion = prevWatchSeriesInfo.mSeriesFirstVersion;
|
|
|
|
memberItem.mWatchSeriesInfo.ReleaseRef();
|
|
}
|
|
}
|
|
|
|
memberItem.mWatchSeriesInfo = watchSeriesInfo;
|
|
//memberItem.mOwnsWatchSeriesInfo = true;
|
|
memberItem.mSeriesMemberIdx = 0;
|
|
memberCount++;
|
|
|
|
var memberWatch = ((WatchListViewItem)memberItem).mWatchEntry;
|
|
|
|
var formattedName = scope String();
|
|
formattedName.AppendF(displayStr, params formatParams);
|
|
String.NewOrSet!(memberWatch.mName, formattedName);
|
|
var formattedEval = scope String();
|
|
formattedEval.AppendF(evalStr, params formatParams);
|
|
String.NewOrSet!(memberWatch.mEvalStr, formattedEval);
|
|
|
|
memberItem.Label = memberWatch.mName;
|
|
|
|
if (wasNewExpression)
|
|
{
|
|
while (memberCount < listViewItem.GetChildCount())
|
|
{
|
|
WatchListViewItem checkMemberItem = (WatchListViewItem)listViewItem.GetChildAtIndex(memberCount);
|
|
if (checkMemberItem.mWatchSeriesInfo == null)
|
|
break;
|
|
listViewItem.RemoveChildItemAt(memberCount);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (memberCount < listViewItem.GetChildCount())
|
|
{
|
|
WatchListViewItem checkMemberItem = (WatchListViewItem)listViewItem.GetChildAtIndex(memberCount);
|
|
if (checkMemberItem.mWatchSeriesInfo == null)
|
|
break;
|
|
checkMemberItem.mWatchSeriesInfo.ReleaseRef();
|
|
watchSeriesInfo.AddRef();
|
|
checkMemberItem.mWatchSeriesInfo = watchSeriesInfo;
|
|
memberCount++;
|
|
}
|
|
}
|
|
|
|
// We update here to avoid doing a Draw with old series information (such as addresses)
|
|
memberItem.mMustUpdateBeforeEvaluate = true;
|
|
}
|
|
else if (memberVals0 == ":addrs")
|
|
{
|
|
WatchListViewItem memberItem = (WatchListViewItem)listViewItem.GetChildAtIndex(memberCount - 1);
|
|
String.NewOrSet!(memberItem.mWatchSeriesInfo.mAddrs, memberVals[1]);
|
|
memberItem.mWatchSeriesInfo.mAddrsEntrySize = 1;
|
|
}
|
|
else if (memberVals0 == ":addrsEntrySize")
|
|
{
|
|
int32 addrsEntrySize = int32.Parse(scope String(memberVals[1]));
|
|
WatchListViewItem memberItem = (WatchListViewItem)listViewItem.GetChildAtIndex(memberCount - 1);
|
|
memberItem.mWatchSeriesInfo.mAddrsEntrySize = addrsEntrySize;
|
|
}
|
|
else if (memberVals0 == ":continuation")
|
|
{
|
|
WatchListViewItem memberItem = (WatchListViewItem)listViewItem.GetChildAtIndex(memberCount - 1);
|
|
String.NewOrSet!(memberItem.mWatchSeriesInfo.mContinuationData, memberVals[1]);
|
|
}
|
|
else if (memberVals0 == ":action")
|
|
{
|
|
watch.mAction = new String(memberVals[1]);
|
|
listViewItem.AddActionButton();
|
|
}
|
|
else if (memberVals0 == ":language")
|
|
{
|
|
int32 language;
|
|
if (int32.Parse(memberVals[1]) case .Ok(out language))
|
|
{
|
|
watch.mLanguage = (.)language;
|
|
}
|
|
}
|
|
else if (memberVals0 == ":warn")
|
|
{
|
|
if (wasNewExpression)
|
|
{
|
|
gApp.ShowOutput();
|
|
gApp.OutputLineSmart("WARNING: {0}", memberVals[1]);
|
|
}
|
|
}
|
|
else
|
|
watch.ParseCmd(memberVals);
|
|
continue;
|
|
}
|
|
|
|
if (memberVals.Count >= 2)
|
|
{
|
|
WatchListViewItem memberItem;
|
|
if (memberCount >= listViewItem.GetChildCount())
|
|
{
|
|
memberItem = (WatchListViewItem)AddWatch("", "", listViewItem);
|
|
}
|
|
else
|
|
memberItem = (WatchListViewItem)listViewItem.GetChildAtIndex(memberCount);
|
|
var memberWatch = ((WatchListViewItem)memberItem).mWatchEntry;
|
|
memberWatch.mLanguage = watch.mLanguage;
|
|
|
|
memberItem.mBottomPadding = 0;
|
|
if (memberItem.mWatchSeriesInfo != null)
|
|
{
|
|
//if (memberItem.mSeriesMemberIdx == 0)
|
|
//delete memberItem.mWatchSeriesInfo;
|
|
//memberItem.mOwnsWatchSeriesInfo = false;
|
|
memberItem.mWatchSeriesInfo.ReleaseRef();
|
|
memberItem.mWatchSeriesInfo = null;
|
|
memberItem.mSeriesMemberIdx = 0;
|
|
}
|
|
String.NewOrSet!(memberWatch.mName, memberVals0);
|
|
String evalStr = scope String();
|
|
if (evalStr.AppendF(scope String(memberVals[1]), watch.mEvalStr) case .Err)
|
|
{
|
|
evalStr.Clear();
|
|
evalStr.Append("Format Error: {0}", scope String(memberVals[1]));
|
|
}
|
|
String.NewOrSet!(memberWatch.mEvalStr, evalStr);
|
|
memberItem.Label = memberWatch.mName;
|
|
memberCount++;
|
|
}
|
|
}
|
|
|
|
if ((watch.mReferenceId == null) && (watch.mEvalStr.Length > 0) && (!valueSubItem.mFailed))
|
|
{
|
|
// Allocate a referenceId if we didn't get one (was a temporary expression)
|
|
// Make it start with a zero so it parses but is easy to identify as not-an-identifier
|
|
watch.mReferenceId = new String();
|
|
watch.mReferenceId.AppendF("0{0}", ++WatchListView.sCurDynReferenceId);
|
|
}
|
|
|
|
while (listViewItem.GetChildCount() > memberCount)
|
|
listViewItem.RemoveChildItem(listViewItem.GetChildAtIndex(memberCount));
|
|
|
|
if ((listViewItem.GetChildCount() == 0) && (listViewItem.mOpenButton != null))
|
|
{
|
|
Widget.RemoveAndDelete(listViewItem.mOpenButton);
|
|
listViewItem.mOpenButton = null;
|
|
DeleteAndNullify!(listViewItem.mChildItems);
|
|
}
|
|
|
|
if (watch.mEvalStr.Length == 0)
|
|
watch.mResultType = WatchResultType.None;
|
|
|
|
watch.mHasValue = true;
|
|
watch.mHadValue = true;
|
|
}
|
|
|
|
public override void AddedToParent()
|
|
{
|
|
base.AddedToParent();
|
|
if (mDisabled)
|
|
mDisabledTicks = 9999;
|
|
}
|
|
|
|
public void CheckClearDirtyWatches()
|
|
{
|
|
var debugger = IDEApp.sApp.mDebugger;
|
|
if ((mWatchesDirty) && (debugger.mIsRunning) && (debugger.IsPaused()))
|
|
{
|
|
MarkDirty();
|
|
ClearWatchValues(mListView.GetRoot());
|
|
mWatchesDirty = false;
|
|
mHadStep = false;
|
|
mClearHadStep = false;
|
|
|
|
if (mIsAuto)
|
|
{
|
|
var parentItem = mListView.GetRoot();
|
|
|
|
var app = IDEApp.sApp;
|
|
String autosStr = scope String();
|
|
app.mDebugger.GetAutoLocals(app.IsInDisassemblyMode(), autosStr);
|
|
var autos = scope List<StringView>(autosStr.Split('\n'));
|
|
|
|
int32 curIdx;
|
|
for (curIdx = 0; curIdx < autos.Count; curIdx++)
|
|
{
|
|
String auto = scope String(autos[curIdx]);
|
|
if (auto.IsEmpty)
|
|
continue;
|
|
bool found = false;
|
|
|
|
while (curIdx < parentItem.GetChildCount())
|
|
{
|
|
var listViewItem = parentItem.GetChildAtIndex(curIdx);
|
|
if (listViewItem.mLabel == auto)
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
parentItem.RemoveChildItemAt(curIdx);
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
var listViewItem = AddWatch(auto);
|
|
var itemAtIdx = parentItem.GetChildAtIndex(curIdx);
|
|
if (itemAtIdx != listViewItem)
|
|
{
|
|
// Wrong order
|
|
parentItem.RemoveChildItem(listViewItem);
|
|
parentItem.InsertChild(listViewItem, itemAtIdx);
|
|
}
|
|
}
|
|
}
|
|
|
|
while (curIdx < mListView.GetRoot().GetChildCount())
|
|
parentItem.RemoveChildItemAt(curIdx);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
base.Update();
|
|
|
|
if (mDisabled)
|
|
mDisabledTicks++;
|
|
|
|
int childCount = mListView.GetRoot().GetChildCount();
|
|
if ((!mIsAuto) && ((childCount == 0) || (mListView.GetRoot().GetChildAtIndex(childCount - 1).mLabel.Length > 0)))
|
|
AddWatch("");
|
|
|
|
CheckClearDirtyWatches();
|
|
}
|
|
|
|
public static void AddSelectableMenuItem(Menu menu, String label, bool selected, Action action)
|
|
{
|
|
Debug.AssertNotStack(action);
|
|
Menu menuItem = menu.AddItem(label);
|
|
if (selected)
|
|
menuItem.mIconImage = DarkTheme.sDarkTheme.GetImage(.Check);
|
|
menuItem.mOnMenuItemSelected.Add(new (imenu) => action() ~ { delete action; });
|
|
}
|
|
|
|
public static void SetDisplayType(String referenceId, DebugManager.IntDisplayType intDisplayType, DebugManager.MmDisplayType mmDisplayType, DebugManager.FloatDisplayType floatDisplayType)
|
|
{
|
|
gApp.mDebugger.SetDisplayTypes(referenceId, intDisplayType, mmDisplayType, floatDisplayType);
|
|
gApp.RefreshWatches();
|
|
}
|
|
|
|
public static bool AddDisplayTypeMenu(String label, Menu menu, WatchResultType watchResultType, String referenceId, bool includeDefault)
|
|
{
|
|
bool hasInt = watchResultType.HasFlag(WatchResultType.Int);
|
|
bool hasFloat = watchResultType.HasFlag(WatchResultType.Float);
|
|
bool hasMM128 = watchResultType.HasFlag(WatchResultType.MM128);
|
|
bool canSetFormat = hasInt || hasFloat || hasMM128;
|
|
|
|
var debugger = IDEApp.sApp.mDebugger;
|
|
bool foundSpecific = debugger.GetDisplayTypes(referenceId, var intDisplayType, var mmDisplayType, var floatDisplayType);
|
|
if ((referenceId != null) && (!foundSpecific))
|
|
{
|
|
intDisplayType = .Default;
|
|
mmDisplayType = .Default;
|
|
floatDisplayType = .Default;
|
|
}
|
|
|
|
if (!canSetFormat)
|
|
return false;
|
|
|
|
Menu parentItem = menu.AddItem(label);
|
|
if (hasInt)
|
|
{
|
|
for (DebugManager.IntDisplayType i = default; i < DebugManager.IntDisplayType.COUNT; i++)
|
|
{
|
|
if ((i == 0) && (!includeDefault))
|
|
{
|
|
if (intDisplayType == 0)
|
|
intDisplayType = DebugManager.IntDisplayType.Decimal;
|
|
continue;
|
|
}
|
|
|
|
var toType = i;
|
|
AddSelectableMenuItem(parentItem, ToStackString!(i), intDisplayType == i,
|
|
new () => SetDisplayType(referenceId, toType, mmDisplayType, floatDisplayType));
|
|
}
|
|
}
|
|
|
|
if (hasFloat)
|
|
{
|
|
for (DebugManager.FloatDisplayType i = default; i < DebugManager.FloatDisplayType.COUNT; i++)
|
|
{
|
|
if ((i == 0) && (!includeDefault))
|
|
{
|
|
if (floatDisplayType == 0)
|
|
floatDisplayType = DebugManager.FloatDisplayType.Minimal;
|
|
continue;
|
|
}
|
|
|
|
var toType = i;
|
|
AddSelectableMenuItem(parentItem, ToStackString!(i), floatDisplayType == i,
|
|
new () => SetDisplayType(referenceId, intDisplayType, mmDisplayType, toType));
|
|
}
|
|
}
|
|
|
|
if (hasMM128)
|
|
{
|
|
for (DebugManager.MmDisplayType i = default; i < DebugManager.MmDisplayType.COUNT; i++)
|
|
{
|
|
var toType = i;
|
|
AddSelectableMenuItem(parentItem, ToStackString!(i), mmDisplayType == i,
|
|
new () => SetDisplayType(referenceId, intDisplayType, toType, floatDisplayType));
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static void ShowRightClickMenu(WatchPanel watchPanel, WatchListView listView, WatchListViewItem listViewItem, float x, float y)
|
|
{
|
|
if (watchPanel != null)
|
|
{
|
|
watchPanel.mDeselectOnFocusLost = false;
|
|
defer:: { watchPanel.mDeselectOnFocusLost = true; }
|
|
}
|
|
|
|
Menu menu = new Menu();
|
|
|
|
Menu anItem;
|
|
|
|
/*if (listViewItem.mParent != mListView.GetRoot())
|
|
{
|
|
anItem = menu.AddItem("Add Watch");
|
|
}*/
|
|
|
|
if (listViewItem != null)
|
|
{
|
|
var clickedHoverItem = listViewItem.GetSubItem(0) as HoverWatch.HoverListViewItem;
|
|
|
|
var watchEntry = listViewItem.mWatchEntry;
|
|
if (listViewItem.mParentItem != listView.GetRoot())
|
|
{
|
|
anItem = menu.AddItem("Add Watch");
|
|
anItem.mOnMenuItemSelected.Add(new (menu) =>
|
|
{
|
|
String compactEvalStr = scope String();
|
|
CompactChildExpression(listViewItem, compactEvalStr);
|
|
gApp.AddWatch(compactEvalStr);
|
|
});
|
|
}
|
|
|
|
AddDisplayTypeMenu("Default Display", menu, listViewItem.mWatchEntry.mResultType, null, false);
|
|
|
|
//Debug.WriteLine(String.Format("RefType: {0}", watchEntry.mReferenceId));
|
|
|
|
if (menu.mItems.Count > 0)
|
|
anItem = menu.AddItem();
|
|
|
|
if (watchEntry.mReferenceId != null)
|
|
AddDisplayTypeMenu("Watch Display", menu, listViewItem.mWatchEntry.mResultType, watchEntry.mReferenceId, true);
|
|
|
|
if (!watchEntry.IsConstant)
|
|
{
|
|
anItem = menu.AddItem("Break When Value Changes");
|
|
if (watchEntry.mMemoryBreakpointAddr == 0)
|
|
{
|
|
anItem.mOnMenuItemSelected.Add(new (evt) =>
|
|
{
|
|
String evalStr = scope String();
|
|
CompactChildExpression(listViewItem, evalStr);
|
|
if (evalStr.StartsWith("*"))
|
|
evalStr.Remove(0, 1);
|
|
else
|
|
evalStr.Insert(0, "&");
|
|
gApp.mBreakpointPanel.CreateMemoryBreakpoint(evalStr);
|
|
gApp.MarkDirty();
|
|
});
|
|
}
|
|
else
|
|
{
|
|
anItem.mIconImage = DarkTheme.sDarkTheme.GetImage(.Check);
|
|
anItem.mOnMenuItemSelected.Add(new (evt) =>
|
|
{
|
|
for (int breakIdx < gApp.mDebugger.mBreakpointList.Count)
|
|
{
|
|
let breakpoint = gApp.mDebugger.mBreakpointList[breakIdx];
|
|
if (breakpoint.mMemoryAddress == watchEntry.mMemoryBreakpointAddr)
|
|
{
|
|
gApp.mDebugger.DeleteBreakpoint(breakpoint);
|
|
gApp.RefreshWatches();
|
|
breakIdx--;
|
|
}
|
|
}
|
|
});
|
|
|
|
let configItem = menu.AddItem("Configure Breakpoint");
|
|
configItem.mOnMenuItemSelected.Add(new (evt) =>
|
|
{
|
|
for (int breakIdx < gApp.mDebugger.mBreakpointList.Count)
|
|
{
|
|
let breakpoint = gApp.mDebugger.mBreakpointList[breakIdx];
|
|
if (breakpoint.mMemoryAddress == watchEntry.mMemoryBreakpointAddr)
|
|
{
|
|
ConditionDialog dialog = new ConditionDialog();
|
|
dialog.Init(breakpoint);
|
|
dialog.PopupWindow(listView.mWidgetWindow);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
if (watchEntry.mResultType.HasFlag(.Pointer))
|
|
{
|
|
if (int.Parse(watchEntry.mEditInitialize) case .Ok(let addr))
|
|
{
|
|
int threadId;
|
|
gApp.mDebugger.GetStackAllocInfo(addr, out threadId, null);
|
|
if (threadId != 0)
|
|
{
|
|
anItem = menu.AddItem("Find on Stack");
|
|
anItem.mOnMenuItemSelected.Add(new (evt) =>
|
|
{
|
|
int stackIdx = -1;
|
|
gApp.mDebugger.GetStackAllocInfo(addr, let threadId, &stackIdx);
|
|
if (stackIdx != -1)
|
|
{
|
|
gApp.ShowCallstack();
|
|
gApp.mCallStackPanel.SelectCallStackIdx(stackIdx);
|
|
}
|
|
else if (threadId != 0)
|
|
{
|
|
gApp.ShowThreads();
|
|
gApp.mThreadPanel.SelectThreadId(threadId);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
void WithSelected(delegate void(ListViewItem) func)
|
|
{
|
|
var root = listView.GetRoot();
|
|
root.WithSelectedItems(func, false, true);
|
|
|
|
if (clickedHoverItem != null)
|
|
func(clickedHoverItem);
|
|
}
|
|
|
|
anItem = menu.AddItem("Copy Value");
|
|
anItem.mOnMenuItemSelected.Add(new (evt) =>
|
|
{
|
|
String selectedText = scope String();
|
|
WithSelected(scope (listViewItem) =>
|
|
{
|
|
if (!selectedText.IsEmpty)
|
|
{
|
|
selectedText.Append("\n");
|
|
}
|
|
var subItem = listViewItem.GetSubItem(1);
|
|
selectedText.Append(subItem.Label);
|
|
});
|
|
gApp.SetClipboardText(selectedText);
|
|
});
|
|
|
|
anItem = menu.AddItem("Copy Expression");
|
|
anItem.mOnMenuItemSelected.Add(new (evt) =>
|
|
{
|
|
String selectedText = scope String();
|
|
WithSelected(scope (listViewItem) =>
|
|
{
|
|
String evalStr = scope String();
|
|
CompactChildExpression((WatchListViewItem)listViewItem, evalStr);
|
|
if (!selectedText.IsEmpty)
|
|
{
|
|
selectedText.Append("\n");
|
|
}
|
|
selectedText.Append(evalStr);
|
|
});
|
|
gApp.SetClipboardText(selectedText);
|
|
});
|
|
|
|
if (watchPanel != null)
|
|
{
|
|
anItem = menu.AddItem("Delete Watch");
|
|
anItem.mOnMenuItemSelected.Add(new (evt) =>
|
|
{
|
|
watchPanel.DeleteSelectedItems();
|
|
});
|
|
}
|
|
}
|
|
|
|
if (menu.mItems.IsEmpty)
|
|
{
|
|
delete menu;
|
|
return;
|
|
}
|
|
MenuWidget menuWidget = ThemeFactory.mDefault.CreateMenuWidget(menu);
|
|
menuWidget.Init(listView.GetRoot(), x, y);
|
|
}
|
|
|
|
protected override void ShowRightClickMenu(Widget relWidget, float x, float y)
|
|
{
|
|
var focusedItem = (WatchListViewItem)mListView.GetRoot().FindFocusedItem();
|
|
ShowRightClickMenu(this, mListView, focusedItem, x, y);
|
|
}
|
|
|
|
void ListViewClicked(MouseEvent theEvent)
|
|
{
|
|
if ((theEvent.mBtn == 1) && (!mDisabled))
|
|
{
|
|
float aX, aY;
|
|
aX = theEvent.mX + mListView.GetRoot().mX;
|
|
aY = theEvent.mY + mListView.GetRoot().mY;
|
|
ShowRightClickMenu(mListView, aX, aY);
|
|
}
|
|
}
|
|
|
|
void ListViewMouseDown(MouseEvent theEvent)
|
|
{
|
|
mListView.GetRoot().SelectItemExclusively(null);
|
|
}
|
|
|
|
public override void KeyChar(char32 theChar)
|
|
{
|
|
base.KeyChar(theChar);
|
|
|
|
if ((mDisabled) || (theChar < (char8)32))
|
|
return;
|
|
|
|
var selectedItem = (WatchListViewItem)mListView.GetRoot().FindFirstSelectedItem();
|
|
if (selectedItem != null)
|
|
{
|
|
ListViewItemMouseDown(selectedItem, 2);
|
|
if (mEditWidget != null)
|
|
mEditWidget.KeyChar(theChar);
|
|
}
|
|
}
|
|
|
|
void DeleteSelectedItems()
|
|
{
|
|
var root = mListView.GetRoot();
|
|
List<ListViewItem> selectedItems = scope List<ListViewItem>();
|
|
root.WithSelectedItems(scope (listViewItem) =>
|
|
{
|
|
selectedItems.Add(listViewItem);
|
|
});
|
|
|
|
// Go through in reverse, to process children before their parents
|
|
for (int itemIdx = selectedItems.Count - 1; itemIdx >= 0; itemIdx--)
|
|
{
|
|
var selectedItem = selectedItems[itemIdx];
|
|
if ((selectedItem != null) && (selectedItem.mLabel.Length > 0) && (selectedItem.mParentItem == root))
|
|
{
|
|
int idx = root.mChildItems.IndexOf(selectedItem);
|
|
root.RemoveChildItem(selectedItem);
|
|
if (idx < root.mChildItems.Count)
|
|
root.SelectItemExclusively(root.mChildItems[idx]);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void TryRenameItem()
|
|
{
|
|
if (mEditWidget != null)
|
|
{
|
|
if (mEditingItem.mColumnIdx == 0)
|
|
{
|
|
let valueItem = (WatchListViewItem)mEditingItem.GetSubItem(1);
|
|
EditEvent evt = scope .();
|
|
evt.mSender = mEditWidget;
|
|
HandleRenameCancel(evt);
|
|
EditListViewItem(valueItem);
|
|
}
|
|
return;
|
|
}
|
|
|
|
var focusedItem = mListView.GetRoot().FindFocusedItem();
|
|
if (focusedItem != null)
|
|
{
|
|
EditListViewItem((WatchListViewItem)focusedItem);
|
|
if (mEditWidget == null)
|
|
{
|
|
EditListViewItem((WatchListViewItem)focusedItem.GetSubItem(1));
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void KeyDown(KeyCode keyCode, bool isRepeat)
|
|
{
|
|
if (keyCode == .Apps)
|
|
{
|
|
ShowRightClickMenu(mListView);
|
|
return;
|
|
}
|
|
|
|
base.KeyDown(keyCode, isRepeat);
|
|
mListView.KeyDown(keyCode, isRepeat);
|
|
if (!mIsAuto)
|
|
{
|
|
if (keyCode == KeyCode.F2)
|
|
{
|
|
TryRenameItem();
|
|
}
|
|
if (keyCode == KeyCode.Delete)
|
|
{
|
|
DeleteSelectedItems();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|