Working popups

This commit is contained in:
Hubert Mattusch 2025-10-06 17:31:41 +02:00
parent d14e2ca055
commit 7c4c98ede8
24 changed files with 498 additions and 297 deletions

45
Debug.cs Normal file
View File

@ -0,0 +1,45 @@

using System;
using System.Diagnostics;
using Object = UnityEngine.Object;
namespace NegUtils
{
public static class Debug
{
private const string LogDefine = "LOG_INFO";
private const string WarningDefine = "LOG_WARNING";
private const string ErrorDefine = "LOG_ERRORS";
private const string AssertDefine = "UNITY_ASSERTIONS";
private const string Editor = "UNITY_EDITOR";
[Conditional(LogDefine), Conditional(Editor)]
public static void Log(object message) => UnityEngine.Debug.Log(message);
[Conditional(LogDefine), Conditional(Editor)]
public static void Log(object message, Object context) => UnityEngine.Debug.Log(message, context);
[Conditional(WarningDefine), Conditional(Editor)]
public static void LogWarning(object message) => UnityEngine.Debug.LogWarning(message);
[Conditional(WarningDefine), Conditional(Editor)]
public static void LogWarning(object message, Object context) => UnityEngine.Debug.LogWarning(message, context);
[Conditional(ErrorDefine), Conditional(Editor)]
public static void LogError(object message) => UnityEngine.Debug.LogError(message);
[Conditional(ErrorDefine), Conditional(Editor)]
public static void LogError(object message, Object context) => UnityEngine.Debug.LogError(message, context);
public static void LogException(Exception e) => UnityEngine.Debug.LogException(e);
[Conditional(AssertDefine)]
public static void Assert(bool state) => UnityEngine.Debug.Assert(state);
[Conditional(AssertDefine)]
public static void Assert(bool state, Object context) => UnityEngine.Debug.Assert(state, context);
[Conditional(AssertDefine)]
public static void Assert(bool state, object message) => UnityEngine.Debug.Assert(state, message);
[Conditional(AssertDefine)]
public static void Assert(bool state, object message, Object context) => UnityEngine.Debug.Assert(state, message, context);
}
}

3
Debug.cs.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: df1918e04df74ff8bc0e5aef1fce3437
timeCreated: 1752327272

11
NEG/UI/Abstraction.cs Normal file
View File

