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