[comp.sys.sgi] TurboCal

tomm@voodoo.voodoo.uucp (Tom Mackey) (12/01/90)

(I tried sending this to Dan Watts, but it bounced.  Maybe he'll
 see it here, and it might prove interesting to others. too.  And
 a note to my lead:  Hey, Mike, umm, you see, I was researching
 User Interface techniques!  Yeah, that's the ticket!  ;^)

Hi Dan,

In comp.sys.sgi you offered to send out your improved version
of ical.  I'd like to see yours, and in return, I'll send you
my version.... I've added a number of enhancements to the
already enhanced version posted a few weeks back (the one that
shows the time in the lower right corner and the sun and moon
trace a circular path thru the day).  My 60 second return is
pretty hacky, so I'd like to see hou you did it.  In fact, I'll
just attach my source to this message.

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
-----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	Readme
#	ical.c
# This archive created: Fri Nov 30 09:01:34 1990
cat << \SHAR_EOF > Readme
The history of what I (tomm@voodoo.boeing.com) am calling "TurboCal"
--------------------------------------------------------------------

Seth Teller writes:

Article 6441 of comp.sys.sgi:
From: seth@miro.Berkeley.EDU (Seth Teller)
Newsgroups: comp.sys.sgi
Subject: new, improved ical; was Re: Ical update
Summary: source code for new ical program
Message-ID: <9095@pasteur.Berkeley.EDU>
Date: 20 Nov 90 17:33:43 GMT
Sender: news@pasteur.Berkeley.EDU
Reply-To: seth@miro.Berkeley.EDU (Seth Teller)
Organization: University of California at Berkeley
Lines: 364

In article <1990Nov19.171917.15946@relay.wpd.sgi.com> schuman@sgi.com
(Aaron Schuman) writes:
>Dan>	Is there a simple way to bump the calendar program
>Dan>	at night so that is shows the correct day if you
>Dan>	leave it running overnight ?
>
>I use this easy shell script (kept in ~/bin/cal_update):
>
>
>kill `ps -ef | grep ical | grep -v ep | awk '{print $2}'`
>/usr/sbin/ical
>echo "sh /usr/people/schuman/bin/cal_update" | at 0500 tomorrow

here's another approach.  below is a hacked version of ical that
a) keeps correct time as long as it gets timer events (days,
weeks, etc.), and b) has a nifty sun & moon that rise and set
at 6am and 6pm.  

i can't remember if a) was added by paul or me.  if it works,
thank him.  if it's broken, complaints to me i suppose (or fix
it yourself).

if any astronomer types make the program faithful to reality, 
please share your efforts with us.

finally, note the hack in the first 7 lines of the c file:
save it as ical.c, and source it (or chmod it and execute
it)... and it will compile itself with no Makefile.

yours,

seth teller
--------------------------------------------------------------------

--------------------------------------------------------------------
November 29, 1990:

I took Paul and Seth's code and hacked on it some more so that:

1) The increment of time adjustment with the B and F keys is 15
   minutes instead of 2.

2) If the day is advanced or retarded by using the B or F keys,
   the blue circle denotes the "bogus" day, while the actual day
   remains displayed in red.

3) If the B, F, or Mouse keys are used to fiddle with the calandar,
   a string "Bogus Data" is displayed in the lower left corner.

4) If the calandar is is fiddled with and then left alone for
   one minute, it returns to the current time and month.

5) If the month is advanced or retarded via the Left and Middle
   mouse buttons, the actual current day of the month is circled
   in blue.  This day reflects the actual current day, or the
   day as advanced with the B and F keys.  Perhaps only one mode
   of twiddling should be supported at a time, but I had already
   wasted too much time for this round of modifications.  This
   should also make for some "interesting" results when dealing
   with the month of February!