@ -0,0 +1,11 @@
using NEG.UI.Popup;
namespace NegUtils.NEG.UI;
internal interface IPopupsHandler
{
internal static IPopupsHandler Instance => instance;
protected static IPopupsHandler instance;
void RefreshPopups();
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d28e117dd3d544a18cf1654c71e5bb00
timeCreated: 1759328259

View File

@ -5,25 +5,14 @@ namespace NEG.UI.Popup
{ {
public class DefaultPopupData : PopupData public class DefaultPopupData : PopupData
{ {
private readonly string content; public string Title;
private readonly IDefaultPopup defaultPopup; public string Content;
private readonly List<(string, Action)> options; public readonly List<(string, Action)> Options = new(5);
private readonly string title; public override void OnRelease()
public DefaultPopupData(IDefaultPopup popup, string title, string content, List<(string, Action)> options) :
base(popup)
{ {
defaultPopup = popup; base.OnRelease();
this.title = title; Options.Clear();
this.content = content;
this.options = options;
}
public override void Show()
{
defaultPopup.SetContent(title, content, options);
base.Show();
} }
} }
} }

View File

@ -1,54 +1,79 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using System; using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using NEG.Utils;
using NegUtils;
using NegUtils.NEG.UI;
namespace NEG.UI.Popup namespace NEG.UI.Popup
{ {
[PublicAPI] public struct PopupDataHook
public class PopupData
{ {
private readonly IPopup popup; private uint version;
private PopupData data;
/// <summary> public bool IsValid => version == data.CurrentVersion;
/// PopupData constructor.
/// </summary> public PopupDataHook(PopupData data)
/// <param name="popup">attached to this data, can be used by different data instances</param>
public PopupData(IPopup popup)
{ {
this.popup = popup; this.data = data;
IsValid = true; version = data.CurrentVersion;
} }
public void Invalidate()
{
if (!IsValid)
return;
data.Dispose();
}
}
[PublicAPI]
public class PopupData : IPoolable
{
private static readonly Dictionary<Type, Action<PopupData>> ReturnDelegates = new();
/// <summary> /// <summary>
/// Is this data is still valid. If set to false, popup will not show. /// Is this data is still valid. If set to false, popup will not show.
/// </summary> /// </summary>
public bool IsValid { get; protected set; } public bool IsValid { get; protected set; }
/// <summary> internal uint CurrentVersion { get; private set; }
/// Event that is fired on closing popup.
/// </summary>
public event Action<PopupData> PopupClosedEvent
{
add => popup.OnPopupClosed += value;
remove => popup.OnPopupClosed -= value;
}
/// <summary> internal void Dispose()
/// Show popup and pass needed data.
/// </summary>
public virtual void Show() => popup.Show(this);
/// <summary>
/// Hide popup. Close visuals without firing events;
/// </summary>
public virtual void Hide() => popup.Close(true);
/// <summary>
/// Invalidate popup, <see cref="UiManager" /> will automatically skip this popup
/// </summary>
public virtual void Invalidate()
{ {
IsValid = false; IsValid = false;
UiManager.Instance.RefreshPopups(); IPopupsHandler.Instance.RefreshPopups();
var type = GetType();
if (!ReturnDelegates.TryGetValue(GetType(), out var returnDelegate))
ReturnDelegates[type] = CreateReturnDelegate(type);
returnDelegate?.Invoke(this);
}
private static Action<PopupData> CreateReturnDelegate(Type type)
{
var returnMethod = typeof(NativePool<>)
.MakeGenericType(type)
.GetMethod(nameof(NativePool<PopupData>.Return), new[] { type });
return (Action<PopupData>)Delegate.CreateDelegate(
typeof(Action<PopupData>),
returnMethod);
}
public virtual void OnGet()
{
IsValid = true;
}
public virtual void OnRelease()
{
CurrentVersion++;
} }
} }
} }

View File

@ -6,39 +6,17 @@ using NegUtils.NEG.UI;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine; using System.Runtime.CompilerServices;
using NegUtils;
using UnityEngine.Pool;
using Debug = UnityEngine.Debug;
namespace NEG.UI namespace NEG.UI
{ {
[PublicAPI] [PublicAPI]
public abstract class UiManager : IDisposable public abstract class UiManager<TWindow, TPopup> : IDisposable, IPopupsHandler where TWindow : Enum where TPopup : Enum
{ {
private IArea currentArea; public static UiManager<TWindow, TPopup> Instance { get; protected set; }
protected IDefaultPopup currentDefaultPopup;
private (PopupData data, int priority) currentShownPopup;
//TODO: localize
private string localizedYes = "Yes", localizedNo = "No", localizedOk = "Ok";
private List<IWindow> mainWindows;
private PriorityQueue<PopupData, int> popupsToShow = new();
protected UiManager(IArea startArea)
{
if (Instance != null)
{
Debug.LogError("Only one instance od UiManager is allowed");
return;
}
Instance = this;
CurrentArea = startArea;
mainWindows = new List<IWindow>();
}
public static UiManager Instance { get; protected set; }
/// <summary> /// <summary>
/// Current area shown on screen. /// Current area shown on screen.
@ -59,38 +37,69 @@ namespace NEG.UI
/// <summary> /// <summary>
/// Current window that is considered main (focused, lastly opened). Can be null. /// Current window that is considered main (focused, lastly opened). Can be null.
/// </summary> /// </summary>
public IWindow CurrentMainWindow => mainWindows.LastOrDefault(); // public IWindow CurrentMainWindow => mainWindows.LastOrDefault();
public PopupData CurrentPopup => currentShownPopup.data; // public PopupData CurrentPopup => currentShownPopup.Data;
private IArea currentArea;
private PopupDataExtended currentShownPopupData;
private IPopup currentShownPopup;
private readonly List<PopupDataExtended> popupsToShow = new();
protected abstract string OkLocalizationKey { get; }
protected abstract string YesLocalizationKey { get; }
protected abstract string NoLocalizationKey { get; }
protected abstract TPopup DefaultPopup { get; }
protected UiManager(IArea startArea)
{
if (Instance != null)
{
Debug.LogError("Only one instance od UiManager is allowed");
return;
}
Instance = this;
IPopupsHandler.instance = this;
CurrentArea = startArea;
}
public virtual void Dispose() => Instance = null; public virtual void Dispose() => Instance = null;
#region Popups
private Dictionary<TPopup, IPopup> registeredPopups = new();
/// <summary> /// <summary>
/// Show popup if there is non other currently shown. Otherwise add current popup to ordered queue and show it later. /// Show popup if there is non other currently shown. Otherwise add current popup to ordered queue and show it later.
/// It will be closed after pressing ok button. /// It will be closed after pressing ok button.
/// </summary> /// </summary>
/// <param name="title">popup title</param> /// <param name="title">popup title key</param>
/// <param name="content">popup content</param> /// <param name="content">popup content key</param>
/// <param name="okText">text to show on ok button, empty for localized "Ok"</param> /// <param name="okText">text to show on ok button, empty for localized "Ok"</param>
/// <param name="okPressed">additional action on ok pressed</param> /// <param name="okPressed">additional action on ok pressed</param>
/// <param name="priority">priority of popup (lower number -> show first)</param> /// <param name="priority">priority of popup (lower number -> show first)</param>
/// <param name="forceShow">force show current popup only if currently shown has lower priority</param> /// <param name="forceShow">force show current popup only if currently shown has lower priority</param>
/// <returns>data for created popup, can be used to invalidate popup (will not show)</returns> /// <returns>data for created popup, can be used to invalidate popup (will not show)</returns>
public PopupData ShowOkPopup(string title, string content, string okText = null, Action okPressed = null, public PopupDataHook ShowOkPopup(string title, string content, string okText = null, Action okPressed = null,
int priority = 0, bool forceShow = false) int priority = 0, bool forceShow = false)
{ {
var data = new DefaultPopupData(currentDefaultPopup, title, content, var data = NativePool<DefaultPopupData>.Get();
new List<(string, Action)> { (okText ?? localizedOk, okPressed) }); data.Title = title;
ShowPopup(data, priority, forceShow); data.Content = content;
return data; data.Options.Add((okText ?? OkLocalizationKey, okPressed));
return ShowPopup(DefaultPopup, data, priority, forceShow);
} }
/// <summary> /// <summary>
/// Show popup if there is non other currently shown. Otherwise add current popup to ordered queue and show it later. /// Show popup if there is non other currently shown. Otherwise add current popup to ordered queue and show it later.
/// It will be closed after pressing yes or no button. /// It will be closed after pressing yes or no button.
/// </summary> /// </summary>
/// <param name="title">popup title</param> /// <param name="title">popup title key</param>
/// <param name="content">popup content</param> /// <param name="content">popup content key</param>
/// <param name="yesText">text to show on yes button, empty for localized "Yes"</param> /// <param name="yesText">text to show on yes button, empty for localized "Yes"</param>
/// <param name="noText">text to show on no button, empty for localized "No"</param> /// <param name="noText">text to show on no button, empty for localized "No"</param>
/// <param name="yesPressed">additional action on yes pressed</param> /// <param name="yesPressed">additional action on yes pressed</param>
@ -98,126 +107,186 @@ namespace NEG.UI
/// <param name="priority">priority of popup (lower number -> show first)</param> /// <param name="priority">priority of popup (lower number -> show first)</param>
/// <param name="forceShow">force show current popup only if currently shown has lower priority</param> /// <param name="forceShow">force show current popup only if currently shown has lower priority</param>
/// <returns>data for created popup, can be used to invalidate popup (will not show)</returns> /// <returns>data for created popup, can be used to invalidate popup (will not show)</returns>
public PopupData ShowYesNoPopup(string title, string content, string yesText = null, string noText = null, public PopupDataHook ShowYesNoPopup(string title, string content, string yesText = null, string noText = null,
Action yesPressed = null, Action noPressed = null, int priority = 0, bool forceShow = false) Action yesPressed = null, Action noPressed = null, int priority = 0, bool forceShow = false)
{ {
var data = new DefaultPopupData(currentDefaultPopup, title, content, var data = NativePool<DefaultPopupData>.Get();
new List<(string, Action)> data.Title = title;
{ data.Content = content;
(yesText ?? localizedYes, yesPressed), (noText ?? localizedNo, noPressed) data.Options.Add((yesText ?? YesLocalizationKey, yesPressed));
}); data.Options.Add((noText ?? NoLocalizationKey, noPressed));
ShowPopup(data, priority, forceShow); return ShowPopup(DefaultPopup, data, priority, forceShow);
return data;
} }
/// <summary> /// <summary>
/// Show popup if there is non other currently shown. Otherwise add current popup to ordered queue and show it later. /// Show popup if there is non other currently shown. Otherwise add current popup to ordered queue and show it later.
/// It will be closed after pressing any button. /// It will be closed after pressing any button.
/// </summary> /// </summary>
/// <param name="title">popup title</param> /// <param name="title">popup title key</param>
/// <param name="content">popup content</param> /// <param name="content">popup content key</param>
/// <param name="actions">list of actions</param> /// <param name="actions">list of actions</param>
/// <param name="priority">priority of popup (lower number -> show first)</param> /// <param name="priority">priority of popup (lower number -> show first)</param>
/// <param name="forceShow">force show current popup only if currently shown has lower priority</param> /// <param name="forceShow">force show current popup only if currently shown has lower priority</param>
/// <returns>data for created popup, can be used to invalidate popup (will not show)</returns> /// <returns>data for created popup, can be used to invalidate popup (will not show)</returns>
public PopupData ShowPopup(string title, string content, List<(string, Action)> actions, int priority = 0, public PopupDataHook ShowPopup(string title, string content, ReadOnlySpan<(string, Action)> actions, int priority = 0, bool forceShow = false)
bool forceShow = false)
{ {
var data = new DefaultPopupData(currentDefaultPopup, title, content, actions); var data = NativePool<DefaultPopupData>.Get();
ShowPopup(data, priority, forceShow); data.Title = title;
return data; data.Content = content;
foreach (var action in actions)
{
data.Options.Add(action);
}
return ShowPopup(DefaultPopup, data, priority, forceShow);
} }
/// <summary> /// <summary>
/// Show popup if there is non other currently shown. Otherwise add current popup to ordered queue and show it later. /// Show popup if there is non other currently shown. Otherwise add current popup to ordered queue and show it later.
/// </summary> /// </summary>
/// <param name="popupType">popup type to show</param>
/// <param name="data">popup data object</param> /// <param name="data">popup data object</param>
/// <param name="priority">priority of popup (lower number -> show first)</param> /// <param name="priority">priority of popup (lower number -> show first)</param>
/// <param name="forceShow">force show current popup only if currently shown has lower priority</param> /// <param name="forceShow">force show current popup only if currently shown has lower priority</param>
public void ShowPopup(PopupData data, int priority = 0, bool forceShow = false) public PopupDataHook ShowPopup(TPopup popupType, PopupData data, int priority = 0, bool forceShow = false)
{ {
popupsToShow.Enqueue(data, priority); var dataExtended = new PopupDataExtended(priority, popupType, data);
UpdatePopupsState(forceShow, priority, data);
if (forceShow)
{
if (currentShownPopupData.Data != null && currentShownPopupData.Priority >= priority)
{
EnqueuePopup(dataExtended);
return new PopupDataHook(data);
}
if (currentShownPopupData.Data != null)
EnqueuePopup(currentShownPopupData, false);
ShowPopup(dataExtended);
return new PopupDataHook(data);
}
popupsToShow.Add(dataExtended);
RefreshPopups();
return new PopupDataHook(data);
} }
public void RegisterPopup(TPopup popupType, IPopup popup)
{
registeredPopups.Add(popupType, popup);
}
public void RefreshPopups()
{
for (int i = popupsToShow.Count - 1; i >= 0; i--)
{
if(!popupsToShow[i].Data.IsValid)
popupsToShow.RemoveAt(i);
}
if(currentShownPopupData.Data?.IsValid == true)
return;
ClosePopupSilently();
if (popupsToShow.Count == 0)
return;
var data = popupsToShow[0];
popupsToShow.RemoveAt(0);
ShowPopup(data);
}
private void ShowPopup(PopupDataExtended data)
{
if (currentShownPopup != null)
ClosePopupSilently();
if (!registeredPopups.TryGetValue(data.PopupType, out var popup))
{
Debug.LogError($"Popup {data.PopupType} does not exist");
data.Data.Dispose();
return;
}
popup.Show(data.Data);
currentShownPopup = popup;
currentShownPopupData = data;
}
private void ClosePopupSilently()
{
currentShownPopup?.Close(true);
currentShownPopupData = default;
currentShownPopup = null;
}
private void EnqueuePopup(PopupDataExtended data, bool asLast = true)
{
for (int i = 0; i < popupsToShow.Count; i++)
{
var popup = popupsToShow[i];
if(popup.Priority > data.Priority || (asLast && popup.Priority == data.Priority))
continue;
popupsToShow.Insert(i, data);
return;
}
popupsToShow.Add(data);
}
private readonly struct PopupDataExtended
{
public readonly int Priority;
public readonly TPopup PopupType;
public readonly PopupData Data;
public PopupDataExtended(int priority, TPopup popupType, PopupData data)
{
Priority = priority;
PopupType = popupType;
Data = data;
}
}
#endregion
public void UseBack() public void UseBack()
{ {
//Remove this ugly alocation
IControllable.BackUsed backUsed = new(); IControllable.BackUsed backUsed = new();
CurrentMainWindow?.TryUseBack(ref backUsed); //CurrentMainWindow?.TryUseBack(ref backUsed);
if (backUsed.Used) if(backUsed.Used)
return; return;
CurrentArea.TryUseBack(ref backUsed); CurrentArea.TryUseBack(ref backUsed);
} }
#region Windows
private Dictionary<TWindow, IWindow> registeredWindows = new();
public void RefreshPopups() #endregion
{
if (currentShownPopup.data is { IsValid: true })
return;
UpdatePopupsState(false);
}
public void SetMainWindow(IWindow window) => mainWindows.Add(window); // public void SetMainWindow(IWindow window) => mainWindows.Add(window);
//
// public void MainWindowClosed(IWindow window) => mainWindows.Remove(window);
//
// public void OnWindowClosed(IWindow window) => MainWindowClosed(window);
public void MainWindowClosed(IWindow window) => mainWindows.Remove(window); // //TODO: select new main window
// protected void PopupClosed(PopupData data)
// {
// if (currentShownPopup.data != data)
// {
// //Debug.LogError("Popup was not shown");
// return;
// }
// UpdatePopupsState(false);
// }
public void OnWindowClosed(IWindow window) => MainWindowClosed(window);
//TODO: select new main window
protected void PopupClosed(PopupData data)
{
if (currentShownPopup.data != data)
//Debug.LogError("Popup was not shown");
return;
UpdatePopupsState(false);
}
protected void SetDefaultPopup(IDefaultPopup popup) => currentDefaultPopup = popup;
protected virtual void UpdatePopupsState(bool forceShow, int priority = 0, PopupData data = null)
{
if (forceShow)
{
if (currentShownPopup.data != null && currentShownPopup.priority >= priority)
return;
popupsToShow.Enqueue(currentShownPopup.data, currentShownPopup.priority);
ShowPopup(data, priority);
return;
}
while (popupsToShow.TryDequeue(out var d, out int p))
{
if (d == null)
continue;
if (!d.IsValid)
continue;
if (d == currentShownPopup.data)
continue;
ShowPopup(d, p);
return;
}
if (currentShownPopup.data == null)
return;
currentShownPopup.data.PopupClosedEvent -= PopupClosed;
currentShownPopup.data.Hide();
currentShownPopup.data = null;
}
private void ShowPopup(PopupData data, int priority)
{
if (currentShownPopup.data != null)
{
currentShownPopup.data.PopupClosedEvent -= PopupClosed;
currentShownPopup.data.Hide();
}
currentShownPopup = (data, priority);
data.Show();
data.PopupClosedEvent += PopupClosed;
}
} }
} }

View File

@ -10,8 +10,8 @@ namespace NEG.UI.Area
private void Start() private void Start()
{ {
if (UiManager.Instance.CurrentMainWindow == null) // if (UiManager.Instance.CurrentMainWindow == null)
window.Open(); // window.Open();
} }
} }
} }

