1 /*
2 * FIG : Facility for Interactive Generation of figures
3 * Copyright (c) 1985-1988 by Supoj Sutanthavibul
4 * Parts Copyright (c) 1989-2007 by Brian V. Smith
5 * Parts Copyright (c) 1991 by Paul King
6 *
7 * Any party obtaining a copy of these files is granted, free of charge, a
8 * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
9 * nonexclusive right and license to deal in this software and documentation
10 * files (the "Software"), including without limitation the rights to use,
11 * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
12 * the Software, and to permit persons who receive copies from any such
13 * party to do so, with the only requirement being that the above copyright
14 * and this permission notice remain intact.
15 *
16 */
17
18 #include "fig.h"
19 #include "figx.h"
20 #include "resources.h"
21 #include "main.h"
22 #include "mode.h"
23 #include "object.h"
24 #include "f_util.h"
25 #include "u_redraw.h"
26 #include "w_canvas.h"
27 #include "w_cmdpanel.h"
28 #include "w_drawprim.h"
29 #include "w_export.h"
30 #include "w_indpanel.h"
31 #include "w_color.h"
32 #include "w_layers.h"
33 #include "w_msgpanel.h"
34 #include "w_print.h"
35 #include "w_util.h"
36 #include "w_setup.h"
37
38 #include <X11/IntrinsicP.h> /* XtResizeWidget() */
39
40 #ifdef I18N
41 #include "d_text.h"
42 #endif /* I18N */
43
44 /* EXPORTS */
45
46 char *grid_inch_choices[] = { "None", "1/16", "1/8", "1/4", "1/2", "1", "2", "5", "10" };
47 int num_grid_inch_choices = sizeof(grid_inch_choices) / sizeof(char *);
48
49 char *grid_tenth_inch_choices[] = { "None", "1/10", "1/5", "1/2", "1", "2", "5", "10" };
50 int num_grid_tenth_inch_choices = sizeof(grid_tenth_inch_choices) / sizeof(char *);
51
52 char *grid_cm_choices[] = { "None", "1 mm", "2 mm", "5 mm", "10 mm",
53 "20 mm", "50 mm", "100 mm" };
54 int num_grid_cm_choices = sizeof(grid_cm_choices) / sizeof(char *);
55
56 char **grid_choices;
57 int n_grid_choices, grid_minor, grid_major;
58 Pixmap check_pm, null_check_pm;
59 Pixmap sm_check_pm, sm_null_check_pm;
60 Pixmap balloons_on_bitmap=(Pixmap) 0;
61 Pixmap balloons_off_bitmap=(Pixmap) 0;
62 Pixmap menu_arrow, menu_cascade_arrow;
63 Pixmap arrow_pixmaps[NUM_ARROW_TYPES+1];
64 Pixmap diamond_pixmap;
65 Pixmap linestyle_pixmaps[NUM_LINESTYLE_TYPES];
66 Pixmap mouse_l=(Pixmap) 0, /* mouse indicator bitmaps for the balloons */
67 mouse_r=(Pixmap) 0;
68
69 /* LOCALS */
70
71 DeclareStaticArgs(14);
72 static void _installscroll(Widget parent, Widget widget);
73
74 static Pixmap spinup_bm=0; /* pixmaps for spinners */
75 static Pixmap spindown_bm=0;
76 static void validate_int(Widget w, XtPointer info, XtPointer dum); /* validation for spinners */
77 static void convert_gridstr(Widget widget, float mult);
78
79 /* for internal consumption only (use MakeIntSpinnerEntry or MakeFloatSpinnerEntry) */
80 static Widget MakeSpinnerEntry(Widget parent, Widget *text, char *name, Widget below, Widget beside, XtCallbackProc callback, char *string, int type, float min, float max, float inc, int width);
81
82 /* bitmap for checkmark */
83 static unsigned char check_bits[] = {
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x7f,
85 0x8c, 0x1f, 0xde, 0x07, 0xfe, 0x03, 0xfc, 0x01, 0xf8, 0x00, 0xf0, 0x00,
86 0x70, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00};
87
88 /* smaller checkmark */
89 /* sm_check_width and _height are defined in w_util.c so w_layers.c can use them */
90 static unsigned char sm_check_bits[] = {
91 0x00, 0x00, 0x80, 0x01, 0xc0, 0x01, 0xe0, 0x01, 0x76, 0x00, 0x3e, 0x00,
92 0x1c, 0x00, 0x18, 0x00, 0x08, 0x00, 0x00, 0x00};
93
94 #define balloons_on_width 16
95 #define balloons_on_height 15
96 static unsigned char balloons_on_bits[] = {
97 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x67, 0xfe, 0x63, 0xfe, 0x71, 0xfe, 0x79,
98 0xfe, 0x7c, 0xe2, 0x7c, 0x46, 0x7e, 0x0e, 0x7e, 0x0e, 0x7f, 0x1e, 0x7f,
99 0x9e, 0x7f, 0xfe, 0x7f, 0x00, 0x00};
100
101 #define balloons_off_width 16
102 #define balloons_off_height 15
103 static unsigned char balloons_off_bits[] = {
104 0xff, 0xff, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
105 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
106 0x01, 0x80, 0x01, 0x80, 0xff, 0xff};
107
108 /* spinner up/down icons */
109
110 #define spinup_width 9
111 #define spinup_height 6
112 static unsigned char spinup_bits[] = {
113 0x10, 0x00, 0x38, 0x00, 0x7c, 0x00, 0xfe, 0x00, 0xff, 0x01, 0x00, 0x00};
114 #define spindown_width 9
115 #define spindown_height 6
116 static unsigned char spindown_bits[] = {
117 0x00, 0x00, 0xff, 0x01, 0xfe, 0x00, 0x7c, 0x00, 0x38, 0x00, 0x10, 0x00};
118
119 #define mouse_r_width 19
120 #define mouse_r_height 10
121 static unsigned char mouse_r_bits[] = {
122 0xff, 0xff, 0x07, 0x41, 0xf0, 0x07, 0x41, 0xf0, 0x07, 0x41, 0xf0, 0x07,
123 0x41, 0xf0, 0x07, 0x41, 0xf0, 0x07, 0x41, 0xf0, 0x07, 0x41, 0xf0, 0x07,
124 0x41, 0xf0, 0x07, 0xff, 0xff, 0x07};
125
126 #define mouse_l_width 19
127 #define mouse_l_height 10
128 static unsigned char mouse_l_bits[] = {
129 0xff, 0xff, 0x07, 0x7f, 0x10, 0x04, 0x7f, 0x10, 0x04, 0x7f, 0x10, 0x04,
130 0x7f, 0x10, 0x04, 0x7f, 0x10, 0x04, 0x7f, 0x10, 0x04, 0x7f, 0x10, 0x04,
131 0x7f, 0x10, 0x04, 0xff, 0xff, 0x07};
132
133 /* arrow for pull-down menus */
134
135 #define menu_arrow_width 11
136 #define menu_arrow_height 13
137 static unsigned char menu_arrow_bits[] = {
138 0xf8,0x00,0xd8,0x00,0xa8,0x00,0xd8,0x00,0xa8,0x00,0xd8,0x00,
139 0xaf,0x07,0x55,0x05,0xaa,0x02,0x54,0x01,0xa8,0x00,0x50,0x00,
140 0x20,0x00};
141
142 /* arrow for cascade menu entries */
143
144 #define menu_cascade_arrow_width 10
145 #define menu_cascade_arrow_height 12
146 static unsigned char menu_cascade_arrow_bits[] = {
147 0x00, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x3e, 0x00, 0xfe, 0x00, 0xfe, 0x01,
148 0xfe, 0x01, 0xfe, 0x00, 0x3e, 0x00, 0x0e, 0x00, 0x02, 0x00, 0x00, 0x00};
149
150 /* diamond for library menu to indicate toplevel files.
151 * For the XAW3D1_5E version, there is a single point on the left edge and the
152 * diamond is moved to the right because the menu's 3D edge obscures it otherwise */
153
154 #ifdef XAW3D1_5E
155 #define diamond_width 12
156 #define diamond_height 7
157 static unsigned char diamond_bits[] = {
158 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0xe1,
159 0x0f, 0xc0, 0x07, 0x80, 0x03, 0x00, 0x01};
160 #else
161 #define diamond_width 7
162 #define diamond_height 7
163 static unsigned char diamond_bits[] = {
164 0x08, 0x1c, 0x3e, 0x7f, 0x3e, 0x1c, 0x08};
165 #endif /* XAW3D1_5E */
166
167 /* popup a confirmation window */
168
169 static int query_result, query_done;
170 static String query_translations =
171 "<Message>WM_PROTOCOLS: DismissQuery()\n";
172 static void accept_cancel(Widget widget, XtPointer closure, XtPointer call_data);
173 static XtActionsRec query_actions[] =
174 {
175 {"DismissQuery", (XtActionProc) accept_cancel},
176 };
177
178 /* synchronize so that (e.g.) new cursor appears etc. */
179
180
181
app_flush(void)182 void app_flush(void)
183 {
184 /* this method prevents "ghost" rubberbanding when the user
185 moves the mouse after creating/resizing object */
186 XSync(tool_d, False);
187 }
188
189 static void
accept_yes(Widget widget,XtPointer closure,XtPointer call_data)190 accept_yes(Widget widget, XtPointer closure, XtPointer call_data)
191 {
192 query_done = 1;
193 query_result = RESULT_YES;
194 }
195
196 static void
accept_no(Widget widget,XtPointer closure,XtPointer call_data)197 accept_no(Widget widget, XtPointer closure, XtPointer call_data)
198 {
199 query_done = 1;
200 query_result = RESULT_NO;
201 }
202
203 static void
accept_cancel(Widget widget,XtPointer closure,XtPointer call_data)204 accept_cancel(Widget widget, XtPointer closure, XtPointer call_data)
205 {
206 query_done = 1;
207 query_result = RESULT_CANCEL;
208 }
209
210 static void
accept_part(Widget widget,XtPointer closure,XtPointer call_data)211 accept_part(Widget widget, XtPointer closure, XtPointer call_data)
212 {
213 query_done = 1;
214 query_result = RESULT_PART;
215 }
216
217 static void
accept_all(Widget widget,XtPointer closure,XtPointer call_data)218 accept_all(Widget widget, XtPointer closure, XtPointer call_data)
219 {
220 query_done = 1;
221 query_result = RESULT_ALL;
222 }
223
224 int
popup_query(int query_type,char * message)225 popup_query(int query_type, char *message)
226 {
227 Widget query_popup, query_form, query_message;
228 Widget query_yes, query_no, query_cancel;
229 Widget query_part, query_all;
230 int xposn, yposn;
231 Window win;
232 XEvent event;
233 static Boolean actions_added=False;
234
235 XTranslateCoordinates(tool_d, main_canvas, XDefaultRootWindow(tool_d),
236 150, 200, &xposn, &yposn, &win);
237 FirstArg(XtNallowShellResize, True);
238 NextArg(XtNx, xposn);
239 NextArg(XtNy, yposn);
240 NextArg(XtNborderWidth, POPUP_BW);
241 NextArg(XtNtitle, "Xfig: Query");
242 NextArg(XtNcolormap, tool_cm);
243 query_popup = XtCreatePopupShell("query_popup", transientShellWidgetClass,
244 tool, Args, ArgCount);
245 XtOverrideTranslations(query_popup,
246 XtParseTranslationTable(query_translations));
247 if (!actions_added) {
248 XtAppAddActions(tool_app, query_actions, XtNumber(query_actions));
249 actions_added = True;
250 }
251
252 FirstArg(XtNdefaultDistance, 10);
253 query_form = XtCreateManagedWidget("query_form", formWidgetClass,
254 query_popup, Args, ArgCount);
255
256 FirstArg(XtNfont, bold_font);
257 NextArg(XtNborderWidth, 0);
258 NextArg(XtNlabel, message);
259 query_message = XtCreateManagedWidget("message", labelWidgetClass,
260 query_form, Args, ArgCount);
261
262 FirstArg(XtNheight, 25);
263 NextArg(XtNvertDistance, 15);
264 NextArg(XtNfromVert, query_message);
265 NextArg(XtNborderWidth, INTERNAL_BW);
266 NextArg(XtNhorizDistance, 55);
267
268 if (query_type == QUERY_ALLPARTCAN) {
269 NextArg(XtNlabel, "Save All ");
270 query_all = XtCreateManagedWidget("all", commandWidgetClass,
271 query_form, Args, ArgCount);
272 XtAddCallback(query_all, XtNcallback, accept_all, (XtPointer) NULL);
273 ArgCount = 4;
274 NextArg(XtNhorizDistance, 25);
275 NextArg(XtNlabel, "Save Part");
276 NextArg(XtNfromHoriz, query_all);
277 query_part = XtCreateManagedWidget("part", commandWidgetClass,
278 query_form, Args, ArgCount);
279 XtAddCallback(query_part, XtNcallback, accept_part, (XtPointer) NULL);
280 /* setup for the cancel button */
281 ArgCount = 5;
282 NextArg(XtNfromHoriz, query_part);
283
284 } else if (query_type == QUERY_OK) {
285 /* just OK button */
286 NextArg(XtNlabel, " Ok ");
287 query_yes = XtCreateManagedWidget("ok", commandWidgetClass,
288 query_form, Args, ArgCount);
289 /* just use the accept_yes callback because the caller only gets one result anyway */
290 XtAddCallback(query_yes, XtNcallback, accept_yes, (XtPointer) NULL);
291
292 } else {
293 /* yes/no or yes/no/cancel */
294
295 NextArg(XtNlabel, " Yes ");
296 query_yes = XtCreateManagedWidget("yes", commandWidgetClass,
297 query_form, Args, ArgCount);
298 XtAddCallback(query_yes, XtNcallback, accept_yes, (XtPointer) NULL);
299
300 if (query_type == QUERY_YESNO || query_type == QUERY_YESNOCAN) {
301 ArgCount = 4;
302 NextArg(XtNhorizDistance, 25);
303 NextArg(XtNlabel, " No ");
304 NextArg(XtNfromHoriz, query_yes);
305 query_no = XtCreateManagedWidget("no", commandWidgetClass,
306 query_form, Args, ArgCount);
307 XtAddCallback(query_no, XtNcallback, accept_no, (XtPointer) NULL);
308
309 /* setup for the cancel button */
310 ArgCount = 5;
311 NextArg(XtNfromHoriz, query_no);
312 } else {
313 /* setup for the cancel button */
314 ArgCount = 4;
315 NextArg(XtNhorizDistance, 25);
316 NextArg(XtNfromHoriz, query_yes);
317 }
318 }
319
320 if (query_type == QUERY_YESCAN || query_type == QUERY_YESNOCAN ||
321 query_type == QUERY_ALLPARTCAN) {
322 NextArg(XtNlabel, "Cancel");
323 query_cancel = XtCreateManagedWidget("cancel", commandWidgetClass,
324 query_form, Args, ArgCount);
325 XtAddCallback(query_cancel, XtNcallback, accept_cancel, (XtPointer) NULL);
326 }
327
328 XtPopup(query_popup, XtGrabExclusive);
329 /* insure that the most recent colormap is installed */
330 set_cmap(XtWindow(query_popup));
331 (void) XSetWMProtocols(tool_d, XtWindow(query_popup), &wm_delete_window, 1);
332 XDefineCursor(tool_d, XtWindow(query_popup), arrow_cursor);
333
334 query_done = 0;
335 while (!query_done) {
336 /* pass events */
337 XNextEvent(tool_d, &event);
338 XtDispatchEvent(&event);
339 }
340
341 XtPopdown(query_popup);
342 XtDestroyWidget(query_popup);
343
344 return (query_result);
345 }
346
347 /*
348 * make a pulldown menu with "nent" button entries (labels) that call "callback"
349 * when pressed.
350 * Additionally, make a dividing line in the menu at the position "divide_line"
351 * (use -1 if no line desired)
352 */
353
354 #ifndef XAW3D1_5E
355 #include "SmeCascade.h"
356 #endif /* XAW3D1_5E */
357
358 #include "d_text.h"
359 #include "e_placelib.h"
360 #include "w_rulers.h"
361
362 Widget
make_pulldown_menu(char ** entries,Cardinal nent,int divide_line,char * divide_message,Widget parent,XtCallbackProc callback)363 make_pulldown_menu(char **entries, Cardinal nent, int divide_line, char *divide_message, Widget parent, XtCallbackProc callback)
364 {
365 Widget pulldown_menu, entry;
366 intptr_t i;
367
368 pulldown_menu = XtCreatePopupShell("menu", simpleMenuWidgetClass, parent,
369 NULL, ZERO);
370
371 for (i = 0; i < nent; i++) {
372 if (i == divide_line) {
373 (void) XtCreateManagedWidget(entries[i], smeLineObjectClass, pulldown_menu,
374 NULL, ZERO);
375 FirstArg(XtNlabel, divide_message);
376 (void) XtCreateManagedWidget("menu_divider", smeBSBObjectClass, pulldown_menu,
377 Args, ArgCount);
378 (void) XtCreateManagedWidget(entries[i], smeLineObjectClass, pulldown_menu,
379 NULL, ZERO);
380 }
381 entry = XtCreateManagedWidget(entries[i], smeBSBObjectClass, pulldown_menu,
382 NULL, ZERO);
383 XtAddCallback(entry, XtNcallback, callback, (XtPointer) i);
384 }
385 return pulldown_menu;
386 }
387
388 static void
CvtStringToFloat(XrmValuePtr args,Cardinal * num_args,XrmValuePtr fromVal,XrmValuePtr toVal)389 CvtStringToFloat(XrmValuePtr args, Cardinal *num_args, XrmValuePtr fromVal, XrmValuePtr toVal)
390 {
391 static float f;
392
393 if (*num_args != 0)
394 XtWarning("String to Float conversion needs no extra arguments");
395 if (sscanf((char *) fromVal->addr, "%f", &f) == 1) {
396 (*toVal).size = sizeof(float);
397 (*toVal).addr = (caddr_t) & f;
398 } else
399 XtStringConversionWarning((char *) fromVal->addr, "Float");
400 }
401
402 static void
CvtIntToFloat(XrmValuePtr args,Cardinal * num_args,XrmValuePtr fromVal,XrmValuePtr toVal)403 CvtIntToFloat(XrmValuePtr args, Cardinal *num_args, XrmValuePtr fromVal, XrmValuePtr toVal)
404 {
405 static float f;
406
407 if (*num_args != 0)
408 XtWarning("Int to Float conversion needs no extra arguments");
409 f = *(int *) fromVal->addr;
410 (*toVal).size = sizeof(float);
411 (*toVal).addr = (caddr_t) & f;
412 }
413
fix_converters(void)414 void fix_converters(void)
415 {
416 XtAppAddConverter(tool_app, "String", "Float", CvtStringToFloat, NULL, 0);
417 XtAppAddConverter(tool_app, "Int", "Float", CvtIntToFloat, NULL, 0);
418 }
419
420
421 static void
cancel_color(Widget w,XtPointer widget,XtPointer dum1)422 cancel_color(Widget w, XtPointer widget, XtPointer dum1)
423 {
424 XtPopdown((Widget)widget);
425 }
426
427 Widget
make_color_popup_menu(Widget parent,char * name,XtCallbackProc callback,Boolean include_transp,Boolean include_backg)428 make_color_popup_menu(Widget parent, char *name, XtCallbackProc callback, Boolean include_transp, Boolean include_backg)
429 {
430 Widget pop_menu, pop_form, color_box;
431 Widget viewp, entry, label;
432 intptr_t i;
433 char buf[30];
434 Position x_val, y_val;
435 Dimension height;
436 int wd, ht;
437 Pixel bgcolor;
438 Boolean first;
439
440 /* position selection panel just below button */
441 FirstArg(XtNheight, &height);
442 GetValues(parent);
443 XtTranslateCoords(parent, (Position) 0, (Position) height,
444 &x_val, &y_val);
445
446 /* by using the name "menu", the menuButton that is using this
447 * shell will know to pop it up, since that is the default menu name */
448 FirstArg(XtNx, x_val);
449 NextArg(XtNy, y_val+4);
450 pop_menu = XtCreatePopupShell("menu",
451 overrideShellWidgetClass, parent,
452 Args, ArgCount);
453
454 /* outer box containing label, color box, and cancel button */
455 FirstArg(XtNorientation, XtorientVertical);
456 pop_form = XtCreateManagedWidget("color_menu_form", formWidgetClass,
457 pop_menu, Args, ArgCount);
458
459 /* get the background color of the form for the "Background" button */
460 FirstArg(XtNbackground, &bgcolor);
461 GetValues(pop_form);
462
463 FirstArg(XtNlabel, name);
464 label = XtCreateManagedWidget("color_menu_label", labelWidgetClass,
465 pop_form, Args, ArgCount);
466
467 /* put the Background, None and Default outside the box/viewport */
468 first = True;
469 for (i=(include_transp? TRANSP_BACKGROUND:
470 include_backg? COLOR_NONE: DEFAULT); i<0; i++) {
471 set_color_name(i,buf);
472 FirstArg(XtNwidth, COLOR_BUT_WID);
473 NextArg(XtNborderWidth, COLOR_BUT_BD_WID);
474 if (!first) {
475 NextArg(XtNfromHoriz, entry);
476 }
477 first = False;
478 NextArg(XtNfromVert, label);
479 if (i==TRANSP_BACKGROUND) {
480 /* make its background transparent by using color of parent */
481 NextArg(XtNforeground, black_color.pixel);
482 NextArg(XtNbackground, bgcolor);
483 /* and it is a little wider due to the longer name */
484 NextArg(XtNwidth, COLOR_BUT_WID+14);
485 } else if (i==TRANSP_NONE) {
486 NextArg(XtNforeground, black_color.pixel);
487 NextArg(XtNbackground, white_color.pixel);
488 } else {
489 NextArg(XtNforeground, white_color.pixel);
490 NextArg(XtNbackground, black_color.pixel);
491 }
492 entry = XtCreateManagedWidget(buf, commandWidgetClass, pop_form, Args, ArgCount);
493 XtAddCallback(entry, XtNcallback, callback, (XtPointer) i);
494 }
495
496 /* make a scrollable viewport in case all the buttons don't fit */
497
498 FirstArg(XtNallowVert, True);
499 NextArg(XtNallowHoriz, False);
500 NextArg(XtNfromVert, entry);
501 if (num_usr_cols > 8) {
502 /* allow for width of scrollbar */
503 wd = 4*(COLOR_BUT_WID+2*COLOR_BUT_BD_WID)+25;
504 } else {
505 wd = 4*(COLOR_BUT_WID+2*COLOR_BUT_BD_WID);
506 }
507 if (num_usr_cols == 0) {
508 ht = 8*(COLOR_BUT_HT+2*COLOR_BUT_BD_WID+3);
509 } else {
510 ht = 12*(COLOR_BUT_HT+2*COLOR_BUT_BD_WID+3);
511 }
512 NextArg(XtNwidth, wd);
513 NextArg(XtNheight, ht);
514 NextArg(XtNborderWidth, 1);
515 viewp = XtCreateManagedWidget("color_viewp", viewportWidgetClass,
516 pop_form, Args, ArgCount);
517
518 FirstArg(XtNorientation, XtorientVertical);
519 NextArg(XtNhSpace, 0); /* small space between entries */
520 NextArg(XtNvSpace, 0);
521 color_box = XtCreateManagedWidget("color_box", boxWidgetClass,
522 viewp, Args, ArgCount);
523
524 /* now make the buttons in the box */
525 for (i = 0; i < NUM_STD_COLS+num_usr_cols; i++) {
526 XColor xcolor;
527 Pixel col;
528
529 /* only those user-defined colors that are defined */
530 if (i >= NUM_STD_COLS && colorFree[i-NUM_STD_COLS])
531 continue;
532 set_color_name(i,buf);
533 FirstArg(XtNwidth, COLOR_BUT_WID);
534 NextArg(XtNborderWidth, COLOR_BUT_BD_WID);
535 if (all_colors_available) {
536 xcolor.pixel = colors[i];
537 /* get RGB of the color to check intensity */
538 XQueryColor(tool_d, tool_cm, &xcolor);
539 /* make contrasting label */
540 if ((0.3 * xcolor.red + 0.59 * xcolor.green + 0.11 * xcolor.blue) <
541 0.55 * (255 << 8))
542 col = colors[WHITE];
543 else
544 col = colors[BLACK];
545 NextArg(XtNforeground, col);
546 NextArg(XtNbackground, colors[i]);
547 }
548 entry = XtCreateManagedWidget(buf, commandWidgetClass, color_box,
549 Args, ArgCount);
550 XtAddCallback(entry, XtNcallback, callback, (XtPointer) i);
551 }
552
553 /* make the cancel button */
554 FirstArg(XtNlabel, "Cancel");
555 NextArg(XtNfromVert, viewp);
556 entry = XtCreateManagedWidget(buf, commandWidgetClass, pop_form,
557 Args, ArgCount);
558 XtAddCallback(entry, XtNcallback, (XtCallbackProc) cancel_color,
559 (XtPointer) pop_menu);
560
561 return pop_menu;
562 }
563
564 void
set_color_name(int color,char * buf)565 set_color_name(int color, char *buf)
566 {
567 if (color == TRANSP_NONE)
568 sprintf(buf,"None");
569 else if (color == TRANSP_BACKGROUND)
570 sprintf(buf,"Background");
571 else if (color == DEFAULT || (color >= 0 && color < NUM_STD_COLS))
572 sprintf(buf, "%s", colorNames[color + 1].name);
573 else
574 sprintf(buf, "User %d", color);
575 }
576
577 /*
578 * Set the color name in the label of widget, set its foreground to
579 * that color, and set its background to a contrasting color
580 */
581
582 void
set_but_col(Widget widget,Pixel color)583 set_but_col(Widget widget, Pixel color)
584 {
585 XColor xcolor;
586 Pixel but_col;
587 char buf[50];
588
589 /* put the color name in the label and the color itself as the background */
590 set_color_name(color, buf);
591 but_col = x_color(color);
592 FirstArg(XtNlabel, buf);
593 NextArg(XtNbackground, but_col); /* set color of button */
594 SetValues(widget);
595
596 /* now set foreground to contrasting color */
597 xcolor.pixel = but_col;
598 XQueryColor(tool_d, tool_cm, &xcolor);
599 pick_contrast(xcolor, widget);
600 }
601
602 static void
inc_flt_spinner(Widget widget,XtPointer info,XtPointer dum)603 inc_flt_spinner(Widget widget, XtPointer info, XtPointer dum)
604 {
605 float val;
606 char *sval,str[40];
607 spin_struct *spins = (spin_struct*) info;
608 Widget textwidg = (Widget) spins->widget;
609
610 FirstArg(XtNstring, &sval);
611 GetValues(textwidg);
612 val = (float) atof(sval);
613 val += spins->inc;
614 if (val < spins->min)
615 val = spins->min;
616 if (val > spins->max)
617 val = spins->max;
618 sprintf(str,"%0.2f",val);
619 FirstArg(XtNstring, str);
620 SetValues(textwidg);
621 FirstArg(XtNinsertPosition, strlen(str));
622 SetValues(textwidg);
623 }
624
625 static void
dec_flt_spinner(Widget widget,XtPointer info,XtPointer dum)626 dec_flt_spinner(Widget widget, XtPointer info, XtPointer dum)
627 {
628 float val;
629 char *sval,str[40];
630 spin_struct *spins = (spin_struct*) info;
631 Widget textwidg = (Widget) spins->widget;
632
633
634 FirstArg(XtNstring, &sval);
635 GetValues(textwidg);
636 val = (float) atof(sval);
637 val -= spins->inc;
638 if (val < spins->min)
639 val = spins->min;
640 if (val > spins->max)
641 val = spins->max;
642 sprintf(str,"%0.2f",val);
643 FirstArg(XtNstring, str);
644 SetValues(textwidg);
645 FirstArg(XtNinsertPosition, strlen(str));
646 SetValues(textwidg);
647 }
648
649 static void
inc_int_spinner(Widget widget,XtPointer info,XtPointer dum)650 inc_int_spinner(Widget widget, XtPointer info, XtPointer dum)
651 {
652 int val;
653 char *sval,str[40];
654 spin_struct *spins = (spin_struct*) info;
655 Widget textwidg = (Widget) spins->widget;
656
657 FirstArg(XtNstring, &sval);
658 GetValues(textwidg);
659 val = (int) atof(sval);
660 val += (int) spins->inc;
661 if (val < (int) spins->min)
662 val = (int) spins->min;
663 if (val > (int) spins->max)
664 val = (int) spins->max;
665 sprintf(str,"%d",val);
666 FirstArg(XtNstring, str);
667 SetValues(textwidg);
668 FirstArg(XtNinsertPosition, strlen(str));
669 SetValues(textwidg);
670 }
671
672 static void
dec_int_spinner(Widget widget,XtPointer info,XtPointer dum)673 dec_int_spinner(Widget widget, XtPointer info, XtPointer dum)
674 {
675 int val;
676 char *sval,str[40];
677 spin_struct *spins = (spin_struct*) info;
678 Widget textwidg = (Widget) spins->widget;
679
680 FirstArg(XtNstring, &sval);
681 GetValues(textwidg);
682 val = (int) atof(sval);
683 val -= (int) spins->inc;
684 if (val < (int) spins->min)
685 val = (int) spins->min;
686 if (val > (int) spins->max)
687 val = (int) spins->max;
688 sprintf(str,"%d",val);
689 FirstArg(XtNstring, str);
690 SetValues(textwidg);
691 FirstArg(XtNinsertPosition, strlen(str));
692 SetValues(textwidg);
693 }
694
695 /***********************************************************************/
696 /* Code to handle automatic spinning when user holds down mouse button */
697 /***********************************************************************/
698
699 static void /* XtTimerCallbackProc */ auto_spin(XtPointer client_data, XtIntervalId *id);
700 static XtIntervalId auto_spinid;
701 static void /* XtEventHandler */ stop_spin_timer(int widget, int data, int event);
702 static Widget cur_spin = (Widget) 0;
703
704 static void /* XtEventHandler */
start_spin_timer(Widget widget,XtPointer data,XEvent event)705 start_spin_timer(Widget widget, XtPointer data, XEvent event)
706 {
707 auto_spinid = XtAppAddTimeOut(tool_app, appres.spinner_delay,
708 (XtTimerCallbackProc) auto_spin, (XtPointer) NULL);
709 /* add event to cancel timer when user releases button */
710 XtAddEventHandler(widget, ButtonReleaseMask, False,
711 (XtEventHandler) stop_spin_timer, (XtPointer) NULL);
712 /* keep track of which one the user is pressing */
713 cur_spin = widget;
714
715 return;
716 }
717
718 static void /* XtEventHandler */
stop_spin_timer(int widget,int data,int event)719 stop_spin_timer(int widget, int data, int event)
720 {
721 XtRemoveTimeOut(auto_spinid);
722
723 return;
724 }
725
726 static void /* XtTimerCallbackProc */
auto_spin(XtPointer client_data,XtIntervalId * id)727 auto_spin(XtPointer client_data, XtIntervalId *id)
728 {
729 auto_spinid = XtAppAddTimeOut(tool_app, appres.spinner_rate,
730 (XtTimerCallbackProc) auto_spin, (XtPointer) NULL);
731 /* call the proper spinup/down routine */
732 XtCallCallbacks(cur_spin, XtNcallback, 0);
733
734 return;
735 }
736
737 /***************************/
738 /* make an integer spinner */
739 /***************************/
740
741 Widget
MakeIntSpinnerEntry(Widget parent,Widget * text,char * name,Widget below,Widget beside,XtCallbackProc callback,char * string,int min,int max,int inc,int width)742 MakeIntSpinnerEntry(Widget parent, Widget *text, char *name, Widget below, Widget beside, XtCallbackProc callback, char *string, int min, int max, int inc, int width)
743 {
744 return MakeSpinnerEntry(parent, text, name, below, beside, callback,
745 string, I_IVAL, (float) min, (float) max, (float) inc, width);
746 }
747
748 /*********************************/
749 /* make a floating point spinner */
750 /*********************************/
751
752 Widget
MakeFloatSpinnerEntry(Widget parent,Widget * text,char * name,Widget below,Widget beside,XtCallbackProc callback,char * string,float min,float max,float inc,int width)753 MakeFloatSpinnerEntry(Widget parent, Widget *text, char *name, Widget below, Widget beside, XtCallbackProc callback, char *string, float min, float max, float inc, int width)
754 {
755 return MakeSpinnerEntry(parent, text, name, below, beside, callback,
756 string, I_FVAL, min, max, inc, width);
757 }
758
759 /*****************************************************************************************
760 Make a "spinner" entry widget - a widget with an asciiTextWidget and
761 two spinners, an up and down spinner to increase and decrease the value.
762 Call with: parent - (Widget) parent widget
763 text - (Widget*) text widget ID is stored here (RETURN)
764 name - (char*) name for text widget
765 below - (Widget) widget below which this one goes
766 beside - (Widget) widget beside which this one goes
767 callback - (XtCallbackProc) callback for the text widget and
768 spinners (0 if none)
769 Callback is passed spin_struct which
770 has min, max
771 string - (char*) initial string for text widget
772 type - (int) entry type (I_FVAL = float, I_IVAL = int)
773 min - (float) minimum value it is allowed to have
774 max - (float) maximum value it is allowed to have
775 inc - (float) increment/decrement value for each press of arrow
776 width - (int) width (pixels) of the text widget part
777
778 Return value is outer box widget which may be used for positioning subsequent widgets.
779 *****************************************************************************************/
780
781 static Widget
MakeSpinnerEntry(Widget parent,Widget * text,char * name,Widget below,Widget beside,XtCallbackProc callback,char * string,int type,float min,float max,float inc,int width)782 MakeSpinnerEntry(Widget parent, Widget *text, char *name, Widget below, Widget beside, XtCallbackProc callback, char *string, int type, float min, float max, float inc, int width)
783 {
784 Widget inform, outform, spinup, spindown, source;
785 spin_struct *spinstruct;
786 Pixel bgcolor;
787
788 if ((spinstruct = (spin_struct *) malloc(sizeof(spin_struct))) == NULL) {
789 file_msg("Can't allocate space for spinner");
790 return 0;
791 }
792
793 FirstArg(XtNfromVert, below);
794 NextArg(XtNfromHoriz, beside);
795 NextArg(XtNdefaultDistance, 0);
796 NextArg(XtNtop, XtChainTop);
797 NextArg(XtNbottom, XtChainTop);
798 NextArg(XtNleft, XtChainLeft);
799 NextArg(XtNright, XtChainLeft);
800 outform = XtCreateManagedWidget("spinner_form", formWidgetClass, parent, Args, ArgCount);
801
802 /* first the ascii widget to the left of the spinner controls */
803 FirstArg(XtNstring, string);
804 NextArg(XtNwidth, width);
805 NextArg(XtNleftMargin, 4);
806 NextArg(XtNeditType, XawtextEdit);
807 NextArg(XtNinsertPosition, strlen(string));
808 NextArg(XtNhorizDistance, 1);
809 NextArg(XtNvertDistance, 1);
810 NextArg(XtNtop, XtChainTop);
811 NextArg(XtNbottom, XtChainTop);
812 NextArg(XtNleft, XtChainLeft);
813 NextArg(XtNright, XtChainLeft);
814 NextArg(XtNborderWidth, 0);
815 *text = XtCreateManagedWidget(name, asciiTextWidgetClass,
816 outform, Args, ArgCount);
817 /* get id of text source widget */
818 FirstArg(XtNtextSource, &source);
819 GetValues(*text);
820
821 /* install callback to validate data that user types in */
822 if (type == I_IVAL)
823 XtAddCallback(source, XtNcallback, validate_int, (XtPointer) spinstruct);
824
825 /* add any callback the user wants */
826 if (callback) {
827 XtAddCallback(source, XtNcallback, callback, (XtPointer) spinstruct);
828 }
829
830 XtOverrideTranslations(*text, XtParseTranslationTable(text_translations));
831
832 /* setup the data structure that gets passed to the callback */
833 spinstruct->widget = *text;
834 spinstruct->min = min;
835 spinstruct->max = max;
836 spinstruct->inc = inc;
837
838 /* now the spinners */
839
840 /* get the background color of the text widget and make that the
841 background of the spinners */
842 FirstArg(XtNbackground, &bgcolor);
843 GetValues(*text);
844
845 /* give the main frame the same background so the little part under
846 the bottom spinner will blend with it */
847 FirstArg(XtNbackground, bgcolor);
848 SetValues(outform);
849
850 /* make the spinner bitmaps if we haven't already */
851 if (spinup_bm == 0 || spindown_bm == 0) {
852 spinup_bm = XCreatePixmapFromBitmapData(tool_d, XtWindow(ind_panel),
853 (char *) spinup_bits, spinup_width, spinup_height,
854 x_color(BLACK), bgcolor, tool_dpth);
855 spindown_bm = XCreatePixmapFromBitmapData(tool_d, XtWindow(ind_panel),
856 (char *) spindown_bits, spindown_width, spindown_height,
857 x_color(BLACK), bgcolor, tool_dpth);
858 }
859
860 /* a form to put them in */
861
862 FirstArg(XtNfromHoriz, *text);
863 NextArg(XtNinternalWidth, 0);
864 NextArg(XtNinternalHeight, 0);
865 NextArg(XtNhorizDistance, 0);
866 NextArg(XtNvertDistance, 0);
867 NextArg(XtNtop, XtChainTop);
868 NextArg(XtNbottom, XtChainTop);
869 NextArg(XtNleft, XtChainRight);
870 NextArg(XtNright, XtChainRight);
871 NextArg(XtNdefaultDistance, 0);
872 NextArg(XtNborderWidth, 0);
873 NextArg(XtNbackground, bgcolor);
874 inform = XtCreateManagedWidget("spinner_frame", formWidgetClass, outform, Args, ArgCount);
875
876 /* then the up spinner */
877
878 FirstArg(XtNbitmap, spinup_bm);
879 NextArg(XtNbackground, bgcolor);
880 NextArg(XtNborderWidth, 0);
881 NextArg(XtNinternalWidth, 0);
882 NextArg(XtNinternalHeight, 0);
883 NextArg(XtNhorizDistance, 0);
884 NextArg(XtNvertDistance, 0);
885 NextArg(XtNtop, XtChainBottom);
886 NextArg(XtNbottom, XtRubber);
887 NextArg(XtNdefaultDistance, 0);
888 spinup = XtCreateManagedWidget("spinup", commandWidgetClass, inform, Args, ArgCount);
889 XtAddCallback(spinup, XtNcallback,
890 (XtCallbackProc) (type==I_IVAL? inc_int_spinner: inc_flt_spinner),
891 (XtPointer) spinstruct);
892 /* add event to start timer when user presses spinner */
893 /* if he keeps pressing, it will count automatically */
894 XtAddEventHandler(spinup, ButtonPressMask, False,
895 (XtEventHandler) start_spin_timer, (XtPointer) NULL);
896 /* add any user validation callback */
897 if (callback) {
898 XtAddCallback(spinup, XtNcallback, callback, (XtPointer) spinstruct);
899 }
900
901 /* finally the down spinner */
902
903 FirstArg(XtNbitmap, spindown_bm);
904 NextArg(XtNbackground, bgcolor);
905 NextArg(XtNborderWidth, 0);
906 NextArg(XtNinternalWidth, 0);
907 NextArg(XtNinternalHeight, 0);
908 NextArg(XtNfromVert, spinup);
909 NextArg(XtNhorizDistance, 0);
910 NextArg(XtNvertDistance, 0);
911 NextArg(XtNtop, XtRubber);
912 NextArg(XtNbottom, XtChainBottom);
913 NextArg(XtNdefaultDistance, 0);
914 spindown = XtCreateManagedWidget("spindown", commandWidgetClass, inform, Args, ArgCount);
915 XtAddCallback(spindown, XtNcallback,
916 (XtCallbackProc) (type==I_IVAL? dec_int_spinner: dec_flt_spinner),
917 (XtPointer) spinstruct);
918 /* add event to start timer when user presses spinner */
919 /* if he keeps pressing, it will count automatically */
920 XtAddEventHandler(spindown, ButtonPressMask, False,
921 (XtEventHandler) start_spin_timer, (XtPointer) NULL);
922 /* add any user validation callback */
923 if (callback) {
924 XtAddCallback(spindown, XtNcallback, callback, (XtPointer) spinstruct);
925 }
926 return outform;
927 }
928
929 /* validate the integer spinner as user types */
930
931 void
validate_int(Widget w,XtPointer info,XtPointer dum)932 validate_int(Widget w, XtPointer info, XtPointer dum)
933 {
934 DeclareArgs(4);
935 spin_struct *spins = (spin_struct*) info;
936 char buf[200];
937 int val, i, modified = 0;
938 XawTextPosition pos;
939
940 /* save cursor position */
941 FirstArg(XtNinsertPosition, &pos);
942 GetValues(spins->widget);
943
944 snprintf(buf, sizeof(buf), "%s", panel_get_value(spins->widget));
945
946 for (i=0; i<strlen(buf); )
947 /* delete any non-digits (including leading "-" when min >= 0 */
948 if ((spins->min >= 0.0 && buf[i] == '-') || ((buf[i] < '0' || buf[i] > '9') && buf[i] != '-') ||
949 (i != 0 && buf[i] == '-')) {
950 memmove(&buf[i], &buf[i+1], strlen(&buf[i]));
951 /* adjust cursor for char we just removed */
952 pos--;
953 modified = 1;
954 } else {
955 i++;
956 }
957
958 if (strlen(buf) > 0 && !(strlen(buf)==1 && buf[0] == '-')) {
959 val = atoi(buf);
960 /* only check max. If min is, say 3 and user wants to type 10, the 1 is too small */
961 if (val > (int) spins->max) {
962 val = (int) spins->max;
963 sprintf(buf,"%d", val);
964 modified = 1;
965 }
966 }
967
968 if (modified) {
969 panel_set_value(spins->widget, buf);
970
971 /* put cursor back */
972 if (pos < strlen(buf)) {
973 FirstArg(XtNinsertPosition, (pos+1));
974 SetValues(spins->widget);
975 }
976 }
977 }
978
979 /* handle the wheelmouse wheel */
980
981 void
spinner_up_down(Widget w,XButtonEvent * ev,String * params,Cardinal * num_params)982 spinner_up_down(Widget w, XButtonEvent *ev, String *params, Cardinal *num_params)
983 {
984 w = XtParent(w);
985 if (params[0][0] == '+') w = XtNameToWidget(w, "*spinup");
986 else w = XtNameToWidget(w, "*spindown");
987 if (w == None) {
988 fprintf(stderr, "spinner_up_down() is called for wrong widget\n");
989 } else {
990 ev->window = XtWindow(w);
991 XSendEvent(ev->display, ev->window, TRUE, ButtonPressMask, (XEvent *)ev);
992 }
993 }
994
995
996 /* if the file message window is up add it to the grab */
997 /* in this way a user may dismiss the file_msg panel if another panel is up */
998
file_msg_add_grab(void)999 void file_msg_add_grab(void)
1000 {
1001 if (file_msg_popup)
1002 XtAddGrab(file_msg_popup, False, False);
1003 }
1004
1005 /* get the pointer relative to the window it is in */
1006
1007 void
get_pointer_win_xy(int * xposn,int * yposn)1008 get_pointer_win_xy(int *xposn, int *yposn)
1009 {
1010 Window win;
1011 int cx, cy;
1012
1013 get_pointer_root_xy(&cx, &cy);
1014 XTranslateCoordinates(tool_d, XDefaultRootWindow(tool_d), main_canvas,
1015 cx, cy, xposn, yposn, &win);
1016 }
1017
1018 /* get the pointer relative to the root */
1019
1020 void
get_pointer_root_xy(int * xposn,int * yposn)1021 get_pointer_root_xy(int *xposn, int *yposn)
1022 {
1023 Window rw, cw;
1024 int cx, cy;
1025 unsigned int mask;
1026
1027 XQueryPointer(tool_d, XtWindow(tool),
1028 &rw, &cw, xposn, yposn, &cx, &cy, &mask);
1029 }
1030
1031 /* give error message if action_on is true. This means we are trying
1032 to switch modes in the middle of some drawing/editing operation */
1033
1034 Boolean
check_action_on(void)1035 check_action_on(void)
1036 {
1037 /* zooming is ok */
1038 if (action_on && cur_mode != F_ZOOM) {
1039 if (cur_mode == F_TEXT)
1040 finish_text_input(0,0,0);/* finish up any text input */
1041 else {
1042 if (cur_mode == F_PLACE_LIB_OBJ)
1043 cancel_place_lib_obj(0, 0, 0);
1044 else {
1045 put_msg("Finish (or cancel) the current operation before changing modes");
1046 beep();
1047 return True;
1048 }
1049 }
1050 }
1051 return False;
1052 }
1053
1054 /* process any (single) outstanding Xt event to allow things like button pushes */
1055
process_pending(void)1056 void process_pending(void)
1057 {
1058 while (XtAppPending(tool_app))
1059 XtAppProcessEvent(tool_app, XtIMAll);
1060 app_flush();
1061 }
1062
1063 Boolean user_colors_saved = False;
1064 XColor saved_user_colors[MAX_USR_COLS];
1065 Boolean saved_userFree[MAX_USR_COLS];
1066 int saved_user_num;
1067
1068 Boolean nuser_colors_saved = False;
1069 XColor saved_nuser_colors[MAX_USR_COLS];
1070 Boolean saved_nuserFree[MAX_USR_COLS];
1071 int saved_nuser_num;
1072
1073 /* save user colors into temp vars */
1074
save_user_colors(void)1075 void save_user_colors(void)
1076 {
1077 int i;
1078
1079 if (appres.DEBUG)
1080 fprintf(stderr,"** Saving user colors. Before: user_colors_saved = %d\n",
1081 user_colors_saved);
1082
1083 user_colors_saved = True;
1084
1085 /* first save the current colors because del_color_cell destroys them */
1086 for (i=0; i<num_usr_cols; i++)
1087 saved_user_colors[i] = user_colors[i];
1088 /* and save Free entries */
1089 for (i=0; i<num_usr_cols; i++)
1090 saved_userFree[i] = colorFree[i];
1091 /* now free any previously defined user colors */
1092 for (i=0; i<num_usr_cols; i++) {
1093 del_color_cell(i); /* remove widget and colormap entry */
1094 }
1095 saved_user_num = num_usr_cols;
1096 }
1097
1098 /* save n_user colors into temp vars */
1099
save_nuser_colors(void)1100 void save_nuser_colors(void)
1101 {
1102 int i;
1103
1104 if (appres.DEBUG)
1105 fprintf(stderr,"** Saving n_user colors. Before: nuser_colors_saved = %d\n",
1106 user_colors_saved);
1107
1108 nuser_colors_saved = True;
1109
1110 /* first save the current colors because del_color_cell destroys them */
1111 for (i=0; i<n_num_usr_cols; i++)
1112 saved_nuser_colors[i] = n_user_colors[i];
1113 /* and save Free entries */
1114 for (i=0; i<n_num_usr_cols; i++)
1115 saved_nuserFree[i] = n_colorFree[i];
1116 saved_nuser_num = n_num_usr_cols;
1117 }
1118
1119 /* restore user colors from temp vars */
1120
restore_user_colors(void)1121 void restore_user_colors(void)
1122 {
1123 int i,num;
1124
1125 if (!user_colors_saved)
1126 return;
1127
1128 if (appres.DEBUG)
1129 fprintf(stderr,"** Restoring user colors. Before: user_colors_saved = %d\n",
1130 user_colors_saved);
1131
1132 user_colors_saved = False;
1133
1134 /* first free any previously defined user colors */
1135 for (i=0; i<num_usr_cols; i++) {
1136 del_color_cell(i); /* remove widget and colormap entry */
1137 }
1138
1139 num_usr_cols = saved_user_num;
1140
1141 /* now restore the orig user colors */
1142 for (i=0; i<num_usr_cols; i++)
1143 user_colors[i] = saved_user_colors[i];
1144 /* and Free entries */
1145 for (i=0; i<num_usr_cols; i++)
1146 colorFree[i] = saved_userFree[i];
1147
1148 /* now try to allocate those colors */
1149 if (num_usr_cols > 0) {
1150 num = num_usr_cols;
1151 num_usr_cols = 0;
1152 /* fill the colormap and the color memories */
1153 for (i=0; i<num; i++) {
1154 if (colorFree[i]) {
1155 colorUsed[i] = False;
1156 } else {
1157 /* and add a widget and colormap entry */
1158 if (add_color_cell(USE_EXISTING_COLOR, i, user_colors[i].red/256,
1159 user_colors[i].green/256,
1160 user_colors[i].blue/256) == -1) {
1161 file_msg("Can't allocate more than %d user colors, not enough colormap entries",
1162 num_usr_cols);
1163 return;
1164 }
1165 colorUsed[i] = True;
1166 }
1167 }
1168 }
1169 }
1170
1171 /* Restore user colors from temp vars into n_user_... */
1172
restore_nuser_colors(void)1173 void restore_nuser_colors(void)
1174 {
1175 int i;
1176
1177 if (!nuser_colors_saved)
1178 return;
1179
1180 if (appres.DEBUG)
1181 fprintf(stderr,"** Restoring user colors into n_...\n");
1182
1183 nuser_colors_saved = False;
1184
1185 n_num_usr_cols = saved_nuser_num;
1186
1187 /* now restore the orig user colors */
1188 for (i=0; i<n_num_usr_cols; i++)
1189 n_user_colors[i] = saved_nuser_colors[i];
1190 /* and Free entries */
1191 for (i=0; i<n_num_usr_cols; i++)
1192 n_colorFree[i] = saved_nuserFree[i];
1193 }
1194
1195 /* create some global bitmaps like menu arrows, checkmarks, etc. */
1196
create_bitmaps(void)1197 void create_bitmaps(void)
1198 {
1199 int i;
1200
1201 /* make a down-arrow for any pull-down menu buttons */
1202 menu_arrow = XCreateBitmapFromData(tool_d, tool_w,
1203 (char *) menu_arrow_bits, menu_arrow_width, menu_arrow_height);
1204 /* make a right-arrow for any cascade menu entries */
1205 menu_cascade_arrow = XCreateBitmapFromData(tool_d, tool_w,
1206 (char *) menu_cascade_arrow_bits,
1207 menu_cascade_arrow_width, menu_cascade_arrow_height);
1208 /* make pixmap for red checkmark */
1209 check_pm = XCreatePixmapFromBitmapData(tool_d, tool_w,
1210 (char *) check_bits, check_width, check_height,
1211 colors[RED], colors[WHITE], tool_dpth);
1212 /* and make one same size but all white */
1213 null_check_pm = XCreatePixmapFromBitmapData(tool_d, tool_w,
1214 (char *) check_bits, check_width, check_height,
1215 colors[WHITE], colors[WHITE], tool_dpth);
1216 /* and one for a smaller checkmark */
1217 sm_check_pm = XCreatePixmapFromBitmapData(tool_d, tool_w,
1218 (char *) sm_check_bits, sm_check_width, sm_check_height,
1219 colors[RED], colors[WHITE], tool_dpth);
1220 /* and make one same size but all white */
1221 sm_null_check_pm = XCreatePixmapFromBitmapData(tool_d, tool_w,
1222 (char *) sm_check_bits, sm_check_width, sm_check_height,
1223 colors[WHITE], colors[WHITE], tool_dpth);
1224 /* create two bitmaps to show on/off state */
1225 balloons_on_bitmap = XCreateBitmapFromData(tool_d, tool_w,
1226 (char *) balloons_on_bits,
1227 balloons_on_width, balloons_on_height);
1228 balloons_off_bitmap = XCreateBitmapFromData(tool_d, tool_w,
1229 (char *) balloons_off_bits,
1230 balloons_off_width, balloons_off_height);
1231 /* create the 1-plane bitmaps of the arrow images */
1232 /* these will go in the "left bitmap" part of the menu */
1233 /* they are used in e_edit.c and w_indpanel.c */
1234 for (i = -1; i < NUM_ARROW_TYPES-1; i++) {
1235 arrow_pixmaps[i+1] = XCreateBitmapFromData(tool_d,canvas_win,
1236 (i==-1? (char*) no_arrow_bits: (char*) arrowtype_choices[i].icon->bits),
1237 32, 32);
1238 }
1239 diamond_pixmap = XCreateBitmapFromData(tool_d, canvas_win,
1240 (char*) diamond_bits, diamond_width, diamond_height);
1241 if (linestyle_pixmaps[0] == 0) {
1242 for (i=0; i<NUM_LINESTYLE_TYPES; i++)
1243 linestyle_pixmaps[i] = XCreateBitmapFromData(tool_d,canvas_win,
1244 (char*) linestyle_choices[i].icon->bits,
1245 linestyle_choices[i].icon->width, linestyle_choices[i].icon->height);
1246 }
1247
1248 /* create the bitmaps that look like mouse buttons pressed */
1249 mouse_l = XCreateBitmapFromData(tool_d, tool_w,
1250 (char *) mouse_l_bits, mouse_l_width, mouse_l_height);
1251 mouse_r = XCreateBitmapFromData(tool_d, tool_w,
1252 (char *) mouse_r_bits, mouse_r_width, mouse_r_height);
1253 }
1254
1255 /* put a string into an ASCII text widget */
1256
1257 void
panel_set_value(Widget widg,char * val)1258 panel_set_value(Widget widg, char *val)
1259 {
1260 FirstArg(XtNstring, val);
1261 SetValues(widg);
1262 /* this must be done separately from setting the string */
1263 FirstArg(XtNinsertPosition, strlen(val));
1264 SetValues(widg);
1265 }
1266
1267 /* get a string from an ASCII text widget */
1268
1269 char *
panel_get_value(Widget widg)1270 panel_get_value(Widget widg)
1271 {
1272 char *val;
1273
1274 FirstArg(XtNstring, &val);
1275 GetValues(widg);
1276 return val;
1277 }
1278
1279 /* put an int into an ASCII text widget */
1280
1281 void
panel_set_int(Widget widg,int intval)1282 panel_set_int(Widget widg, int intval)
1283 {
1284 char buf[80];
1285 sprintf(buf, "%d", intval);
1286 panel_set_value(widg, buf);
1287 }
1288
1289 /* put a float into an ASCII text widget */
1290
1291 void
panel_set_float(Widget widg,float floatval,char * format)1292 panel_set_float(Widget widg, float floatval, char *format)
1293 {
1294 char buf[80];
1295 sprintf(buf, format, floatval);
1296 panel_set_value(widg, buf);
1297 }
1298
1299 /* create a checkbutton with a labelled area to the right */
1300
1301 Widget
CreateCheckbutton(char * label,char * widget_name,Widget parent,Widget below,Widget beside,Boolean manage,Boolean large,Boolean * value,XtCallbackProc user_callback,Widget * togwidg)1302 CreateCheckbutton(char *label, char *widget_name, Widget parent, Widget below, Widget beside, Boolean manage, Boolean large, Boolean *value, XtCallbackProc user_callback, Widget *togwidg)
1303 {
1304 DeclareArgs(20);
1305 Widget form, toggle, labelw;
1306 unsigned int check_ht, udum;
1307 int idum;
1308 Window root;
1309
1310 FirstArg(XtNdefaultDistance, 1);
1311 NextArg(XtNresizable, True);
1312 if (below != NULL)
1313 NextArg(XtNfromVert, below);
1314 if (beside != NULL)
1315 NextArg(XtNfromHoriz, beside);
1316 NextArg(XtNtop, XtChainTop);
1317 NextArg(XtNbottom, XtChainTop);
1318 NextArg(XtNleft, XtChainLeft);
1319 NextArg(XtNright, XtChainLeft);
1320 NextArg(XtNborderWidth, 0);
1321 form = XtCreateWidget(widget_name, formWidgetClass, parent, Args, ArgCount);
1322
1323 FirstArg(XtNradioData, 1);
1324 if (*value) {
1325 if (large) {
1326 NextArg(XtNbitmap, check_pm);
1327 } else {
1328 NextArg(XtNbitmap, sm_check_pm);
1329 }
1330 } else {
1331 if (large) {
1332 NextArg(XtNbitmap, null_check_pm);
1333 } else {
1334 NextArg(XtNbitmap, sm_null_check_pm);
1335 }
1336 }
1337 NextArg(XtNinternalWidth, 1);
1338 NextArg(XtNinternalHeight, 1);
1339 NextArg(XtNleft, XtChainLeft);
1340 NextArg(XtNright, XtChainLeft);
1341 NextArg(XtNtop, XtChainTop);
1342 NextArg(XtNbottom, XtChainTop);
1343 NextArg(XtNleft, XtChainLeft);
1344 NextArg(XtNright, XtChainLeft);
1345 toggle = XtCreateManagedWidget("toggle", toggleWidgetClass,
1346 form, Args, ArgCount);
1347 /* user wants widget ID */
1348 if (togwidg)
1349 *togwidg = toggle;
1350 XtAddCallback(toggle, XtNcallback, (XtCallbackProc) toggle_checkbutton,
1351 (XtPointer) value);
1352 if (user_callback)
1353 XtAddCallback(toggle, XtNcallback, (XtCallbackProc) user_callback,
1354 (XtPointer) value);
1355
1356 /* get the height of the checkmark pixmap */
1357 (void) XGetGeometry(tool_d, (large?check_pm:sm_check_pm), &root,
1358 &idum, &idum, &udum, &check_ht, &udum, &udum);
1359
1360 FirstArg(XtNlabel, label);
1361 NextArg(XtNheight, check_ht+4); /* make label as tall as the check mark */
1362 NextArg(XtNjustify, XtJustifyLeft);
1363 NextArg(XtNborderWidth, 0);
1364 NextArg(XtNfromHoriz, toggle);
1365 NextArg(XtNtop, XtChainTop);
1366 NextArg(XtNbottom, XtChainTop);
1367 NextArg(XtNleft, XtChainLeft);
1368 NextArg(XtNright, XtChainLeft);
1369 /* for small checkmarks, leave less room around label */
1370 if (!large) {
1371 NextArg(XtNinternalWidth, 2);
1372 NextArg(XtNinternalHeight, 1);
1373 }
1374 labelw = XtCreateManagedWidget("label", labelWidgetClass,
1375 form, Args, ArgCount);
1376 if (manage)
1377 XtManageChild(form);
1378 return form;
1379 }
1380
1381 void /* XtCallbackProc */
toggle_checkbutton(Widget w,XtPointer data,XtPointer garbage)1382 toggle_checkbutton(Widget w, XtPointer data, XtPointer garbage)
1383 {
1384 DeclareArgs(5);
1385 Pixmap pm;
1386 Boolean *what = (Boolean *) data;
1387 Boolean large;
1388
1389 *what = !*what;
1390 /* first find out what size pixmap we are using */
1391 FirstArg(XtNbitmap, &pm);
1392 GetValues(w);
1393
1394 large = False;
1395 if (pm == check_pm || pm == null_check_pm)
1396 large = True;
1397
1398 if (*what) {
1399 if (large) {
1400 FirstArg(XtNbitmap, check_pm);
1401 } else {
1402 FirstArg(XtNbitmap, sm_check_pm);
1403 }
1404 /* make button depressed */
1405 NextArg(XtNstate, False);
1406 } else {
1407 if (large) {
1408 FirstArg(XtNbitmap, null_check_pm);
1409 } else {
1410 FirstArg(XtNbitmap, sm_null_check_pm);
1411 }
1412 /* make button raised */
1413 NextArg(XtNstate, True);
1414 }
1415 SetValues(w);
1416
1417 return;
1418 }
1419
1420 /* assemble main window title bar with xfig title and (base) file name */
1421
1422 void
update_wm_title(char * name)1423 update_wm_title(char *name)
1424 {
1425 char wm_title[200];
1426 DeclareArgs(2);
1427
1428 if (strlen(name)==0) sprintf(wm_title, "%s - No file", tool_name);
1429 else sprintf(wm_title, "Xfig - %s", xf_basename(name));
1430 FirstArg(XtNtitle, wm_title);
1431 SetValues(tool);
1432 }
1433
1434 void
check_for_resize(Widget tool,XButtonEvent * event,String * params,Cardinal * nparams)1435 check_for_resize(Widget tool, XButtonEvent *event, String *params, Cardinal *nparams)
1436 {
1437 int dx, dy;
1438 XConfigureEvent *xc = (XConfigureEvent *) event;
1439
1440 if (xc->width == TOOL_WD && xc->height == TOOL_HT)
1441 return; /* no size change */
1442 dx = xc->width - TOOL_WD;
1443 dy = xc->height - TOOL_HT;
1444 TOOL_WD = xc->width;
1445 TOOL_HT = xc->height;
1446 resize_all(CANVAS_WD + dx, CANVAS_HT + dy);
1447 #ifdef I18N
1448 if (xim_ic != NULL)
1449 xim_set_ic_geometry(xim_ic, CANVAS_WD, CANVAS_HT);
1450 #endif /* I18N */
1451 }
1452
1453 /* resize whole shebang given new canvas size (width,height) */
1454
resize_all(int width,int height)1455 void resize_all(int width, int height)
1456 {
1457 Dimension b, b2, b3, w, h, h2;
1458 int min_sw_per_row;
1459 DeclareArgs(10);
1460
1461 setup_sizes(width, height);
1462
1463 FirstArg(XtNheight, &h);
1464 NextArg(XtNborderWidth, &b);
1465 GetValues(mode_panel);
1466 FirstArg(XtNheight, &h2);
1467 NextArg(XtNborderWidth, &b2);
1468 GetValues(topruler_sw);
1469 FirstArg(XtNborderWidth, &b3);
1470 GetValues(canvas_sw);
1471 h = h+2*b;
1472 h2 = CANVAS_HT+2*b3+h2+2*b2 + 2;
1473 /* if mode panel is taller than the canvas + topruler height, increase
1474 but_per_row and decrease canvas width */
1475 /* but don't change it if user explicitely used -but_per_row */
1476 if (appres.but_per_row == 0) {
1477 if (h > h2) {
1478 min_sw_per_row = (mode_sw_ht + INTERNAL_BW*2) * (NUM_MODE_SW+2) / h2 + 1;
1479 if (min_sw_per_row != SW_PER_ROW)
1480 width -= (min_sw_per_row - SW_PER_ROW)*(mode_sw_wd+2*INTERNAL_BW);
1481 SW_PER_ROW = max2(min_sw_per_row, SW_PER_ROW);
1482 setup_sizes(width, height);
1483 XtUnmanageChild(mode_panel);
1484 FirstArg(XtNwidth, MODEPANEL_WD);
1485 NextArg(XtNresizable, True);
1486 SetValues(mode_panel);
1487 /* now resize width of labels "Drawing" and "Editing" */
1488 FirstArg(XtNwidth, mode_sw_wd * SW_PER_ROW + INTERNAL_BW * (SW_PER_ROW - 1));
1489 SetValues(d_label);
1490 SetValues(e_label);
1491 FirstArg(XtNwidth, MODEPANEL_WD);
1492 NextArg(XtNresizable, False);
1493 SetValues(mode_panel);
1494 XtManageChild(mode_panel);
1495 } else {
1496 /* check if we can decrease number of buttons per row (user made tool taller) */
1497 /* do this by checking the height of the "Drawing" label */
1498 FirstArg(XtNheight, &h);
1499 GetValues(d_label);
1500 min_sw_per_row = (mode_sw_ht + INTERNAL_BW*2) * (NUM_MODE_SW+2) / h2 + 1;
1501 if (min_sw_per_row < SW_PER_ROW) {
1502 width -= (min_sw_per_row - SW_PER_ROW)*(mode_sw_wd+2*INTERNAL_BW);
1503 SW_PER_ROW = min_sw_per_row;
1504 setup_sizes(width, height);
1505 XtUnmanageChild(mode_panel);
1506 FirstArg(XtNwidth, MODEPANEL_WD);
1507 NextArg(XtNresizable, True);
1508 SetValues(mode_panel);
1509 /* now resize width of labels "Drawing" and "Editing" */
1510 FirstArg(XtNwidth, mode_sw_wd * SW_PER_ROW + INTERNAL_BW * (SW_PER_ROW - 1));
1511 SetValues(d_label);
1512 SetValues(e_label);
1513 FirstArg(XtNwidth, MODEPANEL_WD);
1514 NextArg(XtNresizable, False);
1515 SetValues(mode_panel);
1516 XtManageChild(mode_panel);
1517 }
1518 } /* if (h > h2) */
1519 } /* appres.but_per_row == 0 */
1520
1521 XawFormDoLayout(tool_form, False);
1522 ignore_exp_cnt++; /* canvas is resized twice - redraw only once */
1523
1524 /* first redo the top panels */
1525 FirstArg(XtNborderWidth, &b);
1526 GetValues(name_panel);
1527 XtResizeWidget(name_panel, NAMEPANEL_WD, CMD_BUT_HT, b);
1528 GetValues(msg_panel);
1529 XtUnmanageChild(mousefun); /* unmanage the mouse function... */
1530 XtUnmanageChild(layer_form);/* and the layer form */
1531 XtResizeWidget(msg_panel, MSGPANEL_WD, MSGPANEL_HT, b);
1532 XtManageChild(mousefun); /* so that they shift with msg_panel */
1533
1534 /* now redo the center area */
1535 XtUnmanageChild(mode_panel);
1536 FirstArg(XtNheight, (MODEPANEL_SPACE + 1) / 2);
1537 SetValues(d_label);
1538 FirstArg(XtNheight, (MODEPANEL_SPACE) / 2);
1539 SetValues(e_label);
1540 XtManageChild(mode_panel); /* so that it adjusts properly */
1541
1542 FirstArg(XtNborderWidth, &b);
1543 GetValues(canvas_sw);
1544 XtResizeWidget(canvas_sw, CANVAS_WD, CANVAS_HT, b);
1545 GetValues(topruler_sw);
1546 XtResizeWidget(topruler_sw, TOPRULER_WD, TOPRULER_HT, b);
1547 resize_topruler();
1548 GetValues(sideruler_sw);
1549 XtResizeWidget(sideruler_sw, SIDERULER_WD, SIDERULER_HT, b);
1550 resize_sideruler();
1551 XtUnmanageChild(sideruler_sw);
1552 XtManageChild(sideruler_sw);/* so that it shifts with canvas */
1553 XtUnmanageChild(unitbox_sw);
1554 XtManageChild(unitbox_sw); /* so that it shifts with canvas */
1555
1556 /* and the bottom */
1557 XtUnmanageChild(ind_panel);
1558 FirstArg(XtNborderWidth, &b);
1559 NextArg(XtNheight, &h);
1560 GetValues(ind_panel);
1561 w = INDPANEL_WD;
1562 /* account for update control */
1563 if (XtIsManaged(upd_ctrl))
1564 w -= UPD_CTRL_WD-2*INTERNAL_BW;
1565 XtResizeWidget(ind_panel, w, h, b);
1566 XtManageChild(ind_panel);
1567 XtUnmanageChild(ind_box);
1568 XtManageChild(ind_box);
1569 XtManageChild(layer_form);
1570
1571 XawFormDoLayout(tool_form, True);
1572 }
1573
1574 void
check_colors(void)1575 check_colors(void)
1576 {
1577 int i;
1578 XColor dum,color;
1579
1580 /* no need to allocate black and white specially */
1581 colors[BLACK] = black_color.pixel;
1582 colors[WHITE] = white_color.pixel;
1583 /* fill the colors array with black (except for white) */
1584 for (i=0; i<NUM_STD_COLS; i++)
1585 if (i != BLACK && i != WHITE)
1586 colors[i] = colors[BLACK];
1587
1588 /* initialize user color cells */
1589 for (i=0; i<MAX_USR_COLS; i++) {
1590 colorFree[i] = True;
1591 n_colorFree[i] = True;
1592 num_usr_cols = 0;
1593 }
1594
1595 /* if monochrome resource is set, do not even check for colors */
1596 if (!all_colors_available || appres.monochrome) {
1597 return;
1598 }
1599
1600 for (i=0; i<NUM_STD_COLS; i++) {
1601 /* try to allocate another named color */
1602 /* first try by #xxxxx form if exists, then by name from rgb.txt file */
1603 if (!xallncol(colorNames[i+1].rgb,&color,&dum)) {
1604 /* can't allocate it, switch colormaps try again */
1605 if (!switch_colormap() ||
1606 (!xallncol(colorNames[i+1].rgb,&color,&dum))) {
1607 fprintf(stderr, "Not enough colormap entries available for basic colors\n");
1608 fprintf(stderr, "using monochrome mode.\n");
1609 all_colors_available = False;
1610 return;
1611 }
1612 }
1613 /* put the colorcell number in the color array */
1614 colors[i] = color.pixel;
1615 }
1616
1617 /* get two grays for insensitive spinners */
1618 if (tool_cells == 2 || appres.monochrome) {
1619 /* use black to gray out an insensitive spinner */
1620 dark_gray_color = colors[BLACK];
1621 med_gray_color = colors[BLACK];
1622 lt_gray_color = colors[BLACK];
1623 /* color of page border */
1624 pageborder_color = colors[BLACK];
1625 } else {
1626 XColor x_color;
1627 /* get a dark gray for making certain spinners insensitive */
1628 XParseColor(tool_d, tool_cm, "gray65", &x_color);
1629 if (XAllocColor(tool_d, tool_cm, &x_color)) {
1630 dark_gray_color = x_color.pixel;
1631 } else {
1632 dark_gray_color = colors[WHITE];
1633 }
1634 /* get a medium one too */
1635 XParseColor(tool_d, tool_cm, "gray80", &x_color);
1636 if (XAllocColor(tool_d, tool_cm, &x_color)) {
1637 med_gray_color = x_color.pixel;
1638 } else {
1639 med_gray_color = colors[WHITE];
1640 }
1641 /* get a lighter one too */
1642 XParseColor(tool_d, tool_cm, "gray90", &x_color);
1643 if (XAllocColor(tool_d, tool_cm, &x_color)) {
1644 lt_gray_color = x_color.pixel;
1645 } else {
1646 lt_gray_color = colors[WHITE];
1647 }
1648
1649 /* get page border color */
1650 XParseColor(tool_d, tool_cm, appres.pageborder, &x_color);
1651 if (XAllocColor(tool_d, tool_cm, &x_color)) {
1652 pageborder_color = x_color.pixel;
1653 } else {
1654 pageborder_color = colors[BLACK];
1655 }
1656 /* get axis lines color */
1657 XParseColor(tool_d, tool_cm, appres.axislines, &x_color);
1658 if (XAllocColor(tool_d, tool_cm, &x_color)) {
1659 axis_lines_color = x_color.pixel;
1660 } else {
1661 axis_lines_color = colors[BLACK];
1662 }
1663 }
1664
1665 }
1666
1667 /* useful when using ups */
XSyncOn(void)1668 void XSyncOn(void)
1669 {
1670 XSynchronize(tool_d, True);
1671 XFlush(tool_d);
1672 }
1673
XSyncOff(void)1674 void XSyncOff(void)
1675 {
1676 XSynchronize(tool_d, False);
1677 XFlush(tool_d);
1678 }
1679
1680 /*
1681 * This will parse the hexadecimal form of the named colors in the standard color
1682 * names. Some servers can't parse the hex form for XAllocNamedColor()
1683 */
1684
1685 int
xallncol(char * name,XColor * color,XColor * exact)1686 xallncol(char *name, XColor *color, XColor *exact)
1687 {
1688 unsigned short r,g,b;
1689 char nam[30];
1690
1691 if (*name != '#')
1692 return XAllocNamedColor(tool_d,tool_cm,name,color,exact);
1693
1694 /* gcc doesn't allow writing on constant strings without the -fwritable_strings
1695 option, and apparently some versions of sscanf need to write a char back */
1696 strcpy(nam,name);
1697 if (sscanf(nam,"#%2hx%2hx%2hx",&r,&g,&b) != 3 || nam[7] != '\0') {
1698 fprintf(stderr,
1699 "Malformed color specification %s in resources.c must be 6 hex digits",nam);
1700 exit(1);
1701 }
1702
1703 color->red = r<<8;
1704 color->green = g<<8;
1705 color->blue = b<<8;
1706 color->flags = DoRed|DoGreen|DoBlue;
1707 *exact = *color;
1708 return XAllocColor(tool_d,tool_cm,color);
1709 }
1710
1711 Widget
make_grid_options(Widget parent,Widget put_below,Widget put_beside,char * minor_grid_value,char * major_grid_value,Widget * grid_minor_menu_button,Widget * grid_major_menu_button,Widget * grid_minor_menu,Widget * grid_major_menu,Widget * print_grid_minor_text,Widget * print_grid_major_text,Widget * grid_unit_label,void (* grid_major_select)(),void (* grid_minor_select)())1712 make_grid_options(Widget parent, Widget put_below, Widget put_beside, char *minor_grid_value, char *major_grid_value,
1713 Widget *grid_minor_menu_button, Widget *grid_major_menu_button, Widget *grid_minor_menu,
1714 Widget *grid_major_menu, Widget *print_grid_minor_text, Widget *print_grid_major_text,
1715 Widget *grid_unit_label, void (*grid_major_select) (/* ??? */), void (*grid_minor_select) (/* ??? */))
1716 {
1717 Widget below, beside;
1718
1719 if (appres.INCHES) {
1720 if (cur_gridunit == FRACT_UNIT) {
1721 grid_choices = grid_inch_choices;
1722 n_grid_choices = sizeof(grid_inch_choices) / sizeof(char *);
1723 } else {
1724 grid_choices = grid_tenth_inch_choices;
1725 n_grid_choices = sizeof(grid_tenth_inch_choices) / sizeof(char *);
1726 }
1727 } else {
1728 grid_choices = grid_cm_choices;
1729 n_grid_choices = sizeof(grid_cm_choices) / sizeof(char *);
1730 }
1731
1732 FirstArg(XtNlabel, "Minor");
1733 NextArg(XtNfromVert, put_below);
1734 NextArg(XtNfromHoriz, put_beside);
1735 NextArg(XtNhorizDistance, 4);
1736 NextArg(XtNborderWidth, INTERNAL_BW);
1737 NextArg(XtNleftBitmap, menu_arrow); /* use menu arrow for pull-down */
1738 NextArg(XtNtop, XtChainTop);
1739 NextArg(XtNbottom, XtChainTop);
1740 NextArg(XtNleft, XtChainLeft);
1741 NextArg(XtNright, XtChainLeft);
1742 beside = *grid_minor_menu_button = XtCreateManagedWidget("minor_grid_menu_button",
1743 menuButtonWidgetClass,
1744 parent, Args, ArgCount);
1745 *grid_minor_menu = make_pulldown_menu(grid_choices, n_grid_choices, -1, NULL,
1746 *grid_minor_menu_button, grid_minor_select);
1747
1748 /* text widget for user to type in minor grid spacing */
1749 FirstArg(XtNstring, minor_grid_value);
1750 NextArg(XtNwidth, 50);
1751 NextArg(XtNleftMargin, 4);
1752 NextArg(XtNfromVert, put_below);
1753 NextArg(XtNfromHoriz, beside);
1754 NextArg(XtNhorizDistance, 1);
1755 NextArg(XtNeditType, XawtextEdit);
1756 NextArg(XtNinsertPosition, 0);
1757 NextArg(XtNborderWidth, INTERNAL_BW);
1758 NextArg(XtNtop, XtChainTop);
1759 NextArg(XtNbottom, XtChainTop);
1760 NextArg(XtNleft, XtChainLeft);
1761 NextArg(XtNright, XtChainLeft);
1762 *print_grid_minor_text = XtCreateManagedWidget("minor_grid_text",
1763 asciiTextWidgetClass,
1764 parent, Args, ArgCount);
1765 XtOverrideTranslations(*print_grid_minor_text,
1766 XtParseTranslationTable(text_translations));
1767
1768 FirstArg(XtNlabel, "Major");
1769 NextArg(XtNfromVert, put_below);
1770 NextArg(XtNfromHoriz, *print_grid_minor_text);
1771 NextArg(XtNhorizDistance, 8);
1772 NextArg(XtNborderWidth, INTERNAL_BW);
1773 NextArg(XtNleftBitmap, menu_arrow); /* use menu arrow for pull-down */
1774 NextArg(XtNtop, XtChainTop);
1775 NextArg(XtNbottom, XtChainTop);
1776 NextArg(XtNleft, XtChainLeft);
1777 NextArg(XtNright, XtChainLeft);
1778 below = *grid_major_menu_button = XtCreateManagedWidget("major_grid_menu_button",
1779 menuButtonWidgetClass,
1780 parent, Args, ArgCount);
1781 *grid_major_menu = make_pulldown_menu(grid_choices, n_grid_choices, -1, NULL,
1782 *grid_major_menu_button, grid_major_select);
1783
1784 /* text widget for user to type in major grid spacing */
1785
1786 FirstArg(XtNstring, major_grid_value);
1787 NextArg(XtNwidth, 50);
1788 NextArg(XtNleftMargin, 4);
1789 NextArg(XtNfromVert, put_below);
1790 NextArg(XtNfromHoriz, below);
1791 NextArg(XtNhorizDistance, 1);
1792 NextArg(XtNeditType, XawtextEdit);
1793 NextArg(XtNinsertPosition, 0);
1794 NextArg(XtNborderWidth, INTERNAL_BW);
1795 NextArg(XtNtop, XtChainTop);
1796 NextArg(XtNbottom, XtChainTop);
1797 NextArg(XtNleft, XtChainLeft);
1798 NextArg(XtNright, XtChainLeft);
1799 *print_grid_major_text = XtCreateManagedWidget("major_grid_text",
1800 asciiTextWidgetClass,
1801 parent, Args, ArgCount);
1802 XtOverrideTranslations(*print_grid_major_text,
1803 XtParseTranslationTable(text_translations));
1804
1805 FirstArg(XtNlabel, appres.INCHES? "inches" : "mm");
1806 NextArg(XtNwidth, 60);
1807 NextArg(XtNfromVert, put_below);
1808 NextArg(XtNfromHoriz, *print_grid_major_text);
1809 NextArg(XtNborderWidth, 0);
1810 NextArg(XtNtop, XtChainTop);
1811 NextArg(XtNbottom, XtChainTop);
1812 NextArg(XtNleft, XtChainLeft);
1813 NextArg(XtNright, XtChainLeft);
1814 *grid_unit_label = XtCreateManagedWidget("grid_unit_label", labelWidgetClass,
1815 parent, Args, ArgCount);
1816
1817 return *grid_minor_menu_button;
1818 }
1819
1820 /* force the the grid choice menu to be consistent with current IP/metric setting */
1821 /* do this in both the print and export panels */
1822
1823 void
reset_grid_menus(Boolean inches)1824 reset_grid_menus(Boolean inches)
1825 {
1826 float convert;
1827
1828 if (inches) {
1829 convert = 1.0;
1830 /* if was metric and is now inches, convert grid values */
1831 if (old_gridunit == MM_UNIT)
1832 convert = 0.03937;
1833 /* if fraction<->decimal find nearest equiv */
1834 if (print_panel) {
1835 /* convert major to metric */
1836 convert_gridstr(print_grid_major_text, convert);
1837 /* convert minor to metric */
1838 convert_gridstr(print_grid_minor_text, convert);
1839 }
1840 if (export_panel) {
1841 /* convert major to metric */
1842 convert_gridstr(export_grid_major_text, convert);
1843 /* convert minor to metric */
1844 convert_gridstr(export_grid_minor_text, convert);
1845 }
1846 if (cur_gridunit == FRACT_UNIT) {
1847 grid_choices = grid_inch_choices;
1848 n_grid_choices = num_grid_inch_choices;
1849 } else {
1850 grid_choices = grid_tenth_inch_choices;
1851 n_grid_choices = num_grid_tenth_inch_choices;
1852 }
1853 FirstArg(XtNlabel, "inches");
1854 if (print_panel)
1855 SetValues(print_grid_unit_label);
1856 if (export_panel)
1857 SetValues(export_grid_unit_label);
1858 } else {
1859 grid_choices = grid_cm_choices;
1860 n_grid_choices = num_grid_cm_choices;
1861 FirstArg(XtNlabel, "mm");
1862 if (print_panel)
1863 SetValues(print_grid_unit_label);
1864 if (export_panel)
1865 SetValues(export_grid_unit_label);
1866 /* if there are any fractions in the values, change them to 10mm */
1867 if (print_panel) {
1868 /* convert major to metric */
1869 convert_gridstr(print_grid_major_text, 25.4);
1870 /* convert minor to metric */
1871 convert_gridstr(print_grid_minor_text, 25.4);
1872 }
1873 if (export_panel) {
1874 /* convert major to metric */
1875 convert_gridstr(export_grid_major_text, 25.4);
1876 /* convert minor to metric */
1877 convert_gridstr(export_grid_minor_text, 25.4);
1878 }
1879 }
1880 if (old_gridunit != cur_gridunit) {
1881 if (print_panel) {
1882 XtDestroyWidget(print_grid_minor_menu);
1883 XtDestroyWidget(print_grid_major_menu);
1884 print_grid_minor_menu = make_pulldown_menu(grid_choices, n_grid_choices, -1, NULL,
1885 print_grid_minor_menu_button, print_grid_minor_select);
1886 print_grid_major_menu = make_pulldown_menu(grid_choices, n_grid_choices, -1, NULL,
1887 print_grid_major_menu_button, print_grid_major_select);
1888 }
1889 if (export_panel) {
1890 XtDestroyWidget(export_grid_minor_menu);
1891 XtDestroyWidget(export_grid_major_menu);
1892 export_grid_minor_menu = make_pulldown_menu(grid_choices,n_grid_choices,-1, NULL,
1893 export_grid_minor_menu_button,export_grid_minor_select);
1894 export_grid_major_menu = make_pulldown_menu(grid_choices,n_grid_choices,-1, NULL,
1895 export_grid_major_menu_button, export_grid_major_select);
1896 }
1897 }
1898 old_gridunit = cur_gridunit;
1899 }
1900
1901 static void
convert_gridstr(Widget widget,float mult)1902 convert_gridstr(Widget widget, float mult)
1903 {
1904 double value, numer, denom, diff;
1905 char *sval, fraction[20];
1906 double fracts[] = { 2, 4, 8, 16, 32 };
1907 double tol[] = { 0.05, 0.1, 0.2, 0.3, 0.6};
1908 #define NUM_FRACTS sizeof(fracts)/sizeof(double)
1909 int i;
1910
1911 FirstArg(XtNstring, &sval);
1912 GetValues(widget);
1913 /* don't convert anything if "none" */
1914 if (strcasecmp(sval, "none") == 0)
1915 return;
1916 if (sscanf(sval,"%lf/%lf", &numer, &denom) == 2) {
1917 value = numer/denom*mult;
1918 } else {
1919 /* not fraction, just convert to metric */
1920 value = numer * mult;
1921 }
1922 /* if user wants fractions, give him fractions */
1923 if (cur_gridunit == FRACT_UNIT) {
1924 for (i=0; i<NUM_FRACTS; i++) {
1925 numer = round(value*fracts[i]);
1926 diff = fabs(value*fracts[i] - numer);
1927 if (diff < tol[i] && numer > 0.0)
1928 break;
1929 }
1930 if (i < NUM_FRACTS) {
1931 sprintf(fraction, "%d/%d", (int) numer, (int) fracts[i]);
1932 panel_set_value(widget, fraction);
1933 return;
1934 }
1935 } else if (cur_gridunit == MM_UNIT) {
1936 /* for metric, round to nearest integer mm */
1937 value = round(value);
1938 }
1939 panel_set_float(widget, value, "%.3lf");
1940 }
1941
1942 /************************/
1943 /* Splash Screen */
1944 /************************/
1945
1946 #define SPLASH_LOGO_XOFFSET 25 /* offset from the corner of the splash to the logo */
1947 #define SPLASH_LOGO_YOFFSET 35
1948 #define SPLASH_LOGO_XTEXT 325 /* offset from the corner to version text */
1949 #define SPLASH_LOGO_YTEXT 30
1950 #define STEPSIZE 4 /* stepsize in pixel columns */
1951
1952 #define COLSTEPS 20 /* number of steps in fading splash */
1953 #define DRAW_PAUSE 1 /* pause between each scan column when drawing the verison number */
1954 #define FADE_PAUSE 50000 /* pause between each shade change in fade */
1955
1956 /****************************************************************************
1957 * Do a splash screen (actually on the canvas itself)
1958 * We draw the xfig logo followed by "3.X.X", STEPSIZE pixels at a time.
1959 * Then we fade the letters to the background color and remove the icon.
1960 ****************************************************************************/
1961
splash_screen(void)1962 void splash_screen(void)
1963 {
1964 GC splash_gc;
1965 XColor col, colbg;
1966 Boolean fade;
1967 int red_step, green_step, blue_step;
1968 Pixmap letters_pm;
1969 int splash_x, splash_y;
1970 int i, x, y, width;
1971 unsigned long plane_mask;
1972 XGCValues gcv;
1973 #ifdef USE_SPLASH
1974 Pixmap spl_bckgnd, dum;
1975 Boolean use_bitmap = False;
1976 #ifdef USE_XPM
1977 XpmAttributes spl_bckgnd_attr;
1978 #endif
1979 #endif /* USE_SPLASH */
1980
1981 /* center the splash on the canvas */
1982 splash_x = (CANVAS_WD - spl_bckgnd_ic.width)/2;
1983 splash_y = (CANVAS_HT - spl_bckgnd_ic.height)/2;
1984
1985 #ifdef USE_SPLASH
1986 /* read the background for the splash screen */
1987 #ifdef USE_XPM
1988 if (all_colors_available) {
1989 /* use the color XPM bitmap */
1990 spl_bckgnd_attr.valuemask = XpmReturnPixels;
1991 spl_bckgnd_attr.colormap = tool_cm;
1992 if (XpmCreatePixmapFromData(tool_d, tool_w,
1993 spl_bckgnd_xpm, &spl_bckgnd,
1994 &dum, &spl_bckgnd_attr) == XpmSuccess)
1995 /* use color pixmap */
1996 use_bitmap = False;
1997 else
1998 /* use mono */
1999 use_bitmap = True;
2000 }
2001 #else
2002 use_bitmap = True;
2003 #endif /* USE_XPM */
2004
2005 if (!all_colors_available || use_bitmap) {
2006 /* use the xbm bitmap */
2007 spl_bckgnd = XCreateBitmapFromData(tool_d, tool_w,
2008 (char *) spl_bckgnd_ic.bits,
2009 spl_bckgnd_ic.width, spl_bckgnd_ic.height);
2010 /* one-bit deep pixmap */
2011 use_bitmap = True;
2012 }
2013 #endif /* USE_SPLASH */
2014
2015 /* if we have a color visual, fade the letters from dark color
2016 * up to the background
2017 * we'll start the text at sort of a bluish-purple
2018 */
2019 col.flags = DoRed|DoGreen|DoBlue;
2020 col.red = 0x66<<8;
2021 col.green = 0x55<<8;
2022 col.blue = 0xaa<<8;
2023
2024 /* with a lighter background (must match color in the background pixmap) */
2025 colbg.flags = DoRed|DoGreen|DoBlue;
2026 colbg.red = 0xa7<<8;
2027 colbg.green = 0xa7<<8;
2028 colbg.blue = 0xd6<<8;
2029
2030 fade = False;
2031 if (all_colors_available) {
2032 if (tool_vclass == GrayScale || tool_vclass == PseudoColor) {
2033 /* allocate a color for the background of the text pixmap */
2034 if (XAllocColorCells(tool_d, tool_cm, 0, &plane_mask, 0,
2035 &colbg.pixel, 1)==0) {
2036 colbg = x_bg_color;
2037 } else {
2038 XStoreColor(tool_d, tool_cm, &colbg);
2039 }
2040 /* allocate a colorcell that we can change to fade the text image */
2041 if (XAllocColorCells(tool_d, tool_cm, 0, &plane_mask, 0,
2042 &col.pixel, 1)==0) {
2043 /* can't get a color, no fading */
2044 fade = False;
2045 } else {
2046 XStoreColor(tool_d, tool_cm, &col);
2047 fade = True;
2048 }
2049 } else if (tool_vclass == TrueColor) {
2050 /* for TrueColor, just allocate two colors for the text part */
2051 XAllocColor(tool_d, tool_cm, &col);
2052 XAllocColor(tool_d, tool_cm, &colbg);
2053 }
2054 } else {
2055 /* monochrome or no colors availble, draw text in fg, bg */
2056 col = x_fg_color;
2057 colbg = x_bg_color;
2058 }
2059 /* make our own gc */
2060 splash_gc = makegc(PAINT, col.pixel, colbg.pixel);
2061
2062 XSetForeground(tool_d, splash_gc, col.pixel);
2063 /* step size to go from the starting color to the background color */
2064 red_step = (x_bg_color.red-col.red)/COLSTEPS;
2065 green_step = (x_bg_color.green-col.green)/COLSTEPS;
2066 blue_step = (x_bg_color.blue-col.blue)/COLSTEPS;
2067
2068 #ifdef USE_SPLASH
2069 /* write the background on the canvas */
2070 if (use_bitmap) {
2071 /* this is the monochrome background */
2072 XCopyPlane(tool_d, spl_bckgnd, canvas_win, gccache[PAINT],
2073 0, 0, spl_bckgnd_ic.width, spl_bckgnd_ic.height,
2074 splash_x, splash_y, 1);
2075 } else {
2076 /* this is the color background */
2077 XCopyArea(tool_d, spl_bckgnd, canvas_win, splash_gc,
2078 0, 0, spl_bckgnd_ic.width, spl_bckgnd_ic.height,
2079 splash_x, splash_y);
2080 }
2081
2082 app_flush();
2083 #endif
2084
2085 /* make the 1-plane bitmap for the version letters "3.X.X" */
2086 letters_pm = XCreateBitmapFromData(tool_d, tool_w,
2087 (char *) letters_ic.bits,
2088 letters_ic.width, letters_ic.height);
2089
2090 /* now write the letters STEPSIZE pixel columns at a time */
2091 x = splash_x + SPLASH_LOGO_XTEXT;
2092 y = splash_y + SPLASH_LOGO_YTEXT;
2093 width = STEPSIZE;
2094
2095 /* clip to letters to their shape so we don't write on the background */
2096 gcv.clip_mask = letters_pm;
2097 gcv.clip_x_origin = x;
2098 gcv.clip_y_origin = y;
2099 XChangeGC(tool_d, splash_gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
2100
2101 /* write bit-by-bit */
2102 for (i=0; i<letters_ic.width; i+=width) {
2103 if (i+width > letters_ic.width)
2104 width = letters_ic.width - i;
2105 XCopyPlane(tool_d, letters_pm, canvas_win, splash_gc,
2106 i, 0, width, letters_ic.height, x+i, y, 1);
2107 app_flush();
2108 /* even though we're pausing only 1 microsecond (!), it seems to be enough,
2109 * probably because of the system call. */
2110 usleep(DRAW_PAUSE);
2111 }
2112
2113 /* now ramp it up to the background color to fade it */
2114 if (fade) {
2115 for (i=0; i<COLSTEPS-1; ++i) {
2116 XStoreColor(tool_d, tool_cm, &col);
2117 /* change the color in the colormap */
2118 XSetForeground(tool_d, splash_gc, col.pixel);
2119 app_flush();
2120 usleep(FADE_PAUSE);
2121 col.red += red_step;
2122 col.green += green_step;
2123 col.blue += blue_step;
2124 }
2125 } else {
2126 /* for fading the text in TrueColor, re-write
2127 * the pixmap in a changing color */
2128 for (i=0; i<COLSTEPS-1; ++i) {
2129 XAllocColor(tool_d, tool_cm, &col);
2130 gcv.foreground = col.pixel;
2131 XChangeGC(tool_d, splash_gc, GCForeground, &gcv);
2132 XCopyPlane(tool_d, letters_pm, canvas_win, splash_gc,
2133 0, 0, letters_ic.width, letters_ic.height, x, y, 1);
2134 app_flush();
2135 usleep(FADE_PAUSE);
2136 col.red += red_step;
2137 col.green += green_step;
2138 col.blue += blue_step;
2139 }
2140 }
2141
2142 /* free up the pixmaps */
2143 XFreePixmap(tool_d, letters_pm);
2144 #ifdef USE_SPLASH
2145 XFreePixmap(tool_d, spl_bckgnd);
2146 #endif
2147
2148 /* and the GC */
2149 XFreeGC(tool_d, splash_gc);
2150
2151 /* free up the color(s) we allocated */
2152 XFreeColors(tool_d, tool_cm, &colbg.pixel, 1, 0);
2153 if (fade)
2154 XFreeColors(tool_d, tool_cm, &col.pixel, 1, 0);
2155
2156 /* and the colors in the xpm image */
2157 #if defined(USE_XPM) && defined(USE_SPLASH)
2158 if (!use_bitmap)
2159 XFreeColors(tool_d, tool_cm,
2160 spl_bckgnd_attr.pixels, spl_bckgnd_attr.npixels, 0);
2161 #endif
2162
2163 /* finally, set flag saying splash is on the screen so it will be cleared later */
2164 splash_onscreen = True;
2165 }
2166
2167 /* clear the splash graphic if it hasn't already been cleared */
2168 /* clear_canvas() zeroes splash_onscreen */
2169
2170 void
clear_splash(void)2171 clear_splash(void)
2172 {
2173 if (splash_onscreen)
2174 clear_canvas();
2175 }
2176
2177 /*
2178 * Install wheel mouse scrolling for the scrollbar of the parent of the passed widget
2179 *
2180 * viewport
2181 * / \
2182 * widget scrollbar
2183 */
2184
2185 static char scroll_accel[] =
2186 "<Btn4Down>: StartScroll(Backward)\n\
2187 <Btn5Down>: StartScroll(Forward)\n\
2188 <BtnUp>: NotifyScroll(FullLength) EndScroll()\n";
2189
2190 static XtAccelerators scroll_acceltable = 0;
2191
2192 void
InstallScroll(Widget widget)2193 InstallScroll(Widget widget)
2194 {
2195 _installscroll(XtParent(widget), widget);
2196 }
2197
2198 /*
2199 * Install wheel mouse scrolling for the scrollbar of the parent of the parent of the passed widget
2200 *
2201 * We look to the parent of the parent for the scrollbar because we have:
2202 * viewport
2203 * / \
2204 * box scrollbar
2205 * |
2206 * widget
2207 */
2208
2209 void
InstallScrollParent(Widget widget)2210 InstallScrollParent(Widget widget)
2211 {
2212 _installscroll(XtParent(XtParent(widget)), widget);
2213 }
2214
2215 static void
_installscroll(Widget parent,Widget widget)2216 _installscroll(Widget parent, Widget widget)
2217 {
2218 Widget scroll;
2219 XtActionList action_list;
2220 int num_actions, i;
2221 Boolean found_scroll_action;
2222
2223 /* only parse the acceleration table once */
2224 if (scroll_acceltable == 0)
2225 scroll_acceltable = XtParseAcceleratorTable(scroll_accel);
2226
2227 /* install the wheel scrolling for the scrollbar of the parent onto the widget */
2228 scroll = XtNameToWidget(parent, "vertical");
2229 if (scroll) {
2230 /* first see if the scrollbar supports the StartScroll action (when Xaw
2231 * is compiled with ARROW_SCROLLBAR, it does not have this action */
2232 found_scroll_action = False;
2233 XtGetActionList(scrollbarWidgetClass, &action_list,
2234 (unsigned int *)&num_actions);
2235 for (i=0; i<num_actions; i++)
2236 if (strcasecmp(action_list[i].string, "startscroll") == 0) {
2237 found_scroll_action = True;
2238 break;
2239 }
2240 if (found_scroll_action) {
2241 XtOverrideTranslations(scroll, scroll_acceltable);
2242 FirstArg(XtNaccelerators, scroll_acceltable);
2243 SetValues(scroll);
2244 XtInstallAccelerators(widget, scroll);
2245 }
2246 }
2247 }
2248