OSDN Git Service

LinGui: don't remove srt subs when changing from mkv to mp4
[handbrake-jp/handbrake-jp-git.git] / win / C# / Controls / PictureSettings.cs
index 096ccad..70273cc 100644 (file)
@@ -1,6 +1,7 @@
 using System;\r
 using System.ComponentModel;\r
 using System.Drawing;\r
+using System.Globalization;\r
 using System.Windows.Forms;\r
 using Handbrake.Parsing;\r
 \r
@@ -8,13 +9,14 @@ namespace Handbrake.Controls
 {\r
     public partial class PictureSettings : UserControl\r
     {\r
-        private bool _preventChangingWidth, _preventChangingHeight;\r
-        private int _maxWidth, _maxHeight, _lastEncodeWidth, _lastEncodeHeight;\r
-        private double _anamorphicRatio, _displayRatio;\r
-        private Title _title;\r
-        private double storageAspect;\r
+        private readonly CultureInfo Culture = new CultureInfo("en-US", false);\r
         public event EventHandler PictureSettingsChanged;\r
 \r
+        private Boolean _preventChangingWidth, _preventChangingHeight, _preventChangingCustom, _preventChangingDisplayWidth;\r
+        private int _presetMaximumWidth, _presetMaximumHeight;\r
+        private double _cachedDar;\r
+        private Title _sourceTitle;\r
+\r
         public PictureSettings()\r
         {\r
             InitializeComponent();\r
@@ -30,356 +32,260 @@ namespace Handbrake.Controls
         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\r
         public Title Source\r
         {\r
-            get { return _title; }\r
+            private get { return _sourceTitle; }\r
             set\r
             {\r
-                _title = value;\r
-                _displayRatio = ((double)_title.Resolution.Width * _title.ParVal.Width / _title.ParVal.Height) / _title.Resolution.Height;\r
-\r
-                Enabled = _title != null;\r
-\r
-                MaximumWidth = _title.Resolution.Width;\r
-                MaximumHeight = _title.Resolution.Height;\r
-\r
-                updownParWidth.Value = _title.ParVal.Width;\r
-                updownParHeight.Value = _title.ParVal.Height;\r
-\r
-                // Set the source resolution\r
-                lbl_src_res.Text = Source.Resolution.Width + " x " + Source.Resolution.Height;\r
-\r
-                // Set ratios\r
-                _anamorphicRatio = (double)Source.Resolution.Width / Source.Resolution.Height;\r
-\r
-                // Set the encode width and height\r
-                EncodeWidth = _title.Resolution.Width;\r
-                EncodeHeight = _title.Resolution.Height;\r
-\r
-                _lastEncodeWidth = _title.Resolution.Width;\r
-                _lastEncodeHeight = _title.Resolution.Height;\r
+                _sourceTitle = value;\r
+                Enabled = _sourceTitle != null;\r
 \r
-                // Set cropping\r
-                CroppingValues = _title.AutoCropDimensions;\r
+                // Set the Aspect Ratio\r
+                lbl_Aspect.Text = _sourceTitle.AspectRatio.ToString(Culture);\r
+                lbl_src_res.Text = _sourceTitle.Resolution.Width + " x " + _sourceTitle.Resolution.Height;\r
 \r
-                lbl_Aspect.Text = _title.AspectRatio.ToString();\r
+                // Set the Recommended Cropping values\r
+                crop_top.Value = GetCropMod2Clean(_sourceTitle.AutoCropDimensions[0]);\r
+                crop_bottom.Value = GetCropMod2Clean(_sourceTitle.AutoCropDimensions[1]);\r
+                crop_left.Value = GetCropMod2Clean(_sourceTitle.AutoCropDimensions[2]);\r
+                crop_right.Value = GetCropMod2Clean(_sourceTitle.AutoCropDimensions[3]);\r
 \r
-                UpdateAnamorphicValue();\r
-            }\r
-        }\r
+                // Set the Resolution Boxes\r
+                if (drp_anamorphic.SelectedIndex == 0)\r
+                {\r
+                    if (text_width.Value == 0) // Only update the values if the fields don't already have values.\r
+                        text_width.Value = _sourceTitle.Resolution.Width;\r
 \r
-        /// <summary>\r
-        /// Gets or sets the resolution of the displayed video.\r
-        /// </summary>\r
-        public Size DisplayResolution { get; set; }\r
+                    check_KeepAR.Checked = true; // Forces Resolution to be correct.\r
+                }\r
+                else\r
+                {\r
+                    if (text_width.Value == 0 && text_height.Value == 0)// Only update the values if the fields don't already have values.\r
+                    {\r
+                        text_width.Value = _sourceTitle.Resolution.Width;\r
+                        text_height.Value = _sourceTitle.Resolution.Height - (int)crop_top.Value - (int)crop_bottom.Value;\r
+                    }\r
 \r
-        public int EncodeWidth { get { return (int)text_width.Value; } set { text_width.Value = value; } }\r
+                    labelDisplaySize.Text = CalculateAnamorphicSizes().Width + "x" + CalculateAnamorphicSizes().Height;\r
+                }\r
 \r
-        public int EncodeHeight { get { return (int)text_height.Value; } set { text_height.Value = value; } }\r
+                //updownDisplayWidth.Value = CalculateAnamorphicSizes().Width;\r
+                updownParWidth.Value = _sourceTitle.ParVal.Width;\r
+                updownParHeight.Value = _sourceTitle.ParVal.Height;\r
+                //_cachedDar = (double)updownDisplayWidth.Value / (double)text_height.Value;\r
 \r
-        public int[] CroppingValues\r
-        {\r
-            get\r
-            {\r
-                return new int[4]\r
-                {\r
-                    (int)crop_top.Value,\r
-                    (int)crop_bottom.Value,\r
-                    (int)crop_left.Value,\r
-                    (int)crop_right.Value\r
-                };\r
-            }\r
-            set\r
-            {\r
-                if (value.Length != 4)\r
-                {\r
-                    throw new ArgumentException("The cropping values given must have a length of 4.");\r
-                }\r
 \r
-                crop_top.Value = value[0];\r
-                crop_bottom.Value = value[1];\r
-                crop_left.Value = value[2];\r
-                crop_right.Value = value[3];\r
+                Size croppedDar = CalculateAnamorphicSizes();\r
+                _cachedDar = (double) croppedDar.Width/croppedDar.Height;\r
+                updownDisplayWidth.Value = croppedDar.Width;\r
             }\r
         }\r
 \r
         /// <summary>\r
-        /// Gets or sets the maximum allowable width of the encoded video.\r
+        /// Gets or sets the maximum allowable size for the encoded resolution. Set a value to\r
+        /// "0" if the maximum does not matter.\r
         /// </summary>\r
-        public int MaximumWidth\r
+        [Browsable(false)]\r
+        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\r
+        public Size PresetMaximumResolution\r
         {\r
-            get { return _maxWidth; }\r
+            get { return new Size(_presetMaximumWidth, _presetMaximumHeight); }\r
             set\r
             {\r
-                _maxWidth = value > 0 ? value : (Source != null ? Source.Resolution.Width : 2560);\r
+                _presetMaximumWidth = value.Width;\r
+                _presetMaximumHeight = value.Height;\r
+\r
+                if (value.Width != 0 && value.Height != 0)\r
+                    lbl_max.Text = "Max Width / Height";\r
+                else if (value.Width != 0)\r
+                    lbl_max.Text = "Max Width";\r
+                else if (value.Height != 0)\r
+                    lbl_max.Text = "Max Height";\r
+                else\r
+                    lbl_max.Text = "";\r
             }\r
         }\r
 \r
-        /// <summary>\r
-        /// Gets or sets the maximum allowable height of the encoded video.\r
-        /// </summary>\r
-        public int MaximumHeight\r
-        {\r
-            get { return _maxHeight; }\r
-            set\r
-            {\r
-                _maxHeight = value > 0 ? value : (Source != null ? Source.Resolution.Height : 2560);\r
-            }\r
-        }      \r
-\r
-        public void setMax()\r
+        // Picture Controls\r
+        private void text_width_ValueChanged(object sender, EventArgs e)\r
         {\r
+            if (Properties.Settings.Default.disableResCalc)\r
+                return;\r
 \r
-        }\r
-\r
-        /// <summary>\r
-        /// Updates the anamorphic value shown as the display width.\r
-        /// </summary>\r
-        private void UpdateAnamorphicValue()\r
-        {\r
-            if (_title == null || _title.ParVal.IsEmpty)\r
+            if (_preventChangingWidth)\r
                 return;\r
 \r
-            // Set globally useful values\r
-            double width;\r
-            double par;\r
+            // Make sure the new value doesn't exceed the maximum\r
+            if (Source != null)\r
+                if (text_width.Value > Source.Resolution.Width)\r
+                    text_width.Value = Source.Resolution.Width;\r
 \r
             switch (drp_anamorphic.SelectedIndex)\r
             {\r
-                case 2:\r
-                    int actualWidth = (int)text_width.Value - (int)crop_left.Value - (int)crop_right.Value;\r
-                    int source_display_width = Source.Resolution.Width * Source.ParVal.Width / Source.ParVal.Height;\r
-                    int source_cropped_height = Source.Resolution.Height - (int)crop_top.Value - (int)crop_bottom.Value;\r
-                    par = ((double) text_height.Value*source_display_width/source_cropped_height)/actualWidth;\r
-                    width = (actualWidth * par);\r
-                    width = Math.Truncate(width);\r
-                    break;\r
-                default:\r
+                case 0:\r
+                    if (check_KeepAR.Checked && Source != null)\r
                     {\r
-                        if (drp_anamorphic.SelectedIndex == 1) // Strict\r
-                            par = (double)Source.ParVal.Width / Source.ParVal.Height;\r
-                        else // Custom\r
-                            par = (double)updownParWidth.Value / (double)updownParHeight.Value;\r
+                        _preventChangingHeight = true;\r
 \r
-                        // Store the latest DAR\r
-                        double rawWidth = (double)text_width.Value * par;\r
-                        _displayRatio = rawWidth / (double)text_height.Value;\r
+                        int width = (int)text_width.Value;\r
 \r
-                        width = (int)Math.Round(rawWidth);\r
-                        break;\r
-                    }\r
-            }\r
+                        double crop_width = Source.Resolution.Width - (int)crop_left.Value - (int)crop_right.Value;\r
+                        double crop_height = Source.Resolution.Height - (int)crop_top.Value - (int)crop_bottom.Value;\r
 \r
-            labelDisplaySize.Text = width + " x " + text_height.Value;\r
+                        if (SourceAspect.Width == 0 && SourceAspect.Height == 0)\r
+                            break;\r
 \r
-            updownDisplayWidth.Value = (decimal)width;\r
-            updownParWidth.Value = (decimal)width;\r
-            updownParHeight.Value = text_width.Value;\r
-        }\r
+                        double newHeight = ((double)width * Source.Resolution.Width * SourceAspect.Height * crop_height) /\r
+                                           (Source.Resolution.Height * SourceAspect.Width * crop_width);\r
+                        text_height.Value = (decimal)GetModulusValue(newHeight);\r
 \r
-        /// <summary>\r
-        /// Sets the visibility of the advanced anamorphic options.\r
-        /// </summary>\r
-        /// <param name="value">Whether or not the options should be visible.</param>\r
-        private void SetCustomAnamorphicOptionsVisible(bool visible)\r
-        {\r
-            lbl_modulus.Visible = visible;\r
-            lbl_displayWidth.Visible = visible;\r
-            lbl_parWidth.Visible = visible;\r
-            lbl_parHeight.Visible = visible;\r
+                        _preventChangingHeight = false;\r
+                    }\r
+                    break;\r
+                case 3:\r
+                    if (check_KeepAR.CheckState == CheckState.Unchecked && Source != null)\r
+                    {\r
+                        if (_preventChangingCustom)\r
+                            break;\r
 \r
-            drp_modulus.Visible = visible;\r
-            updownDisplayWidth.Visible = visible;\r
-            updownParWidth.Visible = visible;\r
-            updownParHeight.Visible = visible;\r
-        }\r
+                        _preventChangingDisplayWidth = true;\r
+                        updownDisplayWidth.Value = text_width.Value * updownParWidth.Value / updownParHeight.Value;\r
+                        _preventChangingDisplayWidth = false;\r
 \r
-        /// <summary>\r
-        /// Gets the normalized value from one given by the user that is divisible by the number\r
-        /// set in <see cref="_modulus"/>.\r
-        /// </summary>\r
-        /// <param name="value">The value to normalize</param>\r
-        /// <returns>A number that is divisible by <see cref="_modulus"/>.</returns>\r
-        /// <remarks>\r
-        /// The way that some video codecs, such as x264, compress video is by creating "macroblocks" \r
-        /// that are seperated into defined squares, often 16x16 pixels. Because of this, if the width \r
-        /// and height of the encoded video are not each divisible by the modulus defined, video quality\r
-        /// will suffer. This method takes the supplied value and normalizes it to the nearest mutliple\r
-        /// of <see cref="_modulus"/>.\r
-        /// </remarks>\r
-        private int GetModulusValue(int value)\r
-        {\r
-            int mod = int.Parse(drp_modulus.SelectedItem.ToString());\r
-            int remainder = value % mod;\r
+                        labelDisplaySize.Text = Math.Truncate(updownDisplayWidth.Value) + "x" + text_height.Value;\r
+                    }\r
 \r
-            if (remainder == 0)\r
-                return value;\r
+                    if (check_KeepAR.CheckState == CheckState.Checked && Source != null)\r
+                    {\r
+                        updownParWidth.Value = updownDisplayWidth.Value;\r
+                        updownParHeight.Value = text_width.Value;\r
+                    }\r
+                    break;\r
+                default:\r
+                    labelDisplaySize.Text = CalculateAnamorphicSizes().Width + "x" + CalculateAnamorphicSizes().Height;\r
+                    break;\r
+            }\r
 \r
-            return remainder >= mod / 2 ? value + (mod - remainder) : value - remainder;\r
+            _preventChangingWidth = false;\r
         }\r
-\r
-        private void ApplyStrictAnamorphic()\r
+        private void text_height_ValueChanged(object sender, EventArgs e)\r
         {\r
-            if (_anamorphicRatio == 0)\r
+            if (Properties.Settings.Default.disableResCalc)\r
                 return;\r
 \r
-            _preventChangingWidth = true;\r
-            _preventChangingHeight = true;\r
+            if (_preventChangingHeight)\r
+                return;\r
 \r
-            text_width.Value = _title.Resolution.Width;\r
-            text_height.Value = _title.Resolution.Height;\r
+            if (Source != null)\r
+                if (text_height.Value > Source.Resolution.Height)\r
+                    text_height.Value = Source.Resolution.Height;\r
 \r
-            _preventChangingWidth = false;\r
-            _preventChangingHeight = false;\r
-        }\r
+            switch (drp_anamorphic.SelectedIndex)\r
+            {\r
+                case 0:\r
+                    if (check_KeepAR.Checked && Source != null)\r
+                    {\r
+                        _preventChangingWidth = true;\r
 \r
-        /// <summary>\r
-        /// Loosely anamorphs encode width and height values.\r
-        /// </summary>\r
-        private void ApplyLooseAnamorphic()\r
-        {\r
-            // Prevents DivideByZeroExceptions\r
-            if (_anamorphicRatio == 0)\r
-                return;\r
+                        double crop_width = Source.Resolution.Width - (int)crop_left.Value - (int)crop_right.Value;\r
+                        double crop_height = Source.Resolution.Height - (int)crop_top.Value - (int)crop_bottom.Value;\r
 \r
-            int actualWidth = (int)text_width.Value - (int)crop_left.Value - (int)crop_right.Value;\r
-            int source_cropped_height = Source.Resolution.Height - (int)crop_top.Value - (int)crop_bottom.Value;\r
+                        double new_width = ((double)text_height.Value * Source.Resolution.Height * SourceAspect.Width * crop_width) /\r
+                                            (Source.Resolution.Width * SourceAspect.Height * crop_height);\r
 \r
-            if (storageAspect == 0)\r
-                storageAspect = (double)actualWidth / source_cropped_height;\r
-            double hcalc = (actualWidth / storageAspect) + 0.5;\r
-            double newHeight = GetModulusValue((int)hcalc);\r
+                        text_width.Value = (decimal)GetModulusValue(new_width);\r
 \r
-            text_width.Value = GetModulusValue((int)text_width.Value);\r
-            text_height.Value = (decimal)newHeight;\r
+                        _preventChangingWidth = false;\r
+                    }\r
+                    break;\r
+                case 3:\r
+                    labelDisplaySize.Text = Math.Truncate(updownDisplayWidth.Value) + "x" + text_height.Value;\r
 \r
-            UpdateAnamorphicValue();\r
-        }\r
+                    if (check_KeepAR.CheckState == CheckState.Checked && Source != null)\r
+                    {\r
+                        // - Changes DISPLAY WIDTH to keep DAR\r
+                        // - Changes PIXEL WIDTH to new DISPLAY WIDTH\r
+                        // - Changes PIXEL HEIGHT to STORAGE WIDTH\r
+                        // DAR = DISPLAY WIDTH / DISPLAY HEIGHT (cache after every modification)\r
 \r
-        /// <summary>\r
-        /// Anamorphs encode width and height based on the custom options specified.\r
-        /// </summary>\r
-        private void ApplyCustomAnamorphic(Control ctrlUpdated)\r
-        {\r
-            // Make sure the PAR values are set correctly\r
-            if (updownParWidth.Value == 0)\r
-                updownParWidth.Value = Source.ParVal.Width;\r
-            if (updownParHeight.Value == 0)\r
-                updownParHeight.Value = Source.ParVal.Height;\r
+                        double rawCalculatedDisplayWidth = (double)text_height.Value * _cachedDar;\r
 \r
-            // Set various values\r
-            int parWidth = (int)updownParWidth.Value;\r
-            int parHeight = (int)updownParHeight.Value;\r
+                        _preventChangingDisplayWidth = true; // Start Guards\r
+                        _preventChangingWidth = true;\r
 \r
-            if (!check_KeepAR.Checked)\r
-            {\r
-                switch (ctrlUpdated.Name)\r
-                {\r
-                    case "text_width":\r
-                    case "updownParWidth":\r
-                    case "updownParHeight":\r
-                        updownDisplayWidth.Value = Math.Round(text_width.Value * parWidth / parHeight);\r
-                        break;\r
-                    case "updownDisplayWidth":\r
+                        updownDisplayWidth.Value = (decimal)rawCalculatedDisplayWidth;\r
                         updownParWidth.Value = updownDisplayWidth.Value;\r
                         updownParHeight.Value = text_width.Value;\r
-                        break;\r
-                }\r
-            }\r
-            else\r
-            {\r
-                switch (ctrlUpdated.Name)\r
-                {\r
-                    case "updownDisplayWidth":\r
-                        _preventChangingHeight = true;\r
 \r
-                        text_height.Value = GetModulusValue((int)((double)updownDisplayWidth.Value / _displayRatio));\r
+                        _preventChangingWidth = false; // Reset Guards\r
+                        _preventChangingDisplayWidth = false;\r
+                    }\r
 \r
-                        _preventChangingHeight = false;\r
-                        goto case "text_width";\r
-                    case "text_height":\r
-                        updownDisplayWidth.Value = GetModulusValue((int)((double)text_width.Value * _anamorphicRatio * _displayRatio));\r
-                        goto case "text_width";\r
-                    case "text_width":\r
-                        updownParWidth.Value = updownDisplayWidth.Value;\r
-                        updownParHeight.Value = text_width.Value;\r
-                        break;\r
-                }\r
+                    break;\r
+                default:\r
+                    labelDisplaySize.Text = CalculateAnamorphicSizes().Width + "x" + CalculateAnamorphicSizes().Height;\r
+                    break;\r
             }\r
-        }\r
-\r
 \r
-\r
-        private void text_width_ValueChanged(object sender, EventArgs e)\r
+            _preventChangingHeight = false;\r
+        }\r
+        private void check_KeepAR_CheckedChanged(object sender, EventArgs e)\r
         {\r
-            if (_preventChangingWidth)\r
+            if (Properties.Settings.Default.disableResCalc)\r
                 return;\r
 \r
-            _preventChangingWidth = true;\r
-\r
-            if (text_width.Value > MaximumWidth)\r
-            {\r
-                text_width.Value = MaximumWidth;\r
-            }\r
+            //Force TextWidth to recalc height\r
+            if (check_KeepAR.Checked)\r
+                text_width_ValueChanged(this, new EventArgs());\r
 \r
-            switch (drp_anamorphic.SelectedIndex)\r
+            // Disable the Custom Anamorphic Par Controls if checked.\r
+            if (drp_anamorphic.SelectedIndex == 3)\r
             {\r
-                case 0:\r
-                    if (check_KeepAR.Checked)\r
-                    {\r
-                        _preventChangingHeight = true;\r
-\r
-                        decimal newHeight = text_width.Value / (decimal)_anamorphicRatio;\r
-                        text_height.Value = newHeight > MaximumHeight ? MaximumHeight : newHeight;\r
-\r
-                        _preventChangingHeight = false;\r
-                    }\r
-                    break;\r
-                case 1:\r
-                    ApplyStrictAnamorphic();\r
-                    break;\r
-                case 2:\r
-                    ApplyLooseAnamorphic();\r
-                    break;\r
-                case 3:\r
-                    ApplyCustomAnamorphic((Control)sender);\r
-                    break;\r
+                updownParWidth.Enabled = !check_KeepAR.Checked;\r
+                updownParHeight.Enabled = !check_KeepAR.Checked;\r
             }\r
 \r
-            _preventChangingWidth = false;\r
+            // Raise the Picture Settings Changed Event\r
+            if (PictureSettingsChanged != null)\r
+                PictureSettingsChanged(this, new EventArgs());\r
         }\r
-\r
-        private void text_height_ValueChanged(object sender, EventArgs e)\r
+        private void updownDisplayWidth_ValueChanged(object sender, EventArgs e)\r
         {\r
-            if (_preventChangingHeight)\r
+            if (Properties.Settings.Default.disableResCalc)\r
                 return;\r
 \r
-            _preventChangingHeight = true;\r
-\r
-            if (text_height.Value > MaximumHeight)\r
+            if (_preventChangingDisplayWidth == false && check_KeepAR.CheckState == CheckState.Unchecked)\r
             {\r
-                text_height.Value = MaximumHeight;\r
+                _preventChangingCustom = true;\r
+                updownParWidth.Value = updownDisplayWidth.Value;\r
+                updownParHeight.Value = text_width.Value;\r
+                _preventChangingCustom = false;\r
             }\r
 \r
-            switch (drp_anamorphic.SelectedIndex)\r
+            if (_preventChangingDisplayWidth == false && check_KeepAR.CheckState == CheckState.Checked)\r
             {\r
-                case 0:\r
-                    if (check_KeepAR.Checked)\r
-                    {\r
-                        _preventChangingWidth = true;\r
-\r
-                        decimal newWidth = text_height.Value * (decimal)_anamorphicRatio;\r
-                        text_width.Value = newWidth > MaximumWidth ? MaximumWidth : newWidth;\r
-\r
-                        _preventChangingWidth = false;\r
-                    }\r
-                    break;\r
-                case 3:\r
-                    ApplyCustomAnamorphic((Control)sender);\r
-                    break;\r
+                // - Changes HEIGHT to keep DAR\r
+                // - Changes PIXEL WIDTH to new DISPLAY WIDTH\r
+                // - Changes PIXEL HEIGHT to STORAGE WIDTH\r
+                // DAR = DISPLAY WIDTH / DISPLAY HEIGHT (cache after every modification)\r
+\r
+                // Calculate new Height Value\r
+                int modulus;\r
+                if(!int.TryParse(drp_modulus.SelectedItem.ToString(), out modulus))\r
+                    modulus = 16;\r
+\r
+                int rawCalculatedHeight = (int)((int)updownDisplayWidth.Value / _cachedDar);\r
+                int modulusHeight = rawCalculatedHeight - (rawCalculatedHeight % modulus);\r
+\r
+                // Update value\r
+                _preventChangingHeight = true;\r
+                text_height.Value = (decimal)modulusHeight;\r
+                updownParWidth.Value = updownDisplayWidth.Value;\r
+                updownParHeight.Value = text_width.Value;\r
+                _preventChangingHeight = false;\r
             }\r
 \r
-            _preventChangingHeight = false;\r
         }\r
 \r
+        // Anamorphic Controls\r
         private void drp_anamorphic_SelectedIndexChanged(object sender, EventArgs e)\r
         {\r
             switch (drp_anamorphic.SelectedIndex)\r
@@ -394,7 +300,12 @@ namespace Handbrake.Controls
                     labelDisplaySize.Visible = false;\r
 \r
                     check_KeepAR.Checked = true;\r
-                    break;\r
+                    drp_modulus.SelectedIndex = 0;\r
+\r
+                    if (check_KeepAR.Checked)\r
+                        text_width_ValueChanged(this, new EventArgs());\r
+                    // Don't update display size if we're not using anamorphic\r
+                    return;\r
                 case 1:\r
                     text_width.Enabled = false;\r
                     text_height.Enabled = false;\r
@@ -403,6 +314,7 @@ namespace Handbrake.Controls
                     SetCustomAnamorphicOptionsVisible(false);\r
                     labelStaticDisplaySize.Visible = true;\r
                     labelDisplaySize.Visible = true;\r
+                    drp_modulus.SelectedIndex = 0;\r
 \r
                     check_KeepAR.Checked = true;\r
                     break;\r
@@ -414,6 +326,7 @@ namespace Handbrake.Controls
                     SetCustomAnamorphicOptionsVisible(false);\r
                     labelStaticDisplaySize.Visible = true;\r
                     labelDisplaySize.Visible = true;\r
+                    drp_modulus.SelectedIndex = 0;\r
 \r
                     check_KeepAR.Checked = true;\r
                     break;\r
@@ -430,30 +343,33 @@ namespace Handbrake.Controls
                     break;\r
             }\r
 \r
-            UpdateAnamorphicValue();\r
-        }\r
+            labelDisplaySize.Text = CalculateAnamorphicSizes().Width + "x" + CalculateAnamorphicSizes().Height;\r
 \r
