OldBlueWater/BlueWater/Assets/Doozy/Editor/EditorUI/Components/FluidButton.cs
2023-08-02 15:08:03 +09:00

440 lines
17 KiB
C#

// Copyright (c) 2015 - 2023 Doozy Entertainment. All Rights Reserved.
// This code can only be used under the standard Unity Asset Store End User License Agreement
// A Copy of the EULA APPENDIX 1 is available at http://unity3d.com/company/legal/as_terms
using System;
using System.Collections.Generic;
using Doozy.Editor.EditorUI.Components.Internal;
using Doozy.Editor.EditorUI.ScriptableObjects.Colors;
using Doozy.Editor.Reactor.Internal;
using Doozy.Editor.UIElements;
using Doozy.Runtime.Colors;
using Doozy.Runtime.Common.Extensions;
using Doozy.Runtime.Reactor.Extensions;
using Doozy.Runtime.Reactor.Internal;
using Doozy.Runtime.Reactor.Reactions;
using Doozy.Runtime.UIElements;
using Doozy.Runtime.UIElements.Extensions;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UIElements;
namespace Doozy.Editor.EditorUI.Components
{
public class FluidButton : PoolableElement<FluidButton>
{
public override void Reset()
{
ResetElementSize();
ResetLayoutOrientation();
ResetButtonStyle();
ResetAnimationTrigger();
this.SetEnabled(true);
this.ResetLayout();
this.SetTooltip(string.Empty);
this.SetName(string.Empty);
this.ResetAccentColor();
this.ClearIcon();
this.ClearLabelText();
this.ClearInfoContainer();
this.ClearOnClick();
this.SetSelectionState(SelectionState.Normal);
buttonLabel.SetStyleTextAlign(TextAnchor.MiddleCenter);
}
public override void Dispose()
{
base.Dispose();
iconReaction?.Recycle();
}
#region ElementSize
private ElementSize elementSize { get; set; }
private List<VisualElement> elementSizeDependentElements { get; }
public FluidButton SetElementSize(ElementSize value)
{
UIElementsUtils.RemoveClass(elementSize.ToString(), elementSizeDependentElements);
UIElementsUtils.AddClass(value.ToString(), elementSizeDependentElements);
elementSize = value;
return this;
}
public FluidButton ResetElementSize() =>
SetElementSize(ElementSize.Normal);
#endregion
#region LayoutOrientation
private LayoutOrientation layoutOrientation { get; set; }
private List<VisualElement> layoutOrientationDependentElements { get; }
public FluidButton SetLayoutOrientation(LayoutOrientation value)
{
UIElementsUtils.RemoveClass(layoutOrientation.ToString(), layoutOrientationDependentElements);
UIElementsUtils.AddClass(value.ToString(), layoutOrientationDependentElements);
layoutOrientation = value;
return this;
}
public FluidButton ResetLayoutOrientation() =>
SetLayoutOrientation(LayoutOrientation.Horizontal);
#endregion
#region ButtonStyle
private ButtonStyle buttonStyle { get; set; }
private List<VisualElement> buttonStyleDependentElements { get; }
public FluidButton SetButtonStyle(ButtonStyle value)
{
UIElementsUtils.RemoveClass(buttonStyle.ToString(), buttonStyleDependentElements);
UIElementsUtils.AddClass(value.ToString(), buttonStyleDependentElements);
buttonStyle = value;
fluidElement.StateChanged();
return this;
}
public FluidButton ResetButtonStyle() =>
SetButtonStyle(ButtonStyle.Clear);
#endregion
#region ButtonAnimationTrigger
private ButtonAnimationTrigger animationTrigger { get; set; }
public FluidButton SetAnimationTrigger(ButtonAnimationTrigger value)
{
animationTrigger = value;
return this;
}
public FluidButton ResetAnimationTrigger() =>
SetAnimationTrigger(ButtonAnimationTrigger.OnPointerEnter);
#endregion
#region IconType
private IconType iconType { get; set; } = IconType.None;
private List<VisualElement> iconDependentComponents { get; }
internal void UpdateIconType(IconType value)
{
if (iconType != IconType.None) UIElementsUtils.RemoveClass(iconType.ToString(), iconDependentComponents);
if (value != IconType.None) UIElementsUtils.AddClass(value.ToString(), iconDependentComponents);
iconType = value;
}
#endregion
public FluidElement fluidElement { get; }
public SelectionState selectionState
{
get => fluidElement.selectionState;
set => fluidElement.selectionState = value;
}
private static Font font => EditorFonts.Ubuntu.Light;
public TemplateContainer templateContainer { get; }
public VisualElement layoutContainer { get; }
public VisualElement buttonContainer { get; }
public Image buttonIcon { get; }
public Label buttonLabel { get; }
public VisualElement infoContainer { get; }
public Texture2DReaction iconReaction { get; internal set; }
public UnityAction OnClick;
public static FluidButton Get(string labelText, string tooltip = "") =>
Get().SetLabelText(labelText).SetTooltip(tooltip);
public static FluidButton Get(string labelText, Texture2D icon, string tooltip = "") =>
Get().SetLabelText(labelText).SetIcon(icon).SetTooltip(tooltip);
public static FluidButton Get(string labelText, IEnumerable<Texture2D> iconTextures, string tooltip = "") =>
Get().SetLabelText(labelText).SetIcon(iconTextures).SetTooltip(tooltip);
public static FluidButton Get(string labelText, EditorSelectableColorInfo accentColor, string tooltip = "") =>
Get().SetLabelText(labelText).SetAccentColor(accentColor).SetTooltip(tooltip);
public static FluidButton Get(string labelText, Texture2D icon, EditorSelectableColorInfo accentColor, string tooltip = "") =>
Get().SetLabelText(labelText).SetIcon(icon).SetAccentColor(accentColor).SetTooltip(tooltip);
public static FluidButton Get(string labelText, IEnumerable<Texture2D> iconTextures, EditorSelectableColorInfo accentColor, string tooltip = "") =>
Get().SetLabelText(labelText).SetIcon(iconTextures).SetAccentColor(accentColor).SetTooltip(tooltip);
public static FluidButton Get(Texture2D icon, string tooltip = "") =>
Get().SetIcon(icon).SetTooltip(tooltip);
public static FluidButton Get(Texture2D icon, EditorSelectableColorInfo accentColor, string tooltip = "") =>
Get().SetIcon(icon).SetAccentColor(accentColor).SetTooltip(tooltip);
public static FluidButton Get(IEnumerable<Texture2D> iconTextures, string tooltip = "") =>
Get().SetIcon(iconTextures).SetTooltip(tooltip);
public static FluidButton Get(IEnumerable<Texture2D> iconTextures, EditorSelectableColorInfo accentColor, string tooltip = "") =>
Get().SetIcon(iconTextures).SetAccentColor(accentColor).SetTooltip(tooltip);
/// <summary>
/// Do not use this as new FluidButton() as that option does not use the internal pooling system
/// <para/> use: 'FluidButton.Get()' to get a new instance (this uses the internal pooling system)
/// </summary>
public FluidButton()
{
Add(templateContainer = EditorLayouts.EditorUI.FluidButton.CloneTree());
templateContainer
.AddStyle(EditorStyles.EditorUI.FieldIcon)
.AddStyle(EditorStyles.EditorUI.FieldName)
.AddStyle(EditorStyles.EditorUI.FluidButton);
layoutContainer = templateContainer.Q<VisualElement>(nameof(layoutContainer));
buttonContainer = layoutContainer.Q<VisualElement>(nameof(buttonContainer));
buttonIcon = layoutContainer.Q<Image>(nameof(buttonIcon));
buttonLabel = layoutContainer.Q<Label>(nameof(buttonLabel));
infoContainer = layoutContainer.Q<VisualElement>(nameof(infoContainer));
elementSizeDependentElements = new List<VisualElement> { layoutContainer, buttonContainer, buttonIcon, buttonLabel };
layoutOrientationDependentElements = new List<VisualElement>(elementSizeDependentElements);
buttonStyleDependentElements = new List<VisualElement>(elementSizeDependentElements);
iconDependentComponents = new List<VisualElement>(elementSizeDependentElements);
buttonLabel.SetStyleUnityFont(font);
fluidElement = new FluidElement(this)
{
OnStateChanged = StateChanged,
OnClick = ExecuteOnClick,
OnPointerEnter = ExecuteOnPointerEnter
};
//RESET
{
ResetElementSize();
ResetLayoutOrientation();
ResetButtonStyle();
ResetAnimationTrigger();
this.ResetLayout();
this.ResetAccentColor();
this.ClearIcon();
this.ClearLabelText();
this.ClearInfoContainer();
this.ClearOnClick();
this.SetTooltip(string.Empty);
selectionState = SelectionState.Normal;
}
}
private void StateChanged()
{
switch (buttonStyle)
{
case ButtonStyle.Contained:
break;
case ButtonStyle.Outline:
fluidElement.containerColor = Color.clear;
fluidElement.containerBorderColor = fluidElement.textColor.WithAlpha(fluidElement.textColor.Alpha() * 0.3f);
break;
case ButtonStyle.Clear:
if (selectionState == SelectionState.Normal)
fluidElement.iconColor = fluidElement.iconSelectableColor.GetColor(selectionState);
fluidElement.containerColor = Color.clear;
fluidElement.containerBorderColor = Color.clear;
break;
default:
throw new ArgumentOutOfRangeException();
}
buttonIcon.SetStyleBackgroundImageTintColor(fluidElement.iconColor); //Icon
buttonLabel.SetStyleColor(fluidElement.textColor); //Label
buttonContainer.SetStyleBackgroundColor(fluidElement.containerColor); //Background
layoutContainer.SetStyleBorderColor(fluidElement.containerBorderColor); //Border
}
public void ExecuteOnClick(EventBase clickEvent = null)
{
if (selectionState == SelectionState.Disabled) return;
OnClick?.Invoke();
if (animationTrigger == ButtonAnimationTrigger.OnClick)
iconReaction?.Play();
}
public void ExecuteOnPointerEnter(PointerEnterEvent enterEvent = null)
{
if (selectionState == SelectionState.Disabled) return;
if (animationTrigger == ButtonAnimationTrigger.OnPointerEnter)
iconReaction?.Play();
}
}
public static class FluidButtonExtensions
{
/// <summary> Set the button's selection state </summary>
/// <param name="target"> Target button </param>
/// <param name="state"> New selection state </param>
public static T SetSelectionState<T>(this T target, SelectionState state) where T : FluidButton
{
target.selectionState = state;
return target;
}
/// <summary> Enable button and update its visual state </summary>
/// <param name="target"> Target button </param>
public static T EnableElement<T>(this T target) where T : FluidButton
{
target.fluidElement.Enable();
return target;
}
/// <summary> Disable button and updates its visual state </summary>
/// <param name="target"> Target Button </param>
public static T DisableElement<T>(this T target) where T : FluidButton
{
target.fluidElement.Disable();
return target;
}
public static T AddToInfoContainer<T>(this T target, VisualElement element) where T : FluidButton
{
target.infoContainer.SetStyleDisplay(DisplayStyle.Flex);
target.infoContainer.AddChild(element);
return target;
}
public static T ClearInfoContainer<T>(this T target) where T : FluidButton
{
target.infoContainer
.RecycleAndClear()
.SetStyleDisplay(DisplayStyle.None);
return target;
}
#region Accent Color
/// <summary> Set button's accent color </summary>
/// <param name="target"> Target button </param>
/// <param name="value"> New accent color </param>
public static T SetAccentColor<T>(this T target, EditorSelectableColorInfo value) where T : FluidButton
{
target.fluidElement.SetAccentColor(value);
return target;
}
/// <summary> Reset the accent color to its default value </summary>
/// <param name="target"> Target Button </param>
public static T ResetAccentColor<T>(this T target) where T : FluidButton
{
target.fluidElement.ResetAccentColor();
return target;
}
#endregion
#region Label
/// <summary> Set label text </summary>
/// <param name="target"> Target Button </param>
/// <param name="labelText"> Label text </param>
public static T SetLabelText<T>(this T target, string labelText) where T : FluidButton
{
target.buttonLabel
.SetText(labelText)
.SetStyleDisplay(labelText.IsNullOrEmpty() ? DisplayStyle.None : DisplayStyle.Flex);
return target;
}
/// <summary> Clear the text and tooltip values from the button's label </summary>
public static T ClearLabelText<T>(this T target) where T : FluidButton =>
target.SetLabelText(string.Empty).SetTooltip(string.Empty);
#endregion
#region Icon
/// <summary> Set Animated Icon </summary>
/// <param name="target"> Target Button </param>
/// <param name="textures"> Icon textures </param>
/// <param name="trigger"> Animated Icon animation trigger </param>
public static T SetIcon<T>(this T target, IEnumerable<Texture2D> textures, ButtonAnimationTrigger trigger = ButtonAnimationTrigger.OnPointerEnter) where T : FluidButton
{
target.UpdateIconType(IconType.Animated);
if (target.iconReaction == null)
{
target.iconReaction = target.buttonIcon.GetTexture2DReaction(textures).SetEditorHeartbeat().SetDuration(0.6f);
}
else
{
target.iconReaction.SetTextures(textures);
}
target.buttonIcon.SetStyleDisplay(DisplayStyle.Flex);
target.SetAnimationTrigger(trigger);
return target;
}
/// <summary> Set Static Icon </summary>
/// <param name="target"> Target Button </param>
/// <param name="iconTexture2D"> Icon texture </param>
public static T SetIcon<T>(this T target, Texture2D iconTexture2D) where T : FluidButton
{
target.UpdateIconType(IconType.Static);
target.iconReaction?.Recycle();
target.iconReaction = null;
target.buttonIcon.SetStyleBackgroundImage(iconTexture2D);
target.buttonIcon.SetStyleDisplay(DisplayStyle.Flex);
target.SetAnimationTrigger(ButtonAnimationTrigger.None);
return target;
}
/// <summary> Clear the icon. If the icon is animated, its reaction will get recycled </summary>
/// <param name="target"> Target Button </param>
public static T ClearIcon<T>(this T target) where T : FluidButton
{
target.UpdateIconType(IconType.None);
target.iconReaction?.Recycle();
target.iconReaction = null;
target.buttonIcon.SetStyleBackgroundImage((Texture2D)null);
target.buttonIcon.SetStyleDisplay(DisplayStyle.None);
return target;
}
#endregion
#region OnClick
/// <summary> Set callback for OnClick (removes any other callbacks set to OnClick) </summary>
/// <param name="target"> Target Button </param>
/// <param name="callback"> OnClick callback </param>
public static T SetOnClick<T>(this T target, UnityAction callback) where T : FluidButton
{
if (callback == null) return target;
target.OnClick = callback;
return target;
}
/// <summary> Add callback to OnClick (adds another callback to OnClick) </summary>
/// <param name="target"> Target Button </param>
/// <param name="callback"> OnClick callback </param>
public static T AddOnClick<T>(this T target, UnityAction callback) where T : FluidButton
{
if (callback == null) return target;
target.OnClick += callback;
return target;
}
/// <summary> Clear any callbacks set to OnClick </summary>
/// <param name="target"> Target Button</param>
public static T ClearOnClick<T>(this T target) where T : FluidButton
{
target.OnClick = null;
return target;
}
#endregion
}
}