aboutsummaryrefslogtreecommitdiffstats
path: root/calendar/gui/e-day-view-top-item.c
diff options
context:
space:
mode:
Diffstat (limited to 'calendar/gui/e-day-view-top-item.c')
-rw-r--r--calendar/gui/e-day-view-top-item.c553
1 files changed, 553 insertions, 0 deletions
diff --git a/calendar/gui/e-day-view-top-item.c b/calendar/gui/e-day-view-top-item.c
new file mode 100644
index 0000000000..fe19c6b491
--- /dev/null
+++ b/calendar/gui/e-day-view-top-item.c
@@ -0,0 +1,553 @@
+/* -*- 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
+ */
+
+/*
+ * EDayViewTopItem - displays the top part of the Day/Work Week calendar view.
+ */
+
+#include "e-day-view-top-item.h"
+
+static void e_day_view_top_item_class_init (EDayViewTopItemClass *class);
+static void e_day_view_top_item_init (EDayViewTopItem *dvtitem);
+
+static void e_day_view_top_item_set_arg (GtkObject *o,
+ GtkArg *arg,
+ guint arg_id);
+static void e_day_view_top_item_update (GnomeCanvasItem *item,
+ double *affine,
+ ArtSVP *clip_path,
+ int flags);
+static void e_day_view_top_item_draw (GnomeCanvasItem *item,
+ GdkDrawable *drawable,
+ int x,
+ int y,
+ int width,
+ int height);
+static void e_day_view_top_item_draw_long_event (EDayViewTopItem *dvtitem,
+ gint event_num,
+ GdkDrawable *drawable,
+ int x,
+ int y,
+ int width,
+ int height);
+static void e_day_view_top_item_draw_triangle (EDayViewTopItem *dvtitem,
+ GdkDrawable *drawable,
+ gint x,
+ gint y,
+ gint w,
+ gint h);
+static double e_day_view_top_item_point (GnomeCanvasItem *item,
+ double x,
+ double y,
+ int cx,
+ int cy,
+ GnomeCanvasItem **actual_item);
+static gint e_day_view_top_item_event (GnomeCanvasItem *item,
+ GdkEvent *event);
+
+
+static GnomeCanvasItemClass *parent_class;
+
+/* The arguments we take */
+enum {
+ ARG_0,
+ ARG_DAY_VIEW
+};
+
+
+GtkType
+e_day_view_top_item_get_type (void)
+{
+ static GtkType e_day_view_top_item_type = 0;
+
+ if (!e_day_view_top_item_type) {
+ GtkTypeInfo e_day_view_top_item_info = {
+ "EDayViewTopItem",
+ sizeof (EDayViewTopItem),
+ sizeof (EDayViewTopItemClass),
+ (GtkClassInitFunc) e_day_view_top_item_class_init,
+ (GtkObjectInitFunc) e_day_view_top_item_init,
+ NULL, /* reserved_1 */
+ NULL, /* reserved_2 */
+ (GtkClassInitFunc) NULL
+ };
+
+ e_day_view_top_item_type = gtk_type_unique (gnome_canvas_item_get_type (), &e_day_view_top_item_info);
+ }
+
+ return e_day_view_top_item_type;
+}
+
+
+static void
+e_day_view_top_item_class_init (EDayViewTopItemClass *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 ("EDayViewTopItem::day_view",
+ GTK_TYPE_POINTER, GTK_ARG_WRITABLE,
+ ARG_DAY_VIEW);
+
+ object_class->set_arg = e_day_view_top_item_set_arg;
+
+ /* GnomeCanvasItem method overrides */
+ item_class->update = e_day_view_top_item_update;
+ item_class->draw = e_day_view_top_item_draw;
+ item_class->point = e_day_view_top_item_point;
+ item_class->event = e_day_view_top_item_event;
+}
+
+
+static void
+e_day_view_top_item_init (EDayViewTopItem *dvtitem)
+{
+ dvtitem->day_view = NULL;
+}
+
+
+static void
+e_day_view_top_item_set_arg (GtkObject *o, GtkArg *arg, guint arg_id)
+{
+ GnomeCanvasItem *item;
+ EDayViewTopItem *dvtitem;
+
+ item = GNOME_CANVAS_ITEM (o);
+ dvtitem = E_DAY_VIEW_TOP_ITEM (o);
+
+ switch (arg_id){
+ case ARG_DAY_VIEW:
+ dvtitem->day_view = GTK_VALUE_POINTER (*arg);
+ break;
+ }
+}
+
+
+static void
+e_day_view_top_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_top_item_draw (GnomeCanvasItem *canvas_item,
+ GdkDrawable *drawable,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ EDayViewTopItem *dvtitem;
+ EDayView *day_view;
+ GtkStyle *style;
+ GdkGC *fg_gc, *bg_gc, *light_gc, *dark_gc;
+ gchar buffer[128];
+ GdkRectangle clip_rect;
+ GdkFont *font;
+ gint canvas_width, canvas_height, left_edge, day, date_width, date_x;
+ gint item_height, event_num;
+ struct tm *day_start;
+
+#if 0
+ g_print ("In e_day_view_top_item_draw %i,%i %ix%i\n",
+ x, y, width, height);
+#endif
+ dvtitem = E_DAY_VIEW_TOP_ITEM (canvas_item);
+ day_view = dvtitem->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];
+ canvas_width = GTK_WIDGET (canvas_item->canvas)->allocation.width;
+ canvas_height = GTK_WIDGET (canvas_item->canvas)->allocation.height;
+ left_edge = 0;
+ item_height = day_view->top_row_height - E_DAY_VIEW_TOP_CANVAS_Y_GAP;
+
+ /* Clear the entire background. */
+ gdk_draw_rectangle (drawable, dark_gc, TRUE,
+ left_edge - x, 0,
+ canvas_width - left_edge, height);
+
+ /* Draw the shadow around the dates. */
+ gdk_draw_line (drawable, light_gc,
+ left_edge + 1 - x, 1 - y,
+ canvas_width - 2 - x, 1 - y);
+ gdk_draw_line (drawable, light_gc,
+ left_edge + 1 - x, 2 - y,
+ left_edge + 1 - x, item_height - 1 - y);
+
+ /* Draw the background for the dates. */
+ gdk_draw_rectangle (drawable, bg_gc, TRUE,
+ left_edge + 2 - x, 2 - y,
+ canvas_width - left_edge - 3,
+ item_height - 3);
+
+ /* Draw the selection background. */
+ if (day_view->selection_start_col != -1) {
+ gint start_col, end_col, rect_x, rect_y, rect_w, rect_h;
+
+ start_col = day_view->selection_start_col;
+ end_col = day_view->selection_end_col;
+
+ if (end_col > start_col
+ || day_view->selection_start_row == -1
+ || day_view->selection_end_row == -1) {
+ rect_x = day_view->day_offsets[start_col];
+ rect_y = item_height;
+ rect_w = day_view->day_offsets[end_col + 1] - rect_x;
+ rect_h = canvas_height - 1 - rect_y;
+
+ gdk_draw_rectangle (drawable, style->white_gc, TRUE,
+ rect_x - x, rect_y - y,
+ rect_w, rect_h);
+ }
+ }
+
+ /* Draw the date. Set a clipping rectangle so we don't draw over the
+ next day. */
+ for (day = 0; day < day_view->days_shown; day++) {
+ day_start = localtime (&day_view->day_starts[day]);
+
+ if (day_view->date_format == E_DAY_VIEW_DATE_FULL)
+ strftime (buffer, 128, "%d %B", day_start);
+ else if (day_view->date_format == E_DAY_VIEW_DATE_ABBREVIATED)
+ strftime (buffer, 128, "%d %b", day_start);
+ else
+ strftime (buffer, 128, "%d", day_start);
+
+ clip_rect.x = day_view->day_offsets[day] - x;
+ clip_rect.y = 2 - y;
+ clip_rect.width = day_view->day_widths[day];
+ clip_rect.height = item_height - 2;
+ gdk_gc_set_clip_rectangle (fg_gc, &clip_rect);
+
+ date_width = gdk_string_width (font, buffer);
+ date_x = day_view->day_offsets[day] + (day_view->day_widths[day] - date_width) / 2;
+ gdk_draw_string (drawable, font, fg_gc,
+ date_x - x, 3 + font->ascent - y, buffer);
+
+ gdk_gc_set_clip_rectangle (fg_gc, NULL);
+
+ /* Draw the lines down the left and right of the date cols. */
+ if (day != 0) {
+ gdk_draw_line (drawable, light_gc,
+ day_view->day_offsets[day] - x,
+ 4 - y,
+ day_view->day_offsets[day] - x,
+ item_height - 4 - y);
+
+ gdk_draw_line (drawable, dark_gc,
+ day_view->day_offsets[day] - 1 - x,
+ 4 - y,
+ day_view->day_offsets[day] - 1 - x,
+ item_height - 4 - y);
+ }
+
+ /* Draw the lines between each column. */
+ if (day != 0) {
+ gdk_draw_line (drawable, style->black_gc,
+ day_view->day_offsets[day] - x,
+ item_height - y,
+ day_view->day_offsets[day] - x,
+ canvas_height - y);
+ }
+ }
+
+ /* Draw the long events. */
+ for (event_num = 0; event_num < day_view->long_events->len;
+ event_num++) {
+ e_day_view_top_item_draw_long_event (dvtitem, event_num,
+ drawable,
+ x, y, width, height);
+ }
+}
+
+
+/* This draws one event in the top canvas. */
+static void
+e_day_view_top_item_draw_long_event (EDayViewTopItem *dvtitem,
+ gint event_num,
+ GdkDrawable *drawable,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ EDayView *day_view;
+ EDayViewEvent *event;
+ GtkStyle *style;
+ GdkGC *gc, *fg_gc, *bg_gc;
+ GdkFont *font;
+ gint start_day, end_day;
+ gint item_x, item_y, item_w, item_h;
+ gint text_x, icon_x, icon_y, icon_x_inc;
+ iCalObject *ico;
+ gchar buffer[16];
+ gint hour, minute, offset, time_width;
+ gboolean draw_start_triangle, draw_end_triangle;
+
+ day_view = dvtitem->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 == E_DAY_VIEW_LONG_EVENT
+ && day_view->drag_event_num == event_num)
+ return;
+
+ if (!e_day_view_get_long_event_position (day_view, event_num,
+ &start_day, &end_day,
+ &item_x, &item_y,
+ &item_w, &item_h))
+ return;
+
+ event = &g_array_index (day_view->long_events, EDayViewEvent,
+ event_num);
+
+ style = GTK_WIDGET (day_view)->style;
+ font = style->font;
+ gc = day_view->main_gc;
+ fg_gc = style->fg_gc[GTK_STATE_NORMAL];
+ bg_gc = style->bg_gc[GTK_STATE_NORMAL];
+ ico = event->ico;
+
+ /* Draw the lines across the top & bottom of the entire event. */
+ gdk_draw_line (drawable, fg_gc,
+ item_x - x, item_y - y,
+ item_x + item_w - 1 - x, item_y - y);
+ gdk_draw_line (drawable, fg_gc,
+ item_x - x, item_y + item_h - 1 - y,
+ item_x + item_w - 1 - x, item_y + item_h - 1 - y);
+
+ /* Fill it in. */
+ gdk_draw_rectangle (drawable, bg_gc, TRUE,
+ item_x - x, item_y + 1 - y,
+ item_w, item_h - 2);
+
+ /* When resizing we don't draw the triangles.*/
+ draw_start_triangle = TRUE;
+ draw_end_triangle = TRUE;
+ if (day_view->resize_drag_pos != E_DAY_VIEW_POS_NONE
+ && day_view->resize_event_day == E_DAY_VIEW_LONG_EVENT
+ && day_view->resize_event_num == event_num) {
+ if (day_view->resize_drag_pos == E_DAY_VIEW_POS_LEFT_EDGE)
+ draw_start_triangle = FALSE;
+
+ if (day_view->resize_drag_pos == E_DAY_VIEW_POS_RIGHT_EDGE)
+ draw_end_triangle = FALSE;
+ }
+
+ /* If the event starts before the first day shown, draw a triangle,
+ else just draw a vertical line down the left. */
+ if (draw_start_triangle
+ && event->start < day_view->day_starts[start_day]) {
+ e_day_view_top_item_draw_triangle (dvtitem, drawable,
+ item_x - x, item_y - y,
+ -E_DAY_VIEW_BAR_WIDTH,
+ item_h);
+ } else {
+ gdk_draw_line (drawable, fg_gc,
+ item_x - x, item_y - y,
+ item_x - x, item_y + item_h - 1 - y);
+ }
+
+ /* Similar for the event end. */
+ if (draw_end_triangle
+ && event->end > day_view->day_starts[end_day + 1]) {
+ e_day_view_top_item_draw_triangle (dvtitem, drawable,
+ item_x + item_w - 1 - x,
+ item_y - y,
+ E_DAY_VIEW_BAR_WIDTH,
+ item_h);
+ } else {
+ gdk_draw_line (drawable, fg_gc,
+ item_x + item_w - 1 - x,
+ item_y - y,
+ item_x + item_w - 1 - x,
+ item_y + item_h - 1 - y);
+ }
+
+ /* If we are editing the event we don't show the icons or the start
+ & end times. */
+ if (day_view->editing_event_day == E_DAY_VIEW_LONG_EVENT
+ && day_view->editing_event_num == event_num)
+ return;
+
+ /* Determine the position of the label, so we know where to place the
+ icons. Note that since the top canvas never scrolls we don't need
+ to take the scroll offset into account. It will always be 0. */
+ text_x = event->canvas_item->x1;
+
+ /* Draw the icons. */
+ icon_x_inc = E_DAY_VIEW_ICON_WIDTH + E_DAY_VIEW_ICON_X_PAD;
+ icon_x = text_x - icon_x_inc - x;
+ icon_y = item_y + 1 + E_DAY_VIEW_ICON_Y_PAD - y;
+
+ if (ico->recur) {
+ 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);
+ icon_x -= icon_x_inc;
+ }
+
+ if (ico->dalarm.enabled || ico->malarm.enabled
+ || ico->palarm.enabled || ico->aalarm.enabled) {
+ 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;
+ }
+ gdk_gc_set_clip_mask (gc, NULL);
+
+ /* Draw the start & end times, if necessary.
+ Note that GtkLabel adds 1 to the ascent so we must do that to be
+ level with it. */
+ if (event->start > day_view->day_starts[start_day]) {
+ offset = day_view->first_hour_shown * 60
+ + day_view->first_minute_shown + event->start_minute;
+ hour = offset / 60;
+ minute = offset % 60;
+ sprintf (buffer, "%02i:%02i", hour, minute);
+ gdk_draw_string (drawable, font, fg_gc,
+ item_x + + E_DAY_VIEW_LONG_EVENT_X_PAD - x,
+ item_y + E_DAY_VIEW_LONG_EVENT_Y_PAD + font->ascent + 1 - y,
+ buffer);
+ }
+
+ if (event->end < day_view->day_starts[end_day + 1]) {
+ offset = day_view->first_hour_shown * 60
+ + day_view->first_minute_shown + event->end_minute;
+ hour = offset / 60;
+ minute = offset % 60;
+ sprintf (buffer, "%02i:%02i", hour, minute);
+ time_width = day_view->small_hour_widths[hour]
+ + day_view->max_minute_width + day_view->colon_width;
+ gdk_draw_string (drawable, font, fg_gc,
+ item_x + item_w - E_DAY_VIEW_LONG_EVENT_X_PAD - time_width - E_DAY_VIEW_LONG_EVENT_TIME_X_PAD - x,
+ item_y + E_DAY_VIEW_LONG_EVENT_Y_PAD + font->ascent + 1 - y,
+ buffer);
+ }
+}
+
+
+/* This draws a little triangle to indicate that an event extends past
+ the days visible on screen. */
+static void
+e_day_view_top_item_draw_triangle (EDayViewTopItem *dvtitem,
+ GdkDrawable *drawable,
+ gint x,
+ gint y,
+ gint w,
+ gint h)
+{
+ EDayView *day_view;
+ GtkStyle *style;
+ GdkGC *fg_gc, *bg_gc;
+ GdkPoint points[3];
+
+ day_view = dvtitem->day_view;
+
+ style = GTK_WIDGET (day_view)->style;
+ fg_gc = style->fg_gc[GTK_STATE_NORMAL];
+ bg_gc = style->bg_gc[GTK_STATE_NORMAL];
+
+ points[0].x = x;
+ points[0].y = y;
+ points[1].x = x + w;
+ points[1].y = y + (h / 2) - 1;
+ points[2].x = x;
+ points[2].y = y + h - 1;
+
+ gdk_draw_polygon (drawable, bg_gc, TRUE, points, 3);
+ gdk_draw_line (drawable, fg_gc, x, y, x + w, y + (h / 2) - 1);
+ gdk_draw_line (drawable, fg_gc, x, y + h - 1, x + w, y + h - (h / 2));
+}
+
+
+/* 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_top_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_top_item_event (GnomeCanvasItem *item, GdkEvent *event)
+{
+ EDayViewTopItem *dvtitem;
+
+ dvtitem = E_DAY_VIEW_TOP_ITEM (item);
+
+ switch (event->type) {
+ case GDK_BUTTON_PRESS:
+
+ case GDK_BUTTON_RELEASE:
+
+ case GDK_MOTION_NOTIFY:
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+