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