Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
ai.fluctio.fluctio-sim / EditorUtils / Gui / EditorGUIExtensions.cs
Size: Mime:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Fluctio.FluctioSim.Common.Icons;
using Fluctio.FluctioSim.EditorUtils.EditorGeneral;
using Fluctio.FluctioSim.Utils.Extensions;
using Fluctio.FluctioSim.Utils.General;
using JetBrains.Annotations;
using UnityEditor;
using UnityEditor.AnimatedValues;
using UnityEngine;
using UnityEngine.UIElements;

namespace Fluctio.FluctioSim.EditorUtils.Gui
{
	public static class EditorGUIExtensions
	{

		#region General property drawing
		
		private static SerializedProperty FindFieldOrPropertyInternal(Func<string, SerializedProperty> fieldOnlyFinder, string fieldOrPropertyName) =>
			fieldOnlyFinder(fieldOrPropertyName) ?? fieldOnlyFinder(Util.GetBackingFieldName(fieldOrPropertyName));

		public static SerializedProperty FindFieldOrProperty(this SerializedObject serializedObject, string fieldOrPropertyName) =>
			FindFieldOrPropertyInternal(serializedObject.FindProperty, fieldOrPropertyName);

		public static SerializedProperty FindFieldOrProperty(this SerializedProperty serializedProperty, string fieldOrPropertyName) =>
			FindFieldOrPropertyInternal(serializedProperty.FindPropertyRelative, fieldOrPropertyName);

		private static bool DrawPropertiesInternal(
			SerializedObject serializedObject,
			Func<string, SerializedProperty> fieldOrPropertyFinder,
			params string[] propertyNames)
		{
			serializedObject.Update();
			foreach (var propertyName in propertyNames)
			{
				var fieldOrProperty = fieldOrPropertyFinder(propertyName);
				if (fieldOrProperty == null)
				{
					// ReSharper disable once Unity.PerformanceCriticalCodeInvocation
					Debug.LogWarning($"Could not find field or property '{propertyName}'");
					continue;
				}
				EditorGUILayout.PropertyField(fieldOrProperty, true);
			}
			return serializedObject.ApplyModifiedProperties();
		}

		public static bool DrawProperties(this SerializedObject serializedObject, params string[] propertyNames) =>
			DrawPropertiesInternal(serializedObject, serializedObject.FindFieldOrProperty, propertyNames);

		public static bool DrawProperties(this SerializedProperty serializedProperty, params string[] propertyNames) =>
			DrawPropertiesInternal(serializedProperty.serializedObject, serializedProperty.FindFieldOrProperty, propertyNames);
		
		#endregion

		#region LeftClickButton

		public static bool LeftClickButton(GUIContent label, [CanBeNull] GUIStyle style = null, params GUILayoutOption[] layoutOptions)
		{
			style ??= GUI.skin.button;
			var isButtonClicked = GUILayout.Button(label, style, layoutOptions);
			EditorGUIUtility.AddCursorRect(GUILayoutUtility.GetLastRect(), MouseCursor.Link, GUIUtility.GetControlID(FocusType.Passive));
			var isLeftButton = Event.current.button == (int)MouseButton.LeftMouse;
			return isButtonClicked && isLeftButton;
		}

		public static bool LeftClickButton(GUIContent label, params GUILayoutOption[] layoutOptions) =>
			LeftClickButton(label, null, layoutOptions);

		public static bool LeftClickButton(string label, params GUILayoutOption[] layoutOptions) =>
			LeftClickButton(new GUIContent(label), layoutOptions);

		public static bool LeftClickButton(Texture2D label, params GUILayoutOption[] layoutOptions) =>
			LeftClickButton(new GUIContent(label), layoutOptions);

		public static bool LeftClickButton(string label, GUIStyle style, params GUILayoutOption[] layoutOptions) =>
			LeftClickButton(new GUIContent(label), style, layoutOptions);

