core: remove the 360 video viewpoint zoom
[vlc.git] / modules / gui / macosx / VLCMainWindowControlsBar.m
blob587e151851f7800b9affb1b93291fb947d17d476
1 /*****************************************************************************
2  * ControlsBar.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2012-2016 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  *****************************************************************************/
25 #import "VLCControlsBarCommon.h"
26 #import "VLCMainWindowControlsBar.h"
27 #import "VLCMain.h"
28 #import "VLCCoreInteraction.h"
29 #import "VLCMainMenu.h"
30 #import "VLCPlaylist.h"
31 #import "CompatibilityFixes.h"
33 /*****************************************************************************
34  * VLCMainWindowControlsBar
35  *
36  *  Holds all specific outlets, actions and code for the main window controls bar.
37  *****************************************************************************/
39 @interface VLCMainWindowControlsBar()
41     NSImage * _repeatImage;
42     NSImage * _pressedRepeatImage;
43     NSImage * _repeatAllImage;
44     NSImage * _pressedRepeatAllImage;
45     NSImage * _repeatOneImage;
46     NSImage * _pressedRepeatOneImage;
47     NSImage * _shuffleImage;
48     NSImage * _pressedShuffleImage;
49     NSImage * _shuffleOnImage;
50     NSImage * _pressedShuffleOnImage;
52     NSButton * _previousButton;
53     NSButton * _nextButton;
55     BOOL b_show_jump_buttons;
56     BOOL b_show_playmode_buttons;
59 - (void)addJumpButtons:(BOOL)b_fast;
60 - (void)removeJumpButtons:(BOOL)b_fast;
61 - (void)addPlaymodeButtons:(BOOL)b_fast;
62 - (void)removePlaymodeButtons:(BOOL)b_fast;
64 @end
66 @implementation VLCMainWindowControlsBar
68 - (void)awakeFromNib
70     [super awakeFromNib];
72     [self.stopButton setToolTip: _NS("Stop")];
73     [[self.stopButton cell] accessibilitySetOverrideValue:_NS("Click to stop playback.") forAttribute:NSAccessibilityDescriptionAttribute];
74     [[self.stopButton cell] accessibilitySetOverrideValue:[self.stopButton toolTip] forAttribute:NSAccessibilityTitleAttribute];
76     [self.playlistButton setToolTip: _NS("Show/Hide Playlist")];
77     [[self.playlistButton 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];
78     [[self.playlistButton cell] accessibilitySetOverrideValue:[self.playlistButton toolTip] forAttribute:NSAccessibilityTitleAttribute];
80     [self.repeatButton setToolTip: _NS("Repeat")];
81     [[self.repeatButton cell] accessibilitySetOverrideValue:_NS("Click to change repeat mode. There are 3 states: repeat one, repeat all and off.") forAttribute:NSAccessibilityDescriptionAttribute];
82     [[self.repeatButton cell] accessibilitySetOverrideValue:[self.repeatButton toolTip] forAttribute:NSAccessibilityTitleAttribute];
84     [self.shuffleButton setToolTip: _NS("Shuffle")];
85     [[self.shuffleButton cell] accessibilitySetOverrideValue:[self.shuffleButton toolTip] forAttribute:NSAccessibilityTitleAttribute];
86     [[self.shuffleButton cell] accessibilitySetOverrideValue:_NS("Click to enable or disable random playback.") forAttribute:NSAccessibilityDescriptionAttribute];
88     NSString *volumeTooltip = [NSString stringWithFormat:_NS("Volume: %i %%"), 100];
89     [self.volumeSlider setToolTip: volumeTooltip];
90     [[self.volumeSlider cell] accessibilitySetOverrideValue:_NS("Click and move the mouse while keeping the button pressed to use this slider to change the volume.") forAttribute:NSAccessibilityDescriptionAttribute];
91     [[self.volumeSlider cell] accessibilitySetOverrideValue:[self.volumeSlider toolTip] forAttribute:NSAccessibilityTitleAttribute];
92     [self.volumeDownButton setToolTip: _NS("Mute")];
93     [[self.volumeDownButton cell] accessibilitySetOverrideValue:_NS("Click to mute or unmute the audio.") forAttribute:NSAccessibilityDescriptionAttribute];
94     [[self.volumeDownButton cell] accessibilitySetOverrideValue:[self.volumeDownButton toolTip] forAttribute:NSAccessibilityTitleAttribute];
95     [self.volumeUpButton setToolTip: _NS("Full Volume")];
96     [[self.volumeUpButton cell] accessibilitySetOverrideValue:_NS("Click to play the audio at maximum volume.") forAttribute:NSAccessibilityDescriptionAttribute];
97     [[self.volumeUpButton cell] accessibilitySetOverrideValue:[self.volumeUpButton toolTip] forAttribute:NSAccessibilityTitleAttribute];
99     [self.effectsButton setToolTip: _NS("Audio Effects")];
100     [[self.effectsButton cell] accessibilitySetOverrideValue:_NS("Click to show an Audio Effects panel featuring an equalizer and further filters.") forAttribute:NSAccessibilityDescriptionAttribute];
101     [[self.effectsButton cell] accessibilitySetOverrideValue:[self.effectsButton toolTip] forAttribute:NSAccessibilityTitleAttribute];
103     if (!self.darkInterface) {
104         [self.stopButton setImage: imageFromRes(@"stop")];
105         [self.stopButton setAlternateImage: imageFromRes(@"stop-pressed")];
107         [self.playlistButton setImage: imageFromRes(@"playlist-btn")];
108         [self.playlistButton setAlternateImage: imageFromRes(@"playlist-btn-pressed")];
109         _repeatImage = imageFromRes(@"repeat");
110         _pressedRepeatImage = imageFromRes(@"repeat-pressed");
111         _repeatAllImage  = imageFromRes(@"repeat-all");
112         _pressedRepeatAllImage = imageFromRes(@"repeat-all-pressed");
113         _repeatOneImage = imageFromRes(@"repeat-one");
114         _pressedRepeatOneImage = imageFromRes(@"repeat-one-pressed");
115         _shuffleImage = imageFromRes(@"shuffle");
116         _pressedShuffleImage = imageFromRes(@"shuffle-pressed");
117         _shuffleOnImage = imageFromRes(@"shuffle-blue");
118         _pressedShuffleOnImage = imageFromRes(@"shuffle-blue-pressed");
120         [self.volumeDownButton setImage: imageFromRes(@"volume-low")];
121         [self.volumeTrackImageView setImage: imageFromRes(@"volume-slider-track")];
122         [self.volumeUpButton setImage: imageFromRes(@"volume-high")];
123         [self.volumeSlider setUsesBrightArtwork: YES];
125         if (self.nativeFullscreenMode) {
126             [self.effectsButton setImage: imageFromRes(@"effects-one-button")];
127             [self.effectsButton setAlternateImage: imageFromRes(@"effects-one-button-pressed")];
128         } else {
129             [self.effectsButton setImage: imageFromRes(@"effects-double-buttons")];
130             [self.effectsButton setAlternateImage: imageFromRes(@"effects-double-buttons-pressed")];
131         }
133         [self.fullscreenButton setImage: imageFromRes(@"fullscreen-double-buttons")];
134         [self.fullscreenButton setAlternateImage: imageFromRes(@"fullscreen-double-buttons-pressed")];
135     } else {
136         [self.stopButton setImage: imageFromRes(@"stop_dark")];
137         [self.stopButton setAlternateImage: imageFromRes(@"stop-pressed_dark")];
139         [self.playlistButton setImage: imageFromRes(@"playlist_dark")];
140         [self.playlistButton setAlternateImage: imageFromRes(@"playlist-pressed_dark")];
141         _repeatImage = imageFromRes(@"repeat_dark");
142         _pressedRepeatImage = imageFromRes(@"repeat-pressed_dark");
143         _repeatAllImage  = imageFromRes(@"repeat-all-blue_dark");
144         _pressedRepeatAllImage = imageFromRes(@"repeat-all-blue-pressed_dark");
145         _repeatOneImage = imageFromRes(@"repeat-one-blue_dark");
146         _pressedRepeatOneImage = imageFromRes(@"repeat-one-blue-pressed_dark");
147         _shuffleImage = imageFromRes(@"shuffle_dark");
148         _pressedShuffleImage = imageFromRes(@"shuffle-pressed_dark");
149         _shuffleOnImage = imageFromRes(@"shuffle-blue_dark");
150         _pressedShuffleOnImage = imageFromRes(@"shuffle-blue-pressed_dark");
152         [self.volumeDownButton setImage: imageFromRes(@"volume-low_dark")];
153         [self.volumeTrackImageView setImage: imageFromRes(@"volume-slider-track_dark")];
154         [self.volumeUpButton setImage: imageFromRes(@"volume-high_dark")];
155         [self.volumeSlider setUsesBrightArtwork: NO];
157         if (self.nativeFullscreenMode) {
158             [self.effectsButton setImage: imageFromRes(@"effects-one-button_dark")];
159             [self.effectsButton setAlternateImage: imageFromRes(@"effects-one-button-pressed-dark")];
160         } else {
161             [self.effectsButton setImage: imageFromRes(@"effects-double-buttons_dark")];
162             [self.effectsButton setAlternateImage: imageFromRes(@"effects-double-buttons-pressed_dark")];
163         }
165         [self.fullscreenButton setImage: imageFromRes(@"fullscreen-double-buttons_dark")];
166         [self.fullscreenButton setAlternateImage: imageFromRes(@"fullscreen-double-buttons-pressed_dark")];
167     }
168     [self.repeatButton setImage: _repeatImage];
169     [self.repeatButton setAlternateImage: _pressedRepeatImage];
170     [self.shuffleButton setImage: _shuffleImage];
171     [self.shuffleButton setAlternateImage: _pressedShuffleImage];
173     BOOL b_mute = ![[VLCCoreInteraction sharedInstance] mute];
174     [self.volumeSlider setEnabled: b_mute];
175     [self.volumeSlider setMaxValue: [[VLCCoreInteraction sharedInstance] maxVolume]];
176     [self.volumeUpButton setEnabled: b_mute];
178     // remove fullscreen button for lion fullscreen
179     if (self.nativeFullscreenMode) {
180         NSRect frame;
182         // == [fullscreenButton frame].size.width;
183         // button is already removed!
184         float f_width = 29.;
185 #define moveItem(item) \
186 frame = [item frame]; \
187 frame.origin.x = f_width + frame.origin.x; \
188 [item setFrame: frame]
190         moveItem(self.effectsButton);
191         moveItem(self.volumeUpButton);
192         moveItem(self.volumeSlider);
193         moveItem(self.volumeTrackImageView);
194         moveItem(self.volumeDownButton);
195 #undef moveItem
197         // time field and progress bar are moved in super method!
198     }
201     b_show_jump_buttons = config_GetInt(getIntf(), "macosx-show-playback-buttons");
202     if (b_show_jump_buttons)
203         [self addJumpButtons:YES];
205     b_show_playmode_buttons = config_GetInt(getIntf(), "macosx-show-playmode-buttons");
206     if (!b_show_playmode_buttons)
207         [self removePlaymodeButtons:YES];
209     if (!config_GetInt(getIntf(), "macosx-show-effects-button"))
210         [self removeEffectsButton:YES];
212     [[[VLCMain sharedInstance] playlist] playbackModeUpdated];
216 #pragma mark -
217 #pragma mark interface customization
220 - (void)toggleEffectsButton
222     if (config_GetInt(getIntf(), "macosx-show-effects-button"))
223         [self addEffectsButton:NO];
224     else
225         [self removeEffectsButton:NO];
228 - (void)addEffectsButton:(BOOL)b_fast
230     if (!self.effectsButton)
231         return;
233     if (b_fast) {
234         [self.effectsButton setHidden: NO];
235     } else {
236         [[self.effectsButton animator] setHidden: NO];
237     }
239 #define moveItem(item) \
240 frame = [item frame]; \
241 frame.origin.x = frame.origin.x - f_space; \
242 if (b_fast) \
243 [item setFrame: frame]; \
244 else \
245 [[item animator] setFrame: frame]
247     NSRect frame;
248     CGFloat f_space = [self.effectsButton frame].size.width;
249     // extra margin between button and volume up button
250     if (self.nativeFullscreenMode)
251         f_space += 2;
254     moveItem(self.volumeUpButton);
255     moveItem(self.volumeSlider);
256     moveItem(self.volumeTrackImageView);
257     moveItem(self.volumeDownButton);
258     moveItem(self.timeField);
259 #undef moveItem
262     frame = [self.progressView frame];
263     frame.size.width = frame.size.width - f_space;
264     if (b_fast)
265         [self.progressView setFrame: frame];
266     else
267         [[self.progressView animator] setFrame: frame];
269     if (!self.nativeFullscreenMode) {
270         if (self.darkInterface) {
271             [self.fullscreenButton setImage: imageFromRes(@"fullscreen-double-buttons_dark")];
272             [self.fullscreenButton setAlternateImage: imageFromRes(@"fullscreen-double-buttons-pressed_dark")];
273         } else {
274             [self.fullscreenButton setImage: imageFromRes(@"fullscreen-double-buttons")];
275             [self.fullscreenButton setAlternateImage: imageFromRes(@"fullscreen-double-buttons-pressed")];
276         }
277     }
279     [self.bottomBarView setNeedsDisplay:YES];
282 - (void)removeEffectsButton:(BOOL)b_fast
284     if (!self.effectsButton)
285         return;
287     [self.effectsButton setHidden: YES];
289 #define moveItem(item) \
290 frame = [item frame]; \
291 frame.origin.x = frame.origin.x + f_space; \
292 if (b_fast) \
293 [item setFrame: frame]; \
294 else \
295 [[item animator] setFrame: frame]
297     NSRect frame;
298     CGFloat f_space = [self.effectsButton frame].size.width;
299     // extra margin between button and volume up button
300     if (self.nativeFullscreenMode)
301         f_space += 2;
303     moveItem(self.volumeUpButton);
304     moveItem(self.volumeSlider);
305     moveItem(self.volumeTrackImageView);
306     moveItem(self.volumeDownButton);
307     moveItem(self.timeField);
308 #undef moveItem
311     frame = [self.progressView frame];
312     frame.size.width = frame.size.width + f_space;
313     if (b_fast)
314         [self.progressView setFrame: frame];
315     else
316         [[self.progressView animator] setFrame: frame];
318     if (!self.nativeFullscreenMode) {
319         if (self.darkInterface) {
320             [[self.fullscreenButton animator] setImage: imageFromRes(@"fullscreen-one-button_dark")];
321             [[self.fullscreenButton animator] setAlternateImage: imageFromRes(@"fullscreen-one-button-pressed_dark")];
322         } else {
323             [[self.fullscreenButton animator] setImage: imageFromRes(@"fullscreen-one-button")];
324             [[self.fullscreenButton animator] setAlternateImage: imageFromRes(@"fullscreen-one-button-pressed")];
325         }
326     }
328     [self.bottomBarView setNeedsDisplay:YES];
331 - (void)toggleJumpButtons
333     b_show_jump_buttons = config_GetInt(getIntf(), "macosx-show-playback-buttons");
335     if (b_show_jump_buttons)
336         [self addJumpButtons:NO];
337     else
338         [self removeJumpButtons:NO];
341 - (void)addJumpButtons:(BOOL)b_fast
343     NSRect preliminaryFrame = [self.backwardButton frame];
344     BOOL b_enabled = [self.backwardButton isEnabled];
345     preliminaryFrame.size.width = 29.;
346     _previousButton = [[NSButton alloc] initWithFrame:preliminaryFrame];
347     [_previousButton setButtonType: NSMomentaryChangeButton];
348     [_previousButton setBezelStyle:NSRegularSquareBezelStyle];
349     [_previousButton setBordered:NO];
350     [_previousButton setTarget:self];
351     [_previousButton setAction:@selector(prev:)];
352     [_previousButton setToolTip: _NS("Previous")];
353     [[_previousButton cell] accessibilitySetOverrideValue:_NS("Previous") forAttribute:NSAccessibilityTitleAttribute];
354     [[_previousButton cell] accessibilitySetOverrideValue:_NS("Click to go to the previous playlist item.") forAttribute:NSAccessibilityDescriptionAttribute];
355     [_previousButton setEnabled: b_enabled];
357     _nextButton = [[NSButton alloc] initWithFrame:preliminaryFrame];
358     [_nextButton setButtonType: NSMomentaryChangeButton];
359     [_nextButton setBezelStyle:NSRegularSquareBezelStyle];
360     [_nextButton setBordered:NO];
361     [_nextButton setTarget:self];
362     [_nextButton setAction:@selector(next:)];
363     [_nextButton setToolTip: _NS("Next")];
364     [[_nextButton cell] accessibilitySetOverrideValue:_NS("Next") forAttribute:NSAccessibilityTitleAttribute];
365     [[_nextButton cell] accessibilitySetOverrideValue:_NS("Click to go to the next playlist item.") forAttribute:NSAccessibilityDescriptionAttribute];
366     [_nextButton setEnabled: b_enabled];
368     if (self.darkInterface) {
369         [_previousButton setImage: imageFromRes(@"previous-6btns-dark")];
370         [_previousButton setAlternateImage: imageFromRes(@"previous-6btns-dark-pressed")];
371         [_nextButton setImage: imageFromRes(@"next-6btns-dark")];
372         [_nextButton setAlternateImage: imageFromRes(@"next-6btns-dark-pressed")];
373     } else {
374         [_previousButton setImage: imageFromRes(@"previous-6btns")];
375         [_previousButton setAlternateImage: imageFromRes(@"previous-6btns-pressed")];
376         [_nextButton setImage: imageFromRes(@"next-6btns")];
377         [_nextButton setAlternateImage: imageFromRes(@"next-6btns-pressed")];
378     }
380     NSRect frame;
381     frame = [self.backwardButton frame];
382     frame.size.width--;
383     [self.backwardButton setFrame:frame];
384     frame = [self.forwardButton frame];
385     frame.size.width--;
386     [self.forwardButton setFrame:frame];
388 #define moveItem(item) \
389 frame = [item frame]; \
390 frame.origin.x = frame.origin.x + f_space; \
391 if (b_fast) \
392     [item setFrame: frame]; \
393 else \
394     [[item animator] setFrame: frame]
396     float f_space = 29.;
397     moveItem(self.backwardButton);
398     f_space = 28.;
399     moveItem(self.playButton);
400     moveItem(self.forwardButton);
401     f_space = 28. * 2;
402     moveItem(self.stopButton);
403     moveItem(self.playlistButton);
404     moveItem(self.repeatButton);
405     moveItem(self.shuffleButton);
406 #undef moveItem
408     frame = [self.progressView frame];
409     frame.size.width = frame.size.width - f_space;
410     frame.origin.x = frame.origin.x + f_space;
411     if (b_fast)
412         [self.progressView setFrame: frame];
413     else
414         [[self.progressView animator] setFrame: frame];
416     if (self.darkInterface) {
417         [[self.forwardButton animator] setImage:imageFromRes(@"forward-6btns-dark")];
418         [[self.forwardButton animator] setAlternateImage:imageFromRes(@"forward-6btns-dark-pressed")];
419         [[self.backwardButton animator] setImage:imageFromRes(@"backward-6btns-dark")];
420         [[self.backwardButton animator] setAlternateImage:imageFromRes(@"backward-6btns-dark-pressed")];
421     } else {
422         [[self.forwardButton animator] setImage:imageFromRes(@"forward-6btns")];
423         [[self.forwardButton animator] setAlternateImage:imageFromRes(@"forward-6btns-pressed")];
424         [[self.backwardButton animator] setImage:imageFromRes(@"backward-6btns")];
425         [[self.backwardButton animator] setAlternateImage:imageFromRes(@"backward-6btns-pressed")];
426     }
428     preliminaryFrame.origin.x = [_previousButton frame].origin.x + [_previousButton frame].size.width + [self.backwardButton frame].size.width + [self.playButton frame].size.width + [self.forwardButton frame].size.width;
429     [_nextButton setFrame: preliminaryFrame];
431     // wait until the animation is done, if displayed
432     if (b_fast) {
433         [self.bottomBarView addSubview:_previousButton];
434         [self.bottomBarView addSubview:_nextButton];
435     } else {
436         [self.bottomBarView performSelector:@selector(addSubview:) withObject:_previousButton afterDelay:.2];
437         [self.bottomBarView performSelector:@selector(addSubview:) withObject:_nextButton afterDelay:.2];
438     }
440     [self toggleForwardBackwardMode: YES];
443 - (void)removeJumpButtons:(BOOL)b_fast
445     if (!_previousButton || !_nextButton)
446         return;
448     if (b_fast) {
449         [_previousButton setHidden: YES];
450         [_nextButton setHidden: YES];
451     } else {
452         [[_previousButton animator] setHidden: YES];
453         [[_nextButton animator] setHidden: YES];
454     }
455     [_previousButton removeFromSuperviewWithoutNeedingDisplay];
456     [_nextButton removeFromSuperviewWithoutNeedingDisplay];
457     _previousButton = nil;
458     _nextButton = nil;
460     NSRect frame;
461     frame = [self.backwardButton frame];
462     frame.size.width++;
463     [self.backwardButton setFrame:frame];
464     frame = [self.forwardButton frame];
465     frame.size.width++;
466     [self.forwardButton setFrame:frame];
468 #define moveItem(item) \
469 frame = [item frame]; \
470 frame.origin.x = frame.origin.x - f_space; \
471 if (b_fast) \
472     [item setFrame: frame]; \
473 else \
474     [[item animator] setFrame: frame]
476     float f_space = 29.;
477     moveItem(self.backwardButton);
478     f_space = 28.;
479     moveItem(self.playButton);
480     moveItem(self.forwardButton);
481     f_space = 28. * 2;
482     moveItem(self.stopButton);
483     moveItem(self.playlistButton);
484     moveItem(self.repeatButton);
485     moveItem(self.shuffleButton);
486 #undef moveItem
488     frame = [self.progressView frame];
489     frame.size.width = frame.size.width + f_space;
490     frame.origin.x = frame.origin.x - f_space;
491     if (b_fast)
492         [self.progressView setFrame: frame];
493     else
494         [[self.progressView animator] setFrame: frame];
496     if (self.darkInterface) {
497         [[self.forwardButton animator] setImage:imageFromRes(@"forward-3btns-dark")];
498         [[self.forwardButton animator] setAlternateImage:imageFromRes(@"forward-3btns-dark-pressed")];
499         [[self.backwardButton animator] setImage:imageFromRes(@"backward-3btns-dark")];
500         [[self.backwardButton animator] setAlternateImage:imageFromRes(@"backward-3btns-dark-pressed")];
501     } else {
502         [[self.forwardButton animator] setImage:imageFromRes(@"forward-3btns")];
503         [[self.forwardButton animator] setAlternateImage:imageFromRes(@"forward-3btns-pressed")];
504         [[self.backwardButton animator] setImage:imageFromRes(@"backward-3btns")];
505         [[self.backwardButton animator] setAlternateImage:imageFromRes(@"backward-3btns-pressed")];
506     }
508     [self toggleForwardBackwardMode: NO];
510     [self.bottomBarView setNeedsDisplay:YES];
513 - (void)togglePlaymodeButtons
515     b_show_playmode_buttons = config_GetInt(getIntf(), "macosx-show-playmode-buttons");
517     if (b_show_playmode_buttons)
518         [self addPlaymodeButtons:NO];
519     else
520         [self removePlaymodeButtons:NO];
523 - (void)addPlaymodeButtons:(BOOL)b_fast
525     NSRect frame;
526     CGFloat f_space = [self.repeatButton frame].size.width + [self.shuffleButton frame].size.width - 6.;
528     if (self.darkInterface) {
529         [[self.playlistButton animator] setImage:imageFromRes(@"playlist_dark")];
530         [[self.playlistButton animator] setAlternateImage:imageFromRes(@"playlist-pressed_dark")];
531     } else {
532         [[self.playlistButton animator] setImage:imageFromRes(@"playlist-btn")];
533         [[self.playlistButton animator] setAlternateImage:imageFromRes(@"playlist-btn-pressed")];
534     }
535     frame = [self.playlistButton frame];
536     frame.size.width--;
537     [self.playlistButton setFrame:frame];
539     if (b_fast) {
540         [self.repeatButton setHidden: NO];
541         [self.shuffleButton setHidden: NO];
542     } else {
543         [[self.repeatButton animator] setHidden: NO];
544         [[self.shuffleButton animator] setHidden: NO];
545     }
547     frame = [self.progressView frame];
548     frame.size.width = frame.size.width - f_space;
549     frame.origin.x = frame.origin.x + f_space;
550     if (b_fast)
551         [self.progressView setFrame: frame];
552     else
553         [[self.progressView animator] setFrame: frame];
556 - (void)removePlaymodeButtons:(BOOL)b_fast
558     NSRect frame;
559     CGFloat f_space = [self.repeatButton frame].size.width + [self.shuffleButton frame].size.width - 6.;
560     [self.repeatButton setHidden: YES];
561     [self.shuffleButton setHidden: YES];
563     if (self.darkInterface) {
564         [[self.playlistButton animator] setImage:imageFromRes(@"playlist-1btn-dark")];
565         [[self.playlistButton animator] setAlternateImage:imageFromRes(@"playlist-1btn-dark-pressed")];
566     } else {
567         [[self.playlistButton animator] setImage:imageFromRes(@"playlist-1btn")];
568         [[self.playlistButton animator] setAlternateImage:imageFromRes(@"playlist-1btn-pressed")];
569     }
570     frame = [self.playlistButton frame];
571     frame.size.width++;
572     [self.playlistButton setFrame:frame];
574     frame = [self.progressView frame];
575     frame.size.width = frame.size.width + f_space;
576     frame.origin.x = frame.origin.x - f_space;
577     if (b_fast)
578         [self.progressView setFrame: frame];
579     else
580         [[self.progressView animator] setFrame: frame];
583 #pragma mark -
584 #pragma mark Extra button actions
586 - (IBAction)stop:(id)sender
588     [[VLCCoreInteraction sharedInstance] stop];
591 // dynamically created next / prev buttons
592 - (IBAction)prev:(id)sender
594     [[VLCCoreInteraction sharedInstance] previous];
597 - (IBAction)next:(id)sender
599     [[VLCCoreInteraction sharedInstance] next];
602 - (void)setRepeatOne
604     [self.repeatButton setImage: _repeatOneImage];
605     [self.repeatButton setAlternateImage: _pressedRepeatOneImage];
608 - (void)setRepeatAll
610     [self.repeatButton setImage: _repeatAllImage];
611     [self.repeatButton setAlternateImage: _pressedRepeatAllImage];
614 - (void)setRepeatOff
616     [self.repeatButton setImage: _repeatImage];
617     [self.repeatButton setAlternateImage: _pressedRepeatImage];
620 - (IBAction)repeat:(id)sender
622     vlc_value_t looping,repeating;
623     intf_thread_t * p_intf = getIntf();
624     playlist_t * p_playlist = pl_Get(p_intf);
626     var_Get(p_playlist, "repeat", &repeating);
627     var_Get(p_playlist, "loop", &looping);
629     if (!repeating.b_bool && !looping.b_bool) {
630         /* was: no repeating at all, switching to Repeat One */
631         [[VLCCoreInteraction sharedInstance] repeatOne];
632         [self setRepeatOne];
633     }
634     else if (repeating.b_bool && !looping.b_bool) {
635         /* was: Repeat One, switching to Repeat All */
636         [[VLCCoreInteraction sharedInstance] repeatAll];
637         [self setRepeatAll];
638     } else {
639         /* was: Repeat All or bug in VLC, switching to Repeat Off */
640         [[VLCCoreInteraction sharedInstance] repeatOff];
641         [self setRepeatOff];
642     }
645 - (void)setShuffle
647     bool b_value;
648     playlist_t *p_playlist = pl_Get(getIntf());
649     b_value = var_GetBool(p_playlist, "random");
651     if (b_value) {
652         [self.shuffleButton setImage: _shuffleOnImage];
653         [self.shuffleButton setAlternateImage: _pressedShuffleOnImage];
654     } else {
655         [self.shuffleButton setImage: _shuffleImage];
656         [self.shuffleButton setAlternateImage: _pressedShuffleImage];
657     }
660 - (IBAction)shuffle:(id)sender
662     [[VLCCoreInteraction sharedInstance] shuffle];
663     [self setShuffle];
666 - (IBAction)togglePlaylist:(id)sender
668     [[[VLCMain sharedInstance] mainWindow] changePlaylistState: psUserEvent];
671 - (IBAction)volumeAction:(id)sender
673     if (sender == self.volumeSlider)
674         [[VLCCoreInteraction sharedInstance] setVolume: [sender intValue]];
675     else if (sender == self.volumeDownButton)
676         [[VLCCoreInteraction sharedInstance] toggleMute];
677     else
678         [[VLCCoreInteraction sharedInstance] setVolume: AOUT_VOLUME_MAX];
681 - (IBAction)effects:(id)sender
683     [[[VLCMain sharedInstance] mainMenu] showAudioEffects: sender];
686 #pragma mark -
687 #pragma mark Extra updaters
689 - (void)updateVolumeSlider
691     int i_volume = [[VLCCoreInteraction sharedInstance] volume];
692     BOOL b_muted = [[VLCCoreInteraction sharedInstance] mute];
694     if (b_muted)
695         i_volume = 0;
697     [self.volumeSlider setIntValue: i_volume];
699     i_volume = (i_volume * 200) / AOUT_VOLUME_MAX;
700     NSString *volumeTooltip = [NSString stringWithFormat:_NS("Volume: %i %%"), i_volume];
701     [self.volumeSlider setToolTip:volumeTooltip];
703     [self.volumeSlider setEnabled: !b_muted];
704     [self.volumeUpButton setEnabled: !b_muted];
707 - (void)updateControls
709     [super updateControls];
711     bool b_input = false;
712     bool b_seekable = false;
713     bool b_plmul = false;
714     bool b_control = false;
715     bool b_chapters = false;
717     playlist_t * p_playlist = pl_Get(getIntf());
719     PL_LOCK;
720     b_plmul = playlist_CurrentSize(p_playlist) > 1;
721     PL_UNLOCK;
723     input_thread_t * p_input = playlist_CurrentInput(p_playlist);
724     if ((b_input = (p_input != NULL))) {
725         /* seekable streams */
726         b_seekable = var_GetBool(p_input, "can-seek");
728         /* check whether slow/fast motion is possible */
729         b_control = var_GetBool(p_input, "can-rate");
731         /* chapters & titles */
732         //FIXME! b_chapters = p_input->stream.i_area_nb > 1;
734         vlc_object_release(p_input);
735     }
737     [self.stopButton setEnabled: b_input];
739     if (b_show_jump_buttons) {
740         [_previousButton setEnabled: (b_seekable || b_plmul || b_chapters)];
741         [_nextButton setEnabled: (b_seekable || b_plmul || b_chapters)];
742     }
744     [[[VLCMain sharedInstance] mainMenu] setRateControlsEnabled: b_control];
747 @end