|
@@ -0,0 +1,869 @@
|
|
|
+using Beefy.theme.dark;
|
|
|
+using Beefy.widgets;
|
|
|
+using System;
|
|
|
+using System.Collections;
|
|
|
+using Beefy.gfx;
|
|
|
+using Beefy.events;
|
|
|
+using IDE.Compiler;
|
|
|
+using System.Threading;
|
|
|
+using System.Security.Cryptography;
|
|
|
+using Beefy.theme;
|
|
|
+
|
|
|
+namespace IDE.ui
|
|
|
+{
|
|
|
+ class GenerateListView : DarkListView
|
|
|
+ {
|
|
|
+ public GenerateDialog mNewClassDialog;
|
|
|
+ }
|
|
|
+
|
|
|
+ class GenerateKindBar : DarkComboBox
|
|
|
+ {
|
|
|
+ public class Entry
|
|
|
+ {
|
|
|
+ public String mTypeName ~ delete _;
|
|
|
+ public String mName ~ delete _;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Dictionary<String, int32> sMRU = new Dictionary<String, int32>() ~ delete _;
|
|
|
+ public static int32 sCurrentMRUIndex = 1;
|
|
|
+
|
|
|
+ public GenerateDialog mNewClassDialog;
|
|
|
+ public List<Entry> mEntries = new List<Entry>() ~ DeleteContainerAndItems!(_);
|
|
|
+ public List<Entry> mShownEntries = new List<Entry>() ~ delete _;
|
|
|
+ public String mFilterString ~ delete _;
|
|
|
+ public String mCurLocation = new String() ~ delete _;
|
|
|
+ public bool mIgnoreChange = false;
|
|
|
+
|
|
|
+ public this(GenerateDialog dialog)
|
|
|
+ {
|
|
|
+ mNewClassDialog = dialog;
|
|
|
+ mLabelAlign = FontAlign.Left;
|
|
|
+ Label = "";
|
|
|
+ mLabelX = GS!(16);
|
|
|
+ mPopulateMenuAction.Add(new => PopulateNavigationBar);
|
|
|
+ MakeEditable();
|
|
|
+ mEditWidget.mOnContentChanged.Add(new => NavigationBarChanged);
|
|
|
+ mEditWidget.mOnGotFocus.Add(new (widget) => mEditWidget.mEditWidgetContent.SelectAll());
|
|
|
+ mEditWidget.mEditWidgetContent.mWantsUndo = false;
|
|
|
+ mEditWidget.mOnSubmit.Add(new => mNewClassDialog.[Friend]EditSubmitHandler);
|
|
|
+ mFocusDropdown = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public ~this()
|
|
|
+ {
|
|
|
+ }
|
|
|
+
|
|
|
+ static ~this()
|
|
|
+ {
|
|
|
+ for (var key in sMRU.Keys)
|
|
|
+ delete key;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetLocation(String location)
|
|
|
+ {
|
|
|
+ if (mCurMenuWidget == null)
|
|
|
+ {
|
|
|
+ mIgnoreChange = true;
|
|
|
+ mEditWidget.SetText(location);
|
|
|
+ mEditWidget.mEditWidgetContent.SelectAll();
|
|
|
+ // SetText can attempt to scroll to the right to make the cursor position visible. Just scroll back to the start.
|
|
|
+ mEditWidget.HorzScrollTo(0);
|
|
|
+ //mNewClassDialog.SelectKind();
|
|
|
+ mIgnoreChange = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private void PopulateNavigationBar(Menu menu)
|
|
|
+ {
|
|
|
+ List<StringView> findStrs = null;
|
|
|
+ if (mFilterString != null)
|
|
|
+ findStrs = scope:: List<StringView>(mFilterString.Split(' '));
|
|
|
+
|
|
|
+ EntryLoop: for (int32 entryIdx = 0; entryIdx < mEntries.Count; entryIdx++)
|
|
|
+ {
|
|
|
+ var entry = mEntries[entryIdx];
|
|
|
+ if (findStrs != null)
|
|
|
+ {
|
|
|
+ for (let findStr in findStrs)
|
|
|
+ {
|
|
|
+ if (entry.mName.IndexOf(findStr, true) == -1)
|
|
|
+ continue EntryLoop;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ mShownEntries.Add(entry);
|
|
|
+ var menuItem = menu.AddItem(entry.mName);
|
|
|
+ menuItem.mOnMenuItemSelected.Add(new (evt) =>
|
|
|
+ {
|
|
|
+ mNewClassDialog.mPendingUIFocus = true;
|
|
|
+ ShowEntry(entryIdx, entry);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void ShowEntry(int32 entryIdx, Entry entry)
|
|
|
+ {
|
|
|
+ mEditWidget.SetText(entry.mName);
|
|
|
+ mEditWidget.mEditWidgetContent.SelectAll();
|
|
|
+ mCurMenuWidget?.Close();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void NavigationBarChanged(EditEvent theEvent)
|
|
|
+ {
|
|
|
+ if (mIgnoreChange)
|
|
|
+ return;
|
|
|
+
|
|
|
+ var editWidget = (EditWidget)theEvent.mSender;
|
|
|
+ var searchText = scope String();
|
|
|
+ editWidget.GetText(searchText);
|
|
|
+ searchText.Trim();
|
|
|
+ mFilterString = searchText;
|
|
|
+ ShowDropdown();
|
|
|
+ mFilterString = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool mIgnoreShowDropdown;
|
|
|
+
|
|
|
+ public override MenuWidget ShowDropdown()
|
|
|
+ {
|
|
|
+ if (mIgnoreShowDropdown)
|
|
|
+ return null;
|
|
|
+ mIgnoreShowDropdown = true;
|
|
|
+ defer { mIgnoreShowDropdown = false; }
|
|
|
+
|
|
|
+ if (!mEditWidget.mHasFocus)
|
|
|
+ SetFocus();
|
|
|
+
|
|
|
+ if (mFilterString == null)
|
|
|
+ mEditWidget.Content.SelectAll();
|
|
|
+
|
|
|
+ mShownEntries.Clear();
|
|
|
+ base.ShowDropdown();
|
|
|
+
|
|
|
+ int32 bestItem = -1;
|
|
|
+ int32 bestPri = -1;
|
|
|
+ var menuWidget = (DarkMenuWidget)mCurMenuWidget;
|
|
|
+
|
|
|
+ for (int32 itemIdx = 0; itemIdx < menuWidget.mItemWidgets.Count; itemIdx++)
|
|
|
+ {
|
|
|
+ var menuItemWidget = (DarkMenuItem)menuWidget.mItemWidgets[itemIdx];
|
|
|
+
|
|
|
+ int32 pri;
|
|
|
+ sMRU.TryGetValue(menuItemWidget.mMenuItem.mLabel, out pri);
|
|
|
+ if (pri > bestPri)
|
|
|
+ {
|
|
|
+ bestItem = itemIdx;
|
|
|
+ bestPri = pri;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bestItem != -1)
|
|
|
+ {
|
|
|
+ mCurMenuWidget.mOnSelectionChanged.Add(new => SelectionChanged);
|
|
|
+ mCurMenuWidget.SetSelection(bestItem);
|
|
|
+ }
|
|
|
+
|
|
|
+ return menuWidget;
|
|
|
+ }
|
|
|
+
|
|
|
+ void SelectionChanged(int selIdx)
|
|
|
+ {
|
|
|
+ if (mEditWidget.mEditWidgetContent.HasSelection())
|
|
|
+ {
|
|
|
+ bool prevIgnoreShowDropdown = mIgnoreShowDropdown;
|
|
|
+ mIgnoreShowDropdown = true;
|
|
|
+ mEditWidget.SetText("");
|
|
|
+ mIgnoreShowDropdown = prevIgnoreShowDropdown;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void MenuClosed()
|
|
|
+ {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ class GenerateDialog : IDEDialog
|
|
|
+ {
|
|
|
+ public class UIEntry
|
|
|
+ {
|
|
|
+ public String mName ~ delete _;
|
|
|
+ public String mData ~ delete _;
|
|
|
+ public String mLabel ~ delete _;
|
|
|
+ public Widget mWidget;
|
|
|
+ }
|
|
|
+
|
|
|
+ public enum ThreadState
|
|
|
+ {
|
|
|
+ None,
|
|
|
+ Executing,
|
|
|
+ Done
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool mPendingGenList;
|
|
|
+ public GenerateKindBar mKindBar;
|
|
|
+ public ThreadState mThreadState;
|
|
|
+ public int mThreadWaitCount;
|
|
|
+ public String mNamespace ~ delete _;
|
|
|
+ public String mProjectName ~ delete _;
|
|
|
+ public ProjectItem mProjectItem ~ _.ReleaseRef();
|
|
|
+ public String mFolderPath ~ delete _;
|
|
|
+ public List<UIEntry> mUIEntries = new .() ~ DeleteContainerAndItems!(_);
|
|
|
+ public GenerateKindBar.Entry mSelectedEntry;
|
|
|
+ public GenerateKindBar.Entry mPendingSelectedEntry;
|
|
|
+ public String mUIData ~ delete _;
|
|
|
+ public float mUIHeight = 0;
|
|
|
+ public OutputPanel mOutputPanel;
|
|
|
+ public bool mPendingUIFocus;
|
|
|
+ public bool mSubmitting;
|
|
|
+ public bool mSubmitQueued;
|
|
|
+ public bool mRegenerating;
|
|
|
+
|
|
|
+ public this(ProjectItem projectItem, bool allowHashMismatch = false)
|
|
|
+ {
|
|
|
+ var project = projectItem.mProject;
|
|
|
+ mProjectItem = projectItem;
|
|
|
+ mProjectItem.AddRef();
|
|
|
+
|
|
|
+ mNamespace = new .();
|
|
|
+
|
|
|
+ var projectFolder = projectItem as ProjectFolder;
|
|
|
+ var projectSource = projectItem as ProjectSource;
|
|
|
+ if (projectSource != null)
|
|
|
+ {
|
|
|
+ projectFolder = projectSource.mParentFolder;
|
|
|
+ mRegenerating = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ projectFolder.GetRelDir(mNamespace); mNamespace.Replace('/', '.'); mNamespace.Replace('\\', '.'); mNamespace.Replace(" ", "");
|
|
|
+ if (mNamespace.StartsWith("src."))
|
|
|
+ {
|
|
|
+ mNamespace.Remove(0, 4);
|
|
|
+ if (!project.mBeefGlobalOptions.mDefaultNamespace.IsWhiteSpace)
|
|
|
+ {
|
|
|
+ mNamespace.Insert(0, ".");
|
|
|
+ mNamespace.Insert(0, project.mBeefGlobalOptions.mDefaultNamespace);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (projectItem.mParentFolder == null)
|
|
|
+ {
|
|
|
+ mNamespace.Clear();
|
|
|
+ mNamespace.Append(project.mBeefGlobalOptions.mDefaultNamespace);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ mNamespace.Clear();
|
|
|
+
|
|
|
+ mFolderPath = projectFolder.GetFullImportPath(.. new .());
|
|
|
+ mProjectName = new String(projectItem.mProject.mProjectName);
|
|
|
+
|
|
|
+ mWindowFlags = .ClientSized | .TopMost | .Caption | .Border | .SysMenu | .Resizable | .PopupPosition;
|
|
|
+
|
|
|
+ AddOkCancelButtons(new (evt) => { CreateClass(); }, null, 0, 1);
|
|
|
+
|
|
|
+ Title = "Generate";
|
|
|
+
|
|
|
+ mKindBar = new GenerateKindBar(this);
|
|
|
+ AddWidget(mKindBar);
|
|
|
+ mKindBar.mEditWidget.mOnContentChanged.Add(new (theEvent) => { SelectKind(); });
|
|
|
+
|
|
|
+ if (mRegenerating)
|
|
|
+ {
|
|
|
+ mSubmitQueued = true;
|
|
|
+ mKindBar.SetVisible(false);
|
|
|
+
|
|
|
+ SourceViewPanel sourceViewPanel = gApp.ShowProjectItem(projectSource, false);
|
|
|
+
|
|
|
+ String filePath = projectSource.GetFullImportPath(.. scope .());
|
|
|
+
|
|
|
+ String text = scope .();
|
|
|
+ sourceViewPanel.mEditWidget.GetText(text);
|
|
|
+
|
|
|
+ StringView generatorName = default;
|
|
|
+ StringView hash = default;
|
|
|
+
|
|
|
+ int dataIdx = -1;
|
|
|
+ for (var line in text.Split('\n'))
|
|
|
+ {
|
|
|
+ if (!line.StartsWith("// "))
|
|
|
+ {
|
|
|
+ dataIdx = @line.MatchPos + 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ int eqPos = line.IndexOf('=');
|
|
|
+ if (eqPos == -1)
|
|
|
+ break;
|
|
|
+ StringView key = line.Substring(3, eqPos - 3);
|
|
|
+ StringView value = line.Substring(eqPos + 1);
|
|
|
+ if (key == "Generator")
|
|
|
+ generatorName = value;
|
|
|
+ else if (key == "GenHash")
|
|
|
+ hash = value;
|
|
|
+ else
|
|
|
+ {
|
|
|
+ UIEntry uiEntry = new .();
|
|
|
+ uiEntry.mName = new .(key);
|
|
|
+ uiEntry.mData = new .(value);
|
|
|
+ mUIEntries.Add(uiEntry);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((generatorName == default) || (hash == default))
|
|
|
+ {
|
|
|
+ Close();
|
|
|
+ gApp.Fail(scope $"File '{filePath}' was not generated by a generator that include regeneration information");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((dataIdx != -1) && (!allowHashMismatch))
|
|
|
+ {
|
|
|
+ var origHash = MD5Hash.Parse(hash).GetValueOrDefault();
|
|
|
+
|
|
|
+ StringView dataStr = text.Substring(dataIdx);
|
|
|
+ var checkHash = MD5.Hash(.((.)dataStr.Ptr, dataStr.Length));
|
|
|
+
|
|
|
+ if (origHash != checkHash)
|
|
|
+ {
|
|
|
+ Close();
|
|
|
+ Dialog dialog = ThemeFactory.mDefault.CreateDialog("Regenerate?", "This file has been modified since it was generated. Are you sure you want to regenerate?", DarkTheme.sDarkTheme.mIconWarning);
|
|
|
+ dialog.AddButton("Yes", new (evt) =>
|
|
|
+ {
|
|
|
+ gApp.mProjectPanel.Regenerate(true);
|
|
|
+ //dialog.Close();
|
|
|
+ });
|
|
|
+ dialog.AddButton("No", new (evt) =>
|
|
|
+ {
|
|
|
+ //dialog.Close();
|
|
|
+ });
|
|
|
+ dialog.PopupWindow(gApp.GetActiveWindow());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ GenerateKindBar.Entry entry = new .();
|
|
|
+ entry.mName = new .(generatorName);
|
|
|
+ entry.mTypeName = new .(generatorName);
|
|
|
+ mKindBar.mEntries.Add(entry);
|
|
|
+ mPendingSelectedEntry = entry;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ mPendingGenList = true;
|
|
|
+
|
|
|
+ mKindBar.mMouseVisible = false;
|
|
|
+ mTabWidgets.Add(mKindBar.mEditWidget);
|
|
|
+ }
|
|
|
+
|
|
|
+ public ~this()
|
|
|
+ {
|
|
|
+ var bfCompiler = gApp.mBfResolveCompiler;
|
|
|
+ if (mThreadState == .Executing)
|
|
|
+ {
|
|
|
+ bfCompiler.WaitForBackground();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SelectKind()
|
|
|
+ {
|
|
|
+ GenerateKindBar.Entry foundEntry = null;
|
|
|
+
|
|
|
+ String text = mKindBar.mEditWidget.GetText(.. scope .());
|
|
|
+ for (var entry in mKindBar.mEntries)
|
|
|
+ if (entry.mName == text)
|
|
|
+ foundEntry = entry;
|
|
|
+
|
|
|
+ if (foundEntry == null)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (mSelectedEntry == foundEntry)
|
|
|
+ return;
|
|
|
+
|
|
|
+ mPendingSelectedEntry = foundEntry;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void ThreadProc()
|
|
|
+ {
|
|
|
+ var bfSystem = gApp.mBfResolveSystem;
|
|
|
+ var bfCompiler = gApp.mBfResolveCompiler;
|
|
|
+
|
|
|
+ String outStr = scope String();
|
|
|
+
|
|
|
+ bfSystem.Lock(0);
|
|
|
+ defer bfSystem.Unlock();
|
|
|
+
|
|
|
+ if (mSelectedEntry != null)
|
|
|
+ {
|
|
|
+ String args = scope .();
|
|
|
+ var project = gApp.mWorkspace.FindProject(mProjectName);
|
|
|
+ if (project == null)
|
|
|
+ return;
|
|
|
+ using (gApp.mMonitor.Enter())
|
|
|
+ {
|
|
|
+ args.AppendF(
|
|
|
+ $"""
|
|
|
+ ProjectName\t{mProjectName}
|
|
|
+ ProjectDir\t{project.mProjectPath}
|
|
|
+ FolderDir\t{mFolderPath}
|
|
|
+ Namespace\t{mNamespace}
|
|
|
+ DefaultNamespace\t{project.mBeefGlobalOptions.mDefaultNamespace}
|
|
|
+ WorkspaceName\t{gApp.mWorkspace.mName}
|
|
|
+ WorkspaceDir\t{gApp.mWorkspace.mDir}
|
|
|
+ DateTime\t{DateTime.Now}
|
|
|
+
|
|
|
+ """);
|
|
|
+
|
|
|
+ if (mSubmitting)
|
|
|
+ {
|
|
|
+ args.AppendF($"Generator\t{mSelectedEntry.mTypeName}\n");
|
|
|
+ for (var uiEntry in mUIEntries)
|
|
|
+ {
|
|
|
+ String data = scope .();
|
|
|
+ if (uiEntry.mData != null)
|
|
|
+ {
|
|
|
+ data.Append(uiEntry.mData);
|
|
|
+ }
|
|
|
+ else if (var editWidget = uiEntry.mWidget as EditWidget)
|
|
|
+ {
|
|
|
+ editWidget.GetText(data);
|
|
|
+ }
|
|
|
+ else if (var comboBox = uiEntry.mWidget as DarkComboBox)
|
|
|
+ {
|
|
|
+ comboBox.GetLabel(data);
|
|
|
+ }
|
|
|
+ else if (var checkBox = uiEntry.mWidget as CheckBox)
|
|
|
+ {
|
|
|
+ checkBox.Checked.ToString(data);
|
|
|
+ }
|
|
|
+ data.Replace('\n', '\r');
|
|
|
+ args.AppendF($"{uiEntry.mName}\t{data}\n");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ mUIData = new String();
|
|
|
+ if (mSubmitting)
|
|
|
+ bfCompiler.GetGeneratorGenData(mSelectedEntry.mTypeName, args, mUIData);
|
|
|
+ else
|
|
|
+ bfCompiler.GetGeneratorInitData(mSelectedEntry.mTypeName, args, mUIData);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ bfCompiler.GetGeneratorTypeDefList(outStr);
|
|
|
+
|
|
|
+ for (var line in outStr.Split('\n', .RemoveEmptyEntries))
|
|
|
+ {
|
|
|
+ if (line.StartsWith("!error"))
|
|
|
+ {
|
|
|
+ ShowError(line.Substring(7));
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ var entry = new GenerateKindBar.Entry();
|
|
|
+ var partItr = line.Split('\t');
|
|
|
+ entry.mTypeName = new String(partItr.GetNext().Value);
|
|
|
+ if (partItr.GetNext() case .Ok(let val))
|
|
|
+ entry.mName = new String(val);
|
|
|
+ else
|
|
|
+ {
|
|
|
+ entry.mName = new String(entry.mTypeName);
|
|
|
+ int termPos = entry.mName.LastIndexOf('.');
|
|
|
+ if (termPos != -1)
|
|
|
+ entry.mName.Remove(0, termPos + 1);
|
|
|
+ termPos = entry.mName.LastIndexOf('+');
|
|
|
+ if (termPos != -1)
|
|
|
+ entry.mName.Remove(0, termPos + 1);
|
|
|
+ }
|
|
|
+ mKindBar.mEntries.Add(entry);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void CalcSize()
|
|
|
+ {
|
|
|
+ mWidth = GS!(320);
|
|
|
+ mHeight = GS!(96);
|
|
|
+ mMinWidth = mWidth;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override void RehupMinSize()
|
|
|
+ {
|
|
|
+ mWidgetWindow.SetMinimumSize(GS!(240), (.)mUIHeight + GS!(24), true);
|
|
|
+ }
|
|
|
+
|
|
|
+ void CreateClass()
|
|
|
+ {
|
|
|
+ //mClassViewPanel.[Friend]mSearchEdit.mOnSubmit(null);
|
|
|
+ }
|
|
|
+
|
|
|
+ void ShowError(StringView error)
|
|
|
+ {
|
|
|
+ if (mOutputPanel == null)
|
|
|
+ {
|
|
|
+ mOutputPanel = new OutputPanel();
|
|
|
+ AddWidget(mOutputPanel);
|
|
|
+ ResizeComponents();
|
|
|
+ }
|
|
|
+ String str = scope .();
|
|
|
+ str.Append(error);
|
|
|
+ str.Replace('\r', '\n');
|
|
|
+ str.Append("\n");
|
|
|
+ mOutputPanel.WriteSmart(str);
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void Update()
|
|
|
+ {
|
|
|
+ base.Update();
|
|
|
+
|
|
|
+ if ((!mKindBar.mEditWidget.mHasFocus) && (mWidgetWindow.mHasFocus))
|
|
|
+ {
|
|
|
+ var sel = mPendingSelectedEntry ?? mSelectedEntry;
|
|
|
+ String editText = mKindBar.mEditWidget.GetText(.. scope .());
|
|
|
+ if ((sel != null) && (editText != sel.mName))
|
|
|
+ {
|
|
|
+ mKindBar.mIgnoreChange = true;
|
|
|
+ mKindBar.mEditWidget.SetText(sel.mName);
|
|
|
+ mKindBar.mIgnoreChange = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mThreadState == .Done)
|
|
|
+ {
|
|
|
+ if (mSelectedEntry != null)
|
|
|
+ {
|
|
|
+ List<UIEntry> oldEntries = scope .();
|
|
|
+ Dictionary<String, UIEntry> entryMap = scope .();
|
|
|
+ if (!mSubmitting)
|
|
|
+ {
|
|
|
+ for (var uiEntry in mUIEntries)
|
|
|
+ {
|
|
|
+ if (!entryMap.TryAdd(uiEntry.mName, uiEntry))
|
|
|
+ oldEntries.Add(uiEntry);
|
|
|
+ }
|
|
|
+ mUIEntries.Clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mUIData != null)
|
|
|
+ {
|
|
|
+ if (mOutputPanel != null)
|
|
|
+ {
|
|
|
+ mOutputPanel.RemoveSelf();
|
|
|
+ DeleteAndNullify!(mOutputPanel);
|
|
|
+ }
|
|
|
+
|
|
|
+ String fileName = default;
|
|
|
+ StringView genText = default;
|
|
|
+ bool hadError = false;
|
|
|
+
|
|
|
+ if (mUIData.IsEmpty)
|
|
|
+ {
|
|
|
+ gApp.Fail("Generator failed to return results");
|
|
|
+ }
|
|
|
+
|
|
|
+ LinesLoop: for (var line in mUIData.Split('\n', .RemoveEmptyEntries))
|
|
|
+ {
|
|
|
+ var partItr = line.Split('\t');
|
|
|
+ var kind = partItr.GetNext().Value;
|
|
|
+
|
|
|
+ switch (kind)
|
|
|
+ {
|
|
|
+ case "!error":
|
|
|
+ ShowError(line.Substring(7));
|
|
|
+ case "addEdit":
|
|
|
+ if (mSubmitting)
|
|
|
+ break;
|
|
|
+ UIEntry uiEntry = new UIEntry();
|
|
|
+ uiEntry.mName = partItr.GetNext().Value.UnQuoteString(.. new .());
|
|
|
+ uiEntry.mLabel = partItr.GetNext().Value.UnQuoteString(.. new .());
|
|
|
+ var defaultValue = partItr.GetNext().Value.UnQuoteString(.. scope .());
|
|
|
+ DarkEditWidget editWidget = new DarkEditWidget();
|
|
|
+ uiEntry.mWidget = editWidget;
|
|
|
+ editWidget.SetText(defaultValue);
|
|
|
+ editWidget.mEditWidgetContent.SelectAll();
|
|
|
+ editWidget.mOnSubmit.Add(new => EditSubmitHandler);
|
|
|
+ AddWidget(editWidget);
|
|
|
+ mUIEntries.Add(uiEntry);
|
|
|
+ mTabWidgets.Add(editWidget);
|
|
|
+ case "addCombo":
|
|
|
+ if (mSubmitting)
|
|
|
+ break;
|
|
|
+ UIEntry uiEntry = new UIEntry();
|
|
|
+ uiEntry.mName = partItr.GetNext().Value.UnQuoteString(.. new .());
|
|
|
+ uiEntry.mLabel = partItr.GetNext().Value.UnQuoteString(.. new .());
|
|
|
+ var defaultValue = partItr.GetNext().Value.UnQuoteString(.. scope .());
|
|
|
+ List<String> choices = new List<String>();
|
|
|
+ DarkComboBox comboBox = new DarkComboBox();
|
|
|
+ while (partItr.GetNext() case .Ok(let val))
|
|
|
+ {
|
|
|
+ choices.Add(val.UnQuoteString(.. new .()));
|
|
|
+ }
|
|
|
+ comboBox.mOnDeleted.Add(new (widget) => { DeleteContainerAndItems!(choices); });
|
|
|
+ comboBox.mPopulateMenuAction.Add(new (menu) =>
|
|
|
+ {
|
|
|
+ for (var choice in choices)
|
|
|
+ {
|
|
|
+ var item = menu.AddItem(choice);
|
|
|
+ item.mOnMenuItemSelected.Add(new (menu) =>
|
|
|
+ {
|
|
|
+ comboBox.Label = menu.mLabel;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ uiEntry.mWidget = comboBox;
|
|
|
+ comboBox.Label = defaultValue;
|
|
|
+ AddWidget(comboBox);
|
|
|
+ mUIEntries.Add(uiEntry);
|
|
|
+ mTabWidgets.Add(comboBox);
|
|
|
+ case "addCheckbox":
|
|
|
+ if (mSubmitting)
|
|
|
+ break;
|
|
|
+ UIEntry uiEntry = new UIEntry();
|
|
|
+ uiEntry.mName = partItr.GetNext().Value.UnQuoteString(.. new .());
|
|
|
+ uiEntry.mLabel = partItr.GetNext().Value.UnQuoteString(.. new .());
|
|
|
+ var defaultValue = partItr.GetNext().Value;
|
|
|
+ DarkCheckBox checkbox = new DarkCheckBox();
|
|
|
+ uiEntry.mWidget = checkbox;
|
|
|
+ checkbox.Label = uiEntry.mLabel;
|
|
|
+ checkbox.Checked = defaultValue == "True";
|
|
|
+ AddWidget(checkbox);
|
|
|
+ mUIEntries.Add(uiEntry);
|
|
|
+ mTabWidgets.Add(checkbox);
|
|
|
+ case "error":
|
|
|
+ hadError = true;
|
|
|
+ gApp.Fail(line.Substring(6).UnQuoteString(.. scope .()));
|
|
|
+ case "fileName":
|
|
|
+ fileName = line.Substring(9).UnQuoteString(.. scope:: .());
|
|
|
+ case "options":
|
|
|
+ case "data":
|
|
|
+ genText = .(mUIData, @line.MatchPos + 1);
|
|
|
+ break LinesLoop;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ResizeComponents();
|
|
|
+ RehupMinSize();
|
|
|
+
|
|
|
+ if (fileName?.EndsWith(".bf", .OrdinalIgnoreCase) == true)
|
|
|
+ fileName.RemoveFromEnd(3);
|
|
|
+
|
|
|
+ if ((fileName != null) && (!mRegenerating))
|
|
|
+ {
|
|
|
+ for (char8 c in fileName.RawChars)
|
|
|
+ {
|
|
|
+ if (!c.IsLetterOrDigit)
|
|
|
+ {
|
|
|
+ gApp.Fail(scope $"Invalid generated file name: {fileName}");
|
|
|
+ hadError = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fileName.IsEmpty)
|
|
|
+ {
|
|
|
+ gApp.Fail("Geneator failed to specify file name");
|
|
|
+ hadError = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((!hadError) && (genText != default) && (fileName != null))
|
|
|
+ {
|
|
|
+ if (!mProjectItem.mDetached)
|
|
|
+ {
|
|
|
+ if (mRegenerating)
|
|
|
+ {
|
|
|
+ gApp.mProjectPanel.Regenerate(mProjectItem as ProjectSource, genText);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ gApp.mProjectPanel.Generate(mProjectItem as ProjectFolder, fileName, genText);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Close();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mPendingUIFocus)
|
|
|
+ {
|
|
|
+ mPendingUIFocus = false;
|
|
|
+ if (!mUIEntries.IsEmpty)
|
|
|
+ mUIEntries[0].mWidget.SetFocus();
|
|
|
+ }
|
|
|
+
|
|
|
+ DeleteAndNullify!(mUIData);
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+
|
|
|
+ if (mSubmitting)
|
|
|
+ {
|
|
|
+ if (!mClosed)
|
|
|
+ {
|
|
|
+ mSubmitting = false;
|
|
|
+ mSubmitQueued = false;
|
|
|
+ mDefaultButton.mDisabled = false;
|
|
|
+ mEscButton.mDisabled = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ for (var uiEntry in entryMap.Values)
|
|
|
+ oldEntries.Add(uiEntry);
|
|
|
+
|
|
|
+ for (var uiEntry in oldEntries)
|
|
|
+ {
|
|
|
+ mTabWidgets.Remove(uiEntry.mWidget);
|
|
|
+ uiEntry.mWidget.RemoveSelf();
|
|
|
+ DeleteAndNullify!(uiEntry.mWidget);
|
|
|
+ }
|
|
|
+
|
|
|
+ ClearAndDeleteItems(oldEntries);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ mKindBar.mMouseVisible = true;
|
|
|
+ mKindBar.SetFocus();
|
|
|
+ mKindBar.SetLocation("New Class");
|
|
|
+ }
|
|
|
+ mThreadState = .None;
|
|
|
+ MarkDirty();
|
|
|
+ }
|
|
|
+
|
|
|
+ bool isWorking = false;
|
|
|
+ if (mThreadState == .None)
|
|
|
+ {
|
|
|
+ if ((mPendingGenList) || (mPendingSelectedEntry != null))
|
|
|
+ {
|
|
|
+ isWorking = true;
|
|
|
+ var bfCompiler = gApp.mBfResolveCompiler;
|
|
|
+ if (!bfCompiler.IsPerformingBackgroundOperation())
|
|
|
+ {
|
|
|
+ bfCompiler.CheckThreadDone();
|
|
|
+
|
|
|
+ mPendingGenList = false;
|
|
|
+ if (mPendingSelectedEntry != null)
|
|
|
+ {
|
|
|
+ if (mSubmitQueued)
|
|
|
+ mSubmitting = true;
|
|
|
+ mSelectedEntry = mPendingSelectedEntry;
|
|
|
+ mPendingSelectedEntry = null;
|
|
|
+ }
|
|
|
+ mThreadState = .Executing;
|
|
|
+ bfCompiler.DoBackgroundHi(new => ThreadProc, new () =>
|
|
|
+ {
|
|
|
+ mThreadState = .Done;
|
|
|
+ }, false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ gApp.mBfResolveCompiler.CheckThreadDone();
|
|
|
+
|
|
|
+ if ((mThreadState == .Executing) || (isWorking))
|
|
|
+ {
|
|
|
+ mThreadWaitCount++;
|
|
|
+ if (mUpdateCnt % 8 == 0)
|
|
|
+ MarkDirty();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ mThreadWaitCount = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void Resize(float x, float y, float width, float height)
|
|
|
+ {
|
|
|
+ base.Resize(x, y, width, height);
|
|
|
+ ResizeComponents();
|
|
|
+ //mClassViewPanel.Resize(0, 0, width, height - GS!(34));
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void PopupWindow(WidgetWindow parentWindow, float offsetX = 0, float offsetY = 0)
|
|
|
+ {
|
|
|
+ base.PopupWindow(parentWindow, offsetX, offsetY);
|
|
|
+ //mKindBar.SetFocus();
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void Draw(Graphics g)
|
|
|
+ {
|
|
|
+ base.Draw(g);
|
|
|
+
|
|
|
+ void DrawLabel(Widget widget, StringView label)
|
|
|
+ {
|
|
|
+ if (widget == null)
|
|
|
+ return;
|
|
|
+ if (widget is CheckBox)
|
|
|
+ return;
|
|
|
+ g.DrawString(label, widget.mX + GS!(6), widget.mY - GS!(20));
|
|
|
+ }
|
|
|
+
|
|
|
+ DrawLabel(mKindBar, mRegenerating ? "Regenerating ..." : "Using Generator");
|
|
|
+ for (var uiEntry in mUIEntries)
|
|
|
+ DrawLabel(uiEntry.mWidget, uiEntry.mLabel);
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void DrawAll(Graphics g)
|
|
|
+ {
|
|
|
+ base.DrawAll(g);
|
|
|
+
|
|
|
+ if (mThreadWaitCount > 10)
|
|
|
+ {
|
|
|
+ using (g.PushColor(0x60505050))
|
|
|
+ g.FillRect(0, 0, mWidth, mHeight - GS!(40));
|
|
|
+ IDEUtils.DrawWait(g, mWidth/2, mHeight/2, mUpdateCnt);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void ResizeComponents()
|
|
|
+ {
|
|
|
+ base.ResizeComponents();
|
|
|
+
|
|
|
+ mUIHeight = GS!(32);
|
|
|
+
|
|
|
+ float insetSize = GS!(12);
|
|
|
+
|
|
|
+ mKindBar.Resize(insetSize, mUIHeight, mWidth - insetSize - insetSize, GS!(22));
|
|
|
+ mUIHeight += GS!(52);
|
|
|
+
|
|
|
+ for (var uiEntry in mUIEntries)
|
|
|
+ {
|
|
|
+ if (uiEntry.mWidget == null)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ float height = GS!(22);
|
|
|
+ if (uiEntry.mWidget is ComboBox)
|
|
|
+ height = GS!(26);
|
|
|
+
|
|
|
+ if (uiEntry.mWidget is CheckBox)
|
|
|
+ {
|
|
|
+ mUIHeight -= GS!(20);
|
|
|
+ height = GS!(20);
|
|
|
+ }
|
|
|
+
|
|
|
+ uiEntry.mWidget.Resize(insetSize, mUIHeight, mWidth - insetSize - insetSize, height);
|
|
|
+ mUIHeight += height + GS!(28);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mOutputPanel != null)
|
|
|
+ {
|
|
|
+ float startY = mKindBar.mVisible ? GS!(60) : GS!(36);
|
|
|
+ mOutputPanel.Resize(insetSize, startY, mWidth - insetSize - insetSize, Math.Max(mHeight - startY - GS!(44), GS!(32)));
|
|
|
+ mUIHeight = Math.Max(mUIHeight, GS!(160));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void Close()
|
|
|
+ {
|
|
|
+ if (mThreadState == .Executing)
|
|
|
+ {
|
|
|
+ var bfCompiler = gApp.mBfResolveCompiler;
|
|
|
+ bfCompiler.RequestFastFinish();
|
|
|
+ bfCompiler.WaitForBackground();
|
|
|
+ }
|
|
|
+ base.Close();
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void Submit()
|
|
|
+ {
|
|
|
+ mDefaultButton.mDisabled = true;
|
|
|
+ mEscButton.mDisabled = true;
|
|
|
+
|
|
|
+ if (mSubmitQueued)
|
|
|
+ return;
|
|
|
+ mSubmitQueued = true;
|
|
|
+ mPendingSelectedEntry = mPendingSelectedEntry ?? mSelectedEntry;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|