Updated Traditional Chinese translation(Hong Kong and Taiwan)
[evolution.git] / calendar / gui / e-day-view-top-item.c
blobe517e75781624afd0bc431226eb4dde9026350bd
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 * Authors:
17 * Damon Chaplin <damon@ximian.com>
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
24 * EDayViewTopItem - displays the top part of the Day/Work Week calendar view.
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
31 #include <glib.h>
32 #include <glib/gi18n.h>
33 #include "e-util/e-categories-config.h"
34 #include <libecal/e-cal-time-util.h>
35 #include <libedataserver/e-data-server-util.h>
36 #include <libedataserver/e-categories.h>
37 #include "e-calendar-view.h"
38 #include "e-day-view-top-item.h"
40 #define E_DAY_VIEW_TOP_ITEM_GET_PRIVATE(obj) \
41 (G_TYPE_INSTANCE_GET_PRIVATE \
42 ((obj), E_TYPE_DAY_VIEW_TOP_ITEM, EDayViewTopItemPrivate))
44 struct _EDayViewTopItemPrivate {
45 /* The parent EDayView widget. */
46 EDayView *day_view;
48 /* Show dates or events. */
49 gboolean show_dates;
52 enum {
53 PROP_0,
54 PROP_DAY_VIEW,
55 PROP_SHOW_DATES
58 static gpointer parent_class;
60 /* This draws a little triangle to indicate that an event extends past
61 the days visible on screen. */
62 static void
63 day_view_top_item_draw_triangle (EDayViewTopItem *top_item,
64 GdkDrawable *drawable,
65 gint x,
66 gint y,
67 gint w,
68 gint h,
69 gint event_num)
71 EDayView *day_view;
72 EDayViewEvent *event;
73 GdkColor bg_color;
74 GdkPoint points[3];
75 gint c1, c2;
76 cairo_t *cr;
78 day_view = e_day_view_top_item_get_day_view (top_item);
80 points[0].x = x;
81 points[0].y = y;
82 points[1].x = x + w;
83 points[1].y = y + (h / 2);
84 points[2].x = x;
85 points[2].y = y + h - 1;
87 /* If the height is odd we can use the same central point for both
88 lines. If it is even we use different end-points. */
89 c1 = c2 = y + (h / 2);
90 if (h % 2 == 0)
91 c1--;
93 if (!is_array_index_in_bounds (day_view->long_events, event_num))
94 return;
96 event = &g_array_index (day_view->long_events, EDayViewEvent,
97 event_num);
99 if (!is_comp_data_valid (event))
100 return;
102 cr = gdk_cairo_create (drawable);
104 cairo_save (cr);
105 /* Fill it in. */
106 if (gdk_color_parse (
107 e_cal_model_get_color_for_component (
108 e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)),
109 event->comp_data), &bg_color)) {
110 GdkColormap *colormap;
112 colormap = gtk_widget_get_colormap (GTK_WIDGET (day_view));
113 if (gdk_colormap_alloc_color (colormap, &bg_color, TRUE, TRUE)) {
114 gdk_cairo_set_source_color (cr, &bg_color);
115 } else {
116 gdk_cairo_set_source_color (
117 cr, &day_view->colors
118 [E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND]);
120 } else {
121 gdk_cairo_set_source_color (
122 cr, &day_view->colors
123 [E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND]);
126 cairo_move_to (cr, points[0].x, points[0].y);
127 cairo_line_to (cr, points[1].x, points[1].y);
128 cairo_line_to (cr, points[2].x, points[2].y);
129 cairo_line_to (cr, points[0].x, points[0].y);
130 cairo_fill (cr);
131 cairo_restore (cr);
133 cairo_save (cr);
134 gdk_cairo_set_source_color (
135 cr, &day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BORDER]);
136 cairo_move_to (cr, x, y);
137 cairo_line_to (cr, x + w, c1);
138 cairo_move_to (cr, x, y + h - 1);
139 cairo_line_to (cr, x + w, c2);
140 cairo_stroke (cr);
141 cairo_restore (cr);
143 cairo_destroy (cr);
146 /* This draws one event in the top canvas. */
147 static void
148 day_view_top_item_draw_long_event (EDayViewTopItem *top_item,
149 gint event_num,
150 GdkDrawable *drawable,
151 gint x,
152 gint y,
153 gint width,
154 gint height)
156 EDayView *day_view;
157 EDayViewEvent *event;
158 GtkStyle *style;
159 gint start_day, end_day;
160 gint item_x, item_y, item_w, item_h;
161 gint text_x, icon_x, icon_y, icon_x_inc;
162 ECalModel *model;
163 ECalComponent *comp;
164 gchar buffer[16];
165 gint hour, display_hour, minute, offset, time_width, time_x;
166 gint min_end_time_x, suffix_width, max_icon_x;
167 const gchar *suffix;
168 gboolean draw_start_triangle, draw_end_triangle;
169 GSList *categories_list, *elem;
170 PangoLayout *layout;
171 GdkColor bg_color;
172 cairo_t *cr;
173 cairo_pattern_t *pat;
174 guint16 red, green, blue;
175 gdouble cc = 65535.0;
176 gdouble x0, y0, rect_height, rect_width, radius;
178 day_view = e_day_view_top_item_get_day_view (top_item);
179 model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view));
181 /* If the event is currently being dragged, don't draw it. It will
182 be drawn in the special drag items. */
183 if (day_view->drag_event_day == E_DAY_VIEW_LONG_EVENT
184 && day_view->drag_event_num == event_num)
185 return;
187 if (!e_day_view_get_long_event_position (day_view, event_num,
188 &start_day, &end_day,
189 &item_x, &item_y,
190 &item_w, &item_h))
191 return;
193 if (!is_array_index_in_bounds (day_view->long_events, event_num))
194 return;
196 event = &g_array_index (day_view->long_events, EDayViewEvent,
197 event_num);
199 if (!is_comp_data_valid (event))
200 return;
202 cr = gdk_cairo_create (drawable);
204 style = gtk_widget_get_style (GTK_WIDGET (day_view));
205 comp = e_cal_component_new ();
206 e_cal_component_set_icalcomponent (
207 comp, icalcomponent_new_clone (event->comp_data->icalcomp));
209 if (gdk_color_parse (
210 e_cal_model_get_color_for_component (
211 e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)),
212 event->comp_data), &bg_color)) {
213 GdkColormap *colormap;
215 colormap = gtk_widget_get_colormap (GTK_WIDGET (day_view));
216 if (gdk_colormap_alloc_color (colormap, &bg_color, TRUE, TRUE)) {
217 red = bg_color.red;
218 green = bg_color.green;
219 blue = bg_color.blue;
220 } else {
221 red = day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND].red;
222 green = day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND].green;
223 blue = day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND].blue;
225 } else {
226 red = day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND].red;
227 green = day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND].green;
228 blue = day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND].blue;
231 /* Fill the background with white to play with transparency */
232 cairo_save (cr);
233 x0 = item_x - x + 4;
234 y0 = item_y + 1 - y;
235 rect_width = item_w - 8;
236 rect_height = item_h - 2;
238 radius = 12;
240 draw_curved_rectangle (cr, x0, y0, rect_width, rect_height, radius);
242 cairo_set_source_rgba (cr, 1, 1, 1, 1.0);
243 cairo_fill_preserve (cr);
245 cairo_restore (cr);
247 /* Draw the border around the event */
249 cairo_save (cr);
250 x0 = item_x - x + 4;
251 y0 = item_y + 1 - y;
252 rect_width = item_w - 8;
253 rect_height = item_h - 2;
255 radius = 12;
257 draw_curved_rectangle (cr, x0, y0, rect_width, rect_height, radius);
259 cairo_set_source_rgb (cr, red/cc, green/cc, blue/cc);
260 cairo_set_line_width (cr, 1.5);
261 cairo_stroke (cr);
262 cairo_restore (cr);
264 /* Fill in with gradient */
266 cairo_save (cr);
268 x0 = item_x - x + 5.5;
269 y0 = item_y + 2.5 - y;
270 rect_width = item_w - 11;
271 rect_height = item_h - 5;
273 radius = 10;
275 draw_curved_rectangle (cr, x0, y0, rect_width, rect_height, radius);
277 pat = cairo_pattern_create_linear (item_x - x + 5.5, item_y + 2.5 - y,
278 item_x - x + 5, item_y - y + item_h + 7.5);
279 cairo_pattern_add_color_stop_rgba (pat, 1, red/cc, green/cc, blue/cc, 0.8);
280 cairo_pattern_add_color_stop_rgba (pat, 0, red/cc, green/cc, blue/cc, 0.4);
281 cairo_set_source (cr, pat);
282 cairo_fill_preserve (cr);
283 cairo_pattern_destroy (pat);
285 cairo_set_source_rgba (cr, red/cc, green/cc, blue/cc, 0);
286 cairo_set_line_width (cr, 0.5);
287 cairo_stroke (cr);
288 cairo_restore (cr);
290 /* When resizing we don't draw the triangles.*/
291 draw_start_triangle = TRUE;
292 draw_end_triangle = TRUE;
293 if (day_view->resize_drag_pos != E_CALENDAR_VIEW_POS_NONE
294 && day_view->resize_event_day == E_DAY_VIEW_LONG_EVENT
295 && day_view->resize_event_num == event_num) {
296 if (day_view->resize_drag_pos == E_CALENDAR_VIEW_POS_LEFT_EDGE)
297 draw_start_triangle = FALSE;
299 if (day_view->resize_drag_pos == E_CALENDAR_VIEW_POS_RIGHT_EDGE)
300 draw_end_triangle = FALSE;
303 /* If the event starts before the first day shown, draw a triangle */
304 if (draw_start_triangle
305 && event->start < day_view->day_starts[start_day]) {
306 day_view_top_item_draw_triangle (
307 top_item, drawable, item_x - x + 4, item_y - y,
308 -E_DAY_VIEW_BAR_WIDTH, item_h, event_num);
311 /* Similar for the event end. */
312 if (draw_end_triangle
313 && event->end > day_view->day_starts[end_day + 1]) {
314 day_view_top_item_draw_triangle (
315 top_item, drawable, item_x + item_w - 4 - x,
316 item_y - y, E_DAY_VIEW_BAR_WIDTH, item_h,
317 event_num);
320 /* If we are editing the event we don't show the icons or the start
321 & end times. */
322 if (day_view->editing_event_day == E_DAY_VIEW_LONG_EVENT
323 && day_view->editing_event_num == event_num) {
324 g_object_unref (comp);
325 cairo_destroy (cr);
326 return;
329 /* Determine the position of the label, so we know where to place the
330 icons. Note that since the top canvas never scrolls we don't need
331 to take the scroll offset into account. It will always be 0. */
332 text_x = event->canvas_item->x1;
334 /* Draw the start & end times, if necessary. */
335 min_end_time_x = item_x + E_DAY_VIEW_LONG_EVENT_X_PAD - x;
337 time_width = e_day_view_get_time_string_width (day_view);
339 gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
341 if (event->start > day_view->day_starts[start_day]) {
342 offset = day_view->first_hour_shown * 60
343 + day_view->first_minute_shown + event->start_minute;
344 hour = offset / 60;
345 minute = offset % 60;
346 /* Calculate the actual hour number to display. For 12-hour
347 format we convert 0-23 to 12-11am/12-11pm. */
348 e_day_view_convert_time_to_display (day_view, hour,
349 &display_hour,
350 &suffix, &suffix_width);
351 if (e_cal_model_get_use_24_hour_format (model)) {
352 g_snprintf (buffer, sizeof (buffer), "%i:%02i",
353 display_hour, minute);
354 } else {
355 g_snprintf (buffer, sizeof (buffer), "%i:%02i%s",
356 display_hour, minute, suffix);
359 cairo_save (cr);
361 cairo_rectangle (cr,
362 item_x - x, item_y - y,
363 item_w - E_DAY_VIEW_LONG_EVENT_BORDER_WIDTH, item_h);
364 cairo_clip (cr);
366 time_x = item_x + E_DAY_VIEW_LONG_EVENT_X_PAD - x;
367 if (display_hour < 10)
368 time_x += day_view->digit_width;
370 layout = gtk_widget_create_pango_layout (GTK_WIDGET (day_view), buffer);
371 cairo_move_to (cr,
372 time_x,
373 item_y + E_DAY_VIEW_LONG_EVENT_BORDER_HEIGHT +
374 E_DAY_VIEW_LONG_EVENT_Y_PAD - y);
375 pango_cairo_show_layout (cr, layout);
376 g_object_unref (layout);
378 cairo_restore (cr);
380 min_end_time_x += time_width
381 + E_DAY_VIEW_LONG_EVENT_TIME_X_PAD;
384 max_icon_x = item_x + item_w - E_DAY_VIEW_LONG_EVENT_X_PAD
385 - E_DAY_VIEW_ICON_WIDTH;
387 if (event->end < day_view->day_starts[end_day + 1]) {
388 offset = day_view->first_hour_shown * 60
389 + day_view->first_minute_shown
390 + event->end_minute;
391 hour = offset / 60;
392 minute = offset % 60;
393 time_x =
394 item_x + item_w - E_DAY_VIEW_LONG_EVENT_X_PAD -
395 time_width - E_DAY_VIEW_LONG_EVENT_TIME_X_PAD - x;
397 if (time_x >= min_end_time_x) {
398 /* Calculate the actual hour number to display. */
399 e_day_view_convert_time_to_display (day_view, hour,
400 &display_hour,
401 &suffix,
402 &suffix_width);
403 if (e_cal_model_get_use_24_hour_format (model)) {
404 g_snprintf (buffer, sizeof (buffer),
405 "%i:%02i", display_hour, minute);
406 } else {
407 g_snprintf (buffer, sizeof (buffer),
408 "%i:%02i%s", display_hour, minute,
409 suffix);
412 if (display_hour < 10)
413 time_x += day_view->digit_width;
415 layout = gtk_widget_create_pango_layout (GTK_WIDGET (day_view), buffer);
416 cairo_move_to (cr,
417 time_x,
418 item_y + E_DAY_VIEW_LONG_EVENT_Y_PAD + 1 - y);
419 pango_cairo_show_layout (cr, layout);
420 g_object_unref (layout);
422 max_icon_x -= time_width + E_DAY_VIEW_LONG_EVENT_TIME_X_PAD;
426 /* Draw the icons. */
427 icon_x_inc = E_DAY_VIEW_ICON_WIDTH + E_DAY_VIEW_ICON_X_PAD;
428 icon_x = text_x - E_DAY_VIEW_LONG_EVENT_ICON_R_PAD
429 - icon_x_inc - x;
430 icon_y = item_y + E_DAY_VIEW_LONG_EVENT_BORDER_HEIGHT
431 + E_DAY_VIEW_ICON_Y_PAD - y;
433 if (icon_x <= max_icon_x && (
434 e_cal_component_has_recurrences (comp) ||
435 e_cal_component_is_instance (comp))) {
436 cairo_save (cr);
437 gdk_cairo_set_source_pixbuf (cr, day_view->recurrence_icon, icon_x, icon_y);
438 cairo_paint (cr);
439 cairo_restore (cr);
441 icon_x -= icon_x_inc;
444 if (icon_x <= max_icon_x && e_cal_component_has_attachments (comp)) {
445 cairo_save (cr);
446 gdk_cairo_set_source_pixbuf (cr, day_view->attach_icon, icon_x, icon_y);
447 cairo_paint (cr);
448 cairo_restore (cr);
450 icon_x -= icon_x_inc;
452 if (icon_x <= max_icon_x && e_cal_component_has_alarms (comp)) {
453 cairo_save (cr);
454 gdk_cairo_set_source_pixbuf (cr, day_view->reminder_icon, icon_x, icon_y);
455 cairo_paint (cr);
456 cairo_restore (cr);
458 icon_x -= icon_x_inc;
461 if (icon_x <= max_icon_x && e_cal_component_has_attendees (comp)) {
462 cairo_save (cr);
463 gdk_cairo_set_source_pixbuf (cr, day_view->meeting_icon, icon_x, icon_y);
464 cairo_paint (cr);
465 cairo_restore (cr);
467 icon_x -= icon_x_inc;
470 /* draw categories icons */
471 e_cal_component_get_categories_list (comp, &categories_list);
472 for (elem = categories_list; elem; elem = elem->next) {
473 gchar *category;
474 const gchar *file;
475 GdkPixbuf *pixbuf;
477 category = (gchar *) elem->data;
478 file = e_categories_get_icon_file_for (category);
479 if (!file)
480 continue;
482 pixbuf = gdk_pixbuf_new_from_file (file, NULL);
483 if (pixbuf == NULL)
484 continue;
486 if (icon_x <= max_icon_x) {
487 gdk_cairo_set_source_pixbuf (cr, pixbuf,
488 icon_x, icon_y);
489 cairo_rectangle (cr,
490 icon_x, icon_y,
491 E_DAY_VIEW_ICON_WIDTH,
492 E_DAY_VIEW_ICON_HEIGHT);
493 cairo_fill (cr);
494 icon_x -= icon_x_inc;
498 e_cal_component_free_categories_list (categories_list);
499 g_object_unref (comp);
500 cairo_destroy (cr);
503 static void
504 day_view_top_item_set_property (GObject *object,
505 guint property_id,
506 const GValue *value,
507 GParamSpec *pspec)
509 switch (property_id) {
510 case PROP_DAY_VIEW:
511 e_day_view_top_item_set_day_view (
512 E_DAY_VIEW_TOP_ITEM (object),
513 g_value_get_object (value));
514 return;
516 case PROP_SHOW_DATES:
517 e_day_view_top_item_set_show_dates (
518 E_DAY_VIEW_TOP_ITEM (object),
519 g_value_get_boolean (value));
520 return;
523 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
526 static void
527 day_view_top_item_get_property (GObject *object,
528 guint property_id,
529 GValue *value,
530 GParamSpec *pspec)
532 switch (property_id) {
533 case PROP_DAY_VIEW:
534 g_value_set_object (
535 value, e_day_view_top_item_get_day_view (
536 E_DAY_VIEW_TOP_ITEM (object)));
537 return;
539 case PROP_SHOW_DATES:
540 g_value_set_boolean (
541 value, e_day_view_top_item_get_show_dates (
542 E_DAY_VIEW_TOP_ITEM (object)));
543 return;
546 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
549 static void
550 day_view_top_item_dispose (GObject *object)
552 EDayViewTopItemPrivate *priv;
554 priv = E_DAY_VIEW_TOP_ITEM_GET_PRIVATE (object);
556 if (priv->day_view != NULL) {
557 g_object_unref (priv->day_view);
558 priv->day_view = NULL;
561 /* Chain up to parent's dispose() method. */
562 G_OBJECT_CLASS (parent_class)->dispose (object);
565 static void
566 day_view_top_item_update (GnomeCanvasItem *item,
567 const cairo_matrix_t *i2c,
568 gint flags)
570 GnomeCanvasItemClass *canvas_item_class;
572 /* Chain up to parent's update() method. */
573 canvas_item_class = GNOME_CANVAS_ITEM_CLASS (parent_class);
574 canvas_item_class->update (item, i2c, flags);
576 /* The item covers the entire canvas area. */
577 item->x1 = 0;
578 item->y1 = 0;
579 item->x2 = INT_MAX;
580 item->y2 = INT_MAX;
583 static void
584 day_view_top_item_draw (GnomeCanvasItem *canvas_item,
585 GdkDrawable *drawable,
586 gint x,
587 gint y,
588 gint width,
589 gint height)
591 EDayViewTopItem *top_item;
592 EDayView *day_view;
593 GtkStyle *style;
594 gchar buffer[128];
595 GtkAllocation allocation;
596 GdkRectangle clip_rect;
597 gint canvas_width, canvas_height, left_edge, day, date_width, date_x;
598 gint item_height, event_num;
599 PangoLayout *layout;
600 cairo_t *cr;
601 GdkColor bg, light, dark;
602 gboolean show_dates;
604 top_item = E_DAY_VIEW_TOP_ITEM (canvas_item);
605 day_view = e_day_view_top_item_get_day_view (top_item);
606 g_return_if_fail (day_view != NULL);
607 show_dates = top_item->priv->show_dates;
609 cr = gdk_cairo_create (drawable);
611 style = gtk_widget_get_style (GTK_WIDGET (day_view));
612 gtk_widget_get_allocation (
613 GTK_WIDGET (canvas_item->canvas), &allocation);
614 canvas_width = allocation.width;
615 canvas_height =
616 (show_dates ? 1 :
617 (MAX (1, day_view->rows_in_top_display) + 1)) *
618 day_view->top_row_height;
619 left_edge = 0;
620 item_height = day_view->top_row_height - E_DAY_VIEW_TOP_CANVAS_Y_GAP;
622 bg = style->bg[GTK_STATE_NORMAL];
623 light = style->light[GTK_STATE_NORMAL];
624 dark = style->dark[GTK_STATE_NORMAL];
626 if (show_dates) {
627 /* Draw the shadow around the dates. */
628 cairo_save (cr);
629 gdk_cairo_set_source_color (cr, &light);
630 cairo_move_to (cr, left_edge - x, 1 - y);
631 cairo_line_to (cr, canvas_width - 2 - x, 1 - y);
632 cairo_move_to (cr, left_edge - x, 2 - y);
633 cairo_line_to (cr, left_edge - x, item_height - 2 - y);
634 cairo_stroke (cr);
635 cairo_restore (cr);
637 cairo_save (cr);
638 gdk_cairo_set_source_color (cr, &dark);
639 cairo_move_to (cr, left_edge - x, item_height - 1 - y);
640 cairo_line_to (cr, canvas_width - 1 - x, item_height - 1 - y);
641 cairo_move_to (cr, canvas_width - 1 - x, 1 - y);
642 cairo_line_to (cr, canvas_width - 1 - x, item_height - 1 - y);
643 cairo_stroke (cr);
644 cairo_restore (cr);
646 /* Draw the background for the dates. */
647 cairo_save (cr);
648 gdk_cairo_set_source_color (cr, &bg);
649 cairo_rectangle (cr, left_edge + 2 - x, 2 - y,
650 canvas_width - left_edge - 3,
651 item_height - 3);
652 cairo_fill (cr);
653 cairo_restore (cr);
656 if (!show_dates) {
657 /* Clear the main area background. */
658 cairo_save (cr);
659 gdk_cairo_set_source_color (cr, &day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS]);
660 cairo_rectangle (cr, left_edge - x, - y,
661 canvas_width - left_edge,
662 canvas_height);
663 cairo_fill (cr);
664 cairo_restore (cr);
666 /* Draw the selection background. */
667 if (gtk_widget_has_focus (GTK_WIDGET (day_view))
668 && day_view->selection_start_day != -1) {
669 gint start_col, end_col, rect_x, rect_y, rect_w, rect_h;
671 start_col = day_view->selection_start_day;
672 end_col = day_view->selection_end_day;
674 if (end_col > start_col
675 || day_view->selection_start_row == -1
676 || day_view->selection_end_row == -1) {
677 rect_x = day_view->day_offsets[start_col];
678 rect_y = 0;
679 rect_w = day_view->day_offsets[end_col + 1] - rect_x;
680 rect_h = canvas_height - 1 - rect_y;
682 cairo_save (cr);
683 gdk_cairo_set_source_color (
684 cr, &day_view->colors
685 [E_DAY_VIEW_COLOR_BG_TOP_CANVAS_SELECTED]);
686 cairo_rectangle (cr, rect_x - x, rect_y - y,
687 rect_w, rect_h);
688 cairo_fill (cr);
689 cairo_restore (cr);
694 if (show_dates) {
695 /* Draw the date. Set a clipping rectangle so we don't draw over the
696 next day. */
697 for (day = 0; day < day_view->days_shown; day++) {
698 e_day_view_top_item_get_day_label (day_view, day, buffer, sizeof (buffer));
699 clip_rect.x = day_view->day_offsets[day] - x;
700 clip_rect.y = 2 - y;
701 if (day_view->days_shown == 1) {
702 gtk_widget_get_allocation (
703 day_view->top_canvas, &allocation);
704 clip_rect.width = allocation.width - day_view->day_offsets[day];
705 } else
706 clip_rect.width = day_view->day_widths[day];
707 clip_rect.height = item_height - 2;
709 cairo_save (cr);
711 gdk_cairo_rectangle (cr, &clip_rect);
712 cairo_clip (cr);
714 layout = gtk_widget_create_pango_layout (GTK_WIDGET (day_view), buffer);
715 pango_layout_get_pixel_size (layout, &date_width, NULL);
716 date_x = day_view->day_offsets[day] + (clip_rect.width - date_width) / 2;
718 gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
719 cairo_move_to (cr, date_x - x, 3 - y);
720 pango_cairo_show_layout (cr, layout);
722 g_object_unref (layout);
723 cairo_restore (cr);
725 /* Draw the lines down the left and right of the date cols. */
726 if (day != 0) {
727 cairo_save (cr);
728 gdk_cairo_set_source_color (cr, &light);
729 cairo_move_to (cr, day_view->day_offsets[day] - x,
730 4 - y);
731 cairo_line_to (cr, day_view->day_offsets[day] - x,
732 item_height - 4 - y);
733 cairo_stroke (cr);
734 gdk_cairo_set_source_color (cr, &dark);
735 cairo_move_to (cr, day_view->day_offsets[day] - 1 - x,
736 4 - y);
737 cairo_line_to (cr, day_view->day_offsets[day] - 1 - x,
738 item_height - 4 - y);
739 cairo_stroke (cr);
740 cairo_restore (cr);
743 /* Draw the lines between each column. */
744 if (day != 0) {
745 cairo_save (cr);
746 gdk_cairo_set_source_color (
747 cr, &day_view->colors
748 [E_DAY_VIEW_COLOR_BG_TOP_CANVAS_GRID]);
749 cairo_move_to (cr, day_view->day_offsets[day] - x,
750 item_height - y);
751 cairo_line_to (cr, day_view->day_offsets[day] - x,
752 canvas_height - y);
753 cairo_stroke (cr);
754 cairo_restore (cr);
759 if (!show_dates) {
760 /* Draw the long events. */
761 for (event_num = 0; event_num < day_view->long_events->len; event_num++) {
762 day_view_top_item_draw_long_event (
763 top_item, event_num, drawable,
764 x, y, width, height);
768 cairo_destroy (cr);
771 static GnomeCanvasItem *
772 day_view_top_item_point (GnomeCanvasItem *item,
773 gdouble x,
774 gdouble y,
775 gint cx,
776 gint cy)
778 return item;
781 static void
782 day_view_top_item_class_init (EDayViewTopItemClass *class)
784 GObjectClass *object_class;
785 GnomeCanvasItemClass *item_class;
787 parent_class = g_type_class_peek_parent (class);
788 g_type_class_add_private (class, sizeof (EDayViewTopItemPrivate));
790 object_class = G_OBJECT_CLASS (class);
791 object_class->set_property = day_view_top_item_set_property;
792 object_class->get_property = day_view_top_item_get_property;
793 object_class->dispose = day_view_top_item_dispose;
795 item_class = GNOME_CANVAS_ITEM_CLASS (class);
796 item_class->update = day_view_top_item_update;
797 item_class->draw = day_view_top_item_draw;
798 item_class->point = day_view_top_item_point;
800 g_object_class_install_property (
801 object_class,
802 PROP_DAY_VIEW,
803 g_param_spec_object (
804 "day_view",
805 "Day View",
806 NULL,
807 E_TYPE_DAY_VIEW,
808 G_PARAM_READWRITE));
810 g_object_class_install_property (
811 object_class,
812 PROP_SHOW_DATES,
813 g_param_spec_boolean (
814 "show_dates",
815 "Show Dates",
816 NULL,
817 TRUE,
818 G_PARAM_READWRITE));
821 static void
822 day_view_top_item_init (EDayViewTopItem *top_item)
824 top_item->priv = E_DAY_VIEW_TOP_ITEM_GET_PRIVATE (top_item);
827 GType
828 e_day_view_top_item_get_type (void)
830 static GType type = 0;
832 if (G_UNLIKELY (type == 0)) {
833 const GTypeInfo type_info = {
834 sizeof (EDayViewTopItemClass),
835 (GBaseInitFunc) NULL,
836 (GBaseFinalizeFunc) NULL,
837 (GClassInitFunc) day_view_top_item_class_init,
838 (GClassFinalizeFunc) NULL,
839 NULL, /* class_data */
840 sizeof (EDayViewTopItem),
841 0, /* n_preallocs */
842 (GInstanceInitFunc) day_view_top_item_init,
843 NULL /* value_table */
846 type = g_type_register_static (
847 GNOME_TYPE_CANVAS_ITEM, "EDayViewTopItem",
848 &type_info, 0);
851 return type;
854 void
855 e_day_view_top_item_get_day_label (EDayView *day_view, gint day,
856 gchar *buffer, gint buffer_len)
858 struct icaltimetype day_start_tt;
859 struct tm day_start = { 0 };
860 const gchar *format;
862 day_start_tt = icaltime_from_timet_with_zone (day_view->day_starts[day],
863 FALSE,
864 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view)));
865 day_start.tm_year = day_start_tt.year - 1900;
866 day_start.tm_mon = day_start_tt.month - 1;
867 day_start.tm_mday = day_start_tt.day;
868 day_start.tm_isdst = -1;
870 day_start.tm_wday = time_day_of_week (day_start_tt.day,
871 day_start_tt.month - 1,
872 day_start_tt.year);
874 if (day_view->date_format == E_DAY_VIEW_DATE_FULL)
875 /* strftime format %A = full weekday name, %d = day of month,
876 %B = full month name. Don't use any other specifiers. */
877 format = _("%A %d %B");
878 else if (day_view->date_format == E_DAY_VIEW_DATE_ABBREVIATED)
879 /* strftime format %a = abbreviated weekday name, %d = day of month,
880 %b = abbreviated month name. Don't use any other specifiers. */
881 format = _("%a %d %b");
882 else if (day_view->date_format == E_DAY_VIEW_DATE_NO_WEEKDAY)
883 /* strftime format %d = day of month, %b = abbreviated month name.
884 Don't use any other specifiers. */
885 format = _("%d %b");
886 else
887 format = "%d";
889 e_utf8_strftime (buffer, buffer_len, format, &day_start);
892 EDayView *
893 e_day_view_top_item_get_day_view (EDayViewTopItem *top_item)
895 g_return_val_if_fail (E_IS_DAY_VIEW_TOP_ITEM (top_item), NULL);
897 return top_item->priv->day_view;
900 void
901 e_day_view_top_item_set_day_view (EDayViewTopItem *top_item,
902 EDayView *day_view)
904 g_return_if_fail (E_IS_DAY_VIEW_TOP_ITEM (top_item));
905 g_return_if_fail (E_IS_DAY_VIEW (day_view));
907 if (top_item->priv->day_view != NULL)
908 g_object_unref (top_item->priv->day_view);
910 top_item->priv->day_view = g_object_ref (day_view);
912 g_object_notify (G_OBJECT (top_item), "day-view");
915 gboolean
916 e_day_view_top_item_get_show_dates (EDayViewTopItem *top_item)
918 g_return_val_if_fail (E_IS_DAY_VIEW_TOP_ITEM (top_item), FALSE);
920 return top_item->priv->show_dates;
923 void
924 e_day_view_top_item_set_show_dates (EDayViewTopItem *top_item,
925 gboolean show_dates)
927 g_return_if_fail (E_IS_DAY_VIEW_TOP_ITEM (top_item));
929 top_item->priv->show_dates = show_dates;
931 g_object_notify (G_OBJECT (top_item), "show-dates");