View File

@ -8,9 +8,9 @@ namespace NEG.UI.Area
{ {
protected override void OnBackUsed(IControllable.BackUsed backUsed) protected override void OnBackUsed(IControllable.BackUsed backUsed)
{ {
base.OnBackUsed(backUsed); // base.OnBackUsed(backUsed);
UiManager.Instance.CurrentMainWindow?.Close(); // UiManager.Instance.CurrentMainWindow?.Close();
backUsed.Used = true; // backUsed.Used = true;
} }
} }
} }

View File

@ -17,8 +17,8 @@ namespace NEG.UI.Area
protected virtual void Awake() protected virtual void Awake()
{ {
if (setAsDefaultArea) // if (setAsDefaultArea)
UiManager.Instance.CurrentArea = this; // UiManager.Instance.CurrentArea = this;
} }
private void Start() private void Start()
@ -29,10 +29,10 @@ namespace NEG.UI.Area
private void OnDestroy() private void OnDestroy()
{ {
if (UiManager.Instance == null) // if (UiManager.Instance == null)
return; // return;
if (ReferenceEquals(UiManager.Instance.CurrentArea, this)) // if (ReferenceEquals(UiManager.Instance.CurrentArea, this))
UiManager.Instance.CurrentArea = null; // UiManager.Instance.CurrentArea = null;
} }
public event Action<object> OnOpened; public event Action<object> OnOpened;

