]> git.sesse.net Git - vlc/blob - modules/gui/macosx/VideoEffects.m
macosx: hide bottom bar of main window only when really necessary
[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:[NSArray arrayWithObject:@";;;0;1.000000;1.000000;1.000000;1.000000;0.050000;16;2.000000;OTA=;4;4;0;16711680;20;15;120;Z3JhZGllbnQ=;1;0;16711680;6;80;VkxD;-1;;-1;255;2;3;3"], @"VideoEffectProfiles", [NSArray arrayWithObject:_NS("Default")], @"VideoEffectProfileNames", nil];
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_puzzle_blackslot_ckb setTitle:_NS("Black Slot")];
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 3D")];
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 = [NSString stringWithUTF8String: 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     [o_puzzle_blackslot_ckb setState: config_GetInt(p_intf, "puzzle-black-slot")];
381     b_state = [o_puzzle_ckb state];
382     [o_puzzle_rows_fld setEnabled: b_state];
383     [o_puzzle_rows_stp setEnabled: b_state];
384     [o_puzzle_rows_lbl setEnabled: b_state];
385     [o_puzzle_columns_fld setEnabled: b_state];
386     [o_puzzle_columns_stp setEnabled: b_state];
387     [o_puzzle_columns_lbl setEnabled: b_state];
388     [o_puzzle_blackslot_ckb setEnabled: b_state];
389     
390     [self setCloneValue: config_GetInt(p_intf, "clone-count")];
391     b_state = [o_clone_ckb state];
392     [o_clone_number_lbl setEnabled: b_state];
393     [o_clone_number_fld setEnabled: b_state];
394     [o_clone_number_stp setEnabled: b_state];
395
396     b_state = [o_wall_ckb state];
397     [self setWallRowsValue: config_GetInt(p_intf, "wall-rows")];
398     [o_wall_numofrows_lbl setEnabled: b_state];
399     [o_wall_numofrows_fld setEnabled: b_state];
400     [o_wall_numofrows_stp setEnabled: b_state];
401     [self setWallColumnsValue: config_GetInt(p_intf, "wall-cols")];
402     [o_wall_numofcols_lbl setEnabled: b_state];
403     [o_wall_numofcols_fld setEnabled: b_state];
404     [o_wall_numofcols_stp setEnabled: b_state];
405
406     [o_threshold_color_fld setStringValue: [[NSString stringWithFormat:@"%llx", config_GetInt(p_intf, "colorthres-color")] uppercaseString]];
407     [o_threshold_saturation_sld setIntValue: config_GetInt(p_intf, "colorthres-saturationthres")];
408     [o_threshold_saturation_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "colorthres-saturationthres")]];
409     [o_threshold_similarity_sld setIntValue: config_GetInt(p_intf, "colorthres-similaritythres")];
410     [o_threshold_similarity_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "colorthres-similaritythres")]];
411     
412     b_state = [o_threshold_ckb state];
413     [o_threshold_color_fld setEnabled: b_state];
414     [o_threshold_color_lbl setEnabled: b_state];
415     [o_threshold_saturation_sld setEnabled: b_state];
416     [o_threshold_saturation_lbl setEnabled: b_state];
417     [o_threshold_similarity_sld setEnabled: b_state];
418     [o_threshold_similarity_lbl setEnabled: b_state];
419     
420     [self setSepiaValue: config_GetInt(p_intf, "sepia-intensity")];
421     b_state = [o_sepia_ckb state];
422     [o_sepia_fld setEnabled: b_state];
423     [o_sepia_stp setEnabled: b_state];
424     [o_sepia_lbl setEnabled: b_state];
425
426     tmpChar = config_GetPsz(p_intf, "gradient-mode");
427     tmpString = [NSString stringWithUTF8String: tmpChar];
428     if ([tmpString isEqualToString:@"hough"])
429         [o_gradient_mode_pop selectItemWithTag: 3];
430     else if ([tmpString isEqualToString:@"edge"])
431         [o_gradient_mode_pop selectItemWithTag: 2];
432     else
433         [o_gradient_mode_pop selectItemWithTag: 1];
434     FREENULL(tmpChar);
435     [o_gradient_cartoon_ckb setState: config_GetInt(p_intf, "gradient-cartoon")];
436     [o_gradient_color_ckb setState: config_GetInt(p_intf, "gradient-type")];
437     b_state = [o_gradient_ckb state];
438     [o_gradient_mode_pop setEnabled: b_state];
439     [o_gradient_mode_lbl setEnabled: b_state];
440     [o_gradient_cartoon_ckb setEnabled: b_state];
441     [o_gradient_color_ckb setEnabled: b_state];
442
443     [o_extract_fld setStringValue: [[NSString stringWithFormat:@"%llx", config_GetInt(p_intf, "extract-component")] uppercaseString]];
444     [o_extract_fld setEnabled: [o_extract_ckb state]];
445     [o_extract_lbl setEnabled: [o_extract_ckb state]];
446
447     [self setPosterizeValue: config_GetInt(p_intf, "posterize-level")];
448     b_state = [o_posterize_ckb state];
449     [o_posterize_fld setEnabled: b_state];
450     [o_posterize_stp setEnabled: b_state];
451     [o_posterize_lbl setEnabled: b_state];
452     
453     [o_blur_sld setIntValue: config_GetInt(p_intf, "blur-factor")];
454     [o_blur_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "blur-factor")]];
455     [o_blur_sld setEnabled: [o_blur_ckb state]];
456     [o_blur_lbl setEnabled: [o_blur_ckb state]];
457
458     tmpChar = config_GetPsz(p_intf, "marq-marquee");
459     if (tmpChar) {
460         [o_addtext_text_fld setStringValue: [NSString stringWithUTF8String: tmpChar]];
461         FREENULL(tmpChar);
462     } else
463         [o_addtext_text_fld setStringValue: @""];
464     [o_addtext_pos_pop selectItemWithTag: config_GetInt(p_intf, "marq-position")];
465     b_state = [o_addtext_ckb state];
466     [o_addtext_pos_pop setEnabled: b_state];
467     [o_addtext_pos_lbl setEnabled: b_state];
468     [o_addtext_text_lbl setEnabled: b_state];
469     [o_addtext_text_fld setEnabled: b_state];
470
471     tmpChar = config_GetPsz(p_intf, "logo-file");
472     if (tmpChar) {
473         [o_addlogo_logo_fld setStringValue: [NSString stringWithUTF8String: tmpChar]];
474         FREENULL(tmpChar);
475     } else
476         [o_addlogo_logo_fld setStringValue: @""];
477     [o_addlogo_pos_pop selectItemWithTag: config_GetInt(p_intf, "logo-position")];
478     [o_addlogo_transparency_sld setIntValue: config_GetInt(p_intf, "logo-opacity")];
479     [o_addlogo_transparency_sld setToolTip: [NSString stringWithFormat:@"%lli", config_GetInt(p_intf, "logo-opacity")]];
480     b_state = [o_addlogo_ckb state];
481     [o_addlogo_pos_pop setEnabled: b_state];
482     [o_addlogo_pos_lbl setEnabled: b_state];
483     [o_addlogo_logo_fld setEnabled: b_state];
484     [o_addlogo_logo_lbl setEnabled: b_state];
485     [o_addlogo_transparency_sld setEnabled: b_state];
486     [o_addlogo_transparency_lbl setEnabled: b_state];
487 }
488
489 - (void)setVideoFilter: (char *)psz_name on:(BOOL)b_on
490 {
491     char *psz_string, *psz_parser;
492     const char *psz_filter_type;
493
494     module_t *p_obj = module_find(psz_name);
495     if (!p_obj) {
496         msg_Err(p_intf, "Unable to find filter module \"%s\".", psz_name);
497         return;
498     }
499     msg_Dbg(p_intf, "will set filter '%s'", psz_name);
500
501     if (module_provides(p_obj, "video splitter")) {
502         psz_filter_type = "video-splitter";
503     } else if (module_provides(p_obj, "video filter2")) {
504         psz_filter_type = "video-filter";
505     } else if (module_provides(p_obj, "sub source")) {
506         psz_filter_type = "sub-source";
507     } else if (module_provides(p_obj, "sub filter")) {
508         psz_filter_type = "sub-filter";
509     } else {
510         msg_Err(p_intf, "Unknown video filter type.");
511         return;
512     }
513
514     psz_string = config_GetPsz(p_intf, psz_filter_type);
515
516     if (b_on) {
517         if (!psz_string)
518             psz_string = psz_name;
519         else if (strstr(psz_string, psz_name) == NULL)
520             psz_string = (char *)[[NSString stringWithFormat: @"%s:%s", psz_string, psz_name] UTF8String];
521     } else {
522         if (!psz_string)
523             return;
524
525         psz_parser = strstr(psz_string, psz_name);
526         if (psz_parser) {
527             if (*(psz_parser + strlen(psz_name)) == ':') {
528                 memmove(psz_parser, psz_parser + strlen(psz_name) + 1,
529                         strlen(psz_parser + strlen(psz_name) + 1) + 1);
530             } else {
531                 *psz_parser = '\0';
532             }
533
534             /* Remove trailing : : */
535             if (strlen(psz_string) > 0 && *(psz_string + strlen(psz_string) -1) == ':')
536                 *(psz_string + strlen(psz_string) -1) = '\0';
537         } else {
538             free(psz_string);
539             return;
540         }
541     }
542     config_PutPsz(p_intf, psz_filter_type, psz_string);
543
544     /* Try to set on the fly */
545     if (!strcmp(psz_filter_type, "video-splitter")) {
546         playlist_t *p_playlist = pl_Get(p_intf);
547         var_SetString(p_playlist, psz_filter_type, psz_string);
548     } else {
549         vout_thread_t *p_vout = getVout();
550         if (p_vout) {
551             var_SetString(p_vout, psz_filter_type, psz_string);
552             vlc_object_release(p_vout);
553         }
554     }
555 }
556
557 - (void)restartFilterIfNeeded: (char *)psz_filter option: (char *)psz_name
558 {
559     vout_thread_t *p_vout = getVout();
560
561     if (p_vout == NULL)
562         return;
563     else
564         vlc_object_release(p_vout);
565
566     vlc_object_t *p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
567     if (p_filter) {
568         int i_type;
569         i_type = var_Type(p_filter, psz_name);
570         if (i_type == 0)
571             i_type = config_GetType(p_intf, psz_name);
572
573         if (!(i_type & VLC_VAR_ISCOMMAND)) {
574             msg_Warn(p_intf, "Brute-restarting filter '%s', because the last changed option isn't a command", psz_name);
575             [self setVideoFilter: psz_filter on: NO];
576             [self setVideoFilter: psz_filter on: YES];
577         } else
578             msg_Dbg(p_intf, "restart not needed");
579
580         vlc_object_release(p_filter);
581     }
582 }
583
584 - (void)setVideoFilterProperty: (char *)psz_name forFilter: (char *)psz_filter integer: (int)i_value
585 {
586     vout_thread_t *p_vout = getVout();
587     vlc_object_t *p_filter;
588
589     config_PutInt(p_intf, psz_name, i_value);
590
591     if (p_vout) {
592         p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
593
594         if (!p_filter) {
595             msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
596             vlc_object_release(p_vout);
597             return;
598         }
599         var_SetInteger(p_filter, psz_name, i_value);
600         vlc_object_release(p_vout);
601         vlc_object_release(p_filter);
602
603         [self restartFilterIfNeeded: psz_filter option: psz_name];
604     }
605 }
606
607 - (void)setVideoFilterProperty: (char *)psz_name forFilter: (char *)psz_filter float: (float)f_value
608 {
609     vout_thread_t *p_vout = getVout();
610     vlc_object_t *p_filter;
611
612     config_PutFloat(p_intf, psz_name, f_value);
613
614     if (p_vout) {
615         p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
616
617         if (!p_filter) {
618             msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
619             vlc_object_release(p_vout);
620             return;
621         }
622         var_SetFloat(p_filter, psz_name, f_value);
623         vlc_object_release(p_vout);
624         vlc_object_release(p_filter);
625
626         [self restartFilterIfNeeded: psz_filter option: psz_name];
627     }
628 }
629
630 - (void)setVideoFilterProperty: (char *)psz_name forFilter: (char *)psz_filter string: (char *)psz_value
631 {
632     vout_thread_t *p_vout = getVout();
633     vlc_object_t *p_filter;
634
635     config_PutPsz(p_intf, psz_name, EnsureUTF8(psz_value));
636
637     if (p_vout) {
638         p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
639
640         if (!p_filter) {
641             msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
642             vlc_object_release(p_vout);
643             return;
644         }
645         var_SetString(p_filter, psz_name, EnsureUTF8(psz_value));
646         vlc_object_release(p_vout);
647         vlc_object_release(p_filter);
648
649         [self restartFilterIfNeeded: psz_filter option: psz_name];
650     }
651 }
652
653 - (void)setVideoFilterProperty: (char *)psz_name forFilter: (char *)psz_filter boolean: (BOOL)b_value
654 {
655     vout_thread_t *p_vout = getVout();
656     vlc_object_t *p_filter;
657
658     config_PutInt(p_intf, psz_name, b_value);
659
660     if (p_vout) {
661         p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
662
663         if (!p_filter) {
664             msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
665             vlc_object_release(p_vout);
666             return;
667         }
668         var_SetBool(p_filter, psz_name, b_value);
669         vlc_object_release(p_vout);
670         vlc_object_release(p_filter);
671     }
672 }
673
674 - (NSString *)generateProfileString
675 {
676     return [NSString stringWithFormat:@"%s;%s;%s;%lli;%f;%f;%f;%f;%f;%lli;%f;%s;%lli;%lli;%lli;%lli;%lli;%lli;%lli;%s;%lli;%lli;%lli;%lli;%lli;%s;%lli;%s;%lli;%lli;%lli;%lli;%lli",
677             vlc_b64_encode(config_GetPsz(p_intf, "video-filter")),
678             vlc_b64_encode(config_GetPsz(p_intf, "sub-source")),
679             vlc_b64_encode(config_GetPsz(p_intf, "video-splitter")),
680             config_GetInt(p_intf, "hue"),
681             config_GetFloat(p_intf, "contrast"),
682             config_GetFloat(p_intf, "brightness"),
683             config_GetFloat(p_intf, "saturation"),
684             config_GetFloat(p_intf, "gamma"),
685             config_GetFloat(p_intf, "sharpen-sigma"),
686             config_GetInt(p_intf, "gradfun-radius"),
687             config_GetFloat(p_intf, "grain-variance"),
688             vlc_b64_encode(config_GetPsz(p_intf, "transform-type")),
689             config_GetInt(p_intf, "puzzle-rows"),
690             config_GetInt(p_intf, "puzzle-cols"),
691             config_GetInt(p_intf, "puzzle-black-slot"),
692             config_GetInt(p_intf, "colorthres-color"),
693             config_GetInt(p_intf, "colorthres-saturationthres"),
694             config_GetInt(p_intf, "colorthres-similaritythres"),
695             config_GetInt(p_intf, "sepia-intensity"),
696             vlc_b64_encode(config_GetPsz(p_intf, "gradient-mode")),
697             config_GetInt(p_intf, "gradient-cartoon"),
698             config_GetInt(p_intf, "gradient-type"),
699             config_GetInt(p_intf, "extract-component"),
700             config_GetInt(p_intf, "posterize-level"),
701             config_GetInt(p_intf, "blur-factor"),
702             vlc_b64_encode(config_GetPsz(p_intf, "marq-marquee")),
703             config_GetInt(p_intf, "marq-position"),
704             vlc_b64_encode(config_GetPsz(p_intf, "logo-file")),
705             config_GetInt(p_intf, "logo-position"),
706             config_GetInt(p_intf, "logo-opacity"),
707             config_GetInt(p_intf, "clone-count"),
708             config_GetInt(p_intf, "wall-rows"),
709             config_GetInt(p_intf, "wall-cols")
710             ];
711 }
712
713 #pragma mark -
714 #pragma mark generic UI code
715
716 - (void)saveCurrentProfile
717 {
718     if (i_old_profile_index == -1)
719         return;
720
721     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
722     /* fetch all the current settings in a uniform string */
723     NSString *newProfile = [self generateProfileString];
724
725     NSMutableArray *workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"VideoEffectProfiles"]];
726     if (i_old_profile_index >= [workArray count])
727         return;
728
729     [workArray replaceObjectAtIndex:i_old_profile_index withObject:newProfile];
730     [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfiles"];
731     [workArray release];
732     [defaults synchronize];
733 }
734
735 - (IBAction)toggleWindow:(id)sender
736 {
737     if ([o_window isVisible])
738         [o_window orderOut:sender];
739     else {
740         [o_window setLevel: [[[VLCMain sharedInstance] voutController] currentWindowLevel]];
741         [o_window makeKeyAndOrderFront:sender];
742     }
743 }
744
745 - (IBAction)profileSelectorAction:(id)sender
746 {
747     [self saveCurrentProfile];
748     i_old_profile_index = [o_profile_pop indexOfSelectedItem];
749
750     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
751     NSUInteger selectedProfile = [o_profile_pop indexOfSelectedItem];
752
753     /* disable all current video filters, if a vout is available */
754     vout_thread_t *p_vout = getVout();
755     if (p_vout) {
756         var_SetString(p_vout, "video-filter", "");
757         var_SetString(p_vout, "sub-source", "");
758         var_SetString(p_vout, "video-splitter", "");
759         vlc_object_release(p_vout);
760     }
761
762     /* fetch preset */
763     NSArray *items = [[[defaults objectForKey:@"VideoEffectProfiles"] objectAtIndex:selectedProfile] componentsSeparatedByString:@";"];
764
765     /* filter handling */
766     NSString *tempString = [NSString stringWithFormat:@"%s", vlc_b64_decode([[items objectAtIndex:0] UTF8String])];
767     NSArray *tempArray;
768     NSUInteger count;
769     /* enable the new filters */
770     if ([tempString length] > 0) {
771         tempArray = [tempString componentsSeparatedByString:@":"];
772         count = [tempArray count];
773         for (NSUInteger x = 0; x < count; x++)
774             [self setVideoFilter:(char *)[[tempArray objectAtIndex:x] UTF8String] on:YES];
775     }
776     config_PutPsz(p_intf, "video-filter", [tempString UTF8String]);
777
778     tempString = [NSString stringWithFormat:@"%s", vlc_b64_decode([[items objectAtIndex:1] UTF8String])];
779     /* enable another round of new filters */
780     if ([tempString length] > 0) {
781         tempArray = [tempString componentsSeparatedByString:@":"];
782         count = [tempArray count];
783         for (NSUInteger x = 0; x < count; x++)
784             [self setVideoFilter:(char *)[[tempArray objectAtIndex:x] UTF8String] on:YES];
785     }
786     config_PutPsz(p_intf,"sub-source", [tempString UTF8String]);
787
788     tempString = [NSString stringWithFormat:@"%s", vlc_b64_decode([[items objectAtIndex:2] UTF8String])];
789     /* enable another round of new filters */
790     if ([tempString length] > 0) {
791         tempArray = [tempString componentsSeparatedByString:@":"];
792         count = [tempArray count];
793         for (NSUInteger x = 0; x < count; x++)
794             [self setVideoFilter:(char *)[[tempArray objectAtIndex:x] UTF8String] on:YES];
795     }
796     config_PutPsz(p_intf,"video-splitter", [tempString UTF8String]);
797
798     /* try to set filter values on-the-fly and store them appropriately */
799     [self setVideoFilterProperty:"hue" forFilter:"adjust" integer:[[items objectAtIndex:3] intValue]];
800     [self setVideoFilterProperty:"contrast" forFilter:"adjust" float:[[items objectAtIndex:4] floatValue]];
801     [self setVideoFilterProperty:"brightness" forFilter:"adjust" float:[[items objectAtIndex:5] floatValue]];
802     [self setVideoFilterProperty:"saturation" forFilter:"adjust" float:[[items objectAtIndex:6] floatValue]];
803     [self setVideoFilterProperty:"gamma" forFilter:"adjust" float:[[items objectAtIndex:7] floatValue]];
804     [self setVideoFilterProperty:"sharpen-sigma" forFilter:"sharpen" float:[[items objectAtIndex:8] floatValue]];
805     [self setVideoFilterProperty:"gradfun-radius" forFilter:"gradfun" integer:[[items objectAtIndex:9] intValue]];
806     [self setVideoFilterProperty:"grain-variance" forFilter:"grain" float:[[items objectAtIndex:10] floatValue]];
807     [self setVideoFilterProperty:"transform-type" forFilter:"transform" string:vlc_b64_decode([[items objectAtIndex:11] UTF8String])];
808     [self setVideoFilterProperty:"puzzle-rows" forFilter:"puzzle" integer:[[items objectAtIndex:12] intValue]];
809     [self setVideoFilterProperty:"puzzle-cols" forFilter:"puzzle" integer:[[items objectAtIndex:13] intValue]];
810     [self setVideoFilterProperty:"puzzle-black-slot" forFilter:"puzzle" boolean:[[items objectAtIndex:14] intValue]];
811     [self setVideoFilterProperty:"colorthres-color" forFilter:"colorthres" integer:[[items objectAtIndex:15] intValue]];
812     [self setVideoFilterProperty:"colorthres-saturationthres" forFilter:"colorthres" integer:[[items objectAtIndex:16] intValue]];
813     [self setVideoFilterProperty:"colorthres-similaritythres" forFilter:"colorthres" integer:[[items objectAtIndex:17] intValue]];
814     [self setVideoFilterProperty:"sepia-intensity" forFilter:"sepia" integer:[[items objectAtIndex:18] intValue]];
815     [self setVideoFilterProperty:"gradient-mode" forFilter:"gradient" string:vlc_b64_decode([[items objectAtIndex:19] UTF8String])];
816     [self setVideoFilterProperty:"gradient-cartoon" forFilter:"gradient" integer:[[items objectAtIndex:20] intValue]];
817     [self setVideoFilterProperty:"gradient-type" forFilter:"gradient" integer:[[items objectAtIndex:21] intValue]];
818     [self setVideoFilterProperty:"extract-component" forFilter:"extract" integer:[[items objectAtIndex:22] intValue]];
819     [self setVideoFilterProperty:"posterize-level" forFilter:"posterize" integer:[[items objectAtIndex:23] intValue]];
820     [self setVideoFilterProperty:"blur-factor" forFilter:"motionblur" integer:[[items objectAtIndex:24] intValue]];
821     [self setVideoFilterProperty:"marq-marquee" forFilter:"marq" string:vlc_b64_decode([[items objectAtIndex:25] UTF8String])];
822     [self setVideoFilterProperty:"marq-position" forFilter:"marq" integer:[[items objectAtIndex:26] intValue]];
823     [self setVideoFilterProperty:"logo-file" forFilter:"logo" string:vlc_b64_decode([[items objectAtIndex:27] UTF8String])];
824     [self setVideoFilterProperty:"logo-position" forFilter:"logo" integer:[[items objectAtIndex:28] intValue]];
825     [self setVideoFilterProperty:"logo-opacity" forFilter:"logo" integer:[[items objectAtIndex:29] intValue]];
826     [self setVideoFilterProperty:"clone-count" forFilter:"clone" integer:[[items objectAtIndex:30] intValue]];
827     [self setVideoFilterProperty:"wall-rows" forFilter:"wall" integer:[[items objectAtIndex:31] intValue]];
828     [self setVideoFilterProperty:"wall-cols" forFilter:"wall" integer:[[items objectAtIndex:32] intValue]];
829
830     [defaults setInteger:selectedProfile forKey:@"VideoEffectSelectedProfile"];
831     [defaults synchronize];
832
833     [self resetValues];
834 }
835
836 - (IBAction)addProfile:(id)sender
837 {
838     /* show panel */
839     VLCEnterTextPanel * panel = [VLCEnterTextPanel sharedInstance];
840     [panel setTitle: _NS("Duplicate current profile for a new profile")];
841     [panel setSubTitle: _NS("Enter a name for the new profile:")];
842     [panel setCancelButtonLabel: _NS("Cancel")];
843     [panel setOKButtonLabel: _NS("Save")];
844     [panel setTarget:self];
845
846     [panel runModalForWindow:o_window];
847 }
848
849 - (void)panel:(VLCEnterTextPanel *)panel returnValue:(NSUInteger)value text:(NSString *)text
850 {
851     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
852
853     if (value != NSOKButton) {
854         [o_profile_pop selectItemAtIndex:[defaults integerForKey:@"VideoEffectSelectedProfile"]];
855         return;
856     }
857
858     NSArray *profileNames = [defaults objectForKey:@"VideoEffectProfileNames"];
859
860     // duplicate names are not allowed in the popup control
861     if ([text length] == 0 || [profileNames containsObject:text]) {
862         [o_profile_pop selectItemAtIndex:[defaults integerForKey:@"VideoEffectSelectedProfile"]];
863
864         NSAlert *alert = [[[NSAlert alloc] init] autorelease];
865         [alert setAlertStyle:NSCriticalAlertStyle];
866         [alert setMessageText:_NS("Please enter a unique name for the new profile.")];
867         [alert setInformativeText:_NS("Multiple profiles with the same name are not allowed.")];
868
869         [alert beginSheetModalForWindow:o_window
870                           modalDelegate:nil
871                          didEndSelector:nil
872                             contextInfo:nil];
873         return;
874     }
875
876     /* fetch all the current settings in a uniform string */
877     NSString *newProfile = [self generateProfileString];
878
879     /* add string to user defaults as well as a label */
880
881     NSMutableArray *workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"VideoEffectProfiles"]];
882     [workArray addObject:newProfile];
883     [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfiles"];
884     [defaults setInteger:[workArray count] - 1 forKey:@"VideoEffectSelectedProfile"];
885     [workArray release];
886     
887     workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"VideoEffectProfileNames"]];
888     [workArray addObject:text];
889     [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfileNames"];
890     [workArray release];
891
892     /* save defaults */
893     [defaults synchronize];
894
895     /* refresh UI */
896     [self resetProfileSelector];
897 }
898
899 - (IBAction)removeProfile:(id)sender
900 {
901     /* show panel */
902     VLCSelectItemInPopupPanel * panel = [VLCSelectItemInPopupPanel sharedInstance];
903     [panel setTitle:_NS("Remove a preset")];
904     [panel setSubTitle:_NS("Select the preset you would like to remove:")];
905     [panel setOKButtonLabel:_NS("Remove")];
906     [panel setCancelButtonLabel:_NS("Cancel")];
907     [panel setPopupButtonContent:[[NSUserDefaults standardUserDefaults] objectForKey:@"VideoEffectProfileNames"]];
908     [panel setTarget:self];
909
910     [panel runModalForWindow:o_window];
911 }
912
913 - (void)panel:(VLCSelectItemInPopupPanel *)panel returnValue:(NSUInteger)value item:(NSUInteger)item
914 {
915     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
916
917     if (value != NSOKButton) {
918         [o_profile_pop selectItemAtIndex:[defaults integerForKey:@"VideoEffectSelectedProfile"]];
919         return;
920     }
921
922     /* remove selected profile from settings */
923     NSMutableArray *workArray = [[NSMutableArray alloc] initWithArray: [defaults objectForKey:@"VideoEffectProfiles"]];
924     [workArray removeObjectAtIndex:item];
925     [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfiles"];
926     [workArray release];
927
928     workArray = [[NSMutableArray alloc] initWithArray: [defaults objectForKey:@"VideoEffectProfileNames"]];
929     [workArray removeObjectAtIndex:item];
930     [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfileNames"];
931     [workArray release];
932
933     if (i_old_profile_index >= item)
934         [defaults setInteger:i_old_profile_index - 1 forKey:@"VideoEffectSelectedProfile"];
935
936     /* save defaults */
937     [defaults synchronize];
938
939     /* do not save deleted profile */
940     i_old_profile_index = -1;
941     /* refresh UI */
942     [self resetProfileSelector];
943 }
944
945 #pragma mark -
946 #pragma mark basic
947 - (IBAction)enableAdjust:(id)sender
948 {
949     BOOL b_state = [o_adjust_ckb state];
950
951     [self setVideoFilter: "adjust" on: b_state];
952     [o_adjust_brightness_sld setEnabled: b_state];
953     [o_adjust_brightness_ckb setEnabled: b_state];
954     [o_adjust_brightness_lbl setEnabled: b_state];
955     [o_adjust_contrast_sld setEnabled: b_state];
956     [o_adjust_contrast_lbl setEnabled: b_state];
957     [o_adjust_gamma_sld setEnabled: b_state];
958     [o_adjust_gamma_lbl setEnabled: b_state];
959     [o_adjust_hue_sld setEnabled: b_state];
960     [o_adjust_hue_lbl setEnabled: b_state];
961     [o_adjust_saturation_sld setEnabled: b_state];
962     [o_adjust_saturation_lbl setEnabled: b_state];
963     [o_adjust_reset_btn setEnabled: b_state];
964 }
965
966 - (IBAction)adjustSliderChanged:(id)sender
967 {
968     if (sender == o_adjust_brightness_sld)
969         [self setVideoFilterProperty: "brightness" forFilter: "adjust" float: [o_adjust_brightness_sld floatValue]];
970     else if (sender == o_adjust_contrast_sld)
971         [self setVideoFilterProperty: "contrast" forFilter: "adjust" float: [o_adjust_contrast_sld floatValue]];
972     else if (sender == o_adjust_gamma_sld)
973         [self setVideoFilterProperty: "gamma" forFilter: "adjust" float: [o_adjust_gamma_sld floatValue]];
974     else if (sender == o_adjust_hue_sld)
975         [self setVideoFilterProperty: "hue" forFilter: "adjust" integer: [o_adjust_hue_sld intValue]];
976     else if (sender == o_adjust_saturation_sld)
977         [self setVideoFilterProperty: "saturation" forFilter: "adjust" float: [o_adjust_saturation_sld floatValue]];
978
979     if (sender == o_adjust_hue_sld)
980         [o_adjust_hue_sld setToolTip: [NSString stringWithFormat:@"%i", [o_adjust_hue_sld intValue]]];
981     else
982         [sender setToolTip: [NSString stringWithFormat:@"%0.3f", [sender floatValue]]];
983 }
984
985 - (IBAction)enableAdjustBrightnessThreshold:(id)sender
986 {
987     if (sender == o_adjust_reset_btn) {
988         [o_adjust_brightness_sld setFloatValue: 1.0];
989         [o_adjust_contrast_sld setFloatValue: 1.0];
990         [o_adjust_gamma_sld setFloatValue: 1.0];
991         [o_adjust_hue_sld setIntValue: 0];
992         [o_adjust_saturation_sld setFloatValue: 1.0];
993         [o_adjust_brightness_sld setToolTip: [NSString stringWithFormat:@"%0.3f", 1.0]];
994         [o_adjust_contrast_sld setToolTip: [NSString stringWithFormat:@"%0.3f", 1.0]];
995         [o_adjust_gamma_sld setToolTip: [NSString stringWithFormat:@"%0.3f", 1.0]];
996         [o_adjust_hue_sld setToolTip: [NSString stringWithFormat:@"%i", 0]];
997         [o_adjust_saturation_sld setToolTip: [NSString stringWithFormat:@"%0.3f", 1.0]];
998         [self setVideoFilterProperty: "brightness" forFilter: "adjust" float: 1.0];
999         [self setVideoFilterProperty: "contrast" forFilter: "adjust" float: 1.0];
1000         [self setVideoFilterProperty: "gamma" forFilter: "adjust" float: 1.0];
1001         [self setVideoFilterProperty: "hue" forFilter: "adjust" integer: 0.0];
1002         [self setVideoFilterProperty: "saturation" forFilter: "adjust" float: 1.0];
1003     } else
1004         config_PutInt(p_intf, "brightness-threshold", [o_adjust_brightness_ckb state]);
1005 }
1006
1007 - (IBAction)enableSharpen:(id)sender
1008 {
1009     BOOL b_state = [o_sharpen_ckb state];
1010
1011     [self setVideoFilter: "sharpen" on: b_state];
1012     [o_sharpen_sld setEnabled: b_state];
1013     [o_sharpen_lbl setEnabled: b_state];
1014 }
1015
1016 - (IBAction)sharpenSliderChanged:(id)sender
1017 {
1018     [self setVideoFilterProperty: "sharpen-sigma" forFilter: "sharpen" float: [sender floatValue]];
1019     [sender setToolTip: [NSString stringWithFormat:@"%0.3f", [sender floatValue]]];
1020 }
1021
1022 - (IBAction)enableBanding:(id)sender
1023 {
1024     BOOL b_state = [o_banding_ckb state];
1025
1026     [self setVideoFilter: "gradfun" on: b_state];
1027     [o_banding_sld setEnabled: b_state];
1028     [o_banding_lbl setEnabled: b_state];
1029 }
1030
1031 - (IBAction)bandingSliderChanged:(id)sender
1032 {
1033     [self setVideoFilterProperty: "gradfun-radius" forFilter: "gradfun" integer: [sender intValue]];
1034     [sender setToolTip: [NSString stringWithFormat:@"%i", [sender intValue]]];
1035 }
1036
1037 - (IBAction)enableGrain:(id)sender
1038 {
1039     BOOL b_state = [o_grain_ckb state];
1040
1041     [self setVideoFilter: "grain" on: b_state];
1042     [o_grain_sld setEnabled: b_state];
1043     [o_grain_lbl setEnabled: b_state];
1044 }
1045
1046 - (IBAction)grainSliderChanged:(id)sender
1047 {
1048     [self setVideoFilterProperty: "grain-variance" forFilter: "grain" float: [sender floatValue]];
1049     [sender setToolTip: [NSString stringWithFormat:@"%0.3f", [sender floatValue]]];
1050 }
1051
1052
1053 #pragma mark -
1054 #pragma mark crop
1055
1056 - (IBAction)cropObjectChanged:(id)sender
1057 {
1058     if ([o_crop_sync_top_bottom_ckb state]) {
1059         if (sender == o_crop_bottom_fld || sender == o_crop_bottom_stp)
1060             [self setCropTopValue: [self cropBottomValue]];
1061         else
1062             [self setCropBottomValue: [self cropTopValue]];
1063     }
1064     if ([o_crop_sync_left_right_ckb state]) {
1065         if (sender == o_crop_right_fld || sender == o_crop_right_stp)
1066             [self setCropLeftValue: [self cropRightValue]];
1067         else
1068             [self setCropRightValue: [self cropLeftValue]];
1069     }
1070
1071     vout_thread_t *p_vout = getVout();
1072     if (p_vout) {
1073         var_SetInteger(p_vout, "crop-top", [o_crop_top_fld intValue]);
1074         var_SetInteger(p_vout, "crop-bottom", [o_crop_bottom_fld intValue]);
1075         var_SetInteger(p_vout, "crop-left", [o_crop_left_fld intValue]);
1076         var_SetInteger(p_vout, "crop-right", [o_crop_right_fld intValue]);
1077         vlc_object_release(p_vout);
1078     }
1079 }
1080
1081 #pragma mark -
1082 #pragma mark geometry
1083 - (IBAction)enableTransform:(id)sender
1084 {
1085     [self setVideoFilter: "transform" on: [o_transform_ckb state]];
1086     [o_transform_pop setEnabled: [o_transform_ckb state]];
1087 }
1088
1089 - (IBAction)transformModifierChanged:(id)sender
1090 {
1091     NSInteger tag = [[o_transform_pop selectedItem] tag];
1092     char *psz_string = (char *)[[NSString stringWithFormat:@"%li", tag] UTF8String];
1093     if (tag == 1)
1094         psz_string = (char *)"hflip";
1095     else if (tag == 2)
1096         psz_string = (char *)"vflip";
1097
1098     [self setVideoFilterProperty: "transform-type" forFilter: "transform" string: psz_string];
1099 }
1100
1101 - (IBAction)enableZoom:(id)sender
1102 {
1103     [self setVideoFilter: "magnify" on: [o_zoom_ckb state]];
1104 }
1105
1106 - (IBAction)enablePuzzle:(id)sender
1107 {
1108     BOOL b_state = [o_puzzle_ckb state];
1109
1110     [self setVideoFilter: "puzzle" on: b_state];
1111     [o_puzzle_columns_fld setEnabled: b_state];
1112     [o_puzzle_columns_stp setEnabled: b_state];
1113     [o_puzzle_columns_lbl setEnabled: b_state];
1114     [o_puzzle_rows_fld setEnabled: b_state];
1115     [o_puzzle_rows_stp setEnabled: b_state];
1116     [o_puzzle_rows_lbl setEnabled: b_state];
1117     [o_puzzle_blackslot_ckb setEnabled: b_state];
1118 }
1119
1120 - (IBAction)puzzleModifierChanged:(id)sender
1121 {
1122     if (sender == o_puzzle_blackslot_ckb)
1123         [self setVideoFilterProperty: "puzzle-black-slot" forFilter: "puzzle" boolean: [o_puzzle_blackslot_ckb state]];
1124     else if (sender == o_puzzle_columns_fld || sender == o_puzzle_columns_stp)
1125         [self setVideoFilterProperty: "puzzle-cols" forFilter: "puzzle" integer: [sender intValue]];
1126     else
1127         [self setVideoFilterProperty: "puzzle-rows" forFilter: "puzzle" integer: [sender intValue]];
1128 }
1129
1130 - (IBAction)enableClone:(id)sender
1131 {
1132     BOOL b_state = [o_clone_ckb state];
1133
1134     if (b_state && [o_wall_ckb state]) {
1135         [o_wall_ckb setState: NSOffState];
1136         [self enableWall: o_wall_ckb];
1137     }
1138
1139     [self setVideoFilter: "clone" on: b_state];
1140     [o_clone_number_lbl setEnabled: b_state];
1141     [o_clone_number_fld setEnabled: b_state];
1142     [o_clone_number_stp setEnabled: b_state];
1143 }
1144
1145 - (IBAction)cloneModifierChanged:(id)sender
1146 {
1147     [self setVideoFilterProperty: "clone-count" forFilter: "clone" integer: [o_clone_number_fld intValue]];
1148 }
1149
1150 - (IBAction)enableWall:(id)sender
1151 {
1152     BOOL b_state = [o_wall_ckb state];
1153
1154     if (b_state && [o_clone_ckb state]) {
1155         [o_clone_ckb setState: NSOffState];
1156         [self enableClone: o_clone_ckb];
1157     }
1158
1159     [self setVideoFilter: "wall" on: b_state];
1160     [o_wall_numofcols_fld setEnabled: b_state];
1161     [o_wall_numofcols_stp setEnabled: b_state];
1162     [o_wall_numofcols_lbl setEnabled: b_state];
1163     
1164     [o_wall_numofrows_fld setEnabled: b_state];
1165     [o_wall_numofrows_stp setEnabled: b_state];
1166     [o_wall_numofrows_lbl setEnabled: b_state];
1167 }
1168
1169 - (IBAction)wallModifierChanged:(id)sender
1170 {
1171     if (sender == o_wall_numofcols_fld || sender == o_wall_numofcols_stp)
1172         [self setVideoFilterProperty: "wall-cols" forFilter: "wall" integer: [sender intValue]];
1173     else
1174         [self setVideoFilterProperty: "wall-rows" forFilter: "wall" integer: [sender intValue]];
1175 }
1176
1177 #pragma mark -
1178 #pragma mark color
1179 - (IBAction)enableThreshold:(id)sender
1180 {
1181     BOOL b_state = [o_threshold_ckb state];
1182
1183     [self setVideoFilter: "colorthres" on: b_state];
1184     [o_threshold_color_fld setEnabled: b_state];
1185     [o_threshold_color_lbl setEnabled: b_state];
1186     [o_threshold_saturation_sld setEnabled: b_state];
1187     [o_threshold_saturation_lbl setEnabled: b_state];
1188     [o_threshold_similarity_sld setEnabled: b_state];
1189     [o_threshold_similarity_lbl setEnabled: b_state];
1190 }
1191
1192 - (IBAction)thresholdModifierChanged:(id)sender
1193 {
1194     if (sender == o_threshold_color_fld)
1195         [self setVideoFilterProperty: "colorthres-color" forFilter: "colorthres" integer: [o_threshold_color_fld intValue]];
1196     else if (sender == o_threshold_saturation_sld) {
1197         [self setVideoFilterProperty: "colorthres-saturationthres" forFilter: "colorthres" integer: [o_threshold_saturation_sld intValue]];
1198         [o_threshold_saturation_sld setToolTip: [NSString stringWithFormat:@"%i", [o_threshold_saturation_sld intValue]]];
1199     } else {
1200         [self setVideoFilterProperty: "colorthres-similaritythres" forFilter: "colorthres" integer: [o_threshold_similarity_sld intValue]];
1201         [o_threshold_similarity_sld setToolTip: [NSString stringWithFormat:@"%i", [o_threshold_similarity_sld intValue]]];
1202     }
1203 }
1204
1205 - (IBAction)enableSepia:(id)sender
1206 {
1207     BOOL b_state = [o_sepia_ckb state];
1208
1209     [self setVideoFilter: "sepia" on: b_state];
1210     [o_sepia_fld setEnabled: b_state];
1211     [o_sepia_stp setEnabled: b_state];
1212     [o_sepia_lbl setEnabled: b_state];
1213 }
1214
1215 - (IBAction)sepiaModifierChanged:(id)sender
1216 {
1217     [self setVideoFilterProperty: "sepia-intensity" forFilter: "sepia" integer: [o_sepia_fld intValue]];
1218 }
1219
1220 - (IBAction)enableNoise:(id)sender
1221 {
1222     [self setVideoFilter: "noise" on: [o_noise_ckb state]];
1223 }
1224
1225 - (IBAction)enableGradient:(id)sender
1226 {
1227     BOOL b_state = [o_gradient_ckb state];
1228
1229     [self setVideoFilter: "gradient" on: b_state];
1230     [o_gradient_mode_pop setEnabled: b_state];
1231     [o_gradient_mode_lbl setEnabled: b_state];
1232     [o_gradient_color_ckb setEnabled: b_state];
1233     [o_gradient_cartoon_ckb setEnabled: b_state];
1234 }
1235
1236 - (IBAction)gradientModifierChanged:(id)sender
1237 {
1238     if (sender == o_gradient_mode_pop) {
1239         if ([[o_gradient_mode_pop selectedItem] tag] == 3)
1240             [self setVideoFilterProperty: "gradient-mode" forFilter: "gradient" string: "hough"];
1241         else if ([[o_gradient_mode_pop selectedItem] tag] == 2)
1242             [self setVideoFilterProperty: "gradient-mode" forFilter: "gradient" string: "edge"];
1243         else
1244             [self setVideoFilterProperty: "gradient-mode" forFilter: "gradient" string: "gradient"];
1245     } else if (sender == o_gradient_color_ckb)
1246         [self setVideoFilterProperty: "gradient-type" forFilter: "gradient" integer: [o_gradient_color_ckb state]];
1247     else
1248         [self setVideoFilterProperty: "gradient-cartoon" forFilter: "gradient" boolean: [o_gradient_cartoon_ckb state]];
1249 }
1250
1251 - (IBAction)enableExtract:(id)sender
1252 {
1253     BOOL b_state = [o_extract_ckb state];
1254     [self setVideoFilter: "extract" on: b_state];
1255     [o_extract_fld setEnabled: b_state];
1256     [o_extract_lbl setEnabled: b_state];
1257 }
1258
1259 - (IBAction)extractModifierChanged:(id)sender
1260 {
1261     [self setVideoFilterProperty: "extract-component" forFilter: "extract" integer: [o_extract_fld intValue]];
1262 }
1263
1264 - (IBAction)enableInvert:(id)sender
1265 {
1266     [self setVideoFilter: "invert" on: [o_invert_ckb state]];
1267 }
1268
1269 - (IBAction)enablePosterize:(id)sender
1270 {
1271     BOOL b_state = [o_posterize_ckb state];
1272
1273     [self setVideoFilter: "posterize" on: b_state];
1274     [o_posterize_fld setEnabled: b_state];
1275     [o_posterize_stp setEnabled: b_state];
1276     [o_posterize_lbl setEnabled: b_state];
1277 }
1278
1279 - (IBAction)posterizeModifierChanged:(id)sender
1280 {
1281     [self setVideoFilterProperty: "posterize-level" forFilter: "posterize" integer: [o_posterize_fld intValue]];
1282 }
1283
1284 - (IBAction)enableBlur:(id)sender
1285 {
1286     BOOL b_state = [o_blur_ckb state];
1287
1288     [self setVideoFilter: "motionblur" on: b_state];
1289     [o_blur_sld setEnabled: b_state];
1290     [o_blur_lbl setEnabled: b_state];
1291 }
1292
1293 - (IBAction)blurModifierChanged:(id)sender
1294 {
1295     [self setVideoFilterProperty: "blur-factor" forFilter: "motionblur" integer: [sender intValue]];
1296     [sender setToolTip: [NSString stringWithFormat:@"%i", [sender intValue]]];
1297 }
1298
1299 - (IBAction)enableMotionDetect:(id)sender
1300 {
1301     [self setVideoFilter: "motiondetect" on: [o_motiondetect_ckb state]];
1302 }
1303
1304 - (IBAction)enableWaterEffect:(id)sender
1305 {
1306     [self setVideoFilter: "ripple" on: [o_watereffect_ckb state]];
1307 }
1308
1309 - (IBAction)enableWaves:(id)sender
1310 {
1311     [self setVideoFilter: "wave" on: [o_waves_ckb state]];
1312 }
1313
1314 - (IBAction)enablePsychedelic:(id)sender
1315 {
1316     [self setVideoFilter: "psychedelic" on: [o_psychedelic_ckb state]];
1317 }
1318
1319 #pragma mark -
1320 #pragma mark Miscellaneous
1321 - (IBAction)enableAddText:(id)sender
1322 {
1323     BOOL b_state = [o_addtext_ckb state];
1324
1325     [o_addtext_pos_pop setEnabled: b_state];
1326     [o_addtext_pos_lbl setEnabled: b_state];
1327     [o_addtext_text_lbl setEnabled: b_state];
1328     [o_addtext_text_fld setEnabled: b_state];
1329     [self setVideoFilter: "marq" on: b_state];
1330     [self setVideoFilterProperty: "marq-marquee" forFilter: "marq" string: (char *)[[o_addtext_text_fld stringValue] UTF8String]];
1331     [self setVideoFilterProperty: "marq-position" forFilter: "marq" integer: [[o_addtext_pos_pop selectedItem] tag]];
1332 }
1333
1334 - (IBAction)addTextModifierChanged:(id)sender
1335 {
1336     if (sender == o_addtext_text_fld)
1337         [self setVideoFilterProperty: "marq-marquee" forFilter: "marq" string: (char *)[[o_addtext_text_fld stringValue] UTF8String]];
1338     else
1339         [self setVideoFilterProperty: "marq-position" forFilter: "marq" integer: [[o_addtext_pos_pop selectedItem] tag]];
1340 }
1341
1342 - (IBAction)enableAddLogo:(id)sender
1343 {
1344     BOOL b_state = [o_addlogo_ckb state];
1345
1346     [o_addlogo_pos_pop setEnabled: b_state];
1347     [o_addlogo_pos_lbl setEnabled: b_state];
1348     [o_addlogo_logo_fld setEnabled: b_state];
1349     [o_addlogo_logo_lbl setEnabled: b_state];
1350     [o_addlogo_transparency_sld setEnabled: b_state];
1351     [o_addlogo_transparency_lbl setEnabled: b_state];
1352     [self setVideoFilter: "logo" on: b_state];
1353 }
1354
1355 - (IBAction)addLogoModifierChanged:(id)sender
1356 {
1357     if (sender == o_addlogo_logo_fld)
1358         [self setVideoFilterProperty: "logo-file" forFilter: "logo" string: (char *)[[o_addlogo_logo_fld stringValue] UTF8String]];
1359     else if (sender == o_addlogo_pos_pop)
1360         [self setVideoFilterProperty: "logo-position" forFilter: "logo" integer: [[o_addlogo_pos_pop selectedItem] tag]];
1361     else {
1362         [self setVideoFilterProperty: "logo-opacity" forFilter: "logo" integer: [o_addlogo_transparency_sld intValue]];
1363         [o_addlogo_transparency_sld setToolTip: [NSString stringWithFormat:@"%i", [o_addlogo_transparency_sld intValue]]];
1364     }
1365 }
1366
1367 - (IBAction)enableAnaglyph:(id)sender
1368 {
1369     [self setVideoFilter: "anaglyph" on: [o_anaglyph_ckb state]];
1370 }
1371
1372 @end