OSDN Git Service

WinGui:
[handbrake-jp/handbrake-jp-git.git] / win / C# / Controls / PictureSettings.cs
1 /*  PictureSetting.cs $\r
2     This file is part of the HandBrake source code.\r
3     Homepage: <http://handbrake.fr>.\r
4     It may be used under the terms of the GNU General Public License. */\r
5 \r
6 namespace Handbrake.Controls\r
7 {\r
8     using System;\r
9     using System.Drawing;\r
10     using System.Globalization;\r
11     using System.Windows.Forms;\r
12 \r
13     using HandBrake.ApplicationServices.Parsing;\r
14 \r
15     using Presets;\r
16 \r
17     /// <summary>\r
18     /// The Picture Settings Panel\r
19     /// </summary>\r
20     public partial class PictureSettings : UserControl\r
21     {\r
22         private readonly CultureInfo culture = new CultureInfo("en-US", false);\r
23         private bool preventChangingWidth;\r
24         private bool preventChangingHeight;\r
25         private bool preventChangingCustom;\r
26         private bool preventChangingDisplayWidth;\r
27         private double cachedDar;\r
28         private Title sourceTitle;\r
29 \r
30         /// <summary>\r
31         /// Initializes a new instance of the <see cref="PictureSettings"/> class. \r
32         /// Creates a new instance of the Picture Settings Class\r
33         /// </summary>\r
34         public PictureSettings()\r
35         {\r
36             InitializeComponent();\r
37 \r
38             drp_anamorphic.SelectedIndex = 1;\r
39             drp_modulus.SelectedIndex = 0;\r
40         }\r
41 \r
42         /// <summary>\r
43         /// Picture Settings Changed Event Handler\r
44         /// </summary>\r
45         public event EventHandler PictureSettingsChanged;\r
46 \r
47         /// <summary>\r
48         /// Gets or sets the source media used by this control.\r
49         /// </summary>\r
50         public Title Source\r
51         {\r
52             private get\r
53             {\r
54                 return sourceTitle;\r
55             }\r
56 \r
57             set\r
58             {\r
59                 sourceTitle = value;\r
60                 Enabled = sourceTitle != null;\r
61                 NewSourceSet();\r
62             }\r
63         }\r
64 \r
65         /// <summary>\r
66         /// Gets or sets the currently selected preset.\r
67         /// </summary>\r
68         public Preset CurrentlySelectedPreset { get; set; }\r
69 \r
70         /// <summary>\r
71         /// Gets or sets the maximum allowable size for the encoded resolution. Set a value to\r
72         /// "0" if the maximum does not matter.\r
73         /// </summary>\r
74         public Size PresetMaximumResolution { get; set; }\r
75 \r
76         /// <summary>\r
77         /// Set the Preset Crop Warning Label\r
78         /// </summary>\r
79         /// <param name="selectedPreset">\r
80         /// The Selected preset\r
81         /// </param>\r
82         public void SetPresetCropWarningLabel(Preset selectedPreset)\r
83         {\r
84             lbl_presetCropWarning.Visible = true;\r
85             if (selectedPreset != null && selectedPreset.PictureSettings == false)\r
86                 lbl_presetCropWarning.Visible = false;\r
87             else if (selectedPreset == null)\r
88                 lbl_presetCropWarning.Visible = false;\r
89         }\r
90 \r
91         /// <summary>\r
92         /// Setup the UI. The Source has just changed.\r
93         /// </summary>\r
94         private void NewSourceSet()\r
95         {\r
96             // Set the Aspect Ratio\r
97             lbl_src_res.Text = sourceTitle.Resolution.Width + " x " + sourceTitle.Resolution.Height;\r
98 \r
99             // Set the Recommended Cropping values, but only if a preset doesn't have hard set picture settings.\r
100             if ((CurrentlySelectedPreset != null && CurrentlySelectedPreset.PictureSettings == false) || CurrentlySelectedPreset == null)\r
101             {\r
102                 crop_top.Value = GetCropMod2Clean(sourceTitle.AutoCropDimensions.Top);\r
103                 crop_bottom.Value = GetCropMod2Clean(sourceTitle.AutoCropDimensions.Bottom);\r
104                 crop_left.Value = GetCropMod2Clean(sourceTitle.AutoCropDimensions.Left);\r
105                 crop_right.Value = GetCropMod2Clean(sourceTitle.AutoCropDimensions.Right);\r
106             }\r
107 \r
108             SetPresetCropWarningLabel(CurrentlySelectedPreset);\r
109 \r
110             // Set the Resolution Boxes\r
111             if (drp_anamorphic.SelectedIndex == 0)\r
112             {\r
113                 int width = sourceTitle.Resolution.Width;\r
114 \r
115                 if (width > PresetMaximumResolution.Width && PresetMaximumResolution.Width != 0) // If the preset has a Max width set, don't use a width larger than it.\r
116                     width = PresetMaximumResolution.Width;\r
117 \r
118                 if (text_width.Value == 0 || (text_width.Value > PresetMaximumResolution.Width && PresetMaximumResolution.Width != 0)) // Only update the values if the fields don't already have values.\r
119                     text_width.Value = width;\r
120 \r
121                 check_KeepAR.Checked = true; // Forces Resolution to be correct.\r
122             }\r
123             else\r
124             {\r
125                 int width = sourceTitle.Resolution.Width;\r
126                 if (width > PresetMaximumResolution.Width && PresetMaximumResolution.Width != 0) // If the preset has a Max width set, don't use a width larger than it.\r
127                     width = PresetMaximumResolution.Width;\r
128 \r
129                 int height = sourceTitle.Resolution.Height;\r
130                 if (height > PresetMaximumResolution.Height && PresetMaximumResolution.Height != 0) // If the preset has a Max height set, don't use a width larger than it.\r
131                     height = PresetMaximumResolution.Height;\r
132 \r
133                 text_width.Value = width;\r
134                 text_height.Value = height - (int)crop_top.Value - (int)crop_bottom.Value;\r
135 \r
136                 labelDisplaySize.Text = CalculateAnamorphicSizes().Width + "x" + CalculateAnamorphicSizes().Height;\r
137             }\r
138 \r
139             updownParWidth.Value = sourceTitle.ParVal.Width;\r
140             updownParHeight.Value = sourceTitle.ParVal.Height;\r
141 \r
142             Size croppedDar = CalculateAnamorphicSizes();\r
143             cachedDar = (double)croppedDar.Width / croppedDar.Height;\r
144             updownDisplayWidth.Value = croppedDar.Width;\r
145         }\r
146 \r
147         // Picture Controls\r
148         private void TextWidthValueChanged(object sender, EventArgs e)\r
149         {\r
150             if (Properties.Settings.Default.disableResCalc)\r
151                 return;\r
152 \r
153             if (preventChangingWidth)\r
154                 return;\r
155 \r
156             // Make sure the new value doesn't exceed the maximum\r
157             if (Source != null)\r
158                 if (text_width.Value > Source.Resolution.Width)\r
159                     text_width.Value = Source.Resolution.Width;\r
160 \r
161             switch (drp_anamorphic.SelectedIndex)\r
162             {\r
163                 case 0:\r
164                     if (check_KeepAR.Checked && Source != null)\r
165                     {\r
166                         preventChangingHeight = true;\r
167 \r
168                         int width = (int)text_width.Value;\r
169 \r
170                         double crop_width = Source.Resolution.Width - (int)crop_left.Value - (int)crop_right.Value;\r
171                         double crop_height = Source.Resolution.Height - (int)crop_top.Value - (int)crop_bottom.Value;\r
172 \r
173                         if (SourceAspect.Width == 0 && SourceAspect.Height == 0)\r
174                             break;\r
175 \r
176                         double newHeight = ((double)width * Source.Resolution.Width * SourceAspect.Height * crop_height) /\r
177                                            (Source.Resolution.Height * SourceAspect.Width * crop_width);\r
178                         text_height.Value = (decimal)GetModulusValue(newHeight);\r
179 \r
180                         preventChangingHeight = false;\r
181                     }\r
182                     break;\r
183                 case 3:\r
184                     if (check_KeepAR.CheckState == CheckState.Unchecked && Source != null)\r
185                     {\r
186                         if (preventChangingCustom)\r
187                             break;\r
188 \r
189                         preventChangingDisplayWidth = true;\r
190                         updownDisplayWidth.Value = text_width.Value * updownParWidth.Value / updownParHeight.Value;\r
191                         preventChangingDisplayWidth = false;\r
192 \r
193                         labelDisplaySize.Text = Math.Truncate(updownDisplayWidth.Value) + "x" + text_height.Value;\r
194                     }\r
195 \r
196                     if (check_KeepAR.CheckState == CheckState.Checked && Source != null)\r
197                     {\r
198                         updownParWidth.Value = updownDisplayWidth.Value;\r
199                         updownParHeight.Value = text_width.Value;\r
200                     }\r
201                     break;\r
202                 default:\r
203                     labelDisplaySize.Text = CalculateAnamorphicSizes().Width + "x" + CalculateAnamorphicSizes().Height;\r
204                     break;\r
205             }\r
206 \r
207             preventChangingWidth = false;\r
208         }\r
209 \r
210         private void TextHeightValueChanged(object sender, EventArgs e)\r
211         {\r
212             if (Properties.Settings.Default.disableResCalc)\r
213                 return;\r
214 \r
215             if (preventChangingHeight)\r
216                 return;\r
217 \r
218             if (Source != null)\r
219                 if (text_height.Value > Source.Resolution.Height)\r
220                     text_height.Value = Source.Resolution.Height;\r
221 \r
222             switch (drp_anamorphic.SelectedIndex)\r
223             {\r
224                 case 0:\r
225                     if (check_KeepAR.Checked && Source != null)\r
226                     {\r
227                         preventChangingWidth = true;\r
228 \r
229                         double crop_width = Source.Resolution.Width - (int)crop_left.Value - (int)crop_right.Value;\r
230                         double crop_height = Source.Resolution.Height - (int)crop_top.Value - (int)crop_bottom.Value;\r
231 \r
232                         double new_width = ((double)text_height.Value * Source.Resolution.Height * SourceAspect.Width *\r
233                                             crop_width) /\r
234                                            (Source.Resolution.Width * SourceAspect.Height * crop_height);\r
235 \r
236                         text_width.Value = (decimal)GetModulusValue(new_width);\r
237 \r
238                         preventChangingWidth = false;\r
239                     }\r
240                     break;\r
241                 case 3:\r
242                     labelDisplaySize.Text = Math.Truncate(updownDisplayWidth.Value) + "x" + text_height.Value;\r
243 \r
244                     if (check_KeepAR.CheckState == CheckState.Checked && Source != null)\r
245                     {\r
246                         // - Changes DISPLAY WIDTH to keep DAR\r
247                         // - Changes PIXEL WIDTH to new DISPLAY WIDTH\r
248                         // - Changes PIXEL HEIGHT to STORAGE WIDTH\r
249                         // DAR = DISPLAY WIDTH / DISPLAY HEIGHT (cache after every modification)\r
250 \r
251                         double rawCalculatedDisplayWidth = (double)text_height.Value * cachedDar;\r
252 \r
253                         preventChangingDisplayWidth = true; // Start Guards\r
254                         preventChangingWidth = true;\r
255 \r
256                         updownDisplayWidth.Value = (decimal)rawCalculatedDisplayWidth;\r
257                         updownParWidth.Value = updownDisplayWidth.Value;\r
258                         updownParHeight.Value = text_width.Value;\r
259 \r
260                         preventChangingWidth = false; // Reset Guards\r
261                         preventChangingDisplayWidth = false;\r
262                     }\r
263 \r
264                     break;\r
265                 default:\r
266                     labelDisplaySize.Text = CalculateAnamorphicSizes().Width + "x" + CalculateAnamorphicSizes().Height;\r
267                     break;\r
268             }\r
269 \r
270             preventChangingHeight = false;\r
271         }\r
272 \r
273         private void CheckKeepArCheckedChanged(object sender, EventArgs e)\r
274         {\r
275             if (Properties.Settings.Default.disableResCalc)\r
276                 return;\r
277 \r
278             // Force TextWidth to recalc height\r
279             if (check_KeepAR.Checked)\r
280                 TextWidthValueChanged(this, new EventArgs());\r
281 \r
282             // Disable the Custom Anamorphic Par Controls if checked.\r
283             if (drp_anamorphic.SelectedIndex == 3)\r
284             {\r
285                 updownParWidth.Enabled = !check_KeepAR.Checked;\r
286                 updownParHeight.Enabled = !check_KeepAR.Checked;\r
287             }\r
288 \r
289             // Raise the Picture Settings Changed Event\r
290             if (PictureSettingsChanged != null)\r
291                 PictureSettingsChanged(this, new EventArgs());\r
292         }\r
293 \r
294         private void UpdownDisplayWidthValueChanged(object sender, EventArgs e)\r
295         {\r
296             if (Properties.Settings.Default.disableResCalc)\r
297                 return;\r
298 \r
299             if (preventChangingDisplayWidth == false && check_KeepAR.CheckState == CheckState.Unchecked)\r
300             {\r
301                 preventChangingCustom = true;\r
302                 updownParWidth.Value = updownDisplayWidth.Value;\r
303                 updownParHeight.Value = text_width.Value;\r
304                 preventChangingCustom = false;\r
305             }\r
306 \r
307             if (preventChangingDisplayWidth == false && check_KeepAR.CheckState == CheckState.Checked)\r
308             {\r
309                 // - Changes HEIGHT to keep DAR\r
310                 // - Changes PIXEL WIDTH to new DISPLAY WIDTH\r
311                 // - Changes PIXEL HEIGHT to STORAGE WIDTH\r
312                 // DAR = DISPLAY WIDTH / DISPLAY HEIGHT (cache after every modification)\r
313 \r
314                 // Calculate new Height Value\r
315                 int modulus;\r
316                 if (!int.TryParse(drp_modulus.SelectedItem.ToString(), out modulus))\r
317                     modulus = 16;\r
318 \r
319                 int rawCalculatedHeight = (int)((int)updownDisplayWidth.Value / cachedDar);\r
320                 int modulusHeight = rawCalculatedHeight - (rawCalculatedHeight % modulus);\r
321 \r
322                 // Update value\r
323                 preventChangingHeight = true;\r
324                 text_height.Value = (decimal)modulusHeight;\r
325                 updownParWidth.Value = updownDisplayWidth.Value;\r
326                 updownParHeight.Value = text_width.Value;\r
327                 preventChangingHeight = false;\r
328             }\r
329         }\r
330 \r
331         // Anamorphic Controls\r
332         private void DrpAnamorphicSelectedIndexChanged(object sender, EventArgs e)\r
333         {\r
334             switch (drp_anamorphic.SelectedIndex)\r
335             {\r
336                 case 0: // None\r
337                     text_width.Enabled = true;\r
338                     text_height.Enabled = true;\r
339                     check_KeepAR.Enabled = true;\r
340 \r
341                     SetCustomAnamorphicOptionsVisible(false);\r
342                     labelStaticDisplaySize.Visible = false;\r
343                     labelDisplaySize.Visible = false;\r
344                     drp_modulus.Visible = true;\r
345                     lbl_modulus.Visible = true;\r
346 \r
347                     // check_KeepAR.Checked = true;\r
348 \r
349                     if (check_KeepAR.Checked)\r
350                         TextWidthValueChanged(this, new EventArgs());\r
351                     // Don't update display size if we're not using anamorphic\r
352                     return;\r
353                 case 1: // Strict\r
354                     text_width.Enabled = false;\r
355                     text_height.Enabled = false;\r
356                     check_KeepAR.Enabled = false;\r
357 \r
358                     SetCustomAnamorphicOptionsVisible(false);\r
359                     labelStaticDisplaySize.Visible = true;\r
360                     labelDisplaySize.Visible = true;\r
361 \r
362                     check_KeepAR.Checked = true;\r
363                     break;\r
364                 case 2: // Loose\r
365                     text_width.Enabled = true;\r
366                     text_height.Enabled = false;\r
367                     check_KeepAR.Enabled = false;\r
368 \r
369                     SetCustomAnamorphicOptionsVisible(false);\r
370                     labelStaticDisplaySize.Visible = true;\r
371                     labelDisplaySize.Visible = true;\r
372                     drp_modulus.Visible = true;\r
373                     lbl_modulus.Visible = true;\r
374 \r
375                     check_KeepAR.Checked = true;\r
376                     break;\r
377                 case 3: // Custom\r
378                     text_width.Enabled = true;\r
379                     text_height.Enabled = true;\r
380                     check_KeepAR.Enabled = true;\r
381 \r
382                     SetCustomAnamorphicOptionsVisible(true);\r
383                     labelStaticDisplaySize.Visible = true;\r
384                     labelDisplaySize.Visible = true;\r
385 \r
386                     check_KeepAR.Checked = true;\r
387                     updownParWidth.Enabled = !check_KeepAR.Checked;\r
388                     updownParHeight.Enabled = !check_KeepAR.Checked;\r
389                     break;\r
390             }\r
391 \r
392             labelDisplaySize.Text = CalculateAnamorphicSizes().Width + "x" + CalculateAnamorphicSizes().Height;\r
393 \r
394             if (check_KeepAR.Checked)\r
395                 TextWidthValueChanged(this, new EventArgs());\r
396 \r
397             if (PictureSettingsChanged != null)\r
398                 PictureSettingsChanged(this, new EventArgs());\r
399         }\r
400 \r
401         private void DrpModulusSelectedIndexChanged(object sender, EventArgs e)\r
402         {\r
403             preventChangingWidth = true;\r
404             preventChangingHeight = true;\r
405 \r
406             text_width.Value = (decimal)GetModulusValue((double)text_width.Value);\r
407             text_height.Value = (decimal)GetModulusValue((double)text_height.Value);\r
408 \r
409             preventChangingWidth = false;\r
410             preventChangingHeight = false;\r
411 \r
412             text_width.Increment = int.Parse(drp_modulus.SelectedItem.ToString());\r
413             text_height.Increment = int.Parse(drp_modulus.SelectedItem.ToString());\r
414 \r
415             if (PictureSettingsChanged != null)\r
416                 PictureSettingsChanged(this, new EventArgs());\r
417         }\r
418 \r
419         // Cropping Controls\r
420         private void CheckAutoCropCheckedChanged(object sender, EventArgs e)\r
421         {\r
422             crop_top.Enabled = check_customCrop.Checked;\r
423             crop_bottom.Enabled = check_customCrop.Checked;\r
424             crop_left.Enabled = check_customCrop.Checked;\r
425             crop_right.Enabled = check_customCrop.Checked;\r
426 \r
427             if (Source != null)\r
428             {\r
429                 crop_top.Value = Source.AutoCropDimensions.Top;\r
430                 crop_bottom.Value = Source.AutoCropDimensions.Bottom;\r
431                 crop_left.Value = Source.AutoCropDimensions.Left;\r
432                 crop_right.Value = Source.AutoCropDimensions.Right;\r
433             }\r
434         }\r
435 \r
436         private void CropValueChanged(object sender, EventArgs e)\r
437         {\r
438             TextWidthValueChanged(this, new EventArgs());\r
439         }\r
440 \r
441         // GUI Functions\r
442         private void SetCustomAnamorphicOptionsVisible(bool visible)\r
443         {\r
444             lbl_modulus.Visible = visible;\r
445             lbl_displayWidth.Visible = visible;\r
446             lbl_parWidth.Visible = visible;\r
447             lbl_parHeight.Visible = visible;\r
448 \r
449             drp_modulus.Visible = visible;\r
450             updownDisplayWidth.Visible = visible;\r
451             updownParWidth.Visible = visible;\r
452             updownParHeight.Visible = visible;\r
453         }\r
454 \r
455         // Calculation Functions\r
456         private Size SourceAspect\r
457         {\r
458             get\r
459             {\r
460                 if (Source != null) // display aspect = (width * par_width) / (height * par_height)\r
461                     return new Size((Source.ParVal.Width * Source.Resolution.Width),\r
462                                     (Source.ParVal.Height * Source.Resolution.Height));\r
463 \r
464                 return new Size(0, 0); // Fall over to 16:9 and hope for the best\r
465             }\r
466         }\r
467 \r
468         private Size CalculateAnamorphicSizes()\r
469         {\r
470             if (Source != null)\r
471             {\r
472                 /* Set up some variables to make the math easier to follow. */\r
473                 int croppedWidth = Source.Resolution.Width - (int)crop_left.Value - (int)crop_right.Value;\r
474                 int croppedHeight = Source.Resolution.Height - (int)crop_top.Value - (int)crop_bottom.Value;\r
475                 double storageAspect = (double)croppedWidth / croppedHeight;\r
476 \r
477                 /* Figure out what width the source would display at. */\r
478                 double sourceDisplayWidth = (double)croppedWidth * Source.ParVal.Width / Source.ParVal.Height;\r
479 \r
480                 /*\r
481                      3 different ways of deciding output dimensions:\r
482                       - 1: Strict anamorphic, preserve source dimensions\r
483                       - 2: Loose anamorphic, round to mod16 and preserve storage aspect ratio\r
484                       - 3: Power user anamorphic, specify everything\r
485                   */\r
486                 double width, height;\r
487                 switch (drp_anamorphic.SelectedIndex)\r
488                 {\r
489                     default:\r
490                     case 1:\r
491                         /* Strict anamorphic */\r
492                         double displayWidth = ((double)croppedWidth * Source.ParVal.Width / Source.ParVal.Height);\r
493                         displayWidth = Math.Round(displayWidth, 0);\r
494                         Size output = new Size((int)displayWidth, croppedHeight);\r
495                         return output;\r
496                     case 2:\r
497                         /* "Loose" anamorphic.\r
498                             - Uses mod16-compliant dimensions,\r
499                             - Allows users to set the width\r
500                         */\r
501                         width = (int)text_width.Value;\r
502                         width = GetModulusValue(width); /* Time to get picture width that divide cleanly.*/\r
503 \r
504                         height = (width / storageAspect) + 0.5;\r
505                         height = GetModulusValue(height); /* Time to get picture height that divide cleanly.*/\r
506 \r
507                         /* The film AR is the source's display width / cropped source height.\r
508                            The output display width is the output height * film AR.\r
509                            The output PAR is the output display width / output storage width. */\r
510                         double pixelAspectWidth = height * sourceDisplayWidth / croppedHeight;\r
511                         double pixelAspectHeight = width;\r
512 \r
513                         double disWidthLoose = (width * pixelAspectWidth / pixelAspectHeight);\r
514                         if (double.IsNaN(disWidthLoose))\r
515                             disWidthLoose = 0;\r
516                         return new Size((int)disWidthLoose, (int)height);\r
517                     case 3:\r
518 \r
519                         // Get the User Interface Values\r
520                         double UIdisplayWidth;\r
521                         double.TryParse(updownDisplayWidth.Text, out UIdisplayWidth);\r
522 \r
523                         /* Anamorphic 3: Power User Jamboree - Set everything based on specified values */\r
524                         height = GetModulusValue((double)text_height.Value);\r
525 \r
526                         if (check_KeepAR.Checked)\r
527                             return new Size((int)Math.Truncate(UIdisplayWidth), (int)height);\r
528 \r
529                         return new Size((int)Math.Truncate(UIdisplayWidth), (int)height);\r
530                 }\r
531             }\r
532 \r
533             // Return a default value of 0,0 to indicate failure\r
534             return new Size(0, 0);\r
535         }\r
536 \r
537         private double GetModulusValue(double value)\r
538         {\r
539             int mod = int.Parse(drp_modulus.SelectedItem.ToString());\r
540             double remainder = value % mod;\r
541 \r
542             if (remainder == 0)\r
543                 return value;\r
544 \r
545             return remainder >= ((double)mod / 2) ? value + (mod - remainder) : value - remainder;\r
546         }\r
547 \r
548         private static int GetCropMod2Clean(int value)\r
549         {\r
550             int remainder = value % 2;\r
551             if (remainder == 0) return value;\r
552             return (value + remainder);\r
553         }\r
554     }\r
555 }