diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-14 17:34:51 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-14 17:34:51 +0000 |
commit | d0260a987dd7e919b7f7dee40c239bf89ea14033 (patch) | |
tree | 6c890855c2a797b9c90d0c7fd70a538bf62a25fd /views | |
parent | f5c655de4121427b4d9d9dc218efd29afa8bba8c (diff) | |
download | chromium_src-d0260a987dd7e919b7f7dee40c239bf89ea14033.zip chromium_src-d0260a987dd7e919b7f7dee40c239bf89ea14033.tar.gz chromium_src-d0260a987dd7e919b7f7dee40c239bf89ea14033.tar.bz2 |
Lands http://codereview.chromium.org/200102 for Oshima:
RadioButton implementation.
- gtk implementation uses gkt's grouping mechanism, which was hard to replace.
A small refactoring.
- changed to use virtual functions instead of if/IsCheckbox
- Removed checkbox's CallClicked
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/194102
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@26117 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r-- | views/controls/button/native_button_gtk.cc | 120 | ||||
-rw-r--r-- | views/controls/button/native_button_gtk.h | 53 | ||||
-rw-r--r-- | views/controls/button/native_button_win.cc | 4 | ||||
-rw-r--r-- | views/controls/button/native_button_win.h | 1 | ||||
-rw-r--r-- | views/controls/button/native_button_wrapper.h | 4 | ||||
-rw-r--r-- | views/controls/button/radio_button.cc | 3 | ||||
-rw-r--r-- | views/controls/button/radio_button.h | 8 |
7 files changed, 166 insertions, 27 deletions
diff --git a/views/controls/button/native_button_gtk.cc b/views/controls/button/native_button_gtk.cc index fd89da2..0632b21 100644 --- a/views/controls/button/native_button_gtk.cc +++ b/views/controls/button/native_button_gtk.cc @@ -54,10 +54,7 @@ void NativeButtonGtk::UpdateEnabled() { void NativeButtonGtk::UpdateDefault() { if (!native_view()) return; - if (IsCheckbox()) - UpdateChecked(); - else - NOTIMPLEMENTED(); + NOTIMPLEMENTED(); } View* NativeButtonGtk::GetView() { @@ -73,6 +70,10 @@ bool NativeButtonGtk::UsesNativeLabel() const { return true; } +bool NativeButtonGtk::UsesNativeRadioButtonGroup() const { + return true; +} + gfx::NativeView NativeButtonGtk::GetTestingHandle() const { return native_view(); } @@ -118,10 +119,18 @@ void NativeButtonGtk::OnClicked() { // NativeCheckboxGtk NativeCheckboxGtk::NativeCheckboxGtk(Checkbox* checkbox) : NativeButtonGtk(checkbox), - checkbox_(checkbox), deliver_click_event_(true) { } +void NativeCheckboxGtk::SyncCheckState() { + checkbox()->SetChecked( + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(native_view()))); +} + +Checkbox* NativeCheckboxGtk::checkbox() { + return static_cast<Checkbox*>(native_button_); +} + void NativeCheckboxGtk::CreateNativeControl() { GtkWidget* widget = gtk_check_button_new(); g_signal_connect(G_OBJECT(widget), "clicked", @@ -133,30 +142,116 @@ void NativeCheckboxGtk::OnClicked() { // ignore event if the event is generated by // gtk_toggle_button_set_active below. if (deliver_click_event_) { - checkbox_->SetChecked(!checkbox_->checked()); + SyncCheckState(); NativeButtonGtk::OnClicked(); } } +void NativeCheckboxGtk::UpdateDefault() { + if (!native_view()) + return; + UpdateChecked(); +} + void NativeCheckboxGtk::UpdateChecked() { if (!native_view()) return; if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(native_view())) - != checkbox_->checked()) { + != checkbox()->checked()) { // gtk_toggle_button_set_active emites "clicked" signal, which // invokes OnClicked method above. deliver_click_event_ flag is used // to prevent such signal to invoke OnClicked callback. deliver_click_event_ = false; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(native_view()), - checkbox_->checked()); + checkbox()->checked()); deliver_click_event_ = true; } } +//////////////////////////////////////////////////////////////////////////////// +NativeRadioButtonGtk::NativeRadioButtonGtk(RadioButton* radio_button) + : NativeCheckboxGtk(radio_button) { +} + +NativeRadioButtonGtk::~NativeRadioButtonGtk() { +} + +RadioButton* NativeRadioButtonGtk::radio_button() { + return static_cast<RadioButton*>(native_button_); +} + +//////////////////////////////////////////////////////////////////////////////// +// NativeRadioButtonGtk, NativeCheckboxGtk overrides: + +void NativeRadioButtonGtk::CreateNativeControl() { + GtkWidget* widget = gtk_radio_button_new(NULL); + g_signal_connect(G_OBJECT(widget), "clicked", + G_CALLBACK(CallClicked), this); + g_signal_connect(G_OBJECT(widget), "toggled", + G_CALLBACK(CallToggled), this); + NativeControlCreated(widget); +} + +void NativeRadioButtonGtk::OnToggled() { + SyncCheckState(); +} + // static -void NativeCheckboxGtk::CallClicked(GtkButton* widget, - NativeCheckboxGtk* button) { - button->OnClicked(); +void NativeRadioButtonGtk::CallToggled(GtkButton* widget, + NativeRadioButtonGtk* button) { + button->OnToggled(); +} + +//////////////////////////////////////////////////////////////////////////////// +// NativeRadioButtonGtk, NativeButtonWrapper overrides: +void NativeRadioButtonGtk::SetGroupFrom(NativeButtonWrapper* wrapper) { + NativeRadioButtonGtk* peer = static_cast<NativeRadioButtonGtk*>(wrapper); + GSList* group = + gtk_radio_button_get_group(GTK_RADIO_BUTTON(peer->native_view())); + // A group object is managed by gtk framework. It's updated as a radio + // button is added to, or removed. + DCHECK(group); + GtkRadioButton* this_radio_button = GTK_RADIO_BUTTON(native_view()); + if (!g_slist_find(group, this_radio_button)) + gtk_radio_button_set_group(this_radio_button, group); +} + +//////////////////////////////////////////////////////////////////////////////// +// NativeRadioButtonGtk, NativeControlGtk overrides: +void NativeRadioButtonGtk::ViewHierarchyChanged(bool is_add, + View *parent, View *child) { + NativeControlGtk::ViewHierarchyChanged(is_add, parent, child); + + // look for the same group and update + if (is_add && child == this) { + View* container = GetParent(); + while (container && container->GetParent()) + container = container->GetParent(); + if (container) { + std::vector<View*> other; + container->GetViewsWithGroup(native_button_->GetGroup(), &other); + for (std::vector<View*>::iterator i = other.begin(); + i != other.end(); + ++i) { + if (*i != native_button_) { + if ((*i)->GetClassName() != RadioButton::kViewClassName) { + NOTREACHED() << "radio-button has same group as other non " + "radio-button views."; + continue; + } + // Join the group + NativeButtonWrapper* wrapper = + static_cast<RadioButton*>(*i)->native_wrapper(); + SetGroupFrom(wrapper); + break; + } + } + } + + // Sync the state after setting the group because single radio button + // is always active. + SyncCheckState(); + } } //////////////////////////////////////////////////////////////////////////////// @@ -183,8 +278,7 @@ NativeButtonWrapper* NativeButtonWrapper::CreateCheckboxWrapper( // static NativeButtonWrapper* NativeButtonWrapper::CreateRadioButtonWrapper( RadioButton* radio_button) { - NOTIMPLEMENTED(); - return NULL; + return new NativeRadioButtonGtk(radio_button); } } // namespace views diff --git a/views/controls/button/native_button_gtk.h b/views/controls/button/native_button_gtk.h index e44b8b3..8a92b92 100644 --- a/views/controls/button/native_button_gtk.h +++ b/views/controls/button/native_button_gtk.h @@ -24,27 +24,27 @@ class NativeButtonGtk : public NativeControlGtk, public NativeButtonWrapper { virtual View* GetView(); virtual void SetFocus(); virtual bool UsesNativeLabel() const; + virtual bool UsesNativeRadioButtonGroup() const; virtual gfx::NativeView GetTestingHandle() const; // Overridden from View: virtual gfx::Size GetPreferredSize(); protected: + static void CallClicked(GtkButton* widget, NativeButtonGtk* button); + virtual void CreateNativeControl(); virtual void NativeControlCreated(GtkWidget* widget); // Invoked when the user clicks on the button. virtual void OnClicked(); - // Returns true if this button is actually a checkbox or radio button. - virtual bool IsCheckbox() const { return false; } - - private: - static void CallClicked(GtkButton* widget, NativeButtonGtk* button); - + protected: // The NativeButton we are bound to. NativeButton* native_button_; + private: + // The preferred size from the last size_request. We save this until we are // notified that data may have caused the preferred size to change because // otherwise it seems every time we call gtk_widget_size_request the size @@ -54,12 +54,18 @@ class NativeButtonGtk : public NativeControlGtk, public NativeButtonWrapper { DISALLOW_COPY_AND_ASSIGN(NativeButtonGtk); }; +// A View that hosts a native Gtk checkbox button. class NativeCheckboxGtk : public NativeButtonGtk { public: explicit NativeCheckboxGtk(Checkbox* checkbox); + protected: + // Update checkbox's check state. + void SyncCheckState(); + private: - static void CallClicked(GtkButton* widget, NativeCheckboxGtk* button); + // Return Checkbox we are bound to. + Checkbox* checkbox(); virtual void CreateNativeControl(); @@ -68,11 +74,7 @@ class NativeCheckboxGtk : public NativeButtonGtk { // Overidden from NativeButtonWrapper virtual void UpdateChecked(); - - // Returns true if this button is actually a checkbox or radio button. - virtual bool IsCheckbox() const { return true; } - - Checkbox* checkbox_; + virtual void UpdateDefault(); // a flag to prevent OnClicked event when updating // gtk control via API gtk_toggle_button_set_active. @@ -81,6 +83,33 @@ class NativeCheckboxGtk : public NativeButtonGtk { DISALLOW_COPY_AND_ASSIGN(NativeCheckboxGtk); }; +// A View that hosts a native Gtk radio button. +class NativeRadioButtonGtk : public NativeCheckboxGtk { + public: + explicit NativeRadioButtonGtk(RadioButton* radio_button); + virtual ~NativeRadioButtonGtk(); + + protected: + // Overridden from NativeCheckboxGtk. + virtual void CreateNativeControl(); + + // Overridden from NativeControlGtk. + virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child); + + private: + static void CallToggled(GtkButton* widget, NativeRadioButtonGtk* button); + + // Return RadioButton we are bound to. + RadioButton* radio_button(); + // Set the gtk radio button's group to that of given wrapper's gruop. + void SetGroupFrom(NativeButtonWrapper* wrapper); + // Invoked when the radio button's state is changed. + void OnToggled(); + + DISALLOW_COPY_AND_ASSIGN(NativeRadioButtonGtk); +}; + + } // namespace views #endif // #ifndef VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_GTK_H_ diff --git a/views/controls/button/native_button_win.cc b/views/controls/button/native_button_win.cc index f134b51..00ec3cc 100644 --- a/views/controls/button/native_button_win.cc +++ b/views/controls/button/native_button_win.cc @@ -67,6 +67,10 @@ bool NativeButtonWin::UsesNativeLabel() const { return true; } +bool NativeButtonWin::UsesNativeRadioButtonGroup() const { + return false; +} + gfx::NativeView NativeButtonWin::GetTestingHandle() const { return native_view(); } diff --git a/views/controls/button/native_button_win.h b/views/controls/button/native_button_win.h index 2ac0817..20ce575 100644 --- a/views/controls/button/native_button_win.h +++ b/views/controls/button/native_button_win.h @@ -25,6 +25,7 @@ class NativeButtonWin : public NativeControlWin, virtual View* GetView(); virtual void SetFocus(); virtual bool UsesNativeLabel() const; + virtual bool UsesNativeRadioButtonGroup() const; virtual gfx::NativeView GetTestingHandle() const; // Overridden from View: diff --git a/views/controls/button/native_button_wrapper.h b/views/controls/button/native_button_wrapper.h index bd974bd..d511702 100644 --- a/views/controls/button/native_button_wrapper.h +++ b/views/controls/button/native_button_wrapper.h @@ -50,6 +50,10 @@ class NativeButtonWrapper { // the caller needs to provide one. virtual bool UsesNativeLabel() const = 0; + // Returns true if the wrapped NativeRadioButton supplies its own grouping + // mechanism, or false if the radio button needs to provide one. + virtual bool UsesNativeRadioButtonGroup() const = 0; + // Returns a handle to the underlying native view for testing. virtual gfx::NativeView GetTestingHandle() const = 0; diff --git a/views/controls/button/radio_button.cc b/views/controls/button/radio_button.cc index 44cf426..4509d74 100644 --- a/views/controls/button/radio_button.cc +++ b/views/controls/button/radio_button.cc @@ -29,7 +29,7 @@ RadioButton::~RadioButton() { void RadioButton::SetChecked(bool checked) { if (checked == RadioButton::checked()) return; - if (checked) { + if (native_wrapper_->UsesNativeRadioButtonGroup() && checked) { // We can't just get the root view here because sometimes the radio // button isn't attached to a root view (e.g., if it's part of a tab page // that is currently not active). @@ -54,7 +54,6 @@ void RadioButton::SetChecked(bool checked) { } } Checkbox::SetChecked(checked); - } //////////////////////////////////////////////////////////////////////////////// diff --git a/views/controls/button/radio_button.h b/views/controls/button/radio_button.h index 9039117..3882ec2 100644 --- a/views/controls/button/radio_button.h +++ b/views/controls/button/radio_button.h @@ -9,6 +9,8 @@ namespace views { +class NativeRadioButtonGtk; + // A Checkbox subclass representing a radio button. class RadioButton : public Checkbox { public: @@ -33,6 +35,12 @@ class RadioButton : public Checkbox { virtual NativeButtonWrapper* CreateWrapper(); private: + friend class NativeRadioButtonGtk; + + // Accessor for |native_wrapper_|. + NativeButtonWrapper* native_wrapper() { return native_wrapper_; } + + private: DISALLOW_COPY_AND_ASSIGN(RadioButton); }; |