Browse Source

Add TreeFileExplorer control

pull/495/head
Ionite 9 months ago
parent
commit
c3022320bf
No known key found for this signature in database
  1. 1
      StabilityMatrix.Avalonia/App.axaml
  2. 65
      StabilityMatrix.Avalonia/Controls/TreeFileExplorer.axaml
  3. 135
      StabilityMatrix.Avalonia/Controls/TreeFileExplorer.axaml.cs
  4. 2
      StabilityMatrix.Avalonia/DesignData/DesignData.cs
  5. 50
      StabilityMatrix.Avalonia/Models/TreeFileExplorer/TreeFileExplorerDirectory.cs
  6. 6
      StabilityMatrix.Avalonia/Models/TreeFileExplorer/TreeFileExplorerFile.cs
  7. 10
      StabilityMatrix.Avalonia/Models/TreeFileExplorer/TreeFileExplorerItem.cs
  8. 15
      StabilityMatrix.Avalonia/Models/TreeFileExplorer/TreeFileExplorerOptions.cs
  9. 8
      StabilityMatrix.Avalonia/Models/TreeFileExplorer/TreeFileExplorerType.cs

1
StabilityMatrix.Avalonia/App.axaml

@ -63,6 +63,7 @@
<StyleInclude Source="Controls/StarsRating.axaml"/>
<StyleInclude Source="Controls/VideoGenerationSettingsCard.axaml"/>
<StyleInclude Source="Controls/VideoOutputSettingsCard.axaml"/>
<StyleInclude Source="Controls/TreeFileExplorer.axaml"/>
<StyleInclude Source="Controls/Inference/StackCard.axaml"/>
<StyleInclude Source="Controls/Inference/StackEditableCard.axaml"/>
<StyleInclude Source="Controls/Inference/StackExpander.axaml"/>

65
StabilityMatrix.Avalonia/Controls/TreeFileExplorer.axaml

@ -0,0 +1,65 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:StabilityMatrix.Avalonia.Controls"
xmlns:system="using:System"
xmlns:treeFileExplorer="clr-namespace:StabilityMatrix.Avalonia.Models.TreeFileExplorer"
xmlns:mock="clr-namespace:StabilityMatrix.Avalonia.DesignData"
xmlns:sg="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia"
xmlns:fluentIcons="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent">
<Design.PreviewWith>
<StackPanel Spacing="16">
<Panel Height="300" Margin="4">
<controls:TreeFileExplorer
RootPath="{x:Static mock:DesignData.CurrentDirectory}" />
</Panel>
<Panel Height="300" Margin="4">
<controls:TreeFileExplorer
IndexFiles="False"
CanSelectFiles="False"
RootPath="{x:Static mock:DesignData.CurrentDirectory}" />
</Panel>
</StackPanel>
</Design.PreviewWith>
<Style Selector="controls|TreeFileExplorer">
<!-- Set Defaults -->
<Setter Property="Template">
<ControlTemplate>
<Grid>
<TreeView
ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RootItem.Children}">
<TreeView.DataTemplates>
<DataTemplate
DataType="treeFileExplorer:TreeFileExplorerFile">
<sg:SpacedGrid ColumnDefinitions="Auto,*" RowSpacing="0" ColumnSpacing="4">
<fluentIcons:SymbolIcon
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Symbol="Document" />
<TextBlock
Grid.Column="1"
Text="{Binding Path.Name}" />
</sg:SpacedGrid>
</DataTemplate>
<TreeDataTemplate
DataType="treeFileExplorer:TreeFileExplorerDirectory"
ItemsSource="{Binding Children}">
<sg:SpacedGrid ColumnDefinitions="Auto,*" RowSpacing="0" ColumnSpacing="4">
<fluentIcons:SymbolIcon
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
IsFilled="True"
Symbol="Folder" />
<TextBlock
Grid.Column="1"
Text="{Binding Path.Name}" />
</sg:SpacedGrid>
</TreeDataTemplate>
</TreeView.DataTemplates>
</TreeView>
</Grid>
</ControlTemplate>
</Setter>
</Style>
</Styles>

135
StabilityMatrix.Avalonia/Controls/TreeFileExplorer.axaml.cs

@ -0,0 +1,135 @@
using Avalonia;
using Avalonia.Controls.Primitives;
using StabilityMatrix.Avalonia.Models.TreeFileExplorer;
using StabilityMatrix.Core.Models.FileInterfaces;
namespace StabilityMatrix.Avalonia.Controls;
public class TreeFileExplorer : TemplatedControl
{
public static readonly StyledProperty<TreeFileExplorerDirectory?> RootItemProperty =
AvaloniaProperty.Register<TreeFileExplorer, TreeFileExplorerDirectory?>("RootItem");
public TreeFileExplorerDirectory? RootItem
{
get => GetValue(RootItemProperty);
set => SetValue(RootItemProperty, value);
}
public static readonly StyledProperty<string?> RootPathProperty = AvaloniaProperty.Register<
TreeFileExplorer,
string?
>("RootPath");
public string? RootPath
{
get => GetValue(RootPathProperty);
set => SetValue(RootPathProperty, value);
}
public static readonly StyledProperty<IPathObject?> SelectedPathProperty = AvaloniaProperty.Register<
TreeFileExplorer,
IPathObject?
>("SelectedPath");
public IPathObject? SelectedPath
{
get => GetValue(SelectedPathProperty);
set => SetValue(SelectedPathProperty, value);
}
public static readonly StyledProperty<bool> CanSelectFilesProperty = AvaloniaProperty.Register<
TreeFileExplorer,
bool
>("CanSelectFiles", true);
public bool CanSelectFiles
{
get => GetValue(CanSelectFilesProperty);
set => SetValue(CanSelectFilesProperty, value);
}
public static readonly StyledProperty<bool> CanSelectFoldersProperty = AvaloniaProperty.Register<
TreeFileExplorer,
bool
>("CanSelectFolders", true);
public bool CanSelectFolders
{
get => GetValue(CanSelectFoldersProperty);
set => SetValue(CanSelectFoldersProperty, value);
}
public static readonly StyledProperty<bool> IndexFilesProperty = AvaloniaProperty.Register<
TreeFileExplorer,
bool
>("IndexFiles", true);
public bool IndexFiles
{
get => GetValue(IndexFilesProperty);
set => SetValue(IndexFilesProperty, value);
}
public static readonly StyledProperty<bool> IndexFoldersProperty = AvaloniaProperty.Register<
TreeFileExplorer,
bool
>("IndexFolders", true);
public bool IndexFolders
{
get => GetValue(IndexFoldersProperty);
set => SetValue(IndexFoldersProperty, value);
}
private TreeFileExplorerOptions GetOptions()
{
var options = TreeFileExplorerOptions.None;
if (CanSelectFiles)
{
options |= TreeFileExplorerOptions.CanSelectFiles;
}
if (CanSelectFolders)
{
options |= TreeFileExplorerOptions.CanSelectFolders;
}
if (IndexFiles)
{
options |= TreeFileExplorerOptions.IndexFiles;
}
if (IndexFolders)
{
options |= TreeFileExplorerOptions.IndexFolders;
}
return options;
}
/// <inheritdoc />
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
if (RootItem is null)
{
RootItem = RootPath is null
? null
: new TreeFileExplorerDirectory(new DirectoryPath(RootPath), GetOptions());
}
}
/// <inheritdoc />
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == RootPathProperty)
{
var path = change.GetNewValue<string?>();
RootItem = path is null
? null
: new TreeFileExplorerDirectory(new DirectoryPath(path), GetOptions());
}
}
}

2
StabilityMatrix.Avalonia/DesignData/DesignData.cs

@ -1008,6 +1008,8 @@ The gallery images are often inpainted, but you will get something very similar
public static ControlNetCardViewModel ControlNetCardViewModel =>
DialogFactory.Get<ControlNetCardViewModel>();
public static string CurrentDirectory => Directory.GetCurrentDirectory();
public static Indexer Types { get; } = new();
public class Indexer

50
StabilityMatrix.Avalonia/Models/TreeFileExplorer/TreeFileExplorerDirectory.cs

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using StabilityMatrix.Core.Models.FileInterfaces;
namespace StabilityMatrix.Avalonia.Models.TreeFileExplorer;
public class TreeFileExplorerDirectory(IPathObject path, TreeFileExplorerOptions options)
: TreeFileExplorerItem(path, options)
{
public IEnumerable<TreeFileExplorerItem> Children =>
GetChildren(Path, Options)
.OrderByDescending(item => item.Path is DirectoryPath)
.ThenBy(item => item.Path.Name);
private static IEnumerable<TreeFileExplorerItem> GetChildren(
IPathObject pathObject,
TreeFileExplorerOptions options
)
{
return pathObject switch
{
FilePath => Enumerable.Empty<TreeFileExplorerItem>(),
DirectoryPath directoryPath => GetChildren(directoryPath, options),
_ => throw new NotSupportedException()
};
}
private static IEnumerable<TreeFileExplorerItem> GetChildren(
DirectoryPath directoryPath,
TreeFileExplorerOptions options
)
{
if (options.HasFlag(TreeFileExplorerOptions.IndexFiles))
{
foreach (var file in directoryPath.EnumerateFiles())
{
yield return new TreeFileExplorerFile(file, options);
}
}
if (options.HasFlag(TreeFileExplorerOptions.IndexFolders))
{
foreach (var directory in directoryPath.EnumerateDirectories())
{
yield return new TreeFileExplorerDirectory(directory, options);
}
}
}
}

6
StabilityMatrix.Avalonia/Models/TreeFileExplorer/TreeFileExplorerFile.cs

@ -0,0 +1,6 @@
using StabilityMatrix.Core.Models.FileInterfaces;
namespace StabilityMatrix.Avalonia.Models.TreeFileExplorer;
public class TreeFileExplorerFile(IPathObject path, TreeFileExplorerOptions options)
: TreeFileExplorerItem(path, options);

10
StabilityMatrix.Avalonia/Models/TreeFileExplorer/TreeFileExplorerItem.cs

@ -0,0 +1,10 @@
using StabilityMatrix.Core.Models.FileInterfaces;
namespace StabilityMatrix.Avalonia.Models.TreeFileExplorer;
public class TreeFileExplorerItem(IPathObject path, TreeFileExplorerOptions options)
{
public IPathObject Path { get; } = path;
public TreeFileExplorerOptions Options { get; } = options;
}

15
StabilityMatrix.Avalonia/Models/TreeFileExplorer/TreeFileExplorerOptions.cs

@ -0,0 +1,15 @@
using System;
namespace StabilityMatrix.Avalonia.Models.TreeFileExplorer;
[Flags]
public enum TreeFileExplorerOptions
{
None = 0,
IndexFiles = 1 << 5,
IndexFolders = 1 << 6,
CanSelectFiles = 1 << 10,
CanSelectFolders = 1 << 11,
}

8
StabilityMatrix.Avalonia/Models/TreeFileExplorer/TreeFileExplorerType.cs

@ -0,0 +1,8 @@
namespace StabilityMatrix.Avalonia.Models.TreeFileExplorer;
public enum TreeFileExplorerType
{
None,
File,
Directory
}
Loading…
Cancel
Save