/* Day view widget for gncal * * Copyright (C) 1998 The Free Software Foundation * * Authors: Federico Mena * Miguel de Icaza */ #include #include "gncal-day-view.h" #include "timeutil.h" #include "view-utils.h" #include "main.h" #include "eventedit.h" #include "popup-menu.h" #define TEXT_BORDER 2 #define MIN_INFO_WIDTH 50 static void gncal_day_view_class_init (GncalDayViewClass *class); static void gncal_day_view_init (GncalDayView *dview); static void gncal_day_view_destroy (GtkObject *object); static void gncal_day_view_realize (GtkWidget *widget); static void gncal_day_view_size_request (GtkWidget *widget, GtkRequisition *requisition); static gint gncal_day_view_expose (GtkWidget *widget, GdkEventExpose *event); static gint gncal_day_view_button_press (GtkWidget *widget, GdkEventButton *event); static GtkWidgetClass *parent_class; guint gncal_day_view_get_type (void) { static guint day_view_type = 0; if (!day_view_type) { GtkTypeInfo day_view_info = { "GncalDayView", sizeof (GncalDayView), sizeof (GncalDayViewClass), (GtkClassInitFunc) gncal_day_view_class_init, (GtkObjectInitFunc) gncal_day_view_init, (GtkArgSetFunc) NULL, (GtkArgGetFunc) NULL }; day_view_type = gtk_type_unique (gtk_widget_get_type (), &day_view_info); } return day_view_type; } static void gncal_day_view_class_init (GncalDayViewClass *class) { GtkObjectClass *object_class; GtkWidgetClass *widget_class; object_class = (GtkObjectClass *) class; widget_class = (GtkWidgetClass *) class; parent_class = gtk_type_class (gtk_widget_get_type ()); object_class->destroy = gncal_day_view_destroy; widget_class->realize = gncal_day_view_realize; widget_class->size_request = gncal_day_view_size_request; widget_class->expose_event = gncal_day_view_expose; widget_class->button_press_event = gncal_day_view_button_press; } static void gncal_day_view_init (GncalDayView *dview) { GTK_WIDGET_UNSET_FLAGS (dview, GTK_NO_WINDOW); dview->calendar = NULL; dview->lower = 0; dview->upper = 0; dview->shadow_type = GTK_SHADOW_ETCHED_IN; } static void gncal_day_view_destroy (GtkObject *object) { GncalDayView *dview; g_return_if_fail (object != NULL); g_return_if_fail (GNCAL_IS_DAY_VIEW (object)); dview = GNCAL_DAY_VIEW (object); if (dview->day_str) g_free (dview->day_str); if (dview->events) calendar_destroy_event_list (dview->events); if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); } static int new_appointment (GtkWidget *widget, gpointer data) { GncalDayView *dayview = GNCAL_DAY_VIEW (data); iCalObject *ico; GtkWidget *ee; struct tm tm; ico = ical_new ("", user_name, ""); ico->new = 1; tm = *localtime (&dayview->lower); tm.tm_hour = day_begin; ico->dtstart = mktime (&tm); tm.tm_hour++; ico->dtend = mktime (&tm); ee = event_editor_new (dayview->calendar, ico); gtk_widget_show (ee); return 1; } static void context_menu (GncalDayView *dayview, GdkEventButton *event) { static struct menu_item main_items[] = { { N_("New appointment..."), (GtkSignalFunc) new_appointment, NULL, TRUE } }; main_items [0].data = dayview; popup_menu (main_items, 1, event); } static void switch_to_day (GncalDayView *dayview) { } static gint gncal_day_view_button_press (GtkWidget *widget, GdkEventButton *event) { GncalDayView *dayview; dayview = GNCAL_DAY_VIEW (widget); if (event->button == 3) context_menu (dayview, event); if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) gnome_calendar_dayjump (dayview->calendar, dayview->lower); return TRUE; } GtkWidget * gncal_day_view_new (GnomeCalendar *calendar, time_t lower, time_t upper) { GncalDayView *dview; g_return_val_if_fail (calendar != NULL, NULL); dview = gtk_type_new (gncal_day_view_get_type ()); dview->calendar = calendar; dview->lower = lower; dview->upper = upper; dview->events = 0; gncal_day_view_update (dview, NULL, 0); return GTK_WIDGET (dview); } static void gncal_day_view_realize (GtkWidget *widget) { GdkWindowAttr attributes; gint attributes_mask; g_return_if_fail (widget != NULL); g_return_if_fail (GNCAL_IS_DAY_VIEW (widget)); GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); attributes.window_type = GDK_WINDOW_CHILD; attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); gdk_window_set_user_data (widget->window, widget); widget->style = gtk_style_attach (widget->style, widget->window); gdk_window_set_background (widget->window, &widget->style->bg[GTK_STATE_PRELIGHT]); } static void gncal_day_view_size_request (GtkWidget *widget, GtkRequisition *requisition) { GncalDayView *dview; int str_width, width; g_return_if_fail (widget != NULL); g_return_if_fail (GNCAL_IS_DAY_VIEW (widget)); g_return_if_fail (requisition != NULL); dview = GNCAL_DAY_VIEW (widget); /* border and min width */ str_width = gdk_string_width (widget->style->font, dview->day_str); width = MAX (MIN_INFO_WIDTH, str_width); requisition->width = 2 * (widget->style->klass->xthickness + TEXT_BORDER) + width; requisition->height = 2 * (widget->style->klass->ythickness + TEXT_BORDER); /* division line */ requisition->height += 2 * TEXT_BORDER + widget->style->klass->ythickness; /* title and at least one line of text */ requisition->height += 2 * (widget->style->font->ascent + widget->style->font->descent); } static gint gncal_day_view_expose (GtkWidget *widget, GdkEventExpose *event) { GncalDayView *dview; int x1, y1, width, height; GdkRectangle rect, dest; GdkFont *font; int str_width; GdkGC *gc; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GNCAL_IS_DAY_VIEW (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); if (!GTK_WIDGET_DRAWABLE (widget)) return FALSE; gc = widget->style->fg_gc [GTK_STATE_NORMAL]; dview = GNCAL_DAY_VIEW (widget); x1 = widget->style->klass->xthickness; y1 = widget->style->klass->ythickness; width = widget->allocation.width - 2 * x1; height = widget->allocation.height - 2 * y1; /* Clear and paint frame shadow */ gdk_window_clear_area (widget->window, event->area.x, event->area.y, event->area.width, event->area.height); gtk_draw_shadow (widget->style, widget->window, GTK_STATE_NORMAL, dview->shadow_type, 0, 0, widget->allocation.width, widget->allocation.height); /* Clear and paint title */ font = widget->style->font; rect.x = x1; rect.y = y1; rect.width = width; rect.height = 2 * TEXT_BORDER + font->ascent + font->descent; if (gdk_rectangle_intersect (&rect, &event->area, &dest)) { gdk_draw_rectangle (widget->window, widget->style->bg_gc[GTK_STATE_NORMAL], TRUE, dest.x, dest.y, dest.width, dest.height); dest = rect; dest.x += TEXT_BORDER; dest.y += TEXT_BORDER; dest.width -= 2 * TEXT_BORDER; dest.height -= 2 * TEXT_BORDER; gdk_gc_set_clip_rectangle (gc, &dest); str_width = gdk_string_width (font, dview->day_str); gdk_draw_string (widget->window, font, gc, dest.x + (dest.width - str_width) / 2, dest.y + font->ascent, dview->day_str); gdk_gc_set_clip_rectangle (gc, NULL); } /* Division line */ gtk_draw_hline (widget->style, widget->window, GTK_STATE_NORMAL, rect.x, rect.x + rect.width - 1, rect.y + rect.height); /* Text */ if (dview->events != NULL){ rect.x = x1 + TEXT_BORDER; rect.y = y1 + 3 * TEXT_BORDER + font->ascent + font->descent + widget->style->klass->ythickness; rect.width = width - 2 * TEXT_BORDER; rect.height = height - (rect.y - y1) - TEXT_BORDER; if (gdk_rectangle_intersect (&rect, &event->area, &dest)) view_utils_draw_events ( widget, widget->window, gc, &rect, VIEW_UTILS_DRAW_END | VIEW_UTILS_DRAW_SPLIT, dview->events, dview->lower, dview->upper); } return FALSE; } void gncal_day_view_update (GncalDayView *dview, iCalObject *ico, int flags) { struct tm tm; char buf[256]; g_return_if_fail (dview != NULL); g_return_if_fail (GNCAL_IS_DAY_VIEW (dview)); g_return_if_fail (dview->calendar->cal); if (dview->day_str) g_free (dview->day_str); tm = *localtime (&dview->lower); strftime (buf, sizeof (buf)-1, "%A %d", &tm); dview->day_str = g_strdup (buf); if (dview->events) calendar_destroy_event_list (dview->events); dview->events = calendar_get_events_in_range (dview->calendar->cal, dview->lower, dview->upper); gtk_widget_draw (GTK_WIDGET (dview), NULL); } void gncal_day_view_set_bounds (GncalDayView *dview, time_t lower, time_t upper) { g_return_if_fail (dview != NULL); g_return_if_fail (GNCAL_IS_DAY_VIEW (dview)); if ((lower != dview->lower) || (upper != dview->upper)) { dview->lower = lower; dview->upper = upper; gncal_day_view_update (dview, NULL, 0); } } void gncal_day_view_set_shadow (GncalDayView *dview, GtkShadowType shadow_type) { g_return_if_fail (dview != NULL); g_return_if_fail (GNCAL_IS_DAY_VIEW (dview)); if (shadow_type != dview->shadow_type) { dview->shadow_type = shadow_type; gtk_widget_draw (GTK_WIDGET (dview), NULL); } }