]> git.sesse.net Git - vlc/blobdiff - modules/gui/macosx/misc.m
macosx: add visual markers for 100% of the volume (refs #8628)
[vlc] / modules / gui / macosx / misc.m
index c8db07d877b2cea99ecab1ed1c5c09eeb66c4e81..875f4c50c70180ae1aaf761d91cecce0df50636f 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * misc.m: code not specific to vlc
  *****************************************************************************
- * Copyright (C) 2003-2012 VLC authors and VideoLAN
+ * Copyright (C) 2003-2013 VLC authors and VideoLAN
  * $Id$
  *
  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
@@ -25,6 +25,7 @@
 #import "misc.h"
 #import "intf.h"                                          /* VLCApplication */
 #import "MainWindow.h"
+#import "ControlsBar.h"
 #import "controls.h"
 #import "CoreInteraction.h"
 #import <CoreAudio/CoreAudio.h>
@@ -175,18 +176,33 @@ static NSMutableArray *blackoutWindows = NULL;
     NSUInteger count = [[NSScreen screens] count];
 
     for ( NSUInteger i = 0; i < count; i++ ) {
-        NSScreen *screen = [[NSScreen screens] objectAtIndex: i];
+        NSScreen *screen = [[NSScreen screens] objectAtIndex:i];
         if ([screen displayID] == displayID)
             return screen;
     }
     return nil;
 }
 
-- (BOOL)mainScreen
+- (BOOL)hasMenuBar
 {
     return ([self displayID] == [[[NSScreen screens] objectAtIndex:0] displayID]);
 }
 
