xdiary 5/5 (X based calendar and diary)
Jason Baietto
jason at gcx1.ssd.csd.harris.com
Thu Dec 13 10:29:37 AEST 1990
#! /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 at 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 at 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 at hcx2.ssd.csd.harris.com | moc.sirrah.dsc.dss.2xch at nosaj |
|===================================|===================================|
More information about the Alt.sources
mailing list