1 /*
2 * FIG : Facility for Interactive Generation of figures
3 * Parts Copyright (c) 1994-2007 by Brian V. Smith
4 * Parts Copyright 1990,1992 Richard Hesketh
5 * Computing Lab. University of Kent at Canterbury, UK
6 *
7 * Pixel Grab color lookup Copyright 1993, David Koblas (koblas@netcom.com)
8 * and Copyright 1995, 1996 Torsten Martinsen (bullestock@dk-online.dk)
9 * (full copyright and permission notice appears above code)
10 *
11 * Any party obtaining a copy of these files is granted, free of charge, a
12 * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
13 * nonexclusive right and license to deal in this software and documentation
14 * files (the "Software"), including without limitation the rights to use,
15 * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
16 * the Software, and to permit persons who receive copies from any such
17 * party to do so, with the only requirement being that the above copyright
18 * and this permission notice remain intact.
19 *
20 ****************************************************************************
21 *
22 * Parts of this work were extracted from Richard Hesketh's xcoloredit
23 * client. Here is the copyright notice which must remain intact:
24 *
25 * Copyright 1990,1992 Richard Hesketh / rlh2@ukc.ac.uk
26 * Computing Lab. University of Kent at Canterbury, UK
27 *
28 * Permission to use, copy, modify and distribute this software and its
29 * documentation for any purpose is hereby granted without fee, provided that
30 * the above copyright notice appear in all copies and that both that
31 * copyright notice and this permission notice appear in supporting
32 * documentation, and that the names of Richard Hesketh and The University of
33 * Kent at Canterbury not be used in advertising or publicity pertaining to
34 * distribution of the software without specific, written prior permission.
35 * Richard Hesketh and The University of Kent at Canterbury make no
36 * representations about the suitability of this software for any purpose.
37 * It is provided "as is" without express or implied warranty.
38 *
39 * Richard Hesketh AND THE UNIVERSITY OF KENT AT CANTERBURY DISCLAIMS ALL
40 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
41 * OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Richard Hesketh OR THE
42 * UNIVERSITY OF KENT AT CANTERBURY BE LIABLE FOR ANY SPECIAL, INDIRECT OR
43 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
44 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
45 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
46 * OF THIS SOFTWARE.
47 *
48 * Author: Richard Hesketh / rlh2@ukc.ac.uk,
49 * Computing Lab. University of Kent at Canterbury, UK
50 */
51
52 /* A picapix lookalike under X11 */
53
54 /*
55 * xcoloredit - a colour palette mixer. Allows existing colormap entries
56 * to be edited.
57 */
58
59 #include "fig.h"
60 #include "figx.h"
61 #include "resources.h"
62 #include "mode.h"
63 #include "object.h"
64 #include "w_drawprim.h"
65 #include "w_indpanel.h"
66 #include "w_color.h"
67 #include "w_msgpanel.h"
68 #include "w_setup.h"
69 #include "w_util.h"
70
71 #include "f_util.h"
72
73 /* EXPORTS */
74
75 Widget delunusedColors;
76
77 /* LOCALS */
78
79 DeclareStaticArgs(30);
80
81 /* callback routines */
82 static void cancel_color_popup(Widget w, XtPointer closure, XtPointer call_data);
83 static void Thumbed(Widget w, XtPointer closure, XtPointer call_data);
84 static void Scrolled(Widget w, XtPointer closure, XtPointer call_data);
85 static void Update_HSV(Widget w, XtPointer closure, XtPointer call_data);
86 static void switch_edit(Widget w, XtPointer client_data, XtPointer call_data);
87
88 /* action routines */
89 static void lock_toggle(Widget w, XEvent *event, String *params, Cardinal *num_params);
90 static void _pick_memory(Widget w, XEvent *event, String *params, Cardinal *num_params);
91 static void pick_memory(int which);
92 static void update_triple(void);
93 static void update_scrl_triple(Widget w, XEvent *event, String *params, Cardinal *num_params);
94 static void update_from_triple(Widget w, XEvent *event, String *params, Cardinal *num_params);
95 static void move_scroll(Widget w, XEvent *event, String *params, Cardinal *num_params);
96 static void set_color_ok(Widget w, char *dum, XButtonEvent *ev, Boolean disp);
97 static void _set_std_color(Widget w, choice_info *sel_choice, XButtonEvent *ev);
98 static void set_std_color(int color);
99 static void add_color(Widget w, XtPointer closure, XtPointer call_data);
100 static void del_color(Widget w, XtPointer closure, XtPointer call_data);
101 static void undel_color(Widget w, XtPointer closure, XtPointer call_data);
102 static void lookup_color(Widget w, XtPointer closure, XtPointer call_data);
103 static void del_unused_user_colors(void);
104
105 /* some local procedures */
106
107 static int WhichButton(String name);
108 static Boolean color_used(int color, F_compound *list);
109 static void DoGrabPixel(Widget w, Pixel *p, Colormap *cmap);
110 static void doGrab(Widget w, int width, int height, int *x, int *y);
111 static void xyToWindowCmap(Display *dpy, int x, int y, Window base, int *nx, int *ny, Window *window, Colormap *cmap);
112 static void draw_boxed(int which);
113 static void erase_boxed(int which);
114 static void c_user_colors(F_compound *obj);
115 static void set_mixed_name(int i, int col);
116
117 #define S_RED 1
118 #define S_GREEN 2
119 #define S_BLUE 4
120 #define S_LOCKED 8
121 #define S_HUE 16
122 #define S_SAT 32
123 #define S_VAL 64
124
125 /* width/height and space between the scrollbars */
126 #define SCROLL_W 23
127 #define SCROLL_H 120
128 #define SCROLL_SP 4
129
130 /* width/height of the standard color cells */
131 #define STD_COL_W 31
132 #define STD_COL_H 20
133
134 /* width/height of the user color cells */
135 #define USR_COL_W 30
136 #define USR_COL_H 20
137 /* spacing between cells */
138 #define USR_COL_SP 2
139
140 /* thickness (height) of the scrollbar (fraction of total) */
141 #define THUMB_H 0.04
142
143 #define COLOR(color_el,rgb) ((color_el<0)? \
144 mixed_color[color_el+2].rgb/256: user_colors[color_el].rgb/256)
145 #define CHANGE_RED(element) \
146 pass_value = 1.0 - (float)(COLOR(element,red)/255.0); \
147 Thumbed(redScroll, (XtPointer)S_RED, (XtPointer)(&pass_value))
148 #define CHANGE_GREEN(element) \
149 pass_value = 1.0 - (float)(COLOR(element,green)/255.0); \
150 Thumbed(greenScroll, (XtPointer)S_GREEN, (XtPointer)(&pass_value))
151 #define CHANGE_BLUE(element) \
152 pass_value = 1.0 - (float)(COLOR(element,blue)/255.0); \
153 Thumbed(blueScroll, (XtPointer)S_BLUE, (XtPointer)(&pass_value))
154
155 static RGB rgb_values[2];
156 static HSV hsv_values;
157 static int buttons_down = 0;
158 static int bars_locked = 0;
159 static float locked_top = 1.0;
160 static float red_top, green_top, blue_top;
161 static float pass_value;
162 static int last_pos;
163 static Boolean do_change = True;
164 static Boolean modified[2];
165 static intptr_t edit_fill;
166 static Pixel original_background;
167 static XColor mixed_color[2];
168 static int mixed_color_indx[2];
169 static int colors_used[MAX_USR_COLS];
170
171 static Boolean moving_hsv = False;
172
173 static unsigned long plane_masks;
174 static unsigned long pixels[MAX_USR_COLS];
175
176 static Widget mixingForm;
177 static Widget mixedForm[2], mixedColor[2], mixedEdit[2];
178 static Widget tripleValue[2];
179 static Widget lockedLabel;
180 static Widget redLocked, greenLocked, blueLocked;
181 static Widget redScroll, greenScroll, blueScroll, lockedScroll;
182 static Widget hueScroll, satScroll, valScroll;
183 static Widget hueLabel, satLabel, valLabel;
184 static Widget ok_button;
185 static Widget addColor, delColor, undelColor, lookupColor;
186 static Widget colorCount;
187 static Widget userLabel, userForm, userViewport, userBox;
188 static Widget colorMemory[MAX_USR_COLS];
189
190 static XtActionsRec actionTable[] = {
191 {"lock_toggle", lock_toggle},
192 {"pick_memory", _pick_memory},
193 {"update_scrl_triple", update_scrl_triple},
194 {"update_from_triple", update_from_triple},
195 {"set_std_color", (XtActionProc)_set_std_color},
196 {"set_color_ok", (XtActionProc)set_color_ok},
197 };
198
199 static String set_panel_translations =
200 "<Key>Return: set_color_ok()\n";
201
202 static String edit_translations =
203 "<EnterWindow>: highlight(Always)\n\
204 <LeaveWindow>: unhighlight()\n\
205 <Btn1Down>,<Btn1Up>: set() notify()\n";
206
207 static String redLocked_translations =
208 "<Btn1Down>: lock_toggle(red)\n";
209 static String greenLocked_translations =
210 "<Btn1Down>: lock_toggle(green)\n";
211 static String blueLocked_translations =
212 "<Btn1Down>: lock_toggle(blue)\n";
213
214 static String std_color_translations =
215 "<Btn1Up>: set_std_color()\n\
216 <Btn1Up>(2): set_color_ok()\n";
217
218 static String user_color_translations =
219 "<Btn1Down>: pick_memory()\n\
220 <Btn1Down>(2): set_color_ok()\n";
221
222 static String triple_translations =
223 "<Key>Return: update_from_triple()\n";
224
225
226 void create_cell (int indx, XColor color);
227 void set_cmap (Window window);
228 void set_slider_sensitivity (void);
229 void set_mixed_color (int which);
230 void pick_contrast (XColor color, Widget widget);
231 int add_color_cell (Boolean use_exist, int indx, int r, int g, int b);
232 void count_one (int color);
233 void move_lock (void);
234 void StoreMix_and_Mem (void);
235 void ThumbHSV (Widget w, float top);
236
YStoreColor(Colormap colormap,XColor * color)237 void YStoreColor(Colormap colormap, XColor *color)
238 {
239 switch( tool_vclass ){
240 case GrayScale:
241 case PseudoColor:
242 XStoreColor(tool_d,colormap,color);
243 break;
244 case StaticGray:
245 case StaticColor:
246 case DirectColor:
247 case TrueColor:
248 XAllocColor(tool_d,colormap,color);
249 break;
250 default:
251 fprintf(stderr,"Unknown Visual Class\n");
252 }
253 }
254
YStoreColors(Colormap colormap,XColor * color,int ncolors)255 void YStoreColors(Colormap colormap, XColor *color, int ncolors)
256 {
257 int i;
258
259 for( i=0; i<ncolors; i++ )
260 YStoreColor(colormap,&color[i]);
261 }
262
create_color_panel(Widget form,Widget label,Widget cancel,ind_sw_info * isw)263 void create_color_panel(Widget form, Widget label, Widget cancel, ind_sw_info *isw)
264 {
265 intptr_t i;
266 choice_info *choice;
267 XColor col;
268 Pixel form_fg;
269 Widget below, beside, stdForm, stdLabel;
270 Widget sb;
271 char str[8];
272
273 current_memory = -1;
274 edit_fill = 0;
275 modified[0] = modified[1] = False;
276
277 /* add a callback to call a cancel function here besides the main one */
278 XtAddCallback(cancel, XtNcallback, cancel_color_popup, (XtPointer) 0);
279
280 pixels[0] = pixels[1] = 0;
281
282 if (all_colors_available) {
283 /* allocate two colorcells for the mixed fill and pen color widgets */
284 if (!alloc_color_cells(pixels,2)) {
285 file_msg("Can't allocate necessary colorcells, can't popup color panel");
286 XtDestroyWidget(isw->panel); /* the panel hasn't been fully created */
287 isw->panel = NULL;
288 return;
289 }
290 mixed_color[0].pixel = pixels[0];
291 mixed_color[1].pixel = pixels[1];
292 }
293
294 /* make carriage return anywhere in form do the OK button */
295 XtOverrideTranslations(form,
296 XtParseTranslationTable(set_panel_translations));
297
298 /* make the OK button */
299 FirstArg(XtNlabel, " Ok ");
300 NextArg(XtNfromVert, cancel);
301 NextArg(XtNborderWidth, INTERNAL_BW);
302 NextArg(XtNtop, XtChainTop);
303 NextArg(XtNbottom, XtChainTop);
304 NextArg(XtNleft, XtChainLeft);
305 NextArg(XtNright, XtChainLeft);
306 ok_button = XtCreateManagedWidget("set_color_ok", commandWidgetClass,
307 form, Args, ArgCount);
308 XtAddEventHandler(ok_button, ButtonReleaseMask, False,
309 (XtEventHandler) set_color_ok, (XtPointer) NULL);
310
311 /* put the fill and pen colors down the left side */
312
313 for (i=0; i<2; i++) {
314 /* wrap the edit fill/color panels in a form widget */
315 if (i==0) {
316 FirstArg(XtNfromVert, ok_button);
317 NextArg(XtNvertDistance, 30);
318 } else {
319 FirstArg(XtNfromVert, mixedForm[0]);
320 NextArg(XtNvertDistance, 20);
321 }
322 NextArg(XtNtop, XtChainTop);
323 NextArg(XtNbottom, XtChainTop);
324 NextArg(XtNleft, XtChainLeft);
325 NextArg(XtNright, XtChainLeft);
326 mixedForm[i] = XtCreateManagedWidget("mixedForm", formWidgetClass,
327 form, Args, ArgCount);
328
329 FirstArg(XtNlabel, (i==0)? "Edit Pen": "Edit Fill");
330 NextArg(XtNwidth, 70);
331 /* make it so that only one of the edit buttons are pressed */
332 if (i)
333 NextArg(XtNradioGroup, mixedEdit[0]);
334 else
335 NextArg(XtNstate, True); /* start with edit pen */
336 NextArg(XtNradioData, (XtPointer) (i+1)); /* can't use 0 */
337 mixedEdit[i] = XtCreateManagedWidget("mixedEdit", toggleWidgetClass,
338 mixedForm[i], Args, ArgCount);
339 XtAddCallback(mixedEdit[i], XtNcallback, switch_edit, (XtPointer) 0);
340
341 /* set up so that at one is always set */
342 XtOverrideTranslations(mixedEdit[i],
343 XtParseTranslationTable(edit_translations));
344
345 FirstArg(XtNbackground, mixed_color[i].pixel);
346 NextArg(XtNwidth, 70);
347 NextArg(XtNheight, 70);
348 NextArg(XtNfromVert, mixedEdit[i]);
349 NextArg(XtNvertDistance, 2);
350 NextArg(XtNresize, False);
351 mixedColor[i] = XtCreateManagedWidget("mixedColor", labelWidgetClass,
352 mixedForm[i], Args, ArgCount);
353
354 strcpy(str,"#000000");
355 FirstArg(XtNstring, str);
356 NextArg(XtNinsertPosition, strlen(str));
357 NextArg(XtNeditType, XawtextEdit);
358 NextArg(XtNwidth, 70);
359 NextArg(XtNfromVert, mixedColor[i]);
360 NextArg(XtNvertDistance, 2);
361 tripleValue[i] = XtCreateManagedWidget("tripleValue", asciiTextWidgetClass,
362 mixedForm[i], Args, ArgCount);
363 /* set value on carriage return */
364 XtOverrideTranslations(tripleValue[i],
365 XtParseTranslationTable(triple_translations));
366 }
367 /* make pen and fill hex value insensitive to start */
368 /* (until user picks memory) */
369 XtSetSensitive(tripleValue[0], False);
370 XtSetSensitive(tripleValue[1], False);
371
372 /********************************/
373 /* now the standard color panel */
374 /********************************/
375
376 FirstArg(XtNlabel, "Standard Colors");
377 NextArg(XtNfromHoriz, mixedForm[0]);
378 NextArg(XtNtop, XtChainTop);
379 NextArg(XtNbottom, XtChainTop);
380 NextArg(XtNleft, XtChainLeft);
381 NextArg(XtNright, XtChainLeft);
382 stdLabel = XtCreateManagedWidget("stdLabel", labelWidgetClass,
383 form, Args, ArgCount);
384
385 /* put them in a form just to make a nice border */
386 FirstArg(XtNfromVert, stdLabel);
387 NextArg(XtNvertDistance, 0);
388 NextArg(XtNfromHoriz, mixedForm[0]);
389 NextArg(XtNborderWidth, 2);
390 NextArg(XtNtop, XtChainTop);
391 NextArg(XtNbottom, XtChainTop);
392 NextArg(XtNleft, XtChainLeft);
393 NextArg(XtNright, XtChainLeft);
394 stdForm = XtCreateManagedWidget("stdForm", formWidgetClass,
395 form, Args, ArgCount);
396 choice = isw->choices;
397 /* create the standard color buttons */
398 for (i = 0; i < isw->numchoices; choice++, i++) {
399 FirstArg(XtNheight, STD_COL_H);
400 choice->value = (i >= NUM_STD_COLS ? DEFAULT : i);
401 /* check for new row of buttons */
402 if (i % isw->sw_per_row == 0) {
403 if (i == 0)
404 below = NULL;
405 else
406 below = beside;
407 beside = NULL;
408 }
409 /* standard color menu */
410 if (i < NUM_STD_COLS && i >= 0) {
411 if (all_colors_available) {
412 col.pixel = x_color(i);
413 XQueryColor(tool_d, tool_cm, &col);
414 if ((0.3 * col.red + 0.59 * col.green + 0.11 * col.blue) < 0.5 * (255 << 8))
415 form_fg = colors[WHITE];
416 else
417 form_fg = colors[BLACK];
418 /* set same so we don't get white or black when click on color */
419 NextArg(XtNforeground, x_color(i));
420 NextArg(XtNbackground, x_color(i));
421 /* mono display */
422 } else {
423 if (i == WHITE) {
424 NextArg(XtNforeground, x_fg_color.pixel);
425 NextArg(XtNbackground, x_bg_color.pixel);
426 } else {
427 NextArg(XtNforeground, x_bg_color.pixel);
428 NextArg(XtNbackground, x_fg_color.pixel);
429 }
430 }
431 /* no need for label because the color is obvious */
432 if (all_colors_available) {
433 NextArg(XtNlabel, "");
434 } else { /* on a monochrome system give short colornames */
435 NextArg(XtNlabel, short_clrNames[i+1]);
436 }
437 NextArg(XtNwidth, STD_COL_W);
438 } else { /* it's the default color */
439 NextArg(XtNforeground, x_bg_color.pixel);
440 NextArg(XtNbackground, x_fg_color.pixel);
441 NextArg(XtNlabel, short_clrNames[0]);
442 NextArg(XtNwidth, STD_COL_W*2+4);
443 }
444 NextArg(XtNfromVert, below);
445 NextArg(XtNfromHoriz, beside);
446 NextArg(XtNresize, False);
447 NextArg(XtNresizable, False);
448 NextArg(XtNtop, XtChainTop);
449 NextArg(XtNbottom, XtChainTop);
450 NextArg(XtNleft, XtChainLeft);
451 NextArg(XtNright, XtChainLeft);
452 beside = XtCreateManagedWidget("stdColor", commandWidgetClass,
453 stdForm, Args, ArgCount);
454 XtAddEventHandler(beside, ButtonReleaseMask, False,
455 (XtEventHandler) _set_std_color, (XtPointer) choice);
456 XtOverrideTranslations(beside,
457 XtParseTranslationTable(std_color_translations));
458 }
459
460 /********************************/
461 /* now the extended color panel */
462 /********************************/
463
464 /* make a label for the color memories */
465
466 FirstArg(XtNlabel, "User Defined Colors");
467 NextArg(XtNfromVert, stdForm);
468 NextArg(XtNfromHoriz, mixedForm[0]);
469 NextArg(XtNtop, XtChainTop);
470 NextArg(XtNbottom, XtChainTop);
471 NextArg(XtNleft, XtChainLeft);
472 NextArg(XtNright, XtChainLeft);
473 userLabel = XtCreateManagedWidget("userLabel", labelWidgetClass,
474 form, Args, ArgCount);
475
476 /* label to show count of colors actually in use */
477
478 FirstArg(XtNlabel, "x In use");
479 NextArg(XtNforeground, x_color(GREEN4));
480 NextArg(XtNfromVert, stdForm);
481 NextArg(XtNfromHoriz, userLabel);
482 NextArg(XtNhorizDistance, 25);
483 NextArg(XtNtop, XtChainTop);
484 NextArg(XtNbottom, XtChainTop);
485 NextArg(XtNleft, XtChainLeft);
486 NextArg(XtNright, XtChainRight);
487 colorCount = XtCreateManagedWidget("colorCount", labelWidgetClass,
488 form, Args, ArgCount);
489
490 /* wrap the rest (after the label) in a form for looks */
491
492 FirstArg(XtNfromVert, userLabel);
493 NextArg(XtNfromHoriz, mixedForm[0]);
494 NextArg(XtNvertDistance, 0);
495 NextArg(XtNborderWidth, 2);
496 NextArg(XtNtop, XtChainTop);
497 NextArg(XtNbottom, XtChainBottom);
498 NextArg(XtNleft, XtChainLeft);
499 NextArg(XtNright, XtChainRight);
500 userForm = XtCreateManagedWidget("userForm", formWidgetClass,
501 form, Args, ArgCount);
502
503 /* make a scrollable viewport widget to contain the color memory buttons */
504
505 FirstArg(XtNallowVert, True);
506 NextArg(XtNwidth, isw->sw_per_row*(STD_COL_W+3));
507 NextArg(XtNheight, (USR_COL_H+USR_COL_SP)*3+22); /* the 22 is for the scrollbar */
508 NextArg(XtNborderWidth, 1);
509 NextArg(XtNforceBars, True);
510 NextArg(XtNtop, XtChainTop);
511 NextArg(XtNbottom, XtChainBottom);
512 NextArg(XtNleft, XtChainLeft);
513 NextArg(XtNright, XtChainRight);
514 userViewport = XtCreateManagedWidget("userViewport", viewportWidgetClass,
515 userForm, Args, ArgCount);
516
517 FirstArg(XtNhSpace, USR_COL_SP); /* spacing between cells */
518 NextArg(XtNresizable, True);
519 NextArg(XtNborderWidth, 0);
520 NextArg(XtNorientation, XtorientVertical);
521
522 userBox = XtCreateManagedWidget("userBox", boxWidgetClass, userViewport,
523 Args, ArgCount);
524
525 /* count the number of user colors actually in use */
526 count_user_colors();
527
528 /* create the color cells */
529 for (i = 0; i < num_usr_cols; i++) {
530 if (!colorFree[i]) {
531 create_cell(i,user_colors[i]);
532 }
533 }
534
535 /* now the add/delete color buttons */
536
537 FirstArg(XtNlabel, "Add Color");
538 NextArg(XtNfromVert, userViewport);
539 NextArg(XtNtop, XtChainBottom);
540 NextArg(XtNbottom, XtChainBottom);
541 NextArg(XtNleft, XtChainLeft);
542 NextArg(XtNright, XtChainLeft);
543 addColor = XtCreateManagedWidget("addColor", commandWidgetClass,
544 userForm, Args, ArgCount);
545 XtAddEventHandler(addColor, ButtonReleaseMask, False,
546 (XtEventHandler) add_color, (XtPointer) 0);
547
548 FirstArg(XtNlabel, "Lookup and Add");
549 NextArg(XtNfromHoriz, addColor);
550 NextArg(XtNfromVert, userViewport);
551 NextArg(XtNtop, XtChainBottom);
552 NextArg(XtNbottom, XtChainBottom);
553 NextArg(XtNleft, XtChainLeft);
554 NextArg(XtNright, XtChainLeft);
555 lookupColor = XtCreateManagedWidget("lookupColor", commandWidgetClass,
556 userForm, Args, ArgCount);
557 XtAddEventHandler(lookupColor, ButtonReleaseMask, False,
558 (XtEventHandler) lookup_color, (XtPointer) 0);
559
560 /* start new row of buttons */
561
562 FirstArg(XtNlabel, "Delete");
563 NextArg(XtNfromVert, addColor);
564 NextArg(XtNtop, XtChainBottom);
565 NextArg(XtNbottom, XtChainBottom);
566 NextArg(XtNleft, XtChainLeft);
567 NextArg(XtNright, XtChainLeft);
568 delColor = XtCreateManagedWidget("deleteColor", commandWidgetClass,
569 userForm, Args, ArgCount);
570 XtAddEventHandler(delColor, ButtonReleaseMask, False,
571 (XtEventHandler) del_color, (XtPointer) 0);
572
573 FirstArg(XtNlabel, "UnDelete");
574 NextArg(XtNfromHoriz, delColor);
575 NextArg(XtNfromVert, addColor);
576 NextArg(XtNtop, XtChainBottom);
577 NextArg(XtNbottom, XtChainBottom);
578 NextArg(XtNleft, XtChainLeft);
579 NextArg(XtNright, XtChainLeft);
580 undelColor = XtCreateManagedWidget("undeleteColor", commandWidgetClass,
581 userForm, Args, ArgCount);
582 XtAddEventHandler(undelColor, ButtonReleaseMask, False,
583 (XtEventHandler) undel_color, (XtPointer) 0);
584
585 FirstArg(XtNlabel, "Delete Unused");
586 NextArg(XtNfromHoriz, undelColor);
587 NextArg(XtNfromVert, addColor);
588 NextArg(XtNtop, XtChainBottom);
589 NextArg(XtNbottom, XtChainBottom);
590 NextArg(XtNleft, XtChainLeft);
591 NextArg(XtNright, XtChainLeft);
592 delunusedColors = XtCreateManagedWidget("deleteUnused", commandWidgetClass,
593 userForm, Args, ArgCount);
594 XtAddEventHandler(delunusedColors, ButtonReleaseMask, False,
595 (XtEventHandler) del_unused_user_colors, (XtPointer) 0);
596
597 /***************************************************************************/
598 /* now the form with the rgb/hsv scrollbars just below the add/del buttons */
599 /***************************************************************************/
600
601 FirstArg(XtNfromVert, delColor);
602 NextArg(XtNdefaultDistance, SCROLL_SP);
603 NextArg(XtNtop, XtChainBottom);
604 NextArg(XtNbottom, XtChainBottom);
605 NextArg(XtNleft, XtChainLeft);
606 NextArg(XtNright, XtChainLeft);
607 mixingForm = XtCreateManagedWidget("mixingForm", formWidgetClass,
608 userForm, Args, ArgCount);
609 XtAppAddActions(XtWidgetToApplicationContext(mixingForm),
610 actionTable, XtNumber(actionTable));
611
612 FirstArg(XtNwidth, SCROLL_W);
613 NextArg(XtNheight, SCROLL_W);
614 NextArg(XtNborderWidth, 2);
615 NextArg(XtNlabel, "");
616 redLocked = XtCreateManagedWidget("redLocked", labelWidgetClass,
617 mixingForm, Args, ArgCount);
618 XtOverrideTranslations(redLocked,
619 XtParseTranslationTable(redLocked_translations));
620 FirstArg(XtNwidth, SCROLL_W);
621 NextArg(XtNheight, SCROLL_W);
622 NextArg(XtNborderWidth, 2);
623 NextArg(XtNlabel, "");
624 NextArg(XtNfromHoriz, redLocked);
625 greenLocked = XtCreateManagedWidget("greenLocked", labelWidgetClass,
626 mixingForm, Args, ArgCount);
627 XtOverrideTranslations(greenLocked,
628 XtParseTranslationTable(greenLocked_translations));
629 FirstArg(XtNwidth, SCROLL_W);
630 NextArg(XtNheight, SCROLL_W);
631 NextArg(XtNborderWidth, 2);
632 NextArg(XtNlabel, "");
633 NextArg(XtNfromHoriz, greenLocked);
634 blueLocked = XtCreateManagedWidget("blueLocked", labelWidgetClass,
635 mixingForm, Args, ArgCount);
636 XtOverrideTranslations(blueLocked,
637 XtParseTranslationTable(blueLocked_translations));
638
639
640 FirstArg(XtNlabel, "Lock");
641 NextArg(XtNheight, SCROLL_W);
642 NextArg(XtNborderWidth, 2);
643 NextArg(XtNfromHoriz, blueLocked);
644 lockedLabel = XtCreateManagedWidget("lockedLabel", labelWidgetClass,
645 mixingForm, Args, ArgCount);
646 FirstArg(XtNborderWidth, 2);
647 NextArg(XtNwidth, SCROLL_W);
648 NextArg(XtNheight, SCROLL_H);
649 NextArg(XtNthumb, None);
650 if (all_colors_available) {
651 NextArg(XtNforeground, colors[RED]);
652 NextArg(XtNborderColor, colors[RED]);
653 }
654
655 NextArg(XtNfromVert, redLocked);
656 redScroll = XtCreateManagedWidget("redScroll", scrollbarWidgetClass,
657 mixingForm, Args, ArgCount);
658 FirstArg(XtNborderWidth, 2);
659 NextArg(XtNwidth, SCROLL_W);
660 NextArg(XtNheight, SCROLL_H);
661 NextArg(XtNthumb, None);
662 if (all_colors_available) {
663 NextArg(XtNforeground, colors[GREEN]);
664 NextArg(XtNborderColor, colors[GREEN]);
665 }
666 NextArg(XtNfromHoriz, redScroll);
667 NextArg(XtNfromVert, greenLocked);
668 greenScroll = XtCreateManagedWidget("greenScroll", scrollbarWidgetClass,
669 mixingForm, Args, ArgCount);
670
671 FirstArg(XtNborderWidth, 2);
672 NextArg(XtNwidth, SCROLL_W);
673 NextArg(XtNheight, SCROLL_H);
674 NextArg(XtNthumb, None);
675 if (all_colors_available) {
676 NextArg(XtNforeground, colors[BLUE]);
677 NextArg(XtNborderColor, colors[BLUE]);
678 }
679 NextArg(XtNfromHoriz, greenScroll);
680 NextArg(XtNfromVert, blueLocked);
681 blueScroll = XtCreateManagedWidget("blueScroll", scrollbarWidgetClass,
682 mixingForm, Args, ArgCount);
683 FirstArg(XtNborderWidth, 2);
684 NextArg(XtNwidth, SCROLL_W);
685 NextArg(XtNheight, SCROLL_H);
686 NextArg(XtNthumb, None);
687 NextArg(XtNfromHoriz, blueScroll);
688 NextArg(XtNfromVert, blueLocked);
689 lockedScroll = XtCreateManagedWidget("lockedScroll",
690 scrollbarWidgetClass, mixingForm, Args, ArgCount);
691 XtSetSensitive(lockedScroll, False);
692
693 FirstArg(XtNlabel, "H");
694 NextArg(XtNwidth, SCROLL_W);
695 NextArg(XtNheight, SCROLL_W);
696 NextArg(XtNborderWidth, 2);
697 NextArg(XtNfromHoriz, lockedLabel);
698 hueLabel = XtCreateManagedWidget("hueLabel", labelWidgetClass,
699 mixingForm, Args, ArgCount);
700 FirstArg(XtNlabel, "S");
701 NextArg(XtNwidth, SCROLL_W);
702 NextArg(XtNheight, SCROLL_W);
703 NextArg(XtNborderWidth, 2);
704 NextArg(XtNfromHoriz, hueLabel);
705 satLabel = XtCreateManagedWidget("satLabel", labelWidgetClass,
706 mixingForm, Args, ArgCount);
707 FirstArg(XtNlabel, "V");
708 NextArg(XtNwidth, SCROLL_W);
709 NextArg(XtNheight, SCROLL_W);
710 NextArg(XtNborderWidth, 2);
711 NextArg(XtNfromHoriz, satLabel);
712 valLabel = XtCreateManagedWidget("valLabel", labelWidgetClass,
713 mixingForm, Args, ArgCount);
714 FirstArg(XtNborderWidth, 2);
715 NextArg(XtNwidth, SCROLL_W);
716 NextArg(XtNheight, SCROLL_H);
717 NextArg(XtNthumb, None);
718 NextArg(XtNfromHoriz, lockedLabel);
719 NextArg(XtNfromVert, hueLabel);
720 hueScroll = XtCreateManagedWidget("hueScroll", scrollbarWidgetClass,
721 mixingForm, Args, ArgCount);
722 FirstArg(XtNborderWidth, 2);
723 NextArg(XtNwidth, SCROLL_W);
724 NextArg(XtNheight, SCROLL_H);
725 NextArg(XtNthumb, None);
726 NextArg(XtNfromHoriz, hueScroll);
727 NextArg(XtNfromVert, satLabel);
728 satScroll = XtCreateManagedWidget("satScroll", scrollbarWidgetClass,
729 mixingForm, Args, ArgCount);
730 FirstArg(XtNborderWidth, 2);
731 NextArg(XtNwidth, SCROLL_W);
732 NextArg(XtNheight, SCROLL_H);
733 NextArg(XtNthumb, None);
734 NextArg(XtNfromHoriz, satScroll);
735 NextArg(XtNfromVert, valLabel);
736 valScroll = XtCreateManagedWidget("valScroll", scrollbarWidgetClass,
737 mixingForm, Args, ArgCount);
738
739 /* get background color of redLocked to restore background for locked sliders */
740 XtVaGetValues(redLocked, XtNbackground, &(original_background), NULL);
741 bars_locked = 0;
742
743 XtAddCallback(redScroll, XtNjumpProc, Thumbed, (XtPointer)S_RED);
744 XtAddCallback(greenScroll, XtNjumpProc, Thumbed, (XtPointer)S_GREEN);
745 XtAddCallback(blueScroll, XtNjumpProc, Thumbed, (XtPointer)S_BLUE);
746 XtAddCallback(lockedScroll, XtNjumpProc, Thumbed, (XtPointer)S_LOCKED);
747
748 XtAddCallback(redScroll, XtNscrollProc, Scrolled, (XtPointer)S_RED);
749 XtAddCallback(greenScroll, XtNscrollProc, Scrolled, (XtPointer)S_GREEN);
750 XtAddCallback(blueScroll, XtNscrollProc, Scrolled, (XtPointer)S_BLUE);
751 XtAddCallback(lockedScroll, XtNscrollProc, Scrolled, (XtPointer)S_LOCKED);
752 XtAddCallback(hueScroll, XtNscrollProc, Scrolled, (XtPointer)S_HUE);
753 XtAddCallback(satScroll, XtNscrollProc, Scrolled, (XtPointer)S_SAT);
754 XtAddCallback(valScroll, XtNscrollProc, Scrolled, (XtPointer)S_VAL);
755
756 XtAddCallback(hueScroll, XtNjumpProc, Update_HSV, (XtPointer)S_HUE);
757 XtAddCallback(satScroll, XtNjumpProc, Update_HSV, (XtPointer)S_SAT);
758 XtAddCallback(valScroll, XtNjumpProc, Update_HSV, (XtPointer)S_VAL);
759
760 /* initialize the two color cells to the current pen/fill colors */
761 restore_mixed_colors();
762
763 /* get the name of the scrollbar in the user color viewport so we can
764 make it solid instead of the default grey pixmap */
765 sb = XtNameToWidget(userViewport, "vertical");
766 FirstArg(XtNthumb, None);
767 SetValues(sb);
768
769 XtPopup(choice_popup, (appres.DEBUG? XtGrabNone: XtGrabExclusive));
770 XtInstallAccelerators(form, cancel);
771
772 /* if the file message window is up add it to the grab */
773 file_msg_add_grab();
774
775 (void) XSetWMProtocols(tool_d, XtWindow(choice_popup), &wm_delete_window, 1);
776 /* insure that the most recent colormap is installed */
777 set_cmap(XtWindow(choice_popup));
778
779 /* activate pen or fill depending on which button was pressed to pop us up */
780 pen_fill_activate(isw->func);
781
782 /* don't know why this is necessary, but the "Lock" label is insensitive otherwise */
783 XtSetSensitive(lockedLabel, True);
784
785 /* inactivate the delete color button until user clicks on colorcell */
786 XtSetSensitive(delColor, False);
787 /* and the undelete color button until user deletes a color */
788 XtSetSensitive(undelColor, False);
789
790 /* and the "delete unused colors" button if there are no user colors */
791 if (num_usr_cols == 0) {
792 XtSetSensitive(delunusedColors, False);
793 }
794
795 /* make sliders insensitive if the selected color (fill or pen)
796 is not a user color */
797
798 set_slider_sensitivity();
799 }
800
pen_fill_activate(int func)801 void pen_fill_activate(int func)
802 {
803 /* make sliders insensitive if the selected color (fill or pen)
804 is not a user color */
805
806 set_slider_sensitivity();
807
808 /* activate the one the user pressed (pen or fill) */
809 XawToggleSetCurrent(mixedEdit[0],(XtPointer) (intptr_t)(func==I_PEN_COLOR? 1:2));
810 }
811
restore_mixed_colors(void)812 void restore_mixed_colors(void)
813 {
814 int save0,save1,save_edit;
815
816 /* initialize the two color cells to the current pen/fill colors */
817 save0 = mixed_color[0].pixel;
818 save1 = mixed_color[1].pixel;
819
820 mixed_color[0].pixel = x_color(cur_pencolor);
821 mixed_color[1].pixel = x_color(cur_fillcolor);
822 XQueryColors(tool_d, tool_cm, mixed_color, 2);
823 /* keep lower 8 bits 0 */
824 mixed_color[0].red &= 0xff00;
825 mixed_color[0].green &= 0xff00;
826 mixed_color[0].blue &= 0xff00;
827 mixed_color[1].red &= 0xff00;
828 mixed_color[1].green &= 0xff00;
829 mixed_color[1].blue &= 0xff00;
830
831 /* put the color name or number in the indicators */
832 set_mixed_name(0, cur_pencolor);
833 set_mixed_name(1, cur_fillcolor);
834 if (!all_colors_available) {
835 if (mixedColor[0] != (Widget) 0) {
836 /* change the background of the widgets */
837 FirstArg(XtNbackground,
838 (cur_pencolor==WHITE? x_bg_color.pixel: x_fg_color.pixel));
839 SetValues(mixedColor[0]);
840 FirstArg(XtNbackground,
841 (cur_fillcolor==WHITE? x_bg_color.pixel: x_fg_color.pixel));
842 SetValues(mixedColor[1]);
843 }
844 return;
845 }
846 mixed_color[0].pixel = save0;
847 mixed_color[1].pixel = save1;
848 /* now change the background of the widgets if StaticGray, StaticColor,
849 DirectColor or TrueColor visuals */
850 set_mixed_color(0);
851 set_mixed_color(1);
852
853 /* set the scrollbars to the initial mixed colour values */
854 do_change = False;
855 CHANGE_RED(edit_fill-2);
856 CHANGE_GREEN(edit_fill-2);
857 CHANGE_BLUE(edit_fill-2);
858 do_change = True;
859
860 /* and update the hex values */
861 save_edit = edit_fill;
862 edit_fill=0;
863 update_triple();
864 edit_fill=1;
865 update_triple();
866 edit_fill = save_edit;
867 }
868
869 /*
870 For the StaticGray, StaticColor, DirectColor and TrueColor visual classes
871 change the background color of the mixed color widget specified by which
872 (0=pen, 1=fill). For the other classes, we changed the color for the
873 allocated pixel when we called YStoreColor().
874 */
875
set_mixed_color(int which)876 void set_mixed_color(int which)
877 {
878 if (!all_colors_available)
879 return;
880
881 if( tool_vclass == StaticGray ||
882 tool_vclass == StaticColor ||
883 tool_vclass == DirectColor ||
884 tool_vclass == TrueColor) {
885 XAllocColor(tool_d, tool_cm, &mixed_color[which]);
886 FirstArg(XtNbackground, mixed_color[which].pixel);
887 SetValues(mixedColor[which]);
888 } else {
889 XStoreColor(tool_d, tool_cm, &mixed_color[which]);
890 }
891 /* now make contrasting color for the label */
892 if (colorMemory[which]) {
893 pick_contrast(mixed_color[which],mixedColor[which]);
894 }
895 }
896
897 /* This is similar to set_mixed_color() except it is for the user colors */
898
set_user_color(int which)899 void set_user_color(int which)
900 {
901 if (!all_colors_available)
902 return;
903
904 if( tool_vclass == StaticGray ||
905 tool_vclass == StaticColor ||
906 tool_vclass == DirectColor ||
907 tool_vclass == TrueColor) {
908 XAllocColor(tool_d, tool_cm, &user_colors[which]);
909 /* update colors pixel value */
910 colors[which+NUM_STD_COLS] = user_colors[which].pixel;
911 if (colorMemory[which]) {
912 FirstArg(XtNbackground, user_colors[which].pixel);
913 SetValues(colorMemory[which]);
914 }
915 } else {
916 XStoreColor(tool_d, tool_cm, &user_colors[which]);
917 }
918 /* make the label in a contrasting color */
919 if (colorMemory[which]) {
920 pick_contrast(user_colors[which],colorMemory[which]);
921 }
922 }
923
pick_contrast(XColor color,Widget widget)924 void pick_contrast(XColor color, Widget widget)
925 {
926 Pixel cell_fg;
927 if ((0.30 * color.red +
928 0.59 * color.green +
929 0.11 * color.blue) < 0.5 * (255 << 8))
930 cell_fg = colors[WHITE];
931 else
932 cell_fg = colors[BLACK];
933 FirstArg(XtNforeground, cell_fg);
934 SetValues(widget);
935 }
936
937 /* change the label of the mixedColor widget[i] to the name of the color */
938 /* also set the foreground color to contrast the background */
939
set_mixed_name(int i,int col)940 void set_mixed_name(int i, int col)
941 {
942 int fore;
943 char buf[20];
944
945 if (col < NUM_STD_COLS) {
946 FirstArg(XtNlabel, colorNames[col+1].name);
947 if (col == WHITE)
948 fore = x_fg_color.pixel;
949 else
950 fore = x_bg_color.pixel;
951 } else {
952 sprintf(buf,"User %d",col);
953 FirstArg(XtNlabel, buf);
954 fore = x_bg_color.pixel;
955 }
956 /* make contrasting foreground (text) color */
957 NextArg(XtNforeground, fore);
958 SetValues(mixedColor[i]);
959 }
960
961 /* come here when cancel is pressed. This is in addition to the
962 cancel callback routine that gets called in w_indpanel.c */
963
964 static void
cancel_color_popup(Widget w,XtPointer closure,XtPointer call_data)965 cancel_color_popup(Widget w, XtPointer closure, XtPointer call_data)
966 {
967 /* restore the mixed color panels */
968 restore_mixed_colors();
969 }
970
971 /* add a color memory cell to the user colors */
972
973 static void
add_color(Widget w,XtPointer closure,XtPointer call_data)974 add_color(Widget w, XtPointer closure, XtPointer call_data)
975 {
976 /* allow user to delete unused colors */
977 XtSetSensitive(delunusedColors, True);
978 /* deselect any cell currently selected */
979 erase_boxed(current_memory);
980 /* add another widget to the user color panel */
981 if ((current_memory = add_color_cell(DONT_USE_EXISTING_COLOR, 0, 0, 0, 0)) == -1)
982 put_msg("No more user colors allowed");
983 modified[edit_fill] = True;
984 pick_memory(current_memory);
985 colorUsed[current_memory]=True;
986
987 }
988
989 /* delete a color memory (current_memory) from the user colors */
990
991 static void
del_color(Widget w,XtPointer closure,XtPointer call_data)992 del_color(Widget w, XtPointer closure, XtPointer call_data)
993 {
994 int save_mem, save_edit;
995 int i;
996 if (current_memory == -1 || num_usr_cols <= 0) {
997 beep();
998 return;
999 }
1000 /* only allow deletion of this color of no object in the figure uses it */
1001 if (color_used(current_memory+NUM_STD_COLS, &objects)) {
1002 put_msg("That color is in use by an object in the figure");
1003 beep();
1004 return;
1005 }
1006 /* get rid of the box drawn around this cell */
1007 erase_boxed(current_memory);
1008 /* save it to undelete */
1009 undel_user_color = user_colors[current_memory];
1010 del_color_cell(current_memory);
1011 /* inactivate the delete color button until user clicks on colorcell */
1012 XtSetSensitive(delColor, False);
1013 /* and activate the undelete button */
1014 XtSetSensitive(undelColor, True);
1015 /* change the current pen/fill color to default if we just deleted that color */
1016 save_mem = current_memory;
1017 save_edit = edit_fill;
1018 /* set_std_color() sets current_memory to -1 when finished (which we want) */
1019 for (i=0; i<2; i++) {
1020 if (mixed_color_indx[i] == save_mem+NUM_STD_COLS) {
1021 edit_fill = i;
1022 set_std_color(DEFAULT);
1023 }
1024 }
1025 edit_fill = save_edit;
1026 }
1027
1028 /* undelete the last user color deleted */
1029
1030 static void
undel_color(Widget w,XtPointer closure,XtPointer call_data)1031 undel_color(Widget w, XtPointer closure, XtPointer call_data)
1032 {
1033 int indx;
1034
1035 XtSetSensitive(undelColor, False);
1036 if ((indx=add_color_cell(DONT_USE_EXISTING_COLOR, 0, undel_user_color.red/256,
1037 undel_user_color.green/256,
1038 undel_user_color.blue/256)) == -1) {
1039 put_msg("Can't allocate more than %d user colors, not enough colormap entries",
1040 num_usr_cols);
1041 return;
1042 }
1043 colorUsed[indx] = True;
1044 }
1045
1046 /* count the number of unique user colors actually used by Fig objects */
1047 /* this is called when the user pops up the color panel */
1048
1049 void
count_user_colors(void)1050 count_user_colors(void)
1051 {
1052 F_compound *c;
1053 int i, count;
1054 char buf[20];
1055
1056 /* keep array of counts of each color */
1057 for (i=0; i<num_usr_cols; i++)
1058 colors_used[i] = 0;
1059
1060 /* count colors in main list */
1061 c_user_colors(&objects);
1062
1063 /* now any "next" compounds off the top of the list */
1064 for (c = objects.next; c != NULL; c = c->next) {
1065 c_user_colors(c);
1066 }
1067 /* now add up the colors that are used */
1068 count = 0;
1069 for (i=0; i<num_usr_cols; i++)
1070 if (colors_used[i])
1071 count++;
1072 sprintf(buf,"%3d In use",count);
1073 FirstArg(XtNlabel, buf);
1074 SetValues(colorCount);
1075 }
1076
c_user_colors(F_compound * obj)1077 void c_user_colors(F_compound *obj)
1078 {
1079 F_arc *a;
1080 F_ellipse *e;
1081 F_line *l;
1082 F_spline *s;
1083 F_text *t;
1084 F_compound *c;
1085
1086 /* traverse the compounds in this compound */
1087 for (c = obj->compounds; c != NULL; c = c->next) {
1088 c_user_colors(c);
1089 }
1090 /* now the other objects */
1091 for (a = obj->arcs; a != NULL; a = a->next) {
1092 count_one(a->pen_color);
1093 count_one(a->fill_color);
1094 }
1095 for (e = obj->ellipses; e != NULL; e = e->next) {
1096 count_one(e->pen_color);
1097 count_one(e->fill_color);
1098 }
1099 for (l = obj->lines; l != NULL; l = l->next) {
1100 count_one(l->pen_color);
1101 count_one(l->fill_color);
1102 }
1103 for (s = obj->splines; s != NULL; s = s->next) {
1104 count_one(s->pen_color);
1105 count_one(s->fill_color);
1106 }
1107 for (t = obj->texts; t != NULL; t = t->next) {
1108 count_one(t->color);
1109 }
1110 }
1111
count_one(int color)1112 void count_one(int color)
1113 {
1114 if (color >= NUM_STD_COLS)
1115 colors_used[color-NUM_STD_COLS] = 1;
1116 }
1117
1118 /* delete unused user colors */
1119
1120 static void
del_unused_user_colors(void)1121 del_unused_user_colors(void)
1122 {
1123 int i, save_mem;
1124 Boolean deleted = False;
1125
1126 save_mem = -1;
1127 /* first unmanage the Box that the color cells are in */
1128 XtUnmanageChild(userBox);
1129 for (i=0; i<num_usr_cols; i++)
1130 if (colors_used[i] == 0 && !colorFree[i]) {
1131 deleted = True;
1132 /* save it to undelete */
1133 undel_user_color = user_colors[i];
1134 del_color_cell(i);
1135 /* if user deletes selected cell */
1136 if (i==current_memory) {
1137 save_mem = current_memory;
1138 current_memory = -1;
1139 }
1140 }
1141 /* remanage the Box */
1142 XtManageChild(userBox);
1143
1144 /* activate the undelete button if any were deleted */
1145 if (deleted)
1146 XtSetSensitive(undelColor, True);
1147
1148 /* if we deleted the selected cell, but another one exists, select it */
1149 if (save_mem >= 0) {
1150 for (i=0; i<num_usr_cols; i++) {
1151 if (!colorFree[i]) {
1152 current_memory = i;
1153 pick_memory(i);
1154 break;
1155 }
1156 }
1157 /* if we didn't find any other user colors, select DEFAULT */
1158 if (i>=num_usr_cols)
1159 set_std_color(DEFAULT);
1160 } else {
1161 /* make sliders insensitive if we deleted the selected color */
1162 set_slider_sensitivity();
1163 }
1164 }
1165
1166 /* lookup color from another window - the user clicks the mouse
1167 on a color and a new cell is created with that color */
1168
1169 static void
lookup_color(Widget w,XtPointer closure,XtPointer call_data)1170 lookup_color(Widget w, XtPointer closure, XtPointer call_data)
1171 {
1172 Colormap cmap;
1173 Pixel p;
1174 XColor xcol;
1175
1176 /* grab the server to get a pixel from a window */
1177 DoGrabPixel(w, &p, &cmap);
1178 /* get its rgb values */
1179 xcol.pixel = p;
1180 xcol.flags = DoRed | DoGreen | DoBlue;
1181 XQueryColor(tool_d, cmap, &xcol);
1182
1183 /* make a new cell and set current_memory to that */
1184 add_color(w, closure, call_data);
1185
1186 /* and store the chosen color (keep lower 8 bits 0) */
1187 user_colors[current_memory].red = xcol.red & 0xff00;
1188 user_colors[current_memory].green = xcol.green & 0xff00;
1189 user_colors[current_memory].blue = xcol.blue & 0xff00;
1190 user_colors[current_memory].flags = DoRed|DoGreen|DoBlue;
1191 set_user_color(current_memory);
1192 pick_memory(current_memory);
1193 }
1194
1195 /* add a widget to the user color list with color r,g,b */
1196 /* call with use_exist true if you wish to allocate cell <indx> explicitly */
1197 /* also increment num_usr_cols if we add a colorcell beyond the current number */
1198 /* return the colorcell number (0..MAX_USR_COLS-1) */
1199 /* return -1 if MAX_USR_COLS already used */
1200
1201 int
add_color_cell(Boolean use_exist,int indx,int r,int g,int b)1202 add_color_cell(Boolean use_exist, int indx, int r, int g, int b)
1203 {
1204 int i;
1205 Boolean new;
1206
1207 if (all_colors_available) {
1208 /* try to get a colorcell */
1209 if (!alloc_color_cells(pixels,1)) {
1210 put_msg("Can't allocate user color, not enough colorcells");
1211 return -1;
1212 }
1213 }
1214 if (!use_exist) {
1215 /* first look for color cell available in the middle */
1216 new = False;
1217 for (i=0; i<num_usr_cols; i++)
1218 if (colorFree[i])
1219 break;
1220 indx = i;
1221 }
1222
1223 /* if a space is free but there was never a color there, must create one */
1224 if (indx < num_usr_cols && colorMemory[indx]==0)
1225 new = True;
1226
1227 /* if not, increment num_usr_cols */
1228 if (indx >= num_usr_cols) {
1229 if (num_usr_cols >= MAX_USR_COLS)
1230 return -1;
1231 if (use_exist)
1232 num_usr_cols = indx+1;
1233 else
1234 num_usr_cols++;
1235 new = True;
1236 }
1237
1238 user_colors[indx].red = r*256;
1239 user_colors[indx].green = g*256;
1240 user_colors[indx].blue = b*256;
1241 user_colors[indx].flags = DoRed|DoGreen|DoBlue;
1242 user_colors[indx].pixel = pixels[0];
1243 /* in case we have read-only colormap, get the pixel value now */
1244 if (all_colors_available)
1245 YStoreColor(tool_cm,&user_colors[indx]);
1246 /* and put it in main colors */
1247 colors[NUM_STD_COLS+indx] = user_colors[indx].pixel;
1248
1249 colorFree[indx] = False;
1250 colorUsed[indx] = False;
1251
1252
1253 /* if the color popup has been created create the widgets */
1254 if (pen_color_button->panel) {
1255 if (new) {
1256 /* if new color is at the end of the list, just create it now */
1257 if (indx == num_usr_cols-1) {
1258 create_cell(indx, user_colors[indx]);
1259 } else {
1260 /* otherwise, delete all after it and recreate them */
1261 /* first unmanage the Box that they're in */
1262 XtUnmanageChild(userBox);
1263 for (i=indx+1; i<num_usr_cols; i++)
1264 if (!colorFree[i])
1265 XtDestroyWidget(colorMemory[i]);
1266 /* now add the new and the old ones back in */
1267 for (i=indx; i<num_usr_cols; i++)
1268 if (!colorFree[i])
1269 create_cell(i, user_colors[indx]);
1270 /* remanage the Box */
1271 XtManageChild(userBox);
1272 }
1273 } else {
1274 /* already exists, just set its color and map it */
1275 FirstArg(XtNforeground, x_bg_color.pixel);
1276 NextArg(XtNbackground, (all_colors_available?
1277 user_colors[indx].pixel: x_fg_color.pixel));
1278 SetValues(colorMemory[indx]);
1279 XtManageChild(colorMemory[indx]);
1280 }
1281 }
1282 /* now set the color of the widget if TrueColor, etc. */
1283 set_user_color(indx);
1284
1285 return indx;
1286 }
1287
1288 /* Create a color cell [indx] with background "color" */
1289 /* Color its border green if it is in use or black otherwise. */
1290 /* NOTE: If we are being called from swap_colors(), the colors_used[]
1291 array is probably not correct, but the color_borders() proc
1292 is called after this anyway. */
1293
create_cell(int indx,XColor color)1294 void create_cell(int indx, XColor color)
1295 {
1296 char labl[5];
1297
1298 /* put the user color number in all the time */
1299 sprintf(labl,"%d", indx+NUM_STD_COLS);
1300 colorMemory[indx] = XtVaCreateManagedWidget("colorMemory",
1301 labelWidgetClass, userBox,
1302 XtNlabel, labl,
1303 XtNforeground, x_bg_color.pixel,
1304 XtNbackground, (all_colors_available?
1305 user_colors[indx].pixel: x_fg_color.pixel),
1306 XtNwidth, USR_COL_W, XtNheight, USR_COL_H,
1307 XtNborder, (colors_used[indx]? x_color(GREEN):x_color(BLACK)),
1308 XtNborderWidth, 2,
1309 NULL);
1310 XtOverrideTranslations(colorMemory[indx],
1311 XtParseTranslationTable(user_color_translations));
1312 /* pick contrasting color for label */
1313 pick_contrast(user_colors[indx],colorMemory[indx]);
1314 }
1315
1316 /*
1317 allocate n colormap entries. If not enough cells are available, switch
1318 to a private colormap. If we are already using a private colormap return
1319 False. The pixel numbers allocated are returned in the Pixel array pixels[]
1320 The new colormap (if used) is set into the main (tool) window and the color
1321 popup panel (if it exists)
1322 */
1323
1324 Boolean
alloc_color_cells(Pixel * pixels,int n)1325 alloc_color_cells(Pixel *pixels, int n)
1326 {
1327 int i;
1328
1329 /* allocate them one at a time in case we can't allocate all of them.
1330 If that is the case then we switch colormaps and allocate the rest */
1331 for (i=0; i<n; i++) {
1332 switch( tool_vclass ){
1333 /*
1334 * Use XAllocColorCells "to allocate read/write color cells and color plane
1335 * combinations for GrayScale and PseudoColor models"
1336 */
1337 case GrayScale:
1338 case PseudoColor:
1339 if (!XAllocColorCells(tool_d, tool_cm, 0, &plane_masks, 0, &pixels[i], 1)) {
1340 /* try again with new colormap */
1341 if (!switch_colormap() ||
1342 (!XAllocColorCells(tool_d, tool_cm, 0, &plane_masks, 0, &pixels[i], 1))) {
1343 put_msg("Cannot define user colors.");
1344 return False;
1345 }
1346 }
1347 break;
1348 /*
1349 * Do not attempt to allocate color resources for static visuals
1350 * (but assume the colors can be achieved).
1351 */
1352 case StaticGray:
1353 case StaticColor:
1354 case DirectColor:
1355 case TrueColor:
1356 break;
1357
1358 default:
1359 put_msg("Cannot define user colors in the Unknown Visual.");
1360 return False;
1361 }
1362 }
1363 return True;
1364 }
1365
1366 /* switch colormaps to private one and reallocate the colors we already used. */
1367 /* Return False if already switched or if can't allocate new colormap */
1368
1369 Boolean
switch_colormap(void)1370 switch_colormap(void)
1371 {
1372 if (swapped_cmap || appres.dontswitchcmap) {
1373 return False;
1374 }
1375 if ((newcmap = XCopyColormapAndFree(tool_d, tool_cm)) == 0) {
1376 file_msg("Cannot allocate new colormap.");
1377 return False;
1378 }
1379 /* swap colormaps */
1380 tool_cm = newcmap;
1381 swapped_cmap = True;
1382 /* and tell the window manager to install it */
1383 if (pen_color_button && pen_color_button->panel &&
1384 XtWindow(pen_color_button->panel) != 0)
1385 set_cmap(XtWindow(pen_color_button->panel));
1386 if (tool_w)
1387 set_cmap(tool_w);
1388 file_msg("Switching to private colormap.");
1389 return True;
1390 }
1391
1392
1393 /* delete a color memory cell (indx) from the widgets and arrays */
1394
del_color_cell(int indx)1395 void del_color_cell(int indx)
1396 {
1397 unsigned long pixels[MAX_USR_COLS];
1398
1399 /* if already free, just return */
1400 if (colorFree[indx])
1401 return;
1402 /* if the color popup has been created unmanage the widget */
1403 if (pen_color_button->panel)
1404 XtUnmanageChild(colorMemory[indx]);
1405
1406 /* free up this colormap entry */
1407 pixels[0] = user_colors[indx].pixel;
1408 if (all_colors_available)
1409 XFreeColors(tool_d, tool_cm, pixels, 1, 0);
1410
1411 /* now set free flag for that cell */
1412 colorFree[indx] = True;
1413 colorUsed[indx] = False;
1414 }
1415
1416 /* if any object in the figure uses the user color "color" return True */
1417
1418 static Boolean
color_used(int color,F_compound * list)1419 color_used(int color, F_compound *list)
1420 {
1421 F_arc *a;
1422 F_text *t;
1423 F_compound *c;
1424 F_ellipse *e;
1425 F_line *l;
1426 F_spline *s;
1427
1428 for (a = list->arcs; a != NULL; a = a->next)
1429 if (a->fill_color == color || a->pen_color == color)
1430 return True;
1431 for (t = list->texts; t != NULL; t = t->next)
1432 if (t->color == color)
1433 return True;
1434 for (c = list->compounds; c != NULL; c = c->next)
1435 if (color_used(color,c))
1436 return True;
1437 for (e = list->ellipses; e != NULL; e = e->next)
1438 if (e->fill_color == color || e->pen_color == color)
1439 return True;
1440 for (l = list->lines; l != NULL; l = l->next)
1441 if (l->fill_color == color || l->pen_color == color)
1442 return True;
1443 for (s = list->splines; s != NULL; s = s->next)
1444 if (s->fill_color == color || s->pen_color == color)
1445 return True;
1446 return False;
1447 }
1448
1449 /* come here when either the edit pen or edit fill button is pressed */
1450 static void
switch_edit(Widget w,XtPointer client_data,XtPointer call_data)1451 switch_edit(Widget w, XtPointer client_data, XtPointer call_data)
1452 {
1453 edit_fill = (intptr_t) XawToggleGetCurrent(mixedEdit[0]) - 1;
1454 /* sometimes XawToggleGetCurrent() returns 0 if the
1455 toggle hasn't been set manually */
1456 if (edit_fill == -1)
1457 edit_fill = 1;
1458 /* only make triple value sensitive if a user color */
1459 if (mixed_color_indx[edit_fill] >= NUM_STD_COLS) {
1460 XtSetSensitive(tripleValue[edit_fill], True);
1461 XtSetSensitive(tripleValue[1-edit_fill], False);
1462 } else {
1463 XtSetSensitive(tripleValue[edit_fill], False);
1464 XtSetSensitive(tripleValue[1-edit_fill], False);
1465 }
1466
1467 /* set the scrollbars to the current mixed colour values */
1468 do_change = False;
1469 CHANGE_RED(edit_fill-2);
1470 CHANGE_GREEN(edit_fill-2);
1471 CHANGE_BLUE(edit_fill-2);
1472 do_change = True;
1473
1474 /* but make them insensitive if the color is not a user defined color */
1475 set_slider_sensitivity();
1476 }
1477
1478 /* if the color for the current mode (fill or pen) is a user-defined color then
1479 make the color sliders sensitive, otherwise make them insensitive */
1480
set_slider_sensitivity(void)1481 void set_slider_sensitivity(void)
1482 {
1483 if (mixed_color_indx[edit_fill] < NUM_STD_COLS)
1484 XtSetSensitive(mixingForm, False);
1485 else
1486 XtSetSensitive(mixingForm, True);
1487 }
1488
1489 /* ok button */
1490
1491 static void
set_color_ok(Widget w,char * dum,XButtonEvent * ev,Boolean disp)1492 set_color_ok(Widget w, char *dum, XButtonEvent *ev, Boolean disp)
1493 {
1494 int i,indx;
1495
1496 /* put the color pixel value in the table */
1497 /* this is done here because if the visual is TrueColor, etc. the value of
1498 the pixel changes with the color itself */
1499 for (i=0; i<=1; i++) {
1500 indx = mixed_color_indx[i];
1501 if (indx >= NUM_STD_COLS)
1502 colors[indx] = user_colors[indx-NUM_STD_COLS].pixel;
1503 }
1504
1505 /* have either the fill or pen color been modified? */
1506
1507 if (modified[0]) {
1508 cur_pencolor = mixed_color_indx[0];
1509 show_pencolor(); /* update the button in the indicator panel */
1510 }
1511 if (modified[1]) {
1512 cur_fillcolor = mixed_color_indx[1];
1513 show_fillcolor(); /* update the button in the indicator panel */
1514 }
1515 modified[0] = modified[1] = False;
1516 choice_panel_dismiss();
1517 }
1518
1519 /* set standard color in mixedColor */
1520
1521 static void
_set_std_color(Widget w,choice_info * sel_choice,XButtonEvent * ev)1522 _set_std_color(Widget w, choice_info *sel_choice, XButtonEvent *ev)
1523 {
1524 set_std_color(sel_choice->value);
1525 }
1526
1527 static void
set_std_color(int color)1528 set_std_color(int color)
1529 {
1530 Pixel save;
1531
1532 /* make sliders insensitive */
1533 XtSetSensitive(mixingForm, False);
1534
1535 /* set flag saying we've modified either the pen or fill color */
1536 modified[edit_fill] = True;
1537
1538 mixed_color_indx[edit_fill] = color;
1539
1540 save = mixed_color[edit_fill].pixel;
1541 mixed_color[edit_fill].pixel = x_color(mixed_color_indx[edit_fill]);
1542 /* put the colorname in the indicator */
1543 set_mixed_name(edit_fill,color);
1544 /* look up color rgb values given the pixel number */
1545 if (all_colors_available) {
1546 XQueryColor(tool_d, tool_cm, &mixed_color[edit_fill]);
1547 /* keep lower 8 bits 0 */
1548 mixed_color[edit_fill].red &= 0xff00;
1549 mixed_color[edit_fill].green &= 0xff00;
1550 mixed_color[edit_fill].blue &= 0xff00;
1551 } else {
1552 /* look up color rgb values from the name */
1553 if (color == DEFAULT) {
1554 mixed_color[edit_fill].red = x_bg_color.red;
1555 mixed_color[edit_fill].green = x_bg_color.green;
1556 mixed_color[edit_fill].blue = x_bg_color.blue;
1557 } else {
1558 XParseColor(tool_d, tool_cm,
1559 colorNames[color+1].rgb, &mixed_color[edit_fill]);
1560 }
1561 /* now change the background of the widget */
1562 if (color == WHITE)
1563 FirstArg(XtNbackground, x_bg_color.pixel);
1564 else
1565 FirstArg(XtNbackground, x_fg_color.pixel);
1566 SetValues(mixedColor[edit_fill]);
1567 }
1568 mixed_color[edit_fill].pixel = save;
1569
1570 /* get the rgb values for that color */
1571 rgb_values[edit_fill].r = mixed_color[edit_fill].red;
1572 rgb_values[edit_fill].g = mixed_color[edit_fill].green;
1573 rgb_values[edit_fill].b = mixed_color[edit_fill].blue;
1574 set_mixed_color(edit_fill);
1575
1576 /* undraw any box around the current user-memory cell */
1577 erase_boxed(current_memory);
1578 /* update the mixedColor stuff and scrollbars */
1579 XawScrollbarSetThumb(redScroll,
1580 (float)(1.0 - rgb_values[edit_fill].r/65536.0), THUMB_H);
1581 XawScrollbarSetThumb(greenScroll,
1582 (float)(1.0 - rgb_values[edit_fill].g/65536.0), THUMB_H);
1583 XawScrollbarSetThumb(blueScroll,
1584 (float)(1.0 - rgb_values[edit_fill].b/65536.0), THUMB_H);
1585 update_triple();
1586 /* inactivate the current_memory cell */
1587 current_memory = -1;
1588 /* and the hexadecimal window */
1589 XtSetSensitive(tripleValue[edit_fill], False);
1590 /* and the delete color button until user clicks on colorcell */
1591 XtSetSensitive(delColor, False);
1592 }
1593
1594 /* make a user color cell active */
1595
1596 static void
_pick_memory(Widget w,XEvent * event,String * params,Cardinal * num_params)1597 _pick_memory(Widget w, XEvent *event, String *params, Cardinal *num_params)
1598 {
1599 int i;
1600
1601 for (i = 0; i < num_usr_cols; i++)
1602 if (w == colorMemory[i]) {
1603 pick_memory(i);
1604 break;
1605 }
1606 }
1607
1608 static void
pick_memory(int which)1609 pick_memory(int which)
1610 {
1611 /* make sliders sensitive */
1612 XtSetSensitive(mixingForm, True);
1613
1614 modified[edit_fill] = True;
1615 /* erase box around old memory cell */
1616 erase_boxed(current_memory);
1617 /* new memory cell */
1618 current_memory = which;
1619 draw_boxed(current_memory);
1620
1621 /* put the color number in the mixed index */
1622 mixed_color_indx[edit_fill] = current_memory+NUM_STD_COLS;
1623 /* put the color name in the indicator */
1624 set_mixed_name(edit_fill,mixed_color_indx[edit_fill]);
1625
1626 if (!colorFree[current_memory]) {
1627 do_change = False;
1628 CHANGE_RED(current_memory);
1629 CHANGE_GREEN(current_memory);
1630 CHANGE_BLUE(current_memory);
1631 do_change = True;
1632 set_mixed_color(edit_fill);
1633 update_scrl_triple((Widget)NULL, (XEvent *)NULL,
1634 (String *)NULL, (Cardinal *)NULL);
1635 } else {
1636 user_colors[current_memory].red =
1637 mixed_color[edit_fill].red;
1638 user_colors[current_memory].green =
1639 mixed_color[edit_fill].green;
1640 user_colors[current_memory].blue =
1641 mixed_color[edit_fill].blue;
1642 set_user_color(current_memory);
1643 }
1644 /* activate the delete color button */
1645 XtSetSensitive(delColor, True);
1646 /* and the hexadecimal window */
1647 XtSetSensitive(tripleValue[edit_fill], True);
1648
1649 /* now set the background of the widget to black if in monochrome */
1650 if (!all_colors_available) {
1651 FirstArg(XtNbackground, x_fg_color.pixel);
1652 SetValues(mixedColor[edit_fill]);
1653 }
1654 }
1655
1656 static void
lock_toggle(Widget w,XEvent * event,String * params,Cardinal * num_params)1657 lock_toggle(Widget w, XEvent *event, String *params, Cardinal *num_params)
1658 {
1659 Arg args[1];
1660 int button = WhichButton(params[0]);
1661
1662 args[0].name = XtNbackground;
1663 if (button & bars_locked) {
1664 args[0].value = original_background;
1665 bars_locked -= button;
1666 if (!bars_locked)
1667 XtSetSensitive(lockedScroll, False);
1668 } else {
1669 if (!all_colors_available)
1670 args[0].value = x_fg_color.pixel;
1671 else {
1672 switch (button) {
1673 case S_RED:
1674 args[0].value = colors[RED];
1675 break;
1676 case S_GREEN:
1677 args[0].value = colors[GREEN];
1678 break;
1679 case S_BLUE:
1680 args[0].value = colors[BLUE];
1681 break;
1682 default:
1683 return;
1684 /* NOT REACHED */
1685 }
1686 }
1687 bars_locked += button;
1688 XtSetSensitive(lockedScroll, True);
1689 }
1690 move_lock();
1691 XtSetValues(w, (ArgList) args, 1);
1692 }
1693
1694 /* change the border for a color button to red and set thickness = 2 */
1695
1696 static void
draw_boxed(int which)1697 draw_boxed(int which)
1698 {
1699 if (which < 0)
1700 return;
1701 FirstArg(XtNborder, x_color(RED));
1702 SetValues(colorMemory[which]);
1703 }
1704
1705 /* change the border for a color button to black if unused or green if used,
1706 and set thickness = 1 */
1707
1708 static void
erase_boxed(int which)1709 erase_boxed(int which)
1710 {
1711 if (which < 0)
1712 return;
1713 if (colors_used[which]) {
1714 FirstArg(XtNborder, x_color(GREEN));
1715 } else {
1716 FirstArg(XtNborder, x_color(BLACK));
1717 }
1718 SetValues(colorMemory[which]);
1719 }
1720
1721 /* color their borders green if in use, black if not */
1722
color_borders(void)1723 void color_borders(void)
1724 {
1725 int i;
1726
1727 for (i = 0; i < num_usr_cols; i++) {
1728 if (colorMemory[i])
1729 erase_boxed(i);
1730 }
1731 }
1732
1733 static int
WhichButton(String name)1734 WhichButton(String name)
1735 {
1736 if (strcmp(name, "red") == 0)
1737 return S_RED;
1738 if (strcmp(name, "blue") == 0)
1739 return S_BLUE;
1740 if (strcmp(name, "green") == 0)
1741 return S_GREEN;
1742 return 0;
1743 }
1744
1745
1746 static void
update_from_triple(Widget w,XEvent * event,String * params,Cardinal * num_params)1747 update_from_triple(Widget w, XEvent *event, String *params, Cardinal *num_params)
1748 {
1749 char *hexvalue, tmphex[10];
1750 int red,green,blue;
1751
1752 /* get the users hex value from the widget */
1753 FirstArg(XtNstring, &hexvalue);
1754 GetValues(tripleValue[edit_fill]);
1755 if (*hexvalue != '#') { /* fix it up if user removed the "#" */
1756 strcpy(tmphex,"#");
1757 strcat(tmphex,hexvalue);
1758 hexvalue = tmphex;
1759 }
1760 if ((strlen(hexvalue) != 7) ||
1761 (sscanf(hexvalue,"#%02x%02x%02x",&red,&green,&blue) != 3)) {
1762 beep();
1763 put_msg("Bad hex value");
1764 return;
1765 }
1766 mixed_color[edit_fill].red = red*256;
1767 mixed_color[edit_fill].green = green*256;
1768 mixed_color[edit_fill].blue = blue*256;
1769
1770 /* and update hsv and rgb scrollbars etc from the new hex value */
1771 update_scrl_triple(w,event,params,num_params);
1772
1773 do_change = False;
1774 pass_value = 1.0 - rgb_values[edit_fill].r/65536.0;
1775 Thumbed(redScroll, (XtPointer)S_RED, (XtPointer)(&pass_value));
1776 pass_value = 1.0 - rgb_values[edit_fill].g/65536.0;
1777 Thumbed(greenScroll, (XtPointer)S_GREEN, (XtPointer)(&pass_value));
1778 do_change = True;
1779 pass_value = 1.0 - rgb_values[edit_fill].b/65536.0;
1780 Thumbed(blueScroll, (XtPointer)S_BLUE, (XtPointer)(&pass_value));
1781 }
1782
1783 /* front-end to update_triple called by scrolling in the scrollbars.
1784 call update_triple only if current_memory is not -1 (user color IS selected) */
1785
1786 static void
update_scrl_triple(Widget w,XEvent * event,String * params,Cardinal * num_params)1787 update_scrl_triple(Widget w, XEvent *event, String *params, Cardinal *num_params)
1788 {
1789 if (current_memory >= 0)
1790 update_triple();
1791 }
1792
1793 static void
update_triple(void)1794 update_triple(void)
1795 {
1796 char hexvalue[10];
1797
1798 (void) sprintf(hexvalue, "#%02x%02x%02x",
1799 COLOR(edit_fill-2,red),
1800 COLOR(edit_fill-2,green),
1801 COLOR(edit_fill-2,blue));
1802 FirstArg(XtNstring, hexvalue);
1803 NextArg(XtNinsertPosition, 7/*strlen(hexvalue)*/);
1804 SetValues(tripleValue[edit_fill]);
1805
1806 rgb_values[edit_fill].r = mixed_color[edit_fill].red;
1807 rgb_values[edit_fill].g = mixed_color[edit_fill].green;
1808 rgb_values[edit_fill].b = mixed_color[edit_fill].blue;
1809
1810 if (!moving_hsv) {
1811 hsv_values = RGBToHSV(rgb_values[edit_fill]);
1812
1813 XawScrollbarSetThumb(hueScroll, (float)(1.0 - hsv_values.h), THUMB_H);
1814 XawScrollbarSetThumb(satScroll, (float)(1.0 - hsv_values.s), THUMB_H);
1815 XawScrollbarSetThumb(valScroll, (float)(1.0 - hsv_values.v), THUMB_H);
1816 }
1817 }
1818
1819 static void
move_scroll(Widget w,XEvent * event,String * params,Cardinal * num_params)1820 move_scroll(Widget w, XEvent *event, String *params, Cardinal *num_params)
1821 {
1822 #define ADJUST_CHANGE(color) if (change < 0) { \
1823 if (color + change < 0) \
1824 change = -color; \
1825 } else { \
1826 if (color + change > 255) \
1827 change = 255-color; \
1828 }
1829
1830 int change;
1831 float pass_value;
1832 int red_pos = 0;
1833 int green_pos = 0;
1834 int blue_pos = 0;
1835
1836 if (buttons_down == 0)
1837 return;
1838
1839 change = last_pos - event->xmotion.y;
1840 last_pos = event->xmotion.y;
1841
1842 if (buttons_down & S_RED) {
1843 red_pos = mixed_color[edit_fill].red/256;
1844 ADJUST_CHANGE(red_pos);
1845 }
1846
1847 if (buttons_down & S_GREEN) {
1848 green_pos = mixed_color[edit_fill].green/256;
1849 ADJUST_CHANGE(green_pos);
1850 }
1851
1852 if (buttons_down & S_BLUE) {
1853 blue_pos = mixed_color[edit_fill].blue/256;
1854 ADJUST_CHANGE(blue_pos);
1855 }
1856
1857 red_pos += change;
1858 green_pos += change;
1859 blue_pos += change;
1860
1861 /* update the new scroll bar positions and change the color */
1862 do_change = False;
1863
1864 if (buttons_down & S_RED) {
1865 pass_value = 1.0 - (float) red_pos/255;
1866 Thumbed(redScroll, (XtPointer)S_RED, (XtPointer)(&pass_value));
1867 }
1868
1869 if (buttons_down & S_GREEN) {
1870 pass_value = 1.0 - (float) green_pos/255;
1871 Thumbed(greenScroll, (XtPointer)S_GREEN, (XtPointer)(&pass_value));
1872 }
1873
1874 if (buttons_down & S_BLUE) {
1875 pass_value = 1.0 - (float) blue_pos/255;
1876 Thumbed(blueScroll, (XtPointer)S_BLUE, (XtPointer)(&pass_value));
1877 }
1878
1879 do_change = True;
1880 if (current_memory >= 0) {
1881 StoreMix_and_Mem();
1882 if (!colorUsed[current_memory])
1883 colorUsed[current_memory] = True;
1884 }
1885 update_scrl_triple((Widget)NULL, (XEvent *)NULL,
1886 (String *)NULL, (Cardinal *)NULL);
1887 }
1888
StoreMix_and_Mem(void)1889 void StoreMix_and_Mem(void)
1890 {
1891 set_mixed_color(edit_fill);
1892 set_mixed_color(edit_fill);
1893 user_colors[current_memory].red = mixed_color[edit_fill].red;
1894 user_colors[current_memory].green = mixed_color[edit_fill].green;
1895 user_colors[current_memory].blue = mixed_color[edit_fill].blue;
1896 set_user_color(current_memory);
1897 }
1898
1899 static void
Scrolled(Widget w,XtPointer closure,XtPointer call_data)1900 Scrolled(Widget w, XtPointer closure, XtPointer call_data)
1901 {
1902 Boolean going_up = (intptr_t) call_data < 0;
1903 intptr_t which = (intptr_t) closure;
1904 int pos = 0;
1905 float blip = 1.0/256.0;
1906
1907 switch (which) {
1908 case S_RED:
1909 pos = COLOR(edit_fill-2,red);
1910 break;
1911 case S_BLUE:
1912 pos = COLOR(edit_fill-2,blue);
1913 break;
1914 case S_GREEN:
1915 pos = COLOR(edit_fill-2,green);
1916 break;
1917 case S_LOCKED:
1918 pos = 255 - (int)(locked_top * 255 + 0.5);
1919 break;
1920 case S_HUE:
1921 hsv_values.h += (going_up? blip: -blip);
1922 ThumbHSV(w, 1.0-hsv_values.h);
1923 return;
1924 case S_SAT:
1925 hsv_values.s += (going_up? blip: -blip);
1926 ThumbHSV(w, 1.0-hsv_values.s);
1927 return;
1928 case S_VAL:
1929 hsv_values.v += (going_up? blip: -blip);
1930 ThumbHSV(w, 1.0-hsv_values.v);
1931 return;
1932 default:
1933 fprintf(stderr, "Oops Scroll calldata invalid\n");
1934 exit(1);
1935 }
1936
1937 if (!going_up) {
1938 if (pos > 0)
1939 pos--;
1940 } else {
1941 if (pos < 255)
1942 pos++;
1943 }
1944
1945 pass_value = 1.0 - (float) pos/255.0;
1946 Thumbed(w, closure, (XtPointer)(&pass_value));
1947 }
1948
1949
1950
1951 static void
Update_HSV(Widget w,XtPointer closure,XtPointer call_data)1952 Update_HSV(Widget w, XtPointer closure, XtPointer call_data)
1953 {
1954 intptr_t which = (intptr_t) closure;
1955 float top = *(float*) call_data;
1956
1957 switch (which) {
1958 case S_HUE:
1959 hsv_values.h = 1.0-top;
1960 break;
1961 case S_SAT:
1962 hsv_values.s = 1.0-top;
1963 break;
1964 case S_VAL:
1965 hsv_values.v = 1.0-top;
1966 break;
1967 }
1968
1969 ThumbHSV(w, top);
1970 }
1971
ThumbHSV(Widget w,float top)1972 void ThumbHSV(Widget w, float top)
1973 {
1974 moving_hsv = True;
1975
1976 rgb_values[edit_fill] = HSVToRGB(hsv_values);
1977 XawScrollbarSetThumb(w, top, THUMB_H);
1978
1979 /* don't update the scrollbars yet */
1980 do_change = False;
1981 pass_value = 1.0 - rgb_values[edit_fill].r/65536.0;
1982 Thumbed(redScroll, (XtPointer)S_RED, (XtPointer)(&pass_value));
1983 pass_value = 1.0 - rgb_values[edit_fill].g/65536.0;
1984 Thumbed(greenScroll, (XtPointer)S_GREEN, (XtPointer)(&pass_value));
1985 /* now update the scrollbars */
1986 do_change = True;
1987 pass_value = 1.0 - rgb_values[edit_fill].b/65536.0;
1988 Thumbed(blueScroll, (XtPointer)S_BLUE, (XtPointer)(&pass_value));
1989
1990 moving_hsv = False;
1991 }
1992
1993
1994 static void
Thumbed(Widget w,XtPointer closure,XtPointer call_data)1995 Thumbed(Widget w, XtPointer closure, XtPointer call_data)
1996 {
1997 intptr_t which = (intptr_t) closure;
1998 int mix;
1999 float top = *(float*) call_data;
2000 XEvent event;
2001
2002 mix = ((int) ((1.0 - top) * 256.0)) << 8;
2003 if (mix > 0xFFFF)
2004 mix = 0xFFFF;
2005
2006 switch (which) {
2007 case S_RED:
2008 mixed_color[edit_fill].red = mix;
2009 red_top = top;
2010 break;
2011 case S_GREEN:
2012 mixed_color[edit_fill].green = mix;
2013 green_top = top;
2014 break;
2015 case S_BLUE:
2016 mixed_color[edit_fill].blue = mix;
2017 blue_top = top;
2018 break;
2019 case S_LOCKED:
2020 buttons_down = bars_locked;
2021 last_pos = (int) (locked_top*255.0);
2022 event.xmotion.y = (int)(top*255.0);
2023 move_scroll(w, &event, (String *)NULL, (Cardinal *)NULL);
2024 buttons_down = 0;
2025 return;
2026 }
2027 if (do_change) {
2028 if (current_memory >= 0) {
2029 StoreMix_and_Mem();
2030 if (!colorUsed[current_memory])
2031 colorUsed[current_memory] = True;
2032 update_scrl_triple((Widget)NULL, (XEvent *)NULL,
2033 (String *)NULL, (Cardinal *)NULL);
2034 }
2035 }
2036 XawScrollbarSetThumb(w, top, THUMB_H);
2037 move_lock();
2038 }
2039
2040
move_lock(void)2041 void move_lock(void)
2042 {
2043 locked_top = 1.0;
2044 if (bars_locked & S_RED)
2045 locked_top = min2(locked_top, red_top);
2046 if (bars_locked & S_BLUE)
2047 locked_top = min2(locked_top, blue_top);
2048 if (bars_locked & S_GREEN)
2049 locked_top = min2(locked_top, green_top);
2050 XawScrollbarSetThumb(lockedScroll, locked_top, THUMB_H);
2051 }
2052
2053 void
next_pencolor(ind_sw_info * sw)2054 next_pencolor(ind_sw_info *sw)
2055 {
2056 while ((++cur_pencolor < NUM_STD_COLS+num_usr_cols) &&
2057 (cur_pencolor >= NUM_STD_COLS && colorFree[cur_pencolor-NUM_STD_COLS]))
2058 ;
2059 if (cur_pencolor >= NUM_STD_COLS+num_usr_cols)
2060 cur_pencolor = DEFAULT;
2061 show_pencolor();
2062 }
2063
2064 void
prev_pencolor(ind_sw_info * sw)2065 prev_pencolor(ind_sw_info *sw)
2066 {
2067 if (cur_pencolor <= DEFAULT)
2068 cur_pencolor = NUM_STD_COLS+num_usr_cols;
2069 while ((--cur_pencolor >= NUM_STD_COLS) && colorFree[cur_pencolor-NUM_STD_COLS])
2070 ;
2071 show_pencolor();
2072 }
2073
2074 /* Update the Pen COLOR in the indicator button */
2075
2076 void
show_pencolor(void)2077 show_pencolor(void)
2078 {
2079 int color;
2080 char colorname[10];
2081
2082 if (cur_pencolor < DEFAULT || cur_pencolor >= NUM_STD_COLS+num_usr_cols ||
2083 cur_pencolor >= NUM_STD_COLS && colorFree[cur_pencolor-NUM_STD_COLS])
2084 cur_pencolor = DEFAULT;
2085 if (cur_pencolor == DEFAULT)
2086 color = x_fg_color.pixel;
2087 else
2088 color = all_colors_available ? colors[cur_pencolor] :
2089 (cur_pencolor == WHITE? x_bg_color.pixel: x_fg_color.pixel);
2090
2091 recolor_fillstyles(); /* change the colors of the fill style indicators */
2092 /* force re-creation of popup fill style panel next time it is popped up
2093 because the user may have changed to/from black and other color. Do this
2094 because the tints must be either created or deleted. */
2095 fill_style_sw->panel = (Widget) NULL;
2096 show_fillstyle(fill_style_sw);
2097 if (cur_pencolor < NUM_STD_COLS) {
2098 strcpy(colorname,colorNames[cur_pencolor + 1].name);
2099 put_msg("Pen color set to %s", colorNames[cur_pencolor + 1].name);
2100 } else {
2101 put_msg("Pen color set to user color %d", cur_pencolor);
2102 sprintf(colorname,"%d",cur_pencolor);
2103 }
2104 /* first erase old colorname */
2105 XDrawImageString(tool_d, pen_color_button->pixmap, ind_button_gc, 3, 25,
2106 " ", 8);
2107 /* now fill the color rectangle with the new color */
2108 XSetForeground(tool_d, pen_color_gc, color);
2109 XFillRectangle(tool_d, pen_color_button->pixmap, pen_color_gc,
2110 pen_color_button->sw_width - 30, 4, 26, 26);
2111 /* and put the color name in the button also */
2112 XDrawImageString(tool_d, pen_color_button->pixmap, ind_button_gc, 3, 25,
2113 colorname, strlen(colorname));
2114 if (pen_color_button->updbut && update_buts_managed)
2115 XtUnmanageChild(pen_color_button->updbut);
2116 FirstArg(XtNbackgroundPixmap, 0);
2117 SetValues(pen_color_button->button);
2118 /* put the pixmap in the widget background */
2119 FirstArg(XtNbackgroundPixmap, pen_color_button->pixmap);
2120 SetValues(pen_color_button->button);
2121 if (pen_color_button->updbut && update_buts_managed)
2122 XtManageChild(pen_color_button->updbut);
2123 }
2124
2125 void
next_fillcolor(ind_sw_info * sw)2126 next_fillcolor(ind_sw_info *sw)
2127 {
2128 while ((++cur_fillcolor < NUM_STD_COLS+num_usr_cols) &&
2129 (cur_fillcolor >= NUM_STD_COLS && colorFree[cur_fillcolor-NUM_STD_COLS]))
2130 ;
2131 if (cur_fillcolor >= NUM_STD_COLS+num_usr_cols)
2132 cur_fillcolor = DEFAULT;
2133 show_fillcolor();
2134 }
2135
2136 void
prev_fillcolor(ind_sw_info * sw)2137 prev_fillcolor(ind_sw_info *sw)
2138 {
2139 if (cur_fillcolor <= DEFAULT)
2140 cur_fillcolor = NUM_STD_COLS+num_usr_cols;
2141 while ((--cur_fillcolor >= NUM_STD_COLS) && colorFree[cur_fillcolor-NUM_STD_COLS])
2142 ;
2143 show_fillcolor();
2144 }
2145
2146 /* Update the Fill COLOR in the indicator button */
2147
2148 void
show_fillcolor(void)2149 show_fillcolor(void)
2150 {
2151 int color;
2152 char colorname[10];
2153
2154 if (cur_fillcolor < DEFAULT || cur_fillcolor >= NUM_STD_COLS+num_usr_cols ||
2155 cur_fillcolor >= NUM_STD_COLS && colorFree[cur_fillcolor-NUM_STD_COLS])
2156 cur_fillcolor = DEFAULT;
2157 if (cur_fillcolor == DEFAULT)
2158 color = x_fg_color.pixel;
2159 else
2160 color = all_colors_available ? colors[cur_fillcolor] :
2161 (cur_fillcolor == WHITE? x_bg_color.pixel: x_fg_color.pixel);
2162
2163 recolor_fillstyles(); /* change the colors of the fill style indicators */
2164 /* force re-creation of popup fill style panel next time it is popped up
2165 because the user may have changed to/from black and other color. Do this
2166 because the tints must be either created or deleted. */
2167 fill_style_sw->panel = (Widget) NULL;
2168 show_fillstyle(fill_style_sw);
2169 if (cur_fillcolor < NUM_STD_COLS) {
2170 put_msg("Fill color set to %s", colorNames[cur_fillcolor + 1].name);
2171 strcpy(colorname,colorNames[cur_fillcolor + 1].name);
2172 } else {
2173 put_msg("Fill color set to user color %d", cur_fillcolor);
2174 sprintf(colorname,"%d",cur_fillcolor);
2175 }
2176 /* first erase old colorname */
2177 XDrawImageString(tool_d, fill_color_button->pixmap, ind_button_gc, 3, 25,
2178 " ", 8);
2179 /* now fill the color rectangle with the new fill color */
2180 XSetForeground(tool_d, fill_color_gc, color);
2181 XFillRectangle(tool_d, fill_color_button->pixmap, fill_color_gc,
2182 fill_color_button->sw_width - 30, 4, 26, 26);
2183 /* and put the color name in the button also */
2184 XDrawImageString(tool_d, fill_color_button->pixmap, ind_button_gc, 3, 25,
2185 colorname, strlen(colorname));
2186 if (fill_color_button->updbut && update_buts_managed)
2187 XtUnmanageChild(fill_color_button->updbut);
2188 FirstArg(XtNbackgroundPixmap, 0);
2189 SetValues(fill_color_button->button);
2190 /* put the pixmap in the widget background */
2191 FirstArg(XtNbackgroundPixmap, fill_color_button->pixmap);
2192 SetValues(fill_color_button->button);
2193 if (fill_color_button->updbut && update_buts_managed)
2194 XtManageChild(fill_color_button->updbut);
2195 }
2196
2197 /* inform the window manager that we have a (possibly) new colormap */
2198
set_cmap(Window window)2199 void set_cmap(Window window)
2200 {
2201 XSetWindowColormap(tool_d, window, tool_cm);
2202 }
2203
2204 /*
2205 * color.c - color helper routines
2206 *
2207 * Author: Christopher A. Kent
2208 * Western Research Laboratory
2209 * Digital Equipment Corporation
2210 * Date: Sun Dec 13 1987
2211 * Copyright (c) 1987 Christopher A. Kent
2212 */
2213
2214 /*
2215 * See David F. Rogers, "Procedural Elements for Computer Graphics",
2216 * McGraw-Hill, for the theory behind these routines.
2217 */
2218
2219 /*
2220 * $Log: w_color.c,v $
2221 * Revision 1.1 1995/02/28 15:40:16 feuille
2222 * Initial revision
2223 *
2224 * Revision 1.2 90/06/30 14:32:48 rlh2
2225 * patchlevel 1
2226 *
2227 * Revision 1.1 90/05/10 11:17:30 rlh2
2228 * Initial revision
2229 *
2230 * Revision 1.2 88/06/30 09:58:36 mikey
2231 * Handles CMY also.
2232 *
2233 * Revision 1.1 88/06/30 09:10:32 mikey
2234 * Initial revision
2235 *
2236 */
2237
2238 #define MAX_INTENSITY 65535 /* for X11 */
2239
2240 #define ABS(x) ((x)<0?-(x):(x))
2241
2242 RGB RGBWhite = { MAX_INTENSITY, MAX_INTENSITY, MAX_INTENSITY };
2243 RGB RGBBlack = { 0, 0, 0 };
2244
2245 /*
2246 * Convert an HSV to an RGB.
2247 */
2248
2249 RGB
HSVToRGB(HSV hsv)2250 HSVToRGB(HSV hsv)
2251 {
2252 RGB rgb;
2253 float p, q, t, f;
2254 int i;
2255
2256 if (hsv.s == 0.0)
2257 rgb = PctToRGB(hsv.v, hsv.v, hsv.v);
2258 else {
2259 if (hsv.s > 1.0)
2260 hsv.s = 1.0;
2261 if (hsv.s < 0.0)
2262 hsv.s = 0.0;
2263 if (hsv.v > 1.0)
2264 hsv.v = 1.0;
2265 if (hsv.v < 0.0)
2266 hsv.v = 0.0;
2267 if (hsv.h >= 1.0)
2268 hsv.h = 0.0;
2269
2270 hsv.h = 6.0 * hsv.h;
2271 i = (int) hsv.h;
2272 f = hsv.h - (float) i;
2273 p = hsv.v * (1.0 - hsv.s);
2274 q = hsv.v * (1.0 - (hsv.s * f));
2275 t = hsv.v * (1.0 - (hsv.s * (1.0 - f)));
2276
2277 switch(i) {
2278 case 0: rgb = PctToRGB(hsv.v, t, p); break;
2279 case 1: rgb = PctToRGB(q, hsv.v, p); break;
2280 case 2: rgb = PctToRGB(p, hsv.v, t); break;
2281 case 3: rgb = PctToRGB(p, q, hsv.v); break;
2282 case 4: rgb = PctToRGB(t, p, hsv.v); break;
2283 case 5: rgb = PctToRGB(hsv.v, p, q); break;
2284 }
2285 }
2286 return rgb;
2287 }
2288
2289 /*
2290 * Convert an RGB to HSV.
2291 */
2292
2293 HSV
RGBToHSV(RGB rgb)2294 RGBToHSV(RGB rgb)
2295 {
2296 HSV hsv;
2297 float rr, gg, bb;
2298 float min, max;
2299 float rc, gc, bc;
2300
2301 rr = (float) rgb.r / (float) MAX_INTENSITY;
2302 gg = (float) rgb.g / (float) MAX_INTENSITY;
2303 bb = (float) rgb.b / (float) MAX_INTENSITY;
2304
2305 max = max2(max2(rr, gg), bb);
2306 min = min2(min2(rr, gg), bb);
2307 hsv.v = max;
2308 if (max == 0.0)
2309 hsv.s = 0.0;
2310 else
2311 hsv.s = (max - min) / max;
2312 if (hsv.s == 0.0)
2313 hsv.h = 0.0;
2314 else {
2315 rc = (max - rr) / (max - min);
2316 gc = (max - gg) / (max - min);
2317 bc = (max - bb) / (max - min);
2318 if (rr == max)
2319 hsv.h = bc - gc;
2320 else if (gg == max)
2321 hsv.h = 2.0 + rc - bc;
2322 else if (bb == max)
2323 hsv.h = 4.0 + gc - rc;
2324
2325 if (hsv.h < 0.0)
2326 hsv.h += 6.0;
2327 hsv.h = hsv.h / 6.0;
2328 }
2329 return hsv;
2330 }
2331
2332 /*
2333 * Intensity percentages to RGB.
2334 */
2335
2336 RGB
PctToRGB(float rr,float gg,float bb)2337 PctToRGB(float rr, float gg, float bb)
2338 {
2339 RGB rgb;
2340
2341 if (rr > 1.0)
2342 rr = 1.0;
2343 if (gg > 1.0)
2344 gg = 1.0;
2345 if (bb > 1.0)
2346 bb = 1.0;
2347
2348 rgb.r = (int)(0.5 + rr * MAX_INTENSITY);
2349 rgb.g = (int)(0.5 + gg * MAX_INTENSITY);
2350 rgb.b = (int)(0.5 + bb * MAX_INTENSITY);
2351 return rgb;
2352 }
2353
2354 /* +-------------------------------------------------------------------+ */
2355 /* | Copyright 1993, David Koblas (koblas@netcom.com) | */
2356 /* | Copyright 1995, 1996 Torsten Martinsen (bullestock@dk-online.dk) | */
2357 /* | | */
2358 /* | Permission to use, copy, modify, and to distribute this software | */
2359 /* | and its documentation for any purpose is hereby granted without | */
2360 /* | fee, provided that the above copyright notice appear in all | */
2361 /* | copies and that both that copyright notice and this permission | */
2362 /* | notice appear in supporting documentation. There is no | */
2363 /* | representations about the suitability of this software for | */
2364 /* | any purpose. this software is provided "as is" without express | */
2365 /* | or implied warranty. | */
2366 /* | | */
2367 /* +-------------------------------------------------------------------+ */
2368
2369
2370 /*
2371 ** Grab the pixel value from some other window
2372 **
2373 ** Store pixel value in *p and colormap ID in *cmap unless they are NULL.
2374 **
2375 ** General strategy:
2376 ** Grab the cursor
2377 ** Wait for the up/down button event
2378 ** Lookup what window the event is over
2379 ** Query the pixel value
2380 */
2381 static void
DoGrabPixel(Widget w,Pixel * p,Colormap * cmap)2382 DoGrabPixel(Widget w, Pixel *p, Colormap *cmap)
2383 {
2384 int x, y, nx, ny;
2385 XImage *xim;
2386 Colormap amap;
2387 Window root = RootWindowOfScreen(XtScreen(w));
2388 Window window;
2389
2390 doGrab(w, 0, 0, &x, &y);
2391
2392 if (cmap == NULL)
2393 cmap = &amap;
2394
2395 xyToWindowCmap(tool_d, x, y, root, &nx, &ny, &window, cmap);
2396
2397 xim = XGetImage(tool_d, window, nx, ny, 1, 1, AllPlanes, ZPixmap);
2398
2399 if (p != NULL)
2400 *p = XGetPixel(xim, 0, 0);
2401
2402 XDestroyImage(xim);
2403 }
2404
2405 /*
2406 * Grab a rectangle of some window.
2407 * Zero width and height specifies to just grab a single pixel.
2408 * Returns coords of event.
2409 */
2410
2411 /*
2412 ** Convenience function for doing server pointer grabs
2413 */
2414 #define GRAB_INTERVAL 30
2415
2416 typedef struct {
2417 XtAppContext app;
2418 Display *dpy;
2419 GC gc;
2420 Window root;
2421 Boolean drawn;
2422 int x, y, ox, oy, width, height;
2423 XtIntervalId id;
2424 } GrabInfo;
2425
2426 static void
doGrab(Widget w,int width,int height,int * x,int * y)2427 doGrab(Widget w, int width, int height, int *x, int *y)
2428 {
2429 XtAppContext app = XtWidgetToApplicationContext(w);
2430 Window root = DefaultRootWindow(tool_d);
2431 XEvent event;
2432 Cursor cursor = XCreateFontCursor(tool_d, XC_crosshair);
2433 int count = 0;
2434 GrabInfo *info = NULL;
2435
2436 /* Set up grab cursor */
2437 if (XGrabPointer(tool_d, root, False,
2438 info == NULL ? ButtonPressMask | ButtonReleaseMask
2439 : ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
2440 GrabModeSync, GrabModeAsync,
2441 root, cursor, CurrentTime))
2442 return;
2443
2444 do {
2445 XAllowEvents(tool_d, SyncPointer, CurrentTime);
2446 XtAppNextEvent(app, &event);
2447 if (event.type == ButtonPress)
2448 count++;
2449 else if (event.type == ButtonRelease) {
2450 if (count == 1)
2451 break;
2452 else
2453 count--;
2454 } else if (event.type == MotionNotify) {
2455 info->x = event.xmotion.x;
2456 info->y = event.xmotion.y;
2457 } else
2458 XtDispatchEvent(&event);
2459 }
2460 while (True);
2461
2462 XUngrabPointer(tool_d, CurrentTime);
2463
2464 if (info != NULL) {
2465 /* remove grab cursor */
2466 if (info->drawn)
2467 XDrawRectangle(info->dpy, info->root, info->gc,
2468 info->ox - info->width / 2,
2469 info->oy - info->height / 2,
2470 info->width, info->height);
2471 XtRemoveTimeOut(info->id);
2472 XFreeGC(tool_d, info->gc);
2473 XtFree((XtPointer) info);
2474 }
2475 *x = event.xbutton.x;
2476 *y = event.xbutton.y;
2477 }
2478
2479 /*
2480 * Given coords x,y in the 'base' window, descend the window hierarchy
2481 * and find the child window of class InputOutput containing those
2482 * coordinates. Return coords in child window in (*nx,*ny).
2483 * If the child window has a colormap, return that; otherwise return
2484 * the default colormap for the display.
2485 */
2486 static void
xyToWindowCmap(Display * dpy,int x,int y,Window base,int * nx,int * ny,Window * window,Colormap * cmap)2487 xyToWindowCmap(Display *dpy, int x, int y, Window base, int *nx, int *ny, Window *window, Colormap *cmap)
2488 {
2489 Window twin;
2490 Colormap tmap;
2491 Window child, sub;
2492 XWindowAttributes attr;
2493
2494 twin = base;
2495 tmap = None;
2496
2497 sub = base;
2498 *nx = x;
2499 *ny = y;
2500
2501 while (sub != None) {
2502 x = *nx;
2503 y = *ny;
2504 child = sub;
2505 XTranslateCoordinates(dpy, base, child, x, y, nx, ny, &sub);
2506 base = child;
2507
2508 XGetWindowAttributes(dpy, child, &attr);
2509 if (attr.class == InputOutput && attr.colormap != None) {
2510 tmap = attr.colormap;
2511 twin = child;
2512 }
2513 }
2514
2515 if (tmap == None)
2516 *cmap = DefaultColormap(dpy, DefaultScreen(dpy));
2517 else
2518 *cmap = tmap;
2519 *window = twin;
2520 }
2521
2522