Chromium Code Reviews| 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 |