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