]> git.sesse.net Git - vlc/blob - modules/gui/macosx/extended.m
* adapted the extended panel to the latest video filter changes and re-designed the...
[vlc] / modules / gui / macosx / extended.m
1 /*****************************************************************************
2  * extended.m: MacOS X Extended interface panel
3  *****************************************************************************
4  * Copyright (C) 2005-2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Felix Kühne <fkuehne@users.sf.net>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24
25 /*****************************************************************************
26  * Note: 
27  * the code used to bind with VLC's modules is heavily based upon 
28  * ../wxwidgets/extrapanel.cpp, written by Clément Stenac.
29  * the code used to insert/remove the views was inspired by intf.m, 
30  * written by Derk-Jan Hartman and Benjamin Pracht. 
31  * (all 3 are members of the VideoLAN team) 
32  *****************************************************************************/
33
34
35 /*****************************************************************************
36  * Preamble
37  *****************************************************************************/
38
39 #import "extended.h"
40 #import "intf.h"
41 #import "vout.h"
42 #import <vlc/aout.h>
43 #import <aout_internal.h>
44 #import <vlc/vout.h>
45 #import <vlc/intf.h>
46
47 /*****************************************************************************
48  * VLCExtended implementation
49  *****************************************************************************/
50
51 @implementation VLCExtended
52
53 static VLCExtended *_o_sharedInstance = nil;
54
55 + (VLCExtended *)sharedInstance
56 {
57     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
58 }
59
60 - (id)init
61 {
62     if (_o_sharedInstance) {
63         [self dealloc];
64     } else {
65         _o_sharedInstance = [super init];
66     }
67
68     return _o_sharedInstance;
69 }
70
71 /*****************************************************************************
72  * GUI methods
73  *****************************************************************************/
74
75 - (void)initStrings
76 {
77     /* localise GUI-strings */
78     /* method is called from intf.m (in method showExtended) */
79     [o_extended_window setTitle: _NS("Extended controls")];
80     [o_lbl_video setStringValue: _NS("Video")];
81     [o_lbl_audio setStringValue: _NS("Audio")];
82     [o_lbl_audioFlts setStringValue: _NS("Audio filters")];
83     [o_lbl_videoFlts setStringValue: _NS("Video filters")];
84     [o_lbl_adjustImage setStringValue: _NS("Image adjustment")];
85     [o_btn_vidFlts_mrInfo setTitle: _NS("More Info")];
86     [o_ckb_wave setTitle: _NS("Wave")];
87     [o_ckb_ripple setTitle: _NS("Ripple")];
88     [o_ckb_psycho setTitle: _NS("Psychedelic")];
89     [o_ckb_gradient setTitle: _NS("Gradient")];
90     [o_lbl_general setStringValue: _NS("General editing filters")];
91     [o_lbl_distort setStringValue: _NS("Distortion filters")];
92     [o_ckb_blur setTitle: _NS("Blur")];
93     [o_ckb_blur setToolTip: _NS("Adds motion blurring to the image")];
94     [o_ckb_imgClone setTitle: _NS("Image clone")];
95     [o_ckb_imgClone setToolTip: _NS("Creates several copies of the Video "
96                                     "output window" )];
97     [o_ckb_imgCrop setTitle: _NS("Image cropping")];
98     [o_ckb_imgCrop setToolTip: _NS("Crops a defined part of the image")];
99     [o_ckb_imgInvers setTitle: _NS("Invert colors")];
100     [o_ckb_imgInvers setToolTip: _NS("Inverts the colors of the image")];
101     [o_ckb_trnsform setTitle: _NS("Transformation")];
102     [o_ckb_trnsform setToolTip: _NS("Rotates or flips the image")];
103     [o_ckb_intZoom setTitle: _NS("Interactive Zoom")];
104     [o_ckb_intZoom setToolTip: _NS("Enables an interactive Zoom feature")];
105     [o_ckb_vlme_norm setTitle: _NS("Volume normalization")];
106     [o_ckb_vlme_norm setToolTip: _NS("Prevents the audio output from going "
107         "over a predefined value.")];
108     [o_ckb_hdphnVirt setTitle: _NS("Headphone virtualization")];
109     [o_ckb_hdphnVirt setToolTip: _NS("Imitates the effect of surround sound "
110         "when using headphones.")];
111     [o_lbl_maxLevel setStringValue: _NS("Maximum level")];
112     [o_btn_rstrDefaults setTitle: _NS("Restore Defaults")];
113     [o_ckb_enblAdjustImg setTitle: _NS("Enable")];
114     [o_lbl_brightness setStringValue: _NS("Brightness")];
115     [o_lbl_contrast setStringValue: _NS("Contrast")];
116     [o_lbl_gamma setStringValue: _NS("Gamma")];
117     [o_lbl_hue setStringValue: _NS("Hue")];
118     [o_lbl_saturation setStringValue: _NS("Saturation")];
119     [o_lbl_opaque setStringValue: _NS("Opaqueness")];
120     
121 }
122
123 - (void)awakeFromNib
124 {
125     /* set the adjust-filter-sliders to the values from the prefs and enable
126      * them, if wanted */
127     char * psz_vfilters;
128     intf_thread_t * p_intf = VLCIntf;
129     psz_vfilters = config_GetPsz( p_intf, "vout-filter" );
130     if( psz_vfilters && strstr( psz_vfilters, "adjust" ) )
131     {
132         [o_ckb_enblAdjustImg setState: NSOnState];
133         [o_btn_rstrDefaults setEnabled: YES];
134         [o_sld_brightness setEnabled: YES];
135         [o_sld_contrast setEnabled: YES];
136         [o_sld_gamma setEnabled: YES];
137         [o_sld_hue setEnabled: YES];
138         [o_sld_saturation setEnabled: YES];
139     }
140     else
141     {
142         [o_ckb_enblAdjustImg setState: NSOffState];
143         [o_btn_rstrDefaults setEnabled: NO];
144         [o_sld_brightness setEnabled: NO];
145         [o_sld_contrast setEnabled: NO];
146         [o_sld_gamma setEnabled: NO];
147         [o_sld_hue setEnabled: NO];
148         [o_sld_saturation setEnabled: NO];
149     }
150     
151     /* set the other video-filter-checkboxes to the correct values */
152     if( psz_vfilters )
153     {
154         [o_ckb_blur setState: (int)strstr( psz_vfilters, "motionblur")];
155         [o_ckb_imgClone setState: (int)strstr( psz_vfilters, "clone")];
156         [o_ckb_imgCrop setState: (int)strstr( psz_vfilters, "crop")];
157         [o_ckb_trnsform setState: (int)strstr( psz_vfilters, "transform")];
158
159         free( psz_vfilters );
160     }
161     
162     /* set the video-filter checkboxes to the correct values */
163     char * psz_vifilters;
164     psz_vifilters = config_GetPsz( p_intf, "video-filter" );
165     if( psz_vifilters )
166     {
167         [o_ckb_wave setState: (int)strstr( psz_vifilters, "wave")];
168         [o_ckb_psycho setState: (int)strstr( psz_vifilters, "psychedelic")];
169         [o_ckb_ripple setState: (int)strstr( psz_vifilters, "ripple")];
170         [o_ckb_gradient setState: (int)strstr( psz_vifilters, "gradient")];
171         [o_ckb_imgInvers setState: (int)strstr( psz_vifilters, "invert")];
172
173         free( psz_vifilters );
174     }
175     
176     /* set the audio-filter-checkboxes to the values taken from the prefs */
177     char * psz_afilters;
178     psz_afilters = config_GetPsz( p_intf, "audio-filter" );
179     if( psz_afilters )
180     {
181         [o_ckb_hdphnVirt setState: (int)strstr( psz_afilters, "headphone" ) ];
182         [o_ckb_vlme_norm setState: (int)strstr( psz_afilters, "normvol" ) ];
183         
184         free( psz_afilters );
185     }
186 }
187
188 - (void)collapsAll
189 {
190     /* collaps all views so Cocoa saves the window position correctly */
191     if( o_adjImg_expanded )
192     {
193         [self extWin_exp_adjImg: nil];
194     }
195     if( o_audFlts_expanded )
196     {
197         [self extWin_exp_audFlts: nil];
198     }
199     if( o_vidFlts_expanded )
200     {
201         [self extWin_exp_vidFlts: nil];
202     }
203 }
204
205 - (BOOL)getConfigChanged
206 {
207     return o_config_changed;
208 }
209
210 - (void)showPanel
211 {
212     /* get the correct slider values from the prefs, in case they were changed
213      * elsewhere */
214     intf_thread_t * p_intf = VLCIntf;
215
216     int i_value = config_GetInt( p_intf, "hue" );
217     if( i_value > 0 && i_value < 360 )
218     {
219         [o_sld_hue setIntValue: i_value];
220     }
221
222     float f_value;
223     
224     f_value = config_GetFloat( p_intf, "saturation" );
225     if( f_value > 0 && f_value < 5 )
226     {
227         [o_sld_saturation setIntValue: (int)(100 * f_value) ];
228     }
229
230     f_value = config_GetFloat( p_intf, "contrast" );
231     if( f_value > 0 && f_value < 4 )
232     {
233         [o_sld_contrast setIntValue: (int)(100 * f_value) ];
234     }
235
236     f_value = config_GetFloat( p_intf, "brightness" );
237     if( f_value > 0 && f_value < 2 )
238     {
239         [o_sld_brightness setIntValue: (int)(100 * f_value) ];
240     }
241
242     f_value = config_GetFloat( p_intf, "gamma" );
243     if( f_value > 0 && f_value < 10 )
244     {
245         [o_sld_gamma setIntValue: (int)(10 * f_value) ];
246     }
247
248     f_value = config_GetFloat( p_intf, "norm-max-level" );
249     if( f_value > 0 && f_value < 10 )
250     {
251         [o_sld_maxLevel setFloatValue: f_value ];
252     }
253
254     [o_sld_opaque setFloatValue: (config_GetFloat( p_intf,
255         "macosx-opaqueness") * 100)];
256
257
258     /* show the window */
259     [o_extended_window displayIfNeeded];
260     [o_extended_window makeKeyAndOrderFront:nil];
261 }
262
263 - (IBAction)adjImg_Enbl:(id)sender
264 {
265     /* en-/disable the sliders */
266     if ([o_ckb_enblAdjustImg state] == NSOnState)
267     {
268         [o_btn_rstrDefaults setEnabled: YES];
269         [o_sld_brightness setEnabled: YES];
270         [o_sld_contrast setEnabled: YES];
271         [o_sld_gamma setEnabled: YES];
272         [o_sld_hue setEnabled: YES];
273         [o_sld_saturation setEnabled: YES];
274         [self changeVoutFiltersString: "adjust" onOrOff: VLC_TRUE];
275     }else{
276         [o_btn_rstrDefaults setEnabled: NO];
277         [o_sld_brightness setEnabled: NO];
278         [o_sld_contrast setEnabled: NO];
279         [o_sld_gamma setEnabled: NO];
280         [o_sld_hue setEnabled: NO];
281         [o_sld_saturation setEnabled: NO];
282         [self changeVoutFiltersString: "adjust" onOrOff: VLC_FALSE];
283     }
284 }
285
286 - (IBAction)adjImg_rstrDefaults:(id)sender
287 {
288     /* reset the sliders */
289     [o_sld_brightness setIntValue: 100];
290     [o_sld_contrast setIntValue: 100];
291     [o_sld_gamma setIntValue: 10];
292     [o_sld_hue setIntValue: 0];
293     [o_sld_saturation setIntValue: 100];
294     
295     /* transmit the values */
296     [self adjImg_sliders: o_sld_brightness];
297     [self adjImg_sliders: o_sld_contrast];
298     [self adjImg_sliders: o_sld_gamma];
299     [self adjImg_sliders: o_sld_hue];
300     [self adjImg_sliders: o_sld_saturation];
301 }
302
303 - (IBAction)adjImg_sliders:(id)sender
304 {
305     /* read-out the sliders' values and apply them */
306     intf_thread_t * p_intf = VLCIntf;
307     vout_thread_t *p_vout = (vout_thread_t *)vlc_object_find(p_intf,
308                                  VLC_OBJECT_VOUT, FIND_ANYWHERE);
309     if( p_vout == NULL )
310     {
311         if (sender == o_sld_brightness)
312         {
313             config_PutFloat( p_intf , "brightness" , [o_sld_brightness floatValue] / 100);
314         } else if (sender == o_sld_contrast)
315         {
316             config_PutFloat( p_intf , "contrast" , [o_sld_contrast floatValue] / 100);
317         } else if (sender == o_sld_gamma)
318         {
319             config_PutFloat( p_intf , "gamma" , [o_sld_gamma floatValue] / 10);
320         } else if (sender == o_sld_hue)
321         {
322             config_PutInt( p_intf , "hue" , [o_sld_hue intValue]);
323         } else if (sender == o_sld_saturation)
324         {
325             config_PutFloat( p_intf , "saturation" , [o_sld_saturation floatValue] / 100);
326         } else {
327             msg_Warn( p_intf, "the corresponding subfilter coundn't be found" );
328         }
329     } else {
330         vlc_value_t val;
331         if (sender == o_sld_brightness)
332         {
333             val.f_float = [o_sld_brightness floatValue] / 100;
334             var_Set( p_vout, "brightness", val );
335             config_PutFloat( p_intf , "brightness" , [o_sld_brightness floatValue] / 100);
336         } else if (sender == o_sld_contrast)
337         {
338             val.f_float = [o_sld_contrast floatValue] / 100;
339             var_Set( p_vout, "contrast", val );
340             config_PutFloat( p_intf , "contrast" , [o_sld_contrast floatValue] / 100);
341         } else if (sender == o_sld_gamma)
342         {
343             val.f_float = [o_sld_gamma floatValue] / 10;
344             var_Set( p_vout, "gamma", val );
345             config_PutFloat( p_intf , "gamma" , [o_sld_gamma floatValue] / 10);
346         } else if (sender == o_sld_hue)
347         {
348             val.i_int = [o_sld_hue intValue];
349             var_Set( p_vout, "hue", val );
350             config_PutInt( p_intf , "hue" , [o_sld_hue intValue]);
351         } else if (sender == o_sld_saturation)
352         {
353             val.f_float = [o_sld_saturation floatValue] / 100;
354             var_Set( p_vout, "saturation", val );
355             config_PutFloat( p_intf , "saturation" , [o_sld_saturation floatValue] / 100);
356         } else {
357             msg_Warn( p_intf, "the corresponding subfilter coundn't be found" );
358         }
359         vlc_object_release( p_vout );
360     }
361
362     o_config_changed = YES;
363 }
364
365 /* change the opaqueness of the vouts */
366 - (IBAction)adjImg_opaque:(id)sender
367 {
368     vlc_value_t val;
369     id o_window = [NSApp keyWindow];
370     NSArray *o_windows = [NSApp orderedWindows];
371     NSEnumerator *o_enumerator = [o_windows objectEnumerator];
372     playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
373         FIND_ANYWHERE );
374     vout_thread_t *p_vout = vlc_object_find( VLCIntf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
375     vout_thread_t *p_real_vout;
376
377     val.f_float = [o_sld_opaque floatValue] / 100;
378
379
380     if( p_vout != NULL )
381     {
382         p_real_vout = [VLCVoutView getRealVout: p_vout];
383         var_Set( p_real_vout, "macosx-opaqueness", val );
384
385         while ((o_window = [o_enumerator nextObject]))
386         {
387             if( [[o_window className] isEqualToString: @"VLCWindow"] ||
388                 [[[VLCMain sharedInstance] getEmbeddedList]
389                                     windowContainsEmbedded: o_window])
390             {
391                 [o_window setAlphaValue: val.f_float];
392             }
393             break;
394         }
395         vlc_object_release( p_vout );
396     }
397     
398     /* store to prefs */
399     config_PutFloat( p_playlist , "macosx-opaqueness" , val.f_float );
400     
401     vlc_object_release( p_playlist );
402
403     o_config_changed = YES;
404 }
405
406 - (IBAction)audFtls_hdphnVirt:(id)sender
407 {
408     /* en-/disable headphone virtualisation */
409     if ([o_ckb_hdphnVirt state] == NSOnState)
410     {
411         [self changeAFiltersString: "headphone_channel_mixer" onOrOff: VLC_TRUE ];
412     }else{
413         [self changeAFiltersString: "headphone_channel_mixer" onOrOff: VLC_FALSE ];
414     }
415 }
416
417 - (IBAction)audFtls_maxLevelSld:(id)sender
418 {
419     /* read-out the slider's value and apply it */
420     intf_thread_t * p_intf = VLCIntf;
421     aout_instance_t * p_aout= (aout_instance_t *)vlc_object_find(p_intf,
422                                  VLC_OBJECT_AOUT, FIND_ANYWHERE);
423     if( p_aout != NULL )
424     {
425         var_SetFloat( p_aout, "norm-max-level", [o_sld_maxLevel floatValue] );
426         vlc_object_release( p_aout );
427     }
428     config_PutFloat( p_intf, "norm-max-level", [o_sld_maxLevel floatValue] );
429
430     o_config_changed = YES;
431 }
432
433 - (IBAction)audFtls_vlmeNorm:(id)sender
434 {
435     /* en-/disable volume normalisation */
436     if ([o_ckb_vlme_norm state] == NSOnState)
437     {
438         [self changeAFiltersString: "normvol" onOrOff: YES ];
439     }else{
440         [self changeAFiltersString: "normvol" onOrOff: NO ];
441     }
442 }
443
444 - (IBAction)extWin_exp_adjImg:(id)sender
445 {
446     /* expand or collapse adjImg */
447     NSRect o_win_rect = [o_extended_window frame];
448     NSRect o_box_audFlts_rect = [o_box_audFlts frame];
449     NSRect o_box_vidFlts_rect = [o_box_vidFlts frame];
450     NSRect o_box_adjImg_rect = [o_box_adjImg frame];
451     
452     if (o_adjImg_expanded)
453     {
454         /* move the window contents upwards (partially done through settings
455          * inside the nib) and resize the window */
456         o_win_rect.size.height = o_win_rect.size.height - 193;
457         o_win_rect.origin.y = [o_extended_window frame].origin.y + 193;
458         o_box_audFlts_rect.origin.y = o_box_audFlts_rect.origin.y + 193;
459         o_box_vidFlts_rect.origin.y = o_box_vidFlts_rect.origin.y + 193;
460         
461         /* remove the inserted view */
462         [o_adjustImg_view removeFromSuperviewWithoutNeedingDisplay];
463     }else{
464     
465         /* move the window contents downwards and resize the window */
466         o_win_rect.size.height = o_win_rect.size.height + 193;
467         o_win_rect.origin.y = [o_extended_window frame].origin.y - 193;
468         o_box_audFlts_rect.origin.y = o_box_audFlts_rect.origin.y - 193;
469         o_box_vidFlts_rect.origin.y = o_box_vidFlts_rect.origin.y - 193;
470     }
471     
472     [o_box_audFlts setFrameFromContentFrame: o_box_audFlts_rect];
473     [o_box_vidFlts setFrameFromContentFrame: o_box_vidFlts_rect];
474     [o_extended_window displayIfNeeded];
475     [o_extended_window setFrame: o_win_rect display:YES animate: YES];
476     
477     if (o_adjImg_expanded)
478     {
479         o_box_adjImg_rect.size.height = [o_box_adjImg frame].size.height - 193;
480         o_adjImg_expanded = NO;
481     } else {
482         /* insert view */
483         o_box_adjImg_rect.size.height = [o_box_adjImg frame].size.height + 193;
484         [o_adjustImg_view setFrame: NSMakeRect( 20, -10, 370, 203)];
485         [o_adjustImg_view setNeedsDisplay:YES];
486         [o_adjustImg_view setAutoresizesSubviews: YES];
487         [[o_box_adjImg contentView] addSubview: o_adjustImg_view];
488         o_adjImg_expanded = YES;
489     }
490     [o_box_adjImg setFrameFromContentFrame: o_box_adjImg_rect];
491 }
492
493 - (IBAction)extWin_exp_audFlts:(id)sender
494 {
495     /* expand or collapse audFlts */
496     NSRect o_win_rect = [o_extended_window frame];
497     NSRect o_box_audFlts_rect = [o_box_audFlts frame];
498     
499     if (o_audFlts_expanded)
500     {
501         /* move the window contents upwards (partially done through settings
502          * inside the nib) and resize the window */
503         o_win_rect.size.height = o_win_rect.size.height - 66;
504         o_win_rect.origin.y = [o_extended_window frame].origin.y + 66;
505         
506         /* remove the inserted view */
507         [o_audioFlts_view removeFromSuperviewWithoutNeedingDisplay];
508     }else{
509         /* move the window contents downwards and resize the window */
510         o_win_rect.size.height = o_win_rect.size.height + 66;
511         o_win_rect.origin.y = [o_extended_window frame].origin.y - 66;
512     }
513     [o_extended_window displayIfNeeded];
514     [o_extended_window setFrame: o_win_rect display:YES animate: YES];
515     
516     
517     if (o_audFlts_expanded)
518     {
519         o_box_audFlts_rect.size.height = [o_box_audFlts frame].size.height - 66;
520         o_audFlts_expanded = NO;
521     } else {
522         /* insert view */
523         o_box_audFlts_rect.size.height = [o_box_audFlts frame].size.height + 66;
524         [o_audioFlts_view setFrame: NSMakeRect( 20, -20, 370, 76)];
525         [o_audioFlts_view setNeedsDisplay:YES];
526         [o_audioFlts_view setAutoresizesSubviews: YES];
527         [[o_box_audFlts contentView] addSubview: o_audioFlts_view];
528         o_audFlts_expanded = YES;
529     }
530     [o_box_audFlts setFrameFromContentFrame: o_box_audFlts_rect];
531 }
532
533 - (IBAction)extWin_exp_vidFlts:(id)sender
534 {
535     /* expand or collapse vidFlts */
536     NSRect o_win_rect = [o_extended_window frame];
537     NSRect o_box_audFlts_rect = [o_box_audFlts frame];
538     NSRect o_box_vidFlts_rect = [o_box_vidFlts frame];
539     
540     if (o_vidFlts_expanded)
541     {
542         /* move the window contents upwards (partially done through settings
543          * inside the nib) and resize the window */
544         o_win_rect.size.height = o_win_rect.size.height - 188;
545         o_win_rect.origin.y = [o_extended_window frame].origin.y + 188;
546         o_box_audFlts_rect.origin.y = o_box_audFlts_rect.origin.y + 188;
547         
548         /* remove the inserted view */
549         [o_videoFilters_view removeFromSuperviewWithoutNeedingDisplay];
550     }else{
551     
552         /* move the window contents downwards and resize the window */
553         o_win_rect.size.height = o_win_rect.size.height + 188;
554         o_win_rect.origin.y = [o_extended_window frame].origin.y - 188;
555         o_box_audFlts_rect.origin.y = o_box_audFlts_rect.origin.y - 188;
556     }
557     
558     [o_box_audFlts setFrameFromContentFrame: o_box_audFlts_rect];
559     [o_extended_window displayIfNeeded];
560     [o_extended_window setFrame: o_win_rect display:YES animate: YES];
561     
562     if (o_vidFlts_expanded)
563     {
564         o_box_vidFlts_rect.size.height = [o_box_vidFlts frame].size.height - 188;
565         o_vidFlts_expanded = NO;
566     } else {
567         /* insert view */
568         o_box_vidFlts_rect.size.height = [o_box_vidFlts frame].size.height + 188;
569         [o_videoFilters_view setFrame: NSMakeRect( 20, -10, 370, 188)];
570         [o_videoFilters_view setNeedsDisplay:YES];
571         [o_videoFilters_view setAutoresizesSubviews: YES];
572         [[o_box_vidFlts contentView] addSubview: o_videoFilters_view];
573         o_vidFlts_expanded = YES;
574     }
575     [o_box_vidFlts setFrameFromContentFrame: o_box_vidFlts_rect];
576 }
577
578 - (IBAction)vidFlts:(id)sender
579 {
580     /* en-/disable video filters */
581     if (sender == o_ckb_blur)
582         [self changeVoutFiltersString: "motionblur" onOrOff: [o_ckb_blur state]];
583
584     else if (sender == o_ckb_imgClone)
585         [self changeVoutFiltersString: "clone" onOrOff: [o_ckb_imgClone state]];
586
587     else if (sender == o_ckb_imgCrop)
588         [self changeVoutFiltersString: "crop" onOrOff: [o_ckb_imgCrop state]];
589
590     else if (sender == o_ckb_imgInvers)
591         [self changeVideoFiltersString: "invert" onOrOff: [o_ckb_imgInvers state]];
592
593     else if (sender == o_ckb_trnsform)
594         [self changeVoutFiltersString: "transform" onOrOff: [o_ckb_trnsform state]];
595
596     else if (sender == o_ckb_intZoom )
597         [self changeVoutFiltersString: "magnify" onOrOff: [o_ckb_intZoom state]];
598
599     else if (sender == o_ckb_wave )
600         [self changeVideoFiltersString: "wave" onOrOff: [o_ckb_wave state]];
601
602     else if (sender == o_ckb_gradient )
603         [self changeVideoFiltersString: "gradient" onOrOff: [o_ckb_gradient state]];
604
605     else if (sender == o_ckb_psycho )
606         [self changeVideoFiltersString: "psychedelic" onOrOff: [o_ckb_psycho state]];
607
608     else if (sender == o_ckb_ripple )
609         [self changeVideoFiltersString: "ripple" onOrOff: [o_ckb_ripple state]];
610
611     else {
612         /* this shouldn't happen */
613         msg_Warn (VLCIntf, "cannot find switched video-filter");
614     }
615 }
616
617 - (IBAction)vidFlts_mrInfo:(id)sender
618 {
619     /* show info sheet */
620     NSBeginInformationalAlertSheet(_NS("More Information"), _NS("OK"), @"", @"",
621         o_extended_window, nil, nil, nil, nil, _NS("This panel allows to "
622         "select video effects filters to apply.\n"
623         "The filters can be configured individually in the Preferences, in "
624         "the subsections of Video/Filters.\n"
625         "To choose the order in which the filter are applied, a filter "
626         "option string can be set in the Preferences, Video / Filters section."));
627 }
628
629
630 /*****************************************************************************
631  * methods to communicate changes to VLC's core
632  *****************************************************************************/
633
634 - (void)changeVoutFiltersString:(char *)psz_name onOrOff:(vlc_bool_t )b_add 
635 {
636     /* copied from ../wxwidgets/extrapanel.cpp
637      * renamed to conform with Cocoa's rules */
638     /* this method only changes 1st generation video filters (the ones which 
639      * can't be used for transcoding). Have a look at changeVideoFiltersString
640      * for the 2nd generation filters. */
641      
642     vout_thread_t *p_vout;
643     intf_thread_t * p_intf = VLCIntf;
644     
645     char *psz_parser, *psz_string;
646     psz_string = config_GetPsz( p_intf, "vout-filter" );
647     
648     if( !psz_string ) psz_string = strdup("");
649
650     psz_parser = strstr( psz_string, psz_name );
651
652     if( b_add )
653     {
654         if( !psz_parser )
655         {
656             psz_parser = psz_string;
657             asprintf( &psz_string, (*psz_string) ? "%s:%s" : "%s%s",
658                             psz_string, psz_name );
659             free( psz_parser );
660         }
661         else
662         {
663             return;
664         }
665     }
666     else
667     {
668         if( psz_parser )
669         {
670             memmove( psz_parser, psz_parser + strlen(psz_name) +
671                             (*(psz_parser + strlen(psz_name)) == ':' ? 1 : 0 ),
672                             strlen(psz_parser + strlen(psz_name)) + 1 );
673
674             /* Remove trailing : : */
675             if( *(psz_string+strlen(psz_string ) -1 ) == ':' )
676             {
677                 *(psz_string+strlen(psz_string ) -1 ) = '\0';
678             }
679          }
680          else
681          {
682              free( psz_string );
683              return;
684          }
685     }
686     /* Vout is not kept, so put that in the config */
687     config_PutPsz( p_intf, "vout-filter", psz_string );
688
689     /* Try to set on the fly */
690     p_vout = (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
691                                               FIND_ANYWHERE );
692     if( p_vout )
693     {
694         var_SetString( p_vout, "vout-filter", psz_string );
695         vlc_object_release( p_vout );
696     }
697
698     free( psz_string );
699
700     o_config_changed = YES;
701 }
702
703
704 - (void)changeVideoFiltersString:(char *)psz_name onOrOff:(vlc_bool_t )b_add 
705 {
706     /* same as changeVoutFiltersString but addressing the "video-filter"
707      * variable which represents the video filter 2 modules */
708      
709     vout_thread_t *p_vout;
710     intf_thread_t * p_intf = VLCIntf;
711     
712     char *psz_parser, *psz_string;
713     psz_string = config_GetPsz( p_intf, "video-filter" );
714     
715     if( !psz_string ) psz_string = strdup("");
716
717     psz_parser = strstr( psz_string, psz_name );
718
719     if( b_add )
720     {
721         if( !psz_parser )
722         {
723             psz_parser = psz_string;
724             asprintf( &psz_string, (*psz_string) ? "%s:%s" : "%s%s",
725                             psz_string, psz_name );
726             free( psz_parser );
727         }
728         else
729         {
730             return;
731         }
732     }
733     else
734     {
735         if( psz_parser )
736         {
737             memmove( psz_parser, psz_parser + strlen(psz_name) +
738                             (*(psz_parser + strlen(psz_name)) == ':' ? 1 : 0 ),
739                             strlen(psz_parser + strlen(psz_name)) + 1 );
740
741             /* Remove trailing : : */
742             if( *(psz_string+strlen(psz_string ) -1 ) == ':' )
743             {
744                 *(psz_string+strlen(psz_string ) -1 ) = '\0';
745             }
746          }
747          else
748          {
749              free( psz_string );
750              return;
751          }
752     }
753     /* Vout is not kept, so put that in the config */
754     config_PutPsz( p_intf, "video-filter", psz_string );
755
756     /* Try to set on the fly */
757     p_vout = (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
758                                               FIND_ANYWHERE );
759     if( p_vout )
760     {
761         var_SetString( p_vout, "video-filter", psz_string );
762         vlc_object_release( p_vout );
763     }
764
765     free( psz_string );
766
767     o_config_changed = YES;
768 }
769
770 - (void)changeAFiltersString: (char *)psz_name onOrOff: (vlc_bool_t )b_add;
771 {
772     /* copied from ../wxwidgets/extrapanel.cpp
773      * renamed to conform with Cocoa's rules */
774
775     char *psz_parser, *psz_string;
776     intf_thread_t * p_intf = VLCIntf;
777     aout_instance_t * p_aout= (aout_instance_t *)vlc_object_find(p_intf,
778                                  VLC_OBJECT_AOUT, FIND_ANYWHERE);
779
780     if( p_aout )
781     {
782         psz_string = var_GetString( p_aout, "audio-filter" );
783     }
784     else
785     {
786         psz_string = config_GetPsz( p_intf, "audio-filter" );
787     }
788
789     if( !psz_string ) psz_string = strdup("");
790
791     psz_parser = strstr( psz_string, psz_name );
792
793     if( b_add )
794     {
795         if( !psz_parser )
796         {
797             psz_parser = psz_string;
798             asprintf( &psz_string, (*psz_string) ? "%s:%s" : "%s%s",
799                             psz_string, psz_name );
800             free( psz_parser );
801         }
802         else
803         {
804             return;
805         }
806     }
807     else
808     {
809         if( psz_parser )
810         {
811             memmove( psz_parser, psz_parser + strlen(psz_name) +
812                             (*(psz_parser + strlen(psz_name)) == ':' ? 1 : 0 ),
813                             strlen(psz_parser + strlen(psz_name)) + 1 );
814
815             if( *(psz_string+strlen(psz_string ) -1 ) == ':' )
816             {
817                 *(psz_string+strlen(psz_string ) -1 ) = '\0';
818             }
819          }
820          else
821          {
822              free( psz_string );
823              return;
824          }
825     }
826
827     if( p_aout == NULL )
828     {
829         config_PutPsz( p_intf, "audio-filter", psz_string );
830     }
831     else
832     {
833         var_SetString( p_aout, "audio-filter", psz_string );
834         int i = 0;
835         while( i < p_aout->i_nb_inputs )
836         {
837             p_aout->pp_inputs[i]->b_restart = VLC_TRUE;
838             i = (i + 1);
839         }
840         vlc_object_release( p_aout );
841     }
842     free( psz_string );
843
844     o_config_changed = YES;
845 }
846
847 - (void)savePrefs
848 {    
849     /* save the preferences to make sure that our module-changes will up on
850      * next launch again */
851     playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
852         FIND_ANYWHERE );
853     int returnedValue;
854     NSArray * theModules;
855     theModules = [[NSArray alloc] initWithObjects: @"main", @"headphone",
856         @"transform", @"adjust", @"invert", @"motionblur", @"distort",
857         @"clone", @"crop", @"normvol", @"headphone_channel_mixer", @"macosx",
858         nil];
859     unsigned int x = 0;
860     
861     while ( x != [theModules count] )
862     {
863         returnedValue = config_SaveConfigFile( p_playlist, [[theModules
864             objectAtIndex: x] UTF8String] );
865
866         if (returnedValue != 0)
867         {
868             msg_Err(p_playlist, "unable to save the preferences of the "
869             "extended control attribute '%s' (%i)", 
870             [[theModules objectAtIndex: x] UTF8String] , returnedValue);
871             [theModules release];
872             vlc_object_release( p_playlist );
873             
874             return;
875         }
876
877         x = ( x + 1 );
878     }
879     
880     msg_Dbg( p_playlist, "VLCExtended: saved certain preferences successfully" );
881     
882     [theModules release];
883     vlc_object_release( p_playlist );
884 }
885 @end