15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/button/label_button_border.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "third_party/skia/include/core/SkPaint.h" 93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "third_party/skia/include/effects/SkLerpXfermode.h" 10a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 11d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/animation.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h" 143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ui/gfx/skia_util.h" 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/gfx/sys_color_change_listener.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/native_theme/native_theme.h" 1703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "ui/resources/grit/ui_resources.h" 18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/border.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/button/label_button.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/native_theme_delegate.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Insets for the unified button images. This assumes that the images 27a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// are of a 9 grid, of 5x5 size each. 28a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)const int kButtonInsets = 5; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The text-button hot and pushed image IDs; normal is unadorned by default. 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kTextHoveredImages[] = IMAGE_GRID(IDR_TEXTBUTTON_HOVER); 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kTextPressedImages[] = IMAGE_GRID(IDR_TEXTBUTTON_PRESSED); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// A helper function to paint the appropriate broder images. 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PaintHelper(LabelButtonBorder* border, 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Canvas* canvas, 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::NativeTheme::State state, 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Rect& rect, 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ui::NativeTheme::ExtraParams& extra) { 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Painter* painter = 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) border->GetPainter(extra.button.is_focused, 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Button::GetButtonStateFrom(state)); 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Paint any corresponding unfocused painter if there is no focused painter. 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!painter && extra.button.is_focused) 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) painter = border->GetPainter(false, Button::GetButtonStateFrom(state)); 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (painter) 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Painter::PaintPainterAt(canvas, painter, rect); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)LabelButtonBorder::LabelButtonBorder(Button::ButtonStyle style) 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : style_(style) { 54a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 55a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const gfx::Insets insets(kButtonInsets, 56a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) kButtonInsets, 57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) kButtonInsets, 58a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) kButtonInsets); 59a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (style == Button::STYLE_BUTTON) { 617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) set_insets(gfx::Insets(8, 13, 8, 13)); 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetPainter(false, Button::STATE_NORMAL, 63a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) Painter::CreateImagePainter( 64a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *rb.GetImageSkiaNamed(IDR_BUTTON_NORMAL), insets)); 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetPainter(false, Button::STATE_HOVERED, 66a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) Painter::CreateImagePainter( 67a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *rb.GetImageSkiaNamed(IDR_BUTTON_HOVER), insets)); 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetPainter(false, Button::STATE_PRESSED, 69a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) Painter::CreateImagePainter( 70a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *rb.GetImageSkiaNamed(IDR_BUTTON_PRESSED), insets)); 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SetPainter(false, Button::STATE_DISABLED, 72a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) Painter::CreateImagePainter( 73a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *rb.GetImageSkiaNamed(IDR_BUTTON_DISABLED), insets)); 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetPainter(true, Button::STATE_NORMAL, 75a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) Painter::CreateImagePainter( 76a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *rb.GetImageSkiaNamed(IDR_BUTTON_FOCUSED_NORMAL), insets)); 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetPainter(true, Button::STATE_HOVERED, 78a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) Painter::CreateImagePainter( 79a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *rb.GetImageSkiaNamed(IDR_BUTTON_FOCUSED_HOVER), insets)); 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetPainter(true, Button::STATE_PRESSED, 81a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) Painter::CreateImagePainter( 82a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *rb.GetImageSkiaNamed(IDR_BUTTON_FOCUSED_PRESSED), insets)); 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SetPainter(true, Button::STATE_DISABLED, 84a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) Painter::CreateImagePainter( 85a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *rb.GetImageSkiaNamed(IDR_BUTTON_DISABLED), insets)); 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (style == Button::STYLE_TEXTBUTTON) { 8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) set_insets(gfx::Insets(5, 6, 5, 6)); 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetPainter(false, Button::STATE_HOVERED, 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Painter::CreateImageGridPainter(kTextHoveredImages)); 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetPainter(false, Button::STATE_PRESSED, 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Painter::CreateImageGridPainter(kTextPressedImages)); 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LabelButtonBorder::~LabelButtonBorder() {} 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LabelButtonBorder::Paint(const View& view, gfx::Canvas* canvas) { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const NativeThemeDelegate* native_theme_delegate = 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<const LabelButton*>(&view); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect rect(native_theme_delegate->GetThemePaintRect()); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::NativeTheme::ExtraParams extra; 102d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const gfx::Animation* animation = native_theme_delegate->GetThemeAnimation(); 103b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ui::NativeTheme::State state = native_theme_delegate->GetThemeState(&extra); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (animation && animation->is_animating()) { 1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // Linearly interpolate background and foreground painters during animation. 1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) const SkRect sk_rect = gfx::RectToSkRect(rect); 1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) canvas->sk_canvas()->saveLayer(&sk_rect, NULL); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state = native_theme_delegate->GetBackgroundThemeState(&extra); 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PaintHelper(this, canvas, state, rect, extra); 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) SkPaint paint; 1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) skia::RefPtr<SkXfermode> sk_lerp_xfer = 1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) skia::AdoptRef(SkLerpXfermode::Create(animation->GetCurrentValue())); 1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) paint.setXfermode(sk_lerp_xfer.get()); 1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) canvas->sk_canvas()->saveLayer(&sk_rect, &paint); 117b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) state = native_theme_delegate->GetForegroundThemeState(&extra); 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PaintHelper(this, canvas, state, rect, extra); 1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) canvas->sk_canvas()->restore(); 1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) canvas->sk_canvas()->restore(); 122b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } else { 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PaintHelper(this, canvas, state, rect, extra); 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Insets LabelButtonBorder::GetInsets() const { 12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return insets_; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)gfx::Size LabelButtonBorder::GetMinimumSize() const { 132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Size minimum_size; 133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (int i = 0; i < 2; ++i) { 134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (int j = 0; j < Button::STATE_COUNT; ++j) { 135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (painters_[i][j]) 136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) minimum_size.SetToMax(painters_[i][j]->GetMinimumSize()); 137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return minimum_size; 140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Painter* LabelButtonBorder::GetPainter(bool focused, 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Button::ButtonState state) { 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return painters_[focused ? 1 : 0][state].get(); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void LabelButtonBorder::SetPainter(bool focused, 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Button::ButtonState state, 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Painter* painter) { 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) painters_[focused ? 1 : 0][state].reset(painter); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace views 154