New Explorer System (#619)
Some checks failed
FModel QA Builder / build (push) Has been cancelled

+ filter by types, find by references (UE5+), and a lot of other improvements

Co-authored-by: Asval <asval.contactme@gmail.com>
Co-authored-by: LongerWarrior <LongerWarrior@gmail.com>
This commit is contained in:
Masusder 2025-12-19 18:34:33 +01:00 committed by GitHub
parent 5776444020
commit 8b95b403bb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
78 changed files with 4437 additions and 1355 deletions

@ -1 +1 @@
Subproject commit 7772c6ccf0f6f195876d20d4b5d49fe533fc564e
Subproject commit d2f6ce6e618576dbbe7f6dd9ed3171f14513182a

View File

@ -1,4 +1,4 @@
<Application x:Class="FModel.App"
<Application x:Class="FModel.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
@ -9,6 +9,14 @@
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/AdonisUI;component/ColorSchemes/Dark.xaml"/>
<ResourceDictionary Source="pack://application:,,,/AdonisUI.ClassicTheme;component/Resources.xaml"/>
<ResourceDictionary Source="Views/Resources/Colors.xaml" />
<ResourceDictionary Source="Views/Resources/Icons.xaml" />
<ResourceDictionary Source="Views/Resources/Controls/ContextMenus/FileContextMenu.xaml" />
<ResourceDictionary Source="Views/Resources/Controls/ContextMenus/FolderContextMenu.xaml" />
<ResourceDictionary Source="Views/Resources/Resources.xaml" />
<ResourceDictionary Source="Views/Resources/Controls/TiledExplorer/Resources.xaml" />
</ResourceDictionary.MergedDictionaries>
<Color x:Key="{x:Static adonisUi:Colors.AccentColor}">#206BD4</Color>

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Diagnostics;
using System.IO;
using System.Numerics;
@ -13,6 +13,7 @@ public static class Constants
public static readonly string APP_VERSION = FileVersionInfo.GetVersionInfo(APP_PATH).FileVersion;
public static readonly string APP_COMMIT_ID = FileVersionInfo.GetVersionInfo(APP_PATH).ProductVersion?.SubstringAfter('+');
public static readonly string APP_SHORT_COMMIT_ID = APP_COMMIT_ID[..7];
public static readonly DateTime APP_BUILD_DATE = File.GetLastWriteTime(APP_PATH);
public const string ZERO_64_CHAR = "0000000000000000000000000000000000000000000000000000000000000000";
public static readonly FGuid ZERO_GUID = new(0U);

View File

@ -33,6 +33,7 @@ public class CreatorPackage : IDisposable
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryConstructCreator([MaybeNullWhen(false)] out UCreator creator)
{
// TODO: convert to a type based system
switch (_exportType)
{
// Fortnite
@ -51,7 +52,7 @@ public class CreatorPackage : IDisposable
case "CosmeticCompanionReactFXItemDefinition":
case "AthenaPickaxeItemDefinition":
case "AthenaGadgetItemDefinition":
case "AthenaGliderItemDefinition":
case "AthenaGliderItemDefinition":
case "AthenaHatItemDefinition":
case "AthenaSprayItemDefinition":
case "AthenaDanceItemDefinition":

View File

@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
using FModel.Extensions;
namespace FModel;
@ -65,16 +66,6 @@ public enum ELoadingMode
AllButPatched,
}
// public enum EUpdateMode
// {
// [Description("Stable")]
// Stable,
// [Description("Beta")]
// Beta,
// [Description("QA Testing")]
// Qa
// }
public enum ECompressedAudio
{
[Description("Play the decompressed data")]
@ -117,3 +108,43 @@ public enum EBulkType
Animations = 1 << 5,
Audio = 1 << 6
}
public enum EAssetCategory : uint
{
All = AssetCategoryExtensions.CategoryBase + (0 << 16),
Blueprints = AssetCategoryExtensions.CategoryBase + (1 << 16),
BlueprintGeneratedClass = Blueprints + 1,
WidgetBlueprintGeneratedClass = Blueprints + 2,
AnimBlueprintGeneratedClass = Blueprints + 3,
RigVMBlueprintGeneratedClass = Blueprints + 4,
UserDefinedEnum = Blueprints + 5,
UserDefinedStruct = Blueprints + 6,
//Metadata
Blueprint = Blueprints + 8,
CookedMetaData = Blueprints + 9,
Mesh = AssetCategoryExtensions.CategoryBase + (2 << 16),
StaticMesh = Mesh + 1,
SkeletalMesh = Mesh + 2,
Skeleton = Mesh + 3,
Texture = AssetCategoryExtensions.CategoryBase + (3 << 16),
Materials = AssetCategoryExtensions.CategoryBase + (4 << 16),
Material = Materials + 1,
MaterialEditorData = Materials + 2,
MaterialFunction = Materials + 3,
MaterialParameterCollection = Materials + 4,
Animation = AssetCategoryExtensions.CategoryBase + (5 << 16),
Level = AssetCategoryExtensions.CategoryBase + (6 << 16),
World = Level + 1,
BuildData = Level + 2,
LevelSequence = Level + 3,
Foliage = Level + 4,
Data = AssetCategoryExtensions.CategoryBase + (7 << 16),
ItemDefinitionBase = Data + 1,
CurveBase = Data + 2,
PhysicsAsset = Data + 3,
Media = AssetCategoryExtensions.CategoryBase + (8 << 16),
Audio = Media + 1,
Video = Media + 2,
Font = Media + 3,
Particle = AssetCategoryExtensions.CategoryBase + (9 << 16),
}

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace FModel.Extensions;
public static class AssetCategoryExtensions
{
public const uint CategoryBase = 0x00010000;
public static EAssetCategory GetBaseCategory(this EAssetCategory category)
{
return (EAssetCategory) ((uint) category & 0xFFFF0000);
}
public static bool IsOfCategory(this EAssetCategory item, EAssetCategory category)
{
return item.GetBaseCategory() == category.GetBaseCategory();
}
public static bool IsBaseCategory(this EAssetCategory category)
{
return category == category.GetBaseCategory();
}
public static IEnumerable<EAssetCategory> GetBaseCategories()
{
return Enum.GetValues<EAssetCategory>().Where(c => c.IsBaseCategory());
}
}

View File

@ -168,8 +168,9 @@
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
<PackageReference Include="SkiaSharp.HarfBuzz" Version="2.88.9" />
<PackageReference Include="SkiaSharp.Svg" Version="1.60.0" />
<PackageReference Include="Svg.Skia" Version="3.2.1" />
<PackageReference Include="Twizzle.ImGui-Bundle.NET" Version="1.91.5.2" />
<PackageReference Include="VirtualizingWrapPanel" Version="2.3.2" />
</ItemGroup>
<ItemGroup>

View File

@ -1,26 +1,22 @@
using System;
using CUE4Parse.Compression;
using CUE4Parse.FileProvider.Objects;
using CUE4Parse.UE4.Assets.Objects;
using CUE4Parse.UE4.Readers;
namespace FModel.Framework;
public class FakeGameFile : GameFile
public class FakeGameFile(string path) : GameFile(path, 0)
{
public FakeGameFile(string path) : base(path, 0)
{
}
public override bool IsEncrypted => false;
public override CompressionMethod CompressionMethod => CompressionMethod.None;
public override byte[] Read()
public override byte[] Read(FByteBulkDataHeader? header = null)
{
throw new NotImplementedException();
}
public override FArchive CreateReader()
public override FArchive CreateReader(FByteBulkDataHeader? header = null)
{
throw new NotImplementedException();
}

View File

@ -38,7 +38,7 @@ public static class Helper
else
{
var w = GetOpenedWindow<T>(windowName);
if (windowName == "Search View") w.WindowState = WindowState.Normal;
if (windowName == "Search For Packages") w.WindowState = WindowState.Normal;
w.Focus();
}
}

View File

@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:FModel"
xmlns:controls="clr-namespace:FModel.Views.Resources.Controls"
xmlns:inputs="clr-namespace:FModel.Views.Resources.Controls.Inputs"
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
xmlns:settings="clr-namespace:FModel.Settings"
xmlns:services="clr-namespace:FModel.Services"
@ -10,8 +11,18 @@
xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI"
xmlns:adonisExtensions="clr-namespace:AdonisUI.Extensions;assembly=AdonisUI"
WindowStartupLocation="CenterScreen" Closing="OnClosing" Loaded="OnLoaded" PreviewKeyDown="OnWindowKeyDown"
Height="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenHeight}, Converter={converters:RatioConverter}, ConverterParameter='0.85'}"
Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.75'}">
Height="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenHeight}, Converter={converters:RatioConverter}, ConverterParameter='0.95'}"
Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.90'}">
<Window.TaskbarItemInfo>
<TaskbarItemInfo ProgressValue="1.0">
<TaskbarItemInfo.ProgressState>
<MultiBinding Converter="{converters:StatusToTaskbarStateConverter}">
<Binding Path="Status.Kind" />
<Binding Path="IsActive" RelativeSource="{RelativeSource AncestorType=Window}" />
</MultiBinding>
</TaskbarItemInfo.ProgressState>
</TaskbarItemInfo>
</Window.TaskbarItemInfo>
<adonisControls:AdonisWindow.Style>
<Style TargetType="adonisControls:AdonisWindow" BasedOn="{StaticResource {x:Type adonisControls:AdonisWindow}}" >
<Setter Property="Title" Value="{Binding DataContext.InitialWindowTitle, RelativeSource={RelativeSource Self}}" />
@ -30,158 +41,179 @@
</Style.Triggers>
</Style>
</adonisControls:AdonisWindow.Style>
<adonisControls:AdonisWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Views/Resources/Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</adonisControls:AdonisWindow.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="{adonisUi:Space 1}" />
<RowDefinition Height="8" />
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Menu Grid.Row="0">
<MenuItem Header="Directory">
<MenuItem Header="Selector" Command="{Binding MenuCommand}" CommandParameter="Directory_Selector">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource DirectoryIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Menu Grid.Column="0">
<MenuItem Header="Directory">
<MenuItem Header="Selector" Command="{Binding MenuCommand}" CommandParameter="Directory_Selector">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource DirectoryIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="AES" Command="{Binding MenuCommand}" CommandParameter="Directory_AES" IsEnabled="{Binding Status.IsReady}">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource KeyIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Backup" Command="{Binding MenuCommand}" CommandParameter="Directory_Backup" IsEnabled="{Binding Status.IsReady}">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource BackupIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Archives Info" Command="{Binding MenuCommand}" CommandParameter="Directory_ArchivesInfo" IsEnabled="{Binding Status.IsReady}">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource InfoIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
<MenuItem Header="AES" Command="{Binding MenuCommand}" CommandParameter="Directory_AES" IsEnabled="{Binding Status.IsReady}">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource KeyIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
<MenuItem Header="Packages">
<MenuItem Header="Search" IsEnabled="{Binding Status.IsReady}" InputGestureText="Ctrl+Shift+F" Click="OnSearchViewClick">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource SearchIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="References" IsEnabled="{Binding Status.IsReady}" InputGestureText="Ctrl+Shift+R" Click="OnRefViewClick">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource SearchIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Favorite Directories" ItemsSource="{Binding CustomDirectories.Directories}" IsEnabled="{Binding Status.IsReady}">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource DirectoriesIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
<MenuItem Header="Backup" Command="{Binding MenuCommand}" CommandParameter="Directory_Backup" IsEnabled="{Binding Status.IsReady}">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource BackupIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
<MenuItem Header="Views">
<MenuItem Header="3D Viewer" Command="{Binding MenuCommand}" CommandParameter="Views_3dViewer">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource MeshIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Audio Player" Command="{Binding MenuCommand}" CommandParameter="Views_AudioPlayer">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource AudioIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Image Merger" Command="{Binding MenuCommand}" CommandParameter="Views_ImageMerger">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource ImageMergerIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
<MenuItem Header="Archives Info" Command="{Binding MenuCommand}" CommandParameter="Directory_ArchivesInfo" IsEnabled="{Binding Status.IsReady}">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource InfoIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
<MenuItem Header="Settings" Command="{Binding MenuCommand}" CommandParameter="Settings" />
<MenuItem Header="Help" >
<MenuItem Header="Donate" Command="{Binding MenuCommand}" CommandParameter="Help_Donate">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource GiftIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Releases" Command="{Binding MenuCommand}" CommandParameter="Help_Releases">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource GitHubIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Bugs Report" Command="{Binding MenuCommand}" CommandParameter="Help_BugsReport">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource BugIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Discord Server" Command="{Binding MenuCommand}" CommandParameter="Help_Discord">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource DiscordIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="About FModel" Command="{Binding MenuCommand}" CommandParameter="Help_About">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource InfoIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</MenuItem>
<MenuItem Header="Packages">
<MenuItem Header="Search" IsEnabled="{Binding Status.IsReady}" InputGestureText="Ctrl+Shift+F" Click="OnSearchViewClick">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource SearchIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Favorite Directories" ItemsSource="{Binding CustomDirectories.Directories}" IsEnabled="{Binding Status.IsReady}">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource DirectoriesIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
<MenuItem Header="Views">
<MenuItem Header="3D Viewer" Command="{Binding MenuCommand}" CommandParameter="Views_3dViewer">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource MeshIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Audio Player" Command="{Binding MenuCommand}" CommandParameter="Views_AudioPlayer">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource AudioIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Image Merger" Command="{Binding MenuCommand}" CommandParameter="Views_ImageMerger">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource ImageMergerIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
<MenuItem Header="Settings" Command="{Binding MenuCommand}" CommandParameter="Settings" />
<MenuItem Header="Help" >
<MenuItem Header="Donate" Command="{Binding MenuCommand}" CommandParameter="Help_Donate">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource GiftIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Releases" Command="{Binding MenuCommand}" CommandParameter="Help_Releases">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource GitHubIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Bugs Report" Command="{Binding MenuCommand}" CommandParameter="Help_BugsReport">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource BugIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Discord Server" Command="{Binding MenuCommand}" CommandParameter="Help_Discord">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource DiscordIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="About FModel" Command="{Binding MenuCommand}" CommandParameter="Help_About">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource InfoIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</Menu>
</Menu>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Preview New Explorer System" VerticalAlignment="Center" />
<CheckBox Grid.Column="1" Margin="5 2 5 0" Unchecked="FeaturePreviewOnUnchecked" KeyboardNavigation.TabNavigation="None" KeyboardNavigation.ControlTabNavigation="None"
IsChecked="{Binding FeaturePreviewNewAssetExplorer, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}"
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}"/>
</Grid>
</Grid>
<Grid x:Name="RootGrid" Grid.Row="2">
<Grid.ColumnDefinitions>
@ -191,8 +223,8 @@
</Grid.ColumnDefinitions>
<GroupBox Grid.Column="0" adonisExtensions:LayerExtension.Layer="2"
Padding="{adonisUi:Space 0}" Background="Transparent">
<TabControl x:Name="LeftTabControl" SelectionChanged="OnTabItemChange">
Padding="0" Background="Transparent">
<TabControl x:Name="LeftTabControl" SelectionChanged="OnTabItemChange" SelectedIndex="{Binding SelectedLeftTabIndex, Mode=TwoWay}">
<TabItem Style="{StaticResource TabItemFillSpace}" Header="Archives">
<DockPanel>
<Grid DockPanel.Dock="Top">
@ -257,7 +289,8 @@
</Grid>
</DockPanel>
</TabItem>
<TabItem Style="{StaticResource TabItemFillSpace}" Header="Folders">
<TabItem Style="{StaticResource TabItemFillSpace}"
Header="Folders">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
@ -315,94 +348,11 @@
</StackPanel>
</Grid>
<Separator Grid.Row="1" Style="{StaticResource CustomSeparator}" Margin="0" />
<TreeView Grid.Row="2" x:Name="AssetsFolderName" Style="{StaticResource AssetsFolderTreeView}" PreviewMouseDoubleClick="OnAssetsTreeMouseDoubleClick">
<TreeView.ContextMenu>
<ContextMenu>
<!-- <MenuItem Header="Extract Folder's Packages" Click="OnFolderExtractClick"> -->
<!-- <MenuItem.Icon> -->
<!-- <Viewbox Width="16" Height="16"> -->
<!-- <Canvas Width="24" Height="24"> -->
<!-- <Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource ExtractIcon}" /> -->
<!-- </Canvas> -->
<!-- </Viewbox> -->
<!-- </MenuItem.Icon> -->
<!-- </MenuItem> -->
<!-- <Separator /> -->
<MenuItem Header="Export Folder's Packages Raw Data (.uasset)" Click="OnFolderExportClick">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource ExportIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Folder's Packages Properties (.json)" Click="OnFolderSaveClick">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource SaveIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Folder's Packages Textures" Click="OnFolderTextureClick">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource TextureIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Folder's Packages Models" Click="OnFolderModelClick">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource ModelIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Folder's Packages Animations" Click="OnFolderAnimationClick">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AnimationIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Folder's Packages Audio" Click="OnFolderAudioClick">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AudioIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="Favorite Directory" Click="OnFavoriteDirectoryClick">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource DirectoriesAddIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Copy Directory Path" Click="OnCopyDirectoryPathClick">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource CopyIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</TreeView.ContextMenu>
<TreeView Grid.Row="2"
x:Name="AssetsFolderName"
Style="{StaticResource AssetsFolderTreeView}"
PreviewKeyDown="OnFoldersPreviewKeyDown"
PreviewMouseDoubleClick="OnAssetsTreeMouseDoubleClick">
</TreeView>
<Separator Grid.Row="3" Style="{StaticResource CustomSeparator}" Tag="INFORMATION" />
<StackPanel Grid.Row="4" Orientation="Vertical" Margin="0 0 0 5">
@ -437,32 +387,11 @@
Header="{Binding SelectedItem.AssetsList.Assets.Count, FallbackValue=0, ElementName=AssetsFolderName}"
HeaderStringFormat="{}{0} Packages">
<DockPanel>
<Grid DockPanel.Dock="Top" ZIndex="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" ZIndex="1" HorizontalAlignment="Left" Margin="5 2 0 0">
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource SearchIcon}" />
</Canvas>
</Viewbox>
</Grid>
<TextBox Grid.Column="0" Grid.ColumnSpan="2" x:Name="AssetsSearchName" AcceptsTab="False" AcceptsReturn="False"
Padding="25 0 0 0" HorizontalAlignment="Stretch" TextChanged="OnFilterTextChanged"
adonisExtensions:WatermarkExtension.Watermark="Search by name..." />
<StackPanel Grid.Column="1" Orientation="Horizontal">
<Button ToolTip="Clear Search Filter" Padding="5" Style="{DynamicResource {x:Static adonisUi:Styles.ToolbarButton}}" Click="OnDeleteSearchClick">
<Viewbox Width="16" Height="16" HorizontalAlignment="Center">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource BackspaceIcon}"/>
</Canvas>
</Viewbox>
</Button>
</StackPanel>
</Grid>
<inputs:SearchTextBox DockPanel.Dock="Top" x:Name="AssetsSearchTextBox"
Text="{Binding SelectedItem.SearchText, ElementName=AssetsFolderName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ClearButtonClick="OnClearFilterClick" />
<Grid DockPanel.Dock="Top">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
@ -471,217 +400,15 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<controls:Breadcrumb Grid.Row="0" MaxWidth="{Binding ActualWidth, ElementName=AssetsSearchName}" HorizontalAlignment="Left" Margin="0 5 0 5"
<controls:Breadcrumb Grid.Row="0" HorizontalAlignment="Left" Margin="0 5 0 5"
MaxWidth="{Binding ActualWidth, ElementName=AssetsSearchTextBox}"
DataContext="{Binding SelectedItem.PathAtThisPoint, ElementName=AssetsFolderName, FallbackValue='No/Directory/Detected/In/Folder'}"/>
<ListBox Grid.Row="1" x:Name="AssetsListName" Style="{StaticResource AssetsListBox}" PreviewMouseDoubleClick="OnAssetsListMouseDoubleClick" PreviewKeyDown="OnPreviewKeyDown">
<ListBox.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Extract in New Tab" Command="{Binding DataContext.RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Extract_New_Tab" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource ExtractIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Show Metadata" Command="{Binding DataContext.RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Show_Metadata" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource InfoIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Decompile Blueprint" Command="{Binding DataContext.RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Decompile" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource InfoIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
<MenuItem.Style>
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource {x:Type MenuItem}}">
<Style.Triggers>
<DataTrigger Binding="{Binding ShowDecompileOption, Source={x:Static settings:UserSettings.Default}}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
<Separator />
<MenuItem Command="{Binding DataContext.RightClickMenuCommand}">
<MenuItem.Header>
<TextBlock
Text="{Binding DataContext.SelectedItem.Extension,
FallbackValue='Export Raw Data',
StringFormat='Export Raw Data (.{0})',
RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
</MenuItem.Header>
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Export_Data" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource ExportIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Properties (.json)" Command="{Binding DataContext.RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Save_Properties" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource SaveIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Texture" Command="{Binding DataContext.RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Save_Textures" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource TextureIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Model" Command="{Binding DataContext.RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Save_Models" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource ModelIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Animation" Command="{Binding DataContext.RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Save_Animations" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AnimationIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Audio" Command="{Binding DataContext.RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Save_Audio" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AudioIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="Copy">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource CopyIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
<MenuItem Header="Package Path" Command="{Binding DataContext.CopyCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="File_Path" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
</MenuItem>
<MenuItem Header="Package Name" Command="{Binding DataContext.CopyCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="File_Name" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
</MenuItem>
<MenuItem Header="Directory Path" Command="{Binding DataContext.CopyCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Directory_Path" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
</MenuItem>
<MenuItem Header="Package Path w/o Extension" Command="{Binding DataContext.CopyCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="File_Path_No_Extension" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
</MenuItem>
<MenuItem Header="Package Name w/o Extension" Command="{Binding DataContext.CopyCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="File_Name_No_Extension" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
</MenuItem>
</MenuItem>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
<ListBox Grid.Row="1" x:Name="AssetsListName"
Style="{StaticResource AssetsListBox}"
PreviewMouseDoubleClick="OnAssetsListMouseDoubleClick"
PreviewKeyDown="OnPreviewKeyDown" />
<Separator Grid.Row="2" Style="{StaticResource CustomSeparator}" Tag="INFORMATION" />
<StackPanel Grid.Row="3" Orientation="Vertical" Margin="0 0 0 5">
<Grid HorizontalAlignment="Stretch">
@ -697,15 +424,15 @@
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding SelectedItem.Offset, ElementName=AssetsListName, FallbackValue=0, StringFormat='{}0x{0:X}'}" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding SelectedItem.Asset.Offset, ElementName=AssetsListName, FallbackValue=0, StringFormat='{}0x{0:X}'}" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="Offset" VerticalAlignment="Center" HorizontalAlignment="Right" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding SelectedItem.Size, ElementName=AssetsListName, FallbackValue=0, Converter={x:Static converters:SizeToStringConverter.Instance}}" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding SelectedItem.Asset.Size, ElementName=AssetsListName, FallbackValue=0, Converter={x:Static converters:SizeToStringConverter.Instance}}" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Grid.Row="1" Grid.Column="1" Text="Size" VerticalAlignment="Center" HorizontalAlignment="Right" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="{Binding SelectedItem.CompressionMethod, ElementName=AssetsListName, FallbackValue='Unknown'}" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="{Binding SelectedItem.Asset.CompressionMethod, ElementName=AssetsListName, FallbackValue='Unknown'}" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Grid.Row="2" Grid.Column="1" Text="Compression Method" VerticalAlignment="Center" HorizontalAlignment="Right" />
<TextBlock Grid.Row="3" Grid.Column="0" Text="{Binding SelectedItem.IsEncrypted, ElementName=AssetsListName, FallbackValue='False'}" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Grid.Row="3" Grid.Column="0" Text="{Binding SelectedItem.Asset.IsEncrypted, ElementName=AssetsListName, FallbackValue='False'}" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Grid.Row="3" Grid.Column="1" Text="Is Encrypted" VerticalAlignment="Center" HorizontalAlignment="Right" />
<TextBlock Grid.Row="4" Grid.Column="0" Text="{Binding SelectedItem.Vfs.Name, ElementName=AssetsListName, FallbackValue='None'}" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Grid.Row="4" Grid.Column="0" Text="{Binding SelectedItem.Asset.Vfs.Name, ElementName=AssetsListName, FallbackValue='None'}" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Grid.Row="4" Grid.Column="1" Text="Included In Archive" VerticalAlignment="Center" HorizontalAlignment="Right" />
</Grid>
</StackPanel>
@ -720,14 +447,154 @@
Background="{DynamicResource {x:Static adonisUi:Brushes.Layer0BackgroundBrush}}" />
<GroupBox Grid.Column="2" adonisExtensions:LayerExtension.Layer="2"
Padding="{adonisUi:Space 0}" Background="Transparent">
Padding="0" Background="Transparent">
<Grid Margin="0 0 3 0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TabControl Grid.Row="0" x:Name="TabControlName" Style="{StaticResource GameFilesTabControl}" />
<Grid Grid.Row="0">
<Border BorderThickness="1" Padding="10"
BorderBrush="{DynamicResource {x:Static adonisUi:Brushes.Layer3BorderBrush}}"
Background="{DynamicResource {x:Static adonisUi:Brushes.Layer3BackgroundBrush}}"
Visibility="{Binding IsAssetsExplorerVisible, Converter={StaticResource BoolToVisibilityConverter}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" adonisExtensions:LayerExtension.Layer="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="Auto" MinWidth="150" />
</Grid.ColumnDefinitions>
<inputs:SearchTextBox x:Name="AssetsExplorerSearch" Grid.Column="0"
Text="{Binding SelectedItem.SearchText, ElementName=AssetsFolderName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ClearButtonClick="OnClearFilterClick" />
<ComboBox x:Name="CategoriesSelector" Grid.Column="2"
ItemsSource="{Binding Categories}"
SelectedItem="{Binding SelectedItem.SelectedCategory, ElementName=AssetsFolderName, Mode=TwoWay}" />
</Grid>
<controls:Breadcrumb Grid.Row="1" Margin="0 5 0 0"
HorizontalAlignment="Left"
DataContext="{Binding SelectedItem.PathAtThisPoint, ElementName=AssetsFolderName}" />
<ListBox x:Name="AssetsExplorer" Grid.Row="2"
ItemsSource="{Binding SelectedItem.CombinedEntries, ElementName=AssetsFolderName, IsAsync=True}"
Style="{StaticResource TiledExplorer}"
Background="{DynamicResource {x:Static adonisUi:Brushes.Layer3BackgroundBrush}}"
PreviewKeyDown="OnPreviewKeyDown" />
</Grid>
</Border>
<TabControl x:Name="TabControlName"
Style="{StaticResource GameFilesTabControl}"
Visibility="{Binding IsAssetsExplorerVisible, Converter={x:Static converters:InvertBoolToVisibilityConverter.Instance}, ConverterParameter=Hidden}" />
</Grid>
<Border Grid.Row="0"
VerticalAlignment="Bottom"
HorizontalAlignment="Right"
Margin="12,12,20,12"
Opacity="0.5"
Visibility="{Binding FeaturePreviewNewAssetExplorer, Source={x:Static settings:UserSettings.Default}, Converter={StaticResource BoolToVisibilityConverter}}"
Background="{DynamicResource {x:Static adonisUi:Brushes.Layer2BackgroundBrush}}"
CornerRadius="8"
Padding="4"
Effect="{DynamicResource ShadowEffect}">
<Border.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
To="1"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
To="0.5"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<ToggleButton Width="32"
Height="32"
Cursor="Hand"
Margin="0, 0, 2, 0"
Checked="OnPreviewTexturesToggled"
Focusable="False"
IsChecked="{Binding PreviewTexturesAssetExplorer, Source={x:Static settings:UserSettings.Default}, Mode=TwoWay}">
<ToggleButton.Style>
<Style TargetType="ToggleButton" BasedOn="{StaticResource ModernToggleButtonStyle}">
<Setter Property="ToolTip" Value="Preview Textures (OFF)" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="MediumPurple" />
<Setter Property="ToolTip" Value="Preview Textures (ON)" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
<Viewbox Width="16"
Height="16">
<Canvas Width="24"
Height="24">
<Path Data="{StaticResource TextureIconAlt}"
Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" />
</Canvas>
</Viewbox>
</ToggleButton>
<ToggleButton Width="32"
Height="32"
Cursor="Hand"
Margin="0, 0, 2, 0"
Checked="OnPreviewTexturesToggled"
ToolTip="Assets Explorer"
Focusable="False"
IsChecked="{Binding IsAssetsExplorerVisible, Mode=TwoWay}"
Style="{StaticResource ModernToggleButtonStyle}">
<Viewbox Width="16"
Height="16">
<Canvas Width="24"
Height="24">
<Path Data="{StaticResource FolderIconAlt}"
Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" />
</Canvas>
</Viewbox>
</ToggleButton>
<ToggleButton Width="32"
Height="32"
Cursor="Hand"
ToolTip="File Properties"
Focusable="False"
IsChecked="{Binding IsAssetsExplorerVisible, Converter={x:Static converters:InvertBooleanConverter.Instance}, Mode=TwoWay}"
Style="{StaticResource ModernToggleButtonStyle}">
<Viewbox Width="16"
Height="16">
<Canvas Width="24"
Height="24">
<Path Data="{StaticResource AssetIcon}"
Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" />
</Canvas>
</Viewbox>
</ToggleButton>
</StackPanel>
</Border>
<Expander Grid.Row="1" Margin="0 5 0 5" ExpandDirection="Down"
IsExpanded="{Binding IsLoggerExpanded, Source={x:Static settings:UserSettings.Default}}">
<Grid>
@ -740,7 +607,7 @@
<controls:CustomRichTextBox Grid.Column="0" Grid.ColumnSpan="3" x:Name="LogRtbName" Style="{StaticResource CustomRichTextBox}" />
<StackPanel Grid.Column="2" Orientation="Vertical" VerticalAlignment="Bottom" Margin="-5 -5 5 5">
<Button Style="{DynamicResource {x:Static adonisUi:Styles.ToolbarButton}}" ToolTip="Open Output Folder" Padding="0,4,0,4"
Command="{Binding MenuCommand}" CommandParameter="ToolBox_Open_Output_Directory">
Command="{Binding MenuCommand}" CommandParameter="ToolBox_Open_Output_Directory" Focusable="False">
<Viewbox Width="16" Height="16" HorizontalAlignment="Center">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource FolderIcon}" />
@ -748,7 +615,7 @@
</Viewbox>
</Button>
<Button Style="{DynamicResource {x:Static adonisUi:Styles.ToolbarButton}}" ToolTip="Clear Logs" Padding="0,4,0,4"
Command="{Binding MenuCommand}" CommandParameter="ToolBox_Clear_Logs">
Command="{Binding MenuCommand}" CommandParameter="ToolBox_Clear_Logs" Focusable="False">
<Viewbox Width="16" Height="16" HorizontalAlignment="Center">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource TrashIcon}"/>

View File

