1+ using System ;
2+ using System . Collections . Generic ;
3+ using UnityEditor ;
4+ using UnityEditorInternal ;
5+ using UnityEngine ;
6+ using PopupWindow = UnityEditor . PopupWindow ;
7+
8+ namespace GBG . PlayableGraphMonitor . Editor
9+ {
10+ public class SearchablePopupWindowContent < T > : PopupWindowContent
11+ {
12+ public static void Show ( Rect activatorRect , GetChoices choicesProvider , Action < T > itemSelected ,
13+ Func < T , string > formatListItemCallback = null , Func < T , string > formatSelectedValueCallback = null )
14+ {
15+ PopupWindow . Show ( activatorRect , new SearchablePopupWindowContent < T > ( choicesProvider , itemSelected ,
16+ formatListItemCallback , formatSelectedValueCallback ) ) ;
17+ }
18+
19+
20+ public delegate void GetChoices ( out IList < T > choices , out int selectionIndex ) ;
21+
22+ private readonly GetChoices _choicesProvider ;
23+ private readonly Action < T > _itemSelected ;
24+ private readonly Func < T , string > _formatListItemCallback ;
25+ private readonly Func < T , string > _formatSelectedValueCallback ;
26+
27+ private string _searchContent ;
28+ private Vector2 _scrollPosition ;
29+ private List < T > _filteredChoices ;
30+ private ReorderableList _list ;
31+
32+ public Vector2 minSize { get ; set ; } = new Vector2 ( 300 , 200 ) ;
33+ public Vector2 maxSize { get ; set ; } = new Vector2 ( 900 , 600 ) ;
34+
35+
36+ public SearchablePopupWindowContent ( GetChoices choicesProvider , Action < T > itemSelected ,
37+ Func < T , string > formatListItemCallback = null , Func < T , string > formatSelectedValueCallback = null )
38+ {
39+ _choicesProvider = choicesProvider ?? throw new ArgumentNullException ( nameof ( choicesProvider ) ) ;
40+ _itemSelected = itemSelected ;
41+ _formatListItemCallback = formatListItemCallback ;
42+ _formatSelectedValueCallback = formatSelectedValueCallback ?? formatListItemCallback ;
43+ }
44+
45+ public override void OnOpen ( )
46+ {
47+ base . OnOpen ( ) ;
48+
49+ IList < T > allChoices = null ;
50+ int currentSelection = - 1 ;
51+ _choicesProvider ? . Invoke ( out allChoices , out currentSelection ) ;
52+
53+ _filteredChoices = new List < T > ( allChoices ?? Array . Empty < T > ( ) ) ;
54+ _list = new ReorderableList ( _filteredChoices , typeof ( T ) )
55+ {
56+ index = currentSelection ,
57+ displayAdd = false ,
58+ displayRemove = false ,
59+ headerHeight = 0 ,
60+ footerHeight = 0 ,
61+ draggable = false ,
62+ onMouseUpCallback = OnMouseUp ,
63+ drawElementCallback = DrawElement ,
64+ drawElementBackgroundCallback = DrawElementBackground ,
65+ } ;
66+ }
67+
68+ public override void OnGUI ( Rect rect )
69+ {
70+ const string SEARCH_CONTROL = "SearchablePopupWindowContent.ToolbarSearchField" ;
71+
72+ EditorGUI . BeginChangeCheck ( ) ;
73+ {
74+ GUI . SetNextControlName ( SEARCH_CONTROL ) ;
75+ _searchContent = EditorGUILayoutHelper . ToolbarSearchField ( _searchContent ) ;
76+ EditorGUI . FocusTextInControl ( SEARCH_CONTROL ) ;
77+ }
78+ if ( EditorGUI . EndChangeCheck ( ) )
79+ {
80+ IList < T > allChoices = null ;
81+ int currentSelection = - 1 ;
82+ _choicesProvider ? . Invoke ( out allChoices , out currentSelection ) ;
83+ allChoices = allChoices ?? Array . Empty < T > ( ) ;
84+
85+ _filteredChoices . Clear ( ) ;
86+ for ( int i = 0 ; i < allChoices . Count ; i ++ )
87+ {
88+ string elemDisplayName = GetElementDisplayName ( allChoices , i , currentSelection == i ) ;
89+ if ( elemDisplayName . IndexOf ( _searchContent , StringComparison . OrdinalIgnoreCase ) >= 0 )
90+ _filteredChoices . Add ( allChoices [ i ] ) ;
91+ }
92+
93+ _list . list = _filteredChoices ;
94+ }
95+
96+ _scrollPosition = EditorGUILayout . BeginScrollView ( _scrollPosition ) ;
97+ _list . DoLayoutList ( ) ;
98+ EditorGUILayout . EndScrollView ( ) ;
99+
100+ editorWindow . Repaint ( ) ;
101+ }
102+
103+ public override Vector2 GetWindowSize ( )
104+ {
105+ IList < T > allChoices = null ;
106+ int currentSelection = - 1 ;
107+ _choicesProvider ? . Invoke ( out allChoices , out currentSelection ) ;
108+ allChoices = allChoices ?? Array . Empty < T > ( ) ;
109+ T currentValue = currentSelection == - 1 ? default : allChoices [ currentSelection ] ;
110+
111+ GUIContent tempLabelContent = new GUIContent ( ) ;
112+ float maxItemWidth = 0 ;
113+ foreach ( T item in allChoices )
114+ {
115+ string label = item ? . GetHashCode ( ) == currentValue ? . GetHashCode ( )
116+ ? _formatSelectedValueCallback ? . Invoke ( item ) ?? item ? . ToString ( ) ?? string . Empty
117+ : _formatListItemCallback ? . Invoke ( item ) ?? item ? . ToString ( ) ?? string . Empty ;
118+ tempLabelContent . text = label ;
119+ float width = EditorStyles . toolbarPopup . CalcSize ( tempLabelContent ) . x + 12 ;
120+ if ( width > maxItemWidth )
121+ maxItemWidth = width ;
122+ }
123+
124+ float listHeight = _list . elementHeight * _list . count + 36 ;
125+ Vector2 size = new Vector2
126+ {
127+ x = Mathf . Clamp ( maxItemWidth , minSize . x , maxSize . x ) ,
128+ y = Mathf . Clamp ( listHeight , minSize . y , maxSize . y ) ,
129+ } ;
130+
131+ return size ;
132+ }
133+
134+
135+ private string GetElementDisplayName ( IList < T > elements , int index , bool isActive )
136+ {
137+ T item = elements [ index ] ;
138+ string text ;
139+ if ( isActive )
140+ text = _formatSelectedValueCallback ? . Invoke ( item ) ?? item . ToString ( ) ;
141+ else
142+ text = _formatListItemCallback ? . Invoke ( item ) ?? item . ToString ( ) ;
143+
144+ return text ;
145+ }
146+
147+ private void DrawElementBackground ( Rect rect , int index , bool isActive , bool isFocused )
148+ {
149+ if ( isActive )
150+ {
151+ EditorGUI . DrawRect ( rect , new Color ( 0.24f , 0.48f , 0.90f , 0.5f ) ) ;
152+ }
153+ else if ( isFocused )
154+ {
155+ EditorGUI . DrawRect ( rect , new Color ( 0.24f , 0.48f , 0.90f , 0.2f ) ) ;
156+ }
157+ else if ( rect . Contains ( Event . current . mousePosition ) )
158+ {
159+ EditorGUI . DrawRect ( rect , new Color ( 0.24f , 0.48f , 0.90f , 0.1f ) ) ;
160+ }
161+ }
162+
163+ private void DrawElement ( Rect rect , int index , bool isActive , bool isFocused )
164+ {
165+ string text = GetElementDisplayName ( _filteredChoices , index , isActive ) ;
166+ GUI . Label ( rect , text ) ;
167+ }
168+
169+ private void OnMouseUp ( ReorderableList list )
170+ {
171+ T newSelection = _filteredChoices [ list . index ] ;
172+ editorWindow . Close ( ) ;
173+ _itemSelected ? . Invoke ( newSelection ) ;
174+ }
175+ }
176+ }
0 commit comments