Skip to content
1 change: 1 addition & 0 deletions WheelWizard/Views/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,6 @@
<StyleInclude Source="Components/WhWzLibrary/PlayerListItem.axaml" />
<StyleInclude Source="Components/WhWzLibrary/Badge.axaml" />
<StyleInclude Source="Components/WhWzLibrary/MiiBlock.axaml" />
<StyleInclude Source="Components/WhWzLibrary/WheelTrail.axaml" />
</Application.Styles>
</Application>
130 changes: 130 additions & 0 deletions WheelWizard/Views/Components/WhWzLibrary/WheelTrail.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:WheelWizard.Views.Converters"
xmlns:controls="using:WheelWizard.Views.Components">
<!--
<Styles.Resources>
<x:Double x:Key="HeightMultiplier">5.0</x:Double>
</Styles.Resources> -->
<Design.PreviewWith>
<Grid Background="{StaticResource Black}" Height="200" Width="180">
<!-- Now you can set the Angle on each instance -->
<controls:WheelTrail Background="Green" Foreground="DarkGreen" Width="31" RelativeLength="4"
X="-70" Y="50" WheelRotation="25" Angle="3" />
<controls:WheelTrail Background="Red" Foreground="DarkRed" Width="11" RelativeLength="10"
Angle="110" X="-50" Y="20" ExtendedHeight="-7" />

<controls:WheelTrail Background="Orange" Foreground="DarkOrange" Width="41" RelativeLength="1.5"
Angle="210" X="10" Y="30" ExtendedHeight="-7">
<controls:WheelTrail.Styles>
<Style Selector="controls|WheelTrail">
<Style.Animations>
<Animation Duration="0:0:1.5" IterationCount="INFINITE">
<KeyFrame Cue="0%">
<Setter Property="WheelRotation" Value="0" />
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="WheelRotation" Value="360" />
</KeyFrame>
</Animation>
</Style.Animations>
</Style>
<Style Selector="controls|WheelTrail">
<Style.Animations>
<Animation Duration="0:0:0.2" IterationCount="INFINITE" PlaybackDirection="Alternate">
<KeyFrame Cue="0%">
<Setter Property="ExtendedHeight" Value="0" />
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="ExtendedHeight" Value="1.2" />
</KeyFrame>
</Animation>
</Style.Animations>
</Style>
</controls:WheelTrail.Styles>
</controls:WheelTrail>

<controls:WheelTrail Background="Cyan" Foreground="DarkCyan" Width="61"
Angle="-20" X="10" Y="90">
<controls:WheelTrail.Styles>
<Style Selector="controls|WheelTrail">
<Style.Animations>
<Animation Duration="0:0:2.5" IterationCount="INFINITE"
Easing="QuadraticEaseInOut">
<KeyFrame Cue="0%">
<Setter Property="WheelRotation" Value="0" />
<Setter Property="ExtendedHeight" Value="0" />
</KeyFrame>
<KeyFrame Cue="50%">
<Setter Property="WheelRotation" Value="180" />
<Setter Property="ExtendedHeight" Value="60" />
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="WheelRotation" Value="360" />
<Setter Property="ExtendedHeight" Value="0" />
</KeyFrame>
</Animation>
</Style.Animations>
</Style>
</controls:WheelTrail.Styles>
</controls:WheelTrail>
</Grid>
</Design.PreviewWith>

<Style Selector="controls|WheelTrail" x:DataType="controls:WheelTrail">
<Setter Property="ClipToBounds" Value="False"></Setter>
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Height" Value="{Binding Width, RelativeSource={RelativeSource Self}}" />

<Setter Property="Template">
<ControlTemplate>
<Border Width="{TemplateBinding Width}"
CornerRadius="100000,100000,0,0" VerticalAlignment="Top"
Margin="{TemplateBinding ExtendedHeight, Converter={x:Static conv:DoubleToThicknessConverters.DoubleToTop}}">
<Border.Height>
<MultiBinding Converter="{x:Static conv:NumberConverters.MultiplyDouble}">
<Binding Path="Width" RelativeSource="{RelativeSource Self}" />
<Binding Path="RelativeLength" RelativeSource="{RelativeSource TemplatedParent}" />
<!--
If you want to do a constant, you can do it like this. And then add the constant to a resource like i did above
<Binding Source="{StaticResource HeightMultiplier}" /> -->
</MultiBinding>
</Border.Height>
<Grid RowDefinitions="1*,10*,1*" ColumnDefinitions="1*,10*,1*"
Width="{TemplateBinding Width}" Height="{TemplateBinding Width}"
VerticalAlignment="Top" HorizontalAlignment="Center">

