diff options
Diffstat (limited to 'calendar/gui/gnome-month-item.c')
-rw-r--r-- | calendar/gui/gnome-month-item.c | 573 |
1 files changed, 573 insertions, 0 deletions
diff --git a/calendar/gui/gnome-month-item.c b/calendar/gui/gnome-month-item.c new file mode 100644 index 0000000000..fc30cdd85b --- /dev/null +++ b/calendar/gui/gnome-month-item.c @@ -0,0 +1,573 @@ +/* General-purpose monthly calendar canvas item for GNOME + * + * Copyright (C) 1998 Red Hat Software, Inc. + * + * Author: Federico Mena <federico@nuclecu.unam.mx> + */ + +#include <config.h> +#include <math.h> +#include <time.h> +#include <gnome.h> +#include "gnome-month-item.h" + + +/* These are indices into the items array of a GnomeMonthItem structure */ +enum { + ITEM_HEAD_GROUP = 0, + ITEM_HEAD_BOX = 7, + ITEM_HEAD_LABEL = 14 +}; + +enum { + ARG_0, + ARG_YEAR, + ARG_MONTH, + ARG_X, + ARG_Y, + ARG_WIDTH, + ARG_HEIGHT, + ARG_ANCHOR, + ARG_PADDING, + ARG_DAY_NAMES, + ARG_HEADING_HEIGHT, + ARG_HEADING_ANCHOR, + ARG_START_ON_MONDAY +}; + + +static void gnome_month_item_class_init (GnomeMonthItemClass *class); +static void gnome_month_item_init (GnomeMonthItem *mitem); +static void gnome_month_item_destroy (GtkObject *object); +static void gnome_month_item_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void gnome_month_item_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); + + + +static GnomeCanvasGroupClass *parent_class; + + +GtkType +gnome_month_item_get_type (void) +{ + static GtkType month_item_type = 0; + + if (!month_item_type) { + GtkTypeInfo month_item_info = { + "GnomeMonthItem", + sizeof (GnomeMonthItem), + sizeof (GnomeMonthItemClass), + (GtkClassInitFunc) gnome_month_item_class_init, + (GtkObjectInitFunc) gnome_month_item_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + month_item_type = gtk_type_unique (gnome_canvas_group_get_type (), &month_item_info); + } + + return month_item_type; +} + +static void +gnome_month_item_class_init (GnomeMonthItemClass *class) +{ + GtkObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + object_class = (GtkObjectClass *) class; + item_class = (GnomeCanvasItemClass *) class; + + parent_class = gtk_type_class (gnome_canvas_group_get_type ()); + + gtk_object_add_arg_type ("GnomeMonthItem::year", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_YEAR); + gtk_object_add_arg_type ("GnomeMonthItem::month", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_MONTH); + gtk_object_add_arg_type ("GnomeMonthItem::x", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X); + gtk_object_add_arg_type ("GnomeMonthItem::y", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y); + gtk_object_add_arg_type ("GnomeMonthItem::width", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_WIDTH); + gtk_object_add_arg_type ("GnomeMonthItem::height", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_HEIGHT); + gtk_object_add_arg_type ("GnomeMonthItem::anchor", GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, ARG_ANCHOR); + gtk_object_add_arg_type ("GnomeMonthItem::padding", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_PADDING); + gtk_object_add_arg_type ("GnomeMonthItem::day_names", GTK_TYPE_POINTER, GTK_ARG_READABLE, ARG_DAY_NAMES); + gtk_object_add_arg_type ("GnomeMonthItem::heading_height", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_HEADING_HEIGHT); + gtk_object_add_arg_type ("GnomeMonthItem::heading_anchor", GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, ARG_HEADING_ANCHOR); + gtk_object_add_arg_type ("GnomeMonthItem::start_on_monday", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_START_ON_MONDAY); + + object_class->destroy = gnome_month_item_destroy; + object_class->set_arg = gnome_month_item_set_arg; + object_class->get_arg = gnome_month_item_get_arg; +} + +/* Takes an anchor specification and the corners of a rectangle, and returns an anchored point with + * respect to that rectangle. + */ +static void +get_label_anchor (GtkAnchorType anchor, double x1, double y1, double x2, double y2, double *x, double *y) +{ + switch (anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + *x = x1; + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + *x = (x1 + x2) / 2.0; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + *x = x2; + break; + } + + switch (anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + *y = y1; + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + *y = (y1 + y2) / 2.0; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + *y = y2; + break; + } +} + +/* Resets the position of the day name headings in the calendar */ +static void +reshape_headings (GnomeMonthItem *mitem) +{ + double width; + int i; + double x, y; + + width = mitem->width / 7; + + for (i = 0; i < 7; i++) { + /* Group */ + gnome_canvas_item_set (mitem->items[ITEM_HEAD_GROUP + i], + "x", width * i, + "y", 0.0, + NULL); + + /* Box */ + gnome_canvas_item_set (mitem->items[ITEM_HEAD_BOX + i], + "x1", 0.0, + "y1", 0.0, + "x2", width, + "y2", mitem->head_height, + NULL); + + /* Label */ + get_label_anchor (mitem->head_anchor, + mitem->padding, + mitem->padding, + width - mitem->padding, + mitem->head_height - mitem->padding, + &x, &y); + + gnome_canvas_item_set (mitem->items[ITEM_HEAD_LABEL + i], + "x", x, + "y", y, + "anchor", mitem->head_anchor, + NULL); + } +} + +/* Changes the positions and resizes the items in the calendar to match the new size of the + * calendar. + */ +static void +reshape (GnomeMonthItem *mitem) +{ + reshape_headings (mitem); +} + +/* Creates the items for the day name headings */ +static void +create_headings (GnomeMonthItem *mitem) +{ + int i; + + /* Just create the items; they will be positioned and configured by a call to reshape() */ + + for (i = 0; i < 7; i++) { + /* Group */ + mitem->items[ITEM_HEAD_GROUP + i] = + gnome_canvas_item_new (GNOME_CANVAS_GROUP (mitem), + gnome_canvas_group_get_type (), + NULL); + + /* Box */ + mitem->items[ITEM_HEAD_BOX + i] = + gnome_canvas_item_new (GNOME_CANVAS_GROUP (mitem->items[ITEM_HEAD_GROUP + i]), + gnome_canvas_rect_get_type (), + "fill_color", "black", + NULL); + + /* Label */ + mitem->items[ITEM_HEAD_LABEL + i] = + gnome_canvas_item_new (GNOME_CANVAS_GROUP (mitem->items[ITEM_HEAD_GROUP + i]), + gnome_canvas_text_get_type (), + "fill_color", "white", + NULL); + } +} + +/* Returns a normalized day index (as in sunday to saturday) based on a visible day index */ +static int +get_day_index (GnomeMonthItem *mitem, int draw_index) +{ + if (mitem->start_on_monday) + return (draw_index + 1) % 7; + else + return draw_index; +} + +/* Resets the text of the day name headings */ +static void +set_day_names (GnomeMonthItem *mitem) +{ + int i; + + for (i = 0; i < 7; i++) + gnome_canvas_item_set (mitem->items[ITEM_HEAD_LABEL + get_day_index (mitem, i)], + "text", mitem->day_names[get_day_index (mitem, i)], + NULL); +} + +/* Creates all the canvas items that make up the calendar */ +static void +create_items (GnomeMonthItem *mitem) +{ + /* 7 heading groups + * 7 heading boxes + * 7 heading labels + * ------------------ + * 21 items total + */ + + mitem->items = g_new (GnomeCanvasItem *, 21); + + create_headings (mitem); + /* FIXME */ + + /* Initialize by default to three-letter day names */ + + mitem->day_names[0] = _("Sun"); + mitem->day_names[1] = _("Mon"); + mitem->day_names[2] = _("Tue"); + mitem->day_names[3] = _("Wed"); + mitem->day_names[4] = _("Thu"); + mitem->day_names[5] = _("Fri"); + mitem->day_names[6] = _("Sat"); + + set_day_names (mitem); + reshape (mitem); +} + +static void +gnome_month_item_init (GnomeMonthItem *mitem) +{ + time_t t; + struct tm *tm; + + /* Initialize to the current month by default */ + + t = time (NULL); + tm = localtime (&t); + + mitem->year = tm->tm_year + 1900; + mitem->month = tm->tm_mon; + + mitem->x = 0.0; + mitem->y = 0.0; + mitem->width = 150.0; /* not unreasonable defaults, I hope */ + mitem->height = 100.0; + mitem->anchor = GTK_ANCHOR_NW; + mitem->padding = 0.0; + mitem->head_height = 14.0; + mitem->head_anchor = GTK_ANCHOR_CENTER; +} + +GnomeCanvasItem * +gnome_month_item_new (GnomeCanvasGroup *parent) +{ + GnomeMonthItem *mitem; + + g_return_val_if_fail (parent != NULL, NULL); + g_return_val_if_fail (GNOME_IS_CANVAS_GROUP (parent), NULL); + + mitem = GNOME_MONTH_ITEM (gnome_canvas_item_new (parent, + gnome_month_item_get_type (), + NULL)); + + gnome_month_item_construct (mitem); + + return GNOME_CANVAS_ITEM (mitem); +} + +void +gnome_month_item_construct (GnomeMonthItem *mitem) +{ + g_return_if_fail (mitem != NULL); + g_return_if_fail (GNOME_IS_MONTH_ITEM (mitem)); + + create_items (mitem); +} + +static void +free_day_names (GnomeMonthItem *mitem) +{ + int i; + + if (mitem->day_names[0]) + for (i = 0; i < 7; i++) + g_free (mitem->day_names[i]); +} + +static void +gnome_month_item_destroy (GtkObject *object) +{ + GnomeMonthItem *mitem; + + g_return_if_fail (object != NULL); + g_return_if_fail (GNOME_IS_MONTH_ITEM (object)); + + mitem = GNOME_MONTH_ITEM (object); + + free_day_names (mitem); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +/* Recalculates the position of the toplevel calendar group based on the logical position and anchor */ +static void +reanchor (GnomeMonthItem *mitem) +{ + double x, y; + + x = mitem->x; + y = mitem->y; + + switch (mitem->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + x -= mitem->width / 2; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + x -= mitem->width; + break; + } + + switch (mitem->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + y -= mitem->height / 2; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + y -= mitem->height; + break; + } + + /* Explicitly use the canvas group class prefix since the month item class has x and y + * arguments as well. + */ + + gnome_canvas_item_set (GNOME_CANVAS_ITEM (mitem), + "GnomeCanvasGroup::x", x, + "GnomeCanvasGroup::y", y, + NULL); +} + +static void +recalc_month (GnomeMonthItem *mitem) +{ + /* FIXME */ +} + +static void +gnome_month_item_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + GnomeMonthItem *mitem; + char **day_names; + int i; + + mitem = GNOME_MONTH_ITEM (object); + + switch (arg_id) { + case ARG_YEAR: + mitem->year = GTK_VALUE_UINT (*arg); + recalc_month (mitem); + break; + + case ARG_MONTH: + mitem->month = GTK_VALUE_UINT (*arg); + recalc_month (mitem); + break; + + case ARG_X: + mitem->x = GTK_VALUE_DOUBLE (*arg); + reanchor (mitem); + break; + + case ARG_Y: + mitem->y = GTK_VALUE_DOUBLE (*arg); + reanchor (mitem); + break; + + case ARG_WIDTH: + mitem->width = fabs (GTK_VALUE_DOUBLE (*arg)); + reanchor (mitem); + reshape (mitem); + break; + + case ARG_HEIGHT: + mitem->height = fabs (GTK_VALUE_DOUBLE (*arg)); + reanchor (mitem); + reshape (mitem); + break; + + case ARG_ANCHOR: + mitem->anchor = GTK_VALUE_ENUM (*arg); + reanchor (mitem); + break; + + case ARG_PADDING: + mitem->padding = fabs (GTK_VALUE_DOUBLE (*arg)); + reshape (mitem); + break; + + case ARG_DAY_NAMES: + day_names = GTK_VALUE_POINTER (*arg); + + /* First, check that none of the names is null */ + + for (i = 0; i < 7; i++) + if (!day_names[i]) { + g_warning ("Day number %d was NULL; day names cannot be NULL!", i); + return; + } + + /* Set the new names */ + + free_day_names (mitem); + for (i = 0; i < 7; i++) + mitem->day_names[i] = g_strdup (day_names[i]); + + set_day_names (mitem); + break; + + case ARG_HEADING_HEIGHT: + mitem->head_height = fabs (GTK_VALUE_DOUBLE (*arg)); + reshape (mitem); + break; + + case ARG_HEADING_ANCHOR: + mitem->head_anchor = GTK_VALUE_ENUM (*arg); + reshape (mitem); + break; + + case ARG_START_ON_MONDAY: + mitem->start_on_monday = GTK_VALUE_BOOL (*arg); + set_day_names (mitem); + break; + + default: + break; + } +} + +static void +gnome_month_item_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + GnomeMonthItem *mitem; + + mitem = GNOME_MONTH_ITEM (object); + + switch (arg_id) { + case ARG_YEAR: + GTK_VALUE_UINT (*arg) = mitem->year; + break; + + case ARG_MONTH: + GTK_VALUE_UINT (*arg) = mitem->month; + break; + + case ARG_X: + GTK_VALUE_DOUBLE (*arg) = mitem->x; + break; + + case ARG_Y: + GTK_VALUE_DOUBLE (*arg) = mitem->y; + break; + + case ARG_WIDTH: + GTK_VALUE_DOUBLE (*arg) = mitem->width; + break; + + case ARG_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = mitem->height; + break; + + case ARG_ANCHOR: + GTK_VALUE_ENUM (*arg) = mitem->anchor; + break; + + case ARG_PADDING: + GTK_VALUE_DOUBLE (*arg) = mitem->padding; + break; + + case ARG_HEADING_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = mitem->head_height; + break; + + case ARG_HEADING_ANCHOR: + GTK_VALUE_ENUM (*arg) = mitem->head_anchor; + break; + + case ARG_START_ON_MONDAY: + GTK_VALUE_BOOL (*arg) = mitem->start_on_monday; + break; + + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} |