From 7a7c3bc7a223499347a9cb4b214aa3649012baed Mon Sep 17 00:00:00 2001 From: Chris Dziemborowicz Date: Mon, 27 Jun 2016 00:10:41 -0700 Subject: [PATCH 1/6] Add dark theme --- Hourglass/CommandLineArguments.cs | 59 ++ Hourglass/Extensions/ColorExtensions.cs | 44 ++ Hourglass/Hourglass.csproj | 6 +- Hourglass/Managers/AppManager.cs | 1 + Hourglass/Managers/ThemeManager.cs | 223 ++++++ Hourglass/Properties/Resources.Designer.cs | 29 +- Hourglass/Properties/Resources.resx | 14 +- Hourglass/Properties/Settings.Designer.cs | 19 +- Hourglass/Properties/Settings.cs | 18 + Hourglass/Properties/Settings.settings | 3 + Hourglass/Resources/Usage.txt | 8 + Hourglass/Serialization/ThemeInfo.cs | 82 +++ Hourglass/Serialization/ThemeInfoList.cs | 44 ++ Hourglass/Serialization/TimerOptionsInfo.cs | 5 + Hourglass/Timing/Color.cs | 26 +- Hourglass/Timing/Theme.cs | 718 ++++++++++++++++++++ Hourglass/Timing/TimerOptions.cs | 63 ++ Hourglass/Windows/ContextMenu.cs | 96 +++ Hourglass/Windows/MultiplierConverter.cs | 69 -- Hourglass/Windows/TimerWindow.xaml | 28 +- Hourglass/Windows/TimerWindow.xaml.cs | 84 ++- Hourglass/Windows/Watermark.cs | 84 ++- Hourglass/Windows/WatermarkAdorner.cs | 14 +- 23 files changed, 1607 insertions(+), 130 deletions(-) create mode 100644 Hourglass/Extensions/ColorExtensions.cs create mode 100644 Hourglass/Managers/ThemeManager.cs create mode 100644 Hourglass/Serialization/ThemeInfo.cs create mode 100644 Hourglass/Serialization/ThemeInfoList.cs create mode 100644 Hourglass/Timing/Theme.cs delete mode 100644 Hourglass/Windows/MultiplierConverter.cs diff --git a/Hourglass/CommandLineArguments.cs b/Hourglass/CommandLineArguments.cs index 76117fd..34e14c9 100644 --- a/Hourglass/CommandLineArguments.cs +++ b/Hourglass/CommandLineArguments.cs @@ -123,6 +123,11 @@ public static string Usage /// public Color Color { get; private set; } + /// + /// Gets the theme of the timer window. + /// + public Theme Theme { get; private set; } + /// /// Gets the sound to play when the timer expires, or null if no sound is to be played. /// @@ -216,6 +221,7 @@ public TimerOptions GetTimerOptions() CloseWhenExpired = this.CloseWhenExpired, ShutDownWhenExpired = this.ShutDownWhenExpired, Color = this.Color, + Theme = this.Theme, Sound = this.Sound, LoopSound = this.LoopSound, WindowSize = this.GetWindowSize() @@ -262,6 +268,7 @@ private static CommandLineArguments GetArgumentsFromMostRecentOptions() CloseWhenExpired = options.CloseWhenExpired, ShutDownWhenExpired = options.ShutDownWhenExpired, Color = options.Color, + Theme = options.Theme, Sound = options.Sound, LoopSound = options.LoopSound, OpenSavedTimers = Settings.Default.OpenSavedTimersOnStartup, @@ -297,6 +304,7 @@ private static CommandLineArguments GetArgumentsFromFactoryDefaults() CloseWhenExpired = defaultOptions.CloseWhenExpired, ShutDownWhenExpired = defaultOptions.ShutDownWhenExpired, Color = defaultOptions.Color, + Theme = defaultOptions.Theme, Sound = defaultOptions.Sound, LoopSound = defaultOptions.LoopSound, OpenSavedTimers = false, @@ -489,6 +497,19 @@ private static CommandLineArguments GetCommandLineArguments(IEnumerable argumentsBasedOnFactoryDefaults.Color = color; break; + case "--theme": + case "-m": + ThrowIfDuplicateSwitch(specifiedSwitches, "--theme"); + + Theme theme = GetThemeValue( + arg, + remainingArgs, + argumentsBasedOnMostRecentOptions.Theme); + + argumentsBasedOnMostRecentOptions.Theme = theme; + argumentsBasedOnFactoryDefaults.Theme = theme; + break; + case "--sound": case "-s": ThrowIfDuplicateSwitch(specifiedSwitches, "--sound"); @@ -752,6 +773,44 @@ private static Color GetColorValue(string arg, Queue remainingArgs, Colo } } + /// + /// Returns the next value in , or throws an exception if + /// is empty or the next argument is not "last" or a valid representation of a + /// . + /// + /// The name of the argument for which the value is to be returned. + /// The unparsed arguments. + /// The value of the argument returned when the user specifies "last". + /// The next value in + /// If is empty or the next argument is not + /// "last" or a valid representation of a . + private static Theme GetThemeValue(string arg, Queue remainingArgs, Theme last) + { + string value = GetRequiredValue(arg, remainingArgs); + + switch (value) + { + case "last": + return last; + + default: + Theme theme = ThemeManager.Instance.GetThemeByName(value, StringComparison.CurrentCultureIgnoreCase); + + if (theme == null) + { + string message = string.Format( + Resources.ResourceManager.GetEffectiveProvider(), + Resources.CommandLineArgumentsParseExceptionInvalidValueForSwitchFormatString, + arg, + value); + + throw new ParseException(message); + } + + return theme; + } + } + /// /// Returns the next value in , or throws an exception if /// is empty or the next argument is not "none", "last", or a valid diff --git a/Hourglass/Extensions/ColorExtensions.cs b/Hourglass/Extensions/ColorExtensions.cs new file mode 100644 index 0000000..e8ad028 --- /dev/null +++ b/Hourglass/Extensions/ColorExtensions.cs @@ -0,0 +1,44 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Chris Dziemborowicz. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace Hourglass.Extensions +{ + using System; + using System.Windows.Media; + + /// + /// Provides utility methods for the struct. + /// + public static class ColorExtensions + { + /// + /// Converts a to an representation. + /// + /// A . + /// An for . + public static int ConverToInt(Color color) + { + return (color.R << 0) | (color.G << 8) | (color.B << 16); + } + + /// + /// Converts a representation of a into a . + /// + /// A representation of a . + /// A . + public static Color ConvertFromString(string colorString) + { + object color = ColorConverter.ConvertFromString(colorString); + + if (color == null) + { + throw new ArgumentException("colorString"); + } + + return (Color)color; + } + } +} diff --git a/Hourglass/Hourglass.csproj b/Hourglass/Hourglass.csproj index f492a23..eb5818e 100644 --- a/Hourglass/Hourglass.csproj +++ b/Hourglass/Hourglass.csproj @@ -87,6 +87,7 @@ + @@ -107,6 +108,7 @@ + @@ -126,6 +128,8 @@ + + @@ -135,6 +139,7 @@ + @@ -144,7 +149,6 @@ ErrorDialog.xaml - diff --git a/Hourglass/Managers/AppManager.cs b/Hourglass/Managers/AppManager.cs index 913bf10..bdc4712 100644 --- a/Hourglass/Managers/AppManager.cs +++ b/Hourglass/Managers/AppManager.cs @@ -27,6 +27,7 @@ public class AppManager : Manager WakeUpManager.Instance, NotificationAreaIconManager.Instance, ColorManager.Instance, + ThemeManager.Instance, SoundManager.Instance, TimerStartManager.Instance, TimerOptionsManager.Instance, diff --git a/Hourglass/Managers/ThemeManager.cs b/Hourglass/Managers/ThemeManager.cs new file mode 100644 index 0000000..57a46c8 --- /dev/null +++ b/Hourglass/Managers/ThemeManager.cs @@ -0,0 +1,223 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Chris Dziemborowicz. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace Hourglass.Managers +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using Hourglass.Properties; + using Hourglass.Timing; + + /// + /// Manages themes. + /// + public class ThemeManager : Manager + { + /// + /// Singleton instance of the class. + /// + public static readonly ThemeManager Instance = new ThemeManager(); + + /// + /// A collection of themes. + /// + private readonly List themes = new List(); + + /// + /// Prevents a default instance of the class from being created. + /// + private ThemeManager() + { + } + + /// + /// Gets the default theme. + /// + public Theme DefaultTheme + { + get { return this.GetThemeByIdentifier("resource:Light theme"); } + } + + /// + /// Gets a collection of all themes. + /// + public IList AllThemes + { + get { return this.themes.ToList(); } + } + + /// + /// Gets a collection of the themes stored in the assembly. + /// + public IList BuiltInThemes + { + get { return this.themes.Where(c => c.IsBuiltIn).ToList(); } + } + + /// + /// Gets a collection of the themes defined by the user. + /// + public IList UserProvidedThemes + { + get { return this.themes.Where(c => !c.IsBuiltIn).ToList(); } + } + + /// + /// Initializes the class. + /// + public override void Initialize() + { + this.themes.Clear(); + this.AddRange(this.GetBuiltInThemes()); + this.AddRange(this.GetUserProvidedThemes()); + } + + /// + /// Persists the state of the class. + /// + public override void Persist() + { + Settings.Default.UserProvidedThemes = this.UserProvidedThemes; + } + + /// + /// Adds a theme. + /// + /// A . + public void Add(Theme theme) + { + if (this.GetThemeByIdentifier(theme.Identifier) == null) + { + this.themes.Add(theme); + } + } + + /// + /// Adds the themes of the specified collection. + /// + /// A collection of s. + public void AddRange(IEnumerable collection) + { + foreach (Theme theme in collection) + { + this.Add(theme); + } + } + + /// + /// Clears all . + /// + public void ClearUserProvidedThemes() + { + this.themes.RemoveAll(c => !c.IsBuiltIn); + } + + /// + /// Returns the theme for the specified identifier, or null if no such theme is loaded. + /// + /// The identifier for the theme. + /// The theme for the specified identifier, or null if no such theme is loaded. + public Theme GetThemeByIdentifier(string identifier) + { + if (string.IsNullOrEmpty(identifier)) + { + return null; + } + + return this.themes.FirstOrDefault(c => c.Identifier == identifier); + } + + /// + /// Returns the theme for the specified identifier, or if no such theme is loaded. + /// + /// The identifier for the theme. + /// The theme for the specified identifier, or if no such theme is loaded. + /// + public Theme GetThemeOrDefaultByIdentifier(string identifier) + { + return this.GetThemeByIdentifier(identifier) ?? this.DefaultTheme; + } + + /// + /// Returns the first theme for the specified name, or null if no such theme is loaded. + /// + /// The name for the theme. + /// One of the enumeration values that specifies how the strings will be + /// compared. + /// The first theme for the specified name, or null if no such theme is loaded. + public Theme GetThemeByName(string name, StringComparison stringComparison = StringComparison.Ordinal) + { + if (string.IsNullOrEmpty(name)) + { + return null; + } + + return this.themes.FirstOrDefault(c => string.Equals(c.Name, name, stringComparison)); + } + + /// + /// Returns the first theme for the specified name, or if no such theme is loaded. + /// + /// The name for the theme. + /// One of the enumeration values that specifies how the strings will be + /// compared. + /// The first theme for the specified name, or if no such theme is loaded. + /// + public Theme GetThemeOrDefaultByName(string name, StringComparison stringComparison = StringComparison.Ordinal) + { + return this.GetThemeByName(name, stringComparison) ?? this.DefaultTheme; + } + + /// + /// Loads the collection of themes defined in the assembly. + /// + /// A collection of themes defined in the assembly. + private IList GetBuiltInThemes() + { + return new List + { + new Theme( + "#FFFFFF" /* backgroundColor */, + "#EEEEEE" /* progressBackgroundColor */, + "#C75050" /* expirationFlashColor */, + "#000000" /* mainTextColor */, + "#808080" /* mainHintColor */, + "#808080" /* secondaryTextColor */, + "#808080" /* secondaryHintColor */, + "#0066CC" /* buttonColor */, + "#FF0000" /* buttonHoverColor */, + Resources.ThemeManagerLightTheme /* name */, + "Light theme" /* invariantName */, + true /* isBuiltIn */), + + new Theme( + "#1E1E1E" /* backgroundColor */, + "#2D2D30" /* progressBackgroundColor */, + "#C75050" /* expirationFlashColor */, + "#808080" /* mainTextColor */, + "#505050" /* mainHintColor */, + "#505050" /* secondaryTextColor */, + "#505050" /* secondaryHintColor */, + "#0066CC" /* buttonColor */, + "#FF0000" /* buttonHoverColor */, + Resources.ThemeManagerDarkTheme /* name */, + "Dark theme" /* invariantName */, + true /* isBuiltIn */) + }; + } + + /// + /// Loads the collection of themes defined by the user. + /// + /// A collection of sounds defined by the user. + private IList GetUserProvidedThemes() + { + return Settings.Default.UserProvidedThemes; + } + } +} diff --git a/Hourglass/Properties/Resources.Designer.cs b/Hourglass/Properties/Resources.Designer.cs index ea0fabd..b039fcc 100644 --- a/Hourglass/Properties/Resources.Designer.cs +++ b/Hourglass/Properties/Resources.Designer.cs @@ -431,7 +431,7 @@ internal static string ContextMenuRecentInputsMenuItem { } /// - /// Looks up a localized string similar to Saved _timers. + /// Looks up a localized string similar to Sa_ved timers. /// internal static string ContextMenuSavedTimersMenuItem { get { @@ -475,6 +475,15 @@ internal static string ContextMenuSoundMenuItem { } } + /// + /// Looks up a localized string similar to _Theme. + /// + internal static string ContextMenuThemeMenuItem { + get { + return ResourceManager.GetString("ContextMenuThemeMenuItem", resourceCulture); + } + } + /// /// Looks up a localized string similar to en-US. /// @@ -1384,6 +1393,24 @@ internal static string SpecialTimeTokenMidnightPattern { } } + /// + /// Looks up a localized string similar to Dark theme. + /// + internal static string ThemeManagerDarkTheme { + get { + return ResourceManager.GetString("ThemeManagerDarkTheme", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Light theme. + /// + internal static string ThemeManagerLightTheme { + get { + return ResourceManager.GetString("ThemeManagerLightTheme", resourceCulture); + } + } + /// /// Looks up a localized string similar to {1} (Expired). /// diff --git a/Hourglass/Properties/Resources.resx b/Hourglass/Properties/Resources.resx index 53a7796..79842c0 100644 --- a/Hourglass/Properties/Resources.resx +++ b/Hourglass/Properties/Resources.resx @@ -885,7 +885,7 @@ $ The text for the recent inputs menu item, where the character following the optional underscore (_) is the access key - Saved _timers + Sa_ved timers The text for the saved timers menu item, where the character following the optional underscore (_) is the access key @@ -1125,4 +1125,16 @@ $ Do not _keep computer awake The text for the do not keep computer awake menu item, where the character following the optional underscore (_) is the access key + + Dark theme + The name of the dark theme + + + Light theme + The name of the light theme + + + _Theme + The text for the theme menu item, where the character following the optional underscore (_) is the access key + \ No newline at end of file diff --git a/Hourglass/Properties/Settings.Designer.cs b/Hourglass/Properties/Settings.Designer.cs index 9564d9a..384b864 100644 --- a/Hourglass/Properties/Settings.Designer.cs +++ b/Hourglass/Properties/Settings.Designer.cs @@ -34,6 +34,18 @@ public static Settings Default { } } + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool OpenSavedTimersOnStartup { + get { + return ((bool)(this["OpenSavedTimersOnStartup"])); + } + set { + this["OpenSavedTimersOnStartup"] = value; + } + } + [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("False")] @@ -104,13 +116,12 @@ public bool ShowInNotificationArea { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("False")] - public bool OpenSavedTimersOnStartup { + public global::Hourglass.Serialization.ThemeInfoList UserProvidedThemeInfos { get { - return ((bool)(this["OpenSavedTimersOnStartup"])); + return ((global::Hourglass.Serialization.ThemeInfoList)(this["UserProvidedThemeInfos"])); } set { - this["OpenSavedTimersOnStartup"] = value; + this["UserProvidedThemeInfos"] = value; } } } diff --git a/Hourglass/Properties/Settings.cs b/Hourglass/Properties/Settings.cs index 859de32..a85a1f6 100644 --- a/Hourglass/Properties/Settings.cs +++ b/Hourglass/Properties/Settings.cs @@ -96,6 +96,24 @@ public IList UserProvidedColors } } + /// + /// Gets or sets the collection of the themes defined by the user. + /// + public IList UserProvidedThemes + { + get + { + IEnumerable userProvidedThemeInfos = this.UserProvidedThemeInfos ?? new ThemeInfoList(); + return userProvidedThemeInfos.Select(Theme.FromThemeInfo).ToList(); + } + + set + { + IEnumerable userProvidedThemeInfos = value.Select(ThemeInfo.FromTheme); + this.UserProvidedThemeInfos = new ThemeInfoList(userProvidedThemeInfos); + } + } + /// /// Gets or sets the . /// diff --git a/Hourglass/Properties/Settings.settings b/Hourglass/Properties/Settings.settings index 93c77f9..816110b 100644 --- a/Hourglass/Properties/Settings.settings +++ b/Hourglass/Properties/Settings.settings @@ -23,6 +23,9 @@ + + + diff --git a/Hourglass/Resources/Usage.txt b/Hourglass/Resources/Usage.txt index 93ac822..cfbdd6f 100644 --- a/Hourglass/Resources/Usage.txt +++ b/Hourglass/Resources/Usage.txt @@ -110,6 +110,13 @@ Options: Default value last Alias -c + --theme last| + Sets the theme of the timer window. + + Required no + Default value last + Alias -m + --sound none|last| Plays a sound when the timer expires. @@ -173,6 +180,7 @@ Options: --close-when-expired off --shut-down-when-expired off --color blue + --theme light theme --sound normal beep --loop-sound off --open-saved-timers off diff --git a/Hourglass/Serialization/ThemeInfo.cs b/Hourglass/Serialization/ThemeInfo.cs new file mode 100644 index 0000000..1343f5b --- /dev/null +++ b/Hourglass/Serialization/ThemeInfo.cs @@ -0,0 +1,82 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Chris Dziemborowicz. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace Hourglass.Serialization +{ + using Hourglass.Timing; + + /// + /// The representation of a used for XML serialization. + /// + public class ThemeInfo + { + /// + /// Gets or sets the friendly name for this theme, or null if no friendly name is specified. + /// + public string Name { get; set; } + + /// + /// Gets or sets the background color of the window. + /// + public System.Windows.Media.Color BackgroundColor { get; set; } + + /// + /// Gets or sets the background color of the progress bar. See for the + /// foreground color of the progress bar. + /// + public System.Windows.Media.Color ProgressBackgroundColor { get; set; } + + /// + /// Gets or sets the color that is flashed on expiration. + /// + public System.Windows.Media.Color ExpirationFlashColor { get; set; } + + /// + /// Gets or sets the color of the primary text. + /// + public System.Windows.Media.Color PrimaryTextColor { get; set; } + + /// + /// Gets or sets the color of the watermark in the primary text box. + /// + public System.Windows.Media.Color PrimaryHintColor { get; set; } + + /// + /// Gets or sets the color of any secondary text. + /// + public System.Windows.Media.Color SecondaryTextColor { get; set; } + + /// + /// Gets or sets the color of the watermark in any secondary text box. + /// + public System.Windows.Media.Color SecondaryHintColor { get; set; } + + /// + /// Gets or sets the color of the button text. + /// + public System.Windows.Media.Color ButtonColor { get; set; } + + /// + /// Gets or sets the color of the button text when the user hovers over the button. + /// + public System.Windows.Media.Color ButtonHoverColor { get; set; } + + /// + /// Returns a for the specified . + /// + /// A . + /// A for the specified . + public static ThemeInfo FromTheme(Theme options) + { + if (options == null) + { + return null; + } + + return options.ToThemeInfo(); + } + } +} diff --git a/Hourglass/Serialization/ThemeInfoList.cs b/Hourglass/Serialization/ThemeInfoList.cs new file mode 100644 index 0000000..98f3471 --- /dev/null +++ b/Hourglass/Serialization/ThemeInfoList.cs @@ -0,0 +1,44 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Chris Dziemborowicz. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace Hourglass.Serialization +{ + using System.Collections.Generic; + + /// + /// A list of objects used for XML serialization. + /// + public class ThemeInfoList : List + { + /// + /// Initializes a new instance of the class that is empty and has the default + /// initial capacity. + /// + public ThemeInfoList() + { + } + + /// + /// Initializes a new instance of the class that contains elements copied from the + /// specified collection and has sufficient capacity to accommodate the number of elements copied. + /// + /// The collection whose elements are copied to the new list. + public ThemeInfoList(IEnumerable collection) + : base(collection) + { + } + + /// + /// Initializes a new instance of the class that is empty and has the specified + /// initial capacity. + /// + /// The number of elements that the new list can initially store. + public ThemeInfoList(int capacity) + : base(capacity) + { + } + } +} diff --git a/Hourglass/Serialization/TimerOptionsInfo.cs b/Hourglass/Serialization/TimerOptionsInfo.cs index 48c3b1b..b2684f9 100644 --- a/Hourglass/Serialization/TimerOptionsInfo.cs +++ b/Hourglass/Serialization/TimerOptionsInfo.cs @@ -65,6 +65,11 @@ public class TimerOptionsInfo /// public string ColorIdentifier { get; set; } + /// + /// Gets or sets the identifier of the theme of the timer window. + /// + public string ThemeIdentifier { get; set; } + /// /// Gets or sets the identifier of the sound to play when the timer expires, or null if no sound is to /// be played. diff --git a/Hourglass/Timing/Color.cs b/Hourglass/Timing/Color.cs index a97c1b6..db08c02 100644 --- a/Hourglass/Timing/Color.cs +++ b/Hourglass/Timing/Color.cs @@ -9,6 +9,7 @@ namespace Hourglass.Timing using System; using System.Windows.Media; + using Hourglass.Extensions; using Hourglass.Managers; /// @@ -30,7 +31,7 @@ public class Color /// A value indicating whether this color is defined in the assembly. /// private readonly bool isBuiltIn; - + /// /// The representation of this color. /// @@ -78,7 +79,7 @@ public Color(byte r, byte g, byte b, string invariantName = null, string name = /// The localized friendly name of the color. (Optional.) /// A value indicating whether this color is defined in the assembly. (Optional.) public Color(string colorString, string invariantName = null, string name = null, bool isBuiltIn = false) - : this(GetMediaColorFromString(colorString), invariantName, name, isBuiltIn) + : this(ColorExtensions.ConvertFromString(colorString), invariantName, name, isBuiltIn) { } @@ -142,7 +143,7 @@ public Brush Brush /// Returns a for the specified identifier, or null if the identifier is null /// or empty. /// - /// The identifier for the sound. + /// The identifier for the color. /// A for the specified identifier, or null if the identifier is /// null or empty. public static Color FromIdentifier(string identifier) @@ -173,24 +174,7 @@ public static Color FromIdentifier(string identifier) /// An for this color. public int ToInt() { - return (this.mediaColor.R << 0) | (this.mediaColor.G << 8) | (this.mediaColor.B << 16); - } - - /// - /// Converts a representation of a into a . - /// - /// A representation of a . - /// A . - private static System.Windows.Media.Color GetMediaColorFromString(string colorString) - { - object color = ColorConverter.ConvertFromString(colorString); - - if (color == null) - { - throw new ArgumentException("colorString"); - } - - return (System.Windows.Media.Color)color; + return ColorExtensions.ConverToInt(this.mediaColor); } } } diff --git a/Hourglass/Timing/Theme.cs b/Hourglass/Timing/Theme.cs new file mode 100644 index 0000000..12d8f6a --- /dev/null +++ b/Hourglass/Timing/Theme.cs @@ -0,0 +1,718 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Chris Dziemborowicz. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace Hourglass.Timing +{ + using System; + using System.ComponentModel; + using System.Windows.Media; + + using Hourglass.Extensions; + using Hourglass.Managers; + using Hourglass.Serialization; + + /// + /// A theme for the timer window. + /// + public class Theme : INotifyPropertyChanged + { + #region Private Members + + /// + /// The friendly name for this theme, or null if no friendly name is specified. + /// + private readonly string name; + + /// + /// A unique identifier for this theme. + /// + private readonly string identifier; + + /// + /// A value indicating whether this theme is defined in the assembly. + /// + private readonly bool isBuiltIn; + + /// + /// The background color of the window. + /// + private System.Windows.Media.Color backgroundColor; + + /// + /// The brush used to paint the background color of the window. + /// + private Brush backgroundBrush; + + /// + /// The background color of the progress bar. See for the foreground color of + /// the progress bar. + /// + private System.Windows.Media.Color progressBackgroundColor; + + /// + /// The brush used to paint the background color of the progress bar. See for + /// the foreground color of the progress bar. + /// + private Brush progressBackgroundBrush; + + /// + /// The color that is flashed on expiration. + /// + private System.Windows.Media.Color expirationFlashColor; + + /// + /// The brush used to paint the color that is flashed on expiration. + /// + private Brush expirationFlashBrush; + + /// + /// The color of the primary text. + /// + private System.Windows.Media.Color primaryTextColor; + + /// + /// The brush used to paint the color of the primary text. + /// + private Brush primaryTextBrush; + + /// + /// The color of the watermark in the primary text box. + /// + private System.Windows.Media.Color primaryHintColor; + + /// + /// The brush used to paint the color of the watermark in the primary text box. + /// + private Brush primaryHintBrush; + + /// + /// The color of any secondary text. + /// + private System.Windows.Media.Color secondaryTextColor; + + /// + /// The brush used to paint the color of any secondary text. + /// + private Brush secondaryTextBrush; + + /// + /// The color of the watermark in any secondary text box. + /// + private System.Windows.Media.Color secondaryHintColor; + + /// + /// The brush used to paint the color of the watermark in any secondary text box. + /// + private Brush secondaryHintBrush; + + /// + /// The color of the button text. + /// + private System.Windows.Media.Color buttonColor; + + /// + /// The brush used to paint the color of the button text. + /// + private Brush buttonBrush; + + /// + /// The color of the button text when the user hovers over the button. + /// + private System.Windows.Media.Color buttonHoverColor; + + /// + /// The brush used to paint the color of the button text when the user hovers over the button. + /// + private Brush buttonHoverBrush; + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The background color of the window. + /// The background color of the progress bar. See for the foreground color of + /// The color that is flashed on expiration. + /// The color of the primary text. + /// The color of the watermark in the primary text box. + /// The color of any secondary text. + /// The color of the watermark in any secondary text box. + /// The color of the button text. + /// The color of the button text when the user hovers over the button. + /// The friendly name for this theme, or null if no friendly name is specified. + /// A unique identifier for this theme. + /// A value indicating whether this theme is defined in the assembly. + public Theme( + System.Windows.Media.Color backgroundColor, + System.Windows.Media.Color progressBackgroundColor, + System.Windows.Media.Color expirationFlashColor, + System.Windows.Media.Color primaryTextColor, + System.Windows.Media.Color primaryHintColor, + System.Windows.Media.Color secondaryTextColor, + System.Windows.Media.Color secondaryHintColor, + System.Windows.Media.Color buttonColor, + System.Windows.Media.Color buttonHoverColor, + string name, + string invariantName = null, + bool isBuiltIn = false) + { + this.name = name; + this.identifier = isBuiltIn ? ("resource:" + invariantName) : ("theme:" + name); + this.isBuiltIn = isBuiltIn; + + this.backgroundColor = backgroundColor; + this.progressBackgroundColor = progressBackgroundColor; + this.expirationFlashColor = expirationFlashColor; + this.primaryTextColor = primaryTextColor; + this.primaryHintColor = primaryHintColor; + this.secondaryTextColor = secondaryTextColor; + this.secondaryHintColor = secondaryHintColor; + this.buttonColor = buttonColor; + this.buttonHoverColor = buttonHoverColor; + } + + /// + /// Initializes a new instance of the class. + /// + /// The background color of the window. + /// The background color of the progress bar. See for the foreground color of + /// The color that is flashed on expiration. + /// The color of the primary text. + /// The color of the watermark in the primary text box. + /// The color of any secondary text. + /// The color of the watermark in any secondary text box. + /// The color of the button text. + /// The color of the button text when the user hovers over the button. + /// The friendly name for this theme, or null if no friendly name is specified. + /// A unique identifier for this theme. + /// A value indicating whether this theme is defined in the assembly. + public Theme( + string backgroundColor, + string progressBackgroundColor, + string expirationFlashColor, + string primaryTextColor, + string primaryHintColor, + string secondaryTextColor, + string secondaryHintColor, + string buttonColor, + string buttonHoverColor, + string name, + string invariantName = null, + bool isBuiltIn = false) + : this( + ColorExtensions.ConvertFromString(backgroundColor), + ColorExtensions.ConvertFromString(progressBackgroundColor), + ColorExtensions.ConvertFromString(expirationFlashColor), + ColorExtensions.ConvertFromString(primaryTextColor), + ColorExtensions.ConvertFromString(primaryHintColor), + ColorExtensions.ConvertFromString(secondaryTextColor), + ColorExtensions.ConvertFromString(secondaryHintColor), + ColorExtensions.ConvertFromString(buttonColor), + ColorExtensions.ConvertFromString(buttonHoverColor), + name, + invariantName, + isBuiltIn) + { + } + + /// + /// Initializes a new instance of the class from a . + /// + /// A . + public Theme(ThemeInfo info) + { + this.name = info.Name; + this.identifier = "theme:" + info.Name; + this.isBuiltIn = false; + + this.backgroundColor = info.BackgroundColor; + this.progressBackgroundColor = info.ProgressBackgroundColor; + this.expirationFlashColor = info.ExpirationFlashColor; + this.primaryTextColor = info.PrimaryTextColor; + this.primaryHintColor = info.PrimaryHintColor; + this.secondaryTextColor = info.SecondaryTextColor; + this.secondaryHintColor = info.SecondaryHintColor; + this.buttonColor = info.ButtonColor; + this.buttonHoverColor = info.ButtonHoverColor; + } + + #endregion + + #region Events + + /// + /// Raised when a property value changes. + /// + public event PropertyChangedEventHandler PropertyChanged; + + #endregion + + #region Properties + + /// + /// Gets the default theme. + /// + public static Theme DefaultTheme + { + get { return ThemeManager.Instance.DefaultTheme; } + } + + /// + /// Gets the friendly name of this theme, or null if no friendly name is specified. + /// + public string Name + { + get { return this.name; } + } + + /// + /// Gets the unique identifier for this theme. + /// + public string Identifier + { + get { return this.identifier; } + } + + /// + /// Gets a value indicating whether this theme is defined in the assembly. + /// + public bool IsBuiltIn + { + get { return this.isBuiltIn; } + } + + /// + /// Gets or sets the background color of the window. + /// + public System.Windows.Media.Color BackgroundColor + { + get + { + return this.backgroundColor; + } + + set + { + if (this.backgroundColor == value) + { + return; + } + + this.backgroundColor = value; + this.backgroundBrush = null; + this.OnPropertyChanged(nameof(this.BackgroundColor)); + } + } + + /// + /// Gets the brush used to paint the background color of the window. + /// + public Brush BackgroundBrush + { + get + { + if (this.backgroundBrush == null) + { + this.backgroundBrush = new SolidColorBrush(this.backgroundColor); + } + + return this.backgroundBrush; + } + } + + /// + /// Gets or sets the background color of the progress bar. See for the + /// foreground color of the progress bar. + /// + public System.Windows.Media.Color ProgressBackgroundColor + { + get + { + return this.progressBackgroundColor; + } + + set + { + if (this.progressBackgroundColor == value) + { + return; + } + + this.progressBackgroundColor = value; + this.progressBackgroundBrush = null; + this.OnPropertyChanged(nameof(this.ProgressBackgroundColor)); + } + } + + /// + /// Gets the brush used to paint the background color of the progress bar. See + /// for the foreground color of the progress bar. + /// + public Brush ProgressBackgroundBrush + { + get + { + if (this.progressBackgroundBrush == null) + { + this.progressBackgroundBrush = new SolidColorBrush(this.progressBackgroundColor); + } + + return this.progressBackgroundBrush; + } + } + + /// + /// Gets or sets the color that is flashed on expiration. + /// + public System.Windows.Media.Color ExpirationFlashColor + { + get + { + return this.expirationFlashColor; + } + + set + { + if (this.expirationFlashColor == value) + { + return; + } + + this.expirationFlashColor = value; + this.expirationFlashBrush = null; + this.OnPropertyChanged(nameof(this.ExpirationFlashColor)); + } + } + + /// + /// Gets the brush used to paint the color that is flashed on expiration. + /// + public Brush ExpirationFlashBrush + { + get + { + if (this.expirationFlashBrush == null) + { + this.expirationFlashBrush = new SolidColorBrush(this.expirationFlashColor); + } + + return this.expirationFlashBrush; + } + } + + /// + /// Gets or sets the color of the primary text. + /// + public System.Windows.Media.Color PrimaryTextColor + { + get + { + return this.primaryTextColor; + } + + set + { + if (this.primaryTextColor == value) + { + return; + } + + this.primaryTextColor = value; + this.primaryTextBrush = null; + this.OnPropertyChanged(nameof(this.PrimaryTextColor)); + } + } + + /// + /// Gets the brush used to paint the color of the primary text. + /// + public Brush PrimaryTextBrush + { + get + { + if (this.primaryTextBrush == null) + { + this.primaryTextBrush = new SolidColorBrush(this.primaryTextColor); + } + + return this.primaryTextBrush; + } + } + + /// + /// Gets or sets the color of the watermark in the primary text box. + /// + public System.Windows.Media.Color PrimaryHintColor + { + get + { + return this.primaryHintColor; + } + + set + { + if (this.primaryHintColor == value) + { + return; + } + + this.primaryHintColor = value; + this.primaryHintBrush = null; + this.OnPropertyChanged(nameof(this.PrimaryHintColor)); + } + } + + /// + /// Gets the brush used to paint the color of the watermark in the primary text box. + /// + public Brush PrimaryHintBrush + { + get + { + if (this.primaryHintBrush == null) + { + this.primaryHintBrush = new SolidColorBrush(this.primaryHintColor); + } + + return this.primaryHintBrush; + } + } + + /// + /// Gets or sets the color of any secondary text. + /// + public System.Windows.Media.Color SecondaryTextColor + { + get + { + return this.secondaryTextColor; + } + + set + { + if (this.secondaryTextColor == value) + { + return; + } + + this.secondaryTextColor = value; + this.secondaryTextBrush = null; + this.OnPropertyChanged(nameof(this.SecondaryTextColor)); + } + } + + /// + /// Gets the brush used to paint the color of any secondary text. + /// + public Brush SecondaryTextBrush + { + get + { + if (this.secondaryTextBrush == null) + { + this.secondaryTextBrush = new SolidColorBrush(this.secondaryTextColor); + } + + return this.secondaryTextBrush; + } + } + + /// + /// Gets or sets the color of the watermark in any secondary text box. + /// + public System.Windows.Media.Color SecondaryHintColor + { + get + { + return this.secondaryHintColor; + } + + set + { + if (this.secondaryHintColor == value) + { + return; + } + + this.secondaryHintColor = value; + this.secondaryHintBrush = null; + this.OnPropertyChanged(nameof(this.SecondaryHintColor)); + } + } + + /// + /// Gets the brush used to paint the color of the watermark in any secondary text box. + /// + public Brush SecondaryHintBrush + { + get + { + if (this.secondaryHintBrush == null) + { + this.secondaryHintBrush = new SolidColorBrush(this.secondaryHintColor); + } + + return this.secondaryHintBrush; + } + } + + /// + /// Gets or sets the color of the button text. + /// + public System.Windows.Media.Color ButtonColor + { + get + { + return this.buttonColor; + } + + set + { + if (this.buttonColor == value) + { + return; + } + + this.buttonColor = value; + this.buttonBrush = null; + this.OnPropertyChanged(nameof(this.ButtonColor)); + } + } + + /// + /// Gets the brush used to paint the color of the button text. + /// + public Brush ButtonBrush + { + get + { + if (this.buttonBrush == null) + { + this.buttonBrush = new SolidColorBrush(this.buttonColor); + } + + return this.buttonBrush; + } + } + + /// + /// Gets or sets the color of the button text when the user hovers over the button. + /// + public System.Windows.Media.Color ButtonHoverColor + { + get + { + return this.buttonHoverColor; + } + + set + { + if (this.buttonHoverColor == value) + { + return; + } + + this.buttonHoverColor = value; + this.buttonHoverBrush = null; + this.OnPropertyChanged(nameof(this.ButtonHoverColor)); + } + } + + /// + /// Gets the brush used to paint the color of the button text when the user hovers over the button. + /// + public Brush ButtonHoverBrush + { + get + { + if (this.buttonHoverBrush == null) + { + this.buttonHoverBrush = new SolidColorBrush(this.buttonHoverColor); + } + + return this.buttonHoverBrush; + } + } + + #endregion + + #region Public Static Methods + + /// + /// Returns the theme for the specified identifier, or null if no such theme is loaded. + /// + /// The identifier for the theme. + /// The theme for the specified identifier, or null if no such theme is loaded. + public static Theme FromIdentifier(string identifier) + { + return ThemeManager.Instance.GetThemeOrDefaultByIdentifier(identifier); + } + + /// + /// Returns a for the specified , or null if the specified + /// is null. + /// + /// A . + /// A for the specified , or null if the specified + /// is null. + public static Theme FromThemeInfo(ThemeInfo info) + { + return info != null ? new Theme(info) : null; + } + + #endregion + + #region Public Methods + + /// + /// Returns the representation of the used for XML serialization. + /// + /// The representation of the used for XML serialization. + public ThemeInfo ToThemeInfo() + { + return new ThemeInfo + { + Name = this.name, + BackgroundColor = this.backgroundColor, + ProgressBackgroundColor = this.progressBackgroundColor, + ExpirationFlashColor = this.expirationFlashColor, + PrimaryTextColor = this.primaryTextColor, + PrimaryHintColor = this.primaryHintColor, + SecondaryTextColor = this.secondaryTextColor, + SecondaryHintColor = this.secondaryHintColor, + ButtonColor = this.buttonColor, + ButtonHoverColor = this.buttonHoverColor + }; + } + + #endregion + + #region Protected Methods + + /// + /// Raises the event. + /// + /// One or more property names. + protected void OnPropertyChanged(params string[] propertyNames) + { + PropertyChangedEventHandler eventHandler = this.PropertyChanged; + + if (eventHandler != null) + { + foreach (string propertyName in propertyNames) + { + eventHandler(this, new PropertyChangedEventArgs(propertyName)); + } + } + } + + #endregion + } +} diff --git a/Hourglass/Timing/TimerOptions.cs b/Hourglass/Timing/TimerOptions.cs index 7ba8330..6d85c84 100644 --- a/Hourglass/Timing/TimerOptions.cs +++ b/Hourglass/Timing/TimerOptions.cs @@ -82,6 +82,11 @@ public class TimerOptions : INotifyPropertyChanged /// private Color color; + /// + /// The theme of the timer window. + /// + private Theme theme; + /// /// The size, position, and state of the timer window. /// @@ -106,6 +111,7 @@ public TimerOptions() this.closeWhenExpired = false; this.shutDownWhenExpired = false; this.color = Color.DefaultColor; + this.theme = Theme.DefaultTheme; this.sound = Sound.DefaultSound; this.loopSound = false; this.windowSize = new WindowSize( @@ -369,6 +375,28 @@ public Color Color } } + /// + /// Gets or sets the theme of the timer window. + /// + public Theme Theme + { + get + { + return this.theme; + } + + set + { + if (object.ReferenceEquals(this.theme, value)) + { + return; + } + + this.theme = value; + this.OnPropertyChanged("Theme"); + } + } + /// /// Gets or sets the sound to play when the timer expires, or null if no sound is to be played. /// @@ -485,9 +513,26 @@ public void Set(TimerOptions options) this.closeWhenExpired = options.closeWhenExpired; this.shutDownWhenExpired = options.shutDownWhenExpired; this.color = options.color; + this.theme = options.theme; this.sound = options.sound; this.loopSound = options.loopSound; this.windowSize = WindowSize.FromWindowSize(options.WindowSize); + + this.OnPropertyChanged( + "Title", + "AlwaysOnTop", + "PromptOnExit", + "DoNotKeepComputerAwake", + "ShowTimeElapsed", + "LoopTimer", + "PopUpWhenExpired", + "CloseWhenExpired", + "ShutDownWhenExpired", + "Color", + "Theme", + "Sound", + "LoopSound", + "WindowSize"); } /// @@ -511,9 +556,26 @@ public void Set(TimerOptionsInfo info) this.closeWhenExpired = info.CloseWhenExpired; this.shutDownWhenExpired = info.ShutDownWhenExpired; this.color = Color.FromIdentifier(info.ColorIdentifier); + this.theme = Theme.FromIdentifier(info.ThemeIdentifier); this.sound = Sound.FromIdentifier(info.SoundIdentifier); this.loopSound = info.LoopSound; this.windowSize = WindowSize.FromWindowSizeInfo(info.WindowSize); + + this.OnPropertyChanged( + "Title", + "AlwaysOnTop", + "PromptOnExit", + "DoNotKeepComputerAwake", + "ShowTimeElapsed", + "LoopTimer", + "PopUpWhenExpired", + "CloseWhenExpired", + "ShutDownWhenExpired", + "Color", + "Theme", + "Sound", + "LoopSound", + "WindowSize"); } /// @@ -534,6 +596,7 @@ public TimerOptionsInfo ToTimerOptionsInfo() CloseWhenExpired = this.closeWhenExpired, ShutDownWhenExpired = this.shutDownWhenExpired, ColorIdentifier = this.color?.Identifier, + ThemeIdentifier = this.theme?.Identifier, SoundIdentifier = this.sound?.Identifier, LoopSound = this.loopSound, WindowSize = WindowSizeInfo.FromWindowSize(this.windowSize) diff --git a/Hourglass/Windows/ContextMenu.cs b/Hourglass/Windows/ContextMenu.cs index 9c7265a..50f2e7c 100644 --- a/Hourglass/Windows/ContextMenu.cs +++ b/Hourglass/Windows/ContextMenu.cs @@ -116,6 +116,16 @@ public class ContextMenu : System.Windows.Controls.ContextMenu /// private IList selectableColorMenuItems; + /// + /// The "Theme" . + /// + private MenuItem themeMenuItem; + + /// + /// The "Theme" s associated with s. + /// + private IList selectableThemeMenuItems; + /// /// The "Add custom color..." . /// @@ -222,6 +232,7 @@ public void Bind(TimerWindow window) this.dispatcherTimer.Tick += this.DispatcherTimerTick; this.selectableColorMenuItems = new List(); + this.selectableThemeMenuItems = new List(); this.selectableSoundMenuItems = new List(); // Build the menu @@ -243,6 +254,7 @@ private void WindowContextMenuOpening(object sender, ContextMenuEventArgs e) this.UpdateRecentInputsMenuItem(); this.UpdateSavedTimersMenuItem(); this.UpdateColorMenuItem(); + this.UpdateThemeMenuItem(); this.UpdateSoundMenuItem(); // Update binding @@ -332,6 +344,12 @@ private void UpdateMenuFromOptions() menuItem.IsChecked = object.Equals(menuItem.Tag, this.timerWindow.Options.Color); } + // Theme + foreach (MenuItem menuItem in this.selectableThemeMenuItems) + { + menuItem.IsChecked = object.Equals(menuItem.Tag, this.timerWindow.Options.Theme); + } + // Sound foreach (MenuItem menuItem in this.selectableSoundMenuItems) { @@ -399,6 +417,10 @@ private void UpdateOptionsFromMenu() MenuItem selectedColorMenuItem = this.selectableColorMenuItems.FirstOrDefault(mi => mi.IsChecked); this.timerWindow.Options.Color = selectedColorMenuItem != null ? selectedColorMenuItem.Tag as Color : Color.DefaultColor; + // Theme + MenuItem selectedThemeMenuItem = this.selectableThemeMenuItems.FirstOrDefault(mi => mi.IsChecked); + this.timerWindow.Options.Theme = selectedThemeMenuItem != null ? selectedThemeMenuItem.Tag as Theme : Theme.DefaultTheme; + // Sound MenuItem selectedSoundMenuItem = this.selectableSoundMenuItems.FirstOrDefault(mi => mi.IsChecked); this.timerWindow.Options.Sound = selectedSoundMenuItem != null ? selectedSoundMenuItem.Tag as Sound : null; @@ -511,6 +533,10 @@ private void BuildMenu() this.colorMenuItem.Header = Properties.Resources.ContextMenuColorMenuItem; this.Items.Add(this.colorMenuItem); + this.themeMenuItem = new MenuItem(); + this.themeMenuItem.Header = Properties.Resources.ContextMenuThemeMenuItem; + this.Items.Add(this.themeMenuItem); + this.soundMenuItem = new MenuItem(); this.soundMenuItem.Header = Properties.Resources.ContextMenuSoundMenuItem; this.Items.Add(this.soundMenuItem); @@ -1010,6 +1036,76 @@ private void ClearCustomColorsMenuItemClick(object sender, RoutedEventArgs e) #endregion + #region Private Methods (Theme) + + /// + /// Updates the . + /// + private void UpdateThemeMenuItem() + { + this.themeMenuItem.Items.Clear(); + this.selectableThemeMenuItems.Clear(); + + // Ensure the current theme is registered + if (!this.timerWindow.Options.Theme.IsBuiltIn) + { + ThemeManager.Instance.Add(this.timerWindow.Options.Theme); + } + + // Themes + this.CreateThemeMenuItemsFromList(ThemeManager.Instance.BuiltInThemes); + + if (ThemeManager.Instance.UserProvidedThemes.Count > 0) + { + this.themeMenuItem.Items.Add(new Separator()); + this.CreateThemeMenuItemsFromList(ThemeManager.Instance.UserProvidedThemes); + } + } + + /// + /// Creates a for a . + /// + /// A . + private void CreateThemeMenuItem(Theme theme) + { + MenuItem menuItem = new MenuItem(); + menuItem.Header = theme.Name; + menuItem.Tag = theme; + menuItem.IsCheckable = true; + menuItem.Click += this.ThemeMenuItemClick; + menuItem.Click += this.CheckableMenuItemClick; + + this.themeMenuItem.Items.Add(menuItem); + this.selectableThemeMenuItems.Add(menuItem); + } + + /// + /// Creates a for each in the collection. + /// + /// A collection of s. + private void CreateThemeMenuItemsFromList(IList themes) + { + foreach (Theme theme in themes) + { + this.CreateThemeMenuItem(theme); + } + } + + /// + /// Invoked when a theme is clicked. + /// + /// The where the event handler is attached. + /// The event data. + private void ThemeMenuItemClick(object sender, RoutedEventArgs e) + { + foreach (MenuItem menuItem in this.selectableThemeMenuItems) + { + menuItem.IsChecked = object.ReferenceEquals(menuItem, sender); + } + } + + #endregion + #region Private Methods (Sound) /// diff --git a/Hourglass/Windows/MultiplierConverter.cs b/Hourglass/Windows/MultiplierConverter.cs deleted file mode 100644 index af21734..0000000 --- a/Hourglass/Windows/MultiplierConverter.cs +++ /dev/null @@ -1,69 +0,0 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) Chris Dziemborowicz. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Hourglass.Windows -{ - using System; - using System.Globalization; - using System.Windows.Data; - - /// - /// Multiplies values by a constant value. - /// - [ValueConversion(typeof(double), typeof(double))] - public class MultiplierConverter : IValueConverter - { - /// - /// The constant value to multiply by when converting. - /// - private readonly double multiplier; - - /// - /// Initializes a new instance of the class with the specified multiplier. - /// - /// The constant value to multiply by when converting. - public MultiplierConverter(double multiplier) - { - this.multiplier = multiplier; - } - - /// - /// Converts a value. - /// - /// The value produced by the binding source. - /// The type of the binding target property. - /// The converter parameter to use. - /// The culture to use in the converter. - /// The value multiplied by the multiplier, or null if the value was null. - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value == null) - { - return null; - } - - return (double)value * this.multiplier; - } - - /// - /// Converts a value back. - /// - /// The value that is produced by the binding target. - /// The type to convert to. - /// The converter parameter to use. - /// The culture to use in the converter. - /// The value divided by the multiplier, or null if the value was null. - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value == null) - { - return null; - } - - return (double)value / this.multiplier; - } - } -} diff --git a/Hourglass/Windows/TimerWindow.xaml b/Hourglass/Windows/TimerWindow.xaml index 960532a..172f110 100644 --- a/Hourglass/Windows/TimerWindow.xaml +++ b/Hourglass/Windows/TimerWindow.xaml @@ -32,7 +32,7 @@ - + @@ -127,7 +127,6 @@