Initial commit: Unity WordConnect project

This commit is contained in:
2025-08-01 19:12:05 +08:00
commit f14db75802
3503 changed files with 448337 additions and 0 deletions

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Chris Foulston
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6c0aa18eb3f7146a0ac2059f49c2c684
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 38063a2f114ea26449d25456472d49b9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b01a1a9e8f5c586419eba255ce2c3ec6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,70 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System;
using UnityEngine;
namespace WordsToolkit.Scripts.Unity_Reorderable_List_master.List.Attributes
{
public class ReorderableAttribute : PropertyAttribute
{
public bool add;
public bool remove;
public bool draggable;
public bool singleLine;
public bool paginate;
public bool sortable;
public int pageSize;
public string elementNameProperty;
public string elementNameOverride;
public string elementIconPath;
public Type surrogateType;
public string surrogateProperty;
public ReorderableAttribute()
: this(null)
{
}
public ReorderableAttribute(string elementNameProperty)
: this(true, true, true, elementNameProperty, null, null)
{
}
public ReorderableAttribute(string elementNameProperty, string elementIconPath)
: this(true, true, true, elementNameProperty, null, elementIconPath)
{
}
public ReorderableAttribute(string elementNameProperty, string elementNameOverride, string elementIconPath)
: this(true, true, true, elementNameProperty, elementNameOverride, elementIconPath)
{
}
public ReorderableAttribute(bool add, bool remove, bool draggable, string elementNameProperty = null, string elementIconPath = null)
: this(add, remove, draggable, elementNameProperty, null, elementIconPath)
{
}
public ReorderableAttribute(bool add, bool remove, bool draggable, string elementNameProperty = null, string elementNameOverride = null, string elementIconPath = null)
{
this.add = add;
this.remove = remove;
this.draggable = draggable;
this.elementNameProperty = elementNameProperty;
this.elementNameOverride = elementNameOverride;
this.elementIconPath = elementIconPath;
sortable = true;
}
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6bc2dc710f98310489d6b4d40d9a1a7d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,19 @@
{
"name": "ReordableEditor",
"rootNamespace": "",
"references": [
"GUID:75bdbcf23199f4cfb86c610d1d946666",
"GUID:343deaaf83e0cee4ca978e7df0b80d21"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: ec2e3f41b7d924a4c9edd7654190551c
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,151 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using WordsToolkit.Scripts.Unity_Reorderable_List_master.List.Attributes;
namespace WordsToolkit.Scripts.Unity_Reorderable_List_master.List.Editor
{
[CustomPropertyDrawer(typeof(ReorderableAttribute))]
public class ReorderableDrawer : PropertyDrawer
{
public const string ARRAY_PROPERTY_NAME = "array";
private static readonly Dictionary<int, ReorderableList> lists = new();
public override bool CanCacheInspectorGUI(SerializedProperty property)
{
return false;
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
var list = GetList(property, attribute as ReorderableAttribute, ARRAY_PROPERTY_NAME);
return list != null ? list.GetHeight() : EditorGUIUtility.singleLineHeight;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var list = GetList(property, attribute as ReorderableAttribute, ARRAY_PROPERTY_NAME);
if (list != null)
{
list.DoList(EditorGUI.IndentedRect(position), label);
}
else
{
GUI.Label(position, "Array must extend from ReorderableArray", EditorStyles.label);
}
}
public static int GetListId(SerializedProperty property)
{
if (property != null)
{
var h1 = property.serializedObject.targetObject.GetHashCode();
var h2 = property.propertyPath.GetHashCode();
return ((h1 << 5) + h1) ^ h2;
}
return 0;
}
public static ReorderableList GetList(SerializedProperty property, string arrayPropertyName)
{
return GetList(property, null, GetListId(property), arrayPropertyName);
}
public static ReorderableList GetList(SerializedProperty property, ReorderableAttribute attrib, string arrayPropertyName)
{
return GetList(property, attrib, GetListId(property), arrayPropertyName);
}
public static ReorderableList GetList(SerializedProperty property, int id, string arrayPropertyName)
{
return GetList(property, null, id, arrayPropertyName);
}
public static ReorderableList GetList(SerializedProperty property, ReorderableAttribute attrib, int id, string arrayPropertyName)
{
if (property == null)
{
return null;
}
ReorderableList list = null;
var array = property.FindPropertyRelative(arrayPropertyName);
if (array != null && array.isArray)
{
if (!lists.TryGetValue(id, out list))
{
if (attrib != null)
{
var icon = !string.IsNullOrEmpty(attrib.elementIconPath) ? AssetDatabase.GetCachedIcon(attrib.elementIconPath) : null;
var displayType = attrib.singleLine ? ReorderableList.ElementDisplayType.SingleLine : ReorderableList.ElementDisplayType.Auto;
list = new ReorderableList(array, attrib.add, attrib.remove, attrib.draggable, displayType, attrib.elementNameProperty, attrib.elementNameOverride, icon);
list.paginate = attrib.paginate;
list.pageSize = attrib.pageSize;
list.sortable = attrib.sortable;
//handle surrogate if any
if (attrib.surrogateType != null)
{
var callback = new SurrogateCallback(attrib.surrogateProperty);
list.surrogate = new ReorderableList.Surrogate(attrib.surrogateType, callback.SetReference);
}
}
else
{
list = new ReorderableList(array, true, true, true);
}
lists.Add(id, list);
}
else
{
list.List = array;
}
}
return list;
}
private struct SurrogateCallback
{
private readonly string property;
internal SurrogateCallback(string property)
{
this.property = property;
}
internal void SetReference(SerializedProperty element, Object objectReference, ReorderableList list)
{
var prop = !string.IsNullOrEmpty(property) ? element.FindPropertyRelative(property) : null;
if (prop != null && prop.propertyType == SerializedPropertyType.ObjectReference)
{
prop.objectReferenceValue = objectReference;
}
}
}
}
}

View File

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

View File

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

View File

@ -0,0 +1,3 @@
{
"name": "Reordable"
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 75bdbcf23199f4cfb86c610d1d946666
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,114 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace WordsToolkit.Scripts.Unity_Reorderable_List_master.List
{
[Serializable]
public abstract class ReorderableArray<T> : ICloneable, IList<T>, ICollection<T>, IEnumerable<T>
{
[SerializeField]
private List<T> array = new();
public ReorderableArray()
: this(0)
{
}
public ReorderableArray(int length)
{
array = new List<T>(length);
}
public T this[int index]
{
get => array[index];
set => array[index] = value;
}
public int Length => array.Count;
public bool IsReadOnly => false;
public int Count => array.Count;
public object Clone()
{
return new List<T>(array);
}
public void CopyFrom(IEnumerable<T> value)
{
array.Clear();
array.AddRange(value);
}
public bool Contains(T value)
{
return array.Contains(value);
}
public int IndexOf(T value)
{
return array.IndexOf(value);
}
public void Insert(int index, T item)
{
array.Insert(index, item);
}
public void RemoveAt(int index)
{
array.RemoveAt(index);
}
public void Add(T item)
{
array.Add(item);
}
public void Clear()
{
array.Clear();
}
public void CopyTo(T[] array, int arrayIndex)
{
this.array.CopyTo(array, arrayIndex);
}
public bool Remove(T item)
{
return array.Remove(item);
}
public T[] ToArray()
{
return array.ToArray();
}
public IEnumerator<T> GetEnumerator()
{
return array.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return array.GetEnumerator();
}
}
}

View File

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

View File

@ -0,0 +1,55 @@
# Reorderable List
An attempt to mimic the ReorderableList within Unity while adding some extended functionality.
![screenshot](https://user-images.githubusercontent.com/6723783/45054643-70b46200-b042-11e8-874c-0d93a46e05a5.jpg)
## Features
* Drag and Drop references (like array inspector)
* Expandable items and list itself
* Multiple selection (ctrl/command, shift select)
* Draggable selection
* Context menu items (revert values, duplicate values, delete values)
* Custom attribute which allows automatic list generation for properties*
* Event delegates and custom styling
* Pagination
* Sorting (sort based on field, ascending and descending)
* Surrogates (Enable adding elements of a different type)
## Usage
There are two ways to use the ReorderableList
1. Create a custom Editor for your class and create a ReorderableList pointing to your serializedProperty
2. Create custom list class which extends from ReorderableArray<T>, assign [Reorderable] attribute above property (not class).
## Pagination
Pagination can be enabled in two ways:
1. With the [Reorderable] attribute:
* `[Reorderable(paginate = true, pageSize = 0)]`
2. Properties of the ReorderableList:
* `list.paginate`
* `list.pageSize`
`pageSize` defines the desired elements per page. Setting `pageSize = 0` will enable the custom page size GUI
When enabled, the ReorderableList GUI will display a small section below the header to facilitate navigating the pages
![pagination](https://user-images.githubusercontent.com/6723783/45054642-701bcb80-b042-11e8-84e4-0886d23c83c9.jpg)
#### NOTE
*Elements can be moved between pages by right-clicking and selecting "Move Array Element"*
## Surrogates
Surrogates can be created to facilitate adding Objects to a ReorderableList that don't match the ReorderableList type.
This can be achieved in two ways:
1. With the [Reorderable] attribute:
* `[Reorderable(surrogateType = typeof(ObjectType), surrogateProperty = "objectProperty")]`
2. Property of the ReorderableList:
* `list.surrogate = new ReorderableList.Surrogate(typeof(ObjectType), Callback);`
Check the `SurrogateTest` and `SurrogateTestEditor` examples for more information

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7be19ada3cefe554cb3808a48c7e0b20
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: