home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xcolored.zip / xcoloredit / xcoloredit.c < prev    next >
C/C++ Source or Header  |  1992-01-25  |  28KB  |  1,052 lines

  1. #ifndef lint
  2. static char sccsid[] = "@(#)xcoloredit.c    1.2 (UKC) 25/1/92";
  3. #endif /* !lint */
  4.  
  5. /* 
  6.  * Copyright 1990,1992 Richard Hesketh / rlh2@ukc.ac.uk
  7.  *                Computing Lab. University of Kent at Canterbury, UK
  8.  *
  9.  * Permission to use, copy, modify and distribute this software and its
  10.  * documentation for any purpose is hereby granted without fee, provided that
  11.  * the above copyright notice appear in all copies and that both that
  12.  * copyright notice and this permission notice appear in supporting
  13.  * documentation, and that the names of Richard Hesketh and The University of
  14.  * Kent at Canterbury not be used in advertising or publicity pertaining to
  15.  * distribution of the software without specific, written prior permission.
  16.  * Richard Hesketh and The University of Kent at Canterbury make no
  17.  * representations about the suitability of this software for any purpose.
  18.  * It is provided "as is" without express or implied warranty.
  19.  *
  20.  * Richard Hesketh AND THE UNIVERSITY OF KENT AT CANTERBURY DISCLAIMS ALL
  21.  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
  22.  * OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Richard Hesketh OR THE
  23.  * UNIVERSITY OF KENT AT CANTERBURY BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  24.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  25.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  26.  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  27.  * OF THIS SOFTWARE.
  28.  *
  29.  * Author:  Richard Hesketh / rlh2@ukc.ac.uk, 
  30.  *                Computing Lab. University of Kent at Canterbury, UK
  31.  */
  32.  
  33. /* A picapix lookalike under X11 */
  34.  
  35. /*
  36.  * xcoloredit - a colour palette mixer.  Allows existing colormap entries
  37.  *        to be edited.
  38.  */
  39.  
  40. #include <stdio.h>
  41. #include <X11/Xatom.h>
  42. #include <X11/X.h>
  43. #include <X11/Intrinsic.h>
  44. #include <X11/StringDefs.h>
  45. #include <X11/Shell.h>
  46. #include <X11/Xaw/Toggle.h>
  47. #include <X11/Xaw/Command.h>
  48. #include <X11/Xaw/Scrollbar.h>
  49. #include <X11/Xaw/Label.h>
  50. #include <X11/Xaw/Form.h>
  51. #include <X11/Xaw/Box.h>
  52. #include <X11/Xmu/Atoms.h>
  53. #include "Xcoloredit.h"
  54. #include "color.h"
  55.  
  56. #define PRIMARY_COLOR "PRIMARY_COLOR"
  57. #define XA_PRIMARY_COLOR XmuInternAtom(XtDisplay(w),_XA_PRIMARY_COLOR)
  58. static AtomPtr _XA_PRIMARY_COLOR = NULL;
  59.  
  60. extern void exit();
  61. extern void XukcRegisterApplicationDefaults();
  62. extern Display *XukcToolkitInitialize();
  63.  
  64. static void OwnSelection();
  65.  
  66. /* callback routines */
  67. static void Set_Selection();
  68. static void Quit();
  69. static void Thumbed();
  70. static void Scrolled();
  71. static void Load();
  72. static void Store();
  73. static void Update_HSV();
  74. static void Update_Triple();
  75.  
  76. /* action routines */
  77. static void lock_toggle();
  78. static void pick_memory();
  79. static void draw_boxed();
  80. static void erase_boxed();
  81. static void border();
  82. static void update_triple();
  83. static void set_scroll();
  84. static void stop_scroll();
  85. static void move_scroll();
  86. static void change_text_colour();
  87.  
  88.  
  89. #define MEMORY_OFFSET    8
  90. #define NUM_MEMORIES    36
  91. #define NUM_IN_ROW    12
  92. #define MAX_COLORS    NUM_MEMORIES+MEMORY_OFFSET
  93. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  94. #define COLOR(color_el,rgb) (colors[color_el].rgb/256)
  95. #define CHANGE_RED(element) \
  96.         pass_value = 1.0 - (double)(COLOR(element,red)/255.0); \
  97.         Thumbed(redScroll, RED, (XtPointer)(&pass_value))
  98. #define CHANGE_GREEN(element) \
  99.         pass_value = 1.0 - (double)(COLOR(element,green)/255.0); \
  100.         Thumbed(greenScroll, GREEN, (XtPointer)(&pass_value))
  101. #define CHANGE_BLUE(element) \
  102.         pass_value = 1.0 - (double)(COLOR(element,blue)/255.0); \
  103.         Thumbed(blueScroll, BLUE, (XtPointer)(&pass_value))
  104.  
  105. static XColor colors[MAX_COLORS];
  106. static Display     *dpy;
  107. static Colormap    cmap;
  108. static GC    boxedGC, boxedChangedGC, unboxedGC;
  109.  
  110. static RGB rgb_values;
  111. static HSV hsv_values;
  112. static int buttons_down = 0;
  113. static int bars_locked = 0;
  114. static double locked_top = 1.0, red_top, green_top, blue_top;
  115. static float pass_value;
  116. static int last_pos;
  117. static Boolean do_change = TRUE;
  118. static int current_memory = 0;
  119. static Pixel original_background;
  120.  
  121. static Widget toplevel, mixingForm, mixedColor;
  122. static Widget redLocked, greenLocked, blueLocked, title;
  123. static Widget redIntensity, greenIntensity, blueIntensity, tripleValue;
  124. static Widget redScroll, greenScroll, blueScroll, lockedScroll;
  125. static Widget hueScroll, satScroll, valScroll;
  126. static Widget hueLabel, satLabel, valLabel;
  127. static Widget quit;
  128. static Widget colorMemory[NUM_MEMORIES];
  129. static Boolean colorUsed[NUM_MEMORIES];
  130.  
  131. #define RED    1
  132. #define GREEN  2
  133. #define BLUE   4
  134. #define LOCKED 8
  135. #define HUE    16
  136. #define SAT    32
  137. #define VAL    64
  138.  
  139. #define MIX_COLOR    0
  140. #define RED_COLOR    1
  141. #define GREEN_COLOR    2
  142. #define BLUE_COLOR    3
  143. #define PURE_BLACK    4
  144. #define PURE_RED    5
  145. #define PURE_GREEN    6
  146. #define PURE_BLUE    7
  147.  
  148. struct app_resources {
  149.     Boolean silent;
  150.     String text;
  151.     String format;
  152. } prog_res;
  153.  
  154. static XtActionsRec actionTable[] = {
  155.     {"lock_toggle", lock_toggle},
  156.     {"pick_memory", pick_memory},
  157.     {"draw_boxed", draw_boxed},
  158.     {"erase_boxed", erase_boxed},
  159.     {"border", border},
  160.     {"update_triple", update_triple},
  161.     {"set_scroll", set_scroll},
  162.     {"stop_scroll", stop_scroll},
  163.     {"move_scroll", move_scroll},
  164.     {"change_text_colour", change_text_colour},
  165. };
  166.  
  167. static XrmOptionDescRec options[] = {
  168.     { "-silent", ".silent", XrmoptionNoArg, (caddr_t)"true" },
  169.     { "-text", ".text", XrmoptionSepArg, (caddr_t)NULL },
  170.     { "-format", ".format", XrmoptionSepArg, (caddr_t)NULL },
  171. };
  172.  
  173. #define offset(field) XtOffset(struct app_resources *, field)
  174. static XtResource resources[] = {
  175.     { "silent", "Silent", XtRBoolean, sizeof(Boolean),
  176.       offset(silent), XtRImmediate, (XtPointer)FALSE },
  177.     { "text", "Text", XtRString, sizeof(String),
  178.       offset(text), XtRImmediate, (XtPointer)NULL },
  179.     { "format", "Format", XtRString, sizeof(String),
  180.       offset(format), XtRImmediate, (XtPointer)"#%02x%02x%02x" }
  181. };
  182. #undef offset
  183.  
  184.  
  185. void main(argc, argv)
  186. unsigned int argc;
  187. char **argv;
  188. {
  189.     Status ok;
  190.     unsigned long plane_masks;
  191.     unsigned long pixels[MAX_COLORS];
  192.     Cardinal i, j, k;
  193.     XGCValues values;
  194.     Widget temp;
  195.  
  196.     dpy = XukcToolkitInitialize((String)NULL, "xcoloredit", "Xcoloredit",
  197.             &argc, argv,
  198.             (XrmOptionDescRec *)options, XtNumber(options));
  199.     XukcRegisterApplicationDefaults(DefaultScreenOfDisplay(dpy),
  200.                     app_defaults, XtNumber(app_defaults));
  201.         toplevel = XtVaAppCreateShell("xcoloredit", "Xcoloredit",
  202.                                         applicationShellWidgetClass, dpy,
  203.                                         NULL);
  204.     XtGetApplicationResources(toplevel, &prog_res, resources,
  205.                     XtNumber(resources), (ArgList)NULL, 0);
  206.  
  207.     cmap = DefaultColormap(dpy, DefaultScreen(dpy));
  208.     if(!XAllocColorCells(dpy, cmap, 0, &plane_masks, 0, pixels,
  209.        MAX_COLORS-1))
  210.         XtError("xcoloredit: Not enough colormap entries available");
  211.  
  212.     /* allocate the standard cells used by the application */
  213.     for (j = 0, i = 1; i < MEMORY_OFFSET; i++) {
  214.         colors[i].pixel = pixels[j++];
  215.         colors[i].flags = DoRed | DoGreen | DoBlue;
  216.     }
  217.  
  218.     /* initialize the pixel memory locations */
  219.     for (k = 1, i = MEMORY_OFFSET; i < MAX_COLORS; i++) {
  220.         colors[i].flags = DoRed | DoGreen | DoBlue;
  221.         if (argc > 1) {
  222.             /* pull in any colormap entries specified on the
  223.              * command line */
  224.             colors[i].pixel = atoi(argv[k++]);
  225.             colorUsed[i-MEMORY_OFFSET] = TRUE;
  226.             argc--;
  227.         } else {
  228.             colors[i].pixel = pixels[j++];
  229.             colors[i].red = colors[i].green = colors[i].blue = 0;
  230.             colorUsed[i-MEMORY_OFFSET] = FALSE;
  231.         }
  232.     }
  233.  
  234.     /* retrieve the given colormap entries current values */
  235.     if (k > 1)
  236.         XQueryColors(dpy, cmap, &(colors[MEMORY_OFFSET]), k-1);
  237.  
  238.     current_memory = 0;
  239.  
  240.     colors[MIX_COLOR].pixel = colors[MEMORY_OFFSET].pixel;
  241.     colors[MIX_COLOR].flags = DoRed | DoGreen | DoBlue;
  242.     colors[MIX_COLOR].red = colors[MEMORY_OFFSET].red;
  243.     colors[MIX_COLOR].green = colors[MEMORY_OFFSET].green;
  244.     colors[MIX_COLOR].blue = colors[MEMORY_OFFSET].blue;
  245.  
  246.     colors[PURE_BLACK].red = colors[PURE_BLACK].green = 0;
  247.     colors[PURE_BLACK].blue = 0;
  248.  
  249.     colors[PURE_RED].blue = colors[PURE_RED].green = 0;
  250.     colors[RED_COLOR].blue = colors[RED_COLOR].green = 0; 
  251.     colors[PURE_RED].red = colors[RED_COLOR].red = (short)~0;
  252.  
  253.     /* not as pure as it should be!! looks better like this though 8-) */
  254.     colors[PURE_GREEN].red = 0x4f*256;
  255.     colors[PURE_GREEN].green = 0xb5*256;
  256.     colors[PURE_GREEN].blue = 0x1e*256;
  257.  
  258.     colors[GREEN_COLOR].red = colors[GREEN_COLOR].blue = 0;
  259.     colors[GREEN_COLOR].green = (short)~0;
  260.  
  261.     colors[PURE_BLUE].red = colors[PURE_BLUE].green = 0;
  262.     colors[BLUE_COLOR].red = colors[BLUE_COLOR].green = 0;
  263.     colors[PURE_BLUE].blue = colors[BLUE_COLOR].blue = (short)~0;
  264.  
  265.     XStoreColors(dpy, cmap, colors, MAX_COLORS);
  266.     for (i = MEMORY_OFFSET; i < j; i++)
  267.         colors[i].flags = DoRed | DoGreen | DoBlue;
  268.  
  269.     XtAppAddActions(XtWidgetToApplicationContext(toplevel),
  270.                     actionTable, XtNumber(actionTable));
  271.  
  272.     /* create the UI */
  273.     mixingForm = XtVaCreateManagedWidget("mixingForm", formWidgetClass,
  274.                         toplevel, NULL);
  275.     redLocked = XtVaCreateManagedWidget("redLocked", labelWidgetClass,
  276.                         mixingForm, NULL);
  277.     greenLocked = XtVaCreateManagedWidget("greenLocked", labelWidgetClass,
  278.                         mixingForm, NULL);
  279.     blueLocked = XtVaCreateManagedWidget("blueLocked", labelWidgetClass,
  280.                         mixingForm, NULL);
  281.     title = XtVaCreateManagedWidget("title", labelWidgetClass,
  282.                         mixingForm, NULL);
  283.     redScroll = XtVaCreateManagedWidget("redScroll", scrollbarWidgetClass,
  284.                         mixingForm, NULL);
  285.     greenScroll = XtVaCreateManagedWidget("greenScroll",
  286.                 scrollbarWidgetClass, mixingForm, NULL);
  287.     blueScroll = XtVaCreateManagedWidget("blueScroll", scrollbarWidgetClass,
  288.                         mixingForm, NULL);
  289.     lockedScroll = XtVaCreateManagedWidget("lockedScroll",
  290.                 scrollbarWidgetClass, mixingForm, NULL);
  291.     mixedColor = XtVaCreateManagedWidget("mixedColor", labelWidgetClass,
  292.                     mixingForm,
  293.                     XtVaTypedArg, XtNforeground, 
  294.                     XtRString, "white", 6,
  295.                     XtNbackground, colors[MIX_COLOR].pixel,
  296.                     NULL);
  297.     if (prog_res.text != NULL)
  298.         XtVaSetValues(mixedColor, XtNlabel, prog_res.text, NULL);
  299.     redIntensity = XtVaCreateManagedWidget("redIntensity", widgetClass,
  300.                     mixingForm,
  301.                     XtNbackground, colors[RED_COLOR].pixel,
  302.                     NULL);
  303.     greenIntensity = XtVaCreateManagedWidget("greenIntensity", widgetClass,
  304.                 mixingForm,
  305.                 XtNbackground, colors[GREEN_COLOR].pixel,
  306.                 NULL);
  307.     blueIntensity = XtVaCreateManagedWidget("blueIntensity", widgetClass,
  308.                 mixingForm,
  309.                 XtNbackground, colors[BLUE_COLOR].pixel,
  310.                 NULL);
  311.     tripleValue = XtVaCreateManagedWidget("tripleValue", toggleWidgetClass,
  312.                         mixingForm, NULL);
  313.     quit = XtVaCreateManagedWidget("quit", commandWidgetClass, mixingForm,
  314.                         NULL);
  315.     hueLabel = XtVaCreateManagedWidget("hueLabel", labelWidgetClass,
  316.                         mixingForm, NULL);
  317.     satLabel = XtVaCreateManagedWidget("satLabel", labelWidgetClass,
  318.                         mixingForm, NULL);
  319.     valLabel = XtVaCreateManagedWidget("valLabel", labelWidgetClass,
  320.                         mixingForm, NULL);
  321.     hueScroll = XtVaCreateManagedWidget("hueScroll", scrollbarWidgetClass,
  322.                         mixingForm, NULL);
  323.     satScroll = XtVaCreateManagedWidget("satScroll", scrollbarWidgetClass,
  324.                         mixingForm, NULL);
  325.     valScroll = XtVaCreateManagedWidget("valScroll", scrollbarWidgetClass,
  326.                         mixingForm, NULL);
  327.  
  328.     temp = quit;
  329.     for (i = 0; i < NUM_MEMORIES; i++) {
  330.         if (i > 0 && i%NUM_IN_ROW == 0)
  331.             temp = colorMemory[i-1];
  332.         colorMemory[i] = XtVaCreateManagedWidget("colorMemory",
  333.                 widgetClass, mixingForm,
  334.                 XtNbackground, colors[i+MEMORY_OFFSET].pixel,
  335.                 XtNfromVert, temp,
  336.                 XtNfromHoriz,
  337.                 (i%NUM_IN_ROW ? colorMemory[i-1] : NULL),
  338.                 NULL);
  339.     }
  340.  
  341.     values.foreground = colors[PURE_RED].pixel;
  342.     values.line_width = 2;
  343.     values.line_style = LineOnOffDash;
  344.     boxedChangedGC = XtGetGC(mixingForm, GCForeground | GCLineWidth,
  345.                     &values);
  346.     boxedGC = XtGetGC(mixingForm, GCForeground | GCLineWidth | GCLineStyle,
  347.                     &values);
  348.  
  349.     XtVaGetValues(mixingForm, XtNbackground, &(values.foreground), NULL);
  350.     unboxedGC = XtGetGC(mixingForm, GCForeground | GCLineWidth, &values);
  351.  
  352.     original_background = values.foreground;
  353.     bars_locked = NULL;
  354.  
  355.     XtAddCallback(redScroll, XtNjumpProc, Thumbed, (XtPointer)RED);
  356.     XtAddCallback(greenScroll, XtNjumpProc, Thumbed, (XtPointer)GREEN);
  357.     XtAddCallback(blueScroll, XtNjumpProc, Thumbed, (XtPointer)BLUE);
  358.     XtAddCallback(lockedScroll, XtNjumpProc, Thumbed, (XtPointer)LOCKED);
  359.  
  360.     XtAddCallback(redScroll, XtNscrollProc, Scrolled, (XtPointer)RED);
  361.     XtAddCallback(greenScroll, XtNscrollProc, Scrolled, (XtPointer)GREEN);
  362.     XtAddCallback(blueScroll, XtNscrollProc, Scrolled, (XtPointer)BLUE);
  363.     XtAddCallback(lockedScroll, XtNscrollProc, Scrolled, (XtPointer)LOCKED);
  364.     XtAddCallback(hueScroll, XtNscrollProc, Scrolled, (XtPointer)HUE);
  365.     XtAddCallback(satScroll, XtNscrollProc, Scrolled, (XtPointer)SAT);
  366.     XtAddCallback(valScroll, XtNscrollProc, Scrolled, (XtPointer)VAL);
  367.  
  368.     XtAddCallback(hueScroll, XtNjumpProc, Update_HSV, (XtPointer)HUE);
  369.     XtAddCallback(satScroll, XtNjumpProc, Update_HSV, (XtPointer)SAT);
  370.     XtAddCallback(valScroll, XtNjumpProc, Update_HSV, (XtPointer)VAL);
  371.  
  372.     XtAddCallback(tripleValue, XtNcallback, Set_Selection,
  373.                         (XtPointer)PRIMARY_COLOR);
  374.     XtAddCallback(quit, XtNcallback, Quit, (XtPointer)toplevel);
  375.  
  376.     XtRealizeWidget(toplevel);
  377.  
  378.     /* set the scrollbars to the initial mixed colour values */
  379.     do_change = FALSE;
  380.     CHANGE_RED(MIX_COLOR);
  381.     CHANGE_GREEN(MIX_COLOR);
  382.     CHANGE_BLUE(MIX_COLOR);
  383.     do_change = TRUE;
  384.     XStoreColors(dpy, cmap, colors, 4);
  385.     update_triple((Widget)NULL, (XEvent *)NULL,
  386.                     (String *)NULL, (Cardinal *)NULL);
  387.  
  388.     XtAppMainLoop(XtWidgetToApplicationContext(toplevel));
  389. }
  390.  
  391. /* ARGSUSED */
  392. static void 
  393. Quit(w, client, call)
  394. Widget w;
  395. XtPointer client, call;
  396. {
  397.     Cardinal i;
  398.  
  399.     colors[current_memory+MEMORY_OFFSET].red = colors[MIX_COLOR].red;
  400.     colors[current_memory+MEMORY_OFFSET].green = colors[MIX_COLOR].green;
  401.     colors[current_memory+MEMORY_OFFSET].blue = colors[MIX_COLOR].blue;
  402.  
  403.     if (!prog_res.silent)
  404.         for (i = 0; i < NUM_MEMORIES; i++)
  405.             if (colorUsed[i]) {
  406.                 printf(prog_res.format,
  407.                       COLOR(i+MEMORY_OFFSET,red),
  408.                       COLOR(i+MEMORY_OFFSET,green),
  409.                       COLOR(i+MEMORY_OFFSET,blue));
  410.                 putchar('\n');
  411.             }
  412.     XtReleaseGC(mixingForm, boxedGC);
  413.     XtReleaseGC(mixingForm, boxedChangedGC);
  414.     XtReleaseGC(mixingForm, unboxedGC);
  415.     exit(0);
  416. }
  417.  
  418. static void
  419. lock_toggle(w, event, params, num_params)
  420. Widget w;
  421. XEvent *event;
  422. String *params;
  423. Cardinal *num_params;
  424. {
  425.     Arg args[1];
  426.     int button = WhichButton(params[0]);
  427.  
  428.     args[0].name = XtNbackground;
  429.     if (button & bars_locked) {
  430.         args[0].value = original_background;
  431.         bars_locked -= button;
  432.         if (!bars_locked)
  433.             XtSetSensitive(lockedScroll, FALSE);
  434.     } else {
  435.         switch (button) {
  436.             case RED:
  437.                 args[0].value = colors[PURE_RED].pixel;
  438.                 break;
  439.             case GREEN:
  440.                 args[0].value = colors[PURE_GREEN].pixel;
  441.                 break;
  442.             case BLUE:
  443.                 args[0].value = colors[PURE_BLUE].pixel;
  444.                 break;
  445.             default:
  446.                 return;
  447.                 /* NOT REACHED */
  448.         }
  449.         bars_locked += button;
  450.         XtSetSensitive(lockedScroll, TRUE);
  451.     }
  452.     move_lock();
  453.     XtSetValues(w, (ArgList)args, 1);
  454. }
  455.  
  456.  
  457. /* draw a dashed box around the given widget */
  458. static void
  459. draw_a_dotted_box(w, gc)
  460. Widget w;
  461. GC gc;
  462. {
  463.     Position x, y;
  464.     Dimension width, height, border_width;
  465.     Arg args[5];
  466.  
  467.     XtSetArg(args[0], XtNborderWidth, &border_width);
  468.     XtSetArg(args[1], XtNx, &x);
  469.     XtSetArg(args[2], XtNy, &y);
  470.     XtSetArg(args[3], XtNwidth, &width);
  471.     XtSetArg(args[4], XtNheight, &height);
  472.     XtGetValues(w, (ArgList)args, 5);
  473.  
  474.     x -= border_width + 1;
  475.     y -= border_width + 1;
  476.     width += border_width*2 + 4;
  477.     height += border_width*2 + 4;
  478.  
  479.     XDrawRectangle(XtDisplay(mixingForm), XtWindow(mixingForm), gc,
  480.                             x, y, width, height);
  481. }
  482.  
  483.  
  484. static void
  485. draw_boxed(w, event, params, num_params)
  486. Widget w;
  487. XEvent *event;
  488. String *params;
  489. Cardinal *num_params;
  490. {
  491.     draw_a_dotted_box(colorMemory[current_memory],
  492.                 colorUsed[current_memory] ? boxedChangedGC :
  493.                 boxedGC);
  494. }
  495.  
  496.  
  497. static void
  498. erase_boxed(w, event, params, num_params)
  499. Widget w;
  500. XEvent *event;
  501. String *params;
  502. Cardinal *num_params;
  503. {
  504.     draw_a_dotted_box(colorMemory[current_memory], unboxedGC);
  505. }
  506.  
  507.  
  508. static void
  509. pick_memory(w, event, params, num_params)
  510. Widget w;
  511. XEvent *event;
  512. String *params;
  513. Cardinal *num_params;
  514. {
  515.     int i;
  516.  
  517.     for (i = 0; i < NUM_MEMORIES; i++) {
  518.         if (w == colorMemory[i]) {
  519.             /* old memory cell */
  520.             draw_a_dotted_box(colorMemory[current_memory],
  521.                       unboxedGC);
  522.             colors[current_memory+MEMORY_OFFSET].red =
  523.                         colors[MIX_COLOR].red;
  524.             colors[current_memory+MEMORY_OFFSET].green =
  525.                         colors[MIX_COLOR].green;
  526.             colors[current_memory+MEMORY_OFFSET].blue =
  527.                         colors[MIX_COLOR].blue;
  528.             XStoreColor(dpy, cmap,
  529.                 &(colors[current_memory+MEMORY_OFFSET]));
  530.  
  531.             /* new memory cell */
  532.             current_memory = i;
  533.             draw_boxed((Widget)NULL, (XEvent *)NULL,
  534.                     (String *)NULL, (Cardinal *)NULL);
  535.  
  536.             colors[MIX_COLOR].pixel =
  537.                 colors[current_memory+MEMORY_OFFSET].pixel;
  538.  
  539.             if (colorUsed[current_memory]) {
  540.                 do_change = FALSE;
  541.                 CHANGE_RED(current_memory+MEMORY_OFFSET);
  542.                 CHANGE_GREEN(current_memory+MEMORY_OFFSET);
  543.                 CHANGE_BLUE(current_memory+MEMORY_OFFSET);
  544.                 do_change = TRUE;
  545.                 XStoreColors(dpy, cmap, colors, 4);
  546.                 update_triple((Widget)NULL, (XEvent *)NULL,
  547.                     (String *)NULL, (Cardinal *)NULL);
  548.             } else {
  549.                 colors[current_memory+MEMORY_OFFSET].red =
  550.                         colors[MIX_COLOR].red;
  551.                 colors[current_memory+MEMORY_OFFSET].green =
  552.                         colors[MIX_COLOR].green;
  553.                 colors[current_memory+MEMORY_OFFSET].blue =
  554.                         colors[MIX_COLOR].blue;
  555.                 XStoreColor(dpy, cmap,
  556.                       &(colors[current_memory+MEMORY_OFFSET]));
  557.             }
  558.             XtVaSetValues(mixedColor, XtNbackground,
  559.                     colors[MIX_COLOR].pixel, NULL);
  560.             break;
  561.         }
  562.     }
  563. }
  564.  
  565. static void
  566. ChangeBorder(button, now_up)
  567. int button;
  568. Boolean now_up;
  569. {
  570.     Widget scrollbar;
  571.  
  572.     switch (button) {
  573.         case RED:
  574.             scrollbar = redScroll;
  575.             button = now_up ? PURE_RED : PURE_BLACK;
  576.             break;
  577.         case GREEN:
  578.             scrollbar = greenScroll;
  579.             button = now_up ? PURE_GREEN : PURE_BLACK;
  580.             break;
  581.         case BLUE:
  582.             scrollbar = blueScroll;
  583.             button = now_up ? PURE_BLUE : PURE_BLACK;
  584.             break;
  585.         default:
  586.             return;
  587.             /* NOTREACHED */
  588.     }
  589.     XtVaSetValues(scrollbar, XtNborderColor, colors[button].pixel, NULL);
  590. }
  591.  
  592. static void
  593. border(w, event, params, num_params)
  594. Widget w;
  595. XEvent *event;
  596. String *params;
  597. Cardinal *num_params;
  598. {
  599.     Boolean reset = (Boolean)(*num_params == 1 && strcmp(params[0], "reset") == 0);
  600.  
  601.     if (w == redScroll)
  602.         ChangeBorder(RED, reset);
  603.     else {
  604.         if (w == greenScroll)
  605.             ChangeBorder(GREEN, reset);
  606.         else {
  607.             if (w == blueScroll)
  608.                 ChangeBorder(BLUE, reset);
  609.             else {
  610.                 if (bars_locked & RED) ChangeBorder(RED, reset);
  611.                 if (bars_locked & GREEN) ChangeBorder(GREEN, reset);
  612.                 if (bars_locked & BLUE) ChangeBorder(BLUE, reset);
  613.             }
  614.         }
  615.     }
  616. }
  617.  
  618.  
  619. static int
  620. WhichButton(name)
  621. String name;
  622. {
  623.     if (strcmp(name, "red") == 0)
  624.         return RED;
  625.     if (strcmp(name, "blue") == 0)
  626.         return BLUE;
  627.     if (strcmp(name, "green") == 0)
  628.         return GREEN;
  629.     return 0;
  630. }
  631.  
  632.  
  633. static void
  634. Update_Triple(w, client_data, call_data)
  635. Widget w;
  636. XtPointer client_data, call_data;
  637. {
  638.     String old_str;
  639.     char old_value[10];
  640.     Cardinal r, g, b;
  641.  
  642.     XtVaGetValues(w, XtNlabel, &old_str, NULL);
  643.     (void)strncpy(old_str, old_value, 8);
  644.     if (sscanf((char *)call_data, prog_res.format, &r, &g, &b) != 3) {
  645.         XtVaSetValues(w, XtNlabel, old_value, NULL);
  646.     }
  647. }
  648.  
  649.  
  650. static void
  651. change_text_colour(w, event, params, num_params)
  652. Widget w;
  653. XEvent *event;
  654. String *params;
  655. Cardinal *num_params;
  656. {
  657.     XtVaSetValues(mixedColor, XtNforeground,
  658.             colors[current_memory+MEMORY_OFFSET].pixel,
  659.             NULL);
  660. }
  661.  
  662.  
  663. static void
  664. update_triple(w, event, params, num_params)
  665. Widget w;
  666. XEvent *event;
  667. String *params;
  668. Cardinal *num_params;
  669. {
  670.     Arg args[1];
  671.     char hexvalue[10];
  672.  
  673.     (void)sprintf(hexvalue, prog_res.format,
  674.             COLOR(MIX_COLOR,red), COLOR(MIX_COLOR,green),
  675.             COLOR(MIX_COLOR,blue));
  676.     XtVaSetValues(tripleValue, XtNlabel, hexvalue, NULL);
  677.     OwnSelection(tripleValue, (XtPointer)FALSE, (XtPointer)TRUE);
  678.  
  679.     rgb_values.r = colors[MIX_COLOR].red;
  680.     rgb_values.g = colors[MIX_COLOR].green;
  681.     rgb_values.b = colors[MIX_COLOR].blue;
  682.  
  683.     hsv_values = RGBToHSV(rgb_values);
  684.  
  685. #ifdef SOLID_THUMB
  686.     XawScrollbarSetThumb(hueScroll, (float)(1.0 - hsv_values.h),
  687.                                 hsv_values.h);
  688.     XawScrollbarSetThumb(satScroll, (float)(1.0 - hsv_values.s),
  689.                                 hsv_values.s);
  690.     XawScrollbarSetThumb(valScroll, (float)(1.0 - hsv_values.v),
  691.                                 hsv_values.v);
  692. #else
  693.     XawScrollbarSetThumb(hueScroll, (float)(1.0 - hsv_values.h),
  694.                                 (float)0.025);
  695.     XawScrollbarSetThumb(satScroll, (float)(1.0 - hsv_values.s),
  696.                                 (float)0.025);
  697.     XawScrollbarSetThumb(valScroll, (float)(1.0 - hsv_values.v),
  698.                                 (float)0.025);
  699. #endif SOLID_THUMB
  700. }
  701.  
  702.  
  703. static void
  704. set_scroll(w, event, params, num_params)
  705. Widget w;
  706. XEvent *event;
  707. String *params;
  708. Cardinal *num_params;
  709. {
  710.     int button_down = WhichButton(params[0]);
  711.     last_pos = event->xbutton.y;
  712.     buttons_down |= button_down;
  713.     ChangeBorder(button_down, FALSE);
  714. }
  715.  
  716.  
  717. static void
  718. stop_scroll(w, event, params, num_params)
  719. Widget w;
  720. XEvent *event;
  721. String *params;
  722. Cardinal *num_params;
  723. {
  724.     int button_up = WhichButton(params[0]);
  725.     buttons_down &= ~button_up;
  726.     ChangeBorder(button_up, TRUE);
  727.     if (!buttons_down)
  728.         update_triple(w, event, params, num_params);
  729. }
  730.  
  731.  
  732. static void
  733. move_scroll(w, event, params, num_params)
  734. Widget w;
  735. XEvent *event;
  736. String *params;
  737. Cardinal *num_params;
  738. {
  739. #define ADJUST_CHANGE(color) if (change < 0) { \
  740.                     if (color + change < 0) \
  741.                         change = -color; \
  742.                  } else { \
  743.                     if (color + change > 255) \
  744.                         change = 255-color; \
  745.                  }
  746.  
  747.     int change;
  748.     float pass_value;
  749.     int red_pos, green_pos, blue_pos;
  750.  
  751.     if (buttons_down == 0)
  752.         return;
  753.  
  754.     change = last_pos - event->xmotion.y;
  755.     last_pos = event->xmotion.y;
  756.  
  757.     if (buttons_down & RED) {
  758.         red_pos = colors[MIX_COLOR].red/256;
  759.         ADJUST_CHANGE(red_pos);
  760.     }
  761.  
  762.     if (buttons_down & GREEN) {
  763.         green_pos = colors[MIX_COLOR].green/256;
  764.         ADJUST_CHANGE(green_pos);
  765.     }
  766.  
  767.     if (buttons_down & BLUE) {
  768.         blue_pos = colors[MIX_COLOR].blue/256;
  769.         ADJUST_CHANGE(blue_pos);
  770.     }
  771.  
  772.     red_pos += change;
  773.     green_pos += change;
  774.     blue_pos += change;
  775.  
  776.     /* update the new scroll bar positions and change the color */
  777.     do_change = FALSE;
  778.  
  779.     if (buttons_down & RED)    {
  780.         pass_value = 1.0 - (float)red_pos/255;
  781.         Thumbed(redScroll, RED, (XtPointer)(&pass_value));
  782.     }
  783.  
  784.     if (buttons_down & GREEN)    {
  785.         pass_value = 1.0 - (float)green_pos/255;
  786.         Thumbed(greenScroll, GREEN, (XtPointer)(&pass_value));
  787.     }
  788.  
  789.     if (buttons_down & BLUE)    {
  790.         pass_value = 1.0 - (float)blue_pos/255;
  791.         Thumbed(blueScroll, BLUE, (XtPointer)(&pass_value));
  792.     }
  793.  
  794.     do_change = TRUE;
  795.     XStoreColors(dpy, cmap, colors, 4);
  796.     if (!colorUsed[current_memory]) {
  797.         colorUsed[current_memory] = TRUE;
  798.         draw_boxed((Widget)NULL, (XEvent *)NULL,
  799.                 (String *)NULL, (Cardinal *)NULL);
  800.     }
  801.     update_triple((Widget)NULL, (XEvent *)NULL,
  802.             (String *)NULL, (Cardinal *)NULL);
  803. }
  804.  
  805.  
  806. static void
  807. Scrolled(w, closure, change)
  808. Widget w;
  809. XtPointer closure, change;
  810. {
  811.     Boolean going_up = (int)change < 0;
  812.     int which = (int)closure;
  813.     int pos = 0;
  814.  
  815.     switch (which) {
  816.         case RED:
  817.             pos = COLOR(MIX_COLOR,red);
  818.             break;
  819.         case BLUE:
  820.             pos = COLOR(MIX_COLOR,blue);
  821.             break;
  822.         case GREEN:
  823.             pos = COLOR(MIX_COLOR,green);
  824.             break;
  825.         case LOCKED:
  826.             pos = 255 - (int)(locked_top * 255 + 0.5);
  827.             break;
  828.         case HUE:
  829.         case SAT:
  830.         case VAL:
  831.             /* Not yet implemented */
  832.             return;
  833.         default:
  834.             fprintf(stderr, "Oops Scroll calldata invalid\n");
  835.             exit(1);
  836.     }
  837.  
  838.     if (going_up) {
  839.         if (pos > 0)
  840.             pos--;
  841.     } else {
  842.         if (pos < 255)
  843.             pos++;
  844.     }
  845.  
  846.     pass_value = 1.0 - (double)pos/255;
  847.     Thumbed(w, closure, (XtPointer)(&pass_value));
  848. }
  849.  
  850.     
  851.  
  852. static void
  853. Update_HSV(w, closure, ptr)
  854. Widget w;
  855. XtPointer closure, ptr;
  856. {
  857.     int which = (int)closure;
  858.     float r, g, b;
  859.     float per = *(float*)ptr;
  860.     double top = (double)per;
  861.     XEvent event;
  862.  
  863.     switch (which) {
  864.         case HUE:
  865.             hsv_values.h = 1.0 - top;
  866.             break;
  867.         case SAT:
  868.             hsv_values.s = 1.0 - top;
  869.             break;
  870.         case VAL:
  871.             hsv_values.v = 1.0 - top;
  872.             break;
  873.     }
  874.  
  875.     rgb_values = HSVToRGB(hsv_values);
  876.  
  877. #ifdef SOLID_THUMB
  878.     XawScrollbarSetThumb(w, top, (float)(1.0 - top));
  879. #else
  880.     XawScrollbarSetThumb(w, top, (float)0.025);
  881. #endif SOLID_THUMB
  882.  
  883.     do_change = FALSE;
  884.     pass_value = 1.0 - rgb_values.r/65536.0;
  885.     Thumbed(redScroll, (XtPointer)RED, (XtPointer)(&pass_value));
  886.     pass_value = 1.0 - rgb_values.g/65536.0;
  887.     Thumbed(greenScroll, (XtPointer)GREEN, (XtPointer)(&pass_value));
  888.     do_change = TRUE;
  889.     pass_value = 1.0 - rgb_values.b/65536.0;
  890.     Thumbed(blueScroll, (XtPointer)BLUE, (XtPointer)(&pass_value));
  891. }
  892.  
  893.  
  894. static void
  895. Thumbed(w, closure, ptr)
  896. Widget w;
  897. XtPointer closure, ptr;
  898. {
  899.     int which = (int)closure;
  900.     int mix;
  901.     float per = *(float*)ptr;
  902.     double top = (double)per;
  903.     XEvent event;
  904.  
  905.     mix = (int) ((1.0 - top) * 256.0 * 256.0);
  906.     if (mix > 0xFFFF)
  907.         mix = 0xFFFF;
  908.  
  909.     switch (which) {
  910.         case RED:
  911.             colors[MIX_COLOR].red = colors[RED_COLOR].red = mix;
  912.             red_top = top;
  913.             break;
  914.         case GREEN:
  915.             colors[MIX_COLOR].green = colors[GREEN_COLOR].green = mix;
  916.             green_top = top;
  917.             break;
  918.         case BLUE:
  919.             colors[MIX_COLOR].blue = colors[BLUE_COLOR].blue = mix;
  920.             blue_top = top;
  921.             break;
  922.         case LOCKED:
  923.             buttons_down = bars_locked;
  924.             last_pos = (int)((double)locked_top*255);
  925.             event.xmotion.y = (int)((double)top*255);
  926.             move_scroll(w, &event, (String *)NULL, (Cardinal *)NULL);
  927.             buttons_down = 0;
  928.             return;
  929.     }
  930.     if (do_change) {
  931.         XStoreColors(dpy, cmap, colors, 4);
  932.         if (!colorUsed[current_memory]) {
  933.             colorUsed[current_memory] = TRUE;
  934.             draw_boxed((Widget)NULL, (XEvent *)NULL,
  935.                     (String *)NULL, (Cardinal *)NULL);
  936.         }
  937.         update_triple((Widget)NULL, (XEvent *)NULL,
  938.                     (String *)NULL, (Cardinal *)NULL);
  939.     }
  940. #ifdef SOLID_THUMB
  941.     XawScrollbarSetThumb(w, top, (float)(1.0 - top));
  942. #else
  943.     XawScrollbarSetThumb(w, top, (float)0.025);
  944. #endif SOLID_THUMB
  945.     move_lock();
  946. }
  947.  
  948.  
  949. move_lock()
  950. {
  951.     locked_top = 1.0;
  952.     if (bars_locked & RED)
  953.         locked_top = MIN(locked_top, red_top);
  954.     if (bars_locked & BLUE)
  955.         locked_top = MIN(locked_top, blue_top);
  956.     if (bars_locked & GREEN)
  957.         locked_top = MIN(locked_top, green_top);
  958. #ifdef SOLID_THUMB
  959.     XawScrollbarSetThumb(lockedScroll, locked_top,
  960.                         (float)(1.0 - locked_top));
  961. #else
  962.     XawScrollbarSetThumb(lockedScroll, locked_top, (float)0.025);
  963. #endif SOLID_THUMB
  964. }
  965.  
  966.  
  967. /* Set the current selection of the PRIMARY_COLOR property to this colour */
  968. /* ARGSUSED */
  969. static void
  970. Set_Selection(w, client_data, call_data)
  971. Widget w;
  972. XtPointer client_data, call_data;
  973. {
  974.     Boolean own;
  975.  
  976.     XtVaGetValues(w, XtNstate, &own, NULL);
  977.     OwnSelection(w, (XtPointer)TRUE, (XtPointer)(own ? TRUE : FALSE));
  978. }
  979.  
  980.  
  981. static Boolean
  982. ConvertSelection(w, selection, target, type, value, length, format)
  983. Widget w;
  984. Atom *selection, *target, *type;
  985. XtPointer *value;
  986. unsigned long *length;
  987. int *format;
  988. {
  989.     if (XmuConvertStandardSelection(w, selection, target, type, value,
  990.         length, format))
  991.         return TRUE;
  992.  
  993.     if (*target == XA_STRING) {
  994.         String color_str;
  995.  
  996.         XtVaGetValues(tripleValue, XtNlabel, &color_str, NULL);
  997.         *type = XA_STRING;
  998.         *value = color_str;
  999.         *length = strlen(*value);
  1000.         *format = 8;
  1001.         return (TRUE);
  1002.     }
  1003.     return (FALSE);
  1004. }
  1005.  
  1006.  
  1007. /* ARGSUSED */
  1008. static void
  1009. LoseSelection(w, selection)
  1010. Widget w;
  1011. Atom *selection;
  1012. {
  1013.     XtVaSetValues(w, XtNstate, FALSE, NULL);
  1014. }
  1015.  
  1016.  
  1017. /* ARGSUSED */
  1018. static void
  1019. DoneSelection(w, selection, target)
  1020. Widget w;
  1021. Atom *selection, *target;
  1022. {
  1023.     /* we don't need to do anything here */
  1024. }
  1025.  
  1026.  
  1027. /* ARGSUSED */
  1028. static void
  1029. OwnSelection(w, client_data, call_data)
  1030. Widget w;
  1031. XtPointer client_data, call_data;
  1032. {
  1033.     Time time = XtLastTimestampProcessed(XtDisplay(w));
  1034.     Boolean primary = (Boolean)client_data;
  1035.     Boolean own = (Boolean)call_data;
  1036.  
  1037.     if (_XA_PRIMARY_COLOR == NULL)
  1038.         _XA_PRIMARY_COLOR = XmuMakeAtom(PRIMARY_COLOR);
  1039.  
  1040.     if (own) {
  1041.         XtOwnSelection(w, XA_PRIMARY_COLOR, time,
  1042.             ConvertSelection, LoseSelection, DoneSelection);
  1043.         if (primary)
  1044.             XtOwnSelection(w, XA_PRIMARY, time,
  1045.                ConvertSelection, LoseSelection, DoneSelection);
  1046.     } else {
  1047.         XtDisownSelection(w, XA_PRIMARY_COLOR, time);
  1048.         if (primary)
  1049.             XtDisownSelection(w, XA_PRIMARY, time);
  1050.     }
  1051. }
  1052.