/* General-purpose monthly calendar canvas item for GNOME * * Copyright (C) 1998 Red Hat Software, Inc. * * Author: Federico Mena */ #include #include #include #include #include "gnome-month-item.h" #define DEFAULT_FONT "-*-helvetica-medium-r-normal--10-*-*-*-p-*-*-*" /* Number of days in a month, for normal and leap years */ static const int days_in_month[2][12] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; /* The weird month of September 1752, where 3 Sep through 13 Sep were eliminated due to the * Gregorian reformation. */ static const int sept_1752[42] = { 0, 0, 1, 2, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; #define REFORMATION_DAY 639787 /* First day of the reformation, counted from 1 Jan 1 */ #define MISSING_DAYS 11 /* They corrected out 11 days */ #define THURSDAY 4 /* First day of reformation */ #define SATURDAY 6 /* Offset value; 1 Jan 1 was a Saturday */ #define SEPT_1752_START 2 /* Start day within month */ #define SEPT_1752_END 20 /* End day within month */ enum { ARG_0, ARG_YEAR, ARG_MONTH, ARG_X, ARG_Y, ARG_WIDTH, ARG_HEIGHT, ARG_ANCHOR, ARG_HEAD_PADDING, ARG_DAY_PADDING, ARG_DAY_NAMES, ARG_HEADING_HEIGHT, ARG_HEADING_ANCHOR, ARG_DAY_ANCHOR, ARG_START_ON_MONDAY, ARG_HEAD_FONT, ARG_HEAD_FONT_GDK, ARG_DAY_FONT, ARG_DAY_FONT_GDK, ARG_HEAD_COLOR, ARG_HEAD_COLOR_GDK, ARG_OUTLINE_COLOR, ARG_OUTLINE_COLOR_GDK, ARG_DAY_BOX_COLOR, ARG_DAY_BOX_COLOR_GDK, ARG_DAY_COLOR, ARG_DAY_COLOR_GDK }; 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::heading_padding", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_HEAD_PADDING); gtk_object_add_arg_type ("GnomeMonthItem::day_padding", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_DAY_PADDING); gtk_object_add_arg_type ("GnomeMonthItem::day_names", GTK_TYPE_POINTER, GTK_ARG_WRITABLE, 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::day_anchor", GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, ARG_DAY_ANCHOR); gtk_object_add_arg_type ("GnomeMonthItem::start_on_monday", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_START_ON_MONDAY); gtk_object_add_arg_type ("GnomeMonthItem::heading_font", GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_HEAD_FONT); gtk_object_add_arg_type ("GnomeMonthItem::heading_font_gdk", GTK_TYPE_GDK_FONT, GTK_ARG_READWRITE, ARG_HEAD_FONT_GDK); gtk_object_add_arg_type ("GnomeMonthItem::day_font", GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_DAY_FONT); gtk_object_add_arg_type ("GnomeMonthItem::day_font_gdk", GTK_TYPE_GDK_FONT, GTK_ARG_READWRITE, ARG_DAY_FONT_GDK); gtk_object_add_arg_type ("GnomeMonthItem::heading_color", GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_HEAD_COLOR); gtk_object_add_arg_type ("GnomeMonthItem::heading_color_gdk", GTK_TYPE_GDK_COLOR, GTK_ARG_READWRITE, ARG_HEAD_COLOR_GDK); gtk_object_add_arg_type ("GnomeMonthItem::outline_color", GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_OUTLINE_COLOR); gtk_object_add_arg_type ("GnomeMonthItem::outline_color_gdk", GTK_TYPE_GDK_COLOR, GTK_ARG_READWRITE, ARG_OUTLINE_COLOR_GDK); gtk_object_add_arg_type ("GnomeMonthItem::day_box_color", GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_DAY_BOX_COLOR); gtk_object_add_arg_type ("GnomeMonthItem::day_box_color_gdk", GTK_TYPE_GDK_COLOR, GTK_ARG_READWRITE, ARG_DAY_BOX_COLOR_GDK); gtk_object_add_arg_type ("GnomeMonthItem::day_color", GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_DAY_COLOR); gtk_object_add_arg_type ("GnomeMonthItem::day_color_gdk", GTK_TYPE_GDK_COLOR, GTK_ARG_READWRITE, ARG_DAY_COLOR_GDK); 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; } /* Calculates the minimum heading height based on the heading font size and padding. It also * calculates the minimum width of the month item based on the width of the headings. */ static void check_heading_sizes (GnomeMonthItem *mitem) { double m_height; double m_width; int width; int max_width; int i; /* Calculate minimum height */ m_height = mitem->head_font->ascent + mitem->head_font->descent + 2 * mitem->head_padding; if (mitem->head_height < m_height) mitem->head_height = m_height; /* Go through each heading and remember the widest one */ max_width = 0; for (i = 0; i < 7; i++) { width = gdk_string_width (mitem->head_font, mitem->day_names[i]); if (max_width < width) max_width = width; } m_width = 7 * (max_width + 2 * mitem->head_padding); if (mitem->width < m_width) mitem->width = m_width; } /* Calculates the minimum width and height of the month item based on the day font size and padding. * Assumes that the minimum heading height has already been computed. */ static void check_day_sizes (GnomeMonthItem *mitem) { double m_height; double m_width; int width; int max_width; char buf[100]; int i; /* Calculate minimum height */ m_height = mitem->head_height + 6 * (mitem->day_font->ascent + mitem->day_font->descent + 2 * mitem->day_padding); if (mitem->height < m_height) mitem->height = m_height; /* Calculate minimum width */ max_width = 0; for (i = 1; i < 32; i++) { sprintf (buf, "%d", i); width = gdk_string_width (mitem->day_font, buf); if (max_width < width) max_width = width; } m_width = 7 * (max_width + 2 * mitem->day_padding); if (mitem->width < m_width) mitem->width = m_width; } /* Calculates the minimum size of the month item based on the font sizes and paddings. If the * current size of the month item is smaller than the required minimum size, this function will * change the size to the appropriate values. */ static void check_sizes (GnomeMonthItem *mitem) { check_heading_sizes (mitem); check_day_sizes (mitem); } /* 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); } /* 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[GNOME_MONTH_ITEM_HEAD_GROUP + i], "x", width * i, "y", 0.0, NULL); /* Box */ gnome_canvas_item_set (mitem->items[GNOME_MONTH_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->head_padding, mitem->head_padding, width - mitem->head_padding, mitem->head_height - mitem->head_padding, &x, &y); gnome_canvas_item_set (mitem->items[GNOME_MONTH_ITEM_HEAD_LABEL + i], "x", x, "y", y, "anchor", mitem->head_anchor, NULL); } } /* Resets the position of the days in the calendar */ static void reshape_days (GnomeMonthItem *mitem) { double width, height; double x, y; int row, col; int i; width = mitem->width / 7; height = (mitem->height - mitem->head_height) / 6; i = 0; for (row = 0; row < 6; row++) for (col = 0; col < 7; col++) { /* Group */ gnome_canvas_item_set (mitem->items[GNOME_MONTH_ITEM_DAY_GROUP + i], "x", width * col, "y", mitem->head_height + height * row, NULL); /* Box */ gnome_canvas_item_set (mitem->items[GNOME_MONTH_ITEM_DAY_BOX + i], "x1", 0.0, "y1", 0.0, "x2", width, "y2", height, NULL); /* Label */ get_label_anchor (mitem->day_anchor, mitem->day_padding, mitem->day_padding, width - mitem->day_padding, height - mitem->day_padding, &x, &y); gnome_canvas_item_set (mitem->items[GNOME_MONTH_ITEM_DAY_LABEL + i], "x", x, "y", y, "anchor", mitem->day_anchor, NULL); i++; } } /* Changes the positions and resizes the items in the calendar to match the new size of the * calendar. */ static void reshape (GnomeMonthItem *mitem) { check_sizes (mitem); reanchor (mitem); reshape_headings (mitem); reshape_days (mitem); } /* Sets the font for all the day headings */ static void set_head_font (GnomeMonthItem *mitem) { int i; for (i = 0; i < 7; i++) gnome_canvas_item_set (mitem->items[GNOME_MONTH_ITEM_HEAD_LABEL + i], "font_gdk", mitem->head_font, NULL); } /* Sets the color for all the headings */ static void set_head_color (GnomeMonthItem *mitem) { int i; GdkColor outline; GdkColor head; outline.pixel = mitem->outline_pixel; head.pixel = mitem->head_pixel; for (i = 0; i < 7; i++) { gnome_canvas_item_set (mitem->items[GNOME_MONTH_ITEM_HEAD_BOX + i], "fill_color_gdk", &outline, NULL); gnome_canvas_item_set (mitem->items[GNOME_MONTH_ITEM_HEAD_LABEL + i], "fill_color_gdk", &head, NULL); } } /* 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[GNOME_MONTH_ITEM_HEAD_GROUP + i] = gnome_canvas_item_new (GNOME_CANVAS_GROUP (mitem), gnome_canvas_group_get_type (), NULL); /* Box */ mitem->items[GNOME_MONTH_ITEM_HEAD_BOX + i] = gnome_canvas_item_new (GNOME_CANVAS_GROUP (mitem->items[GNOME_MONTH_ITEM_HEAD_GROUP + i]), gnome_canvas_rect_get_type (), NULL); /* Label */ mitem->items[GNOME_MONTH_ITEM_HEAD_LABEL + i] = gnome_canvas_item_new (GNOME_CANVAS_GROUP (mitem->items[GNOME_MONTH_ITEM_HEAD_GROUP + i]), gnome_canvas_text_get_type (), NULL); } set_head_font (mitem); set_head_color (mitem); } /* Returns the number of leap years since year 1 up to (but not including) the specified year */ static int leap_years_up_to (int year) { return (year / 4 /* trivial leapness */ - ((year > 1700) ? (year / 100 - 17) : 0) /* minus centuries since 1700 */ + ((year > 1600) ? ((year - 1600) / 400) : 0)); /* plus centuries since 1700 divisible by 400 */ } /* Returns whether the specified year is a leap year */ static int is_leap_year (int year) { if (year <= 1752) return !(year % 4); else return (!(year % 4) && (year % 100)) || !(year % 400); } /* Returns the 1-based day number within the year of the specified date */ static int day_in_year (int day, int month, int year) { int is_leap, i; is_leap = is_leap_year (year); for (i = 0; i < month; i++) day += days_in_month [is_leap][i]; return day; } /* Returns the day of the week (zero-based, zero is Sunday) for the specified date. For the days * that were removed on the Gregorian reformation, it returns Thursday. */ static int day_in_week (int day, int month, int year) { int n; n = (year - 1) * 365 + leap_years_up_to (year - 1) + day_in_year (day, month, year); if (n < REFORMATION_DAY) return (n - 1 + SATURDAY) % 7; if (n >= (REFORMATION_DAY + MISSING_DAYS)) return (n - 1 + SATURDAY - MISSING_DAYS) % 7; return THURSDAY; } /* Fills the 42-element days array with the day numbers for the specified month. Slots outside the * bounds of the month are filled with zeros. The starting and ending indexes of the days are * returned in the start and end arguments. */ static void build_month (int month, int year, int start_on_monday, int *days, int *start, int *end) { int i; int d_month, d_week; /* Note that months are zero-based, so September is month 8 */ if ((year == 1752) && (month == 8)) { memcpy (days, sept_1752, 42 * sizeof (int)); if (start) *start = SEPT_1752_START; if (end) *end = SEPT_1752_END; return; } for (i = 0; i < 42; i++) days[i] = 0; d_month = days_in_month[is_leap_year (year)][month]; d_week = day_in_week (1, month, year); if (start_on_monday) d_week = (d_week + 6) % 7; for (i = 0; i < d_month; i++) days[d_week + i] = i + 1; if (start) *start = d_week; if (end) *end = d_week + d_month - 1; } /* Set the day numbers in the monthly calendar */ static void set_days (GnomeMonthItem *mitem) { int i; int start, end; char buf[100]; build_month (mitem->month, mitem->year, mitem->start_on_monday, mitem->day_numbers, &start, &end); /* Clear days before start of month */ for (i = 0; i < start; i++) gnome_canvas_item_set (mitem->items[GNOME_MONTH_ITEM_DAY_LABEL + i], "text", NULL, NULL); /* Set days of month */ for (; start <= end; start++, i++) { sprintf (buf, "%d", mitem->day_numbers[start]); gnome_canvas_item_set (mitem->items[GNOME_MONTH_ITEM_DAY_LABEL + i], "text", buf, NULL); } /* Clear days after end of month */ for (; i < 42; i++) gnome_canvas_item_set (mitem->items[GNOME_MONTH_ITEM_DAY_LABEL + i], "text", NULL, NULL); } /* Sets the font for all the day numbers */ static void set_day_font (GnomeMonthItem *mitem) { int i; for (i = 0; i < 42; i++) gnome_canvas_item_set (mitem->items[GNOME_MONTH_ITEM_DAY_LABEL + i], "font_gdk", mitem->day_font, NULL); } /* Sets the color for all the day items */ static void set_day_color (GnomeMonthItem *mitem) { int i; GdkColor outline; GdkColor day_box; GdkColor day; outline.pixel = mitem->outline_pixel; day_box.pixel = mitem->day_box_pixel; day.pixel = mitem->day_pixel; for (i = 0; i < 42; i++) { gnome_canvas_item_set (mitem->items[GNOME_MONTH_ITEM_DAY_BOX + i], "outline_color_gdk", &outline, "fill_color_gdk", &day_box, NULL); gnome_canvas_item_set (mitem->items[GNOME_MONTH_ITEM_DAY_LABEL + i], "fill_color_gdk", &day, NULL); } } /* Creates the items for the days */ static void create_days (GnomeMonthItem *mitem) { int i; /* Just create the items; they will be positioned and configured by a call to reshape() */ for (i = 0; i < 42; i++) { /* Group */ mitem->items[GNOME_MONTH_ITEM_DAY_GROUP + i] = gnome_canvas_item_new (GNOME_CANVAS_GROUP (mitem), gnome_canvas_group_get_type (), NULL); /* Box */ mitem->items[GNOME_MONTH_ITEM_DAY_BOX + i] = gnome_canvas_item_new (GNOME_CANVAS_GROUP (mitem->items[GNOME_MONTH_ITEM_DAY_GROUP + i]), gnome_canvas_rect_get_type (), NULL); /* Label */ mitem->items[GNOME_MONTH_ITEM_DAY_LABEL + i] = gnome_canvas_item_new (GNOME_CANVAS_GROUP (mitem->items[GNOME_MONTH_ITEM_DAY_GROUP + i]), gnome_canvas_text_get_type (), NULL); } set_day_font (mitem); set_day_color (mitem); set_days (mitem); } /* 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[GNOME_MONTH_ITEM_HEAD_LABEL + i], "text", mitem->day_names[mitem->start_on_monday ? ((i + 1) % 7) : i], NULL); } /* Creates all the canvas items that make up the calendar */ static void create_items (GnomeMonthItem *mitem) { mitem->items = g_new (GnomeCanvasItem *, GNOME_MONTH_ITEM_LAST); create_headings (mitem); create_days (mitem); /* Initialize by default to three-letter day names */ mitem->day_names[0] = g_strdup (_("Sun")); mitem->day_names[1] = g_strdup (_("Mon")); mitem->day_names[2] = g_strdup (_("Tue")); mitem->day_names[3] = g_strdup (_("Wed")); mitem->day_names[4] = g_strdup (_("Thu")); mitem->day_names[5] = g_strdup (_("Fri")); mitem->day_names[6] = g_strdup (_("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->head_padding = 0.0; mitem->day_padding = 2.0; mitem->head_height = 14.0; mitem->head_anchor = GTK_ANCHOR_CENTER; mitem->day_anchor = GTK_ANCHOR_CENTER; /* Load the default fonts */ mitem->head_font = gdk_font_load (DEFAULT_FONT); if (!mitem->head_font) { mitem->head_font = gdk_font_load ("fixed"); g_assert (mitem->head_font != NULL); } mitem->day_font = gdk_font_load (DEFAULT_FONT); if (!mitem->day_font) { mitem->day_font = gdk_font_load ("fixed"); g_assert (mitem->day_font != NULL); } } 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) { GdkColor color; g_return_if_fail (mitem != NULL); g_return_if_fail (GNOME_IS_MONTH_ITEM (mitem)); gnome_canvas_get_color (GNOME_CANVAS_ITEM (mitem)->canvas, "#d6d6d6d6d6d6", &color); mitem->head_pixel = color.pixel; mitem->day_box_pixel = color.pixel; gnome_canvas_get_color (GNOME_CANVAS_ITEM (mitem)->canvas, "black", &color); mitem->outline_pixel = color.pixel; mitem->day_pixel = color.pixel; 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); } /* Sets the color of the specified pixel value to that of the specified argument, which must be in * GdkColor format if format is TRUE, otherwise it must be in string format. */ static void set_color_arg (GnomeMonthItem *mitem, gulong *pixel, GtkArg *arg, int gdk_format, int set_head, int set_day) { GdkColor color; if (gdk_format) *pixel = ((GdkColor *) GTK_VALUE_BOXED (*arg))->pixel; else { if (gnome_canvas_get_color (GNOME_CANVAS_ITEM (mitem)->canvas, GTK_VALUE_STRING (*arg), &color)) *pixel = color.pixel; else *pixel = 0; } if (set_head) set_head_color (mitem); if (set_day) set_day_color (mitem); } 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); set_days (mitem); break; case ARG_MONTH: mitem->month = GTK_VALUE_UINT (*arg); set_days (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)); reshape (mitem); break; case ARG_HEIGHT: mitem->height = fabs (GTK_VALUE_DOUBLE (*arg)); reshape (mitem); break; case ARG_ANCHOR: mitem->anchor = GTK_VALUE_ENUM (*arg); reanchor (mitem); break; case ARG_HEAD_PADDING: mitem->head_padding = fabs (GTK_VALUE_DOUBLE (*arg)); reshape (mitem); break; case ARG_DAY_PADDING: mitem->day_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); reshape (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_DAY_ANCHOR: mitem->day_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); set_days (mitem); break; case ARG_HEAD_FONT: gdk_font_unref (mitem->head_font); mitem->head_font = gdk_font_load (GTK_VALUE_STRING (*arg)); if (!mitem->head_font) { mitem->head_font = gdk_font_load ("fixed"); g_assert (mitem->head_font != NULL); } set_head_font (mitem); reshape (mitem); break; case ARG_HEAD_FONT_GDK: gdk_font_unref (mitem->head_font); mitem->head_font = GTK_VALUE_BOXED (*arg); gdk_font_ref (mitem->head_font); set_head_font (mitem); reshape (mitem); break; case ARG_DAY_FONT: gdk_font_unref (mitem->day_font); mitem->day_font = gdk_font_load (GTK_VALUE_STRING (*arg)); if (!mitem->day_font) { mitem->day_font = gdk_font_load ("fixed"); g_assert (mitem->day_font != NULL); } set_day_font (mitem); reshape (mitem); break; case ARG_DAY_FONT_GDK: gdk_font_unref (mitem->day_font); mitem->day_font = GTK_VALUE_BOXED (*arg); gdk_font_ref (mitem->day_font); set_day_font (mitem); reshape (mitem); break; case ARG_HEAD_COLOR: set_color_arg (mitem, &mitem->head_pixel, arg, FALSE, TRUE, FALSE); break; case ARG_HEAD_COLOR_GDK: set_color_arg (mitem, &mitem->head_pixel, arg, TRUE, TRUE, FALSE); break; case ARG_OUTLINE_COLOR: set_color_arg (mitem, &mitem->outline_pixel, arg, FALSE, TRUE, TRUE); break; case ARG_OUTLINE_COLOR_GDK: set_color_arg (mitem, &mitem->outline_pixel, arg, TRUE, TRUE, TRUE); break; case ARG_DAY_BOX_COLOR: set_color_arg (mitem, &mitem->day_box_pixel, arg, FALSE, FALSE, TRUE); break; case ARG_DAY_BOX_COLOR_GDK: set_color_arg (mitem, &mitem->day_box_pixel, arg, TRUE, FALSE, TRUE); break; case ARG_DAY_COLOR: set_color_arg (mitem, &mitem->day_pixel, arg, FALSE, FALSE, TRUE); break; case ARG_DAY_COLOR_GDK: set_color_arg (mitem, &mitem->day_pixel, arg, TRUE, FALSE, TRUE); break; default: break; } } /* Allocates a GdkColor structure filled with the specified pixel, and puts it into the specified * arg for returning it in the get_arg method. */ static void get_color_arg (GnomeMonthItem *mitem, gulong pixel, GtkArg *arg) { GdkColor *color; color = g_new (GdkColor, 1); color->pixel = pixel; gdk_color_context_query_color (GNOME_CANVAS_ITEM (mitem)->canvas->cc, color); GTK_VALUE_BOXED (*arg) = color; } 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_HEAD_PADDING: GTK_VALUE_DOUBLE (*arg) = mitem->head_padding; break; case ARG_DAY_PADDING: GTK_VALUE_DOUBLE (*arg) = mitem->day_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_DAY_ANCHOR: GTK_VALUE_ENUM (*arg) = mitem->day_anchor; break; case ARG_START_ON_MONDAY: GTK_VALUE_BOOL (*arg) = mitem->start_on_monday; break; case ARG_HEAD_FONT_GDK: GTK_VALUE_BOXED (*arg) = mitem->head_font; break; case ARG_DAY_FONT_GDK: GTK_VALUE_BOXED (*arg) = mitem->day_font; break; case ARG_HEAD_COLOR_GDK: get_color_arg (mitem, mitem->head_pixel, arg); break; case ARG_OUTLINE_COLOR_GDK: get_color_arg (mitem, mitem->outline_pixel, arg); break; case ARG_DAY_BOX_COLOR_GDK: get_color_arg (mitem, mitem->day_box_pixel, arg); break; case ARG_DAY_COLOR_GDK: get_color_arg (mitem, mitem->day_pixel, arg); break; default: arg->type = GTK_TYPE_INVALID; break; } } GnomeCanvasItem * gnome_month_item_num2child (GnomeMonthItem *mitem, int child_num) { g_return_val_if_fail (mitem != NULL, NULL); g_return_val_if_fail (GNOME_IS_MONTH_ITEM (mitem), NULL); return mitem->items[child_num]; } int gnome_month_item_child2num (GnomeMonthItem *mitem, GnomeCanvasItem *child) { int i; g_return_val_if_fail (mitem != NULL, -1); g_return_val_if_fail (GNOME_IS_MONTH_ITEM (mitem), -1); g_return_val_if_fail (child != NULL, -1); g_return_val_if_fail (GNOME_IS_CANVAS_ITEM (child), -1); for (i = 0; i < GNOME_MONTH_ITEM_LAST; i++) if (mitem->items[i] == child) return i; return -1; } int gnome_month_item_num2day (GnomeMonthItem *mitem, int child_num) { g_return_val_if_fail (mitem != NULL, 0); g_return_val_if_fail (GNOME_IS_MONTH_ITEM (mitem), 0); if ((child_num >= GNOME_MONTH_ITEM_DAY_GROUP) && (child_num < GNOME_MONTH_ITEM_LAST)) { child_num = (child_num - GNOME_MONTH_ITEM_DAY_GROUP) % 42; return mitem->day_numbers[child_num]; } else return 0; } int gnome_month_item_day2index (GnomeMonthItem *mitem, int day_num) { int i; g_return_val_if_fail (mitem != NULL, -1); g_return_val_if_fail (GNOME_IS_MONTH_ITEM (mitem), -1); g_return_val_if_fail (day_num >= 1, -1); /* Find first day of month */ for (i = 0; mitem->day_numbers[i] == 0; i++) ; /* Find the specified day */ for (; (mitem->day_numbers[i] != 0) && (i < 42); i++) if (mitem->day_numbers[i] == day_num) return i; /* Bail out */ return -1; }