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/radio_button.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/accessibility/ax_view_state.h" 990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 1003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "ui/resources/grit/ui_resources.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views { 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const char RadioButton::kViewClassName[] = "RadioButton"; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RadioButton::RadioButton(const base::string16& label, int group_id) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : Checkbox(label) { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetGroup(group_id); 2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Unchecked/Unfocused images. 2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetCustomImage(false, false, STATE_NORMAL, 2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *rb.GetImageSkiaNamed(IDR_RADIO)); 2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetCustomImage(false, false, STATE_HOVERED, 2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *rb.GetImageSkiaNamed(IDR_RADIO_HOVER)); 2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetCustomImage(false, false, STATE_PRESSED, 3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *rb.GetImageSkiaNamed(IDR_RADIO_PRESSED)); 3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetCustomImage(false, false, STATE_DISABLED, 3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *rb.GetImageSkiaNamed(IDR_RADIO_DISABLED)); 3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Checked/Unfocused images. 3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetCustomImage(true, false, STATE_NORMAL, 3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED)); 3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetCustomImage(true, false, STATE_HOVERED, 3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED_HOVER)); 3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetCustomImage(true, false, STATE_PRESSED, 4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED_PRESSED)); 4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetCustomImage(true, false, STATE_DISABLED, 4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED_DISABLED)); 4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Unchecked/Focused images. 4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetCustomImage(false, true, STATE_NORMAL, 4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED)); 4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetCustomImage(false, true, STATE_HOVERED, 4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_HOVER)); 4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetCustomImage(false, true, STATE_PRESSED, 5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_PRESSED)); 5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Checked/Focused images. 5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetCustomImage(true, true, STATE_NORMAL, 5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_CHECKED)); 5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetCustomImage(true, true, STATE_HOVERED, 5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_CHECKED_HOVER)); 5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetCustomImage(true, true, STATE_PRESSED, 5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_CHECKED_PRESSED)); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RadioButton::~RadioButton() { 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RadioButton::SetChecked(bool checked) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (checked == RadioButton::checked()) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (checked) { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We can't just get the root view here because sometimes the radio 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // button isn't attached to a root view (e.g., if it's part of a tab page 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that is currently not active). 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) View* container = parent(); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (container && container->parent()) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) container = container->parent(); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (container) { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Views other; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) container->GetViewsInGroup(GetGroup(), &other); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (Views::iterator i(other.begin()); i != other.end(); ++i) { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*i != this) { 79b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (strcmp((*i)->GetClassName(), kViewClassName)) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "radio-button-nt has same group as other non " 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "radio-button-nt views."; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RadioButton* peer = static_cast<RadioButton*>(*i); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) peer->SetChecked(false); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Checkbox::SetChecked(checked); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 93b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char* RadioButton::GetClassName() const { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return kViewClassName; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void RadioButton::GetAccessibleState(ui::AXViewState* state) { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Checkbox::GetAccessibleState(state); 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state->role = ui::AX_ROLE_RADIO_BUTTON; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View* RadioButton::GetSelectedViewForGroup(int group) { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Views views; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetWidget()->GetRootView()->GetViewsInGroup(group, &views); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (views.empty()) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (Views::const_iterator i(views.begin()); i != views.end(); ++i) { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // REVIEW: why don't we check the runtime type like is done above? 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RadioButton* radio_button = static_cast<RadioButton*>(*i); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (radio_button->checked()) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return radio_button; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool RadioButton::IsGroupFocusTraversable() const { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When focusing a radio button with tab/shift+tab, only the selected button 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // from the group should be focused. 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RadioButton::OnFocus() { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Checkbox::OnFocus(); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetChecked(true); 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), 0, 0); 12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) LabelButton::NotifyClick(event); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RadioButton::NotifyClick(const ui::Event& event) { 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the checked state to true only if we are unchecked, since we can't 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // be toggled on and off like a checkbox. 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!checked()) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetChecked(true); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RequestFocus(); 13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) LabelButton::NotifyClick(event); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ui::NativeTheme::Part RadioButton::GetThemePart() const { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::NativeTheme::kRadio; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace views 144