]> git.sesse.net Git - vlc/blobdiff - modules/gui/macosx/VideoEffects.m
macosx: fix rare crash when changing video effects settings
[vlc] / modules / gui / macosx / VideoEffects.m
index b11050a3462f69ba9dc083ae541373ba5d72f111..47d81a8ce869f9f8fc4a877ebb3b2dc2bd20b17f 100644 (file)
 #import <vlc_common.h>
 #import <vlc_modules.h>
 #import <vlc_charset.h>
+#import <vlc_strings.h>
 #import "VideoEffects.h"
+#import "SharedDialogs.h"
+
+@interface VLCVideoEffects (Internal)
+- (void)resetProfileSelector;
+@end
 
 #pragma mark -
-#pragma mark Initialization & Generic code
+#pragma mark Initialization
 
 @implementation VLCVideoEffects
 static VLCVideoEffects *_o_sharedInstance = nil;
@@ -39,11 +45,17 @@ static VLCVideoEffects *_o_sharedInstance = nil;
     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
 }
 
++ (void)initialize
+{
+    NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithObject:@";;0;1.000000;1.000000;1.000000;1.000000;0.050000;16;2.000000;OTA=;4;4;0;16711680;20;15;120;Z3JhZGllbnQ=;1;0;16711680;6;80;VkxD;-1;;-1;255;2;3;3"], @"VideoEffectProfiles", [NSArray arrayWithObject:_NS("Default")], @"VideoEffectProfileNames", nil];
+    [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
+}
+
 - (id)init
 {
-    if (_o_sharedInstance) {
+    if (_o_sharedInstance)
         [self dealloc];
-    else {
+    else {
         p_intf = VLCIntf;
         _o_sharedInstance = [super init];
     }
@@ -51,19 +63,11 @@ static VLCVideoEffects *_o_sharedInstance = nil;
     return _o_sharedInstance;
 }
 
-- (IBAction)toggleWindow:(id)sender
-{
-    if( [o_window isVisible] )
-        [o_window orderOut:sender];
-    else
-        [o_window makeKeyAndOrderFront:sender];
-}
-
 - (void)awakeFromNib
 {
     [o_window setTitle: _NS("Video Effects")];
     [o_window setExcludedFromWindowsMenu:YES];
-    if (OSX_LION)
+    if (!OSX_SNOW_LEOPARD)
         [o_window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
 
     [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"basic"]] setLabel:_NS("Basic")];
@@ -72,6 +76,8 @@ static VLCVideoEffects *_o_sharedInstance = nil;
     [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"color"]] setLabel:_NS("Color")];
     [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"misc"]] setLabel:_NS("Miscellaneous")];
 
+    [self resetProfileSelector];
+
     [o_adjust_ckb setTitle:_NS("Image Adjust")];
     [o_adjust_hue_lbl setStringValue:_NS("Hue")];
     [o_adjust_contrast_lbl setStringValue:_NS("Contrast")];
@@ -110,6 +116,11 @@ static VLCVideoEffects *_o_sharedInstance = nil;
     [o_puzzle_rows_lbl setStringValue:_NS("Rows")];
     [o_puzzle_columns_lbl setStringValue:_NS("Columns")];
     [o_puzzle_blackslot_ckb setTitle:_NS("Black Slot")];
+    [o_clone_ckb setTitle:_NS("Clone")];
+    [o_clone_number_lbl setStringValue:_NS("Number of clones")];
+    [o_wall_ckb setTitle:_NS("Wall")];
+    [o_wall_numofrows_lbl setStringValue:_NS("Rows")];
+    [o_wall_numofcols_lbl setStringValue:_NS("Columns")];
 
     [o_threshold_ckb setTitle:_NS("Color threshold")];
     [o_threshold_color_lbl setStringValue:_NS("Color")];
@@ -193,6 +204,31 @@ static VLCVideoEffects *_o_sharedInstance = nil;
     [self resetValues];
 }
 
