No issues found
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.
6 *
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.
11 *
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/>
14 *
15 *
16 * Authors:
17 * Damon Chaplin <damon@ximian.com>
18 *
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20 *
21 */
22
23 /*
24 * EDayViewTopItem - displays the top part of the Day/Work Week calendar view.
25 */
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30
31 #include <glib/gi18n.h>
32 #include "e-util/e-categories-config.h"
33
34 #include "e-calendar-view.h"
35 #include "e-day-view-top-item.h"
36
37 #define E_DAY_VIEW_TOP_ITEM_GET_PRIVATE(obj) \
38 (G_TYPE_INSTANCE_GET_PRIVATE \
39 ((obj), E_TYPE_DAY_VIEW_TOP_ITEM, EDayViewTopItemPrivate))
40
41 struct _EDayViewTopItemPrivate {
42 /* The parent EDayView widget. */
43 EDayView *day_view;
44
45 /* Show dates or events. */
46 gboolean show_dates;
47 };
48
49 enum {
50 PROP_0,
51 PROP_DAY_VIEW,
52 PROP_SHOW_DATES
53 };
54
55 G_DEFINE_TYPE (
56 EDayViewTopItem,
57 e_day_view_top_item,
58 GNOME_TYPE_CANVAS_ITEM)
59
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 cairo_t *cr,
65 gint x,
66 gint y,
67 gint w,
68 gint h,
69 gint event_num)
70 {
71 EDayView *day_view;
72 EDayViewEvent *event;
73 GdkColor bg_color;
74 GdkPoint points[3];
75 gint c1, c2;
76
77 day_view = e_day_view_top_item_get_day_view (top_item);
78
79 points[0].x = x;
80 points[0].y = y;
81 points[1].x = x + w;
82 points[1].y = y + (h / 2);
83 points[2].x = x;
84 points[2].y = y + h - 1;
85
86 /* If the height is odd we can use the same central point for both
87 * lines. If it is even we use different end-points. */
88 c1 = c2 = y + (h / 2);
89 if (h % 2 == 0)
90 c1--;
91
92 if (!is_array_index_in_bounds (day_view->long_events, event_num))
93 return;
94
95 event = &g_array_index (day_view->long_events, EDayViewEvent,
96 event_num);
97
98 if (!is_comp_data_valid (event))
99 return;
100
101 cairo_save (cr);
102 /* Fill it in. */
103 if (gdk_color_parse (
104 e_cal_model_get_color_for_component (
105 e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)),
106 event->comp_data), &bg_color)) {
107 gdk_cairo_set_source_color (cr, &bg_color);
108 } else {
109 gdk_cairo_set_source_color (
110 cr, &day_view->colors
111 [E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND]);
112 }
113
114 cairo_move_to (cr, points[0].x, points[0].y);
115 cairo_line_to (cr, points[1].x, points[1].y);
116 cairo_line_to (cr, points[2].x, points[2].y);
117 cairo_line_to (cr, points[0].x, points[0].y);
118 cairo_fill (cr);
119 cairo_restore (cr);
120
121 cairo_save (cr);
122 gdk_cairo_set_source_color (
123 cr, &day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BORDER]);
124 cairo_move_to (cr, x, y);
125 cairo_line_to (cr, x + w, c1);
126 cairo_move_to (cr, x, y + h - 1);
127 cairo_line_to (cr, x + w, c2);
128 cairo_stroke (cr);
129 cairo_restore (cr);
130 }
131
132 /* This draws one event in the top canvas. */
133 static void
134 day_view_top_item_draw_long_event (EDayViewTopItem *top_item,
135 gint event_num,
136 cairo_t *cr,
137 gint x,
138 gint y,
139 gint width,
140 gint height)
141 {
142 EDayView *day_view;
143 EDayViewEvent *event;
144 GtkStyle *style;
145 gint start_day, end_day;
146 gint item_x, item_y, item_w, item_h;
147 gint text_x, icon_x, icon_y, icon_x_inc;
148 ECalModel *model;
149 ECalComponent *comp;
150 gchar buffer[16];
151 gint hour, display_hour, minute, offset, time_width, time_x;
152 gint min_end_time_x, suffix_width, max_icon_x;
153 const gchar *suffix;
154 gboolean draw_start_triangle, draw_end_triangle;
155 GSList *categories_list, *elem;
156 PangoLayout *layout;
157 GdkColor bg_color;
158 cairo_pattern_t *pat;
159 guint16 red, green, blue;
160 gdouble cc = 65535.0;
161 gdouble x0, y0, rect_height, rect_width, radius;
162
163 day_view = e_day_view_top_item_get_day_view (top_item);
164 model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view));
165
166 /* If the event is currently being dragged, don't draw it. It will
167 * be drawn in the special drag items. */
168 if (day_view->drag_event_day == E_DAY_VIEW_LONG_EVENT
169 && day_view->drag_event_num == event_num)
170 return;
171
172 if (!e_day_view_get_long_event_position (day_view, event_num,
173 &start_day, &end_day,
174 &item_x, &item_y,
175 &item_w, &item_h))
176 return;
177
178 if (!is_array_index_in_bounds (day_view->long_events, event_num))
179 return;
180
181 event = &g_array_index (day_view->long_events, EDayViewEvent,
182 event_num);
183
184 if (!is_comp_data_valid (event))
185 return;
186
187 style = gtk_widget_get_style (GTK_WIDGET (day_view));
188 comp = e_cal_component_new ();
189 e_cal_component_set_icalcomponent (
190 comp, icalcomponent_new_clone (event->comp_data->icalcomp));
191
192 if (gdk_color_parse (
193 e_cal_model_get_color_for_component (
194 e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)),
195 event->comp_data), &bg_color)) {
196 red = bg_color.red;
197 green = bg_color.green;
198 blue = bg_color.blue;
199 } else {
200 red = day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND].red;
201 green = day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND].green;
202 blue = day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND].blue;
203 }
204
205 /* Fill the background with white to play with transparency */
206 cairo_save (cr);
207 x0 = item_x - x + 4;
208 y0 = item_y + 1 - y;
209 rect_width = item_w - 8;
210 rect_height = item_h - 2;
211
212 radius = 12;
213
214 draw_curved_rectangle (cr, x0, y0, rect_width, rect_height, radius);
215
216 cairo_set_source_rgba (cr, 1, 1, 1, 1.0);
217 cairo_fill_preserve (cr);
218
219 cairo_restore (cr);
220
221 /* Draw the border around the event */
222
223 cairo_save (cr);
224 x0 = item_x - x + 4;
225 y0 = item_y + 1 - y;
226 rect_width = item_w - 8;
227 rect_height = item_h - 2;
228
229 radius = 12;
230
231 draw_curved_rectangle (cr, x0, y0, rect_width, rect_height, radius);
232
233 cairo_set_source_rgb (cr, red / cc, green / cc, blue / cc);
234 cairo_set_line_width (cr, 1.5);
235 cairo_stroke (cr);
236 cairo_restore (cr);
237
238 /* Fill in with gradient */
239
240 cairo_save (cr);
241
242 x0 = item_x - x + 5.5;
243 y0 = item_y + 2.5 - y;
244 rect_width = item_w - 11;
245 rect_height = item_h - 5;
246
247 radius = 10;
248
249 draw_curved_rectangle (cr, x0, y0, rect_width, rect_height, radius);
250
251 pat = cairo_pattern_create_linear (
252 item_x - x + 5.5, item_y + 2.5 - y,
253 item_x - x + 5, item_y - y + item_h + 7.5);
254 cairo_pattern_add_color_stop_rgba (pat, 1, red / cc, green / cc, blue / cc, 0.8);
255 cairo_pattern_add_color_stop_rgba (pat, 0, red / cc, green / cc, blue / cc, 0.4);
256 cairo_set_source (cr, pat);
257 cairo_fill_preserve (cr);
258 cairo_pattern_destroy (pat);
259
260 cairo_set_source_rgba (cr, red / cc, green / cc, blue / cc, 0);
261 cairo_set_line_width (cr, 0.5);
262 cairo_stroke (cr);
263 cairo_restore (cr);
264
265 /* When resizing we don't draw the triangles.*/
266 draw_start_triangle = TRUE;
267 draw_end_triangle = TRUE;
268 if (day_view->resize_drag_pos != E_CALENDAR_VIEW_POS_NONE
269 && day_view->resize_event_day == E_DAY_VIEW_LONG_EVENT
270 && day_view->resize_event_num == event_num) {
271 if (day_view->resize_drag_pos == E_CALENDAR_VIEW_POS_LEFT_EDGE)
272 draw_start_triangle = FALSE;
273
274 if (day_view->resize_drag_pos == E_CALENDAR_VIEW_POS_RIGHT_EDGE)
275 draw_end_triangle = FALSE;
276 }
277
278 /* If the event starts before the first day shown, draw a triangle */
279 if (draw_start_triangle
280 && event->start < day_view->day_starts[start_day]) {
281 day_view_top_item_draw_triangle (
282 top_item, cr, item_x - x + 4, item_y - y,
283 -E_DAY_VIEW_BAR_WIDTH, item_h, event_num);
284 }
285
286 /* Similar for the event end. */
287 if (draw_end_triangle
288 && event->end > day_view->day_starts[end_day + 1]) {
289 day_view_top_item_draw_triangle (
290 top_item, cr, item_x + item_w - 4 - x,
291 item_y - y, E_DAY_VIEW_BAR_WIDTH, item_h,
292 event_num);
293 }
294
295 /* If we are editing the event we don't show the icons or the start
296 * & end times. */
297 if (day_view->editing_event_day == E_DAY_VIEW_LONG_EVENT
298 && day_view->editing_event_num == event_num) {
299 g_object_unref (comp);
300 return;
301 }
302
303 /* Determine the position of the label, so we know where to place the
304 * icons. Note that since the top canvas never scrolls we don't need
305 * to take the scroll offset into account. It will always be 0. */
306 text_x = event->canvas_item->x1;
307
308 /* Draw the start & end times, if necessary. */
309 min_end_time_x = item_x + E_DAY_VIEW_LONG_EVENT_X_PAD - x;
310
311 time_width = e_day_view_get_time_string_width (day_view);
312
313 gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
314
315 if (event->start > day_view->day_starts[start_day]) {
316 offset = day_view->first_hour_shown * 60
317 + day_view->first_minute_shown + event->start_minute;
318 hour = offset / 60;
319 minute = offset % 60;
320 /* Calculate the actual hour number to display. For 12-hour
321 * format we convert 0-23 to 12-11am/12-11pm. */
322 e_day_view_convert_time_to_display (
323 day_view, hour,
324 &display_hour,
325 &suffix, &suffix_width);
326 if (e_cal_model_get_use_24_hour_format (model)) {
327 g_snprintf (
328 buffer, sizeof (buffer), "%i:%02i",
329 display_hour, minute);
330 } else {
331 g_snprintf (
332 buffer, sizeof (buffer), "%i:%02i%s",
333 display_hour, minute, suffix);
334 }
335
336 cairo_save (cr);
337
338 cairo_rectangle (
339 cr,
340 item_x - x, item_y - y,
341 item_w - E_DAY_VIEW_LONG_EVENT_BORDER_WIDTH, item_h);
342 cairo_clip (cr);
343
344 time_x = item_x + E_DAY_VIEW_LONG_EVENT_X_PAD - x;
345 if (display_hour < 10)
346 time_x += day_view->digit_width;
347
348 layout = gtk_widget_create_pango_layout (GTK_WIDGET (day_view), buffer);
349 cairo_move_to (
350 cr,
351 time_x,
352 item_y + E_DAY_VIEW_LONG_EVENT_BORDER_HEIGHT +
353 E_DAY_VIEW_LONG_EVENT_Y_PAD - y);
354 pango_cairo_show_layout (cr, layout);
355 g_object_unref (layout);
356
357 cairo_restore (cr);
358
359 min_end_time_x += time_width
360 + E_DAY_VIEW_LONG_EVENT_TIME_X_PAD;
361 }
362
363 max_icon_x = item_x + item_w - E_DAY_VIEW_LONG_EVENT_X_PAD
364 - E_DAY_VIEW_ICON_WIDTH;
365
366 if (event->end < day_view->day_starts[end_day + 1]) {
367 offset = day_view->first_hour_shown * 60
368 + day_view->first_minute_shown
369 + event->end_minute;
370 hour = offset / 60;
371 minute = offset % 60;
372 time_x =
373 item_x + item_w - E_DAY_VIEW_LONG_EVENT_X_PAD -
374 time_width - E_DAY_VIEW_LONG_EVENT_TIME_X_PAD - x;
375
376 if (time_x >= min_end_time_x) {
377 /* Calculate the actual hour number to display. */
378 e_day_view_convert_time_to_display (
379 day_view, hour,
380 &display_hour,
381 &suffix,
382 &suffix_width);
383 if (e_cal_model_get_use_24_hour_format (model)) {
384 g_snprintf (
385 buffer, sizeof (buffer),
386 "%i:%02i", display_hour, minute);
387 } else {
388 g_snprintf (
389 buffer, sizeof (buffer),
390 "%i:%02i%s", display_hour, minute,
391 suffix);
392 }
393
394 if (display_hour < 10)
395 time_x += day_view->digit_width;
396
397 layout = gtk_widget_create_pango_layout (GTK_WIDGET (day_view), buffer);
398 cairo_move_to (
399 cr,
400 time_x,
401 item_y + E_DAY_VIEW_LONG_EVENT_Y_PAD + 1 - y);
402 pango_cairo_show_layout (cr, layout);
403 g_object_unref (layout);
404
405 max_icon_x -= time_width + E_DAY_VIEW_LONG_EVENT_TIME_X_PAD;
406 }
407 }
408
409 /* Draw the icons. */
410 icon_x_inc = E_DAY_VIEW_ICON_WIDTH + E_DAY_VIEW_ICON_X_PAD;
411 icon_x = text_x - E_DAY_VIEW_LONG_EVENT_ICON_R_PAD
412 - icon_x_inc - x;
413 icon_y = item_y + E_DAY_VIEW_LONG_EVENT_BORDER_HEIGHT
414 + E_DAY_VIEW_ICON_Y_PAD - y;
415
416 if (icon_x <= max_icon_x && (
417 e_cal_component_has_recurrences (comp) ||
418 e_cal_component_is_instance (comp))) {
419 cairo_save (cr);
420 gdk_cairo_set_source_pixbuf (cr, day_view->recurrence_icon, icon_x, icon_y);
421 cairo_paint (cr);
422 cairo_restore (cr);
423
424 icon_x -= icon_x_inc;
425 }
426
427 if (icon_x <= max_icon_x && e_cal_component_has_attachments (comp)) {
428 cairo_save (cr);
429 gdk_cairo_set_source_pixbuf (cr, day_view->attach_icon, icon_x, icon_y);
430 cairo_paint (cr);
431 cairo_restore (cr);
432
433 icon_x -= icon_x_inc;
434 }
435 if (icon_x <= max_icon_x && e_cal_component_has_alarms (comp)) {
436 cairo_save (cr);
437 gdk_cairo_set_source_pixbuf (cr, day_view->reminder_icon, icon_x, icon_y);
438 cairo_paint (cr);
439 cairo_restore (cr);
440
441 icon_x -= icon_x_inc;
442 }
443
444 if (icon_x <= max_icon_x && e_cal_component_has_attendees (comp)) {
445 cairo_save (cr);
446 gdk_cairo_set_source_pixbuf (cr, day_view->meeting_icon, icon_x, icon_y);
447 cairo_paint (cr);
448 cairo_restore (cr);
449
450 icon_x -= icon_x_inc;
451 }
452
453 /* draw categories icons */
454 e_cal_component_get_categories_list (comp, &categories_list);
455 for (elem = categories_list; elem; elem = elem->next) {
456 gchar *category;
457 const gchar *file;
458 GdkPixbuf *pixbuf;
459
460 category = (gchar *) elem->data;
461 file = e_categories_get_icon_file_for (category);
462 if (!file)
463 continue;
464
465 pixbuf = gdk_pixbuf_new_from_file (file, NULL);
466 if (pixbuf == NULL)
467 continue;
468
469 if (icon_x <= max_icon_x) {
470 gdk_cairo_set_source_pixbuf (
471 cr, pixbuf,
472 icon_x, icon_y);
473 cairo_rectangle (
474 cr,
475 icon_x, icon_y,
476 E_DAY_VIEW_ICON_WIDTH,
477 E_DAY_VIEW_ICON_HEIGHT);
478 cairo_fill (cr);
479 icon_x -= icon_x_inc;
480 }
481 }
482
483 e_cal_component_free_categories_list (categories_list);
484 g_object_unref (comp);
485 }
486
487 static void
488 day_view_top_item_set_property (GObject *object,
489 guint property_id,
490 const GValue *value,
491 GParamSpec *pspec)
492 {
493 switch (property_id) {
494 case PROP_DAY_VIEW:
495 e_day_view_top_item_set_day_view (
496 E_DAY_VIEW_TOP_ITEM (object),
497 g_value_get_object (value));
498 return;
499
500 case PROP_SHOW_DATES:
501 e_day_view_top_item_set_show_dates (
502 E_DAY_VIEW_TOP_ITEM (object),
503 g_value_get_boolean (value));
504 return;
505 }
506
507 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
508 }
509
510 static void
511 day_view_top_item_get_property (GObject *object,
512 guint property_id,
513 GValue *value,
514 GParamSpec *pspec)
515 {
516 switch (property_id) {
517 case PROP_DAY_VIEW:
518 g_value_set_object (
519 value, e_day_view_top_item_get_day_view (
520 E_DAY_VIEW_TOP_ITEM (object)));
521 return;
522
523 case PROP_SHOW_DATES:
524 g_value_set_boolean (
525 value, e_day_view_top_item_get_show_dates (
526 E_DAY_VIEW_TOP_ITEM (object)));
527 return;
528 }
529
530 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
531 }
532
533 static void
534 day_view_top_item_dispose (GObject *object)
535 {
536 EDayViewTopItemPrivate *priv;
537
538 priv = E_DAY_VIEW_TOP_ITEM_GET_PRIVATE (object);
539
540 if (priv->day_view != NULL) {
541 g_object_unref (priv->day_view);
542 priv->day_view = NULL;
543 }
544
545 /* Chain up to parent's dispose() method. */
546 G_OBJECT_CLASS (e_day_view_top_item_parent_class)->dispose (object);
547 }
548
549 static void
550 day_view_top_item_update (GnomeCanvasItem *item,
551 const cairo_matrix_t *i2c,
552 gint flags)
553 {
554 GnomeCanvasItemClass *canvas_item_class;
555
556 /* Chain up to parent's update() method. */
557 canvas_item_class =
558 GNOME_CANVAS_ITEM_CLASS (e_day_view_top_item_parent_class);
559 canvas_item_class->update (item, i2c, flags);
560
561 /* The item covers the entire canvas area. */
562 item->x1 = 0;
563 item->y1 = 0;
564 item->x2 = INT_MAX;
565 item->y2 = INT_MAX;
566 }
567
568 static void
569 day_view_top_item_draw (GnomeCanvasItem *canvas_item,
570 cairo_t *cr,
571 gint x,
572 gint y,
573 gint width,
574 gint height)
575 {
576 EDayViewTopItem *top_item;
577 EDayView *day_view;
578 GtkStyle *style;
579 gchar buffer[128];
580 GtkAllocation allocation;
581 GdkRectangle clip_rect;
582 gint canvas_width, canvas_height, left_edge, day, date_width, date_x;
583 gint item_height, event_num;
584 PangoLayout *layout;
585 GdkColor bg, light, dark;
586 gboolean show_dates;
587
588 top_item = E_DAY_VIEW_TOP_ITEM (canvas_item);
589 day_view = e_day_view_top_item_get_day_view (top_item);
590 g_return_if_fail (day_view != NULL);
591 show_dates = top_item->priv->show_dates;
592
593 style = gtk_widget_get_style (GTK_WIDGET (day_view));
594 gtk_widget_get_allocation (
595 GTK_WIDGET (canvas_item->canvas), &allocation);
596 canvas_width = allocation.width;
597 canvas_height =
598 (show_dates ? 1 :
599 (MAX (1, day_view->rows_in_top_display) + 1)) *
600 day_view->top_row_height;
601 left_edge = 0;
602 item_height = day_view->top_row_height - E_DAY_VIEW_TOP_CANVAS_Y_GAP;
603
604 bg = style->bg[GTK_STATE_NORMAL];
605 light = style->light[GTK_STATE_NORMAL];
606 dark = style->dark[GTK_STATE_NORMAL];
607
608 if (show_dates) {
609 /* Draw the shadow around the dates. */
610 cairo_save (cr);
611 gdk_cairo_set_source_color (cr, &light);
612 cairo_move_to (cr, left_edge - x, 1 - y);
613 cairo_line_to (cr, canvas_width - 2 - x, 1 - y);
614 cairo_move_to (cr, left_edge - x, 2 - y);
615 cairo_line_to (cr, left_edge - x, item_height - 2 - y);
616 cairo_stroke (cr);
617 cairo_restore (cr);
618
619 cairo_save (cr);
620 gdk_cairo_set_source_color (cr, &dark);
621 cairo_move_to (cr, left_edge - x, item_height - 1 - y);
622 cairo_line_to (cr, canvas_width - 1 - x, item_height - 1 - y);
623 cairo_move_to (cr, canvas_width - 1 - x, 1 - y);
624 cairo_line_to (cr, canvas_width - 1 - x, item_height - 1 - y);
625 cairo_stroke (cr);
626 cairo_restore (cr);
627
628 /* Draw the background for the dates. */
629 cairo_save (cr);
630 gdk_cairo_set_source_color (cr, &bg);
631 cairo_rectangle (
632 cr, left_edge + 2 - x, 2 - y,
633 canvas_width - left_edge - 3,
634 item_height - 3);
635 cairo_fill (cr);
636 cairo_restore (cr);
637 }
638
639 if (!show_dates) {
640 /* Clear the main area background. */
641 cairo_save (cr);
642 gdk_cairo_set_source_color (
643 cr, &day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS]);
644 cairo_rectangle (
645 cr, left_edge - x, - y,
646 canvas_width - left_edge,
647 canvas_height);
648 cairo_fill (cr);
649 cairo_restore (cr);
650
651 /* Draw the selection background. */
652 if (gtk_widget_has_focus (GTK_WIDGET (day_view))
653 && day_view->selection_start_day != -1) {
654 gint start_col, end_col, rect_x, rect_y, rect_w, rect_h;
655
656 start_col = day_view->selection_start_day;
657 end_col = day_view->selection_end_day;
658
659 if (end_col > start_col
660 || day_view->selection_start_row == -1
661 || day_view->selection_end_row == -1) {
662 rect_x = day_view->day_offsets[start_col];
663 rect_y = 0;
664 rect_w = day_view->day_offsets[end_col + 1] - rect_x;
665 rect_h = canvas_height - 1 - rect_y;
666
667 cairo_save (cr);
668 gdk_cairo_set_source_color (
669 cr, &day_view->colors
670 [E_DAY_VIEW_COLOR_BG_TOP_CANVAS_SELECTED]);
671 cairo_rectangle (
672 cr, rect_x - x, rect_y - y,
673 rect_w, rect_h);
674 cairo_fill (cr);
675 cairo_restore (cr);
676 }
677 }
678 }
679
680 if (show_dates) {
681 /* Draw the date. Set a clipping rectangle
682 * so we don't draw over the next day. */
683 for (day = 0; day < day_view->days_shown; day++) {
684 e_day_view_top_item_get_day_label (
685 day_view, day, buffer, sizeof (buffer));
686 clip_rect.x = day_view->day_offsets[day] - x;
687 clip_rect.y = 2 - y;
688 if (day_view->days_shown == 1) {
689 gtk_widget_get_allocation (
690 day_view->top_canvas, &allocation);
691 clip_rect.width =
692 allocation.width -
693 day_view->day_offsets[day];
694 } else
695 clip_rect.width = day_view->day_widths[day];
696 clip_rect.height = item_height - 2;
697
698 cairo_save (cr);
699
700 gdk_cairo_rectangle (cr, &clip_rect);
701 cairo_clip (cr);
702
703 layout = gtk_widget_create_pango_layout (
704 GTK_WIDGET (day_view), buffer);
705 pango_layout_get_pixel_size (layout, &date_width, NULL);
706 date_x = day_view->day_offsets[day] +
707 (clip_rect.width - date_width) / 2;
708
709 gdk_cairo_set_source_color (
710 cr, &style->fg[GTK_STATE_NORMAL]);
711 cairo_move_to (cr, date_x - x, 3 - y);
712 pango_cairo_show_layout (cr, layout);
713
714 g_object_unref (layout);
715 cairo_restore (cr);
716
717 /* Draw the lines down the left and right of the date cols. */
718 if (day != 0) {
719 cairo_save (cr);
720 gdk_cairo_set_source_color (cr, &light);
721 cairo_move_to (
722 cr, day_view->day_offsets[day] - x,
723 4 - y);
724 cairo_line_to (
725 cr, day_view->day_offsets[day] - x,
726 item_height - 4 - y);
727 cairo_stroke (cr);
728 gdk_cairo_set_source_color (cr, &dark);
729 cairo_move_to (
730 cr, day_view->day_offsets[day] - 1 - x,
731 4 - y);
732 cairo_line_to (
733 cr, day_view->day_offsets[day] - 1 - x,
734 item_height - 4 - y);
735 cairo_stroke (cr);
736 cairo_restore (cr);
737 }
738
739 /* Draw the lines between each column. */
740 if (day != 0) {
741 cairo_save (cr);
742 gdk_cairo_set_source_color (
743 cr, &day_view->colors
744 [E_DAY_VIEW_COLOR_BG_TOP_CANVAS_GRID]);
745 cairo_move_to (
746 cr, day_view->day_offsets[day] - x,
747 item_height - y);
748 cairo_line_to (
749 cr, day_view->day_offsets[day] - x,
750 canvas_height - y);
751 cairo_stroke (cr);
752 cairo_restore (cr);
753 }
754 }
755 }
756
757 if (!show_dates) {
758 /* Draw the long events. */
759 for (event_num = 0; event_num < day_view->long_events->len; event_num++) {
760 day_view_top_item_draw_long_event (
761 top_item, event_num, cr,
762 x, y, width, height);
763 }
764 }
765 }
766
767 static GnomeCanvasItem *
768 day_view_top_item_point (GnomeCanvasItem *item,
769 gdouble x,
770 gdouble y,
771 gint cx,
772 gint cy)
773 {
774 return item;
775 }
776
777 static void
778 e_day_view_top_item_class_init (EDayViewTopItemClass *class)
779 {
780 GObjectClass *object_class;
781 GnomeCanvasItemClass *item_class;
782
783 g_type_class_add_private (class, sizeof (EDayViewTopItemPrivate));
784
785 object_class = G_OBJECT_CLASS (class);
786 object_class->set_property = day_view_top_item_set_property;
787 object_class->get_property = day_view_top_item_get_property;
788 object_class->dispose = day_view_top_item_dispose;
789
790 item_class = GNOME_CANVAS_ITEM_CLASS (class);
791 item_class->update = day_view_top_item_update;
792 item_class->draw = day_view_top_item_draw;
793 item_class->point = day_view_top_item_point;
794
795 g_object_class_install_property (
796 object_class,
797 PROP_DAY_VIEW,
798 g_param_spec_object (
799 "day_view",
800 "Day View",
801 NULL,
802 E_TYPE_DAY_VIEW,
803 G_PARAM_READWRITE));
804
805 g_object_class_install_property (
806 object_class,
807 PROP_SHOW_DATES,
808 g_param_spec_boolean (
809 "show_dates",
810 "Show Dates",
811 NULL,
812 TRUE,
813 G_PARAM_READWRITE));
814 }
815
816 static void
817 e_day_view_top_item_init (EDayViewTopItem *top_item)
818 {
819 top_item->priv = E_DAY_VIEW_TOP_ITEM_GET_PRIVATE (top_item);
820 }
821
822 void
823 e_day_view_top_item_get_day_label (EDayView *day_view,
824 gint day,
825 gchar *buffer,
826 gint buffer_len)
827 {
828 ECalendarView *view;
829 struct icaltimetype day_start_tt;
830 const icaltimezone *zone;
831 struct tm day_start = { 0 };
832 const gchar *format;
833
834 view = E_CALENDAR_VIEW (day_view);
835 zone = e_calendar_view_get_timezone (view);
836
837 day_start_tt = icaltime_from_timet_with_zone (
838 day_view->day_starts[day], FALSE, zone);
839 day_start.tm_year = day_start_tt.year - 1900;
840 day_start.tm_mon = day_start_tt.month - 1;
841 day_start.tm_mday = day_start_tt.day;
842 day_start.tm_isdst = -1;
843
844 day_start.tm_wday = time_day_of_week (
845 day_start_tt.day,
846 day_start_tt.month - 1,
847 day_start_tt.year);
848
849 if (day_view->date_format == E_DAY_VIEW_DATE_FULL)
850 /* strftime format %A = full weekday name, %d = day of month,
851 * %B = full month name. Don't use any other specifiers. */
852 format = _("%A %d %B");
853 else if (day_view->date_format == E_DAY_VIEW_DATE_ABBREVIATED)
854 /* strftime format %a = abbreviated weekday name, %d = day of month,
855 * %b = abbreviated month name. Don't use any other specifiers. */
856 format = _("%a %d %b");
857 else if (day_view->date_format == E_DAY_VIEW_DATE_NO_WEEKDAY)
858 /* strftime format %d = day of month, %b = abbreviated month name.
859 * Don't use any other specifiers. */
860 format = _("%d %b");
861 else
862 format = "%d";
863
864 e_utf8_strftime (buffer, buffer_len, format, &day_start);
865 }
866
867 EDayView *
868 e_day_view_top_item_get_day_view (EDayViewTopItem *top_item)
869 {
870 g_return_val_if_fail (E_IS_DAY_VIEW_TOP_ITEM (top_item), NULL);
871
872 return top_item->priv->day_view;
873 }
874
875 void
876 e_day_view_top_item_set_day_view (EDayViewTopItem *top_item,
877 EDayView *day_view)
878 {
879 g_return_if_fail (E_IS_DAY_VIEW_TOP_ITEM (top_item));
880 g_return_if_fail (E_IS_DAY_VIEW (day_view));
881
882 if (top_item->priv->day_view == day_view)
883 return;
884
885 if (top_item->priv->day_view != NULL)
886 g_object_unref (top_item->priv->day_view);
887
888 top_item->priv->day_view = g_object_ref (day_view);
889
890 g_object_notify (G_OBJECT (top_item), "day-view");
891 }
892
893 gboolean
894 e_day_view_top_item_get_show_dates (EDayViewTopItem *top_item)
895 {
896 g_return_val_if_fail (E_IS_DAY_VIEW_TOP_ITEM (top_item), FALSE);
897
898 return top_item->priv->show_dates;
899 }
900
901 void
902 e_day_view_top_item_set_show_dates (EDayViewTopItem *top_item,
903 gboolean show_dates)
904 {
905 g_return_if_fail (E_IS_DAY_VIEW_TOP_ITEM (top_item));
906
907 if (top_item->priv->show_dates == show_dates)
908 return;
909
910 top_item->priv->show_dates = show_dates;
911
912 g_object_notify (G_OBJECT (top_item), "show-dates");
913 }