OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #import "chrome/browser/ui/cocoa/constrained_window/cw_button.h" | |
6 | |
7 #include "base/memory/scoped_nsobject.h" | |
8 #include "skia/ext/skia_utils_mac.h" | |
9 #import "third_party/molokocacao/NSBezierPath+MCAdditions.h" | |
10 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" | |
11 | |
12 namespace { | |
13 | |
14 enum ButtonState { | |
15 BUTTON_NORMAL, | |
16 BUTTON_HOVER, | |
17 BUTTON_PRESSED, | |
18 BUTTON_DISABLED, | |
19 }; | |
20 | |
21 } // namespace | |
22 | |
23 @interface CWButton() | |
24 - (BOOL)isMouseReallyInside; | |
25 @end | |
26 | |
27 @interface CWButtonCell() | |
28 - (ButtonState)buttonState; | |
29 @end | |
30 | |
31 namespace { | |
32 | |
33 const CGFloat kButtonHeight = 28; | |
34 const CGFloat kButtonPaddingX = 14; | |
35 | |
36 NSGradient* GetButtonGradient(ButtonState button_state) { | |
37 const SkColor start[] = {0xFFF0F0F0, 0xFFF4F4F4, 0xFFEBEBEB, 0xFFEDEDED}; | |
38 const SkColor end[] = {0xFFE0E0E0, 0xFFE4E4E4, 0xFFDBDBDB, 0xFFDEDEDE}; | |
39 | |
40 NSColor* start_color = gfx::SkColorToCalibratedNSColor(start[button_state]); | |
41 NSColor* end_color = gfx::SkColorToCalibratedNSColor(end[button_state]); | |
42 return [[[NSGradient alloc] initWithColorsAndLocations: | |
43 start_color, 0.0, | |
44 start_color, 0.38, | |
45 end_color, 1.0, | |
46 nil] autorelease]; | |
47 } | |
48 | |
49 NSShadow* GetButtonHighlight(ButtonState button_state) { | |
50 const SkColor color[] = {0xBFFFFFFF, 0xF2FFFFFF, 0x24000000, 0x00000000}; | |
51 | |
52 NSShadow* shadow = [[[NSShadow alloc] init] autorelease]; | |
53 [shadow setShadowColor:gfx::SkColorToCalibratedNSColor(color[button_state])]; | |
54 [shadow setShadowOffset:NSMakeSize(0, -1)]; | |
55 [shadow setShadowBlurRadius:2]; | |
56 return shadow; | |
57 } | |
58 | |
59 NSShadow* GetButtonShadow(ButtonState button_state) { | |
60 const SkColor color[] = {0x14000000, 0x1F000000, 0x00000000, 0x00000000}; | |
61 | |
62 NSShadow* shadow = [[[NSShadow alloc] init] autorelease]; | |
63 [shadow setShadowColor:gfx::SkColorToCalibratedNSColor(color[button_state])]; | |
64 [shadow setShadowOffset:NSMakeSize(0, -1)]; | |
65 [shadow setShadowBlurRadius:0]; | |
66 return shadow; | |
67 } | |
68 | |
69 NSColor* GetButtonBorderColor(ButtonState button_state) { | |
70 const SkColor color[] = {0x40000000, 0x4D000000, 0x4D000000, 0x1F000000}; | |
71 | |
72 return gfx::SkColorToCalibratedNSColor(color[button_state]); | |
73 } | |
74 | |
75 NSAttributedString* GetButtonAttributedString(NSString* title, | |
76 ButtonState button_state) { | |
77 const SkColor text_color[] = {0xFF333333, 0XFF000000, 0xFF000000, 0xFFAAAAAA}; | |
78 // The shadow color should be 0xFFF0F0F0 but that doesn't show up so use | |
79 // pure white instead. | |
80 const SkColor shadow_color[] = | |
81 {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF}; | |
82 | |
83 scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]); | |
84 [shadow setShadowColor: | |
85 gfx::SkColorToCalibratedNSColor(shadow_color[button_state])]; | |
86 [shadow setShadowOffset:NSMakeSize(0, -1)]; | |
87 [shadow setShadowBlurRadius:0]; | |
88 | |
89 scoped_nsobject<NSMutableParagraphStyle> paragraphStyle( | |
90 [[NSMutableParagraphStyle alloc] init]); | |
91 [paragraphStyle setAlignment:NSCenterTextAlignment]; | |
92 | |
93 NSDictionary* attributes = [NSDictionary dictionaryWithObjectsAndKeys: | |
94 [NSFont systemFontOfSize:12], NSFontAttributeName, | |
95 gfx::SkColorToCalibratedNSColor(text_color[button_state]), | |
96 NSForegroundColorAttributeName, | |
97 shadow.get(), NSShadowAttributeName, | |
98 paragraphStyle.get(), NSParagraphStyleAttributeName, | |
99 nil]; | |
100 return [[[NSAttributedString alloc] initWithString:title | |
101 attributes:attributes] autorelease]; | |
102 } | |
103 | |
104 } // namespace | |
105 | |
106 @implementation CWButton | |
107 | |
108 + (Class)cellClass { | |
109 return [CWButtonCell class]; | |
110 } | |
111 | |
112 - (void)updateTrackingAreas { | |
113 BOOL mouseInView = [self isMouseReallyInside]; | |
114 | |
115 if (trackingArea_.get()) | |
116 [self removeTrackingArea:trackingArea_.get()]; | |
117 | |
118 NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | | |
119 NSTrackingActiveInActiveApp | | |
120 NSTrackingInVisibleRect; | |
121 if (mouseInView) | |
122 options |= NSTrackingAssumeInside; | |
123 | |
124 trackingArea_.reset([[CrTrackingArea alloc] | |
125 initWithRect:NSZeroRect | |
126 options:options | |
127 owner:self | |
128 userInfo:nil]); | |
129 [self addTrackingArea:trackingArea_.get()]; | |
130 if ([[self cell] isMouseInside] != mouseInView) { | |
131 [[self cell] setIsMouseInside:mouseInView]; | |
132 [self setNeedsDisplay:YES]; | |
133 } | |
134 } | |
135 | |
136 - (void)mouseEntered:(NSEvent*)theEvent { | |
137 [[self cell] setIsMouseInside:YES]; | |
138 [self setNeedsDisplay:YES]; | |
139 } | |
140 | |
141 - (void)mouseExited:(NSEvent*)theEvent { | |
142 [[self cell] setIsMouseInside:YES]; | |
143 [[self cell] setIsMouseInside:NO]; | |
144 [self setNeedsDisplay:YES]; | |
145 } | |
146 | |
147 - (BOOL)isMouseReallyInside { | |
148 BOOL mouseInView = NO; | |
149 NSWindow* window = [self window]; | |
150 if (window) { | |
151 NSPoint mousePoint = [window mouseLocationOutsideOfEventStream]; | |
152 mousePoint = [self convertPoint:mousePoint fromView:nil]; | |
153 mouseInView = [self mouse:mousePoint inRect:[self bounds]]; | |
154 } | |
155 return mouseInView; | |
156 } | |
157 | |
158 @end | |
159 | |
160 @implementation CWButtonCell | |
161 | |
162 @synthesize isMouseInside = isMouseInside_; | |
163 | |
164 - (void)drawWithFrame:(NSRect)frame | |
165 inView:(NSView *)controlView { | |
166 NSBezierPath* path = nil; | |
167 ButtonState buttonState = [self buttonState]; | |
168 | |
169 // Inset to leave room for shadow. | |
170 frame.size.height--; | |
171 | |
172 // Background and shadow | |
173 path = [NSBezierPath bezierPathWithRoundedRect:frame | |
174 xRadius:2 | |
175 yRadius:2]; | |
176 { | |
177 gfx::ScopedNSGraphicsContextSaveGState scopedGState; | |
178 [GetButtonShadow(buttonState) set]; | |
179 [[NSColor blackColor] set]; | |
180 [path fill]; | |
181 } | |
182 [GetButtonGradient(buttonState) drawInBezierPath:path angle:90.0]; | |
183 | |
184 // Inner highlight | |
185 path = [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 1, 1) | |
186 xRadius:2 | |
187 yRadius:2]; | |
188 [path fillWithInnerShadow:GetButtonHighlight(buttonState)]; | |
189 | |
190 // Border | |
191 path = [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 0.5, 0.5) | |
192 xRadius:2 | |
193 yRadius:2]; | |
194 if ([[[controlView window] firstResponder] isEqual:controlView]) | |
195 [[NSColor colorWithCalibratedRed:0.30 green:0.57 blue:1.0 alpha:1.0] set]; | |
196 else | |
197 [GetButtonBorderColor(buttonState) set]; | |
198 [path stroke]; | |
199 | |
200 [self drawTitle:GetButtonAttributedString([self title], buttonState) | |
201 withFrame:frame | |
202 inView:controlView]; | |
203 } | |
204 | |
205 - (NSSize)cellSize { | |
206 NSAttributedString* attributedString = | |
207 GetButtonAttributedString([self title], BUTTON_NORMAL); | |
208 NSSize size = [attributedString size]; | |
209 size.height = std::max(size.height, kButtonHeight); | |
210 size.width += kButtonPaddingX * 2; | |
211 return size; | |
212 } | |
213 | |
214 - (ButtonState)buttonState { | |
215 if (![self isEnabled]) | |
216 return BUTTON_DISABLED; | |
217 if ([self isHighlighted]) | |
218 return BUTTON_PRESSED; | |
219 if (isMouseInside_) | |
220 return BUTTON_HOVER; | |
221 return BUTTON_NORMAL; | |
222 } | |
223 | |
224 @end | |
OLD | NEW |