jason@gcx1.ssd.csd.harris.com (Jason Baietto) (12/13/90)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 5 (of 5)." # Contents: Calendar.c # Wrapped by jason@hcx2 on Thu Dec 6 12:49:23 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Calendar.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Calendar.c'\" else echo shar: Extracting \"'Calendar.c'\" \(58171 characters\) sed "s/^X//" >'Calendar.c' <<'END_OF_FILE' X/* X * Author: Jason Baietto, jason@ssd.csd.harris.com X * xdiary Copyright 1990 Harris Corporation X * X * Permission to use, copy, modify, and distribute, this software and its X * documentation for any purpose is hereby granted without fee, provided that X * the above copyright notice appear in all copies and that both that X * copyright notice and this permission notice appear in supporting X * documentation, and that the name of the copyright holder be used in X * advertising or publicity pertaining to distribution of the software with X * specific, written prior permission, and that no fee is charged for further X * distribution of this software, or any modifications thereof. The copyright X * holder makes no representations about the suitability of this software for X * any purpose. It is provided "as is" without express or implied warranty. X * X * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, X * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND IN NO X * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR X * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ITS USE, X * LOSS OF DATA, PROFITS, QPA OR GPA, WHETHER IN AN ACTION OF CONTRACT, X * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH X * THE USE OR PERFORMANCE OF THIS SOFTWARE. X */ X X/*==========================================================================*/ X/* Header Files: */ X/*==========================================================================*/ X#include <stdio.h> X#include <X11/Xos.h> X#include <X11/StringDefs.h> X#include <X11/IntrinsicP.h> X#include <X11/Xmu/Converters.h> X#include "CalendarP.h" X X#ifdef DEBUG X#define BEGIN(str) (/*VARARGS0*/fprintf(stderr, "%s()\n", (str))) X#define END(str) ; X#else X#define BEGIN(str) ; X#define END(str) ; X#endif X X X/*==========================================================================*/ X/* Forward References: */ X/*==========================================================================*/ Xstatic void initialize_line_GCs(); Xstatic void initialize_font_GCs_and_info(); Xstatic void compute_minimum_cell_size(); Xstatic void compute_cell_geometry(); Xstatic void free_line_GCs(); Xstatic void free_font_GCs_and_info(); Xstatic void compute_grid(); Xstatic void draw_grid(); Xstatic void draw_weekdays(); Xstatic void draw_title(); Xstatic void draw_digits(); Xstatic void compute_title_string(); Xstatic void toggle_highlight(); Xstatic void rotate_weekdays(); Xstatic void calendar_update(); Xstatic void compute_month_data(); X X X X X/*==========================================================================*/ X/* Static Global Data: */ X/*==========================================================================*/ Xstatic int days_in_month[] = X /* jan feb mar apr may jun jul aug sep oct nov dec */ X { 31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; X X X X X/*==========================================================================*/ X/* Resource List: */ X/*==========================================================================*/ X#define offset(field) XtOffset(CalendarWidget, field) Xstatic XtResource calendar_resources[] = { X { X XtNcallback, X XtCCallback, X XtRCallback, X sizeof(XtPointer), X offset(calendar.callback), X XtRCallback, X NULL X }, X { X XtNlineWidth, X XtCLineWidth, X XtRInt, X sizeof(int), X offset(calendar.line_width), X XtRImmediate, X (XtPointer)DEFAULT_LINE_WIDTH X }, X { X XtNforeground, X XtCForeground, X XtRPixel, X sizeof(Pixel), X offset(calendar.foreground), X XtRString, X XtDefaultForeground X }, X { X XtNbackground, X XtCBackground, X XtRPixel, X sizeof(Pixel), X offset(calendar.background), X XtRString, X XtDefaultBackground X }, X { X XtNdigitFont, X XtCCalendarFont, X XtRFont, X sizeof(Font), X offset(calendar.digit_font), X XtRString, X CALENDAR_DEFAULT_FONT X }, X { X XtNweekdayFont, X XtCCalendarFont, X XtRFont, X sizeof(Font), X offset(calendar.weekday_font), X XtRString, X CALENDAR_DEFAULT_FONT X }, X { X XtNtitleFont, X XtCCalendarFont, X XtRFont, X sizeof(Font), X offset(calendar.title_font), X XtRString, X CALENDAR_DEFAULT_FONT X }, X { X XtNinfoFont, X XtCCalendarFont, X XtRFont, X sizeof(Font), X offset(calendar.info_font), X XtRString, X CALENDAR_DEFAULT_FONT X }, X { X XtNdigitGravity, X XtCDigitGravity, X XtRGravity, X sizeof(XtGravity), X offset(calendar.digit_gravity), X XtRImmediate, X (XtPointer)Center X }, X { XtNdigitNames, X XtCDigitNames, X XtRStringTable, X sizeof(StringTable), X offset(calendar.digit_names), X XtRString, X XtNDefaultDigitNames X }, X { XtNweekdayNames, X XtCWeekdayNames, X XtRStringTable, X sizeof(StringTable), X offset(calendar.weekday_names), X XtRString, X XtNDefaultWeekdayNames X }, X { XtNmonthNames, X XtCMonthNames, X XtRStringTable, X sizeof(StringTable), X offset(calendar.month_names), X XtRString, X XtNDefaultMonthNames X }, X { XtNhighlight, X XtCHighlight, X XtRBoolean, X sizeof(Boolean), X offset(calendar.highlight), X XtRImmediate, X (XtPointer)True X }, X { XtNshowYear, X XtCShowYear, X XtRBoolean, X sizeof(Boolean), X offset(calendar.show_year), X XtRImmediate, X (XtPointer)True X }, X { XtNstartingWeekday, X XtCStartingWeekday, X XtRDayName, X sizeof(XtDayName), X offset(calendar.starting_weekday), X XtRImmediate, X (XtPointer)Sunday X } X}; X X X X/*==========================================================================*/ X/* Action Declarations: */ X/*==========================================================================*/ Xstatic void select_cell_action(); Xstatic void default_button_up_action(); X X X X/*==========================================================================*/ X/* Actions Table: */ X/*==========================================================================*/ Xstatic XtActionsRec calendar_actions[] = { X { "select", select_cell_action }, X { "notify", default_button_up_action } X}; X Xstatic char calendar_default_translations[] = XtRcalendarDefaultTranslations; X X X/*==========================================================================*/ X/* Method Declarations: */ X/*==========================================================================*/ Xstatic void calendar_initialize_method(); Xstatic void calendar_class_initialize_method(); Xstatic void calendar_expose_method(); Xstatic void calendar_destroy_method(); Xstatic void calendar_resize_method(); Xstatic Boolean calendar_set_values_method(); Xstatic XtGeometryResult calendar_query_geometry_method(); X X X X/*==========================================================================*/ X/* Class Record Initialization: */ X/*==========================================================================*/ XCalendarClassRec calendarClassRec = { X { X /* CORE CLASS PART: */ X /* superclass */ (WidgetClass) &coreClassRec, X /* class_name */ "Calendar", X /* widget_size */ sizeof(CalendarRec), X /* class_initialize */ calendar_class_initialize_method, X /* class_part_initialize */ NULL, X /* class_inited */ FALSE, X /* initialize */ calendar_initialize_method, X /* initialize_hook */ NULL, X /* realize */ XtInheritRealize, X /* actions */ calendar_actions, X /* num_actions */ XtNumber(calendar_actions), X /* resources */ calendar_resources, X /* num_resources */ XtNumber(calendar_resources), X /* xrm_class */ NULLQUARK, X /* compress_motion */ TRUE, X /* compress_exposure */ TRUE, X /* compress_enterleave */ TRUE, X /* visible_interest */ FALSE, X /* destroy */ calendar_destroy_method, X /* resize */ calendar_resize_method, X /* expose */ calendar_expose_method, X /* set_values */ calendar_set_values_method, X /* set_values_hook */ NULL, X /* set_values_almost */ XtInheritSetValuesAlmost, X /* get_values_hook */ NULL, X /* accept_focus */ NULL, X /* version */ XtVersion, X /* callback_private */ NULL, X /* tm_table */ calendar_default_translations, X /* query_geometry */ calendar_query_geometry_method, X /* display_accelerator */ XtInheritDisplayAccelerator, X /* extension */ NULL X }, X { X /* CALENDAR CLASS PART: */ X /* dummy field */ 0 X } X}; X X/* Define the calendar widget class in terms of the above record. */ XWidgetClass calendarWidgetClass = (WidgetClass) &calendarClassRec; X X Xstatic XtConvertArgRec screenConvertArg[] = { X { X XtBaseOffset, X (XtPointer)XtOffset(Widget, core.screen), X sizeof(Screen *) X } X}; X X X X/*==========================================================================*/ X/* Method Definitions: */ X/*==========================================================================*/ Xstatic void calendar_class_initialize_method() X{ X /* Register the string to gravity resource converter. */ X XtAddConverter( X XtRString, /* source type */ X XtRGravity, /* target type */ X GravityConverter, /* converter routine */ X NULL, /* args for converter */ X 0 /* num args for converter */ X ); X X /* Register the string to gravity resource converter. */ X XtAddConverter( X XtRString, /* source type */ X XtRDayName, /* target type */ X DayNameConverter, /* converter routine */ X NULL, /* args for converter */ X 0 /* num args for converter */ X ); X X /* Register the string to string table resource converter. */ X XtAddConverter( X XtRString, /* source type */ X XtRStringTable, /* target type */ X StringTableConverter, /* converter routine */ X NULL, /* args for converter */ X 0 /* num args for converter */ X ); X X /* Register the string to bitmap resource converter. */ X XtAddConverter( X XtRString, /* source type */ X XtRBitmap, /* target type */ X XmuCvtStringToBitmap, /* converter routine */ X screenConvertArg, /* args for converter */ X XtNumber(screenConvertArg) /* num args for converter */ X ); X} X X Xstatic void calendar_initialize_method(request, new) XCalendarWidget request; XCalendarWidget new; X{ X XrmValue from; X XrmValue to; X int i; X float initial_cell_width = (float) request->core.width / (float) COLS; X float initial_cell_height = (float) request->core.height / (float) ROWS; X X BEGIN("calendar_initialize_method"); X X /* Now entering the foggy zone. */ X new->calendar.state = foggy; X X /* First check resources: */ X X /* Did we get 7 weekday names? */ X if (StringTableNumber(request->calendar.weekday_names) != 7) { X /*VARARGS*/ X fprintf(stderr, "CalendarWidget: You must specify 7 weekday names.\n"); X X /* Explicitly invoke converter on default value */ X from.addr = XtNDefaultWeekdayNames; X from.size = sizeof(StringTable); X XtConvert(new, XtRString, &from, XtRStringTable, &to); X request->calendar.weekday_names = *(StringTable *)to.addr; X } X X /* Make a widget specific copy so we can twiddle with it if necessary. */ X new->calendar.weekday_names X = StringTableCopy(request->calendar.weekday_names); X X /* Do we need to rotate the weekdays? */ X if (new->calendar.starting_weekday != SUNDAY) { X rotate_weekdays(new); X } X X /* Did we get 12 month names? */ X if (StringTableNumber(request->calendar.month_names) != 12) { X /*VARARGS*/ X fprintf(stderr, "CalendarWidget: You must specify 12 month names.\n"); X X /* Explicitly invoke converter on default value */ X from.addr = XtNDefaultMonthNames; X from.size = sizeof(StringTable); X XtConvert(new, XtRString, &from, XtRStringTable, &to); X new->calendar.month_names = *(StringTable *)to.addr; X X } X X /* Did we get 31 digit names? */ X if (StringTableNumber(request->calendar.digit_names) != 31) { X /*VARARGS*/ X fprintf(stderr, "CalendarWidget: You must specify 31 digit names.\n"); X X /* Explicitly invoke converter on default value */ X from.addr = XtNDefaultDigitNames; X from.size = sizeof(StringTable); X XtConvert(new, XtRString, &from, XtRStringTable, &to); X new->calendar.digit_names = *(StringTable *)to.addr; X } X X range_check( X XtNlineWidth, X new->calendar.line_width, X MIN_LINE_WIDTH, X MAX_LINE_WIDTH X ); X X range_check( X XtNdigitGravity, X new->calendar.digit_gravity, X NorthWest, X SouthEast X ); X X /* Next compute initial state: */ X X /* Compute the lengths of the month, weekday and digit names once and keep */ X /* around so we won't have to recompute them every time they're drawn. */ X for (i=0; i < DAYS_IN_WEEK; i++) { X new->calendar.weekday_name_lengths[i] = strlen(new->calendar.weekday_names[i]); X } X for (i=0; i < MONTHS_IN_YEAR; i++) { X new->calendar.month_name_lengths[i] = strlen(new->calendar.month_names[i]); X } X for (i=0; i < MAX_DAYS_IN_MONTH; i++) { X new->calendar.digit_name_lengths[i] = strlen(new->calendar.digit_names[i]); X } X X initialize_line_GCs(new); X initialize_font_GCs_and_info(new); X compute_minimum_cell_size(new); X X new->calendar.real_cell_width X = MAX(new->calendar.min_cell_width + 1, initial_cell_width); X new->calendar.real_cell_height X = MAX(new->calendar.min_cell_height + 1, initial_cell_height); X X new->calendar.old_window_width = -1; X new->calendar.old_window_height = -1; X X if (new->core.width == 0) { X new->core.width = WINDOW_WIDTH(new->calendar.real_cell_width); X } X if (new->core.height == 0) { X new->core.height = WINDOW_HEIGHT(new->calendar.real_cell_height); X } X X compute_grid (new); X compute_cell_geometry (new); X X /* Calendar defaults to current date. */ X new->calendar.date = GetTodaysDate(); X X /* Allocate a fixed amount of space for the title string. */ X new->calendar.title_string = (char *)XtMalloc(MAX_TITLE_LEN*sizeof(char)); X X /* Force a re-calculation of the month data for the current year. */ X new->calendar.current_year = 0; X compute_month_data(new); X X new->calendar.highlight_days_in_february X = new->calendar.days_in_february; X X /* Calendar highlights current day by default, if highligh is true. */ X new->calendar.highlight_date = new->calendar.date; X X compute_title_string(new); X X END("calendar_initialize_method"); X} X X X X/*ARGSUSED*/ Xstatic void calendar_expose_method(widget, event) XCalendarWidget widget; XXExposeEvent *event; X{ X BEGIN("calendar_expose_method"); X X /* Okay, it's safe to draw now. */ X widget->calendar.state = solid; X X draw_weekdays (widget); X draw_title (widget); X draw_digits (widget); X X if (SYNC(widget)) { X toggle_highlight (widget, ON); X } X X draw_grid (widget); X X END("calendar_expose_method"); X} X X X Xstatic Boolean calendar_set_values_method(current, request, new) XCalendarWidget current; XCalendarWidget request; XCalendarWidget new; X{ X Boolean redraw = False; X Boolean resize = False; X Boolean new_weekday_names = False; X Boolean new_starting_weekday = False; X Display * display; X XGCValues values; X XtGCMask mask; X int i; X int new_width; X int new_height; X X BEGIN("calendar_set_values_method"); X X display = XtDisplay(current); X X /* Line Width: */ X if (request->calendar.line_width != current->calendar.line_width) { X new->calendar.line_width = bound( X request->calendar.line_width, X MIN_LINE_WIDTH, X MAX_LINE_WIDTH X ); X } X if (new->calendar.line_width != current->calendar.line_width) { X mask = GCLineWidth; X values.line_width = new->calendar.line_width; X XChangeGC( X display, X new->calendar.draw_gc, X mask, X &values X ); X redraw = True; X } X X /* Digit Gravity: */ X if (request->calendar.digit_gravity != current->calendar.digit_gravity) { X new->calendar.digit_gravity = (XtGravity) bound( X (int) request->calendar.digit_gravity, X (int) NorthWest, X (int) SouthEast X ); X } X if (new->calendar.digit_gravity != current->calendar.digit_gravity) { X redraw = True; X } X X /* Weekday Names: */ X if (request->calendar.weekday_names != current->calendar.weekday_names) { X if (StringTableNumber(request->calendar.weekday_names) != DAYS_IN_WEEK) { X /*VARARGS*/ X fprintf(stderr, "CalendarWidget: must specify 7 weekday names\n"); X } else { X /* Copy the string table so we can rotate it if necessary. */ X new->calendar.weekday_names = X StringTableCopy(request->calendar.weekday_names); X for (i=0; i < DAYS_IN_WEEK; i++) { X new->calendar.weekday_name_lengths[i] X = strlen(request->calendar.weekday_names[i]); X } X new_weekday_names = True; X redraw = True; X resize = True; X } X } X X /* Month Names: */ X if (request->calendar.month_names != current->calendar.month_names) { X if (StringTableNumber(request->calendar.month_names) != MONTHS_IN_YEAR) { X /*VARARGS*/ X fprintf(stderr, "CalendarWidget: must specify 12 month names\n"); X } else { X new->calendar.month_names = request->calendar.month_names; X for (i=0; i < MONTHS_IN_YEAR; i++) { X new->calendar.month_name_lengths[i] X = strlen(request->calendar.month_names[i]); X } X compute_title_string(new); X redraw = True; X resize = True; X } X } X X /* Digit Names: */ X if (request->calendar.digit_names != current->calendar.digit_names) { X if (StringTableNumber(request->calendar.digit_names) != MAX_DAYS_IN_MONTH) { X /*VARARGS*/ X fprintf(stderr, "CalendarWidget: must specify 31 digit names\n"); X } else { X new->calendar.digit_names = request->calendar.digit_names; X for (i=0; i < MAX_DAYS_IN_MONTH; i++) { X new->calendar.digit_name_lengths[i] X = strlen(request->calendar.digit_names[i]); X } X redraw = True; X resize = True; X } X } X X /* Starting Weekday. */ X new_starting_weekday = (request->calendar.starting_weekday X != current->calendar.starting_weekday); X if (new_starting_weekday X && (request->calendar.starting_weekday < SUNDAY X || request->calendar.starting_weekday > SATURDAY)) { X /* Bogus value specified. */ X /*VARARGS*/ X fprintf(stderr, "CalendarWidget: invalid starting weekday, use [0..6]\n"); X new_starting_weekday = FALSE; X } X if (new_starting_weekday && new_weekday_names) { X new->calendar.starting_weekday = request->calendar.starting_weekday; X rotate_weekdays(new); X } else if (new_weekday_names) { X rotate_weekdays(new); X } else if (new_starting_weekday) { X /* Rotate weekdays, taking into account current rotation. */ X new->calendar.starting_weekday = X ( (7 - current->calendar.starting_weekday) X + request->calendar.starting_weekday ) %7; X rotate_weekdays(new); X new->calendar.starting_weekday = request->calendar.starting_weekday; X redraw = True; X } X X /* Highlight. */ X if (request->calendar.highlight != current->calendar.highlight) { X new->calendar.highlight = request->calendar.highlight; X } X X if (resize) { X compute_minimum_cell_size(new); X new_width = WINDOW_WIDTH(new->calendar.min_cell_width); X new_height = WINDOW_HEIGHT(new->calendar.min_cell_height); X XtMakeResizeRequest(new, new_width, new_height, NULL, NULL); X } X X END("calendar_set_values_method"); X X /* Return true if value change requires expose event to redraw. */ X return (redraw); X} X X X X Xstatic void calendar_resize_method(widget) XCalendarWidget widget; X{ X int window_width = widget->core.width; X int window_height = widget->core.height; X float avail_cell_width = (float) window_width / (float) COLS; X float avail_cell_height = (float) window_height / (float) ROWS; X X BEGIN("calendar_resize_method"); X X /* Now entering the foggy zone. */ X widget->calendar.state = foggy; X X widget->calendar.real_cell_width = low_bound( X avail_cell_width, X widget->calendar.min_cell_width X ); X X widget->calendar.real_cell_height = low_bound( X avail_cell_height, X widget->calendar.min_cell_height X ); X X compute_grid (widget); X compute_cell_geometry (widget); X X /* Don't need to redraw the calendar, an expose event follows. */ X END("calendar_resize_method"); X} X X X X Xstatic XtGeometryResult calendar_query_geometry_method(widget, proposed, preferred) XCalendarWidget widget; XXtWidgetGeometry *proposed; XXtWidgetGeometry *preferred; X{ X /* X * There are three scenarios: X * X * 1. The geometry proposed by our parent is the same as our preferred X * geometry. Return XtGeometryYes to say, "Yes, I'm happy with your X * proposed geometry so please resize me to it." X * X * 2. My preferred geometry is the same as our current geometry. Return X * XtGeometryNo to say, "I'm at my preferred geometry so please don't X * resize me." X * X * 3. The geometry proposed by our parent is not our preferred geometry, X * nor am I at my preferred geometry. Return XtGeometryAlmost to say X * "I'm sending you my preferred geometry. Can't you try again to get X * me the size I want?" X * X * Note that my parent is free to totally ignore this information, just like X * most parents ignore what their kids tell them. X */ X X BEGIN("calendar_query_geometry_method"); X X preferred->request_mode = CWWidth | CWHeight; X preferred->width = WINDOW_WIDTH(widget->calendar.min_cell_width) + 7; X preferred->height = WINDOW_HEIGHT(widget->calendar.min_cell_height) + 8; X X if ( ((proposed->request_mode & (CWWidth | CWHeight)) == (CWWidth | CWHeight)) X && ((proposed->width == preferred->width) X && (proposed->height == preferred->height)) ) { X /* Yes, I like your proposal. */ X return XtGeometryYes; X } else { X if ( (preferred->width == widget->core.width) && X (preferred->height == widget->core.height) ) { X /* Don't resize me! I'm already at my preferred geometry. */ X return XtGeometryNo; X } else { X /* Please try again. */ X return XtGeometryAlmost; X } X } X X END("calendar_query_geometry_method"); X} X X X Xstatic void calendar_destroy_method(w) XWidget w; X{ X free_line_GCs(w); X free_font_GCs_and_info(w); X} X X X X/*==========================================================================*/ X/* Action Definitions: */ X/*==========================================================================*/ Xstatic void select_cell_action(widget, event) XCalendarWidget widget; XXButtonEvent *event; X{ X int window_width = widget->core.width; X int window_height = widget->core.height; X float cell_width = widget->calendar.real_cell_width; X float cell_height = widget->calendar.real_cell_height; X int current_x_cell = widget->calendar.current_x_cell; X int current_y_cell = widget->calendar.current_y_cell; X int x = event->x; X int y = event->y; X int new_y_cell = y / cell_height; X int new_x_cell = x / cell_width; X int cellnum; X X if (widget->calendar.state == foggy) { X return; X } X X /* Ignore events that occur outside the window. These are motion */ X /* events that started inside the window but were dragged outside. */ X if ( (x<1) || (x>window_width-1) || (y<1) || (y>window_height-1) ) { X return; X } X X /* Ignore repeat events for the same cell. */ X if (new_x_cell == current_x_cell && new_y_cell == current_y_cell) { X return; X } X X /* Ignore events in the month/year box. */ X if (new_y_cell<2) { X return; X } X X /* Ignore events outide the cells that we care about for current month. */ X cellnum = CELLXYtoCELLNUM(new_x_cell, new_y_cell); X if (cellnum < widget->calendar.month_start_cellnum || X cellnum > widget->calendar.month_end_cellnum) { X return; X } X X widget->calendar.cell_selected = True; X X /* Reset the old selected cell. */ X if (SYNC(widget)) { X toggle_highlight(widget, OFF); X } X X /* Highlight the newly selected cell. */ X widget->calendar.highlight_date.year = widget->calendar.date.year; X widget->calendar.highlight_date.month = widget->calendar.date.month; X widget->calendar.highlight_date.day = CELLNUMtoDAYNUM(cellnum); X toggle_highlight(widget, ON); X X return; X} X X X X/*ARGSUSED*/ Xstatic void default_button_up_action(widget, event) XCalendarWidget widget; XXButtonEvent *event; X{ X if (!widget->calendar.cell_selected) { X return; X } X widget->calendar.cell_selected = False; X X /* The button-down or button-motion event inverted the cell, so all */ X /* we have to do is call any callbacks that the application registered. */ X XtCallCallbacks(widget, XtNcallback, &widget->calendar.highlight_date); X} X X X X/*==========================================================================*/ X/* Method Support Routines: */ X/*==========================================================================*/ Xstatic void initialize_line_GCs(widget) XCalendarWidget widget; X{ X XGCValues values; X XtGCMask mask; X X mask = GCForeground | GCBackground | GCLineWidth; X values.foreground = widget->calendar.foreground; X values.background = widget->calendar.background; X values.line_width = widget->calendar.line_width; X widget->calendar.draw_gc = XtGetGC(widget, mask, &values); X X mask = GCForeground | GCBackground; X values.foreground = widget->calendar.background; X values.background = widget->calendar.foreground; X widget->calendar.undraw_gc = XtGetGC(widget, mask, &values); X X mask = GCForeground | GCBackground | GCFunction; X values.foreground = widget->calendar.foreground; X values.background = widget->calendar.background; X values.function = GXinvert; X widget->calendar.invert_gc = XtGetGC(widget, mask, &values); X} X X X X Xstatic void initialize_font_GCs_and_info(widget) XCalendarWidget widget; X{ X XGCValues values; X XtGCMask mask; X X/* Digit font */ X mask = GCForeground | GCBackground | GCFont; X values.foreground = widget->calendar.foreground; X values.background = widget->calendar.background; X values.font = widget->calendar.digit_font; X widget->calendar.digit_draw_gc = XtGetGC(widget, mask, &values); X X mask = GCForeground | GCBackground | GCFont; X values.foreground = widget->calendar.background; X values.background = widget->calendar.foreground; X values.font = widget->calendar.digit_font; X widget->calendar.digit_undraw_gc = XtGetGC(widget, mask, &values); X X widget->calendar.digit_fsp = XQueryFont( X XtDisplay(widget), X XGContextFromGC(widget->calendar.digit_draw_gc) X ); X X/* Weekday font */ X mask = GCForeground | GCBackground | GCFont; X values.foreground = widget->calendar.foreground; X values.background = widget->calendar.background; X values.font = widget->calendar.weekday_font; X widget->calendar.weekday_draw_gc = XtGetGC(widget, mask, &values); X X mask = GCForeground | GCBackground | GCFont; X values.foreground = widget->calendar.background; X values.background = widget->calendar.foreground; X values.font = widget->calendar.weekday_font; X widget->calendar.weekday_undraw_gc = XtGetGC(widget, mask, &values); X X widget->calendar.weekday_fsp = XQueryFont( X XtDisplay(widget), X XGContextFromGC(widget->calendar.weekday_draw_gc) X ); X X/* Title font */ X mask = GCForeground | GCBackground | GCFont; X values.foreground = widget->calendar.foreground; X values.background = widget->calendar.background; X values.font = widget->calendar.title_font; X widget->calendar.title_draw_gc = XtGetGC(widget, mask, &values); X X mask = GCForeground | GCBackground | GCFont; X values.foreground = widget->calendar.background; X values.background = widget->calendar.foreground; X values.font = widget->calendar.title_font; X widget->calendar.title_undraw_gc = XtGetGC(widget, mask, &values); X X widget->calendar.title_fsp = XQueryFont( X XtDisplay(widget), X XGContextFromGC(widget->calendar.title_draw_gc) X ); X X/* Info font */ X mask = GCForeground | GCBackground | GCFont; X values.foreground = widget->calendar.foreground; X values.background = widget->calendar.background; X values.font = widget->calendar.info_font; X widget->calendar.info_draw_gc = XtGetGC(widget, mask, &values); X X mask = GCForeground | GCBackground | GCFont; X values.foreground = widget->calendar.background; X values.background = widget->calendar.foreground; X values.font = widget->calendar.info_font; X widget->calendar.info_undraw_gc = XtGetGC(widget, mask, &values); X X widget->calendar.info_fsp = XQueryFont( X XtDisplay(widget), X XGContextFromGC(widget->calendar.info_draw_gc) X ); X X} X X X X/* Compute the minimum allowable height and width of a cell based on */ X/* the specified fonts. This is done during initialization and when */ X/* XtSetValues changes a font or string table. */ Xstatic void compute_minimum_cell_size(new) XCalendarWidget new; X{ X int max_day_digit_width = 0; X int max_day_digit_height = 0; X int max_day_name_width = 0; X int max_day_name_height = 0; X int max_month_name_width = 0; X int max_year_width = 0; X int max_title_width; X int max_title_height; X XFontStruct * font; X char digit_string[4]; X char * string; X int length; X int i; X int temp; X X /* WIDTH: */ X X /* Compute the max width needed for all digits in the digit font. */ X font = new->calendar.digit_fsp; X for (i=0; i < MAX_DAYS_IN_MONTH; i++) { X temp = X XTextWidth( X font, X new->calendar.digit_names[i], X new->calendar.digit_name_lengths[i] X ); X max_day_digit_width = MAX(max_day_digit_width, temp); X } X /* Add in a space to avoid cramming. */ X max_day_digit_width += XTextWidth(font, " ", 1); X X /* Compute the max width needed for all weekday names in the names font. */ X font = new->calendar.weekday_fsp; X for (i=0; i < DAYS_IN_WEEK; i++) { X string = new->calendar.weekday_names[i]; X length = new->calendar.weekday_name_lengths[i]; X temp = XTextWidth(font, string, length); X max_day_name_width = MAX(max_day_name_width, temp); X } X max_day_name_width += XTextWidth(font, " ", 1); X X /* Compute the max width needed for all month names in title font. */ X font = new->calendar.title_fsp; X for (i=0; i < MONTHS_IN_YEAR; i++) { X string = new->calendar.month_names[i]; X length = new->calendar.month_name_lengths[i]; X temp = XTextWidth(font, string, length); X max_month_name_width = MAX(max_month_name_width, temp); X } X X /* Compute the max width needed to hold any 5 digit year in title font. */ X digit_string[1] = NULL; X for (i=0; i < 10; i++) { X digit_string[0] = (char) ('0' + i); X temp = XTextWidth(font, digit_string, 1); X max_year_width = MAX(max_year_width, temp); X } X max_year_width *= 5; X X max_title_width X = max_month_name_width X + max_year_width X + XTextWidth(font, " ", 1) ; X X /* Divide this by the number of rows. Add one for spacing. */ X max_title_width /= (ROWS + 1); X X /* Set the minimum cell width to the max width required above. */ X new->calendar.min_cell_width = X (float) MAX3(max_day_digit_width, X max_day_name_width, X max_title_width); X X /* HEIGHT: */ X X font = new->calendar.digit_fsp; X max_day_digit_height = font->ascent + font->descent; X X font = new->calendar.weekday_fsp; X max_day_name_height = font->ascent + font->descent; X X font = new->calendar.title_fsp; X max_title_height = font->ascent + font->descent; X X /* Set the minimum cell height to the max height required above plus */ X /* whatever we need to for the line width and borders. */ X new->calendar.min_cell_height = X (float) MAX3(max_day_digit_height, max_day_name_height, max_title_height) X + 2 * INVERT_BORDER X + 2 * new->calendar.line_width X + 2; X} X X X Xstatic void free_line_GCs(widget) XCalendarWidget widget; X{ X Display *display; X X display = XtDisplay(widget); X X XFreeGC(display, widget->calendar.draw_gc); X XFreeGC(display, widget->calendar.undraw_gc); X XFreeGC(display, widget->calendar.invert_gc); X} X X X X Xstatic void free_font_GCs_and_info(widget) XCalendarWidget widget; X{ X Display *display; X X display = XtDisplay(widget); X X XFreeGC(display, widget->calendar.digit_draw_gc); X XFreeGC(display, widget->calendar.digit_undraw_gc); X XFreeFont(display, widget->calendar.digit_fsp); X X XFreeGC(display, widget->calendar.weekday_draw_gc); X XFreeGC(display, widget->calendar.weekday_undraw_gc); X XFreeFont(display, widget->calendar.weekday_fsp); X X XFreeGC(display, widget->calendar.title_draw_gc); X XFreeGC(display, widget->calendar.title_undraw_gc); X XFreeFont(display, widget->calendar.title_fsp); X X XFreeGC(display, widget->calendar.info_draw_gc); X XFreeGC(display, widget->calendar.info_undraw_gc); X XFreeFont(display, widget->calendar.info_fsp); X} X X Xstatic void rotate_weekdays(widget) XCalendarWidget widget; X{ X int weekday; X int i; X char * save_names[DAYS_IN_WEEK]; X int save_lengths[DAYS_IN_WEEK]; X X weekday = widget->calendar.starting_weekday; X if (!weekday) { X return; X } X X /* Save a copy of the table. */ X for (i=0; i < DAYS_IN_WEEK; i++) { X save_names[i] = widget->calendar.weekday_names[i]; X save_lengths[i] = widget->calendar.weekday_name_lengths[i]; X } X X /* Rotate the original. */ X for (i=0; i < DAYS_IN_WEEK; i++) { X widget->calendar.weekday_names[i] = save_names[weekday]; X widget->calendar.weekday_name_lengths[i] = save_lengths[weekday]; X weekday++; X if (weekday == DAYS_IN_WEEK) { X weekday = 0; X } X } X} X X X X/* X For simplicity and convenience, the window is divided into a grid of 7 by 8 X rectangles. However, vertical lines are not drawn in the top 2 rows of boxes X because that's where the month/year text and day-of-week names will go. X*/ Xstatic void compute_grid(widget) XCalendarWidget widget; X{ X int window_width = widget->core.width; X int window_height = widget->core.height; X float cell_width = widget->calendar.real_cell_width; X float cell_height = widget->calendar.real_cell_height; X float min_cell_width = widget->calendar.min_cell_width; X float min_cell_height = widget->calendar.min_cell_height; X int bottom_showing = (window_height >= ROWS * min_cell_height); X int right_showing = (window_width >= COLS * min_cell_width); X int line_width = widget->calendar.line_width; X int fudge = line_width % 2; X int seg; X int i; X X /* Compute horizontal segments. */ X seg = 0; X for (i=2; i < HORIZ_SEGMENTS+2; i++, seg++) { X /* Starting point. */ X widget->calendar.segments[seg].x1 = (short) (0); X widget->calendar.segments[seg].y1 = (short) (cell_height * i); X X /* Ending point. */ X widget->calendar.segments[seg].x2 = (short) (window_width); X widget->calendar.segments[seg].y2 = (short) (cell_height * i); X } X X /* Compute vertical segments. */ X for (i=1; i < VERTI_SEGMENTS+1; i++, seg++) { X /* Starting point. */ X widget->calendar.segments[seg].x1 = (short) (cell_width * i); X widget->calendar.segments[seg].y1 = (short) (cell_height * 2); X X /* Ending point. */ X widget->calendar.segments[seg].x2 = (short) (cell_width * i); X widget->calendar.segments[seg].y2 = (short) (window_height); X } X X /* Draw a border around the whole grid. I could do this with an */ X /* XRectangle, but since I'm calling XDrawSegments, it's one less */ X /* function call to do it this way (could still be slower though) */ X X /* draw solid top */ X widget->calendar.segments[seg].x1 = (short) (0); X widget->calendar.segments[seg].y1 = (short) (0); X widget->calendar.segments[seg].x2 = (short) (window_width); X widget->calendar.segments[seg].y2 = (short) (0); X X /* draw solid left */ X seg++; X widget->calendar.segments[seg].x1 = (short) (0); X widget->calendar.segments[seg].y1 = (short) (0); X widget->calendar.segments[seg].x2 = (short) (0); X widget->calendar.segments[seg].y2 = (short) (window_height); X X /* draw solid bottom */ X if (bottom_showing) { X seg++; X widget->calendar.segments[seg].x1 = (short) (0); X widget->calendar.segments[seg].y1 = (short) (window_height - fudge); X widget->calendar.segments[seg].x2 = (short) (window_width); X widget->calendar.segments[seg].y2 = (short) (window_height - fudge); X } X X /* draw solid right */ X if (right_showing) { X seg++; X widget->calendar.segments[seg].x1 = (short) (window_width - fudge); X widget->calendar.segments[seg].y1 = (short) (0); X widget->calendar.segments[seg].x2 = (short) (window_width - fudge); X widget->calendar.segments[seg].y2 = (short) (window_height); X } X X widget->calendar.number_segments = seg+1; X} X X X X Xstatic void draw_grid(widget) XCalendarWidget widget; X{ X if (widget->calendar.state == foggy) { X return; X } X X /* Draw the grid. */ X XDrawSegments( X XtDisplay(widget), X XtWindow(widget), X widget->calendar.draw_gc, X widget->calendar.segments, X widget->calendar.number_segments X ); X} X X X X Xstatic void compute_cell_geometry(widget) XCalendarWidget widget; X{ X int window_width = widget->core.width; X int window_height = widget->core.height; X int old_window_width = widget->calendar.old_window_width; X int old_window_height = widget->calendar.old_window_height; X float cell_width = widget->calendar.real_cell_width; X float cell_height = widget->calendar.real_cell_height; X int line_width = widget->calendar.line_width; X int line_factor = line_width / 2; X int fudge = line_width % 2; X int temp_x; X int temp_y; X int x,y; X X /* If the window size has changed, re-compute the cell_geometry array. */ X /* This takes a little while (lots of float arithmetic) but that's okay */ X /* because it only happens on resize, and we should punish the user. */ X X if (old_window_width != window_width || old_window_height != window_height) { X X /* Compute geometries for cells not along top, right or bottom edge. */ X for (x=0; x < COLS-1; x++) { X for (y=1; y < ROWS-1; y++) { X GEOMETRY(widget, x, y).x = temp_x X = (short) (x * cell_width + line_factor + fudge + INVERT_BORDER); X GEOMETRY(widget, x, y).y = temp_y X = (short) (y * cell_height + line_factor + fudge + INVERT_BORDER); X GEOMETRY(widget, x, y).width X = (unsigned short) ((x+1) * cell_width - line_factor - INVERT_BORDER - temp_x); X GEOMETRY(widget, x, y).height X = (unsigned short) ((y+1) * cell_height - line_factor - INVERT_BORDER - temp_y); X } X } X X /* Compute geometries for cells along right edge. */ X x = COLS-1; X for (y=0; y < ROWS-1; y++) { X GEOMETRY(widget, x, y).x = temp_x X = (short) (x * cell_width + line_factor + fudge + INVERT_BORDER); X GEOMETRY(widget, x, y).y = temp_y X = (short) (y * cell_height + line_factor + fudge + INVERT_BORDER); X GEOMETRY(widget, x, y).width X = (unsigned short) (COLS * cell_width - line_factor - INVERT_BORDER - temp_x - fudge); X GEOMETRY(widget, x, y).height X = (unsigned short) ((y+1) * cell_height - line_factor - INVERT_BORDER - temp_y); X } X X /* Compute geometries for cells along bottom edge. */ X /* For a valid calendar, at most the first two cells in the bottom */ X /* row will be used. */ X y = ROWS-1; X for (x=0; x < 3; x++) { X GEOMETRY(widget, x, y).x = temp_x X = (short) (x * cell_width + line_factor + fudge + INVERT_BORDER); X GEOMETRY(widget, x, y).y = temp_y X = (short) (y * cell_height + line_factor + fudge + INVERT_BORDER); X GEOMETRY(widget, x, y).width X = (unsigned short) ((x+1) * cell_width - line_factor - INVERT_BORDER - temp_x); X GEOMETRY(widget, x, y).height X = (unsigned short) (ROWS * cell_height - line_factor - INVERT_BORDER - temp_y - fudge); X } X X /* Finally, compute the available rectangle for centering the title. */ X widget->calendar.title_geometry.x = temp_x X = (short) (line_factor + fudge + INVERT_BORDER); X widget->calendar.title_geometry.y = temp_y X = (short) (line_factor + fudge + INVERT_BORDER); X widget->calendar.title_geometry.width X = (unsigned short) (COLS * cell_width - line_factor - INVERT_BORDER - temp_x - fudge); X widget->calendar.title_geometry.height X = (unsigned short) (cell_height - line_factor - INVERT_BORDER - temp_y); X X /* Factor in the day names font size for a better appearance. */ X widget->calendar.title_geometry.height X = (unsigned short) (widget->calendar.title_geometry.height X + cell_height X - widget->calendar.weekday_fsp->ascent X - widget->calendar.weekday_fsp->descent X - 1); X X widget->calendar.old_window_height = window_height; X widget->calendar.old_window_width = window_width; X } X} X X X X Xstatic void draw_weekdays(widget) XCalendarWidget widget; X{ X if (widget->calendar.state == foggy) { X return; X } X X DrawStringsInRects( X XtDisplay(widget), X XtWindow(widget), X widget->calendar.weekday_draw_gc, X widget->calendar.weekday_fsp, X widget->calendar.weekday_names, X widget->calendar.weekday_name_lengths, X &GEOMETRY(widget, 0, 1), X DAYS_IN_WEEK, X South, X 1,0 X ); X} X X X Xstatic void draw_digits(widget) XCalendarWidget widget; X{ X int x,y; X int start = widget->calendar.month_start_cellnum; X int end = widget->calendar.month_end_cellnum; X X if (widget->calendar.state == foggy) { X return; X } X X CELLNUMtoCELLXY(start,x,y); X X DrawStringsInRects( X XtDisplay(widget), X XtWindow(widget), X widget->calendar.digit_draw_gc, X widget->calendar.digit_fsp, X widget->calendar.digit_names, X widget->calendar.digit_name_lengths, X &GEOMETRY(widget, x, y), X end - start + 1, X widget->calendar.digit_gravity, X 1,0 X ); X} X X X Xstatic void draw_title(widget) XCalendarWidget widget; X{ X if (widget->calendar.state == foggy) { X return; X } X X DrawStringInRect( X XtDisplay(widget), X XtWindow(widget), X widget->calendar.title_draw_gc, X widget->calendar.title_fsp, X widget->calendar.title_string, X widget->calendar.title_string_length, X &widget->calendar.title_geometry, X Center, X 1,0 X ); X} X X X X X X/* Routine to fill in the widget->calendar.month_starting_weekdays[] and */ X/* the widget->calendar.days_in_february field, given a certain date. */ X/* The data is only computed when the widget's current_year has changed. */ X Xstatic void compute_month_data(widget) XCalendarWidget widget; X{ X int month = widget->calendar.date.month - 1; X int year = widget->calendar.date.year; X int leap_days; X int total_days; X int weekday; X int i; X X if (widget->calendar.current_year != year) { X /* Compute data for the whole year while we're at it. */ X leap_days = 1; /* Year 0 was a leap year. */ X leap_days += year/4; /* Add all years divisible by 4. */ X leap_days -= year/100; /* Subtract all century years. */ X leap_days += year/400; /* Add back century years divisible by 400. */ X X if (A_LEAP_YEAR(year)) { X leap_days--; X widget->calendar.days_in_february = 29; X } else { X widget->calendar.days_in_february = 28; X } X X /* Compute days elapsed to beginning of the year. */ X total_days = (year*365) + leap_days; X X /* Compute the starting weekday for january in this year. */ X weekday = DAYStoWEEKDAY(total_days); X weekday = ROTATE(widget, weekday); X widget->calendar.month_starting_weekdays[JANUARY] = weekday; X X /* Compute the starting weekday for february in this year. */ X total_days += days_in_month[JANUARY]; X weekday = DAYStoWEEKDAY(total_days); X weekday = ROTATE(widget, weekday); X widget->calendar.month_starting_weekdays[FEBRUARY] = weekday; X X /* Compute the starting weekday for the rest of the months. */ X total_days += widget->calendar.days_in_february; X for (i=MARCH; i <= DECEMBER; i++) { X weekday = DAYStoWEEKDAY(total_days); X weekday = ROTATE(widget, weekday); X widget->calendar.month_starting_weekdays[i] = weekday; X total_days += days_in_month[i]; X } X widget->calendar.current_year = year; X X /* Compute the new year string. */ X if (widget->calendar.show_year) { X sprintf(widget->calendar.year_string, "%d" ,widget->calendar.date.year); X widget->calendar.year_string_length = strlen(widget->calendar.year_string); X } else { X strcpy(widget->calendar.year_string, ""); X widget->calendar.year_string_length = 0; X } X } X X widget->calendar.month_start_cellnum X = widget->calendar.month_starting_weekdays[month]; X X widget->calendar.month_end_cellnum X = widget->calendar.month_start_cellnum X + DAYS_IN_MONTH(widget) - 1; X} X X X X X X Xstatic void compute_title_string(widget) XCalendarWidget widget; X{ X int month = widget->calendar.date.month - 1; X X /* Compute the title string length. */ X widget->calendar.title_string_length = widget->calendar.month_name_lengths[month]; X X /* Fill in the title string. */ X strcpy(widget->calendar.title_string, widget->calendar.month_names[month]); X X if (widget->calendar.show_year) { X strcat(widget->calendar.title_string, " "); X widget->calendar.title_string_length += 1; X X strcat(widget->calendar.title_string, widget->calendar.year_string); X widget->calendar.title_string_length += widget->calendar.year_string_length; X } X} X X X X X X Xstatic void clear_calendar(widget) XCalendarWidget widget; X{ X int month_start_cellnum = widget->calendar.month_start_cellnum; X int month_end_cellnum = widget->calendar.month_end_cellnum; X Display * display; X Window window; X int x,y; X X if (widget->calendar.state == foggy) { X return; X } X BEGIN("clear_calendar"); X X display = XtDisplay(widget); X window = XtWindow(widget); X X CELLNUMtoCELLXY(month_start_cellnum, x, y); X X /* Erase the digits. */ X XFillRectangles( X display, X window, X widget->calendar.undraw_gc, X &GEOMETRY(widget,x,y), X month_end_cellnum - month_start_cellnum + 1 X ); X X /* Erase the title box. */ X XFillRectangles( X display, X window, X widget->calendar.undraw_gc, X &widget->calendar.title_geometry, X 1 X ); X X END("clear_calendar"); X} X X X X Xstatic void calendar_update(widget) XCalendarWidget widget; X{ X X BEGIN("calendar_update"); X X clear_calendar (widget); X compute_month_data (widget); X compute_title_string (widget); X draw_title (widget); X draw_digits (widget); X X if (SYNC(widget)) { X toggle_highlight(widget, ON); X } else { X widget->calendar.current_x_cell = 0; X widget->calendar.current_y_cell = 0; X } X X END("calendar_update"); X} X X X Xstatic void toggle_highlight(widget, state) XCalendarWidget widget; Xint state; X{ X int current_x_cell; X int current_y_cell; X int day; X Display * display; X Window window; X GC draw_gc; X GC undraw_gc; X X if (widget->calendar.state == foggy) { X return; X } X BEGIN("toggle_highlight"); X X WIDGETtoCELLXY( X widget, X current_x_cell, X current_y_cell X ); X X day = widget->calendar.highlight_date.day - 1; X X if (current_y_cell && widget->calendar.highlight) { X X display = XtDisplay(widget); X window = XtWindow(widget); X X if (state == ON) { X draw_gc = widget->calendar.draw_gc; X undraw_gc = widget->calendar.digit_undraw_gc; X } else { X draw_gc = widget->calendar.undraw_gc; X undraw_gc = widget->calendar.digit_draw_gc; X } X X XFillRectangles( X display, X window, X draw_gc, X &GEOMETRY(widget, current_x_cell, current_y_cell), X 1 X ); X X DrawStringInRect( X display, X window, X undraw_gc, X widget->calendar.digit_fsp, X widget->calendar.digit_names[day], X widget->calendar.digit_name_lengths[day], X &GEOMETRY(widget, current_x_cell, current_y_cell), X widget->calendar.digit_gravity, X 1,0 X ); X X /* Eventually this will need to draw the day info as well. */ X } X X if (state == OFF) { X widget->calendar.current_x_cell = 0; X widget->calendar.current_y_cell = 0; X } else { X widget->calendar.current_x_cell = current_x_cell; X widget->calendar.current_y_cell = current_y_cell; X } X X END("toggle_highlight"); X} X X X X X X/*==========================================================================*/ X/* Public Functions: */ X/*==========================================================================*/ Xvoid CalendarIncMonth(widget) XCalendarWidget widget; X{ X if (widget->calendar.date.month == DECEMBER+1) { X widget->calendar.date.month = JANUARY+1; X widget->calendar.date.year++; X } else { X widget->calendar.date.month++; X } X calendar_update(widget); X} X X X Xvoid CalendarDecMonth(widget) XCalendarWidget widget; X{ X if (widget->calendar.date.month == JANUARY+1) { X widget->calendar.date.month = DECEMBER+1; X widget->calendar.date.year--; X } else { X widget->calendar.date.month--; X } X calendar_update(widget); X} X X Xvoid CalendarIncYear(widget) XCalendarWidget widget; X{ X widget->calendar.date.year++; X calendar_update(widget); X} X X X Xvoid CalendarDecYear(widget) XCalendarWidget widget; X{ X widget->calendar.date.year--; X calendar_update(widget); X} X X X X Xvoid CalendarIncDay(widget, show) XCalendarWidget widget; XBoolean show; X{ X if (!widget->calendar.highlight_date.day) { X return; X } X BEGIN("CalendarIncDay"); X X if (SYNC(widget)) { X toggle_highlight(widget, OFF); X } X X if (widget->calendar.highlight_date.day == DAYS_IN_HIGHLIGHT_MONTH(widget)) { X /* We've rolled over a month. */ X widget->calendar.highlight_date.day = 1; X X if (widget->calendar.highlight_date.month == DECEMBER+1) { X widget->calendar.highlight_date.month = JANUARY+1; X widget->calendar.highlight_date.year++; X X /* We've rolled over a year, get new days in feb. */ X widget->calendar.highlight_days_in_february X = 28 + A_LEAP_YEAR(widget->calendar.highlight_date.year); X X } else { X widget->calendar.highlight_date.month++; X } X X if (show) { X CalendarShowMonth(widget, widget->calendar.highlight_date); X } X X } else { X widget->calendar.highlight_date.day++; X } X X if (SYNC(widget)) { X toggle_highlight(widget, ON); X } X X END("CalendarIncDay"); X} X X X X X Xvoid CalendarDecDay(widget, show) XCalendarWidget widget; XBoolean show; X{ X if (!widget->calendar.highlight_date.day) { X return; X } X BEGIN("CalendarDecDay"); X X if (SYNC(widget)) { X toggle_highlight(widget, OFF); X } X X if (widget->calendar.highlight_date.day == 1) { X /* We've rolled over a month. */ X X if (widget->calendar.highlight_date.month == JANUARY+1) { X widget->calendar.highlight_date.month = DECEMBER+1; X widget->calendar.highlight_date.year--; X widget->calendar.highlight_date.day = 31; X X /* We've rolled over a year, get new days in feb. */ X widget->calendar.highlight_days_in_february X = 28 + A_LEAP_YEAR(widget->calendar.highlight_date.year); X X } else { X widget->calendar.highlight_date.month--; X widget->calendar.highlight_date.day = DAYS_IN_HIGHLIGHT_MONTH(widget); X } X X if (show) { X CalendarShowMonth(widget, widget->calendar.highlight_date); X } X X } else { X widget->calendar.highlight_date.day--; X } X X if (SYNC(widget)) { X toggle_highlight(widget, ON); X } X X END("CalendarDecDay"); X} X X X X X Xvoid CalendarSetDate(widget, date) XCalendarWidget widget; XDate date; X{ X if (!is_valid_date(&date)) { X return; X } X BEGIN("CalendarSetDate"); X X if (SYNC(widget)) { X /* Reset any already highlighted date. */ X toggle_highlight(widget, OFF); X } X X if (widget->calendar.date.month == date.month && X widget->calendar.date.year == date.year) { X /* The date specified is on the calendar currently being shown. */ X X /* Highlight the specified date. */ X widget->calendar.highlight_date = date; X toggle_highlight(widget, ON); X } else { X /* The date specified is not on the current calendar. */ X X if (date.year != widget->calendar.highlight_date.year) { X widget->calendar.highlight_days_in_february X = 28 + A_LEAP_YEAR(date.year); X } X widget->calendar.highlight_date = date; X } X X END("CalendarSetDate"); X} X X X X Xvoid CalendarShowMonth(widget, date) XCalendarWidget widget; XDate date; X{ X date.day = 1; X if (!is_valid_date(&date)) { X return; X } X BEGIN("CalendarShowMonth"); X X if (widget->calendar.date.month == date.month X && widget->calendar.date.year == date.year) { X /* The corresponding calendar is currently being displayed. */ X } else { X /* The corresponding calendar is not currently being displayed. */ X widget->calendar.date.month = date.month; X widget->calendar.date.year = date.year; X calendar_update(widget); X } X X END("CalendarShowMonth"); X} X X X Xvoid CalendarGetDate(widget, date_ptr) XCalendarWidget widget; XDate * date_ptr; X{ X *date_ptr = widget->calendar.highlight_date; X} X X X XDate DateConverter(widget, string) XCalendarWidget widget; Xchar * string; X{ X /* Call the real converter. This just allows us to hide details. */ X return (convert_string_to_date(widget->calendar.month_names, string)); X} X X X X X/* Returns a Date structure corresponding to the current date. */ X/* Most applications are going to need it so I'll just provide it. */ XDate GetTodaysDate() X{ X Date date; X time_t current_time = time(NULL); X struct tm * current_tm = localtime(¤t_time); X date.month = current_tm->tm_mon + 1; X date.day = current_tm->tm_mday; X date.year = current_tm->tm_year + 1900; X return date; X} X X X X X/* Return a string like "Thursday October 15, 1990" */ Xchar * CalendarPrettyDate(widget) XCalendarWidget widget; X{ X static char buffer[MAX_PRETTY_DATE_STRING_LENGTH]; X Date highlight_date; X Date showing_date; X int weekday; X int month; X X highlight_date = widget->calendar.highlight_date; X showing_date = widget->calendar.date; X X if (showing_date.year == highlight_date.year) { X month = highlight_date.month - 1; X weekday = widget->calendar.month_starting_weekdays[month]; X weekday = (weekday + highlight_date.day - 1) % 7; X } else { X /* No info available, so resort to brute force. */ X weekday = compute_weekday(highlight_date); X weekday = ROTATE(widget, weekday); X } X X /*VARARGS*/ X sprintf( X buffer, X "%s %s %d, %d", X widget->calendar.weekday_names[weekday], X widget->calendar.month_names[highlight_date.month-1], X highlight_date.day, X highlight_date.year X ); X X return buffer; X} X X X Xstatic int compute_weekday(date) XDate date; X{ X int leap_days; X int total_days; X int month; X int days_in_february; X X leap_days = 1; /* Year 0 was a leap year. */ X leap_days += date.year/4; /* Add all years divisible by 4. */ X leap_days -= date.year/100; /* Subtract all century years. */ X leap_days += date.year/400; /* Add back century years divisible by 400. */ X X if (A_LEAP_YEAR(date.year)) { X leap_days--; X days_in_february = 29; X } else { X days_in_february = 28; X } X X total_days = (date.year*365) + leap_days; X X for (month=0; month < date.month - 1; month ++) { X if (month == FEBRUARY) { X total_days += days_in_february; X } else { X total_days += days_in_month[month]; X } X } X X total_days += date.day - 1; X X return DAYStoWEEKDAY(total_days); X} END_OF_FILE if test 58171 -ne `wc -c <'Calendar.c'`; then echo shar: \"'Calendar.c'\" unpacked with wrong size! fi # end of 'Calendar.c' fi echo shar: End of archive 5 \(of 5\). cp /dev/null ark5isdone MISSING="" for I in 1 2 3 4 5 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 5 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- |===================================|===================================| | Jason "Jasper" Baietto | otteiaB "repsaJ" nosaJ | | Harris Computer Systems Division | noisiviD smetsyS retupmoC sirraH | | Fort Lauderdale, Florida | adirolF ,eladreduaL troF | | jason@hcx2.ssd.csd.harris.com | moc.sirrah.dsc.dss.2xch@nosaj | |===================================|===================================|