aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2012-05-17 05:01:39 +0800
committerMilan Crha <mcrha@redhat.com>2012-05-17 05:01:39 +0800
commit9179758e50aa2e094ceb14c6d16b0d46f5d8bb7d (patch)
tree55dd59982598220e44b75e3008bd77f3132d9790
parentde8c6c1bdc0f70e13f9d5e1212b783641b633df0 (diff)
downloadgsoc2013-evolution-9179758e50aa2e094ceb14c6d16b0d46f5d8bb7d.tar.gz
gsoc2013-evolution-9179758e50aa2e094ceb14c6d16b0d46f5d8bb7d.tar.zst
gsoc2013-evolution-9179758e50aa2e094ceb14c6d16b0d46f5d8bb7d.zip
Bug #206484 - Add year scrolling to date picker
-rw-r--r--widgets/misc/e-calendar-item.c105
-rw-r--r--widgets/misc/e-calendar-item.h6
-rw-r--r--widgets/misc/e-calendar.c206
-rw-r--r--widgets/misc/e-calendar.h2
4 files changed, 277 insertions, 42 deletions
diff --git a/widgets/misc/e-calendar-item.c b/widgets/misc/e-calendar-item.c
index 94c1759076..d6fe7c55c1 100644
--- a/widgets/misc/e-calendar-item.c
+++ b/widgets/misc/e-calendar-item.c
@@ -1177,7 +1177,7 @@ e_calendar_item_draw_month (ECalendarItem *calitem,
gint year, month;
gint month_x, month_y, month_w, month_h;
gint min_x, max_x, text_x, text_y;
- gint day, day_index, cells_x, cells_y, min_cell_width, text_width;
+ gint day, day_index, cells_x, cells_y, min_cell_width, text_width, arrow_button_size;
gint clip_width, clip_height;
gchar buffer[64];
PangoContext *pango_context;
@@ -1205,6 +1205,12 @@ e_calendar_item_draw_month (ECalendarItem *calitem,
PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics));
xthickness = style->xthickness;
ythickness = style->ythickness;
+ arrow_button_size =
+ PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics))
+ + PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics))
+ + E_CALENDAR_ITEM_YPAD_ABOVE_MONTH_NAME
+ + E_CALENDAR_ITEM_YPAD_BELOW_MONTH_NAME
+ + 2 * xthickness;
pango_font_metrics_unref (font_metrics);
@@ -1238,7 +1244,7 @@ e_calendar_item_draw_month (ECalendarItem *calitem,
min_x = E_CALENDAR_ITEM_XPAD_BEFORE_MONTH_NAME;
max_x = month_w;
- if (row == 0 && col == calitem->cols - 1)
+ if (row == 0 && col == 0)
max_x -= E_CALENDAR_ITEM_XPAD_AFTER_MONTH_NAME_WITH_BUTTON;
else
max_x -= E_CALENDAR_ITEM_XPAD_AFTER_MONTH_NAME;
@@ -1265,23 +1271,69 @@ e_calendar_item_draw_month (ECalendarItem *calitem,
gdk_cairo_rectangle (cr, &clip_rect);
cairo_clip (cr);
- /* This is a strftime() format. %B = Month name, %Y = Year. */
- e_utf8_strftime (buffer, sizeof (buffer), _("%B %Y"), &tmp_tm);
+ gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
- pango_layout_set_font_description (layout, font_desc);
- pango_layout_set_text (layout, buffer, -1);
+ if (row == 0 && col == 0) {
+ PangoLayout *layout_yr;
+ gchar buffer_yr[64];
+ gdouble max_width;
- /* Ideally we place the text centered in the month, but we
- * won't go to the left of the minimum x position. */
- pango_layout_get_pixel_size (layout, &text_width, NULL);
- text_x = (calitem->month_width - text_width) / 2;
- text_x = MAX (min_x, text_x);
+ layout_yr = gtk_widget_create_pango_layout (widget, NULL);
- gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
- cairo_move_to (cr,
- month_x + text_x,
- text_y);
- pango_cairo_show_layout (cr, layout);
+ /* This is a strftime() format. %B = Month name. */
+ e_utf8_strftime (buffer, sizeof (buffer), C_("CalItem", "%B"), &tmp_tm);
+ /* This is a strftime() format. %Y = Year. */
+ e_utf8_strftime (buffer_yr, sizeof (buffer_yr), C_("CalItem", "%Y"), &tmp_tm);
+
+ pango_layout_set_font_description (layout, font_desc);
+ pango_layout_set_text (layout, buffer, -1);
+
+ pango_layout_set_font_description (layout_yr, font_desc);
+ pango_layout_set_text (layout_yr, buffer_yr, -1);
+
+ if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL) {
+ max_width = calitem->max_month_name_width;
+ pango_layout_get_pixel_size (layout, &text_width, NULL);
+
+ cairo_move_to (cr, month_x + min_x + arrow_button_size + (max_width - text_width) / 2, text_y);
+ pango_cairo_show_layout (cr, layout);
+
+ max_width = calitem->max_digit_width * 5;
+ pango_layout_get_pixel_size (layout_yr, &text_width, NULL);
+
+ cairo_move_to (cr, month_x + month_w - arrow_button_size - (max_width - text_width) / 2 - text_width - min_x, text_y);
+ pango_cairo_show_layout (cr, layout_yr);
+ } else {
+ max_width = calitem->max_digit_width * 5;
+ pango_layout_get_pixel_size (layout_yr, &text_width, NULL);
+
+ cairo_move_to (cr, month_x + min_x + arrow_button_size + (max_width - text_width) / 2, text_y);
+ pango_cairo_show_layout (cr, layout_yr);
+
+ max_width = calitem->max_month_name_width;
+ pango_layout_get_pixel_size (layout, &text_width, NULL);
+
+ cairo_move_to (cr, month_x + month_w - arrow_button_size - (max_width - text_width) / 2 - text_width - min_x, text_y);
+ pango_cairo_show_layout (cr, layout);
+ }
+
+ g_object_unref (layout_yr);
+ } else {
+ /* This is a strftime() format. %B = Month name, %Y = Year. */
+ e_utf8_strftime (buffer, sizeof (buffer), C_("CalItem", "%B %Y"), &tmp_tm);
+
+ pango_layout_set_font_description (layout, font_desc);
+ pango_layout_set_text (layout, buffer, -1);
+
+ /* Ideally we place the text centered in the month, but we
+ * won't go to the left of the minimum x position. */
+ pango_layout_get_pixel_size (layout, &text_width, NULL);
+ text_x = (calitem->month_width - text_width) / 2;
+ text_x = MAX (min_x, text_x);
+
+ cairo_move_to (cr, month_x + text_x, text_y);
+ pango_cairo_show_layout (cr, layout);
+ }
cairo_restore (cr);
}
@@ -1980,6 +2032,8 @@ e_calendar_item_recalc_sizes (ECalendarItem *calitem)
GtkStyle *style;
gint day, max_day_width, digit, max_digit_width, max_week_number_digit_width;
gint char_height, width, min_cell_width, min_cell_height;
+ gchar buffer[64];
+ struct tm tmp_tm;
PangoFontDescription *font_desc, *wkfont_desc;
PangoContext *pango_context;
PangoFontMetrics *font_metrics;
@@ -2072,6 +2126,23 @@ e_calendar_item_recalc_sizes (ECalendarItem *calitem)
+ E_CALENDAR_ITEM_YPAD_ABOVE_CELLS + min_cell_height * 6
+ E_CALENDAR_ITEM_YPAD_BELOW_CELLS;
+ calitem->max_month_name_width = 50;
+ memset (&tmp_tm, 0, sizeof (tmp_tm));
+ tmp_tm.tm_year = 2000 - 100;
+ tmp_tm.tm_mday = 1;
+ tmp_tm.tm_isdst = -1;
+ for (tmp_tm.tm_mon = 0; tmp_tm.tm_mon < 12 ; tmp_tm.tm_mon++) {
+ mktime (&tmp_tm);
+
+ e_utf8_strftime (buffer, sizeof (buffer), C_("CalItem", "%B"), &tmp_tm);
+
+ pango_layout_set_text (layout, buffer, -1);
+ pango_layout_get_pixel_size (layout, &width, NULL);
+
+ if (width > calitem->max_month_name_width)
+ calitem->max_month_name_width = width;
+ }
+
g_object_unref (layout);
g_object_unref (pango_context);
pango_font_metrics_unref (font_metrics);
@@ -3266,6 +3337,8 @@ e_calendar_item_style_set (GtkWidget *widget,
color = &style->fg[GTK_STATE_INSENSITIVE];
calitem->colors[E_CALENDAR_ITEM_COLOR_PREV_OR_NEXT_MONTH_FG] = *color;
+
+ e_calendar_item_recalc_sizes (calitem);
}
void
diff --git a/widgets/misc/e-calendar-item.h b/widgets/misc/e-calendar-item.h
index 19f096c5b2..d8fc5f7277 100644
--- a/widgets/misc/e-calendar-item.h
+++ b/widgets/misc/e-calendar-item.h
@@ -59,10 +59,10 @@ G_BEGIN_DECLS
#define E_CALENDAR_ITEM_YPAD_BELOW_CELLS 2
/* Horizontal padding in the heading bars. */
-#define E_CALENDAR_ITEM_XPAD_BEFORE_MONTH_NAME_WITH_BUTTON 16
+#define E_CALENDAR_ITEM_XPAD_BEFORE_MONTH_NAME_WITH_BUTTON 10
#define E_CALENDAR_ITEM_XPAD_BEFORE_MONTH_NAME 3
#define E_CALENDAR_ITEM_XPAD_AFTER_MONTH_NAME 3
-#define E_CALENDAR_ITEM_XPAD_AFTER_MONTH_NAME_WITH_BUTTON 16
+#define E_CALENDAR_ITEM_XPAD_AFTER_MONTH_NAME_WITH_BUTTON 10
/* Horizontal padding in the month displays. */
#define E_CALENDAR_ITEM_XPAD_BEFORE_WEEK_NUMBERS 4
@@ -241,6 +241,8 @@ struct _ECalendarItem
gint week_number_digit_widths[10];
gint max_week_number_digit_width;
+ gint max_month_name_width;
+
/* Fonts for drawing text. If font isn't set it uses the font from the
* canvas widget. If week_number_font isn't set it uses font. */
PangoFontDescription *font_desc;
diff --git a/widgets/misc/e-calendar.c b/widgets/misc/e-calendar.c
index 1899d7c61f..c5c6283f81 100644
--- a/widgets/misc/e-calendar.c
+++ b/widgets/misc/e-calendar.c
@@ -95,11 +95,20 @@ 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);
-static gboolean e_calendar_auto_move_handler (gpointer data);
-static void e_calendar_stop_auto_move (ECalendar *cal);
+static void e_calendar_on_prev_year_pressed (ECalendar *cal);
+static void e_calendar_on_prev_year_released (ECalendar *cal);
+static void e_calendar_on_prev_year_clicked (ECalendar *cal);
+static void e_calendar_on_next_year_pressed (ECalendar *cal);
+static void e_calendar_on_next_year_released (ECalendar *cal);
+static void e_calendar_on_next_year_clicked (ECalendar *cal);
+
+static void e_calendar_start_auto_move (ECalendar *cal,
+ gboolean moving_forward);
+static gboolean e_calendar_auto_move_handler (gpointer data);
+static void e_calendar_start_auto_move_year (ECalendar *cal,
+ gboolean moving_forward);
+static gboolean e_calendar_auto_move_year_handler (gpointer data);
+static void e_calendar_stop_auto_move (ECalendar *cal);
G_DEFINE_TYPE (
ECalendar,
@@ -175,7 +184,7 @@ e_calendar_init (ECalendar *cal)
"widget", button,
NULL);
a11y = gtk_widget_get_accessible (button);
- atk_object_set_name (a11y, _("Previous"));
+ atk_object_set_name (a11y, _("Previous month"));
button = gtk_button_new ();
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
@@ -199,7 +208,50 @@ e_calendar_init (ECalendar *cal)
"widget", button,
NULL);
a11y = gtk_widget_get_accessible (button);
- atk_object_set_name (a11y, _("Next"));
+ atk_object_set_name (a11y, _("Next month"));
+
+ /* Create the arrow buttons to move to the previous/next year. */
+ button = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ gtk_widget_show (button);
+ g_signal_connect_swapped (button, "pressed",
+ G_CALLBACK (e_calendar_on_prev_year_pressed), cal);
+ g_signal_connect_swapped (button, "released",
+ G_CALLBACK (e_calendar_on_prev_year_released), cal);
+ g_signal_connect_swapped (button, "clicked",
+ G_CALLBACK (e_calendar_on_prev_year_clicked), cal);
+
+ pixmap = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_NONE);
+ gtk_widget_show (pixmap);
+ gtk_container_add (GTK_CONTAINER (button), pixmap);
+
+ cal->prev_item_year = gnome_canvas_item_new (canvas_group,
+ gnome_canvas_widget_get_type (),
+ "widget", button,
+ NULL);
+ a11y = gtk_widget_get_accessible (button);
+ atk_object_set_name (a11y, _("Previous year"));
+
+ button = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ gtk_widget_show (button);
+ g_signal_connect_swapped (button, "pressed",
+ G_CALLBACK (e_calendar_on_next_year_pressed), cal);
+ g_signal_connect_swapped (button, "released",
+ G_CALLBACK (e_calendar_on_next_year_released), cal);
+ g_signal_connect_swapped (button, "clicked",
+ G_CALLBACK (e_calendar_on_next_year_clicked), cal);
+
+ pixmap = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
+ gtk_widget_show (pixmap);
+ gtk_container_add (GTK_CONTAINER (button), pixmap);
+
+ cal->next_item_year = gnome_canvas_item_new (canvas_group,
+ gnome_canvas_widget_get_type (),
+ "widget", button,
+ NULL);
+ a11y = gtk_widget_get_accessible (button);
+ atk_object_set_name (a11y, _("Next year"));
cal->min_rows = 1;
cal->min_cols = 1;
@@ -331,7 +383,8 @@ e_calendar_size_allocate (GtkWidget *widget,
PangoContext *pango_context;
PangoFontMetrics *font_metrics;
gdouble old_x2, old_y2, new_x2, new_y2;
- gdouble xthickness, ythickness, arrow_button_size;
+ gdouble xthickness, ythickness, arrow_button_size, current_x, month_width;
+ gboolean is_rtl;
cal = E_CALENDAR (widget);
style = gtk_widget_get_style (widget);
@@ -364,32 +417,57 @@ e_calendar_size_allocate (GtkWidget *widget,
"y2", new_y2,
NULL);
+ if (cal->calitem->month_width > 0)
+ month_width = cal->calitem->month_width;
+ else
+ month_width = new_x2;
+ month_width -= E_CALENDAR_ITEM_MIN_CELL_XPAD + E_CALENDAR_ARROW_BUTTON_X_PAD;
+
/* Position the arrow buttons. */
arrow_button_size =
PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics))
+ PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics))
+ E_CALENDAR_ITEM_YPAD_ABOVE_MONTH_NAME
+ E_CALENDAR_ITEM_YPAD_BELOW_MONTH_NAME
- - E_CALENDAR_ARROW_BUTTON_Y_PAD * 2;
+ - E_CALENDAR_ARROW_BUTTON_Y_PAD * 2 - 2;
+
+ is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+ current_x = is_rtl ?
+ (month_width - 2 * xthickness - E_CALENDAR_ARROW_BUTTON_X_PAD - arrow_button_size) :
+ (xthickness);
gnome_canvas_item_set (cal->prev_item,
- "x", (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
- ? new_x2 + 1 - xthickness * 2 - E_CALENDAR_ARROW_BUTTON_X_PAD
- - arrow_button_size
- : xthickness * 2 + E_CALENDAR_ARROW_BUTTON_X_PAD,
- "y", ythickness * 2
- + E_CALENDAR_ARROW_BUTTON_Y_PAD,
+ "x", current_x,
+ "y", ythickness + E_CALENDAR_ARROW_BUTTON_Y_PAD,
"width", arrow_button_size,
"height", arrow_button_size,
NULL);
+ current_x += (is_rtl ? -1.0 : +1.0) * (cal->calitem->max_month_name_width - xthickness + 2 * arrow_button_size);
+
gnome_canvas_item_set (cal->next_item,
- "x", (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
- ? xthickness * 2 + E_CALENDAR_ARROW_BUTTON_X_PAD
- : new_x2 + 1 - xthickness * 2 - E_CALENDAR_ARROW_BUTTON_X_PAD
- - arrow_button_size,
- "y", ythickness * 2
- + E_CALENDAR_ARROW_BUTTON_Y_PAD,
+ "x", current_x,
+ "y", ythickness + E_CALENDAR_ARROW_BUTTON_Y_PAD,
+ "width", arrow_button_size,
+ "height", arrow_button_size,
+ NULL);
+
+ current_x = is_rtl ?
+ (xthickness) :
+ (month_width - 2 * xthickness - E_CALENDAR_ARROW_BUTTON_X_PAD - arrow_button_size);
+
+ gnome_canvas_item_set (cal->next_item_year,
+ "x", current_x,
+ "y", ythickness + E_CALENDAR_ARROW_BUTTON_Y_PAD,
+ "width", arrow_button_size,
+ "height", arrow_button_size,
+ NULL);
+
+ current_x += (is_rtl ? +1.0 : -1.0) * (cal->calitem->max_digit_width * 5 - xthickness + 2 * arrow_button_size);
+
+ gnome_canvas_item_set (cal->prev_item_year,
+ "x", current_x,
+ "y", ythickness + E_CALENDAR_ARROW_BUTTON_Y_PAD,
"width", arrow_button_size,
"height", arrow_button_size,
NULL);
@@ -470,6 +548,18 @@ e_calendar_on_next_pressed (ECalendar *cal)
}
static void
+e_calendar_on_prev_year_pressed (ECalendar *cal)
+{
+ e_calendar_start_auto_move_year (cal, FALSE);
+}
+
+static void
+e_calendar_on_next_year_pressed (ECalendar *cal)
+{
+ e_calendar_start_auto_move_year (cal, TRUE);
+}
+
+static void
e_calendar_start_auto_move (ECalendar *cal,
gboolean moving_forward)
{
@@ -483,6 +573,46 @@ e_calendar_start_auto_move (ECalendar *cal,
}
+static void
+e_calendar_start_auto_move_year (ECalendar *cal,
+ gboolean moving_forward)
+{
+ if (cal->timeout_id == 0) {
+ cal->timeout_id = g_timeout_add (E_CALENDAR_AUTO_MOVE_TIMEOUT,
+ e_calendar_auto_move_year_handler,
+ cal);
+ }
+ cal->timeout_delay = E_CALENDAR_AUTO_MOVE_TIMEOUT_DELAY;
+ cal->moving_forward = moving_forward;
+}
+
+static gboolean
+e_calendar_auto_move_year_handler (gpointer data)
+{
+ ECalendar *cal;
+ ECalendarItem *calitem;
+ gint offset;
+
+ g_return_val_if_fail (E_IS_CALENDAR (data), FALSE);
+
+ cal = E_CALENDAR (data);
+ calitem = cal->calitem;
+
+ GDK_THREADS_ENTER ();
+
+ if (cal->timeout_delay > 0) {
+ cal->timeout_delay--;
+ } else {
+ offset = cal->moving_forward ? 12 : -12;
+ e_calendar_item_set_first_month (calitem, calitem->year,
+ calitem->month + offset);
+ }
+
+ GDK_THREADS_LEAVE ();
+
+ return TRUE;
+}
+
static gboolean
e_calendar_auto_move_handler (gpointer data)
{
@@ -522,6 +652,18 @@ e_calendar_on_next_released (ECalendar *cal)
}
static void
+e_calendar_on_prev_year_released (ECalendar *cal)
+{
+ e_calendar_stop_auto_move (cal);
+}
+
+static void
+e_calendar_on_next_year_released (ECalendar *cal)
+{
+ e_calendar_stop_auto_move (cal);
+}
+
+static void
e_calendar_stop_auto_move (ECalendar *cal)
{
if (cal->timeout_id != 0) {
@@ -534,14 +676,28 @@ static void
e_calendar_on_prev_clicked (ECalendar *cal)
{
e_calendar_item_set_first_month (cal->calitem, cal->calitem->year,
- cal->calitem->month - 1);
+ cal->calitem->month - 1);
}
static void
e_calendar_on_next_clicked (ECalendar *cal)
{
e_calendar_item_set_first_month (cal->calitem, cal->calitem->year,
- cal->calitem->month + 1);
+ cal->calitem->month + 1);
+}
+
+static void
+e_calendar_on_prev_year_clicked (ECalendar *cal)
+{
+ e_calendar_item_set_first_month (cal->calitem, cal->calitem->year,
+ cal->calitem->month - 12);
+}
+
+static void
+e_calendar_on_next_year_clicked (ECalendar *cal)
+{
+ e_calendar_item_set_first_month (cal->calitem, cal->calitem->year,
+ cal->calitem->month + 12);
}
static gint
@@ -580,7 +736,7 @@ static gboolean
e_calendar_focus (GtkWidget *widget,
GtkDirectionType direction)
{
-#define E_CALENDAR_FOCUS_CHILDREN_NUM 3
+#define E_CALENDAR_FOCUS_CHILDREN_NUM 5
ECalendar *cal;
GnomeCanvas *canvas;
GnomeCanvasItem *children[E_CALENDAR_FOCUS_CHILDREN_NUM];
@@ -598,6 +754,8 @@ e_calendar_focus (GtkWidget *widget,
children[0] = GNOME_CANVAS_ITEM (cal->calitem);
children[1] = cal->prev_item;
children[2] = cal->next_item;
+ children[3] = cal->prev_item_year;
+ children[4] = cal->next_item_year;
/* get current focused item, if e-calendar has had focus */
if (gtk_widget_has_focus (widget) || e_calendar_button_has_focus (cal))
diff --git a/widgets/misc/e-calendar.h b/widgets/misc/e-calendar.h
index 027a1c1fc3..bdf77786f2 100644
--- a/widgets/misc/e-calendar.h
+++ b/widgets/misc/e-calendar.h
@@ -66,6 +66,8 @@ struct _ECalendar {
GnomeCanvasItem *prev_item;
GnomeCanvasItem *next_item;
+ GnomeCanvasItem *prev_item_year;
+ GnomeCanvasItem *next_item_year;
gint min_rows;
gint min_cols;