forked from Shardstone/trail-into-darkness
added serialzed dictionary
This commit is contained in:
2
Packages/SerializedDictionary-main/.gitignore
vendored
Normal file
2
Packages/SerializedDictionary-main/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.claude/
|
||||
.idea/
|
||||
BIN
Packages/SerializedDictionary-main/.images/generators.png
Normal file
BIN
Packages/SerializedDictionary-main/.images/generators.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.7 KiB |
BIN
Packages/SerializedDictionary-main/.images/menu.png
Normal file
BIN
Packages/SerializedDictionary-main/.images/menu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
BIN
Packages/SerializedDictionary-main/.images/populate.png
Normal file
BIN
Packages/SerializedDictionary-main/.images/populate.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
BIN
Packages/SerializedDictionary-main/.images/populated.png
Normal file
BIN
Packages/SerializedDictionary-main/.images/populated.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
8
Packages/SerializedDictionary-main/Editor.meta
Normal file
8
Packages/SerializedDictionary-main/Editor.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43bd94852ddc6b34dbe9fec318fb54d8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "AYellowpaper.SerializedCollections.Editor",
|
||||
"references": [
|
||||
"GUID:d525ad6bd40672747bde77962f1c401e"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 234340c04eed5674a988bc6ebde7d248
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/SerializedDictionary-main/Editor/Assets.meta
Normal file
8
Packages/SerializedDictionary-main/Editor/Assets.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: edb739dfb1824234681f6480c75cd523
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,170 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8deddfed9f39d7740879d2cb0fcf7ce0
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMasterTextureLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: iPhone
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Windows Store Apps
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,110 @@
|
||||
.sc-close-button {
|
||||
background-image: resource('d_winbtn_win_close@2x');
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
top: 2px;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
border-left-width: 0;
|
||||
border-right-width: 0;
|
||||
border-top-width: 0;
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
|
||||
.sc-close-button:hover {
|
||||
background-color: rgba(80, 80, 80, 255);
|
||||
}
|
||||
|
||||
.sc-close-button:active {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.sc-text-toggle {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sc-text-toggle:checked {
|
||||
-unity-font-style: bold;
|
||||
}
|
||||
|
||||
.sc-text-toggle > Label {
|
||||
min-width: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.sc-text-toggle > .unity-radio-button__input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sc-title {
|
||||
background-color: rgba(40, 40, 40, 0.35);
|
||||
padding-left: 4px;
|
||||
padding-right: 3px;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
border-left-color: rgb(25, 25, 25);
|
||||
border-right-color: rgb(25, 25, 25);
|
||||
border-top-color: rgb(25, 25, 25);
|
||||
border-bottom-color: rgb(25, 25, 25);
|
||||
border-bottom-width: 1px;
|
||||
-unity-font-style: bold;
|
||||
}
|
||||
|
||||
.sc-generator-toggle {
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
.sc-generator-toggle:hover {
|
||||
background-color: rgb(48, 48, 48);
|
||||
}
|
||||
|
||||
.sc-generator-toggle:checked {
|
||||
background-color: rgb(77, 77, 77);
|
||||
}
|
||||
|
||||
.sc-modification-toggle {
|
||||
flex-basis: 100%;
|
||||
flex-shrink: 1;
|
||||
border-left-color: rgb(41, 41, 41);
|
||||
border-right-color: rgb(41, 41, 41);
|
||||
border-top-color: rgb(41, 41, 41);
|
||||
border-bottom-color: rgb(41, 41, 41);
|
||||
border-left-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-top-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
-unity-font-style: normal;
|
||||
-unity-text-align: middle-center;
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.sc-modification-toggle:hover {
|
||||
background-color: rgb(70, 70, 70);
|
||||
}
|
||||
|
||||
.sc-modification-toggle:checked {
|
||||
background-color: rgb(80, 80, 80);
|
||||
}
|
||||
|
||||
.sc-radio-button-group {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sc-radio-button-group > Label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#generators-group {
|
||||
flex-direction: column;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df6c2ef835e40c94c976442569324029
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
@@ -0,0 +1,26 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
|
||||
<Style src="project://database/Assets/Plugins/SerializedCollections/Editor/Assets/KeysGeneratorSelectorWindow.uss?fileID=7433441132597879392&guid=df6c2ef835e40c94c976442569324029&type=3#KeysGeneratorSelectorWindow" />
|
||||
<ui:VisualElement style="flex-direction: row; flex-grow: 1; border-left-color: rgb(97, 97, 97); border-right-color: rgb(97, 97, 97); border-top-color: rgb(97, 97, 97); border-bottom-color: rgb(97, 97, 97); border-left-width: 2px; border-right-width: 2px; border-top-width: 2px; border-bottom-width: 2px;">
|
||||
<ui:VisualElement name="LeftContent" style="flex-basis: 66%; border-left-color: rgb(25, 25, 25); border-right-color: rgb(25, 25, 25); border-top-color: rgb(25, 25, 25); border-bottom-color: rgb(25, 25, 25); border-right-width: 1px;">
|
||||
<ui:Label text="Generators" display-tooltip-when-elided="true" class="sc-title" />
|
||||
<ui:ScrollView scroll-deceleration-rate="0,135" elasticity="0,1" name="generators-content" style="flex-grow: 1;" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="RightContent" style="flex-basis: 100%;">
|
||||
<ui:Label text="Inspector" display-tooltip-when-elided="true" class="sc-title" />
|
||||
<ui:IMGUIContainer name="imgui-inspector" style="flex-grow: 1; margin-left: 4px; margin-right: 4px; margin-top: 4px; margin-bottom: 4px;" />
|
||||
<ui:Label text="4 Elements " display-tooltip-when-elided="true" name="generated-count-label" style="padding-left: 2px; padding-right: 2px; padding-top: 2px; padding-bottom: 2px;" />
|
||||
<ui:VisualElement style="flex-direction: row;">
|
||||
<ui:RadioButtonGroup label="Radio Button Group" value="-1" name="modification-group" class="sc-radio-button-group" style="flex-grow: 1;">
|
||||
<ui:RadioButton label="Add" name="add-modification" tooltip="Add the generated missing keys to the target." class="sc-text-toggle sc-modification-toggle" />
|
||||
<ui:RadioButton label="Remove" name="remove-modification" tooltip="Remove the generated keys form the target." class="sc-text-toggle sc-modification-toggle" />
|
||||
<ui:RadioButton label="Confine" name="confine-modification" tooltip="Remove all keys that are not part of the generated keys from the target." class="sc-text-toggle sc-modification-toggle" />
|
||||
</ui:RadioButtonGroup>
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement style="flex-direction: row;">
|
||||
<ui:Label display-tooltip-when-elided="true" name="result-label" style="flex-grow: 1; -unity-text-align: middle-left; padding-left: 2px; padding-right: 2px; padding-top: 2px; padding-bottom: 2px;" />
|
||||
<ui:Button text="Apply" display-tooltip-when-elided="true" name="apply-button" style="width: 100px;" />
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
<ui:Button display-tooltip-when-elided="true" class="sc-close-button" />
|
||||
</ui:VisualElement>
|
||||
</ui:UXML>
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 681c8a924c8b1e14b9fe53bb7397ec3d
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
8
Packages/SerializedDictionary-main/Editor/Scripts.meta
Normal file
8
Packages/SerializedDictionary-main/Editor/Scripts.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6398825db0c1d5348b5ec85b0c12d9c0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81bf46994f9232b4e8dcf467c109f046
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor.Data
|
||||
{
|
||||
[System.Serializable]
|
||||
internal class ElementData
|
||||
{
|
||||
[SerializeField]
|
||||
private bool _isListToggleActive = false;
|
||||
|
||||
public ElementSettings Settings { get; }
|
||||
public bool ShowAsList => Settings.HasListDrawerToggle && IsListToggleActive;
|
||||
public bool IsListToggleActive { get => _isListToggleActive; set => _isListToggleActive = value; }
|
||||
public DisplayType EffectiveDisplayType => ShowAsList ? DisplayType.List : Settings.DisplayType;
|
||||
|
||||
public ElementData(ElementSettings elementSettings)
|
||||
{
|
||||
Settings = elementSettings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 650a80186cc93b54aa5627197c23ea6e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor.Data
|
||||
{
|
||||
public class ElementSettings
|
||||
{
|
||||
public const string DefaultName = "Not Set";
|
||||
|
||||
public string DisplayName { get; set; } = DefaultName;
|
||||
public DisplayType DisplayType { get; set; } = DisplayType.PropertyNoLabel;
|
||||
public bool HasListDrawerToggle { get; set; } = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12edfc8006691b7498459540b832c5eb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor.Data
|
||||
{
|
||||
[System.Serializable]
|
||||
internal class PropertyData
|
||||
{
|
||||
[SerializeField]
|
||||
private ElementData _keyData;
|
||||
[SerializeField]
|
||||
private ElementData _valueData;
|
||||
[SerializeField]
|
||||
private bool _alwaysShowSearch = false;
|
||||
|
||||
public bool AlwaysShowSearch
|
||||
{
|
||||
get => _alwaysShowSearch;
|
||||
set => _alwaysShowSearch = value;
|
||||
}
|
||||
|
||||
public ElementData GetElementData(bool fieldType)
|
||||
{
|
||||
return fieldType == SCEditorUtility.KeyFlag ? _keyData : _valueData;
|
||||
}
|
||||
|
||||
public PropertyData() : this(new ElementSettings(), new ElementSettings()) { }
|
||||
|
||||
public PropertyData(ElementSettings keySettings, ElementSettings valueSettings)
|
||||
{
|
||||
_keyData = new ElementData(keySettings);
|
||||
_valueData = new ElementData(valueSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ba2d792dfc6653e46bee7c027202acd3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor
|
||||
{
|
||||
public enum DisplayType
|
||||
{
|
||||
Property,
|
||||
PropertyNoLabel,
|
||||
List
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37ee13dd67b545846b6b063923812943
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d74b279cd03ebfb4ca7d2606f3f4f11e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 10b0c99dadaea0e42b49e323700f2eb9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.KeysGenerators
|
||||
{
|
||||
[KeyListGenerator("Populate Enum", typeof(System.Enum), false)]
|
||||
public class EnumGenerator : KeyListGenerator
|
||||
{
|
||||
public override IEnumerable GetKeys(System.Type type)
|
||||
{
|
||||
return System.Enum.GetValues(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d639de5d36bbeea4496c97cc3f1f4e81
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.KeysGenerators
|
||||
{
|
||||
[KeyListGenerator("Int Range", typeof(int))]
|
||||
public class IntRangeGenerator : KeyListGenerator
|
||||
{
|
||||
[SerializeField]
|
||||
private int _startValue = 1;
|
||||
[SerializeField]
|
||||
private int _endValue = 10;
|
||||
|
||||
public override IEnumerable GetKeys(Type type)
|
||||
{
|
||||
int dir = Math.Sign(_endValue - _startValue);
|
||||
dir = dir == 0 ? 1 : dir;
|
||||
for (int i = _startValue; i != _endValue; i += dir)
|
||||
yield return i;
|
||||
yield return _endValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4203f3a582fa874fb035633bd9892b4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.KeysGenerators
|
||||
{
|
||||
[KeyListGenerator("Int Stepping", typeof(int))]
|
||||
public class IntSteppingGenerator : KeyListGenerator
|
||||
{
|
||||
[SerializeField]
|
||||
private int _startIndex = 0;
|
||||
[SerializeField]
|
||||
private int _stepDistance = 10;
|
||||
[SerializeField, Min(0)]
|
||||
private int _stepCount = 1;
|
||||
|
||||
public override IEnumerable GetKeys(Type type)
|
||||
{
|
||||
for (int i = 0; i <= _stepCount; i++)
|
||||
{
|
||||
yield return _startIndex + i * _stepDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99302d4ff0ae27b4898ced57890ed32d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.KeysGenerators
|
||||
{
|
||||
public abstract class KeyListGenerator : ScriptableObject
|
||||
{
|
||||
public abstract IEnumerable GetKeys(System.Type type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08149f25a1b9c5e48a224a7c4d31a154
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.KeysGenerators
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class KeyListGeneratorAttribute : Attribute
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly Type TargetType;
|
||||
public readonly bool NeedsWindow;
|
||||
|
||||
public KeyListGeneratorAttribute(string name, Type targetType, bool needsWindow = true)
|
||||
{
|
||||
Name = name;
|
||||
TargetType = targetType;
|
||||
NeedsWindow = needsWindow;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f6065c936425ab478ecc8a8cf30d38f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.KeysGenerators
|
||||
{
|
||||
public static class KeyListGeneratorCache
|
||||
{
|
||||
private static List<KeyListGeneratorData> _populators;
|
||||
private static Dictionary<Type, List<KeyListGeneratorData>> _populatorsByType;
|
||||
|
||||
static KeyListGeneratorCache()
|
||||
{
|
||||
_populators = new List<KeyListGeneratorData>();
|
||||
_populatorsByType = new Dictionary<Type, List<KeyListGeneratorData>>();
|
||||
var populatorTypes = TypeCache.GetTypesDerivedFrom<KeyListGenerator>();
|
||||
foreach (var populatorType in populatorTypes.Where(x => !x.IsAbstract))
|
||||
{
|
||||
var attributes = populatorType.GetCustomAttributes<KeyListGeneratorAttribute>();
|
||||
foreach (var attribute in attributes)
|
||||
_populators.Add(new KeyListGeneratorData(attribute.Name, attribute.TargetType, populatorType, attribute.NeedsWindow));
|
||||
}
|
||||
}
|
||||
|
||||
public static IReadOnlyList<KeyListGeneratorData> GetPopulatorsForType(Type type)
|
||||
{
|
||||
if (!_populatorsByType.ContainsKey(type))
|
||||
_populatorsByType.Add(type, new List<KeyListGeneratorData>(_populators.Where(x => x.TargetType.IsAssignableFrom(type))));
|
||||
return _populatorsByType[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7936217ae19613d4bb5e46e73a4a587c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.KeysGenerators
|
||||
{
|
||||
public class KeyListGeneratorData
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public Type TargetType { get; set; }
|
||||
public Type GeneratorType { get; set; }
|
||||
public bool NeedsWindow { get; set; }
|
||||
|
||||
public KeyListGeneratorData(string name, Type targetType, Type populatorType, bool needsWindow)
|
||||
{
|
||||
Name = name;
|
||||
TargetType = targetType;
|
||||
GeneratorType = populatorType;
|
||||
NeedsWindow = needsWindow;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8992145ced672cd46a425fb2590b80bb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.KeysGenerators
|
||||
{
|
||||
[CustomEditor(typeof(KeyListGenerator), true)]
|
||||
public class KeyListGeneratorEditor : UnityEditor.Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var iterator = serializedObject.GetIterator();
|
||||
if (iterator.Next(true))
|
||||
{
|
||||
// skip script name
|
||||
iterator.NextVisible(true);
|
||||
while (iterator.NextVisible(true))
|
||||
{
|
||||
EditorGUILayout.PropertyField(iterator);
|
||||
}
|
||||
}
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 211518bea98ede643af247b6295984bd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,182 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.KeysGenerators
|
||||
{
|
||||
public class KeyListGeneratorSelectorWindow : EditorWindow
|
||||
{
|
||||
[SerializeField]
|
||||
private int _selectedIndex;
|
||||
[SerializeField]
|
||||
private ModificationType _modificationType;
|
||||
|
||||
private KeyListGenerator _generator;
|
||||
private UnityEditor.Editor _editor;
|
||||
private List<KeyListGeneratorData> _generatorsData;
|
||||
private Type _targetType;
|
||||
private int _undoStart;
|
||||
private Dictionary<Type, KeyListGenerator> _keysGenerators = new Dictionary<Type, KeyListGenerator>();
|
||||
private string _detailsText;
|
||||
|
||||
public event Action<KeyListGenerator, ModificationType> OnApply;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
VisualTreeAsset document = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Plugins/SerializedCollections/Editor/Assets/KeysGeneratorSelectorWindow.uxml");
|
||||
var element = document.CloneTree();
|
||||
element.style.height = new StyleLength(new Length(100, LengthUnit.Percent));
|
||||
rootVisualElement.Add(element);
|
||||
}
|
||||
|
||||
public void Initialize(IEnumerable<KeyListGeneratorData> generatorsData, Type type)
|
||||
{
|
||||
_targetType = type;
|
||||
_selectedIndex = 0;
|
||||
_modificationType = ModificationType.Add;
|
||||
_undoStart = Undo.GetCurrentGroup();
|
||||
_generatorsData = new List<KeyListGeneratorData>(generatorsData);
|
||||
SetGeneratorIndex(0);
|
||||
Undo.undoRedoPerformed += HandleUndoCallback;
|
||||
|
||||
rootVisualElement.Q<Button>(className: "sc-close-button").clicked += Close;
|
||||
|
||||
rootVisualElement.Q<RadioButton>(name = "add-modification").userData = ModificationType.Add;
|
||||
rootVisualElement.Q<RadioButton>(name = "remove-modification").userData = ModificationType.Remove;
|
||||
rootVisualElement.Q<RadioButton>(name = "confine-modification").userData = ModificationType.Confine;
|
||||
|
||||
var modificationToggles = rootVisualElement.Query<RadioButton>(className: "sc-modification-toggle");
|
||||
modificationToggles.ForEach(InitializeModificationToggle);
|
||||
|
||||
rootVisualElement.Q<IMGUIContainer>(name = "imgui-inspector").onGUIHandler = EditorGUIHandler;
|
||||
rootVisualElement.Q<Button>(name = "apply-button").clicked += ApplyButtonClicked;
|
||||
|
||||
var generatorsContent = rootVisualElement.Q<ScrollView>(name = "generators-content");
|
||||
var radioButtonGroup = new RadioButtonGroup();
|
||||
radioButtonGroup.name = "generators-group";
|
||||
radioButtonGroup.AddToClassList("sc-radio-button-group");
|
||||
generatorsContent.Add(radioButtonGroup);
|
||||
|
||||
for (int i = 0; i < _generatorsData.Count; i++)
|
||||
{
|
||||
var generatorData = _generatorsData[i];
|
||||
|
||||
var radioButton = new RadioButton(generatorData.Name);
|
||||
radioButton.value = i == 0;
|
||||
radioButton.AddToClassList("sc-text-toggle");
|
||||
radioButton.AddToClassList("sc-generator-toggle");
|
||||
radioButton.userData = i;
|
||||
radioButton.RegisterValueChangedCallback(OnGeneratorClicked);
|
||||
radioButtonGroup.Add(radioButton);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyButtonClicked()
|
||||
{
|
||||
OnApply?.Invoke(_editor.target as KeyListGenerator, _modificationType);
|
||||
OnApply = null;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void EditorGUIHandler()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
_editor.OnInspectorGUI();
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
UpdateDetailsText();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeModificationToggle(RadioButton obj)
|
||||
{
|
||||
if ((ModificationType)obj.userData == _modificationType)
|
||||
obj.value = true;
|
||||
obj.RegisterValueChangedCallback(OnModificationToggleClicked);
|
||||
}
|
||||
|
||||
private void OnModificationToggleClicked(ChangeEvent<bool> evt)
|
||||
{
|
||||
if (!evt.newValue)
|
||||
return;
|
||||
|
||||
var modificationType = (ModificationType)((VisualElement)evt.target).userData;
|
||||
_modificationType = modificationType;
|
||||
}
|
||||
|
||||
private void UpdateDetailsText()
|
||||
{
|
||||
var enumerable = _generator.GetKeys(_targetType);
|
||||
int count = 0;
|
||||
var enumerator = enumerable.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
count++;
|
||||
if (count > 100)
|
||||
{
|
||||
_detailsText = "over 100 Elements";
|
||||
return;
|
||||
}
|
||||
}
|
||||
_detailsText = $"{count} Elements";
|
||||
|
||||
rootVisualElement.Q<Label>(name = "generated-count-label").text = _detailsText;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
Undo.undoRedoPerformed -= HandleUndoCallback;
|
||||
Undo.RevertAllDownToGroup(_undoStart);
|
||||
foreach (var keyGenerator in _keysGenerators)
|
||||
DestroyImmediate(keyGenerator.Value);
|
||||
}
|
||||
|
||||
private void OnGeneratorClicked(ChangeEvent<bool> evt)
|
||||
{
|
||||
if (!evt.newValue)
|
||||
return;
|
||||
|
||||
SetGeneratorIndex((int)(evt.target as VisualElement).userData);
|
||||
}
|
||||
|
||||
private void HandleUndoCallback()
|
||||
{
|
||||
UpdateGeneratorAndEditorIfNeeded();
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private void SetGeneratorIndex(int index)
|
||||
{
|
||||
Undo.RecordObject(this, "Change Window");
|
||||
_selectedIndex = index;
|
||||
UpdateGeneratorAndEditorIfNeeded();
|
||||
}
|
||||
|
||||
private void UpdateGeneratorAndEditorIfNeeded()
|
||||
{
|
||||
var targetType = _generatorsData[_selectedIndex].GeneratorType;
|
||||
if (_generator != null && _generator.GetType() == targetType)
|
||||
return;
|
||||
|
||||
_generator = GetOrCreateKeysGenerator(targetType);
|
||||
if (_editor != null)
|
||||
DestroyImmediate(_editor);
|
||||
_editor = UnityEditor.Editor.CreateEditor(_generator);
|
||||
|
||||
UpdateDetailsText();
|
||||
}
|
||||
|
||||
private KeyListGenerator GetOrCreateKeysGenerator(Type type)
|
||||
{
|
||||
if (!_keysGenerators.ContainsKey(type))
|
||||
{
|
||||
var so = (KeyListGenerator)CreateInstance(type);
|
||||
so.hideFlags = HideFlags.DontSave;
|
||||
_keysGenerators.Add(type, so);
|
||||
}
|
||||
return _keysGenerators[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df07fe6d161e3334083f837a066dd949
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace AYellowpaper.SerializedCollections
|
||||
{
|
||||
public enum ModificationType
|
||||
{
|
||||
None,
|
||||
Add,
|
||||
Remove,
|
||||
Confine,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fc2030edc0a04b74a8642773bd8c98fd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,68 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor
|
||||
{
|
||||
public class PagingElement
|
||||
{
|
||||
public int Page
|
||||
{
|
||||
get => _page;
|
||||
set
|
||||
{
|
||||
_page = value;
|
||||
EnsureValidPageIndex();
|
||||
}
|
||||
}
|
||||
public int PageCount
|
||||
{
|
||||
get => _pageCount;
|
||||
set
|
||||
{
|
||||
Debug.Assert(value >= 1, $"{nameof(PageCount)} needs to be 1 or larger but is {value}.");
|
||||
_pageCount = value;
|
||||
EnsureValidPageIndex();
|
||||
}
|
||||
}
|
||||
|
||||
private const int buttonWidth = 20;
|
||||
private const int inputWidth = 20;
|
||||
private const int labelWidth = 30;
|
||||
|
||||
private int _page = 1;
|
||||
private int _pageCount = 1;
|
||||
|
||||
public PagingElement(int pageCount = 1)
|
||||
{
|
||||
PageCount = pageCount;
|
||||
}
|
||||
|
||||
public float GetDesiredWidth()
|
||||
{
|
||||
return buttonWidth * 2 + inputWidth + labelWidth;
|
||||
}
|
||||
|
||||
public void OnGUI(Rect rect)
|
||||
{
|
||||
Rect leftButton = rect.WithXAndWidth(rect.x, buttonWidth);
|
||||
Rect inputRect = leftButton.AppendRight(inputWidth);
|
||||
Rect labelRect = inputRect.AppendRight(labelWidth);
|
||||
Rect rightButton = labelRect.AppendRight(buttonWidth);
|
||||
using (new GUIEnabledScope(Page != 1))
|
||||
if (GUI.Button(leftButton, "<"))
|
||||
Page--;
|
||||
using (new GUIEnabledScope(Page != PageCount))
|
||||
if (GUI.Button(rightButton, ">"))
|
||||
Page++;
|
||||
Page = EditorGUI.IntField(inputRect, Page);
|
||||
GUI.Label(labelRect, "/" + PageCount.ToString());
|
||||
}
|
||||
|
||||
private void EnsureValidPageIndex()
|
||||
{
|
||||
_page = Mathf.Clamp(_page, 1, PageCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f35ac465aece4064582910fc2c206682
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bead4ae311155bd46af1e99788f1d932
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77b8ccff4f0c60943b9a54ce8d698d7f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor.Search
|
||||
{
|
||||
public class EnumMatcher : Matcher
|
||||
{
|
||||
public override bool IsMatch(SerializedProperty property)
|
||||
{
|
||||
if (property.propertyType == SerializedPropertyType.Enum && SCEditorUtility.TryGetTypeFromProperty(property, out var type))
|
||||
{
|
||||
foreach (var text in SCEnumUtility.GetEnumCache(type).GetNamesForValue(property.enumValueFlag))
|
||||
{
|
||||
if (text.Contains(SearchString, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2cf86e71fb0ff04f96ac71dd9961962
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor.Search
|
||||
{
|
||||
public abstract class Matcher
|
||||
{
|
||||
public string SearchString { get; private set; }
|
||||
|
||||
public void Prepare(string searchString)
|
||||
{
|
||||
SearchString = ProcessSearchString(searchString);
|
||||
}
|
||||
|
||||
public virtual string ProcessSearchString(string searchString)
|
||||
{
|
||||
return searchString;
|
||||
}
|
||||
public abstract bool IsMatch(SerializedProperty property);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 218ea85e2d8480a498e8647aad524c8d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor.Search
|
||||
{
|
||||
public static class Matchers
|
||||
{
|
||||
public static IEnumerable<Matcher> RegisteredMatchers => _registeredMatchers;
|
||||
|
||||
private static List<Matcher> _registeredMatchers = new List<Matcher>();
|
||||
|
||||
static Matchers()
|
||||
{
|
||||
_registeredMatchers.Add(new NumericMatcher());
|
||||
_registeredMatchers.Add(new StringMatcher());
|
||||
_registeredMatchers.Add(new EnumMatcher());
|
||||
}
|
||||
|
||||
public static void AddMatcher(Matcher matcher)
|
||||
{
|
||||
_registeredMatchers.Add(matcher);
|
||||
}
|
||||
|
||||
public static bool RemoveMatcher(Matcher matcher)
|
||||
{
|
||||
return _registeredMatchers.Remove(matcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94535827bd107e549baa23442df58bef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,109 @@
|
||||
using System.Globalization;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor.Search
|
||||
{
|
||||
public class NumericMatcher : Matcher
|
||||
{
|
||||
public override string ProcessSearchString(string searchString)
|
||||
{
|
||||
return searchString.Replace(',', '.');
|
||||
}
|
||||
|
||||
public override bool IsMatch(SerializedProperty property)
|
||||
{
|
||||
if (property.propertyType == SerializedPropertyType.Float)
|
||||
{
|
||||
return IsFloatMatch(property.floatValue);
|
||||
}
|
||||
else if (property.propertyType == SerializedPropertyType.Integer)
|
||||
{
|
||||
return IsIntMatch(property.intValue);
|
||||
}
|
||||
else if (property.propertyType == SerializedPropertyType.Quaternion)
|
||||
{
|
||||
var quat = property.quaternionValue;
|
||||
return IsFloatMatch(quat.x) || IsFloatMatch(quat.y) || IsFloatMatch(quat.z) || IsFloatMatch(quat.w);
|
||||
}
|
||||
else if (property.propertyType == SerializedPropertyType.Bounds)
|
||||
{
|
||||
var bounds = property.boundsValue;
|
||||
return IsVector3Match(bounds.center) || IsVector3Match(bounds.size);
|
||||
}
|
||||
else if (property.propertyType == SerializedPropertyType.BoundsInt)
|
||||
{
|
||||
var bounds = property.boundsIntValue;
|
||||
return IsVector3Match(bounds.center) || IsVector3IntMatch(bounds.size);
|
||||
}
|
||||
else if (property.propertyType == SerializedPropertyType.Rect)
|
||||
{
|
||||
var rect = property.rectValue;
|
||||
return IsVector2Match(rect.size) || IsVector2Match(rect.position);
|
||||
}
|
||||
else if (property.propertyType == SerializedPropertyType.RectInt)
|
||||
{
|
||||
var rect = property.rectIntValue;
|
||||
return IsVector2IntMatch(rect.size) || IsVector2IntMatch(rect.position);
|
||||
}
|
||||
else if (property.propertyType == SerializedPropertyType.Vector2)
|
||||
{
|
||||
return IsVector2Match(property.vector2Value);
|
||||
}
|
||||
else if (property.propertyType == SerializedPropertyType.Vector2Int)
|
||||
{
|
||||
return IsVector2IntMatch(property.vector2IntValue);
|
||||
}
|
||||
else if (property.propertyType == SerializedPropertyType.Vector3)
|
||||
{
|
||||
return IsVector3Match(property.vector3Value);
|
||||
}
|
||||
else if (property.propertyType == SerializedPropertyType.Vector3Int)
|
||||
{
|
||||
return IsVector3IntMatch(property.vector3IntValue);
|
||||
}
|
||||
else if (property.propertyType == SerializedPropertyType.Vector4)
|
||||
{
|
||||
return IsVector4Match(property.vector4Value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsFloatMatch(float val)
|
||||
{
|
||||
var str = val.ToString(CultureInfo.InvariantCulture);
|
||||
return str.Contains(SearchString, System.StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private bool IsIntMatch(int val)
|
||||
{
|
||||
var str = val.ToString(CultureInfo.InvariantCulture);
|
||||
return str.Contains(SearchString, System.StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private bool IsVector2Match(Vector2 vector)
|
||||
{
|
||||
return IsFloatMatch(vector.x) || IsFloatMatch(vector.y);
|
||||
}
|
||||
|
||||
private bool IsVector2IntMatch(Vector2Int vector)
|
||||
{
|
||||
return IsIntMatch(vector.x) || IsIntMatch(vector.y);
|
||||
}
|
||||
|
||||
private bool IsVector3Match(Vector3 vector)
|
||||
{
|
||||
return IsFloatMatch(vector.x) || IsFloatMatch(vector.y) || IsFloatMatch(vector.z);
|
||||
}
|
||||
|
||||
private bool IsVector3IntMatch(Vector3Int vector)
|
||||
{
|
||||
return IsIntMatch(vector.x) || IsIntMatch(vector.y) || IsIntMatch(vector.z);
|
||||
}
|
||||
|
||||
private bool IsVector4Match(Vector4 vector)
|
||||
{
|
||||
return IsFloatMatch(vector.x) || IsFloatMatch(vector.y) || IsFloatMatch(vector.z) || IsFloatMatch(vector.w);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc3ee6ec420212140bd3a86688d548de
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Globalization;
|
||||
using UnityEditor;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor.Search
|
||||
{
|
||||
public class StringMatcher : Matcher
|
||||
{
|
||||
public override bool IsMatch(SerializedProperty property)
|
||||
{
|
||||
if ((property.propertyType is SerializedPropertyType.String or SerializedPropertyType.Character) && property.stringValue.Contains(SearchString, System.StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be8bbc3471f8ad04b8da6366285443c6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor.Search
|
||||
{
|
||||
public class PropertySearchResult
|
||||
{
|
||||
public SerializedProperty Property;
|
||||
|
||||
public PropertySearchResult(SerializedProperty property)
|
||||
{
|
||||
Property = property;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Found match in in {Property.propertyPath}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33b4e4c67054c4d488fa66ff14bd3120
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor.Search
|
||||
{
|
||||
public class SearchQuery
|
||||
{
|
||||
public string SearchString
|
||||
{
|
||||
get => _text;
|
||||
set
|
||||
{
|
||||
if (_text == value)
|
||||
return;
|
||||
|
||||
_text = value;
|
||||
foreach (var matcher in _matchers)
|
||||
matcher.Prepare(_text);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Matcher> _matchers;
|
||||
private string _text;
|
||||
|
||||
public SearchQuery(IEnumerable<Matcher> matchers)
|
||||
{
|
||||
_matchers = matchers;
|
||||
}
|
||||
|
||||
public List<PropertySearchResult> ApplyToProperty(SerializedProperty property)
|
||||
{
|
||||
TryGetMatchingProperties(property.Copy(), out var properties);
|
||||
return properties;
|
||||
}
|
||||
|
||||
public IEnumerable<SearchResultEntry> ApplyToArrayProperty(SerializedProperty property)
|
||||
{
|
||||
int arrayCount = property.arraySize;
|
||||
for (int i = 0; i < arrayCount; i++)
|
||||
{
|
||||
var prop = property.GetArrayElementAtIndex(i);
|
||||
if (TryGetMatchingProperties(prop.Copy(), out var properties))
|
||||
yield return new SearchResultEntry(i, prop, properties);
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetMatchingProperties(SerializedProperty property, out List<PropertySearchResult> matchingProperties)
|
||||
{
|
||||
matchingProperties = null;
|
||||
foreach (var child in SCEditorUtility.GetChildren(property, true))
|
||||
{
|
||||
foreach (var matcher in _matchers)
|
||||
{
|
||||
if (matcher.IsMatch(child))
|
||||
{
|
||||
if (matchingProperties == null)
|
||||
matchingProperties = new();
|
||||
matchingProperties.Add(new PropertySearchResult(child.Copy()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matchingProperties != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c87dd0caf3c44ed4e82896aa40bf1b96
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor.Search
|
||||
{
|
||||
public class SearchResultEntry
|
||||
{
|
||||
public readonly int Index;
|
||||
public readonly SerializedProperty Property;
|
||||
public readonly IEnumerable<PropertySearchResult> MatchingResults;
|
||||
|
||||
public SearchResultEntry(int index, SerializedProperty property, IEnumerable<PropertySearchResult> matchingResults)
|
||||
{
|
||||
Index = index;
|
||||
Property = property;
|
||||
MatchingResults = matchingResults;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine($"{Index}: {Property.propertyPath}");
|
||||
foreach (var matchingResult in MatchingResults)
|
||||
sb.AppendLine(matchingResult.ToString());
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8455216ad2701d49b6dfec7f98ca88b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,62 @@
|
||||
using AYellowpaper.SerializedCollections.Editor.Data;
|
||||
using AYellowpaper.SerializedCollections.Editor.States;
|
||||
using AYellowpaper.SerializedCollections.KeysGenerators;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(SerializedDictionary<,>))]
|
||||
public class SerializedDictionaryDrawer : PropertyDrawer
|
||||
{
|
||||
public const string KeyName = nameof(SerializedKeyValuePair<int, int>.Key);
|
||||
public const string ValueName = nameof(SerializedKeyValuePair<int, int>.Value);
|
||||
public const string SerializedListName = nameof(SerializedDictionary<int, int>._serializedList);
|
||||
public const string LookupTableName = nameof(SerializedDictionary<int, int>.LookupTable);
|
||||
|
||||
public const int TopHeaderClipHeight = 20;
|
||||
public const int TopHeaderHeight = 19;
|
||||
public const int SearchHeaderHeight = 20;
|
||||
public const int KeyValueHeaderHeight = 18;
|
||||
public const bool KeyFlag = true;
|
||||
public const bool ValueFlag = false;
|
||||
public static readonly Color BorderColor = new Color(36 / 255f, 36 / 255f, 36 / 255f);
|
||||
public static readonly List<int> NoEntriesList = new List<int>();
|
||||
internal static GUIContent DisplayTypeToggleContent
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_displayTypeToggleContent == null)
|
||||
{
|
||||
var texture = AssetDatabase.LoadAssetAtPath<Texture>("Assets/Plugins/SerializedCollections/Editor/Assets/BurgerMenu@2x.png");
|
||||
_displayTypeToggleContent = new GUIContent(texture, "Toggle to either draw existing editor or draw properties manually.");
|
||||
}
|
||||
return _displayTypeToggleContent;
|
||||
}
|
||||
}
|
||||
private static GUIContent _displayTypeToggleContent;
|
||||
|
||||
private Dictionary<string, SerializedDictionaryInstanceDrawer> _arrayData = new();
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
if (!_arrayData.ContainsKey(property.propertyPath))
|
||||
_arrayData.Add(property.propertyPath, new SerializedDictionaryInstanceDrawer(property, fieldInfo));
|
||||
_arrayData[property.propertyPath].OnGUI(position, label);
|
||||
}
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
if (!_arrayData.ContainsKey(property.propertyPath))
|
||||
_arrayData.Add(property.propertyPath, new SerializedDictionaryInstanceDrawer(property, fieldInfo));
|
||||
return _arrayData[property.propertyPath].GetPropertyHeight(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ccfc6d910f95ca4f94b294a9a3a8872
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,689 @@
|
||||
using AYellowpaper.SerializedCollections.Editor.Data;
|
||||
using AYellowpaper.SerializedCollections.Editor.States;
|
||||
using AYellowpaper.SerializedCollections.KeysGenerators;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor
|
||||
{
|
||||
public class SerializedDictionaryInstanceDrawer
|
||||
{
|
||||
private FieldInfo _fieldInfo;
|
||||
private ReorderableList _unexpandedList;
|
||||
private SingleEditingData _singleEditingData;
|
||||
private FieldInfo _keyFieldInfo;
|
||||
private GUIContent _label;
|
||||
private Rect _totalRect;
|
||||
private GUIStyle _keyValueStyle;
|
||||
private SerializedDictionaryAttribute _dictionaryAttribute;
|
||||
private PropertyData _propertyData;
|
||||
private bool _propertyListSettingsInitialized = false;
|
||||
private List<int> _pagedIndices;
|
||||
private PagingElement _pagingElement;
|
||||
private int _lastListSize = -1;
|
||||
private IReadOnlyList<KeyListGeneratorData> _keyGeneratorsWithoutWindow;
|
||||
private IReadOnlyList<KeyListGeneratorData> _keyGeneratorsWithWindow;
|
||||
private SearchField _searchField;
|
||||
private GUIContent _shortDetailsContent;
|
||||
private GUIContent _detailsContent;
|
||||
private bool _showSearchBar = false;
|
||||
private ListState _activeState;
|
||||
|
||||
internal ReorderableList ReorderableList { get; private set; }
|
||||
internal SerializedProperty ListProperty { get; private set; }
|
||||
internal string SearchText { get; private set; } = string.Empty;
|
||||
internal SearchListState SearchState { get; private set; }
|
||||
internal DefaultListState DefaultState { get; private set; }
|
||||
|
||||
private class SingleEditingData
|
||||
{
|
||||
public bool IsValid => LookupTable != null;
|
||||
public IKeyable LookupTable;
|
||||
|
||||
public void Invalidate()
|
||||
{
|
||||
LookupTable = null;
|
||||
}
|
||||
}
|
||||
|
||||
public SerializedDictionaryInstanceDrawer(SerializedProperty property, FieldInfo fieldInfo)
|
||||
{
|
||||
_fieldInfo = fieldInfo;
|
||||
ListProperty = property.FindPropertyRelative(SerializedDictionaryDrawer.SerializedListName);
|
||||
|
||||
_keyValueStyle = new GUIStyle(EditorStyles.toolbarButton);
|
||||
_keyValueStyle.padding = new RectOffset(0, 0, 0, 0);
|
||||
_keyValueStyle.border = new RectOffset(0, 0, 0, 0);
|
||||
_keyValueStyle.alignment = TextAnchor.MiddleCenter;
|
||||
|
||||
DefaultState = new DefaultListState(this);
|
||||
SearchState = new SearchListState(this);
|
||||
_activeState = DefaultState;
|
||||
|
||||
_dictionaryAttribute = _fieldInfo.GetCustomAttribute<SerializedDictionaryAttribute>();
|
||||
|
||||
_propertyData = SCEditorUtility.GetPropertyData(ListProperty);
|
||||
_propertyData.GetElementData(SCEditorUtility.KeyFlag).Settings.DisplayName = _dictionaryAttribute?.KeyName ?? "Key";
|
||||
_propertyData.GetElementData(SCEditorUtility.ValueFlag).Settings.DisplayName = _dictionaryAttribute?.ValueName ?? "Value";
|
||||
SavePropertyData();
|
||||
|
||||
_pagingElement = new PagingElement();
|
||||
_pagedIndices = new List<int>();
|
||||
UpdatePaging();
|
||||
|
||||
ReorderableList = MakeList();
|
||||
_unexpandedList = MakeUnexpandedList();
|
||||
_searchField = new SearchField();
|
||||
|
||||
var listField = _fieldInfo.FieldType.GetField(SerializedDictionaryDrawer.SerializedListName, BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
var entryType = listField.FieldType.GetGenericArguments()[0];
|
||||
_keyFieldInfo = entryType.GetField(SerializedDictionaryDrawer.KeyName);
|
||||
|
||||
_singleEditingData = new SingleEditingData();
|
||||
|
||||
var keyGenerators = KeyListGeneratorCache.GetPopulatorsForType(_keyFieldInfo.FieldType);
|
||||
_keyGeneratorsWithWindow = keyGenerators.Where(x => x.NeedsWindow).ToList();
|
||||
_keyGeneratorsWithoutWindow = keyGenerators.Where(x => !x.NeedsWindow).ToList();
|
||||
|
||||
UpdateAfterInput();
|
||||
}
|
||||
|
||||
public void OnGUI(Rect position, GUIContent label)
|
||||
{
|
||||
_totalRect = position;
|
||||
_label = new GUIContent(label);
|
||||
|
||||
// Only call Update() in EditorWindow contexts where it's required.
|
||||
// In PropertyDrawers for MonoBehaviours/ScriptableObjects, Unity manages serialization
|
||||
// and calling Update() interferes with pending edits, causing values to revert.
|
||||
if (ListProperty.serializedObject.targetObject is EditorWindow)
|
||||
ListProperty.serializedObject.Update();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
DoList(position);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
ListProperty.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public float GetPropertyHeight(GUIContent label)
|
||||
{
|
||||
if (!ListProperty.isExpanded)
|
||||
return SerializedDictionaryDrawer.TopHeaderClipHeight;
|
||||
|
||||
return ReorderableList.GetHeight();
|
||||
}
|
||||
|
||||
private void DoList(Rect position)
|
||||
{
|
||||
if (ListProperty.isExpanded)
|
||||
ReorderableList.DoList(position);
|
||||
else
|
||||
{
|
||||
using (new GUI.ClipScope(new Rect(0, position.y, position.width + position.x, SerializedDictionaryDrawer.TopHeaderClipHeight)))
|
||||
{
|
||||
_unexpandedList.DoList(position.WithY(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessState()
|
||||
{
|
||||
var newState = _activeState.OnUpdate();
|
||||
if (newState != null && newState != _activeState)
|
||||
{
|
||||
_activeState.OnExit();
|
||||
_activeState = newState;
|
||||
newState.OnEnter();
|
||||
}
|
||||
}
|
||||
|
||||
private SerializedProperty GetElementProperty(SerializedProperty property, bool fieldFlag)
|
||||
{
|
||||
return property.FindPropertyRelative(fieldFlag == SerializedDictionaryDrawer.KeyFlag ? SerializedDictionaryDrawer.KeyName : SerializedDictionaryDrawer.ValueName);
|
||||
}
|
||||
|
||||
internal static float CalculateHeightOfElement(SerializedProperty property, bool drawKeyAsList, bool drawValueAsList)
|
||||
{
|
||||
SerializedProperty keyProperty = property.FindPropertyRelative(SerializedDictionaryDrawer.KeyName);
|
||||
SerializedProperty valueProperty = property.FindPropertyRelative(SerializedDictionaryDrawer.ValueName);
|
||||
return Mathf.Max(SCEditorUtility.CalculateHeight(keyProperty, drawKeyAsList), SCEditorUtility.CalculateHeight(valueProperty, drawValueAsList));
|
||||
}
|
||||
|
||||
private void UpdateAfterInput()
|
||||
{
|
||||
InitializeSettingsIfNeeded();
|
||||
ProcessState();
|
||||
CheckPaging();
|
||||
var elementsPerPage = EditorUserSettings.Get().ElementsPerPage;
|
||||
int pageCount = Mathf.Max(1, Mathf.CeilToInt((float)DefaultState.ListSize / elementsPerPage));
|
||||
ToggleSearchBar(_propertyData.AlwaysShowSearch ? true : SCEditorUtility.ShouldShowSearch(pageCount));
|
||||
}
|
||||
|
||||
private void InitializeSettingsIfNeeded()
|
||||
{
|
||||
void InitializeSettings(bool fieldFlag)
|
||||
{
|
||||
var genericArgs = _fieldInfo.FieldType.GetGenericArguments();
|
||||
var firstProperty = ListProperty.GetArrayElementAtIndex(0);
|
||||
var keySettings = CreateDisplaySettings(GetElementProperty(firstProperty, fieldFlag), genericArgs[fieldFlag == SCEditorUtility.KeyFlag ? 0 : 1]);
|
||||
var settings = _propertyData.GetElementData(fieldFlag).Settings;
|
||||
settings.DisplayType = keySettings.displayType;
|
||||
settings.HasListDrawerToggle = keySettings.canToggleListDrawer;
|
||||
}
|
||||
|
||||
if (!_propertyListSettingsInitialized && ListProperty.minArraySize > 0)
|
||||
{
|
||||
_propertyListSettingsInitialized = true;
|
||||
InitializeSettings(SCEditorUtility.KeyFlag);
|
||||
InitializeSettings(SCEditorUtility.ValueFlag);
|
||||
SavePropertyData();
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckPaging()
|
||||
{
|
||||
// TODO: Is there a better solution to check for Revert/delete/add?
|
||||
if (_lastListSize != _activeState.ListSize)
|
||||
{
|
||||
_lastListSize = _activeState.ListSize;
|
||||
UpdateSingleEditing();
|
||||
UpdatePaging();
|
||||
}
|
||||
}
|
||||
|
||||
private void SavePropertyData()
|
||||
{
|
||||
SCEditorUtility.SavePropertyData(ListProperty, _propertyData);
|
||||
}
|
||||
|
||||
private void UpdateSingleEditing()
|
||||
{
|
||||
if (ListProperty.serializedObject.isEditingMultipleObjects && _singleEditingData.IsValid)
|
||||
_singleEditingData.Invalidate();
|
||||
else if (!ListProperty.serializedObject.isEditingMultipleObjects && !_singleEditingData.IsValid)
|
||||
{
|
||||
var dictionary = SCEditorUtility.GetPropertyValue(ListProperty, ListProperty.serializedObject.targetObject);
|
||||
_singleEditingData.LookupTable = GetLookupTable(dictionary);
|
||||
}
|
||||
}
|
||||
|
||||
private IKeyable GetLookupTable(object dictionary)
|
||||
{
|
||||
var propInfo = dictionary.GetType().GetProperty(SerializedDictionaryDrawer.LookupTableName, BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
return (IKeyable)propInfo.GetValue(dictionary);
|
||||
}
|
||||
|
||||
private void UpdatePaging()
|
||||
{
|
||||
var elementsPerPage = EditorUserSettings.Get().ElementsPerPage;
|
||||
_pagingElement.PageCount = Mathf.Max(1, Mathf.CeilToInt((float)_activeState.ListSize / elementsPerPage));
|
||||
|
||||
_pagedIndices.Clear();
|
||||
_pagedIndices.Capacity = Mathf.Max(elementsPerPage, _pagedIndices.Capacity);
|
||||
|
||||
int startIndex = (_pagingElement.Page - 1) * elementsPerPage;
|
||||
int endIndex = Mathf.Min(startIndex + elementsPerPage, _activeState.ListSize);
|
||||
for (int i = startIndex; i < endIndex; i++)
|
||||
_pagedIndices.Add(i);
|
||||
|
||||
string shortDetailsString = (_activeState.ListSize + " " + (_pagedIndices.Count == 1 ? "Element" : "Elements"));
|
||||
string detailsString = _pagingElement.PageCount > 1
|
||||
? $"{_pagedIndices[0] + 1}..{_pagedIndices.Last() + 1} / {_activeState.ListSize} Elements"
|
||||
: shortDetailsString;
|
||||
_detailsContent = new GUIContent(detailsString);
|
||||
_shortDetailsContent = new GUIContent(shortDetailsString);
|
||||
}
|
||||
|
||||
private ReorderableList MakeList()
|
||||
{
|
||||
var list = new ReorderableList(_pagedIndices, typeof(int), true, true, true, true);
|
||||
list.onAddCallback += OnAdd;
|
||||
list.onRemoveCallback += OnRemove;
|
||||
list.onReorderCallbackWithDetails += OnReorder;
|
||||
list.drawElementCallback += OnDrawElement;
|
||||
list.elementHeightCallback += OnGetElementHeight;
|
||||
list.drawHeaderCallback += OnDrawHeader;
|
||||
list.drawNoneElementCallback += OnDrawNoneElement;
|
||||
return list;
|
||||
}
|
||||
|
||||
private ReorderableList MakeUnexpandedList()
|
||||
{
|
||||
var list = new ReorderableList(SerializedDictionaryDrawer.NoEntriesList, typeof(int));
|
||||
list.drawHeaderCallback = DrawUnexpandedHeader;
|
||||
return list;
|
||||
}
|
||||
|
||||
private void ToggleSearchBar(bool flag)
|
||||
{
|
||||
_showSearchBar = flag;
|
||||
ReorderableList.headerHeight = SerializedDictionaryDrawer.TopHeaderClipHeight + SerializedDictionaryDrawer.KeyValueHeaderHeight + (_showSearchBar ? SerializedDictionaryDrawer.SearchHeaderHeight : 0);
|
||||
if (!_showSearchBar)
|
||||
{
|
||||
if (_searchField.HasFocus())
|
||||
GUI.FocusControl(null);
|
||||
SearchText = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDrawNoneElement(Rect rect)
|
||||
{
|
||||
EditorGUI.LabelField(rect, EditorGUIUtility.TrTextContent(_activeState.NoElementsText));
|
||||
}
|
||||
|
||||
private (DisplayType displayType, bool canToggleListDrawer) CreateDisplaySettings(SerializedProperty property, Type type)
|
||||
{
|
||||
bool hasCustomEditor = SCEditorUtility.HasDrawerForType(type, property.propertyType == SerializedPropertyType.ManagedReference);
|
||||
bool isGenericWithChildren = property.propertyType == SerializedPropertyType.Generic && property.hasVisibleChildren;
|
||||
bool isArray = property.isArray && property.propertyType != SerializedPropertyType.String;
|
||||
bool canToggleListDrawer = isArray || (isGenericWithChildren && hasCustomEditor);
|
||||
DisplayType displayType = DisplayType.PropertyNoLabel;
|
||||
if (canToggleListDrawer)
|
||||
displayType = DisplayType.Property;
|
||||
else if (!isArray && isGenericWithChildren && !hasCustomEditor)
|
||||
displayType = DisplayType.List;
|
||||
return (displayType, canToggleListDrawer);
|
||||
}
|
||||
|
||||
private void DrawUnexpandedHeader(Rect rect)
|
||||
{
|
||||
EditorGUI.BeginProperty(rect, _label, ListProperty);
|
||||
ListProperty.isExpanded = EditorGUI.Foldout(rect.WithX(rect.x - 5), ListProperty.isExpanded, _label, true);
|
||||
|
||||
var detailsStyle = EditorStyles.miniLabel;
|
||||
var detailsRect = rect.AppendRight(0).AppendLeft(detailsStyle.CalcSize(_shortDetailsContent).x);
|
||||
GUI.Label(detailsRect, _shortDetailsContent, detailsStyle);
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
private void DoPaging(Rect rect)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
_pagingElement.OnGUI(rect);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
ReorderableList.ClearSelection();
|
||||
UpdatePaging();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDrawHeader(Rect rect)
|
||||
{
|
||||
Rect topRect = rect.WithHeight(SerializedDictionaryDrawer.TopHeaderHeight);
|
||||
Rect adjustedTopRect = topRect.WithXAndWidth(_totalRect.x + 1, _totalRect.width - 1);
|
||||
|
||||
DoMainHeader(adjustedTopRect.CutLeft(topRect.x - adjustedTopRect.x));
|
||||
if (_showSearchBar)
|
||||
{
|
||||
adjustedTopRect = adjustedTopRect.AppendDown(SerializedDictionaryDrawer.SearchHeaderHeight);
|
||||
DoSearch(adjustedTopRect);
|
||||
}
|
||||
DoKeyValueRect(adjustedTopRect.AppendDown(SerializedDictionaryDrawer.KeyValueHeaderHeight));
|
||||
|
||||
UpdateAfterInput();
|
||||
}
|
||||
|
||||
private void DoMainHeader(Rect rect)
|
||||
{
|
||||
Rect lastTopRect = rect.AppendRight(0).WithHeight(EditorGUIUtility.singleLineHeight);
|
||||
|
||||
lastTopRect = lastTopRect.AppendLeft(20);
|
||||
DoOptionsButton(lastTopRect);
|
||||
lastTopRect = lastTopRect.AppendLeft(5);
|
||||
|
||||
if (_pagingElement.PageCount > 1)
|
||||
{
|
||||
lastTopRect = lastTopRect.AppendLeft(_pagingElement.GetDesiredWidth());
|
||||
DoPaging(lastTopRect);
|
||||
}
|
||||
|
||||
var detailsStyle = EditorStyles.miniLabel;
|
||||
lastTopRect = lastTopRect.AppendLeft(detailsStyle.CalcSize(_detailsContent).x, 5);
|
||||
GUI.Label(lastTopRect, _detailsContent, detailsStyle);
|
||||
|
||||
if (!_singleEditingData.IsValid)
|
||||
{
|
||||
lastTopRect = lastTopRect.AppendLeft(lastTopRect.height + 5);
|
||||
var guicontent = EditorGUIUtility.TrIconContent(EditorGUIUtility.Load("d_console.infoicon") as Texture, "Conflict checking, duplicate key removal and populators not supported in multi object editing mode.");
|
||||
GUI.Label(lastTopRect, guicontent);
|
||||
}
|
||||
|
||||
EditorGUI.BeginProperty(rect, _label, ListProperty);
|
||||
ListProperty.isExpanded = EditorGUI.Foldout(rect.WithXAndWidth(rect.x - 5, lastTopRect.x - rect.x), ListProperty.isExpanded, _label, true);
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
private void DoOptionsButton(Rect rect)
|
||||
{
|
||||
var screenRect = GUIUtility.GUIToScreenRect(rect);
|
||||
if (GUI.Button(rect, EditorGUIUtility.IconContent("pane options@2x"), EditorStyles.iconButton))
|
||||
{
|
||||
var gm = new GenericMenu();
|
||||
SCEditorUtility.AddGenericMenuItem(gm, false, ListProperty.minArraySize > 0, new GUIContent("Clear"), () => QueueAction(ClearList));
|
||||
SCEditorUtility.AddGenericMenuItem(gm, false, true, new GUIContent("Remove Conflicts"), () => QueueAction(RemoveConflicts));
|
||||
SCEditorUtility.AddGenericMenuItem(gm, false, _keyGeneratorsWithWindow.Count > 0, new GUIContent("Bulk Edit..."), () => OpenKeysGeneratorSelectorWindow(screenRect));
|
||||
if (_keyGeneratorsWithoutWindow.Count > 0)
|
||||
{
|
||||
gm.AddSeparator(string.Empty);
|
||||
foreach (var generatorData in _keyGeneratorsWithoutWindow)
|
||||
{
|
||||
SCEditorUtility.AddGenericMenuItem(gm, false, true, new GUIContent(generatorData.Name), OnPopulatorDataSelected, generatorData);
|
||||
}
|
||||
}
|
||||
gm.AddSeparator(string.Empty);
|
||||
SCEditorUtility.AddGenericMenuItem(gm, _propertyData.AlwaysShowSearch, true, new GUIContent("Always Show Search"), ToggleAlwaysShowSearchPropertyData);
|
||||
gm.AddItem(new GUIContent("Preferences..."), false, () => SettingsService.OpenUserPreferences(EditorUserSettingsProvider.PreferencesPath));
|
||||
gm.DropDown(rect);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPopulatorDataSelected(object userData)
|
||||
{
|
||||
var data = (KeyListGeneratorData)userData;
|
||||
var so = (KeyListGenerator)ScriptableObject.CreateInstance(data.GeneratorType);
|
||||
so.hideFlags = HideFlags.DontSave;
|
||||
ApplyPopulatorQueued(so, ModificationType.Add);
|
||||
}
|
||||
|
||||
private void OpenKeysGeneratorSelectorWindow(Rect rect)
|
||||
{
|
||||
var window = ScriptableObject.CreateInstance<KeyListGeneratorSelectorWindow>();
|
||||
window.Initialize(_keyGeneratorsWithWindow, _keyFieldInfo.FieldType);
|
||||
window.ShowAsDropDown(rect, new Vector2(400, 200));
|
||||
window.OnApply += ApplyPopulatorQueued;
|
||||
}
|
||||
|
||||
private void ToggleAlwaysShowSearchPropertyData()
|
||||
{
|
||||
_propertyData.AlwaysShowSearch = !_propertyData.AlwaysShowSearch;
|
||||
SavePropertyData();
|
||||
}
|
||||
|
||||
private void DoKeyValueRect(Rect rect)
|
||||
{
|
||||
float width = EditorGUIUtility.labelWidth + 22;
|
||||
Rect leftRect = rect.WithWidth(width);
|
||||
Rect rightRect = leftRect.AppendRight(rect.width - width);
|
||||
|
||||
if (Event.current.type == EventType.Repaint && _propertyData != null)
|
||||
{
|
||||
_keyValueStyle.Draw(leftRect, EditorGUIUtility.TrTextContent(_propertyData.GetElementData(SerializedDictionaryDrawer.KeyFlag).Settings.DisplayName), false, false, false, false);
|
||||
_keyValueStyle.Draw(rightRect, EditorGUIUtility.TrTextContent(_propertyData.GetElementData(SerializedDictionaryDrawer.ValueFlag).Settings.DisplayName), false, false, false, false);
|
||||
}
|
||||
|
||||
if (ListProperty.minArraySize > 0)
|
||||
{
|
||||
DoDisplayTypeToggle(leftRect, SerializedDictionaryDrawer.KeyFlag);
|
||||
DoDisplayTypeToggle(rightRect, SerializedDictionaryDrawer.ValueFlag);
|
||||
}
|
||||
|
||||
EditorGUI.DrawRect(rect.AppendDown(1, -1), SerializedDictionaryDrawer.BorderColor);
|
||||
}
|
||||
|
||||
private void DoSearch(Rect rect)
|
||||
{
|
||||
EditorGUI.DrawRect(rect.AppendLeft(1), SerializedDictionaryDrawer.BorderColor);
|
||||
EditorGUI.DrawRect(rect.AppendRight(1, -1), SerializedDictionaryDrawer.BorderColor);
|
||||
EditorGUI.DrawRect(rect.AppendDown(1, -1), SerializedDictionaryDrawer.BorderColor);
|
||||
|
||||
SearchText = _searchField.OnToolbarGUI(rect.CutTop(2).CutHorizontal(6), SearchText);
|
||||
}
|
||||
|
||||
private void ApplyPopulatorQueued(KeyListGenerator populator, ModificationType modificationType)
|
||||
{
|
||||
var array = populator.GetKeys(_keyFieldInfo.FieldType).OfType<object>().ToArray();
|
||||
QueueAction(() => ApplyPopulator(array, modificationType));
|
||||
}
|
||||
|
||||
private void QueueAction(EditorApplication.CallbackFunction action)
|
||||
{
|
||||
EditorApplication.delayCall += action;
|
||||
}
|
||||
|
||||
private void ApplyPopulator(IEnumerable<object> elements, ModificationType modificationType)
|
||||
{
|
||||
foreach (var targetObject in ListProperty.serializedObject.targetObjects)
|
||||
{
|
||||
Undo.RecordObject(targetObject, "Populate");
|
||||
var dictionary = SCEditorUtility.GetPropertyValue(ListProperty, targetObject);
|
||||
var lookupTable = GetLookupTable(dictionary);
|
||||
|
||||
if (modificationType == ModificationType.Add)
|
||||
AddElements(lookupTable, elements);
|
||||
else if (modificationType == ModificationType.Remove)
|
||||
RemoveElements(lookupTable, elements);
|
||||
else if (modificationType == ModificationType.Confine)
|
||||
ConfineElements(lookupTable, elements);
|
||||
|
||||
lookupTable.RecalculateOccurences();
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(targetObject);
|
||||
}
|
||||
|
||||
ListProperty.serializedObject.Update();
|
||||
ActiveEditorTracker.sharedTracker.ForceRebuild();
|
||||
}
|
||||
|
||||
private static void AddElements(IKeyable lookupTable, IEnumerable<object> elements)
|
||||
{
|
||||
foreach (var key in elements)
|
||||
{
|
||||
var occurences = lookupTable.GetOccurences(key);
|
||||
if (occurences.Count > 0)
|
||||
continue;
|
||||
lookupTable.AddKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConfineElements(IKeyable lookupTable, IEnumerable<object> elements)
|
||||
{
|
||||
var keysToRemove = lookupTable.Keys.OfType<object>().ToHashSet();
|
||||
foreach (var key in elements)
|
||||
keysToRemove.Remove(key);
|
||||
|
||||
RemoveElements(lookupTable, keysToRemove);
|
||||
}
|
||||
|
||||
private static void RemoveElements(IKeyable lookupTable, IEnumerable<object> elements)
|
||||
{
|
||||
var indicesToRemove = elements.SelectMany(x => lookupTable.GetOccurences(x)).OrderByDescending(index => index);
|
||||
foreach (var index in indicesToRemove)
|
||||
{
|
||||
lookupTable.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearList()
|
||||
{
|
||||
ListProperty.ClearArray();
|
||||
ListProperty.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private void RemoveConflicts()
|
||||
{
|
||||
foreach (var targetObject in ListProperty.serializedObject.targetObjects)
|
||||
{
|
||||
Undo.RecordObject(targetObject, "Remove Conflicts");
|
||||
var dictionary = SCEditorUtility.GetPropertyValue(ListProperty, targetObject);
|
||||
var lookupTable = GetLookupTable(dictionary);
|
||||
|
||||
List<int> duplicateIndices = new List<int>();
|
||||
|
||||
foreach (var key in lookupTable.Keys)
|
||||
{
|
||||
var occurences = lookupTable.GetOccurences(key);
|
||||
for (int i = 1; i < occurences.Count; i++)
|
||||
duplicateIndices.Add(occurences[i]);
|
||||
}
|
||||
|
||||
foreach (var indexToRemove in duplicateIndices.OrderByDescending(x => x))
|
||||
{
|
||||
lookupTable.RemoveAt(indexToRemove);
|
||||
}
|
||||
|
||||
lookupTable.RecalculateOccurences();
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(targetObject);
|
||||
}
|
||||
|
||||
ListProperty.serializedObject.Update();
|
||||
ActiveEditorTracker.sharedTracker.ForceRebuild();
|
||||
}
|
||||
|
||||
private void DoDisplayTypeToggle(Rect contentRect, bool fieldFlag)
|
||||
{
|
||||
var displayData = _propertyData.GetElementData(fieldFlag);
|
||||
|
||||
if (displayData.Settings.HasListDrawerToggle)
|
||||
{
|
||||
Rect rightRectToggle = new Rect(contentRect);
|
||||
rightRectToggle.x += rightRectToggle.width - 18;
|
||||
rightRectToggle.width = 18;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
bool newValue = GUI.Toggle(rightRectToggle, displayData.IsListToggleActive, SerializedDictionaryDrawer.DisplayTypeToggleContent, EditorStyles.toolbarButton);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
displayData.IsListToggleActive = newValue;
|
||||
SavePropertyData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float OnGetElementHeight(int index)
|
||||
{
|
||||
int actualIndex = _pagedIndices[index];
|
||||
var element = _activeState.GetPropertyAtIndex(actualIndex);
|
||||
return CalculateHeightOfElement(element, _propertyData.GetElementData(SerializedDictionaryDrawer.KeyFlag).EffectiveDisplayType == DisplayType.List ? true : false, _propertyData.GetElementData(SerializedDictionaryDrawer.ValueFlag).EffectiveDisplayType == DisplayType.List ? true : false);
|
||||
}
|
||||
|
||||
private void OnDrawElement(Rect rect, int index, bool isActive, bool isFocused)
|
||||
{
|
||||
const int lineLeftSpace = 2;
|
||||
const int lineWidth = 1;
|
||||
const int lineRightSpace = 12;
|
||||
const int totalSpace = lineLeftSpace + lineWidth + lineRightSpace;
|
||||
|
||||
int actualIndex = _pagedIndices[index];
|
||||
|
||||
SerializedProperty kvp = _activeState.GetPropertyAtIndex(actualIndex);
|
||||
Rect keyRect = rect.WithSize(EditorGUIUtility.labelWidth - lineLeftSpace, EditorGUIUtility.singleLineHeight);
|
||||
Rect lineRect = keyRect.WithXAndWidth(keyRect.x + keyRect.width + lineLeftSpace, lineWidth).WithHeight(rect.height);
|
||||
Rect valueRect = keyRect.AppendRight(rect.width - keyRect.width - totalSpace, totalSpace);
|
||||
|
||||
var keyProperty = kvp.FindPropertyRelative(SerializedDictionaryDrawer.KeyName);
|
||||
var valueProperty = kvp.FindPropertyRelative(SerializedDictionaryDrawer.ValueName);
|
||||
|
||||
Color prevColor = GUI.color;
|
||||
if (_singleEditingData.IsValid)
|
||||
{
|
||||
var keyObject = _keyFieldInfo.GetValue(_singleEditingData.LookupTable.GetKeyAt(actualIndex));
|
||||
var occurences = _singleEditingData.LookupTable.GetOccurences(keyObject);
|
||||
if (occurences.Count > 1)
|
||||
{
|
||||
GUI.color = occurences[0] == actualIndex ? Color.yellow : Color.red;
|
||||
}
|
||||
if (!SerializedCollectionsUtility.IsValidKey(keyObject))
|
||||
{
|
||||
GUI.color = Color.red;
|
||||
}
|
||||
}
|
||||
|
||||
var keyDisplayData = _propertyData.GetElementData(SerializedDictionaryDrawer.KeyFlag);
|
||||
DrawGroupedElement(keyRect, 20, keyProperty, keyDisplayData.EffectiveDisplayType);
|
||||
|
||||
EditorGUI.DrawRect(lineRect, new Color(36 / 255f, 36 / 255f, 36 / 255f));
|
||||
GUI.color = prevColor;
|
||||
|
||||
var valueDisplayData = _propertyData.GetElementData(SerializedDictionaryDrawer.ValueFlag);
|
||||
DrawGroupedElement(valueRect, lineRightSpace, valueProperty, valueDisplayData.EffectiveDisplayType);
|
||||
}
|
||||
|
||||
private void DrawGroupedElement(Rect rect, int spaceForProperty, SerializedProperty property, DisplayType displayType)
|
||||
{
|
||||
using (new LabelWidth(rect.width * 0.4f))
|
||||
{
|
||||
float height = SCEditorUtility.CalculateHeight(property.Copy(), displayType);
|
||||
Rect groupRect = rect.CutLeft(-spaceForProperty).WithHeight(height);
|
||||
GUI.BeginGroup(groupRect);
|
||||
|
||||
Rect elementRect = new Rect(spaceForProperty, 0, rect.width, height);
|
||||
_activeState.DrawElement(elementRect, property, displayType);
|
||||
|
||||
DrawInvisibleProperty(rect.WithWidth(spaceForProperty), property);
|
||||
|
||||
GUI.EndGroup();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DrawInvisibleProperty(Rect rect, SerializedProperty property)
|
||||
{
|
||||
const int propertyOffset = 5;
|
||||
|
||||
GUI.BeginClip(rect.CutLeft(-propertyOffset));
|
||||
EditorGUI.BeginProperty(rect, GUIContent.none, property);
|
||||
EditorGUI.EndProperty();
|
||||
GUI.EndClip();
|
||||
}
|
||||
|
||||
internal static void DrawElement(Rect rect, SerializedProperty property, DisplayType displayType, Action<SerializedProperty> BeforeDrawingCallback = null, Action<SerializedProperty> AfterDrawingCallback = null)
|
||||
{
|
||||
switch (displayType)
|
||||
{
|
||||
case DisplayType.Property:
|
||||
BeforeDrawingCallback?.Invoke(property);
|
||||
EditorGUI.PropertyField(rect, property, true);
|
||||
AfterDrawingCallback?.Invoke(property);
|
||||
break;
|
||||
case DisplayType.PropertyNoLabel:
|
||||
BeforeDrawingCallback?.Invoke(property);
|
||||
EditorGUI.PropertyField(rect, property, GUIContent.none, true);
|
||||
AfterDrawingCallback?.Invoke(property);
|
||||
break;
|
||||
case DisplayType.List:
|
||||
Rect childRect = rect.WithHeight(0);
|
||||
foreach (SerializedProperty prop in SCEditorUtility.GetChildren(property.Copy()))
|
||||
{
|
||||
childRect = childRect.AppendDown(EditorGUI.GetPropertyHeight(prop, true));
|
||||
BeforeDrawingCallback?.Invoke(prop);
|
||||
EditorGUI.PropertyField(childRect, prop, true);
|
||||
AfterDrawingCallback?.Invoke(prop);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAdd(ReorderableList list)
|
||||
{
|
||||
int targetIndex = list.selectedIndices.Count > 0 && list.selectedIndices[0] >= 0 ? list.selectedIndices[0] : 0;
|
||||
int actualTargetIndex = targetIndex < _pagedIndices.Count ? _pagedIndices[targetIndex] : 0;
|
||||
_activeState.InserElementAt(actualTargetIndex);
|
||||
}
|
||||
|
||||
private void OnReorder(ReorderableList list, int oldIndex, int newIndex)
|
||||
{
|
||||
UpdatePaging();
|
||||
ListProperty.MoveArrayElement(_pagedIndices[oldIndex], _pagedIndices[newIndex]);
|
||||
}
|
||||
|
||||
private void OnRemove(ReorderableList list)
|
||||
{
|
||||
_activeState.RemoveElementAt(_pagedIndices[list.index]);
|
||||
UpdatePaging();
|
||||
//int actualIndex = _pagedIndices[list.index];
|
||||
//ListProperty.DeleteArrayElementAtIndex(actualIndex);
|
||||
//UpdatePaging();
|
||||
//if (actualIndex >= ListProperty.minArraySize)
|
||||
// list.index = _pagedIndices.Count - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c3b210db82056a4a93c337b45da413b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7691132b92786be418f91bf39639db87
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.IO;
|
||||
using System;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor
|
||||
{
|
||||
public sealed class EditorUserSettings : ScriptableObject
|
||||
{
|
||||
[SerializeField]
|
||||
private bool _alwaysShowSearch = false;
|
||||
[SerializeField, Range(1, 10)]
|
||||
private int _pageCountForSearch = 1;
|
||||
[SerializeField, Min(1)]
|
||||
private int _elementsPerPage = 10;
|
||||
|
||||
public bool AlwaysShowSearch => _alwaysShowSearch;
|
||||
public int PageCountForSearch => _pageCountForSearch;
|
||||
public int ElementsPerPage => _elementsPerPage;
|
||||
|
||||
private static EditorUserSettings _instance;
|
||||
|
||||
private const string _filePath = "UserSettings/SerializedCollectionsEditorSettings.asset";
|
||||
|
||||
public static EditorUserSettings Get()
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = CreateInstance<EditorUserSettings>();
|
||||
LoadInto(_instance);
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
private static void LoadInto(EditorUserSettings settings)
|
||||
{
|
||||
if (!File.Exists(_filePath)) return;
|
||||
|
||||
try
|
||||
{
|
||||
string json = File.ReadAllText(_filePath);
|
||||
EditorJsonUtility.FromJsonOverwrite(json, settings);
|
||||
return;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Save()
|
||||
{
|
||||
string contents = EditorJsonUtility.ToJson(Get());
|
||||
File.WriteAllText(_filePath, contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21353c5f0548cba4a98029e0c433a0dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,82 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEditor.AnimatedValues;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor
|
||||
{
|
||||
public class EditorUserSettingsProvider : SettingsProvider
|
||||
{
|
||||
public const string PreferencesPath = "Preferences/Serialized Collections";
|
||||
|
||||
private SerializedObject _serializedObject;
|
||||
private SerializedProperty _alwaysShowSearch;
|
||||
private SerializedProperty _pageCountForSearch;
|
||||
private SerializedProperty _elementsPerPage;
|
||||
private AnimBool _searchAnimBool;
|
||||
|
||||
class Styles
|
||||
{
|
||||
}
|
||||
|
||||
[SettingsProvider]
|
||||
public static SettingsProvider CreateProvider()
|
||||
{
|
||||
var provider = new EditorUserSettingsProvider(PreferencesPath, SettingsScope.User);
|
||||
|
||||
provider.keywords = GetSearchKeywordsFromGUIContentProperties<Styles>();
|
||||
return provider;
|
||||
}
|
||||
|
||||
public EditorUserSettingsProvider(string path, SettingsScope scope = SettingsScope.User) : base(path, scope) { }
|
||||
|
||||
public static bool IsSettingsAvailable() => EditorUserSettings.Get() != null;
|
||||
|
||||
public override void OnActivate(string searchContext, VisualElement rootElement)
|
||||
{
|
||||
EnsureSerializedObjectExists();
|
||||
}
|
||||
|
||||
private void EnsureSerializedObjectExists()
|
||||
{
|
||||
if (_serializedObject == null)
|
||||
{
|
||||
_searchAnimBool = new AnimBool();
|
||||
_searchAnimBool.valueChanged.AddListener(new UnityAction(Repaint));
|
||||
_serializedObject = new SerializedObject(EditorUserSettings.Get());
|
||||
_alwaysShowSearch = _serializedObject.FindProperty("_alwaysShowSearch");
|
||||
_pageCountForSearch = _serializedObject.FindProperty("_pageCountForSearch");
|
||||
_elementsPerPage = _serializedObject.FindProperty("_elementsPerPage");
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGUI(string searchContext)
|
||||
{
|
||||
EnsureSerializedObjectExists();
|
||||
|
||||
EditorGUI.indentLevel = 1;
|
||||
|
||||
_serializedObject.UpdateIfRequiredOrScript();
|
||||
|
||||
EditorGUILayout.PropertyField(_alwaysShowSearch);
|
||||
_searchAnimBool.target = !_alwaysShowSearch.boolValue;
|
||||
using (var group = new EditorGUILayout.FadeGroupScope(_searchAnimBool.faded))
|
||||
{
|
||||
if (group.visible)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_pageCountForSearch);
|
||||
}
|
||||
}
|
||||
EditorGUILayout.PropertyField(_elementsPerPage);
|
||||
|
||||
bool changed =_serializedObject.ApplyModifiedProperties();
|
||||
if (changed)
|
||||
{
|
||||
EditorUserSettings.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 01b95baf6e99cff43a84c4ba42557db4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b07f70f96e8585f45976044096080ecd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using static AYellowpaper.SerializedCollections.Editor.SerializedDictionaryDrawer;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor.States
|
||||
{
|
||||
internal class DefaultListState : ListState
|
||||
{
|
||||
public override int ListSize => Drawer.ListProperty.minArraySize;
|
||||
|
||||
public DefaultListState(SerializedDictionaryInstanceDrawer serializedDictionaryDrawer) : base(serializedDictionaryDrawer)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnEnter()
|
||||
{
|
||||
Drawer.ReorderableList.draggable = true;
|
||||
}
|
||||
|
||||
public override void OnExit()
|
||||
{
|
||||
}
|
||||
|
||||
public override ListState OnUpdate()
|
||||
{
|
||||
if (Drawer.SearchText.Length > 0)
|
||||
return Drawer.SearchState;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public override void DrawElement(Rect rect, SerializedProperty property, DisplayType displayType)
|
||||
{
|
||||
SerializedDictionaryInstanceDrawer.DrawElement(rect, property, displayType);
|
||||
}
|
||||
|
||||
public override SerializedProperty GetPropertyAtIndex(int index)
|
||||
{
|
||||
return Drawer.ListProperty.GetArrayElementAtIndex(index);
|
||||
}
|
||||
|
||||
public override void RemoveElementAt(int index)
|
||||
{
|
||||
Drawer.ListProperty.DeleteArrayElementAtIndex(index);
|
||||
}
|
||||
|
||||
public override void InserElementAt(int index)
|
||||
{
|
||||
Drawer.ListProperty.InsertArrayElementAtIndex(index);
|
||||
Drawer.ListProperty.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 803188ced5ea71c41b6079f7ae375573
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using static AYellowpaper.SerializedCollections.Editor.SerializedDictionaryDrawer;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor.States
|
||||
{
|
||||
internal abstract class ListState
|
||||
{
|
||||
public abstract int ListSize { get; }
|
||||
public virtual string NoElementsText => "List is Empty.";
|
||||
|
||||
public readonly SerializedDictionaryInstanceDrawer Drawer;
|
||||
|
||||
public ListState(SerializedDictionaryInstanceDrawer serializedDictionaryDrawer)
|
||||
{
|
||||
Drawer = serializedDictionaryDrawer;
|
||||
}
|
||||
|
||||
public abstract SerializedProperty GetPropertyAtIndex(int index);
|
||||
public abstract ListState OnUpdate();
|
||||
public abstract void OnEnter();
|
||||
public abstract void OnExit();
|
||||
public abstract void DrawElement(Rect rect, SerializedProperty property, DisplayType displayType);
|
||||
public abstract void RemoveElementAt(int index);
|
||||
public abstract void InserElementAt(int index);
|
||||
|
||||
public virtual float GetHeightAtIndex(int index, bool drawKeyAsList, bool drawValueAsList)
|
||||
{
|
||||
return SerializedDictionaryInstanceDrawer.CalculateHeightOfElement(GetPropertyAtIndex(index), drawKeyAsList, drawValueAsList);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b4752173882f944eb16a5720a22f3e9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,109 @@
|
||||
using AYellowpaper.SerializedCollections.Editor.Search;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using static AYellowpaper.SerializedCollections.Editor.SerializedDictionaryDrawer;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor.States
|
||||
{
|
||||
internal class SearchListState : ListState
|
||||
{
|
||||
public override int ListSize => _searchResults.Count;
|
||||
public override string NoElementsText => "No Results";
|
||||
public bool OnlyShowMatchingValues { get; set; }
|
||||
|
||||
private string _lastSearch = string.Empty;
|
||||
private List<SearchResultEntry> _searchResults = new List<SearchResultEntry>();
|
||||
private HashSet<string> _foundProperties;
|
||||
private Color _previousColor;
|
||||
|
||||
public SearchListState(SerializedDictionaryInstanceDrawer serializedDictionaryDrawer) : base(serializedDictionaryDrawer)
|
||||
{
|
||||
}
|
||||
|
||||
public override void DrawElement(Rect rect, SerializedProperty property, DisplayType displayType)
|
||||
{
|
||||
SerializedDictionaryInstanceDrawer.DrawElement(rect, property, displayType, BeforeDrawingProperty, AfterDrawingProperty);
|
||||
}
|
||||
|
||||
private void BeforeDrawingProperty(SerializedProperty obj)
|
||||
{
|
||||
_previousColor = GUI.backgroundColor;
|
||||
if (_foundProperties.Contains(obj.propertyPath))
|
||||
{
|
||||
GUI.backgroundColor = Color.blue;
|
||||
}
|
||||
}
|
||||
|
||||
private void AfterDrawingProperty(SerializedProperty obj)
|
||||
{
|
||||
GUI.backgroundColor = _previousColor;
|
||||
}
|
||||
|
||||
public override void OnEnter()
|
||||
{
|
||||
Drawer.ReorderableList.draggable = false;
|
||||
UpdateSearch();
|
||||
}
|
||||
|
||||
public override void OnExit()
|
||||
{
|
||||
}
|
||||
|
||||
public override ListState OnUpdate()
|
||||
{
|
||||
if (Drawer.SearchText.Length == 0)
|
||||
return Drawer.DefaultState;
|
||||
|
||||
UpdateSearch();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void UpdateSearch()
|
||||
{
|
||||
if (_lastSearch != Drawer.SearchText)
|
||||
{
|
||||
_lastSearch = Drawer.SearchText;
|
||||
PerformSearch(Drawer.SearchText);
|
||||
}
|
||||
}
|
||||
|
||||
public void PerformSearch(string searchString)
|
||||
{
|
||||
var query = new SearchQuery(Matchers.RegisteredMatchers);
|
||||
query.SearchString = searchString;
|
||||
_searchResults.Clear();
|
||||
_searchResults.AddRange(query.ApplyToArrayProperty(Drawer.ListProperty));
|
||||
|
||||
_foundProperties = _searchResults.SelectMany(x => x.MatchingResults, (x, y) => y.Property.propertyPath).ToHashSet();
|
||||
}
|
||||
|
||||
public override SerializedProperty GetPropertyAtIndex(int index)
|
||||
{
|
||||
return _searchResults[index].Property;
|
||||
}
|
||||
|
||||
public override float GetHeightAtIndex(int index, bool drawKeyAsList, bool drawValueAsList)
|
||||
{
|
||||
return base.GetHeightAtIndex(index, drawKeyAsList, drawValueAsList);
|
||||
}
|
||||
|
||||
public override void RemoveElementAt(int index)
|
||||
{
|
||||
var indexToDelete = _searchResults[index].Index;
|
||||
Drawer.ListProperty.DeleteArrayElementAtIndex(indexToDelete);
|
||||
PerformSearch(_lastSearch);
|
||||
}
|
||||
|
||||
public override void InserElementAt(int index)
|
||||
{
|
||||
var indexToAdd = _searchResults[index].Index;
|
||||
Drawer.ListProperty.InsertArrayElementAtIndex(indexToAdd);
|
||||
PerformSearch(_lastSearch);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ed2b1abf79f0c74c8224a423ec3123c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ce09595c06b9854abdd9a22a57e16bd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor
|
||||
{
|
||||
public struct GUIEnabledScope : IDisposable
|
||||
{
|
||||
public readonly bool PreviouslyEnabled;
|
||||
|
||||
public GUIEnabledScope(bool enabled)
|
||||
{
|
||||
PreviouslyEnabled = GUI.enabled;
|
||||
GUI.enabled = enabled;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GUI.enabled = PreviouslyEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c671c12e9de22d042be004c62b6f4158
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor
|
||||
{
|
||||
public struct LabelWidth : IDisposable
|
||||
{
|
||||
public float PreviousWidth { get; }
|
||||
|
||||
public LabelWidth(float width)
|
||||
{
|
||||
PreviousWidth = EditorGUIUtility.labelWidth;
|
||||
EditorGUIUtility.labelWidth = width;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
EditorGUIUtility.labelWidth = PreviousWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd75bc249daa39f4e832a3dab9c23c82
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,41 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor
|
||||
{
|
||||
public static class RectUtility
|
||||
{
|
||||
public static Rect WithX(this Rect rect, float x) => new Rect(x, rect.y, rect.width, rect.height);
|
||||
public static Rect WithY(this Rect rect, float y) => new Rect(rect.x, y, rect.width, rect.height);
|
||||
public static Rect WithWidth(this Rect rect, float width) => new Rect(rect.x, rect.y, width, rect.height);
|
||||
public static Rect WithHeight(this Rect rect, float height) => new Rect(rect.x, rect.y, rect.width, height);
|
||||
public static Rect WithPosition(this Rect rect, Vector2 position) => new Rect(position, rect.size);
|
||||
public static Rect WithPosition(this Rect rect, float x, float y) => new Rect(new Vector2(x, y), rect.size);
|
||||
public static Rect WithSize(this Rect rect, Vector2 size) => new Rect(rect.position, size);
|
||||
public static Rect WithSize(this Rect rect, float width, float height) => new Rect(rect.position, new Vector2(width, height));
|
||||
|
||||
public static Rect WithXAndWidth(this Rect rect, float x, float width) => new Rect(x, rect.y, width, rect.height);
|
||||
public static Rect WithYAndHeight(this Rect rect, float y, float height) => new Rect(rect.x, y, rect.width, height);
|
||||
|
||||
public static Rect AppendRight(this Rect rect, float width) => new Rect(rect.x + rect.width, rect.y, width, rect.height);
|
||||
public static Rect AppendRight(this Rect rect, float width, float space) => new Rect(rect.x + rect.width + space, rect.y, width, rect.height);
|
||||
public static Rect AppendLeft(this Rect rect, float width) => new Rect(rect.x - width, rect.y, width, rect.height);
|
||||
public static Rect AppendLeft(this Rect rect, float width, float space) => new Rect(rect.x - space - width, rect.y, width, rect.height);
|
||||
public static Rect AppendUp(this Rect rect, float height) => new Rect(rect.x, rect.y - height, rect.width, height);
|
||||
public static Rect AppendUp(this Rect rect, float height, float space) => new Rect(rect.x, rect.y - space - height, rect.width, height);
|
||||
public static Rect AppendDown(this Rect rect, float height) => new Rect(rect.x, rect.y + rect.height, rect.width, height);
|
||||
public static Rect AppendDown(this Rect rect, float height, float space) => new Rect(rect.x, rect.y + rect.height + space, rect.width, height);
|
||||
|
||||
public static Rect CutLeft(this Rect rect, float width) => new Rect(rect.x + width, rect.y, rect.width - width, rect.height);
|
||||
public static Rect CutRight(this Rect rect, float width) => new Rect(rect.x, rect.y, rect.width - width, rect.height);
|
||||
public static Rect CutTop(this Rect rect, float height) => new Rect(rect.x, rect.y + height, rect.width, rect.height - height);
|
||||
public static Rect CutBottom(this Rect rect, float height) => new Rect(rect.x, rect.y, rect.width, rect.height - height);
|
||||
|
||||
public static Rect CutHorizontal(this Rect rect, float leftAndRight) => CutHorizontal(rect, leftAndRight, leftAndRight);
|
||||
public static Rect CutHorizontal(this Rect rect, float left, float right) => new Rect(rect.x + left, rect.y, rect.width - left - right, rect.height);
|
||||
public static Rect CutVertical(this Rect rect, float topAndBottom) => CutVertical(rect, topAndBottom, topAndBottom);
|
||||
public static Rect CutVertical(this Rect rect, float top, float bottom) => new Rect(rect.x, rect.y + top, rect.width, rect.height - top - bottom);
|
||||
|
||||
public static Rect Cut(this Rect rect, float topBottom, float leftRight) => Cut(rect, topBottom, leftRight, topBottom, leftRight);
|
||||
public static Rect Cut(this Rect rect, float top, float right, float bottom, float left) => new Rect(rect.x + left, rect.y + top, rect.width - left - right, rect.height - top - bottom);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68261ebef89d61441a35961731b0a083
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,201 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using System.Linq;
|
||||
using AYellowpaper.SerializedCollections.Editor.Data;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor
|
||||
{
|
||||
internal static class SCEditorUtility
|
||||
{
|
||||
public const string EditorPrefsPrefix = "SC_";
|
||||
public const bool KeyFlag = true;
|
||||
public const bool ValueFlag = false;
|
||||
|
||||
public static bool GetPersistentBool(string path, bool defaultValue)
|
||||
{
|
||||
return EditorPrefs.GetBool(EditorPrefsPrefix + path, defaultValue);
|
||||
}
|
||||
|
||||
public static bool HasKey(string path)
|
||||
{
|
||||
return EditorPrefs.HasKey( EditorPrefsPrefix + path );
|
||||
}
|
||||
|
||||
public static void SetPersistentBool(string path, bool value)
|
||||
{
|
||||
EditorPrefs.SetBool(EditorPrefsPrefix + path, value);
|
||||
}
|
||||
|
||||
public static float CalculateHeight(SerializedProperty property, DisplayType displayType)
|
||||
{
|
||||
return CalculateHeight(property, displayType == DisplayType.List ? true : false);
|
||||
}
|
||||
|
||||
public static float CalculateHeight(SerializedProperty property, bool drawAsList)
|
||||
{
|
||||
if (drawAsList)
|
||||
{
|
||||
float height = 0;
|
||||
foreach (SerializedProperty child in GetChildren(property))
|
||||
height += EditorGUI.GetPropertyHeight(child, true);
|
||||
return height;
|
||||
}
|
||||
|
||||
return EditorGUI.GetPropertyHeight(property, true);
|
||||
}
|
||||
|
||||
public static IEnumerable<SerializedProperty> GetChildren(SerializedProperty property, bool recursive = false)
|
||||
{
|
||||
if (!property.hasVisibleChildren)
|
||||
{
|
||||
yield return property;
|
||||
yield break;
|
||||
}
|
||||
|
||||
SerializedProperty end = property.GetEndProperty();
|
||||
property.NextVisible(true);
|
||||
do
|
||||
{
|
||||
yield return property;
|
||||
} while (property.NextVisible(recursive) && !SerializedProperty.EqualContents(property, end));
|
||||
}
|
||||
|
||||
public static int GetActualArraySize(SerializedProperty arrayProperty)
|
||||
{
|
||||
return GetChildren(arrayProperty).Count() - 1;
|
||||
}
|
||||
|
||||
public static PropertyData GetPropertyData(SerializedProperty property)
|
||||
{
|
||||
var data = new PropertyData();
|
||||
var json = EditorPrefs.GetString(EditorPrefsPrefix + property.propertyPath, null);
|
||||
if (json != null)
|
||||
EditorJsonUtility.FromJsonOverwrite(json, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
public static void SavePropertyData(SerializedProperty property, PropertyData propertyData)
|
||||
{
|
||||
var json = EditorJsonUtility.ToJson(propertyData);
|
||||
EditorPrefs.SetString(EditorPrefsPrefix + property.propertyPath, json);
|
||||
}
|
||||
|
||||
public static bool ShouldShowSearch(int pages)
|
||||
{
|
||||
var settings = EditorUserSettings.Get();
|
||||
return settings.AlwaysShowSearch ? true : pages >= settings.PageCountForSearch;
|
||||
}
|
||||
|
||||
public static bool HasDrawerForType(Type type, bool isPropertyManagedReferenceType)
|
||||
{
|
||||
Type attributeUtilityType = typeof(SerializedProperty).Assembly.GetType("UnityEditor.ScriptAttributeUtility");
|
||||
if (attributeUtilityType == null)
|
||||
return false;
|
||||
var getDrawerMethod = attributeUtilityType.GetMethod("GetDrawerTypeForType", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
if (getDrawerMethod == null)
|
||||
return false;
|
||||
|
||||
#if UNITY_2022_3_OR_NEWER
|
||||
if (getDrawerMethod.GetParameters().Length == 2)
|
||||
{
|
||||
return getDrawerMethod.Invoke(type, new object[] { type, isPropertyManagedReferenceType }) != null;
|
||||
} else if(getDrawerMethod.GetParameters().Length == 3)
|
||||
{
|
||||
return getDrawerMethod.Invoke(type, new object[] { type, new Type[0], isPropertyManagedReferenceType }) != null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return getDrawerMethod.Invoke(type, new object[] { type }) != null;
|
||||
}
|
||||
#else
|
||||
return getDrawerMethod.Invoke(type, new object[] { type }) != null;
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static void AddGenericMenuItem(GenericMenu genericMenu, bool isOn, bool isEnabled, GUIContent content, GenericMenu.MenuFunction action)
|
||||
{
|
||||
if (isEnabled)
|
||||
genericMenu.AddItem(content, isOn, action);
|
||||
else
|
||||
genericMenu.AddDisabledItem(content);
|
||||
}
|
||||
|
||||
internal static void AddGenericMenuItem(GenericMenu genericMenu, bool isOn, bool isEnabled, GUIContent content, GenericMenu.MenuFunction2 action, object userData)
|
||||
{
|
||||
if (isEnabled)
|
||||
genericMenu.AddItem(content, isOn, action, userData);
|
||||
else
|
||||
genericMenu.AddDisabledItem(content);
|
||||
}
|
||||
|
||||
internal static bool TryGetTypeFromProperty(SerializedProperty property, out Type type)
|
||||
{
|
||||
try
|
||||
{
|
||||
var classType = typeof(EditorGUI).Assembly.GetType("UnityEditor.ScriptAttributeUtility");
|
||||
var methodInfo = classType.GetMethod("GetFieldInfoFromProperty", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
var parameters = new object[] { property, null };
|
||||
methodInfo.Invoke(null, parameters);
|
||||
type = (Type) parameters[1];
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
type = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static object GetPropertyValue(SerializedProperty prop, object target)
|
||||
{
|
||||
var path = prop.propertyPath.Replace(".Array.data[", "[");
|
||||
var elements = path.Split('.');
|
||||
foreach (var element in elements.Take(elements.Length - 1))
|
||||
{
|
||||
if (element.Contains("["))
|
||||
{
|
||||
var elementName = element.Substring(0, element.IndexOf("["));
|
||||
var index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", ""));
|
||||
target = GetValue(target, elementName, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = GetValue(target, element);
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
public static object GetValue(object source, string name)
|
||||
{
|
||||
if (source == null)
|
||||
return null;
|
||||
var type = source.GetType();
|
||||
var f = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
if (f == null)
|
||||
{
|
||||
var p = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
|
||||
if (p == null)
|
||||
return null;
|
||||
return p.GetValue(source, null);
|
||||
}
|
||||
return f.GetValue(source);
|
||||
}
|
||||
|
||||
public static object GetValue(object source, string name, int index)
|
||||
{
|
||||
var enumerable = GetValue(source, name) as IEnumerable;
|
||||
var enm = enumerable.GetEnumerator();
|
||||
while (index-- >= 0)
|
||||
enm.MoveNext();
|
||||
return enm.Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 138277cf2e7d2cd4e99c3cd7e2ecaaed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.Editor
|
||||
{
|
||||
internal static class SCEnumUtility
|
||||
{
|
||||
private static Dictionary<Type, EnumCache> _cache = new Dictionary<Type, EnumCache>();
|
||||
|
||||
internal static EnumCache GetEnumCache(Type enumType)
|
||||
{
|
||||
if (_cache.TryGetValue(enumType, out var val))
|
||||
return val;
|
||||
|
||||
try
|
||||
{
|
||||
var classType = typeof(EditorGUI).Assembly.GetType("UnityEditor.EnumDataUtility");
|
||||
var methodInfo = classType.GetMethod("GetCachedEnumData", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
var parameters = new object[] { enumType, true };
|
||||
var result = methodInfo.Invoke(null, parameters);
|
||||
var flagValues = (int[])result.GetType().GetField("flagValues").GetValue(result);
|
||||
var names = (string[])result.GetType().GetField("names").GetValue(result);
|
||||
var cache = new EnumCache(enumType, flagValues, names);
|
||||
_cache.Add(enumType, cache);
|
||||
return cache;
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal record EnumCache
|
||||
{
|
||||
public readonly Type Type;
|
||||
public readonly bool IsFlag;
|
||||
public readonly int Length;
|
||||
public readonly int[] FlagValues;
|
||||
public readonly string[] Names;
|
||||
|
||||
private readonly Dictionary<int, string[]> _namesByValue = new Dictionary<int, string[]>();
|
||||
|
||||
public EnumCache(Type type, int[] flagValues, string[] displayNames)
|
||||
{
|
||||
Type = type;
|
||||
FlagValues = flagValues;
|
||||
Names = displayNames;
|
||||
Length = flagValues.Length;
|
||||
IsFlag = Type.IsDefined(typeof(FlagsAttribute));
|
||||
}
|
||||
|
||||
internal string[] GetNamesForValue(int value)
|
||||
{
|
||||
if (_namesByValue.TryGetValue(value, out var list))
|
||||
return list;
|
||||
|
||||
string[] array = IsFlag ? GetFlagValues(value).ToArray() : new[] { GetEnumValue(value) };
|
||||
|
||||
_namesByValue.Add(value, array);
|
||||
return array;
|
||||
}
|
||||
|
||||
private string GetEnumValue(int value)
|
||||
{
|
||||
for (int i = 0; i < Length; i++)
|
||||
{
|
||||
if (FlagValues[i] == value)
|
||||
return Names[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetFlagValues(int flagValue)
|
||||
{
|
||||
if (flagValue == 0)
|
||||
{
|
||||
yield return FlagValues[0] == 0 ? Names[0] : "Nothing";
|
||||
yield break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Length; i++)
|
||||
{
|
||||
int fv = FlagValues[i];
|
||||
if ((fv & flagValue) == fv && fv != 0)
|
||||
yield return Names[i];
|
||||
}
|
||||
|
||||
if (FlagValues[Length - 1] != -1 && flagValue == -1)
|
||||
yield return "Everything";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76def6672c756704bac4efd5a3625113
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
7
Packages/SerializedDictionary-main/LICENSE.md
Normal file
7
Packages/SerializedDictionary-main/LICENSE.md
Normal file
@@ -0,0 +1,7 @@
|
||||
Copyright (c) 2023 ayellowpaper
|
||||
|
||||
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 (including the next paragraph) 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.
|
||||
7
Packages/SerializedDictionary-main/LICENSE.md.meta
Normal file
7
Packages/SerializedDictionary-main/LICENSE.md.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c686c48b6dd7004fbba03d7faefcb58
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
83
Packages/SerializedDictionary-main/README.md
Normal file
83
Packages/SerializedDictionary-main/README.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Serialized Dictionary
|
||||
|
||||
Serialized Dictionary is designed to feel native to the Unity Editor while providing some additional functionality to speed up frequent workflows.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Use the class `SerializedDictionary<,>` in the Namespace `AYellowpaper.SerializedCollections` instead of the `Dictionary<,>` class to serialize your data. Use the `SerializedDictionary` Attribute for further customization. It follows the same Unity serialization rules as other Unity types.
|
||||
|
||||
```csharp
|
||||
[SerializedDictionary("Damage Type", "Description")]
|
||||
public SerializedDictionary<DamageType, string> ElementDescriptions;
|
||||
```
|
||||
|
||||
## User Guide
|
||||
|
||||
Serialized Dictionary will serialized any Unity serializable type, including Unity Objects like transforms and ScriptableObjects. Furthermore, it allows to serialize duplicate keys and null values. The main purpose is to avoid accidental loss of data when you decide to change code or remove objects. The following color coding exists:
|
||||
|
||||
- **Red**: The key is invalid, meaning either duplicate or null
|
||||
- **Yellow**: There are duplicate keys, but this is the one that's used (it comes before others)
|
||||
- **Blue**: The key was found in the search
|
||||
|
||||
The Burger Menu in the top right is very important. It contains important options that will speed up your workflow. Most of the should be self explanatory.
|
||||
|
||||

|
||||
|
||||
## Bulk Edit Operations
|
||||
|
||||
To quickly modify lots of existing entries you can use and also create custom `KeyListGenerators`. E.g. for dictionaries that contain enums as keys, there’s a `KeyListGenerator` that will populate the dictionary with all values from the enum with one press of a button.
|
||||
|
||||
1. Select "Populate Enum" with the dictionary that has enum as key
|
||||
|
||||

|
||||
|
||||
2. The dictionary is filled with all values from the enum
|
||||
|
||||

|
||||
|
||||
Furthermore, there are populators for integers, which allow for custom input fields to modify the data that will be generated.
|
||||
|
||||

|
||||
|
||||
n this case, Int Range will create keys between the range of 1 to 10. Before you Apply the generated values, you have the option to select between Add, Remove and Confine. They do the following:
|
||||
|
||||
- Add will add the values if they don’t exist as keys yet
|
||||
- Remove will remove the given values
|
||||
- Confine will add the values if they don’t exist as keys yet, and remove all keys that are not contained in the list of generated values
|
||||
|
||||
As as example, assume you have keys 5 to 15 in your dictionary, and have chosen 1 to 10 in the generator. Given the following options, the resulting keys will be as follows:
|
||||
|
||||
- Add will result in keys from 1 to 15, because 1 to 4 will be added
|
||||
- Remove will result in keys 11 to 15, because 5 to 10 will be removed
|
||||
- Confine will result in 1 to 10, because 1 to 4 will be added and 11 to 15 removed
|
||||
|
||||
## Creating Bulk Edit Operations
|
||||
|
||||
Some KeyListGenerators exist for enums and ints. But you might want to add your own custom Key Generators. This is easily done by creating a new class that inherits from `KeyListGenerator` and adding the `KeyListGenerator` Attribute to it. See below for the int generator example:
|
||||
|
||||
```csharp
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AYellowpaper.SerializedCollections.KeysGenerators
|
||||
{
|
||||
[KeyListGenerator("Int Range", typeof(int))]
|
||||
public class IntRangeGenerator : KeyListGenerator
|
||||
{
|
||||
[SerializeField]
|
||||
private int _startValue = 1;
|
||||
[SerializeField]
|
||||
private int _endValue = 10;
|
||||
|
||||
public override IEnumerable GetKeys(Type type)
|
||||
{
|
||||
int dir = Math.Sign(_endValue - _startValue);
|
||||
dir = dir == 0 ? 1 : dir;
|
||||
for (int i = _startValue; i != _endValue; i += dir)
|
||||
yield return i;
|
||||
yield return _endValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
7
Packages/SerializedDictionary-main/README.md.meta
Normal file
7
Packages/SerializedDictionary-main/README.md.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7adbf5c96b922b459b77fe23d729801
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Packages/SerializedDictionary-main/Readme.pdf
Normal file
BIN
Packages/SerializedDictionary-main/Readme.pdf
Normal file
Binary file not shown.
7
Packages/SerializedDictionary-main/Readme.pdf.meta
Normal file
7
Packages/SerializedDictionary-main/Readme.pdf.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d3a2360c7e15944cbf26d622f2de997
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user