+#pragma mark -
+#pragma mark internal functions
+- (void)resetProfileSelector
+{
+    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+    [o_profile_pop removeAllItems];
+
+    NSArray * profileNames = [defaults objectForKey:@"VideoEffectProfileNames"];
+    [o_profile_pop addItemsWithTitles:profileNames];
+
+    [[o_profile_pop menu] addItem:[NSMenuItem separatorItem]];
+    [o_profile_pop addItemWithTitle:_NS("Save selection as new profile...")];
+    [[o_profile_pop lastItem] setTarget: self];
+    [[o_profile_pop lastItem] setAction: @selector(addProfile:)];
+
+    if ([profileNames count] > 1) {
+        [o_profile_pop addItemWithTitle:_NS("Organize Profiles...")];
+        [[o_profile_pop lastItem] setTarget: self];
+        [[o_profile_pop lastItem] setAction: @selector(removeProfile:)];
+    }
+
+    [o_profile_pop selectItemAtIndex:[defaults integerForKey:@"VideoEffectSelectedProfile"]];
+    [self profileSelectorAction:self];
+}
+
 - (void)resetValues
 {
     NSString *tmpString;
@@ -201,48 +237,84 @@ static VLCVideoEffects *_o_sharedInstance = nil;
 
     /* do we have any filter enabled? if yes, show it. */
     char * psz_vfilters;
-    psz_vfilters = config_GetPsz( p_intf, "video-filter" );
-    if( psz_vfilters ) {
-        [o_adjust_ckb setState: (NSInteger)strstr( psz_vfilters, "adjust")];
-        [o_sharpen_ckb setState: (NSInteger)strstr( psz_vfilters, "sharpen")];
-        [o_banding_ckb setState: (NSInteger)strstr( psz_vfilters, "gradfun")];
-        [o_grain_ckb setState: (NSInteger)strstr( psz_vfilters, "grain")];
-        [o_transform_ckb setState: (NSInteger)strstr( psz_vfilters, "transform")];
-        [o_zoom_ckb setState: (NSInteger)strstr( psz_vfilters, "magnify")];
-        [o_puzzle_ckb setState: (NSInteger)strstr( psz_vfilters, "puzzle")];
-        [o_threshold_ckb setState: (NSInteger)strstr( psz_vfilters, "colorthres")];
-        [o_sepia_ckb setState: (NSInteger)strstr( psz_vfilters, "sepia")];
-        [o_noise_ckb setState: (NSInteger)strstr( psz_vfilters, "noise")];
-        [o_gradient_ckb setState: (NSInteger)strstr( psz_vfilters, "gradient")];
-        [o_extract_ckb setState: (NSInteger)strstr( psz_vfilters, "extract")];
-        [o_invert_ckb setState: (NSInteger)strstr( psz_vfilters, "invert")];
-        [o_posterize_ckb setState: (NSInteger)strstr( psz_vfilters, "posterize")];
-        [o_blur_ckb setState: (NSInteger)strstr( psz_vfilters, "motionblur")];
-        [o_motiondetect_ckb setState: (NSInteger)strstr( psz_vfilters, "motiondetect")];
-        [o_watereffect_ckb setState: (NSInteger)strstr( psz_vfilters, "ripple")];
-        [o_waves_ckb setState: (NSInteger)strstr( psz_vfilters, "wave")];
-        [o_psychedelic_ckb setState: (NSInteger)strstr( psz_vfilters, "psychedelic")];
-        [o_anaglyph_ckb setState: (NSInteger)strstr( psz_vfilters, "anaglyph")];
-        free( psz_vfilters );
+    psz_vfilters = config_GetPsz(p_intf, "video-filter");
+    if (psz_vfilters) {
+        [o_adjust_ckb setState: (NSInteger)strstr(psz_vfilters, "adjust")];
+        [o_sharpen_ckb setState: (NSInteger)strstr(psz_vfilters, "sharpen")];
+        [o_banding_ckb setState: (NSInteger)strstr(psz_vfilters, "gradfun")];
+        [o_grain_ckb setState: (NSInteger)strstr(psz_vfilters, "grain")];
+        [o_transform_ckb setState: (NSInteger)strstr(psz_vfilters, "transform")];
+        [o_zoom_ckb setState: (NSInteger)strstr(psz_vfilters, "magnify")];
+        [o_puzzle_ckb setState: (NSInteger)strstr(psz_vfilters, "puzzle")];
+        [o_threshold_ckb setState: (NSInteger)strstr(psz_vfilters, "colorthres")];
+        [o_sepia_ckb setState: (NSInteger)strstr(psz_vfilters, "sepia")];
+        [o_noise_ckb setState: (NSInteger)strstr(psz_vfilters, "noise")];
+        [o_gradient_ckb setState: (NSInteger)strstr(psz_vfilters, "gradient")];
+        [o_extract_ckb setState: (NSInteger)strstr(psz_vfilters, "extract")];
+        [o_invert_ckb setState: (NSInteger)strstr(psz_vfilters, "invert")];
+        [o_posterize_ckb setState: (NSInteger)strstr(psz_vfilters, "posterize")];
+        [o_blur_ckb setState: (NSInteger)strstr(psz_vfilters, "motionblur")];
+        [o_motiondetect_ckb setState: (NSInteger)strstr(psz_vfilters, "motiondetect")];
+        [o_watereffect_ckb setState: (NSInteger)strstr(psz_vfilters, "ripple")];
+        [o_waves_ckb setState: (NSInteger)strstr(psz_vfilters, "wave")];
+        [o_psychedelic_ckb setState: (NSInteger)strstr(psz_vfilters, "psychedelic")];
+        [o_anaglyph_ckb setState: (NSInteger)strstr(psz_vfilters, "anaglyph")];
+        free(psz_vfilters);
+    } else {
+        [o_adjust_ckb setState: NSOffState];
+        [o_sharpen_ckb setState: NSOffState];
+        [o_banding_ckb setState: NSOffState];
+        [o_grain_ckb setState: NSOffState];
+        [o_transform_ckb setState: NSOffState];
+        [o_zoom_ckb setState: NSOffState];
+        [o_puzzle_ckb setState: NSOffState];
+        [o_threshold_ckb setState: NSOffState];
+        [o_sepia_ckb setState: NSOffState];
+        [o_noise_ckb setState: NSOffState];
+        [o_gradient_ckb setState: NSOffState];
+        [o_extract_ckb setState: NSOffState];
+        [o_invert_ckb setState: NSOffState];
+        [o_posterize_ckb setState: NSOffState];
+        [o_blur_ckb setState: NSOffState];
+        [o_motiondetect_ckb setState: NSOffState];
+        [o_watereffect_ckb setState: NSOffState];
+        [o_waves_ckb setState: NSOffState];
+        [o_psychedelic_ckb setState: NSOffState];
+        [o_anaglyph_ckb setState: NSOffState];
+    }
+
+    psz_vfilters = config_GetPsz(p_intf, "sub-source");
+    if (psz_vfilters) {
+        [o_addtext_ckb setState: (NSInteger)strstr(psz_vfilters, "marq")];
+        [o_addlogo_ckb setState: (NSInteger)strstr(psz_vfilters, "logo")];
+        free(psz_vfilters);
+    } else {
+        [o_addtext_ckb setState: NSOffState];
+        [o_addlogo_ckb setState: NSOffState];
     }
-    psz_vfilters = config_GetPsz( p_intf, "sub-source" );
+
+    psz_vfilters = config_GetPsz(p_intf, "video-splitter");
     if (psz_vfilters) {
-        [o_addtext_ckb setState: (NSInteger)strstr( psz_vfilters, "marq" )];
-        [o_addlogo_ckb setState: (NSInteger)strstr( psz_vfilters, "logo" )];
-        free( psz_vfilters );
+        
+        [o_clone_ckb setState: (NSInteger)strstr(psz_vfilters, "clone")];
+        [o_wall_ckb setState: (NSInteger)strstr(psz_vfilters, "wall")];
+        free(psz_vfilters);
+    } else {
+        [o_clone_ckb setState: NSOffState];
+        [o_wall_ckb setState: NSOffState];
     }
 
     /* fetch and show the various values */
-    [o_adjust_hue_sld setIntValue: config_GetInt( p_intf, "hue" )];
-    [o_adjust_contrast_sld setFloatValue: config_GetFloat( p_intf, "contrast" )];
-    [o_adjust_brightness_sld setFloatValue: config_GetFloat( p_intf, "brightness" )];
-    [o_adjust_saturation_sld setFloatValue: config_GetFloat( p_intf, "saturation" )];
-    [o_adjust_gamma_sld setFloatValue: config_GetFloat( p_intf, "gamma" )];
-    [o_adjust_brightness_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat( p_intf, "brightness" )]];
-    [o_adjust_contrast_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat( p_intf, "contrast" )]];
-    [o_adjust_gamma_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat( p_intf, "gamma" )]];
-    [o_adjust_hue_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt( p_intf, "hue" )]];
-    [o_adjust_saturation_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat( p_intf, "saturation" )]];
+    [o_adjust_hue_sld setIntValue: config_GetInt(p_intf, "hue")];
+    [o_adjust_contrast_sld setFloatValue: config_GetFloat(p_intf, "contrast")];
+    [o_adjust_brightness_sld setFloatValue: config_GetFloat(p_intf, "brightness")];
+    [o_adjust_saturation_sld setFloatValue: config_GetFloat(p_intf, "saturation")];
+    [o_adjust_gamma_sld setFloatValue: config_GetFloat(p_intf, "gamma")];
+    [o_adjust_brightness_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat(p_intf, "brightness")]];
+    [o_adjust_contrast_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat(p_intf, "contrast")]];
+    [o_adjust_gamma_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat(p_intf, "gamma")]];
+    [o_adjust_hue_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "hue")]];
+    [o_adjust_saturation_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat(p_intf, "saturation")]];
     b_state = [o_adjust_ckb state];
     [o_adjust_brightness_sld setEnabled: b_state];
     [o_adjust_brightness_ckb setEnabled: b_state];
@@ -256,16 +328,16 @@ static VLCVideoEffects *_o_sharedInstance = nil;
     [o_adjust_hue_lbl setEnabled: b_state];
     [o_adjust_saturation_lbl setEnabled: b_state];
     [o_adjust_reset_btn setEnabled: b_state];
-    [o_sharpen_sld setFloatValue: config_GetFloat( p_intf, "sharpen-sigma" )];
-    [o_sharpen_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat( p_intf, "sharpen-sigma" )]];
+    [o_sharpen_sld setFloatValue: config_GetFloat(p_intf, "sharpen-sigma")];
+    [o_sharpen_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat(p_intf, "sharpen-sigma")]];
     [o_sharpen_sld setEnabled: [o_sharpen_ckb state]];
     [o_sharpen_lbl setEnabled: [o_sharpen_ckb state]];
-    [o_banding_sld setIntValue: config_GetInt( p_intf, "gradfun-radius" )];
-    [o_banding_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt( p_intf, "gradfun-radius" )]];
+    [o_banding_sld setIntValue: config_GetInt(p_intf, "gradfun-radius")];
+    [o_banding_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "gradfun-radius")]];
     [o_banding_sld setEnabled: [o_banding_ckb state]];
     [o_banding_lbl setEnabled: [o_banding_ckb state]];
-    [o_grain_sld setFloatValue: config_GetFloat( p_intf, "grain-variance" )];
-    [o_grain_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat( p_intf, "grain-variance" )]];
+    [o_grain_sld setFloatValue: config_GetFloat(p_intf, "grain-variance")];
+    [o_grain_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat(p_intf, "grain-variance")]];
     [o_grain_sld setEnabled: [o_grain_ckb state]];
     [o_grain_lbl setEnabled: [o_grain_ckb state]];
 