@ -4,9 +4,8 @@ using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using AdonisUI.Controls;
using CUE4Parse.FileProvider.Objects;
using FModel.Services;
using FModel.Settings;
using FModel.ViewModels;
@ -30,14 +29,54 @@ public partial class MainWindow
{
CommandBindings.Add(new CommandBinding(new RoutedCommand("ReloadMappings", typeof(MainWindow), new InputGestureCollection { new KeyGesture(Key.F12) }), OnMappingsReload));
CommandBindings.Add(new CommandBinding(ApplicationCommands.Find, (_, _) => OnOpenAvalonFinder()));
CommandBindings.Add(new CommandBinding(NavigationCommands.BrowseBack, (_, _) =>
{
if (UserSettings.Default.FeaturePreviewNewAssetExplorer && !_applicationView.IsAssetsExplorerVisible)
{
// back browsing the json view will reopen the assets explorer
_applicationView.IsAssetsExplorerVisible = true;
return;
}
if (LeftTabControl.SelectedIndex == 2)
{
LeftTabControl.SelectedIndex = 1;
}
else if (LeftTabControl.SelectedIndex == 1 && AssetsFolderName.SelectedItem is TreeItem { Parent: TreeItem parent })
{
AssetsFolderName.Focus();
parent.IsSelected = true;
}
}));
DataContext = _applicationView;
InitializeComponent();
AssetsExplorer.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
AssetsListName.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
AssetsExplorer.SelectionChanged += (_, e) => SyncSelection(AssetsListName, e);
AssetsListName.SelectionChanged += (_, e) => SyncSelection(AssetsExplorer, e);
FLogger.Logger = LogRtbName;
YesWeCats = this;
}
// Hack to sync selection between packages tab and explorer
private void SyncSelection(ListBox target, SelectionChangedEventArgs e)
{
foreach (var added in e.AddedItems.OfType<GameFileViewModel>())
{
if (!target.SelectedItems.Contains(added))
target.SelectedItems.Add(added);
}
foreach (var removed in e.RemovedItems.OfType<GameFileViewModel>())
{
if (target.SelectedItems.Contains(removed))
target.SelectedItems.Remove(removed);
}
}
private void OnClosing(object sender, CancelEventArgs e)
{
_discordHandler.Dispose();
@ -61,14 +100,18 @@ public partial class MainWindow
break;
}
await ApplicationViewModel.InitOodle();
await ApplicationViewModel.InitZlib();
await Task.WhenAll(
ApplicationViewModel.InitOodle(),
ApplicationViewModel.InitZlib()
).ConfigureAwait(false);
await _applicationView.CUE4Parse.Initialize();
await _applicationView.AesManager.InitAes();
await _applicationView.UpdateProvider(true);
#if !DEBUG
await _applicationView.CUE4Parse.InitInformation();
#endif
await Task.WhenAll(
_applicationView.CUE4Parse.VerifyConsoleVariables(),
_applicationView.CUE4Parse.VerifyOnDemandArchives(),
@ -107,10 +150,33 @@ public partial class MainWindow
}
else if (_applicationView.Status.IsReady && e.Key == Key.F && Keyboard.Modifiers.HasFlag(ModifierKeys.Control) && Keyboard.Modifiers.HasFlag(ModifierKeys.Shift))
OnSearchViewClick(null, null);
else if (e.Key == Key.Left && _applicationView.CUE4Parse.TabControl.SelectedTab.HasImage)
else if (_applicationView.Status.IsReady && e.Key == Key.R && Keyboard.Modifiers.HasFlag(ModifierKeys.Control) && Keyboard.Modifiers.HasFlag(ModifierKeys.Shift))
OnRefViewClick(null, null);
else if (e.Key == Key.F3)
OnOpenAvalonFinder();
else if (e.Key == Key.Left && !_applicationView.IsAssetsExplorerVisible && _applicationView.CUE4Parse.TabControl.SelectedTab is { HasImage: true })
_applicationView.CUE4Parse.TabControl.SelectedTab.GoPreviousImage();
else if (e.Key == Key.Right && _applicationView.CUE4Parse.TabControl.SelectedTab.HasImage)
else if (e.Key == Key.Right && !_applicationView.IsAssetsExplorerVisible && _applicationView.CUE4Parse.TabControl.SelectedTab is { HasImage: true })
_applicationView.CUE4Parse.TabControl.SelectedTab.GoNextImage();
else if (_applicationView.Status.IsReady && _applicationView.IsAssetsExplorerVisible && Keyboard.Modifiers.HasFlag(ModifierKeys.Alt))
{
CategoriesSelector.SelectedIndex = e.SystemKey switch
{
Key.D0 or Key.NumPad0 => 0,
Key.D1 or Key.NumPad1 => 1,
Key.D2 or Key.NumPad2 => 2,
Key.D3 or Key.NumPad3 => 3,
Key.D4 or Key.NumPad4 => 4,
Key.D5 or Key.NumPad5 => 5,
Key.D6 or Key.NumPad6 => 6,
Key.D7 or Key.NumPad7 => 7,
Key.D8 or Key.NumPad8 => 8,
Key.D9 or Key.NumPad9 => 9,
_ => CategoriesSelector.SelectedIndex
};
}
else if (_applicationView.Status.IsReady && UserSettings.Default.FeaturePreviewNewAssetExplorer && UserSettings.Default.SwitchAssetExplorer.IsTriggered(e.Key))
_applicationView.IsAssetsExplorerVisible = !_applicationView.IsAssetsExplorerVisible;
else if (UserSettings.Default.AssetAddTab.IsTriggered(e.Key))
_applicationView.CUE4Parse.TabControl.AddTab();
else if (UserSettings.Default.AssetRemoveTab.IsTriggered(e.Key))
@ -119,15 +185,22 @@ public partial class MainWindow
_applicationView.CUE4Parse.TabControl.GoLeftTab();
else if (UserSettings.Default.AssetRightTab.IsTriggered(e.Key))
_applicationView.CUE4Parse.TabControl.GoRightTab();
else if (UserSettings.Default.DirLeftTab.IsTriggered(e.Key) && LeftTabControl.SelectedIndex > 0)
LeftTabControl.SelectedIndex--;
else if (UserSettings.Default.DirRightTab.IsTriggered(e.Key) && LeftTabControl.SelectedIndex < LeftTabControl.Items.Count - 1)
LeftTabControl.SelectedIndex++;
else if (UserSettings.Default.DirLeftTab.IsTriggered(e.Key) && _applicationView.SelectedLeftTabIndex > 0)
_applicationView.SelectedLeftTabIndex--;
else if (UserSettings.Default.DirRightTab.IsTriggered(e.Key) && _applicationView.SelectedLeftTabIndex < LeftTabControl.Items.Count - 1)
_applicationView.SelectedLeftTabIndex++;
}
private void OnSearchViewClick(object sender, RoutedEventArgs e)
{
Helper.OpenWindow<AdonisWindow>("Search View", () => new SearchView().Show());
var searchView = Helper.GetWindow<SearchView>("Search For Packages", () => new SearchView().Show());
searchView.FocusTab(ESearchViewTab.SearchView);
}
private void OnRefViewClick(object sender, RoutedEventArgs e)
{
var searchView = Helper.GetWindow<SearchView>("Search For Packages", () => new SearchView().Show());
searchView.FocusTab(ESearchViewTab.RefView);
}
private void OnTabItemChange(object sender, SelectionChangedEventArgs e)
@ -135,7 +208,18 @@ public partial class MainWindow
if (e.OriginalSource is not TabControl tabControl)
return;
(tabControl.SelectedItem as System.Windows.Controls.TabItem)?.Focus();
switch (tabControl.SelectedIndex)
{
case 0:
DirectoryFilesListBox.Focus();
break;
case 1:
AssetsFolderName.Focus();
break;
case 2:
AssetsListName.Focus();
break;
}
}
private async void OnMappingsReload(object sender, ExecutedRoutedEventArgs e)
@ -145,142 +229,71 @@ public partial class MainWindow
private void OnOpenAvalonFinder()
{
_applicationView.CUE4Parse.TabControl.SelectedTab.HasSearchOpen = true;
AvalonEditor.YesWeSearch.Focus();
AvalonEditor.YesWeSearch.SelectAll();
if (_applicationView.IsAssetsExplorerVisible)
{
AssetsExplorerSearch.TextBox.Focus();
AssetsExplorerSearch.TextBox.SelectAll();
}
else if (_applicationView.CUE4Parse.TabControl.SelectedTab is { } tab)
{
tab.HasSearchOpen = true;
AvalonEditor.YesWeSearch.Focus();
AvalonEditor.YesWeSearch.SelectAll();
}
}
private void OnAssetsTreeMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (sender is not TreeView { SelectedItem: TreeItem treeItem } || treeItem.Folders.Count > 0) return;
LeftTabControl.SelectedIndex++;
_applicationView.SelectedLeftTabIndex++;
}
private void OnPreviewTexturesToggled(object sender, RoutedEventArgs e) => ItemContainerGenerator_StatusChanged(AssetsExplorer.ItemContainerGenerator, EventArgs.Empty);
private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
if (sender is not ItemContainerGenerator { Status: GeneratorStatus.ContainersGenerated } generator)
return;
var foundVisibleItem = false;
var itemCount = generator.Items.Count;
for (var i = 0; i < itemCount; i++)
{
var container = generator.ContainerFromIndex(i);
if (container == null)
{
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();
}
}
}
private async void OnAssetsListMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (sender is not ListBox listBox) return;
var selectedItems = listBox.SelectedItems.Cast<GameFile>().ToList();
var selectedItems = listBox.SelectedItems.OfType<GameFileViewModel>().Select(gvm => gvm.Asset).ToArray();
if (selectedItems.Length == 0) return;
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.ExtractSelected(cancellationToken, selectedItems); });
}
private async void OnFolderExtractClick(object sender, RoutedEventArgs e)
private void OnClearFilterClick(object sender, RoutedEventArgs e)
{
if (AssetsFolderName.SelectedItem is TreeItem folder)
{
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.ExtractFolder(cancellationToken, folder); });
folder.SearchText = string.Empty;
folder.SelectedCategory = EAssetCategory.All;
}
}
private async void OnFolderExportClick(object sender, RoutedEventArgs e)
{
if (AssetsFolderName.SelectedItem is TreeItem folder)
{
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.ExportFolder(cancellationToken, folder); });
FLogger.Append(ELog.Information, () =>
{
FLogger.Text("Successfully exported ", Constants.WHITE);
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.RawDataDirectory, true);
});
}
}
private async void OnFolderSaveClick(object sender, RoutedEventArgs e)
{
if (AssetsFolderName.SelectedItem is TreeItem folder)
{
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.SaveFolder(cancellationToken, folder); });
FLogger.Append(ELog.Information, () =>
{
FLogger.Text("Successfully saved ", Constants.WHITE);
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.PropertiesDirectory, true);
});
}
}
private async void OnFolderTextureClick(object sender, RoutedEventArgs e)
{
if (AssetsFolderName.SelectedItem is TreeItem folder)
{
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.TextureFolder(cancellationToken, folder); });
FLogger.Append(ELog.Information, () =>
{
FLogger.Text("Successfully saved textures from ", Constants.WHITE);
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.TextureDirectory, true);
});
}
}
private async void OnFolderModelClick(object sender, RoutedEventArgs e)
{
if (AssetsFolderName.SelectedItem is TreeItem folder)
{
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.ModelFolder(cancellationToken, folder); });
FLogger.Append(ELog.Information, () =>
{
FLogger.Text("Successfully saved models from ", Constants.WHITE);
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.ModelDirectory, true);
});
}
}
private async void OnFolderAnimationClick(object sender, RoutedEventArgs e)
{
if (AssetsFolderName.SelectedItem is TreeItem folder)
{
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.AnimationFolder(cancellationToken, folder); });
FLogger.Append(ELog.Information, () =>
{
FLogger.Text("Successfully saved animations from ", Constants.WHITE);
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.ModelDirectory, true);
});
}
}
private async void OnFolderAudioClick(object sender, RoutedEventArgs e)
{
if (AssetsFolderName.SelectedItem is TreeItem folder)
{
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.AudioFolder(cancellationToken, folder); });
FLogger.Append(ELog.Information, () =>
{
FLogger.Text("Successfully saved audio from ", Constants.WHITE);
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.AudioDirectory, true);
});
}
}
private void OnFavoriteDirectoryClick(object sender, RoutedEventArgs e)
{
if (AssetsFolderName.SelectedItem is not TreeItem folder) return;
_applicationView.CustomDirectories.Add(new CustomDirectory(folder.Header, folder.PathAtThisPoint));
FLogger.Append(ELog.Information, () =>
FLogger.Text($"Successfully saved '{folder.PathAtThisPoint}' as a new favorite directory", Constants.WHITE, true));
}
private void OnCopyDirectoryPathClick(object sender, RoutedEventArgs e)
{
if (AssetsFolderName.SelectedItem is not TreeItem folder) return;
Clipboard.SetText(folder.PathAtThisPoint);
}
private void OnDeleteSearchClick(object sender, RoutedEventArgs e)
{
AssetsSearchName.Text = string.Empty;
AssetsListName.ScrollIntoView(AssetsListName.SelectedItem);
}
private void OnFilterTextChanged(object sender, TextChangedEventArgs e)
{
if (sender is not TextBox textBox || AssetsFolderName.SelectedItem is not TreeItem folder)
return;
var filters = textBox.Text.Trim().Split(' ');
folder.AssetsList.AssetsView.Filter = o => { return o is GameFile entry && filters.All(x => entry.Name.Contains(x, StringComparison.OrdinalIgnoreCase)); };
}
private void OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (!_applicationView.Status.IsReady || sender is not ListBox listBox) return;
@ -290,14 +303,67 @@ public partial class MainWindow
private async void OnPreviewKeyDown(object sender, KeyEventArgs e)
{
if (!_applicationView.Status.IsReady || sender is not ListBox listBox) return;
if (!_applicationView.Status.IsReady || sender is not ListBox listBox)
return;
if (e.Key != Key.Enter)
return;
if (listBox.SelectedItem == null)
return;
switch (e.Key)
switch (listBox.SelectedItem)
{
case Key.Enter:
var selectedItems = listBox.SelectedItems.Cast<GameFile>().ToList();
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.ExtractSelected(cancellationToken, selectedItems); });
case GameFileViewModel file:
_applicationView.IsAssetsExplorerVisible = false;
ApplicationService.ApplicationView.SelectedLeftTabIndex = 2;
await _threadWorkerView.Begin(cancellationToken => _applicationView.CUE4Parse.ExtractSelected(cancellationToken, [file.Asset]));
break;
case TreeItem folder:
ApplicationService.ApplicationView.SelectedLeftTabIndex = 1;
var parent = folder.Parent;
while (parent != null)
{
parent.IsExpanded = true;
parent = parent.Parent;
}
var childFolder = folder;
while (childFolder.Folders.Count == 1 && childFolder.AssetsList.Assets.Count == 0)
{
childFolder.IsExpanded = true;
childFolder = childFolder.Folders[0];
}
childFolder.IsExpanded = true;
childFolder.IsSelected = true;
break;
}
}
private void FeaturePreviewOnUnchecked(object sender, RoutedEventArgs e)
{
_applicationView.IsAssetsExplorerVisible = false;
}
private async void OnFoldersPreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key != Key.Enter || sender is not TreeView treeView || treeView.SelectedItem is not TreeItem folder)
return;
if ((folder.IsExpanded || folder.Folders.Count == 0) && folder.AssetsList.Assets.Count > 0)
{
_applicationView.SelectedLeftTabIndex++;
return;
}
var childFolder = folder;
while (childFolder.Folders.Count == 1 && childFolder.AssetsList.Assets.Count == 0)
{
childFolder.IsExpanded = true;
childFolder = childFolder.Folders[0];
}
childFolder.IsExpanded = true;
childFolder.IsSelected = true;
}
}

View File

@ -3,14 +3,14 @@ using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Input;
using CUE4Parse.UE4.Assets.Exports.Material;
using CUE4Parse.UE4.Assets.Exports.Nanite;
using CUE4Parse.UE4.Versions;
using CUE4Parse_Conversion;
using CUE4Parse_Conversion.Animations;
using CUE4Parse.UE4.Versions;
using CUE4Parse_Conversion.Meshes;
using CUE4Parse_Conversion.Textures;
using CUE4Parse_Conversion.UEFormat.Enums;
using CUE4Parse.UE4.Assets.Exports.Material;
using CUE4Parse.UE4.Assets.Exports.Nanite;
using FModel.Framework;
using FModel.ViewModels;
using FModel.ViewModels.ApiEndpoints.Models;
@ -307,6 +307,13 @@ namespace FModel.Settings
set => SetProperty(ref _dirRightTab, value);
}
private Hotkey _switchAssetExplorer = new(Key.Z);
public Hotkey SwitchAssetExplorer
{
get => _switchAssetExplorer;
set => SetProperty(ref _switchAssetExplorer, value);
}
private Hotkey _assetLeftTab = new(Key.Q);
public Hotkey AssetLeftTab
{
@ -516,5 +523,19 @@ namespace FModel.Settings
get => _saveHdrTexturesAsHdr;
set => SetProperty(ref _saveHdrTexturesAsHdr, value);
}
private bool _featurePreviewNewAssetExplorer = true;
public bool FeaturePreviewNewAssetExplorer
{
get => _featurePreviewNewAssetExplorer;
set => SetProperty(ref _featurePreviewNewAssetExplorer, value);
}
private bool _previewTexturesAssetExplorer = true;
public bool PreviewTexturesAssetExplorer
{
get => _previewTexturesAssetExplorer;
set => SetProperty(ref _previewTexturesAssetExplorer, value);
}
}
}

View File

@ -5,10 +5,8 @@ using RestSharp;
namespace FModel.ViewModels.ApiEndpoints;
public class GitHubApiEndpoint : AbstractApiProvider
public class GitHubApiEndpoint(RestClient client) : AbstractApiProvider(client)
{
public GitHubApiEndpoint(RestClient client) : base(client) { }
public async Task<GitHubCommit[]> GetCommitHistoryAsync(string branch = "dev", int page = 1, int limit = 30)
{
var request = new FRestRequest(Constants.GH_COMMITS_HISTORY);
@ -25,4 +23,11 @@ public class GitHubApiEndpoint : AbstractApiProvider
var response = await _client.ExecuteAsync<GitHubRelease>(request).ConfigureAwait(false);
return response.Data;
}
public async Task<Author> GetUserAsync(string username)
{
var request = new FRestRequest($"https://api.github.com/users/{username}");
var response = await _client.ExecuteAsync<Author>(request).ConfigureAwait(false);
return response.Data;
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Windows;
using AdonisUI.Controls;
using AutoUpdaterDotNET;
@ -37,8 +38,7 @@ public class GitHubAsset : ViewModel
public class GitHubCommit : ViewModel
{
private string _sha;
[J("sha")]
public string Sha
[J("sha")] public string Sha
{
get => _sha;
set
@ -52,6 +52,35 @@ public class GitHubCommit : ViewModel
[J("commit")] public Commit Commit { get; set; }
[J("author")] public Author Author { get; set; }
private Author[] _coAuthors = [];
public Author[] CoAuthors
{
get => _coAuthors;
set
{
SetProperty(ref _coAuthors, value);
RaisePropertyChanged(nameof(Authors));
RaisePropertyChanged(nameof(AuthorNames));
}
}
public Author[] Authors => Author != null ? new[] { Author }.Concat(CoAuthors).ToArray() : CoAuthors;
public string AuthorNames
{
get
{
var authors = Authors;
return authors.Length switch
{
0 => string.Empty,
1 => authors[0].Login,
2 => $"{authors[0].Login} and {authors[1].Login}",
_ => string.Join(", ", authors.Take(authors.Length - 1).Select(a => a.Login)) + $", and {authors[^1].Login}"
};
}
}
private GitHubAsset _asset;
public GitHubAsset Asset
{

View File

@ -11,6 +11,7 @@ using CUE4Parse.Compression;
using CUE4Parse.Encryption.Aes;
using CUE4Parse.UE4.Objects.Core.Misc;
using CUE4Parse.UE4.VirtualFileSystem;
using FModel.Extensions;
using FModel.Framework;
using FModel.Services;
using FModel.Settings;
@ -43,6 +44,32 @@ public class ApplicationViewModel : ViewModel
private init => SetProperty(ref _status, value);
}
public IEnumerable<EAssetCategory> Categories { get; } = AssetCategoryExtensions.GetBaseCategories();
private bool _isAssetsExplorerVisible;
public bool IsAssetsExplorerVisible
{
get => _isAssetsExplorerVisible;
set
{
if (value && !UserSettings.Default.FeaturePreviewNewAssetExplorer)
return;
SetProperty(ref _isAssetsExplorerVisible, value);
}
}
private int _selectedLeftTabIndex;
public int SelectedLeftTabIndex
{
get => _selectedLeftTabIndex;
set
{
if (value is < 0 or > 2) return;
SetProperty(ref _selectedLeftTabIndex, value);
}
}
public RightClickMenuCommand RightClickMenuCommand => _rightClickMenuCommand ??= new RightClickMenuCommand(this);
private RightClickMenuCommand _rightClickMenuCommand;
public MenuCommand MenuCommand => _menuCommand ??= new MenuCommand(this);
@ -50,7 +77,7 @@ public class ApplicationViewModel : ViewModel
public CopyCommand CopyCommand => _copyCommand ??= new CopyCommand(this);
private CopyCommand _copyCommand;
public string InitialWindowTitle => $"FModel ({Constants.APP_SHORT_COMMIT_ID})";
public string InitialWindowTitle => $"FModel ({Constants.APP_SHORT_COMMIT_ID} - {Constants.APP_BUILD_DATE:MMM d, yyyy})";
public string GameDisplayName => CUE4Parse.Provider.GameDisplayName ?? "Unknown";
public string TitleExtra => $"({UserSettings.Default.CurrentDir.UeVersion}){(Build != EBuildKind.Release ? $" ({Build})" : "")}";
@ -196,32 +223,37 @@ public class ApplicationViewModel : ViewModel
public static async Task InitVgmStream()
{
var vgmZipFilePath = Path.Combine(UserSettings.Default.OutputDirectory, ".data", "vgmstream-win.zip");
if (File.Exists(vgmZipFilePath)) return;
var vgmFileInfo = new FileInfo(vgmZipFilePath);
await ApplicationService.ApiEndpointView.DownloadFileAsync("https://github.com/vgmstream/vgmstream/releases/latest/download/vgmstream-win.zip", vgmZipFilePath);
if (new FileInfo(vgmZipFilePath).Length > 0)
if (!vgmFileInfo.Exists || vgmFileInfo.LastWriteTimeUtc < DateTime.UtcNow.AddMonths(-4))
{
var zipDir = Path.GetDirectoryName(vgmZipFilePath)!;
await using var zipFs = File.OpenRead(vgmZipFilePath);
using var zip = new ZipArchive(zipFs, ZipArchiveMode.Read);
await ApplicationService.ApiEndpointView.DownloadFileAsync("https://github.com/vgmstream/vgmstream/releases/latest/download/vgmstream-win.zip", vgmZipFilePath);
vgmFileInfo.Refresh();
foreach (var entry in zip.Entries)
if (vgmFileInfo.Length > 0)
{
var entryPath = Path.Combine(zipDir, entry.FullName);
await using var entryFs = File.Create(entryPath);
await using var entryStream = entry.Open();
await entryStream.CopyToAsync(entryFs);
var zipDir = Path.GetDirectoryName(vgmZipFilePath)!;
await using var zipFs = File.OpenRead(vgmZipFilePath);
using var zip = new ZipArchive(zipFs, ZipArchiveMode.Read);
foreach (var entry in zip.Entries)
{
var entryPath = Path.Combine(zipDir, entry.FullName);
await using var entryFs = File.Create(entryPath);
await using var entryStream = entry.Open();
await entryStream.CopyToAsync(entryFs);
}
}
else
{
FLogger.Append(ELog.Error, () => FLogger.Text("Could not download VgmStream", Constants.WHITE, true));
}
}
else
{
FLogger.Append(ELog.Error, () => FLogger.Text("Could not download VgmStream", Constants.WHITE, true));
}
}
public static async Task InitImGuiSettings(bool forceDownload)
{
var imgui = "imgui.ini";
const string imgui = "imgui.ini";
var imguiPath = Path.Combine(UserSettings.Default.OutputDirectory, ".data", imgui);
if (File.Exists(imgui)) File.Move(imgui, imguiPath, true);
@ -234,7 +266,7 @@ public class ApplicationViewModel : ViewModel
}
}
public static async ValueTask InitOodle()
public static async Task InitOodle()
{
if (File.Exists(OodleHelper.OODLE_DLL_NAME_OLD))
{
@ -245,7 +277,11 @@ public class ApplicationViewModel : ViewModel
catch { /* ignored */}
}
var oodlePath = Path.Combine(UserSettings.Default.OutputDirectory, ".data", OodleHelper.OODLE_DLL_NAME);
var oodlePath = Path.Combine(UserSettings.Default.OutputDirectory, ".data", OodleHelper.OODLE_DLL_NAME_OLD);
if (!File.Exists(oodlePath))
{
oodlePath = Path.Combine(UserSettings.Default.OutputDirectory, ".data", OodleHelper.OODLE_DLL_NAME);
}
if (!File.Exists(oodlePath))
{
@ -259,7 +295,7 @@ public class ApplicationViewModel : ViewModel
OodleHelper.Initialize(oodlePath);
}
public static async ValueTask InitZlib()
public static async Task InitZlib()
{
var zlibPath = Path.Combine(UserSettings.Default.OutputDirectory, ".data", ZlibHelper.DLL_NAME);
var zlibFileInfo = new FileInfo(zlibPath);

View File

@ -1,12 +1,15 @@
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using CUE4Parse.FileProvider.Objects;
using CUE4Parse.UE4.Versions;
using CUE4Parse.UE4.VirtualFileSystem;
using FModel.Extensions;
using FModel.Framework;
using FModel.Services;
@ -14,11 +17,11 @@ namespace FModel.ViewModels;
public class TreeItem : ViewModel
{
private string _header;
private readonly string _header;
public string Header
{
get => _header;
private set => SetProperty(ref _header, value);
private init => SetProperty(ref _header, value);
}
private bool _isExpanded;
@ -56,10 +59,91 @@ public class TreeItem : ViewModel
private set => SetProperty(ref _version, value);
}
private string _searchText = string.Empty;
public string SearchText
{
get => _searchText;
set
{
if (SetProperty(ref _searchText, value))
{
RefreshFilters();
}
}
}
private EAssetCategory _selectedCategory = EAssetCategory.All;
public EAssetCategory SelectedCategory
{
get => _selectedCategory;
set
{
if (SetProperty(ref _selectedCategory, value))
_ = OnSelectedCategoryChanged();
}
}
public string PathAtThisPoint { get; }
public AssetsListViewModel AssetsList { get; }
public RangeObservableCollection<TreeItem> Folders { get; }
public ICollectionView FoldersView { get; }
public AssetsListViewModel AssetsList { get; } = new();
public RangeObservableCollection<TreeItem> Folders { get; } = [];
private ICollectionView _foldersView;
public ICollectionView FoldersView
{
get
{
_foldersView ??= new ListCollectionView(Folders)
{
SortDescriptions = { new SortDescription(nameof(Header), ListSortDirection.Ascending) }
};
return _foldersView;
}
}
private ICollectionView? _filteredFoldersView;
public ICollectionView? FilteredFoldersView
{
get
{
_filteredFoldersView ??= new ListCollectionView(Folders)
{
SortDescriptions = { new SortDescription(nameof(Header), ListSortDirection.Ascending) },
Filter = e => ItemFilter(e, SearchText.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries))
};
return _filteredFoldersView;
}
}
private CompositeCollection _combinedEntries;
public CompositeCollection CombinedEntries
{
get
{
if (_combinedEntries == null)
{
void CreateCombinedEntries()
{
_combinedEntries = new CompositeCollection
{
new CollectionContainer { Collection = FilteredFoldersView },
new CollectionContainer { Collection = AssetsList.AssetsView }
};
}
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.Invoke(CreateCombinedEntries);
}
else
{
CreateCombinedEntries();
}
}
return _combinedEntries;
}
}
public TreeItem Parent { get; init; }
public TreeItem(string header, GameFile entry, string pathHere)
{
@ -71,9 +155,43 @@ public class TreeItem : ViewModel
Version = vfsEntry.Vfs.Ver;
}
PathAtThisPoint = pathHere;
AssetsList = new AssetsListViewModel();
Folders = new RangeObservableCollection<TreeItem>();
FoldersView = new ListCollectionView(Folders) { SortDescriptions = { new SortDescription("Header", ListSortDirection.Ascending) } };
AssetsList.AssetsView.Filter = o => ItemFilter(o, SearchText.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries));
}
private void RefreshFilters()
{
AssetsList.AssetsView.Refresh();
FilteredFoldersView?.Refresh();
}
private bool ItemFilter(object item, IEnumerable<string> filters)
{
var f = filters.ToArray();
switch (item)
{
case GameFileViewModel entry:
{
bool matchesSearch = f.Length == 0 || f.All(x => entry.Asset.Name.Contains(x, StringComparison.OrdinalIgnoreCase));
bool matchesCategory = SelectedCategory == EAssetCategory.All || entry.AssetCategory.IsOfCategory(SelectedCategory);
return matchesSearch && matchesCategory;
}
case TreeItem folder:
{
bool matchesSearch = f.Length == 0 || f.All(x => folder.Header.Contains(x, StringComparison.OrdinalIgnoreCase));
bool matchesCategory = SelectedCategory == EAssetCategory.All;
return matchesSearch && matchesCategory;
}
}
return false;
}
private async Task OnSelectedCategoryChanged()
{
await Task.WhenAll(AssetsList.Assets.Select(asset => asset.ResolveAsync(EResolveCompute.Category)));
RefreshFilters();
}
public override string ToString() => $"{Header} | {Folders.Count} Folders | {AssetsList.Assets.Count} Files";
@ -86,7 +204,7 @@ public class AssetsFolderViewModel
public AssetsFolderViewModel()
{
Folders = new RangeObservableCollection<TreeItem>();
Folders = [];
FoldersView = new ListCollectionView(Folders) { SortDescriptions = { new SortDescription("Header", ListSortDirection.Ascending) } };
}
@ -103,6 +221,7 @@ public class AssetsFolderViewModel
foreach (var entry in entries)
{
TreeItem lastNode = null;
TreeItem parentItem = null;
var folders = entry.Path.Split('/', StringSplitOptions.RemoveEmptyEntries);
var builder = new StringBuilder(64);
var parentNode = treeItems;
@ -127,20 +246,30 @@ public class AssetsFolderViewModel
if (lastNode == null)
{
var nodePath = builder.ToString();
lastNode = new TreeItem(folder, entry, nodePath[..^1]);
lastNode = new TreeItem(folder, entry, nodePath[..^1])
{
Parent = parentItem
};
lastNode.Folders.SetSuppressionState(true);
lastNode.AssetsList.Assets.SetSuppressionState(true);
parentNode.Add(lastNode);
}
parentItem = lastNode;
parentNode = lastNode.Folders;
}
lastNode?.AssetsList.Assets.Add(entry);
lastNode?.AssetsList.Add(entry);
}
if (treeItems.Count > 0)
{
var projectName = ApplicationService.ApplicationView.CUE4Parse.Provider.ProjectName;
(treeItems.FirstOrDefault(x => x.Header.Equals(projectName, StringComparison.OrdinalIgnoreCase)) ?? treeItems[0]).IsSelected = true;
}
Folders.AddRange(treeItems);
ApplicationService.ApplicationView.CUE4Parse.SearchVm.SearchResults.AddRange(entries);
ApplicationService.ApplicationView.CUE4Parse.SearchVm.ChangeCollection(entries);
foreach (var folder in Folders)
InvokeOnCollectionChanged(folder);

View File

@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using System.Windows.Data;
using CUE4Parse.FileProvider.Objects;
using FModel.Framework;
@ -7,15 +7,20 @@ namespace FModel.ViewModels;
public class AssetsListViewModel
{
public RangeObservableCollection<GameFile> Assets { get; }
public ICollectionView AssetsView { get; }
public RangeObservableCollection<GameFileViewModel> Assets { get; } = [];
public AssetsListViewModel()
private ICollectionView _assetsView;
public ICollectionView AssetsView
{
Assets = new RangeObservableCollection<GameFile>();
AssetsView = new ListCollectionView(Assets)
get
{
SortDescriptions = { new SortDescription("Path", ListSortDirection.Ascending) }
};
_assetsView ??= new ListCollectionView(Assets)
{
SortDescriptions = { new SortDescription("Asset.Path", ListSortDirection.Ascending) }
};
return _assetsView;
}
}
public void Add(GameFile gameFile) => Assets.Add(new GameFileViewModel(gameFile));
}

View File

@ -69,6 +69,7 @@ using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
using Serilog;
using SkiaSharp;
using Svg.Skia;
using UE4Config.Parsing;
using Application = System.Windows.Application;
using FGuid = CUE4Parse.UE4.Objects.Core.Misc.FGuid;
@ -133,6 +134,7 @@ public class CUE4ParseViewModel : ViewModel
public GameDirectoryViewModel GameDirectory { get; }
public AssetsFolderViewModel AssetsFolder { get; }
public SearchViewModel SearchVm { get; }
public SearchViewModel RefVm { get; }
public TabControlViewModel TabControl { get; }
public ConfigIni IoStoreOnDemand { get; }
private Lazy<WwiseProvider> _wwiseProviderLazy;
@ -196,6 +198,7 @@ public class CUE4ParseViewModel : ViewModel
GameDirectory = new GameDirectoryViewModel();
AssetsFolder = new AssetsFolderViewModel();
SearchVm = new SearchViewModel();
RefVm = new SearchViewModel();
TabControl = new TabControlViewModel();
IoStoreOnDemand = new ConfigIni(nameof(IoStoreOnDemand));
}
@ -320,7 +323,7 @@ public class CUE4ParseViewModel : ViewModel
AssetsFolder.Folders.Clear();
SearchVm.SearchResults.Clear();
Helper.CloseWindow<AdonisWindow>("Search View");
Helper.CloseWindow<AdonisWindow>("Search For Packages");
Provider.UnloadNonStreamedVfs();
GC.Collect();
}
@ -554,7 +557,7 @@ public class CUE4ParseViewModel : ViewModel
cancellationToken.ThrowIfCancellationRequested();
try
{
action(entry);
action(entry.Asset);
}
catch
{
@ -570,7 +573,7 @@ public class CUE4ParseViewModel : ViewModel
Parallel.ForEach(folder.AssetsList.Assets, entry =>
{
cancellationToken.ThrowIfCancellationRequested();
ExportData(entry, false);
ExportData(entry.Asset, false);
});
foreach (var f in folder.Folders) ExportFolder(cancellationToken, f);
@ -596,6 +599,7 @@ public class CUE4ParseViewModel : ViewModel
public void Extract(CancellationToken cancellationToken, GameFile entry, bool addNewTab = false, EBulkType bulk = EBulkType.None)
{
ApplicationService.ApplicationView.IsAssetsExplorerVisible = false;
Log.Information("User DOUBLE-CLICKED to extract '{FullPath}'", entry.Path);
if (addNewTab && TabControl.CanAddTabs) TabControl.AddTab(entry);
@ -851,15 +855,22 @@ public class CUE4ParseViewModel : ViewModel
{
var data = Provider.SaveAsset(entry);
using var stream = new MemoryStream(data) { Position = 0 };
var svg = new SkiaSharp.Extended.Svg.SKSvg(new SKSize(512, 512));
var svg = new SKSvg();
svg.Load(stream);
var bitmap = new SKBitmap(512, 512);
using (var canvas = new SKCanvas(bitmap))
using (var paint = new SKPaint { IsAntialias = true, FilterQuality = SKFilterQuality.Medium })
{
canvas.DrawPicture(svg.Picture, paint);
}
int size = 512;
var bitmap = new SKBitmap(size, size);
using var canvas = new SKCanvas(bitmap);
canvas.Clear(SKColors.Transparent);
if (svg.Picture == null)
break;
var bounds = svg.Picture.CullRect;
float scale = Math.Min(size / bounds.Width, size / bounds.Height);
canvas.Scale(scale);
canvas.Translate(-bounds.Left, -bounds.Top);
canvas.DrawPicture(svg.Picture);
TabControl.SelectedTab.AddImage(entry.NameWithoutExtension, false, bitmap, saveTextures, updateUi);
@ -999,15 +1010,23 @@ public class CUE4ParseViewModel : ViewModel
var data = svgasset.GetOrDefault<byte[]>("SvgData");
var sourceFile = svgasset.GetOrDefault<string>("SourceFile");
using var stream = new MemoryStream(data) { Position = 0 };
var svg = new SkiaSharp.Extended.Svg.SKSvg(new SKSize(size, size));
var svg = new SKSvg();
svg.Load(stream);
if (svg.Picture == null)
return false;
var b = svg.Picture.CullRect;
float s = Math.Min(size / b.Width, size / b.Height);
var bitmap = new SKBitmap(size, size);
using (var canvas = new SKCanvas(bitmap))
using (var paint = new SKPaint { IsAntialias = true, FilterQuality = SKFilterQuality.Medium })
{
canvas.DrawPicture(svg.Picture, paint);
}
using var canvas = new SKCanvas(bitmap);
using var paint = new SKPaint { IsAntialias = true, FilterQuality = SKFilterQuality.Medium };
canvas.Scale(s);
canvas.Translate(-b.Left, -b.Top);
canvas.DrawPicture(svg.Picture, paint);
if (saveTextures)
{
@ -1167,6 +1186,8 @@ public class CUE4ParseViewModel : ViewModel
public void ShowMetadata(GameFile entry)
{
ApplicationService.ApplicationView.IsAssetsExplorerVisible = false;
var package = Provider.LoadPackage(entry);
if (TabControl.CanAddTabs) TabControl.AddTab(entry);
@ -1178,8 +1199,22 @@ public class CUE4ParseViewModel : ViewModel
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(package, Formatting.Indented), false, false);
}
public void FindReferences(GameFile entry)
{
var refs = Provider.ScanForPackageRefs(entry);
Application.Current.Dispatcher.Invoke(delegate
{
var refView = Helper.GetWindow<SearchView>("Search For Packages", () => new SearchView().Show());
refView.ChangeCollection(ESearchViewTab.RefView, refs, entry);
refView.FocusTab(ESearchViewTab.RefView);
});
}
public void Decompile(GameFile entry)
{
ApplicationService.ApplicationView.IsAssetsExplorerVisible = false;
if (TabControl.CanAddTabs) TabControl.AddTab(entry);
else TabControl.SelectedTab.SoftReset(entry);

View File

@ -1,4 +1,5 @@
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
@ -18,8 +19,16 @@ public class CopyCommand : ViewModelCommand<ApplicationViewModel>
if (parameter is not object[] parameters || parameters[0] is not string trigger)
return;
var entries = ((IList) parameters[1]).Cast<GameFile>().ToArray();
if (!entries.Any()) return;
var entries = (parameters[1] as IEnumerable)?.OfType<object>()
.SelectMany(item => item switch
{
GameFile gf => new[] { gf },
GameFileViewModel gvm => new[] { gvm.Asset },
_ => []
}) ?? [];
if (!entries.Any())
return;
var sb = new StringBuilder();
switch (trigger)

View File

@ -21,7 +21,7 @@ public class GoToCommand : ViewModelCommand<CustomDirectoriesViewModel>
public TreeItem JumpTo(string directory)
{
MainWindow.YesWeCats.LeftTabControl.SelectedIndex = 1; // folders tab
_applicationView.SelectedLeftTabIndex = 1; // folders tab
var root = _applicationView.CUE4Parse.AssetsFolder.Folders;
if (root is not { Count: > 0 }) return null;
@ -54,4 +54,4 @@ public class GoToCommand : ViewModelCommand<CustomDirectoriesViewModel>
return null;
}
}
}

View File

@ -55,8 +55,9 @@ public class LoadCommand : ViewModelCommand<LoadingModesViewModel>
#endif
_applicationView.CUE4Parse.AssetsFolder.Folders.Clear();
_applicationView.CUE4Parse.SearchVm.SearchResults.Clear();
MainWindow.YesWeCats.LeftTabControl.SelectedIndex = 1; // folders tab
Helper.CloseWindow<AdonisWindow>("Search View"); // close search window if opened
_applicationView.SelectedLeftTabIndex = 1; // folders tab
_applicationView.IsAssetsExplorerVisible = true;
Helper.CloseWindow<AdonisWindow>("Search For Packages"); // close search window if opened
await Task.WhenAll(
_applicationView.CUE4Parse.LoadLocalizedResources(), // load locres if not already loaded,
@ -70,7 +71,11 @@ public class LoadCommand : ViewModelCommand<LoadingModesViewModel>
case ELoadingMode.Multiple:
{
var l = (IList) parameter;
if (l.Count < 1) return;
if (l.Count == 0)
{
UserSettings.Default.LoadingMode = ELoadingMode.All;
goto case ELoadingMode.All;
}
var directoryFilesToShow = l.Cast<FileItem>();
FilterDirectoryFilesToDisplay(cancellationToken, directoryFilesToShow);

View File

@ -32,6 +32,7 @@ public class MenuCommand : ViewModelCommand<ApplicationViewModel>
Helper.OpenWindow<AdonisWindow>("Backup Manager", () => new BackupManager(contextViewModel.CUE4Parse.Provider.ProjectName).Show());
break;
case "Directory_ArchivesInfo":
ApplicationService.ApplicationView.IsAssetsExplorerVisible = false;
contextViewModel.CUE4Parse.TabControl.AddTab("Archives Info");
contextViewModel.CUE4Parse.TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector("json");
contextViewModel.CUE4Parse.TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(contextViewModel.CUE4Parse.GameDirectory.DirectoryFiles, Formatting.Indented), false, false);

View File

@ -4,6 +4,8 @@ using System.Threading;
using CUE4Parse.FileProvider.Objects;
using FModel.Framework;
using FModel.Services;
using FModel.Settings;
using FModel.Views.Resources.Controls;
namespace FModel.ViewModels.Commands;
@ -20,16 +22,28 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
if (parameter is not object[] parameters || parameters[0] is not string trigger)
return;
var entries = ((IList) parameters[1]).Cast<GameFile>().ToArray();
if (!entries.Any()) return;
var param = (parameters[1] as IEnumerable)?.OfType<object>().ToArray() ?? [];
if (param.Length == 0) return;
var updateUi = entries.Length > 1 ? EBulkType.Auto : EBulkType.None;
var folders = param.OfType<TreeItem>().ToArray();
var assets = param.SelectMany(item => item switch
{
GameFile gf => new[] { gf }, // search view passes GameFile directly
GameFileViewModel gvm => new[] { gvm.Asset },
_ => []
}).ToArray();
if (folders.Length == 0 && assets.Length == 0)
return;
var updateUi = assets.Length > 1 ? EBulkType.Auto : EBulkType.None;
await _threadWorkerView.Begin(cancellationToken =>
{
switch (trigger)
{
#region Asset Commands
case "Assets_Extract_New_Tab":
foreach (var entry in entries)
foreach (var entry in assets)
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
@ -37,15 +51,22 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
}
break;
case "Assets_Show_Metadata":
foreach (var entry in entries)
foreach (var entry in assets)
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
contextViewModel.CUE4Parse.ShowMetadata(entry);
}
break;
case "Assets_Show_References":
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
contextViewModel.CUE4Parse.FindReferences(assets.FirstOrDefault());
}
break;
case "Assets_Decompile":
foreach (var entry in entries)
foreach (var entry in assets)
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
@ -53,7 +74,7 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
}
break;
case "Assets_Export_Data":
foreach (var entry in entries)
foreach (var entry in assets)
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
@ -61,7 +82,7 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
}
break;
case "Assets_Save_Properties":
foreach (var entry in entries)
foreach (var entry in assets)
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
@ -69,7 +90,7 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
}
break;
case "Assets_Save_Textures":
foreach (var entry in entries)
foreach (var entry in assets)
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
@ -77,7 +98,7 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
}
break;
case "Assets_Save_Models":
foreach (var entry in entries)
foreach (var entry in assets)
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
@ -85,7 +106,7 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
}
break;
case "Assets_Save_Animations":
foreach (var entry in entries)
foreach (var entry in assets)
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
@ -93,13 +114,100 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
}
break;
case "Assets_Save_Audio":
foreach (var entry in entries)
foreach (var entry in assets)
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
contextViewModel.CUE4Parse.Extract(cancellationToken, entry, false, EBulkType.Audio | updateUi);
}
break;
#endregion
#region Folder Commands
case "Folders_Export_Data":
foreach (var folder in folders)
{
cancellationToken.ThrowIfCancellationRequested();
contextViewModel.CUE4Parse.ExportFolder(cancellationToken, folder);
FLogger.Append(ELog.Information, () =>
{
FLogger.Text("Successfully exported ", Constants.WHITE);
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.RawDataDirectory, true);
});
}
break;
case "Folders_Save_Properties":
foreach (var folder in folders)
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
contextViewModel.CUE4Parse.SaveFolder(cancellationToken, folder);
FLogger.Append(ELog.Information, () =>
{
FLogger.Text("Successfully saved ", Constants.WHITE);
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.PropertiesDirectory, true);
});
}
break;
case "Folders_Save_Textures":
foreach (var folder in folders)
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
contextViewModel.CUE4Parse.TextureFolder(cancellationToken, folder);
FLogger.Append(ELog.Information, () =>
{
FLogger.Text("Successfully saved textures from ", Constants.WHITE);
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.TextureDirectory, true);
});
}
break;
case "Folders_Save_Models":
foreach (var folder in folders)
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
contextViewModel.CUE4Parse.ModelFolder(cancellationToken, folder);
FLogger.Append(ELog.Information, () =>
{
FLogger.Text("Successfully saved models from ", Constants.WHITE);
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.ModelDirectory, true);
});
}
break;
case "Folders_Save_Animations":
foreach (var folder in folders)
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
contextViewModel.CUE4Parse.AnimationFolder(cancellationToken, folder);
FLogger.Append(ELog.Information, () =>
{
FLogger.Text("Successfully saved animations from ", Constants.WHITE);
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.ModelDirectory, true);
});
}
break;
case "Folders_Save_Audio":
foreach (var folder in folders)
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
contextViewModel.CUE4Parse.AudioFolder(cancellationToken, folder);
FLogger.Append(ELog.Information, () =>
{
FLogger.Text("Successfully saved audio from ", Constants.WHITE);
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.AudioDirectory, true);
});
}
break;
#endregion
}
});
}

