misc.m
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:23k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * misc.m: code not specific to vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2003-2009 the VideoLAN team
  5.  * $Id: a7ca58f3b818bd58d2285920b6e4b72f8a486998 $
  6.  *
  7.  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
  8.  *          Felix Paul Kühne <fkuehne at videolan dot org>
  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.  *****************************************************************************/
  24. #import <Cocoa/Cocoa.h>
  25. #import <Carbon/Carbon.h>
  26. #import "intf.h"                                          /* VLCApplication */
  27. #import "misc.h"
  28. #import "playlist.h"
  29. #import "controls.h"
  30. /*****************************************************************************
  31.  * NSImage (VLCAdditions)
  32.  *
  33.  *  Addition to NSImage
  34.  *****************************************************************************/
  35. @implementation NSImage (VLCAdditions)
  36. + (id)imageWithSystemName:(int)name
  37. {
  38.     /* ugly Carbon stuff following...
  39.      * regrettably, you can't get the icons through clean Cocoa */
  40.     /* retrieve our error icon */
  41.     NSImage * icon;
  42.     IconRef ourIconRef;
  43.     int returnValue;
  44.     returnValue = GetIconRef(kOnSystemDisk, 'macs', name, &ourIconRef);
  45.     icon = [[[NSImage alloc] initWithSize:NSMakeSize(32,32)] autorelease];
  46.     [icon lockFocus];
  47.     CGRect rect = CGRectMake(0,0,32,32);
  48.     PlotIconRefInContext((CGContextRef)[[NSGraphicsContext currentContext]
  49.         graphicsPort],
  50.         &rect,
  51.         kAlignNone,
  52.         kTransformNone,
  53.         NULL /*inLabelColor*/,
  54.         kPlotIconRefNormalFlags,
  55.         (IconRef)ourIconRef);
  56.     [icon unlockFocus];
  57.     returnValue = ReleaseIconRef(ourIconRef);
  58.     return icon;
  59. }
  60. + (id)imageWithWarningIcon
  61. {
  62.     static NSImage * imageWithWarningIcon = nil;
  63.     if( !imageWithWarningIcon )
  64.     {
  65.         imageWithWarningIcon = [[[self class] imageWithSystemName:'caut'] retain];
  66.     }
  67.     return imageWithWarningIcon;
  68. }
  69. + (id)imageWithErrorIcon
  70. {
  71.     static NSImage * imageWithErrorIcon = nil;
  72.     if( !imageWithErrorIcon )
  73.     {
  74.         imageWithErrorIcon = [[[self class] imageWithSystemName:'stop'] retain];
  75.     }
  76.     return imageWithErrorIcon;
  77. }
  78. @end
  79. /*****************************************************************************
  80.  * NSAnimation (VLCAdditions)
  81.  *
  82.  *  Missing extension to NSAnimation
  83.  *****************************************************************************/
  84. @implementation NSAnimation (VLCAdditions)
  85. /* fake class attributes  */
  86. static NSMapTable *VLCAdditions_userInfo = nil;
  87. + (void)load
  88. {
  89.     /* init our fake object attribute */
  90.     VLCAdditions_userInfo = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks, NSObjectMapValueCallBacks, 16);
  91. }
  92. - (void)dealloc
  93. {
  94.     NSMapRemove(VLCAdditions_userInfo, self);
  95.     [super dealloc];
  96. }
  97. - (void)setUserInfo: (void *)userInfo
  98. {
  99.     NSMapInsert(VLCAdditions_userInfo, self, (void*)userInfo);
  100. }
  101. - (void *)userInfo
  102. {
  103.     return NSMapGet(VLCAdditions_userInfo, self);
  104. }
  105. @end
  106. /*****************************************************************************
  107.  * NSScreen (VLCAdditions)
  108.  *
  109.  *  Missing extension to NSScreen
  110.  *****************************************************************************/
  111. @implementation NSScreen (VLCAdditions)
  112. static NSMutableArray *blackoutWindows = nil;
  113. + (void)load
  114. {
  115.     /* init our fake object attribute */
  116.     blackoutWindows = [[NSMutableArray alloc] initWithCapacity:1];
  117. }
  118. + (NSScreen *)screenWithDisplayID: (CGDirectDisplayID)displayID
  119. {
  120.     int i;
  121.  
  122.     for( i = 0; i < [[NSScreen screens] count]; i++ )
  123.     {
  124.         NSScreen *screen = [[NSScreen screens] objectAtIndex: i];
  125.         if([screen displayID] == displayID)
  126.             return screen;
  127.     }
  128.     return nil;
  129. }
  130. - (BOOL)isMainScreen
  131. {
  132.     return ([self displayID] == [[[NSScreen screens] objectAtIndex:0] displayID]);
  133. }
  134. - (BOOL)isScreen: (NSScreen*)screen
  135. {
  136.     return ([self displayID] == [screen displayID]);
  137. }
  138. - (CGDirectDisplayID)displayID
  139. {
  140. return (CGDirectDisplayID)[[[self deviceDescription] objectForKey: @"NSScreenNumber"] intValue];
  141. }
  142. - (void)blackoutOtherScreens
  143. {
  144.     unsigned int i;
  145.     /* Free our previous blackout window (follow blackoutWindow alloc strategy) */
  146.     [blackoutWindows makeObjectsPerformSelector:@selector(close)];
  147.     [blackoutWindows removeAllObjects];
  148.     for(i = 0; i < [[NSScreen screens] count]; i++)
  149.     {
  150.         NSScreen *screen = [[NSScreen screens] objectAtIndex: i];
  151.         VLCWindow *blackoutWindow;
  152.         NSRect screen_rect;
  153.  
  154.         if([self isScreen: screen])
  155.             continue;
  156.         screen_rect = [screen frame];
  157.         screen_rect.origin.x = screen_rect.origin.y = 0;
  158.         /* blackoutWindow alloc strategy
  159.             - The NSMutableArray blackoutWindows has the blackoutWindow references
  160.             - blackoutOtherDisplays is responsible for alloc/releasing its Windows
  161.         */
  162.         blackoutWindow = [[VLCWindow alloc] initWithContentRect: screen_rect styleMask: NSBorderlessWindowMask
  163.                 backing: NSBackingStoreBuffered defer: NO screen: screen];
  164.         [blackoutWindow setBackgroundColor:[NSColor blackColor]];
  165.         [blackoutWindow setLevel: NSFloatingWindowLevel]; /* Disappear when Expose is triggered */
  166.  
  167.         [blackoutWindow displayIfNeeded];
  168.         [blackoutWindow orderFront: self animate: YES];
  169.         [blackoutWindows addObject: blackoutWindow];
  170.         [blackoutWindow release];
  171.         
  172.         if( [screen isMainScreen ] )
  173.            SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
  174.     }
  175. }
  176. + (void)unblackoutScreens
  177. {
  178.     unsigned int i;
  179.     for(i = 0; i < [blackoutWindows count]; i++)
  180.     {
  181.         VLCWindow *blackoutWindow = [blackoutWindows objectAtIndex: i];
  182.         [blackoutWindow closeAndAnimate: YES];
  183.     }
  184.     
  185.    SetSystemUIMode( kUIModeNormal, 0);
  186. }
  187. @end
  188. /*****************************************************************************
  189.  * VLCWindow
  190.  *
  191.  *  Missing extension to NSWindow
  192.  *****************************************************************************/
  193. @implementation VLCWindow
  194. - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
  195.     backing:(NSBackingStoreType)backingType defer:(BOOL)flag
  196. {
  197.     self = [super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag];
  198.     if( self )
  199.         b_isset_canBecomeKeyWindow = NO;
  200.     return self;
  201. }
  202. - (void)setCanBecomeKeyWindow: (BOOL)canBecomeKey
  203. {
  204.     b_isset_canBecomeKeyWindow = YES;
  205.     b_canBecomeKeyWindow = canBecomeKey;
  206. }
  207. - (BOOL)canBecomeKeyWindow
  208. {
  209.     if(b_isset_canBecomeKeyWindow)
  210.         return b_canBecomeKeyWindow;
  211.     return [super canBecomeKeyWindow];
  212. }
  213. - (void)closeAndAnimate: (BOOL)animate
  214. {
  215.     NSInvocation *invoc;
  216.  
  217.     if (!animate)
  218.     {
  219.         [super close];
  220.         return;
  221.     }
  222.     invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(close)]];
  223.     [invoc setTarget: (id)super];
  224.     if (![self isVisible] || [self alphaValue] == 0.0)
  225.     {
  226.         [super close];
  227.         return;
  228.     }
  229.     [self orderOut: self animate: YES callback: invoc];
  230. }
  231. - (void)orderOut: (id)sender animate: (BOOL)animate
  232. {
  233.     NSInvocation *invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(orderOut:)]];
  234.     [invoc setTarget: (id)super];
  235.     [invoc setArgument: sender atIndex: 0];
  236.     [self orderOut: sender animate: animate callback: invoc];
  237. }
  238. - (void)orderOut: (id)sender animate: (BOOL)animate callback:(NSInvocation *)callback
  239. {
  240.     NSViewAnimation *anim;
  241.     NSViewAnimation *current_anim;
  242.     NSMutableDictionary *dict;
  243.     if (!animate)
  244.     {
  245.         [self orderOut: sender];
  246.         return;
  247.     }
  248.     dict = [[NSMutableDictionary alloc] initWithCapacity:2];
  249.     [dict setObject:self forKey:NSViewAnimationTargetKey];
  250.     [dict setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
  251.     anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
  252.     [dict release];
  253.     [anim setAnimationBlockingMode:NSAnimationNonblocking];
  254.     [anim setDuration:0.9];
  255.     [anim setFrameRate:30];
  256.     [anim setUserInfo: callback];
  257.     @synchronized(self) {
  258.         current_anim = self->animation;
  259.         if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeOutEffect && [current_anim isAnimating])
  260.         {
  261.             [anim release];
  262.         }
  263.         else
  264.         {
  265.             if (current_anim)
  266.             {
  267.                 [current_anim stopAnimation];
  268.                 [anim setCurrentProgress:1.0-[current_anim currentProgress]];
  269.                 [current_anim release];
  270.             }
  271.             else
  272.                 [anim setCurrentProgress:1.0 - [self alphaValue]];
  273.             self->animation = anim;
  274.             [self setDelegate: self];
  275.             [anim startAnimation];
  276.         }
  277.     }
  278. }
  279. - (void)orderFront: (id)sender animate: (BOOL)animate
  280. {
  281.     NSViewAnimation *anim;
  282.     NSViewAnimation *current_anim;
  283.     NSMutableDictionary *dict;
  284.  
  285.     if (!animate)
  286.     {
  287.         [super orderFront: sender];
  288.         [self setAlphaValue: 1.0];
  289.         return;
  290.     }
  291.     if (![self isVisible])
  292.     {
  293.         [self setAlphaValue: 0.0];
  294.         [super orderFront: sender];
  295.     }
  296.     else if ([self alphaValue] == 1.0)
  297.     {
  298.         [super orderFront: self];
  299.         return;
  300.     }
  301.     dict = [[NSMutableDictionary alloc] initWithCapacity:2];
  302.     [dict setObject:self forKey:NSViewAnimationTargetKey];
  303.  
  304.     [dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
  305.     anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
  306.     [dict release];
  307.  
  308.     [anim setAnimationBlockingMode:NSAnimationNonblocking];
  309.     [anim setDuration:0.5];
  310.     [anim setFrameRate:30];
  311.     @synchronized(self) {
  312.         current_anim = self->animation;
  313.         if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeInEffect && [current_anim isAnimating])
  314.         {
  315.             [anim release];
  316.         }
  317.         else
  318.         {
  319.             if (current_anim)
  320.             {
  321.                 [current_anim stopAnimation];
  322.                 [anim setCurrentProgress:1.0 - [current_anim currentProgress]];
  323.                 [current_anim release];
  324.             }
  325.             else
  326.                 [anim setCurrentProgress:[self alphaValue]];
  327.             self->animation = anim;
  328.             [self setDelegate: self];
  329.             [self orderFront: sender];
  330.             [anim startAnimation];
  331.         }
  332.     }
  333. }
  334. - (void)animationDidEnd:(NSAnimation*)anim
  335. {
  336.     if ([self alphaValue] <= 0.0)
  337.     {
  338.         NSInvocation * invoc;
  339.         [super orderOut: nil];
  340.         [self setAlphaValue: 1.0];
  341.         if ((invoc = [anim userInfo]))
  342.             [invoc invoke];
  343.     }
  344. }
  345. @end
  346. /*****************************************************************************
  347.  * VLCControllerWindow
  348.  *****************************************************************************/
  349. @implementation VLCControllerWindow
  350. - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
  351.     backing:(NSBackingStoreType)backingType defer:(BOOL)flag
  352. {
  353.     /* FIXME: this should enable the SnowLeopard window style, however, it leads to ugly artifacts
  354.      *        needs some further investigation! -- feepk
  355.      BOOL b_useTextured = YES;
  356.     if( [[NSWindow class] instancesRespondToSelector:@selector(setContentBorderThickness:forEdge:)] )
  357.     {
  358.         b_useTextured = NO;
  359.         styleMask ^= NSTexturedBackgroundWindowMask;
  360.     } */
  361.     self = [super initWithContentRect:contentRect styleMask:styleMask //& ~NSTitledWindowMask
  362.     backing:backingType defer:flag];
  363.     [[VLCMain sharedInstance] updateTogglePlaylistState];
  364.     /* FIXME: see above...
  365.     if(! b_useTextured )
  366.     {
  367.         [self setContentBorderThickness:28.0 forEdge:NSMinYEdge];
  368.     }
  369.     */
  370.     return self;
  371. }
  372. - (BOOL)performKeyEquivalent:(NSEvent *)o_event
  373. {
  374.     /* We indeed want to prioritize Cocoa key equivalent against libvlc,
  375.        so we perform the menu equivalent now. */
  376.     if([[NSApp mainMenu] performKeyEquivalent:o_event])
  377.         return TRUE;
  378.     return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event] ||
  379.            [(VLCControls *)[[VLCMain sharedInstance] controls] keyEvent:o_event];
  380. }
  381. @end
  382. /*****************************************************************************
  383.  * VLCControllerView
  384.  *****************************************************************************/
  385. @implementation VLCControllerView
  386. - (void)dealloc
  387. {
  388.     [self unregisterDraggedTypes];
  389.     [super dealloc];
  390. }
  391. - (void)awakeFromNib
  392. {
  393.     [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
  394.         NSFilenamesPboardType, nil]];
  395. }
  396. - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
  397. {
  398.     if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
  399.                 == NSDragOperationGeneric)
  400.     {
  401.         return NSDragOperationGeneric;
  402.     }
  403.     else
  404.     {
  405.         return NSDragOperationNone;
  406.     }
  407. }
  408. - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
  409. {
  410.     return YES;
  411. }
  412. - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
  413. {
  414.     NSPasteboard *o_paste = [sender draggingPasteboard];
  415.     NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
  416.     NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
  417.     NSData *o_carried_data = [o_paste dataForType:o_desired_type];
  418.     if( o_carried_data )
  419.     {
  420.         if ([o_desired_type isEqualToString:NSFilenamesPboardType])
  421.         {
  422.             int i;
  423.             NSArray *o_array = [NSArray array];
  424.             NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType]
  425.                         sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
  426.             for( i = 0; i < (int)[o_values count]; i++)
  427.             {
  428.                 NSDictionary *o_dic;
  429.                 o_dic = [NSDictionary dictionaryWithObject:[o_values objectAtIndex:i] forKey:@"ITEM_URL"];
  430.                 o_array = [o_array arrayByAddingObject: o_dic];
  431.             }
  432.             [(VLCPlaylist *)[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
  433.             return YES;
  434.         }
  435.     }
  436.     [self setNeedsDisplay:YES];
  437.     return YES;
  438. }
  439. - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
  440. {
  441.     [self setNeedsDisplay:YES];
  442. }
  443. @end
  444. /*****************************************************************************
  445.  * VLBrushedMetalImageView
  446.  *****************************************************************************/
  447. @implementation VLBrushedMetalImageView
  448. - (BOOL)mouseDownCanMoveWindow
  449. {
  450.     return YES;
  451. }
  452. - (void)dealloc
  453. {
  454.     [self unregisterDraggedTypes];
  455.     [super dealloc];
  456. }
  457. - (void)awakeFromNib
  458. {
  459.     [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
  460.         NSFilenamesPboardType, nil]];
  461. }
  462. - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
  463. {
  464.     if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
  465.                 == NSDragOperationGeneric)
  466.     {
  467.         return NSDragOperationGeneric;
  468.     }
  469.     else
  470.     {
  471.         return NSDragOperationNone;
  472.     }
  473. }
  474. - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
  475. {
  476.     return YES;
  477. }
  478. - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
  479. {
  480.     NSPasteboard *o_paste = [sender draggingPasteboard];
  481.     NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
  482.     NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
  483.     NSData *o_carried_data = [o_paste dataForType:o_desired_type];
  484.     BOOL b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
  485.     if( o_carried_data )
  486.     {
  487.         if ([o_desired_type isEqualToString:NSFilenamesPboardType])
  488.         {
  489.             int i;
  490.             NSArray *o_array = [NSArray array];
  491.             NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType]
  492.                         sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
  493.             for( i = 0; i < (int)[o_values count]; i++)
  494.             {
  495.                 NSDictionary *o_dic;
  496.                 o_dic = [NSDictionary dictionaryWithObject:[o_values objectAtIndex:i] forKey:@"ITEM_URL"];
  497.                 o_array = [o_array arrayByAddingObject: o_dic];
  498.             }
  499.             if( b_autoplay )
  500.                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
  501.             else
  502.                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:YES];
  503.             return YES;
  504.         }
  505.     }
  506.     [self setNeedsDisplay:YES];
  507.     return YES;
  508. }
  509. - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
  510. {
  511.     [self setNeedsDisplay:YES];
  512. }
  513. @end
  514. /*****************************************************************************
  515.  * MPSlider
  516.  *****************************************************************************/
  517. @implementation MPSlider
  518. void _drawKnobInRect(NSRect knobRect)
  519. {
  520.     // Center knob in given rect
  521.     knobRect.origin.x += (int)((float)(knobRect.size.width - 7)/2.0);
  522.     knobRect.origin.y += (int)((float)(knobRect.size.height - 7)/2.0);
  523.  
  524.     // Draw diamond
  525.     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y + 6, 1, 1), NSCompositeSourceOver);
  526.     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 2, knobRect.origin.y + 5, 3, 1), NSCompositeSourceOver);
  527.     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 1, knobRect.origin.y + 4, 5, 1), NSCompositeSourceOver);
  528.     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 0, knobRect.origin.y + 3, 7, 1), NSCompositeSourceOver);
  529.     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 1, knobRect.origin.y + 2, 5, 1), NSCompositeSourceOver);
  530.     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 2, knobRect.origin.y + 1, 3, 1), NSCompositeSourceOver);
  531.     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y + 0, 1, 1), NSCompositeSourceOver);
  532. }
  533. void _drawFrameInRect(NSRect frameRect)
  534. {
  535.     // Draw frame
  536.     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width, 1), NSCompositeSourceOver);
  537.     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y + frameRect.size.height-1, frameRect.size.width, 1), NSCompositeSourceOver);
  538.     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y, 1, frameRect.size.height), NSCompositeSourceOver);
  539.     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x+frameRect.size.width-1, frameRect.origin.y, 1, frameRect.size.height), NSCompositeSourceOver);
  540. }
  541. - (void)drawRect:(NSRect)rect
  542. {
  543.     // Draw default to make sure the slider behaves correctly
  544.     [[NSGraphicsContext currentContext] saveGraphicsState];
  545.     NSRectClip(NSZeroRect);
  546.     [super drawRect:rect];
  547.     [[NSGraphicsContext currentContext] restoreGraphicsState];
  548.  
  549.     // Full size
  550.     rect = [self bounds];
  551.     int diff = (int)(([[self cell] knobThickness] - 7.0)/2.0) - 1;
  552.     rect.origin.x += diff-1;
  553.     rect.origin.y += diff;
  554.     rect.size.width -= 2*diff-2;
  555.     rect.size.height -= 2*diff;
  556.  
  557.     // Draw dark
  558.     NSRect knobRect = [[self cell] knobRectFlipped:NO];
  559.     [[[NSColor blackColor] colorWithAlphaComponent:0.6] set];
  560.     _drawFrameInRect(rect);
  561.     _drawKnobInRect(knobRect);
  562.  
  563.     // Draw shadow
  564.     [[[NSColor blackColor] colorWithAlphaComponent:0.1] set];
  565.     rect.origin.x++;
  566.     rect.origin.y++;
  567.     knobRect.origin.x++;
  568.     knobRect.origin.y++;
  569.     _drawFrameInRect(rect);
  570.     _drawKnobInRect(knobRect);
  571. }
  572. @end
  573. /*****************************************************************************
  574.  * ITSlider
  575.  *****************************************************************************/
  576. @implementation ITSlider
  577. - (void)awakeFromNib
  578. {
  579.     if ([[self cell] class] != [ITSliderCell class]) {
  580.         // replace cell
  581.         NSSliderCell *oldCell = [self cell];
  582.         NSSliderCell *newCell = [[[ITSliderCell alloc] init] autorelease];
  583.         [newCell setTag:[oldCell tag]];
  584.         [newCell setTarget:[oldCell target]];
  585.         [newCell setAction:[oldCell action]];
  586.         [newCell setControlSize:[oldCell controlSize]];
  587.         [newCell setType:[oldCell type]];
  588.         [newCell setState:[oldCell state]];
  589.         [newCell setAllowsTickMarkValuesOnly:[oldCell allowsTickMarkValuesOnly]];
  590.         [newCell setAltIncrementValue:[oldCell altIncrementValue]];
  591.         [newCell setControlTint:[oldCell controlTint]];
  592.         [newCell setKnobThickness:[oldCell knobThickness]];
  593.         [newCell setMaxValue:[oldCell maxValue]];
  594.         [newCell setMinValue:[oldCell minValue]];
  595.         [newCell setDoubleValue:[oldCell doubleValue]];
  596.         [newCell setNumberOfTickMarks:[oldCell numberOfTickMarks]];
  597.         [newCell setEditable:[oldCell isEditable]];
  598.         [newCell setEnabled:[oldCell isEnabled]];
  599.         [newCell setFormatter:[oldCell formatter]];
  600.         [newCell setHighlighted:[oldCell isHighlighted]];
  601.         [newCell setTickMarkPosition:[oldCell tickMarkPosition]];
  602.         [self setCell:newCell];
  603.     }
  604. }
  605. @end
  606. /*****************************************************************************
  607.  * ITSliderCell
  608.  *****************************************************************************/
  609. @implementation ITSliderCell
  610. - (id)init
  611. {
  612.     self = [super init];
  613.     _knobOff = [NSImage imageNamed:@"volumeslider_normal"];
  614.     [self controlTintChanged];
  615.     [[NSNotificationCenter defaultCenter] addObserver: self
  616.                                              selector: @selector( controlTintChanged )
  617.                                                  name: NSControlTintDidChangeNotification
  618.                                                object: nil];
  619.     b_mouse_down = FALSE;
  620.     return self;
  621. }
  622. - (void)controlTintChanged
  623. {
  624.     if( [NSColor currentControlTint] == NSGraphiteControlTint )
  625.         _knobOn = [NSImage imageNamed:@"volumeslider_graphite"];
  626.     else
  627.         _knobOn = [NSImage imageNamed:@"volumeslider_blue"];
  628. }
  629. - (void)dealloc
  630. {
  631.     [[NSNotificationCenter defaultCenter] removeObserver: self];
  632.     [_knobOff release];
  633.     [_knobOn release];
  634.     [super dealloc];
  635. }
  636. - (void)drawKnob:(NSRect)knob_rect
  637. {
  638.     NSImage *knob;
  639.     if( b_mouse_down )
  640.         knob = _knobOn;
  641.     else
  642.         knob = _knobOff;
  643.     [[self controlView] lockFocus];
  644.     [knob compositeToPoint:NSMakePoint( knob_rect.origin.x + 1,
  645.         knob_rect.origin.y + knob_rect.size.height -2 )
  646.         operation:NSCompositeSourceOver];
  647.     [[self controlView] unlockFocus];
  648. }
  649. - (void)stopTracking:(NSPoint)lastPoint at:(NSPoint)stopPoint inView:
  650.         (NSView *)controlView mouseIsUp:(BOOL)flag
  651. {
  652.     b_mouse_down = NO;
  653.     [self drawKnob];
  654.     [super stopTracking:lastPoint at:stopPoint inView:controlView mouseIsUp:flag];
  655. }
  656. - (BOOL)startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView
  657. {
  658.     b_mouse_down = YES;
  659.     [self drawKnob];
  660.     return [super startTrackingAt:startPoint inView:controlView];
  661. }
  662. @end