summaryrefslogtreecommitdiffstats
path: root/win/CS/HandBrakeWPF
diff options
context:
space:
mode:
authorsr55 <[email protected]>2013-01-06 19:22:56 +0000
committersr55 <[email protected]>2013-01-06 19:22:56 +0000
commite133bd8b716c17abc3c49e3acb9f20ad2a090a99 (patch)
treeba73d43db0868ad0c9ff953183dc7e11a662a17b /win/CS/HandBrakeWPF
parent4e914d9785f6f55298c3f2161cb5fa91371ccb77 (diff)
WinGui: Fix AllowSleep option. Port the Numeric Stepper control from Vidcoder onto the Picture settings panel. This should fix a number of strange behavioural issues with the old control. Please report any new issues that this causes.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@5158 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'win/CS/HandBrakeWPF')
-rw-r--r--win/CS/HandBrakeWPF/Controls/NumberBox.xaml175
-rw-r--r--win/CS/HandBrakeWPF/Controls/NumberBox.xaml.cs655
-rw-r--r--win/CS/HandBrakeWPF/Controls/RefireControl.cs134
-rw-r--r--win/CS/HandBrakeWPF/HandBrakeWPF.csproj11
-rw-r--r--win/CS/HandBrakeWPF/ViewModels/PictureSettingsViewModel.cs14
-rw-r--r--win/CS/HandBrakeWPF/Views/PictureSettingsView.xaml37
6 files changed, 1000 insertions, 26 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
diff --git a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj
index 4b3afd937..fe4287bda 100644
--- a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj
+++ b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj
@@ -81,7 +81,8 @@
<Reference Include="Castle.Windsor">
<HintPath>..\libraries\caliburn\Castle.Windsor.dll</HintPath>
</Reference>
- <Reference Include="EagleBoost.Wpf.Presentation">
+ <Reference Include="EagleBoost.Wpf.Presentation, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
<HintPath>..\libraries\EagleBoost.Wpf.Presentation.dll</HintPath>
</Reference>
<Reference Include="GongSolutions.Wpf.DragDrop">
@@ -129,6 +130,10 @@
<Compile Include="Controls\Loading.xaml.cs">
<DependentUpon>Loading.xaml</DependentUpon>
</Compile>
+ <Compile Include="Controls\NumberBox.xaml.cs">
+ <DependentUpon>NumberBox.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Controls\RefireControl.cs" />
<Compile Include="Controls\StatusPanel.xaml.cs">
<DependentUpon>StatusPanel.xaml</DependentUpon>
</Compile>
@@ -299,6 +304,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
+ <Page Include="Controls\NumberBox.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
<Page Include="Controls\StatusPanel.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
diff --git a/win/CS/HandBrakeWPF/ViewModels/PictureSettingsViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/PictureSettingsViewModel.cs
index db8e7ebe8..4c01f8f35 100644
--- a/win/CS/HandBrakeWPF/ViewModels/PictureSettingsViewModel.cs
+++ b/win/CS/HandBrakeWPF/ViewModels/PictureSettingsViewModel.cs
@@ -53,11 +53,6 @@ namespace HandBrakeWPF.ViewModels
private bool showCustomAnamorphicControls;
/// <summary>
- /// The source aspect ratio.
- /// </summary>
- private double sourceAspectRatio;
-
- /// <summary>
/// The source info.
/// </summary>
private string sourceInfo;
@@ -148,7 +143,7 @@ namespace HandBrakeWPF.ViewModels
set
{
- this.Task.Cropping.Bottom = this.CorrectForModulus(this.Task.Cropping.Bottom, value);
+ this.Task.Cropping.Bottom = value;
this.NotifyOfPropertyChange(() => this.CropBottom);
this.SetDisplaySize();
}
@@ -166,7 +161,7 @@ namespace HandBrakeWPF.ViewModels
set
{
- this.Task.Cropping.Left = this.CorrectForModulus(this.Task.Cropping.Left, value);
+ this.Task.Cropping.Left = value;
this.NotifyOfPropertyChange(() => this.CropLeft);
this.SetDisplaySize();
}
@@ -184,7 +179,7 @@ namespace HandBrakeWPF.ViewModels
set
{
- this.Task.Cropping.Right = this.CorrectForModulus(this.Task.Cropping.Right, value);
+ this.Task.Cropping.Right = value;
this.NotifyOfPropertyChange(() => this.CropRight);
this.SetDisplaySize();
}
@@ -202,7 +197,7 @@ namespace HandBrakeWPF.ViewModels
set
{
- this.Task.Cropping.Top = this.CorrectForModulus(this.Task.Cropping.Top, value);
+ this.Task.Cropping.Top = value;
this.NotifyOfPropertyChange(() => this.CropTop);
this.SetDisplaySize();
}
@@ -701,7 +696,6 @@ namespace HandBrakeWPF.ViewModels
if (title != null)
{
// Set cached info
- this.sourceAspectRatio = title.AspectRatio;
this.sourceParValues = title.ParVal;
this.sourceResolution = title.Resolution;
diff --git a/win/CS/HandBrakeWPF/Views/PictureSettingsView.xaml b/win/CS/HandBrakeWPF/Views/PictureSettingsView.xaml
index c68a54e72..e7f5bbb35 100644
--- a/win/CS/HandBrakeWPF/Views/PictureSettingsView.xaml
+++ b/win/CS/HandBrakeWPF/Views/PictureSettingsView.xaml
@@ -1,12 +1,15 @@
<UserControl x:Class="HandBrakeWPF.Views.PictureSettingsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:NumericUpDown="clr-namespace:EagleBoost.Wpf.Presentation.Controls.NumericUpDown;assembly=EagleBoost.Wpf.Presentation"
- xmlns:Converters="clr-namespace:HandBrakeWPF.Converters">
+ xmlns:Converters="clr-namespace:HandBrakeWPF.Converters"
+ xmlns:controls="clr-namespace:HandBrakeWPF.Controls">
<UserControl.Resources>
<Converters:BooleanConverter x:Key="boolConverter" />
<Converters:BooleanToVisibilityConverter x:Key="boolToVisConverter" />
+ <Style TargetType="controls:NumberBox">
+ <Setter Property="Height" Value="24" />
+ </Style>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
@@ -24,10 +27,10 @@
<!-- Row 2-->
<StackPanel Orientation="Horizontal" Margin="5,0,5,0">
<Label Content="Width:" Grid.Row="1" Grid.Column="0" />
- <NumericUpDown:NumericUpDown Value="{Binding Width, Mode=TwoWay}" IsEnabled="{Binding WidthControlEnabled}" SmallChange="{Binding SelectedModulus, Mode=OneWay}"
+ <controls:NumberBox Number="{Binding Width, Mode=TwoWay}" IsEnabled="{Binding WidthControlEnabled}" Modulus="{Binding SelectedModulus, Mode=OneWay}"
Minimum="0" Grid.Row="1" Grid.Column="1" Width="60" />
<Label Content="Height:" Grid.Row="1" Grid.Column="2" />
- <NumericUpDown:NumericUpDown Value="{Binding Height, Mode=TwoWay}" IsEnabled="{Binding HeightControlEnabled}" SmallChange="{Binding SelectedModulus, Mode=OneWay}"
+ <controls:NumberBox Number="{Binding Height, Mode=TwoWay}" IsEnabled="{Binding HeightControlEnabled}" Modulus="{Binding SelectedModulus, Mode=OneWay}"
Minimum="0" Grid.Row="1" Grid.Column="3" Width="60" />
<CheckBox Content="Keep Aspect Ratio" IsChecked="{Binding MaintainAspectRatio}" VerticalAlignment="Center" Margin="5,0,0,0" />
</StackPanel>
@@ -71,10 +74,11 @@
<Label Content="PAR Width:" Grid.Row="1" Grid.Column="0" />
<Label Content="PAR Height:" Grid.Row="5" Grid.Column="0" />
- <NumericUpDown:NumericUpDown Width="60" Value="{Binding DisplayWidth, Mode=TwoWay}" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left" Margin="0,0,0,5" />
- <NumericUpDown:NumericUpDown Width="60" Value="{Binding ParWidth, Mode=TwoWay}" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left"
+ <controls:NumberBox Width="60" Number="{Binding DisplayWidth, Mode=TwoWay}" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left" Margin="0,0,0,5"
+ AllowEmpty="False" />
+ <controls:NumberBox Width="60" Number="{Binding ParWidth, Mode=TwoWay}" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" AllowEmpty="False"
IsEnabled="{Binding MaintainAspectRatio, Converter={StaticResource boolConverter}, ConverterParameter=true}" Margin="0,0,0,5" />
- <NumericUpDown:NumericUpDown Width="60" Value="{Binding ParHeight, Mode=TwoWay}" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left"
+ <controls:NumberBox Width="60" Number="{Binding ParHeight, Mode=TwoWay}" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left" AllowEmpty="False"
IsEnabled="{Binding MaintainAspectRatio, Converter={StaticResource boolConverter}, ConverterParameter=true}" Margin="0,0,0,5" />
</Grid>
@@ -125,14 +129,17 @@
<Label Content="Left" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Center" />
<Label Content="Right" Grid.Row="2" Grid.Column="4" HorizontalAlignment="Center" />
- <NumericUpDown:NumericUpDown Width="60" Value="{Binding CropTop, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" IsEnabled="{Binding IsCustomCrop}" Grid.Row="1" Grid.Column="2"
- HorizontalAlignment="Left" Margin="0,0,0,5" />
- <NumericUpDown:NumericUpDown Width="60" Value="{Binding CropBottom, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" IsEnabled="{Binding IsCustomCrop}" Grid.Row="3" Grid.Column="2"
- HorizontalAlignment="Left" Margin="0,0,0,5" />
- <NumericUpDown:NumericUpDown Width="60" Value="{Binding CropLeft, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" IsEnabled="{Binding IsCustomCrop}" Grid.Row="2" Grid.Column="1"
- HorizontalAlignment="Left" Margin="0,0,0,5" />
- <NumericUpDown:NumericUpDown Width="60" Value="{Binding CropRight, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" IsEnabled="{Binding IsCustomCrop}" Grid.Row="2" Grid.Column="3"
- HorizontalAlignment="Left" Margin="0,0,0,5" />
+ <controls:NumberBox Width="60" HorizontalAlignment="Left" Margin="0,0,0,5" IsEnabled="{Binding IsCustomCrop}" Grid.Row="1" Grid.Column="2"
+ Minimum="0" Modulus="2" Number="{Binding CropTop, Mode=TwoWay}" UpdateBindingOnTextChange="True" ShowIncrementButtons="True" AllowEmpty="False" />
+
+ <controls:NumberBox Width="60" HorizontalAlignment="Left" Margin="0,0,0,5" IsEnabled="{Binding IsCustomCrop}" Grid.Row="3" Grid.Column="2"
+ Minimum="0" Modulus="2" Number="{Binding CropBottom, Mode=TwoWay}" UpdateBindingOnTextChange="True" ShowIncrementButtons="True" AllowEmpty="False" />
+
+ <controls:NumberBox Width="60" HorizontalAlignment="Left" Margin="0,0,0,5" IsEnabled="{Binding IsCustomCrop}" Grid.Row="2" Grid.Column="1"
+ Minimum="0" Modulus="2" Number="{Binding CropLeft, Mode=TwoWay}" UpdateBindingOnTextChange="True" ShowIncrementButtons="True" AllowEmpty="False" />
+
+ <controls:NumberBox Width="60" HorizontalAlignment="Left" Margin="0,0,0,5" IsEnabled="{Binding IsCustomCrop}" Grid.Row="2" Grid.Column="3"
+ Minimum="0" Modulus="2" Number="{Binding CropRight, Mode=TwoWay}" UpdateBindingOnTextChange="True" ShowIncrementButtons="True" AllowEmpty="False" />
</Grid>