Still to do:  (1) The code is pretty hard to follow, and not easy
to modify.  Much of the logic could be cleaned up.  (2) When the
calandar is started with comamnd line options, a different string
should be displayed, and some key should be added to get to the
current month, and another to get back to the command line month.
(3) It would be trivial to steal the moon phase calculating code
from "phoon" or "month" to display the 4 major phases of the moon
under their occurance dates.  (4) Instead of the B and F keys, add
a key that will animate the sunrise - sunset sequence and then
return to the correct time.  (But of course, it IS fun to twiddle
with the cute lil' sun! ;^)  (5) Rethink the handling problems as
described in change 5 above.  (6) Mirror or replace button
functionality with popup menu.

Tom Mackey       (206) 865-6575        tomm@voodoo.boeing.com
Boeing Computer Services         ....uunet!bcstec!voodoo!tomm
M/S 7K-20,     P.O. Box 24346,     Seattle, WA     98124-0346
--------------------------------------------------------------------
SHAR_EOF
cat << \SHAR_EOF > ical.c
#ifdef EXECUTABLE 
set verbose
cc -o ical ical.c -I/usr/include/gl -lgl_s -lm
unset verbose
exit
cc -o ical ical.c -I/usr/include/gl -lgl_s -lgutil -lm
#endif EXECUTABLE
/* to compile this, make .c file executable and type 'source ical.c' */
/*
 *      ical - 
 *              A very simple desk calendar.  Use the left and middle mouse
 *      mouse buttons to go forward and backward in time.
 *      
 *                              Paul Haeberli - 1985
 *
 *      modified to add alpha clock in lrh corner, yellow sun, blue moon...
 *
 *                              Seth Teller - 1989    
 *
 *	Note that Seth's version uses the B, F, and R keys to allow
 *	the user to twiddle with the sun and moon (Back, Fwd, Restore).
 *
 *	Added improvements: B and F keys increment is now 15 minutes,
 *	"Bogus Data" string displayed when B, F, or Mouse buttons change
 *	from actual time and month, current day-of-month always circled
 *	in blue, calandar reverts to current time and month 60 seconds
 *	after being twiddled.  See Readme for more info.
 *
 *				Tom Mackey - 1990
 *
 */
#include <gl.h>
#include <device.h>
#include <math.h>
#include <time.h>

#define rgb(r,g,b) cpack(((unsigned char)(b * 255.0) << 16) | \
			 ((unsigned char)(g * 255.0) << 8)  | \
			 ((unsigned char)(r * 255.0) << 0))

#define grey(i) cpack(((unsigned char)(i * 255.0) << 16) | \
		      ((unsigned char)(i * 255.0) << 8)  | \
		      ((unsigned char)(i * 255.0) << 0))

#define PI (3.1415926)

char *monthnames[] = {  "January", "February", "March", "April",
			"May", "June", "July", "August",
			"September", "October", "November", "December" };