-        private void check_KeepAR_CheckedChanged(object sender, EventArgs e)\r
-        {\r
-            if (drp_anamorphic.SelectedIndex != 3)\r
-            {\r
-                if (check_KeepAR.Checked)\r
-                {\r
-                    text_width_ValueChanged(this, new EventArgs());\r
-                }\r
-            }\r
-            else\r
-            {\r
-                updownParWidth.Enabled = !check_KeepAR.Checked;\r
-                updownParHeight.Enabled = !check_KeepAR.Checked;\r
-            }\r
-        }\r
+            if (check_KeepAR.Checked)\r
+                text_width_ValueChanged(this, new EventArgs());\r
 \r
-        private void crop_ValueChanged(object sender, EventArgs e)\r
+            if (PictureSettingsChanged != null)\r
+                PictureSettingsChanged(this, new EventArgs());\r
+        }\r
+        private void drp_modulus_SelectedIndexChanged(object sender, EventArgs e)\r
         {\r
-            text_width_ValueChanged(this, new EventArgs());\r
+            _preventChangingWidth = true;\r
+            _preventChangingHeight = true;\r
+\r
+            text_width.Value = (decimal)GetModulusValue((double)text_width.Value);\r
+            text_height.Value = (decimal)GetModulusValue((double)text_height.Value);\r
+\r
+            _preventChangingWidth = false;\r
+            _preventChangingHeight = false;\r
+\r
+            text_width.Increment = int.Parse(drp_modulus.SelectedItem.ToString());\r
+            text_height.Increment = int.Parse(drp_modulus.SelectedItem.ToString());\r
+\r
+            if (PictureSettingsChanged != null)\r
+                PictureSettingsChanged(this, new EventArgs());\r
         }\r
 \r
