From c3077f8c91764b1e5258b802a17d086c6afc02af Mon Sep 17 00:00:00 2001 From: sr55 Date: Sat, 11 Feb 2012 23:13:12 +0000 Subject: 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 --- .../HandBrake.ApplicationServices/Parsing/Title.cs | 2 +- win/CS/HandBrakeWPF/HandBrakeWPF.csproj | 1 + win/CS/HandBrakeWPF/Helpers/AutoNameHelper.cs | 25 +- win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs | 26 +- .../ViewModels/PictureSettingsViewModel.cs | 462 ++++++++++++++++++++- win/CS/HandBrakeWPF/Views/PictureSettingsView.xaml | 73 +++- 6 files changed, 523 insertions(+), 66 deletions(-) (limited to 'win') diff --git a/win/CS/HandBrake.ApplicationServices/Parsing/Title.cs b/win/CS/HandBrake.ApplicationServices/Parsing/Title.cs index 6b3d517c9..4c800f24c 100644 --- a/win/CS/HandBrake.ApplicationServices/Parsing/Title.cs +++ b/win/CS/HandBrake.ApplicationServices/Parsing/Title.cs @@ -188,7 +188,7 @@ namespace HandBrake.ApplicationServices.Parsing { thisTitle.Resolution = new Size(int.Parse(m.Groups[1].Value), int.Parse(m.Groups[2].Value)); thisTitle.ParVal = new Size(int.Parse(m.Groups[3].Value), int.Parse(m.Groups[4].Value)); - thisTitle.AspectRatio = float.Parse(m.Groups[5].Value, CultureInfo.InvariantCulture); + thisTitle.AspectRatio = Math.Round(float.Parse(m.Groups[5].Value, CultureInfo.InvariantCulture), 2); thisTitle.Fps = float.Parse(m.Groups[6].Value, CultureInfo.InvariantCulture); } diff --git a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj index 06abbad46..3e940794f 100644 --- a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj +++ b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj @@ -63,6 +63,7 @@ + ..\libraries\caliburn\System.Windows.Interactivity.dll diff --git a/win/CS/HandBrakeWPF/Helpers/AutoNameHelper.cs b/win/CS/HandBrakeWPF/Helpers/AutoNameHelper.cs index f0b942120..589c698e2 100644 --- a/win/CS/HandBrakeWPF/Helpers/AutoNameHelper.cs +++ b/win/CS/HandBrakeWPF/Helpers/AutoNameHelper.cs @@ -13,6 +13,8 @@ namespace HandBrakeWPF.Helpers using System.IO; using System.Linq; + using Caliburn.Micro; + using HandBrake.ApplicationServices.Extensions; using HandBrake.ApplicationServices.Model; using HandBrake.ApplicationServices.Model.Encoding; @@ -23,22 +25,6 @@ namespace HandBrakeWPF.Helpers /// public class AutoNameHelper { - /// - /// Backing field for the user setting service - /// - private static IUserSettingService userSettingService; - - /// - /// Initializes a new instance of the class. - /// - /// - /// The user Setting. - /// - public AutoNameHelper(IUserSettingService userSetting) - { - userSettingService = userSetting; - } - /// /// Function which generates the filename and path automatically based on /// the Source Name, DVD title and DVD Chapters @@ -54,6 +40,13 @@ namespace HandBrakeWPF.Helpers /// public static string AutoName(EncodeTask task, string sourceOrLabelName) { + + IUserSettingService userSettingService = IoC.Get(); + if (task.Destination == null) + { + task.Destination = string.Empty; + } + string autoNamePath = string.Empty; if (task.Title != 0) // TODO check. { diff --git a/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs index 9bb31ee5a..51e032e9a 100644 --- a/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs @@ -27,6 +27,7 @@ namespace HandBrakeWPF.ViewModels using HandBrake.ApplicationServices.Services.Interfaces; using HandBrake.ApplicationServices.Utilities; + using HandBrakeWPF.Helpers; using HandBrakeWPF.ViewModels.Interfaces; using Ookii.Dialogs.Wpf; @@ -329,7 +330,7 @@ namespace HandBrakeWPF.ViewModels { get { - // TODO + // TODO Disc Label //if (this.selectedSourceType == SourceType.DvdDrive) //{ // return this.dvdDriveLabel; @@ -510,6 +511,12 @@ namespace HandBrakeWPF.ViewModels this.SelectedEndPoint = selectedTitle.Chapters.Last().ChapterNumber; this.SelectedPointToPoint = PointToPointMode.Chapters; this.SelectedAngle = 1; + + this.CurrentTask.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName); + this.NotifyOfPropertyChange("CurrentTask"); + + // Setup the tab controls + this.SetupTabs(); } } } @@ -1023,13 +1030,16 @@ namespace HandBrakeWPF.ViewModels private void SetupTabs() { // Setup the Tabs - this.PictureSettingsViewModel.SetSource(this.SelectedTitle, this.SelectedPreset, this.CurrentTask); - this.VideoViewModel.SetSource(this.SelectedTitle, this.SelectedPreset, this.CurrentTask); - this.FiltersViewModel.SetSource(this.SelectedTitle, this.SelectedPreset, this.CurrentTask); - this.AudioViewModel.SetSource(this.SelectedTitle, this.SelectedPreset, this.CurrentTask); - this.SubtitleViewModel.SetSource(this.SelectedTitle, this.SelectedPreset, this.CurrentTask); - this.ChaptersViewModel.SetSource(this.SelectedTitle, this.SelectedPreset, this.CurrentTask); - this.AdvancedViewModel.SetSource(this.SelectedTitle, this.SelectedPreset, this.CurrentTask); + if (this.selectedTitle != null) + { + this.PictureSettingsViewModel.SetSource(this.SelectedTitle, this.SelectedPreset, this.CurrentTask); + this.VideoViewModel.SetSource(this.SelectedTitle, this.SelectedPreset, this.CurrentTask); + this.FiltersViewModel.SetSource(this.SelectedTitle, this.SelectedPreset, this.CurrentTask); + this.AudioViewModel.SetSource(this.SelectedTitle, this.SelectedPreset, this.CurrentTask); + this.SubtitleViewModel.SetSource(this.SelectedTitle, this.SelectedPreset, this.CurrentTask); + this.ChaptersViewModel.SetSource(this.SelectedTitle, this.SelectedPreset, this.CurrentTask); + this.AdvancedViewModel.SetSource(this.SelectedTitle, this.SelectedPreset, this.CurrentTask); + } } #endregion 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 /// /// The crop bottom. @@ -104,6 +113,39 @@ namespace HandBrakeWPF.ViewModels /// private int width; + /// + /// Backing field for show custom anamorphic controls + /// + private bool showCustomAnamorphicControls; + + /// + /// Backing field for for height control enabled + /// + private bool heightControlEnabled = true; + + /// + /// Backing field for width control enabled. + /// + private bool widthControlEnabled = true; + + #endregion + + #region Source Information + + /// + /// Source Resolution + /// + private Size sourceResolution; + + /// + /// Source Aspect Ratio + /// + private double sourceAspectRatio; + + /// + /// Source Par Values + /// + 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,26 +272,11 @@ namespace HandBrakeWPF.ViewModels set { this.displayWidth = value; + this.CustomAnamorphicAdjust(); this.NotifyOfPropertyChange(() => this.DisplayWidth); } } - /// - /// Gets or sets Height. - /// - public int Height - { - get - { - return this.height; - } - set - { - this.height = value; - this.NotifyOfPropertyChange(() => this.Height); - } - } - /// /// Gets or sets a value indicating whether 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); } } + /// + /// Gets or sets Height. + /// + public int Height + { + get + { + return this.height; + } + set + { + this.height = value; + this.HeightAdjust(); + this.NotifyOfPropertyChange(() => this.Height); + } + } + + /// + /// Gets or sets a value indicating whether ShowCustomAnamorphicControls. + /// + public bool ShowCustomAnamorphicControls + { + get + { + return this.showCustomAnamorphicControls; + } + set + { + this.showCustomAnamorphicControls = value; + this.NotifyOfPropertyChange(() => ShowCustomAnamorphicControls); + } + } + + /// + /// Gets or sets a value indicating whether HeightControlEnabled. + /// + public bool HeightControlEnabled + { + get + { + return this.heightControlEnabled; + } + set + { + this.heightControlEnabled = value; + this.NotifyOfPropertyChange(() => HeightControlEnabled); + } + } + + /// + /// Gets or sets a value indicating whether WidthControlEnabled. + /// + 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 /// 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 + + /// + /// Adjust other values after the user has altered the width + /// + 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; + } + } + + /// + /// Adjust other values after the user has altered the height + /// + 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; + } + } + + /// + /// Adjust other values after the user has altered one of the custom anamorphic settings + /// + private void CustomAnamorphicAdjust() + { + this.SetDisplaySize(); + } + + /// + /// Adjust other values after the user has altered the modulus + /// + private void ModulusAdjust() + { + this.WidthAdjust(); + } + + /// + /// Adjust other values after the user has altered the anamorphic. + /// + 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; + } + } + + /// + /// Gets SourceAspect. + /// + 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)); + } + } + + /// + /// Set the display size text + /// + private void SetDisplaySize() + { + this.DisplaySize = this.sourceResolution.IsEmpty + ? "No Title Selected" + : string.Format("{0}x{1}", + this.CalculateAnamorphicSizes().Width, + this.CalculateAnamorphicSizes().Height); + } + + /// + /// Calculate the Anamorphic Resolution for the selected title. + /// + /// + /// A Size With Width/Height for this title. + /// + 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); + } + } + + /// + /// For a given value, correct so that it matches the users currently selected modulus value + /// + /// + /// The value. + /// + /// + /// Value corrected so that value % selected modulus == 0 + /// + 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; + } + + /// + /// Correct the new value so that the result of the modulus of that value is 0 + /// + /// + /// The old value. + /// + /// + /// The new value. + /// + /// + /// The Value corrected so that for a given modulus the result is 0 + /// + 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 diff --git a/win/CS/HandBrakeWPF/Views/PictureSettingsView.xaml b/win/CS/HandBrakeWPF/Views/PictureSettingsView.xaml index 5ebe36b33..d9ed6cef2 100644 --- a/win/CS/HandBrakeWPF/Views/PictureSettingsView.xaml +++ b/win/CS/HandBrakeWPF/Views/PictureSettingsView.xaml @@ -6,6 +6,7 @@ + @@ -16,16 +17,18 @@ - @@ -34,10 +37,6 @@ - - - - @@ -47,21 +46,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +