summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/cocoa/hover_close_button.h32
-rw-r--r--chrome/browser/cocoa/hover_close_button.mm111
-rw-r--r--chrome/browser/cocoa/third_party/LICENSE23
-rw-r--r--chrome/browser/cocoa/third_party/NSBezierPath+MCAdditions.h27
-rw-r--r--chrome/browser/cocoa/third_party/NSBezierPath+MCAdditions.m188
-rw-r--r--chrome/browser/cocoa/third_party/README.chromium14
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.