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/radio_button.h" 6 7#include "base/logging.h" 8#include "grit/ui_resources.h" 9#include "ui/base/accessibility/accessible_view_state.h" 10#include "ui/base/resource/resource_bundle.h" 11#include "ui/views/widget/widget.h" 12 13namespace views { 14 15// static 16const char RadioButton::kViewClassName[] = "RadioButton"; 17 18RadioButton::RadioButton(const string16& label, int group_id) 19 : Checkbox(label) { 20 SetGroup(group_id); 21 22 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 23 24 // Unchecked/Unfocused images. 25 SetCustomImage(false, false, STATE_NORMAL, 26 *rb.GetImageSkiaNamed(IDR_RADIO)); 27 SetCustomImage(false, false, STATE_HOVERED, 28 *rb.GetImageSkiaNamed(IDR_RADIO_HOVER)); 29 SetCustomImage(false, false, STATE_PRESSED, 30 *rb.GetImageSkiaNamed(IDR_RADIO_PRESSED)); 31 SetCustomImage(false, false, STATE_DISABLED, 32 *rb.GetImageSkiaNamed(IDR_RADIO_DISABLED)); 33 34 // Checked/Unfocused images. 35 SetCustomImage(true, false, STATE_NORMAL, 36 *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED)); 37 SetCustomImage(true, false, STATE_HOVERED, 38 *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED_HOVER)); 39 SetCustomImage(true, false, STATE_PRESSED, 40 *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED_PRESSED)); 41 SetCustomImage(true, false, STATE_DISABLED, 42 *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED_DISABLED)); 43 44 // Unchecked/Focused images. 45 SetCustomImage(false, true, STATE_NORMAL, 46 *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED)); 47 SetCustomImage(false, true, STATE_HOVERED, 48 *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_HOVER)); 49 SetCustomImage(false, true, STATE_PRESSED, 50 *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_PRESSED)); 51 52 // Checked/Focused images. 53 SetCustomImage(true, true, STATE_NORMAL, 54 *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_CHECKED)); 55 SetCustomImage(true, true, STATE_HOVERED, 56 *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_CHECKED_HOVER)); 57 SetCustomImage(true, true, STATE_PRESSED, 58 *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_CHECKED_PRESSED)); 59} 60 61RadioButton::~RadioButton() { 62} 63 64void RadioButton::SetChecked(bool checked) { 65 if (checked == RadioButton::checked()) 66 return; 67 if (checked) { 68 // We can't just get the root view here because sometimes the radio 69 // button isn't attached to a root view (e.g., if it's part of a tab page 70 // that is currently not active). 71 View* container = parent(); 72 while (container && container->parent()) 73 container = container->parent(); 74 if (container) { 75 Views other; 76 container->GetViewsInGroup(GetGroup(), &other); 77 for (Views::iterator i(other.begin()); i != other.end(); ++i) { 78 if (*i != this) { 79 if (strcmp((*i)->GetClassName(), kViewClassName)) { 80 NOTREACHED() << "radio-button-nt has same group as other non " 81 "radio-button-nt views."; 82 continue; 83 } 84 RadioButton* peer = static_cast<RadioButton*>(*i); 85 peer->SetChecked(false); 86 } 87 } 88 } 89 } 90 Checkbox::SetChecked(checked); 91} 92 93const char* RadioButton::GetClassName() const { 94 return kViewClassName; 95} 96 97void RadioButton::GetAccessibleState(ui::AccessibleViewState* state) { 98 Checkbox::GetAccessibleState(state); 99 state->role = ui::AccessibilityTypes::ROLE_RADIOBUTTON; 100} 101 102View* RadioButton::GetSelectedViewForGroup(int group) { 103 Views views; 104 GetWidget()->GetRootView()->GetViewsInGroup(group, &views); 105 if (views.empty()) 106 return NULL; 107 108 for (Views::const_iterator i(views.begin()); i != views.end(); ++i) { 109 // REVIEW: why don't we check the runtime type like is done above? 110 RadioButton* radio_button = static_cast<RadioButton*>(*i); 111 if (radio_button->checked()) 112 return radio_button; 113 } 114 return NULL; 115} 116 117bool RadioButton::IsGroupFocusTraversable() const { 118 // When focusing a radio button with tab/shift+tab, only the selected button 119 // from the group should be focused. 120 return false; 121} 122 123void RadioButton::OnFocus() { 124 Checkbox::OnFocus(); 125 SetChecked(true); 126 ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), 0); 127 LabelButton::NotifyClick(event); 128} 129 130void RadioButton::NotifyClick(const ui::Event& event) { 131 // Set the checked state to true only if we are unchecked, since we can't 132 // be toggled on and off like a checkbox. 133 if (!checked()) 134 SetChecked(true); 135 RequestFocus(); 136 LabelButton::NotifyClick(event); 137} 138 139ui::NativeTheme::Part RadioButton::GetThemePart() const { 140 return ui::NativeTheme::kRadio; 141} 142 143} // namespace views 144