Multi-Platform Package Manager for Stable Diffusion
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
4.8 KiB

using System;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using FluentAvalonia.UI.Controls;
using FluentAvalonia.UI.Media.Animation;
using FluentAvalonia.UI.Navigation;
using StabilityMatrix.Avalonia.Animations;
using StabilityMatrix.Core.Extensions;
namespace StabilityMatrix.Avalonia.Controls;
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class FrameCarousel : SelectingItemsControl
{
public static readonly StyledProperty<IDataTemplate?> ContentTemplateProperty = AvaloniaProperty.Register<FrameCarousel, IDataTemplate?>(
"ContentTemplate");
public IDataTemplate? ContentTemplate
{
get => GetValue(ContentTemplateProperty);
set => SetValue(ContentTemplateProperty, value);
}
public static readonly StyledProperty<Type> SourcePageTypeProperty = AvaloniaProperty.Register<FrameCarousel, Type>(
"SourcePageType");
public Type SourcePageType
{
get => GetValue(SourcePageTypeProperty);
set => SetValue(SourcePageTypeProperty, value);
}
private Frame? frame;
private int previousIndex = -1;
private static readonly FrameNavigationOptions ForwardNavigationOptions
= new()
{
TransitionInfoOverride = new BetterSlideNavigationTransition
{
Effect = SlideNavigationTransitionEffect.FromRight,
FromHorizontalOffset = 200
}
};
private static readonly FrameNavigationOptions BackNavigationOptions
= new()
{
TransitionInfoOverride = new BetterSlideNavigationTransition
{
Effect = SlideNavigationTransitionEffect.FromLeft,
FromHorizontalOffset = 200
}
};
private static readonly FrameNavigationOptions DirectionlessNavigationOptions
= new()
{
TransitionInfoOverride = new SuppressNavigationTransitionInfo()
};
/// <inheritdoc />
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
frame = e.NameScope.Find<Frame>("PART_Frame")
?? throw new NullReferenceException("Frame not found");
frame.NavigationPageFactory = new FrameNavigationFactory(SourcePageType);
if (SelectedItem is not null)
{
frame.NavigateFromObject(SelectedItem, DirectionlessNavigationOptions);
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (frame is null) return;
if (change.Property == SelectedItemProperty)
{
if (change.GetNewValue<object?>() is not { } value) return;
if (SelectedIndex > previousIndex)
{
// Going forward
frame.NavigateFromObject(value, ForwardNavigationOptions);
}
else if (SelectedIndex < previousIndex)
{
// Going back
frame.NavigateFromObject(value, BackNavigationOptions);
}
else
{
frame.NavigateFromObject(value, DirectionlessNavigationOptions);
}
previousIndex = SelectedIndex;
}
else if (change.Property == ItemCountProperty)
{
// On item count change to 0, clear the frame cache
var value = change.GetNewValue<int>();
if (value == 0)
{
var pageCache = frame.GetPrivateField<IList>("_pageCache");
pageCache?.Clear();
}
}
}
/// <summary>
/// Moves to the next item in the carousel.
/// </summary>
public void Next()
{
if (SelectedIndex < ItemCount - 1)
{
++SelectedIndex;
}
}
/// <summary>
/// Moves to the previous item in the carousel.
/// </summary>
public void Previous()
{
if (SelectedIndex > 0)
{
--SelectedIndex;
}
}
internal class FrameNavigationFactory : INavigationPageFactory
{
private readonly Type _sourcePageType;
public FrameNavigationFactory(Type sourcePageType)
{
_sourcePageType = sourcePageType;
}
/// <inheritdoc />
public Control GetPage(Type srcType)
{
return (Control) Activator.CreateInstance(srcType)!;
}
/// <inheritdoc />
public Control GetPageFromObject(object target)
{
var view = GetPage(_sourcePageType);
view.DataContext = target;
return view;
}
}
}