+- (BOOL)hasDock
+{
+    NSRect screen_frame = [self frame];
+    NSRect screen_visible_frame = [self visibleFrame];
+    CGFloat f_menu_bar_thickness = [self hasMenuBar] ? [[NSStatusBar systemStatusBar] thickness] : 0.0;
+
+    BOOL b_found_dock = NO;
+    if (screen_visible_frame.size.width < screen_frame.size.width)
+        b_found_dock = YES;
+    else if (screen_visible_frame.size.height + f_menu_bar_thickness < screen_frame.size.height)
+        b_found_dock = YES;
+
+    return b_found_dock;
+}
+
 - (BOOL)isScreen: (NSScreen*)screen
 {
     return ([self displayID] == [screen displayID]);
@@ -205,7 +221,7 @@ static NSMutableArray *blackoutWindows = NULL;
 
     NSUInteger screenCount = [[NSScreen screens] count];
     for (NSUInteger i = 0; i < screenCount; i++) {
-        NSScreen *screen = [[NSScreen screens] objectAtIndex: i];
+        NSScreen *screen = [[NSScreen screens] objectAtIndex:i];
         VLCWindow *blackoutWindow;
         NSRect screen_rect;
 
@@ -230,8 +246,7 @@ static NSMutableArray *blackoutWindows = NULL;
         [blackoutWindows addObject: blackoutWindow];
         [blackoutWindow release];
 
-        if ( [screen mainScreen] )
-            [NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
+        [screen setFullscreenPresentationOptions];
     }
 }
 
@@ -240,203 +255,30 @@ static NSMutableArray *blackoutWindows = NULL;
     NSUInteger blackoutWindowCount = [blackoutWindows count];
 
     for (NSUInteger i = 0; i < blackoutWindowCount; i++) {
-        VLCWindow *blackoutWindow = [blackoutWindows objectAtIndex: i];
+        VLCWindow *blackoutWindow = [blackoutWindows objectAtIndex:i];
+        [[blackoutWindow screen] setNonFullscreenPresentationOptions];
         [blackoutWindow closeAndAnimate: YES];
     }
-
-    [NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
-}
-
-@end
-
-/*****************************************************************************
- * VLCWindow
- *
- *  Missing extension to NSWindow
- *****************************************************************************/
-
-@implementation VLCWindow
-- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
-    backing:(NSBackingStoreType)backingType defer:(BOOL)flag
-{
-    self = [super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag];
-    if ( self ) {
-        b_isset_canBecomeKeyWindow = NO;
-        /* we don't want this window to be restored on relaunch */
-        if (!OSX_SNOW_LEOPARD)
-            [self setRestorable:NO];
-    }
-    return self;
-}
-
-- (void)setCanBecomeKeyWindow: (BOOL)canBecomeKey
-{
-    b_isset_canBecomeKeyWindow = YES;
-    b_canBecomeKeyWindow = canBecomeKey;
-}
-
-- (BOOL)canBecomeKeyWindow
-{
-    if (b_isset_canBecomeKeyWindow)
-        return b_canBecomeKeyWindow;
-
-    return [super canBecomeKeyWindow];
-}
-
-- (void)setCanBecomeMainWindow: (BOOL)canBecomeMain
-{
-    b_isset_canBecomeMainWindow = YES;
-    b_canBecomeMainWindow = canBecomeMain;
-}
-
-- (BOOL)canBecomeMainWindow
-{
-    if (b_isset_canBecomeMainWindow)
-        return b_canBecomeMainWindow;
-
-    return [super canBecomeMainWindow];
-}
-
-- (void)closeAndAnimate: (BOOL)animate
-{
-    NSInvocation *invoc;
-
-    if (!animate) {
-        [super close];
-        return;
-    }
-
-    invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(close)]];
-    [invoc setTarget: self];
-
-    if (![self isVisible] || [self alphaValue] == 0.0) {
-        [super close];
-        return;
-    }
-
-    [self orderOut: self animate: YES callback: invoc];
-}
-
-- (void)orderOut: (id)sender animate: (BOOL)animate
-{
-    NSInvocation *invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(orderOut:)]];
-    [invoc setTarget: self];
-    [invoc setArgument: sender atIndex: 0];
-    [self orderOut: sender animate: animate callback: invoc];
-}
-
-- (void)orderOut: (id)sender animate: (BOOL)animate callback:(NSInvocation *)callback
-{
-    NSViewAnimation *anim;
-    NSViewAnimation *current_anim;
-    NSMutableDictionary *dict;
-
-    if (!animate) {
-        [self orderOut: sender];
-        return;
-    }
-
-    dict = [[NSMutableDictionary alloc] initWithCapacity:2];
-
-    [dict setObject:self forKey:NSViewAnimationTargetKey];
-
-    [dict setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
-    anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
-    [dict release];
-
-    [anim setAnimationBlockingMode:NSAnimationNonblocking];
-    [anim setDuration:0.9];
-    [anim setFrameRate:30];
-    [anim setUserInfo: callback];
-
-    @synchronized(self) {
-        current_anim = self->animation;
-
-        if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeOutEffect && [current_anim isAnimating]) {
-            [anim release];
-        } else {
-            if (current_anim) {
-                [current_anim stopAnimation];
-                [anim setCurrentProgress:1.0-[current_anim currentProgress]];
-                [current_anim release];
-            }
-            else
-                [anim setCurrentProgress:1.0 - [self alphaValue]];
-            self->animation = anim;
-            [self setDelegate: self];
-            [anim startAnimation];
-        }
-    }
 }
 
