home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / xv310a / xvdial.c < prev    next >
Text File  |  1995-06-12  |  16KB  |  452 lines

  1. /* 
  2.  * xvdial.c - DIAL handling functions
  3.  *
  4.  * callable functions:
  5.  *
  6.  *   DCreate()   -  creates a dial
  7.  *   DSetRange() -  sets min/max/current values of control
  8.  *   DSetVal()   -  sets value of control 
  9.  *   DSetActive() - turns dial '.active' on and off
  10.  *   DRedraw()   -  redraws the dial
  11.  *   DTrack()    -  called when clicked.  Operates control 'til mouseup
  12.  */
  13.  
  14. #include "copyright.h"
  15.  
  16. #include "xv.h"
  17.  
  18. #include "bits/dial_cw1"
  19. #include "bits/dial_ccw1"
  20. #include "bits/dial_cw2"
  21. #include "bits/dial_ccw2"
  22.  
  23. static Pixmap cw1Pix, ccw1Pix;  /* up/down arrows */
  24. static Pixmap cw2Pix, ccw2Pix;  /* up/down page arrows */
  25. static int    pixmaps_built=0;   /* true if pixmaps created already */
  26.  
  27. #define PW dial_cw1_width        /* size of arrows */
  28. #define PH dial_cw1_height
  29.  
  30. /* dial regions */
  31. #define INCW1  0
  32. #define INCCW1 1
  33. #define INCW2  2
  34. #define INCCW2 3
  35. #define INDIAL 4
  36.  
  37. #define INC1WAIT 150   /* milliseconds to wait after initial hit */
  38. #define INC2WAIT 150   /* milliseconds to wait between increments */
  39. #define DEG2RAD (3.14159265 / 180.0)
  40. #define RAD2DEG (180.0 / 3.14159265)
  41.  
  42.  
  43. /* local functions */
  44. static int  whereInDial     PARM((DIAL *, int, int));
  45. static void drawArrow       PARM((DIAL *));
  46. static void drawValStr      PARM((DIAL *));
  47. static void drawButt        PARM((DIAL *, int, int));
  48. static int  computeDialVal  PARM((DIAL *, int, int));
  49. static void dimDial         PARM((DIAL *));
  50.  
  51.  
  52. /***************************************************/
  53. void DCreate(dp, parent, x, y, w, h, minv, maxv, curv, page, 
  54.               fg, bg, hi, lo, title, units)
  55. DIAL         *dp;
  56. Window        parent;
  57. int           x,y,w,h,minv,maxv,curv,page;
  58. unsigned long fg,bg,hi,lo;
  59. char         *title, *units;
  60. {
  61.  
  62.   if (!pixmaps_built) {
  63.     cw1Pix   = XCreatePixmapFromBitmapData(theDisp, parent, 
  64.         (char *) dial_cw1_bits, PW, PH, fg, bg, dispDEEP);
  65.     ccw1Pix  = XCreatePixmapFromBitmapData(theDisp, parent, 
  66.             (char *) dial_ccw1_bits, PW, PH, fg, bg, dispDEEP);
  67.     cw2Pix   = XCreatePixmapFromBitmapData(theDisp, parent, 
  68.                 (char *) dial_cw2_bits, PW, PH, fg, bg, dispDEEP);
  69.     ccw2Pix  = XCreatePixmapFromBitmapData(theDisp, parent, 
  70.             (char *) dial_ccw2_bits, PW, PH, fg, bg, dispDEEP);
  71.   }
  72.  
  73.   dp->x     = x;
  74.   dp->y     = y;
  75.  
  76.   dp->w     = w;
  77.   dp->h     = h;
  78.   dp->fg    = fg;
  79.   dp->bg    = bg;
  80.   dp->hi    = hi;
  81.   dp->lo    = lo;
  82.   dp->title = title;
  83.   dp->units = units;
  84.   dp->active = 1;
  85.   dp->drawobj = NULL;
  86.  
  87.   if (w < h-24-16) dp->rad = (w - 8) / 2;
  88.            else dp->rad = (h - 24 - 16 - 8) / 2;
  89.   dp->cx = w / 2;
  90.   dp->cy = dp->rad + 4 + 16;
  91.  
  92.   dp->bx[INCCW1] = 4;       dp->by[INCCW1] = h - 4 - 20;
  93.   dp->bx[INCCW2] = 4;       dp->by[INCCW2] = h - 4 - 10;
  94.   dp->bx[INCW1]  = w-14-4;  dp->by[INCW1]  = h - 4 - 20;
  95.   dp->bx[INCW2]  = w-14-4;  dp->by[INCW2]  = h - 4 - 10;
  96.  
  97.   dp->win = XCreateSimpleWindow(theDisp, parent,x,y,(u_int) w,(u_int) h,
  98.                 1,fg,bg);
  99.   if (!dp->win) FatalError("can't create dial window");
  100.  
  101.   DSetRange(dp, minv, maxv, curv, page);
  102.   XSelectInput(theDisp, dp->win, ExposureMask | ButtonPressMask);
  103. }
  104.  
  105.  
  106. /***************************************************/
  107. void DSetRange(dp, minv, maxv, curv, page)
  108. DIAL *dp;
  109. int   minv, maxv, curv, page;
  110. {
  111.   if (maxv<minv) maxv=minv;
  112.   dp->min = minv;    dp->max = maxv;    dp->page = page;
  113.   dp->active =  (minv < maxv);
  114.  
  115.   DSetVal(dp, curv);
  116. }
  117.  
  118.  
  119. /***************************************************/
  120. void DSetVal(dp, curv)
  121. DIAL *dp;
  122. int   curv;
  123. {
  124.   RANGE(curv, dp->min, dp->max);   /* make sure curv is in-range */
  125.  
  126.   if (curv == dp->val) return;
  127.  
  128.   /* erase old arrow */
  129.   XSetForeground(theDisp, theGC, dp->bg); 
  130.   drawArrow(dp);
  131.  
  132.   dp->val = curv;
  133.  
  134.   /* draw new arrow and string */
  135.   XSetForeground(theDisp, theGC, dp->fg);
  136.   XSetBackground(theDisp, theGC, dp->bg); 
  137.   drawArrow(dp);
  138.   drawValStr(dp);
  139.   if (!dp->active) dimDial(dp);
  140.  
  141.   XFlush(theDisp);
  142. }
  143.  
  144.  
  145. /***************************************************/
  146. void DSetActive(dp, i)
  147. DIAL *dp;
  148. int   i;
  149. {
  150.   if (i == dp->active) return;
  151.  
  152.   dp->active = i;
  153.   XClearWindow(theDisp, dp->win);
  154.   DRedraw(dp);
  155.   XFlush(theDisp);
  156. }
  157.  
  158.  
  159. /***************************************************/
  160. void DRedraw(dp)
  161. DIAL *dp;
  162. {
  163.   double tsize;
  164.   int    i, rad, cx, cy, x1, y1, x2, y2;
  165.  
  166.   rad = dp->rad;  cx = dp->cx;  cy = dp->cy;
  167.  
  168.   Draw3dRect(dp->win, 0,0, (u_int) dp->w-1, (u_int) dp->h-1, R3D_OUT, 2,
  169.          dp->hi, dp->lo, dp->bg);
  170.  
  171.   XSetForeground(theDisp, theGC, dp->fg);
  172.   XSetBackground(theDisp, theGC, dp->bg);
  173.  
  174.   /* draw title */
  175.   CenterString(dp->win, dp->w/2, 8, dp->title);
  176.  
  177.   /* draw tick marks around circle */
  178.   for (i = -60; i<=240; i += 10) {
  179.     if (i%60 == 0) tsize = 0.85;  else tsize = 0.95;
  180.     x1 = cx + (int) ((double) rad * cos(i * DEG2RAD));
  181.     y1 = cy - (int) ((double) rad * sin(i * DEG2RAD));
  182.     x2 = cx + (int) ((double) rad * tsize  * cos(i*DEG2RAD));
  183.     y2 = cy - (int) ((double) rad * tsize  * sin(i*DEG2RAD));
  184.  
  185.     XDrawLine(theDisp, dp->win, theGC, x1, y1, x2, y2);
  186.   }
  187.  
  188.   drawArrow(dp);
  189.  
  190.   /* draw the cw/ccw controls */
  191.   for (i=0; i<4; i++) drawButt(dp, i, 0);
  192.  
  193.   drawValStr(dp);
  194.  
  195.   if (!dp->active) dimDial(dp);
  196. }
  197.  
  198.  
  199. /***************************************************/
  200. int DTrack(dp, mx, my)
  201. DIAL *dp;
  202. int mx,my;
  203. {
  204.   Window       rW,cW;
  205.   int          rx,ry, x,y, ipos, pos, lit, i, origval;
  206.   unsigned int mask;
  207.  
  208.   lit = 0;
  209.  
  210.   if (!dp->active) return 0;
  211.  
  212.   XSetForeground(theDisp, theGC, dp->fg);
  213.   XSetBackground(theDisp, theGC, dp->bg);
  214.  
  215.   /* determine in which of the five regions of the dial the mouse
  216.      was clicked (cw1, ccw1, cw2, ccw2, dial-proper) */
  217.  
  218.   ipos = whereInDial(dp, mx, my);
  219.   if (ipos<0) return 0;          /* didn't hit any of the actual controls */
  220.  
  221.   origval = dp->val;
  222.  
  223.   /* light up appropriate button, if it's in one of them */
  224.   if (ipos != INDIAL) {
  225.     drawButt(dp, ipos, 1);
  226.     switch (ipos) {
  227.     case INCW1:  if (dp->val < dp->max) DSetVal(dp, dp->val+1); break;
  228.     case INCW2:  if (dp->val < dp->max) DSetVal(dp, dp->val+dp->page); break;
  229.     case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-1); break;
  230.     case INCCW2: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->page); break;
  231.     }
  232.     if (dp->drawobj != NULL) (dp->drawobj)();  
  233.     Timer(INC1WAIT);
  234.     lit = 1;
  235.   }
  236.  
  237.   else { 
  238.     i = computeDialVal(dp, mx, my);
  239.     DSetVal(dp, i);
  240.     if (dp->drawobj != NULL) (dp->drawobj)();  
  241.   }
  242.  
  243.   
  244.   /* loop until mouse is released */
  245.   while (XQueryPointer(theDisp,dp->win,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
  246.     if (!(mask & Button1Mask)) break;    /* button released */
  247.  
  248.     if (ipos == INDIAL) {
  249.       int j;
  250.       i = computeDialVal(dp, x, y);
  251.       j = dp->val;
  252.       DSetVal(dp, i);
  253.       if (j != dp->val) {
  254.     /* track whatever dial controls */
  255.     if (dp->drawobj != NULL) (dp->drawobj)();  
  256.       }
  257.     }
  258.  
  259.     else {                            /* a button */
  260.       pos = whereInDial(dp, x, y);
  261.       if ( (pos==ipos && !lit) || (pos!=ipos && lit)) {
  262.     /* need to toggle lit state */
  263.     lit = !lit;
  264.     drawButt(dp, ipos, lit);
  265.       }
  266.  
  267.       if (lit) {
  268.     switch (ipos) {
  269.     case INCW1:  if (dp->val < dp->max) DSetVal(dp, dp->val+1); 
  270.                  break;
  271.     case INCW2:  if (dp->val < dp->max) DSetVal(dp, dp->val+dp->page);
  272.                      break;
  273.     case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-1);
  274.                      break;
  275.     case INCCW2: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->page);
  276.                      break;
  277.     }
  278.  
  279.     /* track whatever dial controls */
  280.     if (dp->drawobj != NULL) (dp->drawobj)();  
  281.  
  282.     Timer(INC2WAIT);
  283.       }
  284.     }
  285.     XFlush(theDisp);
  286.   }
  287.  
  288.  
  289.   /* turn off button, if lit */
  290.   if (ipos != INDIAL && lit) drawButt(dp, ipos, 0);
  291.  
  292.   return (dp->val != origval);
  293. }
  294.  
  295.  
  296.  
  297.  
  298.  
  299. /***************************************************/
  300. static int whereInDial(dp, x, y)
  301. DIAL *dp;
  302. int x, y;
  303. {
  304.   int i;
  305.  
  306.   /* returns region * that x,y is in.  returns -1 if none */
  307.  
  308.   for (i=0; i<4; i++) 
  309.     if (PTINRECT(x,y, dp->bx[i], dp->by[i], 14, 10)) return i;
  310.  
  311.   if (PTINRECT(x,y, dp->cx - dp->rad, dp->cy - dp->rad, 
  312.            2*dp->rad, 2*dp->rad))
  313.     return INDIAL;
  314.  
  315.   return -1;
  316. }
  317.  
  318.       
  319. /***************************************************/
  320. static void drawArrow(dp)
  321. DIAL *dp;
  322. {
  323.   int i, rad, cx, cy;
  324.   XPoint arrow[4];
  325.  
  326.   rad = dp->rad;  cx = dp->cx;  cy = dp->cy;
  327.  
  328.   /* map pos (range minv..maxv) into degrees (range 240..-60) */
  329.   i = 240 + (-300 * (dp->val - dp->min)) / (dp->max - dp->min);
  330.   arrow[0].x = cx + (int) ((double) rad * .80 * cos(i * DEG2RAD));
  331.   arrow[0].y = cy - (int) ((double) rad * .80 * sin(i * DEG2RAD));
  332.   arrow[1].x = cx + (int) ((double) rad * .33 * cos((i+160) * DEG2RAD));
  333.   arrow[1].y = cy - (int) ((double) rad * .33 * sin((i+160) * DEG2RAD));
  334.   arrow[2].x = cx + (int) ((double) rad * .33 * cos((i-160) * DEG2RAD));
  335.   arrow[2].y = cy - (int) ((double) rad * .33 * sin((i-160) * DEG2RAD));
  336.   arrow[3].x = arrow[0].x;
  337.   arrow[3].y = arrow[0].y;
  338.   XDrawLines(theDisp, dp->win, theGC, arrow, 4, CoordModeOrigin);
  339. }
  340.  
  341.  
  342. /***************************************************/
  343. static void drawValStr(dp)
  344. DIAL *dp;
  345. {
  346.   int  i, x1, x2;
  347.   char foo[60], foo1[60];
  348.  
  349.   /* compute longest string necessary so we can right-align this thing */
  350.   sprintf(foo,"%d",dp->min);    x1 = strlen(foo);
  351.   sprintf(foo,"%d",dp->max);    x2 = strlen(foo);
  352.   if (dp->min < 0 && dp->max > 0) x2++;   /* put '+' at beginning */
  353.   i = x1;  if (x2>x1) i = x2;
  354.   if (dp->units) i += strlen(dp->units);
  355.  
  356.   if (dp->min < 0 && dp->max > 0) sprintf(foo,"%+d", dp->val);
  357.   else sprintf(foo,"%d", dp->val);
  358.  
  359.   if (dp->units) strcat(foo,dp->units);
  360.   foo1[0] = '\0';
  361.   if (strlen(foo) < (size_t) i) {
  362.     for (i = i - strlen(foo); i>0; i--) strcat(foo1," ");
  363.   }
  364.   strcat(foo1, foo);
  365.  
  366.   XSetForeground(theDisp, theGC, dp->fg);
  367.   XSetBackground(theDisp, theGC, dp->bg);
  368.   XSetFont(theDisp, theGC, monofont);
  369.   XDrawImageString(theDisp, dp->win, theGC, 
  370.            dp->w/2 - XTextWidth(monofinfo, foo1, (int) strlen(foo1))/2,
  371.            dp->h-14 - (monofinfo->ascent + monofinfo->descent)/2
  372.                                          + monofinfo->ascent, 
  373.            foo1, (int) strlen(foo1));
  374.   XSetFont(theDisp, theGC, mfont);
  375. }
  376.  
  377.  
  378. /***************************************************/
  379. static void drawButt(dp, i, lit)
  380.      DIAL *dp;
  381.      int i, lit;
  382. {
  383.   Pixmap pix = (Pixmap) NULL;
  384.  
  385.   XSetForeground(theDisp, theGC, dp->fg);
  386.   XDrawRectangle(theDisp, dp->win, theGC, dp->bx[i], dp->by[i], 14, 10);
  387.  
  388.   XSetForeground(theDisp, theGC, dp->bg);
  389.   XFillRectangle(theDisp, dp->win, theGC, dp->bx[i]+1, dp->by[i]+1, 13, 9);
  390.  
  391.   if (!lit) Draw3dRect(dp->win, dp->bx[i]+1,dp->by[i]+1, 12,8, R3D_OUT, 1,
  392.                dp->hi, dp->lo, dp->bg);
  393.  
  394.   switch (i) {
  395.   case INCCW1: pix = ccw1Pix;  break;
  396.   case INCCW2: pix = ccw2Pix;  break;
  397.   case INCW1:  pix = cw1Pix;   break;
  398.   case INCW2:  pix = cw2Pix;   break;
  399.   }
  400.  
  401.   XCopyArea(theDisp, pix, dp->win, theGC, 0, 0, PW, PH,
  402.         dp->bx[i]+(15-PW)/2, dp->by[i]+(11-PH)/2);
  403.  
  404.   if (lit) {
  405.     XSetState(theDisp, theGC, dp->fg, dp->bg, GXinvert, dp->fg ^ dp->bg);
  406.     XFillRectangle(theDisp, dp->win, theGC, dp->bx[i]+1, dp->by[i]+1, 13, 9);
  407.     XSetState(theDisp, theGC, dp->fg, dp->bg, GXcopy, AllPlanes);
  408.     XFlush(theDisp);
  409.   }
  410. }
  411.  
  412.  
  413. /***************************************************/
  414. static int computeDialVal(dp, x, y)
  415. DIAL *dp;
  416. int x, y;
  417. {
  418.   int dx, dy, val;
  419.   double angle;
  420.  
  421.   /* compute dx, dy (distance from cx, cy).  Note: +dy is *up* */
  422.   dx = x - dp->cx;  dy = dp->cy - y;
  423.  
  424.   /* if too close to center, return current value to avoid 'spazzing' */
  425.   if (abs(dx) < 3 && abs(dy) < 3) return dp->val;
  426.  
  427.   /* figure out angle of vector dx,dy */
  428.   if (dx==0) {     /* special case */
  429.     if (dy>0) angle =  90.0;
  430.          else angle = -90.0;
  431.   }
  432.   else if (dx>0) angle = atan((double)  dy / (double)  dx) * RAD2DEG;
  433.   else           angle = atan((double) -dy / (double) -dx) * RAD2DEG + 180.0;
  434.     
  435.   /* map angle into range: -90..270, then into to value */
  436.   if (angle > 270.0) angle -= 360.0;
  437.   if (angle < -90.0) angle += 360.0;
  438.  
  439.   val = (int) ((dp->max - dp->min) * (240.0 - angle) / 300.0) + dp->min;
  440.  
  441.   return val;
  442. }
  443.  
  444.  
  445. /***************************************************/
  446. static void dimDial(dp)
  447.      DIAL *dp;
  448. {
  449.   DimRect(dp->win, 0, 0, (u_int) dp->w, (u_int) dp->h, dp->bg);
  450. }
  451.