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