Hotfix
Some checks failed
FModel QA Builder / build (push) Has been cancelled

This commit is contained in:
Masusder
2026-09-23 20:04:37 +02:00
parent a9386e9594
commit f83131ad93
12 changed files with 117 additions and 94 deletions

View File

@@ -4,6 +4,7 @@
xmlns:local="clr-namespace:FModel"
xmlns:viewModels="clr-namespace:FModel.ViewModels"
xmlns:controls="clr-namespace:FModel.Views.Resources.Controls"
xmlns:explorer="clr-namespace:FModel.Views.Resources.Controls.Explorer"
xmlns:inputs="clr-namespace:FModel.Views.Resources.Controls.Inputs"
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
xmlns:settings="clr-namespace:FModel.Settings"
@@ -558,7 +559,7 @@
DataContext="{Binding CUE4Parse.AssetsFolder.SelectedFolder.PathAtThisPoint}" />
<Grid Grid.Row="2">
<ListBox x:Name="AssetsExplorer"
<explorer:AssetExplorerListBox x:Name="AssetsExplorer"
ItemsSource="{Binding CUE4Parse.AssetsFolder.SelectedFolder.CombinedEntries}"
Background="{DynamicResource {x:Static adonisUi:Brushes.Layer3BackgroundBrush}}"
PreviewKeyDown="OnPreviewKeyDown">
@@ -574,9 +575,9 @@
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
</explorer:AssetExplorerListBox>
<!-- once we need sorting, convert this to a listview (see search window) and add the header back (customize the template to re-add GridViewHeaderRowPresenter) -->
<ListBox x:Name="AssetsListExplorer"
<explorer:AssetExplorerListBox x:Name="AssetsListExplorer"
ItemsSource="{Binding CUE4Parse.AssetsFolder.SelectedFolder.CombinedEntries}"
Background="{DynamicResource {x:Static adonisUi:Brushes.Layer3BackgroundBrush}}"
PreviewKeyDown="OnPreviewKeyDown">
@@ -594,7 +595,7 @@
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
</explorer:AssetExplorerListBox>
</Grid>
</Grid>
</Border>

View File

@@ -271,21 +271,17 @@ public partial class MainWindow
if (sender is not ItemContainerGenerator { Status: GeneratorStatus.ContainersGenerated } generator)
return;
var foundVisibleItem = false;
var itemCount = generator.Items.Count;
var list = ReferenceEquals(generator, AssetsExplorer.ItemContainerGenerator) ? AssetsExplorer
: ReferenceEquals(generator, AssetsListExplorer.ItemContainerGenerator) ? AssetsListExplorer
: AssetsListName;
for (var i = 0; i < itemCount; i++)
if (!list.IsVisible || list.FindVisualChild<VirtualizingPanel>() is not { } panel)
return;
foreach (var container in panel.Children.OfType<ListBoxItem>())
{
var container = generator.ContainerFromIndex(i);
if (container == null)
if (container is FrameworkElement { IsVisible: true, DataContext: GameFileViewModel file })
{
if (foundVisibleItem) break; // we're past the visible range already
continue; // keep scrolling to find visible items
}
if (container is FrameworkElement { IsVisible: true } && generator.Items[i] is GameFileViewModel file)
{
foundVisibleItem = true;
file.OnIsVisible();
}
}
@@ -303,7 +299,6 @@ public partial class MainWindow
public void SelectFolder(TreeItem folder)
{
_applicationView.SelectedLeftTabIndex = 1;
UpdateLayout();
AssetsFolderName.SelectFolder(folder);
AssetsFolderName.FocusSelection();
}

View File

@@ -101,9 +101,9 @@ public class TreeItem : ViewModel
{
get
{
// BulkPopulate sorts Folders before this view is created
_filteredFoldersView ??= new ListCollectionView(Folders)
{
SortDescriptions = { new SortDescription(nameof(Header), ListSortDirection.Ascending) },
Filter = e => ItemFilter(e, SearchText.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries))
};
return _filteredFoldersView;

View File

@@ -0,0 +1,20 @@
using System.Collections;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using FModel.Extensions;
namespace FModel.Views.Resources.Controls.Explorer;
public class AssetExplorerListBox : ListBox
{
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
base.OnItemsSourceChanged(oldValue, newValue);
// Always start at the top, otherwise inherited offset can cause items not to be visible when we change folder
if (this.FindVisualChild<VirtualizingPanel>() is IScrollInfo scroll)
{
scroll.SetVerticalOffset(0);
}
}
}

View File

