@@ -27,6 +27,7 @@ namespace WallstopStudios.DataVisualizer.Editor
2727 using UnityEngine . UIElements ;
2828 using Utilities ;
2929 using Helper ;
30+ using NUnit . Framework ;
3031 using Debug = UnityEngine . Debug ;
3132 using Object = UnityEngine . Object ;
3233
@@ -66,6 +67,7 @@ public sealed class DataVisualizer : EditorWindow
6667 private const int MaxSearchResults = 25 ;
6768 private const float DefaultOuterSplitWidth = 200f ;
6869 private const float DefaultInnerSplitWidth = 250f ;
70+ private const int MaxObjectsPerPage = 100 ;
6971
7072 private enum DragType
7173 {
@@ -186,6 +188,11 @@ private int HiddenNamespaces
186188 private VisualElement _selectedNamespaceElement ;
187189
188190 private VisualElement _namespaceListContainer ;
191+ private VisualElement _objectPageController ;
192+ private Button _previousPageButton ;
193+ private Button _nextPageButton ;
194+ private IntegerField _currentPageField ;
195+ private IntegerField _maxPageField ;
189196 private VisualElement _objectListContainer ;
190197 private VisualElement _inspectorContainer ;
191198 private ScrollView _objectScrollView ;
@@ -4610,6 +4617,60 @@ private VisualElement CreateObjectColumn()
46104617 SetupDropTarget ( _andLabelsContainer , LabelFilterSection . AND ) ;
46114618 SetupDropTarget ( _orLabelsContainer , LabelFilterSection . OR ) ;
46124619
4620+ _objectPageController = new VisualElement
4621+ {
4622+ name = "object-page-controller" ,
4623+ style = { display = DisplayStyle . None } ,
4624+ } ;
4625+ _objectPageController . AddToClassList ( "object-page-controller" ) ;
4626+ _previousPageButton = new Button ( ( ) =>
4627+ {
4628+ int currentPage = GetCurrentPage ( _namespaceController . SelectedType ) ;
4629+ if ( currentPage <= 0 )
4630+ {
4631+ return ;
4632+ }
4633+
4634+ SetCurrentPage ( _namespaceController . SelectedType , currentPage - 1 ) ;
4635+ BuildObjectsView ( ) ;
4636+ } ) { text = "←" } ;
4637+ _previousPageButton . AddToClassList ( "go-button-disabled" ) ;
4638+
4639+ _currentPageField = new IntegerField ( ) ;
4640+ _currentPageField . AddToClassList ( "current-page-field" ) ;
4641+ _currentPageField . RegisterValueChangedCallback ( evt =>
4642+ {
4643+ int newValue = evt . newValue ;
4644+ newValue = Mathf . Clamp ( newValue , 0 , _filteredObjects . Count / MaxObjectsPerPage ) ;
4645+ if ( newValue != evt . newValue )
4646+ {
4647+ _currentPageField . SetValueWithoutNotify ( newValue ) ;
4648+ }
4649+
4650+ SetCurrentPage ( _namespaceController . SelectedType , newValue ) ;
4651+ BuildObjectsView ( ) ;
4652+ } ) ;
4653+ _maxPageField = new IntegerField ( ) { isReadOnly = true } ;
4654+ _maxPageField . AddToClassList ( "max-page-field" ) ;
4655+ _nextPageButton = new Button ( ( ) =>
4656+ {
4657+ int currentPage = GetCurrentPage ( _namespaceController . SelectedType ) ;
4658+ if ( _filteredObjects . Count / MaxObjectsPerPage <= currentPage )
4659+ {
4660+ return ;
4661+ }
4662+
4663+ SetCurrentPage ( _namespaceController . SelectedType , currentPage + 1 ) ;
4664+ BuildObjectsView ( ) ;
4665+ } ) { text = "→" } ;
4666+ _nextPageButton . AddToClassList ( "go-button-disabled" ) ;
4667+ _objectPageController . Add ( _previousPageButton ) ;
4668+ _objectPageController . Add ( _currentPageField ) ;
4669+ _objectPageController . Add ( _maxPageField ) ;
4670+ _objectPageController . Add ( _nextPageButton ) ;
4671+
4672+ objectColumn . Add ( _objectPageController ) ;
4673+
46134674 _objectScrollView = new ScrollView ( ScrollViewMode . Vertical )
46144675 {
46154676 name = "object-scrollview" ,
@@ -5743,9 +5804,42 @@ internal void BuildObjectsView()
57435804 return ;
57445805 }
57455806
5746- for ( int i = 0 ; i < _filteredObjects . Count ; i ++ )
5807+ if ( _filteredObjects . Count <= MaxObjectsPerPage )
5808+ {
5809+ if ( _objectPageController != null )
5810+ {
5811+ _objectPageController . style . display = DisplayStyle . None ;
5812+ }
5813+ for ( int i = 0 ; i < _filteredObjects . Count ; i ++ )
5814+ {
5815+ BuildObjectRow ( _filteredObjects [ i ] , i ) ;
5816+ }
5817+ }
5818+ else
57475819 {
5748- BuildObjectRow ( _filteredObjects [ i ] , i ) ;
5820+ if ( _objectPageController != null )
5821+ {
5822+ _objectPageController . style . display = DisplayStyle . Flex ;
5823+ }
5824+
5825+ _maxPageField . value = _filteredObjects . Count / MaxObjectsPerPage ;
5826+ int currentPage = GetCurrentPage ( _namespaceController . SelectedType ) ;
5827+ currentPage = Mathf . Clamp ( currentPage , 0 , _filteredObjects . Count / MaxObjectsPerPage ) ;
5828+ _currentPageField . SetValueWithoutNotify ( currentPage ) ;
5829+
5830+ _previousPageButton . EnableInClassList ( "go-button-disabled" , currentPage <= 0 ) ;
5831+ _previousPageButton . EnableInClassList ( StyleConstants . ActionButtonClass , 0 < currentPage ) ;
5832+ _previousPageButton . EnableInClassList ( "go-button" , 0 < currentPage ) ;
5833+
5834+ _nextPageButton . EnableInClassList ( "go-button-disabled" , _maxPageField . value <= currentPage ) ;
5835+ _nextPageButton . EnableInClassList ( StyleConstants . ActionButtonClass , currentPage < _maxPageField . value ) ;
5836+ _nextPageButton . EnableInClassList ( "go-button" , currentPage < _maxPageField . value ) ;
5837+
5838+ int max = Mathf . Min ( ( currentPage + 1 ) * MaxObjectsPerPage , _filteredObjects . Count ) ;
5839+ for ( int i = currentPage * MaxObjectsPerPage ; i < max ; i ++ )
5840+ {
5841+ BuildObjectRow ( _filteredObjects [ i ] , i ) ;
5842+ }
57495843 }
57505844 }
57515845
@@ -5779,12 +5873,12 @@ private void BuildObjectRow(ScriptableObject dataObject, int index)
57795873
57805874 Button goUpButton = new ( ( ) =>
57815875 {
5782- _objectListContainer . Remove ( objectItemRow ) ;
5783- _objectListContainer . Insert ( 1 , objectItemRow ) ;
5784- foreach ( VisualElement child in _objectListContainer . Children ( ) )
5785- {
5786- NamespaceController . RecalibrateVisualElements ( child , offset : 1 ) ;
5787- }
5876+ _filteredObjects . Remove ( dataObject ) ;
5877+ _filteredObjects . Insert ( 0 , dataObject ) ;
5878+ _filteredObjects . Remove ( dataObject ) ;
5879+ _filteredObjects . Insert ( 0 , dataObject ) ;
5880+ UpdateAndSaveObjectOrderList ( dataObject . GetType ( ) , _selectedObjects ) ;
5881+ BuildObjectsView ( ) ;
57885882 } )
57895883 {
57905884 name = "go-up-button" ,
@@ -5805,12 +5899,12 @@ private void BuildObjectRow(ScriptableObject dataObject, int index)
58055899
58065900 Button goDownButton = new ( ( ) =>
58075901 {
5808- _objectListContainer . Remove ( objectItemRow ) ;
5809- _objectListContainer . Insert ( _objectListContainer . childCount , objectItemRow ) ;
5810- foreach ( VisualElement child in _objectListContainer . Children ( ) )
5811- {
5812- NamespaceController . RecalibrateVisualElements ( child , offset : 1 ) ;
5813- }
5902+ _selectedObjects . Remove ( dataObject ) ;
5903+ _selectedObjects . Add ( dataObject ) ;
5904+ _filteredObjects . Remove ( dataObject ) ;
5905+ _filteredObjects . Add ( dataObject ) ;
5906+ UpdateAndSaveObjectOrderList ( dataObject . GetType ( ) , _selectedObjects ) ;
5907+ BuildObjectsView ( ) ;
58145908 } )
58155909 {
58165910 name = "go-down-button" ,
@@ -6910,7 +7004,7 @@ internal void LoadObjectTypes(Type type)
69107004 _selectedObjects . Clear ( ) ;
69117005 _objectVisualElementMap . Clear ( ) ;
69127006
6913- List < string > customGuidOrder = GetObjectOrderForType ( type . FullName ) ;
7007+ List < string > customGuidOrder = GetObjectOrderForType ( type ) ;
69147008 Dictionary < string , ScriptableObject > objectsByGuid = new ( ) ;
69157009 string [ ] assetGuids = AssetDatabase . FindAssets ( $ "t:{ type . Name } ") ;
69167010 foreach ( string assetGuid in assetGuids )
@@ -6956,8 +7050,15 @@ internal void LoadObjectTypes(Type type)
69567050
69577051 List < ScriptableObject > remainingObjects = objectsByGuid . Values . ToList ( ) ;
69587052 remainingObjects . Sort (
6959- ( a , b ) => string . Compare ( a . name , b . name , StringComparison . OrdinalIgnoreCase )
6960- ) ;
7053+ ( a , b ) =>
7054+ {
7055+ int comparison = string . Compare ( a . name , b . name , StringComparison . OrdinalIgnoreCase ) ;
7056+ if ( comparison != 0 )
7057+ {
7058+ return comparison ;
7059+ }
7060+ return string . Compare ( AssetDatabase . GetAssetPath ( a ) , AssetDatabase . GetAssetPath ( b ) , StringComparison . OrdinalIgnoreCase ) ;
7061+ } ) ;
69617062 sortedObjects . AddRange ( remainingObjects ) ;
69627063
69637064 _selectedObjects . Clear ( ) ;
@@ -8011,9 +8112,9 @@ private string GetLastSelectedNamespaceKey()
80118112 : UserState . lastSelectedNamespaceKey ;
80128113 }
80138114
8014- private List < string > GetObjectOrderForType ( string typeFullName )
8115+ private List < string > GetObjectOrderForType ( Type type )
80158116 {
8016- if ( string . IsNullOrWhiteSpace ( typeFullName ) )
8117+ if ( type == null )
80178118 {
80188119 return new List < string > ( ) ;
80198120 }
@@ -8023,19 +8124,85 @@ private List<string> GetObjectOrderForType(string typeFullName)
80238124 if ( settings . persistStateInSettingsAsset )
80248125 {
80258126 TypeObjectOrder entry = settings . objectOrders ? . Find ( o =>
8026- string . Equals ( o . TypeFullName , typeFullName , StringComparison . Ordinal )
8127+ string . Equals ( o . TypeFullName , type . FullName , StringComparison . Ordinal )
80278128 ) ;
80288129 return entry ? . ObjectGuids ? . ToList ( ) ?? new List < string > ( ) ;
80298130 }
80308131 else
80318132 {
80328133 TypeObjectOrder entry = UserState . objectOrders ? . Find ( o =>
8033- string . Equals ( o . TypeFullName , typeFullName , StringComparison . Ordinal )
8134+ string . Equals ( o . TypeFullName , type . FullName , StringComparison . Ordinal )
80348135 ) ;
80358136 return entry ? . ObjectGuids ? . ToList ( ) ?? new List < string > ( ) ;
80368137 }
80378138 }
80388139
8140+ private int GetCurrentPage ( Type type )
8141+ {
8142+ DataVisualizerSettings settings = Settings ;
8143+ if ( settings . persistStateInSettingsAsset )
8144+ {
8145+ TypeObjectOrder entry = settings . objectOrders ? . Find ( o =>
8146+ string . Equals ( o . TypeFullName , type . FullName , StringComparison . Ordinal )
8147+ ) ;
8148+ return entry ? . page ?? 0 ;
8149+ }
8150+ else
8151+ {
8152+ TypeObjectOrder entry = UserState . objectOrders ? . Find ( o =>
8153+ string . Equals ( o . TypeFullName , type . FullName , StringComparison . Ordinal )
8154+ ) ;
8155+ return entry ? . page ?? 0 ;
8156+ }
8157+ }
8158+
8159+ private void SetCurrentPage ( Type type , int page )
8160+ {
8161+ PersistSettings ( settings =>
8162+ {
8163+ bool dirty = false ;
8164+ TypeObjectOrder entry = settings . objectOrders ? . Find ( o =>
8165+ string . Equals ( o . TypeFullName , type . FullName , StringComparison . Ordinal )
8166+ ) ;
8167+ if ( entry == null )
8168+ {
8169+ entry = new TypeObjectOrder ( ) ;
8170+ settings . objectOrders ??= new List < TypeObjectOrder > ( ) ;
8171+ settings . objectOrders . Add ( entry ) ;
8172+ dirty = true ;
8173+ }
8174+
8175+ if ( page != entry . page )
8176+ {
8177+ dirty = true ;
8178+ entry . page = page ;
8179+ }
8180+
8181+ return dirty ;
8182+ } , userState =>
8183+ {
8184+ bool dirty = false ;
8185+ TypeObjectOrder entry = userState . objectOrders ? . Find ( o =>
8186+ string . Equals ( o . TypeFullName , type . FullName , StringComparison . Ordinal )
8187+ ) ;
8188+ if ( entry == null )
8189+ {
8190+ entry = new TypeObjectOrder ( ) ;
8191+ userState . objectOrders ??= new List < TypeObjectOrder > ( ) ;
8192+ userState . objectOrders . Add ( entry ) ;
8193+ dirty = true ;
8194+ }
8195+
8196+ if ( page != entry . page )
8197+ {
8198+ dirty = true ;
8199+ entry . page = page ;
8200+ }
8201+
8202+ return dirty ;
8203+ } ) ;
8204+ }
8205+
80398206 private void SetObjectOrderForType ( string typeFullName , List < string > objectGuids )
80408207 {
80418208 if ( string . IsNullOrWhiteSpace ( typeFullName ) || objectGuids == null )
0 commit comments