-- (void)orderFront: (id)sender animate: (BOOL)animate
+- (void)setFullscreenPresentationOptions
 {
-    NSViewAnimation *anim;
-    NSViewAnimation *current_anim;
-    NSMutableDictionary *dict;
-
-    if (!animate) {
-        [super orderFront: sender];
-        [self setAlphaValue: 1.0];
-        return;
-    }
-
-    if (![self isVisible]) {
-        [self setAlphaValue: 0.0];
-        [super orderFront: sender];
-    }
-    else if ([self alphaValue] == 1.0) {
-        [super orderFront: self];
-        return;
-    }
-
-    dict = [[NSMutableDictionary alloc] initWithCapacity:2];
-
-    [dict setObject:self forKey:NSViewAnimationTargetKey];
-
-    [dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
-    anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
-    [dict release];
-
-    [anim setAnimationBlockingMode:NSAnimationNonblocking];
-    [anim setDuration:0.5];
-    [anim setFrameRate:30];
-
-    @synchronized(self) {
-        current_anim = self->animation;
-
-        if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeInEffect && [current_anim isAnimating]) {
-            [anim release];
-        } else {
-            if (current_anim) {
-                [current_anim stopAnimation];
-                [anim setCurrentProgress:1.0 - [current_anim currentProgress]];
-                [current_anim release];
-            }
-            else
-                [anim setCurrentProgress:[self alphaValue]];
-            self->animation = anim;
-            [self setDelegate: self];
-            [self orderFront: sender];
-            [anim startAnimation];
-        }
-    }
-}
-
-- (void)animationDidEnd:(NSAnimation*)anim
-{
-    if ([self alphaValue] <= 0.0) {
-        NSInvocation * invoc;
-        [super orderOut: nil];
-        [self setAlphaValue: 1.0];
-        if ((invoc = [anim userInfo]))
-            [invoc invoke];
-    }
+    NSApplicationPresentationOptions presentationOpts = [NSApp presentationOptions];
+    if ([self hasMenuBar])
+        presentationOpts |= NSApplicationPresentationAutoHideMenuBar;
+    if ([self hasMenuBar] || [self hasDock])
+        presentationOpts |= NSApplicationPresentationAutoHideDock;
+    [NSApp setPresentationOptions:presentationOpts];
 }
 
-- (IBAction)fullscreen:(id)sender
+- (void)setNonFullscreenPresentationOptions
 {
-    [[VLCCoreInteraction sharedInstance] toggleFullscreen];
+    NSApplicationPresentationOptions presentationOpts = [NSApp presentationOptions];
+    if ([self hasMenuBar])
+        presentationOpts &= (~NSApplicationPresentationAutoHideMenuBar);
+    if ([self hasMenuBar] || [self hasDock])
+        presentationOpts &= (~NSApplicationPresentationAutoHideDock);
+    [NSApp setPresentationOptions:presentationOpts];
 }
 
 @end