@@ -276,31 +348,48 @@ static VLCVideoEffects *_o_sharedInstance = nil;
     [o_crop_sync_top_bottom_ckb setState: NSOffState];
     [o_crop_sync_left_right_ckb setState: NSOffState];
 
-    tmpChar = config_GetPsz( p_intf, "transform-type" );
+    tmpChar = config_GetPsz(p_intf, "transform-type");
     tmpString = [NSString stringWithUTF8String: tmpChar];
-    if( [tmpString isEqualToString:@"hflip"] )
+    if ([tmpString isEqualToString:@"hflip"])
         [o_transform_pop selectItemWithTag: 1];
-    else if( [tmpString isEqualToString:@"vflip"] )
+    else if ([tmpString isEqualToString:@"vflip"])
         [o_transform_pop selectItemWithTag: 2];
     else
         [o_transform_pop selectItemWithTag:[tmpString intValue]];
-    FREENULL( tmpChar );
+    FREENULL(tmpChar);
     [o_transform_pop setEnabled: [o_transform_ckb state]];
-    [o_puzzle_rows_fld setIntValue: config_GetInt( p_intf, "puzzle-rows" )];
-    [o_puzzle_columns_fld setIntValue: config_GetInt( p_intf, "puzzle-cols" )];
-    [o_puzzle_blackslot_ckb setState: config_GetInt( p_intf, "puzzle-black-slot" )];
+    [o_puzzle_rows_fld setIntValue: config_GetInt(p_intf, "puzzle-rows")];
+    [o_puzzle_columns_fld setIntValue: config_GetInt(p_intf, "puzzle-cols")];
+    [o_puzzle_blackslot_ckb setState: config_GetInt(p_intf, "puzzle-black-slot")];
     b_state = [o_puzzle_ckb state];
     [o_puzzle_rows_fld setEnabled: b_state];
     [o_puzzle_rows_lbl setEnabled: b_state];
     [o_puzzle_columns_fld setEnabled: b_state];
     [o_puzzle_columns_lbl setEnabled: b_state];
     [o_puzzle_blackslot_ckb setEnabled: b_state];
-
-    [o_threshold_color_fld setStringValue: [[NSString stringWithFormat:@"%llx", config_GetInt( p_intf, "colorthres-color" )] uppercaseString]];
-    [o_threshold_saturation_sld setIntValue: config_GetInt( p_intf, "colorthres-saturationthres" )];
-    [o_threshold_saturation_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt( p_intf, "colorthres-saturationthres" )]];
-    [o_threshold_similarity_sld setIntValue: config_GetInt( p_intf, "colorthres-similaritythres" )];
-    [o_threshold_similarity_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt( p_intf, "colorthres-similaritythres" )]];
+    
+    [o_clone_number_fld setIntValue: config_GetInt(p_intf, "clone-count")];
+    b_state = [o_clone_ckb state];
+    [o_clone_number_lbl setEnabled: b_state];
+    [o_clone_number_fld setEnabled: b_state];
+    [o_clone_number_stp setEnabled: b_state];
+
+    b_state = [o_wall_ckb state];
+    [o_wall_numofrows_fld setIntValue: config_GetInt(p_intf, "wall-rows")];
+    [o_wall_numofrows_lbl setEnabled: b_state];
+    [o_wall_numofrows_fld setEnabled: b_state];
+    [o_wall_numofrows_stp setEnabled: b_state];
+    [o_wall_numofcols_fld setIntValue: config_GetInt(p_intf, "wall-cols")];
+    [o_wall_numofcols_lbl setEnabled: b_state];
+    [o_wall_numofcols_fld setEnabled: b_state];
+    [o_wall_numofcols_stp setEnabled: b_state];
+    
+
+    [o_threshold_color_fld setStringValue: [[NSString stringWithFormat:@"%llx", config_GetInt(p_intf, "colorthres-color")] uppercaseString]];
+    [o_threshold_saturation_sld setIntValue: config_GetInt(p_intf, "colorthres-saturationthres")];
+    [o_threshold_saturation_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "colorthres-saturationthres")]];
+    [o_threshold_similarity_sld setIntValue: config_GetInt(p_intf, "colorthres-similaritythres")];
+    [o_threshold_similarity_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "colorthres-similaritythres")]];
     b_state = [o_threshold_ckb state];
     [o_threshold_color_fld setEnabled: b_state];
     [o_threshold_color_lbl setEnabled: b_state];
@@ -308,58 +397,58 @@ static VLCVideoEffects *_o_sharedInstance = nil;
     [o_threshold_saturation_lbl setEnabled: b_state];
     [o_threshold_similarity_sld setEnabled: b_state];
     [o_threshold_similarity_lbl setEnabled: b_state];
-    [o_sepia_fld setIntValue: config_GetInt( p_intf, "sepia-intensity" )];
+    [o_sepia_fld setIntValue: config_GetInt(p_intf, "sepia-intensity")];
     [o_sepia_fld setEnabled: [o_sepia_ckb state]];
     [o_sepia_lbl setEnabled: [o_sepia_ckb state]];
-    tmpChar = config_GetPsz( p_intf, "gradient-mode" );
+    tmpChar = config_GetPsz(p_intf, "gradient-mode");
     tmpString = [NSString stringWithUTF8String: tmpChar];
-    if( [tmpString isEqualToString:@"hough"] )
+    if ([tmpString isEqualToString:@"hough"])
         [o_gradient_mode_pop selectItemWithTag: 3];
-    else if( [tmpString isEqualToString:@"edge"] )
+    else if ([tmpString isEqualToString:@"edge"])
         [o_gradient_mode_pop selectItemWithTag: 2];
     else
         [o_gradient_mode_pop selectItemWithTag: 1];
-    FREENULL( tmpChar );
-    [o_gradient_cartoon_ckb setState: config_GetInt( p_intf, "gradient-cartoon" )];
-    [o_gradient_color_ckb setState: config_GetInt( p_intf, "gradient-type" )];
+    FREENULL(tmpChar);
+    [o_gradient_cartoon_ckb setState: config_GetInt(p_intf, "gradient-cartoon")];
+    [o_gradient_color_ckb setState: config_GetInt(p_intf, "gradient-type")];
     b_state = [o_gradient_ckb state];
     [o_gradient_mode_pop setEnabled: b_state];
     [o_gradient_mode_lbl setEnabled: b_state];
     [o_gradient_cartoon_ckb setEnabled: b_state];
     [o_gradient_color_ckb setEnabled: b_state];
-    [o_extract_fld setStringValue: [[NSString stringWithFormat:@"%llx", config_GetInt( p_intf, "extract-component" )] uppercaseString]];
+    [o_extract_fld setStringValue: [[NSString stringWithFormat:@"%llx", config_GetInt(p_intf, "extract-component")] uppercaseString]];
     [o_extract_fld setEnabled: [o_extract_ckb state]];
     [o_extract_lbl setEnabled: [o_extract_ckb state]];
-    [o_posterize_fld setIntValue: config_GetInt( p_intf, "posterize-level" )];
+    [o_posterize_fld setIntValue: config_GetInt(p_intf, "posterize-level")];
     [o_posterize_fld setEnabled: [o_posterize_ckb state]];
     [o_posterize_lbl setEnabled: [o_posterize_ckb state]];
-    [o_blur_sld setIntValue: config_GetInt( p_intf, "blur-factor" )];
-    [o_blur_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt( p_intf, "blur-factor" )]];
+    [o_blur_sld setIntValue: config_GetInt(p_intf, "blur-factor")];
+    [o_blur_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "blur-factor")]];
     [o_blur_sld setEnabled: [o_blur_ckb state]];
     [o_blur_lbl setEnabled: [o_blur_ckb state]];
 
