]> git.sesse.net Git - vlc/blob - modules/gui/macosx/sfilters.m
Mac OS X gui: Fix logo appearance.
[vlc] / modules / gui / macosx / sfilters.m
1 /*****************************************************************************
2  * sfilter.m: MacOS X Subpicture filters dialogue
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 core is partially based upon the 
28  * RC-interface, written by Antoine Cellerier and Mark F. Moriarty  
29  * (members of the VideoLAN team) 
30  *****************************************************************************/
31
32 #import "sfilters.h"
33 #import "intf.h"
34 #import <vlc_vout.h>
35
36 /* TODO:
37     - check for memory leaks
38     - save the preferences, if requested
39 */
40
41 @implementation VLCsFilters
42
43 static VLCsFilters *_o_sharedInstance = nil;
44
45 + (VLCsFilters *)sharedInstance
46 {
47     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
48 }
49
50 - (id)init
51 {
52     if (_o_sharedInstance) {
53         [self dealloc];
54     } else {
55         _o_sharedInstance = [super init];
56     }
57
58     return _o_sharedInstance;
59 }
60
61 - (void)dealloc
62 {
63     [o_colors release];
64
65     [super dealloc];
66 }
67
68 - (void)initStrings
69 {
70     [o_sfilter_win setTitle: _NS("Subpicture Filters")];
71     [[o_sfilter_tabView tabViewItemAtIndex: 0] setLabel: _NS("Logo")];
72     [[o_sfilter_tabView tabViewItemAtIndex: 1] setLabel: _NS("Time")];
73     [[o_sfilter_tabView tabViewItemAtIndex: 2] setLabel: _NS("Marquee")];
74     [o_sfilter_saveSettings_ckb setTitle: _NS("Save settings")];
75     [o_logo_image_btn setTitle: _NS("Browse...")];
76     [o_logo_enabled_ckb setTitle: _NS("Enabled")];
77     [o_logo_image_lbl setStringValue: _NS("Image:")];
78     [o_logo_pos_lbl setStringValue: _NS("Position:")];
79     [o_logo_opaque_lbl setStringValue: _NS("Opaqueness")];
80     [o_time_enabled_ckb setTitle: _NS("Enabled")];
81     [o_time_stamp_lbl setStringValue: _NS("Timestamp:")];
82     [o_time_size_lbl setStringValue: _NS("Size:")];
83     [o_time_color_lbl setStringValue: _NS("Color:")];
84     [o_time_opaque_lbl setStringValue: _NS("Opaqueness:")];
85     [o_time_pos_lbl setStringValue: _NS("Position:")];
86     [o_time_size_inPx_lbl setStringValue: _NS("(in pixels)")];
87     [o_marq_enabled_ckb setTitle: _NS("Enabled")];
88     [o_marq_color_lbl setStringValue: _NS("Color:")];
89     [o_marq_marq_lbl setStringValue: _NS("Marquee:")];
90     [o_marq_opaque_lbl setStringValue: _NS("Opaqueness")];
91     [o_marq_tmOut_lbl setStringValue: _NS("Timeout:")];
92     [o_marq_tmOut_ms_lbl setStringValue: _NS("ms")];
93     [o_marq_pos_lbl setStringValue: _NS("Position:")];
94     [o_marq_size_lbl setStringValue: _NS("Size:")];
95     [o_time_color_lbl setStringValue: _NS("(in pixels)")];
96 }
97
98 - (void)awakeFromNib
99 {
100     /* colors as implemented at the beginning of marq.c and time.c
101      * feel free to add more colors, but remember to add them to these files 
102      * as well to keep a certain level of consistency across the interfaces */
103     NSArray * o_default;
104     NSArray * o_black;
105     NSArray * o_gray;
106     NSArray * o_silver;
107     NSArray * o_white;
108     NSArray * o_maroon;
109     NSArray * o_red;
110     NSArray * o_fuchsia;
111     NSArray * o_yellow;
112     NSArray * o_olive;
113     NSArray * o_green;
114     NSArray * o_teal;
115     NSArray * o_lime;
116     NSArray * o_purple;
117     NSArray * o_navy;
118     NSArray * o_blue;
119     NSArray * o_aqua;
120     o_default = [NSArray arrayWithObjects: _NS("Default"), @"-1", nil];
121     o_black = [NSArray arrayWithObjects: _NS("Black"), @"0x000000", nil];
122     o_gray = [NSArray arrayWithObjects: _NS("Gray"), @"0x808080", nil];
123     o_silver = [NSArray arrayWithObjects: _NS("Silver"), @"0xC0C0C0", nil];
124     o_white = [NSArray arrayWithObjects: _NS("White"), @"0xFFFFFF", nil];
125     o_maroon = [NSArray arrayWithObjects: _NS("Maroon"), @"0x800000", nil];
126     o_red = [NSArray arrayWithObjects: _NS("Red"), @"0xFF0000", nil];
127     o_fuchsia = [NSArray arrayWithObjects: _NS("Fuchsia"), @"0xFF00FF", nil];
128     o_yellow = [NSArray arrayWithObjects: _NS("Yellow"), @"0xFFFF00", nil];
129     o_olive = [NSArray arrayWithObjects: _NS("Olive"), @"0x808000", nil];
130     o_green = [NSArray arrayWithObjects: _NS("Green"), @"0x008000", nil];
131     o_teal = [NSArray arrayWithObjects: _NS("Teal"), @"0x008080", nil];
132     o_lime = [NSArray arrayWithObjects: _NS("Lime"), @"0x00FF00", nil];
133     o_purple = [NSArray arrayWithObjects: _NS("Purple"), @"0x800080", nil];
134     o_navy = [NSArray arrayWithObjects: _NS("Navy"), @"0x000080", nil];
135     o_blue = [NSArray arrayWithObjects: _NS("Blue"), @"0x0000FF", nil];
136     o_aqua = [NSArray arrayWithObjects: _NS("Aqua"), @"0x00FFFF", nil];
137     o_colors = [[NSArray alloc] initWithObjects: o_default, o_black, o_gray,
138         o_silver, o_white, o_maroon, o_red, o_fuchsia, o_yellow, o_olive,
139         o_green, o_teal, o_lime, o_purple, o_navy, o_blue, o_aqua, nil];
140
141     unsigned int x = 0;
142     [o_marq_color_pop removeAllItems];
143     [o_time_color_pop removeAllItems];
144     
145     /* we are adding tags to the items, so we can easily identify them even if 
146      * the menu was sorted */
147     while (x != [o_colors count])
148     {
149         [o_marq_color_pop addItemWithTitle: [[o_colors objectAtIndex:x]
150             objectAtIndex:0]];
151         [[o_marq_color_pop lastItem] setTag: x];
152         
153         [o_time_color_pop addItemWithTitle: [[o_colors objectAtIndex:x]
154             objectAtIndex:0]];
155         [[o_time_color_pop lastItem] setTag: x];
156         
157         x = (x + 1);
158     }
159
160     [o_marq_color_pop selectItemAtIndex:0];
161     [o_time_color_pop selectItemAtIndex:0];
162
163     /* define the relative positions and copy them to the menues
164      * we can destroy the array afterwards, because we are saving the ints 
165      * as tags to the menu-items */
166     /*NSArray * o_cnt_cnt;
167     NSArray * o_lft_cnt;
168     NSArray * o_rht_cnt;
169     NSArray * o_cnt_top;
170     NSArray * o_lft_top;
171     NSArray * o_rht_top;
172     NSArray * o_cnt_btm;
173     NSArray * o_lft_btm;
174     NSArray * o_rht_btm;
175     NSArray * o_positions;
176     o_cnt_cnt = [NSArray arrayWithObjects: _NS("Center-Center"), @"0", nil];
177     o_lft_cnt = [NSArray arrayWithObjects: _NS("Left-Center"), @"1", nil];
178     o_rht_cnt = [NSArray arrayWithObjects: _NS("Right-Center"), @"2", nil];
179     o_cnt_top = [NSArray arrayWithObjects: _NS("Center-Top"), @"4", nil];
180     o_lft_top = [NSArray arrayWithObjects: _NS("Left-Top"), @"5", nil];
181     o_rht_top = [NSArray arrayWithObjects: _NS("Right-Top"), @"6", nil];
182     o_cnt_btm = [NSArray arrayWithObjects: _NS("Center-Bottom"), @"8", nil];
183     o_lft_btm = [NSArray arrayWithObjects: _NS("Left-Bottom"), @"9", nil];
184     o_rht_btm = [NSArray arrayWithObjects: _NS("Right-Bottom"), @"10", nil];
185     o_positions = [[NSArray alloc] initWithObjects: o_cnt_cnt, o_lft_cnt,
186         o_rht_cnt, o_cnt_top, o_lft_top, o_rht_top, o_cnt_btm, o_lft_btm,
187         o_rht_btm, nil];
188         
189     x = 0;
190     [o_time_pos_rel_pop removeAllItems];
191     [o_marq_pos_rel_pop removeAllItems];
192     [o_logo_pos_rel_pop removeAllItems];
193     
194     * we are adding a tag here, so we can easily select an item later on *
195     while ( x != [o_positions count] )
196     {
197         [o_time_pos_rel_pop addItemWithTitle: [[o_positions objectAtIndex:x]
198             objectAtIndex:0]];
199         [[o_time_pos_rel_pop lastItem] setTag: [[[o_positions objectAtIndex:x]
200             objectAtIndex:1] intValue]];
201         [o_marq_pos_rel_pop addItemWithTitle: [[o_positions objectAtIndex:x]
202             objectAtIndex:0]];
203         [[o_marq_pos_rel_pop lastItem] setTag: [[[o_positions objectAtIndex:x]
204             objectAtIndex:1] intValue]];
205         [o_logo_pos_rel_pop addItemWithTitle: [[o_positions objectAtIndex:x]
206             objectAtIndex:0]];
207         [[o_logo_pos_rel_pop lastItem] setTag: [[[o_positions objectAtIndex:x]
208             objectAtIndex:1] intValue]];
209
210         x = (x + 1);
211     }
212     [o_positions release];*/
213
214     NSArray * o_sizes;
215     o_sizes = [[NSArray alloc] initWithObjects: @"6", @"8", @"10", @"11", @"12",\
216         @"14", @"13", @"16", @"18", @"24", @"36", @"48", @"64", @"72", @"96",
217         @"144", @"288", nil];
218     [o_marq_size_pop removeAllItems];
219     [o_marq_size_pop addItemsWithTitles: o_sizes];
220     [o_time_size_pop removeAllItems];
221     [o_time_size_pop addItemsWithTitles: o_sizes];
222     [o_sizes release];
223 }
224
225 - (void)showAsPanel
226 {
227         char * psz_temp;
228
229     /* called from intf.m */
230     [o_sfilter_win displayIfNeeded];
231     [o_sfilter_win makeKeyAndOrderFront:nil];
232
233     intf_thread_t * p_intf = VLCIntf;
234
235     /* retrieve the marquee settings */
236     int x = 0;
237     int tempInt = config_GetInt( p_intf, "marq-color" );
238     while( strtol([[[o_colors objectAtIndex:x] objectAtIndex:1] UTF8String],
239         NULL, 0) != tempInt )
240     {
241         x = (x + 1);
242         
243         if( x >= [o_marq_color_pop numberOfItems] )
244         {
245             x = 0;
246             return;
247         }
248     }
249     [o_marq_color_pop selectItemAtIndex: x];
250         if( psz_temp = config_GetPsz( p_intf, "time-format" ) )
251                 [o_marq_marq_fld setStringValue: [NSString stringWithUTF8String: psz_temp]];
252         else
253                 [o_marq_marq_fld setStringValue: _NS(@"Not Available")];
254         
255         [o_marq_opaque_sld setIntValue: config_GetInt( p_intf, "marq-opacity")];
256     [o_marq_pos_radio selectCellWithTag: config_GetInt( p_intf, "marq-position" )];
257     /* FIXME: the following line doesn't work with "-1", which is the default
258      * value */
259     [o_marq_size_pop selectItemWithTitle: 
260         [[NSNumber numberWithInt: config_GetInt( p_intf, "marq-size" )]
261             stringValue]];
262     [o_marq_size_pop selectItemAtIndex: x];
263     [o_marq_tmOut_fld setStringValue: [[NSNumber numberWithInt:
264         config_GetInt( p_intf, "marq-timeout" )] stringValue]];
265     
266     /* retrieve the time settings */
267     x = 0;
268     tempInt = config_GetInt( p_intf, "time-color" );
269     while( strtol([[[o_colors objectAtIndex:x] objectAtIndex:1] UTF8String],
270         NULL, 0) != tempInt )
271     {
272         x = (x + 1);
273         
274         if( x >= [o_time_color_pop numberOfItems] )
275         {
276             x = 0;
277             return;
278         }
279     }
280     [o_time_color_pop selectItemAtIndex: x];
281         if( psz_temp = config_GetPsz( p_intf, "time-format" ) )
282                 [o_time_stamp_fld setStringValue: [NSString stringWithUTF8String: psz_temp]];
283         else
284                 [o_time_stamp_fld setStringValue: _NS(@"Not Available")];
285
286     [o_time_opaque_sld setIntValue: config_GetInt( p_intf, "time-opacity")];
287     /* FIXME: the following line doesn't work with "-1", which is the default
288      * value */
289     [o_time_size_pop selectItemWithTitle: 
290         [[NSNumber numberWithInt: config_GetInt( p_intf, "time-size" )]
291             stringValue]];
292     [o_time_pos_radio selectCellWithTag: config_GetInt( p_intf, "time-position" )];    
293
294     /* retrieve the logo settings */
295     [o_logo_opaque_sld setIntValue: config_GetInt( p_intf, "logo-transparency")];
296     /* in case that no path has been saved yet */
297     if( psz_temp = config_GetPsz( p_intf, "logo-file" ) )
298         [o_logo_image_fld setStringValue: [NSString stringWithUTF8String: psz_temp]];
299     else
300         [o_logo_image_fld setStringValue: @""];
301     [o_logo_pos_radio selectCellWithTag: config_GetInt( p_intf, "logo-position" )];
302     
303     /* enable the requested filters */
304     char * psz_subfilters;
305     psz_subfilters = config_GetPsz( p_intf, "sub-filter" );
306     if( psz_subfilters )
307     {
308         if( strstr( psz_subfilters, "marq") )
309             [o_marq_enabled_ckb setState: YES];
310         else
311             [o_marq_enabled_ckb setState: NO];
312         
313         if( strstr( psz_subfilters, "logo") )
314             [o_logo_enabled_ckb setState: YES];
315         else
316             [o_logo_enabled_ckb setState: NO];
317         
318         if( strstr( psz_subfilters, "time") )
319             [o_time_enabled_ckb setState: YES];
320         else
321             [o_time_enabled_ckb setState: NO];
322     }
323     [self enableMarq];
324     [self enableLogo];
325     [self enableTime];
326 }
327
328 - (IBAction)logo_selectFile:(id)sender
329 {
330     NSOpenPanel * openPanel = [NSOpenPanel openPanel];
331     SEL sel = @selector(logo_getFile:returnCode:contextInfo:);
332     [openPanel beginSheetForDirectory:nil file:nil types: [NSArray
333         arrayWithObjects: @"png", @"PNG", @"'PNGf'", nil] modalForWindow:
334         o_sfilter_win modalDelegate:self didEndSelector:sel contextInfo:nil];
335 }
336
337 - (void)logo_getFile: (NSOpenPanel *)sheet returnCode:
338     (int)returnCode contextInfo: (void *)contextInfo
339 {
340     if (returnCode == NSOKButton)
341     {
342         [o_logo_image_fld setStringValue: [sheet filename]];
343                 /* Make sure we notice that */
344                 [self propertyChanged: o_logo_image_fld];
345     }
346 }
347
348 - (IBAction)propertyChanged:(id)sender
349 {
350     intf_thread_t * p_intf = VLCIntf;
351     input_thread_t * p_input = (input_thread_t *)vlc_object_find( p_intf,
352         VLC_OBJECT_INPUT, FIND_ANYWHERE );
353
354     vlc_value_t val;
355
356     /* general properties */
357     if( sender == o_sfilter_saveSettings_ckb)
358     {
359         o_save_settings = [o_sfilter_saveSettings_ckb state]; 
360     }
361
362     /* marquee */
363     else if( sender == o_marq_marq_fld )
364     {
365         if( [[o_marq_marq_fld stringValue] length] == 0 )
366         {
367             val.psz_string = (char *)"";
368         }
369         else
370         {
371             val.psz_string = (char *)[[o_marq_marq_fld stringValue] UTF8String];
372         }
373
374         if( p_input )
375             var_Set( p_input->p_libvlc_global, "marq-marquee", val );
376
377         config_PutPsz( p_intf, "marq-marquee", val.psz_string );
378     }
379     
380     else if( sender == o_marq_pos_radio )
381     {
382         val.i_int = [[o_marq_pos_radio selectedCell] tag];
383
384         if( p_input )
385             var_Set( p_input->p_libvlc_global, "marq-position", val );
386
387         config_PutInt( p_intf, "marq-position", val.i_int );
388     }
389     
390     else if( sender == o_marq_color_pop )
391     {
392         val.i_int = strtol( [[[o_colors objectAtIndex: [o_marq_color_pop
393             indexOfSelectedItem]] objectAtIndex: 1] UTF8String], NULL, 0 );
394
395         if( p_input )
396             var_Set( p_input->p_libvlc_global, "marq-color", val );
397
398         config_PutInt( p_intf, "marq-color", val.i_int );
399     }
400     
401     else if( sender == o_marq_opaque_sld )
402     {
403         val.i_int = [o_marq_opaque_sld intValue];
404
405         if( p_input )
406             var_Set( p_input->p_libvlc_global, "marq-opacity", val );
407
408         config_PutInt( p_intf, "marq-opacity", val.i_int );
409     }
410     
411     else if( sender == o_marq_size_pop )
412     {
413         val.i_int = [[o_marq_size_pop titleOfSelectedItem] intValue];
414
415         if( p_input )
416             var_Set( p_input->p_libvlc_global, "marq-size", val );
417
418         config_PutInt( p_intf, "marq-size", val.i_int );
419     }
420     
421     else if( sender == o_marq_tmOut_fld && [[sender stringValue] length] > 0 )
422     {
423         val.i_int = [o_marq_tmOut_fld intValue];
424
425         if( p_input )
426             var_Set( p_input->p_libvlc_global, "marq-timeout", val );
427
428         config_PutInt( p_intf, "marq-timeout", val.i_int );
429     }
430     
431     /* time */
432     
433     else if( sender == o_time_stamp_fld )
434     {
435         if( [[o_time_stamp_fld stringValue] length] == 0 )
436         {
437             val.psz_string = (char *)"";
438         }
439         else
440         {
441             val.psz_string = (char *)[[o_time_stamp_fld stringValue] UTF8String];
442         }
443
444         if( p_input )
445             var_Set( p_input->p_libvlc_global, "time-format", val );
446
447         config_PutPsz( p_intf, "time-format", val.psz_string );
448     }
449
450     else if( sender == o_time_pos_radio )
451     {
452         val.i_int = [[o_time_pos_radio selectedCell] tag];
453
454         if( p_input )
455             var_Set( p_input->p_libvlc_global, "time-position", val );
456
457         config_PutInt( p_intf, "time-position", val.i_int );
458     }
459     
460     else if( sender == o_time_color_pop )
461     {
462         val.i_int = strtol( [[[o_colors objectAtIndex: [o_time_color_pop
463             indexOfSelectedItem]] objectAtIndex: 1] UTF8String], NULL, 0 );
464
465         if( p_input )
466             var_Set( p_input->p_libvlc_global, "time-color", val );
467
468         config_PutInt( p_intf, "time-color", val.i_int );
469     }
470     
471     else if( sender == o_time_opaque_sld )
472     {
473         val.i_int = [o_time_opaque_sld intValue];
474
475         if( p_input )
476             var_Set( p_input->p_libvlc_global, "time-opacity", val );
477
478         config_PutInt( p_intf, "time-opacity", val.i_int );
479     }
480     
481     else if( sender == o_time_size_pop )
482     {
483         val.i_int = [[o_time_size_pop titleOfSelectedItem] intValue];
484
485         if( p_input )
486             var_Set( p_input->p_libvlc_global, "time-size", val );
487
488         config_PutInt( p_intf, "time-size", val.i_int );
489     }
490
491     /* logo */
492     else if( sender == o_logo_opaque_sld )
493     {
494         val.i_int = [o_logo_opaque_sld intValue];
495
496         if( p_input )
497             var_Set( p_input->p_libvlc_global, "logo-transparency", val );
498
499         config_PutInt( p_intf, "logo-transparency", val.i_int );
500     }
501     
502     else if( sender == o_logo_pos_radio )
503     {
504         val.i_int = [[o_logo_pos_radio selectedCell] tag];
505
506         if( p_input )
507             var_Set( p_input->p_libvlc_global, "logo-position", val );
508
509         config_PutInt( p_intf, "logo-position", val.i_int );
510     }
511     else if ( sender == o_logo_image_fld )
512         {
513         val.psz_string = [[o_logo_image_fld stringValue] cString];
514
515         if( p_input )
516             var_Set( p_input->p_libvlc_global, "logo-file", val );
517
518         config_PutPsz( p_intf, "logo-file", val.psz_string );
519         }
520         else
521     {
522         /* just in case */
523         msg_Err( p_intf, "couldn't find any action for sender" );
524     }
525
526     /* clean up */
527     if ( p_input )
528     {
529         o_config_changed = YES;
530         vlc_object_release( p_input );
531     }
532 }
533
534 - (IBAction)enableFilter:(id)sender
535 {
536     if( sender == o_marq_enabled_ckb )
537     {
538         if( [o_marq_enabled_ckb state] == NSOnState )
539         {
540             [self changeFiltersString:(char *)"marq" onOrOff:VLC_TRUE];
541         }
542         else
543         {
544             [self changeFiltersString:(char *)"marq" onOrOff:VLC_FALSE];
545         }
546         [self enableMarq];
547     }
548     if( sender == o_logo_enabled_ckb )
549     {
550         if( [o_logo_enabled_ckb state] == NSOnState )
551         {
552             [self changeFiltersString:(char *)"logo" onOrOff:VLC_TRUE];
553         }
554         else
555         {
556             [self changeFiltersString:(char *)"logo" onOrOff:VLC_FALSE];
557         }
558         [self enableLogo];
559     }
560     if( sender == o_time_enabled_ckb )
561     {
562         if( [o_time_enabled_ckb state] == NSOnState )
563         {
564             [self changeFiltersString:(char *)"time" onOrOff:VLC_TRUE];
565         }
566         else
567         {
568             [self changeFiltersString:(char *)"time" onOrOff:VLC_FALSE];
569         }
570         [self enableTime];
571     }    
572 }
573
574 - (void)enableMarq
575 {
576     [o_marq_color_pop setEnabled: [o_marq_enabled_ckb state]];
577     [o_marq_marq_fld setEnabled: [o_marq_enabled_ckb state]];
578     [o_marq_opaque_sld setEnabled: [o_marq_enabled_ckb state]];
579     [o_marq_size_pop setEnabled: [o_marq_enabled_ckb state]];
580     [o_marq_tmOut_fld setEnabled: [o_marq_enabled_ckb state]];
581     [o_marq_pos_radio setEnabled: [o_marq_enabled_ckb state]];
582 }
583
584 - (void)enableTime
585 {
586     [o_time_color_pop setEnabled: [o_time_enabled_ckb state]];
587     [o_time_stamp_fld setEnabled: [o_time_enabled_ckb state]];
588     [o_time_opaque_sld setEnabled: [o_time_enabled_ckb state]];
589     [o_time_size_pop setEnabled: [o_time_enabled_ckb state]];
590     [o_time_pos_radio setEnabled: [o_time_enabled_ckb state]];
591 }
592
593 - (void)enableLogo
594 {
595     [o_logo_image_btn setEnabled: [o_logo_enabled_ckb state]];
596     [o_logo_image_fld setEnabled: [o_logo_enabled_ckb state]];
597     [o_logo_opaque_sld setEnabled: [o_logo_enabled_ckb state]];
598     [o_logo_pos_radio setEnabled: [o_logo_enabled_ckb state]];
599 }
600
601 - (void)changeFiltersString:(char *)psz_name onOrOff:(vlc_bool_t )b_add
602 {
603     /* copied from ../wxwidgets/extrapanel.cpp
604      * renamed to conform with Cocoa's rules
605      * and slightly modified to suit our needs */
606
607     intf_thread_t * p_intf = VLCIntf;
608     
609     char *psz_parser, *psz_string;
610     psz_string = config_GetPsz( p_intf, "sub-filter" );
611     
612     if( !psz_string ) psz_string = strdup("");
613
614     psz_parser = strstr( psz_string, psz_name );
615
616     if( b_add )
617     {
618         if( !psz_parser )
619         {
620             psz_parser = psz_string;
621             asprintf( &psz_string, (*psz_string) ? "%s:%s" : "%s%s",
622                             psz_string, psz_name );
623             free( psz_parser );
624         }
625         else
626         {
627             return;
628         }
629     }
630     else
631     {
632         if( psz_parser )
633         {
634             memmove( psz_parser, psz_parser + strlen(psz_name) +
635                             (*(psz_parser + strlen(psz_name)) == ':' ? 1 : 0 ),
636                             strlen(psz_parser + strlen(psz_name)) + 1 );
637
638             /* Remove trailing : : */
639             if( *(psz_string+strlen(psz_string ) -1 ) == ':' )
640             {
641                 *(psz_string+strlen(psz_string ) -1 ) = '\0';
642             }
643          }
644          else
645          {
646              free( psz_string );
647              return;
648          }
649     }
650     
651     config_PutPsz( p_intf, "sub-filter", psz_string );
652     
653     /* Try to set on the fly */
654     /* FIXME: enable this once we support on-the-fly addition of this kind of
655      * filters... */
656     vout_thread_t *p_vout;
657     p_vout = (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
658                                               FIND_ANYWHERE );
659     if( p_vout )
660     {
661         var_SetString( p_vout, "sub-filter", psz_string );
662         vlc_object_release( p_vout );
663     }
664
665     free( psz_string );
666
667     o_config_changed = YES;
668 }
669 @end