OSDN Git Service

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