Home | History | Annotate | Download | only in button
      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