mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-16 22:27:45 +08:00
More progress on C# Console - implement AutoCompletes, some cleanups
This commit is contained in:
parent
712bf7b669
commit
6e9bb83099
@ -139,7 +139,7 @@ Building the project should be straight-forward, the references are all inside t
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
* [ManlyMarco](https://github.com/ManlyMarco) for [Runtime Unity Editor](https://github.com/ManlyMarco/RuntimeUnityEditor) \[[license](THIRDPARTY_LICENSES.md#runtimeunityeditor-license)\], snippets from the REPL Console were used for UnityExplorer's C# Console.
|
||||
* [ManlyMarco](https://github.com/ManlyMarco) for [Runtime Unity Editor](https://github.com/ManlyMarco/RuntimeUnityEditor) \[[license](THIRDPARTY_LICENSES.md#runtimeunityeditor-license)\], the ScriptEvaluator from RUE's REPL console was used for UnityExplorer's C# console.
|
||||
* [denikson](https://github.com/denikson) (aka Horse) for [mcs-unity](https://github.com/denikson/mcs-unity) \[no license\], used as the `Mono.CSharp` reference for the C# Console.
|
||||
* [HerpDerpenstine](https://github.com/HerpDerpinstine) for [MelonCoroutines](https://github.com/LavaGang/MelonLoader/blob/6cc958ec23b5e2e8453a73bc2e0d5aa353d4f0d1/MelonLoader.Support.Il2Cpp/MelonCoroutines.cs) \[[license](THIRDPARTY_LICENSES.md#melonloader-license)\], they were included for standalone IL2CPP coroutine support.
|
||||
|
||||
|
79
src/UI/CSConsole/CSAutoCompleter.cs
Normal file
79
src/UI/CSConsole/CSAutoCompleter.cs
Normal file
@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.UI.CSharpConsole.Lexers;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
|
||||
namespace UnityExplorer.UI.CSharpConsole
|
||||
{
|
||||
public class CSAutoCompleter : ISuggestionProvider
|
||||
{
|
||||
public InputFieldRef InputField => CSConsole.Input;
|
||||
|
||||
public bool AnchorToCaretPosition => true;
|
||||
|
||||
public void OnSuggestionClicked(Suggestion suggestion)
|
||||
{
|
||||
CSConsole.InsertSuggestionAtCaret(suggestion.UnderlyingValue);
|
||||
}
|
||||
|
||||
private readonly HashSet<char> delimiters = new HashSet<char>
|
||||
{
|
||||
'{', '}', ',', ';', '<', '>', '(', ')', '[', ']', '=', '|', '&', '?'
|
||||
};
|
||||
|
||||
//private readonly HashSet<string> expressions = new HashSet<string>
|
||||
//{
|
||||
// "new",
|
||||
// "is", "as",
|
||||
// "return", "yield", "throw", "in",
|
||||
// "do", "for", "foreach",
|
||||
// "else",
|
||||
//};
|
||||
|
||||
public void CheckAutocompletes()
|
||||
{
|
||||
|
||||
if (string.IsNullOrEmpty(InputField.Text))
|
||||
{
|
||||
AutoCompleteModal.Instance.ReleaseOwnership(this);
|
||||
return;
|
||||
}
|
||||
|
||||
int caret = Math.Max(0, Math.Min(InputField.Text.Length - 1, InputField.Component.caretPosition - 1));
|
||||
int i = caret;
|
||||
|
||||
while (i > 0)
|
||||
{
|
||||
i--;
|
||||
char c = InputField.Text[i];
|
||||
if (char.IsWhiteSpace(c) || delimiters.Contains(c))
|
||||
{
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i = Math.Max(0, i);
|
||||
|
||||
string input = InputField.Text.Substring(i, (caret - i + 1));
|
||||
|
||||
string[] evaluatorCompletions = CSConsole.Evaluator.GetCompletions(input, out string prefix);
|
||||
|
||||
if (evaluatorCompletions != null && evaluatorCompletions.Any())
|
||||
{
|
||||
var suggestions = from completion in evaluatorCompletions
|
||||
select new Suggestion($"<color=cyan>{prefix}</color>{completion}", completion);
|
||||
|
||||
AutoCompleteModal.Instance.TakeOwnership(this);
|
||||
AutoCompleteModal.Instance.SetSuggestions(suggestions);
|
||||
}
|
||||
else
|
||||
{
|
||||
AutoCompleteModal.Instance.ReleaseOwnership(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ using UnityEngine.UI;
|
||||
using UnityExplorer.Core.CSharp;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
|
||||
namespace UnityExplorer.UI.CSharpConsole
|
||||
{
|
||||
@ -25,9 +26,9 @@ The following helper methods are available:
|
||||
|
||||
* <color=#add490>StartCoroutine(IEnumerator routine)</color> start the IEnumerator as a UnityEngine.Coroutine
|
||||
|
||||
* <color=#add490>CurrentTarget()</color> returns the currently inspected target on the Home page
|
||||
* <color=#add490>CurrentTarget()</color> returns the target of the active Inspector tab as System.Object
|
||||
|
||||
* <color=#add490>AllTargets()</color> returns an object[] array containing all inspected instances
|
||||
* <color=#add490>AllTargets()</color> returns a System.Object[] array containing the targets of all active tabs
|
||||
|
||||
* <color=#add490>Inspect(someObject)</color> to inspect an instance, eg. Inspect(Camera.main);
|
||||
|
||||
@ -58,12 +59,16 @@ The following helper methods are available:
|
||||
|
||||
public static ScriptEvaluator Evaluator;
|
||||
public static LexerBuilder Lexer;
|
||||
public static CSAutoCompleter Completer;
|
||||
|
||||
private static StringBuilder evaluatorOutput;
|
||||
private static HashSet<string> usingDirectives;
|
||||
private static StringBuilder evaluatorOutput;
|
||||
|
||||
private static CSConsolePanel Panel => UIManager.CSharpConsole;
|
||||
private static InputFieldRef Input => Panel.Input;
|
||||
public static CSConsolePanel Panel => UIManager.CSharpConsole;
|
||||
public static InputFieldRef Input => Panel.Input;
|
||||
|
||||
public static int LastCaretPosition { get; private set; }
|
||||
internal static float defaultInputFieldAlpha;
|
||||
|
||||
// Todo save as config?
|
||||
public static bool EnableCtrlRShortcut { get; private set; } = true;
|
||||
@ -84,73 +89,66 @@ The following helper methods are available:
|
||||
}
|
||||
|
||||
Lexer = new LexerBuilder();
|
||||
Completer = new CSAutoCompleter();
|
||||
|
||||
Panel.OnInputChanged += OnConsoleInputChanged;
|
||||
Panel.InputScroll.OnScroll += ForceOnContentChange;
|
||||
// TODO other panel listeners (buttons, etc)
|
||||
Panel.InputScroll.OnScroll += OnInputScrolled;
|
||||
Panel.OnCompileClicked += Evaluate;
|
||||
Panel.OnResetClicked += ResetConsole;
|
||||
Panel.OnAutoIndentToggled += OnToggleAutoIndent;
|
||||
Panel.OnCtrlRToggled += OnToggleCtrlRShortcut;
|
||||
Panel.OnSuggestionsToggled += OnToggleSuggestions;
|
||||
|
||||
}
|
||||
|
||||
// Updating and event listeners
|
||||
|
||||
private static readonly KeyCode[] onFocusKeys =
|
||||
{
|
||||
KeyCode.Return, KeyCode.Backspace, KeyCode.UpArrow,
|
||||
KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow
|
||||
};
|
||||
|
||||
public static void Update()
|
||||
{
|
||||
UpdateCaret();
|
||||
|
||||
if (EnableCtrlRShortcut)
|
||||
{
|
||||
if ((InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl))
|
||||
&& InputManager.GetKeyDown(KeyCode.R))
|
||||
{
|
||||
var text = Panel.Input.Text.Trim();
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
Evaluate(text);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if (EnableAutoIndent && InputManager.GetKeyDown(KeyCode.Return))
|
||||
// DoAutoIndent();
|
||||
|
||||
//if (EnableAutocompletes && InputField.isFocused)
|
||||
//{
|
||||
// if (InputManager.GetMouseButton(0) || onFocusKeys.Any(it => InputManager.GetKeyDown(it)))
|
||||
// UpdateAutocompletes();
|
||||
//}
|
||||
}
|
||||
|
||||
private static void ForceOnContentChange()
|
||||
{
|
||||
OnConsoleInputChanged(Input.Text);
|
||||
}
|
||||
private static void OnInputScrolled() => HighlightVisibleInput(Input.Text);
|
||||
|
||||
// Invoked at most once per frame
|
||||
private static void OnConsoleInputChanged(string value)
|
||||
{
|
||||
// todo auto indent? or only on enter?
|
||||
// todo update auto completes
|
||||
LastCaretPosition = Input.Component.caretPosition;
|
||||
|
||||
if (EnableSuggestions)
|
||||
Completer.CheckAutocompletes();
|
||||
|
||||
// syntax highlight
|
||||
HighlightVisibleInput(value);
|
||||
}
|
||||
|
||||
public static void Update()
|
||||
{
|
||||
int lastCaretPos = LastCaretPosition;
|
||||
UpdateCaret();
|
||||
bool caretMoved = lastCaretPos != LastCaretPosition;
|
||||
|
||||
if (EnableSuggestions && caretMoved)
|
||||
{
|
||||
Completer.CheckAutocompletes();
|
||||
}
|
||||
|
||||
//if (EnableAutoIndent && caretMoved)
|
||||
// DoAutoIndent();
|
||||
|
||||
if (EnableCtrlRShortcut
|
||||
&& (InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl))
|
||||
&& InputManager.GetKeyDown(KeyCode.R))
|
||||
{
|
||||
Evaluate(Panel.Input.Text);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateCaret()
|
||||
{
|
||||
LastCaretPosition = Input.InputField.caretPosition;
|
||||
LastCaretPosition = Input.Component.caretPosition;
|
||||
|
||||
// todo check if out of bounds
|
||||
// todo check if out of bounds, move content if so
|
||||
}
|
||||
|
||||
|
||||
#region Evaluating console input
|
||||
#region Evaluating
|
||||
|
||||
public static void ResetConsole() => ResetConsole(true);
|
||||
|
||||
public static void ResetConsole(bool logSuccess = true)
|
||||
{
|
||||
@ -180,6 +178,11 @@ The following helper methods are available:
|
||||
}
|
||||
}
|
||||
|
||||
public static void Evaluate()
|
||||
{
|
||||
Evaluate(Input.Text);
|
||||
}
|
||||
|
||||
public static void Evaluate(string input, bool supressLog = false)
|
||||
{
|
||||
try
|
||||
@ -217,48 +220,44 @@ The following helper methods are available:
|
||||
|
||||
private static void HighlightVisibleInput(string value)
|
||||
{
|
||||
int startLine = 0;
|
||||
int endLine = Input.TextGenerator.lineCount - 1;
|
||||
int startIdx = 0;
|
||||
int endIdx = value.Length - 1;
|
||||
int topLine = 0;
|
||||
|
||||
// Calculate visible text if necessary
|
||||
if (Input.Rect.rect.height > Panel.InputScroll.ViewportRect.rect.height)
|
||||
{
|
||||
// This was mostly done through trial and error, it probably depends on the anchoring.
|
||||
int topLine = -1;
|
||||
topLine = -1;
|
||||
int bottomLine = -1;
|
||||
var heightCorrection = Input.Rect.rect.height * 0.5f;
|
||||
|
||||
var viewportMin = Input.Rect.rect.height - Input.Rect.anchoredPosition.y;
|
||||
var viewportMax = viewportMin - Panel.InputScroll.ViewportRect.rect.height;
|
||||
// the top and bottom position of the viewport in relation to the text height
|
||||
// they need the half-height adjustment to normalize against the 'line.topY' value.
|
||||
var viewportMin = Input.Rect.rect.height - Input.Rect.anchoredPosition.y - (Input.Rect.rect.height * 0.5f);
|
||||
var viewportMax = viewportMin - Panel.InputScroll.ViewportRect.rect.height - (Input.Rect.rect.height * 0.5f);
|
||||
|
||||
for (int i = 0; i < Input.TextGenerator.lineCount; i++)
|
||||
{
|
||||
var line = Input.TextGenerator.lines[i];
|
||||
var pos = line.topY + heightCorrection;
|
||||
|
||||
// if top of line is below the viewport top
|
||||
if (topLine == -1 && pos <= viewportMin)
|
||||
// if not set the top line yet, and top of line is below the viewport top
|
||||
if (topLine == -1 && line.topY <= viewportMin)
|
||||
topLine = i;
|
||||
|
||||
// if bottom of line is below the viewport bottom
|
||||
if ((pos - line.height) >= viewportMax)
|
||||
if ((line.topY - line.height) >= viewportMax)
|
||||
bottomLine = i;
|
||||
}
|
||||
// make sure lines are valid
|
||||
topLine = Math.Max(0, topLine - 1);
|
||||
bottomLine = Math.Min(Input.TextGenerator.lineCount - 1, bottomLine + 1);
|
||||
|
||||
startLine = Math.Max(0, topLine - 1);
|
||||
endLine = Math.Min(Input.TextGenerator.lineCount - 1, bottomLine + 1);
|
||||
startIdx = Input.TextGenerator.lines[topLine].startCharIdx;
|
||||
endIdx = bottomLine == Input.TextGenerator.lineCount
|
||||
? value.Length - 1
|
||||
: (Input.TextGenerator.lines[bottomLine + 1].startCharIdx - 1);
|
||||
}
|
||||
|
||||
int startIdx = Input.TextGenerator.lines[startLine].startCharIdx;
|
||||
int endIdx;
|
||||
if (endLine >= Input.TextGenerator.lineCount - 1)
|
||||
endIdx = value.Length - 1;
|
||||
else
|
||||
endIdx = Math.Min(value.Length - 1, Input.TextGenerator.lines[endLine + 1].startCharIdx);
|
||||
|
||||
|
||||
// Highlight the visible text with the LexerBuilder
|
||||
Panel.HighlightText.text = Lexer.BuildHighlightedString(value, startIdx, endIdx, startLine);
|
||||
Panel.HighlightText.text = Lexer.BuildHighlightedString(value, startIdx, endIdx, topLine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -266,7 +265,7 @@ The following helper methods are available:
|
||||
|
||||
#region Autocompletes
|
||||
|
||||
public static void UseSuggestion(string suggestion)
|
||||
public static void InsertSuggestionAtCaret(string suggestion)
|
||||
{
|
||||
string input = Input.Text;
|
||||
input = input.Insert(LastCaretPosition, suggestion);
|
||||
@ -275,25 +274,23 @@ The following helper methods are available:
|
||||
RuntimeProvider.Instance.StartCoroutine(SetAutocompleteCaret(LastCaretPosition += suggestion.Length));
|
||||
}
|
||||
|
||||
public static int LastCaretPosition { get; private set; }
|
||||
internal static float defaultInputFieldAlpha;
|
||||
|
||||
private static IEnumerator SetAutocompleteCaret(int caretPosition)
|
||||
{
|
||||
var color = Input.InputField.selectionColor;
|
||||
var color = Input.Component.selectionColor;
|
||||
color.a = 0f;
|
||||
Input.InputField.selectionColor = color;
|
||||
Input.Component.selectionColor = color;
|
||||
yield return null;
|
||||
|
||||
EventSystem.current.SetSelectedGameObject(Panel.Input.UIRoot, null);
|
||||
yield return null;
|
||||
|
||||
Input.InputField.caretPosition = caretPosition;
|
||||
Input.InputField.selectionFocusPosition = caretPosition;
|
||||
Input.Component.caretPosition = caretPosition;
|
||||
Input.Component.selectionFocusPosition = caretPosition;
|
||||
color.a = defaultInputFieldAlpha;
|
||||
Input.InputField.selectionColor = color;
|
||||
Input.Component.selectionColor = color;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@ -485,5 +482,25 @@ The following helper methods are available:
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region UI Listeners and options
|
||||
|
||||
private static void OnToggleAutoIndent(bool value)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
private static void OnToggleCtrlRShortcut(bool value)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
private static void OnToggleSuggestions(bool value)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,9 @@ namespace UnityExplorer.UI.CSharpConsole.Lexers
|
||||
// all symbols are delimiters
|
||||
public override IEnumerable<char> Delimiters => symbols;
|
||||
|
||||
private readonly HashSet<char> symbols = new HashSet<char>
|
||||
public static bool IsSymbol(char c) => symbols.Contains(c);
|
||||
|
||||
public static readonly HashSet<char> symbols = new HashSet<char>
|
||||
{
|
||||
'[', '{', '(', // open
|
||||
']', '}', ')', // close
|
||||
@ -29,14 +31,14 @@ namespace UnityExplorer.UI.CSharpConsole.Lexers
|
||||
if (!lexer.IsDelimiter(lexer.Previous, true, true))
|
||||
return false;
|
||||
|
||||
if (symbols.Contains(lexer.Current))
|
||||
if (IsSymbol(lexer.Current))
|
||||
{
|
||||
do
|
||||
{
|
||||
lexer.Commit();
|
||||
lexer.PeekNext();
|
||||
}
|
||||
while (symbols.Contains(lexer.Current));
|
||||
while (IsSymbol(lexer.Current));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ using System.IO;
|
||||
using System.Reflection;
|
||||
using Mono.CSharp;
|
||||
|
||||
// Thanks to ManlyMarco for most of this
|
||||
// Thanks to ManlyMarco for this
|
||||
|
||||
namespace UnityExplorer.Core.CSharp
|
||||
{
|
||||
@ -22,7 +22,7 @@ namespace UnityExplorer.Core.CSharp
|
||||
{
|
||||
_textWriter = tw;
|
||||
|
||||
ImportAppdomainAssemblies(ReferenceAssembly);
|
||||
ImportAppdomainAssemblies(Reference);
|
||||
AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad;
|
||||
}
|
||||
|
||||
@ -39,7 +39,15 @@ namespace UnityExplorer.Core.CSharp
|
||||
if (StdLib.Contains(name))
|
||||
return;
|
||||
|
||||
ReferenceAssembly(args.LoadedAssembly);
|
||||
Reference(args.LoadedAssembly);
|
||||
}
|
||||
|
||||
private void Reference(Assembly asm)
|
||||
{
|
||||
var name = asm.GetName().Name;
|
||||
if (name == "completions")
|
||||
return;
|
||||
ReferenceAssembly(asm);
|
||||
}
|
||||
|
||||
private static CompilerContext BuildContext(TextWriter tw)
|
||||
|
@ -6,7 +6,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
|
||||
namespace UnityExplorer.Core.CSharp
|
||||
namespace UnityExplorer.UI.CSharpConsole
|
||||
{
|
||||
public class ScriptInteraction : InteractiveBase
|
||||
{
|
||||
@ -20,45 +20,39 @@ namespace UnityExplorer.Core.CSharp
|
||||
RuntimeProvider.Instance.StartCoroutine(ienumerator);
|
||||
}
|
||||
|
||||
//public static void AddUsing(string directive)
|
||||
//{
|
||||
// CSharpConsole.Instance.AddUsing(directive);
|
||||
//}
|
||||
public static void AddUsing(string directive)
|
||||
{
|
||||
CSConsole.AddUsing(directive);
|
||||
}
|
||||
|
||||
//public static void GetUsing()
|
||||
//{
|
||||
// ExplorerCore.Log(CSharpConsole.Instance.Evaluator.GetUsing());
|
||||
//}
|
||||
public static void GetUsing()
|
||||
{
|
||||
ExplorerCore.Log(CSConsole.Evaluator.GetUsing());
|
||||
}
|
||||
|
||||
//public static void Reset()
|
||||
//{
|
||||
// CSharpConsole.Instance.ResetConsole();
|
||||
//}
|
||||
public static void Reset()
|
||||
{
|
||||
CSConsole.ResetConsole();
|
||||
}
|
||||
|
||||
//public static object CurrentTarget()
|
||||
//{
|
||||
// return InspectorManager.Instance?.m_activeInspector?.Target;
|
||||
//}
|
||||
public static object CurrentTarget()
|
||||
{
|
||||
return InspectorManager.ActiveInspector?.Target;
|
||||
}
|
||||
|
||||
//public static object[] AllTargets()
|
||||
//{
|
||||
// int count = InspectorManager.Instance?.m_currentInspectors.Count ?? 0;
|
||||
// object[] ret = new object[count];
|
||||
// for (int i = 0; i < count; i++)
|
||||
// {
|
||||
// ret[i] = InspectorManager.Instance?.m_currentInspectors[i].Target;
|
||||
// }
|
||||
// return ret;
|
||||
//}
|
||||
public static object[] AllTargets()
|
||||
{
|
||||
return InspectorManager.Inspectors.Select(it => it.Target).ToArray();
|
||||
}
|
||||
|
||||
//public static void Inspect(object obj)
|
||||
//{
|
||||
// InspectorManager.Instance.Inspect(obj);
|
||||
//}
|
||||
public static void Inspect(object obj)
|
||||
{
|
||||
InspectorManager.Inspect(obj);
|
||||
}
|
||||
|
||||
//public static void Inspect(Type type)
|
||||
//{
|
||||
// InspectorManager.Instance.Inspect(type);
|
||||
//}
|
||||
public static void Inspect(Type type)
|
||||
{
|
||||
InspectorManager.Inspect(type);
|
||||
}
|
||||
}
|
||||
}
|
@ -76,10 +76,10 @@ namespace UnityExplorer.UI.Panels
|
||||
default, TextAnchor.LowerCenter);
|
||||
UIFactory.SetLayoutElement(topBarObj, minHeight: 50, flexibleHeight: 0);
|
||||
|
||||
// Top label
|
||||
//// Top label
|
||||
|
||||
var topBarLabel = UIFactory.CreateLabel(topBarObj, "TopLabel", "C# Console", TextAnchor.MiddleLeft, default, true, 25);
|
||||
UIFactory.SetLayoutElement(topBarLabel.gameObject, preferredWidth: 150, flexibleWidth: 5000);
|
||||
//var topBarLabel = UIFactory.CreateLabel(topBarObj, "TopLabel", "C# Console", TextAnchor.MiddleLeft, default, true, 25);
|
||||
//UIFactory.SetLayoutElement(topBarLabel.gameObject, preferredWidth: 150, flexibleWidth: 5000);
|
||||
|
||||
// Enable Ctrl+R toggle
|
||||
|
||||
@ -113,10 +113,10 @@ namespace UnityExplorer.UI.Panels
|
||||
|
||||
var inputObj = UIFactory.CreateSrollInputField(this.content, "ConsoleInput", CSConsole.STARTUP_TEXT, out var inputScroller, fontSize);
|
||||
InputScroll = inputScroller;
|
||||
CSConsole.defaultInputFieldAlpha = Input.InputField.selectionColor.a;
|
||||
CSConsole.defaultInputFieldAlpha = Input.Component.selectionColor.a;
|
||||
Input.OnValueChanged += InvokeOnValueChanged;
|
||||
|
||||
InputText = Input.InputField.textComponent;
|
||||
InputText = Input.Component.textComponent;
|
||||
InputText.supportRichText = false;
|
||||
InputText.color = Color.white;
|
||||
Input.PlaceholderText.fontSize = fontSize;
|
||||
@ -148,12 +148,12 @@ namespace UnityExplorer.UI.Panels
|
||||
new Color(1, 1, 1, 0));
|
||||
|
||||
var resetButton = UIFactory.CreateButton(horozGroupObj, "ResetButton", "Reset", new Color(0.33f, 0.33f, 0.33f));
|
||||
UIFactory.SetLayoutElement(resetButton.Button.gameObject, minHeight: 45, minWidth: 80, flexibleHeight: 0);
|
||||
UIFactory.SetLayoutElement(resetButton.Component.gameObject, minHeight: 45, minWidth: 80, flexibleHeight: 0);
|
||||
resetButton.ButtonText.fontSize = 18;
|
||||
resetButton.OnClick += OnResetClicked;
|
||||
|
||||
var compileButton = UIFactory.CreateButton(horozGroupObj, "CompileButton", "Compile", new Color(0.33f, 0.5f, 0.33f));
|
||||
UIFactory.SetLayoutElement(compileButton.Button.gameObject, minHeight: 45, minWidth: 80, flexibleHeight: 0);
|
||||
UIFactory.SetLayoutElement(compileButton.Component.gameObject, minHeight: 45, minWidth: 80, flexibleHeight: 0);
|
||||
compileButton.ButtonText.fontSize = 18;
|
||||
compileButton.OnClick += OnCompileClicked;
|
||||
|
||||
|
@ -12,11 +12,11 @@ using UnityExplorer.UI.Panels;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
{
|
||||
public class AutoCompleter : UIPanel
|
||||
public class AutoCompleteModal : UIPanel
|
||||
{
|
||||
// Static
|
||||
|
||||
public static AutoCompleter Instance => UIManager.AutoCompleter;
|
||||
public static AutoCompleteModal Instance => UIManager.AutoCompleter;
|
||||
|
||||
// Instance
|
||||
|
||||
@ -36,9 +36,7 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
|
||||
private List<Suggestion> suggestions = new List<Suggestion>();
|
||||
|
||||
private int lastCaretPos;
|
||||
|
||||
public AutoCompleter()
|
||||
public AutoCompleteModal()
|
||||
{
|
||||
OnPanelsReordered += UIPanel_OnPanelsReordered;
|
||||
OnClickedOutsidePanels += AutoCompleter_OnClickedOutsidePanels;
|
||||
@ -80,7 +78,6 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
ReleaseOwnership(CurrentHandler);
|
||||
else
|
||||
{
|
||||
lastCaretPos = CurrentHandler.InputField.InputField.caretPosition;
|
||||
UpdatePosition();
|
||||
}
|
||||
}
|
||||
@ -107,9 +104,9 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
|
||||
private bool ShouldDisplay(Suggestion data, string filter) => true;
|
||||
|
||||
public void SetSuggestions(List<Suggestion> collection)
|
||||
public void SetSuggestions(IEnumerable<Suggestion> collection)
|
||||
{
|
||||
suggestions = collection;
|
||||
suggestions = collection as List<Suggestion> ?? collection.ToList();
|
||||
|
||||
if (!suggestions.Any())
|
||||
UIRoot.SetActive(false);
|
||||
@ -140,28 +137,40 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
cell.Button.ButtonText.text = suggestion.DisplayText;
|
||||
}
|
||||
|
||||
private int lastCaretPosition;
|
||||
private Vector3 lastInputPosition;
|
||||
|
||||
private void UpdatePosition()
|
||||
{
|
||||
if (CurrentHandler == null || !CurrentHandler.InputField.InputField.isFocused)
|
||||
if (CurrentHandler == null || !CurrentHandler.InputField.Component.isFocused)
|
||||
return;
|
||||
|
||||
Vector3 pos;
|
||||
var input = CurrentHandler.InputField;
|
||||
|
||||
var textGen = input.InputField.textComponent.cachedTextGenerator;
|
||||
int caretPos = 0;
|
||||
if (input.Component.caretPosition == lastCaretPosition && input.UIRoot.transform.position == lastInputPosition)
|
||||
return;
|
||||
lastInputPosition = input.UIRoot.transform.position;
|
||||
lastCaretPosition = input.Component.caretPosition;
|
||||
|
||||
if (CurrentHandler.AnchorToCaretPosition)
|
||||
{
|
||||
caretPos = lastCaretPos--;
|
||||
var textGen = input.Component.textComponent.cachedTextGeneratorForLayout;
|
||||
int caretIdx = Math.Max(0, Math.Min(textGen.characterCount - 1, input.Component.caretPosition));
|
||||
|
||||
caretPos = Math.Max(0, caretPos);
|
||||
caretPos = Math.Min(textGen.characterCount - 1, caretPos);
|
||||
// normalize the caret horizontal position
|
||||
Vector3 caretPos = textGen.characters[caretIdx].cursorPos;
|
||||
caretPos += new Vector3(input.Rect.rect.width * 0.5f, 0, 0);
|
||||
// transform to world point
|
||||
caretPos = input.UIRoot.transform.TransformPoint(caretPos);
|
||||
|
||||
uiRoot.transform.position = new Vector3(caretPos.x + 10, caretPos.y - 30, 0);
|
||||
}
|
||||
|
||||
pos = textGen.characters[caretPos].cursorPos;
|
||||
pos = input.UIRoot.transform.TransformPoint(pos);
|
||||
|
||||
else
|
||||
{
|
||||
var textGen = input.Component.textComponent.cachedTextGenerator;
|
||||
var pos = input.UIRoot.transform.TransformPoint(textGen.characters[0].cursorPos);
|
||||
uiRoot.transform.position = new Vector3(pos.x + 10, pos.y - 20, 0);
|
||||
}
|
||||
|
||||
this.Dragger.OnEndResize();
|
||||
}
|
@ -53,7 +53,7 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
SuggestionClicked?.Invoke(suggestion);
|
||||
|
||||
suggestions.Clear();
|
||||
AutoCompleter.Instance.SetSuggestions(suggestions);
|
||||
AutoCompleteModal.Instance.SetSuggestions(suggestions);
|
||||
chosenSuggestion = suggestion.UnderlyingValue;
|
||||
}
|
||||
|
||||
@ -62,14 +62,14 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
if (string.IsNullOrEmpty(value) || value == chosenSuggestion)
|
||||
{
|
||||
chosenSuggestion = null;
|
||||
AutoCompleter.Instance.ReleaseOwnership(this);
|
||||
AutoCompleteModal.Instance.ReleaseOwnership(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetSuggestions(value);
|
||||
|
||||
AutoCompleter.Instance.TakeOwnership(this);
|
||||
AutoCompleter.Instance.SetSuggestions(suggestions);
|
||||
AutoCompleteModal.Instance.TakeOwnership(this);
|
||||
AutoCompleteModal.Instance.SetSuggestions(suggestions);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,23 +105,23 @@ namespace UnityExplorer.UI.Utility
|
||||
|
||||
internal void ProcessInputText()
|
||||
{
|
||||
var curInputRect = InputField.InputField.textComponent.rectTransform.rect;
|
||||
var curInputRect = InputField.Component.textComponent.rectTransform.rect;
|
||||
var scaleFactor = RootScaler.scaleFactor;
|
||||
|
||||
// Current text settings
|
||||
var texGenSettings = InputField.InputField.textComponent.GetGenerationSettings(curInputRect.size);
|
||||
var texGenSettings = InputField.Component.textComponent.GetGenerationSettings(curInputRect.size);
|
||||
texGenSettings.generateOutOfBounds = false;
|
||||
texGenSettings.scaleFactor = scaleFactor;
|
||||
|
||||
// Preferred text rect height
|
||||
var textGen = InputField.InputField.textComponent.cachedTextGeneratorForLayout;
|
||||
var textGen = InputField.Component.textComponent.cachedTextGeneratorForLayout;
|
||||
m_desiredContentHeight = textGen.GetPreferredHeight(m_lastText, texGenSettings) + 10;
|
||||
|
||||
// TODO more intelligent jump.
|
||||
// We can detect if the caret is outside the viewport area.
|
||||
|
||||
// jump to bottom
|
||||
if (InputField.InputField.caretPosition == InputField.Text.Length
|
||||
if (InputField.Component.caretPosition == InputField.Text.Length
|
||||
&& InputField.Text.Length > 0
|
||||
&& InputField.Text[InputField.Text.Length - 1] == '\n')
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user