diff --git a/Assets/AddressableAssetsData/AssetGroups/Prefabs.asset b/Assets/AddressableAssetsData/AssetGroups/Prefabs.asset
index a4e86e06a..5728902ef 100644
--- a/Assets/AddressableAssetsData/AssetGroups/Prefabs.asset
+++ b/Assets/AddressableAssetsData/AssetGroups/Prefabs.asset
@@ -77,6 +77,11 @@ MonoBehaviour:
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
+ - m_GUID: 003f8d83e417e6a44a58ed1929b4eafd
+ m_Address: RecordItem
+ m_ReadOnly: 0
+ m_SerializedLabels: []
+ FlaggedDuringContentUpdateRestriction: 0
m_ReadOnly: 0
m_Settings: {fileID: 11400000, guid: 77169ce22e430f64fb36c771815a4a7b, type: 2}
m_SchemaSet:
diff --git a/Assets/AddressableAssetsData/link.xml b/Assets/AddressableAssetsData/link.xml
deleted file mode 100644
index 7f97daf24..000000000
--- a/Assets/AddressableAssetsData/link.xml
+++ /dev/null
@@ -1,537 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Assets/Plugins/LoopScrollRect.meta b/Assets/Plugins/LoopScrollRect.meta
new file mode 100644
index 000000000..7e1343eed
--- /dev/null
+++ b/Assets/Plugins/LoopScrollRect.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 62fe16447b58e0a4488420a0ebfdd353
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/LoopScrollRect/.gitignore b/Assets/Plugins/LoopScrollRect/.gitignore
new file mode 100644
index 000000000..ce626dedb
--- /dev/null
+++ b/Assets/Plugins/LoopScrollRect/.gitignore
@@ -0,0 +1,30 @@
+/[Ll]ibrary/
+/[Tt]emp/
+/[Oo]bj/
+/[Bb]uild/
+/Logs/
+# Autogenerated VS/MD solution and project files
+*.csproj
+*.unityproj
+*.sln
+*.suo
+*.tmp
+*.user
+*.userprefs
+*.pidb
+*.booproj
+
+# Unity3D generated meta files
+*.pidb.meta
+
+# Unity3D Generated File On Crash Reports
+sysinfo.txt
+
+# OS generated
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
diff --git a/Assets/Plugins/LoopScrollRect/CHANGELOG.md b/Assets/Plugins/LoopScrollRect/CHANGELOG.md
new file mode 100644
index 000000000..c74bf66d2
--- /dev/null
+++ b/Assets/Plugins/LoopScrollRect/CHANGELOG.md
@@ -0,0 +1,82 @@
+# Changelog
+
+## [1.1.4] - 2025-07-18
+### Changed
+- Avoid `UpdateBounds` when disabled
+- Apply inspector to `LoopScrollRectBase`
+- Improved element size estimation
+- Ensure `Rebuild` called as expected
+- Fix scrollbar precision problem with many items and avoid redundant callback
+- Fix `GetFirstItem`+`RefillCells` and `LastItem`+`RefillCellsFromEnd` usage, keeping ScrollRect stable
+- Add more tests in inspector
+
+## [1.1.3] - 2025-02-28
+### Added
+- Multi cell full screen sample.
+- Support item without `ILayoutElement`
+- Support `ToCenter`/`FirstAppear` in `ScrollToCell`
+- Add `contentOffset` in `RefillCellsFromEnd`
+### Changed
+- Deprecated typo API
+- Fill last line in `RefillCellsFromEnd`
+- Consider padding in `RefillCellsFromEnd`
+- `UpdateItems` when `OnRectTransformDimensionsChange`
+
+## [1.1.2] - 2022-07-18
+### Added
+- Infinity sample for multi prefab.
+### Changed
+- Fix API below Unity 2020
+- Fix `RefreshCells` with total count changes.
+- Check `m_Content` afterwards.
+- Fix SizeHelper with no content spacing considered.
+
+## [1.1.1] - 2022-04-23
+### Added
+- Register at OpenUPM.
+### Changed
+- Fix `RefreshCells` when `totalCount` increases.
+
+## [1.1.0] - 2022-03-25
+### Added
+- Changelog
+- Add support for different sources.
+- More complex demo from @SyaoranChang (Great thanks for valuable suggestion)
+### Changed
+- ReOrganize Project with Unity Package.
+- Improve scrolling within tiny steps.
+
+## [1.0.6] - 2021-08-01
+### Changed
+- Continue seperating data source and prefab source.
+- Fix padding from @CodingFishWu.
+- Fix issue when grid is not full from @zxsean.
+
+## [1.0.5] - 2020-10-06
+### Changed
+- Seperate data source.
+- Improve performance with more skippable cases and better pooling.
+- Implement `fillViewRect` in `RefillCells` from @roointan.
+
+## [1.0.4] - 2018-01-04
+### Added
+- Quick jump.
+
+## [1.0.3] - 2016-10-12
+### Added
+- ScrollBar support.
+### Changed
+- Fix Grid issues.
+
+## [1.0.2] - 2016-01-21
+### Changed
+- Code cleanup.
+- Performance optimization from @zxsean.
+
+## [1.0.1] - 2015-12-02
+### Added
+- Infinity version.
+- Reverse Direction mode.
+- Threshold for better control.
+
+## [1.0.0] - 2015-08-15
\ No newline at end of file
diff --git a/Assets/AddressableAssetsData/link.xml.meta b/Assets/Plugins/LoopScrollRect/CHANGELOG.md.meta
similarity index 75%
rename from Assets/AddressableAssetsData/link.xml.meta
rename to Assets/Plugins/LoopScrollRect/CHANGELOG.md.meta
index be9ac3218..3ff873c28 100644
--- a/Assets/AddressableAssetsData/link.xml.meta
+++ b/Assets/Plugins/LoopScrollRect/CHANGELOG.md.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 806686f7b47bc1247aa37dfcc70a7643
+guid: ab3222005e06e4c4aad63f7fd097f61c
TextScriptImporter:
externalObjects: {}
userData:
diff --git a/Assets/Plugins/LoopScrollRect/Editor.meta b/Assets/Plugins/LoopScrollRect/Editor.meta
new file mode 100644
index 000000000..85eb73ec8
--- /dev/null
+++ b/Assets/Plugins/LoopScrollRect/Editor.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: b10ceda9bec25b14ea5e190eb9bb0341
+folderAsset: yes
+timeCreated: 1476279504
+licenseType: Free
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/LoopScrollRect/Editor/LoopScrollRect.Editor.asmdef b/Assets/Plugins/LoopScrollRect/Editor/LoopScrollRect.Editor.asmdef
new file mode 100644
index 000000000..d51f95038
--- /dev/null
+++ b/Assets/Plugins/LoopScrollRect/Editor/LoopScrollRect.Editor.asmdef
@@ -0,0 +1,18 @@
+{
+ "name": "LoopScrollRect.Editor",
+ "rootNamespace": "",
+ "references": [
+ "LoopScrollRect.Runtime"
+ ],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": [],
+ "versionDefines": [],
+ "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/Assets/Plugins/LoopScrollRect/Editor/LoopScrollRect.Editor.asmdef.meta b/Assets/Plugins/LoopScrollRect/Editor/LoopScrollRect.Editor.asmdef.meta
new file mode 100644
index 000000000..b0c2ac1c5
--- /dev/null
+++ b/Assets/Plugins/LoopScrollRect/Editor/LoopScrollRect.Editor.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 8621d9949b0c96543ac733223ddc6f3c
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/LoopScrollRect/Editor/LoopScrollRectInspector.cs b/Assets/Plugins/LoopScrollRect/Editor/LoopScrollRectInspector.cs
new file mode 100644
index 000000000..c68b7249a
--- /dev/null
+++ b/Assets/Plugins/LoopScrollRect/Editor/LoopScrollRectInspector.cs
@@ -0,0 +1,312 @@
+using AibisDream.UI;
+using UnityEditor;
+using UnityEditor.AnimatedValues;
+using UnityEngine;
+using UnityEngine.UI;
+using UnityEngine.UIElements;
+
+namespace AibisDream.UI
+{
+ [CustomEditor(typeof(LoopScrollRectBase), true)]
+ public class LoopScrollRectInspector : Editor
+ {
+ SerializedProperty m_Content;
+ SerializedProperty m_Horizontal;
+ SerializedProperty m_Vertical;
+ SerializedProperty m_MovementType;
+ SerializedProperty m_Elasticity;
+ SerializedProperty m_Inertia;
+ SerializedProperty m_DecelerationRate;
+ SerializedProperty m_ScrollSensitivity;
+ SerializedProperty m_Viewport;
+ SerializedProperty m_HorizontalScrollbar;
+ SerializedProperty m_VerticalScrollbar;
+ SerializedProperty m_HorizontalScrollbarVisibility;
+ SerializedProperty m_VerticalScrollbarVisibility;
+ SerializedProperty m_HorizontalScrollbarSpacing;
+ SerializedProperty m_VerticalScrollbarSpacing;
+ SerializedProperty m_OnValueChanged;
+ AnimBool m_ShowElasticity;
+ AnimBool m_ShowDecelerationRate;
+ bool m_ViewportIsNotChild, m_HScrollbarIsNotChild, m_VScrollbarIsNotChild;
+ static string s_HError = "For this visibility mode, the Viewport property and the Horizontal Scrollbar property both needs to be set to a Rect Transform that is a child to the Scroll Rect.";
+ static string s_VError = "For this visibility mode, the Viewport property and the Vertical Scrollbar property both needs to be set to a Rect Transform that is a child to the Scroll Rect.";
+
+ //==========LoopScrollRect==========
+ SerializedProperty totalCount;
+ SerializedProperty reverseDirection;
+
+ int firstItem = 0, lastItem = 0, scrollIndex = 0;
+ float firstOffset = 0.0f, lastOffset = 0.0f, scrollOffset = 0;
+ LoopScrollRectBase.ScrollMode scrollMode = LoopScrollRectBase.ScrollMode.ToStart;
+ float scrollSpeed = 1000, scrollTime = 1;
+
+ protected virtual void OnEnable()
+ {
+ m_Content = serializedObject.FindProperty("m_Content");
+ m_Horizontal = serializedObject.FindProperty("m_Horizontal");
+ m_Vertical = serializedObject.FindProperty("m_Vertical");
+ m_MovementType = serializedObject.FindProperty("m_MovementType");
+ m_Elasticity = serializedObject.FindProperty("m_Elasticity");
+ m_Inertia = serializedObject.FindProperty("m_Inertia");
+ m_DecelerationRate = serializedObject.FindProperty("m_DecelerationRate");
+ m_ScrollSensitivity = serializedObject.FindProperty("m_ScrollSensitivity");
+ m_Viewport = serializedObject.FindProperty("m_Viewport");
+ m_HorizontalScrollbar = serializedObject.FindProperty("m_HorizontalScrollbar");
+ m_VerticalScrollbar = serializedObject.FindProperty("m_VerticalScrollbar");
+ m_HorizontalScrollbarVisibility = serializedObject.FindProperty("m_HorizontalScrollbarVisibility");
+ m_VerticalScrollbarVisibility = serializedObject.FindProperty("m_VerticalScrollbarVisibility");
+ m_HorizontalScrollbarSpacing = serializedObject.FindProperty("m_HorizontalScrollbarSpacing");
+ m_VerticalScrollbarSpacing = serializedObject.FindProperty("m_VerticalScrollbarSpacing");
+ m_OnValueChanged = serializedObject.FindProperty("m_OnValueChanged");
+
+ m_ShowElasticity = new AnimBool(Repaint);
+ m_ShowDecelerationRate = new AnimBool(Repaint);
+ SetAnimBools(true);
+
+ //==========LoopScrollRect==========
+ totalCount = serializedObject.FindProperty("totalCount");
+ reverseDirection = serializedObject.FindProperty("reverseDirection");
+ }
+
+ protected virtual void OnDisable()
+ {
+ m_ShowElasticity.valueChanged.RemoveListener(Repaint);
+ m_ShowDecelerationRate.valueChanged.RemoveListener(Repaint);
+ }
+
+ void SetAnimBools(bool instant)
+ {
+ SetAnimBool(m_ShowElasticity, !m_MovementType.hasMultipleDifferentValues && m_MovementType.enumValueIndex == (int)ScrollRect.MovementType.Elastic, instant);
+ SetAnimBool(m_ShowDecelerationRate, !m_Inertia.hasMultipleDifferentValues && m_Inertia.boolValue == true, instant);
+ }
+
+ void SetAnimBool(AnimBool a, bool value, bool instant)
+ {
+ if (instant)
+ a.value = value;
+ else
+ a.target = value;
+ }
+
+ void CalculateCachedValues()
+ {
+ m_ViewportIsNotChild = false;
+ m_HScrollbarIsNotChild = false;
+ m_VScrollbarIsNotChild = false;
+ if (targets.Length == 1)
+ {
+ Transform transform = ((LoopScrollRectBase)target).transform;
+ if (m_Viewport.objectReferenceValue == null || ((RectTransform)m_Viewport.objectReferenceValue).transform.parent != transform)
+ m_ViewportIsNotChild = true;
+ if (m_HorizontalScrollbar.objectReferenceValue == null || ((Scrollbar)m_HorizontalScrollbar.objectReferenceValue).transform.parent != transform)
+ m_HScrollbarIsNotChild = true;
+ if (m_VerticalScrollbar.objectReferenceValue == null || ((Scrollbar)m_VerticalScrollbar.objectReferenceValue).transform.parent != transform)
+ m_VScrollbarIsNotChild = true;
+ }
+ }
+
+ public override void OnInspectorGUI()
+ {
+ SetAnimBools(false);
+
+ serializedObject.Update();
+ // Once we have a reliable way to know if the object changed, only re-cache in that case.
+ CalculateCachedValues();
+
+ EditorGUILayout.LabelField("Scroll Rect", EditorStyles.boldLabel);
+ EditorGUILayout.PropertyField(m_Content);
+
+ EditorGUILayout.PropertyField(m_Horizontal);
+ EditorGUILayout.PropertyField(m_Vertical);
+
+ EditorGUILayout.PropertyField(m_MovementType);
+ if (EditorGUILayout.BeginFadeGroup(m_ShowElasticity.faded))
+ {
+ EditorGUI.indentLevel++;
+ EditorGUILayout.PropertyField(m_Elasticity);
+ EditorGUI.indentLevel--;
+ }
+ EditorGUILayout.EndFadeGroup();
+
+ EditorGUILayout.PropertyField(m_Inertia);
+ if (EditorGUILayout.BeginFadeGroup(m_ShowDecelerationRate.faded))
+ {
+ EditorGUI.indentLevel++;
+ EditorGUILayout.PropertyField(m_DecelerationRate);
+ EditorGUI.indentLevel--;
+ }
+ EditorGUILayout.EndFadeGroup();
+
+ EditorGUILayout.PropertyField(m_ScrollSensitivity);
+
+ EditorGUILayout.Space();
+
+ EditorGUILayout.PropertyField(m_Viewport);
+
+ EditorGUILayout.PropertyField(m_HorizontalScrollbar);
+ if (m_HorizontalScrollbar.objectReferenceValue && !m_HorizontalScrollbar.hasMultipleDifferentValues)
+ {
+ EditorGUI.indentLevel++;
+ EditorGUILayout.PropertyField(m_HorizontalScrollbarVisibility, EditorGUIUtility.TrTextContent("Visibility"));
+
+ if ((ScrollRect.ScrollbarVisibility)m_HorizontalScrollbarVisibility.enumValueIndex == ScrollRect.ScrollbarVisibility.AutoHideAndExpandViewport
+ && !m_HorizontalScrollbarVisibility.hasMultipleDifferentValues)
+ {
+ if (m_ViewportIsNotChild || m_HScrollbarIsNotChild)
+ EditorGUILayout.HelpBox(s_HError, MessageType.Error);
+ EditorGUILayout.PropertyField(m_HorizontalScrollbarSpacing, EditorGUIUtility.TrTextContent("Spacing"));
+ }
+
+ EditorGUI.indentLevel--;
+ }
+
+ EditorGUILayout.PropertyField(m_VerticalScrollbar);
+ if (m_VerticalScrollbar.objectReferenceValue && !m_VerticalScrollbar.hasMultipleDifferentValues)
+ {
+ EditorGUI.indentLevel++;
+ EditorGUILayout.PropertyField(m_VerticalScrollbarVisibility, EditorGUIUtility.TrTextContent("Visibility"));
+
+ if ((ScrollRect.ScrollbarVisibility)m_VerticalScrollbarVisibility.enumValueIndex == ScrollRect.ScrollbarVisibility.AutoHideAndExpandViewport
+ && !m_VerticalScrollbarVisibility.hasMultipleDifferentValues)
+ {
+ if (m_ViewportIsNotChild || m_VScrollbarIsNotChild)
+ EditorGUILayout.HelpBox(s_VError, MessageType.Error);
+ EditorGUILayout.PropertyField(m_VerticalScrollbarSpacing, EditorGUIUtility.TrTextContent("Spacing"));
+ }
+
+ EditorGUI.indentLevel--;
+ }
+
+ EditorGUILayout.PropertyField(m_OnValueChanged);
+
+ //==========LoopScrollRect==========
+ EditorGUILayout.LabelField("Loop Scroll Rect", EditorStyles.boldLabel);
+ EditorGUILayout.PropertyField(totalCount);
+ EditorGUILayout.PropertyField(reverseDirection);
+
+ serializedObject.ApplyModifiedProperties();
+
+ LoopScrollRectBase scroll = (LoopScrollRectBase)target;
+ GUI.enabled = Application.isPlaying;
+ const float buttonWidth = 100f;
+
+ #region Basic Test
+ EditorGUILayout.LabelField("Basic Test", EditorStyles.boldLabel);
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.LabelField("Clear existing items");
+ GUILayout.FlexibleSpace();
+ if (GUILayout.Button("Clear", GUILayout.Width(buttonWidth)))
+ {
+ scroll.ClearCells();
+ }
+ EditorGUILayout.EndHorizontal();
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.LabelField("Refresh existing items(only update data)");
+ GUILayout.FlexibleSpace();
+ if (GUILayout.Button("Refresh", GUILayout.Width(buttonWidth)))
+ {
+ scroll.RefreshCells();
+ }
+ EditorGUILayout.EndHorizontal();
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.LabelField("Refill(0, 0.0f)");
+ GUILayout.FlexibleSpace();
+ if(GUILayout.Button("Refill", GUILayout.Width(buttonWidth)))
+ {
+ scroll.RefillCells();
+ }
+ EditorGUILayout.EndHorizontal();
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.LabelField("RefillFromEnd(0, 0.0f)");
+ GUILayout.FlexibleSpace();
+ if(GUILayout.Button("RefillFromEnd", GUILayout.Width(buttonWidth)))
+ {
+ scroll.RefillCellsFromEnd();
+ }
+ EditorGUILayout.EndHorizontal();
+ #endregion
+
+ #region Refill Test
+ EditorGUILayout.LabelField("Refill Test", EditorStyles.boldLabel);
+
+ firstItem = EditorGUILayout.IntField("FirstItem", firstItem);
+ firstOffset = EditorGUILayout.FloatField("FirstOffset", firstOffset);
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.LabelField("Get first item and offset");
+ GUILayout.FlexibleSpace();
+ if (GUILayout.Button("GetFirstItem", GUILayout.Width(buttonWidth)))
+ {
+ firstItem = scroll.GetFirstItem(out firstOffset);
+ }
+ EditorGUILayout.EndHorizontal();
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.LabelField("Refill with first item and offset");
+ GUILayout.FlexibleSpace();
+ if(GUILayout.Button("Refill", GUILayout.Width(buttonWidth)))
+ {
+ scroll.RefillCells(scroll.reverseDirection ? (scroll.totalCount - firstItem) : firstItem, firstOffset);
+ }
+ EditorGUILayout.EndHorizontal();
+ #endregion
+
+ #region Refill Test
+ EditorGUILayout.LabelField("RefillFromEnd Test", EditorStyles.boldLabel);
+
+ lastItem = EditorGUILayout.IntField("LastItem", lastItem);
+ lastOffset = EditorGUILayout.FloatField("LastOffset", lastOffset);
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.LabelField("Get last item and offset");
+ GUILayout.FlexibleSpace();
+ if (GUILayout.Button("GetLastItem", GUILayout.Width(buttonWidth)))
+ {
+ lastItem = scroll.GetLastItem(out lastOffset);
+ }
+ EditorGUILayout.EndHorizontal();
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.LabelField("RefillFromEnd with last item and offset");
+ GUILayout.FlexibleSpace();
+ if(GUILayout.Button("RefillFromEnd", GUILayout.Width(buttonWidth)))
+ {
+ scroll.RefillCellsFromEnd(scroll.reverseDirection ? lastItem : (scroll.totalCount - lastItem), lastOffset);
+ }
+ EditorGUILayout.EndHorizontal();
+ #endregion
+
+ #region Scroll Test
+ EditorGUILayout.LabelField("Scroll Test", EditorStyles.boldLabel);
+ scrollIndex = EditorGUILayout.IntField("ScrollIndex", scrollIndex);
+ scrollOffset = EditorGUILayout.FloatField("ScrollOffset", scrollOffset);
+ scrollMode = (LoopScrollRectBase.ScrollMode)EditorGUILayout.EnumPopup("Mode", scrollMode);
+
+ scrollSpeed = EditorGUILayout.FloatField("Speed", scrollSpeed);
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.LabelField("Scroll to index and offset with speed");
+ GUILayout.FlexibleSpace();
+ if(GUILayout.Button("ScrollToCell", GUILayout.Width(buttonWidth)))
+ {
+ scroll.ScrollToCell(scrollIndex, scrollSpeed, scrollOffset, scrollMode);
+ }
+ EditorGUILayout.EndHorizontal();
+
+ scrollTime = EditorGUILayout.FloatField("Time", scrollTime);
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.LabelField("Scroll to index and offset whtin time");
+ GUILayout.FlexibleSpace();
+ if(GUILayout.Button("ScrollToCellWithinTime", GUILayout.Width(buttonWidth)))
+ {
+ scroll.ScrollToCellWithinTime(scrollIndex, scrollTime, scrollOffset, scrollMode);
+ }
+ EditorGUILayout.EndHorizontal();
+ #endregion
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Plugins/LoopScrollRect/Editor/LoopScrollRectInspector.cs.meta b/Assets/Plugins/LoopScrollRect/Editor/LoopScrollRectInspector.cs.meta
new file mode 100644
index 000000000..4754ff333
--- /dev/null
+++ b/Assets/Plugins/LoopScrollRect/Editor/LoopScrollRectInspector.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 216d44a40b90b944db6c5f4624768e58
+timeCreated: 1439395663
+licenseType: Free
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/LoopScrollRect/Editor/SGDefaultControls.cs b/Assets/Plugins/LoopScrollRect/Editor/SGDefaultControls.cs
new file mode 100644
index 000000000..3ad255fc9
--- /dev/null
+++ b/Assets/Plugins/LoopScrollRect/Editor/SGDefaultControls.cs
@@ -0,0 +1,180 @@
+using UnityEngine;
+using System.Collections.Generic;
+using AibisDream.UI;
+using UnityEngine.UI;
+
+namespace AibisDream.UI
+{
+ public static class SGDefaultControls
+ {
+ #region code from DefaultControls.cs
+ public struct Resources
+ {
+ public Sprite standard;
+ public Sprite background;
+ public Sprite inputField;
+ public Sprite knob;
+ public Sprite checkmark;
+ public Sprite dropdown;
+ public Sprite mask;
+ }
+
+ private const float kWidth = 160f;
+ private const float kThickHeight = 30f;
+ private const float kThinHeight = 20f;
+ //private static Vector2 s_ThickElementSize = new Vector2(kWidth, kThickHeight);
+ //private static Vector2 s_ThinElementSize = new Vector2(kWidth, kThinHeight);
+ //private static Vector2 s_ImageElementSize = new Vector2(100f, 100f);
+ //private static Color s_DefaultSelectableColor = new Color(1f, 1f, 1f, 1f);
+ //private static Color s_PanelColor = new Color(1f, 1f, 1f, 0.392f);
+ private static Color s_TextColor = new Color(50f / 255f, 50f / 255f, 50f / 255f, 1f);
+
+ // Helper methods at top
+
+ private static GameObject CreateUIElementRoot(string name, Vector2 size)
+ {
+ GameObject child = new GameObject(name);
+ RectTransform rectTransform = child.AddComponent();
+ rectTransform.sizeDelta = size;
+ return child;
+ }
+
+ static GameObject CreateUIObject(string name, GameObject parent)
+ {
+ GameObject go = new GameObject(name);
+ go.AddComponent();
+ SetParentAndAlign(go, parent);
+ return go;
+ }
+
+ private static void SetDefaultTextValues(Text lbl)
+ {
+ // Set text values we want across UI elements in default controls.
+ // Don't set values which are the same as the default values for the Text component,
+ // since there's no point in that, and it's good to keep them as consistent as possible.
+ lbl.color = s_TextColor;
+ }
+
+ private static void SetDefaultColorTransitionValues(Selectable slider)
+ {
+ ColorBlock colors = slider.colors;
+ colors.highlightedColor = new Color(0.882f, 0.882f, 0.882f);
+ colors.pressedColor = new Color(0.698f, 0.698f, 0.698f);
+ colors.disabledColor = new Color(0.521f, 0.521f, 0.521f);
+ }
+
+ private static void SetParentAndAlign(GameObject child, GameObject parent)
+ {
+ if (parent == null)
+ return;
+
+ child.transform.SetParent(parent.transform, false);
+ SetLayerRecursively(child, parent.layer);
+ }
+
+ private static void SetLayerRecursively(GameObject go, int layer)
+ {
+ go.layer = layer;
+ Transform t = go.transform;
+ for (int i = 0; i < t.childCount; i++)
+ SetLayerRecursively(t.GetChild(i).gameObject, layer);
+ }
+ #endregion
+
+ public static GameObject CreateLoopHorizontalScrollRect(DefaultControls.Resources resources)
+ {
+ GameObject root = CreateUIElementRoot("Loop Horizontal Scroll Rect", new Vector2(200, 200));
+
+ GameObject viewport = CreateUIObject("Viewport", root);
+
+ RectTransform viewportRT = viewport.GetComponent();
+ viewportRT.anchorMin = new Vector2(0, 0);
+ viewportRT.anchorMax = new Vector2(1, 1);
+ viewportRT.sizeDelta = new Vector2(0, 0);
+ viewportRT.pivot = new Vector2(0.5f, 0.5f);
+
+ viewport.AddComponent();
+
+ GameObject content = CreateUIObject("Content", viewport);
+
+ RectTransform contentRT = content.GetComponent();
+ contentRT.anchorMin = new Vector2(0, 0);
+ contentRT.anchorMax = new Vector2(0, 1);
+ contentRT.sizeDelta = new Vector2(0, 0);
+ contentRT.pivot = new Vector2(0, 0.5f);
+
+ // Setup UI components.
+
+ LoopHorizontalScrollRect scrollRect = root.AddComponent();
+ scrollRect.content = contentRT;
+ scrollRect.viewport = viewportRT;
+ scrollRect.horizontalScrollbar = null;
+ scrollRect.verticalScrollbar = null;
+ scrollRect.horizontal = true;
+ scrollRect.vertical = false;
+ scrollRect.horizontalScrollbarVisibility = LoopScrollRect.ScrollbarVisibility.Permanent;
+ scrollRect.verticalScrollbarVisibility = LoopScrollRect.ScrollbarVisibility.Permanent;
+ scrollRect.horizontalScrollbarSpacing = 0;
+ scrollRect.verticalScrollbarSpacing = 0;
+
+ HorizontalLayoutGroup layoutGroup = content.AddComponent();
+ layoutGroup.childAlignment = TextAnchor.MiddleLeft;
+ layoutGroup.childForceExpandWidth = false;
+ layoutGroup.childForceExpandHeight = true;
+
+ ContentSizeFitter sizeFitter = content.AddComponent();
+ sizeFitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
+ sizeFitter.verticalFit = ContentSizeFitter.FitMode.Unconstrained;
+
+ return root;
+ }
+
+ public static GameObject CreateLoopVerticalScrollRect(DefaultControls.Resources resources)
+ {
+ GameObject root = CreateUIElementRoot("Loop Vertical Scroll Rect", new Vector2(200, 200));
+
+ GameObject viewport = CreateUIObject("Viewport", root);
+
+ RectTransform viewportRT = viewport.GetComponent();
+ viewportRT.anchorMin = new Vector2(0, 0);
+ viewportRT.anchorMax = new Vector2(1, 1);
+ viewportRT.sizeDelta = new Vector2(0, 0);
+ viewportRT.pivot = new Vector2(0.5f, 0.5f);
+
+ viewport.AddComponent();
+
+ GameObject content = CreateUIObject("Content", viewport);
+
+ RectTransform contentRT = content.GetComponent();
+ contentRT.anchorMin = new Vector2(0, 1);
+ contentRT.anchorMax = new Vector2(1, 1);
+ contentRT.sizeDelta = new Vector2(0, 0);
+ contentRT.pivot = new Vector2(0.5f, 1);
+
+ // Setup UI components.
+
+ LoopVerticalScrollRect scrollRect = root.AddComponent();
+ scrollRect.content = contentRT;
+ scrollRect.viewport = viewportRT;
+ scrollRect.horizontalScrollbar = null;
+ scrollRect.verticalScrollbar = null;
+ scrollRect.horizontal = false;
+ scrollRect.vertical = true;
+ scrollRect.horizontalScrollbarVisibility = LoopScrollRect.ScrollbarVisibility.Permanent;
+ scrollRect.verticalScrollbarVisibility = LoopScrollRect.ScrollbarVisibility.Permanent;
+ scrollRect.horizontalScrollbarSpacing = 0;
+ scrollRect.verticalScrollbarSpacing = 0;
+
+ VerticalLayoutGroup layoutGroup = content.AddComponent();
+ layoutGroup.childAlignment = TextAnchor.UpperCenter;
+ layoutGroup.childForceExpandWidth = true;
+ layoutGroup.childForceExpandHeight = false;
+
+ ContentSizeFitter sizeFitter = content.AddComponent();
+ sizeFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
+ sizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
+
+ return root;
+ }
+ }
+}
diff --git a/Assets/Plugins/LoopScrollRect/Editor/SGDefaultControls.cs.meta b/Assets/Plugins/LoopScrollRect/Editor/SGDefaultControls.cs.meta
new file mode 100644
index 000000000..882367d05
--- /dev/null
+++ b/Assets/Plugins/LoopScrollRect/Editor/SGDefaultControls.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 9e2cfa47387224a4eb069fc6dc8ac8b3
+timeCreated: 1476279563
+licenseType: Free
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/LoopScrollRect/Editor/SGMenuOptions.cs b/Assets/Plugins/LoopScrollRect/Editor/SGMenuOptions.cs
new file mode 100644
index 000000000..bdf25e9a7
--- /dev/null
+++ b/Assets/Plugins/LoopScrollRect/Editor/SGMenuOptions.cs
@@ -0,0 +1,151 @@
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.UI;
+
+namespace AibisDream.UI
+{
+ internal static class SGMenuOptions
+ {
+ #region code from MenuOptions.cs
+ private const string kUILayerName = "UI";
+
+ private const string kStandardSpritePath = "UI/Skin/UISprite.psd";
+ private const string kBackgroundSpritePath = "UI/Skin/Background.psd";
+ private const string kInputFieldBackgroundPath = "UI/Skin/InputFieldBackground.psd";
+ private const string kKnobPath = "UI/Skin/Knob.psd";
+ private const string kCheckmarkPath = "UI/Skin/Checkmark.psd";
+ private const string kDropdownArrowPath = "UI/Skin/DropdownArrow.psd";
+ private const string kMaskPath = "UI/Skin/UIMask.psd";
+
+ private static DefaultControls.Resources s_StandardResources;
+
+ private static DefaultControls.Resources GetStandardResources()
+ {
+ if (s_StandardResources.standard == null)
+ {
+ s_StandardResources.standard = AssetDatabase.GetBuiltinExtraResource(kStandardSpritePath);
+ s_StandardResources.background = AssetDatabase.GetBuiltinExtraResource(kBackgroundSpritePath);
+ s_StandardResources.inputField = AssetDatabase.GetBuiltinExtraResource(kInputFieldBackgroundPath);
+ s_StandardResources.knob = AssetDatabase.GetBuiltinExtraResource(kKnobPath);
+ s_StandardResources.checkmark = AssetDatabase.GetBuiltinExtraResource(kCheckmarkPath);
+ s_StandardResources.dropdown = AssetDatabase.GetBuiltinExtraResource(kDropdownArrowPath);
+ s_StandardResources.mask = AssetDatabase.GetBuiltinExtraResource(kMaskPath);
+ }
+ return s_StandardResources;
+ }
+
+ private static void SetPositionVisibleinSceneView(RectTransform canvasRTransform, RectTransform itemTransform)
+ {
+ // Find the best scene view
+ SceneView sceneView = SceneView.lastActiveSceneView;
+ if (sceneView == null && SceneView.sceneViews.Count > 0)
+ sceneView = SceneView.sceneViews[0] as SceneView;
+
+ // Couldn't find a SceneView. Don't set position.
+ if (sceneView == null || sceneView.camera == null)
+ return;
+
+ // Create world space Plane from canvas position.
+ Vector2 localPlanePosition;
+ Camera camera = sceneView.camera;
+ Vector3 position = Vector3.zero;
+ if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRTransform, new Vector2(camera.pixelWidth / 2, camera.pixelHeight / 2), camera, out localPlanePosition))
+ {
+ // Adjust for canvas pivot
+ localPlanePosition.x += canvasRTransform.sizeDelta.x * canvasRTransform.pivot.x;
+ localPlanePosition.y += canvasRTransform.sizeDelta.y * canvasRTransform.pivot.y;
+
+ localPlanePosition.x = Mathf.Clamp(localPlanePosition.x, 0, canvasRTransform.sizeDelta.x);
+ localPlanePosition.y = Mathf.Clamp(localPlanePosition.y, 0, canvasRTransform.sizeDelta.y);
+
+ // Adjust for anchoring
+ position.x = localPlanePosition.x - canvasRTransform.sizeDelta.x * itemTransform.anchorMin.x;
+ position.y = localPlanePosition.y - canvasRTransform.sizeDelta.y * itemTransform.anchorMin.y;
+
+ Vector3 minLocalPosition;
+ minLocalPosition.x = canvasRTransform.sizeDelta.x * (0 - canvasRTransform.pivot.x) + itemTransform.sizeDelta.x * itemTransform.pivot.x;
+ minLocalPosition.y = canvasRTransform.sizeDelta.y * (0 - canvasRTransform.pivot.y) + itemTransform.sizeDelta.y * itemTransform.pivot.y;
+
+ Vector3 maxLocalPosition;
+ maxLocalPosition.x = canvasRTransform.sizeDelta.x * (1 - canvasRTransform.pivot.x) - itemTransform.sizeDelta.x * itemTransform.pivot.x;
+ maxLocalPosition.y = canvasRTransform.sizeDelta.y * (1 - canvasRTransform.pivot.y) - itemTransform.sizeDelta.y * itemTransform.pivot.y;
+
+ position.x = Mathf.Clamp(position.x, minLocalPosition.x, maxLocalPosition.x);
+ position.y = Mathf.Clamp(position.y, minLocalPosition.y, maxLocalPosition.y);
+ }
+
+ itemTransform.anchoredPosition = position;
+ itemTransform.localRotation = Quaternion.identity;
+ itemTransform.localScale = Vector3.one;
+ }
+
+ private static void PlaceUIElementRoot(GameObject element, MenuCommand menuCommand)
+ {
+ GameObject parent = menuCommand.context as GameObject;
+ if (parent == null || parent.GetComponentInParent