From c51f1fe25ed9e092f250001401d468cfbd82a739 Mon Sep 17 00:00:00 2001 From: Patchzy <64382339+patchzyy@users.noreply.github.com> Date: Sat, 27 Dec 2025 15:43:30 +0100 Subject: [PATCH] Add Mii image hover support to MiiBlock --- .../MiiImages/MiiImageLoaderWithHover.axaml | 54 +++++ .../MiiImageLoaderWithHover.axaml.cs | 190 ++++++++++++++++++ .../Components/WhWzLibrary/MiiBlock.axaml | 17 +- .../Components/WhWzLibrary/MiiBlock.axaml.cs | 69 +++++++ 4 files changed, 324 insertions(+), 6 deletions(-) create mode 100644 WheelWizard/Views/BehaviorComponent/MiiImages/MiiImageLoaderWithHover.axaml create mode 100644 WheelWizard/Views/BehaviorComponent/MiiImages/MiiImageLoaderWithHover.axaml.cs diff --git a/WheelWizard/Views/BehaviorComponent/MiiImages/MiiImageLoaderWithHover.axaml b/WheelWizard/Views/BehaviorComponent/MiiImages/MiiImageLoaderWithHover.axaml new file mode 100644 index 00000000..808a2d62 --- /dev/null +++ b/WheelWizard/Views/BehaviorComponent/MiiImages/MiiImageLoaderWithHover.axaml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WheelWizard/Views/BehaviorComponent/MiiImages/MiiImageLoaderWithHover.axaml.cs b/WheelWizard/Views/BehaviorComponent/MiiImages/MiiImageLoaderWithHover.axaml.cs new file mode 100644 index 00000000..16d2d4bd --- /dev/null +++ b/WheelWizard/Views/BehaviorComponent/MiiImages/MiiImageLoaderWithHover.axaml.cs @@ -0,0 +1,190 @@ +using System.ComponentModel; +using Avalonia; +using Avalonia.Media; +using WheelWizard.MiiImages; +using WheelWizard.MiiImages.Domain; +using WheelWizard.WiiManagement.MiiManagement.Domain.Mii; + +namespace WheelWizard.Views.BehaviorComponent; + +public partial class MiiImageLoaderWithHover : BaseMiiImage +{ + public static readonly StyledProperty IsHoveredProperty = AvaloniaProperty.Register( + nameof(IsHovered), + false + ); + + public bool IsHovered + { + get => GetValue(IsHoveredProperty); + set => SetValue(IsHoveredProperty, value); + } + + public static readonly StyledProperty ShowNormalImageProperty = AvaloniaProperty.Register( + nameof(ShowNormalImage), + true + ); + + public bool ShowNormalImage + { + get => GetValue(ShowNormalImageProperty); + private set => SetValue(ShowNormalImageProperty, value); + } + + public static readonly StyledProperty ShowHoverImageProperty = AvaloniaProperty.Register( + nameof(ShowHoverImage), + false + ); + + public bool ShowHoverImage + { + get => GetValue(ShowHoverImageProperty); + private set => SetValue(ShowHoverImageProperty, value); + } + + private void UpdateImageVisibility() + { + var hasHoverImage = GeneratedImages.Count > 1 && GeneratedImages[1] != null; + + if (IsHovered && hasHoverImage) + { + ShowNormalImage = false; + ShowHoverImage = true; + } + else + { + ShowNormalImage = true; + ShowHoverImage = false; + } + } + + public static readonly StyledProperty LoadingColorProperty = AvaloniaProperty.Register( + nameof(LoadingColor), + new SolidColorBrush(ViewUtils.Colors.Neutral900) + ); + + public IBrush LoadingColor + { + get => GetValue(LoadingColorProperty); + set => SetValue(LoadingColorProperty, value); + } + + public static readonly StyledProperty FallBackColorProperty = AvaloniaProperty.Register( + nameof(FallBackColor), + new SolidColorBrush(ViewUtils.Colors.Neutral700) + ); + + public IBrush FallBackColor + { + get => GetValue(FallBackColorProperty); + set => SetValue(FallBackColorProperty, value); + } + + public static readonly StyledProperty ImageOnlyMarginProperty = AvaloniaProperty.Register< + MiiImageLoaderWithHover, + Thickness + >(nameof(ImageOnlyMargin), enableDataValidation: true); + + public Thickness ImageOnlyMargin + { + get => GetValue(ImageOnlyMarginProperty); + set => SetValue(ImageOnlyMarginProperty, value); + } + + public static readonly StyledProperty ImageVariantProperty = AvaloniaProperty.Register< + MiiImageLoaderWithHover, + MiiImageSpecifications + >(nameof(ImageVariant), MiiImageVariants.OnlinePlayerSmall, coerce: CoerceVariant); + + public MiiImageSpecifications ImageVariant + { + get => GetValue(ImageVariantProperty); + set => SetValue(ImageVariantProperty, value); + } + + public static readonly StyledProperty HoverVariantProperty = AvaloniaProperty.Register< + MiiImageLoaderWithHover, + MiiImageSpecifications? + >(nameof(HoverVariant), coerce: CoerceHoverVariant); + + public MiiImageSpecifications? HoverVariant + { + get => GetValue(HoverVariantProperty); + set => SetValue(HoverVariantProperty, value); + } + + private static MiiImageSpecifications? CoerceHoverVariant(AvaloniaObject o, MiiImageSpecifications? value) + { + var loader = (MiiImageLoaderWithHover)o; + // Reload both variants when hover variant changes (if Mii is already set) + // If Mii is not set yet, OnMiiChanged will handle the reload + if (loader.Mii != null && value != null) + { + loader.ReloadBothVariants(); + } + return value; + } + + private static MiiImageSpecifications CoerceVariant(AvaloniaObject o, MiiImageSpecifications value) + { + ((MiiImageLoaderWithHover)o).OnVariantChanged(value); + return value; + } + + public MiiImageLoaderWithHover() + { + InitializeComponent(); + PropertyChanged += MiiImageLoaderWithHover_PropertyChanged; + GeneratedImages.CollectionChanged += (s, e) => UpdateImageVisibility(); + MiiImageLoaded += (s, e) => UpdateImageVisibility(); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == IsHoveredProperty) + { + UpdateImageVisibility(); + } + } + + private void MiiImageLoaderWithHover_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(GeneratedImages)) + { + UpdateImageVisibility(); + } + } + + private void OnVariantChanged(MiiImageSpecifications newSpecifications) + { + ReloadBothVariants(); + } + + protected override void OnMiiChanged(Mii? newMii) + { + // Always reload both variants when Mii changes + // This ensures both images are loaded even if hover variant is set later + ReloadBothVariants(); + } + + public void ReloadBothVariants() + { + if (Mii == null) + return; + + var variants = new List(); + + // Always load the normal variant first + variants.Add(ImageVariant); + + // If hover variant is set, load it as the second image + if (HoverVariant != null) + { + variants.Add(HoverVariant); + } + + ReloadImages(Mii, variants); + } +} diff --git a/WheelWizard/Views/Components/WhWzLibrary/MiiBlock.axaml b/WheelWizard/Views/Components/WhWzLibrary/MiiBlock.axaml index ba72c104..14b06bcd 100644 --- a/WheelWizard/Views/Components/WhWzLibrary/MiiBlock.axaml +++ b/WheelWizard/Views/Components/WhWzLibrary/MiiBlock.axaml @@ -44,12 +44,13 @@ IsVisible="{TemplateBinding Mii, Converter={x:Static ObjectConverters.IsNull} }" Width="1000" Foreground="{StaticResource Neutral500}" /> - + + +