2023-08-02 06:08:03 +00:00
|
|
|
|
// 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 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.Nody.Automation.Generators;
|
|
|
|
|
using Doozy.Editor.Reactor.Internal;
|
|
|
|
|
using Doozy.Editor.UIElements;
|
|
|
|
|
using Doozy.Runtime;
|
|
|
|
|
using Doozy.Runtime.Common.Extensions;
|
|
|
|
|
using Doozy.Runtime.Common.Utils;
|
|
|
|
|
using Doozy.Runtime.Nody;
|
|
|
|
|
using Doozy.Runtime.Reactor.Extensions;
|
|
|
|
|
using Doozy.Runtime.Reactor.Reactions;
|
|
|
|
|
using Doozy.Runtime.UIElements.Extensions;
|
|
|
|
|
using UnityEditor;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.UIElements;
|
|
|
|
|
// ReSharper disable MemberCanBePrivate.Global
|
|
|
|
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
|
|
|
|
|
|
|
|
|
namespace Doozy.Editor.Nody
|
|
|
|
|
{
|
|
|
|
|
public class NodyCreateNodeWindow : FluidWindow<NodyCreateNodeWindow>
|
|
|
|
|
{
|
2023-12-05 06:20:20 +00:00
|
|
|
|
private const string k_WindowTitle = "Create Node";
|
2023-08-02 06:08:03 +00:00
|
|
|
|
public const string k_WindowMenuPath = "Tools/Doozy/Nody/";
|
|
|
|
|
|
2023-12-05 06:20:20 +00:00
|
|
|
|
[MenuItem(k_WindowMenuPath + k_WindowTitle, priority = -800)]
|
|
|
|
|
public static void Open() => InternalOpenWindow(k_WindowTitle);
|
2023-08-02 06:08:03 +00:00
|
|
|
|
|
|
|
|
|
public static Color accentColor => EditorColors.Nody.Color;
|
|
|
|
|
public static EditorSelectableColorInfo selectableAccentColor => EditorSelectableColors.Nody.Color;
|
|
|
|
|
|
|
|
|
|
public Image nodyIcon { get; private set; }
|
|
|
|
|
public Texture2DReaction nodyIconReaction { get; private set; }
|
|
|
|
|
|
|
|
|
|
public FluidToggleButtonTab simpleNodeTabSelector { get; private set; }
|
|
|
|
|
public FluidToggleButtonTab globalNodeTabSelector { get; private set; }
|
|
|
|
|
|
|
|
|
|
public FluidToggleButtonTab runUpdateTabSelector { get; private set; }
|
|
|
|
|
public FluidToggleButtonTab runFixedUpdateTabSelector { get; private set; }
|
|
|
|
|
public FluidToggleButtonTab runLateUpdateTabSelector { get; private set; }
|
|
|
|
|
|
|
|
|
|
public FluidToggleSwitch canBeDeletedSwitch { get; private set; }
|
|
|
|
|
|
|
|
|
|
public FluidField nodeNameField { get; private set; }
|
|
|
|
|
public TextField nodeNameTextField { get; private set; }
|
|
|
|
|
|
|
|
|
|
public FluidField runtimePathField { get; private set; }
|
|
|
|
|
public TextField runtimePathTextField { get; private set; }
|
|
|
|
|
public FluidButton runtimePathButton { get; private set; }
|
|
|
|
|
|
|
|
|
|
public FluidField editorPathField { get; private set; }
|
|
|
|
|
public TextField editorPathTextField { get; private set; }
|
|
|
|
|
public FluidButton editorPathButton { get; private set; }
|
|
|
|
|
|
|
|
|
|
public VisualElement content { get; private set; }
|
|
|
|
|
|
|
|
|
|
public FluidButton createNodeButton { get; private set; }
|
|
|
|
|
|
|
|
|
|
public Label magicLabel { get; private set; }
|
|
|
|
|
|
|
|
|
|
public NodeType nodeType { get; private set; }
|
|
|
|
|
public bool runUpdate { get; private set; } = false;
|
|
|
|
|
public bool runFixedUpdate { get; private set; } = false;
|
|
|
|
|
public bool runLateUpdate { get; private set; } = false;
|
|
|
|
|
public bool canBeDeleted { get; private set; } = true;
|
|
|
|
|
|
|
|
|
|
protected override void OnDestroy()
|
|
|
|
|
{
|
|
|
|
|
base.OnDestroy();
|
|
|
|
|
|
|
|
|
|
simpleNodeTabSelector?.Recycle();
|
|
|
|
|
globalNodeTabSelector?.Recycle();
|
|
|
|
|
|
|
|
|
|
runUpdateTabSelector?.Recycle();
|
|
|
|
|
runFixedUpdateTabSelector?.Recycle();
|
|
|
|
|
runLateUpdateTabSelector?.Recycle();
|
|
|
|
|
|
|
|
|
|
canBeDeletedSwitch?.Recycle();
|
|
|
|
|
|
|
|
|
|
nodeNameField?.Recycle();
|
|
|
|
|
|
|
|
|
|
runtimePathField?.Recycle();
|
|
|
|
|
runtimePathButton?.Recycle();
|
|
|
|
|
|
|
|
|
|
editorPathField?.Recycle();
|
|
|
|
|
editorPathButton?.Recycle();
|
|
|
|
|
|
|
|
|
|
createNodeButton?.Recycle();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnEnable()
|
|
|
|
|
{
|
|
|
|
|
base.OnEnable();
|
|
|
|
|
minSize = new Vector2(480, 310);
|
|
|
|
|
position = new Rect(position.position, minSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void CreateGUI()
|
|
|
|
|
{
|
|
|
|
|
Initialize();
|
|
|
|
|
Compose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Initialize()
|
|
|
|
|
{
|
|
|
|
|
root
|
|
|
|
|
.RecycleAndClear()
|
|
|
|
|
.SetStyleBackgroundColor(EditorColors.Default.BoxBackground);
|
|
|
|
|
|
|
|
|
|
magicLabel =
|
|
|
|
|
DesignUtils.NewFieldNameLabel("I put on my robe and wizard hat")
|
|
|
|
|
.SetStyleAlignSelf(Align.Center)
|
|
|
|
|
.SetStyleTextAlign(TextAnchor.MiddleCenter)
|
|
|
|
|
.SetStyleOpacity(0.5f);
|
|
|
|
|
|
|
|
|
|
nodyIcon =
|
|
|
|
|
new Image()
|
|
|
|
|
.ResetLayout()
|
|
|
|
|
.SetStyleFlexShrink(0)
|
|
|
|
|
.SetStyleBackgroundImageTintColor(EditorColors.Default.WindowHeaderTitle)
|
|
|
|
|
.SetStyleMarginLeft(DesignUtils.k_Spacing3X)
|
|
|
|
|
.SetStyleSize(64);
|
|
|
|
|
|
|
|
|
|
nodyIconReaction =
|
|
|
|
|
nodyIcon
|
|
|
|
|
.GetTexture2DReaction(EditorSpriteSheets.Nody.Icons.Nody)
|
|
|
|
|
.SetEditorHeartbeat();
|
|
|
|
|
|
|
|
|
|
nodyIconReaction.Play();
|
|
|
|
|
nodyIcon.RegisterCallback<PointerEnterEvent>(evt => nodyIconReaction?.Play());
|
|
|
|
|
nodyIcon.AddManipulator(new Clickable(() => nodyIconReaction?.Play()));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
simpleNodeTabSelector =
|
|
|
|
|
GetSelectorTab(NodeType.Simple.ToString())
|
|
|
|
|
.SetTooltip("Simple node is a normal node (most nodes are simple nodes)")
|
|
|
|
|
.SetTabPosition(TabPosition.TabOnLeft)
|
|
|
|
|
.SetOnClick(() => SelectNodeType(NodeType.Simple));
|
|
|
|
|
|
|
|
|
|
globalNodeTabSelector =
|
|
|
|
|
GetSelectorTab(NodeType.Global.ToString())
|
|
|
|
|
.SetTooltip("Global node is a node that that is always running")
|
|
|
|
|
.SetTabPosition(TabPosition.TabOnRight)
|
|
|
|
|
.SetOnClick(() => SelectNodeType(NodeType.Global));
|
|
|
|
|
|
|
|
|
|
runUpdateTabSelector =
|
|
|
|
|
GetSelectorTab("Update")
|
|
|
|
|
.SetTooltip("Run Update when the node is active")
|
|
|
|
|
.SetTabPosition(TabPosition.TabOnLeft)
|
|
|
|
|
.SetOnValueChanged(evt => runUpdate = evt.newValue);
|
|
|
|
|
|
|
|
|
|
runFixedUpdateTabSelector =
|
|
|
|
|
GetSelectorTab("FixedUpdate")
|
|
|
|
|
.SetTooltip("Run FixedUpdate when the node is active")
|
|
|
|
|
.SetTabPosition(TabPosition.TabInCenter)
|
|
|
|
|
.SetOnValueChanged(evt => runFixedUpdate = evt.newValue);
|
|
|
|
|
|
|
|
|
|
runLateUpdateTabSelector =
|
|
|
|
|
GetSelectorTab("LateUpdate")
|
|
|
|
|
.SetTooltip("Run LateUpdate when the node is active")
|
|
|
|
|
.SetTabPosition(TabPosition.TabOnRight)
|
|
|
|
|
.SetOnValueChanged(evt => runLateUpdate = evt.newValue);
|
|
|
|
|
|
|
|
|
|
content =
|
|
|
|
|
new VisualElement()
|
|
|
|
|
.SetStylePadding(DesignUtils.k_Spacing2X)
|
|
|
|
|
.SetStyleMargins(DesignUtils.k_Spacing2X, 0, DesignUtils.k_Spacing2X, DesignUtils.k_Spacing2X)
|
|
|
|
|
.SetStyleBackgroundColor(EditorColors.Default.FieldBackground)
|
|
|
|
|
.SetStyleBorderRadius(4);
|
|
|
|
|
|
|
|
|
|
canBeDeletedSwitch =
|
|
|
|
|
FluidToggleSwitch.Get("Node can be deleted")
|
|
|
|
|
.SetTooltip("[Editor] Used to prevent special nodes from being deleted in the editor")
|
|
|
|
|
.SetToggleAccentColor(selectableAccentColor)
|
|
|
|
|
.SetIsOn(canBeDeleted)
|
|
|
|
|
.SetOnValueChanged(evt => canBeDeleted = evt.newValue);
|
|
|
|
|
|
|
|
|
|
TextField GetTextField() => new TextField().ResetLayout().SetStyleFlexShrink(0).SetStyleFlexGrow(1);
|
|
|
|
|
|
|
|
|
|
TextField GetPathTextField()
|
|
|
|
|
{
|
|
|
|
|
TextField textfield = new TextField().ResetLayout().SetStyleFlexShrink(0).SetStyleFlexGrow(1);
|
|
|
|
|
|
|
|
|
|
textfield.RegisterCallback<AttachToPanelEvent>(_ =>
|
|
|
|
|
{
|
|
|
|
|
textfield.RegisterCallback<DragUpdatedEvent>(OnDragUpdate);
|
|
|
|
|
textfield.RegisterCallback<DragPerformEvent>(OnDragPerformEvent);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
textfield.RegisterCallback<DetachFromPanelEvent>(_ =>
|
|
|
|
|
{
|
|
|
|
|
textfield.UnregisterCallback<DragUpdatedEvent>(OnDragUpdate);
|
|
|
|
|
textfield.UnregisterCallback<DragPerformEvent>(OnDragPerformEvent);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
void OnDragUpdate(DragUpdatedEvent dragUpdatedEvent)
|
|
|
|
|
{
|
|
|
|
|
bool isValid =
|
|
|
|
|
DragAndDrop.objectReferences.Length == 1 &&
|
|
|
|
|
DragAndDrop.objectReferences[0] != null &&
|
|
|
|
|
PathUtils.PathIsDirectory(AssetDatabase.GetAssetPath(DragAndDrop.objectReferences[0]));
|
|
|
|
|
if (!isValid) return;
|
|
|
|
|
DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnDragPerformEvent(DragPerformEvent dragPerformEvent)
|
|
|
|
|
{
|
|
|
|
|
textfield.value = PathUtils.CleanPath(AssetDatabase.GetAssetPath(DragAndDrop.objectReferences[0]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return textfield;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nodeNameTextField = GetTextField().SetName(nameof(nodeNameTextField));
|
|
|
|
|
runtimePathTextField = GetPathTextField().SetName(nameof(runtimePathTextField));
|
|
|
|
|
editorPathTextField = GetPathTextField().SetName(nameof(editorPathTextField));
|
|
|
|
|
|
|
|
|
|
FluidButton GetButton(string openFolderPanelTitle, TextField textField) =>
|
|
|
|
|
FluidButton.Get()
|
|
|
|
|
.SetElementSize(ElementSize.Small)
|
|
|
|
|
.SetIcon(EditorSpriteSheets.EditorUI.Icons.Load)
|
|
|
|
|
.SetOnClick(() =>
|
|
|
|
|
{
|
|
|
|
|
string rawPath = EditorUtility.OpenFolderPanel(openFolderPanelTitle, textField.value, "");
|
|
|
|
|
if (rawPath == textField.value || rawPath.IsNullOrEmpty()) return;
|
|
|
|
|
textField.value = PathUtils.ToRelativePath(rawPath);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
runtimePathButton = GetButton("Runtime Path", runtimePathTextField);
|
|
|
|
|
editorPathButton = GetButton("Editor Path", editorPathTextField);
|
|
|
|
|
|
|
|
|
|
nodeNameField =
|
|
|
|
|
FluidField.Get()
|
|
|
|
|
.SetLabelText("Node Name")
|
|
|
|
|
.SetTooltip("Enter a name for the new node")
|
|
|
|
|
.AddFieldContent(nodeNameTextField)
|
|
|
|
|
.AddInfoElement
|
|
|
|
|
(
|
|
|
|
|
DesignUtils.column
|
|
|
|
|
.AddSpaceBlock(3)
|
|
|
|
|
.AddChild(canBeDeletedSwitch)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
runtimePathField =
|
|
|
|
|
FluidField.Get()
|
|
|
|
|
.SetLabelText("Runtime Path (where the node is saved)")
|
|
|
|
|
.SetTooltip("Set the runtime path where to save the {NodeName}Node.cs file")
|
|
|
|
|
.AddFieldContent(runtimePathTextField)
|
|
|
|
|
.AddInfoElement
|
|
|
|
|
(
|
|
|
|
|
DesignUtils.column
|
|
|
|
|
.AddSpaceBlock(3)
|
|
|
|
|
.AddChild(runtimePathButton)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
editorPathField =
|
|
|
|
|
FluidField.Get()
|
|
|
|
|
.SetLabelText("Editor Path (where the node view and node editor are saved)")
|
|
|
|
|
.SetTooltip("Set the editor path where to save the {NodeName}NodeView.cs and {NodeName}NodeEditor.cs files")
|
|
|
|
|
.AddFieldContent(editorPathTextField)
|
|
|
|
|
.AddInfoElement
|
|
|
|
|
(
|
|
|
|
|
DesignUtils.column
|
|
|
|
|
.AddSpaceBlock(3)
|
|
|
|
|
.AddChild(editorPathButton)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
createNodeButton =
|
|
|
|
|
FluidButton.Get()
|
|
|
|
|
.SetLabelText("Create")
|
|
|
|
|
.SetIcon(EditorSpriteSheets.Nody.Icons.Nody)
|
|
|
|
|
.SetElementSize(ElementSize.Large)
|
|
|
|
|
.SetButtonStyle(ButtonStyle.Contained)
|
|
|
|
|
.SetAccentColor(selectableAccentColor)
|
|
|
|
|
.SetOnClick(() =>
|
|
|
|
|
{
|
|
|
|
|
NewNodeGenerator.CreateNode
|
|
|
|
|
(
|
|
|
|
|
nodeNameTextField.value, nodeType,
|
|
|
|
|
canBeDeleted, runUpdate, runFixedUpdate, runLateUpdate,
|
|
|
|
|
runtimePathTextField.value, editorPathTextField.value
|
|
|
|
|
);
|
2023-12-05 06:20:20 +00:00
|
|
|
|
AssetDatabase.Refresh();
|
2023-08-02 06:08:03 +00:00
|
|
|
|
Close();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
runtimePathTextField.value = $"{RuntimePath.path}/Nody/Nodes/";
|
|
|
|
|
editorPathTextField.value = $"{EditorPath.path}/Nody/Nodes/";
|
|
|
|
|
|
|
|
|
|
SelectNodeType(NodeType.Simple);
|
|
|
|
|
|
|
|
|
|
root.schedule.Execute(() =>
|
|
|
|
|
{
|
|
|
|
|
bool setEnabled = !(nodeNameTextField.value.IsNullOrEmpty() ||
|
|
|
|
|
runtimePathTextField.value.IsNullOrEmpty() ||
|
|
|
|
|
editorPathTextField.value.IsNullOrEmpty());
|
|
|
|
|
|
|
|
|
|
createNodeButton.SetEnabled(setEnabled);
|
|
|
|
|
magicLabel.visible = setEnabled;
|
|
|
|
|
|
|
|
|
|
}).Every(100);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Compose()
|
|
|
|
|
{
|
|
|
|
|
root
|
|
|
|
|
.AddSpaceBlock(2)
|
|
|
|
|
// .AddChild
|
|
|
|
|
// (
|
|
|
|
|
// DesignUtils.row
|
|
|
|
|
// .SetStyleFlexGrow(0)
|
|
|
|
|
// .SetStyleAlignItems(Align.Center)
|
|
|
|
|
// .AddChild(DesignUtils.flexibleSpace)
|
|
|
|
|
// .AddChild(nodyIcon)
|
|
|
|
|
// .AddChild(DesignUtils.flexibleSpace)
|
|
|
|
|
// // .AddChild(searchBox.SetStyleFlexShrink(0))
|
|
|
|
|
// )
|
|
|
|
|
.AddSpaceBlock(2)
|
|
|
|
|
.AddChild
|
|
|
|
|
(
|
|
|
|
|
DesignUtils.row
|
|
|
|
|
.SetStyleFlexShrink(0)
|
|
|
|
|
.SetStyleFlexGrow(0)
|
|
|
|
|
.SetStyleAlignItems(Align.Center)
|
|
|
|
|
.SetStyleBackgroundColor(EditorColors.Default.BoxBackground)
|
|
|
|
|
.SetStylePaddingLeft(DesignUtils.k_Spacing3X)
|
|
|
|
|
.SetStylePaddingRight(DesignUtils.k_Spacing3X)
|
|
|
|
|
.AddChild(simpleNodeTabSelector)
|
|
|
|
|
.AddSpace(2, 0)
|
|
|
|
|
.AddChild(globalNodeTabSelector)
|
|
|
|
|
.AddSpaceBlock(2)
|
|
|
|
|
.AddChild(DesignUtils.flexibleSpace)
|
|
|
|
|
.AddSpaceBlock(2)
|
|
|
|
|
.AddChild(runUpdateTabSelector)
|
|
|
|
|
.AddSpace(2, 0)
|
|
|
|
|
.AddChild(runFixedUpdateTabSelector)
|
|
|
|
|
.AddSpace(2, 0)
|
|
|
|
|
.AddChild(runLateUpdateTabSelector)
|
|
|
|
|
)
|
|
|
|
|
.AddSpaceBlock(2)
|
|
|
|
|
.AddChild
|
|
|
|
|
(
|
|
|
|
|
content
|
|
|
|
|
.AddChild(nodeNameField)
|
|
|
|
|
.AddSpaceBlock(2)
|
|
|
|
|
.AddChild(runtimePathField)
|
|
|
|
|
.AddSpaceBlock(2)
|
|
|
|
|
.AddChild(editorPathField)
|
|
|
|
|
.AddSpaceBlock(2)
|
|
|
|
|
.AddChild(DesignUtils.flexibleSpace)
|
|
|
|
|
)
|
|
|
|
|
.AddSpaceBlock(4)
|
|
|
|
|
.AddChild
|
|
|
|
|
(
|
|
|
|
|
DesignUtils.row
|
|
|
|
|
.AddChild(DesignUtils.flexibleSpace)
|
|
|
|
|
.AddChild(createNodeButton)
|
|
|
|
|
.AddChild(DesignUtils.flexibleSpace)
|
|
|
|
|
)
|
|
|
|
|
.AddChild(magicLabel)
|
|
|
|
|
.AddChild(DesignUtils.flexibleSpace)
|
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void SelectNodeType(NodeType typeOfNode)
|
|
|
|
|
{
|
|
|
|
|
root.schedule.Execute(() =>
|
|
|
|
|
{
|
|
|
|
|
nodeType = typeOfNode;
|
|
|
|
|
simpleNodeTabSelector?.SetIsOn(typeOfNode == NodeType.Simple);
|
|
|
|
|
globalNodeTabSelector?.SetIsOn(typeOfNode == NodeType.Global);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static FluidToggleButtonTab GetSelectorTab(string labelText) =>
|
|
|
|
|
FluidToggleButtonTab.Get()
|
|
|
|
|
.SetLabelText(labelText)
|
|
|
|
|
.SetContainerColorOff(DesignUtils.tabButtonColorOff)
|
|
|
|
|
.SetToggleAccentColor(selectableAccentColor);
|
|
|
|
|
}
|
|
|
|
|
}
|