...
 
Commits (86)
using System;
using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.UI.Xaml;
using System.Threading.Tasks;
using Microsoft.Graphics.Canvas.Effects;
namespace Slide2D.Images
{
public class Img
{
public CanvasBitmap Bmp { get; private set; }
public GaussianBlurEffect GaussianBlurCache { get; set; }
public ScaleEffect ScaleEffect { get; set; }
public string Src { get; private set; }
public double Height
{
get
{
if (Bmp != null) return Bmp.SizeInPixels.Height;
return -1;
}
}
public double Width
{
get
{
if (Bmp != null) return Bmp.SizeInPixels.Width;
return -1;
}
}
public float Scale { get; set; }
public float Opacity { get; set; }
public bool Loaded { get; set; }
public Img(string source)
{
Src = source;
Opacity = 0;
}
public async Task Initialize(ICanvasAnimatedControl cac)
{
Bmp = await CanvasBitmap.LoadAsync(cac, new Uri(Src));
Loaded = true;
}
}
}
\ No newline at end of file
using Microsoft.Graphics.Canvas.Effects;
using Microsoft.Graphics.Canvas.UI.Xaml;
using System;
using Windows.Foundation;
using VLC.Model;
using VLC.ViewModels;
using VLC.ViewModels.MusicVM;
#if WINDOWS_UWP
#else
// This namespace only works on Windows/Windows Phone 8.1 apps.
#endif
namespace Slide2D.Images
{
public class ImgSlideshow
{
private const int IntroFrameThreshold = 200;
private const int OutroFrameThreshold = 900;
private const int EndFrameThresholdDefaultPic = 1020;
private const int EndFrameThreshold = 1100;
private const float MaximumBlur = 10f;
private Random random = new Random();
// Debug only, to slow down frames
int threshold = 0;
private int frame = 0;
private bool fastChange;
private bool clearSlideshow;
private float blurAmount = MaximumBlur;
private int ImgIndex = 0;
private Img currentImg;
public ImgSlideshow()
{
Locator.MusicPlayerVM.PropertyChanged += MusicPlayerVM_PropertyChanged;
Navigated();
}
private void MusicPlayerVM_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(MusicPlayerVM.CurrentTrack))
{
Navigated();
}
}
async void Navigated()
{
var newPic = false;
if (Locator.NavigationService.CurrentPage == VLCPage.MusicPlayerPage)
{
if (Locator.MusicPlayerVM.CurrentTrack == null)
return;
var album = Locator.MediaLibrary.LoadAlbum(Locator.MusicPlayerVM.CurrentTrack.AlbumId);
if (album != null)
{
if (album.IsPictureLoaded)
{
currentImg = new Img(album.AlbumCoverFullUri);
newPic = true;
}
}
}
else
{
newPic = false;
clearSlideshow = true;
}
if (newPic)
{
MetroSlideshow.canvas.Paused = false;
frame = OutroFrameThreshold;
fastChange = true;
}
return;
}
public async void Update(ICanvasAnimatedControl sender, CanvasAnimatedUpdateEventArgs args)
{
try
{
if (currentImg == null) return;
if (!currentImg.Loaded)
{
await currentImg.Initialize(sender);
}
bool computeBlurPic = true;
if (frame < IntroFrameThreshold)
{
if (frame == 0)
{
// Set Default values
currentImg.Opacity = 0;
blurAmount = MaximumBlur;
}
blurAmount -= 0.025f;
}
else if (frame <= OutroFrameThreshold)
{
if (currentImg.GaussianBlurCache != null)
{
computeBlurPic = false;
}
}
else if (frame < 1000)
{
blurAmount += 0.025f;
}
if (computeBlurPic)
{
if (currentImg.Bmp == null)
return;
if (blurAmount < 10)
{
currentImg.GaussianBlurCache = new GaussianBlurEffect()
{
Source = currentImg.Bmp,
BlurAmount = blurAmount,
Optimization = EffectOptimization.Speed
};
}
else
{
}
}
float screenRatio = (float)MetroSlideshow.WindowWidth / (float)MetroSlideshow.WindowHeight;
float imgRatio = (float)currentImg.Width / (float)currentImg.Height;
if (currentImg.Width == -1 || currentImg.Height == -1) return;
if (imgRatio > screenRatio)
{
//img wider than screen, need to scale horizontally
currentImg.Scale = (float)(MetroSlideshow.WindowHeight / currentImg.Height);
}
else
{
currentImg.Scale = (float)(MetroSlideshow.WindowWidth / currentImg.Width);
}
// "Vector2" requires System.Numerics for UWP. But for some reason ScaleEffect can only use Windows.Foundation.Numerics,
// which you can't use to make vectors. So... we can't use this yet until we can figure out what's wrong here.
if (currentImg.GaussianBlurCache == null) return;
var saturationEffect = new SaturationEffect()
{
Source = currentImg.GaussianBlurCache,
Saturation = 1f,
};
var scaleEffect = new ScaleEffect()
{
Source = saturationEffect,
Scale = new System.Numerics.Vector2()
{
X = currentImg.Scale,
Y = currentImg.Scale
},
};
scaleEffect.CenterPoint = new System.Numerics.Vector2() { X = 0, Y = 0 };
currentImg.ScaleEffect = scaleEffect;
if (frame < IntroFrameThreshold)
{
currentImg.Opacity += 0.0020f;
}
else if (frame > OutroFrameThreshold)
{
var decrease = 0.0027f;
if (fastChange)
{
currentImg.Opacity -= decrease * 4;
}
else
{
currentImg.Opacity -= decrease;
}
}
}
catch { }
}
public async void Draw(ICanvasAnimatedControl sender, CanvasAnimatedDrawEventArgs args)
{
if (currentImg?.ScaleEffect != null)
{
//args.DrawingSession.DrawImage(currentImg.ScaleEffect, new System.Numerics.Vector2(), new Rect()
//{
// Height = MetroSlideshow.WindowHeight,
// Width = MetroSlideshow.WindowWidth
//}, currentImg.Opacity);
}
threshold++;
if (threshold == 1)
{
threshold = 0;
if (fastChange)
{
frame += 4;
}
else frame++;
}
if (frame < EndFrameThreshold)
return;
// Resetting variables
var artistCount = Locator.MediaLibrary.ArtistCount();
if (ImgIndex < artistCount - 1)
{
ImgIndex++;
}
else
{
ImgIndex = 0;
}
if (fastChange)
{
fastChange = false;
}
if (clearSlideshow)
{
sender.Paused = true;
}
frame = 0;
blurAmount = MaximumBlur;
}
}
}
using Microsoft.Graphics.Canvas.UI.Xaml;
using Slide2D.Images;
using System.Threading.Tasks;
using Windows.UI.Core;
using Windows.UI.Xaml;
namespace Slide2D
{
public class MetroSlideshow
{
public TaskCompletionSource<bool> IsLoaded = new TaskCompletionSource<bool>();
public static CanvasAnimatedControl canvas;
public static double WindowHeight;
public static double WindowWidth;
public delegate void WindowSizeChanged();
public static event WindowSizeChanged WindowSizeUpdated;
private ImgSlideshow slideshow;
private bool wasPausedBeforeCoreWindowDeactivation = false;
public MetroSlideshow()
{
SetWindowSize();
}
public void Initialize(ref CanvasAnimatedControl cac)
{
canvas = cac;
canvas.CreateResources += Canvas_CreateResources;
canvas.Update += Canvas_Update;
canvas.Draw += Canvas_Draw;
canvas.ForceSoftwareRenderer = false;
canvas.Paused = true;
float dpiLimit = 96.0f;
if (canvas.Dpi > dpiLimit)
{
canvas.DpiScale = dpiLimit / canvas.Dpi;
}
Window.Current.SizeChanged += Current_SizeChanged;
slideshow = new ImgSlideshow();
}
private void Current_SizeChanged(object sender, WindowSizeChangedEventArgs e)
{
SetWindowSize();
WindowSizeUpdated?.Invoke();
}
private void SetWindowSize()
{
WindowWidth = Window.Current.Bounds.Width;
WindowHeight = Window.Current.Bounds.Height;
}
private void Canvas_Update(ICanvasAnimatedControl sender, CanvasAnimatedUpdateEventArgs args)
{
slideshow.Update(sender, args);
}
private void Canvas_Draw(ICanvasAnimatedControl sender, CanvasAnimatedDrawEventArgs args)
{
slideshow.Draw(sender, args);
}
private void Canvas_CreateResources(CanvasAnimatedControl sender,
Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args)
{
IsLoaded.TrySetResult(true);
}
public bool IsPaused
{
get { return canvas != null && canvas.Paused; }
set { if (canvas != null) canvas.Paused = value; }
}
}
}
\ No newline at end of file
using Microsoft.Graphics.Canvas.Text;
using Microsoft.Graphics.Canvas.UI.Xaml;
using Slide2D;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Windows.UI;
namespace VLC_WinRT.Slideshow.Texts
{
public class Txt
{
public int Id { get; set; }
public string Content { get; set; }
public CanvasTextFormat Format { get; private set; }
public CanvasTextLayout TextLayout { get; private set; }
public Color Color { get; private set; }
public float RowHeight => Format.FontSize;
float posX;
float posY;
bool initialized = false;
private bool needToRecomputePosY;
public Txt(string content, Color col, CanvasTextFormat format)
{
Content = content;
Color = col;
Format = format;
MetroSlideshow.WindowSizeUpdated += MetroSlideshow_WindowSizeUpdated;
}
private void MetroSlideshow_WindowSizeUpdated()
{
needToRecomputePosY = true;
}
public void Draw(ref CanvasAnimatedDrawEventArgs drawArgs, ref List<Txt> txts)
{
if (!initialized)
{
if (TextLayout == null)
{
TextLayout = new CanvasTextLayout(drawArgs.DrawingSession, Content, Format, 0.0f, 0.0f)
{
WordWrapping = CanvasWordWrapping.NoWrap
};
}
switch (Format.Direction)
{
case CanvasTextDirection.LeftToRightThenTopToBottom:
posX = -(float)TextLayout.DrawBounds.Width;
break;
case CanvasTextDirection.RightToLeftThenTopToBottom:
posX = (float)((float)MetroSlideshow.WindowWidth + TextLayout.DrawBounds.Width);
break;
}
posY = ComputePosY(ref txts);
initialized = true;
}
if (needToRecomputePosY)
{
posY = ComputePosY(ref txts);
needToRecomputePosY = false;
}
switch (Format.Direction)
{
case CanvasTextDirection.LeftToRightThenTopToBottom:
if (posX < (MetroSlideshow.WindowWidth / 4) || posX > (MetroSlideshow.WindowWidth * (float)(3.0 / 4)))
{
posX += 3;
}
else
{
posX++;
}
if (posX > MetroSlideshow.WindowWidth || posY > MetroSlideshow.WindowHeight)
{
initialized = false;
}
break;
case CanvasTextDirection.RightToLeftThenTopToBottom:
if (posX < (MetroSlideshow.WindowWidth / 4) || posX > (MetroSlideshow.WindowWidth * (float)(3.0 / 4)))
{
posX -= 3;
}
else
{
posX--;
}
if (posX < 0 || posY > MetroSlideshow.WindowHeight)
{
initialized = false;
}
break;
}
drawArgs.DrawingSession.DrawTextLayout(TextLayout, posX, posY, Color);
}
float ComputePosY(ref List<Txt> txts)
{
// Considering a vertical margin of 15% of the height
float Y = 0;
var heightMargin = (float)MetroSlideshow.WindowHeight * 0.15;
var stackHeightTextOnTopItThis = txts.TakeWhile(x => x.Id < Id).Sum(x => x.RowHeight);
Y = (float)heightMargin + stackHeightTextOnTopItThis;
return Y;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>ad0c8b4f-7a03-42cc-b8da-bf8d50df822b</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>VLC_WinRT.Slideshow</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Images\Img.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Images\ImgSlideshow.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Slideshow.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Texts\Txt.cs" />
</ItemGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>232d02e1-f8dc-4a00-a7cd-0c422fc32b14</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="VLC_WinRT.Slideshow.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>
\ No newline at end of file
using System;
using System.Threading.Tasks;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.ViewManagement;
using VLC_WinRT.UI.Legacy.Views;
using VLC_WinRT.UI.Legacy.Views.UserControls.Shell;
namespace VLC_WinRT.Controls
{
public delegate void FlyoutCloseRequested(object sender, EventArgs e);
public delegate void FlyoutNavigated(object sender, EventArgs p);
public delegate void FlyoutClosed(object sender, EventArgs e);
public delegate void ContentSizeChanged(double newWidth);
[TemplatePart(Name = ContentPresenterName, Type = typeof(ContentPresenter))]
[TemplatePart(Name = FlyoutContentPresenterName, Type = typeof(Frame))]
[TemplatePart(Name = FlyoutFadeInName, Type = typeof(Storyboard))]
[TemplatePart(Name = FlyoutFadeOutName, Type = typeof(Storyboard))]
[TemplatePart(Name = FlyoutPlaneProjectionName, Type = typeof(PlaneProjection))]
[TemplatePart(Name = FlyoutGridContainerName, Type = typeof(Grid))]
[TemplatePart(Name = FlyoutBackgroundGridName, Type = typeof(Grid))]
public sealed class SplitShell : Control
{
public event FlyoutCloseRequested FlyoutCloseRequested;
public event FlyoutNavigated FlyoutNavigated;
public event FlyoutClosed FlyoutClosed;
public event ContentSizeChanged ContentSizeChanged;
public TaskCompletionSource<bool> TemplateApplied = new TaskCompletionSource<bool>();
private DispatcherTimer _windowResizerTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(200) };
private const string PageName = "Page";
private const string ContentPresenterName = "ContentPresenter";
private const string FlyoutContentPresenterName = "FlyoutContentPresenter";
private const string FlyoutFadeInName = "FlyoutFadeIn";
private const string FlyoutFadeOutName = "FlyoutFadeOut";
private const string TopBarFadeOutName = "TopBarFadeOut";
private const string TopBarFadeInName = "TopBarFadeIn";
private const string FlyoutPlaneProjectionName = "FlyoutPlaneProjection";
private const string FlyoutGridContainerName = "FlyoutGridContainer";
private const string FlyoutBackgroundGridName = "FlyoutBackgroundGrid";
private const string BackdropGridName = "backDrop";
private Page _page;
private Grid _flyoutGridContainer;
private Grid _flyoutBackgroundGrid;
private ContentPresenter _contentPresenter;
private Frame _flyoutContentPresenter;
//private BackDrop _backdrop;
private PlaneProjection _flyoutPlaneProjection;
private Storyboard _flyoutFadeIn;
private Storyboard _flyoutFadeOut;
private Storyboard _topBarFadeOut;
private Storyboard _topBarFadeIn;
public async void SetContentPresenter(object contentPresenter)
{
await TemplateApplied.Task;
_contentPresenter.Content = contentPresenter;
}
public void SetFlyoutContentPresenter(object content, object param)
{
//FIXME: Remove all those, but that's a looooong refactoring.
//await TemplateApplied.Task;
_flyoutContentPresenter.Navigate((Type)content, param);
ShowFlyout();
Responsive();
}
public async void SetFooterContentPresenter(object content)
{
await TemplateApplied.Task;
_page.BottomAppBar = content as CommandBar;
if (content == null)
return;
}
#region Content Property
public DependencyObject Content
{
get { return (DependencyObject)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
"Content", typeof(DependencyObject), typeof(SplitShell), new PropertyMetadata(default(DependencyObject), ContentPropertyChangedCallback));
private static void ContentPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var that = (SplitShell)dependencyObject;
that.SetContentPresenter(dependencyPropertyChangedEventArgs.NewValue);
}
#endregion
#region RFlyoutContent Property
public bool FlyoutAsHeader
{
get { return (bool)GetValue(FlyoutAsHeaderProperty); }
set { SetValue(FlyoutAsHeaderProperty, value); }
}
public static readonly DependencyProperty FlyoutAsHeaderProperty = DependencyProperty.Register(
nameof(FlyoutAsHeader), typeof(bool), typeof(SplitShell),
new PropertyMetadata(default(bool), FlyoutAsHeaderPropertyChangedCallback));
private static void FlyoutAsHeaderPropertyChangedCallback(DependencyObject dO, DependencyPropertyChangedEventArgs args)
{
var that = (SplitShell)dO;
that.Responsive();
}
#endregion
#region FooterContent Property
public DependencyObject FooterContent
{
get { return (DependencyObject)GetValue(FooterContentProperty); }
set { SetValue(FooterContentProperty, value); }
}
public static readonly DependencyProperty FooterContentProperty = DependencyProperty.Register(
nameof(FooterContent), typeof(DependencyObject), typeof(SplitShell),
new PropertyMetadata(default(DependencyObject), FooterContentPropertyChangedCallback));
private static void FooterContentPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var that = (SplitShell)dependencyObject;
that.SetFooterContentPresenter(dependencyPropertyChangedEventArgs.NewValue);
}
#endregion
public SplitShell()
{
DefaultStyleKey = typeof(SplitShell);
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
_page = (Page)GetTemplateChild(PageName);
_contentPresenter = (ContentPresenter)GetTemplateChild(ContentPresenterName);
_flyoutContentPresenter = (Frame)GetTemplateChild(FlyoutContentPresenterName);
_flyoutFadeIn = (Storyboard)GetTemplateChild(FlyoutFadeInName);
_flyoutFadeOut = (Storyboard)GetTemplateChild(FlyoutFadeOutName);
_topBarFadeOut = (Storyboard)GetTemplateChild(TopBarFadeOutName);
_topBarFadeIn = (Storyboard)GetTemplateChild(TopBarFadeInName);
_flyoutPlaneProjection = (PlaneProjection)GetTemplateChild(FlyoutPlaneProjectionName);
_flyoutGridContainer = (Grid)GetTemplateChild(FlyoutGridContainerName);
_flyoutBackgroundGrid = (Grid)GetTemplateChild(FlyoutBackgroundGridName);
//_backdrop = (BackDrop)GetTemplateChild(BackdropGridName);
Responsive();
Window.Current.SizeChanged += Current_SizeChanged;
_contentPresenter.Width = Window.Current.Bounds.Width;
TemplateApplied.SetResult(true);
_flyoutGridContainer.Visibility = Visibility.Collapsed;
if (_flyoutBackgroundGrid != null