home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-386-Vol-2of3.iso / c / cwikwidg.zip / cwikwidget / Cmap / Cmap.c next >
C/C++ Source or Header  |  1992-04-04  |  25KB  |  872 lines

  1. /*
  2.  * Copyright 1992 John L. Cwikla
  3.  * 
  4.  * Permission to use, copy, modify, distribute, and sell this software
  5.  * and its documentation for any purpose is hereby granted without fee,
  6.  * provided that the above copyright notice appears in all copies and that
  7.  * both that copyright notice and this permission notice appear in
  8.  * supporting documentation, and that the name of John L. Cwikla or
  9.  * University of Illinois not be used in advertising or publicity
  10.  * pertaining to distribution of the software without specific, written
  11.  * prior permission.  John L. Cwikla and University of Illinois make no
  12.  * representations about the suitability of this software for any
  13.  * purpose.  It is provided "as is" without express or implied warranty.
  14.  *
  15.  * John L. Cwikla and University of Illinois disclaim all warranties with
  16.  * regard to this software, including all implied warranties of
  17.  * merchantability and fitness, in no event shall John L. Cwikla or
  18.  * University of Illinois be liable for any special, indirect or
  19.  * consequential damages or any damages whatsoever resulting from loss of
  20.  * use, data or profits, whether in an action of contract, negligence or
  21.  * other tortious action, arising out of or in connection with the use or
  22.  * performance of this software.
  23.  *
  24.  * Author:
  25.  *     John L. Cwikla
  26.  *     Materials Research Laboratory Center for Computation
  27.  *     University Of Illinois at Urbana-Champaign
  28.  *    104 S. Goodwin
  29.  *     Urbana, IL 61801
  30.  * 
  31.  *     cwikla@uimrl7.mrl.uiuc.edu
  32.  */
  33.  
  34. /*
  35. ** Cmap Widget
  36. */
  37.  
  38. /*
  39. ** Resources:           Type:      Default:         Comment:
  40. **
  41. **  XtNmargin         : integer  :  5             : minimum margin around widget picture and label
  42. **  XtNselected       : integer  :  0             : current box for selection and values
  43. **  XtNchangeCallback : callback : NULL           : callback when any new box is chosen
  44. **  XtNfont           : string   : XtDefaultFont  : fontname for label
  45. **  XtNforeground     : pixel    : XtDefautlForeground : pixel value for selected box and label
  46. **  XtNboxWidth       : integer  : 0              : maximum box width (0 for calculate/resize)
  47. **  XtNboxHeight      : integer  : 0              : maximum box height (0 for calculate/resize)
  48. **
  49. */
  50.  
  51.  
  52. #include <X11/Xos.h>
  53. #include <X11/IntrinsicP.h>
  54. #include <X11/StringDefs.h>
  55.  
  56. #include <math.h>
  57. #include <varargs.h>
  58.  
  59. #include "CmapP.h"
  60. #include "Cmap.h"
  61.  
  62. /* For actions */
  63. #if NeedFunctionProtoTypes
  64. static void Left(CmapWidget _w, XEvent *_event, String *_argv, int *_argc);
  65. static void Right(CmapWidget _w, XEvent *_event, String *_argv, int *_argc);
  66. static void Up(CmapWidget _w, XEvent *_event, String *_argv, int *_argc);
  67. static void Down(CmapWidget _w, XEvent *_event, String *_argv, int *_argc);
  68. static void Select(CmapWidget _w, XEvent *_event, String *_argv, int *_argc);
  69. #else
  70. static void Left();
  71. static void Right();
  72. static void Up();
  73. static void Down();
  74. static void Select();
  75. #endif
  76.  
  77. /* For widget internals */
  78. #if NeedFunctionProtoTypes
  79. static void Initialize(CmapWidget _request, CmapWidget _new);
  80. static void Realize(CmapWidget _w, XtValueMask *_xvm, XSetWindowAttributes *_xswa);
  81. static void Resize(CmapWidget _w);
  82. static void Destroy(CmapWidget _w);
  83. static void Redisplay(CmapWidget _w, XEvent *_event, Region _region);
  84. static Boolean SetValues(CmapWidget _current, CmapWidget _request, CmapWidget _new);
  85. static void MyXtWarning();
  86. #else
  87. static void Initialize();
  88. static void Realize();
  89. static void Resize();
  90. static void Destroy();
  91. static void Redisplay();
  92. static Boolean SetValues();
  93. static void MyXtWarning();
  94. #endif
  95.  
  96. /* For Misc */
  97. #if NeedFunctionProtoTypes
  98. static int XYtoBox(CmapWidget _w, int _x, int _y);
  99. static void ReString(CmapWidget _w);
  100. static void DrawLabel(CmapWidget _w, GC _gc);
  101. static void DrawSelected(CmapWidget _w, int _boxNumber);
  102. static void DrawBox(CmapWidget _w, int _boxNumber);
  103. #else
  104. static int XYtoBox();
  105. static void ReString();
  106. static void DrawLabel();
  107. static void DrawSelected();
  108. static void DrawBox();
  109. #endif
  110.  
  111. static char CmapTranslations[] =
  112. "<Key>h:        left()\n\
  113.  <Key>l:    right()\n\
  114.  <Key>k:        up()\n\
  115.  <Key>j:        down()\n\
  116.  <Btn1Down>:    select()\n\
  117.  <Btn1Motion>:  select()";
  118.  
  119. static XtActionsRec CmapActions[] = 
  120. {
  121.   { "left", Left },
  122.   { "right", Right },
  123.   { "up", Up },
  124.   { "down", Down },
  125.   { "select", Select}
  126. };
  127.  
  128. #define RGB_STRING "R:%d G:%d B:%d (%d of %d)"
  129. #define CMAP_MINBOXWIDTH 5
  130. #define CMAP_MINBOXHEIGHT 5
  131.  
  132. #define BOXtoX(w, b) (((b) % w->cmap.numX) * w->cmap.realBoxWidth + w->cmap.drawPos.x)
  133. #define BOXtoY(w, b) (((b) / w->cmap.numX) * w->cmap.realBoxHeight + w->cmap.drawPos.y) 
  134. #define ROW(w, a) ((a) / w->cmap.numX)
  135. #define COL(w, a) ((a) % w->cmap.numX)
  136.  
  137. #ifndef MAX
  138. #define MAX(a,b) ((a) > (b) ? (a) : (b))
  139. #endif
  140. #ifndef MIN
  141. #define MIN(a,b) ((a) < (b) ? (a) : (b))
  142. #endif
  143.  
  144. #define TheOffset(field) XtOffset(CmapWidget, cmap.field)
  145.  
  146. static XtResource CmapResources[] = 
  147. {
  148.   {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
  149.     TheOffset(font), XtRString, (caddr_t)XtDefaultFont},
  150.   {XtNchangeCallback, XtCCallback, XtRCallback, sizeof(caddr_t),
  151.     TheOffset(changeCallback), XtRCallback, (caddr_t)NULL},
  152.   {XtNmargin, XtCMargin, XtRInt, sizeof(int),
  153.     TheOffset(margin), XtRImmediate, (caddr_t)5},
  154.   {XtNselected, XtCSelected, XtRInt, sizeof(int),
  155.     TheOffset(selected), XtRImmediate, (caddr_t)0},
  156.   {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  157.     TheOffset(foreground), XtRString, (caddr_t)XtDefaultForeground},
  158.   {XtNboxWidth, XtCBoxWidth, XtRInt, sizeof(int),
  159.     TheOffset(boxWidth), XtRImmediate, (caddr_t)0},
  160.   {XtNboxHeight, XtCBoxHeight, XtRInt, sizeof(int),
  161.     TheOffset(boxHeight), XtRImmediate, (caddr_t)0},
  162.   {XtNfirstIndex, XtCFirstIndex, XtRInt, sizeof(int),
  163.     TheOffset(firstIndex), XtRImmediate, (caddr_t)0},
  164.   {XtNlastIndex, XtCLastIndex, XtRInt, sizeof(int),
  165.     TheOffset(lastIndex), XtRImmediate, (caddr_t)LastIndexDefault}
  166. };
  167.  
  168. #undef TheOffset
  169.  
  170. CmapClassRec cmapClassRec = 
  171. {
  172.   {        /* CoreClassPart */
  173.     (WidgetClass)&widgetClassRec,  /* superclass */
  174.     "Cmap",                        /* class_name */
  175.     sizeof(CmapRec),               /* widget_size */
  176.     NULL,                          /* class_initialize */
  177.     NULL,                          /* class_part_initialize */
  178.     FALSE,                         /* class_init */
  179.     Initialize,                    /* initialize */
  180.     NULL,                          /* initialize_hook */
  181.     Realize,                       /* realize */
  182.     CmapActions,                   /* actions */
  183.     XtNumber(CmapActions),         /* num_actions */
  184.     CmapResources,                 /* resources */
  185.     XtNumber(CmapResources),       /* num_resources */
  186.     NULLQUARK,                     /* xrm_class */
  187.     TRUE,                          /* compress_motion */
  188.     TRUE,                          /* compress_exposure */
  189.     TRUE,                          /* compress_enterleave */
  190.     TRUE,                          /* visible_intress */
  191.     Destroy,                       /* destroy */
  192.     Resize,                        /* resize */
  193.     Redisplay,                     /* expose */
  194.     SetValues,                     /* set_values */
  195.     NULL,                          /* set_values_hook */
  196.     XtInheritSetValuesAlmost,      /* set_values_almost */
  197.     NULL,                          /* get_values_hook */
  198.     NULL,                          /* accept_focus */
  199.     XtVersion,                     /* version */
  200.     NULL,                          /* callback_private */
  201.     CmapTranslations,              /* tm_translations */
  202.     NULL,
  203.     NULL,
  204.     NULL,
  205.   },
  206.   { 
  207.     0 /* empty */
  208.   }
  209. };
  210.  
  211. WidgetClass cmapWidgetClass = (WidgetClass) &cmapClassRec;
  212.  
  213. #define CMAP _new->cmap
  214. #define CORE _new->core
  215.  
  216. static void Initialize(_request, _new)
  217. CmapWidget _request;
  218. CmapWidget _new;
  219. {
  220.   Display *display;
  221.   XColor color;
  222.  
  223.   display = XtDisplay(_new);
  224.  
  225.   if (CMAP.font == (XFontStruct *)NULL)
  226.   {
  227.     if ((CMAP.font = XLoadQueryFont(display, "fixed")) == NULL) 
  228.       if ((CMAP.font = XLoadQueryFont(display, "9x15")) == NULL)
  229.         MyXtWarning("CmapWidget: Fonts %s and %s not found.", "fixed", "9x15");
  230.   }
  231.  
  232.   if (CMAP.margin < 0)
  233.   {
  234.     MyXtWarning("CmapWidget: Margin (%d) cannot be negative.  Margin set to 0.", CMAP.margin);
  235.     CMAP.margin = 0;
  236.   }
  237.  
  238.   if (CMAP.boxWidth < 0)
  239.   {
  240.     MyXtWarning("CmapWidget: BoxWidth (%d) cannot be negative. BoxWidth set to 0.", CMAP.boxWidth);
  241.     CMAP.boxWidth = 0;
  242.   }
  243.  
  244.   if (CMAP.boxHeight < 0)
  245.   {
  246.     MyXtWarning("CmapWidget: BoxHeight (%d) cannot be negative. BoxHeight set to 0.", CMAP.boxHeight);
  247.     CMAP.boxHeight = 0;
  248.   }
  249.  
  250.   if (CMAP.firstIndex < 0)
  251.   {
  252.     MyXtWarning("CmapWidget: FirstIndex (%d) cannot be negative. FirstIndex set to 0.", CMAP.firstIndex);
  253.     CMAP.firstIndex = 0;
  254.   }
  255.  
  256.   CMAP.availColors = XDisplayCells(display, DefaultScreen(display));
  257.   if (CMAP.lastIndex == LastIndexDefault)
  258.     CMAP.lastIndex = CMAP.availColors-1; 
  259.  
  260.   if (CMAP.lastIndex < CMAP.firstIndex)
  261.   {
  262.     MyXtWarning("CmapWidget: LastIndex (%d) cannot be less than FirstIndex (%d).  LastIndex set to %d.", 
  263.       CMAP.lastIndex, CMAP.firstIndex, CMAP.firstIndex+1);
  264.     CMAP.lastIndex = CMAP.firstIndex + 1;
  265.   }
  266.  
  267.   if (CMAP.lastIndex > CMAP.availColors-1)
  268.   {
  269.     MyXtWarning("CmapWidget: LastIndex (%d) cannot be more than greatest index (%d).  LastIndex set to %d.",
  270.       CMAP.lastIndex, CMAP.availColors-1, CMAP.availColors-1);
  271.     CMAP.lastIndex = CMAP.availColors-1;
  272.   }
  273.  
  274.   CMAP.usedColors = MIN(CMAP.lastIndex-CMAP.firstIndex+1, CMAP.availColors);
  275.  
  276.   CMAP.numX = (int)floor(sqrt((double)(CMAP.usedColors)));
  277.   CMAP.numY = CMAP.usedColors/CMAP.numX + (CMAP.usedColors % CMAP.numX ? 1 : 0);
  278.  
  279.   if (CMAP.selected > CMAP.usedColors)
  280.   {
  281.     MyXtWarning("CmapWidget: Selected pixel (%d) is greater than %d. Selected set to %d.",
  282.       CMAP.selected, CMAP.usedColors-1, CMAP.usedColors-1);
  283.     CMAP.selected = CMAP.usedColors-1;
  284.   }
  285.  
  286.   if (CMAP.selected < 0)
  287.   {
  288.     MyXtWarning("CmapWidget: Selected pixel cannot be negative! Selected set to 0.");
  289.     CMAP.selected = 0;
  290.   }
  291.  
  292.   color.pixel = CMAP.selected+CMAP.firstIndex;
  293.   XQueryColor(display, CORE.colormap, &color);
  294.  
  295.   CMAP.selectedColor = color;
  296.   sprintf(CMAP.label, RGB_STRING, color.red, color.green,
  297.     color.blue, CMAP.selected+1, CMAP.usedColors);
  298.  
  299.   CMAP.labelHeight = CMAP.font->ascent + CMAP.font->descent;
  300.   CMAP.labelWidth = XTextWidth(CMAP.font, CMAP.label, strlen(CMAP.label));
  301.  
  302.   if (_request->core.width == 0)
  303.     CORE.width = MAX ((CMAP.boxWidth ? CMAP.boxWidth : CMAP_MINBOXWIDTH) * CMAP.numX, CMAP.labelWidth)
  304.       + 2 * CMAP.margin;
  305.   if (_request->core.height == 0)
  306.     CORE.height = (CMAP.boxHeight ? CMAP.boxHeight : CMAP_MINBOXHEIGHT) * CMAP.numY + CMAP.margin 
  307.       + CMAP.labelHeight + 2 * CMAP.margin;
  308.  
  309.   Resize(_new);
  310. }
  311. #undef CMAP 
  312. #undef CORE
  313.  
  314. static void Realize(_w, _xvm, _xswa)
  315. CmapWidget _w; 
  316. XtValueMask *_xvm;
  317. XSetWindowAttributes *_xswa;
  318. {
  319.   XGCValues gcValues;
  320.  
  321. /* Call the Realize procedure (XtInheritRealize) */
  322.   (*cmapWidgetClass->core_class.superclass->core_class.realize)((Widget)_w, _xvm, _xswa);
  323.  
  324. /* Now we can create our GC's */
  325.  
  326.   gcValues.foreground = _w->cmap.selected;
  327.   _w->cmap.gc = XCreateGC(XtDisplay(_w), XtWindow(_w), GCForeground, &gcValues);
  328.  
  329. /* This one is read only */
  330.  
  331.   gcValues.foreground = _w->cmap.foreground;
  332.   gcValues.font = _w->cmap.font->fid;
  333.   _w->cmap.foregroundGC = XtGetGC((Widget)_w, GCFont | GCForeground, &gcValues);
  334.  
  335. /* This one is read only */
  336.  
  337.   gcValues.foreground = _w->core.background_pixel;
  338.   _w->cmap.eraseGC = XtGetGC((Widget)_w, GCFont | GCForeground, &gcValues);
  339. }
  340.  
  341. static void Resize(_w)
  342. CmapWidget _w;
  343. {
  344.   int marginX, marginY;
  345.  
  346.   marginX = 2 * _w->cmap.margin;
  347.   marginY = 2 * _w->cmap.margin;
  348.  
  349.   _w->cmap.realBoxWidth = (_w->core.width - marginX)/_w->cmap.numX;
  350.   _w->cmap.realBoxHeight = (_w->core.height - marginY - (_w->cmap.labelHeight + _w->cmap.margin)) /
  351.     _w->cmap.numY;
  352.  
  353.   if (_w->cmap.boxWidth)
  354.     if (_w->cmap.realBoxWidth > _w->cmap.boxWidth)
  355.        _w->cmap.realBoxWidth = _w->cmap.boxWidth;
  356.  
  357.   if (_w->cmap.boxHeight)
  358.     if (_w->cmap.realBoxHeight > _w->cmap.boxHeight)
  359.      _w->cmap.realBoxHeight = _w->cmap.boxHeight; 
  360.  
  361.   marginX += (_w->core.width - marginX) - (_w->cmap.numX * _w->cmap.realBoxWidth);
  362.   marginY += (_w->core.height - marginY) - (_w->cmap.numY * _w->cmap.realBoxHeight + _w->cmap.margin + _w->cmap.labelHeight);
  363.  
  364.   _w->cmap.drawPos.y = marginY / 2;
  365.   _w->cmap.drawPos.x = marginX / 2;
  366.  
  367.   _w->cmap.labelPos.x = (_w->core.width/2) - (_w->cmap.labelWidth)/2;
  368.   _w->cmap.labelPos.y = _w->cmap.drawPos.y + (_w->cmap.numY * _w->cmap.realBoxHeight) + _w->cmap.font->ascent 
  369.     + _w->cmap.margin;
  370. }
  371.  
  372. static void Destroy(_w)
  373. CmapWidget _w;
  374. {
  375.   XFreeGC(XtDisplay(_w), _w->cmap.gc);
  376.   XtReleaseGC((Widget)_w, _w->cmap.foregroundGC);
  377.   XtReleaseGC((Widget)_w, _w->cmap.eraseGC);
  378.   XFreeFont(XtDisplay(_w),_w->cmap.font);
  379.   XtRemoveAllCallbacks((Widget)_w, XtNchangeCallback);
  380. }
  381.  
  382. static void DrawLabel(_w, _gc)
  383. CmapWidget _w; 
  384. GC _gc;
  385. {
  386.   XDrawString(XtDisplay(_w), XtWindow(_w), _gc,
  387.     _w->cmap.labelPos.x, _w->cmap.labelPos.y,
  388.     _w->cmap.label, strlen(_w->cmap.label));
  389. }
  390.  
  391. static void DrawSelected(_w, _boxNumber)
  392. CmapWidget _w;
  393. int _boxNumber;
  394. {
  395.   int x, y;
  396.   XRectangle rect[2];
  397.   x = BOXtoX(_w, _boxNumber);
  398.   y = BOXtoY(_w, _boxNumber);
  399.  
  400.   rect[0].x = x;
  401.   rect[0].y = y;
  402.   rect[0].width = (unsigned short)MAX(0, _w->cmap.realBoxWidth - 1);
  403.   rect[0].height = (unsigned short)MAX(0, _w->cmap.realBoxHeight - 1);
  404.   rect[1].x = x + 2;
  405.   rect[1].y = y + 2;
  406.   rect[1].width = (unsigned short)MAX(0, _w->cmap.realBoxWidth - 5);
  407.   rect[1].height = (unsigned short)MAX(0, _w->cmap.realBoxHeight - 5);
  408.  
  409.   XDrawRectangles(XtDisplay(_w), XtWindow(_w), _w->cmap.foregroundGC,
  410.     rect, 2);
  411.   XDrawRectangle(XtDisplay(_w), XtWindow(_w), _w->cmap.eraseGC,
  412.     x+1, y+1,
  413.     MAX(0, _w->cmap.realBoxWidth - 3),
  414.     MAX(0, _w->cmap.realBoxHeight - 3));
  415. }
  416.  
  417. static void DrawBox(_w, _boxNumber)
  418. CmapWidget _w;
  419. int _boxNumber;
  420. {
  421.   int x, y;
  422.   XSetForeground(XtDisplay(_w), _w->cmap.gc, _boxNumber+_w->cmap.firstIndex);
  423.   x = BOXtoX(_w, _boxNumber);
  424.   y = BOXtoY(_w, _boxNumber);
  425.   XFillRectangle(XtDisplay(_w), XtWindow(_w), _w->cmap.gc,
  426.     x, y,
  427.     _w->cmap.realBoxWidth, _w->cmap.realBoxHeight);
  428. }
  429.  
  430. static void Redisplay(_w, _event, _region)
  431. CmapWidget _w; 
  432. XEvent *_event; 
  433. Region _region;
  434. {
  435.   int i,j;
  436.   int scol, ecol;
  437.   int srow, erow;
  438.   XRectangle rect;
  439.  
  440.   XClipBox(_region, &rect);
  441.   if (_w->core.visible)
  442.   {
  443.     XFillRectangle(XtDisplay(_w), XtWindow(_w), _w->cmap.eraseGC, rect.x, rect.y,
  444.       rect.width, rect.height);
  445.  
  446.     rect.x = MAX(rect.x, _w->cmap.drawPos.x);
  447.     rect.y = MAX(rect.y, _w->cmap.drawPos.y);
  448.  
  449.     rect.width = MIN(rect.x+rect.width, _w->cmap.drawPos.x+_w->cmap.numX*_w->cmap.realBoxWidth-1);
  450.     rect.height = MIN(rect.y+rect.height, _w->cmap.drawPos.y+_w->cmap.numY*_w->cmap.realBoxHeight-1);
  451.  
  452.     if(!( (rect.x >= rect.width) || (rect.y >= rect.height)))
  453.     {
  454.       scol = COL(_w, XYtoBox(_w, rect.x, rect.y));
  455.       ecol = COL(_w, XYtoBox(_w, rect.width, rect.y));
  456.       srow = ROW(_w, XYtoBox(_w, rect.x, rect.y));
  457.       erow = ROW(_w, XYtoBox(_w, rect.x, rect.height));
  458.       i = scol;
  459.       j = srow;
  460.       for(;i<=ecol; i++)
  461.       {
  462.         for(;(j<=erow) && ((i+_w->cmap.numX*j)<_w->cmap.usedColors);j++)
  463.           DrawBox(_w, i + j*_w->cmap.numX); 
  464.         j = srow;
  465.       }
  466.     }
  467.     DrawLabel(_w, _w->cmap.eraseGC);
  468.     DrawLabel(_w, _w->cmap.foregroundGC);
  469.     DrawSelected(_w, _w->cmap.selected);
  470.   }
  471.   XFlush(XtDisplay(_w));
  472. }
  473.  
  474. #define CMAP _new->cmap
  475.  
  476. static Boolean SetValues(_current, _request, _new)
  477. CmapWidget _current; 
  478. CmapWidget _request; 
  479. CmapWidget _new;
  480. {
  481.   Boolean redisplay = FALSE;
  482.   Boolean newErase = FALSE;
  483.   Boolean newSelected = FALSE;
  484.   Display *display = XtDisplay(_new);
  485.   XGCValues gcValues;
  486.   int gcMask = GCFont;
  487.  
  488.   if (CMAP.margin < 0)
  489.   {
  490.     MyXtWarning("CmapWidget: Margin (%d) cannot be negative.  Margin set to 0.", CMAP.margin);
  491.     CMAP.margin = 0;
  492.   }
  493.  
  494.   if (CMAP.boxWidth < 0)
  495.   {
  496.     MyXtWarning("CmapWidget: BoxWidth (%d) cannot be negative. BoxWidth set to 0.", CMAP.boxWidth);
  497.     CMAP.boxWidth = 0;
  498.   }
  499.  
  500.   if (CMAP.boxHeight < 0)
  501.   {
  502.     MyXtWarning("CmapWidget: BoxHeight (%d) cannot be negative. BoxHeight set to 0.", CMAP.boxHeight);
  503.     CMAP.boxHeight = 0;
  504.   }
  505.  
  506.   if (CMAP.font == (XFontStruct *)NULL)
  507.   {
  508.     if ((CMAP.font = XLoadQueryFont(display, "fixed")) == NULL)
  509.     if ((CMAP.font = XLoadQueryFont(display, "9x15")) == NULL)
  510.       MyXtWarning("CmapWidget: Fonts %s and %s not found.", "fixed", "9x15");
  511.     newSelected = TRUE;
  512.     redisplay = TRUE;
  513.   }
  514.  
  515.   if (_new->core.background_pixel != _current->core.background_pixel)
  516.   {
  517.     gcValues.foreground = gcValues.background = _new->core.background_pixel;
  518.     gcMask |= (GCForeground | GCBackground);
  519.     newErase = TRUE;
  520.     redisplay = TRUE;
  521.   }
  522.  
  523.   if (CMAP.foreground != _current->cmap.foreground)
  524.     newSelected = TRUE;
  525.  
  526.   if (CMAP.selected != _current->cmap.selected)
  527.   {
  528.     if (CMAP.selected < 0)
  529.     {
  530.       MyXtWarning("CmapWidget: Selected pixel cannot be negative! Selected set to 0.");
  531.       CMAP.selected = 0;
  532.     }
  533.  
  534.     if (CMAP.lastIndex == LastIndexDefault) 
  535.       CMAP.lastIndex = CMAP.availColors-1;
  536.  
  537.     if (CMAP.lastIndex < CMAP.firstIndex)
  538.     {
  539.       MyXtWarning("CmapWidget: LastIndex (%d) cannot be less than FirstIndex (%d).  LastIndex set to %d.",
  540.         CMAP.lastIndex, CMAP.firstIndex, CMAP.firstIndex+1);
  541.       CMAP.lastIndex = CMAP.firstIndex + 1;
  542.     }
  543.  
  544.     if (CMAP.lastIndex > CMAP.availColors-1)
  545.     {
  546.       MyXtWarning("CmapWidget: LastIndex (%d) cannot be more than greatest index (%d).  LastIndex set to %d.",
  547.         CMAP.lastIndex, CMAP.availColors-1, CMAP.availColors-1);
  548.       CMAP.lastIndex = CMAP.availColors-1;
  549.     }
  550.  
  551.     CMAP.usedColors = MIN(CMAP.lastIndex-CMAP.firstIndex+1, CMAP.availColors);
  552.  
  553.     CMAP.numX = (int)floor(sqrt((double)(CMAP.usedColors)));
  554.     CMAP.numY = CMAP.usedColors / CMAP.numX + (CMAP.usedColors % CMAP.numX ? 1 : 0);
  555.  
  556.     if (CMAP.selected > CMAP.usedColors-1)
  557.     {
  558.       MyXtWarning("CmapWidget: Selected pixel (%d) is greater than %d. Selected set to %d.",
  559.         CMAP.selected, CMAP.usedColors-1, CMAP.usedColors-1);
  560.       CMAP.selected = CMAP.lastIndex;
  561.     }
  562.  
  563.     if (CMAP.selected < 0)
  564.     {
  565.       MyXtWarning("CmapWidget: Selected pixel (%d) cannot be negative. Selected set to 0.",
  566.         CMAP.selected);
  567.       CMAP.selected = 0;
  568.     }
  569.  
  570.     DrawLabel(_current, _current->cmap.eraseGC);
  571.     CMAP.selectedColor.pixel = CMAP.selected+CMAP.firstIndex;
  572.     XQueryColor(display, _new->core.colormap, &CMAP.selectedColor);
  573.     ReString(_new);
  574.     DrawLabel(_new, CMAP.foregroundGC);
  575.     DrawBox(_new, _current->cmap.selected);
  576.     DrawSelected(_new, CMAP.selected);
  577.     XFlush(XtDisplay(_new));
  578.   }
  579.     
  580.   if (CMAP.font->fid != _current->cmap.font->fid)
  581.   {
  582.     XFreeFont(display, _current->cmap.font);
  583.     XSetFont(display, CMAP.foregroundGC, CMAP.font->fid);
  584.     ReString(_new);
  585.     newSelected = TRUE;
  586.     newErase = TRUE;
  587.     redisplay = TRUE;
  588.   }
  589.  
  590.   gcValues.font = CMAP.font->fid;
  591.  
  592.   if (newErase)
  593.   {
  594.     XtReleaseGC((Widget)_new, CMAP.eraseGC);
  595.     _new->cmap.eraseGC = XtGetGC((Widget)_new, gcMask, &gcValues);
  596.   }
  597.  
  598.   if (newSelected)
  599.   {
  600.     XtReleaseGC((Widget)_new, CMAP.foregroundGC);
  601.     gcValues.foreground = CMAP.foreground;
  602.     _new->cmap.foregroundGC = XtGetGC((Widget)_new, GCFont | GCForeground, &gcValues);
  603.   }
  604.  
  605.   if ((CMAP.boxHeight != _current->cmap.boxHeight) ||
  606.       (CMAP.boxWidth != _current->cmap.boxWidth))
  607.   {
  608.     Resize(_new);
  609.     redisplay = TRUE;
  610.   }
  611.  
  612.   return redisplay;
  613. }
  614. #undef CMAP
  615.  
  616. static void ReString(_w)
  617. CmapWidget _w;
  618. {
  619.   sprintf(_w->cmap.label, RGB_STRING, _w->cmap.selectedColor.red, _w->cmap.selectedColor.green,
  620.     _w->cmap.selectedColor.blue, _w->cmap.selected+1, _w->cmap.usedColors);
  621.   _w->cmap.labelHeight = _w->cmap.font->ascent + _w->cmap.font->descent;
  622.   _w->cmap.labelWidth = XTextWidth(_w->cmap.font, _w->cmap.label, strlen(_w->cmap.label));
  623.   _w->cmap.labelPos.x = (_w->core.width/2) - (_w->cmap.labelWidth)/2;
  624.   _w->cmap.labelPos.y = _w->cmap.drawPos.y + (_w->cmap.numY * _w->cmap.realBoxHeight) + _w->cmap.font->ascent +
  625.     _w->cmap.margin;
  626. }
  627.  
  628. static int XYtoBox(_w, _x, _y)
  629. CmapWidget _w; 
  630. int _x; 
  631. int _y;
  632. {
  633.   int trux, truy;
  634.   int twidth, theight;
  635.   int x, y;
  636.  
  637.   trux = _x - _w->cmap.drawPos.x;
  638.   truy = _y - _w->cmap.drawPos.y;
  639.   twidth = _w->cmap.numX * _w->cmap.realBoxWidth;
  640.   theight = _w->cmap.numY * _w->cmap.realBoxHeight; 
  641.  
  642.   if ((trux < 0) || (truy < 0) || (trux >= twidth) || (truy >= theight))
  643.    return -1;
  644.  
  645.   return trux/_w->cmap.realBoxWidth +
  646.     truy/_w->cmap.realBoxHeight * _w->cmap.numX;
  647. }
  648.  
  649. static void Left(_w, _event, _argv, _argc)
  650. CmapWidget _w; 
  651. XEvent *_event; 
  652. String *_argv; 
  653. int *_argc;
  654. {
  655.   int box;
  656.   Arg warg;
  657.   CmapCallbackStruct ccs;
  658.  
  659.   if (*_argc != 0)
  660.     MyXtWarning("CmapWidget: Left takes no paramaters.");
  661.  
  662.   box = ((_w->cmap.selected - 1) < 0) ? _w->cmap.usedColors - 1 : _w->cmap.selected - 1;
  663.   XtSetArg(warg, XtNselected, box);
  664.   XtSetValues((Widget)_w, &warg, 1);
  665.   ccs.reason = CMAP_LEFT;
  666.   ccs.event = _event;
  667.   ccs.color = _w->cmap.selectedColor;
  668.   XtCallCallbacks((Widget)_w, XtNchangeCallback, &ccs);
  669. }
  670.  
  671. static void Right(_w, _event, _argv, _argc)
  672. CmapWidget _w; 
  673. XEvent *_event;
  674. String *_argv; 
  675. int *_argc;
  676. {
  677.   int box;
  678.   Arg warg;
  679.   CmapCallbackStruct ccs;
  680.  
  681.   if (*_argc != 0)
  682.     MyXtWarning("CmapWidget: Right takes no paramaters.");
  683.  
  684.   box = ((_w->cmap.selected + 1) == _w->cmap.usedColors ) ? 0  : _w->cmap.selected + 1;
  685.   XtSetArg(warg, XtNselected, box);
  686.   XtSetValues((Widget)_w, &warg, 1);
  687.   ccs.reason = CMAP_RIGHT;
  688.   ccs.event = _event;
  689.   ccs.color = _w->cmap.selectedColor;
  690.   XtCallCallbacks((Widget)_w, XtNchangeCallback, &ccs);
  691. }
  692.  
  693. static void Up(_w, _event, _argv, _argc)
  694. CmapWidget _w; 
  695. XEvent *_event;
  696. String *_argv;
  697. int *_argc;
  698. {
  699.   int box;
  700.   Arg warg;
  701.   CmapCallbackStruct ccs;
  702.  
  703.   if (*_argc != 0)
  704.     MyXtWarning("CmapWidget: Up takes no paramaters.");
  705.  
  706.   box = _w->cmap.selected - _w->cmap.numX;
  707.  
  708.   if (box < 0)
  709.   {
  710.     box += _w->cmap.numX * (_w->cmap.numY+1) + 1;
  711.     while (box > _w->cmap.usedColors-1)
  712.       box -= _w->cmap.numX;
  713.   }
  714.  
  715.   XtSetArg(warg, XtNselected, box);
  716.   XtSetValues((Widget)_w, &warg, 1);
  717.   ccs.reason = CMAP_UP;
  718.   ccs.event = _event;
  719.   ccs.color = _w->cmap.selectedColor;
  720.   XtCallCallbacks((Widget)_w, XtNchangeCallback, &ccs);
  721. }
  722.  
  723. static void Down(_w, _event, _argv, _argc)
  724. CmapWidget _w;
  725. XEvent *_event;
  726. String *_argv;
  727. int *_argc;
  728. {
  729.   int box;
  730.   Arg warg;
  731.   CmapCallbackStruct ccs;
  732.  
  733.   if (*_argc != 0)
  734.     MyXtWarning("CmapWidget: Down takes no paramaters.");
  735.  
  736.   box = _w->cmap.selected + _w->cmap.numX;
  737.  
  738.   if (box >= _w->cmap.usedColors)
  739.   {
  740.     box -= _w->cmap.numX * (_w->cmap.numY+1) + 1;
  741.     while (box < 0)
  742.       box += _w->cmap.numX;
  743.   } 
  744.  
  745.   XtSetArg(warg, XtNselected, box);
  746.   XtSetValues((Widget)_w, &warg, 1);
  747.   ccs.reason = CMAP_DOWN;
  748.   ccs.event = _event;
  749.   ccs.color = _w->cmap.selectedColor;
  750.   XtCallCallbacks((Widget)_w, XtNchangeCallback, &ccs);
  751. }
  752.  
  753. static void Select(_w, _event, _argv, _argc)
  754. CmapWidget _w;
  755. XEvent *_event;
  756. String *_argv;
  757. int *_argc;
  758. {
  759.   int box;
  760.   int x, y;
  761.   Arg warg;
  762.   CmapCallbackStruct ccs;
  763.  
  764.   switch (_event->type)
  765.   {
  766.     case ButtonPress:
  767.     case ButtonRelease:
  768.       x = ((XButtonEvent *)_event)->x;
  769.       y = ((XButtonEvent *)_event)->y;
  770.       break;
  771.     case KeyPress:
  772.     case KeyRelease:
  773.       x = ((XKeyEvent *)_event)->x;
  774.       y = ((XKeyEvent *)_event)->y;
  775.       break;
  776.     case MotionNotify:
  777.       x = ((XMotionEvent *)_event)->x;
  778.       y = ((XMotionEvent *)_event)->y;
  779.       break;
  780.     default: return; break;
  781.   }
  782.  
  783.   if ((box = XYtoBox(_w, x, y)) < 0)
  784.     return;
  785.  
  786.   if (box ==_w->cmap.selected)
  787.     return;
  788.  
  789.   if (box > _w->cmap.usedColors-1)
  790.     return;
  791.  
  792.   XtSetArg(warg, XtNselected, box);
  793.   XtSetValues((Widget)_w, &warg, 1);
  794.   ccs.reason = CMAP_SELECT;
  795.   ccs.event = _event;
  796.   ccs.color = _w->cmap.selectedColor;
  797.   XtCallCallbacks((Widget)_w, XtNchangeCallback, &ccs);
  798. }
  799.  
  800. #define MAXSTRING 300
  801.  
  802. static void MyXtWarning(_format, va_alist)
  803. char *_format; 
  804. va_dcl   /* stupid define already has a ; on it */
  805. {
  806.   va_list parms;
  807.   char dest[MAXSTRING];
  808.  
  809.   va_start(parms);
  810.   vsprintf(dest, _format, parms);
  811.   va_end(parms);
  812.  
  813.   XtWarning(dest);
  814. }
  815.  
  816. /* External routines */
  817.  
  818. /* If you have
  819. ** an application that plays with the colormap, you 
  820. ** must verify that the label is correct for that 
  821. ** color (ie, the r,g,b values are correct.
  822. ** * NOTE * The event is NULL in the callback.
  823. */
  824.  
  825. void CmapVerifySelectedColor(_w, _notify)
  826. Widget _w;
  827. Boolean _notify;
  828. {
  829.   XColor color;
  830.   CmapWidget cw;
  831.  
  832.   if (!(XtIsCmap(_w)))
  833.   {
  834.     MyXtWarning("Widget passed to CmapVerifySelectedColor is not a Cmap widget!");
  835.     return;
  836.   }
  837.  
  838.   cw = (CmapWidget)_w;
  839.   color.pixel = cw->cmap.selected;
  840.   XQueryColor(XtDisplay(cw), cw->core.colormap, &color);
  841.   DrawLabel(cw, cw->cmap.eraseGC);
  842.   cw->cmap.selectedColor = color;
  843.   ReString(cw);
  844.   DrawLabel(cw, cw->cmap.foregroundGC);
  845.  
  846.   if (_notify)
  847.   {
  848.     CmapCallbackStruct ccs;
  849.     ccs.event = (XEvent *)NULL;
  850.     ccs.color = color;
  851.     ccs.reason = CMAP_VERIFY;
  852.     XtCallCallbacks(_w, XtNchangeCallback, &ccs);
  853.   }
  854. }
  855.  
  856. /* 
  857. ** Currently selected box in colormap.
  858. ** If the widget is not a Cmap widget, the returned value is undefined 
  859. */
  860.  
  861. XColor CmapGetSelected(_w)
  862. Widget _w;
  863. {
  864.   if (!XtIsCmap(_w))
  865.   {
  866.     XColor xc;
  867.     MyXtWarning("Widget passed to CmapGetSelected is not a Cmap widget!");
  868.     return xc;
  869.   }
  870.   return ((CmapWidget)_w)->cmap.selectedColor;
  871. }
  872.