OSDN Git Service

MacGui: Fixed a warning.
[handbrake-jp/handbrake-jp-git.git] / macosx / HBAdvancedController.m
1 /* HBAdvancedController
2
3     This file is part of the HandBrake source code.
4     Homepage: <http://handbrake.fr/>.
5     It may be used under the terms of the GNU General Public License. */
6     
7 #import "HBAdvancedController.h"
8
9 @implementation HBAdvancedController
10
11 - (id)init
12 {
13     [super init];
14     [self loadMyNibFile];
15     
16     return self;
17 }
18
19 - (void) setView: (NSBox *) box
20 {
21     fOptionsBox = box;
22     [fOptionsBox setContentView:fX264optView];
23 }
24
25 - (BOOL) loadMyNibFile
26 {
27     if(![NSBundle loadNibNamed:@"AdvancedView" owner:self])
28     {
29         NSLog(@"Warning! Could not load myNib file.\n");
30         return NO;
31     }
32     
33     return YES;
34 }
35
36 - (NSString *) optionsString
37 {
38     return [fDisplayX264Options stringValue];
39 }
40
41 - (void) setOptions: (NSString *)string
42 {
43     [fDisplayX264Options setStringValue:string];
44     [self X264AdvancedOptionsSet:nil];
45 }
46
47 - (void) setHidden: (BOOL) hide
48 {
49     if(hide)
50     {
51         [fOptionsBox setContentView:fEmptyView];
52         [fX264optViewTitleLabel setStringValue: @"Only Used With The x264 (H.264) Codec"];
53     }
54     else
55     {
56         [fOptionsBox setContentView:fX264optView];
57         [fX264optViewTitleLabel setStringValue: @""];
58     }
59     return;
60 }
61
62  - (void) enableUI: (bool) b
63 {
64     unsigned i;
65     NSControl * controls[] =
66       { fX264optViewTitleLabel,fDisplayX264Options,fDisplayX264OptionsLabel,fX264optBframesLabel,
67         fX264optBframesPopUp,fX264optRefLabel,fX264optRefPopUp,fX264optNfpskipLabel,fX264optNfpskipSwitch,
68         fX264optNodctdcmtLabel,fX264optNodctdcmtSwitch,fX264optSubmeLabel,fX264optSubmePopUp,
69         fX264optTrellisLabel,fX264optTrellisPopUp,fX264optMixedRefsLabel,fX264optMixedRefsSwitch,
70         fX264optMotionEstLabel,fX264optMotionEstPopUp,fX264optMERangeLabel,fX264optMERangePopUp,
71         fX264optWeightBLabel,fX264optWeightBSwitch,fX264optBRDOLabel,fX264optBRDOSwitch,
72         fX264optBPyramidLabel,fX264optBPyramidSwitch,fX264optBiMELabel,fX264optBiMESwitch,
73         fX264optDirectPredLabel,fX264optDirectPredPopUp,fX264optDeblockLabel,fX264optAnalyseLabel,
74         fX264optAnalysePopUp,fX264opt8x8dctLabel,fX264opt8x8dctSwitch,fX264optCabacLabel,fX264optCabacSwitch,
75         fX264optAlphaDeblockPopUp,fX264optBetaDeblockPopUp};
76
77     for( i = 0; i < sizeof( controls ) / sizeof( NSControl * ); i++ )
78     {
79         if( [[controls[i] className] isEqualToString: @"NSTextField"] )
80         {
81             NSTextField * tf = (NSTextField *) controls[i];
82             if( ![tf isBezeled] )
83             {
84                 [tf setTextColor: b ? [NSColor controlTextColor] :
85                     [NSColor disabledControlTextColor]];
86                 continue;
87             }
88         }
89         [controls[i] setEnabled: b];
90
91     }
92     
93     [fX264optView setWantsLayer:YES];
94 }
95
96 - (void)dealloc
97 {
98     [super dealloc];
99 }
100
101 /**
102  * Populates the option widgets
103  */
104 - (IBAction) X264AdvancedOptionsSet: (id) sender
105 {
106     /*Set opt widget values here*/
107     
108     /*B-Frames fX264optBframesPopUp*/
109     int i;
110     [fX264optBframesPopUp removeAllItems];
111     [fX264optBframesPopUp addItemWithTitle:@"Default (0)"];
112     for (i=0; i<17;i++)
113     {
114         [fX264optBframesPopUp addItemWithTitle:[NSString stringWithFormat:@"%d",i]];
115     }
116     
117     /*Reference Frames fX264optRefPopUp*/
118     [fX264optRefPopUp removeAllItems];
119     [fX264optRefPopUp addItemWithTitle:@"Default (1)"];
120     for (i=0; i<17;i++)
121     {
122         [fX264optRefPopUp addItemWithTitle:[NSString stringWithFormat:@"%d",i]];
123     }
124     
125     /*No Fast P-Skip fX264optNfpskipSwitch BOOLEAN*/
126     [fX264optNfpskipSwitch setState:0];
127     
128     /*No Dict Decimate fX264optNodctdcmtSwitch BOOLEAN*/
129     [fX264optNodctdcmtSwitch setState:0];    
130     
131     /*Sub Me fX264optSubmePopUp*/
132     [fX264optSubmePopUp removeAllItems];
133     [fX264optSubmePopUp addItemWithTitle:@"Default (4)"];
134     for (i=0; i<8;i++)
135     {
136         [fX264optSubmePopUp addItemWithTitle:[NSString stringWithFormat:@"%d",i]];
137     }
138     
139     /*Trellis fX264optTrellisPopUp*/
140     [fX264optTrellisPopUp removeAllItems];
141     [fX264optTrellisPopUp addItemWithTitle:@"Default (0)"];
142     for (i=0; i<3;i++)
143     {
144         [fX264optTrellisPopUp addItemWithTitle:[NSString stringWithFormat:@"%d",i]];
145     }
146     [fX264optTrellisPopUp setWantsLayer:YES];
147     
148     /*Mixed-references fX264optMixedRefsSwitch BOOLEAN*/
149     [fX264optMixedRefsSwitch setState:0];
150     [fX264optMixedRefsSwitch setWantsLayer:YES];
151     
152     /*Motion Estimation fX264optMotionEstPopUp*/
153     [fX264optMotionEstPopUp removeAllItems];
154     [fX264optMotionEstPopUp addItemWithTitle:@"Default (Hexagon)"];
155     [fX264optMotionEstPopUp addItemWithTitle:@"Diamond"];
156     [fX264optMotionEstPopUp addItemWithTitle:@"Hexagon"];
157     [fX264optMotionEstPopUp addItemWithTitle:@"Uneven Multi-Hexagon"];
158     [fX264optMotionEstPopUp addItemWithTitle:@"Exhaustive"];
159     
160     /*Motion Estimation range fX264optMERangePopUp*/
161     [fX264optMERangePopUp removeAllItems];
162     [fX264optMERangePopUp addItemWithTitle:@"Default (16)"];
163     for (i=4; i<65;i++)
164     {
165         [fX264optMERangePopUp addItemWithTitle:[NSString stringWithFormat:@"%d",i]];
166     }
167     
168     /*Weighted B-Frame Prediction fX264optWeightBSwitch BOOLEAN*/
169     [fX264optWeightBSwitch setState:0];
170     [fX264optWeightBSwitch setWantsLayer:YES];
171     
172     /*B-Frame Rate Distortion Optimization fX264optBRDOSwitch BOOLEAN*/
173     [fX264optBRDOSwitch setState:0];
174     [fX264optBRDOSwitch setWantsLayer:YES];
175     
176     /*B-frame Pyramids fX264optBPyramidSwitch BOOLEAN*/
177     [fX264optBPyramidSwitch setState:0];
178     [fX264optBPyramidSwitch setWantsLayer:YES];
179     
180     /*Bidirectional Motion Estimation Refinement fX264optBiMESwitch BOOLEAN*/
181     [fX264optBiMESwitch setState:0];
182     [fX264optBiMESwitch setWantsLayer:YES];
183     
184     /*Direct B-Frame Prediction Mode fX264optDirectPredPopUp*/
185     [fX264optDirectPredPopUp removeAllItems];
186     [fX264optDirectPredPopUp addItemWithTitle:@"Default (Spatial)"];
187     [fX264optDirectPredPopUp addItemWithTitle:@"None"];
188     [fX264optDirectPredPopUp addItemWithTitle:@"Spatial"];
189     [fX264optDirectPredPopUp addItemWithTitle:@"Temporal"];
190     [fX264optDirectPredPopUp addItemWithTitle:@"Automatic"];
191     [fX264optDirectPredPopUp setWantsLayer:YES];
192     
193     /*Alpha Deblock*/
194     [fX264optAlphaDeblockPopUp removeAllItems];
195     [fX264optAlphaDeblockPopUp addItemWithTitle:@"Default (0)"];
196     for (i=-6; i<7;i++)
197     {
198         [fX264optAlphaDeblockPopUp addItemWithTitle:[NSString stringWithFormat:@"%d",i]];
199     }
200
201     /*Beta Deblock*/
202     [fX264optBetaDeblockPopUp removeAllItems];
203     [fX264optBetaDeblockPopUp addItemWithTitle:@"Default (0)"];
204     for (i=-6; i<7;i++)
205     {
206         [fX264optBetaDeblockPopUp addItemWithTitle:[NSString stringWithFormat:@"%d",i]];
207     }
208
209     /* Analysis fX264optAnalysePopUp */
210     [fX264optAnalysePopUp removeAllItems];
211     [fX264optAnalysePopUp addItemWithTitle:@"Default (some)"]; /* 0=default */
212     [fX264optAnalysePopUp addItemWithTitle:[NSString stringWithFormat:@"None"]]; /* 1=none */
213     [fX264optAnalysePopUp addItemWithTitle:[NSString stringWithFormat:@"All"]]; /* 2=all */
214
215     /* 8x8 DCT fX264op8x8dctSwitch */
216     [fX264opt8x8dctSwitch setState:0];
217     [fX264opt8x8dctSwitch setWantsLayer:YES];
218
219     /* CABAC fX264opCabacSwitch */
220     [fX264optCabacSwitch setState:1];
221
222     /* Standardize the option string */
223     [self X264AdvancedOptionsStandardizeOptString:nil];
224
225     /* Set Current GUI Settings based on newly standardized string */
226     [self X264AdvancedOptionsSetCurrentSettings:nil];
227
228     /* Fade out options that don't apply */
229     [self X264AdvancedOptionsAnimate: sender];
230 }
231
232 /**
233  * Cleans the option string to use a standard format of option=value
234  */
235 - (IBAction) X264AdvancedOptionsStandardizeOptString: (id) sender
236 {
237     /* Set widgets depending on the opt string in field */
238     NSString * thisOpt; // The separated option such as "bframes=3"
239     NSString * optName = @""; // The option name such as "bframes"
240     NSString * optValue = @"";// The option value such as "3"
241     NSString * changedOptString = @"";
242     NSArray *currentOptsArray;
243     
244     /*First, we get an opt string to process */
245     NSString *currentOptString = [fDisplayX264Options stringValue];
246     
247     /* Verify there is an opt string to process by making sure an
248        option is getting its value set. If so, start to process it. */
249     NSRange currentOptRange = [currentOptString rangeOfString:@"="];
250     if (currentOptRange.location != NSNotFound)
251     {
252         /*Put individual options into an array based on the ":" separator for processing, result is "<opt>=<value>"*/
253         currentOptsArray = [currentOptString componentsSeparatedByString:@":"];
254         
255         /*iterate through the array and get <opts> and <values*/
256         int loopcounter;
257         int currentOptsArrayCount = [currentOptsArray count];
258         for (loopcounter = 0; loopcounter < currentOptsArrayCount; loopcounter++)
259         {
260             thisOpt = [currentOptsArray objectAtIndex:loopcounter];
261             
262             NSRange splitOptRange = [thisOpt rangeOfString:@"="];
263             if (splitOptRange.location != NSNotFound)
264             {
265                 optName = [thisOpt substringToIndex:splitOptRange.location];
266                 optValue = [thisOpt substringFromIndex:splitOptRange.location + 1];
267                 
268                 /* Standardize the names here depending on whats in the string */
269                 optName = [self X264AdvancedOptionsStandardizeOptNames:optName];
270                 thisOpt = [NSString stringWithFormat:@"%@=%@",optName,optValue];    
271             }
272             else // No value given so we use a default of "1"
273             {
274                 optName = thisOpt;
275
276                 /* Standardize the names here depending on whats in the string */
277                 optName = [self X264AdvancedOptionsStandardizeOptNames:optName];
278                 thisOpt = [NSString stringWithFormat:@"%@=%d",optName,1];
279             }
280             
281             /* Construct New String for opts here.*/
282             if ([thisOpt isEqualToString:@""])
283             {
284                 /* Blank option, just add it to the string. (Why?) */
285                 changedOptString = [NSString stringWithFormat:@"%@%@",changedOptString,thisOpt];
286             }
287             else
288             {
289                 if ([changedOptString isEqualToString:@""])
290                 {
291                     /* Blank string, output the current option. */
292                     changedOptString = [NSString stringWithFormat:@"%@",thisOpt];
293                 }
294                 else
295                 {
296                     /* Option exists and string exists, so append the option
297                        to the string with a semi-colon inbetween them.       */
298                     changedOptString = [NSString stringWithFormat:@"%@:%@",changedOptString,thisOpt];
299                 }
300             }
301         }
302     }
303     
304     /* Change the option string to reflect the new standardized option string */
305     [fDisplayX264Options setStringValue:[NSString stringWithFormat:changedOptString]];
306 }
307
308 /**
309  * Cleans the option string to use a standard set of option names, by conflating synonyms.
310  */
311 - (NSString *) X264AdvancedOptionsStandardizeOptNames:(NSString *) cleanOptNameString
312 {
313     /* Reference Frames */
314     if ([cleanOptNameString isEqualToString:@"ref"] || [cleanOptNameString isEqualToString:@"frameref"])
315     {
316         cleanOptNameString = @"ref";
317     }
318     
319     /*No Fast PSkip nofast_pskip*/
320     if ([cleanOptNameString isEqualToString:@"no-fast-pskip"] || [cleanOptNameString isEqualToString:@"no_fast_pskip"] || [cleanOptNameString isEqualToString:@"nofast_pskip"])
321     {
322         cleanOptNameString = @"no-fast-pskip";
323     }
324     
325     /*No Dict Decimate*/
326     if ([cleanOptNameString isEqualToString:@"no-dct-decimate"] || [cleanOptNameString isEqualToString:@"no_dct_decimate"] || [cleanOptNameString isEqualToString:@"nodct_decimate"])
327     {
328         cleanOptNameString = @"no-dct-decimate";
329     }
330     
331     /*Subme*/
332     if ([cleanOptNameString isEqualToString:@"subme"])
333     {
334         cleanOptNameString = @"subq";
335     }
336     
337     /*ME Range*/
338     if ([cleanOptNameString isEqualToString:@"me-range"] || [cleanOptNameString isEqualToString:@"me_range"])
339         cleanOptNameString = @"merange";
340     
341     /*WeightB*/
342     if ([cleanOptNameString isEqualToString:@"weight-b"] || [cleanOptNameString isEqualToString:@"weight_b"])
343     {
344         cleanOptNameString = @"weightb";
345     }
346     
347     /*BRDO*/
348     if ([cleanOptNameString isEqualToString:@"b-rdo"] || [cleanOptNameString isEqualToString:@"b_rdo"])
349     {
350         cleanOptNameString = @"brdo";
351     }
352     
353     /*B Pyramid*/
354     if ([cleanOptNameString isEqualToString:@"b_pyramid"])
355     {
356         cleanOptNameString = @"b-pyramid";
357     }
358     
359     /*Direct Prediction*/
360     if ([cleanOptNameString isEqualToString:@"direct-pred"] || [cleanOptNameString isEqualToString:@"direct_pred"])
361     {
362         cleanOptNameString = @"direct";
363     }
364     
365     /*Deblocking*/
366     if ([cleanOptNameString isEqualToString:@"filter"])
367     {
368         cleanOptNameString = @"deblock";
369     }
370     
371     /*Analysis*/
372     if ([cleanOptNameString isEqualToString:@"partitions"])
373     {
374         cleanOptNameString = @"analyse";
375     }
376     
377     return cleanOptNameString;    
378 }
379
380 /**
381  * Fades options in and out depending on whether they're available..
382  */
383 - (IBAction) X264AdvancedOptionsAnimate: (id) sender
384 {
385     /* Lots of situations to cover.
386        - B-frames (when 0 turn of b-frame specific stuff, when < 2 disable b-pyramid)
387        - CABAC (when 0 turn off trellis)
388        - subme  (if under 6 turn off brdo)
389        - analysis (if none, turn off 8x8dct and direct pred)
390        - refs (under 2, disable mixed-refs)
391     */
392     
393     if ( [fX264optBframesPopUp indexOfSelectedItem ] < 2)
394     {
395         /* If the b-frame widget is at 0 or 1, the user has chosen
396            not to use b-frames at all. So disable the options
397            that can only be used when b-frames are enabled.        */
398         [[fX264optWeightBSwitch animator] setHidden:YES];
399         [[fX264optWeightBLabel animator] setHidden:YES];
400         if ( [fX264optWeightBSwitch state] == 1 && sender != fX264optWeightBSwitch && sender != fX264optBRDOSwitch && sender != fX264optBPyramidSwitch && sender != fX264optBiMESwitch && sender != fX264optDirectPredPopUp)
401             [fX264optWeightBSwitch performClick:self];
402         
403         [[fX264optBRDOSwitch animator] setHidden:YES];
404         [[fX264optBRDOLabel animator] setHidden:YES];
405         if ( [fX264optBRDOSwitch state] == 1 && sender != fX264optWeightBSwitch && sender != fX264optBRDOSwitch && sender != fX264optBPyramidSwitch && sender != fX264optBiMESwitch && sender != fX264optDirectPredPopUp)
406             [fX264optBRDOSwitch performClick:self];
407
408         [[fX264optBPyramidSwitch animator] setHidden:YES];
409         [[fX264optBPyramidLabel animator] setHidden:YES];
410         if ( [fX264optBPyramidSwitch state] == 1 && sender != fX264optWeightBSwitch && sender != fX264optBRDOSwitch && sender != fX264optBPyramidSwitch && sender != fX264optBiMESwitch && sender != fX264optDirectPredPopUp)
411             [fX264optBPyramidSwitch performClick:self];
412
413         [[fX264optBiMESwitch animator] setHidden:YES];
414         [[fX264optBiMELabel animator] setHidden:YES];
415         if ( [fX264optBiMESwitch state] == 1 && sender != fX264optWeightBSwitch && sender != fX264optBRDOSwitch && sender != fX264optBPyramidSwitch && sender != fX264optBiMESwitch && sender != fX264optDirectPredPopUp)
416             [fX264optBiMESwitch performClick:self];
417
418         [[fX264optDirectPredPopUp animator] setHidden:YES];
419         [[fX264optDirectPredLabel animator] setHidden:YES];
420         [fX264optDirectPredPopUp selectItemAtIndex: 0];        
421         if ( [fX264optDirectPredPopUp indexOfSelectedItem] > 1 && sender != fX264optWeightBSwitch && sender != fX264optBRDOSwitch && sender != fX264optBPyramidSwitch && sender != fX264optBiMESwitch && sender != fX264optDirectPredPopUp)
422             [[fX264optDirectPredPopUp cell] performClick:self];
423     }
424     else if ( [fX264optBframesPopUp indexOfSelectedItem ] == 2)
425     {
426         /* Only 1 b-frame? Disable b-pyramid. */
427         [[fX264optBPyramidSwitch animator] setHidden:YES];
428         [[fX264optBPyramidLabel animator] setHidden:YES];
429         if ( [fX264optBPyramidSwitch state] == 1 && sender != fX264optBPyramidSwitch)
430             [fX264optBPyramidSwitch performClick:self];
431
432         [[fX264optWeightBSwitch animator] setHidden:NO];
433         [[fX264optWeightBLabel animator] setHidden:NO];
434
435         [[fX264optBiMESwitch animator] setHidden:NO];
436         [[fX264optBiMELabel animator] setHidden:NO];
437                 
438         if ( [fX264optSubmePopUp indexOfSelectedItem] >= 7)
439         {
440             /* Only show B-RDO if both bframes and subme allow it. */
441             [[fX264optBRDOSwitch animator] setHidden:NO];
442             [[fX264optBRDOLabel animator] setHidden:NO];
443         }
444         
445         if ( [fX264optAnalysePopUp indexOfSelectedItem] != 1)
446         {
447             /* Only show direct pred when allowed by both bframes and analysis.*/
448             [[fX264optDirectPredPopUp animator] setHidden:NO];
449             [[fX264optDirectPredLabel animator] setHidden:NO];
450         }
451     }
452     else
453     {
454         [[fX264optWeightBSwitch animator] setHidden:NO];
455         [[fX264optWeightBLabel animator] setHidden:NO];
456
457         [[fX264optBPyramidSwitch animator] setHidden:NO];
458         [[fX264optBPyramidLabel animator] setHidden:NO];
459
460         [[fX264optBiMESwitch animator] setHidden:NO];
461         [[fX264optBiMELabel animator] setHidden:NO];
462
463         if ( [fX264optSubmePopUp indexOfSelectedItem] >= 7)
464         {
465             /* Only show B-RDO if both bframes and subme allow it. */
466             [[fX264optBRDOSwitch animator] setHidden:NO];
467             [[fX264optBRDOLabel animator] setHidden:NO];
468         }
469
470         if ( [fX264optAnalysePopUp indexOfSelectedItem] != 1)
471         {
472             /* Only show direct pred when allowed by both bframes and analysis.*/
473             [[fX264optDirectPredPopUp animator] setHidden:NO];
474             [[fX264optDirectPredLabel animator] setHidden:NO];
475         }
476     }
477     
478     if ( [fX264optCabacSwitch state] == false)
479     {
480         /* Without CABAC entropy coding, trellis doesn't run. */
481         
482         [[fX264optTrellisPopUp animator] setHidden:YES];
483         [[fX264optTrellisLabel animator] setHidden:YES];
484         [fX264optTrellisPopUp selectItemAtIndex:0];
485         if (sender != fX264optTrellisPopUp)
486             [[fX264optTrellisPopUp cell] performClick:self];
487     }
488     else
489     {
490         [[fX264optTrellisPopUp animator] setHidden:NO];
491         [[fX264optTrellisLabel animator] setHidden:NO];
492     }
493     
494     if ( [fX264optSubmePopUp indexOfSelectedItem] < 7)
495     {
496         /* When subme < 6, B-RDO doesn't work. */
497         [[fX264optBRDOSwitch animator] setHidden:YES];
498         [[fX264optBRDOLabel animator] setHidden:YES];
499         if ( [fX264optBRDOSwitch state] == 1 && sender != fX264optBRDOSwitch )
500             [fX264optBRDOSwitch performClick:self];
501     }
502     else if ( [fX264optBframesPopUp indexOfSelectedItem ] >= 2 )
503     {
504         /* Make sure to only display B-RDO if allowed by both
505            the subme and bframe option settings.               */
506         [[fX264optBRDOSwitch animator] setHidden:NO]; 
507         [[fX264optBRDOLabel animator] setHidden:NO]; 
508     }
509     
510     if ( [fX264optAnalysePopUp indexOfSelectedItem] == 1)
511     {
512         /* No analysis? Disable 8x8dct and direct pred */
513         [[fX264opt8x8dctSwitch animator] setHidden:YES];
514         [[fX264opt8x8dctLabel animator] setHidden:YES];
515         if ( [fX264opt8x8dctSwitch state] == 1 && sender != fX264opt8x8dctSwitch )
516             [fX264opt8x8dctSwitch performClick:self];
517
518         [[fX264optDirectPredPopUp animator] setHidden:YES];
519         [[fX264optDirectPredLabel animator] setHidden:YES];
520         [fX264optDirectPredPopUp selectItemAtIndex: 0];        
521         if ( [fX264optDirectPredPopUp indexOfSelectedItem] > 1 && sender != fX264optDirectPredPopUp)
522             [[fX264optDirectPredPopUp cell] performClick:self];
523     }
524     else
525     {
526         [[fX264opt8x8dctSwitch animator] setHidden:NO];
527         [[fX264opt8x8dctLabel animator] setHidden:NO];
528
529         if ( [fX264optBframesPopUp indexOfSelectedItem ] >= 2)
530         {
531             /* Onlt show direct pred when allowed by both analysis and bframes */
532             [[fX264optDirectPredPopUp animator] setHidden:NO];
533             [[fX264optDirectPredLabel animator] setHidden:NO];
534         }
535     }
536     
537     if ( [fX264optRefPopUp indexOfSelectedItem] < 3)
538     {
539         /* Only do mixed-refs when there are at least 2 refs to mix. */
540         [[fX264optMixedRefsSwitch animator] setHidden:YES];
541         [[fX264optMixedRefsLabel animator] setHidden:YES];
542         if ( [fX264optMixedRefsSwitch state] == 1 && sender != fX264optMixedRefsSwitch )
543             [fX264optMixedRefsSwitch performClick:self];
544     }
545     else
546     {
547         [[fX264optMixedRefsSwitch animator] setHidden:NO];
548         [[fX264optMixedRefsLabel animator] setHidden:NO];
549     }
550 }
551
552 /**
553  * Resets the GUI widgets to the contents of the option string.
554  */
555 - (IBAction) X264AdvancedOptionsSetCurrentSettings: (id) sender
556 {
557     /* Set widgets depending on the opt string in field */
558     NSString * thisOpt; // The separated option such as "bframes=3"
559     NSString * optName = @""; // The option name such as "bframes"
560     NSString * optValue = @"";// The option value such as "3"
561     NSArray *currentOptsArray;
562     
563     /*First, we get an opt string to process */
564     NSString *currentOptString = [fDisplayX264Options stringValue];
565     
566     /* Verify there is an opt string to process by making sure an
567        option is getting its value set. If so, start to process it. */
568     NSRange currentOptRange = [currentOptString rangeOfString:@"="];
569     if (currentOptRange.location != NSNotFound)
570     {
571         /*Put individual options into an array based on the ":" separator for processing, result is "<opt>=<value>"*/
572         currentOptsArray = [currentOptString componentsSeparatedByString:@":"];
573         
574         /*iterate through the array and get <opts> and <values*/
575         int loopcounter;
576         int currentOptsArrayCount = [currentOptsArray count];
577         for (loopcounter = 0; loopcounter < currentOptsArrayCount; loopcounter++)
578         {
579             thisOpt = [currentOptsArray objectAtIndex:loopcounter];
580             
581             /* Verify the option sets a value */
582             NSRange splitOptRange = [thisOpt rangeOfString:@"="];            
583             if (splitOptRange.location != NSNotFound)
584             {
585                 /* Split thisOpt into an optName setting an optValue. */
586                 optName = [thisOpt substringToIndex:splitOptRange.location];
587                 optValue = [thisOpt substringFromIndex:splitOptRange.location + 1];
588                 
589                 /*Run through the available widgets for x264 opts and set them, as you add widgets, 
590                     they need to be added here. This should be moved to its own method probably*/
591                 
592                 /*bframes NSPopUpButton*/
593                 if ([optName isEqualToString:@"bframes"])
594                 {
595                     [fX264optBframesPopUp selectItemAtIndex:[optValue intValue]+1];
596                 }
597                 /*ref NSPopUpButton*/
598                 if ([optName isEqualToString:@"ref"])
599                 {
600                     [fX264optRefPopUp selectItemAtIndex:[optValue intValue]+1];
601                 }
602                 /*No Fast PSkip NSButton*/
603                 if ([optName isEqualToString:@"no-fast-pskip"])
604                 {
605                     [fX264optNfpskipSwitch setState:[optValue intValue]];
606                 }
607                 /*No Dict Decimate NSButton*/
608                 if ([optName isEqualToString:@"no-dct-decimate"])
609                 {
610                     [fX264optNodctdcmtSwitch setState:[optValue intValue]];
611                 }
612                 /*Sub Me NSPopUpButton*/
613                 if ([optName isEqualToString:@"subq"])
614                 {
615                     [fX264optSubmePopUp selectItemAtIndex:[optValue intValue]+1];
616                 }
617                 /*Trellis NSPopUpButton*/
618                 if ([optName isEqualToString:@"trellis"])
619                 {
620                     [fX264optTrellisPopUp selectItemAtIndex:[optValue intValue]+1];
621                 }
622                 /*Mixed Refs NSButton*/
623                 if ([optName isEqualToString:@"mixed-refs"])
624                 {
625                     [fX264optMixedRefsSwitch setState:[optValue intValue]];
626                 }
627                 /*Motion Estimation NSPopUpButton*/
628                 if ([optName isEqualToString:@"me"])
629                 {
630                     if ([optValue isEqualToString:@"dia"])
631                         [fX264optMotionEstPopUp selectItemAtIndex:1];
632                     else if ([optValue isEqualToString:@"hex"])
633                         [fX264optMotionEstPopUp selectItemAtIndex:2];
634                     else if ([optValue isEqualToString:@"umh"])
635                         [fX264optMotionEstPopUp selectItemAtIndex:3];
636                     else if ([optValue isEqualToString:@"esa"])
637                         [fX264optMotionEstPopUp selectItemAtIndex:4];                        
638                 }
639                 /*ME Range NSPopUpButton*/
640                 if ([optName isEqualToString:@"merange"])
641                 {
642                     [fX264optMERangePopUp selectItemAtIndex:[optValue intValue]-3];
643                 }
644                 /*Weighted B-Frames NSButton*/
645                 if ([optName isEqualToString:@"weightb"])
646                 {
647                     [fX264optWeightBSwitch setState:[optValue intValue]];
648                 }
649                 /*BRDO NSButton*/
650                 if ([optName isEqualToString:@"brdo"])
651                 {
652                     [fX264optBRDOSwitch setState:[optValue intValue]];
653                 }
654                 /*B Pyramid NSPButton*/
655                 if ([optName isEqualToString:@"b-pyramid"])
656                 {
657                     [fX264optBPyramidSwitch setState:[optValue intValue]];
658                 }
659                 /*Bidirectional Motion Estimation Refinement NSButton*/
660                 if ([optName isEqualToString:@"bime"])
661                 {
662                     [fX264optBiMESwitch setState:[optValue intValue]];
663                 }
664                 /*Direct B-frame Prediction NSPopUpButton*/
665                 if ([optName isEqualToString:@"direct"])
666                 {
667                     if ([optValue isEqualToString:@"none"])
668                         [fX264optDirectPredPopUp selectItemAtIndex:1];
669                     else if ([optValue isEqualToString:@"spatial"])
670                         [fX264optDirectPredPopUp selectItemAtIndex:2];
671                     else if ([optValue isEqualToString:@"temporal"])
672                         [fX264optDirectPredPopUp selectItemAtIndex:3];
673                     else if ([optValue isEqualToString:@"auto"])
674                         [fX264optDirectPredPopUp selectItemAtIndex:4];                        
675                 }
676                 /*Deblocking NSPopUpButtons*/
677                 if ([optName isEqualToString:@"deblock"])
678                 {
679                     NSString * alphaDeblock = @"";
680                     NSString * betaDeblock = @"";
681                     
682                     NSRange splitDeblock = [optValue rangeOfString:@","];
683                     alphaDeblock = [optValue substringToIndex:splitDeblock.location];
684                     betaDeblock = [optValue substringFromIndex:splitDeblock.location + 1];
685                     
686                     if ([alphaDeblock isEqualToString:@"0"] && [betaDeblock isEqualToString:@"0"])
687                     {
688                         /* When both filters are at 0, default */
689                         [fX264optAlphaDeblockPopUp selectItemAtIndex:0];                        
690                         [fX264optBetaDeblockPopUp selectItemAtIndex:0];                               
691                     }
692                     else
693                     {
694                         if (![alphaDeblock isEqualToString:@"0"])
695                         {
696                             /* Alpha isn't 0, so set it. The offset of 7 is
697                                because filters start at -6 instead of at 0. */
698                             [fX264optAlphaDeblockPopUp selectItemAtIndex:[alphaDeblock intValue]+7];
699                         }
700                         else
701                         {
702                             /* Set alpha filter to 0, which is 7 up
703                                because filters start at -6, not 0. */
704                             [fX264optAlphaDeblockPopUp selectItemAtIndex:7];                        
705                         }
706                         
707                         if (![betaDeblock isEqualToString:@"0"])
708                         {
709                             /* Beta isn't 0, so set it. */
710                             [fX264optBetaDeblockPopUp selectItemAtIndex:[betaDeblock intValue]+7];
711                         }
712                         else
713                         {
714                             /* Set beta filter to 0. */
715                             [fX264optBetaDeblockPopUp selectItemAtIndex:7];                        
716                         }
717                     }
718                 }
719                 /* Analysis NSPopUpButton */
720                 if ([optName isEqualToString:@"analyse"])
721                 {
722                     if ([optValue isEqualToString:@"p8x8,b8x8,i8x8,i4x4"])
723                     {
724                         /* Default ("some") */
725                         [fX264optAnalysePopUp selectItemAtIndex:0];
726                     }
727                     if ([optValue isEqualToString:@"none"])
728                     {
729                         [fX264optAnalysePopUp selectItemAtIndex:1];
730                     }
731                     if ([optValue isEqualToString:@"all"])
732                     {
733                         [fX264optAnalysePopUp selectItemAtIndex:2];
734                     }
735                 }
736                 /* 8x8 DCT NSButton */
737                 if ([optName isEqualToString:@"8x8dct"])
738                 {
739                     [fX264opt8x8dctSwitch setState:[optValue intValue]];
740                 }
741                 /* CABAC NSButton */
742                 if ([optName isEqualToString:@"cabac"])
743                 {
744                     [fX264optCabacSwitch setState:[optValue intValue]];
745                 }                                                                 
746             }
747         }
748     }
749 }
750
751 /**
752  * Resets the option string to mirror the GUI widgets.
753  */
754 - (IBAction) X264AdvancedOptionsChanged: (id) sender
755 {
756     /*Determine which outlet is being used and set optName to process accordingly */
757     NSString * optNameToChange = @""; // The option name such as "bframes"
758     
759     if (sender == fX264optBframesPopUp)
760     {
761         optNameToChange = @"bframes";
762     }
763     if (sender == fX264optRefPopUp)
764     {
765         optNameToChange = @"ref";
766     }
767     if (sender == fX264optNfpskipSwitch)
768     {
769         optNameToChange = @"no-fast-pskip";
770     }
771     if (sender == fX264optNodctdcmtSwitch)
772     {
773         optNameToChange = @"no-dct-decimate";
774     }
775     if (sender == fX264optSubmePopUp)
776     {
777         optNameToChange = @"subq";
778     }
779     if (sender == fX264optTrellisPopUp)
780     {
781         optNameToChange = @"trellis";
782     }
783     if (sender == fX264optMixedRefsSwitch)
784     {
785         optNameToChange = @"mixed-refs";
786     }
787     if (sender == fX264optMotionEstPopUp)
788     {
789         optNameToChange = @"me";
790     }
791     if (sender == fX264optMERangePopUp)
792     {
793         optNameToChange = @"merange";
794     }
795     if (sender == fX264optWeightBSwitch)
796     {
797         optNameToChange = @"weightb";
798     }
799     if (sender == fX264optBRDOSwitch)
800     {
801         optNameToChange = @"brdo";
802     }
803     if (sender == fX264optBPyramidSwitch)
804     {
805         optNameToChange = @"b-pyramid";
806     }
807     if (sender == fX264optBiMESwitch)
808     {
809         optNameToChange = @"bime";
810     }
811     if (sender == fX264optDirectPredPopUp)
812     {
813         optNameToChange = @"direct";
814     }
815     if (sender == fX264optAlphaDeblockPopUp)
816     {
817         optNameToChange = @"deblock";
818     }
819     if (sender == fX264optBetaDeblockPopUp)
820     {
821         optNameToChange = @"deblock";
822     }        
823     if (sender == fX264optAnalysePopUp)
824     {
825         optNameToChange = @"analyse";
826     }
827     if (sender == fX264opt8x8dctSwitch)
828     {
829         optNameToChange = @"8x8dct";
830     }
831     if (sender == fX264optCabacSwitch)
832     {
833         optNameToChange = @"cabac";
834     }
835     
836     /* Set widgets depending on the opt string in field */
837     NSString * thisOpt; // The separated option such as "bframes=3"
838     NSString * optName = @""; // The option name such as "bframes"
839     NSString * optValue = @"";// The option value such as "3"
840     NSArray *currentOptsArray;
841     
842     /*First, we get an opt string to process */
843     NSString *currentOptString = [fDisplayX264Options stringValue];
844     
845     /* There are going to be a few possibilities.
846        - The option might start off the string.
847        - The option might be in the middle of the string.
848        - The option might not be in the string at all yet.
849        - The string itself might not yet exist.
850        
851        Because each of these possibilities means constructing a different kind of string,
852        they're all handled separately in a sea of messy, somewhat redundant code. =(     */
853        
854     /* If the option is in the string but not the beginning of it, it will be in the form of ":optName=value"
855        so we really want to be looking for ":optNameToChange=" rather than "optNameToChange".                 */
856     NSString *checkOptNameToChange = [NSString stringWithFormat:@":%@=",optNameToChange];
857     
858     /* Now we store the part of the string up through the option name in currentOptRange. */
859     NSRange currentOptRange = [currentOptString rangeOfString:checkOptNameToChange];
860
861     /*  We need to know if the option is at the beginning of the string.
862         If it is at the start, it won't be preceded by a colon.
863         To figure this out, we'll use the rangeOfString method. First,
864         store what the option name would be if if it was at the beginning,
865         in checkOptNameToChangeBeginning. Then, find its range in the string.
866         If the range is 0, it's the first option listed in the string.       */        
867     NSString *checkOptNameToChangeBeginning = [NSString stringWithFormat:@"%@=",optNameToChange];
868     NSRange currentOptRangeBeginning = [currentOptString rangeOfString:checkOptNameToChangeBeginning];
869     
870     if (currentOptRange.location != NSNotFound || currentOptRangeBeginning.location == 0)
871     {
872         /* If the option is in the string wth a semicolon, or starts the string, it's time to edit.
873            This means parsing the whole string into an array of options and values. From there,
874            iterate through the options, and when you reach the one that's been changed, edit it.   */
875         
876         /* Create new empty opt string*/
877         NSString *changedOptString = @"";
878         
879         /*Put individual options into an array based on the ":" separator for processing, result is "<opt>=<value>"*/
880         currentOptsArray = [currentOptString componentsSeparatedByString:@":"];
881         
882         /*iterate through the array and get <opts> and <values*/
883         int loopcounter;
884         int currentOptsArrayCount = [currentOptsArray count];
885         for (loopcounter = 0; loopcounter < currentOptsArrayCount; loopcounter++)
886         {
887             thisOpt = [currentOptsArray objectAtIndex:loopcounter];
888             NSRange splitOptRange = [thisOpt rangeOfString:@"="];
889             
890             if (splitOptRange.location != NSNotFound)
891             {
892                 /* First off, it's time to handle option strings that
893                    already have at least one option=value pair in them. */
894                    
895                 optName = [thisOpt substringToIndex:splitOptRange.location];
896                 optValue = [thisOpt substringFromIndex:splitOptRange.location + 1];
897                 
898                 /*Run through the available widgets for x264 opts and set them, as you add widgets, 
899                     they need to be added here. This should be moved to its own method probably*/
900                 
901                 /*If the optNameToChange is found, appropriately change the value or delete it if
902                     "Unspecified" is set.*/
903                 if ([optName isEqualToString:optNameToChange])
904                 {
905                     if ([optNameToChange isEqualToString:@"deblock"])
906                     {
907                         if ((([fX264optAlphaDeblockPopUp indexOfSelectedItem] == 0) || ([fX264optAlphaDeblockPopUp indexOfSelectedItem] == 7)) && (([fX264optBetaDeblockPopUp indexOfSelectedItem] == 0) || ([fX264optBetaDeblockPopUp indexOfSelectedItem] == 7)))
908                         {
909                             /* When both deblock widgets are 0 or default or a mix of the two,
910                                use a blank string, since deblocking defaults to 0,0.           */
911                             thisOpt = @"";                                
912                         }
913                         else
914                         {
915                             /* Otherwise the format is deblock=a,b, where a and b both have an array
916                                offset of 7 because deblocking values start at -6 instead of at zero. */
917                             thisOpt = [NSString stringWithFormat:@"%@=%d,%d",optName, ([fX264optAlphaDeblockPopUp indexOfSelectedItem] != 0) ? [fX264optAlphaDeblockPopUp indexOfSelectedItem]-7 : 0,([fX264optBetaDeblockPopUp indexOfSelectedItem] != 0) ? [fX264optBetaDeblockPopUp indexOfSelectedItem]-7 : 0];
918                         }
919                     }
920                     else if /*Boolean Switches*/ ([optNameToChange isEqualToString:@"mixed-refs"] || [optNameToChange isEqualToString:@"weightb"] || [optNameToChange isEqualToString:@"brdo"] || [optNameToChange isEqualToString:@"bime"] || [optNameToChange isEqualToString:@"b-pyramid"] || [optNameToChange isEqualToString:@"no-fast-pskip"] || [optNameToChange isEqualToString:@"no-dct-decimate"] || [optNameToChange isEqualToString:@"8x8dct"] )
921                     {
922                         /* Here is where we take care of the boolean options that work overtly:
923                            no-dct-decimate being on means no-dct-decimate=1, etc. Some options
924                            require the inverse, but those will be handled a couple lines down. */
925                         if ([sender state] == 0)
926                         {
927                             /* When these options are false, don't include them. They all default
928                                to being set off, so they don't need to be mentioned at all.       */
929                             thisOpt = @"";
930                         }
931                         else
932                         {
933                             /* Otherwise, include them as optioname=1 */
934                             thisOpt = [NSString stringWithFormat:@"%@=%d",optName,1];
935                         }
936                     }
937                     else if ([optNameToChange isEqualToString:@"cabac"])
938                     {
939                         /* CABAC is odd, in that it defaults to being on. That means
940                            it only needs to be included in the string when turned off. */
941                         if ([sender state] == 1)
942                         {
943                             /* It's true so don't include it. */
944                             thisOpt = @"";
945                         }
946                         else
947                         {
948                             /* Otherwise, include cabac=0 in the string to enable CAVLC. */
949                             thisOpt = [NSString stringWithFormat:@"%@=%d",optName,0];
950                         }
951                     }                                        
952                     else if (([sender indexOfSelectedItem] == 0) && (sender != fX264optAlphaDeblockPopUp) && (sender != fX264optBetaDeblockPopUp) ) // means that "unspecified" is chosen, lets then remove it from the string
953                     {
954                         /* When a widget is at index 0, it's default. Default means don't add to the string.
955                            The exception for deblocking is because for those, *both* need to at index 0
956                            for it to default, so it's handled separately, above this section.                */
957                         thisOpt = @"";
958                     }
959                     else if ([optNameToChange isEqualToString:@"me"])
960                     {
961                         /* Motion estimation uses string values, so this switch
962                            pairs the widget index with the right value string.  */
963                         switch ([sender indexOfSelectedItem])
964                         {   
965                             case 1:
966                                 thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"dia"];
967                                 break;
968                                 
969                             case 2:
970                                 thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"hex"];
971                                 break;
972                                 
973                             case 3:
974                                 thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"umh"];
975                                 break;
976                                 
977                             case 4:
978                                 thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"esa"];
979                                 break;
980                                 
981                             default:
982                                 break;
983                         }
984                     }
985                     else if ([optNameToChange isEqualToString:@"direct"])
986                     {
987                         /* Direct prediction uses string values, so this switch
988                            pairs the right string value with the right widget index. */
989                         switch ([sender indexOfSelectedItem])
990                         {   
991                             case 1:
992                                 thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"none"];
993                                 break;
994                                 
995                             case 2:
996                                 thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"spatial"];
997                                 break;
998                                 
999                             case 3:
1000                                 thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"temporal"];
1001                                 break;
1002                                 
1003                             case 4:
1004                                 thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"auto"];
1005                                 break;
1006                                 
1007                             default:
1008                                 break;
1009                         }
1010                     }
1011                     else if ([optNameToChange isEqualToString:@"analyse"])
1012                     {
1013                         /* Analysis uses string values as well. */
1014                         switch ([sender indexOfSelectedItem])
1015                         {   
1016                             case 1:
1017                                 thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"none"];
1018                                 break;
1019                                 
1020                             case 2:
1021                                 thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"all"];
1022                                 break;
1023                                 
1024                             default:
1025                                 break;
1026                         }
1027                     }
1028                     else if ([optNameToChange isEqualToString:@"merange"])
1029                     {
1030                         /* Motion estimation range uses an odd array offset because in addition
1031                            to starting with index 0 as default, index 1 starts at 4 instead of 1,
1032                            because merange can't go below 4. So it has to be handled separately.  */
1033                         thisOpt = [NSString stringWithFormat:@"%@=%d",optName,[sender indexOfSelectedItem]+3];
1034                     }
1035                     else // we have a valid value to change, so change it
1036                     {
1037                         if ( [sender indexOfSelectedItem] != 0 )
1038                         /* Here's our general case, that catches things like ref frames and b-frames.
1039                            Basically, any options that are PopUp menus with index 0 as default and
1040                            index 1 as 1, with numerical values, are all handled right here. All of
1041                            the above stuff is for the exceptions to the general case.              */
1042                             thisOpt = [NSString stringWithFormat:@"%@=%d",optName,[sender indexOfSelectedItem]-1];
1043                     }
1044                 }
1045             }
1046             
1047             /* Construct New String for opts here */
1048             if ([thisOpt isEqualToString:@""])
1049             {
1050                 /* Blank option, so just add it to the string. (Why?) */
1051                 changedOptString = [NSString stringWithFormat:@"%@%@",changedOptString,thisOpt];
1052             }
1053             else
1054             {
1055                 if ([changedOptString isEqualToString:@""])
1056                 {
1057                     /* No existing string, make the string this option. */
1058                     changedOptString = [NSString stringWithFormat:@"%@",thisOpt];
1059                 }
1060                 else
1061                 {
1062                     /* Existing string, existing option. Append the
1063                        option to the string, preceding it with a colon. */
1064                     changedOptString = [NSString stringWithFormat:@"%@:%@",changedOptString,thisOpt];
1065                 }
1066             }
1067         }
1068         
1069         /* Change the dislayed option string to reflect the new modified settings */
1070         [fDisplayX264Options setStringValue:[NSString stringWithFormat:changedOptString]];    
1071     }
1072     else // if none exists, add it to the string
1073     {
1074         /* This is where options that aren't already in the string are handled. */
1075         if ([[fDisplayX264Options stringValue] isEqualToString: @""])
1076         {
1077             /* The option might not be in the string because the
1078                string is empty. Handle this possibility first.   */
1079             if ([optNameToChange isEqualToString:@"me"])
1080             {
1081                 /* Special case for motion estimation, which uses string values
1082                    that need to be paired up with the equivalent widget index.  */
1083                 switch ([sender indexOfSelectedItem])
1084                 {   
1085                     case 1:
1086                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
1087                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"dia"]]];
1088                         break;
1089                         
1090                     case 2:
1091                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
1092                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"hex"]]];
1093                         break;
1094                         
1095                     case 3:
1096                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
1097                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"umh"]]];
1098                         break;
1099                         
1100                     case 4:
1101                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
1102                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"esa"]]];
1103                         break;
1104                         
1105                     default:
1106                         break;
1107                 }
1108             }
1109             else if ([optNameToChange isEqualToString:@"direct"])
1110             {
1111                 /* Special case for direct prediction, which uses string values
1112                    that need to be paired up with the equivalent widget index.  */
1113                 switch ([sender indexOfSelectedItem])
1114                 {   
1115                     case 1:
1116                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
1117                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"none"]]];
1118                         break;
1119                         
1120                     case 2:
1121                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
1122                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"spatial"]]];
1123                         break;
1124                         
1125                     case 3:
1126                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
1127                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"temporal"]]];
1128                         break;
1129                         
1130                     case 4:
1131                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
1132                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"auto"]]];
1133                         break;
1134                         
1135                     default:
1136                         break;
1137                 }
1138             }
1139             else if ([optNameToChange isEqualToString:@"analyse"])
1140             {
1141                 /* Special case for partition analysis, which uses string values
1142                    that need to be paired up with the equivalent widget index.  */
1143                 switch ([sender indexOfSelectedItem])
1144                 {   
1145                     case 1:
1146                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
1147                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"none"]]];
1148                         break;
1149                         
1150                     case 2:
1151                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
1152                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"all"]]];
1153                         break;
1154                         
1155                     default:
1156                         break;
1157                 }
1158             }
1159             
1160             else if ([optNameToChange isEqualToString:@"merange"])
1161             {
1162                 /* Special case for motion estimation range, which uses
1163                    a widget index offset of 3. This is because the
1164                    first valid value after default is four, not zero.   */
1165                 [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
1166                     [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"%d",[sender indexOfSelectedItem]+3]]];
1167             }
1168             else if ([optNameToChange isEqualToString:@"deblock"])
1169             {
1170                 /* Very special case for deblock. Uses a weird widget index offset
1171                    of 7, because the first value after default is -6, rather than 0.
1172                    As well, deblock only goes to default when *both* alpha and beta
1173                    are zero. If only one is zero, you can't mark it down as default.
1174                    Instead, mark that one down as literally 0. This is because when
1175                    widgets are at default values, they aren't included in the string.
1176                    If only one filter is at 0, both need to be overtly specified.    */
1177                 [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"%d,%d", ([fX264optAlphaDeblockPopUp indexOfSelectedItem] != 0) ? [fX264optAlphaDeblockPopUp indexOfSelectedItem]-7 : 0, ([fX264optBetaDeblockPopUp indexOfSelectedItem] != 0) ? [fX264optBetaDeblockPopUp indexOfSelectedItem]-7 : 0]]];                
1178             }
1179             else if /*Boolean Switches*/ ([optNameToChange isEqualToString:@"mixed-refs"] || [optNameToChange isEqualToString:@"weightb"] || [optNameToChange isEqualToString:@"brdo"] || [optNameToChange isEqualToString:@"bime"] || [optNameToChange isEqualToString:@"b-pyramid"] || [optNameToChange isEqualToString:@"no-fast-pskip"] || [optNameToChange isEqualToString:@"no-dct-decimate"] || [optNameToChange isEqualToString:@"8x8dct"] )
1180             {
1181                 /* This covers all the boolean options that need to be specified only when true. */
1182                 if ([sender state] == 0)
1183                 {
1184                     [fDisplayX264Options setStringValue:[NSString stringWithFormat:@""]];                    
1185                 }
1186                 else
1187                 {
1188                     [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
1189                         [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"%d",[sender state]]]];
1190                 }
1191             }
1192             else if ([optNameToChange isEqualToString:@"cabac"])
1193             {
1194                 /* CABAC is weird in that you need the inverse. Only include in the string
1195                    when cabac=0, because cabac=1 is the default. Turning it off means CAVLC. */
1196                 if ([sender state] == 1)
1197                 {
1198                     [fDisplayX264Options setStringValue:[NSString stringWithFormat:@""]];                                        
1199                 }
1200                 else
1201                 {
1202                     [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
1203                         [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"%d",[sender state]]]];                    
1204                 }
1205             }            
1206             else
1207             {
1208                 if ( [sender indexOfSelectedItem] != 0 )
1209                 /* General case to cover all the normal PopUp widgets, like ref and b-frames. */
1210                     [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
1211                     [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"%d",[sender indexOfSelectedItem]-1]]];
1212             }
1213         }
1214         else
1215         {
1216             /* The string isn't empty, and the option isn't already in it,
1217                so it will need to be appended to the string with a colon.  */
1218             if ([optNameToChange isEqualToString:@"me"])
1219             {
1220                 /* Special case for motion estimation, which uses string values
1221                    that need to be paired up with the equivalent widget index.  */
1222                 switch ([sender indexOfSelectedItem])
1223                 {   
1224                     case 1:
1225                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@", 
1226                             [NSString stringWithFormat:[fDisplayX264Options stringValue]],
1227                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"dia"]]];
1228                         break;
1229                         
1230                     case 2:
1231                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@", 
1232                             [NSString stringWithFormat:[fDisplayX264Options stringValue]],
1233                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"hex"]]];
1234                         break;
1235                         
1236                     case 3:
1237                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@", 
1238                             [NSString stringWithFormat:[fDisplayX264Options stringValue]],
1239                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"umh"]]];
1240                         break;
1241                         
1242                     case 4:
1243                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@", 
1244                             [NSString stringWithFormat:[fDisplayX264Options stringValue]],
1245                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"esa"]]];
1246                         break;
1247                         
1248                     default:
1249                         break;
1250                 }
1251             }
1252             else if ([optNameToChange isEqualToString:@"direct"])
1253             {
1254                 /* Special case for direct prediction, which uses string values
1255                    that need to be paired up with the equivalent widget index.  */
1256                 switch ([sender indexOfSelectedItem])
1257                 {   
1258                     case 1:
1259                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@", 
1260                             [NSString stringWithFormat:[fDisplayX264Options stringValue]],
1261                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"none"]]];
1262                         break;
1263                         
1264                     case 2:
1265                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@", 
1266                             [NSString stringWithFormat:[fDisplayX264Options stringValue]],
1267                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"spatial"]]];
1268                         break;
1269                         
1270                     case 3:
1271                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@", 
1272                             [NSString stringWithFormat:[fDisplayX264Options stringValue]],
1273                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"temporal"]]];
1274                         break;
1275                         
1276                     case 4:
1277                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@", 
1278                             [NSString stringWithFormat:[fDisplayX264Options stringValue]],
1279                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"auto"]]];
1280                         break;
1281                         
1282                     default:
1283                         break;
1284                 }
1285             }
1286             else if ([optNameToChange isEqualToString:@"analyse"])
1287             {
1288                 /* Special case for partition analysis, which uses string values
1289                    that need to be paired up with the equivalent widget index.  */
1290                 switch ([sender indexOfSelectedItem])
1291                 {   
1292                     case 1:
1293                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@", 
1294                             [NSString stringWithFormat:[fDisplayX264Options stringValue]],
1295                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"none"]]];
1296                         break;
1297                         
1298                     case 2:
1299                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@", 
1300                             [NSString stringWithFormat:[fDisplayX264Options stringValue]],
1301                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"all"]]];
1302                         break;
1303                         
1304                     default:
1305                         break;
1306                 }
1307             }
1308             
1309             else if ([optNameToChange isEqualToString:@"merange"])
1310             {
1311                 /* Motion estimation range uses a weird offset since its index goes
1312                    0: default, 1: 4, because the first valid value is 4, not 1.     */
1313                 [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@",[NSString stringWithFormat:[fDisplayX264Options stringValue]], 
1314                     [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"%d",[sender indexOfSelectedItem]+3]]];
1315             }
1316             else if ([optNameToChange isEqualToString:@"deblock"])
1317             {
1318                 /* Deblock is really weird because it has two values, and if only one is default, both
1319                    still need to be specified directly. with the default one at zero. To make deblock
1320                    just a little more fun, values start at -6 instead of at zero.                       */
1321                 [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@", [NSString stringWithFormat:[fDisplayX264Options stringValue]], [NSString stringWithFormat:optNameToChange], [NSString stringWithFormat:@"%d,%d", ([fX264optAlphaDeblockPopUp indexOfSelectedItem] != 0) ? [fX264optAlphaDeblockPopUp indexOfSelectedItem]-7 : 0, ([fX264optBetaDeblockPopUp indexOfSelectedItem] != 0) ? [fX264optBetaDeblockPopUp indexOfSelectedItem]-7 : 0]]];                
1322             }
1323             else if /*Boolean Switches*/ ([optNameToChange isEqualToString:@"mixed-refs"] || [optNameToChange isEqualToString:@"weightb"] || [optNameToChange isEqualToString:@"brdo"] || [optNameToChange isEqualToString:@"bime"] || [optNameToChange isEqualToString:@"b-pyramid"] || [optNameToChange isEqualToString:@"no-fast-pskip"] || [optNameToChange isEqualToString:@"no-dct-decimate"] || [optNameToChange isEqualToString:@"8x8dct"] )
1324             {
1325                 /* Covers all the normal booleans, that only need to be included in the string when they're true. */
1326                 if ([sender state] == 0)
1327                 {
1328                     [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@",[NSString stringWithFormat:[fDisplayX264Options stringValue]]]];                    
1329                 }
1330                 else
1331                 {
1332                     [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@",[NSString stringWithFormat:[fDisplayX264Options stringValue]], 
1333                         [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"%d",[sender state]]]];                
1334                 }
1335             }
1336             else if ([optNameToChange isEqualToString:@"cabac"])
1337             {
1338                 /* CABAC is weird, in that it's an inverse. Only include it in the string when it's false. */
1339                 if ([sender state] == 1)
1340                 {
1341                     [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@",[NSString stringWithFormat:[fDisplayX264Options stringValue]]]];                    
1342                 }
1343                 else
1344                 {
1345                     [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@",[NSString stringWithFormat:[fDisplayX264Options stringValue]], 
1346                         [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"%d",[sender state]]]];
1347                 }
1348             }
1349             else
1350             {
1351                 /* General case to handle the normal PopUp widgets like ref and b-frames. */
1352                 if ( [sender indexOfSelectedItem] != 0 )
1353                     [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@",[NSString stringWithFormat:[fDisplayX264Options stringValue]], 
1354                     [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"%d",[sender indexOfSelectedItem]-1]]];
1355             }
1356         }
1357     }
1358     
1359     /* We now need to reset the opt widgets since we changed some stuff */        
1360     [self X264AdvancedOptionsSet:sender];        
1361 }
1362
1363 @end