View File

@ -34,11 +34,11 @@ namespace NEG.UI.UnityUi.Buttons
protected virtual void Awake() protected virtual void Awake()
{ {
button.onClick.AddListener(OnClicked); // button.onClick.AddListener(OnClicked);
if (groupButtonSettings == null) // if (groupButtonSettings == null)
MonoUiManager.Instance.DefaultUiSettings.Apply(this); // MonoUiManager.Instance.DefaultUiSettings.Apply(this);
else // else
groupButtonSettings.Apply(this); // groupButtonSettings.Apply(this);
} }
private void Start() => OnDeselect(null); private void Start() => OnDeselect(null);
@ -74,13 +74,13 @@ namespace NEG.UI.UnityUi.Buttons
public void AddOrOverrideSetting(SettingData data) public void AddOrOverrideSetting(SettingData data)
{ {
if (behaviours.TryGetValue(data.Key, out var setting)) // if (behaviours.TryGetValue(data.Key, out var setting))
{ // {
setting.ChangeData(data); // setting.ChangeData(data);
return; // return;
} // }
//
behaviours.Add(data.Key, MonoUiManager.Instance.BehavioursFactory.CreateInstance(data.Key, this, data)); // behaviours.Add(data.Key, MonoUiManager.Instance.BehavioursFactory.CreateInstance(data.Key, this, data));
} }
public void RemoveSetting(string key) public void RemoveSetting(string key)

