* First string review of the OSX interface
[vlc.git] / modules / gui / macosx / extended.m
1 /*****************************************************************************
2  * extended.m: MacOS X Extended interface panel
3  *****************************************************************************
4  * Copyright (C) 2005 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("Adjust Image")];
85     [o_btn_vidFlts_mrInfo setTitle: _NS("More Info")];
86     [o_ckb_blur setTitle: _NS("Blurring")];
87     [o_ckb_blur setToolTip: _NS("Creates a motion blurring on the image")];
88     [o_ckb_distortion setTitle: _NS("Distortion")];
89     [o_ckb_distortion setToolTip: _NS("Adds distorsion effects")];
90     [o_ckb_imgClone setTitle: _NS("Image clone")];
91     [o_ckb_imgClone setToolTip: _NS("Creates several copies of the Video " \
92                                     "output window" )];
93     [o_ckb_imgCrop setTitle: _NS("Image cropping")];
94     [o_ckb_imgCrop setToolTip: _NS("Crops a defined part of the image")];
95     [o_ckb_imgInvers setTitle: _NS("Image inversion")];
96     [o_ckb_imgInvers setToolTip: _NS("Inverts the image colors")];
97     [o_ckb_trnsform setTitle: _NS("Transformation")];
98     [o_ckb_trnsform setToolTip: _NS("Rotates or flips the image")];
99     [o_ckb_vlme_norm setTitle: _NS("Volume normalization")];
100     [o_ckb_vlme_norm setToolTip: _NS("This filters prevents the audio output " \
101         "level from exceeding a defined value.")];
102     [o_ckb_hdphnVirt setTitle: _NS("Headphone virtualization")];
103     [o_ckb_hdphnVirt setToolTip: _NS("This filter gives the feeling of a " \
104         "5.1 speaker set when using a headphone.")];
105     [o_lbl_maxLevel setStringValue: _NS("Maximum level")];
106     [o_btn_rstrDefaults setTitle: _NS("Restore Defaults")];
107     [o_ckb_enblAdjustImg setTitle: _NS("Enable")];
108     [o_lbl_brightness setStringValue: _NS("Brightness")];
109     [o_lbl_contrast setStringValue: _NS("Contrast")];
110     [o_lbl_gamma setStringValue: _NS("Gamma")];
111     [o_lbl_hue setStringValue: _NS("Hue")];
112     [o_lbl_saturation setStringValue: _NS("Saturation")];
113     [o_lbl_opaque setStringValue: _NS("Opaqueness")];
114     
115 }
116
117 - (void)awakeFromNib
118 {
119     /* set the adjust-filter-sliders to the values from the prefs and enable
120      * them, if wanted */
121     char * psz_vfilters;
122     intf_thread_t * p_intf = VLCIntf;
123     psz_vfilters = config_GetPsz( p_intf, "vout-filter" );
124     if( psz_vfilters && strstr( psz_vfilters, "adjust" ) )
125     {
126         [o_ckb_enblAdjustImg setState: NSOnState];
127         [o_btn_rstrDefaults setEnabled: YES];
128         [o_sld_brightness setEnabled: YES];
129         [o_sld_contrast setEnabled: YES];
130         [o_sld_gamma setEnabled: YES];
131         [o_sld_hue setEnabled: YES];
132         [o_sld_saturation setEnabled: YES];
133     }
134     else
135     {
136         [o_ckb_enblAdjustImg setState: NSOffState];
137         [o_btn_rstrDefaults setEnabled: NO];
138         [o_sld_brightness setEnabled: NO];
139         [o_sld_contrast setEnabled: NO];
140         [o_sld_gamma setEnabled: NO];
141         [o_sld_hue setEnabled: NO];
142         [o_sld_saturation setEnabled: NO];
143     }
144     
145     /* set the other video-filter-checkboxes to the correct values */
146     if( psz_vfilters )
147     {
148         [o_ckb_blur setState: (int)strstr( psz_vfilters, "motionblur")];
149         [o_ckb_distortion setState: (int)strstr( psz_vfilters, "distort")];
150         [o_ckb_imgClone setState: (int)strstr( psz_vfilters, "clone")];
151         [o_ckb_imgCrop setState: (int)strstr( psz_vfilters, "crop")];
152         [o_ckb_imgInvers setState: (int)strstr( psz_vfilters, "invert")];
153         [o_ckb_trnsform setState: (int)strstr( psz_vfilters, "transform")];
154         
155         free( psz_vfilters );
156     }
157     
158     /* set the audio-filter-checkboxes to the values taken from the prefs */
159     char * psz_afilters;
160     psz_afilters = config_GetPsz( p_intf, "audio-filter" );
161     if( psz_afilters )
162     {
163         [o_ckb_hdphnVirt setState: (int)strstr( psz_afilters, "headphone" ) ];
164         [o_ckb_vlme_norm setState: (int)strstr( psz_afilters, "normvol" ) ];
165         
166         free( psz_afilters );
167     }
168 }
169
170 - (void)collapsAll
171 {
172     /* collaps all views so Cocoa saves the window position correctly */
173     if( o_adjImg_expanded )
174     {
175         [self extWin_exp_adjImg: nil];
176     }
177     if( o_audFlts_expanded )
178     {
179         [self extWin_exp_audFlts: nil];
180     }
181     if( o_vidFlts_expanded )
182     {
183         [self extWin_exp_vidFlts: nil];
184     }
185 }
186
187 - (BOOL)getConfigChanged
188 {
189     return o_config_changed;
190 }
191
192 - (void)showPanel
193 {
194     /* get the correct slider values from the prefs, in case they were changed
195      * elsewhere */
196     intf_thread_t * p_intf = VLCIntf;
197
198     int i_value = config_GetInt( p_intf, "hue" );
199     if( i_value > 0 && i_value < 360 )
200     {
201         [o_sld_hue setIntValue: i_value];
202     }
203
204     float f_value;
205     
206     f_value = config_GetFloat( p_intf, "saturation" );
207     if( f_value > 0 && f_value < 5 )
208     {
209         [o_sld_saturation setIntValue: (int)(100 * f_value) ];
210     }
211
212     f_value = config_GetFloat( p_intf, "contrast" );
213     if( f_value > 0 && f_value < 4 )
214     {
215         [o_sld_contrast setIntValue: (int)(100 * f_value) ];
216     }
217
218     f_value = config_GetFloat( p_intf, "brightness" );
219     if( f_value > 0 && f_value < 2 )
220     {
221         [o_sld_brightness setIntValue: (int)(100 * f_value) ];
222     }
223
224     f_value = config_GetFloat( p_intf, "gamma" );
225     if( f_value > 0 && f_value < 10 )
226     {
227         [o_sld_gamma setIntValue: (int)(10 * f_value) ];
228     }
229
230     f_value = config_GetFloat( p_intf, "norm-max-level" );
231     if( f_value > 0 && f_value < 10 )
232     {
233         [o_sld_maxLevel setFloatValue: f_value ];
234     }
235
236     [o_sld_opaque setFloatValue: (config_GetFloat( p_intf, \
237         "macosx-opaqueness") * 100)];
238
239
240     /* show the window */
241     [o_extended_window displayIfNeeded];
242     [o_extended_window makeKeyAndOrderFront:nil];
243 }
244
245 - (IBAction)adjImg_Enbl:(id)sender
246 {
247     /* en-/disable the sliders */
248     if ([o_ckb_enblAdjustImg state] == NSOnState)
249     {
250         [o_btn_rstrDefaults setEnabled: YES];
251         [o_sld_brightness setEnabled: YES];
252         [o_sld_contrast setEnabled: YES];
253         [o_sld_gamma setEnabled: YES];
254         [o_sld_hue setEnabled: YES];
255         [o_sld_saturation setEnabled: YES];
256         [self changeVFiltersString: "adjust" onOrOff: VLC_TRUE];
257     }else{
258         [o_btn_rstrDefaults setEnabled: NO];
259         [o_sld_brightness setEnabled: NO];
260         [o_sld_contrast setEnabled: NO];
261         [o_sld_gamma setEnabled: NO];
262         [o_sld_hue setEnabled: NO];
263         [o_sld_saturation setEnabled: NO];
264         [self changeVFiltersString: "adjust" onOrOff: VLC_FALSE];
265     }
266 }
267
268 - (IBAction)adjImg_rstrDefaults:(id)sender
269 {
270     /* reset the sliders */
271     [o_sld_brightness setIntValue: 100];
272     [o_sld_contrast setIntValue: 100];
273     [o_sld_gamma setIntValue: 10];
274     [o_sld_hue setIntValue: 0];
275     [o_sld_saturation setIntValue: 100];
276     
277     /* transmit the values */
278     [self adjImg_sliders: o_sld_brightness];
279     [self adjImg_sliders: o_sld_contrast];
280     [self adjImg_sliders: o_sld_gamma];
281     [self adjImg_sliders: o_sld_hue];
282     [self adjImg_sliders: o_sld_saturation];
283 }
284
285 - (IBAction)adjImg_sliders:(id)sender
286 {
287     /* read-out the sliders' values and apply them */
288     intf_thread_t * p_intf = VLCIntf;
289     vout_thread_t *p_vout = (vout_thread_t *)vlc_object_find(p_intf,
290                                  VLC_OBJECT_VOUT, FIND_ANYWHERE);
291     if( p_vout == NULL )
292     {
293         if (sender == o_sld_brightness)
294         {
295             config_PutFloat( p_intf , "brightness" , [o_sld_brightness floatValue] / 100);
296         } else if (sender == o_sld_contrast)
297         {
298             config_PutFloat( p_intf , "contrast" , [o_sld_contrast floatValue] / 100);
299         } else if (sender == o_sld_gamma)
300         {
301             config_PutFloat( p_intf , "gamma" , [o_sld_gamma floatValue] / 10);
302         } else if (sender == o_sld_hue)
303         {
304             config_PutInt( p_intf , "hue" , [o_sld_hue intValue]);
305         } else if (sender == o_sld_saturation)
306         {
307             config_PutFloat( p_intf , "saturation" , [o_sld_saturation floatValue] / 100);
308         } else {
309             msg_Warn( p_intf, "the corresponding subfilter coundn't be found" );
310         }
311     } else {
312         vlc_value_t val;
313         if (sender == o_sld_brightness)
314         {
315             val.f_float = [o_sld_brightness floatValue] / 100;
316             var_Set( p_vout, "brightness", val );
317             config_PutFloat( p_intf , "brightness" , [o_sld_brightness floatValue] / 100);
318         } else if (sender == o_sld_contrast)
319         {
320             val.f_float = [o_sld_contrast floatValue] / 100;
321             var_Set( p_vout, "contrast", val );
322             config_PutFloat( p_intf , "contrast" , [o_sld_contrast floatValue] / 100);
323         } else if (sender == o_sld_gamma)
324         {
325             val.f_float = [o_sld_gamma floatValue] / 10;
326             var_Set( p_vout, "gamma", val );
327             config_PutFloat( p_intf , "gamma" , [o_sld_gamma floatValue] / 10);
328         } else if (sender == o_sld_hue)
329         {
330             val.i_int = [o_sld_hue intValue];
331             var_Set( p_vout, "hue", val );
332             config_PutInt( p_intf , "hue" , [o_sld_hue intValue]);
333         } else if (sender == o_sld_saturation)
334         {
335             val.f_float = [o_sld_saturation floatValue] / 100;
336             var_Set( p_vout, "saturation", val );
337             config_PutFloat( p_intf , "saturation" , [o_sld_saturation floatValue] / 100);
338         } else {
339             msg_Warn( p_intf, "the corresponding subfilter coundn't be found" );
340         }
341         vlc_object_release( p_vout );
342     }
343
344     o_config_changed = YES;
345 }
346
347 /* change the opaqueness of the vouts */
348 - (IBAction)adjImg_opaque:(id)sender
349 {
350     vlc_value_t val;
351     id o_window = [NSApp keyWindow];
352     NSArray *o_windows = [NSApp orderedWindows];
353     NSEnumerator *o_enumerator = [o_windows objectEnumerator];
354     playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST, \
355         FIND_ANYWHERE );
356     vout_thread_t *p_vout = vlc_object_find( VLCIntf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
357     vout_thread_t *p_real_vout;
358
359     val.f_float = [o_sld_opaque floatValue] / 100;
360
361
362     if( p_vout != NULL )
363     {
364         p_real_vout = [VLCVoutView getRealVout: p_vout];
365         var_Set( p_real_vout, "macosx-opaqueness", val );
366
367         while ((o_window = [o_enumerator nextObject]))
368         {
369             if( [[o_window className] isEqualToString: @"VLCWindow"] ||
370                 [[[VLCMain sharedInstance] getEmbeddedList]
371                                     windowContainsEmbedded: o_window])
372             {
373                 [o_window setAlphaValue: val.f_float];
374             }
375             break;
376         }
377         vlc_object_release( p_vout );
378     }
379     
380     /* store to prefs */
381     config_PutFloat( p_playlist , "macosx-opaqueness" , val.f_float );
382     
383     vlc_object_release( p_playlist );
384
385     o_config_changed = YES;
386 }
387
388 - (IBAction)audFtls_hdphnVirt:(id)sender
389 {
390     /* en-/disable headphone virtualisation */
391     if ([o_ckb_hdphnVirt state] == NSOnState)
392     {
393         [self changeAFiltersString: "headphone_channel_mixer" onOrOff: VLC_TRUE ];
394     }else{
395         [self changeAFiltersString: "headphone_channel_mixer" onOrOff: VLC_FALSE ];
396     }
397 }
398
399 - (IBAction)audFtls_maxLevelSld:(id)sender
400 {
401     /* read-out the slider's value and apply it */
402     intf_thread_t * p_intf = VLCIntf;
403     aout_instance_t * p_aout= (aout_instance_t *)vlc_object_find(p_intf,
404                                  VLC_OBJECT_AOUT, FIND_ANYWHERE);
405     if( p_aout != NULL )
406     {
407         var_SetFloat( p_aout, "norm-max-level", [o_sld_maxLevel floatValue] );
408         vlc_object_release( p_aout );
409     }
410     config_PutFloat( p_intf, "norm-max-level", [o_sld_maxLevel floatValue] );
411
412     o_config_changed = YES;
413 }
414
415 - (IBAction)audFtls_vlmeNorm:(id)sender
416 {
417     /* en-/disable volume normalisation */
418     if ([o_ckb_vlme_norm state] == NSOnState)
419     {
420         [self changeAFiltersString: "normvol" onOrOff: YES ];
421     }else{
422         [self changeAFiltersString: "normvol" onOrOff: NO ];
423     }
424 }
425
426 - (IBAction)extWin_exp_adjImg:(id)sender
427 {
428     /* expand or collapse adjImg */
429     NSRect o_win_rect = [o_extended_window frame];
430     NSRect o_box_audFlts_rect = [o_box_audFlts frame];
431     NSRect o_box_vidFlts_rect = [o_box_vidFlts frame];
432     NSRect o_box_adjImg_rect = [o_box_adjImg frame];
433     
434     if (o_adjImg_expanded)
435     {
436         /* move the window contents upwards (partially done through settings
437          * inside the nib) and resize the window */
438         o_win_rect.size.height = o_win_rect.size.height - 171;
439         o_win_rect.origin.y = [o_extended_window frame].origin.y + 171;
440         o_box_audFlts_rect.origin.y = o_box_audFlts_rect.origin.y + 171;
441         o_box_vidFlts_rect.origin.y = o_box_vidFlts_rect.origin.y + 171;
442         
443         /* remove the inserted view */
444         [o_adjustImg_view removeFromSuperviewWithoutNeedingDisplay];
445     }else{
446     
447         /* move the window contents downwards and resize the window */
448         o_win_rect.size.height = o_win_rect.size.height + 171;
449         o_win_rect.origin.y = [o_extended_window frame].origin.y - 171;
450         o_box_audFlts_rect.origin.y = o_box_audFlts_rect.origin.y - 171;
451         o_box_vidFlts_rect.origin.y = o_box_vidFlts_rect.origin.y - 171;
452     }
453     
454     [o_box_audFlts setFrameFromContentFrame: o_box_audFlts_rect];
455     [o_box_vidFlts setFrameFromContentFrame: o_box_vidFlts_rect];
456     [o_extended_window displayIfNeeded];
457     [o_extended_window setFrame: o_win_rect display:YES animate: YES];
458     
459     if (o_adjImg_expanded)
460     {
461         o_box_adjImg_rect.size.height = [o_box_adjImg frame].size.height - 171;
462         msg_Dbg( VLCIntf, "collapsed adjust-image section");
463         o_adjImg_expanded = NO;
464     } else {
465         /* insert view */
466         o_box_adjImg_rect.size.height = [o_box_adjImg frame].size.height + 171;
467         [o_adjustImg_view setFrame: NSMakeRect( 20, -10, 370, 181)];
468         [o_adjustImg_view setNeedsDisplay:YES];
469         [o_adjustImg_view setAutoresizesSubviews: YES];
470         [[o_box_adjImg contentView] addSubview: o_adjustImg_view];
471         msg_Dbg( VLCIntf, "expanded adjust-image section");
472         o_adjImg_expanded = YES;
473     }
474     [o_box_adjImg setFrameFromContentFrame: o_box_adjImg_rect];
475 }
476
477 - (IBAction)extWin_exp_audFlts:(id)sender
478 {
479     /* expand or collapse audFlts */
480     NSRect o_win_rect = [o_extended_window frame];
481     NSRect o_box_audFlts_rect = [o_box_audFlts frame];
482     
483     if (o_audFlts_expanded)
484     {
485         /* move the window contents upwards (partially done through settings
486          * inside the nib) and resize the window */
487         o_win_rect.size.height = o_win_rect.size.height - 66;
488         o_win_rect.origin.y = [o_extended_window frame].origin.y + 66;
489         
490         /* remove the inserted view */
491         [o_audioFlts_view removeFromSuperviewWithoutNeedingDisplay];
492     }else{
493         /* move the window contents downwards and resize the window */
494         o_win_rect.size.height = o_win_rect.size.height + 66;
495         o_win_rect.origin.y = [o_extended_window frame].origin.y - 66;
496     }
497     [o_extended_window displayIfNeeded];
498     [o_extended_window setFrame: o_win_rect display:YES animate: YES];
499     
500     
501     if (o_audFlts_expanded)
502     {
503         o_box_audFlts_rect.size.height = [o_box_audFlts frame].size.height - 66;
504         msg_Dbg( VLCIntf, "collapsed audio-filters section");
505         o_audFlts_expanded = NO;
506     } else {
507         /* insert view */
508         o_box_audFlts_rect.size.height = [o_box_audFlts frame].size.height + 66;
509         [o_audioFlts_view setFrame: NSMakeRect( 20, -20, 370, 76)];
510         [o_audioFlts_view setNeedsDisplay:YES];
511         [o_audioFlts_view setAutoresizesSubviews: YES];
512         [[o_box_audFlts contentView] addSubview: o_audioFlts_view];
513         msg_Dbg( VLCIntf, "expanded audio-filters section");
514         o_audFlts_expanded = YES;
515     }
516     [o_box_audFlts setFrameFromContentFrame: o_box_audFlts_rect];
517 }
518
519 - (IBAction)extWin_exp_vidFlts:(id)sender
520 {
521     /* expand or collapse vidFlts */
522     NSRect o_win_rect = [o_extended_window frame];
523     NSRect o_box_audFlts_rect = [o_box_audFlts frame];
524     NSRect o_box_vidFlts_rect = [o_box_vidFlts frame];
525     
526     if (o_vidFlts_expanded)
527     {
528         /* move the window contents upwards (partially done through settings
529          * inside the nib) and resize the window */
530         o_win_rect.size.height = o_win_rect.size.height - 134;
531         o_win_rect.origin.y = [o_extended_window frame].origin.y + 134;
532         o_box_audFlts_rect.origin.y = o_box_audFlts_rect.origin.y + 134;
533         
534         /* remove the inserted view */
535         [o_videoFilters_view removeFromSuperviewWithoutNeedingDisplay];
536     }else{
537     
538         /* move the window contents downwards and resize the window */
539         o_win_rect.size.height = o_win_rect.size.height + 134;
540         o_win_rect.origin.y = [o_extended_window frame].origin.y - 134;
541         o_box_audFlts_rect.origin.y = o_box_audFlts_rect.origin.y - 134;
542     }
543     
544     [o_box_audFlts setFrameFromContentFrame: o_box_audFlts_rect];
545     [o_extended_window displayIfNeeded];
546     [o_extended_window setFrame: o_win_rect display:YES animate: YES];
547     
548     if (o_vidFlts_expanded)
549     {
550         o_box_vidFlts_rect.size.height = [o_box_vidFlts frame].size.height - 134;
551         msg_Dbg( VLCIntf, "collapsed video-filters section");
552         o_vidFlts_expanded = NO;
553     } else {
554         /* insert view */
555         o_box_vidFlts_rect.size.height = [o_box_vidFlts frame].size.height + 134;
556         [o_videoFilters_view setFrame: NSMakeRect( 20, -10, 370, 144)];
557         [o_videoFilters_view setNeedsDisplay:YES];
558         [o_videoFilters_view setAutoresizesSubviews: YES];
559         [[o_box_vidFlts contentView] addSubview: o_videoFilters_view];
560         msg_Dbg( VLCIntf, "expanded video-filters section");
561         o_vidFlts_expanded = YES;
562     }
563     [o_box_vidFlts setFrameFromContentFrame: o_box_vidFlts_rect];
564 }
565
566 - (IBAction)vidFlts:(id)sender
567 {
568     /* en-/disable video filters */
569     if (sender == o_ckb_blur)
570     {
571         [self changeVFiltersString: "motionblur" onOrOff: [o_ckb_blur state]];
572     }
573     else if (sender == o_ckb_distortion)
574     {
575         [self changeVFiltersString: "distort" onOrOff: [o_ckb_distortion state]];
576     }
577     else if (sender == o_ckb_imgClone)
578     {
579         [self changeVFiltersString: "clone" onOrOff: [o_ckb_imgClone state]];
580     }
581     else if (sender == o_ckb_imgCrop)
582     {
583         [self changeVFiltersString: "crop" onOrOff: [o_ckb_imgCrop state]];
584     }
585     else if (sender == o_ckb_imgInvers)
586     {
587         [self changeVFiltersString: "invert" onOrOff: [o_ckb_imgInvers state]];
588     }
589     else if (sender == o_ckb_trnsform)
590     {
591         [self changeVFiltersString: "transform" onOrOff: [o_ckb_trnsform state]];
592     } else {
593         /* this shouldn't happen */
594         msg_Warn (VLCIntf, "cannot find selected video-filter");
595     }
596 }
597
598 - (IBAction)vidFlts_mrInfo:(id)sender
599 {
600     /* show info sheet */
601     NSBeginInformationalAlertSheet(_NS("More information"), _NS("OK"), @"", @"", \
602         o_extended_window, nil, nil, nil, nil, _NS("This panel allows to " \
603         "select video effects filters to apply.\n" \
604         "The filters can be configured indivudually in the Preferences, in " \
605         "the subsections of Video/Filters\n." \
606         "To choose the order in which the filter are applied, a filter " \
607         "option string can be set in the Preferences, Video / Filters section."));
608 }
609
610
611 /*****************************************************************************
612  * methods to communicate changes to VLC's core
613  *****************************************************************************/
614
615 - (void)changeVFiltersString:(char *)psz_name onOrOff:(vlc_bool_t )b_add 
616 {
617     /* copied from ../wxwidgets/extrapanel.cpp
618      * renamed to conform with Cocoa's rules */
619      
620     vout_thread_t *p_vout;
621     intf_thread_t * p_intf = VLCIntf;
622     
623     char *psz_parser, *psz_string;
624     psz_string = config_GetPsz( p_intf, "vout-filter" );
625     
626     if( !psz_string ) psz_string = strdup("");
627
628     psz_parser = strstr( psz_string, psz_name );
629
630     if( b_add )
631     {
632         if( !psz_parser )
633         {
634             psz_parser = psz_string;
635             asprintf( &psz_string, (*psz_string) ? "%s:%s" : "%s%s",
636                             psz_string, psz_name );
637             free( psz_parser );
638         }
639         else
640         {
641             return;
642         }
643     }
644     else
645     {
646         if( psz_parser )
647         {
648             memmove( psz_parser, psz_parser + strlen(psz_name) +
649                             (*(psz_parser + strlen(psz_name)) == ':' ? 1 : 0 ),
650                             strlen(psz_parser + strlen(psz_name)) + 1 );
651
652             /* Remove trailing : : */
653             if( *(psz_string+strlen(psz_string ) -1 ) == ':' )
654             {
655                 *(psz_string+strlen(psz_string ) -1 ) = '\0';
656             }
657          }
658          else
659          {
660              free( psz_string );
661              return;
662          }
663     }
664     /* Vout is not kept, so put that in the config */
665     config_PutPsz( p_intf, "vout-filter", psz_string );
666
667     /* Try to set on the fly */
668     p_vout = (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
669                                               FIND_ANYWHERE );
670     if( p_vout )
671     {
672         var_SetString( p_vout, "vout-filter", psz_string );
673         vlc_object_release( p_vout );
674     }
675
676     free( psz_string );
677
678     o_config_changed = YES;
679 }
680
681
682 - (void)changeAFiltersString: (char *)psz_name onOrOff: (vlc_bool_t )b_add;
683 {
684     /* copied from ../wxwidgets/extrapanel.cpp
685      * renamed to conform with Cocoa's rules */
686
687     char *psz_parser, *psz_string;
688     intf_thread_t * p_intf = VLCIntf;
689     aout_instance_t * p_aout= (aout_instance_t *)vlc_object_find(p_intf,
690                                  VLC_OBJECT_AOUT, FIND_ANYWHERE);
691
692     if( p_aout )
693     {
694         psz_string = var_GetString( p_aout, "audio-filter" );
695     }
696     else
697     {
698         psz_string = config_GetPsz( p_intf, "audio-filter" );
699     }
700
701     if( !psz_string ) psz_string = strdup("");
702
703     psz_parser = strstr( psz_string, psz_name );
704
705     if( b_add )
706     {
707         if( !psz_parser )
708         {
709             psz_parser = psz_string;
710             asprintf( &psz_string, (*psz_string) ? "%s:%s" : "%s%s",
711                             psz_string, psz_name );
712             free( psz_parser );
713         }
714         else
715         {
716             return;
717         }
718     }
719     else
720     {
721         if( psz_parser )
722         {
723             memmove( psz_parser, psz_parser + strlen(psz_name) +
724                             (*(psz_parser + strlen(psz_name)) == ':' ? 1 : 0 ),
725                             strlen(psz_parser + strlen(psz_name)) + 1 );
726
727             if( *(psz_string+strlen(psz_string ) -1 ) == ':' )
728             {
729                 *(psz_string+strlen(psz_string ) -1 ) = '\0';
730             }
731          }
732          else
733          {
734              free( psz_string );
735              return;
736          }
737     }
738
739     if( p_aout == NULL )
740     {
741         config_PutPsz( p_intf, "audio-filter", psz_string );
742     }
743     else
744     {
745         var_SetString( p_aout, "audio-filter", psz_string );
746         int i = 0;
747         while( i < p_aout->i_nb_inputs )
748         {
749             p_aout->pp_inputs[i]->b_restart = VLC_TRUE;
750             i = (i + 1);
751         }
752         vlc_object_release( p_aout );
753     }
754     free( psz_string );
755
756     o_config_changed = YES;
757 }
758
759 - (void)savePrefs
760 {    
761     /* save the preferences to make sure that our module-changes will up on
762      * next launch again */
763     playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST, \
764         FIND_ANYWHERE );
765     int returnedValue;
766     NSArray * theModules;
767     theModules = [[NSArray alloc] initWithObjects: @"main", @"headphone", \
768         @"transform", @"adjust", @"invert", @"motionblur", @"distort", \
769         @"clone", @"crop", @"normvol", @"headphone_channel_mixer", @"macosx", \
770         nil];
771     unsigned int x = 0;
772     
773     while ( x != [theModules count] )
774     {
775         returnedValue = config_SaveConfigFile( p_playlist, [[theModules \
776             objectAtIndex: x] UTF8String] );
777
778         if (returnedValue != 0)
779         {
780             msg_Err(p_playlist, "Unable to save the preferences of the " \
781             "extended control attribute '%s' (%i)", 
782             [[theModules objectAtIndex: x] UTF8String] , returnedValue);
783             [theModules release];
784             vlc_object_release( p_playlist );
785             
786             return;
787         }
788
789         x = ( x + 1 );
790     }
791     
792     msg_Dbg( p_playlist, "VLCExtended: saved certain preferences successfully" );
793     
794     [theModules release];
795     vlc_object_release( p_playlist );
796 }
797 @end