home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / sun / volume1 / calentool / part04 / dpaint.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-27  |  23.5 KB  |  830 lines

  1. /*
  2.  * $Header: dpaint.c,v 2.2 89/05/10 10:06:20 billr Exp $
  3.  */
  4. /*
  5.  * dpaint.c
  6.  *
  7.  * Author: Philip Heller, Sun Microsystems. Inc. <terrapin!heller@sun.com>
  8.  *
  9.  * Original source Copyright (C) 1987, Sun Microsystems, Inc.
  10.  *    All Rights Reserved
  11.  * Permission is hereby granted to use and modify this program in source
  12.  * or binary form as long as it is not sold for profit and this copyright
  13.  * notice remains intact.
  14.  *
  15.  *
  16.  * Changes/additions by: Bill Randle, Tektronix, Inc. <billr@saab.CNA.TEK.COM>
  17.  *
  18.  * Changes and additions Copyright (C) 1988, 1989 Tektronix, Inc.
  19.  *    All Rights Reserved
  20.  * Permission is hereby granted to use and modify the modifications in source
  21.  * or binary form as long as they are not sold for profit and this copyright
  22.  * notice remains intact.
  23.  */
  24. /***************************************************
  25.  *                           *
  26.  *    Artistic routines that draw in the main    *
  27.  * subwindow for the day display.           *
  28.  *                           *
  29.  ***************************************************/
  30.  
  31. #include <suntool/sunview.h>
  32. #include <suntool/canvas.h>
  33. #include <ctype.h>
  34. #include <sys/time.h>
  35. #include <stdio.h>
  36. #include "ct.h"
  37. #include "paint.h"
  38. #include "riseset.h"
  39. #define J1970   2440587.5 /* VAX clock Epoch 1970 Jan 1 (0h UT) */
  40.  
  41. #ifndef NO_SUN_MOON
  42. extern Frame mframe, sframe;
  43. extern Canvas mcanvas, scanvas;
  44. extern Panel_item mdate_pi, sdate_pi;
  45. #endif
  46. extern Pixrect *leftarrow, *rightarrow;
  47. extern Pixrect *arrowshaft_pr, *arrowhead_pr;
  48. extern int day_message_size;
  49. extern char riseset_buf[][64];
  50. extern int old_slot;
  51. extern int show_future;
  52. extern char *index();
  53.  
  54. struct tm save_day;
  55. struct appt_entry future[MAX_FUTURE_ENTRIES];
  56. int findex = 0;        /* index into struct future array */
  57.  
  58. /*
  59.  * This one draws the current selected day in the
  60.  * main subwindow.
  61.  */
  62.  
  63. draw_day()
  64. {
  65.     draw_day1();
  66.     draw_future_appts();
  67. #ifndef NO_SUN_MOON
  68.     if (sframe)
  69.         write_sun_data();
  70.     if (mframe)
  71.         write_moon_data();
  72. #endif
  73. }
  74.  
  75. /*
  76.  * Draw main day page without future appts or Sun/Moon data
  77.  */
  78. draw_day1()
  79. {
  80.     lock_cursors();
  81.     fix_current_day();
  82.     working(TRUE);
  83.     pw_batch_on(main_pixwin);
  84.     draw_day_outline();
  85.     pw_batch_off(main_pixwin);
  86.     get_day_appts();
  87.     working(FALSE);
  88.     pw_batch_on(main_pixwin);
  89.     draw_day_appts();
  90.     pw_batch_off(main_pixwin);
  91.     day_is_open = TRUE;
  92.     unlock_cursors();
  93. }
  94.  
  95. /*
  96.  * Utility for draw_day ... draws the outline of a day.
  97.  */
  98. draw_day_outline()
  99. {
  100.     char timestring[6], daystring[31], buf[64], *src;
  101.     int x, y, starty, i, d;
  102.     Rect *rect;
  103.  
  104.     /* First erase the window. */
  105.     rect = (Rect *) window_get(canvas, WIN_RECT);
  106.         pw_writebackground(main_pixwin, 0, 0,
  107.       rect->r_width, rect->r_height, PIX_CLR);
  108.     old_slot = -1;    /* text cursor no longer displayed */
  109.  
  110.     /* Calculate coords of top-left corner of big box. */
  111.     x = (rect->r_width - dayslot_width) / 2;
  112.     starty = y = (rect->r_height - (N_SLOTS * dayslot_height)) / 2;
  113.  
  114.     /* Format daystring to say, for example, */
  115.     /* Tuesday, March 12, 1985 */
  116.     sprintf(daystring, "%s %s %d, %d",
  117.         daynames[current.tm_wday], monthnames[current.tm_mon],
  118.         current.tm_mday, 1900 + current.tm_year);
  119.     pw_text(main_pixwin, (rect->r_width - bigfont->pf_defaultsize.x*strlen(daystring))/2, starty/2 + 7,
  120.       PIX_SRC, bigfont, daystring);
  121.  
  122.     for (i=0; i<N_SLOTS; i++) {    /* Init and draw each 30 minute slot. */
  123.                 slots[i].slot_pos.top = y;
  124.         slots[i].slot_pos.left = x;
  125.         slots[i].slot_pos.bottom = y + dayslot_height + 1;
  126.         slots[i].slot_pos.right = x + dayslot_width + 1;
  127.         slots[i].moreb_pos.top = y;
  128.         slots[i].moreb_pos.left = rect->r_width - 8 - morebutton->pr_size.x;
  129.         slots[i].moreb_pos.bottom = y + morebutton->pr_size.y;
  130.         slots[i].moreb_pos.right = rect->r_width - 8;
  131.         slots[i].larrow_pos.top = slots[i].slot_pos.top+(dayslot_height-leftarrow->pr_size.y)/2;
  132.         slots[i].larrow_pos.left = slots[i].slot_pos.right + 8;
  133.         slots[i].larrow_pos.bottom = slots[i].larrow_pos.top + leftarrow->pr_size.y;
  134.         slots[i].larrow_pos.right = slots[i].larrow_pos.left + leftarrow->pr_size.x;
  135.         slots[i].rarrow_pos.top = slots[i].larrow_pos.top;
  136.         slots[i].rarrow_pos.left = slots[i].larrow_pos.right + 8;
  137.         slots[i].rarrow_pos.bottom = slots[i].larrow_pos.bottom;
  138.         slots[i].rarrow_pos.right = slots[i].rarrow_pos.left + rightarrow->pr_size.x;
  139.         if (!ymd_compare(current, today))
  140.             pw_write(main_pixwin,x,y,dayslot_width,dayslot_height,PIX_SRC,timeslot_td_pr,0,0);
  141.         else
  142.             pw_write(main_pixwin,x,y,dayslot_width,dayslot_height,PIX_SRC,timeslot_pr,0,0);
  143.         if (i < n_tslots) {
  144.             /* display time */
  145.             sprintf(timestring, "%2d:%s",
  146.                 (START_HOUR+(i/2))%12 == 0 ? 12 : (START_HOUR+(i/2))%12,
  147.                 i%2 == 0 ? "00" : "30");
  148.         } else if (i == n_tslots) {
  149.             sprintf(timestring, "Notes");
  150.         } else {
  151.             sprintf(timestring, "     ");
  152.         }
  153.         pw_text(main_pixwin,x-8*font->pf_defaultsize.x,y+font->pf_defaultsize.y,PIX_SRC,font,timestring);
  154.         y += dayslot_height - 1;
  155.     }
  156.  
  157.     pw_vector(main_pixwin,x,starty,x+dayslot_width-1,starty,PIX_SET,1);
  158.         pw_vector(main_pixwin,x,y,x+dayslot_width-1,y,PIX_SET,1);
  159.     y += (dayslot_height - 1) * 2;
  160.     sprintf(buf, "Day of year: %d  --  %d days remaining",
  161.         day_of_year((double)current.tm_mday, current.tm_mon+1, current.tm_year),
  162.         days_remaining_in_year((double)current.tm_mday, current.tm_mon+1, current.tm_year));
  163.     pw_text(main_pixwin, x, y, PIX_SRC, font, buf);
  164.     sun_moon_buttons(TRUE);
  165.     print_button(TRUE);
  166. }
  167.  
  168.  
  169. /*
  170.  * Fills in appointments for the day.  
  171.  * The ".tmp.aptsXXXXX" file is filled out
  172.  * with all the lines from the ".appointments" file 
  173.  * which do not pertain to the current day.
  174.  */
  175. get_day_appts()
  176. {
  177.     FILE *apts, *temp_apts;
  178.     int slotno, n_arrows, i;
  179.     int read_stat;
  180.     struct appt_entry appt;
  181.     struct appt_entry *nappt, *aptr;
  182.     char buf[MAX_STRLEN], *sptr;
  183.  
  184.     if ((apts = fopen(apts_pathname, "r")) == NULL)
  185.         err_rpt("can't open appointments file", FATAL);
  186.  
  187.     if (!read_only)
  188.             if ((temp_apts = fopen(tmpapts_pathname, "w")) == NULL)
  189.             err_rpt("can't open temp file for writing", FATAL);
  190.  
  191.     for (i=0; i<N_SLOTS; i++) {    /* init each slot */
  192.                 slots[i].active = INACTIVE;
  193.         slots[i].count = 0;
  194.         slots[i].cur_appt = NULL;
  195.         slots[i].first = NULL;
  196.     }
  197.     First = current;
  198.     findex = 0;
  199.  
  200. #ifndef NO_HOLIDAYS
  201.     /*
  202.      * First check to see if the user has selected any holiday
  203.      * options and add them in.
  204.      */
  205.     if (a_dates(&appt, holiday_a))
  206.         add_note(&appt);
  207.     if (c_dates(&appt, holiday_c))
  208.         add_note(&appt);
  209.     working(FALSE);
  210.     if (i = i_dates(&appt, holiday_i))
  211.         if (i == 2) {
  212.             /* two notes in one */
  213.             strcpy(buf, appt.str);
  214.             /* look for \n */
  215.             sptr = index(appt.str, '\n');
  216.             *sptr = '\0';
  217.             add_note(&appt);
  218.             /* now second half of string in the next note */
  219.             strcpy(appt.str, &buf[(int)(sptr-appt.str)+1]);
  220.             add_note(&appt);
  221.         } else
  222.             add_note(&appt);
  223.     working(TRUE);
  224.     if (j_dates(&appt, holiday_j))
  225.         add_note(&appt);
  226.     if (s_dates(&appt, holiday_s))
  227.         add_note(&appt);
  228. #endif
  229.             
  230.     /*
  231.      * now go thru the appointments file
  232.      */
  233.     while ((read_stat=get_aentry(apts, &appt)) != EOF) {
  234.         if (read_stat)
  235.             continue;    /* read error (ignore) */
  236.         if (appt.flags & A_COMMENT) {
  237.             if (put_aentry(temp_apts, &appt)) {
  238.                 /* write error */
  239.                 break;
  240.             }
  241.             continue;
  242.         }
  243.         current.tm_year = appt.year;
  244.         current.tm_mon = appt.month;
  245.         current.tm_mday = appt.day;
  246.         if (appt.flags & ALL_YEARS)
  247.             current.tm_year = First.tm_year;
  248.         if (appt.flags & ALL_MONTHS)
  249.             current.tm_mon = First.tm_mon;
  250.         if (appt.flags & ALL_DAYS)
  251.             current.tm_mday = First.tm_mday;
  252.         else if (appt.flags & EVERY_SOMEDAY) {
  253.             if (Pickday(appt.flags) == First.tm_wday) {
  254.                 if (chk_week(appt.repeat, First.tm_mday))
  255.                     current.tm_mday = First.tm_mday;
  256.             }
  257.         } else if (appt.flags & REPEAT) {
  258.             while (ymd_compare(current, First) < 0) {
  259.                 current.tm_mday += appt.repeat;
  260.                 fix_current_day();
  261.             }
  262.         }
  263.         if (ymd_compare(current, First) == 0) {
  264.             /* if it's for this day, fill in slot info */
  265.             if (appt.flags & A_NOTE)
  266.                 /* notes section */
  267.                 add_note(&appt);
  268.             else {
  269.                 /* regular appointment */
  270.                 slotno = (appt.hour-START_HOUR) * 2 + appt.minute / 30;
  271.                 if (slotno < 0)
  272.                     slotno = 0;
  273.                 if (slotno >= n_tslots)
  274.                     slotno = n_tslots - 1;
  275.                 /* add this appt to the list of appts for the slot */
  276.                 /* and update all the reference counts */
  277.                 add_to_slot(slotno, &appt, FALSE);
  278.             }
  279.         } else if (appt.flags & LOOKAHEAD) {
  280.             /* This lookahead appt was not for today, so
  281.              * put it in the temp file.
  282.              */
  283.             if (put_aentry(temp_apts, &appt)) {
  284.                 /* write error */
  285.                 break;
  286.             }
  287.             if (appt.flags & EVERY_SOMEDAY) {
  288.                 /* find next occurance of this appt */
  289.                 /* starting from the current day */
  290.                 current.tm_mday = First.tm_mday;
  291.                 fix_current_day();
  292.                 find_date(&appt); /* may modify current */
  293.             }
  294.             if (ymd_compare(current, First) > 0) {
  295.                 /* this appt is happening in
  296.                  * the future, so remind us of it if
  297.                  * it is within the lookahead window.
  298.                  */
  299.                 save_day = current;
  300.                 current.tm_mday -= appt.lookahead;
  301.                 fix_current_day();
  302.                 if (ymd_compare(current, First) <=0) {
  303.                     /* save this one for the future popup window */
  304.                     if (findex > MAX_FUTURE_ENTRIES-1) {
  305.                         err_rpt("Too many future reminders", NON_FATAL);
  306.                         continue;
  307.                     }
  308.                     future[findex] = appt;
  309.                     /* fix up ymd */
  310.                     future[findex].year = save_day.tm_year;
  311.                     future[findex].month = save_day.tm_mon;
  312.                     future[findex].day = save_day.tm_mday;
  313.                     ++findex;
  314.                 }
  315.             }
  316.                 } else {     /* line is not for today */
  317.             /* copy it to temp file */
  318.             if (put_aentry(temp_apts, &appt)) {
  319.                 /* write error */
  320.                 break;
  321.             }
  322.         }
  323.         }
  324.     if (!read_only) {
  325.         if (ferror(temp_apts))
  326.             err_rpt("write on temp file failed", FATAL);
  327.             fclose(temp_apts);        
  328.     }
  329.         fclose(apts);             
  330.     current = First;
  331.     fix_current_day();
  332. }
  333.  
  334.  
  335. /* check for match on weekly re-ocurring appts */
  336. chk_week(repeat, curday)
  337. int repeat, curday;
  338. {
  339.     int weeknr = 0;
  340.  
  341.     if ((repeat & ALL_WEEKS) == ALL_WEEKS)
  342.         return(1);    /* every week */
  343.     if ((repeat & LAST_WEEK) && ((curday+7) > monthlength(current.tm_mon)))
  344.         return(1);    /* last week in month */
  345.  
  346.     while (curday > 7) {
  347.         /* find which week this day is in */
  348.         curday -= 7;
  349.         weeknr++;
  350.     }
  351.     if (repeat & (0x1<<weeknr))
  352.         return(1);
  353.     
  354.     return(0);    /* no match */
  355. }
  356.  
  357.  
  358. /*
  359.  * get date of next occurrance of a weekly repeated appt
  360.  * (it may bridge into next week, month or year)
  361.  */
  362. find_date(appt)
  363. struct appt_entry *appt;
  364. {
  365.     struct tm save;
  366.  
  367.     save = current;
  368.     /* set current to match dow of repeated appt */
  369.     current.tm_mday += Pickday(appt->flags) - current.tm_wday;
  370.     fix_current_day();
  371.     if (ymd_compare(current, save) < 0) {
  372.         /* already happened, so start looking next week */
  373.         current.tm_mday += 7;
  374.         fix_current_day();
  375.     }
  376.     /* search for first matching week */
  377.     while (!chk_week(appt->repeat, current.tm_mday)) {
  378.         current.tm_mday += 7;
  379.         fix_current_day();
  380.     }
  381.     /* now check to make sure this is legal, i.e. there
  382.      * were no month or year restrictions
  383.      */
  384.     if ((!(appt->flags & ALL_YEARS) && current.tm_year != save.tm_year)
  385.        || (!(appt->flags & ALL_MONTHS) && current.tm_mon != save.tm_mon))
  386.         /* invalid date, due to month or year wrap */
  387.         current = save;
  388. }
  389.  
  390.         
  391. /* add a note to the current day */
  392. add_note(appt)
  393. struct appt_entry *appt;
  394. {
  395.     int    slotno;
  396.  
  397.     /* auto-hunt for free note slot */
  398.     for (slotno=n_tslots; slotno<N_SLOTS; slotno++)
  399.         if (slots[slotno].active == INACTIVE)
  400.             break;
  401.     if (slotno == N_SLOTS) {
  402.         /* overflow of notes field, so
  403.          * add to last note field list
  404.          */
  405.         slotno = N_SLOTS - 1;
  406.     }
  407.     add_to_slot(slotno, appt, FALSE);
  408. }
  409.  
  410. /* draw in todays appointments */
  411. draw_day_appts()
  412. {
  413.     int slotno = 0;
  414.  
  415.     while (slotno < N_SLOTS) {
  416.         if (slots[slotno].count > 0) {
  417.             switch (slots[slotno].active) {
  418.                 case ACTIVE:
  419.                     rewrite_string(slotno, JUSTIFY_LEFT);
  420.                     break;
  421.                 case ARROW_SHAFT:
  422.                     draw_arrowshaft(slotno);
  423.                     break;
  424.                 case ARROW_HEAD:
  425.                     draw_arrowhead(slotno);
  426.                     break;
  427.                 case INACTIVE:
  428.                     break;
  429.             }
  430.             more_check(slotno);
  431.         }
  432.         ++slotno;
  433.     }
  434. }
  435.  
  436. /* Blacks out day-slot and then re-writes string. */
  437. rewrite_string(bi, justify)
  438. int bi, justify;  
  439. {
  440.     char slot_str[MAX_STRLEN];
  441.     char *ptr;
  442.     int strl, *iptr;
  443.  
  444.     strl = strlen(slots[bi].cur_appt->str);
  445.     iptr = &slots[bi].cur_appt->sindex;
  446.     if (strl < day_message_size) {
  447.         *iptr = 0; /* just in case */
  448.         strcpy(slot_str, slots[bi].cur_appt->str);
  449.         /* erase any previously existing scroll arrows */
  450.         pw_writebackground(main_pixwin, slots[bi].larrow_pos.left,
  451.             slots[bi].larrow_pos.top, slots[bi].rarrow_pos.right-slots[bi].larrow_pos.left,
  452.             slots[bi].larrow_pos.bottom-slots[bi].larrow_pos.top,
  453.             PIX_CLR);
  454.     } else {
  455.         if (justify == JUSTIFY_RIGHT) {
  456.             /* show trailing part */
  457.             ptr = &slots[bi].cur_appt->str[strl - day_message_size + 1];
  458.             *iptr = strl - day_message_size + 1;
  459.             strcpy(slot_str, ptr);
  460.         } else {
  461.             /* show leading or indexed part */
  462.             if (justify == JUSTIFY_LEFT)
  463.                 *iptr = 0;
  464.             if (*iptr > (strl - day_message_size + 1))
  465.                 *iptr = strl - day_message_size + 1;
  466.             if (strlen(&slots[bi].cur_appt->str[*iptr]) >= day_message_size-1) {
  467.                 strncpy(slot_str, &slots[bi].cur_appt->str[*iptr], day_message_size-1);
  468.                 slot_str[day_message_size-1] = '\0';
  469.             } else
  470.                 strcpy(slot_str, &slots[bi].cur_appt->str[*iptr]);
  471.         }
  472.         /* display scroll arrows */
  473.         pw_write(main_pixwin, slots[bi].larrow_pos.left,
  474.             slots[bi].larrow_pos.top, leftarrow->pr_size.x,
  475.             leftarrow->pr_size.y, PIX_SRC, leftarrow, 0, 0);
  476.         pw_write(main_pixwin, slots[bi].rarrow_pos.left,
  477.             slots[bi].rarrow_pos.top, rightarrow->pr_size.x,
  478.             rightarrow->pr_size.y, PIX_SRC, rightarrow, 0, 0);
  479.     }
  480.         pw_write(main_pixwin, slots[bi].slot_pos.left+1, slots[bi].slot_pos.top+1,
  481.                 dayslot_width-2, dayslot_height-2, PIX_SET, NULL, 0, 0);
  482.         pw_text(main_pixwin, slots[bi].slot_pos.left+5, slots[bi].slot_pos.top+font->pf_defaultsize.y,
  483.                 PIX_NOT(PIX_SRC), font, slot_str);
  484. }
  485.  
  486. /* display "more" button if necessary */
  487. more_check(slotno)
  488. int slotno;
  489. {
  490.     int x, y, w;
  491.  
  492.     x = morebutton->pr_size.x;
  493.     y = morebutton->pr_size.y;
  494.  
  495.     /* clear any previous button that may be there */
  496.     pw_write(main_pixwin, slots[slotno].moreb_pos.left, slots[slotno].moreb_pos.top,
  497.         x, y, PIX_CLR, NULL, 0, 0);
  498.     /* button displayed when more than 1 reference
  499.      * and at least one real appt for this slot.
  500.      */
  501.     if (slots[slotno].count > 1 && slots[slotno].first)
  502.         /* display more button to right of slot */
  503.         pw_write(main_pixwin, slots[slotno].moreb_pos.left, slots[slotno].moreb_pos.top,
  504.             x, y, PIX_SRC, morebutton, 0, 0);
  505. }
  506.  
  507. draw_arrowshaft(i)
  508. int i;
  509. {
  510.     pw_rop(main_pixwin, slots[i].slot_pos.left+1, slots[i].slot_pos.top+1,
  511.       dayslot_width-2, dayslot_height-2, PIX_SRC|PIX_DST, arrowshaft_pr, 0, 0);
  512.     slots[i].active = ARROW_SHAFT;
  513. }
  514.  
  515.  
  516.  
  517. draw_arrowhead(i)
  518. int i;
  519. {
  520.         pw_rop(main_pixwin, slots[i].slot_pos.left+1, slots[i].slot_pos.top+1,
  521.           dayslot_width-2, dayslot_height-2, PIX_SRC|PIX_DST, arrowhead_pr, 0, 0);
  522.         slots[i].active = ARROW_HEAD;
  523. }
  524.  
  525. /*
  526.  * Routine to create popup window with future appts shown in it
  527.  */
  528. draw_future_appts()
  529. {
  530.     if (show_future && findex && (ymd_compare(current, today) == 0)) {
  531.         create_future_popup();
  532.     } else {
  533.         /* nothing to show */
  534.         /* destroy future appts popup, if it exists */
  535.         if (fframe) {
  536.             window_destroy(fframe);
  537.             fframe = 0;
  538.         }
  539.     }
  540. }
  541.  
  542. /*
  543.  * Add an appointment entry pointed to by aptr to the day slot
  544.  * specified by slotno. This routine is also used by paste()
  545.  * when copying an entry off the save shelf. If dpyflag is true,
  546.  * then any deactivated slots are cleared on the display (used by
  547.  * paste). Also used to add a deleted entry for a specific day.
  548.  */
  549. add_to_slot(slotno, aptr, dpyflag)
  550. int slotno;
  551. struct appt_entry *aptr;
  552. int dpyflag;
  553. {
  554.     struct appt_entry *nappt, *optr;
  555.     int n_arrows, n, nbi, found = 0, i;
  556.     int deactivate_lower_arrows();
  557.  
  558.     if ((nappt = (struct appt_entry *)malloc(sizeof(struct appt_entry))) == NULL)
  559.         err_rpt("out of memory", FATAL);
  560.     if (aptr == NULL) {
  561.         /* fill in some needed fields */
  562.         nappt->arrows = nappt->flags = 0;
  563.         nappt->sindex = 0;
  564.         nappt->str[0] = '\0';
  565.     } else
  566.         *nappt = *aptr;
  567.     nappt->next = NULL;
  568.     /* add appt to list of appts for this slot */
  569.     if (slots[slotno].first == NULL) {
  570.         slots[slotno].first = nappt;
  571.         slots[slotno].cur_appt = nappt;
  572.     } else {
  573.         /* search for end of list */
  574.         for (optr=slots[slotno].first;optr->next;optr=optr->next)
  575.             ;
  576.         optr->next = nappt;
  577.     }
  578.     /* make sure it doesn't extend too far and truncate if neccessary */
  579.     if (slotno >= n_tslots)
  580.         nappt->arrows = 0;    /* force notes to have no arrows */
  581.     else if ((slotno + nappt->arrows) >= n_tslots)
  582.         nappt->arrows = n_tslots - slotno - 1;    /* truncate */
  583.     n_arrows = nappt->arrows;
  584.     if (nappt->flags & DELETED) {
  585.         /* look for matching non-deleted appt in list */
  586.         for (optr=slots[slotno].first;optr;optr=optr->next)
  587.             if (!strcmp(nappt->str, optr->str) && !(optr->flags & DELETED)) {
  588.                 found = 1;
  589.                 break;
  590.             }
  591.         if (found && slots[slotno].cur_appt == optr) {
  592.             /* the deleted appt is the current one */
  593.             /* if it's active, undisplay it and display
  594.              * next one in list (if any)
  595.              */
  596.             if (slots[slotno].active == ACTIVE) {
  597.                 if (slots[slotno].count > 1)
  598.                     /* there's another one here */
  599.                     next_appt(slotno, dpyflag);
  600.                 else {
  601.                     deactivate_slot(slotno, dpyflag);
  602.                     if (slots[slotno].cur_appt->arrows > 0)
  603.                         (void)deactivate_lower_arrows(slotno, dpyflag);
  604.                 }
  605.                 /* adjust reference counts */
  606.                 slots[slotno].count--;
  607.                 i = 1;
  608.                 while (i <= n_arrows) {
  609.                     if (--(slots[slotno+i].count) > 0)
  610.                         /* try to activate any hidden ones */
  611.                         (void)activate_slot(slotno+i, dpyflag);
  612.                     ++i;
  613.                 }
  614.             } else {
  615.                 /* currently inactive */
  616.                 /* set current to next one in the list */
  617.                 if (optr->next)
  618.                     slots[slotno].cur_appt = optr->next;
  619.                 else
  620.                     slots[slotno].cur_appt = slots[slotno].first;
  621.                 while (n_arrows >= 0)
  622.                     slots[slotno+(n_arrows--)].count--;
  623.             }
  624.         } else {
  625.             /* just adjust the counts */
  626.             while (n_arrows >= 0)
  627.                 slots[slotno+(n_arrows--)].count--;
  628.         }
  629.     } else {
  630.         /* look for matching deleted appt in list */
  631.         for (optr=slots[slotno].first;optr;optr=optr->next)
  632.             if (!strcmp(nappt->str, optr->str) && optr->flags & DELETED) {
  633.                 found = 1;
  634.                 break;
  635.             }
  636.         if (found) {
  637.             /* just adjust reference counts and return */
  638.             while (n_arrows >= 0)
  639.                 slots[slotno+(n_arrows--)].count++;
  640.             return;
  641.         }
  642.         /*
  643.          * Make sure there are no overlaps with the appt we
  644.          * are adding. If there are, hide the overlapping appt.
  645.          */
  646.         nbi = slotno;
  647.         do {
  648.             if (slots[nbi].active == ACTIVE) {
  649.                 deactivate_slot(nbi, dpyflag);
  650.                 if (slots[nbi].cur_appt->arrows > 0)
  651.                     nbi = deactivate_lower_arrows(nbi, dpyflag);
  652.             } else if (slots[nbi].active != INACTIVE)
  653.                 nbi = deactivate_lower_arrows(nbi, dpyflag);
  654.             while (++nbi <= slotno+n_arrows)
  655.                 if (slots[nbi].active == ACTIVE)
  656.                     break;
  657.         } while (nbi <= slotno + n_arrows);
  658.         /* set current one to the new one */
  659.         slots[slotno].cur_appt = nappt;
  660.         /* now go back and put in the info for the appt we're inserting */
  661.         slots[slotno].active = ACTIVE;
  662.         slots[slotno].count++;
  663.         if (n_arrows > 0) {
  664.             slots[slotno+n_arrows].count++;
  665.             slots[slotno+n_arrows].active = ARROW_HEAD;
  666.             while (--n_arrows > 0) {
  667.                 slots[slotno+n_arrows].count++;
  668.                 slots[slotno+n_arrows].active = ARROW_SHAFT;
  669.             }
  670.         }
  671.     }
  672.     if (dpyflag)
  673.         draw_day_appts();    /* redraw display */
  674. }
  675.  
  676.  
  677. #ifndef NO_SUN_MOON
  678. /*
  679.  * write sun data to the popup canvas
  680.  */
  681. write_sun_data()
  682. {
  683.     int    x, y, height;
  684.     char    buf[64];
  685.     Pixwin    *spixwin;
  686.     Rect    *rect;
  687.     struct    timeval tp;
  688.     double    jdays, secs, offset;
  689.     double    julian_day();
  690.  
  691.     /* first erase the window. */
  692.     spixwin = (Pixwin *)canvas_pixwin(scanvas);
  693.     rect = (Rect *) window_get(scanvas, WIN_RECT);
  694.         pw_writebackground(spixwin, 0, 0,
  695.       rect->r_width, rect->r_height, PIX_CLR);
  696.  
  697.     x = font->pf_defaultsize.x;
  698.     height = y = font->pf_defaultsize.y;
  699.  
  700.     gettimeofday(&tp, 0);
  701.     if (ymd_compare(current, today) == 0) {
  702.         /* use current time */
  703.         write_times();
  704.         panel_set(sdate_pi, PANEL_LABEL_STRING, riseset_buf[B_DMY], 0);
  705.         y += 11 * height;
  706.     } else {
  707.         /* convert today's date to approx. seconds from 1-1-1970 */
  708.         jdays = julian_day((double)today.tm_mday, today.tm_mon+1, today.tm_year+1900) - J1970;
  709.         /* seconds from 00:00 GMT to now */
  710.         offset = tp.tv_sec - (jdays * 24. * 3600.);
  711.         /* convert this date to approx. seconds from 1-1-1970 */
  712.         jdays = julian_day((double)current.tm_mday, current.tm_mon+1, current.tm_year+1900) - J1970;
  713.         /* seconds to the same time on selected day */
  714.         secs = (jdays * 24.0 * 3600.) + offset;
  715.         riseset((long)secs);
  716.         panel_set(sdate_pi, PANEL_LABEL_STRING, riseset_buf[B_DMY], 0);
  717.         pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_JLD]);
  718.         y += height;
  719.     }
  720.     sprintf(buf, "Sun Rise    (today): %s", riseset_buf[B_SRD]);
  721.     pw_text(spixwin, x, y, PIX_SRC, font, buf);
  722.     y += height;
  723.     sprintf(buf, "Sun Set     (today): %s", riseset_buf[B_SSD]);
  724.     pw_text(spixwin, x, y, PIX_SRC, font, buf);
  725.     y += height;
  726.     sprintf(buf, "Sun Rise (tomorrow): %s", riseset_buf[B_SRT]);
  727.     pw_text(spixwin, x, y, PIX_SRC, font, buf);
  728.     y += height;
  729.     sprintf(buf, "Sun Set  (tomorrow): %s", riseset_buf[B_SST]);
  730.     pw_text(spixwin, x, y, PIX_SRC, font, buf);
  731. }
  732.  
  733. /*
  734.  * write sun time data to the popup canvas
  735.  */
  736. write_times()
  737. {
  738.     int    x, y, height;
  739.     Pixwin    *spixwin;
  740.     struct    timeval tp;
  741.  
  742.     /* only update these if displaying today's page */
  743.     if (ymd_compare(current, today) != 0)
  744.         return;
  745.  
  746.     spixwin = (Pixwin *)canvas_pixwin(scanvas);
  747.  
  748.     x = font->pf_defaultsize.x;
  749.     y = height = font->pf_defaultsize.y;
  750.  
  751.     gettimeofday(&tp, 0);
  752.     riseset(tp.tv_sec);
  753.     pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_GMT]);
  754.     y += height;
  755.     pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_TDT]);
  756.     y += height;
  757.     pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_LCT]);
  758.     y += height;
  759.     pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_LMT]);
  760.     y += height;
  761.     pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_GST]);
  762.     y += height;
  763.     pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_LST]);
  764.     y += height;
  765.     pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_JLD]);
  766.     y += height;
  767.     pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_LHA]);
  768.     y += height;
  769.     pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_SDE]);
  770.     y += height;
  771.     pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_SAZ]);
  772.     y += height;
  773.     pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_SEL]);
  774. }
  775.  
  776. /*
  777.  * write moon data to the popup canvas
  778.  */
  779. write_moon_data()
  780. {
  781.     int    x, y, height;
  782.     char    buf[64];
  783.     Pixwin    *mpixwin;
  784.     Rect    *rect;
  785.     struct    timeval tp;
  786.     double    jdays, secs, offset;
  787.     double    julian_day();
  788.  
  789.     /* first erase the window. */
  790.     mpixwin = (Pixwin *)canvas_pixwin(mcanvas);
  791.     rect = (Rect *) window_get(mcanvas, WIN_RECT);
  792.         pw_writebackground(mpixwin, 0, 0,
  793.       rect->r_width, rect->r_height, PIX_CLR);
  794.  
  795.     x = font->pf_defaultsize.x;
  796.     y = height = font->pf_defaultsize.y;
  797.  
  798.     gettimeofday(&tp, 0);
  799.     if (ymd_compare(current, today) == 0) {
  800.         /* use current time */
  801.         riseset(tp.tv_sec);
  802.         moon_data(tp.tv_sec);
  803.     } else {
  804.         /* convert today's date to approx. seconds from 1-1-1970 */
  805.         jdays = julian_day((double)today.tm_mday, today.tm_mon+1, today.tm_year+1900) - J1970;
  806.         /* seconds from 00:00 GMT to now */
  807.         offset = tp.tv_sec - (jdays * 24. * 3600.);
  808.         /* convert this date to seconds from 1-1-1970 */
  809.         jdays = julian_day((double)current.tm_mday, current.tm_mon+1, current.tm_year+1900) - J1970;
  810.         /* seconds to the same time on selected day */
  811.         secs = (jdays * 24.0 * 3600.) + offset;
  812.         riseset((long)secs);
  813.         moon_data((long)secs);
  814.     }
  815.     panel_set(mdate_pi, PANEL_LABEL_STRING, riseset_buf[B_DMY], 0);
  816.     y = 6 * height;
  817.     sprintf(buf, "Moon Rise    (today): %s", riseset_buf[B_MRD]);
  818.     pw_text(mpixwin, x, y, PIX_SRC, font, buf);
  819.     y += height;
  820.     sprintf(buf, "Moon Set     (today): %s", riseset_buf[B_MSD]);
  821.     pw_text(mpixwin, x, y, PIX_SRC, font, buf);
  822.     y += height;
  823.     sprintf(buf, "Moon Rise (tomorrow): %s", riseset_buf[B_MRT]);
  824.     pw_text(mpixwin, x, y, PIX_SRC, font, buf);
  825.     y += height;
  826.     sprintf(buf, "Moon Set  (tomorrow): %s", riseset_buf[B_MST]);
  827.     pw_text(mpixwin, x, y, PIX_SRC, font, buf);
  828. }
  829. #endif    /* NO_SUN_MOON */
  830.