MacOSX/VLC_app: port the fullscreen zoom and the fspanel from gui/macosx to VLC_app.
[vlc.git] / extras / MacOSX / VLC_app / Sources / VLCFullScreenControllerWindow.m
1 /*****************************************************************************
2  * VLCFullScreenControllerWindow.m: class that allow media controlling in
3  * fullscreen (with the mouse)
4  *****************************************************************************
5  * Copyright (C) 2007 Pierre d'Herbemont
6  * Copyright (C) 2007 the VideoLAN team
7  * $Id: VLCBrowsableVideoView.m 24179 2008-01-07 21:00:49Z pdherbemont $
8  *
9  * Authors:  Jérôme Decoodt <djc at videolan dot org>
10  *           Felix Kühne <fkuehne at videolan dot org>
11  *           Pierre d'Herbemont <pdherbemont # videolan.org>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 #import "VLCFullScreenControllerWindow.h"
29
30 @interface VLCFullScreenControllerWindow (Private)
31 - (void)hide;
32 - (void)show;
33 - (void)updateTrackingRect;
34 @end
35
36 /*****************************************************************************
37  * @implementation VLCFullScreenControllerWindow
38  */
39
40 @implementation VLCFullScreenControllerWindow
41
42 /* We override this initializer so we can set the NSBorderlessWindowMask styleMask, and set a few other important settings */
43 - (id)initWithContentRect:(NSRect)contentRect 
44                 styleMask:(unsigned int)aStyle 
45                   backing:(NSBackingStoreType)bufferingType 
46                     defer:(BOOL)flag
47 {
48     if( self = [super initWithContentRect:contentRect styleMask:NSTexturedBackgroundWindowMask backing:bufferingType defer:flag] )
49     {
50         [self setOpaque:NO];
51         [self setHasShadow: NO];
52         [self setBackgroundColor:[NSColor clearColor]];
53         
54         /* let the window sit on top of everything else and start out completely transparent */
55         [self setLevel:NSFloatingWindowLevel];
56         [self center];
57     }
58     return self;
59 }
60
61 - (void)dealloc
62 {
63     [[NSNotificationCenter defaultCenter] removeObserver:self];
64
65     [hideWindowTimer invalidate];
66     [hideWindowTimer release];
67     [videoViewTrackingArea release];
68     [super dealloc];
69 }
70
71 - (void)awakeFromNib
72 {
73     hideWindowTimer = nil;
74     videoViewTrackingArea = nil;
75
76     [self setMovableByWindowBackground:YES];
77
78     /* Make sure we'll detect when to close the window, see animationDidStop:finished: */
79     CAAnimation *alphaValueAnimation = [CABasicAnimation animation];
80     [alphaValueAnimation setDelegate:self];
81     [self setAnimations:[NSDictionary dictionaryWithObject:alphaValueAnimation forKey:@"alphaValue"]];
82     hideWindowTimer = nil;
83
84     /* WindowView setup */
85     [[mainWindow.videoView window] setAcceptsMouseMovedEvents:YES];
86     [[mainWindow.videoView window] makeFirstResponder:mainWindow.videoView];
87     [mainWindow.videoView setPostsBoundsChangedNotifications: YES];
88     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(videoViewDidChangeBounds:) name:NSViewBoundsDidChangeNotification object:(id)mainWindow.videoView];
89
90     /* Make sure we can know when the mouse is inside us */
91     [[self contentView] addTrackingRect:[[self contentView] bounds] owner:self userData:nil assumeInside:NO];
92
93     /* Bindings connection */
94     /* Sound */
95     [volumeSlider setKnobImage:[NSImage imageNamed:@"fs_volume_slider_knob_highlight.png"]];
96     [volumeSlider setBackgroundImage:[NSImage imageNamed:@"fs_volume_slider_bar.png"]];
97     [volumeSlider setNeedsDisplay:YES];
98     [volumeSlider bind:@"value" toObject:[VLCLibrary sharedLibrary] withKeyPath:@"audio.volume" options: nil];
99
100     /* media position */
101     [mediaPositionSlider setKnobImage:[NSImage imageNamed:@"fs_time_slider_knob.png"]];
102     [mediaPositionSlider setBackgroundImage:[NSImage imageNamed:@"fs_time_slider.png"]];
103     [mediaPositionSlider setNeedsDisplay:YES];
104
105     [mediaPositionSlider bind:@"enabled" toObject:mainWindow.mediaPlayer withKeyPath:@"media" options: [NSDictionary dictionaryWithObject:@"NonNilAsBoolTransformer" forKey:NSValueTransformerNameBindingOption]];
106     [mediaPositionSlider bind:@"enabled2" toObject:mainWindow.mediaPlayer withKeyPath:@"seekable" options: nil];
107
108     [mediaPositionSlider bind:@"value" toObject:mainWindow.mediaPlayer withKeyPath:@"position" options:
109         [NSDictionary dictionaryWithObjectsAndKeys:@"Float10000FoldTransformer", NSValueTransformerNameBindingOption,
110                                                   [NSNumber numberWithBool:NO], NSConditionallySetsEnabledBindingOption, nil ]];
111
112
113     [fillScreenButton bind:@"value" toObject:mainWindow.videoView withKeyPath:@"fillScreen" options: nil];
114     [fullScreenButton bind:@"value" toObject:mainWindow.videoView withKeyPath:@"fullScreen" options: nil];
115
116     [mediaReadingProgressText bind:@"value" toObject:mainWindow.mediaPlayer withKeyPath:@"time.stringValue" options: nil];
117     [mediaDescriptionText bind:@"value" toObject:mainWindow.mediaPlayer withKeyPath:@"description" options: nil];
118
119     /* mediaPlayer */
120     [mediaPlayerPlayPauseStopButton bind:@"enabled" toObject:mainWindow.mediaPlayer withKeyPath:@"media" options: [NSDictionary dictionaryWithObject:@"NonNilAsBoolTransformer" forKey:NSValueTransformerNameBindingOption]];
121     [mediaPlayerPlayPauseStopButton bind:@"state"   toObject:mainWindow.mediaPlayer withKeyPath:@"playing" options: nil];
122     [mediaPlayerPlayPauseStopButton bind:@"alternateImage" toObject:mainWindow.mediaPlayer withKeyPath:@"stateAsFullScreenButtonAlternateImage" options: nil];
123     [mediaPlayerPlayPauseStopButton bind:@"image"   toObject:mainWindow.mediaPlayer withKeyPath:@"stateAsFullScreenButtonImage" options: nil];
124     [mediaPlayerBackwardPrevButton  bind:@"enabled" toObject:mainWindow.mediaPlayer withKeyPath:@"playing" options: nil];
125     [mediaPlayerForwardNextButton   bind:@"enabled" toObject:mainWindow.mediaPlayer withKeyPath:@"playing" options: nil];
126     [mediaPlayerForwardNextButton   setTarget:mainWindow.mediaPlayer];
127     [mediaPlayerForwardNextButton   setAction:@selector(fastForward)];
128     [mediaPlayerBackwardPrevButton  setTarget:mainWindow.mediaPlayer];
129     [mediaPlayerBackwardPrevButton  setAction:@selector(rewind)];
130     [mediaPlayerPlayPauseStopButton setTarget:mainWindow.mediaPlayer];
131     [mediaPlayerPlayPauseStopButton setAction:@selector(pause)];
132
133     [self bind:@"fullScreen" toObject:mainWindow.videoView withKeyPath:@"fullScreen" options: nil];
134     
135     active = NO;
136 }
137
138 - (BOOL)fullScreen
139 {
140     /* Only to comply to KVC */
141     return active;
142 }
143
144 - (void)setFullScreen:(BOOL)fullScreen
145 {
146     if(fullScreen)
147     {
148         active = YES;
149         [self show];
150     }
151     else
152     {
153         [self hide];
154         active = NO;
155     }
156 }
157
158 -(void)center
159 {
160     /* centre the panel in the lower third of the screen */
161     NSPoint theCoordinate;
162     NSRect theScreensFrame;
163     NSRect theWindowsFrame;
164
165     theScreensFrame = [[self screen] frame];
166
167     theWindowsFrame = [self frame];
168     
169     theCoordinate.x = (theScreensFrame.size.width - theWindowsFrame.size.width) / 2 + theScreensFrame.origin.x;
170     theCoordinate.y = (theScreensFrame.size.height / 3) - theWindowsFrame.size.height + theScreensFrame.origin.y;
171     [self setFrameTopLeftPoint: theCoordinate];
172 }
173
174 @end
175
176 /*****************************************************************************
177  * @implementation VLCFullScreenControllerWindow (Private)
178  */
179
180 @implementation VLCFullScreenControllerWindow (Private)
181 - (void)show
182 {
183     if(![self isVisible])
184         self.alphaValue = 0.0;
185
186     if( !NSPointInRect([NSEvent mouseLocation],[self frame]) )
187     {
188         [hideWindowTimer invalidate];
189         [hideWindowTimer release];
190         hideWindowTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(hide) userInfo:nil repeats:NO] retain];
191     }
192     [self orderFront:self];
193     [self.animator setAlphaValue:1.0];
194 }
195
196 - (void)hide
197 {
198     [hideWindowTimer invalidate];
199     [hideWindowTimer release];
200     hideWindowTimer = nil;
201     if ([self isVisible])
202     {
203         [self.animator setAlphaValue:0.0];
204         [NSCursor setHiddenUntilMouseMoves:YES];
205     }
206     [self updateTrackingRect];
207 }
208
209 - (void)updateTrackingRect
210 {
211     VLCVideoView * videoView = mainWindow.videoView;
212
213     if( videoViewTrackingArea )
214     {
215         [videoView removeTrackingArea:videoViewTrackingArea];
216         [videoViewTrackingArea release];
217     }
218     videoViewTrackingArea = [[NSTrackingArea alloc] initWithRect:[videoView bounds] options:NSTrackingMouseMoved|NSTrackingActiveAlways|NSTrackingAssumeInside|NSTrackingEnabledDuringMouseDrag owner:self userInfo:nil];
219     [videoView addTrackingArea:videoViewTrackingArea];
220
221 }
222
223 @end
224
225 /*****************************************************************************
226  * @implementation VLCFullScreenControllerWindow (NSAnimationDelegate)
227  */
228
229 @implementation VLCFullScreenControllerWindow (NSAnimationDelegate)
230 - (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag 
231 {
232     if( self.alphaValue == 0.0 )
233         [self orderOut:self];
234 }
235 @end
236
237 /*****************************************************************************
238  * @implementation VLCFullScreenControllerWindow (NSTrackingRectCallbacksInVideoView)
239  */
240
241 @implementation VLCFullScreenControllerWindow (NSTrackingRectCallbacks)
242 - (void)mouseMoved:(NSEvent *)theEvent
243 {
244     if([theEvent window] != self)
245     {
246         if( active )
247             [self show];
248     }
249 }
250 - (void)mouseEntered:(NSEvent *)theEvent
251 {
252     if([theEvent window] == self)
253     {
254         [hideWindowTimer invalidate];
255         [hideWindowTimer release];
256         hideWindowTimer = nil;
257     }
258 }
259 - (void)mouseExited:(NSEvent *)theEvent
260 {
261     if([theEvent window] == self)
262     {
263         [hideWindowTimer invalidate];
264         [hideWindowTimer release];
265         hideWindowTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(hide) userInfo:nil repeats:NO] retain];
266     }
267     else
268     {
269         if( active )
270             [self hide];
271     }
272 }
273 - (void)cursorUpdate:(NSEvent *)event
274 {
275
276 }
277 @end
278
279 /*****************************************************************************
280  * @implementation VLCFullScreenControllerWindow (VideoViewBoundsChanges)
281  */
282 @implementation VLCFullScreenControllerWindow (VideoViewBoundsChanges)
283 - (void)videoViewDidChangeBounds:(NSNotification *)theNotification
284 {
285     [self updateTrackingRect];
286 }
287
288 @end