diff options
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/cocoa/hover_close_button.h | 32 | ||||
-rw-r--r-- | chrome/browser/cocoa/hover_close_button.mm | 111 | ||||
-rw-r--r-- | chrome/browser/cocoa/third_party/LICENSE | 23 | ||||
-rw-r--r-- | chrome/browser/cocoa/third_party/NSBezierPath+MCAdditions.h | 27 | ||||
-rw-r--r-- | chrome/browser/cocoa/third_party/NSBezierPath+MCAdditions.m | 188 | ||||
-rw-r--r-- | chrome/browser/cocoa/third_party/README.chromium | 14 |
6 files changed, 365 insertions, 30 deletions
diff --git a/chrome/browser/cocoa/hover_close_button.h b/chrome/browser/cocoa/hover_close_button.h index 7c34395..97c49ce 100644 --- a/chrome/browser/cocoa/hover_close_button.h +++ b/chrome/browser/cocoa/hover_close_button.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,20 +6,36 @@ #include "base/scoped_nsobject.h" -// The standard close button for our Mac UI which is the "x" -// that changes to the red circle with the "x" when you hover over it. -// At this time it is used by the popup blocker, download bar, info bar -// and tabs. +// The standard close button for our Mac UI which is the "x" that changes to a +// dark circle with the "x" when you hover over it. At this time it is used by +// the popup blocker, download bar, info bar and tabs. @interface HoverCloseButton : NSButton { - // Tracking area for close button mouseover images. + @private + // Enumeration of the hover states that the close button can be in at any one + // time. The button cannot be in more than one hover state at a time. + enum HoverState { + kHoverStateNone = 0, + kHoverStateMouseOver = 1, + kHoverStateMouseDown = 2 + }; + + HoverState hoverState_; + + // Tracking area for close button mouseover states. scoped_nsobject<NSTrackingArea> closeTrackingArea_; + + // Bezier path for drawing the 'x' within the button. + scoped_nsobject<NSBezierPath> xPath_; + + // Bezier path for drawing the hover state circle behind the 'x'. + scoped_nsobject<NSBezierPath> circlePath_; } // Enables or disables the |NSTrackingRect|s for the button. - (void)setTrackingEnabled:(BOOL)enabled; -// Sets up the button's images, tracking areas, and accessibility info -// when instantiated via initWithFrame or awakeFromNib. +// Sets up the button's tracking areas and accessibility info when instantiated +// via initWithFrame or awakeFromNib. - (void)commonInit; // Checks to see whether the mouse is in the button's bounds and update diff --git a/chrome/browser/cocoa/hover_close_button.mm b/chrome/browser/cocoa/hover_close_button.mm index ee6e609..c885ae6 100644 --- a/chrome/browser/cocoa/hover_close_button.mm +++ b/chrome/browser/cocoa/hover_close_button.mm @@ -1,21 +1,31 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #import "chrome/browser/cocoa/hover_close_button.h" #include "app/l10n_util.h" -#include "base/nsimage_cache_mac.h" +#include "base/scoped_nsobject.h" +#import "chrome/browser/cocoa/third_party/NSBezierPath+MCAdditions.h" #include "grit/generated_resources.h" namespace { +// Convenience function to return the middle point of the given |rect|. +static NSPoint MidRect(NSRect rect) { + return NSMakePoint(NSMidX(rect), NSMidY(rect)); +} -NSString* const kNormalImageString = @"close_bar.pdf"; -NSString* const kHoverImageString = @"close_bar_h.pdf"; -NSString* const kPressedImageString = @"close_bar_p.pdf"; - +const CGFloat kCircleRadiusPercentage = 0.45; +const CGFloat kCircleHoverWhite = 0.565; +const CGFloat kCircleClickWhite = 0.396; +const CGFloat kXShadowAlpha = 0.6; +const CGFloat kXShadowCircleAlpha = 0.1; } // namespace +@interface HoverCloseButton(Private) +- (void)setUpDrawingPaths; +@end + @implementation HoverCloseButton - (id)initWithFrame:(NSRect)frameRect { @@ -29,10 +39,39 @@ NSString* const kPressedImageString = @"close_bar_p.pdf"; [self commonInit]; } +- (void)drawRect:(NSRect)rect { + if (!circlePath_.get() || !xPath_.get()) + [self setUpDrawingPaths]; + + // If the user is hovering over the button, a light/dark gray circle is drawn + // behind the 'x'. + if (hoverState_ != kHoverStateNone) { + // Adjust the darkness of the circle depending on whether it is being + // clicked. + CGFloat white = (hoverState_ == kHoverStateMouseOver) ? + kCircleHoverWhite : kCircleClickWhite; + [[NSColor colorWithCalibratedWhite:white alpha:1.0] set]; + [circlePath_ fill]; + } + + [[NSColor whiteColor] set]; + [xPath_ fill]; + + // Give the 'x' an inner shadow for depth. If the button is in a hover state + // (circle behind it), then adjust the shadow accordingly (not as harsh). + NSShadow* shadow = [[NSShadow alloc] init]; + CGFloat alpha = (hoverState_ != kHoverStateNone) ? + kXShadowCircleAlpha : kXShadowAlpha; + [shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.0 + alpha:alpha]]; + [shadow setShadowOffset:NSMakeSize(0.0, -1.0)]; + [shadow setShadowBlurRadius:2.0]; + [xPath_ fillWithInnerShadow:shadow]; +} + - (void)commonInit { [self setTrackingEnabled:YES]; - NSImage* alternateImage = nsimage_cache::ImageNamed(kPressedImageString); - [self setAlternateImage:alternateImage]; + hoverState_ = kHoverStateNone; [self updateTrackingAreas]; // Set accessibility description. @@ -42,20 +81,51 @@ NSString* const kPressedImageString = @"close_bar_p.pdf"; forAttribute:NSAccessibilityDescriptionAttribute]; } +- (void)setUpDrawingPaths { + NSPoint viewCenter = MidRect([self bounds]); + + circlePath_.reset([[NSBezierPath bezierPath] retain]); + [circlePath_ moveToPoint:viewCenter]; + CGFloat radius = kCircleRadiusPercentage * NSWidth([self bounds]); + [circlePath_ appendBezierPathWithArcWithCenter:viewCenter + radius:radius + startAngle:0.0 + endAngle:365.0]; + + // Construct an 'x' by drawing two intersecting rectangles in the shape of a + // cross and then rotating the path by 45 degrees. + xPath_.reset([[NSBezierPath bezierPath] retain]); + [xPath_ appendBezierPathWithRect:NSMakeRect(3.5, 7.0, 9.0, 2.0)]; + [xPath_ appendBezierPathWithRect:NSMakeRect(7.0, 3.5, 2.0, 9.0)]; + + NSPoint pathCenter = MidRect([xPath_ bounds]); + + NSAffineTransform* transform = [NSAffineTransform transform]; + [transform translateXBy:viewCenter.x yBy:viewCenter.y]; + [transform rotateByDegrees:45.0]; + [transform translateXBy:-pathCenter.x yBy:-pathCenter.y]; + + [xPath_ transformUsingAffineTransform:transform]; +} + - (void)dealloc { [self setTrackingEnabled:NO]; [super dealloc]; } - (void)mouseEntered:(NSEvent*)theEvent { - [self setImage:nsimage_cache::ImageNamed(kHoverImageString)]; + hoverState_ = kHoverStateMouseOver; + [self setNeedsDisplay:YES]; } - (void)mouseExited:(NSEvent*)theEvent { - [self setImage:nsimage_cache::ImageNamed(kNormalImageString)]; + hoverState_ = kHoverStateNone; + [self setNeedsDisplay:YES]; } - (void)mouseDown:(NSEvent*)theEvent { + hoverState_ = kHoverStateMouseDown; + [self setNeedsDisplay:YES]; // The hover button needs to hold onto itself here for a bit. Otherwise, // it can be freed while |super mouseDown:| is in it's loop, and the // |checkImageState| call will crash. @@ -100,18 +170,15 @@ NSString* const kPressedImageString = @"close_bar_p.pdf"; } - (void)checkImageState { - if (closeTrackingArea_.get()) { - // Update the close buttons if the tab has moved. - NSPoint mouseLoc = [[self window] mouseLocationOutsideOfEventStream]; - mouseLoc = [self convertPoint:mouseLoc fromView:nil]; - NSString* name = NSPointInRect(mouseLoc, [self bounds]) ? - kHoverImageString : kNormalImageString; - NSImage* newImage = nsimage_cache::ImageNamed(name); - NSImage* buttonImage = [self image]; - if (![buttonImage isEqual:newImage]) { - [self setImage:newImage]; - } - } + if (!closeTrackingArea_.get()) + return; + + // Update the close buttons if the tab has moved. + NSPoint mouseLoc = [[self window] mouseLocationOutsideOfEventStream]; + mouseLoc = [self convertPoint:mouseLoc fromView:nil]; + hoverState_ = NSPointInRect(mouseLoc, [self bounds]) ? + kHoverStateMouseOver : kHoverStateNone; + [self setNeedsDisplay:YES]; } @end diff --git a/chrome/browser/cocoa/third_party/LICENSE b/chrome/browser/cocoa/third_party/LICENSE new file mode 100644 index 0000000..6133156 --- /dev/null +++ b/chrome/browser/cocoa/third_party/LICENSE @@ -0,0 +1,23 @@ +Copyright 2008 MolokoCacao +All rights reserved + +Redistribution and use in source and binary forms, with or without +modification, are permitted providing that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/chrome/browser/cocoa/third_party/NSBezierPath+MCAdditions.h b/chrome/browser/cocoa/third_party/NSBezierPath+MCAdditions.h new file mode 100644 index 0000000..7750fca --- /dev/null +++ b/chrome/browser/cocoa/third_party/NSBezierPath+MCAdditions.h @@ -0,0 +1,27 @@ +// +// NSBezierPath+MCAdditions.h +// +// Created by Sean Patrick O'Brien on 4/1/08. +// Copyright 2008 MolokoCacao. All rights reserved. +// + +#ifndef CHROME_BROWSER_COCOA_THIRD_PARTY_NSBEZIERPATH_MCADDITIONS_H_ +#define CHROME_BROWSER_COCOA_THIRD_PARTY_NSBEZIERPATH_MCADDITIONS_H_ + +#import <Cocoa/Cocoa.h> + +@interface NSBezierPath (MCAdditions) + ++ (NSBezierPath*)bezierPathWithCGPath:(CGPathRef)pathRef; + +- (NSBezierPath*)pathWithStrokeWidth:(CGFloat)strokeWidth; + +- (void)fillWithInnerShadow:(NSShadow*)shadow; +- (void)drawBlurWithColor:(NSColor*)color radius:(CGFloat)radius; + +- (void)strokeInside; +- (void)strokeInsideWithinRect:(NSRect)clipRect; + +@end + +#endif // CHROME_BROWSER_COCOA_THIRD_PARTY_NSBEZIERPATH_MCADDITIONS_H_ diff --git a/chrome/browser/cocoa/third_party/NSBezierPath+MCAdditions.m b/chrome/browser/cocoa/third_party/NSBezierPath+MCAdditions.m new file mode 100644 index 0000000..e1771cc --- /dev/null +++ b/chrome/browser/cocoa/third_party/NSBezierPath+MCAdditions.m @@ -0,0 +1,188 @@ +// +// NSBezierPath+MCAdditions.m +// +// Created by Sean Patrick O'Brien on 4/1/08. +// Copyright 2008 MolokoCacao. All rights reserved. +// + +#import "NSBezierPath+MCAdditions.h" + +#import "third_party/GTM/AppKit/GTMNSBezierPath+CGPath.h" + +// remove/comment out this line of you don't want to use undocumented functions +#define MCBEZIER_USE_PRIVATE_FUNCTION + +#ifdef MCBEZIER_USE_PRIVATE_FUNCTION +extern CGPathRef CGContextCopyPath(CGContextRef context); +#endif + +static void CGPathCallback(void *info, const CGPathElement *element) +{ + NSBezierPath *path = info; + CGPoint *points = element->points; + + switch (element->type) { + case kCGPathElementMoveToPoint: + { + [path moveToPoint:NSMakePoint(points[0].x, points[0].y)]; + break; + } + case kCGPathElementAddLineToPoint: + { + [path lineToPoint:NSMakePoint(points[0].x, points[0].y)]; + break; + } + case kCGPathElementAddQuadCurveToPoint: + { + // NOTE: This is untested. + NSPoint currentPoint = [path currentPoint]; + NSPoint interpolatedPoint = NSMakePoint((currentPoint.x + 2*points[0].x) / 3, (currentPoint.y + 2*points[0].y) / 3); + [path curveToPoint:NSMakePoint(points[1].x, points[1].y) controlPoint1:interpolatedPoint controlPoint2:interpolatedPoint]; + break; + } + case kCGPathElementAddCurveToPoint: + { + [path curveToPoint:NSMakePoint(points[2].x, points[2].y) controlPoint1:NSMakePoint(points[0].x, points[0].y) controlPoint2:NSMakePoint(points[1].x, points[1].y)]; + break; + } + case kCGPathElementCloseSubpath: + { + [path closePath]; + break; + } + } +} + +@implementation NSBezierPath (MCAdditions) + ++ (NSBezierPath *)bezierPathWithCGPath:(CGPathRef)pathRef +{ + NSBezierPath *path = [NSBezierPath bezierPath]; + CGPathApply(pathRef, path, CGPathCallback); + + return path; +} + +- (NSBezierPath *)pathWithStrokeWidth:(CGFloat)strokeWidth +{ +#ifdef MCBEZIER_USE_PRIVATE_FUNCTION + NSBezierPath *path = [self copy]; + CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; + CGPathRef pathRef = [path gtm_CGPath]; + [path release]; + + CGContextSaveGState(context); + + CGContextBeginPath(context); + CGContextAddPath(context, pathRef); + CGContextSetLineWidth(context, strokeWidth); + CGContextReplacePathWithStrokedPath(context); + CGPathRef strokedPathRef = CGContextCopyPath(context); + CGContextBeginPath(context); + NSBezierPath *strokedPath = [NSBezierPath bezierPathWithCGPath:strokedPathRef]; + + CGContextRestoreGState(context); + + CFRelease(pathRef); + CFRelease(strokedPathRef); + + return strokedPath; +#else + return nil; +#endif // MCBEZIER_USE_PRIVATE_FUNCTION +} + +- (void)fillWithInnerShadow:(NSShadow *)shadow +{ + [NSGraphicsContext saveGraphicsState]; + + NSSize offset = shadow.shadowOffset; + NSSize originalOffset = offset; + CGFloat radius = shadow.shadowBlurRadius; + NSRect bounds = NSInsetRect(self.bounds, -(ABS(offset.width) + radius), -(ABS(offset.height) + radius)); + offset.height += bounds.size.height; + shadow.shadowOffset = offset; + NSAffineTransform *transform = [NSAffineTransform transform]; + if ([[NSGraphicsContext currentContext] isFlipped]) + [transform translateXBy:0 yBy:bounds.size.height]; + else + [transform translateXBy:0 yBy:-bounds.size.height]; + + NSBezierPath *drawingPath = [NSBezierPath bezierPathWithRect:bounds]; + [drawingPath setWindingRule:NSEvenOddWindingRule]; + [drawingPath appendBezierPath:self]; + [drawingPath transformUsingAffineTransform:transform]; + + [self addClip]; + [shadow set]; + [[NSColor blackColor] set]; + [drawingPath fill]; + + shadow.shadowOffset = originalOffset; + + [NSGraphicsContext restoreGraphicsState]; +} + +- (void)drawBlurWithColor:(NSColor *)color radius:(CGFloat)radius +{ + NSRect bounds = NSInsetRect(self.bounds, -radius, -radius); + NSShadow *shadow = [[NSShadow alloc] init]; + shadow.shadowOffset = NSMakeSize(0, bounds.size.height); + shadow.shadowBlurRadius = radius; + shadow.shadowColor = color; + NSBezierPath *path = [self copy]; + NSAffineTransform *transform = [NSAffineTransform transform]; + if ([[NSGraphicsContext currentContext] isFlipped]) + [transform translateXBy:0 yBy:bounds.size.height]; + else + [transform translateXBy:0 yBy:-bounds.size.height]; + [path transformUsingAffineTransform:transform]; + + [NSGraphicsContext saveGraphicsState]; + + [shadow set]; + [[NSColor blackColor] set]; + NSRectClip(bounds); + [path fill]; + + [NSGraphicsContext restoreGraphicsState]; + + [path release]; + [shadow release]; +} + +// Credit for the next two methods goes to Matt Gemmell +- (void)strokeInside +{ + /* Stroke within path using no additional clipping rectangle. */ + [self strokeInsideWithinRect:NSZeroRect]; +} + +- (void)strokeInsideWithinRect:(NSRect)clipRect +{ + NSGraphicsContext *thisContext = [NSGraphicsContext currentContext]; + float lineWidth = [self lineWidth]; + + /* Save the current graphics context. */ + [thisContext saveGraphicsState]; + + /* Double the stroke width, since -stroke centers strokes on paths. */ + [self setLineWidth:(lineWidth * 2.0)]; + + /* Clip drawing to this path; draw nothing outwith the path. */ + [self setClip]; + + /* Further clip drawing to clipRect, usually the view's frame. */ + if (clipRect.size.width > 0.0 && clipRect.size.height > 0.0) { + [NSBezierPath clipRect:clipRect]; + } + + /* Stroke the path. */ + [self stroke]; + + /* Restore the previous graphics context. */ + [thisContext restoreGraphicsState]; + [self setLineWidth:lineWidth]; +} + +@end diff --git a/chrome/browser/cocoa/third_party/README.chromium b/chrome/browser/cocoa/third_party/README.chromium new file mode 100644 index 0000000..c82463f --- /dev/null +++ b/chrome/browser/cocoa/third_party/README.chromium @@ -0,0 +1,14 @@ +Name: NSBezierPath additions from Sean Patrick O'Brien +URL: http://www.seanpatrickobrien.com/journal/posts/3 +Source URL: http://www.seanpatrickobrien.com/downloads/track/?path=%2Ftutorials%2F1%2FExampleButton.zip +Version: 1.0 +License: BSD +License File: LICENSE + +Description: +Additions to NSBezierPath to make certain operations more convenient (inner +shadows on paths, for example). + +Local Modifications: + - Added LICENSE file based on email correspondence with Sean. + - Added header guards. |