home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / program / gempp15b.zoo / src / gemhf.cc < prev    next >
C/C++ Source or Header  |  1993-04-25  |  15KB  |  585 lines

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