Chromium Code Reviews| Index: ui/views/controls/button/web_style_text_button.cc |
| diff --git a/ui/views/controls/button/web_style_text_button.cc b/ui/views/controls/button/web_style_text_button.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ce81df785a0eaf5c447072d9b8c681429ff8116a |
| --- /dev/null |
| +++ b/ui/views/controls/button/web_style_text_button.cc |
| @@ -0,0 +1,299 @@ |
| +// 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/web_style_text_button.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); |
| +} |
| +} // namespace |
| + |
| +class WebStyleTextButtonBackground : public Background { |
|
Ben Goodger (Google)
2012/09/17 22:37:26
Also I would like to come up with a different name
Mike Wittman
2012/09/21 22:53:18
Works for me. I wasn't sure what the best name fo
|
| + public: |
| + WebStyleTextButtonBackground() { |
| + } |
| + |
| + virtual ~WebStyleTextButtonBackground() { |
| + } |
| + |
| + // 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(WebStyleTextButtonBackground); |
| +}; |
| + |
| +class WebStyleTextButtonBorderPainter : public views::Painter { |
| + public: |
| + WebStyleTextButtonBorderPainter() |
| + // 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(WebStyleTextButtonBorderPainter); |
| +}; |
| + |
| + |
| +class WebStyleTextButtonBorder : public views::Border { |
| + public: |
| + WebStyleTextButtonBorder() |
| + : painter_(new WebStyleTextButtonBorderPainter) { |
| + } |
| + |
| + // 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: |
| + WebStyleTextButtonBorderPainter* painter_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(WebStyleTextButtonBorder); |
| +}; |
| + |
| + |
| + |
| +const char WebStyleTextButton::kViewClassName[] = "WebStyleTextButton"; |
| + |
| +WebStyleTextButton::WebStyleTextButton(ButtonListener* listener, |
| + const string16& title) |
| + : TextButton(listener, title), |
| + prior_state_(state()), |
| + web_style_background_(NULL), |
| + web_style_border_(NULL) { |
| + set_focusable(true); |
| + set_request_focus_on_press(false); |
| + |
| + set_alignment(ALIGN_CENTER); |
| + web_style_background_ = new WebStyleTextButtonBackground; |
| + set_background(web_style_background_); |
| + |
| + SetEnabledColor(kEnabledTextColor); |
| + SetDisabledColor(kDisabledTextColor); |
| + SetHoverColor(kHoverTextColor); |
| + |
| + SetBackgroundForState(state()); |
| + SetShadowForState(state()); |
| + |
| + web_style_border_ = new WebStyleTextButtonBorder; |
| + set_border(web_style_border_); |
| + |
| + SetBorderColorForState(state()); |
| +} |
| + |
| +gfx::Size WebStyleTextButton::GetPreferredSize() { |
| + gfx::Size prefsize(TextButton::GetPreferredSize()); |
| + prefsize.set_width(std::max(prefsize.height(), kMinWidth)); |
| + prefsize.set_height(std::max(prefsize.height(), kMinHeight)); |
| + |
| + return prefsize; |
| +} |
| + |
| +void WebStyleTextButton::OnPaintFocusBorder(gfx::Canvas* canvas) { |
| + if (HasFocus() && (focusable() || IsAccessibilityFocusable())) { |
| + gfx::Rect rect(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); |
| + } |
| +} |
| + |
| +void WebStyleTextButton::StateChanged() { |
| + TextButton::StateChanged(); |
| + |
| + SetBackgroundForState(state()); |
| + |
| + // Update text shadow when transitioning to/from pushed state. |
| + if (state() == BS_PUSHED || prior_state_ == BS_PUSHED) { |
| + SetShadowForState(state()); |
| + } |
| + |
| + // Update border color. We need to change it in all cases except hot |
| + // followed by pushed. |
| + if (!(state() == BS_PUSHED && prior_state_ == BS_HOT)) { |
| + SetBorderColorForState(state()); |
| + } |
| + |
| + prior_state_ = state(); |
| +} |
| + |
| +std::string WebStyleTextButton::GetClassName() const { |
| + return kViewClassName; |
| +} |
| + |
| +void WebStyleTextButton::SetBackgroundForState(ButtonState state) { |
| + SkColor top; |
| + SkColor bottom; |
| + |
| + switch (state) { |
| + case BS_NORMAL: |
| + top = kNormalBackgroundTopColor; |
| + bottom = kNormalBackgroundBottomColor; |
| + break; |
| + |
| + case BS_HOT: |
| + top = kHotBackgroundTopColor; |
| + bottom = kHotBackgroundBottomColor; |
| + break; |
| + |
| + case BS_PUSHED: |
| + top = kPushedBackgroundTopColor; |
| + bottom = kPushedBackgroundBottomColor; |
| + break; |
| + |
| + case BS_DISABLED: |
| + top = kDisabledBackgroundTopColor; |
| + bottom = kDisabledBackgroundBottomColor; |
| + break; |
| + |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + |
| + web_style_background_->SetColors(top, bottom); |
| +} |
| + |
| +void WebStyleTextButton::SetShadowForState(ButtonState state) { |
| + if (state == BS_PUSHED) { |
| + // Turn off text shadow. |
| + ClearEmbellishing(); |
| + } else { |
| + SetTextShadowColors(kTextShadowColor, kTextShadowColor); |
| + SetTextShadowOffset(kTextShadowOffsetX, kTextShadowOffsetY); |
| + } |
| +} |
| + |
| +void WebStyleTextButton::SetBorderColorForState(ButtonState state) { |
| + SkColor border_color; |
| + |
| + switch (state) { |
| + case BS_NORMAL: |
| + border_color = kBorderNormalColor; |
| + break; |
| + |
| + case BS_HOT: |
| + case BS_PUSHED: |
| + border_color = kBorderActiveColor; |
| + break; |
| + |
| + case BS_DISABLED: |
| + border_color = kBorderDisabledColor; |
| + break; |
| + |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + |
| + web_style_border_->SetColor(border_color); |
| +} |
| + |
| +} // namespace views |