-    tmpChar = config_GetPsz( p_intf, "marq-marquee" );
-    if( tmpChar )
-    {
+    tmpChar = config_GetPsz(p_intf, "marq-marquee");
+    if (tmpChar) {
         [o_addtext_text_fld setStringValue: [NSString stringWithUTF8String: tmpChar]];
-        FREENULL( tmpChar );
-    }
-    [o_addtext_pos_pop selectItemWithTag: config_GetInt( p_intf, "marq-position" )];
+        FREENULL(tmpChar);
+    } else
+        [o_addtext_text_fld setStringValue: @""];
+    [o_addtext_pos_pop selectItemWithTag: config_GetInt(p_intf, "marq-position")];
     b_state = [o_addtext_ckb state];
     [o_addtext_pos_pop setEnabled: b_state];
     [o_addtext_pos_lbl setEnabled: b_state];
     [o_addtext_text_lbl setEnabled: b_state];
     [o_addtext_text_fld setEnabled: b_state];
 
-    tmpChar = config_GetPsz( p_intf, "logo-file" );
-    if( tmpChar )
-    {
-       [o_addlogo_logo_fld setStringValue: [NSString stringWithUTF8String: tmpChar]];
-        FREENULL( tmpChar );
-    }
-    [o_addlogo_pos_pop selectItemWithTag: config_GetInt( p_intf, "logo-position" )];
-    [o_addlogo_transparency_sld setIntValue: config_GetInt( p_intf, "logo-opacity" )];
-    [o_addlogo_transparency_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt( p_intf, "logo-opacity" )]];
+    tmpChar = config_GetPsz(p_intf, "logo-file");
+    if (tmpChar) {
+        [o_addlogo_logo_fld setStringValue: [NSString stringWithUTF8String: tmpChar]];
+        FREENULL(tmpChar);
+    } else
+        [o_addlogo_logo_fld setStringValue: @""];
+    [o_addlogo_pos_pop selectItemWithTag: config_GetInt(p_intf, "logo-position")];
+    [o_addlogo_transparency_sld setIntValue: config_GetInt(p_intf, "logo-opacity")];
+    [o_addlogo_transparency_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "logo-opacity")]];
     b_state = [o_addlogo_ckb state];
     [o_addlogo_pos_pop setEnabled: b_state];
     [o_addlogo_pos_lbl setEnabled: b_state];
@@ -374,88 +463,65 @@ static VLCVideoEffects *_o_sharedInstance = nil;
     char *psz_string, *psz_parser;
     const char *psz_filter_type;
 
