405 lines
17 KiB
C#
405 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 System.IO;
|
|
using System.Linq;
|
|
using Doozy.Editor.EditorUI;
|
|
using Doozy.Editor.EditorUI.Components;
|
|
using Doozy.Editor.EditorUI.Components.Internal;
|
|
using Doozy.Editor.EditorUI.ScriptableObjects.Colors;
|
|
using Doozy.Editor.EditorUI.Utils;
|
|
using Doozy.Editor.EditorUI.Windows.Internal;
|
|
using Doozy.Editor.Interfaces;
|
|
using Doozy.Editor.Reactor.Internal;
|
|
using Doozy.Editor.UIElements;
|
|
using Doozy.Runtime.Common.Extensions;
|
|
using Doozy.Runtime.Reactor.Extensions;
|
|
using Doozy.Runtime.Reactor.Internal;
|
|
using Doozy.Runtime.Reactor.Reactions;
|
|
using Doozy.Runtime.UIElements.Extensions;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
|
|
// ReSharper disable MemberCanBePrivate.Global
|
|
|
|
namespace Doozy.Editor.Dashboard.Windows
|
|
{
|
|
public class DoozyDashboardWindow : FluidWindow<DoozyDashboardWindow>
|
|
{
|
|
private const string k_WindowTitle = "Dashboard";
|
|
public const string WINDOW_MENU_PATH = "Tools/Doozy/Dashboard";
|
|
|
|
[MenuItem(WINDOW_MENU_PATH, priority = -2000)]
|
|
public static void Open() => InternalOpenWindow(k_WindowTitle);
|
|
|
|
private TemplateContainer templateContainer { get; set; }
|
|
private VisualElement layoutContainer { get; set; }
|
|
private VisualElement sideMenuContainer { get; set; }
|
|
private VisualElement contentContainer { get; set; }
|
|
|
|
private const float k_MaxIconSize = 64f;
|
|
private const float k_MinIconSize = 32f;
|
|
private const int k_TitleFontSize = 18;
|
|
private const int k_SubtitleFontSize = 14;
|
|
|
|
internal string selectedTab { get; set; }
|
|
private string selectedTabKey => EditorPrefsKey($"{nameof(selectedTab)}");
|
|
|
|
private static IEnumerable<Texture2D> dashboardIconTextures => EditorSpriteSheets.EditorUI.Icons.Dashboard;
|
|
private Image dashboardIconImage { get; set; }
|
|
private VisualElement dashboardTitleContainer { get; set; }
|
|
private Label dashboardTitleLabel { get; set; }
|
|
private Label dashboardSubtitleLabel { get; set; }
|
|
|
|
private ScrollView contentScrollView { get; set; }
|
|
private VisualElement itemsContainer { get; set; }
|
|
|
|
private FluidSideMenu sideMenu { get; set; }
|
|
private string sideMenuWidthKey => EditorPrefsKey($"{nameof(sideMenu)}.{nameof(sideMenu.customWidth)}");
|
|
private string sideMenuIsCollapsedKey => EditorPrefsKey($"{nameof(sideMenu)}.{nameof(sideMenu.isCollapsed)}");
|
|
private FluidResizer sideMenuResizer { get; set; }
|
|
|
|
private VisualElement footerContainer { get; set; }
|
|
private FluidPlaceholder emptyPlaceholder { get; set; }
|
|
|
|
// protected override void OnEnable()
|
|
// {
|
|
// base.OnEnable();
|
|
// minSize = new Vector2(1200, 673);
|
|
// }
|
|
|
|
protected override void CreateGUI()
|
|
{
|
|
Initialize();
|
|
Compose();
|
|
}
|
|
|
|
private void Initialize()
|
|
{
|
|
root
|
|
.RecycleAndClear()
|
|
.Add(templateContainer = EditorLayouts.Dashboard.DashboardWindow.CloneTree());
|
|
|
|
templateContainer
|
|
.SetStyleFlexGrow(1)
|
|
.AddStyle(EditorUI.EditorStyles.Dashboard.DashboardWindow);
|
|
|
|
layoutContainer = templateContainer.Q<VisualElement>(nameof(layoutContainer));
|
|
sideMenuContainer = layoutContainer.Q<VisualElement>(nameof(sideMenuContainer));
|
|
contentContainer = layoutContainer.Q<VisualElement>(nameof(contentContainer));
|
|
|
|
InitializeDoozyIcon();
|
|
InitializeSideMenu();
|
|
InitializeContent();
|
|
InitializeFooter();
|
|
}
|
|
|
|
private void InitializeDoozyIcon()
|
|
{
|
|
dashboardTitleLabel =
|
|
DesignUtils.NewLabel("Dashboard")
|
|
.SetStyleColor(EditorColors.Default.TextTitle)
|
|
.SetStyleFontSize(k_TitleFontSize);
|
|
|
|
dashboardSubtitleLabel =
|
|
DesignUtils.NewLabel("Hub")
|
|
.SetStyleColor(EditorColors.Default.TextSubtitle)
|
|
.SetStyleFontSize(k_SubtitleFontSize);
|
|
|
|
dashboardIconImage =
|
|
new Image()
|
|
.SetStyleFlexShrink(0)
|
|
.SetStyleMargins(DesignUtils.k_Spacing)
|
|
.SetStyleAlignSelf(Align.Center);
|
|
|
|
Texture2DReaction reaction =
|
|
dashboardIconImage
|
|
.GetTexture2DReaction(dashboardIconTextures)
|
|
.SetEditorHeartbeat();
|
|
|
|
root.schedule.Execute(() =>
|
|
{
|
|
UpdateDoozyIconSize(EditorPrefs.GetBool(sideMenuIsCollapsedKey, false) ? k_MinIconSize : sideMenu.customWidth);
|
|
|
|
});
|
|
|
|
dashboardIconImage.RegisterCallback<PointerEnterEvent>(evt => reaction?.Play());
|
|
dashboardIconImage.AddManipulator(new Clickable(() => reaction?.Play()));
|
|
}
|
|
|
|
private void UpdateDoozyIconSize(float size)
|
|
{
|
|
size = Mathf.Max(k_MinIconSize, size);
|
|
size = Mathf.Min(k_MaxIconSize, size);
|
|
dashboardIconImage.SetStyleSize(size);
|
|
}
|
|
|
|
private void InitializeSideMenu()
|
|
{
|
|
//setup side menu
|
|
sideMenu =
|
|
new FluidSideMenu()
|
|
.SetMenuLevel(FluidSideMenu.MenuLevel.Level_0)
|
|
.IsCollapsable(true)
|
|
.SetCustomWidth(EditorPrefs.GetInt(sideMenuWidthKey, 200));
|
|
|
|
//link expand/collapse reaction to affect the doozy icon size
|
|
FloatReaction titleFontSizeReaction =
|
|
Reaction.Get<FloatReaction>()
|
|
.SetEditorHeartbeat()
|
|
.SetDuration(FluidSideMenu.EXPAND_COLLAPSE_DURATION * 0.5f)
|
|
.SetEase(FluidSideMenu.EXPAND_COLLAPSE_EASE);
|
|
|
|
sideMenu.expandCollapseReaction.AddOnUpdateCallback(() =>
|
|
{
|
|
float value = sideMenu.expandCollapseReaction.currentValue;
|
|
dashboardTitleContainer.SetStyleOpacity(value);
|
|
dashboardIconImage.SetStyleLeft(DesignUtils.k_Spacing * (1 - value));
|
|
});
|
|
|
|
sideMenu.OnCollapse += () => EditorPrefs.SetBool(sideMenuIsCollapsedKey, true);
|
|
sideMenu.OnExpand += () => EditorPrefs.SetBool(sideMenuIsCollapsedKey, false);
|
|
|
|
bool sideMenuIsCollapsed = EditorPrefs.GetBool(sideMenuIsCollapsedKey, false);
|
|
//update side menu collapse state
|
|
if (sideMenu.isCollapsable) sideMenu.ToggleMenu(!sideMenuIsCollapsed, false);
|
|
|
|
//add doozy icon to the side menu header
|
|
dashboardTitleContainer =
|
|
DesignUtils.column
|
|
.AddChild(dashboardTitleLabel)
|
|
.AddChild(dashboardSubtitleLabel);
|
|
|
|
if (sideMenuIsCollapsed)
|
|
{
|
|
dashboardTitleContainer.SetStyleOpacity(0f);
|
|
dashboardIconImage.SetStyleLeft(DesignUtils.k_Spacing);
|
|
}
|
|
|
|
sideMenu.headerContainer
|
|
.SetStyleDisplay(DisplayStyle.Flex)
|
|
.AddChild
|
|
(
|
|
DesignUtils.row
|
|
.SetStyleOverflow(Overflow.Hidden)
|
|
.SetStyleAlignSelf(Align.Center)
|
|
.SetStyleAlignItems(Align.Center)
|
|
.AddChild(dashboardIconImage)
|
|
.AddChild(dashboardTitleContainer)
|
|
);
|
|
|
|
//connect the doozy icon size to the side menu expand/collapse reaction
|
|
sideMenu.expandCollapseReaction.AddOnUpdateCallback(() =>
|
|
{
|
|
float currentValue = sideMenu.expandCollapseReaction.currentValue;
|
|
float size = Mathf.LerpUnclamped(k_MinIconSize, sideMenu.customWidth, currentValue);
|
|
UpdateDoozyIconSize(size);
|
|
});
|
|
|
|
//setup side menu resizer
|
|
sideMenuResizer = new FluidResizer(FluidResizer.Position.Right);
|
|
sideMenuResizer.onPointerMoveEvent += evt =>
|
|
{
|
|
if (sideMenu.isCollapsed) return;
|
|
int delta = (int)(sideMenu.customWidth + evt.deltaPosition.x);
|
|
sideMenu.SetCustomWidth(delta);
|
|
UpdateDoozyIconSize(delta);
|
|
};
|
|
sideMenuResizer.onPointerUp += evt =>
|
|
{
|
|
if (sideMenu.isCollapsed) return;
|
|
EditorPrefs.SetInt(sideMenuWidthKey, sideMenu.customWidth);
|
|
};
|
|
|
|
//add the menu and the resizer to the side menu container
|
|
sideMenuContainer.Add
|
|
(
|
|
DesignUtils.row
|
|
.AddChild(sideMenu)
|
|
.AddChild(sideMenuResizer)
|
|
);
|
|
|
|
//get all the types that implement the IDashboardWindowLayout interface
|
|
//they are used to generate the side menu buttons and to get/display the corresponding content
|
|
IEnumerable<IDashboardWindowLayout> layouts =
|
|
TypeCache.GetTypesDerivedFrom(typeof(IDashboardWindowLayout)) //get all the types that derive from IDashboardWindowLayout
|
|
.Select(type => (IDashboardWindowLayout)Activator.CreateInstance(type)) //create an instance of the type
|
|
.OrderBy(layout => layout.order) //sort the layouts by order (set in each layout's class)
|
|
.ThenBy(layout => layout.layoutName); //sort the layouts by name (set in each layout's class)
|
|
|
|
|
|
//get the previously selected layout name
|
|
string previouslySelectedLayoutName = EditorPrefs.GetString(selectedTabKey, string.Empty);
|
|
//the previously selected tab reference
|
|
FluidToggleButtonTab previouslySelectedTab = null;
|
|
//order indicator used to add spacing between the tabs, when the difference is greater or equal to 50
|
|
int previousOrder = -1;
|
|
|
|
//add buttons to side menu
|
|
foreach (IDashboardWindowLayout l in layouts)
|
|
{
|
|
//VALIDATE LAYOUT - check if the layout is valid and can be added to the side menu
|
|
if (!l.isValid) continue; //if the layout is not valid, skip it
|
|
|
|
//INJECT SPACE
|
|
if (l.order > 0 && l.order - previousOrder >= 50) //if the layout order difference is greater or equal than 50
|
|
sideMenu.AddSpaceBetweenButtons(); //add a vertical space between side menu buttons
|
|
previousOrder = l.order; //keep track of the previous layout order
|
|
|
|
//SIDE MENU BUTTON
|
|
FluidToggleButtonTab sideMenuButton = sideMenu.AddButton(l.layoutName, l.selectableAccentColor);
|
|
|
|
if (!previouslySelectedLayoutName.IsNullOrEmpty() && //if a layout was previously selected
|
|
l.layoutName.Equals(previouslySelectedLayoutName)) //and the current layout is the same as the previously selected layout
|
|
previouslySelectedTab = sideMenuButton; //set the previously selected tab to the current one
|
|
|
|
//ADD SIDE MENU BUTTON ICON (animated or static)
|
|
if (l.animatedIconTextures?.Count > 0)
|
|
sideMenuButton.SetIcon(l.animatedIconTextures); // <<< ANIMATED ICON
|
|
else if (l.staticIconTexture != null)
|
|
sideMenuButton.SetIcon(l.staticIconTexture); // <<< STATIC ICON
|
|
|
|
//WINDOW LAYOUT (added to the content container when the button is pressed)
|
|
VisualElement customWindowLayout = ((VisualElement)l).SetStyleFlexGrow(1);
|
|
|
|
sideMenuButton.SetToggleAccentColor(((IDashboardWindowLayout)customWindowLayout).selectableAccentColor);
|
|
|
|
sideMenuButton.name = l.layoutName;
|
|
|
|
//SIDE MENU BUTTON - ON VALUE CHANGED
|
|
//show the appropriate window layout when the value of the side menu button changes
|
|
sideMenuButton.OnValueChanged += evt =>
|
|
{
|
|
if (!evt.newValue) return;
|
|
contentContainer.Clear();
|
|
contentContainer.Add(customWindowLayout);
|
|
EditorPrefs.SetString(selectedTabKey, l.layoutName);
|
|
selectedTab = l.layoutName;
|
|
};
|
|
}
|
|
|
|
//select the previously selected tab (if any)
|
|
root.schedule.Execute(() => previouslySelectedTab?.SetIsOn(true));
|
|
}
|
|
|
|
private void InitializeContent()
|
|
{
|
|
contentScrollView = new ScrollView().SetStyleFlexGrow(1);
|
|
contentContainer
|
|
.AddChild(contentScrollView);
|
|
}
|
|
|
|
private void InitializeFooter()
|
|
{
|
|
footerContainer =
|
|
DesignUtils.row
|
|
.SetStyleFlexShrink(0)
|
|
.SetStyleFlexGrow(0)
|
|
.SetStyleAlignItems(Align.Center)
|
|
.SetStyleBackgroundColor(EditorColors.Default.BoxBackground)
|
|
.SetStylePaddingLeft(DesignUtils.k_Spacing2X)
|
|
.SetStylePaddingRight(DesignUtils.k_Spacing2X)
|
|
.SetStylePaddingTop(DesignUtils.k_Spacing)
|
|
.SetStylePaddingBottom(DesignUtils.k_Spacing)
|
|
;
|
|
|
|
FluidButton GetSocialButton
|
|
(
|
|
List<Texture2D> iconTextures,
|
|
EditorSelectableColorInfo selectableColorInfo,
|
|
string tooltip,
|
|
string url
|
|
)
|
|
=> FluidButton.Get()
|
|
.SetStyleFlexShrink(0)
|
|
.SetIcon(iconTextures)
|
|
.SetAccentColor(selectableColorInfo)
|
|
.SetTooltip(tooltip)
|
|
.SetOnClick(() => Application.OpenURL(url));
|
|
|
|
var youtubeButton =
|
|
GetSocialButton
|
|
(
|
|
EditorSpriteSheets.EditorUI.Icons.Youtube,
|
|
EditorSelectableColors.Brands.YouTube,
|
|
"YouTube",
|
|
"https://youtube.doozyui.com"
|
|
);
|
|
|
|
var twitterButton =
|
|
GetSocialButton
|
|
(
|
|
EditorSpriteSheets.EditorUI.Icons.Twitter,
|
|
EditorSelectableColors.Brands.Twitter,
|
|
"Twitter",
|
|
"https://twitter.doozyui.com"
|
|
);
|
|
|
|
var facebookButton =
|
|
GetSocialButton
|
|
(
|
|
EditorSpriteSheets.EditorUI.Icons.Facebook,
|
|
EditorSelectableColors.Brands.Facebook,
|
|
"Facebook",
|
|
"https://facebook.doozyui.com"
|
|
);
|
|
|
|
var discordButton =
|
|
GetSocialButton
|
|
(
|
|
EditorSpriteSheets.EditorUI.Icons.Discord,
|
|
EditorSelectableColors.Brands.Discord,
|
|
"Discord",
|
|
"https://discord.doozyui.com"
|
|
);
|
|
|
|
var doozyWebsiteButton =
|
|
FluidButton.Get("doozyui.com")
|
|
.SetStyleFlexShrink(0)
|
|
.SetOnClick(() => Application.OpenURL("https://doozyui.com"));
|
|
|
|
bool proVersionExists = Directory.Exists($"{EditorPath.path}/UIManager/Pro");
|
|
if (proVersionExists)
|
|
{
|
|
Image proImage =
|
|
new Image()
|
|
.SetStyleBackgroundImage(EditorTextures.EditorUI.Icons.Pro)
|
|
.SetStyleBackgroundImageTintColor(EditorColors.Default.Icon)
|
|
.SetStyleBackgroundScaleMode(ScaleMode.ScaleAndCrop)
|
|
.SetStyleSize(32);
|
|
|
|
VisualElement proContainer =
|
|
new VisualElement()
|
|
.SetStylePosition(Position.Absolute)
|
|
.SetStyleLeft(0)
|
|
.SetStyleRight(0)
|
|
.SetStyleTop(0)
|
|
.SetStyleBottom(0)
|
|
.SetStyleAlignItems(Align.Center)
|
|
.SetStyleJustifyContent(Justify.Center)
|
|
.AddChild(proImage);
|
|
|
|
footerContainer
|
|
.AddChild(proContainer);
|
|
}
|
|
|
|
footerContainer
|
|
.AddChild(youtubeButton)
|
|
.AddChild(twitterButton)
|
|
.AddChild(facebookButton)
|
|
.AddChild(discordButton)
|
|
.AddFlexibleSpace()
|
|
.AddChild(doozyWebsiteButton);
|
|
}
|
|
|
|
private void Compose()
|
|
{
|
|
root.AddChild(footerContainer);
|
|
}
|
|
}
|
|
}
|