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
This commit is contained in:
Bolian Yin
2003-09-22 03:19:00 +00:00
committed by Bolian Yin
parent 939c8a4b82
commit 88d4fd5eac
6 changed files with 362 additions and 53 deletions

View File

@ -1,3 +1,23 @@
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.
2003-08-27 Hans Petter Jansson <hpj@ximian.com> 2003-08-27 Hans Petter Jansson <hpj@ximian.com>
Fixes #15638. Fixes #15638.

View File

@ -3,6 +3,7 @@
/* /*
* Author : * Author :
* Damon Chaplin <damon@ximian.com> * Damon Chaplin <damon@ximian.com>
* Bolian Yin <bolian.yin@sun.com>
* *
* Copyright 2000, Ximian, Inc. * Copyright 2000, Ximian, Inc.
* *
@ -41,6 +42,7 @@
#include <gtk/gtkmenuitem.h> #include <gtk/gtkmenuitem.h>
#include <gtk/gtklabel.h> #include <gtk/gtklabel.h>
#include <gtk/gtksignal.h> #include <gtk/gtksignal.h>
#include <gdk/gdkkeysyms.h>
#include <libgnome/gnome-i18n.h> #include <libgnome/gnome-i18n.h>
#include <gal/util/e-util.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, static void e_calendar_item_set_arg (GtkObject *o,
GtkArg *arg, GtkArg *arg,
guint arg_id); 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_realize (GnomeCanvasItem *item);
static void e_calendar_item_unrealize (GnomeCanvasItem *item); static void e_calendar_item_unrealize (GnomeCanvasItem *item);
static void e_calendar_item_unmap (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 cx,
int cy, int cy,
GnomeCanvasItem **actual_item); 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, static gint e_calendar_item_event (GnomeCanvasItem *item,
GdkEvent *event); GdkEvent *event);
static void e_calendar_item_bounds (GnomeCanvasItem *item, double *x1, double *y1, static void e_calendar_item_bounds (GnomeCanvasItem *item, double *x1, double *y1,
@ -211,7 +222,8 @@ static gboolean e_calendar_item_ensure_days_visible (ECalendarItem *calitem,
gint start_day, gint start_day,
gint end_year, gint end_year,
gint end_month, gint end_month,
gint end_day); gint end_day,
gboolean emission);
static void e_calendar_item_show_popup_menu (ECalendarItem *calitem, static void e_calendar_item_show_popup_menu (ECalendarItem *calitem,
GdkEventButton *event, GdkEventButton *event,
gint month_offset); 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_date_range_changed (ECalendarItem *calitem);
static void e_calendar_item_queue_signal_emission (ECalendarItem *calitem); static void e_calendar_item_queue_signal_emission (ECalendarItem *calitem);
static gboolean e_calendar_item_signal_emission_idle_cb (gpointer data); 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. */ /* Our arguments. */
enum { enum {
@ -273,11 +289,13 @@ static void
e_calendar_item_class_init (ECalendarItemClass *class) e_calendar_item_class_init (ECalendarItemClass *class)
{ {
GtkObjectClass *object_class; GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GnomeCanvasItemClass *item_class; GnomeCanvasItemClass *item_class;
parent_class = g_type_class_ref(gnome_canvas_item_get_type()); parent_class = g_type_class_ref(gnome_canvas_item_get_type());
object_class = (GtkObjectClass *) class; object_class = (GtkObjectClass *) class;
widget_class = (GtkWidgetClass *) class;
item_class = (GnomeCanvasItemClass *) class; item_class = (GnomeCanvasItemClass *) class;
gtk_object_add_arg_type ("ECalendarItem::year", 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->get_arg = e_calendar_item_get_arg;
object_class->set_arg = e_calendar_item_set_arg; object_class->set_arg = e_calendar_item_set_arg;
widget_class->focus = e_calendar_item_focus;
/* GnomeCanvasItem method overrides */ /* GnomeCanvasItem method overrides */
item_class->realize = e_calendar_item_realize; item_class->realize = e_calendar_item_realize;
item_class->unrealize = e_calendar_item_unrealize; item_class->unrealize = e_calendar_item_unrealize;
@ -416,6 +435,9 @@ e_calendar_item_init (ECalendarItem *calitem)
calitem->x2 = 0.0; calitem->x2 = 0.0;
calitem->y2 = 0.0; calitem->y2 = 0.0;
calitem->selecting = FALSE;
calitem->selecting_axis = NULL;
calitem->selection_set = FALSE; calitem->selection_set = FALSE;
calitem->selection_changed = FALSE; calitem->selection_changed = FALSE;
@ -467,6 +489,8 @@ e_calendar_item_destroy (GtkObject *o)
calitem->week_number_font_desc = NULL; calitem->week_number_font_desc = NULL;
} }
if (calitem->selecting_axis)
g_free (calitem->selecting_axis);
if (GTK_OBJECT_CLASS (parent_class)->destroy) if (GTK_OBJECT_CLASS (parent_class)->destroy)
(* GTK_OBJECT_CLASS (parent_class)->destroy) (o); (* 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 static void
e_calendar_item_realize (GnomeCanvasItem *item) 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].green = 65535;
calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_FG].blue = 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].red = 47000;
calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG].green = 47000; calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG].green = 47000;
calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG].blue = 48000; 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 num_chars, digit;
gint week_num, mon, days_from_week_start; gint week_num, mon, days_from_week_start;
gint years[3], months[3], days_in_month[3]; 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; gboolean bold, draw_day, finished = FALSE;
gint today_year, today_month, today_mday, month_offset; gint today_year, today_month, today_mday, month_offset;
gchar buffer[2]; 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]; day_style = calitem->styles[(month_offset + 1) * 32 + day_num];
/* Get the colors & style to use for the day.*/ /* 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) if (calitem->style_callback)
(*calitem->style_callback) (*calitem->style_callback)
(calitem, (calitem,
@ -1586,6 +1632,128 @@ e_calendar_item_point (GnomeCanvasItem *item, double x, double y,
return 0.0; 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 static gint
e_calendar_item_event (GnomeCanvasItem *item, GdkEvent *event) 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); return e_calendar_item_button_release (calitem, event);
case GDK_MOTION_NOTIFY: case GDK_MOTION_NOTIFY:
return e_calendar_item_motion (calitem, event); 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: default:
break; break;
} }
@ -1752,7 +1924,11 @@ e_calendar_item_get_day_style (ECalendarItem *calitem,
if (selected) { if (selected) {
*fg_color = &calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_FG]; *fg_color = &calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_FG];
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]; *bg_color = &calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG];
} }
} }
@ -1840,33 +2016,11 @@ e_calendar_item_button_press (ECalendarItem *calitem,
return TRUE; return TRUE;
} }
static gboolean static gboolean
e_calendar_item_button_release (ECalendarItem *calitem, e_calendar_item_button_release (ECalendarItem *calitem,
GdkEvent *event) GdkEvent *event)
{ {
if (!calitem->selecting) e_calendar_item_stop_selecting (calitem, event->button.time);
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));
return FALSE; return FALSE;
} }
@ -2727,10 +2881,11 @@ e_calendar_item_get_selection (ECalendarItem *calitem,
} }
void static void
e_calendar_item_set_selection (ECalendarItem *calitem, e_calendar_item_set_selection_if_emission (ECalendarItem *calitem,
GDate *start_date, GDate *start_date,
GDate *end_date) GDate *end_date,
gboolean emission)
{ {
gint start_year, start_month, start_day; gint start_year, start_month, start_day;
gint end_year, end_month, end_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)); 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 /* If start_date is NULL, we clear the selection without changing the
month shown. */ month shown. */
if (start_date == NULL) { if (start_date == NULL) {
@ -2775,7 +2923,8 @@ e_calendar_item_set_selection (ECalendarItem *calitem,
start_day, start_day,
end_year, end_year,
end_month, end_month,
end_day); end_day,
emission);
new_start_month_offset = (start_year - calitem->year) * 12 new_start_month_offset = (start_year - calitem->year) * 12
+ start_month - calitem->month; + start_month - calitem->month;
@ -2794,6 +2943,7 @@ e_calendar_item_set_selection (ECalendarItem *calitem,
|| calitem->selection_end_day != new_end_day) { || calitem->selection_end_day != new_end_day) {
need_update = TRUE; need_update = TRUE;
calitem->selection_changed = TRUE; calitem->selection_changed = TRUE;
if (emission)
e_calendar_item_queue_signal_emission (calitem); e_calendar_item_queue_signal_emission (calitem);
calitem->selection_set = TRUE; calitem->selection_set = TRUE;
calitem->selection_start_month_offset = new_start_month_offset; calitem->selection_start_month_offset = new_start_month_offset;
@ -2810,6 +2960,22 @@ e_calendar_item_set_selection (ECalendarItem *calitem,
gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (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 /* 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. 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 start_day,
gint end_year, gint end_year,
gint end_month, gint end_month,
gint end_day) gint end_day,
gboolean emission)
{ {
gint current_end_year, current_end_month; gint current_end_year, current_end_month;
gint months_shown, months; 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); e_calendar_item_date_range_changed (calitem);
return need_update; return need_update;

View File

@ -45,6 +45,7 @@ typedef enum
{ {
E_CALENDAR_ITEM_COLOR_TODAY_BOX, E_CALENDAR_ITEM_COLOR_TODAY_BOX,
E_CALENDAR_ITEM_COLOR_SELECTION_FG, E_CALENDAR_ITEM_COLOR_SELECTION_FG,
E_CALENDAR_ITEM_COLOR_SELECTION_BG_FOCUSED,
E_CALENDAR_ITEM_COLOR_SELECTION_BG, E_CALENDAR_ITEM_COLOR_SELECTION_BG,
E_CALENDAR_ITEM_COLOR_PREV_OR_NEXT_MONTH_FG, 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 top-left calendar month view. Note that -1 is used for the last days
from the previous month. The days are real month days. */ from the previous month. The days are real month days. */
gboolean selecting; gboolean selecting;
GDate *selecting_axis;
gboolean selection_dragging_end; gboolean selection_dragging_end;
gboolean selection_from_full_week; gboolean selection_from_full_week;
gboolean selection_set; gboolean selection_set;

View File

@ -3,6 +3,7 @@
/* /*
* Author : * Author :
* Damon Chaplin <damon@ximian.com> * Damon Chaplin <damon@ximian.com>
* Bolian Yin <bolian.yin@sun.com>
* *
* Copyright 2000, Ximian, Inc. * Copyright 2000, Ximian, Inc.
* *
@ -86,11 +87,16 @@ static gint e_calendar_drag_motion (GtkWidget *widget,
static void e_calendar_drag_leave (GtkWidget *widget, static void e_calendar_drag_leave (GtkWidget *widget,
GdkDragContext *context, GdkDragContext *context,
guint time); 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_pressed (ECalendar *cal);
static void e_calendar_on_prev_released (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_pressed (ECalendar *cal);
static void e_calendar_on_next_released (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, static void e_calendar_start_auto_move (ECalendar *cal,
gboolean moving_forward); gboolean moving_forward);
@ -124,6 +130,7 @@ e_calendar_class_init (ECalendarClass *class)
widget_class->size_allocate = e_calendar_size_allocate; widget_class->size_allocate = e_calendar_size_allocate;
widget_class->drag_motion = e_calendar_drag_motion; widget_class->drag_motion = e_calendar_drag_motion;
widget_class->drag_leave = e_calendar_drag_leave; 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; PangoFontDescription *small_font_desc;
GtkWidget *button, *pixmap; GtkWidget *button, *pixmap;
GTK_WIDGET_UNSET_FLAGS (cal, GTK_CAN_FOCUS);
/* Create the small font. */ /* Create the small font. */
small_font_desc = small_font_desc =
@ -154,7 +159,6 @@ e_calendar_init (ECalendar *cal)
/* Create the arrow buttons to move to the previous/next month. */ /* Create the arrow buttons to move to the previous/next month. */
button = gtk_button_new (); button = gtk_button_new ();
GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
gtk_widget_show (button); gtk_widget_show (button);
gtk_signal_connect_object (GTK_OBJECT (button), "pressed", 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", gtk_signal_connect_object (GTK_OBJECT (button), "released",
G_CALLBACK (e_calendar_on_prev_released), G_CALLBACK (e_calendar_on_prev_released),
GTK_OBJECT (cal)); 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); pixmap = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_NONE);
gtk_widget_show (pixmap); gtk_widget_show (pixmap);
@ -174,7 +181,6 @@ e_calendar_init (ECalendar *cal)
NULL); NULL);
button = gtk_button_new (); button = gtk_button_new ();
GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
gtk_widget_show (button); gtk_widget_show (button);
gtk_signal_connect_object (GTK_OBJECT (button), "pressed", 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", gtk_signal_connect_object (GTK_OBJECT (button), "released",
G_CALLBACK (e_calendar_on_next_released), G_CALLBACK (e_calendar_on_next_released),
GTK_OBJECT (cal)); 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); pixmap = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
gtk_widget_show (pixmap); gtk_widget_show (pixmap);
@ -431,6 +440,12 @@ e_calendar_on_prev_pressed (ECalendar *cal)
e_calendar_start_auto_move (cal, FALSE); 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 static void
e_calendar_on_next_pressed (ECalendar *cal) 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); 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 static void
e_calendar_start_auto_move (ECalendar *cal, e_calendar_start_auto_move (ECalendar *cal,
@ -549,3 +570,99 @@ e_calendar_drag_leave (GtkWidget *widget,
#endif #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);
}
}

View File

@ -93,6 +93,7 @@ void e_calendar_get_border_size (ECalendar *cal,
gint *left, gint *left,
gint *right); gint *right);
void e_calendar_set_focusable (ECalendar *cal, gboolean focusable);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1180,6 +1180,7 @@ e_date_edit_show_date_popup (EDateEdit *dedit)
position_date_popup (dedit); position_date_popup (dedit);
gtk_widget_show (priv->cal_popup); 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_widget_grab_focus (priv->cal_popup);
gtk_grab_add (priv->cal_popup); gtk_grab_add (priv->cal_popup);
gdk_pointer_grab (priv->cal_popup->window, TRUE, 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_widget_hide (dedit->priv->cal_popup);
gtk_grab_remove (dedit->priv->cal_popup); gtk_grab_remove (dedit->priv->cal_popup);
gdk_pointer_ungrab (GDK_CURRENT_TIME); gdk_pointer_ungrab (GDK_CURRENT_TIME);
gdk_keyboard_ungrab (GDK_CURRENT_TIME);
} }