+        // Cropping Controls\r
         private void check_autoCrop_CheckedChanged(object sender, EventArgs e)\r
         {\r
             crop_top.Enabled = check_customCrop.Checked;\r
@@ -461,11 +377,125 @@ namespace Handbrake.Controls
             crop_left.Enabled = check_customCrop.Checked;\r
             crop_right.Enabled = check_customCrop.Checked;\r
         }\r
+        private void crop_ValueChanged(object sender, EventArgs e)\r
+        {\r
+            text_width_ValueChanged(this, new EventArgs());\r
+        }\r
 \r
-        private void drp_modulus_SelectedIndexChanged(object sender, EventArgs e)\r
+        // GUI Functions\r
+        private void SetCustomAnamorphicOptionsVisible(bool visible)\r
         {\r
-            text_width.Increment = int.Parse(drp_modulus.SelectedItem.ToString());\r
-            text_height.Increment = int.Parse(drp_modulus.SelectedItem.ToString());\r
+            lbl_modulus.Visible = visible;\r
+            lbl_displayWidth.Visible = visible;\r
+            lbl_parWidth.Visible = visible;\r
+            lbl_parHeight.Visible = visible;\r
+\r
+            drp_modulus.Visible = visible;\r
+            updownDisplayWidth.Visible = visible;\r
+            updownParWidth.Visible = visible;\r
+            updownParHeight.Visible = visible;\r
+        }\r
+\r
+        // Calculation Functions\r
+        private Size SourceAspect\r
+        {\r
+            get\r
+            {\r
+                if (Source != null) // display aspect = (width * par_width) / (height * par_height)\r
+                    return new Size((Source.ParVal.Width * Source.Resolution.Width), (Source.ParVal.Height * Source.Resolution.Height));\r
+\r
+                return new Size(0, 0); // Fall over to 16:9 and hope for the best\r
+            }\r
+        }\r
+        private Size CalculateAnamorphicSizes()\r
+        {\r
+            if (Source != null)\r
+            {\r
+                /* Set up some variables to make the math easier to follow. */\r
+                int cropped_width = Source.Resolution.Width - (int)crop_left.Value - (int)crop_right.Value;\r
+                int cropped_height = Source.Resolution.Height - (int)crop_top.Value - (int)crop_bottom.Value;\r
+                double storage_aspect = (double)cropped_width / cropped_height;\r
+\r
+                /* Figure out what width the source would display at. */\r
+                double source_display_width = (double)cropped_width * Source.ParVal.Width / Source.ParVal.Height;\r
+\r
+                /*\r
+                     3 different ways of deciding output dimensions:\r
+                      - 1: Strict anamorphic, preserve source dimensions\r
+                      - 2: Loose anamorphic, round to mod16 and preserve storage aspect ratio\r
+                      - 3: Power user anamorphic, specify everything\r
+                  */\r
+                double width, height;\r
+                switch (drp_anamorphic.SelectedIndex)\r
+                {\r
+                    default:\r
+                    case 1:\r
+                        /* Strict anamorphic */\r
+                        double displayWidth = ((double)cropped_width * Source.ParVal.Width / Source.ParVal.Height);\r
+                        displayWidth = Math.Round(displayWidth, 0);\r
+                        Size output = new Size((int)displayWidth, cropped_height);\r
+                        return output;\r
+                    case 2:\r
+                        /* "Loose" anamorphic.\r
+                            - Uses mod16-compliant dimensions,\r
+                            - Allows users to set the width\r
+                        */\r
+                        width = (int)text_width.Value - (int)crop_left.Value - (int)crop_right.Value;\r
+                        width = GetModulusValue(width); /* Time to get picture width that divide cleanly.*/\r
+\r
+                        height = (width / storage_aspect) + 0.5;\r
+                        height = GetModulusValue(height); /* Time to get picture height that divide cleanly.*/\r
+\r
+                        /* The film AR is the source's display width / cropped source height.\r
+                           The output display width is the output height * film AR.\r
+                           The output PAR is the output display width / output storage width. */\r
+                        double pixel_aspect_width = height * source_display_width / cropped_height;\r
+                        double pixel_aspect_height = width;\r
+\r
+                        double disWidthLoose = (width * pixel_aspect_width / pixel_aspect_height);\r
+                        return new Size((int)disWidthLoose, (int)height);\r
+                    case 3:\r
+\r
+                        // Get the User Interface Values\r
+                        double UIdisplayWidth;\r
+                        double.TryParse(updownDisplayWidth.Text, out UIdisplayWidth);\r
+\r
+                        /* Anamorphic 3: Power User Jamboree - Set everything based on specified values */\r
+                        height = GetModulusValue((double)text_height.Value);\r
+\r
+                        if (check_KeepAR.Checked)\r
+                            return new Size((int)Math.Truncate(UIdisplayWidth), (int)height);\r
+\r
+                        return new Size((int)Math.Truncate(UIdisplayWidth), (int)height);\r
+                }\r
+            }\r
+\r
+            // Return a default value of 0,0 to indicate failure\r
+            return new Size(0, 0);\r
+        }\r
+        private double GetModulusValue(double value)\r
+        {\r
+            int mod = int.Parse(drp_modulus.SelectedItem.ToString());\r
+            double remainder = value % mod;\r
+\r
+            if (remainder == 0)\r
+                return value;\r
+\r
+            return remainder >= ((double)mod / 2) ? value + (mod - remainder) : value - remainder;\r
+        }\r
+        private static int GetCropMod2Clean(int value)\r
+        {\r
+            int remainder = value % 2;\r
+            if (remainder == 0) return value;\r
+            return (value + remainder);\r
+        }\r
+\r
+        // Hidden UI feature to drop the MaxWidth / Height with the MaxWidth/Height label is double clicked\r
+        private void lbl_max_DoubleClick(object sender, EventArgs e)\r
+        {\r
+            PresetMaximumResolution = new Size(0,0);\r
+            if (PictureSettingsChanged != null)\r
+                PictureSettingsChanged(this, new EventArgs());\r
         }\r
     }\r
-}\r
+}
\ No newline at end of file