View File

@ -31,6 +31,9 @@ public class TabCommand : ViewModelCommand<TabItem>
case "Close_Other_Tabs":
_applicationView.CUE4Parse.TabControl.RemoveOtherTabs(tabViewModel);
break;
case "Find_References":
_applicationView.CUE4Parse.FindReferences(tabViewModel.Entry);
break;
case "Asset_Export_Data":
await _threadWorkerView.Begin(_ => _applicationView.CUE4Parse.ExportData(tabViewModel.Entry));
break;

View File

@ -0,0 +1,407 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using CUE4Parse.FileProvider.Objects;
using CUE4Parse.GameTypes.FN.Assets.Exports.DataAssets;
using CUE4Parse.UE4.Assets;
using CUE4Parse.UE4.Assets.Exports.Animation;
using CUE4Parse.UE4.Assets.Exports.BuildData;
using CUE4Parse.UE4.Assets.Exports.Component;
using CUE4Parse.UE4.Assets.Exports.CriWare;
using CUE4Parse.UE4.Assets.Exports.Engine;
using CUE4Parse.UE4.Assets.Exports.Engine.Font;
using CUE4Parse.UE4.Assets.Exports.Fmod;
using CUE4Parse.UE4.Assets.Exports.Foliage;
using CUE4Parse.UE4.Assets.Exports.Internationalization;
using CUE4Parse.UE4.Assets.Exports.LevelSequence;
using CUE4Parse.UE4.Assets.Exports.Material;
using CUE4Parse.UE4.Assets.Exports.Material.Editor;
using CUE4Parse.UE4.Assets.Exports.Niagara;
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
using CUE4Parse.UE4.Assets.Exports.Sound;
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
using CUE4Parse.UE4.Assets.Exports.Texture;
using CUE4Parse.UE4.Assets.Exports.Wwise;
using CUE4Parse.UE4.Assets.Objects;
using CUE4Parse.UE4.Objects.Engine;
using CUE4Parse.UE4.Objects.Engine.Animation;
using CUE4Parse.UE4.Objects.Engine.Curves;
using CUE4Parse.UE4.Objects.MediaAssets;
using CUE4Parse.UE4.Objects.Niagara;
using CUE4Parse.UE4.Objects.PhysicsEngine;
using CUE4Parse.UE4.Objects.RigVM;
using CUE4Parse.UE4.Objects.UObject;
using CUE4Parse.UE4.Objects.UObject.Editor;
using CUE4Parse.Utils;
using CUE4Parse_Conversion.Textures;
using FModel.Framework;
using FModel.Services;
using FModel.Settings;
using Serilog;
using SkiaSharp;
using Svg.Skia;
namespace FModel.ViewModels;
public class GameFileViewModel(GameFile asset) : ViewModel
{
private const int MaxPreviewSize = 128;
private ApplicationViewModel _applicationView => ApplicationService.ApplicationView;
public EResolveCompute Resolved { get; private set; } = EResolveCompute.None;
public GameFile Asset { get; } = asset;
private string _resolvedAssetType = asset.Extension;
public string ResolvedAssetType
{
get => _resolvedAssetType;
private set => SetProperty(ref _resolvedAssetType, value);
}
private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set => SetProperty(ref _isSelected, value);
}
private EAssetCategory _assetCategory = EAssetCategory.All;
public EAssetCategory AssetCategory
{
get => _assetCategory;
private set
{
SetProperty(ref _assetCategory, value);
Resolved |= EResolveCompute.Category; // blindly assume category is resolved when set, even if unchanged
}
}
private ImageSource _previewImage;
public ImageSource PreviewImage
{
get => _previewImage;
private set
{
if (SetProperty(ref _previewImage, value))
{
Resolved |= EResolveCompute.Preview;
}
}
}
public Task ExtractAsync()
=> ApplicationService.ThreadWorkerView.Begin(cancellationToken =>
_applicationView.CUE4Parse.ExtractSelected(cancellationToken, [Asset]));
public Task ResolveAsync(EResolveCompute resolve)
{
try
{
return ResolveInternalAsync(resolve);
}
catch (Exception e)
{
Log.Error(e, "Failed to resolve asset {AssetName} ({Resolver})", Asset.Path, resolve.ToStringBitfield());
Resolved = EResolveCompute.All;
return Task.CompletedTask;
}
}
private Task ResolveInternalAsync(EResolveCompute resolve)
{
if (!_applicationView.IsAssetsExplorerVisible || !UserSettings.Default.PreviewTexturesAssetExplorer)
{
resolve &= ~EResolveCompute.Preview;
}
resolve &= ~Resolved;
if (resolve == EResolveCompute.None)
return Task.CompletedTask;
if (!Asset.IsUePackage || _applicationView.CUE4Parse is null)
return ResolveByExtensionAsync(resolve);
return ResolveByPackageAsync(resolve);
}
private Task ResolveByPackageAsync(EResolveCompute resolve)
{
if (Asset.Extension is "umap")
{
AssetCategory = EAssetCategory.World;
ResolvedAssetType = "World";
Resolved |= EResolveCompute.Preview;
return Task.CompletedTask;
}
if (Asset.NameWithoutExtension.EndsWith("_BuiltData"))
{
AssetCategory = EAssetCategory.BuildData;
ResolvedAssetType = "MapBuildDataRegistry";
Resolved |= EResolveCompute.Preview;
return Task.CompletedTask;
}
return Task.Run(() =>
{
// TODO: cache and reuse packages
var pkg = _applicationView.CUE4Parse?.Provider.LoadPackage(Asset);
if (pkg is null)
throw new InvalidOperationException($"Failed to load {Asset.Path} as UE package.");
var mainIndex = pkg.GetExportIndex(Asset.NameWithoutExtension, StringComparison.OrdinalIgnoreCase);
if (mainIndex < 0) mainIndex = pkg.GetExportIndex($"{Asset.NameWithoutExtension}_C", StringComparison.OrdinalIgnoreCase);
if (mainIndex < 0) mainIndex = 0;
var pointer = new FPackageIndex(pkg, mainIndex + 1).ResolvedObject;
if (pointer?.Object is null)
return;
var dummy = ((AbstractUePackage) pkg).ConstructObject(pointer.Class?.Object?.Value as UStruct, pkg);
ResolvedAssetType = dummy.ExportType;
AssetCategory = dummy switch
{
URigVMBlueprintGeneratedClass => EAssetCategory.RigVMBlueprintGeneratedClass,
UAnimBlueprintGeneratedClass => EAssetCategory.AnimBlueprintGeneratedClass,
UWidgetBlueprintGeneratedClass => EAssetCategory.WidgetBlueprintGeneratedClass,
UBlueprintGeneratedClass or UFunction => EAssetCategory.BlueprintGeneratedClass,
UUserDefinedEnum => EAssetCategory.UserDefinedEnum,
UUserDefinedStruct => EAssetCategory.UserDefinedStruct,
UBlueprintCore => EAssetCategory.Blueprint,
UClassCookedMetaData or UStructCookedMetaData or UEnumCookedMetaData => EAssetCategory.CookedMetaData,
UStaticMesh => EAssetCategory.StaticMesh,
USkeletalMesh => EAssetCategory.SkeletalMesh,
UPhysicsAsset => EAssetCategory.PhysicsAsset,
UTexture => EAssetCategory.Texture,
UMaterialInterface => EAssetCategory.Material,
UMaterialInterfaceEditorOnlyData => EAssetCategory.MaterialEditorData,
UMaterialFunction => EAssetCategory.MaterialFunction,
UMaterialParameterCollection => EAssetCategory.MaterialParameterCollection,
UAnimationAsset => EAssetCategory.Animation,
USkeleton => EAssetCategory.Skeleton,
UWorld => EAssetCategory.World,
UMapBuildDataRegistry => EAssetCategory.BuildData,
ULevelSequence => EAssetCategory.LevelSequence,
UFoliageType => EAssetCategory.Foliage,
UItemDefinitionBase => EAssetCategory.ItemDefinitionBase,
UDataAsset or UDataTable or UCurveTable or UStringTable => EAssetCategory.Data,
UCurveBase => EAssetCategory.CurveBase,
UWwiseAssetLibrary or USoundBase or UAkMediaAssetData or UAtomWaveBank or USoundAtomCue
or UAtomCueSheet or USoundAtomCueSheet or UFMODBank or UFMODEvent or UAkAudioType => EAssetCategory.Audio,
UFileMediaSource => EAssetCategory.Video,
UFont or UFontFace => EAssetCategory.Font,
UNiagaraSystem or UNiagaraScriptBase or UParticleSystem => EAssetCategory.Particle,
_ => EAssetCategory.All
};
switch (AssetCategory)
{
case EAssetCategory.Texture when pointer.Object.Value is UTexture texture:
{
if (!resolve.HasFlag(EResolveCompute.Preview))
break;
var img = texture.Decode(MaxPreviewSize, UserSettings.Default.CurrentDir.TexturePlatform);
if (img != null)
{
using var bitmap = img.ToSkBitmap();
using var image = bitmap.Encode(SKEncodedImageFormat.Png, 100);
SetPreviewImage(image);
}
break;
}
case EAssetCategory.ItemDefinitionBase:
if (!resolve.HasFlag(EResolveCompute.Preview))
break;
if (pointer.Object.Value is UItemDefinitionBase itemDef)
{
if (LookupPreview(itemDef.DataList)) break;
if (itemDef is UAthenaPickaxeItemDefinition pickaxe && pickaxe.WeaponDefinition.TryLoad(out UItemDefinitionBase weaponDef))
{
LookupPreview(weaponDef.DataList);
}
bool LookupPreview(FInstancedStruct[] dataList)
{
foreach (var data in dataList)
{
if (!data.NonConstStruct.TryGetValue(out FSoftObjectPath icon, "Icon", "LargeIcon") ||
!icon.TryLoad<UTexture2D>(out var texture))
continue;
var img = texture.Decode(MaxPreviewSize, UserSettings.Default.CurrentDir.TexturePlatform);
if (img == null) return false;
using var bitmap = img.ToSkBitmap();
using var image = bitmap.Encode(SKEncodedImageFormat.Png, 100);
SetPreviewImage(image);
return true;
}
return false;
}
}
break;
default:
Resolved |= EResolveCompute.Preview;
break;
}
});
}
private Task ResolveByExtensionAsync(EResolveCompute resolve)
{
Resolved |= EResolveCompute.Preview;
switch (Asset.Extension)
{
case "uproject":
case "uefnproject":
case "upluginmanifest":
case "uplugin":
case "ini":
case "locmeta":
case "locres":
case "verse":
case "lua":
case "luac":
case "json5":
case "json":
case "bin":
case "txt":
case "log":
case "pem":
case "xml":
AssetCategory = EAssetCategory.Data;
break;
case "wav":
case "bank":
case "bnk":
case "pck":
case "awb":
case "acb":
case "xvag":
case "flac":
case "at9":
case "wem":
case "ogg":
AssetCategory = EAssetCategory.Audio;
break;
case "ufont":
case "otf":
case "ttf":
AssetCategory = EAssetCategory.Font;
break;
case "mp4":
AssetCategory = EAssetCategory.Video;
break;
case "jpg":
case "png":
case "bmp":
case "svg":
{
Resolved |= ~EResolveCompute.Preview;
AssetCategory = EAssetCategory.Texture;
if (!resolve.HasFlag(EResolveCompute.Preview))
break;
return Task.Run(() =>
{
var data = _applicationView.CUE4Parse.Provider.SaveAsset(Asset);
using var stream = new MemoryStream(data);
stream.Position = 0;
SKBitmap bitmap;
if (Asset.Extension == "svg")
{
var svg = new SKSvg();
svg.Load(stream);
if (svg.Picture == null)
return;
bitmap = new SKBitmap(MaxPreviewSize, MaxPreviewSize);
using var canvas = new SKCanvas(bitmap);
canvas.Clear(SKColors.Transparent);
var bounds = svg.Picture.CullRect;
float scale = Math.Min(MaxPreviewSize / bounds.Width, MaxPreviewSize / bounds.Height);
canvas.Scale(scale);
canvas.Translate(-bounds.Left, -bounds.Top);
canvas.DrawPicture(svg.Picture);
}
else
{
bitmap = SKBitmap.Decode(stream);
}
using var image = bitmap.Encode(Asset.Extension == "jpg" ? SKEncodedImageFormat.Jpeg : SKEncodedImageFormat.Png, 100);
SetPreviewImage(image);
bitmap.Dispose();
});
}
default:
AssetCategory = EAssetCategory.All; // just so it sets resolved
break;
}
return Task.CompletedTask;
}
private void SetPreviewImage(SKData data)
{
using var ms = new MemoryStream(data.ToArray());
ms.Position = 0;
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = ms;
bitmap.EndInit();
bitmap.Freeze();
Application.Current.Dispatcher.InvokeAsync(() => PreviewImage = bitmap);
}
private CancellationTokenSource _previewCts;
public void OnIsVisible()
{
if (Resolved == EResolveCompute.All)
return;
_previewCts?.Cancel();
_previewCts = new CancellationTokenSource();
var token = _previewCts.Token;
Task.Delay(100, token).ContinueWith(t =>
{
if (t.IsCanceled) return;
ResolveAsync(EResolveCompute.All);
}, TaskScheduler.FromCurrentSynchronizationContext());
}
}
[Flags]
public enum EResolveCompute
{
None = 0,
Category = 1 << 0,
Preview = 1 << 1,
All = Category | Preview
}

View File

@ -1,6 +1,5 @@
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@ -20,7 +19,7 @@ public class SearchViewModel : ViewModel
Descending
}
private string _filterText;
private string _filterText = string.Empty;
public string FilterText
{
get => _filterText;
@ -48,22 +47,45 @@ public class SearchViewModel : ViewModel
set => SetProperty(ref _currentSortSizeMode, value);
}
public int ResultsCount => SearchResults?.Count ?? 0;
private int _resultsCount = 0;
public int ResultsCount
{
get => _resultsCount;
private set => SetProperty(ref _resultsCount, value);
}
private GameFile _refFile;
public GameFile RefFile
{
get => _refFile;
private set => SetProperty(ref _refFile, value);
}
public RangeObservableCollection<GameFile> SearchResults { get; }
public ICollectionView SearchResultsView { get; }
public ListCollectionView SearchResultsView { get; }
public SearchViewModel()
{
SearchResults = new RangeObservableCollection<GameFile>();
SearchResults = [];
SearchResultsView = new ListCollectionView(SearchResults)
{
Filter = e => ItemFilter(e, FilterText?.Trim().Split(' ') ?? []),
Filter = e => ItemFilter(e, FilterText.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries)),
};
ResultsCount = SearchResultsView.Count;
}
public void RefreshFilter()
{
SearchResultsView.Refresh();
ResultsCount = SearchResultsView.Count;
}
public void ChangeCollection(IEnumerable<GameFile> files, GameFile refFile = null)
{
SearchResults.Clear();
SearchResults.AddRange(files);
RefFile = refFile;
ResultsCount = SearchResultsView.Count;
}
public async Task CycleSortSizeMode()
@ -105,7 +127,7 @@ public class SearchViewModel : ViewModel
});
SearchResults.Clear();
SearchResults.AddRange(sorted.ToList());
SearchResults.AddRange(sorted);
}
private bool ItemFilter(object item, IEnumerable<string> filters)

View File

@ -40,10 +40,6 @@ public class ThreadWorkerViewModel : ViewModel
private ApplicationViewModel _applicationView => ApplicationService.ApplicationView;
private readonly AsyncQueue<Action<CancellationToken>> _jobs;
private const string _at = " at ";
private const char _dot = '.';
private const char _colon = ':';
private const string _gray = "#999";
public ThreadWorkerViewModel()
{
@ -104,37 +100,7 @@ public class ThreadWorkerViewModel : ViewModel
CurrentCancellationTokenSource = null; // kill token
Log.Error("{Exception}", e);
FLogger.Append(ELog.Error, () =>
{
if ((e.InnerException ?? e) is { TargetSite.DeclaringType: not null } exception)
{
if (exception.TargetSite.ToString() == "CUE4Parse.FileProvider.GameFile get_Item(System.String)")
{
FLogger.Text(e.Message, Constants.WHITE, true);
}
else
{
var t = exception.GetType();
FLogger.Text(t.Namespace + _dot, Constants.GRAY);
FLogger.Text(t.Name, Constants.WHITE);
FLogger.Text(_colon + " ", Constants.GRAY);
FLogger.Text(exception.Message, Constants.RED, true);
FLogger.Text(_at, _gray);
FLogger.Text(exception.TargetSite.DeclaringType.FullName + _dot, Constants.GRAY);
FLogger.Text(exception.TargetSite.Name, Constants.YELLOW);
var p = exception.TargetSite.GetParameters();
var parameters = new string[p.Length];
for (int i = 0; i < parameters.Length; i++)
{
parameters[i] = p[i].ParameterType.Name + " " + p[i].Name;
}
FLogger.Text("(" + string.Join(", ", parameters) + ")", Constants.GRAY, true);
}
}
});
FLogger.Append(e);
return;
}
}

View File

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Data;
using CUE4Parse.Utils;
@ -13,7 +15,7 @@ using FModel.Views.Resources.Converters;
namespace FModel.ViewModels;
public class UpdateViewModel : ViewModel
public partial class UpdateViewModel : ViewModel
{
private ApiEndpointViewModel _apiEndpointView => ApplicationService.ApiEndpointView;
@ -25,7 +27,7 @@ public class UpdateViewModel : ViewModel
public UpdateViewModel()
{
Commits = new RangeObservableCollection<GitHubCommit>();
Commits = [];
CommitsView = new ListCollectionView(Commits)
{
GroupDescriptions = { new PropertyGroupDescription("Commit.Author.Date", new DateTimeToDateConverter()) }
@ -35,43 +37,121 @@ public class UpdateViewModel : ViewModel
RemindMeCommand.Execute(this, null);
}
public async Task Load()
public async Task LoadAsync()
{
Commits.AddRange(await _apiEndpointView.GitHubApi.GetCommitHistoryAsync());
var commits = await _apiEndpointView.GitHubApi.GetCommitHistoryAsync();
if (commits == null || commits.Length == 0)
return;
var qa = await _apiEndpointView.GitHubApi.GetReleaseAsync("qa");
var assets = qa.Assets.OrderByDescending(x => x.CreatedAt).ToList();
Commits.AddRange(commits);
for (var i = 0; i < assets.Count; i++)
try
{
var asset = assets[i];
asset.IsLatest = i == 0;
var commitSha = asset.Name.SubstringBeforeLast(".zip");
var commit = Commits.FirstOrDefault(x => x.Sha == commitSha);
if (commit != null)
{
commit.Asset = asset;
}
else
{
Commits.Add(new GitHubCommit
{
Sha = commitSha,
Commit = new Commit
{
Message = $"FModel ({commitSha[..7]})",
Author = new Author { Name = asset.Uploader.Login, Date = asset.CreatedAt }
},
Author = asset.Uploader,
Asset = asset
});
}
_ = LoadCoAuthors();
_ = LoadAssets();
}
catch
{
//
}
}
private Task LoadCoAuthors()
{
return Task.Run(async () =>
{
var coAuthorMap = new Dictionary<GitHubCommit, HashSet<string>>();
foreach (var commit in Commits)
{
if (!commit.Commit.Message.Contains("Co-authored-by"))
continue;
var regex = GetCoAuthorRegex();
var matches = regex.Matches(commit.Commit.Message);
if (matches.Count == 0) continue;
commit.Commit.Message = regex.Replace(commit.Commit.Message, string.Empty).Trim();
coAuthorMap[commit] = [];
foreach (Match match in matches)
{
if (match.Groups.Count < 3) continue;
coAuthorMap[commit].Add(match.Groups[1].Value);
}
}
if (coAuthorMap.Count == 0) return;
var uniqueUsernames = coAuthorMap.Values.SelectMany(x => x).Distinct().ToArray();
var authorCache = new Dictionary<string, Author>();
foreach (var username in uniqueUsernames)
{
try
{
var author = await _apiEndpointView.GitHubApi.GetUserAsync(username);
if (author != null)
authorCache[username] = author;
}
catch
{
//
}
}
foreach (var (commit, usernames) in coAuthorMap)
{
var coAuthors = usernames
.Where(username => authorCache.ContainsKey(username))
.Select(username => authorCache[username])
.ToArray();
if (coAuthors.Length > 0)
commit.CoAuthors = coAuthors;
}
});
}
private Task LoadAssets()
{
return Task.Run(async () =>
{
var qa = await _apiEndpointView.GitHubApi.GetReleaseAsync("qa");
var assets = qa.Assets.OrderByDescending(x => x.CreatedAt).ToList();
for (var i = 0; i < assets.Count; i++)
{
var asset = assets[i];
asset.IsLatest = i == 0;
var commitSha = asset.Name.SubstringBeforeLast(".zip");
var commit = Commits.FirstOrDefault(x => x.Sha == commitSha);
if (commit != null)
{
commit.Asset = asset;
}
else
{
Commits.Add(new GitHubCommit
{
Sha = commitSha,
Commit = new Commit
{
Message = $"FModel ({commitSha[..7]})",
Author = new Author { Name = asset.Uploader.Login, Date = asset.CreatedAt }
},
Author = asset.Uploader,
Asset = asset
});
}
}
});
}
public void DownloadLatest()
{
Commits.FirstOrDefault(x => x.IsDownloadable && x.Asset.IsLatest)?.Download();
}
[GeneratedRegex(@"Co-authored-by:\s*(.+?)\s*<(.+?)>", RegexOptions.IgnoreCase | RegexOptions.Multiline, "en-US")]
private static partial Regex GetCoAuthorRegex();
}

View File

@ -11,13 +11,6 @@
<Setter Property="Title" Value="About" />
</Style>
</adonisControls:AdonisWindow.Style>
<adonisControls:AdonisWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</adonisControls:AdonisWindow.Resources>
<StackPanel Margin="30 10">
<StackPanel HorizontalAlignment="Center" Margin="0 0 0 30">
<TextBlock Text="{Binding Source={x:Static local:Constants.APP_VERSION}, StringFormat={}FModel {0}}" FontSize="15" FontWeight="500" Foreground="#9DA3DD" FontStretch="Expanded" />

View File

@ -14,13 +14,6 @@
<Setter Property="Title" Value="AES Manager" />
</Style>
</adonisControls:AdonisWindow.Style>
<adonisControls:AdonisWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</adonisControls:AdonisWindow.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>

View File

@ -16,13 +16,6 @@
<Setter Property="Title" Value="Audio Player" />
</Style>
</adonisControls:AdonisWindow.Style>
<adonisControls:AdonisWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</adonisControls:AdonisWindow.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="350" />

View File

@ -12,13 +12,6 @@
<Setter Property="Title" Value="Backup Manager" />
</Style>
</adonisControls:AdonisWindow.Style>
<adonisControls:AdonisWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</adonisControls:AdonisWindow.Resources>
<Grid Column="2" adonisExtensions:LayerExtension.Layer="2" Margin="10" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />

View File

@ -14,13 +14,6 @@
<Setter Property="Title" Value="Directory Selector" />
</Style>
</adonisControls:AdonisWindow.Style>
<adonisControls:AdonisWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</adonisControls:AdonisWindow.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>

View File

@ -14,14 +14,6 @@
<Setter Property="Title" Value="Image Merger"/>
</Style>
</adonisControls:AdonisWindow.Style>
<adonisControls:AdonisWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</adonisControls:AdonisWindow.Resources>
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>

View File

@ -0,0 +1,35 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="NeutralBrush" Color="White" />
<SolidColorBrush x:Key="BlueprintBrush" Color="DodgerBlue" />
<SolidColorBrush x:Key="BlueprintWidgetBrush" Color="DarkViolet" />
<SolidColorBrush x:Key="BlueprintAnimBrush" Color="Crimson" />
<SolidColorBrush x:Key="BlueprintRigVMBrush" Color="Teal" />
<SolidColorBrush x:Key="CookedMetaDataBrush" Color="Yellow" />
<SolidColorBrush x:Key="UserDefinedEnumBrush" Color="DarkGoldenrod" />
<SolidColorBrush x:Key="UserDefinedStructBrush" Color="Tan" />
<SolidColorBrush x:Key="MaterialBrush" Color="BurlyWood" />
<SolidColorBrush x:Key="MaterialEditorBrush" Color="Yellow" />
<SolidColorBrush x:Key="BinaryBrush" Color="Yellow" />
<SolidColorBrush x:Key="TextureBrush" Color="MediumPurple" />
<SolidColorBrush x:Key="ConfigBrush" Color="LightSlateGray" />
<SolidColorBrush x:Key="AudioBrush" Color="MediumSeaGreen" />
<SolidColorBrush x:Key="VideoBrush" Color="IndianRed" />
<SolidColorBrush x:Key="DataTableBrush" Color="SteelBlue" />
<SolidColorBrush x:Key="CurveBrush" Color="HotPink" />
<SolidColorBrush x:Key="PluginBrush" Color="GreenYellow" />
<SolidColorBrush x:Key="ProjectBrush" Color="DeepSkyBlue" />
<SolidColorBrush x:Key="LocalizationBrush" Color="CornflowerBlue" />
<SolidColorBrush x:Key="WorldBrush" Color="Orange" />
<SolidColorBrush x:Key="BuildDataBrush" Color="Tomato" />
<SolidColorBrush x:Key="LevelSequenceBrush" Color="Coral" />
<SolidColorBrush x:Key="FoliageBrush" Color="ForestGreen" />
<SolidColorBrush x:Key="ParticleBrush" Color="Gold" />
<SolidColorBrush x:Key="AnimationBrush" Color="Coral" />
<SolidColorBrush x:Key="LuaBrush" Color="DarkBlue" />
<SolidColorBrush x:Key="JsonXmlBrush" Color="LightGreen" />
</ResourceDictionary>

View File

@ -5,13 +5,6 @@
xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit"
xmlns:adonisExtensions="clr-namespace:AdonisUI.Extensions;assembly=AdonisUI"
PreviewKeyDown="OnPreviewKeyDown">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />

View File

@ -2,12 +2,5 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContextChanged="OnDataContextChanged">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<StackPanel x:Name="InMeDaddy" Orientation="Horizontal" HorizontalAlignment="Right" Height="24" />
</UserControl>

View File

@ -1,4 +1,4 @@
using System.Linq;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
@ -10,7 +10,7 @@ namespace FModel.Views.Resources.Controls;
public partial class Breadcrumb
{
private const string _NAVIGATE_NEXT = "M9.31 6.71c-.39.39-.39 1.02 0 1.41L13.19 12l-3.88 3.88c-.39.39-.39 1.02 0 1.41.39.39 1.02.39 1.41 0l4.59-4.59c.39-.39.39-1.02 0-1.41L10.72 6.7c-.38-.38-1.02-.38-1.41.01z";
private const string NavigateNext = "M9.31 6.71c-.39.39-.39 1.02 0 1.41L13.19 12l-3.88 3.88c-.39.39-.39 1.02 0 1.41.39.39 1.02.39 1.41 0l4.59-4.59c.39-.39.39-1.02 0-1.41L10.72 6.7c-.38-.38-1.02-.38-1.41.01z";
public Breadcrumb()
{
@ -25,17 +25,27 @@ public partial class Breadcrumb
var folders = pathAtThisPoint.Split('/');
for (var i = 0; i < folders.Length; i++)
{
var textBlock = new TextBlock
var border = new Border
{
Text = folders[i],
BorderThickness = new Thickness(1),
BorderBrush = Brushes.Transparent,
Background = Brushes.Transparent,
Padding = new Thickness(6, 3, 6, 3),
Cursor = Cursors.Hand,
Tag = i + 1,
Margin = new Thickness(0, 3, 0, 0)
IsEnabled = i < folders.Length - 1,
Child = new TextBlock
{
Text = folders[i],
VerticalAlignment = VerticalAlignment.Center
}
};
textBlock.MouseUp += OnMouseClick;
InMeDaddy.Children.Add(textBlock);
border.MouseEnter += OnMouseEnter;
border.MouseLeave += OnMouseLeave;
border.MouseUp += OnMouseClick;
InMeDaddy.Children.Add(border);
if (i >= folders.Length - 1) continue;
InMeDaddy.Children.Add(new Viewbox
@ -52,7 +62,8 @@ public partial class Breadcrumb
new Path
{
Fill = Brushes.White,
Data = Geometry.Parse(_NAVIGATE_NEXT)
Data = Geometry.Parse(NavigateNext),
Opacity = 0.6
}
}
}
@ -60,13 +71,31 @@ public partial class Breadcrumb
}
}
private void OnMouseEnter(object sender, MouseEventArgs e)
{
if (sender is Border border)
{
border.BorderBrush = new SolidColorBrush(Color.FromRgb(127, 127, 144));
border.Background = new SolidColorBrush(Color.FromRgb(72, 73, 92));
}
}
private void OnMouseLeave(object sender, MouseEventArgs e)
{
if (sender is Border border)
{
border.BorderBrush = Brushes.Transparent;
border.Background = Brushes.Transparent;
}
}
private void OnMouseClick(object sender, MouseButtonEventArgs e)
{
if (sender is not TextBlock { DataContext: string pathAtThisPoint, Tag: int index }) return;
if (sender is not Border { DataContext: string pathAtThisPoint, Tag: int index }) return;
var directory = string.Join('/', pathAtThisPoint.Split('/').Take(index));
if (pathAtThisPoint.Equals(directory)) return;
ApplicationService.ApplicationView.CustomDirectories.GoToCommand.JumpTo(directory);
}
}
}

View File

@ -4,13 +4,6 @@
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
xmlns:controls="clr-namespace:FModel.Views.Resources.Controls">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Border BorderThickness="1" CornerRadius="0.5"
BorderBrush="{DynamicResource {x:Static adonisUi:Brushes.Layer4BackgroundBrush}}">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
@ -42,22 +35,33 @@
<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="16"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Ellipse Grid.Column="0">
<Ellipse.Fill>
<ImageBrush ImageSource="{Binding Author.AvatarUrl}" />
</Ellipse.Fill>
</Ellipse>
<ItemsControl Grid.Column="0" ItemsSource="{Binding Authors}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Width="16" Height="16" Margin="0,0,2,0">
<Ellipse.Fill>
<ImageBrush ImageSource="{Binding AvatarUrl}" />
</Ellipse.Fill>
</Ellipse>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Grid.Column="2" FontSize="11">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} committed {1}">
<Binding Path="Author.Login" />
<Binding Path="AuthorNames" />
<Binding Path="Commit.Author.Date" Converter="{x:Static converters:RelativeDateTimeConverter.Instance}" />
</MultiBinding>
</TextBlock.Text>
@ -128,4 +132,3 @@
</Grid>
</Border>
</UserControl>

View File

@ -3,13 +3,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />

View File

@ -0,0 +1,305 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
xmlns:settings="clr-namespace:FModel.Settings"
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters">
<ContextMenu x:Key="FileContextMenu" x:Shared="False"
DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Window}}">
<MenuItem Header="Extract in New Tab" Command="{Binding RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Extract_New_Tab" />
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource ExtractIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Show Metadata" Command="{Binding RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Show_Metadata" />
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.IsEnabled>
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}">
<Binding.Converter>
<converters:AnyItemMeetsConditionConverter>
<converters:AnyItemMeetsConditionConverter.Conditions>
<converters:ItemIsUePackageCondition />
</converters:AnyItemMeetsConditionConverter.Conditions>
</converters:AnyItemMeetsConditionConverter>
</Binding.Converter>
</Binding>
</MenuItem.IsEnabled>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource InfoIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Find References" Command="{Binding RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Show_References" />
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.IsEnabled>
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}">
<Binding.Converter>
<converters:AnyItemMeetsConditionConverter>
<converters:AnyItemMeetsConditionConverter.Conditions>
<converters:ItemIsUePackageCondition />
<converters:ItemIsIoStoreCondition />
</converters:AnyItemMeetsConditionConverter.Conditions>
</converters:AnyItemMeetsConditionConverter>
</Binding.Converter>
</Binding>
</MenuItem.IsEnabled>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource SearchIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Decompile Blueprint"
Command="{Binding RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Decompile" />
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.IsEnabled>
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}">
<Binding.Converter>
<converters:AnyItemMeetsConditionConverter>
<converters:AnyItemMeetsConditionConverter.Conditions>
<converters:ItemCategoryCondition Category="Blueprint" />
</converters:AnyItemMeetsConditionConverter.Conditions>
</converters:AnyItemMeetsConditionConverter>
</Binding.Converter>
</Binding>
</MenuItem.IsEnabled>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource CppIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
<MenuItem.Style>
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource {x:Type MenuItem}}">
<Style.Triggers>
<DataTrigger Binding="{Binding ShowDecompileOption, Source={x:Static settings:UserSettings.Default}}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
<Separator />
<MenuItem Command="{Binding RightClickMenuCommand}">
<MenuItem.Header>
<TextBlock
Text="{Binding PlacementTarget.SelectedItem.Asset.Extension,
FallbackValue='Export Raw Data',
StringFormat='Export Raw Data (.{0})',
RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
</MenuItem.Header>
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Export_Data" />
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource ExportIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Properties (.json)" Command="{Binding RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Save_Properties" />
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource SaveIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Texture" Command="{Binding RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Save_Textures" />
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.IsEnabled>
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}">
<Binding.Converter>
<converters:AnyItemMeetsConditionConverter>
<converters:AnyItemMeetsConditionConverter.Conditions>
<converters:ItemCategoryCondition Category="Texture" />
</converters:AnyItemMeetsConditionConverter.Conditions>
</converters:AnyItemMeetsConditionConverter>
</Binding.Converter>
</Binding>
</MenuItem.IsEnabled>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource TextureIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Model" Command="{Binding RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Save_Models" />
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.IsEnabled>
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}">
<Binding.Converter>
<converters:AnyItemMeetsConditionConverter>
<converters:AnyItemMeetsConditionConverter.Conditions>
<converters:ItemCategoryCondition Category="Mesh" />
</converters:AnyItemMeetsConditionConverter.Conditions>
</converters:AnyItemMeetsConditionConverter>
</Binding.Converter>
</Binding>
</MenuItem.IsEnabled>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource ModelIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Animation" Command="{Binding RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Save_Animations" />
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.IsEnabled>
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}">
<Binding.Converter>
<converters:AnyItemMeetsConditionConverter>
<converters:AnyItemMeetsConditionConverter.Conditions>
<converters:ItemCategoryCondition Category="Animation" />
</converters:AnyItemMeetsConditionConverter.Conditions>
</converters:AnyItemMeetsConditionConverter>
</Binding.Converter>
</Binding>
</MenuItem.IsEnabled>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AnimationIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Audio" Command="{Binding RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Save_Audio" />
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.IsEnabled>
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}">
<Binding.Converter>
<converters:AnyItemMeetsConditionConverter>
<converters:AnyItemMeetsConditionConverter.Conditions>
<converters:ItemCategoryCondition Category="Audio" />
</converters:AnyItemMeetsConditionConverter.Conditions>
</converters:AnyItemMeetsConditionConverter>
</Binding.Converter>
</Binding>
</MenuItem.IsEnabled>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AudioIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="Copy">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource CopyIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
<MenuItem Header="Package Path" Command="{Binding CopyCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="File_Path" />
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
</MenuItem>
<MenuItem Header="Package Name" Command="{Binding CopyCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="File_Name" />
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
</MenuItem>
<MenuItem Header="Directory Path" Command="{Binding CopyCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Directory_Path" />
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
</MenuItem>
<MenuItem Header="Package Path w/o Extension" Command="{Binding CopyCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="File_Path_No_Extension" />
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
</MenuItem>
<MenuItem Header="Package Name w/o Extension" Command="{Binding CopyCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="File_Name_No_Extension" />
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
</MenuItem>
</MenuItem>
</ContextMenu>
</ResourceDictionary>

View File

@ -0,0 +1,150 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
x:Class="FModel.Views.Resources.Controls.ContextMenus.FolderContextMenuDictionary">
<ContextMenu x:Key="FolderContextMenu" x:Shared="False"
Opened="FolderContextMenu_OnOpened">
<MenuItem Header="Export Folder's Packages Raw Data (.uasset)"
Command="{Binding RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Folders_Export_Data" />
<Binding Path="Tag"
RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16"
Height="16">
<Canvas Width="24"
Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}"
Data="{StaticResource ExportIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Folder's Packages Properties (.json)"
Command="{Binding RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Folders_Save_Properties" />
<Binding Path="Tag"
RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16"
Height="16">
<Canvas Width="24"
Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}"
Data="{StaticResource SaveIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Folder's Packages Textures"
Command="{Binding RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Folders_Save_Textures" />
<Binding Path="Tag"
RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16"
Height="16">
<Canvas Width="24"
Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}"
Data="{StaticResource TextureIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Folder's Packages Models"
Command="{Binding RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Folders_Save_Models" />
<Binding Path="Tag"
RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16"
Height="16">
<Canvas Width="24"
Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}"
Data="{StaticResource ModelIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Folder's Packages Animations"
Command="{Binding RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Folders_Save_Animations" />
<Binding Path="Tag"
RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16"
Height="16">
<Canvas Width="24"
Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}"
Data="{StaticResource AnimationIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save Folder's Packages Audio"
Command="{Binding RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Folders_Save_Audio" />
<Binding Path="Tag"
RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16"
Height="16">
<Canvas Width="24"
Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}"
Data="{StaticResource AudioIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="Favorite Directory" Click="OnFavoriteDirectoryClick"
CommandParameter="{Binding Tag, RelativeSource={RelativeSource AncestorType=ContextMenu}}">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource DirectoriesAddIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Copy Directory Path" Click="OnCopyDirectoryPathClick"
CommandParameter="{Binding Tag, RelativeSource={RelativeSource AncestorType=ContextMenu}}">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource CopyIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ResourceDictionary>

