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..2dd67eb68acbf27e7884365b3d3c396152a82188 |
--- /dev/null |
+++ b/ui/views/controls/button/chrome_style.cc |
@@ -0,0 +1,330 @@ |
+// 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 = SkFloatToScalar(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] = { |
+ SkFloatToScalar(0.0f), kGradientStartLocation, SkFloatToScalar(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 = SkFloatToScalar(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 = SkFloatToScalar(GetButtonInset() - kFocusRingWidth / 2.0f); |
+ rect.Inset(inset, inset); |
+ SkPaint paint; |
+ paint.setStyle(SkPaint::kStroke_Style); |
+ paint.setStrokeWidth(SkIntToScalar(kFocusRingWidth)); |
+ paint.setColor(kFocusRingColor); |
+ canvas->DrawRoundRect(rect, SkIntToScalar(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: |
+ 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(); |
+ return; |
+ 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(); |
+ return; |
+ 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 |