testss
@@ -0,0 +1,21 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace Unity.VisualScripting.Analytics
|
||||
{
|
||||
class StateMacroSavedEvent : UnityEditor.AssetModificationProcessor
|
||||
{
|
||||
static string[] OnWillSaveAssets(string[] paths)
|
||||
{
|
||||
foreach (string path in paths)
|
||||
{
|
||||
var assetType = AssetDatabase.GetMainAssetTypeAtPath(path);
|
||||
if (assetType == typeof(StateGraphAsset))
|
||||
{
|
||||
UsageAnalytics.CollectAndSend();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(StateGraph))]
|
||||
public sealed class StateGraphDescriptor : GraphDescriptor<StateGraph, GraphDescription>
|
||||
{
|
||||
public StateGraphDescriptor(StateGraph target) : base(target) { }
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(StateMachine))]
|
||||
public sealed class StateMachineDescriptor : MachineDescriptor<StateMachine, MachineDescription>
|
||||
{
|
||||
public StateMachineDescriptor(StateMachine target) : base(target) { }
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(StateGraphAsset))]
|
||||
public sealed class StateMacroDescriptor : MacroDescriptor<StateGraphAsset, MacroDescription>
|
||||
{
|
||||
public StateMacroDescriptor(StateGraphAsset target) : base(target) { }
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 415 B |
After Width: | Height: | Size: 703 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 421 B |
After Width: | Height: | Size: 587 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 317 B |
After Width: | Height: | Size: 518 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,25 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[GraphContextExtension(typeof(FlowGraphContext))]
|
||||
public sealed class FlowGraphContextStateExtension : GraphContextExtension<FlowGraphContext>
|
||||
{
|
||||
public FlowGraphContextStateExtension(FlowGraphContext context) : base(context) { }
|
||||
|
||||
public override bool AcceptsDragAndDrop()
|
||||
{
|
||||
return DragAndDropUtility.Is<StateGraphAsset>();
|
||||
}
|
||||
|
||||
public override void PerformDragAndDrop()
|
||||
{
|
||||
var statemacro = DragAndDropUtility.Get<StateGraphAsset>();
|
||||
var stateUnit = new StateUnit(statemacro);
|
||||
context.canvas.AddUnit(stateUnit, DragAndDropUtility.position);
|
||||
}
|
||||
|
||||
public override void DrawDragAndDropPreview()
|
||||
{
|
||||
GraphGUI.DrawDragAndDropPreviewLabel(DragAndDropUtility.offsetedPosition, DragAndDropUtility.Get<StateGraphAsset>().name, typeof(StateGraphAsset).Icon());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(StateUnit))]
|
||||
public class StateUnitDescriptor : NesterUnitDescriptor<StateUnit>
|
||||
{
|
||||
public StateUnitDescriptor(StateUnit unit) : base(unit) { }
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Editor(typeof(StateUnit))]
|
||||
public sealed class StateUnitEditor : NesterUnitEditor
|
||||
{
|
||||
public StateUnitEditor(Metadata metadata) : base(metadata) { }
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Widget(typeof(StateUnit))]
|
||||
public class StateUnitWidget : NestrerUnitWidget<StateUnit>, IDragAndDropHandler
|
||||
{
|
||||
public StateUnitWidget(FlowCanvas canvas, StateUnit unit) : base(canvas, unit) { }
|
||||
|
||||
public DragAndDropVisualMode dragAndDropVisualMode => DragAndDropVisualMode.Generic;
|
||||
|
||||
public bool AcceptsDragAndDrop()
|
||||
{
|
||||
return DragAndDropUtility.Is<StateGraphAsset>();
|
||||
}
|
||||
|
||||
public void PerformDragAndDrop()
|
||||
{
|
||||
UndoUtility.RecordEditedObject("Drag & Drop Macro");
|
||||
unit.nest.source = GraphSource.Macro;
|
||||
unit.nest.macro = DragAndDropUtility.Get<StateGraphAsset>();
|
||||
unit.nest.embed = null;
|
||||
unit.Define();
|
||||
GUI.changed = true;
|
||||
}
|
||||
|
||||
public void UpdateDragAndDrop()
|
||||
{
|
||||
}
|
||||
|
||||
public void DrawDragAndDropPreview()
|
||||
{
|
||||
GraphGUI.DrawDragAndDropPreviewLabel(new Vector2(edgePosition.x, outerPosition.yMax), "Replace with: " + DragAndDropUtility.Get<StateGraphAsset>().name, typeof(StateGraphAsset).Icon());
|
||||
}
|
||||
|
||||
public void ExitDragAndDrop()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[InitializeAfterPlugins]
|
||||
public static class UnitBaseStateExtensions
|
||||
{
|
||||
static UnitBaseStateExtensions()
|
||||
{
|
||||
UnitBase.staticUnitsExtensions.Add(GetStaticOptions);
|
||||
UnitBase.dynamicUnitsExtensions.Add(GetDynamicOptions);
|
||||
UnitBase.contextualUnitsExtensions.Add(GetContextualOptions);
|
||||
}
|
||||
|
||||
private static IEnumerable<IUnitOption> GetStaticOptions()
|
||||
{
|
||||
yield return StateUnit.WithStart().Option();
|
||||
}
|
||||
|
||||
private static IEnumerable<IUnitOption> GetDynamicOptions()
|
||||
{
|
||||
var stateMacros = UnityAPI.Await(() => AssetUtility.GetAllAssetsOfType<StateGraphAsset>().ToArray());
|
||||
|
||||
foreach (var stateUnit in stateMacros.Select(statemacro => new StateUnit(statemacro)))
|
||||
{
|
||||
yield return stateUnit.Option();
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<IUnitOption> GetContextualOptions(GraphReference reference)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,333 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Canvas(typeof(StateGraph))]
|
||||
public sealed class StateCanvas : VisualScriptingCanvas<StateGraph>
|
||||
{
|
||||
public StateCanvas(StateGraph graph) : base(graph) { }
|
||||
|
||||
|
||||
#region View
|
||||
|
||||
protected override bool shouldEdgePan => base.shouldEdgePan || isCreatingTransition;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Drawing
|
||||
|
||||
protected override void DrawBackground()
|
||||
{
|
||||
base.DrawBackground();
|
||||
|
||||
if (isCreatingTransition)
|
||||
{
|
||||
var startRect = this.Widget(transitionSource).position;
|
||||
var end = mousePosition;
|
||||
|
||||
Edge startEdge, endEdge;
|
||||
|
||||
GraphGUI.GetConnectionEdge
|
||||
(
|
||||
startRect.center,
|
||||
end,
|
||||
out startEdge,
|
||||
out endEdge
|
||||
);
|
||||
|
||||
var start = startRect.GetEdgeCenter(startEdge);
|
||||
|
||||
GraphGUI.DrawConnectionArrow(Color.white, start, end, startEdge, endEdge);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Clipboard
|
||||
|
||||
public override void ShrinkCopyGroup(HashSet<IGraphElement> copyGroup)
|
||||
{
|
||||
copyGroup.RemoveWhere(element =>
|
||||
{
|
||||
if (element is IStateTransition)
|
||||
{
|
||||
var transition = (IStateTransition)element;
|
||||
|
||||
if (!copyGroup.Contains(transition.source) ||
|
||||
!copyGroup.Contains(transition.destination))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Window
|
||||
|
||||
public override void OnToolbarGUI()
|
||||
{
|
||||
if (graph.states.Any(u => u.GetException(reference) != null) || graph.transitions.Any(t => t.GetException(reference) != null))
|
||||
{
|
||||
if (GUILayout.Button("Clear Errors", LudiqStyles.toolbarButton))
|
||||
{
|
||||
foreach (var state in graph.states)
|
||||
{
|
||||
state.SetException(reference, null);
|
||||
}
|
||||
|
||||
foreach (var transition in graph.transitions)
|
||||
{
|
||||
transition.SetException(reference, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
BoltCore.Configuration.dimInactiveNodes = GUILayout.Toggle(BoltCore.Configuration.dimInactiveNodes, "Dim", LudiqStyles.toolbarButton);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
BoltCore.Configuration.Save();
|
||||
}
|
||||
|
||||
base.OnToolbarGUI();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Context
|
||||
|
||||
protected override void OnContext()
|
||||
{
|
||||
if (isCreatingTransition)
|
||||
{
|
||||
CancelTransition();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnContext();
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<DropdownOption> GetContextOptions()
|
||||
{
|
||||
yield return new DropdownOption((Action<Vector2>)CreateFlowState, "Create Script State");
|
||||
yield return new DropdownOption((Action<Vector2>)CreateSuperState, "Create Super State");
|
||||
yield return new DropdownOption((Action<Vector2>)CreateAnyState, "Create Any State");
|
||||
|
||||
foreach (var baseOption in base.GetContextOptions())
|
||||
{
|
||||
yield return baseOption;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateFlowState(Vector2 position)
|
||||
{
|
||||
var flowState = FlowState.WithEnterUpdateExit();
|
||||
|
||||
if (!graph.states.Any())
|
||||
{
|
||||
flowState.isStart = true;
|
||||
flowState.nest.embed.title = "Start";
|
||||
}
|
||||
|
||||
AddState(flowState, position);
|
||||
}
|
||||
|
||||
private void CreateSuperState(Vector2 position)
|
||||
{
|
||||
var superState = SuperState.WithStart();
|
||||
|
||||
if (!graph.states.Any())
|
||||
{
|
||||
superState.isStart = true;
|
||||
superState.nest.embed.title = "Start";
|
||||
}
|
||||
|
||||
AddState(superState, position);
|
||||
}
|
||||
|
||||
private void CreateAnyState(Vector2 position)
|
||||
{
|
||||
AddState(new AnyState(), position);
|
||||
}
|
||||
|
||||
public void AddState(IState state, Vector2 position)
|
||||
{
|
||||
UndoUtility.RecordEditedObject("Create State");
|
||||
state.position = position;
|
||||
graph.states.Add(state);
|
||||
state.position -= this.Widget(state).position.size / 2;
|
||||
state.position = state.position.PixelPerfect();
|
||||
this.Widget(state).Reposition();
|
||||
selection.Select(state);
|
||||
GUI.changed = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Lifecycle
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
|
||||
CancelTransition();
|
||||
}
|
||||
|
||||
protected override void HandleHighPriorityInput()
|
||||
{
|
||||
if (isCreatingTransition)
|
||||
{
|
||||
if (e.IsMouseDrag(MouseButton.Left))
|
||||
{
|
||||
// Priority over lasso
|
||||
e.Use();
|
||||
}
|
||||
else if (e.IsKeyDown(KeyCode.Escape))
|
||||
{
|
||||
CancelTransition();
|
||||
e.Use();
|
||||
}
|
||||
if (e.IsMouseDown(MouseButton.Left) || e.IsMouseUp(MouseButton.Left))
|
||||
{
|
||||
CompleteTransitionToNewState();
|
||||
e.Use();
|
||||
}
|
||||
}
|
||||
|
||||
base.HandleHighPriorityInput();
|
||||
}
|
||||
|
||||
public void CompleteTransitionToNewState()
|
||||
{
|
||||
var startRect = this.Widget(transitionSource).position;
|
||||
var end = mousePosition;
|
||||
|
||||
GraphGUI.GetConnectionEdge
|
||||
(
|
||||
startRect.center,
|
||||
end,
|
||||
out var startEdge,
|
||||
out var endEdge
|
||||
);
|
||||
|
||||
var destination = FlowState.WithEnterUpdateExit();
|
||||
graph.states.Add(destination);
|
||||
|
||||
Vector2 offset;
|
||||
|
||||
var size = this.Widget(destination).position.size;
|
||||
|
||||
switch (endEdge)
|
||||
{
|
||||
case Edge.Left:
|
||||
offset = new Vector2(0, -size.y / 2);
|
||||
break;
|
||||
case Edge.Right:
|
||||
offset = new Vector2(-size.x, -size.y / 2);
|
||||
break;
|
||||
case Edge.Top:
|
||||
offset = new Vector2(-size.x / 2, 0);
|
||||
break;
|
||||
case Edge.Bottom:
|
||||
offset = new Vector2(-size.x / 2, -size.y);
|
||||
break;
|
||||
default:
|
||||
throw new UnexpectedEnumValueException<Edge>(endEdge);
|
||||
}
|
||||
|
||||
destination.position = mousePosition + offset;
|
||||
|
||||
destination.position = destination.position.PixelPerfect();
|
||||
|
||||
EndTransition(destination);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Drag & Drop
|
||||
|
||||
public override bool AcceptsDragAndDrop()
|
||||
{
|
||||
return DragAndDropUtility.Is<ScriptGraphAsset>() || DragAndDropUtility.Is<StateGraphAsset>();
|
||||
}
|
||||
|
||||
public override void PerformDragAndDrop()
|
||||
{
|
||||
if (DragAndDropUtility.Is<ScriptGraphAsset>())
|
||||
{
|
||||
var flowMacro = DragAndDropUtility.Get<ScriptGraphAsset>();
|
||||
var flowState = new FlowState(flowMacro);
|
||||
AddState(flowState, DragAndDropUtility.position);
|
||||
}
|
||||
else if (DragAndDropUtility.Is<StateGraphAsset>())
|
||||
{
|
||||
var asset = DragAndDropUtility.Get<StateGraphAsset>();
|
||||
var superState = new SuperState(asset);
|
||||
AddState(superState, DragAndDropUtility.position);
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawDragAndDropPreview()
|
||||
{
|
||||
if (DragAndDropUtility.Is<ScriptGraphAsset>())
|
||||
{
|
||||
GraphGUI.DrawDragAndDropPreviewLabel(DragAndDropUtility.offsetedPosition, DragAndDropUtility.Get<ScriptGraphAsset>().name, typeof(ScriptGraphAsset).Icon());
|
||||
}
|
||||
else if (DragAndDropUtility.Is<StateGraphAsset>())
|
||||
{
|
||||
GraphGUI.DrawDragAndDropPreviewLabel(DragAndDropUtility.offsetedPosition, DragAndDropUtility.Get<StateGraphAsset>().name, typeof(StateGraphAsset).Icon());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Transition Creation
|
||||
|
||||
public IState transitionSource { get; set; }
|
||||
|
||||
public bool isCreatingTransition => transitionSource != null;
|
||||
|
||||
public void StartTransition(IState source)
|
||||
{
|
||||
transitionSource = source;
|
||||
window.Focus();
|
||||
}
|
||||
|
||||
public void EndTransition(IState destination)
|
||||
{
|
||||
UndoUtility.RecordEditedObject("Create State Transition");
|
||||
|
||||
var transition = FlowStateTransition.WithDefaultTrigger(transitionSource, destination);
|
||||
graph.transitions.Add(transition);
|
||||
transitionSource = null;
|
||||
this.Widget(transition).BringToFront();
|
||||
selection.Select(transition);
|
||||
GUI.changed = true;
|
||||
}
|
||||
|
||||
public void CancelTransition()
|
||||
{
|
||||
transitionSource = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[GraphContext(typeof(StateGraph))]
|
||||
public class StateGraphContext : GraphContext<StateGraph, StateCanvas>
|
||||
{
|
||||
public StateGraphContext(GraphReference reference) : base(reference) { }
|
||||
|
||||
public override string windowTitle => "State Graph";
|
||||
|
||||
protected override IEnumerable<ISidebarPanelContent> SidebarPanels()
|
||||
{
|
||||
yield return new GraphInspectorPanel(this);
|
||||
yield return new VariablesPanel(this);
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,39 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(ID)]
|
||||
[PluginDependency(BoltCore.ID)]
|
||||
[Product(BoltProduct.ID)]
|
||||
[PluginRuntimeAssembly("Unity." + ID)]
|
||||
public sealed class BoltState : Plugin
|
||||
{
|
||||
[RenamedFrom("Bolt.State")]
|
||||
public const string ID = "VisualScripting.State";
|
||||
|
||||
public BoltState() : base()
|
||||
{
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public static BoltState instance { get; private set; }
|
||||
|
||||
public static BoltStateManifest Manifest => (BoltStateManifest)instance.manifest;
|
||||
public static BoltStateConfiguration Configuration => (BoltStateConfiguration)instance.configuration;
|
||||
public static BoltStateResources Resources => (BoltStateResources)instance.resources;
|
||||
public static BoltStateResources.Icons Icons => Resources.icons;
|
||||
public const string LegacyRuntimeDllGuid = "dcd2196c4e9166f499793f2007fcda35";
|
||||
public const string LegacyEditorDllGuid = "25cf173c22a896d44ae550407b10ed98";
|
||||
|
||||
public override IEnumerable<ScriptReferenceReplacement> scriptReferenceReplacements
|
||||
{
|
||||
get
|
||||
{
|
||||
#pragma warning disable 618
|
||||
yield return ScriptReferenceReplacement.From<StateMachine>(ScriptReference.Dll(LegacyRuntimeDllGuid, "Bolt", "StateMachine"));
|
||||
yield return ScriptReferenceReplacement.From<StateGraphAsset>(ScriptReference.Dll(LegacyRuntimeDllGuid, "Bolt", "StateMacro"));
|
||||
#pragma warning restore 618
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
public sealed class BoltStateConfiguration : PluginConfiguration
|
||||
{
|
||||
private BoltStateConfiguration(BoltState plugin) : base(plugin) { }
|
||||
|
||||
public override string header => "State Graphs";
|
||||
|
||||
/// <summary>
|
||||
/// Determines under which condition events should be shown in state nodes.
|
||||
/// </summary>
|
||||
[EditorPref]
|
||||
public StateRevealCondition statesReveal { get; set; } = StateRevealCondition.Always;
|
||||
|
||||
/// <summary>
|
||||
/// Determines under which condition event names should be shown in state transition.
|
||||
/// </summary>
|
||||
[EditorPref]
|
||||
public StateRevealCondition transitionsReveal { get; set; } = StateRevealCondition.OnHoverWithAlt;
|
||||
|
||||
/// <summary>
|
||||
/// Whether state transitions should show an arrow at their destination state. This can appear confusing when there are
|
||||
/// multiple transitions.
|
||||
/// </summary>
|
||||
[EditorPref]
|
||||
public bool transitionsEndArrow { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether traversed transitions should show a droplet animation.
|
||||
/// </summary>
|
||||
[EditorPref]
|
||||
public bool animateTransitions { get; set; } = true;
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
public sealed class BoltStateManifest : PluginManifest
|
||||
{
|
||||
private BoltStateManifest(BoltState plugin) : base(plugin) { }
|
||||
|
||||
public override string name => "Visual Scripting State";
|
||||
public override string author => "";
|
||||
public override string description => "State-machine based visual scripting.";
|
||||
public override SemanticVersion version => "1.5.1";
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
public sealed class BoltStateResources : PluginResources
|
||||
{
|
||||
private BoltStateResources(BoltState plugin) : base(plugin)
|
||||
{
|
||||
icons = new Icons(this);
|
||||
}
|
||||
|
||||
public Icons icons { get; private set; }
|
||||
|
||||
public override void LateInitialize()
|
||||
{
|
||||
icons.Load();
|
||||
}
|
||||
|
||||
public class Icons
|
||||
{
|
||||
public Icons(BoltStateResources resources)
|
||||
{
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
private readonly BoltStateResources resources;
|
||||
public EditorTexture graph { get; private set; }
|
||||
public EditorTexture state { get; private set; }
|
||||
|
||||
public void Load()
|
||||
{
|
||||
graph = typeof(StateGraph).Icon();
|
||||
state = typeof(State).Icon();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
internal class Changelog_1_0_0 : PluginChangelog
|
||||
{
|
||||
public Changelog_1_0_0(Plugin plugin) : base(plugin) { }
|
||||
|
||||
public override string description => "Initial Release";
|
||||
public override SemanticVersion version => "1.0.0";
|
||||
public override DateTime date => new DateTime(2017, 07, 26);
|
||||
public override IEnumerable<string> changes => Enumerable.Empty<string>();
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
internal class Changelog_1_0_1 : PluginChangelog
|
||||
{
|
||||
public Changelog_1_0_1(Plugin plugin) : base(plugin) { }
|
||||
|
||||
public override SemanticVersion version => "1.0.1";
|
||||
public override DateTime date => new DateTime(2017, 08, 01);
|
||||
|
||||
public override IEnumerable<string> changes
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "[Fixed] State header icon size on retina displays";
|
||||
yield return "[Fixed] Pasting into state transition";
|
||||
yield return "[Fixed] Transition events not being triggered from state entry";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
internal class Changelog_1_0_2 : PluginChangelog
|
||||
{
|
||||
public Changelog_1_0_2(Plugin plugin) : base(plugin) { }
|
||||
|
||||
public override SemanticVersion version => "1.0.2";
|
||||
public override DateTime date => new DateTime(2017, 09, 08);
|
||||
|
||||
public override IEnumerable<string> changes
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "[Fixed] Order-of-operations issues with transitions and updates";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
internal class Changelog_1_1_1 : PluginChangelog
|
||||
{
|
||||
public Changelog_1_1_1(Plugin plugin) : base(plugin) { }
|
||||
|
||||
public override SemanticVersion version => "1.1.1";
|
||||
public override DateTime date => new DateTime(2017, 10, 10);
|
||||
|
||||
public override IEnumerable<string> changes
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "[Changed] Default transitions to not include Update event anymore";
|
||||
yield return "[Fixed] Inactive states sometimes updating";
|
||||
yield return "[Optimized] Editor recursion performance";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
internal class Changelog_1_1_2 : PluginChangelog
|
||||
{
|
||||
public Changelog_1_1_2(Plugin plugin) : base(plugin) { }
|
||||
|
||||
public override SemanticVersion version => "1.1.2";
|
||||
public override DateTime date => new DateTime(2017, 10, 16);
|
||||
|
||||
public override IEnumerable<string> changes
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "[Fixed] Issue with dragging";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
internal class Changelog_1_1_3 : PluginChangelog
|
||||
{
|
||||
public Changelog_1_1_3(Plugin plugin) : base(plugin) { }
|
||||
|
||||
public override SemanticVersion version => "1.1.3";
|
||||
public override DateTime date => new DateTime(2017, 10, 30);
|
||||
|
||||
public override IEnumerable<string> changes
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "[Fixed] Deserialization error due to nester owner being serialized";
|
||||
yield return "[Fixed] Descriptor error with nested events";
|
||||
yield return "[Fixed] Event listening state being serialized";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
internal class Changelog_1_2_2 : PluginChangelog
|
||||
{
|
||||
public Changelog_1_2_2(Plugin plugin) : base(plugin) { }
|
||||
|
||||
public override SemanticVersion version => "1.2.2";
|
||||
public override DateTime date => new DateTime(2017, 12, 04);
|
||||
|
||||
public override IEnumerable<string> changes
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "[Added] Any State";
|
||||
yield return "[Added] Droplet animations for transitions";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
internal class Changelog_1_2_3 : PluginChangelog
|
||||
{
|
||||
public Changelog_1_2_3(Plugin plugin) : base(plugin) { }
|
||||
|
||||
public override SemanticVersion version => "1.2.3";
|
||||
public override DateTime date => new DateTime(2018, 01, 25);
|
||||
|
||||
public override IEnumerable<string> changes
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "[Added] Trigger enter / exit state events in transitions";
|
||||
yield return "[Fixed] Fixed Update and Late Update not firing in super states";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
internal class Changelog_1_2_4 : PluginChangelog
|
||||
{
|
||||
public Changelog_1_2_4(Plugin plugin) : base(plugin) { }
|
||||
|
||||
public override SemanticVersion version => "1.2.4";
|
||||
public override DateTime date => new DateTime(2018, 02, 26);
|
||||
|
||||
public override IEnumerable<string> changes
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "[Fixed] Manual events not triggering in state units";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
internal class Changelog_1_3_0 : PluginChangelog
|
||||
{
|
||||
public Changelog_1_3_0(Plugin plugin) : base(plugin) { }
|
||||
|
||||
public override SemanticVersion version => "1.3.0";
|
||||
public override DateTime date => new DateTime(2018, 04, 06);
|
||||
|
||||
public override IEnumerable<string> changes
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "[Fixed] State unit relations";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
internal class Changelog_1_4_0f6 : PluginChangelog
|
||||
{
|
||||
public Changelog_1_4_0f6(Plugin plugin) : base(plugin) { }
|
||||
|
||||
public override SemanticVersion version => "1.4.0f6";
|
||||
public override DateTime date => new DateTime(2018, 09, 06);
|
||||
|
||||
public override IEnumerable<string> changes
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "[Fixed] On Enter State and On Exit State events not firing in super units";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Plugin(BoltState.ID)]
|
||||
internal class Changelog_1_4_0f10 : PluginChangelog
|
||||
{
|
||||
public Changelog_1_4_0f10(Plugin plugin) : base(plugin) { }
|
||||
|
||||
public override SemanticVersion version => "1.4.0f10";
|
||||
public override DateTime date => new DateTime(2018, 10, 29);
|
||||
|
||||
public override IEnumerable<string> changes
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "[Fixed] Inactive states starting to listen after undo";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
internal class Changelog_1_4_1 : PluginChangelog
|
||||
{
|
||||
public Changelog_1_4_1(Plugin plugin) : base(plugin) { }
|
||||
|
||||
public override SemanticVersion version => "1.4.1";
|
||||
|
||||
public override DateTime date => new DateTime(2019, 01, 22);
|
||||
|
||||
public override IEnumerable<string> changes
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "[Changed] Allowed state machines to receive Start, OnEnable and OnDisable events for consistency";
|
||||
yield return "[Fixed] Graph data type mismatch in event listening handlers for state graphs";
|
||||
yield return "[Fixed] Non instantiated state graphs showing force enter / force exit contextual menu options";
|
||||
yield return "[Fixed] Live-added Any States not sending transitions";
|
||||
yield return "[Fixed] Any States not exiting properly when stopping the graph";
|
||||
yield return "[Fixed] Live-added start states not getting automatically entered";
|
||||
yield return "[Fixed] Force Enter and Force Exit showing in Any State context menu";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltState.ID)]
|
||||
internal class Migration_1_4_13_to_1_5_1 : PluginMigration
|
||||
{
|
||||
public Migration_1_4_13_to_1_5_1(Plugin plugin) : base(plugin)
|
||||
{
|
||||
order = 2;
|
||||
}
|
||||
|
||||
public override SemanticVersion @from => "1.4.13";
|
||||
public override SemanticVersion to => "1.5.1";
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
plugin.configuration.Initialize();
|
||||
|
||||
try
|
||||
{
|
||||
MigrateProjectSettings();
|
||||
}
|
||||
#pragma warning disable 168
|
||||
catch (Exception e)
|
||||
#pragma warning restore 168
|
||||
{
|
||||
Debug.LogWarning("There was a problem migrating your Visual Scripting project settings. Be sure to check them in Edit -> Project Settings -> Visual Scripting");
|
||||
#if VISUAL_SCRIPT_DEBUG_MIGRATION
|
||||
Debug.LogError(e);
|
||||
#endif
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
MigrationUtility_1_4_13_to_1_5_1.MigrateEditorPreferences(this.plugin);
|
||||
}
|
||||
#pragma warning disable 168
|
||||
catch (Exception e)
|
||||
#pragma warning restore 168
|
||||
{
|
||||
Debug.LogWarning("There was a problem migrating your Visual Scripting editor preferences. Be sure to check them in Edit -> Preferences -> Visual Scripting");
|
||||
#if VISUAL_SCRIPT_DEBUG_MIGRATION
|
||||
Debug.LogError(e);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private void MigrateProjectSettings()
|
||||
{
|
||||
// Bolt.State -> VisualScripting.State
|
||||
var stateProjectSettings = BoltState.Configuration.projectSettings;
|
||||
|
||||
var boltStateProjectSettings = MigrationUtility_1_4_13_to_1_5_1.GetLegacyProjectSettingsAsset("Bolt.State");
|
||||
if (boltStateProjectSettings != null)
|
||||
{
|
||||
MigrationUtility_1_4_13_to_1_5_1.TransferSettings(boltStateProjectSettings, stateProjectSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Plugin(BoltState.ID)]
|
||||
internal class DeprecatedSavedVersionLoader_1_4_13_to_1_5_1 : PluginDeprecatedSavedVersionLoader
|
||||
{
|
||||
public DeprecatedSavedVersionLoader_1_4_13_to_1_5_1(Plugin plugin) : base(plugin) { }
|
||||
|
||||
public override SemanticVersion @from => "1.4.13";
|
||||
|
||||
public override bool Run(out SemanticVersion savedVersion)
|
||||
{
|
||||
var manuallyParsedVersion = MigrationUtility_1_4_13_to_1_5_1.TryManualParseSavedVersion("Bolt.State");
|
||||
savedVersion = manuallyParsedVersion;
|
||||
|
||||
return savedVersion != "0.0.0";
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
#if DISTRIBUTE_ASSEMBLIES
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
|
||||
[assembly: AssemblyTitle("Visual Scripting State (Editor)")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Unity")]
|
||||
[assembly: AssemblyProduct("Visual Scripting")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
|
||||
[assembly: Guid("50495950-7a88-44ea-9818-505a9748a580")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
#endif
|
@@ -0,0 +1,10 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Editor(typeof(StateGraph))]
|
||||
public class StateGraphEditor : GraphEditor
|
||||
{
|
||||
public StateGraphEditor(Metadata metadata) : base(metadata) { }
|
||||
|
||||
private new StateGraph graph => (StateGraph)base.graph;
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public enum StateRevealCondition
|
||||
{
|
||||
Never,
|
||||
Always,
|
||||
OnHover,
|
||||
OnHoverWithAlt,
|
||||
WhenSelected,
|
||||
OnHoverOrSelected,
|
||||
OnHoverWithAltOrSelected,
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(AnyState))]
|
||||
public class AnyStateDescriptor : StateDescriptor<AnyState>
|
||||
{
|
||||
public AnyStateDescriptor(AnyState state) : base(state) { }
|
||||
}
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Widget(typeof(AnyState))]
|
||||
public class AnyStateWidget : StateWidget<AnyState>
|
||||
{
|
||||
public AnyStateWidget(StateCanvas canvas, AnyState state) : base(canvas, state) { }
|
||||
|
||||
protected override NodeColorMix color => NodeColorMix.TealReadable;
|
||||
|
||||
protected override string summary => null;
|
||||
|
||||
public override bool canToggleStart => false;
|
||||
|
||||
public override bool canForceEnter => false;
|
||||
|
||||
public override bool canForceExit => false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(FlowState))]
|
||||
public class FlowStateDescriptor : NesterStateDescriptor<FlowState>
|
||||
{
|
||||
public FlowStateDescriptor(FlowState state) : base(state) { }
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Editor(typeof(FlowState))]
|
||||
public sealed class FlowStateEditor : NesterStateEditor
|
||||
{
|
||||
public FlowStateEditor(Metadata metadata) : base(metadata) { }
|
||||
}
|
||||
}
|
@@ -0,0 +1,231 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Widget(typeof(FlowState))]
|
||||
public sealed class FlowStateWidget : NesterStateWidget<FlowState>, IDragAndDropHandler
|
||||
{
|
||||
public FlowStateWidget(StateCanvas canvas, FlowState state) : base(canvas, state)
|
||||
{
|
||||
state.nest.beforeGraphChange += BeforeGraphChange;
|
||||
state.nest.afterGraphChange += AfterGraphChange;
|
||||
|
||||
if (state.nest.graph != null)
|
||||
{
|
||||
state.nest.graph.elements.CollectionChanged += CacheEventLinesOnUnityThread;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
state.nest.beforeGraphChange -= BeforeGraphChange;
|
||||
state.nest.afterGraphChange -= AfterGraphChange;
|
||||
}
|
||||
|
||||
private void BeforeGraphChange()
|
||||
{
|
||||
if (state.nest.graph != null)
|
||||
{
|
||||
state.nest.graph.elements.CollectionChanged -= CacheEventLinesOnUnityThread;
|
||||
}
|
||||
}
|
||||
|
||||
private void AfterGraphChange()
|
||||
{
|
||||
CacheEventLinesOnUnityThread();
|
||||
|
||||
if (state.nest.graph != null)
|
||||
{
|
||||
state.nest.graph.elements.CollectionChanged += CacheEventLinesOnUnityThread;
|
||||
}
|
||||
}
|
||||
|
||||
#region Model
|
||||
|
||||
private List<EventLine> eventLines { get; } = new List<EventLine>();
|
||||
|
||||
private void CacheEventLinesOnUnityThread()
|
||||
{
|
||||
UnityAPI.Async(CacheEventLines);
|
||||
}
|
||||
|
||||
private void CacheEventLines()
|
||||
{
|
||||
eventLines.Clear();
|
||||
|
||||
if (state.nest.graph != null)
|
||||
{
|
||||
eventLines.AddRange(state.nest.graph.units
|
||||
.OfType<IEventUnit>()
|
||||
.Select(e => e.GetType())
|
||||
.Distinct()
|
||||
.Select(eventType => new EventLine(eventType))
|
||||
.OrderBy(eventLine => eventLine.content.text));
|
||||
}
|
||||
|
||||
Reposition();
|
||||
}
|
||||
|
||||
protected override void CacheItemFirstTime()
|
||||
{
|
||||
base.CacheItemFirstTime();
|
||||
|
||||
CacheEventLines();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Positioning
|
||||
|
||||
public Dictionary<EventLine, Rect> eventLinesPositions { get; } = new Dictionary<EventLine, Rect>();
|
||||
|
||||
public override void CachePosition()
|
||||
{
|
||||
base.CachePosition();
|
||||
|
||||
eventLinesPositions.Clear();
|
||||
|
||||
var y = contentInnerPosition.y;
|
||||
|
||||
foreach (var eventLine in eventLines)
|
||||
{
|
||||
var eventLinePosition = new Rect
|
||||
(
|
||||
contentInnerPosition.x,
|
||||
y,
|
||||
contentInnerPosition.width,
|
||||
eventLine.GetHeight(contentInnerPosition.width)
|
||||
);
|
||||
|
||||
eventLinesPositions.Add(eventLine, eventLinePosition);
|
||||
|
||||
y += eventLinePosition.height;
|
||||
}
|
||||
}
|
||||
|
||||
protected override float GetContentHeight(float width)
|
||||
{
|
||||
var eventLinesHeight = 0f;
|
||||
|
||||
foreach (var eventLine in eventLines)
|
||||
{
|
||||
eventLinesHeight += eventLine.GetHeight(width);
|
||||
}
|
||||
|
||||
return eventLinesHeight;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Drawing
|
||||
|
||||
protected override bool showContent => eventLines.Count > 0;
|
||||
|
||||
protected override void DrawContent()
|
||||
{
|
||||
foreach (var eventLine in eventLines)
|
||||
{
|
||||
eventLine.Draw(eventLinesPositions[eventLine]);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Drag & Drop
|
||||
|
||||
public DragAndDropVisualMode dragAndDropVisualMode => DragAndDropVisualMode.Generic;
|
||||
|
||||
public bool AcceptsDragAndDrop()
|
||||
{
|
||||
return DragAndDropUtility.Is<ScriptGraphAsset>();
|
||||
}
|
||||
|
||||
public void PerformDragAndDrop()
|
||||
{
|
||||
UndoUtility.RecordEditedObject("Drag & Drop Macro");
|
||||
state.nest.source = GraphSource.Macro;
|
||||
state.nest.macro = DragAndDropUtility.Get<ScriptGraphAsset>();
|
||||
state.nest.embed = null;
|
||||
GUI.changed = true;
|
||||
}
|
||||
|
||||
public void UpdateDragAndDrop() { }
|
||||
|
||||
public void DrawDragAndDropPreview()
|
||||
{
|
||||
GraphGUI.DrawDragAndDropPreviewLabel(new Vector2(edgePosition.x, outerPosition.yMax), "Replace with: " + DragAndDropUtility.Get<ScriptGraphAsset>().name, typeof(ScriptGraphAsset).Icon());
|
||||
}
|
||||
|
||||
public void ExitDragAndDrop() { }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public new static class Styles
|
||||
{
|
||||
static Styles()
|
||||
{
|
||||
eventLine = new GUIStyle(EditorStyles.label);
|
||||
eventLine.wordWrap = true;
|
||||
eventLine.imagePosition = ImagePosition.TextOnly; // The icon is drawn manually
|
||||
eventLine.padding = new RectOffset(0, 0, 3, 3);
|
||||
}
|
||||
|
||||
public static readonly GUIStyle eventLine;
|
||||
|
||||
public static readonly float spaceAroundLineIcon = 5;
|
||||
}
|
||||
|
||||
public class EventLine
|
||||
{
|
||||
public EventLine(Type eventType)
|
||||
{
|
||||
content = new GUIContent(BoltFlowNameUtility.UnitTitle(eventType, false, true), eventType.Icon()?[IconSize.Small]);
|
||||
}
|
||||
|
||||
public GUIContent content { get; }
|
||||
|
||||
public float GetHeight(float width)
|
||||
{
|
||||
var labelWidth = width - Styles.spaceAroundLineIcon - IconSize.Small - Styles.spaceAroundLineIcon;
|
||||
|
||||
return Styles.eventLine.CalcHeight(content, labelWidth);
|
||||
}
|
||||
|
||||
public void Draw(Rect position)
|
||||
{
|
||||
var iconPosition = new Rect
|
||||
(
|
||||
position.x + Styles.spaceAroundLineIcon,
|
||||
position.y + Styles.eventLine.padding.top - 1,
|
||||
IconSize.Small,
|
||||
IconSize.Small
|
||||
);
|
||||
|
||||
var labelPosition = new Rect
|
||||
(
|
||||
iconPosition.xMax + Styles.spaceAroundLineIcon,
|
||||
position.y,
|
||||
position.width - Styles.spaceAroundLineIcon - iconPosition.width - Styles.spaceAroundLineIcon,
|
||||
position.height
|
||||
);
|
||||
|
||||
if (content.image != null)
|
||||
{
|
||||
GUI.DrawTexture(iconPosition, content.image);
|
||||
}
|
||||
|
||||
GUI.Label(labelPosition, content, Styles.eventLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public interface IStateWidget : IGraphElementWidget
|
||||
{
|
||||
IState state { get; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Analyser(typeof(INesterState))]
|
||||
public class NesterStateAnalyser<TNesterState> : StateAnalyser<TNesterState>
|
||||
where TNesterState : class, INesterState
|
||||
{
|
||||
public NesterStateAnalyser(GraphReference reference, TNesterState state) : base(reference, state) { }
|
||||
|
||||
protected override IEnumerable<Warning> Warnings()
|
||||
{
|
||||
foreach (var baseWarning in base.Warnings())
|
||||
{
|
||||
yield return baseWarning;
|
||||
}
|
||||
|
||||
if (state.childGraph == null)
|
||||
{
|
||||
yield return Warning.Caution("Missing nested graph.");
|
||||
}
|
||||
|
||||
if (state.nest.hasBackgroundEmbed)
|
||||
{
|
||||
yield return Warning.Caution("Background embed graph detected.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(INesterState))]
|
||||
public class NesterStateDescriptor<TNesterState> : StateDescriptor<TNesterState>
|
||||
where TNesterState : class, INesterState
|
||||
{
|
||||
public NesterStateDescriptor(TNesterState state) : base(state) { }
|
||||
|
||||
[RequiresUnityAPI]
|
||||
public override string Title()
|
||||
{
|
||||
return GraphNesterDescriptor.Title(state);
|
||||
}
|
||||
|
||||
[RequiresUnityAPI]
|
||||
public override string Summary()
|
||||
{
|
||||
return GraphNesterDescriptor.Summary(state);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Editor(typeof(INesterState))]
|
||||
public class NesterStateEditor : StateEditor
|
||||
{
|
||||
public NesterStateEditor(Metadata metadata) : base(metadata) { }
|
||||
|
||||
private Metadata nestMetadata => metadata[nameof(INesterState.nest)];
|
||||
|
||||
private Metadata graphMetadata => nestMetadata[nameof(IGraphNest.graph)];
|
||||
|
||||
protected override GraphReference headerReference => reference.ChildReference((INesterState)metadata.value, false);
|
||||
|
||||
protected override Metadata headerTitleMetadata => graphMetadata[nameof(IGraph.title)];
|
||||
|
||||
protected override Metadata headerSummaryMetadata => graphMetadata[nameof(IGraph.summary)];
|
||||
|
||||
protected override float GetInspectorHeight(float width)
|
||||
{
|
||||
return LudiqGUI.GetEditorHeight(this, nestMetadata, width);
|
||||
}
|
||||
|
||||
protected override void OnInspectorGUI(Rect position)
|
||||
{
|
||||
LudiqGUI.Editor(nestMetadata, position);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public abstract class NesterStateWidget<TNesterState> : StateWidget<TNesterState>
|
||||
where TNesterState : class, INesterState
|
||||
{
|
||||
protected NesterStateWidget(StateCanvas canvas, TNesterState state) : base(canvas, state) { }
|
||||
|
||||
protected override IEnumerable<DropdownOption> contextOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
var childReference = reference.ChildReference(state, false);
|
||||
|
||||
if (state.childGraph != null)
|
||||
{
|
||||
yield return new DropdownOption((Action)(() => window.reference = childReference), "Open");
|
||||
yield return new DropdownOption((Action)(() => GraphWindow.OpenTab(childReference)), "Open in new window");
|
||||
}
|
||||
|
||||
foreach (var baseOption in base.contextOptions)
|
||||
{
|
||||
yield return baseOption;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDoubleClick()
|
||||
{
|
||||
if (state.graph.zoom == 1)
|
||||
{
|
||||
var childReference = reference.ChildReference(state, false);
|
||||
|
||||
if (childReference != null)
|
||||
{
|
||||
if (e.ctrlOrCmd)
|
||||
{
|
||||
GraphWindow.OpenTab(childReference);
|
||||
}
|
||||
else
|
||||
{
|
||||
window.reference = childReference;
|
||||
}
|
||||
}
|
||||
|
||||
e.Use();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnDoubleClick();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Analyser(typeof(IState))]
|
||||
public class StateAnalyser<TState> : Analyser<TState, StateAnalysis>
|
||||
where TState : class, IState
|
||||
{
|
||||
public StateAnalyser(GraphReference reference, TState target) : base(reference, target) { }
|
||||
|
||||
public TState state => target;
|
||||
|
||||
[Assigns]
|
||||
protected virtual bool IsEntered()
|
||||
{
|
||||
using (var recursion = Recursion.New(1))
|
||||
{
|
||||
return IsEntered(state, recursion);
|
||||
}
|
||||
}
|
||||
|
||||
[Assigns]
|
||||
protected virtual IEnumerable<Warning> Warnings()
|
||||
{
|
||||
if (!IsEntered())
|
||||
{
|
||||
yield return Warning.Info("State is never entered.");
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsEntered(IState state, Recursion recursion)
|
||||
{
|
||||
if (state.isStart)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!recursion?.TryEnter(state) ?? false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var incomingTransition in state.incomingTransitions)
|
||||
{
|
||||
if (IsEntered(incomingTransition.source, recursion) && incomingTransition.Analysis<StateTransitionAnalysis>(context).isTraversed)
|
||||
{
|
||||
recursion?.Exit(state);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
recursion?.Exit(state);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public sealed class StateAnalysis : GraphElementAnalysis
|
||||
{
|
||||
public bool isEntered { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public sealed class StateDescription : GraphElementDescription
|
||||
{
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(IState))]
|
||||
public class StateDescriptor<TState> : Descriptor<TState, StateDescription>
|
||||
where TState : class, IState
|
||||
{
|
||||
public StateDescriptor(TState target) : base(target) { }
|
||||
|
||||
public TState state => target;
|
||||
|
||||
[Assigns]
|
||||
public override string Title()
|
||||
{
|
||||
return state.GetType().HumanName();
|
||||
}
|
||||
|
||||
[Assigns]
|
||||
public override string Summary()
|
||||
{
|
||||
return state.GetType().Summary();
|
||||
}
|
||||
|
||||
[Assigns]
|
||||
[RequiresUnityAPI]
|
||||
public override EditorTexture Icon()
|
||||
{
|
||||
return state.GetType().Icon();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Editor(typeof(IState))]
|
||||
public class StateEditor : GraphElementEditor<StateGraphContext>
|
||||
{
|
||||
public StateEditor(Metadata metadata) : base(metadata) { }
|
||||
|
||||
protected IState state => (IState)element;
|
||||
|
||||
protected new StateDescription description => (StateDescription)base.description;
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public sealed class StateTransitionAnalysis : GraphElementAnalysis
|
||||
{
|
||||
public bool isTraversed { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,632 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public abstract class StateWidget<TState> : NodeWidget<StateCanvas, TState>, IStateWidget
|
||||
where TState : class, IState
|
||||
{
|
||||
protected StateWidget(StateCanvas canvas, TState state) : base(canvas, state)
|
||||
{
|
||||
minResizeSize = new Vector2(State.DefaultWidth, 0);
|
||||
}
|
||||
|
||||
public virtual bool canForceEnter => true;
|
||||
|
||||
public virtual bool canForceExit => true;
|
||||
|
||||
public virtual bool canToggleStart => true;
|
||||
|
||||
|
||||
#region Model
|
||||
|
||||
protected TState state => element;
|
||||
|
||||
protected IStateDebugData stateDebugData => GetDebugData<IStateDebugData>();
|
||||
|
||||
protected State.Data stateData => reference.hasData ? reference.GetElementData<State.Data>(state) : null;
|
||||
|
||||
IState IStateWidget.state => state;
|
||||
|
||||
protected StateDescription description { get; private set; }
|
||||
|
||||
protected StateAnalysis analysis => state.Analysis<StateAnalysis>(context);
|
||||
|
||||
protected override void CacheDescription()
|
||||
{
|
||||
description = state.Description<StateDescription>();
|
||||
|
||||
title = description.title;
|
||||
summary = description.summary;
|
||||
|
||||
titleContent.text = " " + title;
|
||||
titleContent.image = description.icon?[IconSize.Small];
|
||||
summaryContent.text = summary;
|
||||
|
||||
Reposition();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Lifecycle
|
||||
|
||||
public override void BeforeFrame()
|
||||
{
|
||||
base.BeforeFrame();
|
||||
|
||||
if (currentContentOuterHeight != targetContentOuterHeight)
|
||||
{
|
||||
Reposition();
|
||||
}
|
||||
}
|
||||
|
||||
public override void HandleInput()
|
||||
{
|
||||
if (e.IsMouseDrag(MouseButton.Left) &&
|
||||
e.ctrlOrCmd &&
|
||||
!canvas.isCreatingTransition)
|
||||
{
|
||||
if (state.canBeSource)
|
||||
{
|
||||
canvas.StartTransition(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Cannot create a transition from this state.\n");
|
||||
}
|
||||
|
||||
e.Use();
|
||||
}
|
||||
else if (e.IsMouseDrag(MouseButton.Left) && canvas.isCreatingTransition)
|
||||
{
|
||||
e.Use();
|
||||
}
|
||||
else if (e.IsMouseUp(MouseButton.Left) && canvas.isCreatingTransition)
|
||||
{
|
||||
var source = canvas.transitionSource;
|
||||
var destination = (canvas.hoveredWidget as IStateWidget)?.state;
|
||||
|
||||
if (destination == null)
|
||||
{
|
||||
canvas.CompleteTransitionToNewState();
|
||||
}
|
||||
else if (destination == source)
|
||||
{
|
||||
canvas.CancelTransition();
|
||||
}
|
||||
else if (destination.canBeDestination)
|
||||
{
|
||||
canvas.EndTransition(destination);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Cannot create a transition to this state.\n");
|
||||
canvas.CancelTransition();
|
||||
}
|
||||
|
||||
e.Use();
|
||||
}
|
||||
|
||||
base.HandleInput();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Contents
|
||||
|
||||
protected virtual string title { get; set; }
|
||||
|
||||
protected virtual string summary { get; set; }
|
||||
|
||||
private GUIContent titleContent { get; } = new GUIContent();
|
||||
|
||||
private GUIContent summaryContent { get; } = new GUIContent();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Positioning
|
||||
|
||||
public override IEnumerable<IWidget> positionDependers => state.transitions.Select(transition => (IWidget)canvas.Widget(transition));
|
||||
|
||||
public Rect titlePosition { get; private set; }
|
||||
|
||||
public Rect summaryPosition { get; private set; }
|
||||
|
||||
public Rect contentOuterPosition { get; private set; }
|
||||
|
||||
public Rect contentBackgroundPosition { get; private set; }
|
||||
|
||||
public Rect contentInnerPosition { get; private set; }
|
||||
|
||||
private float targetContentOuterHeight;
|
||||
|
||||
private float currentContentOuterHeight;
|
||||
|
||||
private bool revealInitialized;
|
||||
|
||||
private Rect _position;
|
||||
|
||||
public override Rect position
|
||||
{
|
||||
get { return _position; }
|
||||
set
|
||||
{
|
||||
state.position = value.position;
|
||||
state.width = value.width;
|
||||
}
|
||||
}
|
||||
|
||||
public override void CachePosition()
|
||||
{
|
||||
var edgeOrigin = state.position;
|
||||
var edgeX = edgeOrigin.x;
|
||||
var edgeY = edgeOrigin.y;
|
||||
var edgeWidth = state.width;
|
||||
var innerOrigin = EdgeToInnerPosition(new Rect(edgeOrigin, Vector2.zero)).position;
|
||||
var innerX = innerOrigin.x;
|
||||
var innerY = innerOrigin.y;
|
||||
var innerWidth = EdgeToInnerPosition(new Rect(0, 0, edgeWidth, 0)).width;
|
||||
var innerHeight = 0f;
|
||||
|
||||
var y = innerY;
|
||||
|
||||
if (showTitle)
|
||||
{
|
||||
using (LudiqGUIUtility.iconSize.Override(IconSize.Small))
|
||||
{
|
||||
titlePosition = new Rect
|
||||
(
|
||||
innerX,
|
||||
y,
|
||||
innerWidth,
|
||||
Styles.title.CalcHeight(titleContent, innerWidth)
|
||||
);
|
||||
|
||||
y += titlePosition.height;
|
||||
innerHeight += titlePosition.height;
|
||||
}
|
||||
}
|
||||
|
||||
if (showTitle && showSummary)
|
||||
{
|
||||
y += Styles.spaceBetweenTitleAndSummary;
|
||||
innerHeight += Styles.spaceBetweenTitleAndSummary;
|
||||
}
|
||||
|
||||
if (showSummary)
|
||||
{
|
||||
summaryPosition = new Rect
|
||||
(
|
||||
innerX,
|
||||
y,
|
||||
innerWidth,
|
||||
Styles.summary.CalcHeight(summaryContent, innerWidth)
|
||||
);
|
||||
|
||||
y += summaryPosition.height;
|
||||
innerHeight += summaryPosition.height;
|
||||
}
|
||||
|
||||
if (showContent)
|
||||
{
|
||||
var contentInnerWidth = edgeWidth - Styles.contentBackground.padding.left - Styles.contentBackground.padding.right;
|
||||
|
||||
targetContentOuterHeight = revealContent ? (Styles.spaceBeforeContent + Styles.contentBackground.padding.top + GetContentHeight(contentInnerWidth) + Styles.contentBackground.padding.bottom) : 0;
|
||||
|
||||
if (!revealInitialized)
|
||||
{
|
||||
currentContentOuterHeight = targetContentOuterHeight;
|
||||
revealInitialized = true;
|
||||
}
|
||||
|
||||
currentContentOuterHeight = Mathf.Lerp(currentContentOuterHeight, targetContentOuterHeight, canvas.repaintDeltaTime * Styles.contentRevealSpeed);
|
||||
|
||||
if (Mathf.Abs(targetContentOuterHeight - currentContentOuterHeight) < 1)
|
||||
{
|
||||
currentContentOuterHeight = targetContentOuterHeight;
|
||||
}
|
||||
|
||||
contentOuterPosition = new Rect
|
||||
(
|
||||
edgeX,
|
||||
y,
|
||||
edgeWidth,
|
||||
currentContentOuterHeight
|
||||
);
|
||||
|
||||
contentBackgroundPosition = new Rect
|
||||
(
|
||||
0,
|
||||
Styles.spaceBeforeContent,
|
||||
edgeWidth,
|
||||
currentContentOuterHeight - Styles.spaceBeforeContent
|
||||
);
|
||||
|
||||
contentInnerPosition = new Rect
|
||||
(
|
||||
Styles.contentBackground.padding.left,
|
||||
Styles.spaceBeforeContent + Styles.contentBackground.padding.top,
|
||||
contentInnerWidth,
|
||||
contentBackgroundPosition.height - Styles.contentBackground.padding.top
|
||||
);
|
||||
|
||||
y += contentOuterPosition.height;
|
||||
innerHeight += contentOuterPosition.height;
|
||||
}
|
||||
|
||||
var edgeHeight = InnerToEdgePosition(new Rect(0, 0, 0, innerHeight)).height;
|
||||
|
||||
_position = new Rect
|
||||
(
|
||||
edgeX,
|
||||
edgeY,
|
||||
edgeWidth,
|
||||
edgeHeight
|
||||
);
|
||||
}
|
||||
|
||||
protected virtual float GetContentHeight(float width) => 0;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Drawing
|
||||
|
||||
protected virtual bool showTitle => true;
|
||||
|
||||
protected virtual bool showSummary => !StringUtility.IsNullOrWhiteSpace(summary);
|
||||
|
||||
protected virtual bool showContent => false;
|
||||
|
||||
protected virtual NodeColorMix baseColor => NodeColor.Gray;
|
||||
|
||||
protected override NodeColorMix color
|
||||
{
|
||||
get
|
||||
{
|
||||
if (stateDebugData.runtimeException != null)
|
||||
{
|
||||
return NodeColor.Red;
|
||||
}
|
||||
|
||||
var color = baseColor;
|
||||
|
||||
if (state.isStart)
|
||||
{
|
||||
color = NodeColor.Green;
|
||||
}
|
||||
|
||||
if (stateData?.isActive ?? false)
|
||||
{
|
||||
color = NodeColor.Blue;
|
||||
}
|
||||
else if (EditorApplication.isPaused)
|
||||
{
|
||||
if (EditorTimeBinding.frame == stateDebugData.lastEnterFrame)
|
||||
{
|
||||
color = NodeColor.Blue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
color.blue = Mathf.Lerp(1, 0, (EditorTimeBinding.time - stateDebugData.lastExitTime) / Styles.enterFadeDuration);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
protected override NodeShape shape => NodeShape.Square;
|
||||
|
||||
private bool revealContent
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (BoltState.Configuration.statesReveal)
|
||||
{
|
||||
case StateRevealCondition.Always:
|
||||
|
||||
return true;
|
||||
case StateRevealCondition.Never:
|
||||
|
||||
return false;
|
||||
case StateRevealCondition.OnHover:
|
||||
|
||||
return isMouseOver;
|
||||
case StateRevealCondition.OnHoverWithAlt:
|
||||
|
||||
return isMouseOver && e.alt;
|
||||
case StateRevealCondition.WhenSelected:
|
||||
|
||||
return selection.Contains(state);
|
||||
case StateRevealCondition.OnHoverOrSelected:
|
||||
|
||||
return isMouseOver || selection.Contains(state);
|
||||
case StateRevealCondition.OnHoverWithAltOrSelected:
|
||||
|
||||
return isMouseOver && e.alt || selection.Contains(state);
|
||||
default:
|
||||
|
||||
throw new UnexpectedEnumValueException<StateRevealCondition>(BoltState.Configuration.statesReveal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool revealedContent;
|
||||
|
||||
private void CheckReveal()
|
||||
{
|
||||
var revealContent = this.revealContent;
|
||||
|
||||
if (revealContent != revealedContent)
|
||||
{
|
||||
Reposition();
|
||||
}
|
||||
|
||||
revealedContent = revealContent;
|
||||
}
|
||||
|
||||
protected override bool dim
|
||||
{
|
||||
get
|
||||
{
|
||||
var dim = BoltCore.Configuration.dimInactiveNodes && !analysis.isEntered;
|
||||
|
||||
if (isMouseOver || isSelected)
|
||||
{
|
||||
dim = false;
|
||||
}
|
||||
|
||||
return dim;
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawForeground()
|
||||
{
|
||||
BeginDim();
|
||||
|
||||
base.DrawForeground();
|
||||
|
||||
if (showTitle)
|
||||
{
|
||||
DrawTitle();
|
||||
}
|
||||
|
||||
if (showSummary)
|
||||
{
|
||||
DrawSummary();
|
||||
}
|
||||
|
||||
if (showContent)
|
||||
{
|
||||
DrawContentWrapped();
|
||||
}
|
||||
|
||||
EndDim();
|
||||
|
||||
CheckReveal();
|
||||
}
|
||||
|
||||
private void DrawTitle()
|
||||
{
|
||||
using (LudiqGUIUtility.iconSize.Override(IconSize.Small))
|
||||
{
|
||||
GUI.Label(titlePosition, titleContent, invertForeground ? Styles.titleInverted : Styles.title);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSummary()
|
||||
{
|
||||
GUI.Label(summaryPosition, summaryContent, invertForeground ? Styles.summaryInverted : Styles.summary);
|
||||
}
|
||||
|
||||
private void DrawContentWrapped()
|
||||
{
|
||||
GUI.BeginClip(contentOuterPosition);
|
||||
|
||||
DrawContentBackground();
|
||||
|
||||
DrawContent();
|
||||
|
||||
GUI.EndClip();
|
||||
}
|
||||
|
||||
protected virtual void DrawContentBackground()
|
||||
{
|
||||
if (e.IsRepaint)
|
||||
{
|
||||
Styles.contentBackground.Draw(contentBackgroundPosition, false, false, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void DrawContent() { }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Selecting
|
||||
|
||||
public override bool canSelect => true;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Dragging
|
||||
|
||||
protected override bool snapToGrid => BoltCore.Configuration.snapToGrid;
|
||||
|
||||
public override bool canDrag => true;
|
||||
|
||||
public override void ExpandDragGroup(HashSet<IGraphElement> dragGroup)
|
||||
{
|
||||
if (BoltCore.Configuration.carryChildren)
|
||||
{
|
||||
foreach (var transition in state.outgoingTransitions)
|
||||
{
|
||||
if (dragGroup.Contains(transition.destination))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
dragGroup.Add(transition.destination);
|
||||
|
||||
canvas.Widget(transition.destination).ExpandDragGroup(dragGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Deleting
|
||||
|
||||
public override bool canDelete => true;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Resizing
|
||||
|
||||
public override bool canResizeHorizontal => true;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Clipboard
|
||||
|
||||
public override void ExpandCopyGroup(HashSet<IGraphElement> copyGroup)
|
||||
{
|
||||
copyGroup.UnionWith(state.transitions.Cast<IGraphElement>());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Actions
|
||||
|
||||
protected override IEnumerable<DropdownOption> contextOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Application.isPlaying && reference.hasData)
|
||||
{
|
||||
if (canForceEnter)
|
||||
{
|
||||
yield return new DropdownOption((Action)ForceEnter, "Force Enter");
|
||||
}
|
||||
|
||||
if (canForceExit)
|
||||
{
|
||||
yield return new DropdownOption((Action)ForceExit, "Force Exit");
|
||||
}
|
||||
}
|
||||
|
||||
if (canToggleStart)
|
||||
{
|
||||
yield return new DropdownOption((Action)ToggleStart, "Toggle Start");
|
||||
}
|
||||
|
||||
if (state.canBeSource)
|
||||
{
|
||||
yield return new DropdownOption((Action)MakeTransition, "Make Transition");
|
||||
}
|
||||
|
||||
if (state.canBeSource && state.canBeDestination)
|
||||
{
|
||||
yield return new DropdownOption((Action)MakeSelfTransition, "Make Self Transition");
|
||||
}
|
||||
|
||||
foreach (var baseOption in base.contextOptions)
|
||||
{
|
||||
yield return baseOption;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ForceEnter()
|
||||
{
|
||||
using (var flow = Flow.New(reference))
|
||||
{
|
||||
state.OnEnter(flow, StateEnterReason.Forced);
|
||||
}
|
||||
}
|
||||
|
||||
private void ForceExit()
|
||||
{
|
||||
using (var flow = Flow.New(reference))
|
||||
{
|
||||
state.OnExit(flow, StateExitReason.Forced);
|
||||
}
|
||||
}
|
||||
|
||||
protected void MakeTransition()
|
||||
{
|
||||
canvas.StartTransition(state);
|
||||
}
|
||||
|
||||
protected void MakeSelfTransition()
|
||||
{
|
||||
canvas.StartTransition(state);
|
||||
canvas.EndTransition(state);
|
||||
}
|
||||
|
||||
protected void ToggleStart()
|
||||
{
|
||||
UndoUtility.RecordEditedObject("Toggle State Start");
|
||||
|
||||
state.isStart = !state.isStart;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public static class Styles
|
||||
{
|
||||
static Styles()
|
||||
{
|
||||
title = new GUIStyle(BoltCore.Styles.nodeLabel);
|
||||
title.fontSize = 12;
|
||||
title.alignment = TextAnchor.MiddleCenter;
|
||||
title.wordWrap = true;
|
||||
|
||||
summary = new GUIStyle(BoltCore.Styles.nodeLabel);
|
||||
summary.fontSize = 10;
|
||||
summary.alignment = TextAnchor.MiddleCenter;
|
||||
summary.wordWrap = true;
|
||||
|
||||
titleInverted = new GUIStyle(title);
|
||||
titleInverted.normal.textColor = ColorPalette.unityBackgroundDark;
|
||||
|
||||
summaryInverted = new GUIStyle(summary);
|
||||
summaryInverted.normal.textColor = ColorPalette.unityBackgroundDark;
|
||||
|
||||
contentBackground = new GUIStyle("In BigTitle");
|
||||
contentBackground.padding = new RectOffset(0, 0, 4, 4);
|
||||
}
|
||||
|
||||
public static readonly GUIStyle title;
|
||||
|
||||
public static readonly GUIStyle summary;
|
||||
|
||||
public static readonly GUIStyle titleInverted;
|
||||
|
||||
public static readonly GUIStyle summaryInverted;
|
||||
|
||||
public static readonly GUIStyle contentBackground;
|
||||
|
||||
public static readonly float spaceBeforeContent = 5;
|
||||
|
||||
public static readonly float spaceBetweenTitleAndSummary = 0;
|
||||
|
||||
public static readonly float enterFadeDuration = 0.5f;
|
||||
|
||||
public static readonly float contentRevealSpeed = 15;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(SuperState))]
|
||||
public class SuperStateDescriptor : NesterStateDescriptor<SuperState>
|
||||
{
|
||||
public SuperStateDescriptor(SuperState state) : base(state) { }
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Editor(typeof(SuperState))]
|
||||
public sealed class SuperStateEditor : NesterStateEditor
|
||||
{
|
||||
public SuperStateEditor(Metadata metadata) : base(metadata) { }
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Widget(typeof(SuperState))]
|
||||
public sealed class SuperStateWidget : NesterStateWidget<SuperState>, IDragAndDropHandler
|
||||
{
|
||||
public SuperStateWidget(StateCanvas canvas, SuperState state) : base(canvas, state) { }
|
||||
|
||||
#region Drag & Drop
|
||||
|
||||
public DragAndDropVisualMode dragAndDropVisualMode => DragAndDropVisualMode.Generic;
|
||||
|
||||
public bool AcceptsDragAndDrop()
|
||||
{
|
||||
return DragAndDropUtility.Is<StateGraphAsset>();
|
||||
}
|
||||
|
||||
public void PerformDragAndDrop()
|
||||
{
|
||||
UndoUtility.RecordEditedObject("Drag & Drop Macro");
|
||||
state.nest.source = GraphSource.Macro;
|
||||
state.nest.macro = DragAndDropUtility.Get<StateGraphAsset>();
|
||||
state.nest.embed = null;
|
||||
GUI.changed = true;
|
||||
}
|
||||
|
||||
public void UpdateDragAndDrop()
|
||||
{
|
||||
}
|
||||
|
||||
public void DrawDragAndDropPreview()
|
||||
{
|
||||
GraphGUI.DrawDragAndDropPreviewLabel(new Vector2(edgePosition.x, outerPosition.yMax), "Replace with: " + DragAndDropUtility.Get<StateGraphAsset>().name, typeof(StateGraphAsset).Icon());
|
||||
}
|
||||
|
||||
public void ExitDragAndDrop()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Analyser(typeof(FlowStateTransition))]
|
||||
public class FlowStateTransitionAnalyser : NesterStateTransitionAnalyser<FlowStateTransition>
|
||||
{
|
||||
public FlowStateTransitionAnalyser(GraphReference reference, FlowStateTransition transition) : base(reference, transition) { }
|
||||
|
||||
protected override bool IsTraversed()
|
||||
{
|
||||
var graph = transition.nest.graph;
|
||||
|
||||
if (graph == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using (var recursion = Recursion.New(1))
|
||||
{
|
||||
foreach (var trigger in graph.GetUnitsRecursive(recursion).OfType<TriggerStateTransition>())
|
||||
{
|
||||
if (trigger.Analysis<UnitAnalysis>(context).isEntered)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override IEnumerable<Warning> Warnings()
|
||||
{
|
||||
foreach (var baseWarning in base.Warnings())
|
||||
{
|
||||
yield return baseWarning;
|
||||
}
|
||||
|
||||
var graph = transition.nest.graph;
|
||||
|
||||
if (graph == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
using (var recursion = Recursion.New(1))
|
||||
{
|
||||
if (!graph.GetUnitsRecursive(recursion).OfType<IEventUnit>().Any())
|
||||
{
|
||||
yield return Warning.Caution("Transition graph is missing an event.");
|
||||
}
|
||||
}
|
||||
|
||||
using (var recursion = Recursion.New(1))
|
||||
{
|
||||
if (!graph.GetUnitsRecursive(recursion).OfType<TriggerStateTransition>().Any())
|
||||
{
|
||||
yield return Warning.Caution("Transition graph is missing a trigger unit.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,106 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(FlowStateTransition))]
|
||||
public class FlowStateTransitionDescriptor : NesterStateTransitionDescriptor<FlowStateTransition>
|
||||
{
|
||||
public FlowStateTransitionDescriptor(FlowStateTransition transition) : base(transition) { }
|
||||
|
||||
public override string Title()
|
||||
{
|
||||
var graph = transition.nest.graph;
|
||||
|
||||
if (graph != null)
|
||||
{
|
||||
if (!StringUtility.IsNullOrWhiteSpace(graph.title))
|
||||
{
|
||||
return graph.title;
|
||||
}
|
||||
|
||||
using (var recursion = Recursion.New(1))
|
||||
{
|
||||
var events = graph.GetUnitsRecursive(recursion).OfType<IEventUnit>().ToList();
|
||||
|
||||
if (events.Count == 0)
|
||||
{
|
||||
return "(No Event)";
|
||||
}
|
||||
else if (events.Count == 1)
|
||||
{
|
||||
return events[0].Description().title;
|
||||
}
|
||||
else // if (events.Count > 1)
|
||||
{
|
||||
return "(Multiple Events)";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return "(No Transition)";
|
||||
}
|
||||
}
|
||||
|
||||
public override string Summary()
|
||||
{
|
||||
var graph = transition.nest.graph;
|
||||
|
||||
if (graph != null)
|
||||
{
|
||||
if (!StringUtility.IsNullOrWhiteSpace(graph.summary))
|
||||
{
|
||||
return graph.summary;
|
||||
}
|
||||
|
||||
using (var recursion = Recursion.New(1))
|
||||
{
|
||||
var events = graph.GetUnitsRecursive(recursion).OfType<IEventUnit>().ToList();
|
||||
|
||||
if (events.Count == 0)
|
||||
{
|
||||
return "Open the transition graph to add an event.";
|
||||
}
|
||||
else if (events.Count == 1)
|
||||
{
|
||||
return events[0].Description().summary;
|
||||
}
|
||||
else // if (events.Count > 1)
|
||||
{
|
||||
return "Open the transition graph to see the full transition.";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Choose a source in the graph inspector.";
|
||||
}
|
||||
}
|
||||
|
||||
public override EditorTexture Icon()
|
||||
{
|
||||
var graph = transition.nest.graph;
|
||||
|
||||
using (var recursion = Recursion.New(1))
|
||||
{
|
||||
if (graph != null)
|
||||
{
|
||||
var events = graph.GetUnitsRecursive(recursion).OfType<IEventUnit>().ToList();
|
||||
|
||||
if (events.Count == 1)
|
||||
{
|
||||
return events[0].Description().icon;
|
||||
}
|
||||
else
|
||||
{
|
||||
return typeof(IStateTransition).Icon();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return typeof(IStateTransition).Icon();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Editor(typeof(FlowStateTransition))]
|
||||
public sealed class FlowStateTransitionEditor : NesterStateTransitionEditor
|
||||
{
|
||||
public FlowStateTransitionEditor(Metadata metadata) : base(metadata) { }
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Widget(typeof(FlowStateTransition))]
|
||||
public sealed class FlowStateTransitionWidget : NesterStateTransitionWidget<FlowStateTransition>, IDragAndDropHandler
|
||||
{
|
||||
public FlowStateTransitionWidget(StateCanvas canvas, FlowStateTransition transition) : base(canvas, transition) { }
|
||||
|
||||
#region Drag & Drop
|
||||
|
||||
public DragAndDropVisualMode dragAndDropVisualMode => DragAndDropVisualMode.Generic;
|
||||
|
||||
public bool AcceptsDragAndDrop()
|
||||
{
|
||||
return DragAndDropUtility.Is<ScriptGraphAsset>();
|
||||
}
|
||||
|
||||
public void PerformDragAndDrop()
|
||||
{
|
||||
UndoUtility.RecordEditedObject("Drag & Drop Macro");
|
||||
transition.nest.source = GraphSource.Macro;
|
||||
transition.nest.macro = DragAndDropUtility.Get<ScriptGraphAsset>();
|
||||
transition.nest.embed = null;
|
||||
GUI.changed = true;
|
||||
}
|
||||
|
||||
public void UpdateDragAndDrop()
|
||||
{
|
||||
}
|
||||
|
||||
public void DrawDragAndDropPreview()
|
||||
{
|
||||
GraphGUI.DrawDragAndDropPreviewLabel(new Vector2(edgePosition.x, outerPosition.yMax), "Replace with: " + DragAndDropUtility.Get<ScriptGraphAsset>().name, typeof(ScriptGraphAsset).Icon());
|
||||
}
|
||||
|
||||
public void ExitDragAndDrop()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public interface IStateTransitionWidget : INodeWidget
|
||||
{
|
||||
Edge sourceEdge { get; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Analyser(typeof(INesterStateTransition))]
|
||||
public class NesterStateTransitionAnalyser<TGraphNesterStateTransition> : StateTransitionAnalyser<TGraphNesterStateTransition>
|
||||
where TGraphNesterStateTransition : class, INesterStateTransition
|
||||
{
|
||||
public NesterStateTransitionAnalyser(GraphReference reference, TGraphNesterStateTransition transition) : base(reference, transition) { }
|
||||
|
||||
protected override IEnumerable<Warning> Warnings()
|
||||
{
|
||||
foreach (var baseWarning in base.Warnings())
|
||||
{
|
||||
yield return baseWarning;
|
||||
}
|
||||
|
||||
if (transition.childGraph == null)
|
||||
{
|
||||
yield return Warning.Caution("Missing transition graph.");
|
||||
}
|
||||
|
||||
if (transition.nest.hasBackgroundEmbed)
|
||||
{
|
||||
yield return Warning.Caution("Background embed graph detected.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(INesterStateTransition))]
|
||||
public class NesterStateTransitionDescriptor<TNesterStateTransition> : StateTransitionDescriptor<TNesterStateTransition>
|
||||
where TNesterStateTransition : class, INesterStateTransition
|
||||
{
|
||||
public NesterStateTransitionDescriptor(TNesterStateTransition transition) : base(transition) { }
|
||||
|
||||
[RequiresUnityAPI]
|
||||
public override string Title()
|
||||
{
|
||||
return GraphNesterDescriptor.Title(transition);
|
||||
}
|
||||
|
||||
[RequiresUnityAPI]
|
||||
public override string Summary()
|
||||
{
|
||||
return GraphNesterDescriptor.Summary(transition);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Editor(typeof(INesterStateTransition))]
|
||||
public class NesterStateTransitionEditor : StateTransitionEditor
|
||||
{
|
||||
public NesterStateTransitionEditor(Metadata metadata) : base(metadata) { }
|
||||
|
||||
private Metadata nestMetadata => metadata[nameof(INesterStateTransition.nest)];
|
||||
|
||||
private Metadata graphMetadata => nestMetadata[nameof(IGraphNest.graph)];
|
||||
|
||||
protected override GraphReference headerReference => reference.ChildReference((INesterStateTransition)metadata.value, false);
|
||||
|
||||
protected override Metadata headerTitleMetadata => graphMetadata[nameof(IGraph.title)];
|
||||
|
||||
protected override Metadata headerSummaryMetadata => graphMetadata[nameof(IGraph.summary)];
|
||||
|
||||
protected override float GetInspectorHeight(float width)
|
||||
{
|
||||
return LudiqGUI.GetEditorHeight(this, nestMetadata, width);
|
||||
}
|
||||
|
||||
protected override void OnInspectorGUI(Rect position)
|
||||
{
|
||||
LudiqGUI.Editor(nestMetadata, position);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public abstract class NesterStateTransitionWidget<TNesterStateTransition> : StateTransitionWidget<TNesterStateTransition>
|
||||
where TNesterStateTransition : class, INesterStateTransition
|
||||
{
|
||||
protected NesterStateTransitionWidget(StateCanvas canvas, TNesterStateTransition transition) : base(canvas, transition) { }
|
||||
|
||||
protected override IEnumerable<DropdownOption> contextOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
var childReference = reference.ChildReference(transition, false);
|
||||
|
||||
if (childReference != null)
|
||||
{
|
||||
yield return new DropdownOption((Action)(() => window.reference = childReference), "Open");
|
||||
yield return new DropdownOption((Action)(() => GraphWindow.OpenTab(childReference)), "Open in new window");
|
||||
}
|
||||
|
||||
foreach (var baseOption in base.contextOptions)
|
||||
{
|
||||
yield return baseOption;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDoubleClick()
|
||||
{
|
||||
if (transition.graph.zoom == 1)
|
||||
{
|
||||
var childReference = reference.ChildReference(transition, false);
|
||||
|
||||
if (childReference != null)
|
||||
{
|
||||
if (e.ctrlOrCmd)
|
||||
{
|
||||
GraphWindow.OpenTab(childReference);
|
||||
}
|
||||
else
|
||||
{
|
||||
window.reference = childReference;
|
||||
}
|
||||
}
|
||||
|
||||
e.Use();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnDoubleClick();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public abstract class StateTransitionAnalyser<TStateTransition> : Analyser<TStateTransition, StateTransitionAnalysis>
|
||||
where TStateTransition : IStateTransition
|
||||
{
|
||||
protected StateTransitionAnalyser(GraphReference reference, TStateTransition target) : base(reference, target) { }
|
||||
|
||||
public TStateTransition transition => target;
|
||||
|
||||
[Assigns]
|
||||
protected virtual bool IsTraversed()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
[Assigns]
|
||||
protected virtual IEnumerable<Warning> Warnings()
|
||||
{
|
||||
if (!IsTraversed())
|
||||
{
|
||||
yield return Warning.Info("Transition is never traversed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public sealed class StateTransitionDescription : GraphElementDescription
|
||||
{
|
||||
public string label { get; set; }
|
||||
public string tooltip { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public abstract class StateTransitionDescriptor<TStateTransition> : Descriptor<TStateTransition, StateTransitionDescription>
|
||||
where TStateTransition : class, IStateTransition
|
||||
{
|
||||
protected StateTransitionDescriptor(TStateTransition target) : base(target) { }
|
||||
|
||||
public TStateTransition transition => target;
|
||||
|
||||
[Assigns]
|
||||
public override string Title()
|
||||
{
|
||||
return "Transition";
|
||||
}
|
||||
|
||||
[Assigns]
|
||||
public override string Summary()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
[Assigns]
|
||||
public virtual string Label()
|
||||
{
|
||||
return Title();
|
||||
}
|
||||
|
||||
[Assigns]
|
||||
public virtual string Tooltip()
|
||||
{
|
||||
return Summary();
|
||||
}
|
||||
|
||||
[Assigns]
|
||||
[RequiresUnityAPI]
|
||||
public override EditorTexture Icon()
|
||||
{
|
||||
return typeof(IStateTransition).Icon();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Editor(typeof(IStateTransition))]
|
||||
public class StateTransitionEditor : GraphElementEditor<StateGraphContext>
|
||||
{
|
||||
public StateTransitionEditor(Metadata metadata) : base(metadata) { }
|
||||
|
||||
private IStateTransition transition => (IStateTransition)element;
|
||||
|
||||
protected new StateTransitionDescription description => (StateTransitionDescription)base.description;
|
||||
}
|
||||
}
|
@@ -0,0 +1,692 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public abstract class StateTransitionWidget<TStateTransition> : NodeWidget<StateCanvas, TStateTransition>, IStateTransitionWidget
|
||||
where TStateTransition : class, IStateTransition
|
||||
{
|
||||
protected StateTransitionWidget(StateCanvas canvas, TStateTransition transition) : base(canvas, transition) { }
|
||||
|
||||
|
||||
#region Model
|
||||
|
||||
protected TStateTransition transition => element;
|
||||
|
||||
protected IStateTransitionDebugData transitionDebugData => GetDebugData<IStateTransitionDebugData>();
|
||||
|
||||
private StateTransitionDescription description;
|
||||
|
||||
private StateTransitionAnalysis analysis => transition.Analysis<StateTransitionAnalysis>(context);
|
||||
|
||||
protected override void CacheDescription()
|
||||
{
|
||||
description = transition.Description<StateTransitionDescription>();
|
||||
|
||||
label.text = description.label;
|
||||
label.image = description.icon?[IconSize.Small];
|
||||
label.tooltip = description.tooltip;
|
||||
|
||||
if (!revealLabel)
|
||||
{
|
||||
label.tooltip = label.text + ": " + label.tooltip;
|
||||
}
|
||||
|
||||
Reposition();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lifecycle
|
||||
|
||||
public override void BeforeFrame()
|
||||
{
|
||||
base.BeforeFrame();
|
||||
|
||||
if (showDroplets)
|
||||
{
|
||||
GraphGUI.UpdateDroplets(canvas, droplets, transitionDebugData.lastBranchFrame, ref lastBranchTime, ref dropTime);
|
||||
}
|
||||
|
||||
if (currentInnerWidth != targetInnerWidth)
|
||||
{
|
||||
Reposition();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Contents
|
||||
|
||||
private GUIContent label { get; } = new GUIContent();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Positioning
|
||||
|
||||
private readonly List<IStateTransition> siblingStateTransitions = new List<IStateTransition>();
|
||||
|
||||
private Rect sourcePosition;
|
||||
|
||||
private Rect destinationPosition;
|
||||
|
||||
private Edge sourceEdge;
|
||||
|
||||
private Edge entryEdge;
|
||||
|
||||
private Edge exitEdge;
|
||||
|
||||
private Edge destinationEdge;
|
||||
|
||||
private Vector2 sourceEdgeCenter;
|
||||
|
||||
private Vector2 entryEdgeCenter;
|
||||
|
||||
private Vector2 exitEdgeCenter;
|
||||
|
||||
private Vector2 destinationEdgeCenter;
|
||||
|
||||
private Vector2 middle;
|
||||
|
||||
private Rect _position;
|
||||
|
||||
private Rect _clippingPosition;
|
||||
|
||||
private float targetInnerWidth;
|
||||
|
||||
private float currentInnerWidth;
|
||||
|
||||
private bool revealInitialized;
|
||||
|
||||
private float minBend
|
||||
{
|
||||
get
|
||||
{
|
||||
if (transition.source != transition.destination)
|
||||
{
|
||||
return 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (middle.y - canvas.Widget(transition.source).position.center.y) / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float relativeBend => 1 / 4f;
|
||||
|
||||
Edge IStateTransitionWidget.sourceEdge => sourceEdge;
|
||||
|
||||
public override IEnumerable<IWidget> positionDependencies
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return canvas.Widget(transition.source);
|
||||
yield return canvas.Widget(transition.destination);
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<IWidget> positionDependers
|
||||
{
|
||||
get
|
||||
{
|
||||
// Return all sibling transitions. This is an asymetrical dependency / depender
|
||||
// relation (because the siblings are not included in the dependers) to force
|
||||
// repositioning of siblings while avoiding stack overflow.
|
||||
|
||||
foreach (var graphTransition in canvas.graph.transitions)
|
||||
{
|
||||
var current = transition == graphTransition;
|
||||
|
||||
var analog =
|
||||
transition.source == graphTransition.source &&
|
||||
transition.destination == graphTransition.destination;
|
||||
|
||||
var inverted =
|
||||
transition.source == graphTransition.destination &&
|
||||
transition.destination == graphTransition.source;
|
||||
|
||||
if (!current && (analog || inverted))
|
||||
{
|
||||
var widget = canvas.Widget(graphTransition);
|
||||
|
||||
if (widget.isPositionValid) // Avoid stack overflow
|
||||
{
|
||||
yield return widget;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Rect iconPosition { get; private set; }
|
||||
|
||||
public Rect clipPosition { get; private set; }
|
||||
|
||||
public Rect labelInnerPosition { get; private set; }
|
||||
|
||||
public override Rect position
|
||||
{
|
||||
get { return _position; }
|
||||
set { }
|
||||
}
|
||||
|
||||
public override Rect clippingPosition => _clippingPosition;
|
||||
|
||||
public override void CachePositionFirstPass()
|
||||
{
|
||||
// Calculate the size immediately, because other transitions will rely on it for positioning
|
||||
|
||||
targetInnerWidth = Styles.eventIcon.fixedWidth;
|
||||
|
||||
var labelWidth = Styles.label.CalcSize(label).x;
|
||||
var labelHeight = EditorGUIUtility.singleLineHeight;
|
||||
|
||||
if (revealLabel)
|
||||
{
|
||||
targetInnerWidth += Styles.spaceAroundIcon;
|
||||
targetInnerWidth += labelWidth;
|
||||
}
|
||||
|
||||
if (!revealInitialized)
|
||||
{
|
||||
currentInnerWidth = targetInnerWidth;
|
||||
revealInitialized = true;
|
||||
}
|
||||
|
||||
currentInnerWidth = Mathf.Lerp(currentInnerWidth, targetInnerWidth, canvas.repaintDeltaTime * Styles.revealSpeed);
|
||||
|
||||
if (Mathf.Abs(targetInnerWidth - currentInnerWidth) < 1)
|
||||
{
|
||||
currentInnerWidth = targetInnerWidth;
|
||||
}
|
||||
|
||||
var innerWidth = currentInnerWidth;
|
||||
var innerHeight = labelHeight;
|
||||
|
||||
var edgeSize = InnerToEdgePosition(new Rect(0, 0, innerWidth, innerHeight)).size;
|
||||
var edgeWidth = edgeSize.x;
|
||||
var edgeHeight = edgeSize.y;
|
||||
|
||||
_position.width = edgeWidth;
|
||||
_position.height = edgeHeight;
|
||||
}
|
||||
|
||||
public override void CachePosition()
|
||||
{
|
||||
var innerWidth = innerPosition.width;
|
||||
var innerHeight = innerPosition.height;
|
||||
var edgeWidth = edgePosition.width;
|
||||
var edgeHeight = edgePosition.height;
|
||||
var labelWidth = Styles.label.CalcSize(label).x;
|
||||
var labelHeight = EditorGUIUtility.singleLineHeight;
|
||||
|
||||
sourcePosition = canvas.Widget(transition.source).position;
|
||||
destinationPosition = canvas.Widget(transition.destination).position;
|
||||
|
||||
Vector2 sourceClosestPoint;
|
||||
Vector2 destinationClosestPoint;
|
||||
LudiqGUIUtility.ClosestPoints(sourcePosition, destinationPosition, out sourceClosestPoint, out destinationClosestPoint);
|
||||
|
||||
if (transition.destination != transition.source)
|
||||
{
|
||||
GraphGUI.GetConnectionEdge
|
||||
(
|
||||
sourceClosestPoint,
|
||||
destinationClosestPoint,
|
||||
out sourceEdge,
|
||||
out destinationEdge
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceEdge = Edge.Right;
|
||||
destinationEdge = Edge.Left;
|
||||
}
|
||||
|
||||
sourceEdgeCenter = sourcePosition.GetEdgeCenter(sourceEdge);
|
||||
destinationEdgeCenter = destinationPosition.GetEdgeCenter(destinationEdge);
|
||||
|
||||
siblingStateTransitions.Clear();
|
||||
|
||||
var siblingIndex = 0;
|
||||
|
||||
// Assign one common axis for transition for all siblings,
|
||||
// regardless of their inversion. The axis is arbitrarily
|
||||
// chosen as the axis for the first transition.
|
||||
var assignedTransitionAxis = false;
|
||||
var transitionAxis = Vector2.zero;
|
||||
|
||||
foreach (var graphTransition in canvas.graph.transitions)
|
||||
{
|
||||
var current = transition == graphTransition;
|
||||
|
||||
var analog =
|
||||
transition.source == graphTransition.source &&
|
||||
transition.destination == graphTransition.destination;
|
||||
|
||||
var inverted =
|
||||
transition.source == graphTransition.destination &&
|
||||
transition.destination == graphTransition.source;
|
||||
|
||||
if (current)
|
||||
{
|
||||
siblingIndex = siblingStateTransitions.Count;
|
||||
}
|
||||
|
||||
if (current || analog || inverted)
|
||||
{
|
||||
if (!assignedTransitionAxis)
|
||||
{
|
||||
var siblingStateTransitionDrawer = canvas.Widget<IStateTransitionWidget>(graphTransition);
|
||||
|
||||
transitionAxis = siblingStateTransitionDrawer.sourceEdge.Normal();
|
||||
|
||||
assignedTransitionAxis = true;
|
||||
}
|
||||
|
||||
siblingStateTransitions.Add(graphTransition);
|
||||
}
|
||||
}
|
||||
|
||||
// Fix the edge case where the source and destination perfectly overlap
|
||||
|
||||
if (transitionAxis == Vector2.zero)
|
||||
{
|
||||
transitionAxis = Vector2.right;
|
||||
}
|
||||
|
||||
// Calculate the spread axis and origin for the set of siblings
|
||||
|
||||
var spreadAxis = transitionAxis.Perpendicular1().Abs();
|
||||
var spreadOrigin = (sourceEdgeCenter + destinationEdgeCenter) / 2;
|
||||
|
||||
if (transition.source == transition.destination)
|
||||
{
|
||||
spreadAxis = Vector2.up;
|
||||
spreadOrigin = sourcePosition.GetEdgeCenter(Edge.Bottom) - Vector2.down * 10;
|
||||
}
|
||||
|
||||
if (BoltCore.Configuration.developerMode && BoltCore.Configuration.debug)
|
||||
{
|
||||
Handles.BeginGUI();
|
||||
Handles.color = Color.yellow;
|
||||
Handles.DrawLine(spreadOrigin + spreadAxis * -1000, spreadOrigin + spreadAxis * 1000);
|
||||
Handles.EndGUI();
|
||||
}
|
||||
|
||||
// Calculate the offset of the current sibling by iterating over its predecessors
|
||||
|
||||
var spreadOffset = 0f;
|
||||
var previousSpreadSize = 0f;
|
||||
|
||||
for (var i = 0; i <= siblingIndex; i++)
|
||||
{
|
||||
var siblingSize = canvas.Widget<IStateTransitionWidget>(siblingStateTransitions[i]).outerPosition.size;
|
||||
var siblingSizeProjection = GraphGUI.SizeProjection(siblingSize, spreadOrigin, spreadAxis);
|
||||
spreadOffset += previousSpreadSize / 2 + siblingSizeProjection / 2;
|
||||
previousSpreadSize = siblingSizeProjection;
|
||||
}
|
||||
|
||||
if (transition.source != transition.destination)
|
||||
{
|
||||
// Calculate the total spread size to center the sibling set
|
||||
|
||||
var totalSpreadSize = 0f;
|
||||
|
||||
for (var i = 0; i < siblingStateTransitions.Count; i++)
|
||||
{
|
||||
var siblingSize = canvas.Widget<IStateTransitionWidget>(siblingStateTransitions[i]).outerPosition.size;
|
||||
var siblingSizeProjection = GraphGUI.SizeProjection(siblingSize, spreadOrigin, spreadAxis);
|
||||
totalSpreadSize += siblingSizeProjection;
|
||||
}
|
||||
|
||||
spreadOffset -= totalSpreadSize / 2;
|
||||
}
|
||||
|
||||
// Finally, calculate the positions
|
||||
|
||||
middle = spreadOrigin + spreadOffset * spreadAxis;
|
||||
|
||||
var edgeX = middle.x - edgeWidth / 2;
|
||||
var edgeY = middle.y - edgeHeight / 2;
|
||||
|
||||
_position = new Rect
|
||||
(
|
||||
edgeX,
|
||||
edgeY,
|
||||
edgeWidth,
|
||||
edgeHeight
|
||||
).PixelPerfect();
|
||||
|
||||
var innerX = innerPosition.x;
|
||||
var innerY = innerPosition.y;
|
||||
|
||||
_clippingPosition = _position.Encompass(sourceEdgeCenter).Encompass(destinationEdgeCenter);
|
||||
|
||||
if (transition.source != transition.destination)
|
||||
{
|
||||
entryEdge = destinationEdge;
|
||||
exitEdge = sourceEdge;
|
||||
}
|
||||
else
|
||||
{
|
||||
entryEdge = sourceEdge;
|
||||
exitEdge = destinationEdge;
|
||||
}
|
||||
|
||||
entryEdgeCenter = edgePosition.GetEdgeCenter(entryEdge);
|
||||
exitEdgeCenter = edgePosition.GetEdgeCenter(exitEdge);
|
||||
|
||||
var x = innerX;
|
||||
|
||||
iconPosition = new Rect
|
||||
(
|
||||
x,
|
||||
innerY,
|
||||
Styles.eventIcon.fixedWidth,
|
||||
Styles.eventIcon.fixedHeight
|
||||
).PixelPerfect();
|
||||
|
||||
x += iconPosition.width;
|
||||
|
||||
var clipWidth = innerWidth - (x - innerX);
|
||||
|
||||
clipPosition = new Rect
|
||||
(
|
||||
x,
|
||||
edgeY,
|
||||
clipWidth,
|
||||
edgeHeight
|
||||
).PixelPerfect();
|
||||
|
||||
labelInnerPosition = new Rect
|
||||
(
|
||||
Styles.spaceAroundIcon,
|
||||
innerY - edgeY,
|
||||
labelWidth,
|
||||
labelHeight
|
||||
).PixelPerfect();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Drawing
|
||||
|
||||
protected virtual NodeColorMix baseColor => NodeColor.Gray;
|
||||
|
||||
protected override NodeColorMix color
|
||||
{
|
||||
get
|
||||
{
|
||||
if (transitionDebugData.runtimeException != null)
|
||||
{
|
||||
return NodeColor.Red;
|
||||
}
|
||||
|
||||
var color = baseColor;
|
||||
|
||||
if (analysis.warnings.Count > 0)
|
||||
{
|
||||
var mostSevereWarning = Warning.MostSevereLevel(analysis.warnings);
|
||||
|
||||
switch (mostSevereWarning)
|
||||
{
|
||||
case WarningLevel.Error:
|
||||
color = NodeColor.Red;
|
||||
|
||||
break;
|
||||
|
||||
case WarningLevel.Severe:
|
||||
color = NodeColor.Orange;
|
||||
|
||||
break;
|
||||
|
||||
case WarningLevel.Caution:
|
||||
color = NodeColor.Yellow;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
{
|
||||
if (EditorApplication.isPaused)
|
||||
{
|
||||
if (EditorTimeBinding.frame == transitionDebugData.lastBranchFrame)
|
||||
{
|
||||
color = NodeColor.Blue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
color.blue = Mathf.Lerp(1, 0, (EditorTimeBinding.time - transitionDebugData.lastBranchTime) / StateWidget<IState>.Styles.enterFadeDuration);
|
||||
}
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
protected override NodeShape shape => NodeShape.Hex;
|
||||
|
||||
private bool revealLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (BoltState.Configuration.transitionsReveal)
|
||||
{
|
||||
case StateRevealCondition.Always:
|
||||
|
||||
return true;
|
||||
case StateRevealCondition.Never:
|
||||
|
||||
return false;
|
||||
case StateRevealCondition.OnHover:
|
||||
|
||||
return isMouseOver;
|
||||
case StateRevealCondition.OnHoverWithAlt:
|
||||
|
||||
return isMouseOver && e.alt;
|
||||
case StateRevealCondition.WhenSelected:
|
||||
|
||||
return selection.Contains(transition);
|
||||
case StateRevealCondition.OnHoverOrSelected:
|
||||
|
||||
return isMouseOver || selection.Contains(transition);
|
||||
case StateRevealCondition.OnHoverWithAltOrSelected:
|
||||
|
||||
return isMouseOver && e.alt || selection.Contains(transition);
|
||||
default:
|
||||
|
||||
throw new UnexpectedEnumValueException<StateRevealCondition>(BoltState.Configuration.transitionsReveal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool revealedLabel;
|
||||
|
||||
private void CheckReveal()
|
||||
{
|
||||
var revealLabel = this.revealLabel;
|
||||
|
||||
if (revealLabel != revealedLabel)
|
||||
{
|
||||
Reposition();
|
||||
}
|
||||
|
||||
revealedLabel = revealLabel;
|
||||
}
|
||||
|
||||
protected override bool dim
|
||||
{
|
||||
get
|
||||
{
|
||||
var dim = BoltCore.Configuration.dimInactiveNodes && !(transition.source.Analysis<StateAnalysis>(context).isEntered && analysis.isTraversed);
|
||||
|
||||
if (isMouseOver || isSelected)
|
||||
{
|
||||
dim = false;
|
||||
}
|
||||
|
||||
return dim;
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawForeground()
|
||||
{
|
||||
BeginDim();
|
||||
|
||||
base.DrawForeground();
|
||||
|
||||
GUI.Label(iconPosition, label, Styles.eventIcon);
|
||||
|
||||
GUI.BeginClip(clipPosition);
|
||||
|
||||
GUI.Label(labelInnerPosition, label, invertForeground ? Styles.labelInverted : Styles.label);
|
||||
|
||||
GUI.EndClip();
|
||||
|
||||
EndDim();
|
||||
|
||||
CheckReveal();
|
||||
}
|
||||
|
||||
public override void DrawBackground()
|
||||
{
|
||||
BeginDim();
|
||||
|
||||
base.DrawBackground();
|
||||
|
||||
DrawConnection();
|
||||
|
||||
if (showDroplets)
|
||||
{
|
||||
DrawDroplets();
|
||||
}
|
||||
|
||||
EndDim();
|
||||
}
|
||||
|
||||
private void DrawConnection()
|
||||
{
|
||||
GraphGUI.DrawConnectionArrow(Color.white, sourceEdgeCenter, entryEdgeCenter, sourceEdge, entryEdge, relativeBend, minBend);
|
||||
|
||||
if (BoltState.Configuration.transitionsEndArrow)
|
||||
{
|
||||
GraphGUI.DrawConnectionArrow(Color.white, exitEdgeCenter, destinationEdgeCenter, exitEdge, destinationEdge, relativeBend, minBend);
|
||||
}
|
||||
else
|
||||
{
|
||||
GraphGUI.DrawConnection(Color.white, exitEdgeCenter, destinationEdgeCenter, exitEdge, destinationEdge, null, Vector2.zero, relativeBend, minBend);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Selecting
|
||||
|
||||
public override bool canSelect => true;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Dragging
|
||||
|
||||
public override bool canDrag => false;
|
||||
|
||||
protected override bool snapToGrid => false;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Deleting
|
||||
|
||||
public override bool canDelete => true;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Droplets
|
||||
|
||||
private readonly List<float> droplets = new List<float>();
|
||||
|
||||
private float dropTime;
|
||||
|
||||
private float lastBranchTime;
|
||||
|
||||
protected virtual bool showDroplets => BoltState.Configuration.animateTransitions;
|
||||
|
||||
protected virtual Vector2 GetDropletSize()
|
||||
{
|
||||
return BoltFlow.Icons.valuePortConnected?[12].Size() ?? 12 * Vector2.one;
|
||||
}
|
||||
|
||||
protected virtual void DrawDroplet(Rect position)
|
||||
{
|
||||
GUI.DrawTexture(position, BoltFlow.Icons.valuePortConnected?[12]);
|
||||
}
|
||||
|
||||
private void DrawDroplets()
|
||||
{
|
||||
foreach (var droplet in droplets)
|
||||
{
|
||||
Vector2 position;
|
||||
|
||||
if (droplet < 0.5f)
|
||||
{
|
||||
var t = droplet / 0.5f;
|
||||
position = GraphGUI.GetPointOnConnection(t, sourceEdgeCenter, entryEdgeCenter, sourceEdge, entryEdge, relativeBend, minBend);
|
||||
}
|
||||
else
|
||||
{
|
||||
var t = (droplet - 0.5f) / 0.5f;
|
||||
position = GraphGUI.GetPointOnConnection(t, exitEdgeCenter, destinationEdgeCenter, exitEdge, destinationEdge, relativeBend, minBend);
|
||||
}
|
||||
|
||||
var size = GetDropletSize();
|
||||
|
||||
using (LudiqGUI.color.Override(Color.white))
|
||||
{
|
||||
DrawDroplet(new Rect(position.x - size.x / 2, position.y - size.y / 2, size.x, size.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public static class Styles
|
||||
{
|
||||
static Styles()
|
||||
{
|
||||
label = new GUIStyle(BoltCore.Styles.nodeLabel);
|
||||
label.alignment = TextAnchor.MiddleCenter;
|
||||
label.imagePosition = ImagePosition.TextOnly;
|
||||
|
||||
labelInverted = new GUIStyle(label);
|
||||
labelInverted.normal.textColor = ColorPalette.unityBackgroundDark;
|
||||
|
||||
eventIcon = new GUIStyle();
|
||||
eventIcon.imagePosition = ImagePosition.ImageOnly;
|
||||
eventIcon.fixedHeight = 16;
|
||||
eventIcon.fixedWidth = 16;
|
||||
}
|
||||
|
||||
public static readonly GUIStyle label;
|
||||
|
||||
public static readonly GUIStyle labelInverted;
|
||||
|
||||
public static readonly GUIStyle eventIcon;
|
||||
|
||||
public static readonly float spaceAroundIcon = 5;
|
||||
|
||||
public static readonly float revealSpeed = 15;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Widget(typeof(TriggerStateTransition))]
|
||||
public sealed class TriggerStateTransitionWidget : UnitWidget<TriggerStateTransition>
|
||||
{
|
||||
public TriggerStateTransitionWidget(FlowCanvas canvas, TriggerStateTransition unit) : base(canvas, unit) { }
|
||||
|
||||
protected override NodeColorMix baseColor => NodeColorMix.TealReadable;
|
||||
}
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Unity.VisualScripting.State.Editor",
|
||||
"references": [
|
||||
"Unity.VisualScripting.Core",
|
||||
"Unity.VisualScripting.Flow",
|
||||
"Unity.VisualScripting.State",
|
||||
"Unity.VisualScripting.Core.Editor",
|
||||
"Unity.VisualScripting.Flow.Editor"
|
||||
],
|
||||
"optionalUnityReferences": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false
|
||||
}
|