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

  1. /*
  2.  * $Header: devent.c,v 2.1 89/05/09 14:18:59 billr Exp $
  3.  */
  4. /*
  5.  * devent.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.  *      Day event routines for main subwindow.        *
  27.  *                            *
  28.  ********************************************************/
  29.  
  30.  
  31. #include <stdio.h>
  32. #include <suntool/sunview.h>
  33. #include <suntool/canvas.h>
  34. #include <suntool/panel.h>
  35. #include <suntool/menu.h>
  36. #include <sys/time.h>
  37. #include <fcntl.h>
  38. #include "ct.h"
  39. #include "event.h"
  40.  
  41. extern Menu day_sel_menu;
  42. extern Frame attr_frame;
  43. extern Panel_item everyx_pi, repeat_pi, remind_pi;
  44. extern Panel_item whichwk_pi, marked_pi;
  45. extern Panel_item del_choice_pi;
  46. extern Frame del_frame;
  47. extern Panel del_panel;
  48. extern Pixrect tri_right_pr, tri_up_pr;
  49. extern Pixrect *leftarrow, *rightarrow, *morebutton;
  50. extern int n_tslots;
  51. int attr_bi;
  52. struct appt_entry shelf_appt = {0};
  53. int old_slot = -1;    /* for text cursor location */
  54.  
  55. day_inputevent(canvas, event)
  56. Canvas canvas;
  57. Event *event;
  58. {
  59.     Menu_item an_item;
  60.     int box_index, x, y, found_flag;
  61.     int i, j, active_above, strl;
  62.     struct appt_entry *aptr;
  63.     static int start_arrow_box = -1, prev_box = 0;
  64.     static int expecting = 0;
  65.  
  66.         found_flag = 0;                    /* See if cursor is in a box. */
  67.     /* translate coordinates back to pixwin space */
  68.     event = canvas_window_event(canvas, event);
  69.         x = event_x(event);
  70.         y = event_y(event);
  71.     /*fix_event(canvas, event);    /* check for LOC_RGNENTER */
  72.     if (event_id(event) == LOC_RGNEXIT && old_slot >= 0) {
  73.         /* erase text cursor */
  74.         text_cursor(old_slot);
  75.         old_slot = -1;
  76.     }
  77.  
  78.         for (box_index=0; box_index<N_SLOTS; box_index++) {
  79.         /* is cursor inside a slot ? */
  80.                 if (x>=slots[box_index].slot_pos.left && x<=slots[box_index].slot_pos.right &&
  81.                     y>=slots[box_index].slot_pos.top && y<=slots[box_index].slot_pos.bottom) {
  82.                         found_flag = FOUND_SLOT;
  83.                         break;
  84.                 }
  85.         /* is cursor inside a "more" button ? */
  86.                 if (x>=slots[box_index].moreb_pos.left && x<=slots[box_index].moreb_pos.right &&
  87.                     y>=slots[box_index].moreb_pos.top && y<=slots[box_index].moreb_pos.bottom) {
  88.             if (slots[box_index].count > 1) {
  89.                 /* "more" button is active */
  90.                 found_flag = FOUND_MORE;
  91.                 break;
  92.             }
  93.         }
  94.         /* is cursor inside a "leftarrow" button ? */
  95.                 if (x>=slots[box_index].larrow_pos.left && x<=slots[box_index].larrow_pos.right &&
  96.                     y>=slots[box_index].larrow_pos.top && y<=slots[box_index].larrow_pos.bottom) {
  97.             found_flag = FOUND_LARROW;
  98.             break;
  99.         }
  100.         /* is cursor inside a "rightarrow" button ? */
  101.                 if (x>=slots[box_index].rarrow_pos.left && x<=slots[box_index].rarrow_pos.right &&
  102.                     y>=slots[box_index].rarrow_pos.top && y<=slots[box_index].rarrow_pos.bottom) {
  103.             found_flag = FOUND_RARROW;
  104.             break;
  105.         }
  106.     }
  107.     if (old_slot >= 0) {
  108.         /* erase text cursor at old location */
  109.         text_cursor(old_slot);
  110.         old_slot = -1;
  111.     }
  112.  
  113.         if (!found_flag && !expecting)
  114.                 return(0);        /* Not in a box => ignore. */
  115.  
  116.     if (event_id(event) == LOC_STILL || (event_is_button(event) && event_is_up(event))) {
  117.         if (found_flag == FOUND_SLOT && box_index != old_slot)
  118.             /* in a different slot than we were before */
  119.             if (slots[box_index].active == ACTIVE)
  120.                 /* display cursor at new location */
  121.                 text_cursor(box_index);
  122.     }
  123.         if (found_flag == FOUND_SLOT && event_id(event) <= ASCII_LAST) {
  124.         /* Process a kbd event. */
  125.                 if (slots[box_index].active != ACTIVE)
  126.                         return(0);
  127.         if (event_id(event) == CTRL_R) {
  128.                         rewrite_string(box_index, JUSTIFY_LEFT);
  129.                         return(0);
  130.         }
  131.         new_entry = 1;    /* flag for file updating */
  132.         strl = strlen(slots[box_index].cur_appt->str);
  133.                 if (event_id(event) == CTRL_U) {
  134.                         slots[box_index].cur_appt->str[0] = '\0';
  135.                         rewrite_string(box_index, JUSTIFY_LEFT);
  136.                 } else if (event_id(event) == CTRL_W) {
  137.                         while (strl > 0 && slots[box_index].cur_appt->str[strl-1] != ' ') {
  138.                                 slots[box_index].cur_appt->str[strl-1] = '\0';
  139.                 strl--;
  140.                         }
  141.             rewrite_string(box_index, JUSTIFY_RIGHT);
  142.                 } else if (event_id(event) == DEL || event_id(event) == BACKSPACE) {
  143.             if (strl > 0) {
  144.                                 slots[box_index].cur_appt->str[strl-1] = '\0';
  145.                                 rewrite_string(box_index, JUSTIFY_RIGHT);
  146.                         }
  147.                 } else if (event_id(event) >= (int)' ' && strl < MAX_STRLEN-2) {
  148.                         slots[box_index].cur_appt->str[strl] = (char)event_id(event);
  149.             slots[box_index].cur_appt->str[strl+1] = '\0';
  150.                         rewrite_string(box_index, JUSTIFY_RIGHT);
  151.                 }
  152.         /* display cursor at new location */
  153.         text_cursor(box_index);
  154.     } else if (event_id(event) == MS_LEFT && event_is_down(event)) {
  155.         /* LB down event */
  156.         switch (found_flag) {
  157.             case FOUND_SLOT:
  158.                 break;
  159.             case FOUND_MORE:
  160.                 /* reverse video "more" button */
  161.                 pw_rop(main_pixwin, slots[box_index].moreb_pos.left, slots[box_index].moreb_pos.top,
  162.                     morebutton->pr_width, morebutton->pr_height, PIX_NOT(PIX_DST),
  163.                     morebutton, 0, 0);
  164.                 expecting = box_index + (FOUND_MORE<<8);
  165.                 break;
  166.             case FOUND_LARROW:
  167.                 do_left_arrow(canvas, box_index);
  168.                 break;
  169.             case FOUND_RARROW:
  170.                 do_right_arrow(canvas, box_index);
  171.                 break;
  172.         }
  173.     } else if (event_id(event) == MS_LEFT && event_is_up(event)) {
  174.         /* Process an LB up click. */
  175.         i = expecting>>8;
  176.         if (expecting && found_flag != i) {
  177.             /* return button to normal video */
  178.             if (i == FOUND_MORE) {
  179.                 /* "more" button */
  180.                 i = expecting & 0xff;
  181.                 pw_rop(main_pixwin, slots[i].moreb_pos.left, slots[i].moreb_pos.top,
  182.                     morebutton->pr_width, morebutton->pr_height, PIX_SRC,
  183.                     morebutton, 0, 0);
  184.             }
  185.         } else {
  186.             switch (found_flag) {
  187.                 case FOUND_SLOT:
  188.                     make_box_active(box_index);
  189.                     new_entry = 1;
  190.                     break;
  191.                 case FOUND_MORE:
  192.                     next_appt(box_index, TRUE);
  193.                     /* normal video "more" button */
  194.                     pw_rop(main_pixwin, slots[box_index].moreb_pos.left, slots[box_index].moreb_pos.top,
  195.                         morebutton->pr_width, morebutton->pr_height, PIX_SRC,
  196.                         morebutton, 0, 0);
  197.                     break;
  198.                 case FOUND_LARROW:
  199.                     break;
  200.                 case FOUND_RARROW:
  201.                     break;
  202.             }
  203.         }
  204.         expecting = 0;
  205.         } else if (found_flag == FOUND_SLOT && event_id(event) == MS_MIDDLE) {
  206.         /* Process a MB click. */
  207.         if (box_index >= n_tslots)
  208.             /* don't flow into notes section */
  209.             box_index = n_tslots - 1;
  210.         if (event_is_down(event)) {
  211.             /* try to start dragging from here */
  212.             if (slots[box_index].active != ACTIVE) {
  213.                 start_arrow_box = -1;
  214.                 return(0);
  215.             }
  216.             if (slots[box_index].cur_appt->arrows > 0) {
  217.                 /* remove old arrows and adjust counts */
  218.                 (void)deactivate_lower_arrows(box_index);
  219.                 j = slots[box_index].cur_appt->arrows;
  220.                 while (j > 0)
  221.                     slots[box_index+(j--)].count--;
  222.                 slots[box_index].cur_appt->arrows = 0;
  223.             }
  224.             prev_box = start_arrow_box = box_index;
  225.         } else {
  226.             /* end of dragging => end of arrow */
  227.             if (box_index < start_arrow_box || start_arrow_box == -1) {
  228.                 start_arrow_box = -1;
  229.                 return(0);
  230.             }
  231.             if (box_index > start_arrow_box) {
  232.                 i = start_arrow_box;
  233.                 slots[i].cur_appt->arrows = box_index - start_arrow_box;
  234.                 while (++i < box_index) {
  235.                     slots[i].count++;
  236.                     if (slots[i].active == INACTIVE)
  237.                         slots[i].active = ARROW_SHAFT;
  238.                     /*
  239.                      * erase arrow shaft on boxes - it will be
  240.                      * replaced by a real arrowshaft during redraw
  241.                      */
  242.                     pw_rop(main_pixwin, slots[i].slot_pos.left+1,
  243.                         slots[i].slot_pos.top+1,
  244.                         dayslot_width-2, dayslot_height-2,
  245.                         PIX_SRC^PIX_DST, arrowshaft_pr,
  246.                         0, 0);
  247.                 }
  248.                 slots[i].count++;
  249.                 if (slots[i].active == INACTIVE)
  250.                     slots[i].active = ARROW_HEAD;
  251.                 /*
  252.                  * erase arrow shaft on last box - it will be
  253.                  * replaced by an arrowhead during redraw
  254.                  */
  255.                 pw_rop(main_pixwin, slots[i].slot_pos.left+1,
  256.                     slots[i].slot_pos.top+1,
  257.                     dayslot_width-2, dayslot_height-2,
  258.                     PIX_SRC^PIX_DST, arrowshaft_pr,
  259.                     0, 0);
  260.             }
  261.             start_arrow_box = -1;
  262.             new_entry = 1;
  263.             draw_day_appts();
  264.         }
  265.     } else if (found_flag == FOUND_SLOT && event_id(event) == LOC_DRAG) {
  266.         /* mouse dragging - is it the middle button ? */
  267.         if ((int)window_get(canvas, WIN_EVENT_STATE, MS_MIDDLE) && start_arrow_box >= 0) {
  268.             if (box_index >= n_tslots)
  269.                 /* don't flow into notes section */
  270.                 box_index = n_tslots - 1;
  271.             /*
  272.              * xor arrow shaft thru current slot so
  273.              * we can see where we're dragging
  274.              */
  275.             if (box_index > prev_box) {
  276.                 while (++prev_box <= box_index) {
  277.                     pw_rop(main_pixwin, slots[prev_box].slot_pos.left+1,
  278.                         slots[prev_box].slot_pos.top+1,
  279.                         dayslot_width-2, dayslot_height-2,
  280.                         PIX_SRC^PIX_DST, arrowshaft_pr,
  281.                         0, 0);
  282.                 }
  283.                 prev_box = box_index;
  284.             } else if (box_index < prev_box && box_index >= start_arrow_box) {
  285.                 /* going backwards - cleanup as we go */
  286.                 while (prev_box > box_index) {
  287.                     pw_rop(main_pixwin, slots[prev_box].slot_pos.left+1,
  288.                         slots[prev_box].slot_pos.top+1,
  289.                         dayslot_width-2, dayslot_height-2,
  290.                         PIX_SRC^PIX_DST, arrowshaft_pr,
  291.                         0, 0);
  292.                     --prev_box;
  293.                 }
  294.             }
  295.         }
  296.     } else if (found_flag == FOUND_SLOT && event_id(event) == MS_RIGHT && event_is_down(event)) {
  297.         /* Process a RB click. */
  298.         /*
  299.          * display popup menu of choices, but first disable
  300.          * certain entries if this is a readonly appointment
  301.          * or an empty slot.
  302.          */
  303.         /* undelete - almost always inactive */
  304.         an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MUNDELETE);
  305.         menu_set(an_item, MENU_INACTIVE, TRUE, 0);
  306.         if (!slots[box_index].first) {
  307.             /* empty slot. only paste active */
  308.             paste_only();
  309.         } else if (slots[box_index].cur_appt->flags & READONLY) {
  310.             /* readonly => paste and copy only */
  311.             paste_only();
  312.             /* copy */
  313.             an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MCOPY);
  314.             menu_set(an_item, MENU_INACTIVE, FALSE, 0);
  315.         } else {
  316.             /* delete */
  317.             an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MDELETE);
  318.             menu_set(an_item, MENU_INACTIVE, FALSE, 0);
  319.             /* cut */
  320.             an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MCUT);
  321.             menu_set(an_item, MENU_INACTIVE, FALSE, 0);
  322.             /* copy */
  323.             an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MCOPY);
  324.             menu_set(an_item, MENU_INACTIVE, FALSE, 0);
  325.             /* modify */
  326.             an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MMODIFY);
  327.             menu_set(an_item, MENU_INACTIVE, FALSE, 0);
  328.             for (aptr=slots[box_index].first; aptr; aptr=aptr->next)
  329.                 if (aptr->flags & DELETED) {
  330.                     if (slots[box_index].active != ACTIVE)
  331.                         /* only paste and undelete */
  332.                         paste_only();
  333.                     /* undelete */
  334.                     an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MUNDELETE);
  335.                     menu_set(an_item, MENU_INACTIVE, FALSE, 0);
  336.                     break;
  337.                 }
  338.         }
  339.         i = (int) menu_show(day_sel_menu, canvas, event, 0);
  340.         if (i > 0)
  341.             switch (i) {
  342.                 case MDELETE:
  343.                     delete_appt(box_index, canvas);
  344.                     break;
  345.                 case MCUT:
  346.                     cut_appt(box_index, canvas);
  347.                     break;
  348.                 case MCOPY:
  349.                     copy_appt(box_index);
  350.                     break;
  351.                 case MPASTE:
  352.                     paste_appt(box_index);
  353.                     break;
  354.                 case MMODIFY:
  355.                     modify_appt(box_index, canvas);
  356.                     break;
  357.                 case MUNDELETE:
  358.                     undelete_appt(box_index);
  359.                     break;
  360.             }
  361.         if (new_entry) {
  362.             close_day();
  363.             draw_day();    /* redraw display */
  364.         }
  365.     } else
  366.         window_default_event_proc(canvas, event, 0);
  367.  
  368. }
  369.  
  370. /* make "paste" the only active menu entry */
  371. paste_only()
  372. {
  373.     Menu_item an_item;
  374.  
  375.     /* delete */
  376.     an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MDELETE);
  377.     menu_set(an_item, MENU_INACTIVE, TRUE, 0);
  378.     /* cut */
  379.     an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MCUT);
  380.     menu_set(an_item, MENU_INACTIVE, TRUE, 0);
  381.     /* copy */
  382.     an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MCOPY);
  383.     menu_set(an_item, MENU_INACTIVE, TRUE, 0);
  384.     /* modify */
  385.     an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MMODIFY);
  386.     menu_set(an_item, MENU_INACTIVE, TRUE, 0);
  387. }
  388.  
  389. /* draw (or erase) text cursor in a day slot */
  390. text_cursor(slotno)
  391. int slotno;
  392. {
  393.     int    strl, x;
  394.  
  395.     strl = strlen(&slots[slotno].cur_appt->str[slots[slotno].cur_appt->sindex]);
  396.     if (strl > (day_message_size-1)) {
  397.         pw_write(main_pixwin, slots[slotno].slot_pos.right, slots[slotno].slot_pos.bottom-4,
  398.           8, 8, PIX_SRC^PIX_DST, &tri_right_pr, 0, 0);
  399.     } else {
  400.         x = slots[slotno].slot_pos.left + strl * font->pf_defaultsize.x;
  401.         pw_write(main_pixwin, x, slots[slotno].slot_pos.bottom-4,
  402.           16, 16, PIX_SRC^PIX_DST, &tri_up_pr, 0, 0);
  403.     }
  404.     old_slot = slotno;
  405. }
  406.  
  407. /* make slot active */
  408. make_box_active(bi)
  409. int bi;
  410. {
  411.     add_to_slot(bi, NULL, TRUE);
  412.     fill_appt(bi);
  413.     rewrite_string(bi, JUSTIFY_LEFT);
  414.     text_cursor(bi);
  415. }
  416.  
  417. /* activate a hidden appt and make it visible */
  418. int
  419. activate_slot(bi, dpyflag)
  420. int bi;
  421. int dpyflag;
  422. {
  423.     int n, e_slot;
  424.  
  425.     if (slots[bi].count <= 0)
  426.         /* nothing to activate */
  427.         return(0);
  428.     if (slots[bi].cur_appt == NULL) {
  429.         /* may be hidden arrows */
  430.         /* find appt that they came from so we can see if
  431.          * it should be arrow shaft or arrow head
  432.          */
  433.         n = bi;
  434.         while (--n >= 0 && slots[n].active != ACTIVE)
  435.             ;
  436.         if (n >= 0) {
  437.             e_slot = n + slots[n].cur_appt->arrows;
  438.             if (e_slot < bi)
  439.                 /* no arrows here to show */
  440.                 return(0);
  441.             while (++n < e_slot && slots[n].active != ACTIVE)
  442.                 slots[n].active = ARROW_SHAFT;
  443.             if (slots[n].active != ACTIVE)
  444.                 slots[n].active = ARROW_HEAD;
  445.         } else
  446.             /* no active appt above */
  447.             return(0);
  448.     } else {
  449.         /* there's a real appt hidden */
  450.         slots[bi].active = ACTIVE;
  451.         if (slots[bi].cur_appt->arrows > 0) {
  452.             e_slot = bi + slots[bi].cur_appt->arrows;
  453.             while (++bi < e_slot && slots[bi].active != ACTIVE)
  454.                 slots[bi].active = ARROW_SHAFT;
  455.             if (slots[bi].active != ACTIVE)
  456.                 slots[bi].active = ARROW_HEAD;
  457.         }
  458.     }
  459.     if (dpyflag)
  460.         draw_day_appts();    /* redraw display */
  461.     return(1);
  462. }
  463.  
  464. /* clears a day slot */
  465. deactivate_slot(bi, dpyflag)
  466. int bi;
  467. {
  468.     slots[bi].active = INACTIVE;
  469.     if (!dpyflag)
  470.         return;
  471.     /* erase text cursor at old location */
  472.     if (old_slot >= 0) {
  473.         text_cursor(old_slot);
  474.         old_slot = -1;
  475.     }
  476.     /* erase displayed slot */
  477.     if (!ymd_compare(current, today))
  478.         pw_write(main_pixwin, slots[bi].slot_pos.left, slots[bi].slot_pos.top,
  479.           dayslot_width, dayslot_height, PIX_SRC, timeslot_td_pr, 0, 0);
  480.     else
  481.         pw_write(main_pixwin, slots[bi].slot_pos.left+1, slots[bi].slot_pos.top+1,
  482.           dayslot_width-2, dayslot_height-2, PIX_CLR, NULL, 0, 0);
  483. }
  484.  
  485. /* returns pointer to slot containing arrow head */
  486. int
  487. deactivate_lower_arrows(bi, dpyflag)
  488. int bi;
  489. {
  490.     while (bi < N_SLOTS-1) {
  491.         bi++;
  492.         if (slots[bi].active != ARROW_SHAFT &&
  493.             slots[bi].active != ARROW_HEAD)
  494.             return(bi-1);
  495.         slots[bi].active = INACTIVE;
  496.         if (!dpyflag)
  497.             continue;
  498.         /* erase displayed slot */
  499.         if (!ymd_compare(current, today))
  500.             pw_write(main_pixwin, slots[bi].slot_pos.left, slots[bi].slot_pos.top,
  501.               dayslot_width, dayslot_height, PIX_SRC, timeslot_td_pr, 0, 0);
  502.         else
  503.             pw_write(main_pixwin, slots[bi].slot_pos.left+1, slots[bi].slot_pos.top+1,
  504.               dayslot_width-2, dayslot_height-2, PIX_CLR, NULL, 0, 0);
  505.     }
  506. }
  507.  
  508. /* fill in appt struct with current info */
  509. fill_appt(bi)
  510. int bi;
  511. {
  512.     int s_hour, s_minute, n_arrows;
  513.  
  514.     slots[bi].cur_appt->year = current.tm_year;
  515.     slots[bi].cur_appt->month = current.tm_mon;
  516.     slots[bi].cur_appt->day = current.tm_mday;
  517.     slots[bi].cur_appt->arrows = 0;
  518.     slots[bi].cur_appt->flags = slots[bi].cur_appt->repeat = 0;
  519.     slots[bi].cur_appt->lookahead = slots[bi].cur_appt->sindex = 0;
  520.     if (bi >= n_tslots) {
  521.         /* notes section */
  522.         slots[bi].cur_appt->hour = 99;
  523.         slots[bi].cur_appt->minute = 0;
  524.         slots[bi].cur_appt->flags = A_NOTE;
  525.     } else {
  526.         /* regular appt */
  527.         slots[bi].cur_appt->hour = bi/2 + START_HOUR;
  528.         slots[bi].cur_appt->minute = (bi % 2) * 30;
  529.     }
  530.     slots[bi].cur_appt->str[0] = '\0';
  531. }
  532.  
  533. /*
  534.  * Display delete popup window to let user choose delete mode for
  535.  * recurring appts (delete this one only or delete all), otherwise,
  536.  * just wipe it out with no options.
  537.  */
  538. delete_appt(bi, canvas)
  539. int bi;
  540. Canvas canvas;
  541. {
  542.     Rect *canvas_r;
  543.     int top, left, width, height;
  544.  
  545.     if (slots[bi].cur_appt->flags & READONLY) {
  546.         err_rpt("Can't delete a read-only appt", NON_FATAL);
  547.         return;
  548.     }
  549.     if (slots[bi].cur_appt->flags & (REPEAT|ALL_YEARS|ALL_MONTHS|ALL_DAYS)) {
  550.         attr_bi = bi;    /* set global index for notify func */
  551.  
  552.         /* get x,y position of canvas window on the screen so we
  553.          * can center popup window in it.
  554.          */
  555.         canvas_r = (Rect *) window_get(canvas, WIN_RECT);
  556.         panel_set(del_choice_pi, PANEL_CHOICE_STRINGS,
  557.             "Delete this occurrance only",
  558.             "Delete all occurrances", 0,
  559.             PANEL_CLIENT_DATA, 0,
  560.             0);
  561.         window_fit(del_panel);
  562.         window_fit(del_frame);
  563.         width = (int) window_get(del_frame, WIN_WIDTH);
  564.         height = (int) window_get(del_frame, WIN_HEIGHT);
  565.         left =  canvas_r->r_left + (canvas_r->r_width - width) / 2;
  566.         top =  canvas_r->r_top + (canvas_r->r_height - height) / 2;
  567.         window_set(del_frame, WIN_X, left, WIN_Y, top, 0);
  568.         panel_set_value(del_choice_pi, 0);
  569.  
  570.         window_loop(del_frame);    /* let user select things */
  571.     } else {
  572.         cut_delete(bi);
  573.         new_entry = 1;
  574.     }
  575. }
  576.  
  577. cut_appt(bi, canvas)
  578. int bi;
  579. Canvas canvas;
  580. {
  581.     Rect *canvas_r;
  582.     int top, left, width, height;
  583.     int i;
  584.  
  585.     /* cut (delete) current entry, saving the info on the "shelf" */
  586.     if (slots[bi].cur_appt->flags & READONLY) {
  587.         err_rpt("Can't cut a read-only appt", NON_FATAL);
  588.         return;
  589.     }
  590.     shelf_appt = *slots[bi].cur_appt;
  591.     if (slots[bi].cur_appt->flags & (REPEAT|ALL_YEARS|ALL_MONTHS|ALL_DAYS)) {
  592.         attr_bi = bi;    /* set global index for notify func */
  593.  
  594.         /* get x,y position of canvas window on the screen so we
  595.          * can center popup window in it.
  596.          */
  597.         canvas_r = (Rect *) window_get(canvas, WIN_RECT);
  598.         panel_set(del_choice_pi, PANEL_CHOICE_STRINGS,
  599.             "Move this occurrance only",
  600.             "Move all occurrances", 0,
  601.             PANEL_CLIENT_DATA, 1,
  602.             0);
  603.         window_fit(del_panel);
  604.         window_fit(del_frame);
  605.         width = (int) window_get(del_frame, WIN_WIDTH);
  606.         height = (int) window_get(del_frame, WIN_HEIGHT);
  607.         left =  canvas_r->r_left + (canvas_r->r_width - width) / 2;
  608.         top =  canvas_r->r_top + (canvas_r->r_height - height) / 2;
  609.         window_set(del_frame, WIN_X, left, WIN_Y, top, 0);
  610.         panel_set_value(del_choice_pi, 0);
  611.  
  612.         window_loop(del_frame);    /* let user select things */
  613.     } else {
  614.         cut_delete(bi);
  615.         new_entry = 1;
  616.     }
  617. }
  618.  
  619. cut_delete(bi)
  620. int bi;
  621. {
  622.     int j;
  623.     struct appt_entry *aptr, *cptr, *optr;
  624.  
  625.     cptr = slots[bi].cur_appt;
  626.     slots[bi].count--;
  627.     deactivate_slot(bi, TRUE);
  628.     if ( (j = cptr->arrows) > 0) {
  629.         /* remove old arrows and adjust counts */
  630.         (void) deactivate_lower_arrows(bi, TRUE);
  631.         while (j > 0)
  632.             slots[bi+(j--)].count--;
  633.     }
  634.     if (slots[bi].cur_appt == slots[bi].first) {
  635.         /* displaying first entry in list */
  636.         /* see if there's any more */
  637.         if (slots[bi].first->next)
  638.             slots[bi].first = slots[bi].first->next;
  639.         else {
  640.             /* last one */
  641.             slots[bi].first = NULL;
  642.             slots[bi].active = INACTIVE;
  643.         }
  644.         slots[bi].cur_appt = slots[bi].first;
  645.     } else {
  646.         /* not first, so find previous one to this */
  647.         for (aptr=slots[bi].first; slots[bi].cur_appt!=aptr; optr=aptr,aptr=aptr->next)
  648.             ;
  649.         slots[bi].cur_appt = optr->next = aptr->next;
  650.         if (!optr->next)
  651.             slots[bi].cur_appt = slots[bi].first;
  652.     }
  653.     free(cptr);
  654.     (void)activate_slot(bi, TRUE);    /* show any hidden appts */
  655. }
  656.  
  657. copy_appt(bi)
  658. int bi;
  659. {
  660.     /* copy current entry, saving the info on the "shelf" */
  661.     shelf_appt = *slots[bi].cur_appt;
  662. }
  663.  
  664. paste_appt(bi)
  665. int bi;
  666. {
  667.     int j;
  668.  
  669.     /* insert the saved entry (if any) */
  670.     if (shelf_appt.str[0] == '\0') {
  671.         err_rpt("nothing to paste", NON_FATAL);
  672.         return;
  673.     }
  674.     shelf_appt.year = current.tm_year;
  675.     shelf_appt.month = current.tm_mon;
  676.     shelf_appt.day = current.tm_mday;
  677.     if (bi >= N_TSLOTS) {
  678.         /* notes section */
  679.         shelf_appt.hour = 99;
  680.         shelf_appt.minute = 0;
  681.         /* just in case converting from time to note */
  682.         shelf_appt.flags |= A_NOTE;
  683.     } else {
  684.         /* regular appt */
  685.         shelf_appt.hour = bi/2 + START_HOUR;
  686.         shelf_appt.minute = (bi % 2) * 30;
  687.         /* just in case converting from note to time */
  688.         shelf_appt.flags &= ~MARKED_NOTE;
  689.     }
  690.     add_to_slot(bi, &shelf_appt, TRUE);
  691.     new_entry = 1;
  692. }
  693.  
  694. /*
  695.  * Display attributes popup window to let user modify
  696.  * various appointment options (such as repeat interval,
  697.  * etc.)
  698.  */
  699. modify_appt(bi, canvas)
  700. int bi;
  701. Canvas canvas;
  702. {
  703.     Rect *canvas_r;
  704.     int top, left, width, height;
  705.  
  706.     if (slots[bi].cur_appt->flags & READONLY) {
  707.         err_rpt("Can't modify a read-only appt", NON_FATAL);
  708.         return;
  709.     }
  710.     attr_bi = bi;    /* set global index for notify func */
  711.     set_attr();    /* set panel item current values */
  712.  
  713.     /* get x,y position of canvas window on the screen so we
  714.      * can center this one in it.
  715.      */
  716.     canvas_r = (Rect *) window_get(canvas, WIN_RECT);
  717.     width = (int) window_get(attr_frame, WIN_WIDTH);
  718.     height = (int) window_get(attr_frame, WIN_HEIGHT);
  719.     left =  canvas_r->r_left + (canvas_r->r_width - width) / 2;
  720.     top =  canvas_r->r_top + (canvas_r->r_height - height) / 2;
  721.     window_set(attr_frame, WIN_X, left, WIN_Y, top, 0);
  722.  
  723.     window_loop(attr_frame);    /* let user select things */
  724.     window_set(attr_frame, WIN_SHOW, FALSE, 0);
  725. }
  726.  
  727. /* undelete a recurring appointment for this day */
  728. /* we only get here if a deleted appt exits */
  729. undelete_appt(bi)
  730. int bi;
  731. {
  732.     struct appt_entry *aptr, *optr;
  733.  
  734.     /* search list to find deleted entry */
  735.     for (optr=aptr=slots[bi].first; aptr; optr=aptr,aptr=aptr->next)
  736.         if (aptr->flags & DELETED)
  737.             break;
  738.     if (aptr == slots[bi].first)
  739.         slots[bi].first = aptr->next;
  740.     else
  741.         optr->next = aptr->next;
  742.     slots[bi].count++;
  743.     if (slots[bi].active == INACTIVE) {
  744.         slots[bi].cur_appt = slots[bi].first;
  745.         (void)activate_slot(bi, TRUE);
  746.     }
  747.     free(aptr);
  748.     new_entry = 1;
  749. }
  750.  
  751. set_attr()
  752. {
  753.     int everyx_val = 0, whichwk_val = 0;
  754.     char str[5];
  755.     struct appt_entry *apt = slots[attr_bi].cur_appt;
  756.  
  757.     panel_set_value(repeat_pi, "");    /* set default */
  758.     panel_set_value(remind_pi, "");    /* set default */
  759.     if (apt->flags & ALL_DAYS)
  760.         everyx_val |= 0x1;
  761.     if (apt->flags & ALL_MONTHS)
  762.         everyx_val |= 0x4;
  763.     if (apt->flags & ALL_YEARS)
  764.         everyx_val |= 0x8;
  765.     if (apt->flags & EVERY_SOMEDAY) {
  766.         everyx_val |= 0x2;
  767.         whichwk_val = apt->repeat;
  768.         panel_set(repeat_pi, PANEL_SHOW_ITEM, FALSE, 0);
  769.         panel_set(whichwk_pi, PANEL_SHOW_ITEM, TRUE, 0);
  770.     } else {
  771.         if (apt->repeat) {
  772.             sprintf(str, "%d", apt->repeat);
  773.             panel_set_value(repeat_pi, str);
  774.         }
  775.         panel_set(whichwk_pi, PANEL_SHOW_ITEM, FALSE, 0);
  776.         panel_set(repeat_pi, PANEL_SHOW_ITEM, TRUE, 0);
  777.     }
  778.     panel_set_value(everyx_pi, everyx_val);
  779.     panel_set_value(whichwk_pi, whichwk_val);
  780.     if (apt->flags & LOOKAHEAD) {
  781.         sprintf(str, "%d", apt->lookahead);
  782.         panel_set_value(remind_pi, str);
  783.     }
  784.     panel_set_value(marked_pi, (apt->flags & MARKED ? 1 : 0));
  785.     if (apt->flags & A_NOTE)
  786.         panel_set(marked_pi, PANEL_SHOW_ITEM, TRUE, 0);
  787.     else
  788.         panel_set(marked_pi, PANEL_SHOW_ITEM, FALSE, 0);
  789. }
  790.  
  791. /* "more" button selected. Display next appt in rotation. */
  792. next_appt(bi, dpyflag)
  793. int bi;
  794. int dpyflag;
  795. {
  796.     if (slots[bi].active == ACTIVE) {
  797.         deactivate_slot(bi, dpyflag);
  798.         if (slots[bi].cur_appt->arrows > 0)
  799.             (void)deactivate_lower_arrows(bi, dpyflag);
  800.     } else
  801.         /* must have arrows displayed */
  802.         (void)deactivate_lower_arrows(bi, dpyflag);
  803.  
  804.     if (slots[bi].cur_appt == NULL)
  805.         /* end of the chain */
  806.         slots[bi].cur_appt = slots[bi].first;
  807.     else
  808.         /* activate next in chain */
  809.         slots[bi].cur_appt = slots[bi].cur_appt->next;
  810.     /* make sure it is not a deleted one */
  811.     if (chk_deleted(bi))
  812.         next_appt(bi, dpyflag); /* try next in chain */
  813.     else if (!activate_slot(bi, dpyflag))
  814.         next_appt(bi, dpyflag); /* try next in chain */
  815. }
  816.  
  817. /* check to see if current is deleted */
  818. int
  819. chk_deleted(bi)
  820. int bi;
  821. {
  822.     int found = 0;
  823.     struct appt_entry *aptr;
  824.  
  825.     if (slots[bi].cur_appt == NULL)
  826.         return(0);
  827.     if (slots[bi].cur_appt->flags & DELETED)
  828.         return(1);
  829.     /* run through the list to see if there are any deleted */
  830.     for (aptr=slots[bi].first; aptr; aptr=aptr->next)
  831.         if (aptr->flags & DELETED) {
  832.             found = 1;
  833.             break;
  834.         }
  835.     /* now see if the current one matches */
  836.     if (found && !strcmp(aptr->str, slots[bi].cur_appt->str))
  837.         return(1);
  838.     
  839.     return(0);
  840. }
  841.  
  842. /* left scroll arrow selected */
  843. do_left_arrow(canvas, bi)
  844. Canvas canvas;
  845. int bi;
  846. {
  847.     struct timeval timeout;
  848.     Event event;
  849.     int fd, ertn, flags;
  850.  
  851.     if (slots[bi].active != ACTIVE || strlen(slots[bi].cur_appt->str) < day_message_size)
  852.         return;
  853.     timeout.tv_sec = 0L;
  854.     timeout.tv_usec = 100000L;    /* 1/10 sec */
  855.     fd = (int)window_get(canvas, WIN_FD);
  856.     flags = fcntl(fd, F_GETFL, 0);
  857.     (void)fcntl(fd, F_SETFL, flags|FNDELAY);
  858.     /* reverse video the arrow */
  859.     pw_rop(main_pixwin, slots[bi].larrow_pos.left, slots[bi].larrow_pos.top,
  860.         19, 14, PIX_NOT(PIX_DST), leftarrow, 0, 0);
  861.     while (TRUE) {
  862.         if (slots[bi].cur_appt->sindex < strlen(slots[bi].cur_appt->str)) {
  863.             ++slots[bi].cur_appt->sindex;
  864.             rewrite_string(bi, JUSTIFY_INDEX);
  865.             /* reverse video the arrow (rewrite changed it) */
  866.             pw_rop(main_pixwin, slots[bi].larrow_pos.left, slots[bi].larrow_pos.top,
  867.                 19, 14, PIX_NOT(PIX_DST), leftarrow, 0, 0);
  868.         }
  869.         /* do this garbage to handle a repeat function */
  870.         (void)select(0, NULL, NULL, NULL, &timeout);
  871.         ertn = window_read_event(canvas, &event);
  872.         if (ertn != -1 && event_is_up(&event))
  873.             break;
  874.     }
  875.     /* put arrow back to normal */
  876.     pw_rop(main_pixwin, slots[bi].larrow_pos.left, slots[bi].larrow_pos.top,
  877.         19, 14, PIX_SRC, leftarrow, 0, 0);
  878.     (void)fcntl(fd, F_SETFL, flags & ~FNDELAY);
  879. }
  880.  
  881. /* right scroll arrow selected */
  882. do_right_arrow(canvas, bi)
  883. Canvas canvas;
  884. int bi;
  885. {
  886.     struct timeval timeout;
  887.     Event event;
  888.     int fd, ertn, flags;
  889.  
  890.     if (slots[bi].active != ACTIVE || strlen(slots[bi].cur_appt->str) < day_message_size)
  891.         return;
  892.     timeout.tv_sec = 0L;
  893.     timeout.tv_usec = 100000L;    /* 1/10 sec */
  894.     fd = (int)window_get(canvas, WIN_FD);
  895.     flags = fcntl(fd, F_GETFL, 0);
  896.     (void)fcntl(fd, F_SETFL, flags|FNDELAY);
  897.     /* reverse video the arrow */
  898.     pw_rop(main_pixwin, slots[bi].rarrow_pos.left, slots[bi].rarrow_pos.top,
  899.         19, 14, PIX_NOT(PIX_DST), rightarrow, 0, 0);
  900.     while (TRUE) {
  901.         if (slots[bi].cur_appt->sindex > 0) {
  902.             --slots[bi].cur_appt->sindex;
  903.             rewrite_string(bi, JUSTIFY_INDEX);
  904.             /* reverse video the arrow (rewrite changed it) */
  905.             pw_rop(main_pixwin, slots[bi].rarrow_pos.left, slots[bi].rarrow_pos.top,
  906.                 19, 14, PIX_NOT(PIX_DST), rightarrow, 0, 0);
  907.         }
  908.         /* do this garbage to handle a repeat function */
  909.         (void)select(0, NULL, NULL, NULL, &timeout);
  910.         ertn = window_read_event(canvas, &event);
  911.         if (ertn != -1 && event_is_up(&event))
  912.             break;
  913.     }
  914.     pw_rop(main_pixwin, slots[bi].rarrow_pos.left, slots[bi].rarrow_pos.top,
  915.         19, 14, PIX_SRC, rightarrow, 0, 0);
  916.     (void)fcntl(fd, F_SETFL, flags & ~FNDELAY);
  917. }
  918.