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