Skip to content

Commit e68c292

Browse files
authored
Merge pull request stride3d#2756 from Color-Rise/feature/xplat/node-commands
feat: node commands and updaters (property grid)
2 parents 43b8cb2 + df3d891 commit e68c292

File tree

46 files changed

+1492
-877
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1492
-877
lines changed

sources/Directory.Packages.props

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@
115115
</ItemGroup>
116116
<!-- Avalonia dependencies -->
117117
<PropertyGroup>
118-
<AvaloniaVersion>11.2.6</AvaloniaVersion>
118+
<AvaloniaVersion>11.2.7</AvaloniaVersion>
119+
<AvaloniaBehaviorVersion>11.2.7.3</AvaloniaBehaviorVersion>
119120
</PropertyGroup>
120121
<ItemGroup>
121122
<PackageVersion Include="Avalonia" Version="$(AvaloniaVersion)" />
@@ -124,7 +125,8 @@
124125
<PackageVersion Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)" />
125126
<PackageVersion Include="Avalonia.Fonts.Inter" Version="$(AvaloniaVersion)" />
126127
<PackageVersion Include="Avalonia.Themes.Fluent" Version="$(AvaloniaVersion)" />
127-
<PackageVersion Include="Avalonia.Xaml.Interactions" Version="$(AvaloniaVersion)" />
128+
<PackageVersion Include="Avalonia.Xaml.Behaviors " Version="$(AvaloniaBehaviorVersion)" />
129+
<PackageVersion Include="Avalonia.Xaml.Interactions" Version="$(AvaloniaBehaviorVersion)" />
128130
<PackageVersion Include="Markdown.Avalonia.Tight" Version="11.0.2" />
129131
</ItemGroup>
130132
<!-- Windows/WPF dependencies -->

sources/editor/Stride.Assets.Editor.Avalonia/StrideEditorViewPlugin.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ public override void RegisterAssetPreviewViewTypes(IDictionary<Type, Type> asset
6565
}
6666
}
6767

