Started project

This commit is contained in:
Caleb Sandford deQuincey
2025-11-14 17:30:41 +00:00
parent 00b55a5b1e
commit 334021d04e
36526 changed files with 4940113 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
using System.Collections.Generic;
namespace Unity.PlasticSCM.Editor.UI.UndoRedo
{
internal class UndoRedoHelper
{
internal interface IUndoRedoHost
{
UndoRedoState UndoRedoState { get; set; }
}
internal bool CanUndo
{
get { return mCurrentNode != null && mCurrentNode.Previous != null; }
}
internal bool CanRedo
{
get { return mCurrentNode != null && mCurrentNode.Next != null; }
}
internal UndoRedoHelper(IUndoRedoHost host)
{
mHost = host;
}
internal bool TryGetLastState(out UndoRedoState state)
{
state = null;
if (!IsInLastState)
return false;
state = mCurrentNode.Value;
return true;
}
internal void UpdateLastState()
{
UpdateLastState(mHost.UndoRedoState);
}
internal void Undo()
{
if (mCurrentNode != null && mCurrentNode.Previous != null)
{
mCurrentNode = mCurrentNode.Previous;
mHost.UndoRedoState = mCurrentNode.Value;
}
}
internal void Redo()
{
if (mCurrentNode != null && mCurrentNode.Next != null)
{
mCurrentNode = mCurrentNode.Next;
mHost.UndoRedoState = mCurrentNode.Value;
}
}
internal void Snapshot()
{
UndoRedoState current = mHost.UndoRedoState;
if (mCurrentNode == null || !mCurrentNode.Value.Equals(current))
{
if (mCurrentNode != null && mCurrentNode.Next != null)
DiscardRedo();
mStates.AddLast(current);
mCurrentNode = mStates.Last;
if (mStates.Count > UNDO_LIMIT)
mStates.RemoveFirst();
}
}
bool IsInLastState
{
get { return mCurrentNode != null && mCurrentNode.Next == null; }
}
void UpdateLastState(UndoRedoState state)
{
if (mStates.Last != null)
mStates.Last.Value = state;
}
void DiscardRedo()
{
while (mCurrentNode != null && mCurrentNode.Next != null)
mStates.Remove(mCurrentNode.Next);
}
LinkedListNode<UndoRedoState> mCurrentNode;
readonly IUndoRedoHost mHost;
readonly LinkedList<UndoRedoState> mStates = new LinkedList<UndoRedoState>();
const int UNDO_LIMIT = 250;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 962c713f307637f459a3eb76c8aba5f0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,43 @@
using System;
namespace Unity.PlasticSCM.Editor.UI.UndoRedo
{
internal class UndoRedoState : IEquatable<UndoRedoState>
{
internal string Text { get; private set; }
internal int CaretPosition { get; private set;}
internal UndoRedoState(string text, int caretPosition)
{
Text = text;
CaretPosition = caretPosition;
}
bool IEquatable<UndoRedoState>.Equals(UndoRedoState other)
{
return ReferenceEquals(Text, other.Text) || Equals(Text, other.Text);
}
public override bool Equals(object obj)
{
if (!(obj is UndoRedoState))
return false;
return ((IEquatable<UndoRedoState>)this).Equals((UndoRedoState)obj);
}
public override int GetHashCode()
{
if (Text == null)
return 0;
return Text.GetHashCode();
}
public override string ToString()
{
return string.Format("Text: {0}, CaretPosition: {1}", Text, CaretPosition);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0e750291f98133747b5ebea5ce056f81
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,221 @@
using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
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; }
}
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;
}
}
internal void OnGUI(GUIStyle watermarkStyle, params GUILayoutOption[] options)
{
OnGUIInternal(
() => EditorGUILayout.TextArea(mText, options),
() => EditorGUI.LabelField(GUILayoutUtility.GetLastRect(), mWatermarkText, watermarkStyle));
}
internal void OnGUI(Rect position, GUIStyle style, GUIStyle watermarkStyle)
{
OnGUIInternal(
() => EditorGUI.TextArea(position, mText, style),
() => EditorGUI.LabelField(position, mWatermarkText, watermarkStyle));
}
void OnGUIInternal(Func<string> drawTextArea, Action drawWatermark)
{
GUI.SetNextControlName(mControlName);
// 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 && IsFocused(mControlName))
GUIUtility.keyboardControl = 0;
string oldText = mText;
string newText = drawTextArea();
mText = newText;
if (string.IsNullOrEmpty(mText) && !string.IsNullOrEmpty(mWatermarkText))
drawWatermark();
if (mRequireFocusReset && IsFocused(mControlName))
GUIUtility.keyboardControl = keyboardControlBackup;
mRequireFocusReset = false;
TextEditor editor = GetActiveTextEditor();
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 (!IsFocused(mControlName))
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();
}
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);
}
static TextEditor GetActiveTextEditor()
{
// Use reflection to access the internal "activeEditor" field of EditorGUI
Type editorGUIType = typeof(EditorGUI);
FieldInfo field = editorGUIType.GetField(
"activeEditor",
BindingFlags.Static | BindingFlags.NonPublic);
if (field != null)
return field.GetValue(null) as TextEditor;
return null;
}
static bool IsFocused(string controlName)
{
return GUI.GetNameOfFocusedControl() == controlName;
}
bool mRequireFocusReset;
int mCaretIndex;
string mText;
string mWatermarkText;
readonly string mControlName;
readonly Action mRepaint;
readonly UndoRedoHelper mUndoRedoHelper;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 75c9f3ad270d332499854cfab52bb2d7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: