Browse Source

Added selectable image button control for Outputs page & beyond

pull/240/head
JT 1 year ago
parent
commit
d3d10be753
  1. 1
      StabilityMatrix.Avalonia/App.axaml
  2. 51
      StabilityMatrix.Avalonia/Controls/SelectableImageCard/SelectableImageButton.axaml
  3. 25
      StabilityMatrix.Avalonia/Controls/SelectableImageCard/SelectableImageButton.cs
  4. 26
      StabilityMatrix.Avalonia/DesignData/DesignData.cs
  5. 18
      StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
  6. 6
      StabilityMatrix.Avalonia/Languages/Resources.resx
  7. 19
      StabilityMatrix.Avalonia/ViewModels/OutputsPage/OutputImageViewModel.cs
  8. 74
      StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
  9. 78
      StabilityMatrix.Avalonia/Views/OutputsPage.axaml

1
StabilityMatrix.Avalonia/App.axaml

@ -60,6 +60,7 @@
<StyleInclude Source="Controls/SharpenCard.axaml"/> <StyleInclude Source="Controls/SharpenCard.axaml"/>
<StyleInclude Source="Controls/FreeUCard.axaml"/> <StyleInclude Source="Controls/FreeUCard.axaml"/>
<StyleInclude Source="Controls/Paginator.axaml"/> <StyleInclude Source="Controls/Paginator.axaml"/>
<StyleInclude Source="Controls/SelectableImageCard/SelectableImageButton.axaml"/>
<Style Selector="DockControl"> <Style Selector="DockControl">
<Setter Property="(DockProperties.ControlRecycling)" Value="{StaticResource ControlRecyclingKey}" /> <Setter Property="(DockProperties.ControlRecycling)" Value="{StaticResource ControlRecyclingKey}" />

51
StabilityMatrix.Avalonia/Controls/SelectableImageCard/SelectableImageButton.axaml

@ -0,0 +1,51 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:selectableImageCard="clr-namespace:StabilityMatrix.Avalonia.Controls.SelectableImageCard"
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls">
<Design.PreviewWith>
<Border Padding="20">
<!-- Add Controls for Previewer Here -->
<selectableImageCard:SelectableImageButton
Source="https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/78fd2a0a-42b6-42b0-9815-81cb11bb3d05/00009-2423234823.jpeg" />
</Border>
</Design.PreviewWith>
<!-- Add Styles Here -->
<Style Selector="selectableImageCard|SelectableImageButton">
<Setter Property="Template">
<ControlTemplate>
<Grid>
<CheckBox VerticalAlignment="Top"
HorizontalAlignment="Right"
Margin="14,8"
Padding="0"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
ZIndex="100">
<CheckBox.RenderTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5" />
</CheckBox.RenderTransform>
<CheckBox.Styles>
<Style Selector="CheckBox">
<Setter Property="CornerRadius" Value="16" />
</Style>
</CheckBox.Styles>
</CheckBox>
<Button
Margin="0"
Padding="4"
CornerRadius="12"
Command="{TemplateBinding Command}"
CommandParameter="{TemplateBinding CommandParameter}">
<controls:BetterAdvancedImage
Width="300"
Height="300"
Stretch="UniformToFill"
CornerRadius="8"
ContextFlyout="{TemplateBinding ContextFlyout}"
Source="{TemplateBinding Source}" />
</Button>
</Grid>
</ControlTemplate>
</Setter>
</Style>
</Styles>

25
StabilityMatrix.Avalonia/Controls/SelectableImageCard/SelectableImageButton.cs

@ -0,0 +1,25 @@
using Avalonia;
using Avalonia.Controls;
namespace StabilityMatrix.Avalonia.Controls.SelectableImageCard;
public class SelectableImageButton : Button
{
public static readonly StyledProperty<bool?> IsSelectedProperty =
CheckBox.IsCheckedProperty.AddOwner<SelectableImageButton>();
public static readonly StyledProperty<string?> SourceProperty =
BetterAdvancedImage.SourceProperty.AddOwner<SelectableImageButton>();
public bool? IsSelected
{
get => GetValue(IsSelectedProperty);
set => SetValue(IsSelectedProperty, value);
}
public string? Source
{
get => GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
}
}

26
StabilityMatrix.Avalonia/DesignData/DesignData.cs

@ -7,6 +7,7 @@ using System.IO;
using System.Net.Http; using System.Net.Http;
using System.Text; using System.Text;
using AvaloniaEdit.Utils; using AvaloniaEdit.Utils;
using DynamicData.Binding;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.Controls.CodeCompletion; using StabilityMatrix.Avalonia.Controls.CodeCompletion;
@ -20,6 +21,7 @@ using StabilityMatrix.Avalonia.ViewModels.CheckpointManager;
using StabilityMatrix.Avalonia.ViewModels.Dialogs; using StabilityMatrix.Avalonia.ViewModels.Dialogs;
using StabilityMatrix.Avalonia.ViewModels.Progress; using StabilityMatrix.Avalonia.ViewModels.Progress;
using StabilityMatrix.Avalonia.ViewModels.Inference; using StabilityMatrix.Avalonia.ViewModels.Inference;
using StabilityMatrix.Avalonia.ViewModels.OutputsPage;
using StabilityMatrix.Avalonia.ViewModels.Settings; using StabilityMatrix.Avalonia.ViewModels.Settings;
using StabilityMatrix.Core.Api; using StabilityMatrix.Core.Api;
using StabilityMatrix.Core.Database; using StabilityMatrix.Core.Database;
@ -29,6 +31,7 @@ using StabilityMatrix.Core.Helper.Factory;
using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models;
using StabilityMatrix.Core.Models.Api; using StabilityMatrix.Core.Models.Api;
using StabilityMatrix.Core.Models.Api.Comfy; using StabilityMatrix.Core.Models.Api.Comfy;
using StabilityMatrix.Core.Models.Database;
using StabilityMatrix.Core.Models.PackageModification; using StabilityMatrix.Core.Models.PackageModification;
using StabilityMatrix.Core.Models.Progress; using StabilityMatrix.Core.Models.Progress;
using StabilityMatrix.Core.Python; using StabilityMatrix.Core.Python;
@ -336,8 +339,27 @@ public static class DesignData
public static LaunchPageViewModel LaunchPageViewModel => public static LaunchPageViewModel LaunchPageViewModel =>
Services.GetRequiredService<LaunchPageViewModel>(); Services.GetRequiredService<LaunchPageViewModel>();
public static OutputsPageViewModel OutputsPageViewModel => public static OutputsPageViewModel OutputsPageViewModel
Services.GetRequiredService<OutputsPageViewModel>(); {
get
{
var vm = Services.GetRequiredService<OutputsPageViewModel>();
vm.Outputs = new ObservableCollectionExtended<OutputImageViewModel>
{
new(
new LocalImageFile
{
AbsolutePath =
"https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/78fd2a0a-42b6-42b0-9815-81cb11bb3d05/00009-2423234823.jpeg",
RelativePath =
"https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/78fd2a0a-42b6-42b0-9815-81cb11bb3d05/00009-2423234823.jpeg",
ImageType = LocalImageFileType.TextToImage
}
)
};
return vm;
}
}
public static PackageManagerViewModel PackageManagerViewModel public static PackageManagerViewModel PackageManagerViewModel
{ {

18
StabilityMatrix.Avalonia/Languages/Resources.Designer.cs generated

@ -257,6 +257,15 @@ namespace StabilityMatrix.Avalonia.Languages {
} }
} }
/// <summary>
/// Looks up a localized string similar to Open in Image Viewer.
/// </summary>
public static string Action_OpenInViewer {
get {
return ResourceManager.GetString("Action_OpenInViewer", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Open on CivitAI. /// Looks up a localized string similar to Open on CivitAI.
/// </summary> /// </summary>
@ -1157,6 +1166,15 @@ namespace StabilityMatrix.Avalonia.Languages {
} }
} }
/// <summary>
/// Looks up a localized string similar to {0} images selected.
/// </summary>
public static string Label_NumImagesSelected {
get {
return ResourceManager.GetString("Label_NumImagesSelected", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Only available on Windows. /// Looks up a localized string similar to Only available on Windows.
/// </summary> /// </summary>

6
StabilityMatrix.Avalonia/Languages/Resources.resx

@ -687,4 +687,10 @@
<data name="Action_Copy" xml:space="preserve"> <data name="Action_Copy" xml:space="preserve">
<value>Copy</value> <value>Copy</value>
</data> </data>
<data name="Action_OpenInViewer" xml:space="preserve">
<value>Open in Image Viewer</value>
</data>
<data name="Label_NumImagesSelected" xml:space="preserve">
<value>{0} images selected</value>
</data>
</root> </root>

19
StabilityMatrix.Avalonia/ViewModels/OutputsPage/OutputImageViewModel.cs

@ -0,0 +1,19 @@
using System;
using CommunityToolkit.Mvvm.ComponentModel;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Core.Models.Database;
namespace StabilityMatrix.Avalonia.ViewModels.OutputsPage;
public partial class OutputImageViewModel : ViewModelBase
{
public LocalImageFile ImageFile { get; }
[ObservableProperty]
private bool isSelected;
public OutputImageViewModel(LocalImageFile imageFile)
{
ImageFile = imageFile;
}
}

74
StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs

@ -4,21 +4,24 @@ using System.Collections.ObjectModel;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsyncAwaitBestPractices; using AsyncAwaitBestPractices;
using AsyncImageLoader; using AsyncImageLoader;
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Threading; using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using DynamicData; using DynamicData;
using DynamicData.Binding; using DynamicData.Binding;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using Microsoft.Extensions.Logging;
using StabilityMatrix.Avalonia.Extensions; using StabilityMatrix.Avalonia.Extensions;
using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.ViewModels.Dialogs; using StabilityMatrix.Avalonia.ViewModels.Dialogs;
using StabilityMatrix.Avalonia.Views; using StabilityMatrix.Avalonia.ViewModels.OutputsPage;
using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Helper.Factory; using StabilityMatrix.Core.Helper.Factory;
@ -32,21 +35,23 @@ using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource;
namespace StabilityMatrix.Avalonia.ViewModels; namespace StabilityMatrix.Avalonia.ViewModels;
[View(typeof(OutputsPage))] [View(typeof(Views.OutputsPage))]
public partial class OutputsPageViewModel : PageViewModelBase public partial class OutputsPageViewModel : PageViewModelBase
{ {
private readonly ISettingsManager settingsManager; private readonly ISettingsManager settingsManager;
private readonly INotificationService notificationService; private readonly INotificationService notificationService;
private readonly INavigationService navigationService; private readonly INavigationService navigationService;
private readonly ILogger<OutputsPageViewModel> logger;
public override string Title => "Outputs"; public override string Title => "Outputs";
public override IconSource IconSource => public override IconSource IconSource =>
new SymbolIconSource { Symbol = Symbol.Grid, IsFilled = true }; new SymbolIconSource { Symbol = Symbol.Grid, IsFilled = true };
public SourceCache<LocalImageFile, string> OutputsCache { get; } = new(p => p.AbsolutePath); public SourceCache<OutputImageViewModel, string> OutputsCache { get; } =
new(p => p.ImageFile.AbsolutePath);
public IObservableCollection<LocalImageFile> Outputs { get; } = public IObservableCollection<OutputImageViewModel> Outputs { get; set; } =
new ObservableCollectionExtended<LocalImageFile>(); new ObservableCollectionExtended<OutputImageViewModel>();
public IEnumerable<SharedOutputType> OutputTypes { get; } = Enum.GetValues<SharedOutputType>(); public IEnumerable<SharedOutputType> OutputTypes { get; } = Enum.GetValues<SharedOutputType>();
@ -60,25 +65,35 @@ public partial class OutputsPageViewModel : PageViewModelBase
[ObservableProperty] [ObservableProperty]
private SharedOutputType selectedOutputType; private SharedOutputType selectedOutputType;
[ObservableProperty]
private int numItemsSelected;
public bool CanShowOutputTypes => SelectedCategory.Name.Equals("Shared Output Folder"); public bool CanShowOutputTypes => SelectedCategory.Name.Equals("Shared Output Folder");
public OutputsPageViewModel( public OutputsPageViewModel(
ISettingsManager settingsManager, ISettingsManager settingsManager,
IPackageFactory packageFactory, IPackageFactory packageFactory,
INotificationService notificationService, INotificationService notificationService,
INavigationService navigationService INavigationService navigationService,
ILogger<OutputsPageViewModel> logger
) )
{ {
this.settingsManager = settingsManager; this.settingsManager = settingsManager;
this.notificationService = notificationService; this.notificationService = notificationService;
this.navigationService = navigationService; this.navigationService = navigationService;
this.logger = logger;
OutputsCache OutputsCache
.Connect() .Connect()
.DeferUntilLoaded() .DeferUntilLoaded()
.SortBy(x => x.CreatedAt, SortDirection.Descending) .SortBy(x => x.ImageFile.CreatedAt, SortDirection.Descending)
.ObserveOn(SynchronizationContext.Current)
.Bind(Outputs) .Bind(Outputs)
.Subscribe(); .WhenPropertyChanged(p => p.IsSelected)
.Subscribe(_ =>
{
NumItemsSelected = Outputs.Count(o => o.IsSelected);
});
if (!settingsManager.IsLibraryDirSet || Design.IsDesignMode) if (!settingsManager.IsLibraryDirSet || Design.IsDesignMode)
return; return;
@ -152,16 +167,29 @@ public partial class OutputsPageViewModel : PageViewModelBase
GetOutputs(path); GetOutputs(path);
} }
public async Task OnImageClick(LocalImageFile item) public async Task OnImageClick(OutputImageViewModel item)
{
// Select image if we're in "select mode"
if (NumItemsSelected > 0)
{
item.IsSelected = !item.IsSelected;
}
else
{
await ShowImageDialog(item);
}
}
public async Task ShowImageDialog(OutputImageViewModel item)
{ {
var currentIndex = Outputs.IndexOf(item); var currentIndex = Outputs.IndexOf(item);
var image = new ImageSource(new FilePath(item.AbsolutePath)); var image = new ImageSource(new FilePath(item.ImageFile.AbsolutePath));
// Preload // Preload
await image.GetBitmapAsync(); await image.GetBitmapAsync();
var vm = new ImageViewerViewModel { ImageSource = image, LocalImageFile = item }; var vm = new ImageViewerViewModel { ImageSource = image, LocalImageFile = item.ImageFile };
using var onNext = Observable using var onNext = Observable
.FromEventPattern<DirectionalNavigationEventArgs>( .FromEventPattern<DirectionalNavigationEventArgs>(
@ -180,14 +208,14 @@ public partial class OutputsPageViewModel : PageViewModelBase
{ {
var newImage = Outputs[newIndex]; var newImage = Outputs[newIndex];
var newImageSource = new ImageSource( var newImageSource = new ImageSource(
new FilePath(newImage.AbsolutePath) new FilePath(newImage.ImageFile.AbsolutePath)
); );
// Preload // Preload
await newImageSource.GetBitmapAsync(); await newImageSource.GetBitmapAsync();
sender.ImageSource = newImageSource; sender.ImageSource = newImageSource;
sender.LocalImageFile = newImage; sender.LocalImageFile = newImage.ImageFile;
currentIndex = newIndex; currentIndex = newIndex;
} }
@ -207,9 +235,9 @@ public partial class OutputsPageViewModel : PageViewModelBase
public async Task OpenImage(string imagePath) => await ProcessRunner.OpenFileBrowser(imagePath); public async Task OpenImage(string imagePath) => await ProcessRunner.OpenFileBrowser(imagePath);
public async Task DeleteImage(LocalImageFile? item) public async Task DeleteImage(OutputImageViewModel? item)
{ {
if (item?.GetFullPath(settingsManager.ImagesDirectory) is not { } imagePath) if (item?.ImageFile.GetFullPath(settingsManager.ImagesDirectory) is not { } imagePath)
{ {
return; return;
} }
@ -223,7 +251,7 @@ public partial class OutputsPageViewModel : PageViewModelBase
return; return;
} }
Outputs.Remove(item); OutputsCache.Remove(item);
// Invalidate cache // Invalidate cache
if (ImageLoader.AsyncImageLoader is FallbackRamCachedWebImageLoader loader) if (ImageLoader.AsyncImageLoader is FallbackRamCachedWebImageLoader loader)
@ -244,6 +272,14 @@ public partial class OutputsPageViewModel : PageViewModelBase
EventManager.Instance.OnInferenceUpscaleRequested(image); EventManager.Instance.OnInferenceUpscaleRequested(image);
} }
public void ClearSelection()
{
foreach (var output in Outputs)
{
output.IsSelected = false;
}
}
private void GetOutputs(string directory) private void GetOutputs(string directory)
{ {
if (!settingsManager.IsLibraryDirSet) if (!settingsManager.IsLibraryDirSet)
@ -257,9 +293,9 @@ public partial class OutputsPageViewModel : PageViewModelBase
var list = Directory var list = Directory
.EnumerateFiles(directory, "*.png", SearchOption.AllDirectories) .EnumerateFiles(directory, "*.png", SearchOption.AllDirectories)
.Select(file => LocalImageFile.FromPath(file)) .Select(file => new OutputImageViewModel(LocalImageFile.FromPath(file)))
.OrderByDescending(f => f.CreatedAt); .OrderByDescending(f => f.ImageFile.CreatedAt);
OutputsCache.EditDiff(list, (x, y) => x.AbsolutePath == y.AbsolutePath); OutputsCache.EditDiff(list, (x, y) => x.ImageFile.AbsolutePath == y.ImageFile.AbsolutePath);
} }
} }

78
StabilityMatrix.Avalonia/Views/OutputsPage.axaml

@ -13,7 +13,8 @@
xmlns:models1="clr-namespace:StabilityMatrix.Avalonia.Models" xmlns:models1="clr-namespace:StabilityMatrix.Avalonia.Models"
xmlns:database="clr-namespace:StabilityMatrix.Core.Models.Database;assembly=StabilityMatrix.Core" xmlns:database="clr-namespace:StabilityMatrix.Core.Models.Database;assembly=StabilityMatrix.Core"
xmlns:fluentAvalonia="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia" xmlns:fluentAvalonia="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia"
xmlns:models="clr-namespace:StabilityMatrix.Core.Models;assembly=StabilityMatrix.Core" xmlns:outputsPage="clr-namespace:StabilityMatrix.Avalonia.ViewModels.OutputsPage"
xmlns:selectableImageCard="clr-namespace:StabilityMatrix.Avalonia.Controls.SelectableImageCard"
d:DataContext="{x:Static mocks:DesignData.OutputsPageViewModel}" d:DataContext="{x:Static mocks:DesignData.OutputsPageViewModel}"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="700" d:DesignWidth="700"
@ -24,8 +25,9 @@
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,16" <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,16"
HorizontalAlignment="Left"> HorizontalAlignment="Left">
<Grid RowDefinitions="Auto, *"> <Grid RowDefinitions="Auto, *">
<TextBlock Text="Output Folder" Margin="4"/> <TextBlock Text="Output Folder" Margin="4" />
<ComboBox Grid.Row="1" ItemsSource="{Binding Categories}" <ComboBox Grid.Row="1" ItemsSource="{Binding Categories}"
CornerRadius="8"
SelectedItem="{Binding SelectedCategory}" SelectedItem="{Binding SelectedCategory}"
MinWidth="150"> MinWidth="150">
<ComboBox.Styles> <ComboBox.Styles>
@ -48,13 +50,31 @@
</Grid> </Grid>
<Grid RowDefinitions="Auto, *" Margin="8,0" <Grid RowDefinitions="Auto, *" Margin="8,0"
IsVisible="{Binding CanShowOutputTypes}"> IsVisible="{Binding CanShowOutputTypes}">
<TextBlock Text="Output Type" Margin="4"/> <TextBlock Text="Output Type" Margin="4" />
<ComboBox Grid.Row="1" ItemsSource="{Binding OutputTypes}" <ComboBox Grid.Row="1" ItemsSource="{Binding OutputTypes}"
CornerRadius="8"
SelectedItem="{Binding SelectedOutputType}" SelectedItem="{Binding SelectedOutputType}"
MinWidth="150" MinWidth="150"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
VerticalContentAlignment="Center"/> VerticalContentAlignment="Center" />
</Grid> </Grid>
<TextBlock IsVisible="{Binding !!NumItemsSelected}"
FontSize="16"
Margin="8, 0"
VerticalAlignment="Center"
TextAlignment="Center">
<Run Text="{Binding NumItemsSelected}" />
<Run Text="images selected" />
</TextBlock>
<Button Content="Clear Selection"
VerticalAlignment="Bottom"
CornerRadius="8"
Margin="8, 0"
Height="40"
Command="{Binding ClearSelection}"
IsVisible="{Binding !!NumItemsSelected}" />
</StackPanel> </StackPanel>
<ScrollViewer Grid.Row="1"> <ScrollViewer Grid.Row="1">
@ -65,45 +85,45 @@
<UniformGridLayout MinColumnSpacing="16" MinRowSpacing="16" /> <UniformGridLayout MinColumnSpacing="16" MinRowSpacing="16" />
</ItemsRepeater.Layout> </ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate> <ItemsRepeater.ItemTemplate>
<DataTemplate DataType="{x:Type database:LocalImageFile}"> <DataTemplate DataType="{x:Type outputsPage:OutputImageViewModel}">
<Button <selectableImageCard:SelectableImageButton
Margin="0"
Padding="4"
Command="{Binding $parent[ItemsRepeater].((vm:OutputsPageViewModel)DataContext).OnImageClick}" Command="{Binding $parent[ItemsRepeater].((vm:OutputsPageViewModel)DataContext).OnImageClick}"
CommandParameter="{Binding }"> CommandParameter="{Binding }"
<controls:BetterAdvancedImage IsSelected="{Binding IsSelected}"
Width="300" Source="{Binding ImageFile.AbsolutePath}">
Height="300" <selectableImageCard:SelectableImageButton.ContextFlyout>
Stretch="UniformToFill"
Source="{Binding AbsolutePath}" />
<Button.ContextFlyout>
<ui:FAMenuFlyout> <ui:FAMenuFlyout>
<ui:MenuFlyoutItem
HotKey="{x:Null}"
Text="{x:Static lang:Resources.Action_Delete}"
IconSource="Delete"
Command="{Binding $parent[ItemsRepeater].((vm:OutputsPageViewModel)DataContext).DeleteImage}"
CommandParameter="{Binding }" />
<ui:MenuFlyoutItem <ui:MenuFlyoutItem
HotKey="{x:Null}" HotKey="{x:Null}"
Text="{x:Static lang:Resources.Action_Copy}" Text="{x:Static lang:Resources.Action_Copy}"
IconSource="Copy" IconSource="Copy"
Command="{Binding $parent[ItemsRepeater].((vm:OutputsPageViewModel)DataContext).CopyImage}" Command="{Binding $parent[ItemsRepeater].((vm:OutputsPageViewModel)DataContext).CopyImage}"
CommandParameter="{Binding AbsolutePath}" /> CommandParameter="{Binding ImageFile.AbsolutePath}" />
<ui:MenuFlyoutItem <ui:MenuFlyoutItem
HotKey="{x:Null}" HotKey="{x:Null}"
Text="{x:Static lang:Resources.Action_OpenInExplorer}" Text="{x:Static lang:Resources.Action_OpenInExplorer}"
IconSource="Folder" IconSource="Folder"
Command="{Binding $parent[ItemsRepeater].((vm:OutputsPageViewModel)DataContext).OpenImage}" Command="{Binding $parent[ItemsRepeater].((vm:OutputsPageViewModel)DataContext).OpenImage}"
CommandParameter="{Binding AbsolutePath}" /> CommandParameter="{Binding ImageFile.AbsolutePath}" />
<ui:MenuFlyoutItem
HotKey="{x:Null}"
Text="{x:Static lang:Resources.Action_OpenInViewer}"
IconSource="Image"
IsVisible="{Binding !!$parent[ItemsRepeater].((vm:OutputsPageViewModel)DataContext).NumItemsSelected}"
Command="{Binding $parent[ItemsRepeater].((vm:OutputsPageViewModel)DataContext).ShowImageDialog}"
CommandParameter="{Binding }" />
<ui:MenuFlyoutItem
HotKey="{x:Null}"
Text="{x:Static lang:Resources.Action_Delete}"
IconSource="Delete"
Command="{Binding $parent[ItemsRepeater].((vm:OutputsPageViewModel)DataContext).DeleteImage}"
CommandParameter="{Binding }" />
<ui:MenuFlyoutSeparator <ui:MenuFlyoutSeparator
IsVisible="{Binding GenerationParameters, Converter={x:Static ObjectConverters.IsNotNull}}" /> IsVisible="{Binding ImageFile.GenerationParameters, Converter={x:Static ObjectConverters.IsNotNull}}" />
<ui:MenuFlyoutSubItem Text="Send to Inference" IconSource="Share" <ui:MenuFlyoutSubItem Text="Send to Inference" IconSource="Share"
IsVisible="{Binding GenerationParameters, Converter={x:Static ObjectConverters.IsNotNull}}"> IsVisible="{Binding ImageFile.GenerationParameters, Converter={x:Static ObjectConverters.IsNotNull}}">
<ui:MenuFlyoutItem <ui:MenuFlyoutItem
HotKey="{x:Null}" HotKey="{x:Null}"
Text="Text to Image" Text="Text to Image"
@ -135,8 +155,8 @@
</ui:MenuFlyoutItem> </ui:MenuFlyoutItem>
</ui:MenuFlyoutSubItem> </ui:MenuFlyoutSubItem>
</ui:FAMenuFlyout> </ui:FAMenuFlyout>
</Button.ContextFlyout> </selectableImageCard:SelectableImageButton.ContextFlyout>
</Button> </selectableImageCard:SelectableImageButton>
</DataTemplate> </DataTemplate>
</ItemsRepeater.ItemTemplate> </ItemsRepeater.ItemTemplate>
</ItemsRepeater> </ItemsRepeater>

Loading…
Cancel
Save