home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / lang / dial_cde.hqx / cdef.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-09-14  |  15.3 KB  |  744 lines

  1. /*
  2.  * Doug Felt, 9/5/88 creation.
  3.  *
  4.  * the cdev routines
  5.  *
  6.  * varcodes:
  7.  *
  8.  * if the low bit of the varcode is 1, do not show the number box in the middle of
  9.  * the dial.
  10.  * 
  11.  * bugs:
  12.  *
  13.  * there may be memory problems involving allocation of the offscreen bitmaps during
  14.  * drawing.  this is just a quick hack so I don't know.
  15.  *
  16.  * possible modifications:
  17.  *
  18.  * -- more varcodes to number the ticks, and to toggle whether the name shows.
  19.  *
  20.  * -- changing to 'inactive' state is slow since I redraw the whole image.  it would
  21.  * probably be better to keep a region of the dial background and redraw it in
  22.  * white.  
  23.  *
  24.  * -- what really slows this down on the plus is the floating point calculations,
  25.  * so if this were to run on the plus it might be better to use fixed point.
  26.  * 
  27.  * -- support for color, real grays, pixmaps instead of bitmaps, etc.
  28.  */
  29.  
  30. #include "cdef.h"
  31.  
  32. #include "sincos.h"
  33. #include "rectutils.h"
  34. #include "bitmap.h"
  35.  
  36. static void cDraw(ControlHandle theControl, long param);
  37. static long cTest(ControlHandle theControl, long param);
  38. static void cCalcRgns(ControlHandle theControl, long param);
  39. static void cInit(int varCode, ControlHandle theControl);
  40. static void cDispose(ControlHandle theControl);
  41. static void cPos(ControlHandle theControl, long param);
  42. static void cThumb(ControlHandle theControl, long param);
  43. static long cDrag(ControlHandle theControl, long param);
  44. static long cAutoTrack(ControlHandle theControl, long param);
  45.  
  46. static void redrawPict(ControlHandle ch);
  47. static void calcValue(ControlHandle ch);
  48. static void drawValue(ControlHandle ch);
  49. static int  pointToValue(ControlHandle ch, Point pt);
  50. static void xdrawValue(ControlHandle ch);
  51. static void drawRectImage(ControlHandle ch, Rect *r);
  52. static void setNewValue(ControlHandle ch, int v);
  53. static Boolean checkAndUpdate(ControlHandle ch);
  54.  
  55. /* 
  56.  * try to accomodate the system we are running on a little bit, in case it has
  57.  * a wierd selection of fonts.
  58.  */
  59. #define kNumFontName "\pGeneva"
  60. #define kNameFontName "\pNew York"
  61. #define kNameFontMax 16
  62. #define kNameFontMin 12
  63. #define kNumFontMax 10
  64. #define kNumFontMin 8
  65.  
  66. /* 
  67.  * needle image ranges between -kNeedleMax and kNeedleMax degrees.
  68.  * ticks are in increments of kTickIncrement degrees, should evenly divide
  69.  * 2 * kNeedleMax
  70.  */
  71. #define kNeedleMax 80
  72. #define kTickIncrement 10
  73.  
  74. typedef struct {
  75.     Rect limitRect;
  76.     Rect slopRect;
  77.     int axis;
  78. } CThumbRec, *PCThumbRec;
  79.  
  80. typedef struct {
  81.     Rect lastR;
  82.     Rect trackR;
  83.     Rect titleR;
  84.     Rect numR;
  85.     Boolean inactive;
  86.     Boolean doNum;
  87.     int numFont;
  88.     int numSize;
  89.     int numBase;
  90.     Point cp,ep;
  91.     PBMap buffer;
  92.     PBMap image;
  93. } IData, *PIData, **HIData;
  94.  
  95. long
  96. MyControl(varCode, theControl, message, param)
  97. int varCode;
  98. ControlHandle theControl;
  99. int message;
  100. long int param;
  101. {
  102. long int res = 0L;
  103. GrafPtr port;
  104.  
  105.     GetPort(&port);    /* I'm chicken */
  106.     SetPort((**theControl).contrlOwner);
  107.     switch (message) {
  108.         case drawCntl: cDraw(theControl,param); break;
  109.         case testCntl: res = cTest(theControl,param); break;
  110.         case calcCRgns: cCalcRgns(theControl,param); break;
  111.         case initCntl: cInit(varCode,theControl); break;
  112.         case dispCntl: cDispose(theControl); break;
  113.         case dragCntl: res = cDrag(theControl,param); break;
  114.         case posCntl: cPos(theControl,param); break;
  115.         case thumbCntl: cThumb(theControl,param); break;
  116.         case autoTrack: res = cAutoTrack(theControl,param); break;
  117.         default: break;
  118.     }
  119.     SetPort(port);
  120.     return res;
  121. }
  122.  
  123. static void
  124. cDraw(ch,param)
  125. ControlHandle ch;
  126. long param;
  127. {
  128. HIData idh;
  129. Rect r;
  130. Boolean newpict;
  131.  
  132.     if ((**ch).contrlVis) {
  133.         param &= 0xffff;    /* apparently, garbage in high word!!! */
  134.         idh = (HIData)(**ch).contrlData;
  135.         r = (**ch).contrlRect;
  136.         if (idh) {
  137.             newpict = checkAndUpdate(ch);
  138.             if ((param != 129) || newpict) {
  139.                 if (newpict)
  140.                     calcValue(ch);
  141.                 drawRectImage(ch,&r);
  142.             } else {
  143.                 setNewValue(ch,(**ch).contrlValue);    /* only track indicator */
  144.             }
  145.         } else {
  146.             PenNormal();    /* couldn't allocate offscreen buffers, etc */
  147.             FrameRect(&r);
  148.             SysBeep(3);
  149.         }
  150.     }
  151. }
  152.  
  153. /*
  154.  * return the number of the control part
  155.  */
  156. static long
  157. cTest(ch,param)
  158. ControlHandle ch;
  159. long param;
  160. {
  161. CPartNumber res = CInNothing;
  162. HIData idh;
  163. int bot;
  164. Point pt;
  165.  
  166.     if ((**ch).contrlHilite != 255) {
  167.         pt = *(Point *)¶m;
  168.         if (PtInRect(pt,&(**ch).contrlRect)) {
  169.             idh = (HIData)(**ch).contrlData;
  170.             if (idh) {
  171.                 bot = (**idh).titleR.top;
  172.                 if (pt.v > bot)
  173.                     res = CInTitle;
  174.                 else {
  175.                     if ((**idh).doNum && PtInRect(pt,&(**idh).numR)) {
  176.                         res = CInNumBox;
  177.                     } else {
  178.                         res = CInDial;
  179.                     }
  180.                 }
  181.             }
  182.         }
  183.     }
  184.     return (long)res;
  185. }
  186.  
  187. /*
  188.  * This Control Manager hack will break when the mac moves to 32-bit memory
  189.  * management.  To be a bit safer, I only mess with param when iOnly is set.
  190.  * Apple has only themselves to blame.
  191.  */
  192. static void 
  193. cCalcRgns(ch,param)
  194. ControlHandle ch;
  195. long param;
  196. {
  197. Boolean iOnly;
  198. Rect r;
  199.  
  200.     iOnly = (param & 0x80000000) != 0;
  201.     if (iOnly) {
  202.     /* 
  203.      * essentially ignore iOnly since the Control Manager should never call it.  But
  204.      * then you never know what kinds of ugly madness lurk within the toolbox.
  205.      */
  206.         SysBeep(3);
  207.         param &= 0x00ffffff;
  208.         SetEmptyRgn((RgnHandle)param);
  209.     } else {
  210.         /*
  211.          * gets called when I free, move the control.  Make sure this is a solid
  212.          * region since the CM apparently uses InvalRgn to clear us!!!
  213.          */
  214.         OpenRgn();
  215.             r = (**ch).contrlRect;
  216.             FrameRect(&r);
  217.         CloseRgn((RgnHandle)param);
  218.     }
  219. }
  220.  
  221. static void
  222. cInit(vc,ch)
  223. int vc;
  224. ControlHandle ch;
  225. {
  226. HIData idh = 0;
  227. PIData idp;
  228.  
  229.     idh = (HIData)NewHandle(sizeof(IData));
  230.     if (idh) {
  231.         HLock(idh);
  232.         idp = *idh;
  233.         SetRect(&idp->lastR,0,0,0,0);
  234.         idp->trackR = idp->lastR;
  235.         idp->titleR = idp->lastR;
  236.         idp->numR = idp->lastR;
  237.         idp->inactive = false;
  238.         idp->doNum = (vc & 0x01) == 0; /* default is to show number box */
  239.         idp->numFont = 0;
  240.         idp->numSize = 0;
  241.         idp->numBase = 0;
  242.         SetPt(&idp->cp,0,0);
  243.         SetPt(&idp->ep,0,0);
  244.         idp->buffer = BMNew();
  245.         idp->image = BMNew();
  246.         
  247.         if (!(idp->buffer && idp->image)) {
  248.             if (idp->buffer)
  249.                 BMDispose(idp->buffer);
  250.             if (idp->image)
  251.                 BMDispose(idp->image);
  252.             DisposHandle(idh);
  253.             idh = 0L;
  254.         } else {
  255.             HUnlock(idh);
  256.         }
  257.     }
  258.     (**ch).contrlData = (Handle)idh;
  259.     (**ch).contrlAction = 0L;
  260. }
  261.  
  262. static void
  263. cDispose(ch)
  264. ControlHandle ch;
  265. {
  266. HIData idh;
  267.  
  268.     idh = (HIData)(**ch).contrlData;
  269.     if (idh) {
  270.         BMDispose((**idh).image);
  271.         BMDispose((**idh).buffer);
  272.         DisposHandle(idh);
  273.         (**ch).contrlData = 0L;
  274.     }
  275. }
  276.  
  277. static long
  278. cDrag(ch,param)
  279. ControlHandle ch;
  280. long param;
  281. {
  282. long res;
  283. Point pt;
  284. Rect oldr,newr;
  285.  
  286.     if (!(**ch).contrlData) {
  287.         res = -1;            /* better safe than sorry */
  288.     } else {
  289.         param &= 0xffff;        /* garbage in high word again */
  290.         if (param != 0) {
  291.             int v;
  292.             while (StillDown()) {
  293.                 GetMouse(&pt);
  294.                 v = pointToValue(ch,pt);
  295.                 if (v != (**ch).contrlValue) {
  296.                     setNewValue(ch,v);
  297.                 }
  298.             }
  299.             /* 
  300.              * pass -1 to keep cPos from being called.  just passing 1 doesn't work,
  301.              * obviously it expects some other byte to be non zero, so I use -1
  302.              * to get all four
  303.              */
  304.             res = -1;
  305.         } else {
  306.             res = 0;    /* let control manager drag us */
  307.         }
  308.     }
  309.     return res;
  310. }
  311.  
  312. /*
  313.  * since I drag the indicator when I move it, and never restore the
  314.  * previous position, this need never be called.  In case it does get
  315.  * called, here it is, but it does nothing.
  316.  */
  317. static void
  318. cPos(ch,param)
  319. ControlHandle ch;
  320. long param;
  321. {
  322. }
  323.  
  324. /*
  325.  * This is clearly a hack for scroll bars to call DragGrayRgn.  Why even make 
  326.  * this part of the CDEF interface? This will get called before I drag the
  327.  * indicator, but I don't use it, nor do I see how to usefully do so.
  328.  */
  329. static void
  330. cThumb(ch,param)
  331. ControlHandle ch;
  332. long param;
  333. {
  334. PCThumbRec p;
  335.  
  336.     p = (PCThumbRec)param;
  337.     p->limitRect = (**ch).contrlRect;
  338.     p->slopRect = (**ch).contrlRect;
  339.     p->axis = noConstraint; /* from window manager */
  340. }
  341.  
  342. /*
  343.  * again, this should never be called.
  344.  */
  345. static long
  346. cAutoTrack(ch,param)
  347. ControlHandle ch;
  348. long param;
  349. {
  350. long res = 0L;
  351.  
  352.     SysBeep(3);
  353.     return res;
  354. }
  355.  
  356. /*
  357.  *************************************************************************
  358.  */
  359.  
  360. static void
  361. redrawPict(ch)
  362. ControlHandle ch;
  363. {
  364. GrafPtr port;
  365. HIData idh;
  366. Rect b,r,r2,r3;
  367. int oldFont,oldFace,oldSize;
  368. int fnum,i,space,base,ht,wid,xwid;
  369. int minang,maxang;
  370. Point c,p;
  371. FontInfo finfo;
  372. char *str;
  373. double pi80,fh,fv;
  374. Boolean active;
  375. RgnHandle oclip,ovis;
  376. Pattern backpat;
  377.  
  378.     GetPort(&port);
  379.  
  380.     oclip = NewRgn();
  381.     ovis = NewRgn();
  382.     if (oclip && ovis) {
  383.         GetClip(oclip);
  384.         ClipRect(&(**ch).contrlRect);    /* in case we're off the window when drawing */
  385.         CopyRgn(port->visRgn,ovis);
  386.         RectRgn(port->visRgn,&(**ch).contrlRect);
  387.     } else {
  388.         if (ovis) DisposeRgn(ovis);
  389.         if (oclip) DisposeRgn(oclip);
  390.         ovis = oclip = 0L;
  391.     }
  392.     pi80 = PI / 180.0;
  393.  
  394.     b = (**ch).contrlRect;
  395.     idh = (HIData)(**ch).contrlData;
  396.     r = b;
  397.     r.right -= 2;
  398.     r.bottom -= 2;
  399.     
  400.     str = (char *)&(**ch).contrlTitle;
  401.     active = (**ch).contrlHilite != 255;
  402.     
  403.     PenNormal();
  404.     FrameRect(&r);
  405.     PenSize(2,2);
  406.     MoveTo(r.right,r.top+2);
  407.     LineTo(r.right,r.bottom);
  408.     LineTo(r.left+2,r.bottom);
  409.     
  410.     oldFont = port->txFont;
  411.     oldFace = port->txFace;
  412.     oldSize = port->txSize;
  413.     
  414.     GetFNum(kNameFontName,&fnum);
  415.     TextFont(fnum);
  416.     TextFace((Style)bold);
  417.     for (i=kNameFontMax; i>=kNameFontMin; --i)
  418.         if (RealFont(fnum,i)) break;
  419.     TextSize(i);
  420.     
  421.     GetFontInfo(&finfo);
  422.     space = 2;
  423.     base = finfo.descent + finfo.leading + space;
  424.     ht = finfo.ascent + base + space;
  425.     wid = StringWidth(str);
  426.     
  427.     r2.left = r.left + 2;
  428.     r2.right = r.right - 2;
  429.     r2.bottom = r.bottom - 2;
  430.     r2.top = r2.bottom - ht;
  431.     
  432.     xwid = r2.right-r2.left-2;
  433.     if (wid > xwid) {
  434.         if (oclip) {
  435.             r3 = r2;
  436.             InsetRect(&r3,1,0);
  437.             ClipRect(&r3);
  438.             MoveTo(r3.left,r.bottom-base);
  439.             DrawString(str);
  440.             ClipRect(&(**ch).contrlRect);
  441.         }
  442.     } else {
  443.         MoveTo((r.right+r.left-wid) >> 1,r.bottom-base);
  444.         DrawString(str);
  445.     }
  446.     
  447.     if (active) {
  448.         InvertRect(&r2);
  449.     }
  450.     (**idh).titleR = r2;
  451.     
  452.     PenSize(1,1);
  453.     MoveTo(r.left,r2.top - 2);
  454.     LineTo(r.right,r2.top - 2);
  455.     
  456.     r3 = r;
  457.     r3.bottom = r2.top;
  458.     InsetRect(&r3,2,2);
  459.     if (active) {
  460.         StuffHex(&backpat,"\pAA55AA55AA55AA55");
  461.         FillRect(&r3,&backpat);
  462.     }
  463.     
  464.     c.h = (r.right + r.left) >> 1;
  465.     c.v = r2.top - 10;
  466.     
  467.     wid = c.h - (r.left+7);
  468.     ht = c.v - (r.top+7);
  469.     SetRect(&r2,c.h-wid,c.v-ht,c.h+wid,c.v+ht);
  470.     PenSize(3,1);
  471.     minang = -kNeedleMax-5;
  472.     maxang = kNeedleMax+5;
  473.     EraseArc(&r2,minang,170);
  474.     FrameArc(&r2,minang,170);
  475.     fh = wid * sin(minang * pi80);
  476.     fv = ht * -cos(minang * pi80);
  477.     p.h = c.h + fh;
  478.     p.v = c.v + fv;
  479.     MoveTo(p.h,p.v);
  480.     LineTo(c.h,c.v);
  481.     p.h = c.h - fh;        /* dial is symmetric around vertical axis */
  482.     LineTo(p.h,p.v);
  483.     PenNormal();
  484.     
  485.     InsetRect(&r2,7,7);
  486.     (**idh).trackR = r2;
  487.     SetPt(&(**idh).cp,c.h,c.v);
  488.     
  489.     for (i=-kNeedleMax; i<=kNeedleMax; i+=kTickIncrement) {
  490.         fh = sin(i * pi80);
  491.         fv = -cos(i * pi80);
  492.         p.h = c.h + wid * fh;
  493.         p.v = c.v + ht * fv;
  494.         MoveTo(p.h,p.v);
  495.         p.h = c.h + (wid-4) * fh;
  496.         p.v = c.v + (ht-4) * fv;
  497.         LineTo(p.h,p.v);
  498.     }
  499.     
  500.     GetFNum(kNumFontName,&fnum);
  501.     TextFont(fnum);
  502.     TextFace((Style)bold);
  503.     for (i=kNumFontMax; i>=kNumFontMin; --i)
  504.         if (RealFont(fnum,i)) break;
  505.     TextSize(i);
  506.     
  507.     GetFontInfo(&finfo);
  508.     base = finfo.descent + finfo.leading;
  509.     ht = finfo.ascent + base;
  510.     wid = finfo.widMax * 3;
  511.     r3.left = c.h - (wid >> 1);
  512.     r3.right = r3.left + wid;
  513.     r3.bottom = c.v - 7;
  514.     r3.top = r3.bottom - ht;
  515.     (**idh).numR = r3;
  516.     (**idh).numFont = fnum;
  517.     (**idh).numSize = i;
  518.     (**idh).numBase = base;
  519.     
  520.     TextFont(oldFont);
  521.     TextFace(oldFace);
  522.     TextSize(oldSize);
  523.     
  524.     if (oclip) {
  525.         SetClip(oclip);
  526.         DisposeRgn(oclip);
  527.     }
  528.     if (ovis) {
  529.         CopyRgn(ovis,port->visRgn);
  530.         DisposeRgn(ovis);
  531.     }
  532. }
  533.  
  534. /*
  535.  * calculate the needle position
  536.  */
  537. static void
  538. calcValue(ch)
  539. ControlHandle ch;
  540. {
  541. double pi80,fv,nrange,range;
  542. int v,max,min;
  543. HIData id;
  544.  
  545.     pi80 = PI / 180.0;
  546.     v = (**ch).contrlValue;
  547.     max = (**ch).contrlMax;
  548.     min = (**ch).contrlMin;
  549.     range = max-min;
  550.     nrange = kNeedleMax * 2;
  551.     id = (HIData)(**ch).contrlData;
  552.     if (v < min)
  553.         v = min;
  554.     else if (v > max)
  555.         v = max;
  556.     fv = pi80 * (-kNeedleMax + ((v-min) * nrange / range));
  557.     (**id).ep.h = ((**id).cp.h - (**id).trackR.left) * sin(fv);
  558.     (**id).ep.v = ((**id).cp.v - (**id).trackR.top) * -cos(fv);
  559. }
  560.  
  561. static void
  562. drawValue(ch)
  563. ControlHandle ch;
  564. {
  565. Rect r;
  566. Str255 str;
  567. int wid,v;
  568. HIData idh;
  569. PIData idp;
  570. SignedByte state;
  571.  
  572.     PenNormal();
  573.     idh = (HIData)(**ch).contrlData;
  574.     state = HGetState(idh);
  575.     HLock(idh);
  576.     idp = *idh;
  577.     
  578.     MoveTo(idp->cp.h,idp->cp.v);
  579.     Line(idp->ep.h,idp->ep.v);
  580.     SetRect(&r,idp->cp.h-3,idp->cp.v-3,idp->cp.h+3,idp->cp.v+3);
  581.     PaintOval(&r);
  582.     if (idp->doNum) {
  583.         r = idp->numR;
  584.         FrameRect(&r);
  585.         InsetRect(&r,1,1);
  586.         EraseRect(&r);
  587.         TextFont(idp->numFont);
  588.         TextSize(idp->numSize);
  589.         TextFace((Style)0);
  590.         v = (**ch).contrlValue;
  591.         NumToString(v,&str);
  592.         wid = StringWidth(&str);
  593.         MoveTo((idp->numR.right + idp->numR.left - wid) >> 1,idp->numR.bottom - idp->numBase);
  594.         DrawString(&str);
  595.     }
  596.     HSetState(idh,state);
  597. }
  598.  
  599. static int
  600. pointToValue(ch,pt)
  601. ControlHandle ch;
  602. Point pt;
  603. {
  604. int v,min,max;
  605. Rect r;
  606. HIData idh;
  607. double val,range,nrange;
  608.  
  609.     r = (**ch).contrlRect;
  610.     idh = (HIData)(**ch).contrlData;
  611.     if (PtInRect(pt,&r)) {
  612.         r = (**idh).trackR;
  613.         PtToAngle(&r,pt,&v);
  614.         if (v > 180)
  615.             v -= 360;
  616.         if (v > kNeedleMax)
  617.             v = kNeedleMax;
  618.         else if (v < -kNeedleMax)
  619.             v = -kNeedleMax;
  620.         min = (**ch).contrlMin;
  621.         max = (**ch).contrlMax;
  622.         nrange = kNeedleMax * 2;
  623.         range = max-min;
  624.         val = v + kNeedleMax;
  625.         v = min + (val * range / nrange);
  626.         return v;
  627.     } else {
  628.         return (**ch).contrlValue;
  629.     }
  630. }
  631.  
  632. static void
  633. xdrawvalue(ch)
  634. ControlHandle ch;
  635. {
  636. HIData idh;
  637.  
  638.     idh = (HIData)(**ch).contrlData;
  639.     BMDraw((**idh).image);
  640.     drawValue(ch);
  641. }
  642.  
  643. /*
  644.  * might be memory problems here if I can't size the buffer.  I haven't bothered
  645.  * to check.
  646.  */
  647. static void
  648. drawRectImage(ch,r)
  649. ControlHandle ch;
  650. Rect *r;
  651. {
  652. HIData idh;
  653.  
  654.     idh = (HIData)(**ch).contrlData;
  655.     BMSize((**idh).buffer,r);
  656.     BMInBitMapDo((**idh).buffer,xdrawvalue,ch);
  657.     BMDraw((**idh).buffer);
  658. }
  659.  
  660. /*
  661.  * calculates the new value of the needle and updates immediately
  662.  */
  663. static void
  664. setNewValue(ch,v)
  665. ControlHandle ch;
  666. int v;
  667. {
  668. Rect r,r2;
  669. Point pt;
  670. HIData idh;
  671. PIData idp;
  672. SignedByte state;
  673.  
  674.     idh = (HIData)(**ch).contrlData;
  675.     state = HGetState(idh);
  676.     HLock(idh);
  677.     idp = *idh;
  678.     
  679.     RUMakeDeltaRect(idp->cp,idp->ep,&r);
  680.     InsetRect(&r,-1,-1);
  681.     (**ch).contrlValue = v;
  682.     calcValue(ch);
  683.     RUMakeDeltaRect(idp->cp,idp->ep,&r2);
  684.     InsetRect(&r2,-1,-1);
  685.     UnionRect(&r2,&r,&r);
  686.     if (idp->doNum)
  687.         UnionRect(&idp->numR,&r,&r);
  688.     drawRectImage(ch,&r);
  689.     
  690.     HSetState(idh,state);
  691. }
  692.  
  693. /*
  694.  * see whether I need to update the offscreen image, either because
  695.  * it changed size, or because it changed highlight state, and
  696.  * redraw the image if so.
  697.  * return true if the image was redrawn.
  698.  */
  699. static Boolean
  700. checkAndUpdate(ch)
  701. ControlHandle ch;
  702. {
  703. Boolean inactive,newactive,newsize,newpict;
  704. Point owh,wh,d;
  705. Rect r;
  706. SignedByte state;
  707. HIData idh;
  708. PIData idp;
  709.  
  710.     r = (**ch).contrlRect;
  711.     idh = (HIData)(**ch).contrlData;
  712.     state = HGetState(idh);
  713.     HLock(idh);
  714.     idp = *idh;
  715.     
  716.     inactive = (**ch).contrlHilite == 255;
  717.     newactive = idp->inactive != inactive;
  718.     owh.h = r.right-r.left;
  719.     owh.v = r.bottom-r.top;
  720.     wh.h = idp->lastR.right - idp->lastR.left;
  721.     wh.v = idp->lastR.bottom - idp->lastR.top;
  722.     newsize = (owh.h != wh.h) || (owh.v != wh.v);
  723.     newpict = newsize || newactive;
  724.     if (newpict) {
  725.         idp->inactive = inactive;
  726.         idp->lastR = r;
  727.         BMSize(idp->image,&r);
  728.         BMErase(idp->image);
  729.         BMInBitMapDo(idp->image,redrawPict,ch);
  730.     } else if (!EqualRect(&r,&idp->lastR)) {
  731.         d.h = r.left - idp->lastR.left;
  732.         d.v = r.top - idp->lastR.top;
  733.         BMSize(idp->image,&r);
  734.         idp->lastR = r;
  735.         OffsetRect(&idp->titleR,d.h,d.v);
  736.         OffsetRect(&idp->numR,d.h,d.v);
  737.         OffsetRect(&idp->trackR,d.h,d.v);
  738.         AddPt(d,&idp->cp);
  739.     }
  740.     HSetState(idh,state);
  741.     
  742.     return newpict;
  743. }
  744.