home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / program / 331 / gemfxm14 / minicolr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-20  |  34.4 KB  |  822 lines

  1. /**************************************************************************
  2.  *
  3.  * mini_pallete - A little bitty control-panel-like color pallete acc.
  4.  *
  5.  *  Public Domain example program by Ian Lepore.
  6.  *
  7.  *  This is distributed as an example of how to write an accessory using
  8.  *  my AESFAST public domain GEM bindings.  This example uses a few of
  9.  *  the nifty utilities from AESFAST, but it's pretty much straightforward
  10.  *  window-handling code.
  11.  *
  12.  *  I built this beast because I have some graphics programs (Mandelbrot
  13.  *  fractal generators, a spyrograph program, etc), in which one would
  14.  *  naturally want to change the screen colors on the fly, but the %^$%#*&
  15.  *  system control panel covers the whole screen in low rez.  This acc
  16.  *  gives a nice itty-bitty moveable window with all the necessary color
  17.  *  controls in it.
  18.  *
  19.  *  This acc does not behave like the system control panel, in that it
  20.  *  will not reset the colors the application has set when you call it up.
  21.  *  On the other hand, the color changes you do with this accessory will 
  22.  *  not be saved if you use 'Save Desktop'. (Hint:  You would need to code
  23.  *  the shel_read() and shel_write() AES functions to make that work.  
  24.  *  Actually doing it is left as an excerise for the reader <grin>).
  25.  *
  26.  *  Also, the order of the colored boxes on the screen corresponds to the
  27.  *  TOS order of colors, not the VDI order.  (EG:  The foreground and
  28.  *  background colors are the first and last boxes, not the first two).
  29.  *
  30.  *  This code is pretty heavily commented.  Please excuse me if some of 
  31.  *  the comments seem obvious, but I figure the audience for this will 
  32.  *  include both beginning C programmers, and old-timers who just need to
  33.  *  see how my bindings work as opposed to other bindings.
  34.  *
  35.  *************************************************************************/
  36.  
  37. #include <gemfast.h>
  38. #include <osbind.h>
  39.  
  40. #ifndef TRUE
  41. #define TRUE  1
  42. #define FALSE 0
  43. #endif
  44.  
  45. #define Getcolor(a) ((int)(Setcolor((a), -1)))
  46.  
  47. #define graf_mkstate    graq_mstate    /* use Line-A mouse state call */
  48.  
  49. /**************************************************************************
  50.  *
  51.  * global vars (gee, there's not many of these for a change...)
  52.  *
  53.  *************************************************************************/
  54.  
  55. struct rgb_settings {
  56.         char red, grn, blu, filler;
  57.         } cur_setting;
  58.  
  59. int     coloridx = 0;                   /* default color index is # 0    */
  60.  
  61. #define WI_KIND         (MOVER|CLOSER|NAME)
  62. #define NO_WINDOW       -1
  63.  
  64. extern int gl_apid;                     /* defined in bindings library   */
  65.  
  66. int     menu_id ;                       /* our menu id                   */
  67. int     wi_handle;                      /* window handle                 */
  68. GRECT   treerect;                       /* object tree (in window) rect  */
  69.  
  70. char    menu_title[] = "  Mini Pallete  ";
  71. char    wind_title[] = " Mini Pallete ";
  72.  
  73. /**************************************************************************
  74.  *
  75.  * palttree - The color pallete dialog tree.
  76.  *
  77.  *  This is NOT the output from a resource editor (it was a long time ago,
  78.  *  but it's been pretty much re-done by hand).
  79.  *
  80.  *  About extended object types... 
  81.  *
  82.  *  The ob_type field is a word, but the AES only uses the lower byte of 
  83.  *  it.  It has become a sort of standard technique for programs to use
  84.  *  the upper byte for their own evil purposes.  (Really, the object 
  85.  *  structure should have had an 'ob_apspec' longword in it for the 
  86.  *  application's use).  Anyway, there is some discussion under the 
  87.  *  'find_boxchar' routine below on accessing arrays of objects in a tree
  88.  *  without being sure where the objects are in the tree array.  The
  89.  *  methods discussed below work fine for boxchar objects; the extended
  90.  *  object type can be used for other types of objects.  
  91.  *
  92.  *  For example, suppose you have 10 strings in a dialog box.  You want to
  93.  *  set the ob_spec pointers at runtime to correspond to the elements in
  94.  *  an array of strings you've defined in your program.  You can code a
  95.  *  lot of C statements using the hard-coded object names, but what if you
  96.  *  have 50 strings instead of 10?  More to the point, what if some hacker
  97.  *  edits the .RSC file and changes the order of the objects? Bombs, that's
  98.  *  what.  So, you can (with most resource editors) set the extended 
  99.  *  object type for the strings to the numbers 1-10, then at runtime you
  100.  *  can scan the tree looking for an object with an extended type of 1,
  101.  *  then set the first string pointer, then scan for 2, and so on.  Now,
  102.  *  no matter where those strings get moved to in the tree structure, they
  103.  *  will be found at runtime and pointers will be assigned properly.
  104.  *
  105.  *  Now that I've described this nifty string-thing, I should mention that
  106.  *  this program doesn't use that techique, as it contains no strings in
  107.  *  the dialog. 
  108.  * 
  109.  *  This program uses the extended object type to hold the TOS color index
  110.  *  value that corresponds to the colored box which is the object.  This
  111.  *  is due to the screwy way the ST maps TOS colors to VDI colors.  If you
  112.  *  compare the VDI/object color number in the ob_spec field to the extended
  113.  *  object type value, you'll see the translation table that maps TOS colors
  114.  *  to GEM colors.  For the ob_type values below which are not described
  115.  *  by name, the format is 0xcc14, where 'cc' is the TOS color number, and
  116.  *  '14' is a box type object.
  117.  *
  118.  *  The ob_spec field for box-like objects maps out as follows:
  119.  *   0xaabbcdef
  120.  *     |||||||+-- inside fill color
  121.  *     ||||||+--- fill pattern and opaque/transparent flag
  122.  *     |||||+---- text color
  123.  *     ||||+----- border color
  124.  *     ||++------ border thickness (neg = outside width, pos = inside width)
  125.  *     ++-------- ASCII character for boxchar objects, zero for other types
  126.  *
  127.  *  The two objects flagged as HIDETREE are no longer used, and I don't
  128.  *  want to rebuild the whole tree to remove them (and I've lost the
  129.  *  .RSC file that this source comes from).
  130.  *************************************************************************/
  131.  
  132. OBJECT  palttree[] = {
  133.  
  134. /*          type       flags   state   ob_spec     x       y       w        h   */
  135.  
  136. -1,  1, 35, G_BOX,     NONE,     0, 0x00000000L, 0x0000, 0x0000, 0x0212, 0x0506,
  137.  
  138.  2, -1, -1, G_BOXCHAR, HIDETREE, 0, 0x05FF1100L, 0x0000, 0x0000, 0x0000, 0x0000,
  139.  3, -1, -1, G_BOX,     HIDETREE, 0, 0x00FF1121L, 0x0000, 0x0000, 0x0000, 0x0000,
  140.  
  141.  7,  4,  6, G_IBOX,    NONE,     0, 0x00001101L, 0x0100, 0x0100, 0x0401, 0x0703,
  142.  5, -1, -1, G_BOXCHAR, NONE,     0, 0x52001100L, 0x0200, 0x0100, 0x0001, 0x0001,
  143.  6, -1, -1, G_BOXCHAR, NONE,     0, 0x47001100L, 0x0200, 0x0401, 0x0001, 0x0001,
  144.  3, -1, -1, G_BOXCHAR, NONE,     0, 0x42001100L, 0x0200, 0x0702, 0x0001, 0x0001,
  145.  
  146. 35,  8, 26, G_IBOX,    NONE,     0, 0x00001100L, 0x0501, 0x0200, 0x0210, 0x0603,
  147.  
  148. 17,  9, 16, G_IBOX,    NONE,     0, 0x00001100L, 0x0100, 0x0000, 0x0010, 0x0001,
  149. 10, -1, -1, G_BOXCHAR, NONE,     0, 0x30FF1100L,  0, 0, 2, 1,
  150. 11, -1, -1, G_BOXCHAR, NONE,     0, 0x31FF1100L,  2, 0, 2, 1,
  151. 12, -1, -1, G_BOXCHAR, NONE,     0, 0x32FF1100L,  4, 0, 2, 1,
  152. 13, -1, -1, G_BOXCHAR, NONE,     0, 0x33FF1100L,  6, 0, 2, 1,
  153. 14, -1, -1, G_BOXCHAR, NONE,     0, 0x34FF1100L,  8, 0, 2, 1,
  154. 15, -1, -1, G_BOXCHAR, NONE,     0, 0x35FF1100L, 10, 0, 2, 1,
  155. 16, -1, -1, G_BOXCHAR, NONE,     0, 0x36FF1100L, 12, 0, 2, 1,
  156.  8, -1, -1, G_BOXCHAR, NONE,     0, 0x37FF1100L, 14, 0, 2, 1,
  157.  
  158. 26, 18, 25, G_IBOX,    NONE,     0, 0x00001100L, 0x0100, 0x0301, 0x0010, 0x0001,
  159. 19, -1, -1, G_BOXCHAR, NONE,     0, 0x30FF1100L,  0, 0, 2, 1,
  160. 20, -1, -1, G_BOXCHAR, NONE,     0, 0x31FF1100L,  2, 0, 2, 1,
  161. 21, -1, -1, G_BOXCHAR, NONE,     0, 0x32FF1100L,  4, 0, 2, 1,
  162. 22, -1, -1, G_BOXCHAR, NONE,     0, 0x33FF1100L,  6, 0, 2, 1,
  163. 23, -1, -1, G_BOXCHAR, NONE,     0, 0x34FF1100L,  8, 0, 2, 1,
  164. 24, -1, -1, G_BOXCHAR, NONE,     0, 0x35FF1100L, 10, 0, 2, 1,
  165. 25, -1, -1, G_BOXCHAR, NONE,     0, 0x36FF1100L, 12, 0, 2, 1,
  166. 17, -1, -1, G_BOXCHAR, NONE,     0, 0x37FF1100L, 14, 0, 2, 1,
  167.  
  168.  7, 27, 34, G_IBOX,    NONE,     0, 0x00001100L, 0x0100, 0x0602, 0x0010, 0x0001,
  169. 28, -1, -1, G_BOXCHAR, NONE,     0, 0x30FF1100L,  0, 0, 2, 1,
  170. 29, -1, -1, G_BOXCHAR, NONE,     0, 0x31FF1100L,  2, 0, 2, 1,
  171. 30, -1, -1, G_BOXCHAR, NONE,     0, 0x32FF1100L,  4, 0, 2, 1,
  172. 31, -1, -1, G_BOXCHAR, NONE,     0, 0x33FF1100L,  6, 0, 2, 1,
  173. 32, -1, -1, G_BOXCHAR, NONE,     0, 0x34FF1100L,  8, 0, 2, 1,
  174. 33, -1, -1, G_BOXCHAR, NONE,     0, 0x35FF1100L, 10, 0, 2, 1,
  175. 34, -1, -1, G_BOXCHAR, NONE,     0, 0x36FF1100L, 12, 0, 2, 1,
  176. 26, -1, -1, G_BOXCHAR, NONE,     0, 0x37FF1100L, 14, 0, 2, 1,
  177.  
  178.  0, 36, 51, G_IBOX,    NONE,     0, 0x00001100L, 0x0000, 0x0104, 0x0212, 0x0302,
  179. 37, -1, -1, 0x0014,    NONE,     0, 0x00011170L, 512,    512,    2,      1,
  180. 38, -1, -1, 0x0814,    NONE,     0, 0x00000179L, 512,    769,    2,      1,
  181. 39, -1, -1, 0x0114,    NONE,     0, 0x00001172L, 1026,   512,    2,      1,
  182. 40, -1, -1, 0x0214,    NONE,     0, 0x00002173L, 1540,   512,    2,      1,
  183. 41, -1, -1, 0x0314,    NONE,     0, 0x00003176L, 7,      512,    2,      1,
  184. 42, -1, -1, 0x0414,    NONE,     0, 0x00000174L, 521,    512,    2,      1,
  185. 43, -1, -1, 0x0514,    NONE,     0, 0x00001177L, 1035,   512,    2,      1,
  186. 44, -1, -1, 0x0614,    NONE,     0, 0x00002175L, 1549,   512,    2,      1,
  187. 45, -1, -1, 0x0A14,    NONE,     0, 0x0000217BL, 1540,   769,    2,      1,
  188. 46, -1, -1, 0x0B14,    NONE,     0, 0x0000317EL, 7,      769,    2,      1,
  189. 47, -1, -1, 0x0C14,    NONE,     0, 0x0000017CL, 521,    769,    2,      1,
  190. 48, -1, -1, 0x0D14,    NONE,     0, 0x0000117FL, 1035,   769,    2,      1,
  191. 49, -1, -1, 0x0E14,    NONE,     0, 0x0000217DL, 1549,   769,    2,      1,
  192. 50, -1, -1, 0x0714,    NONE,     0, 0x00003178L, 16,     512,    2,      1,
  193. 51, -1, -1, 0x0914,    NONE,     0, 0x0000117AL, 1026,   769,    2,      1,
  194. 35, -1, -1, 0x0F14,    LASTOB,   0, 0x00003171L, 16,     769,    2,      1
  195. }; /* END of palttree[] */
  196.  
  197. /* resource set indicies (names) for objects in palttree */
  198.  
  199. #define PALTTREE 0  /* root */
  200. #define PALTPNUM 7  /* Parent box for all the intensity parents */
  201. #define PALTPRED 8  /* Parent box for the RED intensity numbers */
  202. #define PALTPGRN 17 /* Parent box for the GRN intensity numbers */
  203. #define PALTPBLU 26 /* Parent box for the BLU intensity numbers */
  204. #define PALTPCOL 35 /* Parent box for the color-selection boxes */
  205.  
  206. /**************************************************************************
  207.  *
  208.  * find_boxchar - Return the object index of a child boxchar with a given
  209.  *  letter in its box, or -1 if no matching object can be found.
  210.  *
  211.  *  Say what?  Well, this routine cruises through all the children of a 
  212.  *  given parent object, and for every boxchar type object found the char
  213.  *  in the box is compared to the char passed to this routine.  On the 
  214.  *  first match found, the object index of the matching object is returned.
  215.  *  (Note that the object type is masked with 0x00FF to strip out any
  216.  *  extended object type info, so that the object type compare will work).
  217.  *  
  218.  *  Why do this, you wonder?  Well, boxchar objects make great radio
  219.  *  buttons, especially for things like selecting a device, or in this 
  220.  *  case, a color intensity from 0-7.  In the case of device selection, 
  221.  *  you need to have buttons for A-P, but on most systems, there won't
  222.  *  be this many devices, and you'll need to set some of the buttons
  223.  *  (boxchars) to DISABLED.  Since you'll be doing this at runtime, you
  224.  *  need a way to find the corresponding button for each device.  It is
  225.  *  AN ABSOLUTE NO-NO to hard-code object indicies (names) or treat the 
  226.  *  objects as an array, because as soon as you do some user will come  
  227.  *  along with a resouce editor & re-sort your objects.  Then the user will
  228.  *  complain when s/he clicks on the drive A button, and drive B gets
  229.  *  formatted instead.
  230.  *
  231.  *************************************************************************/
  232.  
  233. int
  234. find_boxchar(tree, parent, boxchar)
  235.         register OBJECT *tree;
  236.         register int    parent;
  237.         register char   boxchar;
  238. {
  239.         register int kid;
  240.  
  241.         kid = tree[parent].ob_head;
  242.  
  243.         while ( (kid != parent) && (kid >= R_TREE) ) {
  244.                 if ((0x00FF & tree[kid].ob_type) == G_BOXCHAR) {
  245.                         if (boxchar == (char)(tree[kid].ob_spec >> 24)) {
  246.                                 return(kid);
  247.                         }
  248.                 }
  249.                 kid = tree[kid].ob_next;
  250.         }
  251.         return(-1);
  252. }
  253.  
  254. /**************************************************************************
  255.  *
  256.  * rgb2color - convert cur_settings structure to a TOS color value.
  257.  *  This routine combines the separate ASCII RGB values into a single
  258.  *  integer RGB value in TOS format.  That is, if the cur_settings struct
  259.  *  contains '2', '6', and '3', this routine will return 0x0263.
  260.  *  
  261.  *************************************************************************/
  262.  
  263. int
  264. rgb2color()
  265. {
  266.         return ( ((cur_setting.red & 0x000F) << 8) | 
  267.                  ((cur_setting.grn & 0x000F) << 4) | 
  268.                   (cur_setting.blu & 0x000F) );
  269. }
  270.  
  271. /**************************************************************************
  272.  *
  273.  * color2rgb - convert a TOS color to characters in cur_settings.
  274.  *  This routine separates an integer TOS-format RGB value into 3 ASCII
  275.  *  characters in cur_settings.  If the TOS color is 0x0746, the structure
  276.  *  will contain '7', '4', and '6'.
  277.  *
  278.  *************************************************************************/
  279.  
  280. void
  281. color2rgb(color)
  282.         register int color;
  283. {
  284.         cur_setting.red = '0' + ( 0x000F & (color >> 8) );
  285.         cur_setting.grn = '0' + ( 0x000F & (color >> 4) );
  286.         cur_setting.blu = '0' + ( 0x000F &  color );
  287.  
  288. /**************************************************************************
  289.  *
  290.  * new_color - Change the current selected color box on the screen (like
  291.  *  a radio button), and set the new intensity settings (numbered boxes) 
  292.  *  to match the new active color box.
  293.  *
  294.  *  To show which color box is current, we set the ob_state to CROSSED
  295.  *  instead of SELECTED.  SELECTED will invert the color of the object,
  296.  *  which sorta defeats our purpose.  We don't have as much room on the
  297.  *  screen as the regular control panel, so we can't just make the box
  298.  *  a little bigger like it does.
  299.  *
  300.  *  If 'drawflag' is TRUE, the screen is updated with the state changes
  301.  *  (this is the normal state of affairs).  If the flag is FALSE, the
  302.  *  object states are set, but no screen work is done (this is for
  303.  *  initializing the dialog before it is displayed).
  304.  *************************************************************************/
  305.  
  306. void 
  307. new_color(newobject, drawflag)
  308.         register int newobject, drawflag;
  309. {
  310.         register OBJECT *ptree;
  311.         register int    wrkobject;
  312.         register int    curobject;
  313.         int             dmy;
  314.  
  315.         ptree = palttree;               /* quick register tree pointer */
  316.  
  317. /*
  318.  * figure out which is the currently-selected color box object. 
  319.  * if the current object is the same as the new object, the user is
  320.  * leaning on the mouse button; to avoid nasty object flashing on
  321.  * the screen in this case, just return.
  322.  */
  323.  
  324.         curobject = obj_rbfind(ptree, PALTPCOL, CROSSED);
  325.         if (curobject == newobject) {
  326.                 return;
  327.         }
  328.         
  329. /*
  330.  * de-select the numbered radio buttons that show the intensity
  331.  * settings for the current color.  the 'if (-1 != ...)' logic prevents
  332.  * us from croaking the first time thru, since no buttons will be selected.
  333.  */
  334.  
  335.         if (-1 != (wrkobject = objrb_which(ptree, PALTPRED)))
  336.                 objst_change(ptree, wrkobject, ~SELECTED, drawflag);
  337.         if (-1 != (wrkobject = objrb_which(ptree, PALTPGRN)))
  338.                 objst_change(ptree, wrkobject, ~SELECTED, drawflag);
  339.         if (-1 != (wrkobject = objrb_which(ptree, PALTPBLU)))
  340.                 objst_change(ptree, wrkobject, ~SELECTED, drawflag);
  341.  
  342. /*
  343.  * de-select the current color box, select the new color box.  
  344.  * again the '-1' check is for the first time thru case.
  345.  */
  346.  
  347.         if (-1 != curobject) 
  348.                 objst_change(ptree, curobject, ~CROSSED, drawflag);
  349.         objst_change(ptree, newobject,  CROSSED, drawflag);
  350.  
  351. /*
  352.  * change our picture of what's current.  the TOS color index is encoded
  353.  * as the 'extended object type' of the color-box objects (see discussion 
  354.  * on this above, where palttree is defined).  the 'color2rgb' call will
  355.  * fill in the 'cur_settings' structure to represent the current intensity
  356.  * of the color just selected.  
  357.  */
  358.  
  359.         coloridx = 0x000F & (ptree[newobject].ob_type >> 8);
  360.         color2rgb( Getcolor(coloridx) );
  361.  
  362. /*
  363.  * select the appropriate numbered boxes to represent the color intensity
  364.  * settings for the newly-selected color. the 'cur_settings' array holds
  365.  * the ASCII representation of the RGB instensities.  this is done so that
  366.  * we can find the corresponding radio buttons (which are BOXCHAR objects)
  367.  * via the find_boxchar() function.
  368.  */
  369.  
  370.         wrkobject = find_boxchar(ptree, PALTPRED, cur_setting.red);
  371.         objst_change(ptree, wrkobject,  SELECTED, drawflag);
  372.         
  373.         wrkobject = find_boxchar(ptree, PALTPGRN, cur_setting.grn);    
  374.         objst_change(ptree, wrkobject,  SELECTED, drawflag);
  375.         
  376.         wrkobject = find_boxchar(ptree, PALTPBLU, cur_setting.blu);
  377.         objst_change(ptree, wrkobject,  SELECTED, drawflag);
  378.  
  379. /* all done */
  380.  
  381. }
  382.      
  383. /**************************************************************************
  384.  *
  385.  * new_settings - Process a click in a numbered box of the dialog, and
  386.  *  change the color intensity in the TOS color pallete correspondingly.
  387.  *
  388.  *************************************************************************/
  389.  
  390. void
  391. new_settings(newobject)
  392. {
  393.         char boxchar;
  394.         int  curparent,
  395.              curobject;
  396.  
  397. /*
  398.  * figure out what's being changed.  the 'curparent' value will tell us
  399.  * whether it's the R, G, or B value.  the 'curobject' is used to detect
  400.  * whether the user is leaning on the mouse (curobject == newobject);
  401.  * in this case we exit without taking any action, to avoid nasty graphic
  402.  * flashing on the screen.
  403.  *
  404.  */
  405.  
  406.         curparent = obj_parent(palttree, newobject);
  407.         curobject = objrb_which(palttree, curparent);
  408.         
  409.         if (curobject == newobject) {
  410.                 return;
  411.         }
  412.         
  413. /*
  414.  * the displayed intensity buttons are G_BOXCHAR objects, with the chars
  415.  * ranging from '0' - '7' for each color.  we pluck the displayed char 
  416.  * out of the ob_spec value in the tree (ob_spec for boxchars looks like
  417.  * 0xCCnnnnnn), and we plug the char right into the 'cur_settings' array,
  418.  * still in its ASCII form. 
  419.  */
  420.  
  421.         boxchar = (char)(palttree[newobject].ob_spec >> 24);
  422.  
  423.         switch (curparent) {
  424.                 case PALTPRED:
  425.                         cur_setting.red = boxchar;
  426.                         break;
  427.                 case PALTPGRN:
  428.                         cur_setting.grn = boxchar;
  429.                         break;
  430.                 case PALTPBLU:
  431.                         cur_setting.blu = boxchar;
  432.                         break;
  433.         }  
  434.         
  435. /* 
  436.  * now that the 'cur_settings' array contains the new intensity setting,
  437.  * call 'rgb2color' to convert the ASCII values to a single binary TOS
  438.  * color value, then call the TOS 'Setcolor' function to make the change.
  439.  */
  440.  
  441.         Setcolor( coloridx, rgb2color() );
  442.  
  443. /*
  444.  * de-select the old intensity setting, select the new one...
  445.  */
  446.         objst_change(palttree, curobject, ~SELECTED, TRUE);
  447.         objst_change(palttree, newobject,  SELECTED, TRUE); 
  448.  
  449. /* all done */
  450.  
  451. }
  452.  
  453. /**************************************************************************
  454.  *
  455.  * prg_init - Mundane program init stuff.
  456.  *  The only item of note here is a call to 'rsc_treefix'.  This is a
  457.  *  routine from the AESFAST library that will do an rsrc_obfix() call for
  458.  *  each object in a tree.  It's used only for resource trees buried in 
  459.  *  source code, if the resource file is loaded, the rsrc_load() call
  460.  *  handles the object x/y/w/h fixup internally.
  461.  *
  462.  *  Oh yeah -- I discovered an interesting problem coding this:  If the
  463.  *  'menu_register' call is not the first AES call following the appl_init
  464.  *  the accessory sometimes doesn't show up on the DESK menu until
  465.  *  after you've run some other GEM program.  This is consistant with the
  466.  *  rules of AES multitasking:  your program can be swapped out on ANY
  467.  *  AES call, not just when you do an evnt_???? call.  It just isn't 
  468.  *  mentioned in any of the docs I have.
  469.  *************************************************************************/
  470.  
  471. prg_init()
  472. {
  473.         appl_init();
  474.  
  475.         menu_id = menu_register(gl_apid, menu_title);
  476.         
  477.         rsc_treefix(palttree);
  478.  
  479.         form_center(palttree, &treerect.g_x, &treerect.g_y, 
  480.                               &treerect.g_w, &treerect.g_h);
  481.  
  482.         new_color(0, FALSE);
  483.  
  484.         wi_handle = NO_WINDOW;
  485. }
  486.  
  487. /**************************************************************************
  488.  *
  489.  * open_window 
  490.  *   Create and open the window, if it's not open already.
  491.  *
  492.  *   If the window is already open, it may be hidden from the user by an
  493.  *   overlapping window, and the only way to get us back may be to
  494.  *   click on us again in the DESK menu.  In this case, we just ask
  495.  *   the AES to bring our window back to the top.
  496.  *
  497.  *   Before opening the window, we calculate its size and location (total 
  498.  *   size, including its borders & controls) based upon the current size 
  499.  *   and location of the pallete object tree.  The first time the window
  500.  *   opens, this will be the center of the screen, because we do a 
  501.  *   form_center on the pallete tree.  For subsequent calls, we show up
  502.  *   wherever we were last on the screen.
  503.  *
  504.  *   We also set the window title bar here, before opening the window.   
  505.  *************************************************************************/
  506.  
  507. open_window()
  508. {
  509.         GRECT windrect;
  510.         
  511.         if (wi_handle == NO_WINDOW) {
  512.         
  513.                 wind_calc(WC_BORDER, WI_KIND, treerect, 
  514.                            &windrect.g_x, &windrect.g_y,
  515.                            &windrect.g_w, &windrect.g_h);
  516.                            
  517.                 wi_handle = wind_create(WI_KIND, windrect);
  518.                 
  519.                 wind_set(wi_handle, WF_NAME, wind_title, 0L);
  520.                 
  521.                 wind_open(wi_handle, windrect);
  522.         } 
  523.         else {
  524.                 wind_set(wi_handle, WF_TOP, 0L, 0L);
  525.         }
  526. }
  527.  
  528. /**************************************************************************
  529.  *
  530.  * close_window
  531.  *  Close and delete the window, if it's open.
  532.  *************************************************************************/
  533.  
  534. close_window()
  535. {
  536.         if (wi_handle != NO_WINDOW) {       
  537.                 wind_close(wi_handle);
  538.                 wind_delete(wi_handle);
  539.                 wi_handle = NO_WINDOW;
  540.         }
  541. }
  542.  
  543. /**************************************************************************
  544.  *
  545.  * do_redraw - Process redraw list.
  546.  *  Ok, let's see if I can explain this better than the DRI books do...
  547.  *
  548.  *  After somebody has munged up the screen (say with a dialog box), they
  549.  *  send a redraw request to the whole world.  The redraw request comes
  550.  *  from one of two sources:  1) Somebody does a form_dial(FMD_FINISH...)
  551.  *  call, or 2) Somebody does a wind_close() call.  (Ummm, ok, so there's
  552.  *  other sources, now that I think of it, like windows being moved or
  553.  *  sized).  Anyway, when AES sends out a redraw request, it sends it to
  554.  *  everybody who owns a window, and what it sends is the full x/y/w/h
  555.  *  values of the area of the screen to restore.
  556.  *
  557.  *  The area to be restored may or may not overlap any of the windows you
  558.  *  have open on the screen.  The AES can provide you with a list of the
  559.  *  visible rectangles that comprise your window(s).  (Remember that not
  560.  *  all of a window you have open may be visible).  So, to process a 
  561.  *  redraw, you have to ask AES for each of the visible rectangles, and
  562.  *  for each one returned, see if it overlaps the screen area to be redrawn.
  563.  *
  564.  *  There is a library routine in AESFAST called 'rc_intersect' that will
  565.  *  compute the intersecting portion of 2 rectangular screen areas. If 
  566.  *  the rectangles don't overlap at all, it will return FALSE.  Thus, we
  567.  *  have a loop in which we ask the AES for each rectangle, and we check
  568.  *  it against the redraw rectangle, and if there is some overlap, we call
  569.  *  the routine which actually draws the window contents, passing that
  570.  *  routine the boundries of the intersecting rectangle.  The looping 
  571.  *  continues until the AES returns us a rectangle from the list that has
  572.  *  zero height and width.
  573.  *
  574.  *************************************************************************/
  575.  
  576. do_redraw(updtrect)
  577.         GRECT updtrect;         /* the full area that needs updating */
  578. {
  579.         GRECT listrect;         /* one of our visible areas */
  580.  
  581.         wind_get(wi_handle, WF_FIRSTXYWH,
  582.                   &listrect.g_x, &listrect.g_y, 
  583.                   &listrect.g_w, &listrect.g_h);
  584.                   
  585.         while ( listrect.g_w && listrect.g_h ) {
  586.                 if ( rc_intersect(&updtrect, &listrect) ) {
  587.                         draw_window(listrect);
  588.                 }
  589.                 wind_get(wi_handle, WF_NEXTXYWH, 
  590.                           &listrect.g_x, &listrect.g_y,
  591.                           &listrect.g_w, &listrect.g_h);
  592.         }
  593. }
  594.  
  595.  
  596. /**************************************************************************
  597.  *
  598.  * draw_window - Draw the contents of the window, with clipping.
  599.  *  In this case, we just do an objc_draw call on our tree, passing the
  600.  *  clipping rectangle we receive along to the objc_draw.
  601.  *
  602.  *************************************************************************/
  603.  
  604.  
  605. draw_window(cliprect)
  606. GRECT cliprect;
  607.         objc_draw(palttree, R_TREE, MAX_DEPTH, cliprect);
  608. }
  609.  
  610.  
  611. /**************************************************************************
  612.  *
  613.  * just for grins dept:  This is what a draw_window() routine might
  614.  *  look like if the window was not based upon an object tree.  I'm
  615.  *  assuming a really stupid window which has a circle and some blit-based
  616.  *  graphics in it.
  617.  *
  618.  *************************************************************************/
  619.  
  620. #if 0                           /* don't really compile this code... */
  621.  
  622. draw_vwindow(cliprect)
  623. GRECT cliprect;
  624. {
  625.         long  dmyfdb = 0L;
  626.         VRECT vdiclip;
  627.         struct {
  628.                 VRECT blit1rect;
  629.                 VRECT blit2rect;
  630.                 } blitarea;
  631.  
  632. /*
  633.  * convert the GRECT-type clipping rectangle (x/y/w/h) to a VRECT-type
  634.  * rectangle (x1,y1,x2,y2).  set the VDI clipping area, and call the
  635.  * VDI circle function.
  636.  */
  637.  
  638.         rc_gtov(&cliprect, &vdiclip);
  639.         vs_clip(vdi_handle, &vdiclip, TRUE);
  640.         v_circle(vdi_handle, x, y, r);
  641.  
  642. /*
  643.  * for the blit, I'm assuming the blit buffer is a 32k screen image, and
  644.  * you just want to blit the corresponding area back onto the screen. the
  645.  * MFDB structure describing the blit buffer has already been filled out
  646.  * before this routine is ever called <grin>.  (Obscure Fact Dept: for
  647.  * blitting to the screen, a full MFDB is not needed...one only needs
  648.  * a longword of zeroes, which is a key telling VDI to use the screen as
  649.  * the destination.)
  650.  *
  651.  * the blit routine needs a VRECT describing the source and another 
  652.  * describing the destination, and the docs always describe this as a 
  653.  * 'pxy array', so everybody defines pxy[8] and tediously loads all the
  654.  * array elements with x/y values.  structures in C place all the elements
  655.  * contiguously, so the 'blitarea' structure defined above is pretty much
  656.  * equivelent to using a pxy array, except the code is now *much* more
  657.  * readable.
  658.  */
  659.         
  660.         rc_gtov(&cliprect, &blitarea.blit1rect);
  661.         rc_gtov(&cliprect, &blitarea.blit2rect);
  662.         vro_cpyfm(vdi_handle, S_ONLY, &blitarea, &sourcefdb, &dmyfdb);
  663. }
  664.  
  665. #endif
  666.  
  667. /**************************************************************************
  668.  *
  669.  * do_msg - Handle a message returned by evnt_multi().
  670.  *  This is pretty standard message handling for an accessory.  One item of
  671.  *  interest I discovered when building this is that you should *not* 
  672.  *  attempt to close any open windows when you get an AC_CLOSED message.
  673.  *  This message apparently tells you that your windows have already been
  674.  *  closed and deleted, and you should just mark your window handle(s) as
  675.  *  no longer valid.
  676.  *
  677.  *  The only piece of weirdness here is the WM_MOVED case.  The window
  678.  *  provides a frame for our object tree, so when it gets moved, we have
  679.  *  to update the ob_x and ob_y values in the pallete tree to match (so
  680.  *  that objc_draw commands will draw inside the window's work area).
  681.  *  The values in msgbuf reflect the new x/y/w/h of the window's total 
  682.  *  size (borders and controls included).  We have the option of changing
  683.  *  these values (like snapping to a character grid or whatever) or even
  684.  *  of ignoring them, but in this instance we don't care about any of that
  685.  *  so we just tell AES to use the values directly.  After doing the 
  686.  *  wind_set call to set the new location of the window, we call wind_get
  687.  *  to find out the new x/y/w/h of the work area of the window, so that
  688.  *  we can reposition the object tree.  We don't have to redraw the
  689.  *  window contents during WM_MOVED processing, because the AES will blit
  690.  *  the window contents for us if it can.  If not all of the window can
  691.  *  be blitted, the AES will send redraw messages to us, and we'll get
  692.  *  them on the next iteration of the evnt_multi loop.
  693.  *************************************************************************/
  694.  
  695. do_msg(msgbuf)
  696. register int msgbuf[];
  697. {
  698.  
  699.         switch (msgbuf[0]) {
  700.  
  701.                 case AC_OPEN:
  702.                         if (msgbuf[4] == menu_id) 
  703.                                 open_window();
  704.                         break;
  705.  
  706.                 case AC_CLOSE:
  707.                         wi_handle = NO_WINDOW;
  708.                         break;
  709.  
  710.                 case WM_REDRAW:
  711.                         if (msgbuf[3] == wi_handle)
  712.                                 do_redraw(msgbuf[4], msgbuf[5],
  713.                                           msgbuf[6], msgbuf[7]);
  714.                         break;
  715.  
  716.                 case WM_NEWTOP:
  717.                 case WM_TOPPED:
  718.                         if (msgbuf[3] == wi_handle) 
  719.                                 wind_set(wi_handle, WF_TOP, 0L, 0L);
  720.                         break;
  721.  
  722.                 case WM_CLOSED:
  723.                         close_window();
  724.                         break;
  725.  
  726.                 case WM_MOVED:
  727.                         if(msgbuf[3] == wi_handle) {
  728.                                 wind_set(wi_handle, WF_CURRXYWH, 
  729.                                           msgbuf[4], msgbuf[5],
  730.                                           msgbuf[6], msgbuf[7]);
  731.                                 wind_get(wi_handle, WF_WORKXYWH,
  732.                                           &treerect.g_x, &treerect.g_y, 
  733.                                           &treerect.g_w, &treerect.g_h);
  734.                                 palttree->ob_x = treerect.g_x;
  735.                                 palttree->ob_y = treerect.g_y;                 
  736.                         }
  737.                         break;
  738.  
  739.                 } /* END switch (msgbuf[0]) */
  740. }
  741.  
  742. /**************************************************************************
  743.  *
  744.  * do_btn - Handle a button click within our window.
  745.  *  Do a graf_mkstate() call to get the most-current location of the
  746.  *  mouse.  Call objc_find() to see if the mouse is located over an object
  747.  *  in our tree.  If so, we determine the parent of the tree.  If the
  748.  *  parent is one of the boxes which holds our various radio buttons, we
  749.  *  go process the button, as appropriate.  If it is over an object of
  750.  *  ours, but not within a parent box, we just ignore the click.
  751.  *
  752.  *************************************************************************/
  753.  
  754. do_btn()
  755. {
  756.         int mouse_x;
  757.         int mouse_y;
  758.         int selobject;
  759.         int dmy;
  760.         
  761.         graf_mkstate(&mouse_x, &mouse_y, &dmy, &dmy);
  762.  
  763.         selobject = objc_find(palttree, R_TREE, MAX_DEPTH, mouse_x, mouse_y);
  764.  
  765.         if (selobject != -1) {
  766.                 switch (obj_parent(palttree, selobject)) {
  767.                         case PALTPCOL: 
  768.                                 new_color(selobject, TRUE);
  769.                                 break;
  770.                         case PALTPRED: 
  771.                         case PALTPGRN:
  772.                         case PALTPBLU:
  773.                                 new_settings(selobject);
  774.                                 break;
  775.                 } /* END switch (obj_parent(selobject)) */
  776.         } /* END if (selobject != -1) */
  777. }
  778.  
  779. /**************************************************************************
  780.  *
  781.  * main routine
  782.  *  Call the init routine, then fall into a do-forever evnt_multi() loop.
  783.  *
  784.  *************************************************************************/
  785.  
  786. main()
  787. {
  788.         int dmy;
  789.         int event;
  790.         int msgbuf[8];
  791.         
  792.         prg_init();
  793.  
  794.         while (TRUE) {
  795.                 event = evnt_multi(
  796.                          MU_MESAG | MU_BUTTON,
  797.                          1,1,1,               /* mbclicks, mbmask, mbstate*/
  798.                          0,0,0,0,0,           /* Mouse event rectangle 1  */
  799.                          0,0,0,0,0,           /* Mouse event rectangle 2  */
  800.                          msgbuf,              /* Message buffer           */
  801.                          0,0,                 /* timer event, time = 0,0  */
  802.                          &dmy, &dmy,          /* Mouse x & y at event     */
  803.                          &dmy,                /* Mouse button at event    */
  804.                          &dmy,                /* Keystate at event        */           
  805.                          &dmy,                /* Keypress at event        */
  806.                          &dmy);               /* Mouse click count        */
  807.  
  808.                 wind_update(BEG_UPDATE);
  809.  
  810.                 if (event & MU_MESAG)
  811.                         do_msg(msgbuf);
  812.                 
  813.                 if (event & MU_BUTTON) 
  814.                         do_btn();
  815.                 
  816.                 wind_update(END_UPDATE);
  817.         
  818.         } /* END while (TRUE) */
  819. }
  820.