using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Shapes;
namespace StrixMusic.Shells.ZuneDesktop.Controls.Shells
{
///
/// A Control to display bars dancing as if music were playing.
///
public sealed partial class NowPlayingButtonContent : UserControl
{
private const double PADDING = .8;
private const double MINIMUM_HEIGHT_FACTOR = .05;
private const double MINIMUM_CHANGE_FACTOR = 0.25;
private const double POST_NOISE = 0.05;
private const double SECONDS = .8;
private Rectangle[] _rectangles;
private double[] _activeScale;
private ScaleTransform[] _rectScaleTransforms;
private DoubleAnimation[] _dAnimations;
private Storyboard _storyboard;
private Random _random;
///
/// for the property.
///
public static readonly DependencyProperty BarCountProperty =
DependencyProperty.Register(
nameof(BarCount),
typeof(int),
typeof(NowPlayingButtonContent),
new PropertyMetadata(4));
///
/// Initializes a new instance of the class.
///
public NowPlayingButtonContent()
{
this.InitializeComponent();
_activeScale = new double[0];
_rectangles = new Rectangle[0];
_rectScaleTransforms = new ScaleTransform[0];
_dAnimations = new DoubleAnimation[0];
_storyboard = new Storyboard();
_random = new Random();
Loaded += NowPlayingButtonContent_Loaded;
}
private void NowPlayingButtonContent_Loaded(object sender, RoutedEventArgs e)
{
Loaded -= NowPlayingButtonContent_Loaded;
Unloaded += NowPlayingButtonContent_Unloaded;
CreateLayout();
CreateAndBeginStoryboard();
}
private void NowPlayingButtonContent_Unloaded(object sender, RoutedEventArgs e)
{
Unloaded -= NowPlayingButtonContent_Unloaded;
}
///
/// Gets or sets how many bars to display.
///
public int BarCount
{
get => (int)GetValue(BarCountProperty);
set
{
SetValue(BarCountProperty, value);
CreateLayout();
}
}
private void CreateLayout()
{
var columns = RootGrid.ColumnDefinitions;
columns.Clear();
_rectangles = new Rectangle[BarCount];
_rectScaleTransforms = new ScaleTransform[BarCount];
// Calculate the width of all rectangles to display
double rectWidth = (RootGrid.ActualWidth / BarCount) - (PADDING * (BarCount - 1));
for (int i = 0; i < BarCount; i++)
{
columns.Add(new ColumnDefinition());
var rect = CreateRectangle(rectWidth);
var scaleTransform = SetRectangleRenderTransform(rect);
scaleTransform.ScaleY = _random.NextDouble();
Grid.SetColumn(rect, i);
_rectangles[i] = rect;
_rectScaleTransforms[i] = scaleTransform;
RootGrid.Children.Add(rect);
}
}
private void CreateAndBeginStoryboard()
{
_storyboard = new Storyboard();
var timelines = _storyboard.Children;
_dAnimations = new DoubleAnimation[_rectangles.Length];
_activeScale = new double[_rectangles.Length];
for (int i = 0; i < _rectScaleTransforms.Length; i++)
{
_activeScale[i] = _random.NextDouble();
var dAnimation = new DoubleAnimation();
Storyboard.SetTarget(dAnimation, _rectScaleTransforms[i]);
Storyboard.SetTargetProperty(dAnimation, "ScaleY");
_dAnimations[i] = dAnimation;
timelines.Add(dAnimation);
}
_storyboard.Duration = new Duration(TimeSpan.FromSeconds(SECONDS));
_storyboard.Completed += Storyboard_Completed;
_storyboard.Begin();
}
private Rectangle CreateRectangle(double width)
{
var rect = new Rectangle();
rect.Fill = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 219, 13, 148));
rect.Width = width;
return rect;
}
private ScaleTransform SetRectangleRenderTransform(Rectangle rect)
{
var scaleTransform = new ScaleTransform();
rect.RenderTransformOrigin = new Windows.Foundation.Point(.5, 1);
rect.RenderTransform = scaleTransform;
return scaleTransform;
}
private void Storyboard_Completed(object sender, object e)
{
for (int i = 0; i < _dAnimations.Length; i++)
{
double value = _random.NextDouble();
double active = _activeScale[i];
double invalidMin = active - MINIMUM_CHANGE_FACTOR;
double invalidMax = active + MINIMUM_CHANGE_FACTOR;
invalidMin = Math.Max(invalidMin, MINIMUM_HEIGHT_FACTOR);
invalidMax = Math.Min(invalidMax, 1);
double invalidRange = invalidMax - invalidMin;
double invalidRangeFull = invalidRange + MINIMUM_HEIGHT_FACTOR;
value *= 1 - invalidRangeFull;
value += MINIMUM_HEIGHT_FACTOR;
if (value > invalidMin)
{
value += invalidRange;
}
double noise = _random.NextDouble();
noise *= POST_NOISE * 2;
noise -= POST_NOISE;
value += noise;
_activeScale[i] = value;
_dAnimations[i].To = value;
}
_storyboard.Begin();
}
}
}