OSDN Git Service

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