AxibugEmuOnline/AxibugEmuOnline.Client.Transplant/Assets/Script/AppMain/UI/OptionUI/OptionUI.cs

440 lines
14 KiB
C#
Raw Normal View History

using DG.Tweening;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace AxibugEmuOnline.Client
{
public class OptionUI : CommandExecuter
{
[SerializeField]
RectTransform MenuRoot;
[SerializeField]
Selector SelectBorder;
[Space]
[Header("ģ<><C4A3>")]
[SerializeField] OptionUI_ExecuteItem TEMPLATE_EXECUTEITEM;
[SerializeField] OptionUI_ValueEditItem TEMPLATE_VALUEEDITITEM;
private OptionUI m_child;
private OptionUI m_parent;
public override bool AloneMode => true;
public override bool Enable => m_bPoped && (m_child == null || !m_child.m_bPoped);
private bool m_bPoped = false;
private List<OptionUI_MenuItem> m_runtimeMenuItems = new List<OptionUI_MenuItem>();
private int m_selectIndex = -1;
public int SelectIndex
{
get { return m_selectIndex; }
set
{
value = Mathf.Clamp(value, 0, m_runtimeMenuItems.Count - 1);
if (m_selectIndex == value) return;
var gap = value - m_selectIndex;
while (!m_runtimeMenuItems[value].Visible)
{
var temp = value;
if (gap > 0)
{
temp++;
}
else
{
temp--;
}
if (temp >= 0 && temp < m_runtimeMenuItems.Count)
value = temp;
}
m_selectIndex = value;
OptionUI_MenuItem optionUI_MenuItem = m_runtimeMenuItems[m_selectIndex];
optionUI_MenuItem.OnFocus();
var itemUIRect = optionUI_MenuItem.transform as RectTransform;
SelectBorder.Target = itemUIRect;
}
}
protected override void Awake()
{
TEMPLATE_EXECUTEITEM.gameObject.SetActiveEx(false);
TEMPLATE_VALUEEDITITEM.gameObject.SetActiveEx(false);
SelectBorder.gameObject.SetActiveEx(false);
base.Awake();
}
protected override void Update()
{
SelectBorder.Active = Enable;
UpdateMenuState();
base.Update();
}
private void UpdateMenuState()
{
bool dirty = false;
dirty = checkDirty();
if (dirty)
{
RebuildSelectIndex();
}
}
private void RebuildSelectIndex()
{
Canvas.ForceUpdateCanvases();
SelectIndex = Mathf.Clamp(SelectIndex, 0, m_runtimeMenuItems.Count - 1);
var selectItem = m_runtimeMenuItems[SelectIndex];
if (selectItem.Visible == false)
{
bool find = false;
int currentSelect = SelectIndex;
while (currentSelect > 0)
{
currentSelect--;
if (m_runtimeMenuItems[currentSelect].Visible)
{
find = true;
}
}
if (!find)
{
currentSelect = SelectIndex;
while (currentSelect < m_runtimeMenuItems.Count)
{
if (m_runtimeMenuItems[currentSelect].Visible)
{
find = true;
}
currentSelect++;
}
}
if (find)
SelectIndex = currentSelect;
}
else
{
var itemUIRect = selectItem.transform as RectTransform;
SelectBorder.Target = itemUIRect;
}
}
private bool checkDirty()
{
bool dirty = false;
foreach (var menuItem in m_runtimeMenuItems)
{
if (menuItem.gameObject.activeSelf != menuItem.Visible)
{
dirty = true;
menuItem.gameObject.SetActive(menuItem.Visible);
}
}
return dirty;
}
IKeyMapperChanger m_lastCS;
private Action m_onClose;
/// <summary>
/// <20><><EFBFBD>˵<EFBFBD><CBB5><EFBFBD><EFBFBD><EFBFBD>ʱ,<2C><>̬<EFBFBD><CCAC><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>˵<EFBFBD>ѡ<EFBFBD><D1A1>
/// </summary>
/// <param name="menu"></param>
public void AddOptionMenuWhenPoping(OptionMenu menu)
{
if (!m_bPoped) return;
CreateRuntimeMenuItem(menu);
Canvas.ForceUpdateCanvases();
OptionUI_MenuItem optionUI_MenuItem = m_runtimeMenuItems[m_selectIndex];
SelectBorder.Target = null;
SelectBorder.Target = optionUI_MenuItem.transform as RectTransform;
}
public void Pop<T>(List<T> menus, int defaultIndex = 0, Action onClose = null) where T : OptionMenu
{
m_onClose = onClose;
ReleaseRuntimeMenus();
foreach (var menu in menus) CreateRuntimeMenuItem(menu);
CommandDispatcher.Instance.RegistController(this);
SelectBorder.gameObject.SetActiveEx(true);
Canvas.ForceUpdateCanvases();
m_selectIndex = defaultIndex;
OptionUI_MenuItem optionUI_MenuItem = m_runtimeMenuItems[defaultIndex];
optionUI_MenuItem.OnFocus();
var itemUIRect = optionUI_MenuItem.transform as RectTransform;
SelectBorder.Target = itemUIRect;
SelectBorder.RefreshPosition();
if (!m_bPoped)
{
m_bPoped = true;
Vector2 start = new Vector2(0, MenuRoot.anchoredPosition.y);
Vector2 end = new Vector2(-MenuRoot.rect.width, MenuRoot.anchoredPosition.y);
DOTween.To(
() => start,
(value) =>
{
var moveDelta = value - start;
start = value;
var topParent = m_parent;
while (topParent != null && topParent.m_parent != null)
{
topParent = topParent.m_parent;
}
if (topParent != null)
{
topParent.MenuRoot.anchoredPosition += moveDelta;
}
else
{
MenuRoot.anchoredPosition += moveDelta;
}
},
end,
0.3f
).SetEase(Ease.OutCubic);
m_lastCS = CommandDispatcher.Instance.Current;
CommandDispatcher.Instance.Current = CommandDispatcher.Instance.Normal;
}
}
public void Hide()
{
if (m_bPoped)
{
Vector2 start = new Vector2(-MenuRoot.rect.width, MenuRoot.anchoredPosition.y);
Vector2 end = new Vector2(0, MenuRoot.anchoredPosition.y);
ReleaseRuntimeMenus();
m_runtimeMenuItems.Clear();
SelectBorder.gameObject.SetActiveEx(false);
CommandDispatcher.Instance.UnRegistController(this);
Canvas.ForceUpdateCanvases();
DOTween.To(
() => start,
(value) =>
{
var moveDelta = value - start;
start = value;
var topParent = m_parent;
while (topParent != null && topParent.m_parent != null)
{
topParent = topParent.m_parent;
}
if (topParent != null)
{
topParent.MenuRoot.anchoredPosition += moveDelta;
}
else
{
MenuRoot.anchoredPosition += moveDelta;
}
},
end,
0.3f
).SetEase(Ease.OutCubic);
m_bPoped = false;
CommandDispatcher.Instance.Current = m_lastCS;
m_onClose?.Invoke();
m_onClose = null;
}
}
private void CreateRuntimeMenuItem(OptionMenu menuData)
{
if (menuData is ExecuteMenu executeMenu)
{
var menuUI = Instantiate(TEMPLATE_EXECUTEITEM.gameObject, TEMPLATE_EXECUTEITEM.transform.parent).GetComponent<OptionUI_ExecuteItem>();
menuUI.gameObject.SetActive(true);
menuUI.SetData(this, executeMenu);
m_runtimeMenuItems.Add(menuUI);
}
else if (menuData is ValueSetMenu valueSetMenu)
{
var menuUI = Instantiate(TEMPLATE_VALUEEDITITEM.gameObject, TEMPLATE_VALUEEDITITEM.transform.parent).GetComponent<OptionUI_ValueEditItem>();
menuUI.gameObject.SetActive(true);
menuUI.SetData(this, valueSetMenu);
m_runtimeMenuItems.Add(menuUI);
}
else throw new NotImplementedException($"<22>ݲ<EFBFBD>֧<EFBFBD>ֵIJ˵<C4B2><CBB5><EFBFBD><EFBFBD><EFBFBD>{menuData.GetType().Name}");
}
private void ReleaseRuntimeMenus()
{
foreach (var item in m_runtimeMenuItems)
{
item.OnHide();
Destroy(item.gameObject);
}
m_runtimeMenuItems.Clear();
}
protected override void OnCmdSelectItemDown()
{
SelectIndex++;
}
protected override void OnCmdSelectItemUp()
{
SelectIndex--;
}
protected override void OnCmdBack()
{
Hide();
}
protected override void OnCmdSelectItemLeft()
{
var executer = m_runtimeMenuItems[SelectIndex];
if (executer != null)
{
executer.OnLeft();
}
}
protected override void OnCmdSelectItemRight()
{
var executer = m_runtimeMenuItems[SelectIndex];
if (!executer.IsExpandMenu)
{
executer.OnRight();
return;
}
OnCmdEnter();
}
protected override bool OnCmdEnter()
{
var executer = m_runtimeMenuItems[SelectIndex];
bool cancelHide = false;
executer.OnExecute(this, ref cancelHide);
if (!cancelHide) Hide();
return false;
}
/// <summary>
/// չ<><D5B9><EFBFBD>¼<EFBFBD><C2BC>˵<EFBFBD>
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="menus"></param>
/// <param name="defaultIndex"></param>
/// <param name="onClose"></param>
public void ExpandSubMenu<T>(List<T> menus, int defaultIndex = 0, Action onClose = null) where T : OptionMenu
{
if (m_child == null)
{
var sourcePrefab = Resources.Load<GameObject>("UIPrefabs/OptionUI");
m_child = Instantiate(sourcePrefab, transform).GetComponent<OptionUI>();
m_child.name = $"{name}_Sub";
m_child.m_parent = this;
}
Canvas.ForceUpdateCanvases();
m_child.Pop(menus, 0, onClose);
}
public void RemoveItem(OptionUI_MenuItem ui)
{
var index = m_runtimeMenuItems.IndexOf(ui);
if (index == -1) return;
m_runtimeMenuItems.Remove(ui);
ui.OnHide();
Destroy(ui.gameObject);
RebuildSelectIndex();
}
}
/// <summary>
/// <20><><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4><EFBFBD><EFBFBD>Ϊ<EFBFBD>IJ˵<C4B2>
/// </summary>
public abstract class ExecuteMenu : OptionMenu
{
public ExecuteMenu(string name, Sprite icon = null) : base(name, icon) { }
public abstract void OnExcute(OptionUI optionUI, ref bool cancelHide);
}
/// <summary>
/// <20><><EFBFBD><EFBFBD>չ<EFBFBD><D5B9><EFBFBD><EFBFBD>Ϊ<EFBFBD>IJ˵<C4B2>
/// </summary>
public abstract class ExpandMenu : ExecuteMenu
{
protected ExpandMenu(string name, Sprite icon = null) : base(name, icon) { }
public sealed override void OnExcute(OptionUI optionUI, ref bool cancelHide)
{
cancelHide = true;
optionUI.ExpandSubMenu(GetOptionMenus());
}
protected abstract List<OptionMenu> GetOptionMenus();
}
/// <summary> <20><>Ҫֱ<D2AA>Ӽ̳<D3BC><CCB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> </summary>
public abstract class OptionMenu
{
public string Name { get; protected set; }
public Sprite Icon { get; protected set; }
public virtual bool Visible => true;
public virtual bool Enable => true;
public OptionMenu(string name, Sprite icon = null)
{
Name = name;
Icon = icon;
}
public virtual void OnFocus() { }
public virtual void OnShow(OptionUI_MenuItem ui) { }
public virtual void OnHide() { }
}
/// <summary>
/// <20><><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD>ͱ༭<CDB1>IJ˵<C4B2>
/// </summary>
public abstract class ValueSetMenu : OptionMenu
{
public ValueSetMenu(string name) : base(name) { }
public abstract Type ValueType { get; }
public abstract object ValueRaw { get; }
public abstract void OnValueChanged(object newValue);
public abstract object Min { get; }
public abstract object Max { get; }
}
}