Skip to content

Instantly share code, notes, and snippets.

@shoffing
Created November 25, 2015 16:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shoffing/5d304ff858d25546e7e7 to your computer and use it in GitHub Desktop.
Save shoffing/5d304ff858d25546e7e7 to your computer and use it in GitHub Desktop.
Hacky workaround to fix some stuff with InputField
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
using System.Collections;
using System.IO;
public class ScriptEditor : InputField {
public Text lineNumbers;
private RectTransform rectTransform;
protected override void Start() {
rectTransform = GetComponent<RectTransform>();
onValueChange.AddListener(new UnityEngine.Events.UnityAction<string>(TextChanged));
onValueChange.AddListener(new UnityEngine.Events.UnityAction<string>(ResizeInput));
onValueChange.AddListener(new UnityEngine.Events.UnityAction<string>(UpdateLineNumbers));
onValidateInput = AutoIndent;
}
// Fix InputField not setting Text component's text
private void TextChanged(string iText) {
m_Text = iText;
UpdateLabel();
m_TextComponent.text = iText;
}
// Resize input field as new lines get added
private void ResizeInput(string iText) {
string fullText = text;
Vector2 extents = textComponent.rectTransform.rect.size;
var settings = textComponent.GetGenerationSettings(extents);
settings.generateOutOfBounds = false;
var prefHeight = new TextGenerator().GetPreferredHeight(fullText, settings) + 16;
if(prefHeight > textComponent.rectTransform.rect.height - 16 || prefHeight < textComponent.rectTransform.rect.height + 16) {
rectTransform.sizeDelta = new Vector2(rectTransform.sizeDelta.x, prefHeight);
}
}
// Update the line numbers
private void UpdateLineNumbers(string text) {
int numLines = 0;
foreach(char c in text) {
if(c == '\n') numLines++;
}
string lineNumText = "";
for(int i = 0; i <= numLines; i++) {
lineNumText += (i + 1) + "\n";
}
lineNumbers.text = lineNumText;
}
// Automatic indentation matching
private char AutoIndent(string input, int charIndex, char addedChar) {
if(addedChar == '\n') {
string prevLine;
int prevLineStart = input.LastIndexOf('\n', Mathf.Max(charIndex - 1, 0)) + 1;
prevLine = input.Substring(prevLineStart, charIndex - prevLineStart);
int numWhitespace = 0;
string autoWhitespace = "";
while(numWhitespace < prevLine.Length && (prevLine[numWhitespace] == '\t' || prevLine[numWhitespace] == ' ')) {
autoWhitespace += prevLine[numWhitespace];
numWhitespace++;
}
text = input.Insert(charIndex, '\n' + autoWhitespace);
caretPosition = charIndex + 1 + numWhitespace;
return '\0';
}
return addedChar;
}
//Returns string on given line number
public string GetTextOnLineNumber( int lineNumber ) {
using ( StringReader reader = new StringReader( text ) ) {
int currLine = 0;
string line;
while ( (line = reader.ReadLine()) != null ) {
if ( currLine == lineNumber ) {
return line;
} else {
currLine++;
}
}
return null;
}
}
// Overriding InputField
// InputField source: https://bitbucket.org/Unity-Technologies/ui/src/7c219d27562749b5581b017103c6947cebca6536/UnityEngine.UI/UI/Core/InputField.cs
// this code, is bananas. B.A.N.A.N.A.S.
public void SetText(string value) {
// Try
try {
m_Text = value;
UpdateLabel();
if(onValueChange != null)
onValueChange.Invoke(m_Text);
} catch {
SetTextForReal(value);
}
}
private void SetTextForReal(string value) {
// Try harder
m_Text = value;
UpdateLabel();
if(onValueChange != null)
onValueChange.Invoke(m_Text);
}
private int GetUnclampedCharacterLineFromPosition(Vector2 pos, TextGenerator generator)
{
if (!multiLine)
return 0;
float height = m_TextComponent.rectTransform.rect.yMax;
// Position is above first line.
if (pos.y > height)
return -1;
for (int i = 0; i < generator.lineCount; ++i)
{
float lineHeight = generator.lines[i].height / m_TextComponent.pixelsPerUnit;
if (pos.y <= height && pos.y > (height - lineHeight))
return i;
height -= lineHeight;
}
// Position is after last line.
return generator.lineCount;
}
private static int GetLineEndPosition(TextGenerator gen, int line)
{
line = Mathf.Max(line, 0);
if (line + 1 < gen.lines.Count)
return gen.lines[line + 1].startCharIdx - 1;
return gen.characterCountVisible;
}
protected new int GetCharacterIndexFromPosition(Vector2 pos)
{
TextGenerator gen = m_TextComponent.cachedTextGenerator;
if (gen.lineCount == 0)
return 0;
int line = GetUnclampedCharacterLineFromPosition(pos, gen);
if (line < 0)
return 0;
if (line >= gen.lineCount)
return gen.characterCountVisible;
int startCharIndex = gen.lines[line].startCharIdx;
int endCharIndex = GetLineEndPosition(gen, line);
for (int i = startCharIndex; i < endCharIndex; i++)
{
if (i >= gen.characterCountVisible)
break;
UICharInfo charInfo = gen.characters[i];
Vector2 charPos = charInfo.cursorPos / m_TextComponent.pixelsPerUnit;
float distToCharStart = pos.x - charPos.x;
float distToCharEnd = charPos.x + (charInfo.charWidth / m_TextComponent.pixelsPerUnit) - pos.x;
if (distToCharStart < distToCharEnd)
return i;
}
return endCharIndex;
}
public override void OnPointerDown(PointerEventData eventData)
{
EventSystem.current.SetSelectedGameObject(gameObject, eventData);
base.OnPointerDown(eventData);
Vector2 pos = ScreenToLocal(eventData.position);
caretPosition = GetCharacterIndexFromPosition(pos) + m_DrawStart;
UpdateLabel();
eventData.Use();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment