OSDN Git Service

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