char *daynames[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

char monlength[] = { 0,
		    31, 29, 31, 30,
		    31, 30, 31, 31,
		    30, 31, 30, 31 };

struct  caltime
{
    int second;
    int minute;
    int hour;
    int day;
    int month;
    int year;
};

struct caltime Today = { -1, -1, -1, -1, -1, -1 }, Show;
int CalWin = 0;
long Toffset = 0;
int BogusTime = 0;

void print_timeofday();

void update_time (show, today)
struct caltime *show, *today;
{
    static long lasttime, thetime, showtime, lastreq;
    static float correction = 1.0;
    static struct tm *tm, *showtm;

    lasttime = thetime;
    thetime = time(0);
    showtime = thetime + Toffset;

    tm = localtime(&thetime);

    today->second = tm->tm_sec;
    if (today->minute != tm->tm_min) {
        today->minute = tm->tm_min;
        qenter (REDRAW, CalWin);
    }
    today->hour = tm->tm_hour;

    today->year = tm->tm_year + 1900;
    today->month = tm->tm_mon + 1;
    today->day = tm->tm_mday;

    showtm = localtime(&showtime);

    show->day = showtm->tm_mday;
    show->second = showtm->tm_sec;
    show->minute = showtm->tm_min;
    show->hour = showtm->tm_hour;

    if (lastreq && thetime - lasttime >= 30 && !Toffset)
        correction = (lastreq / 60.0) / (thetime - lasttime);

    lastreq = (int)(20 + 60 * (60 - today->second) * correction);

    if (!Toffset)
        noise (TIMER0, lastreq);
    else
        noise (TIMER0, 3600);
}

main(argc, argv)
char *argv[];
{
    short val;
    static long deadline;

    prefsize(260,185);

    CalWin = winopen("TurboCal");
    if (getplanes() > 8)
        doublebuffer();
    RGBmode();
    gconfig();

    qdevice(REDRAW);
    qdevice(LEFTMOUSE);
    qdevice(MIDDLEMOUSE);
    qdevice(TIMER0);
    qdevice(BKEY);
    qdevice(FKEY);
    qdevice(RKEY);

    update_time(&Show, &Today);

    if (argc >= 2) {
        Show.month = atoi(argv[1]);
        Show.year = atoi(argv[2]);
        Show.day = 1;
    } else
        Show = Today;

    while (1) {
        switch (qread(&val)) {

            case BKEY :
                if (val)    {
                    Toffset -= 15 * 60;  /* 15 minutes */
		    deadline = time(0);
		    BogusTime = 1;
                    update_time(&Show, &Today);
                    drawcal(&Show, &Today);
		}
                break;

            case FKEY :
                if (val)    {
                    Toffset += 15 * 60;  /* 15 minutes */
		    deadline = time(0);
		    BogusTime = 1;
                    update_time(&Show, &Today);
                    drawcal(&Show, &Today);
		}
                break;

            case RKEY :
                if (val)    {
                    Toffset = 0;
                    update_time(&Show, &Today);
                    drawcal(&Show, &Today);
		}
                break;

            case LEFTMOUSE :
                if (val) {
                    Show.month--;
                    if (Show.month == 0) {
                        Show.year--;
                        Show.month = 12;
                    }
		    deadline = time(0);
		    BogusTime = 1;
                    drawcal(&Show, &Today);
                }
                break;

            case MIDDLEMOUSE :
                if (val) {
                    Show.month++;
                    if (Show.month == 13) {
                        Show.year++;
                        Show.month = 1;
		    }
		    deadline = time(0);
		    BogusTime = 1;
		    drawcal(&Show, &Today);
		}
                break;

            case REDRAW :
                drawcal(&Show, &Today);
                break;

	    case TIMER0 :
		if ((time(0) - deadline) > 20 && BogusTime)
		{
		    Show.month = Today.month;
		    Show.year = Today.year;
		    BogusTime = FALSE;
		    qenter(RKEY, 1);
		}
		else
		    update_time(&Show, &Today);
		break;

	    default:
		break;
	    }
    }
}

int drawcal(show, today)
struct caltime *show, *today;
{
    register i;
    int c;
    int ycoord;
    int samemonth;
    char tempstr[30];

    reshapeviewport();
    gsync();

    /* find out if we are showing the current month */
    samemonth = ((today->year == show->year) && (today->month == show->month));

    grey(0.8);
    clear();
    grey(0.0);

    {
	/* draw in the sun and the moon */
	/* sun as yellow circle, moon as blue crescent */

	static short left, right, bottom, top;
	int sunx, suny;
	float sung;			    /* green comp */

	if (left == right)
	    getscrmask (&left, &right, &bottom, &top); 

	/* scr mask to clip to top half of screen */
	scrmask (left, right, bottom + (top - bottom) / 2 + 8, top);

	/* draw sun */
	sunx = 130.0 - (60.0 * sin (2.0 * PI * ((show->hour / 24.0) +
		show->minute/(60.0 * 24.0)))); 

	suny =  98.0 - (60.0 * cos (2.0 * PI * ((show->hour / 24.0) +
		show->minute/(60.0 * 24.0)))); 

	if (suny < 118.0 && suny >= 98.0)
	    sung = (12.8 * (suny - 98.0)) / 255.0;  
	else if (suny < 98.0 && suny >= 78.0)
	    sung = 0.0;
	else
	    sung = 1.0;

	rgb (1.0, sung, 0.0);
	circf (sunx, suny, 20.0);

	/* scr mask to clip to bottom half of screen */
	scrmask (left, right, bottom, bottom + (top - bottom) / 2 - 1 + 8);

	rgb (0.0, 0.0, 1.0);
	circfi ((int)sunx, (int)suny, 20);
	grey (0.8);
	circfi ((int)sunx - 10, (int)suny, 20);

	/* scr mask back to normal */
	scrmask (left, right, bottom, top);

	rgb(0.0, 1.0, 0.0);
	move2i(20,99);
	draw2i(240,99);
    }

    grey(0.5);
    move2i(20,163);
    draw2i(240,163);

    rgb(0.0,0.0,1.0);
    cmov2i(20,165);
    charstr(monthnames[show->month-1]);
    rgb(1.0,0.0,0.0);
    sprintf(tempstr,"%u",show->year);
    cmov2i(208,165);
    charstr(tempstr);

    rgb(0.5, 0.5, 0.5);
    move2i(20,143);
    draw2i(240,143);

    grey(0.0);

    for (i=0; i<7; i++){
        cmov2i(24+32*i,145);
        charstr(daynames[i]);
    }

    c = dayofweek(show->month, show->year);
    ycoord = 125;
    for (i=1; i<=monlength[show->month]; i++) {
        cmov2i(24+32*c,ycoord);
        sprintf(tempstr,"%2d",i); 
        if ((i == today->day) && samemonth) {
	    pushattributes();
		rgb(1.0,0.0,0.0);
		charstr(tempstr);
	    popattributes();
	}
	else {
	    charstr(tempstr);
	}

	if (i == show->day) {
	    pushattributes();
		rgb(0.0,0.0,1.0);
		circi((24+32*c)+8, ycoord+5, 12);
	    popattributes();
	}

	/* if finished with this line, drop down to next */
        if (++c == 7) {
            c = 0;
            ycoord -= 20;
        }
    }

    if (Toffset)
	print_timeofday(show);
    else
	print_timeofday(today);

    if (BogusTime)
    {
	pushattributes();
	    rgb(0.15,0.5,0.0);
	    cmov2i(20,10);
	    charstr("Bogus Data");
	popattributes();
    }

    swapbuffers();
}

/*
** build and print time of day string
*/
void print_timeofday(someday)
struct caltime *someday;
{
    char tempstr[30];

    pushattributes();
	rgb(0.0,0.0,1.0);
	cmov2i(176, 10);
	sprintf(tempstr,"%2d:%02d %cm", (someday->hour - 1 + 12) % 12 + 1,
			    someday->minute, someday->hour > 11 ? 'p' : 'a'); 
	charstr(tempstr);
    popattributes();
}

dayofweek(m, y)
{
    register d, i;

    d = jan1(y);

    if (((jan1(y+1)+7-d)%7) == 1)
        monlength[2] = 28;
    else
        monlength[2] = 29;

    for (i=1; i<m; i++)
        d += monlength[i];

    return d%7;
}

/*
 *      return day of the week
 *      of jan 1 of given year
 */
jan1(y)
int y;
{
    register int d;

    d = y + 4 + (y+3)/4;

    if (y > 1752) {
        d += 3;
        if (y > 1800) {
            d -= (y-1701)/100;
            d += (y-1601)/400;
        }
    }
    return d%7;
}


SHAR_EOF
#	End of shell archive
exit 0
--
Tom Mackey       (206) 865-6575        tomm@voodoo.boeing.com
Boeing Computer Services         ....uunet!bcstec!voodoo!tomm
M/S 7K-20,     P.O. Box 24346,     Seattle, WA     98124-0346