diff options
author | Bolian Yin <bolian.yin@sun.com> | 2003-09-22 11:19:00 +0800 |
---|---|---|
committer | Bolian Yin <byin@src.gnome.org> | 2003-09-22 11:19:00 +0800 |
commit | 88d4fd5eac6bf7bcfd845f548efabc9801199cd2 (patch) | |
tree | 315ccd29c815a961e66ac9db129f960d10339d1b /widgets/misc | |
parent | 939c8a4b8284418ad379cdbd990353b9941b551a (diff) | |
download | gsoc2013-evolution-88d4fd5eac6bf7bcfd845f548efabc9801199cd2.tar.gz gsoc2013-evolution-88d4fd5eac6bf7bcfd845f548efabc9801199cd2.tar.zst gsoc2013-evolution-88d4fd5eac6bf7bcfd845f548efabc9801199cd2.zip |
Fixes #1245. ECalendar should be usable with the keyboard
2003-09-19 Bolian Yin <bolian.yin@sun.com>
Fixes #1245. ECalendar should be usable with the keyboard
*misc/e-calendar-item.c (e_calendar_item_focus): new func, focus handler.
(e_calendar_item_key_press_event): new func, key press event handler
(e_calendar_item_selection_add_days, e_calendar_item_stop_selecting): helpers.
(e_calendar_item_ensure_days_visible, e_calendar_item_set_selection_if_emission):
add the flag to control if we should emit e-calendar signals.
(e_calendar_item_class_init): register focus handler.
(e_calendar_item_event): add code for GDK_FOCUS_CHANGE and GDK_KEY_PRESS.
*misc/e-calendar.c (e_calendar_focus): new func, focus handler
(e_calendar_button_has_focus): new func, if prev/next button has focus.
(e_calendar_on_next_clicked, e_calendar_on_prev_clicked): click signal handler
for prev/next buttons.
(e_calendar_set_focusable): set if the e-calendar is focusable
*misc/e-dateedit.c (e_date_edit_show_date_popup, hide_date_popup): grab/ungrab gdk keyboard.
svn path=/trunk/; revision=22632
Diffstat (limited to 'widgets/misc')
-rw-r--r-- | widgets/misc/e-calendar-item.c | 265 | ||||
-rw-r--r-- | widgets/misc/e-calendar-item.h | 2 | ||||
-rw-r--r-- | widgets/misc/e-calendar.c | 125 | ||||
-rw-r--r-- | widgets/misc/e-calendar.h | 1 | ||||
-rw-r--r-- | widgets/misc/e-dateedit.c | 2 |
5 files changed, 342 insertions, 53 deletions
diff --git a/widgets/misc/e-calendar-item.c b/widgets/misc/e-calendar-item.c index 1f430124d9..883ec6e0d6 100644 --- a/widgets/misc/e-calendar-item.c +++ b/widgets/misc/e-calendar-item.c @@ -3,6 +3,7 @@ /* * Author : * Damon Chaplin <damon@ximian.com> + * Bolian Yin <bolian.yin@sun.com> * * Copyright 2000, Ximian, Inc. * @@ -41,6 +42,7 @@ #include <gtk/gtkmenuitem.h> #include <gtk/gtklabel.h> #include <gtk/gtksignal.h> +#include <gdk/gdkkeysyms.h> #include <libgnome/gnome-i18n.h> #include <gal/util/e-util.h> @@ -92,6 +94,8 @@ static void e_calendar_item_get_arg (GtkObject *o, static void e_calendar_item_set_arg (GtkObject *o, GtkArg *arg, guint arg_id); +static gboolean e_calendar_item_focus (GtkWidget *widget, + GtkDirectionType direction); static void e_calendar_item_realize (GnomeCanvasItem *item); static void e_calendar_item_unrealize (GnomeCanvasItem *item); static void e_calendar_item_unmap (GnomeCanvasItem *item); @@ -130,6 +134,13 @@ static double e_calendar_item_point (GnomeCanvasItem *item, int cx, int cy, GnomeCanvasItem **actual_item); +static void e_calendar_item_stop_selecting (ECalendarItem *calitem, + guint32 time); +static void e_calendar_item_selection_add_days (ECalendarItem *calitem, + gint n_days, + gboolean multi_selection); +static gint e_calendar_item_key_press_event (ECalendarItem *item, + GdkEvent *event); static gint e_calendar_item_event (GnomeCanvasItem *item, GdkEvent *event); static void e_calendar_item_bounds (GnomeCanvasItem *item, double *x1, double *y1, @@ -205,13 +216,14 @@ static gint e_calendar_item_get_inclusive_days (ECalendarItem *calitem, static void e_calendar_item_ensure_valid_day (ECalendarItem *calitem, gint *month_offset, gint *day); -static gboolean e_calendar_item_ensure_days_visible (ECalendarItem *calitem, - gint start_year, - gint start_month, - gint start_day, - gint end_year, - gint end_month, - gint end_day); +static gboolean e_calendar_item_ensure_days_visible (ECalendarItem *calitem, + gint start_year, + gint start_month, + gint start_day, + gint end_year, + gint end_month, + gint end_day, + gboolean emission); static void e_calendar_item_show_popup_menu (ECalendarItem *calitem, GdkEventButton *event, gint month_offset); @@ -225,6 +237,10 @@ static void e_calendar_item_position_menu (GtkMenu *menu, static void e_calendar_item_date_range_changed (ECalendarItem *calitem); static void e_calendar_item_queue_signal_emission (ECalendarItem *calitem); static gboolean e_calendar_item_signal_emission_idle_cb (gpointer data); +static void e_calendar_item_set_selection_if_emission (ECalendarItem *calitem, + GDate *start_date, + GDate *end_date, + gboolean emission); /* Our arguments. */ enum { @@ -273,11 +289,13 @@ static void e_calendar_item_class_init (ECalendarItemClass *class) { GtkObjectClass *object_class; + GtkWidgetClass *widget_class; GnomeCanvasItemClass *item_class; parent_class = g_type_class_ref(gnome_canvas_item_get_type()); object_class = (GtkObjectClass *) class; + widget_class = (GtkWidgetClass *) class; item_class = (GnomeCanvasItemClass *) class; gtk_object_add_arg_type ("ECalendarItem::year", @@ -363,6 +381,7 @@ e_calendar_item_class_init (ECalendarItemClass *class) object_class->get_arg = e_calendar_item_get_arg; object_class->set_arg = e_calendar_item_set_arg; + widget_class->focus = e_calendar_item_focus; /* GnomeCanvasItem method overrides */ item_class->realize = e_calendar_item_realize; item_class->unrealize = e_calendar_item_unrealize; @@ -416,6 +435,9 @@ e_calendar_item_init (ECalendarItem *calitem) calitem->x2 = 0.0; calitem->y2 = 0.0; + calitem->selecting = FALSE; + calitem->selecting_axis = NULL; + calitem->selection_set = FALSE; calitem->selection_changed = FALSE; @@ -467,6 +489,8 @@ e_calendar_item_destroy (GtkObject *o) calitem->week_number_font_desc = NULL; } + if (calitem->selecting_axis) + g_free (calitem->selecting_axis); if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (o); } @@ -693,6 +717,18 @@ e_calendar_item_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) } } +static gboolean +e_calendar_item_focus (GtkWidget *widget, GtkDirectionType direction) +{ + ECalendarItem *calitem; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (E_IS_CALENDAR_ITEM (widget), FALSE); + calitem = E_CALENDAR_ITEM (widget); + + GTK_WIDGET_CLASS (parent_class)->focus (widget, direction); + return TRUE; +} static void e_calendar_item_realize (GnomeCanvasItem *item) @@ -717,6 +753,10 @@ e_calendar_item_realize (GnomeCanvasItem *item) calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_FG].green = 65535; calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_FG].blue = 65535; + calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG_FOCUSED].red = 4700; + calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG_FOCUSED].green = 4700; + calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG_FOCUSED].blue = 65535; + calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG].red = 47000; calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG].green = 47000; calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG].blue = 48000; @@ -1254,7 +1294,7 @@ e_calendar_item_draw_day_numbers (ECalendarItem *calitem, gint num_chars, digit; gint week_num, mon, days_from_week_start; gint years[3], months[3], days_in_month[3]; - gboolean today, selected, has_focus = FALSE, drop_target = FALSE; + gboolean today, selected, has_focus, drop_target = FALSE; gboolean bold, draw_day, finished = FALSE; gint today_year, today_month, today_mday, month_offset; gchar buffer[2]; @@ -1403,6 +1443,12 @@ e_calendar_item_draw_day_numbers (ECalendarItem *calitem, day_style = calitem->styles[(month_offset + 1) * 32 + day_num]; /* Get the colors & style to use for the day.*/ + if ((GTK_WIDGET_HAS_FOCUS(item->canvas)) && + item->canvas->focused_item == item) + has_focus = TRUE; + else + has_focus = FALSE; + if (calitem->style_callback) (*calitem->style_callback) (calitem, @@ -1586,6 +1632,128 @@ e_calendar_item_point (GnomeCanvasItem *item, double x, double y, return 0.0; } +static void +e_calendar_item_stop_selecting (ECalendarItem *calitem, guint32 time) +{ + if (!calitem->selecting) + return; + + gnome_canvas_item_ungrab (GNOME_CANVAS_ITEM (calitem), time); + + calitem->selecting = FALSE; + + /* If the user selects the grayed dates before the first month or + after the last month, we move backwards or forwards one month. + The set_month() call should take care of updating the selection. */ + if (calitem->selection_end_month_offset == -1) + e_calendar_item_set_first_month (calitem, calitem->year, + calitem->month - 1); + else if (calitem->selection_start_month_offset == calitem->rows * calitem->cols) + e_calendar_item_set_first_month (calitem, calitem->year, + calitem->month + 1); + + calitem->selection_changed = TRUE; + if (calitem->selecting_axis) { + g_free (calitem->selecting_axis); + calitem->selecting_axis = NULL; + } + + e_calendar_item_queue_signal_emission (calitem); + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (calitem)); +} + +static void +e_calendar_item_selection_add_days (ECalendarItem *calitem, gint n_days, + gboolean multi_selection) +{ + GDate gdate_start, gdate_end; + + g_return_if_fail (E_IS_CALENDAR_ITEM (calitem)); + + if (!e_calendar_item_get_selection (calitem, &gdate_start, &gdate_end)) + return; + if (multi_selection && calitem->max_days_selected > 1) { + gint days_between; + + days_between = g_date_days_between (&gdate_start, &gdate_end); + if (!calitem->selecting_axis) { + calitem->selecting_axis = g_new (GDate, 1); + *(calitem->selecting_axis) = gdate_start; + } + if ((days_between != 0 && + g_date_compare (calitem->selecting_axis, &gdate_end) == 0) || + (days_between == 0 && n_days < 0)) { + if (days_between - n_days > calitem->max_days_selected - 1) + n_days = days_between + 1 - calitem->max_days_selected; + g_date_add_days (&gdate_start, n_days); + } + else { + if (days_between + n_days > calitem->max_days_selected - 1) + n_days = calitem->max_days_selected - 1 - days_between; + g_date_add_days (&gdate_end, n_days); + } + + if (g_date_compare (&gdate_end, &gdate_start) < 0) { + GDate tmp_date; + tmp_date = gdate_start; + gdate_start = gdate_end; + gdate_end = tmp_date; + } + } + else { + /* clear "selecting_axis", it is only for mulit-selecting */ + if (calitem->selecting_axis) { + g_free (calitem->selecting_axis); + calitem->selecting_axis = NULL; + } + g_date_add_days (&gdate_start, n_days); + gdate_end = gdate_start; + } + + calitem->selecting = TRUE; + + e_calendar_item_set_selection_if_emission (calitem, + &gdate_start, &gdate_end, + FALSE); +} + +static gint +e_calendar_item_key_press_event (ECalendarItem *calitem, GdkEvent *event) +{ + guint keyval = event->key.keyval; + gboolean multi_selection = FALSE; + + if (event->key.state & GDK_CONTROL_MASK || + event->key.state & GDK_MOD1_MASK) + return FALSE; + + multi_selection = event->key.state & GDK_SHIFT_MASK; + switch (keyval) { + case GDK_Up: + e_calendar_item_selection_add_days (calitem, -7, + multi_selection); + break; + case GDK_Down: + e_calendar_item_selection_add_days (calitem, 7, + multi_selection); + break; + case GDK_Left: + e_calendar_item_selection_add_days (calitem, -1, + multi_selection); + break; + case GDK_Right: + e_calendar_item_selection_add_days (calitem, 1, + multi_selection); + break; + case GDK_space: + case GDK_Return: + e_calendar_item_stop_selecting (calitem, event->key.time); + break; + default: + return FALSE; + } + return TRUE; +} static gint e_calendar_item_event (GnomeCanvasItem *item, GdkEvent *event) @@ -1601,6 +1769,10 @@ e_calendar_item_event (GnomeCanvasItem *item, GdkEvent *event) return e_calendar_item_button_release (calitem, event); case GDK_MOTION_NOTIFY: return e_calendar_item_motion (calitem, event); + case GDK_FOCUS_CHANGE: + gnome_canvas_item_request_update (item); + case GDK_KEY_PRESS: + return e_calendar_item_key_press_event (calitem, event); default: break; } @@ -1752,7 +1924,11 @@ e_calendar_item_get_day_style (ECalendarItem *calitem, if (selected) { *fg_color = &calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_FG]; - *bg_color = &calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG]; + if (has_focus) + *bg_color = &calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG_FOCUSED]; + else + *bg_color = &calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG]; + } } @@ -1840,33 +2016,11 @@ e_calendar_item_button_press (ECalendarItem *calitem, return TRUE; } - static gboolean e_calendar_item_button_release (ECalendarItem *calitem, GdkEvent *event) { - if (!calitem->selecting) - return FALSE; - - gnome_canvas_item_ungrab (GNOME_CANVAS_ITEM (calitem), - event->button.time); - - calitem->selecting = FALSE; - - /* If the user selects the grayed dates before the first month or - after the last month, we move backwards or forwards one month. - The set_month() call should take care of updating the selection. */ - if (calitem->selection_end_month_offset == -1) - e_calendar_item_set_first_month (calitem, calitem->year, - calitem->month - 1); - else if (calitem->selection_start_month_offset == calitem->rows * calitem->cols) - e_calendar_item_set_first_month (calitem, calitem->year, - calitem->month + 1); - - calitem->selection_changed = TRUE; - e_calendar_item_queue_signal_emission (calitem); - gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (calitem)); - + e_calendar_item_stop_selecting (calitem, event->button.time); return FALSE; } @@ -2727,10 +2881,11 @@ e_calendar_item_get_selection (ECalendarItem *calitem, } -void -e_calendar_item_set_selection (ECalendarItem *calitem, - GDate *start_date, - GDate *end_date) +static void +e_calendar_item_set_selection_if_emission (ECalendarItem *calitem, + GDate *start_date, + GDate *end_date, + gboolean emission) { gint start_year, start_month, start_day; gint end_year, end_month, end_day; @@ -2740,13 +2895,6 @@ e_calendar_item_set_selection (ECalendarItem *calitem, g_return_if_fail (E_IS_CALENDAR_ITEM (calitem)); - /* If the user is in the middle of a selection, we must abort it. */ - if (calitem->selecting) { - gnome_canvas_item_ungrab (GNOME_CANVAS_ITEM (calitem), - GDK_CURRENT_TIME); - calitem->selecting = FALSE; - } - /* If start_date is NULL, we clear the selection without changing the month shown. */ if (start_date == NULL) { @@ -2759,9 +2907,9 @@ e_calendar_item_set_selection (ECalendarItem *calitem, if (end_date == NULL) end_date = start_date; - + g_return_if_fail (g_date_compare (start_date, end_date) <= 0); - + start_year = g_date_get_year (start_date); start_month = g_date_get_month (start_date) - 1; start_day = g_date_get_day (start_date); @@ -2775,7 +2923,8 @@ e_calendar_item_set_selection (ECalendarItem *calitem, start_day, end_year, end_month, - end_day); + end_day, + emission); new_start_month_offset = (start_year - calitem->year) * 12 + start_month - calitem->month; @@ -2794,7 +2943,8 @@ e_calendar_item_set_selection (ECalendarItem *calitem, || calitem->selection_end_day != new_end_day) { need_update = TRUE; calitem->selection_changed = TRUE; - e_calendar_item_queue_signal_emission (calitem); + if (emission) + e_calendar_item_queue_signal_emission (calitem); calitem->selection_set = TRUE; calitem->selection_start_month_offset = new_start_month_offset; calitem->selection_start_day = new_start_day; @@ -2810,6 +2960,22 @@ e_calendar_item_set_selection (ECalendarItem *calitem, gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (calitem)); } +void +e_calendar_item_set_selection (ECalendarItem *calitem, + GDate *start_date, + GDate *end_date) +{ + /* If the user is in the middle of a selection, we must abort it. */ + if (calitem->selecting) { + gnome_canvas_item_ungrab (GNOME_CANVAS_ITEM (calitem), + GDK_CURRENT_TIME); + calitem->selecting = FALSE; + } + + e_calendar_item_set_selection_if_emission (calitem, + start_date, end_date, + TRUE); +} /* This tries to ensure that the given time range is visible. If the range given is longer than we can show, only the start of it will be visible. @@ -2822,7 +2988,8 @@ e_calendar_item_ensure_days_visible (ECalendarItem *calitem, gint start_day, gint end_year, gint end_month, - gint end_day) + gint end_day, + gboolean emission) { gint current_end_year, current_end_month; gint months_shown, months; @@ -2903,7 +3070,7 @@ e_calendar_item_ensure_days_visible (ECalendarItem *calitem, } } - if (need_update) + if (need_update && emission) e_calendar_item_date_range_changed (calitem); return need_update; diff --git a/widgets/misc/e-calendar-item.h b/widgets/misc/e-calendar-item.h index a6fe161e5d..218095f741 100644 --- a/widgets/misc/e-calendar-item.h +++ b/widgets/misc/e-calendar-item.h @@ -45,6 +45,7 @@ typedef enum { E_CALENDAR_ITEM_COLOR_TODAY_BOX, E_CALENDAR_ITEM_COLOR_SELECTION_FG, + E_CALENDAR_ITEM_COLOR_SELECTION_BG_FOCUSED, E_CALENDAR_ITEM_COLOR_SELECTION_BG, E_CALENDAR_ITEM_COLOR_PREV_OR_NEXT_MONTH_FG, @@ -174,6 +175,7 @@ struct _ECalendarItem top-left calendar month view. Note that -1 is used for the last days from the previous month. The days are real month days. */ gboolean selecting; + GDate *selecting_axis; gboolean selection_dragging_end; gboolean selection_from_full_week; gboolean selection_set; diff --git a/widgets/misc/e-calendar.c b/widgets/misc/e-calendar.c index ec720e9047..b2eb17cf2e 100644 --- a/widgets/misc/e-calendar.c +++ b/widgets/misc/e-calendar.c @@ -3,6 +3,7 @@ /* * Author : * Damon Chaplin <damon@ximian.com> + * Bolian Yin <bolian.yin@sun.com> * * Copyright 2000, Ximian, Inc. * @@ -86,11 +87,16 @@ static gint e_calendar_drag_motion (GtkWidget *widget, static void e_calendar_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time); +static gboolean e_calendar_button_has_focus (ECalendar *cal); +static gboolean e_calendar_focus (GtkWidget *widget, + GtkDirectionType direction); static void e_calendar_on_prev_pressed (ECalendar *cal); static void e_calendar_on_prev_released (ECalendar *cal); +static void e_calendar_on_prev_clicked (ECalendar *cal); static void e_calendar_on_next_pressed (ECalendar *cal); static void e_calendar_on_next_released (ECalendar *cal); +static void e_calendar_on_next_clicked (ECalendar *cal); static void e_calendar_start_auto_move (ECalendar *cal, gboolean moving_forward); @@ -124,6 +130,7 @@ e_calendar_class_init (ECalendarClass *class) widget_class->size_allocate = e_calendar_size_allocate; widget_class->drag_motion = e_calendar_drag_motion; widget_class->drag_leave = e_calendar_drag_leave; + widget_class->focus = e_calendar_focus; } @@ -134,8 +141,6 @@ e_calendar_init (ECalendar *cal) PangoFontDescription *small_font_desc; GtkWidget *button, *pixmap; - GTK_WIDGET_UNSET_FLAGS (cal, GTK_CAN_FOCUS); - /* Create the small font. */ small_font_desc = @@ -154,7 +159,6 @@ e_calendar_init (ECalendar *cal) /* Create the arrow buttons to move to the previous/next month. */ button = gtk_button_new (); - GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_widget_show (button); gtk_signal_connect_object (GTK_OBJECT (button), "pressed", @@ -163,6 +167,9 @@ e_calendar_init (ECalendar *cal) gtk_signal_connect_object (GTK_OBJECT (button), "released", G_CALLBACK (e_calendar_on_prev_released), GTK_OBJECT (cal)); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + G_CALLBACK (e_calendar_on_prev_clicked), + GTK_OBJECT (cal)); pixmap = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_NONE); gtk_widget_show (pixmap); @@ -174,7 +181,6 @@ e_calendar_init (ECalendar *cal) NULL); button = gtk_button_new (); - GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_widget_show (button); gtk_signal_connect_object (GTK_OBJECT (button), "pressed", @@ -183,6 +189,9 @@ e_calendar_init (ECalendar *cal) gtk_signal_connect_object (GTK_OBJECT (button), "released", G_CALLBACK (e_calendar_on_next_released), GTK_OBJECT (cal)); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + G_CALLBACK (e_calendar_on_next_clicked), + GTK_OBJECT (cal)); pixmap = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_NONE); gtk_widget_show (pixmap); @@ -431,6 +440,12 @@ e_calendar_on_prev_pressed (ECalendar *cal) e_calendar_start_auto_move (cal, FALSE); } +static void +e_calendar_on_prev_clicked (ECalendar *cal) +{ + e_calendar_item_set_first_month (cal->calitem, cal->calitem->year, + cal->calitem->month - 1); +} static void e_calendar_on_next_pressed (ECalendar *cal) @@ -438,6 +453,12 @@ e_calendar_on_next_pressed (ECalendar *cal) e_calendar_start_auto_move (cal, TRUE); } +static void +e_calendar_on_next_clicked (ECalendar *cal) +{ + e_calendar_item_set_first_month (cal->calitem, cal->calitem->year, + cal->calitem->month + 1); +} static void e_calendar_start_auto_move (ECalendar *cal, @@ -549,3 +570,99 @@ e_calendar_drag_leave (GtkWidget *widget, #endif } +static gboolean +e_calendar_button_has_focus (ECalendar *cal) +{ + GtkWidget *prev_widget, *next_widget; + gboolean ret_val; + + g_return_val_if_fail (E_IS_CALENDAR (cal), FALSE); + + prev_widget = GNOME_CANVAS_WIDGET(cal->prev_item)->widget; + next_widget = GNOME_CANVAS_WIDGET(cal->next_item)->widget; + ret_val = GTK_WIDGET_HAS_FOCUS (prev_widget) || + GTK_WIDGET_HAS_FOCUS (next_widget); + return ret_val; +} + +static gboolean +e_calendar_focus (GtkWidget *widget, GtkDirectionType direction) +{ +#define E_CALENDAR_FOCUS_CHILDREN_NUM 3 + ECalendar *cal; + GnomeCanvas *canvas; + GnomeCanvasItem *children[E_CALENDAR_FOCUS_CHILDREN_NUM]; + gint focused_index = -1; + gint index; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (E_IS_CALENDAR (widget), FALSE); + cal = E_CALENDAR (widget); + canvas = GNOME_CANVAS (widget); + + if (!GTK_WIDGET_CAN_FOCUS (widget)) + return FALSE; + + children[0] = GNOME_CANVAS_ITEM (cal->calitem); + children[1] = cal->prev_item; + children[2] = cal->next_item; + + /* get current focused item, if e-calendar has had focus */ + if (GTK_WIDGET_HAS_FOCUS (widget) || e_calendar_button_has_focus (cal)) + for (index = 0; canvas->focused_item && index < E_CALENDAR_FOCUS_CHILDREN_NUM; ++index) { + if (children[index] == canvas->focused_item) { + focused_index = index; + break; + } + } + + if (focused_index == -1) + if (direction == GTK_DIR_TAB_FORWARD) + focused_index = 0; + else + focused_index = E_CALENDAR_FOCUS_CHILDREN_NUM - 1; + else + if (direction == GTK_DIR_TAB_FORWARD) + ++focused_index; + else + --focused_index; + + if (focused_index < 0 || + focused_index >= E_CALENDAR_FOCUS_CHILDREN_NUM) + /* move out of e-calendar */ + return FALSE; + gnome_canvas_item_grab_focus (children[focused_index]); + if (GNOME_IS_CANVAS_WIDGET (children[focused_index])) { + GtkWidget *widget; + widget = GNOME_CANVAS_WIDGET (children[focused_index])->widget; + gtk_widget_grab_focus (widget); + } + return TRUE; +} + +void +e_calendar_set_focusable (ECalendar *cal, gboolean focusable) +{ + GtkWidget *prev_widget, *next_widget; + + g_return_if_fail (E_IS_CALENDAR (cal)); + + prev_widget = GNOME_CANVAS_WIDGET(cal->prev_item)->widget; + next_widget = GNOME_CANVAS_WIDGET(cal->next_item)->widget; + + if (focusable) { + GTK_WIDGET_SET_FLAGS (cal, GTK_CAN_FOCUS); + GTK_WIDGET_SET_FLAGS (prev_widget, GTK_CAN_FOCUS); + GTK_WIDGET_SET_FLAGS (next_widget, GTK_CAN_FOCUS); + } + else { + if (GTK_WIDGET_HAS_FOCUS (cal) || e_calendar_button_has_focus (cal)) { + GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (cal)); + if (toplevel) + gtk_widget_grab_focus (toplevel); + } + GTK_WIDGET_UNSET_FLAGS (cal, GTK_CAN_FOCUS); + GTK_WIDGET_UNSET_FLAGS (prev_widget, GTK_CAN_FOCUS); + GTK_WIDGET_UNSET_FLAGS (next_widget, GTK_CAN_FOCUS); + } +} diff --git a/widgets/misc/e-calendar.h b/widgets/misc/e-calendar.h index aadde962f4..1fe6d2500c 100644 --- a/widgets/misc/e-calendar.h +++ b/widgets/misc/e-calendar.h @@ -93,6 +93,7 @@ void e_calendar_get_border_size (ECalendar *cal, gint *left, gint *right); +void e_calendar_set_focusable (ECalendar *cal, gboolean focusable); #ifdef __cplusplus } diff --git a/widgets/misc/e-dateedit.c b/widgets/misc/e-dateedit.c index 31b070a2e8..c6c2ad9bc7 100644 --- a/widgets/misc/e-dateedit.c +++ b/widgets/misc/e-dateedit.c @@ -1180,6 +1180,7 @@ e_date_edit_show_date_popup (EDateEdit *dedit) position_date_popup (dedit); gtk_widget_show (priv->cal_popup); + gdk_keyboard_grab (priv->cal_popup->window, TRUE, GDK_CURRENT_TIME); gtk_widget_grab_focus (priv->cal_popup); gtk_grab_add (priv->cal_popup); gdk_pointer_grab (priv->cal_popup->window, TRUE, @@ -1365,6 +1366,7 @@ hide_date_popup (EDateEdit *dedit) gtk_widget_hide (dedit->priv->cal_popup); gtk_grab_remove (dedit->priv->cal_popup); gdk_pointer_ungrab (GDK_CURRENT_TIME); + gdk_keyboard_ungrab (GDK_CURRENT_TIME); } |