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 "ui/accessibility/ax_view_state.h" 9 #include "ui/base/resource/resource_bundle.h" 10 #include "ui/resources/grit/ui_resources.h" 11 #include "ui/views/widget/widget.h" 12 13 namespace views { 14 15 // static 16 const char RadioButton::kViewClassName[] = "RadioButton"; 17 18 RadioButton::RadioButton(const base::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 61 RadioButton::~RadioButton() { 62 } 63 64 void 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 93 const char* RadioButton::GetClassName() const { 94 return kViewClassName; 95 } 96 97 void RadioButton::GetAccessibleState(ui::AXViewState* state) { 98 Checkbox::GetAccessibleState(state); 99 state->role = ui::AX_ROLE_RADIO_BUTTON; 100 } 101 102 View* 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 117 bool 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 123 void RadioButton::OnFocus() { 124 Checkbox::OnFocus(); 125 SetChecked(true); 126 ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), 0, 0); 127 LabelButton::NotifyClick(event); 128 } 129 130 void 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 139 ui::NativeTheme::Part RadioButton::GetThemePart() const { 140 return ui::NativeTheme::kRadio; 141 } 142 143 } // namespace views 144