home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume17 / calentool / part15 / devent.c next >
Encoding:
C/C++ Source or Header  |  1991-04-06  |  29.5 KB  |  1,038 lines

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