1 /*****************************************************************************
2 * sfilter.m: MacOS X Subpicture filters dialogue
3 *****************************************************************************
4 * Copyright (C) 2005 the VideoLAN team
7 * Authors: Felix K
\9fhne <fkuehne@users.sf.net>
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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
25 /*****************************************************************************
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 *****************************************************************************/
38 - if a vout closes and another is opened, the marquee is shown at marq-x /
39 marq-y regardless of the fact whether the user wants it to be positioned
40 fixed or not. This needs fixing in marq.c and a new global config-variable
41 - That will probably happen with logo and time as well.
42 - implement initStrings
43 - check for memory leaks
44 - save the preferences, if requested
45 - fix 10.3 compatibility
48 @implementation VLCsFilters
50 static VLCsFilters *_o_sharedInstance = nil;
52 + (VLCsFilters *)sharedInstance
54 return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
59 if (_o_sharedInstance) {
62 _o_sharedInstance = [super init];
65 return _o_sharedInstance;
81 /* colors as implemented at the beginning of marq.c and time.c
82 * feel free to add more colors, but remember to add them to these files
83 * as well to keep a certain level of consistency across the interfaces */
101 o_default = [NSArray arrayWithObjects: _NS("Default"), @"-1", nil];
102 o_black = [NSArray arrayWithObjects: _NS("Black"), @"0x000000", nil];
103 o_gray = [NSArray arrayWithObjects: _NS("Gray"), @"0x808080", nil];
104 o_silver = [NSArray arrayWithObjects: _NS("Silver"), @"0xC0C0C0", nil];
105 o_white = [NSArray arrayWithObjects: _NS("White"), @"0xFFFFFF", nil];
106 o_maroon = [NSArray arrayWithObjects: _NS("Maroon"), @"0x800000", nil];
107 o_red = [NSArray arrayWithObjects: _NS("Red"), @"0xFF0000", nil];
108 o_fuchsia = [NSArray arrayWithObjects: _NS("Fuchsia"), @"0xFF00FF", nil];
109 o_yellow = [NSArray arrayWithObjects: _NS("Yellow"), @"0xFFFF00", nil];
110 o_olive = [NSArray arrayWithObjects: _NS("Olive"), @"0x808000", nil];
111 o_green = [NSArray arrayWithObjects: _NS("Green"), @"0x008000", nil];
112 o_teal = [NSArray arrayWithObjects: _NS("Teal"), @"0x008080", nil];
113 o_lime = [NSArray arrayWithObjects: _NS("Lime"), @"0x00FF00", nil];
114 o_purple = [NSArray arrayWithObjects: _NS("Purple"), @"0x800080", nil];
115 o_navy = [NSArray arrayWithObjects: _NS("Navy"), @"0x000080", nil];
116 o_blue = [NSArray arrayWithObjects: _NS("Blue"), @"0x0000FF", nil];
117 o_aqua = [NSArray arrayWithObjects: _NS("Aqua"), @"0x00FFFF", nil];
118 o_colors = [[NSArray alloc] initWithObjects: o_default, o_black, o_gray, \
119 o_silver, o_white, o_maroon, o_red, o_fuchsia, o_yellow, o_olive, \
120 o_green, o_teal, o_lime, o_purple, o_navy, o_blue, o_aqua, nil];
123 [o_marq_color_pop removeAllItems];
124 [o_time_color_pop removeAllItems];
126 /* we are adding tags to the items, so we can easily identify them even if
127 * the menu was sorted */
128 while (x != [o_colors count])
130 [o_marq_color_pop addItemWithTitle: [[o_colors objectAtIndex:x] \
132 [[o_marq_color_pop lastItem] setTag: x];
134 [o_time_color_pop addItemWithTitle: [[o_colors objectAtIndex:x] \
136 [[o_time_color_pop lastItem] setTag: x];
141 [o_marq_color_pop selectItemAtIndex:0];
142 [o_time_color_pop selectItemAtIndex:0];
144 /* define the relative positions and copy them to the menues
145 * we can destroy the array afterwards, because we are saving the ints
146 * as tags to the menu-items */
156 NSArray * o_positions;
157 o_cnt_cnt = [NSArray arrayWithObjects: _NS("Center-Center"), @"0", nil];
158 o_lft_cnt = [NSArray arrayWithObjects: _NS("Left-Center"), @"1", nil];
159 o_rht_cnt = [NSArray arrayWithObjects: _NS("Right-Center"), @"2", nil];
160 o_cnt_top = [NSArray arrayWithObjects: _NS("Center-Top"), @"4", nil];
161 o_lft_top = [NSArray arrayWithObjects: _NS("Left-Top"), @"5", nil];
162 o_rht_top = [NSArray arrayWithObjects: _NS("Right-Top"), @"6", nil];
163 o_cnt_btm = [NSArray arrayWithObjects: _NS("Center-Bottom"), @"8", nil];
164 o_lft_btm = [NSArray arrayWithObjects: _NS("Left-Bottom"), @"9", nil];
165 o_rht_btm = [NSArray arrayWithObjects: _NS("Right-Bottom"), @"10", nil];
166 o_positions = [[NSArray alloc] initWithObjects: o_cnt_cnt, o_lft_cnt, \
167 o_rht_cnt, o_cnt_top, o_lft_top, o_rht_top, o_cnt_btm, o_lft_btm, \
171 [o_time_pos_rel_pop removeAllItems];
172 [o_marq_pos_rel_pop removeAllItems];
173 [o_logo_pos_rel_pop removeAllItems];
175 /* we are adding a tag here, so we can easily select an item later on */
176 while ( x != [o_positions count] )
178 [o_time_pos_rel_pop addItemWithTitle: [[o_positions objectAtIndex:x] \
180 [[o_time_pos_rel_pop lastItem] setTag: [[[o_positions objectAtIndex:x] \
181 objectAtIndex:1] intValue]];
182 [o_marq_pos_rel_pop addItemWithTitle: [[o_positions objectAtIndex:x] \
184 [[o_marq_pos_rel_pop lastItem] setTag: [[[o_positions objectAtIndex:x] \
185 objectAtIndex:1] intValue]];
186 [o_logo_pos_rel_pop addItemWithTitle: [[o_positions objectAtIndex:x] \
188 [[o_logo_pos_rel_pop lastItem] setTag: [[[o_positions objectAtIndex:x] \
189 objectAtIndex:1] intValue]];
193 [o_positions release];
196 o_sizes = [[NSArray alloc] initWithObjects: @"6", @"8", @"10", @"11", @"12",\
197 @"14", @"13", @"16", @"18", @"24", @"36", @"48", @"64", @"72", @"96", \
198 @"144", @"288", nil];
199 [o_marq_size_pop removeAllItems];
200 [o_marq_size_pop addItemsWithTitles: o_sizes];
201 [o_time_size_pop removeAllItems];
202 [o_time_size_pop addItemsWithTitles: o_sizes];
208 /* called from intf.m */
209 [o_sfilter_win displayIfNeeded];
210 [o_sfilter_win makeKeyAndOrderFront:nil];
212 intf_thread_t * p_intf = VLCIntf;
214 /* retrieve the marquee settings from core... */
216 int tempInt = config_GetInt( p_intf, "marq-color" );
217 while( strtol([[[o_colors objectAtIndex:x] objectAtIndex:1] UTF8String], \
218 NULL, 0) != tempInt )
222 if( x >= [o_marq_color_pop numberOfItems] )
228 [o_marq_color_pop selectItemAtIndex: x];
229 [o_marq_marq_fld setStringValue: [NSString stringWithUTF8String: \
230 config_GetPsz( p_intf, "marq-marquee" )]];
231 [o_marq_opaque_sld setIntValue: config_GetInt( p_intf, "marq-opacity")];
232 [o_marq_pos_fix_X_fld setStringValue: [[NSNumber numberWithInt: \
233 config_GetInt( p_intf, "marq-x")] stringValue]];
234 [o_marq_pos_fix_Y_fld setStringValue: [[NSNumber numberWithInt: \
235 config_GetInt( p_intf, "marq-y")] stringValue]];
236 [o_marq_pos_rel_pop selectItemWithTag: \
237 config_GetInt( p_intf, "marq-position" )];
239 tempInt = config_GetInt( p_intf, "marq-size" );
240 while( [[[o_marq_size_pop itemAtIndex: x] title] intValue] != tempInt )
243 if( x >= [o_marq_size_pop numberOfItems] )
248 [o_marq_size_pop selectItemAtIndex: x];
249 [o_marq_tmOut_fld setStringValue: [[NSNumber numberWithInt: \
250 config_GetInt( p_intf, "marq-timeout" )] stringValue]];
252 // FIXME: retrieve the proper values for logo and time from core, too!
254 char * psz_subfilters;
255 psz_subfilters = config_GetPsz( p_intf, "sub-filter" );
258 [o_marq_enabled_ckb setState: (int)strstr( psz_subfilters, "marq")];
259 [o_logo_enabled_ckb setState: (int)strstr( psz_subfilters, "logo")];
260 [o_time_enabled_ckb setState: (int)strstr( psz_subfilters, "time")];
267 - (IBAction)logo_selectFile:(id)sender
269 NSOpenPanel * openPanel = [NSOpenPanel openPanel];
270 SEL sel = @selector(logo_getFile:returnCode:contextInfo:);
271 [openPanel beginSheetForDirectory:nil file:nil types:nil modalForWindow: \
272 o_sfilter_win modalDelegate:self didEndSelector:sel contextInfo:nil];
275 - (void)logo_getFile: (NSOpenPanel *)sheet returnCode: \
276 (int)returnCode contextInfo: (void *)contextInfo
278 if (returnCode == NSOKButton)
280 [o_logo_image_fld setStringValue: [sheet filename]];
284 - (IBAction)propertyChanged:(id)sender
286 intf_thread_t * p_intf = VLCIntf;
287 input_thread_t * p_input = (input_thread_t *)vlc_object_find( p_intf, \
288 VLC_OBJECT_INPUT, FIND_ANYWHERE );
292 /* general properties */
293 if( sender == o_time_pos_rel_btn)
295 o_save_settings = [o_time_pos_rel_btn state];
299 else if( sender == o_marq_marq_fld )
301 if( [[o_marq_marq_fld stringValue] length] == 0 )
307 val.psz_string = [[o_marq_marq_fld stringValue] UTF8String];
311 var_Set( p_input->p_libvlc, "marq-marquee", val );
313 config_PutPsz( p_intf, "marq-marquee", val.psz_string );
316 else if( sender == o_marq_pos_fix_X_fld && [[sender stringValue] length] > 0 )
318 val.i_int = [o_marq_pos_fix_X_fld intValue];
321 var_Set( p_input->p_libvlc, "marq-x", val );
323 config_PutInt( p_intf, "marq-x", val.i_int );
326 else if( sender == o_marq_pos_fix_Y_fld && [[sender stringValue] length] > 0 )
328 val.i_int = [o_marq_pos_fix_Y_fld intValue];
331 var_Set( p_input->p_libvlc, "marq-y", val );
333 config_PutInt( p_intf, "marq-y", val.i_int );
336 else if( sender == o_marq_pos_rel_pop )
338 val.i_int = [[o_marq_pos_rel_pop selectedItem] tag];
341 var_Set( p_input->p_libvlc, "marq-position", val );
343 config_PutInt( p_intf, "marq-position", val.i_int );
346 else if( sender == o_marq_color_pop )
348 val.i_int = strtol( [[[o_colors objectAtIndex: [o_marq_color_pop \
349 indexOfSelectedItem]] objectAtIndex: 1] UTF8String], NULL, 0 );
352 var_Set( p_input->p_libvlc, "marq-color", val );
354 config_PutInt( p_intf, "marq-color", val.i_int );
357 else if( sender == o_marq_opaque_sld )
359 val.i_int = [o_marq_opaque_sld intValue];
362 var_Set( p_input->p_libvlc, "marq-opacity", val );
364 config_PutInt( p_intf, "marq-opacity", val.i_int );
367 else if( sender == o_marq_size_pop )
369 val.i_int = [[o_marq_size_pop titleOfSelectedItem] intValue];
372 var_Set( p_input->p_libvlc, "marq-size", val );
374 config_PutInt( p_intf, "marq-size", val.i_int );
377 else if( sender == o_marq_tmOut_fld && [[sender stringValue] length] > 0 )
379 val.i_int = [o_marq_tmOut_fld intValue];
382 var_Set( p_input->p_libvlc, "marq-timeout", val );
384 config_PutInt( p_intf, "marq-timeout", val.i_int );
393 o_config_changed = YES;
394 vlc_object_release( p_input );
398 - (IBAction)enableFilter:(id)sender
400 if( sender == o_marq_enabled_ckb )
402 if( [o_marq_enabled_ckb state] == NSOnState )
404 [self changeFiltersString:"marq" onOrOff:VLC_TRUE];
408 [self changeFiltersString:"marq" onOrOff:VLC_FALSE];
412 if( sender == o_logo_enabled_ckb )
414 if( [o_logo_enabled_ckb state] == NSOnState )
416 [self changeFiltersString:"logo" onOrOff:VLC_TRUE];
420 [self changeFiltersString:"logo" onOrOff:VLC_FALSE];
424 if( sender == o_time_enabled_ckb )
426 if( [o_time_enabled_ckb state] == NSOnState )
428 [self changeFiltersString:"time" onOrOff:VLC_TRUE];
432 [self changeFiltersString:"time" onOrOff:VLC_FALSE];
440 [o_marq_color_pop setEnabled: [o_marq_enabled_ckb state]];
441 [o_marq_marq_fld setEnabled: [o_marq_enabled_ckb state]];
442 [o_marq_opaque_sld setEnabled: [o_marq_enabled_ckb state]];
443 [o_marq_pos_fix_btn setEnabled: [o_marq_enabled_ckb state]];
444 [o_marq_pos_rel_btn setEnabled: [o_marq_enabled_ckb state]];
445 [o_marq_size_pop setEnabled: [o_marq_enabled_ckb state]];
446 [o_marq_tmOut_fld setEnabled: [o_marq_enabled_ckb state]];
447 if( [o_marq_enabled_ckb state] )
449 [self otherPositionForMarq: nil];
451 [o_marq_pos_fix_X_fld setEnabled: NO];
452 [o_marq_pos_fix_Y_fld setEnabled: NO];
453 [o_marq_pos_rel_pop setEnabled: NO];
459 [o_time_color_pop setEnabled: [o_time_enabled_ckb state]];
460 [o_time_stamp_fld setEnabled: [o_time_enabled_ckb state]];
461 [o_time_opaque_sld setEnabled: [o_time_enabled_ckb state]];
462 [o_time_pos_fix_btn setEnabled: [o_time_enabled_ckb state]];
463 [o_time_pos_rel_btn setEnabled: [o_time_enabled_ckb state]];
464 [o_time_size_pop setEnabled: [o_time_enabled_ckb state]];
465 if( [o_time_enabled_ckb state] )
467 [self otherPositionForTime: nil];
469 [o_time_pos_fix_X_fld setEnabled: NO];
470 [o_time_pos_fix_Y_fld setEnabled: NO];
471 [o_time_pos_rel_pop setEnabled: NO];
477 [o_logo_image_btn setEnabled: [o_logo_enabled_ckb state]];
478 [o_logo_image_fld setEnabled: [o_logo_enabled_ckb state]];
479 [o_logo_opaque_sld setEnabled: [o_logo_enabled_ckb state]];
480 [o_logo_pos_fix_btn setEnabled: [o_logo_enabled_ckb state]];
481 [o_logo_pos_rel_btn setEnabled: [o_logo_enabled_ckb state]];
482 if( [o_logo_enabled_ckb state] )
484 [self otherPositionForLogo: nil];
486 [o_logo_pos_fix_X_fld setEnabled: NO];
487 [o_logo_pos_fix_Y_fld setEnabled: NO];
488 [o_logo_pos_rel_pop setEnabled: NO];
492 - (IBAction)otherPositionForLogo:(id)sender
494 if( [o_logo_pos_fix_btn state] )
496 [o_logo_pos_fix_X_fld setEnabled: YES];
497 [o_logo_pos_fix_Y_fld setEnabled: YES];
498 [o_logo_pos_rel_pop setEnabled: NO];
502 [o_logo_pos_fix_X_fld setEnabled: NO];
503 [o_logo_pos_fix_Y_fld setEnabled: NO];
504 [o_logo_pos_rel_pop setEnabled: YES];
508 - (IBAction)otherPositionForMarq:(id)sender
510 if( [o_marq_pos_fix_btn state] )
512 [o_marq_pos_fix_X_fld setEnabled: YES];
513 [o_marq_pos_fix_Y_fld setEnabled: YES];
514 [o_marq_pos_rel_pop setEnabled: NO];
518 [o_marq_pos_fix_X_fld setEnabled: NO];
519 [o_marq_pos_fix_Y_fld setEnabled: NO];
520 [o_marq_pos_rel_pop setEnabled: YES];
524 - (IBAction)otherPositionForTime:(id)sender
526 if( [o_time_pos_fix_btn state] )
528 [o_time_pos_fix_X_fld setEnabled: YES];
529 [o_time_pos_fix_Y_fld setEnabled: YES];
530 [o_time_pos_rel_pop setEnabled: NO];
534 [o_time_pos_fix_X_fld setEnabled: NO];
535 [o_time_pos_fix_Y_fld setEnabled: NO];
536 [o_time_pos_rel_pop setEnabled: YES];
540 - (void)changeFiltersString:(char *)psz_name onOrOff:(vlc_bool_t )b_add
542 /* copied from ../wxwidgets/extrapanel.cpp
543 * renamed to conform with Cocoa's rules
544 * and slightly modified to suit our needs */
546 intf_thread_t * p_intf = VLCIntf;
548 char *psz_parser, *psz_string;
549 psz_string = config_GetPsz( p_intf, "sub-filter" );
551 if( !psz_string ) psz_string = strdup("");
553 psz_parser = strstr( psz_string, psz_name );
559 psz_parser = psz_string;
560 asprintf( &psz_string, (*psz_string) ? "%s:%s" : "%s%s",
561 psz_string, psz_name );
573 memmove( psz_parser, psz_parser + strlen(psz_name) +
574 (*(psz_parser + strlen(psz_name)) == ':' ? 1 : 0 ),
575 strlen(psz_parser + strlen(psz_name)) + 1 );
577 /* Remove trailing : : */
578 if( *(psz_string+strlen(psz_string ) -1 ) == ':' )
580 *(psz_string+strlen(psz_string ) -1 ) = '\0';
590 config_PutPsz( p_intf, "sub-filter", psz_string );
592 /* Try to set on the fly */
593 /* FIXME: enable this once we support on-the-fly addition of this kind of
595 vout_thread_t *p_vout;
596 p_vout = (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
600 var_SetString( p_vout, "sub-filter", psz_string );
601 vlc_object_release( p_vout );
606 vlc_object_release( p_intf );
608 o_config_changed = YES;