@@ -460,7 +302,7 @@ static NSMutableArray *blackoutWindows = NULL;
 
 - (void)awakeFromNib
 {
-    [self registerForDraggedTypes:[NSArray arrayWithObject: NSFilenamesPboardType]];
+    [self registerForDraggedTypes:@[NSFilenamesPboardType]];
     [self setImageScaling: NSScaleToFit];
     [self setImageFrameStyle: NSImageFrameNone];
     [self setImageAlignment: NSImageAlignCenter];
@@ -569,6 +411,7 @@ void _drawFrameInRect(NSRect frameRect)
 - (void)scrollWheel:(NSEvent *)o_event
 {
     intf_thread_t * p_intf = VLCIntf;
+    BOOL b_forward = NO;
     CGFloat f_deltaY = [o_event deltaY];
     CGFloat f_deltaX = [o_event deltaX];
 
@@ -582,17 +425,19 @@ void _drawFrameInRect(NSRect frameRect)
     CGFloat f_abs;
     int i_vlckey;
 
-    if (f_delta > 0.0f) {
-        i_vlckey = ACTIONID_JUMP_BACKWARD_EXTRASHORT;
+    if (f_delta > 0.0f)
         f_abs = f_delta;
-    }
     else {
-        i_vlckey = ACTIONID_JUMP_FORWARD_EXTRASHORT;
+        b_forward = YES;
         f_abs = -f_delta;
     }
 
-    for (NSUInteger i = 0; i < (int)(f_abs/4.+1.) && f_abs > 0.05 ; i++)
-        var_SetInteger( p_intf->p_libvlc, "key-action", i_vlckey );
+    for (NSUInteger i = 0; i < (int)(f_abs/4.+1.) && f_abs > 0.05 ; i++) {
+        if (b_forward)
+            [[VLCCoreInteraction sharedInstance] forwardExtraShort];
+        else
+            [[VLCCoreInteraction sharedInstance] backwardExtraShort];
+    }
 }
 
 - (BOOL)acceptsFirstResponder
@@ -644,8 +489,8 @@ void _drawFrameInRect(NSRect frameRect)
 
 - (void)drawRect:(NSRect)rect
 {
-    [[[VLCMain sharedInstance] mainWindow] drawFancyGradientEffectForTimeSlider];
-    msleep( 10000 ); //wait for the gradient to draw completely
+    [[(VLCVideoWindowCommon *)[self window] controlsBar] drawFancyGradientEffectForTimeSlider];
+    msleep(10000); //wait for the gradient to draw completely
 
     /* Draw default to make sure the slider behaves correctly */
     [[NSGraphicsContext currentContext] saveGraphicsState];
@@ -654,15 +499,78 @@ void _drawFrameInRect(NSRect frameRect)
     [[NSGraphicsContext currentContext] restoreGraphicsState];
 
     NSRect knobRect = [[self cell] knobRectFlipped:NO];
-    if (b_dark)
-        knobRect.origin.y+=2;
-    else
-        knobRect.origin.y+=1;
+    knobRect.origin.y+=1;
     [self drawKnobInRect: knobRect];
 }
 
 @end
 
+/*****************************************************************************
+ * VLCVolumeSliderCommon
+ *****************************************************************************/
+
+@implementation VLCVolumeSliderCommon : NSSlider
+
+@synthesize usesBrightArtwork = _usesBrightArtwork;
+
+- (void)scrollWheel:(NSEvent *)o_event
+{
+    intf_thread_t * p_intf = VLCIntf;
+    BOOL b_up = NO;
+    CGFloat f_deltaY = [o_event deltaY];
+    CGFloat f_deltaX = [o_event deltaX];
+
+    if (!OSX_SNOW_LEOPARD && [o_event isDirectionInvertedFromDevice])
+        f_deltaX = -f_deltaX; // optimisation, actually double invertion of f_deltaY here
+    else
+        f_deltaY = -f_deltaY;
+
+    // positive for left / down, negative otherwise
+    CGFloat f_delta = f_deltaX + f_deltaY;
+    CGFloat f_abs;
+    int i_vlckey;
+
+    if (f_delta > 0.0f)
+        f_abs = f_delta;
+    else {
+        b_up = YES;
+        f_abs = -f_delta;
+    }
+
+    for (NSUInteger i = 0; i < (int)(f_abs/4.+1.) && f_abs > 0.05 ; i++) {
+        if (b_up)
+            [[VLCCoreInteraction sharedInstance] volumeUp];
+        else
+            [[VLCCoreInteraction sharedInstance] volumeDown];
+    }
+}
+
+- (void)drawFullVolumeMarker
+{
+    NSRect frame = [self frame];
+
+    NSColor *drawingColor;
+    if (_usesBrightArtwork)
+        drawingColor = [[NSColor whiteColor] colorWithAlphaComponent:.8];
+    else
+        drawingColor = [[NSColor blackColor] colorWithAlphaComponent:.6];
+
+    NSBezierPath* bezierPath = [NSBezierPath bezierPath];
+
+    float fullVolPos = frame.size.width / 2.;
+    [bezierPath moveToPoint:NSMakePoint(fullVolPos, frame.size.height - 3.)];
+    [bezierPath lineToPoint:NSMakePoint(fullVolPos, 3.)];
+    [bezierPath closePath];
+
+    bezierPath.lineWidth = 1.;
+    [drawingColor setStroke];
+    [bezierPath stroke];
+    [drawingColor setFill];
+    [bezierPath fill];
+}
+
+@end
+
 /*****************************************************************************
  * ITSlider
  *****************************************************************************/
@@ -702,40 +610,13 @@ void _drawFrameInRect(NSRect frameRect)
     [super drawRect:rect];
     [[NSGraphicsContext currentContext] restoreGraphicsState];
 
+    [self drawFullVolumeMarker];
+
     NSRect knobRect = [[self cell] knobRectFlipped:NO];
     knobRect.origin.y+=2;
     [self drawKnobInRect: knobRect];
 }
 