-    module_t *p_obj = module_find( psz_name );
-    if( !p_obj )
-    {
-        msg_Err( p_intf, "Unable to find filter module \"%s\".", psz_name );
+    module_t *p_obj = module_find(psz_name);
+    if (!p_obj) {
+        msg_Err(p_intf, "Unable to find filter module \"%s\".", psz_name);
         return;
     }
-    msg_Dbg( p_intf, "will set filter '%s'", psz_name );
+    msg_Dbg(p_intf, "will set filter '%s'", psz_name);
 
-    if( module_provides( p_obj, "video splitter" ) )
-    {
+    if (module_provides(p_obj, "video splitter")) {
         psz_filter_type = "video-splitter";
-    }
-    else if( module_provides( p_obj, "video filter2" ) )
-    {
+    } else if (module_provides(p_obj, "video filter2")) {
         psz_filter_type = "video-filter";
-    }
-    else if( module_provides( p_obj, "sub source" ) )
-    {
+    } else if (module_provides(p_obj, "sub source")) {
         psz_filter_type = "sub-source";
-    }
-    else if( module_provides( p_obj, "sub filter" ) )
-    {
+    } else if (module_provides(p_obj, "sub filter")) {
         psz_filter_type = "sub-filter";
-    }
-    else
-    {
-        msg_Err( p_intf, "Unknown video filter type." );
+    } else {
+        msg_Err(p_intf, "Unknown video filter type.");
         return;
     }
 
-    psz_string = config_GetPsz( p_intf, psz_filter_type );
+    psz_string = config_GetPsz(p_intf, psz_filter_type);
 
     if (b_on) {
-        if(! psz_string)
+        if (! psz_string)
             psz_string = psz_name;
-        else if( (NSInteger)strstr( psz_string, psz_name ) == NO )
+        else if ((NSInteger)strstr(psz_string, psz_name) == NO)
             psz_string = (char *)[[NSString stringWithFormat: @"%s:%s", psz_string, psz_name] UTF8String];
     } else {
-        if( !psz_string )
+        if (!psz_string)
             return;
 
-        psz_parser = strstr( psz_string, psz_name );
-        if( psz_parser )
-        {
-            if( *( psz_parser + strlen( psz_name ) ) == ':' )
-            {
-                memmove( psz_parser, psz_parser + strlen( psz_name ) + 1,
-                        strlen( psz_parser + strlen( psz_name ) + 1 ) + 1 );
-            }
-            else
-            {
+        psz_parser = strstr(psz_string, psz_name);
+        if (psz_parser) {
+            if (*(psz_parser + strlen(psz_name)) == ':') {
+                memmove(psz_parser, psz_parser + strlen(psz_name) + 1,
+                        strlen(psz_parser + strlen(psz_name) + 1) + 1);
+            } else {
                 *psz_parser = '\0';
             }
 
             /* Remove trailing : : */
-            if( strlen( psz_string ) > 0 &&
-               *( psz_string + strlen( psz_string ) -1 ) == ':' )
-            {
-                *( psz_string + strlen( psz_string ) -1 ) = '\0';
-            }
-        }
-        else
-        {
-            free( psz_string );
+            if (strlen(psz_string) > 0 && *(psz_string + strlen(psz_string) -1) == ':')
+                *(psz_string + strlen(psz_string) -1) = '\0';
+        } else {
+            free(psz_string);
             return;
         }
     }
-    config_PutPsz( p_intf, psz_filter_type, psz_string );
+    config_PutPsz(p_intf, psz_filter_type, psz_string);
 
     /* Try to set on the fly */
-    if( !strcmp( psz_filter_type, "video-splitter" ) )
-    {
-        playlist_t *p_playlist = pl_Get( p_intf );
-        var_SetString( p_playlist, psz_filter_type, psz_string );
-    }
-    else
-    {
+    if (!strcmp(psz_filter_type, "video-splitter")) {
+        playlist_t *p_playlist = pl_Get(p_intf);
+        var_SetString(p_playlist, psz_filter_type, psz_string);
+    } else {
         vout_thread_t *p_vout = getVout();
-        if( p_vout )
-        {
-            var_SetString( p_vout, psz_filter_type, psz_string );
-            vlc_object_release( p_vout );
+        if (p_vout) {
+            var_SetString(p_vout, psz_filter_type, psz_string);
+            vlc_object_release(p_vout);
         }
     }
 }
@@ -467,25 +533,24 @@ static VLCVideoEffects *_o_sharedInstance = nil;
     if (p_vout == NULL)
         return;
     else
-        vlc_object_release( p_vout );
-
-    vlc_object_t *p_filter = vlc_object_find_name( pl_Get(p_intf), psz_filter );
-    int i_type;
-    i_type = var_Type( p_filter, psz_name );
-    if( i_type == 0 )
-        i_type = config_GetType( p_intf, psz_name );
-
-    if( !(i_type & VLC_VAR_ISCOMMAND) )
-    {
-        msg_Warn( p_intf, "Brute-restarting filter '%s', because the last changed option isn't a command", psz_name );
-        [self setVideoFilter: psz_filter on: NO];
-        [self setVideoFilter: psz_filter on: YES];
+        vlc_object_release(p_vout);
+
+    vlc_object_t *p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
+    if (p_filter) {
+        int i_type;
+        i_type = var_Type(p_filter, psz_name);
+        if (i_type == 0)
+            i_type = config_GetType(p_intf, psz_name);
+
+        if (!(i_type & VLC_VAR_ISCOMMAND)) {
+            msg_Warn(p_intf, "Brute-restarting filter '%s', because the last changed option isn't a command", psz_name);
+            [self setVideoFilter: psz_filter on: NO];
+            [self setVideoFilter: psz_filter on: YES];
+        } else
+            msg_Dbg(p_intf, "restart not needed");
+
+        vlc_object_release(p_filter);
     }
-    else
-        msg_Dbg( p_intf, "restart not needed" );
-
-    if( p_filter )
-        vlc_object_release( p_filter );
 }
 
 - (void)setVideoFilterProperty: (char *)psz_name forFilter: (char *)psz_filter integer: (int)i_value
@@ -493,23 +558,22 @@ static VLCVideoEffects *_o_sharedInstance = nil;
     vout_thread_t *p_vout = getVout();
     vlc_object_t *p_filter;
 
-    if( p_vout == NULL ) {
-        config_PutInt( p_intf , psz_name , i_value );
-    } else {
-        p_filter = vlc_object_find_name( pl_Get(p_intf), psz_filter );
+    config_PutInt(p_intf , psz_name , i_value);
 
-        if(! p_filter ) {
-            msg_Err( p_intf, "we're unable to find the filter '%s'", psz_filter );
-            vlc_object_release( p_vout );
+    if (p_vout) {
+        p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
+
+        if (! p_filter) {
+            msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
+            vlc_object_release(p_vout);
             return;
         }
-        var_SetInteger( p_filter, psz_name, i_value );
-        config_PutInt( p_intf, psz_name, i_value );
-        vlc_object_release( p_vout );
-        vlc_object_release( p_filter );
-    }
+        var_SetInteger(p_filter, psz_name, i_value);
+        vlc_object_release(p_vout);
+        vlc_object_release(p_filter);
 
-    [self restartFilterIfNeeded:psz_filter option: psz_name];
+        [self restartFilterIfNeeded:psz_filter option: psz_name];
+    }
 }
 
 - (void)setVideoFilterProperty: (char *)psz_name forFilter: (char *)psz_filter float: (float)f_value
@@ -517,20 +581,19 @@ static VLCVideoEffects *_o_sharedInstance = nil;
     vout_thread_t *p_vout = getVout();
     vlc_object_t *p_filter;
 
-    if( p_vout == NULL ) {
-        config_PutFloat( p_intf , psz_name , f_value );
-    } else {
-        p_filter = vlc_object_find_name( pl_Get(p_intf), psz_filter );
+    config_PutFloat(p_intf , psz_name , f_value);
+
+    if (p_vout) {
+        p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
 
-        if(! p_filter ) {
-            msg_Err( p_intf, "we're unable to find the filter '%s'", psz_filter );
-            vlc_object_release( p_vout );
+        if (! p_filter) {
+            msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
+            vlc_object_release(p_vout);
             return;
         }
-        var_SetFloat( p_filter, psz_name, f_value );
-        config_PutFloat( p_intf, psz_name, f_value );
-        vlc_object_release( p_vout );
-        vlc_object_release( p_filter );
+        var_SetFloat(p_filter, psz_name, f_value);
+        vlc_object_release(p_vout);
+        vlc_object_release(p_filter);
 
         [self restartFilterIfNeeded:psz_filter option: psz_name];
     }
@@ -541,20 +604,19 @@ static VLCVideoEffects *_o_sharedInstance = nil;
     vout_thread_t *p_vout = getVout();
     vlc_object_t *p_filter;
 
-    if( p_vout == NULL ) {
-        config_PutPsz( p_intf, psz_name, EnsureUTF8(psz_value) );
-    } else {
-        p_filter = vlc_object_find_name( pl_Get(p_intf), psz_filter );
+    config_PutPsz(p_intf, psz_name, EnsureUTF8(psz_value));
+
+    if (p_vout) {
+        p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
 
-        if(! p_filter ) {
-            msg_Err( p_intf, "we're unable to find the filter '%s'", psz_filter );
-            vlc_object_release( p_vout );
+        if (! p_filter) {
+            msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
+            vlc_object_release(p_vout);
             return;
         }
-        var_SetString( p_filter, psz_name, EnsureUTF8(psz_value) );
-        config_PutPsz( p_intf, psz_name, EnsureUTF8(psz_value) );
-        vlc_object_release( p_vout );
-        vlc_object_release( p_filter );
+        var_SetString(p_filter, psz_name, EnsureUTF8(psz_value));
+        vlc_object_release(p_vout);
+        vlc_object_release(p_filter);
 
         [self restartFilterIfNeeded:psz_filter option: psz_name];
     }
@@ -565,22 +627,222 @@ static VLCVideoEffects *_o_sharedInstance = nil;
     vout_thread_t *p_vout = getVout();
     vlc_object_t *p_filter;
 
-    if( p_vout == NULL ) {
-        config_PutInt( p_intf, psz_name, b_value );
-    } else {
-        p_filter = vlc_object_find_name( pl_Get(p_intf), psz_filter );
+    config_PutInt(p_intf, psz_name, b_value);
+
+    if (p_vout) {
+        p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
 
-        if(! p_filter ) {
-            msg_Err( p_intf, "we're unable to find the filter '%s'", psz_filter );
-            vlc_object_release( p_vout );
+        if (! p_filter) {
+            msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
+            vlc_object_release(p_vout);
             return;
         }
-        var_SetBool( p_filter, psz_name, b_value );
-        config_PutInt( p_intf, psz_name, b_value );
-        vlc_object_release( p_vout );
+        var_SetBool(p_filter, psz_name, b_value);
+        vlc_object_release(p_vout);
     }
 }
 
+- (NSString *)generateProfileString
+{
+    return [NSString stringWithFormat:@"%s;%s;%lli;%f;%f;%f;%f;%f;%lli;%f;%s;%lli;%lli;%lli;%lli;%lli;%lli;%lli;%s;%lli;%lli;%lli;%lli;%lli;%s;%lli;%s;%lli;%lli;%lli;%lli;%lli",
+            vlc_b64_encode(config_GetPsz(p_intf, "video-filter")),
+            vlc_b64_encode(config_GetPsz(p_intf, "sub-source")),
+            config_GetInt(p_intf, "hue"),
+            config_GetFloat(p_intf, "contrast"),
+            config_GetFloat(p_intf, "brightness"),
+            config_GetFloat(p_intf, "saturation"),
+            config_GetFloat(p_intf, "gamma"),
+            config_GetFloat(p_intf, "sharpen-sigma"),
+            config_GetInt(p_intf, "gradfun-radius"),
+            config_GetFloat(p_intf, "grain-variance"),
+            vlc_b64_encode(config_GetPsz(p_intf, "transform-type")),
+            config_GetInt(p_intf, "puzzle-rows"),
+            config_GetInt(p_intf, "puzzle-cols"),
+            config_GetInt(p_intf, "puzzle-black-slot"),
+            config_GetInt(p_intf, "colorthres-color"),
+            config_GetInt(p_intf, "colorthres-saturationthres"),
+            config_GetInt(p_intf, "colorthres-similaritythres"),
+            config_GetInt(p_intf, "sepia-intensity"),
+            vlc_b64_encode(config_GetPsz(p_intf, "gradient-mode")),
+            config_GetInt(p_intf, "gradient-cartoon"),
+            config_GetInt(p_intf, "gradient-type"),
+            config_GetInt(p_intf, "extract-component"),
+            config_GetInt(p_intf, "posterize-level"),
+            config_GetInt(p_intf, "blur-factor"),
+            vlc_b64_encode(config_GetPsz(p_intf, "marq-marquee")),
+            config_GetInt(p_intf, "marq-position"),
+            vlc_b64_encode(config_GetPsz(p_intf, "logo-file")),
+            config_GetInt(p_intf, "logo-position"),
+            config_GetInt(p_intf, "logo-opacity"),
+            config_GetInt(p_intf, "clone-count"),
+            config_GetInt(p_intf, "wall-rows"),
+            config_GetInt(p_intf, "wall-cols")
+            ];
+}
+
+#pragma mark -
+#pragma mark generic UI code
+- (IBAction)toggleWindow:(id)sender
+{
+    if ([o_window isVisible])
+        [o_window orderOut:sender];
+    else
+        [o_window makeKeyAndOrderFront:sender];
+}
+
+- (IBAction)profileSelectorAction:(id)sender
+{
+    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+    NSUInteger selectedProfile = [o_profile_pop indexOfSelectedItem];
+
+    /* disable all current video filters, if a vout is available */
+    vout_thread_t *p_vout = getVout();
+    if (p_vout) {
+        var_SetString(p_vout, "video-filter", "");
+        var_SetString(p_vout, "sub-source", "");
+        vlc_object_release(p_vout);
+    }
+
+    /* fetch preset */
+    NSArray *items = [[[defaults objectForKey:@"VideoEffectProfiles"] objectAtIndex:selectedProfile] componentsSeparatedByString:@";"];
+
+    /* filter handling */
+    NSString *tempString = [NSString stringWithFormat:@"%s", vlc_b64_decode([[items objectAtIndex:0] UTF8String])];
+    NSArray *tempArray;
+    NSUInteger count;
+    /* enable the new filters */
+    if ([tempString length] > 0) {
+        tempArray = [tempString componentsSeparatedByString:@":"];
+        count = [tempArray count];
+        for (NSUInteger x = 0; x < count; x++)
+            [self setVideoFilter:(char *)[[tempArray objectAtIndex:x] UTF8String] on:YES];
+    }
+    config_PutPsz(p_intf,"video-filter",[tempString UTF8String]);
+    tempString = [NSString stringWithFormat:@"%s", vlc_b64_decode([[items objectAtIndex:1] UTF8String])];
+    /* enable another round of new filters */
+    if ([tempString length] > 0) {
+        tempArray = [tempString componentsSeparatedByString:@":"];
+        count = [tempArray count];
+        for (NSUInteger x = 0; x < count; x++)
+            [self setVideoFilter:(char *)[[tempArray objectAtIndex:x] UTF8String] on:YES];
+    }
+    config_PutPsz(p_intf,"sub-source",[tempString UTF8String]);
+
+    /* try to set filter values on-the-fly and store them appropriately */
+    [self setVideoFilterProperty:"hue" forFilter:"adjust" integer:[[items objectAtIndex:2] intValue]];
+    [self setVideoFilterProperty:"contrast" forFilter:"adjust" float:[[items objectAtIndex:3] floatValue]];
+    [self setVideoFilterProperty:"brightness" forFilter:"adjust" float:[[items objectAtIndex:4] floatValue]];
+    [self setVideoFilterProperty:"saturation" forFilter:"adjust" float:[[items objectAtIndex:5] floatValue]];
+    [self setVideoFilterProperty:"gamma" forFilter:"adjust" float:[[items objectAtIndex:6] floatValue]];
+    [self setVideoFilterProperty:"sharpen-sigma" forFilter:"sharpen" float:[[items objectAtIndex:7] floatValue]];
+    [self setVideoFilterProperty:"gradfun-radius" forFilter:"gradfun" integer:[[items objectAtIndex:8] intValue]];
+    [self setVideoFilterProperty:"grain-variance" forFilter:"grain" float:[[items objectAtIndex:9] floatValue]];
+    [self setVideoFilterProperty:"transform-type" forFilter:"transform" string:vlc_b64_decode([[items objectAtIndex:10] UTF8String])];
+    [self setVideoFilterProperty:"puzzle-rows" forFilter:"puzzle" integer:[[items objectAtIndex:11] intValue]];
+    [self setVideoFilterProperty:"puzzle-cols" forFilter:"puzzle" integer:[[items objectAtIndex:12] intValue]];
+    [self setVideoFilterProperty:"puzzle-black-slot" forFilter:"puzzle" boolean:[[items objectAtIndex:13] intValue]];
+    [self setVideoFilterProperty:"colorthres-color" forFilter:"colorthres" integer:[[items objectAtIndex:14] intValue]];
+    [self setVideoFilterProperty:"colorthres-saturationthres" forFilter:"colorthres" integer:[[items objectAtIndex:15] intValue]];
+    [self setVideoFilterProperty:"colorthres-similaritythres" forFilter:"colorthres" integer:[[items objectAtIndex:16] intValue]];
+    [self setVideoFilterProperty:"sepia-intensity" forFilter:"sepia" integer:[[items objectAtIndex:17] intValue]];
+    [self setVideoFilterProperty:"gradient-mode" forFilter:"gradient" string:vlc_b64_decode([[items objectAtIndex:18] UTF8String])];
+    [self setVideoFilterProperty:"gradient-cartoon" forFilter:"gradient" integer:[[items objectAtIndex:19] intValue]];
+    [self setVideoFilterProperty:"gradient-type" forFilter:"gradient" integer:[[items objectAtIndex:20] intValue]];
+    [self setVideoFilterProperty:"extract-component" forFilter:"extract" integer:[[items objectAtIndex:21] intValue]];
+    [self setVideoFilterProperty:"posterize-level" forFilter:"posterize" integer:[[items objectAtIndex:22] intValue]];
+    [self setVideoFilterProperty:"blur-factor" forFilter:"motionblur" integer:[[items objectAtIndex:23] intValue]];
+    [self setVideoFilterProperty:"marq-marquee" forFilter:"marq" string:vlc_b64_decode([[items objectAtIndex:24] UTF8String])];
+    [self setVideoFilterProperty:"marq-position" forFilter:"marq" integer:[[items objectAtIndex:25] intValue]];
+    [self setVideoFilterProperty:"logo-file" forFilter:"logo" string:vlc_b64_decode([[items objectAtIndex:26] UTF8String])];
+    [self setVideoFilterProperty:"logo-position" forFilter:"logo" integer:[[items objectAtIndex:27] intValue]];
+    [self setVideoFilterProperty:"logo-opacity" forFilter:"logo" integer:[[items objectAtIndex:28] intValue]];
+    [self setVideoFilterProperty:"clone-count" forFilter:"clone" integer:[[items objectAtIndex:29] intValue]];
+    [self setVideoFilterProperty:"wall-rows" forFilter:"wall" integer:[[items objectAtIndex:30] intValue]];
+    [self setVideoFilterProperty:"wall-cols" forFilter:"wall" integer:[[items objectAtIndex:31] intValue]];
+
+    [defaults setInteger:selectedProfile forKey:@"VideoEffectSelectedProfile"];
+    [defaults synchronize];
+
+    [self resetValues];
+}
+
+- (IBAction)addProfile:(id)sender
+{
+    /* show panel */
+    VLCEnterTextPanel * panel = [VLCEnterTextPanel sharedInstance];
+    [panel setTitle: _NS("Save current selection as new profile")];
+    [panel setSubTitle: _NS("Enter a name for the new profile:")];
+    [panel setCancelButtonLabel: _NS("Cancel")];
+    [panel setOKButtonLabel: _NS("Save")];
+    [panel setTarget:self];
+
+    [panel runModalForWindow:o_window];
+}
+
+- (void)panel:(VLCEnterTextPanel *)panel returnValue:(NSUInteger)value text:(NSString *)text
+{
+    if (value == NSOKButton) {
+        if ([text length] > 0) {
+            /* fetch all the current settings in a uniform string */
+            NSString *newProfile = [self generateProfileString];
+
+            /* add string to user defaults as well as a label */
+            NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+            NSMutableArray *workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"VideoEffectProfiles"]];
+            [workArray addObject:newProfile];
+            [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfiles"];
+            [defaults setInteger:[workArray count] - 1 forKey:@"VideoEffectSelectedProfile"];
+            [workArray release];
+            workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"VideoEffectProfileNames"]];
+            [workArray addObject:text];
+            [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfileNames"];
+            [workArray release];
+
+            /* save defaults */
+            [defaults synchronize];
+        }
+    }
+
+    /* refresh UI */
+    [self resetProfileSelector];
+}
+
+- (IBAction)removeProfile:(id)sender
+{
+    /* show panel */
+    VLCSelectItemInPopupPanel * panel = [VLCSelectItemInPopupPanel sharedInstance];
+    [panel setTitle:_NS("Remove a preset")];
+    [panel setSubTitle:_NS("Select the preset you would like to remove:")];
+    [panel setOKButtonLabel:_NS("Remove")];
+    [panel setCancelButtonLabel:_NS("Cancel")];
+    [panel setPopupButtonContent:[[NSUserDefaults standardUserDefaults] objectForKey:@"VideoEffectProfileNames"]];
+    [panel setTarget:self];
+
+    [panel runModalForWindow:o_window];
+}
+
+- (void)panel:(VLCSelectItemInPopupPanel *)panel returnValue:(NSUInteger)value item:(NSUInteger)item
+{
+    if (value == NSOKButton) {
+        /* remove selected profile from settings */
+        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+        NSMutableArray *workArray = [defaults objectForKey:@"VideoEffectProfiles"];
+        [workArray removeObjectAtIndex:item];
+        [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfiles"];
+        [workArray release];
+        workArray = [defaults objectForKey:@"VideoEffectProfileNames"];
+        [workArray removeObjectAtIndex:item];
+        [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfileNames"];
+        [workArray release];
+
+        /* save defaults */
+        [defaults synchronize];
+    }
+
+    /* refresh UI */
+    [self resetProfileSelector];
+}
+
 #pragma mark -
 #pragma mark basic
 - (IBAction)enableAdjust:(id)sender
@@ -604,18 +866,18 @@ static VLCVideoEffects *_o_sharedInstance = nil;
 
 - (IBAction)adjustSliderChanged:(id)sender
 {
-    if( sender == o_adjust_brightness_sld )
+    if (sender == o_adjust_brightness_sld)
         [self setVideoFilterProperty: "brightness" forFilter: "adjust" float: [o_adjust_brightness_sld floatValue]];
-    else if( sender == o_adjust_contrast_sld )
+    else if (sender == o_adjust_contrast_sld)
         [self setVideoFilterProperty: "contrast" forFilter: "adjust" float: [o_adjust_contrast_sld floatValue]];
-    else if( sender == o_adjust_gamma_sld )
+    else if (sender == o_adjust_gamma_sld)
         [self setVideoFilterProperty: "gamma" forFilter: "adjust" float: [o_adjust_gamma_sld floatValue]];
-    else if( sender == o_adjust_hue_sld )
+    else if (sender == o_adjust_hue_sld)
         [self setVideoFilterProperty: "hue" forFilter: "adjust" integer: [o_adjust_hue_sld intValue]];
-    else if( sender == o_adjust_saturation_sld )
+    else if (sender == o_adjust_saturation_sld)
         [self setVideoFilterProperty: "saturation" forFilter: "adjust" float: [o_adjust_saturation_sld floatValue]];
 
-    if( sender == o_adjust_hue_sld )
+    if (sender == o_adjust_hue_sld)
         [o_adjust_hue_sld setToolTip: [NSString stringWithFormat:@"%i", [o_adjust_hue_sld intValue]]];
     else
         [sender setToolTip: [NSString stringWithFormat:@"%0.3f", [sender floatValue]]];
@@ -623,8 +885,7 @@ static VLCVideoEffects *_o_sharedInstance = nil;
 
 - (IBAction)enableAdjustBrightnessThreshold:(id)sender
 {
-    if (sender == o_adjust_reset_btn)
-    {
+    if (sender == o_adjust_reset_btn) {
         [o_adjust_brightness_sld setFloatValue: 1.0];
         [o_adjust_contrast_sld setFloatValue: 1.0];
         [o_adjust_gamma_sld setFloatValue: 1.0];
@@ -640,9 +901,8 @@ static VLCVideoEffects *_o_sharedInstance = nil;
         [self setVideoFilterProperty: "gamma" forFilter: "adjust" float: 1.0];
         [self setVideoFilterProperty: "hue" forFilter: "adjust" integer: 0.0];
         [self setVideoFilterProperty: "saturation" forFilter: "adjust" float: 1.0];
-    }
-    else
-        config_PutInt( p_intf, "brightness-threshold", [o_adjust_brightness_ckb state] );
+    } else
+        config_PutInt(p_intf, "brightness-threshold", [o_adjust_brightness_ckb state]);
 }
 
 - (IBAction)enableSharpen:(id)sender
@@ -694,51 +954,47 @@ static VLCVideoEffects *_o_sharedInstance = nil;
 #pragma mark -
 #pragma mark crop
 
-#define updateopposite( giver, taker ) \
+#define updateopposite(giver, taker) \
     if (sender == giver) \
         [taker setIntValue: [giver intValue]]
 
 - (IBAction)cropObjectChanged:(id)sender
 {
-    updateopposite( o_crop_top_fld, o_crop_top_stp );
-    updateopposite( o_crop_top_stp, o_crop_top_fld );
-    updateopposite( o_crop_left_fld, o_crop_left_stp );
-    updateopposite( o_crop_left_stp, o_crop_left_fld );
-    updateopposite( o_crop_right_fld, o_crop_right_stp );
-    updateopposite( o_crop_right_stp, o_crop_right_fld );
-    updateopposite( o_crop_bottom_fld, o_crop_bottom_stp );
-    updateopposite( o_crop_bottom_stp, o_crop_bottom_fld );
-
-    if( [o_crop_sync_top_bottom_ckb state] ) {
-        if (sender == o_crop_top_fld || sender == o_crop_top_stp ) {
+    updateopposite(o_crop_top_fld, o_crop_top_stp);
+    updateopposite(o_crop_top_stp, o_crop_top_fld);
+    updateopposite(o_crop_left_fld, o_crop_left_stp);
+    updateopposite(o_crop_left_stp, o_crop_left_fld);
+    updateopposite(o_crop_right_fld, o_crop_right_stp);
+    updateopposite(o_crop_right_stp, o_crop_right_fld);
+    updateopposite(o_crop_bottom_fld, o_crop_bottom_stp);
+    updateopposite(o_crop_bottom_stp, o_crop_bottom_fld);
+
+    if ([o_crop_sync_top_bottom_ckb state]) {
+        if (sender == o_crop_top_fld || sender == o_crop_top_stp) {
             [o_crop_bottom_fld setIntValue: [o_crop_top_fld intValue]];
             [o_crop_bottom_stp setIntValue: [o_crop_top_fld intValue]];
-        }
-        else
-        {
+        } else {
             [o_crop_top_fld setIntValue: [o_crop_bottom_fld intValue]];
             [o_crop_top_stp setIntValue: [o_crop_bottom_fld intValue]];
         }
     }
-    if( [o_crop_sync_left_right_ckb state] ) {
-        if (sender == o_crop_left_fld || sender == o_crop_left_stp ) {
+    if ([o_crop_sync_left_right_ckb state]) {
+        if (sender == o_crop_left_fld || sender == o_crop_left_stp) {
             [o_crop_right_fld setIntValue: [o_crop_left_fld intValue]];
             [o_crop_right_stp setIntValue: [o_crop_left_fld intValue]];
-        }
-        else
-        {
+        } else {
             [o_crop_left_fld setIntValue: [o_crop_right_fld intValue]];
             [o_crop_left_stp setIntValue: [o_crop_right_fld intValue]];
         }
     }
 
     vout_thread_t *p_vout = getVout();
-    if( p_vout ) {
-        var_SetInteger( p_vout, "crop-top", [o_crop_top_fld intValue] );
-        var_SetInteger( p_vout, "crop-bottom", [o_crop_bottom_fld intValue] );
-        var_SetInteger( p_vout, "crop-left", [o_crop_left_fld intValue] );
-        var_SetInteger( p_vout, "crop-right", [o_crop_right_fld intValue] );
-        vlc_object_release( p_vout );
+    if (p_vout) {
+        var_SetInteger(p_vout, "crop-top", [o_crop_top_fld intValue]);
+        var_SetInteger(p_vout, "crop-bottom", [o_crop_bottom_fld intValue]);
+        var_SetInteger(p_vout, "crop-left", [o_crop_left_fld intValue]);
+        var_SetInteger(p_vout, "crop-right", [o_crop_right_fld intValue]);
+        vlc_object_release(p_vout);
     }
 }
 
@@ -756,9 +1012,9 @@ static VLCVideoEffects *_o_sharedInstance = nil;
 {
     NSInteger tag = [[o_transform_pop selectedItem] tag];
     char * psz_string = (char *)[[NSString stringWithFormat:@"%li", tag] UTF8String];
-    if( tag == 1 )
+    if (tag == 1)
         psz_string = (char *)"hflip";
-    else if( tag == 2 )
+    else if (tag == 2)
         psz_string = (char *)"vflip";
 
     [self setVideoFilterProperty: "transform-type" forFilter: "transform" string: psz_string];
@@ -783,14 +1039,58 @@ static VLCVideoEffects *_o_sharedInstance = nil;
 
 - (IBAction)puzzleModifierChanged:(id)sender
 {
-    if( sender == o_puzzle_blackslot_ckb )
+    if (sender == o_puzzle_blackslot_ckb)
         [self setVideoFilterProperty: "puzzle-black-slot" forFilter: "puzzle" boolean: [o_puzzle_blackslot_ckb state]];
-    else if( sender == o_puzzle_columns_fld )
+    else if (sender == o_puzzle_columns_fld)
         [self setVideoFilterProperty: "puzzle-cols" forFilter: "puzzle" integer: [o_puzzle_columns_fld intValue]];
     else
         [self setVideoFilterProperty: "puzzle-rows" forFilter: "puzzle" integer: [o_puzzle_rows_fld intValue]];
 }
 
+- (IBAction)enableClone:(id)sender
+{
+    BOOL b_state = [o_clone_ckb state];
+
+    if (b_state && [o_wall_ckb state]) {
+        [o_wall_ckb setState: NSOffState];
+        [self enableWall: o_wall_ckb];
+    }
+
+    [self setVideoFilter: "clone" on: b_state];
+    [o_clone_number_lbl setEnabled: b_state];
+    [o_clone_number_fld setEnabled: b_state];
+    [o_clone_number_stp setEnabled: b_state];
+}
+
+- (IBAction)cloneModifierChanged:(id)sender
+{
+    [self setVideoFilterProperty: "clone-count" forFilter: "clone" integer: [o_clone_number_fld intValue]];
+}
+
+- (IBAction)enableWall:(id)sender
+{
+    BOOL b_state = [o_wall_ckb state];
+
+    if (b_state && [o_clone_ckb state]) {
+        [o_clone_ckb setState: NSOffState];
+        [self enableClone: o_clone_ckb];
+    }
+
+    [self setVideoFilter: "wall" on: b_state];
+    [o_wall_numofcols_fld setEnabled: b_state];
+    [o_wall_numofcols_stp setEnabled: b_state];
+    [o_wall_numofcols_lbl setEnabled: b_state];
+    
+    [o_wall_numofrows_fld setEnabled: b_state];
+    [o_wall_numofrows_stp setEnabled: b_state];
+    [o_wall_numofrows_lbl setEnabled: b_state];
+}
+
+- (IBAction)wallModifierChanged:(id)sender
+{
+    [self setVideoFilterProperty: "wall-cols" forFilter: "wall" integer: [o_wall_numofcols_fld intValue]];
+    [self setVideoFilterProperty: "wall-rows" forFilter: "wall" integer: [o_wall_numofrows_fld intValue]];
+}
 
 #pragma mark -
 #pragma mark color
@@ -809,15 +1109,12 @@ static VLCVideoEffects *_o_sharedInstance = nil;
 
 - (IBAction)thresholdModifierChanged:(id)sender
 {
-    if( sender == o_threshold_color_fld )
+    if (sender == o_threshold_color_fld)
         [self setVideoFilterProperty: "colorthres-color" forFilter: "colorthres" integer: [o_threshold_color_fld intValue]];
-    else if( sender == o_threshold_saturation_sld )
-    {
+    else if (sender == o_threshold_saturation_sld) {
         [self setVideoFilterProperty: "colorthres-saturationthres" forFilter: "colorthres" integer: [o_threshold_saturation_sld intValue]];
         [o_threshold_saturation_sld setToolTip: [NSString stringWithFormat:@"%i", [o_threshold_saturation_sld intValue]]];
-    }
-    else
-    {
+    } else {
         [self setVideoFilterProperty: "colorthres-similaritythres" forFilter: "colorthres" integer: [o_threshold_similarity_sld intValue]];
         [o_threshold_similarity_sld setToolTip: [NSString stringWithFormat:@"%i", [o_threshold_similarity_sld intValue]]];
     }
@@ -855,15 +1152,14 @@ static VLCVideoEffects *_o_sharedInstance = nil;
 
 - (IBAction)gradientModifierChanged:(id)sender
 {
-    if( sender == o_gradient_mode_pop ) {
-        if( [[o_gradient_mode_pop selectedItem] tag] == 3 )
+    if (sender == o_gradient_mode_pop) {
+        if ([[o_gradient_mode_pop selectedItem] tag] == 3)
             [self setVideoFilterProperty: "gradient-mode" forFilter: "gradient" string: "hough"];
-        else if( [[o_gradient_mode_pop selectedItem] tag] == 2 )
+        else if ([[o_gradient_mode_pop selectedItem] tag] == 2)
             [self setVideoFilterProperty: "gradient-mode" forFilter: "gradient" string: "edge"];
         else
             [self setVideoFilterProperty: "gradient-mode" forFilter: "gradient" string: "gradient"];
-    }
-    else if( sender == o_gradient_color_ckb )
+    } else if (sender == o_gradient_color_ckb)
         [self setVideoFilterProperty: "gradient-type" forFilter: "gradient" integer: [o_gradient_color_ckb state]];
     else
         [self setVideoFilterProperty: "gradient-cartoon" forFilter: "gradient" boolean: [o_gradient_cartoon_ckb state]];
@@ -898,7 +1194,7 @@ static VLCVideoEffects *_o_sharedInstance = nil;
 
 - (IBAction)posterizeModifierChanged:(id)sender
 {
-    [self setVideoFilterProperty: "posterize-level" forFilter: "posterize" integer: [o_extract_fld intValue]];
+    [self setVideoFilterProperty: "posterize-level" forFilter: "posterize" integer: [o_posterize_fld intValue]];
 }
 
 - (IBAction)enableBlur:(id)sender
@@ -978,8 +1274,7 @@ static VLCVideoEffects *_o_sharedInstance = nil;
         [self setVideoFilterProperty: "logo-file" forFilter: "logo" string: (char *)[[o_addlogo_logo_fld stringValue] UTF8String]];
     else if (sender == o_addlogo_pos_pop)
         [self setVideoFilterProperty: "logo-position" forFilter: "logo" integer: [[o_addlogo_pos_pop selectedItem] tag]];
-    else
-    {
+    else {
         [self setVideoFilterProperty: "logo-opacity" forFilter: "logo" integer: [o_addlogo_transparency_sld intValue]];
         [o_addlogo_transparency_sld setToolTip: [NSString stringWithFormat:@"%i", [o_addlogo_transparency_sld intValue]]];
     }