@@ -9,6 +9,16 @@
xmlns:adonisExtensions="clr-namespace:AdonisUI.Extensions;assembly=AdonisUI"
xmlns:adonisConverters="clr-namespace:AdonisUI.Converters;assembly=AdonisUI"
x:Class="FModel.Views.Resources.Controls.TiledExplorer.ResourcesDictionary">
<LinearGradientBrush x:Key="TiledFolderTabBrush" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFE8C480" Offset="0" />
<GradientStop Color="#FFD9AA63" Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="TiledFolderBodyBrush" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFF3D9A4" Offset="0" />
<GradientStop Color="#FFE5BD77" Offset="1" />
</LinearGradientBrush>
<SolidColorBrush x:Key="TiledFolderOutlineBrush" Color="#D8A360" />
<controls:TypeDataTemplateSelector x:Key="TiledExplorerTemplateSelector"
FolderTemplateKey="TiledFolderDataTemplate"
FileTemplateKey="TiledFileDataTemplate" />
@@ -69,14 +79,7 @@
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<ContentControl Content="{Binding}"
ContentTemplateSelector="{StaticResource TiledExplorerTemplateSelector}" />
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplateSelector" Value="{StaticResource TiledExplorerTemplateSelector}" />
<Setter Property="Template">
<Setter.Value>
@@ -201,7 +204,7 @@
</DataTemplate>
<DataTemplate x:Key="TiledFolderDataTemplate" DataType="{x:Type vm:TreeItem}">
<tiledExplorer:FolderButton ContextMenu="{StaticResource FolderContextMenu}" />
<tiledExplorer:FolderButton />
</DataTemplate>
<DataTemplate x:Key="ListFileDataTemplate"
@@ -211,7 +214,7 @@
<DataTemplate x:Key="ListFolderDataTemplate"
DataType="{x:Type vm:TreeItem}">
<listExplorer:FolderRow ContextMenu="{StaticResource FolderContextMenu}" />
<listExplorer:FolderRow />
</DataTemplate>
<DataTemplate x:Key="TextureNumTemplate">

View File

