diff --git a/Audio.cs b/Audio.cs index a730a00..5578f3d 100644 --- a/Audio.cs +++ b/Audio.cs @@ -71,5 +71,4 @@ private static byte[] GetWavResource(string wav) } } } - } \ No newline at end of file diff --git a/BabySmash.csproj b/BabySmash.csproj index 9e52b32..9473dd2 100644 --- a/BabySmash.csproj +++ b/BabySmash.csproj @@ -1,5 +1,5 @@  - + Debug AnyCPU @@ -56,6 +56,7 @@ 4 x86 AllRules.ruleset + false pdbonly @@ -65,9 +66,16 @@ prompt 4 AllRules.ruleset + false + + + + packages\Newtonsoft.Json.9.0.1\lib\net35\Newtonsoft.Json.dll + True + 3.0 @@ -77,9 +85,7 @@ - - 3.0 - + 3.5 @@ -104,24 +110,16 @@ MSBuild:Compile Designer - MSBuild:Compile - Designer - Designer - MSBuild:Compile MSBuild:Compile Designer - Designer - MSBuild:Compile MSBuild:Compile Designer - Designer - MSBuild:Compile MSBuild:Compile Designer @@ -130,28 +128,20 @@ Designer - Designer - MSBuild:Compile MSBuild:Compile Designer - Designer - MSBuild:Compile MSBuild:Compile Designer - Designer - MSBuild:Compile MSBuild:Compile Designer MSBuild:Compile Designer - MSBuild:Compile - Designer CoolCircle.xaml @@ -182,44 +172,30 @@ MSBuild:Compile Designer - MSBuild:Compile - Designer - Designer - MSBuild:Compile MSBuild:Compile Designer - Designer - MSBuild:Compile MSBuild:Compile Designer - Designer - MSBuild:Compile MSBuild:Compile Designer - Designer - MSBuild:Compile MSBuild:Compile Designer - Designer - MSBuild:Compile MSBuild:Compile Designer MSBuild:Compile Designer - MSBuild:Compile - Designer App.xaml @@ -277,12 +253,19 @@ + SettingsSingleFileGenerator Settings.Designer.cs + + Always + + + Always + @@ -360,9 +343,8 @@ --> - - + \ No newline at end of file diff --git a/BabySmash.sln b/BabySmash.sln index 6bb4042..a195eea 100644 --- a/BabySmash.sln +++ b/BabySmash.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.22609.0 +VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BabySmash", "BabySmash.csproj", "{FB378E07-FDE4-4FC7-9210-68F80B561164}" EndProject diff --git a/Controller.cs b/Controller.cs index a4a4fcf..e22c82c 100644 --- a/Controller.cs +++ b/Controller.cs @@ -5,7 +5,6 @@ using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; -using System.Speech.Synthesis; using System.Threading; using System.Windows; using System.Windows.Controls; @@ -22,6 +21,13 @@ namespace BabySmash { + using System.Globalization; + using System.IO; + using System.Speech.Synthesis; + using System.Text; + + using Newtonsoft.Json; + public class Controller { [DllImport("user32.dll")] @@ -31,7 +37,7 @@ public class Controller private static extern bool SetForegroundWindow(IntPtr hWnd); private static Controller instance = new Controller(); - + public bool isOptionsDialogShown { get; set; } private bool isDrawing = false; private readonly SpeechSynthesizer objSpeech = new SpeechSynthesizer(); @@ -179,35 +185,17 @@ void timer_Tick(object sender, EventArgs e) public void ProcessKey(FrameworkElement uie, KeyEventArgs e) { - bool Alt = (Keyboard.Modifiers & ModifierKeys.Alt) != 0; - bool Control = (Keyboard.Modifiers & ModifierKeys.Control) != 0; - bool Shift = (Keyboard.Modifiers & ModifierKeys.Shift) != 0; - if (uie.IsMouseCaptured) { uie.ReleaseMouseCapture(); } - - //TODO: Might be able to remove this: http://www.ageektrapped.com/blog/using-commands-in-babysmash/ - if (Alt && Control && Shift && e.Key == Key.O) - { - ShowOptionsDialog(); - e.Handled = true; - return; - } - + char displayChar = GetDisplayChar(e.Key); AddFigure(uie, displayChar); } private char GetDisplayChar(Key key) { - // If a letter was pressed, display the letter. - if (key >= Key.A && key <= Key.Z) - { - return (char)('A' + key - Key.A); - } - // If a number on the normal number track is pressed, display the number. if (key >= Key.D0 && key <= Key.D9) { @@ -220,8 +208,71 @@ private char GetDisplayChar(Key key) return (char)('0' + key - Key.NumPad0); } - // Otherwise, display a random shape. - return '*'; + try + { + return char.ToUpperInvariant(TryGetLetter(key)); + } + catch (Exception ex) + { + Debug.Assert(false, ex.ToString()); + return '*'; + } + } + + public enum MapType : uint + { + MAPVK_VK_TO_VSC = 0x0, + MAPVK_VSC_TO_VK = 0x1, + MAPVK_VK_TO_CHAR = 0x2, + MAPVK_VSC_TO_VK_EX = 0x3, + } + + [DllImport("user32.dll")] + public static extern int ToUnicode( + uint wVirtKey, + uint wScanCode, + byte[] lpKeyState, + [Out, MarshalAs(UnmanagedType.LPWStr, SizeParamIndex = 4)] + StringBuilder pwszBuff, + int cchBuff, + uint wFlags); + + [DllImport("user32.dll")] + public static extern bool GetKeyboardState(byte[] lpKeyState); + + [DllImport("user32.dll")] + public static extern uint MapVirtualKey(uint uCode, MapType uMapType); + + private static char TryGetLetter(Key key) + { + char ch = ' '; + + int virtualKey = KeyInterop.VirtualKeyFromKey(key); + byte[] keyboardState = new byte[256]; + GetKeyboardState(keyboardState); + + uint scanCode = MapVirtualKey((uint)virtualKey, MapType.MAPVK_VK_TO_VSC); + StringBuilder stringBuilder = new StringBuilder(2); + + int result = ToUnicode((uint)virtualKey, scanCode, keyboardState, stringBuilder, stringBuilder.Capacity, 0); + switch (result) + { + case -1: + break; + case 0: + break; + case 1: + { + ch = stringBuilder[0]; + break; + } + default: + { + ch = stringBuilder[0]; + break; + } + } + return ch; } private void AddFigure(FrameworkElement uie, char c) @@ -246,8 +297,8 @@ private void AddFigure(FrameworkElement uie, char c) Canvas.SetTop(f, Utils.RandomBetweenTwoNumbers(0, Convert.ToInt32(window.ActualHeight - f.Height))); Storyboard storyboard = Animation.CreateDPAnimation(uie, f, - UIElement.OpacityProperty, - new Duration(TimeSpan.FromSeconds(Settings.Default.FadeAfter)), 1, 0); + UIElement.OpacityProperty, + new Duration(TimeSpan.FromSeconds(Settings.Default.FadeAfter)), 1, 0); if (Settings.Default.FadeAway) storyboard.Begin(uie); IHasFace face = f as IHasFace; @@ -347,9 +398,44 @@ public void PlaySound(FigureTemplate template) } else { - SpeakString(Utils.ColorToString(template.Color) + " " + template.Name); + SpeakString(GetLocalizedString(Utils.ColorToString(template.Color)) + " " + template.Name); + } + } + } + + /// + /// Returns if value or culture is not found. + /// + public static string GetLocalizedString(string key) + { + CultureInfo keyboardLanguage = System.Windows.Forms.InputLanguage.CurrentInputLanguage.Culture; + string culture = keyboardLanguage.Name; + string path = $@"Resources\Strings\{culture}.json"; + string path2 = @"Resources\Strings\en-EN.json"; + string jsonConfig = null; + if (File.Exists(path)) + { + jsonConfig = File.ReadAllText(path); + } + else if (File.Exists(path2)) + { + jsonConfig = File.ReadAllText(path2); + } + + if (jsonConfig != null) + { + Dictionary config = JsonConvert.DeserializeObject>(jsonConfig); + if (config.ContainsKey(key)) + { + return config[key].ToString(); } } + else + { + System.Diagnostics.Debug.Assert(false, "No file"); + } + + return key; } private void PlayLaughter() @@ -370,6 +456,31 @@ private class ThreadedSpeak public ThreadedSpeak(string Word) { this.Word = Word; + CultureInfo keyboardLanguage = System.Windows.Forms.InputLanguage.CurrentInputLanguage.Culture; + InstalledVoice neededVoice = this.SpeechSynth.GetInstalledVoices(keyboardLanguage).FirstOrDefault(); + if (neededVoice == null) + { + //http://superuser.com/questions/590779/how-to-install-more-voices-to-windows-speech + //https://msdn.microsoft.com/en-us/library/windows.media.speechsynthesis.speechsynthesizer.voice.aspx + //http://stackoverflow.com/questions/34776593/speechsynthesizer-selectvoice-fails-with-no-matching-voice-is-installed-or-th + this.Word = "Unsupported Language"; + } + else if (!neededVoice.Enabled) + { + this.Word = "Voice Disabled"; + } + else + { + try + { + this.SpeechSynth.SelectVoice(neededVoice.VoiceInfo.Name); + } + catch (Exception ex) + { + Debug.Assert(false, ex.ToString()); + } + } + SpeechSynth.Rate = -1; SpeechSynth.Volume = 100; } @@ -391,7 +502,7 @@ private void Start() } } - private void ShowOptionsDialog() + public void ShowOptionsDialog() { bool foo = Settings.Default.TransparentBackground; isOptionsDialogShown = true; @@ -415,8 +526,8 @@ private void ShowOptionsDialog() if (foo != Settings.Default.TransparentBackground) { MessageBoxResult result = MessageBox.Show( - "You've changed the Window Transparency Option. We'll need to restart BabySmash! for you to see the change. Pressing YES will restart BabySmash!. Is that OK?", - "Need to Restart", MessageBoxButton.YesNo, MessageBoxImage.Question); + "You've changed the Window Transparency Option. We'll need to restart BabySmash! for you to see the change. Pressing YES will restart BabySmash!. Is that OK?", + "Need to Restart", MessageBoxButton.YesNo, MessageBoxImage.Question); if (result == MessageBoxResult.Yes) { Application.Current.Shutdown(); diff --git a/Extensions/ObjectExtensions.cs b/Extensions/ObjectExtensions.cs new file mode 100644 index 0000000..d1a0e49 --- /dev/null +++ b/Extensions/ObjectExtensions.cs @@ -0,0 +1,71 @@ +namespace BabySmash.Extensions +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Reflection; + + /// + /// Contains extension methods for objects + /// + public static class ObjectExtensions + { + /// + /// Uses reflection to find a private field and validate its type. + /// + /// The type that declares the field. FlattenHierarchy doesn't work for private fields, so you have to pass the base type that declares the field. + /// Expected field type. + /// Name of the field to read. + /// Field information. + /// + /// When field is not found or it is of incorrect type. + + public static FieldInfo GetField(this Type ownerType, Type valueType, string fieldName) + { + FieldInfo field = ownerType.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance); + if (field == null) + { + throw new ArgumentException($"Failed to find field '{fieldName}' on type {ownerType.FullName}."); + } + + if (!valueType.IsAssignableFrom(field.FieldType)) + { + throw new ArgumentException($"Field '{fieldName}' on type {ownerType.FullName} is {field.FieldType.FullName}, but expected {valueType.FullName}."); + } + + return field; + } + + /// + /// Uses reflection to read a value of a private field. + /// + /// The type that declares the field. FlattenHierarchy doesn't work for private fields, so you have to pass the base type that declares the field. + /// Expected field type. + /// The instance to read the field value from. + /// Name of the field to read. + /// Field value. + /// + /// When field is not found or it is of incorrect type. + [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "ReadField", Justification = "'Read' is a clear verb and 'field value' is the subject.")] + public static TValue ReadFieldValue(this TOwner owner, string fieldName) + { + FieldInfo field = GetField(typeof(TOwner), typeof(TValue), fieldName); + return (TValue)field.GetValue(owner); + } + + /// + /// Uses reflection to set a value of a private field. + /// + /// The type that declares the field. FlattenHierarchy doesn't work for private fields, so you have to pass the base type that declares the field. + /// Expected field type. + /// The instance to write the field value to. + /// Name of the field to write. + /// The value to set. + /// + /// When field is not found or it is of incorrect type. + public static void WriteFieldValue(this TOwner owner, string fieldName, TValue value) + { + FieldInfo field = GetField(typeof(TOwner), typeof(TValue), fieldName); + field.SetValue(owner, value); + } + } +} \ No newline at end of file diff --git a/KeyboardHook.cs b/KeyboardHook.cs index 0e6521d..edcf4d6 100644 --- a/KeyboardHook.cs +++ b/KeyboardHook.cs @@ -20,7 +20,7 @@ public static IntPtr SetHook(LowLevelKeyboardProc proc) using (Process curProcess = Process.GetCurrentProcess()) using (ProcessModule curModule = curProcess.MainModule) { - return SetWindowsHookEx(WH_KEYBOARD_LL, proc,GetModuleHandle(curModule.ModuleName), 0); + return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0); } } diff --git a/MainWindow.xaml b/MainWindow.xaml index b45bf5f..b8c0b5c 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -1,30 +1,37 @@  + AllowsTransparency="True"> - - - + + - - - - - - + + + + + + - - - - - - + + + + + + + + + + + + + - + - - - - - - BabySmash! by Scott Hanselman with community contributions! - http://www.babysmash.com + + + + + + BabySmash! by Scott Hanselman with community contributions! - http://www.babysmash.com - Ctrl-Shift-Alt-O for options, ALT-F4 to exit - + Ctrl-Shift-Alt-O for options, ALT-F4 to exit + - - - - - + + + + + Updating BabySmash in the background... - + - + \ No newline at end of file diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 45095a7..95b4003 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -1,16 +1,6 @@ -using System; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Diagnostics; -using System.Speech.Synthesis; -using System.Windows; +using System.Windows; using System.Windows.Controls; -using System.Windows.Data; using System.Windows.Input; -using System.Windows.Navigation; -using System.Windows.Shapes; -using BabySmash.Properties; using System.Windows.Media; namespace BabySmash @@ -22,7 +12,7 @@ public partial class MainWindow : Window private UserControl customCursor; public UserControl CustomCursor { get { return customCursor; } set { customCursor = value; } } - + public void AddFigure(UserControl c) { this.figuresCanvas.Children.Add(c); @@ -30,7 +20,7 @@ public void AddFigure(UserControl c) public void RemoveFigure(UserControl c) { - this.figuresCanvas.Children.Remove(c); + this.figuresCanvas.Children.Remove(c); } public MainWindow(Controller c) @@ -44,52 +34,52 @@ public MainWindow(Controller c) protected override void OnMouseWheel(MouseWheelEventArgs e) { - base.OnMouseWheel(e); - controller.MouseWheel(this, e); + base.OnMouseWheel(e); + controller.MouseWheel(this, e); } protected override void OnMouseUp(MouseButtonEventArgs e) { - base.OnMouseUp(e); - controller.MouseUp(this, e); + base.OnMouseUp(e); + controller.MouseUp(this, e); } protected override void OnMouseDown(MouseButtonEventArgs e) { - base.OnMouseDown(e); - controller.MouseDown(this, e); + base.OnMouseDown(e); + controller.MouseDown(this, e); } protected override void OnMouseEnter(MouseEventArgs e) { - base.OnMouseEnter(e); - AssertCursor(); - CustomCursor.Visibility = Visibility.Visible; + base.OnMouseEnter(e); + AssertCursor(); + CustomCursor.Visibility = Visibility.Visible; } protected override void OnMouseLeave(MouseEventArgs e) { - base.OnMouseLeave(e); - CustomCursor.Visibility = Visibility.Hidden; + base.OnMouseLeave(e); + CustomCursor.Visibility = Visibility.Hidden; } protected override void OnMouseMove(MouseEventArgs e) { - base.OnMouseMove(e); - if (controller.isOptionsDialogShown == false) - { - CustomCursor.Visibility = Visibility.Visible; - Point p = e.GetPosition(mouseDragCanvas); - double pX = p.X; - double pY = p.Y; - Cursor = Cursors.None; - Canvas.SetTop(CustomCursor, pY); - Canvas.SetLeft(CustomCursor, pX); - Canvas.SetZIndex(CustomCursor, int.MaxValue); - } - controller.MouseMove(this, e); + base.OnMouseMove(e); + if (controller.isOptionsDialogShown == false) + { + CustomCursor.Visibility = Visibility.Visible; + Point p = e.GetPosition(mouseDragCanvas); + double pX = p.X; + double pY = p.Y; + Cursor = Cursors.None; + Canvas.SetTop(CustomCursor, pY); + Canvas.SetLeft(CustomCursor, pX); + Canvas.SetZIndex(CustomCursor, int.MaxValue); + } + controller.MouseMove(this, e); } - + protected override void OnKeyUp(KeyEventArgs e) { base.OnKeyUp(e); @@ -105,24 +95,28 @@ protected override void OnLostMouseCapture(MouseEventArgs e) internal void AssertCursor() { - try - { - mouseCursorCanvas.Children.Clear(); - CustomCursor = Utils.GetCursor(); - if (CustomCursor.Parent != null) - { - ((Canvas)CustomCursor.Parent).Children.Remove(CustomCursor); - } - CustomCursor.RenderTransform = new ScaleTransform(0.5, 0.5); - CustomCursor.Name = "customCursor"; - mouseCursorCanvas.Children.Insert(0, CustomCursor); //in front! - CustomCursor.Visibility = Visibility.Hidden; - } - catch (System.NotSupportedException) - { - //we can die here if we ALT-F4 while in the Options Dialog - } + try + { + mouseCursorCanvas.Children.Clear(); + CustomCursor = Utils.GetCursor(); + if (CustomCursor.Parent != null) + { + ((Canvas)CustomCursor.Parent).Children.Remove(CustomCursor); + } + CustomCursor.RenderTransform = new ScaleTransform(0.5, 0.5); + CustomCursor.Name = "customCursor"; + mouseCursorCanvas.Children.Insert(0, CustomCursor); //in front! + CustomCursor.Visibility = Visibility.Hidden; + } + catch (System.NotSupportedException) + { + //we can die here if we ALT-F4 while in the Options Dialog + } + } + private void Properties_Executed(object sender, ExecutedRoutedEventArgs e) + { + controller.ShowOptionsDialog(); } } } \ No newline at end of file diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs index f88aa91..202ab18 100644 --- a/Properties/Resources.Designer.cs +++ b/Properties/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18444 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs index 1daf447..7c003da 100644 --- a/Properties/Settings.Designer.cs +++ b/Properties/Settings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18444 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -12,7 +12,7 @@ namespace BabySmash.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -50,12 +50,12 @@ public bool FadeAway { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("False")] - public bool UseEffects { + public bool BitmapEffects { get { - return ((bool)(this["UseEffects"])); + return ((bool)(this["BitmapEffects"])); } set { - this["UseEffects"] = value; + this["BitmapEffects"] = value; } } diff --git a/Resources/Strings/en-EN.json b/Resources/Strings/en-EN.json new file mode 100644 index 0000000..a243d1a --- /dev/null +++ b/Resources/Strings/en-EN.json @@ -0,0 +1,21 @@ +{ + "Circle": "Circle", + "Oval": "Oval", + "Rectangle": "Rectangle", + "Hexagon": "Hexagon", + "Trapezoid": "Trapezoid", + "Star": "Star", + "Square": "Square", + "Triangle": "Triangle", + "Heart": "Heart", + + "Red": "Red", + "Blue": "Blue", + "Yellow": "Yellow", + "Green": "Green", + "Purple": "Purple", + "Pink": "Pink", + "Orange": "Orange", + "Tan": "Tan", + "Gray": "Gray" +} \ No newline at end of file diff --git a/Resources/Strings/ru-RU.json b/Resources/Strings/ru-RU.json new file mode 100644 index 0000000..8c47701 --- /dev/null +++ b/Resources/Strings/ru-RU.json @@ -0,0 +1,21 @@ +{ + "Circle": "Круг", + "Oval": "Овал", + "Rectangle": "Прямоугольник", + "Hexagon": "Шестиугольник", + "Trapezoid": "Трапеция", + "Star": "Звезда", + "Square": "Квадрат", + "Triangle": "Треугольник", + "Heart": "Сердце", + + "Red": "красный", + "Blue": "синий", + "Yellow": "желтый", + "Green": "зеленый", + "Purple": "фиолетовый", + "Pink": "розовый", + "Orange": "оранжевый", + "Tan": "желтовато-коричневый", + "Gray": "серый" +} \ No newline at end of file diff --git a/Shapes/AnimationBehaviors.cs b/Shapes/AnimationBehaviors.cs index 26efc78..3d8e25c 100644 --- a/Shapes/AnimationBehaviors.cs +++ b/Shapes/AnimationBehaviors.cs @@ -89,1697 +89,1696 @@ consumer rights under your local laws which this license cannot change. To the namespace AnimationBehaviors { - #region Behavior Enumerations - - /// - /// LoadedBehaviors are used to add an animation that runs when a page is loaded. - /// Currenly only one LoadedBehavior is supported per element however by using decorator elements multiple behaviors can be simultated - /// - public enum LoadedBehavior - { - None, - FadeIn, - FadeOut, - ZoomIn, - ZoomInSpringy, - ZoomInRotate, - SlideInFromLeft, - SlideInFromTop, - SlideInFromRight, - SlideInFromBottom, - ScaleInVertically, - ScaleInHorizontally, - } - - /// - /// UnloadedBehaviors are used to add an animation that runs when a page navigated away from. - /// Currenly only one UnloadedBehavior is supported per element however by using decorator elements multiple behaviors can be simultated - /// - public enum UnloadedBehavior - { - None, - FadeIn, - FadeOut, - ZoomOut, - ZoomOutRotate, - SlideOutToLeft, - SlideOutToTop, - SlideOutToRight, - SlideOutToBottom, - ScaleOutVertically, - ScaleOutHorizontally, - } - - /// - /// ClickBehaviors are used to add an animation that runs when an element is clicked on. - /// For most elements this actually means the MouseUp event, however for buttons it hooks to the Click event - /// Currenly only one ClickBehavior is supported per element however by using decorator elements multiple behaviors can be simultated - /// - public enum ClickBehavior - { - None, - Jiggle, - Throb, - Rotate, - Snap, - } - - /// - /// LayoutBehaviors are used to add an animation that runs when an element gets a new layout position. - /// Instead of simply poping to the new position LayoutBehaviors can cause the element to animate to the new position - /// Currenly only one ClickBehavior is supported per element however by using decorator elements multiple behaviors can be simultated - /// - public enum LayoutBehavior - { - None, - Smooth, - Springy, - } - - #endregion - - /// - /// AnimationBehaviorHost is responsible for adding animations to elements that use it's attached properties. - /// - /// This class is typically located near the top of each pages visual tree so that decendant elements can add - /// common animations simply by attaching a property in XAML. - /// - /// Currently behaviors do not attempt to preserve RenderTransforms, so any element that uses AnimationBehaviors should not - /// count on a consistant TransoformCollection. - /// - public class AnimationBehaviorHost : Decorator - { - /// - /// AnimationBehaviorHost constructor - /// - public AnimationBehaviorHost() - { - //hook loaded because we need the navigation service and it's not available at this time - this.Loaded += new RoutedEventHandler(AnimationBehaviorHost_Loaded); - } - /// - /// AnimationBehaviorHost_Loaded is called when this class is Loaded because the NavigationService is not available at construction time. - /// - /// - /// - private void AnimationBehaviorHost_Loaded(object sender, RoutedEventArgs e) - { - //hook the Navigating event so we can cancel it to allow UnloadedBehavior animations to run first - NavigationService ns = NavigationService.GetNavigationService(this); - if (ns != null) - ns.Navigating += new NavigatingCancelEventHandler(CancelNavigating); - } - - #region Loaded Behavior - - #region Loaded Behavior Attached Properties - /// - /// LoadedBehaviorProperty is an attached property which allows decendant elements to run animations when the page is loaded - /// - public static readonly DependencyProperty LoadedBehaviorProperty = - DependencyProperty.RegisterAttached("LoadedBehavior", - typeof(LoadedBehavior), - typeof(AnimationBehaviorHost), - new PropertyMetadata(LoadedBehavior.None, LoadedBehaviorChanged)); - /// - /// Used to set an elements LoadedBehavior attached property - /// - /// - /// - public static void SetLoadedBehavior(DependencyObject element, LoadedBehavior b) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - element.SetValue(AnimationBehaviorHost.LoadedBehaviorProperty, b); - } - - /// - /// Used to get an elements LoadedBehavior attached property - /// - /// - /// - public static LoadedBehavior GetLoadedBehavior(DependencyObject element) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - return (LoadedBehavior)element.GetValue(AnimationBehaviorHost.LoadedBehaviorProperty); - } - - /// - /// LoadedDurationProperty is an attached property used to control the duration of the LoadedBehavior animation. It defaults to 1 second. - /// - public static readonly DependencyProperty LoadedDurationProperty = - DependencyProperty.RegisterAttached("LoadedDuration", - typeof(Duration), - typeof(AnimationBehaviorHost), - new PropertyMetadata(new Duration(TimeSpan.FromSeconds(1)))); - - /// - /// Used to set an elements LoadedBehavior attached property - /// - /// - /// - public static void SetLoadedDuration(DependencyObject element, Duration b) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - element.SetValue(AnimationBehaviorHost.LoadedDurationProperty, b); - } - - /// - /// Used to get an elements LoadedBehavior attached property - /// - /// - /// - public static Duration GetLoadedDuration(DependencyObject element) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - return (Duration)element.GetValue(AnimationBehaviorHost.LoadedDurationProperty); - } - - /// - /// LoadedDelayProperty is an attached property used to the duration of the delay before the LoadedBehavior animation starts. It defaults to 0 seconds. - /// - public static readonly DependencyProperty LoadedDelayProperty = - DependencyProperty.RegisterAttached("LoadedDelay", - typeof(Duration), - typeof(AnimationBehaviorHost), - new PropertyMetadata(new Duration(TimeSpan.Zero))); - - /// - /// Used to set an elements LoadedDelay attached property - /// - /// - /// - public static void SetLoadedDelay(DependencyObject element, Duration b) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - element.SetValue(AnimationBehaviorHost.LoadedDelayProperty, b); - } - - /// - /// Used to get an elements LoadedDelay attached property - /// - /// - /// - public static Duration GetLoadedDelay(DependencyObject element) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - return (Duration)element.GetValue(AnimationBehaviorHost.LoadedDelayProperty); - } - #endregion - - #region Loaded Behavior Realization - /// - /// This gets called when the LoadedBehavior attached property is set on an element. We simply hook it's Loaded - /// event. - /// - /// - /// - private static void LoadedBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - FrameworkElement element = (d as FrameworkElement); - if (element != null) - { - - LoadedBehavior newbehavior = (LoadedBehavior)e.NewValue; - LoadedBehavior oldbehavior = (LoadedBehavior)e.OldValue; - - if (newbehavior == oldbehavior) - return; - - //walk the tree to find the closes AnimationBehaviorHost - AnimationBehaviorHost host = FindHost(element); - if (host == null) - return; - - //dont forget to remove the event if the user decides to set it to None form something else - if (newbehavior == LoadedBehavior.None) - element.Loaded -= host.ApplyLoadedBehavior; - - //hook loaded if not None so we can apply the animation once it's on the page - if (oldbehavior == LoadedBehavior.None) - element.Loaded += host.ApplyLoadedBehavior; - } - } - - /// - /// This is where the LoadedBehavior animations takes place. We simply apply an animation based on the type of behavior - /// - /// - /// - private void ApplyLoadedBehavior(object sender, RoutedEventArgs e) - { - FrameworkElement element = (FrameworkElement)sender; - LoadedBehavior behavior = AnimationBehaviorHost.GetLoadedBehavior(element); - Duration duration = GetLoadedDuration(element); - Duration delay = GetLoadedDelay(element); - - switch (behavior) - { - case LoadedBehavior.FadeIn: - ApplyFadeIn(element, duration, delay); - break; - case LoadedBehavior.FadeOut: - ApplyFadeOut(element, duration, delay); - break; - case LoadedBehavior.ZoomIn: - ApplyZoomIn(element, duration, delay); - break; - case LoadedBehavior.ZoomInSpringy: - ApplyZoomInSpringy(element, duration, delay); - break; - case LoadedBehavior.ZoomInRotate: - ApplyZoomInRotate(element, duration, delay); - break; - case LoadedBehavior.SlideInFromLeft: - ApplySlideInFromLeft(element, duration, delay); - break; - case LoadedBehavior.SlideInFromTop: - ApplySlideInFromTop(element, duration, delay); - break; - case LoadedBehavior.SlideInFromRight: - ApplySlideInFromRight(element, duration, delay); - break; - case LoadedBehavior.SlideInFromBottom: - ApplySlideInFromBottom(element, duration, delay); - break; - case LoadedBehavior.ScaleInVertically: - ApplyScaleInVertically(element, duration, delay); - break; - case LoadedBehavior.ScaleInHorizontally: - ApplyScaleInHorizontally(element, duration, delay); - break; - } - } - #endregion - - #region Loaded Behaviors Applied - private void ApplyFadeIn(FrameworkElement fe, Duration duration, Duration delay) - { - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(0.0, 1.0, duration); - fe.BeginAnimation(FrameworkElement.OpacityProperty, da); - } - else - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; - fe.BeginAnimation(FrameworkElement.OpacityProperty, da); - } - } - - private void ApplyFadeOut(FrameworkElement fe, Duration duration, Duration delay) - { - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(1.0, 0.0, duration); - fe.BeginAnimation(FrameworkElement.OpacityProperty, da); - } - else - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; - fe.BeginAnimation(FrameworkElement.OpacityProperty, da); - } - } - - private void ApplyZoomIn(FrameworkElement fe, Duration duration, Duration delay) - { - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(0.0, 1.0, duration); - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new ScaleTransform(1, 1); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); - } - else - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new ScaleTransform(1, 1); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); - } - } + #region Behavior Enumerations + + /// + /// LoadedBehaviors are used to add an animation that runs when a page is loaded. + /// Currenly only one LoadedBehavior is supported per element however by using decorator elements multiple behaviors can be simultated + /// + public enum LoadedBehavior + { + None, + FadeIn, + FadeOut, + ZoomIn, + ZoomInSpringy, + ZoomInRotate, + SlideInFromLeft, + SlideInFromTop, + SlideInFromRight, + SlideInFromBottom, + ScaleInVertically, + ScaleInHorizontally, + } + + /// + /// UnloadedBehaviors are used to add an animation that runs when a page navigated away from. + /// Currenly only one UnloadedBehavior is supported per element however by using decorator elements multiple behaviors can be simultated + /// + public enum UnloadedBehavior + { + None, + FadeIn, + FadeOut, + ZoomOut, + ZoomOutRotate, + SlideOutToLeft, + SlideOutToTop, + SlideOutToRight, + SlideOutToBottom, + ScaleOutVertically, + ScaleOutHorizontally, + } + + /// + /// ClickBehaviors are used to add an animation that runs when an element is clicked on. + /// For most elements this actually means the MouseUp event, however for buttons it hooks to the Click event + /// Currenly only one ClickBehavior is supported per element however by using decorator elements multiple behaviors can be simultated + /// + public enum ClickBehavior + { + None, + Jiggle, + Throb, + Rotate, + Snap, + } + + /// + /// LayoutBehaviors are used to add an animation that runs when an element gets a new layout position. + /// Instead of simply poping to the new position LayoutBehaviors can cause the element to animate to the new position + /// Currenly only one ClickBehavior is supported per element however by using decorator elements multiple behaviors can be simultated + /// + public enum LayoutBehavior + { + None, + Smooth, + Springy, + } + + #endregion + + /// + /// AnimationBehaviorHost is responsible for adding animations to elements that use it's attached properties. + /// + /// This class is typically located near the top of each pages visual tree so that decendant elements can add + /// common animations simply by attaching a property in XAML. + /// + /// Currently behaviors do not attempt to preserve RenderTransforms, so any element that uses AnimationBehaviors should not + /// count on a consistant TransoformCollection. + /// + public class AnimationBehaviorHost : Decorator + { + /// + /// AnimationBehaviorHost constructor + /// + public AnimationBehaviorHost() + { + //hook loaded because we need the navigation service and it's not available at this time + this.Loaded += new RoutedEventHandler(AnimationBehaviorHost_Loaded); + } + /// + /// AnimationBehaviorHost_Loaded is called when this class is Loaded because the NavigationService is not available at construction time. + /// + /// + /// + private void AnimationBehaviorHost_Loaded(object sender, RoutedEventArgs e) + { + //hook the Navigating event so we can cancel it to allow UnloadedBehavior animations to run first + NavigationService ns = NavigationService.GetNavigationService(this); + if (ns != null) + ns.Navigating += new NavigatingCancelEventHandler(CancelNavigating); + } + + #region Loaded Behavior + + #region Loaded Behavior Attached Properties + /// + /// LoadedBehaviorProperty is an attached property which allows decendant elements to run animations when the page is loaded + /// + public static readonly DependencyProperty LoadedBehaviorProperty = + DependencyProperty.RegisterAttached("LoadedBehavior", + typeof(LoadedBehavior), + typeof(AnimationBehaviorHost), + new PropertyMetadata(LoadedBehavior.None, LoadedBehaviorChanged)); + /// + /// Used to set an elements LoadedBehavior attached property + /// + /// + /// + public static void SetLoadedBehavior(DependencyObject element, LoadedBehavior b) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } - private void ApplyZoomInSpringy(FrameworkElement fe, Duration duration, Duration delay) - { - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.1, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.9, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.05, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.95, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + element.SetValue(AnimationBehaviorHost.LoadedBehaviorProperty, b); + } + + /// + /// Used to get an elements LoadedBehavior attached property + /// + /// + /// + public static LoadedBehavior GetLoadedBehavior(DependencyObject element) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } - da.Duration = duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; + return (LoadedBehavior)element.GetValue(AnimationBehaviorHost.LoadedBehaviorProperty); + } + + /// + /// LoadedDurationProperty is an attached property used to control the duration of the LoadedBehavior animation. It defaults to 1 second. + /// + public static readonly DependencyProperty LoadedDurationProperty = + DependencyProperty.RegisterAttached("LoadedDuration", + typeof(Duration), + typeof(AnimationBehaviorHost), + new PropertyMetadata(new Duration(TimeSpan.FromSeconds(1)))); + + /// + /// Used to set an elements LoadedBehavior attached property + /// + /// + /// + public static void SetLoadedDuration(DependencyObject element, Duration b) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new ScaleTransform(1, 1); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); - } - else - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.1, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.9, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.05, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.95, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + element.SetValue(AnimationBehaviorHost.LoadedDurationProperty, b); + } + + /// + /// Used to get an elements LoadedBehavior attached property + /// + /// + /// + public static Duration GetLoadedDuration(DependencyObject element) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } - da.Duration = delay + duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; + return (Duration)element.GetValue(AnimationBehaviorHost.LoadedDurationProperty); + } + + /// + /// LoadedDelayProperty is an attached property used to the duration of the delay before the LoadedBehavior animation starts. It defaults to 0 seconds. + /// + public static readonly DependencyProperty LoadedDelayProperty = + DependencyProperty.RegisterAttached("LoadedDelay", + typeof(Duration), + typeof(AnimationBehaviorHost), + new PropertyMetadata(new Duration(TimeSpan.Zero))); + + /// + /// Used to set an elements LoadedDelay attached property + /// + /// + /// + public static void SetLoadedDelay(DependencyObject element, Duration b) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new ScaleTransform(1, 1); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); - } - } - - private void ApplyZoomInRotate(FrameworkElement fe, Duration duration, Duration delay) - { - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da1 = new DoubleAnimation(0.0, 1.0, duration); - da1.AccelerationRatio = da1.DecelerationRatio = 0.2; + element.SetValue(AnimationBehaviorHost.LoadedDelayProperty, b); + } + + /// + /// Used to get an elements LoadedDelay attached property + /// + /// + /// + public static Duration GetLoadedDelay(DependencyObject element) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } - DoubleAnimation da2 = new DoubleAnimation(0.0, 360.0, duration); - da2.AccelerationRatio = da2.DecelerationRatio = 0.2; + return (Duration)element.GetValue(AnimationBehaviorHost.LoadedDelayProperty); + } + #endregion + + #region Loaded Behavior Realization + /// + /// This gets called when the LoadedBehavior attached property is set on an element. We simply hook it's Loaded + /// event. + /// + /// + /// + private static void LoadedBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + FrameworkElement element = (d as FrameworkElement); + if (element != null) + { - TransformGroup tg = new TransformGroup(); - tg.Children.Add(new ScaleTransform(1, 1)); - tg.Children.Add(new RotateTransform(0)); + LoadedBehavior newbehavior = (LoadedBehavior)e.NewValue; + LoadedBehavior oldbehavior = (LoadedBehavior)e.OldValue; - tg.Children[0].BeginAnimation(ScaleTransform.ScaleXProperty, da1); - tg.Children[0].BeginAnimation(ScaleTransform.ScaleYProperty, da1); + if (newbehavior == oldbehavior) + return; - tg.Children[1].BeginAnimation(RotateTransform.AngleProperty, da2); + //walk the tree to find the closes AnimationBehaviorHost + AnimationBehaviorHost host = FindHost(element); + if (host == null) + return; - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = tg; - } - else - { - DoubleAnimationUsingKeyFrames da1 = new DoubleAnimationUsingKeyFrames(); - da1.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da1.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da1.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da1.Duration = delay + duration; - da1.AccelerationRatio = da1.DecelerationRatio = 0.2; + //dont forget to remove the event if the user decides to set it to None form something else + if (newbehavior == LoadedBehavior.None) + element.Loaded -= host.ApplyLoadedBehavior; - DoubleAnimationUsingKeyFrames da2 = new DoubleAnimationUsingKeyFrames(); - da2.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da2.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da2.KeyFrames.Add(new LinearDoubleKeyFrame(360.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da2.Duration = delay + duration; - da2.AccelerationRatio = da2.DecelerationRatio = 0.2; + //hook loaded if not None so we can apply the animation once it's on the page + if (oldbehavior == LoadedBehavior.None) + element.Loaded += host.ApplyLoadedBehavior; + } + } + + /// + /// This is where the LoadedBehavior animations takes place. We simply apply an animation based on the type of behavior + /// + /// + /// + private void ApplyLoadedBehavior(object sender, RoutedEventArgs e) + { + FrameworkElement element = (FrameworkElement)sender; + LoadedBehavior behavior = AnimationBehaviorHost.GetLoadedBehavior(element); + Duration duration = GetLoadedDuration(element); + Duration delay = GetLoadedDelay(element); + + switch (behavior) + { + case LoadedBehavior.FadeIn: + ApplyFadeIn(element, duration, delay); + break; + case LoadedBehavior.FadeOut: + ApplyFadeOut(element, duration, delay); + break; + case LoadedBehavior.ZoomIn: + ApplyZoomIn(element, duration, delay); + break; + case LoadedBehavior.ZoomInSpringy: + ApplyZoomInSpringy(element, duration, delay); + break; + case LoadedBehavior.ZoomInRotate: + ApplyZoomInRotate(element, duration, delay); + break; + case LoadedBehavior.SlideInFromLeft: + ApplySlideInFromLeft(element, duration, delay); + break; + case LoadedBehavior.SlideInFromTop: + ApplySlideInFromTop(element, duration, delay); + break; + case LoadedBehavior.SlideInFromRight: + ApplySlideInFromRight(element, duration, delay); + break; + case LoadedBehavior.SlideInFromBottom: + ApplySlideInFromBottom(element, duration, delay); + break; + case LoadedBehavior.ScaleInVertically: + ApplyScaleInVertically(element, duration, delay); + break; + case LoadedBehavior.ScaleInHorizontally: + ApplyScaleInHorizontally(element, duration, delay); + break; + } + } + #endregion - TransformGroup tg = new TransformGroup(); - tg.Children.Add(new ScaleTransform(1, 1)); - tg.Children.Add(new RotateTransform(0)); + #region Loaded Behaviors Applied + private void ApplyFadeIn(FrameworkElement fe, Duration duration, Duration delay) + { + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(0.0, 1.0, duration); + fe.BeginAnimation(FrameworkElement.OpacityProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + fe.BeginAnimation(FrameworkElement.OpacityProperty, da); + } + } - tg.Children[0].BeginAnimation(ScaleTransform.ScaleXProperty, da1); - tg.Children[0].BeginAnimation(ScaleTransform.ScaleYProperty, da1); + private void ApplyFadeOut(FrameworkElement fe, Duration duration, Duration delay) + { + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(1.0, 0.0, duration); + fe.BeginAnimation(FrameworkElement.OpacityProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + fe.BeginAnimation(FrameworkElement.OpacityProperty, da); + } + } - tg.Children[1].BeginAnimation(RotateTransform.AngleProperty, da2); + private void ApplyZoomIn(FrameworkElement fe, Duration duration, Duration delay) + { + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(0.0, 1.0, duration); + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = new ScaleTransform(1, 1); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = new ScaleTransform(1, 1); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); + } + } - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = tg; - } - } - - private void ApplySlideInFromLeft(FrameworkElement fe, Duration duration, Duration delay) - { - GeneralTransform transform = fe.TransformToAncestor(this); - Point slidepoint = transform.Transform(new Point(fe.ActualWidth, 0)); - - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(-slidepoint.X, 0, duration); - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); - } - else - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(-slidepoint.X, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(-slidepoint.X, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); - } - } - - private void ApplySlideInFromTop(FrameworkElement fe, Duration duration, Duration delay) - { - GeneralTransform transform = fe.TransformToAncestor(this); - Point slidepoint = transform.Transform(new Point(0, fe.ActualHeight)); - - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(-slidepoint.Y, 0, duration); - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); - } - else - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(-slidepoint.Y, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(-slidepoint.Y, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); - } - } - - private void ApplySlideInFromRight(FrameworkElement fe, Duration duration, Duration delay) - { - GeneralTransform transform = fe.TransformToAncestor(this); - - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(this.ActualWidth, 0, duration); - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); - } - else - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(this.ActualWidth, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(this.ActualWidth, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); - } - } - - private void ApplySlideInFromBottom(FrameworkElement fe, Duration duration, Duration delay) - { - GeneralTransform transform = fe.TransformToAncestor(this); - - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(this.ActualHeight, 0, duration); - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); - } - else - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(this.ActualHeight, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(this.ActualHeight, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); - } - } - - private void ApplyScaleInVertically(FrameworkElement fe, Duration duration, Duration delay) - { - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(0.0, 1.0, duration); - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new ScaleTransform(1, 1); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); - } - else - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new ScaleTransform(1, 1); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); - } - } - - private void ApplyScaleInHorizontally(FrameworkElement fe, Duration duration, Duration delay) - { - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(0.0, 1.0, duration); - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new ScaleTransform(1, 1); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); - } - else - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new ScaleTransform(1, 1); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); - } - } - - #endregion - - #endregion - - #region Unloaded Behavior - - #region Unloaded Behavior Attached Properties - - /// - /// UnloadedBehaviorProperty is an attached property which allows decendant elements to run animations when the page is navigated away from - /// - public static readonly DependencyProperty UnloadedBehaviorProperty = - DependencyProperty.RegisterAttached("UnloadedBehavior", - typeof(UnloadedBehavior), - typeof(AnimationBehaviorHost), - new PropertyMetadata(UnloadedBehavior.None)); - - /// - /// Used to set an elements UnloadedBehavior attached property - /// - /// - /// - public static void SetUnloadedBehavior(DependencyObject element, UnloadedBehavior b) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - element.SetValue(AnimationBehaviorHost.UnloadedBehaviorProperty, b); - } - - /// - /// Used to get an elements UnloadedBehavior attached property - /// - /// - /// - public static UnloadedBehavior GetUnloadedBehavior(DependencyObject element) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - return (UnloadedBehavior)element.GetValue(AnimationBehaviorHost.UnloadedBehaviorProperty); - } - - - /// - /// UnloadedDurationProperty is an attached property used to control the duration of the UnloadedBehavior animation. It defaults to 1 second. - /// - public static readonly DependencyProperty UnloadedDurationProperty = - DependencyProperty.RegisterAttached("UnloadedDuration", - typeof(Duration), - typeof(AnimationBehaviorHost), - new PropertyMetadata(new Duration(TimeSpan.FromSeconds(1)))); - - /// - /// Used to set an elements UnloadedDuration attached property - /// - /// - /// - public static void SetUnloadedDuration(DependencyObject element, Duration b) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - element.SetValue(AnimationBehaviorHost.UnloadedDurationProperty, b); - } - - /// - /// Used to get an elements UnloadedDuration attached property - /// - /// - /// - public static Duration GetUnloadedDuration(DependencyObject element) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - return (Duration)element.GetValue(AnimationBehaviorHost.UnloadedDurationProperty); - } - - /// - /// UnloadedDelayProperty is an attached property used to the duration of the delay before the UnloadedBehavior animation starts. It defaults to 0 seconds. - /// - public static readonly DependencyProperty UnloadedDelayProperty = - DependencyProperty.RegisterAttached("UnloadedDelay", - typeof(Duration), - typeof(AnimationBehaviorHost), - new PropertyMetadata(new Duration(TimeSpan.Zero))); - - /// - /// Used to set an elements UnloadedDelay attached property - /// - /// - /// - public static void SetUnloadedDelay(DependencyObject element, Duration b) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - element.SetValue(AnimationBehaviorHost.UnloadedDelayProperty, b); - } - - /// - /// Used to get an elements UnloadedDelay attached property - /// - /// - /// - public static Duration GetUnloadedDelay(DependencyObject element) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - return (Duration)element.GetValue(AnimationBehaviorHost.UnloadedDelayProperty); - } - - #endregion - - #region Unloaded Behavior Realization - /// - /// This even is fired after UnloadBehavior animations have completed but before the page is navigated - /// - public event EventHandler UnloadBehaviorsComplete; - - /// - /// When a navigation is canceled we hold on to the arguments so we can resume the navigation after UnloadBehavior animations have completed - /// - private NavigatingCancelEventArgs canceledNavigation = null; - - /// - /// Walks the visual tree looking for FE's that have unload behaviors - /// - /// - private List GetUnloadBehaviorElements() - { - List unloadedBehaviorElements = new List(); - - GetUnloadBehaviorElementsRecursive(this, unloadedBehaviorElements); - - return unloadedBehaviorElements; - } - - /// - /// recursivly does a tree walk (depth first) to collect FE's - /// - /// - /// - private void GetUnloadBehaviorElementsRecursive(FrameworkElement fe, List list) - { - if (GetUnloadedBehavior(fe) != UnloadedBehavior.None) - list.Add(fe); - - for (int i = 0; i < VisualTreeHelper.GetChildrenCount(fe); i++) - { - FrameworkElement child = VisualTreeHelper.GetChild(fe, i) as FrameworkElement; - if (child != null) - { - GetUnloadBehaviorElementsRecursive(child, list); - } - } - } - - /// - /// This event handler is called when the NavigationService fires it's Navigating event. - /// We then cancel the event, run UnloadBehavior animations, and then resume the navigation once they are done - /// - /// - /// - private void CancelNavigating(object sender, NavigatingCancelEventArgs e) - { - List unloadedBehaviorElements = GetUnloadBehaviorElements(); - if (unloadedBehaviorElements.Count > 0) - { - canceledNavigation = e; - this.UnloadBehaviorsComplete += ResumeNavigation; - ApplyUnloadedBehaviors(unloadedBehaviorElements); - e.Cancel = true; - } - } - - /// - /// When a navigation is attempted we first cancel it then once UnloadBehavior animations have complete we resume the Navigation in this method - /// - /// - /// - private void ResumeNavigation(object sender, EventArgs e) - { - this.UnloadBehaviorsComplete -= ResumeNavigation; - NavigationService ns = NavigationService.GetNavigationService(this); - if (ns != null) - { - ns.Navigating -= CancelNavigating; //we dont need to cancel next time around - ns.Navigate(canceledNavigation.Uri, canceledNavigation.ExtraData); //navigate using previously stored data - } - } - - /// - /// Given a list of elements with Unloaded Behaviors this method simply applies them and waits till they are done - /// - /// - private void ApplyUnloadedBehaviors(List unloadedBehaviorElements) - { - TimeSpan longestUnload = TimeSpan.FromSeconds(0); - //find the longest UnloadedBehavior so we can wait till it's done - foreach (FrameworkElement fe in unloadedBehaviorElements) - { - ApplyUnloadedBehavior(fe); - Duration dur = GetUnloadedDelay(fe) + GetUnloadedDuration(fe); - if (dur.TimeSpan > longestUnload) - longestUnload = dur.TimeSpan; - } - DispatcherTimer unloadTimer = new DispatcherTimer(longestUnload, DispatcherPriority.Render, HandleUnloadedBehaviorComplete, Dispatcher.CurrentDispatcher); - } - - /// - /// Once all the UnloadedBehaviors have completed we should fire our UnloadBehaviorsComplete event - /// to let anyone else know about this. - /// - /// - /// - private void HandleUnloadedBehaviorComplete(object sender, EventArgs args) - { - DispatcherTimer unloadTimer = (DispatcherTimer)sender; - unloadTimer.Stop(); - if (UnloadBehaviorsComplete != null) - UnloadBehaviorsComplete(this, null); - - } - - /// - /// Given an element, simply apply animations based on the type of UnloadedBehavior it has - /// - /// - private void ApplyUnloadedBehavior(FrameworkElement element) - { - UnloadedBehavior behavior = AnimationBehaviorHost.GetUnloadedBehavior(element); - Duration duration = GetUnloadedDuration(element); - Duration delay = GetUnloadedDelay(element); - - switch (behavior) - { - case UnloadedBehavior.FadeIn: - ApplyFadeIn(element, duration, delay); - break; - case UnloadedBehavior.FadeOut: - ApplyFadeOut(element, duration, delay); - break; - case UnloadedBehavior.ZoomOut: - ApplyZoomOut(element, duration, delay); - break; - case UnloadedBehavior.ZoomOutRotate: - ApplyZoomOutRotate(element, duration, delay); - break; - case UnloadedBehavior.SlideOutToLeft: - ApplySlideOutToLeft(element, duration, delay); - break; - case UnloadedBehavior.SlideOutToTop: - ApplySlideOutToTop(element, duration, delay); - break; - case UnloadedBehavior.SlideOutToRight: - ApplySlideOutToRight(element, duration, delay); - break; - case UnloadedBehavior.SlideOutToBottom: - ApplySlideOutToBottom(element, duration, delay); - break; - case UnloadedBehavior.ScaleOutVertically: - ApplyScaleOutVertically(element, duration, delay); - break; - case UnloadedBehavior.ScaleOutHorizontally: - ApplyScaleOutHorizontally(element, duration, delay); - break; - } - } - - #endregion - - #region UnloadedBehaviors Applied - - private void ApplyZoomOut(FrameworkElement fe, Duration duration, Duration delay) - { - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(1.0, 0.0, duration); - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new ScaleTransform(1, 1); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); - } - else - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new ScaleTransform(1, 1); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); - } + private void ApplyZoomInSpringy(FrameworkElement fe, Duration duration, Duration delay) + { + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.1, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.9, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.05, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.95, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + + da.Duration = duration; + da.AccelerationRatio = da.DecelerationRatio = 0.2; + + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = new ScaleTransform(1, 1); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.1, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.9, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.05, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.95, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + + da.Duration = delay + duration; + da.AccelerationRatio = da.DecelerationRatio = 0.2; + + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = new ScaleTransform(1, 1); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); + } + } - } + private void ApplyZoomInRotate(FrameworkElement fe, Duration duration, Duration delay) + { + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da1 = new DoubleAnimation(0.0, 1.0, duration); + da1.AccelerationRatio = da1.DecelerationRatio = 0.2; - private void ApplyZoomOutRotate(FrameworkElement fe, Duration duration, Duration delay) - { - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da1 = new DoubleAnimation(1.0, 0.0, duration); - da1.AccelerationRatio = da1.DecelerationRatio = 0.2; + DoubleAnimation da2 = new DoubleAnimation(0.0, 360.0, duration); + da2.AccelerationRatio = da2.DecelerationRatio = 0.2; - DoubleAnimation da2 = new DoubleAnimation(0.0, -360.0, duration); - da2.AccelerationRatio = da2.DecelerationRatio = 0.2; + TransformGroup tg = new TransformGroup(); + tg.Children.Add(new ScaleTransform(1, 1)); + tg.Children.Add(new RotateTransform(0)); - TransformGroup tg = new TransformGroup(); - tg.Children.Add(new ScaleTransform(1, 1)); - tg.Children.Add(new RotateTransform(0)); + tg.Children[0].BeginAnimation(ScaleTransform.ScaleXProperty, da1); + tg.Children[0].BeginAnimation(ScaleTransform.ScaleYProperty, da1); - tg.Children[0].BeginAnimation(ScaleTransform.ScaleXProperty, da1); - tg.Children[0].BeginAnimation(ScaleTransform.ScaleYProperty, da1); + tg.Children[1].BeginAnimation(RotateTransform.AngleProperty, da2); - tg.Children[1].BeginAnimation(RotateTransform.AngleProperty, da2); + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = tg; + } + else + { + DoubleAnimationUsingKeyFrames da1 = new DoubleAnimationUsingKeyFrames(); + da1.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da1.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da1.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da1.Duration = delay + duration; + da1.AccelerationRatio = da1.DecelerationRatio = 0.2; + + DoubleAnimationUsingKeyFrames da2 = new DoubleAnimationUsingKeyFrames(); + da2.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da2.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da2.KeyFrames.Add(new LinearDoubleKeyFrame(360.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da2.Duration = delay + duration; + da2.AccelerationRatio = da2.DecelerationRatio = 0.2; + + TransformGroup tg = new TransformGroup(); + tg.Children.Add(new ScaleTransform(1, 1)); + tg.Children.Add(new RotateTransform(0)); + + tg.Children[0].BeginAnimation(ScaleTransform.ScaleXProperty, da1); + tg.Children[0].BeginAnimation(ScaleTransform.ScaleYProperty, da1); + + tg.Children[1].BeginAnimation(RotateTransform.AngleProperty, da2); + + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = tg; + } + } - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = tg; - } - else - { - DoubleAnimationUsingKeyFrames da1 = new DoubleAnimationUsingKeyFrames(); - da1.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da1.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da1.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da1.Duration = delay + duration; - da1.AccelerationRatio = da1.DecelerationRatio = 0.2; + private void ApplySlideInFromLeft(FrameworkElement fe, Duration duration, Duration delay) + { + GeneralTransform transform = fe.TransformToAncestor(this); + Point slidepoint = transform.Transform(new Point(fe.ActualWidth, 0)); - DoubleAnimationUsingKeyFrames da2 = new DoubleAnimationUsingKeyFrames(); - da2.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da2.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da2.KeyFrames.Add(new LinearDoubleKeyFrame(-360.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da2.Duration = delay + duration; - da2.AccelerationRatio = da2.DecelerationRatio = 0.2; + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(-slidepoint.X, 0, duration); + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(-slidepoint.X, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(-slidepoint.X, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); + } + } - TransformGroup tg = new TransformGroup(); - tg.Children.Add(new ScaleTransform(1, 1)); - tg.Children.Add(new RotateTransform(0)); + private void ApplySlideInFromTop(FrameworkElement fe, Duration duration, Duration delay) + { + GeneralTransform transform = fe.TransformToAncestor(this); + Point slidepoint = transform.Transform(new Point(0, fe.ActualHeight)); - tg.Children[0].BeginAnimation(ScaleTransform.ScaleXProperty, da1); - tg.Children[0].BeginAnimation(ScaleTransform.ScaleYProperty, da1); + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(-slidepoint.Y, 0, duration); + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(-slidepoint.Y, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(-slidepoint.Y, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); + } + } - tg.Children[1].BeginAnimation(RotateTransform.AngleProperty, da2); + private void ApplySlideInFromRight(FrameworkElement fe, Duration duration, Duration delay) + { + GeneralTransform transform = fe.TransformToAncestor(this); - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = tg; - } - } + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(this.ActualWidth, 0, duration); + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(this.ActualWidth, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(this.ActualWidth, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); + } + } + private void ApplySlideInFromBottom(FrameworkElement fe, Duration duration, Duration delay) + { + GeneralTransform transform = fe.TransformToAncestor(this); - private void ApplySlideOutToLeft(FrameworkElement fe, Duration duration, Duration delay) - { - GeneralTransform transform = fe.TransformToAncestor(this); - Point slidepoint = transform.Transform(new Point(fe.ActualWidth, 0)); + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(this.ActualHeight, 0, duration); + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(this.ActualHeight, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(this.ActualHeight, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); + } + } - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(0, -slidepoint.X, duration); - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); - } - else - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(-slidepoint.X, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); - } - } - - private void ApplySlideOutToTop(FrameworkElement fe, Duration duration, Duration delay) - { - GeneralTransform transform = fe.TransformToAncestor(this); - Point slidepoint = transform.Transform(new Point(0, fe.ActualHeight)); - - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(0, -slidepoint.Y, duration); - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); - } - else - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(-slidepoint.Y, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); - } - } - - private void ApplySlideOutToRight(FrameworkElement fe, Duration duration, Duration delay) - { - GeneralTransform transform = fe.TransformToAncestor(this); - - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(0, this.ActualWidth, duration); - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); - } - else - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(this.ActualWidth, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); - } - } - - private void ApplySlideOutToBottom(FrameworkElement fe, Duration duration, Duration delay) - { - GeneralTransform transform = fe.TransformToAncestor(this); - - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(0, this.ActualHeight, duration); - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); - } - else - { + private void ApplyScaleInVertically(FrameworkElement fe, Duration duration, Duration delay) + { + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(0.0, 1.0, duration); + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = new ScaleTransform(1, 1); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = new ScaleTransform(1, 1); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); + } + } + + private void ApplyScaleInHorizontally(FrameworkElement fe, Duration duration, Duration delay) + { + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(0.0, 1.0, duration); + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = new ScaleTransform(1, 1); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = new ScaleTransform(1, 1); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); + } + } + + #endregion + + #endregion + + #region Unloaded Behavior + + #region Unloaded Behavior Attached Properties + + /// + /// UnloadedBehaviorProperty is an attached property which allows decendant elements to run animations when the page is navigated away from + /// + public static readonly DependencyProperty UnloadedBehaviorProperty = + DependencyProperty.RegisterAttached("UnloadedBehavior", + typeof(UnloadedBehavior), + typeof(AnimationBehaviorHost), + new PropertyMetadata(UnloadedBehavior.None)); + + /// + /// Used to set an elements UnloadedBehavior attached property + /// + /// + /// + public static void SetUnloadedBehavior(DependencyObject element, UnloadedBehavior b) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } + + element.SetValue(AnimationBehaviorHost.UnloadedBehaviorProperty, b); + } + + /// + /// Used to get an elements UnloadedBehavior attached property + /// + /// + /// + public static UnloadedBehavior GetUnloadedBehavior(DependencyObject element) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } + + return (UnloadedBehavior)element.GetValue(AnimationBehaviorHost.UnloadedBehaviorProperty); + } + + + /// + /// UnloadedDurationProperty is an attached property used to control the duration of the UnloadedBehavior animation. It defaults to 1 second. + /// + public static readonly DependencyProperty UnloadedDurationProperty = + DependencyProperty.RegisterAttached("UnloadedDuration", + typeof(Duration), + typeof(AnimationBehaviorHost), + new PropertyMetadata(new Duration(TimeSpan.FromSeconds(1)))); + + /// + /// Used to set an elements UnloadedDuration attached property + /// + /// + /// + public static void SetUnloadedDuration(DependencyObject element, Duration b) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } + + element.SetValue(AnimationBehaviorHost.UnloadedDurationProperty, b); + } + + /// + /// Used to get an elements UnloadedDuration attached property + /// + /// + /// + public static Duration GetUnloadedDuration(DependencyObject element) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } + + return (Duration)element.GetValue(AnimationBehaviorHost.UnloadedDurationProperty); + } + + /// + /// UnloadedDelayProperty is an attached property used to the duration of the delay before the UnloadedBehavior animation starts. It defaults to 0 seconds. + /// + public static readonly DependencyProperty UnloadedDelayProperty = + DependencyProperty.RegisterAttached("UnloadedDelay", + typeof(Duration), + typeof(AnimationBehaviorHost), + new PropertyMetadata(new Duration(TimeSpan.Zero))); + + /// + /// Used to set an elements UnloadedDelay attached property + /// + /// + /// + public static void SetUnloadedDelay(DependencyObject element, Duration b) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } + + element.SetValue(AnimationBehaviorHost.UnloadedDelayProperty, b); + } + + /// + /// Used to get an elements UnloadedDelay attached property + /// + /// + /// + public static Duration GetUnloadedDelay(DependencyObject element) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } + + return (Duration)element.GetValue(AnimationBehaviorHost.UnloadedDelayProperty); + } + + #endregion + + #region Unloaded Behavior Realization + /// + /// This even is fired after UnloadBehavior animations have completed but before the page is navigated + /// + public event EventHandler UnloadBehaviorsComplete; + + /// + /// When a navigation is canceled we hold on to the arguments so we can resume the navigation after UnloadBehavior animations have completed + /// + private NavigatingCancelEventArgs canceledNavigation = null; + + /// + /// Walks the visual tree looking for FE's that have unload behaviors + /// + /// + private List GetUnloadBehaviorElements() + { + List unloadedBehaviorElements = new List(); + + GetUnloadBehaviorElementsRecursive(this, unloadedBehaviorElements); + + return unloadedBehaviorElements; + } + + /// + /// recursivly does a tree walk (depth first) to collect FE's + /// + /// + /// + private void GetUnloadBehaviorElementsRecursive(FrameworkElement fe, List list) + { + if (GetUnloadedBehavior(fe) != UnloadedBehavior.None) + list.Add(fe); + + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(fe); i++) + { + FrameworkElement child = VisualTreeHelper.GetChild(fe, i) as FrameworkElement; + if (child != null) + { + GetUnloadBehaviorElementsRecursive(child, list); + } + } + } + + /// + /// This event handler is called when the NavigationService fires it's Navigating event. + /// We then cancel the event, run UnloadBehavior animations, and then resume the navigation once they are done + /// + /// + /// + private void CancelNavigating(object sender, NavigatingCancelEventArgs e) + { + List unloadedBehaviorElements = GetUnloadBehaviorElements(); + if (unloadedBehaviorElements.Count > 0) + { + canceledNavigation = e; + this.UnloadBehaviorsComplete += ResumeNavigation; + ApplyUnloadedBehaviors(unloadedBehaviorElements); + e.Cancel = true; + } + } + + /// + /// When a navigation is attempted we first cancel it then once UnloadBehavior animations have complete we resume the Navigation in this method + /// + /// + /// + private void ResumeNavigation(object sender, EventArgs e) + { + this.UnloadBehaviorsComplete -= ResumeNavigation; + NavigationService ns = NavigationService.GetNavigationService(this); + if (ns != null) + { + ns.Navigating -= CancelNavigating; //we dont need to cancel next time around + ns.Navigate(canceledNavigation.Uri, canceledNavigation.ExtraData); //navigate using previously stored data + } + } + + /// + /// Given a list of elements with Unloaded Behaviors this method simply applies them and waits till they are done + /// + /// + private void ApplyUnloadedBehaviors(List unloadedBehaviorElements) + { + TimeSpan longestUnload = TimeSpan.FromSeconds(0); + //find the longest UnloadedBehavior so we can wait till it's done + foreach (FrameworkElement fe in unloadedBehaviorElements) + { + ApplyUnloadedBehavior(fe); + Duration dur = GetUnloadedDelay(fe) + GetUnloadedDuration(fe); + if (dur.TimeSpan > longestUnload) + longestUnload = dur.TimeSpan; + } + DispatcherTimer unloadTimer = new DispatcherTimer(longestUnload, DispatcherPriority.Render, HandleUnloadedBehaviorComplete, Dispatcher.CurrentDispatcher); + } + + /// + /// Once all the UnloadedBehaviors have completed we should fire our UnloadBehaviorsComplete event + /// to let anyone else know about this. + /// + /// + /// + private void HandleUnloadedBehaviorComplete(object sender, EventArgs args) + { + DispatcherTimer unloadTimer = (DispatcherTimer)sender; + unloadTimer.Stop(); + if (UnloadBehaviorsComplete != null) + UnloadBehaviorsComplete(this, null); + + } + + /// + /// Given an element, simply apply animations based on the type of UnloadedBehavior it has + /// + /// + private void ApplyUnloadedBehavior(FrameworkElement element) + { + UnloadedBehavior behavior = AnimationBehaviorHost.GetUnloadedBehavior(element); + Duration duration = GetUnloadedDuration(element); + Duration delay = GetUnloadedDelay(element); + + switch (behavior) + { + case UnloadedBehavior.FadeIn: + ApplyFadeIn(element, duration, delay); + break; + case UnloadedBehavior.FadeOut: + ApplyFadeOut(element, duration, delay); + break; + case UnloadedBehavior.ZoomOut: + ApplyZoomOut(element, duration, delay); + break; + case UnloadedBehavior.ZoomOutRotate: + ApplyZoomOutRotate(element, duration, delay); + break; + case UnloadedBehavior.SlideOutToLeft: + ApplySlideOutToLeft(element, duration, delay); + break; + case UnloadedBehavior.SlideOutToTop: + ApplySlideOutToTop(element, duration, delay); + break; + case UnloadedBehavior.SlideOutToRight: + ApplySlideOutToRight(element, duration, delay); + break; + case UnloadedBehavior.SlideOutToBottom: + ApplySlideOutToBottom(element, duration, delay); + break; + case UnloadedBehavior.ScaleOutVertically: + ApplyScaleOutVertically(element, duration, delay); + break; + case UnloadedBehavior.ScaleOutHorizontally: + ApplyScaleOutHorizontally(element, duration, delay); + break; + } + } + + #endregion + + #region UnloadedBehaviors Applied + + private void ApplyZoomOut(FrameworkElement fe, Duration duration, Duration delay) + { + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(1.0, 0.0, duration); + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = new ScaleTransform(1, 1); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = new ScaleTransform(1, 1); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); + } + + } + + private void ApplyZoomOutRotate(FrameworkElement fe, Duration duration, Duration delay) + { + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da1 = new DoubleAnimation(1.0, 0.0, duration); + da1.AccelerationRatio = da1.DecelerationRatio = 0.2; + + DoubleAnimation da2 = new DoubleAnimation(0.0, -360.0, duration); + da2.AccelerationRatio = da2.DecelerationRatio = 0.2; + + TransformGroup tg = new TransformGroup(); + tg.Children.Add(new ScaleTransform(1, 1)); + tg.Children.Add(new RotateTransform(0)); + + tg.Children[0].BeginAnimation(ScaleTransform.ScaleXProperty, da1); + tg.Children[0].BeginAnimation(ScaleTransform.ScaleYProperty, da1); + + tg.Children[1].BeginAnimation(RotateTransform.AngleProperty, da2); + + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = tg; + } + else + { + DoubleAnimationUsingKeyFrames da1 = new DoubleAnimationUsingKeyFrames(); + da1.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da1.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da1.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da1.Duration = delay + duration; + da1.AccelerationRatio = da1.DecelerationRatio = 0.2; + + DoubleAnimationUsingKeyFrames da2 = new DoubleAnimationUsingKeyFrames(); + da2.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da2.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da2.KeyFrames.Add(new LinearDoubleKeyFrame(-360.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da2.Duration = delay + duration; + da2.AccelerationRatio = da2.DecelerationRatio = 0.2; + + TransformGroup tg = new TransformGroup(); + tg.Children.Add(new ScaleTransform(1, 1)); + tg.Children.Add(new RotateTransform(0)); + + tg.Children[0].BeginAnimation(ScaleTransform.ScaleXProperty, da1); + tg.Children[0].BeginAnimation(ScaleTransform.ScaleYProperty, da1); + + tg.Children[1].BeginAnimation(RotateTransform.AngleProperty, da2); + + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = tg; + } + } + + + private void ApplySlideOutToLeft(FrameworkElement fe, Duration duration, Duration delay) + { + GeneralTransform transform = fe.TransformToAncestor(this); + Point slidepoint = transform.Transform(new Point(fe.ActualWidth, 0)); + + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(0, -slidepoint.X, duration); + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(-slidepoint.X, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); + } + } + + private void ApplySlideOutToTop(FrameworkElement fe, Duration duration, Duration delay) + { + GeneralTransform transform = fe.TransformToAncestor(this); + Point slidepoint = transform.Transform(new Point(0, fe.ActualHeight)); + + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(0, -slidepoint.Y, duration); + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(-slidepoint.Y, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); + } + } + + private void ApplySlideOutToRight(FrameworkElement fe, Duration duration, Duration delay) + { + GeneralTransform transform = fe.TransformToAncestor(this); + + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(0, this.ActualWidth, duration); + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(this.ActualWidth, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da); + } + } + + private void ApplySlideOutToBottom(FrameworkElement fe, Duration duration, Duration delay) + { + GeneralTransform transform = fe.TransformToAncestor(this); + + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(0, this.ActualHeight, duration); + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(this.ActualHeight, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0, 0); + fe.RenderTransform = new TranslateTransform(0, 0); + fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); + } + } + + private void ApplyScaleOutVertically(FrameworkElement fe, Duration duration, Duration delay) + { + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(1.0, 0.0, duration); + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = new ScaleTransform(1, 1); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = new ScaleTransform(1, 1); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); + } + + } + + private void ApplyScaleOutHorizontally(FrameworkElement fe, Duration duration, Duration delay) + { + if (delay.TimeSpan == TimeSpan.Zero) + { + DoubleAnimation da = new DoubleAnimation(1.0, 0.0, duration); + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = new ScaleTransform(1, 1); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); + } + else + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan))); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); + da.Duration = delay + duration; + da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0.5, 0.5); + fe.RenderTransform = new ScaleTransform(1, 1); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); + } + } + #endregion + + #endregion + + #region Click Behavior + + #region Click Behavior Attached Properties + /// + /// ClickBehaviorProperty is an attached property which allows decendant elements to run animations when the element is clicked. + /// If the element is not a button the MouseUp event is used instead. + /// + public static readonly DependencyProperty ClickBehaviorProperty = + DependencyProperty.RegisterAttached("ClickBehavior", + typeof(ClickBehavior), + typeof(AnimationBehaviorHost), + new PropertyMetadata(ClickBehavior.None, ClickBehaviorChanged)); + + /// + /// Used to set an elements ClickBehavior attached property + /// + /// + /// + public static void SetClickBehavior(DependencyObject element, ClickBehavior b) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } + + element.SetValue(AnimationBehaviorHost.ClickBehaviorProperty, b); + } + + /// + /// Used to get an elements ClickBehavior attached property + /// + /// + /// + public static ClickBehavior GetClickBehavior(DependencyObject element) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } + + return (ClickBehavior)element.GetValue(AnimationBehaviorHost.ClickBehaviorProperty); + } + + /// + /// ClickDurationProperty is an attached property used to control the duration of the ClickBehavior animation. It defaults to 0.5 seconds. + /// + public static readonly DependencyProperty ClickDurationProperty = + DependencyProperty.RegisterAttached("ClickDuration", + typeof(Duration), + typeof(AnimationBehaviorHost), + new PropertyMetadata(new Duration(TimeSpan.FromMilliseconds(500)))); + + /// + /// Used to set an elements ClickDuration attached property + /// + /// + /// + public static void SetClickDuration(DependencyObject element, Duration b) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } + + element.SetValue(AnimationBehaviorHost.ClickDurationProperty, b); + } + + /// + /// Used to get an elements ClickDuration attached property + /// + /// + /// + public static Duration GetClickDuration(DependencyObject element) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } + + return (Duration)element.GetValue(AnimationBehaviorHost.ClickDurationProperty); + } + + #endregion + + #region Click Behavior Realization + /// + /// When the ClickBehavior attached property is changed we subscribe to the appropriate event on the element + /// + /// + /// + private static void ClickBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + FrameworkElement element = (d as FrameworkElement); + if (element != null) + { + ClickBehavior newbehavior = (ClickBehavior)e.NewValue; + ClickBehavior oldbehavior = (ClickBehavior)e.OldValue; + + if (newbehavior == oldbehavior) + return; + + AnimationBehaviorHost host = FindHost(element); + if (host == null) + return; + + //use Click if it's a button, otherwise use MouseUp + System.Windows.Controls.Primitives.ButtonBase button = + element as System.Windows.Controls.Primitives.ButtonBase; + if (button != null) + { + //use click handler + if (newbehavior == ClickBehavior.None) + button.Click -= host.ApplyClickBehavior; + + if (oldbehavior == ClickBehavior.None) + button.Click += host.ApplyClickBehavior; + } + else + { + //no click handler, so fall back to mouse up + if (newbehavior == ClickBehavior.None) + element.MouseUp -= host.ApplyClickBehavior; + + if (oldbehavior == ClickBehavior.None) + element.MouseUp += host.ApplyClickBehavior; + } + + } + } + + /// + /// When a 'click' is initiated we apply an aninimation to the element based on it's ClickBehavior type. + /// + /// + /// + private void ApplyClickBehavior(object sender, RoutedEventArgs e) + { + FrameworkElement element = (FrameworkElement)sender; + ClickBehavior behavior = AnimationBehaviorHost.GetClickBehavior(element); + Duration duration = GetClickDuration(element); + + switch (behavior) + { + case ClickBehavior.Jiggle: + ApplyJiggle(element, duration); + break; + case ClickBehavior.Throb: + ApplyThrob(element, duration); + break; + case ClickBehavior.Rotate: + ApplyRotate(element, duration); + break; + case ClickBehavior.Snap: + ApplySnap(element, duration); + break; + } + } + #endregion + + #region Click Behaviors Applied + private void ApplyJiggle(FrameworkElement fe, Duration duration) + { DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(this.ActualHeight, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; - fe.RenderTransformOrigin = new Point(0, 0); - fe.RenderTransform = new TranslateTransform(0, 0); - fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da); - } - } - - private void ApplyScaleOutVertically(FrameworkElement fe, Duration duration, Duration delay) - { - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(1.0, 0.0, duration); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(10, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(-10, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(5, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(-5, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); + + da.Duration = duration; da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new ScaleTransform(1, 1); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); - } - else - { + fe.RenderTransform = new RotateTransform(0); + fe.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, da); + } + + private void ApplyThrob(FrameworkElement fe, Duration duration) + { DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.1, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.9, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1.05, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0.95, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + + da.Duration = duration; da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0.5, 0.5); fe.RenderTransform = new ScaleTransform(1, 1); + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); - } + } - } + private void ApplyRotate(FrameworkElement fe, Duration duration) + { + DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(-5, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(90, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(180, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(270, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(360, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(365, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(360, KeyTime.Paced)); - private void ApplyScaleOutHorizontally(FrameworkElement fe, Duration duration, Duration delay) - { - if (delay.TimeSpan == TimeSpan.Zero) - { - DoubleAnimation da = new DoubleAnimation(1.0, 0.0, duration); + da.Duration = duration; da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new ScaleTransform(1, 1); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); - } - else - { + fe.RenderTransform = new RotateTransform(0); + fe.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, da); + } + + private void ApplySnap(FrameworkElement fe, Duration duration) + { DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(TimeSpan.Zero))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, KeyTime.FromTimeSpan(delay.TimeSpan))); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.FromTimeSpan(delay.TimeSpan + duration.TimeSpan))); - da.Duration = delay + duration; + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); + da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); + + da.Duration = duration; da.AccelerationRatio = da.DecelerationRatio = 0.2; + fe.RenderTransformOrigin = new Point(0.5, 0.5); fe.RenderTransform = new ScaleTransform(1, 1); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); - } - } - #endregion - - #endregion - - #region Click Behavior - - #region Click Behavior Attached Properties - /// - /// ClickBehaviorProperty is an attached property which allows decendant elements to run animations when the element is clicked. - /// If the element is not a button the MouseUp event is used instead. - /// - public static readonly DependencyProperty ClickBehaviorProperty = - DependencyProperty.RegisterAttached("ClickBehavior", - typeof(ClickBehavior), - typeof(AnimationBehaviorHost), - new PropertyMetadata(ClickBehavior.None, ClickBehaviorChanged)); - - /// - /// Used to set an elements ClickBehavior attached property - /// - /// - /// - public static void SetClickBehavior(DependencyObject element, ClickBehavior b) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - element.SetValue(AnimationBehaviorHost.ClickBehaviorProperty, b); - } - - /// - /// Used to get an elements ClickBehavior attached property - /// - /// - /// - public static ClickBehavior GetClickBehavior(DependencyObject element) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - return (ClickBehavior)element.GetValue(AnimationBehaviorHost.ClickBehaviorProperty); - } - - /// - /// ClickDurationProperty is an attached property used to control the duration of the ClickBehavior animation. It defaults to 0.5 seconds. - /// - public static readonly DependencyProperty ClickDurationProperty = - DependencyProperty.RegisterAttached("ClickDuration", - typeof(Duration), - typeof(AnimationBehaviorHost), - new PropertyMetadata(new Duration(TimeSpan.FromMilliseconds(500)))); - - /// - /// Used to set an elements ClickDuration attached property - /// - /// - /// - public static void SetClickDuration(DependencyObject element, Duration b) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - element.SetValue(AnimationBehaviorHost.ClickDurationProperty, b); - } - - /// - /// Used to get an elements ClickDuration attached property - /// - /// - /// - public static Duration GetClickDuration(DependencyObject element) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - return (Duration)element.GetValue(AnimationBehaviorHost.ClickDurationProperty); - } - - #endregion - - #region Click Behavior Realization - /// - /// When the ClickBehavior attached property is changed we subscribe to the appropriate event on the element - /// - /// - /// - private static void ClickBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - FrameworkElement element = (d as FrameworkElement); - if (element != null) - { - ClickBehavior newbehavior = (ClickBehavior)e.NewValue; - ClickBehavior oldbehavior = (ClickBehavior)e.OldValue; - - if (newbehavior == oldbehavior) - return; - - AnimationBehaviorHost host = FindHost(element); - if (host == null) - return; - - //use Click if it's a button, otherwise use MouseUp - System.Windows.Controls.Primitives.ButtonBase button = - element as System.Windows.Controls.Primitives.ButtonBase; - if (button != null) - { - //use click handler - if (newbehavior == ClickBehavior.None) - button.Click -= host.ApplyClickBehavior; - - if (oldbehavior == ClickBehavior.None) - button.Click += host.ApplyClickBehavior; + fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); + } + #endregion + + #endregion + + #region Layout Behavior + + #region Layout Behavior Attached Properties + /// + /// LayoutBehaviorProperty is an attached property that can be set on an element to control how it responds to being layed out + /// + public static readonly DependencyProperty LayoutBehaviorProperty = + DependencyProperty.RegisterAttached("LayoutBehavior", + typeof(LayoutBehavior), + typeof(AnimationBehaviorHost), + new PropertyMetadata(LayoutBehavior.None, LayoutBehaviorChanged)); + + /// + /// sets the LayoutBehavior attached property + /// + /// + /// + public static void SetLayoutBehavior(DependencyObject element, LayoutBehavior b) + { + if (element == null) + { + throw new ArgumentNullException("element"); } - else + + element.SetValue(AnimationBehaviorHost.LayoutBehaviorProperty, b); + } + + /// + /// gets the LayoutBehavior attached property + /// + /// + /// + public static LayoutBehavior GetLayoutBehavior(DependencyObject element) + { + if (element == null) { - //no click handler, so fall back to mouse up - if (newbehavior == ClickBehavior.None) - element.MouseUp -= host.ApplyClickBehavior; - - if (oldbehavior == ClickBehavior.None) - element.MouseUp += host.ApplyClickBehavior; - } - - } - } - - /// - /// When a 'click' is initiated we apply an aninimation to the element based on it's ClickBehavior type. - /// - /// - /// - private void ApplyClickBehavior(object sender, RoutedEventArgs e) - { - FrameworkElement element = (FrameworkElement)sender; - ClickBehavior behavior = AnimationBehaviorHost.GetClickBehavior(element); - Duration duration = GetClickDuration(element); - - switch (behavior) - { - case ClickBehavior.Jiggle: - ApplyJiggle(element, duration); - break; - case ClickBehavior.Throb: - ApplyThrob(element, duration); - break; - case ClickBehavior.Rotate: - ApplyRotate(element, duration); - break; - case ClickBehavior.Snap: - ApplySnap(element, duration); - break; - } - } - #endregion - - #region Click Behaviors Applied - private void ApplyJiggle(FrameworkElement fe, Duration duration) - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(10, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(-10, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(5, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(-5, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); - - da.Duration = duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; - - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new RotateTransform(0); - fe.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, da); - } - - private void ApplyThrob(FrameworkElement fe, Duration duration) - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.1, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.9, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1.05, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0.95, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); - - da.Duration = duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; - - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new ScaleTransform(1, 1); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); - } - - private void ApplyRotate(FrameworkElement fe, Duration duration) - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(-5, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(90, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(180, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(270, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(360, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(365, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(360, KeyTime.Paced)); - - da.Duration = duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; - - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new RotateTransform(0); - fe.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, da); - } - - private void ApplySnap(FrameworkElement fe, Duration duration) - { - DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames(); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(0, KeyTime.Paced)); - da.KeyFrames.Add(new LinearDoubleKeyFrame(1, KeyTime.Paced)); - - da.Duration = duration; - da.AccelerationRatio = da.DecelerationRatio = 0.2; - - fe.RenderTransformOrigin = new Point(0.5, 0.5); - fe.RenderTransform = new ScaleTransform(1, 1); - fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da); - } - #endregion - - #endregion - - #region Layout Behavior - - #region Layout Behavior Attached Properties - /// - /// LayoutBehaviorProperty is an attached property that can be set on an element to control how it responds to being layed out - /// - public static readonly DependencyProperty LayoutBehaviorProperty = - DependencyProperty.RegisterAttached("LayoutBehavior", - typeof(LayoutBehavior), - typeof(AnimationBehaviorHost), - new PropertyMetadata(LayoutBehavior.None, LayoutBehaviorChanged)); - - /// - /// sets the LayoutBehavior attached property - /// - /// - /// - public static void SetLayoutBehavior(DependencyObject element, LayoutBehavior b) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - element.SetValue(AnimationBehaviorHost.LayoutBehaviorProperty, b); - } - - /// - /// gets the LayoutBehavior attached property - /// - /// - /// - public static LayoutBehavior GetLayoutBehavior(DependencyObject element) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - return (LayoutBehavior)element.GetValue(AnimationBehaviorHost.LayoutBehaviorProperty); - } - /// - /// LayoutDurationProperty is an attached property used to control the duration of the LayoutBehavior animation. It defaults to 0.5 seconds. - /// - public static readonly DependencyProperty LayoutDurationProperty = - DependencyProperty.RegisterAttached("LayoutDuration", - typeof(Duration), - typeof(AnimationBehaviorHost), - new PropertyMetadata(new Duration(TimeSpan.FromMilliseconds(500)))); - - /// - /// Used to set an elements LayoutDuration attached property - /// - /// - /// - public static void SetLayoutDuration(DependencyObject element, Duration b) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - element.SetValue(AnimationBehaviorHost.LayoutDurationProperty, b); - } - - /// - /// Used to get an elements LayoutDuration attached property - /// - /// - /// - public static Duration GetLayoutDuration(DependencyObject element) - { - if (element == null) - { - throw new ArgumentNullException("element"); - } - - return (Duration)element.GetValue(AnimationBehaviorHost.LayoutDurationProperty); - } - #endregion - - #region Layout Behavior Realization - /// - /// called when an element changes it's LayoutBehavior. Here we simply remember which elements require - /// layout animations so that later when layout is updated we cant add animations as nessesary. - /// - /// - /// - private static void LayoutBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - FrameworkElement element = (d as FrameworkElement); - if (element != null) - { - - LayoutBehavior newbehavior = (LayoutBehavior)e.NewValue; - LayoutBehavior oldbehavior = (LayoutBehavior)e.OldValue; - - if (newbehavior == oldbehavior) - return; - - AnimationBehaviorHost host = FindHost(element); - if (host == null) - return; - - if (oldbehavior == LayoutBehavior.None) - { - host.RegisterLayoutBehaviorElement(element); - - } - - if (newbehavior == LayoutBehavior.None) - { - host.UnregisterLayoutBehaviorElement(element); - } - } - } - - /// - /// this dictionary associates elements with the last known position relative to the host - /// - private Dictionary layoutBehaviorElementPosition = new Dictionary(); - - /// - /// we remember how many elements need layout animations so that we can unsubscribe from the LayoutUpdated event when its not needed - /// - private int layoutBehaviorCount = 0; - private int LayoutBehaviorCount - { - get { return layoutBehaviorCount; } - set - { - int oldval = layoutBehaviorCount; - layoutBehaviorCount = value; - if (oldval == 0 && layoutBehaviorCount > 0) - this.LayoutUpdated += OnLayoutUpdated; - else if (oldval > 0 && layoutBehaviorCount == 0) - this.LayoutUpdated -= OnLayoutUpdated; - } - } - - private void RegisterLayoutBehaviorElement(FrameworkElement element) - { - LayoutBehaviorCount++; - layoutBehaviorElementPosition[element] = null; - } - - private void UnregisterLayoutBehaviorElement(FrameworkElement element) - { - LayoutBehaviorCount--; - layoutBehaviorElementPosition.Remove(element); - } - - - /// - /// this gets called whenever ANY element is updated so we need to check that a specific elements position has changed - /// before adding animations. - /// - /// - /// - void OnLayoutUpdated(object sender, EventArgs e) - { - //TODO: rewrite this method to clean it up and handle corner cases with layout - Dictionary updateDict = new Dictionary(); - foreach (KeyValuePair pair in layoutBehaviorElementPosition) - { - FrameworkElement fe = pair.Key; - Point? savedPosition = pair.Value; - Point currentPosition = fe.TransformToAncestor(this).Transform(new Point(0, 0)); - if (savedPosition.HasValue) - { - if (!AreClose(currentPosition, savedPosition.Value)) - { - LayoutBehavior behavior = GetLayoutBehavior(fe); - Duration duration = GetLayoutDuration(fe); - switch (behavior) - { - case LayoutBehavior.Smooth: - ApplySmoothLayout(fe, savedPosition.Value, currentPosition, duration); - break; - case LayoutBehavior.Springy: - ApplySpringyLayout(fe, savedPosition.Value, currentPosition, duration); - break; - } - - //this is probably a shitty way to update the collection - updateDict[fe] = currentPosition; - } + throw new ArgumentNullException("element"); } - else + + return (LayoutBehavior)element.GetValue(AnimationBehaviorHost.LayoutBehaviorProperty); + } + /// + /// LayoutDurationProperty is an attached property used to control the duration of the LayoutBehavior animation. It defaults to 0.5 seconds. + /// + public static readonly DependencyProperty LayoutDurationProperty = + DependencyProperty.RegisterAttached("LayoutDuration", + typeof(Duration), + typeof(AnimationBehaviorHost), + new PropertyMetadata(new Duration(TimeSpan.FromMilliseconds(500)))); + + /// + /// Used to set an elements LayoutDuration attached property + /// + /// + /// + public static void SetLayoutDuration(DependencyObject element, Duration b) + { + if (element == null) { - //the first time it's layed out just remember where - updateDict[fe] = currentPosition; - } - } - - //update layoutBehaviorElementPosition now that we're not iterating it - if (updateDict != null) - { - foreach (KeyValuePair pair in updateDict) - layoutBehaviorElementPosition[pair.Key] = new Point?(pair.Value); - } - } - - #endregion - - #region Layout Behaviors Applied - private void ApplySmoothLayout(FrameworkElement fe, Point oldpoint, Point newpoint, Duration duration) - { - fe.RenderTransform = new TranslateTransform(); - DoubleAnimation da1 = new DoubleAnimation(oldpoint.X - newpoint.X, 0.0, duration); - da1.AccelerationRatio = da1.DecelerationRatio = 0.2; - DoubleAnimation da2 = new DoubleAnimation(oldpoint.Y - newpoint.Y, 0.0, duration); - da2.AccelerationRatio = da2.DecelerationRatio = 0.2; - fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da1); - fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da2); - } - - private void ApplySpringyLayout(FrameworkElement fe, Point oldpoint, Point newpoint, Duration duration) - { - fe.RenderTransform = new TranslateTransform(); - if (oldpoint.X != newpoint.X) - { - double startx = oldpoint.X - newpoint.X; - double dx = -startx; - - DoubleAnimationUsingKeyFrames da1 = new DoubleAnimationUsingKeyFrames(); - da1.KeyFrames.Add(new LinearDoubleKeyFrame(startx, KeyTime.Paced)); - da1.KeyFrames.Add(new LinearDoubleKeyFrame(startx + dx * 1.25, KeyTime.Paced)); - da1.KeyFrames.Add(new LinearDoubleKeyFrame(startx + dx * 0.75, KeyTime.Paced)); - da1.KeyFrames.Add(new LinearDoubleKeyFrame(startx + dx * 1.1, KeyTime.Paced)); - da1.KeyFrames.Add(new LinearDoubleKeyFrame(startx + dx * 0.9, KeyTime.Paced)); - da1.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.Paced)); - - da1.Duration = duration; - da1.AccelerationRatio = da1.DecelerationRatio = 0.2; + throw new ArgumentNullException("element"); + } - fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da1); - } - - if (oldpoint.Y != newpoint.Y) - { - double starty = oldpoint.Y - newpoint.Y; - double dy = -starty; - - DoubleAnimationUsingKeyFrames da2 = new DoubleAnimationUsingKeyFrames(); - da2.KeyFrames.Add(new LinearDoubleKeyFrame(starty, KeyTime.Paced)); - da2.KeyFrames.Add(new LinearDoubleKeyFrame(starty + dy * 1.25, KeyTime.Paced)); - da2.KeyFrames.Add(new LinearDoubleKeyFrame(starty + dy * 0.75, KeyTime.Paced)); - da2.KeyFrames.Add(new LinearDoubleKeyFrame(starty + dy * 1.1, KeyTime.Paced)); - da2.KeyFrames.Add(new LinearDoubleKeyFrame(starty + dy * 0.9, KeyTime.Paced)); - da2.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.Paced)); - - da2.Duration = duration; - da2.AccelerationRatio = da2.DecelerationRatio = 0.2; + element.SetValue(AnimationBehaviorHost.LayoutDurationProperty, b); + } + + /// + /// Used to get an elements LayoutDuration attached property + /// + /// + /// + public static Duration GetLayoutDuration(DependencyObject element) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } + + return (Duration)element.GetValue(AnimationBehaviorHost.LayoutDurationProperty); + } + #endregion + + #region Layout Behavior Realization + /// + /// called when an element changes it's LayoutBehavior. Here we simply remember which elements require + /// layout animations so that later when layout is updated we cant add animations as nessesary. + /// + /// + /// + private static void LayoutBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + FrameworkElement element = (d as FrameworkElement); + if (element != null) + { + + LayoutBehavior newbehavior = (LayoutBehavior)e.NewValue; + LayoutBehavior oldbehavior = (LayoutBehavior)e.OldValue; + if (newbehavior == oldbehavior) + return; + AnimationBehaviorHost host = FindHost(element); + if (host == null) + return; + + if (oldbehavior == LayoutBehavior.None) + { + host.RegisterLayoutBehaviorElement(element); + + } + + if (newbehavior == LayoutBehavior.None) + { + host.UnregisterLayoutBehaviorElement(element); + } + } + } + + /// + /// this dictionary associates elements with the last known position relative to the host + /// + private Dictionary layoutBehaviorElementPosition = new Dictionary(); + + /// + /// we remember how many elements need layout animations so that we can unsubscribe from the LayoutUpdated event when its not needed + /// + private int layoutBehaviorCount = 0; + private int LayoutBehaviorCount + { + get { return layoutBehaviorCount; } + set + { + int oldval = layoutBehaviorCount; + layoutBehaviorCount = value; + if (oldval == 0 && layoutBehaviorCount > 0) + this.LayoutUpdated += OnLayoutUpdated; + else if (oldval > 0 && layoutBehaviorCount == 0) + this.LayoutUpdated -= OnLayoutUpdated; + } + } + + private void RegisterLayoutBehaviorElement(FrameworkElement element) + { + LayoutBehaviorCount++; + layoutBehaviorElementPosition[element] = null; + } + + private void UnregisterLayoutBehaviorElement(FrameworkElement element) + { + LayoutBehaviorCount--; + layoutBehaviorElementPosition.Remove(element); + } + + + /// + /// this gets called whenever ANY element is updated so we need to check that a specific elements position has changed + /// before adding animations. + /// + /// + /// + void OnLayoutUpdated(object sender, EventArgs e) + { + //TODO: rewrite this method to clean it up and handle corner cases with layout + Dictionary updateDict = new Dictionary(); + foreach (KeyValuePair pair in layoutBehaviorElementPosition) + { + FrameworkElement fe = pair.Key; + Point? savedPosition = pair.Value; + Point currentPosition = fe.TransformToAncestor(this).Transform(new Point(0, 0)); + if (savedPosition.HasValue) + { + if (!AreClose(currentPosition, savedPosition.Value)) + { + LayoutBehavior behavior = GetLayoutBehavior(fe); + Duration duration = GetLayoutDuration(fe); + switch (behavior) + { + case LayoutBehavior.Smooth: + ApplySmoothLayout(fe, savedPosition.Value, currentPosition, duration); + break; + case LayoutBehavior.Springy: + ApplySpringyLayout(fe, savedPosition.Value, currentPosition, duration); + break; + } + + //this is probably a shitty way to update the collection + updateDict[fe] = currentPosition; + } + } + else + { + //the first time it's layed out just remember where + updateDict[fe] = currentPosition; + } + } + + //update layoutBehaviorElementPosition now that we're not iterating it + if (updateDict != null) + { + foreach (KeyValuePair pair in updateDict) + layoutBehaviorElementPosition[pair.Key] = new Point?(pair.Value); + } + } + + #endregion + + #region Layout Behaviors Applied + private void ApplySmoothLayout(FrameworkElement fe, Point oldpoint, Point newpoint, Duration duration) + { + fe.RenderTransform = new TranslateTransform(); + DoubleAnimation da1 = new DoubleAnimation(oldpoint.X - newpoint.X, 0.0, duration); + da1.AccelerationRatio = da1.DecelerationRatio = 0.2; + DoubleAnimation da2 = new DoubleAnimation(oldpoint.Y - newpoint.Y, 0.0, duration); + da2.AccelerationRatio = da2.DecelerationRatio = 0.2; + fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da1); fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da2); - } - } + } - #endregion + private void ApplySpringyLayout(FrameworkElement fe, Point oldpoint, Point newpoint, Duration duration) + { + fe.RenderTransform = new TranslateTransform(); + if (oldpoint.X != newpoint.X) + { + double startx = oldpoint.X - newpoint.X; + double dx = -startx; - #endregion + DoubleAnimationUsingKeyFrames da1 = new DoubleAnimationUsingKeyFrames(); + da1.KeyFrames.Add(new LinearDoubleKeyFrame(startx, KeyTime.Paced)); + da1.KeyFrames.Add(new LinearDoubleKeyFrame(startx + dx * 1.25, KeyTime.Paced)); + da1.KeyFrames.Add(new LinearDoubleKeyFrame(startx + dx * 0.75, KeyTime.Paced)); + da1.KeyFrames.Add(new LinearDoubleKeyFrame(startx + dx * 1.1, KeyTime.Paced)); + da1.KeyFrames.Add(new LinearDoubleKeyFrame(startx + dx * 0.9, KeyTime.Paced)); + da1.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.Paced)); + da1.Duration = duration; + da1.AccelerationRatio = da1.DecelerationRatio = 0.2; - #region Utility Methods + fe.RenderTransform.BeginAnimation(TranslateTransform.XProperty, da1); + } - /// - /// a utility method to see if two points are close together - /// - /// - /// - /// - private bool AreClose(Point p1, Point p2) - { - return (Math.Abs(p1.X - p2.X) < .001 && Math.Abs(p1.Y - p2.Y) < .001); - } + if (oldpoint.Y != newpoint.Y) + { + double starty = oldpoint.Y - newpoint.Y; + double dy = -starty; + DoubleAnimationUsingKeyFrames da2 = new DoubleAnimationUsingKeyFrames(); + da2.KeyFrames.Add(new LinearDoubleKeyFrame(starty, KeyTime.Paced)); + da2.KeyFrames.Add(new LinearDoubleKeyFrame(starty + dy * 1.25, KeyTime.Paced)); + da2.KeyFrames.Add(new LinearDoubleKeyFrame(starty + dy * 0.75, KeyTime.Paced)); + da2.KeyFrames.Add(new LinearDoubleKeyFrame(starty + dy * 1.1, KeyTime.Paced)); + da2.KeyFrames.Add(new LinearDoubleKeyFrame(starty + dy * 0.9, KeyTime.Paced)); + da2.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, KeyTime.Paced)); - /// - /// Given an element, this method walks the tree to find the AnimationBehaviorHost - /// - /// - /// - private static AnimationBehaviorHost FindHost(FrameworkElement e) - { - FrameworkElement current = e; + da2.Duration = duration; + da2.AccelerationRatio = da2.DecelerationRatio = 0.2; - while (current != null) - { - AnimationBehaviorHost host = current as AnimationBehaviorHost; - if (host != null) - return host; + fe.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da2); + } + } + + #endregion + + #endregion + + #region Utility Methods + + /// + /// a utility method to see if two points are close together + /// + /// + /// + /// + private bool AreClose(Point p1, Point p2) + { + return (Math.Abs(p1.X - p2.X) < .001 && Math.Abs(p1.Y - p2.Y) < .001); + } + + + /// + /// Given an element, this method walks the tree to find the AnimationBehaviorHost + /// + /// + /// + private static AnimationBehaviorHost FindHost(FrameworkElement e) + { + FrameworkElement current = e; + + while (current != null) + { + AnimationBehaviorHost host = current as AnimationBehaviorHost; - current = VisualTreeHelper.GetParent(current) as FrameworkElement; - } + if (host != null) + return host; + + current = VisualTreeHelper.GetParent(current) as FrameworkElement; + } - return null; - } + return null; + } - #endregion - } + #endregion + } } \ No newline at end of file diff --git a/Shapes/BabySmashShape.cs b/Shapes/BabySmashShape.cs new file mode 100644 index 0000000..dcbd3a8 --- /dev/null +++ b/Shapes/BabySmashShape.cs @@ -0,0 +1,15 @@ +namespace BabySmash.Shapes +{ + public enum BabySmashShape + { + Circle, + Oval, + Rectangle, + Hexagon, + Trapezoid, + Star, + Square, + Triangle, + Heart + } +} \ No newline at end of file diff --git a/Shapes/CoolCircle.xaml.cs b/Shapes/CoolCircle.xaml.cs index 1b45637..57c7408 100644 --- a/Shapes/CoolCircle.xaml.cs +++ b/Shapes/CoolCircle.xaml.cs @@ -1,15 +1,6 @@ using System; -using System.Collections.Generic; -using System.Text; using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; namespace BabySmash { @@ -19,8 +10,7 @@ namespace BabySmash [Serializable] public partial class CoolCircle : IHasFace { - public CoolCircle(Brush x) - : this() + public CoolCircle(Brush x) : this() { this.Body.Fill = x; } @@ -29,9 +19,7 @@ public CoolCircle() { this.InitializeComponent(); } - - #region IHasFace Members - + public Visibility FaceVisible { get @@ -43,7 +31,5 @@ public Visibility FaceVisible Face.Visibility = value; } } - - #endregion } } \ No newline at end of file diff --git a/Shapes/CoolHeart.xaml.cs b/Shapes/CoolHeart.xaml.cs index cae3715..b861037 100644 --- a/Shapes/CoolHeart.xaml.cs +++ b/Shapes/CoolHeart.xaml.cs @@ -1,49 +1,35 @@ using System; -using System.Collections.Generic; -using System.Text; using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; namespace BabySmash { - /// - /// Interaction logic for CoolHeart.xaml - /// - [Serializable] - public partial class CoolHeart : IHasFace - { - public CoolHeart(Brush x) - : this() - { - this.Body.Fill = x; - } + /// + /// Interaction logic for CoolHeart.xaml + /// + [Serializable] + public partial class CoolHeart : IHasFace + { + public CoolHeart(Brush x) : this() + { + this.Body.Fill = x; + } - public CoolHeart() - { - this.InitializeComponent(); - } - - #region IHasFace Members - - public Visibility FaceVisible - { - get - { - return Face.Visibility; - } - set - { - Face.Visibility = value; - } - } - - #endregion - } + public CoolHeart() + { + this.InitializeComponent(); + } + + public Visibility FaceVisible + { + get + { + return Face.Visibility; + } + set + { + Face.Visibility = value; + } + } + } } \ No newline at end of file diff --git a/Shapes/CoolHexagon.xaml.cs b/Shapes/CoolHexagon.xaml.cs index 8f94be0..f547dfe 100644 --- a/Shapes/CoolHexagon.xaml.cs +++ b/Shapes/CoolHexagon.xaml.cs @@ -1,48 +1,35 @@ using System; -using System.Collections.Generic; -using System.Text; using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; namespace BabySmash { - /// - /// Interaction logic for CoolHexagon.xaml - /// - [Serializable] - public partial class CoolHexagon :IHasFace - { - public CoolHexagon(Brush x) - : this() - { - this.Body.Fill = x; - } + /// + /// Interaction logic for CoolHexagon.xaml + /// + [Serializable] + public partial class CoolHexagon : IHasFace + { + public CoolHexagon(Brush x) : this() + { + this.Body.Fill = x; + } - public CoolHexagon() - { - this.InitializeComponent(); - } - #region IHasFace Members - - public Visibility FaceVisible - { - get - { - return Face.Visibility; - } - set - { - Face.Visibility = value; - } - } - - #endregion - } + public CoolHexagon() + { + this.InitializeComponent(); + } + + public Visibility FaceVisible + { + get + { + return Face.Visibility; + } + set + { + Face.Visibility = value; + } + } + } } \ No newline at end of file diff --git a/Shapes/CoolLetter.xaml.cs b/Shapes/CoolLetter.xaml.cs index d36156f..0121e07 100644 --- a/Shapes/CoolLetter.xaml.cs +++ b/Shapes/CoolLetter.xaml.cs @@ -18,8 +18,7 @@ public CoolLetter() this.InitializeComponent(); } - public CoolLetter(Brush x, char letter) - : this() + public CoolLetter(Brush x, char letter) : this() { this.Character = letter; this.letterPath.Fill = x; diff --git a/Shapes/CoolOval.xaml.cs b/Shapes/CoolOval.xaml.cs index 37b9a5b..abfb44c 100644 --- a/Shapes/CoolOval.xaml.cs +++ b/Shapes/CoolOval.xaml.cs @@ -10,8 +10,7 @@ [Serializable] public partial class CoolOval : IHasFace { - public CoolOval(Brush x) - : this() + public CoolOval(Brush x) : this() { this.Body.Fill = x; } @@ -20,9 +19,7 @@ public CoolOval() { this.InitializeComponent(); } - - #region IHasFace Members - + public Visibility FaceVisible { get @@ -34,7 +31,5 @@ public Visibility FaceVisible Face.Visibility = value; } } - - #endregion } } \ No newline at end of file diff --git a/Shapes/CoolRectangle.xaml.cs b/Shapes/CoolRectangle.xaml.cs index 355f832..f272bf2 100644 --- a/Shapes/CoolRectangle.xaml.cs +++ b/Shapes/CoolRectangle.xaml.cs @@ -1,50 +1,35 @@ using System; -using System.Collections.Generic; -using System.Text; using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; namespace BabySmash { - /// - /// Interaction logic for CoolSquare.xaml - /// - [Serializable] - public partial class CoolRectangle :IHasFace - { - public CoolRectangle(Brush x) - : this() - { - this.Body.Fill = x; - } + /// + /// Interaction logic for CoolSquare.xaml + /// + [Serializable] + public partial class CoolRectangle : IHasFace + { + public CoolRectangle(Brush x) : this() + { + this.Body.Fill = x; + } - public CoolRectangle() - { - this.InitializeComponent(); - } - - #region IHasFace Members - - public Visibility FaceVisible - { - get - { - return Face.Visibility; - } - set - { - Face.Visibility = value; - } - } - - #endregion - - } + public CoolRectangle() + { + this.InitializeComponent(); + } + + public Visibility FaceVisible + { + get + { + return Face.Visibility; + } + set + { + Face.Visibility = value; + } + } + } } \ No newline at end of file diff --git a/Shapes/CoolSquare.xaml.cs b/Shapes/CoolSquare.xaml.cs index 61e05b3..e0e20b2 100644 --- a/Shapes/CoolSquare.xaml.cs +++ b/Shapes/CoolSquare.xaml.cs @@ -1,50 +1,35 @@ using System; -using System.Collections.Generic; -using System.Text; using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; namespace BabySmash { - /// - /// Interaction logic for CoolSquare.xaml - /// - [Serializable] - public partial class CoolSquare : IHasFace - { - public CoolSquare(Brush x) - : this() - { - this.Body.Fill = x; - } + /// + /// Interaction logic for CoolSquare.xaml + /// + [Serializable] + public partial class CoolSquare : IHasFace + { + public CoolSquare(Brush x) : this() + { + this.Body.Fill = x; + } - public CoolSquare() - { - this.InitializeComponent(); - } - - #region IHasFace Members - - public Visibility FaceVisible - { - get - { - return Face.Visibility; - } - set - { - Face.Visibility = value; - } - } - - #endregion - - } + public CoolSquare() + { + this.InitializeComponent(); + } + + public Visibility FaceVisible + { + get + { + return Face.Visibility; + } + set + { + Face.Visibility = value; + } + } + } } \ No newline at end of file diff --git a/Shapes/CoolStar.xaml.cs b/Shapes/CoolStar.xaml.cs index 1082d6d..46f04b0 100644 --- a/Shapes/CoolStar.xaml.cs +++ b/Shapes/CoolStar.xaml.cs @@ -1,49 +1,35 @@ using System; -using System.Collections.Generic; -using System.Text; using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; namespace BabySmash { - /// - /// Interaction logic for CoolStar.xaml - /// - [Serializable] - public partial class CoolStar : IHasFace - { - public CoolStar(Brush x) : this() - { - Body.Fill = x; - } - - - public CoolStar() - { - this.InitializeComponent(); - } - - #region IHasFace Members - - public Visibility FaceVisible - { - get - { - return Face.Visibility; - } - set - { - Face.Visibility = value; - } - } - - #endregion - } + /// + /// Interaction logic for CoolStar.xaml + /// + [Serializable] + public partial class CoolStar : IHasFace + { + public CoolStar(Brush x) : this() + { + Body.Fill = x; + } + + public CoolStar() + { + this.InitializeComponent(); + } + + public Visibility FaceVisible + { + get + { + return Face.Visibility; + } + set + { + Face.Visibility = value; + } + } + } } \ No newline at end of file diff --git a/Shapes/CoolTrapezoid.xaml.cs b/Shapes/CoolTrapezoid.xaml.cs index aaccc10..e6a00b5 100644 --- a/Shapes/CoolTrapezoid.xaml.cs +++ b/Shapes/CoolTrapezoid.xaml.cs @@ -1,48 +1,35 @@ using System; -using System.Collections.Generic; -using System.Text; using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; namespace BabySmash { - /// - /// Interaction logic for CoolTrapezoid.xaml - /// - [Serializable] - public partial class CoolTrapezoid : IHasFace - { - public CoolTrapezoid(Brush x) - : this() - { - Body.Fill = x; - } + /// + /// Interaction logic for CoolTrapezoid.xaml + /// + [Serializable] + public partial class CoolTrapezoid : IHasFace + { + public CoolTrapezoid(Brush x) : this() + { + Body.Fill = x; + } - public CoolTrapezoid() - { - this.InitializeComponent(); - } - #region IHasFace Members - - public Visibility FaceVisible - { - get - { - return Face.Visibility; - } - set - { - Face.Visibility = value; - } - } - - #endregion - } + public CoolTrapezoid() + { + this.InitializeComponent(); + } + + public Visibility FaceVisible + { + get + { + return Face.Visibility; + } + set + { + Face.Visibility = value; + } + } + } } \ No newline at end of file diff --git a/Shapes/CoolTriangle.xaml.cs b/Shapes/CoolTriangle.xaml.cs index ccb7f6f..7b01ff4 100644 --- a/Shapes/CoolTriangle.xaml.cs +++ b/Shapes/CoolTriangle.xaml.cs @@ -1,48 +1,35 @@ using System; -using System.Collections.Generic; -using System.Text; using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; namespace BabySmash { - /// - /// Interaction logic for CoolTriangle.xaml - /// - [Serializable] - public partial class CoolTriangle : IHasFace - { - public CoolTriangle(Brush x) : this() - { - Body.Fill = x; - } + /// + /// Interaction logic for CoolTriangle.xaml + /// + [Serializable] + public partial class CoolTriangle : IHasFace + { + public CoolTriangle(Brush x) : this() + { + Body.Fill = x; + } - public CoolTriangle() - { - this.InitializeComponent(); - } - - #region IHasFace Members - - public Visibility FaceVisible - { - get - { - return Face.Visibility; - } - set - { - Face.Visibility = value; - } - } - - #endregion - } + public CoolTriangle() + { + this.InitializeComponent(); + } + + public Visibility FaceVisible + { + get + { + return Face.Visibility; + } + set + { + Face.Visibility = value; + } + } + } } \ No newline at end of file diff --git a/Shapes/Figure.cs b/Shapes/Figure.cs index 64968a4..eb07a0c 100644 --- a/Shapes/Figure.cs +++ b/Shapes/Figure.cs @@ -1,8 +1,4 @@ -using System.Globalization; using System.Windows; -using System.Windows.Media; -using System.Windows.Shapes; -using BabySmash.Properties; namespace BabySmash { @@ -10,5 +6,4 @@ public interface IHasFace { Visibility FaceVisible { get; set; } } - } \ No newline at end of file diff --git a/Shapes/FigureGenerator.cs b/Shapes/FigureGenerator.cs index ef90544..c4c7712 100644 --- a/Shapes/FigureGenerator.cs +++ b/Shapes/FigureGenerator.cs @@ -6,6 +6,7 @@ using System.Windows.Media.Effects; using BrushControlFunc = System.Func; using BabySmash.Properties; +using BabySmash.Shapes; namespace BabySmash { @@ -21,23 +22,23 @@ public class FigureTemplate public class FigureGenerator { - private static readonly List> hashTableOfFigureGenerators = new List> - { - new KeyValuePair("Circle", x => new CoolCircle(x) ), - new KeyValuePair("Oval", x => new CoolOval(x) ), - new KeyValuePair("Rectangle", x => new CoolRectangle(x) ), - new KeyValuePair("Hexagon", x => new CoolHexagon(x) ), - new KeyValuePair("Trapezoid", x => new CoolTrapezoid(x) ), - new KeyValuePair("Star", x => new CoolStar(x) ), - new KeyValuePair("Square", x => new CoolSquare(x) ), - new KeyValuePair("Triangle", x => new CoolTriangle(x) ), - new KeyValuePair("Heart", x => new CoolHeart(x) ) - }; + private static readonly List> hashTableOfFigureGenerators = new List> + { + new KeyValuePair(BabySmashShape.Circle, x => new CoolCircle(x) ), + new KeyValuePair(BabySmashShape.Oval, x => new CoolOval(x) ), + new KeyValuePair(BabySmashShape.Rectangle, x => new CoolRectangle(x) ), + new KeyValuePair(BabySmashShape.Hexagon, x => new CoolHexagon(x) ), + new KeyValuePair(BabySmashShape.Trapezoid, x => new CoolTrapezoid(x) ), + new KeyValuePair(BabySmashShape.Star, x => new CoolStar(x) ), + new KeyValuePair(BabySmashShape.Square, x => new CoolSquare(x) ), + new KeyValuePair(BabySmashShape.Triangle, x => new CoolTriangle(x) ), + new KeyValuePair(BabySmashShape.Heart, x => new CoolHeart(x) ) + }; public static UserControl NewUserControlFrom(FigureTemplate template) { UserControl retVal = null; - + if (template.Letter.Length == 1 && Char.IsLetterOrDigit(template.Letter[0])) { retVal = new CoolLetter(template.Fill.Clone(), template.Letter[0]); @@ -60,11 +61,11 @@ public static UserControl NewUserControlFrom(FigureTemplate template) group.Children[0].BeginAnimation(ScaleTransform.ScaleYProperty, ani1); group.Children[1].BeginAnimation(RotateTransform.AngleProperty, ani2); - if (Settings.Default.UseEffects) + if (Settings.Default.BitmapEffects) { retVal.Effect = template.Effect.Clone(); } - + return retVal; } @@ -76,11 +77,21 @@ public static FigureTemplate GenerateFigureTemplate(char displayChar) { Color c = Utils.GetRandomColor(); - var nameFunc = hashTableOfFigureGenerators[Utils.RandomBetweenTwoNumbers(0, hashTableOfFigureGenerators.Count - 1)]; + string name = null; + KeyValuePair nameFunc = hashTableOfFigureGenerators[Utils.RandomBetweenTwoNumbers(0, hashTableOfFigureGenerators.Count - 1)]; + if (Char.IsLetterOrDigit(displayChar)) + { + name = displayChar.ToString(); + } + else + { + name = Controller.GetLocalizedString(nameFunc.Key.ToString()); + } + return new FigureTemplate { Color = c, - Name = Char.IsLetterOrDigit(displayChar) ? displayChar.ToString() : nameFunc.Key, + Name = name, GeneratorFunc = nameFunc.Value, Fill = Utils.GetGradientBrush(c), Letter = displayChar.ToString(), diff --git a/Shapes/FunCursor1.xaml.cs b/Shapes/FunCursor1.xaml.cs index 0828378..d16bd46 100644 --- a/Shapes/FunCursor1.xaml.cs +++ b/Shapes/FunCursor1.xaml.cs @@ -1,26 +1,15 @@ using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; namespace BabySmash { - /// - /// Interaction logic for FunCursor1.xaml - /// - public partial class FunCursor1 - { - public FunCursor1() - { - this.InitializeComponent(); - } - } + /// + /// Interaction logic for FunCursor1.xaml + /// + public partial class FunCursor1 + { + public FunCursor1() + { + this.InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Shapes/FunCursor2.xaml.cs b/Shapes/FunCursor2.xaml.cs index 4c0194c..6a21df5 100644 --- a/Shapes/FunCursor2.xaml.cs +++ b/Shapes/FunCursor2.xaml.cs @@ -1,26 +1,15 @@ using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; namespace BabySmash { - /// - /// Interaction logic for FunCursor2.xaml - /// - public partial class FunCursor2 - { - public FunCursor2() - { - this.InitializeComponent(); - } - } + /// + /// Interaction logic for FunCursor2.xaml + /// + public partial class FunCursor2 + { + public FunCursor2() + { + this.InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Tweening/Equations.cs b/Tweening/Equations.cs index 41df622..5059cf8 100644 --- a/Tweening/Equations.cs +++ b/Tweening/Equations.cs @@ -1,6 +1,5 @@ namespace Tweener { - using System; /// @@ -31,12 +30,12 @@ All rights reserved. */ public static class Equations - { - // ================================================================================================================================== - // TWEENING EQUATIONS functions ----------------------------------------------------------------------------------------------------- - // (the original equations are Robert Penner's work as mentioned on the disclaimer) + { + // ================================================================================================================================== + // TWEENING EQUATIONS functions ----------------------------------------------------------------------------------------------------- + // (the original equations are Robert Penner's work as mentioned on the disclaimer) - /** + /** * Easing equation function for a simple linear tweening, with no easing. * * @param t Current time (in seconds). @@ -50,9 +49,9 @@ public static double EaseNone(params double[] args) double t; double b; double c; double d; t = args[0]; b = args[1]; c = args[2]; d = args[3]; return c * t / d + b; - } - - /** + } + + /** * Easing equation function for a quadratic (t^2) easing in: accelerating from zero velocity. * * @param t Current time (in seconds). @@ -66,7 +65,7 @@ public static double EaseInQuad(params double[] args) double t; double b; double c; double d; t = args[0]; b = args[1]; c = args[2]; d = args[3]; return c * (t /= d) * t + b; - } + } /** * Easing equation function for a quadratic (t^2) easing out: decelerating to zero velocity. @@ -793,6 +792,6 @@ public static double EaseOutInBounce(params double[] args) if (t < d / 2) return EaseOutBounce(t * 2, b, c / 2, d); return EaseInBounce((t * 2) - d, b + c / 2, c / 2, d); } - - } -} + + } +} \ No newline at end of file diff --git a/Tweening/TransitionType.cs b/Tweening/TransitionType.cs index 7a895a7..d9bb9d2 100644 --- a/Tweening/TransitionType.cs +++ b/Tweening/TransitionType.cs @@ -170,4 +170,4 @@ public enum TransitionType /// EaseOutInBounce } -} +} \ No newline at end of file diff --git a/Tweening/Tween.cs b/Tweening/Tween.cs index 881b5a6..65eed3e 100644 --- a/Tweening/Tween.cs +++ b/Tweening/Tween.cs @@ -45,13 +45,15 @@ private static void OnTweenChanged(DependencyObject o, DependencyPropertyChanged { DoubleAnimationUsingKeyFrames animation = o as DoubleAnimationUsingKeyFrames; - if (animation != null && animation.Duration.HasTimeSpan) { + if (animation != null && animation.Duration.HasTimeSpan) + { TransitionType type = GetTransitionType(animation); double from = GetFrom(animation); double to = GetTo(animation); double fps = GetFps(animation); - if (fps <= 0) { + if (fps <= 0) + { fps = DefaultFps; } @@ -69,7 +71,8 @@ private static void FillAnimation(DoubleAnimationUsingKeyFrames animation, Trans // clear animation animation.KeyFrames.Clear(); - for (double i = 0; i < total; i += step) { + for (double i = 0; i < total; i += step) + { LinearDoubleKeyFrame frame = new LinearDoubleKeyFrame(); frame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(i)); frame.Value = equation(i, from, to - from, total); @@ -192,4 +195,4 @@ public static void SetFps(DependencyObject o, double value) o.SetValue(FpsProperty, value); } } -} +} \ No newline at end of file diff --git a/Utils.cs b/Utils.cs index 6f7c76e..3800347 100644 --- a/Utils.cs +++ b/Utils.cs @@ -2,24 +2,21 @@ using System.Collections.Generic; using System.Windows; using System.Windows.Media; -using System.Windows.Markup; -using System.IO; -using System.Xml; namespace BabySmash { - internal static class Utils - { - private static readonly Dictionary brushToString; + internal static class Utils + { + private static readonly Dictionary brushToString; - private static readonly Random lRandom = new Random(); // BUG BUG: Believe it or not, Random is NOT THREAD SAFE! + private static readonly Random lRandom = new Random(); // BUG BUG: Believe it or not, Random is NOT THREAD SAFE! - private static readonly FunCursor1 fun1 = new FunCursor1(); - private static readonly FunCursor2 fun2 = new FunCursor2(); + private static readonly FunCursor1 fun1 = new FunCursor1(); + private static readonly FunCursor2 fun2 = new FunCursor2(); - private static readonly Color[] someColors; + private static readonly Color[] someColors; - private static readonly string[] sounds = { + private static readonly string[] sounds = { "giggle.wav", "babylaugh.wav", "babygigl2.wav", @@ -28,9 +25,9 @@ internal static class Utils "scooby2.wav", }; - static Utils() - { - brushToString = new Dictionary + static Utils() + { + brushToString = new Dictionary { {Colors.Red, "Red"}, {Colors.Blue, "Blue"}, @@ -43,69 +40,69 @@ static Utils() {Colors.Gray, "Gray"} }; - someColors = new Color[brushToString.Count]; - brushToString.Keys.CopyTo(someColors, 0); - } - - public static Color GetRandomColor() - { - Color color = someColors[lRandom.Next(0, someColors.Length)]; - return color; - } - - public static Brush GetGradientBrush(Color color) - { - RadialGradientBrush myBrush = new RadialGradientBrush(); - myBrush.GradientOrigin = new Point(0.75, 0.25); - myBrush.GradientStops.Add(new GradientStop(color.LightenOrDarken(50), 0.0)); - myBrush.GradientStops.Add(new GradientStop(color, 0.5)); - myBrush.GradientStops.Add(new GradientStop(color.LightenOrDarken(-50), 1.0)); - return myBrush; - } - - public static Color LightenOrDarken(this Color src, sbyte degree) - { - Color ret = new Color(); - ret.A = src.A; - ret.R = (byte)Math.Max(Math.Min(src.R + degree, 255), 0); - ret.G = (byte)Math.Max(Math.Min(src.G + degree, 255), 0); - ret.B = (byte)Math.Max(Math.Min(src.B + degree, 255), 0); - return ret; - } - - - public static string ColorToString(Color b) - { - return brushToString[b]; - } - - public static string GetRandomSoundFile() - { - return sounds[lRandom.Next(0, sounds.Length)]; - } - - public static bool GetRandomBoolean() - { - if (lRandom.Next(0, 2) == 0) - return false; - return true; - } - - public static int RandomBetweenTwoNumbers(int min, int max) - { - return lRandom.Next(min, max + 1); - } - - internal static System.Windows.Controls.UserControl GetCursor() - { - switch (Properties.Settings.Default.CursorType) - { - case "Hand": - return fun2; - case "Arrow": - return fun1; - } - return fun1; - } - } + someColors = new Color[brushToString.Count]; + brushToString.Keys.CopyTo(someColors, 0); + } + + public static Color GetRandomColor() + { + Color color = someColors[lRandom.Next(0, someColors.Length)]; + return color; + } + + public static Brush GetGradientBrush(Color color) + { + RadialGradientBrush myBrush = new RadialGradientBrush(); + myBrush.GradientOrigin = new Point(0.75, 0.25); + myBrush.GradientStops.Add(new GradientStop(color.LightenOrDarken(50), 0.0)); + myBrush.GradientStops.Add(new GradientStop(color, 0.5)); + myBrush.GradientStops.Add(new GradientStop(color.LightenOrDarken(-50), 1.0)); + return myBrush; + } + + public static Color LightenOrDarken(this Color src, sbyte degree) + { + Color ret = new Color(); + ret.A = src.A; + ret.R = (byte)Math.Max(Math.Min(src.R + degree, 255), 0); + ret.G = (byte)Math.Max(Math.Min(src.G + degree, 255), 0); + ret.B = (byte)Math.Max(Math.Min(src.B + degree, 255), 0); + return ret; + } + + + public static string ColorToString(Color b) + { + return brushToString[b]; + } + + public static string GetRandomSoundFile() + { + return sounds[lRandom.Next(0, sounds.Length)]; + } + + public static bool GetRandomBoolean() + { + if (lRandom.Next(0, 2) == 0) + return false; + return true; + } + + public static int RandomBetweenTwoNumbers(int min, int max) + { + return lRandom.Next(min, max + 1); + } + + internal static System.Windows.Controls.UserControl GetCursor() + { + switch (Properties.Settings.Default.CursorType) + { + case "Hand": + return fun2; + case "Arrow": + return fun1; + } + return fun1; + } + } } \ No newline at end of file diff --git a/Words.txt b/Words.txt index 575b318..369dd07 100644 --- a/Words.txt +++ b/Words.txt @@ -1,25 +1,1810 @@ +AARAV +AARON +ABIGAIL +ABLE +ABOUT +ABOVE +ABRAHAM +ACCEPT +ACCEPTED +ACCEPTING +ACCEPTS +ACORN +ACORNS +ACROSS +ACT +ACTED +ACTING +ACTOR +ACTORS +ACTS +ADAM +ADD +ADDED +ADDER +ADDERS +ADDING +ADDS +ADJECTIVE +ADJECTIVES +AFTER +AGAIN +AGAINST +AGO +AIDEN +AIR +AIRED +AIRING +AIRPLANE +AIRPLANES +AIRS +ALEX +ALEXIS +ALFIE +ALI +ALICE +ALL +ALONG +ALSO +ALWAYS +ALYSSA +AM +AMBER +AMELIA +AMELIE +AMERICA +AMONG +AMY +AN +AND +ANDREW +ANIMAL +ANIMALS +ANNA +ANOTHER +ANSWER +ANSWERED +ANSWERING +ANSWERS +ANT +ANTS +ANY +APPEAR +APPEARED +APPEARING +APPEARS +APPLE +APPLES +ARE +AREA +ARIA +ARIANA +AROUND +ARTHUR +AS +ASK +ASKED +ASKING +AT +ATE +AUDIO +AUNT +AUNTS +AUSTIN +AVA +AVERY +AWAY BABIES BABY +BABYSMASH +BACK +BACKS +BAD +BALD +BALL +BAN BANANA BANANAS +BANG +BANNED +BANNING +BANS +BAR +BARD +BARRED +BARRING +BARS +BASE +BASED +BASES +BASING +BATTERIES +BATTERY +BE +BEAR +BEARING +BEARS +BEAUTIFUL +BEAUTY +BECAME +BECAUSE +BECOME +BED +BEDS +BEE +BEEN +BEES +BEFORE +BEGAN +BEGIN +BEGUN +BEHIND +BELINDA +BELL +BELLA +BELLS +BEN +BENEATH +BENJAMIN +BEST +BETHANY +BETTER +BETWEEN +BIG +BIGGER +BIGGEST +BILL +BILLED +BILLING +BILLS +BIRD +BIRDS +BIRTH +BIRTHDAY +BIRTHDAYS +BIRTHS +BIRTS +BLACK +BLAKE +BLUE +BLUES +BOAT +BOATS +BODIES +BODY +BOLT +BOLTS +BOOK +BOOKED +BOOKING +BOOKS +BOTH +BOUGHT +BOWL +BOWLS +BOX +BOXED +BOXES +BOXING +BOY +BOYS +BRANCH +BRANCHED +BRANCHES +BRANCHING +BREAD +BREADED +BREADS +BRING +BRINGS +BROAD +BROTHER +BROTHERS +BROUGHT +BROWN +BUILD +BUILDING +BUILDINGS +BUILDS +BUILT +BUSIER +BUSIEST +BUSY +BUT +BUY +BUYER +BUYING +BUYS +BY +BYE +CAB +CABLE +CABLES +CABS +CAKE +CAKED +CAKES +CALEB +CALL +CALLED +CALLING +CALLS +CALLUM +CAME +CAMERON +CAMP +CAMPED +CAMPER +CAMPERS +CAMPING +CAN +CANNOT +CAR +CARE +CARED +CAREFUL +CAREFULLY +CARES +CARING +CARRIES +CARROT +CARROTS +CARRY +CARS +CARSON +CASE +CASTLE +CASTLES +CAT +CATS +CAUSE +CAYLEE +CELL +CELLAR +CELLARS +CELLS +CENT +CENTER +CENTS +CENTURIES +CENTURY +CERTAIN +CHAIR +CHAIRS +CHANGE +CHANGES +CHARLIE +CHECK +CHECKS +CHEER +CHEERED +CHEERING +CHEERS +CHICKEN +CHICKENS +CHILD +CHILDREN +CHLOE +CIRCLE +CIRCLES +CITIES +CITY +CLARA +CLASS +CLASSES +CLEAN +CLEAR +CLEARED +CLEARING +CLEARS +CLOSE +CLOSED +CLOSER +CLOSES +CLOSING +CLOTHES +COAT +COATS +CODE +CODED +CODER +CODERS +CODES +CODING +COLD +COLDER +COLDEST +COLDS +COLOR +COLORED +COLORFUL +COLORING +COLORS +COME +COMING +COMMON +COMPANY +COMPLETE +COMPLETED +COMPLETING +COMPUTED +COMPUTER +COMPUTERS +COMPUTING +CONNOR +CONTAIN +CONTAINS +COOL +COOLED +COOLER +COOLERS +COOLING +CORD +CORDS +CORN +CORNS +CORRECT +CORRECTED +CORRECTS +COULD +COUNTRIES +COUNTRY +COURSE +COURSES +COVER +COVERED +COVERS +COW +COWS +CRAB +CRABS +CREEPY +CRIED +CRIER +CRIES +CROSS +CROSSED +CROSSING +CRY +CURSOR +CURSORS +CURSORY +CURTAIN +CURTAINS +CUT +CUTE +CUTER +CUTEST +CUTS +DAD +DADDY +DADS +DAISY +DANIEL +DARK +DAUGHTER +DAUGHTERS +DAVID +DAY +DAYS +DECIDE +DECIDED +DECIDING +DEEP +DEEPER +DENISE +DESK +DESKS +DEVELOP +DEVELOPER +DEVELOPING +DEVELOPS +DEXTER +DID +DIFFER +DIFFERENT +DIRECT +DISTANCE +DISTANT +DO +DOES +DOG +DOGS +DOLL +DOLLAR +DOLLARS +DOLLS +DONE +DOOR +DOORS +DORA +DOWN +DRAGON +DRAGONS +DRAIN +DRAINED +DRAINING +DRAINS +DRANK +DRAW +DRAWS +DRINK +DRINKS +DRIVE +DRIVER +DRIVES +DRIVING +DROVE +DRY +DUCK +DUCKED +DUCKING +DUCKS +DURING +DYLAN +EACH +EARLY +EARTH +EASE +EASES +EASIER +EASIEST +EAST +EASY +EAT +ED +EDWARD +EGG +EGGS +EIGHT +EIGHTEEN +EIGHTEENTH +EIGHTH +EIGHTY +ELBOW +ELBOWS +ELEANOR +ELEMENT +ELEMENTS +ELENA +ELEVEN +ELEVENTH +ELI +ELIJAH +ELIOT +ELIZA +ELLA +ELLIE +ELLIS +ELSA +ELSIE +EMILIA +EMILY +EMMA +END +ENDS +ENGLISH +ENOUGH +EQUATE +EQUATION +ERIN +ESME +ETHAN +EVA +EVAN +EVELYN +EVEN +EVER +EVERY +EVIE +EXAMPLE +EXPLAIN +EYE +EYES +FACE +FACES +FACT +FACTS +FAITH +FALL +FAMILIAR +FAMILIES +FAMILY +FAR +FARM +FARMER +FARMERS +FARMS +FAST +FASTER +FASTEST +FATHER +FATHERS +FEEL +FEELING +FEELINGS +FEET +FELIX +FELL +FELT +FEW +FIELD +FIELDS +FIFTEEN +FIFTEENTH +FIFTH +FIFTY +FIGURE +FIGURED +FIGURES +FIGURING +FILE +FILED +FILING +FILL +FILLED +FILLER +FILLERS +FILLING +FILLS +FINAL +FINALLY +FIND +FINDER +FINDING +FINDINGS +FINE +FINES +FINGER +FINGERS +FINLEY +FINN +FIRE +FIRES +FIRST +FISH +FISHER +FISHERY +FISHES +FIVE +FLED +FLEE +FLIER +FLIES +FLIGHT +FLIGHTS +FLOOR +FLOORS +FLOPPY +FLORENCE +FLOW +FLOWER +FLOWERS +FLOWS +FLU +FLUFF +FLUFFY +FLY +FOLLOW +FOLLOWED +FOLLOWER +FOLLOWERS +FOLLOWING +FOLLOWS +FOOD +FOODS +FOOT +FOR +FORCE +FORCED +FORCES +FORCING +FORK +FORKS +FORM +FORMS +FORTY +FOUND +FOUR +FOURTEEN +FOURTEENTH +FOURTH +FRAME +FRAMES +FREDDIE +FREE +FREED +FREEING +FREES +FREYA +FRIDAY +FRIEND +FRIENDS +FROM +FRONT +FULL FUN +FUNNIER +FUNNIEST +FUNNY +GABRIEL +GAME +GAMER +GAMES +GAMING +GARDEN +GARDENS +GAVE +GEORGE +GEORGIA +GET +GIANT +GIFT +GIFTED +GIFTING +GIFTS +GIRL +GIRLS +GIVE +GIVER +GIVING +GO +GOES +GOLD +GONE +GOOD +GOODS +GOT +GOVERN +GOVERNMENT +GRACE +GRACIE +GRAN +GRANDDAD +GRASS +GREAT +GREEN +GROUND +GROUNDS +GROUP +GROW +GROWING +GROWN +GROWS +GUARD +GUARDED +GUARDING +GUARDS +HAD +HALF +HAND +HANDED +HANDING +HANDS +HANDY +HANNAH +HAPPEN +HAPPENED +HAPPENING +HAPPENS +HAPPY +HARD +HARP +HARPER +HARPS +HARRIET +HARRISON +HARRY +HARVEY +HAS +HAT +HATS +HAVE +HE +HEAD +HEADS +HEAR +HEARD +HEARING +HEARS +HEART +HEARTS +HEAT +HEATED +HEATER +HEATING +HEATS +HEAVY +HELP +HELPED +HELPER +HELPING +HELPS +HENRY +HER +HERE +HERS +HEXAGON +HEXAGONS +HIGH +HILL +HILLS +HIM +HIMSELF +HIS +HISTORY +HOLD +HOLLY +HOME +HOMES +HORSE +HORSES +HOT +HOTTER +HOTTEST +HOUR +HOURS +HOUSE +HOUSES +HOUSING +HOUSINGS +HOW +HOWEVER +HUDNRED +HUGO +HUNDRED +HUNDREDS +HUNTER +HURT +IBRAHIM +IDEA +IDEAS +IF +ILL +IMOGEN +IMPORTANT +IN +INCH +INCHES +INCLUDE +INFINITY +INSIDE +INSIDER +INSIDES +INTEREST +INTERESTED +INTERESTING +INTERESTS +INTO +IRIS +IS +ISAAC +ISABELLA +ISABELLE +ISLA +ISLAND +ISLANDS +ISSUE +ISSUES +IT +ITS +IVY +JACK +JACKSON +JACOB +JAKE +JAMES +JAMIE +JASMINE +JASON +JASPER +JAYDEN +JAZZ +JESSICA +JILL +JOANA +JODI +JOHN +JOKE +JOKED +JOKER +JOKERS +JOKES +JOKING +JONATHAN +JOSEPH +JOSHUA +JUDE +JUMP +JUMPED +JUMPER +JUMPING +JUMPS +JUST +KAI +KATIE +KATY +KAY +KAYAK +KAYAKS +KAYLA +KEEP +KEPT +KEY +KEYBOARD +KEYBOARDS +KEYS +KIAN +KIND +KINDS +KING +KINGS +KITE +KITES +KITTY +KNEW +KNIFE +KNIVES +KNOW +KNOWING +KNOWN +KNOWS +KYLE +LACEY +LAND +LANDED +LANDING +LANDS +LANGUAGE +LANGUAGES +LARA +LARGE +LARGER +LARGEST +LAST +LATE +LATER +LATEST +LAUGH +LAUGHED +LAUGHING +LAUGHS +LAY +LAYLA +LEAD +LEADS +LEAH +LEARN +LEAVE +LEAVES +LEFT +LEG +LEGS +LEO +LEON +LESS +LET +LETS +LETTER +LETTERS +LEWIS +LEXI +LIAM +LIFE +LIFT +LIFTED +LIFTING +LIFTS +LIGHT +LIKE +LIKED +LILY +LINE +LINED +LINES +LINING +LININGS +LIST +LISTEN +LISTENED +LISTENER +LISTENING +LISTENS +LITTLE +LITTLER +LITTLEST +LIVE +LIVED +LIVES +LIVING +LNE +LOGAN +LOLA +LONG +LOOK +LOOKED +LOOKING +LOOKS +LOTTIE +LOVE +LOVED +LOVES +LOVING +LOW +LOWS +LUCA +LUCAS +LUCY +MACHINE +MACHINES +MADE +MADISON +MAIN +MAISIE +MAKE +MAKES +MAKING +MAN +MANY +MAP +MAPS +MARCUS +MARIA +MARK +MARKS +MARYAM +MASON +MATERIAL +MATILDA +MATTHEW +MAX +MAY +MAYA +ME +MEAN +MEANS +MEASURE +MEASURED +MEASURES +MEASURING +MEAT +MEATS +MEET +MEETS +MEGAN +MEN +METAL +METALS +MIA +MICHAEL +MIGHT +MILA +MILE +MILK +MILLIE +MILO +MIND +MINDS +MINUTE +MINUTES +MISS +MISSED +MISSES +MISSING +MOLLY +MOM +MOMMY +MOMS +MONDAY +MONEY +MONTH +MONTHS +MOON +MOONS +MORE +MORNING +MOST +MOTHER +MOTHERS +MOUNTAIN +MOUNTAINS +MOVE +MOVED +MOVER +MOVES +MOVING +MUCH +MULTIPLY +MUM +MUSIC +MUST +MY +MYSELF +NAIL +NAILS +NAME +NAMES +NANA +NAOMI +NATHAN +NEAR +NECK +NECKLACE +NECKLACES +NECKS +NEED +NEEDED +NEEDING +NEEDS +NEST +NESTS +NEVER +NEW +NEWS +NEXT +NIAMH +NIGHT +NIGHTS +NINE +NINETEEN +NINETEENTH +NINETY +NINTH +NO +NOAH +NORTH +NOT +NOTE +NOTES +NOTHING +NOTICE +NOUN +NOUNS +NOW +NUMBER +NUMBERS +NUMERAL +OBJECT +OCEAN +OF +OFF +OFFICE +OFFICES +OFFICIAL +OFFICIALS +OFTEN +OH +OIL +OILS +OKAY +OLD +OLIVER +OLIVIA +OLLIE +OMAR +ON +ONCE +ONE +ONLY +OPEN +OPENED +OPENING +OPENS +OR +ORANGE +ORANGES +ORB +ORBIT +ORBITS +ORBS +ORDER +ORDERED +ORDERING +ORDERS +OSCAR +OTHER +OTHERS +OUR +OURS +OUT +OUTSIDE +OVAL +OVALS +OVER +OVERNMENT +OWEN +OWN +PAGE +PAGED +PAGER +PAGES +PAGING +PAINT +PAINTED +PAINTER +PAINTERS +PAINTING +PAINTINGS +PAINTS +PAIR +PAIRS +PALACE +PALACES +PANT +PANTS +PAPA +PAPER +PAPERS +PAPERWORK +PARK +PARKED +PARKER +PARKING +PARKS +PART +PARTED +PARTING +PARTS +PARTY +PASS +PASSED +PASSES +PASSING +PATTERN +PEN +PENCIL +PENCILS +PENNED +PENS +PEOPLE +PERSON +PHOEBE +PICK +PICKED +PICKER +PICKING +PICKS +PICTURE +PICTURED +PICTURES +PICTURING +PIECE +PIECED +PIECES +PIECING +PIG +PIGS +PIPE +PIPES +PLACE +PLACES +PLAIN +PLAINS +PLAN +PLANE +PLANES +PLANNED +PLANNER +PLANNING +PLANS +PLANT +PLANTED +PLANTER +PLANTERS +PLANTING +PLANTS +PLASTIC +PLASTICS +PLATE +PLATES +PLAY +PLAYED +PLAYER +PLAYING +PLAYS +PLEASE +POINT +POINTS +POPPY +PORT +PORTAGE +PORTING +PORTS +POSE +POSED +POSES +POSING +POSSIBLE +POUND +POUNDING +POUNDS +POWER +PREPOSITION +PREPOSITIONS +PRESENT +PRESENTS +PRESS +PRESSED +PRESSES +PRESSING +PRETTY +PROBLEM +PROBLEMS +PRODUCE +PRODUCED +PRODUCER +PRODUCES +PRODUCING +PRODUCT +PRODUCTS +PUBLIC +PUDDING +PUDDINGS +PULL +PULLED +PULLEY +PULLEYS +PULLS +PUT +PUTS +PUTTER +PUTTERS +PUTTING +QUEEN +QUEENS +QUESTION +QUESTIONED +QUESTIONING +QUESTIONS +QUICK +QUICKLY +QUIET +QUIETER +QUIETLY +QUIETS +RABBIT +RABBITS +RADIO +RADIOS +RAIL +RAILS +RAIN +RAINS +RAN +RANDY +REACH +REACHED +REACHES +REACHING +READ +READY +REALLY +REBECCA +RECORD +RECORDED +RECORDING +RECORDS +RECTANGLE +RECTANGLES +RED +REMEMBER +REMEMBERED +REMEMBERING +REMEMBERS +REMOVE +REMOVED +REMOVES +REMOVING +REST +RESTED +RESTING +RESTS +REUBEN +RIDE +RIDES +RIGHT +RIGHTS +RILEY +RING +RINGS +RIVER +RIVERS +ROAD +ROADS +ROBIN +ROBINS +ROBYN +ROCK +ROCKED +ROCKING +ROCKS +RODE +ROLL +ROLLS +RONDA +ROOM +ROOMS +RORY +ROSE +ROSIE +ROUND +RUBY +RULE +RULED +RULER +RULERS +RULES +RULING +RUN +RYAN +SAFE +SAFEST +SAFETY +SAID +SALE +SALES +SALON +SAM +SAME +SAMUEL +SANG +SARAH +SAT +SATURDAY +SAVE +SAVED +SAVES +SAVING +SAVINGS +SAW +SAWS +SAY +SCARLETT +SCHOOL +SCHOOLS +SCIENCE +SCIENCES +SCIENTISTS +SCOTT +SEA +SECOND +SECONDS +SEE +SEED +SEEDS +SEEING +SEEM +SEEN +SELF +SELL +SELLER +SELLING +SELVES +SENTENCE +SERVE +SET +SETH +SEVEN +SEVENTEEN +SEVENTEENTH +SEVENTH +SEVENTY +SEVERAL +SHALL +SHAPE +SHAPES +SHE +SHEEP +SHEPHERD +SHIP +SHIPPED +SHIPPING +SHIPS +SHIRT +SHIRTS +SHOE +SHOES +SHOP +SHOPPED +SHOPPER +SHOPPING +SHOPS +SHORT +SHORTS +SHOULD +SHOULDER +SHOULDERS +SHOW +SHOWN +SHUTTLE +SHUTTLES +SIDE +SIDED +SIDES +SIDING +SIENNA +SIGN +SILLIER +SILLIEST +SILLY +SIMON +SINCE +SING +SISTER +SISTERS +SIT +SIX +SIXTEEN +SIXTEENTH +SIXTH +SIXTY +SIZE +SKIRT +SKIRTS +SKYE +SLEEP +SLOW +SLOWER +SLOWEST +SLOWLY +SMALL +SMALLER +SMALLEST SMASH SMASHED SMASHES SMASHING -WORD -WORDS -CAT -DOG -MOMMY -MOM -DAD -PAPA -NANA SNAKE -FOOD -MILK -COMPUTER +SNAKES +SNOW +SNOWS +SO +SOCK +SOCKS +SOME +SON +SONG +SONGS +SONS +SOON +SOPHIA +SOPHIE +SOUND +SOUNDS +SOUTH +SPACE +SPACES +SPACING +SPECIAL +SPEED +SPEEDS +SPELL +SPELLED +SPELLING +SPELLS +SPOON +SPOONS +SPORK +SPORT +SPORTING +SPORTS +SQUARE +SQUARES +SQUIRREL +SQUIRRELS +STAND +STANLEY +STAR +STARS +START +STARTS +STATE +STATED +STATES +STATING +STAY +STAYED +STAYING +STAYS +STEAD +STEP +STEPPED +STEPPING +STEPS +STICK +STICKS +STILL +STING +STINGS +STOOD +STOP +STOPPED +STOPPER +STOPPING +STOPS +STORIES +STORY +STREET +STREETS +STRING +STRINGS +STRONG +STRONGER +STRONGEST +STUDIED +STUDIES +STUDY +STUMP +STUMPS +SUCH +SUDDEN +SUDDENLY +SUMMER +SUN +SUNDAY +SURE +SURFACE +SURFACED +SURFACES +SURFACING +SYSTEM +SYSTEMS +TABLE +TABLES +TAIL +TAILS +TAKE +TALE +TALES +TALK +TALKED +TALKER +TALKING +TALKS +TAUGHT +TEA +TEACH +TEACHER +TEACHERS +TEACHES +TEACHING +TEDDY +TELEVISION +TELL +TELLER +TELLING +TELLS +TEN +TENTH +TERRI +TEST +TESTS +THAN +THANK +THANKS +THAT +THE +THEA +THEIR +THEM +THEN +THEO +THERE +THERES +THESE +THEY +THIN +THING +THINGS +THINK +THINKER +THINKING +THIRD +THIRTEEN +THIRTEENTH +THIRTY +THIS +THOMAS +THOSE +THOUGH +THOUGHT +THOUGHTS +THOUSAND +THOUSANDS +THREE +THROUGH +THURSDAY +TIME +TIMED +TIMER +TIMES +TIMING +TIRE +TIRED +TIRES +TIRING +TISSUE +TISSUES +TO +TOBY +TODAY +TOE +TOES +TOGETHER +TOLD +TOMMY +TOMORROW +TOO +TOOK +TOP +TOPS +TOUR +TOURS +TOWARD +TOWEL +TOWELS +TOWN +TOWNS +TOY +TOYS +TRAIN +TRAINS +TRAPEZOID +TRAPEZOIDS +TRAVEL +TRAVELS +TREE +TREES +TRIANGLE +TRIANGLES +TRIED +TRIES +TRIP +TRIPPED +TRIPPING +TRIPS +TRUE +TRUST +TRUSTED +TRUSTING +TRUSTS +TRY +TUESDAY +TURN TV -DORA -POOP \ No newline at end of file +TWELFTH +TWELVE +TWENTIETH +TWENTY +TWIN +TWINKLE +TWINKLES +TWINS +TWO +TYLER +UNDER +UNDERSTAND +UNDERSTANDING +UNDERSTANDS +UNDERSTOOD +UNIT +UNTIL +UP +UPON +US +USE +USED +USER +USERS +USES +USING +USUAL +USUALLY +VERB +VERBS +VERY +VIOLET +VOICE +VOWEL +VOWELS +WAIT +WAITS +WALK +WANT +WAR +WARM +WARMER +WARMERS +WARMEST +WARMS +WARS +WAS +WASH +WASHED +WASHER +WASHES +WATCH +WATCHED +WATCHES +WATCHING +WATER +WATERS +WAVE +WAVED +WAVER +WAVERS +WAVES +WAVING +WAY +WAYS +WE +WEDNESDAY +WEEK +WEEKS +WELL +WELLS +WENT +WERE +WEST +WHAT +WHEEL +WHEELS +WHEN +WHERE +WHICH +WHITE +WHO +WHOLE +WHY +WILL +WILLIAM +WILLOW +WIND +WINDOW +WINDOWS +WINDS +WISH +WISHED +WISHES +WISHING +WITH +WOMAN +WOMEN +WONDER +WONDERFUL +WONDERING +WONDERS +WOOD +WOODS +WORD +WORDS +WORM +WORMS +WORK +WORKED +WORKER +WORKERS +WORKING +WORKS +WORLD +WORLDS +WOULD +WRITE +WRITES +WRITING +WRITINGS +WROTE +YEAR +YEARS +YELLOW +YES +YESTERDAY +YET +YOU +YOUNG +YOUR +ZACHARY +ZARA +ZEBRA +ZEBRAS +ZOE \ No newline at end of file diff --git a/app.config b/app.config index 1cb2e9d..fce508d 100644 --- a/app.config +++ b/app.config @@ -58,5 +58,5 @@ - + diff --git a/packages.config b/packages.config new file mode 100644 index 0000000..ff91865 --- /dev/null +++ b/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/test.txt b/test.txt deleted file mode 100644 index 30d74d2..0000000 --- a/test.txt +++ /dev/null @@ -1 +0,0 @@ -test \ No newline at end of file