You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
406 lines
12 KiB
C#
406 lines
12 KiB
C#
|
3 years ago
|
using UnityEngine;
|
||
|
|
using System.Reflection;
|
||
|
|
using UnityEngine.Polybrush;
|
||
|
|
|
||
|
|
namespace UnityEditor.Polybrush
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// GUI field extensions.
|
||
|
|
/// </summary>
|
||
|
|
internal static class PolyGUILayout
|
||
|
|
{
|
||
|
|
static GUIStyle m_HelpStyle;
|
||
|
|
|
||
|
|
static GUIStyle HelpStyle
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
if (m_HelpStyle == null)
|
||
|
|
{
|
||
|
|
m_HelpStyle = GUI.skin.FindStyle("IconButton");
|
||
|
|
}
|
||
|
|
return m_HelpStyle;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Color field control
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="text"></param>
|
||
|
|
/// <param name="mask"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
internal static ColorMask ColorMaskField(string text, ColorMask mask)
|
||
|
|
{
|
||
|
|
return ColorMaskField(string.IsNullOrEmpty(text) ? null : PolyGUI.TempContent(text), mask);
|
||
|
|
}
|
||
|
|
|
||
|
|
internal static ColorMask ColorMaskField(GUIContent gc, ColorMask mask)
|
||
|
|
{
|
||
|
|
using (new GUILayout.HorizontalScope())
|
||
|
|
{
|
||
|
|
if (gc != null)
|
||
|
|
{
|
||
|
|
EditorGUILayout.LabelField(gc, GUILayout.Width(EditorGUIUtility.currentViewWidth - 160));
|
||
|
|
}
|
||
|
|
|
||
|
|
bool newValue;
|
||
|
|
newValue = GUILayout.Toggle(mask.r, "R", "Button");
|
||
|
|
if (newValue != mask.r)
|
||
|
|
mask.r = !mask.r;
|
||
|
|
|
||
|
|
newValue = GUILayout.Toggle(mask.g, "G", "Button");
|
||
|
|
if (newValue != mask.g)
|
||
|
|
mask.g = !mask.g;
|
||
|
|
|
||
|
|
newValue = GUILayout.Toggle(mask.b, "B", "Button");
|
||
|
|
if (newValue != mask.b)
|
||
|
|
mask.b = !mask.b;
|
||
|
|
|
||
|
|
newValue = GUILayout.Toggle(mask.a, "A", "Button");
|
||
|
|
if (newValue != mask.a)
|
||
|
|
mask.a = !mask.a;
|
||
|
|
}
|
||
|
|
EditorGUILayout.Space();
|
||
|
|
return mask;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal static uint BitMaskField(uint value, string[] descriptions, string tooltip)
|
||
|
|
{
|
||
|
|
GUIContent gc = PolyGUI.TempContent("", tooltip);
|
||
|
|
|
||
|
|
using (new GUILayout.HorizontalScope())
|
||
|
|
{
|
||
|
|
int l = descriptions.Length;
|
||
|
|
|
||
|
|
for (int i = 1; i < l; i++)
|
||
|
|
{
|
||
|
|
int s = i - 1;
|
||
|
|
|
||
|
|
bool toggled = (value & (1u << s)) > 0;
|
||
|
|
|
||
|
|
gc.text = descriptions[i];
|
||
|
|
|
||
|
|
bool newValue = GUILayout.Toggle(toggled, gc, "Button", GUILayout.Width(30));
|
||
|
|
|
||
|
|
if (toggled != newValue)
|
||
|
|
value ^= (1u << s);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal static int CycleButton(int index, GUIContent[] content, GUIStyle style = null)
|
||
|
|
{
|
||
|
|
if(style != null)
|
||
|
|
{
|
||
|
|
if( GUILayout.Button(content[index], style) )
|
||
|
|
return (index + 1) % content.Length;
|
||
|
|
else
|
||
|
|
return index;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if( GUILayout.Button(content[index]) )
|
||
|
|
return (index + 1) % content.Length;
|
||
|
|
else
|
||
|
|
return index;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Similar to EditorGUILayoutUtility.Slider, except this allows for values outside of the min/max bounds via the float field.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="content"></param>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="min"></param>
|
||
|
|
/// <param name="max"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
internal static float FreeSlider(string content, float value, float min, float max)
|
||
|
|
{
|
||
|
|
return FreeSlider(PolyGUI.TempContent(content), value, min, max);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Similar to EditorGUILayoutUtility.Slider, except this allows for values outside of the min/max bounds via the float field.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="content"></param>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="min"></param>
|
||
|
|
/// <param name="max"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
internal static float FreeSlider(GUIContent content, float value, float min, float max)
|
||
|
|
{
|
||
|
|
const float PAD = 4f;
|
||
|
|
const float SLIDER_HEIGHT = 16f;
|
||
|
|
const float MIN_LABEL_WIDTH = 0f;
|
||
|
|
const float MAX_LABEL_WIDTH = 128f;
|
||
|
|
const float MIN_FIELD_WIDTH = 48f;
|
||
|
|
|
||
|
|
GUILayoutUtility.GetRect(Screen.width, 18);
|
||
|
|
|
||
|
|
Rect previousRect = GUILayoutUtility.GetLastRect();
|
||
|
|
float y = previousRect.y;
|
||
|
|
|
||
|
|
float labelWidth = content != null ? Mathf.Max(MIN_LABEL_WIDTH, Mathf.Min(GUI.skin.label.CalcSize(content).x + PAD, MAX_LABEL_WIDTH)) : 0f;
|
||
|
|
float remaining = (Screen.width - (PAD * 2f)) - labelWidth;
|
||
|
|
float sliderWidth = remaining - (MIN_FIELD_WIDTH + PAD);
|
||
|
|
float floatWidth = MIN_FIELD_WIDTH;
|
||
|
|
|
||
|
|
Rect labelRect = new Rect(PAD, y + 2f, labelWidth, SLIDER_HEIGHT);
|
||
|
|
Rect sliderRect = new Rect(labelRect.x + labelWidth, y + 1f, sliderWidth, SLIDER_HEIGHT);
|
||
|
|
Rect floatRect = new Rect(sliderRect.x + sliderRect.width + PAD, y + 1f, floatWidth, SLIDER_HEIGHT);
|
||
|
|
|
||
|
|
if(content != null)
|
||
|
|
GUI.Label(labelRect, content);
|
||
|
|
|
||
|
|
EditorGUI.BeginChangeCheck();
|
||
|
|
|
||
|
|
int controlID = GUIUtility.GetControlID(FocusType.Passive, sliderRect);
|
||
|
|
float tmp = value;
|
||
|
|
tmp = GUI.Slider(sliderRect, tmp, 0f, min, max, GUI.skin.horizontalSlider, (!EditorGUI.showMixedValue) ? GUI.skin.horizontalSliderThumb : "SliderMixed", true, controlID);
|
||
|
|
|
||
|
|
if(EditorGUI.EndChangeCheck())
|
||
|
|
value = Event.current.control ? 1f * Mathf.Round(tmp / 1f) : tmp;
|
||
|
|
|
||
|
|
value = EditorGUI.FloatField(floatRect, value);
|
||
|
|
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal static int ChannelField(int index, AttributeLayout[] channels, int thumbSize, int yPos)
|
||
|
|
{
|
||
|
|
int mIndex = index;
|
||
|
|
int attribsLength = channels != null ? channels.Length : 0;
|
||
|
|
|
||
|
|
const int margin = 4; // group pad
|
||
|
|
const int pad = 2; // texture pad
|
||
|
|
const int selected_rect_height = 10; // the little green bar and height padding
|
||
|
|
|
||
|
|
int actual_width = thumbSize + pad;
|
||
|
|
int container_width = (int) Mathf.Floor(EditorGUIUtility.currentViewWidth) - ((margin + pad) * 2);
|
||
|
|
// The container_width is currently as wide as the current view - margins and padding.
|
||
|
|
// Adjust it to take the size of the vertical scrollbar.
|
||
|
|
container_width -= (int)GUI.skin.verticalScrollbar.fixedWidth;
|
||
|
|
int columns = (int) Mathf.Floor(container_width / actual_width);
|
||
|
|
int rows = attribsLength / columns + (attribsLength % columns == 0 ? 0 : 1);
|
||
|
|
int height = rows * (actual_width + selected_rect_height);// + margin * 2;
|
||
|
|
|
||
|
|
Rect r = new Rect(margin + pad, yPos, actual_width, actual_width);
|
||
|
|
Rect border = new Rect( margin + pad , yPos, container_width, height);
|
||
|
|
|
||
|
|
// Draw background
|
||
|
|
EditorGUI.DrawRect(border, EditorGUIUtility.isProSkin ? PolyGUI.k_BoxOutlineDark : PolyGUI.k_BoxOutlineLight);
|
||
|
|
|
||
|
|
for (int i = 0; i < attribsLength; i++)
|
||
|
|
{
|
||
|
|
if(i > 0 && i % columns == 0)
|
||
|
|
{
|
||
|
|
r.x = pad + margin;
|
||
|
|
r.y += r.height + selected_rect_height;
|
||
|
|
}
|
||
|
|
|
||
|
|
string summary = channels[i].propertyTarget;
|
||
|
|
|
||
|
|
if(string.IsNullOrEmpty(summary))
|
||
|
|
summary = "channel\n" + (i+1);
|
||
|
|
|
||
|
|
if( AttributeComponentButton(r, summary, channels[i].previewTexture, i == mIndex) )
|
||
|
|
{
|
||
|
|
mIndex = i;
|
||
|
|
GUI.changed = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
r.x += r.width;
|
||
|
|
}
|
||
|
|
|
||
|
|
GUILayoutUtility.GetRect(container_width - 8, height);
|
||
|
|
|
||
|
|
return mIndex;
|
||
|
|
}
|
||
|
|
|
||
|
|
static readonly Color texture_button_border = new Color(.1f, .1f, .1f, 1f);
|
||
|
|
static readonly Color texture_button_fill = new Color(.18f, .18f, .18f, 1f);
|
||
|
|
|
||
|
|
static bool AttributeComponentButton(Rect rect, string text, Texture2D img, bool selected)
|
||
|
|
{
|
||
|
|
bool clicked = false;
|
||
|
|
|
||
|
|
Rect r = rect;
|
||
|
|
|
||
|
|
Rect border = new Rect(r.x + 2, r.y + 6, r.width - 4, r.height - 4);
|
||
|
|
|
||
|
|
EditorGUI.DrawRect(border, texture_button_border);
|
||
|
|
|
||
|
|
border.x += 2;
|
||
|
|
border.y += 2;
|
||
|
|
border.width -= 4;
|
||
|
|
border.height -= 4;
|
||
|
|
|
||
|
|
if(img != null)
|
||
|
|
{
|
||
|
|
EditorGUI.DrawPreviewTexture(border, img, null, ScaleMode.ScaleToFit, 0f);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
EditorGUI.DrawRect(border, texture_button_fill);
|
||
|
|
GUI.Label(border, text, PolyGUI.CenteredStyle);
|
||
|
|
}
|
||
|
|
|
||
|
|
if(selected)
|
||
|
|
{
|
||
|
|
r.y += r.height + 4;
|
||
|
|
r.x += 2;
|
||
|
|
r.width -= 5;
|
||
|
|
r.height = 6;
|
||
|
|
EditorGUI.DrawRect(r, Color.green);
|
||
|
|
}
|
||
|
|
|
||
|
|
clicked = GUI.Button(border, "", GUIStyle.none);
|
||
|
|
|
||
|
|
return clicked;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal static bool AssetPreviewButton(Rect rect, Object obj, bool selected)
|
||
|
|
{
|
||
|
|
bool clicked = false;
|
||
|
|
Rect r = rect;
|
||
|
|
Rect border = new Rect(r.x + 2, r.y + 6, r.width - 4, r.height - 4);
|
||
|
|
|
||
|
|
EditorGUI.DrawRect(border, texture_button_border);
|
||
|
|
|
||
|
|
border.x += 2;
|
||
|
|
border.y += 2;
|
||
|
|
border.width -= 4;
|
||
|
|
border.height -= 4;
|
||
|
|
|
||
|
|
Texture2D preview = PreviewsDatabase.GetAssetPreview(obj);
|
||
|
|
|
||
|
|
if(preview != null)
|
||
|
|
{
|
||
|
|
EditorGUI.DrawPreviewTexture(border, preview, null, ScaleMode.ScaleToFit, 0f);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
string text = obj != null ? obj.name : "null";
|
||
|
|
EditorGUI.DrawRect(border, texture_button_fill);
|
||
|
|
GUI.Label(border, text, PolyGUI.CenteredStyle);
|
||
|
|
}
|
||
|
|
|
||
|
|
if(selected)
|
||
|
|
{
|
||
|
|
r.y += r.height + 4;
|
||
|
|
r.x += 2;
|
||
|
|
r.width -= 5;
|
||
|
|
r.height = 6;
|
||
|
|
|
||
|
|
EditorGUI.DrawRect(r, Color.green);
|
||
|
|
}
|
||
|
|
|
||
|
|
clicked = GUI.Button(border, "", GUIStyle.none);
|
||
|
|
|
||
|
|
return clicked;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
internal static void Label(GUIContent gc)
|
||
|
|
{
|
||
|
|
EditorGUILayout.LabelField(gc,GUILayout.Width(140));
|
||
|
|
}
|
||
|
|
|
||
|
|
internal static bool Foldout(bool state, GUIContent content)
|
||
|
|
{
|
||
|
|
return EditorGUILayout.Foldout(state, content, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
public static bool Foldout(bool state, GUIContent content, GUILayoutOption[] options)
|
||
|
|
{
|
||
|
|
if (GUILayout.Button(PolyGUI.TempContent(""), state ? "FoldoutOpen" : "FoldoutClosed", options))
|
||
|
|
state = !state;
|
||
|
|
|
||
|
|
GUILayout.Label(content, options);
|
||
|
|
return state;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal static bool Toggle(GUIContent gc, bool isToggled)
|
||
|
|
{
|
||
|
|
using (new GUILayout.HorizontalScope())
|
||
|
|
{
|
||
|
|
EditorGUILayout.LabelField(gc,GUILayout.Width(140));
|
||
|
|
GUILayout.FlexibleSpace();
|
||
|
|
isToggled = EditorGUILayout.Toggle(isToggled, GUILayout.Width(15*(EditorGUI.indentLevel+1)));
|
||
|
|
}
|
||
|
|
|
||
|
|
return isToggled;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal static int PopupFieldWithTitle(GUIContent title, int selectionIndex, string[] values)
|
||
|
|
{
|
||
|
|
using (new GUILayout.HorizontalScope())
|
||
|
|
{
|
||
|
|
GUILayout.Label(title, GUILayout.Width(140));
|
||
|
|
int selection = EditorGUILayout.Popup(selectionIndex, values);
|
||
|
|
return selection;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
internal static float FloatField(GUIContent gc, float value, params GUILayoutOption[] options)
|
||
|
|
{
|
||
|
|
using (new GUILayout.HorizontalScope())
|
||
|
|
{
|
||
|
|
EditorGUILayout.LabelField(gc, GUILayout.Width(140));
|
||
|
|
float ret = EditorGUILayout.FloatField(value, "textfield");
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
internal static float FloatFieldWithSlider(GUIContent gc, float value, float minValue, float maxValue)
|
||
|
|
{
|
||
|
|
using (new GUILayout.HorizontalScope())
|
||
|
|
{
|
||
|
|
float returnValue = value;
|
||
|
|
|
||
|
|
EditorGUILayout.LabelField(gc, GUILayout.Width(100));
|
||
|
|
returnValue = EditorGUILayout.Slider(returnValue, minValue, maxValue);
|
||
|
|
returnValue = Mathf.Clamp(returnValue, minValue, maxValue);
|
||
|
|
|
||
|
|
return returnValue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
internal static Color ColorField(GUIContent gc, Color color)
|
||
|
|
{
|
||
|
|
if(gc != null && !string.IsNullOrEmpty(gc.text))
|
||
|
|
GUILayout.Label(gc);
|
||
|
|
|
||
|
|
var ret = EditorGUILayout.ColorField(PolyGUI.TempContent("", gc.tooltip), color);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal static Gradient GradientField(GUIContent gc, Gradient value)
|
||
|
|
{
|
||
|
|
GUILayout.Label(gc);
|
||
|
|
|
||
|
|
object out_gradient = EditorGUILayout.GradientField(PolyGUI.TempContent("", gc.tooltip), value, null);
|
||
|
|
|
||
|
|
return (Gradient) out_gradient;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal static bool HeaderWithDocsLink(GUIContent gc)
|
||
|
|
{
|
||
|
|
using (new GUILayout.HorizontalScope())
|
||
|
|
{
|
||
|
|
EditorGUILayout.LabelField(gc, EditorStyles.boldLabel);
|
||
|
|
GUILayout.FlexibleSpace();
|
||
|
|
|
||
|
|
GUIContent helpIcon = EditorGUIUtility.IconContent("_Help");
|
||
|
|
Vector2 iconSize = HelpStyle.CalcSize(helpIcon);
|
||
|
|
Rect rect = GUILayoutUtility.GetRect(iconSize.x, iconSize.y);
|
||
|
|
|
||
|
|
return GUI.Button(rect, helpIcon, HelpStyle);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|