Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -854,9 +854,9 @@
<!-- Providers for floating-point number -->
<DataTemplate x:Key="FloatEditorTemplate" DataType="cpqvm:NodeViewModel">
<sd:NumericTextBox x:Name="NumericTextBox"
Value="{Binding NodeValue, Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDecimal}}, UpdateSourceTrigger=Explicit}"
Minimum="{Binding [Minimum], Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDecimal}}, FallbackValue={x:Static s:Decimal.MinValue}}"
Maximum="{Binding [Maximum], Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDecimal}}, FallbackValue={x:Static s:Decimal.MaxValue}}">
Value="{Binding NodeValue, Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDouble}}, UpdateSourceTrigger=Explicit}"
Minimum="{Binding [Minimum], Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDouble}}, FallbackValue={x:Static s:Decimal.MinValue}}"
Maximum="{Binding [Maximum], Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDouble}}, FallbackValue={x:Static s:Decimal.MaxValue}}">
<Interaction.Behaviors>
<DataTriggerBehavior Binding="{Binding NodeValue}" Value="{x:Static cpqvm:NodeViewModel.DifferentValues}">
<ChangePropertyAction PropertyName="Watermark" Value="{sd:LocalizeString (Different values)}"/>
Expand All @@ -872,9 +872,9 @@
<!-- Providers for fixed-point number -->
<DataTemplate x:Key="IntEditorTemplate" DataType="cpqvm:NodeViewModel">
<sd:NumericTextBox x:Name="NumericTextBox"
Value="{Binding NodeValue, Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDecimal}}, UpdateSourceTrigger=Explicit}"
Minimum="{Binding [Minimum], Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDecimal}}, FallbackValue={x:Static s:Decimal.MinValue}}"
Maximum="{Binding [Maximum], Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDecimal}}, FallbackValue={x:Static s:Decimal.MaxValue}}">
Value="{Binding NodeValue, Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDouble}}, UpdateSourceTrigger=Explicit}"
Minimum="{Binding [Minimum], Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDouble}}, FallbackValue={x:Static s:Decimal.MinValue}}"
Maximum="{Binding [Maximum], Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDouble}}, FallbackValue={x:Static s:Decimal.MaxValue}}">
<Interaction.Behaviors>
<DataTriggerBehavior Binding="{Binding NodeValue}" Value="{x:Static cpqvm:NodeViewModel.DifferentValues}">
<ChangePropertyAction PropertyName="Watermark" Value="{sd:LocalizeString (Different values)}"/>
Expand Down Expand Up @@ -918,9 +918,9 @@
LargeChange="{Binding [LargeStep], Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDouble}}}"/>
<sd:NumericTextBox Grid.Column="1"
Margin="6,2,2,2"
Value="{Binding NodeValue, Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDecimal}}, UpdateSourceTrigger=Explicit}"
Minimum="{Binding [Minimum], Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDecimal}}, FallbackValue={x:Static s:Decimal.MinValue}}"
Maximum="{Binding [Maximum], Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDecimal}}, FallbackValue={x:Static s:Decimal.MaxValue}}">
Value="{Binding NodeValue, Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDouble}}, UpdateSourceTrigger=Explicit}"
Minimum="{Binding [Minimum], Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDouble}}, FallbackValue={x:Static s:Decimal.MinValue}}"
Maximum="{Binding [Maximum], Converter={sd:Chained {caec:DifferentValuesToNull}, {sd:ToDouble}}, FallbackValue={x:Static s:Decimal.MaxValue}}">
<Interaction.Behaviors>
<DataTriggerBehavior Binding="{Binding NodeValue}" Value="{x:Static cpqvm:NodeViewModel.DifferentValues}">
<ChangePropertyAction PropertyName="Watermark" Value="{sd:LocalizeString (Different values)}"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ public sealed class AssetCollectionViewModel : DispatcherViewModel
private readonly ObservableSet<object> selectedContent = [];
private object? singleSelectedContent;

private bool discardSelectionChanges;

public AssetCollectionViewModel(SessionViewModel session)
: base(session.ServiceProvider)
: base(session.SafeArgument().ServiceProvider)
{
Session = session;

Expand Down Expand Up @@ -128,6 +130,11 @@ internal IReadOnlyCollection<DirectoryBaseViewModel> GetSelectedDirectories(bool
return result.ToList();
}

internal void UpdateAssetsCollection(ICollection<AssetViewModel> newAssets)
{
UpdateAssetsCollection(newAssets, true);
}

private void AssetsCollectionInDirectoryChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
// If the changes are too important, rebuild completely the collection.
Expand Down Expand Up @@ -190,6 +197,9 @@ private async void SelectedContentCollectionChanged(object? sender, NotifyCollec
}
}

