├── .gitignore
├── Attributes.cs
├── Editor
├── EditorHelper.cs
├── EditorHelper.cs.meta
├── PropertyDrawer.cs
├── PropertyDrawer.cs.meta
├── SelectionWizard.cs
└── SelectionWizard.cs.meta
├── Example
├── DemoObject.cs
├── DemoObject.cs.meta
├── Editor.meta
└── Editor
│ ├── Base32Encoding.cs
│ ├── Base32Encoding.cs.meta
│ ├── DemoScenarios.cs
│ ├── DemoScenarios.cs.meta
│ ├── SampleEditor.cs
│ └── SampleEditor.cs.meta
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | /[Ll]ibrary/
2 | /[Tt]emp/
3 | /[Oo]bj/
4 | /[Bb]uild/
5 | /[Bb]uilds/
6 | /Assets/AssetStoreTools*
7 |
8 | # Autogenerated VS/MD solution and project files
9 | ExportedObj/
10 | *.csproj
11 | *.unityproj
12 | *.sln
13 | *.suo
14 | *.tmp
15 | *.user
16 | *.userprefs
17 | *.pidb
18 | *.booproj
19 | *.svd
20 |
21 |
22 | # Unity3D generated meta files
23 | *.pidb.meta
24 |
25 | # Unity3D Generated File On Crash Reports
26 | sysinfo.txt
27 | /*.meta
28 |
--------------------------------------------------------------------------------
/Attributes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 |
4 | namespace UnityEditorHelper
5 | {
6 | public class LayerAttribute : PropertyAttribute { }
7 |
8 | public class LimitAttribute : PropertyAttribute
9 | {
10 | private enum Mode { LimitLower, LimitUpper, LimitBoth }
11 |
12 | private readonly Mode _limitMode;
13 |
14 | private readonly int _lowerLimit;
15 | private readonly int _upperLimit;
16 |
17 | public LimitAttribute(int lowerLimit) : this(Mode.LimitLower, lowerLimit, int.MaxValue) { }
18 |
19 | public LimitAttribute(int lowerLimit, int upperLimit) : this(Mode.LimitBoth, lowerLimit, upperLimit) { }
20 |
21 | private LimitAttribute(Mode mode, int lowerLimit, int upperLimit)
22 | {
23 | _limitMode = mode;
24 | _lowerLimit = lowerLimit;
25 | _upperLimit = upperLimit;
26 | }
27 |
28 | public int Limit(int value)
29 | {
30 | switch (_limitMode)
31 | {
32 | case Mode.LimitLower:
33 | return Mathf.Clamp(value, _lowerLimit, int.MaxValue);
34 | case Mode.LimitUpper:
35 | return Mathf.Clamp(value, int.MinValue, _upperLimit);
36 | case Mode.LimitBoth:
37 | return Mathf.Clamp(value, _lowerLimit, _upperLimit);
38 | default:
39 | throw new ArgumentOutOfRangeException();
40 | }
41 | }
42 | }
43 |
44 | public class SortingLayerAttribute : PropertyAttribute { }
45 |
46 | public class TagAttribute : PropertyAttribute { }
47 | }
--------------------------------------------------------------------------------
/Editor/EditorHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using UnityEditor;
4 | using UnityEngine;
5 |
6 | namespace UnityEditorHelper
7 | {
8 | public static class EditorHelper
9 | {
10 | private static GUIStyle _simpleRectStyle;
11 |
12 | public static GUIStyle SimpleRectStyle
13 | {
14 | get
15 | {
16 | if (_simpleRectStyle != null)
17 | return _simpleRectStyle;
18 |
19 | Texture2D simpleTexture = new Texture2D(1, 1);
20 | simpleTexture.SetPixel(0, 0, Color.white);
21 | simpleTexture.Apply();
22 | return _simpleRectStyle = new GUIStyle { normal = { background = simpleTexture } };
23 | }
24 | }
25 |
26 | private static Texture2D _checkerboard;
27 |
28 | public static Texture2D Checkerboard
29 | {
30 | get
31 | {
32 | return _checkerboard ?? (_checkerboard = CreateCheckerTex(
33 | new Color(0.1f, 0.1f, 0.1f, 0.5f),
34 | new Color(0.2f, 0.2f, 0.2f, 0.5f)));
35 | }
36 | }
37 |
38 | #region Utility Functions
39 |
40 | public static string GetAssetPath(string assetFileName)
41 | {
42 | if (!AssetDatabase.GetAllAssetPaths().Any(p => p.EndsWith(assetFileName)))
43 | {
44 | AssetDatabase.Refresh();
45 | }
46 | string basePath = AssetDatabase.GetAllAssetPaths().First(p => p.EndsWith(assetFileName));
47 | int lastDelimiter = basePath.LastIndexOf('/') + 1;
48 | basePath = basePath.Remove(lastDelimiter, basePath.Length - lastDelimiter);
49 | return basePath;
50 | }
51 |
52 | public static GUIStyle GetEditorStyle(string style)
53 | {
54 | return EditorGUIUtility.GetBuiltinSkin(EditorGUIUtility.isProSkin ? EditorSkin.Scene : EditorSkin.Inspector).GetStyle(style);
55 | }
56 |
57 | public static GUIStyle GetColoredTextStyle(Color color, FontStyle fontStyle)
58 | {
59 | return new GUIStyle
60 | {
61 | normal = { textColor = color },
62 | fontStyle = fontStyle
63 | };
64 | }
65 |
66 | public static int IndexOf(this SerializedProperty prop, string value)
67 | {
68 | if (!prop.isArray)
69 | return -1;
70 | for (int i = 0; i < prop.arraySize; i++)
71 | {
72 | if (prop.GetArrayElementAtIndex(i).stringValue.Equals(value))
73 | return i;
74 | }
75 | return -1;
76 | }
77 |
78 | public static Vector3 ScrollableSelectableLabel(Vector3 position, string text, GUIStyle style)
79 | {
80 | // Source: yoyo @ https://answers.unity.com/questions/255119/selectablelabel-or-textarea-in-scrollview.html
81 | // Extract scroll position and width from position vector.
82 | Vector2 scrollPos = new Vector2(position.x, position.y);
83 | float width = position.z;
84 | float pixelHeight = style.CalcHeight(new GUIContent(text), width);
85 |
86 | scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.Height(pixelHeight + 10));
87 | // Calculate height of text.
88 | EditorGUILayout.SelectableLabel(text, style, GUILayout.Height(pixelHeight));
89 | // Update the width on repaint, based on width of the SelectableLabel's rectangle.
90 | if (Event.current.type == EventType.Repaint)
91 | {
92 | width = GUILayoutUtility.GetLastRect().width;
93 | }
94 | EditorGUILayout.EndScrollView();
95 | // Put scroll position and width back into the Vector3 used to track position.
96 | return new Vector3(scrollPos.x, scrollPos.y, width);
97 | }
98 |
99 | #endregion Utility Functions
100 |
101 | #region GUI Utilities
102 |
103 | public static bool DrawIconHeader(string key, Texture icon, string caption, Color captionColor, bool canToggle = true)
104 | {
105 | bool state = EditorPrefs.GetBool(key, true);
106 | EditorGUILayout.BeginHorizontal();
107 | {
108 | EditorGUILayout.LabelField(new GUIContent(icon), EditorStyles.miniLabel, GUILayout.Width(22), GUILayout.Height(22));
109 | using (new SwitchBackgroundColor(captionColor))
110 | {
111 | EditorGUILayout.BeginVertical();
112 | GUILayout.Space(5);
113 | GUIStyle style = new GUIStyle { normal = { textColor = captionColor }, fontStyle = FontStyle.Bold };
114 | EditorGUILayout.LabelField(caption, style);
115 | EditorGUILayout.EndVertical();
116 | }
117 | EditorGUILayout.Space();
118 | string cap = state ? "\u25bc" : "\u25b2";
119 | if (canToggle)
120 | {
121 | if (GUILayout.Button(cap, EditorStyles.label, GUILayout.Width(16), GUILayout.Height(16)))
122 | {
123 | state = !state;
124 | EditorPrefs.SetBool(key, state);
125 | }
126 | }
127 | }
128 | EditorGUILayout.EndHorizontal();
129 | GUILayout.Space(2);
130 | return state;
131 | }
132 |
133 | public static void GUIDrawRect(Rect position, Color color)
134 | {
135 | using (new SwitchColor(color))
136 | {
137 | GUI.Box(position, GUIContent.none, SimpleRectStyle);
138 | }
139 | }
140 |
141 | public static void DrawTiledTexture(Rect rect, Texture tex)
142 | {
143 | GUI.BeginGroup(rect);
144 | {
145 | int width = Mathf.RoundToInt(rect.width);
146 | int height = Mathf.RoundToInt(rect.height);
147 |
148 | for (int y = 0; y < height; y += tex.height)
149 | {
150 | for (int x = 0; x < width; x += tex.width)
151 | {
152 | GUI.DrawTexture(new Rect(x, y, tex.width, tex.height), tex);
153 | }
154 | }
155 | }
156 | GUI.EndGroup();
157 | }
158 |
159 | public static Texture2D CreateCheckerTex(Color c0, Color c1, int size = 16, int columns = 2)
160 | {
161 | if (columns > size)
162 | throw new ArgumentOutOfRangeException("Cannot generate Checkerboard texture with more columns than texture has pixels");
163 | if (size % columns != 0)
164 | throw new ArgumentOutOfRangeException("Size has to be dividable by columns");
165 |
166 | Texture2D tex = new Texture2D(size, size)
167 | {
168 | name = "[EditorHelper] Checker Texture",
169 | hideFlags = HideFlags.DontSave
170 | };
171 |
172 | int fieldSize = size / columns;
173 | for (int y = 0; y < size; y++)
174 | {
175 | for (int x = 0; x < size; x++)
176 | {
177 | if (y / fieldSize % 2 != 0)
178 | tex.SetPixel(x, y, y / fieldSize % 2 == 0 || x / fieldSize % 2 == 0 ? c1 : c0);
179 | else
180 | tex.SetPixel(x, y, y / fieldSize % 2 != 0 || x / fieldSize % 2 != 0 ? c1 : c0);
181 | }
182 | }
183 | tex.Apply();
184 | tex.filterMode = FilterMode.Point;
185 | return tex;
186 | }
187 |
188 | public enum OutlineMode { Outside, Centered, Inside }
189 |
190 | public static void DrawOutline(Rect rect, Color color, float borderWidth = 1f, OutlineMode mode = OutlineMode.Outside)
191 | {
192 | if (Event.current.type == EventType.Repaint)
193 | {
194 | Texture2D tex = EditorGUIUtility.whiteTexture;
195 | GUI.color = color;
196 |
197 | switch (mode)
198 | {
199 | case OutlineMode.Outside:
200 | GUI.DrawTexture(new Rect(rect.xMin - borderWidth, rect.yMin - borderWidth, borderWidth, rect.height + borderWidth * 2), tex); // left
201 | GUI.DrawTexture(new Rect(rect.xMax, rect.yMin - borderWidth, borderWidth, rect.height + borderWidth * 2), tex); // right
202 | GUI.DrawTexture(new Rect(rect.xMin, rect.yMin - borderWidth, rect.width, borderWidth), tex); // top
203 | GUI.DrawTexture(new Rect(rect.xMin, rect.yMax, rect.width + borderWidth, borderWidth), tex); // bottom
204 | break;
205 |
206 | case OutlineMode.Centered:
207 | GUI.DrawTexture(new Rect(rect.xMin - borderWidth / 2, rect.yMin - borderWidth / 2, borderWidth, rect.height + borderWidth), tex); // left
208 | GUI.DrawTexture(new Rect(rect.xMax - borderWidth / 2, rect.yMin - borderWidth / 2, borderWidth, rect.height + borderWidth), tex); // right
209 | GUI.DrawTexture(new Rect(rect.xMin - borderWidth / 2, rect.yMin - borderWidth / 2, rect.width + borderWidth, borderWidth), tex); // top
210 | GUI.DrawTexture(new Rect(rect.xMin - borderWidth / 2, rect.yMax - borderWidth / 2, rect.width + borderWidth, borderWidth), tex); // bottom
211 | break;
212 |
213 | case OutlineMode.Inside:
214 | GUI.DrawTexture(new Rect(rect.xMin, rect.yMin, borderWidth, rect.height), tex); // left
215 | GUI.DrawTexture(new Rect(rect.xMax - borderWidth, rect.yMin, borderWidth, rect.height), tex); // right
216 | GUI.DrawTexture(new Rect(rect.xMin, rect.yMin, rect.width, borderWidth), tex); // top
217 | GUI.DrawTexture(new Rect(rect.xMin, rect.yMax - borderWidth, rect.width, borderWidth), tex); // bottom
218 | break;
219 |
220 | default:
221 | throw new ArgumentOutOfRangeException("mode", mode, null);
222 | }
223 |
224 | GUI.color = Color.white;
225 | }
226 | }
227 |
228 | #endregion GUI Utilities
229 | }
230 |
231 | #region Blocks
232 |
233 | public sealed class RoundedBox : IDisposable
234 | {
235 | public RoundedBox()
236 | {
237 | GUILayout.Space(8f);
238 | GUILayout.BeginHorizontal();
239 | GUILayout.Space(4f);
240 | EditorGUILayout.BeginHorizontal(EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector).GetStyle("sv_iconselector_labelselection"), GUILayout.MinHeight(10f));
241 | GUILayout.BeginVertical();
242 | GUILayout.Space(4f);
243 | }
244 |
245 | public void Dispose()
246 | {
247 | GUILayout.Space(3f);
248 | GUILayout.EndVertical();
249 | EditorGUILayout.EndHorizontal();
250 | GUILayout.Space(3f);
251 | GUILayout.EndHorizontal();
252 | GUILayout.Space(3f);
253 | }
254 | }
255 |
256 | public sealed class EditorFrame : IDisposable
257 | {
258 | public EditorFrame(string caption, Color captionColor, int width = -1)
259 | {
260 | if (width == -1)
261 | GUILayout.BeginVertical();
262 | else
263 | GUILayout.BeginVertical(GUILayout.Width(width));
264 |
265 | GUILayout.Space(8);
266 | using (new EditorBlock(EditorBlock.Orientation.Horizontal))
267 | {
268 | GUILayout.Space(11);
269 | using (new EditorBlock(EditorBlock.Orientation.Horizontal, "TL LogicBar 1"))
270 | {
271 | GUILayout.Space(4);
272 | EditorGUILayout.LabelField(caption, EditorHelper.GetColoredTextStyle(captionColor, FontStyle.Bold));
273 | }
274 | GUILayout.FlexibleSpace();
275 | GUILayout.Space(11);
276 | }
277 | GUILayout.Space(-11);
278 |
279 | EditorGUILayout.BeginVertical("GroupBox");
280 | }
281 |
282 | public void Dispose()
283 | {
284 | EditorGUILayout.EndVertical();
285 | EditorGUILayout.EndVertical();
286 | }
287 | }
288 |
289 | public sealed class FoldableEditorFrame : IDisposable
290 | {
291 | public bool Expanded;
292 |
293 | public FoldableEditorFrame(string key, string caption, Color captionColor, Color folderColor, int width = -1)
294 | {
295 | Expanded = EditorPrefs.GetBool(key, true);
296 | Draw(ref Expanded, caption, captionColor, folderColor, width);
297 | EditorPrefs.SetBool(key, Expanded);
298 | }
299 |
300 | public FoldableEditorFrame(ref bool expanded, string caption, Color captionColor, Color folderColor, int width = -1)
301 | {
302 | Draw(ref expanded, caption, captionColor, folderColor, width);
303 | }
304 |
305 | private void Draw(ref bool expanded, string caption, Color captionColor, Color folderColor, int width = -1)
306 | {
307 | Expanded = expanded;
308 |
309 | if (width == -1)
310 | GUILayout.BeginVertical();
311 | else
312 | GUILayout.BeginVertical(GUILayout.Width(width));
313 | GUILayout.Space(8);
314 |
315 | using (new EditorBlock(EditorBlock.Orientation.Horizontal))
316 | {
317 | GUIStyle coloredTextStyle = EditorHelper.GetColoredTextStyle(captionColor, FontStyle.Bold);
318 | float textWidth = coloredTextStyle.CalcSize(new GUIContent(caption)).x + 15;
319 |
320 | GUILayout.Space(11);
321 | expanded = EditorGUILayout.Toggle(expanded, "TL LogicBar 0", GUILayout.Width(Mathf.Max(textWidth, 196)), GUILayout.Height(24));
322 | GUILayout.Space(-Mathf.Max(textWidth, 196) + 4);
323 | using (new EditorBlock(EditorBlock.Orientation.Vertical))
324 | {
325 | GUILayout.Space(6);
326 | EditorGUILayout.LabelField(caption, coloredTextStyle);
327 | }
328 | }
329 | GUILayout.Space(-11);
330 | if (Expanded)
331 | {
332 | using (new SwitchColor(folderColor))
333 | {
334 | EditorGUILayout.BeginVertical("GroupBox", GUILayout.ExpandWidth(true));
335 | }
336 | }
337 | }
338 |
339 | public void Dispose()
340 | {
341 | EditorGUILayout.EndVertical();
342 | if (Expanded)
343 | {
344 | EditorGUILayout.EndVertical();
345 | }
346 | }
347 | }
348 |
349 | public sealed class EditorBlock : IDisposable
350 | {
351 | public enum Orientation
352 | {
353 | Horizontal,
354 | Vertical
355 | }
356 |
357 | private readonly Orientation _orientation;
358 |
359 | public EditorBlock(Orientation orientation, string style, params GUILayoutOption[] options)
360 | {
361 | _orientation = orientation;
362 | if (orientation == Orientation.Horizontal)
363 | {
364 | EditorGUILayout.BeginHorizontal(string.IsNullOrEmpty(style) ? GUIStyle.none : style, options);
365 | }
366 | else
367 | {
368 | EditorGUILayout.BeginVertical(string.IsNullOrEmpty(style) ? GUIStyle.none : style, options);
369 | }
370 | }
371 |
372 | public EditorBlock(Orientation orientation, string style) : this(orientation, style, new GUILayoutOption[] { })
373 | {
374 | }
375 |
376 | public EditorBlock(Orientation orientation) : this(orientation, null, new GUILayoutOption[] { })
377 | {
378 | }
379 |
380 | public EditorBlock(Orientation orientation, params GUILayoutOption[] layoutOptions) : this(orientation, null, layoutOptions)
381 | {
382 | }
383 |
384 | public void Dispose()
385 | {
386 | if (_orientation == Orientation.Horizontal)
387 | {
388 | EditorGUILayout.EndHorizontal();
389 | }
390 | else
391 | {
392 | EditorGUILayout.EndVertical();
393 | }
394 | }
395 | }
396 |
397 | public sealed class SwitchColor : IDisposable
398 | {
399 | private readonly Color _savedColor;
400 |
401 | public SwitchColor(Color newColor)
402 | {
403 | _savedColor = GUI.color;
404 | GUI.color = newColor;
405 | }
406 |
407 | public void Dispose()
408 | {
409 | GUI.color = _savedColor;
410 | }
411 | }
412 |
413 | public sealed class SwitchBackgroundColor : IDisposable
414 | {
415 | private readonly Color _savedColor;
416 |
417 | public SwitchBackgroundColor(Color newColor)
418 | {
419 | _savedColor = GUI.backgroundColor;
420 | GUI.backgroundColor = newColor;
421 | }
422 |
423 | public void Dispose()
424 | {
425 | GUI.backgroundColor = _savedColor;
426 | }
427 | }
428 |
429 | public sealed class SwitchGUIDepth : IDisposable
430 | {
431 | private readonly int _savedDepth;
432 |
433 | public SwitchGUIDepth(int depth)
434 | {
435 | _savedDepth = GUI.depth;
436 | GUI.depth = depth;
437 | }
438 |
439 | public void Dispose()
440 | {
441 | GUI.depth = _savedDepth;
442 | }
443 | }
444 |
445 | public class IndentBlock : IDisposable
446 | {
447 | public IndentBlock()
448 | {
449 | EditorGUI.indentLevel++;
450 | }
451 |
452 | public void Dispose()
453 | {
454 | EditorGUI.indentLevel--;
455 | }
456 | }
457 |
458 | public class ScrollViewBlock : IDisposable
459 | {
460 | public ScrollViewBlock(ref Vector2 scrollPosition, params GUILayoutOption[] options)
461 | {
462 | scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, options);
463 | }
464 |
465 | public void Dispose()
466 | {
467 | EditorGUILayout.EndScrollView();
468 | }
469 | }
470 |
471 | public class PaddedBlock : IDisposable
472 | {
473 | public PaddedBlock(int left, int right, int top, int bottom)
474 | {
475 | GUIStyle style = new GUIStyle(EditorStyles.inspectorDefaultMargins) { padding = new RectOffset(left, right, top, bottom) };
476 | EditorGUILayout.BeginVertical(style);
477 | }
478 |
479 | public PaddedBlock(int padding) : this(padding, padding, padding, padding)
480 | {
481 | }
482 |
483 | public void Dispose()
484 | {
485 | EditorGUILayout.EndVertical();
486 | }
487 | }
488 |
489 | public sealed class FoldableBlock : IDisposable
490 | {
491 | private readonly Color _defaultBackgroundColor;
492 |
493 | private readonly bool _expanded;
494 |
495 | public FoldableBlock(ref bool expanded, string header) : this(ref expanded, header, null)
496 | {
497 | }
498 |
499 | public FoldableBlock(ref bool expanded, string header, Texture2D icon)
500 | {
501 | _defaultBackgroundColor = GUI.backgroundColor;
502 | EditorGUILayout.BeginHorizontal();
503 | GUI.changed = false;
504 | if (!GUILayout.Toggle(true, new GUIContent("" + header + "", icon), "dragtab", GUILayout.MinWidth(20f)))
505 | expanded = !expanded;
506 | EditorGUILayout.EndHorizontal();
507 | GUILayout.Space(-2f);
508 |
509 | if (expanded)
510 | {
511 | GUILayout.BeginHorizontal();
512 | EditorGUILayout.BeginHorizontal("TextArea", GUILayout.MinHeight(10f));
513 | GUILayout.BeginVertical();
514 | }
515 | _expanded = expanded;
516 | }
517 |
518 | public void Dispose()
519 | {
520 | if (_expanded)
521 | {
522 | GUILayout.EndVertical();
523 | EditorGUILayout.EndHorizontal();
524 | GUILayout.EndHorizontal();
525 | GUI.backgroundColor = _defaultBackgroundColor;
526 | }
527 | }
528 | }
529 |
530 | #endregion Blocks
531 | }
--------------------------------------------------------------------------------
/Editor/EditorHelper.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1c3e20c87f936934aaefd4030d9b275b
3 | timeCreated: 1434825476
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Editor/PropertyDrawer.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using UnityEditor;
3 | using UnityEditorInternal;
4 | using UnityEngine;
5 |
6 | namespace UnityEditorHelper
7 | {
8 | [CustomPropertyDrawer(typeof(LayerAttribute))]
9 | public class LayerPropertyDrawer : PropertyDrawer
10 | {
11 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
12 | {
13 | if (property.propertyType != SerializedPropertyType.Integer)
14 | {
15 | Debug.LogWarning("LayerAttribute can only be applied on integer properties/fields");
16 | return;
17 | }
18 |
19 | property.intValue = EditorGUI.LayerField(position, property.name, property.intValue);
20 | }
21 | }
22 |
23 | [CustomPropertyDrawer(typeof(LimitAttribute))]
24 | public class LimitPropertyDrawer : PropertyDrawer
25 | {
26 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
27 | {
28 | if (property.propertyType != SerializedPropertyType.Integer)
29 | {
30 | Debug.LogWarning("LimitAttribute can only be applied on integer properties/fields");
31 | return;
32 | }
33 |
34 | LimitAttribute limiter = (LimitAttribute)attribute;
35 | property.intValue = limiter.Limit(EditorGUI.IntField(position, property.name, property.intValue));
36 | }
37 | }
38 |
39 | [CustomPropertyDrawer(typeof(SortingLayerAttribute))]
40 | public class SortingLayerDrawer : PropertyDrawer
41 | {
42 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
43 | {
44 | if (property.propertyType != SerializedPropertyType.Integer)
45 | {
46 | Debug.LogWarning("SortingLayerAttributes can only be applied on integer properties/fields");
47 | return;
48 | }
49 | EditorGUI.LabelField(position, label);
50 |
51 | position.x += EditorGUIUtility.labelWidth;
52 | position.width -= EditorGUIUtility.labelWidth;
53 |
54 | string[] sortingLayerNames = GetSortingLayerNames();
55 | int[] sortingLayerIDs = GetSortingLayerIDs();
56 |
57 | int sortingLayerIndex = Mathf.Max(0, System.Array.IndexOf(sortingLayerIDs, property.intValue));
58 | sortingLayerIndex = EditorGUI.Popup(position, sortingLayerIndex, sortingLayerNames);
59 | property.intValue = sortingLayerIDs[sortingLayerIndex];
60 | }
61 |
62 | private string[] GetSortingLayerNames()
63 | {
64 | System.Type internalEditorUtilityType = typeof(InternalEditorUtility);
65 | PropertyInfo sortingLayersProperty = internalEditorUtilityType.GetProperty("sortingLayerNames", BindingFlags.Static | BindingFlags.NonPublic);
66 | return (string[])sortingLayersProperty.GetValue(null, new object[0]);
67 | }
68 |
69 | private int[] GetSortingLayerIDs()
70 | {
71 | System.Type internalEditorUtilityType = typeof(InternalEditorUtility);
72 | PropertyInfo sortingLayersProperty = internalEditorUtilityType.GetProperty("sortingLayerUniqueIDs", BindingFlags.Static | BindingFlags.NonPublic);
73 | return (int[])sortingLayersProperty.GetValue(null, new object[0]);
74 | }
75 | }
76 |
77 | [CustomPropertyDrawer(typeof(TagAttribute))]
78 | public class TagPropertyDrawer : PropertyDrawer
79 | {
80 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
81 | {
82 | if (property.propertyType != SerializedPropertyType.String)
83 | {
84 | Debug.LogWarning("TagAttribute can only be applied on string properties/fields");
85 | return;
86 | }
87 |
88 | property.stringValue = EditorGUI.TagField(position, property.name, property.stringValue);
89 | }
90 | }
91 | }
--------------------------------------------------------------------------------
/Editor/PropertyDrawer.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: db7cad7f95703f84ea5d8b4baea7a483
3 | timeCreated: 1434825477
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Editor/SelectionWizard.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using UnityEngine;
5 | using UnityEditor;
6 |
7 | namespace UnityEditorHelper
8 | {
9 | public abstract class SelectionWizard : ScriptableWizard
10 | {
11 | public static SelectionWizard Instance;
12 |
13 | private void OnEnable()
14 | {
15 | Instance = this;
16 | }
17 |
18 | private void OnDisable()
19 | {
20 | Instance = null;
21 | }
22 |
23 | private Vector2 _scrollPos = Vector2.zero;
24 | private string _searchString = "";
25 | protected List Elements;
26 | protected float ItemSize;
27 | protected float Padding;
28 | protected Func SearchStringFilterFunc { get; set; }
29 | private float _clickTime;
30 | protected T Selected;
31 | protected Func TextureGetter;
32 | protected Func CaptionGetter;
33 | protected Action SelectionCallback;
34 |
35 |
36 | private static Texture2D _selectionTexture;
37 | protected static Texture2D selectionTexture { get { return _selectionTexture ?? CreateSelectionTexture(); } }
38 |
39 | const float textHeight = 26;
40 |
41 |
42 | private static Texture2D CreateSelectionTexture()
43 | {
44 | Texture2D tex = new Texture2D(2, 2, TextureFormat.ARGB32, false)
45 | {
46 | name = "[EditorHelper] Selection Texture",
47 | hideFlags = HideFlags.DontSave
48 | };
49 |
50 | tex.SetPixels(new[] { Color.blue, Color.blue, Color.blue, Color.blue });
51 | tex.filterMode = FilterMode.Point;
52 | tex.Apply();
53 | _selectionTexture = tex;
54 | return tex;
55 | }
56 |
57 | public static void Show(string caption, List elements, Func searchStringFilterFunc, Func textureGetter,
58 | Func captionGetter, Action selectionCallback, float itemSize = 80, float padding = 10) where K : SelectionWizard
59 | {
60 | if (Instance != null)
61 | {
62 | Instance.Close();
63 | Instance = null;
64 | }
65 |
66 | SelectionWizard self = DisplayWizard(caption);
67 | self.Elements = elements;
68 | self.SearchStringFilterFunc = searchStringFilterFunc;
69 | self.ItemSize = itemSize;
70 | self.Padding = padding;
71 | self.TextureGetter = textureGetter;
72 | self.CaptionGetter = captionGetter;
73 | self.SelectionCallback = selectionCallback;
74 | }
75 |
76 | private void OnGUI()
77 | {
78 | EditorGUIUtility.labelWidth = 80;
79 | bool close = false;
80 | using (new EditorBlock(EditorBlock.Orientation.Horizontal))
81 | {
82 | GUILayout.Space(84f);
83 | _searchString = EditorGUILayout.TextField("", _searchString, "SearchTextField");
84 |
85 | if (GUILayout.Button("", "SearchCancelButton", GUILayout.Width(18f)))
86 | {
87 | _searchString = "";
88 | GUIUtility.keyboardControl = 0;
89 | }
90 | GUILayout.Space(84);
91 | }
92 |
93 | List elements = Elements.Where(arg => SearchStringFilterFunc.Invoke(arg, _searchString)).ToList();
94 |
95 | float padded = ItemSize + Padding;
96 | int columns = Math.Max(1, Mathf.FloorToInt(Screen.width / padded));
97 | int offset = 0;
98 | Rect rect = new Rect(10, 0, ItemSize, ItemSize);
99 | GUILayout.Space(10f);
100 | using (new ScrollViewBlock(ref _scrollPos))
101 | {
102 | int rows = 1;
103 |
104 | while (offset < elements.Count)
105 | {
106 | using (new EditorBlock(EditorBlock.Orientation.Horizontal))
107 | {
108 | int col = 0;
109 | rect.x = 10;
110 |
111 | for (; offset < elements.Count; ++offset)
112 | {
113 | Rect frame = new Rect(rect);
114 | frame.xMin -= 2;
115 | frame.yMin -= 2;
116 | frame.xMax += 2;
117 | frame.yMax += 8 + textHeight;
118 |
119 | if (Selected != null && ReferenceEquals(Selected, elements[offset]))
120 | {
121 | GUI.DrawTexture(frame, selectionTexture, ScaleMode.StretchToFill);
122 | }
123 |
124 | if (GUI.Button(rect, ""))
125 | {
126 | if (Event.current.button == 0)
127 | {
128 | float delta = Time.realtimeSinceStartup - _clickTime;
129 | _clickTime = Time.realtimeSinceStartup;
130 |
131 | if (!ReferenceEquals(Selected, elements[offset]))
132 | {
133 | Selected = elements[offset];
134 | Repaint();
135 | }
136 | else if (delta < 0.5f)
137 | close = true;
138 | }
139 | }
140 |
141 | if (Event.current.type == EventType.Repaint)
142 | {
143 | GUI.DrawTexture(rect, EditorHelper.Checkerboard, ScaleMode.ScaleToFit);
144 | GUI.DrawTexture(rect, TextureGetter.Invoke(elements[offset]), ScaleMode.ScaleAndCrop);
145 | }
146 |
147 | GUI.backgroundColor = new Color(1f, 1f, 1f, 0.5f);
148 | GUI.contentColor = new Color(1f, 1f, 1f, 0.7f);
149 | GUI.Label(new Rect(rect.x, rect.y + rect.height, rect.width, 32f), CaptionGetter.Invoke(elements[offset]), "ProgressBarBack");
150 | GUI.contentColor = Color.white;
151 | GUI.backgroundColor = Color.white;
152 |
153 | if (++col >= columns)
154 | {
155 | ++offset;
156 | break;
157 | }
158 | rect.x += padded;
159 | }
160 | }
161 | GUILayout.Space(padded);
162 | rect.y += padded + textHeight;
163 | ++rows;
164 | }
165 | GUILayout.Space(rows * textHeight);
166 | }
167 | if (close)
168 | {
169 | if (SelectionCallback != null)
170 | SelectionCallback.Invoke(Selected);
171 | Close();
172 | }
173 | }
174 | }
175 | }
--------------------------------------------------------------------------------
/Editor/SelectionWizard.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 663cd1bdf8d65ea47b88ee6f954a393b
3 | timeCreated: 1519320015
4 | licenseType: Free
5 | MonoImporter:
6 | externalObjects: {}
7 | serializedVersion: 2
8 | defaultReferences: []
9 | executionOrder: 0
10 | icon: {instanceID: 0}
11 | userData:
12 | assetBundleName:
13 | assetBundleVariant:
14 |
--------------------------------------------------------------------------------
/Example/DemoObject.cs:
--------------------------------------------------------------------------------
1 | using UnityEditorHelper;
2 | using UnityEngine;
3 |
4 | public class DemoObject : ScriptableObject
5 | {
6 | [Layer]
7 | public int Layer;
8 |
9 | [Tag]
10 | public string Tag;
11 |
12 | [SortingLayer]
13 | public int SortingLayer;
14 |
15 | [Limit(0)]
16 | public int LimitLow;
17 |
18 | [Limit(-10, 42)]
19 | public int LimitBoth;
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/Example/DemoObject.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 384a49a068f68564b813e8710a281b64
3 | timeCreated: 1519321980
4 | licenseType: Free
5 | MonoImporter:
6 | externalObjects: {}
7 | serializedVersion: 2
8 | defaultReferences: []
9 | executionOrder: 0
10 | icon: {instanceID: 0}
11 | userData:
12 | assetBundleName:
13 | assetBundleVariant:
14 |
--------------------------------------------------------------------------------
/Example/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b36ef011582d2f642b7cd2c5c46303e7
3 | folderAsset: yes
4 | timeCreated: 1519321541
5 | licenseType: Free
6 | DefaultImporter:
7 | externalObjects: {}
8 | userData:
9 | assetBundleName:
10 | assetBundleVariant:
11 |
--------------------------------------------------------------------------------
/Example/Editor/Base32Encoding.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Derived from https://github.com/google/google-authenticator-android/blob/master/AuthenticatorApp/src/main/java/com/google/android/apps/authenticator/Base32String.java
3 | *
4 | * Copyright (C) 2016 BravoTango86
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | using System;
20 | using System.Collections.Generic;
21 | using System.Text;
22 | using System.Text.RegularExpressions;
23 |
24 | public static class Base32
25 | {
26 |
27 | private static readonly char[] DIGITS;
28 | private static readonly int MASK;
29 | private static readonly int SHIFT;
30 | private static Dictionary CHAR_MAP = new Dictionary();
31 | private const string SEPARATOR = "-";
32 |
33 | static Base32()
34 | {
35 | DIGITS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".ToCharArray();
36 | MASK = DIGITS.Length - 1;
37 | SHIFT = numberOfTrailingZeros(DIGITS.Length);
38 | for (int i = 0; i < DIGITS.Length; i++) CHAR_MAP[DIGITS[i]] = i;
39 | }
40 |
41 | private static int numberOfTrailingZeros(int i)
42 | {
43 | // HD, Figure 5-14
44 | int y;
45 | if (i == 0) return 32;
46 | int n = 31;
47 | y = i << 16; if (y != 0) { n = n - 16; i = y; }
48 | y = i << 8; if (y != 0) { n = n - 8; i = y; }
49 | y = i << 4; if (y != 0) { n = n - 4; i = y; }
50 | y = i << 2; if (y != 0) { n = n - 2; i = y; }
51 | return n - (int)((uint)(i << 1) >> 31);
52 | }
53 |
54 | public static string FromBase32(this string input)
55 | {
56 | return Encoding.ASCII.GetString(Decode(input));
57 | }
58 |
59 | public static string ToBase32(this string input)
60 | {
61 | return Encode(Encoding.ASCII.GetBytes(input));
62 | }
63 |
64 | public static byte[] Decode(string encoded)
65 | {
66 | // Remove whitespace and separators
67 | encoded = encoded.Trim().Replace(SEPARATOR, "");
68 |
69 | // Remove padding. Note: the padding is used as hint to determine how many
70 | // bits to decode from the last incomplete chunk (which is commented out
71 | // below, so this may have been wrong to start with).
72 | encoded = Regex.Replace(encoded, "[=]*$", "");
73 |
74 | // Canonicalize to all upper case
75 | encoded = encoded.ToUpper();
76 | if (encoded.Length == 0)
77 | {
78 | return new byte[0];
79 | }
80 | int encodedLength = encoded.Length;
81 | int outLength = encodedLength * SHIFT / 8;
82 | byte[] result = new byte[outLength];
83 | int buffer = 0;
84 | int next = 0;
85 | int bitsLeft = 0;
86 | foreach (char c in encoded)
87 | {
88 | if (!CHAR_MAP.ContainsKey(c))
89 | {
90 | throw new DecodingException("Illegal character: " + c);
91 | }
92 | buffer <<= SHIFT;
93 | buffer |= CHAR_MAP[c] & MASK;
94 | bitsLeft += SHIFT;
95 | if (bitsLeft >= 8)
96 | {
97 | result[next++] = (byte)(buffer >> (bitsLeft - 8));
98 | bitsLeft -= 8;
99 | }
100 | }
101 | // We'll ignore leftover bits for now.
102 | //
103 | // if (next != outLength || bitsLeft >= SHIFT) {
104 | // throw new DecodingException("Bits left: " + bitsLeft);
105 | // }
106 | return result;
107 | }
108 |
109 |
110 | public static string Encode(byte[] data, bool padOutput = false)
111 | {
112 | if (data.Length == 0)
113 | {
114 | return "";
115 | }
116 |
117 | // SHIFT is the number of bits per output character, so the length of the
118 | // output is the length of the input multiplied by 8/SHIFT, rounded up.
119 | if (data.Length >= 1 << 28)
120 | {
121 | // The computation below will fail, so don't do it.
122 | throw new ArgumentOutOfRangeException("data");
123 | }
124 |
125 | int outputLength = (data.Length * 8 + SHIFT - 1) / SHIFT;
126 | StringBuilder result = new StringBuilder(outputLength);
127 |
128 | int buffer = data[0];
129 | int next = 1;
130 | int bitsLeft = 8;
131 | while (bitsLeft > 0 || next < data.Length)
132 | {
133 | if (bitsLeft < SHIFT)
134 | {
135 | if (next < data.Length)
136 | {
137 | buffer <<= 8;
138 | buffer |= data[next++] & 0xff;
139 | bitsLeft += 8;
140 | }
141 | else
142 | {
143 | int pad = SHIFT - bitsLeft;
144 | buffer <<= pad;
145 | bitsLeft += pad;
146 | }
147 | }
148 | int index = MASK & (buffer >> (bitsLeft - SHIFT));
149 | bitsLeft -= SHIFT;
150 | result.Append(DIGITS[index]);
151 | }
152 | if (padOutput)
153 | {
154 | int padding = 8 - result.Length % 8;
155 | if (padding > 0) result.Append(new string('=', padding == 8 ? 0 : padding));
156 | }
157 | return result.ToString();
158 | }
159 |
160 | private class DecodingException : Exception
161 | {
162 | public DecodingException(string message) : base(message)
163 | {
164 | }
165 | }
166 | }
--------------------------------------------------------------------------------
/Example/Editor/Base32Encoding.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: de420fedcefd5b644b5bd0d34f2d134d
3 | timeCreated: 1519762039
4 | licenseType: Free
5 | MonoImporter:
6 | externalObjects: {}
7 | serializedVersion: 2
8 | defaultReferences: []
9 | executionOrder: 0
10 | icon: {instanceID: 0}
11 | userData:
12 | assetBundleName:
13 | assetBundleVariant:
14 |
--------------------------------------------------------------------------------
/Example/Editor/DemoScenarios.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using UnityEditor;
4 | using UnityEditorHelper;
5 | using UnityEngine;
6 |
7 | public static class DemoScenarios
8 | {
9 | public static DemoScenario EditorBlockHorizontal = new DemoScenario
10 | {
11 | Name = "EditorBlock (horizontal)",
12 | Scenarios = new List
13 | {
14 | new DemoScenarioContent("Simple horizontal block", "Same as EditorGUILayout.BeginHorizontal/EndHorizontal",
15 | delegate
16 | {
17 | using (new EditorBlock(EditorBlock.Orientation.Horizontal))
18 | {
19 | EditorGUILayout.TextField("Text", "");
20 | EditorGUILayout.ColorField("Color", Color.grey);
21 | }
22 | }, "OVZWS3THEAUG4ZLXEBCWI2LUN5ZEE3DPMNVSQRLENF2G64SCNRXWG2ZOJ5ZGSZLOORQXI2LPNYXEQ33SNF5G63TUMFWCSKIKPMFCAIBAEBCWI2LUN5ZEOVKJJRQXS33VOQXFIZLYORDGSZLMMQUCEVDFPB2CELBAEIRCSOYKEAQCAICFMRUXI33SI5KUSTDBPFXXK5BOINXWY33SIZUWK3DEFAREG33MN5ZCELBAINXWY33SFZTXEZLZFE5QU7I=".FromBase32()),
23 | new DemoScenarioContent("Horizontal block with named style 'Box'",
24 | "Same as above but uses a style of a given name",
25 | delegate
26 | {
27 | using (new EditorBlock(EditorBlock.Orientation.Horizontal, "Box"))
28 | {
29 | EditorGUILayout.TextField("Text", "");
30 | EditorGUILayout.ColorField("Color", Color.grey);
31 | }
32 | }, "OVZWS3THEAUG4ZLXEBCWI2LUN5ZEE3DPMNVSQRLENF2G64SCNRXWG2ZOJ5ZGSZLOORQXI2LPNYXEQ33SNF5G63TUMFWCYIBCIJXXQIRJFEFHWCRAEAQCARLENF2G64SHKVEUYYLZN52XILSUMV4HIRTJMVWGIKBCKRSXQ5BCFQQCEIRJHMFCAIBAEBCWI2LUN5ZEOVKJJRQXS33VOQXEG33MN5ZEM2LFNRSCQISDN5WG64RCFQQEG33MN5ZC4Z3SMV4SSOYKPU======".FromBase32()),
33 | new DemoScenarioContent("Horizontal block with named style 'GroupBox'",
34 | "Same as above but uses a style of a given name",
35 | delegate
36 | {
37 | using (new EditorBlock(EditorBlock.Orientation.Horizontal, "GroupBox"))
38 | {
39 | EditorGUILayout.TextField("Text", "");
40 | EditorGUILayout.ColorField("Color", Color.grey);
41 | }
42 | }, "OVZWS3THEAUG4ZLXEBCWI2LUN5ZEE3DPMNVSQRLENF2G64SCNRXWG2ZOJ5ZGSZLOORQXI2LPNYXEQ33SNF5G63TUMFWCYIBCI5ZG65LQIJXXQIRJFEFHWCRAEAQCARLENF2G64SHKVEUYYLZN52XILSUMV4HIRTJMVWGIKBCKRSXQ5BCFQQCEIRJHMFCAIBAEBCWI2LUN5ZEOVKJJRQXS33VOQXEG33MN5ZEM2LFNRSCQISDN5WG64RCFQQEG33MN5ZC4Z3SMV4SSOYKPU======".FromBase32()),
43 | new DemoScenarioContent("Horizontal block with named style 'TL LogicBar 1'",
44 | "Same as above but uses a style of a given name",
45 | delegate
46 | {
47 | using (new EditorBlock(EditorBlock.Orientation.Horizontal, "TL LogicBar 1"))
48 | {
49 | EditorGUILayout.TextField("Text", "");
50 | EditorGUILayout.ColorField("Color", Color.grey);
51 | }
52 | }, "OVZWS3THEAUG4ZLXEBCWI2LUN5ZEE3DPMNVSQRLENF2G64SCNRXWG2ZOJ5ZGSZLOORQXI2LPNYXFMZLSORUWGYLMFQQCEVCMEBGG6Z3JMNBGC4RAGERCSKIKPMFCAIBAEBCWI2LUN5ZEOVKJJRQXS33VOQXFIZLYORDGSZLMMQUCEVDFPB2CELBAEIRCSOYKEAQCAICFMRUXI33SI5KUSTDBPFXXK5BOINXWY33SIZUWK3DEFAREG33MN5ZCELBAINXWY33SFZTXEZLZFE5QU7I=".FromBase32()),
53 | }
54 | };
55 |
56 | public static DemoScenario EditorBlockVertical = new DemoScenario
57 | {
58 | Name = "EditorBlock (vertical)",
59 | Scenarios = new List
60 | {
61 | new DemoScenarioContent("Simple vertical block", "Same as EditorGUILayout.BeginVertical/EndVertical",
62 | delegate
63 | {
64 | using (new EditorBlock(EditorBlock.Orientation.Vertical))
65 | {
66 | DrawSampleControls();
67 | }
68 | }, "OVZWS3THEAUG4ZLXEBCWI2LUN5ZEE3DPMNVSQRLENF2G64SCNRXWG2ZOJ5ZGSZLOORQXI2LPNYXFMZLSORUWGYLMFEUQU6YKEAQCAICFMRUXI33SI5KUSTDBPFXXK5BOKRSXQ5CGNFSWYZBIEJKGK6DUEIWCAIRCFE5QUIBAEAQEKZDJORXXER2VJFGGC6LPOV2C4Q3PNRXXERTJMVWGIKBCINXWY33SEIWCAQ3PNRXXELTHOJSXSKJ3BJ6QU===".FromBase32()),
69 | new DemoScenarioContent("Vertical block with named style 'Box'",
70 | "Same as above but uses a style of a given name",
71 | delegate
72 | {
73 | using (new EditorBlock(EditorBlock.Orientation.Vertical, "Box"))
74 | {
75 | DrawSampleControls();
76 | }
77 | }, "OVZWS3THEAUG4ZLXEBCWI2LUN5ZEE3DPMNVSQRLENF2G64SCNRXWG2ZOJ5ZGSZLOORQXI2LPNYXFMZLSORUWGYLMFQQCEQTPPARCSKIKPMFCAIBAEBCWI2LUN5ZEOVKJJRQXS33VOQXFIZLYORDGSZLMMQUCEVDFPB2CELBAEIRCSOYKEAQCAICFMRUXI33SI5KUSTDBPFXXK5BOINXWY33SIZUWK3DEFAREG33MN5ZCELBAINXWY33SFZTXEZLZFE5QU7I=".FromBase32()),
78 | new DemoScenarioContent("Vertical block with named style 'GroupBox'",
79 | "Same as above but uses a style of a given name",
80 | delegate
81 | {
82 | using (new EditorBlock(EditorBlock.Orientation.Vertical, "GroupBox"))
83 | {
84 | DrawSampleControls();
85 | }
86 | }, "OVZWS3THEAUG4ZLXEBCWI2LUN5ZEE3DPMNVSQRLENF2G64SCNRXWG2ZOJ5ZGSZLOORQXI2LPNYXFMZLSORUWGYLMFQQCER3SN52XAQTPPARCSKIKPMFCAIBAEBCWI2LUN5ZEOVKJJRQXS33VOQXFIZLYORDGSZLMMQUCEVDFPB2CELBAEIRCSOYKEAQCAICFMRUXI33SI5KUSTDBPFXXK5BOINXWY33SIZUWK3DEFAREG33MN5ZCELBAINXWY33SFZTXEZLZFE5QU7I=".FromBase32()),
87 | new DemoScenarioContent("Vertical block with named style 'TE NodeBox'",
88 | "Same as above but uses a style of a given name",
89 | delegate
90 | {
91 | using (new EditorBlock(EditorBlock.Orientation.Vertical, "TE NodeBox"))
92 | {
93 | DrawSampleControls();
94 | }
95 | }, "OVZWS3THEAUG4ZLXEBCWI2LUN5ZEE3DPMNVSQRLENF2G64SCNRXWG2ZOJ5ZGSZLOORQXI2LPNYXFMZLSORUWGYLMFQQCEVCMEBGG6Z3JMNBGC4RAGERCSKIKPMFCAIBAEBCWI2LUN5ZEOVKJJRQXS33VOQXFIZLYORDGSZLMMQUCEVDFPB2CELBAEIRCSOYKEAQCAICFMRUXI33SI5KUSTDBPFXXK5BOINXWY33SIZUWK3DEFAREG33MN5ZCELBAINXWY33SFZTXEZLZFE5QU7I=".FromBase32()),
96 | }
97 | };
98 |
99 | public static DemoScenario RoundedBox = new DemoScenario
100 | {
101 | Name = "RoundedBox",
102 | Scenarios = new List
103 | {
104 | new DemoScenarioContent("RoundedBox", "A simple solid colored rectangle with rounded corners. Currently, no further customizations are available",
105 | delegate
106 | {
107 | using (new RoundedBox())
108 | {
109 | DrawSampleControls();
110 | }
111 | }, "OVZWS3THEAUG4ZLXEBJG65LOMRSWIQTPPAUCSKIKPMFCAIBAEBCWI2LUN5ZEOVKJJRQXS33VOQXFIZLYORDGSZLMMQUCEVDFPB2CELBAEIRCSOYKEAQCAICFMRUXI33SI5KUSTDBPFXXK5BOINXWY33SIZUWK3DEFAREG33MN5ZCELBAINXWY33SFZTXEZLZFE5QU7I=".FromBase32()),
112 | new DemoScenarioContent("RoundedBox with color", "For the moment this needs 2 SwitchColor blocks. This will be improved in a future release",
113 | delegate
114 | {
115 | using (new SwitchColor(Color.cyan))
116 | {
117 | using (new RoundedBox())
118 | {
119 | using (new SwitchColor(Color.white))
120 | {
121 | DrawSampleControls();
122 | }
123 | }
124 | }
125 | }, "OVZWS3THEAUG4ZLXEBJXO2LUMNUEG33MN5ZCQQ3PNRXXELTDPFQW4KJJBJ5QUIBAEAQHK43JNZTSAKDOMV3SAUTPOVXGIZLEIJXXQKBJFEFCAIBAEB5QUIBAEAQCAIBAEB2XG2LOM4QCQ3TFO4QFG53JORRWQQ3PNRXXEKCDN5WG64ROO5UGS5DFFEUQUIBAEAQCAIBAEB5QUIBAEAQCAIBAEAQCAIBAIVSGS5DPOJDVKSKMMF4W65LUFZKGK6DUIZUWK3DEFARFIZLYOQRCYIBCEIUTWCRAEAQCAIBAEAQCAIBAEBCWI2LUN5ZEOVKJJRQXS33VOQXEG33MN5ZEM2LFNRSCQISDN5WG64RCFQQEG33MN5ZC4Z3SMV4SSOYKEAQCAIBAEAQCA7IKEAQCAID5BJ6Q====".FromBase32()),
126 | }
127 | };
128 |
129 | public static DemoScenario EditorFrame = new DemoScenario
130 | {
131 | Name = "EditorFrame",
132 | Scenarios = new List
133 | {
134 | new DemoScenarioContent("EditorFrame", "A box with a header looking like an index card",
135 | delegate
136 | {
137 | using (new EditorFrame("Caption", Color.white))
138 | {
139 | DrawSampleControls();
140 | }
141 | }, "OVZWS3THEAUG4ZLXEBCWI2LUN5ZEM4TBNVSSQISDMFYHI2LPNYRCYICDN5WG64ROO5UGS5DFFEUQU6YKEAQCAICFMRUXI33SI5KUSTDBPFXXK5BOKRSXQ5CGNFSWYZBIEJKGK6DUEIWCAIRCFE5QUIBAEAQEKZDJORXXER2VJFGGC6LPOV2C4Q3PNRXXERTJMVWGIKBCINXWY33SEIWCAQ3PNRXXELTHOJSXSKJ3BJ6Q====".FromBase32()),
142 | new DemoScenarioContent("EditorFrame, colored Caption", "Same as above, but with customized color for the caption",
143 | delegate
144 | {
145 | using (new EditorFrame("Caption", Color.cyan))
146 | {
147 | DrawSampleControls();
148 | }
149 | }, "OVZWS3THEAUG4ZLXEBCWI2LUN5ZEM4TBNVSSQISDMFYHI2LPNYRCYICDN5WG64ROMN4WC3RJFEFHWCRAEAQCARLENF2G64SHKVEUYYLZN52XILSUMV4HIRTJMVWGIKBCKRSXQ5BCFQQCEIRJHMFCAIBAEBCWI2LUN5ZEOVKJJRQXS33VOQXEG33MN5ZEM2LFNRSCQISDN5WG64RCFQQEG33MN5ZC4Z3SMV4SSOYKPU======".FromBase32()),
150 | new DemoScenarioContent("EditorFrame, fixed width", "Same as above, but with a fixed width",
151 | delegate
152 | {
153 | using (new EditorFrame("Caption", Color.cyan, 500))
154 | {
155 | DrawSampleControls();
156 | }
157 | }, "OVZWS3THEAUG4ZLXEBCWI2LUN5ZEM4TBNVSSQISDMFYHI2LPNYRCYICDN5WG64ROMN4WC3RMEA2TAMBJFEFHWCRAEAQCARLENF2G64SHKVEUYYLZN52XILSUMV4HIRTJMVWGIKBCKRSXQ5BCFQQCEIRJHMFCAIBAEBCWI2LUN5ZEOVKJJRQXS33VOQXEG33MN5ZEM2LFNRSCQISDN5WG64RCFQQEG33MN5ZC4Z3SMV4SSOYKPU======".FromBase32()),
158 | }
159 | };
160 |
161 | public static DemoScenario FoldableEditorFrame = new DemoScenario
162 | {
163 | Name = "FoldableEditorFrame",
164 | Scenarios = new List
165 | {
166 | new DemoScenarioContent("FoldableEditorFrame", "Similar to EditorFrame, but can be collapsed by clicking on the header",
167 | delegate
168 | {
169 | using (FoldableEditorFrame foldable = new FoldableEditorFrame("[FoldableEditorFrameExample]", "Click me!", Color.white, Color.white))
170 | {
171 | if(foldable.Expanded)
172 | {
173 | DrawSampleControls();
174 | }
175 | else
176 | GUILayout.Space(10);
177 | }
178 | }, "OVZWS3THEAUEM33MMRQWE3DFIVSGS5DPOJDHEYLNMUQGM33MMRQWE3DFEA6SA3TFO4QEM33MMRQWE3DFIVSGS5DPOJDHEYLNMUUCEW2GN5WGIYLCNRSUKZDJORXXERTSMFWWKRLYMFWXA3DFLURCYIBCINWGSY3LEBWWKIJCFQQEG33MN5ZC453INF2GKLBAINXWY33SFZ3WQ2LUMUUSSCT3BIQCAIBANFTCQZTPNRSGCYTMMUXEK6DQMFXGIZLEFEFCAIBAEB5QUIBAEAQCAIBAEBCWI2LUN5ZEOVKJJRQXS33VOQXFIZLYORDGSZLMMQUCEVDFPB2CELBAEIRCSOYKEAQCAIBAEAQCARLENF2G64SHKVEUYYLZN52XILSDN5WG64SGNFSWYZBIEJBW63DPOIRCYICDN5WG64ROM5ZGK6JJHMFCAIBAEB6QUIBAEAQGK3DTMUFCAIBAEAQCAIBAI5KUSTDBPFXXK5BOKNYGCY3FFAYTAKJ3BJ6Q====".FromBase32()),
179 | new DemoScenarioContent("FoldableEditorFrame, colored caption and content", "Same as above, but with customized colors",
180 | delegate
181 | {
182 | using (FoldableEditorFrame foldable = new FoldableEditorFrame("[FoldableEditorFrameExample]", "Click me!", Color.cyan, Color.red))
183 | {
184 | if(foldable.Expanded)
185 | {
186 | DrawSampleControls();
187 | }
188 | else
189 | GUILayout.Space(10);
190 | }
191 | }, "OVZWS3THEAUEM33MMRQWE3DFIVSGS5DPOJDHEYLNMUQGM33MMRQWE3DFEA6SA3TFO4QEM33MMRQWE3DFIVSGS5DPOJDHEYLNMUUCEW2GN5WGIYLCNRSUKZDJORXXERTSMFWWKRLYMFWXA3DFLURCYIBCINWGSY3LEBWWKIJCFQQEG33MN5ZC4Y3ZMFXCYICDN5WG64ROOJSWIKJJBJ5QUIBAEAQGSZRIMZXWYZDBMJWGKLSFPBYGC3TEMVSCSCRAEAQCA6YKEAQCAIBAEAQCARLENF2G64SHKVEUYYLZN52XILSUMV4HIRTJMVWGIKBCKRSXQ5BCFQQCEIRJHMFCAIBAEAQCAIBAIVSGS5DPOJDVKSKMMF4W65LUFZBW63DPOJDGSZLMMQUCEQ3PNRXXEIRMEBBW63DPOIXGO4TFPEUTWCRAEAQCA7IKEAQCAIDFNRZWKCRAEAQCAIBAEAQEOVKJJRQXS33VOQXFG4DBMNSSQMJQFE5Q====".FromBase32()),
192 | }
193 | };
194 |
195 | //ToDo
196 | //SwitchColor
197 | //SwitchBackgroundColor
198 | //SwitchGUIDepth
199 | //IndentBlock
200 | //ScrollViewBlock
201 | //PaddedBlock
202 | //FoldableBlock
203 |
204 | private static Vector2 _switchGUIDepthScrollPos;
205 |
206 | public static DemoScenario SwitchGUIDepth = new DemoScenario
207 | {
208 | Name = "SwitchGUIDepth",
209 | Scenarios = new List
210 | {
211 | new DemoScenarioContent("SwitchGUIDepth", "Similar to EditorFrame, but can be collapsed by clicking on the header",
212 | delegate
213 | {
214 | Rect rect = EditorGUILayout.GetControlRect(false, 50);
215 |
216 | GUI.RepeatButton(rect, "Button 2");
217 | using (new SwitchGUIDepth(999))
218 | {
219 | rect.xMin += 40;
220 | rect.yMin += 30;
221 | rect.xMax -= 40;
222 | rect.yMax += 30;
223 | GUI.RepeatButton(rect, "Button 1");
224 | }
225 | GUILayout.Space(40);
226 | }, "KJSWG5BAOJSWG5BAHUQEKZDJORXXER2VJFGGC6LPOV2C4R3FORBW63TUOJXWYUTFMN2CQZTBNRZWKLBAGUYCSOYKBJDVKSJOKJSXAZLBORBHK5DUN5XCQ4TFMN2CYIBCIJ2XI5DPNYQDEIRJHMFHK43JNZTSAKDOMV3SAU3XNF2GG2CHKVEUIZLQORUCQOJZHEUSSCT3BIQCAIBAOJSWG5BOPBGWS3RAFM6SANBQHMFCAIBAEBZGKY3UFZ4U22LOEAVT2IBTGA5QUIBAEAQHEZLDOQXHQTLBPAQC2PJAGQYDWCRAEAQCA4TFMN2C46KNMF4CAKZ5EAZTAOYKEAQCAICHKVES4UTFOBSWC5CCOV2HI33OFBZGKY3UFQQCEQTVOR2G63RAGERCSOYKPUFEOVKJJRQXS33VOQXFG4DBMNSSQNBQFE5Q====".FromBase32()),
227 | }
228 | };
229 |
230 | private static void DrawSampleControls()
231 | {
232 | EditorGUILayout.TextField("Text", "");
233 | EditorGUILayout.ColorField("Color", Color.grey);
234 | }
235 | }
236 |
237 | public class DemoScenario
238 | {
239 | public string Name;
240 |
241 | public List Scenarios;
242 |
243 | public DemoScenario()
244 | {
245 | Scenarios = new List();
246 | }
247 | }
248 |
249 | public class DemoScenarioContent
250 | {
251 | public string Caption;
252 | public string Description;
253 | public Action Sample;
254 | public string SampleCode;
255 |
256 | public bool ShowCode;
257 | public Vector3 ScrollPos;
258 |
259 | public DemoScenarioContent(string caption, string description, Action sample, string sampleCode)
260 | {
261 | Caption = caption;
262 | Description = description;
263 | Sample = sample;
264 | SampleCode = sampleCode;
265 | }
266 | }
--------------------------------------------------------------------------------
/Example/Editor/DemoScenarios.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 845f236207bc0b5478d491c5a414ec99
3 | timeCreated: 1519378311
4 | licenseType: Free
5 | MonoImporter:
6 | externalObjects: {}
7 | serializedVersion: 2
8 | defaultReferences: []
9 | executionOrder: 0
10 | icon: {instanceID: 0}
11 | userData:
12 | assetBundleName:
13 | assetBundleVariant:
14 |
--------------------------------------------------------------------------------
/Example/Editor/SampleEditor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using UnityEditor;
5 | using UnityEditorHelper;
6 | using UnityEngine;
7 |
8 | public class DemoScriptEditor : EditorWindow
9 | {
10 | private enum EditorPage { PropertyDrawer, Blocks, Utility, About }
11 |
12 | private EditorPage _currentPage;
13 |
14 | [MenuItem("Tools/UnityEditorHelper/Open Demo Window")]
15 | public static void OpenDemoEditor()
16 | {
17 | GetWindow(false, "Demo");
18 | }
19 |
20 | private DemoObject _demoObject;
21 | private SerializedObject _serializedObject;
22 |
23 | private static List _blockDemoScenarios;
24 |
25 | private void OnEnable()
26 | {
27 | _blockDemoScenarios = new List
28 | {
29 | DemoScenarios.EditorBlockHorizontal,
30 | DemoScenarios.EditorBlockVertical,
31 | DemoScenarios.RoundedBox,
32 | DemoScenarios.EditorFrame,
33 | DemoScenarios.FoldableEditorFrame,
34 | DemoScenarios.SwitchGUIDepth,
35 | };
36 |
37 | _demoObject = CreateInstance();
38 | _serializedObject = new SerializedObject(_demoObject);
39 | }
40 |
41 | private void OnGUI()
42 | {
43 | using (new EditorBlock(EditorBlock.Orientation.Vertical))
44 | {
45 | DrawToolbar();
46 |
47 | switch (_currentPage)
48 | {
49 | case EditorPage.PropertyDrawer:
50 | DrawPropertyDrawer();
51 | break;
52 |
53 | case EditorPage.Blocks:
54 | DrawBlockExamples();
55 | break;
56 |
57 | case EditorPage.Utility:
58 | using (new PaddedBlock(8, 8, 16, 0))
59 | DrawUtilityDemos();
60 | break;
61 |
62 | case EditorPage.About:
63 | break;
64 |
65 | default:
66 | throw new ArgumentOutOfRangeException();
67 | }
68 | }
69 | }
70 |
71 | public void DrawToolbar()
72 | {
73 | EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
74 | string[] enumNames = Enum.GetNames(typeof(EditorPage));
75 | EditorPage[] enumValues = (EditorPage[])Enum.GetValues(typeof(EditorPage));
76 | for (int i = 0; i < enumNames.Length; i++)
77 | {
78 | if (GUILayout.Toggle(_currentPage == enumValues[i], enumNames[i], EditorStyles.toolbarButton, GUILayout.Width(100)))
79 | {
80 | _currentPage = enumValues[i];
81 | }
82 | }
83 | GUILayout.Toolbar(0, new[] { "" }, EditorStyles.toolbar, GUILayout.ExpandWidth(true));
84 | EditorGUILayout.EndHorizontal();
85 | EditorGUILayout.Space();
86 | }
87 |
88 | private void DrawPropertyDrawer()
89 | {
90 | EditorGUILayout.PropertyField(_serializedObject.FindProperty("Layer"));
91 | EditorGUILayout.PropertyField(_serializedObject.FindProperty("Tag"));
92 | EditorGUILayout.PropertyField(_serializedObject.FindProperty("SortingLayer"));
93 | EditorGUILayout.PropertyField(_serializedObject.FindProperty("LimitLow"));
94 | EditorGUILayout.PropertyField(_serializedObject.FindProperty("LimitBoth"));
95 |
96 | _serializedObject.ApplyModifiedProperties();
97 | }
98 |
99 | private void DrawUtilityDemos()
100 | {
101 | bool expanded = true;
102 | using (new FoldableBlock(ref expanded, "GetAssetPath"))
103 | {
104 | EditorGUILayout.LabelField("", "The Asset \"SampleEditor.cs\" is located at the following path:");
105 | EditorGUILayout.TextField("", EditorHelper.GetAssetPath("SampleEditor.cs"));
106 | }
107 |
108 | using (new FoldableBlock(ref expanded, "DrawIconHeader"))
109 | {
110 | if (EditorHelper.DrawIconHeader("DemoKey", EditorGUIUtility.FindTexture("SceneAsset Icon"), "Caption (foldable)", Color.white))
111 | {
112 | EditorGUILayout.LabelField("", "Some fancy content...");
113 | }
114 |
115 | if (EditorHelper.DrawIconHeader("DemoKey", EditorGUIUtility.FindTexture("Shader Icon"), "Caption (non-foldable)", Color.white, false))
116 | {
117 | EditorGUILayout.LabelField("", "Even more fancy content...");
118 | }
119 | }
120 |
121 | using (new FoldableBlock(ref expanded, "GUIDrawRect"))
122 | {
123 | using (new EditorBlock(EditorBlock.Orientation.Horizontal))
124 | {
125 | for (int i = 0; i <= 10; i++)
126 | {
127 | Rect rect = EditorGUILayout.GetControlRect(false, 32);
128 | rect.width = 32;
129 | EditorHelper.GUIDrawRect(rect, new Color(0.1f * i, 0.7f, 0.8f));
130 | }
131 | }
132 | }
133 |
134 | using (new FoldableBlock(ref expanded, "DrawTiledTexture"))
135 | {
136 | Rect rect = EditorGUILayout.GetControlRect(false, 64);
137 | EditorHelper.DrawTiledTexture(rect, EditorGUIUtility.FindTexture("_Help"));
138 | }
139 |
140 | using (new FoldableBlock(ref expanded, "CreateCheckerTex"))
141 | {
142 | using (new EditorBlock(EditorBlock.Orientation.Horizontal))
143 | {
144 | using (new EditorBlock(EditorBlock.Orientation.Vertical))
145 | {
146 | Rect rect = EditorGUILayout.GetControlRect(false, 32);
147 | rect.width = 32;
148 | GUI.DrawTexture(rect, EditorHelper.CreateCheckerTex(Color.blue, Color.cyan, 32));
149 |
150 | rect = EditorGUILayout.GetControlRect(false, 32);
151 | rect.width = 32;
152 | GUI.DrawTexture(rect, EditorHelper.CreateCheckerTex(Color.blue, Color.cyan, 32, 8));
153 | }
154 |
155 | using (new EditorBlock(EditorBlock.Orientation.Vertical))
156 | {
157 | Rect rect = EditorGUILayout.GetControlRect(false, 64);
158 | rect.width = 64;
159 | GUI.DrawTexture(rect, EditorHelper.CreateCheckerTex(new Color(0.1f, 0.1f, 0.1f, 0.5f), new Color(0.2f, 0.2f, 0.2f, 0.5f), 64));
160 |
161 | rect = EditorGUILayout.GetControlRect(false, 64);
162 | rect.width = 64;
163 | GUI.DrawTexture(rect, EditorHelper.CreateCheckerTex(new Color(0.1f, 0.1f, 0.1f, 0.5f), new Color(0.2f, 0.2f, 0.2f, 0.5f), 64, 8));
164 | }
165 |
166 | Rect largeRect = EditorGUILayout.GetControlRect(false, 128);
167 | largeRect.width = 128;
168 | GUI.DrawTexture(largeRect, EditorHelper.CreateCheckerTex(new Color(0.1f, 0.1f, 0.1f, 0.5f), new Color(0.2f, 0.2f, 0.2f, 0.5f), 128, 64));
169 | }
170 | }
171 |
172 | using (new FoldableBlock(ref expanded, "DrawOutline"))
173 | {
174 | EditorGUILayout.Space();
175 | using (new EditorBlock(EditorBlock.Orientation.Horizontal))
176 | {
177 | EditorGUILayout.Space();
178 | Rect rect = EditorGUILayout.GetControlRect(false, 64);
179 | rect.width = 128;
180 | EditorHelper.DrawOutline(rect, Color.blue, 4f);
181 | EditorHelper.GUIDrawRect(rect, new Color(1f, 1f, 1f, 0.5f));
182 | EditorGUILayout.Space();
183 |
184 | rect = EditorGUILayout.GetControlRect(false, 64);
185 | rect.width = 128;
186 | EditorHelper.DrawOutline(rect, Color.blue, 4f, EditorHelper.OutlineMode.Centered);
187 | EditorHelper.GUIDrawRect(rect, new Color(1f, 1f, 1f, 0.5f));
188 | EditorGUILayout.Space();
189 |
190 | rect = EditorGUILayout.GetControlRect(false, 64);
191 | rect.width = 128;
192 | EditorHelper.DrawOutline(rect, Color.blue, 4f, EditorHelper.OutlineMode.Inside);
193 | EditorHelper.GUIDrawRect(rect, new Color(1f, 1f, 1f, 0.5f));
194 | EditorGUILayout.Space();
195 | }
196 | EditorGUILayout.Space();
197 | }
198 | }
199 |
200 | private int _selectedBlockIndex = -1;
201 | private Vector2 _scrollPos;
202 |
203 | private void DrawBlockExamples()
204 | {
205 | GUILayout.Space(-10);
206 | using (new EditorBlock(EditorBlock.Orientation.Horizontal, GUILayout.ExpandWidth(true)))
207 | {
208 | using (new EditorBlock(EditorBlock.Orientation.Vertical, "Box", GUILayout.Width(200), GUILayout.ExpandHeight(true)))
209 | {
210 | int oldSelectedBlockIndex = _selectedBlockIndex;
211 | _selectedBlockIndex = GUILayout.SelectionGrid(_selectedBlockIndex, _blockDemoScenarios.Select(s => s.Name).ToArray(), 1);
212 | if (oldSelectedBlockIndex != _selectedBlockIndex)
213 | {
214 | GUI.SetNextControlName("Some stuff to loose focus");
215 | GUI.Label(new Rect(-float.MaxValue, -float.MaxValue, 1, 1), "");
216 | GUI.FocusControl("Some stuff to loose focus");
217 | }
218 | }
219 | using (new EditorBlock(EditorBlock.Orientation.Vertical, GUILayout.ExpandHeight(true)))
220 | {
221 | if (_selectedBlockIndex >= 0)
222 | {
223 | using (new ScrollViewBlock(ref _scrollPos, GUILayout.ExpandWidth(true)))
224 | {
225 | foreach (DemoScenarioContent scenario in _blockDemoScenarios[_selectedBlockIndex].Scenarios)
226 | {
227 | using (FoldableEditorFrame block = new FoldableEditorFrame("[SampleEditorScenario]." + scenario.Caption, scenario.Caption, Color.white, Color.white))
228 | {
229 | if (block.Expanded)
230 | {
231 | EditorGUILayout.LabelField(scenario.Description, EditorStyles.miniLabel );
232 |
233 | EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
234 | string[] tabs = { "Sample", "Code" };
235 | for (int i = 0; i < tabs.Length; i++)
236 | {
237 | if (GUILayout.Toggle(i == (scenario.ShowCode ? 1 : 0), tabs[i], EditorStyles.toolbarButton, GUILayout.Width(100)))
238 | {
239 | scenario.ShowCode = i == 1;
240 | }
241 | }
242 | GUILayout.Toolbar(0, new[] { "" }, EditorStyles.toolbar, GUILayout.ExpandWidth(true));
243 | EditorGUILayout.EndHorizontal();
244 | EditorGUILayout.Space();
245 |
246 | GUILayout.Space(-10);
247 | using (new EditorBlock(EditorBlock.Orientation.Vertical, "Box"))
248 | {
249 | using (new PaddedBlock(10))
250 | {
251 | if (scenario.ShowCode)
252 | {
253 | EditorHelper.ScrollableSelectableLabel(scenario.ScrollPos, scenario.SampleCode, EditorStyles.label);
254 | }
255 | else
256 | {
257 | scenario.Sample.Invoke();
258 | }
259 | }
260 | }
261 | }
262 | else
263 | EditorGUILayout.Space();
264 | }
265 | }
266 | }
267 | }
268 | }
269 | }
270 | }
271 | }
272 |
--------------------------------------------------------------------------------
/Example/Editor/SampleEditor.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 2144e9a906a2afe4f95e6874ac925ed1
3 | timeCreated: 1519321546
4 | licenseType: Free
5 | MonoImporter:
6 | externalObjects: {}
7 | serializedVersion: 2
8 | defaultReferences: []
9 | executionOrder: 0
10 | icon: {instanceID: 0}
11 | userData:
12 | assetBundleName:
13 | assetBundleVariant:
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2016 Thomas Hummes
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # UnityEditorHelper
2 | An organized bunch of scripts to make editor scripting in Unity easier - gathered from some of my projects and other free sources
3 |
4 | More information can be found in the wiki including examples and screenshots: https://github.com/JefferiesTube/UnityEditorHelper/wiki
5 |
--------------------------------------------------------------------------------