-- (void)scrollWheel:(NSEvent *)o_event
-{
-    intf_thread_t * p_intf = VLCIntf;
-    CGFloat f_deltaY = [o_event deltaY];
-    CGFloat f_deltaX = [o_event deltaX];
-
-    if (!OSX_SNOW_LEOPARD && [o_event isDirectionInvertedFromDevice])
-        f_deltaX = -f_deltaX; // optimisation, actually double invertion of f_deltaY here
-    else
-        f_deltaY = -f_deltaY;
-
-    // positive for left / down, negative otherwise
-    CGFloat f_delta = f_deltaX + f_deltaY;
-    CGFloat f_abs;
-    int i_vlckey;
-
-    if (f_delta > 0.0f) {
-        i_vlckey = ACTIONID_VOL_DOWN;
-        f_abs = f_delta;
-    }
-    else {
-        i_vlckey = ACTIONID_VOL_UP;
-        f_abs = -f_delta;
-    }
-
-    for (NSUInteger i = 0; i < (int)(f_abs/4.+1.) && f_abs > 0.05 ; i++)
-        var_SetInteger( p_intf->p_libvlc, "key-action", i_vlckey );
-}
-
 @end
 
 /*****************************************************************************
@@ -747,21 +628,28 @@ void _drawFrameInRect(NSRect frameRect)
 @implementation VLCTimeField
 + (void)initialize{
     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
-    NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:@"NO" forKey:@"DisplayTimeAsTimeRemaining"];
-
+    NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
+                                 @"NO", @"DisplayTimeAsTimeRemaining",
+                                 @"YES", @"DisplayFullscreenTimeAsTimeRemaining",
+                                 nil];
+    
     [defaults registerDefaults:appDefaults];
 }
 
-- (void)awakeFromNib
+- (id)initWithFrame:(NSRect)frameRect
 {
-    NSColor *o_string_color;
-    if (!config_GetInt( VLCIntf, "macosx-interfacestyle"))
-        o_string_color = [NSColor colorWithCalibratedRed:0.229 green:0.229 blue:0.229 alpha:100.0];
-    else
-        o_string_color = [NSColor colorWithCalibratedRed:0.64 green:0.64 blue:0.64 alpha:100.0];
+    if (self = [super initWithFrame:frameRect]) {
+        textAlignment = NSCenterTextAlignment;
+        o_remaining_identifier = @"";
+    }
+    
+    return self;
+}
 
-    textAlignment = NSCenterTextAlignment;
-    o_string_attributes_dict = [[NSDictionary dictionaryWithObjectsAndKeys: o_string_color, NSForegroundColorAttributeName, [NSFont titleBarFontOfSize:10.0], NSFontAttributeName, nil] retain];
+- (void)setRemainingIdentifier:(NSString *)o_string
+{
+    o_remaining_identifier = o_string;
+    b_time_remaining = [[NSUserDefaults standardUserDefaults] boolForKey:o_remaining_identifier];
 }
 
 - (void)setAlignment:(NSTextAlignment)alignment
@@ -773,7 +661,6 @@ void _drawFrameInRect(NSRect frameRect)
 - (void)dealloc
 {
     [o_string_shadow release];
-    [o_string_attributes_dict release];
     [super dealloc];
 }
 
@@ -782,11 +669,11 @@ void _drawFrameInRect(NSRect frameRect)
     if (!o_string_shadow) {
         o_string_shadow = [[NSShadow alloc] init];
         [o_string_shadow setShadowColor: [NSColor colorWithCalibratedWhite:1.0 alpha:0.5]];
-        [o_string_shadow setShadowOffset:NSMakeSize(0.0, -1.5)];
+        [o_string_shadow setShadowOffset:NSMakeSize(0.0, -1.0)];
         [o_string_shadow setShadowBlurRadius:0.0];
     }
 
-    NSMutableAttributedString *o_attributed_string = [[NSMutableAttributedString alloc] initWithString:string attributes: o_string_attributes_dict];
+    NSMutableAttributedString *o_attributed_string = [[NSMutableAttributedString alloc] initWithString:string attributes: nil];
     NSUInteger i_stringLength = [string length];
 
     [o_attributed_string addAttribute: NSShadowAttributeName value: o_string_shadow range: NSMakeRange(0, i_stringLength)];
@@ -801,17 +688,29 @@ void _drawFrameInRect(NSRect frameRect)
         [[[VLCMain sharedInstance] controls] goToSpecificTime: nil];
     else
     {
-        if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DisplayTimeAsTimeRemaining"])
-            [[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:@"DisplayTimeAsTimeRemaining"];
-        else
-            [[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:@"DisplayTimeAsTimeRemaining"];
+        if (![o_remaining_identifier isEqualToString: @""]) {
+            if ([[NSUserDefaults standardUserDefaults] boolForKey:o_remaining_identifier]) {
+                [[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:o_remaining_identifier];
+                b_time_remaining = NO;
+            } else {
+                [[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:o_remaining_identifier];
+                b_time_remaining = YES;
+            }
+        } else {
+            b_time_remaining = !b_time_remaining;
+            [[NSUserDefaults standardUserDefaults] setObject:(b_time_remaining ? @"YES" : @"NO") forKey:o_remaining_identifier];
+        }
     }
 }
 
 - (BOOL)timeRemaining
 {
-    return [[NSUserDefaults standardUserDefaults] boolForKey:@"DisplayTimeAsTimeRemaining"];
+    if (![o_remaining_identifier isEqualToString: @""])
+        return [[NSUserDefaults standardUserDefaults] boolForKey:o_remaining_identifier];
+    else
+        return b_time_remaining;
 }
+
 @end
 
 /*****************************************************************************
@@ -885,7 +784,7 @@ void _drawFrameInRect(NSRect frameRect)
 
 - (void)awakeFromNib
 {
-    [self registerForDraggedTypes:[NSArray arrayWithObject: NSFilenamesPboardType]];
+    [self registerForDraggedTypes:@[NSFilenamesPboardType]];
 }
 
 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
@@ -915,4 +814,46 @@ void _drawFrameInRect(NSRect frameRect)
     [self setNeedsDisplay:YES];
 }
 
+@end
+
+@implementation PositionFormatter
+
+- (id)init
+{
+    self = [super init];
+    NSMutableCharacterSet *nonNumbers = [[[NSCharacterSet decimalDigitCharacterSet] invertedSet] mutableCopy];
+    [nonNumbers removeCharactersInString:@":"];
+    o_forbidden_characters = [nonNumbers copy];
+    [nonNumbers release];
+
+    return self;
+}
+
+- (void)dealloc
+{
+    [o_forbidden_characters release];
+    [super dealloc];
+}
+
+- (NSString*)stringForObjectValue:(id)obj
+{
+    return obj;
+}
+
+- (BOOL)getObjectValue:(id*)obj forString:(NSString*)string errorDescription:(NSString**)error
+{
+    *obj = [[string copy] autorelease];
+    return YES;
+}
+
+- (bool)isPartialStringValid:(NSString*)partialString newEditingString:(NSString**)newString errorDescription:(NSString**)error
+{
+    if ([partialString rangeOfCharacterFromSet:o_forbidden_characters options:NSLiteralSearch].location != NSNotFound) {
+        return NO;
+    } else {
+        return YES;
+    }
+}
+
+
 @end