View File

@ -30,10 +30,10 @@ namespace NEG.UI.UnityUi.Buttons.Behaviours
button.OnSelected -= OnButtonSelected; button.OnSelected -= OnButtonSelected;
button.OnDeselected -= OnButtonDeselected; button.OnDeselected -= OnButtonDeselected;
} }
//
[FactoryRegistration] // [FactoryRegistration]
private static void RegisterInFactory() => // private static void RegisterInFactory() =>
MonoUiManager.Instance.BehavioursFactory.Register("ChangeTextColor", typeof(ChangeTextColorBehaviour)); // MonoUiManager.Instance.BehavioursFactory.Register("ChangeTextColor", typeof(ChangeTextColorBehaviour));
private void OnButtonSelected(bool _) => button.Text.color = data.SelectedColor; private void OnButtonSelected(bool _) => button.Text.color = data.SelectedColor;
private void OnButtonDeselected(bool _) => button.Text.color = data.DeselectedColor; private void OnButtonDeselected(bool _) => button.Text.color = data.DeselectedColor;

View File

@ -2,6 +2,8 @@
{ {
public class CloseAllWindows : ButtonReaction public class CloseAllWindows : ButtonReaction
{ {
protected override void OnClicked() => UiManager.Instance.CurrentArea.CloseAllWindows(); //protected override void OnClicked() => UiManager.Instance.CurrentArea.CloseAllWindows();
protected override void OnClicked() {
}
} }
} }