View File

@ -0,0 +1,70 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using FModel.Services;
using FModel.Settings;
using FModel.ViewModels;
namespace FModel.Views.Resources.Controls.ContextMenus;
public partial class FolderContextMenuDictionary
{
private ApplicationViewModel _applicationView => ApplicationService.ApplicationView;
public FolderContextMenuDictionary()
{
InitializeComponent();
}
private void FolderContextMenu_OnOpened(object sender, RoutedEventArgs e)
{
if (sender is not ContextMenu { PlacementTarget: FrameworkElement fe } menu)
return;
var listBox = FindAncestor<ListBox>(fe);
if (listBox != null)
{
menu.DataContext = listBox.DataContext;
menu.Tag = listBox.SelectedItems;
return;
}
var treeView = FindAncestor<TreeView>(fe);
if (treeView != null)
{
menu.DataContext = treeView.DataContext;
menu.Tag = new[] { treeView.SelectedItem }.ToList();
}
}
private static T FindAncestor<T>(DependencyObject current) where T : DependencyObject
{
while (current != null)
{
if (current is T t)
return t;
current = VisualTreeHelper.GetParent(current);
}
return null;
}
private void OnFavoriteDirectoryClick(object sender, RoutedEventArgs e)
{
if (sender is not MenuItem { CommandParameter: IEnumerable<object> list } || list.FirstOrDefault() is not TreeItem folder)
return;
_applicationView.CustomDirectories.Add(new CustomDirectory(folder.Header, folder.PathAtThisPoint));
FLogger.Append(ELog.Information, () =>
FLogger.Text($"Successfully saved '{folder.PathAtThisPoint}' as a new favorite directory", Constants.WHITE, true));
}
private void OnCopyDirectoryPathClick(object sender, RoutedEventArgs e)
{
if (sender is not MenuItem { CommandParameter: IEnumerable<object> list } || list.FirstOrDefault() is not TreeItem folder)
return;
Clipboard.SetText(folder.PathAtThisPoint);
}
}

View File

@ -9,13 +9,6 @@
WindowStartupLocation="CenterScreen" IconVisibility="Collapsed" ResizeMode="NoResize" SizeToContent="Width"
MinWidth="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.30'}"
Height="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.20'}">
<adonisControls:AdonisWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</adonisControls:AdonisWindow.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>

View File

@ -9,13 +9,6 @@
WindowStartupLocation="CenterScreen" IconVisibility="Collapsed" ResizeMode="NoResize"
Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.50'}"
Height="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.35'}">
<adonisControls:AdonisWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</adonisControls:AdonisWindow.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>

View File

@ -4,13 +4,6 @@
xmlns:controls="clr-namespace:FModel.Views.Resources.Controls"
xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI"
WindowStartupLocation="CenterScreen" IconVisibility="Collapsed">
<adonisControls:AdonisWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</adonisControls:AdonisWindow.Resources>
<DockPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<controls:MagnifierManager.Magnifier>
<controls:Magnifier Radius="150" ZoomFactor=".7" />

View File

@ -0,0 +1,41 @@
<UserControl x:Class="FModel.Views.Resources.Controls.Inputs.SearchTextBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignWidth="300"
x:Name="Root"
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
xmlns:adonisExtensions="clr-namespace:AdonisUI.Extensions;assembly=AdonisUI">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" ZIndex="1" HorizontalAlignment="Left" Margin="5 2 0 0">
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource SearchIcon}" />
</Canvas>
</Viewbox>
</Grid>
<TextBox x:Name="TextBox" Grid.Column="0" Grid.ColumnSpan="2" AcceptsTab="False" AcceptsReturn="False"
Text="{Binding Text, ElementName=Root, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Padding="25 0 0 0" HorizontalAlignment="Stretch"
adonisExtensions:WatermarkExtension.Watermark="{Binding Watermark, ElementName=Root}" />
<Button Grid.Column="1" ToolTip="Clear Search Filter" Padding="5"
Click="OnClearButtonClick"
Style="{DynamicResource {x:Static adonisUi:Styles.ToolbarButton}}">
<Viewbox Width="16" Height="16" HorizontalAlignment="Center">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}"
Data="{StaticResource BackspaceIcon}"/>
</Canvas>
</Viewbox>
</Button>
</Grid>
</UserControl>

View File

@ -0,0 +1,48 @@
using System.Windows;
using System.Windows.Controls;
namespace FModel.Views.Resources.Controls.Inputs;
public partial class SearchTextBox : UserControl
{
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register(nameof(Text), typeof(string), typeof(SearchTextBox),
new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public static readonly DependencyProperty WatermarkProperty =
DependencyProperty.Register(nameof(Watermark), typeof(string), typeof(SearchTextBox),
new PropertyMetadata("Search by name..."));
public static readonly RoutedEvent ClearButtonClickEvent =
EventManager.RegisterRoutedEvent(nameof(ClearButtonClick), RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(SearchTextBox));
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public string Watermark
{
get => (string)GetValue(WatermarkProperty);
set => SetValue(WatermarkProperty, value);
}
public event RoutedEventHandler ClearButtonClick
{
add => AddHandler(ClearButtonClickEvent, value);
remove => RemoveHandler(ClearButtonClickEvent, value);
}
public SearchTextBox()
{
InitializeComponent();
}
private void OnClearButtonClick(object sender, RoutedEventArgs e)
{
Text = string.Empty;
RaiseEvent(new RoutedEventArgs(ClearButtonClickEvent, this));
}
}

View File

@ -0,0 +1,42 @@
using System.Windows;
using System.Windows.Controls;
namespace FModel.Views.Resources.Controls;
public sealed class ListBoxItemBehavior
{
public static bool GetIsBroughtIntoViewWhenSelected(ListBoxItem listBoxItem)
{
return (bool) listBoxItem.GetValue(IsBroughtIntoViewWhenSelectedProperty);
}
public static void SetIsBroughtIntoViewWhenSelected(ListBoxItem listBoxItem, bool value)
{
listBoxItem.SetValue(IsBroughtIntoViewWhenSelectedProperty, value);
}
public static readonly DependencyProperty IsBroughtIntoViewWhenSelectedProperty =
DependencyProperty.RegisterAttached("IsBroughtIntoViewWhenSelected", typeof(bool), typeof(ListBoxItemBehavior),
new UIPropertyMetadata(false, OnIsBroughtIntoViewWhenSelectedChanged));
private static void OnIsBroughtIntoViewWhenSelectedChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
{
if (depObj is not ListBoxItem item)
return;
if (e.NewValue is not bool value)
return;
if (value)
item.Selected += OnListBoxItemSelected;
else
item.Selected -= OnListBoxItemSelected;
}
private static void OnListBoxItemSelected(object sender, RoutedEventArgs e)
{
if (e.OriginalSource is ListBoxItem item)
item.BringIntoView();
}
}

View File

@ -7,13 +7,6 @@
xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI"
WindowStartupLocation="CenterScreen" IconVisibility="Collapsed" PreviewKeyDown="OnPreviewKeyDown"
Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.40'}">
<adonisControls:AdonisWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</adonisControls:AdonisWindow.Resources>
<DockPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<avalonEdit:TextEditor x:Name="MyAvalonEditor" Background="{DynamicResource {x:Static adonisUi:Brushes.Layer3BackgroundBrush}}"
FontFamily="Consolas" FontSize="8pt" IsReadOnly="True" ShowLineNumbers="True" Foreground="#DAE5F2"

View File

@ -34,6 +34,11 @@ public class FLogger : ITextFormatter
private static readonly BrushConverter _brushConverter = new();
private static int _previous;
private const string _at = " at ";
private const char _dot = '.';
private const char _colon = ':';
private const string _gray = "#999";
public static void Append(ELog type, Action job)
{
Application.Current.Dispatcher.Invoke(delegate
@ -58,6 +63,45 @@ public class FLogger : ITextFormatter
}, DispatcherPriority.Background);
}
public static void Append(Exception e)
{
Append(ELog.Error, () =>
{
if ((e.InnerException ?? e) is { TargetSite.DeclaringType: not null } exception)
{
if (exception.TargetSite.ToString() == "CUE4Parse.FileProvider.GameFile get_Item(System.String)")
{
Text(e.Message, Constants.WHITE, true);
}
else
{
var t = exception.GetType();
Text(t.Namespace + _dot, Constants.GRAY);
Text(t.Name, Constants.WHITE);
Text(_colon + " ", Constants.GRAY);
Text(exception.Message, Constants.RED, true);
Text(_at, _gray);
Text(exception.TargetSite.DeclaringType.FullName + _dot, Constants.GRAY);
Text(exception.TargetSite.Name, Constants.YELLOW);
var p = exception.TargetSite.GetParameters();
var parameters = new string[p.Length];
for (int i = 0; i < parameters.Length; i++)
{
parameters[i] = p[i].ParameterType.Name + " " + p[i].Name;
}
Text("(" + string.Join(", ", parameters) + ")", Constants.GRAY, true);
}
}
else
{
Text(e.Message, Constants.WHITE, true);
}
});
}
public static void Text(string message, string color, bool newLine = false)
{
try

View File

@ -0,0 +1,81 @@
<UserControl x:Class="FModel.Views.Resources.Controls.TiledExplorer.FileButton2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignWidth="128" d:DesignHeight="192"
d:DataContext="{d:DesignInstance Type=vm:GameFileViewModel, IsDesignTimeCreatable=False}"
xmlns:vm="clr-namespace:FModel.ViewModels"
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
Width="128" Height="192"
Background="{DynamicResource {x:Static adonisUi:Brushes.Layer4BackgroundBrush}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="2" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Height="128" Background="{DynamicResource {x:Static adonisUi:Brushes.Layer3BorderBrush}}">
<Image Stretch="Uniform" Source="{Binding PreviewImage}" />
<Path x:Name="FallbackIcon" Width="64" Stretch="Uniform">
<Path.Style>
<Style TargetType="{x:Type Path}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding PreviewImage}" Value="{x:Null}">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Path.Style>
<Path.Data>
<MultiBinding Converter="{x:Static converters:FileToGeometryConverter.Instance}">
<Binding Path="AssetCategory" />
<Binding Path="ResolvedAssetType" />
</MultiBinding>
</Path.Data>
<Path.Fill>
<MultiBinding Converter="{x:Static converters:FileToGeometryConverter.Instance}">
<Binding Path="AssetCategory" />
<Binding Path="ResolvedAssetType" />
</MultiBinding>
</Path.Fill>
</Path>
</Grid>
<Rectangle Grid.Row="1" Fill="{Binding Fill, ElementName=FallbackIcon, FallbackValue=Red}" />
<Grid Grid.Row="2" Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Asset.NameWithoutExtension, FallbackValue=Asset Name}"
FontSize="13" TextWrapping="Wrap" TextTrimming="CharacterEllipsis" FontWeight="DemiBold"
TextAlignment="Left" HorizontalAlignment="Left" VerticalAlignment="Top"
Foreground="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}"/>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding ResolvedAssetType, FallbackValue=Asset Type}"
FontSize="9" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" FontWeight="Normal"
TextAlignment="Left" HorizontalAlignment="Left" VerticalAlignment="Bottom"
Foreground="{DynamicResource {x:Static adonisUi:Brushes.DisabledForegroundBrush}}" />
<TextBlock Grid.Column="2" Text="{Binding Asset.Size, Converter={x:Static converters:SizeToStringConverter.Instance}, FallbackValue=0 B}"
FontSize="9" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" FontWeight="Normal"
TextAlignment="Right" HorizontalAlignment="Right" VerticalAlignment="Bottom"
Foreground="{DynamicResource {x:Static adonisUi:Brushes.DisabledForegroundBrush}}" />
</Grid>
</Grid>
</Grid>
</UserControl>

View File

@ -0,0 +1,12 @@
using System.Windows.Controls;
namespace FModel.Views.Resources.Controls.TiledExplorer;
public partial class FileButton2 : UserControl
{
public FileButton2()
{
InitializeComponent();
}
}

View File

@ -0,0 +1,110 @@
<UserControl x:Class="FModel.Views.Resources.Controls.TiledExplorer.FolderButton2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignWidth="128" d:DesignHeight="192"
d:DataContext="{d:DesignInstance Type=vm:TreeItem, IsDesignTimeCreatable=False}"
xmlns:vm="clr-namespace:FModel.ViewModels"
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
Width="128" Height="192"
Padding="5"
Background="{DynamicResource {x:Static adonisUi:Brushes.Layer2BackgroundBrush}}">
<Grid VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="2" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<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}"
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}"
StrokeThickness="2"
Data="M13 60 H115 V104 C115 110 110 115 104 115 H24 C18 115 13 110 13 104 Z" />
<Ellipse Canvas.Left="90" Canvas.Top="90" Width="36" Height="36"
Opacity="0.95" Stroke="#b28c53" StrokeThickness="1.5"
Fill="{DynamicResource {x:Static adonisUi:Brushes.Layer3BackgroundBrush}}"
Visibility="{Binding Visibility, ElementName=HintIcon}" />
<Path x:Name="HintIcon" Canvas.Left="98" Canvas.Top="98" Width="20" Height="20" Stretch="Uniform"
Data="{Binding Header, Converter={x:Static converters:FolderToGeometryConverter.Instance}}"
Fill="{Binding Header, Converter={x:Static converters:FolderToGeometryConverter.Instance}}">
<Path.Style>
<Style TargetType="Path">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding Data, RelativeSource={RelativeSource Self}}" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
</Canvas>
</Viewbox>
<Grid Grid.Row="2"
Margin="0 10 0 0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="6" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Text="{Binding Header, FallbackValue=Folder Name}"
FontSize="13"
TextWrapping="NoWrap"
TextTrimming="CharacterEllipsis"
FontWeight="DemiBold"
TextAlignment="Center"
HorizontalAlignment="Center"
Foreground="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" />
<TextBlock Grid.Row="2"
Text="{Binding Folders.Count, StringFormat=Subfolders: {0}}"
FontSize="11"
HorizontalAlignment="Center"
Foreground="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}"
Opacity="0.8" />
<TextBlock Grid.Row="3"
Text="{Binding AssetsList.Assets.Count, StringFormat=Assets: {0}}"
FontSize="11"
HorizontalAlignment="Center"
Foreground="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}"
Opacity="0.8" />
</Grid>
</Grid>
</UserControl>

View File

@ -0,0 +1,11 @@
using System.Windows.Controls;
namespace FModel.Views.Resources.Controls.TiledExplorer;
public partial class FolderButton2 : UserControl
{
public FolderButton2()
{
InitializeComponent();
}
}

View File

@ -0,0 +1,92 @@
<UserControl x:Class="FModel.Views.Resources.Controls.TiledExplorer.FolderButton3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignWidth="128" d:DesignHeight="192"
d:DataContext="{d:DesignInstance Type=vm:TreeItem, IsDesignTimeCreatable=False}"
xmlns:vm="clr-namespace:FModel.ViewModels"
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
Width="128" Height="192"
Background="{DynamicResource {x:Static adonisUi:Brushes.Layer4BackgroundBrush}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="2" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Viewbox Grid.Row="0" Height="128">
<Canvas Width="128" Height="128">
<Canvas.Resources>
<LinearGradientBrush x:Key="TabGradient" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#c9975f" Offset="0" />
<GradientStop Color="#b28c53" Offset="0.5" />
<GradientStop Color="#a67f47" Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="BodyGradient" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#d4ae75" Offset="0" />
<GradientStop Color="#c9a167" Offset="0.3" />
<GradientStop Color="#b89456" Offset="1" />
</LinearGradientBrush>
</Canvas.Resources>
<Path Fill="{StaticResource TabGradient}" Data="M16.0018 36l0 -0.0701281 -0.00162402 -6.66681c-0.00509351,-0.616462 0.113829,-1.21757 0.342594,-1.77092 0.231423,-0.559917 0.572171,-1.07266 1.00696,-1.50532 0.433169,-0.431029 0.945252,-0.767794 1.50347,-0.997075 0.565823,-0.232308 1.16664,-0.355291 1.76937,-0.355291l21.1332 0c0.951601,0 1.85847,0.293947 2.61673,0.810088 0.736639,0.501452 1.3282,1.21875 1.67805,2.08502l0.00118111 -0.000442914 3.63056 8.46288 0.00346949 0.00797243 -33.6839 0z" />
<Path Fill="{StaticResource BodyGradient}" Data="M108.153 43.8407l-0.0177904 9.81969c0.785875,0.192373 1.50296,0.514888 2.10509,0.981201 1.08706,0.841681 1.75062,2.06176 1.75298,3.71021l-0.000664368 39.2644 0.00752957 0c0,1.58298 -0.652563,3.01883 -1.70758,4.06093 -1.045,1.03266 -2.48541,1.67126 -4.072,1.67126l-5.88529 0c-0.0760337,0.00967031 -0.159523,0.017126 -0.266782,0.017126l-76.1944 0c-2.15884,0 -4.12043,-0.871213 -5.54403,-2.27754 -1.43312,-1.4157 -2.32116,-3.36711 -2.32116,-5.51553l0.00752957 0 -0.0145423 -59.5726 33.6839 0 0.053814 0.125493 50.7405 0.0420768 0 -0.00745568c2.16629,0 4.07872,0.839394 5.45766,2.21856 1.38698,1.38706 2.22269,3.30945 2.22269,5.46209l-0.00752957 0z" />
<Path Fill="#b28c53" Data="M108 53.6604l-74.8763 0c-0.499091,0 -0.926356,0.196998 -1.22768,0.512895 -0.339715,0.356103 -0.542126,0.865894 -0.542126,1.43438l0 47.7579 -3.84043 0 0 -47.7579c0,-1.56880 0.600001,-3.01883 1.60733,-4.07466 1.00667,-1.05509 2.4017,-1.71304 4.00291,-1.71304l74.8763 0 0 3.84043z" />
<Ellipse Canvas.Left="80" Canvas.Top="80" Width="36" Height="36"
Opacity="0.95" Stroke="#b28c53" StrokeThickness="1.5"
Fill="{DynamicResource {x:Static adonisUi:Brushes.Layer3BackgroundBrush}}"
Visibility="{Binding Visibility, ElementName=HintIcon}" />
<Path x:Name="HintIcon" Canvas.Left="88" Canvas.Top="88" Width="20" Height="20" Stretch="Uniform"
Data="{Binding Header, Converter={x:Static converters:FolderToGeometryConverter.Instance}}"
Fill="{Binding Header, Converter={x:Static converters:FolderToGeometryConverter.Instance}}">
<Path.Style>
<Style TargetType="Path">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding Data, RelativeSource={RelativeSource Self}}" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
</Canvas>
</Viewbox>
<Grid Grid.Row="2" Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="2" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Header, FallbackValue=Folder Name}"
FontSize="13" TextWrapping="Wrap" TextTrimming="CharacterEllipsis" FontWeight="DemiBold"
TextAlignment="Center" HorizontalAlignment="Stretch" VerticalAlignment="Top"
Foreground="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}"/>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition>
<ColumnDefinition.Width>
<MultiBinding Converter="{x:Static converters:RatioToGridLengthConverter.Instance}">
<Binding Path="Folders.Count" />
<Binding Path="AssetsList.Assets.Count" />
</MultiBinding>
</ColumnDefinition.Width>
</ColumnDefinition>
<ColumnDefinition Width="1" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="#E8C480" />
<Border Grid.Column="2" Background="#A8D8EA" />
</Grid>
</Grid>
</Grid>
</UserControl>

View File

@ -0,0 +1,11 @@
using System.Windows.Controls;
namespace FModel.Views.Resources.Controls.TiledExplorer;
public partial class FolderButton3 : UserControl
{
public FolderButton3()
{
InitializeComponent();
}
}

View File

@ -0,0 +1,117 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vwp="clr-namespace:WpfToolkit.Controls;assembly=VirtualizingWrapPanel"
xmlns:vm="clr-namespace:FModel.ViewModels"
xmlns:controls="clr-namespace:FModel.Views.Resources.Controls"
xmlns:local="clr-namespace:FModel.Views.Resources.Controls.TiledExplorer"
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
xmlns:adonisExtensions="clr-namespace:AdonisUI.Extensions;assembly=AdonisUI"
xmlns:adonisConverters="clr-namespace:AdonisUI.Converters;assembly=AdonisUI"
x:Class="FModel.Views.Resources.Controls.TiledExplorer.ResourcesDictionary">
<controls:TypeDataTemplateSelector x:Key="TemplateSelector" />
<Style x:Key="TiledExplorer" TargetType="ListBox" BasedOn="{StaticResource {x:Type ListBox}}">
<Setter Property="local:SmoothScroll.IsEnabled" Value="True" />
<Setter Property="local:SmoothScroll.Factor" Value="1.25" />
<Setter Property="SelectionMode" Value="Extended" />
<Setter Property="ContextMenu" Value="{StaticResource FileContextMenu}" />
<Setter Property="VirtualizingPanel.IsVirtualizing" Value="True" />
<Setter Property="VirtualizingPanel.VirtualizationMode" Value="Recycling" />
<Setter Property="ScrollViewer.CanContentScroll" Value="True" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=OneWay}" />
<Setter Property="Margin" Value="5" />
<Setter Property="Padding" Value="5" />
<Setter Property="BorderThickness" Value="1.5" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="controls:ListBoxItemBehavior.IsBroughtIntoViewWhenSelected" Value="True" />
<Setter Property="Background" Value="{DynamicResource {x:Static adonisUi:Brushes.Layer0BackgroundBrush}}" />
<EventSetter Event="MouseDoubleClick" Handler="OnMouseDoubleClick" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid>
<Border x:Name="Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding adonisExtensions:CornerRadiusExtension.CornerRadius}">
<ContentPresenter />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<vwp:VirtualizingWrapPanel Orientation="Horizontal" SpacingMode="Uniform" ScrollUnit="Pixel" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<ContentControl Content="{Binding}" ContentTemplateSelector="{StaticResource TemplateSelector}" />
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Grid>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer Focusable="False">
<ItemsPresenter />
</ScrollViewer>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ItemsSource, RelativeSource={RelativeSource Self}, Converter={x:Static adonisConverters:IsNullToBoolConverter.Instance}}" Value="False" />
<Condition Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}, FallbackValue=0}" Value="0" />
</MultiDataTrigger.Conditions>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<TextBlock Text="No folders or packages found" FontWeight="SemiBold" TextAlignment="Center"
Foreground="{DynamicResource {x:Static adonisUi:Brushes.ErrorBrush}}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>
<DataTemplate x:Key="TiledFileDataTemplate" DataType="{x:Type vm:GameFileViewModel}">
<local:FileButton2 />
</DataTemplate>
<DataTemplate x:Key="TiledFolderDataTemplate" DataType="{x:Type vm:TreeItem}">
<local:FolderButton2 ContextMenu="{StaticResource FolderContextMenu}" />
</DataTemplate>
</ResourceDictionary>

View File

@ -0,0 +1,52 @@
using System.Windows.Controls;
using System.Windows.Input;
using FModel.Services;
using FModel.ViewModels;
namespace FModel.Views.Resources.Controls.TiledExplorer;
public partial class ResourcesDictionary
{
public ResourcesDictionary()
{
InitializeComponent();
}
private void OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (sender is not ListBoxItem item)
return;
switch (item.DataContext)
{
case GameFileViewModel file:
ApplicationService.ApplicationView.SelectedLeftTabIndex = 2;
file.IsSelected = true;
file.ExtractAsync();
break;
case TreeItem folder:
ApplicationService.ApplicationView.SelectedLeftTabIndex = 1;
// Expand all parent folders if not expanded
var parent = folder.Parent;
while (parent != null)
{
parent.IsExpanded = true;
parent = parent.Parent;
}
// Auto expand single child folders
var childFolder = folder;
while (childFolder.Folders.Count == 1 && childFolder.AssetsList.Assets.Count == 0)
{
childFolder.IsExpanded = true;
childFolder = childFolder.Folders[0];
}
childFolder.IsExpanded = true;
childFolder.IsSelected = true;
break;
}
}
}

View File

@ -0,0 +1,90 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace FModel.Views.Resources.Controls.TiledExplorer;
/// <summary>
/// Attached behavior to reduce mouse-wheel scroll sensitivity for elements containing a ScrollViewer.
/// Attach to the ListBox (or its Style) with IsEnabled="True" and optionally set Factor to control strength.
/// Smaller Factor -> smaller scroll per notch.
/// </summary>
public static class SmoothScroll
{
public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached(
"IsEnabled", typeof(bool), typeof(SmoothScroll), new PropertyMetadata(false, OnIsEnabledChanged));
public static readonly DependencyProperty FactorProperty = DependencyProperty.RegisterAttached(
"Factor", typeof(double), typeof(SmoothScroll), new PropertyMetadata(0.25));
public static void SetIsEnabled(DependencyObject obj, bool value) => obj.SetValue(IsEnabledProperty, value);
public static bool GetIsEnabled(DependencyObject obj) => (bool)obj.GetValue(IsEnabledProperty);
public static void SetFactor(DependencyObject obj, double value) => obj.SetValue(FactorProperty, value);
public static double GetFactor(DependencyObject obj) => (double)obj.GetValue(FactorProperty);
private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is UIElement element)
{
if ((bool)e.NewValue)
element.PreviewMouseWheel += Element_PreviewMouseWheel;
else
element.PreviewMouseWheel -= Element_PreviewMouseWheel;
}
}
private static void Element_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (sender is not DependencyObject dep) return;
var sv = FindScrollViewer(dep);
if (sv == null) return;
double factor = GetFactor(dep);
if (double.IsNaN(factor) || factor <= 0) factor = 0.25;
// e.Delta is typically +/-120 per notch
double notches = e.Delta / 120.0;
// Base pixels per notch (tweakable); smaller value gives smoother/less jumpy scroll
const double basePixelsPerNotch = 50.0;
double adjustedPixels = notches * basePixelsPerNotch * factor;
// Prefer vertical scrolling when possible
if (sv.ScrollableHeight > 0)
{
double newOffset = sv.VerticalOffset - adjustedPixels;
if (newOffset < 0) newOffset = 0;
if (newOffset > sv.ScrollableHeight) newOffset = sv.ScrollableHeight;
sv.ScrollToVerticalOffset(newOffset);
e.Handled = true;
return;
}
if (sv.ScrollableWidth > 0)
{
double newOffset = sv.HorizontalOffset - adjustedPixels;
if (newOffset < 0) newOffset = 0;
if (newOffset > sv.ScrollableWidth) newOffset = sv.ScrollableWidth;
sv.ScrollToHorizontalOffset(newOffset);
e.Handled = true;
}
}
private static ScrollViewer FindScrollViewer(DependencyObject d)
{
if (d == null) return null;
if (d is ScrollViewer sv) return sv;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(d); i++)
{
var child = VisualTreeHelper.GetChild(d, i);
var result = FindScrollViewer(child);
if (result != null) return result;
}
return null;
}
}

View File

@ -0,0 +1,18 @@
using System.Windows;
using System.Windows.Controls;
using FModel.ViewModels;
namespace FModel.Views.Resources.Controls;
public class TypeDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
return item switch
{
TreeItem when container is FrameworkElement f => f.FindResource("TiledFolderDataTemplate") as DataTemplate,
GameFileViewModel when container is FrameworkElement f => f.FindResource("TiledFileDataTemplate") as DataTemplate,
_ => base.SelectTemplate(item, container)
};
}
}

View File

@ -0,0 +1,60 @@
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Windows.Data;
using CUE4Parse.UE4.IO.Objects;
using FModel.Extensions;
using FModel.ViewModels;
namespace FModel.Views.Resources.Converters;
public class AnyItemMeetsConditionConverter : IValueConverter
{
public Collection<IItemCondition> Conditions { get; } = [];
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is not IEnumerable items || Conditions.Count == 0)
return false;
return items.OfType<GameFileViewModel>().Any(item => Conditions.All(c => c.Matches(item)));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public interface IItemCondition
{
bool Matches(GameFileViewModel item);
}
public class ItemCategoryCondition : IItemCondition
{
public EAssetCategory Category { get; set; }
public bool Matches(GameFileViewModel item)
{
return item != null && item.AssetCategory.IsOfCategory(Category);
}
}
public class ItemIsUePackageCondition : IItemCondition
{
public bool Matches(GameFileViewModel item)
{
return item?.Asset?.IsUePackage ?? false;
}
}
public class ItemIsIoStoreCondition : IItemCondition
{
public bool Matches(GameFileViewModel item)
{
return item?.Asset is FIoStoreEntry;
}
}

View File

@ -0,0 +1,91 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
namespace FModel.Views.Resources.Converters;
public class FileToGeometryConverter : IMultiValueConverter
{
public static readonly FileToGeometryConverter Instance = new();
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length < 2 || values[0] is not EAssetCategory category || values[1] is not string resolvedAssetType)
return null;
resolvedAssetType = resolvedAssetType.ToLowerInvariant();
var (geometry, brush) = category switch
{
EAssetCategory.Blueprint => ("BlueprintIcon", "BlueprintBrush"),
EAssetCategory.BlueprintGeneratedClass => ("BlueprintIcon", "BlueprintBrush"),
EAssetCategory.WidgetBlueprintGeneratedClass => ("BlueprintIcon", "BlueprintWidgetBrush"),
EAssetCategory.AnimBlueprintGeneratedClass => ("BlueprintIcon" , "BlueprintAnimBrush"),
EAssetCategory.RigVMBlueprintGeneratedClass => ("BlueprintIcon", "BlueprintRigVMBrush"),
EAssetCategory.UserDefinedEnum => ("BlueprintIcon", "UserDefinedEnumBrush"),
EAssetCategory.UserDefinedStruct => ("BlueprintIcon", "UserDefinedStructBrush"),
EAssetCategory.CookedMetaData => ("BlueprintIcon", "CookedMetaDataBrush"),
EAssetCategory.Texture => ("TextureIconAlt", "TextureBrush"),
EAssetCategory.StaticMesh => ("StaticMeshIconAlt", "NeutralBrush"),
EAssetCategory.SkeletalMesh => ("SkeletalMeshIconAlt", "NeutralBrush"),
EAssetCategory.Skeleton => ("SkeletonIcon", "NeutralBrush"),
EAssetCategory.Material => ("MaterialIcon", "MaterialBrush"),
EAssetCategory.MaterialEditorData => ("MaterialIcon", "MaterialEditorBrush"),
EAssetCategory.MaterialParameterCollection => ("MaterialParameterCollectionIcon", "MaterialBrush"),
EAssetCategory.MaterialFunction => ("MaterialFunctionIcon", "MaterialBrush"),
EAssetCategory.Animation => ("AnimationIconAlt", "AnimationBrush"),
EAssetCategory.World => ("WorldIcon", "WorldBrush"),
EAssetCategory.BuildData => ("MapIconAlt", "BuildDataBrush"),
EAssetCategory.LevelSequence => ("ClapperIcon", "LevelSequenceBrush"),
EAssetCategory.Foliage => ("FoliageIcon", "FoliageBrush"),
EAssetCategory.PhysicsAsset => ("PhysicsIcon", "NeutralBrush"),
EAssetCategory.CurveBase => ("CurveIcon", "CurveBrush"),
EAssetCategory.ItemDefinitionBase => ("DataTableIcon", "NeutralBrush"),
EAssetCategory.Audio => ("AudioIconAlt", "AudioBrush"),
EAssetCategory.Video => ("VideoIcon", "VideoBrush"),
EAssetCategory.Font => ("FontIcon", "NeutralBrush"),
EAssetCategory.Particle => ("ParticleIcon", "ParticleBrush"),
EAssetCategory.Data => resolvedAssetType switch
{
"uplugin" or "upluginmanifest" => ("PluginIcon", "PluginBrush"),
"uproject" or "uefnproject" => ("PluginIcon", "ProjectBrush"),
"ini" => ("ConfigIcon", "ConfigBrush"),
"locmeta" or "locres" => ("LocaleIcon", "LocalizationBrush"),
"lua" or "luac" => ("LuaIcon", "LuaBrush"),
"json5" or "json" => ("JsonIcon", "JsonXmlBrush"),
"txt" or "log" => ("TxtIcon", "NeutralBrush"),
"pem" => ("CertificateIcon", "NeutralBrush"),
"verse" => ("VerseIcon", "NeutralBrush"),
"function" => ("FunctionIcon", "NeutralBrush"),
"bin" => ("DataTableIcon", "BinaryBrush"),
"xml" => ("XmlIcon", "JsonXmlBrush"),
_ => ("DataTableIcon", "NeutralBrush")
},
_ => ("AssetIcon", "NeutralBrush")
};
if (targetType == typeof(Geometry))
return Application.Current.FindResource(geometry) as Geometry;
if (targetType == typeof(Brush))
return Application.Current.FindResource(brush) as Brush;
return null;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

View File

@ -0,0 +1,57 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
namespace FModel.Views.Resources.Converters;
public class FolderToGeometryConverter : IValueConverter
{
public static readonly FolderToGeometryConverter Instance = new();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is not string folderName)
return null;
folderName = folderName.ToLowerInvariant();
var (geometry, brush) = folderName switch
{
"textures" or "texture" or "ui" or "icons" or "umgassets" or "hud" or "hdri" or "tex" => ("TextureIconAlt", "TextureBrush"),
"config" or "tags" => ("ConfigIcon", "ConfigBrush"),
"audio" or "wwiseaudio" or "wwise" or "fmod" or "soundbanks" or "banks" or "sound" or "sounds" or "cue" => ("AudioIconAlt", "AudioBrush"),
"movies" or "video" or "videos" or "cinematics" => ("VideoIcon", "VideoBrush"),
"data" or "datatable" or "datatables" => ("DataTableIcon", "DataTableBrush"),
"curves" => ("CurveIcon", "CurveBrush"),
"bp" or "blueprint" or "blueprints" or "audioblueprints" => ("BlueprintIcon", "BlueprintBrush"),
"staticmesh" or "mesh" or "meshes" or "model" or "models" or "characters" or "environment" or "props" => ("StaticMeshIconAlt", "NeutralBrush"),
"material" or "materials" or "materialinstance" or "mastermaterial" => ("MaterialIcon", "MaterialBrush"),
"materialfunctions" or "materialfunction" => ("MaterialFunctionIcon", "MaterialBrush"),
"plugin" or "plugins" => ("PluginIcon", "PluginBrush"),
"localization" => ("LocaleIcon", "LocalizationBrush"),
"map" or "maps" or "world" or "worlds" => ("WorldIcon", "WorldBrush"),
"effect" or "effects" or "niagara" or "vfx" or "particlesystems" or "particles" => ("ParticleIcon", "ParticleBrush"),
"animation" or "animations" or "anim" or "animsequences" or "animsequence" or "montage" or "montages" => ("AnimationIconAlt", "AnimationBrush"),
"physics" or "physicasset" or "physicassets" => ("PhysicsIcon", "NeutralBrush"),
"windows" => ("MonitorIcon", "NeutralBrush"),
"locale" or "localization" or "l10n" => ("LocaleIcon", "LocalizationBrush"),
"skeleton" or "skeletons" => ("SkeletonIcon", "NeutralBrush"),
"certificate" or "certificates" => ("CertificateIcon", "NeutralBrush"),
_ => (null, "NeutralBrush"),
};
if (targetType == typeof(Geometry) && geometry != null)
return Application.Current.FindResource(geometry) as Geometry;
if (targetType == typeof(Brush))
return Application.Current.FindResource(brush) as Brush;
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

