OSDN Git Service

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