View File

@ -8,6 +8,10 @@ namespace NEG.UI.UnityUi.Buttons.Reactions
{ {
[SerializeField] private MonoWindow windowToOpen; [SerializeField] private MonoWindow windowToOpen;
protected override void OnClicked() => UiManager.Instance.CurrentMainWindow.OpenAsChild(windowToOpen); // protected override void OnClicked() => UiManager.Instance.CurrentMainWindow.OpenAsChild(windowToOpen);
protected override void OnClicked()
{
throw new System.NotImplementedException();
}
} }
} }

View File

@ -21,12 +21,12 @@ namespace NEG.UI.UnityUi
{ {
public DefaultInputModule() public DefaultInputModule()
{ {
var defaultActions = new DefaultInputActions(); // var defaultActions = new DefaultInputActions();
InputActionReference.Create(defaultActions.UI.Navigate).action.performed += // InputActionReference.Create(defaultActions.UI.Navigate).action.performed +=
ctx => OnSelectionChangeStarted(); // ctx => OnSelectionChangeStarted();
InputActionReference.Create(defaultActions.UI.Cancel).action.performed += // InputActionReference.Create(defaultActions.UI.Cancel).action.performed +=
_ => UiManager.Instance.UseBack(); // _ => UiManager.Instance.UseBack();
defaultActions.Enable(); // defaultActions.Enable();
if (Gamepad.current != null) if (Gamepad.current != null)
SetDirectionInput(); SetDirectionInput();
@ -60,28 +60,28 @@ namespace NEG.UI.UnityUi
private void SetDirectionInput() private void SetDirectionInput()
{ {
if (EventSystem.current == null || MonoUiManager.Instance == null) return; // if (EventSystem.current == null || MonoUiManager.Instance == null) return;
CurrentSelectionSource = SelectionSource.Direction; // CurrentSelectionSource = SelectionSource.Direction;
Cursor.visible = false; // Cursor.visible = false;
if (EventSystem.current.currentSelectedGameObject == null && // if (EventSystem.current.currentSelectedGameObject == null &&
MonoUiManager.Instance.CurrentMainWindow != null) // MonoUiManager.Instance.CurrentMainWindow != null)
{ // {
EventSystem.current.SetSelectedGameObject(((MonoWindow)MonoUiManager.Instance.CurrentMainWindow) // EventSystem.current.SetSelectedGameObject(((MonoWindow)MonoUiManager.Instance.CurrentMainWindow)
.DefaultSelectedItem); // .DefaultSelectedItem);
return; // return;
} // }
//
var data = new PointerEventData(EventSystem.current); // var data = new PointerEventData(EventSystem.current);
var currentSelected = EventSystem.current.currentSelectedGameObject; // var currentSelected = EventSystem.current.currentSelectedGameObject;
if (currentSelected != null) // if (currentSelected != null)
{ // {
for (var current = EventSystem.current.currentSelectedGameObject.transform; // for (var current = EventSystem.current.currentSelectedGameObject.transform;
current != null; // current != null;
current = current.parent) // current = current.parent)
ExecuteEvents.Execute(current.gameObject, data, ExecuteEvents.pointerExitHandler); // ExecuteEvents.Execute(current.gameObject, data, ExecuteEvents.pointerExitHandler);
} // }
//
EventSystem.current.SetSelectedGameObject(currentSelected); // EventSystem.current.SetSelectedGameObject(currentSelected);
} }
private void SetPointerInput() private void SetPointerInput()

View File

@ -24,7 +24,7 @@ namespace NEG.UI.UnityUi
/// </para> /// </para>
/// NEG_UI_DISABLE_WARNING_DEFAULT_SELECTION /// NEG_UI_DISABLE_WARNING_DEFAULT_SELECTION
/// </summary> /// </summary>
public class MonoUiManager : UiManager, IDisposable public abstract class MonoUiManager<TWindow, TPopup> : UiManager<TWindow, TPopup>, IDisposable where TWindow : Enum where TPopup : Enum
{ {
private readonly GameObject canvasPrefab; private readonly GameObject canvasPrefab;
@ -51,9 +51,9 @@ namespace NEG.UI.UnityUi
canvasPrefab = popupCanvas; canvasPrefab = popupCanvas;
defaultPopupPrefab = defaultPopup.GetComponent<MonoDefaultPopup>(); defaultPopupPrefab = defaultPopup.GetComponent<MonoDefaultPopup>();
SpawnDefaultPopup(); // SpawnDefaultPopup();
//
SceneManager.activeSceneChanged += (_, _) => SpawnDefaultPopup(); // SceneManager.activeSceneChanged += (_, _) => SpawnDefaultPopup();
BehavioursFactory = new KeyBasedFactory<string, ButtonElementBehaviour>(); BehavioursFactory = new KeyBasedFactory<string, ButtonElementBehaviour>();
BehavioursFactory.FireRegistration(); BehavioursFactory.FireRegistration();
@ -64,7 +64,7 @@ namespace NEG.UI.UnityUi
//TODO: use default unity selection //TODO: use default unity selection
//TODO: window snaping to slots //TODO: window snaping to slots
public static new MonoUiManager Instance { get; private set; } //public static new MonoUiManager<T, T1, T2> Instance { get; private set; }
public ButtonSettings DefaultUiSettings { get; } public ButtonSettings DefaultUiSettings { get; }
public KeyBasedFactory<string, ButtonElementBehaviour> BehavioursFactory { get; } public KeyBasedFactory<string, ButtonElementBehaviour> BehavioursFactory { get; }
@ -75,27 +75,27 @@ namespace NEG.UI.UnityUi
Instance = null; Instance = null;
} }
protected override void UpdatePopupsState(bool forceShow, int priority = 0, PopupData data = null) // protected override void UpdatePopupsState(bool forceShow, int priority = 0, PopupData data = null)
{ // {
base.UpdatePopupsState(forceShow, priority, data); // base.UpdatePopupsState(forceShow, priority, data);
if (inputModule.CurrentSelectionSource != SelectionSource.Direction) // if (inputModule.CurrentSelectionSource != SelectionSource.Direction)
return; // return;
//
// if (CurrentPopup == null && (EventSystem.current.currentSelectedGameObject == null ||
// !EventSystem.current.currentSelectedGameObject.activeInHierarchy))
// {
// if (((MonoWindow)CurrentMainWindow).DefaultSelectedItem == null)
// return;
// EventSystem.current.SetSelectedGameObject(((MonoWindow)CurrentMainWindow).DefaultSelectedItem);
// }
// }
if (CurrentPopup == null && (EventSystem.current.currentSelectedGameObject == null || // private void SpawnDefaultPopup()
!EventSystem.current.currentSelectedGameObject.activeInHierarchy)) // {
{ // var canvas = Object.Instantiate(canvasPrefab);
if (((MonoWindow)CurrentMainWindow).DefaultSelectedItem == null) // canvas.name = "DefaultPopupCanvas";
return; // SetDefaultPopup(Object.Instantiate(defaultPopupPrefab, canvas.transform));
EventSystem.current.SetSelectedGameObject(((MonoWindow)CurrentMainWindow).DefaultSelectedItem); // currentDefaultPopup.Close(true);
} // }
}
private void SpawnDefaultPopup()
{
var canvas = Object.Instantiate(canvasPrefab);
canvas.name = "DefaultPopupCanvas";
SetDefaultPopup(Object.Instantiate(defaultPopupPrefab, canvas.transform));
currentDefaultPopup.Close(true);
}
} }
} }

