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/checkbox.h"
6
7#include "ui/accessibility/ax_view_state.h"
8#include "ui/base/resource/resource_bundle.h"
9#include "ui/resources/grit/ui_resources.h"
10#include "ui/views/controls/button/label_button_border.h"
11#include "ui/views/painter.h"
12
13namespace views {
14
15// static
16const char Checkbox::kViewClassName[] = "Checkbox";
17
18Checkbox::Checkbox(const base::string16& label)
19    : LabelButton(NULL, label),
20      checked_(false) {
21  SetHorizontalAlignment(gfx::ALIGN_LEFT);
22  scoped_ptr<LabelButtonBorder> button_border(new LabelButtonBorder(style()));
23  button_border->SetPainter(false, STATE_HOVERED, NULL);
24  button_border->SetPainter(false, STATE_PRESSED, NULL);
25  // Inset the trailing side by a couple pixels for the focus border.
26  button_border->set_insets(gfx::Insets(0, 0, 0, 2));
27  SetBorder(button_border.PassAs<Border>());
28  SetFocusable(true);
29
30  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
31
32  // Unchecked/Unfocused images.
33  SetCustomImage(false, false, STATE_NORMAL,
34                 *rb.GetImageSkiaNamed(IDR_CHECKBOX));
35  SetCustomImage(false, false, STATE_HOVERED,
36                 *rb.GetImageSkiaNamed(IDR_CHECKBOX_HOVER));
37  SetCustomImage(false, false, STATE_PRESSED,
38                 *rb.GetImageSkiaNamed(IDR_CHECKBOX_PRESSED));
39  SetCustomImage(false, false, STATE_DISABLED,
40                 *rb.GetImageSkiaNamed(IDR_CHECKBOX_DISABLED));
41
42  // Checked/Unfocused images.
43  SetCustomImage(true, false, STATE_NORMAL,
44                 *rb.GetImageSkiaNamed(IDR_CHECKBOX_CHECKED));
45  SetCustomImage(true, false, STATE_HOVERED,
46                 *rb.GetImageSkiaNamed(IDR_CHECKBOX_CHECKED_HOVER));
47  SetCustomImage(true, false, STATE_PRESSED,
48                 *rb.GetImageSkiaNamed(IDR_CHECKBOX_CHECKED_PRESSED));
49  SetCustomImage(true, false, STATE_DISABLED,
50                 *rb.GetImageSkiaNamed(IDR_CHECKBOX_CHECKED_DISABLED));
51
52  // Unchecked/Focused images.
53  SetCustomImage(false, true, STATE_NORMAL,
54                 *rb.GetImageSkiaNamed(IDR_CHECKBOX_FOCUSED));
55  SetCustomImage(false, true, STATE_HOVERED,
56                 *rb.GetImageSkiaNamed(IDR_CHECKBOX_FOCUSED_HOVER));
57  SetCustomImage(false, true, STATE_PRESSED,
58                 *rb.GetImageSkiaNamed(IDR_CHECKBOX_FOCUSED_PRESSED));
59
60  // Checked/Focused images.
61  SetCustomImage(true, true, STATE_NORMAL,
62                 *rb.GetImageSkiaNamed(IDR_CHECKBOX_FOCUSED_CHECKED));
63  SetCustomImage(true, true, STATE_HOVERED,
64                 *rb.GetImageSkiaNamed(IDR_CHECKBOX_FOCUSED_CHECKED_HOVER));
65  SetCustomImage(true, true, STATE_PRESSED,
66                 *rb.GetImageSkiaNamed(IDR_CHECKBOX_FOCUSED_CHECKED_PRESSED));
67
68  // Limit the checkbox height to match the legacy appearance.
69  const gfx::Size preferred_size(LabelButton::GetPreferredSize());
70  SetMinSize(gfx::Size(0, preferred_size.height() + 4));
71}
72
73Checkbox::~Checkbox() {
74}
75
76void Checkbox::SetChecked(bool checked) {
77  checked_ = checked;
78  UpdateImage();
79}
80
81void Checkbox::Layout() {
82  LabelButton::Layout();
83
84  // Construct a focus painter that only surrounds the label area.
85  gfx::Rect rect = label()->GetMirroredBounds();
86  rect.Inset(-2, 3);
87  SetFocusPainter(Painter::CreateDashedFocusPainterWithInsets(
88                      gfx::Insets(rect.y(), rect.x(),
89                                  height() - rect.bottom(),
90                                  width() - rect.right())));
91}
92
93const char* Checkbox::GetClassName() const {
94  return kViewClassName;
95}
96
97void Checkbox::GetAccessibleState(ui::AXViewState* state) {
98  LabelButton::GetAccessibleState(state);
99  state->role = ui::AX_ROLE_CHECK_BOX;
100  if (checked())
101    state->AddStateFlag(ui::AX_STATE_CHECKED);
102}
103
104void Checkbox::OnFocus() {
105  LabelButton::OnFocus();
106  UpdateImage();
107}
108
109void Checkbox::OnBlur() {
110  LabelButton::OnBlur();
111  UpdateImage();
112}
113
114const gfx::ImageSkia& Checkbox::GetImage(ButtonState for_state) {
115  const size_t checked_index = checked_ ? 1 : 0;
116  const size_t focused_index = HasFocus() ? 1 : 0;
117  if (for_state != STATE_NORMAL &&
118      images_[checked_index][focused_index][for_state].isNull())
119    return images_[checked_index][focused_index][STATE_NORMAL];
120  return images_[checked_index][focused_index][for_state];
121}
122
123void Checkbox::SetCustomImage(bool checked,
124                              bool focused,
125                              ButtonState for_state,
126                              const gfx::ImageSkia& image) {
127  const size_t checked_index = checked ? 1 : 0;
128  const size_t focused_index = focused ? 1 : 0;
129  images_[checked_index][focused_index][for_state] = image;
130  UpdateImage();
131}
132
133void Checkbox::NotifyClick(const ui::Event& event) {
134  SetChecked(!checked());
135  LabelButton::NotifyClick(event);
136}
137
138ui::NativeTheme::Part Checkbox::GetThemePart() const {
139  return ui::NativeTheme::kCheckbox;
140}
141
142void Checkbox::GetExtraParams(ui::NativeTheme::ExtraParams* params) const {
143  LabelButton::GetExtraParams(params);
144  params->button.checked = checked_;
145}
146
147}  // namespace views
148