1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
// Copyright (c) 2011 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/ui/cocoa/hover_close_button.h"
#include "base/memory/scoped_nsobject.h"
#include "grit/generated_resources.h"
#import "third_party/molokocacao/NSBezierPath+MCAdditions.h"
#include "ui/base/l10n/l10n_util.h"
namespace {
const CGFloat kCircleRadius = 0.415 * 16;
const CGFloat kCircleHoverWhite = 0.565;
const CGFloat kCircleClickWhite = 0.396;
const CGFloat kXShadowAlpha = 0.75;
const CGFloat kXShadowCircleAlpha = 0.1;
} // namespace
@interface HoverCloseButton(Private)
- (void)updatePaths;
- (void)setUpDrawingPaths;
@end
@implementation HoverCloseButton
- (id)initWithFrame:(NSRect)frameRect {
if ((self = [super initWithFrame:frameRect])) {
[self commonInit];
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
[self commonInit];
}
- (void)drawRect:(NSRect)rect {
if (!circlePath_.get() || !xPath_.get())
[self setUpDrawingPaths];
// Only call updatePaths if the size changed.
if (!NSEqualSizes(oldSize_, [self bounds].size))
[self updatePaths];
// 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] autorelease];
CGFloat alpha = (hoverState_ != kHoverStateNone) ?
kXShadowCircleAlpha : kXShadowAlpha;
[shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.15
alpha:alpha]];
[shadow setShadowOffset:NSMakeSize(0.0, 0.0)];
[shadow setShadowBlurRadius:2.5];
[xPath_ fillWithInnerShadow:shadow];
}
- (void)commonInit {
// Set accessibility description.
NSString* description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_CLOSE);
[[self cell]
accessibilitySetOverrideValue:description
forAttribute:NSAccessibilityDescriptionAttribute];
// Add a tooltip.
[self setToolTip:l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_CLOSE_TAB)];
}
- (void)setUpDrawingPaths {
// Keep the paths centered around the origin in this function. It is then
// translated in -updatePaths.
NSPoint xCenter = NSZeroPoint;
circlePath_.reset([[NSBezierPath bezierPath] retain]);
[circlePath_ moveToPoint:xCenter];
CGFloat radius = kCircleRadius;
[circlePath_ appendBezierPathWithArcWithCenter:xCenter
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)];
NSRect pathBounds = [xPath_ bounds];
NSPoint pathCenter = NSMakePoint(NSMidX(pathBounds), NSMidY(pathBounds));
NSAffineTransform* transform = [NSAffineTransform transform];
[transform translateXBy:xCenter.x yBy:xCenter.y];
[transform rotateByDegrees:45.0];
[transform translateXBy:-pathCenter.x yBy:-pathCenter.y];
[xPath_ transformUsingAffineTransform:transform];
}
- (void)updatePaths {
oldSize_ = [self bounds].size;
// Revert the current transform for the two points.
if (transform_.get()) {
[transform_.get() invert];
[circlePath_.get() transformUsingAffineTransform:transform_.get()];
[xPath_.get() transformUsingAffineTransform:transform_.get()];
}
// Create the new transform. [self bounds] is prefered in case aRect wasn't
// literally taken as bounds (e.g. cropped).
NSPoint xCenter = NSMakePoint(8, oldSize_.height / 2.0f);
// Retain here, as scoped_* don't retain.
transform_.reset([[NSAffineTransform transform] retain]);
[transform_.get() translateXBy:xCenter.x yBy:xCenter.y];
[circlePath_.get() transformUsingAffineTransform:transform_.get()];
[xPath_.get() transformUsingAffineTransform:transform_.get()];
}
@end
|