View File

@ -27,10 +27,10 @@ namespace NEG.UI.UnityUi.Window
private void OnDestroy() private void OnDestroy()
{ {
if (UiManager.Instance == null) // if (UiManager.Instance == null)
return; // return;
if (IsOpened) // if (IsOpened)
UiManager.Instance.OnWindowClosed(this); // UiManager.Instance.OnWindowClosed(this);
} }
private void OnValidate() private void OnValidate()
@ -50,23 +50,23 @@ namespace NEG.UI.UnityUi.Window
public void SetOpenedState(IWindowSlot parentSlot, object data) public void SetOpenedState(IWindowSlot parentSlot, object data)
{ {
gameObject.SetActive(true); // gameObject.SetActive(true);
IsOpened = true; // IsOpened = true;
Parent = parentSlot; // Parent = parentSlot;
EventSystem.current.SetSelectedGameObject(defaultSelectedItem); // EventSystem.current.SetSelectedGameObject(defaultSelectedItem);
if (parentSlot.OpenWindowAsMain) // if (parentSlot.OpenWindowAsMain)
UiManager.Instance.SetMainWindow(this); // UiManager.Instance.SetMainWindow(this);
OnOpened?.Invoke(data); // OnOpened?.Invoke(data);
} }
public void SetClosedState() public void SetClosedState()
{ {
gameObject.SetActive(false); // gameObject.SetActive(false);
IsOpened = false; // IsOpened = false;
Parent = null; // Parent = null;
((ISlotsHolder)this).CloseAllWindows(); // ((ISlotsHolder)this).CloseAllWindows();
UiManager.Instance.OnWindowClosed(this); // UiManager.Instance.OnWindowClosed(this);
OnClosed?.Invoke(); // OnClosed?.Invoke();
} }
public void SetHiddenState() => gameObject.SetActive(false); public void SetHiddenState() => gameObject.SetActive(false);

