mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-17 15:46:05 +02:00
2132 lines
61 KiB
Beef
2132 lines
61 KiB
Beef
#pragma warning disable 168
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Diagnostics;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Beefy;
|
|
using Beefy.gfx;
|
|
using Beefy.widgets;
|
|
using Beefy.theme.dark;
|
|
using Beefy.events;
|
|
using Beefy.geom;
|
|
using System.IO;
|
|
|
|
namespace IDE.ui
|
|
{
|
|
public class SearchEditWidget : DarkEditWidget
|
|
{
|
|
public int mSearchVersion;
|
|
|
|
protected override void SetupInsets()
|
|
{
|
|
mScrollContentInsets.Set(GS!(3), GS!(23), GS!(3), GS!(3));
|
|
}
|
|
}
|
|
|
|
public class KeysEditWidgetContent : DarkEditWidgetContent
|
|
{
|
|
public override void MouseDown(float x, float y, int32 btn, int32 btnCount)
|
|
{
|
|
// Disable
|
|
}
|
|
}
|
|
|
|
public class KeysEditWidget : DarkEditWidget
|
|
{
|
|
public this() : base(new KeysEditWidgetContent())
|
|
{
|
|
mEditWidgetContent.mEditWidget = this;
|
|
mOnKeyDown.Add(new => KeyDownEvent);
|
|
}
|
|
|
|
void KeyDownEvent(KeyDownEvent evt)
|
|
{
|
|
if ((evt.mKeyCode == .Control) ||
|
|
(evt.mKeyCode == .Shift) ||
|
|
(evt.mKeyCode == .Alt) ||
|
|
(evt.mKeyCode == .RAlt))
|
|
return;
|
|
|
|
if ((evt.mKeyFlags.HeldKeys == 0) &&
|
|
(evt.mKeyCode == .Escape))
|
|
{
|
|
evt.mHandled = false;
|
|
return;
|
|
}
|
|
|
|
var keyState = scope KeyState();
|
|
keyState.mKeyCode = evt.mKeyCode;
|
|
keyState.mKeyFlags = evt.mKeyFlags.HeldKeys;
|
|
|
|
if (keyState.mKeyFlags.HeldKeys == 0)
|
|
{
|
|
if (keyState.mKeyCode == .Return)
|
|
return;
|
|
}
|
|
|
|
evt.mHandled = true;
|
|
var str = scope String();
|
|
keyState.ToString(str);
|
|
|
|
|
|
if (HasKeys)
|
|
{
|
|
str.Insert(0, ", ");
|
|
mEditWidgetContent.mIsReadOnly = false;
|
|
Content.InsertAtCursor(str);
|
|
mEditWidgetContent.mIsReadOnly = true;
|
|
}
|
|
else
|
|
{
|
|
if ((evt.mKeyFlags.HeldKeys == 0) &&
|
|
((evt.mKeyCode == .Delete) || (evt.mKeyCode == .Backspace)) &&
|
|
((Content.HasSelection()) || (!HasKeys)))
|
|
{
|
|
if ((evt.mKeyCode == .Delete) || (evt.mKeyCode == .Backspace))
|
|
{
|
|
Content.ClearText();
|
|
return;
|
|
}
|
|
}
|
|
|
|
mEditWidgetContent.mIsReadOnly = false;
|
|
Content.InsertAtCursor(str);
|
|
mEditWidgetContent.mIsReadOnly = true;
|
|
}
|
|
}
|
|
|
|
public override void MouseDown(float x, float y, int32 btn, int32 btnCount)
|
|
{
|
|
base.MouseDown(x, y, btn, btnCount);
|
|
}
|
|
|
|
public bool HasKeys
|
|
{
|
|
get
|
|
{
|
|
var str = scope String();
|
|
GetText(str);
|
|
return !str.IsEmpty && !str.StartsWith("<");
|
|
}
|
|
}
|
|
}
|
|
|
|
public class PropertiesDialog : IDEDialog
|
|
{
|
|
public interface IMultiValued
|
|
{
|
|
void GetValue(int idx, String outValue);
|
|
bool SetValue(int idx, StringView value);
|
|
}
|
|
|
|
class OwnedStringList : List<String>
|
|
{
|
|
|
|
}
|
|
|
|
protected class ValueContainer<T>
|
|
{
|
|
public T mValue;
|
|
}
|
|
|
|
protected class MoveItemWidget : Widget
|
|
{
|
|
public int32 mArrowDir;
|
|
|
|
public override void Draw(Graphics g)
|
|
{
|
|
base.Draw(g);
|
|
//g.FillRect(0, 0, mWidth, mHeight);
|
|
|
|
if (mArrowDir == -1)
|
|
{
|
|
using (g.PushScale(1, -1))
|
|
g.Draw(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.ArrowMoveDown), 0, -20);
|
|
}
|
|
else
|
|
{
|
|
g.Draw(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.ArrowMoveDown), 0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected class PropPage
|
|
{
|
|
public enum Flags
|
|
{
|
|
None = 0,
|
|
AllowSearch = 1,
|
|
AllowReset = 2,
|
|
}
|
|
|
|
public int32 mCategoryType;
|
|
public DarkListView mPropertiesListView ~ delete _;
|
|
public Dictionary<ListViewItem, PropEntry[]> mPropEntries = new .() ~ delete _;
|
|
public bool mHasChanges;
|
|
public Flags mFlags;
|
|
|
|
public this()
|
|
{
|
|
//Debug.WriteLine("PropPage this {0}", this);
|
|
}
|
|
|
|
public ~this()
|
|
{
|
|
//Debug.WriteLine("PropPage ~this {0}", this);
|
|
|
|
for (var propEntryArr in mPropEntries.Values)
|
|
{
|
|
for (var propEntry in propEntryArr)
|
|
delete propEntry;
|
|
delete propEntryArr;
|
|
}
|
|
if (mPropertiesListView.mParent != null)
|
|
mPropertiesListView.RemoveSelf();
|
|
}
|
|
}
|
|
|
|
protected class PropEntry
|
|
{
|
|
public enum Flags
|
|
{
|
|
None,
|
|
BrowseForFile,
|
|
BrowseForFolder,
|
|
}
|
|
|
|
public enum MultiEncodeKind
|
|
{
|
|
Semicolon,
|
|
Extended // Uses /v to split
|
|
}
|
|
|
|
public Flags mFlags;
|
|
public DarkListViewItem mListViewItem;
|
|
public Object mTarget;
|
|
public String mPropertyName ~ delete _;
|
|
public FieldInfo mFieldInfo;
|
|
public Action mApplyAction ~ delete _;
|
|
public String[] mOptionValues ~ DeleteContainerAndItems!(_);
|
|
public String mNotSetString;
|
|
public List<DarkComboBox> mComboBoxes ~ delete _;
|
|
public DarkCheckBox mCheckBox;
|
|
public Variant mCurValue ~ DisposeVariant(ref _);
|
|
public Variant mOrigValue ~ DisposeVariant(ref _);
|
|
public PropertyBag mProperties ~ delete _;
|
|
public Event<delegate bool()> mOnUpdate ~ _.Dispose();
|
|
public bool mDisabled;
|
|
public bool mMultiRootReadOnly;
|
|
public uint32? mColorOverride;
|
|
public String mRelPath ~ delete _;
|
|
public bool mIsTypeWildcard;
|
|
public bool mAllowMultiline;
|
|
public bool mReadOnly;
|
|
public Insets mEditInsets ~ delete _;
|
|
|
|
public ~this()
|
|
{
|
|
|
|
}
|
|
|
|
public static void DisposeVariant(ref Variant variant)
|
|
{
|
|
if ((variant.OwnsMemory) && (variant.IsObject))
|
|
{
|
|
var obj = variant.Get<Object>();
|
|
if (var strList = obj as String[])
|
|
{
|
|
for (var str in strList)
|
|
delete str;
|
|
}
|
|
if (var strList = obj as List<String>)
|
|
{
|
|
for (var str in strList)
|
|
delete str;
|
|
}
|
|
if (var keyList = obj as List<KeyState>)
|
|
{
|
|
for (var keyState in keyList)
|
|
delete keyState;
|
|
}
|
|
}
|
|
variant.Dispose();
|
|
}
|
|
|
|
public static bool IsVariantEqual(Variant lhs, Variant rhs)
|
|
{
|
|
//var curEq = lhs as IEquatable;
|
|
//if (curEq.Equals(rhs))
|
|
//return false;
|
|
|
|
//TODO: Implement equals
|
|
var type = lhs.VariantType;
|
|
if (type.IsObject)
|
|
{
|
|
Object obj = lhs.Get<Object>();
|
|
var iEquatable = obj as IEquatable;
|
|
if (iEquatable != null)
|
|
return iEquatable.Equals(rhs.Get<Object>());
|
|
}
|
|
|
|
#unwarn
|
|
var origType = rhs.VariantType;
|
|
Debug.Assert(type == rhs.VariantType);
|
|
|
|
#unwarn
|
|
var keyStateListType = typeof(List<KeyState>);
|
|
|
|
if (type == typeof(String))
|
|
return Variant.Equals!<String>(lhs, rhs);
|
|
else if (type == typeof(bool))
|
|
return Variant.Equals!<bool>(lhs, rhs);
|
|
else if (type == typeof(Color))
|
|
return Variant.Equals!<Color>(lhs, rhs);
|
|
else if (type.IsNullable)
|
|
{
|
|
return lhs == rhs;
|
|
}
|
|
else if (type == typeof(List<KeyState>))
|
|
{
|
|
let curVal = lhs.Get<List<KeyState>>();
|
|
let origVal = rhs.Get<List<KeyState>>();
|
|
if (curVal.Count != origVal.Count)
|
|
return false;
|
|
for (int32 i = 0; i < curVal.Count; i++)
|
|
{
|
|
if (curVal[i] != origVal[i])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
else if (lhs.VariantType.IsGenericType)
|
|
{
|
|
let curVal = lhs.Get<List<String>>();
|
|
let origVal = rhs.Get<List<String>>();
|
|
if (curVal.Count != origVal.Count)
|
|
return false;
|
|
for (int32 i = 0; i < curVal.Count; i++)
|
|
{
|
|
if (curVal[i] != origVal[i])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
else if (type.IsObject)
|
|
{
|
|
var lhsObj = lhs.Get<Object>();
|
|
var rhsObj = rhs.Get<Object>();
|
|
|
|
if ((var lhsEq = lhsObj as IEquatable) && (var rhsEq = rhsObj as IEquatable))
|
|
{
|
|
return lhsEq.Equals(rhsEq);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
else // Could be an int or enum
|
|
return Variant.Equals!<int32>(lhs, rhs);
|
|
}
|
|
|
|
public bool HasChanged()
|
|
{
|
|
return !IsVariantEqual(mCurValue, mOrigValue);
|
|
}
|
|
|
|
public void ApplyValue()
|
|
{
|
|
var type = mCurValue.VariantType;
|
|
if (type == typeof(String))
|
|
{
|
|
if (mApplyAction != null)
|
|
mApplyAction();
|
|
String prevString = mOrigValue.Get<String>();
|
|
String curString = mCurValue.Get<String>();
|
|
prevString.Set(curString);
|
|
}
|
|
else if (type == typeof(List<KeyState>))
|
|
{
|
|
let prevList = mOrigValue.Get<List<KeyState>>();
|
|
let curList = mCurValue.Get<List<KeyState>>();
|
|
|
|
ClearAndDeleteItems(prevList);
|
|
for (var keyState in curList)
|
|
{
|
|
prevList.Add(keyState.Clone());
|
|
}
|
|
}
|
|
else if (type == typeof(List<String>))
|
|
{
|
|
List<String> prevList = mOrigValue.Get<List<String>>();
|
|
List<String> curList = mCurValue.Get<List<String>>();
|
|
|
|
ClearAndDeleteItems(prevList);
|
|
for (var str in curList)
|
|
{
|
|
prevList.Add(new String(str));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (mApplyAction != null)
|
|
{
|
|
mApplyAction();
|
|
}
|
|
else
|
|
{
|
|
Debug.Assert(type.IsPrimitive || type.IsEnum || type.IsNullable);
|
|
Debug.Assert(!mCurValue.OwnsMemory); // 'Large' structs not supported
|
|
mOrigValue = mCurValue;
|
|
}
|
|
if (mFieldInfo != default(FieldInfo))
|
|
mFieldInfo.SetValue(mTarget, mCurValue);
|
|
}
|
|
}
|
|
|
|
/*public void Init()
|
|
{
|
|
|
|
}*/
|
|
}
|
|
|
|
protected const uint32 cHeaderColor = 0xFFE8E8E8;
|
|
|
|
public class CategoryListViewItem : DarkListViewItem
|
|
{
|
|
public int32 mCategoryIdx;
|
|
|
|
public override void DrawSelect(Graphics g)
|
|
{
|
|
using (g.PushColor(mListView.mHasFocus ? 0xFFFFFFFF : 0x80FFFFFF))
|
|
base.DrawSelect(g);
|
|
}
|
|
}
|
|
|
|
public class CategoryListView : DarkListView
|
|
{
|
|
protected override ListViewItem CreateListViewItem()
|
|
{
|
|
return new CategoryListViewItem();
|
|
}
|
|
|
|
public override void KeyDown(KeyCode keyCode, bool isRepeat)
|
|
{
|
|
var focusedListViewItem = GetRoot().FindFocusedItem();
|
|
|
|
bool changeFocus = (keyCode == .Tab) && (mWidgetWindow.GetKeyFlags(true) == .None);
|
|
if ((keyCode == .Right) && ((focusedListViewItem == null) || (focusedListViewItem.GetChildCount() == 0)))
|
|
changeFocus = true;
|
|
|
|
if (changeFocus)
|
|
{
|
|
var propertiesDialog = (PropertiesDialog)mParent;
|
|
var propListView = propertiesDialog.mPropPage.mPropertiesListView;
|
|
propListView.SetFocus();
|
|
return;
|
|
}
|
|
|
|
base.KeyDown(keyCode, isRepeat);
|
|
}
|
|
}
|
|
|
|
|
|
public class PropListViewItem : DarkListViewItem
|
|
{
|
|
public override void DrawSelect(Graphics g)
|
|
{
|
|
SelfToOtherTranslate(mListView, 0, 0, var parentX, var parentY);
|
|
var width = mListView.mColumns[0].mWidth;
|
|
|
|
using (g.PushColor(mListView.mHasFocus ? 0xFFFFFFFF : 0x80FFFFFF))
|
|
using (g.PushColor(0x20FFFFFF))
|
|
g.FillRect(-parentX, 0, width, mHeight);
|
|
}
|
|
}
|
|
|
|
public class PropListView : DarkListView
|
|
{
|
|
|
|
protected override ListViewItem CreateListViewItem()
|
|
{
|
|
return new PropListViewItem();
|
|
}
|
|
|
|
public override void SetFocus()
|
|
{
|
|
base.SetFocus();
|
|
|
|
if (GetRoot().FindFocusedItem() == null)
|
|
{
|
|
for (int idx < GetRoot().GetChildCount())
|
|
{
|
|
var item = GetRoot().GetChildAtIndex(idx);
|
|
if (item.mSelfHeight > 0)
|
|
{
|
|
item.Focused = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void KeyDown(KeyCode keyCode, bool isRepeat)
|
|
{
|
|
var propertiesDialog = (PropertiesDialog)mParent;
|
|
|
|
let keyFlags = mWidgetWindow.GetKeyFlags(true);
|
|
bool changeFocus = (keyCode == .Tab) && (keyFlags == .Shift);
|
|
if (keyCode == .Left)
|
|
{
|
|
var selectedItem = GetRoot().FindFocusedItem();
|
|
if ((selectedItem != null) && (selectedItem.mParentItem == GetRoot()))
|
|
changeFocus = true;
|
|
}
|
|
|
|
if (changeFocus)
|
|
{
|
|
propertiesDialog.mCategorySelector.SetFocus();
|
|
return;
|
|
}
|
|
|
|
base.KeyDown(keyCode, isRepeat);
|
|
}
|
|
|
|
public override void MouseDown(float x, float y, int32 btn, int32 btnCount)
|
|
{
|
|
base.MouseDown(x, y, btn, btnCount);
|
|
GetRoot().SelectItemExclusively(null);
|
|
}
|
|
}
|
|
|
|
protected Object mCurPropertiesTarget;
|
|
protected Object[] mCurPropertiesTargets ~ delete _;
|
|
protected CategoryListView mCategorySelector;
|
|
protected bool mCancelingEdit;
|
|
protected PropPage mPropPage;
|
|
protected EditWidget mPropEditWidget;
|
|
protected ButtonWidget mApplyButton;
|
|
protected SearchEditWidget mSearchEdit;
|
|
protected DarkButton mResetButton;
|
|
protected PropEntry[] mEditingProps ~ delete _;
|
|
protected ListViewItem mEditingListViewItem;
|
|
protected Widget mPreviousFocus;
|
|
protected List<CategoryListViewItem> mCategoryListViewItems = new List<CategoryListViewItem>() ~ delete _;
|
|
protected bool mHideSelector;
|
|
|
|
protected virtual float TopY
|
|
{
|
|
get
|
|
{
|
|
return GS!(32);
|
|
}
|
|
}
|
|
|
|
public this()
|
|
{
|
|
//mMinWidth = GS!(320);
|
|
|
|
mWindowFlags = .ClientSized | .TopMost | .Caption | .Border | .SysMenu | .Resizable | .PopupPosition;
|
|
|
|
mButtonBottomMargin = GS!(6);
|
|
mButtonRightMargin = GS!(6);
|
|
AddOkCancelButtons(new (evt) => { evt.mCloseDialog = ApplyChanges(); }, null, 0, 1);
|
|
mApplyButton = AddButton("Apply", new (evt) => { evt.mCloseDialog = false; ApplyChanges(); });
|
|
|
|
mCategorySelector = new CategoryListView();
|
|
mCategorySelector.mHiliteOffset = GS!(-2);
|
|
mCategorySelector.SetShowHeader(false);
|
|
mCategorySelector.InitScrollbars(false, false);
|
|
mCategorySelector.mAutoFocus = true;
|
|
|
|
mCategorySelector.mAllowMultiSelect = false;
|
|
mCategorySelector.mOnKeyDown.Add(new (key) => ChildKeyDown(key.mKeyCode));
|
|
mCategorySelector.mOnFocusChanged.Add(new (listViewItem) => { if (listViewItem.Focused) CategoryChanged(listViewItem); });
|
|
mCategorySelector.mChildIndent = GS!(16);
|
|
|
|
AddWidget(mCategorySelector);
|
|
mTabWidgets.Insert(0, mCategorySelector);
|
|
}
|
|
|
|
public ~this()
|
|
{
|
|
|
|
}
|
|
|
|
public override void AddedToParent()
|
|
{
|
|
base.AddedToParent();
|
|
mCategorySelector.SetFocus();
|
|
}
|
|
|
|
protected override void RehupMinSize()
|
|
{
|
|
mWidgetWindow.SetMinimumSize(GS!(320), GS!(180), true);
|
|
}
|
|
|
|
public override bool HandleTab(int dir)
|
|
{
|
|
if ((dir == 1) && (var propListView = mWidgetWindow.mFocusWidget as PropListView))
|
|
{
|
|
var selectedItem = propListView.GetRoot().FindFocusedItem();
|
|
if ((selectedItem != null) && (selectedItem.GetSubItemCount() == 2))
|
|
{
|
|
MouseEvent evt = scope .();
|
|
var valueItem = selectedItem.GetSubItem(1);
|
|
evt.mX = -1;
|
|
evt.mY = -1;
|
|
evt.mSender = valueItem;
|
|
valueItem.mOnMouseDown(evt);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return base.HandleTab(dir);
|
|
}
|
|
|
|
protected void CreatePropPage(int32 categoryType, PropPage.Flags flags = .None)
|
|
{
|
|
mPropPage = new PropPage();
|
|
mPropPage.mCategoryType = categoryType;
|
|
mPropPage.mFlags = flags;
|
|
|
|
mPropPage.mPropertiesListView = new PropListView();
|
|
mPropPage.mPropertiesListView.mAutoFocus = false;
|
|
mPropPage.mPropertiesListView.mAllowMultiSelect = false;
|
|
mPropPage.mPropertiesListView.mHiliteOffset = GS!(-2);
|
|
var column = mPropPage.mPropertiesListView.AddColumn(GS!(220), "Title");
|
|
column.mMinWidth = GS!(80);
|
|
mPropPage.mPropertiesListView.AddColumn(GS!(180), "Value");
|
|
}
|
|
|
|
protected void RemovePropPage()
|
|
{
|
|
if (mPropPage != null)
|
|
{
|
|
mTabWidgets.Remove(mPropPage.mPropertiesListView);
|
|
mPropPage.mPropertiesListView.RemoveSelf();
|
|
mPropPage = null;
|
|
}
|
|
}
|
|
|
|
protected virtual void ShowPropPage(int32 categoryTypeInt)
|
|
{
|
|
RemovePropPage();
|
|
MarkDirty();
|
|
}
|
|
|
|
protected void UpdateSearch()
|
|
{
|
|
String searchStr = scope String();
|
|
if (mSearchEdit != null)
|
|
{
|
|
mSearchEdit.GetText(searchStr);
|
|
searchStr.Trim();
|
|
}
|
|
|
|
var listView = mPropPage.mPropertiesListView;
|
|
float lineSpacing = listView.mFont.GetLineSpacing();
|
|
if (searchStr.IsEmpty)
|
|
{
|
|
listView.GetRoot().WithItems(scope (item) =>
|
|
{
|
|
item.mSelfHeight = lineSpacing;
|
|
});
|
|
}
|
|
else
|
|
{
|
|
listView.GetRoot().WithItems(scope (listViewItem) =>
|
|
{
|
|
listViewItem.mSelfHeight = 0;
|
|
});
|
|
|
|
listView.GetRoot().WithItems(scope (listViewItem) =>
|
|
{
|
|
if (listViewItem.GetSubItemCount() < 2)
|
|
return;
|
|
|
|
bool found = false;
|
|
|
|
if (listViewItem.Label.IndexOf(searchStr, true) != -1)
|
|
found = true;
|
|
|
|
for (int32 subItemIdx = 1; subItemIdx < listViewItem.GetSubItemCount(); subItemIdx++)
|
|
{
|
|
var valueItem = listViewItem.GetSubItem(subItemIdx);
|
|
if (valueItem.Label.IndexOf(searchStr, true) != -1)
|
|
found = true;
|
|
}
|
|
|
|
if (found)
|
|
{
|
|
var checkItem = listViewItem;
|
|
while (checkItem != listView.GetRoot())
|
|
{
|
|
checkItem.mSelfHeight = lineSpacing;
|
|
checkItem = checkItem.mParentItem;
|
|
}
|
|
}
|
|
else
|
|
listViewItem.Selected = false;
|
|
});
|
|
}
|
|
listView.Resized();
|
|
}
|
|
|
|
public void AddPropPageWidget()
|
|
{
|
|
int defaultButtonIdx = mTabWidgets.IndexOf(mDefaultButton);
|
|
mTabWidgets.Insert(defaultButtonIdx, mPropPage.mPropertiesListView);
|
|
AddWidget(mPropPage.mPropertiesListView);
|
|
UpdateSearch();
|
|
}
|
|
|
|
protected void CategoryChanged(ListViewItem listViewItem)
|
|
{
|
|
//String category = listViewItem.mLabel;
|
|
//int32 categoryType = listViewItem.mParentItem.GetIndexOfChild(listViewItem);
|
|
ShowPropPage(((CategoryListViewItem)listViewItem).mCategoryIdx);
|
|
}
|
|
|
|
public bool AssertNotCompilingOrRunning()
|
|
{
|
|
var app = IDEApp.sApp;
|
|
if (app.IsCompiling)
|
|
{
|
|
app.Fail("Changes cannot be applied while compiling.");
|
|
return false;
|
|
}
|
|
if (app.mDebugger.mIsRunning)
|
|
{
|
|
app.Fail("Changes cannot be applied while debugging.");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
protected void ApplyChanges(PropPage propPage, ref bool hadChanges)
|
|
{
|
|
for (var propEntries in propPage.mPropEntries.Values)
|
|
{
|
|
for (var propEntry in propEntries)
|
|
{
|
|
if (propEntry.HasChanged())
|
|
{
|
|
hadChanges = true;
|
|
propEntry.ApplyValue();
|
|
}
|
|
}
|
|
if (propPage == mPropPage)
|
|
UpdatePropertyValue(propEntries);
|
|
}
|
|
|
|
propPage.mHasChanges = false;
|
|
}
|
|
|
|
protected virtual bool ApplyChanges()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
protected void ChildKeyDown(KeyCode keyCode)
|
|
{
|
|
if (keyCode == KeyCode.Escape)
|
|
{
|
|
KeyDown(keyCode, false);
|
|
}
|
|
else if (keyCode == KeyCode.Return)
|
|
{
|
|
mDefaultButton.SetFocus();
|
|
mDefaultButton.KeyDown(keyCode, false);
|
|
}
|
|
}
|
|
|
|
protected virtual void ResetSettings()
|
|
{
|
|
|
|
}
|
|
|
|
public override void ResizeComponents()
|
|
{
|
|
base.ResizeComponents();
|
|
|
|
float topY = TopY;
|
|
float propTopY = topY;
|
|
//var font = DarkTheme.sDarkTheme.mSmallFont;
|
|
|
|
bool hasTop = false;
|
|
float rightX = mWidth - GS!(12);
|
|
|
|
float selectorWidth = GS!(140);
|
|
|
|
if (mHideSelector)
|
|
selectorWidth = 0;
|
|
|
|
// Reset Settings
|
|
if (mPropPage.mFlags.HasFlag(.AllowReset))
|
|
{
|
|
if (mResetButton == null)
|
|
{
|
|
mResetButton = new DarkButton();
|
|
mResetButton.Label = "Reset Settings";
|
|
mResetButton.mOnMouseClick.Add(new (dlg) =>
|
|
{
|
|
ResetSettings();
|
|
});
|
|
AddWidget(mResetButton);
|
|
mTabWidgets.Insert(1, mResetButton);
|
|
}
|
|
float btnWidth = DarkTheme.sDarkTheme.mSmallFont.GetWidth(mResetButton.Label) + GS!(24);
|
|
mResetButton.Resize(mWidth - btnWidth - GS!(6), topY, btnWidth, GS!(22));
|
|
hasTop = true;
|
|
rightX = Math.Max(mResetButton.mX - GS!(6), 0);
|
|
}
|
|
else if (mResetButton != null)
|
|
{
|
|
mTabWidgets.Remove(mResetButton);
|
|
mResetButton.RemoveSelf();
|
|
DeleteAndNullify!(mResetButton);
|
|
}
|
|
|
|
// Search edit
|
|
if (mPropPage.mFlags.HasFlag(.AllowSearch))
|
|
{
|
|
if (mSearchEdit == null)
|
|
{
|
|
mSearchEdit = new SearchEditWidget();
|
|
AddWidget(mSearchEdit);
|
|
mTabWidgets.Insert(1, mSearchEdit);
|
|
}
|
|
float x = selectorWidth + GS!(12);
|
|
if (selectorWidth == 0)
|
|
x = GS!(6);
|
|
|
|
mSearchEdit.Resize(x, topY, Math.Max(rightX - x, 0), GS!(22));
|
|
hasTop = true;
|
|
}
|
|
else if (mSearchEdit != null)
|
|
{
|
|
mTabWidgets.Remove(mSearchEdit);
|
|
mSearchEdit.RemoveSelf();
|
|
DeleteAndNullify!(mSearchEdit);
|
|
UpdateSearch();
|
|
}
|
|
|
|
|
|
if (hasTop)
|
|
{
|
|
propTopY += GS!(26);
|
|
}
|
|
|
|
float catRight;
|
|
if (selectorWidth > 0)
|
|
{
|
|
catRight = mCategorySelector.mX + mCategorySelector.mWidth;
|
|
mCategorySelector.SetVisible(true);
|
|
mCategorySelector.Resize(GS!(6), topY, selectorWidth, Math.Max(mHeight - topY - GS!(32), 0));
|
|
}
|
|
else
|
|
{
|
|
catRight = 0;
|
|
mCategorySelector.SetVisible(false);
|
|
}
|
|
|
|
mPropPage.mPropertiesListView.Resize(catRight + GS!(6), propTopY, Math.Max(mWidth - catRight - GS!(12), 0), Math.Max(mHeight - propTopY - GS!(32), 0));
|
|
|
|
if (mPropEditWidget != null)
|
|
{
|
|
DarkListViewItem editItem = (DarkListViewItem)mEditingListViewItem;
|
|
let propEntry = mEditingProps[0];
|
|
|
|
float xPos;
|
|
float yPos;
|
|
editItem.SelfToOtherTranslate(editItem.mListView, 0, -1, out xPos, out yPos);
|
|
Rect rect = .(xPos, yPos, GetValueEditWidth(editItem), GS!(20));
|
|
propEntry.mEditInsets?.ApplyTo(ref rect);
|
|
|
|
if (mPropEditWidget.mEditWidgetContent.mIsMultiline)
|
|
rect.mHeight *= 4;
|
|
|
|
mPropEditWidget.Resize(rect.Left, rect.Top, rect.Width, rect.mHeight);
|
|
|
|
//mPropEditWidget.Resize(mPropEditWidget.mX, mPropEditWidget.mY, GetValueEditWidth(mEditingListViewItem.GetSubItem(1)), mPropEditWidget.mHeight);
|
|
if (mPropEditWidget.mChildWidgets != null)
|
|
{
|
|
for (var childWidget in mPropEditWidget.mChildWidgets)
|
|
childWidget.mX = mPropEditWidget.mWidth - childWidget.mWidth;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CategoryValueClicked(MouseEvent theEvent)
|
|
{
|
|
DarkListViewItem clickedItem = (DarkListViewItem)theEvent.mSender;
|
|
mCategorySelector.GetRoot().SelectItemExclusively(clickedItem);
|
|
mCategorySelector.SetFocus();
|
|
}
|
|
|
|
protected DarkListViewItem AddCategoryItem(DarkListViewItem parent, String name)
|
|
{
|
|
var item = (CategoryListViewItem)parent.CreateChildItem();
|
|
item.Label = name;
|
|
item.mFocusColor = Color.Mult(DarkTheme.COLOR_TEXT, 0xFFA0A0A0);
|
|
item.mOnMouseDown.Add(new => CategoryValueClicked);
|
|
item.mCategoryIdx = (int32)mCategoryListViewItems.Count;
|
|
mCategoryListViewItems.Add(item);
|
|
return item;
|
|
}
|
|
|
|
protected void HandleEditLostFocus(Widget widget)
|
|
{
|
|
Debug.Assert(widget == mPropEditWidget);
|
|
|
|
EditWidget editWidget = (EditWidget)widget;
|
|
editWidget.mOnLostFocus.Remove(scope => HandleEditLostFocus, true);
|
|
editWidget.mOnSubmit.Remove(scope => HandleSubmit, true);
|
|
editWidget.mOnCancel.Remove(scope => HandleCancel, true);
|
|
mWidgetWindow.mOnMouseWheel.Remove(scope => HandleMouseWheel, true);
|
|
mWidgetWindow.mOnWindowMoved.Remove(scope => HandleWindowMoved, true);
|
|
|
|
String newValue = scope String();
|
|
editWidget.GetText(newValue);
|
|
newValue.Trim();
|
|
|
|
DarkListViewItem rootItem = (DarkListViewItem)mEditingListViewItem.GetSubItem(0);
|
|
//DarkListViewItem valueItem = (DarkListViewItem)item.GetSubItem(1);
|
|
|
|
if (!editWidget.mEditWidgetContent.HasUndoData())
|
|
mCancelingEdit = true;
|
|
|
|
if (!mCancelingEdit)
|
|
{
|
|
var editingProp = mEditingProps[0];
|
|
bool multiCopyToOthers = false;
|
|
|
|
bool handled = false;
|
|
var curVariantType = editingProp.mCurValue.VariantType;
|
|
if (curVariantType.IsNullable)
|
|
{
|
|
let elementType = ((SpecializedGenericType)curVariantType).GetGenericArg(0);
|
|
if (elementType.[Friend]mTypeCode == .Int32)
|
|
{
|
|
handled = true;
|
|
editingProp.mCurValue.[Friend]mData = 0;
|
|
int32? value = null;
|
|
if ((newValue.Length != 0) && (!String.Equals(newValue, "Not Set", .OrdinalIgnoreCase)))
|
|
{
|
|
if (int32.Parse(newValue) case .Ok(let intVal))
|
|
{
|
|
value = intVal;
|
|
}
|
|
else
|
|
{
|
|
let error = scope String();
|
|
error.AppendF("Invalid number: {0}", newValue);
|
|
gApp.Fail(error);
|
|
}
|
|
}
|
|
|
|
*((bool*)&editingProp.mCurValue.[Friend]mData + elementType.[Friend]mSize) = value.HasValue;
|
|
if (value.HasValue)
|
|
{
|
|
void* valueData = editingProp.mCurValue.GetValueData();
|
|
Internal.MemCpy(valueData, &value.[Friend]mValue, elementType.[Friend]mSize);
|
|
}
|
|
multiCopyToOthers = true;
|
|
}
|
|
}
|
|
|
|
if (handled)
|
|
{
|
|
//
|
|
}
|
|
else if (editingProp.mListViewItem != rootItem)
|
|
{
|
|
List<String> curEntries = editingProp.mCurValue.Get<List<String>>();
|
|
List<String> entries = new List<String>(curEntries.GetEnumerator());
|
|
|
|
for (int32 childIdx = 0; childIdx < editingProp.mListViewItem.GetChildCount(); childIdx++)
|
|
{
|
|
if (rootItem == editingProp.mListViewItem.GetChildAtIndex(childIdx))
|
|
{
|
|
if (childIdx >= entries.Count)
|
|
entries.Add(new String(newValue));
|
|
else
|
|
entries[childIdx].Set(newValue);
|
|
}
|
|
}
|
|
curEntries.Clear();
|
|
|
|
for (int32 i = 0; i < entries.Count; i++)
|
|
{
|
|
entries[i].Trim();
|
|
if (entries[i] == "")
|
|
{
|
|
delete entries[i];
|
|
entries.RemoveAt(i);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
PropEntry.DisposeVariant(ref editingProp.mCurValue);
|
|
editingProp.mCurValue = Variant.Create(entries, true);
|
|
multiCopyToOthers = true;
|
|
}
|
|
else
|
|
{
|
|
var prevValue = editingProp.mCurValue;
|
|
bool setValue = true;
|
|
|
|
if (curVariantType == typeof(List<KeyState>))
|
|
{
|
|
if (!newValue.StartsWith("<"))
|
|
{
|
|
let entries = new List<KeyState>();
|
|
if (!newValue.IsEmpty)
|
|
KeyState.Parse(newValue, entries);
|
|
editingProp.mCurValue = Variant.Create(entries, true);
|
|
}
|
|
else
|
|
editingProp.mCurValue = DuplicateVariant(editingProp.mOrigValue);
|
|
}
|
|
else if (curVariantType == typeof(List<String>))
|
|
{
|
|
let entryViews = scope List<StringView>();
|
|
entryViews.AddRange(newValue.Split(';'));
|
|
let entries = new List<String>();
|
|
|
|
for (int32 i = 0; i < entryViews.Count; i++)
|
|
{
|
|
String entry = scope String(entryViews[i]);
|
|
entry.Trim();
|
|
if (entry.Length > 0)
|
|
{
|
|
entries.Add(new String(entry));
|
|
}
|
|
}
|
|
editingProp.mCurValue = Variant.Create(entries, true);
|
|
}
|
|
else if (curVariantType.[Friend]mTypeCode == .Int32)
|
|
{
|
|
if (int32.Parse(newValue) case .Ok(let intVal))
|
|
{
|
|
editingProp.mCurValue = Variant.Create(intVal);
|
|
}
|
|
else
|
|
{
|
|
let error = scope String();
|
|
error.AppendF("Invalid number: {0}", newValue);
|
|
gApp.Fail(error);
|
|
}
|
|
}
|
|
else if (curVariantType == typeof(Color))
|
|
{
|
|
if (int64.Parse(newValue, .HexNumber) case .Ok(let intVal))
|
|
{
|
|
editingProp.mCurValue = Variant.Create((Color)((uint32)intVal | 0xFF000000));
|
|
}
|
|
else
|
|
{
|
|
let error = scope String();
|
|
error.AppendF("Invalid number: {0}", newValue);
|
|
gApp.Fail(error);
|
|
setValue = false;
|
|
}
|
|
}
|
|
else if (curVariantType.[Friend]mTypeCode == .Float)
|
|
{
|
|
if (float.Parse(newValue) case .Ok(let floatVal))
|
|
{
|
|
editingProp.mCurValue = Variant.Create(floatVal);
|
|
}
|
|
else
|
|
{
|
|
let error = scope String();
|
|
error.AppendF("Invalid number: {0}", newValue);
|
|
gApp.Fail(error);
|
|
setValue = false;
|
|
}
|
|
}
|
|
else if ((curVariantType.IsObject) && (var multiValue = prevValue.Get<Object>() as IMultiValued))
|
|
{
|
|
multiValue.SetValue(mEditingListViewItem.mColumnIdx - 1, newValue);
|
|
setValue = false;
|
|
}
|
|
else
|
|
editingProp.mCurValue = Variant.Create(new String(newValue), true);
|
|
|
|
if (setValue)
|
|
{
|
|
PropEntry.DisposeVariant(ref prevValue);
|
|
multiCopyToOthers = true;
|
|
}
|
|
}
|
|
|
|
if (multiCopyToOthers)
|
|
{
|
|
for (int propIdx = 1; propIdx < mEditingProps.Count; propIdx++)
|
|
{
|
|
var otherProp = mEditingProps[propIdx];
|
|
PropEntry.DisposeVariant(ref otherProp.mCurValue);
|
|
otherProp.mCurValue = DuplicateVariant(editingProp.mCurValue);
|
|
}
|
|
}
|
|
|
|
UpdatePropertyValue(mEditingProps);
|
|
}
|
|
|
|
editWidget.RemoveSelf();
|
|
gApp.DeferDelete(editWidget);
|
|
mPropEditWidget = null;
|
|
DeleteAndNullify!(mEditingProps);
|
|
mEditingListViewItem = null;
|
|
|
|
if ((mPreviousFocus != null) && (mPreviousFocus.mWidgetWindow != null))
|
|
mPreviousFocus.SetFocus();
|
|
mPreviousFocus = null;
|
|
|
|
if (mWidgetWindow.mFocusWidget == null)
|
|
mDefaultButton.SetFocus();
|
|
CheckForChanges();
|
|
}
|
|
|
|
protected virtual bool HasChanges()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
protected void CheckForChanges()
|
|
{
|
|
bool hasChanges = HasChanges();
|
|
for (var propEntries in mPropPage.mPropEntries.Values)
|
|
{
|
|
for (var propEntry in propEntries)
|
|
if (propEntry.HasChanged())
|
|
hasChanges = true;
|
|
|
|
var propEntry = propEntries[0];
|
|
if (propEntry.mComboBoxes != null)
|
|
{
|
|
for (var comboBox in propEntry.mComboBoxes)
|
|
{
|
|
if (comboBox.mCurMenuWidget != null)
|
|
comboBox.mBkgColor = 0x20FFFFFF;
|
|
else
|
|
comboBox.mBkgColor = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
mPropPage.mHasChanges = hasChanges;
|
|
}
|
|
|
|
protected void CheckForChanges(PropPage[] propPages)
|
|
{
|
|
CheckForChanges();
|
|
bool hasChanges = false;
|
|
|
|
for (int32 pageIdx = 0; pageIdx < propPages.Count; pageIdx++)
|
|
{
|
|
var propPage = propPages[pageIdx];
|
|
bool isCurrent = propPage == mPropPage;
|
|
if (propPage != null)
|
|
{
|
|
var categoryItem = mCategoryListViewItems[pageIdx];
|
|
if (isCurrent)
|
|
categoryItem.mIsBold = propPage.mHasChanges;
|
|
hasChanges |= propPage.mHasChanges;
|
|
}
|
|
}
|
|
|
|
if (hasChanges)
|
|
mApplyButton.mDisabled = false;
|
|
else
|
|
mApplyButton.mDisabled = true;
|
|
}
|
|
|
|
protected void ChangeProperty(PropEntry[] propEntries, Variant value)
|
|
{
|
|
for (var propEntry in propEntries)
|
|
{
|
|
let curVariantType = propEntry.mCurValue.VariantType;
|
|
if (propEntry.mCurValue.VariantType.IsNullable)
|
|
{
|
|
let genericType = (SpecializedGenericType)curVariantType;
|
|
let elementType = genericType.GetGenericArg(0);
|
|
|
|
propEntry.mCurValue.[Friend]mData = 0;
|
|
*((bool*)&propEntry.mCurValue.[Friend]mData + elementType.[Friend]mSize) = value.HasValue;
|
|
if (value.HasValue)
|
|
{
|
|
void* valueData = propEntry.mCurValue.GetValueData();
|
|
var copyValue = value;
|
|
Internal.MemCpy(valueData, copyValue.GetValueData(), elementType.[Friend]mSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PropEntry.DisposeVariant(ref propEntry.mCurValue);
|
|
propEntry.mCurValue = value;
|
|
}
|
|
}
|
|
UpdatePropertyValue(propEntries);
|
|
}
|
|
|
|
void HandleCancel(EditEvent theEvent)
|
|
{
|
|
mCancelingEdit = true;
|
|
HandleEditLostFocus((EditWidget)theEvent.mSender);
|
|
}
|
|
|
|
protected void HandleSubmit(EditEvent theEvent)
|
|
{
|
|
if ((mPropEditWidget != null) && (var sewc = mPropEditWidget.mEditWidgetContent as SourceEditWidgetContent))
|
|
{
|
|
if (sewc.mAutoComplete != null)
|
|
return;
|
|
}
|
|
|
|
HandleEditLostFocus((EditWidget)theEvent.mSender);
|
|
}
|
|
|
|
protected void MoveEditingItem(int32 subValueIdx, int32 dir)
|
|
{
|
|
ListViewItem item = mEditingListViewItem;
|
|
var itemParent = item.mParentItem;
|
|
String editText = scope String();
|
|
mPropEditWidget.GetText(editText);
|
|
PropEntry propEntry = mEditingProps[0];
|
|
|
|
var propEntries = new PropEntry[mEditingProps.Count];
|
|
defer delete propEntries;
|
|
mEditingProps.CopyTo(propEntries);
|
|
|
|
var curStringList = propEntry.mCurValue.Get<List<String>>();
|
|
List<String> stringList = new List<String>();
|
|
for (var str in curStringList)
|
|
{
|
|
stringList.Add(new String(str));
|
|
}
|
|
|
|
mCancelingEdit = true;
|
|
HandleEditLostFocus(mPropEditWidget);
|
|
|
|
if (subValueIdx >= stringList.Count)
|
|
stringList.Add(editText);
|
|
|
|
String swap = stringList[subValueIdx];
|
|
stringList[subValueIdx] = stringList[subValueIdx + dir];
|
|
stringList[subValueIdx + dir] = swap;
|
|
PropEntry.DisposeVariant(ref propEntry.mCurValue);
|
|
propEntry.mCurValue = Variant.Create(stringList, true);
|
|
for (int otherIdx = 1; otherIdx < propEntries.Count; otherIdx++)
|
|
{
|
|
var otherProps = propEntries[otherIdx];
|
|
PropEntry.DisposeVariant(ref otherProps.mCurValue);
|
|
otherProps.mCurValue = DuplicateVariant(propEntry.mCurValue);
|
|
}
|
|
UpdatePropertyValue(propEntries);
|
|
|
|
ListViewItem newItem = itemParent.GetChildAtIndex(subValueIdx + dir);
|
|
EditValue(newItem, propEntries, subValueIdx + dir);
|
|
mPropEditWidget.SetText(editText);
|
|
}
|
|
|
|
protected void EditValue(ListViewItem item, PropEntry[] propEntries, int32 subValueIdx = -1)
|
|
{
|
|
DarkListViewItem editItem = (DarkListViewItem)item.GetSubItem(1);
|
|
|
|
mPreviousFocus = null;
|
|
if ((mWidgetWindow.mFocusWidget == mPropPage.mPropertiesListView) && (mPropPage.mPropertiesListView.GetRoot().FindFocusedItem() != null))
|
|
mPreviousFocus = mWidgetWindow.mFocusWidget;
|
|
|
|
mCancelingEdit = false;
|
|
|
|
var propEntry = propEntries[0];
|
|
|
|
if ((propEntry.mMultiRootReadOnly) && (subValueIdx == -1))
|
|
return;
|
|
|
|
var valueItem = propEntry.mListViewItem.GetSubItem(1);
|
|
let type = propEntry.mCurValue.VariantType;
|
|
|
|
DarkEditWidget editWidget;
|
|
if (propEntry.mIsTypeWildcard)
|
|
editWidget = new TypeWildcardEditWidget();
|
|
else if (propEntry.mRelPath != null)
|
|
{
|
|
var pathEditWidget = new PathEditWidget();
|
|
pathEditWidget.mRelPath = new String(propEntry.mRelPath);
|
|
editWidget = pathEditWidget;
|
|
}
|
|
else if (type == typeof(List<KeyState>))
|
|
{
|
|
editWidget = new KeysEditWidget();
|
|
editWidget.Content.mIsReadOnly = true;
|
|
}
|
|
else
|
|
editWidget = new DarkEditWidget();
|
|
|
|
let ewc = editWidget.mEditWidgetContent;
|
|
ewc.mIsMultiline = propEntry.mAllowMultiline;
|
|
if (ewc.mIsMultiline)
|
|
editWidget.InitScrollbars(false, true);
|
|
|
|
if (propEntry.mReadOnly)
|
|
editWidget.mEditWidgetContent.mIsReadOnly = true;
|
|
|
|
editWidget.mScrollContentInsets.Set(GS!(3), GS!(3), GS!(1), GS!(3));
|
|
editWidget.Content.mTextInsets.Set(GS!(-3), GS!(2), 0, GS!(2));
|
|
//editWidget.RehupSize();
|
|
if (subValueIdx != -1)
|
|
{
|
|
var obj = propEntry.mCurValue.Get<Object>();
|
|
if (var multiValued = obj as IMultiValued)
|
|
{
|
|
var label = multiValued.GetValue(subValueIdx, .. scope .());
|
|
editWidget.SetText(label);
|
|
}
|
|
else
|
|
{
|
|
List<String> stringList = obj as List<String>;
|
|
if (subValueIdx < stringList.Count)
|
|
editWidget.SetText(stringList[subValueIdx]);
|
|
|
|
MoveItemWidget moveItemWidget;
|
|
if (subValueIdx > 0)
|
|
{
|
|
moveItemWidget = new MoveItemWidget();
|
|
editWidget.AddWidget(moveItemWidget);
|
|
moveItemWidget.Resize(6, editWidget.mY - GS!(16), GS!(20), GS!(20));
|
|
moveItemWidget.mArrowDir = -1;
|
|
moveItemWidget.mOnMouseDown.Add(new (evt) => { MoveEditingItem(subValueIdx, -1); });
|
|
if (!ewc.mIsMultiline)
|
|
editWidget.mOnKeyDown.Add(new (evt) => { if (evt.mKeyCode == KeyCode.Up) MoveEditingItem(subValueIdx, -1); });
|
|
}
|
|
|
|
if (subValueIdx < stringList.Count - 1)
|
|
{
|
|
moveItemWidget = new MoveItemWidget();
|
|
editWidget.AddWidget(moveItemWidget);
|
|
moveItemWidget.Resize(6, editWidget.mY + GS!(16), GS!(20), GS!(20));
|
|
moveItemWidget.mArrowDir = 1;
|
|
moveItemWidget.mOnMouseDown.Add(new (evt) => { MoveEditingItem(subValueIdx, 1); });
|
|
if (!ewc.mIsMultiline)
|
|
editWidget.mOnKeyDown.Add(new (evt) => { if (evt.mKeyCode == KeyCode.Down) MoveEditingItem(subValueIdx, 1); });
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
String label = valueItem.mLabel;
|
|
if ((propEntry.mNotSetString != null) && (label == propEntry.mNotSetString))
|
|
label = "";
|
|
/*var curVariantType = mEditingProp.mCurValue.VariantType;
|
|
if (curVariantType.IsNullable)
|
|
{
|
|
if (label == "Not Set")
|
|
label = "";
|
|
}*/
|
|
|
|
if (propEntry.mCurValue.VariantType == typeof(List<String>))
|
|
{
|
|
List<String> stringList = propEntry.mCurValue.Get<List<String>>();
|
|
String allValues = scope .();
|
|
for (int i = 0; i < stringList.Count; i++)
|
|
{
|
|
if (i > 0)
|
|
allValues.Append(";");
|
|
allValues.Append(stringList[i]);
|
|
}
|
|
editWidget.SetText(allValues);
|
|
}
|
|
else if (editWidget is KeysEditWidget)
|
|
editWidget.SetText("< Press Key >");
|
|
else
|
|
editWidget.SetText(label);
|
|
}
|
|
|
|
editWidget.Content.SelectAll();
|
|
|
|
editItem.mListView.AddWidget(editWidget);
|
|
|
|
editWidget.mOnLostFocus.Add(new => HandleEditLostFocus);
|
|
editWidget.mOnSubmit.Add(new => HandleSubmit);
|
|
editWidget.mOnCancel.Add(new => HandleCancel);
|
|
editWidget.SetFocus();
|
|
mWidgetWindow.mOnMouseWheel.Add(new => HandleMouseWheel);
|
|
mWidgetWindow.mOnWindowMoved.Add(new => HandleWindowMoved);
|
|
editWidget.mEditWidgetContent.ClearUndoData();
|
|
|
|
mEditingListViewItem = item;
|
|
mPropEditWidget = editWidget;
|
|
|
|
mEditingProps = new PropEntry[propEntries.Count];
|
|
for (int i < propEntries.Count)
|
|
mEditingProps[i] = propEntries[i];
|
|
|
|
ResizeComponents();
|
|
}
|
|
|
|
void HandleMouseWheel(MouseEvent evt)
|
|
{
|
|
mCancelingEdit = true;
|
|
HandleEditLostFocus(mPropEditWidget);
|
|
}
|
|
|
|
void HandleWindowMoved(BFWindow window)
|
|
{
|
|
mCancelingEdit = true;
|
|
HandleEditLostFocus(mPropEditWidget);
|
|
}
|
|
|
|
protected virtual void UpdatePropertyValue(PropEntry[] propEntries)
|
|
{
|
|
var propEntry = propEntries[0];
|
|
if (propEntry.mListViewItem == null)
|
|
return;
|
|
bool areDifferent = false;
|
|
for (int checkIdx = 1; checkIdx < propEntries.Count; checkIdx++)
|
|
{
|
|
var checkProp = propEntries[checkIdx];
|
|
if (!PropEntry.IsVariantEqual(checkProp.mCurValue, propEntry.mCurValue))
|
|
areDifferent = true;
|
|
}
|
|
|
|
bool hasChanged = false;
|
|
for (var checkPropEntry in propEntries)
|
|
{
|
|
if (checkPropEntry.HasChanged())
|
|
hasChanged = true;
|
|
}
|
|
|
|
/*if (propEntry.mFieldInfo == default(FieldInfo))
|
|
return;*/
|
|
|
|
var curVariantType = propEntry.mCurValue.VariantType;
|
|
|
|
bool handled = false;
|
|
if (propEntry.mOnUpdate.HasListeners)
|
|
{
|
|
handled |= propEntry.mOnUpdate();
|
|
}
|
|
bool isNotSet = false;
|
|
var valueItem = (DarkListViewItem)propEntry.mListViewItem.GetSubItem(1);
|
|
if (curVariantType.IsNullable)
|
|
{
|
|
propEntry.mNotSetString = "Not Set";
|
|
|
|
let genericType = (SpecializedGenericType)curVariantType;
|
|
let elementType = genericType.GetGenericArg(0);
|
|
|
|
bool hasValue = *((bool*)&propEntry.mCurValue.[Friend]mData + elementType.[Friend]mSize);
|
|
curVariantType = elementType;
|
|
if (!hasValue)
|
|
{
|
|
valueItem.Label = "Not Set";
|
|
handled = true;
|
|
isNotSet = true;
|
|
}
|
|
}
|
|
|
|
void FixLabel(ListViewItem lvItem)
|
|
{
|
|
if (!lvItem.mLabel.Contains('\n'))
|
|
return;
|
|
lvItem.mLabel.Replace('\n', ' ');
|
|
}
|
|
|
|
if (handled)
|
|
{
|
|
if (curVariantType == typeof(String))
|
|
{
|
|
var str = propEntry.mCurValue.Get<String>();
|
|
if ((propEntry.mNotSetString != null) &&
|
|
((propEntry.mNotSetString == str) || (str.IsEmpty)))
|
|
{
|
|
isNotSet = true;
|
|
str = propEntry.mNotSetString;
|
|
}
|
|
valueItem.Label = str;
|
|
}
|
|
}
|
|
else if (propEntry.mOptionValues != null)
|
|
{
|
|
int32 idx = 0;
|
|
if (curVariantType == typeof(bool))
|
|
{
|
|
if (propEntry.mCurValue.Get<bool>())
|
|
idx = 1;
|
|
}
|
|
else if (curVariantType.IsEnum)
|
|
{
|
|
//idx = propEntry.mCurValue.Get<int32>();
|
|
int64 val = 0;
|
|
Internal.MemCpy(&val, propEntry.mCurValue.GetValueData(), curVariantType.Size);
|
|
idx = (int32)val;
|
|
}
|
|
valueItem.Label = propEntry.mOptionValues[idx];
|
|
}
|
|
else if (curVariantType == typeof(List<KeyState>))
|
|
{
|
|
var keyList = propEntry.mCurValue.Get<List<KeyState>>();
|
|
|
|
var str = scope String();
|
|
KeyState.ToString(keyList, str);
|
|
if (str.IsEmpty)
|
|
{
|
|
let origEntry = propEntry.mOrigValue.Get<List<KeyState>>();
|
|
if (!origEntry.IsEmpty)
|
|
str.Append("< Removed >");
|
|
}
|
|
|
|
valueItem.Label = str;
|
|
}
|
|
else if (curVariantType.IsGenericType)
|
|
{
|
|
String allValues = scope String();
|
|
List<String> strVals;
|
|
if (areDifferent)
|
|
strVals = scope:: .();
|
|
else
|
|
strVals = propEntry.mCurValue.Get<List<String>>();
|
|
for (int32 i = 0; i <= strVals.Count; i++)
|
|
{
|
|
String curValue = "<Add New...>";
|
|
if (i < strVals.Count)
|
|
{
|
|
if (i > 0)
|
|
allValues.Append(";");
|
|
curValue = strVals[i];
|
|
allValues.Append(curValue);
|
|
if (curValue.Contains(';')) // Don't allow editing if the parsing will mess up
|
|
propEntry.mMultiRootReadOnly = true;
|
|
}
|
|
|
|
DarkListViewItem childItem;
|
|
DarkListViewItem childSubItem;
|
|
if (i >= propEntry.mListViewItem.GetChildCount())
|
|
{
|
|
childItem = (DarkListViewItem)propEntry.mListViewItem.CreateChildItem();
|
|
childSubItem = (DarkListViewItem)childItem.CreateSubItem(1);
|
|
int32 curIdx = i;
|
|
|
|
PropEntry[] propEntriesCopy = new PropEntry[propEntries.Count];
|
|
propEntries.CopyTo(propEntriesCopy);
|
|
|
|
childSubItem.mOnMouseDown.Add(new (evt) =>
|
|
{
|
|
if (areDifferent)
|
|
{
|
|
var strList = propEntry.mCurValue.Get<List<String>>();
|
|
ClearAndDeleteItems(strList);
|
|
}
|
|
ArrayPropValueClicked(propEntriesCopy, curIdx);
|
|
}
|
|
~
|
|
{
|
|
delete propEntriesCopy;
|
|
});
|
|
}
|
|
else
|
|
{
|
|
childItem = (DarkListViewItem)propEntry.mListViewItem.GetChildAtIndex(i);
|
|
childSubItem = (DarkListViewItem)childItem.GetSubItem(1);
|
|
}
|
|
if (i < strVals.Count)
|
|
{
|
|
childItem.Label = scope String()..AppendF("#{0}", i + 1);
|
|
childSubItem.mTextColor = DarkTheme.COLOR_TEXT;
|
|
}
|
|
else
|
|
{
|
|
childItem.Label = "";
|
|
childSubItem.mTextColor = Color.Mult(DarkTheme.COLOR_TEXT, 0xFFC0C0C0);
|
|
}
|
|
childSubItem.Label = curValue;
|
|
FixLabel(childSubItem);
|
|
}
|
|
|
|
while (propEntry.mListViewItem.GetChildCount() > strVals.Count + 1)
|
|
propEntry.mListViewItem.RemoveChildItem(propEntry.mListViewItem.GetChildAtIndex(propEntry.mListViewItem.GetChildCount() - 1));
|
|
|
|
valueItem.Label = allValues;
|
|
FixLabel(valueItem);
|
|
}
|
|
else if ((curVariantType.IsObject) && (var multiValue = propEntry.mCurValue.Get<Object>() as IMultiValued))
|
|
{
|
|
for (int columnIdx in 1..<propEntry.mListViewItem.mSubItems.Count)
|
|
{
|
|
var subItem = propEntry.mListViewItem.GetSubItem(columnIdx);
|
|
var label = multiValue.GetValue(columnIdx - 1, .. scope .());
|
|
subItem.Label = label;
|
|
}
|
|
}
|
|
else if (propEntry.mCheckBox != null)
|
|
{
|
|
propEntry.mCheckBox.Checked = propEntry.mCurValue.Get<bool>();
|
|
}
|
|
else if (curVariantType.IsEnum)
|
|
{
|
|
var enumStr = scope String();
|
|
|
|
Debug.Assert(curVariantType.Size <= 8);
|
|
int64 val = 0;
|
|
Internal.MemCpy(&val, propEntry.mCurValue.GetValueData(), curVariantType.Size);
|
|
Enum.EnumToString(curVariantType, enumStr, val);
|
|
GetEnumDisp(enumStr);
|
|
valueItem.Label = enumStr;
|
|
}
|
|
else if (curVariantType == typeof(String))
|
|
{
|
|
valueItem.Label = propEntry.mCurValue.Get<String>();
|
|
}
|
|
else if (curVariantType == typeof(int32))
|
|
{
|
|
let valStr = scope String();
|
|
int32 intVal = propEntry.mCurValue.Get<int32>();
|
|
intVal.ToString(valStr);
|
|
valueItem.Label = valStr;
|
|
}
|
|
else if (curVariantType == typeof(Color))
|
|
{
|
|
let valStr = scope String();
|
|
int32 intVal = propEntry.mCurValue.Get<int32>();
|
|
(intVal & 0x00FFFFFF).ToString(valStr, "X6", null);
|
|
valueItem.Label = valStr;
|
|
}
|
|
else if (curVariantType == typeof(float))
|
|
{
|
|
let valStr = scope String();
|
|
float floatVal = propEntry.mCurValue.Get<float>();
|
|
floatVal.ToString(valStr);
|
|
valueItem.Label = valStr;
|
|
}
|
|
else if (curVariantType == typeof(Workspace.ConfigSelection))
|
|
{
|
|
var platformItem = (DarkListViewItem)propEntry.mListViewItem.GetSubItem(2);
|
|
|
|
var configSelection = propEntry.mCurValue.Get<Workspace.ConfigSelection>();
|
|
valueItem.Label = configSelection.mConfig;
|
|
platformItem.Label = configSelection.mPlatform;
|
|
}
|
|
else
|
|
ThrowUnimplemented();
|
|
//valueItem.Label = ToStackString!(propEntry.mCurValue);
|
|
|
|
if (hasChanged)
|
|
valueItem.mIsBold = true;
|
|
else
|
|
valueItem.mIsBold = false;
|
|
|
|
if (areDifferent)
|
|
{
|
|
valueItem.Label = "<Multiple Values>";
|
|
valueItem.mTextColor = Color.Mult(DarkTheme.COLOR_TEXT, 0xFFC0C0C0);
|
|
}
|
|
else if (propEntry.mColorOverride.HasValue)
|
|
valueItem.mTextColor = propEntry.mColorOverride.Value;
|
|
else if (isNotSet)
|
|
valueItem.mTextColor = Color.Mult(DarkTheme.COLOR_TEXT, 0xFFC0C0C0);
|
|
else
|
|
valueItem.mTextColor = Color.Mult(DarkTheme.COLOR_TEXT, 0xFFFFFFFF);
|
|
}
|
|
|
|
void GetEnumDisp(String enumDisp)
|
|
{
|
|
int32 firstUpperChar = -1;
|
|
|
|
for (int32 i = 0; i < enumDisp.Length; i++)
|
|
{
|
|
char8 c = enumDisp[i];
|
|
if (c.IsUpper)
|
|
{
|
|
if (firstUpperChar == -1)
|
|
firstUpperChar = i;
|
|
}
|
|
|
|
if (c.IsLower)
|
|
{
|
|
if (firstUpperChar > 0)
|
|
{
|
|
enumDisp.Insert(firstUpperChar, " ");
|
|
i++;
|
|
}
|
|
|
|
firstUpperChar = -1;
|
|
}
|
|
}
|
|
|
|
if (firstUpperChar > 0)
|
|
{
|
|
enumDisp.Insert(firstUpperChar, " ");
|
|
}
|
|
}
|
|
|
|
protected void PopulateComboBox(Menu menu, PropEntry[] propEntries)
|
|
{
|
|
var propEntry = propEntries[0];
|
|
var valueType = propEntry.mCurValue.VariantType;
|
|
|
|
if (valueType.IsNullable)
|
|
{
|
|
let genericType = (SpecializedGenericType)valueType;
|
|
let elementType = genericType.GetGenericArg(0);
|
|
|
|
var menuItem = menu.AddItem("Not Set");
|
|
Variant newVariant = Variant();
|
|
menuItem.mOnMenuItemSelected.Add(new (evt) => { ChangeProperty(propEntries, newVariant); });
|
|
valueType = elementType;
|
|
}
|
|
|
|
if (propEntry.mOptionValues != null)
|
|
{
|
|
for (int32 i = 0; i < propEntry.mOptionValues.Count; i++)
|
|
{
|
|
var menuItem = menu.AddItem(propEntry.mOptionValues[i]);
|
|
|
|
Variant newVariant = Variant();
|
|
if (valueType == typeof(bool))
|
|
newVariant = Variant.Create(i != 0);
|
|
else if (valueType.IsEnum)
|
|
{
|
|
newVariant = Variant.Create(valueType, &i);
|
|
}
|
|
//newVariant = Variant.Create(!propEntry.mCurValue.Get<bool>());
|
|
menuItem.mOnMenuItemSelected.Add(new (evt) => { ChangeProperty(propEntries, newVariant); });
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (var enumValue in ((TypeInstance)valueType).GetFields())
|
|
{
|
|
var enumStr = scope String();
|
|
enumStr.Append(enumValue.Name);
|
|
GetEnumDisp(enumStr);
|
|
var menuItem = menu.AddItem(enumStr);
|
|
Variant newVariant = enumValue.GetValue(null);
|
|
menuItem.mOnMenuItemSelected.Add(new (evt) => { ChangeProperty(propEntries, newVariant); });
|
|
}
|
|
}
|
|
}
|
|
|
|
protected float GetValueEditWidth(ListViewItem subItem)
|
|
{
|
|
float width = subItem.mWidth;
|
|
float transX;
|
|
float transY;
|
|
subItem.SelfToOtherTranslate(subItem.mListView, 0, 0, out transX, out transY);
|
|
width = Math.Max(subItem.mListView.mWidth - transX - GS!(18), GS!(80));
|
|
return width;
|
|
}
|
|
|
|
static Variant DuplicateVariant(Variant prevVariant)
|
|
{
|
|
if (!prevVariant.HasValue)
|
|
return Variant();
|
|
|
|
var type = prevVariant.VariantType;
|
|
if (prevVariant.IsObject)
|
|
{
|
|
if (type == typeof(List<String>))
|
|
{
|
|
var newStrList = new List<String>();
|
|
for (var str in prevVariant.Get<List<String>>())
|
|
newStrList.Add(new String(str));
|
|
return Variant.Create(newStrList, true);
|
|
}
|
|
if (type == typeof(List<KeyState>))
|
|
{
|
|
var newList = new List<KeyState>();
|
|
for (var keyState in prevVariant.Get<List<KeyState>>())
|
|
newList.Add(keyState.Clone());
|
|
return Variant.Create(newList, true);
|
|
}
|
|
if (type == typeof(String))
|
|
{
|
|
var str = new String(prevVariant.Get<String>());
|
|
return Variant.Create(str, true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Variant.Create();
|
|
|
|
var data = prevVariant.[Friend]mData;
|
|
return Variant.Create(prevVariant.VariantType, &data);
|
|
|
|
/*if (type == typeof(bool))
|
|
return Variant.Create(prevVariant.Get<bool>());
|
|
if (type == typeof(int32))
|
|
return Variant.Create(prevVariant.Get<int32>());
|
|
if (type.IsEnum)
|
|
return Variant.Create(prevVariant.VariantType, prevVariant.Get<int32>());*/
|
|
}
|
|
|
|
ThrowUnimplemented();
|
|
}
|
|
|
|
protected void UpdateFromTarget(Dictionary<Object, Object> targetDict)
|
|
{
|
|
for (let propKV in mPropPage.mPropEntries)
|
|
{
|
|
#unwarn
|
|
var listViewItem = propKV.key;
|
|
var propEntries = propKV.value;
|
|
|
|
for (var propEntry in propEntries)
|
|
{
|
|
Object target;
|
|
if (!targetDict.TryGetValue(propEntry.mTarget, out target))
|
|
{
|
|
//Debug.FatalError();
|
|
continue;
|
|
}
|
|
|
|
String usePropName = scope:: String(propEntry.mPropertyName);
|
|
|
|
while (true)
|
|
{
|
|
int dotIdx = usePropName.IndexOf('.');
|
|
if (dotIdx == -1)
|
|
break;
|
|
|
|
String newTargetName = scope String(usePropName, 0, (int)dotIdx);
|
|
usePropName.Remove(0, dotIdx + 1);
|
|
|
|
int idx = -1;
|
|
if (newTargetName.EndsWith("]"))
|
|
{
|
|
int bracketPos = newTargetName.IndexOf("[");
|
|
String idxStr = scope String(newTargetName, bracketPos + 1, (int)newTargetName.Length - bracketPos - 2);
|
|
idx = int32.Parse(idxStr).GetValueOrDefault();
|
|
newTargetName.RemoveToEnd(bracketPos);
|
|
}
|
|
|
|
Debug.Assert(target != null);
|
|
var targetFieldInfo = target.GetType().GetField(newTargetName);
|
|
targetFieldInfo.Value.GetValue(target, out target);
|
|
|
|
if (idx != -1)
|
|
{
|
|
if (var iList = target as IList)
|
|
{
|
|
var vari = iList[idx];
|
|
Debug.Assert(vari.IsObject);
|
|
target = vari.Get<Object>();
|
|
}
|
|
}
|
|
|
|
Debug.Assert(target != null);
|
|
}
|
|
|
|
var fieldInfo = target.GetType().GetField(usePropName).Value;
|
|
var curValue = fieldInfo.GetValue(target).GetValueOrDefault();
|
|
PropEntry.DisposeVariant(ref propEntry.mCurValue);
|
|
propEntry.mCurValue = DuplicateVariant(curValue);
|
|
}
|
|
UpdatePropertyValue(propEntries);
|
|
}
|
|
}
|
|
|
|
void BrowseForFile(String outPath)
|
|
{
|
|
#if !CLI
|
|
var fileDialog = scope OpenFileDialog();
|
|
fileDialog.Title = "Select File";
|
|
fileDialog.SetFilter("All files (*.*)|*.*");
|
|
|
|
if (!outPath.IsWhiteSpace)
|
|
{
|
|
String initialDir = scope .();
|
|
Path.GetDirectoryPath(outPath, initialDir);
|
|
fileDialog.InitialDirectory = initialDir;
|
|
}
|
|
|
|
if (fileDialog.ShowDialog(mWidgetWindow).GetValueOrDefault() == .OK)
|
|
{
|
|
for (String openFileName in fileDialog.FileNames)
|
|
{
|
|
outPath.Set(openFileName);
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void BrowseForFolder(String outPath)
|
|
{
|
|
#if !CLI
|
|
var folderDialog = scope FolderBrowserDialog();
|
|
if (!outPath.IsWhiteSpace)
|
|
{
|
|
folderDialog.SelectedPath = outPath;
|
|
}
|
|
if (folderDialog.ShowDialog(mWidgetWindow).GetValueOrDefault() == .OK)
|
|
{
|
|
outPath.Set(folderDialog.SelectedPath);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
protected PropEntry SetupPropertiesItem(DarkListViewItem item, String name, Object propName = null, String[] optionValues = null, PropEntry.Flags flags = .None)
|
|
{
|
|
if ((propName == null) || (propName == ""))
|
|
return null;
|
|
|
|
DarkListViewItem subItem = null;
|
|
if (item.GetSubItemCount() >= 2)
|
|
subItem = (DarkListViewItem)item.GetSubItem(1);
|
|
else
|
|
subItem = (DarkListViewItem)item.CreateSubItem(1);
|
|
|
|
if (mCurPropertiesTargets == null)
|
|
{
|
|
mCurPropertiesTargets = scope:: Object[1];
|
|
mCurPropertiesTargets[0] = mCurPropertiesTarget;
|
|
defer:: { mCurPropertiesTargets = null; }
|
|
}
|
|
//
|
|
//var comboBox = new DarkComboBox();
|
|
//Action act = new () => { comboBox.Resize(0, 0, GetValueEditWidth(subItem), subItem.mHeight + 1); };
|
|
|
|
//
|
|
|
|
PropEntry[] propEntries = new PropEntry[mCurPropertiesTargets.Count];
|
|
for (int propIdx < (int)propEntries.Count)
|
|
PropBlock:
|
|
{
|
|
Object target = mCurPropertiesTargets[propIdx];
|
|
|
|
String usePropName = propName as String;
|
|
if (usePropName != null)
|
|
{
|
|
usePropName = scope:PropBlock String(usePropName);
|
|
}
|
|
else if (var propNames = propName as String[])
|
|
{
|
|
usePropName = scope:PropBlock String(propNames[propIdx]);
|
|
}
|
|
|
|
String[] useOptionValues = optionValues;
|
|
|
|
while (true)
|
|
{
|
|
int dotIdx = usePropName.IndexOf('.');
|
|
if (dotIdx == -1)
|
|
break;
|
|
|
|
String newTargetName = scope String(usePropName, 0, (int)dotIdx);
|
|
usePropName.Remove(0, dotIdx + 1);
|
|
|
|
int idx = -1;
|
|
if (newTargetName.EndsWith("]"))
|
|
{
|
|
int bracketPos = newTargetName.IndexOf("[");
|
|
String idxStr = scope String(newTargetName, bracketPos + 1, (int)newTargetName.Length - bracketPos - 2);
|
|
idx = int32.Parse(idxStr).GetValueOrDefault();
|
|
newTargetName.RemoveToEnd(bracketPos);
|
|
}
|
|
|
|
Debug.Assert(target != null);
|
|
var targetFieldInfo = target.GetType().GetField(newTargetName);
|
|
targetFieldInfo.Value.GetValue(target, out target);
|
|
|
|
if (idx != -1)
|
|
{
|
|
if (var iList = target as IList)
|
|
{
|
|
var vari = iList[idx];
|
|
Debug.Assert(vari.IsObject);
|
|
target = vari.Get<Object>();
|
|
}
|
|
}
|
|
|
|
Debug.Assert(target != null);
|
|
}
|
|
|
|
PropEntry propEntry = new PropEntry();
|
|
propEntry.mFlags = flags;
|
|
propEntry.mPropertyName = new String(usePropName);
|
|
propEntry.mTarget = target;
|
|
propEntry.mListViewItem = item;
|
|
|
|
propEntries[propIdx] = propEntry;
|
|
|
|
//TODO:
|
|
var fieldInfo = target.GetType().GetField(usePropName).Value;
|
|
propEntry.mFieldInfo = fieldInfo;
|
|
|
|
var curValue = fieldInfo.GetValue(target).GetValueOrDefault();
|
|
propEntry.mOrigValue = curValue;
|
|
propEntry.mCurValue = DuplicateVariant(curValue);
|
|
//TODO: Duplicate optionValues
|
|
|
|
if (useOptionValues != null)
|
|
{
|
|
// Duplicate onto heap
|
|
var prevOptionValues = useOptionValues;
|
|
useOptionValues = new String[useOptionValues.Count];
|
|
for (int32 i = 0; i < prevOptionValues.Count; i++)
|
|
useOptionValues[i] = new String(prevOptionValues[i]);
|
|
}
|
|
|
|
propEntry.mOptionValues = useOptionValues;
|
|
bool handledMouseDown = false;
|
|
|
|
var fieldType = fieldInfo.FieldType;
|
|
|
|
if ((fieldType == typeof(bool)) && (useOptionValues == null))
|
|
{
|
|
propEntry.mOptionValues = new String[] ( new String("No"), new String("Yes") );
|
|
}
|
|
|
|
if (fieldType.IsNullable)
|
|
{
|
|
fieldType = ((SpecializedGenericType)fieldType).GetGenericArg(0);
|
|
}
|
|
|
|
if ((fieldType.IsEnum) || (fieldType == typeof(bool)))
|
|
{
|
|
if (propIdx == 0)
|
|
{
|
|
var comboBox = new DarkComboBox();
|
|
comboBox.mFrameKind = .Transparent;
|
|
comboBox.mPopulateMenuAction.Add(new (menu) => { PopulateComboBox(menu, propEntries); });
|
|
subItem.AddWidget(comboBox);
|
|
subItem.mOnResized.Add(new (evt) => { comboBox.Resize(0, 0, GetValueEditWidth(subItem), subItem.mHeight + 1); });
|
|
propEntry.mComboBoxes = new List<DarkComboBox>();
|
|
propEntry.mComboBoxes.Add(comboBox);
|
|
subItem.mOnMouseDown.Add(new (evt) =>
|
|
{
|
|
comboBox.MouseDown(-1, -1, 0, 1);
|
|
//comboBox.ShowDropdown();
|
|
});
|
|
}
|
|
handledMouseDown = true;
|
|
}
|
|
else if (fieldType == typeof(List<String>)) // List<T>
|
|
{
|
|
item.MakeParent();
|
|
}
|
|
|
|
if (!handledMouseDown)
|
|
{
|
|
if (propIdx == 0)
|
|
subItem.mOnMouseDown.Add(new => PropValueClicked);
|
|
}
|
|
|
|
if ((flags.HasFlag(.BrowseForFile)) | (flags.HasFlag(.BrowseForFolder)))
|
|
{
|
|
propEntry.mEditInsets = new .();
|
|
|
|
DarkButton browseButton = new DarkButton();
|
|
browseButton.Label = "...";
|
|
browseButton.mOnMouseClick.Add(new (evt) =>
|
|
{
|
|
let path = propEntry.mCurValue.Get<String>();
|
|
if (propEntry.mFlags.HasFlag(.BrowseForFile))
|
|
{
|
|
BrowseForFile(path);
|
|
}
|
|
else
|
|
{
|
|
BrowseForFolder(path);
|
|
}
|
|
propEntry.mListViewItem.GetSubItem(1).Label = path;
|
|
CheckForChanges();
|
|
});
|
|
subItem.mOnResized.Add(new (evt) =>
|
|
{
|
|
let width = GetValueEditWidth(subItem);
|
|
propEntry.mEditInsets.mRight = GS!(22);
|
|
browseButton.mLabelYOfs = GS!(-2);
|
|
browseButton.Resize(width - GS!(21), GS!(1), GS!(20), subItem.mHeight - 2);
|
|
|
|
});
|
|
subItem.AddWidget(browseButton);
|
|
}
|
|
}
|
|
|
|
mPropPage.mPropEntries[item] = propEntries;
|
|
|
|
UpdatePropertyValue(propEntries);
|
|
|
|
return propEntries[0];
|
|
}
|
|
|
|
protected (DarkListViewItem, PropEntry) AddPropertiesItem(DarkListViewItem parent, String name, String propName = null, String[] optionValues = null, PropEntry.Flags flags = .None)
|
|
{
|
|
var item = (DarkListViewItem)parent.CreateChildItem();
|
|
item.Label = name;
|
|
item.mFocusColor = Color.Mult(DarkTheme.COLOR_TEXT, 0xFFA0A0A0);
|
|
item.mOnMouseDown.Add(new => PropValueClicked);
|
|
let propEntry = SetupPropertiesItem(item, name, propName, optionValues, flags);
|
|
return (item, propEntry);
|
|
}
|
|
|
|
protected void PropValueClicked(MouseEvent theEvent)
|
|
{
|
|
DarkListViewItem clickedItem = (DarkListViewItem)theEvent.mSender;
|
|
if (clickedItem.mColumnIdx == 0)
|
|
{
|
|
clickedItem.mListView.SetFocus();
|
|
clickedItem.mListView.GetRoot().SelectItemExclusively(clickedItem);
|
|
return;
|
|
}
|
|
|
|
if (theEvent.mX != -1)
|
|
{
|
|
clickedItem.mListView.GetRoot().SelectItemExclusively(null);
|
|
}
|
|
|
|
DarkListViewItem item = (DarkListViewItem)clickedItem;
|
|
DarkListViewItem rootItem = (DarkListViewItem)item.GetSubItem(0);
|
|
|
|
PropEntry[] propertyEntries = mPropPage.mPropEntries[rootItem];
|
|
if (propertyEntries[0].mDisabled)
|
|
return;
|
|
EditValue(item, propertyEntries);
|
|
}
|
|
|
|
protected void ArrayPropValueClicked(PropEntry[] propEntries, int32 idx)
|
|
{
|
|
var propEntry = propEntries[0];
|
|
DarkListViewItem parentItem = propEntry.mListViewItem;
|
|
DarkListViewItem clickedItem = (DarkListViewItem)parentItem.GetChildAtIndex(idx);
|
|
DarkListViewItem item = (DarkListViewItem)clickedItem.GetSubItem(1);
|
|
EditValue(item, propEntries, idx);
|
|
}
|
|
|
|
public override void DrawAll(Graphics g)
|
|
{
|
|
base.DrawAll(g);
|
|
|
|
if (mCategorySelector.mVisible)
|
|
IDEUtils.DrawOutline(g, mCategorySelector);
|
|
|
|
IDEUtils.DrawOutline(g, mPropPage.mPropertiesListView, 0, 1);
|
|
|
|
if (mSearchEdit != null)
|
|
{
|
|
g.Draw(DarkTheme.sDarkTheme.GetImage(.Search), mSearchEdit.mX + GS!(2), mSearchEdit.mY + GS!(1));
|
|
}
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
base.Update();
|
|
|
|
if (mSearchEdit != null)
|
|
{
|
|
int curVersion = mSearchEdit.mEditWidgetContent.mData.mCurTextVersionId;
|
|
if (curVersion != mSearchEdit.mSearchVersion)
|
|
{
|
|
UpdateSearch();
|
|
mSearchEdit.mSearchVersion = curVersion;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|