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 = SkFloatToScalar(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] = { |
| 78 SkFloatToScalar(0.0f), kGradientStartLocation, SkFloatToScalar(1.0f) }; |
| 79 |
| 80 painter_.reset( |
| 81 Painter::CreateVerticalMultiColorGradient(colors, pos, count)); |
| 82 SetNativeControlColor( |
| 83 color_utils::AlphaBlend(colors[0], colors[count - 1], 128)); |
| 84 } |
| 85 |
| 86 private: |
| 87 scoped_ptr<Painter> painter_; |
| 88 |
| 89 DISALLOW_COPY_AND_ASSIGN(ChromeStyleTextButtonBackground); |
| 90 }; |
| 91 |
| 92 class ChromeStyleTextButtonBorderPainter : public views::Painter { |
| 93 public: |
| 94 ChromeStyleTextButtonBorderPainter() |
| 95 // This value should be updated prior to rendering; it's set to a |
| 96 // well-defined value here defensively. |
| 97 : color_(SkColorSetRGB(0x0, 0x0, 0x0)) { |
| 98 } |
| 99 |
| 100 // Overriden from Painter |
| 101 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) { |
| 102 SkPaint paint; |
| 103 paint.setStyle(SkPaint::kStroke_Style); |
| 104 paint.setColor(color_); |
| 105 paint.setStrokeWidth(kBorderWidth); |
| 106 |
| 107 // Inset by 1/2 pixel to align the stroke with pixel centers. |
| 108 SkScalar inset = SkFloatToScalar(0.5f); |
| 109 SkRect rect = SkRect::MakeLTRB(inset, inset, |
| 110 SkIntToScalar(size.width()) - inset, |
| 111 SkIntToScalar(size.height()) - inset); |
| 112 |
| 113 canvas->sk_canvas()->drawRoundRect( |
| 114 rect, kBorderRadius, kBorderRadius, paint); |
| 115 } |
| 116 |
| 117 void set_color(SkColor color) { |
| 118 color_ = color; |
| 119 } |
| 120 |
| 121 private: |
| 122 SkColor color_; |
| 123 |
| 124 DISALLOW_COPY_AND_ASSIGN(ChromeStyleTextButtonBorderPainter); |
| 125 }; |
| 126 |
| 127 |
| 128 class ChromeStyleTextButtonBorder : public views::Border { |
| 129 public: |
| 130 ChromeStyleTextButtonBorder() |
| 131 : painter_(new ChromeStyleTextButtonBorderPainter) { |
| 132 } |
| 133 |
| 134 // Overriden from Border |
| 135 virtual void Paint(const View& view, gfx::Canvas* canvas) const { |
| 136 gfx::Rect bounds = view.GetLocalBounds(); |
| 137 int border_inset = GetButtonInset() - kBorderWidth; |
| 138 bounds.Inset(border_inset, border_inset, border_inset, border_inset); |
| 139 Painter::PaintPainterAt(canvas, painter_, bounds); |
| 140 } |
| 141 virtual void GetInsets(gfx::Insets* insets) const { |
| 142 DCHECK(insets); |
| 143 int inset = GetButtonInset(); |
| 144 insets->Set(inset, inset, inset, inset); |
| 145 } |
| 146 |
| 147 void SetColor(SkColor color) { |
| 148 painter_->set_color(color); |
| 149 } |
| 150 |
| 151 private: |
| 152 ChromeStyleTextButtonBorderPainter* painter_; |
| 153 |
| 154 DISALLOW_COPY_AND_ASSIGN(ChromeStyleTextButtonBorder); |
| 155 }; |
| 156 |
| 157 class ChromeStyleFocusBorder : public views::FocusBorder { |
| 158 public: |
| 159 ChromeStyleFocusBorder() {} |
| 160 |
| 161 // Overriden from Border |
| 162 virtual void Paint(const View& view, gfx::Canvas* canvas) const { |
| 163 gfx::Rect rect(view.GetLocalBounds()); |
| 164 SkScalar inset = SkFloatToScalar(GetButtonInset() - kFocusRingWidth / 2.0f); |
| 165 rect.Inset(inset, inset); |
| 166 SkPaint paint; |
| 167 paint.setStyle(SkPaint::kStroke_Style); |
| 168 paint.setStrokeWidth(SkIntToScalar(kFocusRingWidth)); |
| 169 paint.setColor(kFocusRingColor); |
| 170 canvas->DrawRoundRect(rect, SkIntToScalar(kFocusRingRadius), paint); |
| 171 } |
| 172 |
| 173 private: |
| 174 DISALLOW_COPY_AND_ASSIGN(ChromeStyleFocusBorder); |
| 175 }; |
| 176 |
| 177 class ChromeStyleStateChangedUpdater |
| 178 : public CustomButtonStateChangedDelegate { |
| 179 public: |
| 180 // The background and border may be NULL. |
| 181 ChromeStyleStateChangedUpdater(TextButton* button, |
| 182 ChromeStyleTextButtonBackground* background, |
| 183 ChromeStyleTextButtonBorder* border) |
| 184 : button_(button), |
| 185 background_(background), |
| 186 border_(border), |
| 187 prior_state_(button->state()) { |
| 188 SetBackgroundForState(button->state()); |
| 189 SetShadowForState(button->state()); |
| 190 SetBorderColorForState(button->state()); |
| 191 } |
| 192 |
| 193 virtual void StateChanged(CustomButton::ButtonState state) { |
| 194 SetBackgroundForState(state); |
| 195 |
| 196 // Update text shadow when transitioning to/from pushed state. |
| 197 if (state == CustomButton::BS_PUSHED || |
| 198 prior_state_ == CustomButton::BS_PUSHED) { |
| 199 SetShadowForState(state); |
| 200 } |
| 201 |
| 202 // Update border color. We need to change it in all cases except hot |
| 203 // followed by pushed. |
| 204 if (!(state == CustomButton::BS_PUSHED && |
| 205 prior_state_ == CustomButton::BS_HOT)) { |
| 206 SetBorderColorForState(state); |
| 207 } |
| 208 |
| 209 prior_state_ = state; |
| 210 } |
| 211 |
| 212 private: |
| 213 void SetBackgroundForState(CustomButton::ButtonState state) { |
| 214 if (!background_) |
| 215 return; |
| 216 |
| 217 SkColor top; |
| 218 SkColor bottom; |
| 219 |
| 220 switch (state) { |
| 221 case CustomButton::BS_NORMAL: |
| 222 top = kNormalBackgroundTopColor; |
| 223 bottom = kNormalBackgroundBottomColor; |
| 224 break; |
| 225 |
| 226 case CustomButton::BS_HOT: |
| 227 top = kHotBackgroundTopColor; |
| 228 bottom = kHotBackgroundBottomColor; |
| 229 break; |
| 230 |
| 231 case CustomButton::BS_PUSHED: |
| 232 top = kPushedBackgroundTopColor; |
| 233 bottom = kPushedBackgroundBottomColor; |
| 234 break; |
| 235 |
| 236 case CustomButton::BS_DISABLED: |
| 237 top = kDisabledBackgroundTopColor; |
| 238 bottom = kDisabledBackgroundBottomColor; |
| 239 break; |
| 240 |
| 241 default: |
| 242 NOTREACHED(); |
| 243 return; |
| 244 break; |
| 245 } |
| 246 |
| 247 background_->SetColors(top, bottom); |
| 248 } |
| 249 |
| 250 void SetShadowForState(CustomButton::ButtonState state) { |
| 251 if (state == CustomButton::BS_PUSHED) { |
| 252 // Turn off text shadow. |
| 253 button_->ClearEmbellishing(); |
| 254 } else { |
| 255 button_->SetTextShadowColors(kTextShadowColor, kTextShadowColor); |
| 256 button_->SetTextShadowOffset(kTextShadowOffsetX, kTextShadowOffsetY); |
| 257 } |
| 258 } |
| 259 |
| 260 void SetBorderColorForState(CustomButton::ButtonState state) { |
| 261 if (!border_) |
| 262 return; |
| 263 |
| 264 SkColor border_color; |
| 265 |
| 266 switch (state) { |
| 267 case CustomButton::BS_NORMAL: |
| 268 border_color = kBorderNormalColor; |
| 269 break; |
| 270 |
| 271 case CustomButton::BS_HOT: |
| 272 case CustomButton::BS_PUSHED: |
| 273 border_color = kBorderActiveColor; |
| 274 break; |
| 275 |
| 276 case CustomButton::BS_DISABLED: |
| 277 border_color = kBorderDisabledColor; |
| 278 break; |
| 279 |
| 280 default: |
| 281 NOTREACHED(); |
| 282 return; |
| 283 break; |
| 284 } |
| 285 |
| 286 border_->SetColor(border_color); |
| 287 } |
| 288 |
| 289 // Weak pointer to the associated button. |
| 290 TextButton* button_; |
| 291 |
| 292 // Weak pointers to background and border owned by the CustomButton. |
| 293 ChromeStyleTextButtonBackground* background_; |
| 294 ChromeStyleTextButtonBorder* border_; |
| 295 |
| 296 CustomButton::ButtonState prior_state_; |
| 297 |
| 298 DISALLOW_COPY_AND_ASSIGN(ChromeStyleStateChangedUpdater); |
| 299 }; |
| 300 } // namespace |
| 301 |
| 302 |
| 303 void ApplyChromeStyle(TextButton* button) { |
| 304 button->set_focusable(true); |
| 305 button->set_request_focus_on_press(false); |
| 306 |
| 307 button->set_alignment(TextButton::ALIGN_CENTER); |
| 308 button->set_min_width(kMinWidth); |
| 309 button->set_min_height(kMinHeight); |
| 310 |
| 311 button->SetEnabledColor(kEnabledTextColor); |
| 312 button->SetDisabledColor(kDisabledTextColor); |
| 313 button->SetHoverColor(kHoverTextColor); |
| 314 |
| 315 ChromeStyleTextButtonBackground* background = |
| 316 new ChromeStyleTextButtonBackground; |
| 317 button->set_background(background); |
| 318 |
| 319 ChromeStyleTextButtonBorder* border = new ChromeStyleTextButtonBorder; |
| 320 button->set_border(border); |
| 321 |
| 322 button->set_focus_border(new ChromeStyleFocusBorder); |
| 323 |
| 324 ChromeStyleStateChangedUpdater* state_changed_updater = |
| 325 new ChromeStyleStateChangedUpdater(button, background, border); |
| 326 |
| 327 button->set_state_changed_delegate(state_changed_updater); |
| 328 } |
| 329 |
| 330 } // namespace views |
OLD | NEW |