Merge pull request 'better-ui-manager' (#2) from better-ui-manager into main
Reviewed-on: http://newexceptiongames.dynamic-dns.net:3000/NewExceptionGames/Neg_Utils/pulls/2
This commit is contained in:
commit
d06350da06
46
Editor/MonoBehaviourExtensions.cs
Normal file
46
Editor/MonoBehaviourExtensions.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace NEG.Utils.Editor
|
||||
{
|
||||
public static class MonoBehaviourExtensions
|
||||
{
|
||||
[MenuItem("CONTEXT/MonoBehaviour/Change Script")]
|
||||
public static void ChangeScript(MenuCommand command)
|
||||
{
|
||||
if (command.context == null)
|
||||
return;
|
||||
|
||||
var monoBehaviour = command.context as MonoBehaviour;
|
||||
var monoScript = MonoScript.FromMonoBehaviour(monoBehaviour);
|
||||
|
||||
string scriptPath = AssetDatabase.GetAssetPath(monoScript);
|
||||
string directoryPath = new FileInfo(scriptPath).Directory?.FullName;
|
||||
|
||||
// Allow the user to select which script to replace with
|
||||
string newScriptPath = EditorUtility.OpenFilePanel("Select replacement script", directoryPath, "cs");
|
||||
|
||||
// Don't log anything if they cancelled the window
|
||||
if (string.IsNullOrEmpty(newScriptPath)) return;
|
||||
|
||||
// Load the selected asset
|
||||
string relativePath = "Assets\\" + Path.GetRelativePath(Application.dataPath, newScriptPath);
|
||||
var chosenTextAsset = AssetDatabase.LoadAssetAtPath<TextAsset>(relativePath);
|
||||
|
||||
if (chosenTextAsset == null)
|
||||
{
|
||||
Debug.LogWarning($"Selected script couldn't be loaded ({relativePath})");
|
||||
return;
|
||||
}
|
||||
|
||||
Undo.RegisterCompleteObjectUndo(command.context, "Changing component script");
|
||||
|
||||
var so = new SerializedObject(monoBehaviour);
|
||||
var scriptProperty = so.FindProperty("m_Script");
|
||||
so.Update();
|
||||
scriptProperty.objectReferenceValue = chosenTextAsset;
|
||||
so.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Editor/MonoBehaviourExtensions.cs.meta
Normal file
3
Editor/MonoBehaviourExtensions.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0501eedeaf1d4dcf8c4d0f1b7a0c1761
|
||||
timeCreated: 1684519404
|
||||
21
Editor/ScreenshotMaker.cs
Normal file
21
Editor/ScreenshotMaker.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NEG.Editor
|
||||
{
|
||||
public static class ScreenshotMaker
|
||||
{
|
||||
[MenuItem("CONTEXT/Camera/Save view")]
|
||||
public static void Capture(MenuCommand command)
|
||||
{
|
||||
string path = EditorUtility.SaveFilePanel("Save screenshot", "", "screen.png", "png");
|
||||
if (path.Length == 0)
|
||||
return;
|
||||
|
||||
ScreenCapture.CaptureScreenshot(path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
3
Editor/ScreenshotMaker.cs.meta
Normal file
3
Editor/ScreenshotMaker.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7dba407e8e8740a1bed3ee5fa833b13c
|
||||
timeCreated: 1687881092
|
||||
@ -15,7 +15,7 @@ namespace NEG.Utils.Serialization
|
||||
return @this.FindPropertyRelative(GetBackingFieldName(name));
|
||||
}
|
||||
|
||||
private static string GetBackingFieldName(string name)
|
||||
public static string GetBackingFieldName(string name)
|
||||
{
|
||||
#if NET_STANDARD || NET_STANDARD_2_1
|
||||
return string.Create(1/*<*/ + name.Length + 16/*>k__BackingField*/, name, static (span, name) =>
|
||||
|
||||
16
Editor/TsvImporter.cs
Normal file
16
Editor/TsvImporter.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEditor.AssetImporters;
|
||||
using UnityEditor.Experimental.AssetImporters;
|
||||
using UnityEngine;
|
||||
|
||||
[ScriptedImporter(1, "tsv")]
|
||||
public class TsvImporter : ScriptedImporter
|
||||
{
|
||||
public override void OnImportAsset(AssetImportContext ctx)
|
||||
{
|
||||
var textAsset = new TextAsset(File.ReadAllText(ctx.assetPath));
|
||||
ctx.AddObjectToAsset(Path.GetFileNameWithoutExtension(ctx.assetPath), textAsset);
|
||||
ctx.SetMainObject(textAsset);
|
||||
}
|
||||
}
|
||||
11
Editor/TsvImporter.cs.meta
Normal file
11
Editor/TsvImporter.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3f8438db4084014bab0a063e4675d3f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
54
KeyBasedFactory.cs
Normal file
54
KeyBasedFactory.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace NEG.Utils
|
||||
{
|
||||
public class KeyBasedFactory<T1, T2>
|
||||
{
|
||||
[PublicAPI]
|
||||
protected Dictionary<T1, Type> data;
|
||||
|
||||
public KeyBasedFactory()
|
||||
{
|
||||
data = new Dictionary<T1, Type>();
|
||||
}
|
||||
|
||||
public void FireRegistration()
|
||||
{
|
||||
ScanAssembly(typeof(T2).Assembly);
|
||||
|
||||
if(typeof(T2).Assembly.GetType().Assembly == typeof(T2).Assembly)
|
||||
return;
|
||||
|
||||
ScanAssembly(typeof(T2).Assembly.GetType().Assembly);
|
||||
}
|
||||
|
||||
private static void ScanAssembly(Assembly assembly)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
var methodFields =
|
||||
type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
for (int i = 0; i < methodFields.Length; i++)
|
||||
{
|
||||
if (Attribute.GetCustomAttribute(methodFields[i], typeof(FactoryRegistration)) != null)
|
||||
{
|
||||
methodFields[i].Invoke(null, Array.Empty<object>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Register(T1 key, Type type) => data.Add(key, type);
|
||||
|
||||
public T2 CreateInstance(T1 key, params object[] args) => (T2)Activator.CreateInstance(data[key], args);
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class FactoryRegistration : Attribute
|
||||
{
|
||||
public FactoryRegistration() { }
|
||||
}
|
||||
}
|
||||
3
KeyBasedFactory.cs.meta
Normal file
3
KeyBasedFactory.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e0d3df1ddd34209bfb7262b4e51abfe
|
||||
timeCreated: 1683917310
|
||||
@ -1,9 +1,11 @@
|
||||
using NEG.UI.WindowSlot;
|
||||
using NegUtils.NEG.UI;
|
||||
|
||||
namespace NEG.UI.Area
|
||||
{
|
||||
public interface IArea : ISlotsHolder, IUiElement
|
||||
public interface IArea : ISlotsHolder, IControllable
|
||||
{
|
||||
|
||||
void Open();
|
||||
void Close();
|
||||
}
|
||||
}
|
||||
18
NEG/UI/IControllable.cs
Normal file
18
NEG/UI/IControllable.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace NegUtils.NEG.UI
|
||||
{
|
||||
public interface IControllable
|
||||
{
|
||||
public class BackUsed
|
||||
{
|
||||
public bool Used { get; set; }
|
||||
}
|
||||
|
||||
event Action<object> OnOpened;
|
||||
event Action OnClosed;
|
||||
event Action<BackUsed> OnBackUsed;
|
||||
|
||||
public void TryUseBack(ref BackUsed backUsed);
|
||||
}
|
||||
}
|
||||
3
NEG/UI/IControllable.cs.meta
Normal file
3
NEG/UI/IControllable.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 175798310e4048eda768cf40e6ee6de3
|
||||
timeCreated: 1686596400
|
||||
7
NEG/UI/IController.cs
Normal file
7
NEG/UI/IController.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace NegUtils.NEG.UI
|
||||
{
|
||||
public interface IController
|
||||
{
|
||||
IControllable Controllable { get; }
|
||||
}
|
||||
}
|
||||
3
NEG/UI/IController.cs.meta
Normal file
3
NEG/UI/IController.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b88f4a93020a4bc6bde40e0438d296a9
|
||||
timeCreated: 1686595825
|
||||
@ -1,11 +0,0 @@
|
||||
namespace NEG.UI
|
||||
{
|
||||
public interface IUiElement
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets only visible state of element
|
||||
/// </summary>
|
||||
/// <param name="setEnabled"></param>
|
||||
void SetEnabled(bool setEnabled);
|
||||
}
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 296bf6969a6347f8aea788a7bdd086af
|
||||
timeCreated: 1670693177
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "NEG.UI",
|
||||
"rootNamespace": "",
|
||||
"references": [],
|
||||
"references": ["GUID:3c4294719a93e3c4e831a9ff0c261e8a"],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
|
||||
@ -2,6 +2,8 @@ using JetBrains.Annotations;
|
||||
using NEG.UI.Area;
|
||||
using NEG.UI.Popup;
|
||||
using NEG.UI.Window;
|
||||
using NEG.Utils;
|
||||
using NegUtils.NEG.UI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
@ -9,9 +11,9 @@ using UnityEngine;
|
||||
namespace NEG.UI
|
||||
{
|
||||
[PublicAPI]
|
||||
public abstract class UiManager
|
||||
public abstract class UiManager : IDisposable
|
||||
{
|
||||
public static UiManager Instance { get; private set; }
|
||||
public static UiManager Instance { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current area shown on screen.
|
||||
@ -21,11 +23,11 @@ namespace NEG.UI
|
||||
get => currentArea;
|
||||
set
|
||||
{
|
||||
currentArea?.SetEnabled(false);
|
||||
currentArea?.Close();
|
||||
|
||||
currentArea = value;
|
||||
|
||||
currentArea?.SetEnabled(true);
|
||||
currentArea?.Open();
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,6 +126,17 @@ namespace NEG.UI
|
||||
UpdatePopupsState(forceShow, priority, data);
|
||||
}
|
||||
|
||||
public void UseBack()
|
||||
{
|
||||
IControllable.BackUsed backUsed = new();
|
||||
|
||||
CurrentMainWindow?.TryUseBack(ref backUsed);
|
||||
if(backUsed.Used)
|
||||
return;
|
||||
CurrentArea.TryUseBack(ref backUsed);
|
||||
}
|
||||
|
||||
|
||||
public void RefreshPopups()
|
||||
{
|
||||
if(currentShownPopup.data is { IsValid: true })
|
||||
@ -131,6 +144,18 @@ namespace NEG.UI
|
||||
UpdatePopupsState(false);
|
||||
}
|
||||
|
||||
public virtual void Dispose() => Instance = null;
|
||||
|
||||
public void SetMainWindow(IWindow window) => CurrentMainWindow = window;
|
||||
|
||||
public void OnWindowClosed(IWindow window)
|
||||
{
|
||||
if(CurrentMainWindow != window)
|
||||
return;
|
||||
|
||||
//TODO: select new main window
|
||||
}
|
||||
|
||||
protected void PopupClosed(PopupData data)
|
||||
{
|
||||
if (currentShownPopup.data != data)
|
||||
@ -143,11 +168,12 @@ namespace NEG.UI
|
||||
|
||||
protected void SetDefaultPopup(IDefaultPopup popup) => currentDefaultPopup = popup;
|
||||
|
||||
|
||||
private void UpdatePopupsState(bool forceShow, int priority = 0, PopupData data = null)
|
||||
{
|
||||
if (forceShow)
|
||||
{
|
||||
if(currentShownPopup.priority <= priority)
|
||||
if(currentShownPopup.data != null && currentShownPopup.priority >= priority)
|
||||
return;
|
||||
|
||||
popupsToShow.Enqueue(currentShownPopup.data, currentShownPopup.priority);
|
||||
@ -159,6 +185,8 @@ namespace NEG.UI
|
||||
{
|
||||
if(!d.IsValid)
|
||||
continue;
|
||||
if(d == currentShownPopup.data)
|
||||
continue;
|
||||
ShowPopup(d, p);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using NEG.UI.UnityUi.Window;
|
||||
using NEG.UI.Window;
|
||||
using System;
|
||||
using KBCore.Refs;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NEG.UI.Area
|
||||
|
||||
19
NEG/UI/UnityUi/Area/CloseMainWindowOnBack.cs
Normal file
19
NEG/UI/UnityUi/Area/CloseMainWindowOnBack.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using KBCore.Refs;
|
||||
using NEG.UI.UnityUi;
|
||||
using NEG.UI.Window;
|
||||
using NegUtils.NEG.UI;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NEG.UI.Area
|
||||
{
|
||||
public class CloseMainWindowOnBack : MonoController
|
||||
{
|
||||
protected override void OnBackUsed(IControllable.BackUsed backUsed)
|
||||
{
|
||||
base.OnBackUsed(backUsed);
|
||||
UiManager.Instance.CurrentMainWindow.Close();
|
||||
backUsed.Used = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
NEG/UI/UnityUi/Area/CloseMainWindowOnBack.cs.meta
Normal file
3
NEG/UI/UnityUi/Area/CloseMainWindowOnBack.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ec2bf64cda740a1849d024d4f163a01
|
||||
timeCreated: 1686598066
|
||||
@ -5,12 +5,17 @@ using NEG.UI.UnityUi.Window;
|
||||
using NEG.UI.UnityUi.WindowSlot;
|
||||
using NEG.UI.Window;
|
||||
using NEG.UI.WindowSlot;
|
||||
using NegUtils.NEG.UI;
|
||||
using System;
|
||||
|
||||
namespace NEG.UI.Area
|
||||
{
|
||||
public class MonoArea : MonoBehaviour, IArea
|
||||
{
|
||||
public event Action<object> OnOpened;
|
||||
public event Action OnClosed;
|
||||
public event Action<IControllable.BackUsed> OnBackUsed;
|
||||
|
||||
public IEnumerable<IWindowSlot> AvailableSlots => windowSlots;
|
||||
public IWindowSlot DefaultWindowSlot => windowSlots[0];
|
||||
|
||||
@ -18,24 +23,37 @@ namespace NEG.UI.Area
|
||||
|
||||
[SerializeField] private List<MonoWindowSlot> windowSlots;
|
||||
|
||||
public virtual void SetEnabled(bool setEnabled) => gameObject.SetActive(setEnabled);
|
||||
|
||||
public virtual void OpenWindow(IWindow window, object data = null)
|
||||
public void Open()
|
||||
{
|
||||
DefaultWindowSlot.AttachWindow(window);
|
||||
window.SetData(data);
|
||||
gameObject.SetActive(true);
|
||||
OnOpened?.Invoke(null);
|
||||
}
|
||||
|
||||
protected virtual void Awake()
|
||||
public void Close(){
|
||||
gameObject.SetActive(false);
|
||||
OnClosed?.Invoke();
|
||||
}
|
||||
|
||||
public void OpenWindow(IWindow window, object data = null) => DefaultWindowSlot.AttachWindow(window, data);
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (setAsDefaultArea)
|
||||
UiManager.Instance.CurrentArea = this;
|
||||
}
|
||||
|
||||
protected virtual void OnDestroy()
|
||||
private void Start()
|
||||
{
|
||||
if(!setAsDefaultArea)
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (ReferenceEquals(UiManager.Instance.CurrentArea, this))
|
||||
UiManager.Instance.CurrentArea = null;
|
||||
}
|
||||
|
||||
public void TryUseBack(ref IControllable.BackUsed backUsed) => OnBackUsed?.Invoke(backUsed);
|
||||
}
|
||||
}
|
||||
@ -1,77 +1,96 @@
|
||||
using FMOD.Studio;
|
||||
using FMODUnity;
|
||||
using KBCore.Refs;
|
||||
using NEG.UI.UnityUi.Buttons.Reaction;
|
||||
using NEG.UI.UnityUi.Buttons.Settings;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Serialization;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace NEG.UI.UnityUi.Buttons
|
||||
{
|
||||
[RequireComponent(typeof(ButtonSerializeFields))]
|
||||
[DefaultExecutionOrder(-1)]
|
||||
[RequireComponent(typeof(Button))]
|
||||
public class BaseButton : MonoBehaviour, ISelectHandler, IDeselectHandler, IPointerEnterHandler, IPointerExitHandler
|
||||
{
|
||||
public delegate void SelectionHandler(bool isSilent);
|
||||
/// <summary>
|
||||
/// is silent
|
||||
/// </summary>
|
||||
public event SelectionHandler OnSelected;
|
||||
public event SelectionHandler OnDeselected;
|
||||
public event Action OnButtonPressed;
|
||||
|
||||
public bool Interactable { get => serializeFields.Button.interactable; set => serializeFields.Button.interactable = value; }
|
||||
public bool Interactable { get => button.interactable; set => button.interactable = value; }
|
||||
|
||||
[SerializeField]
|
||||
protected ButtonSerializeFields serializeFields;
|
||||
public TMP_Text Text => text;
|
||||
|
||||
private bool isHovered;
|
||||
[SerializeField, Self(Flag.Optional)] private Button button;
|
||||
[SerializeField, Child(Flag.Optional)] private TMP_Text text;
|
||||
[SerializeField, Child(Flag.Optional)] private Image icon;
|
||||
|
||||
public virtual void OnSelect(BaseEventData eventData)
|
||||
{
|
||||
if (serializeFields.Text)
|
||||
serializeFields.Text.color = serializeFields.SelectedTextColor;
|
||||
}
|
||||
[SerializeField] private ButtonSettings groupButtonSettings;
|
||||
|
||||
public void OnDeselect(BaseEventData eventData)
|
||||
{
|
||||
if (serializeFields.Text)
|
||||
serializeFields.Text.color = serializeFields.DeselectedTextColor;
|
||||
}
|
||||
private readonly Dictionary<string, ButtonElementBehaviour> behaviours = new Dictionary<string, ButtonElementBehaviour>();
|
||||
|
||||
public void OnPointerEnter(PointerEventData eventData)
|
||||
{
|
||||
isHovered = true;
|
||||
if (serializeFields.Text)
|
||||
serializeFields.Text.color = serializeFields.SelectedTextColor;
|
||||
}
|
||||
public virtual void OnSelect(BaseEventData eventData) => OnSelected?.Invoke(eventData is SilentEventData);
|
||||
|
||||
public void OnDeselect(BaseEventData eventData) => OnDeselected?.Invoke(eventData is SilentEventData);
|
||||
|
||||
public void OnPointerEnter(PointerEventData eventData) => EventSystem.current.SetSelectedGameObject(gameObject);
|
||||
|
||||
public void OnPointerExit(PointerEventData eventData)
|
||||
{
|
||||
isHovered = false;
|
||||
if (serializeFields.Text)
|
||||
serializeFields.Text.color = serializeFields.DeselectedTextColor;
|
||||
if(EventSystem.current.currentSelectedGameObject == gameObject)
|
||||
EventSystem.current.SetSelectedGameObject(null);
|
||||
}
|
||||
|
||||
public void SetText(string text)
|
||||
public void SetText(string txt)
|
||||
{
|
||||
if(serializeFields == null)
|
||||
if(text == null)
|
||||
return;
|
||||
if(serializeFields.Text == null)
|
||||
text.text = txt;
|
||||
}
|
||||
|
||||
public void AddOrOverrideSetting(SettingData data)
|
||||
{
|
||||
if (behaviours.TryGetValue(data.Key, out var setting))
|
||||
{
|
||||
setting.ChangeData(data);
|
||||
return;
|
||||
serializeFields.Text.text = text;
|
||||
}
|
||||
behaviours.Add(data.Key, MonoUiManager.Instance.BehavioursFactory.CreateInstance(data.Key, this, data));
|
||||
}
|
||||
|
||||
public void RemoveSetting(string key)
|
||||
{
|
||||
if (!behaviours.TryGetValue(key, out var setting))
|
||||
{
|
||||
Debug.LogError($"Behaviour with key {key} was not found");
|
||||
return;
|
||||
}
|
||||
setting.Dispose();
|
||||
behaviours.Remove(key);
|
||||
}
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
if(serializeFields == null)
|
||||
serializeFields = GetComponent<ButtonSerializeFields>();
|
||||
serializeFields.Button.onClick.AddListener(OnClicked);
|
||||
OnDeselect(null);
|
||||
button.onClick.AddListener(OnClicked);
|
||||
if (groupButtonSettings == null)
|
||||
MonoUiManager.Instance.DefaultUiSettings.Apply(this);
|
||||
else
|
||||
groupButtonSettings.Apply(this);
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
if(serializeFields == null)
|
||||
serializeFields = GetComponent<ButtonSerializeFields>();
|
||||
}
|
||||
private void Start() => OnDeselect(null);
|
||||
|
||||
private void OnValidate() => this.ValidateRefs();
|
||||
|
||||
protected virtual void OnClicked()
|
||||
{
|
||||
OnDeselect(null);
|
||||
isHovered = false;
|
||||
OnButtonPressed?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a250ef2d0c34e7396a16fc5eddbdb01
|
||||
timeCreated: 1670777213
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -1
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using KBCore.Refs;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NEG.UI.UnityUi.Buttons
|
||||
@ -6,9 +7,13 @@ namespace NEG.UI.UnityUi.Buttons
|
||||
[RequireComponent(typeof(BaseButton))]
|
||||
public abstract class ButtonReaction : MonoBehaviour
|
||||
{
|
||||
protected virtual void Awake() => GetComponent<BaseButton>().OnButtonPressed += OnClicked;
|
||||
[SerializeField, Self(Flag.Optional)] protected BaseButton button;
|
||||
|
||||
protected virtual void OnDestroy() => GetComponent<BaseButton>().OnButtonPressed -= OnClicked;
|
||||
protected virtual void Awake() => button.OnButtonPressed += OnClicked;
|
||||
|
||||
protected virtual void OnDestroy() => button.OnButtonPressed -= OnClicked;
|
||||
|
||||
private void OnValidate() => this.ValidateRefs();
|
||||
|
||||
protected abstract void OnClicked();
|
||||
}
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
using FMODUnity;
|
||||
using System;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace NEG.UI.UnityUi.Buttons
|
||||
{
|
||||
public class ButtonSerializeFields : MonoBehaviour
|
||||
{
|
||||
[field: SerializeField]
|
||||
public Button Button { get; private set; }
|
||||
[field: SerializeField]
|
||||
public TMP_Text Text { get; private set; }
|
||||
[field: SerializeField]
|
||||
public Color SelectedTextColor { get; private set; }
|
||||
[field: SerializeField]
|
||||
public Color DeselectedTextColor { get; private set; }
|
||||
[field: SerializeField]
|
||||
public EventReference HoverEventRef { get; private set; }
|
||||
[field: SerializeField]
|
||||
public EventReference ClickEventRef { get; private set; }
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
if(Button == null)
|
||||
Button = GetComponent<Button>();
|
||||
if (Text == null)
|
||||
Text = GetComponentInChildren<TMP_Text>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f8c6cf4cf18463c86ec1165c61c79b2
|
||||
timeCreated: 1670777232
|
||||
63
NEG/UI/UnityUi/Buttons/CustomNavigationButton.cs
Normal file
63
NEG/UI/UnityUi/Buttons/CustomNavigationButton.cs
Normal file
@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace NEG.UI.UnityUi.Buttons
|
||||
{
|
||||
public class CustomNavigationButton : Button
|
||||
{
|
||||
[SerializeField] [HideInInspector] private OverridableNavigation upOverride;
|
||||
[SerializeField] private OverridableNavigation downOverride;
|
||||
[SerializeField] private OverridableNavigation leftOverride;
|
||||
[SerializeField] private OverridableNavigation rightOverride;
|
||||
|
||||
|
||||
public override void OnMove(AxisEventData eventData)
|
||||
{
|
||||
switch (eventData.moveDir)
|
||||
{
|
||||
case MoveDirection.Left:
|
||||
if(TryNavigate(eventData, leftOverride))
|
||||
return;
|
||||
break;
|
||||
case MoveDirection.Up:
|
||||
if(TryNavigate(eventData, upOverride))
|
||||
return;
|
||||
break;
|
||||
case MoveDirection.Right:
|
||||
if(TryNavigate(eventData, rightOverride))
|
||||
return;
|
||||
break;
|
||||
case MoveDirection.Down:
|
||||
if(TryNavigate(eventData, downOverride))
|
||||
return;
|
||||
break;
|
||||
case MoveDirection.None:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
base.OnMove(eventData);
|
||||
}
|
||||
|
||||
public static bool TryNavigate(BaseEventData eventData, OverridableNavigation overrideNavigation)
|
||||
{
|
||||
if(!overrideNavigation.Override)
|
||||
return false;
|
||||
|
||||
if (overrideNavigation.Selectable == null || !overrideNavigation.Selectable.IsActive())
|
||||
return true;
|
||||
|
||||
eventData.selectedObject = overrideNavigation.Selectable.gameObject;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class OverridableNavigation
|
||||
{
|
||||
[field: SerializeField] public bool Override { get; private set; }
|
||||
[field: SerializeField] public Selectable Selectable { get; private set; }
|
||||
}
|
||||
}
|
||||
3
NEG/UI/UnityUi/Buttons/CustomNavigationButton.cs.meta
Normal file
3
NEG/UI/UnityUi/Buttons/CustomNavigationButton.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9b5ca8863c240f792232d6e276d8d56
|
||||
timeCreated: 1684520970
|
||||
15
NEG/UI/UnityUi/Buttons/OpenAsCurrentMainChild.cs
Normal file
15
NEG/UI/UnityUi/Buttons/OpenAsCurrentMainChild.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using KBCore.Refs;
|
||||
using NEG.UI.UnityUi.Window;
|
||||
using NEG.UI.Window;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NEG.UI.UnityUi.Buttons
|
||||
{
|
||||
public class OpenAsCurrentMainChild : ButtonReaction
|
||||
{
|
||||
[SerializeField]
|
||||
private MonoWindow windowToOpen;
|
||||
|
||||
protected override void OnClicked() => UiManager.Instance.CurrentMainWindow.OpenAsChild(windowToOpen);
|
||||
}
|
||||
}
|
||||
3
NEG/UI/UnityUi/Buttons/OpenAsCurrentMainChild.cs.meta
Normal file
3
NEG/UI/UnityUi/Buttons/OpenAsCurrentMainChild.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 049e222140c94fc28fb36bca4aaddba4
|
||||
timeCreated: 1686595194
|
||||
3
NEG/UI/UnityUi/Buttons/Reaction.meta
Normal file
3
NEG/UI/UnityUi/Buttons/Reaction.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 953c3353e3af44258625fe607ede632b
|
||||
timeCreated: 1683915598
|
||||
22
NEG/UI/UnityUi/Buttons/Reaction/ButtonElementBehaviour.cs
Normal file
22
NEG/UI/UnityUi/Buttons/Reaction/ButtonElementBehaviour.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using NEG.UI.UnityUi.Buttons.Settings;
|
||||
using System;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace NEG.UI.UnityUi.Buttons.Reaction
|
||||
{
|
||||
public abstract class ButtonElementBehaviour : IDisposable
|
||||
{
|
||||
protected SettingData baseData;
|
||||
protected readonly BaseButton button;
|
||||
|
||||
public ButtonElementBehaviour(BaseButton baseButton, SettingData settingData)
|
||||
{
|
||||
button = baseButton;
|
||||
baseData = settingData;
|
||||
}
|
||||
|
||||
public virtual void ChangeData(SettingData newData) => baseData = newData;
|
||||
|
||||
public abstract void Dispose();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5e3decad6424cb288eff3e6f7e0d28e
|
||||
timeCreated: 1683919740
|
||||
43
NEG/UI/UnityUi/Buttons/Reaction/ChangeTextColorBehaviour.cs
Normal file
43
NEG/UI/UnityUi/Buttons/Reaction/ChangeTextColorBehaviour.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using NEG.UI.UnityUi.Buttons.Settings;
|
||||
using NEG.Utils;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace NEG.UI.UnityUi.Buttons.Reaction
|
||||
{
|
||||
public class ChangeTextColorBehaviour : ButtonElementBehaviour
|
||||
{
|
||||
private ColorData data;
|
||||
|
||||
public ChangeTextColorBehaviour(BaseButton baseButton, ColorData data) : base(baseButton, data)
|
||||
{
|
||||
if (baseButton.Text == null)
|
||||
return;
|
||||
|
||||
baseButton.OnSelected += OnButtonSelected;
|
||||
baseButton.OnDeselected += OnButtonDeselected;
|
||||
ChangeData(data);
|
||||
}
|
||||
|
||||
public override void ChangeData(SettingData newData)
|
||||
{
|
||||
base.ChangeData(newData);
|
||||
Debug.Assert(newData is ColorData, "newData is not ColorData");
|
||||
data = (ColorData)newData;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
button.OnSelected -= OnButtonSelected;
|
||||
button.OnDeselected -= OnButtonDeselected;
|
||||
}
|
||||
|
||||
[FactoryRegistration]
|
||||
private static void RegisterInFactory() =>
|
||||
MonoUiManager.Instance.BehavioursFactory.Register("ChangeTextColor", typeof(ChangeTextColorBehaviour));
|
||||
|
||||
private void OnButtonSelected(bool _) => button.Text.color = data.SelectedColor;
|
||||
private void OnButtonDeselected(bool _) => button.Text.color = data.DeselectedColor;
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2079225d6e34001ae85f74a0a418d68
|
||||
timeCreated: 1683919878
|
||||
24
NEG/UI/UnityUi/Buttons/Reaction/SimpleSoundBehaviour.cs
Normal file
24
NEG/UI/UnityUi/Buttons/Reaction/SimpleSoundBehaviour.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using NEG.UI.UnityUi.Buttons.Settings;
|
||||
using NEG.Utils;
|
||||
#if FMOD
|
||||
|
||||
namespace NEG.UI.UnityUi.Buttons.Reaction
|
||||
{
|
||||
public class SimpleSoundBehaviour : ButtonElementBehaviour
|
||||
{
|
||||
public SimpleSoundBehaviour(BaseButton baseButton, FmodSoundData data) : base(baseButton, data)
|
||||
{
|
||||
//TODO: use silnet to not play sound
|
||||
}
|
||||
|
||||
[FactoryRegistration]
|
||||
private static void RegisterInFactory() =>
|
||||
MonoUiManager.Instance.BehavioursFactory.Register("SimpleSound", typeof(SimpleSoundBehaviour));
|
||||
|
||||
public override void ChangeData(SettingData newData) => throw new System.NotImplementedException();
|
||||
|
||||
public override void Dispose() => throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d75c0d86eeab47a1a6340f0b03b83de0
|
||||
timeCreated: 1684002680
|
||||
3
NEG/UI/UnityUi/Buttons/Settings.meta
Normal file
3
NEG/UI/UnityUi/Buttons/Settings.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d25aba738e174616bcab9bf2d52a3ed1
|
||||
timeCreated: 1683398272
|
||||
32
NEG/UI/UnityUi/Buttons/Settings/ButtonSettings.cs
Normal file
32
NEG/UI/UnityUi/Buttons/Settings/ButtonSettings.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace NEG.UI.UnityUi.Buttons.Settings
|
||||
{
|
||||
public class ButtonSettings : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private List<SettingData> settingDatas = new();
|
||||
|
||||
public void Apply(BaseButton button)
|
||||
{
|
||||
foreach (var setting in settingDatas)
|
||||
{
|
||||
setting.Apply(button);
|
||||
}
|
||||
}
|
||||
|
||||
[ContextMenu("Refresh")]
|
||||
public void Refresh()
|
||||
{
|
||||
settingDatas.Clear();
|
||||
var components = GetComponents<SettingData>();
|
||||
foreach (var data in components)
|
||||
{
|
||||
settingDatas.Add(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
NEG/UI/UnityUi/Buttons/Settings/ButtonSettings.cs.meta
Normal file
3
NEG/UI/UnityUi/Buttons/Settings/ButtonSettings.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5292008faae496ab9028ad1faa0a3ba
|
||||
timeCreated: 1683398713
|
||||
10
NEG/UI/UnityUi/Buttons/Settings/ColorData.cs
Normal file
10
NEG/UI/UnityUi/Buttons/Settings/ColorData.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NEG.UI.UnityUi.Buttons.Settings
|
||||
{
|
||||
public class ColorData : SettingData
|
||||
{
|
||||
[field: SerializeField] public Color SelectedColor { get; private set; } = Color.black;
|
||||
[field: SerializeField] public Color DeselectedColor { get; private set; } = Color.black;
|
||||
}
|
||||
}
|
||||
3
NEG/UI/UnityUi/Buttons/Settings/ColorData.cs.meta
Normal file
3
NEG/UI/UnityUi/Buttons/Settings/ColorData.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cec5286cd31b4819981e244b1adb977e
|
||||
timeCreated: 1684001181
|
||||
14
NEG/UI/UnityUi/Buttons/Settings/FmodSoundData.cs
Normal file
14
NEG/UI/UnityUi/Buttons/Settings/FmodSoundData.cs
Normal file
@ -0,0 +1,14 @@
|
||||
#if FMOD
|
||||
using FMODUnity;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NEG.UI.UnityUi.Buttons.Settings
|
||||
{
|
||||
public class FmodSoundData : SettingData
|
||||
{
|
||||
[field: SerializeField] public EventReference SelectedSound { get; private set; }
|
||||
[field: SerializeField] public EventReference ClickedSound { get; private set; }
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
3
NEG/UI/UnityUi/Buttons/Settings/FmodSoundData.cs.meta
Normal file
3
NEG/UI/UnityUi/Buttons/Settings/FmodSoundData.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e6a7b10c07d40408ee9492c931e3ec9
|
||||
timeCreated: 1684001979
|
||||
7
NEG/UI/UnityUi/Buttons/Settings/RemoveFeature.cs
Normal file
7
NEG/UI/UnityUi/Buttons/Settings/RemoveFeature.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace NEG.UI.UnityUi.Buttons.Settings
|
||||
{
|
||||
public class RemoveFeature : SettingData
|
||||
{
|
||||
public override void Apply(BaseButton button) => button.RemoveSetting(Key);
|
||||
}
|
||||
}
|
||||
3
NEG/UI/UnityUi/Buttons/Settings/RemoveFeature.cs.meta
Normal file
3
NEG/UI/UnityUi/Buttons/Settings/RemoveFeature.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b44cdc2e0164ebdb8f6da348d653e77
|
||||
timeCreated: 1684001264
|
||||
28
NEG/UI/UnityUi/Buttons/Settings/SettingData.cs
Normal file
28
NEG/UI/UnityUi/Buttons/Settings/SettingData.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using KBCore.Refs;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace NEG.UI.UnityUi.Buttons.Settings
|
||||
{
|
||||
public abstract class SettingData : MonoBehaviour
|
||||
{
|
||||
[field: SerializeField] public string Key { get; private set; }
|
||||
[SerializeField, Self(Flag.Optional)] private BaseButton attachedButton;
|
||||
|
||||
public virtual void Apply(BaseButton button) => button.AddOrOverrideSetting(this);
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if(attachedButton != null)
|
||||
Apply(attachedButton);
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
this.ValidateRefs();
|
||||
if (attachedButton == null && TryGetComponent(out ButtonSettings settings))
|
||||
settings.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
NEG/UI/UnityUi/Buttons/Settings/SettingData.cs.meta
Normal file
3
NEG/UI/UnityUi/Buttons/Settings/SettingData.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49b3fccda2b4485193eada1b3611ea40
|
||||
timeCreated: 1684001079
|
||||
10
NEG/UI/UnityUi/Buttons/Settings/SpriteData.cs
Normal file
10
NEG/UI/UnityUi/Buttons/Settings/SpriteData.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NEG.UI.UnityUi.Buttons.Settings
|
||||
{
|
||||
public class SpriteData : SettingData
|
||||
{
|
||||
[field: SerializeField] public Sprite SelectedSprite { get; private set; }
|
||||
[field: SerializeField] public Sprite DeselectedSprite { get; private set; }
|
||||
}
|
||||
}
|
||||
3
NEG/UI/UnityUi/Buttons/Settings/SpriteData.cs.meta
Normal file
3
NEG/UI/UnityUi/Buttons/Settings/SpriteData.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aeba07ffa68b4674bc7025ba4f328562
|
||||
timeCreated: 1684001906
|
||||
42
NEG/UI/UnityUi/Editor/ButtonsExtensions.cs
Normal file
42
NEG/UI/UnityUi/Editor/ButtonsExtensions.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using NEG.UI.UnityUi.Buttons;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace NEG.UI.UnityUi.Editor
|
||||
{
|
||||
public static class ButtonsExtensions
|
||||
{
|
||||
[MenuItem("CONTEXT/Button/Change To Navigation Button")]
|
||||
public static void ChangeScript(MenuCommand command)
|
||||
{
|
||||
if (command.context == null)
|
||||
return;
|
||||
|
||||
var button = command.context as Button;
|
||||
var go = new GameObject();
|
||||
var sourceScriptAsset = MonoScript.FromMonoBehaviour(go.AddComponent<CustomNavigationButton>());
|
||||
string relativePath = AssetDatabase.GetAssetPath(sourceScriptAsset);
|
||||
Object.DestroyImmediate(go);
|
||||
|
||||
var chosenTextAsset = AssetDatabase.LoadAssetAtPath<TextAsset>(relativePath);
|
||||
|
||||
if (chosenTextAsset == null)
|
||||
{
|
||||
Debug.LogWarning($"Selected script couldn't be loaded ({relativePath})");
|
||||
return;
|
||||
}
|
||||
|
||||
Undo.RegisterCompleteObjectUndo(command.context, "Changing component script");
|
||||
|
||||
var so = new SerializedObject(button);
|
||||
var scriptProperty = so.FindProperty("m_Script");
|
||||
so.Update();
|
||||
scriptProperty.objectReferenceValue = chosenTextAsset;
|
||||
so.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
NEG/UI/UnityUi/Editor/ButtonsExtensions.cs.meta
Normal file
11
NEG/UI/UnityUi/Editor/ButtonsExtensions.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b09e744f7ec6704c95ec273584a964f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
36
NEG/UI/UnityUi/Editor/CustomNavigationButtonEditor.cs
Normal file
36
NEG/UI/UnityUi/Editor/CustomNavigationButtonEditor.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using UnityEditor;
|
||||
using UnityEditor.UI;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace NEG.UI.UnityUi.Editor
|
||||
{
|
||||
[CustomEditor(typeof(Buttons.CustomNavigationButton), true)]
|
||||
public class CustomNavigationButtonEditor : ButtonEditor
|
||||
{
|
||||
private SerializedProperty upOverrideProperty;
|
||||
private SerializedProperty downOverrideProperty;
|
||||
private SerializedProperty leftOverrideProperty;
|
||||
private SerializedProperty rightOverrideProperty;
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
upOverrideProperty = serializedObject.FindProperty("upOverride");
|
||||
downOverrideProperty = serializedObject.FindProperty("downOverride");
|
||||
leftOverrideProperty = serializedObject.FindProperty("leftOverride");
|
||||
rightOverrideProperty = serializedObject.FindProperty("rightOverride");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
EditorGUILayout.Space();
|
||||
serializedObject.Update();
|
||||
EditorGUILayout.PropertyField(upOverrideProperty);
|
||||
EditorGUILayout.PropertyField(downOverrideProperty);
|
||||
EditorGUILayout.PropertyField(leftOverrideProperty);
|
||||
EditorGUILayout.PropertyField(rightOverrideProperty);
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 162f4693585f414b85f0a4210a10a585
|
||||
timeCreated: 1684521873
|
||||
@ -2,7 +2,8 @@
|
||||
"name": "NEG.UI.UnityUi.Editor",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:e2aaf8effe1c9634d87b2edda6988a6a"
|
||||
"GUID:e2aaf8effe1c9634d87b2edda6988a6a",
|
||||
"GUID:5928dc8d9173fd348aa77d4593ca3fd8"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
|
||||
114
NEG/UI/UnityUi/Editor/OverridableNavigationDrawer.cs
Normal file
114
NEG/UI/UnityUi/Editor/OverridableNavigationDrawer.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using NEG.UI.UnityUi.Buttons;
|
||||
using NEG.Utils.Serialization;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.UIElements;
|
||||
using ObjectField = UnityEditor.Search.ObjectField;
|
||||
|
||||
using Toggle = UnityEngine.UIElements.Toggle;
|
||||
|
||||
namespace NEG.UI.UnityUi.Editor
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(OverridableNavigation))]
|
||||
public class OverridableNavigationDrawer: PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
// Draw label
|
||||
position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
|
||||
|
||||
// Don't make child fields be indented
|
||||
int indent = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0;
|
||||
|
||||
// Calculate rects
|
||||
var amountRect = new Rect(position.x, position.y, 200, position.height);
|
||||
var unitRect = new Rect(position.x + 35, position.y, 200, position.height);
|
||||
|
||||
// Draw fields - pass GUIContent.none to each so they are drawn without labels
|
||||
EditorGUI.PropertyField(amountRect, property.FindAutoPropertyRelative(nameof(OverridableNavigation.Override)), GUIContent.none);
|
||||
EditorGUI.PropertyField(unitRect, property.FindAutoPropertyRelative(nameof(OverridableNavigation.Selectable)), GUIContent.none);
|
||||
|
||||
// Set indent back to what it was
|
||||
EditorGUI.indentLevel = indent;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
public override VisualElement CreatePropertyGUI(SerializedProperty property)
|
||||
{
|
||||
var container = new VisualElement()
|
||||
{
|
||||
style =
|
||||
{
|
||||
paddingLeft = 3,
|
||||
paddingRight = -2,
|
||||
flexDirection = FlexDirection.Row,
|
||||
justifyContent = Justify.SpaceBetween
|
||||
}
|
||||
};
|
||||
|
||||
string name = property.name;
|
||||
if (name.Length > 0)
|
||||
{
|
||||
name = $"{char.ToUpper(name[0])}{name[1..]}";
|
||||
}
|
||||
|
||||
var innerContainer = new VisualElement()
|
||||
{
|
||||
style =
|
||||
{
|
||||
flexDirection = FlexDirection.Row,
|
||||
justifyContent = Justify.SpaceBetween,
|
||||
marginRight = 2,
|
||||
flexGrow = 1
|
||||
}
|
||||
};
|
||||
|
||||
var label = new Label(name);
|
||||
|
||||
var enabler = new Toggle();
|
||||
enabler.BindProperty(property.FindPropertyRelative("<Override>k__BackingField"));
|
||||
|
||||
var field = new ObjectField()
|
||||
{
|
||||
style =
|
||||
{
|
||||
flexGrow = 100
|
||||
}
|
||||
};
|
||||
|
||||
var selectableField = property.FindAutoPropertyRelative(nameof(OverridableNavigation.Selectable));
|
||||
|
||||
field.BindProperty(selectableField);
|
||||
field.objectType = typeof(Selectable);
|
||||
|
||||
innerContainer.Add(label);
|
||||
innerContainer.Add(enabler);
|
||||
|
||||
container.Add(innerContainer);
|
||||
container.Add(field);
|
||||
|
||||
container.RegisterCallback<GeometryChangedEvent>(_ =>
|
||||
{
|
||||
var panel = container.panel;
|
||||
var size = panel.visualTree.contentRect.size;
|
||||
|
||||
// magic value measured with ruler, may change in the future!
|
||||
field.style.maxWidth = size.x * 0.55f + 15;
|
||||
});
|
||||
|
||||
field.SetEnabled(enabler.value);
|
||||
enabler.RegisterValueChangedCallback(v =>
|
||||
{
|
||||
field.SetEnabled(v.newValue);
|
||||
});
|
||||
|
||||
return container;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 63ba4de7f1a04763bf035b4a88317a7d
|
||||
timeCreated: 1685212390
|
||||
29
NEG/UI/UnityUi/MonoController.cs
Normal file
29
NEG/UI/UnityUi/MonoController.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using KBCore.Refs;
|
||||
using NegUtils.NEG.UI;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NEG.UI.UnityUi
|
||||
{
|
||||
public abstract class MonoController : MonoBehaviour, IController
|
||||
{
|
||||
public IControllable Controllable => controllable.Value;
|
||||
|
||||
[SerializeField, Self] protected InterfaceRef<IControllable> controllable;
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
controllable.Value.OnOpened += OnOpened;
|
||||
controllable.Value.OnClosed += OnClosed;
|
||||
controllable.Value.OnBackUsed += OnBackUsed;
|
||||
}
|
||||
|
||||
private void OnValidate() => this.ValidateRefs();
|
||||
|
||||
protected virtual void OnOpened(object data) { }
|
||||
|
||||
protected virtual void OnClosed() { }
|
||||
|
||||
protected virtual void OnBackUsed(IControllable.BackUsed obj) { }
|
||||
}
|
||||
}
|
||||
89
NEG/UI/UnityUi/MonoUiInputManger.cs
Normal file
89
NEG/UI/UnityUi/MonoUiInputManger.cs
Normal file
@ -0,0 +1,89 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.UI;
|
||||
|
||||
namespace NEG.UI.UnityUi
|
||||
{
|
||||
public enum SelectionSource
|
||||
{
|
||||
Pointer,
|
||||
Direction
|
||||
}
|
||||
|
||||
public class UiInputModule { }
|
||||
|
||||
public class DefaultInputModule : UiInputModule
|
||||
{
|
||||
public SelectionSource CurrentSelectionSource { get; private set; }
|
||||
|
||||
public DefaultInputModule()
|
||||
{
|
||||
var defaultActions = new DefaultInputActions();
|
||||
InputActionReference.Create(defaultActions.UI.Navigate).action.performed += (ctx) => OnSelectionChangeStarted();
|
||||
defaultActions.Enable();
|
||||
|
||||
if (Gamepad.current != null)
|
||||
SetDirectionInput();
|
||||
else
|
||||
SetPointerInput();
|
||||
|
||||
//var keyboardAction = new InputAction(binding: "/<Keyboard>/*");
|
||||
//keyboardAction.performed += (context) => CurrentInputSource = EInputSource.Keyboard;
|
||||
//keyboardAction.Enable();
|
||||
var gamepadAction = new InputAction(binding: "/<Gamepad>/*");
|
||||
gamepadAction.performed += (context) => OnSelectionChangeStarted();
|
||||
gamepadAction.Enable();
|
||||
|
||||
var mouseAction = new InputAction(binding: "/<Mouse>/*");
|
||||
mouseAction.performed += (context) =>
|
||||
{
|
||||
if(CurrentSelectionSource == SelectionSource.Pointer)
|
||||
return;
|
||||
SetPointerInput();
|
||||
};
|
||||
mouseAction.Enable();
|
||||
}
|
||||
|
||||
private void OnSelectionChangeStarted()
|
||||
{
|
||||
if(CurrentSelectionSource == SelectionSource.Direction)
|
||||
return;
|
||||
SetDirectionInput();
|
||||
}
|
||||
|
||||
private void SetDirectionInput()
|
||||
{
|
||||
CurrentSelectionSource = SelectionSource.Direction;
|
||||
Cursor.visible = false;
|
||||
}
|
||||
|
||||
private void SetPointerInput()
|
||||
{
|
||||
CurrentSelectionSource = SelectionSource.Pointer;
|
||||
Cursor.visible = true;
|
||||
|
||||
if (EventSystem.current == null)
|
||||
{
|
||||
SetDirectionInput();
|
||||
return;
|
||||
}
|
||||
|
||||
if (EventSystem.current.currentInputModule == null)
|
||||
return;
|
||||
|
||||
var module = (InputSystemUIInputModule)EventSystem.current.currentInputModule;
|
||||
var result = module.GetLastRaycastResult(0);
|
||||
if(result.gameObject == null)
|
||||
return;
|
||||
|
||||
var data = new PointerEventData(EventSystem.current);
|
||||
for (var current = result.gameObject.transform;
|
||||
current != null;
|
||||
current = current.parent)
|
||||
{
|
||||
ExecuteEvents.Execute(current.gameObject, data, ExecuteEvents.pointerEnterHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
NEG/UI/UnityUi/MonoUiInputManger.cs.meta
Normal file
3
NEG/UI/UnityUi/MonoUiInputManger.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6cd55755dda4f71a4257fac75cb902d
|
||||
timeCreated: 1684009354
|
||||
@ -1,45 +1,71 @@
|
||||
using NEG.UI.Area;
|
||||
using NEG.UI.Popup;
|
||||
using NEG.UI.UnityUi.Buttons.Reaction;
|
||||
using NEG.UI.UnityUi.Buttons.Settings;
|
||||
using NEG.UI.UnityUi.Popup;
|
||||
using NEG.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.Assertions;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace NEG.UI.UnityUi
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements ui using UnityUI and Unity Event System with New Input System.
|
||||
/// <para>You have to provide prefabs with addresses:</para>
|
||||
/// <para> - NEG/UI/PopupCanvas - prefab with canvas to create popups (will be created on every scene)</para>
|
||||
/// <para> - NEG/UI/DefaultPopupPrefab - prefab of default popup with 2 options (has to have <see cref="MonoDefaultPopup"/> component)</para>
|
||||
/// <para>You have to provide prefabs within resources:</para>
|
||||
/// <para> - UI/PopupCanvas - prefab with canvas to create popups (will be created on every scene)</para>
|
||||
/// <para> - UI/DefaultPopupPrefab - prefab of default popup with 2 options (has to have <see cref="MonoDefaultPopup"/> component)</para>
|
||||
/// NEG_UI_DISABLE_WARNING_DEFAULT_SELECTION
|
||||
/// </summary>
|
||||
public class MonoUiManager : UiManager
|
||||
public class MonoUiManager : UiManager, IDisposable
|
||||
{
|
||||
//TODO: use default unity selection
|
||||
//TODO: window snaping to slots
|
||||
public static new MonoUiManager Instance { get; private set; }
|
||||
|
||||
public ButtonSettings DefaultUiSettings { get; }
|
||||
public KeyBasedFactory<string, ButtonElementBehaviour> BehavioursFactory { get; private set; }
|
||||
|
||||
//TODO: editor to auto add slots, buttons
|
||||
|
||||
private readonly MonoDefaultPopup defaultPopupPrefab;
|
||||
private readonly GameObject canvasPrefab;
|
||||
|
||||
public MonoUiManager(IArea startArea) : base(startArea)
|
||||
private UiInputModule inputModule;
|
||||
|
||||
public MonoUiManager(IArea startArea, Type inputModuleType, ButtonSettings defaultUiSettings) : base(startArea)
|
||||
{
|
||||
var prefabs =
|
||||
Addressables.LoadAssetsAsync<GameObject>(new List<string>() { "NEG/UI/PopupCanvas", "NEG/UI/DefaultPopupPrefab" }, (_) => { }, Addressables.MergeMode.Union).WaitForCompletion();
|
||||
Instance = this;
|
||||
|
||||
Assert.AreEqual(prefabs.Count, 2, "No prefabs was provided. Please check MonoUiManager class documentation");
|
||||
Assert.IsNotNull(prefabs[0].GetComponent<Canvas>());
|
||||
Assert.IsNotNull(prefabs[1].GetComponent<MonoDefaultPopup>());
|
||||
var popupCanvas = Resources.Load<GameObject>("UI/PopupCanvas");
|
||||
var defaultPopup = Resources.Load<GameObject>("UI/DefaultPopupPrefab");
|
||||
|
||||
canvasPrefab = prefabs[0];
|
||||
defaultPopupPrefab = prefabs[1].GetComponent<MonoDefaultPopup>();
|
||||
Assert.IsNotNull(popupCanvas,"No canvas prefab was provided. Please check MonoUiManager class documentation");
|
||||
Assert.IsNotNull(defaultPopup,"No popup prefab was provided. Please check MonoUiManager class documentation");
|
||||
Assert.IsNotNull(popupCanvas.GetComponent<Canvas>());
|
||||
Assert.IsNotNull(defaultPopup.GetComponent<MonoDefaultPopup>());
|
||||
|
||||
canvasPrefab = popupCanvas;
|
||||
defaultPopupPrefab = defaultPopup.GetComponent<MonoDefaultPopup>();
|
||||
|
||||
SpawnDefaultPopup();
|
||||
|
||||
SceneManager.activeSceneChanged += (_, _) => SpawnDefaultPopup();
|
||||
|
||||
BehavioursFactory = new KeyBasedFactory<string, ButtonElementBehaviour>();
|
||||
BehavioursFactory.FireRegistration();
|
||||
|
||||
inputModule = (UiInputModule)Activator.CreateInstance(inputModuleType);
|
||||
DefaultUiSettings = defaultUiSettings;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
Instance = null;
|
||||
}
|
||||
|
||||
private void SpawnDefaultPopup()
|
||||
@ -49,6 +75,5 @@ namespace NEG.UI.UnityUi
|
||||
SetDefaultPopup(Object.Instantiate(defaultPopupPrefab, canvas.transform));
|
||||
currentDefaultPopup.Close(true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -5,10 +5,11 @@
|
||||
"GUID:343deaaf83e0cee4ca978e7df0b80d21",
|
||||
"GUID:7361f1d9c43da6649923760766194746",
|
||||
"GUID:6055be8ebefd69e48b49212b09b47b2f",
|
||||
"GUID:23eed6c2401dca1419d1ebd180e58c5a",
|
||||
"GUID:33759803a11f4d538227861a78aba30b",
|
||||
"GUID:0c752da273b17c547ae705acf0f2adf2",
|
||||
"GUID:9e24947de15b9834991c9d8411ea37cf",
|
||||
"GUID:84651a3751eca9349aac36a66bba901b",
|
||||
"GUID:23eed6c2401dca1419d1ebd180e58c5a"
|
||||
"GUID:3c4294719a93e3c4e831a9ff0c261e8a",
|
||||
"GUID:75469ad4d38634e559750d17036d5f7c"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
||||
@ -10,13 +10,13 @@ namespace NEG.UI.UnityUi.Popup
|
||||
|
||||
protected PopupData data;
|
||||
|
||||
public void Show(PopupData data)
|
||||
public virtual void Show(PopupData data)
|
||||
{
|
||||
this.data = data;
|
||||
gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
public void Close(bool silent = false)
|
||||
public virtual void Close(bool silent = false)
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
|
||||
|
||||
11
NEG/UI/UnityUi/SilentEventData.cs
Normal file
11
NEG/UI/UnityUi/SilentEventData.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace NEG.UI.UnityUi
|
||||
{
|
||||
public class SilentEventData : BaseEventData
|
||||
{
|
||||
public SilentEventData(EventSystem eventSystem) : base(eventSystem)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
3
NEG/UI/UnityUi/SilentEventData.cs.meta
Normal file
3
NEG/UI/UnityUi/SilentEventData.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 718df112d05a4270bad895acce9dfa87
|
||||
timeCreated: 1684008766
|
||||
19
NEG/UI/UnityUi/Window/CloseWindowOnBack.cs
Normal file
19
NEG/UI/UnityUi/Window/CloseWindowOnBack.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using KBCore.Refs;
|
||||
using NEG.UI.Window;
|
||||
using NegUtils.NEG.UI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NEG.UI.UnityUi.Window
|
||||
{
|
||||
public class CloseWindowOnBack : MonoController
|
||||
{
|
||||
[SerializeField, Self(Flag.Editable)] private MonoWindow window;
|
||||
|
||||
protected override void OnBackUsed(IControllable.BackUsed backUsed)
|
||||
{
|
||||
base.OnBackUsed(backUsed);
|
||||
window.Close();
|
||||
backUsed.Used = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
NEG/UI/UnityUi/Window/CloseWindowOnBack.cs.meta
Normal file
3
NEG/UI/UnityUi/Window/CloseWindowOnBack.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4a156da6df74abeb281176000738ebb
|
||||
timeCreated: 1686598323
|
||||
@ -3,14 +3,21 @@ using NEG.UI.UnityUi.Buttons;
|
||||
using NEG.UI.UnityUi.WindowSlot;
|
||||
using NEG.UI.Window;
|
||||
using NEG.UI.WindowSlot;
|
||||
using NegUtils.NEG.UI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace NEG.UI.UnityUi.Window
|
||||
{
|
||||
public class MonoWindow : MonoBehaviour, IWindow
|
||||
{
|
||||
public event Action<object> OnOpened;
|
||||
public event Action OnClosed;
|
||||
public event Action<IControllable.BackUsed> OnBackUsed;
|
||||
|
||||
public IEnumerable<IWindowSlot> AvailableSlots => windowSlots;
|
||||
public IWindowSlot Parent { get; private set; }
|
||||
|
||||
@ -19,20 +26,17 @@ namespace NEG.UI.UnityUi.Window
|
||||
private IWindowSlot DefaultWindowSlot => windowSlots[0];
|
||||
|
||||
[SerializeField] private List<MonoWindowSlot> windowSlots;
|
||||
[SerializeField] private WindowController controller;
|
||||
|
||||
public void SetOpenedState(IWindowSlot parentSlot)
|
||||
[SerializeField] private GameObject defaultSelectedItem;
|
||||
|
||||
public void SetOpenedState(IWindowSlot parentSlot, object data)
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
Parent = parentSlot;
|
||||
if (controller != null)
|
||||
controller.OnOpened();
|
||||
}
|
||||
|
||||
public void SetData(object data)
|
||||
{
|
||||
if (controller != null)
|
||||
controller.SetData(data);
|
||||
EventSystem.current.SetSelectedGameObject(defaultSelectedItem);
|
||||
if (parentSlot.OpenWindowAsMain)
|
||||
UiManager.Instance.SetMainWindow(this);
|
||||
OnOpened?.Invoke(data);
|
||||
}
|
||||
|
||||
public void SetClosedState()
|
||||
@ -40,22 +44,28 @@ namespace NEG.UI.UnityUi.Window
|
||||
gameObject.SetActive(false);
|
||||
Parent = null;
|
||||
((ISlotsHolder)this).CloseAllWindows();
|
||||
if(controller != null)
|
||||
controller.OnClosed();
|
||||
UiManager.Instance.OnWindowClosed(this);
|
||||
OnClosed?.Invoke();
|
||||
}
|
||||
|
||||
private void Awake() => ((IWindow)this).SetClosedState();
|
||||
public void SetHiddenState() => gameObject.SetActive(false);
|
||||
|
||||
public void SeVisibleState() => gameObject.SetActive(true);
|
||||
|
||||
private void Awake() => ((IWindow)this).SetHiddenState();
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
if (controller == null)
|
||||
controller = GetComponent<WindowController>();
|
||||
#if !NEG_UI_DISABLE_WARNING_DEFAULT_SELECTION
|
||||
if(defaultSelectedItem == null)
|
||||
Debug.LogWarning($"Window {name} should have default selected item set");
|
||||
#endif
|
||||
}
|
||||
|
||||
public void OpenWindow(IWindow window, object data = null)
|
||||
{
|
||||
DefaultWindowSlot.AttachWindow(window);
|
||||
window.SetData(data);
|
||||
}
|
||||
public void OpenWindow(IWindow window, object data = null) => DefaultWindowSlot.AttachWindow(window, data);
|
||||
|
||||
public void SetDefaultSelectedItem(GameObject item) => defaultSelectedItem = item;
|
||||
|
||||
public void TryUseBack(ref IControllable.BackUsed backUsed) => OnBackUsed?.Invoke(backUsed);
|
||||
}
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NEG.UI.UnityUi.Window
|
||||
{
|
||||
[RequireComponent(typeof(MonoWindow))]
|
||||
//Due to prefab variants we need this
|
||||
public abstract class WindowController : MonoBehaviour
|
||||
{
|
||||
protected MonoWindow window;
|
||||
|
||||
public abstract void SetData(object data);
|
||||
|
||||
public virtual void OnOpened() { }
|
||||
|
||||
public virtual void OnClosed() { }
|
||||
|
||||
protected virtual void Awake() => window = GetComponent<MonoWindow>();
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
using NEG.UI.Area;
|
||||
using KBCore.Refs;
|
||||
using NEG.UI.Area;
|
||||
using NEG.UI.Window;
|
||||
using NEG.UI.WindowSlot;
|
||||
using System;
|
||||
@ -12,7 +13,7 @@ namespace NEG.UI.UnityUi.WindowSlot
|
||||
[field: SerializeField] public bool OpenWindowAsMain { get; private set; }
|
||||
|
||||
public ISlotsHolder ParentHolder => slotsHolder.Value;
|
||||
public abstract void AttachWindow(IWindow window);
|
||||
public abstract void AttachWindow(IWindow window, object data);
|
||||
public abstract void DetachWindow(IWindow window);
|
||||
public abstract void CloseAllWindows();
|
||||
|
||||
|
||||
@ -9,17 +9,21 @@ namespace NEG.UI.WindowSlot
|
||||
public IWindow CurrentWindow
|
||||
{
|
||||
get => currentWindow;
|
||||
set
|
||||
protected set
|
||||
{
|
||||
currentWindow?.SetClosedState();
|
||||
currentWindow = value;
|
||||
currentWindow?.SetOpenedState(this);
|
||||
}
|
||||
}
|
||||
|
||||
private IWindow currentWindow;
|
||||
|
||||
public override void AttachWindow(IWindow window) => CurrentWindow = window;
|
||||
public override void AttachWindow(IWindow window, object data)
|
||||
{
|
||||
CurrentWindow = window;
|
||||
window.SetOpenedState(this, data);
|
||||
}
|
||||
|
||||
public override void DetachWindow(IWindow window) => CurrentWindow = null;
|
||||
public override void CloseAllWindows() => CurrentWindow = null;
|
||||
}
|
||||
|
||||
57
NEG/UI/UnityUi/WindowSlot/SingleWindowSlotWithHistory.cs
Normal file
57
NEG/UI/UnityUi/WindowSlot/SingleWindowSlotWithHistory.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using NEG.UI.UnityUi.WindowSlot;
|
||||
using NEG.UI.Window;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace NegUtils.NEG.UI.UnityUi.WindowSlot
|
||||
{
|
||||
public class SingleWindowSlotWithHistory : MonoWindowSlot
|
||||
{
|
||||
public IWindow CurrentWindow
|
||||
{
|
||||
get => currentWindow;
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
CloseAllWindows();
|
||||
return;
|
||||
}
|
||||
|
||||
currentWindow?.SetHiddenState();
|
||||
currentWindow = value;
|
||||
windowsHistory.Add(currentWindow);
|
||||
}
|
||||
}
|
||||
|
||||
private IWindow currentWindow;
|
||||
|
||||
private readonly List<IWindow> windowsHistory = new List<IWindow>();
|
||||
|
||||
public override void AttachWindow(IWindow window, object data)
|
||||
{
|
||||
CurrentWindow = window;
|
||||
CurrentWindow.SetOpenedState(this, data);
|
||||
}
|
||||
|
||||
public override void DetachWindow(IWindow window)
|
||||
{
|
||||
if(window == null)
|
||||
return;
|
||||
window.SetClosedState();
|
||||
windowsHistory.Remove(window);
|
||||
if (window != currentWindow || windowsHistory.Count == 0) return;
|
||||
windowsHistory[^1].SeVisibleState();
|
||||
currentWindow = windowsHistory[^1];
|
||||
}
|
||||
public override void CloseAllWindows()
|
||||
{
|
||||
currentWindow = null;
|
||||
foreach (var window in windowsHistory)
|
||||
{
|
||||
window.SetClosedState();
|
||||
}
|
||||
windowsHistory.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d98305dbca084b218b635682f06b934b
|
||||
timeCreated: 1685995642
|
||||
@ -1,11 +1,12 @@
|
||||
using JetBrains.Annotations;
|
||||
using NEG.UI.Area;
|
||||
using NEG.UI.WindowSlot;
|
||||
using NegUtils.NEG.UI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NEG.UI.Window
|
||||
{
|
||||
public interface IWindow : ISlotsHolder
|
||||
public interface IWindow : ISlotsHolder, IControllable
|
||||
{
|
||||
/// <summary>
|
||||
/// Parent slot of this window.
|
||||
@ -16,18 +17,23 @@ namespace NEG.UI.Window
|
||||
/// Called internally by slot to open window.
|
||||
/// </summary>
|
||||
/// <param name="parentSlot">slot that opens window</param>
|
||||
void SetOpenedState(IWindowSlot parentSlot);
|
||||
|
||||
/// <summary>
|
||||
/// Sets data for window, usually used for dynamic content set by external logic controller.
|
||||
/// </summary>
|
||||
/// <param name="data">can be any type, window should cast for expected type</param>
|
||||
void SetData(object data);
|
||||
/// <param name="data">data</param>
|
||||
void SetOpenedState(IWindowSlot parentSlot, object data);
|
||||
|
||||
/// <summary>
|
||||
/// Called internally to close window by slot.
|
||||
/// </summary>
|
||||
void SetClosedState();
|
||||
|
||||
/// <summary>
|
||||
/// Called internally to hide window by slot.
|
||||
/// </summary>
|
||||
void SetHiddenState();
|
||||
|
||||
/// <summary>
|
||||
/// Called internally to set window visible by slot.
|
||||
/// </summary>
|
||||
void SeVisibleState();
|
||||
}
|
||||
|
||||
public static class WindowInterfaceExtensions
|
||||
@ -42,8 +48,7 @@ namespace NEG.UI.Window
|
||||
{
|
||||
if (slot != null)
|
||||
{
|
||||
slot.AttachWindow(window);
|
||||
window.SetData(data);
|
||||
slot.AttachWindow(window, data);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ namespace NEG.UI.WindowSlot
|
||||
{
|
||||
bool OpenWindowAsMain { get; }
|
||||
ISlotsHolder ParentHolder { get; }
|
||||
void AttachWindow(IWindow window);
|
||||
void AttachWindow(IWindow window, object data);
|
||||
void DetachWindow(IWindow window);
|
||||
void CloseAllWindows();
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ namespace NEG.Utils
|
||||
/// <param name="type">Interface type.</param>
|
||||
public RequireInterfaceAttribute(System.Type type)
|
||||
{
|
||||
this.requiredType = type;
|
||||
requiredType = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,15 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
|
||||
namespace NEG.Utils.Timing
|
||||
{
|
||||
public class AutoTimeMachine
|
||||
{
|
||||
[PublicAPI]
|
||||
public double Interval { get; set; }
|
||||
public Action Action { get; set; }
|
||||
|
||||
[PublicAPI]
|
||||
public Action Action { get; }
|
||||
|
||||
private readonly TimeMachine machine;
|
||||
|
||||
|
||||
@ -5,66 +5,61 @@ namespace NEG.Utils.Timing
|
||||
{
|
||||
public class TimeMachine
|
||||
{
|
||||
private double time;
|
||||
private double timeInternal;
|
||||
|
||||
public TimeMachine()
|
||||
{
|
||||
time = 0;
|
||||
timeInternal = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds time into the TimeMachine
|
||||
/// </summary>
|
||||
/// <param name="time">Amount of time to be added</param>
|
||||
public void Accumulate(double time)
|
||||
{
|
||||
this.time += time;
|
||||
}
|
||||
public void Accumulate(double time) => timeInternal += time;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves given amount of time from the TimeMachine
|
||||
/// </summary>
|
||||
/// <param name="maxTime"></param>
|
||||
/// <returns>Amount of time retrievend</returns>
|
||||
/// <returns>Amount of time retrieved</returns>
|
||||
public double Retrieve(double maxTime)
|
||||
{
|
||||
if(!double.IsFinite(maxTime))
|
||||
{
|
||||
double timeRetrieved = time;
|
||||
time = 0;
|
||||
double timeRetrieved = timeInternal;
|
||||
timeInternal = 0;
|
||||
return timeRetrieved;
|
||||
}
|
||||
double timeLeft = time - maxTime;
|
||||
time = Math.Max(timeLeft, 0);
|
||||
double timeLeft = timeInternal - maxTime;
|
||||
timeInternal = Math.Max(timeLeft, 0);
|
||||
return Math.Min(maxTime + timeLeft, maxTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to retrieves given amount of time from the TimeMachine <br/>
|
||||
/// If there is enough <paramref name="time"/> accumulated in this machine subtructs that amount and returns true, otherwise returns false
|
||||
/// If there is enough <paramref name="time"/> accumulated in this machine subtracts that amount and returns true, otherwise returns false
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
public bool TryRetrieve(double time)
|
||||
{
|
||||
if (this.time >= time)
|
||||
{
|
||||
this.time -= time;
|
||||
return true;
|
||||
}
|
||||
if (!(timeInternal >= time))
|
||||
return false;
|
||||
timeInternal -= time;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result is equivalent to calling <see cref="TryRetrieve(double)"/> as many times as possible, but is faster for larger <paramref name="limit"/> values
|
||||
/// </summary>
|
||||
/// <param name="interval">Single unit of warp time, must be positive/param>
|
||||
/// <param name="interval">Single unit of warp time, must be positive</param>
|
||||
/// <param name="limit">Maximum amount of warps, must be positive</param>
|
||||
/// <returns>Amount of warps</returns>
|
||||
public int RetrieveAll(double interval, int limit = int.MaxValue)
|
||||
{
|
||||
int result = Mathf.FloorToInt((float)(time / interval));
|
||||
int result = Mathf.FloorToInt((float)(timeInternal / interval));
|
||||
result = Math.Clamp(result, 0, limit);
|
||||
time -= result * interval;
|
||||
timeInternal -= result * interval;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
11
UiToolkit/MultiSelectChips/IMultiSelectChipItem.cs
Normal file
11
UiToolkit/MultiSelectChips/IMultiSelectChipItem.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NEG.Utils.UiToolkits
|
||||
{
|
||||
public interface IMultiSelectChipItem
|
||||
{
|
||||
string Name { get; }
|
||||
Color Color { get; }
|
||||
}
|
||||
}
|
||||
11
UiToolkit/MultiSelectChips/IMultiSelectChipItem.cs.meta
Normal file
11
UiToolkit/MultiSelectChips/IMultiSelectChipItem.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f032e3d346d243d458c929d4046f0a1e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
22
UiToolkit/MultiSelectChips/MultiSelectChipItem.cs
Normal file
22
UiToolkit/MultiSelectChips/MultiSelectChipItem.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace NEG.Utils.UiToolkits
|
||||
{
|
||||
public class MultiSelectChipItem
|
||||
{
|
||||
public VisualElement VisualElement { get; }
|
||||
public IMultiSelectChipItem ChipItem { get; }
|
||||
|
||||
private readonly MultiSelectChips parent;
|
||||
|
||||
public MultiSelectChipItem(VisualElement visualElement, IMultiSelectChipItem element, MultiSelectChips multiSelectChips)
|
||||
{
|
||||
VisualElement = visualElement;
|
||||
ChipItem = element;
|
||||
parent = multiSelectChips;
|
||||
visualElement.Q<Label>("Name").text = element.Name;
|
||||
visualElement.Q<VisualElement>("Color").style.backgroundColor = element.Color;
|
||||
visualElement.Q<Button>("RemoveBtn").clicked += () => parent.TryRemoveItem(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
UiToolkit/MultiSelectChips/MultiSelectChipItem.cs.meta
Normal file
11
UiToolkit/MultiSelectChips/MultiSelectChipItem.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1906fa5e31f79fe48a6edda94b9c1b4d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,14 +1,19 @@
|
||||
#if ADDRESSABLES && UI_ELEMENTS
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
public class MultiSelectChips : VisualElement
|
||||
namespace NEG.Utils.UiToolkits
|
||||
{
|
||||
public class MultiSelectChips : VisualElement
|
||||
{
|
||||
public event Action<IMultiSelectChipItem> OnTryingToRemoveItem;
|
||||
public event Action<Rect> OnTryingToAddItem;
|
||||
|
||||
public string LabelText
|
||||
{
|
||||
get => label.text;
|
||||
@ -31,7 +36,7 @@ public class MultiSelectChips : VisualElement
|
||||
}
|
||||
}
|
||||
|
||||
public IList ItemsSource
|
||||
public ICollection<IMultiSelectChipItem> ItemsSource
|
||||
{
|
||||
get => itemsSource;
|
||||
|
||||
@ -43,11 +48,14 @@ public class MultiSelectChips : VisualElement
|
||||
}
|
||||
|
||||
private Label label;
|
||||
private AsyncOperationHandle<VisualTreeAsset> uxmlHandle, itemUxmlHandle;
|
||||
|
||||
private VisualTreeAsset itemPrefab;
|
||||
|
||||
private IList itemsSource;
|
||||
private ICollection<IMultiSelectChipItem> itemsSource;
|
||||
|
||||
private readonly List<MultiSelectChipItem> spawnedItems = new();
|
||||
|
||||
private VisualElement realItemsParent;
|
||||
|
||||
public new class UxmlFactory : UxmlFactory<MultiSelectChips, UxmlTraits>
|
||||
{
|
||||
@ -75,53 +83,70 @@ public class MultiSelectChips : VisualElement
|
||||
|
||||
public MultiSelectChips() : base()
|
||||
{
|
||||
uxmlHandle = Addressables.LoadAssetAsync<VisualTreeAsset>("NegUiToolkits/MultiSelectChips.uxml");
|
||||
itemUxmlHandle = Addressables.LoadAssetAsync<VisualTreeAsset>("NegUiToolkits/MultiSelectChipsItem.uxml");
|
||||
uxmlHandle.Completed += OnUxmlLoaded;
|
||||
itemUxmlHandle.Completed += OnItemUxmlLoaded;
|
||||
#if UNITY_EDITOR
|
||||
string path = AssetDatabase.GUIDToAssetPath(AssetDatabase.FindAssets($"t:Script {nameof(MultiSelectChips)}")[0]);
|
||||
path = path.Remove(path.LastIndexOf('/'));
|
||||
|
||||
SetVisuals(AssetDatabase.LoadAssetAtPath<VisualTreeAsset>($"{path}/Resources/MultiSelectChips.uxml"));
|
||||
itemPrefab = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>($"{path}/Resources/MultiSelectChipItem.uxml");
|
||||
#else
|
||||
SetVisuals(Resources.Load<VisualTreeAsset>("MultiSelectChips.uxml"));
|
||||
itemPrefab = Resources.Load<VisualTreeAsset>("MultiSelectChipItem.uxml");
|
||||
#endif
|
||||
}
|
||||
|
||||
public void UpdateItems()
|
||||
{
|
||||
if (itemPrefab == null)
|
||||
if (itemPrefab == null || itemsSource == null || realItemsParent == null)
|
||||
return;
|
||||
|
||||
var itemsToDestroy = new List<MultiSelectChipItem>(spawnedItems);
|
||||
|
||||
itemsToDestroy.RemoveAll((x) => itemsSource.Contains(x.ChipItem));
|
||||
|
||||
foreach (var item in itemsToDestroy)
|
||||
{
|
||||
realItemsParent.Remove(item.VisualElement);
|
||||
spawnedItems.Remove(item);
|
||||
}
|
||||
|
||||
List<IMultiSelectChipItem> itemsToAdd = new(itemsSource);
|
||||
|
||||
foreach (var item in spawnedItems)
|
||||
{
|
||||
if (itemsToAdd.Contains(item.ChipItem))
|
||||
itemsToAdd.Remove(item.ChipItem);
|
||||
}
|
||||
|
||||
foreach (var item in itemsToAdd)
|
||||
{
|
||||
VisualElement chipItemVisuals = itemPrefab.Instantiate();
|
||||
realItemsParent.Insert(0, chipItemVisuals);
|
||||
spawnedItems.Add(new MultiSelectChipItem(chipItemVisuals, item, this));
|
||||
}
|
||||
}
|
||||
|
||||
public void TryRemoveItem(IMultiSelectChipItem item) => OnTryingToRemoveItem?.Invoke(item);
|
||||
|
||||
private void InitLabel()
|
||||
{
|
||||
label = new Label()
|
||||
{
|
||||
pickingMode = PickingMode.Ignore
|
||||
};
|
||||
Add(label);
|
||||
Insert(0, label);
|
||||
}
|
||||
|
||||
private void OnUxmlLoaded(AsyncOperationHandle<VisualTreeAsset> operation)
|
||||
private void SetVisuals(VisualTreeAsset treeAsset)
|
||||
{
|
||||
if (operation.Status == AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
Add(operation.Result.Instantiate());
|
||||
Addressables.Release(uxmlHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Asset failed to load.");
|
||||
}
|
||||
}
|
||||
realItemsParent = treeAsset.Instantiate();
|
||||
Add(realItemsParent);
|
||||
|
||||
private void OnItemUxmlLoaded(AsyncOperationHandle<VisualTreeAsset> operation)
|
||||
{
|
||||
var button = realItemsParent.Q<Button>("AddItem");
|
||||
|
||||
if (operation.Status == AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
itemPrefab = operation.Result;
|
||||
Addressables.Release(itemUxmlHandle);
|
||||
UpdateItems();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Asset failed to load.");
|
||||
button.clicked += () => OnTryingToAddItem?.Invoke(button.worldBound);
|
||||
|
||||
realItemsParent = button.parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
8
UiToolkit/MultiSelectChips/Resources.meta
Normal file
8
UiToolkit/MultiSelectChips/Resources.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a807a09d7c00be478bf44636c2cc89f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,7 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
|
||||
<ui:VisualElement name="VisualElement" class="unity-button" style="min-height: 21px; flex-shrink: 1; flex-direction: row; flex-wrap: wrap; align-items: center;">
|
||||
<ui:VisualElement name="Color" style="min-height: 15px; min-width: 15px; border-top-left-radius: 22px; border-bottom-left-radius: 22px; border-top-right-radius: 22px; border-bottom-right-radius: 22px; border-left-width: 0; border-right-width: 0; border-top-width: 0; border-bottom-width: 0; border-left-color: rgba(0, 0, 125, 255); border-right-color: rgba(0, 0, 125, 255); border-top-color: rgba(0, 0, 125, 255); border-bottom-color: rgba(0, 0, 125, 255); background-color: rgba(255, 0, 0, 255); max-height: 15px; justify-content: center; align-items: center;" />
|
||||
<ui:Label text="Name" display-tooltip-when-elided="true" name="Name" style="padding-left: 7px; padding-right: 5px;" />
|
||||
<ui:Button text="X" display-tooltip-when-elided="true" name="RemoveBtn" />
|
||||
</ui:VisualElement>
|
||||
</ui:UXML>
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7e7a545b35ac90447adefa27e61dc82b
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@ -1,5 +1,4 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
|
||||
<ui:ListView focusable="true" show-add-remove-footer="false" horizontal-scrolling="true" />
|
||||
<ui:VisualElement style="flex-direction: row; flex-wrap: wrap;">
|
||||
<ui:Button text="+" display-tooltip-when-elided="true" name="AddItem" />
|
||||
</ui:VisualElement>
|
||||
28
UiToolkit/NEG_UiToolkit.asmdef
Normal file
28
UiToolkit/NEG_UiToolkit.asmdef
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "NEG_UiToolkit",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"Unity.Addressables",
|
||||
"Unity.ResourceManager"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.addressables",
|
||||
"expression": "",
|
||||
"define": "ADDRESSABLES"
|
||||
},
|
||||
{
|
||||
"name": "com.unity.modules.uielements",
|
||||
"expression": "",
|
||||
"define": "UI_ELEMENTS"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
UiToolkit/NEG_UiToolkit.asmdef.meta
Normal file
7
UiToolkit/NEG_UiToolkit.asmdef.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ff6afcd64a25ab4497e324400b59140
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -91,6 +91,8 @@ namespace NEG.Utils
|
||||
|
||||
public static Vector3 zzz(this Vector3 a) { return new Vector3(a.z, a.z, a.z); }
|
||||
|
||||
public static Vector3 x0y(this Vector2 a) { return new Vector3(a.x, 0f, a.y);}
|
||||
|
||||
//swizzles of size 4
|
||||
public static Vector4 xxxx(this Vector3 a) { return new Vector4(a.x, a.x, a.x, a.x); }
|
||||
public static Vector4 yxxx(this Vector3 a) { return new Vector4(a.y, a.x, a.x, a.x); }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user