diff --git a/MoeIDE/EditorBackground.cs b/MoeIDE/EditorBackground.cs index 7783d80..a96801f 100644 --- a/MoeIDE/EditorBackground.cs +++ b/MoeIDE/EditorBackground.cs @@ -114,6 +114,11 @@ private void SetSolidBrush(ThemeChangedEventArgs e) var color = uiShell.GetThemedWPFColor(EnvironmentColors.SystemWindowColorKey); var brush = new SolidColorBrush(color); brush.Freeze(); + if (hostRootVisual == null) + { + var source = PresentationSource.FromVisual(control) as HwndSource; + hostRootVisual = source.RootVisual as Panel; + } hostRootVisual.Background = brush; } diff --git a/MoeIDE/ImageSwitcher.xaml b/MoeIDE/ImageSwitcher.xaml new file mode 100644 index 0000000..2968a62 --- /dev/null +++ b/MoeIDE/ImageSwitcher.xaml @@ -0,0 +1,13 @@ + + + + + + diff --git a/MoeIDE/ImageSwitcher.xaml.cs b/MoeIDE/ImageSwitcher.xaml.cs new file mode 100644 index 0000000..b13497a --- /dev/null +++ b/MoeIDE/ImageSwitcher.xaml.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Media.Imaging; +using System.Windows.Threading; + +namespace Meowtrix.MoeIDE +{ + /// + /// Interaction logic for ImageSwitcher.xaml + /// + public partial class ImageSwitcher : UserControl + { + public static readonly DependencyProperty StretchProperty = + DependencyProperty.Register("Stretch", typeof(Stretch), typeof(ImageSwitcher), new PropertyMetadata(Stretch.UniformToFill)); + + public Stretch Stretch + { + get { return (Stretch)GetValue(StretchProperty); } + set { SetValue(StretchProperty, value); } + } + + public static readonly DependencyProperty IntervalProperty = + DependencyProperty.Register("Interval", typeof(double), typeof(ImageSwitcher), new PropertyMetadata(120000.0)); + + public double Interval + { + get { return (double)GetValue(IntervalProperty); } + set + { + if ((double)GetValue(IntervalProperty) != value) + { + if (backgroundChanger != null) + { + backgroundChanger.Stop(); + backgroundChanger.Interval = TimeSpan.FromMilliseconds(value); + if (!Hibernating) + { + backgroundChanger.Start(); + } + } + SetValue(IntervalProperty, value); + } + } + } + + public enum Transitions + { + [Description("Smooth fade between 2 images")]FADE, // Implemented :D + [Description("Fade-out old image, fade-in new image")] FADE_IN_OUT, // todo: later + [Description("Slide new image to the left")] SLIDE_TO_LEFT, // todo: later + [Description("Slide new image to the right")] SLIDE_TO_RIGHT, //todo: later + } + + private DispatcherTimer backgroundChanger; + private Queue imageFiles; + private Storyboard story = new Storyboard(); + private bool Hibernating = true; + + public double TransitionDuration; + public Transitions TransitionType; + public Image ActiveImage; + + public ImageSwitcher(string mustExistsFolderPath) + { + TransitionType = Transitions.FADE; + Interval = 30000.0; + Stretch = Stretch.UniformToFill; + TransitionDuration = 2000.0; + var files = Directory.EnumerateFiles(mustExistsFolderPath).Where(f => f.EndsWith(".jpg") || f.EndsWith(".png")); + imageFiles = new Queue(files); + backgroundChanger = new DispatcherTimer + { + Interval = TimeSpan.FromMilliseconds(Interval) // 2 minutes | todo: implement on setting Page + }; + backgroundChanger.Tick += BackgroundChanger_Tick; + + InitializeComponent(); + } + + public void Hibernate() + { + backgroundChanger.Stop(); + Hibernating = true; + } + + public void Wake() + { + if (!Hibernating) + { + if (!backgroundChanger.IsEnabled) + { + backgroundChanger.Start(); + } + return; + } + + if (imageFiles.Count > 0) + { + var t = imageFiles.Dequeue(); + SwitchTo(LoadImage(t)); + imageFiles.Enqueue(t); + } + if (imageFiles.Count > 1) + { + backgroundChanger.Start(); + } + Hibernating = false; + } + + private void BackgroundChanger_Tick(object sender, EventArgs e) + { + backgroundChanger.Stop(); + + var t = imageFiles.Dequeue(); + ImageSource newImg = LoadImage(t); + imageFiles.Enqueue(t); + SwitchTo(newImg, TransitionType); + + backgroundChanger.Start(); + } + + public void SwitchTo(ImageSource newImage) + { + SwitchTo(newImage, TransitionType); + } + + public void SwitchTo(ImageSource newImage, Transitions transition) + { + if (newImage == null) + { + return; + } + switch (transition) + { + default: + case Transitions.FADE: + if (ActiveImage == behind) + { + front.Source = newImage; + ActiveImage = front; + front.BeginAnimation(OpacityProperty, + new DoubleAnimation(1, + new Duration(TimeSpan.FromMilliseconds(TransitionDuration)))); + } + else + { + behind.Source = newImage; + ActiveImage = behind; + front.BeginAnimation(OpacityProperty, + new DoubleAnimation(0, + new Duration(TimeSpan.FromMilliseconds(TransitionDuration)))); + } + break; + case Transitions.FADE_IN_OUT: + break; + case Transitions.SLIDE_TO_LEFT: + break; + case Transitions.SLIDE_TO_RIGHT: + break; + } + } + + private BitmapFrame LoadImage(string filename) + { + var imagesource = BitmapFrame.Create(new Uri(filename), BitmapCreateOptions.None, BitmapCacheOption.OnLoad); + imagesource.Freeze(); + return imagesource; + } + + public void ChangeFolder(string folderPath) + { + if (imageFiles.Count > 0 && imageFiles.Peek().Contains(folderPath)) + { + return; + } + backgroundChanger.Stop(); + + var files = Directory.EnumerateFiles(folderPath).Where(f => f.EndsWith(".jpg") || f.EndsWith(".png")); + imageFiles = new Queue(files); + if (!Hibernating) + { + if (imageFiles.Count > 0) + { + var t = imageFiles.Dequeue(); + SwitchTo(LoadImage(t), TransitionType); + imageFiles.Enqueue(t); + } + if (imageFiles.Count > 1) + { + backgroundChanger.Start(); + } + } + } + + private void behind_SourceUpdated(object sender, DataTransferEventArgs e) + { + ActiveImage = behind; + } + + private void front_SourceUpdated(object sender, DataTransferEventArgs e) + { + ActiveImage = front; + } + } +} \ No newline at end of file diff --git a/MoeIDE/MoeIDE.csproj b/MoeIDE/MoeIDE.csproj index be9c70f..d6aedcb 100644 --- a/MoeIDE/MoeIDE.csproj +++ b/MoeIDE/MoeIDE.csproj @@ -55,6 +55,9 @@ + + ImageSwitcher.xaml + @@ -113,30 +116,30 @@ False - - - + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + @@ -164,13 +167,17 @@ + + Designer + MSBuild:Compile + Designer MSBuild:Compile - + {15cacac9-9e3c-4056-a26d-b4b9cd7fe596} Meowtrix.WPF.Extend BuiltProjectOutputGroup%3bBuiltProjectOutputGroupDependencies%3bGetCopyToOutputDirectoryItems%3bSatelliteDllsProjectOutputGroup diff --git a/MoeIDE/SettingsModel.cs b/MoeIDE/SettingsModel.cs index 574f77a..cd007ed 100644 --- a/MoeIDE/SettingsModel.cs +++ b/MoeIDE/SettingsModel.cs @@ -9,21 +9,25 @@ namespace Meowtrix.MoeIDE public class SettingsModel { [Serializable] - public class ImageInfo + public class SettingPack { public string Filename { get; set; } + public bool IsLive { get; set; } = false; + public string Folderpath { get; set; } + public double Interval { get; set; } = 30000.0; + public double TransitionDuration { get; set; } = 2000.0; public Stretch Stretch { get; set; } = Stretch.UniformToFill; public HorizontalAlignment HorizontalAlignment { get; set; } = HorizontalAlignment.Center; public VerticalAlignment VerticalAlignment { get; set; } = VerticalAlignment.Center; public Color BackColor { get; set; } = Colors.Transparent; public double Opacity { get; set; } = 1.0; public double Blur { get; set; } = 0.0; - public ImageInfo Clone() => (ImageInfo)MemberwiseClone(); + public SettingPack Clone() => (SettingPack)MemberwiseClone(); } - public ImageInfo MainBackground { get; set; } = new ImageInfo(); + public SettingPack MainSetting { get; set; } = new SettingPack(); public SettingsModel Clone() => new SettingsModel { - MainBackground = this.MainBackground.Clone() + MainSetting = this.MainSetting.Clone() }; } } diff --git a/MoeIDE/SettingsPage.xaml b/MoeIDE/SettingsPage.xaml index 5dc16b0..1c8788e 100644 --- a/MoeIDE/SettingsPage.xaml +++ b/MoeIDE/SettingsPage.xaml @@ -6,7 +6,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:meowtrix="urn:meowtrix" d:DataContext="{d:DesignInstance local:SettingsModel}" - d:DesignHeight="300" d:DesignWidth="300" + d:DesignWidth="300" Focusable="True" mc:Ignorable="d"> @@ -19,7 +19,73 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -36,10 +102,6 @@ - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - MoeIDE @@ -128,7 +127,7 @@ ※Please select a transparent theme in Environment->General->Color Theme to get best experience. - Main Background + Static Background Settings File name @@ -151,6 +150,31 @@ Blur radius + + Select Background Mode + + + Static + + + Live (Experimental) + + + Live Background Settings + + + Image Settings + + + Folder path + + + Interval (Milliseconds) + + + Trans. Duration + + resources\moeide.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a diff --git a/MoeIDE/WindowBackground.cs b/MoeIDE/WindowBackground.cs index 3b13707..4ed3802 100644 --- a/MoeIDE/WindowBackground.cs +++ b/MoeIDE/WindowBackground.cs @@ -10,44 +10,79 @@ namespace Meowtrix.MoeIDE public class WindowBackground { private readonly Border parentBorder = new Border(); - private readonly Image imagecontrol = new Image(); + private readonly ImageSwitcher liveImageControl = null; + private readonly Image staticImageControl = new Image(); + private bool IsLiveMode = false; + public WindowBackground(Window window) { if (window.IsLoaded) Window_Loaded(window, null); window.Loaded += Window_Loaded; SettingsManager.SettingsUpdated += SettingsUpdated; + liveImageControl = new ImageSwitcher(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)); } private void SettingsUpdated(SettingsModel oldSettings, SettingsModel newSettings) { try { - var imagesource = BitmapFrame.Create(new Uri(newSettings.MainBackground.Filename), BitmapCreateOptions.None, BitmapCacheOption.OnLoad); - imagesource.Freeze(); - imagecontrol.Source = imagesource; - imagecontrol.Stretch = newSettings.MainBackground.Stretch; - imagecontrol.HorizontalAlignment = newSettings.MainBackground.HorizontalAlignment; - imagecontrol.VerticalAlignment = newSettings.MainBackground.VerticalAlignment; - var br = new SolidColorBrush(newSettings.MainBackground.BackColor); + IsLiveMode = newSettings.MainSetting.IsLive; + if (IsLiveMode) + { + liveImageControl.ChangeFolder(newSettings.MainSetting.Folderpath); + liveImageControl.Stretch = newSettings.MainSetting.Stretch; + liveImageControl.Interval = newSettings.MainSetting.Interval; + liveImageControl.TransitionDuration = newSettings.MainSetting.TransitionDuration; + liveImageControl.HorizontalAlignment = newSettings.MainSetting.HorizontalAlignment; + liveImageControl.VerticalAlignment = newSettings.MainSetting.VerticalAlignment; + + liveImageControl.Wake(); + } + else + { + liveImageControl.Hibernate(); + + var imagesource = BitmapFrame.Create(new Uri(newSettings.MainSetting.Filename), BitmapCreateOptions.None, BitmapCacheOption.OnLoad); + imagesource.Freeze(); + staticImageControl.Source = imagesource; + staticImageControl.Stretch = newSettings.MainSetting.Stretch; + staticImageControl.HorizontalAlignment = newSettings.MainSetting.HorizontalAlignment; + staticImageControl.VerticalAlignment = newSettings.MainSetting.VerticalAlignment; + } + + var br = new SolidColorBrush(newSettings.MainSetting.BackColor); br.Freeze(); parentBorder.Background = br; - imagecontrol.Opacity = newSettings.MainBackground.Opacity; - double blur = newSettings.MainBackground.Blur; + + liveImageControl.Opacity = newSettings.MainSetting.Opacity; + staticImageControl.Opacity = newSettings.MainSetting.Opacity; + + double blur = newSettings.MainSetting.Blur; if (blur == 0.0) - imagecontrol.Effect = null; - else imagecontrol.Effect = new BlurEffect { Radius = blur }; + { + liveImageControl.Effect = null; + staticImageControl.Effect = null; + } + else + { + liveImageControl.Effect = new BlurEffect { Radius = blur }; + staticImageControl.Effect = new BlurEffect { Radius = blur }; + } + + parentBorder.Child = IsLiveMode ? (UIElement)liveImageControl : staticImageControl; } catch { - imagecontrol.Source = null; + liveImageControl.Hibernate(); + staticImageControl.Source = null; + parentBorder.Child = staticImageControl; } } private void Window_Loaded(object sender, RoutedEventArgs e) { var mainwindow = (Window)sender; - - parentBorder.Child = imagecontrol; + var cache = new BitmapCache { SnapsToDevicePixels = true }; cache.Freeze(); parentBorder.CacheMode = cache;