Files

242 lines
6.5 KiB
C#
Raw Permalink Normal View History

2026-01-08 16:50:20 +00:00
using System;
using UnityEngine;
using EditorGUI = Unity.PlasticSCM.Editor.UnityInternals.UnityEditor.EditorGUI;
namespace Unity.PlasticSCM.Editor.UI.UndoRedo
{
internal class UndoRedoTextArea : UndoRedoHelper.IUndoRedoHost
{
internal UndoRedoTextArea(
Action repaint,
string text = null,
string watermark = null)
{
mRepaint = repaint;
mControlName = Guid.NewGuid().ToString();
mUndoRedoHelper = new UndoRedoHelper(this);
Text = text;
WatermarkText = watermark;
}
internal string Text
{
get { return mText; }
set
{
mRequireFocusReset = true;
mText = value;
mCaretIndex = value != null ? value.Length : 0;
OnTextChanged();
mRepaint();
}
}
internal string WatermarkText
{
get { return mWatermarkText; }
set
{
mWatermarkText = value;
mRepaint();
}
}
internal int CaretIndex
{
get { return mCaretIndex; }
}
internal void SetFocus()
{
mRequireFocusSet = true;
}
internal void SetCursorToLastChar()
{
mHasToSetCursorToLastChar = true;
}
UndoRedoState UndoRedoHelper.IUndoRedoHost.UndoRedoState
{
get { return new UndoRedoState(mText, mCaretIndex); }
set
{
mText = value.Text;
mCaretIndex = value.CaretPosition;
TextEditor editor = GetActiveTextEditor();
if (editor == null)
return;
editor.text = value.Text;
editor.cursorIndex = value.CaretPosition;
editor.selectIndex = mCaretIndex;
}
}
protected void OnGUIInternal(Func<string> drawTextArea, Action drawWatermark)
{
GUI.SetNextControlName(mControlName);
if (mIsFocused)
ProcessKeyPressed(mUndoRedoHelper, Event.current);
bool isNewKeyboardFocus = CommandEvent.IsNewKeyboardFocus(Event.current);
// When the text area has focus, it won't reflect changes to the source string.
// To update the text programmatically, we must:
// 1. Remove focus
// 2. Set the new text
// 3. Restore focus
int keyboardControlBackup = GUIUtility.keyboardControl;
if (mRequireFocusReset && mIsFocused)
GUIUtility.keyboardControl = 0;
string oldText = mText;
string newText = drawTextArea();
mText = newText;
TextEditor editor = GetActiveTextEditor();
if (isNewKeyboardFocus && editor != null)
{
if (mHasToSetCursorToLastChar)
{
editor.cursorIndex = editor.text.Length;
mHasToSetCursorToLastChar = false;
}
editor.SelectNone();
}
if (Event.current.type == EventType.Repaint && mRequireFocusSet)
{
GUI.FocusControl(mControlName);
mRequireFocusSet = false;
}
if (Event.current.type != EventType.Layout)
mIsFocused = IsFocused(mControlName);
if (string.IsNullOrEmpty(mText) && !string.IsNullOrEmpty(mWatermarkText))
drawWatermark();
if (mRequireFocusReset && mIsFocused)
GUIUtility.keyboardControl = keyboardControlBackup;
mRequireFocusReset = false;
if (editor != null)
{
int oldCaretIndex = mCaretIndex;
int newCaretIndex = editor.cursorIndex;
mCaretIndex = newCaretIndex;
if (oldCaretIndex != newCaretIndex && Event.current.type != EventType.Used)
OnCaretIndexChanged();
}
if (oldText != newText)
OnTextChanged();
if (!mIsFocused)
return;
ProcessKeyboardShorcuts(mUndoRedoHelper, Event.current);
}
void OnCaretIndexChanged()
{
UndoRedoState state;
if (!mUndoRedoHelper.TryGetLastState(out state))
return;
if (state.Text == Text)
mUndoRedoHelper.UpdateLastState();
}
void OnTextChanged()
{
mUndoRedoHelper.Snapshot();
}
protected virtual void ProcessKeyPressed(UndoRedoHelper undoRedoHelper, Event e)
{
}
static void ProcessKeyboardShorcuts(UndoRedoHelper undoRedoHelper, Event e)
{
if (IsUndoShortcutPressed(e))
{
e.Use();
if (!undoRedoHelper.CanUndo)
return;
undoRedoHelper.Undo();
return;
}
if (IsRedoShortcutPressed(e))
{
e.Use();
if (!undoRedoHelper.CanRedo)
return;
undoRedoHelper.Redo();
return;
}
}
static bool IsUndoShortcutPressed(Event e)
{
return Keyboard.IsControlOrCommandKeyPressed(e) &&
Keyboard.IsKeyPressed(e, KeyCode.Z);
}
static bool IsRedoShortcutPressed(Event e)
{
if (Keyboard.IsControlOrCommandAndShiftKeyPressed(e) &&
Keyboard.IsKeyPressed(e, KeyCode.Z))
return true;
if (Application.platform != RuntimePlatform.WindowsEditor)
return false;
return Keyboard.IsControlOrCommandKeyPressed(e) &&
Keyboard.IsKeyPressed(e, KeyCode.Y);
}
protected static TextEditor GetActiveTextEditor()
{
return EditorGUI.activeEditor;
}
static bool IsFocused(string controlName)
{
return GUI.GetNameOfFocusedControl() == controlName;
}
bool mRequireFocusReset;
bool mRequireFocusSet;
bool mHasToSetCursorToLastChar;
int mCaretIndex;
bool mIsFocused;
protected string mText;
protected string mWatermarkText;
readonly string mControlName;
readonly Action mRepaint;
readonly UndoRedoHelper mUndoRedoHelper;
}
}