<Path Grid.Column="1" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"
Fill="{TemplateBinding Foreground}" Data="{StaticResource WheelIcon}"
Stretch="Uniform">
<Path.RenderTransform>
<RotateTransform
Angle="{Binding WheelRotation, RelativeSource={RelativeSource TemplatedParent}}" />
</Path.RenderTransform>
</Path>
</Grid>
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop
Color="{Binding Background,
RelativeSource={RelativeSource TemplatedParent},
Converter={x:Static conv:BrushColorConverters.BrushToColor}}"
Offset="0.0" />
<GradientStop
Color="{Binding Background,
RelativeSource={RelativeSource TemplatedParent},
Converter={x:Static conv:BrushColorConverters.BrushToColor}}"
Offset="0.75" />
<GradientStop
Color="{Binding Background,
RelativeSource={RelativeSource TemplatedParent},
Converter={x:Static conv:BrushColorConverters.TransparentColor}}"
Offset="1.0" />
</LinearGradientBrush>
</Border.Background>
</Border>

</ControlTemplate>
</Setter>
</Style>
</Styles>
93 changes: 93 additions & 0 deletions WheelWizard/Views/Components/WhWzLibrary/WheelTrail.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using Avalonia;
using Avalonia.Controls.Primitives;
using Avalonia.Media;

namespace WheelWizard.Views.Components
{
public class WheelTrail : TemplatedControl
{
public static readonly StyledProperty<double> AngleProperty = AvaloniaProperty.Register<WheelTrail, double>(nameof(Angle));

public double Angle
{
get => GetValue(AngleProperty);
set => SetValue(AngleProperty, value);
}

public static readonly StyledProperty<double> WheelRotationProperty = AvaloniaProperty.Register<WheelTrail, double>(
nameof(WheelRotation)
);

public double WheelRotation
{
get => GetValue(WheelRotationProperty);
set => SetValue(WheelRotationProperty, value);
}

public static readonly StyledProperty<double> RelativeLengthProperty = AvaloniaProperty.Register<WheelTrail, double>(
nameof(RelativeLength),
6.0
);
public double RelativeLength
{
get => GetValue(RelativeLengthProperty);
set => SetValue(RelativeLengthProperty, value);
}

public static readonly StyledProperty<double> XProperty = AvaloniaProperty.Register<WheelTrail, double>(nameof(X));

public double X
{
get => GetValue(XProperty);
set => SetValue(XProperty, value);
}

public static readonly StyledProperty<double> YProperty = AvaloniaProperty.Register<WheelTrail, double>(nameof(Y));

public double Y
{
get => GetValue(YProperty);
set => SetValue(YProperty, value);
}

public static readonly StyledProperty<double> ExtendedHeightProperty = AvaloniaProperty.Register<WheelTrail, double>(
nameof(ExtendedHeight)
);

public double ExtendedHeight
{
get => GetValue(ExtendedHeightProperty);
set => SetValue(ExtendedHeightProperty, value);
}

private readonly RotateTransform _rotateTransform = new RotateTransform { CenterX = 0.5, CenterY = 0.5 };
private readonly TranslateTransform _translateTransform = new TranslateTransform { X = 0, Y = 0 };

public WheelTrail()
{
var group = new TransformGroup();
group.Children.Add(_rotateTransform);
group.Children.Add(_translateTransform);
this.RenderTransform = group;
}

protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);

if (change.Property == AngleProperty)
{
_rotateTransform.Angle = (double)(change.NewValue ?? 0.0);
}

if (change.Property == XProperty)
{
_translateTransform.X = (double)(change.NewValue ?? 0.0);
}
if (change.Property == YProperty)
{
_translateTransform.Y = (double)(change.NewValue ?? 0.0);
}
}
}
}
28 changes: 28 additions & 0 deletions WheelWizard/Views/Converters/BrushColorConverters.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Avalonia.Data.Converters;
using Avalonia.Media;

