summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-14 17:34:51 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-14 17:34:51 +0000
commitd0260a987dd7e919b7f7dee40c239bf89ea14033 (patch)
tree6c890855c2a797b9c90d0c7fd70a538bf62a25fd /views
parentf5c655de4121427b4d9d9dc218efd29afa8bba8c (diff)
downloadchromium_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.cc120
-rw-r--r--views/controls/button/native_button_gtk.h53
-rw-r--r--views/controls/button/native_button_win.cc4
-rw-r--r--views/controls/button/native_button_win.h1
-rw-r--r--views/controls/button/native_button_wrapper.h4
-rw-r--r--views/controls/button/radio_button.cc3
-rw-r--r--views/controls/button/radio_button.h8
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);
};