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