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