Commit a0140fe5 authored by David Fuhrmann's avatar David Fuhrmann

macosx: create new classes for all controls bar related code

Now, we have two classes (instantiated from the xib file for each window)
with controls bar stuff:
- VLCControlsBarCommon holds all code common for main and detached window
- VLCMainWindowControlsBar adds code specific for the main window bar

With that, we can avoid all these redundant code for o_detached_*, furthermore
this decouples all detached window control bar stuff from MainWindow.m.

The objects can be accessed through the controlsBar method.
parent b219b338
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -977,6 +977,8 @@
DC769AB8085DF0DB001A838D /* wizard.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = wizard.h; path = ../../../modules/gui/macosx/wizard.h; sourceTree = SOURCE_ROOT; };
DCE7BD0608A5724D007B10AE /* bookmarks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = bookmarks.m; path = ../../../modules/gui/macosx/bookmarks.m; sourceTree = SOURCE_ROOT; };
DCE7BD0708A5724D007B10AE /* bookmarks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bookmarks.h; path = ../../../modules/gui/macosx/bookmarks.h; sourceTree = SOURCE_ROOT; };
E0382C00160BA09E0031D7FF /* ControlsBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ControlsBar.h; path = ../../../modules/gui/macosx/ControlsBar.h; sourceTree = SOURCE_ROOT; };
E0382C01160BA09E0031D7FF /* ControlsBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ControlsBar.m; path = ../../../modules/gui/macosx/ControlsBar.m; sourceTree = SOURCE_ROOT; };
E06CF7F416020F6200C698B7 /* Windows.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Windows.h; path = ../../../modules/gui/macosx/Windows.h; sourceTree = SOURCE_ROOT; };
E06CF7F516020F6200C698B7 /* Windows.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Windows.m; path = ../../../modules/gui/macosx/Windows.m; sourceTree = SOURCE_ROOT; };
F69B0CA702E24F6401A80112 /* English */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.plist.strings; name = English; path = Resources/English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
......@@ -1056,6 +1058,8 @@
CC448A6113B68A0B009F72E0 /* CoreInteraction.m */,
CC448A6213B68A0B009F72E0 /* MainWindow.h */,
CC448A6313B68A0B009F72E0 /* MainWindow.m */,
E0382C00160BA09E0031D7FF /* ControlsBar.h */,
E0382C01160BA09E0031D7FF /* ControlsBar.m */,
CC4A33220F8CB017000FC4A7 /* coredialogs.h */,
CC4A33210F8CB017000FC4A7 /* coredialogs.m */,
5CCED71014C0D4A90057F8D1 /* ExtensionsDialogProvider.h */,
......
/*****************************************************************************
* ControlsBar.h: MacOS X interface module
*****************************************************************************
* Copyright (C) 2012 VLC authors and VideoLAN
* $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.
*****************************************************************************/
#import <Cocoa/Cocoa.h>
#import "CompatibilityFixes.h"
@class VLCFSPanel;
/*****************************************************************************
* VLCControlsBarCommon
*
* Holds all outlets, actions and code common for controls bar in detached
* and in main window.
*****************************************************************************/
@interface VLCControlsBarCommon : NSObject
{
IBOutlet id o_associated_window;
IBOutlet id o_bottombar_view;
IBOutlet id o_play_btn;
IBOutlet id o_bwd_btn;
IBOutlet id o_fwd_btn;
IBOutlet id o_progress_view;
IBOutlet id o_time_sld;
IBOutlet id o_time_sld_fancygradient_view;
IBOutlet id o_time_sld_background;
IBOutlet id o_progress_bar;
IBOutlet id o_time_fld;
IBOutlet id o_fullscreen_btn;
IBOutlet id o_resize_view;
NSImage * o_pause_img;
NSImage * o_pause_pressed_img;
NSImage * o_play_img;
NSImage * o_play_pressed_img;
NSTimeInterval last_fwd_event;
NSTimeInterval last_bwd_event;
BOOL just_triggered_next;
BOOL just_triggered_previous;
BOOL b_nativeFullscreenMode;
BOOL b_dark_interface;
}
@property (readonly) id bottomBarView;
- (IBAction)play:(id)sender;
- (IBAction)bwd:(id)sender;
- (IBAction)fwd:(id)sender;
- (IBAction)timeSliderAction:(id)sender;
- (IBAction)fullscreen:(id)sender;
- (void)updateTimeSlider;
- (void)drawFancyGradientEffectForTimeSlider;
- (void)updateControls;
- (void)setPause;
- (void)setPlay;
- (void)setFullscreenState:(BOOL)b_fullscreen;
@end
/*****************************************************************************
* VLCMainWindowControlsBar
*
* Holds all specific outlets, actions and code for the main window controls bar.
*****************************************************************************/
@interface VLCMainWindowControlsBar : VLCControlsBarCommon
{
IBOutlet id o_stop_btn;
IBOutlet id o_playlist_btn;
IBOutlet id o_repeat_btn;
IBOutlet id o_shuffle_btn;
IBOutlet id o_volume_sld;
IBOutlet id o_volume_track_view;
IBOutlet id o_volume_down_btn;
IBOutlet id o_volume_up_btn;
IBOutlet id o_effects_btn;
NSImage * o_repeat_img;
NSImage * o_repeat_pressed_img;
NSImage * o_repeat_all_img;
NSImage * o_repeat_all_pressed_img;
NSImage * o_repeat_one_img;
NSImage * o_repeat_one_pressed_img;
NSImage * o_shuffle_img;
NSImage * o_shuffle_pressed_img;
NSImage * o_shuffle_on_img;
NSImage * o_shuffle_on_pressed_img;
NSButton * o_prev_btn;
NSButton * o_next_btn;
BOOL b_show_jump_buttons;
BOOL b_show_playmode_buttons;
}
- (IBAction)stop:(id)sender;
- (IBAction)shuffle:(id)sender;
- (IBAction)volumeAction:(id)sender;
- (IBAction)effects:(id)sender;
- (void)setRepeatOne;
- (void)setRepeatAll;
- (void)setRepeatOff;
- (IBAction)repeat:(id)sender;
- (void)setShuffle;
- (IBAction)shuffle:(id)sender;
- (void)toggleJumpButtons;
- (void)togglePlaymodeButtons;
- (void)updateVolumeSlider;
- (void)updateControls;
- (void)updatePosAndTimeInFSPanel:(VLCFSPanel *)o_fspanel;
@end
/*****************************************************************************
* ControlsBar.m: MacOS X interface module
*****************************************************************************
* Copyright (C) 2012 VLC authors and VideoLAN
* $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.
*****************************************************************************/
#import "ControlsBar.h"
#import "intf.h"
#import "CoreInteraction.h"
#import "MainMenu.h"
#import "fspanel.h"
#import <vlc_aout_intf.h>
/*****************************************************************************
* VLCControlsBarCommon
*
* Holds all outlets, actions and code common for controls bar in detached
* and in main window.
*****************************************************************************/
@implementation VLCControlsBarCommon
@synthesize bottomBarView=o_bottombar_view;
- (void)awakeFromNib
{
b_dark_interface = config_GetInt(VLCIntf, "macosx-interfacestyle");
b_nativeFullscreenMode = NO;
#ifdef MAC_OS_X_VERSION_10_7
if (!OSX_SNOW_LEOPARD)
b_nativeFullscreenMode = var_InheritBool(VLCIntf, "macosx-nativefullscreenmode");
#endif
[o_play_btn setToolTip: _NS("Play/Pause")];
[[o_play_btn cell] accessibilitySetOverrideValue:_NS("Click to play or pause the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
[[o_play_btn cell] accessibilitySetOverrideValue:[o_play_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
[o_bwd_btn setToolTip: _NS("Backward")];
[[o_bwd_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the previous playlist item. Hold to skip backward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
[[o_bwd_btn cell] accessibilitySetOverrideValue:[o_bwd_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
[o_fwd_btn setToolTip: _NS("Forward")];
[[o_fwd_btn cell] accessibilitySetOverrideValue:_NS("Click to go to the next playlist item. Hold to skip forward through the current media.") forAttribute:NSAccessibilityDescriptionAttribute];
[[o_fwd_btn cell] accessibilitySetOverrideValue:[o_fwd_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
[o_time_sld setToolTip: _NS("Position")];
[[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];
[[o_time_sld cell] accessibilitySetOverrideValue:[o_time_sld toolTip] forAttribute:NSAccessibilityTitleAttribute];
[o_fullscreen_btn setToolTip: _NS("Toggle Fullscreen mode")];
[[o_fullscreen_btn cell] accessibilitySetOverrideValue:_NS("Click to enable fullscreen video playback.") forAttribute:NSAccessibilityDescriptionAttribute];
[[o_fullscreen_btn cell] accessibilitySetOverrideValue:[o_fullscreen_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
if (!b_dark_interface) {
[o_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottom-background"] middle: [NSImage imageNamed:@"bottom-background"] right: [NSImage imageNamed:@"bottom-background"]];
[o_bwd_btn setImage: [NSImage imageNamed:@"backward-3btns"]];
[o_bwd_btn setAlternateImage: [NSImage imageNamed:@"backward-3btns-pressed"]];
o_play_img = [[NSImage imageNamed:@"play"] retain];
o_play_pressed_img = [[NSImage imageNamed:@"play-pressed"] retain];
o_pause_img = [[NSImage imageNamed:@"pause"] retain];
o_pause_pressed_img = [[NSImage imageNamed:@"pause-pressed"] retain];
[o_fwd_btn setImage: [NSImage imageNamed:@"forward-3btns"]];
[o_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-3btns-pressed"]];
[o_time_sld_background setImagesLeft: [NSImage imageNamed:@"progression-track-wrapper-left"] middle: [NSImage imageNamed:@"progression-track-wrapper-middle"] right: [NSImage imageNamed:@"progression-track-wrapper-right"]];
[o_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progression-fill-left"] middle:[NSImage imageNamed:@"progression-fill-middle"] right:[NSImage imageNamed:@"progression-fill-right"]];
[o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-one-button"]];
[o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-one-button-pressed"]];
} else {
[o_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottomdark-left"] middle: [NSImage imageNamed:@"bottom-background_dark"] right: [NSImage imageNamed:@"bottomdark-right"]];
[o_bwd_btn setImage: [NSImage imageNamed:@"backward-3btns-dark"]];
[o_bwd_btn setAlternateImage: [NSImage imageNamed:@"backward-3btns-dark-pressed"]];
o_play_img = [[NSImage imageNamed:@"play_dark"] retain];
o_play_pressed_img = [[NSImage imageNamed:@"play-pressed_dark"] retain];
o_pause_img = [[NSImage imageNamed:@"pause_dark"] retain];
o_pause_pressed_img = [[NSImage imageNamed:@"pause-pressed_dark"] retain];
[o_fwd_btn setImage: [NSImage imageNamed:@"forward-3btns-dark"]];
[o_fwd_btn setAlternateImage: [NSImage imageNamed:@"forward-3btns-dark-pressed"]];
[o_time_sld_background setImagesLeft: [NSImage imageNamed:@"progression-track-wrapper-left_dark"] middle: [NSImage imageNamed:@"progression-track-wrapper-middle_dark"] right: [NSImage imageNamed:@"progression-track-wrapper-right_dark"]];
[o_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progressbar-fill-left_dark"] middle:[NSImage imageNamed:@"progressbar-fill-middle_dark"] right:[NSImage imageNamed:@"progressbar-fill-right_dark"]];
[o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-one-button-pressed_dark"]];
[o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-one-button-pressed_dark"]];
}
[o_play_btn setImage: o_play_img];
[o_play_btn setAlternateImage: o_play_pressed_img];
[o_time_fld setAlignment: NSCenterTextAlignment];
[o_time_fld setNeedsDisplay:YES];
// prepare time slider fance gradient view
if (!b_dark_interface) {
NSRect frame;
frame = [o_time_sld_fancygradient_view frame];
frame.size.height = frame.size.height - 1;
frame.origin.y = frame.origin.y + 1;
[o_time_sld_fancygradient_view setFrame: frame];
}
NSRect frame;
frame = [o_time_sld_fancygradient_view frame];
frame.size.width = 0;
[o_time_sld_fancygradient_view setFrame: frame];
// hide resize view if necessary
if (!OSX_SNOW_LEOPARD)
[o_resize_view setImage: NULL];
if ([o_associated_window styleMask] & NSResizableWindowMask)
[o_resize_view removeFromSuperviewWithoutNeedingDisplay];
}
#pragma mark -
#pragma mark Button Actions
- (IBAction)play:(id)sender
{
[[VLCCoreInteraction sharedInstance] play];
}
- (void)resetPreviousButton
{
if (([NSDate timeIntervalSinceReferenceDate] - last_bwd_event) >= 0.35) {
// seems like no further event occurred, so let's switch the playback item
[[VLCCoreInteraction sharedInstance] previous];
just_triggered_previous = NO;
}
}
- (void)resetBackwardSkip
{
// the user stopped skipping, so let's allow him to change the item
if (([NSDate timeIntervalSinceReferenceDate] - last_bwd_event) >= 0.35)
just_triggered_previous = NO;
}
- (IBAction)bwd:(id)sender
{
if (!just_triggered_previous) {
just_triggered_previous = YES;
[self performSelector:@selector(resetPreviousButton)
withObject: NULL
afterDelay:0.40];
} else {
if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.16) {
// we just skipped 4 "continous" events, otherwise we are too fast
[[VLCCoreInteraction sharedInstance] backwardExtraShort];
last_bwd_event = [NSDate timeIntervalSinceReferenceDate];
[self performSelector:@selector(resetBackwardSkip)
withObject: NULL
afterDelay:0.40];
}
}
}
- (void)resetNextButton
{
if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) >= 0.35) {
// seems like no further event occurred, so let's switch the playback item
[[VLCCoreInteraction sharedInstance] next];
just_triggered_next = NO;
}
}
- (void)resetForwardSkip
{
// the user stopped skipping, so let's allow him to change the item
if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) >= 0.35)
just_triggered_next = NO;
}
- (IBAction)fwd:(id)sender
{
if (!just_triggered_next) {
just_triggered_next = YES;
[self performSelector:@selector(resetNextButton)
withObject: NULL
afterDelay:0.40];
} else {
if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.16) {
// we just skipped 4 "continous" events, otherwise we are too fast
[[VLCCoreInteraction sharedInstance] forwardExtraShort];
last_fwd_event = [NSDate timeIntervalSinceReferenceDate];
[self performSelector:@selector(resetForwardSkip)
withObject: NULL
afterDelay:0.40];
}
}
}
- (IBAction)timeSliderAction:(id)sender
{
float f_updated;
input_thread_t * p_input;
switch([[NSApp currentEvent] type]) {
case NSLeftMouseUp:
case NSLeftMouseDown:
case NSLeftMouseDragged:
f_updated = [sender floatValue];
break;
default:
return;
}
p_input = pl_CurrentInput(VLCIntf);
if (p_input != NULL) {
vlc_value_t pos;
NSString * o_time;
pos.f_float = f_updated / 10000.;
var_Set(p_input, "position", pos);
[o_time_sld setFloatValue: f_updated];
o_time = [[VLCStringUtility sharedInstance] getCurrentTimeAsString: p_input negative:[o_time_fld timeRemaining]];
[o_time_fld setStringValue: o_time];
vlc_object_release(p_input);
}
}
- (IBAction)fullscreen:(id)sender
{
[[VLCCoreInteraction sharedInstance] toggleFullscreen];
}
#pragma mark -
#pragma mark Updaters
- (void)updateTimeSlider
{
input_thread_t * p_input;
p_input = pl_CurrentInput(VLCIntf);
if (p_input) {
NSString * o_time;
vlc_value_t pos;
float f_updated;
var_Get(p_input, "position", &pos);
f_updated = 10000. * pos.f_float;
[o_time_sld setFloatValue: f_updated];
o_time = [[VLCStringUtility sharedInstance] getCurrentTimeAsString: p_input negative:[o_time_fld timeRemaining]];
mtime_t dur = input_item_GetDuration(input_GetItem(p_input));
if (dur == -1) {
[o_time_sld setEnabled: NO];
[o_time_sld setHidden: YES];
[o_time_sld_fancygradient_view setHidden: YES];
} else {
[o_time_sld setEnabled: YES];
[o_time_sld setHidden: NO];
[o_time_sld_fancygradient_view setHidden: NO];
}
[o_time_fld setStringValue: o_time];
[o_time_fld setNeedsDisplay:YES];
vlc_object_release(p_input);
} else {
[o_time_sld setFloatValue: 0.0];
[o_time_fld setStringValue: @"00:00"];
[o_time_sld setEnabled: NO];
[o_time_sld setHidden: YES];
[o_time_sld_fancygradient_view setHidden: YES];
}
}
- (void)drawFancyGradientEffectForTimeSlider
{
NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
CGFloat f_value = [o_time_sld knobPosition];
if (f_value > 7.5) {
NSRect oldFrame = [o_time_sld_fancygradient_view frame];
if (f_value != oldFrame.size.width) {
if ([o_time_sld_fancygradient_view isHidden])
[o_time_sld_fancygradient_view setHidden: NO];
[o_time_sld_fancygradient_view setFrame: NSMakeRect(oldFrame.origin.x, oldFrame.origin.y, f_value, oldFrame.size.height)];
}
} else {
NSRect frame;
frame = [o_time_sld_fancygradient_view frame];
if (frame.size.width > 0) {
frame.size.width = 0;
[o_time_sld_fancygradient_view setFrame: frame];
}
[o_time_sld_fancygradient_view setHidden: YES];
}
[o_pool release];
}
- (void)updateControls
{
bool b_plmul = false;
bool b_seekable = false;
bool b_chapters = false;
playlist_t * p_playlist = pl_Get(VLCIntf);
PL_LOCK;
b_plmul = playlist_CurrentSize(p_playlist) > 1;
PL_UNLOCK;
input_thread_t * p_input = playlist_CurrentInput(p_playlist);
if (p_input) {
/* seekable streams */
b_seekable = var_GetBool(p_input, "can-seek");
/* chapters & titles */
//FIXME! b_chapters = p_input->stream.i_area_nb > 1;
vlc_object_release(p_input);
}
[o_fwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
[o_bwd_btn setEnabled: (b_seekable || b_plmul || b_chapters)];
}
- (void)setPause
{
[o_play_btn setImage: o_pause_img];
[o_play_btn setAlternateImage: o_pause_pressed_img];
[o_play_btn setToolTip: _NS("Pause")];
}
- (void)setPlay
{
[o_play_btn setImage: o_play_img];
[o_play_btn setAlternateImage: o_play_pressed_img];
[o_play_btn setToolTip: _NS("Play")];
}
- (void)setFullscreenState:(BOOL)b_fullscreen
{
[o_fullscreen_btn setState:b_fullscreen];
}
@end
/*****************************************************************************
* VLCMainWindowControlsBar
*
* Holds all specific outlets, actions and code for the main window controls bar.
*****************************************************************************/
@implementation VLCMainWindowControlsBar
- (void)awakeFromNib
{
[super awakeFromNib];
[o_stop_btn setToolTip: _NS("Stop")];
[[o_stop_btn cell] accessibilitySetOverrideValue:_NS("Click to stop playback.") forAttribute:NSAccessibilityDescriptionAttribute];
[[o_stop_btn cell] accessibilitySetOverrideValue:[o_stop_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
[o_playlist_btn setToolTip: _NS("Show/Hide Playlist")];
[[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];
[[o_playlist_btn cell] accessibilitySetOverrideValue:[o_playlist_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
[o_repeat_btn setToolTip: _NS("Repeat")];
[[o_repeat_btn cell] accessibilitySetOverrideValue:_NS("Click to change repeat mode. There are 3 states: repeat one, repeat all and off.") forAttribute:NSAccessibilityDescriptionAttribute];
[[o_repeat_btn cell] accessibilitySetOverrideValue:[o_repeat_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
[o_shuffle_btn setToolTip: _NS("Shuffle")];
[[o_shuffle_btn cell] accessibilitySetOverrideValue:[o_shuffle_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
[[o_shuffle_btn cell] accessibilitySetOverrideValue:_NS("Click to enable or disable random playback.") forAttribute:NSAccessibilityDescriptionAttribute];
[o_volume_sld setToolTip: _NS("Volume")];
[[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];
[[o_volume_sld cell] accessibilitySetOverrideValue:[o_volume_sld toolTip] forAttribute:NSAccessibilityTitleAttribute];
[o_volume_down_btn setToolTip: _NS("Mute")];
[[o_volume_down_btn cell] accessibilitySetOverrideValue:_NS("Click to mute or unmute the audio.") forAttribute:NSAccessibilityDescriptionAttribute];
[[o_volume_down_btn cell] accessibilitySetOverrideValue:[o_volume_down_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
[o_volume_up_btn setToolTip: _NS("Full Volume")];
[[o_volume_up_btn cell] accessibilitySetOverrideValue:_NS("Click to play the audio at maximum volume.") forAttribute:NSAccessibilityDescriptionAttribute];
[[o_volume_up_btn cell] accessibilitySetOverrideValue:[o_volume_up_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
[o_effects_btn setToolTip: _NS("Effects")];
[[o_effects_btn cell] accessibilitySetOverrideValue:_NS("Click to show an Audio Effects panel featuring an equalizer and further filters.") forAttribute:NSAccessibilityDescriptionAttribute];
[[o_effects_btn cell] accessibilitySetOverrideValue:[o_effects_btn toolTip] forAttribute:NSAccessibilityTitleAttribute];
if (!b_dark_interface) {
[o_stop_btn setImage: [NSImage imageNamed:@"stop"]];
[o_stop_btn setAlternateImage: [NSImage imageNamed:@"stop-pressed"]];