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