68+
public override void RegisterPrimitiveTypes(ICollection<Type> primitiveTypes)
69+
{
70+
// nothing for now
71+
}
72+
6873
public override void RegisterTemplateProviders(ICollection<ITemplateProvider> templateProviders)
6974
{
7075
foreach (var (_, value) in new EntityPropertyTemplateProviders())

sources/editor/Stride.Assets.Editor.Avalonia/Views/EntityPropertyTemplateProviders.axaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
<UniformGrid Rows="1" DockPanel.Dock="Right">
9090
<Button IsVisible="{Binding [HasCommand_PickupEntity]}"
9191
Command="{Binding [PickupEntity]}"
92-
CommandParameter="{sd:MultiBinding {Binding [OwnerAsset]}, {Binding Source={x:Null}},
92+
CommandParameter="{sd:MultiBinding {Binding [OwnerAsset]}, {Binding Source={x:Static AvaloniaProperty.UnsetValue}},
9393
Converter={sd:MultiToTuple}}"
9494
ToolTip.Tip="{sd:LocalizeString Select an asset, Context=ToolTip}">
9595
<Image Source="{StaticResource ImagePickup}" Width="16" Height="16"/>
@@ -138,7 +138,7 @@
138138
IsEnabled="{Binding #InstanceTypeSelectionComboBox.SelectedItem, Converter={sd:ObjectToBool}}">
139139
<InvokeCommandAction Command="{Binding [AddNewItem]}"
140140
CommandParameter="{Binding #InstanceTypeSelectionComboBox.SelectedItem}"/>
141-
<sd:ChangePropertyAction PropertyName="SelectedItem" Value="{x:Null}"/>
141+
<ChangePropertyAction PropertyName="SelectedItem" Value="{x:Null}"/>
142142
</EventTriggerBehavior>
143143
</Interaction.Behaviors>
144144
</ComboBox>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
2+
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
3+
4+
using Stride.Assets.Editor.ViewModels;
5+
using Stride.Assets.Presentation.ViewModels;
6+
using Stride.Core;
7+
using Stride.Core.Assets.Editor.Services;
8+
using Stride.Core.Presentation.Quantum.Presenters;
9+
using Stride.Engine;
10+
11+
namespace Stride.Assets.Editor.Quantum.NodePresenters.Commands;
12+
13+
internal sealed class FetchEntityCommand : SyncNodePresenterCommandBase
14+
{
15+
/// <summary>
16+
/// The name of this command.
17+
/// </summary>
18+
public const string CommandName = "FetchEntity";
19+
20+
/// <inheritdoc/>
21+
public override string Name => CommandName;
22+
23+
public override bool CanAttach(INodePresenter nodePresenter)
24+
{
25+
return typeof(Entity).IsAssignableFrom(nodePresenter.Type) || typeof(EntityComponent).IsAssignableFrom(nodePresenter.Type);
26+
}
27+
28+
protected override void ExecuteSync(INodePresenter nodePresenter, object? parameter, object? preExecuteResult)
29+
{
30+
if (parameter is EntityHierarchyViewModel hierarchy)
31+
{
32+
Fetch(hierarchy, nodePresenter.Value);
33+
}
34+
}
35+
36+
/// <summary>
37+
/// Fetches the entity corresponding to the given content.
38+
/// </summary>
39+
/// <param name="hierarchy">The hierarchy owning the entity to fetch.</param>
40+
/// <param name="content">The entity to fetch, or one of its components.</param>
41+
public static void Fetch(EntityHierarchyViewModel hierarchy, object content)
42+
{
43+
var entity = content is EntityComponent component ? component.Entity : content as Entity;
44+
if (entity is null)
45+
return;
46+
47+
if (!hierarchy.ServiceProvider.Get<IAssetEditorsManager>().TryGetAssetEditor<EntityHierarchyEditorViewModel>(hierarchy, out var editor))
48+
return;
49+
50+
var partId = new AbsoluteId(hierarchy.Id, entity.Id);
51+
if (editor.FindPartViewModel(partId) is not EntityViewModel viewModel)
52+
return;
53+
54+
editor.SelectedItems.Clear();
55+
editor.SelectedItems.Add(viewModel);
56+
// FIXME xplat-editor
57+
//editor.Controller.GetService<IEditorGameEntityCameraViewModelService>().CenterOnEntity(viewModel);
58+
}
59+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
2+
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
3+
4+
using Stride.Assets.Presentation.ViewModels;
5+
using Stride.Core.Assets.Editor.Quantum.NodePresenters.Commands;
6+
using Stride.Core.Presentation.Quantum.Presenters;
7+
using Stride.Engine;
8+
9+
namespace Stride.Assets.Editor.Quantum.NodePresenters.Commands;
10+
11+
internal sealed class SetComponentReferenceCommand : ChangeValueCommandBase
12+
{
13+
public record struct Parameter(EntityViewModel Entity, int Index);
14+
15+
/// <summary>
16+
/// The name of this command.
17+
/// </summary>
18+
public const string CommandName = "SetComponentReference";
19+
20+
/// <inheritdoc/>
21+
public override string Name => CommandName;
22+
23+
/// <inheritdoc/>
24+
public override bool CanAttach(INodePresenter nodePresenter)
25+
{
26+
return typeof(EntityComponent).IsAssignableFrom(nodePresenter.Type);
27+
}
28+
29+
/// <inheritdoc/>
30+
protected override object? ChangeValue(object currentValue, object? parameter, object? preExecuteResult)
31+
{
32+
return parameter is Parameter param ? param.Entity?.AssetSideEntity.Components[param.Index] : null;
33+
}
34+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
2+
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
3+
4+
using Stride.Assets.Presentation.ViewModels;
5+
using Stride.Core.Assets.Editor.Quantum.NodePresenters.Commands;
6+
using Stride.Core.Presentation.Quantum.Presenters;
7+
using Stride.Engine;
8+
9+
namespace Stride.Assets.Editor.Quantum.NodePresenters.Commands;
10+
11+
internal sealed class SetEntityReferenceCommand : ChangeValueCommandBase
12+
{
13+
/// <summary>
14+
/// The name of this command.
15+
/// </summary>
16+
public const string CommandName = "SetEntityReference";
17+
18+
/// <inheritdoc/>
19+
public override string Name => CommandName;
20+
21+
/// <inheritdoc/>
22+
public override bool CanAttach(INodePresenter nodePresenter)
23+
{
24+
return typeof(Entity).IsAssignableFrom(nodePresenter.Type);
25+
}
26+
27+
/// <inheritdoc/>
28+
protected override object? ChangeValue(object currentValue, object? parameter, object? preExecuteResult)
29+
{
30+
return (parameter as EntityViewModel)?.AssetSideEntity;
31+
}
32+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
2+
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
3+
4+
using Stride.Core;
5+
using Stride.Rendering.Compositing;
6+
7+
namespace Stride.Assets.Editor.Quantum.NodePresenters.Keys;
8+
9+
internal static class CameraSlotData
10+
{
11+
public const string SceneCameraSlots = nameof(SceneCameraSlots);
12+
public const string UpdateCameraSlotIndex = nameof(UpdateCameraSlotIndex);
13+
14+
public static readonly PropertyKey<List<SceneCameraSlot>> CameraSlotsKey = new(SceneCameraSlots, typeof(CameraSlotData));
15+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
2+
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
3+
4+
using Stride.Core.Presentation.Quantum.Presenters;
5+
using Stride.Core;
6+
using Stride.Core.Assets.Editor.Quantum.NodePresenters.Commands;
7+
using Stride.Core.Assets.Editor.Quantum.NodePresenters.Keys;
8+
9+
namespace Stride.Assets.Editor.Quantum.NodePresenters.Keys;
10+
11+
internal static class EntityHierarchyData
12+
{
13+
public const string EntityComponentAvailableTypes = nameof(EntityComponentAvailableTypes);
14+
public static readonly PropertyKey<IEnumerable<AbstractNodeType>> EntityComponentAvailableTypesKey = new(EntityComponentAvailableTypes, typeof(EntityHierarchyData), new PropertyCombinerMetadata(AbstractNodeEntryData.CombineProperty));
15+
16+
public const string EntityComponentAvailableTypeGroups = nameof(EntityComponentAvailableTypeGroups);
17+
public static readonly PropertyKey<IEnumerable<AbstractNodeTypeGroup>> EntityComponentAvailableTypeGroupsKey = new(EntityComponentAvailableTypeGroups, typeof(EntityHierarchyData), new PropertyCombinerMetadata(AbstractNodeEntryData.CombineProperty));
18+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
2+
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
3+
4+
using Stride.Core;
5+
6+
namespace Stride.Assets.Editor.Quantum.NodePresenters.Keys;
7+
8+
internal static class MaterialData
9+
{
10+
public const string AvailableEffectShaders = nameof(AvailableEffectShaders);
11+
public static readonly PropertyKey<IEnumerable<string>> Key = new(AvailableEffectShaders, typeof(MaterialData));
12+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
2+
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
3+
4+
using Stride.Assets.Models;
5+
using Stride.Assets.Presentation.ViewModels;
6+
using Stride.Core.Assets.Presentation.Quantum.NodePresenters;
7+
8+
namespace Stride.Assets.Editor.Quantum.NodePresenters.Updaters;
9+
10+
internal sealed class AnimationAssetNodeUpdater : AssetNodePresenterUpdaterBase
11+
{
12+
protected override void UpdateNode(IAssetNodePresenter node)
13+
{
14+
if (node.Asset is not AnimationViewModel)
15+
return;
16+
17+
if (node.Name is nameof(AnimationAsset.AnimationTimeMinimum) or nameof(AnimationAsset.AnimationTimeMaximum))
18+
node.IsVisible = false;
19+
20+
// Base clip duration
21+
if (node.Name is nameof(AnimationAssetDuration.StartAnimationTime) or nameof(AnimationAssetDuration.EndAnimationTime))
22+
{
23+
var childNode = node.Parent[nameof(AnimationAssetDuration.Enabled)];
24+
25+
if (childNode != null && childNode.Value.ToString().ToLowerInvariant().Equals("false"))
26+
node.IsVisible = false;
27+
else
28+
node.IsVisible = true;
29+
}
30+
31+
// Reference clip duration
32+
if (node.Name is nameof(AnimationAssetDurationUnchecked.StartAnimationTimeBox) or nameof(AnimationAssetDurationUnchecked.EndAnimationTimeBox))
33+
{
34+
var childNode = node.Parent[nameof(AnimationAssetDurationUnchecked.Enabled)];
35+
36+
if (childNode != null && childNode.Value.ToString().ToLowerInvariant().Equals("false"))
37+
node.IsVisible = false;
38+
else
39+
node.IsVisible = true;
40+
}
41+
42+
// If there is a skeleton, hide ScaleImport and PivotPosition (they are overriden by skeleton values)
43+
if (typeof(AnimationAsset).IsAssignableFrom(node.Type))
44+
{
45+
if (node[nameof(AnimationAsset.Skeleton)].Value != null)
46+
{
47+
node[nameof(AnimationAsset.PivotPosition)].IsVisible = false;
48+
node[nameof(AnimationAsset.ScaleImport)].IsVisible = false;
49+
}
50+
51+
// Add dependency to reevaluate if value changes
52+
node.AddDependency(node[nameof(AnimationAsset.Skeleton)], false);
53+
}
54+
}
55+
56+
protected override void FinalizeTree(IAssetNodePresenter root)
57+
{
58+
var asset = root.Asset?.Asset as AnimationAsset;
59+
if (asset?.Type is DifferenceAnimationAssetType)
60+
{
61+
var clipDuration = root[nameof(AnimationAsset.Type)][nameof(DifferenceAnimationAssetType.ClipDuration)];
62+
var mode = root[nameof(AnimationAsset.Type)][nameof(DifferenceAnimationAssetType.Mode)];
63+
clipDuration.AddDependency(mode, false);
64+
65+
var enabledNode = clipDuration[nameof(AnimationAssetDurationUnchecked.Enabled)];
66+
67+
var startNode = clipDuration[nameof(AnimationAssetDurationUnchecked.StartAnimationTimeBox)];
68+
startNode.AddDependency(enabledNode, false);
69+
70+
var endNode = clipDuration[nameof(AnimationAssetDurationUnchecked.EndAnimationTimeBox)];
71+
endNode.AddDependency(enabledNode, false);
72+
}
73+
74+
if (asset != null)
75+
{
76+
var enabledNode = root[nameof(AnimationAsset.ClipDuration)][nameof(AnimationAssetDuration.Enabled)];
77+
78+
var startNode = root[nameof(AnimationAsset.ClipDuration)][nameof(AnimationAssetDuration.StartAnimationTime)];
79+
startNode.AddDependency(enabledNode, false);
80+
81+
var endNode = root[nameof(AnimationAsset.ClipDuration)][nameof(AnimationAssetDuration.EndAnimationTime)];
82+
endNode.AddDependency(enabledNode, false);
83+
}
84+
}
85+
}

0 commit comments

Comments
 (0)