macosx: save default video profile as custom when quiting
[vlc.git] / modules / gui / macosx / VLCVideoEffectsWindowController.m
blob2ab0316cf990e62253615ffcb447b3b63805c55b
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  *****************************************************************************/
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 #import "VLCHexNumberFormatter.h"
32 #define getWidgetBoolValue(w)   ((vlc_value_t){ .b_bool = [w state] })
33 #define getWidgetIntValue(w)    ((vlc_value_t){ .i_int = [w intValue] })
34 #define getWidgetFloatValue(w)  ((vlc_value_t){ .f_float = [w floatValue] })
35 #define getWidgetStringValue(w) ((vlc_value_t){ .psz_string = (char *)[[w stringValue] UTF8String] })
37 @interface VLCVideoEffectsWindowController()
39     NSInteger i_old_profile_index;
41 @end
43 #pragma mark -
44 #pragma mark Initialization
46 @implementation VLCVideoEffectsWindowController
48 + (void)initialize
50     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",
51                                  [NSArray arrayWithObject:_NS("Default")], @"VideoEffectProfileNames", nil];
52     [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
55 - (id)init
57     self = [super initWithWindowNibName:@"VideoEffects"];
58     if (self) {
59         i_old_profile_index = -1;
61         self.popupPanel = [[VLCPopupPanelController alloc] init];
62         self.textfieldPanel = [[VLCTextfieldPanelController alloc] init];
63     }
65     if ([[NSUserDefaults standardUserDefaults] boolForKey:@"VideoEffectApplyProfileOnStartup"]) {
66         [self resetValues];
67         [self loadProfile];
68     }
70     return self;
73 - (void)loadProfile
75     intf_thread_t *p_intf = getIntf();
76     playlist_t *p_playlist = pl_Get(p_intf);
77     VLCCoreInteraction *vci_si = [VLCCoreInteraction sharedInstance];
78     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
79     NSUInteger profile = [defaults integerForKey:@"VideoEffectSelectedProfile"];
81     /* fetch preset */
82     NSArray *items = [[[defaults objectForKey:@"VideoEffectProfiles"] objectAtIndex:profile] componentsSeparatedByString:@";"];
84     // version 1 of profile string has 32 entries
85     if ([items count] < 32) {
86         msg_Err(p_intf, "Error in parsing profile string");
87         return;
88     }
90     /* filter handling */
91     NSString *tempString = B64DecNSStr([items firstObject]);
92     NSArray<NSValue *> *vouts = getVouts();
94     /* enable the new filters */
95     var_SetString(p_playlist, "video-filter", [tempString UTF8String]);
96     if (vouts)
97         for (NSValue *ptr in vouts) {
98             vout_thread_t *p_vout = [ptr pointerValue];
99             var_SetString(p_vout, "video-filter", [tempString UTF8String]);
100         }
102     tempString = B64DecNSStr([items objectAtIndex:1]);
103     /* enable another round of new filters */
104     var_SetString(p_playlist, "sub-source", [tempString UTF8String]);
105     if (vouts)
106         for (NSValue *ptr in vouts) {
107             vout_thread_t *p_vout = [ptr pointerValue];
108             var_SetString(p_vout, "sub-source", [tempString UTF8String]);
109             vlc_object_release(p_vout);
110         }
112     tempString = B64DecNSStr([items objectAtIndex:2]);
113     /* enable another round of new filters */
114     char *psz_current_splitter = var_GetString(p_playlist, "video-splitter");
115     bool b_filter_changed = ![tempString isEqualToString:toNSStr(psz_current_splitter)];
116     free(psz_current_splitter);
118     if (b_filter_changed)
119         var_SetString(p_playlist, "video-splitter", [tempString UTF8String]);
121     /* try to set filter values on-the-fly and store them appropriately */
122     // index 3 is deprecated
123     [vci_si setVideoFilterProperty: "contrast" forFilter: "adjust" withValue: getWidgetFloatValue([items objectAtIndex:4])];
124     [vci_si setVideoFilterProperty: "brightness" forFilter: "adjust" withValue: getWidgetFloatValue([items objectAtIndex:5])];
125     [vci_si setVideoFilterProperty: "saturation" forFilter: "adjust" withValue: getWidgetFloatValue([items objectAtIndex:6])];
126     [vci_si setVideoFilterProperty: "gamma" forFilter: "adjust" withValue: getWidgetFloatValue([items objectAtIndex:7])];
127     [vci_si setVideoFilterProperty: "sharpen-sigma" forFilter: "sharpen" withValue: getWidgetFloatValue([items objectAtIndex:8])];
128     [vci_si setVideoFilterProperty: "gradfun-radius" forFilter: "gradfun" withValue: getWidgetIntValue([items objectAtIndex:9])];
129     [vci_si setVideoFilterProperty: "grain-variance" forFilter: "grain" withValue: getWidgetFloatValue([items objectAtIndex:10])];
130     [vci_si setVideoFilterProperty: "transform-type" forFilter: "transform" withValue: (vlc_value_t){ .psz_string = (char *)[B64DecNSStr([items objectAtIndex:11]) UTF8String] }];
131     [vci_si setVideoFilterProperty: "puzzle-rows" forFilter: "puzzle" withValue: getWidgetIntValue([items objectAtIndex:12])];
132     [vci_si setVideoFilterProperty: "puzzle-cols" forFilter: "puzzle" withValue: getWidgetIntValue([items objectAtIndex:13])];
133     [vci_si setVideoFilterProperty: "colorthres-color" forFilter: "colorthres" withValue: getWidgetIntValue([items objectAtIndex:14])];
134     [vci_si setVideoFilterProperty: "colorthres-saturationthres" forFilter: "colorthres" withValue: getWidgetIntValue([items objectAtIndex:15])];
135     [vci_si setVideoFilterProperty: "colorthres-similaritythres" forFilter: "colorthres" withValue: getWidgetIntValue([items objectAtIndex:16])];
136     [vci_si setVideoFilterProperty: "sepia-intensity" forFilter: "sepia" withValue: getWidgetIntValue([items objectAtIndex:17])];
137     [vci_si setVideoFilterProperty: "gradient-mode" forFilter: "gradient" withValue: (vlc_value_t){ .psz_string = (char *)[B64DecNSStr([items objectAtIndex:18]) UTF8String] }];
138     [vci_si setVideoFilterProperty: "gradient-cartoon" forFilter: "gradient" withValue: (vlc_value_t){ .b_bool = [[items objectAtIndex:19] intValue] }];
139     [vci_si setVideoFilterProperty: "gradient-type" forFilter: "gradient" withValue: getWidgetIntValue([items objectAtIndex:20])];
140     [vci_si setVideoFilterProperty: "extract-component" forFilter: "extract" withValue: getWidgetIntValue([items objectAtIndex:21])];
141     [vci_si setVideoFilterProperty: "posterize-level" forFilter: "posterize" withValue: getWidgetIntValue([items objectAtIndex:22])];
142     [vci_si setVideoFilterProperty: "blur-factor" forFilter: "motionblur" withValue: getWidgetIntValue([items objectAtIndex:23])];
143     [vci_si setVideoFilterProperty: "marq-marquee" forFilter: "marq" withValue: (vlc_value_t){ .psz_string = (char *)[B64DecNSStr([items objectAtIndex:24]) UTF8String] }];
144     [vci_si setVideoFilterProperty: "marq-position" forFilter: "marq" withValue: getWidgetIntValue([items objectAtIndex:25])];
145     [vci_si setVideoFilterProperty: "logo-file" forFilter: "logo" withValue: (vlc_value_t){ .psz_string = (char *)[B64DecNSStr([items objectAtIndex:26]) UTF8String] }];
146     [vci_si setVideoFilterProperty: "logo-position" forFilter: "logo" withValue: getWidgetIntValue([items objectAtIndex:27])];
147     [vci_si setVideoFilterProperty: "logo-opacity" forFilter: "logo" withValue: getWidgetIntValue([items objectAtIndex:28])];
148     [vci_si setVideoFilterProperty: "clone-count" forFilter: "clone" withValue: getWidgetIntValue([items objectAtIndex:29])];
149     [vci_si setVideoFilterProperty: "wall-rows" forFilter: "wall" withValue: getWidgetIntValue([items objectAtIndex:30])];
150     [vci_si setVideoFilterProperty: "wall-cols" forFilter: "wall" withValue: getWidgetIntValue([items objectAtIndex:31])];
152     if ([items count] >= 33) { // version >=2 of profile string
153         [vci_si setVideoFilterProperty: "brightness-threshold" forFilter: "adjust" withValue: (vlc_value_t){ .b_bool = [[items objectAtIndex:32] intValue] }];
154     }
156     vlc_value_t hueValue;
157     if ([items count] >= 34) { // version >=3 of profile string
158         hueValue.f_float = [[items objectAtIndex:33] floatValue];
159     } else {
160         hueValue.f_float = [[items objectAtIndex:3] intValue]; // deprecated since 3.0.0
161         // convert to new scale ([0,360] --> [-180,180])
162         hueValue.f_float -= 180;
163     }
164     [vci_si setVideoFilterProperty: "hue" forFilter: "adjust" withValue: hueValue];
166     [defaults setInteger:profile forKey:@"VideoEffectSelectedProfile"];
167     [defaults synchronize];
170 - (void)windowDidLoad
172     [self.window setTitle: _NS("Video Effects")];
173     [self.window setExcludedFromWindowsMenu:YES];
174     [self.window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
176     [[_tabView tabViewItemAtIndex:[_tabView indexOfTabViewItemWithIdentifier:@"basic"]] setLabel:_NS("Basic")];
177     [[_tabView tabViewItemAtIndex:[_tabView indexOfTabViewItemWithIdentifier:@"crop"]] setLabel:_NS("Crop")];
178     [[_tabView tabViewItemAtIndex:[_tabView indexOfTabViewItemWithIdentifier:@"geometry"]] setLabel:_NS("Geometry")];
179     [[_tabView tabViewItemAtIndex:[_tabView indexOfTabViewItemWithIdentifier:@"color"]] setLabel:_NS("Color")];
180     [[_tabView tabViewItemAtIndex:[_tabView indexOfTabViewItemWithIdentifier:@"misc"]] setLabel:_NS("Miscellaneous")];
182     [_applyProfileCheckbox setState:[[NSUserDefaults standardUserDefaults] boolForKey:@"VideoEffectApplyProfileOnStartup"]];
184     [self resetProfileSelector];
186     [_adjustCheckbox setTitle:_NS("Image Adjust")];
187     [_adjustHueLabel setStringValue:_NS("Hue")];
188     [_adjustContrastLabel setStringValue:_NS("Contrast")];
189     [_adjustBrightnessLabel setStringValue:_NS("Brightness")];
190     [_adjustBrightnessCheckbox setTitle:_NS("Brightness Threshold")];
191     [_adjustSaturationLabel setStringValue:_NS("Saturation")];
192     [_adjustGammaLabel setStringValue:_NS("Gamma")];
193     [_adjustResetButton setTitle: _NS("Reset")];
194     [_sharpenCheckbox setTitle:_NS("Sharpen")];
195     [_sharpenLabel setStringValue:_NS("Sigma")];
196     [_bandingCheckbox setTitle:_NS("Banding removal")];
197     [_bandingLabel setStringValue:_NS("Radius")];
198     [_grainCheckbox setTitle:_NS("Film Grain")];
199     [_grainLabel setStringValue:_NS("Variance")];
200     [_cropTopLabel setStringValue:_NS("Top")];
201     [_cropLeftLabel setStringValue:_NS("Left")];
202     [_cropRightLabel setStringValue:_NS("Right")];
203     [_cropBottomLabel setStringValue:_NS("Bottom")];
204     [_cropSyncTopBottomCheckbox setTitle:_NS("Synchronize top and bottom")];
205     [_cropSyncLeftRightCheckbox setTitle:_NS("Synchronize left and right")];
207     [_transformCheckbox setTitle:_NS("Transform")];
208     [_transformPopup removeAllItems];
209     [_transformPopup addItemWithTitle: _NS("Rotate by 90 degrees")];
210     [[_transformPopup lastItem] setRepresentedObject: @"90"];
211     [[_transformPopup lastItem] setTag: 90];
212     [_transformPopup addItemWithTitle: _NS("Rotate by 180 degrees")];
213     [[_transformPopup lastItem] setRepresentedObject: @"180"];
214     [[_transformPopup lastItem] setTag: 180];
215     [_transformPopup addItemWithTitle: _NS("Rotate by 270 degrees")];
216     [[_transformPopup lastItem] setRepresentedObject: @"270"];
217     [[_transformPopup lastItem] setTag: 270];
218     [_transformPopup addItemWithTitle: _NS("Flip horizontally")];
219     [[_transformPopup lastItem] setRepresentedObject: @"hflip"];
220     [[_transformPopup lastItem] setTag: 1];
221     [_transformPopup addItemWithTitle: _NS("Flip vertically")];
222     [[_transformPopup lastItem] setRepresentedObject: @"vflip"];
223     [[_transformPopup lastItem] setTag: 2];
224     [_zoomCheckbox setTitle:_NS("Magnification/Zoom")];
225     [_puzzleCheckbox setTitle:_NS("Puzzle game")];
226     [_puzzleRowsLabel setStringValue:_NS("Rows")];
227     [_puzzleColumnsLabel setStringValue:_NS("Columns")];
228     [_cloneCheckbox setTitle:_NS("Clone")];
229     [_cloneNumberLabel setStringValue:_NS("Number of clones")];
230     [_wallCheckbox setTitle:_NS("Wall")];
231     [_wallNumbersOfRowsLabel setStringValue:_NS("Rows")];
232     [_wallNumberOfColumnsLabel setStringValue:_NS("Columns")];
234     [_thresholdCheckbox setTitle:_NS("Color threshold")];
235     [_thresholdColorLabel setStringValue:_NS("Color")];
236     [_thresholdColorTextField setFormatter:[[VLCHexNumberFormatter alloc] init]];
237     [_thresholdSaturationLabel setStringValue:_NS("Saturation")];
238     [_thresholdSimilarityLabel setStringValue:_NS("Similarity")];
239     [_sepiaCheckbox setTitle:_NS("Sepia")];
240     [_sepiaLabel setStringValue:_NS("Intensity")];
241     [_noiseCheckbox setTitle:_NS("Noise")];
242     [_gradientCheckbox setTitle:_NS("Gradient")];
243     [_gradientModeLabel setStringValue:_NS("Mode")];
244     [_gradientModePopup removeAllItems];
245     [_gradientModePopup addItemWithTitle: _NS("Gradient")];
246     [[_gradientModePopup lastItem] setRepresentedObject: @"gradient"];
247     [[_gradientModePopup lastItem] setTag: 1];
248     [_gradientModePopup addItemWithTitle: _NS("Edge")];
249     [[_gradientModePopup lastItem] setRepresentedObject: @"edge"];
250     [[_gradientModePopup lastItem] setTag: 2];
251     [_gradientModePopup addItemWithTitle: _NS("Hough")];
252     [[_gradientModePopup lastItem] setRepresentedObject: @"hough"];
253     [[_gradientModePopup lastItem] setTag: 3];
254     [_gradientColorCheckbox setTitle:_NS("Color")];
255     [_gradientCartoonCheckbox setTitle:_NS("Cartoon")];
256     [_extractCheckbox setTitle:_NS("Color extraction")];
257     [_extractLabel setStringValue:_NS("Color")];
258     [_extractTextField setFormatter:[[VLCHexNumberFormatter alloc] init]];
259     [_invertCheckbox setTitle:_NS("Invert colors")];
260     [_posterizeCheckbox setTitle:_NS("Posterize")];
261     [_posterizeLabel setStringValue:_NS("Posterize level")];
262     [_blurCheckbox setTitle:_NS("Motion blur")];
263     [_blurLabel setStringValue:_NS("Factor")];
264     [_motiondetectCheckbox setTitle:_NS("Motion Detect")];
265     [_watereffectCheckbox setTitle:_NS("Water effect")];
266     [_wavesCheckbox setTitle:_NS("Waves")];
267     [_psychedelicCheckbox setTitle:_NS("Psychedelic")];
268     [_anaglyphCheckbox setTitle:_NS("Anaglyph")];
269     [_addTextCheckbox setTitle:_NS("Add text")];
270     [_addTextTextLabel setStringValue:_NS("Text")];
271     [_addTextPositionLabel setStringValue:_NS("Position")];
272     [_addTextPositionPopup removeAllItems];
273     [_addTextPositionPopup addItemWithTitle: _NS("Center")];
274     [[_addTextPositionPopup lastItem] setTag: 0];
275     [_addTextPositionPopup addItemWithTitle: _NS("Left")];
276     [[_addTextPositionPopup lastItem] setTag: 1];
277     [_addTextPositionPopup addItemWithTitle: _NS("Right")];
278     [[_addTextPositionPopup lastItem] setTag: 2];
279     [_addTextPositionPopup addItemWithTitle: _NS("Top")];
280     [[_addTextPositionPopup lastItem] setTag: 4];
281     [_addTextPositionPopup addItemWithTitle: _NS("Bottom")];
282     [[_addTextPositionPopup lastItem] setTag: 8];
283     [_addTextPositionPopup addItemWithTitle: _NS("Top-Left")];
284     [[_addTextPositionPopup lastItem] setTag: 5];
285     [_addTextPositionPopup addItemWithTitle: _NS("Top-Right")];
286     [[_addTextPositionPopup lastItem] setTag: 6];
287     [_addTextPositionPopup addItemWithTitle: _NS("Bottom-Left")];
288     [[_addTextPositionPopup lastItem] setTag: 9];
289     [_addTextPositionPopup addItemWithTitle: _NS("Bottom-Right")];
290     [[_addTextPositionPopup lastItem] setTag: 10];
291     [_addLogoCheckbox setTitle:_NS("Add logo")];
292     [_addLogoLogoLabel setStringValue:_NS("Logo")];
293     [_addLogoPositionLabel setStringValue:_NS("Position")];
294     [_addLogoPositionPopup removeAllItems];
295     [_addLogoPositionPopup addItemWithTitle: _NS("Center")];
296     [[_addLogoPositionPopup lastItem] setTag: 0];
297     [_addLogoPositionPopup addItemWithTitle: _NS("Left")];
298     [[_addLogoPositionPopup lastItem] setTag: 1];
299     [_addLogoPositionPopup addItemWithTitle: _NS("Right")];
300     [[_addLogoPositionPopup lastItem] setTag: 2];
301     [_addLogoPositionPopup addItemWithTitle: _NS("Top")];
302     [[_addLogoPositionPopup lastItem] setTag: 4];
303     [_addLogoPositionPopup addItemWithTitle: _NS("Bottom")];
304     [[_addLogoPositionPopup lastItem] setTag: 8];
305     [_addLogoPositionPopup addItemWithTitle: _NS("Top-Left")];
306     [[_addLogoPositionPopup lastItem] setTag: 5];
307     [_addLogoPositionPopup addItemWithTitle: _NS("Top-Right")];
308     [[_addLogoPositionPopup lastItem] setTag: 6];
309     [_addLogoPositionPopup addItemWithTitle: _NS("Bottom-Left")];
310     [[_addLogoPositionPopup lastItem] setTag: 9];
311     [_addLogoPositionPopup addItemWithTitle: _NS("Bottom-Right")];
312     [[_addLogoPositionPopup lastItem] setTag: 10];
313     [_addLogoTransparencyLabel setStringValue:_NS("Transparency")];
315     [_tabView selectFirstTabViewItem:self];
317     [[NSNotificationCenter defaultCenter] addObserver:self
318                                              selector:@selector(inputChangedEvent:)
319                                                  name:VLCInputChangedNotification
320                                                object:nil];
322     [self resetValues];
325 - (void)dealloc
327     [[NSNotificationCenter defaultCenter] removeObserver:self];
330 - (void)updateCocoaWindowLevel:(NSInteger)i_level
332     if (self.isWindowLoaded && [self.window isVisible] && [self.window level] != i_level)
333         [self.window setLevel: i_level];
336 #pragma mark -
337 #pragma mark internal functions
339 -(void)inputChangedEvent:(NSNotification *)o_notification
341     // reset crop values when input changed
342     [self setCropBottomValue:0];
343     [self setCropTopValue:0];
344     [self setCropLeftValue:0];
345     [self setCropRightValue:0];
348 - (void)resetProfileSelector
350     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
351     [_profilePopup removeAllItems];
353     NSArray *profileNames = [defaults objectForKey:@"VideoEffectProfileNames"];
354     [_profilePopup addItemsWithTitles:profileNames];
356     [[_profilePopup menu] addItem:[NSMenuItem separatorItem]];
357     [_profilePopup addItemWithTitle:_NS("Duplicate current profile...")];
358     [[_profilePopup lastItem] setTarget: self];
359     [[_profilePopup lastItem] setAction: @selector(addProfile:)];
361     if ([profileNames count] > 1) {
362         [_profilePopup addItemWithTitle:_NS("Organize profiles...")];
363         [[_profilePopup lastItem] setTarget: self];
364         [[_profilePopup lastItem] setAction: @selector(removeProfile:)];
365     }
367     [_profilePopup selectItemAtIndex:[defaults integerForKey:@"VideoEffectSelectedProfile"]];
368     if (i_old_profile_index || [defaults integerForKey:@"VideoEffectSelectedProfile"])
369         [self profileSelectorAction:self];
372 - (void)setWidgetValue: (id)widget forOption: (char *)psz_option enabled: (bool)b_state
374     intf_thread_t *p_intf = getIntf();
375     playlist_t *p_playlist = pl_Get(p_intf);
377     vlc_value_t val;
378     int i_type = config_GetType(p_intf, psz_option) & VLC_VAR_CLASS;
379     switch (i_type)
380     {
381     case VLC_VAR_BOOL:
382     case VLC_VAR_INTEGER:
383     case VLC_VAR_FLOAT:
384     case VLC_VAR_STRING:
385         break;
386     default:
387         msg_Err(p_intf, "%s variable is of an unsupported type (%d)", psz_option, i_type);
388         return;
389     }
390     if (var_Create(p_playlist, psz_option, i_type | VLC_VAR_DOINHERIT) ||
391         var_GetChecked(p_playlist, psz_option, i_type, &val))
392         return;
394     if (i_type == VLC_VAR_BOOL || i_type == VLC_VAR_INTEGER)
395     {
396         if ([widget isKindOfClass: [NSSlider class]])
397         {
398             [widget setIntValue: val.i_int];
399             [widget setToolTip: [NSString stringWithFormat:@"%lli", val.i_int]];
400         }
401         else if ([widget isKindOfClass: [NSButton class]])
402             [widget setState: val.i_int ? NSOnState : NSOffState];
403         else if ([widget isKindOfClass: [NSTextField class]])
404             [widget setIntValue: val.i_int];
405         else if ([widget isKindOfClass: [NSStepper class]])
406             [widget setIntValue: val.i_int];
407         else if ([widget isKindOfClass: [NSPopUpButton class]])
408             [widget selectItemWithTag: val.i_int];
409     }
410     else if (i_type == VLC_VAR_FLOAT)
411     {
412         if ([widget isKindOfClass: [NSSlider class]])
413         {
414             [widget setFloatValue: val.f_float];
415             [widget setToolTip: [NSString stringWithFormat:@"%0.3f", val.f_float]];
416         }
417     }
418     else if (i_type == VLC_VAR_STRING)
419     {
420         if ([widget isKindOfClass: [NSPopUpButton class]])
421         {
422             for (NSMenuItem *item in [widget itemArray])
423                 if ([item representedObject] &&
424                     !strcmp([[item representedObject] UTF8String], val.psz_string))
425                 {
426                     [widget selectItemWithTitle: [item title]];
427                     break;
428                 }
429         }
430         else if ([widget isKindOfClass: [NSTextField class]])
431             [widget setStringValue: toNSStr(val.psz_string)];
432         free(val.psz_string);
433     }
435     [widget setEnabled: b_state];
438 - (void)resetValues
440     intf_thread_t *p_intf = getIntf();
441     playlist_t *p_playlist = pl_Get(p_intf);
442     NSString *tmpString;
443     char *tmpChar;
444     BOOL b_state;
446     /* do we have any filter enabled? if yes, show it. */
447     char * psz_vfilters;
448     psz_vfilters = var_InheritString(p_playlist, "video-filter");
449     if (psz_vfilters) {
450         [_adjustCheckbox setState: (NSInteger)strstr(psz_vfilters, "adjust")];
451         [_sharpenCheckbox setState: (NSInteger)strstr(psz_vfilters, "sharpen")];
452         [_bandingCheckbox setState: (NSInteger)strstr(psz_vfilters, "gradfun")];
453         [_grainCheckbox setState: (NSInteger)strstr(psz_vfilters, "grain")];
454         [_transformCheckbox setState: (NSInteger)strstr(psz_vfilters, "transform")];
455         [_zoomCheckbox setState: (NSInteger)strstr(psz_vfilters, "magnify")];
456         [_puzzleCheckbox setState: (NSInteger)strstr(psz_vfilters, "puzzle")];
457         [_thresholdCheckbox setState: (NSInteger)strstr(psz_vfilters, "colorthres")];
458         [_sepiaCheckbox setState: (NSInteger)strstr(psz_vfilters, "sepia")];
459         [_noiseCheckbox setState: (NSInteger)strstr(psz_vfilters, "noise")];
460         [_gradientCheckbox setState: (NSInteger)strstr(psz_vfilters, "gradient")];
461         [_extractCheckbox setState: (NSInteger)strstr(psz_vfilters, "extract")];
462         [_invertCheckbox setState: (NSInteger)strstr(psz_vfilters, "invert")];
463         [_posterizeCheckbox setState: (NSInteger)strstr(psz_vfilters, "posterize")];
464         [_blurCheckbox setState: (NSInteger)strstr(psz_vfilters, "motionblur")];
465         [_motiondetectCheckbox setState: (NSInteger)strstr(psz_vfilters, "motiondetect")];
466         [_watereffectCheckbox setState: (NSInteger)strstr(psz_vfilters, "ripple")];
467         [_wavesCheckbox setState: (NSInteger)strstr(psz_vfilters, "wave")];
468         [_psychedelicCheckbox setState: (NSInteger)strstr(psz_vfilters, "psychedelic")];
469         [_anaglyphCheckbox setState: (NSInteger)strstr(psz_vfilters, "anaglyph")];
470         free(psz_vfilters);
471     } else {
472         [_adjustCheckbox setState: NSOffState];
473         [_sharpenCheckbox setState: NSOffState];
474         [_bandingCheckbox setState: NSOffState];
475         [_grainCheckbox setState: NSOffState];
476         [_transformCheckbox setState: NSOffState];
477         [_zoomCheckbox setState: NSOffState];
478         [_puzzleCheckbox setState: NSOffState];
479         [_thresholdCheckbox setState: NSOffState];
480         [_sepiaCheckbox setState: NSOffState];
481         [_noiseCheckbox setState: NSOffState];
482         [_gradientCheckbox setState: NSOffState];
483         [_extractCheckbox setState: NSOffState];
484         [_invertCheckbox setState: NSOffState];
485         [_posterizeCheckbox setState: NSOffState];
486         [_blurCheckbox setState: NSOffState];
487         [_motiondetectCheckbox setState: NSOffState];
488         [_watereffectCheckbox setState: NSOffState];
489         [_wavesCheckbox setState: NSOffState];
490         [_psychedelicCheckbox setState: NSOffState];
491         [_anaglyphCheckbox setState: NSOffState];
492     }
494     psz_vfilters = var_InheritString(p_playlist, "sub-source");
495     if (psz_vfilters) {
496         [_addTextCheckbox setState: (NSInteger)strstr(psz_vfilters, "marq")];
497         [_addLogoCheckbox setState: (NSInteger)strstr(psz_vfilters, "logo")];
498         free(psz_vfilters);
499     } else {
500         [_addTextCheckbox setState: NSOffState];
501         [_addLogoCheckbox setState: NSOffState];
502     }
504     psz_vfilters = var_InheritString(p_playlist, "video-splitter");
505     if (psz_vfilters) {
506         [_cloneCheckbox setState: (NSInteger)strstr(psz_vfilters, "clone")];
507         [_wallCheckbox setState: (NSInteger)strstr(psz_vfilters, "wall")];
508         free(psz_vfilters);
509     } else {
510         [_cloneCheckbox setState: NSOffState];
511         [_wallCheckbox setState: NSOffState];
512     }
514     /* fetch and show the various values */
515     b_state = [_adjustCheckbox state];
516     [self setWidgetValue: _adjustHueSlider forOption: "hue" enabled: b_state];
517     [self setWidgetValue: _adjustContrastSlider forOption: "contrast" enabled: b_state];
518     [self setWidgetValue: _adjustBrightnessSlider forOption: "brightness" enabled: b_state];
519     [self setWidgetValue: _adjustSaturationSlider forOption: "saturation" enabled: b_state];
520     [self setWidgetValue: _adjustBrightnessCheckbox forOption: "brightness-threshold" enabled: b_state];
521     [self setWidgetValue: _adjustGammaSlider forOption: "gamma" enabled: b_state];
522     [_adjustBrightnessLabel setEnabled: b_state];
523     [_adjustContrastLabel setEnabled: b_state];
524     [_adjustGammaLabel setEnabled: b_state];
525     [_adjustHueLabel setEnabled: b_state];
526     [_adjustSaturationLabel setEnabled: b_state];
527     [_adjustResetButton setEnabled: b_state];
529     [self setWidgetValue: _sharpenSlider forOption: "sharpen-sigma" enabled: [_sharpenCheckbox state]];
530     [_sharpenLabel setEnabled: [_sharpenCheckbox state]];
532     [self setWidgetValue: _bandingSlider forOption: "gradfun-radius" enabled: [_bandingCheckbox state]];
533     [_bandingLabel setEnabled: [_bandingCheckbox state]];
535     [self setWidgetValue: _grainSlider forOption: "grain-variance" enabled: [_grainCheckbox state]];
536     [_grainLabel setEnabled: [_grainCheckbox state]];
538     [self setCropLeftValue: 0];
539     [self setCropTopValue: 0];
540     [self setCropRightValue: 0];
541     [self setCropBottomValue: 0];
542     [_cropSyncTopBottomCheckbox setState: NSOffState];
543     [_cropSyncLeftRightCheckbox setState: NSOffState];
545     [self setWidgetValue: _transformPopup forOption: "transform-type" enabled: [_transformCheckbox state]];
547     b_state = [_puzzleCheckbox state];
548     [self setWidgetValue: _puzzleColumnsTextField forOption: "puzzle-cols" enabled: b_state];
549     [self setWidgetValue: _puzzleColumnsStepper forOption: "puzzle-cols" enabled: b_state];
550     [self setWidgetValue: _puzzleRowsTextField forOption: "puzzle-rows" enabled: b_state];
551     [self setWidgetValue: _puzzleRowsStepper forOption: "puzzle-rows" enabled: b_state];
552     [_puzzleRowsLabel setEnabled: b_state];
553     [_puzzleColumnsLabel setEnabled: b_state];
555     b_state = [_cloneCheckbox state];
556     [self setWidgetValue: _cloneNumberTextField forOption: "clone-count" enabled: b_state];
557     [self setWidgetValue: _cloneNumberStepper forOption: "clone-count" enabled: b_state];
558     [_cloneNumberLabel setEnabled: b_state];
560     b_state = [_wallCheckbox state];
561     [self setWidgetValue: _wallNumbersOfRowsTextField forOption: "wall-rows" enabled: b_state];
562     [self setWidgetValue: _wallNumbersOfRowsStepper forOption: "wall-rows" enabled: b_state];
563     [self setWidgetValue: _wallNumberOfColumnsTextField forOption: "wall-cols" enabled: b_state];
564     [self setWidgetValue: _wallNumberOfColumnsStepper forOption: "wall-cols" enabled: b_state];
565     [_wallNumbersOfRowsLabel setEnabled: b_state];
566     [_wallNumberOfColumnsLabel setEnabled: b_state];
568     b_state = [_thresholdCheckbox state];
569     [self setWidgetValue: _thresholdColorTextField forOption: "colorthres-color" enabled: b_state];
570     [self setWidgetValue: _thresholdSaturationSlider forOption: "colorthres-saturationthres" enabled: b_state];
571     [self setWidgetValue: _thresholdSimilaritySlider forOption: "colorthres-similaritythres" enabled: b_state];
572     [_thresholdColorLabel setEnabled: b_state];
573     [_thresholdSaturationLabel setEnabled: b_state];
574     [_thresholdSimilarityLabel setEnabled: b_state];
576     b_state = [_sepiaCheckbox state];
577     [self setWidgetValue: _sepiaTextField forOption: "sepia-intensity" enabled: b_state];
578     [self setWidgetValue: _sepiaStepper forOption: "sepia-intensity" enabled: b_state];
579     [_sepiaLabel setEnabled: b_state];
581     b_state = [_gradientCheckbox state];
582     [self setWidgetValue: _gradientModePopup forOption: "gradient-mode" enabled: b_state];
583     [self setWidgetValue: _gradientCartoonCheckbox forOption: "gradient-cartoon" enabled: b_state];
584     [self setWidgetValue: _gradientColorCheckbox forOption: "gradient-type" enabled: b_state];
585     [_gradientModeLabel setEnabled: b_state];
587     [self setWidgetValue: _extractTextField forOption: "extract-component" enabled: [_extractCheckbox state]];
588     [_extractLabel setEnabled: [_extractCheckbox state]];
590     b_state = [_posterizeCheckbox state];
591     [self setWidgetValue: _posterizeTextField forOption: "posterize-level" enabled: b_state];
592     [self setWidgetValue: _posterizeStepper forOption: "posterize-level" enabled: b_state];
593     [_posterizeLabel setEnabled: b_state];
595     [self setWidgetValue: _blurSlider forOption: "blur-factor" enabled: [_blurCheckbox state]];
596     [_blurLabel setEnabled: [_blurCheckbox state]];
598     b_state = [_addTextCheckbox state];
599     [self setWidgetValue: _addTextTextTextField forOption: "marq-marquee" enabled: b_state];
600     [self setWidgetValue: _addTextPositionPopup forOption: "marq-position" enabled: b_state];
601     [_addTextPositionLabel setEnabled: b_state];
602     [_addTextTextLabel setEnabled: b_state];
604     b_state = [_addLogoCheckbox state];
605     [self setWidgetValue: _addLogoLogoTextField forOption: "logo-file" enabled: b_state];
606     [self setWidgetValue: _addLogoPositionPopup forOption: "logo-position" enabled: b_state];
607     [self setWidgetValue: _addLogoTransparencySlider forOption: "logo-opacity" enabled: b_state];
608     [_addLogoPositionLabel setEnabled: b_state];
609     [_addLogoLogoLabel setEnabled: b_state];
610     [_addLogoTransparencyLabel setEnabled: b_state];
613 - (NSString *)generateProfileString
615     intf_thread_t *p_intf = getIntf();
616     playlist_t *p_playlist = pl_Get(p_intf);
617     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",
618                      B64EncAndFree(var_InheritString(p_playlist, "video-filter")),
619                      B64EncAndFree(var_InheritString(p_playlist, "sub-source")),
620                      B64EncAndFree(var_InheritString(p_playlist, "video-splitter")),
621                      0LL, // former "hue" value, deprecated since 3.0.0
622                      var_InheritFloat(p_playlist, "contrast"),
623                      var_InheritFloat(p_playlist, "brightness"),
624                      var_InheritFloat(p_playlist, "saturation"),
625                      var_InheritFloat(p_playlist, "gamma"),
626                      var_InheritFloat(p_playlist, "sharpen-sigma"),
627                      var_InheritInteger(p_playlist, "gradfun-radius"),
628                      var_InheritFloat(p_playlist, "grain-variance"),
629                      B64EncAndFree(var_InheritString(p_playlist, "transform-type")),
630                      var_InheritInteger(p_playlist, "puzzle-rows"),
631                      var_InheritInteger(p_playlist, "puzzle-cols"),
632                      var_InheritInteger(p_playlist, "colorthres-color"),
633                      var_InheritInteger(p_playlist, "colorthres-saturationthres"),
634                      var_InheritInteger(p_playlist, "colorthres-similaritythres"),
635                      var_InheritInteger(p_playlist, "sepia-intensity"),
636                      B64EncAndFree(var_InheritString(p_playlist, "gradient-mode")),
637                      (int64_t)var_InheritBool(p_playlist, "gradient-cartoon"),
638                      var_InheritInteger(p_playlist, "gradient-type"),
639                      var_InheritInteger(p_playlist, "extract-component"),
640                      var_InheritInteger(p_playlist, "posterize-level"),
641                      var_InheritInteger(p_playlist, "blur-factor"),
642                      B64EncAndFree(var_InheritString(p_playlist, "marq-marquee")),
643                      var_InheritInteger(p_playlist, "marq-position"),
644                      B64EncAndFree(var_InheritString(p_playlist, "logo-file")),
645                      var_InheritInteger(p_playlist, "logo-position"),
646                      var_InheritInteger(p_playlist, "logo-opacity"),
647                      var_InheritInteger(p_playlist, "clone-count"),
648                      var_InheritInteger(p_playlist, "wall-rows"),
649                      var_InheritInteger(p_playlist, "wall-cols"),
650                      // version 2 of profile string:
651                      (int64_t)var_InheritBool(p_playlist, "brightness-threshold"), // index: 32
652                      // version 3 of profile string: (vlc-3.0.0)
653                      var_InheritFloat(p_playlist, "hue") // index: 33
654             ];
657 #pragma mark -
658 #pragma mark generic UI code
660 - (void)saveCurrentProfile
662     if (!i_old_profile_index || i_old_profile_index == -1)
663         return;
665     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
666     /* fetch all the current settings in a uniform string */
667     NSString *newProfile = [self generateProfileString];
669     NSMutableArray *workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"VideoEffectProfiles"]];
670     if (i_old_profile_index >= [workArray count])
671         return;
673     [workArray replaceObjectAtIndex:i_old_profile_index withObject:newProfile];
674     [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfiles"];
675     [defaults synchronize];
678 - (void)saveCurrentProfileAtTerminate
680     if (i_old_profile_index)
681         return [self saveCurrentProfile];
683     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
684     NSString *newProfile = [self generateProfileString];
685     if ([newProfile compare:[[defaults objectForKey:@"VideoEffectProfiles"] firstObject]] == NSOrderedSame)
686         return;
688     NSMutableArray *workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"VideoEffectProfiles"]];
689     [workArray addObject:newProfile];
690     [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfiles"];
692     NSArray<NSString *> *profileNames = [defaults objectForKey:@"VideoEffectProfileNames"];
693     NSString *newProfileName;
695     unsigned int num_custom = 0;
696     do
697         newProfileName = [@"Custom" stringByAppendingString:[NSString stringWithFormat:@"%03i",num_custom++]];
698     while ([profileNames containsObject:newProfileName]);
700     workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"VideoEffectProfileNames"]];
701     [workArray addObject:newProfileName];
702     [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfileNames"];
704     [defaults synchronize];
707 - (IBAction)toggleWindow:(id)sender
709     if ([self.window isKeyWindow])
710         [self.window orderOut:sender];
711     else {
712         [self.window setLevel: [[[VLCMain sharedInstance] voutController] currentStatusWindowLevel]];
713         [self.window makeKeyAndOrderFront:sender];
714     }
717 - (IBAction)profileSelectorAction:(id)sender
719     [self saveCurrentProfile];
720     i_old_profile_index = [_profilePopup indexOfSelectedItem];
721     [[NSUserDefaults standardUserDefaults] setInteger:i_old_profile_index forKey:@"VideoEffectSelectedProfile"];
722     [self loadProfile];
723     [self resetValues];
726 - (void)addProfile:(id)sender
728     /* show panel */
729 #pragma clang diagnostic push
730 #pragma clang diagnostic ignored "-Wpartial-availability"
731 #ifdef MAC_OS_X_VERSION_10_10
732     if (OSX_YOSEMITE_AND_HIGHER) {
733         [[_textfieldPanel window] setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]];
734     }
735 #endif
736 #pragma clang diagnostic pop
737     [_textfieldPanel setTitleString:_NS("Duplicate current profile for a new profile")];
738     [_textfieldPanel setSubTitleString:_NS("Enter a name for the new profile:")];
739     [_textfieldPanel setCancelButtonString:_NS("Cancel")];
740     [_textfieldPanel setOkButtonString:_NS("Save")];
742     // TODO: Change to weak, when dropping 10.7 support
743     __unsafe_unretained typeof(self) _self = self;
744     [_textfieldPanel runModalForWindow:self.window completionHandler:^(NSInteger returnCode, NSString *resultingText) {
746         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
748         if (returnCode != NSOKButton) {
749             [_profilePopup selectItemAtIndex:[defaults integerForKey:@"VideoEffectSelectedProfile"]];
750             return;
751         }
753         NSArray *profileNames = [defaults objectForKey:@"VideoEffectProfileNames"];
755         // duplicate names are not allowed in the popup control
756         if ([resultingText length] == 0 || [profileNames containsObject:resultingText]) {
757             [_profilePopup selectItemAtIndex:[defaults integerForKey:@"VideoEffectSelectedProfile"]];
759             NSAlert *alert = [[NSAlert alloc] init];
760             [alert setAlertStyle:NSCriticalAlertStyle];
761             [alert setMessageText:_NS("Please enter a unique name for the new profile.")];
762             [alert setInformativeText:_NS("Multiple profiles with the same name are not allowed.")];
764             [alert beginSheetModalForWindow:_self.window
765                               modalDelegate:nil
766                              didEndSelector:nil
767                                 contextInfo:nil];
768             return;
769         }
771         /* fetch all the current settings in a uniform string */
772         NSString *newProfile = [_self generateProfileString];
774         /* add string to user defaults as well as a label */
776         NSMutableArray *workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"VideoEffectProfiles"]];
777         [workArray addObject:newProfile];
778         [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfiles"];
779         [defaults setInteger:[workArray count] - 1 forKey:@"VideoEffectSelectedProfile"];
781         workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"VideoEffectProfileNames"]];
782         [workArray addObject:resultingText];
783         [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfileNames"];
785         /* save defaults */
786         [defaults synchronize];
788         /* refresh UI */
789         [_self resetProfileSelector];
790     }];
793 - (void)removeProfile:(id)sender
795     /* show panel */
796 #pragma clang diagnostic push
797 #pragma clang diagnostic ignored "-Wpartial-availability"
798 #ifdef MAC_OS_X_VERSION_10_10
799     if (OSX_YOSEMITE_AND_HIGHER) {
800         [[_popupPanel window] setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]];
801     }
802 #endif
803 #pragma clang diagnostic pop
804     [_popupPanel setTitleString:_NS("Remove a preset")];
805     [_popupPanel setSubTitleString:_NS("Select the preset you would like to remove:")];
806     [_popupPanel setOkButtonString:_NS("Remove")];
807     [_popupPanel setCancelButtonString:_NS("Cancel")];
808     [_popupPanel setPopupButtonContent:[[NSUserDefaults standardUserDefaults] objectForKey:@"VideoEffectProfileNames"]];
810     // TODO: Change to weak, when dropping 10.7 support
811     __unsafe_unretained typeof(self) _self = self;
812     [_popupPanel runModalForWindow:self.window completionHandler:^(NSInteger returnCode, NSInteger selectedIndex) {
814         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
816         if (returnCode != NSOKButton) {
817             [_profilePopup selectItemAtIndex:[defaults integerForKey:@"VideoEffectSelectedProfile"]];
818             return;
819         }
821         if (!selectedIndex) { // TODO: add popup to notify user
822             [_profilePopup selectItemAtIndex:[defaults integerForKey:@"VideoEffectSelectedProfile"]];
823             return;
824         }
826         /* remove selected profile from settings */
827         NSMutableArray *workArray = [[NSMutableArray alloc] initWithArray: [defaults objectForKey:@"VideoEffectProfiles"]];
828         [workArray removeObjectAtIndex:selectedIndex];
829         [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfiles"];
831         workArray = [[NSMutableArray alloc] initWithArray: [defaults objectForKey:@"VideoEffectProfileNames"]];
832         [workArray removeObjectAtIndex:selectedIndex];
833         [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"VideoEffectProfileNames"];
835         if (i_old_profile_index >= selectedIndex)
836             [defaults setInteger:i_old_profile_index - 1 forKey:@"VideoEffectSelectedProfile"];
838         /* save defaults */
839         [defaults synchronize];
841         /* do not save deleted profile */
842         i_old_profile_index = -1;
843         /* refresh UI */
844         [_self resetProfileSelector];
845     }];
848 - (IBAction)applyProfileCheckboxChanged:(id)sender
850     [[NSUserDefaults standardUserDefaults] setBool:[sender state] forKey:@"VideoEffectApplyProfileOnStartup"];
853 #pragma mark -
854 #pragma mark basic
855 - (IBAction)enableAdjust:(id)sender
857     if (sender == _adjustResetButton) {
858         [_adjustBrightnessSlider setFloatValue: 1.0];
859         [_adjustContrastSlider setFloatValue: 1.0];
860         [_adjustGammaSlider setFloatValue: 1.0];
861         [_adjustHueSlider setFloatValue: 0];
862         [_adjustSaturationSlider setFloatValue: 1.0];
863         [_adjustBrightnessSlider setToolTip: [NSString stringWithFormat:@"%0.3f", 1.0]];
864         [_adjustContrastSlider setToolTip: [NSString stringWithFormat:@"%0.3f", 1.0]];
865         [_adjustGammaSlider setToolTip: [NSString stringWithFormat:@"%0.3f", 1.0]];
866         [_adjustHueSlider setToolTip: [NSString stringWithFormat:@"%.0f", 0.0]];
867         [_adjustSaturationSlider setToolTip: [NSString stringWithFormat:@"%0.3f", 1.0]];
869         VLCCoreInteraction *vci_si = [VLCCoreInteraction sharedInstance];
870         [vci_si setVideoFilterProperty: "brightness" forFilter: "adjust" withValue: (vlc_value_t){ .f_float = 1.f }];
871         [vci_si setVideoFilterProperty: "contrast" forFilter: "adjust" withValue: (vlc_value_t){ .f_float = 1.f }];
872         [vci_si setVideoFilterProperty: "gamma" forFilter: "adjust" withValue: (vlc_value_t){ .f_float = 1.f }];
873         [vci_si setVideoFilterProperty: "hue" forFilter: "adjust" withValue: (vlc_value_t){ .f_float = .0f }];
874         [vci_si setVideoFilterProperty: "saturation" forFilter: "adjust" withValue: (vlc_value_t){ .f_float = 1.f }];
875     } else {
876         BOOL b_state = [_adjustCheckbox state];
878         [[VLCCoreInteraction sharedInstance] setVideoFilter: "adjust" on: b_state];
879         [_adjustBrightnessSlider setEnabled: b_state];
880         [_adjustBrightnessCheckbox setEnabled: b_state];
881         [_adjustBrightnessLabel setEnabled: b_state];
882         [_adjustContrastSlider setEnabled: b_state];
883         [_adjustContrastLabel setEnabled: b_state];
884         [_adjustGammaSlider setEnabled: b_state];
885         [_adjustGammaLabel setEnabled: b_state];
886         [_adjustHueSlider setEnabled: b_state];
887         [_adjustHueLabel setEnabled: b_state];
888         [_adjustSaturationSlider setEnabled: b_state];
889         [_adjustSaturationLabel setEnabled: b_state];
890         [_adjustResetButton setEnabled: b_state];
891     }
894 - (IBAction)adjustSliderChanged:(id)sender
896     char const *psz_property;
898     if (sender == _adjustBrightnessSlider)
899         psz_property = "brightness";
900     else if (sender == _adjustContrastSlider)
901         psz_property = "contrast";
902     else if (sender == _adjustGammaSlider)
903         psz_property = "gamma";
904     else if (sender == _adjustHueSlider)
905         psz_property = "hue";
906     else if (sender == _adjustSaturationSlider)
907         psz_property = "saturation";
908     [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: psz_property forFilter: "adjust" withValue: getWidgetFloatValue(sender)];
910     if (sender == _adjustHueSlider)
911         [_adjustHueSlider setToolTip: [NSString stringWithFormat:@"%.0f", [_adjustHueSlider floatValue]]];
912     else
913         [sender setToolTip: [NSString stringWithFormat:@"%0.3f", [sender floatValue]]];
916 - (IBAction)enableAdjustBrightnessThreshold:(id)sender
918     [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "brightness-threshold"
919                                                       forFilter: "adjust"
920                                                       withValue: getWidgetBoolValue(sender)];
923 - (IBAction)enableSharpen:(id)sender
925     BOOL b_state = [_sharpenCheckbox state];
927     [[VLCCoreInteraction sharedInstance] setVideoFilter: "sharpen" on: b_state];
928     [_sharpenSlider setEnabled: b_state];
929     [_sharpenLabel setEnabled: b_state];
932 - (IBAction)sharpenSliderChanged:(id)sender
934     [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "sharpen-sigma" forFilter: "sharpen" withValue: getWidgetFloatValue(sender)];
935     [sender setToolTip: [NSString stringWithFormat:@"%0.3f", [sender floatValue]]];
938 - (IBAction)enableBanding:(id)sender
940     BOOL b_state = [_bandingCheckbox state];
942     [[VLCCoreInteraction sharedInstance] setVideoFilter: "gradfun" on: b_state];
943     [_bandingSlider setEnabled: b_state];
944     [_bandingLabel setEnabled: b_state];
947 - (IBAction)bandingSliderChanged:(id)sender
949     [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "gradfun-radius" forFilter: "gradfun" withValue: getWidgetIntValue(sender)];
950     [sender setToolTip: [NSString stringWithFormat:@"%i", [sender intValue]]];
953 - (IBAction)enableGrain:(id)sender
955     BOOL b_state = [_grainCheckbox state];
957     [[VLCCoreInteraction sharedInstance] setVideoFilter: "grain" on: b_state];
958     [_grainSlider setEnabled: b_state];
959     [_grainLabel setEnabled: b_state];
962 - (IBAction)grainSliderChanged:(id)sender
964     [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "grain-variance" forFilter: "grain" withValue: getWidgetFloatValue(sender)];
965     [sender setToolTip: [NSString stringWithFormat:@"%0.3f", [sender floatValue]]];
969 #pragma mark -
970 #pragma mark crop
972 - (IBAction)cropObjectChanged:(id)sender
974     if ([_cropSyncTopBottomCheckbox state]) {
975         if (sender == _cropBottomTextField || sender == _cropBottomStepper)
976             [self setCropTopValue: [self cropBottomValue]];
977         else
978             [self setCropBottomValue: [self cropTopValue]];
979     }
980     if ([_cropSyncLeftRightCheckbox state]) {
981         if (sender == _cropRightTextField || sender == _cropRightStepper)
982             [self setCropLeftValue: [self cropRightValue]];
983         else
984             [self setCropRightValue: [self cropLeftValue]];
985     }
987     NSArray<NSValue *> *vouts = getVouts();
988     if (vouts)
989         for (NSValue *ptr in vouts) {
990             vout_thread_t *p_vout = [ptr pointerValue];
991             var_SetInteger(p_vout, "crop-top", [_cropTopTextField intValue]);
992             var_SetInteger(p_vout, "crop-bottom", [_cropBottomTextField intValue]);
993             var_SetInteger(p_vout, "crop-left", [_cropLeftTextField intValue]);
994             var_SetInteger(p_vout, "crop-right", [_cropRightTextField intValue]);
995             vlc_object_release(p_vout);
996         }
999 #pragma mark -
1000 #pragma mark geometry
1001 - (IBAction)enableTransform:(id)sender
1003     [[VLCCoreInteraction sharedInstance] setVideoFilter: "transform" on: [_transformCheckbox state]];
1004     [_transformPopup setEnabled: [_transformCheckbox state]];
1007 - (IBAction)transformModifierChanged:(id)sender
1009     vlc_value_t value = { .psz_string = (char *)[[[_transformPopup selectedItem] representedObject] UTF8String] };
1010     [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "transform-type" forFilter: "transform" withValue: value];
1013 - (IBAction)enableZoom:(id)sender
1015     [[VLCCoreInteraction sharedInstance] setVideoFilter: "magnify" on: [_zoomCheckbox state]];
1018 - (IBAction)enablePuzzle:(id)sender
1020     BOOL b_state = [_puzzleCheckbox state];
1022     [[VLCCoreInteraction sharedInstance] setVideoFilter: "puzzle" on: b_state];
1023     [_puzzleColumnsTextField setEnabled: b_state];
1024     [_puzzleColumnsStepper setEnabled: b_state];
1025     [_puzzleColumnsLabel setEnabled: b_state];
1026     [_puzzleRowsTextField setEnabled: b_state];
1027     [_puzzleRowsStepper setEnabled: b_state];
1028     [_puzzleRowsLabel setEnabled: b_state];
1031 - (IBAction)puzzleModifierChanged:(id)sender
1033     if (sender == _puzzleColumnsTextField || sender == _puzzleColumnsStepper)
1034         [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "puzzle-cols" forFilter: "puzzle" withValue: getWidgetIntValue(sender)];
1035     else
1036         [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "puzzle-rows" forFilter: "puzzle" withValue: getWidgetIntValue(sender)];
1039 - (IBAction)enableClone:(id)sender
1041     BOOL b_state = [_cloneCheckbox state];
1043     if (b_state && [_wallCheckbox state]) {
1044         [_wallCheckbox setState: NSOffState];
1045         [self enableWall:_wallCheckbox];
1046     }
1048     [[VLCCoreInteraction sharedInstance] setVideoFilter: "clone" on: b_state];
1049     [_cloneNumberLabel setEnabled: b_state];
1050     [_cloneNumberTextField setEnabled: b_state];
1051     [_cloneNumberStepper setEnabled: b_state];
1054 - (IBAction)cloneModifierChanged:(id)sender
1056     [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "clone-count" forFilter: "clone" withValue: getWidgetIntValue(_cloneNumberTextField)];
1059 - (IBAction)enableWall:(id)sender
1061     BOOL b_state = [_wallCheckbox state];
1063     if (b_state && [_cloneCheckbox state]) {
1064         [_cloneCheckbox setState: NSOffState];
1065         [self enableClone:_cloneCheckbox];
1066     }
1068     [[VLCCoreInteraction sharedInstance] setVideoFilter: "wall" on: b_state];
1069     [_wallNumberOfColumnsTextField setEnabled: b_state];
1070     [_wallNumberOfColumnsStepper setEnabled: b_state];
1071     [_wallNumberOfColumnsLabel setEnabled: b_state];
1073     [_wallNumbersOfRowsTextField setEnabled: b_state];
1074     [_wallNumbersOfRowsStepper setEnabled: b_state];
1075     [_wallNumbersOfRowsLabel setEnabled: b_state];
1078 - (IBAction)wallModifierChanged:(id)sender
1080     char const *psz_property;
1081     if (sender == _wallNumberOfColumnsTextField || sender == _wallNumberOfColumnsStepper)
1082         psz_property = "wall-cols";
1083     else
1084         psz_property = "wall-rows";
1085     [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: psz_property forFilter: "wall" withValue: getWidgetIntValue(sender)];
1088 #pragma mark -
1089 #pragma mark color
1090 - (IBAction)enableThreshold:(id)sender
1092     BOOL b_state = [_thresholdCheckbox state];
1094     [[VLCCoreInteraction sharedInstance] setVideoFilter: "colorthres" on: b_state];
1095     [_thresholdColorTextField setEnabled: b_state];
1096     [_thresholdColorLabel setEnabled: b_state];
1097     [_thresholdSaturationSlider setEnabled: b_state];
1098     [_thresholdSaturationLabel setEnabled: b_state];
1099     [_thresholdSimilaritySlider setEnabled: b_state];
1100     [_thresholdSimilarityLabel setEnabled: b_state];
1103 - (IBAction)thresholdModifierChanged:(id)sender
1105     if (sender == _thresholdColorTextField)
1106         [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "colorthres-color" forFilter: "colorthres" withValue: getWidgetIntValue(sender)];
1107     else if (sender == _thresholdSaturationSlider) {
1108         [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "colorthres-saturationthres" forFilter: "colorthres" withValue: getWidgetIntValue(sender)];
1109         [_thresholdSaturationSlider setToolTip: [NSString stringWithFormat:@"%i", [_thresholdSaturationSlider intValue]]];
1110     } else {
1111         [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "colorthres-similaritythres" forFilter: "colorthres" withValue: getWidgetIntValue(sender)];
1112         [_thresholdSimilaritySlider setToolTip: [NSString stringWithFormat:@"%i", [_thresholdSimilaritySlider intValue]]];
1113     }
1116 - (IBAction)enableSepia:(id)sender
1118     BOOL b_state = [_sepiaCheckbox state];
1120     [[VLCCoreInteraction sharedInstance] setVideoFilter: "sepia" on: b_state];
1121     [_sepiaTextField setEnabled: b_state];
1122     [_sepiaStepper setEnabled: b_state];
1123     [_sepiaLabel setEnabled: b_state];
1126 - (IBAction)sepiaModifierChanged:(id)sender
1128     [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "sepia-intensity" forFilter: "sepia" withValue: getWidgetIntValue(sender)];
1131 - (IBAction)enableNoise:(id)sender
1133     [[VLCCoreInteraction sharedInstance] setVideoFilter: "noise" on: [_noiseCheckbox state]];
1136 - (IBAction)enableGradient:(id)sender
1138     BOOL b_state = [_gradientCheckbox state];
1140     [[VLCCoreInteraction sharedInstance] setVideoFilter: "gradient" on: b_state];
1141     [_gradientModePopup setEnabled: b_state];
1142     [_gradientModeLabel setEnabled: b_state];
1143     [_gradientColorCheckbox setEnabled: b_state];
1144     [_gradientCartoonCheckbox setEnabled: b_state];
1147 - (IBAction)gradientModifierChanged:(id)sender
1149     if (sender == _gradientModePopup) {
1150         vlc_value_t value = { .psz_string = (char *)[[[sender selectedItem] representedObject] UTF8String] };
1151         [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "gradient-mode" forFilter: "gradient" withValue: value];
1152     } else if (sender == _gradientColorCheckbox)
1153         [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "gradient-type" forFilter: "gradient" withValue: getWidgetBoolValue(sender)];
1154     else
1155         [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "gradient-cartoon" forFilter: "gradient" withValue: getWidgetBoolValue(sender)];
1158 - (IBAction)enableExtract:(id)sender
1160     BOOL b_state = [_extractCheckbox state];
1161     [[VLCCoreInteraction sharedInstance] setVideoFilter: "extract" on: b_state];
1162     [_extractTextField setEnabled: b_state];
1163     [_extractLabel setEnabled: b_state];
1166 - (IBAction)extractModifierChanged:(id)sender
1168     [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "extract-component" forFilter: "extract" withValue: getWidgetIntValue(sender)];
1171 - (IBAction)enableInvert:(id)sender
1173     [[VLCCoreInteraction sharedInstance] setVideoFilter: "invert" on: [_invertCheckbox state]];
1176 - (IBAction)enablePosterize:(id)sender
1178     BOOL b_state = [_posterizeCheckbox state];
1180     [[VLCCoreInteraction sharedInstance] setVideoFilter: "posterize" on: b_state];
1181     [_posterizeTextField setEnabled: b_state];
1182     [_posterizeStepper setEnabled: b_state];
1183     [_posterizeLabel setEnabled: b_state];
1186 - (IBAction)posterizeModifierChanged:(id)sender
1188     [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "posterize-level" forFilter: "posterize" withValue: getWidgetIntValue(sender)];
1191 - (IBAction)enableBlur:(id)sender
1193     BOOL b_state = [_blurCheckbox state];
1195     [[VLCCoreInteraction sharedInstance] setVideoFilter: "motionblur" on: b_state];
1196     [_blurSlider setEnabled: b_state];
1197     [_blurLabel setEnabled: b_state];
1200 - (IBAction)blurModifierChanged:(id)sender
1202     [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "blur-factor" forFilter: "motionblur" withValue: getWidgetIntValue(sender)];
1203     [sender setToolTip: [NSString stringWithFormat:@"%i", [sender intValue]]];
1206 - (IBAction)enableMotionDetect:(id)sender
1208     [[VLCCoreInteraction sharedInstance] setVideoFilter: "motiondetect" on: [_motiondetectCheckbox state]];
1211 - (IBAction)enableWaterEffect:(id)sender
1213     [[VLCCoreInteraction sharedInstance] setVideoFilter: "ripple" on: [_watereffectCheckbox state]];
1216 - (IBAction)enableWaves:(id)sender
1218     [[VLCCoreInteraction sharedInstance] setVideoFilter: "wave" on: [_wavesCheckbox state]];
1221 - (IBAction)enablePsychedelic:(id)sender
1223     [[VLCCoreInteraction sharedInstance] setVideoFilter: "psychedelic" on: [_psychedelicCheckbox state]];
1226 #pragma mark -
1227 #pragma mark Miscellaneous
1228 - (IBAction)enableAddText:(id)sender
1230     BOOL b_state = [_addTextCheckbox state];
1231     VLCCoreInteraction *vci_si = [VLCCoreInteraction sharedInstance];
1233     [_addTextPositionPopup setEnabled: b_state];
1234     [_addTextPositionLabel setEnabled: b_state];
1235     [_addTextTextLabel setEnabled: b_state];
1236     [_addTextTextTextField setEnabled: b_state];
1237     [vci_si setVideoFilter: "marq" on: b_state];
1238     [vci_si setVideoFilterProperty: "marq-marquee" forFilter: "marq" withValue: getWidgetStringValue(_addTextTextTextField)];
1239     [vci_si setVideoFilterProperty: "marq-position" forFilter: "marq" withValue: (vlc_value_t){ .i_int = [[_addTextPositionPopup selectedItem] tag] }];
1242 - (IBAction)addTextModifierChanged:(id)sender
1244     if (sender == _addTextTextTextField)
1245         [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "marq-marquee" forFilter: "marq" withValue: getWidgetStringValue(sender)];
1246     else
1247         [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "marq-position" forFilter: "marq" withValue: (vlc_value_t){ .i_int = [[sender selectedItem] tag] }];
1250 - (IBAction)enableAddLogo:(id)sender
1252     BOOL b_state = [_addLogoCheckbox state];
1254     [_addLogoPositionPopup setEnabled: b_state];
1255     [_addLogoPositionLabel setEnabled: b_state];
1256     [_addLogoLogoTextField setEnabled: b_state];
1257     [_addLogoLogoLabel setEnabled: b_state];
1258     [_addLogoTransparencySlider setEnabled: b_state];
1259     [_addLogoTransparencyLabel setEnabled: b_state];
1260     [[VLCCoreInteraction sharedInstance] setVideoFilter: "logo" on: b_state];
1263 - (IBAction)addLogoModifierChanged:(id)sender
1265     if (sender == _addLogoLogoTextField)
1266         [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "logo-file" forFilter: "logo" withValue: getWidgetStringValue(sender)];
1267     else if (sender == _addLogoPositionPopup)
1268         [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "logo-position" forFilter: "logo" withValue: (vlc_value_t){ .i_int = [[_addLogoPositionPopup selectedItem] tag] }];
1269     else {
1270         [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "logo-opacity" forFilter: "logo" withValue: getWidgetIntValue(sender)];
1271         [_addLogoTransparencySlider setToolTip: [NSString stringWithFormat:@"%i", [_addLogoTransparencySlider intValue]]];
1272     }
1275 - (IBAction)enableAnaglyph:(id)sender
1277     [[VLCCoreInteraction sharedInstance] setVideoFilter: "anaglyph" on: [_anaglyphCheckbox state]];
1280 @end