diff options
author | Owen Taylor <otaylor@redhat.com> | 2001-10-16 21:02:24 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 2001-10-16 21:02:24 +0000 |
commit | 1ebe3b518b7fe1ac64d96aa4ee025d6aac435442 (patch) | |
tree | 5521b85a657a92cee4289904e0f8a9dce9890190 /gtk/gtkradiobutton.c | |
parent | 3612439d217cfb55f1066a95f5f0ee9e2124f8c4 (diff) | |
download | gtk+-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.c | 181 |
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; |