home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / program / prosrc / gemc13.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-10-05  |  14.0 KB  |  539 lines

  1. #include "portab.h"                /* portable coding conv    */
  2. #include "machine.h"                /* machine depndnt conv    */
  3. #include "obdefs.h"                /* object definitions    */
  4. #include "gembind.h"                /* gem binding structs    */
  5. #include "taddr.h"
  6.  
  7. #define    M1_ENTER    0x0000
  8. #define    M1_EXIT        0x0001
  9.  
  10. #define BS    0x0008
  11. #define    TAB    0x0009
  12. #define    CR    0x000D
  13. #define ESC    0x001B
  14. #define    BTAB    0x0f00
  15. #define    UP    0x4800
  16. #define    DOWN    0x5000
  17. #define    DEL    0x5300
  18.                     /* Global variables used by */
  19.                     /* 'mapped' functions        */
  20. MLOCAL    GRECT    br_rect;        /* Current break rectangle  */
  21. MLOCAL    WORD    br_mx, br_my, br_togl;    /* Break mouse posn & flag  */ 
  22. MLOCAL    WORD    fn_obj;            /* Found tabable object        */
  23. MLOCAL    WORD    fn_last;        /* Object tabbing from        */
  24. MLOCAL    WORD    fn_prev;        /* Last EDITABLE obj seen   */
  25. MLOCAL    WORD    fn_dir;            /* 1 = TAB, 0 = BACKTAB        */
  26.  
  27. /************* Utility routines for new forms manager ***************/
  28.  
  29.     VOID
  30. objc_toggle(tree, obj)            /* Reverse the SELECT state */
  31.     LONG    tree;            /* of an object, and redraw */
  32.     WORD    obj;            /* it immediately.        */
  33.     {
  34.     WORD    state, newstate;
  35.     GRECT    root, ob_rect;
  36.  
  37.     objc_xywh(tree, ROOT, &root);
  38.     state = LWGET(OB_STATE(obj));
  39.     newstate = state ^ SELECTED;
  40.     objc_change(tree, obj, 0, root.g_x, root.g_y, 
  41.         root.g_w, root.g_h, newstate, 1);
  42.     }
  43.  
  44.     VOID                /* If the object is not already */
  45. objc_sel(tree, obj)            /* SELECTED, make it so.    */
  46.     LONG    tree;
  47.     WORD    obj;
  48.     {
  49.     if ( !(LWGET(OB_STATE(obj)) & SELECTED) )
  50.         objc_toggle(tree, obj);
  51.     }
  52.  
  53.     VOID                /* If the object is SELECTED,    */
  54. objc_dsel(tree, obj)            /* deselect it.            */
  55.     LONG    tree;
  56.     WORD    obj;
  57.     {
  58.     if (LWGET(OB_STATE(obj)) & SELECTED)
  59.         objc_toggle(tree, obj);
  60.     }
  61.  
  62.     VOID                /* Return the object's GRECT      */
  63. objc_xywh(tree, obj, p)            /* through 'p'            */
  64.     LONG    tree;
  65.     WORD    obj;
  66.     GRECT    *p;
  67.     {
  68.     objc_offset(tree, obj, &p->g_x, &p->g_y);
  69.     p->g_w = LWGET(OB_WIDTH(obj));
  70.     p->g_h = LWGET(OB_HEIGHT(obj));
  71.     }
  72.  
  73.     VOID                /* Non-cursive traverse of an    */
  74. map_tree(tree, this, last, routine)    /* object tree.  This routine    */
  75.     LONG        tree;        /* is described in PRO GEM #5.    */
  76.     WORD        this, last;
  77.     WORD        (*routine)();
  78.     {
  79.     WORD        tmp1;
  80.  
  81.     tmp1 = this;        /* Initialize to impossible value: */
  82.                 /* TAIL won't point to self!       */
  83.                 /* Look until final node, or off   */
  84.                 /* the end of tree           */ 
  85.     while (this != last && this != NIL)
  86.                 /* Did we 'pop' into this node       */
  87.                 /* for the second time?           */
  88.         if (LWGET(OB_TAIL(this)) != tmp1)
  89.             {
  90.             tmp1 = this;    /* This is a new node       */
  91.             this = NIL;
  92.                     /* Apply operation, testing  */
  93.                     /* for rejection of sub-tree */
  94.             if ((*routine)(tree, tmp1))
  95.                 this = LWGET(OB_HEAD(tmp1));
  96.                     /* Subtree path not taken,   */
  97.                     /* so traverse right         */    
  98.             if (this == NIL)
  99.                 this = LWGET(OB_NEXT(tmp1));
  100.             }
  101.         else            /* Revisiting parent:          */
  102.                     /* No operation, move right  */
  103.             {
  104.             tmp1 = this;
  105.             this = LWGET(OB_NEXT(tmp1));
  106.             }
  107.     }
  108.  
  109.     WORD                /* Find the parent object of     */
  110. get_parent(tree, obj)            /* by traversing right until    */
  111.     LONG        tree;        /* we find nodes whose NEXT    */
  112.     WORD        obj;        /* and TAIL links point to     */
  113.     {                /* each other.            */
  114.     WORD        pobj;
  115.  
  116.     if (obj == NIL)
  117.         return (NIL);
  118.     pobj = LWGET(OB_NEXT(obj));
  119.     if (pobj != NIL)
  120.     {
  121.       while( LWGET(OB_TAIL(pobj)) != obj ) 
  122.       {
  123.         obj = pobj;
  124.         pobj = LWGET(OB_NEXT(obj));
  125.       }
  126.     }
  127.     return(pobj);
  128.     } 
  129.  
  130.     WORD
  131. inside(x, y, pt)        /* determine if x,y is in rectangle    */
  132.     WORD        x, y;
  133.     GRECT        *pt;
  134.     {
  135.     if ( (x >= pt->g_x) && (y >= pt->g_y) &&
  136.         (x < pt->g_x + pt->g_w) && (y < pt->g_y + pt->g_h) )
  137.         return(TRUE);
  138.     else
  139.         return(FALSE);
  140.     } 
  141.  
  142.     WORD
  143. rc_intersect(p1, p2)        /* compute intersection of two GRECTs    */
  144.     GRECT        *p1, *p2;
  145.     {
  146.     WORD        tx, ty, tw, th;
  147.  
  148.     tw = min(p2->g_x + p2->g_w, p1->g_x + p1->g_w);
  149.     th = min(p2->g_y + p2->g_h, p1->g_y + p1->g_h);
  150.     tx = max(p2->g_x, p1->g_x);
  151.     ty = max(p2->g_y, p1->g_y);
  152.     p2->g_x = tx;
  153.     p2->g_y = ty;
  154.     p2->g_w = tw - tx;
  155.     p2->g_h = th - ty;
  156.     return( (tw > tx) && (th > ty) );
  157.     }
  158.  
  159.     VOID
  160. rc_copy(psbox, pdbox)        /* copy source to destination rectangle    */
  161.     GRECT    *psbox;
  162.     GRECT    *pdbox;
  163.     {
  164.     pdbox->g_x = psbox->g_x;
  165.     pdbox->g_y = psbox->g_y;
  166.     pdbox->g_w = psbox->g_w;
  167.     pdbox->g_h = psbox->g_h;
  168.     }
  169.  
  170. /************* "Hot-spot" manager and subroutines  ***************/
  171.  
  172.     WORD
  173. break_x(pxy)
  174.     WORD    *pxy;
  175.     {                /* Breaking object is right of    */
  176.     if (br_mx < pxy[0])        /* mouse.  Reduce width of     */
  177.         {            /* bounding rectangle.        */
  178.         br_rect.g_w = pxy[0] - br_rect.g_x;
  179.         return (TRUE);
  180.         }
  181.     if (br_mx > pxy[2])        /* Object to left.  Reduce width*/
  182.         {            /* and move rect. to right    */
  183.         br_rect.g_w += br_rect.g_x - pxy[2] - 1;
  184.         br_rect.g_x = pxy[2] + 1;
  185.         return (TRUE);
  186.         }
  187.     return (FALSE);            /* Mouse within object segment.    */
  188.     }                /* Break attempt fails.        */
  189.  
  190.     WORD
  191. break_y(pxy)
  192.     WORD    *pxy;
  193.     {
  194.     if (br_my < pxy[1])        /* Object below mouse.  Reduce    */
  195.         {            /* height of bounding rect.    */
  196.         br_rect.g_h = pxy[1] - br_rect.g_y;
  197.         return (TRUE);
  198.         }
  199.     if (br_my > pxy[3])        /* Object above mouse.  Reduce    */
  200.         {            /* height and shift downward.    */
  201.         br_rect.g_h += br_rect.g_y - pxy[3] - 1;
  202.         br_rect.g_y = pxy[3] + 1;
  203.         return (TRUE); 
  204.         }
  205.     /* Emergency escape test! Protection vs. turkeys who nest */
  206.     /* non-selectable objects inside of selectables.          */
  207.     if (br_mx >= pxy[0] && br_mx <= pxy[1])
  208.         {                /* Will X break fail?      */
  209.         br_rect.g_x = br_mx;        /* If so, punt!          */
  210.         br_rect.g_y = br_my;
  211.         br_rect.g_w = br_rect.g_h = 1;
  212.         return (TRUE);
  213.         }
  214.     return (FALSE);
  215.     }
  216.  
  217.     WORD
  218. break_obj(tree, obj)            /* Called once per object to    */
  219.     LONG    tree;            /* check if the bounding rect.    */
  220.     WORD    obj;            /* needs to be modified.    */
  221.     {
  222.     GRECT    s;
  223.     WORD    flags, broken, pxy[4];
  224.  
  225.     objc_xywh(tree, obj, &s);
  226.     grect_to_array(&s, pxy);
  227.     if (!rc_intersect(&br_rect, &s))
  228.         return (FALSE);        /* Trivial rejection case     */
  229.  
  230.     flags = LWGET(OB_FLAGS(obj));    /* Is this object a potential    */
  231.     if (flags & HIDETREE)        /* hot-spot?                 */
  232.         return (FALSE);
  233.     if ( !(flags & SELECTABLE) )
  234.         return (TRUE);
  235.     if (LWGET(OB_STATE(obj)) & DISABLED)
  236.         return (TRUE);
  237.  
  238.     for (broken = FALSE; !broken; ) /* This could take two passes     */
  239.         {            /* if the first break fails.       */
  240.         if (br_togl)
  241.             broken = break_x(pxy);
  242.         else
  243.             broken = break_y(pxy);
  244.         br_togl = !br_togl;
  245.         }
  246.     return (TRUE);
  247.     }
  248.  
  249.     WORD                /* Manages mouse rectangle events */
  250. form_hot(tree, hot_obj, mx, my, rect, mode)
  251.     LONG    tree;
  252.     WORD    hot_obj, mx, my, *mode;
  253.     GRECT    *rect;
  254.     {
  255.     GRECT    root;
  256.     WORD    state;
  257.  
  258.     objc_xywh(tree, ROOT, &root);    /* If there is already a hot-spot */
  259.     if (hot_obj != NIL)        /* turn it off.              */
  260.         objc_toggle(tree, hot_obj);
  261.  
  262.     if (!(inside(mx, my, &root)) )    /* Mouse has moved outside of       */
  263.         {            /* the dialog.  Wait for return.  */
  264.         *mode = M1_ENTER;
  265.         rc_copy(&root, rect);
  266.         return (NIL);
  267.         }
  268.                     /* What object is mouse over?      */
  269.                     /* (Hit is guaranteed.)           */
  270.     hot_obj = objc_find(tree, ROOT, MAX_DEPTH, mx, my);
  271.                     /* Is this object a hot-spot?      */
  272.     state = LWGET(OB_STATE(hot_obj));
  273.     if (LWGET(OB_FLAGS(hot_obj)) & SELECTABLE)
  274.     if ( !(state & DISABLED) )
  275.         {            /* Yes!  Set up wait state.      */
  276.         *mode = M1_EXIT;
  277.         objc_xywh(tree, hot_obj, rect);
  278.         if (state & SELECTED)    /* But only toggle if it's not      */
  279.             return (NIL);    /* already SELECTED!          */
  280.         else
  281.             {
  282.             objc_toggle(tree, hot_obj);
  283.             return (hot_obj);
  284.             }
  285.         }
  286.  
  287.     rc_copy(&root, &br_rect);    /* No hot object, so compute    */
  288.     br_mx = mx;            /* mouse bounding rectangle.    */
  289.     br_my = my;
  290.     br_togl = 0;
  291.     map_tree(tree, ROOT, NIL, break_obj);
  292.     rc_copy(&br_rect, rect);    /* Then return to wait state.    */
  293.     *mode = M1_EXIT;
  294.     return (NIL);
  295.     }
  296.  
  297. /************* Keyboard manager and subroutines ***************/
  298.  
  299.     WORD
  300. find_def(tree, obj)        /* Check if the object is DEFAULT    */
  301.     LONG    tree;
  302.     WORD    obj;
  303.     {            /* Is sub-tree hidden?            */
  304.     if (HIDETREE & LWGET(OB_FLAGS(obj)))
  305.         return (FALSE);
  306.                 /* Must be DEFAULT and not DISABLED    */
  307.     if (DEFAULT & LWGET(OB_FLAGS(obj)))
  308.     if ( !(DISABLED & LWGET(OB_STATE(obj))) )
  309.         fn_obj = obj;    /* Record object number            */
  310.     return (TRUE);
  311.     }
  312.  
  313.     WORD
  314. find_tab(tree, obj)        /* Look for target of TAB operation.    */
  315.     LONG    tree;
  316.     WORD    obj;
  317.     {            /* Check for hiddens subtree.        */
  318.     if (HIDETREE & LWGET(OB_FLAGS(obj)))
  319.         return (FALSE);
  320.                 /* If not EDITABLE, who cares?        */
  321.     if ( !(EDITABLE & LWGET(OB_FLAGS(obj))) )
  322.         return (TRUE);
  323.                 /* Check for forward tab match        */
  324.     if (fn_dir && fn_prev == fn_last)
  325.         fn_obj = obj;
  326.                 /* Check for backward tab match        */
  327.     if (!fn_dir && obj == fn_last)
  328.         fn_obj = fn_prev;
  329.     fn_prev = obj;        /* Record object for next call.        */
  330.     return (TRUE);
  331.     }    
  332.  
  333.     WORD
  334. form_keybd(tree, edit_obj, next_obj, kr, out_obj, okr)
  335.     LONG    tree;
  336.     WORD    edit_obj, next_obj, kr, *out_obj, *okr;
  337.     {
  338.     if (LLOBT(kr))        /* If lower byte valid, mask out    */
  339.         kr &= 0xff;    /* extended code byte.            */
  340.     fn_dir = 0;        /* Default tab direction if backward.    */
  341.     switch (kr) {
  342.         case CR:    /* Zap character.            */
  343.             *okr = 0;
  344.                 /* Look for a DEFAULT object.        */
  345.             fn_obj = NIL;
  346.             map_tree(tree, ROOT, NIL, find_def);
  347.                 /* If found, SELECT and force exit.    */
  348.             if (fn_obj != NIL)
  349.                 {
  350.                 objc_sel(tree, fn_obj);
  351.                 *out_obj = fn_obj;
  352.                 return (FALSE);
  353.                 }        /* Falls through to     */ 
  354.         case TAB:            /* tab if no default     */
  355.         case DOWN:    
  356.             fn_dir = 1;        /* Set fwd direction     */
  357.         case BTAB:
  358.         case UP:
  359.             *okr = 0;        /* Zap character    */
  360.             fn_last = edit_obj;
  361.             fn_prev = fn_obj = NIL; /* Look for TAB object    */
  362.             map_tree(tree, ROOT, NIL, find_tab);
  363.             if (fn_obj == NIL)    /* try to wrap around     */
  364.                 map_tree(tree, ROOT, NIL, find_tab);
  365.             if (fn_obj != NIL)
  366.                 *out_obj = fn_obj;
  367.             break;
  368.         default:            /* Pass other chars    */
  369.             return (TRUE);
  370.         }
  371.     return (TRUE);
  372.     }
  373.  
  374. /************* Mouse button manager and subroutines ***************/
  375.  
  376.     WORD
  377. do_radio(tree, obj)
  378.     LONG    tree;
  379.     WORD    obj;
  380.     {
  381.     GRECT    root;
  382.     WORD    pobj, sobj, state;
  383.  
  384.     objc_xywh(tree, ROOT, &root);
  385.     pobj = get_parent(tree, obj);        /* Get the object's parent */
  386.  
  387.     for (sobj = LWGET(OB_HEAD(pobj)); sobj != pobj;
  388.         sobj = LWGET(OB_NEXT(sobj)) )
  389.         {                /* Deselect all but...       */
  390.         if (sobj != obj)
  391.             objc_dsel(tree, sobj);
  392.         }
  393.     objc_sel(tree, obj);            /* the one being SELECTED  */
  394.     }
  395.  
  396.     WORD                    /* Mouse button handler       */
  397. form_button(tree, obj, clicks, next_obj, hot_obj)
  398.     LONG    tree;
  399.     WORD    obj, clicks, *next_obj, *hot_obj;
  400.     {
  401.     WORD    flags, state, hibit, texit, sble, dsbld, edit;
  402.     WORD    in_out, in_state;
  403.  
  404.     flags = LWGET(OB_FLAGS(obj));        /* Get flags and states   */
  405.     state = LWGET(OB_STATE(obj));
  406.     texit = flags & TOUCHEXIT;
  407.     sble = flags & SELECTABLE;
  408.     dsbld = state & DISABLED;
  409.     edit = flags & EDITABLE;
  410.  
  411.     if (!texit && (!sble || dsbld) && !edit) /* This is not an      */
  412.         {                 /* interesting object    */
  413.         *next_obj = 0;
  414.         return (TRUE);
  415.         }
  416.  
  417.     if (texit && clicks == 2)        /* Preset special flag    */
  418.         hibit = 0x8000;
  419.     else
  420.         hibit = 0x0;
  421.  
  422.     if (sble && !dsbld)            /* Hot stuff!        */
  423.         {
  424.         if (flags & RBUTTON)        /* Process radio buttons*/
  425.             do_radio(tree, obj);    /* immediately!        */ 
  426.         else if (!texit)
  427.             {
  428.             in_state = (obj == *hot_obj)?    /* Already toggled ? */
  429.                 state: state ^ SELECTED;    
  430.             if (!graf_watchbox(tree, obj, in_state, 
  431.                 in_state ^ SELECTED))
  432.                 {            /* He gave up...  */
  433.                 *next_obj = 0;
  434.                 *hot_obj = NIL;
  435.                 return (TRUE);
  436.                 }
  437.             }
  438.         else /* if (texit) */
  439.             if (obj != *hot_obj)    /* Force SELECTED    */
  440.                 objc_toggle(tree, obj);
  441.         }
  442.  
  443.     if (obj == *hot_obj)        /* We're gonna do it! So don't    */
  444.         *hot_obj = NIL;        /* turn it off later.        */
  445.  
  446.     if (texit || (flags & EXIT) )    /* Exit conditions.        */
  447.         {
  448.         *next_obj = obj | hibit;
  449.         return (FALSE);        /* Time to leave!        */
  450.         }
  451.     else if (!edit)            /* Clear object unless tabbing    */
  452.         *next_obj = 0;
  453.  
  454.     return (TRUE);
  455.     }
  456.  
  457. /************* New forms manager: Entry point and main loop *************/
  458.  
  459.     WORD
  460. form_do(tree, start_fld)
  461.     REG LONG    tree;
  462.     WORD        *start_fld;
  463.     {
  464.     REG WORD    edit_obj;
  465.     WORD        next_obj, hot_obj, hot_mode;
  466.     WORD        which, cont;
  467.     WORD        idx;
  468.     WORD        mx, my, mb, ks, kr, br;
  469.     GRECT        hot_rect;
  470.     WORD        (*valid)();
  471.                         /* Init. editing    */
  472.     next_obj = *start_fld;
  473.     edit_obj = 0;
  474.                         /* Initial hotspot cndx */
  475.     hot_obj = NIL; hot_mode = M1_ENTER;
  476.     objc_xywh(tree, ROOT, &hot_rect);
  477.                         /* Main event loop    */
  478.     cont = TRUE;
  479.     while (cont)
  480.       {
  481.                         /* position cursor on    */
  482.                         /*   the selected     */
  483.                         /*   editting field    */
  484.       if (edit_obj != next_obj)
  485.       if (next_obj != 0)
  486.           {
  487.             edit_obj = next_obj;
  488.             next_obj = 0;
  489.             objc_edit(tree, edit_obj, 0, &idx, EDINIT);
  490.           }
  491.                         /* wait for button or   */
  492.                         /* key or rectangle    */
  493.       which = evnt_multi(MU_KEYBD | MU_BUTTON | MU_M1, 
  494.             0x02, 0x01, 0x01,
  495.             hot_mode, hot_rect.g_x, hot_rect.g_y, 
  496.                 hot_rect.g_w, hot_rect.g_h, 
  497.             0, 0, 0, 0, 0,
  498.             0x0L,
  499.             0, 0,
  500.             &mx, &my, &mb, &ks, &kr, &br);
  501.  
  502.       if (which & MU_M1)            /* handle rect. event     */
  503.           hot_obj = form_hot(tree, hot_obj, mx, my, &hot_rect, &hot_mode);
  504.                         /* handle keyboard event*/
  505.       if (which & MU_KEYBD)
  506.           {                /* Control char filter    */
  507.             cont = form_keybd(tree, edit_obj, next_obj, kr, &next_obj, &kr);
  508.             if (kr && edit_obj)        /* Add others to object    */
  509.             objc_edit(tree, edit_obj, kr, &idx, EDCHAR);
  510.           }
  511.                         /* handle button event    */
  512.       if (which & MU_BUTTON)
  513.           {                /* Which object hit?    */
  514.             next_obj = objc_find(tree, ROOT, MAX_DEPTH, mx, my);
  515.              if (next_obj == NIL)
  516.                   next_obj = 0;
  517.             else                /* Process a click    */
  518.                 cont = form_button(tree, next_obj, br, 
  519.                 &next_obj, &hot_obj);
  520.           }
  521.                         /* handle end of field    */
  522.                         /*   clean up        */
  523.       if (!cont || (next_obj != edit_obj && next_obj != 0))
  524.       if (edit_obj != 0) 
  525.           objc_edit(tree, edit_obj, 0, &idx, EDEND);
  526.       }
  527.                         /* If defaulted, may    */
  528.                         /* need to clear hotspot*/
  529.     if (hot_obj != (next_obj & 0x7fff))
  530.     if (hot_obj != NIL)
  531.         objc_toggle(tree, hot_obj);
  532.                         /* return exit object    */
  533.                         /*   hi bit may be set    */
  534.                         /*   if exit obj. was    */
  535.                         /*   double-clicked    */
  536.     *start_fld = edit_obj;
  537.     return(next_obj);
  538.     }
  539.