From 9e6e3ccdee8e03ba12243d9298b76d52af37ffc7 Mon Sep 17 00:00:00 2001 From: rowan Date: Wed, 6 Aug 2025 12:51:11 -0400 Subject: [PATCH] recycle view --- Assets/Canto URP.asset | 2 +- Assets/Resources/Glock17.fbx | Bin 0 -> 73852 bytes Assets/Resources/Glock17.fbx.meta | 107 ++++ Assets/Resources/Main.glb | Bin 0 -> 115440 bytes Assets/Resources/Main.glb.meta | 7 + Assets/SOAP/Items/DebugKey.asset | 2 +- Assets/SOAP/Items/TestInventory.asset | 4 +- Assets/Scenes/RecycleView.unity | 406 ++++++++++++++ Assets/Scenes/RecycleView.unity.meta | 7 + Assets/Scenes/SampleScene.unity | 4 +- Assets/Scenes/UI.unity | 518 ++++++++++++++++++ Assets/Scenes/UI.unity.meta | 7 + .../ConditionalDisplayPropertyDrawer.cs | 140 ++++- Assets/Scripts/Extension/Collection.cs | 41 ++ Assets/Scripts/Interaction/Interactor.cs | 18 +- .../System/Attributes/HideIfAttribute.cs | 19 + .../System/Attributes/HideIfAttribute.cs.meta | 2 + Assets/Scripts/System/Collections.meta | 8 + .../System/Collections/BiDictionary.cs | 140 +++++ .../System/Collections/BiDictionary.cs.meta | 2 + .../Scripts/System/Collections/CycleList.cs | 140 +++++ .../System/Collections/CycleList.cs.meta | 2 + Assets/Scripts/System/IsExternalInit.cs | 6 + Assets/Scripts/System/IsExternalInit.cs.meta | 2 + Assets/Scripts/UI/Elements/Layout.meta | 8 + .../UI/Elements/Layout/DynamicLayout.cs | 176 ++++++ .../UI/Elements/Layout/DynamicLayout.cs.meta | 2 + .../Scripts/UI/Elements/Layout/FixedLayout.cs | 38 ++ .../UI/Elements/Layout/FixedLayout.cs.meta | 2 + Assets/Scripts/UI/Elements/Layout/ILayout.cs | 14 + .../UI/Elements/Layout/ILayout.cs.meta | 2 + Assets/Scripts/UI/Elements/RecycleView.meta | 8 + .../RecycleView/ICollectionDataSource.cs | 13 + .../RecycleView/ICollectionDataSource.cs.meta | 2 + .../RecycleView/IDragAndDropController.cs | 4 + .../IDragAndDropController.cs.meta | 2 + .../RecycleView/IVirtualizationController.cs | 14 + .../IVirtualizationController.cs.meta | 2 + .../UI/Elements/RecycleView/RecycleView.cs | 203 +++++++ .../Elements/RecycleView/RecycleView.cs.meta | 2 + .../RecycleVirtualizationController.cs | 380 +++++++++++++ .../RecycleVirtualizationController.cs.meta | 2 + Assets/Scripts/UI/TestRecycleView.cs | 57 ++ Assets/Scripts/UI/TestRecycleView.cs.meta | 2 + Assets/Settings/DefaultVolumeProfile.asset | 2 +- Assets/UI Toolkit/PanelSettings.asset | 8 +- .../UnityThemes/CantoComponents.uss | 21 + .../UnityThemes/CantoComponents.uss.meta | 11 + .../UnityThemes/CantoRuntimeTheme.tss | 4 + .../UnityThemes/CantoRuntimeTheme.tss.meta | 11 + .../UnityThemes/UnityDefaultRuntimeTheme.tss | 4 +- Assets/UI/HorizontalList.uxml | 2 + Assets/UI/HorizontalList.uxml.meta | 10 + Assets/UI/Inventory.uxml | 54 +- Assets/UI/Item Preview.renderTexture | 39 ++ Assets/UI/Item Preview.renderTexture.meta | 8 + Assets/UI/ItemSlot.uxml | 20 + Assets/UI/ItemSlot.uxml.meta | 10 + Assets/UI/Test.meta | 8 + Assets/UI/Test/ProfileView.cs | 30 + Assets/UI/Test/ProfileView.cs.meta | 2 + Assets/UI/Test/Resources.meta | 8 + Assets/UI/Test/Resources/UserProfileItem.uxml | 6 + .../Test/Resources/UserProfileItem.uxml.meta | 10 + Assets/UI/Test/Resources/UserProfileList.uxml | 3 + .../Test/Resources/UserProfileList.uxml.meta | 10 + Assets/UI/Test/UserProfile.cs | 74 +++ Assets/UI/Test/UserProfile.cs.meta | 2 + .../UI/Test/UserProfileItemVisualElement.cs | 33 ++ .../Test/UserProfileItemVisualElement.cs.meta | 2 + Assets/UI/inventory.uss | 65 +++ Assets/UI/inventory.uss.meta | 11 + Assets/UI/itemslot.uss | 3 + Assets/UI/itemslot.uss.meta | 11 + ProjectSettings/QualitySettings.asset | 2 +- ProjectSettings/TagManager.asset | 2 +- 76 files changed, 2963 insertions(+), 40 deletions(-) create mode 100644 Assets/Resources/Glock17.fbx create mode 100644 Assets/Resources/Glock17.fbx.meta create mode 100644 Assets/Resources/Main.glb create mode 100644 Assets/Resources/Main.glb.meta create mode 100644 Assets/Scenes/RecycleView.unity create mode 100644 Assets/Scenes/RecycleView.unity.meta create mode 100644 Assets/Scenes/UI.unity create mode 100644 Assets/Scenes/UI.unity.meta create mode 100644 Assets/Scripts/System/Attributes/HideIfAttribute.cs create mode 100644 Assets/Scripts/System/Attributes/HideIfAttribute.cs.meta create mode 100644 Assets/Scripts/System/Collections.meta create mode 100644 Assets/Scripts/System/Collections/BiDictionary.cs create mode 100644 Assets/Scripts/System/Collections/BiDictionary.cs.meta create mode 100644 Assets/Scripts/System/Collections/CycleList.cs create mode 100644 Assets/Scripts/System/Collections/CycleList.cs.meta create mode 100644 Assets/Scripts/System/IsExternalInit.cs create mode 100644 Assets/Scripts/System/IsExternalInit.cs.meta create mode 100644 Assets/Scripts/UI/Elements/Layout.meta create mode 100644 Assets/Scripts/UI/Elements/Layout/DynamicLayout.cs create mode 100644 Assets/Scripts/UI/Elements/Layout/DynamicLayout.cs.meta create mode 100644 Assets/Scripts/UI/Elements/Layout/FixedLayout.cs create mode 100644 Assets/Scripts/UI/Elements/Layout/FixedLayout.cs.meta create mode 100644 Assets/Scripts/UI/Elements/Layout/ILayout.cs create mode 100644 Assets/Scripts/UI/Elements/Layout/ILayout.cs.meta create mode 100644 Assets/Scripts/UI/Elements/RecycleView.meta create mode 100644 Assets/Scripts/UI/Elements/RecycleView/ICollectionDataSource.cs create mode 100644 Assets/Scripts/UI/Elements/RecycleView/ICollectionDataSource.cs.meta create mode 100644 Assets/Scripts/UI/Elements/RecycleView/IDragAndDropController.cs create mode 100644 Assets/Scripts/UI/Elements/RecycleView/IDragAndDropController.cs.meta create mode 100644 Assets/Scripts/UI/Elements/RecycleView/IVirtualizationController.cs create mode 100644 Assets/Scripts/UI/Elements/RecycleView/IVirtualizationController.cs.meta create mode 100644 Assets/Scripts/UI/Elements/RecycleView/RecycleView.cs create mode 100644 Assets/Scripts/UI/Elements/RecycleView/RecycleView.cs.meta create mode 100644 Assets/Scripts/UI/Elements/RecycleView/RecycleVirtualizationController.cs create mode 100644 Assets/Scripts/UI/Elements/RecycleView/RecycleVirtualizationController.cs.meta create mode 100644 Assets/Scripts/UI/TestRecycleView.cs create mode 100644 Assets/Scripts/UI/TestRecycleView.cs.meta create mode 100644 Assets/UI Toolkit/UnityThemes/CantoComponents.uss create mode 100644 Assets/UI Toolkit/UnityThemes/CantoComponents.uss.meta create mode 100644 Assets/UI Toolkit/UnityThemes/CantoRuntimeTheme.tss create mode 100644 Assets/UI Toolkit/UnityThemes/CantoRuntimeTheme.tss.meta create mode 100644 Assets/UI/HorizontalList.uxml create mode 100644 Assets/UI/HorizontalList.uxml.meta create mode 100644 Assets/UI/Item Preview.renderTexture create mode 100644 Assets/UI/Item Preview.renderTexture.meta create mode 100644 Assets/UI/ItemSlot.uxml create mode 100644 Assets/UI/ItemSlot.uxml.meta create mode 100644 Assets/UI/Test.meta create mode 100644 Assets/UI/Test/ProfileView.cs create mode 100644 Assets/UI/Test/ProfileView.cs.meta create mode 100644 Assets/UI/Test/Resources.meta create mode 100644 Assets/UI/Test/Resources/UserProfileItem.uxml create mode 100644 Assets/UI/Test/Resources/UserProfileItem.uxml.meta create mode 100644 Assets/UI/Test/Resources/UserProfileList.uxml create mode 100644 Assets/UI/Test/Resources/UserProfileList.uxml.meta create mode 100644 Assets/UI/Test/UserProfile.cs create mode 100644 Assets/UI/Test/UserProfile.cs.meta create mode 100644 Assets/UI/Test/UserProfileItemVisualElement.cs create mode 100644 Assets/UI/Test/UserProfileItemVisualElement.cs.meta create mode 100644 Assets/UI/inventory.uss create mode 100644 Assets/UI/inventory.uss.meta create mode 100644 Assets/UI/itemslot.uss create mode 100644 Assets/UI/itemslot.uss.meta diff --git a/Assets/Canto URP.asset b/Assets/Canto URP.asset index 9645d3f..0169bb9 100644 --- a/Assets/Canto URP.asset +++ b/Assets/Canto URP.asset @@ -25,7 +25,7 @@ MonoBehaviour: m_SupportsTerrainHoles: 1 m_SupportsHDR: 1 m_HDRColorBufferPrecision: 0 - m_MSAA: 1 + m_MSAA: 2 m_RenderScale: 1 m_UpscalingFilter: 0 m_FsrOverrideSharpness: 0 diff --git a/Assets/Resources/Glock17.fbx b/Assets/Resources/Glock17.fbx new file mode 100644 index 0000000000000000000000000000000000000000..11d5008652405fe5008eef1a2194e353551b76e7 GIT binary patch literal 73852 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∓p&!f{uPBlUyy)#LX|UyG0#w!PoT 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 literal 0 HcmV?d00001 diff --git a/Assets/Resources/Glock17.fbx.meta b/Assets/Resources/Glock17.fbx.meta new file mode 100644 index 0000000..f4ec38d --- /dev/null +++ b/Assets/Resources/Glock17.fbx.meta @@ -0,0 +1,107 @@ +fileFormatVersion: 2 +guid: bf9d862a19647f28795df2e666425003 +ModelImporter: + serializedVersion: 22200 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 0 + motionNodeName: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importPhysicalCameras: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + strictVertexDataChecks: 0 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + importBlendShapeDeformPercent: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Main.glb b/Assets/Resources/Main.glb new file mode 100644 index 0000000000000000000000000000000000000000..0bfa787d782fd8a4a7188abd015e23b5b17950d7 GIT binary patch literal 115440 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 H-% -1) { - properties[i] = serializedObject.FindProperty(names[i]); + var parentPath = path[..path.LastIndexOf('.')]; + var parent = obj.FindProperty(parentPath); + for (int i = 0; i < len; i++) + { + properties[i] = parent.FindPropertyRelative(propertyNames[i]); + } + } + else + { + for (int i = 0; i < len; i++) + { + properties[i] = obj.FindProperty(propertyNames[i]); + } } - return new BoolConditionPropertyField(properties, attribute, property); + return properties; } public abstract class ConditionalPropertyField : PropertyField @@ -57,13 +76,13 @@ public class ConditionalDisplayPropertyDrawer : PropertyDrawer protected abstract void OnTrackedValueChanged(SerializedProperty property); } - public class BoolConditionPropertyField : ConditionalPropertyField + public class SimpleConditionPropertyField : ConditionalPropertyField { - public BoolConditionPropertyField(SerializedProperty[] properties, ConditionalDisplayAttribute attribute, SerializedProperty property) : base(properties, attribute, property) + public SimpleConditionPropertyField(SerializedProperty[] properties, ConditionalDisplayAttribute attribute, SerializedProperty property) : base(properties, attribute, property) { } - public BoolConditionPropertyField(SerializedProperty[] properties, ConditionalDisplayAttribute attribute, SerializedProperty property, string label) : base(properties, attribute, property, label) + public SimpleConditionPropertyField(SerializedProperty[] properties, ConditionalDisplayAttribute attribute, SerializedProperty property, string label) : base(properties, attribute, property, label) { } @@ -76,16 +95,105 @@ public class ConditionalDisplayPropertyDrawer : PropertyDrawer _ => false }; - for (int i = 0; i < properties.Length; i++) + var display = attribute.LogicalOperator switch { - if (properties[i].boolValue == value) + LogicalOperator.And => All(properties, attribute.Value, attribute.ComparisonOperator), + LogicalOperator.Or => Any(properties, attribute.Value, attribute.ComparisonOperator), + }; + + DisplayElement(display); + } + + protected bool Compare(T self, T other, ComparisonOperator op) where T : IComparable + { + var value = self.CompareTo(other); + + return op switch + { + ComparisonOperator.Less => value < 0, + ComparisonOperator.Equal => value == 0, + ComparisonOperator.LessEqual => value <= 0, + ComparisonOperator.Greater => value > 0, + ComparisonOperator.NotEqual => value != 0, + ComparisonOperator.GreaterEqual => value >= 0, + _ => throw new NotImplementedException(), + }; + } + + protected bool Compare(T self, object other, ComparisonOperator op) where T : IComparable + { + return other is T otherValue && Compare(self, otherValue, op); + } + + protected bool Compare(SerializedProperty self, object other, ComparisonOperator op) + { + return self.propertyType switch + { + SerializedPropertyType.Generic => false, + SerializedPropertyType.Float or SerializedPropertyType.Integer => self.numericType switch { - DisplayElement(value); - return; + SerializedPropertyNumericType.Unknown => false, + SerializedPropertyNumericType.UInt8 or SerializedPropertyNumericType.UInt16 or SerializedPropertyNumericType.UInt32 => Compare(self.uintValue, other, op), + SerializedPropertyNumericType.Int8 or SerializedPropertyNumericType.Int16 or SerializedPropertyNumericType.Int32 => Compare(self.intValue, other, op), + SerializedPropertyNumericType.Int64 => Compare(self.longValue, other, op), + SerializedPropertyNumericType.UInt64 => Compare(self.ulongValue, other, op), + SerializedPropertyNumericType.Float => Compare(self.floatValue, other, op), + SerializedPropertyNumericType.Double => Compare(self.doubleValue, other, op), + _ => false, + }, + SerializedPropertyType.Boolean => Compare(self.boolValue, other, op), + SerializedPropertyType.String => Compare(self.stringValue, other, op), + // SerializedPropertyType.Color => Compare(self.colorValue, other, op), + SerializedPropertyType.ObjectReference => false, + SerializedPropertyType.LayerMask => Compare(self.intValue, other, op), + SerializedPropertyType.Enum => Compare(self.intValue, other, op), + // SerializedPropertyType.Vector2 => Compare(self.vector2Value, other, op), + // SerializedPropertyType.Vector3 => Compare(self.vector3Value, other, op), + // SerializedPropertyType.Vector4 => Compare(self.vector4Value, other, op), + // SerializedPropertyType.Rect => Compare(self.rectValue, other, op), + SerializedPropertyType.ArraySize => Compare(self.arraySize, other, op), + SerializedPropertyType.Character => Compare(self.stringValue, other, op), + // SerializedPropertyType.AnimationCurve => Compare(self.animationCurveValue, other, op), + // SerializedPropertyType.Bounds => Compare(self.boundsValue, other, op), + // SerializedPropertyType.Gradient => Compare(self.gradientValue, other, op), + // SerializedPropertyType.Quaternion => Compare(self.quaternionValue, other, op), + SerializedPropertyType.ExposedReference => false, + // SerializedPropertyType.FixedBufferSize => Compare(self.fixedBufferSize, other, op), + // SerializedPropertyType.Vector2Int => Compare(self.vector2IntValue, other, op), + // SerializedPropertyType.Vector3Int => Compare(self.vector3IntValue, other, op), + // SerializedPropertyType.RectInt => Compare(self.rectIntValue, other, op), + // SerializedPropertyType.BoundsInt => Compare(self.boundsIntValue, other, op), + SerializedPropertyType.ManagedReference => false, + SerializedPropertyType.Hash128 => Compare(self.hash128Value, other, op), + SerializedPropertyType.RenderingLayerMask => Compare(self.intValue, other, op), + _ => false, + }; + } + + protected bool All(SerializedProperty[] properties, object value, ComparisonOperator op) + { + foreach (var prop in properties) + { + if (!Compare(prop, value, op)) + { + return false; } } - DisplayElement(!value); + return true; + } + + protected bool Any(SerializedProperty[] properties, object value, ComparisonOperator op) + { + foreach (var prop in properties) + { + if (Compare(prop, value, op)) + { + return true; + } + } + + return false; } private void DisplayElement(bool displayed) diff --git a/Assets/Scripts/Extension/Collection.cs b/Assets/Scripts/Extension/Collection.cs index d3f5eb9..aca2d91 100644 --- a/Assets/Scripts/Extension/Collection.cs +++ b/Assets/Scripts/Extension/Collection.cs @@ -1,6 +1,47 @@ +using System; + namespace KitsuneCafe.Extension { public static class CollectionExtension { + public static bool IsTypeOf() + { + return IsTypeOf(typeof(T), typeof(U)); + } + + public static bool IsTypeOf(this object value) + { + return IsTypeOf(value.GetType(), typeof(T)); + } + + public static bool IsTypeOf(this object value, Type type) + { + return IsTypeOf(value.GetType(), type); + } + + public static bool IsTypeOf(this Type type) + { + if (type == null) { return false; } + + return IsTypeOf(type, typeof(T)); + } + + public static bool IsTypeOf(this Type type, Type other) + { + if (type == null || other == null || !other.IsGenericTypeDefinition) + { + return false; + } + + return other.IsGenericType && other.GetGenericTypeDefinition() == type; + } + + public static Type GetGenericArgument(this object value) + { + if (value == null) { return null; } + var type = value.GetType(); + var args = type.GetGenericArguments(); + return args.Length > 0 ? args[0] : null; + } } } diff --git a/Assets/Scripts/Interaction/Interactor.cs b/Assets/Scripts/Interaction/Interactor.cs index 7ab1f0f..239a712 100644 --- a/Assets/Scripts/Interaction/Interactor.cs +++ b/Assets/Scripts/Interaction/Interactor.cs @@ -1,13 +1,11 @@ -using UnityEngine; using System.Linq; - +using KitsuneCafe.Extension; +using KitsuneCafe.Interaction; +using KitsuneCafe.SOAP; +using ObservableCollections; using R3; using R3.Triggers; -using ObservableCollections; - -using KitsuneCafe.Interaction; -using KitsuneCafe.Extension; -using KitsuneCafe.SOAP; +using UnityEngine; namespace KitsuneCafe.Player { @@ -26,8 +24,8 @@ namespace KitsuneCafe.Player [SerializeField] private ReactiveEvent interactSource; - [SerializeField] - private int updateFrequency = 10; + // [SerializeField] + // private int updateFrequency = 10; [SerializeField, Tooltip("How far an object must move before being considered")] private float minimumChangeDelta = 0.1f; @@ -147,4 +145,4 @@ namespace KitsuneCafe.Player return current; } } -} \ No newline at end of file +} diff --git a/Assets/Scripts/System/Attributes/HideIfAttribute.cs b/Assets/Scripts/System/Attributes/HideIfAttribute.cs new file mode 100644 index 0000000..fe60d65 --- /dev/null +++ b/Assets/Scripts/System/Attributes/HideIfAttribute.cs @@ -0,0 +1,19 @@ +using System; + +namespace KitsuneCafe.System.Attributes +{ + public class HideIfAttribute : ConditionalDisplayAttribute + { + public HideIfAttribute(string property) : this(property, false) + { + } + + public HideIfAttribute(string property, object value) : base(ComparisonOperator.Equal, value, property) + { + } + + public HideIfAttribute(LogicalOperator logicalOp, params string[] properties) : base(logicalOp, ComparisonOperator.Equal, false, properties) + { + } + } +} diff --git a/Assets/Scripts/System/Attributes/HideIfAttribute.cs.meta b/Assets/Scripts/System/Attributes/HideIfAttribute.cs.meta new file mode 100644 index 0000000..4a70919 --- /dev/null +++ b/Assets/Scripts/System/Attributes/HideIfAttribute.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cbcedbac951b59685ac98946b7c71e51 \ No newline at end of file diff --git a/Assets/Scripts/System/Collections.meta b/Assets/Scripts/System/Collections.meta new file mode 100644 index 0000000..bcbcfb8 --- /dev/null +++ b/Assets/Scripts/System/Collections.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: af2a2151c7ac49dfaabbabac6f556d37 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/System/Collections/BiDictionary.cs b/Assets/Scripts/System/Collections/BiDictionary.cs new file mode 100644 index 0000000..5a2750e --- /dev/null +++ b/Assets/Scripts/System/Collections/BiDictionary.cs @@ -0,0 +1,140 @@ +using System.Collections; +using System.Collections.Generic; + +namespace KitsuneCafe.System.Collections +{ + public class BiDictionary + : IDictionary.Left, BiDictionary.Right>, + IDictionary.Right, BiDictionary.Left> + { + public record Left(TKey Value) + { + public static implicit operator Left(TKey key) => new(key); + public static implicit operator TKey(Left left) => left.Value; + } + + public record Right(TValue Value) + { + public static implicit operator Right(TValue value) => new(value); + public static implicit operator TValue(Right right) => right.Value; + } + + private readonly Dictionary forward = new(); + private readonly Dictionary reverse = new(); + + public ICollection Keys => ((IDictionary)forward).Keys; + + public ICollection Values => ((IDictionary)forward).Values; + + public int Count => ((ICollection>)forward).Count; + + public bool IsReadOnly => ((ICollection>)forward).IsReadOnly; + + ICollection IDictionary.Keys => ((IDictionary)reverse).Keys; + + ICollection IDictionary.Values => ((IDictionary)reverse).Values; + + public Left this[Right key] { get => ((IDictionary)reverse)[key]; set => ((IDictionary)reverse)[key] = value; } + public Right this[Left key] { get => ((IDictionary)forward)[key]; set => ((IDictionary)forward)[key] = value; } + + public void Add(Left key, Right value) + { + ((IDictionary)forward).Add(key, value); + } + + public bool ContainsKey(Left key) + { + return ((IDictionary)forward).ContainsKey(key); + } + + public bool Remove(Left key) + { + return ((IDictionary)forward).Remove(key); + } + + public bool TryGetValue(Left key, out Right value) + { + return ((IDictionary)forward).TryGetValue(key, out value); + } + + public void Add(KeyValuePair item) + { + ((ICollection>)forward).Add(item); + } + + public void Clear() + { + ((ICollection>)forward).Clear(); + } + + public bool Contains(KeyValuePair item) + { + return ((ICollection>)forward).Contains(item); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + ((ICollection>)forward).CopyTo(array, arrayIndex); + } + + public bool Remove(KeyValuePair item) + { + return ((ICollection>)forward).Remove(item); + } + + public IEnumerator> GetEnumerator() + { + return ((IEnumerable>)forward).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)forward).GetEnumerator(); + } + + public void Add(Right key, Left value) + { + ((IDictionary)reverse).Add(key, value); + } + + public bool ContainsKey(Right key) + { + return ((IDictionary)reverse).ContainsKey(key); + } + + public bool Remove(Right key) + { + return ((IDictionary)reverse).Remove(key); + } + + public bool TryGetValue(Right key, out Left value) + { + return ((IDictionary)reverse).TryGetValue(key, out value); + } + + public void Add(KeyValuePair item) + { + ((ICollection>)reverse).Add(item); + } + + public bool Contains(KeyValuePair item) + { + return ((ICollection>)reverse).Contains(item); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + ((ICollection>)reverse).CopyTo(array, arrayIndex); + } + + public bool Remove(KeyValuePair item) + { + return ((ICollection>)reverse).Remove(item); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return ((IEnumerable>)reverse).GetEnumerator(); + } + } +} diff --git a/Assets/Scripts/System/Collections/BiDictionary.cs.meta b/Assets/Scripts/System/Collections/BiDictionary.cs.meta new file mode 100644 index 0000000..b858728 --- /dev/null +++ b/Assets/Scripts/System/Collections/BiDictionary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ee096968879dadffa8fd3597a0ec0b12 \ No newline at end of file diff --git a/Assets/Scripts/System/Collections/CycleList.cs b/Assets/Scripts/System/Collections/CycleList.cs new file mode 100644 index 0000000..055ec48 --- /dev/null +++ b/Assets/Scripts/System/Collections/CycleList.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace KitsuneCafe.System.Collections +{ + public class CycleList : IList, IList + { + private readonly List source; + + public CycleList(IList source) + { + this.source = source.ToList(); + } + + + public CycleList() : this(new List()) { } + + public T this[int index] { get => Get(index); set => Set(index, value); } + + object IList.this[int index] + { + get => ((IList)source)[Index(index)]; + set => ((IList)source)[Index(index)] = value; + } + + public int Count => 375_000; + + private int Index(int index) + { + if (source.Count == 0) + { + return -1; + } + + return index % source.Count; + } + + private T Get(int index) + { + return source.Count == 0 ? default : source[Index(index)]; + } + + private void Set(int index, T value) + { + source[Index(index)] = value; + } + + public int IndexOf(T item) + { + return ((IList)source).IndexOf(item); + } + + public void Insert(int index, T item) + { + ((IList)source).Insert(index, item); + } + + public void RemoveAt(int index) + { + ((IList)source).RemoveAt(index); + } + + public void Add(T item) + { + ((ICollection)source).Add(item); + } + + public void Clear() + { + ((ICollection)source).Clear(); + } + + public bool Contains(T item) + { + return ((ICollection)source).Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + ((ICollection)source).CopyTo(array, arrayIndex); + } + + public bool Remove(T item) + { + return ((ICollection)source).Remove(item); + } + + public IEnumerator GetEnumerator() + { + return ((IEnumerable)source).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)source).GetEnumerator(); + } + + public int Add(object value) + { + return ((IList)source).Add(value); + } + + public bool Contains(object value) + { + return ((IList)source).Contains(value); + } + + public int IndexOf(object value) + { + return ((IList)source).IndexOf(value); + } + + public void Insert(int index, object value) + { + ((IList)source).Insert(index, value); + } + + public void Remove(object value) + { + ((IList)source).Remove(value); + } + + public void CopyTo(Array array, int index) + { + ((ICollection)source).CopyTo(array, index); + } + + + public bool IsReadOnly => ((ICollection)source).IsReadOnly; + + public bool IsFixedSize => ((IList)source).IsFixedSize; + + public bool IsSynchronized => ((ICollection)source).IsSynchronized; + + public object SyncRoot => ((ICollection)source).SyncRoot; + + } +} diff --git a/Assets/Scripts/System/Collections/CycleList.cs.meta b/Assets/Scripts/System/Collections/CycleList.cs.meta new file mode 100644 index 0000000..08c55b6 --- /dev/null +++ b/Assets/Scripts/System/Collections/CycleList.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 254c0563f8601e998a3d4eacff1833c6 \ No newline at end of file diff --git a/Assets/Scripts/System/IsExternalInit.cs b/Assets/Scripts/System/IsExternalInit.cs new file mode 100644 index 0000000..d72b9df --- /dev/null +++ b/Assets/Scripts/System/IsExternalInit.cs @@ -0,0 +1,6 @@ +using System.ComponentModel; +namespace System.Runtime.CompilerServices +{ + [EditorBrowsable(EditorBrowsableState.Never)] + internal class IsExternalInit { } +} diff --git a/Assets/Scripts/System/IsExternalInit.cs.meta b/Assets/Scripts/System/IsExternalInit.cs.meta new file mode 100644 index 0000000..1593eac --- /dev/null +++ b/Assets/Scripts/System/IsExternalInit.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ea4ec4bcaf729ed14ba315e9a9923ceb \ No newline at end of file diff --git a/Assets/Scripts/UI/Elements/Layout.meta b/Assets/Scripts/UI/Elements/Layout.meta new file mode 100644 index 0000000..1476596 --- /dev/null +++ b/Assets/Scripts/UI/Elements/Layout.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 12d6aff0f2ce160ac8660ee5c8c47b71 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/UI/Elements/Layout/DynamicLayout.cs b/Assets/Scripts/UI/Elements/Layout/DynamicLayout.cs new file mode 100644 index 0000000..86f384e --- /dev/null +++ b/Assets/Scripts/UI/Elements/Layout/DynamicLayout.cs @@ -0,0 +1,176 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UIElements; + +namespace KitsuneCafe.UI +{ + public record LayoutItem(float Position, float Size) + { + public float Min => Position; + public float Max => Position + Size; + } + + public class DynamicLayout : ILayout, IEnumerable + { + + public struct LayoutEnumerator : IEnumerator + { + public readonly int Start; + public int Index; + private readonly DynamicLayout layout; + + public LayoutEnumerator(int index, DynamicLayout layout) + { + Start = index; + Index = index; + this.layout = layout; + } + + public LayoutEnumerator(DynamicLayout layout) : this(0, layout) { } + + public readonly LayoutItem Current => new( + layout.positions[Index - 1], + layout.sizes[Index - 1] + ); + + readonly object IEnumerator.Current => Current; + + public readonly void Dispose() { } + + public bool MoveNext() + { + Index += 1; + return Index < layout.positions.Count; + } + + public void Reset() + { + Index = Start; + } + } + + public float DefaultItemSize { get; set; } + public float GutterSize { get; set; } + public FlowDirection Direction { get; set; } + public float ContentSize { get; private set; } + + private readonly List positions = new(); + private readonly List sizes = new(); + + public DynamicLayout(FlowDirection direction, float defaultItemSize = 22, float gutterSize = 0) + { + Direction = direction; + GutterSize = gutterSize; + DefaultItemSize = defaultItemSize; + } + + public float GetItemPosition(int index) + { + if (index > 0) + { + return GetItemPosition(index - 1) + GetItemSize(index - 1) + GutterSize; + } + + return 0; + } + + public float GetItemSize(int index) + { + if (index >= 0 && index < sizes.Count) + { + return sizes[index]; + } + + return DefaultItemSize; + } + + private float LastPositionOrDefault() + { + return positions.Count > 0 ? positions[^1] : DefaultItemSize + GutterSize; + } + + public void Update(int itemCount, VisualElement container) + { + while (positions.Count < itemCount) + { + var last = LastPositionOrDefault(); + positions.Add(last + DefaultItemSize + GutterSize); + sizes.Add(DefaultItemSize); + } + + if (positions.Count > itemCount) + { + positions.RemoveRange(itemCount, positions.Count - itemCount); + sizes.RemoveRange(itemCount, sizes.Count - itemCount); + } + + ContentSize = LastPositionOrDefault(); + } + + private float CalculatePositions(int startingIndex = 0, float initialPosition = 0) + { + var position = initialPosition; + + for (int i = startingIndex; i < positions.Count; i++) + { + positions[i] = position; + position += GetItemSize(i) + GutterSize; + } + + return ContentSize = position; + } + + public void SetMeasuredItemSize(int index, float size) + { + if (index < sizes.Count && Mathf.Approximately(sizes[index], size)) + { + return; + } + + sizes[index] = size; + + var position = index > 0 ? positions[index - 1] + sizes[index - 1] + GutterSize : 0; + CalculatePositions(index, position); + } + + public int GetFirstVisibleIndex(float scrollOffset) + { + if (scrollOffset <= 0) { return 0; } + + for (int i = 0; i < positions.Count; i++) + { + if (positions[i] >= scrollOffset) + { + return i; + } + } + + return positions.Count - 1; + } + + public IEnumerable Enumerate(int startIndex = 0) + { + var len = positions.Count; + for (int i = startIndex; i < len; i++) + { + yield return new LayoutItem(positions[i], sizes[i]); + } + } + + public IEnumerator GetEnumerator() + { + return new LayoutEnumerator(this); + } + + public IEnumerator GetEnumerator(int startIndex) + { + return new LayoutEnumerator(startIndex, this); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/Assets/Scripts/UI/Elements/Layout/DynamicLayout.cs.meta b/Assets/Scripts/UI/Elements/Layout/DynamicLayout.cs.meta new file mode 100644 index 0000000..577cc50 --- /dev/null +++ b/Assets/Scripts/UI/Elements/Layout/DynamicLayout.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e38b8fbcaf537546ab9ecd9312112a49 \ No newline at end of file diff --git a/Assets/Scripts/UI/Elements/Layout/FixedLayout.cs b/Assets/Scripts/UI/Elements/Layout/FixedLayout.cs new file mode 100644 index 0000000..a62309f --- /dev/null +++ b/Assets/Scripts/UI/Elements/Layout/FixedLayout.cs @@ -0,0 +1,38 @@ +using UnityEngine.UIElements; + +namespace KitsuneCafe.UI +{ + public class FixedLayout : ILayout + { + public FlowDirection Direction { get; set; } + public float ContentSize { get; private set; } + + + public float ItemSize { get; set; } + public float GutterSize { get; set; } + + public FixedLayout(FlowDirection direction, float itemSize, float gutterSize) + { + Direction = direction; + ItemSize = itemSize; + GutterSize = gutterSize; + } + + public FixedLayout(FlowDirection direction, float itemSize) : this(direction, itemSize, 0) { } + + public float GetItemPosition(int index) + { + return index * (ItemSize + GutterSize); + } + + public float GetItemSize(int _index) + { + return ItemSize; + } + + public void Update(int itemCount, VisualElement _container) + { + ContentSize = itemCount * (ItemSize + GutterSize); + } + } +} diff --git a/Assets/Scripts/UI/Elements/Layout/FixedLayout.cs.meta b/Assets/Scripts/UI/Elements/Layout/FixedLayout.cs.meta new file mode 100644 index 0000000..90326b1 --- /dev/null +++ b/Assets/Scripts/UI/Elements/Layout/FixedLayout.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 59a6a1d658db51ba5acf7f0235f34571 \ No newline at end of file diff --git a/Assets/Scripts/UI/Elements/Layout/ILayout.cs b/Assets/Scripts/UI/Elements/Layout/ILayout.cs new file mode 100644 index 0000000..eae001f --- /dev/null +++ b/Assets/Scripts/UI/Elements/Layout/ILayout.cs @@ -0,0 +1,14 @@ +using UnityEngine.UIElements; + +namespace KitsuneCafe.UI +{ + public interface ILayout + { + FlowDirection Direction { get; } + float ContentSize { get; } + + float GetItemPosition(int index); + float GetItemSize(int index); + void Update(int itemCount, VisualElement container); + } +} diff --git a/Assets/Scripts/UI/Elements/Layout/ILayout.cs.meta b/Assets/Scripts/UI/Elements/Layout/ILayout.cs.meta new file mode 100644 index 0000000..47eff30 --- /dev/null +++ b/Assets/Scripts/UI/Elements/Layout/ILayout.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0cfd00f2409d6a95ca26d19888b4d8d2 \ No newline at end of file diff --git a/Assets/Scripts/UI/Elements/RecycleView.meta b/Assets/Scripts/UI/Elements/RecycleView.meta new file mode 100644 index 0000000..f1d109e --- /dev/null +++ b/Assets/Scripts/UI/Elements/RecycleView.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0721663a92e075ca781f4fde5b3aec5d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/UI/Elements/RecycleView/ICollectionDataSource.cs b/Assets/Scripts/UI/Elements/RecycleView/ICollectionDataSource.cs new file mode 100644 index 0000000..e123346 --- /dev/null +++ b/Assets/Scripts/UI/Elements/RecycleView/ICollectionDataSource.cs @@ -0,0 +1,13 @@ +using UnityEngine.UIElements; + +namespace KitsuneCafe.UI +{ + public interface ICollectionDataSource + { + int Length { get; } + + VisualElement CreateItem(); + void BindItem(VisualElement element, int index); + void UnbindItem(VisualElement element, int index); + } +} diff --git a/Assets/Scripts/UI/Elements/RecycleView/ICollectionDataSource.cs.meta b/Assets/Scripts/UI/Elements/RecycleView/ICollectionDataSource.cs.meta new file mode 100644 index 0000000..b37b8f5 --- /dev/null +++ b/Assets/Scripts/UI/Elements/RecycleView/ICollectionDataSource.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8cc192cc5a0da4ac0ba2505e808281ef \ No newline at end of file diff --git a/Assets/Scripts/UI/Elements/RecycleView/IDragAndDropController.cs b/Assets/Scripts/UI/Elements/RecycleView/IDragAndDropController.cs new file mode 100644 index 0000000..60088d6 --- /dev/null +++ b/Assets/Scripts/UI/Elements/RecycleView/IDragAndDropController.cs @@ -0,0 +1,4 @@ +namespace KitsuneCafe.UI +{ + public interface IDragAndDropController { } +} diff --git a/Assets/Scripts/UI/Elements/RecycleView/IDragAndDropController.cs.meta b/Assets/Scripts/UI/Elements/RecycleView/IDragAndDropController.cs.meta new file mode 100644 index 0000000..b0b8fd1 --- /dev/null +++ b/Assets/Scripts/UI/Elements/RecycleView/IDragAndDropController.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3206838b8b365654090a0ba619bf954f \ No newline at end of file diff --git a/Assets/Scripts/UI/Elements/RecycleView/IVirtualizationController.cs b/Assets/Scripts/UI/Elements/RecycleView/IVirtualizationController.cs new file mode 100644 index 0000000..df409c2 --- /dev/null +++ b/Assets/Scripts/UI/Elements/RecycleView/IVirtualizationController.cs @@ -0,0 +1,14 @@ +using UnityEngine.UIElements; + +namespace KitsuneCafe.UI +{ + public interface IVirtualizationController + { + ICollectionDataSource DataSource { get; set; } + VisualElement Container { get; set; } + void Setup(); + void OnParentSizeChanged(UnityEngine.Vector2 size); + void OnScrolled(float scrollOffset); + float GetContentSize(); + } +} diff --git a/Assets/Scripts/UI/Elements/RecycleView/IVirtualizationController.cs.meta b/Assets/Scripts/UI/Elements/RecycleView/IVirtualizationController.cs.meta new file mode 100644 index 0000000..5774fd5 --- /dev/null +++ b/Assets/Scripts/UI/Elements/RecycleView/IVirtualizationController.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b0f05a19f2918482b8d5c617729a9b31 \ No newline at end of file diff --git a/Assets/Scripts/UI/Elements/RecycleView/RecycleView.cs b/Assets/Scripts/UI/Elements/RecycleView/RecycleView.cs new file mode 100644 index 0000000..eed8d71 --- /dev/null +++ b/Assets/Scripts/UI/Elements/RecycleView/RecycleView.cs @@ -0,0 +1,203 @@ +using System; +using Unity.Properties; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +namespace KitsuneCafe.UI +{ + public enum FlowDirection + { + Vertical = 0, + Horizontal = 1 + } + + + public abstract record CollectionItemSize; + + [Serializable] + public record FixedItemSize(float Size) : CollectionItemSize; + + [Serializable] + public record DynamicItemSize() : CollectionItemSize + { + public static readonly DynamicItemSize Instance = new(); + } + + public class CollectionItemSizeConverter : UxmlAttributeConverter + { + public override CollectionItemSize FromString(string value) + { + return value switch + { + "()" => new DynamicItemSize(), + var v => new FixedItemSize(int.Parse(v)) + }; + } + + public override string ToString(CollectionItemSize value) + { + return value switch + { + DynamicItemSize => "()", + var v => v.ToString(), + }; + } + } + + [UxmlElement] + public partial class RecycleView : VisualElement, IDisposable + { + public const string RecycleViewBaseClass = "kitsunecafe__recycle-view"; + public const string RecycleViewScrollViewClass = "kitsunecafe__recycle-view--scroll-view"; + public const string RecycleViewContentContainerClass = "kitsunecafe__recycle-view--content-container"; + public const string RecycleViewDynamicItemClass = "kitsunecafe__recycle-view--dynamic-item"; + + + private FlowDirection direction; + + [UxmlAttribute, CreateProperty] + public FlowDirection Direction + { + get => direction; + set + { + if (direction != value) + { + direction = value; + virtualizationController.Layout = CreateLayout(); + UpdateDirection(); + } + + } + } + + private bool isDynamicSize = false; + + [UxmlAttribute, CreateProperty] + public bool IsDynamicSize + { + get => isDynamicSize; + set + { + if (isDynamicSize != value) + { + isDynamicSize = value; + virtualizationController.Layout = CreateLayout(); + } + + } + } + + private float itemSize = 22; + + [UxmlAttribute, CreateProperty, Delayed, Tooltip("In a dynamic layout, this is used for initial calculations")] + public float ItemSize + { + get => itemSize; + set + { + if (itemSize != value) + { + itemSize = value; + if (virtualizationController.Layout is FixedLayout fixedLayout) + { + fixedLayout.ItemSize = value; + } + else if (virtualizationController.Layout is DynamicLayout dynamicLayout) + { + dynamicLayout.DefaultItemSize = value; + } + } + } + } + + [CreateProperty] + public ICollectionDataSource DataSource + { + get => virtualizationController?.DataSource; + set + { + if (virtualizationController != null) + { + virtualizationController.DataSource = value; + virtualizationController.Setup(); + } + } + } + + private readonly ScrollView scrollView; + public override VisualElement contentContainer => scrollView.contentContainer; + + private readonly IRecycleVirtualizationContainer virtualizationController; + + public RecycleView() + { + AddToClassList(RecycleViewBaseClass); + + scrollView = new ScrollView(); + scrollView.AddToClassList(RecycleViewScrollViewClass); + hierarchy.Add(scrollView); + contentContainer.AddToClassList(RecycleViewContentContainerClass); + + virtualizationController = new RecycleVirtualizationController + { + Container = contentContainer + }; + + RegisterCallback(OnGeometryChanged); + } + + private ILayout CreateLayout() + { + return isDynamicSize switch + { + true => new DynamicLayout(Direction, itemSize), + false => new FixedLayout(Direction, itemSize) + }; + } + + + private void UpdateDirection() + { + switch (direction) + { + case FlowDirection.Vertical: + scrollView.mode = ScrollViewMode.Vertical; + scrollView.verticalScrollerVisibility = ScrollerVisibility.Auto; + scrollView.horizontalScrollerVisibility = ScrollerVisibility.Hidden; + scrollView.horizontalScroller.valueChanged -= virtualizationController.OnScrolled; + scrollView.verticalScroller.valueChanged += virtualizationController.OnScrolled; + break; + case FlowDirection.Horizontal: + scrollView.mode = ScrollViewMode.Horizontal; + scrollView.verticalScrollerVisibility = ScrollerVisibility.Hidden; + scrollView.horizontalScrollerVisibility = ScrollerVisibility.Auto; + scrollView.verticalScroller.valueChanged -= virtualizationController.OnScrolled; + scrollView.horizontalScroller.valueChanged += virtualizationController.OnScrolled; + break; + } + } + + public void OnGeometryChanged(GeometryChangedEvent evt) + { + if (evt.newRect.size != evt.oldRect.size && virtualizationController != null) + { + virtualizationController.OnParentSizeChanged(evt.newRect.size); + } + } + + public void Dispose() + { + if (virtualizationController is IDisposable disposable) + { + disposable.Dispose(); + } + } + + ~RecycleView() + { + Dispose(); + } + } +} diff --git a/Assets/Scripts/UI/Elements/RecycleView/RecycleView.cs.meta b/Assets/Scripts/UI/Elements/RecycleView/RecycleView.cs.meta new file mode 100644 index 0000000..3a46aba --- /dev/null +++ b/Assets/Scripts/UI/Elements/RecycleView/RecycleView.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 902d6b824a8533b7982956ca9cb66e40 \ No newline at end of file diff --git a/Assets/Scripts/UI/Elements/RecycleView/RecycleVirtualizationController.cs b/Assets/Scripts/UI/Elements/RecycleView/RecycleVirtualizationController.cs new file mode 100644 index 0000000..e8d01db --- /dev/null +++ b/Assets/Scripts/UI/Elements/RecycleView/RecycleVirtualizationController.cs @@ -0,0 +1,380 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using KitsuneCafe.System.Collections; +using R3; +using UnityEngine; +using UnityEngine.UIElements; + +namespace KitsuneCafe.UI +{ + + interface IRecycleVirtualizationContainer : IVirtualizationController + { + ILayout Layout { get; set; } + } + + public class RecycleVirtualizationController : IRecycleVirtualizationContainer, IDisposable + { + internal record ItemGeometry(float Position, float Size); + + public abstract record UpdateRequest; + public record FullUpdate : UpdateRequest; + public record PartialUpdate(int Index) : UpdateRequest; + + private ICollectionDataSource dataSource; + + public ICollectionDataSource DataSource + { + get => dataSource; + set + { + if (dataSource != value) + { + dataSource = value; + Setup(); + } + } + } + + private VisualElement container; + public VisualElement Container + { + get => container; + set + { + if (container != value) + { + container = value; + Setup(); + } + } + } + + private ILayout layout; + public ILayout Layout + { + get => layout; + set + { + if (layout != value) + { + layout = value; + Setup(); + } + } + } + + public FlowDirection Direction => Layout.Direction; + + private readonly Queue itemPool = new(); + private readonly BiDictionary visibleItems = new(); + private float parentSize = 0; + private float lastKnownScrollOffset = 0; + + private readonly int itemCountBuffer = 2; + + private readonly Subject requestSubject = new(); + private IDisposable subscriptions; + + public void Setup() + { + Dispose(); + + + if (DataSource == null || DataSource.Length == 0 || Layout == null || Container == null) + { + return; + } + + var full = requestSubject.Where(req => req is FullUpdate) + .ThrottleLastFrame(1) + .Subscribe(_ => UpdateVisibleItems()); + + var partial = requestSubject.Where(req => req is PartialUpdate) + .Select(req => (PartialUpdate)req) + .ChunkFrame(1) + .Where(requests => requests.Any()) + .Subscribe(requests => + { + var index = requests.Min(req => req.Index); + UpdateFromIndex(index); + }); + + subscriptions = Disposable.Combine(full, partial); + // subscriptions = Observable.Merge(full, partial) + // // var updateSubscription = requestSubject.ThrottleLastFrame(1) + // .Subscribe(request => + // { + // if (request is PartialUpdate req) + // { + // UpdateFromIndex(req.Index); + // } + // else { UpdateVisibleItems(); } + // }); + + Layout.Update(DataSource.Length, Container); + ScheduleUpdate(); + } + + public void OnScrolled(float scrollOffset) + { + lastKnownScrollOffset = scrollOffset; + ScheduleUpdate(); + } + + public void OnParentSizeChanged(Vector2 size) + { + parentSize = Direction switch + { + FlowDirection.Vertical => size.y, + FlowDirection.Horizontal => size.x, + _ => throw new NotImplementedException(), + }; + + if (!float.IsNaN(parentSize)) + { + ScheduleUpdate(); + } + } + + private void ScheduleUpdate() + { + requestSubject.OnNext(new FullUpdate()); + } + + private void ScheduleUpdate(int index) + { + requestSubject.OnNext(new PartialUpdate(index)); + } + + private void UpdateSize(VisualElement element, StyleLength size) + { + if (Layout is null) + { + element.style.width = 0; + element.style.height = 0; + } + else if (Direction == FlowDirection.Vertical) + { + element.style.width = StyleKeyword.Auto; + element.style.height = size; + } + else if (Direction == FlowDirection.Horizontal) + { + element.style.height = StyleKeyword.Auto; + element.style.width = size; + } + } + + private VisualElement RecycleItem() + { + var item = itemPool.Dequeue(); + item.UnregisterCallback(OnItemGeometryChanged); + + return item; + } + + private VisualElement CreateItem(int index) + { + var item = DataSource.CreateItem(); + + if (Layout is FixedLayout) + { + float itemSize = Layout.GetItemSize(index); + UpdateSize(item, itemSize); + } + + return item; + } + + private VisualElement GetItem(int index) + { + VisualElement item = itemPool.Count > 0 ? RecycleItem() : CreateItem(index); + + item.RegisterCallback(OnItemGeometryChanged, index); + + DataSource.BindItem(item, index); + visibleItems[index] = item; + Container.Add(item); + + var position = Layout.GetItemPosition(index); + if (Direction == FlowDirection.Horizontal) + { + item.style.left = position; + } + else + { + item.style.top = position; + } + + + if (Layout is DynamicLayout layout) + { + var size = Direction switch + { + FlowDirection.Vertical => item.resolvedStyle.height, + FlowDirection.Horizontal => item.resolvedStyle.width, + _ => throw new NotImplementedException() + }; + + if (!float.IsNaN(size)) + { + layout.SetMeasuredItemSize(index, size); + } + } + + return item; + } + + private void OnItemGeometryChanged(GeometryChangedEvent evt, int index) + { + if (Layout is DynamicLayout layout) + { + var newSize = Direction == FlowDirection.Horizontal ? evt.newRect.width : evt.newRect.height; + layout.SetMeasuredItemSize(index, newSize); + UpdateSize(Container, Layout.ContentSize); + ScheduleUpdate(index); + } + } + + private Range GetDynamicItems(DynamicLayout layout, float scrollOffset) + { + var first = layout.GetFirstVisibleIndex(scrollOffset); + var count = 1; + var position = layout.GetItemPosition(first); + var width = position + parentSize; + + foreach (var item in layout.Enumerate(first)) + { + if (item.Position > width) { break; } + count += 1; + position = item.Position; + } + + return new Range(first, Math.Min(DataSource.Length, first + count)); + } + + private Range GetFixedItems(FixedLayout layout, float scrollOffset) + { + var size = layout.ItemSize + layout.GutterSize; + var first = Mathf.FloorToInt(scrollOffset / (layout.ItemSize + layout.GutterSize)); + var count = Mathf.CeilToInt(parentSize / size) + itemCountBuffer; + var last = Math.Min(DataSource.Length, first + count); + + return new Range(first, last); + } + + private void UpdateVisibleItems() + { + if (DataSource == null || DataSource.Length == 0 || Mathf.Approximately(parentSize, 0)) + { + return; + } + + + var scrollOffset = lastKnownScrollOffset; + + var range = Layout switch + { + FixedLayout fl => GetFixedItems(fl, scrollOffset), + DynamicLayout dl => GetDynamicItems(dl, scrollOffset), + _ => throw new NotImplementedException(), + }; + + var firstIndex = range.Start.Value; + var lastIndex = range.End.Value; + + var itemsToRemove = new List(); + foreach (var (index, item) in visibleItems) + { + if (index < firstIndex || index >= lastIndex) + { + item.Value.UnregisterCallback(OnItemGeometryChanged); + DataSource.UnbindItem(item, index); + itemPool.Enqueue(item); + Container.Remove(item); + itemsToRemove.Add(index); + } + } + + foreach (int index in itemsToRemove) + { + visibleItems.Remove(index); + } + + for (int i = firstIndex; i < lastIndex; i++) + { + if (!visibleItems.ContainsKey(i)) + { + var item = GetItem(i); + + float position = Layout.GetItemPosition(i); + if (Direction == FlowDirection.Horizontal) + { + item.style.left = position; + } + else + { + item.style.top = position; + } + } + } + } + + private void UpdateFromIndex(int index) + { + foreach (var (i, item) in visibleItems) + { + if (i >= index) + { + float position = Layout.GetItemPosition(i); + if (Direction == FlowDirection.Horizontal) + { + item.Value.style.left = position; + } + else + { + item.Value.style.top = position; + } + } + } + } + + public float GetContentSize() + { + return Layout.ContentSize; + } + + private void UnregisterCallback(VisualElement element) + { + element.UnregisterCallback(OnItemGeometryChanged); + } + + public void Dispose() + { + foreach (var item in visibleItems.Values) + { + UnregisterCallback(item); + } + + foreach (var item in itemPool) + { + UnregisterCallback(item); + } + + + lastKnownScrollOffset = 0; + + subscriptions?.Dispose(); + Container.Clear(); + itemPool.Clear(); + visibleItems.Clear(); + } + + ~RecycleVirtualizationController() + { + Dispose(); + } + } +} diff --git a/Assets/Scripts/UI/Elements/RecycleView/RecycleVirtualizationController.cs.meta b/Assets/Scripts/UI/Elements/RecycleView/RecycleVirtualizationController.cs.meta new file mode 100644 index 0000000..132302b --- /dev/null +++ b/Assets/Scripts/UI/Elements/RecycleView/RecycleVirtualizationController.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a6e0bb01a1a66c1098e4392d86ce88df \ No newline at end of file diff --git a/Assets/Scripts/UI/TestRecycleView.cs b/Assets/Scripts/UI/TestRecycleView.cs new file mode 100644 index 0000000..8bf4555 --- /dev/null +++ b/Assets/Scripts/UI/TestRecycleView.cs @@ -0,0 +1,57 @@ +using KitsuneCafe.System.Collections; +using UnityEngine; +using UnityEngine.UIElements; + +namespace KitsuneCafe.UI +{ + public class TestRecycleView : MonoBehaviour + { + [SerializeField] + private UIDocument doc; + + private ListView listView; + + private void OnValidate() + { + if (doc == null) + { + doc = GetComponent(); + } + } + + private void Awake() + { + listView = doc.rootVisualElement.Q(); + listView.Q().verticalScrollerVisibility = ScrollerVisibility.Hidden; + listView.makeItem = () => new Label(); + listView.bindItem = (visualElement, index) => + { + Label label = visualElement as Label; + label.text = listView.itemsSource[index].ToString(); + }; + + } + + private void Start() + { + var list = new CycleList() { "one", "two", "three" }; + listView.itemsSource = list; + listView.RefreshItems(); + } + + private void OnEnable() + { + listView.itemsSourceChanged += ScrollToMiddle; + } + + private void OnDisable() + { + listView.itemsSourceChanged -= ScrollToMiddle; + } + + private void ScrollToMiddle() + { + listView.ScrollToItem(listView.itemsSource.Count / 2); + } + } +} diff --git a/Assets/Scripts/UI/TestRecycleView.cs.meta b/Assets/Scripts/UI/TestRecycleView.cs.meta new file mode 100644 index 0000000..df9ba6d --- /dev/null +++ b/Assets/Scripts/UI/TestRecycleView.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0b73a6c894b05e193a00e4926ac578ed \ No newline at end of file diff --git a/Assets/Settings/DefaultVolumeProfile.asset b/Assets/Settings/DefaultVolumeProfile.asset index 3b6663e..eb411de 100644 --- a/Assets/Settings/DefaultVolumeProfile.asset +++ b/Assets/Settings/DefaultVolumeProfile.asset @@ -793,7 +793,7 @@ MonoBehaviour: m_Value: 0 gaussianStart: m_OverrideState: 1 - m_Value: 20 + m_Value: 10 gaussianEnd: m_OverrideState: 1 m_Value: 30 diff --git a/Assets/UI Toolkit/PanelSettings.asset b/Assets/UI Toolkit/PanelSettings.asset index 40b3384..fb84d7b 100644 --- a/Assets/UI Toolkit/PanelSettings.asset +++ b/Assets/UI Toolkit/PanelSettings.asset @@ -12,20 +12,20 @@ MonoBehaviour: m_Script: {fileID: 19101, guid: 0000000000000000e000000000000000, type: 0} m_Name: PanelSettings m_EditorClassIdentifier: - themeUss: {fileID: -4733365628477956816, guid: 4e01e0da3979f115d951c3cb798e4313, type: 3} + themeUss: {fileID: -4733365628477956816, guid: 255b091878454b37c92e400e84da7ebe, type: 3} m_DisableNoThemeWarning: 0 m_TargetTexture: {fileID: 0} m_RenderMode: 0 m_WorldSpaceLayer: 0 - m_ScaleMode: 1 + m_ScaleMode: 0 m_ReferenceSpritePixelsPerUnit: 100 m_PixelsPerUnit: 100 m_Scale: 1 m_ReferenceDpi: 96 m_FallbackDpi: 96 - m_ReferenceResolution: {x: 1200, y: 800} + m_ReferenceResolution: {x: 800, y: 600} m_ScreenMatchMode: 0 - m_Match: 0 + m_Match: 1 m_SortingOrder: 0 m_TargetDisplay: 0 m_BindingLogLevel: 0 diff --git a/Assets/UI Toolkit/UnityThemes/CantoComponents.uss b/Assets/UI Toolkit/UnityThemes/CantoComponents.uss new file mode 100644 index 0000000..087f009 --- /dev/null +++ b/Assets/UI Toolkit/UnityThemes/CantoComponents.uss @@ -0,0 +1,21 @@ +:root { + color: rgb(255, 255, 255); + --primary: rgb(238, 66, 10); + --text: rgb(255, 255, 255); + --background: rgb(29, 29, 29); + flex-grow: 1; +} + +.kitsunecafe__recycle-view { + display: flex; +} + +.kitsunecafe__recycle-view, +.kitsunecafe__recycle-view--scroll-view, +.kitsunecafe__recycle-view--content-container { + flex-grow: 1; +} + +.kitsunecafe__recycle-view--content-container > * { + position: absolute; +} diff --git a/Assets/UI Toolkit/UnityThemes/CantoComponents.uss.meta b/Assets/UI Toolkit/UnityThemes/CantoComponents.uss.meta new file mode 100644 index 0000000..6b4fe6f --- /dev/null +++ b/Assets/UI Toolkit/UnityThemes/CantoComponents.uss.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 561bcbad89b31ba65bf470beac5635ec +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 diff --git a/Assets/UI Toolkit/UnityThemes/CantoRuntimeTheme.tss b/Assets/UI Toolkit/UnityThemes/CantoRuntimeTheme.tss new file mode 100644 index 0000000..58bb803 --- /dev/null +++ b/Assets/UI Toolkit/UnityThemes/CantoRuntimeTheme.tss @@ -0,0 +1,4 @@ +@import url("unity-theme://default"); + +@import url("CantoComponents.uss"); +VisualElement {} diff --git a/Assets/UI Toolkit/UnityThemes/CantoRuntimeTheme.tss.meta b/Assets/UI Toolkit/UnityThemes/CantoRuntimeTheme.tss.meta new file mode 100644 index 0000000..ae9ea2d --- /dev/null +++ b/Assets/UI Toolkit/UnityThemes/CantoRuntimeTheme.tss.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 255b091878454b37c92e400e84da7ebe +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12388, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 diff --git a/Assets/UI Toolkit/UnityThemes/UnityDefaultRuntimeTheme.tss b/Assets/UI Toolkit/UnityThemes/UnityDefaultRuntimeTheme.tss index 1056e07..b12af85 100644 --- a/Assets/UI Toolkit/UnityThemes/UnityDefaultRuntimeTheme.tss +++ b/Assets/UI Toolkit/UnityThemes/UnityDefaultRuntimeTheme.tss @@ -1 +1,3 @@ -@import url("unity-theme://default"); \ No newline at end of file +@import url("unity-theme://default"); +@import url("CantoTheme.tss"); + diff --git a/Assets/UI/HorizontalList.uxml b/Assets/UI/HorizontalList.uxml new file mode 100644 index 0000000..ebc3bf8 --- /dev/null +++ b/Assets/UI/HorizontalList.uxml @@ -0,0 +1,2 @@ + + diff --git a/Assets/UI/HorizontalList.uxml.meta b/Assets/UI/HorizontalList.uxml.meta new file mode 100644 index 0000000..7ba753b --- /dev/null +++ b/Assets/UI/HorizontalList.uxml.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 91d808ff132e03eca9dab667939a41cb +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} diff --git a/Assets/UI/Inventory.uxml b/Assets/UI/Inventory.uxml index eed38bf..d063435 100644 --- a/Assets/UI/Inventory.uxml +++ b/Assets/UI/Inventory.uxml @@ -1,3 +1,55 @@ - +