diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | ChangeLog.pre-2-0 | 6 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 6 | ||||
-rw-r--r-- | ChangeLog.pre-2-2 | 6 | ||||
-rw-r--r-- | ChangeLog.pre-2-4 | 6 | ||||
-rw-r--r-- | ChangeLog.pre-2-6 | 6 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 6 | ||||
-rw-r--r-- | TODO | 16 | ||||
-rw-r--r-- | examples/calendar/Makefile | 8 | ||||
-rw-r--r-- | examples/calendar/gcalendar.c | 366 | ||||
-rw-r--r-- | gtk/Makefile.am | 2 | ||||
-rw-r--r-- | gtk/gtk.h | 1 | ||||
-rw-r--r-- | gtk/gtkcalendar.c | 2561 | ||||
-rw-r--r-- | gtk/gtkcalendar.h | 153 |
14 files changed, 3149 insertions, 0 deletions
@@ -1,3 +1,9 @@ +Sun Sep 27 02:18:06 CDT 1998 Shawn T. Amundson <amundson@gtk.org> + + * gtk/gtkcalendar.h: + gtk/gtkcalendar.c: + examples/calendar: Added gtkcalendar widget and demo + Sat Sep 26 06:15:34 1998 Tim Janik <timj@gtk.org> * gtk/gtkclist.c (gtk_clist_sort): diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index befa11e63c..d2e2908dca 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,9 @@ +Sun Sep 27 02:18:06 CDT 1998 Shawn T. Amundson <amundson@gtk.org> + + * gtk/gtkcalendar.h: + gtk/gtkcalendar.c: + examples/calendar: Added gtkcalendar widget and demo + Sat Sep 26 06:15:34 1998 Tim Janik <timj@gtk.org> * gtk/gtkclist.c (gtk_clist_sort): diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index befa11e63c..d2e2908dca 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,9 @@ +Sun Sep 27 02:18:06 CDT 1998 Shawn T. Amundson <amundson@gtk.org> + + * gtk/gtkcalendar.h: + gtk/gtkcalendar.c: + examples/calendar: Added gtkcalendar widget and demo + Sat Sep 26 06:15:34 1998 Tim Janik <timj@gtk.org> * gtk/gtkclist.c (gtk_clist_sort): diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index befa11e63c..d2e2908dca 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,9 @@ +Sun Sep 27 02:18:06 CDT 1998 Shawn T. Amundson <amundson@gtk.org> + + * gtk/gtkcalendar.h: + gtk/gtkcalendar.c: + examples/calendar: Added gtkcalendar widget and demo + Sat Sep 26 06:15:34 1998 Tim Janik <timj@gtk.org> * gtk/gtkclist.c (gtk_clist_sort): diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index befa11e63c..d2e2908dca 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,9 @@ +Sun Sep 27 02:18:06 CDT 1998 Shawn T. Amundson <amundson@gtk.org> + + * gtk/gtkcalendar.h: + gtk/gtkcalendar.c: + examples/calendar: Added gtkcalendar widget and demo + Sat Sep 26 06:15:34 1998 Tim Janik <timj@gtk.org> * gtk/gtkclist.c (gtk_clist_sort): diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index befa11e63c..d2e2908dca 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,9 @@ +Sun Sep 27 02:18:06 CDT 1998 Shawn T. Amundson <amundson@gtk.org> + + * gtk/gtkcalendar.h: + gtk/gtkcalendar.c: + examples/calendar: Added gtkcalendar widget and demo + Sat Sep 26 06:15:34 1998 Tim Janik <timj@gtk.org> * gtk/gtkclist.c (gtk_clist_sort): diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index befa11e63c..d2e2908dca 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,9 @@ +Sun Sep 27 02:18:06 CDT 1998 Shawn T. Amundson <amundson@gtk.org> + + * gtk/gtkcalendar.h: + gtk/gtkcalendar.c: + examples/calendar: Added gtkcalendar widget and demo + Sat Sep 26 06:15:34 1998 Tim Janik <timj@gtk.org> * gtk/gtkclist.c (gtk_clist_sort): @@ -275,3 +275,19 @@ Text/Edit widget: - "changed" emitted when doing deletes on empty Text widget. - Delete IC in editable->unrealize, not editable->finalize? + +Calendar Widget: + + - The widget should be nicely resizeable vertical to. + + - CALENDAR_MARGIN should be removed, uses INNER_BORDER and + style->class->[xy]thickness insted. + + - Flag to choose between using standard three letter abbreviated + weekday name or just the first character from it. It looks like + that is what most other calendar-widgets do. + + - Arrows should resize with the header-font. + + - The keyboard support has to be finished. + diff --git a/examples/calendar/Makefile b/examples/calendar/Makefile new file mode 100644 index 0000000000..eb3a3306b4 --- /dev/null +++ b/examples/calendar/Makefile @@ -0,0 +1,8 @@ + +CC = gcc + +gcalendar: gcalendar.c + $(CC) `gtk-config --cflags` `gtk-config --libs` gcalendar.c -o gcalendar + +clean: + rm -f gcalendar diff --git a/examples/calendar/gcalendar.c b/examples/calendar/gcalendar.c new file mode 100644 index 0000000000..d62a510504 --- /dev/null +++ b/examples/calendar/gcalendar.c @@ -0,0 +1,366 @@ +/* G Calendar + * Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson, Mattias Grönlund + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <gtk/gtk.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#define DEF_PAD 10 +#define DEF_PAD_SMALL 5 + +#define TM_YEAR_BASE 1900 + + +typedef struct _CalendarData { + GtkWidget *flag_checkboxes[5]; + gboolean settings[5]; + gchar *font; + GtkWidget *font_dialog; + GtkWidget *window; + GtkWidget *selected; + GtkWidget *selected_double_click; + GtkWidget *month; +} CalendarData; + +void create_calendar(); +gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data); +void destroy (GtkWidget *widget, gpointer data); +void day_selected_double_click (GtkWidget *widget, gpointer data); +int main(int argc, char *argv[]); +void calendar_month_changed (GtkWidget *widget, CalendarData *data); +void calendar_day_selected (GtkWidget *widget, CalendarData *data); +void calendar_day_selected_double_click (GtkWidget *widget, CalendarData *data); + + +void calendar_set_flags(CalendarData *calendar); +void calendar_toggle_flag(GtkWidget * toggle, CalendarData *calendar); +void calendar_font_selection_ok(GtkWidget * button, CalendarData *calendar); +void calendar_font_selection_destroy(GtkWidget * button, GtkWidget widget); +void calendar_select_font(GtkWidget * button, CalendarData *calendar); +void calendar_create_window_destroy(GtkWidget * ignore, CalendarData *calendar); +void calendar_create_window(GtkWidget * ignored, CalendarData * calendar); +void calendar_window_destroy(GtkWidget * ignore, CalendarData *calendar); +void create_calendar(); + +/* + * GtkCalendar + */ + +void +calendar_month_changed (GtkWidget *widget, CalendarData *data) +{ + char buffer[256]; + struct tm tm; + time_t time; + memset (&tm, 0, sizeof (tm)); + gtk_calendar_get_date (GTK_CALENDAR(data->window), &tm.tm_year, &tm.tm_mon, &tm.tm_mday); + tm.tm_year -= TM_YEAR_BASE; + time = mktime(&tm); + strftime (buffer, 255, "%x", gmtime(&time)); + gtk_label_set (GTK_LABEL (data->month), buffer); +} + +void +calendar_day_selected (GtkWidget *widget, CalendarData *data) +{ + char buffer[256]; + struct tm tm; + time_t time; + memset (&tm, 0, sizeof (tm)); + gtk_calendar_get_date (GTK_CALENDAR(data->window), &tm.tm_year, &tm.tm_mon, &tm.tm_mday); + tm.tm_year -= TM_YEAR_BASE; + time = mktime(&tm); + strftime (buffer, 255, "%x", gmtime(&time)); + gtk_label_set (GTK_LABEL (data->selected), buffer); +} + +void +calendar_day_selected_double_click (GtkWidget *widget, CalendarData *data) +{ + char buffer[256]; + struct tm tm; + time_t time; + memset (&tm, 0, sizeof (tm)); + gtk_calendar_get_date (GTK_CALENDAR(data->window), &tm.tm_year, &tm.tm_mon, &tm.tm_mday); + tm.tm_year -= TM_YEAR_BASE; + time = mktime(&tm); + strftime (buffer, 255, "%x", gmtime(&time)); + gtk_label_set (GTK_LABEL (data->selected_double_click), buffer); +} + +enum { + calendar_show_header, + calendar_show_days, + calendar_month_change, + calendar_show_week, + calendar_monday_first +}; + +void +calendar_set_flags(CalendarData *calendar) +{ + gint i; + gint options=0; + for (i=0;i<5;i++) + if (calendar->settings[i]) + { + options=options + (1<<i); + } + if (calendar->window) + gtk_calendar_display_options (GTK_CALENDAR (calendar->window), options); +} + +void +calendar_toggle_flag(GtkWidget * toggle, CalendarData *calendar) +{ + gint i; + gint j; + j=0; + for (i=0; i<5; i++) + if (calendar->flag_checkboxes[i] == toggle) + j = i; + + calendar->settings[j]=!calendar->settings[j]; + calendar_set_flags(calendar); + +} +#ifdef GTK_HAVE_FEATURES_1_1_0 +void +calendar_font_selection_ok(GtkWidget * button, CalendarData *calendar) +{ + GtkStyle *style; + GdkFont *font; + + calendar->font = gtk_font_selection_dialog_get_font_name (GTK_FONT_SELECTION_DIALOG (calendar->font_dialog)); + if (calendar->window) + { + font = gtk_font_selection_dialog_get_font(GTK_FONT_SELECTION_DIALOG(calendar->font_dialog)); + if (font) + { + style = gtk_style_copy (gtk_widget_get_style (calendar->window)); + gdk_font_unref (style->font); + style->font = font; + gdk_font_ref (style->font); + gtk_widget_set_style (calendar->window, style); + } + } +} + +void +calendar_select_font(GtkWidget * button, CalendarData *calendar) +{ + GtkWidget *window; + + if (!calendar->font_dialog) { + window = gtk_font_selection_dialog_new ("Font Selection Dialog"); + g_return_if_fail(GTK_IS_FONT_SELECTION_DIALOG(window)); + calendar->font_dialog = window; + + gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroyed), + &calendar->font_dialog); + + gtk_signal_connect (GTK_OBJECT (GTK_FONT_SELECTION_DIALOG (window)->ok_button), + "clicked", GTK_SIGNAL_FUNC(calendar_font_selection_ok), + calendar); + gtk_signal_connect_object (GTK_OBJECT (GTK_FONT_SELECTION_DIALOG (window)->cancel_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (calendar->font_dialog)); + } + window=calendar->font_dialog; + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); + +} +#endif /* GTK_HAVE_FEATURES_1_1_0 */ + +void +create_calendar() +{ + GtkWidget *window; + GtkWidget *vbox, *vbox2, *vbox3; + GtkWidget *hbox; + GtkWidget *hbbox; + GtkWidget *calendar; + GtkWidget *toggle; + GtkWidget *button; + GtkWidget *frame; + GtkWidget *separator; + GtkWidget *label; + GtkWidget *bbox; + static CalendarData calendar_data; + gint i; + + struct { + char *label; + } flags[] = + { + { "Show Heading" }, + { "Show Day Names" }, + { "No Month Change" }, + { "Show Week Numbers" }, + { "Week Start Monday" } + }; + + + calendar_data.window = NULL; + calendar_data.font = NULL; + calendar_data.font_dialog = NULL; + + for (i=0; i<5; i++) { + calendar_data.settings[i]=0; + } + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_border_width (GTK_CONTAINER (window), 5); + gtk_signal_connect(GTK_OBJECT(window), "destroy", + GTK_SIGNAL_FUNC(gtk_main_quit), + NULL); + gtk_signal_connect(GTK_OBJECT(window), "delete-event", + GTK_SIGNAL_FUNC(gtk_false), + NULL); + + gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, TRUE); + + vbox = gtk_vbox_new(FALSE, DEF_PAD); + gtk_container_add (GTK_CONTAINER (window), vbox); + + /* + * The top part of the window, Calendar, flags and fontsel. + */ + + hbox = gtk_hbox_new(FALSE, DEF_PAD); + gtk_box_pack_start (GTK_BOX(vbox), hbox, TRUE, TRUE, DEF_PAD); + hbbox = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(hbox), hbbox, FALSE, FALSE, DEF_PAD); + gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_SPREAD); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(hbbox), 5); + + /* Calendar widget */ + frame = gtk_frame_new("Calendar"); + gtk_box_pack_start(GTK_BOX(hbbox), frame, TRUE, TRUE, DEF_PAD); + calendar=gtk_calendar_new(); + calendar_data.window = calendar; + calendar_set_flags(&calendar_data); + gtk_calendar_mark_day ( GTK_CALENDAR(calendar), 19); + gtk_container_add( GTK_CONTAINER( frame), calendar); + gtk_signal_connect (GTK_OBJECT (calendar), "month_changed", + GTK_SIGNAL_FUNC (calendar_month_changed), + &calendar_data); + gtk_signal_connect (GTK_OBJECT (calendar), "day_selected", + GTK_SIGNAL_FUNC (calendar_day_selected), + &calendar_data); + gtk_signal_connect (GTK_OBJECT (calendar), "day_selected_double_click", + GTK_SIGNAL_FUNC (calendar_day_selected_double_click), + &calendar_data); + + + separator = gtk_vseparator_new (); + gtk_box_pack_start (GTK_BOX (hbox), separator, FALSE, TRUE, 0); + + vbox2 = gtk_vbox_new(FALSE, DEF_PAD); + gtk_box_pack_start(GTK_BOX(hbox), vbox2, FALSE, FALSE, DEF_PAD); + + /* Build the Right frame with the flags in */ + + frame = gtk_frame_new("Flags"); + gtk_box_pack_start(GTK_BOX(vbox2), frame, TRUE, TRUE, DEF_PAD); + vbox3 = gtk_vbox_new(TRUE, DEF_PAD_SMALL); + gtk_container_add(GTK_CONTAINER(frame), vbox3); + + for (i = 0; i < 5; i++) + { + toggle = gtk_check_button_new_with_label(flags[i].label); + gtk_signal_connect (GTK_OBJECT (toggle), + "toggled", + GTK_SIGNAL_FUNC(calendar_toggle_flag), + &calendar_data); + gtk_box_pack_start (GTK_BOX (vbox3), toggle, TRUE, TRUE, 0); + calendar_data.flag_checkboxes[i]=toggle; + } +#ifdef GTK_HAVE_FEATURES_1_1_0 + /* Build the right font-button */ + button = gtk_button_new_with_label("Font..."); + gtk_signal_connect (GTK_OBJECT (button), + "clicked", + GTK_SIGNAL_FUNC(calendar_select_font), + &calendar_data); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); +#endif /* GTK_HAVE_FEATURES_1_1_0 */ + + /* + * Build the Signal-event part. + */ + + frame = gtk_frame_new("Signal events"); + gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, DEF_PAD); + vbox2 = gtk_vbox_new(TRUE, DEF_PAD_SMALL); + gtk_container_add(GTK_CONTAINER(frame), vbox2); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0); + label = gtk_label_new ("Day selected:"); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0); + calendar_data.selected = gtk_label_new (""); + gtk_box_pack_start (GTK_BOX (hbox), calendar_data.selected, FALSE, TRUE, 0); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0); + label = gtk_label_new ("Day selected double click:"); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0); + calendar_data.selected_double_click = gtk_label_new (""); + gtk_box_pack_start (GTK_BOX (hbox), calendar_data.selected_double_click, FALSE, TRUE, 0); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0); + label = gtk_label_new ("Month change:"); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0); + calendar_data.month = gtk_label_new (""); + gtk_box_pack_start (GTK_BOX (hbox), calendar_data.month, FALSE, TRUE, 0); + + bbox = gtk_hbutton_box_new (); + gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + + button = gtk_button_new_with_label ("Close"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_main_quit), + NULL); + gtk_container_add (GTK_CONTAINER (bbox), button); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + + gtk_widget_show_all(window); +} + + +int +main(int argc, char *argv[]) +{ + gtk_set_locale (); + gtk_init (&argc, &argv); + create_calendar(); + gtk_main (); + return 0; +} diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 08eaeaac02..6eed5d25a8 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -18,6 +18,7 @@ libgtk_la_SOURCES = \ gtkbbox.c \ gtkbox.c \ gtkbutton.c \ + gtkcalendar.c \ gtkcheckbutton.c \ gtkcheckmenuitem.c \ gtkclist.c \ @@ -122,6 +123,7 @@ source_headers = \ gtkbbox.h \ gtkbox.h \ gtkbutton.h \ + gtkcalendar.h \ gtkcheckbutton.h \ gtkcheckmenuitem.h \ gtkclist.h \ @@ -33,6 +33,7 @@ #include <gtk/gtkbox.h> #include <gtk/gtkbbox.h> #include <gtk/gtkbutton.h> +#include <gtk/gtkcalendar.h> #include <gtk/gtkcheckbutton.h> #include <gtk/gtkcheckmenuitem.h> #include <gtk/gtkclist.h> diff --git a/gtk/gtkcalendar.c b/gtk/gtkcalendar.c new file mode 100644 index 0000000000..55bde3cbf2 --- /dev/null +++ b/gtk/gtkcalendar.c @@ -0,0 +1,2561 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * GTK Calendar Widget + * Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson and Mattias Grönlund + * + * lib_date routines + * Copyright (c) 1995, 1996, 1997, 1998 by Steffen Beyer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <sys/time.h> +#include <string.h> +#include <stdlib.h> +#include <time.h> +#include <stdio.h> +#include "gtkcalendar.h" +#include "gdk/gdkkeysyms.h" + +/***************************************************************************/ +/* The following date routines are taken from the lib_date package. Keep + * them seperate in case we want to update them if a newer lib_date comes + * out with fixes. */ + +typedef unsigned int N_int; +typedef unsigned long N_long; +typedef signed long Z_long; +typedef enum { false = FALSE , true = TRUE } boolean; + +#define and && /* logical (boolean) operators: lower case */ +#define or || + +static N_int month_length[2][13] = +{ + { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; + +static N_int days_in_months[2][14] = +{ + { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } +}; + +static Z_long calc_days(N_int year, N_int mm, N_int dd); +static N_int day_of_week(N_int year, N_int mm, N_int dd); +static Z_long dates_difference(N_int year1, N_int mm1, N_int dd1, + N_int year2, N_int mm2, N_int dd2); +static N_int weeks_in_year(N_int year); + +static boolean +leap(N_int year) +{ + return((((year % 4) == 0) and ((year % 100) != 0)) or ((year % 400) == 0)); +} + +static N_int +day_of_week(N_int year, N_int mm, N_int dd) +{ + Z_long days; + + days = calc_days(year, mm, dd); + if (days > 0L) + { + days--; + days %= 7L; + days++; + } + return( (N_int) days ); +} + +static N_int weeks_in_year(N_int year) +{ + return(52 + ((day_of_week(year,1,1)==4) or (day_of_week(year,12,31)==4))); +} + +static boolean +check_date(N_int year, N_int mm, N_int dd) +{ + if (year < 1) return(false); + if ((mm < 1) or (mm > 12)) return(false); + if ((dd < 1) or (dd > month_length[leap(year)][mm])) return(false); + return(true); +} + +static N_int +week_number(N_int year, N_int mm, N_int dd) +{ + N_int first; + + first = day_of_week(year,1,1) - 1; + return( (N_int) ( (dates_difference(year,1,1, year,mm,dd) + first) / 7L ) + + (first < 4) ); +} + +static Z_long +year_to_days(N_int year) +{ + return( year * 365L + (year / 4) - (year / 100) + (year / 400) ); +} + + +static Z_long +calc_days(N_int year, N_int mm, N_int dd) +{ + boolean lp; + + if (year < 1) return(0L); + if ((mm < 1) or (mm > 12)) return(0L); + if ((dd < 1) or (dd > month_length[(lp = leap(year))][mm])) return(0L); + return( year_to_days(--year) + days_in_months[lp][mm] + dd ); +} + +static boolean +week_of_year(N_int *week, N_int *year, N_int mm, N_int dd) +{ + if (check_date(*year,mm,dd)) + { + *week = week_number(*year,mm,dd); + if (*week == 0) + *week = weeks_in_year(--(*year)); + else if (*week > weeks_in_year(*year)) + { + *week = 1; + (*year)++; + } + return(true); + } + return(false); +} + +static Z_long +dates_difference(N_int year1, N_int mm1, N_int dd1, + N_int year2, N_int mm2, N_int dd2) +{ + return( calc_days(year2, mm2, dd2) - calc_days(year1, mm1, dd1) ); +} + +/** END OF lib_date routines ************************************************/ + +#define CALENDAR_MARGIN 0 +#define CALENDAR_YSEP 4 +#define CALENDAR_XSEP 4 +#define INNER_BORDER 4 + +#define DAY_XPAD 2 +#define DAY_YPAD 2 +#define DAY_XSEP 0 /* not really good for small calendar */ +#define DAY_YSEP 0 /* not really good for small calendar */ + +/* Color usage */ +#define HEADER_FG_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)]) +#define HEADER_BG_COLOR(widget) (& (widget)->style->bg[GTK_WIDGET_STATE (widget)]) +#define DAY_NAME_COLOR(widget) (& (widget)->style->dark[GTK_WIDGET_STATE (widget)]) +#define NORMAL_DAY_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)]) +#define SELECTION_FOCUS_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)]) +#define SELECTION_NO_FOCUS_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)]) +#define PREV_MONTH_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)]) +#define NEXT_MONTH_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)]) +#define MARKED_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)]) +#define FOREGROUND_COLOR(widget) (& (widget)->style->fg[GTK_WIDGET_STATE (widget)]) +#define BACKGROUND_COLOR(widget) (& (widget)->style->base[GTK_WIDGET_STATE (widget)]) +#define HIGHLIGHT_BACK_COLOR(widget) (& (widget)->style->mid[GTK_WIDGET_STATE (widget)]) + +#define HEADER_FONT(widget) ((widget)->style->font) +#define LABEL_FONT(widget) ((widget)->style->font) +#define DAY_FONT(widget) ((widget)->style->font) + +enum { + ARROW_YEAR_LEFT, + ARROW_YEAR_RIGHT, + ARROW_MONTH_LEFT, + ARROW_MONTH_RIGHT +}; + +enum { + MONTH_PREV, + MONTH_CURRENT, + MONTH_NEXT +}; + +static GtkWidgetClass *parent_class = NULL; + +enum { + MONTH_CHANGED_SIGNAL, + DAY_SELECTED_SIGNAL, + DAY_SELECTED_DOUBLE_CLICK_SIGNAL, + PREV_MONTH_SIGNAL, + NEXT_MONTH_SIGNAL, + PREV_YEAR_SIGNAL, + NEXT_YEAR_SIGNAL, + LAST_SIGNAL +}; + +static gint gtk_calendar_signals[LAST_SIGNAL] = { 0 }; + +typedef void (*GtkCalendarSignalDate) (GtkObject *object, guint arg1, guint arg2, guint arg3, gpointer data); + +static void gtk_calendar_class_init (GtkCalendarClass *class); +static void gtk_calendar_init (GtkCalendar *calendar); +static void gtk_calendar_realize (GtkWidget *widget); +static void gtk_calendar_unrealize (GtkWidget *widget); +static void gtk_calendar_draw_focus (GtkWidget *widget); +static void gtk_calendar_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_calendar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gtk_calendar_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_calendar_button_press (GtkWidget *widget, + GdkEventButton *event); +static void gtk_calendar_main_button (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_calendar_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static gint gtk_calendar_enter_notify (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_calendar_leave_notify (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_calendar_key_press (GtkWidget *widget, + GdkEventKey *event); +static gint gtk_calendar_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_calendar_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static void gtk_calendar_state_changed (GtkWidget *widget, + GtkStateType previous_state); +static void gtk_calendar_style_set (GtkWidget *widget, + GtkStyle *previous_style); +void gtk_calendar_paint_header (GtkWidget *widget); +void gtk_calendar_paint_day_names (GtkWidget *widget); +void gtk_calendar_paint_week_numbers (GtkWidget *widget); +void gtk_calendar_paint_main (GtkWidget *widget); + + +static void gtk_calendar_paint (GtkWidget *widget, GdkRectangle *area); +static void gtk_calendar_paint_arrow (GtkWidget *widget, guint arrow); +static void gtk_calendar_paint_day_num (GtkWidget *widget, gint day); +static void gtk_calendar_paint_day (GtkWidget *widget, gint row, gint col); +static void gtk_calendar_draw (GtkWidget *widget, GdkRectangle *area); +static void gtk_calendar_compute_days (GtkCalendar *calendar); +static gint left_x_for_column (GtkCalendar *calendar, gint column); +static gint top_y_for_row (GtkCalendar *calendar, gint row); + +static char *default_abbreviated_dayname[7]; +static char *default_monthname[12]; + +guint +gtk_calendar_get_type () +{ + static guint calendar_type = 0; + + if (!calendar_type) + { + GtkTypeInfo calendar_info = + { + "GtkCalendar", + sizeof (GtkCalendar), + sizeof (GtkCalendarClass), + (GtkClassInitFunc) gtk_calendar_class_init, + (GtkObjectInitFunc) gtk_calendar_init, + (GtkArgSetFunc) NULL, + (GtkArgGetFunc) NULL, + }; + + calendar_type = gtk_type_unique (gtk_widget_get_type (), &calendar_info); + } + + return calendar_type; +} + +static void +gtk_calendar_class_init (GtkCalendarClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + parent_class = gtk_type_class (gtk_widget_get_type ()); + + widget_class->realize = gtk_calendar_realize; + widget_class->unrealize = gtk_calendar_unrealize; + widget_class->expose_event = gtk_calendar_expose; + widget_class->draw = gtk_calendar_draw; + widget_class->draw_focus = gtk_calendar_draw_focus; + widget_class->size_request = gtk_calendar_size_request; + widget_class->size_allocate = gtk_calendar_size_allocate; + widget_class->button_press_event = gtk_calendar_button_press; + widget_class->motion_notify_event = gtk_calendar_motion_notify; + widget_class->enter_notify_event = gtk_calendar_enter_notify; + widget_class->leave_notify_event = gtk_calendar_leave_notify; + widget_class->key_press_event = gtk_calendar_key_press; + widget_class->focus_in_event = gtk_calendar_focus_in; + widget_class->focus_out_event = gtk_calendar_focus_out; + widget_class->style_set = gtk_calendar_style_set; + widget_class->state_changed = gtk_calendar_state_changed; + + gtk_calendar_signals[MONTH_CHANGED_SIGNAL] = + gtk_signal_new ("month_changed", + GTK_RUN_FIRST, object_class->type, + GTK_SIGNAL_OFFSET (GtkCalendarClass, gtk_calendar_month_changed), + gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); + gtk_calendar_signals[DAY_SELECTED_SIGNAL] = + gtk_signal_new ("day_selected", + GTK_RUN_FIRST, object_class->type, + GTK_SIGNAL_OFFSET (GtkCalendarClass, gtk_calendar_day_selected), + gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); + gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL] = + gtk_signal_new ("day_selected_double_click", + GTK_RUN_FIRST, object_class->type, + GTK_SIGNAL_OFFSET (GtkCalendarClass, gtk_calendar_day_selected_double_click), + gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); + gtk_calendar_signals[PREV_MONTH_SIGNAL] = + gtk_signal_new ("prev_month", + GTK_RUN_FIRST, object_class->type, + GTK_SIGNAL_OFFSET (GtkCalendarClass, gtk_calendar_prev_month), + gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); + gtk_calendar_signals[NEXT_MONTH_SIGNAL] = + gtk_signal_new ("next_month", + GTK_RUN_FIRST, object_class->type, + GTK_SIGNAL_OFFSET (GtkCalendarClass, gtk_calendar_next_month), + gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); + gtk_calendar_signals[PREV_YEAR_SIGNAL] = + gtk_signal_new ("prev_year", + GTK_RUN_FIRST, object_class->type, + GTK_SIGNAL_OFFSET (GtkCalendarClass, gtk_calendar_prev_year), + gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); + gtk_calendar_signals[NEXT_YEAR_SIGNAL] = + gtk_signal_new ("next_year", + GTK_RUN_FIRST, object_class->type, + GTK_SIGNAL_OFFSET (GtkCalendarClass, gtk_calendar_next_year), + gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, gtk_calendar_signals, LAST_SIGNAL); + + class->gtk_calendar_month_changed = NULL; + class->gtk_calendar_day_selected = NULL; + class->gtk_calendar_day_selected_double_click = NULL; + class->gtk_calendar_prev_month = NULL; + class->gtk_calendar_next_month = NULL; + class->gtk_calendar_prev_year = NULL; + class->gtk_calendar_next_year = NULL; + + return; +} + +static void +gtk_calendar_init (GtkCalendar *calendar) +{ + time_t secs; + struct tm *tm; + gint i; + char buffer[255]; + time_t tmp_time; + GtkWidget *widget; + + widget = GTK_WIDGET (calendar); + GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS); + + if (!default_abbreviated_dayname[0]) + for (i=0; i<7; i++) + { + tmp_time= (i+3)*86400; + strftime ( buffer, sizeof (buffer), "%a", gmtime (&tmp_time)); + default_abbreviated_dayname[i] = g_strdup (buffer); + } + + if (!default_monthname[0]) + for (i=0; i<12; i++) + { + tmp_time=i*2764800; + strftime ( buffer, sizeof (buffer), "%B", gmtime (&tmp_time)); + default_monthname[i] = g_strdup (buffer); + } + + /* Set defaults */ + secs = time (NULL); + tm = localtime (&secs); + calendar->month = tm->tm_mon; + calendar->year = 1900 + tm->tm_year; + + for (i=0;i<31;i++) + calendar->marked_date[i] = FALSE; + calendar->selected_day = 1; + + calendar->arrow_width = 10; + + /* Create cursor */ + /* calendar->cross = gdk_cursor_new (GDK_PLUS); */ + + calendar->highlight_row = -1; + calendar->highlight_col = -1; + + + calendar->max_day_char_width=0; + calendar->max_week_char_width=0; + calendar->dirty_header = 0; + calendar->dirty_day_names = 0; + calendar->dirty_week = 0; + calendar->dirty_main = 0; + calendar->frozen = 0; +} + +GtkWidget* +gtk_calendar_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_calendar_get_type ())); +} + +/* column_from_x: returns the column 0-6 that the + * x pixel of the xwindow is in */ +static gint +column_from_x (GtkCalendar *calendar, gint event_x) +{ + gint c, column; + gint x_left, x_right; + + column = -1; + + for (c = 0; c < 7; c++) + { + x_left = left_x_for_column (calendar, c); + x_right = x_left + calendar->day_width; + + if (event_x > x_left && event_x < x_right) + { + column = c; + break; + } + } + + return column; +} + +static gint +row_height (GtkCalendar *calendar) +{ + return (calendar->main_h - CALENDAR_MARGIN + - ((calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES) + ? CALENDAR_YSEP : CALENDAR_MARGIN)) / 6; +} + + +/* row_from_y: returns the row 0-5 that the + * y pixel of the xwindow is in */ +static gint +row_from_y (GtkCalendar *calendar, gint event_y) +{ + gint r, row; + gint height; + gint y_top, y_bottom; + + height = row_height (calendar); + row = -1; + + for (r = 0; r < 6; r++) + { + y_top = top_y_for_row (calendar, r); + y_bottom = y_top + height; + + if (event_y > y_top && event_y < y_bottom) + { + row = r; + break; + } + } + + return row; +} + +/* left_x_for_column: returns the x coordinate + * for the left of the column */ +static gint +left_x_for_column (GtkCalendar *calendar, gint column) +{ + gint width; + gint x_left; + + width = calendar->day_width; + if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS) + x_left = DAY_XSEP + (width + DAY_XSEP) * column; + else + x_left = CALENDAR_MARGIN + (width + DAY_XSEP) * column; + + return x_left; +} + +/* top_y_for_row: returns the y coordinate + * for the top of the row */ +static gint +top_y_for_row (GtkCalendar *calendar, gint row) +{ + + return calendar->main_h - (CALENDAR_MARGIN + (6 - row) * + row_height (calendar)); +} + +/* This function should be done by the toolkit, but we don't like the + * GTK arrows because they don't look good on this widget */ +static void +draw_arrow_right (GdkWindow *window, GdkGC *gc, gint x, gint y, gint size) +{ + gint i; + + for (i = 0; i <= size / 2; i++) + { + gdk_draw_line (window, gc, + x + i, + y + i, + x + i, + y + size - i); + } +} + +/* This function should be done by the toolkit, but we don't like the + * GTK arrows because they don't look good on this widget */ +static void +draw_arrow_left (GdkWindow *window, GdkGC *gc, gint x, gint y, gint size) +{ + gint i; + + for (i = 0; i <= size / 2; i++) + { + gdk_draw_line (window, gc, + x + size/2 - i, + y + i, + x + size/2 - i, + y + size - i); + } +} + +static void +gtk_calendar_set_month_prev (GtkCalendar *calendar) +{ + gint month_len; + + if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE) + return; + + if (calendar->month == 0) + { + calendar->month = 11; + calendar->year--; + } + else + calendar->month--; + + month_len = month_length[leap (calendar->year)][calendar->month + 1]; + + gtk_calendar_freeze (calendar); + gtk_calendar_compute_days (calendar); + + gtk_signal_emit (GTK_OBJECT (calendar), + gtk_calendar_signals[PREV_MONTH_SIGNAL]); + gtk_signal_emit (GTK_OBJECT (calendar), + gtk_calendar_signals[MONTH_CHANGED_SIGNAL]); + + if (month_len < calendar->selected_day) + { + calendar->selected_day = 0; + gtk_calendar_select_day (calendar, month_len); + } + else + { + if (calendar->selected_day < 0) + calendar->selected_day = calendar->selected_day + 1 + month_length[leap (calendar->year)][calendar->month + 1]; + else + gtk_calendar_select_day (calendar, calendar->selected_day); + } + + gtk_calendar_select_day (calendar, calendar->selected_day); + gtk_calendar_paint (GTK_WIDGET (calendar), NULL); + gtk_calendar_thaw (calendar); +} + + +static void +gtk_calendar_set_month_next (GtkCalendar *calendar) +{ + gint month_len; + + g_return_if_fail (calendar != NULL); + g_return_if_fail (GTK_IS_WIDGET (calendar)); + + if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE) + return; + + + if (calendar->month == 11) + { + calendar->month = 0; + calendar->year++; + } + else + calendar->month++; + + gtk_calendar_freeze (calendar); + gtk_calendar_compute_days (calendar); + gtk_signal_emit (GTK_OBJECT (calendar), + gtk_calendar_signals[NEXT_MONTH_SIGNAL]); + gtk_signal_emit (GTK_OBJECT (calendar), + gtk_calendar_signals[MONTH_CHANGED_SIGNAL]); + + month_len = month_length[leap (calendar->year)][calendar->month + 1]; + + if (month_len < calendar->selected_day) + { + calendar->selected_day = 0; + gtk_calendar_select_day (calendar, month_len); + } + else + gtk_calendar_select_day (calendar, calendar->selected_day); + + gtk_calendar_paint (GTK_WIDGET(calendar), NULL); + gtk_calendar_thaw (calendar); +} + +static void +gtk_calendar_set_year_prev (GtkCalendar *calendar) +{ + gint month_len; + + g_return_if_fail (calendar != NULL); + g_return_if_fail (GTK_IS_WIDGET (calendar)); + + calendar->year--; + gtk_calendar_freeze (calendar); + gtk_calendar_compute_days (calendar); + gtk_signal_emit (GTK_OBJECT (calendar), + gtk_calendar_signals[PREV_YEAR_SIGNAL]); + gtk_signal_emit (GTK_OBJECT (calendar), + gtk_calendar_signals[MONTH_CHANGED_SIGNAL]); + + month_len = month_length[leap (calendar->year)][calendar->month + 1]; + + if (month_len < calendar->selected_day) + { + calendar->selected_day = 0; + gtk_calendar_select_day (calendar, month_len); + } + else + gtk_calendar_select_day (calendar, calendar->selected_day); + + gtk_calendar_paint (GTK_WIDGET (calendar), NULL); + gtk_calendar_thaw (calendar); +} + +static void +gtk_calendar_set_year_next (GtkCalendar *calendar) +{ + gint month_len; + GtkWidget *widget; + + g_return_if_fail (calendar != NULL); + g_return_if_fail (GTK_IS_WIDGET (calendar)); + + widget = GTK_WIDGET (calendar); + + gtk_calendar_freeze (calendar); + + calendar->year++; + gtk_calendar_compute_days (calendar); + gtk_signal_emit (GTK_OBJECT (calendar), + gtk_calendar_signals[NEXT_YEAR_SIGNAL]); + gtk_signal_emit (GTK_OBJECT (calendar), + gtk_calendar_signals[MONTH_CHANGED_SIGNAL]); + + month_len = month_length[leap (calendar->year)][calendar->month + 1]; + + if (month_len < calendar->selected_day) + { + calendar->selected_day = 0; + gtk_calendar_select_day (calendar, month_len); + } + else + gtk_calendar_select_day (calendar, calendar->selected_day); + + gtk_calendar_paint (GTK_WIDGET (calendar), NULL); + gtk_calendar_thaw (calendar); +} + +static void +gtk_calendar_main_button (GtkWidget *widget, + GdkEventButton *event) +{ + GtkCalendar *calendar; + gint x, y; + gint row, col; + gint day_month; + + calendar = GTK_CALENDAR (widget); + + x = (gint) (event->x); + y = (gint) (event->y); + + row = row_from_y (calendar, y); + col = column_from_x (calendar, x); + + day_month = calendar->day_month[row][col]; + + if (day_month == MONTH_CURRENT) + { + if (event->type == GDK_2BUTTON_PRESS) + gtk_signal_emit (GTK_OBJECT (calendar), + gtk_calendar_signals[DAY_SELECTED_DOUBLE_CLICK_SIGNAL]); + else + { + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + gtk_calendar_select_day (calendar, calendar->day[row][col]); + } + } + else if (day_month == MONTH_PREV) + gtk_calendar_set_month_prev (calendar); + else if (day_month == MONTH_NEXT) + gtk_calendar_set_month_next (calendar); +} + +static void +gtk_calendar_realize_arrows (GtkWidget *widget) +{ + GtkCalendar *calendar; + GdkWindowAttr attributes; + gint attributes_mask; + gint i; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + + calendar = GTK_CALENDAR (widget); + /* Arrow windows ------------------------------------- */ + if (! (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE) + && (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING)) + { + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + 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 | GDK_BUTTON_RELEASE_MASK + | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + attributes.y = 3; + attributes.width = calendar->arrow_width; + attributes.height = calendar->header_h - 7; + for (i = 0; i < 4; i++) + { + switch (i) + { + case ARROW_MONTH_LEFT: + attributes.x = 3; + break; + case ARROW_MONTH_RIGHT: + attributes.x = calendar->arrow_width + calendar->max_month_width; + break; + case ARROW_YEAR_LEFT: + attributes.x = (widget->allocation.width + - (3 + 2*calendar->arrow_width + calendar->max_year_width)); + break; + case ARROW_YEAR_RIGHT: + attributes.x = widget->allocation.width - 3 - calendar->arrow_width; + break; + } + calendar->arrow_win[i] = gdk_window_new (calendar->header_win, + &attributes, attributes_mask); + calendar->arrow_state[i] = GTK_STATE_NORMAL; + gdk_window_set_background (calendar->arrow_win[i], + HEADER_BG_COLOR (GTK_WIDGET (calendar))); + gdk_window_show (calendar->arrow_win[i]); + gdk_window_set_user_data (calendar->arrow_win[i], widget); + } + } + else + for (i = 0; i < 4; i++) + calendar->arrow_win[i] = NULL; +} + +static void +gtk_calendar_realize_header (GtkWidget *widget) +{ + GtkCalendar *calendar; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + + calendar = GTK_CALENDAR (widget); + + /* Header window ------------------------------------- */ + if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING) + { + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + 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; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + attributes.x = 0; + attributes.y = 0; + attributes.width = widget->allocation.width; + attributes.height = calendar->header_h; + calendar->header_win = gdk_window_new (widget->window, + &attributes, attributes_mask); + + gdk_window_set_background (calendar->header_win, + HEADER_BG_COLOR (GTK_WIDGET (calendar))); + gdk_window_show (calendar->header_win); + gdk_window_set_user_data (calendar->header_win, widget); + + } + else + calendar->header_win = NULL; + + gtk_calendar_realize_arrows (widget); +} + +static void +gtk_calendar_realize_day_names (GtkWidget *widget) +{ + GtkCalendar *calendar; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + + calendar = GTK_CALENDAR (widget); + + /* Day names window --------------------------------- */ + if ( calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES) + { + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + 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; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + attributes.x = (widget->style->klass->xthickness + INNER_BORDER); + attributes.y = calendar->header_h + (widget->style->klass->ythickness + INNER_BORDER); + attributes.width = widget->allocation.width - (widget->style->klass->xthickness + INNER_BORDER) *2; + attributes.height = calendar->day_name_h; + calendar->day_name_win = gdk_window_new (widget->window, + &attributes, attributes_mask); + gdk_window_set_background (calendar->day_name_win, BACKGROUND_COLOR ( GTK_WIDGET ( calendar))); + gdk_window_show (calendar->day_name_win); + gdk_window_set_user_data (calendar->day_name_win, widget); + } + else + calendar->day_name_win = NULL; +} + +static void +gtk_calendar_realize_week_numbers (GtkWidget *widget) +{ + GtkCalendar *calendar; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + + calendar = GTK_CALENDAR (widget); + /* Week number window -------------------------------- */ + if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS) + { + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + 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; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + attributes.x = + (widget->style->klass->xthickness + INNER_BORDER); + attributes.y = (calendar->header_h + calendar->day_name_h + + (widget->style->klass->ythickness + INNER_BORDER)); + attributes.width = calendar->week_width; + attributes.height = calendar->main_h; + calendar->week_win = gdk_window_new (widget->window, + &attributes, attributes_mask); + gdk_window_set_background (calendar->week_win, BACKGROUND_COLOR (GTK_WIDGET (calendar))); + gdk_window_show (calendar->week_win); + gdk_window_set_user_data (calendar->week_win, widget); + } + else + calendar->week_win = NULL; +} + + +static void +gtk_calendar_realize (GtkWidget *widget) +{ + GtkCalendar *calendar; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + + calendar = GTK_CALENDAR (widget); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + gtk_calendar_compute_days (calendar); + + 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.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = (gtk_widget_get_events (widget) + | GDK_EXPOSURE_MASK |GDK_KEY_PRESS_MASK); + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (widget->parent->window, + &attributes, attributes_mask); + + widget->style = gtk_style_attach (widget->style, widget->window); + + /* Header window ------------------------------------- */ + gtk_calendar_realize_header (widget); + /* Day names window --------------------------------- */ + gtk_calendar_realize_day_names (widget); + /* Week number window -------------------------------- */ + gtk_calendar_realize_week_numbers (widget); + /* Main Window -------------------------------------- */ + attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK + | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK); + + if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS) + attributes.x = calendar->week_width; + else + attributes.x = 0; + attributes.x += (widget->style->klass->xthickness + INNER_BORDER); + attributes.y = calendar->header_h + calendar->day_name_h + (widget->style->klass->ythickness + INNER_BORDER); + attributes.width = widget->allocation.width - attributes.x - (widget->style->klass->xthickness + INNER_BORDER); + attributes.height = calendar->main_h; + calendar->main_win = gdk_window_new (widget->window, + &attributes, attributes_mask); + gdk_window_set_background (calendar->main_win, BACKGROUND_COLOR ( GTK_WIDGET ( calendar))); + gdk_window_show (calendar->main_win); + gdk_window_set_user_data (calendar->main_win, widget); + gdk_window_set_background (widget->window, BACKGROUND_COLOR (widget)); + gdk_window_show (widget->window); + gdk_window_set_user_data (widget->window, widget); + + /* Set widgets gc */ + calendar->gc = gdk_gc_new (widget->window); +} + +static void +gtk_calendar_unrealize (GtkWidget *widget) +{ + GtkCalendar *calendar; + gint i; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + + calendar = GTK_CALENDAR (widget); + + if (calendar->header_win) + { + for (i=0; i<4; i++) + if (calendar->arrow_win[i]) + { + gdk_window_set_user_data (calendar->arrow_win[i], NULL); + gdk_window_destroy (calendar->arrow_win[i]); + calendar->arrow_win[i] = NULL; + } + gdk_window_set_user_data (calendar->header_win, NULL); + gdk_window_destroy (calendar->header_win); + calendar->header_win = NULL; + } + + if (calendar->week_win) + { + gdk_window_set_user_data (calendar->week_win, NULL); + gdk_window_destroy (calendar->week_win); + calendar->week_win = NULL; + } + + if (calendar->main_win) + { + gdk_window_set_user_data (calendar->main_win, NULL); + gdk_window_destroy (calendar->main_win); + calendar->main_win = NULL; + } + + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} + +static void +gtk_calendar_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkCalendar *calendar; + gint height; + gint i; + gchar buffer[255]; + gint calendar_margin = CALENDAR_MARGIN; + gint header_width, main_width; + gint day_font_lbearing; + gint day_font_rbearing; + gint day_font_width; +#ifdef GTK_HAVE_FEATURES_1_1_0 + gint lbearing; + gint rbearing; + gint ascent; + gint descent; + gint width; +#endif /* GTK_HAVE_FEATURES_1_1_0 */ + + calendar = GTK_CALENDAR (widget); + + /* + * Calculate the requisition width for the widget. + */ + + /* Header width */ + + if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING) + { + calendar->max_month_width = 0; + for (i = 0; i < 12; i++) + calendar->max_month_width = MAX (calendar->max_month_width, + gdk_string_measure (HEADER_FONT (widget), + default_monthname[i]) + 8); + + calendar->max_year_width = 0; + for (i=0; i<10; i++) + { + sprintf (buffer, "%d%d%d%d", i,i,i,i); + calendar->max_year_width = MAX (calendar->max_year_width, + gdk_string_measure (HEADER_FONT (widget), + buffer) + 8); + } + } + else + { + calendar->max_month_width = 0; + calendar->max_year_width = 0; + } + + if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE) + header_width = (calendar->max_month_width + calendar->max_year_width + + 3 * 3); + else + header_width = (calendar->max_month_width + calendar->max_year_width + + 4 * calendar->arrow_width + 3 * 3); + + /* Mainwindow labels width */ + + calendar->max_day_char_width = 0; + for (i = 0; i < 9; i++) + { + sprintf (buffer, "%d%d", i, i); + calendar->min_day_width = MAX (calendar->max_day_char_width, + gdk_string_measure (DAY_FONT (widget), + buffer)); + } + /* We add one to max_day_char_width to be able to make the marked day "bold" */ + calendar->max_day_char_width = calendar->min_day_width / 2 +1; + + if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES) + for (i = 0; i < 7; i++) + { +#ifdef GTK_HAVE_FEATURES_1_1_0 + gdk_text_extents (LABEL_FONT (widget), + default_abbreviated_dayname[i], + strlen(default_abbreviated_dayname[i]), + &lbearing, + &rbearing, + &width, + &ascent, + &descent); + calendar->min_day_width = MAX (calendar->min_day_width, width); + calendar->max_label_char_ascent = MAX (calendar->max_label_char_ascent, + ascent); + calendar->max_label_char_descent = MAX (calendar->max_label_char_descent + , descent); +#else /* not GTK_HAVE_FEATURES_1_1_0 */ + calendar->min_day_width = MAX (calendar->min_day_width, + gdk_string_measure (LABEL_FONT (widget), + default_abbreviated_dayname[i])); + calendar->max_label_char_ascent = LABEL_FONT (widget)->ascent; + calendar->max_label_char_descent = LABEL_FONT (widget)->descent; +#endif /* not GTK_HAVE_FEATURES_1_1_0 */ + } + + calendar->max_week_char_width = 0; + if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS) + for (i = 0; i < 9; i++) + { + sprintf (buffer, "%d%d", i, i); + calendar->max_week_char_width = MAX (calendar->max_week_char_width, + gdk_string_measure (LABEL_FONT (widget), buffer) / 2); + } + + main_width = (7 * (calendar->min_day_width + DAY_XPAD * 2) + (DAY_XSEP * 6) + CALENDAR_MARGIN * 2 + + (calendar->max_week_char_width + ? calendar->max_week_char_width * 2 + DAY_XPAD * 2 + CALENDAR_XSEP * 2 + : 0)); + + + requisition->width = MAX (header_width, main_width + (widget->style->klass->xthickness + INNER_BORDER) *2); + + /* + * Calculate the requisition height for the widget. + */ + + if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING) + calendar->header_h = (HEADER_FONT (widget)->ascent + HEADER_FONT (widget)->descent + + CALENDAR_YSEP * 2); + else + calendar->header_h = 0; + + + if (calendar->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES) + { + calendar->day_name_h = (calendar->max_label_char_ascent + + calendar->max_label_char_descent + + 2 * DAY_YPAD + calendar_margin); + calendar_margin = CALENDAR_YSEP; + } + else + calendar->day_name_h = 0; + +#ifdef GTK_HAVE_FEATURES_1_1_0 + gdk_text_extents (DAY_FONT (widget), + "0123456789", + 10, + &lbearing, + &rbearing, + &width, + &calendar->max_day_char_ascent, + &calendar->max_day_char_descent); +#else /* not GTK_HAVE_FEATURES_1_1_0 */ + calendar->max_day_char_ascent = DAY_FONT (widget)->ascent; + calendar->max_day_char_descent = DAY_FONT (widget)->descent; +#endif /* not GTK_HAVE_FEATURES_1_1_0 */ + + calendar->main_h = (CALENDAR_MARGIN + calendar_margin + + 6 * (calendar->max_day_char_ascent + + calendar->max_day_char_descent + DAY_YPAD * 2) + + DAY_YSEP * 5); + + /* + * If we display weeknumbers we need some extra space + */ + + if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS) + calendar->main_h = MAX (calendar->main_h, + (CALENDAR_MARGIN + calendar_margin + + 6 * (calendar->max_day_char_ascent + + calendar->max_day_char_descent + + DAY_YPAD * 2) + + DAY_YSEP * 5)); + + height = calendar->header_h + calendar->day_name_h + calendar->main_h; + + requisition->height = height + (widget->style->klass->ythickness + INNER_BORDER) * 2; +} + +static void +gtk_calendar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkCalendar *calendar; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + + calendar = GTK_CALENDAR (widget); + + if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS) + { + calendar->day_width = (calendar->min_day_width + * ((allocation->width - (widget->style->klass->xthickness + INNER_BORDER) * 2 + - (CALENDAR_MARGIN * 2) - (DAY_XSEP * 7) - CALENDAR_XSEP * 2)) + / (7 * calendar->min_day_width + calendar->max_week_char_width * 2)); + calendar->week_width = ((allocation->width - (widget->style->klass->xthickness + INNER_BORDER) * 2 + - (CALENDAR_MARGIN * 2) - (DAY_XSEP * 7) - CALENDAR_XSEP * 2 ) + - calendar->day_width * 7 + CALENDAR_MARGIN + CALENDAR_XSEP); + } + else + { + calendar->day_width = (allocation->width + - (widget->style->klass->xthickness + INNER_BORDER) * 2 + - (CALENDAR_MARGIN * 2) + - (DAY_XSEP * 7))/7; + calendar->week_width = 0; + } + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + if (calendar->header_win) + gdk_window_move_resize (calendar->header_win, + 0, 0, + allocation->width, calendar->header_h); + if (calendar->arrow_win[ARROW_MONTH_LEFT]) + gdk_window_move_resize (calendar->arrow_win[ARROW_MONTH_LEFT], + 3, 3, + calendar->arrow_width, + calendar->header_h - 7); + if (calendar->arrow_win[ARROW_MONTH_RIGHT]) + gdk_window_move_resize (calendar->arrow_win[ARROW_MONTH_RIGHT], + calendar->arrow_width + calendar->max_month_width, 3, + calendar->arrow_width, + calendar->header_h - 7); + if (calendar->arrow_win[ARROW_YEAR_LEFT]) + gdk_window_move_resize (calendar->arrow_win[ARROW_YEAR_LEFT], + allocation->width + - (3 + 2*calendar->arrow_width + calendar->max_year_width), + 3, + calendar->arrow_width, + calendar->header_h - 7); + if (calendar->arrow_win[ARROW_YEAR_RIGHT]) + gdk_window_move_resize (calendar->arrow_win[ARROW_YEAR_RIGHT], + allocation->width - 3 - calendar->arrow_width, 3, + calendar->arrow_width, + calendar->header_h - 7); + if (calendar->day_name_win) + gdk_window_move_resize (calendar->day_name_win, + (widget->style->klass->xthickness + INNER_BORDER), + calendar->header_h + (widget->style->klass->ythickness + INNER_BORDER), + allocation->width - (widget->style->klass->xthickness + INNER_BORDER) * 2, + calendar->day_name_h); + if (calendar->week_win) + gdk_window_move_resize (calendar->week_win, + (widget->style->klass->xthickness + INNER_BORDER), + calendar->header_h + calendar->day_name_h + + (widget->style->klass->ythickness + INNER_BORDER), + calendar->week_width, + calendar->main_h); + gdk_window_move_resize (calendar->main_win, + (calendar->week_width ? calendar->week_width + CALENDAR_XSEP :0) + + (widget->style->klass->xthickness + INNER_BORDER), + calendar->header_h + calendar->day_name_h + + (widget->style->klass->ythickness + INNER_BORDER), + allocation->width + - (calendar->week_width ? calendar->week_width + CALENDAR_XSEP :0) + - (widget->style->klass->xthickness + INNER_BORDER) * 2, + calendar->main_h); + } +} + + + +static void +gtk_calendar_draw_focus (GtkWidget *widget) +{ + gint width, height; + gint x, y; + GtkCalendar *calendar; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + calendar = GTK_CALENDAR (widget); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + x = 0; + y = 0; + gdk_window_get_size (widget->window, &width, &height); + gdk_window_clear (widget->window); + + if (calendar->display_flags & GTK_CALENDAR_SHOW_HEADING) + { + y += calendar->header_h; + height -= calendar->header_h; + } + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + x += 1; + y += 1; + width -= 2; + height -= 2; + } + else + { + gdk_draw_rectangle (widget->window, + widget->style->base_gc[GTK_WIDGET_STATE (widget)], + FALSE, x + 2, y + 2, width - 5, height - 5); + } + + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_IN, + x, y, width, height); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + gdk_window_get_size (widget->window, &width, &height); + gdk_draw_rectangle (widget->window, widget->style->fg_gc[GTK_STATE_NORMAL], + FALSE, 0, 0, width - 1, height - 1); + } + } +} + +static gint +gtk_calendar_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkCalendar *calendar; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + calendar = GTK_CALENDAR (widget); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + if (event->window == calendar->main_win) + gtk_calendar_paint_main (widget); + + if (event->window == calendar->header_win) + gtk_calendar_paint_header (widget); + + if (event->window == calendar->day_name_win) + gtk_calendar_paint_day_names (widget); + + if (event->window == calendar->week_win) + gtk_calendar_paint_week_numbers (widget); + if (event->window == widget->window) + gtk_widget_draw_focus (widget); + } + + return FALSE; +} + +static void +gtk_calendar_draw (GtkWidget *widget, + GdkRectangle *area) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + gtk_calendar_paint (widget, area); + +} + + +static void +gtk_calendar_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GtkCalendar *calendar; + + g_return_if_fail (widget != NULL); + g_return_if_fail (widget->window != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + + calendar = GTK_CALENDAR (widget); + + if (calendar->main_win != NULL) + gtk_calendar_paint_main (widget); + + if (calendar->header_win != NULL) + gtk_calendar_paint_header (widget); + + if (calendar->day_name_win != NULL) + gtk_calendar_paint_day_names (widget); + + if (calendar->week_win != NULL) + gtk_calendar_paint_week_numbers (widget); + + gtk_widget_draw_focus (widget); +} + +void +gtk_calendar_paint_header (GtkWidget *widget) +{ + GtkCalendar *calendar; + GdkGC *gc; + char buffer[255]; + int y, y_arrow; + gint cal_width, cal_height; + gint str_width; + gint max_month_width; + gint max_year_width; + + calendar = GTK_CALENDAR (widget); + if (calendar->frozen) + { + calendar->dirty_header = 1; + return; + } + calendar->dirty_header = 0; + gc = calendar->gc; + + /* Clear window */ + gdk_window_clear (calendar->header_win); + + cal_width = widget->allocation.width; + cal_height = widget->allocation.height; + + max_month_width = calendar->max_month_width; + max_year_width = calendar->max_year_width; + + gdk_gc_set_foreground (gc, BACKGROUND_COLOR (GTK_WIDGET (calendar))); + gtk_draw_shadow (widget->style, calendar->header_win, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, + 0, 0, cal_width, calendar->header_h); + + + /* Draw title */ + y = calendar->header_h - (calendar->header_h - HEADER_FONT (widget)->ascent + + HEADER_FONT (widget)->descent) / 2; + y_arrow = (calendar->header_h - 9) / 2; + + /* Draw year and its arrows */ + sprintf (buffer, "%d", calendar->year); + str_width = gdk_string_measure (HEADER_FONT (widget), buffer); + gdk_gc_set_foreground (gc, HEADER_FG_COLOR (GTK_WIDGET (calendar))); + if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE) + gdk_draw_string (calendar->header_win, HEADER_FONT (widget), gc, + cal_width - (3 + max_year_width + - (max_year_width - str_width)/2), + y, buffer); + else + gdk_draw_string (calendar->header_win, HEADER_FONT (widget), gc, + cal_width - (3 + calendar->arrow_width + max_year_width + - (max_year_width - str_width)/2), + y, buffer); + + /* Draw month */ + sprintf (buffer, "%s", default_monthname[calendar->month]); + str_width = gdk_string_measure (HEADER_FONT (widget), buffer); + if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE) + gdk_draw_string (calendar->header_win, HEADER_FONT (widget), gc, + 3 + (max_month_width - str_width) / 2, + y, buffer); + else + gdk_draw_string (calendar->header_win, HEADER_FONT (widget), gc, + 3 + calendar->arrow_width + (max_month_width - str_width)/2, + y, buffer); + + y += CALENDAR_YSEP + HEADER_FONT (widget)->descent; + + gdk_gc_set_foreground (gc, BACKGROUND_COLOR (GTK_WIDGET (calendar))); + + gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT); + gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT); + gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT); + gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT); + +} + +void +gtk_calendar_paint_day_names (GtkWidget *widget) +{ + GtkCalendar *calendar; + GdkGC *gc; + char buffer[255]; + int day,i; + int day_width, cal_width; + gint cal_height; + int day_wid_sep; + int str_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + calendar = GTK_CALENDAR (widget); + gc = calendar->gc; + + /* + * Handle freeze/thaw functionality + */ + + if (calendar->frozen) + { + calendar->dirty_day_names = 1; + return; + } + calendar->dirty_day_names = 0; + + /* + * Clear the window + */ + + gdk_window_clear (calendar->day_name_win); + + day_width = calendar->day_width; + cal_width = widget->allocation.width; + cal_height = widget->allocation.height; + day_wid_sep = day_width + DAY_XSEP; + + /* + * Draw rectangles as inverted background for the labels. + */ + + gdk_gc_set_foreground (gc, DAY_NAME_COLOR (GTK_WIDGET (calendar))); + gdk_gc_set_background (gc, DAY_NAME_COLOR (GTK_WIDGET (calendar))); + gdk_draw_rectangle (calendar->day_name_win, gc, TRUE, + CALENDAR_MARGIN, CALENDAR_MARGIN, + cal_width-CALENDAR_MARGIN * 2, + calendar->day_name_h - CALENDAR_MARGIN); + + + if (calendar->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS) + gdk_draw_rectangle (calendar->day_name_win, gc, TRUE, + CALENDAR_MARGIN, + calendar->day_name_h - CALENDAR_YSEP, + calendar->week_width - CALENDAR_YSEP - CALENDAR_MARGIN, + CALENDAR_YSEP); + + /* + * Write the labels + */ + + gdk_gc_set_foreground (gc, BACKGROUND_COLOR ( GTK_WIDGET (calendar))); + for (i = 0; i < 7; i++) + { + day=i; + if (calendar->display_flags & GTK_CALENDAR_WEEK_START_MONDAY) + day= (day+1)%7; + sprintf (buffer, "%s", default_abbreviated_dayname[day]); + str_width = gdk_string_measure (LABEL_FONT (widget), buffer); + gdk_draw_string (calendar->day_name_win, LABEL_FONT (widget), + gc, + ((calendar->week_width ? CALENDAR_XSEP : CALENDAR_MARGIN) + + day_wid_sep * i + + calendar->week_width + + (day_width - str_width)/2), + CALENDAR_MARGIN + DAY_YPAD + + calendar->max_label_char_ascent, buffer); + } +} + +void +gtk_calendar_paint_week_numbers (GtkWidget *widget) +{ + GtkCalendar *calendar; + GdkGC *gc; + gint row, week, year; + gint x_loc; + char buffer[3]; + gint y_baseline, day_height; + + g_return_if_fail (widget != NULL); + g_return_if_fail (widget->window != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + calendar = GTK_CALENDAR (widget); + gc = calendar->gc; + + /* + * Handle freeze/thaw functionality + */ + + if (calendar->frozen) + { + calendar->dirty_week = 1; + return; + } + calendar->dirty_week = 0; + + /* + * Clear the window + */ + + gdk_window_clear (calendar->week_win); + + /* + * Draw a rectangle as inverted background for the labels. + */ + + gdk_gc_set_foreground (gc, DAY_NAME_COLOR (GTK_WIDGET (calendar))); + gdk_gc_set_background (gc, DAY_NAME_COLOR (GTK_WIDGET (calendar))); + if (calendar->day_name_win) + gdk_draw_rectangle (calendar->week_win, gc, TRUE, + CALENDAR_MARGIN, + 0, + calendar->week_width - CALENDAR_MARGIN - CALENDAR_XSEP, + calendar->main_h - CALENDAR_MARGIN); + else + gdk_draw_rectangle (calendar->week_win, gc, TRUE, + CALENDAR_MARGIN, + CALENDAR_MARGIN, + calendar->week_width - CALENDAR_MARGIN - CALENDAR_XSEP, + calendar->main_h - 2 * CALENDAR_MARGIN); + + /* + * Write the labels + */ + + gdk_gc_set_foreground (gc, BACKGROUND_COLOR (GTK_WIDGET (calendar))); + day_height = row_height (calendar); + for (row = 0; row < 6; row++) + { + year = calendar->year; + if (calendar->day[row][6] < 15 && row > 3 && calendar->month == 11) + year++; + y_baseline = (top_y_for_row (calendar, row) + + (day_height + LABEL_FONT (widget)->ascent + - LABEL_FONT (widget)->descent)/2); + g_return_if_fail (week_of_year (&week, &year, + ((calendar->day[row][6] < 15 && row > 3 ? 1 : 0) + + calendar->month) % 12 + 1, calendar->day[row][6])); + x_loc= (calendar->week_width - (calendar->week_width - CALENDAR_XSEP + - DAY_XPAD * 2 - CALENDAR_MARGIN ) / 2 + - calendar->max_week_char_width + - CALENDAR_XSEP - DAY_XPAD); + + if (week > 9) + { + sprintf (buffer, "%d", week/10); + gdk_draw_string (calendar->week_win, LABEL_FONT (widget), gc, + x_loc, y_baseline , buffer); + } + + sprintf (buffer, "%d", week%10); + gdk_draw_string (calendar->week_win, LABEL_FONT (widget), gc, + x_loc + calendar->max_week_char_width, y_baseline , buffer); + } +} + +static void +gtk_calendar_paint_day_num (GtkWidget *widget, gint day) +{ + GtkCalendar *calendar; + gint r, c, row, col; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + + calendar = GTK_CALENDAR (widget); + + row = -1; + col = -1; + for (r = 0; r < 6; r++) + for (c = 0; c < 7; c++) + if (calendar->day_month[r][c] == MONTH_CURRENT && + calendar->day[r][c] == day) + { + row = r; + col = c; + } + + g_return_if_fail (row != -1); + g_return_if_fail (col != -1); + + gtk_calendar_paint_day (widget, row, col); +} + + +static void +gtk_calendar_paint_day (GtkWidget *widget, gint row, gint col) +{ + GtkCalendar *calendar; + GdkGC *gc; + gchar buffer[255]; + gint day; + gint day_height; + gint x_left; + gint x_loc; + gint y_top; + gint y_baseline; + gint day_xspace; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + g_return_if_fail (row < 6); + g_return_if_fail (col < 7); + calendar = GTK_CALENDAR (widget); + + /* + * Handle freeze/thaw functionality + */ + + if (calendar->frozen) + { + calendar->dirty_main = 1; + return; + } + + day_height = row_height (calendar); + + day_xspace = calendar->day_width - calendar->max_day_char_width*2; + + day = calendar->day[row][col]; + + x_left = left_x_for_column (calendar, col); + x_loc = x_left + calendar->day_width / 2 + calendar->max_day_char_width; + + y_top = top_y_for_row (calendar, row); + y_baseline = y_top + (day_height + calendar->max_day_char_ascent)/2; + + gdk_window_clear_area (calendar->main_win, x_left, y_top, + calendar->day_width, day_height); + + gc = calendar->gc; + + if (calendar->day_month[row][col] == MONTH_PREV) + { + gdk_gc_set_foreground (gc, PREV_MONTH_COLOR (GTK_WIDGET (calendar))); + } + else if (calendar->day_month[row][col] == MONTH_NEXT) + { + gdk_gc_set_foreground (gc, NEXT_MONTH_COLOR (GTK_WIDGET (calendar))); + } + else + { + if (calendar->highlight_row == row && calendar->highlight_col == col) + { + gdk_gc_set_foreground (gc, HIGHLIGHT_BACK_COLOR (GTK_WIDGET (calendar))); + gdk_draw_rectangle (calendar->main_win, gc, TRUE, x_left, y_top, + calendar->day_width, day_height); + } + + if (calendar->selected_day == day) + { + if (GTK_WIDGET_HAS_FOCUS (widget)) + gdk_gc_set_foreground (gc, SELECTION_FOCUS_COLOR (GTK_WIDGET (calendar))); + else + gdk_gc_set_foreground (gc, SELECTION_NO_FOCUS_COLOR (GTK_WIDGET (calendar))); + gdk_draw_rectangle (calendar->main_win, gc, FALSE, x_left, y_top, + calendar->day_width-1, day_height-1); + } + + if (calendar->marked_date[day-1]) + gdk_gc_set_foreground (gc, MARKED_COLOR (GTK_WIDGET (calendar))); + else + gdk_gc_set_foreground (gc, NORMAL_DAY_COLOR (GTK_WIDGET (calendar))); + } + + sprintf (buffer, "%d", day); + x_loc -= gdk_string_measure (DAY_FONT (widget), buffer); + sprintf (buffer, "%d", day); + gdk_draw_string (calendar->main_win, + DAY_FONT (widget), gc, + x_loc, y_baseline, buffer); + if (calendar->marked_date[day-1]) + gdk_draw_string (calendar->main_win, + DAY_FONT (widget), gc, + x_loc-1, y_baseline, buffer); +} + + +void +gtk_calendar_paint_main (GtkWidget *widget) +{ + GtkCalendar *calendar; + gint row, col; + + g_return_if_fail (widget != NULL); + g_return_if_fail (widget->window != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + + calendar = GTK_CALENDAR (widget); + if (calendar->frozen) + { + calendar->dirty_main = 1; + return; + } + calendar->dirty_main = 0; + gdk_window_clear (calendar->main_win); + + // gtk_calendar_compute_days (calendar); /* REMOVE later */ + + for (col = 0; col < 7; col++) + for (row = 0; row < 6; row++) + gtk_calendar_paint_day (widget, row, col); +} + +static void +gtk_calendar_compute_days (GtkCalendar *calendar) +{ + gint month; + gint year; + gint ndays_in_month; + gint ndays_in_prev_month; + gint first_day; + gint row; + gint col; + gint day; + + g_return_if_fail (calendar != NULL); + g_return_if_fail (GTK_IS_CALENDAR (calendar)); + + year = calendar->year; + month = calendar->month + 1; + + ndays_in_month = month_length[leap (year)][month]; + + first_day = day_of_week (year, month, 1); + + if (calendar->display_flags & GTK_CALENDAR_WEEK_START_MONDAY) + first_day--; + else + first_day %= 7; + + + /* Compute days of previous month */ + if (month > 1) + ndays_in_prev_month = month_length[leap (year)][month-1]; + else + ndays_in_prev_month = month_length[leap (year)][12]; + day = ndays_in_prev_month - first_day + 1; + + row = 0; + if (first_day > 0) + { + for (col = 0; col < first_day; col++) + { + calendar->day[row][col] = day; + calendar->day_month[row][col] = MONTH_PREV; + day++; + } + } + + /* Compute days of current month */ + col = first_day; + for (day = 1; day <= ndays_in_month; day++) + { + calendar->day[row][col] = day; + calendar->day_month[row][col] = MONTH_CURRENT; + + col++; + if (col == 7) + { + row++; + col = 0; + } + } + + /* Compute days of next month */ + day = 1; + for (; row <= 5; row++) + { + for (; col <= 6; col++) + { + calendar->day[row][col] = day; + calendar->day_month[row][col] = MONTH_NEXT; + day++; + } + col = 0; + } +} + +/* ---------------------------------------------------------------------- + NAME: gtk_calendar_display_options + DESCRIPTION: Set display options (whether to display the + heading and the month headings) + + flags is can be an XOR of: + GTK_CALENDAR_SHOW_HEADING + GTK_CALENDAR_SHOW_DAY_NAMES + GTK_CALENDAR_NO_MONTH_CHANGE + GTK_CALENDAR_SHOW_WEEK_NUMBERS + GTK_CALENDAR_WEEK_START_MONDAY + ---------------------------------------------------------------------- */ + +void gtk_calendar_display_options (GtkCalendar *calendar, + GtkCalendarDisplayOptions flags) +{ + gint resize = 0; + GtkWidget *widget; + gint i; + + g_return_if_fail (GTK_IS_CALENDAR (calendar)); + g_return_if_fail (GTK_IS_WIDGET (calendar)); + widget = GTK_WIDGET (calendar); + + if (GTK_WIDGET_REALIZED (widget)) + { + if ((flags ^ calendar->display_flags) & GTK_CALENDAR_NO_MONTH_CHANGE) + { + resize ++; + if (! (flags & GTK_CALENDAR_NO_MONTH_CHANGE) + && (calendar->header_win)) + { + calendar->display_flags &= ~GTK_CALENDAR_NO_MONTH_CHANGE; + gtk_calendar_realize_arrows (widget); + } + else + { + for (i=0; i<4; i++) + if (calendar->arrow_win[i]) + { + gdk_window_set_user_data (calendar->arrow_win[i], NULL); + gdk_window_destroy (calendar->arrow_win[i]); + calendar->arrow_win[i] = NULL; + } + } + } + + if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_HEADING) + { + resize++; + + if (flags & GTK_CALENDAR_SHOW_HEADING) + { + calendar->display_flags |= GTK_CALENDAR_SHOW_HEADING; + gtk_calendar_realize_header (widget); + } + else + { + for (i=0; i<4; i++) + if (calendar->arrow_win[i]) + { + gdk_window_set_user_data (calendar->arrow_win[i], NULL); + gdk_window_destroy (calendar->arrow_win[i]); + calendar->arrow_win[i] = NULL; + } + gdk_window_set_user_data (calendar->header_win, NULL); + gdk_window_destroy (calendar->header_win); + calendar->header_win = NULL; + } + } + + + if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_DAY_NAMES) + { + resize++; + + if (flags & GTK_CALENDAR_SHOW_DAY_NAMES) + { + calendar->display_flags |= GTK_CALENDAR_SHOW_DAY_NAMES; + gtk_calendar_realize_day_names (widget); + } + else + { + gdk_window_set_user_data (calendar->day_name_win, NULL); + gdk_window_destroy (calendar->day_name_win); + calendar->day_name_win = NULL; + } + } + + if ((flags ^ calendar->display_flags) & GTK_CALENDAR_SHOW_WEEK_NUMBERS) + { + resize++; + + if (flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS) + { + calendar->display_flags |= GTK_CALENDAR_SHOW_WEEK_NUMBERS; + gtk_calendar_realize_week_numbers (widget); + } + else + { + gdk_window_set_user_data (calendar->week_win, NULL); + gdk_window_destroy (calendar->week_win); + calendar->week_win = NULL; + } + } + + if ((flags ^ calendar->display_flags) & GTK_CALENDAR_WEEK_START_MONDAY) + { + if (calendar->display_flags & GTK_CALENDAR_WEEK_START_MONDAY) + calendar->display_flags &= ~GTK_CALENDAR_WEEK_START_MONDAY; + else + calendar->display_flags |= GTK_CALENDAR_WEEK_START_MONDAY; + + gtk_calendar_compute_days (calendar); + gtk_calendar_paint_main (GTK_WIDGET (calendar)); + if (calendar->day_name_win) + gtk_calendar_paint_day_names (GTK_WIDGET (calendar)); + } + + calendar->display_flags = flags; + if (resize) + gtk_widget_queue_resize (GTK_WIDGET (calendar)); + + } + else + calendar->display_flags = flags; + +} + +gint +gtk_calendar_select_month (GtkCalendar *calendar, gint month, gint year) +{ + g_return_val_if_fail (calendar != NULL, FALSE); + g_return_val_if_fail (month >= 0 && month <= 11, FALSE); + g_return_val_if_fail (GTK_IS_CALENDAR (calendar), FALSE); + + calendar->month = month; + calendar->year = year; + + gtk_calendar_compute_days (calendar); + + if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar))) + gtk_calendar_paint (GTK_WIDGET (calendar), NULL); + + gtk_signal_emit (GTK_OBJECT (calendar), + gtk_calendar_signals[MONTH_CHANGED_SIGNAL]); + return TRUE; +} + +void +gtk_calendar_select_day (GtkCalendar *calendar, gint day) +{ + g_return_if_fail (calendar != NULL); + g_return_if_fail (GTK_IS_CALENDAR(calendar)); + + // gtk_calendar_compute_days (calendar); + + /* Deselect the old day */ + if (calendar->selected_day > 0) + { + gint selected_day; + + selected_day = calendar->selected_day; + calendar->selected_day = 0; + if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar))) + gtk_calendar_paint_day_num (GTK_WIDGET (calendar), selected_day); + } + + calendar->selected_day = day; + + /* Deselect the new day */ + if (day != 0) + { + if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar))) + gtk_calendar_paint_day_num (GTK_WIDGET (calendar), day); + } + + gtk_signal_emit (GTK_OBJECT (calendar), + gtk_calendar_signals[DAY_SELECTED_SIGNAL]); +} + +void +gtk_calendar_clear_marks (GtkCalendar *calendar) +{ + gint day; + + g_return_if_fail (calendar != NULL); + + for (day = 0; day < 31; day ++) + { + calendar->marked_date[day] = FALSE; + } + + if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar))) + { + gtk_calendar_paint_main (GTK_WIDGET (calendar)); + } +} + +gint +gtk_calendar_mark_day (GtkCalendar *calendar, gint day) +{ + g_return_val_if_fail (calendar != NULL, FALSE); + + if (day>=1 && day <=31) + calendar->marked_date[day-1] = TRUE; + + if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar))) + { + gtk_calendar_paint_main (GTK_WIDGET (calendar)); + } + return TRUE; +} + +gint +gtk_calendar_unmark_day (GtkCalendar *calendar, gint day) +{ + g_return_val_if_fail (calendar != NULL, FALSE); + + if (day>=1 && day <=31) + calendar->marked_date[day-1] = FALSE; + + if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (calendar))) + { + gtk_calendar_paint_main (GTK_WIDGET (calendar)); + } + return TRUE; +} + +void +gtk_calendar_get_date (GtkCalendar *calendar, gint *year, gint *month, gint *day) +{ + g_return_if_fail (calendar != NULL); + g_return_if_fail (GTK_IS_CALENDAR (calendar)); + + if (year) + *year = calendar->year; + + if (month) + *month = calendar->month; + + if (day) + *day = calendar->selected_day; +} + +static gint +gtk_calendar_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkCalendar *calendar; + gint x, y; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + calendar = GTK_CALENDAR (widget); + + x = (gint) (event->x); + y = (gint) (event->y); + + if (event->window == calendar->arrow_win[ARROW_MONTH_LEFT]) + gtk_calendar_set_month_prev (calendar); + + if (event->window == calendar->arrow_win[ARROW_MONTH_RIGHT]) + gtk_calendar_set_month_next (calendar); + + if (event->window == calendar->arrow_win[ARROW_YEAR_LEFT]) + gtk_calendar_set_year_prev (calendar); + + if (event->window == calendar->arrow_win[ARROW_YEAR_RIGHT]) + gtk_calendar_set_year_next (calendar); + + if (event->window == calendar->main_win) + gtk_calendar_main_button (widget, event); + + return FALSE; +} + +static gint +gtk_calendar_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkCalendar *calendar; + gint event_x, event_y; + gint row, col; + gint old_row, old_col; + + calendar = (GtkCalendar*) widget; + event_x = (gint) (event->x); + event_y = (gint) (event->y); + + if (event->window == calendar->main_win) + { + + row = row_from_y (calendar, event_y); + col = column_from_x (calendar, event_x); + + if (row != calendar->highlight_row || calendar->highlight_col != col) + { + old_row = calendar->highlight_row; + old_col = calendar->highlight_col; + if (old_row > -1 && old_col > -1) + { + calendar->highlight_row = -1; + calendar->highlight_col = -1; + gtk_calendar_paint_day (widget, old_row, old_col); + } + + calendar->highlight_row = row; + calendar->highlight_col = col; + + if (row > -1 && col > -1) + gtk_calendar_paint_day (widget, row, col); + } + } + return TRUE; +} + +static gint +gtk_calendar_enter_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GtkCalendar *calendar; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + calendar = GTK_CALENDAR (widget); + + if (event->window == calendar->arrow_win[ARROW_MONTH_LEFT]) + { + calendar->arrow_state[ARROW_MONTH_LEFT] = GTK_STATE_PRELIGHT; + gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT); + } + + if (event->window == calendar->arrow_win[ARROW_MONTH_RIGHT]) + { + calendar->arrow_state[ARROW_MONTH_RIGHT] = GTK_STATE_PRELIGHT; + gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT); + } + + if (event->window == calendar->arrow_win[ARROW_YEAR_LEFT]) + { + calendar->arrow_state[ARROW_YEAR_LEFT] = GTK_STATE_PRELIGHT; + gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT); + } + + if (event->window == calendar->arrow_win[ARROW_YEAR_RIGHT]) + { + calendar->arrow_state[ARROW_YEAR_RIGHT] = GTK_STATE_PRELIGHT; + gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT); + } + + return TRUE; +} + +static gint +gtk_calendar_leave_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GtkCalendar *calendar; + gint row; + gint col; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + calendar = GTK_CALENDAR (widget); + + if (event->window == calendar->main_win) + { + row = calendar->highlight_row; + col = calendar->highlight_col; + calendar->highlight_row = -1; + calendar->highlight_col = -1; + if (row > -1 && col > -1) + gtk_calendar_paint_day (widget, row, col); + } + + if (event->window == calendar->arrow_win[ARROW_MONTH_LEFT]) + { + calendar->arrow_state[ARROW_MONTH_LEFT] = GTK_STATE_NORMAL; + gtk_calendar_paint_arrow (widget, ARROW_MONTH_LEFT); + } + + if (event->window == calendar->arrow_win[ARROW_MONTH_RIGHT]) + { + calendar->arrow_state[ARROW_MONTH_RIGHT] = GTK_STATE_NORMAL; + gtk_calendar_paint_arrow (widget, ARROW_MONTH_RIGHT); + } + + if (event->window == calendar->arrow_win[ARROW_YEAR_LEFT]) + { + calendar->arrow_state[ARROW_YEAR_LEFT] = GTK_STATE_NORMAL; + gtk_calendar_paint_arrow (widget, ARROW_YEAR_LEFT); + } + + if (event->window == calendar->arrow_win[ARROW_YEAR_RIGHT]) + { + calendar->arrow_state[ARROW_YEAR_RIGHT] = GTK_STATE_NORMAL; + gtk_calendar_paint_arrow (widget, ARROW_YEAR_RIGHT); + } + + return TRUE; +} + +static void +gtk_calendar_paint_arrow (GtkWidget *widget, guint arrow) +{ + GdkWindow *window; + GdkGC *gc; + GtkCalendar *calendar; + gint state; + gint width, height; + + g_return_if_fail (widget != NULL); + + calendar = GTK_CALENDAR (widget); + if (calendar->frozen) + { + calendar->dirty_header = 1; + return; + } + window = calendar->arrow_win[arrow]; + if (window) + { + state = calendar->arrow_state[arrow]; + gc = calendar->gc; + + gdk_window_clear (window); + gdk_window_set_background (window, &(widget)->style->bg[state]); + gdk_window_get_size (window, &width, &height); + gdk_window_clear_area (window, + 0,0, + width,height); + + gdk_gc_set_foreground (gc, & (widget)->style->fg[state]); + + if (arrow == ARROW_MONTH_LEFT || arrow == ARROW_YEAR_LEFT) + draw_arrow_left (window, gc, width/2 - 3, height/2 - 4, 8); + else + draw_arrow_right (window, gc, width/2 - 2, height/2 - 4, 8); + return; + } +} + +void +gtk_calendar_freeze (GtkCalendar *calendar) +{ + g_return_if_fail (GTK_IS_CALENDAR (calendar)); + calendar->frozen++; +} + +void +gtk_calendar_thaw (GtkCalendar *calendar) +{ + g_return_if_fail (GTK_IS_CALENDAR (calendar)); + if (calendar->frozen) + { + calendar->frozen--; + if (calendar->frozen) + return; + + if (calendar->dirty_header) + if (GTK_WIDGET_DRAWABLE (calendar)) + gtk_calendar_paint_header (GTK_WIDGET (calendar)); + + if (calendar->dirty_day_names) + if (GTK_WIDGET_DRAWABLE (calendar)) + gtk_calendar_paint_day_names (GTK_WIDGET (calendar)); + + if (calendar->dirty_week) + if (GTK_WIDGET_DRAWABLE (calendar)) + gtk_calendar_paint_week_numbers (GTK_WIDGET (calendar)); + + if (calendar->dirty_main) + if (GTK_WIDGET_DRAWABLE (calendar)) + gtk_calendar_paint_main (GTK_WIDGET (calendar)); + } +} + +static void +gtk_calendar_set_background(GtkWidget *widget) +{ + GtkCalendar *calendar; + gint i; + + g_return_if_fail (GTK_IS_CALENDAR (widget)); + if (GTK_WIDGET_REALIZED (widget)) + { + calendar = GTK_CALENDAR (widget); + for (i=0; i<4; i++) + if (calendar->arrow_win[i]) + gdk_window_set_background (calendar->arrow_win[i], HEADER_BG_COLOR (widget)); + if (calendar->header_win) + gdk_window_set_background (calendar->header_win, HEADER_BG_COLOR (widget)); + if (calendar->day_name_win) + gdk_window_set_background (calendar->day_name_win, BACKGROUND_COLOR (widget)); + if (calendar->week_win) + gdk_window_set_background (calendar->week_win, BACKGROUND_COLOR (widget)); + if (calendar->main_win) + gdk_window_set_background (calendar->main_win, BACKGROUND_COLOR (widget)); + if (widget->window) + gdk_window_set_background (widget->window, BACKGROUND_COLOR (widget)); + } + if (GTK_WIDGET_DRAWABLE (widget)) + gdk_window_clear (widget->window); +} + +static void +gtk_calendar_style_set (GtkWidget *widget, + GtkStyle *previous_style) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + + if (previous_style && GTK_WIDGET_REALIZED (widget)) + gtk_calendar_set_background(widget); +} + +static void +gtk_calendar_state_changed (GtkWidget *widget, + GtkStateType previous_state) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CALENDAR (widget)); + + gtk_calendar_set_background(widget); +} + +static gint gtk_calendar_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ + GtkCalendar *calendar; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + calendar = GTK_CALENDAR (widget); + + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + gtk_calendar_paint_day_num (widget, calendar->selected_day); +#undef USE_XIM +#ifdef USE_XIM + if (GTK_EDITABLE(widget)->ic) + gdk_im_begin (GTK_EDITABLE(widget)->ic, GTK_ENTRY(widget)->text_area); +#endif + + return FALSE; + +} + +static gint gtk_calendar_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + GtkCalendar *calendar; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + calendar = GTK_CALENDAR (widget); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + gtk_calendar_paint_day_num (widget, calendar->selected_day); +#ifdef USE_XIM + gdk_im_end (); +#endif + + return FALSE; +} + +static gint +gtk_calendar_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + GtkCalendar *calendar; + gint return_val; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CALENDAR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + calendar = GTK_CALENDAR (widget); + return_val = FALSE; + + + switch (event->keyval) + { + case GDK_Left: + return_val = TRUE; + if (event->state & GDK_CONTROL_MASK) + gtk_calendar_set_month_prev (calendar); + else + { + if (calendar->selected_day == 1) + { + if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE) + { + gtk_calendar_select_day (calendar, month_length[leap (calendar->year)][calendar->month + 1]); + } + else + { + calendar->selected_day = -1; + gtk_calendar_set_month_prev (calendar); + } + } + else + gtk_calendar_select_day (calendar, calendar->selected_day - 1); + } + break; + case GDK_Right: + return_val = TRUE; + if (event->state & GDK_CONTROL_MASK) + gtk_calendar_set_month_next (calendar); + else + { + if (calendar->selected_day == month_length[leap (calendar->year)][calendar->month + 1]) + { + if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE) + { + gtk_calendar_select_day (calendar, 1); + } + else + { + calendar->selected_day = 1; + gtk_calendar_set_month_next (calendar); + } + } + else + gtk_calendar_select_day (calendar, calendar->selected_day + 1); + } + break; + case GDK_Up: + return_val = TRUE; + if (event->state & GDK_CONTROL_MASK) + gtk_calendar_set_year_prev (calendar); + else + { + gint overlap; + overlap = calendar->selected_day - 7; + if (overlap < 1) + { + if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE) + { + gint month_len; + month_len = month_length[leap (calendar->year)][calendar->month + 1]; + gtk_calendar_select_day (calendar, month_len - (month_len - (month_len / 7) * 7 - overlap)%7); + } + else + { + calendar->selected_day = overlap - 1; + gtk_calendar_set_month_prev (calendar); + } + } + else + gtk_calendar_select_day (calendar, calendar->selected_day - 7); + } + break; + case GDK_Down: + return_val = TRUE; + if (event->state & GDK_CONTROL_MASK) + gtk_calendar_set_year_next (calendar); + else + { + gint month_len; + gint overlap; + month_len = month_length[leap (calendar->year)][calendar->month + 1]; + overlap = (calendar->selected_day + 7 - month_len); + if (overlap > 0) + { + if (calendar->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE) + { + gtk_calendar_select_day (calendar, (month_len - 1 - (month_len / 7) * 7 + + overlap) % 7 + 1); + } + else + { + calendar->selected_day = overlap; + gtk_calendar_set_month_next (calendar); + } + } + else + gtk_calendar_select_day (calendar, calendar->selected_day + 7); + } + break; + } + return return_val; +} diff --git a/gtk/gtkcalendar.h b/gtk/gtkcalendar.h new file mode 100644 index 0000000000..b09a95d791 --- /dev/null +++ b/gtk/gtkcalendar.h @@ -0,0 +1,153 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * GTK Calendar Widget + * Copyright (C) 1998 Cesar Miquel and Shawn T. Amundson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __GTK_CALENDAR_H__ +#define __GTK_CALENDAR_H__ + +#include <gdk/gdk.h> +#include <gtk/gtksignal.h> +#include <gtk/gtkwidget.h> +#include <gtk/gtkfeatures.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define GTK_CALENDAR(obj) GTK_CHECK_CAST (obj, gtk_calendar_get_type (), GtkCalendar) +#define GTK_CALENDAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_calendar_get_type (), GtkCalendarClass) +#define GTK_IS_CALENDAR(obj) GTK_CHECK_TYPE (obj, gtk_calendar_get_type ()) + +typedef struct _GtkCalendar GtkCalendar; +typedef struct _GtkCalendarClass GtkCalendarClass; + +typedef enum +{ + GTK_CALENDAR_SHOW_HEADING = 1 << 0, + GTK_CALENDAR_SHOW_DAY_NAMES = 1 << 1, + GTK_CALENDAR_NO_MONTH_CHANGE = 1 << 2, + GTK_CALENDAR_SHOW_WEEK_NUMBERS = 1 << 3, + GTK_CALENDAR_WEEK_START_MONDAY = 1 << 4 +} GtkCalendarDisplayOptions; + +struct _GtkCalendar +{ + /* This widget is derived from GtkWidget */ + GtkWidget widget; + + GdkWindow *header_win, *day_name_win, *main_win, *week_win; + gint header_h, day_name_h, main_h; + + GtkStyle *header_style; + GtkStyle *label_style; + + gint month; + gint year; + gint selected_day; + + gint day_month[6][7]; + gint day[6][7]; + + gint num_marked_dates; + gint marked_date[31]; + GtkCalendarDisplayOptions display_flags; + GdkColor marked_date_color[31]; + + /* Header Information */ + GdkWindow *arrow_win[4]; + gint arrow_state[4]; + gint arrow_width; + gint max_month_width; + gint max_year_width; + + /* Other info */ + gint calstarty, calnumrows; + + /* Style parameters for this widget */ + GdkGC *gc; + GdkCursor *cross; + + gint day_width; + gint week_width; + GdkRectangle header_button[4]; + GdkRectangle rect_days[6][7]; + + gint highlight_row; + gint highlight_col; + + gint min_day_width; + gint max_day_char_width; + gint max_day_char_ascent; + gint max_day_char_descent; + gint max_label_char_ascent; + gint max_label_char_descent; + gint max_week_char_width; + /* flags */ + unsigned int dirty_header:1; + unsigned int dirty_day_names:1; + unsigned int dirty_main:1; + unsigned int dirty_week:1; + unsigned int frozen; + + gint week_num_w; + gint font_width_day_name, font_width_day; + char grow_space [32]; +}; + +struct _GtkCalendarClass +{ + GtkWidgetClass parent_class; + + /* Signal handlers */ + void (* gtk_calendar_month_changed) (GtkCalendarClass *); + void (* gtk_calendar_day_selected) (GtkCalendarClass *); + void (* gtk_calendar_day_selected_double_click) (GtkCalendarClass *); + void (* gtk_calendar_prev_month) (GtkCalendarClass *); + void (* gtk_calendar_next_month) (GtkCalendarClass *); + void (* gtk_calendar_prev_year) (GtkCalendarClass *); + void (* gtk_calendar_next_year) (GtkCalendarClass *); + +}; + + +guint gtk_calendar_get_type (void); +GtkWidget* gtk_calendar_new (void); + +gint gtk_calendar_select_month (GtkCalendar *calendar, + gint month, gint year); +void gtk_calendar_select_day (GtkCalendar *calendar, gint day); + +gint gtk_calendar_mark_day (GtkCalendar *calendar, gint day); +gint gtk_calendar_unmark_day (GtkCalendar *calendar, gint day); +void gtk_calendar_clear_marks (GtkCalendar *calendar); + + +void gtk_calendar_display_options (GtkCalendar *calendar, + GtkCalendarDisplayOptions flags); + +void gtk_calendar_get_date (GtkCalendar *calendar, + gint *year, gint *month, gint *day); +void gtk_calendar_freeze (GtkCalendar *calendar); +void gtk_calendar_thaw (GtkCalendar *calendar); +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GTK_CALENDAR_H__ */ |