]> git.sesse.net Git - vlc/blob - modules/gui/macosx/VideoEffects.m
025467fe59a9c63d69dc036d2c884eb0046d46d4
[vlc] / modules / gui / macosx / VideoEffects.m
1 /*****************************************************************************
2  * VideoEffects.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2011-2012 Felix Paul Kühne
5  * $Id$
6  *
7  * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #import "CompatibilityFixes.h"
25 #import "intf.h"
26 #import <vlc_common.h>
27 #import <vlc_modules.h>
28 #import <vlc_charset.h>
29 #import <vlc_strings.h>
30 #import "VideoEffects.h"
31 #import "SharedDialogs.h"
32
33 @interface VLCVideoEffects (Internal)
34 - (void)resetProfileSelector;
35 @end
36
37 #pragma mark -
38 #pragma mark Initialization
39
40 @implementation VLCVideoEffects
41 static VLCVideoEffects *_o_sharedInstance = nil;
42
43 @synthesize cropLeftValue, cropTopValue, cropRightValue, cropBottomValue;
44 @synthesize puzzleRowsValue, puzzleColumnsValue;
45 @synthesize wallRowsValue, wallColumnsValue;
46 @synthesize cloneValue;
47 @synthesize sepiaValue;
48 @synthesize posterizeValue;
49
50 + (VLCVideoEffects *)sharedInstance
51 {
52     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
53 }
54
55 + (void)initialize
56 {
57     NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:@[@";;;0;1.000000;1.000000;1.000000;1.000000;0.050000;16;2.000000;OTA=;4;4;16711680;20;15;120;Z3JhZGllbnQ=;1;0;16711680;6;80;VkxD;-1;;-1;255;2;3;3"], @"VideoEffectProfiles",
58                                  @[_NS("Default")], @"VideoEffectProfileNames", nil];
59     [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
60 }
61
62 - (id)init
63 {
64     if (_o_sharedInstance)
65         [self dealloc];
66     else {
67         p_intf = VLCIntf;
68         i_old_profile_index = -1;
69         _o_sharedInstance = [super init];
70     }
71
72     return _o_sharedInstance;
73 }
74
75 - (void)awakeFromNib
76 {
77     [o_window setTitle: _NS("Video Effects")];
78     [o_window setExcludedFromWindowsMenu:YES];
79     if (!OSX_SNOW_LEOPARD)
80         [o_window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
81
82     [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"basic"]] setLabel:_NS("Basic")];
83     [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"crop"]] setLabel:_NS("Crop")];
84     [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"geometry"]] setLabel:_NS("Geometry")];
85     [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"color"]] setLabel:_NS("Color")];
86     [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"misc"]] setLabel:_NS("Miscellaneous")];
87
88     [self resetProfileSelector];
89
90     [o_adjust_ckb setTitle:_NS("Image Adjust")];
91     [o_adjust_hue_lbl setStringValue:_NS("Hue")];
92     [o_adjust_contrast_lbl setStringValue:_NS("Contrast")];
93     [o_adjust_brightness_lbl setStringValue:_NS("Brightness")];
94     [o_adjust_brightness_ckb setTitle:_NS("Brightness Threshold")];
95     [o_adjust_saturation_lbl setStringValue:_NS("Saturation")];
96     [o_adjust_gamma_lbl setStringValue:_NS("Gamma")];
97     [o_adjust_reset_btn setTitle: _NS("Reset")];
98     [o_sharpen_ckb setTitle:_NS("Sharpen")];
99     [o_sharpen_lbl setStringValue:_NS("Sigma")];
100     [o_banding_ckb setTitle:_NS("Banding removal")];
101     [o_banding_lbl setStringValue:_NS("Radius")];
102     [o_grain_ckb setTitle:_NS("Film Grain")];
103     [o_grain_lbl setStringValue:_NS("Variance")];
104     [o_crop_top_lbl setStringValue:_NS("Top")];
105     [o_crop_left_lbl setStringValue:_NS("Left")];
106     [o_crop_right_lbl setStringValue:_NS("Right")];
107     [o_crop_bottom_lbl setStringValue:_NS("Bottom")];
108     [o_crop_sync_top_bottom_ckb setTitle:_NS("Synchronize top and bottom")];
109     [o_crop_sync_left_right_ckb setTitle:_NS("Synchronize left and right")];
110
111     [o_transform_ckb setTitle:_NS("Transform")];
112     [o_transform_pop removeAllItems];
113     [o_transform_pop addItemWithTitle: _NS("Rotate by 90 degrees")];
114     [[o_transform_pop lastItem] setTag: 90];
115     [o_transform_pop addItemWithTitle: _NS("Rotate by 180 degrees")];
116     [[o_transform_pop lastItem] setTag: 180];
117     [o_transform_pop addItemWithTitle: _NS("Rotate by 270 degrees")];
118     [[o_transform_pop lastItem] setTag: 270];
119     [o_transform_pop addItemWithTitle: _NS("Flip horizontally")];
120     [[o_transform_pop lastItem] setTag: 1];
121     [o_transform_pop addItemWithTitle: _NS("Flip vertically")];
122     [[o_transform_pop lastItem] setTag: 2];
123     [o_zoom_ckb setTitle:_NS("Magnification/Zoom")];
124     [o_puzzle_ckb setTitle:_NS("Puzzle game")];
125     [o_puzzle_rows_lbl setStringValue:_NS("Rows")];
126     [o_puzzle_columns_lbl setStringValue:_NS("Columns")];
127     [o_clone_ckb setTitle:_NS("Clone")];
128     [o_clone_number_lbl setStringValue:_NS("Number of clones")];
129     [o_wall_ckb setTitle:_NS("Wall")];
130     [o_wall_numofrows_lbl setStringValue:_NS("Rows")];
131     [o_wall_numofcols_lbl setStringValue:_NS("Columns")];
132
133     [o_threshold_ckb setTitle:_NS("Color threshold")];
134     [o_threshold_color_lbl setStringValue:_NS("Color")];
135     [o_threshold_saturation_lbl setStringValue:_NS("Saturation")];
136     [o_threshold_similarity_lbl setStringValue:_NS("Similarity")];
137     [o_sepia_ckb setTitle:_NS("Sepia")];
138     [o_sepia_lbl setStringValue:_NS("Intensity")];
139     [o_noise_ckb setTitle:_NS("Noise")];
140     [o_gradient_ckb setTitle:_NS("Gradient")];
141     [o_gradient_mode_lbl setStringValue:_NS("Mode")];
142     [o_gradient_mode_pop removeAllItems];
143     [o_gradient_mode_pop addItemWithTitle: _NS("Gradient")];
144     [[o_gradient_mode_pop lastItem] setTag: 1];
145     [o_gradient_mode_pop addItemWithTitle: _NS("Edge")];
146     [[o_gradient_mode_pop lastItem] setTag: 2];
147     [o_gradient_mode_pop addItemWithTitle: _NS("Hough")];
148     [[o_gradient_mode_pop lastItem] setTag: 3];
149     [o_gradient_color_ckb setTitle:_NS("Color")];
150     [o_gradient_cartoon_ckb setTitle:_NS("Cartoon")];
151     [o_extract_ckb setTitle:_NS("Color extraction")];
152     [o_extract_lbl setStringValue:_NS("Color")];
153     [o_invert_ckb setTitle:_NS("Invert colors")];
154     [o_posterize_ckb setTitle:_NS("Posterize")];
155     [o_posterize_lbl setStringValue:_NS("Posterize level")];
156     [o_blur_ckb setTitle:_NS("Motion blur")];
157     [o_blur_lbl setStringValue:_NS("Factor")];
158     [o_motiondetect_ckb setTitle:_NS("Motion Detect")];
159     [o_watereffect_ckb setTitle:_NS("Water effect")];
160     [o_waves_ckb setTitle:_NS("Waves")];
161     [o_psychedelic_ckb setTitle:_NS("Psychedelic")];
162     [o_anaglyph_ckb setTitle:_NS("Anaglyph")];
163
164     [o_addtext_ckb setTitle:_NS("Add text")];
165     [o_addtext_text_lbl setStringValue:_NS("Text")];
166     [o_addtext_pos_lbl setStringValue:_NS("Position")];
167     [o_addtext_pos_pop removeAllItems];
168     [o_addtext_pos_pop addItemWithTitle: _NS("Center")];
169     [[o_addtext_pos_pop lastItem] setTag: 0];
170     [o_addtext_pos_pop addItemWithTitle: _NS("Left")];
171     [[o_addtext_pos_pop lastItem] setTag: 1];
172     [o_addtext_pos_pop addItemWithTitle: _NS("Right")];
173     [[o_addtext_pos_pop lastItem] setTag: 2];
174     [o_addtext_pos_pop addItemWithTitle: _NS("Top")];
175     [[o_addtext_pos_pop lastItem] setTag: 4];
176     [o_addtext_pos_pop addItemWithTitle: _NS("Bottom")];
177     [[o_addtext_pos_pop lastItem] setTag: 8];
178     [o_addtext_pos_pop addItemWithTitle: _NS("Top-Left")];
179     [[o_addtext_pos_pop lastItem] setTag: 5];
180     [o_addtext_pos_pop addItemWithTitle: _NS("Top-Right")];
181     [[o_addtext_pos_pop lastItem] setTag: 6];
182     [o_addtext_pos_pop addItemWithTitle: _NS("Bottom-Left")];
183     [[o_addtext_pos_pop lastItem] setTag: 9];
184     [o_addtext_pos_pop addItemWithTitle: _NS("Bottom-Right")];
185     [[o_addtext_pos_pop lastItem] setTag: 10];
186     [o_addlogo_ckb setTitle:_NS("Add logo")];
187     [o_addlogo_logo_lbl setStringValue:_NS("Logo")];
188     [o_addlogo_pos_lbl setStringValue:_NS("Position")];
189     [o_addlogo_pos_pop removeAllItems];
190     [o_addlogo_pos_pop addItemWithTitle: _NS("Center")];
191     [[o_addlogo_pos_pop lastItem] setTag: 0];
192     [o_addlogo_pos_pop addItemWithTitle: _NS("Left")];
193     [[o_addlogo_pos_pop lastItem] setTag: 1];
194     [o_addlogo_pos_pop addItemWithTitle: _NS("Right")];
195     [[o_addlogo_pos_pop lastItem] setTag: 2];
196     [o_addlogo_pos_pop addItemWithTitle: _NS("Top")];
197     [[o_addlogo_pos_pop lastItem] setTag: 4];
198     [o_addlogo_pos_pop addItemWithTitle: _NS("Bottom")];
199     [[o_addlogo_pos_pop lastItem] setTag: 8];
200     [o_addlogo_pos_pop addItemWithTitle: _NS("Top-Left")];
201     [[o_addlogo_pos_pop lastItem] setTag: 5];
202     [o_addlogo_pos_pop addItemWithTitle: _NS("Top-Right")];
203     [[o_addlogo_pos_pop lastItem] setTag: 6];
204     [o_addlogo_pos_pop addItemWithTitle: _NS("Bottom-Left")];
205     [[o_addlogo_pos_pop lastItem] setTag: 9];
206     [o_addlogo_pos_pop addItemWithTitle: _NS("Bottom-Right")];
207     [[o_addlogo_pos_pop lastItem] setTag: 10];
208     [o_addlogo_transparency_lbl setStringValue:_NS("Transparency")];
209
210     [o_tableView selectFirstTabViewItem:self];
211
212     [self resetValues];
213 }
214
215 - (void)updateCocoaWindowLevel:(NSInteger)i_level
216 {
217     if (o_window && [o_window isVisible] && [o_window level] != i_level)
218         [o_window setLevel: i_level];
219 }
220
221 #pragma mark -
222 #pragma mark internal functions
223 - (void)resetProfileSelector
224 {
225     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
226     [o_profile_pop removeAllItems];
227
228     NSArray * profileNames = [defaults objectForKey:@"VideoEffectProfileNames"];
229     [o_profile_pop addItemsWithTitles:profileNames];
230
231     [[o_profile_pop menu] addItem:[NSMenuItem separatorItem]];
232     [o_profile_pop addItemWithTitle:_NS("Duplicate current profile...")];
233     [[o_profile_pop lastItem] setTarget: self];
234     [[o_profile_pop lastItem] setAction: @selector(addProfile:)];
235
236     if ([profileNames count] > 1) {
237         [o_profile_pop addItemWithTitle:_NS("Organize profiles...")];
238         [[o_profile_pop lastItem] setTarget: self];
239         [[o_profile_pop lastItem] setAction: @selector(removeProfile:)];
240     }
241
242     [o_profile_pop selectItemAtIndex:[defaults integerForKey:@"VideoEffectSelectedProfile"]];
243     [self profileSelectorAction:self];
244 }
245
246 - (void)resetValues
247 {
248     NSString *tmpString;
249     char *tmpChar;
250     BOOL b_state;
251
252     /* do we have any filter enabled? if yes, show it. */
253     char * psz_vfilters;
254     psz_vfilters = config_GetPsz(p_intf, "video-filter");
255     if (psz_vfilters) {
256         [o_adjust_ckb setState: (NSInteger)strstr(psz_vfilters, "adjust")];
257         [o_sharpen_ckb setState: (NSInteger)strstr(psz_vfilters, "sharpen")];
258         [o_banding_ckb setState: (NSInteger)strstr(psz_vfilters, "gradfun")];
259         [o_grain_ckb setState: (NSInteger)strstr(psz_vfilters, "grain")];
260         [o_transform_ckb setState: (NSInteger)strstr(psz_vfilters, "transform")];
261         [o_zoom_ckb setState: (NSInteger)strstr(psz_vfilters, "magnify")];
262         [o_puzzle_ckb setState: (NSInteger)strstr(psz_vfilters, "puzzle")];
263         [o_threshold_ckb setState: (NSInteger)strstr(psz_vfilters, "colorthres")];
264         [o_sepia_ckb setState: (NSInteger)strstr(psz_vfilters, "sepia")];
265         [o_noise_ckb setState: (NSInteger)strstr(psz_vfilters, "noise")];
266         [o_gradient_ckb setState: (NSInteger)strstr(psz_vfilters, "gradient")];
267         [o_extract_ckb setState: (NSInteger)strstr(psz_vfilters, "extract")];
268         [o_invert_ckb setState: (NSInteger)strstr(psz_vfilters, "invert")];
269         [o_posterize_ckb setState: (NSInteger)strstr(psz_vfilters, "posterize")];
270         [o_blur_ckb setState: (NSInteger)strstr(psz_vfilters, "motionblur")];
271         [o_motiondetect_ckb setState: (NSInteger)strstr(psz_vfilters, "motiondetect")];
272         [o_watereffect_ckb setState: (NSInteger)strstr(psz_vfilters, "ripple")];
273         [o_waves_ckb setState: (NSInteger)strstr(psz_vfilters, "wave")];
274         [o_psychedelic_ckb setState: (NSInteger)strstr(psz_vfilters, "psychedelic")];
275         [o_anaglyph_ckb setState: (NSInteger)strstr(psz_vfilters, "anaglyph")];
276         free(psz_vfilters);
277     } else {
278         [o_adjust_ckb setState: NSOffState];
279         [o_sharpen_ckb setState: NSOffState];
280         [o_banding_ckb setState: NSOffState];
281         [o_grain_ckb setState: NSOffState];
282         [o_transform_ckb setState: NSOffState];
283         [o_zoom_ckb setState: NSOffState];
284         [o_puzzle_ckb setState: NSOffState];
285         [o_threshold_ckb setState: NSOffState];
286         [o_sepia_ckb setState: NSOffState];
287         [o_noise_ckb setState: NSOffState];
288         [o_gradient_ckb setState: NSOffState];
289         [o_extract_ckb setState: NSOffState];
290         [o_invert_ckb setState: NSOffState];
291         [o_posterize_ckb setState: NSOffState];
292         [o_blur_ckb setState: NSOffState];
293         [o_motiondetect_ckb setState: NSOffState];
294         [o_watereffect_ckb setState: NSOffState];
295         [o_waves_ckb setState: NSOffState];
296         [o_psychedelic_ckb setState: NSOffState];
297         [o_anaglyph_ckb setState: NSOffState];
298     }
299
300     psz_vfilters = config_GetPsz(p_intf, "sub-source");
301     if (psz_vfilters) {
302         [o_addtext_ckb setState: (NSInteger)strstr(psz_vfilters, "marq")];
303         [o_addlogo_ckb setState: (NSInteger)strstr(psz_vfilters, "logo")];
304         free(psz_vfilters);
305     } else {
306         [o_addtext_ckb setState: NSOffState];
307         [o_addlogo_ckb setState: NSOffState];
308     }
309
310     psz_vfilters = config_GetPsz(p_intf, "video-splitter");
311     if (psz_vfilters) {
312         [o_clone_ckb setState: (NSInteger)strstr(psz_vfilters, "clone")];
313         [o_wall_ckb setState: (NSInteger)strstr(psz_vfilters, "wall")];
314         free(psz_vfilters);
315     } else {
316         [o_clone_ckb setState: NSOffState];
317         [o_wall_ckb setState: NSOffState];
318     }
319
320     /* fetch and show the various values */
321     [o_adjust_hue_sld setIntValue: config_GetInt(p_intf, "hue")];
322     [o_adjust_contrast_sld setFloatValue: config_GetFloat(p_intf, "contrast")];
323     [o_adjust_brightness_sld setFloatValue: config_GetFloat(p_intf, "brightness")];
324     [o_adjust_saturation_sld setFloatValue: config_GetFloat(p_intf, "saturation")];
325     [o_adjust_gamma_sld setFloatValue: config_GetFloat(p_intf, "gamma")];
326     [o_adjust_brightness_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat(p_intf, "brightness")]];
327     [o_adjust_contrast_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat(p_intf, "contrast")]];
328     [o_adjust_gamma_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat(p_intf, "gamma")]];
329     [o_adjust_hue_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "hue")]];
330     [o_adjust_saturation_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat(p_intf, "saturation")]];
331     b_state = [o_adjust_ckb state];
332     [o_adjust_brightness_sld setEnabled: b_state];
333     [o_adjust_brightness_ckb setEnabled: b_state];
334     [o_adjust_contrast_sld setEnabled: b_state];
335     [o_adjust_gamma_sld setEnabled: b_state];
336     [o_adjust_hue_sld setEnabled: b_state];
337     [o_adjust_saturation_sld setEnabled: b_state];
338     [o_adjust_brightness_lbl setEnabled: b_state];
339     [o_adjust_contrast_lbl setEnabled: b_state];
340     [o_adjust_gamma_lbl setEnabled: b_state];
341     [o_adjust_hue_lbl setEnabled: b_state];
342     [o_adjust_saturation_lbl setEnabled: b_state];
343     [o_adjust_reset_btn setEnabled: b_state];
344
345     [o_sharpen_sld setFloatValue: config_GetFloat(p_intf, "sharpen-sigma")];
346     [o_sharpen_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat(p_intf, "sharpen-sigma")]];
347     [o_sharpen_sld setEnabled: [o_sharpen_ckb state]];
348     [o_sharpen_lbl setEnabled: [o_sharpen_ckb state]];
349
350     [o_banding_sld setIntValue: config_GetInt(p_intf, "gradfun-radius")];
351     [o_banding_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "gradfun-radius")]];
352     [o_banding_sld setEnabled: [o_banding_ckb state]];
353     [o_banding_lbl setEnabled: [o_banding_ckb state]];
354
355     [o_grain_sld setFloatValue: config_GetFloat(p_intf, "grain-variance")];
356     [o_grain_sld setToolTip: [NSString stringWithFormat:@"%0.3f", config_GetFloat(p_intf, "grain-variance")]];
357     [o_grain_sld setEnabled: [o_grain_ckb state]];
358     [o_grain_lbl setEnabled: [o_grain_ckb state]];
359
360     [self setCropLeftValue: 0];
361     [self setCropTopValue: 0];
362     [self setCropRightValue: 0];
363     [self setCropBottomValue: 0];
364     [o_crop_sync_top_bottom_ckb setState: NSOffState];
365     [o_crop_sync_left_right_ckb setState: NSOffState];
366
367     tmpChar = config_GetPsz(p_intf, "transform-type");
368     tmpString = @(tmpChar);
369     if ([tmpString isEqualToString:@"hflip"])
370         [o_transform_pop selectItemWithTag: 1];
371     else if ([tmpString isEqualToString:@"vflip"])
372         [o_transform_pop selectItemWithTag: 2];
373     else
374         [o_transform_pop selectItemWithTag:[tmpString intValue]];
375     FREENULL(tmpChar);
376     [o_transform_pop setEnabled: [o_transform_ckb state]];
377
378     [self setPuzzleColumnsValue: config_GetInt(p_intf, "puzzle-cols")];
379     [self setPuzzleRowsValue: config_GetInt(p_intf, "puzzle-rows")];
380     b_state = [o_puzzle_ckb state];
381     [o_puzzle_rows_fld setEnabled: b_state];
382     [o_puzzle_rows_stp setEnabled: b_state];
383     [o_puzzle_rows_lbl setEnabled: b_state];
384     [o_puzzle_columns_fld setEnabled: b_state];
385     [o_puzzle_columns_stp setEnabled: b_state];
386     [o_puzzle_columns_lbl setEnabled: b_state];
387
388     [self setCloneValue: config_GetInt(p_intf, "clone-count")];
389     b_state = [o_clone_ckb state];
390     [o_clone_number_lbl setEnabled: b_state];
391     [o_clone_number_fld setEnabled: b_state];
392     [o_clone_number_stp setEnabled: b_state];
393
394     b_state = [o_wall_ckb state];
395     [self setWallRowsValue: config_GetInt(p_intf, "wall-rows")];
396     [o_wall_numofrows_lbl setEnabled: b_state];
397     [o_wall_numofrows_fld setEnabled: b_state];
398     [o_wall_numofrows_stp setEnabled: b_state];
399     [self setWallColumnsValue: config_GetInt(p_intf, "wall-cols")];
400     [o_wall_numofcols_lbl setEnabled: b_state];
401     [o_wall_numofcols_fld setEnabled: b_state];
402     [o_wall_numofcols_stp setEnabled: b_state];
403
404     [o_threshold_color_fld setStringValue: [[NSString stringWithFormat:@"%llx", config_GetInt(p_intf, "colorthres-color")] uppercaseString]];
405     [o_threshold_saturation_sld setIntValue: config_GetInt(p_intf, "colorthres-saturationthres")];
406     [o_threshold_saturation_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "colorthres-saturationthres")]];
407     [o_threshold_similarity_sld setIntValue: config_GetInt(p_intf, "colorthres-similaritythres")];
408     [o_threshold_similarity_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "colorthres-similaritythres")]];
409     
410     b_state = [o_threshold_ckb state];
411     [o_threshold_color_fld setEnabled: b_state];
412     [o_threshold_color_lbl setEnabled: b_state];
413     [o_threshold_saturation_sld setEnabled: b_state];
414     [o_threshold_saturation_lbl setEnabled: b_state];
415     [o_threshold_similarity_sld setEnabled: b_state];
416     [o_threshold_similarity_lbl setEnabled: b_state];
417     
418     [self setSepiaValue: config_GetInt(p_intf, "sepia-intensity")];
419     b_state = [o_sepia_ckb state];
420     [o_sepia_fld setEnabled: b_state];
421     [o_sepia_stp setEnabled: b_state];
422     [o_sepia_lbl setEnabled: b_state];
423
424     tmpChar = config_GetPsz(p_intf, "gradient-mode");
425     tmpString = @(tmpChar);
426     if ([tmpString isEqualToString:@"hough"])
427         [o_gradient_mode_pop selectItemWithTag: 3];
428     else if ([tmpString isEqualToString:@"edge"])
429         [o_gradient_mode_pop selectItemWithTag: 2];
430     else
431         [o_gradient_mode_pop selectItemWithTag: 1];
432     FREENULL(tmpChar);
433     [o_gradient_cartoon_ckb setState: config_GetInt(p_intf, "gradient-cartoon")];
434     [o_gradient_color_ckb setState: config_GetInt(p_intf, "gradient-type")];
435     b_state = [o_gradient_ckb state];
436     [o_gradient_mode_pop setEnabled: b_state];
437     [o_gradient_mode_lbl setEnabled: b_state];
438     [o_gradient_cartoon_ckb setEnabled: b_state];
439     [o_gradient_color_ckb setEnabled: b_state];
440
441     [o_extract_fld setStringValue: [[NSString stringWithFormat:@"%llx", config_GetInt(p_intf, "extract-component")] uppercaseString]];
442     [o_extract_fld setEnabled: [o_extract_ckb state]];
443     [o_extract_lbl setEnabled: [o_extract_ckb state]];
444
445     [self setPosterizeValue: config_GetInt(p_intf, "posterize-level")];
446     b_state = [o_posterize_ckb state];
447     [o_posterize_fld setEnabled: b_state];
448     [o_posterize_stp setEnabled: b_state];
449     [o_posterize_lbl setEnabled: b_state];
450     
451     [o_blur_sld setIntValue: config_GetInt(p_intf, "blur-factor")];
452     [o_blur_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "blur-factor")]];
453     [o_blur_sld setEnabled: [o_blur_ckb state]];
454     [o_blur_lbl setEnabled: [o_blur_ckb state]];
455
456     tmpChar = config_GetPsz(p_intf, "marq-marquee");
457     if (tmpChar) {
458         [o_addtext_text_fld setStringValue: @(tmpChar)];
459         FREENULL(tmpChar);
460     } else
461         [o_addtext_text_fld setStringValue: @""];
462     [o_addtext_pos_pop selectItemWithTag: config_GetInt(p_intf, "marq-position")];
463     b_state = [o_addtext_ckb state];
464     [o_addtext_pos_pop setEnabled: b_state];
465     [o_addtext_pos_lbl setEnabled: b_state];
466     [o_addtext_text_lbl setEnabled: b_state];
467     [o_addtext_text_fld setEnabled: b_state];
468
469     tmpChar = config_GetPsz(p_intf, "logo-file");
470     if (tmpChar) {
471         [o_addlogo_logo_fld setStringValue: @(tmpChar)];
472         FREENULL(tmpChar);
473     } else
474         [o_addlogo_logo_fld setStringValue: @""];
475     [o_addlogo_pos_pop selectItemWithTag: config_GetInt(p_intf, "logo-position")];
476     [o_addlogo_transparency_sld setIntValue: config_GetInt(p_intf, "logo-opacity")];
477     [o_addlogo_transparency_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "logo-opacity")]];
478     b_state = [o_addlogo_ckb state];
479     [o_addlogo_pos_pop setEnabled: b_state];
480     [o_addlogo_pos_lbl setEnabled: b_state];
481     [o_addlogo_logo_fld setEnabled: b_state];
482     [o_addlogo_logo_lbl setEnabled: b_state];
483     [o_addlogo_transparency_sld setEnabled: b_state];
484     [o_addlogo_transparency_lbl setEnabled: b_state];
485 }
486
487 - (void)setVideoFilter: (char *)psz_name on:(BOOL)b_on
488 {
489     char *psz_string, *psz_parser;
490     const char *psz_filter_type;
491
492     module_t *p_obj = module_find(psz_name);
493     if (!p_obj) {
494         msg_Err(p_intf, "Unable to find filter module \"%s\".", psz_name);
495         return;
496     }
497     msg_Dbg(p_intf, "will set filter '%s'", psz_name);
498
499     if (module_provides(p_obj, "video splitter")) {
500         psz_filter_type = "video-splitter";
501     } else if (module_provides(p_obj, "video filter2")) {
502         psz_filter_type = "video-filter";
503     } else if (module_provides(p_obj, "sub source")) {
504         psz_filter_type = "sub-source";
505     } else if (module_provides(p_obj, "sub filter")) {
506         psz_filter_type = "sub-filter";
507     } else {
508         msg_Err(p_intf, "Unknown video filter type.");
509         return;
510     }
511
512     psz_string = config_GetPsz(p_intf, psz_filter_type);
513
514     if (b_on) {
515         if (!psz_string)
516             psz_string = psz_name;
517         else if (strstr(psz_string, psz_name) == NULL)
518             psz_string = (char *)[[NSString stringWithFormat: @"%s:%s", psz_string, psz_name] UTF8String];
519     } else {
520         if (!psz_string)
521             return;
522
523         psz_parser = strstr(psz_string, psz_name);
524         if (psz_parser) {
525             if (*(psz_parser + strlen(psz_name)) == ':') {
526                 memmove(psz_parser, psz_parser + strlen(psz_name) + 1,
527                         strlen(psz_parser + strlen(psz_name) + 1) + 1);
528             } else {
529                 *psz_parser = '\0';
530             }
531
532             /* Remove trailing : : */
533             if (strlen(psz_string) > 0 && *(psz_string + strlen(psz_string) -1) == ':')
534                 *(psz_string + strlen(psz_string) -1) = '\0';
535         } else {
536             free(psz_string);
537             return;
538         }
539     }
540     config_PutPsz(p_intf, psz_filter_type, psz_string);
541
542     /* Try to set on the fly */
543     if (!strcmp(psz_filter_type, "video-splitter")) {
544         playlist_t *p_playlist = pl_Get(p_intf);
545         var_SetString(p_playlist, psz_filter_type, psz_string);
546     } else {
547         vout_thread_t *p_vout = getVout();
548         if (p_vout) {
549             var_SetString(p_vout, psz_filter_type, psz_string);
550             vlc_object_release(p_vout);
551         }
552     }
553 }
554
555 - (void)restartFilterIfNeeded: (char *)psz_filter option: (char *)psz_name
556 {
557     vout_thread_t *p_vout = getVout();
558
559     if (p_vout == NULL)
560         return;
561     else
562         vlc_object_release(p_vout);
563
564     vlc_object_t *p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
565     if (p_filter) {
566         int i_type;
567         i_type = var_Type(p_filter, psz_name);
568         if (i_type == 0)
569             i_type = config_GetType(p_intf, psz_name);
570
571         if (!(i_type & VLC_VAR_ISCOMMAND)) {
572             msg_Warn(p_intf, "Brute-restarting filter '%s', because the last changed option isn't a command", psz_name);
573             [self setVideoFilter: psz_filter on: NO];
574             [self setVideoFilter: psz_filter on: YES];
575         } else
576             msg_Dbg(p_intf, "restart not needed");
577
578         vlc_object_release(p_filter);
579     }
580 }
581
582 - (void)setVideoFilterProperty: (char *)psz_name forFilter: (char *)psz_filter integer: (int)i_value
583 {
584     vout_thread_t *p_vout = getVout();
585     vlc_object_t *p_filter;
586
587     config_PutInt(p_intf, psz_name, i_value);
588
589     if (p_vout) {
590         p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
591
592         if (!p_filter) {
593             msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
594             vlc_object_release(p_vout);
595             return;
596         }
597         var_SetInteger(p_filter, psz_name, i_value);
598         vlc_object_release(p_vout);
599         vlc_object_release(p_filter);
600
601         [self restartFilterIfNeeded: psz_filter option: psz_name];
602     }
603 }
604
605 - (void)setVideoFilterProperty: (char *)psz_name forFilter: (char *)psz_filter float: (float)f_value
606 {
607     vout_thread_t *p_vout = getVout();
608     vlc_object_t *p_filter;
609
610     config_PutFloat(p_intf, psz_name, f_value);
611
612     if (p_vout) {
613         p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
614
615         if (!p_filter) {
616             msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
617             vlc_object_release(p_vout);
618             return;
619         }
620         var_SetFloat(p_filter, psz_name, f_value);
621         vlc_object_release(p_vout);
622         vlc_object_release(p_filter);
623
624         [self restartFilterIfNeeded: psz_filter option: psz_name];
625     }
626 }
627
628 - (void)setVideoFilterProperty: (char *)psz_name forFilter: (char *)psz_filter string: (char *)psz_value
629 {
630     vout_thread_t *p_vout = getVout();
631     vlc_object_t *p_filter;
632
633     config_PutPsz(p_intf, psz_name, EnsureUTF8(psz_value));
634
635     if (p_vout) {
636         p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
637
638         if (!p_filter) {
639             msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
640             vlc_object_release(p_vout);
641             return;
642         }
643         var_SetString(p_filter, psz_name, EnsureUTF8(psz_value));
644         vlc_object_release(p_vout);
645         vlc_object_release(p_filter);
646
647         [self restartFilterIfNeeded: psz_filter option: psz_name];
648     }
649 }
650
651 - (void)setVideoFilterProperty: (char *)psz_name forFilter: (char *)psz_filter boolean: (BOOL)b_value
652 {
653     vout_thread_t *p_vout = getVout();
654     vlc_object_t *p_filter;
655
656     config_PutInt(p_intf, psz_name, b_value);
657
658     if (p_vout) {
659         p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
660
661         if (!p_filter) {
662             msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
663             vlc_object_release(p_vout);
664             return;
665         }
666         var_SetBool(p_filter, psz_name, b_value);
667         vlc_object_release(p_vout);
668         vlc_object_release(p_filter);
669     }
670 }
671
672 - (NSString *)generateProfileString
673 {
674     return [NSString stringWithFormat:@"%s;%s;%s;%lli;%f;%f;%f;%f;%f;%lli;%f;%s;%lli;%lli;%lli;%lli;%lli;%lli;%s;%lli;%lli;%lli;%lli;%lli;%s;%lli;%s;%lli;%lli;%lli;%lli;%lli",
675             vlc_b64_encode(config_GetPsz(p_intf, "video-filter")),
676             vlc_b64_encode(config_GetPsz(p_intf, "sub-source")),
677             vlc_b64_encode(config_GetPsz(p_intf, "video-splitter")),
678             config_GetInt(p_intf, "hue"),
679             config_GetFloat(p_intf, "contrast"),
680             config_GetFloat(p_intf, "brightness"),
681             config_GetFloat(p_intf, "saturation"),
682             config_GetFloat(p_intf, "gamma"),
683             config_GetFloat(p_intf, "sharpen-sigma"),
684             config_GetInt(p_intf, "gradfun-radius"),
685             config_GetFloat(p_intf, "grain-variance"),
686             vlc_b64_encode(config_GetPsz(p_intf, "transform-type")),
687             config_GetInt(p_intf, "puzzle-rows"),
688             config_GetInt(p_intf, "puzzle-cols"),
689             config_GetInt(p_intf, "colorthres-color"),
690             config_GetInt(p_intf, "colorthres-saturationthres"),
691             config_GetInt(p_intf, "colorthres-similaritythres"),
692             config_GetInt(p_intf, "sepia-intensity"),
693             vlc_b64_encode(config_GetPsz(p_intf, "gradient-mode")),
694             config_GetInt(p_intf, "gradient-cartoon"),
695             config_GetInt(p_intf, "gradient-type"),
696             config_GetInt(p_intf, "extract-component"),
697             config_GetInt(p_intf, "posterize-level"),
698             config_GetInt(p_intf, "blur-factor"),
699             vlc_b64_encode(config_GetPsz(p_intf, "marq-marquee")),
700             config_GetInt(p_intf, "marq-position"),
701             vlc_b64_encode(config_GetPsz(p_intf, "logo-file")),
702             config_GetInt(p_intf, "logo-position"),
703             config_GetInt(p_intf, "logo-opacity"),
704             config_GetInt(p_intf, "clone-count"),
705             config_GetInt(p_intf, "wall-rows"),
706             config_GetInt(p_intf, "wall-cols")
707             ];
708 }
709
710 #pragma mark -
711 #pragma mark generic UI code
712
713 - (void)saveCurrentProfile
714 {
715     if (i_old_profile_index == -1)
716         return;
717
718     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
719     /* fetch all the current settings in a uniform string */
720     NSString *newProfile = [self generateProfileString];
721
722     NSMutableArray *workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"VideoEffectProfiles"]];
723     if (i_old_profile_index >= [workArray count])
724         return;
725
726     [workArray replaceObjectAtIndex:i_old_profile_index withObject:newProfile];
727     [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfiles"];
728     [workArray release];
729     [defaults synchronize];
730 }
731
732 - (IBAction)toggleWindow:(id)sender
733 {
734     if ([o_window isVisible])
735         [o_window orderOut:sender];
736     else {
737         [o_window setLevel: [[[VLCMain sharedInstance] voutController] currentWindowLevel]];
738         [o_window makeKeyAndOrderFront:sender];
739     }
740 }
741
742 - (IBAction)profileSelectorAction:(id)sender
743 {
744     [self saveCurrentProfile];
745     i_old_profile_index = [o_profile_pop indexOfSelectedItem];
746
747     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
748     NSUInteger selectedProfile = [o_profile_pop indexOfSelectedItem];
749
750     /* disable all current video filters, if a vout is available */
751     vout_thread_t *p_vout = getVout();
752     if (p_vout) {
753         var_SetString(p_vout, "video-filter", "");
754         var_SetString(p_vout, "sub-source", "");
755         var_SetString(p_vout, "video-splitter", "");
756         vlc_object_release(p_vout);
757     }
758
759     /* fetch preset */
760     NSArray *items = [[[defaults objectForKey:@"VideoEffectProfiles"] objectAtIndex:selectedProfile] componentsSeparatedByString:@";"];
761
762     /* filter handling */
763     NSString *tempString = [NSString stringWithFormat:@"%s", vlc_b64_decode([[items objectAtIndex:0] UTF8String])];
764     NSArray *tempArray;
765     NSUInteger count;
766
767     /* enable the new filters */
768     config_PutPsz(p_intf, "video-filter", "");
769     if ([tempString length] > 0) {
770         tempArray = [tempString componentsSeparatedByString:@":"];
771         count = [tempArray count];
772         for (NSUInteger x = 0; x < count; x++)
773             [self setVideoFilter:(char *)[[tempArray objectAtIndex:x] UTF8String] on:YES];
774     }
775
776     tempString = [NSString stringWithFormat:@"%s", vlc_b64_decode([[items objectAtIndex:1] UTF8String])];
777     /* enable another round of new filters */
778     config_PutPsz(p_intf,"sub-source", "");
779     if ([tempString length] > 0) {
780         tempArray = [tempString componentsSeparatedByString:@":"];
781         count = [tempArray count];
782         for (NSUInteger x = 0; x < count; x++)
783             [self setVideoFilter:(char *)[[tempArray objectAtIndex:x] UTF8String] on:YES];
784     }
785
786     tempString = [NSString stringWithFormat:@"%s", vlc_b64_decode([[items objectAtIndex:2] UTF8String])];
787     /* enable another round of new filters */
788     config_PutPsz(p_intf,"video-splitter", "");
789     if ([tempString length] > 0) {
790         tempArray = [tempString componentsSeparatedByString:@":"];
791         count = [tempArray count];
792         for (NSUInteger x = 0; x < count; x++)
793             [self setVideoFilter:(char *)[[tempArray objectAtIndex:x] UTF8String] on:YES];
794     }
795
796     /* try to set filter values on-the-fly and store them appropriately */
797     [self setVideoFilterProperty:"hue" forFilter:"adjust" integer:[[items objectAtIndex:3] intValue]];
798     [self setVideoFilterProperty:"contrast" forFilter:"adjust" float:[[items objectAtIndex:4] floatValue]];
799     [self setVideoFilterProperty:"brightness" forFilter:"adjust" float:[[items objectAtIndex:5] floatValue]];
800     [self setVideoFilterProperty:"saturation" forFilter:"adjust" float:[[items objectAtIndex:6] floatValue]];
801     [self setVideoFilterProperty:"gamma" forFilter:"adjust" float:[[items objectAtIndex:7] floatValue]];
802     [self setVideoFilterProperty:"sharpen-sigma" forFilter:"sharpen" float:[[items objectAtIndex:8] floatValue]];
803     [self setVideoFilterProperty:"gradfun-radius" forFilter:"gradfun" integer:[[items objectAtIndex:9] intValue]];
804     [self setVideoFilterProperty:"grain-variance" forFilter:"grain" float:[[items objectAtIndex:10] floatValue]];
805     [self setVideoFilterProperty:"transform-type" forFilter:"transform" string:vlc_b64_decode([[items objectAtIndex:11] UTF8String])];
806     [self setVideoFilterProperty:"puzzle-rows" forFilter:"puzzle" integer:[[items objectAtIndex:12] intValue]];
807     [self setVideoFilterProperty:"puzzle-cols" forFilter:"puzzle" integer:[[items objectAtIndex:13] intValue]];
808     [self setVideoFilterProperty:"colorthres-color" forFilter:"colorthres" integer:[[items objectAtIndex:14] intValue]];
809     [self setVideoFilterProperty:"colorthres-saturationthres" forFilter:"colorthres" integer:[[items objectAtIndex:15] intValue]];
810     [self setVideoFilterProperty:"colorthres-similaritythres" forFilter:"colorthres" integer:[[items objectAtIndex:16] intValue]];
811     [self setVideoFilterProperty:"sepia-intensity" forFilter:"sepia" integer:[[items objectAtIndex:17] intValue]];
812     [self setVideoFilterProperty:"gradient-mode" forFilter:"gradient" string:vlc_b64_decode([[items objectAtIndex:18] UTF8String])];
813     [self setVideoFilterProperty:"gradient-cartoon" forFilter:"gradient" integer:[[items objectAtIndex:19] intValue]];
814     [self setVideoFilterProperty:"gradient-type" forFilter:"gradient" integer:[[items objectAtIndex:20] intValue]];
815     [self setVideoFilterProperty:"extract-component" forFilter:"extract" integer:[[items objectAtIndex:21] intValue]];
816     [self setVideoFilterProperty:"posterize-level" forFilter:"posterize" integer:[[items objectAtIndex:22] intValue]];
817     [self setVideoFilterProperty:"blur-factor" forFilter:"motionblur" integer:[[items objectAtIndex:23] intValue]];
818     [self setVideoFilterProperty:"marq-marquee" forFilter:"marq" string:vlc_b64_decode([[items objectAtIndex:24] UTF8String])];
819     [self setVideoFilterProperty:"marq-position" forFilter:"marq" integer:[[items objectAtIndex:25] intValue]];
820     [self setVideoFilterProperty:"logo-file" forFilter:"logo" string:vlc_b64_decode([[items objectAtIndex:26] UTF8String])];
821     [self setVideoFilterProperty:"logo-position" forFilter:"logo" integer:[[items objectAtIndex:27] intValue]];
822     [self setVideoFilterProperty:"logo-opacity" forFilter:"logo" integer:[[items objectAtIndex:28] intValue]];
823     [self setVideoFilterProperty:"clone-count" forFilter:"clone" integer:[[items objectAtIndex:29] intValue]];
824     [self setVideoFilterProperty:"wall-rows" forFilter:"wall" integer:[[items objectAtIndex:30] intValue]];
825     [self setVideoFilterProperty:"wall-cols" forFilter:"wall" integer:[[items objectAtIndex:31] intValue]];
826
827     [defaults setInteger:selectedProfile forKey:@"VideoEffectSelectedProfile"];
828     [defaults synchronize];
829
830     [self resetValues];
831 }
832
833 - (IBAction)addProfile:(id)sender
834 {
835     /* show panel */
836     VLCEnterTextPanel * panel = [VLCEnterTextPanel sharedInstance];
837     [panel setTitle: _NS("Duplicate current profile for a new profile")];
838     [panel setSubTitle: _NS("Enter a name for the new profile:")];
839     [panel setCancelButtonLabel: _NS("Cancel")];
840     [panel setOKButtonLabel: _NS("Save")];
841     [panel setTarget:self];
842
843     [panel runModalForWindow:o_window];
844 }
845
846 - (void)panel:(VLCEnterTextPanel *)panel returnValue:(NSUInteger)value text:(NSString *)text
847 {
848     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
849
850     if (value != NSOKButton) {
851         [o_profile_pop selectItemAtIndex:[defaults integerForKey:@"VideoEffectSelectedProfile"]];
852         return;
853     }
854
855     NSArray *profileNames = [defaults objectForKey:@"VideoEffectProfileNames"];
856
857     // duplicate names are not allowed in the popup control
858     if ([text length] == 0 || [profileNames containsObject:text]) {
859         [o_profile_pop selectItemAtIndex:[defaults integerForKey:@"VideoEffectSelectedProfile"]];
860
861         NSAlert *alert = [[[NSAlert alloc] init] autorelease];
862         [alert setAlertStyle:NSCriticalAlertStyle];
863         [alert setMessageText:_NS("Please enter a unique name for the new profile.")];
864         [alert setInformativeText:_NS("Multiple profiles with the same name are not allowed.")];
865
866         [alert beginSheetModalForWindow:o_window
867                           modalDelegate:nil
868                          didEndSelector:nil
869                             contextInfo:nil];
870         return;
871     }
872
873     /* fetch all the current settings in a uniform string */
874     NSString *newProfile = [self generateProfileString];
875
876     /* add string to user defaults as well as a label */
877
878     NSMutableArray *workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"VideoEffectProfiles"]];
879     [workArray addObject:newProfile];
880     [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfiles"];
881     [defaults setInteger:[workArray count] - 1 forKey:@"VideoEffectSelectedProfile"];
882     [workArray release];
883     
884     workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"VideoEffectProfileNames"]];
885     [workArray addObject:text];
886     [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfileNames"];
887     [workArray release];
888
889     /* save defaults */
890     [defaults synchronize];
891
892     /* refresh UI */
893     [self resetProfileSelector];
894 }
895
896 - (IBAction)removeProfile:(id)sender
897 {
898     /* show panel */
899     VLCSelectItemInPopupPanel * panel = [VLCSelectItemInPopupPanel sharedInstance];
900     [panel setTitle:_NS("Remove a preset")];
901     [panel setSubTitle:_NS("Select the preset you would like to remove:")];
902     [panel setOKButtonLabel:_NS("Remove")];
903     [panel setCancelButtonLabel:_NS("Cancel")];
904     [panel setPopupButtonContent:[[NSUserDefaults standardUserDefaults] objectForKey:@"VideoEffectProfileNames"]];
905     [panel setTarget:self];
906
907     [panel runModalForWindow:o_window];
908 }
909
910 - (void)panel:(VLCSelectItemInPopupPanel *)panel returnValue:(NSUInteger)value item:(NSUInteger)item
911 {
912     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
913
914     if (value != NSOKButton) {
915         [o_profile_pop selectItemAtIndex:[defaults integerForKey:@"VideoEffectSelectedProfile"]];
916         return;
917     }
918
919     /* remove selected profile from settings */
920     NSMutableArray *workArray = [[NSMutableArray alloc] initWithArray: [defaults objectForKey:@"VideoEffectProfiles"]];
921     [workArray removeObjectAtIndex:item];
922     [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfiles"];
923     [workArray release];
924
925     workArray = [[NSMutableArray alloc] initWithArray: [defaults objectForKey:@"VideoEffectProfileNames"]];
926     [workArray removeObjectAtIndex:item];
927     [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfileNames"];
928     [workArray release];
929
930     if (i_old_profile_index >= item)
931         [defaults setInteger:i_old_profile_index - 1 forKey:@"VideoEffectSelectedProfile"];
932
933     /* save defaults */
934     [defaults synchronize];
935
936     /* do not save deleted profile */
937     i_old_profile_index = -1;
938     /* refresh UI */
939     [self resetProfileSelector];
940 }
941
942 #pragma mark -
943 #pragma mark basic
944 - (IBAction)enableAdjust:(id)sender
945 {
946     BOOL b_state = [o_adjust_ckb state];
947
948     [self setVideoFilter: "adjust" on: b_state];
949     [o_adjust_brightness_sld setEnabled: b_state];
950     [o_adjust_brightness_ckb setEnabled: b_state];
951     [o_adjust_brightness_lbl setEnabled: b_state];
952     [o_adjust_contrast_sld setEnabled: b_state];
953     [o_adjust_contrast_lbl setEnabled: b_state];
954     [o_adjust_gamma_sld setEnabled: b_state];
955     [o_adjust_gamma_lbl setEnabled: b_state];
956     [o_adjust_hue_sld setEnabled: b_state];
957     [o_adjust_hue_lbl setEnabled: b_state];
958     [o_adjust_saturation_sld setEnabled: b_state];
959     [o_adjust_saturation_lbl setEnabled: b_state];
960     [o_adjust_reset_btn setEnabled: b_state];
961 }
962
963 - (IBAction)adjustSliderChanged:(id)sender
964 {
965     if (sender == o_adjust_brightness_sld)
966         [self setVideoFilterProperty: "brightness" forFilter: "adjust" float: [o_adjust_brightness_sld floatValue]];
967     else if (sender == o_adjust_contrast_sld)
968         [self setVideoFilterProperty: "contrast" forFilter: "adjust" float: [o_adjust_contrast_sld floatValue]];
969     else if (sender == o_adjust_gamma_sld)
970         [self setVideoFilterProperty: "gamma" forFilter: "adjust" float: [o_adjust_gamma_sld floatValue]];
971     else if (sender == o_adjust_hue_sld)
972         [self setVideoFilterProperty: "hue" forFilter: "adjust" integer: [o_adjust_hue_sld intValue]];
973     else if (sender == o_adjust_saturation_sld)
974         [self setVideoFilterProperty: "saturation" forFilter: "adjust" float: [o_adjust_saturation_sld floatValue]];
975
976     if (sender == o_adjust_hue_sld)
977         [o_adjust_hue_sld setToolTip: [NSString stringWithFormat:@"%i", [o_adjust_hue_sld intValue]]];
978     else
979         [sender setToolTip: [NSString stringWithFormat:@"%0.3f", [sender floatValue]]];
980 }
981
982 - (IBAction)enableAdjustBrightnessThreshold:(id)sender
983 {
984     if (sender == o_adjust_reset_btn) {
985         [o_adjust_brightness_sld setFloatValue: 1.0];
986         [o_adjust_contrast_sld setFloatValue: 1.0];
987         [o_adjust_gamma_sld setFloatValue: 1.0];
988         [o_adjust_hue_sld setIntValue: 0];
989         [o_adjust_saturation_sld setFloatValue: 1.0];
990         [o_adjust_brightness_sld setToolTip: [NSString stringWithFormat:@"%0.3f", 1.0]];
991         [o_adjust_contrast_sld setToolTip: [NSString stringWithFormat:@"%0.3f", 1.0]];
992         [o_adjust_gamma_sld setToolTip: [NSString stringWithFormat:@"%0.3f", 1.0]];
993         [o_adjust_hue_sld setToolTip: [NSString stringWithFormat:@"%i", 0]];
994         [o_adjust_saturation_sld setToolTip: [NSString stringWithFormat:@"%0.3f", 1.0]];
995         [self setVideoFilterProperty: "brightness" forFilter: "adjust" float: 1.0];
996         [self setVideoFilterProperty: "contrast" forFilter: "adjust" float: 1.0];
997         [self setVideoFilterProperty: "gamma" forFilter: "adjust" float: 1.0];
998         [self setVideoFilterProperty: "hue" forFilter: "adjust" integer: 0.0];
999         [self setVideoFilterProperty: "saturation" forFilter: "adjust" float: 1.0];
1000     } else
1001         config_PutInt(p_intf, "brightness-threshold", [o_adjust_brightness_ckb state]);
1002 }
1003
1004 - (IBAction)enableSharpen:(id)sender
1005 {
1006     BOOL b_state = [o_sharpen_ckb state];
1007
1008     [self setVideoFilter: "sharpen" on: b_state];
1009     [o_sharpen_sld setEnabled: b_state];
1010     [o_sharpen_lbl setEnabled: b_state];
1011 }
1012
1013 - (IBAction)sharpenSliderChanged:(id)sender
1014 {
1015     [self setVideoFilterProperty: "sharpen-sigma" forFilter: "sharpen" float: [sender floatValue]];
1016     [sender setToolTip: [NSString stringWithFormat:@"%0.3f", [sender floatValue]]];
1017 }
1018
1019 - (IBAction)enableBanding:(id)sender
1020 {
1021     BOOL b_state = [o_banding_ckb state];
1022
1023     [self setVideoFilter: "gradfun" on: b_state];
1024     [o_banding_sld setEnabled: b_state];
1025     [o_banding_lbl setEnabled: b_state];
1026 }
1027
1028 - (IBAction)bandingSliderChanged:(id)sender
1029 {
1030     [self setVideoFilterProperty: "gradfun-radius" forFilter: "gradfun" integer: [sender intValue]];
1031     [sender setToolTip: [NSString stringWithFormat:@"%i", [sender intValue]]];
1032 }
1033
1034 - (IBAction)enableGrain:(id)sender
1035 {
1036     BOOL b_state = [o_grain_ckb state];
1037
1038     [self setVideoFilter: "grain" on: b_state];
1039     [o_grain_sld setEnabled: b_state];
1040     [o_grain_lbl setEnabled: b_state];
1041 }
1042
1043 - (IBAction)grainSliderChanged:(id)sender
1044 {
1045     [self setVideoFilterProperty: "grain-variance" forFilter: "grain" float: [sender floatValue]];
1046     [sender setToolTip: [NSString stringWithFormat:@"%0.3f", [sender floatValue]]];
1047 }
1048
1049
1050 #pragma mark -
1051 #pragma mark crop
1052
1053 - (IBAction)cropObjectChanged:(id)sender
1054 {
1055     if ([o_crop_sync_top_bottom_ckb state]) {
1056         if (sender == o_crop_bottom_fld || sender == o_crop_bottom_stp)
1057             [self setCropTopValue: [self cropBottomValue]];
1058         else
1059             [self setCropBottomValue: [self cropTopValue]];
1060     }
1061     if ([o_crop_sync_left_right_ckb state]) {
1062         if (sender == o_crop_right_fld || sender == o_crop_right_stp)
1063             [self setCropLeftValue: [self cropRightValue]];
1064         else
1065             [self setCropRightValue: [self cropLeftValue]];
1066     }
1067
1068     vout_thread_t *p_vout = getVout();
1069     if (p_vout) {
1070         var_SetInteger(p_vout, "crop-top", [o_crop_top_fld intValue]);
1071         var_SetInteger(p_vout, "crop-bottom", [o_crop_bottom_fld intValue]);
1072         var_SetInteger(p_vout, "crop-left", [o_crop_left_fld intValue]);
1073         var_SetInteger(p_vout, "crop-right", [o_crop_right_fld intValue]);
1074         vlc_object_release(p_vout);
1075     }
1076 }
1077
1078 #pragma mark -
1079 #pragma mark geometry
1080 - (IBAction)enableTransform:(id)sender
1081 {
1082     [self setVideoFilter: "transform" on: [o_transform_ckb state]];
1083     [o_transform_pop setEnabled: [o_transform_ckb state]];
1084 }
1085
1086 - (IBAction)transformModifierChanged:(id)sender
1087 {
1088     NSInteger tag = [[o_transform_pop selectedItem] tag];
1089     char *psz_string = (char *)[[NSString stringWithFormat:@"%li", tag] UTF8String];
1090     if (tag == 1)
1091         psz_string = (char *)"hflip";
1092     else if (tag == 2)
1093         psz_string = (char *)"vflip";
1094
1095     [self setVideoFilterProperty: "transform-type" forFilter: "transform" string: psz_string];
1096 }
1097
1098 - (IBAction)enableZoom:(id)sender
1099 {
1100     [self setVideoFilter: "magnify" on: [o_zoom_ckb state]];
1101 }
1102
1103 - (IBAction)enablePuzzle:(id)sender
1104 {
1105     BOOL b_state = [o_puzzle_ckb state];
1106
1107     [self setVideoFilter: "puzzle" on: b_state];
1108     [o_puzzle_columns_fld setEnabled: b_state];
1109     [o_puzzle_columns_stp setEnabled: b_state];
1110     [o_puzzle_columns_lbl setEnabled: b_state];
1111     [o_puzzle_rows_fld setEnabled: b_state];
1112     [o_puzzle_rows_stp setEnabled: b_state];
1113     [o_puzzle_rows_lbl setEnabled: b_state];
1114 }
1115
1116 - (IBAction)puzzleModifierChanged:(id)sender
1117 {
1118     if (sender == o_puzzle_columns_fld || sender == o_puzzle_columns_stp)
1119         [self setVideoFilterProperty: "puzzle-cols" forFilter: "puzzle" integer: [sender intValue]];
1120     else
1121         [self setVideoFilterProperty: "puzzle-rows" forFilter: "puzzle" integer: [sender intValue]];
1122 }
1123
1124 - (IBAction)enableClone:(id)sender
1125 {
1126     BOOL b_state = [o_clone_ckb state];
1127
1128     if (b_state && [o_wall_ckb state]) {
1129         [o_wall_ckb setState: NSOffState];
1130         [self enableWall: o_wall_ckb];
1131     }
1132
1133     [self setVideoFilter: "clone" on: b_state];
1134     [o_clone_number_lbl setEnabled: b_state];
1135     [o_clone_number_fld setEnabled: b_state];
1136     [o_clone_number_stp setEnabled: b_state];
1137 }
1138
1139 - (IBAction)cloneModifierChanged:(id)sender
1140 {
1141     [self setVideoFilterProperty: "clone-count" forFilter: "clone" integer: [o_clone_number_fld intValue]];
1142 }
1143
1144 - (IBAction)enableWall:(id)sender
1145 {
1146     BOOL b_state = [o_wall_ckb state];
1147
1148     if (b_state && [o_clone_ckb state]) {
1149         [o_clone_ckb setState: NSOffState];
1150         [self enableClone: o_clone_ckb];
1151     }
1152
1153     [self setVideoFilter: "wall" on: b_state];
1154     [o_wall_numofcols_fld setEnabled: b_state];
1155     [o_wall_numofcols_stp setEnabled: b_state];
1156     [o_wall_numofcols_lbl setEnabled: b_state];
1157     
1158     [o_wall_numofrows_fld setEnabled: b_state];
1159     [o_wall_numofrows_stp setEnabled: b_state];
1160     [o_wall_numofrows_lbl setEnabled: b_state];
1161 }
1162
1163 - (IBAction)wallModifierChanged:(id)sender
1164 {
1165     if (sender == o_wall_numofcols_fld || sender == o_wall_numofcols_stp)
1166         [self setVideoFilterProperty: "wall-cols" forFilter: "wall" integer: [sender intValue]];
1167     else
1168         [self setVideoFilterProperty: "wall-rows" forFilter: "wall" integer: [sender intValue]];
1169 }
1170
1171 #pragma mark -
1172 #pragma mark color
1173 - (IBAction)enableThreshold:(id)sender
1174 {
1175     BOOL b_state = [o_threshold_ckb state];
1176
1177     [self setVideoFilter: "colorthres" on: b_state];
1178     [o_threshold_color_fld setEnabled: b_state];
1179     [o_threshold_color_lbl setEnabled: b_state];
1180     [o_threshold_saturation_sld setEnabled: b_state];
1181     [o_threshold_saturation_lbl setEnabled: b_state];
1182     [o_threshold_similarity_sld setEnabled: b_state];
1183     [o_threshold_similarity_lbl setEnabled: b_state];
1184 }
1185
1186 - (IBAction)thresholdModifierChanged:(id)sender
1187 {
1188     if (sender == o_threshold_color_fld)
1189         [self setVideoFilterProperty: "colorthres-color" forFilter: "colorthres" integer: [o_threshold_color_fld intValue]];
1190     else if (sender == o_threshold_saturation_sld) {
1191         [self setVideoFilterProperty: "colorthres-saturationthres" forFilter: "colorthres" integer: [o_threshold_saturation_sld intValue]];
1192         [o_threshold_saturation_sld setToolTip: [NSString stringWithFormat:@"%i", [o_threshold_saturation_sld intValue]]];
1193     } else {
1194         [self setVideoFilterProperty: "colorthres-similaritythres" forFilter: "colorthres" integer: [o_threshold_similarity_sld intValue]];
1195         [o_threshold_similarity_sld setToolTip: [NSString stringWithFormat:@"%i", [o_threshold_similarity_sld intValue]]];
1196     }
1197 }
1198
1199 - (IBAction)enableSepia:(id)sender
1200 {
1201     BOOL b_state = [o_sepia_ckb state];
1202
1203     [self setVideoFilter: "sepia" on: b_state];
1204     [o_sepia_fld setEnabled: b_state];
1205     [o_sepia_stp setEnabled: b_state];
1206     [o_sepia_lbl setEnabled: b_state];
1207 }
1208
1209 - (IBAction)sepiaModifierChanged:(id)sender
1210 {
1211     [self setVideoFilterProperty: "sepia-intensity" forFilter: "sepia" integer: [o_sepia_fld intValue]];
1212 }
1213
1214 - (IBAction)enableNoise:(id)sender
1215 {
1216     [self setVideoFilter: "noise" on: [o_noise_ckb state]];
1217 }
1218
1219 - (IBAction)enableGradient:(id)sender
1220 {
1221     BOOL b_state = [o_gradient_ckb state];
1222
1223     [self setVideoFilter: "gradient" on: b_state];
1224     [o_gradient_mode_pop setEnabled: b_state];
1225     [o_gradient_mode_lbl setEnabled: b_state];
1226     [o_gradient_color_ckb setEnabled: b_state];
1227     [o_gradient_cartoon_ckb setEnabled: b_state];
1228 }
1229
1230 - (IBAction)gradientModifierChanged:(id)sender
1231 {
1232     if (sender == o_gradient_mode_pop) {
1233         if ([[o_gradient_mode_pop selectedItem] tag] == 3)
1234             [self setVideoFilterProperty: "gradient-mode" forFilter: "gradient" string: "hough"];
1235         else if ([[o_gradient_mode_pop selectedItem] tag] == 2)
1236             [self setVideoFilterProperty: "gradient-mode" forFilter: "gradient" string: "edge"];
1237         else
1238             [self setVideoFilterProperty: "gradient-mode" forFilter: "gradient" string: "gradient"];
1239     } else if (sender == o_gradient_color_ckb)
1240         [self setVideoFilterProperty: "gradient-type" forFilter: "gradient" integer: [o_gradient_color_ckb state]];
1241     else
1242         [self setVideoFilterProperty: "gradient-cartoon" forFilter: "gradient" boolean: [o_gradient_cartoon_ckb state]];
1243 }
1244
1245 - (IBAction)enableExtract:(id)sender
1246 {
1247     BOOL b_state = [o_extract_ckb state];
1248     [self setVideoFilter: "extract" on: b_state];
1249     [o_extract_fld setEnabled: b_state];
1250     [o_extract_lbl setEnabled: b_state];
1251 }
1252
1253 - (IBAction)extractModifierChanged:(id)sender
1254 {
1255     [self setVideoFilterProperty: "extract-component" forFilter: "extract" integer: [o_extract_fld intValue]];
1256 }
1257
1258 - (IBAction)enableInvert:(id)sender
1259 {
1260     [self setVideoFilter: "invert" on: [o_invert_ckb state]];
1261 }
1262
1263 - (IBAction)enablePosterize:(id)sender
1264 {
1265     BOOL b_state = [o_posterize_ckb state];
1266
1267     [self setVideoFilter: "posterize" on: b_state];
1268     [o_posterize_fld setEnabled: b_state];
1269     [o_posterize_stp setEnabled: b_state];
1270     [o_posterize_lbl setEnabled: b_state];
1271 }
1272
1273 - (IBAction)posterizeModifierChanged:(id)sender
1274 {
1275     [self setVideoFilterProperty: "posterize-level" forFilter: "posterize" integer: [o_posterize_fld intValue]];
1276 }
1277
1278 - (IBAction)enableBlur:(id)sender
1279 {
1280     BOOL b_state = [o_blur_ckb state];
1281
1282     [self setVideoFilter: "motionblur" on: b_state];
1283     [o_blur_sld setEnabled: b_state];
1284     [o_blur_lbl setEnabled: b_state];
1285 }
1286
1287 - (IBAction)blurModifierChanged:(id)sender
1288 {
1289     [self setVideoFilterProperty: "blur-factor" forFilter: "motionblur" integer: [sender intValue]];
1290     [sender setToolTip: [NSString stringWithFormat:@"%i", [sender intValue]]];
1291 }
1292
1293 - (IBAction)enableMotionDetect:(id)sender
1294 {
1295     [self setVideoFilter: "motiondetect" on: [o_motiondetect_ckb state]];
1296 }
1297
1298 - (IBAction)enableWaterEffect:(id)sender
1299 {
1300     [self setVideoFilter: "ripple" on: [o_watereffect_ckb state]];
1301 }
1302
1303 - (IBAction)enableWaves:(id)sender
1304 {
1305     [self setVideoFilter: "wave" on: [o_waves_ckb state]];
1306 }
1307
1308 - (IBAction)enablePsychedelic:(id)sender
1309 {
1310     [self setVideoFilter: "psychedelic" on: [o_psychedelic_ckb state]];
1311 }
1312
1313 #pragma mark -
1314 #pragma mark Miscellaneous
1315 - (IBAction)enableAddText:(id)sender
1316 {
1317     BOOL b_state = [o_addtext_ckb state];
1318
1319     [o_addtext_pos_pop setEnabled: b_state];
1320     [o_addtext_pos_lbl setEnabled: b_state];
1321     [o_addtext_text_lbl setEnabled: b_state];
1322     [o_addtext_text_fld setEnabled: b_state];
1323     [self setVideoFilter: "marq" on: b_state];
1324     [self setVideoFilterProperty: "marq-marquee" forFilter: "marq" string: (char *)[[o_addtext_text_fld stringValue] UTF8String]];
1325     [self setVideoFilterProperty: "marq-position" forFilter: "marq" integer: [[o_addtext_pos_pop selectedItem] tag]];
1326 }
1327
1328 - (IBAction)addTextModifierChanged:(id)sender
1329 {
1330     if (sender == o_addtext_text_fld)
1331         [self setVideoFilterProperty: "marq-marquee" forFilter: "marq" string: (char *)[[o_addtext_text_fld stringValue] UTF8String]];
1332     else
1333         [self setVideoFilterProperty: "marq-position" forFilter: "marq" integer: [[o_addtext_pos_pop selectedItem] tag]];
1334 }
1335
1336 - (IBAction)enableAddLogo:(id)sender
1337 {
1338     BOOL b_state = [o_addlogo_ckb state];
1339
1340     [o_addlogo_pos_pop setEnabled: b_state];
1341     [o_addlogo_pos_lbl setEnabled: b_state];
1342     [o_addlogo_logo_fld setEnabled: b_state];
1343     [o_addlogo_logo_lbl setEnabled: b_state];
1344     [o_addlogo_transparency_sld setEnabled: b_state];
1345     [o_addlogo_transparency_lbl setEnabled: b_state];
1346     [self setVideoFilter: "logo" on: b_state];
1347 }
1348
1349 - (IBAction)addLogoModifierChanged:(id)sender
1350 {
1351     if (sender == o_addlogo_logo_fld)
1352         [self setVideoFilterProperty: "logo-file" forFilter: "logo" string: (char *)[[o_addlogo_logo_fld stringValue] UTF8String]];
1353     else if (sender == o_addlogo_pos_pop)
1354         [self setVideoFilterProperty: "logo-position" forFilter: "logo" integer: [[o_addlogo_pos_pop selectedItem] tag]];
1355     else {
1356         [self setVideoFilterProperty: "logo-opacity" forFilter: "logo" integer: [o_addlogo_transparency_sld intValue]];
1357         [o_addlogo_transparency_sld setToolTip: [NSString stringWithFormat:@"%i", [o_addlogo_transparency_sld intValue]]];
1358     }
1359 }
1360
1361 - (IBAction)enableAnaglyph:(id)sender
1362 {
1363     [self setVideoFilter: "anaglyph" on: [o_anaglyph_ckb state]];
1364 }
1365
1366 @end