summaryrefslogtreecommitdiff
path: root/gtk/gtkradiobutton.c
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2001-10-16 21:02:24 +0000
committerOwen Taylor <otaylor@src.gnome.org>2001-10-16 21:02:24 +0000
commit1ebe3b518b7fe1ac64d96aa4ee025d6aac435442 (patch)
tree5521b85a657a92cee4289904e0f8a9dce9890190 /gtk/gtkradiobutton.c
parent3612439d217cfb55f1066a95f5f0ee9e2124f8c4 (diff)
downloadgtk+-1ebe3b518b7fe1ac64d96aa4ee025d6aac435442.tar.gz
Add a utility function to translate coordinates relative to one widget's
Tue Oct 16 15:50:03 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkwidget.c (gtk_widget_translate_coordinates): Add a utility function to translate coordinates relative to one widget's allocation to coordinates relative to another widget's allocation. * gtk/gtkradiobutton.c: Add a special ->focus() implementation that: - only accepts external focus if there is no active member of the group or the button is active. - makes arrow keys move the active button as well as the focus - make tab tab out directly. This makes a radio button group act as a single focus location. (#53577). * gtk/gtkcontainer.c (gtk_container_focus): Remove prefiltering - it was only a small optimization that didn't matter and made things more complicated. * gtk/gtkcontainer.c (gtk_container_focus_tab): Get rid of custom sorter for FOCUS_TAB as we did for the other focus directions, sort by center of widgets, not upper-left corner. (Shouldn't matter in general.) * gtk/gtkcontainer.c: Restructure code to remove duplicate code from the different types of focusing: encapsulate sorting the widgets for the focus direction into one routine (gtk_container_focus_sort()) and then share the work of moving the focus between the different focus directions. * gtk/gtkcontainer.c: Fix bug where arrow navigation might not work correctly with focus chains containing non-immediate children. Sorting was being done using allocation coordinates for each widget in the focus chain, and if there were intermediate window-widgets, these allocations would not be in the same coordinate system.
Diffstat (limited to 'gtk/gtkradiobutton.c')
-rw-r--r--gtk/gtkradiobutton.c181
1 files changed, 168 insertions, 13 deletions
diff --git a/gtk/gtkradiobutton.c b/gtk/gtkradiobutton.c
index 245bec87e9..e5cf6a318e 100644
--- a/gtk/gtkradiobutton.c
+++ b/gtk/gtkradiobutton.c
@@ -35,19 +35,20 @@ enum {
};
-static void gtk_radio_button_class_init (GtkRadioButtonClass *klass);
-static void gtk_radio_button_init (GtkRadioButton *radio_button);
-static void gtk_radio_button_destroy (GtkObject *object);
-static void gtk_radio_button_clicked (GtkButton *button);
-static void gtk_radio_button_draw_indicator (GtkCheckButton *check_button,
- GdkRectangle *area);
-static void gtk_radio_button_set_arg (GtkObject *object,
- GtkArg *arg,
- guint arg_id);
-static void gtk_radio_button_get_arg (GtkObject *object,
- GtkArg *arg,
- guint arg_id);
-
+static void gtk_radio_button_class_init (GtkRadioButtonClass *klass);
+static void gtk_radio_button_init (GtkRadioButton *radio_button);
+static void gtk_radio_button_destroy (GtkObject *object);
+static gboolean gtk_radio_button_focus (GtkWidget *widget,
+ GtkDirectionType direction);
+static void gtk_radio_button_clicked (GtkButton *button);
+static void gtk_radio_button_draw_indicator (GtkCheckButton *check_button,
+ GdkRectangle *area);
+static void gtk_radio_button_set_arg (GtkObject *object,
+ GtkArg *arg,
+ guint arg_id);
+static void gtk_radio_button_get_arg (GtkObject *object,
+ GtkArg *arg,
+ guint arg_id);
static GtkCheckButtonClass *parent_class = NULL;
@@ -83,8 +84,10 @@ gtk_radio_button_class_init (GtkRadioButtonClass *class)
GtkObjectClass *object_class;
GtkButtonClass *button_class;
GtkCheckButtonClass *check_button_class;
+ GtkWidgetClass *widget_class;
object_class = (GtkObjectClass*) class;
+ widget_class = (GtkWidgetClass*) class;
button_class = (GtkButtonClass*) class;
check_button_class = (GtkCheckButtonClass*) class;
@@ -96,6 +99,8 @@ gtk_radio_button_class_init (GtkRadioButtonClass *class)
object_class->get_arg = gtk_radio_button_get_arg;
object_class->destroy = gtk_radio_button_destroy;
+ widget_class->focus = gtk_radio_button_focus;
+
button_class->clicked = gtk_radio_button_clicked;
check_button_class->draw_indicator = gtk_radio_button_draw_indicator;
@@ -331,6 +336,156 @@ gtk_radio_button_destroy (GtkObject *object)
}
static void
+get_coordinates (GtkWidget *widget,
+ GtkWidget *reference,
+ gint *x,
+ gint *y)
+{
+ *x = widget->allocation.x + widget->allocation.width / 2;
+ *y = widget->allocation.y + widget->allocation.height / 2;
+
+ gtk_widget_translate_coordinates (widget, reference, *x, *y, x, y);
+}
+
+static gint
+left_right_compare (gconstpointer a,
+ gconstpointer b,
+ gpointer data)
+{
+ gint x1, y1, x2, y2;
+
+ get_coordinates ((GtkWidget *)a, data, &x1, &y1);
+ get_coordinates ((GtkWidget *)b, data, &x2, &y2);
+
+ if (y1 == y2)
+ return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1);
+ else
+ return (y1 < y2) ? -1 : 1;
+}
+
+static gint
+up_down_compare (gconstpointer a,
+ gconstpointer b,
+ gpointer data)
+{
+ gint x1, y1, x2, y2;
+
+ get_coordinates ((GtkWidget *)a, data, &x1, &y1);
+ get_coordinates ((GtkWidget *)b, data, &x2, &y2);
+
+ if (x1 == x2)
+ return (y1 < y2) ? -1 : ((y1 == y2) ? 0 : 1);
+ else
+ return (x1 < x2) ? -1 : 1;
+}
+
+static gboolean
+gtk_radio_button_focus (GtkWidget *widget,
+ GtkDirectionType direction)
+{
+ GtkRadioButton *radio_button = GTK_RADIO_BUTTON (widget);
+ GSList *tmp_slist;
+
+ if (gtk_widget_is_focus (widget))
+ {
+ GSList *focus_list, *tmp_list;
+ GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
+ GtkWidget *new_focus = NULL;
+
+ focus_list = g_slist_copy (radio_button->group);
+
+ switch (direction)
+ {
+ case GTK_DIR_TAB_FORWARD:
+ case GTK_DIR_TAB_BACKWARD:
+ return FALSE;
+ case GTK_DIR_LEFT:
+ case GTK_DIR_RIGHT:
+ focus_list = g_slist_sort_with_data (focus_list, left_right_compare, toplevel);
+ break;
+ case GTK_DIR_UP:
+ case GTK_DIR_DOWN:
+ focus_list = g_slist_sort_with_data (focus_list, up_down_compare, toplevel);
+ break;
+ }
+
+ if (direction == GTK_DIR_LEFT || direction == GTK_DIR_UP)
+ focus_list = g_slist_reverse (focus_list);
+
+ tmp_list = g_slist_find (focus_list, widget);
+
+ if (tmp_list)
+ {
+ tmp_list = tmp_list->next;
+
+ while (tmp_list)
+ {
+ GtkWidget *child = tmp_list->data;
+
+ if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_IS_SENSITIVE (child))
+ {
+ new_focus = child;
+ break;
+ }
+
+ tmp_list = tmp_list->next;
+ }
+ }
+
+ if (!new_focus)
+ {
+ tmp_list = focus_list;
+
+ while (tmp_list)
+ {
+ GtkWidget *child = tmp_list->data;
+
+ if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_IS_SENSITIVE (child))
+ {
+ new_focus = child;
+ break;
+ }
+
+ tmp_list = tmp_list->next;
+ }
+ }
+
+ g_slist_free (focus_list);
+
+ if (new_focus)
+ {
+ gtk_widget_grab_focus (new_focus);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (new_focus), TRUE);
+ }
+
+ return TRUE;
+ }
+ else
+ {
+ GtkRadioButton *selected_button = NULL;
+
+ /* We accept the focus if, we don't have the focus and
+ * - we are the currently active button in the group
+ * - there is no currently active radio button.
+ */
+
+ tmp_slist = radio_button->group;
+ while (tmp_slist)
+ {
+ if (GTK_TOGGLE_BUTTON (tmp_slist->data)->active)
+ selected_button = tmp_slist->data;
+ tmp_slist = tmp_slist->next;
+ }
+
+ if (selected_button && selected_button != radio_button)
+ return FALSE;
+
+ gtk_widget_grab_focus (widget);
+ return TRUE;
+ }
+}
+
+static void
gtk_radio_button_clicked (GtkButton *button)
{
GtkToggleButton *toggle_button;