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