gui/macosx: use input vars instead of controls
[vlc.git] / modules / gui / macosx / VLCControlsBarCommon.m
blob9cc83db12dd8c99252b058f17e6487fd0ed5f187
1 /*****************************************************************************
2  * VLCControlsBarCommon.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 "VLCMain.h"
27 #import "VLCCoreInteraction.h"
28 #import "VLCMainMenu.h"
29 #import "VLCPlaylist.h"
30 #import "CompatibilityFixes.h"
32 /*****************************************************************************
33  * VLCControlsBarCommon
34  *
35  *  Holds all outlets, actions and code common for controls bar in detached
36  *  and in main window.
37  *****************************************************************************/
39 @interface VLCControlsBarCommon ()
41     NSImage * _pauseImage;
42     NSImage * _pressedPauseImage;
43     NSImage * _playImage;
44     NSImage * _pressedPlayImage;
46     NSTimeInterval last_fwd_event;
47     NSTimeInterval last_bwd_event;
48     BOOL just_triggered_next;
49     BOOL just_triggered_previous;
51 @end
53 @implementation VLCControlsBarCommon
55 - (void)awakeFromNib
57     [super awakeFromNib];
58     
59     _nativeFullscreenMode = var_InheritBool(getIntf(), "macosx-nativefullscreenmode");
61     [self.dropView setDrawBorder: NO];
63     [self.playButton setToolTip: _NS("Play")];
64     self.playButton.accessibilityLabel = self.playButton.toolTip;
66     [self.backwardButton setToolTip: _NS("Backward")];
67     self.backwardButton.accessibilityLabel = _NS("Seek backward");
68     self.backwardButton.accessibilityTitle = self.backwardButton.toolTip;
70     [self.forwardButton setToolTip: _NS("Forward")];
71     self.forwardButton.accessibilityLabel = _NS("Seek forward");
72     self.forwardButton.accessibilityTitle = self.forwardButton.toolTip;
74     [self.timeSlider setToolTip: _NS("Position")];
75     self.timeSlider.accessibilityLabel = _NS("Playback position");
76     self.timeSlider.accessibilityTitle = self.timeSlider.toolTip;
78     [self.fullscreenButton setToolTip: _NS("Enter fullscreen")];
79     self.fullscreenButton.accessibilityLabel = self.fullscreenButton.toolTip;
81     [self.backwardButton setImage: imageFromRes(@"backward-3btns")];
82     [self.backwardButton setAlternateImage: imageFromRes(@"backward-3btns-pressed")];
83     _playImage = imageFromRes(@"play");
84     _pressedPlayImage = imageFromRes(@"play-pressed");
85     _pauseImage = imageFromRes(@"pause");
86     _pressedPauseImage = imageFromRes(@"pause-pressed");
87     [self.forwardButton setImage: imageFromRes(@"forward-3btns")];
88     [self.forwardButton setAlternateImage: imageFromRes(@"forward-3btns-pressed")];
90     [self.fullscreenButton setImage: imageFromRes(@"fullscreen-one-button")];
91     [self.fullscreenButton setAlternateImage: imageFromRes(@"fullscreen-one-button-pressed")];
93     [self.playButton setImage: _playImage];
94     [self.playButton setAlternateImage: _pressedPlayImage];
96     NSColor *timeFieldTextColor = [NSColor colorWithCalibratedRed:0.64 green:0.64 blue:0.64 alpha:100.0];
97     [self.timeField setTextColor: timeFieldTextColor];
98     [self.timeField setFont:[NSFont titleBarFontOfSize:10.0]];
99     [self.timeField setAlignment: NSCenterTextAlignment];
100     [self.timeField setNeedsDisplay:YES];
101     [self.timeField setRemainingIdentifier:@"DisplayTimeAsTimeRemaining"];
102     self.timeField.accessibilityLabel = _NS("Playback time");
104     // remove fullscreen button for lion fullscreen
105     if (_nativeFullscreenMode) {
106         self.fullscreenButtonWidthConstraint.constant = 0;
107     }
109     if (config_GetInt("macosx-show-playback-buttons"))
110         [self toggleForwardBackwardMode: YES];
113 - (CGFloat)height
115     return [self.bottomBarView frame].size.height;
118 - (void)toggleForwardBackwardMode:(BOOL)b_alt
120     if (b_alt == YES) {
121         /* change the accessibility help for the backward/forward buttons accordingly */
122         self.backwardButton.accessibilityTitle = _NS("Backward");
123         self.backwardButton.accessibilityLabel = _NS("Seek backward");
125         self.forwardButton.accessibilityTitle = _NS("Forward");
126         self.forwardButton.accessibilityLabel = _NS("Seek forward");
128         [self.forwardButton setAction:@selector(alternateForward:)];
129         [self.backwardButton setAction:@selector(alternateBackward:)];
131     } else {
132         /* change the accessibility help for the backward/forward buttons accordingly */
133         self.backwardButton.accessibilityTitle = _NS("Previous");
134         self.backwardButton.accessibilityLabel = _NS("Go to previous item");
136         self.forwardButton.accessibilityTitle = _NS("Next");
137         self.forwardButton.accessibilityLabel = _NS("Go to next item");
139         [self.forwardButton setAction:@selector(fwd:)];
140         [self.backwardButton setAction:@selector(bwd:)];
141     }
144 #pragma mark -
145 #pragma mark Button Actions
147 - (IBAction)play:(id)sender
149     [[VLCCoreInteraction sharedInstance] playOrPause];
152 - (void)resetPreviousButton
154     if (([NSDate timeIntervalSinceReferenceDate] - last_bwd_event) >= 0.35) {
155         // seems like no further event occurred, so let's switch the playback item
156         [[VLCCoreInteraction sharedInstance] previous];
157         just_triggered_previous = NO;
158     }
161 - (void)resetBackwardSkip
163     // the user stopped skipping, so let's allow him to change the item
164     if (([NSDate timeIntervalSinceReferenceDate] - last_bwd_event) >= 0.35)
165         just_triggered_previous = NO;
168 - (IBAction)bwd:(id)sender
170     if (!just_triggered_previous) {
171         just_triggered_previous = YES;
172         [self performSelector:@selector(resetPreviousButton)
173                    withObject: NULL
174                    afterDelay:0.40];
175     } else {
176         if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.16) {
177             // we just skipped 4 "continous" events, otherwise we are too fast
178             [[VLCCoreInteraction sharedInstance] backwardExtraShort];
179             last_bwd_event = [NSDate timeIntervalSinceReferenceDate];
180             [self performSelector:@selector(resetBackwardSkip)
181                        withObject: NULL
182                        afterDelay:0.40];
183         }
184     }
187 - (void)resetNextButton
189     if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) >= 0.35) {
190         // seems like no further event occurred, so let's switch the playback item
191         [[VLCCoreInteraction sharedInstance] next];
192         just_triggered_next = NO;
193     }
196 - (void)resetForwardSkip
198     // the user stopped skipping, so let's allow him to change the item
199     if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) >= 0.35)
200         just_triggered_next = NO;
203 - (IBAction)fwd:(id)sender
205     if (!just_triggered_next) {
206         just_triggered_next = YES;
207         [self performSelector:@selector(resetNextButton)
208                    withObject: NULL
209                    afterDelay:0.40];
210     } else {
211         if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.16) {
212             // we just skipped 4 "continous" events, otherwise we are too fast
213             [[VLCCoreInteraction sharedInstance] forwardExtraShort];
214             last_fwd_event = [NSDate timeIntervalSinceReferenceDate];
215             [self performSelector:@selector(resetForwardSkip)
216                        withObject: NULL
217                        afterDelay:0.40];
218         }
219     }
222 // alternative actions for forward / backward buttons when next / prev are activated
223 - (IBAction)alternateForward:(id)sender
225     [[VLCCoreInteraction sharedInstance] forwardExtraShort];
228 - (IBAction)alternateBackward:(id)sender
230     [[VLCCoreInteraction sharedInstance] backwardExtraShort];
233 - (IBAction)timeSliderAction:(id)sender
235     float f_updated;
236     input_thread_t * p_input;
238     switch([[NSApp currentEvent] type]) {
239         case NSLeftMouseUp:
240             /* Ignore mouse up, as this is a continous slider and
241              * when the user does a single click to a position on the slider,
242              * the action is called twice, once for the mouse down and once
243              * for the mouse up event. This results in two short seeks one
244              * after another to the same position, which results in weird
245              * audio quirks.
246              */
247             return;
248         case NSLeftMouseDown:
249         case NSLeftMouseDragged:
250             f_updated = [sender floatValue];
251             break;
252         case NSScrollWheel:
253             f_updated = [sender floatValue];
254             break;
256         default:
257             return;
258     }
259     p_input = pl_CurrentInput(getIntf());
260     if (p_input != NULL) {
261         vlc_value_t pos;
262         NSString * o_time;
264         pos.f_float = f_updated / 10000.;
265         var_Set(p_input, "position", pos);
266         [self.timeSlider setFloatValue: f_updated];
268         o_time = [[VLCStringUtility sharedInstance] getCurrentTimeAsString: p_input negative:[self.timeField timeRemaining]];
269         [self.timeField setStringValue: o_time];
270         vlc_object_release(p_input);
271     }
274 - (IBAction)fullscreen:(id)sender
276     [[VLCCoreInteraction sharedInstance] toggleFullscreen];
279 #pragma mark -
280 #pragma mark Updaters
282 - (void)updateTimeSlider
284     input_thread_t * p_input;
285     p_input = pl_CurrentInput(getIntf());
287     [self.timeSlider setHidden:NO];
289     if (!p_input) {
290         // Nothing playing
291         [self.timeSlider setKnobHidden:YES];
292         [self.timeSlider setFloatValue: 0.0];
293         [self.timeField setStringValue: @"00:00"];
294         [self.timeSlider setIndefinite:NO];
295         [self.timeSlider setEnabled:NO];
296         return;
297     }
299     [self.timeSlider setKnobHidden:NO];
301     vlc_value_t pos;
302     var_Get(p_input, "position", &pos);
303     [self.timeSlider setFloatValue:(10000. * pos.f_float)];
305     vlc_tick_t dur = input_item_GetDuration(input_GetItem(p_input));
306     if (dur == -1) {
307         // No duration, disable slider
308         [self.timeSlider setEnabled:NO];
309     } else {
310         input_state_e inputState = var_GetInteger(p_input, "state");
311         bool buffering = (inputState == INIT_S || inputState == OPENING_S);
312         [self.timeSlider setIndefinite:buffering];
313     }
315     NSString *time = [[VLCStringUtility sharedInstance] getCurrentTimeAsString:p_input
316                                                                       negative:[self.timeField timeRemaining]];
317     [self.timeField setStringValue:time];
318     [self.timeField setNeedsDisplay:YES];
320     vlc_object_release(p_input);
323 - (void)updateControls
325     bool b_plmul = false;
326     bool b_seekable = false;
327     bool b_chapters = false;
329     playlist_t * p_playlist = pl_Get(getIntf());
331     PL_LOCK;
332     b_plmul = playlist_CurrentSize(p_playlist) > 1;
333     PL_UNLOCK;
335     input_thread_t * p_input = playlist_CurrentInput(p_playlist);
337     if (p_input) {
338         /* seekable streams */
339         b_seekable = var_GetBool(p_input, "can-seek");
341         /* chapters & titles */
342         //FIXME! b_chapters = p_input->stream.i_area_nb > 1;
344         vlc_object_release(p_input);
345     }
347     [self.timeSlider setEnabled: b_seekable];
349     [self.forwardButton setEnabled: (b_seekable || b_plmul || b_chapters)];
350     [self.backwardButton setEnabled: (b_seekable || b_plmul || b_chapters)];
353 - (void)setPause
355     [self.playButton setImage: _pauseImage];
356     [self.playButton setAlternateImage: _pressedPauseImage];
357     [self.playButton setToolTip: _NS("Pause")];
358     self.playButton.accessibilityLabel = self.playButton.toolTip;
361 - (void)setPlay
363     [self.playButton setImage: _playImage];
364     [self.playButton setAlternateImage: _pressedPlayImage];
365     [self.playButton setToolTip: _NS("Play")];
366     self.playButton.accessibilityLabel = self.playButton.toolTip;
369 - (void)setFullscreenState:(BOOL)b_fullscreen
371     if (!self.nativeFullscreenMode)
372         [self.fullscreenButton setState:b_fullscreen];
375 @end