summaryrefslogtreecommitdiffstats
path: root/win/CS/HandBrakeWPF/ViewModels/PictureSettingsViewModel.cs
diff options
context:
space:
mode:
authorsr55 <[email protected]>2012-02-11 23:13:12 +0000
committersr55 <[email protected]>2012-02-11 23:13:12 +0000
commitc3077f8c91764b1e5258b802a17d086c6afc02af (patch)
treeabce8ba7664b3688863c3418b2625782d2cad15c /win/CS/HandBrakeWPF/ViewModels/PictureSettingsViewModel.cs
parent1d504d557ecc008e3f7924df4181f07b793448fc (diff)
WinGui: (WPF) Initial wire-up work on the Picture settings panel and setup the auto-nameing feature for the destination path.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@4445 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'win/CS/HandBrakeWPF/ViewModels/PictureSettingsViewModel.cs')
-rw-r--r--win/CS/HandBrakeWPF/ViewModels/PictureSettingsViewModel.cs462
1 files changed, 441 insertions, 21 deletions
diff --git a/win/CS/HandBrakeWPF/ViewModels/PictureSettingsViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/PictureSettingsViewModel.cs
index 4a1a76cd6..6f741dea1 100644
--- a/win/CS/HandBrakeWPF/ViewModels/PictureSettingsViewModel.cs
+++ b/win/CS/HandBrakeWPF/ViewModels/PictureSettingsViewModel.cs
@@ -9,8 +9,10 @@
namespace HandBrakeWPF.ViewModels
{
+ using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
+ using System.Drawing;
using Caliburn.Micro;
@@ -27,7 +29,14 @@ namespace HandBrakeWPF.ViewModels
[Export(typeof(IPictureSettingsViewModel))]
public class PictureSettingsViewModel : ViewModelBase, IPictureSettingsViewModel
{
- #region Constants and Fields
+ /*
+ * TODO:
+ * Handle Presets when a new title is set
+ * Handle changes in cropping affecting the resolution calcuation.
+ *
+ */
+
+ #region Backing Fields
/// <summary>
/// The crop bottom.
@@ -104,6 +113,39 @@ namespace HandBrakeWPF.ViewModels
/// </summary>
private int width;
+ /// <summary>
+ /// Backing field for show custom anamorphic controls
+ /// </summary>
+ private bool showCustomAnamorphicControls;
+
+ /// <summary>
+ /// Backing field for for height control enabled
+ /// </summary>
+ private bool heightControlEnabled = true;
+
+ /// <summary>
+ /// Backing field for width control enabled.
+ /// </summary>
+ private bool widthControlEnabled = true;
+
+ #endregion
+
+ #region Source Information
+
+ /// <summary>
+ /// Source Resolution
+ /// </summary>
+ private Size sourceResolution;
+
+ /// <summary>
+ /// Source Aspect Ratio
+ /// </summary>
+ private double sourceAspectRatio;
+
+ /// <summary>
+ /// Source Par Values
+ /// </summary>
+ private Size sourceParValues;
#endregion
#region Constructors and Destructors
@@ -120,6 +162,7 @@ namespace HandBrakeWPF.ViewModels
public PictureSettingsViewModel(IWindowManager windowManager, IUserSettingService userSettingService)
{
this.SelectedModulus = 16;
+ this.MaintainAspectRatio = true;
}
#endregion
@@ -148,7 +191,7 @@ namespace HandBrakeWPF.ViewModels
}
set
{
- this.cropBottom = value;
+ this.cropBottom = this.CorrectForModulus(this.cropBottom, value);
this.NotifyOfPropertyChange(() => this.CropBottom);
}
}
@@ -164,7 +207,7 @@ namespace HandBrakeWPF.ViewModels
}
set
{
- this.cropLeft = value;
+ this.cropLeft = this.CorrectForModulus(this.cropLeft, value);
this.NotifyOfPropertyChange(() => this.CropLeft);
}
}
@@ -180,7 +223,7 @@ namespace HandBrakeWPF.ViewModels
}
set
{
- this.cropRight = value;
+ this.cropRight = this.CorrectForModulus(this.cropRight, value);
this.NotifyOfPropertyChange(() => this.CropRight);
}
}
@@ -196,7 +239,7 @@ namespace HandBrakeWPF.ViewModels
}
set
{
- this.cropTop = value;
+ this.cropTop = this.CorrectForModulus(this.cropTop, value);
this.NotifyOfPropertyChange(() => this.CropTop);
}
}
@@ -229,27 +272,12 @@ namespace HandBrakeWPF.ViewModels
set
{
this.displayWidth = value;
+ this.CustomAnamorphicAdjust();
this.NotifyOfPropertyChange(() => this.DisplayWidth);
}
}
/// <summary>
- /// Gets or sets Height.
- /// </summary>
- public int Height
- {
- get
- {
- return this.height;
- }
- set
- {
- this.height = value;
- this.NotifyOfPropertyChange(() => this.Height);
- }
- }
-
- /// <summary>
/// Gets or sets a value indicating whether IsCustomCrop.
/// </summary>
public bool IsCustomCrop
@@ -277,6 +305,7 @@ namespace HandBrakeWPF.ViewModels
set
{
this.maintainAspectRatio = value;
+ this.WidthAdjust();
this.NotifyOfPropertyChange(() => this.MaintainAspectRatio);
}
}
@@ -304,6 +333,7 @@ namespace HandBrakeWPF.ViewModels
set
{
this.parHeight = value;
+ this.CustomAnamorphicAdjust();
this.NotifyOfPropertyChange(() => this.ParHeight);
}
}
@@ -320,6 +350,7 @@ namespace HandBrakeWPF.ViewModels
set
{
this.parWidth = value;
+ this.CustomAnamorphicAdjust();
this.NotifyOfPropertyChange(() => this.ParWidth);
}
}
@@ -336,6 +367,7 @@ namespace HandBrakeWPF.ViewModels
set
{
this.selectedAnamorphicMode = value;
+ this.AnamorphicAdjust();
this.NotifyOfPropertyChange(() => this.SelectedAnamorphicMode);
}
}
@@ -352,6 +384,7 @@ namespace HandBrakeWPF.ViewModels
set
{
this.selectedModulus = value;
+ this.ModulusAdjust();
this.NotifyOfPropertyChange(() => this.SelectedModulus);
}
}
@@ -384,10 +417,76 @@ namespace HandBrakeWPF.ViewModels
set
{
this.width = value;
+ this.WidthAdjust();
this.NotifyOfPropertyChange(() => this.Width);
}
}
+ /// <summary>
+ /// Gets or sets Height.
+ /// </summary>
+ public int Height
+ {
+ get
+ {
+ return this.height;
+ }
+ set
+ {
+ this.height = value;
+ this.HeightAdjust();
+ this.NotifyOfPropertyChange(() => this.Height);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether ShowCustomAnamorphicControls.
+ /// </summary>
+ public bool ShowCustomAnamorphicControls
+ {
+ get
+ {
+ return this.showCustomAnamorphicControls;
+ }
+ set
+ {
+ this.showCustomAnamorphicControls = value;
+ this.NotifyOfPropertyChange(() => ShowCustomAnamorphicControls);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether HeightControlEnabled.
+ /// </summary>
+ public bool HeightControlEnabled
+ {
+ get
+ {
+ return this.heightControlEnabled;
+ }
+ set
+ {
+ this.heightControlEnabled = value;
+ this.NotifyOfPropertyChange(() => HeightControlEnabled);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether WidthControlEnabled.
+ /// </summary>
+ public bool WidthControlEnabled
+ {
+ get
+ {
+ return this.widthControlEnabled;
+ }
+ set
+ {
+ this.widthControlEnabled = value;
+ this.NotifyOfPropertyChange(() => WidthControlEnabled);
+ }
+ }
+
#endregion
#region Public Methods
@@ -406,7 +505,328 @@ namespace HandBrakeWPF.ViewModels
/// </param>
public void SetSource(Title title, Preset preset, EncodeTask task)
{
+ if (title != null)
+ {
+ // Set cached info
+ this.sourceAspectRatio = title.AspectRatio;
+ this.sourceParValues = title.ParVal;
+ this.sourceResolution = title.Resolution;
+
+ // Set Screen Controls
+ this.SourceInfo = string.Format("{0}x{1}, Aspect Ratio: {2:0.00}", title.Resolution.Width, title.Resolution.Height, title.AspectRatio);
+ this.CropTop = title.AutoCropDimensions.Top;
+ this.CropBottom = title.AutoCropDimensions.Bottom;
+ this.CropLeft = title.AutoCropDimensions.Left;
+ this.CropRight = title.AutoCropDimensions.Right;
+
+ // TODO handle preset max width / height
+ this.Width = title.Resolution.Width;
+ this.Height = title.Resolution.Height;
+ this.MaintainAspectRatio = true;
+ }
}
#endregion
+
+ /// <summary>
+ /// Adjust other values after the user has altered the width
+ /// </summary>
+ private void WidthAdjust()
+ {
+ if (this.width > this.sourceResolution.Width)
+ {
+ this.width = this.sourceResolution.Width;
+ }
+
+ switch (SelectedAnamorphicMode)
+ {
+ case Anamorphic.None:
+ if (this.MaintainAspectRatio)
+ {
+ double crop_width = this.sourceResolution.Width - this.CropLeft - this.CropRight;
+ double crop_height = this.sourceResolution.Height - this.CropTop - this.CropBottom;
+
+ if (SourceAspect.Width == 0 && SourceAspect.Height == 0)
+ break;
+
+ double newHeight = ((double)this.Width * this.sourceResolution.Width * SourceAspect.Height * crop_height) /
+ (this.sourceResolution.Height * SourceAspect.Width * crop_width);
+
+ this.height = (int)Math.Round(GetModulusValue(newHeight), 0);
+ this.NotifyOfPropertyChange("Height");
+ }
+ break;
+ case Anamorphic.Strict:
+ this.width = 0;
+ this.height = 0;
+
+ this.NotifyOfPropertyChange("Width");
+ this.NotifyOfPropertyChange("Height");
+ this.SetDisplaySize();
+ break;
+ case Anamorphic.Loose:
+ this.height = 0;
+ this.NotifyOfPropertyChange("Width");
+ this.NotifyOfPropertyChange("Height");
+ this.SetDisplaySize();
+ break;
+ case Anamorphic.Custom:
+ this.SetDisplaySize();
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Adjust other values after the user has altered the height
+ /// </summary>
+ private void HeightAdjust()
+ {
+ if (this.height > this.sourceResolution.Height)
+ {
+ this.height = this.sourceResolution.Height;
+ }
+
+ switch (SelectedAnamorphicMode)
+ {
+ case Anamorphic.None:
+ if (this.MaintainAspectRatio)
+ {
+ double crop_width = this.sourceResolution.Width - this.CropLeft - this.CropRight;
+ double crop_height = this.sourceResolution.Height - this.CropTop - this.CropBottom;
+
+ double new_width = ((double)this.Height * this.sourceResolution.Height * SourceAspect.Width * crop_width) /
+ (this.sourceResolution.Width * SourceAspect.Height * crop_height);
+
+ this.Width = (int)Math.Round(GetModulusValue(new_width), 0);
+ this.NotifyOfPropertyChange("Width");
+ }
+ break;
+ case Anamorphic.Custom:
+ this.SetDisplaySize();
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Adjust other values after the user has altered one of the custom anamorphic settings
+ /// </summary>
+ private void CustomAnamorphicAdjust()
+ {
+ this.SetDisplaySize();
+ }
+
+ /// <summary>
+ /// Adjust other values after the user has altered the modulus
+ /// </summary>
+ private void ModulusAdjust()
+ {
+ this.WidthAdjust();
+ }
+
+ /// <summary>
+ /// Adjust other values after the user has altered the anamorphic.
+ /// </summary>
+ private void AnamorphicAdjust()
+ {
+ this.DisplaySize = this.sourceResolution.IsEmpty
+ ? "No Title Selected"
+ : string.Format("{0}x{1}",
+ this.CalculateAnamorphicSizes().Width,
+ this.CalculateAnamorphicSizes().Height);
+
+ switch (SelectedAnamorphicMode)
+ {
+ case Anamorphic.None:
+ this.WidthControlEnabled = true;
+ this.HeightControlEnabled = true;
+ this.ShowCustomAnamorphicControls = false;
+ this.Width = sourceResolution.Width;
+ this.SetDisplaySize();
+ break;
+ case Anamorphic.Strict:
+ this.WidthControlEnabled = false;
+ this.HeightControlEnabled = false;
+ this.ShowCustomAnamorphicControls = false;
+
+ this.width = 0;
+ this.height = 0;
+ this.NotifyOfPropertyChange(() => Width);
+ this.NotifyOfPropertyChange(() => Height);
+ this.SetDisplaySize();
+ break;
+
+ case Anamorphic.Loose:
+ this.WidthControlEnabled = true;
+ this.HeightControlEnabled = false;
+ this.ShowCustomAnamorphicControls = false;
+
+ this.width = this.sourceResolution.Width;
+ this.height = 0;
+ this.NotifyOfPropertyChange(() => Width);
+ this.NotifyOfPropertyChange(() => Height);
+ this.SetDisplaySize();
+ break;
+
+ case Anamorphic.Custom:
+ this.WidthControlEnabled = true;
+ this.HeightControlEnabled = true;
+ this.ShowCustomAnamorphicControls = true;
+
+ this.width = this.sourceResolution.Width;
+ this.height = 0;
+ this.NotifyOfPropertyChange(() => Width);
+ this.NotifyOfPropertyChange(() => Height);
+
+ this.displayWidth = this.CalculateAnamorphicSizes().Width;
+ this.parWidth = this.sourceParValues.Width;
+ this.parHeight = this.sourceParValues.Height;
+ this.NotifyOfPropertyChange(() => ParHeight);
+ this.NotifyOfPropertyChange(() => ParWidth);
+ this.NotifyOfPropertyChange(() => DisplayWidth);
+
+ this.SetDisplaySize();
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Gets SourceAspect.
+ /// </summary>
+ private Size SourceAspect
+ {
+ get
+ {
+ // display aspect = (width * par_width) / (height * par_height)
+ return new Size((this.sourceParValues.Width * this.sourceResolution.Width),
+ (this.sourceParValues.Height * this.sourceResolution.Height));
+ }
+ }
+
+ /// <summary>
+ /// Set the display size text
+ /// </summary>
+ private void SetDisplaySize()
+ {
+ this.DisplaySize = this.sourceResolution.IsEmpty
+ ? "No Title Selected"
+ : string.Format("{0}x{1}",
+ this.CalculateAnamorphicSizes().Width,
+ this.CalculateAnamorphicSizes().Height);
+ }
+
+ /// <summary>
+ /// Calculate the Anamorphic Resolution for the selected title.
+ /// </summary>
+ /// <returns>
+ /// A Size With Width/Height for this title.
+ /// </returns>
+ private Size CalculateAnamorphicSizes()
+ {
+ if (this.sourceResolution.IsEmpty)
+ {
+ return new Size(0, 0);
+ }
+
+ /* Set up some variables to make the math easier to follow. */
+ int croppedWidth = this.sourceResolution.Width - this.CropLeft - this.CropRight;
+ int croppedHeight = this.sourceResolution.Height - this.CropTop - this.CropBottom;
+ double storageAspect = (double)croppedWidth / croppedHeight;
+
+ /* Figure out what width the source would display at. */
+ double sourceDisplayWidth = (double)croppedWidth * this.sourceParValues.Width / this.sourceParValues.Height;
+
+ /*
+ 3 different ways of deciding output dimensions:
+ - 1: Strict anamorphic, preserve source dimensions
+ - 2: Loose anamorphic, round to mod16 and preserve storage aspect ratio
+ - 3: Power user anamorphic, specify everything
+ */
+ double calcWidth, calcHeight;
+ switch (this.SelectedAnamorphicMode)
+ {
+ default:
+ case Anamorphic.Strict:
+ /* Strict anamorphic */
+ double dispWidth = ((double)croppedWidth * this.sourceParValues.Width / this.sourceParValues.Height);
+ dispWidth = Math.Round(dispWidth, 0);
+ Size output = new Size((int)dispWidth, croppedHeight);
+ return output;
+
+ case Anamorphic.Loose:
+ /* "Loose" anamorphic.
+ - Uses mod16-compliant dimensions,
+ - Allows users to set the width
+ */
+ calcWidth = GetModulusValue(this.Width); /* Time to get picture width that divide cleanly.*/
+ calcHeight = (calcWidth / storageAspect) + 0.5;
+ calcHeight = GetModulusValue(calcHeight); /* Time to get picture height that divide cleanly.*/
+
+ /* The film AR is the source's display width / cropped source height.
+ The output display width is the output height * film AR.
+ The output PAR is the output display width / output storage width. */
+ double pixelAspectWidth = calcHeight * sourceDisplayWidth / croppedHeight;
+ double pixelAspectHeight = calcWidth;
+
+ double disWidthLoose = (calcWidth * pixelAspectWidth / pixelAspectHeight);
+ if (double.IsNaN(disWidthLoose))
+ disWidthLoose = 0;
+
+ return new Size((int)disWidthLoose, (int)calcHeight);
+
+ case Anamorphic.Custom:
+ // Get the User Interface Values
+ double UIdisplayWidth;
+ double.TryParse(this.DisplayWidth.ToString(), out UIdisplayWidth);
+
+ /* Anamorphic 3: Power User Jamboree - Set everything based on specified values */
+ calcHeight = GetModulusValue(this.Height);
+
+ if (this.MaintainAspectRatio)
+ return new Size((int)Math.Truncate(UIdisplayWidth), (int)calcHeight);
+
+ return new Size((int)Math.Truncate(UIdisplayWidth), (int)calcHeight);
+ }
+ }
+
+ /// <summary>
+ /// For a given value, correct so that it matches the users currently selected modulus value
+ /// </summary>
+ /// <param name="value">
+ /// The value.
+ /// </param>
+ /// <returns>
+ /// Value corrected so that value % selected modulus == 0
+ /// </returns>
+ private double GetModulusValue(double value)
+ {
+ double remainder = value % this.SelectedModulus;
+
+ if (remainder == 0)
+ return value;
+
+ return remainder >= ((double)this.SelectedModulus / 2) ? value + (this.SelectedModulus - remainder) : value - remainder;
+ }
+
+ /// <summary>
+ /// Correct the new value so that the result of the modulus of that value is 0
+ /// </summary>
+ /// <param name="oldValue">
+ /// The old value.
+ /// </param>
+ /// <param name="newValue">
+ /// The new value.
+ /// </param>
+ /// <returns>
+ /// The Value corrected so that for a given modulus the result is 0
+ /// </returns>
+ private int CorrectForModulus(int oldValue, int newValue)
+ {
+ int remainder = newValue % 2;
+ if (remainder == 0)
+ {
+ return newValue;
+ }
+
+ return newValue > oldValue ? newValue + remainder : newValue - remainder;
+ }
}
} \ No newline at end of file