/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with the program; if not, see * * * Authors: * Damon Chaplin * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ /* * EWeekViewEventItem - displays the background, times and icons for an event * in the week/month views. A separate EText canvas item is used to display & * edit the text. */ #ifdef HAVE_CONFIG_H #include #endif #include "e-util/e-categories-config.h" #include "e-week-view-event-item.h" #include #include "e-calendar-view.h" #include "comp-util.h" #include #define E_WEEK_VIEW_EVENT_ITEM_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), E_TYPE_WEEK_VIEW_EVENT_ITEM, EWeekViewEventItemPrivate)) struct _EWeekViewEventItemPrivate { /* The event index in the EWeekView events array. */ gint event_num; /* The span index within the event. */ gint span_num; }; enum { PROP_0, PROP_EVENT_NUM, PROP_SPAN_NUM }; G_DEFINE_TYPE ( EWeekViewEventItem, e_week_view_event_item, GNOME_TYPE_CANVAS_ITEM) static gboolean can_draw_in_region (cairo_region_t *draw_region, gint x, gint y, gint width, gint height) { GdkRectangle rect; g_return_val_if_fail (draw_region != NULL, FALSE); rect.x = x; rect.y = y; rect.width = width; rect.height = height; return cairo_region_contains_rectangle (draw_region, &rect) != CAIRO_REGION_OVERLAP_OUT; } static ECalendarViewPosition week_view_event_item_get_position (EWeekViewEventItem *event_item, gdouble x, gdouble y) { EWeekView *week_view; GnomeCanvasItem *item; GtkWidget *parent; item = GNOME_CANVAS_ITEM (event_item); parent = gtk_widget_get_parent (GTK_WIDGET (item->canvas)); g_return_val_if_fail (E_IS_WEEK_VIEW (parent), E_CALENDAR_VIEW_POS_NONE); week_view = E_WEEK_VIEW (parent); if (x < item->x1 + E_WEEK_VIEW_EVENT_L_PAD || x >= item->x2 - E_WEEK_VIEW_EVENT_R_PAD) return E_CALENDAR_VIEW_POS_NONE; /* Support left/right edge for long events only. */ if (!e_week_view_is_one_day_event (week_view, event_item->priv->event_num)) { if (x < item->x1 + E_WEEK_VIEW_EVENT_L_PAD + E_WEEK_VIEW_EVENT_BORDER_WIDTH + E_WEEK_VIEW_EVENT_EDGE_X_PAD) return E_CALENDAR_VIEW_POS_LEFT_EDGE; if (x >= item->x2 + 1 - E_WEEK_VIEW_EVENT_R_PAD - E_WEEK_VIEW_EVENT_BORDER_WIDTH - E_WEEK_VIEW_EVENT_EDGE_X_PAD) return E_CALENDAR_VIEW_POS_RIGHT_EDGE; } return E_CALENDAR_VIEW_POS_EVENT; } static gboolean week_view_event_item_double_click (EWeekViewEventItem *event_item, GdkEvent *button_event) { EWeekView *week_view; EWeekViewEvent *event; GnomeCanvasItem *item; GtkWidget *parent; item = GNOME_CANVAS_ITEM (event_item); parent = gtk_widget_get_parent (GTK_WIDGET (item->canvas)); g_return_val_if_fail (E_IS_WEEK_VIEW (parent), FALSE); week_view = E_WEEK_VIEW (parent); if (!is_array_index_in_bounds (week_view->events, event_item->priv->event_num)) return TRUE; event = &g_array_index ( week_view->events, EWeekViewEvent, event_item->priv->event_num); if (!is_comp_data_valid (event)) return TRUE; if (week_view->editing_event_num >= 0) { EWeekViewEvent *editing; if (!is_array_index_in_bounds ( week_view->events, week_view->editing_event_num)) return TRUE; editing = &g_array_index ( week_view->events, EWeekViewEvent, week_view->editing_event_num); /* Do not call edit of the component, if double clicked * on the component, which is not on the server. */ if (editing && event && editing->comp_data == event->comp_data && is_comp_data_valid (editing) && (!event->comp_data || !is_icalcomp_on_the_server ( event->comp_data->icalcomp, event->comp_data->client))) return TRUE; } e_week_view_stop_editing_event (week_view); e_calendar_view_edit_appointment ( E_CALENDAR_VIEW (week_view), event->comp_data->client, event->comp_data->icalcomp, EDIT_EVENT_AUTODETECT); return TRUE; } static gboolean week_view_event_item_button_press (EWeekViewEventItem *event_item, GdkEvent *button_event) { EWeekView *week_view; ECalendarViewPosition pos; EWeekViewEvent *event; EWeekViewEventSpan *span; GnomeCanvasItem *item; GtkWidget *parent; guint event_button = 0; gdouble event_x_win = 0; gdouble event_y_win = 0; gdk_event_get_button (button_event, &event_button); gdk_event_get_coords (button_event, &event_x_win, &event_y_win); item = GNOME_CANVAS_ITEM (event_item); parent = gtk_widget_get_parent (GTK_WIDGET (item->canvas)); g_return_val_if_fail (E_IS_WEEK_VIEW (parent), FALSE); week_view = E_WEEK_VIEW (parent); if (!is_array_index_in_bounds (week_view->events, event_item->priv->event_num)) return FALSE; event = &g_array_index ( week_view->events, EWeekViewEvent, event_item->priv->event_num); if (!is_array_index_in_bounds ( week_view->spans, event->spans_index + event_item->priv->span_num)) return FALSE; span = &g_array_index (week_view->spans, EWeekViewEventSpan, event->spans_index + event_item->priv->span_num); pos = week_view_event_item_get_position ( event_item, event_x_win, event_y_win); if (pos == E_CALENDAR_VIEW_POS_NONE) return FALSE; if (event_button == 1) { week_view->pressed_event_num = event_item->priv->event_num; week_view->pressed_span_num = event_item->priv->span_num; /* Ignore clicks on the event while editing. */ if (E_TEXT (span->text_item)->editing) return FALSE; /* Remember the item clicked and the mouse position, * so we can start a drag if the mouse moves. */ week_view->drag_event_x = event_x_win; week_view->drag_event_y = event_y_win; /* FIXME: Remember the day offset from the start of the event. */ return TRUE; } else if (event_button == 3) { if (!gtk_widget_has_focus (GTK_WIDGET (week_view))) { gtk_widget_grab_focus (GTK_WIDGET (week_view)); if (week_view->event_destroyed) { week_view->event_destroyed = FALSE; return FALSE; } } e_week_view_set_selected_time_range_visible ( week_view, event->start, event->end); e_week_view_show_popup_menu ( week_view, button_event, event_item->priv->event_num); g_signal_stop_emission_by_name ( item->canvas, "button_press_event"); return TRUE; } return FALSE; } static gboolean week_view_event_item_button_release (EWeekViewEventItem *event_item, GdkEvent *event) { EWeekView *week_view; GnomeCanvasItem *item; GtkWidget *parent; item = GNOME_CANVAS_ITEM (event_item); parent = gtk_widget_get_parent (GTK_WIDGET (item->canvas)); g_return_val_if_fail (E_IS_WEEK_VIEW (parent), FALSE); week_view = E_WEEK_VIEW (parent); if (week_view->pressed_event_num != -1 && week_view->pressed_event_num == event_item->priv->event_num && week_view->pressed_span_num == event_item->priv->span_num) { e_week_view_start_editing_event ( week_view, event_item->priv->event_num, event_item->priv->span_num, NULL); week_view->pressed_event_num = -1; return TRUE; } week_view->pressed_event_num = -1; return FALSE; } static void week_view_draw_time (EWeekView *week_view, cairo_t *cr, gint time_x, gint time_y, gint hour, gint minute) { ECalModel *model; GtkStyle *style; gint hour_to_display, suffix_width; gint time_y_normal_font, time_y_small_font; const gchar *suffix; gchar buffer[128]; PangoLayout *layout; PangoFontDescription *small_font_desc; cairo_save (cr); model = e_calendar_view_get_model (E_CALENDAR_VIEW (week_view)); style = gtk_widget_get_style (GTK_WIDGET (week_view)); small_font_desc = week_view->small_font_desc; gdk_cairo_set_source_color (cr, &week_view->colors[E_WEEK_VIEW_COLOR_EVENT_TEXT]); layout = gtk_widget_create_pango_layout (GTK_WIDGET (week_view), NULL); time_y_normal_font = time_y_small_font = time_y; if (small_font_desc) time_y_small_font = time_y; e_week_view_convert_time_to_display ( week_view, hour, &hour_to_display, &suffix, &suffix_width); if (week_view->use_small_font && week_view->small_font_desc) { g_snprintf ( buffer, sizeof (buffer), "%2i:%02i", hour_to_display, minute); /* Draw the hour. */ if (hour_to_display < 10) { pango_layout_set_text (layout, buffer + 1, 1); cairo_move_to ( cr, time_x + week_view->digit_width, time_y_normal_font); pango_cairo_show_layout (cr, layout); } else { pango_layout_set_text (layout, buffer, 2); cairo_move_to ( cr, time_x, time_y_normal_font); pango_cairo_show_layout (cr, layout); } time_x += week_view->digit_width * 2; /* Draw the start minute, in the small font. */ pango_layout_set_font_description (layout, week_view->small_font_desc); pango_layout_set_text (layout, buffer + 3, 2); cairo_move_to ( cr, time_x, time_y_small_font); pango_cairo_show_layout (cr, layout); pango_layout_set_font_description (layout, style->font_desc); time_x += week_view->small_digit_width * 2; /* Draw the 'am'/'pm' suffix, if 12-hour format. */ if (!e_cal_model_get_use_24_hour_format (model)) { pango_layout_set_text (layout, suffix, -1); cairo_move_to ( cr, time_x, time_y_normal_font); pango_cairo_show_layout (cr, layout); } } else { /* Draw the start time in one go. */ g_snprintf ( buffer, sizeof (buffer), "%2i:%02i%s", hour_to_display, minute, suffix); if (hour_to_display < 10) { pango_layout_set_text (layout, buffer + 1, -1); cairo_move_to ( cr, time_x + week_view->digit_width, time_y_normal_font); pango_cairo_show_layout (cr, layout); } else { pango_layout_set_text (layout, buffer, -1); cairo_move_to ( cr, time_x, time_y_normal_font); pango_cairo_show_layout (cr, layout); } } g_object_unref (layout); cairo_restore (cr); } static void week_view_event_item_draw_icons (EWeekViewEventItem *event_item, cairo_t *cr, gint icon_x, gint icon_y, gint x2, gboolean right_align, cairo_region_t *draw_region) { EWeekView *week_view; EWeekViewEvent *event; ECalComponent *comp; GnomeCanvas *canvas; GtkWidget *parent; gint num_icons = 0, icon_x_inc; gboolean draw_reminder_icon = FALSE, draw_recurrence_icon = FALSE; gboolean draw_timezone_icon = FALSE, draw_attach_icon = FALSE; gboolean draw_meeting_icon = FALSE; GSList *categories_pixbufs = NULL, *pixbufs; canvas = GNOME_CANVAS_ITEM (event_item)->canvas; parent = gtk_widget_get_parent (GTK_WIDGET (canvas)); week_view = E_WEEK_VIEW (parent); if (!is_array_index_in_bounds (week_view->events, event_item->priv->event_num)) return; event = &g_array_index (week_view->events, EWeekViewEvent, event_item->priv->event_num); if (!is_comp_data_valid (event)) return; comp = e_cal_component_new (); e_cal_component_set_icalcomponent ( comp, icalcomponent_new_clone (event->comp_data->icalcomp)); if (e_cal_component_has_alarms (comp)) { draw_reminder_icon = TRUE; num_icons++; } if (e_cal_component_has_recurrences (comp) || e_cal_component_is_instance (comp)) { draw_recurrence_icon = TRUE; num_icons++; } if (e_cal_component_has_attachments (comp)) { draw_attach_icon = TRUE; num_icons++; } if (e_cal_component_has_attendees (comp)) { draw_meeting_icon = TRUE; num_icons++; } if (event->different_timezone) { draw_timezone_icon = TRUE; num_icons++; } num_icons += cal_comp_util_get_n_icons (comp, &categories_pixbufs); icon_x_inc = E_WEEK_VIEW_ICON_WIDTH + E_WEEK_VIEW_ICON_X_PAD; if (right_align) icon_x -= icon_x_inc * num_icons; #define draw_pixbuf(pf) \ if (can_draw_in_region (draw_region, icon_x, icon_y, \ E_WEEK_VIEW_ICON_WIDTH, E_WEEK_VIEW_ICON_HEIGHT)) { \ cairo_save (cr); \ gdk_cairo_set_source_pixbuf (cr, pf, icon_x, icon_y); \ cairo_paint (cr); \ cairo_restore (cr); \ } \ \ icon_x += icon_x_inc; if (draw_reminder_icon && icon_x + E_WEEK_VIEW_ICON_WIDTH <= x2) { draw_pixbuf (week_view->reminder_icon); } if (draw_attach_icon && icon_x + E_WEEK_VIEW_ICON_WIDTH <= x2) { draw_pixbuf (week_view->attach_icon); } if (draw_recurrence_icon && icon_x + E_WEEK_VIEW_ICON_WIDTH <= x2) { draw_pixbuf (week_view->recurrence_icon); } if (draw_timezone_icon && icon_x + E_WEEK_VIEW_ICON_WIDTH <= x2) { draw_pixbuf (week_view->timezone_icon); } if (draw_meeting_icon && icon_x + E_WEEK_VIEW_ICON_WIDTH <= x2) { draw_pixbuf (week_view->meeting_icon); } /* draw categories icons */ for (pixbufs = categories_pixbufs; pixbufs; pixbufs = pixbufs->next) { GdkPixbuf *pixbuf = pixbufs->data; draw_pixbuf (pixbuf); } #undef draw_pixbuf g_slist_foreach (categories_pixbufs, (GFunc) g_object_unref, NULL); g_slist_free (categories_pixbufs); g_object_unref (comp); } /* This draws a little triangle to indicate that an event extends past * the days visible on screen. */ static void week_view_event_item_draw_triangle (EWeekViewEventItem *event_item, cairo_t *cr, GdkColor bg_color, gint x, gint y, gint w, gint h, cairo_region_t *draw_region) { ECalModel *model; EWeekView *week_view; EWeekViewEvent *event; GnomeCanvas *canvas; GtkWidget *parent; GdkPoint points[3]; const gchar *color_spec; gint c1, c2; if (!can_draw_in_region (draw_region, x, y, w, h)) return; canvas = GNOME_CANVAS_ITEM (event_item)->canvas; parent = gtk_widget_get_parent (GTK_WIDGET (canvas)); week_view = E_WEEK_VIEW (parent); if (!is_array_index_in_bounds (week_view->events, event_item->priv->event_num)) return; event = &g_array_index (week_view->events, EWeekViewEvent, event_item->priv->event_num); if (!is_comp_data_valid (event)) return; points[0].x = x; points[0].y = y; points[1].x = x + w; points[1].y = y + (h / 2); points[2].x = x; points[2].y = y + h - 1; model = e_calendar_view_get_model (E_CALENDAR_VIEW (week_view)); color_spec = e_cal_model_get_color_for_component (model, event->comp_data); if (gdk_color_parse (color_spec, &bg_color)) { gdk_cairo_set_source_color (cr, &bg_color); } else { EWeekViewColors wvc; GdkColor *color; wvc = E_WEEK_VIEW_COLOR_EVENT_BACKGROUND; color = &week_view->colors[wvc]; gdk_cairo_set_source_color (cr, color); } cairo_save (cr); cairo_set_line_width (cr, 0.7); cairo_move_to (cr, points[0].x, points[0].y); cairo_line_to (cr, points[1].x, points[1].y); cairo_line_to (cr, points[2].x, points[2].y); cairo_line_to (cr, points[0].x, points[0].y); cairo_fill (cr); cairo_restore (cr); cairo_save (cr); gdk_cairo_set_source_color ( cr, &week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BORDER]); /* If the height is odd we can use the same central point for both * lines. If it is even we use different end-points. */ c1 = c2 = y + (h / 2); if (h % 2 == 0) c1--; cairo_set_line_width (cr, 0.7); cairo_move_to (cr, x, y); cairo_line_to (cr, x + w, c1); cairo_move_to (cr, x, y + h - 1); cairo_line_to (cr, x + w, c2); cairo_restore (cr); } static void week_view_event_item_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { switch (property_id) { case PROP_EVENT_NUM: e_week_view_event_item_set_event_num ( E_WEEK_VIEW_EVENT_ITEM (object), g_value_get_int (value)); return; case PROP_SPAN_NUM: e_week_view_event_item_set_span_num ( E_WEEK_VIEW_EVENT_ITEM (object), g_value_get_int (value)); return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } static void week_view_event_item_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { switch (property_id) { case PROP_EVENT_NUM: g_value_set_int ( value, e_week_view_event_item_get_event_num ( E_WEEK_VIEW_EVENT_ITEM (object))); return; case PROP_SPAN_NUM: g_value_set_int ( value, e_week_view_event_item_get_span_num ( E_WEEK_VIEW_EVENT_ITEM (object))); return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } static void week_view_event_item_update (GnomeCanvasItem *item, const cairo_matrix_t *i2c, gint flags) { GnomeCanvasItemClass *canvas_item_class; EWeekViewEventItem *event_item; EWeekView *week_view; GtkWidget *parent; gint event_num, span_num; gint span_x, span_y, span_w; event_item = E_WEEK_VIEW_EVENT_ITEM (item); parent = gtk_widget_get_parent (GTK_WIDGET (item->canvas)); g_return_if_fail (E_IS_WEEK_VIEW (parent)); week_view = E_WEEK_VIEW (parent); /* Chain up to parent's update() method. */ canvas_item_class = GNOME_CANVAS_ITEM_CLASS (e_week_view_event_item_parent_class); canvas_item_class->update (item, i2c, flags); item->x1 = 0; item->y1 = 0; item->x2 = 0; item->y2 = 0; event_num = e_week_view_event_item_get_event_num (event_item); span_num = e_week_view_event_item_get_span_num (event_item); if (event_num != -1 && span_num != -1) { if (e_week_view_get_span_position ( week_view, event_num, span_num, &span_x, &span_y, &span_w)) { item->x1 = span_x; item->y1 = span_y; item->x2 = span_x + span_w - 1; item->y2 = span_y + week_view->row_height - 1; } } } static void week_view_event_item_draw (GnomeCanvasItem *canvas_item, cairo_t *cr, gint x, gint y, gint width, gint height) { EWeekViewEventItem *event_item; EWeekView *week_view; EWeekViewEvent *event; EWeekViewEventSpan *span; ECalModel *model; GtkWidget *parent; gint x1, y1, x2, y2, time_x, time_y; gint icon_x, icon_y, time_width, min_end_time_x, max_icon_x; gint rect_x, rect_w, rect_x2 = 0; gboolean one_day_event, editing_span = FALSE; gint start_hour, start_minute, end_hour, end_minute; gboolean draw_start, draw_end; gboolean draw_start_triangle = FALSE, draw_end_triangle = FALSE; GdkColor bg_color; cairo_pattern_t *pat; guint16 red, green, blue; gdouble radius, cx0, cy0, rect_height, rect_width; gdouble cc = 65535.0; cairo_region_t *draw_region; GdkRectangle rect; const gchar *color_spec; event_item = E_WEEK_VIEW_EVENT_ITEM (canvas_item); parent = gtk_widget_get_parent (GTK_WIDGET (canvas_item->canvas)); g_return_if_fail (E_IS_WEEK_VIEW (parent)); week_view = E_WEEK_VIEW (parent); if (event_item->priv->event_num == -1 || event_item->priv->span_num == -1) return; g_return_if_fail (event_item->priv->event_num < week_view->events->len); if (!is_array_index_in_bounds (week_view->events, event_item->priv->event_num)) return; event = &g_array_index (week_view->events, EWeekViewEvent, event_item->priv->event_num); if (!is_comp_data_valid (event)) return; g_return_if_fail ( event->spans_index + event_item->priv->span_num < week_view->spans->len); if (!is_array_index_in_bounds ( week_view->spans, event->spans_index + event_item->priv->span_num)) return; span = &g_array_index ( week_view->spans, EWeekViewEventSpan, event->spans_index + event_item->priv->span_num); x1 = canvas_item->x1 - x; y1 = canvas_item->y1 - y; x2 = canvas_item->x2 - x; y2 = canvas_item->y2 - y; if (x1 == x2 || y1 == y2) return; rect.x = 0; rect.y = 0; rect.width = width; rect.height = height; if (rect.width > 0 && rect.height > 0) draw_region = cairo_region_create_rectangle (&rect); else draw_region = cairo_region_create (); if (!can_draw_in_region (draw_region, x1, y1, x2 - x1, y2 - y1)) { cairo_region_destroy (draw_region); return; } icon_y = y1 + E_WEEK_VIEW_EVENT_BORDER_HEIGHT + E_WEEK_VIEW_ICON_Y_PAD; /* Get the start & end times in 24-hour format. */ start_hour = event->start_minute / 60; start_minute = event->start_minute % 60; /* Modulo 24 because a midnight end time will be '24' */ end_hour = (event->end_minute / 60) % 24; end_minute = event->end_minute % 60; time_y = y1 + E_WEEK_VIEW_EVENT_BORDER_HEIGHT + E_WEEK_VIEW_EVENT_TEXT_Y_PAD; time_width = e_week_view_get_time_string_width (week_view); one_day_event = e_week_view_is_one_day_event ( week_view, event_item->priv->event_num); model = e_calendar_view_get_model (E_CALENDAR_VIEW (week_view)); color_spec = e_cal_model_get_color_for_component (model, event->comp_data); bg_color = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND]; if (!gdk_color_parse (color_spec, &bg_color)) { bg_color = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND]; } red = bg_color.red; green = bg_color.green; blue = bg_color.blue; if (one_day_event) { time_x = x1 + E_WEEK_VIEW_EVENT_L_PAD + 1; rect_x = x1 + E_WEEK_VIEW_EVENT_L_PAD; rect_w = x2 - x1 - E_WEEK_VIEW_EVENT_L_PAD - E_WEEK_VIEW_EVENT_R_PAD + 1; /* Here we draw the border around the event*/ cx0 = rect_x; cy0 = y1 + 1; rect_width = rect_w; rect_height = y2 - y1 - 1; radius = 12; if (can_draw_in_region (draw_region, cx0, cy0, rect_width, rect_height)) { cairo_save (cr); draw_curved_rectangle (cr, cx0, cy0, rect_width, rect_height, radius); cairo_set_line_width (cr, 2.0); cairo_set_source_rgb (cr, red / cc, green / cc, blue / cc); cairo_stroke (cr); cairo_restore (cr); } /* Fill it in the Event */ cx0 = rect_x + 1.5; cy0 = y1 + 2.75; rect_width = rect_w - 3.; rect_height = y2 - y1 - 4.5; radius = 8; if (can_draw_in_region (draw_region, cx0, cy0, rect_width, rect_height)) { cairo_save (cr); draw_curved_rectangle ( cr, cx0, cy0, rect_width, rect_height, radius); pat = cairo_pattern_create_linear ( rect_x + 2, y1 + 1, rect_x + 2, y2 - 7.25); cairo_pattern_add_color_stop_rgba ( pat, 1, red / cc, green / cc, blue / cc, 0.8); cairo_pattern_add_color_stop_rgba ( pat, 0, red / cc, green / cc, blue / cc, 0.4); cairo_set_source (cr, pat); cairo_fill_preserve (cr); cairo_pattern_destroy (pat); cairo_set_source_rgba (cr, red / cc, green / cc, blue / cc, 0.2); cairo_set_line_width (cr, 0.5); cairo_stroke (cr); cairo_restore (cr); } /* Draw the start and end times, as required. */ switch (week_view->time_format) { case E_WEEK_VIEW_TIME_BOTH_SMALL_MIN: case E_WEEK_VIEW_TIME_BOTH: draw_start = TRUE; draw_end = TRUE; break; case E_WEEK_VIEW_TIME_START_SMALL_MIN: case E_WEEK_VIEW_TIME_START: draw_start = TRUE; draw_end = FALSE; break; case E_WEEK_VIEW_TIME_NONE: draw_start = FALSE; draw_end = FALSE; break; default: g_return_if_reached (); draw_start = FALSE; draw_end = FALSE; break; } if (draw_start) { week_view_draw_time ( week_view, cr, time_x, time_y, start_hour, start_minute); time_x += time_width; } if (draw_end) { time_x += E_WEEK_VIEW_EVENT_TIME_SPACING; week_view_draw_time ( week_view, cr, time_x, time_y, end_hour, end_minute); time_x += time_width; } icon_x = time_x; if (draw_start) icon_x += E_WEEK_VIEW_EVENT_TIME_X_PAD; /* Draw the icons. */ week_view_event_item_draw_icons ( event_item, cr, icon_x, icon_y, x2, FALSE, draw_region); } else { rect_x = x1 + E_WEEK_VIEW_EVENT_L_PAD; rect_w = x2 - x1 - E_WEEK_VIEW_EVENT_L_PAD - E_WEEK_VIEW_EVENT_R_PAD + 1; /* Draw the triangles at the start & end, if needed. * They also use the first few pixels at the edge of the * event so we update rect_x & rect_w so we don't draw over * them. */ if (event->start < week_view->day_starts[span->start_day]) { draw_start_triangle = TRUE; rect_x += 2; rect_w -= 2; } if (event->end > week_view->day_starts[span->start_day + span->num_days]) { draw_end_triangle = TRUE; rect_w -= 2; } /* Here we draw the border around the event */ cx0 = rect_x; cy0 = y1 + 1; rect_width = rect_w; rect_height = y2 - y1 - 1; radius = 12; if (can_draw_in_region (draw_region, cx0, cy0, rect_width, rect_height)) { cairo_save (cr); draw_curved_rectangle (cr, cx0, cy0, rect_width, rect_height, radius); cairo_set_line_width (cr, 2.0); cairo_set_source_rgb (cr, red / cc, green / cc, blue / cc); cairo_stroke (cr); cairo_restore (cr); } /* Here we fill it in the event*/ cx0 = rect_x + 1.5; cy0 = y1 + 2.75; rect_width = rect_w - 3.; rect_height = y2 - y1 - 4.5; radius = 8; if (can_draw_in_region (draw_region, cx0, cy0, rect_width, rect_height)) { cairo_save (cr); draw_curved_rectangle ( cr, cx0, cy0, rect_width, rect_height, radius); pat = cairo_pattern_create_linear ( rect_x + 2, y1 + 1, rect_x + 2, y2 - 7.25); cairo_pattern_add_color_stop_rgba ( pat, 1, red / cc, green / cc, blue / cc, 0.8); cairo_pattern_add_color_stop_rgba ( pat, 0, red / cc, green / cc, blue / cc, 0.4); cairo_set_source (cr, pat); cairo_fill_preserve (cr); cairo_pattern_destroy (pat); cairo_set_source_rgba (cr, red / cc, green / cc, blue / cc, 0.2); cairo_set_line_width (cr, 0.5); cairo_stroke (cr); cairo_restore (cr); } if (draw_start_triangle) { week_view_event_item_draw_triangle ( event_item, cr, bg_color, x1 + E_WEEK_VIEW_EVENT_L_PAD + 2, y1, -3, y2 - y1 + 1, draw_region); } else if (can_draw_in_region (draw_region, rect_x, y1, 1, y2 - y1)) { EWeekViewColors wvc; GdkColor *color; wvc = E_WEEK_VIEW_COLOR_EVENT_BORDER; color = &week_view->colors[wvc]; cairo_save (cr); gdk_cairo_set_source_color (cr, color); cairo_set_line_width (cr, 0.7); cairo_move_to (cr, rect_x, y1); cairo_line_to (cr, rect_x, y2); cairo_stroke (cr); cairo_restore (cr); } if (draw_end_triangle) { week_view_event_item_draw_triangle ( event_item, cr, bg_color, x2 - E_WEEK_VIEW_EVENT_R_PAD - 2, y1, 3, y2 - y1 + 1, draw_region); } else if (can_draw_in_region (draw_region, rect_x2, y2, 1, 1)) { EWeekViewColors wvc; GdkColor *color; wvc = E_WEEK_VIEW_COLOR_EVENT_BORDER; color = &week_view->colors[wvc]; cairo_save (cr); gdk_cairo_set_source_color (cr, color); cairo_set_line_width (cr, 0.7); /* rect_x2 is used uninitialized here */ cairo_move_to (cr, rect_x2, y2); cairo_line_to (cr, rect_x2, y2); cairo_stroke (cr); cairo_restore (cr); } if (span->text_item && E_TEXT (span->text_item)->editing) editing_span = TRUE; /* Draw the start & end times, if they are not on day * boundaries. The start time would always be shown if it was * needed, though it may be clipped as the window shrinks. * The end time is only displayed if there is enough room. * We calculate the minimum position for the end time, which * depends on whether the start time is displayed. If the end * time doesn't fit, then we don't draw it. */ min_end_time_x = x1 + E_WEEK_VIEW_EVENT_L_PAD + E_WEEK_VIEW_EVENT_BORDER_WIDTH + E_WEEK_VIEW_EVENT_EDGE_X_PAD; if (!editing_span && event->start > week_view->day_starts[span->start_day]) { time_x = x1 + E_WEEK_VIEW_EVENT_L_PAD + E_WEEK_VIEW_EVENT_BORDER_WIDTH + E_WEEK_VIEW_EVENT_EDGE_X_PAD; cairo_save (cr); cairo_rectangle ( cr, x1, y1, x2 - x1 - E_WEEK_VIEW_EVENT_R_PAD - E_WEEK_VIEW_EVENT_BORDER_WIDTH + 1, y2 - y1 + 1); cairo_clip (cr); week_view_draw_time ( week_view, cr, time_x, time_y, start_hour, start_minute); cairo_restore (cr); /* We don't want the end time to be drawn over the * start time, so we increase the minimum position. */ min_end_time_x += time_width + E_WEEK_VIEW_EVENT_TIME_X_PAD; } max_icon_x = x2 + 1 - E_WEEK_VIEW_EVENT_R_PAD - E_WEEK_VIEW_EVENT_BORDER_WIDTH - E_WEEK_VIEW_EVENT_EDGE_X_PAD; if (!editing_span && event->end < week_view->day_starts[span->start_day + span->num_days]) { /* Calculate where the end time should be displayed. */ time_x = x2 + 1 - E_WEEK_VIEW_EVENT_R_PAD - E_WEEK_VIEW_EVENT_BORDER_WIDTH - E_WEEK_VIEW_EVENT_EDGE_X_PAD - time_width; /* Draw the end time, if the position is greater than * the minimum calculated above. */ if (time_x >= min_end_time_x) { week_view_draw_time ( week_view, cr, time_x, time_y, end_hour, end_minute); max_icon_x -= time_width + E_WEEK_VIEW_EVENT_TIME_X_PAD; } } /* Draw the icons. */ if (span->text_item && (week_view->editing_event_num != event_item->priv->event_num || week_view->editing_span_num != event_item->priv->span_num)) { icon_x = span->text_item->x1 - E_WEEK_VIEW_ICON_R_PAD - x; week_view_event_item_draw_icons ( event_item, cr, icon_x, icon_y, max_icon_x, TRUE, draw_region); } } cairo_region_destroy (draw_region); } static GnomeCanvasItem * week_view_event_item_point (GnomeCanvasItem *item, gdouble x, gdouble y, gint cx, gint cy) { return item; } static gint week_view_event_item_event (GnomeCanvasItem *item, GdkEvent *event) { EWeekViewEventItem *event_item; event_item = E_WEEK_VIEW_EVENT_ITEM (item); switch (event->type) { case GDK_2BUTTON_PRESS: return week_view_event_item_double_click (event_item, event); case GDK_BUTTON_PRESS: return week_view_event_item_button_press (event_item, event); case GDK_BUTTON_RELEASE: return week_view_event_item_button_release (event_item, event); case GDK_MOTION_NOTIFY: break; default: break; } return FALSE; } static void e_week_view_event_item_class_init (EWeekViewEventItemClass *class) { GObjectClass *object_class; GnomeCanvasItemClass *item_class; g_type_class_add_private (class, sizeof (EWeekViewEventItemPrivate)); object_class = G_OBJECT_CLASS (class); object_class->set_property = week_view_event_item_set_property; object_class->get_property = week_view_event_item_get_property; item_class = GNOME_CANVAS_ITEM_CLASS (class); item_class->update = week_view_event_item_update; item_class->draw = week_view_event_item_draw; item_class->point = week_view_event_item_point; item_class->event = week_view_event_item_event; g_object_class_install_property ( object_class, PROP_EVENT_NUM, g_param_spec_int ( "event-num", "Event Num", NULL, G_MININT, G_MAXINT, -1, G_PARAM_READWRITE)); g_object_class_install_property ( object_class, PROP_SPAN_NUM, g_param_spec_int ( "span-num", "Span Num", NULL, G_MININT, G_MAXINT, -1, G_PARAM_READWRITE)); } static void e_week_view_event_item_init (EWeekViewEventItem *event_item) { event_item->priv = E_WEEK_VIEW_EVENT_ITEM_GET_PRIVATE (event_item); event_item->priv->event_num = -1; event_item->priv->span_num = -1; } gint e_week_view_event_item_get_event_num (EWeekViewEventItem *event_item) { g_return_val_if_fail (E_IS_WEEK_VIEW_EVENT_ITEM (event_item), -1); return event_item->priv->event_num; } void e_week_view_event_item_set_event_num (EWeekViewEventItem *event_item, gint event_num) { g_return_if_fail (E_IS_WEEK_VIEW_EVENT_ITEM (event_item)); if (event_item->priv->event_num == event_num) return; event_item->priv->event_num = event_num; gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (event_item)); g_object_notify (G_OBJECT (event_item), "event-num"); } gint e_week_view_event_item_get_span_num (EWeekViewEventItem *event_item) { g_return_val_if_fail (E_IS_WEEK_VIEW_EVENT_ITEM (event_item), -1); return event_item->priv->span_num; } void e_week_view_event_item_set_span_num (EWeekViewEventItem *event_item, gint span_num) { g_return_if_fail (E_IS_WEEK_VIEW_EVENT_ITEM (event_item)); if (event_item->priv->span_num == span_num) return; event_item->priv->span_num = span_num; gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (event_item)); g_object_notify (G_OBJECT (event_item), "span-num"); }