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 #include "ui/views/controls/button/chrome_style.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "ui/gfx/canvas.h" | |
10 #include "ui/gfx/color_utils.h" | |
11 #include "ui/views/painter.h" | |
12 #include "ui/views/background.h" | |
13 | |
14 namespace views { | |
15 namespace { | |
16 const int kMinWidth = 72; | |
17 const int kMinHeight = 27; | |
18 | |
19 // Fractional position between top and bottom of button where the | |
20 // gradient starts. | |
21 const SkScalar kGradientStartLocation = 0.38f; | |
22 const SkColor kNormalBackgroundTopColor = SkColorSetRGB(0xf0, 0xf0, 0xf0); | |
23 const SkColor kNormalBackgroundBottomColor = SkColorSetRGB(0xe0, 0xe0, 0xe0); | |
24 const SkColor kHotBackgroundTopColor = SkColorSetRGB(0xf4, 0xf4, 0xf4); | |
25 const SkColor kHotBackgroundBottomColor = SkColorSetRGB(0xe4, 0xe4, 0xe4); | |
26 const SkColor kPushedBackgroundTopColor = SkColorSetRGB(0xeb, 0xeb, 0xeb); | |
27 const SkColor kPushedBackgroundBottomColor = SkColorSetRGB(0xdb, 0xdb, 0xdb); | |
28 const SkColor kDisabledBackgroundTopColor = SkColorSetRGB(0xed, 0xed, 0xed); | |
29 const SkColor kDisabledBackgroundBottomColor = SkColorSetRGB(0xde, 0xde, 0xde); | |
30 | |
31 const SkColor kEnabledTextColor = SkColorSetRGB(0x33, 0x33, 0x33); | |
32 const SkColor kDisabledTextColor = SkColorSetRGB(0xaa, 0xaa, 0xaa); | |
33 const SkColor kHoverTextColor = SkColorSetRGB(0x0, 0x0, 0x0); | |
34 | |
35 const SkColor kTextShadowColor = SkColorSetRGB(0xf0, 0xf0, 0xf0); | |
36 const int kTextShadowOffsetX = 0; | |
37 const int kTextShadowOffsetY = 1; | |
38 | |
39 const int kBorderWidth = 1; | |
40 const int kBorderRadius = 2; | |
41 const SkColor kBorderNormalColor = SkColorSetARGB(0x3f, 0x0, 0x0, 0x0); | |
42 const SkColor kBorderActiveColor = SkColorSetARGB(0x4b, 0x0, 0x0, 0x0); | |
43 const SkColor kBorderDisabledColor = SkColorSetARGB(0x1d, 0x0, 0x0, 0x0); | |
44 | |
45 const int kFocusRingWidth = 2; | |
46 const int kFocusRingRadius = 2; | |
47 const SkColor kFocusRingColor = SkColorSetARGB(0x7f, 0xe5, 0x97, 0x00); | |
48 | |
49 // Returns the uniform inset of the button from its local bounds. | |
50 int GetButtonInset() { | |
51 return std::max(kBorderWidth, kFocusRingWidth); | |
52 } | |
53 | |
54 class ChromeStyleTextButtonBackground : public Background { | |
55 public: | |
56 ChromeStyleTextButtonBackground() { | |
57 } | |
58 | |
59 virtual ~ChromeStyleTextButtonBackground() { | |
60 } | |
61 | |
62 // Overriden from Background | |
63 virtual void Paint(gfx::Canvas* canvas, View* view) const { | |
64 if (painter_.get()) | |
65 { | |
66 gfx::Rect bounds = view->GetLocalBounds(); | |
67 // Inset to the actual button region. | |
68 int inset = GetButtonInset(); | |
69 bounds.Inset(inset, inset, inset, inset); | |
70 Painter::PaintPainterAt(canvas, painter_.get(), bounds); | |
71 } | |
72 } | |
73 | |
74 void SetColors(SkColor top, SkColor bottom) { | |
75 static const int count = 3; | |
76 SkColor colors[count] = { top, top, bottom }; | |
77 SkScalar pos[count] = { 0.0f, kGradientStartLocation, 1.0f }; | |
78 | |
79 painter_.reset( | |
80 Painter::CreateVerticalMultiColorGradient(colors, pos, count)); | |
81 SetNativeControlColor( | |
82 color_utils::AlphaBlend(colors[0], colors[count - 1], 128)); | |
83 } | |
84 | |
85 private: | |
86 scoped_ptr<Painter> painter_; | |
87 | |
88 DISALLOW_COPY_AND_ASSIGN(ChromeStyleTextButtonBackground); | |
89 }; | |
90 | |
91 class ChromeStyleTextButtonBorderPainter : public views::Painter { | |
92 public: | |
93 ChromeStyleTextButtonBorderPainter() | |
94 // This value should be updated prior to rendering; it's set to a | |
95 // well-defined value here defensively. | |
96 : color_(SkColorSetRGB(0x0, 0x0, 0x0)) { | |
97 } | |
98 | |
99 // Overriden from Painter | |
100 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) { | |
101 SkPaint paint; | |
102 paint.setStyle(SkPaint::kStroke_Style); | |
103 paint.setColor(color_); | |
104 paint.setStrokeWidth(kBorderWidth); | |
105 | |
106 // Inset by 1/2 pixel to align the stroke with pixel centers. | |
107 SkScalar inset = 0.5f; | |
108 SkRect rect = SkRect::MakeLTRB(inset, inset, | |
109 SkIntToScalar(size.width()) - inset, | |
110 SkIntToScalar(size.height()) - inset); | |
111 | |
112 canvas->sk_canvas()->drawRoundRect( | |
113 rect, kBorderRadius, kBorderRadius, paint); | |
114 } | |
115 | |
116 void set_color(SkColor color) { | |
117 color_ = color; | |
118 } | |
119 | |
120 private: | |
121 SkColor color_; | |
122 | |
123 DISALLOW_COPY_AND_ASSIGN(ChromeStyleTextButtonBorderPainter); | |
124 }; | |
125 | |
126 | |
127 class ChromeStyleTextButtonBorder : public views::Border { | |
128 public: | |
129 ChromeStyleTextButtonBorder() | |
130 : painter_(new ChromeStyleTextButtonBorderPainter) { | |
131 } | |
132 | |
133 // Overriden from Border | |
134 virtual void Paint(const View& view, gfx::Canvas* canvas) const { | |
135 gfx::Rect bounds = view.GetLocalBounds(); | |
136 int border_inset = GetButtonInset() - kBorderWidth; | |
137 bounds.Inset(border_inset, border_inset, border_inset, border_inset); | |
138 Painter::PaintPainterAt(canvas, painter_, bounds); | |
139 } | |
140 virtual void GetInsets(gfx::Insets* insets) const { | |
141 DCHECK(insets); | |
142 int inset = GetButtonInset(); | |
143 insets->Set(inset, inset, inset, inset); | |
144 } | |
145 | |
146 void SetColor(SkColor color) { | |
147 painter_->set_color(color); | |
148 } | |
149 | |
150 private: | |
151 ChromeStyleTextButtonBorderPainter* painter_; | |
152 | |
153 DISALLOW_COPY_AND_ASSIGN(ChromeStyleTextButtonBorder); | |
154 }; | |
155 | |
156 class ChromeStyleFocusBorder : public views::FocusBorder { | |
157 public: | |
158 ChromeStyleFocusBorder() {} | |
159 | |
160 // Overriden from Border | |
161 virtual void Paint(const View& view, gfx::Canvas* canvas) const { | |
162 gfx::Rect rect(view.GetLocalBounds()); | |
163 SkScalar inset = GetButtonInset() - kFocusRingWidth / 2.0f; | |
164 rect.Inset(inset, inset); | |
165 SkPaint paint; | |
166 paint.setStyle(SkPaint::kStroke_Style); | |
167 paint.setStrokeWidth(SkScalar(kFocusRingWidth)); | |
168 paint.setColor(kFocusRingColor); | |
169 canvas->DrawRoundRect(rect, SkScalar(kFocusRingRadius), paint); | |
170 } | |
171 | |
172 private: | |
173 DISALLOW_COPY_AND_ASSIGN(ChromeStyleFocusBorder); | |
174 }; | |
175 | |
176 class ChromeStyleStateChangedUpdater | |
177 : public CustomButtonStateChangedDelegate { | |
178 public: | |
179 // The background and border may be NULL. | |
180 ChromeStyleStateChangedUpdater(TextButton* button, | |
181 ChromeStyleTextButtonBackground* background, | |
182 ChromeStyleTextButtonBorder* border) | |
183 : button_(button), | |
184 background_(background), | |
185 border_(border), | |
186 prior_state_(button->state()) { | |
187 SetBackgroundForState(button->state()); | |
188 SetShadowForState(button->state()); | |
189 SetBorderColorForState(button->state()); | |
190 } | |
191 | |
192 virtual void StateChanged(CustomButton::ButtonState state) { | |
193 SetBackgroundForState(state); | |
194 | |
195 // Update text shadow when transitioning to/from pushed state. | |
196 if (state == CustomButton::BS_PUSHED || | |
197 prior_state_ == CustomButton::BS_PUSHED) { | |
198 SetShadowForState(state); | |
199 } | |
200 | |
201 // Update border color. We need to change it in all cases except hot | |
202 // followed by pushed. | |
203 if (!(state == CustomButton::BS_PUSHED && | |
204 prior_state_ == CustomButton::BS_HOT)) { | |
205 SetBorderColorForState(state); | |
206 } | |
207 | |
208 prior_state_ = state; | |
209 } | |
210 | |
211 private: | |
212 void SetBackgroundForState(CustomButton::ButtonState state) { | |
213 if (!background_) | |
214 return; | |
215 | |
216 SkColor top; | |
217 SkColor bottom; | |
218 | |
219 switch (state) { | |
220 case CustomButton::BS_NORMAL: | |
Ben Goodger (Google)
2012/09/27 16:16:12
outdent the whole body of the switch by 2 spaces,
| |
221 top = kNormalBackgroundTopColor; | |
222 bottom = kNormalBackgroundBottomColor; | |
223 break; | |
224 | |
225 case CustomButton::BS_HOT: | |
226 top = kHotBackgroundTopColor; | |
227 bottom = kHotBackgroundBottomColor; | |
228 break; | |
229 | |
230 case CustomButton::BS_PUSHED: | |
231 top = kPushedBackgroundTopColor; | |
232 bottom = kPushedBackgroundBottomColor; | |
233 break; | |
234 | |
235 case CustomButton::BS_DISABLED: | |
236 top = kDisabledBackgroundTopColor; | |
237 bottom = kDisabledBackgroundBottomColor; | |
238 break; | |
239 | |
240 default: | |
241 NOTREACHED(); | |
242 break; | |
243 } | |
244 | |
245 background_->SetColors(top, bottom); | |
246 } | |
247 | |
248 void SetShadowForState(CustomButton::ButtonState state) { | |
249 if (state == CustomButton::BS_PUSHED) { | |
250 // Turn off text shadow. | |
251 button_->ClearEmbellishing(); | |
252 } else { | |
253 button_->SetTextShadowColors(kTextShadowColor, kTextShadowColor); | |
254 button_->SetTextShadowOffset(kTextShadowOffsetX, kTextShadowOffsetY); | |
255 } | |
256 } | |
257 | |
258 void SetBorderColorForState(CustomButton::ButtonState state) { | |
259 if (!border_) | |
260 return; | |
261 | |
262 SkColor border_color; | |
263 | |
264 switch (state) { | |
265 case CustomButton::BS_NORMAL: | |
266 border_color = kBorderNormalColor; | |
267 break; | |
268 | |
269 case CustomButton::BS_HOT: | |
270 case CustomButton::BS_PUSHED: | |
271 border_color = kBorderActiveColor; | |
272 break; | |
273 | |
274 case CustomButton::BS_DISABLED: | |
275 border_color = kBorderDisabledColor; | |
276 break; | |
277 | |
278 default: | |
279 NOTREACHED(); | |
280 break; | |
281 } | |
282 | |
283 border_->SetColor(border_color); | |
284 } | |
285 | |
286 // Weak pointer to the associated button. | |
287 TextButton* button_; | |
288 | |
289 // Weak pointers to background and border owned by the CustomButton. | |
290 ChromeStyleTextButtonBackground* background_; | |
291 ChromeStyleTextButtonBorder* border_; | |
292 | |
293 CustomButton::ButtonState prior_state_; | |
294 | |
295 DISALLOW_COPY_AND_ASSIGN(ChromeStyleStateChangedUpdater); | |
296 }; | |
297 } // namespace | |
298 | |
299 | |
300 void ApplyChromeStyle(TextButton* button) { | |
301 button->set_focusable(true); | |
302 button->set_request_focus_on_press(false); | |
303 | |
304 button->set_alignment(TextButton::ALIGN_CENTER); | |
305 button->set_min_width(kMinWidth); | |
306 button->set_min_height(kMinHeight); | |
307 | |
308 button->SetEnabledColor(kEnabledTextColor); | |
309 button->SetDisabledColor(kDisabledTextColor); | |
310 button->SetHoverColor(kHoverTextColor); | |
311 | |
312 ChromeStyleTextButtonBackground* background = | |
313 new ChromeStyleTextButtonBackground; | |
314 button->set_background(background); | |
315 | |
316 ChromeStyleTextButtonBorder* border = new ChromeStyleTextButtonBorder; | |
317 button->set_border(border); | |
318 | |
319 button->set_focus_border(new ChromeStyleFocusBorder); | |
320 | |
321 ChromeStyleStateChangedUpdater* state_changed_updater = | |
322 new ChromeStyleStateChangedUpdater(button, background, border); | |
323 | |
324 button->set_state_changed_delegate(state_changed_updater); | |
325 } | |
326 | |
327 } // namespace views | |
OLD | NEW |