namespace WheelWizard.Views.Converters;

// Note that this is static, which means you dont have to add it as a converter
public static class BrushColorConverters
{
public static readonly IValueConverter TransparentColor = new FuncValueConverter<object, Color>(x =>
{
if (x is ISolidColorBrush brush)
return new Color(0, brush.Color.R, brush.Color.G, brush.Color.B);
if (x is Color c)
return new Color(0, c.R, c.G, c.B);

return (Colors.Transparent);
});

public static readonly IValueConverter BrushToColor = new FuncValueConverter<IBrush, Color>(x =>
{
if (x is ISolidColorBrush brush)
return brush.Color;
if (x is IGradientBrush gradientBrush)
return gradientBrush.GradientStops[0].Color;

return (Colors.Transparent);
});
}
13 changes: 13 additions & 0 deletions WheelWizard/Views/Converters/DoubleToThicknessConverters.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Avalonia;
using Avalonia.Data.Converters;
using Avalonia.Media;

namespace WheelWizard.Views.Converters;

public class DoubleToThicknessConverters
{
public static readonly IValueConverter DoubleToTop = new FuncValueConverter<double, Thickness?>(x => new Thickness(0, x, 0, 0));
public static readonly IValueConverter DoubleToBottom = new FuncValueConverter<double, Thickness?>(x => new Thickness(0, 0, 0, x));
public static readonly IValueConverter DoubleToLeft = new FuncValueConverter<double, Thickness?>(x => new Thickness(x, 0, 0, 0));
public static readonly IValueConverter DoubleToRight = new FuncValueConverter<double, Thickness?>(x => new Thickness(0, 0, x, 0));
}
12 changes: 10 additions & 2 deletions WheelWizard/Views/Converters/NumberConverters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@ public static class NumberConverters
public static readonly IValueConverter DoubleToInt = new FuncValueConverter<double, int>(x => (int)x);
public static readonly IValueConverter FloatToInt = new FuncValueConverter<float, int>(x => (int)x);

public static readonly IMultiValueConverter MultiplyDouble = new FuncMultiValueConverter<double, double>(x =>
{
double result = 1;
foreach (var brush in x)
{
result *= brush;
}
return result;
});

// TODO, find out if you can have a third parameter so that its not always 0, but instead that you can specify the value

public static readonly IValueConverter Equals0 = new FuncValueConverter<double, bool>(x => x == 0);
public static readonly IValueConverter GreaterThan0 = new FuncValueConverter<double, bool>(x => x > 0);
public static readonly IValueConverter SmallerThan0 = new FuncValueConverter<double, bool>(x => x < 0);
public static readonly IValueConverter GreaterThanOrEqual0 = new FuncValueConverter<double, bool>(x => x >= 0);
public static readonly IValueConverter SmallerThanOrEqual0 = new FuncValueConverter<double, bool>(x => x <= 0);

public static readonly IValueConverter AlwaysFalse = new FuncValueConverter<bool, bool>(x => false);
}
8 changes: 5 additions & 3 deletions WheelWizard/Views/Layout.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,11 @@
<Border Grid.Column="1" Grid.Row="1" Grid.RowSpan="5"
CornerRadius="{StaticResource WindowCornerRadiusLeftRightTwix}"
Background="{StaticResource BackgroundColor}" />
<ContentControl Grid.Column="1" Grid.Row="1" Grid.RowSpan="5" ClipToBounds="False"
x:Name="ContentArea" Margin="{StaticResource EdgeGap}" />

<Grid Grid.Column="1" Grid.Row="1" Grid.RowSpan="5" ClipToBounds="True">
<ContentControl HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ClipToBounds="False"
x:Name="ContentArea" Margin="{StaticResource EdgeGap}" />
</Grid>

<StackPanel Grid.Row="3" Orientation="Horizontal" VerticalAlignment="Bottom"
Margin="0,0,0,25">
<components:StateBox x:Name="PlayerCountBox" Text="0" Variant="Dark"
Expand Down
Loading
Loading