VLCMainWindowControlsBar.m 27.7 KB
Newer Older
1 2 3
/*****************************************************************************
 * ControlsBar.m: MacOS X interface module
 *****************************************************************************
4
 * Copyright (C) 2012-2016 VLC authors and VideoLAN
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 * $Id$
 *
 * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
 *          David Fuhrmann <david dot fuhrmann at googlemail dot com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

25 26
#import "VLCControlsBarCommon.h"
#import "VLCMainWindowControlsBar.h"
27
#import "VLCMain.h"
28
#import "VLCCoreInteraction.h"
29
#import "VLCMainMenu.h"
30
#import "VLCPlaylist.h"
31
#import "CompatibilityFixes.h"
32 33 34 35 36 37 38

/*****************************************************************************
 * VLCMainWindowControlsBar
 *
 *  Holds all specific outlets, actions and code for the main window controls bar.
 *****************************************************************************/

39 40
@interface VLCMainWindowControlsBar()
{
41 42 43 44 45 46 47 48 49 50 51 52 53
    NSImage * _repeatImage;
    NSImage * _pressedRepeatImage;
    NSImage * _repeatAllImage;
    NSImage * _pressedRepeatAllImage;
    NSImage * _repeatOneImage;
    NSImage * _pressedRepeatOneImage;
    NSImage * _shuffleImage;
    NSImage * _pressedShuffleImage;
    NSImage * _shuffleOnImage;
    NSImage * _pressedShuffleOnImage;

    NSButton * _previousButton;
    NSButton * _nextButton;
54 55 56 57 58

    BOOL b_show_jump_buttons;
    BOOL b_show_playmode_buttons;
}

59 60 61 62
- (void)addJumpButtons:(BOOL)b_fast;
- (void)removeJumpButtons:(BOOL)b_fast;
- (void)addPlaymodeButtons:(BOOL)b_fast;
- (void)removePlaymodeButtons:(BOOL)b_fast;
63

64 65
@end

66 67 68 69 70 71
@implementation VLCMainWindowControlsBar