@@ -44,7 +44,7 @@ public partial class ResourcesDictionary
{
if (sender is not ListBoxItem item)
return;
if (item.DataContext is not GameFileViewModel)
if (item.DataContext is not (GameFileViewModel or TreeItem))
return;
var listBox = ItemsControl.ItemsControlFromItemContainer(item) as ListBox;
if (listBox == null)
@@ -57,9 +57,20 @@ public partial class ResourcesDictionary
}
item.Focus();
var contextMenu = listBox.FindResource("FileContextMenu") as ContextMenu;
var isFolder = item.DataContext is TreeItem;
var contextMenu = listBox.FindResource(isFolder ? "FolderContextMenu" : "FileContextMenu") as ContextMenu;
if (contextMenu is not null)
{
if (isFolder)
{
// Create FolderContextMenu only on right-click
listBox.ContextMenu = null;
contextMenu.PlacementTarget = item;
contextMenu.IsOpen = true;
e.Handled = true;
return;
}
listBox.ContextMenu = null;
item.Dispatcher.BeginInvoke(new Action(() =>
{

View File

@@ -20,36 +20,13 @@
<Viewbox Grid.Row="0" Height="96" VerticalAlignment="Center">
<Canvas Width="128" Height="128">
<Canvas.Resources>
<LinearGradientBrush x:Key="FolderTabGradient"
StartPoint="0,0"
EndPoint="0,1">
<GradientStop Color="#FFE8C480"
Offset="0" />
<GradientStop Color="#FFD9AA63"
Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="FolderBodyGradient"
StartPoint="0,0"
EndPoint="0,1">
<GradientStop Color="#FFF3D9A4"
Offset="0" />
<GradientStop Color="#FFE5BD77"
Offset="1" />
</LinearGradientBrush>
<SolidColorBrush x:Key="FolderOutlineBrush"
Color="#D8A360" />
</Canvas.Resources>
<Path Fill="{StaticResource FolderTabGradient}"
Stroke="{StaticResource FolderOutlineBrush}"
<Path Fill="{StaticResource TiledFolderTabBrush}"
Stroke="{StaticResource TiledFolderOutlineBrush}"
StrokeThickness="2"
Data="M20 34 H54 L62 46 H108 C112 46 115 49 115 53 V60 H13 V45 C13 39 16 34 20 34 Z" />
<Path Fill="{StaticResource FolderBodyGradient}"
Stroke="{StaticResource FolderOutlineBrush}"
<Path Fill="{StaticResource TiledFolderBodyBrush}"
Stroke="{StaticResource TiledFolderOutlineBrush}"
StrokeThickness="2"
Data="M13 60 H115 V104 C115 110 110 115 104 115 H24 C18 115 13 110 13 104 Z" />

View File

@@ -12,6 +12,9 @@ public sealed class FolderTree : ListBox
{
public static readonly DependencyProperty FoldersProperty = DependencyProperty.Register(nameof(Folders), typeof(AssetsFolderViewModel), typeof(FolderTree));
public static readonly RoutedEvent ExpandArrowEvent = EventManager.RegisterRoutedEvent("ExpandArrow", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(FolderTree));
public static readonly RoutedEvent CollapseArrowEvent = EventManager.RegisterRoutedEvent("CollapseArrow", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(FolderTree));
public AssetsFolderViewModel Folders
{
get => (AssetsFolderViewModel) GetValue(FoldersProperty);
@@ -58,12 +61,28 @@ public sealed class FolderTree : ListBox
}
}
private void ToggleFolder(TreeItem folder)
{
if (Folders == null)
return;
var wasExpanded = folder.IsExpanded;
Folders.Toggle(folder);
if (folder.IsExpanded == wasExpanded)
return;
if (ItemContainerGenerator.ContainerFromItem(folder) is ListBoxItem row)
{
row.FindVisualChild<ToggleButton>()?.RaiseEvent(new RoutedEventArgs(folder.IsExpanded ? ExpandArrowEvent : CollapseArrowEvent));
}
}
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
{
if (e.OriginalSource is DependencyObject source && source.FindAncestor<ToggleButton>() is { DataContext: TreeItem folder } && ContainerFromElement(this, source) is ListBoxItem)
{
e.Handled = true;
Folders?.Toggle(folder);
ToggleFolder(folder);
return;
}
@@ -77,7 +96,7 @@ public sealed class FolderTree : ListBox
e.Handled = true;
if (folder.Folders.Count > 0)
{
Folders?.Toggle(folder);
ToggleFolder(folder);
}
else if (folder.AssetsList.Assets.Count > 0)
{
@@ -113,7 +132,7 @@ public sealed class FolderTree : ListBox
case Key.Left:
if (folder.IsExpanded)
{
Folders?.Toggle(folder);
ToggleFolder(folder);
}
else if (folder.Parent != null)
{
@@ -123,7 +142,7 @@ public sealed class FolderTree : ListBox
case Key.Right:
if (!folder.IsExpanded)
{
Folders?.Toggle(folder);
ToggleFolder(folder);
}
else if (folder.Folders.Count > 0)
{
@@ -144,7 +163,7 @@ public sealed class FolderTree : ListBox
SelectFolder(folder);
if (!folder.IsExpanded)
{
Folders?.Toggle(folder);
ToggleFolder(folder);
}
break;
default:

View File

@@ -311,33 +311,30 @@
<Setter TargetName="Arrow"
Property="Tag"
Value="-45" />
<Trigger.EnterActions>
<BeginStoryboard x:Name="ExpandArrow">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ArrowRotation"
Storyboard.TargetProperty="Angle"
From="-90"
To="-45"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard x:Name="CollapseArrow">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ArrowRotation"
Storyboard.TargetProperty="Angle"
From="-45"
To="-90"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<!-- Don't replay animation whe not needed -->
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<RemoveStoryboard BeginStoryboardName="ExpandArrow" />
<RemoveStoryboard BeginStoryboardName="CollapseArrow" />
<EventTrigger RoutedEvent="controls:FolderTree.ExpandArrow">
<BeginStoryboard x:Name="ExpandArrow">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ArrowRotation"
Storyboard.TargetProperty="Angle"
From="-90"
To="-45"
FillBehavior="Stop"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="controls:FolderTree.CollapseArrow">
<BeginStoryboard x:Name="CollapseArrow">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ArrowRotation"
Storyboard.TargetProperty="Angle"
From="-45"
To="-90"
FillBehavior="Stop"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="FrameworkElement.Unloaded">
<RemoveStoryboard BeginStoryboardName="ExpandArrow" />

View File

@@ -56,7 +56,7 @@ public class StaticModel : UModel<MeshVertex>
Box = staticMesh.Bounds * 1.5f * Constants.SCALE_DOWN_RATIO;
}
public StaticModel(UPaperSprite paperSprite, UTexture2D texture) : base(paperSprite)
public StaticModel(UPaperSprite paperSprite) : base(paperSprite)
{
Indices = new uint[paperSprite.BakedRenderData.Length];
for (int i = 0; i < Indices.Length; i++)
@@ -97,7 +97,7 @@ public class StaticModel : UModel<MeshVertex>
{
Materials[0] = new Material();
}
Materials[0].Parameters.Textures[CMaterialParams2.FallbackDiffuse] = texture;
Materials[0].Parameters.Textures[CMaterialParams2.FallbackDiffuse] = paperSprite.BakedSourceTexture;
Materials[0].IsUsed = true;
Sections = new Section[1];

View File

@@ -460,7 +460,7 @@ public class Renderer : IDisposable
return;
}
Options.Models[guid] = new StaticModel(original, texture);
Options.Models[guid] = new StaticModel(original);
Options.SelectModel(guid);
}
@@ -804,8 +804,8 @@ public class Renderer : IDisposable
private void WorldTextureData(Material material, UObject textureData, string name, string key)
{
if (textureData.TryGetValue(out FPackageIndex package, name) && package.Load() is UTexture2D texture)
material.Parameters.Textures[key] = texture;
if (textureData.TryGetValue(out FPackageIndex package, name))
material.Parameters.Textures[key] = package;
}
private void AdditionalWorlds(UObject actor, Matrix4x4 relation, CancellationToken cancellationToken)