diff options
Diffstat (limited to 'win/CS/HandBrakeWPF/Controls')
-rw-r--r-- | win/CS/HandBrakeWPF/Controls/NumberBox.xaml | 175 | ||||
-rw-r--r-- | win/CS/HandBrakeWPF/Controls/NumberBox.xaml.cs | 655 | ||||
-rw-r--r-- | win/CS/HandBrakeWPF/Controls/RefireControl.cs | 134 |
3 files changed, 964 insertions, 0 deletions
diff --git a/win/CS/HandBrakeWPF/Controls/NumberBox.xaml b/win/CS/HandBrakeWPF/Controls/NumberBox.xaml new file mode 100644 index 000000000..d8248d4e1 --- /dev/null +++ b/win/CS/HandBrakeWPF/Controls/NumberBox.xaml @@ -0,0 +1,175 @@ +<UserControl x:Class="HandBrakeWPF.Controls.NumberBox"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ Loaded="UserControl_Loaded">
+ <UserControl.Resources>
+ <Style x:Key="Arrow" TargetType="Polygon">
+ <Setter Property="Fill" Value="#333" />
+ </Style>
+ <!-- UpButton and DownButton are identical except for the border radius in the control template.
+ We can't pass that through so we need to duplicate the template. After a change is made from one button
+ template it should be copied to the other. -->
+ <Style x:Key="UpButton" TargetType="Button">
+ <Setter Property="Margin" Value="0"/>
+ <Setter Property="Background" >
+ <Setter.Value>
+ <LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
+ <GradientStop Color="#EEE" Offset="0.4"/>
+ <GradientStop Color="#BBB" Offset="1"/>
+ </LinearGradientBrush>
+ </Setter.Value>
+ </Setter>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="Button">
+ <Border
+ Name="border"
+ BorderThickness="1"
+ BorderBrush="#888"
+ CornerRadius="0,2,0,0"
+ Background="{TemplateBinding Background}">
+ <ContentPresenter
+ Name="content"
+ HorizontalAlignment="Center" VerticalAlignment="Center" />
+ </Border>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsMouseOver" Value="True">
+ <Setter TargetName="border" Property="BorderBrush" Value="#FF4788c8" />
+ <Setter Property="Foreground" Value="#FF4788c8" />
+ </Trigger>
+ <Trigger Property="IsPressed" Value="True">
+ <Setter Property="Background" >
+ <Setter.Value>
+ <LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
+ <GradientStop Color="#CCC" Offset="0.4"/>
+ <GradientStop Color="#999" Offset="1"/>
+ </LinearGradientBrush>
+ </Setter.Value>
+ </Setter>
+ <Setter TargetName="content" Property="RenderTransform" >
+ <Setter.Value>
+ <TranslateTransform Y="1.0" />
+ </Setter.Value>
+ </Setter>
+ </Trigger>
+ <Trigger Property="IsDefaulted" Value="True">
+ <Setter TargetName="border" Property="BorderBrush" Value="#FF282828" />
+ </Trigger>
+ <Trigger Property="IsFocused" Value="True">
+ <Setter TargetName="border" Property="BorderBrush" Value="#FF282828" />
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="False">
+ <Setter TargetName="border" Property="Opacity" Value="0.7" />
+ <Setter Property="Foreground" Value="Gray" />
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+ <Style x:Key="DownButton" TargetType="Button">
+ <Setter Property="Margin" Value="0"/>
+ <Setter Property="Background" >
+ <Setter.Value>
+ <LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
+ <GradientStop Color="#EEE" Offset="0.4"/>
+ <GradientStop Color="#BBB" Offset="1"/>
+ </LinearGradientBrush>
+ </Setter.Value>
+ </Setter>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="Button">
+ <Border
+ Name="border"
+ BorderThickness="1"
+ BorderBrush="#888"
+ CornerRadius="0,0,2,0"
+ Background="{TemplateBinding Background}">
+ <ContentPresenter
+ Name="content"
+ HorizontalAlignment="Center" VerticalAlignment="Center" />
+ </Border>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsMouseOver" Value="True">
+ <Setter TargetName="border" Property="BorderBrush" Value="#FF4788c8" />
+ <Setter Property="Foreground" Value="#FF4788c8" />
+ </Trigger>
+ <Trigger Property="IsPressed" Value="True">
+ <Setter Property="Background" >
+ <Setter.Value>
+ <LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
+ <GradientStop Color="#CCC" Offset="0.4"/>
+ <GradientStop Color="#999" Offset="1"/>
+ </LinearGradientBrush>
+ </Setter.Value>
+ </Setter>
+ <Setter TargetName="content" Property="RenderTransform" >
+ <Setter.Value>
+ <TranslateTransform Y="1.0" />
+ </Setter.Value>
+ </Setter>
+ </Trigger>
+ <Trigger Property="IsDefaulted" Value="True">
+ <Setter TargetName="border" Property="BorderBrush" Value="#FF282828" />
+ </Trigger>
+ <Trigger Property="IsFocused" Value="True">
+ <Setter TargetName="border" Property="BorderBrush" Value="#FF282828" />
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="False">
+ <Setter TargetName="border" Property="Opacity" Value="0.7" />
+ <Setter Property="Foreground" Value="Gray" />
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+ </UserControl.Resources>
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="*" />
+ <ColumnDefinition Width="Auto" />
+ </Grid.ColumnDefinitions>
+ <TextBox
+ Name="numberBox"
+ Grid.Column="0"
+ GotFocus="NumberBoxGotFocus"
+ LostFocus="NumberBoxLostFocus"
+ PreviewTextInput="NumberBoxPreviewTextInput"
+ PreviewKeyDown="NumberBoxPreviewKeyDown"
+ PreviewMouseDown="NumberBoxPreviewMouseDown"
+ PreviewMouseUp="NumberBoxPreviewMouseUp"
+ TextChanged="NumberBoxTextChanged"
+ VerticalContentAlignment="Center"/>
+ <Grid
+ Name="incrementButtonsGrid"
+ Grid.Column="1"
+ Width="16">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="*" />
+ <RowDefinition Height="*" />
+ </Grid.RowDefinitions>
+ <Button
+ Style="{StaticResource UpButton}"
+ Grid.Row="0"
+ FontSize="4"
+ PreviewMouseLeftButtonDown="UpButtonMouseLeftButtonDown"
+ PreviewMouseLeftButtonUp="UpButtonMouseLeftButtonUp">
+ <Polygon
+ Style="{StaticResource Arrow}"
+ Points="4,0 0,4 8,4" />
+ </Button>
+ <Button
+ Style="{StaticResource DownButton}"
+ Grid.Row="1"
+ FontSize="4"
+ PreviewMouseLeftButtonDown="DownButtonMouseLeftButtonDown"
+ PreviewMouseLeftButtonUp="DownButtonMouseLeftButtonUp">
+ <Polygon
+ Style="{StaticResource Arrow}"
+ Points="0,0 8,0 4,4" />
+ </Button>
+ </Grid>
+ </Grid>
+</UserControl>
diff --git a/win/CS/HandBrakeWPF/Controls/NumberBox.xaml.cs b/win/CS/HandBrakeWPF/Controls/NumberBox.xaml.cs new file mode 100644 index 000000000..7a8fc7519 --- /dev/null +++ b/win/CS/HandBrakeWPF/Controls/NumberBox.xaml.cs @@ -0,0 +1,655 @@ +// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="NumberBox.xaml.cs" company="HandBrake Project (http://handbrake.fr)">
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
+// </copyright>
+// <summary>
+// Interaction logic for NumberBox.xaml
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace HandBrakeWPF.Controls
+{
+ using System;
+ using System.Globalization;
+ using System.Linq;
+ using System.Windows;
+ using System.Windows.Controls;
+ using System.Windows.Input;
+ using System.Windows.Media;
+
+ /// <summary>
+ /// Interaction logic for NumberBox.xaml
+ /// </summary>
+ public partial class NumberBox
+ {
+ #region Constants and Fields
+
+ /// <summary>
+ /// The maximum property name.
+ /// </summary>
+ public const string MaximumPropertyName = "Maximum";
+
+ /// <summary>
+ /// The minimum property name.
+ /// </summary>
+ public const string MinimumPropertyName = "Minimum";
+
+ /// <summary>
+ /// The modulus property name.
+ /// </summary>
+ public const string ModulusPropertyName = "Modulus";
+
+ /// <summary>
+ /// The allow empty property.
+ /// </summary>
+ public static readonly DependencyProperty AllowEmptyProperty = DependencyProperty.Register(
+ "AllowEmpty", typeof(bool), typeof(NumberBox), new PropertyMetadata(true, OnAllowEmptyChanged));
+
+ /// <summary>
+ /// The maximum property.
+ /// </summary>
+ public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
+ MaximumPropertyName, typeof(double), typeof(NumberBox), new UIPropertyMetadata(double.MaxValue));
+
+ /// <summary>
+ /// The minimum property.
+ /// </summary>
+ public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
+ MinimumPropertyName, typeof(double), typeof(NumberBox), new UIPropertyMetadata(double.MinValue));
+
+ /// <summary>
+ /// The modulus property.
+ /// </summary>
+ public static readonly DependencyProperty ModulusProperty = DependencyProperty.Register(
+ ModulusPropertyName, typeof(double), typeof(NumberBox), new UIPropertyMetadata(0.0));
+
+ /// <summary>
+ /// The number property.
+ /// </summary>
+ public static readonly DependencyProperty NumberProperty = DependencyProperty.Register(
+ "Number", typeof(double), typeof(NumberBox), new PropertyMetadata(OnNumberChanged));
+
+ /// <summary>
+ /// The select all threshold.
+ /// </summary>
+ private static readonly TimeSpan SelectAllThreshold = TimeSpan.FromMilliseconds(500);
+
+ /// <summary>
+ /// The has focus.
+ /// </summary>
+ private bool hasFocus;
+
+ /// <summary>
+ /// The last focus mouse down.
+ /// </summary>
+ private DateTime lastFocusMouseDown;
+
+ /// <summary>
+ /// The none caption.
+ /// </summary>
+ private string noneCaption;
+
+ /// <summary>
+ /// The refire control.
+ /// </summary>
+ private RefireControl refireControl;
+
+ /// <summary>
+ /// The suppress refresh.
+ /// </summary>
+ private bool suppressRefresh;
+
+ #endregion
+
+ #region Constructors and Destructors
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="NumberBox"/> class.
+ /// </summary>
+ public NumberBox()
+ {
+ this.noneCaption = "(none)";
+ this.UpdateBindingOnTextChange = true;
+ this.ShowIncrementButtons = true;
+ this.SelectAllOnClick = true;
+
+ this.InitializeComponent();
+
+ this.RefreshNumberBox();
+ }
+
+ #endregion
+
+ #region Properties
+
+ /// <summary>
+ /// Gets or sets a value indicating whether allow empty.
+ /// </summary>
+ public bool AllowEmpty
+ {
+ get
+ {
+ return (bool)this.GetValue(AllowEmptyProperty);
+ }
+
+ set
+ {
+ this.SetValue(AllowEmptyProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the maximum.
+ /// </summary>
+ public double Maximum
+ {
+ get
+ {
+ return (double)this.GetValue(MaximumProperty);
+ }
+ set
+ {
+ this.SetValue(MaximumProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the minimum.
+ /// </summary>
+ public double Minimum
+ {
+ get
+ {
+ return (double)this.GetValue(MinimumProperty);
+ }
+ set
+ {
+ this.SetValue(MinimumProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the modulus.
+ /// </summary>
+ public double Modulus
+ {
+ get
+ {
+ return (double)this.GetValue(ModulusProperty);
+ }
+ set
+ {
+ this.SetValue(ModulusProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the none caption.
+ /// </summary>
+ public string NoneCaption
+ {
+ get
+ {
+ return this.noneCaption;
+ }
+
+ set
+ {
+ this.noneCaption = value;
+ this.RefreshNumberBox();
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the number.
+ /// </summary>
+ public double Number
+ {
+ get
+ {
+ return (double)this.GetValue(NumberProperty);
+ }
+
+ set
+ {
+ this.SetValue(NumberProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether select all on click.
+ /// </summary>
+ public bool SelectAllOnClick { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether show increment buttons.
+ /// </summary>
+ public bool ShowIncrementButtons { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether update binding on text change.
+ /// </summary>
+ public bool UpdateBindingOnTextChange { get; set; }
+
+ /// <summary>
+ /// Gets the increment.
+ /// </summary>
+ private double Increment
+ {
+ get
+ {
+ return this.Modulus > 0 ? this.Modulus : 1;
+ }
+ }
+
+ #endregion
+
+ #region Methods
+
+ /// <summary>
+ /// The on allow empty changed.
+ /// </summary>
+ /// <param name="dependencyObject">
+ /// The dependency object.
+ /// </param>
+ /// <param name="eventArgs">
+ /// The event args.
+ /// </param>
+ private static void OnAllowEmptyChanged(
+ DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
+ {
+ var numBox = dependencyObject as NumberBox;
+ if (numBox != null)
+ {
+ numBox.RefreshNumberBox();
+ }
+ }
+
+ /// <summary>
+ /// The on number changed.
+ /// </summary>
+ /// <param name="dependencyObject">
+ /// The dependency object.
+ /// </param>
+ /// <param name="eventArgs">
+ /// The event args.
+ /// </param>
+ private static void OnNumberChanged(
+ DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
+ {
+ if (eventArgs.NewValue != eventArgs.OldValue)
+ {
+ var numBox = dependencyObject as NumberBox;
+
+ if (!numBox.suppressRefresh)
+ {
+ numBox.RefreshNumberBox();
+ }
+ }
+ }
+
+ /// <summary>
+ /// The decrement number.
+ /// </summary>
+ private void DecrementNumber()
+ {
+ double newNumber;
+ if (this.AllowEmpty && this.Number == 0)
+ {
+ newNumber = Math.Min(this.Maximum, -this.Increment);
+ }
+ else
+ {
+ newNumber = this.Number - this.Increment;
+ }
+
+ if (newNumber < this.Minimum)
+ {
+ newNumber = this.Minimum;
+ }
+
+ if (newNumber != this.Number)
+ {
+ this.Number = newNumber;
+ }
+ }
+
+ /// <summary>
+ /// The down button mouse left button down.
+ /// </summary>
+ /// <param name="sender">
+ /// The sender.
+ /// </param>
+ /// <param name="e">
+ /// The e.
+ /// </param>
+ private void DownButtonMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+ {
+ this.refireControl = new RefireControl(this.DecrementNumber);
+ this.refireControl.Begin();
+ }
+
+ /// <summary>
+ /// The down button mouse left button up.
+ /// </summary>
+ /// <param name="sender">
+ /// The sender.
+ /// </param>
+ /// <param name="e">
+ /// The e.
+ /// </param>
+ private void DownButtonMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
+ {
+ this.refireControl.Stop();
+ }
+
+ /// <summary>
+ /// The get nearest value.
+ /// </summary>
+ /// <param name="number">
+ /// The number.
+ /// </param>
+ /// <param name="modulus">
+ /// The modulus.
+ /// </param>
+ /// <returns>
+ /// The <see cref="double"/>.
+ /// </returns>
+ private double GetNearestValue(double number, double modulus)
+ {
+ double remainder = number % modulus;
+
+ if (remainder == 0)
+ {
+ return number;
+ }
+
+ return remainder >= (modulus / 2) ? number + (modulus - remainder) : number - remainder;
+ }
+
+ /// <summary>
+ /// The increment number.
+ /// </summary>
+ private void IncrementNumber()
+ {
+ double newNumber;
+ if (this.AllowEmpty && this.Number == 0)
+ {
+ newNumber = Math.Max(this.Minimum, this.Increment);
+ }
+ else
+ {
+ newNumber = this.Number + this.Increment;
+ }
+
+ if (newNumber > this.Maximum)
+ {
+ newNumber = this.Maximum;
+ }
+
+ if (newNumber != this.Number)
+ {
+ this.Number = newNumber;
+ }
+ }
+
+ /// <summary>
+ /// The number box got focus.
+ /// </summary>
+ /// <param name="sender">
+ /// The sender.
+ /// </param>
+ /// <param name="e">
+ /// The e.
+ /// </param>
+ private void NumberBoxGotFocus(object sender, RoutedEventArgs e)
+ {
+ this.hasFocus = true;
+
+ if (this.AllowEmpty)
+ {
+ if (this.Number == 0)
+ {
+ this.numberBox.Text = string.Empty;
+ }
+
+ this.numberBox.Foreground = new SolidColorBrush(Colors.Black);
+ }
+ }
+
+ /// <summary>
+ /// The number box lost focus.
+ /// </summary>
+ /// <param name="sender">
+ /// The sender.
+ /// </param>
+ /// <param name="e">
+ /// The e.
+ /// </param>
+ private void NumberBoxLostFocus(object sender, RoutedEventArgs e)
+ {
+ this.hasFocus = false;
+
+ if (this.AllowEmpty && this.numberBox.Text == string.Empty)
+ {
+ this.Number = 0;
+ this.RefreshNumberBox();
+ return;
+ }
+
+ this.UpdateNumberBindingFromBox();
+ this.RefreshNumberBox();
+ }
+
+ /// <summary>
+ /// The number box preview key down.
+ /// </summary>
+ /// <param name="sender">
+ /// The sender.
+ /// </param>
+ /// <param name="e">
+ /// The e.
+ /// </param>
+ private void NumberBoxPreviewKeyDown(object sender, KeyEventArgs e)
+ {
+ if (e.Key == Key.Space)
+ {
+ e.Handled = true;
+ }
+ }
+
+ /// <summary>
+ /// The number box preview mouse down.
+ /// </summary>
+ /// <param name="sender">
+ /// The sender.
+ /// </param>
+ /// <param name="e">
+ /// The e.
+ /// </param>
+ private void NumberBoxPreviewMouseDown(object sender, MouseButtonEventArgs e)
+ {
+ if (!this.hasFocus)
+ {
+ this.lastFocusMouseDown = DateTime.Now;
+ }
+ }
+
+ /// <summary>
+ /// The number box preview mouse up.
+ /// </summary>
+ /// <param name="sender">
+ /// The sender.
+ /// </param>
+ /// <param name="e">
+ /// The e.
+ /// </param>
+ private void NumberBoxPreviewMouseUp(object sender, MouseButtonEventArgs e)
+ {
+ // If this mouse up is soon enough after an initial click on the box, select all.
+ if (this.SelectAllOnClick && DateTime.Now - this.lastFocusMouseDown < SelectAllThreshold)
+ {
+ this.Dispatcher.BeginInvoke(new Action(() => this.numberBox.SelectAll()));
+ }
+ }
+
+ /// <summary>
+ /// The number box preview text input.
+ /// </summary>
+ /// <param name="sender">
+ /// The sender.
+ /// </param>
+ /// <param name="e">
+ /// The e.
+ /// </param>
+ private void NumberBoxPreviewTextInput(object sender, TextCompositionEventArgs e)
+ {
+ if (e.Text.Any(c => !char.IsNumber(c) && c != '.' && (this.Minimum >= 0 || c != '-')))
+ {
+ e.Handled = true;
+ }
+ }
+
+ /// <summary>
+ /// The number box text changed.
+ /// </summary>
+ /// <param name="sender">
+ /// The sender.
+ /// </param>
+ /// <param name="e">
+ /// The e.
+ /// </param>
+ private void NumberBoxTextChanged(object sender, TextChangedEventArgs e)
+ {
+ if (this.UpdateBindingOnTextChange)
+ {
+ if (this.AllowEmpty && this.numberBox.Text == string.Empty)
+ {
+ this.Number = 0;
+ return;
+ }
+
+ this.UpdateNumberBindingFromBox();
+ }
+
+ this.RefreshNumberBoxColor();
+ }
+
+ /// <summary>
+ /// The number is valid.
+ /// </summary>
+ /// <param name="number">
+ /// The number.
+ /// </param>
+ /// <returns>
+ /// The <see cref="bool"/>.
+ /// </returns>
+ private bool NumberIsValid(double number)
+ {
+ return number >= this.Minimum && number <= this.Maximum;
+ }
+
+ /// <summary>
+ /// The refresh number box.
+ /// </summary>
+ private void RefreshNumberBox()
+ {
+ if (this.AllowEmpty && this.Number == 0)
+ {
+ this.numberBox.Text = this.hasFocus ? string.Empty : this.NoneCaption;
+
+ // this.numberBox.Foreground = new SolidColorBrush(Colors.Gray);
+ }
+ else
+ {
+ this.numberBox.Text = this.Number.ToString(CultureInfo.InvariantCulture);
+
+ // this.numberBox.Foreground = new SolidColorBrush(Colors.Black);
+ }
+
+ this.RefreshNumberBoxColor();
+ }
+
+ /// <summary>
+ /// The refresh number box color.
+ /// </summary>
+ private void RefreshNumberBoxColor()
+ {
+ this.numberBox.Foreground = this.numberBox.Text == this.NoneCaption ? new SolidColorBrush(Colors.Gray) : new SolidColorBrush(Colors.Black);
+ }
+
+ /// <summary>
+ /// The up button mouse left button down.
+ /// </summary>
+ /// <param name="sender">
+ /// The sender.
+ /// </param>
+ /// <param name="e">
+ /// The e.
+ /// </param>
+ private void UpButtonMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+ {
+ this.refireControl = new RefireControl(this.IncrementNumber);
+ this.refireControl.Begin();
+ }
+
+ /// <summary>
+ /// The up button mouse left button up.
+ /// </summary>
+ /// <param name="sender">
+ /// The sender.
+ /// </param>
+ /// <param name="e">
+ /// The e.
+ /// </param>
+ private void UpButtonMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
+ {
+ this.refireControl.Stop();
+ }
+
+ /// <summary>
+ /// The update number binding from box.
+ /// </summary>
+ private void UpdateNumberBindingFromBox()
+ {
+ double newNumber;
+ if (double.TryParse(this.numberBox.Text, out newNumber))
+ {
+ if (this.NumberIsValid(newNumber))
+ {
+ if (this.Modulus != 0)
+ {
+ newNumber = this.GetNearestValue(newNumber, this.Modulus);
+ }
+
+ if (newNumber != this.Number)
+ {
+ // While updating the binding we don't need to react to the change.
+ this.suppressRefresh = true;
+ this.Number = newNumber;
+ this.suppressRefresh = false;
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// The user control_ loaded.
+ /// </summary>
+ /// <param name="sender">
+ /// The sender.
+ /// </param>
+ /// <param name="e">
+ /// The e.
+ /// </param>
+ private void UserControl_Loaded(object sender, RoutedEventArgs e)
+ {
+ if (!this.ShowIncrementButtons)
+ {
+ this.incrementButtonsGrid.Visibility = Visibility.Collapsed;
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file diff --git a/win/CS/HandBrakeWPF/Controls/RefireControl.cs b/win/CS/HandBrakeWPF/Controls/RefireControl.cs new file mode 100644 index 000000000..e32f3b589 --- /dev/null +++ b/win/CS/HandBrakeWPF/Controls/RefireControl.cs @@ -0,0 +1,134 @@ +// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="RefireControl.cs" company="HandBrake Project (http://handbrake.fr)">
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
+// </copyright>
+// <summary>
+// The refire control.
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace HandBrakeWPF.Controls
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Threading;
+ using System.Windows;
+
+ /// <summary>
+ /// The refire control.
+ /// </summary>
+ public class RefireControl
+ {
+ #region Constants and Fields
+
+ /// <summary>
+ /// How long stages last.
+ /// </summary>
+ private const int StageDurationMsec = 900;
+
+ /// <summary>
+ /// The delays. At each stage the refire rate increases.
+ /// </summary>
+ private static readonly List<int> Delays = new List<int> { 500, 200, 100, 50, 20 };
+
+ /// <summary>
+ /// The refire action.
+ /// </summary>
+ private readonly Action refireAction;
+
+ /// <summary>
+ /// The refire sync.
+ /// </summary>
+ private readonly object refireSync = new object();
+
+ /// <summary>
+ /// The refire timer.
+ /// </summary>
+ private Timer refireTimer;
+
+ /// <summary>
+ /// The running.
+ /// </summary>
+ private bool running;
+
+ /// <summary>
+ /// The stopwatch.
+ /// </summary>
+ private Stopwatch stopwatch;
+
+ #endregion
+
+ #region Constructors and Destructors
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="RefireControl"/> class.
+ /// </summary>
+ /// <param name="refireAction">
+ /// The refire action.
+ /// </param>
+ public RefireControl(Action refireAction)
+ {
+ this.refireAction = refireAction;
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ /// <summary>
+ /// The begin.
+ /// </summary>
+ public void Begin()
+ {
+ lock (this.refireSync)
+ {
+ this.stopwatch = Stopwatch.StartNew();
+ this.running = true;
+
+ // Fire once immediately.
+ this.refireAction();
+
+ this.refireTimer = new Timer(
+ obj =>
+ {
+ lock (this.refireSync)
+ {
+ if (this.running)
+ {
+ var stage = (int)(this.stopwatch.ElapsedMilliseconds / StageDurationMsec);
+
+ int newDelay = stage >= Delays.Count ? Delays[Delays.Count - 1] : Delays[stage];
+
+ Application.Current.Dispatcher.BeginInvoke(this.refireAction);
+
+ this.refireTimer.Change(newDelay, newDelay);
+ }
+ }
+ },
+ null,
+ Delays[0],
+ Delays[0]);
+ }
+ }
+
+ /// <summary>
+ /// The stop.
+ /// </summary>
+ public void Stop()
+ {
+ lock (this.refireSync)
+ {
+ this.stopwatch.Stop();
+ this.running = false;
+
+ if (this.refireTimer != null)
+ {
+ this.refireTimer.Dispose();
+ }
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file |