update forge
This commit is contained in:
@@ -0,0 +1,289 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using Godot;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class AsymmetricBinaryNestedResolverEditorBase<TResource> : NodeEditorProperty
|
||||
where TResource : BinaryNestedResolverResourceBase, new()
|
||||
{
|
||||
private StatescriptGraph? _graph;
|
||||
private Action? _onChanged;
|
||||
private Type _expectedType = typeof(ForgeVariant128);
|
||||
private OptionButton? _leftResolverDropdown;
|
||||
private OptionButton? _rightResolverDropdown;
|
||||
private FoldableContainer? _leftFoldable;
|
||||
private FoldableContainer? _rightFoldable;
|
||||
private VBoxContainer? _leftEditorContainer;
|
||||
private VBoxContainer? _rightEditorContainer;
|
||||
private NodeEditorProperty? _leftEditor;
|
||||
private NodeEditorProperty? _rightEditor;
|
||||
private List<Func<NodeEditorProperty>> _leftFactories = [];
|
||||
private List<Func<NodeEditorProperty>> _rightFactories = [];
|
||||
|
||||
protected abstract Type[] LeftFactoryExpectedTypes { get; }
|
||||
|
||||
protected abstract Type[] RightFactoryExpectedTypes { get; }
|
||||
|
||||
protected abstract Type LeftNestedExpectedType { get; }
|
||||
|
||||
protected abstract Type RightNestedExpectedType { get; }
|
||||
|
||||
protected virtual string LeftTitle => "Left:";
|
||||
|
||||
protected virtual string RightTitle => "Right:";
|
||||
|
||||
public override void Setup(
|
||||
StatescriptGraph graph,
|
||||
StatescriptNodeProperty? property,
|
||||
Type expectedType,
|
||||
Action onChanged,
|
||||
bool isArray)
|
||||
{
|
||||
_graph = graph;
|
||||
_onChanged = onChanged;
|
||||
_expectedType = expectedType;
|
||||
_leftFactories = ResolverEditorFactoryCatalog.GetCompatibleFactories(
|
||||
GetConstrainedExpectedTypes(GetLeftFactoryExpectedTypes(expectedType), expectedType));
|
||||
_rightFactories = ResolverEditorFactoryCatalog.GetCompatibleFactories(
|
||||
GetConstrainedExpectedTypes(GetRightFactoryExpectedTypes(expectedType), expectedType));
|
||||
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
var vBox = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
AddChild(vBox);
|
||||
|
||||
if (_leftFactories.Count == 0 || _rightFactories.Count == 0)
|
||||
{
|
||||
var errorLabel = new Label { Text = "No compatible resolvers." };
|
||||
errorLabel.AddThemeColorOverride("font_color", Colors.Red);
|
||||
vBox.AddChild(errorLabel);
|
||||
return;
|
||||
}
|
||||
|
||||
var existingResource = property?.Resolver as TResource;
|
||||
|
||||
_leftFoldable = CreateFoldable(LeftTitle, existingResource?.LeftFolded ?? true);
|
||||
vBox.AddChild(_leftFoldable);
|
||||
var leftContainer = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
_leftFoldable.AddChild(leftContainer);
|
||||
_leftEditorContainer = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
_leftResolverDropdown = CreateResolverDropdownControl(_leftFactories, existingResource?.Left);
|
||||
leftContainer.AddChild(_leftResolverDropdown);
|
||||
leftContainer.AddChild(_leftEditorContainer);
|
||||
|
||||
ShowNestedEditor(
|
||||
_leftFactories,
|
||||
GetSelectedIndex(_leftFactories, existingResource?.Left),
|
||||
existingResource?.Left,
|
||||
GetConstrainedExpectedTypes(GetLeftFactoryExpectedTypes(expectedType), expectedType),
|
||||
_leftEditorContainer,
|
||||
x => _leftEditor = x);
|
||||
|
||||
_leftResolverDropdown.ItemSelected += OnLeftResolverDropdownItemSelected;
|
||||
|
||||
_rightFoldable = CreateFoldable(RightTitle, existingResource?.RightFolded ?? true);
|
||||
vBox.AddChild(_rightFoldable);
|
||||
var rightContainer = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
_rightFoldable.AddChild(rightContainer);
|
||||
_rightEditorContainer = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
_rightResolverDropdown = CreateResolverDropdownControl(_rightFactories, existingResource?.Right);
|
||||
rightContainer.AddChild(_rightResolverDropdown);
|
||||
rightContainer.AddChild(_rightEditorContainer);
|
||||
|
||||
ShowNestedEditor(
|
||||
_rightFactories,
|
||||
GetSelectedIndex(_rightFactories, existingResource?.Right),
|
||||
existingResource?.Right,
|
||||
GetConstrainedExpectedTypes(GetRightFactoryExpectedTypes(expectedType), expectedType),
|
||||
_rightEditorContainer,
|
||||
x => _rightEditor = x);
|
||||
|
||||
_rightResolverDropdown.ItemSelected += OnRightResolverDropdownItemSelected;
|
||||
UpdateFoldableTitles();
|
||||
}
|
||||
|
||||
public override void SaveTo(StatescriptNodeProperty property)
|
||||
{
|
||||
StatescriptResolverResource? left = null;
|
||||
StatescriptResolverResource? right = null;
|
||||
|
||||
if (_leftEditor is not null)
|
||||
{
|
||||
var leftProperty = new StatescriptNodeProperty();
|
||||
_leftEditor.SaveTo(leftProperty);
|
||||
left = leftProperty.Resolver;
|
||||
}
|
||||
|
||||
if (_rightEditor is not null)
|
||||
{
|
||||
var rightProperty = new StatescriptNodeProperty();
|
||||
_rightEditor.SaveTo(rightProperty);
|
||||
right = rightProperty.Resolver;
|
||||
}
|
||||
|
||||
property.Resolver = new TResource
|
||||
{
|
||||
Left = left,
|
||||
LeftFolded = _leftFoldable?.Folded ?? false,
|
||||
Right = right,
|
||||
RightFolded = _rightFoldable?.Folded ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
public override void ClearCallbacks()
|
||||
{
|
||||
base.ClearCallbacks();
|
||||
_onChanged = null;
|
||||
_leftEditor?.ClearCallbacks();
|
||||
_rightEditor?.ClearCallbacks();
|
||||
}
|
||||
|
||||
protected virtual Type[] GetLeftFactoryExpectedTypes(Type expectedType)
|
||||
{
|
||||
return LeftFactoryExpectedTypes;
|
||||
}
|
||||
|
||||
protected virtual Type[] GetRightFactoryExpectedTypes(Type expectedType)
|
||||
{
|
||||
return RightFactoryExpectedTypes;
|
||||
}
|
||||
|
||||
private static int GetSelectedIndex(
|
||||
List<Func<NodeEditorProperty>> factories,
|
||||
StatescriptResolverResource? existingResolver)
|
||||
{
|
||||
return NestedResolverEditorUtilities.GetSelectedIndex(factories, existingResolver);
|
||||
}
|
||||
|
||||
private static OptionButton CreateResolverDropdownControl(
|
||||
List<Func<NodeEditorProperty>> factories,
|
||||
StatescriptResolverResource? existingResolver)
|
||||
{
|
||||
return NestedResolverEditorUtilities.CreateResolverDropdownControl(factories, existingResolver);
|
||||
}
|
||||
|
||||
private FoldableContainer CreateFoldable(string title, bool folded)
|
||||
{
|
||||
var foldable = new FoldableContainer { Title = title, Folded = folded };
|
||||
foldable.FoldingChanged += OnFoldingChanged;
|
||||
return foldable;
|
||||
}
|
||||
|
||||
private void OnFoldingChanged(bool isFolded)
|
||||
{
|
||||
UpdateFoldableTitles();
|
||||
_onChanged?.Invoke();
|
||||
RaiseLayoutSizeChanged();
|
||||
}
|
||||
|
||||
private void OnLeftResolverDropdownItemSelected(long index)
|
||||
{
|
||||
HandleResolverDropdownChanged(
|
||||
_leftFactories,
|
||||
(int)index,
|
||||
GetConstrainedExpectedTypes(GetLeftFactoryExpectedTypes(_expectedType), _expectedType),
|
||||
_leftEditorContainer,
|
||||
x => _leftEditor = x);
|
||||
}
|
||||
|
||||
private void OnRightResolverDropdownItemSelected(long index)
|
||||
{
|
||||
HandleResolverDropdownChanged(
|
||||
_rightFactories,
|
||||
(int)index,
|
||||
GetConstrainedExpectedTypes(GetRightFactoryExpectedTypes(_expectedType), _expectedType),
|
||||
_rightEditorContainer,
|
||||
x => _rightEditor = x);
|
||||
}
|
||||
|
||||
private void HandleResolverDropdownChanged(
|
||||
List<Func<NodeEditorProperty>> factories,
|
||||
int selectedIndex,
|
||||
Type[] allowedExpectedTypes,
|
||||
VBoxContainer? editorContainer,
|
||||
Action<NodeEditorProperty?> setEditor)
|
||||
{
|
||||
if (editorContainer is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NestedResolverEditorUtilities.ClearContainer(editorContainer);
|
||||
|
||||
setEditor(null);
|
||||
ShowNestedEditor(
|
||||
factories,
|
||||
selectedIndex,
|
||||
null,
|
||||
allowedExpectedTypes,
|
||||
editorContainer,
|
||||
setEditor);
|
||||
UpdateFoldableTitles();
|
||||
_onChanged?.Invoke();
|
||||
RaiseLayoutSizeChanged();
|
||||
}
|
||||
|
||||
private void ShowNestedEditor(
|
||||
List<Func<NodeEditorProperty>> factories,
|
||||
int factoryIndex,
|
||||
StatescriptResolverResource? existingResolver,
|
||||
Type[] allowedExpectedTypes,
|
||||
VBoxContainer? container,
|
||||
Action<NodeEditorProperty?> setEditor)
|
||||
{
|
||||
if (_graph is null || container is null || factoryIndex < 0 || factoryIndex >= factories.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NodeEditorProperty? editor = NestedResolverEditorUtilities.CreateNestedEditor(
|
||||
_graph,
|
||||
factories,
|
||||
factoryIndex,
|
||||
existingResolver,
|
||||
allowedExpectedTypes,
|
||||
OnNestedEditorChanged,
|
||||
RaiseLayoutSizeChanged);
|
||||
|
||||
if (editor is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
container.AddChild(editor);
|
||||
setEditor(editor);
|
||||
}
|
||||
|
||||
private void OnNestedEditorChanged()
|
||||
{
|
||||
UpdateFoldableTitles();
|
||||
_onChanged?.Invoke();
|
||||
}
|
||||
|
||||
private void UpdateFoldableTitles()
|
||||
{
|
||||
if (_leftFoldable is not null)
|
||||
{
|
||||
InlineConstantSummaryFormatter.ApplyFoldableTitle(LeftTitle, _leftFoldable, _leftEditor);
|
||||
}
|
||||
|
||||
if (_rightFoldable is not null)
|
||||
{
|
||||
InlineConstantSummaryFormatter.ApplyFoldableTitle(RightTitle, _rightFoldable, _rightEditor);
|
||||
}
|
||||
}
|
||||
|
||||
private Type[] GetConstrainedExpectedTypes(Type[] candidateExpectedTypes, Type expectedType)
|
||||
{
|
||||
return NestedResolverEditorUtilities.ConstrainExpectedTypes(
|
||||
GetAllowedExpectedTypes(expectedType),
|
||||
candidateExpectedTypes);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://cyow4kcn6tbea
|
||||
@@ -0,0 +1,288 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using Godot;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class BinaryNestedResolverEditorBase<TResource> : NodeEditorProperty
|
||||
where TResource : BinaryNestedResolverResourceBase, new()
|
||||
{
|
||||
private StatescriptGraph? _graph;
|
||||
private Action? _onChanged;
|
||||
private Type _expectedType = typeof(ForgeVariant128);
|
||||
private OptionButton? _leftResolverDropdown;
|
||||
private OptionButton? _rightResolverDropdown;
|
||||
private FoldableContainer? _leftFoldable;
|
||||
private FoldableContainer? _rightFoldable;
|
||||
private VBoxContainer? _leftEditorContainer;
|
||||
private VBoxContainer? _rightEditorContainer;
|
||||
private NodeEditorProperty? _leftEditor;
|
||||
private NodeEditorProperty? _rightEditor;
|
||||
private List<Func<NodeEditorProperty>> _factories = [];
|
||||
|
||||
protected abstract Type[] FactoryExpectedTypes { get; }
|
||||
|
||||
protected abstract Type NestedExpectedType { get; }
|
||||
|
||||
protected virtual string LeftTitle => "Left:";
|
||||
|
||||
protected virtual string RightTitle => "Right:";
|
||||
|
||||
public override void Setup(
|
||||
StatescriptGraph graph,
|
||||
StatescriptNodeProperty? property,
|
||||
Type expectedType,
|
||||
Action onChanged,
|
||||
bool isArray)
|
||||
{
|
||||
_graph = graph;
|
||||
_onChanged = onChanged;
|
||||
_expectedType = expectedType;
|
||||
_factories = ResolverEditorFactoryCatalog.GetCompatibleFactories(GetConstrainedExpectedTypes(expectedType));
|
||||
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
var vBox = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
AddChild(vBox);
|
||||
|
||||
if (_factories.Count == 0)
|
||||
{
|
||||
var errorLabel = new Label { Text = "No compatible resolvers." };
|
||||
errorLabel.AddThemeColorOverride("font_color", Colors.Red);
|
||||
vBox.AddChild(errorLabel);
|
||||
return;
|
||||
}
|
||||
|
||||
var existingResource = property?.Resolver as TResource;
|
||||
|
||||
_leftFoldable = CreateFoldable(LeftTitle, existingResource?.LeftFolded ?? true);
|
||||
vBox.AddChild(_leftFoldable);
|
||||
var leftContainer = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
_leftFoldable.AddChild(leftContainer);
|
||||
_leftEditorContainer = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
_leftResolverDropdown = CreateResolverDropdownControl(existingResource?.Left);
|
||||
leftContainer.AddChild(_leftResolverDropdown);
|
||||
leftContainer.AddChild(_leftEditorContainer);
|
||||
|
||||
ShowNestedEditor(
|
||||
GetSelectedIndex(existingResource?.Left),
|
||||
existingResource?.Left,
|
||||
_leftEditorContainer,
|
||||
x => _leftEditor = x);
|
||||
|
||||
_leftResolverDropdown.ItemSelected += OnLeftResolverDropdownItemSelected;
|
||||
|
||||
_rightFoldable = CreateFoldable(RightTitle, existingResource?.RightFolded ?? true);
|
||||
vBox.AddChild(_rightFoldable);
|
||||
var rightContainer = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
_rightFoldable.AddChild(rightContainer);
|
||||
_rightEditorContainer = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
_rightResolverDropdown = CreateResolverDropdownControl(existingResource?.Right);
|
||||
rightContainer.AddChild(_rightResolverDropdown);
|
||||
rightContainer.AddChild(_rightEditorContainer);
|
||||
|
||||
ShowNestedEditor(
|
||||
GetSelectedIndex(existingResource?.Right),
|
||||
existingResource?.Right,
|
||||
_rightEditorContainer,
|
||||
x => _rightEditor = x);
|
||||
|
||||
_rightResolverDropdown.ItemSelected += OnRightResolverDropdownItemSelected;
|
||||
UpdateFoldableTitles();
|
||||
}
|
||||
|
||||
public override void SaveTo(StatescriptNodeProperty property)
|
||||
{
|
||||
StatescriptResolverResource? left = null;
|
||||
StatescriptResolverResource? right = null;
|
||||
|
||||
if (_leftEditor is not null)
|
||||
{
|
||||
var leftProperty = new StatescriptNodeProperty();
|
||||
_leftEditor.SaveTo(leftProperty);
|
||||
left = leftProperty.Resolver;
|
||||
}
|
||||
|
||||
if (_rightEditor is not null)
|
||||
{
|
||||
var rightProperty = new StatescriptNodeProperty();
|
||||
_rightEditor.SaveTo(rightProperty);
|
||||
right = rightProperty.Resolver;
|
||||
}
|
||||
|
||||
property.Resolver = new TResource
|
||||
{
|
||||
Left = left,
|
||||
LeftFolded = _leftFoldable?.Folded ?? false,
|
||||
Right = right,
|
||||
RightFolded = _rightFoldable?.Folded ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
public override void ClearCallbacks()
|
||||
{
|
||||
base.ClearCallbacks();
|
||||
_onChanged = null;
|
||||
_leftEditor?.ClearCallbacks();
|
||||
_rightEditor?.ClearCallbacks();
|
||||
}
|
||||
|
||||
public override bool TryGetHighlightedVariableName(out string variableName)
|
||||
{
|
||||
if (_leftEditor is not null && _leftEditor.TryGetHighlightedVariableName(out variableName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_rightEditor is not null && _rightEditor.TryGetHighlightedVariableName(out variableName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
variableName = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TryGetHighlightedSharedVariable(out string sharedVariableSetPath, out string variableName)
|
||||
{
|
||||
if (_leftEditor is not null
|
||||
&& _leftEditor.TryGetHighlightedSharedVariable(out sharedVariableSetPath, out variableName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_rightEditor is not null
|
||||
&& _rightEditor.TryGetHighlightedSharedVariable(out sharedVariableSetPath, out variableName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
sharedVariableSetPath = string.Empty;
|
||||
variableName = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual Type[] GetFactoryExpectedTypes(Type expectedType)
|
||||
{
|
||||
return FactoryExpectedTypes;
|
||||
}
|
||||
|
||||
protected virtual Type GetNestedExpectedType(Type expectedType)
|
||||
{
|
||||
return NestedExpectedType;
|
||||
}
|
||||
|
||||
private FoldableContainer CreateFoldable(string title, bool folded)
|
||||
{
|
||||
var foldable = new FoldableContainer { Title = title, Folded = folded };
|
||||
foldable.FoldingChanged += OnFoldingChanged;
|
||||
return foldable;
|
||||
}
|
||||
|
||||
private void OnFoldingChanged(bool isFolded)
|
||||
{
|
||||
UpdateFoldableTitles();
|
||||
_onChanged?.Invoke();
|
||||
RaiseLayoutSizeChanged();
|
||||
}
|
||||
|
||||
private void OnLeftResolverDropdownItemSelected(long index)
|
||||
{
|
||||
HandleResolverDropdownChanged((int)index, _leftEditorContainer, x => _leftEditor = x);
|
||||
}
|
||||
|
||||
private void OnRightResolverDropdownItemSelected(long index)
|
||||
{
|
||||
HandleResolverDropdownChanged((int)index, _rightEditorContainer, x => _rightEditor = x);
|
||||
}
|
||||
|
||||
private void HandleResolverDropdownChanged(
|
||||
int selectedIndex,
|
||||
VBoxContainer? editorContainer,
|
||||
Action<NodeEditorProperty?> setEditor)
|
||||
{
|
||||
if (editorContainer is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NestedResolverEditorUtilities.ClearContainer(editorContainer);
|
||||
|
||||
setEditor(null);
|
||||
ShowNestedEditor(selectedIndex, null, editorContainer, setEditor);
|
||||
UpdateFoldableTitles();
|
||||
_onChanged?.Invoke();
|
||||
RaiseLayoutSizeChanged();
|
||||
}
|
||||
|
||||
private int GetSelectedIndex(StatescriptResolverResource? existingResolver)
|
||||
{
|
||||
return NestedResolverEditorUtilities.GetSelectedIndex(_factories, existingResolver);
|
||||
}
|
||||
|
||||
private OptionButton CreateResolverDropdownControl(StatescriptResolverResource? existingResolver)
|
||||
{
|
||||
return NestedResolverEditorUtilities.CreateResolverDropdownControl(_factories, existingResolver);
|
||||
}
|
||||
|
||||
private void ShowNestedEditor(
|
||||
int factoryIndex,
|
||||
StatescriptResolverResource? existingResolver,
|
||||
VBoxContainer? container,
|
||||
Action<NodeEditorProperty?> setEditor)
|
||||
{
|
||||
if (_graph is null || container is null || factoryIndex < 0 || factoryIndex >= _factories.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NodeEditorProperty? editor = NestedResolverEditorUtilities.CreateNestedEditor(
|
||||
_graph,
|
||||
_factories,
|
||||
factoryIndex,
|
||||
existingResolver,
|
||||
GetConstrainedExpectedTypes(_expectedType),
|
||||
OnNestedEditorChanged,
|
||||
RaiseLayoutSizeChanged);
|
||||
|
||||
if (editor is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
container.AddChild(editor);
|
||||
setEditor(editor);
|
||||
}
|
||||
|
||||
private void OnNestedEditorChanged()
|
||||
{
|
||||
UpdateFoldableTitles();
|
||||
_onChanged?.Invoke();
|
||||
}
|
||||
|
||||
private void UpdateFoldableTitles()
|
||||
{
|
||||
if (_leftFoldable is not null)
|
||||
{
|
||||
InlineConstantSummaryFormatter.ApplyFoldableTitle(LeftTitle, _leftFoldable, _leftEditor);
|
||||
}
|
||||
|
||||
if (_rightFoldable is not null)
|
||||
{
|
||||
InlineConstantSummaryFormatter.ApplyFoldableTitle(RightTitle, _rightFoldable, _rightEditor);
|
||||
}
|
||||
}
|
||||
|
||||
private Type[] GetConstrainedExpectedTypes(Type expectedType)
|
||||
{
|
||||
return NestedResolverEditorUtilities.ConstrainExpectedTypes(
|
||||
GetAllowedExpectedTypes(expectedType),
|
||||
GetFactoryExpectedTypes(expectedType));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://b3pmp2xiewgvy
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class BooleanBinaryResolverEditorBase<TResource> : BinaryNestedResolverEditorBase<TResource>
|
||||
where TResource : BinaryNestedResolverResourceBase, new()
|
||||
{
|
||||
protected override Type[] FactoryExpectedTypes => [typeof(bool)];
|
||||
|
||||
protected override Type NestedExpectedType => typeof(bool);
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(bool) || expectedType == typeof(ForgeVariant128);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://dc0mydw6yowuf
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class BooleanUnaryResolverEditorBase<TResource> : UnaryNestedResolverEditorBase<TResource>
|
||||
where TResource : UnaryNestedResolverResourceBase, new()
|
||||
{
|
||||
protected override Type[] FactoryExpectedTypes => [typeof(bool)];
|
||||
|
||||
protected override Type NestedExpectedType => typeof(bool);
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(bool) || expectedType == typeof(ForgeVariant128);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://w6f613rs3afl
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class FloatUnaryResolverEditorBase<TResource> : UnaryNestedResolverEditorBase<TResource>
|
||||
where TResource : UnaryNestedResolverResourceBase, new()
|
||||
{
|
||||
protected override Type[] FactoryExpectedTypes => ResolverEditorCompatibility.FloatOperandExpectedTypes;
|
||||
|
||||
protected override Type NestedExpectedType => typeof(float);
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
|| ResolverEditorCompatibility.IsFloatType(expectedType);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://kbcr62hyn625
|
||||
@@ -0,0 +1,165 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript;
|
||||
using Godot;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal static class NestedResolverEditorUtilities
|
||||
{
|
||||
public static int GetSelectedIndex(
|
||||
List<Func<NodeEditorProperty>> factories,
|
||||
StatescriptResolverResource? existingResolver)
|
||||
{
|
||||
return ResolverEditorFactoryCatalog.GetDefaultFactoryIndex(factories, existingResolver, "Variant");
|
||||
}
|
||||
|
||||
public static OptionButton CreateResolverDropdownControl(
|
||||
List<Func<NodeEditorProperty>> factories,
|
||||
StatescriptResolverResource? existingResolver)
|
||||
{
|
||||
var dropdown = new OptionButton { SizeFlagsHorizontal = Control.SizeFlags.ExpandFill };
|
||||
|
||||
foreach (Func<NodeEditorProperty> factory in factories)
|
||||
{
|
||||
dropdown.AddItem(StatescriptResolverRegistry.GetDisplayName(factory));
|
||||
}
|
||||
|
||||
dropdown.Selected = GetSelectedIndex(factories, existingResolver);
|
||||
return dropdown;
|
||||
}
|
||||
|
||||
public static void ClearContainer(VBoxContainer? container)
|
||||
{
|
||||
if (container is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (Node child in container.GetChildren())
|
||||
{
|
||||
container.RemoveChild(child);
|
||||
child.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public static Type[] ConstrainExpectedTypes(Type[] allowedExpectedTypes, Type[] candidateExpectedTypes)
|
||||
{
|
||||
if (allowedExpectedTypes.Length == 0)
|
||||
{
|
||||
return candidateExpectedTypes;
|
||||
}
|
||||
|
||||
if (ContainsVariantType(allowedExpectedTypes))
|
||||
{
|
||||
return candidateExpectedTypes;
|
||||
}
|
||||
|
||||
var constrainedExpectedTypes = new List<Type>();
|
||||
|
||||
for (int i = 0; i < candidateExpectedTypes.Length; i++)
|
||||
{
|
||||
Type candidateExpectedType = candidateExpectedTypes[i];
|
||||
|
||||
for (int j = 0; j < allowedExpectedTypes.Length; j++)
|
||||
{
|
||||
if (!AreExpectedTypesCompatible(candidateExpectedType, allowedExpectedTypes[j]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!constrainedExpectedTypes.Contains(candidateExpectedType))
|
||||
{
|
||||
constrainedExpectedTypes.Add(candidateExpectedType);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return constrainedExpectedTypes.Count > 0 ? [.. constrainedExpectedTypes] : candidateExpectedTypes;
|
||||
}
|
||||
|
||||
public static NodeEditorProperty? CreateNestedEditor(
|
||||
StatescriptGraph? graph,
|
||||
List<Func<NodeEditorProperty>> factories,
|
||||
int factoryIndex,
|
||||
StatescriptResolverResource? existingResolver,
|
||||
Type[] allowedExpectedTypes,
|
||||
Action onChanged,
|
||||
Action layoutSizeChanged)
|
||||
{
|
||||
if (graph is null || factoryIndex < 0 || factoryIndex >= factories.Count)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
NodeEditorProperty editor = factories[factoryIndex]();
|
||||
Type[] compatibleExpectedTypes = GetCompatibleExpectedTypes(editor, allowedExpectedTypes);
|
||||
Type[] effectiveAllowedExpectedTypes = compatibleExpectedTypes.Length > 0
|
||||
? compatibleExpectedTypes
|
||||
: allowedExpectedTypes;
|
||||
|
||||
editor.ConfigureAllowedExpectedTypes(effectiveAllowedExpectedTypes);
|
||||
|
||||
StatescriptNodeProperty? tempProperty = existingResolver is null
|
||||
? null
|
||||
: new StatescriptNodeProperty { Resolver = existingResolver };
|
||||
|
||||
editor.Setup(
|
||||
graph,
|
||||
tempProperty,
|
||||
GetEffectiveExpectedType(effectiveAllowedExpectedTypes),
|
||||
onChanged,
|
||||
false);
|
||||
editor.LayoutSizeChanged += layoutSizeChanged;
|
||||
return editor;
|
||||
}
|
||||
|
||||
private static Type[] GetCompatibleExpectedTypes(NodeEditorProperty editor, Type[] allowedExpectedTypes)
|
||||
{
|
||||
var compatibleExpectedTypes = new List<Type>();
|
||||
|
||||
for (int i = 0; i < allowedExpectedTypes.Length; i++)
|
||||
{
|
||||
Type allowedExpectedType = allowedExpectedTypes[i];
|
||||
|
||||
if (editor.IsCompatibleWith(allowedExpectedType) && !compatibleExpectedTypes.Contains(allowedExpectedType))
|
||||
{
|
||||
compatibleExpectedTypes.Add(allowedExpectedType);
|
||||
}
|
||||
}
|
||||
|
||||
return [.. compatibleExpectedTypes];
|
||||
}
|
||||
|
||||
private static Type GetEffectiveExpectedType(Type[] allowedExpectedTypes)
|
||||
{
|
||||
return allowedExpectedTypes.Length == 1
|
||||
? allowedExpectedTypes[0]
|
||||
: typeof(ForgeVariant128);
|
||||
}
|
||||
|
||||
private static bool AreExpectedTypesCompatible(Type candidateExpectedType, Type allowedExpectedType)
|
||||
{
|
||||
return ResolverEditorCompatibility.AreExpectedTypesCompatible(candidateExpectedType, allowedExpectedType);
|
||||
}
|
||||
|
||||
private static bool ContainsVariantType(Type[] expectedTypes)
|
||||
{
|
||||
for (int i = 0; i < expectedTypes.Length; i++)
|
||||
{
|
||||
if (expectedTypes[i] == typeof(ForgeVariant128))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://b45b56tgc7ahy
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
using SysVector2 = System.Numerics.Vector2;
|
||||
using SysVector3 = System.Numerics.Vector3;
|
||||
using SysVector4 = System.Numerics.Vector4;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class NumericOrVectorBinaryResolverEditorBase<TResource>
|
||||
: BinaryNestedResolverEditorBase<TResource>
|
||||
where TResource : BinaryNestedResolverResourceBase, new()
|
||||
{
|
||||
protected override Type[] FactoryExpectedTypes =>
|
||||
[
|
||||
typeof(int),
|
||||
typeof(float),
|
||||
typeof(double),
|
||||
typeof(SysVector2),
|
||||
typeof(SysVector3),
|
||||
typeof(SysVector4),
|
||||
];
|
||||
|
||||
protected override Type NestedExpectedType => typeof(ForgeVariant128);
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
|| ResolverEditorCompatibility.IsNumericOrVectorType(expectedType);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://cpom40i1c7wxx
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
using SysVector2 = System.Numerics.Vector2;
|
||||
using SysVector3 = System.Numerics.Vector3;
|
||||
using SysVector4 = System.Numerics.Vector4;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class NumericOrVectorTernaryResolverEditorBase<TResource>
|
||||
: TernaryNestedResolverEditorBase<TResource>
|
||||
where TResource : TernaryNestedResolverResourceBase, new()
|
||||
{
|
||||
protected override Type[] FirstFactoryExpectedTypes =>
|
||||
[typeof(int), typeof(float), typeof(double), typeof(SysVector2), typeof(SysVector3), typeof(SysVector4)];
|
||||
|
||||
protected override Type[] SecondFactoryExpectedTypes =>
|
||||
[typeof(int), typeof(float), typeof(double), typeof(SysVector2), typeof(SysVector3), typeof(SysVector4)];
|
||||
|
||||
protected override Type[] ThirdFactoryExpectedTypes => [typeof(int), typeof(float), typeof(double)];
|
||||
|
||||
protected override Type FirstNestedExpectedType => typeof(ForgeVariant128);
|
||||
|
||||
protected override Type SecondNestedExpectedType => typeof(ForgeVariant128);
|
||||
|
||||
protected override Type ThirdNestedExpectedType => typeof(float);
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
|| ResolverEditorCompatibility.IsNumericOrVectorType(expectedType);
|
||||
}
|
||||
|
||||
protected override Type[] GetFirstFactoryExpectedTypes(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
? FirstFactoryExpectedTypes
|
||||
: [expectedType];
|
||||
}
|
||||
|
||||
protected override Type[] GetSecondFactoryExpectedTypes(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
? SecondFactoryExpectedTypes
|
||||
: [expectedType];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://bjf5jvybvbfjw
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
using SysVector2 = System.Numerics.Vector2;
|
||||
using SysVector3 = System.Numerics.Vector3;
|
||||
using SysVector4 = System.Numerics.Vector4;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class NumericOrVectorUnaryResolverEditorBase<TResource>
|
||||
: UnaryNestedResolverEditorBase<TResource>
|
||||
where TResource : UnaryNestedResolverResourceBase, new()
|
||||
{
|
||||
protected override Type[] FactoryExpectedTypes =>
|
||||
[
|
||||
typeof(int),
|
||||
typeof(float),
|
||||
typeof(double),
|
||||
typeof(SysVector2),
|
||||
typeof(SysVector3),
|
||||
typeof(SysVector4),
|
||||
];
|
||||
|
||||
protected override Type NestedExpectedType => typeof(ForgeVariant128);
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
|| ResolverEditorCompatibility.IsNumericOrVectorType(expectedType);
|
||||
}
|
||||
|
||||
protected override Type[] GetFactoryExpectedTypes(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
? FactoryExpectedTypes
|
||||
: [expectedType];
|
||||
}
|
||||
|
||||
protected override Type GetNestedExpectedType(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
? typeof(ForgeVariant128)
|
||||
: expectedType;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://brf7wrfe565v4
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class NumericUnaryResolverEditorBase<TResource> : UnaryNestedResolverEditorBase<TResource>
|
||||
where TResource : UnaryNestedResolverResourceBase, new()
|
||||
{
|
||||
protected override Type[] FactoryExpectedTypes => [typeof(int), typeof(float), typeof(double)];
|
||||
|
||||
protected override Type NestedExpectedType => typeof(ForgeVariant128);
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(int) || expectedType == typeof(ForgeVariant128);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://buuajtwqdgktk
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
using SysQuaternion = System.Numerics.Quaternion;
|
||||
using SysVector2 = System.Numerics.Vector2;
|
||||
using SysVector3 = System.Numerics.Vector3;
|
||||
using SysVector4 = System.Numerics.Vector4;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class NumericVectorOrQuaternionBinaryResolverEditorBase<TResource>
|
||||
: BinaryNestedResolverEditorBase<TResource>
|
||||
where TResource : BinaryNestedResolverResourceBase, new()
|
||||
{
|
||||
protected override Type[] FactoryExpectedTypes =>
|
||||
[
|
||||
typeof(int),
|
||||
typeof(float),
|
||||
typeof(double),
|
||||
typeof(SysVector2),
|
||||
typeof(SysVector3),
|
||||
typeof(SysVector4),
|
||||
typeof(SysQuaternion),
|
||||
];
|
||||
|
||||
protected override Type NestedExpectedType => typeof(ForgeVariant128);
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
|| ResolverEditorCompatibility.IsNumericVectorOrQuaternionType(expectedType);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://xg6lfxuo5b4x
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript;
|
||||
using Godot;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
[Tool]
|
||||
internal abstract partial class RandomInfoResolverEditorBase : NodeEditorProperty
|
||||
{
|
||||
protected abstract string InfoText { get; }
|
||||
|
||||
public override void Setup(
|
||||
StatescriptGraph graph,
|
||||
StatescriptNodeProperty? property,
|
||||
Type expectedType,
|
||||
Action onChanged,
|
||||
bool isArray)
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
AddChild(new Label
|
||||
{
|
||||
Text = InfoText,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill,
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://c043v4m3uh5xf
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
using SysPlane = System.Numerics.Plane;
|
||||
using SysQuaternion = System.Numerics.Quaternion;
|
||||
using SysVector2 = System.Numerics.Vector2;
|
||||
using SysVector3 = System.Numerics.Vector3;
|
||||
using SysVector4 = System.Numerics.Vector4;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal static class ResolverEditorCompatibility
|
||||
{
|
||||
public static readonly Type[] FloatOperandExpectedTypes = [typeof(int), typeof(float), typeof(double)];
|
||||
|
||||
public static bool IsNumericType(Type expectedType)
|
||||
{
|
||||
if (!StatescriptVariableTypeConverter.TryFromSystemType(expectedType, out StatescriptVariableType variableType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return StatescriptEditorControls.IsIntegerType(variableType)
|
||||
|| StatescriptEditorControls.IsFloatType(variableType);
|
||||
}
|
||||
|
||||
public static bool IsFloatType(Type expectedType)
|
||||
{
|
||||
if (!StatescriptVariableTypeConverter.TryFromSystemType(expectedType, out StatescriptVariableType variableType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return StatescriptEditorControls.IsFloatType(variableType);
|
||||
}
|
||||
|
||||
public static bool IsVectorType(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(SysVector2)
|
||||
|| expectedType == typeof(SysVector3)
|
||||
|| expectedType == typeof(SysVector4);
|
||||
}
|
||||
|
||||
public static bool IsQuaternionType(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(SysQuaternion);
|
||||
}
|
||||
|
||||
public static bool IsPlaneType(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(SysPlane);
|
||||
}
|
||||
|
||||
public static bool IsVectorPlaneOrQuaternionType(Type expectedType)
|
||||
{
|
||||
return IsVectorType(expectedType) || IsPlaneType(expectedType) || IsQuaternionType(expectedType);
|
||||
}
|
||||
|
||||
public static bool IsNumericOrVectorType(Type expectedType)
|
||||
{
|
||||
return IsNumericType(expectedType) || IsVectorType(expectedType);
|
||||
}
|
||||
|
||||
public static bool IsNumericVectorOrQuaternionType(Type expectedType)
|
||||
{
|
||||
return IsNumericOrVectorType(expectedType) || IsQuaternionType(expectedType);
|
||||
}
|
||||
|
||||
public static bool AreExpectedTypesCompatible(Type candidateExpectedType, Type allowedExpectedType)
|
||||
{
|
||||
return candidateExpectedType == allowedExpectedType
|
||||
|| candidateExpectedType == typeof(ForgeVariant128)
|
||||
|| allowedExpectedType == typeof(ForgeVariant128)
|
||||
|| StatescriptVariableTypeConverter.IsCompatible(allowedExpectedType, candidateExpectedType);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://w2k56r4k5fv2
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal static class ResolverEditorFactoryCatalog
|
||||
{
|
||||
public static List<Func<NodeEditorProperty>> GetCompatibleFactories(params Type[] expectedTypes)
|
||||
{
|
||||
var result = new List<Func<NodeEditorProperty>>();
|
||||
var seenTypeIds = new HashSet<string>(StringComparer.Ordinal);
|
||||
|
||||
foreach (Type expectedType in expectedTypes)
|
||||
{
|
||||
result.AddRange(StatescriptResolverRegistry.GetCompatibleFactories(expectedType)
|
||||
.Where(factory => seenTypeIds.Add(StatescriptResolverRegistry.GetResolverTypeId(factory))));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int GetDefaultFactoryIndex(
|
||||
List<Func<NodeEditorProperty>> factories,
|
||||
StatescriptResolverResource? existingResolver,
|
||||
string preferredResolverTypeId)
|
||||
{
|
||||
if (existingResolver is not null)
|
||||
{
|
||||
for (int i = 0; i < factories.Count; i++)
|
||||
{
|
||||
if (StatescriptResolverRegistry.GetResolverTypeId(factories[i]) == existingResolver.ResolverTypeId)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < factories.Count; i++)
|
||||
{
|
||||
if (StatescriptResolverRegistry.GetResolverTypeId(factories[i]) == preferredResolverTypeId)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://b480krgjgsy3r
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class ScalarBinaryResolverEditorBase<TResource> : BinaryNestedResolverEditorBase<TResource>
|
||||
where TResource : BinaryNestedResolverResourceBase, new()
|
||||
{
|
||||
protected override Type[] FactoryExpectedTypes => ResolverEditorCompatibility.FloatOperandExpectedTypes;
|
||||
|
||||
protected override Type NestedExpectedType => typeof(float);
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(float)
|
||||
|| expectedType == typeof(double)
|
||||
|| expectedType == typeof(ForgeVariant128);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://bpkyp5u4b4ash
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using Godot;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class ScalarConstantResolverEditorBase<TResource> : NodeEditorProperty
|
||||
where TResource : TypedConstantResolverResourceBase, new()
|
||||
{
|
||||
private StatescriptVariableType _valueType;
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(float)
|
||||
|| expectedType == typeof(double)
|
||||
|| expectedType == typeof(ForgeVariant128);
|
||||
}
|
||||
|
||||
public override void Setup(
|
||||
StatescriptGraph graph,
|
||||
StatescriptNodeProperty? property,
|
||||
Type expectedType,
|
||||
Action onChanged,
|
||||
bool isArray)
|
||||
{
|
||||
if (property?.Resolver is TResource)
|
||||
{
|
||||
_valueType = NormalizeValueType();
|
||||
}
|
||||
else
|
||||
{
|
||||
_valueType = StatescriptVariableType.Double;
|
||||
}
|
||||
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
var row = new HBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
AddChild(row);
|
||||
|
||||
row.AddChild(new Label
|
||||
{
|
||||
Text = "Type:",
|
||||
CustomMinimumSize = new Vector2(45, 0),
|
||||
HorizontalAlignment = HorizontalAlignment.Right,
|
||||
});
|
||||
|
||||
row.AddChild(new Label
|
||||
{
|
||||
Text = "Float",
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill,
|
||||
});
|
||||
}
|
||||
|
||||
public override void SaveTo(StatescriptNodeProperty property)
|
||||
{
|
||||
property.Resolver = new TResource { ValueType = _valueType };
|
||||
}
|
||||
|
||||
private static StatescriptVariableType NormalizeValueType()
|
||||
{
|
||||
return StatescriptVariableType.Double;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://bukuprj6otl7h
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class ScalarUnaryResolverEditorBase<TResource> : UnaryNestedResolverEditorBase<TResource>
|
||||
where TResource : UnaryNestedResolverResourceBase, new()
|
||||
{
|
||||
protected override Type[] FactoryExpectedTypes => ResolverEditorCompatibility.FloatOperandExpectedTypes;
|
||||
|
||||
protected override Type NestedExpectedType => typeof(float);
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(float)
|
||||
|| expectedType == typeof(double)
|
||||
|| expectedType == typeof(ForgeVariant128);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://20nlyaem5arx
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
using SysVector2 = System.Numerics.Vector2;
|
||||
using SysVector3 = System.Numerics.Vector3;
|
||||
using SysVector4 = System.Numerics.Vector4;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class ScaleResolverEditorBase<TResource> : AsymmetricBinaryNestedResolverEditorBase<TResource>
|
||||
where TResource : BinaryNestedResolverResourceBase, new()
|
||||
{
|
||||
protected override Type[] LeftFactoryExpectedTypes => [typeof(SysVector2), typeof(SysVector3), typeof(SysVector4)];
|
||||
|
||||
protected override Type[] RightFactoryExpectedTypes => ResolverEditorCompatibility.FloatOperandExpectedTypes;
|
||||
|
||||
protected override Type LeftNestedExpectedType => typeof(ForgeVariant128);
|
||||
|
||||
protected override Type RightNestedExpectedType => typeof(float);
|
||||
|
||||
protected override string LeftTitle => "Vector:";
|
||||
|
||||
protected override string RightTitle => "Scalar:";
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
|| ResolverEditorCompatibility.IsVectorType(expectedType);
|
||||
}
|
||||
|
||||
protected override Type[] GetLeftFactoryExpectedTypes(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
? LeftFactoryExpectedTypes
|
||||
: [expectedType];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://cxicv3x5hgik1
|
||||
@@ -0,0 +1,450 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using Godot;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class TernaryNestedResolverEditorBase<TResource> : NodeEditorProperty
|
||||
where TResource : TernaryNestedResolverResourceBase, new()
|
||||
{
|
||||
private enum ResolverSlot
|
||||
{
|
||||
First = 0,
|
||||
Second = 1,
|
||||
Third = 2,
|
||||
}
|
||||
|
||||
private StatescriptGraph? _graph;
|
||||
private Action? _onChanged;
|
||||
private FoldableContainer? _firstFoldable;
|
||||
private FoldableContainer? _secondFoldable;
|
||||
private FoldableContainer? _thirdFoldable;
|
||||
private NodeEditorProperty? _firstEditor;
|
||||
private NodeEditorProperty? _secondEditor;
|
||||
private NodeEditorProperty? _thirdEditor;
|
||||
private List<Func<NodeEditorProperty>> _firstFactories = [];
|
||||
private List<Func<NodeEditorProperty>> _secondFactories = [];
|
||||
private List<Func<NodeEditorProperty>> _thirdFactories = [];
|
||||
|
||||
protected abstract Type[] FirstFactoryExpectedTypes { get; }
|
||||
|
||||
protected abstract Type[] SecondFactoryExpectedTypes { get; }
|
||||
|
||||
protected abstract Type[] ThirdFactoryExpectedTypes { get; }
|
||||
|
||||
protected abstract Type FirstNestedExpectedType { get; }
|
||||
|
||||
protected abstract Type SecondNestedExpectedType { get; }
|
||||
|
||||
protected abstract Type ThirdNestedExpectedType { get; }
|
||||
|
||||
protected virtual string FirstTitle => "First:";
|
||||
|
||||
protected virtual string SecondTitle => "Second:";
|
||||
|
||||
protected virtual string ThirdTitle => "Third:";
|
||||
|
||||
public override void Setup(
|
||||
StatescriptGraph graph,
|
||||
StatescriptNodeProperty? property,
|
||||
Type expectedType,
|
||||
Action onChanged,
|
||||
bool isArray)
|
||||
{
|
||||
_graph = graph;
|
||||
_onChanged = onChanged;
|
||||
_firstFactories =
|
||||
ResolverEditorFactoryCatalog.GetCompatibleFactories(
|
||||
GetConstrainedExpectedTypes(GetFirstFactoryExpectedTypes(expectedType), expectedType));
|
||||
_secondFactories =
|
||||
ResolverEditorFactoryCatalog.GetCompatibleFactories(
|
||||
GetConstrainedExpectedTypes(GetSecondFactoryExpectedTypes(expectedType), expectedType));
|
||||
_thirdFactories =
|
||||
ResolverEditorFactoryCatalog.GetCompatibleFactories(
|
||||
GetConstrainedExpectedTypes(GetThirdFactoryExpectedTypes(expectedType), expectedType));
|
||||
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
var vBox = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
AddChild(vBox);
|
||||
|
||||
if (_firstFactories.Count == 0 || _secondFactories.Count == 0 || _thirdFactories.Count == 0)
|
||||
{
|
||||
var errorLabel = new Label { Text = "No compatible resolvers." };
|
||||
errorLabel.AddThemeColorOverride("font_color", Colors.Red);
|
||||
vBox.AddChild(errorLabel);
|
||||
return;
|
||||
}
|
||||
|
||||
var existingResource = property?.Resolver as TResource;
|
||||
|
||||
BuildSlot(
|
||||
vBox,
|
||||
ResolverSlot.First,
|
||||
FirstTitle,
|
||||
_firstFactories,
|
||||
existingResource?.First,
|
||||
GetConstrainedExpectedTypes(GetFirstFactoryExpectedTypes(expectedType), expectedType),
|
||||
existingResource?.FirstFolded ?? true);
|
||||
|
||||
BuildSlot(
|
||||
vBox,
|
||||
ResolverSlot.Second,
|
||||
SecondTitle,
|
||||
_secondFactories,
|
||||
existingResource?.Second,
|
||||
GetConstrainedExpectedTypes(GetSecondFactoryExpectedTypes(expectedType), expectedType),
|
||||
existingResource?.SecondFolded ?? true);
|
||||
|
||||
BuildSlot(
|
||||
vBox,
|
||||
ResolverSlot.Third,
|
||||
ThirdTitle,
|
||||
_thirdFactories,
|
||||
existingResource?.Third,
|
||||
GetConstrainedExpectedTypes(GetThirdFactoryExpectedTypes(expectedType), expectedType),
|
||||
existingResource?.ThirdFolded ?? true);
|
||||
|
||||
UpdateFoldableTitles();
|
||||
}
|
||||
|
||||
public override void SaveTo(StatescriptNodeProperty property)
|
||||
{
|
||||
property.Resolver = new TResource
|
||||
{
|
||||
First = SaveNestedEditor(_firstEditor),
|
||||
FirstFolded = _firstFoldable?.Folded ?? false,
|
||||
Second = SaveNestedEditor(_secondEditor),
|
||||
SecondFolded = _secondFoldable?.Folded ?? false,
|
||||
Third = SaveNestedEditor(_thirdEditor),
|
||||
ThirdFolded = _thirdFoldable?.Folded ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
public override void ClearCallbacks()
|
||||
{
|
||||
base.ClearCallbacks();
|
||||
_onChanged = null;
|
||||
_firstEditor?.ClearCallbacks();
|
||||
_secondEditor?.ClearCallbacks();
|
||||
_thirdEditor?.ClearCallbacks();
|
||||
_firstFoldable = null;
|
||||
_secondFoldable = null;
|
||||
_thirdFoldable = null;
|
||||
_firstEditor = null;
|
||||
_secondEditor = null;
|
||||
_thirdEditor = null;
|
||||
}
|
||||
|
||||
public override bool TryGetHighlightedVariableName(out string variableName)
|
||||
{
|
||||
if (_firstEditor is not null && _firstEditor.TryGetHighlightedVariableName(out variableName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_secondEditor is not null && _secondEditor.TryGetHighlightedVariableName(out variableName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_thirdEditor is not null && _thirdEditor.TryGetHighlightedVariableName(out variableName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
variableName = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TryGetHighlightedSharedVariable(out string sharedVariableSetPath, out string variableName)
|
||||
{
|
||||
if (_firstEditor is not null
|
||||
&& _firstEditor.TryGetHighlightedSharedVariable(out sharedVariableSetPath, out variableName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_secondEditor is not null
|
||||
&& _secondEditor.TryGetHighlightedSharedVariable(out sharedVariableSetPath, out variableName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_thirdEditor is not null
|
||||
&& _thirdEditor.TryGetHighlightedSharedVariable(out sharedVariableSetPath, out variableName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
sharedVariableSetPath = string.Empty;
|
||||
variableName = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual Type[] GetFirstFactoryExpectedTypes(Type expectedType)
|
||||
{
|
||||
return FirstFactoryExpectedTypes;
|
||||
}
|
||||
|
||||
protected virtual Type[] GetSecondFactoryExpectedTypes(Type expectedType)
|
||||
{
|
||||
return SecondFactoryExpectedTypes;
|
||||
}
|
||||
|
||||
protected virtual Type[] GetThirdFactoryExpectedTypes(Type expectedType)
|
||||
{
|
||||
return ThirdFactoryExpectedTypes;
|
||||
}
|
||||
|
||||
private static StatescriptResolverResource? SaveNestedEditor(NodeEditorProperty? editor)
|
||||
{
|
||||
if (editor is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var property = new StatescriptNodeProperty();
|
||||
editor.SaveTo(property);
|
||||
return property.Resolver;
|
||||
}
|
||||
|
||||
private static int GetSelectedIndex(
|
||||
List<Func<NodeEditorProperty>> factories,
|
||||
StatescriptResolverResource? existingResolver)
|
||||
{
|
||||
return NestedResolverEditorUtilities.GetSelectedIndex(factories, existingResolver);
|
||||
}
|
||||
|
||||
private static VBoxContainer? GetNestedEditorContainer(FoldableContainer? foldable)
|
||||
{
|
||||
if (foldable is null || foldable.GetChildCount() <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (foldable.GetChild(0) is not VBoxContainer slotContainer || slotContainer.GetChildCount() <= 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return slotContainer.GetChild(1) as VBoxContainer;
|
||||
}
|
||||
|
||||
private void BuildSlot(
|
||||
VBoxContainer root,
|
||||
ResolverSlot slot,
|
||||
string title,
|
||||
List<Func<NodeEditorProperty>> factories,
|
||||
StatescriptResolverResource? existingResolver,
|
||||
Type[] allowedExpectedTypes,
|
||||
bool folded)
|
||||
{
|
||||
FoldableContainer foldable = new() { Title = title, Folded = folded };
|
||||
foldable.FoldingChanged += OnFoldableFoldingChanged;
|
||||
SetFoldable(slot, foldable);
|
||||
root.AddChild(foldable);
|
||||
|
||||
var container = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
foldable.AddChild(container);
|
||||
|
||||
OptionButton resolverDropdown =
|
||||
NestedResolverEditorUtilities.CreateResolverDropdownControl(factories, existingResolver);
|
||||
|
||||
int selectedIndex = GetSelectedIndex(factories, existingResolver);
|
||||
resolverDropdown.Selected = selectedIndex;
|
||||
container.AddChild(resolverDropdown);
|
||||
|
||||
var editorContainer = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
container.AddChild(editorContainer);
|
||||
ShowNestedEditor(
|
||||
slot,
|
||||
factories,
|
||||
selectedIndex,
|
||||
existingResolver,
|
||||
allowedExpectedTypes,
|
||||
editorContainer);
|
||||
|
||||
resolverDropdown.ItemSelected += slot switch
|
||||
{
|
||||
ResolverSlot.First => OnFirstResolverDropdownItemSelected,
|
||||
ResolverSlot.Second => OnSecondResolverDropdownItemSelected,
|
||||
_ => OnThirdResolverDropdownItemSelected,
|
||||
};
|
||||
}
|
||||
|
||||
private void ShowNestedEditor(
|
||||
ResolverSlot slot,
|
||||
List<Func<NodeEditorProperty>> factories,
|
||||
int factoryIndex,
|
||||
StatescriptResolverResource? existingResolver,
|
||||
Type[] allowedExpectedTypes,
|
||||
VBoxContainer container)
|
||||
{
|
||||
if (_graph is null || factoryIndex < 0 || factoryIndex >= factories.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NodeEditorProperty? editor = NestedResolverEditorUtilities.CreateNestedEditor(
|
||||
_graph,
|
||||
factories,
|
||||
factoryIndex,
|
||||
existingResolver,
|
||||
allowedExpectedTypes,
|
||||
OnNestedEditorChanged,
|
||||
RaiseLayoutSizeChanged);
|
||||
|
||||
if (editor is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
container.AddChild(editor);
|
||||
SetEditor(slot, editor);
|
||||
}
|
||||
|
||||
private void OnFoldableFoldingChanged(bool folded)
|
||||
{
|
||||
UpdateFoldableTitles();
|
||||
_onChanged?.Invoke();
|
||||
RaiseLayoutSizeChanged();
|
||||
}
|
||||
|
||||
private void OnFirstResolverDropdownItemSelected(long index)
|
||||
{
|
||||
HandleResolverDropdownChanged(ResolverSlot.First, (int)index, _firstFactories, GetFirstAllowedExpectedTypes());
|
||||
}
|
||||
|
||||
private void OnSecondResolverDropdownItemSelected(long index)
|
||||
{
|
||||
HandleResolverDropdownChanged(ResolverSlot.Second, (int)index, _secondFactories, GetSecondAllowedExpectedTypes());
|
||||
}
|
||||
|
||||
private void OnThirdResolverDropdownItemSelected(long index)
|
||||
{
|
||||
HandleResolverDropdownChanged(ResolverSlot.Third, (int)index, _thirdFactories, GetThirdAllowedExpectedTypes());
|
||||
}
|
||||
|
||||
private void HandleResolverDropdownChanged(
|
||||
ResolverSlot slot,
|
||||
int index,
|
||||
List<Func<NodeEditorProperty>> factories,
|
||||
Type[] allowedExpectedTypes)
|
||||
{
|
||||
VBoxContainer? editorContainer = GetEditorContainer(slot);
|
||||
if (editorContainer is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NestedResolverEditorUtilities.ClearContainer(editorContainer);
|
||||
SetEditor(slot, null);
|
||||
ShowNestedEditor(slot, factories, index, null, allowedExpectedTypes, editorContainer);
|
||||
UpdateFoldableTitles();
|
||||
_onChanged?.Invoke();
|
||||
RaiseLayoutSizeChanged();
|
||||
}
|
||||
|
||||
private Type[] GetFirstAllowedExpectedTypes()
|
||||
{
|
||||
return GetConstrainedExpectedTypes(FirstFactoryExpectedTypes, FirstNestedExpectedType);
|
||||
}
|
||||
|
||||
private Type[] GetSecondAllowedExpectedTypes()
|
||||
{
|
||||
return GetConstrainedExpectedTypes(SecondFactoryExpectedTypes, SecondNestedExpectedType);
|
||||
}
|
||||
|
||||
private Type[] GetThirdAllowedExpectedTypes()
|
||||
{
|
||||
return GetConstrainedExpectedTypes(ThirdFactoryExpectedTypes, ThirdNestedExpectedType);
|
||||
}
|
||||
|
||||
private void SetFoldable(ResolverSlot slot, FoldableContainer foldable)
|
||||
{
|
||||
switch (slot)
|
||||
{
|
||||
case ResolverSlot.First:
|
||||
_firstFoldable = foldable;
|
||||
break;
|
||||
case ResolverSlot.Second:
|
||||
_secondFoldable = foldable;
|
||||
break;
|
||||
default:
|
||||
_thirdFoldable = foldable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetEditor(ResolverSlot slot, NodeEditorProperty? editor)
|
||||
{
|
||||
switch (slot)
|
||||
{
|
||||
case ResolverSlot.First:
|
||||
_firstEditor = editor;
|
||||
break;
|
||||
case ResolverSlot.Second:
|
||||
_secondEditor = editor;
|
||||
break;
|
||||
default:
|
||||
_thirdEditor = editor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private VBoxContainer? GetEditorContainer(ResolverSlot slot)
|
||||
{
|
||||
return slot switch
|
||||
{
|
||||
ResolverSlot.First => GetNestedEditorContainer(_firstFoldable),
|
||||
ResolverSlot.Second => GetNestedEditorContainer(_secondFoldable),
|
||||
_ => GetNestedEditorContainer(_thirdFoldable),
|
||||
};
|
||||
}
|
||||
|
||||
private void OnNestedEditorChanged()
|
||||
{
|
||||
UpdateFoldableTitles();
|
||||
_onChanged?.Invoke();
|
||||
}
|
||||
|
||||
private void UpdateFoldableTitles()
|
||||
{
|
||||
if (_firstFoldable is not null)
|
||||
{
|
||||
InlineConstantSummaryFormatter.ApplyFoldableTitle(
|
||||
FirstTitle,
|
||||
_firstFoldable,
|
||||
_firstEditor);
|
||||
}
|
||||
|
||||
if (_secondFoldable is not null)
|
||||
{
|
||||
InlineConstantSummaryFormatter.ApplyFoldableTitle(
|
||||
SecondTitle,
|
||||
_secondFoldable,
|
||||
_secondEditor);
|
||||
}
|
||||
|
||||
if (_thirdFoldable is not null)
|
||||
{
|
||||
InlineConstantSummaryFormatter.ApplyFoldableTitle(
|
||||
ThirdTitle,
|
||||
_thirdFoldable,
|
||||
_thirdEditor);
|
||||
}
|
||||
}
|
||||
|
||||
private Type[] GetConstrainedExpectedTypes(Type[] candidateExpectedTypes, Type expectedType)
|
||||
{
|
||||
return NestedResolverEditorUtilities.ConstrainExpectedTypes(
|
||||
GetAllowedExpectedTypes(expectedType),
|
||||
candidateExpectedTypes);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://mypllipf2wwh
|
||||
@@ -0,0 +1,225 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using Godot;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class UnaryNestedResolverEditorBase<TResource> : NodeEditorProperty
|
||||
where TResource : UnaryNestedResolverResourceBase, new()
|
||||
{
|
||||
private StatescriptGraph? _graph;
|
||||
private Action? _onChanged;
|
||||
private Type _expectedType = typeof(ForgeVariant128);
|
||||
private FoldableContainer? _operandFoldable;
|
||||
private OptionButton? _resolverDropdown;
|
||||
private VBoxContainer? _editorContainer;
|
||||
private NodeEditorProperty? _operandEditor;
|
||||
private List<Func<NodeEditorProperty>> _factories = [];
|
||||
|
||||
protected abstract Type[] FactoryExpectedTypes { get; }
|
||||
|
||||
protected abstract Type NestedExpectedType { get; }
|
||||
|
||||
protected virtual string OperandTitle => "Operand:";
|
||||
|
||||
public override void Setup(
|
||||
StatescriptGraph graph,
|
||||
StatescriptNodeProperty? property,
|
||||
Type expectedType,
|
||||
Action onChanged,
|
||||
bool isArray)
|
||||
{
|
||||
_graph = graph;
|
||||
_onChanged = onChanged;
|
||||
_expectedType = expectedType;
|
||||
_factories = ResolverEditorFactoryCatalog.GetCompatibleFactories(GetConstrainedExpectedTypes(expectedType));
|
||||
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
var vBox = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
AddChild(vBox);
|
||||
|
||||
if (_factories.Count == 0)
|
||||
{
|
||||
var errorLabel = new Label { Text = "No compatible resolvers." };
|
||||
errorLabel.AddThemeColorOverride("font_color", Colors.Red);
|
||||
vBox.AddChild(errorLabel);
|
||||
return;
|
||||
}
|
||||
|
||||
var existingResource = property?.Resolver as TResource;
|
||||
_operandFoldable = CreateFoldable(OperandTitle, existingResource?.OperandFolded ?? true);
|
||||
vBox.AddChild(_operandFoldable);
|
||||
|
||||
var operandContainer = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
_operandFoldable.AddChild(operandContainer);
|
||||
|
||||
_editorContainer = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
_resolverDropdown = CreateResolverDropdownControl(existingResource?.Operand);
|
||||
operandContainer.AddChild(_resolverDropdown);
|
||||
operandContainer.AddChild(_editorContainer);
|
||||
|
||||
ShowNestedEditor(GetSelectedIndex(existingResource?.Operand), existingResource?.Operand);
|
||||
_resolverDropdown.ItemSelected += OnResolverDropdownItemSelected;
|
||||
UpdateFoldableTitle();
|
||||
}
|
||||
|
||||
public override void SaveTo(StatescriptNodeProperty property)
|
||||
{
|
||||
StatescriptResolverResource? operand = null;
|
||||
|
||||
if (_operandEditor is not null)
|
||||
{
|
||||
var operandProperty = new StatescriptNodeProperty();
|
||||
_operandEditor.SaveTo(operandProperty);
|
||||
operand = operandProperty.Resolver;
|
||||
}
|
||||
|
||||
property.Resolver = new TResource
|
||||
{
|
||||
Operand = operand,
|
||||
OperandFolded = _operandFoldable?.Folded ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
public override void ClearCallbacks()
|
||||
{
|
||||
base.ClearCallbacks();
|
||||
_onChanged = null;
|
||||
_operandEditor?.ClearCallbacks();
|
||||
}
|
||||
|
||||
public override bool TryGetHighlightedVariableName(out string variableName)
|
||||
{
|
||||
if (_operandEditor is not null && _operandEditor.TryGetHighlightedVariableName(out variableName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
variableName = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TryGetHighlightedSharedVariable(out string sharedVariableSetPath, out string variableName)
|
||||
{
|
||||
if (_operandEditor is not null
|
||||
&& _operandEditor.TryGetHighlightedSharedVariable(out sharedVariableSetPath, out variableName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
sharedVariableSetPath = string.Empty;
|
||||
variableName = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual Type[] GetFactoryExpectedTypes(Type expectedType)
|
||||
{
|
||||
return FactoryExpectedTypes;
|
||||
}
|
||||
|
||||
protected virtual Type GetNestedExpectedType(Type expectedType)
|
||||
{
|
||||
return NestedExpectedType;
|
||||
}
|
||||
|
||||
private FoldableContainer CreateFoldable(string title, bool folded)
|
||||
{
|
||||
var foldable = new FoldableContainer { Title = title, Folded = folded };
|
||||
foldable.FoldingChanged += OnFoldingChanged;
|
||||
return foldable;
|
||||
}
|
||||
|
||||
private void OnFoldingChanged(bool isFolded)
|
||||
{
|
||||
UpdateFoldableTitle();
|
||||
_onChanged?.Invoke();
|
||||
RaiseLayoutSizeChanged();
|
||||
}
|
||||
|
||||
private void OnResolverDropdownItemSelected(long index)
|
||||
{
|
||||
HandleResolverDropdownChanged((int)index);
|
||||
}
|
||||
|
||||
private void HandleResolverDropdownChanged(int selectedIndex)
|
||||
{
|
||||
if (_editorContainer is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NestedResolverEditorUtilities.ClearContainer(_editorContainer);
|
||||
|
||||
_operandEditor = null;
|
||||
ShowNestedEditor(selectedIndex, null);
|
||||
UpdateFoldableTitle();
|
||||
_onChanged?.Invoke();
|
||||
RaiseLayoutSizeChanged();
|
||||
}
|
||||
|
||||
private int GetSelectedIndex(StatescriptResolverResource? existingResolver)
|
||||
{
|
||||
return NestedResolverEditorUtilities.GetSelectedIndex(_factories, existingResolver);
|
||||
}
|
||||
|
||||
private OptionButton CreateResolverDropdownControl(StatescriptResolverResource? existingResolver)
|
||||
{
|
||||
return NestedResolverEditorUtilities.CreateResolverDropdownControl(_factories, existingResolver);
|
||||
}
|
||||
|
||||
private void ShowNestedEditor(int factoryIndex, StatescriptResolverResource? existingResolver)
|
||||
{
|
||||
if (_graph is null || _editorContainer is null || factoryIndex < 0 || factoryIndex >= _factories.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NodeEditorProperty? editor = NestedResolverEditorUtilities.CreateNestedEditor(
|
||||
_graph,
|
||||
_factories,
|
||||
factoryIndex,
|
||||
existingResolver,
|
||||
GetConstrainedExpectedTypes(_expectedType),
|
||||
OnNestedEditorChanged,
|
||||
RaiseLayoutSizeChanged);
|
||||
|
||||
if (editor is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_editorContainer.AddChild(editor);
|
||||
_operandEditor = editor;
|
||||
}
|
||||
|
||||
private void OnNestedEditorChanged()
|
||||
{
|
||||
UpdateFoldableTitle();
|
||||
_onChanged?.Invoke();
|
||||
}
|
||||
|
||||
private void UpdateFoldableTitle()
|
||||
{
|
||||
if (_operandFoldable is not null)
|
||||
{
|
||||
InlineConstantSummaryFormatter.ApplyFoldableTitle(
|
||||
OperandTitle,
|
||||
_operandFoldable,
|
||||
_operandEditor);
|
||||
}
|
||||
}
|
||||
|
||||
private Type[] GetConstrainedExpectedTypes(Type expectedType)
|
||||
{
|
||||
return NestedResolverEditorUtilities.ConstrainExpectedTypes(
|
||||
GetAllowedExpectedTypes(expectedType),
|
||||
GetFactoryExpectedTypes(expectedType));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://n0pm7n7js8x4
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
using SysVector2 = System.Numerics.Vector2;
|
||||
using SysVector3 = System.Numerics.Vector3;
|
||||
using SysVector4 = System.Numerics.Vector4;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class VectorBinaryResolverEditorBase<TResource> : BinaryNestedResolverEditorBase<TResource>
|
||||
where TResource : BinaryNestedResolverResourceBase, new()
|
||||
{
|
||||
protected override Type[] FactoryExpectedTypes => [typeof(SysVector2), typeof(SysVector3), typeof(SysVector4)];
|
||||
|
||||
protected override Type NestedExpectedType => typeof(ForgeVariant128);
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
|| ResolverEditorCompatibility.IsVectorType(expectedType);
|
||||
}
|
||||
|
||||
protected override Type[] GetFactoryExpectedTypes(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
? [typeof(SysVector2), typeof(SysVector3), typeof(SysVector4)]
|
||||
: [expectedType];
|
||||
}
|
||||
|
||||
protected override Type GetNestedExpectedType(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
? typeof(ForgeVariant128)
|
||||
: expectedType;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://ferkvxbrh6o0
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
using SysQuaternion = System.Numerics.Quaternion;
|
||||
using SysVector2 = System.Numerics.Vector2;
|
||||
using SysVector3 = System.Numerics.Vector3;
|
||||
using SysVector4 = System.Numerics.Vector4;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class VectorOrQuaternionBinaryFloatResolverEditorBase<TResource>
|
||||
: BinaryNestedResolverEditorBase<TResource>
|
||||
where TResource : BinaryNestedResolverResourceBase, new()
|
||||
{
|
||||
protected override Type[] FactoryExpectedTypes =>
|
||||
[typeof(SysVector2), typeof(SysVector3), typeof(SysVector4), typeof(SysQuaternion)];
|
||||
|
||||
protected override Type NestedExpectedType => typeof(ForgeVariant128);
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128) || ResolverEditorCompatibility.IsFloatType(expectedType);
|
||||
}
|
||||
|
||||
protected override Type[] GetFactoryExpectedTypes(Type expectedType)
|
||||
{
|
||||
return FactoryExpectedTypes;
|
||||
}
|
||||
|
||||
protected override Type GetNestedExpectedType(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128) ? typeof(ForgeVariant128) : expectedType;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://bgqvyy6yj0gy4
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
using SysQuaternion = System.Numerics.Quaternion;
|
||||
using SysVector2 = System.Numerics.Vector2;
|
||||
using SysVector3 = System.Numerics.Vector3;
|
||||
using SysVector4 = System.Numerics.Vector4;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class VectorOrQuaternionUnaryFloatResolverEditorBase<TResource>
|
||||
: UnaryNestedResolverEditorBase<TResource>
|
||||
where TResource : UnaryNestedResolverResourceBase, new()
|
||||
{
|
||||
protected override Type[] FactoryExpectedTypes =>
|
||||
[typeof(SysVector2), typeof(SysVector3), typeof(SysVector4), typeof(SysQuaternion)];
|
||||
|
||||
protected override Type NestedExpectedType => typeof(ForgeVariant128);
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128) || ResolverEditorCompatibility.IsFloatType(expectedType);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://car5p5m6k82sw
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright © Gamesmiths Guild.
|
||||
|
||||
#if TOOLS
|
||||
using System;
|
||||
using Gamesmiths.Forge.Godot.Resources.Statescript.Resolvers.Bases;
|
||||
using ForgeVariant128 = Gamesmiths.Forge.Statescript.Variant128;
|
||||
using SysPlane = System.Numerics.Plane;
|
||||
using SysQuaternion = System.Numerics.Quaternion;
|
||||
using SysVector2 = System.Numerics.Vector2;
|
||||
using SysVector3 = System.Numerics.Vector3;
|
||||
using SysVector4 = System.Numerics.Vector4;
|
||||
|
||||
namespace Gamesmiths.Forge.Godot.Editor.Statescript.Resolvers.Bases;
|
||||
|
||||
internal abstract partial class VectorPlaneQuaternionUnaryResolverEditorBase<TResource>
|
||||
: UnaryNestedResolverEditorBase<TResource>
|
||||
where TResource : UnaryNestedResolverResourceBase, new()
|
||||
{
|
||||
protected override Type[] FactoryExpectedTypes =>
|
||||
[typeof(SysVector2), typeof(SysVector3), typeof(SysVector4), typeof(SysPlane), typeof(SysQuaternion)];
|
||||
|
||||
protected override Type NestedExpectedType => typeof(ForgeVariant128);
|
||||
|
||||
public override bool IsCompatibleWith(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
|| ResolverEditorCompatibility.IsVectorPlaneOrQuaternionType(expectedType);
|
||||
}
|
||||
|
||||
protected override Type[] GetFactoryExpectedTypes(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
? FactoryExpectedTypes
|
||||
: [expectedType];
|
||||
}
|
||||
|
||||
protected override Type GetNestedExpectedType(Type expectedType)
|
||||
{
|
||||
return expectedType == typeof(ForgeVariant128)
|
||||
? typeof(ForgeVariant128)
|
||||
: expectedType;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
uid://bcybyi44d61ts
|
||||
Reference in New Issue
Block a user