mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-10 04:22:20 +02:00
1051 lines
26 KiB
Beef
1051 lines
26 KiB
Beef
using Beefy.theme.dark;
|
|
using System;
|
|
using Beefy.widgets;
|
|
using Beefy.gfx;
|
|
using Beefy.events;
|
|
using Beefy.utils;
|
|
using System.Diagnostics;
|
|
using IDE.Compiler;
|
|
using System.Collections;
|
|
using System.Threading;
|
|
|
|
namespace IDE.ui
|
|
{
|
|
class ClassViewPanel : Panel
|
|
{
|
|
public class ClassViewListViewItem : IDEListViewItem
|
|
{
|
|
public float mLabelOffset;
|
|
public Object mRefObject;
|
|
public DataKind mKind;
|
|
public PendingEntry mMemberInfo ~ delete _;
|
|
public bool mProcessedLabel;
|
|
|
|
protected override float GetLabelOffset()
|
|
{
|
|
return mLabelOffset;
|
|
}
|
|
|
|
public override float ResizeComponents(float xOffset)
|
|
{
|
|
return base.ResizeComponents(xOffset);
|
|
}
|
|
|
|
public override void DrawSelect(Graphics g)
|
|
{
|
|
bool hasFocus = mListView.mHasFocus;
|
|
if ((mWidgetWindow.mFocusWidget != null) && (mWidgetWindow.mFocusWidget.HasParent(mListView)))
|
|
hasFocus = true;
|
|
let parent = (ClassViewListView)mListView;
|
|
if (parent.mPanel.mFindClassDialog != null)
|
|
hasFocus = true;
|
|
using (g.PushColor(hasFocus ? 0xFFFFFFFF : 0x80FFFFFF))
|
|
base.DrawSelect(g);
|
|
}
|
|
|
|
public override void Draw(Graphics g)
|
|
{
|
|
if ((!mProcessedLabel) && (mLabel != null))
|
|
{
|
|
uint32 color = 0;
|
|
switch (mMemberInfo.mKind)
|
|
{
|
|
case .Globals:
|
|
/*color = SourceEditWidgetContent.sTextColors[(int32)SourceElementType.Identifier];
|
|
color = Color.Mult(color, Color.Get(0.8f));*/
|
|
case .Namespace:
|
|
color = SourceEditWidgetContent.sTextColors[(int32)SourceElementType.Namespace];
|
|
case .Interface,
|
|
.Class,
|
|
.ValueType:
|
|
IDEUtils.ColorizeCodeString(mLabel, .Type);
|
|
case .Field,
|
|
.Property:
|
|
IDEUtils.ColorizeCodeString(mLabel, .Field);
|
|
case .Method,
|
|
.MethodOverride:
|
|
IDEUtils.ColorizeCodeString(mLabel, .Method);
|
|
default:
|
|
}
|
|
|
|
if (color != 0)
|
|
IDEUtils.InsertColorChange(mLabel, 0, color);
|
|
|
|
mProcessedLabel = true;
|
|
}
|
|
|
|
base.Draw(g);
|
|
|
|
if (mRefObject != null)
|
|
{
|
|
bool hasChanged = false;
|
|
var workspace = mRefObject as Workspace;
|
|
if (workspace != null)
|
|
hasChanged = workspace.mHasChanged;
|
|
var project = mRefObject as Project;
|
|
if (project != null)
|
|
hasChanged = project.mHasChanged;
|
|
if (hasChanged)
|
|
g.DrawString("*", g.mFont.GetWidth(mLabel) + mLabelOffset + LabelX + 1, 0);
|
|
}
|
|
}
|
|
|
|
public void Init()
|
|
{
|
|
Image icon = null;
|
|
|
|
switch (mKind)
|
|
{
|
|
case .Project:
|
|
icon = DarkTheme.sDarkTheme.GetImage(.Project);
|
|
case .Namespace:
|
|
icon = DarkTheme.sDarkTheme.GetImage(.Namespace);
|
|
case .Class:
|
|
icon = DarkTheme.sDarkTheme.GetImage(.Type_Class);
|
|
case .Interface:
|
|
icon = DarkTheme.sDarkTheme.GetImage(.Interface);
|
|
case .ValueType:
|
|
icon = DarkTheme.sDarkTheme.GetImage(.Type_ValueType);
|
|
case .Field:
|
|
icon = DarkTheme.sDarkTheme.GetImage(.Field);
|
|
case .Property:
|
|
icon = DarkTheme.sDarkTheme.GetImage(.Property);
|
|
case .Method,
|
|
.MethodOverride:
|
|
icon = DarkTheme.sDarkTheme.GetImage(.Method);
|
|
default:
|
|
}
|
|
IconImage = icon;
|
|
}
|
|
}
|
|
|
|
public class ClassViewListView : IDEListView
|
|
{
|
|
public ClassViewPanel mPanel;
|
|
|
|
protected override ListViewItem CreateListViewItem()
|
|
{
|
|
var anItem = new ClassViewListViewItem();
|
|
return anItem;
|
|
}
|
|
|
|
public override void KeyDown(KeyCode keyCode, bool isRepeat)
|
|
{
|
|
base.KeyDown(keyCode, isRepeat);
|
|
|
|
if (keyCode == .Return)
|
|
{
|
|
if (var item = (ClassViewListViewItem)GetRoot().FindFocusedItem())
|
|
mPanel.ShowItem(item);
|
|
}
|
|
else if (keyCode == .Tab)
|
|
{
|
|
if (this == mPanel.mTypeLV)
|
|
{
|
|
if (mWidgetWindow.IsKeyDown(.Shift))
|
|
mPanel.mSearchEdit.SetFocus();
|
|
else if (mPanel.mMemberLV != null)
|
|
{
|
|
if (mPanel.mMemberLV.GetRoot().GetChildCount() > 0)
|
|
{
|
|
if (mPanel.mMemberLV.GetRoot().FindFocusedItem() == null)
|
|
mPanel.mMemberLV.GetRoot().GetChildAtIndex(0).Focused = true;
|
|
mPanel.mMemberLV.SetFocus();
|
|
}
|
|
}
|
|
else
|
|
mPanel.mSearchEdit.SetFocus();
|
|
}
|
|
else
|
|
{
|
|
if (mWidgetWindow.IsKeyDown(.Shift))
|
|
mPanel.mTypeLV.SetFocus();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public class TypeArea : DockedWidget
|
|
{
|
|
public ClassViewPanel mPanel;
|
|
|
|
public override void Resize(float x, float y, float width, float height)
|
|
{
|
|
base.Resize(x, y, width, height);
|
|
mPanel.mSearchEdit.Resize(GS!(2), GS!(4), width - GS!(4), GS!(24));
|
|
mPanel.mTypeLV.Resize(0, GS!(30), width, height - GS!(30));
|
|
}
|
|
|
|
public override void DrawAll(Beefy.gfx.Graphics g)
|
|
{
|
|
base.DrawAll(g);
|
|
using (g.PushColor(0x80FFFFFF))
|
|
g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.Bkg), 0, mHeight - GS!(1), mWidth, GS!(4));
|
|
}
|
|
}
|
|
|
|
public class PendingEntry : IHashable, IEquatable<PendingEntry>
|
|
{
|
|
public DataKind mKind;
|
|
public bool mShow = true;
|
|
public String mName ~ delete _;
|
|
public PendingEntry mParent;
|
|
public HashSet<PendingEntry> mChildren;
|
|
public List<PendingEntry> mSortedList;
|
|
public Object mRefObject;
|
|
|
|
public String mFile ~ delete _;
|
|
public int mLine;
|
|
public int mColumn;
|
|
|
|
public this()
|
|
{
|
|
}
|
|
|
|
public this(DataKind kind, String name)
|
|
{
|
|
mKind = kind;
|
|
mName = name;
|
|
}
|
|
|
|
public ~this()
|
|
{
|
|
if (mSortedList != null)
|
|
{
|
|
DeleteContainerAndItems!(mSortedList);
|
|
delete mChildren;
|
|
}
|
|
else
|
|
{
|
|
DeleteContainerAndItems!(mChildren);
|
|
}
|
|
}
|
|
|
|
void Detach()
|
|
{
|
|
mName = null;
|
|
}
|
|
|
|
public bool Equals(PendingEntry other)
|
|
{
|
|
return this == other;
|
|
}
|
|
|
|
[Commutable]
|
|
public static bool operator==(PendingEntry val1, PendingEntry val2)
|
|
{
|
|
if (((Object)val1 == null) || ((Object)val2 == null))
|
|
return ((Object)val1 == null) && ((Object)val2 == null);
|
|
if (val1.mKind != val2.mKind)
|
|
{
|
|
if ((val1.mKind == .Project) || (val2.mKind == .Project))
|
|
return false;
|
|
if ((val1.mKind != .Namespace) && (val2.mKind != .Namespace))
|
|
return false;
|
|
}
|
|
return (val1.mName == val2.mName);
|
|
}
|
|
|
|
public int GetHashCode()
|
|
{
|
|
return mName.GetHashCode();
|
|
}
|
|
|
|
public PendingEntry AddChild(DataKind kind, String name)
|
|
{
|
|
if (mChildren == null)
|
|
{
|
|
mChildren = new HashSet<PendingEntry>();
|
|
PendingEntry child = new PendingEntry(kind, new String(name));
|
|
if (mKind != .Root)
|
|
child.mParent = this;
|
|
Debug.Assert(child != (Object)this);
|
|
mChildren.Add(child);
|
|
return child;
|
|
}
|
|
|
|
PendingEntry pendingEntry = scope PendingEntry(kind, name);
|
|
PendingEntry* entryPtr;
|
|
if (mChildren.Add(pendingEntry, out entryPtr))
|
|
{
|
|
let child = new PendingEntry(kind, new String(name));
|
|
if (mKind != .Root)
|
|
child.mParent = this;
|
|
Debug.Assert(child != (Object)this);
|
|
*entryPtr = child;
|
|
}
|
|
else
|
|
{
|
|
if (kind > (*entryPtr).mKind)
|
|
(*entryPtr).mKind = kind;
|
|
}
|
|
pendingEntry.Detach();
|
|
return *entryPtr;
|
|
}
|
|
|
|
public void Sort()
|
|
{
|
|
if (mChildren == null)
|
|
return;
|
|
|
|
mSortedList = new List<PendingEntry>();
|
|
for (var entry in mChildren)
|
|
{
|
|
entry.Sort();
|
|
mSortedList.Add(entry);
|
|
}
|
|
mSortedList.Sort(scope (a, b) =>
|
|
{
|
|
DataKind lk = a.mKind;
|
|
DataKind rk = b.mKind;
|
|
if (lk < .Field)
|
|
lk = .ValueType;
|
|
if (rk < .Field)
|
|
rk = .ValueType;
|
|
int comp = lk <=> rk;
|
|
if (comp != 0)
|
|
return comp;
|
|
return a.mName.CompareTo(b.mName, true);
|
|
});
|
|
}
|
|
}
|
|
|
|
public enum DataKind
|
|
{
|
|
Root,
|
|
Project,
|
|
Globals,
|
|
Namespace,
|
|
Interface,
|
|
Class,
|
|
ValueType,
|
|
|
|
Field,
|
|
Property,
|
|
Method,
|
|
MethodOverride,
|
|
}
|
|
|
|
class PendingInfo
|
|
{
|
|
public PendingEntry mPendingRoot ~ delete _;
|
|
public String mTypeStr ~ delete _;
|
|
public String mSearchStr ~ delete _;
|
|
public WaitEvent mDoneEvent = new .() ~ delete _;
|
|
}
|
|
|
|
public DarkDockingFrame mDockingFrame;
|
|
public DarkEditWidget mSearchEdit;
|
|
public ClassViewListView mTypeLV;
|
|
public ClassViewListView mMemberLV;
|
|
public int32 mLastCompileRevision;
|
|
public int32 mCompileRevisionDirtyDelay;
|
|
public bool mTypesDirty = true;
|
|
public bool mMembersDirty = true;
|
|
public int32 mWorkWait = -1;
|
|
public bool mWantsSubmit;
|
|
|
|
public String mRequestedTypeName = new .() ~ delete _;
|
|
public String mRequestedSearchStr = new .() ~ delete _;
|
|
PendingInfo mPendingInfo ~ delete _;
|
|
public List<PendingEntry> mHiddenEntries = new .() ~ DeleteContainerAndItems!(_);
|
|
public FindClassDialog mFindClassDialog;
|
|
|
|
public this(FindClassDialog findClassDialog = null)
|
|
{
|
|
mFindClassDialog = findClassDialog;
|
|
mSearchEdit = new DarkEditWidget();
|
|
mSearchEdit.mOnKeyDown.Add(new (evt) =>
|
|
{
|
|
if ((evt.mKeyCode == .Tab) && (evt.mKeyFlags == 0))
|
|
{
|
|
mTypeLV.SetFocus();
|
|
}
|
|
});
|
|
|
|
mTypeLV = new ClassViewListView();
|
|
mTypeLV.mPanel = this;
|
|
mTypeLV.SetShowHeader(false);
|
|
mTypeLV.InitScrollbars(true, true);
|
|
mTypeLV.mOnFocusChanged.Add(new => FocusChangedHandler);
|
|
mTypeLV.mOnItemMouseDown.Add(new => ItemMouseDown);
|
|
mTypeLV.mOnItemMouseClicked.Add(new => ListViewItemMouseClicked);
|
|
mTypeLV.mOnKeyDown.Add(new => ListViewKeyDown_ShowMenu);
|
|
|
|
if (mFindClassDialog == null)
|
|
{
|
|
mMemberLV = new ClassViewListView();
|
|
mMemberLV.mPanel = this;
|
|
mMemberLV.SetShowHeader(false);
|
|
mMemberLV.InitScrollbars(true, true);
|
|
mMemberLV.mOnItemMouseDown.Add(new => ItemMouseDown);
|
|
mMemberLV.mOnItemMouseClicked.Add(new => ListViewItemMouseClicked);
|
|
mMemberLV.mOnKeyDown.Add(new => ListViewKeyDown_ShowMenu);
|
|
|
|
var typeDock = new TypeArea();
|
|
typeDock.mPanel = this;
|
|
typeDock.AddWidget(mSearchEdit);
|
|
typeDock.AddWidget(mTypeLV);
|
|
var memberDock = new DockingProxy(mMemberLV);
|
|
|
|
mDockingFrame = new DarkDockingFrame();
|
|
mDockingFrame.mDrawBkg = false;
|
|
mDockingFrame.AddDockedWidget(typeDock, null, .Top);
|
|
mDockingFrame.AddDockedWidget(memberDock, typeDock, .Bottom);
|
|
AddWidget(mDockingFrame);
|
|
}
|
|
else
|
|
{
|
|
AddWidget(mTypeLV);
|
|
AddWidget(mSearchEdit);
|
|
|
|
mFindClassDialog.[Friend]mTabWidgets.Add(mTypeLV);
|
|
mFindClassDialog.[Friend]mTabWidgets.Add(mSearchEdit);
|
|
|
|
mSearchEdit.mOnKeyDown.Add(new => EditKeyDownHandler);
|
|
mSearchEdit.mOnSubmit.Add(new (evt) =>
|
|
{
|
|
mWantsSubmit = true;
|
|
});
|
|
}
|
|
|
|
//mListView.mDragEndHandler.Add(new => HandleDragEnd);
|
|
//mListView.mDragUpdateHandler.Add(new => HandleDragUpdate);
|
|
|
|
mTypeLV.mOnMouseDown.Add(new => ListViewMouseDown);
|
|
|
|
/*ListViewColumn column = mTypeLV.AddColumn(100, "Name");
|
|
column.mMinWidth = 40;*/
|
|
|
|
SetScaleData();
|
|
|
|
/*ListView lv = new MemberListView();
|
|
AddWidget(lv);
|
|
lv.Resize(100, 100, 300, 300);
|
|
let lvItem = lv.GetRoot().CreateChildItem();
|
|
lvItem.Label = "Yoofster";
|
|
lvItem.Focused = true;*/
|
|
}
|
|
|
|
public ~this()
|
|
{
|
|
if (mPendingInfo != null)
|
|
mPendingInfo.mDoneEvent.WaitFor();
|
|
}
|
|
|
|
void EditKeyDownHandler(KeyDownEvent evt)
|
|
{
|
|
switch (evt.mKeyCode)
|
|
{
|
|
case .Up,
|
|
.Down,
|
|
.Left,
|
|
.Right,
|
|
.PageUp,
|
|
.PageDown:
|
|
mTypeLV.KeyDown(evt.mKeyCode, false);
|
|
default:
|
|
}
|
|
|
|
if (evt.mKeyFlags == .Ctrl)
|
|
{
|
|
switch (evt.mKeyCode)
|
|
{
|
|
case .Home,
|
|
.End:
|
|
mTypeLV.KeyDown(evt.mKeyCode, false);
|
|
default:
|
|
}
|
|
}
|
|
}
|
|
|
|
void SetScaleData()
|
|
{
|
|
//mTypeLV.mColumns[0].mMinWidth = GS!(40);
|
|
|
|
mTypeLV.mIconX = GS!(20);
|
|
mTypeLV.mOpenButtonX = GS!(4);
|
|
mTypeLV.mLabelX = GS!(44);
|
|
mTypeLV.mChildIndent = GS!(16);
|
|
mTypeLV.mHiliteOffset = GS!(-2);
|
|
|
|
if (mMemberLV != null)
|
|
{
|
|
mMemberLV.mIconX = GS!(20);
|
|
mMemberLV.mOpenButtonX = GS!(4);
|
|
mMemberLV.mLabelX = GS!(44);
|
|
mMemberLV.mChildIndent = GS!(16);
|
|
mMemberLV.mHiliteOffset = GS!(-2);
|
|
}
|
|
}
|
|
|
|
public override void RehupScale(float oldScale, float newScale)
|
|
{
|
|
base.RehupScale(oldScale, newScale);
|
|
SetScaleData();
|
|
}
|
|
|
|
public override void FocusForKeyboard()
|
|
{
|
|
base.FocusForKeyboard();
|
|
mTypeLV.SetFocus();
|
|
}
|
|
|
|
public void StartRebuildUI()
|
|
{
|
|
Debug.Assert(mPendingInfo.mPendingRoot == null);
|
|
mPendingInfo.mPendingRoot = new .();
|
|
|
|
for (var project in IDEApp.sApp.mWorkspace.mProjects)
|
|
{
|
|
mPendingInfo.mPendingRoot.AddChild(.Project, project.mProjectName);
|
|
}
|
|
}
|
|
|
|
public override void Serialize(StructuredData data)
|
|
{
|
|
base.Serialize(data);
|
|
|
|
data.Add("Type", "ClassViewPanel");
|
|
}
|
|
|
|
public override bool Deserialize(StructuredData data)
|
|
{
|
|
return base.Deserialize(data);
|
|
}
|
|
|
|
void FocusChangedHandler(ListViewItem listViewItem)
|
|
{
|
|
if (listViewItem.Focused)
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
void ShowRightClickMenu(ProjectItem projectItem, float x, float y)
|
|
{
|
|
|
|
}
|
|
|
|
bool GetName(PendingEntry entry, String name)
|
|
{
|
|
if (entry.mParent != null)
|
|
{
|
|
if (GetName(entry.mParent, name))
|
|
name.Append(".");
|
|
}
|
|
|
|
if (entry.mKind == .Project)
|
|
{
|
|
name.Append(entry.mName);
|
|
name.Append(":");
|
|
return false;
|
|
}
|
|
|
|
name.Append(entry.mName);
|
|
return true;
|
|
}
|
|
|
|
bool GetName(ClassViewListViewItem item, String name)
|
|
{
|
|
if (item == null)
|
|
return false;
|
|
|
|
if (item.mMemberInfo != null)
|
|
return GetName(item.mMemberInfo, name);
|
|
|
|
if (item.mKind == .Project)
|
|
{
|
|
name.Append(item.mLabel);
|
|
name.Append(":");
|
|
return false;
|
|
}
|
|
let parentItem = (ClassViewListViewItem)item.mParentItem;
|
|
if (GetName(parentItem, name))
|
|
name.Append(".");
|
|
name.Append(item.mLabel);
|
|
return true;
|
|
}
|
|
|
|
void ShowItem(ClassViewListViewItem item)
|
|
{
|
|
void Show(String file, int line, int column)
|
|
{
|
|
gApp.RecordHistoryLocation(true);
|
|
gApp.ShowSourceFileLocation(file, -1, -1, line, column, .Always);
|
|
if (mFindClassDialog != null)
|
|
mFindClassDialog.Close();
|
|
}
|
|
|
|
if (item.mMemberInfo != null)
|
|
{
|
|
let info = item.mMemberInfo;
|
|
if (info.mFile != null)
|
|
{
|
|
Show(info.mFile, info.mLine, info.mColumn);
|
|
return;
|
|
}
|
|
}
|
|
|
|
String typeName = scope .();
|
|
GetName(item, typeName);
|
|
String info = scope .();
|
|
gApp.mBfResolveCompiler.GetTypeDefInfo(typeName, info);
|
|
|
|
for (let str in info.Split('\n'))
|
|
{
|
|
if (str.IsEmpty)
|
|
continue;
|
|
if (str[0] == 'S')
|
|
{
|
|
var srcInfo = str.Substring(1).Split('\t');
|
|
let filePath = srcInfo.GetNext().Get();
|
|
int lineNum = int.Parse(srcInfo.GetNext());
|
|
int column = int.Parse(srcInfo.GetNext());
|
|
Show(scope String()..Append(filePath), lineNum, column);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ItemMouseDown(ListViewItem item, float x, float y, int32 btnNum, int32 btnCount)
|
|
{
|
|
ListViewItemMouseDown(item, x, y, btnNum, btnCount);
|
|
let baseItem = (ClassViewListViewItem)item.GetSubItem(0);
|
|
if ((btnNum == 0) && (btnCount == 2))
|
|
{
|
|
ShowItem(baseItem);
|
|
}
|
|
}
|
|
|
|
void ListViewMouseDown(MouseEvent theEvent)
|
|
{
|
|
// We clicked off all items, so deselect
|
|
mTypeLV.GetRoot().WithSelectedItems(scope (item) => { item.Selected = false; } );
|
|
|
|
if (theEvent.mBtn == 1)
|
|
{
|
|
float aX, aY;
|
|
theEvent.GetRootCoords(out aX, out aY);
|
|
ShowRightClickMenu(null, aX, aY);
|
|
}
|
|
}
|
|
|
|
void ParseTypeInfo(String str)
|
|
{
|
|
List<PendingEntry> projectEntries = scope List<PendingEntry>();
|
|
PendingEntry curProject = null;
|
|
|
|
List<PendingEntry> partialRefs = scope List<PendingEntry>();
|
|
|
|
char8[] seps = scope char8[] ('.', '+');
|
|
|
|
for (var subStrRef in str.Split('\n'))
|
|
{
|
|
String param = scope String();
|
|
param.Reference(subStrRef);
|
|
if (param.Length == 0)
|
|
continue;
|
|
|
|
char8 cmd = param[0];
|
|
param.AdjustPtr(1);
|
|
|
|
if (cmd == 'S')
|
|
continue;
|
|
|
|
int addIdx = -1;
|
|
PendingEntry parentEntry = null;
|
|
|
|
if (cmd == '>')
|
|
{
|
|
int atPos = param.IndexOf('@');
|
|
addIdx = int.Parse(StringView(param, 0, atPos)).Get();
|
|
param.AdjustPtr(atPos + 1);
|
|
cmd = param[0];
|
|
param.AdjustPtr(1);
|
|
}
|
|
else if (cmd == '<')
|
|
{
|
|
int atPos = param.IndexOf('@');
|
|
int refIdx = int.Parse(StringView(param, 0, atPos)).Get();
|
|
parentEntry = partialRefs[refIdx];
|
|
param.AdjustPtr(atPos + 1);
|
|
cmd = param[0];
|
|
param.AdjustPtr(1);
|
|
}
|
|
else if (cmd == ':')
|
|
{
|
|
parentEntry = mPendingInfo.mPendingRoot;
|
|
cmd = param[0];
|
|
param.AdjustPtr(1);
|
|
}
|
|
|
|
switch (cmd)
|
|
{
|
|
case '=':
|
|
int32 idx = int32.Parse(param);
|
|
curProject = projectEntries[idx];
|
|
case '+':
|
|
curProject = mPendingInfo.mPendingRoot.AddChild(.Project, param);
|
|
projectEntries.Add(curProject);
|
|
if (mPendingInfo.mSearchStr != null)
|
|
curProject.mShow = false;
|
|
case 'i', 'c', 'v', 'g':
|
|
var curEntry = curProject;
|
|
|
|
DataKind kind = .ValueType;
|
|
if (cmd == 'i')
|
|
kind = .Interface;
|
|
else if (cmd == 'c')
|
|
kind = .Class;
|
|
else if (cmd == 'g')
|
|
kind = .Globals;
|
|
|
|
if (parentEntry != null)
|
|
{
|
|
if (parentEntry == (Object)mPendingInfo.mPendingRoot)
|
|
{
|
|
curEntry = parentEntry.AddChild(kind, param);
|
|
curEntry.mParent = curProject;
|
|
break;
|
|
}
|
|
|
|
if (parentEntry.mName == param)
|
|
{
|
|
parentEntry.mKind = kind;
|
|
break;
|
|
}
|
|
|
|
param.AdjustPtr(parentEntry.mName.Length + 1);
|
|
curEntry = parentEntry;
|
|
}
|
|
|
|
int nameIdx = 0;
|
|
for (var subName in param.Split(seps))
|
|
{
|
|
if (nameIdx < addIdx)
|
|
{
|
|
nameIdx++;
|
|
continue;
|
|
}
|
|
|
|
String subNameStr = scope String();
|
|
|
|
bool isLast = subName.Ptr + subName.Length == param.Ptr + param.Length;
|
|
|
|
if (nameIdx == addIdx)
|
|
{
|
|
DataKind insertKind = isLast ? kind : .Namespace;
|
|
subNameStr.Reference(StringView(param, 0, @subName.MatchPos));
|
|
curEntry = mPendingInfo.mPendingRoot.AddChild(insertKind, subNameStr);
|
|
curEntry.mParent = curProject;
|
|
Debug.Assert(curProject != (Object)curEntry);
|
|
partialRefs.Add(curEntry);
|
|
nameIdx++;
|
|
addIdx = -1;
|
|
continue;
|
|
}
|
|
|
|
DataKind insertKind = kind;
|
|
if (!isLast)
|
|
{
|
|
char8 nextChar = subName.Ptr[subName.Length];
|
|
if (nextChar == '.')
|
|
insertKind = .Namespace;
|
|
}
|
|
|
|
subNameStr.Reference(subName);
|
|
curEntry = curEntry.AddChild(insertKind, subNameStr);
|
|
|
|
nameIdx++;
|
|
}
|
|
default:
|
|
DataKind kind = default;
|
|
switch (cmd)
|
|
{
|
|
case 'I': kind = .Interface;
|
|
case 'C': kind = .Class;
|
|
case 'V': kind = .ValueType;
|
|
case 'F': kind = .Field;
|
|
case 'P': kind = .Property;
|
|
case 'M': kind = .Method;
|
|
case 'o': kind = .MethodOverride;
|
|
}
|
|
var itr = param.Split('\t');
|
|
let entry = mPendingInfo.mPendingRoot.AddChild(kind, scope String()..Reference(itr.GetNext().Get()));
|
|
if (entry.mFile == null)
|
|
{
|
|
if (itr.GetNext() case .Ok(let fileName))
|
|
{
|
|
entry.mFile = new String(fileName);
|
|
if (!entry.mFile.IsEmpty)
|
|
{
|
|
entry.mLine = int.Parse(itr.GetNext()).Get();
|
|
entry.mColumn = int.Parse(itr.GetNext()).Get();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Debug.Assert(addIdx == -1);
|
|
}
|
|
|
|
mPendingInfo.mPendingRoot.Sort();
|
|
}
|
|
|
|
void BkgGetTypeList()
|
|
{
|
|
var bfSystem = gApp.mBfResolveSystem;
|
|
var bfCompiler = gApp.mBfResolveCompiler;
|
|
|
|
bfSystem.Lock(0);
|
|
String outStr = scope String();
|
|
if (mPendingInfo.mSearchStr != null)
|
|
bfCompiler.GetTypeDefMatches(mPendingInfo.mSearchStr, outStr);
|
|
else
|
|
bfCompiler.GetTypeDefList(outStr);
|
|
bfSystem.Unlock();
|
|
|
|
ParseTypeInfo(outStr);
|
|
|
|
mPendingInfo.mDoneEvent.Set();
|
|
}
|
|
|
|
void BkgGetTypeInfo()
|
|
{
|
|
var bfSystem = gApp.mBfResolveSystem;
|
|
var bfCompiler = gApp.mBfResolveCompiler;
|
|
|
|
bfSystem.Lock(0);
|
|
String info = scope .();
|
|
bfCompiler.GetTypeDefInfo(mPendingInfo.mTypeStr, info);
|
|
bfSystem.Unlock();
|
|
ParseTypeInfo(info);
|
|
|
|
mPendingInfo.mDoneEvent.Set();
|
|
}
|
|
|
|
void HandleEntries(ClassViewListViewItem listViewItem, PendingEntry pendingEntry)
|
|
{
|
|
int32 curIdx = 0;
|
|
|
|
if (pendingEntry.mSortedList != null)
|
|
{
|
|
for (var child in pendingEntry.mSortedList)
|
|
{
|
|
if (!child.mShow)
|
|
{
|
|
@child.Current = null;
|
|
mHiddenEntries.Add(child);
|
|
continue;
|
|
}
|
|
|
|
ClassViewListViewItem childListViewItem;
|
|
if (curIdx < listViewItem.GetChildCount())
|
|
{
|
|
childListViewItem = (ClassViewListViewItem)listViewItem.GetChildAtIndex(curIdx);
|
|
}
|
|
else
|
|
{
|
|
childListViewItem = (ClassViewListViewItem)listViewItem.CreateChildItem();
|
|
}
|
|
childListViewItem.Label = child.mName;
|
|
childListViewItem.mRefObject = pendingEntry.mRefObject;
|
|
childListViewItem.mOpenOnDoubleClick = false;
|
|
childListViewItem.mKind = child.mKind;
|
|
childListViewItem.mProcessedLabel = false;
|
|
DeleteAndNullify!(childListViewItem.mMemberInfo);
|
|
//if (child.mFile != null)
|
|
{
|
|
childListViewItem.mMemberInfo = child;
|
|
@child.Current = null;
|
|
}
|
|
|
|
childListViewItem.Init();
|
|
|
|
HandleEntries(childListViewItem, child);
|
|
curIdx++;
|
|
}
|
|
}
|
|
|
|
while (curIdx < listViewItem.GetChildCount())
|
|
listViewItem.RemoveChildItemAt(curIdx);
|
|
listViewItem.TryUnmakeParent();
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
base.Update();
|
|
|
|
if (gApp.mBfResolveCompiler == null)
|
|
return;
|
|
|
|
var focusedItem = (ClassViewListViewItem)mTypeLV.GetRoot().FindFocusedItem();
|
|
var focusedStr = scope String();
|
|
if (focusedItem != null)
|
|
GetName(focusedItem, focusedStr);
|
|
|
|
if (gApp.mBfResolveCompiler != null)
|
|
{
|
|
int32 compileRevision = gApp.mBfResolveCompiler.GetCompileRevision();
|
|
if (mLastCompileRevision != compileRevision)
|
|
{
|
|
mCompileRevisionDirtyDelay = 30;
|
|
mLastCompileRevision = compileRevision;
|
|
}
|
|
}
|
|
|
|
if ((mCompileRevisionDirtyDelay > 0) && (--mCompileRevisionDirtyDelay == 0))
|
|
{
|
|
mTypesDirty = true;
|
|
mMembersDirty = true;
|
|
}
|
|
|
|
var searchStr = scope String();
|
|
mSearchEdit.GetText(searchStr);
|
|
searchStr.Trim();
|
|
|
|
if (mPendingInfo != null)
|
|
{
|
|
mWorkWait++;
|
|
if (gApp.mUpdateCnt % 10 == 0)
|
|
MarkDirty();
|
|
if (mPendingInfo.mDoneEvent.WaitFor(0))
|
|
{
|
|
if (mPendingInfo.mTypeStr != null)
|
|
{
|
|
if (mPendingInfo.mTypeStr == focusedStr)
|
|
HandleEntries((ClassViewListViewItem)mMemberLV.GetRoot(), mPendingInfo.mPendingRoot);
|
|
}
|
|
else if (mPendingInfo.mPendingRoot != null)
|
|
{
|
|
ClearAndDeleteItems(mHiddenEntries);
|
|
HandleEntries((ClassViewListViewItem)mTypeLV.GetRoot(), mPendingInfo.mPendingRoot);
|
|
focusedItem = (ClassViewListViewItem)mTypeLV.GetRoot().FindFocusedItem();
|
|
if ((focusedItem == null) && (mTypeLV.GetRoot().GetChildCount() != 0))
|
|
{
|
|
mTypeLV.GetRoot().GetChildAtIndex(0).Focused = true;
|
|
}
|
|
}
|
|
|
|
DeleteAndNullify!(mPendingInfo);
|
|
mWorkWait = -1;
|
|
MarkDirty();
|
|
}
|
|
}
|
|
|
|
if (mPendingInfo == null)
|
|
{
|
|
bool TryStartWork()
|
|
{
|
|
mWorkWait++;
|
|
return !gApp.mBfResolveCompiler.IsPerformingBackgroundOperation();
|
|
}
|
|
|
|
if (!searchStr.IsEmpty)
|
|
{
|
|
bool hasFocus = mHasFocus;
|
|
if ((mWidgetWindow.mFocusWidget != null) && (mWidgetWindow.mFocusWidget.HasParent(this)))
|
|
hasFocus = true;
|
|
if ((searchStr != mRequestedSearchStr) ||
|
|
((mTypesDirty) && (hasFocus)))
|
|
{
|
|
if (TryStartWork())
|
|
{
|
|
mPendingInfo = new .();
|
|
mPendingInfo.mPendingRoot = new .();
|
|
mPendingInfo.mSearchStr = new String(searchStr);
|
|
gApp.mBfResolveCompiler.DoBackground(new => BkgGetTypeList);
|
|
mRequestedSearchStr.Set(searchStr);
|
|
mTypesDirty = false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((searchStr != mRequestedSearchStr) || (mTypesDirty))
|
|
{
|
|
if (TryStartWork())
|
|
{
|
|
mPendingInfo = new .();
|
|
StartRebuildUI();
|
|
//Debug.WriteLine("Rebuilding UI...");
|
|
gApp.mBfResolveCompiler.DoBackground(new => BkgGetTypeList);
|
|
mRequestedSearchStr.Set(searchStr);
|
|
mTypesDirty = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((mPendingInfo == null) && (mMemberLV != null))
|
|
{
|
|
if ((mRequestedTypeName != focusedStr) || (mMembersDirty))
|
|
{
|
|
if (TryStartWork())
|
|
{
|
|
mPendingInfo = new PendingInfo();
|
|
mPendingInfo.mTypeStr = new String(focusedStr);
|
|
mPendingInfo.mPendingRoot = new .();
|
|
gApp.mBfResolveCompiler.DoBackground(new => BkgGetTypeInfo);
|
|
mRequestedTypeName.Set(focusedStr);
|
|
mMembersDirty = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mWorkWait == -1)
|
|
{
|
|
if (mWantsSubmit)
|
|
{
|
|
mTypeLV.KeyDown(.Return, false);
|
|
mWantsSubmit = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void Resize(float x, float y, float width, float height)
|
|
{
|
|
base.Resize(x, y, width, height);
|
|
if (mDockingFrame != null)
|
|
mDockingFrame.Resize(0, 0, mWidth, mHeight);
|
|
else
|
|
{
|
|
float insetSize = GS!(6);
|
|
mTypeLV.Resize(GS!(6), GS!(6), mWidth - GS!(12), mHeight - GS!(32));
|
|
mSearchEdit.Resize(insetSize, mTypeLV.mY + mTypeLV.mHeight + insetSize, mWidth - insetSize - insetSize, GS!(22));
|
|
}
|
|
}
|
|
|
|
public override void DrawAll(Graphics g)
|
|
{
|
|
base.DrawAll(g);
|
|
|
|
void DrawRefresh(Widget widget, int life)
|
|
{
|
|
widget.SelfToOtherTranslate(this, 0, 0, var x, var y);
|
|
|
|
using (g.PushColor(0x60505050))
|
|
g.FillRect(x, y, widget.Width, widget.Height);
|
|
IDEUtils.DrawWait(g, x + widget.Width/2, y + widget.Height/2, life);
|
|
}
|
|
|
|
if (mWorkWait >= 30)
|
|
{
|
|
bool hasFocus = mHasFocus;
|
|
if ((mWidgetWindow.mFocusWidget != null) && (mWidgetWindow.mFocusWidget.HasParent(this)))
|
|
hasFocus = true;
|
|
bool hasContent = (mTypeLV.GetRoot().GetChildCount() > 0) || (!mSearchEdit.IsWhiteSpace());
|
|
if ((hasFocus) || (!hasContent))
|
|
{
|
|
if (mPendingInfo?.mTypeStr != null)
|
|
DrawRefresh(mMemberLV, mUpdateCnt);
|
|
else
|
|
DrawRefresh(mTypeLV, mUpdateCnt);
|
|
}
|
|
}
|
|
|
|
if (mFindClassDialog != null)
|
|
IDEUtils.DrawOutline(g, mTypeLV);
|
|
}
|
|
}
|
|
}
|