View File

@ -0,0 +1,57 @@
using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Windows.Data;
using CUE4Parse.FileProvider.Objects;
using CUE4Parse.UE4.IO.Objects;
using FModel.ViewModels;
namespace FModel.Views.Resources.Converters;
/// <summary>
/// TODO: migrate legacy view models to use GameFileViewModel instead of GameFile, then remove this converter
/// for example <see cref="TabItem"/> or <see cref="SearchViewModel"/>
/// </summary>
public class GameFileMeetsConditionConverter : IValueConverter
{
public Collection<IGameFileCondition> Conditions { get; } = [];
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var gameFile = value switch
{
GameFile file => file,
TabItem tabItem => tabItem.Entry,
_ => null
};
if (gameFile is null || Conditions.Count == 0) return false;
return Conditions.All(c => c.Matches(gameFile));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public interface IGameFileCondition
{
bool Matches(GameFile item);
}
public class GameFileIsUePackageCondition : IGameFileCondition
{
public bool Matches(GameFile item)
{
return item?.IsUePackage ?? false;
}
}
public class GameFileIsIoStoreCondition : IGameFileCondition
{
public bool Matches(GameFile item)
{
return item is FIoStoreEntry;
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace FModel.Views.Resources.Converters;
public class InvertBoolToVisibilityConverter : IValueConverter
{
public static readonly InvertBoolToVisibilityConverter Instance = new();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool boolValue)
{
bool useHidden = parameter?.ToString().Equals("Hidden", StringComparison.OrdinalIgnoreCase) ?? false;
return boolValue ? (useHidden ? Visibility.Hidden : Visibility.Collapsed) : Visibility.Visible;
}
return Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Visibility visibility)
{
return visibility != Visibility.Visible;
}
return true;
}
}

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Globalization;
using System.Windows.Data;
@ -18,7 +18,5 @@ public class InvertBooleanConverter : IValueConverter
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
=> value is bool b ? !b : value;
}

View File

