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