forked from Unity-Technologies/UnityCsReference
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathExposablePopupMenu.cs
235 lines (194 loc) · 8.55 KB
/
ExposablePopupMenu.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
// Unity C# reference source
// Copyright (c) Unity Technologies. For terms of use, see
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
using System.Collections.Generic;
using System.Linq;
using System.IO;
using UnityEditorInternal;
using UnityEngine;
namespace UnityEditor
{
internal class ExposablePopupMenu
{
public class ItemData
{
public ItemData(GUIContent content, GUIStyle style, bool on, bool enabled, object userData)
{
m_GUIContent = content;
m_Style = style;
m_On = on;
m_Enabled = enabled;
m_UserData = userData;
}
public GUIContent m_GUIContent;
public GUIStyle m_Style;
public bool m_On;
public bool m_Enabled;
public object m_UserData;
public float m_Width;
public float m_Height;
}
public class PopupButtonData
{
public PopupButtonData(GUIContent content, GUIStyle style)
{
m_GUIContent = content;
m_Style = style;
}
public GUIContent m_GUIContent;
public GUIStyle m_Style;
}
List<ItemData> m_Items;
float m_ItemSpacing;
PopupButtonData m_PopupButtonData;
GUIContent m_Label;
int[] m_ItemControlIDs;
int m_DropDownButtonControlID;
static readonly int s_ItemHash = "ItemButton".GetHashCode();
static readonly int m_DropDownButtonHash = "DropDownButton".GetHashCode();
float m_SpacingLabelToButton = 5f;
float m_WidthOfLabel;
float m_WidthOfButtons;
float m_MinWidthOfPopup;
Vector2 m_PopupButtonSize = Vector2.zero;
System.Action<ItemData> m_SelectionChangedCallback = null; // <userData>
public float widthOfButtonsAndLabel { get { return m_WidthOfButtons + labelAndSpacingWidth; } }
public float widthOfPopupAndLabel { get { return m_PopupButtonSize.x + labelAndSpacingWidth; } }
public bool rightAligned { get; set; }
float labelAndSpacingWidth { get { return m_WidthOfLabel > 0 ? m_WidthOfLabel + m_SpacingLabelToButton : 0f; } }
bool hasLabel { get { return m_Label != null && m_Label != GUIContent.none; } }
public void Init(List<ItemData> items, float itemSpacing, float minWidthOfPopup, PopupButtonData popupButtonData, System.Action<ItemData> selectionChangedCallback)
{
Init(GUIContent.none, items, itemSpacing, minWidthOfPopup, popupButtonData, selectionChangedCallback);
}
public void Init(GUIContent label, List<ItemData> items, float itemSpacing, float minWidthOfPopup, PopupButtonData popupButtonData, System.Action<ItemData> selectionChangedCallback)
{
m_Label = label;
m_Items = items;
m_ItemSpacing = itemSpacing;
m_PopupButtonData = popupButtonData;
m_SelectionChangedCallback = selectionChangedCallback;
m_MinWidthOfPopup = minWidthOfPopup;
CalcWidths();
}
public float OnGUI(Rect rect)
{
// To ensure we allocate a consistent amount of controlIDs on every OnGUI we preallocate before any logic
if (m_Items.Count > 0 && (m_ItemControlIDs == null || m_ItemControlIDs.Length != m_Items.Count))
m_ItemControlIDs = new int[m_Items.Count];
for (int i = 0; i < m_Items.Count; ++i)
m_ItemControlIDs[i] = GUIUtility.GetControlID(s_ItemHash, FocusType.Passive);
m_DropDownButtonControlID = GUIUtility.GetControlID(m_DropDownButtonHash, FocusType.Passive);
if (rect.width >= widthOfButtonsAndLabel && rect.width > m_MinWidthOfPopup)
{
// Show as buttons
if (hasLabel)
{
Rect labelRect = rect;
labelRect.width = m_WidthOfLabel;
if (rightAligned)
labelRect.x = rect.xMax - widthOfButtonsAndLabel;
GUI.Label(labelRect, m_Label, EditorStyles.boldLabel);
rect.xMin += (m_WidthOfLabel + m_SpacingLabelToButton);
}
Rect buttonRect = rect;
buttonRect.width = widthOfButtonsAndLabel;
if (rightAligned)
buttonRect.x = rect.xMax - m_WidthOfButtons;
for (int i = 0; i < m_Items.Count; ++i)
{
var item = m_Items[i];
buttonRect.width = item.m_Width;
buttonRect.y = rect.y + (rect.height - item.m_Height) / 2;
buttonRect.height = item.m_Height;
EditorGUI.BeginChangeCheck();
using (new EditorGUI.DisabledScope(!item.m_Enabled))
{
GUI.Toggle(buttonRect, m_ItemControlIDs[i], item.m_On, item.m_GUIContent, item.m_Style);
}
if (EditorGUI.EndChangeCheck())
{
SelectionChanged(item);
GUIUtility.ExitGUI(); // To make sure we can survive if m_Buttons are reallocated in the callback we exit gui
}
buttonRect.x += item.m_Width + m_ItemSpacing;
}
return widthOfButtonsAndLabel;
}
else
{
// Show as popup
var dropDownRect = rect;
if (hasLabel)
{
Rect labelRect = dropDownRect;
labelRect.width = m_WidthOfLabel;
if (rightAligned)
labelRect.x = rect.xMax - widthOfPopupAndLabel;
GUI.Label(labelRect, m_Label, EditorStyles.boldLabel);
dropDownRect.x = labelRect.x + (m_WidthOfLabel + m_SpacingLabelToButton);
}
else
{
if (rightAligned)
dropDownRect.x = rect.xMax - dropDownRect.width;
}
dropDownRect.width = Mathf.Clamp(dropDownRect.width, 0, m_PopupButtonSize.x);
dropDownRect.height = m_PopupButtonSize.y;
dropDownRect.y = rect.y + (rect.height - dropDownRect.height) / 2;
if (EditorGUI.DropdownButton(m_DropDownButtonControlID, dropDownRect, m_PopupButtonData.m_GUIContent, m_PopupButtonData.m_Style))
PopUpMenu.Show(dropDownRect, m_Items, this);
return widthOfPopupAndLabel;
}
}
void CalcWidths()
{
// Buttons
m_WidthOfButtons = 0f;
foreach (var item in m_Items)
{
var itemSize = item.m_Style.CalcSize(item.m_GUIContent);
item.m_Width = itemSize.x;
item.m_Height = itemSize.y;
m_WidthOfButtons += item.m_Width;
}
m_WidthOfButtons += (m_Items.Count - 1) * m_ItemSpacing;
// Popup
m_PopupButtonSize = m_PopupButtonData.m_Style.CalcSize(m_PopupButtonData.m_GUIContent);
// Label
m_WidthOfLabel = hasLabel ? EditorStyles.boldLabel.CalcSize(m_Label).x : 0;
}
void SelectionChanged(ItemData item)
{
if (m_SelectionChangedCallback != null)
m_SelectionChangedCallback(item);
else
Debug.LogError("Callback is null");
}
internal class PopUpMenu
{
static List<ItemData> m_Data;
static ExposablePopupMenu m_Caller;
static internal void Show(Rect activatorRect, List<ItemData> buttonData, ExposablePopupMenu caller)
{
m_Data = buttonData;
m_Caller = caller;
GenericMenu menu = new GenericMenu();
foreach (ItemData item in m_Data)
if (item.m_Enabled)
menu.AddItem(item.m_GUIContent, item.m_On, SelectionCallback, item);
else
menu.AddDisabledItem(item.m_GUIContent);
menu.DropDown(activatorRect);
}
static void SelectionCallback(object userData)
{
ItemData item = (ItemData)userData;
m_Caller.SelectionChanged(item);
// Cleanup
m_Caller = null;
m_Data = null;
}
}
}
} // end namespace UnityEditor