@ -0,0 +1,32 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace FModel.Views.Resources.Converters;
public class RatioToGridLengthConverter : IMultiValueConverter
{
public static readonly RatioToGridLengthConverter Instance = new();
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length < 2)
return new GridLength(1, GridUnitType.Star);
var count1 = values[0] is int c1 ? c1 : 0;
var count2 = values[1] is int c2 ? c2 : 0;
var total = count1 + count2;
if (total == 0) return new GridLength(1, GridUnitType.Star);
var ratio = (double)count1 / total;
return new GridLength(ratio, GridUnitType.Star);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Markup;
using System.Windows.Shell;
namespace FModel.Views.Resources.Converters;
public class StatusToTaskbarStateConverter : MarkupExtension, IMultiValueConverter
{
private static readonly StatusToTaskbarStateConverter _instance = new();
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length != 2 || values[1] is true || values[0] is not EStatusKind kind)
return TaskbarItemProgressState.None;
return kind switch
{
EStatusKind.Loading => TaskbarItemProgressState.Normal,
EStatusKind.Stopping => TaskbarItemProgressState.Paused,
EStatusKind.Failed => TaskbarItemProgressState.Error,
_ => TaskbarItemProgressState.None,
};
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
=> throw new NotSupportedException();
public override object ProvideValue(IServiceProvider serviceProvider) => _instance;
}

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Globalization;
using System.Windows.Controls;
using System.Windows.Data;
@ -23,4 +23,4 @@ public class TabSizeConverter : IMultiValueConverter
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,93 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Geometry x:Key="StatusBarIcon">M22,9v6c0,1.1-0.9,2-2,2h-1l0-2h1V9H4v6h6v2H4c-1.1,0-2-0.9-2-2V9c0-1.1,0.9-2,2-2h16C21.1,7,22,7.9,22,9z M14.04,17.99 c0.18,0.39,0.73,0.39,0.91,0l0.63-1.4l1.4-0.63c0.39-0.18,0.39-0.73,0-0.91l-1.4-0.63l-0.63-1.4c-0.18-0.39-0.73-0.39-0.91,0 l-0.63,1.4l-1.4,0.63c-0.39,0.18-0.39,0.73,0,0.91l1.4,0.63L14.04,17.99z M16.74,13.43c0.1,0.22,0.42,0.22,0.52,0l0.36-0.8 l0.8-0.36c0.22-0.1,0.22-0.42,0-0.52l-0.8-0.36l-0.36-0.8c-0.1-0.22-0.42-0.22-0.52,0l-0.36,0.8l-0.8,0.36 c-0.22,0.1-0.22,0.42,0,0.52l0.8,0.36L16.74,13.43z</Geometry>
<Geometry x:Key="SearchIcon">M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z</Geometry>
<Geometry x:Key="DirectoryIcon">M19.71,15.71l-3.59,3.59c-0.63,0.63-1.71,0.18-1.71-0.71V16h-7c-1.1,0-2-0.9-2-2V5c0-0.55,0.45-1,1-1h0c0.55,0,1,0.45,1,1 v9h7v-2.59c0-0.89,1.08-1.34,1.71-0.71l3.59,3.59C20.1,14.68,20.1,15.32,19.71,15.71z</Geometry>
<Geometry x:Key="AddIcon">M18 13h-5v5c0 .55-.45 1-1 1s-1-.45-1-1v-5H6c-.55 0-1-.45-1-1s.45-1 1-1h5V6c0-.55.45-1 1-1s1 .45 1 1v5h5c.55 0 1 .45 1 1s-.45 1-1 1z</Geometry>
<Geometry x:Key="RemoveIcon">M18.3,5.71L18.3,5.71c-0.39-0.39-1.02-0.39-1.41,0L12,10.59L7.11,5.7c-0.39-0.39-1.02-0.39-1.41,0l0,0 c-0.39,0.39-0.39,1.02,0,1.41L10.59,12L5.7,16.89c-0.39,0.39-0.39,1.02,0,1.41l0,0c0.39,0.39,1.02,0.39,1.41,0L12,13.41l4.89,4.89 c0.39,0.39,1.02,0.39,1.41,0l0,0c0.39-0.39,0.39-1.02,0-1.41L13.41,12l4.89-4.89C18.68,6.73,18.68,6.09,18.3,5.71z</Geometry>
<Geometry x:Key="ArrowIcon">M7.71,9.29l3.88,3.88l3.88-3.88c0.39-0.39,1.02-0.39,1.41,0l0,0c0.39,0.39,0.39,1.02,0,1.41l-4.59,4.59 c-0.39,0.39-1.02,0.39-1.41,0L6.29,10.7c-0.39-0.39-0.39-1.02,0-1.41l0,0C6.68,8.91,7.32,8.9,7.71,9.29z</Geometry>
<Geometry x:Key="KeyIcon">M3,17h18c0.55,0,1,0.45,1,1v0c0,0.55-0.45,1-1,1H3c-0.55,0-1-0.45-1-1v0C2,17.45,2.45,17,3,17z M2.5,12.57 c0.36,0.21,0.82,0.08,1.03-0.28L4,11.47l0.48,0.83c0.21,0.36,0.67,0.48,1.03,0.28l0,0c0.36-0.21,0.48-0.66,0.28-1.02L5.3,10.72 h0.95C6.66,10.72,7,10.38,7,9.97v0c0-0.41-0.34-0.75-0.75-0.75H5.3L5.77,8.4C5.98,8.04,5.86,7.58,5.5,7.37l0,0 C5.14,7.17,4.68,7.29,4.47,7.65L4,8.47L3.53,7.65C3.32,7.29,2.86,7.17,2.5,7.37l0,0C2.14,7.58,2.02,8.04,2.23,8.4L2.7,9.22H1.75 C1.34,9.22,1,9.56,1,9.97v0c0,0.41,0.34,0.75,0.75,0.75H2.7l-0.48,0.83C2.02,11.91,2.14,12.37,2.5,12.57L2.5,12.57z M10.5,12.57 L10.5,12.57c0.36,0.21,0.82,0.08,1.03-0.28L12,11.47l0.48,0.83c0.21,0.36,0.67,0.48,1.03,0.28l0,0c0.36-0.21,0.48-0.66,0.28-1.02 l-0.48-0.83h0.95c0.41,0,0.75-0.34,0.75-0.75v0c0-0.41-0.34-0.75-0.75-0.75H13.3l0.47-0.82c0.21-0.36,0.08-0.82-0.27-1.03l0,0 c-0.36-0.21-0.82-0.08-1.02,0.27L12,8.47l-0.47-0.82c-0.21-0.36-0.67-0.48-1.02-0.27l0,0c-0.36,0.21-0.48,0.67-0.27,1.03 l0.47,0.82H9.75C9.34,9.22,9,9.56,9,9.97v0c0,0.41,0.34,0.75,0.75,0.75h0.95l-0.48,0.83C10.02,11.91,10.14,12.37,10.5,12.57z M23,9.97c0-0.41-0.34-0.75-0.75-0.75H21.3l0.47-0.82c0.21-0.36,0.08-0.82-0.27-1.03l0,0c-0.36-0.21-0.82-0.08-1.02,0.27L20,8.47 l-0.47-0.82c-0.21-0.36-0.67-0.48-1.02-0.27l0,0c-0.36,0.21-0.48,0.67-0.27,1.03l0.47,0.82h-0.95C17.34,9.22,17,9.56,17,9.97v0 c0,0.41,0.34,0.75,0.75,0.75h0.95l-0.48,0.83c-0.21,0.36-0.08,0.82,0.28,1.02l0,0c0.36,0.21,0.82,0.08,1.03-0.28L20,11.47 l0.48,0.83c0.21,0.36,0.67,0.48,1.03,0.28l0,0c0.36-0.21,0.48-0.66,0.28-1.02l-0.48-0.83h0.95C22.66,10.72,23,10.38,23,9.97 L23,9.97z</Geometry>
<Geometry x:Key="BackupIcon">M19,11c0-3.87-3.13-7-7-7C8.78,4,6.07,6.18,5.26,9.15C2.82,9.71,1,11.89,1,14.5C1,17.54,3.46,20,6.5,20 c1.76,0,10.25,0,12,0l0,0c2.49-0.01,4.5-2.03,4.5-4.52C23,13.15,21.25,11.26,19,11z M13,13v2c0,0.55-0.45,1-1,1h0 c-0.55,0-1-0.45-1-1v-2H9.21c-0.45,0-0.67-0.54-0.35-0.85l2.79-2.79c0.2-0.2,0.51-0.2,0.71,0l2.79,2.79 c0.31,0.31,0.09,0.85-0.35,0.85H13z</Geometry>
<Geometry x:Key="ExpanderIcon">M16,17.01V11c0-0.55-0.45-1-1-1s-1,0.45-1,1v6.01h-1.79c-0.45,0-0.67,0.54-0.35,0.85l2.79,2.78c0.2,0.19,0.51,0.19,0.71,0 l2.79-2.78c0.32-0.31,0.09-0.85-0.35-0.85H16z M8.65,3.35L5.86,6.14c-0.32,0.31-0.1,0.85,0.35,0.85H8V13c0,0.55,0.45,1,1,1 s1-0.45,1-1V6.99h1.79c0.45,0,0.67-0.54,0.35-0.85L9.35,3.35C9.16,3.16,8.84,3.16,8.65,3.35z</Geometry>
<Geometry x:Key="FolderIcon">M20,6h-8l-1.41-1.41C10.21,4.21,9.7,4,9.17,4H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8 C22,6.9,21.1,6,20,6z M15.98,15.74l-1.07-0.82l-1.07,0.82c-0.39,0.29-0.92-0.08-0.78-0.55l0.42-1.36l-1.2-0.95 C11.91,12.6,12.12,12,12.59,12H14l0.43-1.34c0.15-0.46,0.8-0.46,0.95,0L15.82,12h1.41c0.47,0,0.68,0.6,0.31,0.89l-1.2,0.95 l0.42,1.36C16.91,15.66,16.37,16.04,15.98,15.74z</Geometry>
<Geometry x:Key="ExportIcon">M19.41,7.41l-4.83-4.83C14.21,2.21,13.7,2,13.17,2H6C4.9,2,4.01,2.9,4.01,4L4,20c0,1.1,0.89,2,1.99,2H18c1.1,0,2-0.9,2-2 V8.83C20,8.3,19.79,7.79,19.41,7.41z M14.8,15H13v3c0,0.55-0.45,1-1,1s-1-0.45-1-1v-3H9.21c-0.45,0-0.67-0.54-0.35-0.85l2.8-2.79 c0.2-0.19,0.51-0.19,0.71,0l2.79,2.79C15.46,14.46,15.24,15,14.8,15z M14,9c-0.55,0-1-0.45-1-1V3.5L18.5,9H14z</Geometry>
<Geometry x:Key="SaveIcon">M16.17,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V7.83c0-0.53-0.21-1.04-0.59-1.41l-2.83-2.83 C17.21,3.21,16.7,3,16.17,3z M12,18c-1.66,0-3-1.34-3-3s1.34-3,3-3s3,1.34,3,3S13.66,18,12,18z M14,10H7c-0.55,0-1-0.45-1-1V7 c0-0.55,0.45-1,1-1h7c0.55,0,1,0.45,1,1v2C15,9.55,14.55,10,14,10z</Geometry>
<Geometry x:Key="TextureIcon">M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M6.6,16.2l2-2.67 c0.2-0.27,0.6-0.27,0.8,0L11.25,16l2.6-3.47c0.2-0.27,0.6-0.27,0.8,0l2.75,3.67c0.25,0.33,0.01,0.8-0.4,0.8H7 C6.59,17,6.35,16.53,6.6,16.2z</Geometry>
<Geometry x:Key="ModelIcon">M12 6q-.825 0-1.412-.588Q10 4.825 10 4t.588-1.413Q11.175 2 12 2t1.413.587Q14 3.175 14 4q0 .825-.587 1.412Q12.825 6 12 6ZM9 22V9H3V7h18v2h-6v13h-2v-6h-2v6Z</Geometry>
<Geometry x:Key="AnimationIcon">M9 22q-1.45 0-2.725-.55Q5 20.9 4.05 19.95q-.95-.95-1.5-2.225Q2 16.45 2 15q0-2.025 1.05-3.7Q4.1 9.625 5.8 8.75q.5-.975 1.238-1.713Q7.775 6.3 8.75 5.8q.825-1.7 2.525-2.75T15 2q1.45 0 2.725.55Q19 3.1 19.95 4.05q.95.95 1.5 2.225Q22 7.55 22 9q0 2.125-1.05 3.75t-2.75 2.5q-.5.975-1.238 1.712-.737.738-1.712 1.238-.875 1.7-2.55 2.75Q11.025 22 9 22Zm0-2q.825 0 1.588-.25Q11.35 19.5 12 19q-1.45 0-2.725-.55Q8 17.9 7.05 16.95q-.95-.95-1.5-2.225Q5 13.45 5 12q-.5.65-.75 1.412Q4 14.175 4 15q0 1.05.4 1.95.4.9 1.075 1.575.675.675 1.575 1.075.9.4 1.95.4Zm3-3q.825 0 1.613-.25.787-.25 1.437-.75-1.475 0-2.75-.562-1.275-.563-2.225-1.513-.95-.95-1.513-2.225Q8 10.425 8 8.95q-.5.65-.75 1.437Q7 11.175 7 12q0 1.05.388 1.95.387.9 1.087 1.575.675.7 1.575 1.088.9.387 1.95.387Zm3-3q.45 0 .863-.075.412-.075.837-.225.55-1.5.163-2.888-.388-1.387-1.338-2.337-.95-.95-2.337-1.338Q11.8 6.75 10.3 7.3q-.15.425-.225.837Q10 8.55 10 9q0 1.05.387 1.95.388.9 1.088 1.575.675.7 1.575 1.088.9.387 1.95.387Zm4-1.95q.5-.65.75-1.438Q20 9.825 20 9q0-1.05-.387-1.95-.388-.9-1.088-1.575-.675-.7-1.575-1.088Q16.05 4 15 4q-.875 0-1.637.25-.763.25-1.413.75 1.475 0 2.75.562 1.275.563 2.225 1.513.95.95 1.513 2.225.562 1.275.562 2.75Z</Geometry>
<Geometry x:Key="CopyIcon">M3,7L3,7C2.45,7,2,7.45,2,8v13c0,1.1,0.9,2,2,2h11c0.55,0,1-0.45,1-1v0c0-0.55-0.45-1-1-1H4V8C4,7.45,3.55,7,3,7z M15.59,1.59C15.21,1.21,14.7,1,14.17,1H8C6.9,1,6.01,1.9,6.01,3L6,17c0,1.1,0.89,2,1.99,2H19c1.1,0,2-0.9,2-2V7.83 c0-0.53-0.21-1.04-0.59-1.41L15.59,1.59z M14,7V2.5L19.5,8H15C14.45,8,14,7.55,14,7z</Geometry>
<Geometry x:Key="DirectoriesIcon">M14.4,6l-0.24-1.2C14.07,4.34,13.66,4,13.18,4H6C5.45,4,5,4.45,5,5v15c0,0.55,0.45,1,1,1l0,0c0.55,0,1-0.45,1-1v-6h5.6 l0.24,1.2c0.09,0.47,0.5,0.8,0.98,0.8H19c0.55,0,1-0.45,1-1V7c0-0.55-0.45-1-1-1H14.4z</Geometry>
<Geometry x:Key="DirectoriesAddIcon">M20 1v3h3v2h-3v3h-2V6h-3V4h3V1h2zm-8 12c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm2-9.75V7h3v3h2.92c.05.39.08.79.08 1.2 0 3.32-2.67 7.25-8 11.8-5.33-4.55-8-8.48-8-11.8C4 6.22 7.8 3 12 3c.68 0 1.35.08 2 .25z</Geometry>
<Geometry x:Key="ExtractIcon">M20.29,10.29l-3.59-3.59C16.08,6.08,15,6.52,15,7.41V10H8c-2.76,0-5,2.24-5,5v3c0,0.55,0.45,1,1,1h0c0.55,0,1-0.45,1-1v-3 c0-1.65,1.35-3,3-3h7v2.59c0,0.89,1.08,1.34,1.71,0.71l3.59-3.59C20.68,11.32,20.68,10.68,20.29,10.29z</Geometry>
<Geometry x:Key="GoToIcon">M9.5,5.5c1.1,0,2-0.9,2-2s-0.9-2-2-2s-2,0.9-2,2S8.4,5.5,9.5,5.5z M5.75,8.9L3.23,21.81C3.11,22.43,3.58,23,4.21,23H4.3 c0.47,0,0.88-0.33,0.98-0.79L6.85,15L9,17v5c0,0.55,0.45,1,1,1h0c0.55,0,1-0.45,1-1v-6.14c0-0.27-0.11-0.52-0.29-0.71L8.95,13.4 l0.6-3c1.07,1.32,2.58,2.23,4.31,2.51c0.6,0.1,1.14-0.39,1.14-1v0c0-0.49-0.36-0.9-0.84-0.98c-1.49-0.25-2.75-1.15-3.51-2.38 L9.7,6.95C9.35,6.35,8.7,6,8,6C7.75,6,7.5,6.05,7.25,6.15l-4.63,1.9C2.25,8.2,2,8.57,2,8.97V12c0,0.55,0.45,1,1,1h0 c0.55,0,1-0.45,1-1V9.65L5.75,8.9 M21,2h-7c-0.55,0-1,0.45-1,1v5c0,0.55,0.45,1,1,1h2.75v13.25c0,0.41,0.34,0.75,0.75,0.75 s0.75-0.34,0.75-0.75V9H21c0.55,0,1-0.45,1-1V3C22,2.45,21.55,2,21,2z M20.15,5.85l-1.28,1.29c-0.31,0.32-0.85,0.09-0.85-0.35V6.25 h-2.76c-0.41,0-0.75-0.34-0.75-0.75s0.34-0.75,0.75-0.75h2.76V4.21c0-0.45,0.54-0.67,0.85-0.35l1.28,1.29 C20.34,5.34,20.34,5.66,20.15,5.85z</Geometry>
<Geometry x:Key="DiscordIcon">M22,24L16.75,19L17.38,21H4.5A2.5,2.5 0 0,1 2,18.5V3.5A2.5,2.5 0 0,1 4.5,1H19.5A2.5,2.5 0 0,1 22,3.5V24M12,6.8C9.32,6.8 7.44,7.95 7.44,7.95C8.47,7.03 10.27,6.5 10.27,6.5L10.1,6.33C8.41,6.36 6.88,7.53 6.88,7.53C5.16,11.12 5.27,14.22 5.27,14.22C6.67,16.03 8.75,15.9 8.75,15.9L9.46,15C8.21,14.73 7.42,13.62 7.42,13.62C7.42,13.62 9.3,14.9 12,14.9C14.7,14.9 16.58,13.62 16.58,13.62C16.58,13.62 15.79,14.73 14.54,15L15.25,15.9C15.25,15.9 17.33,16.03 18.73,14.22C18.73,14.22 18.84,11.12 17.12,7.53C17.12,7.53 15.59,6.36 13.9,6.33L13.73,6.5C13.73,6.5 15.53,7.03 16.56,7.95C16.56,7.95 14.68,6.8 12,6.8M9.93,10.59C10.58,10.59 11.11,11.16 11.1,11.86C11.1,12.55 10.58,13.13 9.93,13.13C9.29,13.13 8.77,12.55 8.77,11.86C8.77,11.16 9.28,10.59 9.93,10.59M14.1,10.59C14.75,10.59 15.27,11.16 15.27,11.86C15.27,12.55 14.75,13.13 14.1,13.13C13.46,13.13 12.94,12.55 12.94,11.86C12.94,11.16 13.45,10.59 14.1,10.59Z</Geometry>
<Geometry x:Key="BugIcon">M14,12H10V10H14M14,16H10V14H14M20,8H17.19C16.74,7.22 16.12,6.55 15.37,6.04L17,4.41L15.59,3L13.42,5.17C12.96,5.06 12.5,5 12,5C11.5,5 11.04,5.06 10.59,5.17L8.41,3L7,4.41L8.62,6.04C7.88,6.55 7.26,7.22 6.81,8H4V10H6.09C6.04,10.33 6,10.66 6,11V12H4V14H6V15C6,15.34 6.04,15.67 6.09,16H4V18H6.81C7.85,19.79 9.78,21 12,21C14.22,21 16.15,19.79 17.19,18H20V16H17.91C17.96,15.67 18,15.34 18,15V14H20V12H18V11C18,10.66 17.96,10.33 17.91,10H20V8Z</Geometry>
<Geometry x:Key="GiftIcon">M22 10.92L19.26 9.33C21.9 7.08 19.25 2.88 16.08 4.31L15.21 4.68L15.1 3.72C15 2.64 14.44 1.87 13.7 1.42C12.06 .467 9.56 1.12 9.16 3.5L6.41 1.92C5.45 1.36 4.23 1.69 3.68 2.65L2.68 4.38C2.4 4.86 2.57 5.47 3.05 5.75L10.84 10.25L12.34 7.65L14.07 8.65L12.57 11.25L20.36 15.75C20.84 16 21.46 15.86 21.73 15.38L22.73 13.65C23.28 12.69 22.96 11.47 22 10.92M12.37 5C11.5 5.25 10.8 4.32 11.24 3.55C11.5 3.07 12.13 2.91 12.61 3.18C13.38 3.63 13.23 4.79 12.37 5M17.56 8C16.7 8.25 16 7.32 16.44 6.55C16.71 6.07 17.33 5.91 17.8 6.18C18.57 6.63 18.42 7.79 17.56 8M20.87 16.88C21.28 16.88 21.67 16.74 22 16.5V20C22 21.11 21.11 22 20 22H4C2.9 22 2 21.11 2 20V11H10.15L11 11.5V20H13V12.65L19.87 16.61C20.17 16.79 20.5 16.88 20.87 16.88Z</Geometry>
<Geometry x:Key="NoteIcon">M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM8 19h12c.55 0 1-.45 1-1s-.45-1-1-1H8c-.55 0-1 .45-1 1s.45 1 1 1zm0-6h12c.55 0 1-.45 1-1s-.45-1-1-1H8c-.55 0-1 .45-1 1s.45 1 1 1zM7 6c0 .55.45 1 1 1h12c.55 0 1-.45 1-1s-.45-1-1-1H8c-.55 0-1 .45-1 1z</Geometry>
<Geometry x:Key="InfoIcon">M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 15c-.55 0-1-.45-1-1v-4c0-.55.45-1 1-1s1 .45 1 1v4c0 .55-.45 1-1 1zm1-8h-2V7h2v2z</Geometry>
<Geometry x:Key="TrashIcon">M6,19c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2V7H6V19z M9.17,12.59c-0.39-0.39-0.39-1.02,0-1.41c0.39-0.39,1.02-0.39,1.41,0 L12,12.59l1.41-1.41c0.39-0.39,1.02-0.39,1.41,0s0.39,1.02,0,1.41L13.41,14l1.41,1.41c0.39,0.39,0.39,1.02,0,1.41 s-1.02,0.39-1.41,0L12,15.41l-1.41,1.41c-0.39,0.39-1.02,0.39-1.41,0c-0.39-0.39-0.39-1.02,0-1.41L10.59,14L9.17,12.59z M18,4h-2.5 l-0.71-0.71C14.61,3.11,14.35,3,14.09,3H9.91c-0.26,0-0.52,0.11-0.7,0.29L8.5,4H6C5.45,4,5,4.45,5,5s0.45,1,1,1h12 c0.55,0,1-0.45,1-1S18.55,4,18,4z</Geometry>
<Geometry x:Key="HomeIcon">M18,4v16H6V4H18 M18,2H6C4.9,2,4,2.9,4,4v16c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V4C20,2.9,19.1,2,18,2L18,2z M7,19h10v-6H7 V19z M10,10h4v1h3V5H7v6h3V10z</Geometry>
<Geometry x:Key="RegexIcon">M16,16.92C15.67,16.97 15.34,17 15,17C14.66,17 14.33,16.97 14,16.92V13.41L11.5,15.89C11,15.5 10.5,15 10.11,14.5L12.59,12H9.08C9.03,11.67 9,11.34 9,11C9,10.66 9.03,10.33 9.08,10H12.59L10.11,7.5C10.3,7.25 10.5,7 10.76,6.76V6.76C11,6.5 11.25,6.3 11.5,6.11L14,8.59V5.08C14.33,5.03 14.66,5 15,5C15.34,5 15.67,5.03 16,5.08V8.59L18.5,6.11C19,6.5 19.5,7 19.89,7.5L17.41,10H20.92C20.97,10.33 21,10.66 21,11C21,11.34 20.97,11.67 20.92,12H17.41L19.89,14.5C19.7,14.75 19.5,15 19.24,15.24V15.24C19,15.5 18.75,15.7 18.5,15.89L16,13.41V16.92H16V16.92M5,19A2,2 0 0,1 7,17A2,2 0 0,1 9,19A2,2 0 0,1 7,21A2,2 0 0,1 5,19H5Z</Geometry>
<Geometry x:Key="BackspaceIcon">M22,3H7C6.31,3 5.77,3.35 5.41,3.88L0,12L5.41,20.11C5.77,20.64 6.31,21 7,21H22A2,2 0 0,0 24,19V5A2,2 0 0,0 22,3M19,15.59L17.59,17L14,13.41L10.41,17L9,15.59L12.59,12L9,8.41L10.41,7L14,10.59L17.59,7L19,8.41L15.41,12</Geometry>
<Geometry x:Key="AudioIcon">M3 10v4c0 .55.45 1 1 1h3l3.29 3.29c.63.63 1.71.18 1.71-.71V6.41c0-.89-1.08-1.34-1.71-.71L7 9H4c-.55 0-1 .45-1 1zm13.5 2c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 4.45v.2c0 .38.25.71.6.85C17.18 6.53 19 9.06 19 12s-1.82 5.47-4.4 6.5c-.36.14-.6.47-.6.85v.2c0 .63.63 1.07 1.21.85C18.6 19.11 21 15.84 21 12s-2.4-7.11-5.79-8.4c-.58-.23-1.21.22-1.21.85z</Geometry>
<Geometry x:Key="MapIcon">M14.65 4.98l-5-1.75c-.42-.15-.88-.15-1.3-.01L4.36 4.56C3.55 4.84 3 5.6 3 6.46v11.85c0 1.41 1.41 2.37 2.72 1.86l2.93-1.14c.22-.09.47-.09.69-.01l5 1.75c.42.15.88.15 1.3.01l3.99-1.34c.81-.27 1.36-1.04 1.36-1.9V5.69c0-1.41-1.41-2.37-2.72-1.86l-2.93 1.14c-.22.08-.46.09-.69.01zM15 18.89l-6-2.11V5.11l6 2.11v11.67z</Geometry>
<Geometry x:Key="ChallengesIcon">M12.09 2.91C10.08.9 7.07.49 4.65 1.67L8.28 5.3c.39.39.39 1.02 0 1.41L6.69 8.3c-.39.4-1.02.4-1.41 0L1.65 4.67C.48 7.1.89 10.09 2.9 12.1c1.86 1.86 4.58 2.35 6.89 1.48l7.96 7.96c1.03 1.03 2.69 1.03 3.71 0 1.03-1.03 1.03-2.69 0-3.71L13.54 9.9c.92-2.34.44-5.1-1.45-6.99z</Geometry>
<Geometry x:Key="MatchCaseIcon">M2.5 5.5C2.5 6.33 3.17 7 4 7h3.5v10.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V7H14c.83 0 1.5-.67 1.5-1.5S14.83 4 14 4H4c-.83 0-1.5.67-1.5 1.5zM20 9h-6c-.83 0-1.5.67-1.5 1.5S13.17 12 14 12h1.5v5.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V12H20c.83 0 1.5-.67 1.5-1.5S20.83 9 20 9z</Geometry>
<Geometry x:Key="CreatorIcon">M21 13h-6c-.55 0-1-.45-1-1s.45-1 1-1h6c.55 0 1 .45 1 1s-.45 1-1 1zm0-6h-6c-.55 0-1 .45-1 1s.45 1 1 1h6c.55 0 1-.45 1-1s-.45-1-1-1zm-6 10h6c.55 0 1-.45 1-1s-.45-1-1-1h-6c-.55 0-1 .45-1 1s.45 1 1 1zm-3-8v6c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V9c0-1.1.9-2 2-2h6c1.1 0 2 .9 2 2zm-2.1 5.2l-1.26-1.68c-.2-.26-.59-.27-.8-.01L6.5 14.26l-.85-1.03c-.2-.25-.58-.24-.78.01l-.74.95c-.26.33-.02.81.39.81H9.5c.41 0 .65-.47.4-.8z</Geometry>
<Geometry x:Key="KeyboardIcon">M20 5H4c-1.1 0-1.99.9-1.99 2L2 17c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0 3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm8 7H9c-.55 0-1-.45-1-1s.45-1 1-1h6c.55 0 1 .45 1 1s-.45 1-1 1zm1-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z</Geometry>
<Geometry x:Key="SearchUpIcon">M2.7,17.29c0.39,0.39,1.02,0.39,1.41,0l4.59-4.59c0.39-0.39,1.02-0.39,1.41,0l1.17,1.17c1.17,1.17,3.07,1.17,4.24,0 l4.18-4.17l1.44,1.44c0.31,0.31,0.85,0.09,0.85-0.35V6.5C22,6.22,21.78,6,21.5,6h-4.29c-0.45,0-0.67,0.54-0.35,0.85l1.44,1.44 l-4.17,4.17c-0.39,0.39-1.02,0.39-1.41,0l-1.17-1.17c-1.17-1.17-3.07-1.17-4.24,0L2.7,15.88C2.32,16.27,2.32,16.91,2.7,17.29z</Geometry>
<Geometry x:Key="WholeWordIcon">M18 10v3H6v-3c0-.55-.45-1-1-1s-1 .45-1 1v4c0 .55.45 1 1 1h14c.55 0 1-.45 1-1v-4c0-.55-.45-1-1-1s-1 .45-1 1z</Geometry>
<Geometry x:Key="CloseIcon">M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm4.3 14.3c-.39.39-1.02.39-1.41 0L12 13.41 9.11 16.3c-.39.39-1.02.39-1.41 0-.39-.39-.39-1.02 0-1.41L10.59 12 7.7 9.11c-.39-.39-.39-1.02 0-1.41.39-.39 1.02-.39 1.41 0L12 10.59l2.89-2.89c.39-.39 1.02-.39 1.41 0 .39.39.39 1.02 0 1.41L13.41 12l2.89 2.89c.38.38.38 1.02 0 1.41z</Geometry>
<Geometry x:Key="PlayIcon">M8 6.82v10.36c0 .79.87 1.27 1.54.84l8.14-5.18c.62-.39.62-1.29 0-1.69L9.54 5.98C8.87 5.55 8 6.03 8 6.82z</Geometry>
<Geometry x:Key="PauseIcon">M8 19c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2s-2 .9-2 2v10c0 1.1.9 2 2 2zm6-12v10c0 1.1.9 2 2 2s2-.9 2-2V7c0-1.1-.9-2-2-2s-2 .9-2 2z</Geometry>
<Geometry x:Key="StopIcon">M8 6h8c1.1 0 2 .9 2 2v8c0 1.1-.9 2-2 2H8c-1.1 0-2-.9-2-2V8c0-1.1.9-2 2-2z</Geometry>
<Geometry x:Key="SkipNextIcon">M7.58 16.89l5.77-4.07c.56-.4.56-1.24 0-1.63L7.58 7.11C6.91 6.65 6 7.12 6 7.93v8.14c0 .81.91 1.28 1.58.82zM16 7v10c0 .55.45 1 1 1s1-.45 1-1V7c0-.55-.45-1-1-1s-1 .45-1 1z</Geometry>
<Geometry x:Key="SkipPreviousIcon">M7 6c.55 0 1 .45 1 1v10c0 .55-.45 1-1 1s-1-.45-1-1V7c0-.55.45-1 1-1zm3.66 6.82l5.77 4.07c.66.47 1.58-.01 1.58-.82V7.93c0-.81-.91-1.28-1.58-.82l-5.77 4.07c-.57.4-.57 1.24 0 1.64z</Geometry>
<Geometry x:Key="AddAudioIcon">M13 10H3c-.55 0-1 .45-1 1s.45 1 1 1h10c.55 0 1-.45 1-1s-.45-1-1-1zm0-4H3c-.55 0-1 .45-1 1s.45 1 1 1h10c.55 0 1-.45 1-1s-.45-1-1-1zm5 8v-3c0-.55-.45-1-1-1s-1 .45-1 1v3h-3c-.55 0-1 .45-1 1s.45 1 1 1h3v3c0 .55.45 1 1 1s1-.45 1-1v-3h3c.55 0 1-.45 1-1s-.45-1-1-1h-3zM3 16h6c.55 0 1-.45 1-1s-.45-1-1-1H3c-.55 0-1 .45-1 1s.45 1 1 1z</Geometry>
<Geometry x:Key="SavePlaylistIcon">M14 6H4c-.55 0-1 .45-1 1s.45 1 1 1h10c.55 0 1-.45 1-1s-.45-1-1-1zm0 4H4c-.55 0-1 .45-1 1s.45 1 1 1h10c.55 0 1-.45 1-1s-.45-1-1-1zM4 16h6c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1zM19 6c-1.1 0-2 .9-2 2v6.18c-.31-.11-.65-.18-1-.18-1.84 0-3.28 1.64-2.95 3.54.21 1.21 1.2 2.2 2.41 2.41 1.9.33 3.54-1.11 3.54-2.95V8h2c.55 0 1-.45 1-1s-.45-1-1-1h-2z</Geometry>
<Geometry x:Key="ImageMergerIcon">M10 12c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zM6 8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12-8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-4 8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm4-4c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-4-4c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-4-4c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z</Geometry>
<Geometry x:Key="GliderIcon">M12,17c-1.1,0-2-0.9-2-2s0.9-2,2-2s2,0.9,2,2S13.1,17,12,17z M17.95,14c-0.52,0-0.94,0.4-0.99,0.92 c-0.2,2.03-1.05,2.68-1.48,3.02C14.68,18.54,14,19,12,19s-2.68-0.46-3.48-1.06c-0.43-0.34-1.28-0.99-1.48-3.02 C6.99,14.4,6.57,14,6.05,14c-0.59,0-1.06,0.51-1,1.09c0.22,2.08,1.07,3.47,2.24,4.41c0.5,0.4,1.1,0.7,1.7,0.9L9,24h6v-3.6 c0.6-0.2,1.2-0.5,1.7-0.9c1.17-0.94,2.03-2.32,2.24-4.41C19.01,14.51,18.53,14,17.95,14z M12,0C5.92,0,1,1.9,1,4.25v3.49 C1,8.55,1.88,9,2.56,8.57C2.7,8.48,2.84,8.39,3,8.31L5,13h2l1.5-6.28C9.6,6.58,10.78,6.5,12,6.5s2.4,0.08,3.5,0.22L17,13h2l2-4.69 c0.16,0.09,0.3,0.17,0.44,0.26C22.12,9,23,8.55,23,7.74V4.25C23,1.9,18.08,0,12,0z M5.88,11.24L4.37,7.69 c0.75-0.28,1.6-0.52,2.53-0.71L5.88,11.24z M18.12,11.24L17.1,6.98c0.93,0.19,1.78,0.43,2.53,0.71L18.12,11.24z</Geometry>
<Geometry x:Key="AnchorIcon">M13,9V7.82C14.16,7.4,15,6.3,15,5c0-1.65-1.35-3-3-3S9,3.35,9,5c0,1.3,0.84,2.4,2,2.82V9H9c-0.55,0-1,0.45-1,1v0 c0,0.55,0.45,1,1,1h2v8.92c-2.22-0.33-4.59-1.68-5.55-3.37l1.14-1.14c0.22-0.22,0.19-0.57-0.05-0.75L3.8,12.6 C3.47,12.35,3,12.59,3,13v2c0,3.88,4.92,7,9,7s9-3.12,9-7v-2c0-0.41-0.47-0.65-0.8-0.4l-2.74,2.05c-0.24,0.18-0.27,0.54-0.05,0.75 l1.14,1.14c-0.96,1.69-3.33,3.04-5.55,3.37V11h2c0.55,0,1-0.45,1-1v0c0-0.55-0.45-1-1-1H13z M12,4c0.55,0,1,0.45,1,1s-0.45,1-1,1 s-1-0.45-1-1S11.45,4,12,4z</Geometry>
<Geometry x:Key="FoldIcon">M8.12 19.3c.39.39 1.02.39 1.41 0L12 16.83l2.47 2.47c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41l-3.17-3.17c-.39-.39-1.02-.39-1.41 0l-3.17 3.17c-.4.38-.4 1.02-.01 1.41zm7.76-14.6c-.39-.39-1.02-.39-1.41 0L12 7.17 9.53 4.7c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.03 0 1.42l3.17 3.17c.39.39 1.02.39 1.41 0l3.17-3.17c.4-.39.4-1.03.01-1.42z</Geometry>
<Geometry x:Key="UnfoldIcon">M12 5.83l2.46 2.46c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L12.7 3.7c-.39-.39-1.02-.39-1.41 0L8.12 6.88c-.39.39-.39 1.02 0 1.41.39.39 1.02.39 1.41 0L12 5.83zm0 12.34l-2.46-2.46c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.02 0 1.41l3.17 3.18c.39.39 1.02.39 1.41 0l3.17-3.17c.39-.39.39-1.02 0-1.41-.39-.39-1.02-.39-1.41 0L12 18.17z</Geometry>
<Geometry x:Key="LocateMeIcon">M11.71,17.99C8.53,17.84,6,15.22,6,12c0-3.31,2.69-6,6-6c3.22,0,5.84,2.53,5.99,5.71l-2.1-0.63C15.48,9.31,13.89,8,12,8 c-2.21,0-4,1.79-4,4c0,1.89,1.31,3.48,3.08,3.89L11.71,17.99z M22,12c0,0.3-0.01,0.6-0.04,0.9l-1.97-0.59C20,12.21,20,12.1,20,12 c0-4.42-3.58-8-8-8s-8,3.58-8,8s3.58,8,8,8c0.1,0,0.21,0,0.31-0.01l0.59,1.97C12.6,21.99,12.3,22,12,22C6.48,22,2,17.52,2,12 C2,6.48,6.48,2,12,2S22,6.48,22,12z M18.23,16.26l2.27-0.76c0.46-0.15,0.45-0.81-0.01-0.95l-7.6-2.28 c-0.38-0.11-0.74,0.24-0.62,0.62l2.28,7.6c0.14,0.47,0.8,0.48,0.95,0.01l0.76-2.27l3.91,3.91c0.2,0.2,0.51,0.2,0.71,0l1.27-1.27 c0.2-0.2,0.2-0.51,0-0.71L18.23,16.26z</Geometry>
<Geometry x:Key="MeshIcon">M1.8 6q-.525 0-.887-.35Q.55 5.3.55 4.8V4q0-1.425 1.012-2.438Q2.575.55 4 .55h.8q.5 0 .85.362.35.363.35.888 0 .5-.35.85T4.8 3H4q-.425 0-.712.287Q3 3.575 3 4v.8q0 .5-.35.85T1.8 6ZM4 23.45q-1.425 0-2.438-1.012Q.55 21.425.55 20v-.8q0-.5.363-.85.362-.35.887-.35.5 0 .85.35t.35.85v.8q0 .425.288.712Q3.575 21 4 21h.8q.5 0 .85.35t.35.85q0 .525-.35.887-.35.363-.85.363Zm15.2 0q-.5 0-.85-.363-.35-.362-.35-.887 0-.5.35-.85t.85-.35h.8q.425 0 .712-.288Q21 20.425 21 20v-.8q0-.5.35-.85t.85-.35q.525 0 .888.35.362.35.362.85v.8q0 1.425-1.012 2.438Q21.425 23.45 20 23.45ZM22.2 6q-.5 0-.85-.35T21 4.8V4q0-.425-.288-.713Q20.425 3 20 3h-.8q-.5 0-.85-.35T18 1.8q0-.525.35-.888.35-.362.85-.362h.8q1.425 0 2.438 1.012Q23.45 2.575 23.45 4v.8q0 .5-.362.85-.363.35-.888.35ZM12 17.35l1-.575v-4.1l3.55-2.075V9.425l-1-.575L12 10.925 8.45 8.85l-1 .575V10.6L11 12.675v4.1Zm-1.325 2.325-4.55-2.65q-.625-.35-.975-.963-.35-.612-.35-1.337V9.45q0-.725.35-1.337.35-.613.975-.963l4.55-2.65Q11.3 4.15 12 4.15t1.325.35l4.55 2.65q.625.35.975.963.35.612.35 1.337v5.275q0 .725-.35 1.337-.35.613-.975.963l-4.55 2.65q-.625.35-1.325.35t-1.325-.35Z</Geometry>
<Geometry x:Key="ArchiveIcon">M3.5 1.75v11.5c0 .09.048.173.126.217a.75.75 0 0 1-.752 1.298A1.748 1.748 0 0 1 2 13.25V1.75C2 .784 2.784 0 3.75 0h5.586c.464 0 .909.185 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v8.586A1.75 1.75 0 0 1 12.25 15h-.5a.75.75 0 0 1 0-1.5h.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177L9.513 1.573a.25.25 0 0 0-.177-.073H7.25a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5h-3a.25.25 0 0 0-.25.25Zm3.75 8.75h.5c.966 0 1.75.784 1.75 1.75v3a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1-.75-.75v-3c0-.966.784-1.75 1.75-1.75ZM6 5.25a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 6 5.25Zm.75 2.25h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM8 6.75A.75.75 0 0 1 8.75 6h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 8 6.75ZM8.75 3h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM8 9.75A.75.75 0 0 1 8.75 9h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 8 9.75Zm-1 2.5v2.25h1v-2.25a.25.25 0 0 0-.25-.25h-.5a.25.25 0 0 0-.25.25Z</Geometry>
<Geometry x:Key="GitHubIcon">M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z</Geometry>
<Geometry x:Key="SortIcon">M8 16H4l6 6V2H8zm6-11v17h2V8h4l-6-6z</Geometry>
<Geometry x:Key="FolderIconAlt">M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z</Geometry>
<Geometry x:Key="AssetIcon">M13,9V3.5L18.5,9M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6Z</Geometry>
<Geometry x:Key="DataTableIcon">M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M10,19H7V17H10V19M10,16H7V14H10V16M10,13H7V11H10V13M14,19H11V17H14V19M14,16H11V14H14V16M14,13H11V11H14V13M13,9V3.5L18.5,9H13Z</Geometry>
<Geometry x:Key="MapIconAlt">M15,19L9,16.89V5L15,7.11M20.5,3C20.44,3 20.39,3 20.34,3L15,5.1L9,3L3.36,4.9C3.15,4.97 3,5.15 3,5.38V20.5A0.5,0.5 0 0,0 3.5,21C3.55,21 3.61,21 3.66,20.97L9,18.9L15,21L20.64,19.1C20.85,19 21,18.85 21,18.62V3.5A0.5,0.5 0 0,0 20.5,3Z</Geometry>
<Geometry x:Key="PluginIcon">M20.5,11H19V7C19,5.89 18.1,5 17,5H13V3.5A2.5,2.5 0 0,0 10.5,1A2.5,2.5 0 0,0 8,3.5V5H4A2,2 0 0,0 2,7V10.8H3.5C5,10.8 6.2,12 6.2,13.5C6.2,15 5,16.2 3.5,16.2H2V20A2,2 0 0,0 4,22H7.8V20.5C7.8,19 9,17.8 10.5,17.8C12,17.8 13.2,19 13.2,20.5V22H17A2,2 0 0,0 19,20V16H20.5A2.5,2.5 0 0,0 23,13.5A2.5,2.5 0 0,0 20.5,11Z</Geometry>
<Geometry x:Key="ConfigIcon">M12,15.5A3.5,3.5 0 0,1 8.5,12A3.5,3.5 0 0,1 12,8.5A3.5,3.5 0 0,1 15.5,12A3.5,3.5 0 0,1 12,15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.5,12C4.5,12.33 4.53,12.65 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.03 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.67 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.03 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z</Geometry>
<Geometry x:Key="AudioIconAlt">M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M13,13H11V18A2,2 0 0,1 9,20A2,2 0 0,1 7,18A2,2 0 0,1 9,16C9.4,16 9.7,16.1 10,16.3V11H13V13M13,9V3.5L18.5,9H13Z</Geometry>
<Geometry x:Key="StaticMeshIconAlt">M5.206,19.956l0.199,42.771c0.003,0.55,0.306,1.054,0.789,1.314l34.161,17.887c0.223,0.119,0.467,0.179,0.711,0.179 c0.001,0,0.002,0,0.003,0c0.103,0.117,0.218,0.227,0.355,0.309c0.236,0.141,0.502,0.212,0.769,0.212 c0.246,0,0.49-0.061,0.712-0.181l33.729-18.292c0.484-0.263,0.787-0.77,0.787-1.319v-44.5c0-0.013-0.005-0.025-0.005-0.039 c-0.001-0.011,0.003-0.021,0.003-0.033c-0.002-0.043-0.019-0.082-0.022-0.124c-0.013-0.082-0.022-0.164-0.047-0.243 c-0.018-0.055-0.041-0.104-0.064-0.157c-0.031-0.07-0.062-0.139-0.104-0.203c-0.031-0.05-0.068-0.095-0.105-0.141 c-0.047-0.058-0.096-0.112-0.152-0.163c-0.044-0.04-0.091-0.076-0.141-0.111c-0.032-0.022-0.059-0.053-0.094-0.073 c-0.032-0.02-0.069-0.028-0.104-0.045c-0.029-0.015-0.052-0.036-0.081-0.049L41.747,0.118c-0.405-0.171-0.864-0.155-1.258,0.042 L6.131,18.071c-0.504,0.254-0.822,0.77-0.825,1.333c0,0.009,0.004,0.017,0.004,0.025C5.249,19.596,5.205,19.772,5.206,19.956z M72.456,18.501l-30.28,16.93L10.111,19.425L41.218,3.151L72.456,18.501z M43.692,78.61V38.021l30.729-17.173v41.09L43.692,78.61z</Geometry>
<Geometry x:Key="SkeletalMeshIconAlt">M 299.53 18.813 C 279.92 19.169 258.693 28.151 241.78 45.063 C 219.82 67.023 211.263 96.303 217.562 119.813 C 154.784 90.813 159.904 88.397 97.282 48.219 C 87.209 41.756 77.84 38.799 69.469 38.405 C 55.515 37.751 44.351 44.21 37.343 53.343 C 26.13 67.956 24.96 89.496 48.28 107.75 C 79.307 132.036 107.123 148.79 127.312 167.22 C 147.502 185.647 159.96 207.81 155.656 237.25 C 152.498 258.86 141.966 275.248 129.186 288.72 C 116.408 302.19 101.44 313.206 87.75 325.406 C 60.37 349.806 37.42 377.159 42.687 439.656 C 46.015 479.139 76.845 494.773 102.344 492.031 C 115.094 490.661 125.854 484.695 131.75 474.564 C 137.647 464.432 139.446 449.126 130.72 426.814 C 123.125 407.398 133.822 385.978 149.063 369.72 C 164.303 353.46 185.893 340.9 207.938 344.72 C 214.113 345.79 219.358 349.44 222.968 353.875 C 226.578 358.31 228.964 363.495 230.938 369.125 C 234.884 380.385 237.208 393.799 240.063 407.688 C 245.773 435.465 253.725 463.655 273.125 476.156 C 311.089 500.624 348.383 493.578 365.031 476.626 C 373.356 468.148 376.946 457.766 374.157 445.469 C 371.369 433.169 361.449 418.311 339.877 403.624 C 316.212 387.514 307.221 355.334 306.032 323.499 C 304.844 291.663 311.32 259.422 326.158 239.469 C 333.036 230.219 343.704 226.351 355.814 222.062 C 367.924 217.772 382.021 213.587 396.564 207.374 C 425.651 194.949 456.2 175.177 475.689 130.594 C 492.767 91.524 479.063 66.276 460.409 57.094 C 451.081 52.501 440.279 51.962 429.971 56.468 C 419.661 60.972 409.541 70.654 402.531 88.218 C 389.391 121.15 363.313 139.925 332.095 144.654 C 325.881 145.596 319.481 146.01 312.907 145.967 C 312.461 145.687 312.012 145.397 311.563 145.122 C 317.666 141.304 323.317 136.807 328.407 131.716 C 358.471 101.651 363.457 57.86 339.532 33.934 C 329.066 23.466 314.788 18.531 299.532 18.808 L 299.53 18.813 Z M 297.188 37.969 C 306.761 37.779 315.712 41.139 322.281 48.249 C 337.298 64.499 334.181 94.205 315.314 114.624 C 296.444 135.044 268.986 138.437 253.97 122.187 C 238.953 105.937 242.07 76.2 260.938 55.78 C 271.551 44.295 284.878 38.21 297.188 37.97 L 297.188 37.969 Z M 65.03 62.593 L 127.72 108.061 L 117.438 123.687 L 54.062 77.717 L 65.032 62.593 L 65.03 62.593 Z M 439.095 85.03 L 455.189 94.53 L 418.814 156.125 L 405.782 141.469 L 439.096 85.029 L 439.095 85.03 Z M 142.875 119.062 L 182.815 148.032 C 180.185 153.969 177.865 159.966 175.875 166.094 L 132.595 134.688 L 142.875 119.063 L 142.875 119.062 Z M 214.815 138.938 C 215.543 138.925 216.265 138.931 217.001 138.938 C 248.215 139.218 282.064 146.615 309.845 166.625 C 309.415 199.908 248.937 315.907 248.937 315.907 C 221.243 316.177 195.231 314.66 170.907 301.407 C 170.907 301.407 212.624 138.975 214.813 138.938 L 214.815 138.938 Z M 389.47 151.188 L 402.75 166.156 L 326.937 194.75 C 327.69 188.073 328.132 181.234 328.375 174.22 L 389.469 151.188 L 389.47 151.188 Z M 149.125 302.218 L 161.781 315.968 L 109.471 364.125 L 88.501 358.031 L 149.126 302.221 L 149.125 302.218 Z M 260.281 324.844 L 283.314 373.874 L 266.064 381.124 L 243.344 332.781 L 260.282 324.845 L 260.281 324.844 Z M 83.281 375.969 L 102.221 381.469 L 106.095 466.374 L 87.407 467.218 L 83.282 375.968 L 83.281 375.969 Z M 292.845 390.155 L 335.439 458.875 L 319.564 468.718 L 275.407 397.468 L 292.845 390.154 L 292.845 390.155 Z</Geometry>
<Geometry x:Key="BlueprintIcon">M1.5,7.23 V22.5 H19.64 A2.87,2.87 0 0 0 19.64,16.77 H17.73 V7.23 Z M17.73,1.5 V16.77 H19.64 A2.88,2.88 0 0 1 21.64,17.61 A2.85,2.85 0 0 1 22.48,19.68 V4.36 A2.87,2.87 0 0 0 19.64,1.5 Z M13.91,18.68 L5.32,18.68 L5.32,10.09 M7.23,12 L5.32,12 M7.23,14.86 L5.32,14.86 M9.14,16.77 L9.14,18.68 M12,16.77 L12,18.68</Geometry>
<Geometry x:Key="MaterialIcon">M165.446 34.793c-23.17.023-45.634 12.97-54.612 36.323l-83.67 326.167c-12.673 94.537 81.04 88.742 137.957 65.396 81.422-33.396 181.723-29.213 263.244-8.26l6.45-17.218c-7.38-2.638-15.334-5.988-22.252-8.039.473-4.364.955-8.72 1.437-13.074l23.038 4.118 3.234-18.1c-8.074-1.441-16.147-2.885-24.221-4.328.615-5.403 1.238-10.799 1.87-16.189l22.134 3.278 2.693-18.186c-7.548-1.12-15.098-2.238-22.647-3.355.456-3.765.91-7.53 1.375-11.29 7.615 1.092 15.231 2.183 22.847 3.273l2.607-18.2-23.164-3.316c.46-3.593 1.29-9.988 1.76-13.577l22.781 2.55 2.045-17.57c-7.467-.834-14.935-1.671-22.402-2.508.783-5.767 1.917-11.182 2.728-16.943 7.67 1.12 15.341 2.244 23.012 3.368l2.31-17.139c-7.683-1.127-15.366-2.25-23.05-3.374.792-5.415 1.252-10.129 2.071-15.542 7.074 1.264 14.149 2.528 21.223 3.79l3.232-18.1-21.654-3.866c.736-4.676 1.473-9.35 2.23-14.026 6.978 1.673 13.955 3.347 20.932 5.022L465.276 208c-7.401-1.778-14.803-3.554-22.204-5.33a2809.25 2809.25 0 0 1 2.132-12.477c6.98 1.583 13.961 3.165 20.942 4.746l4.064-17.93c-7.271-1.65-14.543-3.298-21.815-4.946.769-4.267 1.55-8.535 2.342-12.805l20.742 5.151 4.431-17.843-21.751-5.405c.741-3.847 1.494-7.696 2.254-11.548l20.28 5.014 4.413-17.849-21.057-5.207a2444.47 2444.47 0 0 1 2.571-12.374c8.386 2.41 13.13 2.364 21.41 4.99L486 88.456c-83.808-26.776-179.25-33.22-244.192-6.453-24.337 114.036-37.305 221.4-68.032 338.64-3.407 13-14.47 21.89-27.342 28.064-27 11.608-64.033 13.778-84.63-4.91-10.971-10.34-16.174-27.036-12.467-47.579 2.303-12.762 10.883-21.986 20.834-26.378 19.749-7.074 43.492-4.25 58.893 7.95 12.463 9.302 12.318 38.283-3.882 31.82-9.639-6.17-1.964-11.851-8.615-17.378-11.6-7.428-26.42-10.872-38.972-5.57-5.564 2.455-8.887 5.737-10.166 12.822-2.94 16.29.685 24.996 6.985 30.933 18.333 13.49 45.279 10.495 64.068 1.712 10.045-4.82 16.277-11.436 17.511-16.147 30.538-116.518 43.443-224.123 68.293-339.964-11.796-28.344-35.67-41.247-58.84-41.225z</Geometry>
<Geometry x:Key="SkeletonIcon">M 292.845 390.155 L 335.439 458.875 L 319.564 468.718 L 275.407 397.468 L 292.845 390.154 Z M 83.282 375.968 L 83.282 375.969 L 83.281 375.969 Z M 102.221 381.469 L 106.095 466.374 L 87.407 467.218 L 83.282 375.969 Z M 283.314 373.874 L 266.064 381.124 L 243.344 332.781 L 260.282 324.845 Z M 149.125 302.218 L 161.781 315.968 L 109.471 364.125 L 88.501 358.031 L 149.126 302.221 Z M 389.47 151.188 L 402.75 166.156 L 326.937 194.75 C 327.69 188.073 328.132 181.234 328.375 174.22 L 389.469 151.188 Z M 214.815 138.938 C 215.543 138.925 216.265 138.931 217.001 138.938 C 248.215 139.218 282.064 146.615 309.845 166.625 C 309.415 199.908 304.967 225.572 288.565 252.875 C 274.021 243.958 258.239 236.19 241.907 230.781 L 226.437 277.031 L 256.157 282.939 L 248.937 315.907 C 221.243 316.177 195.231 314.66 170.907 301.407 L 178.345 267.501 L 207.97 273.376 L 223.844 225.876 C 210.907 223.124 197.794 222.041 184.781 223.188 C 186.441 189.978 193.497 165.248 208.281 139.158 C 210.449 139.088 212.624 138.975 214.813 138.938 Z M 142.875 119.062 L 182.815 148.032 C 180.185 153.969 177.865 159.966 175.875 166.094 L 132.595 134.688 L 142.875 119.063 Z M 455.189 94.53 L 418.814 156.125 L 405.782 141.469 L 439.095 85.03 Z M 65.032 62.593 L 65.031 62.594 L 65.03 62.593 Z M 127.72 108.061 L 117.438 123.687 L 54.062 77.717 L 65.031 62.594 Z M 297.188 37.969 C 306.761 37.779 315.712 41.139 322.281 48.249 C 337.298 64.499 334.181 94.205 315.314 114.624 C 296.444 135.044 268.986 138.437 253.97 122.187 C 238.953 105.937 242.07 76.2 260.938 55.78 C 271.551 44.295 284.878 38.21 297.188 37.97 Z</Geometry>
<Geometry x:Key="PhysicsIcon">M129.593,64.314c23.543-30.833,44.788-45.063,54.751-45.063c1.37,0,2.507,0.258,3.386,0.775c5.324,3.076,6.332,16.619,2.766,34.505c5.686,1.086,11.14,2.326,16.335,3.722c5.583-26.958,1.861-45.619-10.649-52.856c-12.716-7.34-30.498-1.318-51.434,17.42c-12.018,10.754-24.622,25.416-36.339,42.062c-11.687,0.676-23.237,1.953-34.188,3.813c-7.913-26.6-7.343-44.886-0.783-48.667c0.879-0.517,2.016-0.775,3.386-0.775c7.289,0,19.255,7.237,32.023,19.385c3.618-4.471,7.263-8.736,10.907-12.742C97.657,5.036,78.246-2.253,65.013,5.397C52.297,12.712,48.626,31.114,54.39,58.64c0.901,4.301,2.036,8.788,3.376,13.409C25.626,79.809,2,93.278,2,111.935c0,15.378,16.231,28.637,45.696,37.322l1.241,0.362l0.362-1.215c1.344-4.42,2.869-8.917,4.523-13.388l0.465-1.292l-1.318-0.388c-20.392-5.97-34.065-14.577-34.065-21.4c0-7.721,16.139-17.594,44.084-24.042c3.821,10.43,8.516,21.254,13.893,32.034c-8.08,17.761-14.137,35.252-17.321,50.473c-5.764,27.5-2.094,45.903,10.623,53.217c3.463,2.016,7.366,3.024,11.605,3.024c10.571,0,23.468-6.384,37.606-18.532c-3.851-3.929-7.625-8.064-11.295-12.38c-10.519,8.891-19.979,14.06-26.105,14.06c-1.344,0-2.481-0.259-3.386-0.776c-8.213-4.751-7.064-32.19,8.403-70.244c24.572,42.417,63.859,87.871,92.371,87.871c4.239,0,8.141-1.008,11.605-3.024h0.026c26.285-15.146,10.054-73.998-16.516-123.493c-6.306-1.008-13.207-1.835-20.729-2.43l0.853,1.447c33.316,57.689,38.795,103.592,27.94,109.872c-0.905,0.517-2.042,0.776-3.386,0.776c-13.13,0-45.98-24.787-77.797-79.891c-2.015-3.492-3.924-6.939-5.738-10.338c3.243-6.601,6.866-13.421,10.907-20.419c3.659-6.338,7.331-12.256,10.986-17.8c3.423-0.101,6.903-0.163,10.466-0.163c66.606,0,109.122,18.222,109.122,30.757c0,6.436-12.199,14.448-30.731,20.367c2.042,5.324,3.903,10.623,5.531,15.843c27.164-8.684,42.078-21.452,42.078-36.21C254,81.266,190.199,64.601,129.593,64.314z M91.919,90.689c-1.915,3.32-3.771,6.67-5.566,10.036c-2.506-5.53-4.744-10.887-6.695-16.017c5.395-0.837,11.099-1.547,17.094-2.107C95.11,85.272,93.492,87.964,91.919,90.689z M111.783,114.85c0,10.231,8.324,18.555,18.555,18.555c10.231,0,18.555-8.324,18.555-18.555s-8.324-18.555-18.555-18.555C120.107,96.294,111.783,104.618,111.783,114.85z</Geometry>
<Geometry x:Key="LocaleIcon">M11 1H3C1.9 1 1 1.9 1 3V15L4 12H9V11C9 8.8 10.79 7 13 7V3C13 1.9 12.1 1 11 1M11 4L9.5 4C9.16 5.19 8.54 6.3 7.68 7.26L7.66 7.28L8.92 8.53L8.55 9.54L7 8L4.5 10.5L3.81 9.77L6.34 7.28C5.72 6.59 5.22 5.82 4.86 5H5.85C6.16 5.6 6.54 6.17 7 6.68C7.72 5.88 8.24 4.97 8.57 4L3 4V3H6.5V2H7.5V3H11V4M21 9H13C11.9 9 11 9.9 11 11V18C11 19.1 11.9 20 13 20H20L23 23V11C23 9.9 22.1 9 21 9M19.63 19L18.78 16.75H15.22L14.38 19H12.88L16.25 10H17.75L21.13 19H19.63M17 12L18.22 15.25H15.79L17 12Z</Geometry>
<Geometry x:Key="FontIcon">M17,8H20V20H21V21H17V20H18V17H14L12.5,20H14V21H10V20H11L17,8M18,9L14.5,16H18V9M5,3H10C11.11,3 12,3.89 12,5V16H9V11H6V16H3V5C3,3.89 3.89,3 5,3M6,5V9H9V5H6Z</Geometry>
<Geometry x:Key="LuaIcon">M10.5,5A8.5,8.5 0 0,0 2,13.5A8.5,8.5 0 0,0 10.5,22A8.5,8.5 0 0,0 19,13.5A8.5,8.5 0 0,0 10.5,5M13.5,13A2.5,2.5 0 0,1 11,10.5A2.5,2.5 0 0,1 13.5,8A2.5,2.5 0 0,1 16,10.5A2.5,2.5 0 0,1 13.5,13M19.5,2A2.5,2.5 0 0,0 17,4.5A2.5,2.5 0 0,0 19.5,7A2.5,2.5 0 0,0 22,4.5A2.5,2.5 0 0,0 19.5,2</Geometry>
<Geometry x:Key="JsonIcon">M5,3H7V5H5V10A2,2 0 0,1 3,12A2,2 0 0,1 5,14V19H7V21H5C3.93,20.73 3,20.1 3,19V15A2,2 0 0,0 1,13H0V11H1A2,2 0 0,0 3,9V5A2,2 0 0,1 5,3M19,3A2,2 0 0,1 21,5V9A2,2 0 0,0 23,11H24V13H23A2,2 0 0,0 21,15V19A2,2 0 0,1 19,21H17V19H19V14A2,2 0 0,1 21,12A2,2 0 0,1 19,10V5H17V3H19M12,15A1,1 0 0,1 13,16A1,1 0 0,1 12,17A1,1 0 0,1 11,16A1,1 0 0,1 12,15M8,15A1,1 0 0,1 9,16A1,1 0 0,1 8,17A1,1 0 0,1 7,16A1,1 0 0,1 8,15M16,15A1,1 0 0,1 17,16A1,1 0 0,1 16,17A1,1 0 0,1 15,16A1,1 0 0,1 16,15Z</Geometry>
<Geometry x:Key="TxtIcon">M14,17H7V15H14M17,13H7V11H17M17,9H7V7H17M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3Z</Geometry>
<Geometry x:Key="TextureIconAlt">M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6,20H15L18,20V12L14,16L12,14L6,20M8,9A2,2 0 0,0 6,11A2,2 0 0,0 8,13A2,2 0 0,0 10,11A2,2 0 0,0 8,9Z</Geometry>
<Geometry x:Key="VideoIcon">M608 0H160a32 32 0 0 0-32 32v96h160V64h192v320h128a32 32 0 0 0 32-32V32a32 32 0 0 0-32-32M232 103a9 9 0 0 1-9 9h-30a9 9 0 0 1-9-9V73a9 9 0 0 1 9-9h30a9 9 0 0 1 9 9zm352 208a9 9 0 0 1-9 9h-30a9 9 0 0 1-9-9v-30a9 9 0 0 1 9-9h30a9 9 0 0 1 9 9zm0-104a9 9 0 0 1-9 9h-30a9 9 0 0 1-9-9v-30a9 9 0 0 1 9-9h30a9 9 0 0 1 9 9zm0-104a9 9 0 0 1-9 9h-30a9 9 0 0 1-9-9V73a9 9 0 0 1 9-9h30a9 9 0 0 1 9 9zm-168 57H32a32 32 0 0 0-32 32v288a32 32 0 0 0 32 32h384a32 32 0 0 0 32-32V192a32 32 0 0 0-32-32M96 224a32 32 0 1 1-32 32a32 32 0 0 1 32-32m288 224H64v-32l64-64l32 32l128-128l96 96z</Geometry>
<Geometry x:Key="CppIcon">M 21.955078 6.001953 L 13.535156 1.269531 C 12.896484 0.912109 12.103516 0.912109 11.464844 1.269531 L 3.044922 6.001953 C 2.400391 6.363281 2 7.041016 2 7.767578 L 2 17.232422 C 2 17.958984 2.400391 18.636719 3.044922 18.998047 L 11.464844 23.730469 C 11.785156 23.910156 12.142578 24 12.5 24 C 12.857422 24 13.214844 23.910156 13.535156 23.730469 L 21.955078 18.998047 C 22.599609 18.636719 23 17.958984 23 17.232422 L 23 7.767578 C 23 7.041016 22.599609 6.363281 21.955078 6.001953 Z M 12.5 18.5 C 9.191406 18.5 6.5 15.808594 6.5 12.5 C 6.5 9.191406 9.191406 6.5 12.5 6.5 C 14.390625 6.5 16.136719 7.376953 17.271484 8.871094 L 15.080078 10.138672 C 14.421875 9.417969 13.486328 9 12.5 9 C 10.570313 9 9 10.570313 9 12.5 C 9 14.429688 10.570313 16 12.5 16 C 13.486328 16 14.421875 15.582031 15.080078 14.861328 L 17.271484 16.128906 C 16.136719 17.623047 14.390625 18.5 12.5 18.5 Z M 18.5 13 L 17.5 13 L 17.5 14 L 16.5 14 L 16.5 13 L 15.5 13 L 15.5 12 L 16.5 12 L 16.5 11 L 17.5 11 L 17.5 12 L 18.5 12 Z M 22 13 L 21 13 L 21 14 L 20 14 L 20 13 L 19 13 L 19 12 L 20 12 L 20 11 L 21 11 L 21 12 L 22 12 Z</Geometry>
<Geometry x:Key="AnimationIconAlt">M4,2C2.89,2 2,2.89 2,4V14H4V4H14V2H4M8,6C6.89,6 6,6.89 6,8V18H8V8H18V6H8M12,10C10.89,10 10,10.89 10,12V20C10,21.11 10.89,22 12,22H20C21.11,22 22,21.11 22,20V12C22,10.89 21.11,10 20,10H12Z</Geometry>
<Geometry x:Key="ClearFiltersIcon">M14.46,15.88L15.88,14.46L18,16.59L20.12,14.46L21.54,15.88L19.41,18L21.54,20.12L20.12,21.54L18,19.41L15.88,21.54L14.46,20.12L16.59,18L14.46,15.88M12,17V15H7V17H12M17,11H7V13H14.69C13.07,14.07 12,15.91 12,18C12,19.09 12.29,20.12 12.8,21H5C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3H19A2,2 0 0,1 21,5V12.8C20.12,12.29 19.09,12 18,12L17,12.08V11M17,9V7H7V9H17Z</Geometry>
<Geometry x:Key="ParticleIcon">M18,11a1,1,0,0,1-1,1,5,5,0,0,0-5,5,1,1,0,0,1-2,0,5,5,0,0,0-5-5,1,1,0,0,1,0-2,5,5,0,0,0,5-5,1,1,0,0,1,2,0,5,5,0,0,0,5,5A1,1,0,0,1,18,11Z M19,24a1,1,0,0,1-1,1,2,2,0,0,0-2,2,1,1,0,0,1-2,0,2,2,0,0,0-2-2,1,1,0,0,1,0-2,2,2,0,0,0,2-2,1,1,0,0,1,2,0,2,2,0,0,0,2,2A1,1,0,0,1,19,24Z M28,17a1,1,0,0,1-1,1,4,4,0,0,0-4,4,1,1,0,0,1-2,0,4,4,0,0,0-4-4,1,1,0,0,1,0-2,4,4,0,0,0,4-4,1,1,0,0,1,2,0,4,4,0,0,0,4,4A1,1,0,0,1,28,17Z</Geometry>
<Geometry x:Key="WorldIcon">M24.965,14.125c1.913,2.718,2.076,2.976,2.092,3.345c0.646,0.529,1.002,1.082,1.002,1.621 c0,2.141-5.571,4.535-13.03,4.535c-7.457,0-13.03-2.396-13.03-4.535c0-0.859,0.912-1.76,2.475-2.529 c0.373-0.715,0.843-1.61,1.429-2.721C2.456,14.931,0,16.703,0,19.091c0,4.244,7.743,6.535,15.029,6.535 c7.287,0,15.03-2.291,15.03-6.535C30.059,16.896,27.977,15.228,24.965,14.125z M12.849,20.742c4.61,0,8.348-0.45,8.348-1.01c0-0.029-0.442-0.652-0.855-1.229c2.933-0.05,5.217-0.445,5.217-0.927 c0-0.013-5.186-7.367-6.614-9.396c-0.082-0.117-0.218-0.187-0.36-0.188c-0.144,0-0.279,0.07-0.362,0.187l-1.804,2.551 L13.24,4.668c-0.078-0.145-0.228-0.236-0.392-0.236c-0.165,0-0.315,0.091-0.393,0.236C10.802,7.788,4.5,19.685,4.5,19.731 C4.499,20.291,8.236,20.742,12.849,20.742z</Geometry>
<Geometry x:Key="VerseIcon">M 0 0 L 191 380 L 381 0 L 227 0 L 298 52 L 204 238 L 85 1 Z</Geometry>
<Geometry x:Key="CurveIcon">M9.96,11.31C10.82,8.1 11.5,6 13,6C14.5,6 15.18,8.1 16.04,11.31C17,14.92 18.1,19 22,19V17C19.8,17 19,14.54 17.97,10.8C17.08,7.46 16.15,4 13,4C9.85,4 8.92,7.46 8.03,10.8C7.03,14.54 6.2,17 4,17V2H2V22H22V20H4V19C7.9,19 9,14.92 9.96,11.31Z</Geometry>
<Geometry x:Key="FunctionIcon">M15.6,5.29C14.5,5.19 13.53,6 13.43,7.11L13.18,10H16V12H13L12.56,17.07C12.37,19.27 10.43,20.9 8.23,20.7C6.92,20.59 5.82,19.86 5.17,18.83L6.67,17.33C6.91,18.07 7.57,18.64 8.4,18.71C9.5,18.81 10.47,18 10.57,16.89L11,12H8V10H11.17L11.44,6.93C11.63,4.73 13.57,3.1 15.77,3.3C17.08,3.41 18.18,4.14 18.83,5.17L17.33,6.67C17.09,5.93 16.43,5.36 15.6,5.29Z</Geometry>
<Geometry x:Key="MaterialFunctionIcon">M165.446 34.793c-23.17.023-45.634 12.97-54.612 36.323l-83.67 326.167c-12.673 94.537 81.04 88.742 137.957 65.396 81.422-33.396 181.723-29.213 263.244-8.26l6.45-17.218c-7.38-2.638-15.334-5.988-22.252-8.039.473-4.364.955-8.72 1.437-13.074l23.038 4.118 3.234-18.1c-8.074-1.441-16.147-2.885-24.221-4.328.615-5.403 1.238-10.799 1.87-16.189l22.134 3.278 2.693-18.186c-7.548-1.12-15.098-2.238-22.647-3.355.456-3.765.91-7.53 1.375-11.29 7.615 1.092 15.231 2.183 22.847 3.273l2.607-18.2-23.164-3.316c.46-3.593 1.29-9.988 1.76-13.577l22.781 2.55 2.045-17.57c-7.467-.834-14.935-1.671-22.402-2.508.783-5.767 1.917-11.182 2.728-16.943 7.67 1.12 15.341 2.244 23.012 3.368l2.31-17.139c-7.683-1.127-15.366-2.25-23.05-3.374.792-5.415 1.252-10.129 2.071-15.542 7.074 1.264 14.149 2.528 21.223 3.79l3.232-18.1-21.654-3.866c.736-4.676 1.473-9.35 2.23-14.026 6.978 1.673 13.955 3.347 20.932 5.022L465.276 208c-7.401-1.778-14.803-3.554-22.204-5.33a2809.25 2809.25 0 0 1 2.132-12.477c6.98 1.583 13.961 3.165 20.942 4.746l4.064-17.93c-7.271-1.65-14.543-3.298-21.815-4.946.769-4.267 1.55-8.535 2.342-12.805l20.742 5.151 4.431-17.843-21.751-5.405c.741-3.847 1.494-7.696 2.254-11.548l20.28 5.014 4.413-17.849-21.057-5.207a2444.47 2444.47 0 0 1 2.571-12.374c8.386 2.41 13.13 2.364 21.41 4.99L486 88.456c-83.808-26.776-179.25-33.22-244.192-6.453-24.337 114.036-37.305 221.4-68.032 338.64-3.407 13-14.47 21.89-27.342 28.064-27 11.608-64.033 13.778-84.63-4.91-10.971-10.34-16.174-27.036-12.467-47.579 2.303-12.762 10.883-21.986 20.834-26.378 19.749-7.074 43.492-4.25 58.893 7.95 12.463 9.302 12.318 38.283-3.882 31.82-9.639-6.17-1.964-11.851-8.615-17.378-11.6-7.428-26.42-10.872-38.972-5.57-5.564 2.455-8.887 5.737-10.166 12.822-2.94 16.29.685 24.996 6.985 30.933 18.333 13.49 45.279 10.495 64.068 1.712 10.045-4.82 16.277-11.436 17.511-16.147 30.538-116.518 43.443-224.123 68.293-339.964-11.796-28.344-35.67-41.247-58.84-41.225z M350 153.5c-13.2-1.2-25.8 8.4-27 21.2l-3 34.8h36v24h-36l-5.3 60.8c-2.3 26.4-25.6 45.9-52 43.4-15.7-1.3-28.9-10.1-36.7-22.4l18-18c2.9 8.9 10.8 15.7 20.7 16.5 13.2 1.2 25.8-8.4 27-21.2l5.2-58.9h-36v-24h38l3.3-36.8c2.3-26.4 25.6-45.9 52-43.4 15.7 1.3 28.9 10.1 36.7 22.4l-18 18c-2.9-8.9-10.8-15.7-20.7-16.5z</Geometry>
<Geometry x:Key="MonitorIcon">M21,16H3V4H21M21,2H3C1.89,2 1,2.89 1,4V16A2,2 0 0,0 3,18H10V20H8V22H16V20H14V18H21A2,2 0 0,0 23,16V4C23,2.89 22.1,2 21,2Z</Geometry>
<Geometry x:Key="ClapperIcon">M60.131 21.423H35.659l24.279-2.656l1.878-.206l-.224-1.876l-1.53-12.849l-.183-1.524l-1.527-.12l-2.22-.173L55.888 2l-.24.044l-51.923 9.565L2 11.927l.207 1.744l.404 3.397v16.381l.477.029v16.524l1.473.32l52.982 11.516l.746.162l.646-.408l2.191-1.383l.874-.55V21.423h-1.869M55.985 3.884l2.22.174l1.37 11.494l-1.739-2.536l-6.791-8.222l4.94-.91M42.58 6.354l9.299 11.413l-8.489.929l-8.431-10.938l7.621-1.404M28.059 9.029l7.692 10.503l-6.908.756l-7.046-10.105l6.262-1.154m-11.981 2.206l6.482 9.74l-5.731.626l-5.988-9.401l5.237-.965m-5.461 15.844l-2.77-3.601l.096-.184h4.72l-2.046 3.785m1.064 3.165c0 .55-.393.973-.874.946c-.479-.027-.863-.488-.863-1.029s.385-.965.863-.945c.481.018.874.479.874 1.028M4.516 17.246l-.453-3.797l1.961-.361l5.554 9.089l-1.146.125l-2.766.303l-.588-1l-2.562-4.359M6.474 22.8c0 .525-.359.952-.799.957c-.437.002-.787-.414-.787-.931c0-.519.351-.945.787-.957c.439-.011.799.406.799.931m-.799 6.213c.439.018.799.457.799.982c0 .525-.359.929-.799.903c-.437-.024-.787-.463-.787-.98c0-.518.35-.922.787-.905m54.456 15.454l-1.867.482l-43.419-5.381v4.129l43.419 6.875l1.867-.797v1.365l-1.867.814l-53.307-8.87v-.948l8.956 1.414v-4.098l-8.956-1.11v-.948l53.307 6.174l1.867-.468v1.367m0-8.235l-1.867.311l-53.307-3.89v-.923l9.713.62l-1.161-1.51l4.27-7.546h5.096l-5.473 9.183l5.727.369l6.006-9.552h6.882l-6.614 9.957l6.905.445l7.319-10.402h8.458L43.94 34.189l8.485.547l5.937-7.888l1.769-3.007v12.391</Geometry>
<Geometry x:Key="XmlIcon">M19 3H5C3.89 3 3 3.89 3 5V19C3 20.11 3.89 21 5 21H19C20.11 21 21 20.11 21 19V5C21 3.89 20.11 3 19 3M8 15H6.5L6 13L5.5 15H4L4.75 12L4 9H5.5L6 11L6.5 9H8L7.25 12L8 15M15.5 15H14V10.5H13V14H11.5V10.5H10.5V15H9V11C9 9.9 9.9 9 11 9H13.5C14.61 9 15.5 9.9 15.5 11V15M20 15H17V9H18.5V13.5H20V15Z</Geometry>
<Geometry x:Key="FoliageIcon">m397.529,58.225c-37.359,0-72.27,11.235-100.957,32.49-25.401,18.819-44.228,44.84-51.653,71.391-8.498,30.386-1.593,57.841 18.431,75.96-6.892,12.102-13.298,24.592-18.372,36.707-4.66-11.592-10.865-21.973-17.882-31.224 9.949-15.808 11.327-35.12 3.511-54.911-7.36-18.635-22.266-35.818-41.974-48.386-21.258-13.556-46.288-20.721-72.383-20.721-33.485,0-67.836,12.078-99.338,34.928l-16.912,12.268 20.162,5.478c33.26,9.036 59.805,34.679 83.225,57.303 23.91,23.098 46.495,44.914 72.659,44.921 0.004,0 0.008,0 0.012,0 12.875,0 25.18-5.146 37.498-15.667 11.82,16.664 20.228,37.094 20.228,61.938v127h20c0,0 0.018-122.778 0.018-129.384 0-15.96 9.362-39.486 26.042-68.882 12.387,6.689 23.962,9.954 35.235,9.954 36.76,0 60.665-35.173 85.974-72.41 22.59-33.238 48.194-70.911 86.29-90.421l18.581-9.516-19.061-8.516c-30.153-13.47-60.209-20.3-89.334-20.3zm-221.471,196.203c-0.002,0-0.004,0-0.007,0-18.085-0.005-36.938-18.218-58.768-39.306-20.663-19.961-43.588-42.108-72.305-55.135 23.345-13.586 47.248-20.456 71.272-20.456 48.227,0 84.676,28.4 95.755,56.453 2.869,7.266 5.835,19.295 0.99,31.335-17.942-18.216-37.69-30.663-49.979-38.408-3.594-2.266-6.698-4.222-8.771-5.695l-11.59,16.299c2.526,1.797 5.85,3.892 9.697,6.316 12.659,7.979 31.868,20.09 48.451,37.523-8.638,7.436-16.76,11.074-24.745,11.074zm208.452-78.693c-23.213,34.155-43.261,63.652-69.432,63.652-7.676,0-15.897-2.358-24.996-7.165 0.894-1.439 1.797-2.886 2.722-4.348 19.815-31.329 39.938-56.696 40.139-56.949l-15.649-12.454c-1.715,2.155-22.828,28.846-43.394,61.905-12.095-13.03-15.666-31.622-9.72-52.884 6.252-22.354 22.397-44.482 44.298-60.708 17.584-13.028 47.309-28.56 89.051-28.56 20.458,0 41.53,3.779 62.861,11.258-32.716,22.745-55.46,56.209-75.88,86.253z</Geometry>
<Geometry x:Key="MaterialParameterCollectionIcon">M165.446 34.793c-23.17.023-45.634 12.97-54.612 36.323l-83.67 326.167c-12.673 94.537 81.04 88.742 137.957 65.396 81.422-33.396 181.723-29.213 263.244-8.26l6.45-17.218c-7.38-2.638-15.334-5.988-22.252-8.039.473-4.364.955-8.72 1.437-13.074l23.038 4.118 3.234-18.1c-8.074-1.441-16.147-2.885-24.221-4.328.615-5.403 1.238-10.799 1.87-16.189l22.134 3.278 2.693-18.186c-7.548-1.12-15.098-2.238-22.647-3.355.456-3.765.91-7.53 1.375-11.29 7.615 1.092 15.231 2.183 22.847 3.273l2.607-18.2-23.164-3.316c.46-3.593 1.29-9.988 1.76-13.577l22.781 2.55 2.045-17.57c-7.467-.834-14.935-1.671-22.402-2.508.783-5.767 1.917-11.182 2.728-16.943 7.67 1.12 15.341 2.244 23.012 3.368l2.31-17.139c-7.683-1.127-15.366-2.25-23.05-3.374.792-5.415 1.252-10.129 2.071-15.542 7.074 1.264 14.149 2.528 21.223 3.79l3.232-18.1-21.654-3.866c.736-4.676 1.473-9.35 2.23-14.026 6.978 1.673 13.955 3.347 20.932 5.022L465.276 208c-7.401-1.778-14.803-3.554-22.204-5.33a2809.25 2809.25 0 0 1 2.132-12.477c6.98 1.583 13.961 3.165 20.942 4.746l4.064-17.93c-7.271-1.65-14.543-3.298-21.815-4.946.769-4.267 1.55-8.535 2.342-12.805l20.742 5.151 4.431-17.843-21.751-5.405c.741-3.847 1.494-7.696 2.254-11.548l20.28 5.014 4.413-17.849-21.057-5.207a2444.47 2444.47 0 0 1 2.571-12.374c8.386 2.41 13.13 2.364 21.41 4.99L486 88.456c-83.808-26.776-179.25-33.22-244.192-6.453-24.337 114.036-37.305 221.4-68.032 338.64-3.407 13-14.47 21.89-27.342 28.064-27 11.608-64.033 13.778-84.63-4.91-10.971-10.34-16.174-27.036-12.467-47.579 2.303-12.762 10.883-21.986 20.834-26.378 19.749-7.074 43.492-4.25 58.893 7.95 12.463 9.302 12.318 38.283-3.882 31.82-9.639-6.17-1.964-11.851-8.615-17.378-11.6-7.428-26.42-10.872-38.972-5.57-5.564 2.455-8.887 5.737-10.166 12.822-2.94 16.29.685 24.996 6.985 30.933 18.333 13.49 45.279 10.495 64.068 1.712 10.045-4.82 16.277-11.436 17.511-16.147 30.538-116.518 43.443-224.123 68.293-339.964-11.796-28.344-35.67-41.247-58.84-41.225z M341 395l-36 -40 -45 20 3 -13 24 -11c5,-2 9,-4 11,-5 -2,-2 -5,-5 -8,-8l-19 -21 2 -12 33 36 49 -22 -3 13 -33 15c-2,1 -4,2 -6,2 2,2 4,4 5,5l24 26 -3 13zm-15 -177l-10 54 -9 -2 10 -54 9 2zm25 5l-10 54 -9 -2 10 -54 9 2zm39 -76l-2 10 -64 -12c2,3 4,6 5,11 2,4 3,8 3,12l-10 -2c-2,-6 -4,-12 -7,-17 -3,-5 -6,-9 -9,-11l1 -6 82 16z</Geometry>
<Geometry x:Key="CertificateIcon">M4,3C2.89,3 2,3.89 2,5V15A2,2 0 0,0 4,17H12V22L15,19L18,22V17H20A2,2 0 0,0 22,15V8L22,6V5A2,2 0 0,0 20,3H16V3H4M12,5L15,7L18,5V8.5L21,10L18,11.5V15L15,13L12,15V11.5L9,10L12,8.5V5M4,5H9V7H4V5M4,9H7V11H4V9M4,13H9V15H4V13Z</Geometry>
</ResourceDictionary>

