/* Day view widget for gncal
*
* Copyright (C) 1998 The Free Software Foundation
*
* Author: Federico Mena <federico@nuclecu.unam.mx>
*/
#include <gtk/gtksignal.h>
#include "gncal-day-view.h"
#include "timeutil.h"
#include "view-utils.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 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;
}
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)
g_list_free (dview->events);
if (GTK_OBJECT_CLASS (parent_class)->destroy)
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}
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;
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;
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 (widget->style->fg_gc[GTK_STATE_NORMAL], &dest);
str_width = gdk_string_width (font, dview->day_str);
gdk_draw_string (widget->window,
font,
widget->style->fg_gc[GTK_STATE_NORMAL],
dest.x + (dest.width - str_width) / 2,
dest.y + font->ascent,
dview->day_str);
gdk_gc_set_clip_rectangle (widget->style->fg_gc[GTK_STATE_NORMAL], 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 */
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,
widget->style->fg_gc[GTK_STATE_NORMAL],
&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));
if (!dview->calendar->cal)
return;
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)
g_list_free (dview->events);
dview->events = calendar_get_events_in_range (dview->calendar->cal,
dview->lower,
dview->upper,
calendar_compare_by_dtstart);
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);
}
}