home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Environments / Frontier 4.0.1 / Frontier SDK 4.0b2 / Sample Code / BarChart / barchart.c next >
Encoding:
C/C++ Source or Header  |  1996-01-25  |  24.0 KB  |  1,251 lines  |  [TEXT/CWIE]

  1.  
  2. /*© copyright 1991-96 UserLand Software, Inc. All Rights Reserved.*/
  3.  
  4.  
  5. #include <applet.h>
  6.  
  7. /*
  8. these are the IAC messages that BarChart can receive from Frontier scripts.
  9.  
  10. for the other side of this interface, check out system.verbs.apps.BarChart in
  11. Frontier.root.
  12. */
  13.     #define setbarvaluetoken     'sval'
  14.     #define getbarvaluetoken     'gval'
  15.     #define setbarlabeltoken     'slab'
  16.     #define getbarlabeltoken     'glab'
  17.     #define setbartoken            'sbar'
  18.     #define addbartoken         'abar'
  19.     #define setunitstoken        'sunt'
  20.     #define setbarcounttoken    'scnt'
  21.     #define getbarcounttoken    'gcnt'
  22.     #define updatetoken            'updt'
  23.     
  24.  
  25. #define minwindowwidth 100 /*for zooming windows*/
  26.  
  27. #define labelcolor blackindex /*draw labels in black, other colors look flaky*/
  28.  
  29. #define firstbarcolor 8 /*start of a set of bold colors*/
  30.  
  31. RGBColor backgroundcolor = {52428, 65535, 52428}; /*a soft green color*/
  32.  
  33.  
  34. #define maxbars 25
  35.  
  36. typedef long tyvalues [maxbars]; /*holds an array worth of values*/
  37.  
  38. #define maxlabelchars 32
  39.  
  40.  
  41. typedef struct tybarrecord {
  42.     
  43.     boolean flhasbeenset: 1; /*avoid displaying if it's never been assigned to*/
  44.     
  45.     boolean fldirty: 1; /*the bar needs updating, watch for this in the idle callback*/
  46.     
  47.     long value;
  48.     
  49.     char label [maxlabelchars];
  50.     } tybarrecord;
  51.  
  52.  
  53. typedef struct tybarchartrecord {
  54.     
  55.     short versionnumber; /*this structure is saved on disk*/
  56.     
  57.     PicHandle backgroundpicture; /*picture displayed behind bars*/
  58.     
  59.     bigstring barunits; /*concatenated at the end of every displayed value*/
  60.     
  61.     short ctbars; /*number of bars in the chart*/
  62.     
  63.     long minvalue, maxvalue; /*the range of values*/
  64.     
  65.     short pixelsbetweenbars; /*how much space between the bars?*/
  66.     
  67.     short onebarwidth; /*how wide is one of the bars?*/
  68.     
  69.     short maxbarheight; /*max height in pixels of a bar*/
  70.     
  71.     short horizbaseline; /*the bottom edge of all the bars*/
  72.     
  73.     short vertbaseline; /*the left edge of the first bar*/
  74.     
  75.     short labelfont, labelsize, labelstyle; /*how are labels drawn?*/
  76.     
  77.     short labelbaseline; /*the horiz baseline for bar labels*/
  78.     
  79.     short labellineheight; /*vertical pixels for a label*/
  80.     
  81.     tybarrecord bars [maxbars];
  82.     } tybarchartrecord, *ptrbarchartrecord, **hdlbarchartrecord;
  83.     
  84.     
  85. bigstring bsbarchartsearch; /*see selectbarchartwindow*/
  86.  
  87. #define pictmargin 20 /*leave this much room on all sides of chart*/
  88.  
  89. boolean flbitmap = false; /*true if an offscreen bitmap is open*/
  90.  
  91.  
  92.  
  93.  
  94. static boolean isFrontProcess () {
  95.     
  96.     ProcessSerialNumber currentprocess, frontprocess;
  97.     Boolean fl;
  98.     
  99.     GetCurrentProcess (¤tprocess);
  100.     
  101.     GetFrontProcess (&frontprocess);
  102.     
  103.     SameProcess (¤tprocess, &frontprocess, &fl);
  104.     
  105.     return (fl);
  106.     } /*isFrontProcess*/
  107.     
  108.     
  109. static boolean isActiveWindow (hdlappwindow appwindow) {
  110.     
  111.     if (!isFrontProcess ())
  112.         return (false);
  113.     
  114.     return (FrontWindow () == (**appwindow).macwindow);
  115.     } /*isActiveWindow*/
  116.     
  117.     
  118. static RGBColor *getBackgroundColor (hdlappwindow appwindow) {
  119.     
  120.     if (isActiveWindow (appwindow))
  121.         return (&backgroundcolor);
  122.     else
  123.         return (&whitecolor);
  124.     } /*getBackgroundColor*/
  125.     
  126.     
  127. static void pushlabelstyle (void) {
  128.     
  129.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  130.     
  131.     pushstyle ((**hb).labelfont, (**hb).labelsize, (**hb).labelstyle);
  132.     } /*pushlabelstyle*/
  133.     
  134.     
  135. static boolean setchartconsts (void) {
  136.     
  137.     /*
  138.     set values for the computed and constant fields of the barchart record.
  139.     
  140.     assume non-computed fields have been set and are accurate.
  141.     */
  142.     
  143.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  144.     hdlappwindow ha = app.appwindow;
  145.     short totalwidth;
  146.     short ctbars = (**hb).ctbars;
  147.     Rect r;
  148.     
  149.     (**hb).pixelsbetweenbars = 10;
  150.     
  151.     (**hb).labelfont = geneva;
  152.     
  153.     (**hb).labelsize = 9;
  154.     
  155.     (**hb).labelstyle = bold;
  156.     
  157.     pushlabelstyle ();
  158.     
  159.     (**hb).labellineheight = globalfontinfo.ascent + globalfontinfo.descent;
  160.     
  161.     popstyle ();
  162.     
  163.     r = (**ha).windowrect;
  164.     
  165.     totalwidth = (**ha).windowhorizpixels - (2 * pictmargin);
  166.     
  167.     totalwidth -= (ctbars + 1) * (**hb).pixelsbetweenbars;
  168.     
  169.     if (ctbars <= 0) 
  170.         (**hb).onebarwidth = 0; /*defensive driving*/
  171.     else
  172.         (**hb).onebarwidth = totalwidth / ctbars;
  173.     
  174.     (**hb).labelbaseline = r.bottom - pictmargin;
  175.     
  176.     (**hb).horizbaseline = r.bottom - pictmargin - (2 * (**hb).labellineheight);
  177.     
  178.     (**hb).maxbarheight = (**hb).horizbaseline - r.top - pictmargin;
  179.     
  180.     (**hb).vertbaseline = r.left + pictmargin;
  181.     
  182.     return (true);
  183.     } /*setchartconsts*/
  184.     
  185.     
  186. static short getbarleftedge (short barnum) {
  187.  
  188.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  189.  
  190.     return ( 
  191.         (**hb).vertbaseline + 
  192.         
  193.         ((**hb).pixelsbetweenbars * (barnum + 1)) + 
  194.         
  195.         ((**hb).onebarwidth * barnum));
  196.     } /*getbarleftedge*/
  197.     
  198.  
  199. static boolean drawbar (short barnumber) {
  200.     
  201.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  202.     hdlappwindow ha = app.appwindow;
  203.     short barnum = barnumber;
  204.     short maxbarheight = (**hb).maxbarheight;
  205.     long value = (**hb).bars [barnum].value;
  206.     long maxvalue = (**hb).maxvalue;
  207.     short whitearea;
  208.     Rect rbar, rwindow;
  209.     RGBColor rgb;
  210.     boolean flclosebitmap = false;
  211.     
  212.     if (!(**hb).bars [barnum].flhasbeenset)
  213.         return (true);
  214.         
  215.     rwindow = (**ha).windowrect;
  216.     
  217.     rbar.left = getbarleftedge (barnum);
  218.         
  219.     rbar.right = rbar.left + (**hb).onebarwidth;
  220.     
  221.     rbar.bottom = (**hb).horizbaseline;
  222.     
  223.     rbar.top = rbar.bottom - maxbarheight;
  224.     
  225.     if (!flbitmap) {
  226.         
  227.         flbitmap = appopenbitmap (rbar, ha);
  228.         
  229.         flclosebitmap = true;
  230.         }
  231.         
  232.     oldclutconverter (firstbarcolor + barnumber, &rgb);
  233.     
  234.     pushforecolor (&rgb); 
  235.     
  236.     pushbackcolor (getBackgroundColor (ha));
  237.     
  238.     EraseRect (&rbar);
  239.     
  240.     if (maxvalue == 0) /*avoid divide by zero error*/
  241.         whitearea = 0;
  242.         
  243.     else { /*do arithmetic with longs*/
  244.         
  245.         long l1 = maxvalue - value;
  246.         long l2 = maxbarheight;
  247.         long l3 = maxvalue;
  248.         long l4 = (l1 * l2) / l3;
  249.         
  250.         whitearea = (short) l4;
  251.         }
  252.     
  253.     if (whitearea > 0)
  254.         rbar.top += whitearea;
  255.     
  256.     if (isActiveWindow (ha))
  257.         FillRect (&rbar, &quickdrawglobal (gray));
  258.     else 
  259.         FillRect (&rbar, &quickdrawglobal (ltGray));        
  260.     
  261.     pushpen ();
  262.     
  263.     PenPat (&quickdrawglobal (black));
  264.  
  265.     FrameRect (&rbar);
  266.     
  267.     poppen ();
  268.     
  269.     popbackcolor ();
  270.     
  271.     popforecolor ();
  272.     
  273.     if (flclosebitmap) {
  274.         
  275.         appclosebitmap (ha);
  276.         
  277.         flbitmap = false;
  278.         }
  279.     
  280.     return (true);
  281.     } /*drawbar*/
  282.     
  283.     
  284. static boolean drawlabel (short barnumber) {
  285.     
  286.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  287.     hdlappwindow ha = app.appwindow;
  288.     short lh = (**hb).labellineheight;
  289.     bigstring bs;
  290.     Rect r;
  291.     boolean flclosebitmap = false;
  292.     
  293.     if (!(**hb).bars [barnumber].flhasbeenset)
  294.         return (true);
  295.         
  296.     copystring ((**hb).bars [barnumber].label, bs);
  297.     
  298.     r.left = getbarleftedge (barnumber);
  299.         
  300.     r.right = r.left + (**hb).onebarwidth;
  301.     
  302.     r.bottom = (**hb).labelbaseline - lh;
  303.     
  304.     r.top = r.bottom - lh;
  305.     
  306.     if (!flbitmap) {
  307.         
  308.         Rect rbitmap = r;
  309.         
  310.         rbitmap.bottom += lh;
  311.         
  312.         flbitmap = appopenbitmap (rbitmap, ha);
  313.         
  314.         flclosebitmap = true;
  315.         }
  316.         
  317.     pushforecolor (&blackcolor); 
  318.     
  319.     pushbackcolor (getBackgroundColor (ha));
  320.         
  321.     pushlabelstyle ();
  322.     
  323.     EraseRect (&r);
  324.     
  325.     centerstring (r, bs);
  326.     
  327.     r.bottom += lh;
  328.     
  329.     r.top += lh;
  330.     
  331.     NumToString ((**hb).bars [barnumber].value, bs);
  332.     
  333.     pushstring ((**hb).barunits, bs);
  334.         
  335.     EraseRect (&r);
  336.     
  337.     centerstring (r, bs);
  338.     
  339.     popstyle ();
  340.     
  341.     popbackcolor ();
  342.     
  343.     popforecolor ();
  344.     
  345.     if (flclosebitmap) {
  346.         
  347.         appclosebitmap (ha);
  348.         
  349.         flbitmap = false;
  350.         }
  351.     
  352.     return (true);
  353.     } /*drawlabel*/
  354.     
  355.     
  356. static void drawbarchart (void) {
  357.     
  358.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  359.     short i;
  360.     
  361.     for (i = 0; i < (**hb).ctbars; i++) {
  362.         
  363.         drawbar (i);
  364.         
  365.         drawlabel (i);
  366.         } /*for*/
  367.     } /*drawbarchart*/
  368.     
  369.  
  370. static void drawfreemem (void) {
  371.     
  372.     Rect r;
  373.     Str255 s;
  374.     
  375.     pushbackcolor (getBackgroundColor (app.appwindow));
  376.     
  377.     r = (**app.appwindow).windowrect;
  378.     
  379.     r.top = r.bottom - 15;
  380.     
  381.     r.right -= 20;
  382.     
  383.     EraseRect (&r);
  384.     
  385.     NumToString (FreeMem () / 1024, s);
  386.     
  387.     MoveTo (r.left + 3, r.bottom - 3);
  388.     
  389.     setfontsizestyle (geneva, 9, 0);
  390.     
  391.     DrawString (s);
  392.     
  393.     DrawString ("\pK");
  394.     
  395.     popbackcolor ();
  396.     } /*drawfreemem*/
  397.     
  398.     
  399. static boolean setminmax (void) {
  400.     
  401.     /*
  402.     examine the values array, and reset the min and max, if necessary.
  403.     
  404.     return true if at least one changed, false otherwise.
  405.     */
  406.     
  407.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  408.     long newmax, newmin;
  409.     long val;
  410.     short i;
  411.     
  412.     newmax = intminusinfinity; /*assume only short values*/
  413.     
  414.     for (i = 0; i < (**hb).ctbars; i++) {
  415.         
  416.         val = (**hb).bars [i].value;
  417.         
  418.         if (val > newmax)
  419.             newmax = val;
  420.         } /*for*/
  421.             
  422.     newmin = intinfinity; /*assume only short values*/
  423.     
  424.     for (i = 0; i < (**hb).ctbars; i++) {
  425.         
  426.         val = (**hb).bars [i].value;
  427.         
  428.         if (val < newmin)
  429.             newmin = val;
  430.         } /*for*/
  431.             
  432.     if ((newmax != (**hb).maxvalue) || (newmin != (**hb).minvalue)) {
  433.         
  434.         (**hb).maxvalue = newmax;
  435.         
  436.         (**hb).minvalue = newmin;
  437.         
  438.         return (true);
  439.         }
  440.     
  441.     return (false); /*no change*/
  442.     } /*setminmax*/
  443.     
  444.     
  445. static void smashchartdisplay (boolean flerase) {
  446.  
  447.     hdlappwindow ha = app.appwindow;
  448.  
  449.     setchartconsts (); /*reset all the drawing parameters*/
  450.     
  451.     setminmax (); /*min and max might have changed*/
  452.     
  453.     invalappwindow (ha, flerase);
  454.     
  455.     updateappwindow (ha);
  456.     } /*smashchartdisplay*/
  457.     
  458.  
  459. static boolean setbarunits (bigstring bs) {
  460.     
  461.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  462.  
  463.     copystring (bs, (**hb).barunits);
  464.     
  465.     smashchartdisplay (false); /*redraw the whole thing*/
  466.     
  467.     (**app.appwindow).flmadechanges = true;
  468.     
  469.     return (true);
  470.     } /*setbarunits*/
  471.     
  472.     
  473. static boolean setbarvalue (short barnumber, long barvalue) {
  474.     
  475.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  476.  
  477.     if ((barnumber < 0) || (barnumber >= (**hb).ctbars)) /*defensive driving*/
  478.         return (false);
  479.     
  480.     (**hb).bars [barnumber].value = barvalue;
  481.     
  482.     (**hb).bars [barnumber].flhasbeenset = true;
  483.     
  484.     if (setminmax ())
  485.         smashchartdisplay (false); /*redraw the whole thing*/
  486.         
  487.     else {
  488.         drawbar (barnumber);
  489.     
  490.         drawlabel (barnumber);
  491.         }
  492.     
  493.     (**app.appwindow).flmadechanges = true;
  494.  
  495.     return (true);
  496.     } /*setbarvalue*/
  497.     
  498.  
  499. static boolean getbarvalue (short barnumber, long *barvalue) {
  500.     
  501.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  502.  
  503.     *barvalue = 0; /*default returned value*/
  504.     
  505.     if ((barnumber < 0) || (barnumber >= (**hb).ctbars)) /*defensive driving*/
  506.         return (false);
  507.     
  508.     *barvalue = (**hb).bars [barnumber].value;
  509.     
  510.     return (true);
  511.     } /*getbarvalue*/
  512.     
  513.     
  514. static boolean setallvalues (short ct, tyvalues vals) {
  515.     
  516.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  517.     short i;
  518.     
  519.     for (i = 0; i < ct; i++) {
  520.     
  521.         (**hb).bars [i].value = vals [i];
  522.         
  523.         (**hb).bars [i].flhasbeenset = true;
  524.         } /*for*/
  525.         
  526.     setminmax ();
  527.     
  528.     smashchartdisplay (false); /*redraw the whole thing*/
  529.     
  530.     (**app.appwindow).flmadechanges = true;
  531.  
  532.     return (true);
  533.     } /*setallvalues*/
  534.     
  535.     
  536. static boolean setbarlabel (short barnumber, bigstring bslabel) {
  537.     
  538.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  539.     
  540.     if ((barnumber < 0) || (barnumber >= (**hb).ctbars)) /*defensive driving*/
  541.         return (false);
  542.         
  543.     copystring (bslabel, (**hb).bars [barnumber].label);
  544.     
  545.     (**hb).bars [barnumber].flhasbeenset = true;
  546.     
  547.     drawlabel (barnumber);
  548.     
  549.     (**app.appwindow).flmadechanges = true;
  550.     
  551.     return (true);
  552.     } /*setbarlabel*/
  553.     
  554.  
  555. static boolean setbar (short barnumber, bigstring bslabel, long barvalue) {
  556.     
  557.     /*
  558.     sets both the label and the value for the indicated bar.
  559.     
  560.     this is provided so that a single IAC call can set both.
  561.     */
  562.     
  563.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  564.  
  565.     if ((barnumber < 0) || (barnumber >= (**hb).ctbars)) /*defensive driving*/
  566.         return (false);
  567.     
  568.     if (!setbarlabel (barnumber, bslabel))
  569.         return (false);
  570.         
  571.     return (setbarvalue (barnumber, barvalue));
  572.     } /*setbar*/
  573.     
  574.     
  575. static short addbar (bigstring bslabel, long barvalue) {
  576.     
  577.     /*
  578.     returns the number of the new bar, -1 if it failed.
  579.     */
  580.     
  581.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  582.     short barnumber = (**hb).ctbars;
  583.     
  584.     (**hb).ctbars++;
  585.     
  586.     setbarvalue (barnumber, barvalue);
  587.     
  588.     if (!setbarlabel (barnumber, bslabel)) {
  589.         
  590.         (**hb).ctbars--;
  591.         
  592.         return (-1);
  593.         }
  594.     
  595.     smashchartdisplay (true);
  596.     
  597.     (**app.appwindow).flmadechanges = true;
  598.  
  599.     return (barnumber);
  600.     } /*addbar*/
  601.     
  602.  
  603. static boolean getbarlabel (short barnumber, bigstring bslabel) {
  604.     
  605.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  606.     
  607.     setemptystring (bslabel); /*default returned value*/
  608.     
  609.     if ((barnumber < 0) || (barnumber >= (**hb).ctbars)) /*defensive driving*/
  610.         return (false);
  611.     
  612.     copystring ((**hb).bars [barnumber].label, bslabel);
  613.     
  614.     return (true);
  615.     } /*getbarlabel*/
  616.     
  617.  
  618. static boolean resetbarchartwindow (short ctbars) {
  619.     
  620.     (**(hdlbarchartrecord) app.appdata).ctbars = ctbars;
  621.     
  622.     smashchartdisplay (false);
  623.     
  624.     (**app.appwindow).flmadechanges = true;
  625.  
  626.     return (true);
  627.     } /*resetbarchartwindow*/
  628.     
  629.     
  630. static boolean bcnewrecord (void) {
  631.     
  632.     hdlbarchartrecord hb;
  633.     short i;
  634.     
  635.     if (!newclearhandle (longsizeof (tybarchartrecord), (Handle *) &app.appdata))
  636.         return (false);
  637.         
  638.     hb = (hdlbarchartrecord) app.appdata;
  639.     
  640.     (**hb).versionnumber = 1;
  641.     
  642.     (**hb).ctbars = 0;
  643.     
  644.     (**hb).minvalue = 0;
  645.     
  646.     (**hb).maxvalue = 0;
  647.     
  648.     (**hb).pixelsbetweenbars = 10;
  649.     
  650.     for (i = 0; i < maxbars; i++) {
  651.         
  652.         (**hb).bars [i].value = 0;
  653.         
  654.         setstringlength ((**hb).bars [i].label, 0);
  655.         } /*for*/
  656.     
  657.     setchartconsts ();
  658.     
  659.     return (true);
  660.     } /*bcnewrecord*/
  661.  
  662.  
  663. static boolean bcdisposerecord (void) {
  664.     
  665.     disposehandle ((Handle) app.appdata);
  666.         
  667.     return (true);
  668.     } /*bcdisposerecord*/
  669.     
  670.     
  671. static boolean bcadjustcursor (void) {
  672.  
  673.     arrowcursor (); /*BarChart's "adjust cursor" is pretty simple*/
  674.     
  675.     return (true);
  676.     } /*bcadjustcursor*/
  677.  
  678.  
  679. static boolean bcwindowresize (void) {
  680.  
  681.     setchartconsts (); /*reset all computed values*/
  682.     
  683.     return (true);
  684.     } /*bcwindowresize*/
  685.     
  686.  
  687. static boolean bcactivate (boolean flactive) {
  688.     
  689.     hdlappwindow ha = app.appwindow;
  690.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  691.     
  692.     if (hb == nil) /*no data, it can't be our window*/
  693.         return (false);
  694.         
  695.     invalappwindow (ha, false);
  696.         
  697.     return (true);
  698.     } /*bcactivate*/
  699.     
  700.     
  701. static boolean bcupdate (void) {
  702.     
  703.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  704.     hdlappwindow ha = app.appwindow;
  705.     Rect rcontent = (**ha).contentrect;
  706.     
  707.     if (hb == nil) /*no data, it can't be our window*/
  708.         return (false);
  709.         
  710.     flbitmap = appopenbitmap ((**ha).windowrect, ha);
  711.     
  712.     pushbackcolor (getBackgroundColor (ha));
  713.     
  714.     /*erase everything but the size box -- new in 3.0*/ {
  715.         
  716.         Rect r = rcontent;
  717.         short sizegrow = 16;
  718.         
  719.         r.right -= sizegrow;
  720.         
  721.         r.bottom -= sizegrow;
  722.         
  723.         EraseRect (&r);
  724.     
  725.         r = rcontent;
  726.         
  727.         r.top = r.bottom - sizegrow;
  728.         
  729.         r.right -= sizegrow;
  730.         
  731.         EraseRect (&r);
  732.         
  733.         r = rcontent;
  734.         
  735.         r.left = r.right - sizegrow;
  736.         
  737.         r.bottom -= sizegrow;
  738.         
  739.         EraseRect (&r);
  740.         }
  741.     
  742.     DrawPicture ((**hb).backgroundpicture, &rcontent);
  743.     
  744.     drawbarchart ();
  745.     
  746.     drawfreemem ();
  747.     
  748.     popbackcolor ();
  749.     
  750.     if (flbitmap)
  751.         appclosebitmap (ha);
  752.         
  753.     flbitmap = false;
  754.         
  755.     return (true);
  756.     } /*bcupdate*/
  757.     
  758.     
  759. static void allbarsdirty (void) {
  760.     
  761.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  762.     short i;
  763.     
  764.     for (i = 0; i < (**hb).ctbars; i++) 
  765.         (**hb).bars [i].fldirty = true;
  766.     } /*bcidle*/
  767.     
  768.  
  769. static boolean setbarvalueverb (void) {
  770.     
  771.     /*
  772.     verb that sets the value of one of the bars in the target window.
  773.     */
  774.     
  775.     short barnumber;
  776.     long barvalue;
  777.     
  778.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  779.         return (false);
  780.         
  781.     if (!IACgetshortparam (keyDirectObject, &barnumber))
  782.         return (false);
  783.         
  784.     barnumber--; /*our IAC interface is 1-based, internally we're 0-based*/
  785.         
  786.     if (!IACgetlongparam ('vbar', &barvalue))
  787.         return (false);
  788.         
  789.     return (IACreturnboolean (setbarvalue (barnumber, barvalue)));
  790.     } /*setbarvalueverb*/
  791.     
  792.  
  793. static boolean getbarvalueverb (void) {
  794.     
  795.     /*
  796.     verb that returns the value of one of the bars in the target window.
  797.     */
  798.     
  799.     short barnumber;
  800.     long barvalue;
  801.     
  802.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  803.         return (false);
  804.         
  805.     if (!IACgetshortparam (keyDirectObject, &barnumber))
  806.         return (false);
  807.         
  808.     barnumber--; /*our IAC interface is 1-based, internally we're 0-based*/
  809.         
  810.     getbarvalue (barnumber, &barvalue);
  811.         
  812.     return (IACreturnlong (barvalue));
  813.     } /*getbarvalueverb*/
  814.     
  815.  
  816. static boolean setbarverb (void) {
  817.     
  818.     /*
  819.     verb that sets both the value and label of one of the bars in the
  820.     target window.
  821.     */
  822.     
  823.     short barnumber;
  824.     bigstring bslabel;
  825.     long barvalue;
  826.     
  827.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  828.         return (false);
  829.         
  830.     if (!IACgetshortparam (keyDirectObject, &barnumber))
  831.         return (false);
  832.         
  833.     barnumber--; /*our IAC interface is 1-based, internally we're 0-based*/
  834.         
  835.     if (!IACgetstringparam ('lbar', bslabel))
  836.         return (false);
  837.         
  838.     if (!IACgetlongparam ('vbar', &barvalue))
  839.         return (false);
  840.  
  841.     return (IACreturnboolean (setbar (barnumber, bslabel, barvalue)));
  842.     } /*setbarverb*/
  843.     
  844.     
  845. static boolean setbarlabelverb (void) {
  846.     
  847.     /*
  848.     verb that sets the label of one of the bars in the target window.
  849.     */
  850.     
  851.     short barnumber;
  852.     bigstring bslabel;
  853.     
  854.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  855.         return (false);
  856.         
  857.     if (!IACgetshortparam (keyDirectObject, &barnumber))
  858.         return (false);
  859.         
  860.     barnumber--; /*our IAC interface is 1-based, internally we're 0-based*/
  861.         
  862.     if (!IACgetstringparam ('lbar', bslabel))
  863.         return (false);
  864.         
  865.     return (IACreturnboolean (setbarlabel (barnumber, bslabel)));
  866.     } /*setbarlabelverb*/
  867.     
  868.     
  869. static boolean addbarverb (void) {
  870.     
  871.     /*
  872.     verb that adds a new bar to the target window with indicated label and
  873.     value.
  874.     */
  875.     
  876.     bigstring bslabel;
  877.     long barvalue;
  878.     
  879.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  880.         return (false);
  881.         
  882.     if (!IACgetstringparam (keyDirectObject, bslabel))
  883.         return (false);
  884.         
  885.     if (!IACgetlongparam ('vbar', &barvalue))
  886.         return (false);
  887.         
  888.     return (IACreturnshort (addbar (bslabel, barvalue) + 1));
  889.     } /*addbarverb*/
  890.     
  891.     
  892. static boolean setbarcountverb (void) {
  893.     
  894.     /*
  895.     changes the number of bars in the target window.
  896.     */
  897.     
  898.     short ctbars;
  899.     
  900.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  901.         return (false);
  902.         
  903.     if (!IACgetshortparam (keyDirectObject, &ctbars))
  904.         return (false);
  905.         
  906.     return (IACreturnboolean (resetbarchartwindow (ctbars)));
  907.     } /*setbarcountverb*/
  908.     
  909.  
  910. static boolean getbarcountverb (void) {
  911.     
  912.     /*
  913.     returns the number of bars in the target window.
  914.     */
  915.     
  916.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  917.         return (false);
  918.         
  919.     return (IACreturnshort ((**(hdlbarchartrecord) app.appdata).ctbars));
  920.     } /*getbarcountverb*/
  921.     
  922.  
  923. static boolean setunitsverb (void) {
  924.     
  925.     /*
  926.     sets the units string of the target window.  this string is displayed
  927.     with the value of each of the bars.
  928.     */
  929.     
  930.     bigstring bs;
  931.     
  932.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  933.         return (false);
  934.         
  935.     if (!IACgetstringparam (keyDirectObject, bs))
  936.         return (false);
  937.     
  938.     setbarunits (bs);
  939.         
  940.     return (IACreturnboolean (true));
  941.     } /*setunitsverb*/
  942.     
  943.     
  944. static boolean getbarlabelverb (void) {
  945.     
  946.     /*
  947.     returns the label of one of the bars in the target window.  you provide
  948.     us with a bar number.
  949.     */
  950.     
  951.     short barnumber;
  952.     bigstring barlabel;
  953.     
  954.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  955.         return (false);
  956.         
  957.     if (!IACgetshortparam (keyDirectObject, &barnumber))
  958.         return (false);
  959.         
  960.     barnumber--; /*our IAC interface is 1-based, internally we're 0-based*/
  961.         
  962.     getbarlabel (barnumber, barlabel);
  963.         
  964.     return (IACreturnstring (barlabel));
  965.     } /*getbarlabelverb*/
  966.     
  967.  
  968. static boolean bciacmessage (void) {
  969.     
  970.     switch (IACgetverbtoken ()) {
  971.         
  972.         case setbarvaluetoken:
  973.             setbarvalueverb (); break;
  974.         
  975.         case getbarvaluetoken:
  976.             getbarvalueverb (); break;
  977.             
  978.         case setbarlabeltoken:
  979.             setbarlabelverb (); break;
  980.             
  981.         case setbartoken:
  982.             setbarverb (); break;
  983.             
  984.         case getbarlabeltoken:
  985.             getbarlabelverb (); break;
  986.         
  987.         case addbartoken:
  988.             addbarverb (); break;
  989.             
  990.         case setunitstoken:
  991.             setunitsverb (); break;
  992.                 
  993.         case setbarcounttoken:
  994.             setbarcountverb (); break;        
  995.             
  996.         case getbarcounttoken:
  997.             getbarcountverb (); break;    
  998.             
  999.         case updatetoken:
  1000.             drawbarchart (); break;
  1001.             
  1002.         default:
  1003.             IACnothandlederror (); break;
  1004.         } /*switch*/
  1005.         
  1006.     return (false);
  1007.     } /*bciacmessage*/
  1008.     
  1009.     
  1010. static boolean bcpack (hpacked) Handle *hpacked; {
  1011.     
  1012.     hdlbarchartrecord hb;
  1013.     
  1014.     if (!copyhandle (app.appdata, hpacked)) 
  1015.         return (false);
  1016.         
  1017.     hb = (hdlbarchartrecord) *hpacked;
  1018.     
  1019.     return (true);
  1020.     } /*bcpack*/
  1021.     
  1022.  
  1023. static boolean bcunpack (hpacked) Handle hpacked; {
  1024.     
  1025.     hdlbarchartrecord hb = (hdlbarchartrecord) hpacked;
  1026.     hdlbarchartrecord hcopy;
  1027.     
  1028.     if ((**hb).versionnumber != 1)
  1029.         return (false);
  1030.         
  1031.     if (!copyhandle ((Handle) hb, (Handle *) &hcopy))
  1032.         return (false);
  1033.         
  1034.     disposehandle (app.appdata);
  1035.     
  1036.     app.appdata = (Handle) hcopy;
  1037.     
  1038.     setchartconsts (); /*reset all computed values*/
  1039.         
  1040.     return (true);
  1041.     } /*bcunpack*/
  1042.     
  1043.     
  1044. static boolean bcgetpicture (hpicture) PicHandle *hpicture; {
  1045.     
  1046.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  1047.     hdlappwindow ha = app.appwindow;
  1048.     Rect r = (**ha).contentrect;
  1049.     
  1050.     *hpicture = nil; /*return value if error*/
  1051.     
  1052.     if (hb == nil) /*no data, it can't be our window*/
  1053.         return (false);
  1054.     
  1055.     *hpicture = OpenPicture (&r);
  1056.     
  1057.     ClipRect (&r);
  1058.     
  1059.     drawbarchart ();
  1060.     
  1061.     ClosePicture ();
  1062.     
  1063.     return (true);
  1064.     } /*bcgetpicture*/
  1065.     
  1066.  
  1067. static boolean bcputpicture (hpicture) PicHandle hpicture; {
  1068.     
  1069.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  1070.     
  1071.     (**hb).backgroundpicture = hpicture;
  1072.     
  1073.     bcupdate ();
  1074.     
  1075.     return (true);
  1076.     } /*bcputpicture*/
  1077.  
  1078.  
  1079. static boolean bcopenprint (void) {
  1080.     
  1081.     app.printinfo.ctpages = 1;
  1082.     
  1083.     return (true);
  1084.     } /*bcopenprint*/
  1085.  
  1086.  
  1087. static boolean bccloseprint (void) {
  1088.     
  1089.     setchartconsts (); /*restore drawing parameters*/
  1090.     
  1091.     return (true);
  1092.     } /*bccloseprint*/
  1093.  
  1094.  
  1095. static boolean bcprintpage (pagenumber) short pagenumber; {
  1096.     
  1097.     setchartconsts (); /*reset all the drawing parameters*/
  1098.     
  1099.     drawbarchart ();
  1100.     
  1101.     return (true);
  1102.     } /*bcprintpage*/
  1103.     
  1104.     
  1105. static boolean bchaveselection (void) {
  1106.     
  1107.     return (false); /*no selection in BarChart*/
  1108.     } /*bchaveselection*/
  1109.     
  1110.     
  1111. static boolean bcselectall (void) {
  1112.     
  1113.     return (false); /*no selection in BarChart*/
  1114.     } /*bcselectall*/
  1115.     
  1116.     
  1117. static boolean bcgetcontentsize (void) { 
  1118.     
  1119.     /*
  1120.     called when a BarChart window is zoomed. we return the optimal size
  1121.     for the window. horizontally, it's a function of the number of bars
  1122.     and the width of their labels. vertically, we make it 3/5 of the 
  1123.     window width.
  1124.     */
  1125.  
  1126.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  1127.     hdlappwindow ha = app.appwindow;
  1128.     short i;
  1129.     bigstring bs;
  1130.     short maxwidth = 0;
  1131.     short width;
  1132.     
  1133.     pushlabelstyle ();
  1134.     
  1135.     for (i = 0; i < (**hb).ctbars; i++) {
  1136.         
  1137.         short x = StringWidth ((ConstStr255Param) (**hb).bars [i].label) + 4;
  1138.         
  1139.         maxwidth = max (maxwidth, x);
  1140.         
  1141.         NumToString ((**hb).bars [i].value, bs);
  1142.     
  1143.         pushstring ((**hb).barunits, bs);
  1144.         
  1145.         x = StringWidth (bs) + 4;
  1146.         
  1147.         maxwidth = max (maxwidth, x);
  1148.         } /*for*/
  1149.     
  1150.     width =     
  1151.         ((**hb).vertbaseline * 2) + 
  1152.         
  1153.         (maxwidth * (**hb).ctbars) + 
  1154.         
  1155.         ((**hb).pixelsbetweenbars * ((**hb).ctbars - 1));
  1156.     
  1157.     (**ha).zoomwidth = max (width, minwindowwidth);
  1158.     
  1159.     (**ha).zoomheight = ((**ha).zoomwidth * 3) / 5;
  1160.     
  1161.     return (true);
  1162.     } /*bcgetcontentsize*/
  1163.     
  1164.  
  1165. static boolean bcidle (void) {
  1166.     
  1167.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  1168.     short i;
  1169.     
  1170.     setcursortype (cursorisarrow);
  1171.     
  1172.     if (hb == nil) /*no window open*/
  1173.         return (true);
  1174.     
  1175.     for (i = 0; i < (**hb).ctbars; i++) {
  1176.     
  1177.         if ((**hb).bars [i].fldirty) {
  1178.             
  1179.             drawbar (i);
  1180.     
  1181.             drawlabel (i);
  1182.             }
  1183.         
  1184.         (**hb).bars [i].fldirty = false;
  1185.         } /*for*/
  1186.     
  1187.     return (true);
  1188.     } /*bcidle*/
  1189.     
  1190.  
  1191. void main (void) {
  1192.     
  1193.     clearbytes (&app, longsizeof (app)); /*init all fields to 0*/
  1194.     
  1195.     app.creator = 'BARC';
  1196.     
  1197.     app.filetype = 'CHRT';
  1198.     
  1199.     app.usecolor = true;
  1200.     
  1201.     app.resizeable = true;
  1202.     
  1203.     app.eraseonresize = true;
  1204.     
  1205.     app.haswindowmenu = true; /*3.0*/
  1206.     
  1207.     app.usetempmemory = true; /*3.0*/
  1208.     
  1209.     app.newrecordcallback = &bcnewrecord;
  1210.     
  1211.     app.disposerecordcallback = &bcdisposerecord;
  1212.     
  1213.     app.idlecallback = &bcadjustcursor;
  1214.     
  1215.     app.activatecallback = (tyappbooleancallback) &bcactivate;
  1216.     
  1217.     app.switchcallback = (tyappbooleancallback) &bcactivate; /*3.0*/
  1218.     
  1219.     app.updatecallback = &bcupdate;
  1220.     
  1221.     app.windowresizecallback = &bcwindowresize;
  1222.     
  1223.     app.iacmessagecallback = &bciacmessage;
  1224.     
  1225.     app.packcallback = &bcpack;
  1226.     
  1227.     app.unpackcallback = &bcunpack;
  1228.     
  1229.     app.getpictcallback = (tyapphandleptrcallback) &bcgetpicture;
  1230.     
  1231.     app.putpictcallback = (tyapphandlecallback) &bcputpicture;
  1232.     
  1233.     app.openprintcallback = &bcopenprint;
  1234.     
  1235.     app.printpagecallback = (tyappshortcallback) &bcprintpage;
  1236.     
  1237.     app.closeprintcallback = &bccloseprint;
  1238.     
  1239.     app.haveselectioncallback = &bchaveselection;
  1240.     
  1241.     app.selectallcallback = &bcselectall;
  1242.     
  1243.     app.idlecallback = &bcidle;
  1244.     
  1245.     app.getcontentsizecallback = &bcgetcontentsize; 
  1246.  
  1247.     runapplet ();
  1248.     } /*main*/
  1249.     
  1250.     
  1251.