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/label_button_border.h" 6 7 #include "base/logging.h" 8 #include "third_party/skia/include/core/SkPaint.h" 9 #include "third_party/skia/include/effects/SkLerpXfermode.h" 10 #include "ui/base/resource/resource_bundle.h" 11 #include "ui/gfx/animation/animation.h" 12 #include "ui/gfx/canvas.h" 13 #include "ui/gfx/rect.h" 14 #include "ui/gfx/skia_util.h" 15 #include "ui/gfx/sys_color_change_listener.h" 16 #include "ui/native_theme/native_theme.h" 17 #include "ui/resources/grit/ui_resources.h" 18 #include "ui/views/border.h" 19 #include "ui/views/controls/button/label_button.h" 20 #include "ui/views/native_theme_delegate.h" 21 22 namespace views { 23 24 namespace { 25 26 // Insets for the unified button images. This assumes that the images 27 // are of a 9 grid, of 5x5 size each. 28 const int kButtonInsets = 5; 29 30 // The text-button hot and pushed image IDs; normal is unadorned by default. 31 const int kTextHoveredImages[] = IMAGE_GRID(IDR_TEXTBUTTON_HOVER); 32 const int kTextPressedImages[] = IMAGE_GRID(IDR_TEXTBUTTON_PRESSED); 33 34 // A helper function to paint the appropriate broder images. 35 void PaintHelper(LabelButtonBorder* border, 36 gfx::Canvas* canvas, 37 ui::NativeTheme::State state, 38 const gfx::Rect& rect, 39 const ui::NativeTheme::ExtraParams& extra) { 40 Painter* painter = 41 border->GetPainter(extra.button.is_focused, 42 Button::GetButtonStateFrom(state)); 43 // Paint any corresponding unfocused painter if there is no focused painter. 44 if (!painter && extra.button.is_focused) 45 painter = border->GetPainter(false, Button::GetButtonStateFrom(state)); 46 if (painter) 47 Painter::PaintPainterAt(canvas, painter, rect); 48 } 49 50 } // namespace 51 52 LabelButtonBorder::LabelButtonBorder(Button::ButtonStyle style) 53 : style_(style) { 54 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 55 const gfx::Insets insets(kButtonInsets, 56 kButtonInsets, 57 kButtonInsets, 58 kButtonInsets); 59 60 if (style == Button::STYLE_BUTTON) { 61 set_insets(gfx::Insets(8, 13, 8, 13)); 62 SetPainter(false, Button::STATE_NORMAL, 63 Painter::CreateImagePainter( 64 *rb.GetImageSkiaNamed(IDR_BUTTON_NORMAL), insets)); 65 SetPainter(false, Button::STATE_HOVERED, 66 Painter::CreateImagePainter( 67 *rb.GetImageSkiaNamed(IDR_BUTTON_HOVER), insets)); 68 SetPainter(false, Button::STATE_PRESSED, 69 Painter::CreateImagePainter( 70 *rb.GetImageSkiaNamed(IDR_BUTTON_PRESSED), insets)); 71 SetPainter(false, Button::STATE_DISABLED, 72 Painter::CreateImagePainter( 73 *rb.GetImageSkiaNamed(IDR_BUTTON_DISABLED), insets)); 74 SetPainter(true, Button::STATE_NORMAL, 75 Painter::CreateImagePainter( 76 *rb.GetImageSkiaNamed(IDR_BUTTON_FOCUSED_NORMAL), insets)); 77 SetPainter(true, Button::STATE_HOVERED, 78 Painter::CreateImagePainter( 79 *rb.GetImageSkiaNamed(IDR_BUTTON_FOCUSED_HOVER), insets)); 80 SetPainter(true, Button::STATE_PRESSED, 81 Painter::CreateImagePainter( 82 *rb.GetImageSkiaNamed(IDR_BUTTON_FOCUSED_PRESSED), insets)); 83 SetPainter(true, Button::STATE_DISABLED, 84 Painter::CreateImagePainter( 85 *rb.GetImageSkiaNamed(IDR_BUTTON_DISABLED), insets)); 86 } else if (style == Button::STYLE_TEXTBUTTON) { 87 set_insets(gfx::Insets(5, 6, 5, 6)); 88 SetPainter(false, Button::STATE_HOVERED, 89 Painter::CreateImageGridPainter(kTextHoveredImages)); 90 SetPainter(false, Button::STATE_PRESSED, 91 Painter::CreateImageGridPainter(kTextPressedImages)); 92 } 93 } 94 95 LabelButtonBorder::~LabelButtonBorder() {} 96 97 void LabelButtonBorder::Paint(const View& view, gfx::Canvas* canvas) { 98 const NativeThemeDelegate* native_theme_delegate = 99 static_cast<const LabelButton*>(&view); 100 gfx::Rect rect(native_theme_delegate->GetThemePaintRect()); 101 ui::NativeTheme::ExtraParams extra; 102 const gfx::Animation* animation = native_theme_delegate->GetThemeAnimation(); 103 ui::NativeTheme::State state = native_theme_delegate->GetThemeState(&extra); 104 105 if (animation && animation->is_animating()) { 106 // Linearly interpolate background and foreground painters during animation. 107 const SkRect sk_rect = gfx::RectToSkRect(rect); 108 canvas->sk_canvas()->saveLayer(&sk_rect, NULL); 109 state = native_theme_delegate->GetBackgroundThemeState(&extra); 110 PaintHelper(this, canvas, state, rect, extra); 111 112 SkPaint paint; 113 skia::RefPtr<SkXfermode> sk_lerp_xfer = 114 skia::AdoptRef(SkLerpXfermode::Create(animation->GetCurrentValue())); 115 paint.setXfermode(sk_lerp_xfer.get()); 116 canvas->sk_canvas()->saveLayer(&sk_rect, &paint); 117 state = native_theme_delegate->GetForegroundThemeState(&extra); 118 PaintHelper(this, canvas, state, rect, extra); 119 canvas->sk_canvas()->restore(); 120 121 canvas->sk_canvas()->restore(); 122 } else { 123 PaintHelper(this, canvas, state, rect, extra); 124 } 125 } 126 127 gfx::Insets LabelButtonBorder::GetInsets() const { 128 return insets_; 129 } 130 131 gfx::Size LabelButtonBorder::GetMinimumSize() const { 132 gfx::Size minimum_size; 133 for (int i = 0; i < 2; ++i) { 134 for (int j = 0; j < Button::STATE_COUNT; ++j) { 135 if (painters_[i][j]) 136 minimum_size.SetToMax(painters_[i][j]->GetMinimumSize()); 137 } 138 } 139 return minimum_size; 140 } 141 142 Painter* LabelButtonBorder::GetPainter(bool focused, 143 Button::ButtonState state) { 144 return painters_[focused ? 1 : 0][state].get(); 145 } 146 147 void LabelButtonBorder::SetPainter(bool focused, 148 Button::ButtonState state, 149 Painter* painter) { 150 painters_[focused ? 1 : 0][state].reset(painter); 151 } 152 153 } // namespace views 154