View File

@ -13,65 +13,8 @@
xmlns:adonisConverters="clr-namespace:AdonisUI.Converters;assembly=AdonisUI"
xmlns:adonisExtensions="clr-namespace:AdonisUI.Extensions;assembly=AdonisUI"
xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI">
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<Geometry x:Key="StatusBarIcon">M22,9v6c0,1.1-0.9,2-2,2h-1l0-2h1V9H4v6h6v2H4c-1.1,0-2-0.9-2-2V9c0-1.1,0.9-2,2-2h16C21.1,7,22,7.9,22,9z M14.04,17.99 c0.18,0.39,0.73,0.39,0.91,0l0.63-1.4l1.4-0.63c0.39-0.18,0.39-0.73,0-0.91l-1.4-0.63l-0.63-1.4c-0.18-0.39-0.73-0.39-0.91,0 l-0.63,1.4l-1.4,0.63c-0.39,0.18-0.39,0.73,0,0.91l1.4,0.63L14.04,17.99z M16.74,13.43c0.1,0.22,0.42,0.22,0.52,0l0.36-0.8 l0.8-0.36c0.22-0.1,0.22-0.42,0-0.52l-0.8-0.36l-0.36-0.8c-0.1-0.22-0.42-0.22-0.52,0l-0.36,0.8l-0.8,0.36 c-0.22,0.1-0.22,0.42,0,0.52l0.8,0.36L16.74,13.43z</Geometry>
<Geometry x:Key="SearchIcon">M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z</Geometry>
<Geometry x:Key="DirectoryIcon">M19.71,15.71l-3.59,3.59c-0.63,0.63-1.71,0.18-1.71-0.71V16h-7c-1.1,0-2-0.9-2-2V5c0-0.55,0.45-1,1-1h0c0.55,0,1,0.45,1,1 v9h7v-2.59c0-0.89,1.08-1.34,1.71-0.71l3.59,3.59C20.1,14.68,20.1,15.32,19.71,15.71z</Geometry>
<Geometry x:Key="AddIcon">M18 13h-5v5c0 .55-.45 1-1 1s-1-.45-1-1v-5H6c-.55 0-1-.45-1-1s.45-1 1-1h5V6c0-.55.45-1 1-1s1 .45 1 1v5h5c.55 0 1 .45 1 1s-.45 1-1 1z</Geometry>
<Geometry x:Key="RemoveIcon">M18.3,5.71L18.3,5.71c-0.39-0.39-1.02-0.39-1.41,0L12,10.59L7.11,5.7c-0.39-0.39-1.02-0.39-1.41,0l0,0 c-0.39,0.39-0.39,1.02,0,1.41L10.59,12L5.7,16.89c-0.39,0.39-0.39,1.02,0,1.41l0,0c0.39,0.39,1.02,0.39,1.41,0L12,13.41l4.89,4.89 c0.39,0.39,1.02,0.39,1.41,0l0,0c0.39-0.39,0.39-1.02,0-1.41L13.41,12l4.89-4.89C18.68,6.73,18.68,6.09,18.3,5.71z</Geometry>
<Geometry x:Key="ArrowIcon">M7.71,9.29l3.88,3.88l3.88-3.88c0.39-0.39,1.02-0.39,1.41,0l0,0c0.39,0.39,0.39,1.02,0,1.41l-4.59,4.59 c-0.39,0.39-1.02,0.39-1.41,0L6.29,10.7c-0.39-0.39-0.39-1.02,0-1.41l0,0C6.68,8.91,7.32,8.9,7.71,9.29z</Geometry>
<Geometry x:Key="KeyIcon">M3,17h18c0.55,0,1,0.45,1,1v0c0,0.55-0.45,1-1,1H3c-0.55,0-1-0.45-1-1v0C2,17.45,2.45,17,3,17z M2.5,12.57 c0.36,0.21,0.82,0.08,1.03-0.28L4,11.47l0.48,0.83c0.21,0.36,0.67,0.48,1.03,0.28l0,0c0.36-0.21,0.48-0.66,0.28-1.02L5.3,10.72 h0.95C6.66,10.72,7,10.38,7,9.97v0c0-0.41-0.34-0.75-0.75-0.75H5.3L5.77,8.4C5.98,8.04,5.86,7.58,5.5,7.37l0,0 C5.14,7.17,4.68,7.29,4.47,7.65L4,8.47L3.53,7.65C3.32,7.29,2.86,7.17,2.5,7.37l0,0C2.14,7.58,2.02,8.04,2.23,8.4L2.7,9.22H1.75 C1.34,9.22,1,9.56,1,9.97v0c0,0.41,0.34,0.75,0.75,0.75H2.7l-0.48,0.83C2.02,11.91,2.14,12.37,2.5,12.57L2.5,12.57z M10.5,12.57 L10.5,12.57c0.36,0.21,0.82,0.08,1.03-0.28L12,11.47l0.48,0.83c0.21,0.36,0.67,0.48,1.03,0.28l0,0c0.36-0.21,0.48-0.66,0.28-1.02 l-0.48-0.83h0.95c0.41,0,0.75-0.34,0.75-0.75v0c0-0.41-0.34-0.75-0.75-0.75H13.3l0.47-0.82c0.21-0.36,0.08-0.82-0.27-1.03l0,0 c-0.36-0.21-0.82-0.08-1.02,0.27L12,8.47l-0.47-0.82c-0.21-0.36-0.67-0.48-1.02-0.27l0,0c-0.36,0.21-0.48,0.67-0.27,1.03 l0.47,0.82H9.75C9.34,9.22,9,9.56,9,9.97v0c0,0.41,0.34,0.75,0.75,0.75h0.95l-0.48,0.83C10.02,11.91,10.14,12.37,10.5,12.57z M23,9.97c0-0.41-0.34-0.75-0.75-0.75H21.3l0.47-0.82c0.21-0.36,0.08-0.82-0.27-1.03l0,0c-0.36-0.21-0.82-0.08-1.02,0.27L20,8.47 l-0.47-0.82c-0.21-0.36-0.67-0.48-1.02-0.27l0,0c-0.36,0.21-0.48,0.67-0.27,1.03l0.47,0.82h-0.95C17.34,9.22,17,9.56,17,9.97v0 c0,0.41,0.34,0.75,0.75,0.75h0.95l-0.48,0.83c-0.21,0.36-0.08,0.82,0.28,1.02l0,0c0.36,0.21,0.82,0.08,1.03-0.28L20,11.47 l0.48,0.83c0.21,0.36,0.67,0.48,1.03,0.28l0,0c0.36-0.21,0.48-0.66,0.28-1.02l-0.48-0.83h0.95C22.66,10.72,23,10.38,23,9.97 L23,9.97z</Geometry>
<Geometry x:Key="BackupIcon">M19,11c0-3.87-3.13-7-7-7C8.78,4,6.07,6.18,5.26,9.15C2.82,9.71,1,11.89,1,14.5C1,17.54,3.46,20,6.5,20 c1.76,0,10.25,0,12,0l0,0c2.49-0.01,4.5-2.03,4.5-4.52C23,13.15,21.25,11.26,19,11z M13,13v2c0,0.55-0.45,1-1,1h0 c-0.55,0-1-0.45-1-1v-2H9.21c-0.45,0-0.67-0.54-0.35-0.85l2.79-2.79c0.2-0.2,0.51-0.2,0.71,0l2.79,2.79 c0.31,0.31,0.09,0.85-0.35,0.85H13z</Geometry>
<Geometry x:Key="ExpanderIcon">M16,17.01V11c0-0.55-0.45-1-1-1s-1,0.45-1,1v6.01h-1.79c-0.45,0-0.67,0.54-0.35,0.85l2.79,2.78c0.2,0.19,0.51,0.19,0.71,0 l2.79-2.78c0.32-0.31,0.09-0.85-0.35-0.85H16z M8.65,3.35L5.86,6.14c-0.32,0.31-0.1,0.85,0.35,0.85H8V13c0,0.55,0.45,1,1,1 s1-0.45,1-1V6.99h1.79c0.45,0,0.67-0.54,0.35-0.85L9.35,3.35C9.16,3.16,8.84,3.16,8.65,3.35z</Geometry>
<Geometry x:Key="FolderIcon">M20,6h-8l-1.41-1.41C10.21,4.21,9.7,4,9.17,4H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8 C22,6.9,21.1,6,20,6z M15.98,15.74l-1.07-0.82l-1.07,0.82c-0.39,0.29-0.92-0.08-0.78-0.55l0.42-1.36l-1.2-0.95 C11.91,12.6,12.12,12,12.59,12H14l0.43-1.34c0.15-0.46,0.8-0.46,0.95,0L15.82,12h1.41c0.47,0,0.68,0.6,0.31,0.89l-1.2,0.95 l0.42,1.36C16.91,15.66,16.37,16.04,15.98,15.74z</Geometry>
<Geometry x:Key="ExportIcon">M19.41,7.41l-4.83-4.83C14.21,2.21,13.7,2,13.17,2H6C4.9,2,4.01,2.9,4.01,4L4,20c0,1.1,0.89,2,1.99,2H18c1.1,0,2-0.9,2-2 V8.83C20,8.3,19.79,7.79,19.41,7.41z M14.8,15H13v3c0,0.55-0.45,1-1,1s-1-0.45-1-1v-3H9.21c-0.45,0-0.67-0.54-0.35-0.85l2.8-2.79 c0.2-0.19,0.51-0.19,0.71,0l2.79,2.79C15.46,14.46,15.24,15,14.8,15z M14,9c-0.55,0-1-0.45-1-1V3.5L18.5,9H14z</Geometry>
<Geometry x:Key="SaveIcon">M16.17,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V7.83c0-0.53-0.21-1.04-0.59-1.41l-2.83-2.83 C17.21,3.21,16.7,3,16.17,3z M12,18c-1.66,0-3-1.34-3-3s1.34-3,3-3s3,1.34,3,3S13.66,18,12,18z M14,10H7c-0.55,0-1-0.45-1-1V7 c0-0.55,0.45-1,1-1h7c0.55,0,1,0.45,1,1v2C15,9.55,14.55,10,14,10z</Geometry>
<Geometry x:Key="TextureIcon">M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M6.6,16.2l2-2.67 c0.2-0.27,0.6-0.27,0.8,0L11.25,16l2.6-3.47c0.2-0.27,0.6-0.27,0.8,0l2.75,3.67c0.25,0.33,0.01,0.8-0.4,0.8H7 C6.59,17,6.35,16.53,6.6,16.2z</Geometry>
<Geometry x:Key="ModelIcon">M12 6q-.825 0-1.412-.588Q10 4.825 10 4t.588-1.413Q11.175 2 12 2t1.413.587Q14 3.175 14 4q0 .825-.587 1.412Q12.825 6 12 6ZM9 22V9H3V7h18v2h-6v13h-2v-6h-2v6Z</Geometry>
<Geometry x:Key="AnimationIcon">M9 22q-1.45 0-2.725-.55Q5 20.9 4.05 19.95q-.95-.95-1.5-2.225Q2 16.45 2 15q0-2.025 1.05-3.7Q4.1 9.625 5.8 8.75q.5-.975 1.238-1.713Q7.775 6.3 8.75 5.8q.825-1.7 2.525-2.75T15 2q1.45 0 2.725.55Q19 3.1 19.95 4.05q.95.95 1.5 2.225Q22 7.55 22 9q0 2.125-1.05 3.75t-2.75 2.5q-.5.975-1.238 1.712-.737.738-1.712 1.238-.875 1.7-2.55 2.75Q11.025 22 9 22Zm0-2q.825 0 1.588-.25Q11.35 19.5 12 19q-1.45 0-2.725-.55Q8 17.9 7.05 16.95q-.95-.95-1.5-2.225Q5 13.45 5 12q-.5.65-.75 1.412Q4 14.175 4 15q0 1.05.4 1.95.4.9 1.075 1.575.675.675 1.575 1.075.9.4 1.95.4Zm3-3q.825 0 1.613-.25.787-.25 1.437-.75-1.475 0-2.75-.562-1.275-.563-2.225-1.513-.95-.95-1.513-2.225Q8 10.425 8 8.95q-.5.65-.75 1.437Q7 11.175 7 12q0 1.05.388 1.95.387.9 1.087 1.575.675.7 1.575 1.088.9.387 1.95.387Zm3-3q.45 0 .863-.075.412-.075.837-.225.55-1.5.163-2.888-.388-1.387-1.338-2.337-.95-.95-2.337-1.338Q11.8 6.75 10.3 7.3q-.15.425-.225.837Q10 8.55 10 9q0 1.05.387 1.95.388.9 1.088 1.575.675.7 1.575 1.088.9.387 1.95.387Zm4-1.95q.5-.65.75-1.438Q20 9.825 20 9q0-1.05-.387-1.95-.388-.9-1.088-1.575-.675-.7-1.575-1.088Q16.05 4 15 4q-.875 0-1.637.25-.763.25-1.413.75 1.475 0 2.75.562 1.275.563 2.225 1.513.95.95 1.513 2.225.562 1.275.562 2.75Z</Geometry>
<Geometry x:Key="CopyIcon">M3,7L3,7C2.45,7,2,7.45,2,8v13c0,1.1,0.9,2,2,2h11c0.55,0,1-0.45,1-1v0c0-0.55-0.45-1-1-1H4V8C4,7.45,3.55,7,3,7z M15.59,1.59C15.21,1.21,14.7,1,14.17,1H8C6.9,1,6.01,1.9,6.01,3L6,17c0,1.1,0.89,2,1.99,2H19c1.1,0,2-0.9,2-2V7.83 c0-0.53-0.21-1.04-0.59-1.41L15.59,1.59z M14,7V2.5L19.5,8H15C14.45,8,14,7.55,14,7z</Geometry>
<Geometry x:Key="DirectoriesIcon">M14.4,6l-0.24-1.2C14.07,4.34,13.66,4,13.18,4H6C5.45,4,5,4.45,5,5v15c0,0.55,0.45,1,1,1l0,0c0.55,0,1-0.45,1-1v-6h5.6 l0.24,1.2c0.09,0.47,0.5,0.8,0.98,0.8H19c0.55,0,1-0.45,1-1V7c0-0.55-0.45-1-1-1H14.4z</Geometry>
<Geometry x:Key="DirectoriesAddIcon">M20 1v3h3v2h-3v3h-2V6h-3V4h3V1h2zm-8 12c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm2-9.75V7h3v3h2.92c.05.39.08.79.08 1.2 0 3.32-2.67 7.25-8 11.8-5.33-4.55-8-8.48-8-11.8C4 6.22 7.8 3 12 3c.68 0 1.35.08 2 .25z</Geometry>
<Geometry x:Key="ExtractIcon">M20.29,10.29l-3.59-3.59C16.08,6.08,15,6.52,15,7.41V10H8c-2.76,0-5,2.24-5,5v3c0,0.55,0.45,1,1,1h0c0.55,0,1-0.45,1-1v-3 c0-1.65,1.35-3,3-3h7v2.59c0,0.89,1.08,1.34,1.71,0.71l3.59-3.59C20.68,11.32,20.68,10.68,20.29,10.29z</Geometry>
<Geometry x:Key="GoToIcon">M9.5,5.5c1.1,0,2-0.9,2-2s-0.9-2-2-2s-2,0.9-2,2S8.4,5.5,9.5,5.5z M5.75,8.9L3.23,21.81C3.11,22.43,3.58,23,4.21,23H4.3 c0.47,0,0.88-0.33,0.98-0.79L6.85,15L9,17v5c0,0.55,0.45,1,1,1h0c0.55,0,1-0.45,1-1v-6.14c0-0.27-0.11-0.52-0.29-0.71L8.95,13.4 l0.6-3c1.07,1.32,2.58,2.23,4.31,2.51c0.6,0.1,1.14-0.39,1.14-1v0c0-0.49-0.36-0.9-0.84-0.98c-1.49-0.25-2.75-1.15-3.51-2.38 L9.7,6.95C9.35,6.35,8.7,6,8,6C7.75,6,7.5,6.05,7.25,6.15l-4.63,1.9C2.25,8.2,2,8.57,2,8.97V12c0,0.55,0.45,1,1,1h0 c0.55,0,1-0.45,1-1V9.65L5.75,8.9 M21,2h-7c-0.55,0-1,0.45-1,1v5c0,0.55,0.45,1,1,1h2.75v13.25c0,0.41,0.34,0.75,0.75,0.75 s0.75-0.34,0.75-0.75V9H21c0.55,0,1-0.45,1-1V3C22,2.45,21.55,2,21,2z M20.15,5.85l-1.28,1.29c-0.31,0.32-0.85,0.09-0.85-0.35V6.25 h-2.76c-0.41,0-0.75-0.34-0.75-0.75s0.34-0.75,0.75-0.75h2.76V4.21c0-0.45,0.54-0.67,0.85-0.35l1.28,1.29 C20.34,5.34,20.34,5.66,20.15,5.85z</Geometry>
<Geometry x:Key="DiscordIcon">M22,24L16.75,19L17.38,21H4.5A2.5,2.5 0 0,1 2,18.5V3.5A2.5,2.5 0 0,1 4.5,1H19.5A2.5,2.5 0 0,1 22,3.5V24M12,6.8C9.32,6.8 7.44,7.95 7.44,7.95C8.47,7.03 10.27,6.5 10.27,6.5L10.1,6.33C8.41,6.36 6.88,7.53 6.88,7.53C5.16,11.12 5.27,14.22 5.27,14.22C6.67,16.03 8.75,15.9 8.75,15.9L9.46,15C8.21,14.73 7.42,13.62 7.42,13.62C7.42,13.62 9.3,14.9 12,14.9C14.7,14.9 16.58,13.62 16.58,13.62C16.58,13.62 15.79,14.73 14.54,15L15.25,15.9C15.25,15.9 17.33,16.03 18.73,14.22C18.73,14.22 18.84,11.12 17.12,7.53C17.12,7.53 15.59,6.36 13.9,6.33L13.73,6.5C13.73,6.5 15.53,7.03 16.56,7.95C16.56,7.95 14.68,6.8 12,6.8M9.93,10.59C10.58,10.59 11.11,11.16 11.1,11.86C11.1,12.55 10.58,13.13 9.93,13.13C9.29,13.13 8.77,12.55 8.77,11.86C8.77,11.16 9.28,10.59 9.93,10.59M14.1,10.59C14.75,10.59 15.27,11.16 15.27,11.86C15.27,12.55 14.75,13.13 14.1,13.13C13.46,13.13 12.94,12.55 12.94,11.86C12.94,11.16 13.45,10.59 14.1,10.59Z</Geometry>
<Geometry x:Key="BugIcon">M14,12H10V10H14M14,16H10V14H14M20,8H17.19C16.74,7.22 16.12,6.55 15.37,6.04L17,4.41L15.59,3L13.42,5.17C12.96,5.06 12.5,5 12,5C11.5,5 11.04,5.06 10.59,5.17L8.41,3L7,4.41L8.62,6.04C7.88,6.55 7.26,7.22 6.81,8H4V10H6.09C6.04,10.33 6,10.66 6,11V12H4V14H6V15C6,15.34 6.04,15.67 6.09,16H4V18H6.81C7.85,19.79 9.78,21 12,21C14.22,21 16.15,19.79 17.19,18H20V16H17.91C17.96,15.67 18,15.34 18,15V14H20V12H18V11C18,10.66 17.96,10.33 17.91,10H20V8Z</Geometry>
<Geometry x:Key="GiftIcon">M22 10.92L19.26 9.33C21.9 7.08 19.25 2.88 16.08 4.31L15.21 4.68L15.1 3.72C15 2.64 14.44 1.87 13.7 1.42C12.06 .467 9.56 1.12 9.16 3.5L6.41 1.92C5.45 1.36 4.23 1.69 3.68 2.65L2.68 4.38C2.4 4.86 2.57 5.47 3.05 5.75L10.84 10.25L12.34 7.65L14.07 8.65L12.57 11.25L20.36 15.75C20.84 16 21.46 15.86 21.73 15.38L22.73 13.65C23.28 12.69 22.96 11.47 22 10.92M12.37 5C11.5 5.25 10.8 4.32 11.24 3.55C11.5 3.07 12.13 2.91 12.61 3.18C13.38 3.63 13.23 4.79 12.37 5M17.56 8C16.7 8.25 16 7.32 16.44 6.55C16.71 6.07 17.33 5.91 17.8 6.18C18.57 6.63 18.42 7.79 17.56 8M20.87 16.88C21.28 16.88 21.67 16.74 22 16.5V20C22 21.11 21.11 22 20 22H4C2.9 22 2 21.11 2 20V11H10.15L11 11.5V20H13V12.65L19.87 16.61C20.17 16.79 20.5 16.88 20.87 16.88Z</Geometry>
<Geometry x:Key="NoteIcon">M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM8 19h12c.55 0 1-.45 1-1s-.45-1-1-1H8c-.55 0-1 .45-1 1s.45 1 1 1zm0-6h12c.55 0 1-.45 1-1s-.45-1-1-1H8c-.55 0-1 .45-1 1s.45 1 1 1zM7 6c0 .55.45 1 1 1h12c.55 0 1-.45 1-1s-.45-1-1-1H8c-.55 0-1 .45-1 1z</Geometry>
<Geometry x:Key="InfoIcon">M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 15c-.55 0-1-.45-1-1v-4c0-.55.45-1 1-1s1 .45 1 1v4c0 .55-.45 1-1 1zm1-8h-2V7h2v2z</Geometry>
<Geometry x:Key="TrashIcon">M6,19c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2V7H6V19z M9.17,12.59c-0.39-0.39-0.39-1.02,0-1.41c0.39-0.39,1.02-0.39,1.41,0 L12,12.59l1.41-1.41c0.39-0.39,1.02-0.39,1.41,0s0.39,1.02,0,1.41L13.41,14l1.41,1.41c0.39,0.39,0.39,1.02,0,1.41 s-1.02,0.39-1.41,0L12,15.41l-1.41,1.41c-0.39,0.39-1.02,0.39-1.41,0c-0.39-0.39-0.39-1.02,0-1.41L10.59,14L9.17,12.59z M18,4h-2.5 l-0.71-0.71C14.61,3.11,14.35,3,14.09,3H9.91c-0.26,0-0.52,0.11-0.7,0.29L8.5,4H6C5.45,4,5,4.45,5,5s0.45,1,1,1h12 c0.55,0,1-0.45,1-1S18.55,4,18,4z</Geometry>
<Geometry x:Key="HomeIcon">M18,4v16H6V4H18 M18,2H6C4.9,2,4,2.9,4,4v16c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V4C20,2.9,19.1,2,18,2L18,2z M7,19h10v-6H7 V19z M10,10h4v1h3V5H7v6h3V10z</Geometry>
<Geometry x:Key="RegexIcon">M16,16.92C15.67,16.97 15.34,17 15,17C14.66,17 14.33,16.97 14,16.92V13.41L11.5,15.89C11,15.5 10.5,15 10.11,14.5L12.59,12H9.08C9.03,11.67 9,11.34 9,11C9,10.66 9.03,10.33 9.08,10H12.59L10.11,7.5C10.3,7.25 10.5,7 10.76,6.76V6.76C11,6.5 11.25,6.3 11.5,6.11L14,8.59V5.08C14.33,5.03 14.66,5 15,5C15.34,5 15.67,5.03 16,5.08V8.59L18.5,6.11C19,6.5 19.5,7 19.89,7.5L17.41,10H20.92C20.97,10.33 21,10.66 21,11C21,11.34 20.97,11.67 20.92,12H17.41L19.89,14.5C19.7,14.75 19.5,15 19.24,15.24V15.24C19,15.5 18.75,15.7 18.5,15.89L16,13.41V16.92H16V16.92M5,19A2,2 0 0,1 7,17A2,2 0 0,1 9,19A2,2 0 0,1 7,21A2,2 0 0,1 5,19H5Z</Geometry>
<Geometry x:Key="BackspaceIcon">M22,3H7C6.31,3 5.77,3.35 5.41,3.88L0,12L5.41,20.11C5.77,20.64 6.31,21 7,21H22A2,2 0 0,0 24,19V5A2,2 0 0,0 22,3M19,15.59L17.59,17L14,13.41L10.41,17L9,15.59L12.59,12L9,8.41L10.41,7L14,10.59L17.59,7L19,8.41L15.41,12</Geometry>
<Geometry x:Key="AudioIcon">M3 10v4c0 .55.45 1 1 1h3l3.29 3.29c.63.63 1.71.18 1.71-.71V6.41c0-.89-1.08-1.34-1.71-.71L7 9H4c-.55 0-1 .45-1 1zm13.5 2c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 4.45v.2c0 .38.25.71.6.85C17.18 6.53 19 9.06 19 12s-1.82 5.47-4.4 6.5c-.36.14-.6.47-.6.85v.2c0 .63.63 1.07 1.21.85C18.6 19.11 21 15.84 21 12s-2.4-7.11-5.79-8.4c-.58-.23-1.21.22-1.21.85z</Geometry>
<Geometry x:Key="MapIcon">M14.65 4.98l-5-1.75c-.42-.15-.88-.15-1.3-.01L4.36 4.56C3.55 4.84 3 5.6 3 6.46v11.85c0 1.41 1.41 2.37 2.72 1.86l2.93-1.14c.22-.09.47-.09.69-.01l5 1.75c.42.15.88.15 1.3.01l3.99-1.34c.81-.27 1.36-1.04 1.36-1.9V5.69c0-1.41-1.41-2.37-2.72-1.86l-2.93 1.14c-.22.08-.46.09-.69.01zM15 18.89l-6-2.11V5.11l6 2.11v11.67z</Geometry>
<Geometry x:Key="ChallengesIcon">M12.09 2.91C10.08.9 7.07.49 4.65 1.67L8.28 5.3c.39.39.39 1.02 0 1.41L6.69 8.3c-.39.4-1.02.4-1.41 0L1.65 4.67C.48 7.1.89 10.09 2.9 12.1c1.86 1.86 4.58 2.35 6.89 1.48l7.96 7.96c1.03 1.03 2.69 1.03 3.71 0 1.03-1.03 1.03-2.69 0-3.71L13.54 9.9c.92-2.34.44-5.1-1.45-6.99z</Geometry>
<Geometry x:Key="MatchCaseIcon">M2.5 5.5C2.5 6.33 3.17 7 4 7h3.5v10.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V7H14c.83 0 1.5-.67 1.5-1.5S14.83 4 14 4H4c-.83 0-1.5.67-1.5 1.5zM20 9h-6c-.83 0-1.5.67-1.5 1.5S13.17 12 14 12h1.5v5.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V12H20c.83 0 1.5-.67 1.5-1.5S20.83 9 20 9z</Geometry>
<Geometry x:Key="CreatorIcon">M21 13h-6c-.55 0-1-.45-1-1s.45-1 1-1h6c.55 0 1 .45 1 1s-.45 1-1 1zm0-6h-6c-.55 0-1 .45-1 1s.45 1 1 1h6c.55 0 1-.45 1-1s-.45-1-1-1zm-6 10h6c.55 0 1-.45 1-1s-.45-1-1-1h-6c-.55 0-1 .45-1 1s.45 1 1 1zm-3-8v6c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V9c0-1.1.9-2 2-2h6c1.1 0 2 .9 2 2zm-2.1 5.2l-1.26-1.68c-.2-.26-.59-.27-.8-.01L6.5 14.26l-.85-1.03c-.2-.25-.58-.24-.78.01l-.74.95c-.26.33-.02.81.39.81H9.5c.41 0 .65-.47.4-.8z</Geometry>
<Geometry x:Key="KeyboardIcon">M20 5H4c-1.1 0-1.99.9-1.99 2L2 17c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0 3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm8 7H9c-.55 0-1-.45-1-1s.45-1 1-1h6c.55 0 1 .45 1 1s-.45 1-1 1zm1-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z</Geometry>
<Geometry x:Key="SearchUpIcon">M2.7,17.29c0.39,0.39,1.02,0.39,1.41,0l4.59-4.59c0.39-0.39,1.02-0.39,1.41,0l1.17,1.17c1.17,1.17,3.07,1.17,4.24,0 l4.18-4.17l1.44,1.44c0.31,0.31,0.85,0.09,0.85-0.35V6.5C22,6.22,21.78,6,21.5,6h-4.29c-0.45,0-0.67,0.54-0.35,0.85l1.44,1.44 l-4.17,4.17c-0.39,0.39-1.02,0.39-1.41,0l-1.17-1.17c-1.17-1.17-3.07-1.17-4.24,0L2.7,15.88C2.32,16.27,2.32,16.91,2.7,17.29z</Geometry>
<Geometry x:Key="WholeWordIcon">M18 10v3H6v-3c0-.55-.45-1-1-1s-1 .45-1 1v4c0 .55.45 1 1 1h14c.55 0 1-.45 1-1v-4c0-.55-.45-1-1-1s-1 .45-1 1z</Geometry>
<Geometry x:Key="CloseIcon">M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm4.3 14.3c-.39.39-1.02.39-1.41 0L12 13.41 9.11 16.3c-.39.39-1.02.39-1.41 0-.39-.39-.39-1.02 0-1.41L10.59 12 7.7 9.11c-.39-.39-.39-1.02 0-1.41.39-.39 1.02-.39 1.41 0L12 10.59l2.89-2.89c.39-.39 1.02-.39 1.41 0 .39.39.39 1.02 0 1.41L13.41 12l2.89 2.89c.38.38.38 1.02 0 1.41z</Geometry>
<Geometry x:Key="PlayIcon">M8 6.82v10.36c0 .79.87 1.27 1.54.84l8.14-5.18c.62-.39.62-1.29 0-1.69L9.54 5.98C8.87 5.55 8 6.03 8 6.82z</Geometry>
<Geometry x:Key="PauseIcon">M8 19c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2s-2 .9-2 2v10c0 1.1.9 2 2 2zm6-12v10c0 1.1.9 2 2 2s2-.9 2-2V7c0-1.1-.9-2-2-2s-2 .9-2 2z</Geometry>
<Geometry x:Key="StopIcon">M8 6h8c1.1 0 2 .9 2 2v8c0 1.1-.9 2-2 2H8c-1.1 0-2-.9-2-2V8c0-1.1.9-2 2-2z</Geometry>
<Geometry x:Key="SkipNextIcon">M7.58 16.89l5.77-4.07c.56-.4.56-1.24 0-1.63L7.58 7.11C6.91 6.65 6 7.12 6 7.93v8.14c0 .81.91 1.28 1.58.82zM16 7v10c0 .55.45 1 1 1s1-.45 1-1V7c0-.55-.45-1-1-1s-1 .45-1 1z</Geometry>
<Geometry x:Key="SkipPreviousIcon">M7 6c.55 0 1 .45 1 1v10c0 .55-.45 1-1 1s-1-.45-1-1V7c0-.55.45-1 1-1zm3.66 6.82l5.77 4.07c.66.47 1.58-.01 1.58-.82V7.93c0-.81-.91-1.28-1.58-.82l-5.77 4.07c-.57.4-.57 1.24 0 1.64z</Geometry>
<Geometry x:Key="AddAudioIcon">M13 10H3c-.55 0-1 .45-1 1s.45 1 1 1h10c.55 0 1-.45 1-1s-.45-1-1-1zm0-4H3c-.55 0-1 .45-1 1s.45 1 1 1h10c.55 0 1-.45 1-1s-.45-1-1-1zm5 8v-3c0-.55-.45-1-1-1s-1 .45-1 1v3h-3c-.55 0-1 .45-1 1s.45 1 1 1h3v3c0 .55.45 1 1 1s1-.45 1-1v-3h3c.55 0 1-.45 1-1s-.45-1-1-1h-3zM3 16h6c.55 0 1-.45 1-1s-.45-1-1-1H3c-.55 0-1 .45-1 1s.45 1 1 1z</Geometry>
<Geometry x:Key="SavePlaylistIcon">M14 6H4c-.55 0-1 .45-1 1s.45 1 1 1h10c.55 0 1-.45 1-1s-.45-1-1-1zm0 4H4c-.55 0-1 .45-1 1s.45 1 1 1h10c.55 0 1-.45 1-1s-.45-1-1-1zM4 16h6c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1zM19 6c-1.1 0-2 .9-2 2v6.18c-.31-.11-.65-.18-1-.18-1.84 0-3.28 1.64-2.95 3.54.21 1.21 1.2 2.2 2.41 2.41 1.9.33 3.54-1.11 3.54-2.95V8h2c.55 0 1-.45 1-1s-.45-1-1-1h-2z</Geometry>
<Geometry x:Key="ImageMergerIcon">M10 12c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zM6 8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12-8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-4 8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm4-4c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-4-4c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-4-4c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z</Geometry>
<Geometry x:Key="GliderIcon">M12,17c-1.1,0-2-0.9-2-2s0.9-2,2-2s2,0.9,2,2S13.1,17,12,17z M17.95,14c-0.52,0-0.94,0.4-0.99,0.92 c-0.2,2.03-1.05,2.68-1.48,3.02C14.68,18.54,14,19,12,19s-2.68-0.46-3.48-1.06c-0.43-0.34-1.28-0.99-1.48-3.02 C6.99,14.4,6.57,14,6.05,14c-0.59,0-1.06,0.51-1,1.09c0.22,2.08,1.07,3.47,2.24,4.41c0.5,0.4,1.1,0.7,1.7,0.9L9,24h6v-3.6 c0.6-0.2,1.2-0.5,1.7-0.9c1.17-0.94,2.03-2.32,2.24-4.41C19.01,14.51,18.53,14,17.95,14z M12,0C5.92,0,1,1.9,1,4.25v3.49 C1,8.55,1.88,9,2.56,8.57C2.7,8.48,2.84,8.39,3,8.31L5,13h2l1.5-6.28C9.6,6.58,10.78,6.5,12,6.5s2.4,0.08,3.5,0.22L17,13h2l2-4.69 c0.16,0.09,0.3,0.17,0.44,0.26C22.12,9,23,8.55,23,7.74V4.25C23,1.9,18.08,0,12,0z M5.88,11.24L4.37,7.69 c0.75-0.28,1.6-0.52,2.53-0.71L5.88,11.24z M18.12,11.24L17.1,6.98c0.93,0.19,1.78,0.43,2.53,0.71L18.12,11.24z</Geometry>
<Geometry x:Key="AnchorIcon">M13,9V7.82C14.16,7.4,15,6.3,15,5c0-1.65-1.35-3-3-3S9,3.35,9,5c0,1.3,0.84,2.4,2,2.82V9H9c-0.55,0-1,0.45-1,1v0 c0,0.55,0.45,1,1,1h2v8.92c-2.22-0.33-4.59-1.68-5.55-3.37l1.14-1.14c0.22-0.22,0.19-0.57-0.05-0.75L3.8,12.6 C3.47,12.35,3,12.59,3,13v2c0,3.88,4.92,7,9,7s9-3.12,9-7v-2c0-0.41-0.47-0.65-0.8-0.4l-2.74,2.05c-0.24,0.18-0.27,0.54-0.05,0.75 l1.14,1.14c-0.96,1.69-3.33,3.04-5.55,3.37V11h2c0.55,0,1-0.45,1-1v0c0-0.55-0.45-1-1-1H13z M12,4c0.55,0,1,0.45,1,1s-0.45,1-1,1 s-1-0.45-1-1S11.45,4,12,4z</Geometry>
<Geometry x:Key="FoldIcon">M8.12 19.3c.39.39 1.02.39 1.41 0L12 16.83l2.47 2.47c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41l-3.17-3.17c-.39-.39-1.02-.39-1.41 0l-3.17 3.17c-.4.38-.4 1.02-.01 1.41zm7.76-14.6c-.39-.39-1.02-.39-1.41 0L12 7.17 9.53 4.7c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.03 0 1.42l3.17 3.17c.39.39 1.02.39 1.41 0l3.17-3.17c.4-.39.4-1.03.01-1.42z</Geometry>
<Geometry x:Key="UnfoldIcon">M12 5.83l2.46 2.46c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L12.7 3.7c-.39-.39-1.02-.39-1.41 0L8.12 6.88c-.39.39-.39 1.02 0 1.41.39.39 1.02.39 1.41 0L12 5.83zm0 12.34l-2.46-2.46c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.02 0 1.41l3.17 3.18c.39.39 1.02.39 1.41 0l3.17-3.17c.39-.39.39-1.02 0-1.41-.39-.39-1.02-.39-1.41 0L12 18.17z</Geometry>
<Geometry x:Key="LocateMeIcon">M11.71,17.99C8.53,17.84,6,15.22,6,12c0-3.31,2.69-6,6-6c3.22,0,5.84,2.53,5.99,5.71l-2.1-0.63C15.48,9.31,13.89,8,12,8 c-2.21,0-4,1.79-4,4c0,1.89,1.31,3.48,3.08,3.89L11.71,17.99z M22,12c0,0.3-0.01,0.6-0.04,0.9l-1.97-0.59C20,12.21,20,12.1,20,12 c0-4.42-3.58-8-8-8s-8,3.58-8,8s3.58,8,8,8c0.1,0,0.21,0,0.31-0.01l0.59,1.97C12.6,21.99,12.3,22,12,22C6.48,22,2,17.52,2,12 C2,6.48,6.48,2,12,2S22,6.48,22,12z M18.23,16.26l2.27-0.76c0.46-0.15,0.45-0.81-0.01-0.95l-7.6-2.28 c-0.38-0.11-0.74,0.24-0.62,0.62l2.28,7.6c0.14,0.47,0.8,0.48,0.95,0.01l0.76-2.27l3.91,3.91c0.2,0.2,0.51,0.2,0.71,0l1.27-1.27 c0.2-0.2,0.2-0.51,0-0.71L18.23,16.26z</Geometry>
<Geometry x:Key="MeshIcon">M1.8 6q-.525 0-.887-.35Q.55 5.3.55 4.8V4q0-1.425 1.012-2.438Q2.575.55 4 .55h.8q.5 0 .85.362.35.363.35.888 0 .5-.35.85T4.8 3H4q-.425 0-.712.287Q3 3.575 3 4v.8q0 .5-.35.85T1.8 6ZM4 23.45q-1.425 0-2.438-1.012Q.55 21.425.55 20v-.8q0-.5.363-.85.362-.35.887-.35.5 0 .85.35t.35.85v.8q0 .425.288.712Q3.575 21 4 21h.8q.5 0 .85.35t.35.85q0 .525-.35.887-.35.363-.85.363Zm15.2 0q-.5 0-.85-.363-.35-.362-.35-.887 0-.5.35-.85t.85-.35h.8q.425 0 .712-.288Q21 20.425 21 20v-.8q0-.5.35-.85t.85-.35q.525 0 .888.35.362.35.362.85v.8q0 1.425-1.012 2.438Q21.425 23.45 20 23.45ZM22.2 6q-.5 0-.85-.35T21 4.8V4q0-.425-.288-.713Q20.425 3 20 3h-.8q-.5 0-.85-.35T18 1.8q0-.525.35-.888.35-.362.85-.362h.8q1.425 0 2.438 1.012Q23.45 2.575 23.45 4v.8q0 .5-.362.85-.363.35-.888.35ZM12 17.35l1-.575v-4.1l3.55-2.075V9.425l-1-.575L12 10.925 8.45 8.85l-1 .575V10.6L11 12.675v4.1Zm-1.325 2.325-4.55-2.65q-.625-.35-.975-.963-.35-.612-.35-1.337V9.45q0-.725.35-1.337.35-.613.975-.963l4.55-2.65Q11.3 4.15 12 4.15t1.325.35l4.55 2.65q.625.35.975.963.35.612.35 1.337v5.275q0 .725-.35 1.337-.35.613-.975.963l-4.55 2.65q-.625.35-1.325.35t-1.325-.35Z</Geometry>
<Geometry x:Key="ArchiveIcon">M3.5 1.75v11.5c0 .09.048.173.126.217a.75.75 0 0 1-.752 1.298A1.748 1.748 0 0 1 2 13.25V1.75C2 .784 2.784 0 3.75 0h5.586c.464 0 .909.185 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v8.586A1.75 1.75 0 0 1 12.25 15h-.5a.75.75 0 0 1 0-1.5h.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177L9.513 1.573a.25.25 0 0 0-.177-.073H7.25a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5h-3a.25.25 0 0 0-.25.25Zm3.75 8.75h.5c.966 0 1.75.784 1.75 1.75v3a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1-.75-.75v-3c0-.966.784-1.75 1.75-1.75ZM6 5.25a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 6 5.25Zm.75 2.25h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM8 6.75A.75.75 0 0 1 8.75 6h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 8 6.75ZM8.75 3h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM8 9.75A.75.75 0 0 1 8.75 9h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 8 9.75Zm-1 2.5v2.25h1v-2.25a.25.25 0 0 0-.25-.25h-.5a.25.25 0 0 0-.25.25Z</Geometry>
<Geometry x:Key="GitHubIcon">M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z</Geometry>
<Geometry x:Key="SortIcon">M8 16H4l6 6V2H8zm6-11v17h2V8h4l-6-6z</Geometry>
<Style x:Key="TabItemFillSpace" TargetType="TabItem" BasedOn="{StaticResource {x:Type TabItem}}">
<Setter Property="Width">
<Setter.Value>
@ -199,7 +142,7 @@
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding CUE4Parse.GameDirectory.DirectoryFilesView.Count}" Value="0">
<DataTrigger Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}, FallbackValue=0}" Value="0">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
@ -257,7 +200,7 @@
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding AudioPlayer.AudioFilesView.Count}" Value="0">
<DataTrigger Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}, FallbackValue=0}" Value="0">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
@ -431,6 +374,7 @@
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="ContextMenu" Value="{StaticResource FolderContextMenu}" />
<Setter Property="controls:TreeViewItemBehavior.IsBroughtIntoViewWhenSelected" Value="True"/>
<Setter Property="Padding" Value="5 3" />
<Setter Property="Template">
@ -568,12 +512,12 @@
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding CUE4Parse.AssetsFolder.FoldersView.Count, FallbackValue=0}" Value="0">
<DataTrigger Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}, FallbackValue=0}" Value="0">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<TextBlock Text="No folder found in archives, make sure you loaded at least one" FontWeight="SemiBold" TextAlignment="Center"
<TextBlock Text="No folders found in archives, make sure you loaded at least one" FontWeight="SemiBold" TextAlignment="Center"
Foreground="{DynamicResource {x:Static adonisUi:Brushes.ErrorBrush}}" />
</Grid>
</ControlTemplate>
@ -586,6 +530,9 @@
<Style x:Key="AssetsListBox" TargetType="ListBox" BasedOn="{StaticResource {x:Type ListBox}}">
<Setter Property="ItemsSource" Value="{Binding SelectedItem.AssetsList.AssetsView, ElementName=AssetsFolderName, IsAsync=True}" />
<Setter Property="SelectionMode" Value="Extended" />
<Setter Property="ContextMenu" Value="{StaticResource FileContextMenu}" />
<Setter Property="VirtualizingPanel.IsVirtualizing" Value="True" />
<Setter Property="VirtualizingPanel.VirtualizationMode" Value="Recycling" />
<Setter Property="adonisExtensions:ScrollViewerExtension.VerticalScrollBarExpansionMode" Value="NeverExpand"/>
<Setter Property="adonisExtensions:ScrollViewerExtension.VerticalScrollBarPlacement" Value="Docked"/>
<Setter Property="adonisExtensions:ScrollViewerExtension.HorizontalScrollBarExpansionMode" Value="NeverExpand"/>
@ -601,19 +548,19 @@
<Image x:Name="ListImage" Source="/FModel;component/Resources/unknown_asset.png"
Width="16" Height="16" HorizontalAlignment="Center" Margin="0 0 3 0" />
<TextBlock Grid.Column="1" HorizontalAlignment="Left" Text="{Binding Name}" />
<TextBlock Grid.Column="1" HorizontalAlignment="Left" Text="{Binding Asset.Name}" />
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Extension}" Value="uasset">
<DataTrigger Binding="{Binding Asset.Extension}" Value="uasset">
<Setter TargetName="ListImage" Property="Source" Value="/FModel;component/Resources/asset.png" />
</DataTrigger>
<DataTrigger Binding="{Binding Extension}" Value="ini">
<DataTrigger Binding="{Binding Asset.Extension}" Value="ini">
<Setter TargetName="ListImage" Property="Source" Value="/FModel;component/Resources/asset_ini.png" />
</DataTrigger>
<DataTrigger Binding="{Binding Extension}" Value="png">
<DataTrigger Binding="{Binding Asset.Extension}" Value="png">
<Setter TargetName="ListImage" Property="Source" Value="/FModel;component/Resources/asset_png.png" />
</DataTrigger>
<DataTrigger Binding="{Binding Extension}" Value="psd">
<DataTrigger Binding="{Binding Asset.Extension}" Value="psd">
<Setter TargetName="ListImage" Property="Source" Value="/FModel;component/Resources/asset_psd.png" />
</DataTrigger>
</DataTemplate.Triggers>
@ -625,16 +572,18 @@
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Padding" Value="5 3" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="controls:ListBoxItemBehavior.IsBroughtIntoViewWhenSelected" Value="True" />
</Style>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItem.AssetsList.Assets.Count, ElementName=AssetsFolderName, FallbackValue=0}" Value="0">
<DataTrigger Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}, FallbackValue=0}" Value="0">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<TextBlock Text="No package found in folder" FontWeight="SemiBold" TextAlignment="Center"
<TextBlock Text="No packages found in folder" FontWeight="SemiBold" TextAlignment="Center"
Foreground="{DynamicResource {x:Static adonisUi:Brushes.ErrorBrush}}" />
</Grid>
</ControlTemplate>
@ -861,6 +810,28 @@
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="Find References" Command="{Binding TabCommand}" CommandParameter="Find_References">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource SearchIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
<MenuItem.IsEnabled>
<Binding Path="PlacementTarget.DataContext" RelativeSource="{RelativeSource AncestorType=ContextMenu}">
<Binding.Converter>
<converters:GameFileMeetsConditionConverter>
<converters:GameFileMeetsConditionConverter.Conditions>
<converters:GameFileIsUePackageCondition />
<converters:GameFileIsIoStoreCondition />
</converters:GameFileMeetsConditionConverter.Conditions>
</converters:GameFileMeetsConditionConverter>
</Binding.Converter>
</Binding>
</MenuItem.IsEnabled>
</MenuItem>
<Separator />
<MenuItem Command="{Binding TabCommand}" CommandParameter="Asset_Export_Data">
<MenuItem.Header>
<TextBlock Text="{Binding Entry.Extension, FallbackValue='Export Raw Data', StringFormat='Export Raw Data (.{0})'}" />
@ -1379,25 +1350,25 @@
<Setter.Value>
<ControlTemplate TargetType="{x:Type avalonedit:TextEditor}">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer
Focusable="False"
Name="PART_ScrollViewer"
CanContentScroll="True"
VerticalScrollBarVisibility="{TemplateBinding VerticalScrollBarVisibility}"
HorizontalScrollBarVisibility="{TemplateBinding HorizontalScrollBarVisibility}"
Content="{Binding TextArea, RelativeSource={RelativeSource TemplatedParent}}"
VerticalContentAlignment="Top"
HorizontalContentAlignment="Left"
Padding="{TemplateBinding Padding}"
Focusable="False"
Name="PART_ScrollViewer"
CanContentScroll="True"
VerticalScrollBarVisibility="{TemplateBinding VerticalScrollBarVisibility}"
HorizontalScrollBarVisibility="{TemplateBinding HorizontalScrollBarVisibility}"
Content="{Binding TextArea, RelativeSource={RelativeSource TemplatedParent}}"
VerticalContentAlignment="Top"
HorizontalContentAlignment="Left"
Padding="{TemplateBinding Padding}"
controls:CustomScrollViewer.VerticalOffset="{Binding ScrollPosition}"
adonisExtensions:ScrollViewerExtension.VerticalScrollBarExpansionMode="ExpandOnHover"
adonisExtensions:ScrollViewerExtension.VerticalScrollBarPlacement="Docked"
adonisExtensions:ScrollViewerExtension.HorizontalScrollBarExpansionMode="NeverExpand"
adonisExtensions:ScrollViewerExtension.HorizontalScrollBarPlacement="Docked"
/>
/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="WordWrap" Value="True">
@ -1961,4 +1932,48 @@
<Setter Property="SelectedFoldingMarkerBackgroundBrush" Value="#2A2B34" />
</Style>
<DropShadowEffect x:Key="ShadowEffect"
Color="Black"
BlurRadius="6"
ShadowDepth="0"
Opacity="0.3" />
<Style x:Key="ModernToggleButtonStyle"
TargetType="ToggleButton">
<Setter Property="Background"
Value="{DynamicResource {x:Static adonisUi:Brushes.Layer1BackgroundBrush}}" />
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static adonisUi:Brushes.Layer3BackgroundBrush}}" />
<Setter Property="BorderThickness"
Value="1" />
<Setter Property="Padding"
Value="4" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="8"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter Property="Background"
Value="{DynamicResource {x:Static adonisUi:Brushes.AccentBrush}}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background"
Value="{DynamicResource {x:Static adonisUi:Brushes.Layer3BackgroundBrush}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,9 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using CUE4Parse.FileProvider.Objects;
using FModel.Services;
@ -8,61 +11,167 @@ using FModel.ViewModels;
namespace FModel.Views;
public enum ESearchViewTab
{
SearchView,
RefView
}
public partial class SearchView
{
private ThreadWorkerViewModel _threadWorkerView => ApplicationService.ThreadWorkerView;
private ApplicationViewModel _applicationView => ApplicationService.ApplicationView;
private SearchViewModel _searchViewModel => _applicationView.CUE4Parse.SearchVm;
private SearchViewModel _refViewModel => _applicationView.CUE4Parse.RefVm;
private ESearchViewTab _currentTab = ESearchViewTab.SearchView;
public SearchView()
{
DataContext = _applicationView;
DataContext = new
{
mainApplication = _applicationView,
SearchTab = _searchViewModel,
RefTab = _refViewModel,
};
InitializeComponent();
Activate();
WpfSuckMyDick.Focus();
WpfSuckMyDick.SelectAll();
SearchTextBox.Focus();
SearchTextBox.SelectAll();
}
public void FocusTab(ESearchViewTab view)
{
if (_currentTab == view)
return;
_currentTab = view;
SearchTabControl.SelectedIndex = view switch
{
ESearchViewTab.SearchView => 0,
ESearchViewTab.RefView => 1,
_ => SearchTabControl.SelectedIndex
};
CurrentTextBox?.Focus();
CurrentTextBox?.SelectAll();
}
public void ChangeCollection(ESearchViewTab view, IEnumerable<GameFile> files, GameFile refFile)
{
var vm = view switch
{
ESearchViewTab.SearchView => _searchViewModel,
ESearchViewTab.RefView => _refViewModel,
_ => null
};
vm?.ChangeCollection(files, refFile);
}
private async void OnFindRefs(object sender, RoutedEventArgs e)
{
if (CurrentListView?.SelectedItem is not GameFile entry)
return;
await _threadWorkerView.Begin(_ => _applicationView.CUE4Parse.FindReferences(entry));
}
private void OnTabItemChange(object sender, SelectionChangedEventArgs e)
{
if (e.OriginalSource is not TabControl tabControl)
return;
_currentTab = tabControl.SelectedIndex switch
{
0 => ESearchViewTab.SearchView,
1 => ESearchViewTab.RefView,
_ => _currentTab
};
CurrentTextBox?.Focus();
CurrentTextBox?.SelectAll();
}
private void OnDeleteSearchClick(object sender, RoutedEventArgs e)
{
_applicationView.CUE4Parse.SearchVm.FilterText = string.Empty;
_applicationView.CUE4Parse.SearchVm.RefreshFilter();
var viewModel = CurrentViewModel;
if (viewModel == null)
return;
viewModel.FilterText = string.Empty;
viewModel.RefreshFilter();
}
private async void OnSortClick(object sender, RoutedEventArgs e)
private SearchViewModel CurrentViewModel => _currentTab switch
{
await _applicationView.CUE4Parse.SearchVm.CycleSortSizeMode();
ESearchViewTab.SearchView => _applicationView.CUE4Parse.SearchVm,
ESearchViewTab.RefView => _applicationView.CUE4Parse.RefVm,
_ => null
};
private ListView CurrentListView => _currentTab switch
{
ESearchViewTab.SearchView => SearchListView,
ESearchViewTab.RefView => RefListView,
_ => null
};
private TextBox CurrentTextBox => _currentTab switch
{
ESearchViewTab.SearchView => SearchTextBox,
ESearchViewTab.RefView => RefSearchTextBox,
_ => null
};
private async void OnSearchSortClick(object sender, RoutedEventArgs e)
{
await CurrentViewModel?.CycleSortSizeMode();
}
private async void OnAssetDoubleClick(object sender, RoutedEventArgs e)
{
if (SearchListView.SelectedItem is not GameFile entry)
if (CurrentListView?.SelectedItem is not GameFile entry)
return;
await NavigateToAssetAndSelect(entry);
}
private async void OnGoToRefPackage(object sender, RoutedEventArgs e)
{
if (_refViewModel.RefFile is not GameFile entry)
return;
await NavigateToAssetAndSelect(entry);
}
private async Task NavigateToAssetAndSelect(GameFile entry)
{
WindowState = WindowState.Minimized;
MainWindow.YesWeCats.AssetsListName.ItemsSource = null;
var folder = _applicationView.CustomDirectories.GoToCommand.JumpTo(entry.Directory);
if (folder == null) return;
if (folder == null)
return;
MainWindow.YesWeCats.Activate();
do { await Task.Delay(100); } while (MainWindow.YesWeCats.AssetsListName.Items.Count < folder.AssetsList.Assets.Count);
do
{ await Task.Delay(100); } while (MainWindow.YesWeCats.AssetsListName.Items.Count < folder.AssetsList.Assets.Count);
while (!folder.IsSelected || MainWindow.YesWeCats.AssetsFolderName.SelectedItem != folder)
await Task.Delay(50); // stops assets tab from opening too early
MainWindow.YesWeCats.LeftTabControl.SelectedIndex = 2; // assets tab
ApplicationService.ApplicationView.SelectedLeftTabIndex = 2; // assets tab
do
{
await Task.Delay(100);
MainWindow.YesWeCats.AssetsListName.SelectedItem = entry;
MainWindow.YesWeCats.AssetsListName.ScrollIntoView(entry);
var vm = MainWindow.YesWeCats.AssetsListName.Items
.OfType<GameFileViewModel>()
.FirstOrDefault(x => x.Asset == entry);
MainWindow.YesWeCats.AssetsListName.SelectedItem = vm;
MainWindow.YesWeCats.AssetsListName.ScrollIntoView(vm);
} while (MainWindow.YesWeCats.AssetsListName.SelectedItem == null);
}
private async void OnAssetExtract(object sender, RoutedEventArgs e)
{
if (SearchListView.SelectedItem is not GameFile entry)
if (CurrentListView?.SelectedItem is not GameFile entry)
return;
WindowState = WindowState.Minimized;
@ -73,8 +182,9 @@ public partial class SearchView
private void OnWindowKeyDown(object sender, KeyEventArgs e)
{
if (e.Key != Key.Enter) return;
_applicationView.CUE4Parse.SearchVm.RefreshFilter();
if (e.Key != Key.Enter)
return;
CurrentViewModel?.RefreshFilter();
}
private void OnStateChanged(object sender, EventArgs e)
@ -83,8 +193,8 @@ public partial class SearchView
{
case WindowState.Normal:
Activate();
WpfSuckMyDick.Focus();
WpfSuckMyDick.SelectAll();
CurrentTextBox?.Focus();
CurrentTextBox?.SelectAll();
return;
}
}

View File

@ -18,10 +18,6 @@
</adonisControls:AdonisWindow.Style>
<adonisControls:AdonisWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
<controls:OnTagDataTemplateSelector x:Key="TagTemplateSelector" />
<DataTemplate x:Key="GeneralTemplate">
<Grid adonisExtensions:LayerExtension.Layer="2">
@ -544,6 +540,7 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@ -560,32 +557,35 @@
<Separator Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" Style="{StaticResource CustomSeparator}" />
<TextBlock Grid.Row="3" Grid.Column="0" Text="Left Switch on Asset Tab" VerticalAlignment="Center" Margin="0 0 0 5" />
<TextBlock Grid.Row="3" Grid.Column="0" Text="Switch Asset Explorer" VerticalAlignment="Center" Margin="0 0 0 5" />
<controls:HotkeyTextBox Grid.Row="3" Grid.Column="2" Style="{StaticResource TextBoxDefaultStyle}" Margin="0 0 0 5"
HotKey="{Binding AssetLeftTab, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
<TextBlock Grid.Row="4" Grid.Column="0" Text="Right Switch on Asset Tab" VerticalAlignment="Center" Margin="0 0 0 5" />
HotKey="{Binding SwitchAssetExplorer, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
<TextBlock Grid.Row="4" Grid.Column="0" Text="Left Switch on Asset Tab" VerticalAlignment="Center" Margin="0 0 0 5" />
<controls:HotkeyTextBox Grid.Row="4" Grid.Column="2" Style="{StaticResource TextBoxDefaultStyle}" Margin="0 0 0 5"
HotKey="{Binding AssetRightTab, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
<TextBlock Grid.Row="5" Grid.Column="0" Text="Add Asset Tab" VerticalAlignment="Center" Margin="0 0 0 5" />
HotKey="{Binding AssetLeftTab, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
<TextBlock Grid.Row="5" Grid.Column="0" Text="Right Switch on Asset Tab" VerticalAlignment="Center" Margin="0 0 0 5" />
<controls:HotkeyTextBox Grid.Row="5" Grid.Column="2" Style="{StaticResource TextBoxDefaultStyle}" Margin="0 0 0 5"
HotKey="{Binding AssetRightTab, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
<TextBlock Grid.Row="6" Grid.Column="0" Text="Add Asset Tab" VerticalAlignment="Center" Margin="0 0 0 5" />
<controls:HotkeyTextBox Grid.Row="6" Grid.Column="2" Style="{StaticResource TextBoxDefaultStyle}" Margin="0 0 0 5"
HotKey="{Binding AssetAddTab, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
<TextBlock Grid.Row="6" Grid.Column="0" Text="Remove Selected Asset Tab" VerticalAlignment="Center" />
<controls:HotkeyTextBox Grid.Row="6" Grid.Column="2" Style="{StaticResource TextBoxDefaultStyle}"
<TextBlock Grid.Row="7" Grid.Column="0" Text="Remove Selected Asset Tab" VerticalAlignment="Center" />
<controls:HotkeyTextBox Grid.Row="7" Grid.Column="2" Style="{StaticResource TextBoxDefaultStyle}"
HotKey="{Binding AssetRemoveTab, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
<Separator Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="3" Style="{StaticResource CustomSeparator}" />
<Separator Grid.Row="8" Grid.Column="0" Grid.ColumnSpan="3" Style="{StaticResource CustomSeparator}" />
<TextBlock Grid.Row="8" Grid.Column="0" Text="Add Audio File" VerticalAlignment="Center" Margin="0 0 0 5" />
<controls:HotkeyTextBox Grid.Row="8" Grid.Column="2" Style="{StaticResource TextBoxDefaultStyle}" Margin="0 0 0 5"
HotKey="{Binding AddAudio, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
<TextBlock Grid.Row="9" Grid.Column="0" Text="Play / Pause Current Audio" VerticalAlignment="Center" Margin="0 0 0 5" />
<TextBlock Grid.Row="9" Grid.Column="0" Text="Add Audio File" VerticalAlignment="Center" Margin="0 0 0 5" />
<controls:HotkeyTextBox Grid.Row="9" Grid.Column="2" Style="{StaticResource TextBoxDefaultStyle}" Margin="0 0 0 5"
HotKey="{Binding PlayPauseAudio, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
<TextBlock Grid.Row="10" Grid.Column="0" Text="Previous Audio" VerticalAlignment="Center" Margin="0 0 0 5" />
HotKey="{Binding AddAudio, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
<TextBlock Grid.Row="10" Grid.Column="0" Text="Play / Pause Current Audio" VerticalAlignment="Center" Margin="0 0 0 5" />
<controls:HotkeyTextBox Grid.Row="10" Grid.Column="2" Style="{StaticResource TextBoxDefaultStyle}" Margin="0 0 0 5"
HotKey="{Binding PreviousAudio, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
<TextBlock Grid.Row="11" Grid.Column="0" Text="Next Audio" VerticalAlignment="Center" Margin="0 0 0 5" />
HotKey="{Binding PlayPauseAudio, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
<TextBlock Grid.Row="11" Grid.Column="0" Text="Previous Audio" VerticalAlignment="Center" Margin="0 0 0 5" />
<controls:HotkeyTextBox Grid.Row="11" Grid.Column="2" Style="{StaticResource TextBoxDefaultStyle}" Margin="0 0 0 5"
HotKey="{Binding PreviousAudio, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
<TextBlock Grid.Row="12" Grid.Column="0" Text="Next Audio" VerticalAlignment="Center" Margin="0 0 0 5" />
<controls:HotkeyTextBox Grid.Row="12" Grid.Column="2" Style="{StaticResource TextBoxDefaultStyle}" Margin="0 0 0 5"
HotKey="{Binding NextAudio, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
</Grid>
</DataTemplate>

View File

@ -15,13 +15,6 @@
<Setter Property="Title" Value="Releases" />
</Style>
</adonisControls:AdonisWindow.Style>
<adonisControls:AdonisWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</adonisControls:AdonisWindow.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
@ -76,7 +69,7 @@
<Separator Grid.Row="2" Style="{StaticResource CustomSeparator}" Tag="History" />
<ScrollViewer Grid.Row="3" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<ItemsControl ItemsSource="{Binding CommitsView}">
<ItemsControl ItemsSource="{Binding CommitsView, IsAsync=True}">
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
@ -107,6 +100,24 @@
<controls:CommitControl Margin="0 0 0 1" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Style>
<Style TargetType="ItemsControl" BasedOn="{StaticResource {x:Type ItemsControl}}">
<Style.Triggers>
<DataTrigger Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}, FallbackValue=0}" Value="0">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<TextBlock Text="No commits found" FontWeight="SemiBold" TextAlignment="Center"
Foreground="{DynamicResource {x:Static adonisUi:Brushes.ErrorBrush}}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsControl.Style>
</ItemsControl>
</ScrollViewer>
</Grid>

