aboutsummaryrefslogtreecommitdiffstats
path: root/calendar/gui/e-day-view-main-item.c
diff options
context:
space:
mode:
Diffstat (limited to 'calendar/gui/e-day-view-main-item.c')
-rw-r--r--calendar/gui/e-day-view-main-item.c631
1 files changed, 631 insertions, 0 deletions
diff --git a/calendar/gui/e-day-view-main-item.c b/calendar/gui/e-day-view-main-item.c
new file mode 100644
index 0000000000..5d002b5945
--- /dev/null
+++ b/calendar/gui/e-day-view-main-item.c
@@ -0,0 +1,631 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * Author :
+ * Damon Chaplin <damon@helixcode.com>
+ *
+ * Copyright 1999, Helix Code, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ * EDayViewMainItem - canvas item which displays most of the appointment
+ * data in the main Day/Work Week display.
+ */
+
+#include "e-day-view-main-item.h"
+
+static void e_day_view_main_item_class_init (EDayViewMainItemClass *class);
+static void e_day_view_main_item_init (EDayViewMainItem *dvtitem);
+
+static void e_day_view_main_item_set_arg (GtkObject *o, GtkArg *arg,
+ guint arg_id);
+static void e_day_view_main_item_update (GnomeCanvasItem *item,
+ double *affine,
+ ArtSVP *clip_path, int flags);
+static void e_day_view_main_item_draw (GnomeCanvasItem *item,
+ GdkDrawable *drawable,
+ int x, int y,
+ int width, int height);
+static double e_day_view_main_item_point (GnomeCanvasItem *item,
+ double x, double y,
+ int cx, int cy,
+ GnomeCanvasItem **actual_item);
+static gint e_day_view_main_item_event (GnomeCanvasItem *item,
+ GdkEvent *event);
+
+static void e_day_view_main_item_draw_long_events_in_vbars (EDayViewMainItem *dvmitem,
+ GdkDrawable *drawable,
+ int x,
+ int y,
+ int width,
+ int height);
+static void e_day_view_main_item_draw_events_in_vbars (EDayViewMainItem *dvmitem,
+ GdkDrawable *drawable,
+ int x, int y,
+ int width, int height,
+ gint day);
+static void e_day_view_main_item_draw_day_events (EDayViewMainItem *dvmitem,
+ GdkDrawable *drawable,
+ int x, int y,
+ int width, int height,
+ gint day);
+static void e_day_view_main_item_draw_day_event (EDayViewMainItem *dvmitem,
+ GdkDrawable *drawable,
+ int x, int y,
+ int width, int height,
+ gint day, gint event_num);
+
+static GnomeCanvasItemClass *parent_class;
+
+/* The arguments we take */
+enum {
+ ARG_0,
+ ARG_DAY_VIEW
+};
+
+
+GtkType
+e_day_view_main_item_get_type (void)
+{
+ static GtkType e_day_view_main_item_type = 0;
+
+ if (!e_day_view_main_item_type) {
+ GtkTypeInfo e_day_view_main_item_info = {
+ "EDayViewMainItem",
+ sizeof (EDayViewMainItem),
+ sizeof (EDayViewMainItemClass),
+ (GtkClassInitFunc) e_day_view_main_item_class_init,
+ (GtkObjectInitFunc) e_day_view_main_item_init,
+ NULL, /* reserved_1 */
+ NULL, /* reserved_2 */
+ (GtkClassInitFunc) NULL
+ };
+
+ e_day_view_main_item_type = gtk_type_unique (gnome_canvas_item_get_type (), &e_day_view_main_item_info);
+ }
+
+ return e_day_view_main_item_type;
+}
+
+
+static void
+e_day_view_main_item_class_init (EDayViewMainItemClass *class)
+{
+ GtkObjectClass *object_class;
+ GnomeCanvasItemClass *item_class;
+
+ parent_class = gtk_type_class (gnome_canvas_item_get_type());
+
+ object_class = (GtkObjectClass *) class;
+ item_class = (GnomeCanvasItemClass *) class;
+
+ gtk_object_add_arg_type ("EDayViewMainItem::day_view",
+ GTK_TYPE_POINTER, GTK_ARG_WRITABLE,
+ ARG_DAY_VIEW);
+
+ object_class->set_arg = e_day_view_main_item_set_arg;
+
+ /* GnomeCanvasItem method overrides */
+ item_class->update = e_day_view_main_item_update;
+ item_class->draw = e_day_view_main_item_draw;
+ item_class->point = e_day_view_main_item_point;
+ item_class->event = e_day_view_main_item_event;
+}
+
+
+static void
+e_day_view_main_item_init (EDayViewMainItem *dvtitem)
+{
+ dvtitem->day_view = NULL;
+}
+
+
+static void
+e_day_view_main_item_set_arg (GtkObject *o, GtkArg *arg, guint arg_id)
+{
+ GnomeCanvasItem *item;
+ EDayViewMainItem *dvmitem;
+
+ item = GNOME_CANVAS_ITEM (o);
+ dvmitem = E_DAY_VIEW_MAIN_ITEM (o);
+
+ switch (arg_id){
+ case ARG_DAY_VIEW:
+ dvmitem->day_view = GTK_VALUE_POINTER (*arg);
+ break;
+ }
+}
+
+
+static void
+e_day_view_main_item_update (GnomeCanvasItem *item,
+ double *affine,
+ ArtSVP *clip_path,
+ int flags)
+{
+ if (GNOME_CANVAS_ITEM_CLASS (parent_class)->update)
+ (* GNOME_CANVAS_ITEM_CLASS (parent_class)->update) (item, affine, clip_path, flags);
+
+ /* The item covers the entire canvas area. */
+ item->x1 = 0;
+ item->y1 = 0;
+ item->x2 = INT_MAX;
+ item->y2 = INT_MAX;
+}
+
+
+/*
+ * DRAWING ROUTINES - functions to paint the canvas item.
+ */
+
+static void
+e_day_view_main_item_draw (GnomeCanvasItem *canvas_item, GdkDrawable *drawable,
+ int x, int y, int width, int height)
+{
+ EDayViewMainItem *dvmitem;
+ EDayView *day_view;
+ GtkStyle *style;
+ GdkGC *fg_gc, *bg_gc, *light_gc, *dark_gc, *gc;
+ GdkFont *font;
+ gint row, row_y, grid_x1, grid_x2;
+ gint day, grid_y1, grid_y2;
+ gint work_day_start_row, work_day_end_row;
+ gint work_day_start_y, work_day_end_y;
+ gint work_day_x, work_day_w;
+ gint start_row, end_row, rect_x, rect_y, rect_width, rect_height;
+
+#if 0
+ g_print ("In e_day_view_main_item_draw %i,%i %ix%i\n",
+ x, y, width, height);
+#endif
+ dvmitem = E_DAY_VIEW_MAIN_ITEM (canvas_item);
+ day_view = dvmitem->day_view;
+ g_return_if_fail (day_view != NULL);
+
+ style = GTK_WIDGET (day_view)->style;
+ font = style->font;
+ fg_gc = style->fg_gc[GTK_STATE_NORMAL];
+ bg_gc = style->bg_gc[GTK_STATE_NORMAL];
+ light_gc = style->light_gc[GTK_STATE_NORMAL];
+ dark_gc = style->dark_gc[GTK_STATE_NORMAL];
+
+ /* Paint the background colors. */
+ gc = day_view->main_gc;
+ work_day_start_row = e_day_view_convert_time_to_row (day_view, day_view->work_day_start_hour, day_view->work_day_start_minute);
+ work_day_start_y = work_day_start_row * day_view->row_height - y;
+ work_day_end_row = e_day_view_convert_time_to_row (day_view, day_view->work_day_end_hour, day_view->work_day_end_minute);
+ work_day_end_y = work_day_end_row * day_view->row_height - y;
+
+ work_day_x = day_view->day_offsets[0] - x;
+ work_day_w = width - work_day_x;
+ gdk_gc_set_foreground (gc, &day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING]);
+ gdk_draw_rectangle (drawable, gc, TRUE,
+ work_day_x, 0 - y,
+ work_day_w, work_day_start_y - (0 - y));
+ gdk_gc_set_foreground (gc, &day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING]);
+ gdk_draw_rectangle (drawable, gc, TRUE,
+ work_day_x, work_day_start_y,
+ work_day_w, work_day_end_y - work_day_start_y);
+ gdk_gc_set_foreground (gc, &day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING]);
+ gdk_draw_rectangle (drawable, gc, TRUE,
+ work_day_x, work_day_end_y,
+ work_day_w, height - work_day_end_y);
+
+ /* Paint the selection background. */
+ if (day_view->selection_start_col != -1
+ && !day_view->selection_in_top_canvas) {
+ for (day = day_view->selection_start_col;
+ day <= day_view->selection_end_col;
+ day++) {
+ if (day == day_view->selection_start_col
+ && day_view->selection_start_row != -1)
+ start_row = day_view->selection_start_row;
+ else
+ start_row = 0;
+ if (day == day_view->selection_end_col
+ && day_view->selection_end_row != -1)
+ end_row = day_view->selection_end_row;
+ else
+ end_row = day_view->rows - 1;
+
+ rect_x = day_view->day_offsets[day] - x;
+ rect_width = day_view->day_widths[day];
+ rect_y = start_row * day_view->row_height - y;
+ rect_height = (end_row - start_row + 1) * day_view->row_height;
+
+ gc = style->bg_gc[GTK_STATE_SELECTED];
+ gdk_draw_rectangle (drawable, gc, TRUE,
+ rect_x, rect_y,
+ rect_width, rect_height);
+ }
+ }
+
+ /* Drawing the horizontal grid lines. */
+ grid_x1 = day_view->day_offsets[0] - x;
+ grid_x2 = day_view->day_offsets[day_view->days_shown] - x;
+
+ for (row = 0, row_y = 0 - y;
+ row < day_view->rows && row_y < height;
+ row++, row_y += day_view->row_height) {
+ if (row_y >= 0 && row_y < height)
+ gdk_draw_line (drawable, dark_gc,
+ grid_x1, row_y, grid_x2, row_y);
+ }
+
+ /* Draw the vertical bars down the left of each column. */
+ grid_y1 = 0;
+ grid_y2 = height;
+ for (day = 0; day < day_view->days_shown; day++) {
+ grid_x1 = day_view->day_offsets[day] - x;
+
+ /* Skip if it isn't visible. */
+ if (grid_x1 >= width || grid_x1 + E_DAY_VIEW_BAR_WIDTH <= 0)
+ continue;
+
+ gdk_draw_line (drawable, fg_gc,
+ grid_x1, grid_y1,
+ grid_x1, grid_y2);
+ gdk_draw_line (drawable, fg_gc,
+ grid_x1 + E_DAY_VIEW_BAR_WIDTH - 1, grid_y1,
+ grid_x1 + E_DAY_VIEW_BAR_WIDTH - 1, grid_y2);
+ gdk_draw_rectangle (drawable, style->white_gc, TRUE,
+ grid_x1 + 1, grid_y1,
+ E_DAY_VIEW_BAR_WIDTH - 2, grid_y2 - grid_y1);
+
+ /* Fill in the bars when the user is busy. */
+ e_day_view_main_item_draw_events_in_vbars (dvmitem, drawable,
+ x, y,
+ width, height,
+ day);
+ }
+
+ /* Fill in the vertical bars corresponding to the busy times from the
+ long events. */
+ e_day_view_main_item_draw_long_events_in_vbars (dvmitem, drawable,
+ x, y, width, height);
+
+ /* Draw the event borders and backgrounds, and the vertical bars
+ down the left edges. */
+ for (day = 0; day < day_view->days_shown; day++) {
+ e_day_view_main_item_draw_day_events (dvmitem, drawable,
+ x, y, width, height,
+ day);
+ }
+}
+
+
+static void
+e_day_view_main_item_draw_events_in_vbars (EDayViewMainItem *dvmitem,
+ GdkDrawable *drawable,
+ int x, int y,
+ int width, int height,
+ gint day)
+{
+ EDayView *day_view;
+ EDayViewEvent *event;
+ GdkGC *gc;
+ gint grid_x, event_num, bar_y, bar_h;
+
+ day_view = dvmitem->day_view;
+
+ gc = day_view->main_gc;
+ gdk_gc_set_foreground (gc, &day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR]);
+
+ grid_x = day_view->day_offsets[day] + 1 - x;
+
+ /* Draw the busy times corresponding to the events in the day. */
+ for (event_num = 0; event_num < day_view->events[day]->len;
+ event_num++) {
+ event = &g_array_index (day_view->events[day], EDayViewEvent,
+ event_num);
+
+ /* We can skip the events in the first column since they will
+ draw over this anyway. */
+ if (event->num_columns > 0 && event->start_row_or_col == 0)
+ continue;
+
+ bar_y = event->start_minute * day_view->row_height / day_view->mins_per_row;
+ bar_h = event->end_minute * day_view->row_height / day_view->mins_per_row - bar_y;
+ bar_y -= y;
+
+ /* Skip it if it isn't visible. */
+ if (bar_y >= height || bar_y + bar_h <= 0)
+ continue;
+
+ gdk_draw_rectangle (drawable, gc, TRUE,
+ grid_x, bar_y,
+ E_DAY_VIEW_BAR_WIDTH - 2, bar_h);
+ }
+}
+
+
+static void
+e_day_view_main_item_draw_long_events_in_vbars (EDayViewMainItem *dvmitem,
+ GdkDrawable *drawable,
+ int x, int y,
+ int width, int height)
+{
+ EDayView *day_view;
+ EDayViewEvent *event;
+ gint event_num, start_day, end_day, day, bar_y1, bar_y2, grid_x;
+ GdkGC *gc;
+
+ day_view = dvmitem->day_view;
+
+ gc = day_view->main_gc;
+ gdk_gc_set_foreground (gc, &day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR]);
+
+ for (event_num = 0; event_num < day_view->long_events->len;
+ event_num++) {
+ event = &g_array_index (day_view->long_events, EDayViewEvent,
+ event_num);
+
+ if (!e_day_view_find_long_event_days (day_view, event,
+ &start_day, &end_day))
+ continue;
+
+ for (day = start_day; day <= end_day; day++) {
+ grid_x = day_view->day_offsets[day] + 1 - x;
+
+ /* Skip if it isn't visible. */
+ if (grid_x >= width
+ || grid_x + E_DAY_VIEW_BAR_WIDTH <= 0)
+ continue;
+
+ if (event->start <= day_view->day_starts[day]) {
+ bar_y1 = 0;
+ } else {
+ bar_y1 = event->start_minute * day_view->row_height / day_view->mins_per_row - y;
+ }
+
+ if (event->end >= day_view->day_starts[day + 1]) {
+ bar_y2 = height;
+ } else {
+ bar_y2 = event->end_minute * day_view->row_height / day_view->mins_per_row - y;
+ }
+
+ if (bar_y1 < height && bar_y2 > 0 && bar_y2 > bar_y1) {
+ gdk_draw_rectangle (drawable, gc, TRUE,
+ grid_x, bar_y1,
+ E_DAY_VIEW_BAR_WIDTH - 2,
+ bar_y2 - bar_y1);
+ }
+ }
+
+
+ }
+}
+
+
+static void
+e_day_view_main_item_draw_day_events (EDayViewMainItem *dvmitem,
+ GdkDrawable *drawable,
+ int x, int y, int width, int height,
+ gint day)
+{
+ EDayView *day_view;
+ gint event_num;
+
+ day_view = dvmitem->day_view;
+
+ for (event_num = 0; event_num < day_view->events[day]->len;
+ event_num++) {
+ e_day_view_main_item_draw_day_event (dvmitem, drawable,
+ x, y, width, height,
+ day, event_num);
+ }
+}
+
+
+static void
+e_day_view_main_item_draw_day_event (EDayViewMainItem *dvmitem,
+ GdkDrawable *drawable,
+ int x, int y, int width, int height,
+ gint day, gint event_num)
+{
+ EDayView *day_view;
+ EDayViewEvent *event;
+ gint item_x, item_y, item_w, item_h, bar_y1, bar_y2;
+ GtkStyle *style;
+ GdkGC *gc;
+ iCalObject *ico;
+ gint num_icons, icon_x, icon_y, icon_x_inc, icon_y_inc;
+ gboolean draw_reminder_icon, draw_recurrence_icon;
+
+ day_view = dvmitem->day_view;
+
+ /* If the event is currently being dragged, don't draw it. It will
+ be drawn in the special drag items. */
+ if (day_view->drag_event_day == day
+ && day_view->drag_event_num == event_num)
+ return;
+
+ style = GTK_WIDGET (day_view)->style;
+
+ gc = day_view->main_gc;
+ gdk_gc_set_foreground (gc, &day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR]);
+
+ /* Get the position of the event. If it is not shown skip it.*/
+ if (!e_day_view_get_event_position (day_view, day, event_num,
+ &item_x, &item_y,
+ &item_w, &item_h))
+ return;
+
+ item_x -= x;
+ item_y -= y;
+
+ event = &g_array_index (day_view->events[day], EDayViewEvent,
+ event_num);
+
+ /* Fill in the white background. Note that for events in the first
+ column of the day, we might not want topaint over the vertical bar,
+ since that is used for multiple events. But then you can't see
+ where the event in the first column finishes. */
+#if 0
+ if (event->start_row_or_col == 0)
+ gdk_draw_rectangle (drawable, style->white_gc, TRUE,
+ item_x + E_DAY_VIEW_BAR_WIDTH, item_y + 1,
+ item_w - E_DAY_VIEW_BAR_WIDTH - 1,
+ item_h - 2);
+ else
+#endif
+ gdk_draw_rectangle (drawable, style->white_gc, TRUE,
+ item_x + 1, item_y + 1,
+ item_w - 2, item_h - 2);
+
+ /* Draw the right edge of the vertical bar. */
+ gdk_draw_line (drawable, style->black_gc,
+ item_x + E_DAY_VIEW_BAR_WIDTH - 1,
+ item_y + 1,
+ item_x + E_DAY_VIEW_BAR_WIDTH - 1,
+ item_y + item_h - 2);
+
+ /* Draw the vertical colored bar showing when the appointment
+ begins & ends. */
+ bar_y1 = event->start_minute * day_view->row_height / day_view->mins_per_row - y;
+ bar_y2 = event->end_minute * day_view->row_height / day_view->mins_per_row - y;
+
+ /* When an item is being resized, we fill the bar up to the new row. */
+ if (day_view->resize_drag_pos != E_DAY_VIEW_POS_NONE
+ && day_view->resize_event_day == day
+ && day_view->resize_event_num == event_num) {
+ if (day_view->resize_drag_pos == E_DAY_VIEW_POS_TOP_EDGE)
+ bar_y1 = item_y + 1;
+ else if (day_view->resize_drag_pos == E_DAY_VIEW_POS_BOTTOM_EDGE)
+ bar_y2 = item_y + item_h - 1;
+ }
+
+ gdk_draw_rectangle (drawable, gc, TRUE,
+ item_x + 1, bar_y1,
+ E_DAY_VIEW_BAR_WIDTH - 2, bar_y2 - bar_y1);
+
+ /* Draw the box around the entire event. Do this after drawing
+ the colored bar so we don't have to worry about being 1
+ pixel out. */
+ gdk_draw_rectangle (drawable, style->black_gc, FALSE,
+ item_x, item_y, item_w - 1, item_h - 1);
+
+#if 0
+ /* Draw the horizontal bars above and beneath the event if it
+ is currently being edited. */
+ if (day_view->editing_event_day == day
+ && day_view->editing_event_num == event_num) {
+ gdk_draw_rectangle (drawable, gc, TRUE,
+ item_x,
+ item_y - E_DAY_VIEW_BAR_HEIGHT,
+ item_w,
+ E_DAY_VIEW_BAR_HEIGHT);
+ gdk_draw_rectangle (drawable, gc, TRUE,
+ item_x, item_y + item_h,
+ item_w, E_DAY_VIEW_BAR_HEIGHT);
+ }
+#endif
+
+ /* Draw the reminder & recurrence icons, if needed. */
+ num_icons = 0;
+ draw_reminder_icon = FALSE;
+ draw_recurrence_icon = FALSE;
+ icon_x = item_x + E_DAY_VIEW_BAR_WIDTH + E_DAY_VIEW_ICON_X_PAD;
+ icon_y = item_y + E_DAY_VIEW_EVENT_BORDER_HEIGHT
+ + E_DAY_VIEW_ICON_Y_PAD;
+ ico = event->ico;
+
+ if (ico->dalarm.enabled || ico->malarm.enabled
+ || ico->palarm.enabled || ico->aalarm.enabled) {
+ draw_reminder_icon = TRUE;
+ num_icons++;
+ }
+
+ if (ico->recur) {
+ draw_recurrence_icon = TRUE;
+ num_icons++;
+ }
+
+ if (num_icons != 0) {
+ if (item_h >= (E_DAY_VIEW_ICON_HEIGHT + E_DAY_VIEW_ICON_Y_PAD)
+ * num_icons) {
+ icon_x_inc = 0;
+ icon_y_inc = E_DAY_VIEW_ICON_HEIGHT
+ + E_DAY_VIEW_ICON_Y_PAD;
+ } else {
+ icon_x_inc = E_DAY_VIEW_ICON_WIDTH
+ + E_DAY_VIEW_ICON_X_PAD;
+ icon_y_inc = 0;
+ }
+
+ if (draw_reminder_icon) {
+ gdk_gc_set_clip_origin (gc, icon_x, icon_y);
+ gdk_gc_set_clip_mask (gc, day_view->reminder_mask);
+ gdk_draw_pixmap (drawable, gc,
+ day_view->reminder_icon,
+ 0, 0, icon_x, icon_y,
+ E_DAY_VIEW_ICON_WIDTH,
+ E_DAY_VIEW_ICON_HEIGHT);
+ icon_x += icon_x_inc;
+ icon_y += icon_y_inc;
+ }
+
+ if (draw_recurrence_icon) {
+ gdk_gc_set_clip_origin (gc, icon_x, icon_y);
+ gdk_gc_set_clip_mask (gc, day_view->recurrence_mask);
+ gdk_draw_pixmap (drawable, gc,
+ day_view->recurrence_icon,
+ 0, 0, icon_x, icon_y,
+ E_DAY_VIEW_ICON_WIDTH,
+ E_DAY_VIEW_ICON_HEIGHT);
+ }
+ gdk_gc_set_clip_mask (gc, NULL);
+ }
+}
+
+
+/* This is supposed to return the nearest item the the point and the distance.
+ Since we are the only item we just return ourself and 0 for the distance.
+ This is needed so that we get button/motion events. */
+static double
+e_day_view_main_item_point (GnomeCanvasItem *item, double x, double y,
+ int cx, int cy,
+ GnomeCanvasItem **actual_item)
+{
+ *actual_item = item;
+ return 0.0;
+}
+
+
+static gint
+e_day_view_main_item_event (GnomeCanvasItem *item, GdkEvent *event)
+{
+ EDayViewMainItem *dvtitem;
+
+ dvtitem = E_DAY_VIEW_MAIN_ITEM (item);
+
+ switch (event->type) {
+ case GDK_BUTTON_PRESS:
+
+ case GDK_BUTTON_RELEASE:
+
+ case GDK_MOTION_NOTIFY:
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+