]> git.sesse.net Git - vlc/blob - modules/gui/macosx/ControlsBar.m
macosx: use position formatter for start and stop time in open panel
[vlc] / modules / gui / macosx / ControlsBar.m
1 /*****************************************************************************
2  * ControlsBar.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2012-2013 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
8  *          David Fuhrmann <david dot fuhrmann at googlemail dot com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #import "ControlsBar.h"
26 #import "intf.h"
27 #import "CoreInteraction.h"
28 #import "MainMenu.h"
29 #import "fspanel.h"
30
31 /*****************************************************************************
32  * VLCControlsBarCommon
33  *
34  *  Holds all outlets, actions and code common for controls bar in detached
35  *  and in main window.
36  *****************************************************************************/
37
38 @implementation VLCControlsBarCommon
39
40 @synthesize bottomBarView=o_bottombar_view;
41
42 - (void)awakeFromNib
43 {
44     b_dark_interface = config_GetInt(VLCIntf, "macosx-interfacestyle");
45
46     b_nativeFullscreenMode = NO;
47 #ifdef MAC_OS_X_VERSION_10_7
48     if (!OSX_SNOW_LEOPARD)
49         b_nativeFullscreenMode = var_InheritBool(VLCIntf, "macosx-nativefullscreenmode");
50 #endif
51
52     [o_play_btn setToolTip: _NS("Play/Pause")];
53     [[o_play_btn cell] accessibilitySetOverrideValue:_NS("Click to play or pause the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
54     [[o_play_btn cell] accessibilitySetOverrideValue:[o_play_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
55
56     [o_bwd_btn setToolTip: _NS("Backward")];
57     [[o_bwd_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the previous playlist item. Hold to skip backward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
58     [[o_bwd_btn cell] accessibilitySetOverrideValue:[o_bwd_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
59
60     [o_fwd_btn setToolTip: _NS("Forward")];
61     [[o_fwd_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the next playlist item. Hold to skip forward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
62     [[o_fwd_btn cell] accessibilitySetOverrideValue:[o_fwd_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
63
64     [o_time_sld setToolTip: _NS("Position")];
65     [[o_time_sld cell] accessibilitySetOverrideValue:_NS("Click and move the mouse while keeping the button pressed to use this slider to change current playback position.") forAttribute:NSAccessibilityDescriptionAttribute];
66     [[o_time_sld cell] accessibilitySetOverrideValue:[o_time_sld toolTip] forAttribute:NSAccessibilityTitleAttribute];
67
68     [o_fullscreen_btn setToolTip: _NS("Toggle Fullscreen mode")];
69     [[o_fullscreen_btn cell] accessibilitySetOverrideValue:_NS("Click to enable fullscreen video playback.") forAttribute:NSAccessibilityDescriptionAttribute];
70     [[o_fullscreen_btn cell] accessibilitySetOverrideValue:[o_fullscreen_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
71
72     if (!b_dark_interface) {
73         [o_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottom-background"] middle: [NSImage imageNamed:@"bottom-background"] right: [NSImage imageNamed:@"bottom-background"]];
74
75         [o_bwd_btn setImage: [NSImage imageNamed:@"backward-3btns"]];
76         [o_bwd_btn setAlternateImage: [NSImage imageNamed:@"backward-3btns-pressed"]];
77         o_play_img = [[NSImage imageNamed:@"play"] retain];
78         o_play_pressed_img = [[NSImage imageNamed:@"play-pressed"] retain];
79         o_pause_img = [[NSImage imageNamed:@"pause"] retain];
80         o_pause_pressed_img = [[NSImage imageNamed:@"pause-pressed"] retain];
81         [o_fwd_btn setImage: [NSImage imageNamed:@"forward-3btns"]];
82         [o_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-3btns-pressed"]];
83
84         [o_time_sld_background setImagesLeft: [NSImage imageNamed:@"progression-track-wrapper-left"] middle: [NSImage imageNamed:@"progression-track-wrapper-middle"] right: [NSImage imageNamed:@"progression-track-wrapper-right"]];
85         [o_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progression-fill-left"] middle:[NSImage imageNamed:@"progression-fill-middle"] right:[NSImage imageNamed:@"progression-fill-right"]];
86
87         [o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-one-button"]];
88         [o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-one-button-pressed"]];
89     } else {
90         [o_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottomdark-left"] middle: [NSImage imageNamed:@"bottom-background_dark"] right: [NSImage imageNamed:@"bottomdark-right"]];
91
92         [o_bwd_btn setImage: [NSImage imageNamed:@"backward-3btns-dark"]];
93         [o_bwd_btn setAlternateImage: [NSImage imageNamed:@"backward-3btns-dark-pressed"]];
94         o_play_img = [[NSImage imageNamed:@"play_dark"] retain];
95         o_play_pressed_img = [[NSImage imageNamed:@"play-pressed_dark"] retain];
96         o_pause_img = [[NSImage imageNamed:@"pause_dark"] retain];
97         o_pause_pressed_img = [[NSImage imageNamed:@"pause-pressed_dark"] retain];
98         [o_fwd_btn setImage: [NSImage imageNamed:@"forward-3btns-dark"]];
99         [o_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-3btns-dark-pressed"]];
100
101         [o_time_sld_background setImagesLeft: [NSImage imageNamed:@"progression-track-wrapper-left_dark"] middle: [NSImage imageNamed:@"progression-track-wrapper-middle_dark"] right: [NSImage imageNamed:@"progression-track-wrapper-right_dark"]];
102         [o_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progressbar-fill-left_dark"] middle:[NSImage imageNamed:@"progressbar-fill-middle_dark"] right:[NSImage imageNamed:@"progressbar-fill-right_dark"]];
103
104         [o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-one-button-pressed_dark"]];
105         [o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-one-button-pressed_dark"]];
106     }
107
108     [o_play_btn setImage: o_play_img];
109     [o_play_btn setAlternateImage: o_play_pressed_img];
110
111     NSColor *o_string_color;
112     if (!var_InheritBool(VLCIntf, "macosx-interfacestyle"))
113         o_string_color = [NSColor colorWithCalibratedRed:0.229 green:0.229 blue:0.229 alpha:100.0];
114     else
115         o_string_color = [NSColor colorWithCalibratedRed:0.64 green:0.64 blue:0.64 alpha:100.0];
116     [o_time_fld setTextColor: o_string_color];
117     [o_time_fld setFont:[NSFont titleBarFontOfSize:10.0]];
118     [o_time_fld setAlignment: NSCenterTextAlignment];
119     [o_time_fld setNeedsDisplay:YES];
120     [o_time_fld setRemainingIdentifier:@"DisplayTimeAsTimeRemaining"];
121
122     // prepare time slider fance gradient view
123     if (!b_dark_interface) {
124         NSRect frame;
125         frame = [o_time_sld_fancygradient_view frame];
126         frame.size.height = frame.size.height - 1;
127         frame.origin.y = frame.origin.y + 1;
128         [o_time_sld_fancygradient_view setFrame: frame];
129     }
130
131     NSRect frame;
132     frame = [o_time_sld_fancygradient_view frame];
133     frame.size.width = 0;
134     [o_time_sld_fancygradient_view setFrame: frame];
135
136     // hide resize view if necessary
137     if (!OSX_SNOW_LEOPARD)
138         [o_resize_view setImage: NULL];
139
140     if ([[o_bottombar_view window] styleMask] & NSResizableWindowMask)
141         [o_resize_view removeFromSuperviewWithoutNeedingDisplay];
142
143
144     // remove fullscreen button for lion fullscreen
145     if (b_nativeFullscreenMode) {
146         float f_width = [o_fullscreen_btn frame].size.width;
147
148         NSRect frame = [o_time_fld frame];
149         frame.origin.x += f_width;
150         [o_time_fld setFrame: frame];
151
152         frame = [o_progress_view frame];
153         frame.size.width = f_width + frame.size.width;
154         [o_progress_view setFrame: frame];
155
156         [o_fullscreen_btn removeFromSuperviewWithoutNeedingDisplay];
157     }
158
159 }
160
161 - (CGFloat)height
162 {
163     return [o_bottombar_view frame].size.height;
164 }
165
166 #pragma mark -
167 #pragma mark Button Actions
168
169 - (IBAction)play:(id)sender
170 {
171     [[VLCCoreInteraction sharedInstance] playOrPause];
172 }
173
174 - (void)resetPreviousButton
175 {
176     if (([NSDate timeIntervalSinceReferenceDate] - last_bwd_event) >= 0.35) {
177         // seems like no further event occurred, so let's switch the playback item
178         [[VLCCoreInteraction sharedInstance] previous];
179         just_triggered_previous = NO;
180     }
181 }
182
183 - (void)resetBackwardSkip
184 {
185     // the user stopped skipping, so let's allow him to change the item
186     if (([NSDate timeIntervalSinceReferenceDate] - last_bwd_event) >= 0.35)
187         just_triggered_previous = NO;
188 }
189
190 - (IBAction)bwd:(id)sender
191 {
192     if (!just_triggered_previous) {
193         just_triggered_previous = YES;
194         [self performSelector:@selector(resetPreviousButton)
195                    withObject: NULL
196                    afterDelay:0.40];
197     } else {
198         if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.16) {
199             // we just skipped 4 "continous" events, otherwise we are too fast
200             [[VLCCoreInteraction sharedInstance] backwardExtraShort];
201             last_bwd_event = [NSDate timeIntervalSinceReferenceDate];
202             [self performSelector:@selector(resetBackwardSkip)
203                        withObject: NULL
204                        afterDelay:0.40];
205         }
206     }
207 }
208
209 - (void)resetNextButton
210 {
211     if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) >= 0.35) {
212         // seems like no further event occurred, so let's switch the playback item
213         [[VLCCoreInteraction sharedInstance] next];
214         just_triggered_next = NO;
215     }
216 }
217
218 - (void)resetForwardSkip
219 {
220     // the user stopped skipping, so let's allow him to change the item
221     if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) >= 0.35)
222         just_triggered_next = NO;
223 }
224
225 - (IBAction)fwd:(id)sender
226 {
227     if (!just_triggered_next) {
228         just_triggered_next = YES;
229         [self performSelector:@selector(resetNextButton)
230                    withObject: NULL
231                    afterDelay:0.40];
232     } else {
233         if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.16) {
234             // we just skipped 4 "continous" events, otherwise we are too fast
235             [[VLCCoreInteraction sharedInstance] forwardExtraShort];
236             last_fwd_event = [NSDate timeIntervalSinceReferenceDate];
237             [self performSelector:@selector(resetForwardSkip)
238                        withObject: NULL
239                        afterDelay:0.40];
240         }
241     }
242 }
243
244 - (IBAction)timeSliderAction:(id)sender
245 {
246     float f_updated;
247     input_thread_t * p_input;
248
249     switch([[NSApp currentEvent] type]) {
250         case NSLeftMouseUp:
251         case NSLeftMouseDown:
252         case NSLeftMouseDragged:
253             f_updated = [sender floatValue];
254             break;
255
256         default:
257             return;
258     }
259     p_input = pl_CurrentInput(VLCIntf);
260     if (p_input != NULL) {
261         vlc_value_t pos;
262         NSString * o_time;
263
264         pos.f_float = f_updated / 10000.;
265         var_Set(p_input, "position", pos);
266         [o_time_sld setFloatValue: f_updated];
267
268         o_time = [[VLCStringUtility sharedInstance] getCurrentTimeAsString: p_input negative:[o_time_fld timeRemaining]];
269         [o_time_fld setStringValue: o_time];
270         vlc_object_release(p_input);
271     }
272 }
273
274 - (IBAction)fullscreen:(id)sender
275 {
276     [[VLCCoreInteraction sharedInstance] toggleFullscreen];
277 }
278
279 #pragma mark -
280 #pragma mark Updaters
281
282 - (void)updateTimeSlider
283 {
284     input_thread_t * p_input;
285     p_input = pl_CurrentInput(VLCIntf);
286     if (p_input) {
287         NSString * o_time;
288         vlc_value_t pos;
289         float f_updated;
290
291         var_Get(p_input, "position", &pos);
292         f_updated = 10000. * pos.f_float;
293         [o_time_sld setFloatValue: f_updated];
294
295         o_time = [[VLCStringUtility sharedInstance] getCurrentTimeAsString: p_input negative:[o_time_fld timeRemaining]];
296
297         mtime_t dur = input_item_GetDuration(input_GetItem(p_input));
298         if (dur == -1) {
299             [o_time_sld setHidden: YES];
300             [o_time_sld_fancygradient_view setHidden: YES];
301         } else {
302             if ([o_time_sld isHidden] == YES) {
303                 bool b_buffering = false;
304                 input_state_e inputState = input_GetState(p_input);
305                 if (inputState == INIT_S || inputState == OPENING_S)
306                     b_buffering = YES;
307
308                 [o_time_sld setHidden: b_buffering];
309                 [o_time_sld_fancygradient_view setHidden: b_buffering];
310             }
311         }
312         [o_time_fld setStringValue: o_time];
313         [o_time_fld setNeedsDisplay:YES];
314
315         vlc_object_release(p_input);
316     } else {
317         [o_time_sld setFloatValue: 0.0];
318         [o_time_fld setStringValue: @"00:00"];
319         [o_time_sld setHidden: YES];
320         [o_time_sld_fancygradient_view setHidden: YES];
321     }
322 }
323
324 - (void)drawFancyGradientEffectForTimeSlider
325 {
326     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
327     CGFloat f_value = [o_time_sld knobPosition];
328     if (f_value > 7.5) {
329         NSRect oldFrame = [o_time_sld_fancygradient_view frame];
330         if (f_value != oldFrame.size.width) {
331             if ([o_time_sld_fancygradient_view isHidden])
332                 [o_time_sld_fancygradient_view setHidden: NO];
333             [o_time_sld_fancygradient_view setFrame: NSMakeRect(oldFrame.origin.x, oldFrame.origin.y, f_value, oldFrame.size.height)];
334         }
335     } else {
336         NSRect frame;
337         frame = [o_time_sld_fancygradient_view frame];
338         if (frame.size.width > 0) {
339             frame.size.width = 0;
340             [o_time_sld_fancygradient_view setFrame: frame];
341         }
342         [o_time_sld_fancygradient_view setHidden: YES];
343     }
344     [o_pool release];
345 }
346
347 - (void)updateControls
348 {
349     bool b_plmul = false;
350     bool b_seekable = false;
351     bool b_chapters = false;
352     bool b_buffering = false;
353
354     playlist_t * p_playlist = pl_Get(VLCIntf);
355
356     PL_LOCK;
357     b_plmul = playlist_CurrentSize(p_playlist) > 1;
358     PL_UNLOCK;
359
360     input_thread_t * p_input = playlist_CurrentInput(p_playlist);
361
362
363     if (p_input) {
364         input_state_e inputState = input_GetState(p_input);
365         if (inputState == INIT_S || inputState == OPENING_S)
366             b_buffering = YES;
367
368         /* seekable streams */
369         b_seekable = var_GetBool(p_input, "can-seek");
370
371         /* chapters & titles */
372         //FIXME! b_chapters = p_input->stream.i_area_nb > 1;
373
374         vlc_object_release(p_input);
375     }
376
377
378     if (b_buffering) {
379         [o_progress_bar startAnimation:self];
380         [o_progress_bar setIndeterminate:YES];
381         [o_progress_bar setHidden:NO];
382     } else {
383         [o_progress_bar stopAnimation:self];
384         [o_progress_bar setHidden:YES];
385     }
386
387     [o_time_sld setEnabled: b_seekable];
388
389     [o_fwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
390     [o_bwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
391 }
392
393 - (void)setPause
394 {
395     [o_play_btn setImage: o_pause_img];
396     [o_play_btn setAlternateImage: o_pause_pressed_img];
397     [o_play_btn setToolTip: _NS("Pause")];
398 }
399
400 - (void)setPlay
401 {
402     [o_play_btn setImage: o_play_img];
403     [o_play_btn setAlternateImage: o_play_pressed_img];
404     [o_play_btn setToolTip: _NS("Play")];
405 }
406
407 - (void)setFullscreenState:(BOOL)b_fullscreen
408 {
409     if (!b_nativeFullscreenMode)
410         [o_fullscreen_btn setState:b_fullscreen];
411 }
412
413 @end
414
415
416 /*****************************************************************************
417  * VLCMainWindowControlsBar
418  *
419  *  Holds all specific outlets, actions and code for the main window controls bar.
420  *****************************************************************************/
421
422 @interface VLCMainWindowControlsBar (Internal)
423 - (void)addJumpButtons:(BOOL)b_fast;
424 - (void)removeJumpButtons:(BOOL)b_fast;
425 - (void)addPlaymodeButtons:(BOOL)b_fast;
426 - (void)removePlaymodeButtons:(BOOL)b_fast;
427 @end
428
429 @implementation VLCMainWindowControlsBar
430
431 - (void)awakeFromNib
432 {
433     [super awakeFromNib];
434
435
436     [o_stop_btn setToolTip: _NS("Stop")];
437     [[o_stop_btn cell] accessibilitySetOverrideValue:_NS("Click to stop playback.") forAttribute:NSAccessibilityDescriptionAttribute];
438     [[o_stop_btn cell] accessibilitySetOverrideValue:[o_stop_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
439
440     [o_playlist_btn setToolTip: _NS("Show/Hide Playlist")];
441     [[o_playlist_btn cell] accessibilitySetOverrideValue:_NS("Click to switch between video output and playlist. If no video is shown in the main window, this allows you to hide the playlist.") forAttribute:NSAccessibilityDescriptionAttribute];
442     [[o_playlist_btn cell] accessibilitySetOverrideValue:[o_playlist_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
443
444     [o_repeat_btn setToolTip: _NS("Repeat")];
445     [[o_repeat_btn cell] accessibilitySetOverrideValue:_NS("Click to change repeat mode. There are 3 states: repeat one, repeat all and off.") forAttribute:NSAccessibilityDescriptionAttribute];
446     [[o_repeat_btn cell] accessibilitySetOverrideValue:[o_repeat_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
447
448     [o_shuffle_btn setToolTip: _NS("Shuffle")];
449     [[o_shuffle_btn cell] accessibilitySetOverrideValue:[o_shuffle_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
450     [[o_shuffle_btn cell] accessibilitySetOverrideValue:_NS("Click to enable or disable random playback.") forAttribute:NSAccessibilityDescriptionAttribute];
451
452     [o_volume_sld setToolTip: _NS("Volume")];
453     [[o_volume_sld cell] accessibilitySetOverrideValue:_NS("Click and move the mouse while keeping the button pressed to use this slider to change the volume.") forAttribute:NSAccessibilityDescriptionAttribute];
454     [[o_volume_sld cell] accessibilitySetOverrideValue:[o_volume_sld toolTip] forAttribute:NSAccessibilityTitleAttribute];
455     [o_volume_down_btn setToolTip: _NS("Mute")];
456     [[o_volume_down_btn cell] accessibilitySetOverrideValue:_NS("Click to mute or unmute the audio.") forAttribute:NSAccessibilityDescriptionAttribute];
457     [[o_volume_down_btn cell] accessibilitySetOverrideValue:[o_volume_down_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
458     [o_volume_up_btn setToolTip: _NS("Full Volume")];
459     [[o_volume_up_btn cell] accessibilitySetOverrideValue:_NS("Click to play the audio at maximum volume.") forAttribute:NSAccessibilityDescriptionAttribute];
460     [[o_volume_up_btn cell] accessibilitySetOverrideValue:[o_volume_up_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
461
462     [o_effects_btn setToolTip: _NS("Effects")];
463     [[o_effects_btn cell] accessibilitySetOverrideValue:_NS("Click to show an Audio Effects panel featuring an equalizer and further filters.") forAttribute:NSAccessibilityDescriptionAttribute];
464     [[o_effects_btn cell] accessibilitySetOverrideValue:[o_effects_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
465
466     if (!b_dark_interface) {
467         [o_stop_btn setImage: [NSImage imageNamed:@"stop"]];
468         [o_stop_btn setAlternateImage: [NSImage imageNamed:@"stop-pressed"]];
469
470         [o_playlist_btn setImage: [NSImage imageNamed:@"playlist-btn"]];
471         [o_playlist_btn setAlternateImage: [NSImage imageNamed:@"playlist-btn-pressed"]];
472         o_repeat_img = [[NSImage imageNamed:@"repeat"] retain];
473         o_repeat_pressed_img = [[NSImage imageNamed:@"repeat-pressed"] retain];
474         o_repeat_all_img  = [[NSImage imageNamed:@"repeat-all"] retain];
475         o_repeat_all_pressed_img = [[NSImage imageNamed:@"repeat-all-pressed"] retain];
476         o_repeat_one_img = [[NSImage imageNamed:@"repeat-one"] retain];
477         o_repeat_one_pressed_img = [[NSImage imageNamed:@"repeat-one-pressed"] retain];
478         o_shuffle_img = [[NSImage imageNamed:@"shuffle"] retain];
479         o_shuffle_pressed_img = [[NSImage imageNamed:@"shuffle-pressed"] retain];
480         o_shuffle_on_img = [[NSImage imageNamed:@"shuffle-blue"] retain];
481         o_shuffle_on_pressed_img = [[NSImage imageNamed:@"shuffle-blue-pressed"] retain];
482
483         [o_volume_down_btn setImage: [NSImage imageNamed:@"volume-low"]];
484         [o_volume_track_view setImage: [NSImage imageNamed:@"volume-slider-track"]];
485         [o_volume_up_btn setImage: [NSImage imageNamed:@"volume-high"]];
486
487         if (b_nativeFullscreenMode) {
488             [o_effects_btn setImage: [NSImage imageNamed:@"effects-one-button"]];
489             [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-one-button-pressed"]];
490         } else {
491             [o_effects_btn setImage: [NSImage imageNamed:@"effects-double-buttons"]];
492             [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-double-buttons-pressed"]];
493         }
494
495         [o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-double-buttons"]];
496         [o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-double-buttons-pressed"]];
497     } else {
498         [o_stop_btn setImage: [NSImage imageNamed:@"stop_dark"]];
499         [o_stop_btn setAlternateImage: [NSImage imageNamed:@"stop-pressed_dark"]];
500
501         [o_playlist_btn setImage: [NSImage imageNamed:@"playlist_dark"]];
502         [o_playlist_btn setAlternateImage: [NSImage imageNamed:@"playlist-pressed_dark"]];
503         o_repeat_img = [[NSImage imageNamed:@"repeat_dark"] retain];
504         o_repeat_pressed_img = [[NSImage imageNamed:@"repeat-pressed_dark"] retain];
505         o_repeat_all_img  = [[NSImage imageNamed:@"repeat-all-blue_dark"] retain];
506         o_repeat_all_pressed_img = [[NSImage imageNamed:@"repeat-all-blue-pressed_dark"] retain];
507         o_repeat_one_img = [[NSImage imageNamed:@"repeat-one-blue_dark"] retain];
508         o_repeat_one_pressed_img = [[NSImage imageNamed:@"repeat-one-blue-pressed_dark"] retain];
509         o_shuffle_img = [[NSImage imageNamed:@"shuffle_dark"] retain];
510         o_shuffle_pressed_img = [[NSImage imageNamed:@"shuffle-pressed_dark"] retain];
511         o_shuffle_on_img = [[NSImage imageNamed:@"shuffle-blue_dark"] retain];
512         o_shuffle_on_pressed_img = [[NSImage imageNamed:@"shuffle-blue-pressed_dark"] retain];
513
514         [o_volume_down_btn setImage: [NSImage imageNamed:@"volume-low_dark"]];
515         [o_volume_track_view setImage: [NSImage imageNamed:@"volume-slider-track_dark"]];
516         [o_volume_up_btn setImage: [NSImage imageNamed:@"volume-high_dark"]];
517
518         if (b_nativeFullscreenMode) {
519             [o_effects_btn setImage: [NSImage imageNamed:@"effects-one-button_dark"]];
520             [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-one-button-pressed-dark"]];
521         } else {
522             [o_effects_btn setImage: [NSImage imageNamed:@"effects-double-buttons_dark"]];
523             [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-double-buttons-pressed_dark"]];
524         }
525
526         [o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-double-buttons_dark"]];
527         [o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-double-buttons-pressed_dark"]];
528     }
529     [o_repeat_btn setImage: o_repeat_img];
530     [o_repeat_btn setAlternateImage: o_repeat_pressed_img];
531     [o_shuffle_btn setImage: o_shuffle_img];
532     [o_shuffle_btn setAlternateImage: o_shuffle_pressed_img];
533
534     BOOL b_mute = ![[VLCCoreInteraction sharedInstance] mute];
535     [o_volume_sld setEnabled: b_mute];
536     [o_volume_up_btn setEnabled: b_mute];
537
538
539     // remove fullscreen button for lion fullscreen
540     if (b_nativeFullscreenMode) {
541         NSRect frame;
542
543         // == [o_fullscreen_btn frame].size.width;
544         // button is already removed!
545         float f_width = 29.;
546 #define moveItem(item) \
547 frame = [item frame]; \
548 frame.origin.x = f_width + frame.origin.x; \
549 [item setFrame: frame]
550
551         moveItem(o_effects_btn);
552         moveItem(o_volume_up_btn);
553         moveItem(o_volume_sld);
554         moveItem(o_volume_track_view);
555         moveItem(o_volume_down_btn);
556 #undef moveItem
557
558         // time field and progress bar are moved in super method!
559     }
560
561
562     b_show_jump_buttons = config_GetInt(VLCIntf, "macosx-show-playback-buttons");
563     if (b_show_jump_buttons)
564         [self addJumpButtons:YES];
565
566     b_show_playmode_buttons = config_GetInt(VLCIntf, "macosx-show-playmode-buttons");
567     if (!b_show_playmode_buttons)
568         [self removePlaymodeButtons:YES];
569
570     if (!config_GetInt(VLCIntf, "macosx-show-effects-button"))
571         [self removeEffectsButton:YES];
572
573     [[VLCMain sharedInstance] playbackModeUpdated];
574
575 }
576
577 #pragma mark -
578 #pragma mark interface customization
579
580
581 - (void)toggleEffectsButton
582 {
583     if (config_GetInt(VLCIntf, "macosx-show-effects-button"))
584         [self addEffectsButton:NO];
585     else
586         [self removeEffectsButton:NO];
587 }
588
589 - (void)addEffectsButton:(BOOL)b_fast
590 {
591     if (!o_effects_btn)
592         return;
593
594     if (b_fast) {
595         [o_effects_btn setHidden: NO];
596     } else {
597         [[o_effects_btn animator] setHidden: NO];
598     }
599
600 #define moveItem(item) \
601 frame = [item frame]; \
602 frame.origin.x = frame.origin.x - f_space; \
603 if (b_fast) \
604 [item setFrame: frame]; \
605 else \
606 [[item animator] setFrame: frame]
607
608     NSRect frame;
609     float f_space = [o_effects_btn frame].size.width;
610     // extra margin between button and volume up button
611     if (b_nativeFullscreenMode)
612         f_space += 2;
613
614
615     moveItem(o_volume_up_btn);
616     moveItem(o_volume_sld);
617     moveItem(o_volume_track_view);
618     moveItem(o_volume_down_btn);
619     moveItem(o_time_fld);
620 #undef moveItem
621
622
623     frame = [o_progress_view frame];
624     frame.size.width = frame.size.width - f_space;
625     if (b_fast)
626         [o_progress_view setFrame: frame];
627     else
628         [[o_progress_view animator] setFrame: frame];
629
630     if (!b_nativeFullscreenMode) {
631         if (b_dark_interface) {
632             [o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-double-buttons_dark"]];
633             [o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-double-buttons-pressed_dark"]];
634         } else {
635             [o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-double-buttons"]];
636             [o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-double-buttons-pressed"]];
637         }
638     }
639
640     [o_bottombar_view setNeedsDisplay:YES];
641 }
642
643 - (void)removeEffectsButton:(BOOL)b_fast
644 {
645     if (!o_effects_btn)
646         return;
647
648     [o_effects_btn setHidden: YES];
649
650 #define moveItem(item) \
651 frame = [item frame]; \
652 frame.origin.x = frame.origin.x + f_space; \
653 if (b_fast) \
654 [item setFrame: frame]; \
655 else \
656 [[item animator] setFrame: frame]
657
658     NSRect frame;
659     float f_space = [o_effects_btn frame].size.width;
660     // extra margin between button and volume up button
661     if (b_nativeFullscreenMode)
662         f_space += 2;
663
664     moveItem(o_volume_up_btn);
665     moveItem(o_volume_sld);
666     moveItem(o_volume_track_view);
667     moveItem(o_volume_down_btn);
668     moveItem(o_time_fld);
669 #undef moveItem
670
671
672     frame = [o_progress_view frame];
673     frame.size.width = frame.size.width + f_space;
674     if (b_fast)
675         [o_progress_view setFrame: frame];
676     else
677         [[o_progress_view animator] setFrame: frame];
678
679     if (!b_nativeFullscreenMode) {
680         if (b_dark_interface) {
681             [[o_fullscreen_btn animator] setImage: [NSImage imageNamed:@"fullscreen-one-button_dark"]];
682             [[o_fullscreen_btn animator] setAlternateImage: [NSImage imageNamed:@"fullscreen-one-button-pressed_dark"]];
683         } else {
684             [[o_fullscreen_btn animator] setImage: [NSImage imageNamed:@"fullscreen-one-button"]];
685             [[o_fullscreen_btn animator] setAlternateImage: [NSImage imageNamed:@"fullscreen-one-button-pressed"]];
686         }
687     }
688
689     [o_bottombar_view setNeedsDisplay:YES];
690 }
691
692 - (void)toggleJumpButtons
693 {
694     b_show_jump_buttons = config_GetInt(VLCIntf, "macosx-show-playback-buttons");
695
696     if (b_show_jump_buttons)
697         [self addJumpButtons:NO];
698     else
699         [self removeJumpButtons:NO];
700 }
701
702 - (void)addJumpButtons:(BOOL)b_fast
703 {
704     NSRect preliminaryFrame = [o_bwd_btn frame];
705     BOOL b_enabled = [o_bwd_btn isEnabled];
706     preliminaryFrame.size.width = 29.;
707     o_prev_btn = [[NSButton alloc] initWithFrame:preliminaryFrame];
708     [o_prev_btn setButtonType: NSMomentaryChangeButton];
709     [o_prev_btn setBezelStyle:NSRegularSquareBezelStyle];
710     [o_prev_btn setBordered:NO];
711     [o_prev_btn setTarget:self];
712     [o_prev_btn setAction:@selector(prev:)];
713     [o_prev_btn setToolTip: _NS("Previous")];
714     [[o_prev_btn cell] accessibilitySetOverrideValue:_NS("Previous") forAttribute:NSAccessibilityTitleAttribute];
715     [[o_prev_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the previous playlist item.") forAttribute:NSAccessibilityDescriptionAttribute];
716     [o_prev_btn setEnabled: b_enabled];
717
718     o_next_btn = [[NSButton alloc] initWithFrame:preliminaryFrame];
719     [o_next_btn setButtonType: NSMomentaryChangeButton];
720     [o_next_btn setBezelStyle:NSRegularSquareBezelStyle];
721     [o_next_btn setBordered:NO];
722     [o_next_btn setTarget:self];
723     [o_next_btn setAction:@selector(next:)];
724     [o_next_btn setToolTip: _NS("Next")];
725     [[o_next_btn cell] accessibilitySetOverrideValue:_NS("Next") forAttribute:NSAccessibilityTitleAttribute];
726     [[o_next_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the next playlist item.") forAttribute:NSAccessibilityDescriptionAttribute];
727     [o_next_btn setEnabled: b_enabled];
728
729     if (b_dark_interface) {
730         [o_prev_btn setImage: [NSImage imageNamed:@"previous-6btns-dark"]];
731         [o_prev_btn setAlternateImage: [NSImage imageNamed:@"previous-6btns-dark-pressed"]];
732         [o_next_btn setImage: [NSImage imageNamed:@"next-6btns-dark"]];
733         [o_next_btn setAlternateImage: [NSImage imageNamed:@"next-6btns-dark-pressed"]];
734     } else {
735         [o_prev_btn setImage: [NSImage imageNamed:@"previous-6btns"]];
736         [o_prev_btn setAlternateImage: [NSImage imageNamed:@"previous-6btns-pressed"]];
737         [o_next_btn setImage: [NSImage imageNamed:@"next-6btns"]];
738         [o_next_btn setAlternateImage: [NSImage imageNamed:@"next-6btns-pressed"]];
739     }
740
741     /* change the accessibility help for the backward/forward buttons accordingly */
742     [[o_bwd_btn cell] accessibilitySetOverrideValue:_NS("Click and hold to skip backward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
743     [[o_fwd_btn cell] accessibilitySetOverrideValue:_NS("Click and hold to skip forward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
744
745     NSRect frame;
746     frame = [o_bwd_btn frame];
747     frame.size.width--;
748     [o_bwd_btn setFrame:frame];
749     frame = [o_fwd_btn frame];
750     frame.size.width--;
751     [o_fwd_btn setFrame:frame];
752
753 #define moveItem(item) \
754 frame = [item frame]; \
755 frame.origin.x = frame.origin.x + f_space; \
756 if (b_fast) \
757     [item setFrame: frame]; \
758 else \
759     [[item animator] setFrame: frame]
760
761     float f_space = 29.;
762     moveItem(o_bwd_btn);
763     f_space = 28.;
764     moveItem(o_play_btn);
765     moveItem(o_fwd_btn);
766     f_space = 28. * 2;
767     moveItem(o_stop_btn);
768     moveItem(o_playlist_btn);
769     moveItem(o_repeat_btn);
770     moveItem(o_shuffle_btn);
771 #undef moveItem
772
773     frame = [o_progress_view frame];
774     frame.size.width = frame.size.width - f_space;
775     frame.origin.x = frame.origin.x + f_space;
776     if (b_fast)
777         [o_progress_view setFrame: frame];
778     else
779         [[o_progress_view animator] setFrame: frame];
780
781     if (b_dark_interface) {
782         [[o_fwd_btn animator] setImage:[NSImage imageNamed:@"forward-6btns-dark"]];
783         [[o_fwd_btn animator] setAlternateImage:[NSImage imageNamed:@"forward-6btns-dark-pressed"]];
784         [[o_bwd_btn animator] setImage:[NSImage imageNamed:@"backward-6btns-dark"]];
785         [[o_bwd_btn animator] setAlternateImage:[NSImage imageNamed:@"backward-6btns-dark-pressed"]];
786     } else {
787         [[o_fwd_btn animator] setImage:[NSImage imageNamed:@"forward-6btns"]];
788         [[o_fwd_btn animator] setAlternateImage:[NSImage imageNamed:@"forward-6btns-pressed"]];
789         [[o_bwd_btn animator] setImage:[NSImage imageNamed:@"backward-6btns"]];
790         [[o_bwd_btn animator] setAlternateImage:[NSImage imageNamed:@"backward-6btns-pressed"]];
791     }
792
793     preliminaryFrame.origin.x = [o_prev_btn frame].origin.x + [o_prev_btn frame].size.width + [o_bwd_btn frame].size.width + [o_play_btn frame].size.width + [o_fwd_btn frame].size.width;
794     [o_next_btn setFrame: preliminaryFrame];
795
796     // wait until the animation is done, if displayed
797     if (b_fast) {
798         [o_bottombar_view addSubview:o_prev_btn];
799         [o_bottombar_view addSubview:o_next_btn];
800     } else {
801         [o_bottombar_view performSelector:@selector(addSubview:) withObject:o_prev_btn afterDelay:.2];
802         [o_bottombar_view performSelector:@selector(addSubview:) withObject:o_next_btn afterDelay:.2];
803     }
804
805     [o_fwd_btn setAction:@selector(forward:)];
806     [o_bwd_btn setAction:@selector(backward:)];
807 }
808
809 - (void)removeJumpButtons:(BOOL)b_fast
810 {
811     if (!o_prev_btn || !o_next_btn)
812         return;
813
814     if (b_fast) {
815         [o_prev_btn setHidden: YES];
816         [o_next_btn setHidden: YES];
817     } else {
818         [[o_prev_btn animator] setHidden: YES];
819         [[o_next_btn animator] setHidden: YES];
820     }
821     [o_prev_btn removeFromSuperviewWithoutNeedingDisplay];
822     [o_next_btn removeFromSuperviewWithoutNeedingDisplay];
823     [o_prev_btn release];
824     o_prev_btn = NULL;
825     [o_next_btn release];
826     o_next_btn = NULL;
827
828     /* change the accessibility help for the backward/forward buttons accordingly */
829     [[o_bwd_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the previous playlist item. Hold to skip backward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
830     [[o_fwd_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the next playlist item. Hold to skip forward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
831
832     NSRect frame;
833     frame = [o_bwd_btn frame];
834     frame.size.width++;
835     [o_bwd_btn setFrame:frame];
836     frame = [o_fwd_btn frame];
837     frame.size.width++;
838     [o_fwd_btn setFrame:frame];
839
840 #define moveItem(item) \
841 frame = [item frame]; \
842 frame.origin.x = frame.origin.x - f_space; \
843 if (b_fast) \
844     [item setFrame: frame]; \
845 else \
846     [[item animator] setFrame: frame]
847
848     float f_space = 29.;
849     moveItem(o_bwd_btn);
850     f_space = 28.;
851     moveItem(o_play_btn);
852     moveItem(o_fwd_btn);
853     f_space = 28. * 2;
854     moveItem(o_stop_btn);
855     moveItem(o_playlist_btn);
856     moveItem(o_repeat_btn);
857     moveItem(o_shuffle_btn);
858 #undef moveItem
859
860     frame = [o_progress_view frame];
861     frame.size.width = frame.size.width + f_space;
862     frame.origin.x = frame.origin.x - f_space;
863     if (b_fast)
864         [o_progress_view setFrame: frame];
865     else
866         [[o_progress_view animator] setFrame: frame];
867
868     if (b_dark_interface) {
869         [[o_fwd_btn animator] setImage:[NSImage imageNamed:@"forward-3btns-dark"]];
870         [[o_fwd_btn animator] setAlternateImage:[NSImage imageNamed:@"forward-3btns-dark-pressed"]];
871         [[o_bwd_btn animator] setImage:[NSImage imageNamed:@"backward-3btns-dark"]];
872         [[o_bwd_btn animator] setAlternateImage:[NSImage imageNamed:@"backward-3btns-dark-pressed"]];
873     } else {
874         [[o_fwd_btn animator] setImage:[NSImage imageNamed:@"forward-3btns"]];
875         [[o_fwd_btn animator] setAlternateImage:[NSImage imageNamed:@"forward-3btns-pressed"]];
876         [[o_bwd_btn animator] setImage:[NSImage imageNamed:@"backward-3btns"]];
877         [[o_bwd_btn animator] setAlternateImage:[NSImage imageNamed:@"backward-3btns-pressed"]];
878     }
879
880     [o_bottombar_view setNeedsDisplay:YES];
881
882     [o_fwd_btn setAction:@selector(fwd:)];
883     [o_bwd_btn setAction:@selector(bwd:)];
884 }
885
886 - (void)togglePlaymodeButtons
887 {
888     b_show_playmode_buttons = config_GetInt(VLCIntf, "macosx-show-playmode-buttons");
889
890     if (b_show_playmode_buttons)
891         [self addPlaymodeButtons:NO];
892     else
893         [self removePlaymodeButtons:NO];
894 }
895
896 - (void)addPlaymodeButtons:(BOOL)b_fast
897 {
898     NSRect frame;
899     float f_space = [o_repeat_btn frame].size.width + [o_shuffle_btn frame].size.width - 6.;
900
901     if (b_dark_interface) {
902         [[o_playlist_btn animator] setImage:[NSImage imageNamed:@"playlist_dark"]];
903         [[o_playlist_btn animator] setAlternateImage:[NSImage imageNamed:@"playlist-pressed_dark"]];
904     } else {
905         [[o_playlist_btn animator] setImage:[NSImage imageNamed:@"playlist-btn"]];
906         [[o_playlist_btn animator] setAlternateImage:[NSImage imageNamed:@"playlist-btn-pressed"]];
907     }
908     frame = [o_playlist_btn frame];
909     frame.size.width--;
910     [o_playlist_btn setFrame:frame];
911
912     if (b_fast) {
913         [o_repeat_btn setHidden: NO];
914         [o_shuffle_btn setHidden: NO];
915     } else {
916         [[o_repeat_btn animator] setHidden: NO];
917         [[o_shuffle_btn animator] setHidden: NO];
918     }
919
920     frame = [o_progress_view frame];
921     frame.size.width = frame.size.width - f_space;
922     frame.origin.x = frame.origin.x + f_space;
923     if (b_fast)
924         [o_progress_view setFrame: frame];
925     else
926         [[o_progress_view animator] setFrame: frame];
927 }
928
929 - (void)removePlaymodeButtons:(BOOL)b_fast
930 {
931     NSRect frame;
932     float f_space = [o_repeat_btn frame].size.width + [o_shuffle_btn frame].size.width - 6.;
933     [o_repeat_btn setHidden: YES];
934     [o_shuffle_btn setHidden: YES];
935
936     if (b_dark_interface) {
937         [[o_playlist_btn animator] setImage:[NSImage imageNamed:@"playlist-1btn-dark"]];
938         [[o_playlist_btn animator] setAlternateImage:[NSImage imageNamed:@"playlist-1btn-dark-pressed"]];
939     } else {
940         [[o_playlist_btn animator] setImage:[NSImage imageNamed:@"playlist-1btn"]];
941         [[o_playlist_btn animator] setAlternateImage:[NSImage imageNamed:@"playlist-1btn-pressed"]];
942     }
943     frame = [o_playlist_btn frame];
944     frame.size.width++;
945     [o_playlist_btn setFrame:frame];
946
947     frame = [o_progress_view frame];
948     frame.size.width = frame.size.width + f_space;
949     frame.origin.x = frame.origin.x - f_space;
950     if (b_fast)
951         [o_progress_view setFrame: frame];
952     else
953         [[o_progress_view animator] setFrame: frame];
954 }
955
956 #pragma mark -
957 #pragma mark Extra button actions
958
959 - (IBAction)stop:(id)sender
960 {
961     [[VLCCoreInteraction sharedInstance] stop];
962 }
963
964 // dynamically created next / prev buttons
965 - (IBAction)prev:(id)sender
966 {
967     [[VLCCoreInteraction sharedInstance] previous];
968 }
969
970 - (IBAction)next:(id)sender
971 {
972     [[VLCCoreInteraction sharedInstance] next];
973 }
974
975 // alternative actions for forward / backward buttons when next / prev are activated
976 - (IBAction)forward:(id)sender
977 {
978     [[VLCCoreInteraction sharedInstance] forwardExtraShort];
979 }
980
981 - (IBAction)backward:(id)sender
982 {
983     [[VLCCoreInteraction sharedInstance] backwardExtraShort];
984 }
985
986 - (void)setRepeatOne
987 {
988     [o_repeat_btn setImage: o_repeat_one_img];
989     [o_repeat_btn setAlternateImage: o_repeat_one_pressed_img];
990 }
991
992 - (void)setRepeatAll
993 {
994     [o_repeat_btn setImage: o_repeat_all_img];
995     [o_repeat_btn setAlternateImage: o_repeat_all_pressed_img];
996 }
997
998 - (void)setRepeatOff
999 {
1000     [o_repeat_btn setImage: o_repeat_img];
1001     [o_repeat_btn setAlternateImage: o_repeat_pressed_img];
1002 }
1003
1004 - (IBAction)repeat:(id)sender
1005 {
1006     vlc_value_t looping,repeating;
1007     intf_thread_t * p_intf = VLCIntf;
1008     playlist_t * p_playlist = pl_Get(p_intf);
1009
1010     var_Get(p_playlist, "repeat", &repeating);
1011     var_Get(p_playlist, "loop", &looping);
1012
1013     if (!repeating.b_bool && !looping.b_bool) {
1014         /* was: no repeating at all, switching to Repeat One */
1015         [[VLCCoreInteraction sharedInstance] repeatOne];
1016         [self setRepeatOne];
1017     }
1018     else if (repeating.b_bool && !looping.b_bool) {
1019         /* was: Repeat One, switching to Repeat All */
1020         [[VLCCoreInteraction sharedInstance] repeatAll];
1021         [self setRepeatAll];
1022     } else {
1023         /* was: Repeat All or bug in VLC, switching to Repeat Off */
1024         [[VLCCoreInteraction sharedInstance] repeatOff];
1025         [self setRepeatOff];
1026     }
1027 }
1028
1029 - (void)setShuffle
1030 {
1031     bool b_value;
1032     playlist_t *p_playlist = pl_Get(VLCIntf);
1033     b_value = var_GetBool(p_playlist, "random");
1034
1035     if (b_value) {
1036         [o_shuffle_btn setImage: o_shuffle_on_img];
1037         [o_shuffle_btn setAlternateImage: o_shuffle_on_pressed_img];
1038     } else {
1039         [o_shuffle_btn setImage: o_shuffle_img];
1040         [o_shuffle_btn setAlternateImage: o_shuffle_pressed_img];
1041     }
1042 }
1043
1044 - (IBAction)shuffle:(id)sender
1045 {
1046     [[VLCCoreInteraction sharedInstance] shuffle];
1047     [self setShuffle];
1048 }
1049
1050 - (IBAction)volumeAction:(id)sender
1051 {
1052     if (sender == o_volume_sld)
1053         [[VLCCoreInteraction sharedInstance] setVolume: [sender intValue]];
1054     else if (sender == o_volume_down_btn)
1055         [[VLCCoreInteraction sharedInstance] toggleMute];
1056     else
1057         [[VLCCoreInteraction sharedInstance] setVolume: AOUT_VOLUME_MAX];
1058 }
1059
1060 - (IBAction)effects:(id)sender
1061 {
1062     [[VLCMainMenu sharedInstance] showAudioEffects: sender];
1063 }
1064
1065 #pragma mark -
1066 #pragma mark Extra updaters
1067
1068 - (void)updateVolumeSlider
1069 {
1070     int i_volume = [[VLCCoreInteraction sharedInstance] volume];
1071     BOOL b_muted = [[VLCCoreInteraction sharedInstance] mute];
1072
1073     if (!b_muted)
1074         [o_volume_sld setIntValue: i_volume];
1075     else
1076         [o_volume_sld setIntValue: 0];
1077
1078     [o_volume_sld setEnabled: !b_muted];
1079     [o_volume_up_btn setEnabled: !b_muted];
1080 }
1081
1082 - (void)updateControls
1083 {
1084     [super updateControls];
1085
1086     bool b_input = false;
1087     bool b_seekable = false;
1088     bool b_plmul = false;
1089     bool b_control = false;
1090     bool b_chapters = false;
1091
1092     playlist_t * p_playlist = pl_Get(VLCIntf);
1093
1094     PL_LOCK;
1095     b_plmul = playlist_CurrentSize(p_playlist) > 1;
1096     PL_UNLOCK;
1097
1098     input_thread_t * p_input = playlist_CurrentInput(p_playlist);
1099     if ((b_input = (p_input != NULL))) {
1100         /* seekable streams */
1101         b_seekable = var_GetBool(p_input, "can-seek");
1102
1103         /* check whether slow/fast motion is possible */
1104         b_control = var_GetBool(p_input, "can-rate");
1105
1106         /* chapters & titles */
1107         //FIXME! b_chapters = p_input->stream.i_area_nb > 1;
1108
1109         vlc_object_release(p_input);
1110     }
1111
1112     [o_stop_btn setEnabled: b_input];
1113
1114     if (b_show_jump_buttons) {
1115         [o_prev_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1116         [o_next_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
1117     }
1118
1119     [[VLCMainMenu sharedInstance] setRateControlsEnabled: b_control];
1120 }
1121
1122 @end