View File

@ -12,10 +12,10 @@ public partial class UpdateView
InitializeComponent();
}
private async void OnLoaded(object sender, RoutedEventArgs e)
private void OnLoaded(object sender, RoutedEventArgs e)
{
if (DataContext is not UpdateViewModel viewModel) return;
await viewModel.Load();
_ = viewModel.LoadAsync();
}
private void OnDownloadLatest(object sender, RoutedEventArgs e)
@ -24,4 +24,3 @@ public partial class UpdateView
viewModel.DownloadLatest();
}
}

1
NOTICE
View File

@ -18,6 +18,7 @@ This software includes material developed by the following third-party libraries
- Serilog (https://github.com/serilog/serilog/blob/dev/LICENSE) - Copyright 2013-2015 Serilog Contributors. Licensed under the Apache License 2.0.
- SixLabors.ImageSharp (https://github.com/SixLabors/ImageSharp/blob/main/LICENSE) - Copyright (c) Six Labors. Licensed under the Apache License 2.0.
- SkiaSharp (https://github.com/mono/SkiaSharp/blob/main/LICENSE.md) - Copyright (c) 2015-2016 Xamarin, Inc. & 2017-2018 Microsoft Corporation. Licensed under the MIT License.
- VirtualizingWrapPanel (https://github.com/sbaeumlisberger/VirtualizingWrapPanel/blob/master/LICENSE) - Copyright (c) 2019 S. Bäumlisberger. Licensed under the MIT License.
---------------------------------------------------------------------------