Chromium Code Reviews| Index: ui/views/controls/button/chrome_style.cc |
| diff --git a/ui/views/controls/button/chrome_style.cc b/ui/views/controls/button/chrome_style.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ec9be13469799f7669a66fa25713cba4b50dea95 |
| --- /dev/null |
| +++ b/ui/views/controls/button/chrome_style.cc |
| @@ -0,0 +1,327 @@ |
| +// Copyright (c) 2012 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. |
| + |
| +#include "ui/views/controls/button/chrome_style.h" |
| + |
| +#include <algorithm> |
| + |
| +#include "ui/gfx/canvas.h" |
| +#include "ui/gfx/color_utils.h" |
| +#include "ui/views/painter.h" |
| +#include "ui/views/background.h" |
| + |
| +namespace views { |
| +namespace { |
| +const int kMinWidth = 72; |
| +const int kMinHeight = 27; |
| + |
| +// Fractional position between top and bottom of button where the |
| +// gradient starts. |
| +const SkScalar kGradientStartLocation = 0.38f; |
| +const SkColor kNormalBackgroundTopColor = SkColorSetRGB(0xf0, 0xf0, 0xf0); |
| +const SkColor kNormalBackgroundBottomColor = SkColorSetRGB(0xe0, 0xe0, 0xe0); |
| +const SkColor kHotBackgroundTopColor = SkColorSetRGB(0xf4, 0xf4, 0xf4); |
| +const SkColor kHotBackgroundBottomColor = SkColorSetRGB(0xe4, 0xe4, 0xe4); |
| +const SkColor kPushedBackgroundTopColor = SkColorSetRGB(0xeb, 0xeb, 0xeb); |
| +const SkColor kPushedBackgroundBottomColor = SkColorSetRGB(0xdb, 0xdb, 0xdb); |
| +const SkColor kDisabledBackgroundTopColor = SkColorSetRGB(0xed, 0xed, 0xed); |
| +const SkColor kDisabledBackgroundBottomColor = SkColorSetRGB(0xde, 0xde, 0xde); |
| + |
| +const SkColor kEnabledTextColor = SkColorSetRGB(0x33, 0x33, 0x33); |
| +const SkColor kDisabledTextColor = SkColorSetRGB(0xaa, 0xaa, 0xaa); |
| +const SkColor kHoverTextColor = SkColorSetRGB(0x0, 0x0, 0x0); |
| + |
| +const SkColor kTextShadowColor = SkColorSetRGB(0xf0, 0xf0, 0xf0); |
| +const int kTextShadowOffsetX = 0; |
| +const int kTextShadowOffsetY = 1; |
| + |
| +const int kBorderWidth = 1; |
| +const int kBorderRadius = 2; |
| +const SkColor kBorderNormalColor = SkColorSetARGB(0x3f, 0x0, 0x0, 0x0); |
| +const SkColor kBorderActiveColor = SkColorSetARGB(0x4b, 0x0, 0x0, 0x0); |
| +const SkColor kBorderDisabledColor = SkColorSetARGB(0x1d, 0x0, 0x0, 0x0); |
| + |
| +const int kFocusRingWidth = 2; |
| +const int kFocusRingRadius = 2; |
| +const SkColor kFocusRingColor = SkColorSetARGB(0x7f, 0xe5, 0x97, 0x00); |
| + |
| +// Returns the uniform inset of the button from its local bounds. |
| +int GetButtonInset() { |
| + return std::max(kBorderWidth, kFocusRingWidth); |
| +} |
| + |
| +class ChromeStyleTextButtonBackground : public Background { |
| + public: |
| + ChromeStyleTextButtonBackground() { |
| + } |
| + |
| + virtual ~ChromeStyleTextButtonBackground() { |
| + } |
| + |
| + // Overriden from Background |
| + virtual void Paint(gfx::Canvas* canvas, View* view) const { |
| + if (painter_.get()) |
| + { |
| + gfx::Rect bounds = view->GetLocalBounds(); |
| + // Inset to the actual button region. |
| + int inset = GetButtonInset(); |
| + bounds.Inset(inset, inset, inset, inset); |
| + Painter::PaintPainterAt(canvas, painter_.get(), bounds); |
| + } |
| + } |
| + |
| + void SetColors(SkColor top, SkColor bottom) { |
| + static const int count = 3; |
| + SkColor colors[count] = { top, top, bottom }; |
| + SkScalar pos[count] = { 0.0f, kGradientStartLocation, 1.0f }; |
| + |
| + painter_.reset( |
| + Painter::CreateVerticalMultiColorGradient(colors, pos, count)); |
| + SetNativeControlColor( |
| + color_utils::AlphaBlend(colors[0], colors[count - 1], 128)); |
| + } |
| + |
| + private: |
| + scoped_ptr<Painter> painter_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ChromeStyleTextButtonBackground); |
| +}; |
| + |
| +class ChromeStyleTextButtonBorderPainter : public views::Painter { |
| + public: |
| + ChromeStyleTextButtonBorderPainter() |
| + // This value should be updated prior to rendering; it's set to a |
| + // well-defined value here defensively. |
| + : color_(SkColorSetRGB(0x0, 0x0, 0x0)) { |
| + } |
| + |
| + // Overriden from Painter |
| + virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) { |
| + SkPaint paint; |
| + paint.setStyle(SkPaint::kStroke_Style); |
| + paint.setColor(color_); |
| + paint.setStrokeWidth(kBorderWidth); |
| + |
| + // Inset by 1/2 pixel to align the stroke with pixel centers. |
| + SkScalar inset = 0.5f; |
| + SkRect rect = SkRect::MakeLTRB(inset, inset, |
| + SkIntToScalar(size.width()) - inset, |
| + SkIntToScalar(size.height()) - inset); |
| + |
| + canvas->sk_canvas()->drawRoundRect( |
| + rect, kBorderRadius, kBorderRadius, paint); |
| + } |
| + |
| + void set_color(SkColor color) { |
| + color_ = color; |
| + } |
| + |
| + private: |
| + SkColor color_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ChromeStyleTextButtonBorderPainter); |
| +}; |
| + |
| + |
| +class ChromeStyleTextButtonBorder : public views::Border { |
| + public: |
| + ChromeStyleTextButtonBorder() |
| + : painter_(new ChromeStyleTextButtonBorderPainter) { |
| + } |
| + |
| + // Overriden from Border |
| + virtual void Paint(const View& view, gfx::Canvas* canvas) const { |
| + gfx::Rect bounds = view.GetLocalBounds(); |
| + int border_inset = GetButtonInset() - kBorderWidth; |
| + bounds.Inset(border_inset, border_inset, border_inset, border_inset); |
| + Painter::PaintPainterAt(canvas, painter_, bounds); |
| + } |
| + virtual void GetInsets(gfx::Insets* insets) const { |
| + DCHECK(insets); |
| + int inset = GetButtonInset(); |
| + insets->Set(inset, inset, inset, inset); |
| + } |
| + |
| + void SetColor(SkColor color) { |
| + painter_->set_color(color); |
| + } |
| + |
| + private: |
| + ChromeStyleTextButtonBorderPainter* painter_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ChromeStyleTextButtonBorder); |
| +}; |
| + |
| +class ChromeStyleFocusBorder : public views::FocusBorder { |
| + public: |
| + ChromeStyleFocusBorder() {} |
| + |
| + // Overriden from Border |
| + virtual void Paint(const View& view, gfx::Canvas* canvas) const { |
| + gfx::Rect rect(view.GetLocalBounds()); |
| + SkScalar inset = GetButtonInset() - kFocusRingWidth / 2.0f; |
| + rect.Inset(inset, inset); |
| + SkPaint paint; |
| + paint.setStyle(SkPaint::kStroke_Style); |
| + paint.setStrokeWidth(SkScalar(kFocusRingWidth)); |
| + paint.setColor(kFocusRingColor); |
| + canvas->DrawRoundRect(rect, SkScalar(kFocusRingRadius), paint); |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(ChromeStyleFocusBorder); |
| +}; |
| + |
| +class ChromeStyleStateChangedUpdater |
| + : public CustomButtonStateChangedDelegate { |
| + public: |
| + // The background and border may be NULL. |
| + ChromeStyleStateChangedUpdater(TextButton* button, |
| + ChromeStyleTextButtonBackground* background, |
| + ChromeStyleTextButtonBorder* border) |
| + : button_(button), |
| + background_(background), |
| + border_(border), |
| + prior_state_(button->state()) { |
| + SetBackgroundForState(button->state()); |
| + SetShadowForState(button->state()); |
| + SetBorderColorForState(button->state()); |
| + } |
| + |
| + virtual void StateChanged(CustomButton::ButtonState state) { |
| + SetBackgroundForState(state); |
| + |
| + // Update text shadow when transitioning to/from pushed state. |
| + if (state == CustomButton::BS_PUSHED || |
| + prior_state_ == CustomButton::BS_PUSHED) { |
| + SetShadowForState(state); |
| + } |
| + |
| + // Update border color. We need to change it in all cases except hot |
| + // followed by pushed. |
| + if (!(state == CustomButton::BS_PUSHED && |
| + prior_state_ == CustomButton::BS_HOT)) { |
| + SetBorderColorForState(state); |
| + } |
| + |
| + prior_state_ = state; |
| + } |
| + |
| + private: |
| + void SetBackgroundForState(CustomButton::ButtonState state) { |
| + if (!background_) |
| + return; |
| + |
| + SkColor top; |
| + SkColor bottom; |
| + |
| + switch (state) { |
| + case CustomButton::BS_NORMAL: |
|
Ben Goodger (Google)
2012/09/27 16:16:12
outdent the whole body of the switch by 2 spaces,
|
| + top = kNormalBackgroundTopColor; |
| + bottom = kNormalBackgroundBottomColor; |
| + break; |
| + |
| + case CustomButton::BS_HOT: |
| + top = kHotBackgroundTopColor; |
| + bottom = kHotBackgroundBottomColor; |
| + break; |
| + |
| + case CustomButton::BS_PUSHED: |
| + top = kPushedBackgroundTopColor; |
| + bottom = kPushedBackgroundBottomColor; |
| + break; |
| + |
| + case CustomButton::BS_DISABLED: |
| + top = kDisabledBackgroundTopColor; |
| + bottom = kDisabledBackgroundBottomColor; |
| + break; |
| + |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + |
| + background_->SetColors(top, bottom); |
| + } |
| + |
| + void SetShadowForState(CustomButton::ButtonState state) { |
| + if (state == CustomButton::BS_PUSHED) { |
| + // Turn off text shadow. |
| + button_->ClearEmbellishing(); |
| + } else { |
| + button_->SetTextShadowColors(kTextShadowColor, kTextShadowColor); |
| + button_->SetTextShadowOffset(kTextShadowOffsetX, kTextShadowOffsetY); |
| + } |
| + } |
| + |
| + void SetBorderColorForState(CustomButton::ButtonState state) { |
| + if (!border_) |
| + return; |
| + |
| + SkColor border_color; |
| + |
| + switch (state) { |
| + case CustomButton::BS_NORMAL: |
| + border_color = kBorderNormalColor; |
| + break; |
| + |
| + case CustomButton::BS_HOT: |
| + case CustomButton::BS_PUSHED: |
| + border_color = kBorderActiveColor; |
| + break; |
| + |
| + case CustomButton::BS_DISABLED: |
| + border_color = kBorderDisabledColor; |
| + break; |
| + |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + |
| + border_->SetColor(border_color); |
| + } |
| + |
| + // Weak pointer to the associated button. |
| + TextButton* button_; |
| + |
| + // Weak pointers to background and border owned by the CustomButton. |
| + ChromeStyleTextButtonBackground* background_; |
| + ChromeStyleTextButtonBorder* border_; |
| + |
| + CustomButton::ButtonState prior_state_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ChromeStyleStateChangedUpdater); |
| +}; |
| +} // namespace |
| + |
| + |
| +void ApplyChromeStyle(TextButton* button) { |
| + button->set_focusable(true); |
| + button->set_request_focus_on_press(false); |
| + |
| + button->set_alignment(TextButton::ALIGN_CENTER); |
| + button->set_min_width(kMinWidth); |
| + button->set_min_height(kMinHeight); |
| + |
| + button->SetEnabledColor(kEnabledTextColor); |
| + button->SetDisabledColor(kDisabledTextColor); |
| + button->SetHoverColor(kHoverTextColor); |
| + |
| + ChromeStyleTextButtonBackground* background = |
| + new ChromeStyleTextButtonBackground; |
| + button->set_background(background); |
| + |
| + ChromeStyleTextButtonBorder* border = new ChromeStyleTextButtonBorder; |
| + button->set_border(border); |
| + |
| + button->set_focus_border(new ChromeStyleFocusBorder); |
| + |
| + ChromeStyleStateChangedUpdater* state_changed_updater = |
| + new ChromeStyleStateChangedUpdater(button, background, border); |
| + |
| + button->set_state_changed_delegate(state_changed_updater); |
| +} |
| + |
| +} // namespace views |