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 
19 #include "fig.h"
20 #include "figx.h"
21 #include "resources.h"
22 #include "object.h"
23 #include "mode.h"
24 #include "f_read.h"
25 #include "w_drawprim.h"
26 #include "w_dir.h"
27 #include "w_file.h"
28 #include "w_indpanel.h"
29 #include "w_layers.h"
30 #include "w_util.h"
31 #include "w_setup.h"
32 #include "u_redraw.h"
33 #include "w_snap.h"
34 
35 #include "w_cmdpanel.h"
36 #include "w_msgpanel.h"
37 #include "w_canvas.h"
38 
39 /* EXPORTS */
40 
41 /* which layer buttons are active */
42 Boolean	active_layers[MAX_DEPTH +1];
43 Boolean	any_active_in_compound(F_compound *cmpnd);
44 Widget	layer_form;
45 Boolean	gray_layers = True;
46 int	object_depths[MAX_DEPTH +1];	/* count of objects at each depth */
47 int	saved_depths[MAX_DEPTH +1];	/* saved when delete all is done */
48 int	saved_min_depth, saved_max_depth; /* saved min/max depth */
49 int	max_depth_request, min_depth_request;
50 Boolean	save_layers[MAX_DEPTH+1];
51 int	LAYER_WD=DEF_LAYER_WD;
52 int	LAYER_HT;
53 
54 /* LOCALS */
55 
56 DeclareStaticArgs(20);
57 
58 static	Widget		all_active_but, all_inactive_but, toggle_all_but;
59 static	Widget		graytoggle, blanktoggle, graylabel, blanklabel;
60 static	Widget		layer_viewp, layer_canvas;
61 static	void	toggle_layer(Widget w, XButtonEvent *event, String *params, Cardinal *nparams);
62 static	void	set_depth_to_layer(Widget w, XButtonEvent *event, String *params, Cardinal *nparams);
63 static	void	sweep_layer(Widget w, XButtonEvent *event, String *params, Cardinal *nparams);
64 static	void	leave_layer(Widget w, XButtonEvent *event, String *params, Cardinal *nparams);
65 static	void	all_active(Widget w, XtPointer closure, XtPointer call_data);
66 static	void	all_inactive(Widget w, XtPointer closure, XtPointer call_data);
67 static	void	toggle_all(Widget w, XtPointer closure, XtPointer call_data);
68 static	void	switch_layer_mode(Widget w, XtPointer closure, XtPointer call_data);
69 static	void	layer_exposed(Widget w, XExposeEvent *event, String *params, Cardinal *nparams);
70 
71 #ifndef XAW3D1_5E
72 /* popup message over command button when mouse enters it */
73 static void     layer_balloon_trigger(Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch);
74 static void     layer_unballoon(Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch);
75 #endif /* XAW3D1_5E */
76 
77 static  void	draw_layer_button(Window win, int but);
78 static  void	draw_layer_buttons(void);
79 
80 XtActionsRec	layer_actions[] =
81 {
82     {"ExposeLayerButtons", (XtActionProc) layer_exposed},
83     {"ToggleLayerButton", (XtActionProc) toggle_layer},
84     {"SetDepthToLayer", (XtActionProc) set_depth_to_layer},
85     {"SweepLayerButton", (XtActionProc) sweep_layer},
86     {"LeaveLayerButton", (XtActionProc) leave_layer},
87 };
88 
89 static String	layer_translations =
90     "<Btn1Down>:ToggleLayerButton()\n\
91      <Btn1Motion>: SweepLayerButton()\n\
92      <Btn3Down>:SetDepthToLayer()\n\
93      <Leave>: LeaveLayerButton()\n\
94      <Expose>:ExposeLayerButtons()\n";
95 
96 
97 
98 void
reset_layers(void)99 reset_layers(void)
100 {
101   int i;
102   for (i=0; i<=MAX_DEPTH;  i++) {
103      active_layers[i] = True;
104   }
105 }
106 
107 void
reset_depths(void)108 reset_depths(void)
109 {
110   int i;
111   for (i=0; i<=MAX_DEPTH;  i++) {
112      object_depths[i] = 0;
113   }
114 }
115 
116 void
init_depth_panel(Widget parent)117 init_depth_panel(Widget parent)
118 {
119     Widget	 label, below;
120     Widget	 layer_viewform;
121 
122     /* MOUSEFUN_HT and ind_panel height aren't known yet */
123     LAYER_HT = TOPRULER_HT + CANVAS_HT;
124 
125     /* main form to hold all the layer stuff */
126 
127     FirstArg(XtNfromHoriz, sideruler_sw);
128     NextArg(XtNdefaultDistance, 1);
129     NextArg(XtNwidth, LAYER_WD);
130     NextArg(XtNheight, LAYER_HT);
131     NextArg(XtNleft, XtChainRight);
132     NextArg(XtNright, XtChainRight);
133     NextArg(XtNfromVert, snap_indicator_panel);
134     layer_form = XtCreateWidget("layer_form",formWidgetClass, parent, Args, ArgCount);
135     if (appres.showdepthmanager)
136 	XtManageChild(layer_form);
137 
138     /* a label */
139     FirstArg(XtNlabel, "Depths   ");
140     NextArg(XtNtop, XtChainTop);
141     NextArg(XtNbottom, XtChainTop);
142     NextArg(XtNleft, XtChainLeft);
143     NextArg(XtNright, XtChainRight);
144     label = XtCreateManagedWidget("layer_label", labelWidgetClass, layer_form,
145 				Args, ArgCount);
146 
147     /* buttons to make all active, all inactive or toggle all */
148 
149     FirstArg(XtNlabel, "All On  ");
150     NextArg(XtNfromVert, label);
151     NextArg(XtNtop, XtChainTop);
152     NextArg(XtNbottom, XtChainTop);
153     NextArg(XtNleft, XtChainLeft);
154     NextArg(XtNright, XtChainRight);
155     below = all_active_but = XtCreateManagedWidget("all_active", commandWidgetClass,
156 				layer_form, Args, ArgCount);
157     XtAddCallback(below, XtNcallback, (XtCallbackProc)all_active, (XtPointer) NULL);
158 #ifndef XAW3D1_5E
159     /* popup when mouse passes over button */
160     XtAddEventHandler(below, EnterWindowMask, False,
161 			  (XtEventHandler)layer_balloon_trigger, (XtPointer) "Display all depths");
162     XtAddEventHandler(below, LeaveWindowMask, False,
163 			   (XtEventHandler)layer_unballoon, (XtPointer) NULL);
164 #endif /* XAW3D1_5E */
165 
166     FirstArg(XtNlabel, "All Off ");
167     NextArg(XtNfromVert, below);
168     NextArg(XtNtop, XtChainTop);
169     NextArg(XtNbottom, XtChainTop);
170     NextArg(XtNleft, XtChainLeft);
171     NextArg(XtNright, XtChainRight);
172     below = all_inactive_but = XtCreateManagedWidget("all_inactive", commandWidgetClass,
173 				layer_form, Args, ArgCount);
174     XtAddCallback(below, XtNcallback, (XtCallbackProc)all_inactive, (XtPointer) NULL);
175 #ifndef XAW3D1_5E
176     /* popup when mouse passes over button */
177     XtAddEventHandler(below, EnterWindowMask, False,
178 			   (XtEventHandler)layer_balloon_trigger, (XtPointer) "Hide all depths");
179     XtAddEventHandler(below, LeaveWindowMask, False,
180 			   (XtEventHandler)layer_unballoon, (XtPointer) NULL);
181 #endif /* XAW3D1_5E */
182 
183     FirstArg(XtNlabel, "Toggle  ");
184     NextArg(XtNfromVert, below);
185     NextArg(XtNtop, XtChainTop);
186     NextArg(XtNbottom, XtChainTop);
187     NextArg(XtNleft, XtChainLeft);
188     NextArg(XtNright, XtChainRight);
189     below = toggle_all_but = XtCreateManagedWidget("toggle_all", commandWidgetClass,
190 				layer_form, Args, ArgCount);
191     XtAddCallback(below, XtNcallback, (XtCallbackProc)toggle_all, (XtPointer) NULL);
192 #ifndef XAW3D1_5E
193     /* popup when mouse passes over button */
194     XtAddEventHandler(below, EnterWindowMask, False,
195 			   (XtEventHandler)layer_balloon_trigger, (XtPointer) "Toggle displayed/hidden depths");
196     XtAddEventHandler(below, LeaveWindowMask, False,
197 			   (XtEventHandler)layer_unballoon, (XtPointer) NULL);
198 #endif /* XAW3D1_5E */
199 
200     /* radio buttons to switch between graying out inactive layers or blanking altogether */
201 
202     /* radio for graying out */
203     /* we'll insert the checkmark bitmap in setup_depth_panel */
204     FirstArg(XtNwidth, sm_check_width+6);
205     NextArg(XtNheight, sm_check_height+6);
206     NextArg(XtNfromVert, below);
207     NextArg(XtNtop, XtChainTop);
208     NextArg(XtNbottom, XtChainTop);
209     NextArg(XtNleft, XtChainLeft);
210     NextArg(XtNright, XtChainLeft);
211     NextArg(XtNinternalWidth, 1);
212     NextArg(XtNinternalHeight, 1);
213     NextArg(XtNfont, bold_font);
214     NextArg(XtNlabel, "  ");
215     NextArg(XtNsensitive, (gray_layers? False : True));	/* make opposite button sens */
216     NextArg(XtNstate, gray_layers);	/* initial state */
217     NextArg(XtNradioData, 1);		/* when this is pressed the value is 1 */
218     graytoggle = XtCreateManagedWidget("graytoggle", toggleWidgetClass,
219 				layer_form, Args, ArgCount);
220     XtAddCallback(graytoggle, XtNcallback, (XtCallbackProc) switch_layer_mode,
221 					(XtPointer) NULL);
222 
223     /* label - "Gray" */
224 
225     FirstArg(XtNborderWidth, 0);
226     NextArg(XtNfromVert, below);
227     NextArg(XtNfromHoriz, graytoggle);
228     NextArg(XtNtop, XtChainTop);
229     NextArg(XtNbottom, XtChainTop);
230     NextArg(XtNleft, XtChainRight);
231     NextArg(XtNright, XtChainRight);
232     NextArg(XtNlabel, "Gray  ");
233     graylabel = below = XtCreateManagedWidget("graylabel", labelWidgetClass,
234 				layer_form, Args, ArgCount);
235 #ifndef XAW3D1_5E
236     /* popup when mouse passes over button */
237     XtAddEventHandler(below, EnterWindowMask, False,
238 			   (XtEventHandler)layer_balloon_trigger, (XtPointer) "Display inactive layers in gray");
239     XtAddEventHandler(below, LeaveWindowMask, False,
240 			   (XtEventHandler)layer_unballoon, (XtPointer) NULL);
241 #endif /* XAW3D1_5E */
242 
243     /* radio for blanking */
244     FirstArg(XtNwidth, sm_check_width+6);
245     NextArg(XtNheight, sm_check_height+6);
246     NextArg(XtNfromVert, graytoggle);
247     NextArg(XtNtop, XtChainTop);
248     NextArg(XtNbottom, XtChainTop);
249     NextArg(XtNleft, XtChainLeft);
250     NextArg(XtNright, XtChainLeft);
251     NextArg(XtNinternalWidth, 1);
252     NextArg(XtNinternalHeight, 1);
253     NextArg(XtNfont, bold_font);
254     NextArg(XtNlabel, "  ");
255     NextArg(XtNsensitive, (gray_layers? True : False));	/* make opposite button sens */
256     NextArg(XtNstate, !gray_layers);	/* initial state */
257     NextArg(XtNradioData, 2);		/* when this is pressed the value is 2 */
258     NextArg(XtNradioGroup, graytoggle);	/* this is the other radio button in the group */
259     blanktoggle = XtCreateManagedWidget("blanktoggle", toggleWidgetClass,
260 				layer_form, Args, ArgCount);
261     XtAddCallback(blanktoggle, XtNcallback, (XtCallbackProc) switch_layer_mode,
262 					(XtPointer) NULL);
263 
264     /* label - "Blank" */
265 
266     FirstArg(XtNborderWidth, 0);
267     NextArg(XtNfromVert, graytoggle);
268     NextArg(XtNfromHoriz, blanktoggle);
269     NextArg(XtNlabel, "Blank ");
270     NextArg(XtNtop, XtChainTop);
271     NextArg(XtNbottom, XtChainTop);
272     NextArg(XtNleft, XtChainRight);
273     NextArg(XtNright, XtChainRight);
274     blanklabel = below = XtCreateManagedWidget("blanklabel", labelWidgetClass,
275 				layer_form, Args, ArgCount);
276 #ifndef XAW3D1_5E
277     /* popup when mouse passes over button */
278     XtAddEventHandler(below, EnterWindowMask, False,
279 			   (XtEventHandler)layer_balloon_trigger, (XtPointer) "Blank inactive layers");
280     XtAddEventHandler(below, LeaveWindowMask, False,
281 			   (XtEventHandler)layer_unballoon, (XtPointer) NULL);
282 #endif /* XAW3D1_5E */
283 
284     /* a form to hold the "Front" and "Back" labels and the viewport widget */
285 
286     FirstArg(XtNborderWidth, 1);
287     NextArg(XtNfromVert, below);
288     NextArg(XtNdefaultDistance, 1);
289     NextArg(XtNtop, XtChainTop);
290     NextArg(XtNbottom, XtChainBottom);
291     NextArg(XtNleft, XtChainRight);
292     NextArg(XtNright, XtChainRight);
293     layer_viewform = XtCreateManagedWidget("layer_viewform",formWidgetClass,
294 			layer_form, Args, ArgCount);
295 
296     /* label - "Front" */
297 
298     FirstArg(XtNborderWidth, 0);
299     NextArg(XtNlabel, " Front ");
300     NextArg(XtNtop, XtChainTop);
301     NextArg(XtNbottom, XtChainTop);
302     NextArg(XtNleft, XtChainRight);
303     NextArg(XtNright, XtChainRight);
304     below = XtCreateManagedWidget("frontlabel", labelWidgetClass,
305 				layer_viewform, Args, ArgCount);
306 
307     /* viewport to be able to scroll the layer buttons */
308 
309     FirstArg(XtNborderWidth, 1);
310     NextArg(XtNwidth, LAYER_WD);
311     NextArg(XtNallowVert, True);
312     NextArg(XtNfromVert, below);
313     NextArg(XtNtop, XtChainTop);
314     NextArg(XtNbottom, XtChainBottom);
315     NextArg(XtNleft, XtChainLeft);
316     NextArg(XtNright, XtChainRight);
317     layer_viewp = XtCreateManagedWidget("layer_viewp", viewportWidgetClass,
318 			layer_viewform, Args, ArgCount);
319     /* popup when mouse passes over button */
320 
321     /* pass null pointer for trigger message so we'll use the two-line one */
322 #ifndef XAW3D1_5E
323     XtAddEventHandler(layer_viewp, EnterWindowMask, False,
324 			   (XtEventHandler)layer_balloon_trigger, (XtPointer) NULL);
325     XtAddEventHandler(layer_viewp, LeaveWindowMask, False,
326 			   (XtEventHandler)layer_unballoon, (XtPointer) NULL);
327 #endif /* XAW3D1_5E */
328     XtAddEventHandler(layer_viewp, StructureNotifyMask, False,
329 			   (XtEventHandler)update_layers, (XtPointer) NULL);
330 
331     /* canvas (label, actually) in which to create the buttons */
332     /* we're not using real commandButtons because of the time to create
333        potentially hundreds of them depending on the number of layers in the figure */
334     FirstArg(XtNleft, XtChainLeft);
335     NextArg(XtNright, XtChainRight);
336     NextArg(XtNlabel, "");
337     layer_canvas = XtCreateManagedWidget("layer_canvas", labelWidgetClass,
338 				layer_viewp, Args, ArgCount);
339     /* label - "Back" */
340 
341     FirstArg(XtNborderWidth, 0);
342     NextArg(XtNfromVert, layer_viewp);
343     NextArg(XtNlabel, " Back  ");
344     NextArg(XtNtop, XtChainBottom);
345     NextArg(XtNbottom, XtChainBottom);
346     NextArg(XtNleft, XtChainRight);
347     NextArg(XtNright, XtChainRight);
348     below = XtCreateManagedWidget("backlabel", labelWidgetClass,
349 				layer_viewform, Args, ArgCount);
350 
351     /* make actions/translations for user to click on a layer "button" and
352        to redraw buttons on expose */
353     XtAppAddActions(tool_app, layer_actions, XtNumber(layer_actions));
354     XtOverrideTranslations(layer_canvas,
355 			   XtParseTranslationTable(layer_translations));
356 
357 #ifdef XAW3D1_5E
358     update_layerpanel();
359 #endif /* XAW3D1_5E */
360 }
361 
362 /* now that the mouse function and indicator panels have been sized
363    correctly, resize our form */
364 
365 void
setup_depth_panel(void)366 setup_depth_panel(void)
367 {
368     Dimension	 ind_ht, snap_ht=0;
369     /* get height of indicator and snap panels */
370     FirstArg(XtNheight, &ind_ht);
371     GetValues(ind_panel);
372     FirstArg(XtNheight, &snap_ht);
373     GetValues(snap_indicator_panel);
374     LAYER_HT = MOUSEFUN_HT + TOPRULER_HT + CANVAS_HT + ind_ht - snap_ht + INTERNAL_BW*4;
375 
376     /* now that the bitmaps have been created, put the checkmark in the proper toggle */
377     FirstArg(XtNbitmap, (gray_layers? sm_check_pm : sm_null_check_pm));
378     SetValues(graytoggle);
379     FirstArg(XtNbitmap, (gray_layers? sm_null_check_pm : sm_check_pm));
380     SetValues(blanktoggle);
381 
382     XtUnmanageChild(layer_form);
383     FirstArg(XtNheight, LAYER_HT);
384     SetValues(layer_form);
385     XtManageChild(layer_form);
386 }
387 
388 #define B_WIDTH		48
389 #define B_BORDER	2
390 #define C_SIZE		10
391 #define TOT_B_HEIGHT	(C_SIZE+2*B_BORDER)
392 
393 /* now make a checkbox for each layer in the figure */
394 /* get_min_max_depth() must have already been called */
395 
396 void
update_layers(void)397 update_layers(void)
398 {
399     Window	 w = XtWindow(layer_canvas);
400     int		 i, height;
401 
402     /* don't update depth panel when previewing or reading in a Fig file */
403     if (preview_in_progress || defer_update_layers)
404 	return;
405 
406     XClearWindow(tool_d, w);
407     if (min_depth < 0) return;  /* if no objects, return */
408 
409     height = B_BORDER * 3;
410     for (i = min_depth; i <= max_depth; i++) {
411       if (object_depths[i] > 0) height += TOT_B_HEIGHT;
412     }
413 
414     /* set height of canvas for all buttons */
415     FirstArg(XtNheight, (Dimension)height);
416     SetValues(layer_canvas);
417     /* force drawing */
418     draw_layer_buttons();
419 }
420 
421 static void
draw_layer_buttons(void)422 draw_layer_buttons(void)
423 {
424     Window	 w = XtWindow(layer_canvas);
425     int		 i;
426 
427     XClearWindow(tool_d, w);
428     if (min_depth < 0) return;  /* if no objects, return */
429 
430     for (i = min_depth; i <= max_depth; i++) {
431         if (object_depths[i] > 0) draw_layer_button(w, i);
432     }
433 }
434 
435 
436 #define draw_l(w, x1, y1, x2, y2) \
437 	XDrawLine(tool_d, w, button_gc, x1, y1, x2, y2);
438 
439 static void
draw_layer_button(Window win,int but)440 draw_layer_button(Window win, int but)
441 {
442     char	 str[20];
443     int		 x, y, w, h, i;
444 
445     if (object_depths[but] == 0) return;  /* no object for the depth */
446 
447     x = B_BORDER;
448     w = B_WIDTH;
449 
450     y = B_BORDER;
451     for (i = min_depth; i < but; i++) {
452       if (object_depths[i]) y += TOT_B_HEIGHT;
453     }
454     h = TOT_B_HEIGHT;
455 
456     /* the whole border */
457     draw_l(win,  x,  y,x+w,  y);
458     draw_l(win,x+w,  y,x+w,y+h);
459     draw_l(win,x+w,y+h,  x,y+h);
460     draw_l(win,x,  y+h,  x,  y);
461 
462     /* now the checkbox border */
463     x=x+B_BORDER; y=y+B_BORDER;
464     w=C_SIZE;
465 
466     draw_l(win,  x,  y,x+w,  y);
467     draw_l(win,x+w,  y,x+w,y+w);
468     draw_l(win,x+w,y+w,  x,y+w);
469     draw_l(win,  x,y+w,  x,  y);
470 
471     /* draw in the checkmark or a blank */
472     if (active_layer(but))
473 	XCopyArea(tool_d, sm_check_pm, win, button_gc, 0, 0,
474 		sm_check_width, sm_check_height, x+1, y+1);
475     else
476 	XCopyArea(tool_d, sm_null_check_pm, win, button_gc, 0, 0,
477 		sm_check_width, sm_check_height, x+1, y+1);
478 
479     /* now draw in the layer number for the button */
480     sprintf(str, "%3d", but);
481     XDrawString(tool_d, win, button_gc, x+w+3*B_BORDER, y+w, str, strlen(str));
482 }
483 
484 /* this is the callback to refresh the layer buttons that have been exposed */
485 
486 static void
layer_exposed(Widget w,XExposeEvent * event,String * params,Cardinal * nparams)487 layer_exposed(Widget w, XExposeEvent *event, String *params, Cardinal *nparams)
488 {
489     int		    y, i;
490 
491     if (min_depth < 0) return;  /* if no objects return */
492 
493     y = 0;
494     for (i = min_depth; i <= max_depth; i++) {
495       if (object_depths[i] > 0) {
496 	y += TOT_B_HEIGHT;
497 	if (event->y <= y && y - TOT_B_HEIGHT <= event->y + event->height)
498 	  draw_layer_button(XtWindow(w), i);
499       }
500     }
501 }
502 
503 /* come here when user toggles layer button */
504 
505 static int pressed_but = -1;
506 
507 static int
calculate_pressed_depth(int y)508 calculate_pressed_depth(int y)
509 {
510   int i, y1;
511 
512   y1 = TOT_B_HEIGHT;
513   for (i = min_depth; i <= max_depth; i++) {
514     if (object_depths[i] > 0) {
515       if (y < y1) return i;
516       y1 += TOT_B_HEIGHT;
517     }
518   }
519   return max_depth + 1;
520 }
521 
522 /* user pressed right button on layer checkbox, set depth attribute to that layer */
523 
524 static void
set_depth_to_layer(Widget w,XButtonEvent * event,String * params,Cardinal * nparams)525 set_depth_to_layer(Widget w, XButtonEvent *event, String *params, Cardinal *nparams)
526 {
527     int		    but;
528 
529     but = calculate_pressed_depth(event->y);
530     if (but < min_depth || max_depth < but)
531 	return;  /* no such button */
532     cur_depth = but;
533     show_depth(depth_button);
534 }
535 
536 static void
toggle_layer(Widget w,XButtonEvent * event,String * params,Cardinal * nparams)537 toggle_layer(Widget w, XButtonEvent *event, String *params, Cardinal *nparams)
538 {
539     Window	    win = XtWindow(layer_canvas);
540     int		    but, i;
541     Boolean	    obscure;
542 
543     if (min_depth < 0) return;  /* if no objects, return */
544 
545     but = calculate_pressed_depth(event->y);
546     if (but < min_depth || max_depth < but)
547 	return;  /* no such button */
548 
549     /* yes, toggle visibility and redraw */
550     active_layers[but] = !active_layers[but];
551     draw_layer_button(win, but);
552     /* if user just turned on a layer, draw only it if there are no active layers on top */
553     if (active_layers[but]) {
554 	obscure = False;
555 	for (i=0; i<but; i++)
556 	    if (active_layers[i]) {
557 		obscure = True;
558 		break;
559 	    }
560 	if (!obscure) {
561 	    clearcounts();
562 	    redisplay_compoundobject(&objects, but);
563 	} else
564 	    redisplay_canvas();
565     } else {
566 	/* otherwise redraw whole canvas to get rid of that layer */
567 	redisplay_canvas();
568     }
569     pressed_but = but;
570 }
571 
572 static void
sweep_layer(Widget w,XButtonEvent * event,String * params,Cardinal * nparams)573 sweep_layer(Widget w, XButtonEvent *event, String *params, Cardinal *nparams)
574 {
575     Window	    win = XtWindow(layer_canvas);
576     int		    but;
577     int		    i;
578     Boolean	    changed = FALSE;
579 
580     if (min_depth < 0) return;
581     if (pressed_but < 0) return;
582 
583     but = calculate_pressed_depth(event->y);
584     if (but < min_depth) but = min_depth;
585     if (max_depth < but) but = max_depth;
586 
587     if (pressed_but < but) {
588       for (i = pressed_but + 1; i <= but; i++) {
589 	if (object_depths[i] > 0
590 	    && active_layers[i] != active_layers[pressed_but]) {
591 	  active_layers[i] = active_layers[pressed_but];
592 	  draw_layer_button(win, i);
593 	  changed = TRUE;
594 	}
595       }
596     } else {
597       for (i = pressed_but - 1; but <= i; i--) {
598 	if (object_depths[i] > 0
599 	    && active_layers[i] != active_layers[pressed_but]) {
600 	  active_layers[i] = active_layers[pressed_but];
601 	  draw_layer_button(win, i);
602 	  changed = TRUE;
603 	}
604       }
605     }
606 
607     if (changed)
608 	redisplay_canvas();
609 }
610 
611 static void
leave_layer(Widget w,XButtonEvent * event,String * params,Cardinal * nparams)612 leave_layer(Widget w, XButtonEvent *event, String *params, Cardinal *nparams)
613 {
614     pressed_but = -1;
615 }
616 
617 static void
all_active(Widget w,XtPointer closure,XtPointer call_data)618 all_active(Widget w, XtPointer closure, XtPointer call_data)
619 {
620     int i;
621     Boolean changed = False;
622 
623     if (min_depth < 0) return;
624 
625     for (i=min_depth; i<=max_depth; i++) {
626 	if (!active_layers[i]) {
627 	    active_layers[i] = True;
628 	    changed = True;
629 	}
630     }
631     /* only redisplay if any of the buttons changed */
632     if (changed) {
633 	draw_layer_buttons();
634 	redisplay_canvas();
635     }
636 }
637 
638 static void
all_inactive(Widget w,XtPointer closure,XtPointer call_data)639 all_inactive(Widget w, XtPointer closure, XtPointer call_data)
640 {
641     int i;
642     Boolean changed = False;
643 
644     if (min_depth < 0) return;
645 
646     for (i=min_depth; i<=max_depth; i++) {
647 	if (active_layers[i]) {
648 	    active_layers[i] = False;
649 	    changed = True;
650 	}
651     }
652     /* only redisplay if any of the buttons changed */
653     if (changed) {
654 	draw_layer_buttons();
655 	redisplay_canvas();
656     }
657 }
658 
659 static void
toggle_all(Widget w,XtPointer closure,XtPointer call_data)660 toggle_all(Widget w, XtPointer closure, XtPointer call_data)
661 {
662     int i;
663 
664     if (min_depth < 0) return;
665 
666     for (i=min_depth; i<=max_depth; i++) {
667 	active_layers[i] = !active_layers[i];
668     }
669     draw_layer_buttons();
670     redisplay_canvas();
671 }
672 
673 /* when user toggles between gray-out and blank inactive layers */
674 
675 static void
switch_layer_mode(Widget w,XtPointer closure,XtPointer call_data)676 switch_layer_mode(Widget w, XtPointer closure, XtPointer call_data)
677 {
678     Boolean	    state;
679     intptr_t	    which;
680 
681     /* check state of the toggle and set/remove checkmark */
682     FirstArg(XtNstate, &state);
683     GetValues(w);
684 
685     if (state ) {
686 	FirstArg(XtNbitmap, sm_check_pm);
687     } else {
688 	FirstArg(XtNbitmap, sm_null_check_pm);
689     }
690     SetValues(w);
691 
692     /* set the sensitivity of the toggle button to the opposite of its state
693        so that the user must press the other one now */
694     XtSetSensitive(w, !state);
695     /* and make the *other* button the opposite state */
696     if (w == graytoggle) {
697 	XtSetSensitive(blanktoggle, state);
698     } else {
699 	XtSetSensitive(graytoggle, state);
700     }
701     /* which button */
702     which = (intptr_t) XawToggleGetCurrent(w);
703     if (which == 0)		/* no buttons on, in transition so return now */
704 	return;
705     if (which == 2)		/* "blank" button, invert state */
706 	state = !state;
707 
708     /* set global state */
709     gray_layers = state;
710 
711     /* now simply redisplay everything */
712     clear_canvas();
713     redisplay_canvas();
714 }
715 
716 /* return True if *any* object in the compound is in any active layer */
717 
718 Boolean
any_active_in_compound(F_compound * cmpnd)719 any_active_in_compound(F_compound *cmpnd)
720 {
721 	F_ellipse  *e;
722 	F_arc	   *a;
723 	F_line	   *l;
724 	F_spline   *s;
725 	F_text	   *t;
726 	F_compound *c;
727 
728 	for (a = cmpnd->arcs; a != NULL; a = a->next)
729 	    if (active_layer(a->depth))
730 		return True;
731 	for (e = cmpnd->ellipses; e != NULL; e = e->next)
732 	    if (active_layer(e->depth))
733 		return True;
734 	for (l = cmpnd->lines; l != NULL; l = l->next)
735 	    if (active_layer(l->depth))
736 		return True;
737 	for (s = cmpnd->splines; s != NULL; s = s->next)
738 	    if (active_layer(s->depth))
739 		return True;
740 	for (t = cmpnd->texts; t != NULL; t = t->next)
741 	    if (active_layer(t->depth))
742 		return True;
743 	for (c = cmpnd->compounds; c != NULL; c = c->next)
744 	    if (any_active_in_compound(c))
745 		return True;
746 	return False;
747 }
748 
749 #ifdef XAW3D1_5E
update_layerpanel()750 void update_layerpanel()
751 {
752     /*
753      * We must test for the widgets, as this is called by
754      * w_cmdpanel.c:refresh_view_menu().
755      */
756 
757     if (all_active_but)
758 	if (appres.showballoons)
759 	    XawTipEnable(all_active_but, "Display all depths");
760 	else
761 	    XawTipDisable(all_active_but);
762     if (all_inactive_but)
763 	if (appres.showballoons)
764 	    XawTipEnable(all_inactive_but, "Hide all depths");
765 	else
766 	    XawTipDisable(all_inactive_but);
767     if (toggle_all_but)
768 	if (appres.showballoons)
769 	    XawTipEnable(toggle_all_but, "Toggle displayed/hidden depths");
770 	else
771 	    XawTipDisable(toggle_all_but);
772     if (layer_viewp)
773 	if (appres.showballoons)
774 	    XawTipEnable(layer_viewp, "Display or hide any depth");
775 	else
776 	    XawTipDisable(layer_viewp);
777     if (graylabel)
778 	if (appres.showballoons)
779 	    XawTipEnable(graylabel, "Display inactive layers in gray");
780 	else
781 	    XawTipDisable(graylabel);
782     if (blanklabel)
783 	if (appres.showballoons)
784 	    XawTipEnable(blanklabel, "Blank inactive layers");
785 	else
786 	    XawTipDisable(blanklabel);
787 }
788 #else
789 static	Widget layer_balloon_popup = (Widget) 0;
790 static	XtIntervalId balloon_id = (XtIntervalId) 0;
791 static	Widget balloon_w;
792 static	char *popmsg;
793 
794 static	void layer_balloon(Widget w, XtPointer closure, XtPointer call_data);
795 
796 /* come here when the mouse passes over a button in the depths panel */
797 
798 static void
layer_balloon_trigger(Widget widget,XtPointer closure,XEvent * event,Boolean * continue_to_dispatch)799 layer_balloon_trigger(Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch)
800 {
801 	if (!appres.showballoons)
802 		return;
803 	balloon_w = widget;
804 	/* save the message to popup */
805 	popmsg = (char *) closure;
806 	/* if an old balloon is still up, destroy it */
807 	if ((balloon_id != 0) || (layer_balloon_popup != (Widget) 0)) {
808 		layer_unballoon((Widget) 0, (XtPointer) 0, (XEvent*) 0, (Boolean*) 0);
809 	}
810 	balloon_id = XtAppAddTimeOut(tool_app, appres.balloon_delay,
811 			(XtTimerCallbackProc) layer_balloon, (XtPointer) widget);
812 }
813 
814 /* come here when the timer times out (and the mouse is still over the button) */
815 
816 static void
layer_balloon(Widget w,XtPointer closure,XtPointer call_data)817 layer_balloon(Widget w, XtPointer closure, XtPointer call_data)
818 {
819 	Position  x, y;
820 	Dimension wid, ht;
821 	Widget box, balloon_label;
822 	XtWidgetGeometry xtgeom,comp;
823 
824 	XtTranslateCoords(w, 0, 0, &x, &y);
825 	FirstArg(XtNx, x);
826 	NextArg(XtNy, y);
827 	layer_balloon_popup = XtCreatePopupShell("layer_balloon_popup",
828 				overrideShellWidgetClass, tool, Args, ArgCount);
829 	FirstArg(XtNborderWidth, 0);
830 	NextArg(XtNhSpace, 0);
831 	NextArg(XtNvSpace, 0);
832 	NextArg(XtNorientation, XtorientVertical);
833 	box = XtCreateManagedWidget("box", boxWidgetClass,
834 				layer_balloon_popup, Args, ArgCount);
835 
836 	/* make label for mouse message */
837 	/* if the message was passed via the callback */
838 	if (popmsg) {
839 		FirstArg(XtNborderWidth, 0);
840 		NextArg(XtNlabel, popmsg);
841 		balloon_label = XtCreateManagedWidget("l_label", labelWidgetClass,
842 					    box, Args, ArgCount);
843 	} else {
844 		/* otherwise it is the two-line message with mouse indicators */
845 		FirstArg(XtNborderWidth, 0);
846 		NextArg(XtNleftBitmap, mouse_l);	/* bitmap of mouse with left button pushed */
847 		NextArg(XtNlabel, "Display or hide depth    ");
848 		balloon_label = XtCreateManagedWidget("l_label", labelWidgetClass,
849 					    box, Args, ArgCount);
850 		FirstArg(XtNborderWidth, 0);
851 		NextArg(XtNleftBitmap, mouse_r);	/* bitmap of mouse with right button pushed */
852 		NextArg(XtNlabel, "Set current depth to this");
853 		(void) XtCreateManagedWidget("r_label", labelWidgetClass,
854 					box, Args, ArgCount);
855 	}
856 
857 	/* realize the popup so we can get its size */
858 	XtRealizeWidget(layer_balloon_popup);
859 
860 	/* get width/height */
861 	FirstArg(XtNwidth, &wid);
862 	NextArg(XtNheight, &ht);
863 	GetValues(balloon_label);
864 	/* only change X position of widget */
865 	xtgeom.request_mode = CWX;
866 	/* shift popup left */
867 	xtgeom.x = x-wid-5;
868 	/* if the mouse is in the depth button area, position the y there */
869 	if (w == layer_viewp) {
870 	    int wx, wy;	/* XTranslateCoordinates wants int, not Position */
871 	    get_pointer_win_xy(&wx, &wy);
872 	    xtgeom.request_mode |= CWY;
873 	    xtgeom.y = y+wy - (int) ht - 60;
874 	}
875 	(void) XtMakeGeometryRequest(layer_balloon_popup, &xtgeom, &comp);
876 
877 	XtPopup(layer_balloon_popup,XtGrabNone);
878 	XtRemoveTimeOut(balloon_id);
879 	balloon_id = (XtIntervalId) 0;
880 }
881 
882 /* come here when the mouse leaves a button in the layer panel */
883 
884 static void
layer_unballoon(Widget widget,XtPointer closure,XEvent * event,Boolean * continue_to_dispatch)885 layer_unballoon(Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch)
886 {
887     if (balloon_id) {
888 	XtRemoveTimeOut(balloon_id);
889     }
890     balloon_id = (XtIntervalId) 0;
891     if (layer_balloon_popup != (Widget) 0) {
892 	XtDestroyWidget(layer_balloon_popup);
893 	layer_balloon_popup = (Widget) 0;
894     }
895 }
896 #endif /* XAW3D1_5E */
897 
898 /* map/unmap the depth manager on the right side */
899 
900 void
toggle_show_depths(void)901 toggle_show_depths(void)
902 {
903     Dimension	wid, b;
904 
905     appres.showdepthmanager = !appres.showdepthmanager;
906     put_msg("%s depth manager",
907 		appres.showdepthmanager? "Show": "Don't show");
908     /* get actual width of layer form */
909     FirstArg(XtNwidth, &wid);
910     NextArg(XtNborderWidth, &b);
911     GetValues(layer_form);
912     if (appres.showdepthmanager) {
913 	/* make sure it's the right size */
914 	setup_depth_panel();
915 	/* make canvas smaller to fit depth manager */
916 	resize_all(CANVAS_WD-wid-2*b, CANVAS_HT);
917     } else {
918 	XtUnmanageChild(layer_form);
919 	/* make canvas larger to fill space where depth manager was */
920 	resize_all(CANVAS_WD+wid+2*b, CANVAS_HT);
921     }
922     /* update the View menu */
923     refresh_view_menu();
924     /* and redraw the objects */
925     redisplay_canvas();
926 }
927 
928 void
save_active_layers(void)929 save_active_layers(void)
930 {
931     int		 i;
932     for (i=0; i<=MAX_DEPTH; i++)
933 	save_layers[i] = active_layers[i];
934 }
935 
936 /* save depth counts and min/max depth */
937 
938 void
save_depths(void)939 save_depths(void)
940 {
941     int		 i;
942     saved_min_depth = min_depth;
943     saved_max_depth = max_depth;
944     for (i=0; i<=MAX_DEPTH; i++)
945 	saved_depths[i] = object_depths[i];
946 }
947 
948 void
save_counts(void)949 save_counts(void)
950 {
951     int		 i;
952     for (i=0; i<=MAX_DEPTH; i++)
953 	saved_counts[i] = counts[i];
954 }
955 
956 void
save_counts_and_clear(void)957 save_counts_and_clear(void)
958 {
959     save_counts();
960     clearallcounts();
961 }
962 
963 void
restore_active_layers(void)964 restore_active_layers(void)
965 {
966     int		 i;
967     for (i=0; i<=MAX_DEPTH; i++)
968 	active_layers[i] = save_layers[i];
969 }
970 
971 /* restore depth counts and reset min/max depth */
972 
973 void
restore_depths(void)974 restore_depths(void)
975 {
976     int		 i;
977     min_depth = saved_min_depth;
978     max_depth = saved_max_depth;
979     for (i=0; i<=MAX_DEPTH; i++)
980 	object_depths[i] = saved_depths[i];
981     /* refresh the layer manager */
982     update_layers();
983 }
984 
985 void
restore_counts(void)986 restore_counts(void)
987 {
988     int		 i;
989     for (i=0; i<=MAX_DEPTH; i++)
990 	 counts[i] = saved_counts[i];
991 }
992 
993 /* swap depth counts and reset min/max depth */
994 
995 void
swap_depths(void)996 swap_depths(void)
997 {
998     int	i;
999     int	temp;
1000 
1001     temp = min_depth;
1002     min_depth = saved_min_depth;
1003     saved_min_depth = temp;
1004 
1005     temp = max_depth;
1006     max_depth = saved_max_depth;
1007     saved_max_depth = temp;
1008 
1009     for (i=0; i<=MAX_DEPTH; i++){
1010         temp = object_depths[i];
1011 	object_depths[i] = saved_depths[i];
1012         saved_depths[i] = temp;
1013     }
1014     /* refresh the layer manager */
1015     update_layers();
1016 }
1017 
1018 void
swap_counts(void)1019 swap_counts(void)
1020 {
1021     int i;
1022     struct counts temp;
1023     for (i=0; i<=MAX_DEPTH; i++){
1024          temp = counts[i];
1025 	 counts[i] = saved_counts[i];
1026 	 saved_counts[i] = temp;
1027     }
1028 }
1029