View File

@ -25,9 +25,9 @@ namespace NEG.UI.WindowSlot
public override void DetachWindow(IWindow window) public override void DetachWindow(IWindow window)
{ {
if (UiManager.Instance.CurrentMainWindow == window) // if (UiManager.Instance.CurrentMainWindow == window)
UiManager.Instance.MainWindowClosed(window); // UiManager.Instance.MainWindowClosed(window);
CurrentWindow = null; // CurrentWindow = null;
} }
public override void CloseAllWindows() => CurrentWindow = null; public override void CloseAllWindows() => CurrentWindow = null;

View File

@ -38,16 +38,16 @@ namespace NegUtils.NEG.UI.UnityUi.WindowSlot
public override void DetachWindow(IWindow window) public override void DetachWindow(IWindow window)
{ {
if (window == null) // if (window == null)
return; // return;
window.SetClosedState(); // window.SetClosedState();
windowsHistory.Remove(window); // windowsHistory.Remove(window);
if (window != currentWindow || windowsHistory.Count == 0) return; // if (window != currentWindow || windowsHistory.Count == 0) return;
currentWindow = windowsHistory[^1]; // currentWindow = windowsHistory[^1];
currentWindow.SeVisibleState(); // currentWindow.SeVisibleState();
if (UiManager.Instance.CurrentMainWindow == window) // if (UiManager.Instance.CurrentMainWindow == window)
UiManager.Instance.MainWindowClosed(window); // UiManager.Instance.MainWindowClosed(window);
EventSystem.current.SetSelectedGameObject(((MonoWindow)currentWindow).DefaultSelectedItem); // EventSystem.current.SetSelectedGameObject(((MonoWindow)currentWindow).DefaultSelectedItem);
} }
public override void CloseAllWindows() public override void CloseAllWindows()

View File

@ -51,7 +51,7 @@ namespace NEG.UI.Window
return; return;
} }
UiManager.Instance.CurrentArea.OpenWindow(window, data); //UiManager.Instance.CurrentArea.OpenWindow(window, data);
} }
/// <summary> /// <summary>
@ -94,13 +94,13 @@ namespace NEG.UI.Window
return; return;
} }
if (UiManager.Instance.CurrentMainWindow != null) // if (UiManager.Instance.CurrentMainWindow != null)
{ // {
UiManager.Instance.CurrentMainWindow.OpenWindow(window, data); // UiManager.Instance.CurrentMainWindow.OpenWindow(window, data);
return; // return;
} // }
//
UiManager.Instance.CurrentArea.OpenWindow(window, data); // UiManager.Instance.CurrentArea.OpenWindow(window, data);
} }
/// <summary> /// <summary>

47
NativePool.cs Normal file
View File

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using UnityEngine.Assertions;
namespace NegUtils;
public interface NativePool<T> where T : class, IPoolable
{
private static readonly List<T> Instances = new(10);
public static T Get()
{
T item;
if (Instances.Count == 0)
item = Activator.CreateInstance<T>();
else
{
item = Instances[^1];
Instances.RemoveAt(Instances.Count - 1);
}
item.OnGet();
return item;
}
public static void Return(T obj)
{
Assert.IsNotNull(obj);
obj.OnRelease();
if(Instances.Count >= Capacity)
return;
Instances.Add(obj);
}
public static int Capacity
{
get => Instances.Count;
set => Instances.Capacity = value;
}
}
public interface IPoolable
{
void OnGet();
void OnRelease();
}

3
NativePool.cs.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 924ee76ac4a34cd6b60b4d9b93ff0ee5
timeCreated: 1757278537