		public static bool LeftClickButton(Texture2D label, GUIStyle style, params GUILayoutOption[] layoutOptions) =>
			LeftClickButton(new GUIContent(label), style, layoutOptions);

		#endregion

		#region TypedDropdown

		public static T TypedDropdown<T>(string label, List<T> values, T oldValue, Func<T, string> displayNameGetter)
		{
			var oldIndex = values.FindIndex(value => Equals(value, oldValue));
			var displayNames = values.Select(displayNameGetter);
			
			if (oldIndex < 0)
			{
				var oldDisplayName = displayNameGetter(oldValue);
				EditorGUILayout.HelpBox($"\"{oldDisplayName}\" is not a valid value for \"{label}\"", MessageType.Warning);
				displayNames = displayNames.Append(oldDisplayName);
				oldIndex = values.Count;
			}
			
			var newIndex = EditorGUILayout.Popup(label, oldIndex, displayNames.ToArray());
			return newIndex < values.Count ? values[newIndex] : oldValue;
		}

		public static string TypedDropdown(string label, List<string> values, string oldValue) =>
			TypedDropdown(label, values, oldValue, Util.Identity);

		public static T TypedDropdown<T>(string label, T oldValue) where T: Enum
		{
			var values = ReflectionExtensions.GetEnumOptions<T>().ToList();
			return TypedDropdown(label, values, oldValue, EnumDisplayGetter);
			string EnumDisplayGetter(T enumValue) => enumValue.AsField().GetDescription();
		}
		
		#endregion

		#region Other

		public static string FilePicker(string label, string currentValue, string extensions, string defaultDirectory = "")
		{
			using var horizontalScope = new EditorGUILayout.HorizontalScope();
			var textFieldValue = EditorGUILayout.TextField(label, currentValue);
			var isButtonClicked = EditorGUIExtensions.LeftClickButton(DefinedIcons.FilePicker, EditorUtil.InlineIconStyle);
			if (!isButtonClicked)
			{
				return textFieldValue;
			}
			
			var directory = string.IsNullOrWhiteSpace(currentValue)
				? defaultDirectory
				: Path.GetDirectoryName(currentValue);
			var filePanelValue = EditorUtility.OpenFilePanel(label, directory, extensions);
			if (filePanelValue == "")
			{
				return currentValue;
			}
			
			EditorGUIUtility.editingTextField = false;
			return filePanelValue;
		}

		public static void HorizontalLine() => EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);

		public static bool WebLink(string url, string text = null)
		{
			text ??= url;
			var isClicked = EditorGUILayout.LinkButton(text);
			if (isClicked)
			{
				Application.OpenURL(url);
			}
			return isClicked;
		}

		public static void Foldout(GUIContent label, AnimBool isOpen, Action drawAction, bool isFoldout = true, string additionalInfo = null)
		{
			if (!isFoldout)
			{
				GUILayout.Label(label);
				drawAction();
				return;
			}

			if (!isOpen.target && !string.IsNullOrWhiteSpace(additionalInfo))
			{
				label.text += $" ({additionalInfo})";
			}
			isOpen.target = EditorGUILayout.Foldout(isOpen.target, label, true);
			using var fadeGroupScope = new EditorGUILayout.FadeGroupScope(isOpen.faded);
			if (!isOpen.value)
			{
				return;
			}
			
			using var indentScope = new EditorGUI.IndentLevelScope();
			drawAction();
		}

		public static void Foldout(string label, AnimBool isOpen, Action drawAction, bool isFoldout = true) =>
			Foldout(new GUIContent(label), isOpen, drawAction, isFoldout);

		public static void ThrowingDialog(string message, string ok = "OK", string cancel = "Cancel", string title = "Are you sure?", string exceptionMessage = "")
		{
			var isConfirmed = EditorUtility.DisplayDialog(title, message, ok, cancel);
			if (!isConfirmed)
			{
				throw new OperationCanceledException(exceptionMessage);
			}
		}

		#endregion
		
	}
}