+ return optNameToChange;
+}
+
+- (NSString *) X264AdvancedOptionsWidgetToString: (NSString *) optName withID: (id) sender
+{
+ NSString * thisOpt = @""; // The option=value string the method will return
+
+ if ([optName isEqualToString:@"deblock"])
+ {
+ if ((([fX264optAlphaDeblockPopUp indexOfSelectedItem] == 0) || ([fX264optAlphaDeblockPopUp indexOfSelectedItem] == 7)) && (([fX264optBetaDeblockPopUp indexOfSelectedItem] == 0) || ([fX264optBetaDeblockPopUp indexOfSelectedItem] == 7)))
+ {
+ /* When both deblock widgets are 0 or default or a mix of the two,
+ use a blank string, since deblocking defaults to 0,0. */
+ thisOpt = @"";
+ }
+ else
+ {
+ /* Otherwise the format is deblock=a,b, where a and b both have an array
+ offset of 7 because deblocking values start at -6 instead of at zero. */
+ thisOpt = [NSString stringWithFormat:@"%@=%d,%d",optName, ([fX264optAlphaDeblockPopUp indexOfSelectedItem] != 0) ? [fX264optAlphaDeblockPopUp indexOfSelectedItem]-7 : 0,([fX264optBetaDeblockPopUp indexOfSelectedItem] != 0) ? [fX264optBetaDeblockPopUp indexOfSelectedItem]-7 : 0];
+ }
+ }
+
+ else if ([optName isEqualToString:@"psy-rd"])
+ {
+ if( [fX264optPsyRDSlider floatValue] == 1.0 && [fX264optPsyTrellisSlider floatValue] == 0.0 )
+ {
+ /* When PsyRD is 1 and PsyTrel is 0 they're default values and can be ignored. */
+ thisOpt = @"";
+ }
+ else
+ {
+ /* Otherwise the format is deblock=a,b, where a and b both have an array
+ offset of 7 because deblocking values start at -6 instead of at zero. */
+ thisOpt = [NSString stringWithFormat:@"%@=%0.1f,%0.1f", optName, [fX264optPsyRDSlider floatValue], [fX264optPsyTrellisSlider floatValue] ];
+ }
+ }
+
+ else if /*Boolean Switches*/ ( [optName isEqualToString:@"b-pyramid"] || [optName isEqualToString:@"no-fast-pskip"] || [optName isEqualToString:@"no-dct-decimate"] )
+ {
+ /* Here is where we take care of the boolean options that work overtly:
+ no-dct-decimate being on means no-dct-decimate=1, etc. Some options
+ require the inverse, but those will be handled a couple lines down. */
+ if ([sender state] == 0)
+ {
+ /* When these options are false, don't include them. They all default
+ to being set off, so they don't need to be mentioned at all. */
+ thisOpt = @"";
+ }
+ else
+ {
+ /* Otherwise, include them as optioname=1 */
+ thisOpt = [NSString stringWithFormat:@"%@=%d",optName,1];
+ }
+ }
+
+ else if ( [optName isEqualToString:@"8x8dct"] || [optName isEqualToString:@"weightb"] || [optName isEqualToString:@"mixed-refs"] || [optName isEqualToString:@"cabac"] )
+ {
+ /* These options default to being on. That means they
+ only need to be included in the string when turned off. */
+ if ([sender state] == 1)
+ {
+ /* It's true so don't include it. */
+ thisOpt = @"";
+ }
+ else
+ {
+ /* Otherwise, include cabac=0, etc, in the string. */
+ thisOpt = [NSString stringWithFormat:@"%@=%d",optName,0];
+ }
+ }
+
+ else if (([sender indexOfSelectedItem] == 0) && (sender != fX264optAlphaDeblockPopUp) && (sender != fX264optBetaDeblockPopUp) ) // means that "unspecified" is chosen, lets then remove it from the string
+ {
+ /* When a widget is at index 0, it's default. Default means don't add to the string.
+ The exception for deblocking is because for those, *both* need to at index 0
+ for it to default, so it's handled separately, above this section. */
+ thisOpt = @"";
+ }
+
+ else if ([optName isEqualToString:@"me"])
+ {
+ /* Motion estimation uses string values, so this switch
+ pairs the widget index with the right value string. */
+ switch ([sender indexOfSelectedItem])
+ {
+ case 1:
+ thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"dia"];
+ break;
+
+ case 2:
+ thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"hex"];
+ break;
+
+ case 3:
+ thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"umh"];
+ break;
+
+ case 4:
+ thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"esa"];
+ break;
+
+ case 5:
+ thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"tesa"];
+
+ default:
+ break;
+ }
+ }
+
+ else if ([optName isEqualToString:@"direct"])
+ {
+ /* Direct prediction uses string values, so this switch
+ pairs the right string value with the right widget index. */
+ switch ([sender indexOfSelectedItem])
+ {
+ case 1:
+ thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"none"];
+ break;
+
+ case 2:
+ thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"spatial"];
+ break;
+
+ case 3:
+ thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"temporal"];
+ break;
+
+ case 4:
+ thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"auto"];
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ else if ([optName isEqualToString:@"analyse"])
+ {
+ /* Analysis uses string values as well. */
+ switch ([sender indexOfSelectedItem])
+ {
+ case 1:
+ thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"none"];
+ break;
+
+ case 2:
+ thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"all"];
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ else if ([optName isEqualToString:@"merange"])
+ {
+ /* Motion estimation range uses an odd array offset because in addition
+ to starting with index 0 as default, index 1 starts at 4 instead of 1,
+ because merange can't go below 4. So it has to be handled separately. */
+ thisOpt = [NSString stringWithFormat:@"%@=%d",optName,[sender indexOfSelectedItem]+3];
+ }
+
+ else if ([optName isEqualToString:@"b-adapt"])
+ {
+ /* B-adapt starts at index 0 with default then goes 0, 1, 2)*/
+ thisOpt = [NSString stringWithFormat:@"%@=%d", optName, [sender indexOfSelectedItem]-1];
+ }
+
+ else // we have a valid value to change, so change it
+ {
+ if ( [sender indexOfSelectedItem] != 0 )
+ /* Here's our general case, that catches things like ref frames and b-frames.
+ Basically, any options that are PopUp menus with index 0 as default and
+ index 1 as 1, with numerical values, are all handled right here. All of
+ the above stuff is for the exceptions to the general case. */
+ thisOpt = [NSString stringWithFormat:@"%@=%d",optName,[sender indexOfSelectedItem]-1];
+ }
+
+ return thisOpt;
+}
+
+- (BOOL) X264AdvancedOptionsIsOpt: (NSString *) optNameToChange inString: (NSString *) currentOptString
+{
+ /* If the option is in the string but not the beginning of it,
+ it will be in the form of ":optName=value" so we really want
+ to be looking for ":optNameToChange=" rather than "optNameToChange". */
+ NSString *checkOptNameToChange = [NSString stringWithFormat:@":%@=",optNameToChange];
+
+ /* Now we store the part of the string up through the option name in currentOptRange. */
+ NSRange currentOptRange = [currentOptString rangeOfString:checkOptNameToChange];
+
+ /* We need to know if the option is at the beginning of the string.
+ If it is at the start, it won't be preceded by a colon.
+ To figure this out, we'll use the rangeOfString method. First,
+ store what the option name would be if if it was at the beginning,
+ in checkOptNameToChangeBeginning. Then, find its range in the string.
+ If the range is 0, it's the first option listed in the string. */
+ NSString *checkOptNameToChangeBeginning = [NSString stringWithFormat:@"%@=",optNameToChange];
+ NSRange currentOptRangeBeginning = [currentOptString rangeOfString:checkOptNameToChangeBeginning];
+
+ if (currentOptRange.location != NSNotFound || currentOptRangeBeginning.location == 0)
+ return true;
+ else
+ return false;
+}
+
+/**
+ * Resets the option string to mirror the GUI widgets.
+ */
+- (IBAction) X264AdvancedOptionsChanged: (id) sender
+{
+ /* Look up the equivalent string option name of the calling widget. */
+ NSString * optNameToChange = [self X264AdvancedOptionsOptIDToString: sender];
+
+ NSString * thisOpt = @""; // The separated option such as "bframes=3"
+ NSString * optName = @""; // The option name such as "bframes"
+ NSString * optValue = @""; // The option value such as "3"
+ NSArray *currentOptsArray;
+
+ /* Get the current opt string being displayed. */
+ NSString *currentOptString = [fDisplayX264Options stringValue];
+
+ /* There are going to be a few possibilities.
+ - The option might start off the string.
+ - The option might be in the middle of the string.
+ - The option might not be in the string at all yet.
+ - The string itself might not yet exist. */
+
+ if( [self X264AdvancedOptionsIsOpt: optNameToChange inString: currentOptString] )
+ {
+ /* If the option is in the string wth a semicolon, or starts the string, it's time to edit.
+ This means parsing the whole string into an array of options and values. From there,
+ iterate through the options, and when you reach the one that's been changed, edit it. */