if (discardSelectionChanges)
return;

AssetViewProperties.UpdateTypeAndName(SelectedAssets, x => x.TypeDisplayName, x => x.Url, "assets");
await AssetViewProperties.GenerateSelectionPropertiesAsync(SelectedAssets);
}
Expand Down Expand Up @@ -219,7 +229,7 @@ private void UpdateAssetsCollection(ICollection<AssetViewModel> newAssets, bool
// If the selection can be restored as it is currently, prevent the CollectionChanged handler to rebuild the view model for nothing.
if (previousSelection.Count == SelectedAssets.Count)
{
//discardSelectionChanges = true;
discardSelectionChanges = true;
}

assets.Clear();
Expand All @@ -233,7 +243,7 @@ private void UpdateAssetsCollection(ICollection<AssetViewModel> newAssets, bool

//RefreshFilters();

//discardSelectionChanges = false;
discardSelectionChanges = false;
}

private void UpdateLocations()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.

using Stride.Core.Assets.Presentation.ViewModels;
using Stride.Core.Extensions;
using Stride.Core.Presentation.ViewModels;

namespace Stride.Core.Assets.Editor.ViewModels;

/// <summary>
/// A view model that represents the referencers and referencees of a selection of asset.
/// </summary>
public sealed class ReferencesViewModel : DispatcherViewModel
{
/// <summary>
/// The asset collection view model of assets for which we want to gather references.
/// </summary>
private readonly AssetCollectionViewModel assetCollection;
/// <summary>
/// The collection of referencers for the current selection of assets.
/// </summary>
private readonly HashSet<AssetViewModel> referencerAssets = [];
/// <summary>
/// The collection of referencees for the current selection of assets.
/// </summary>
private readonly HashSet<AssetViewModel> referencedAssets = [];
private bool showReferencers;
private string typeCountersAsText = "";

public ReferencesViewModel(SessionViewModel session)
: base(session.SafeArgument().ServiceProvider)
{
assetCollection = session.AssetCollection;
DisplayedReferences = new AssetCollectionViewModel(session);

assetCollection.SelectedAssets.CollectionChanged += (_, _) => RefreshReferences();
session.AssetPropertiesChanged += (_, _) => Dispatcher.Invoke(RefreshReferences);
}

/// <summary>
/// Gets the <see cref="AssetCollectionViewModel"/> that should be currently displayed according to other properties values.
/// </summary>
public AssetCollectionViewModel DisplayedReferences { get; }

/// <summary>
/// Gets or sets whether to show the referencers of the selection of assets. If <c>false</c>, the referenced assets will be displayed instead.
/// </summary>
public bool ShowReferencers
{
get => showReferencers;
set => SetValue(ref showReferencers, value, UpdateDisplayedContent);
}

/// <summary>
/// Gets the counter of asset references grouped by types.
/// </summary>
public string TypeCountersAsText
{
get => typeCountersAsText;
private set => SetValue(ref typeCountersAsText, value);
}

/// <summary>
/// Rebuilds the references collections from the current selection in the asset view model collection passed to the constructor of this instance.
/// </summary>
private void RefreshReferences()
{
Dispatcher.EnsureAccess();

var referencers = assetCollection.SelectedAssets.SelectMany(x => x.Dependencies.ReferencerAssets);
referencerAssets.Clear();
referencerAssets.AddRange(referencers);

var referenced = AssetViewModel.ComputeRecursiveReferencedAssets(assetCollection.SelectedAssets);
referencedAssets.Clear();
referencedAssets.AddRange(referenced);

UpdateDisplayedContent();
}

/// <summary>
/// Updates the <see cref="DisplayedReferences"/> collection.
/// </summary>
private void UpdateDisplayedContent()
{
var assets = ShowReferencers ? referencerAssets : referencedAssets;

DisplayedReferences.UpdateAssetsCollection(assets);
UpdateStats(assets);
}

/// <summary>
/// Updates the <see cref="TypeCountersAsText"/> property.
/// </summary>
/// <param name="assets"></param>
private void UpdateStats(IEnumerable<AssetViewModel> assets)
{
var typeCounters = assets.GroupBy(a => a.TypeDisplayName).Select(grp =>
{
var count = grp.Count();
return $"{count} {Pluralize(grp.Key, count)}";
});
TypeCountersAsText = string.Join(", ", typeCounters);
}

private static string Pluralize(string word, int count)
{
if (count == 1)
return word;

// special case
return string.Equals(word, "entity", StringComparison.OrdinalIgnoreCase)
? $"{word[..^1]}es"
: $"{word}s";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ private SessionViewModel(IViewModelServiceProvider serviceProvider, PackageSessi
// Initialize logs
AssetLog = new AssetLogViewModel(ServiceProvider, this);

// Initialize the reference view model related to the main asset view
References = new ReferencesViewModel(this);

// Construct package categories
var localPackageName = session.SolutionPath != null ? string.Format(Tr._(@"Solution '{0}'"), session.SolutionPath.GetFileNameWithoutExtension()) : LocalPackageCategoryName;
packageCategories.Add(LocalPackageCategoryName, new PackageCategoryViewModel(localPackageName, this));
Expand Down Expand Up @@ -173,6 +176,8 @@ private set

public IReadOnlyDictionary<string, PackageCategoryViewModel> PackageCategories => packageCategories;

public ReferencesViewModel References { get; }

public UFile SolutionPath => session.SolutionPath;

public IAssetSourceTrackerViewModel SourceTracker { get; private set; }
Expand Down
45 changes: 43 additions & 2 deletions sources/editor/Stride.GameStudio.Avalonia/Views/MainView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sd="http://schemas.stride3d.net/xaml/presentation"
xmlns:caect="using:Stride.Core.Assets.Editor.Components.Transactions"
xmlns:caevm="using:Stride.Core.Assets.Editor.ViewModels"
xmlns:capvm="using:Stride.Core.Assets.Presentation.ViewModels"
xmlns:cpc="using:Stride.Core.Presentation.Commands"
xmlns:gsc="using:Stride.GameStudio.Avalonia.Converters"
xmlns:gsh="using:Stride.GameStudio.Avalonia.Helpers"
xmlns:gsvm="using:Stride.GameStudio.Avalonia.ViewModels"
xmlns:gsvw="using:Stride.GameStudio.Avalonia.Views"
Expand Down Expand Up @@ -161,9 +164,47 @@
</ListBox>
</TabItem>
<TabItem Header="References">

<DockPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<ToggleButton IsChecked="{Binding !Session.References.ShowReferencers}" Content="{sd:LocalizeString References}" MinWidth="80"/>
<ToggleButton IsChecked="{Binding Session.References.ShowReferencers}" Content="{sd:LocalizeString Referenced by}" MinWidth="80"/>
</StackPanel>
<Border DockPanel.Dock="Bottom"
Padding="8,4">
<TextBlock Text="{Binding Session.References.TypeCountersAsText}"
TextTrimming="CharacterEllipsis" TextWrapping="NoWrap">
<ToolTip.Tip>
<TextBlock Text="{Binding Session.References.TypeCountersAsText}"
TextTrimming="None" TextWrapping="Wrap"/>
</ToolTip.Tip>
</TextBlock>
</Border>
<ListBox ItemsSource="{Binding Session.References.DisplayedReferences.Assets}"
Margin="4">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type capvm:AssetViewModel}">
<StackPanel Orientation="Horizontal">
<Interaction.Behaviors>
<EventTriggerBehavior EventName="DoubleTapped">
<InvokeCommandAction Command="{Binding ((caevm:SessionViewModel)Session).AssetCollection.SelectAssetCommand}"
CommandParameter="{Binding}"/>
</EventTriggerBehavior>
</Interaction.Behaviors>
<TextBlock Text="Asset: " />
<TextBlock Text="{Binding Name}" />
<Image Source="{Binding ThumbnailData.Presenter, Converter={gsc:StrideImage}, FallbackValue={x:Static AvaloniaProperty.UnsetValue}}"
Width="64" Height="64"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
</DockPanel>
</TabItem>

</TabControl>
</Grid>
</Grid>
Expand Down
Loading