- (void)awakeFromNib
{
    [super awakeFromNib];

72 73 74
    [self.stopButton setToolTip: _NS("Stop")];
    [[self.stopButton cell] accessibilitySetOverrideValue:_NS("Click to stop playback.") forAttribute:NSAccessibilityDescriptionAttribute];
    [[self.stopButton cell] accessibilitySetOverrideValue:[self.stopButton toolTip] forAttribute:NSAccessibilityTitleAttribute];
75

76 77 78
    [self.playlistButton setToolTip: _NS("Show/Hide Playlist")];
    [[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];
    [[self.playlistButton cell] accessibilitySetOverrideValue:[self.playlistButton toolTip] forAttribute:NSAccessibilityTitleAttribute];
79

80 81 82
    [self.repeatButton setToolTip: _NS("Repeat")];
    [[self.repeatButton cell] accessibilitySetOverrideValue:_NS("Click to change repeat mode. There are 3 states: repeat one, repeat all and off.") forAttribute:NSAccessibilityDescriptionAttribute];
    [[self.repeatButton cell] accessibilitySetOverrideValue:[self.repeatButton toolTip] forAttribute:NSAccessibilityTitleAttribute];
83

84 85 86
    [self.shuffleButton setToolTip: _NS("Shuffle")];
    [[self.shuffleButton cell] accessibilitySetOverrideValue:[self.shuffleButton toolTip] forAttribute:NSAccessibilityTitleAttribute];
    [[self.shuffleButton cell] accessibilitySetOverrideValue:_NS("Click to enable or disable random playback.") forAttribute:NSAccessibilityDescriptionAttribute];
87

88
    NSString *volumeTooltip = [NSString stringWithFormat:_NS("Volume: %i %%"), 100];
89 90 91 92 93 94 95 96 97 98 99 100 101
    [self.volumeSlider setToolTip: volumeTooltip];
    [[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];
    [[self.volumeSlider cell] accessibilitySetOverrideValue:[self.volumeSlider toolTip] forAttribute:NSAccessibilityTitleAttribute];
    [self.volumeDownButton setToolTip: _NS("Mute")];
    [[self.volumeDownButton cell] accessibilitySetOverrideValue:_NS("Click to mute or unmute the audio.") forAttribute:NSAccessibilityDescriptionAttribute];
    [[self.volumeDownButton cell] accessibilitySetOverrideValue:[self.volumeDownButton toolTip] forAttribute:NSAccessibilityTitleAttribute];
    [self.volumeUpButton setToolTip: _NS("Full Volume")];
    [[self.volumeUpButton cell] accessibilitySetOverrideValue:_NS("Click to play the audio at maximum volume.") forAttribute:NSAccessibilityDescriptionAttribute];
    [[self.volumeUpButton cell] accessibilitySetOverrideValue:[self.volumeUpButton toolTip] forAttribute:NSAccessibilityTitleAttribute];

    [self.effectsButton setToolTip: _NS("Audio Effects")];
    [[self.effectsButton cell] accessibilitySetOverrideValue:_NS("Click to show an Audio Effects panel featuring an equalizer and further filters.") forAttribute:NSAccessibilityDescriptionAttribute];
    [[self.effectsButton cell] accessibilitySetOverrideValue:[self.effectsButton toolTip] forAttribute:NSAccessibilityTitleAttribute];
102

103
    if (!self.darkInterface) {
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
        [self.stopButton setImage: imageFromRes(@"stop")];
        [self.stopButton setAlternateImage: imageFromRes(@"stop-pressed")];

        [self.playlistButton setImage: imageFromRes(@"playlist-btn")];
        [self.playlistButton setAlternateImage: imageFromRes(@"playlist-btn-pressed")];
        _repeatImage = imageFromRes(@"repeat");
        _pressedRepeatImage = imageFromRes(@"repeat-pressed");
        _repeatAllImage  = imageFromRes(@"repeat-all");
        _pressedRepeatAllImage = imageFromRes(@"repeat-all-pressed");
        _repeatOneImage = imageFromRes(@"repeat-one");
        _pressedRepeatOneImage = imageFromRes(@"repeat-one-pressed");
        _shuffleImage = imageFromRes(@"shuffle");
        _pressedShuffleImage = imageFromRes(@"shuffle-pressed");
        _shuffleOnImage = imageFromRes(@"shuffle-blue");
        _pressedShuffleOnImage = imageFromRes(@"shuffle-blue-pressed");

        [self.volumeDownButton setImage: imageFromRes(@"volume-low")];
        [self.volumeTrackImageView setImage: imageFromRes(@"volume-slider-track")];
        [self.volumeUpButton setImage: imageFromRes(@"volume-high")];
        [self.volumeSlider setUsesBrightArtwork: YES];
124

125
        if (self.nativeFullscreenMode) {
126 127
            [self.effectsButton setImage: imageFromRes(@"effects-one-button")];
            [self.effectsButton setAlternateImage: imageFromRes(@"effects-one-button-pressed")];
128
        } else {
129 130
            [self.effectsButton setImage: imageFromRes(@"effects-double-buttons")];
            [self.effectsButton setAlternateImage: imageFromRes(@"effects-double-buttons-pressed")];
131 132
        }

133 134
        [self.fullscreenButton setImage: imageFromRes(@"fullscreen-double-buttons")];
        [self.fullscreenButton setAlternateImage: imageFromRes(@"fullscreen-double-buttons-pressed")];
135
    } else {
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
        [self.stopButton setImage: imageFromRes(@"stop_dark")];
        [self.stopButton setAlternateImage: imageFromRes(@"stop-pressed_dark")];

        [self.playlistButton setImage: imageFromRes(@"playlist_dark")];
        [self.playlistButton setAlternateImage: imageFromRes(@"playlist-pressed_dark")];
        _repeatImage = imageFromRes(@"repeat_dark");
        _pressedRepeatImage = imageFromRes(@"repeat-pressed_dark");
        _repeatAllImage  = imageFromRes(@"repeat-all-blue_dark");
        _pressedRepeatAllImage = imageFromRes(@"repeat-all-blue-pressed_dark");
        _repeatOneImage = imageFromRes(@"repeat-one-blue_dark");
        _pressedRepeatOneImage = imageFromRes(@"repeat-one-blue-pressed_dark");
        _shuffleImage = imageFromRes(@"shuffle_dark");
        _pressedShuffleImage = imageFromRes(@"shuffle-pressed_dark");
        _shuffleOnImage = imageFromRes(@"shuffle-blue_dark");
        _pressedShuffleOnImage = imageFromRes(@"shuffle-blue-pressed_dark");

        [self.volumeDownButton setImage: imageFromRes(@"volume-low_dark")];
        [self.volumeTrackImageView setImage: imageFromRes(@"volume-slider-track_dark")];
        [self.volumeUpButton setImage: imageFromRes(@"volume-high_dark")];
        [self.volumeSlider setUsesBrightArtwork: NO];
156

157
        if (self.nativeFullscreenMode) {
158 159
            [self.effectsButton setImage: imageFromRes(@"effects-one-button_dark")];
            [self.effectsButton setAlternateImage: imageFromRes(@"effects-one-button-pressed-dark")];
160
        } else {
161 162
            [self.effectsButton setImage: imageFromRes(@"effects-double-buttons_dark")];
            [self.effectsButton setAlternateImage: imageFromRes(@"effects-double-buttons-pressed_dark")];
163 164
        }

165 166
        [self.fullscreenButton setImage: imageFromRes(@"fullscreen-double-buttons_dark")];
        [self.fullscreenButton setAlternateImage: imageFromRes(@"fullscreen-double-buttons-pressed_dark")];
167
    }
168 169 170 171
    [self.repeatButton setImage: _repeatImage];
    [self.repeatButton setAlternateImage: _pressedRepeatImage];
    [self.shuffleButton setImage: _shuffleImage];
    [self.shuffleButton setAlternateImage: _pressedShuffleImage];
172 173

    BOOL b_mute = ![[VLCCoreInteraction sharedInstance] mute];
174 175 176
    [self.volumeSlider setEnabled: b_mute];
    [self.volumeSlider setMaxValue: [[VLCCoreInteraction sharedInstance] maxVolume]];
    [self.volumeUpButton setEnabled: b_mute];
177 178

    // remove fullscreen button for lion fullscreen
179
    if (self.nativeFullscreenMode) {
180 181
        NSRect frame;

182
        // == [fullscreenButton frame].size.width;
183 184
        // button is already removed!
        float f_width = 29.;
185 186 187 188 189
#define moveItem(item) \
frame = [item frame]; \
frame.origin.x = f_width + frame.origin.x; \
[item setFrame: frame]

190 191 192 193 194
        moveItem(self.effectsButton);
        moveItem(self.volumeUpButton);
        moveItem(self.volumeSlider);
        moveItem(self.volumeTrackImageView);
        moveItem(self.volumeDownButton);
195 196
#undef moveItem

197
        // time field and progress bar are moved in super method!
198
    }
199

200

201
    b_show_jump_buttons = config_GetInt(getIntf(), "macosx-show-playback-buttons");
202 203 204
    if (b_show_jump_buttons)
        [self addJumpButtons:YES];

205
    b_show_playmode_buttons = config_GetInt(getIntf(), "macosx-show-playmode-buttons");
206 207 208
    if (!b_show_playmode_buttons)
        [self removePlaymodeButtons:YES];

209
    if (!config_GetInt(getIntf(), "macosx-show-effects-button"))
210 211
        [self removeEffectsButton:YES];

212
    [[[VLCMain sharedInstance] playlist] playbackModeUpdated];
213

214 215 216 217 218
}

#pragma mark -
#pragma mark interface customization

219 220 221

- (void)toggleEffectsButton
{
222
    if (config_GetInt(getIntf(), "macosx-show-effects-button"))
223 224 225 226 227 228 229
        [self addEffectsButton:NO];
    else
        [self removeEffectsButton:NO];
}

- (void)addEffectsButton:(BOOL)b_fast
{
230
    if (!self.effectsButton)
231 232 233
        return;

    if (b_fast) {
234
        [self.effectsButton setHidden: NO];
235
    } else {
236
        [[self.effectsButton animator] setHidden: NO];
237 238 239 240 241 242 243 244 245 246 247
    }

#define moveItem(item) \
frame = [item frame]; \
frame.origin.x = frame.origin.x - f_space; \
if (b_fast) \
[item setFrame: frame]; \
else \
[[item animator] setFrame: frame]

    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 252 253
        f_space += 2;


254 255 256 257 258
    moveItem(self.volumeUpButton);
    moveItem(self.volumeSlider);
    moveItem(self.volumeTrackImageView);
    moveItem(self.volumeDownButton);
    moveItem(self.timeField);
259 260 261
#undef moveItem


262
    frame = [self.progressView frame];
263 264
    frame.size.width = frame.size.width - f_space;
    if (b_fast)
265
        [self.progressView setFrame: frame];
266
    else
267
        [[self.progressView animator] setFrame: frame];
268

269 270
    if (!self.nativeFullscreenMode) {
        if (self.darkInterface) {
271 272
            [self.fullscreenButton setImage: imageFromRes(@"fullscreen-double-buttons_dark")];
            [self.fullscreenButton setAlternateImage: imageFromRes(@"fullscreen-double-buttons-pressed_dark")];
273
        } else {
274 275
            [self.fullscreenButton setImage: imageFromRes(@"fullscreen-double-buttons")];
            [self.fullscreenButton setAlternateImage: imageFromRes(@"fullscreen-double-buttons-pressed")];
276 277 278
        }
    }

279
    [self.bottomBarView setNeedsDisplay:YES];
280 281 282 283
}

- (void)removeEffectsButton:(BOOL)b_fast
{
284
    if (!self.effectsButton)
285 286
        return;

287
    [self.effectsButton setHidden: YES];
288 289 290 291 292 293 294 295 296 297

#define moveItem(item) \
frame = [item frame]; \
frame.origin.x = frame.origin.x + f_space; \
if (b_fast) \
[item setFrame: frame]; \
else \
[[item animator] setFrame: frame]

    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 302
        f_space += 2;

303 304 305 306 307
    moveItem(self.volumeUpButton);
    moveItem(self.volumeSlider);
    moveItem(self.volumeTrackImageView);
    moveItem(self.volumeDownButton);
    moveItem(self.timeField);
308 309 310
#undef moveItem


311
    frame = [self.progressView frame];
312 313
    frame.size.width = frame.size.width + f_space;
    if (b_fast)
314
        [self.progressView setFrame: frame];
315
    else
316
        [[self.progressView animator] setFrame: frame];
317

318 319
    if (!self.nativeFullscreenMode) {
        if (self.darkInterface) {
320 321
            [[self.fullscreenButton animator] setImage: imageFromRes(@"fullscreen-one-button_dark")];
            [[self.fullscreenButton animator] setAlternateImage: imageFromRes(@"fullscreen-one-button-pressed_dark")];
322
        } else {
323 324
            [[self.fullscreenButton animator] setImage: imageFromRes(@"fullscreen-one-button")];
            [[self.fullscreenButton animator] setAlternateImage: imageFromRes(@"fullscreen-one-button-pressed")];
325 326 327
        }
    }

328
    [self.bottomBarView setNeedsDisplay:YES];
329 330
}

331 332
- (void)toggleJumpButtons
{
333
    b_show_jump_buttons = config_GetInt(getIntf(), "macosx-show-playback-buttons");
334 335 336 337 338 339 340 341 342

    if (b_show_jump_buttons)
        [self addJumpButtons:NO];
    else
        [self removeJumpButtons:NO];
}

- (void)addJumpButtons:(BOOL)b_fast
{
343 344
    NSRect preliminaryFrame = [self.backwardButton frame];
    BOOL b_enabled = [self.backwardButton isEnabled];
345
    preliminaryFrame.size.width = 29.;
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
    _previousButton = [[NSButton alloc] initWithFrame:preliminaryFrame];
    [_previousButton setButtonType: NSMomentaryChangeButton];
    [_previousButton setBezelStyle:NSRegularSquareBezelStyle];
    [_previousButton setBordered:NO];
    [_previousButton setTarget:self];
    [_previousButton setAction:@selector(prev:)];
    [_previousButton setToolTip: _NS("Previous")];
    [[_previousButton cell] accessibilitySetOverrideValue:_NS("Previous") forAttribute:NSAccessibilityTitleAttribute];
    [[_previousButton cell] accessibilitySetOverrideValue:_NS("Click to go to the previous playlist item.") forAttribute:NSAccessibilityDescriptionAttribute];
    [_previousButton setEnabled: b_enabled];

    _nextButton = [[NSButton alloc] initWithFrame:preliminaryFrame];
    [_nextButton setButtonType: NSMomentaryChangeButton];
    [_nextButton setBezelStyle:NSRegularSquareBezelStyle];
    [_nextButton setBordered:NO];
    [_nextButton setTarget:self];
    [_nextButton setAction:@selector(next:)];
    [_nextButton setToolTip: _NS("Next")];
    [[_nextButton cell] accessibilitySetOverrideValue:_NS("Next") forAttribute:NSAccessibilityTitleAttribute];
    [[_nextButton cell] accessibilitySetOverrideValue:_NS("Click to go to the next playlist item.") forAttribute:NSAccessibilityDescriptionAttribute];
    [_nextButton setEnabled: b_enabled];
367

368
    if (self.darkInterface) {
369 370 371 372
        [_previousButton setImage: imageFromRes(@"previous-6btns-dark")];
        [_previousButton setAlternateImage: imageFromRes(@"previous-6btns-dark-pressed")];
        [_nextButton setImage: imageFromRes(@"next-6btns-dark")];
        [_nextButton setAlternateImage: imageFromRes(@"next-6btns-dark-pressed")];
373
    } else {
374 375 376 377
        [_previousButton setImage: imageFromRes(@"previous-6btns")];
        [_previousButton setAlternateImage: imageFromRes(@"previous-6btns-pressed")];
        [_nextButton setImage: imageFromRes(@"next-6btns")];
        [_nextButton setAlternateImage: imageFromRes(@"next-6btns-pressed")];
378 379 380
    }

    NSRect frame;
381
    frame = [self.backwardButton frame];
382
    frame.size.width--;
383 384
    [self.backwardButton setFrame:frame];
    frame = [self.forwardButton frame];
385
    frame.size.width--;
386
    [self.forwardButton setFrame:frame];
387 388 389 390 391

#define moveItem(item) \
frame = [item frame]; \
frame.origin.x = frame.origin.x + f_space; \
if (b_fast) \
392
    [item setFrame: frame]; \
393
else \
394
    [[item animator] setFrame: frame]
395

396
    float f_space = 29.;
397
    moveItem(self.backwardButton);
398
    f_space = 28.;
399 400
    moveItem(self.playButton);
    moveItem(self.forwardButton);
401
    f_space = 28. * 2;
402 403 404 405
    moveItem(self.stopButton);
    moveItem(self.playlistButton);
    moveItem(self.repeatButton);
    moveItem(self.shuffleButton);
406 407
#undef moveItem

408
    frame = [self.progressView frame];
409 410 411
    frame.size.width = frame.size.width - f_space;
    frame.origin.x = frame.origin.x + f_space;
    if (b_fast)
412
        [self.progressView setFrame: frame];
413
    else
414
        [[self.progressView animator] setFrame: frame];
415

416
    if (self.darkInterface) {
417 418 419 420
        [[self.forwardButton animator] setImage:imageFromRes(@"forward-6btns-dark")];
        [[self.forwardButton animator] setAlternateImage:imageFromRes(@"forward-6btns-dark-pressed")];
        [[self.backwardButton animator] setImage:imageFromRes(@"backward-6btns-dark")];
        [[self.backwardButton animator] setAlternateImage:imageFromRes(@"backward-6btns-dark-pressed")];
421
    } else {
422 423 424 425
        [[self.forwardButton animator] setImage:imageFromRes(@"forward-6btns")];
        [[self.forwardButton animator] setAlternateImage:imageFromRes(@"forward-6btns-pressed")];
        [[self.backwardButton animator] setImage:imageFromRes(@"backward-6btns")];
        [[self.backwardButton animator] setAlternateImage:imageFromRes(@"backward-6btns-pressed")];
426 427
    }

428 429
    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;
    [_nextButton setFrame: preliminaryFrame];
430 431 432

    // wait until the animation is done, if displayed
    if (b_fast) {
433 434
        [self.bottomBarView addSubview:_previousButton];
        [self.bottomBarView addSubview:_nextButton];
435
    } else {
436 437
        [self.bottomBarView performSelector:@selector(addSubview:) withObject:_previousButton afterDelay:.2];
        [self.bottomBarView performSelector:@selector(addSubview:) withObject:_nextButton afterDelay:.2];
438 439
    }

440
    [self toggleForwardBackwardMode: YES];
441 442 443 444
}

- (void)removeJumpButtons:(BOOL)b_fast
{
445
    if (!_previousButton || !_nextButton)
446 447 448
        return;

    if (b_fast) {
449 450
        [_previousButton setHidden: YES];
        [_nextButton setHidden: YES];
451
    } else {
452 453
        [[_previousButton animator] setHidden: YES];
        [[_nextButton animator] setHidden: YES];
454
    }
455 456 457 458
    [_previousButton removeFromSuperviewWithoutNeedingDisplay];
    [_nextButton removeFromSuperviewWithoutNeedingDisplay];
    _previousButton = nil;
    _nextButton = nil;
459 460

    NSRect frame;
461
    frame = [self.backwardButton frame];
462
    frame.size.width++;
463 464
    [self.backwardButton setFrame:frame];
    frame = [self.forwardButton frame];
465
    frame.size.width++;
466
    [self.forwardButton setFrame:frame];
467 468 469 470 471

#define moveItem(item) \
frame = [item frame]; \
frame.origin.x = frame.origin.x - f_space; \
if (b_fast) \
472
    [item setFrame: frame]; \
473
else \
474
    [[item animator] setFrame: frame]
475

476
    float f_space = 29.;
477
    moveItem(self.backwardButton);
478
    f_space = 28.;
479 480
    moveItem(self.playButton);
    moveItem(self.forwardButton);
481
    f_space = 28. * 2;
482 483 484 485
    moveItem(self.stopButton);
    moveItem(self.playlistButton);
    moveItem(self.repeatButton);
    moveItem(self.shuffleButton);
486 487
#undef moveItem

488
    frame = [self.progressView frame];
489 490 491
    frame.size.width = frame.size.width + f_space;
    frame.origin.x = frame.origin.x - f_space;
    if (b_fast)
492
        [self.progressView setFrame: frame];
493
    else
494
        [[self.progressView animator] setFrame: frame];
495

496
    if (self.darkInterface) {
497 498 499 500
        [[self.forwardButton animator] setImage:imageFromRes(@"forward-3btns-dark")];
        [[self.forwardButton animator] setAlternateImage:imageFromRes(@"forward-3btns-dark-pressed")];
        [[self.backwardButton animator] setImage:imageFromRes(@"backward-3btns-dark")];
        [[self.backwardButton animator] setAlternateImage:imageFromRes(@"backward-3btns-dark-pressed")];
501
    } else {
502 503 504 505
        [[self.forwardButton animator] setImage:imageFromRes(@"forward-3btns")];
        [[self.forwardButton animator] setAlternateImage:imageFromRes(@"forward-3btns-pressed")];
        [[self.backwardButton animator] setImage:imageFromRes(@"backward-3btns")];
        [[self.backwardButton animator] setAlternateImage:imageFromRes(@"backward-3btns-pressed")];
506 507
    }

508
    [self toggleForwardBackwardMode: NO];
509

510
    [self.bottomBarView setNeedsDisplay:YES];
511 512 513 514
}

- (void)togglePlaymodeButtons
{
515
    b_show_playmode_buttons = config_GetInt(getIntf(), "macosx-show-playmode-buttons");
516 517 518 519 520 521 522 523 524 525

    if (b_show_playmode_buttons)
        [self addPlaymodeButtons:NO];
    else
        [self removePlaymodeButtons:NO];
}

- (void)addPlaymodeButtons:(BOOL)b_fast
{
    NSRect frame;
526
    CGFloat f_space = [self.repeatButton frame].size.width + [self.shuffleButton frame].size.width - 6.;
527

528
    if (self.darkInterface) {
529 530
        [[self.playlistButton animator] setImage:imageFromRes(@"playlist_dark")];
        [[self.playlistButton animator] setAlternateImage:imageFromRes(@"playlist-pressed_dark")];
531
    } else {
532 533
        [[self.playlistButton animator] setImage:imageFromRes(@"playlist-btn")];
        [[self.playlistButton animator] setAlternateImage:imageFromRes(@"playlist-btn-pressed")];
534
    }
535
    frame = [self.playlistButton frame];
536
    frame.size.width--;
537
    [self.playlistButton setFrame:frame];
538 539

    if (b_fast) {
540 541
        [self.repeatButton setHidden: NO];
        [self.shuffleButton setHidden: NO];
542
    } else {
543 544
        [[self.repeatButton animator] setHidden: NO];
        [[self.shuffleButton animator] setHidden: NO];
545 546
    }

547
    frame = [self.progressView frame];
548 549 550
    frame.size.width = frame.size.width - f_space;
    frame.origin.x = frame.origin.x + f_space;
    if (b_fast)
551
        [self.progressView setFrame: frame];
552
    else
553
        [[self.progressView animator] setFrame: frame];
554 555 556 557 558
}

- (void)removePlaymodeButtons:(BOOL)b_fast
{
    NSRect frame;
559 560 561
    CGFloat f_space = [self.repeatButton frame].size.width + [self.shuffleButton frame].size.width - 6.;
    [self.repeatButton setHidden: YES];
    [self.shuffleButton setHidden: YES];
562

563
    if (self.darkInterface) {
564 565
        [[self.playlistButton animator] setImage:imageFromRes(@"playlist-1btn-dark")];
        [[self.playlistButton animator] setAlternateImage:imageFromRes(@"playlist-1btn-dark-pressed")];
566
    } else {
567 568
        [[self.playlistButton animator] setImage:imageFromRes(@"playlist-1btn")];
        [[self.playlistButton animator] setAlternateImage:imageFromRes(@"playlist-1btn-pressed")];
569
    }
570
    frame = [self.playlistButton frame];
571
    frame.size.width++;
572
    [self.playlistButton setFrame:frame];
573

574
    frame = [self.progressView frame];
575 576 577
    frame.size.width = frame.size.width + f_space;
    frame.origin.x = frame.origin.x - f_space;
    if (b_fast)
578
        [self.progressView setFrame: frame];
579
    else
580
        [[self.progressView animator] setFrame: frame];
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
}

#pragma mark -
#pragma mark Extra button actions

- (IBAction)stop:(id)sender
{
    [[VLCCoreInteraction sharedInstance] stop];
}

// dynamically created next / prev buttons
- (IBAction)prev:(id)sender
{
    [[VLCCoreInteraction sharedInstance] previous];
}

- (IBAction)next:(id)sender
{
    [[VLCCoreInteraction sharedInstance] next];
}

- (void)setRepeatOne
{
604 605
    [self.repeatButton setImage: _repeatOneImage];
    [self.repeatButton setAlternateImage: _pressedRepeatOneImage];
606 607 608 609
}

- (void)setRepeatAll
{
610 611
    [self.repeatButton setImage: _repeatAllImage];
    [self.repeatButton setAlternateImage: _pressedRepeatAllImage];
612 613 614 615
}

- (void)setRepeatOff
{
616 617
    [self.repeatButton setImage: _repeatImage];
    [self.repeatButton setAlternateImage: _pressedRepeatImage];
618 619 620 621 622
}

- (IBAction)repeat:(id)sender
{
    vlc_value_t looping,repeating;
623
    intf_thread_t * p_intf = getIntf();
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
    playlist_t * p_playlist = pl_Get(p_intf);

    var_Get(p_playlist, "repeat", &repeating);
    var_Get(p_playlist, "loop", &looping);

    if (!repeating.b_bool && !looping.b_bool) {
        /* was: no repeating at all, switching to Repeat One */
        [[VLCCoreInteraction sharedInstance] repeatOne];
        [self setRepeatOne];
    }
    else if (repeating.b_bool && !looping.b_bool) {
        /* was: Repeat One, switching to Repeat All */
        [[VLCCoreInteraction sharedInstance] repeatAll];
        [self setRepeatAll];
    } else {
        /* was: Repeat All or bug in VLC, switching to Repeat Off */
        [[VLCCoreInteraction sharedInstance] repeatOff];
        [self setRepeatOff];
    }
}

- (void)setShuffle
{
    bool b_value;
648
    playlist_t *p_playlist = pl_Get(getIntf());
649 650 651
    b_value = var_GetBool(p_playlist, "random");

    if (b_value) {
652 653
        [self.shuffleButton setImage: _shuffleOnImage];
        [self.shuffleButton setAlternateImage: _pressedShuffleOnImage];
654
    } else {
655 656
        [self.shuffleButton setImage: _shuffleImage];
        [self.shuffleButton setAlternateImage: _pressedShuffleImage];
657 658 659 660 661 662 663 664 665
    }
}

- (IBAction)shuffle:(id)sender
{
    [[VLCCoreInteraction sharedInstance] shuffle];
    [self setShuffle];
}

666 667 668 669 670
- (IBAction)togglePlaylist:(id)sender
{
    [[[VLCMain sharedInstance] mainWindow] changePlaylistState: psUserEvent];
}

671 672
- (IBAction)volumeAction:(id)sender
{
673
    if (sender == self.volumeSlider)
674
        [[VLCCoreInteraction sharedInstance] setVolume: [sender intValue]];
675
    else if (sender == self.volumeDownButton)
676 677 678 679 680 681 682
        [[VLCCoreInteraction sharedInstance] toggleMute];
    else
        [[VLCCoreInteraction sharedInstance] setVolume: AOUT_VOLUME_MAX];
}

- (IBAction)effects:(id)sender
{
683
    [[[VLCMain sharedInstance] mainMenu] showAudioEffects: sender];
684 685 686 687 688 689 690 691 692 693
}

#pragma mark -
#pragma mark Extra updaters

- (void)updateVolumeSlider
{
    int i_volume = [[VLCCoreInteraction sharedInstance] volume];
    BOOL b_muted = [[VLCCoreInteraction sharedInstance] mute];

694 695 696
    if (b_muted)
        i_volume = 0;

697
    [self.volumeSlider setIntValue: i_volume];
698 699 700

    i_volume = (i_volume * 200) / AOUT_VOLUME_MAX;
    NSString *volumeTooltip = [NSString stringWithFormat:_NS("Volume: %i %%"), i_volume];
701
    [self.volumeSlider setToolTip:volumeTooltip];
702

703 704
    [self.volumeSlider setEnabled: !b_muted];
    [self.volumeUpButton setEnabled: !b_muted];
705 706 707 708 709 710 711
}

- (void)updateControls
{
    [super updateControls];

    bool b_input = false;
712
    bool b_seekable = false;
713 714 715 716
    bool b_plmul = false;
    bool b_control = false;
    bool b_chapters = false;

717
    playlist_t * p_playlist = pl_Get(getIntf());
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732

    PL_LOCK;
    b_plmul = playlist_CurrentSize(p_playlist) > 1;
    PL_UNLOCK;

    input_thread_t * p_input = playlist_CurrentInput(p_playlist);
    if ((b_input = (p_input != NULL))) {
        /* seekable streams */
        b_seekable = var_GetBool(p_input, "can-seek");

        /* check whether slow/fast motion is possible */
        b_control = var_GetBool(p_input, "can-rate");

        /* chapters & titles */
        //FIXME! b_chapters = p_input->stream.i_area_nb > 1;
733

734 735 736
        vlc_object_release(p_input);
    }

737
    [self.stopButton setEnabled: b_input];
738 739

    if (b_show_jump_buttons) {
740 741
        [_previousButton setEnabled: (b_seekable || b_plmul || b_chapters)];
        [_nextButton setEnabled: (b_seekable || b_plmul || b_chapters)];
742 743
    }

744
    [[[VLCMain sharedInstance] mainMenu] setRateControlsEnabled: b_control];
745 746
}

747
@end