1 /*****************************************************************************
2 * VLCVideoEffectsWindowController.m: MacOS X interface module
3 *****************************************************************************
4 * Copyright (C) 2011-2015 Felix Paul Kühne
7 * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
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.
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.
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"
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;
44 #pragma mark Initialization
46 @implementation VLCVideoEffectsWindowController
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];
57 self = [super initWithWindowNibName:@"VideoEffects"];
59 i_old_profile_index = -1;
61 self.popupPanel = [[VLCPopupPanelController alloc] init];
62 self.textfieldPanel = [[VLCTextfieldPanelController alloc] init];
65 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"VideoEffectApplyProfileOnStartup"]) {
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"];
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");
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]);
97 for (NSValue *ptr in vouts) {
98 vout_thread_t *p_vout = [ptr pointerValue];
99 var_SetString(p_vout, "video-filter", [tempString UTF8String]);
102 tempString = B64DecNSStr([items objectAtIndex:1]);
103 /* enable another round of new filters */
104 var_SetString(p_playlist, "sub-source", [tempString UTF8String]);
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);
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] }];
156 vlc_value_t hueValue;
157 if ([items count] >= 34) { // version >=3 of profile string
158 hueValue.f_float = [[items objectAtIndex:33] floatValue];
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;
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
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];
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:)];
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);
378 int i_type = config_GetType(p_intf, psz_option) & VLC_VAR_CLASS;
382 case VLC_VAR_INTEGER:
387 msg_Err(p_intf, "%s variable is of an unsupported type (%d)", psz_option, i_type);
390 if (var_Create(p_playlist, psz_option, i_type | VLC_VAR_DOINHERIT) ||
391 var_GetChecked(p_playlist, psz_option, i_type, &val))
394 if (i_type == VLC_VAR_BOOL || i_type == VLC_VAR_INTEGER)
396 if ([widget isKindOfClass: [NSSlider class]])
398 [widget setIntValue: val.i_int];
399 [widget setToolTip: [NSString stringWithFormat:@"%lli", val.i_int]];
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];
410 else if (i_type == VLC_VAR_FLOAT)
412 if ([widget isKindOfClass: [NSSlider class]])
414 [widget setFloatValue: val.f_float];
415 [widget setToolTip: [NSString stringWithFormat:@"%0.3f", val.f_float]];
418 else if (i_type == VLC_VAR_STRING)
420 if ([widget isKindOfClass: [NSPopUpButton class]])
422 for (NSMenuItem *item in [widget itemArray])
423 if ([item representedObject] &&
424 !strcmp([[item representedObject] UTF8String], val.psz_string))
426 [widget selectItemWithTitle: [item title]];
430 else if ([widget isKindOfClass: [NSTextField class]])
431 [widget setStringValue: toNSStr(val.psz_string)];
432 free(val.psz_string);
435 [widget setEnabled: b_state];
440 intf_thread_t *p_intf = getIntf();
441 playlist_t *p_playlist = pl_Get(p_intf);
446 /* do we have any filter enabled? if yes, show it. */
448 psz_vfilters = var_InheritString(p_playlist, "video-filter");
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")];
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];
494 psz_vfilters = var_InheritString(p_playlist, "sub-source");
496 [_addTextCheckbox setState: (NSInteger)strstr(psz_vfilters, "marq")];
497 [_addLogoCheckbox setState: (NSInteger)strstr(psz_vfilters, "logo")];
500 [_addTextCheckbox setState: NSOffState];
501 [_addLogoCheckbox setState: NSOffState];
504 psz_vfilters = var_InheritString(p_playlist, "video-splitter");
506 [_cloneCheckbox setState: (NSInteger)strstr(psz_vfilters, "clone")];
507 [_wallCheckbox setState: (NSInteger)strstr(psz_vfilters, "wall")];
510 [_cloneCheckbox setState: NSOffState];
511 [_wallCheckbox setState: NSOffState];
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
658 #pragma mark generic UI code
660 - (void)saveCurrentProfile
662 if (!i_old_profile_index || i_old_profile_index == -1)
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])
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)
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;
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];
712 [self.window setLevel: [[[VLCMain sharedInstance] voutController] currentStatusWindowLevel]];
713 [self.window makeKeyAndOrderFront:sender];
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"];
726 - (void)addProfile:(id)sender
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]];
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"]];
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
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"];
786 [defaults synchronize];
789 [_self resetProfileSelector];
793 - (void)removeProfile:(id)sender
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]];
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"]];
821 if (!selectedIndex) { // TODO: add popup to notify user
822 [_profilePopup selectItemAtIndex:[defaults integerForKey:@"VideoEffectSelectedProfile"]];
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"];
839 [defaults synchronize];
841 /* do not save deleted profile */
842 i_old_profile_index = -1;
844 [_self resetProfileSelector];
848 - (IBAction)applyProfileCheckboxChanged:(id)sender
850 [[NSUserDefaults standardUserDefaults] setBool:[sender state] forKey:@"VideoEffectApplyProfileOnStartup"];
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 }];
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];
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]]];
913 [sender setToolTip: [NSString stringWithFormat:@"%0.3f", [sender floatValue]]];
916 - (IBAction)enableAdjustBrightnessThreshold:(id)sender
918 [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "brightness-threshold"
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]]];
972 - (IBAction)cropObjectChanged:(id)sender
974 if ([_cropSyncTopBottomCheckbox state]) {
975 if (sender == _cropBottomTextField || sender == _cropBottomStepper)
976 [self setCropTopValue: [self cropBottomValue]];
978 [self setCropBottomValue: [self cropTopValue]];
980 if ([_cropSyncLeftRightCheckbox state]) {
981 if (sender == _cropRightTextField || sender == _cropRightStepper)
982 [self setCropLeftValue: [self cropRightValue]];
984 [self setCropRightValue: [self cropLeftValue]];
987 NSArray<NSValue *> *vouts = getVouts();
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);
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)];
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];
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];
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";
1084 psz_property = "wall-rows";
1085 [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: psz_property forFilter: "wall" withValue: getWidgetIntValue(sender)];
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]]];
1111 [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "colorthres-similaritythres" forFilter: "colorthres" withValue: getWidgetIntValue(sender)];
1112 [_thresholdSimilaritySlider setToolTip: [NSString stringWithFormat:@"%i", [_thresholdSimilaritySlider intValue]]];
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)];
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]];
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)];
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] }];
1270 [[VLCCoreInteraction sharedInstance] setVideoFilterProperty: "logo-opacity" forFilter: "logo" withValue: getWidgetIntValue(sender)];
1271 [_addLogoTransparencySlider setToolTip: [NSString stringWithFormat:@"%i", [_addLogoTransparencySlider intValue]]];
1275 - (IBAction)enableAnaglyph:(id)sender
1277 [[VLCCoreInteraction sharedInstance] setVideoFilter: "anaglyph" on: [_anaglyphCheckbox state]];