1 /*
2  * FIG : Facility for Interactive Generation of figures
3  * Copyright (c) 1985-1988 by Supoj Sutanthavibul
4  * Parts Copyright (c) 1989-2015 by Brian V. Smith
5  * Parts Copyright (c) 1991 by Paul King
6  * Parts Copyright (c) 2016-2020 by Thomas Loimer
7  *
8  * Change function implemented by Frank Schmuck (schmuck@svax.cs.cornell.edu)
9  * X version by Jon Tombs <jon@uk.ac.oxford.robots>
10  * Parts Copyright (c) 1995 by C. Blanc and C. Schlick
11  *
12  * Any party obtaining a copy of these files is granted, free of charge, a
13  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
14  * nonexclusive right and license to deal in this software and documentation
15  * files (the "Software"), including without limitation the rights to use,
16  * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
17  * the Software, and to permit persons who receive copies from any such
18  * party to do so, with the only requirement being that the above copyright
19  * and this permission notice remain intact.
20  *
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include "e_edit.h"
27 
28 #include <errno.h>
29 #include <math.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/stat.h>
34 #include <sys/wait.h>		/* waitpid() */
35 #include <time.h>
36 #include <unistd.h>
37 #include <X11/Intrinsic.h>	/* Widget, Boolean */
38 
39 #include "figx.h"
40 #include "resources.h"		/* also PATH_MAX */
41 #include "mode.h"
42 #include "object.h"
43 #include "paintop.h"
44 #include "e_placelib.h"
45 #include "e_scale.h"
46 #include "d_line.h"
47 #include "d_subspline.h"
48 #include "d_text.h"
49 #include "f_picobj.h"
50 #include "f_read.h"
51 #include "f_util.h"
52 #include "u_bound.h"
53 #include "u_create.h"
54 #include "u_draw.h"
55 #include "u_fonts.h"
56 #include "u_free.h"
57 #include "u_geom.h"
58 #include "u_list.h"
59 #include "u_markers.h"
60 #include "u_redraw.h"
61 #include "u_search.h"
62 #include "u_translate.h"
63 #include "u_undo.h"
64 #include "w_browse.h"
65 #include "w_canvas.h"
66 #include "w_color.h"
67 #include "w_capture.h"
68 #include "w_cursor.h"
69 #include "w_dir.h"
70 #include "w_drawprim.h"
71 #include "w_fontbits.h"
72 #include "w_icons.h"
73 #include "w_indpanel.h"
74 #include "w_msgpanel.h"
75 #include "w_mousefun.h"
76 #include "w_setup.h"
77 #include "w_util.h"
78 #ifdef I18N
79 #include "w_i18n.h"
80 #endif
81 #include "xfig_math.h"
82 
83 /* EXPORTS */
84 
85 Widget	pic_name_panel;		/* global to be visible in w_browse */
86 
87 /* LOCAL */
88 
89 #define NUM_IMAGES	16
90 #define	MAXDISPTS	100	/* maximum number of points to display for line, spline, etc */
91 
92 static	int what_rotation(int dx, int dy);
93 
94 #define XY_WIDTH	56	/* width of text widgets for x/y points */
95 
96 /* define some true/false constants to make proc calls easier to read */
97 #define GENERICS	True
98 #define NO_GENERICS	False
99 
100 #define ARROWS		True
101 #define NO_ARROWS	False
102 
103 static Position rootx, rooty;
104 static void	new_generic_values(void);
105 static void	new_arrow_values(void);
106 static void	get_new_line_values(void);
107 static void	generic_window(char *object_type, char *sub_type, icon_struct *icon, void (*d_proc) (/* ??? */), Boolean generics, Boolean arrows, char *comments);
108 static void     spline_point_window(int x, int y);
109 static void	font_image_panel(Pixmap pixmap, char *label, Widget *pi_x);
110 static Widget	pen_color_selection_panel(void);
111 static Widget	fill_color_selection_panel(void);
112 static void	float_label(float x, char *label, Widget *pi_x);
113 static void	int_label(int x, char *label, Widget *pi_x);
114 static void	str_panel(char *string, char *name, Widget *pi_x, int width, Boolean size_to_width, Boolean international);
115 static void	xy_panel(int x, int y, char *label, Widget *pi_x, Widget *pi_y, Boolean make_unit_menu);
116 static void	f_pair_panel(F_pos *fp, char *label, Widget *pi_x, char *xlabel, Widget *pi_y, char *ylabel, Boolean make_unit_menu);
117 static void	get_f_pos(F_pos *fp, Widget pi_x, Widget pi_y);
118 static void	points_panel(struct f_point *p);
119 static void	get_points(struct f_point *p);
120 static void	arc_type_select(Widget w, XtPointer new_style, XtPointer call_data);
121 static void	cap_style_select(Widget w, XtPointer new_type, XtPointer call_data);
122 static void	join_style_select(Widget w, XtPointer new_type, XtPointer call_data);
123 static void	line_style_select(Widget w, XtPointer new_style, XtPointer call_data);
124 static void	for_arrow_type_select(Widget w, XtPointer new_type, XtPointer call_data);
125 static void	back_arrow_type_select(Widget w, XtPointer new_type, XtPointer call_data);
126 static void	textjust_select(Widget w, XtPointer new_textjust, XtPointer call_data);
127 static void	fill_style_select(Widget w, XtPointer new_fillflag, XtPointer call_data);
128 static void	flip_pic_select(Widget w, XtPointer new_flipflag, XtPointer call_data);
129 static void	rotation_select(Widget w, XtPointer new_rotation, XtPointer call_data);
130 static void	hidden_text_select(Widget w, XtPointer new_hidden_text, XtPointer call_data);
131 static void	rigid_text_select(Widget w, XtPointer new_rigid_text, XtPointer call_data);
132 static void	special_text_select(Widget w, XtPointer new_special_text, XtPointer call_data);
133 static void	pen_color_select(Widget w, XtPointer new_color, XtPointer call_data);
134 static void	fill_color_select(Widget w, XtPointer new_color, XtPointer call_data);
135 static int	panel_get_dim_value(Widget widg);
136 static void	panel_clear_value(Widget widg);
137 static void	get_new_compound_values(void);
138 static void	panel_set_scaled_int(Widget widg, int intval);
139 static void	unit_select(Widget w, XtPointer new_unit, XtPointer call_data);
140 static void	init_convert_array(void);
141 static void	add_to_convert(Widget widget);
142 static double	cvt_to_units(int fig_unit);
143 static void	cvt_to_units_str(int x, char *buf);
144 static int	cvt_to_fig(double real_unit);
145 
146 static void	reposition_picture(Widget w);
147 static void	resize_picture(Widget w);
148 
149 static void	modify_compound(Widget w);
150 static void	reposition_top(void);
151 static void	reposition_bottom(void);
152 static void	rescale_compound(void);
153 static void	collapse_depth(Widget panel_local, XtPointer closure, XtPointer call_data);
154 
155 static void	done_line(void);
156 static void	done_text(void);
157 static void	done_arc(void);
158 static void	done_ellipse(void);
159 static void	done_spline(void);
160 static void	done_spline_point(void);
161 static void	done_compound(void);
162 static void	done_figure_comments(void);
163 
164 static void	done_button(Widget panel_local, XtPointer closure, XtPointer call_data), apply_button(Widget panel_local, XtPointer closure, XtPointer call_data), cancel_button(Widget panel_local, XtPointer closure, XtPointer call_data);
165 static void	toggle_sfactor_type(Widget panel_local, XtPointer _sfactor_index, XtPointer call_data);
166 static void	change_sfactor_value(Widget panel_local, XtPointer closure, XtPointer _top);
167 static void	scroll_sfactor_value(Widget panel_local, XtPointer closure, XtPointer _num_pixels);
168 static void	grab_button(Widget panel_local, XtPointer closure, XtPointer call_data), browse_button(Widget panel_local, XtPointer closure, XtPointer call_data), image_edit_button(Widget panel_local, XtPointer closure, XtPointer call_data);
169 static void	update_fill_image(Widget w, XtPointer dummy, XtPointer dummy2);
170 
171 static Widget	popup, form;
172 static Widget	below, beside;
173 static Widget	above_arrows;
174 static Widget	comment_popup;
175 static Widget	arc_points_form;
176 
177 static Widget	float_panel(float x, Widget parent, char *label, Widget pbeside, Widget *pi_x, float min, float max, float inc, int prec);
178 static Widget	int_panel(int x, Widget parent, char *label, Widget beside, Widget *pi_x, int min, int max, int inc);
179 static Widget	int_panel_callb(int x, Widget parent, char *label, Widget pbeside, Widget *pi_x, int min, int max, int inc, XtCallbackProc callback);
180 static Widget	reread, shrink, expand, origsize;
181 static Widget	percent_button, percent, percent_entry;
182 static Widget	label;
183 static Widget	thickness_panel;
184 static Widget	depth_panel;
185 static Widget	angle_panel;
186 static Widget	textjust_panel;
187 static Widget	hidden_text_panel;
188 static Widget	rigid_text_panel;
189 static Widget	special_text_panel;
190 static Widget	fill_intens, fill_intens_panel, fill_intens_label, fill_image;
191 static Widget	fill_pat, fill_pat_panel, fill_pat_label;
192 static Widget	flip_pic_panel;
193 static Widget	rotation_panel;
194 static Widget	arc_type_panel;
195 static Widget	cap_style_panel;
196 static Widget	join_style_panel;
197 static Widget	line_style_panel;
198 static Widget	for_arrow_type_panel;
199 static Widget	back_arrow_type_panel;
200 static Widget	style_val, style_val_panel, style_val_label;
201 static Widget	for_arrow_height,for_arrow_width,for_arrow_thick;
202 static Widget	back_arrow_height,back_arrow_width,back_arrow_thick;
203 static Widget	for_thick_label,for_height_label,for_width_label;
204 static Widget	back_thick_label,back_height_label,back_width_label;
205 static Widget	for_thick,for_height,for_width;
206 static Widget	back_thick,back_height,back_width;
207 static Boolean	for_arrow, back_arrow;
208 
209 static Widget	text_panel;
210 static Widget	x1_panel, y1_panel;
211 static Widget	x2_panel, y2_panel;
212 static Widget	x3_panel, y3_panel;
213 static Widget	width_panel, height_panel;
214 static Widget	hw_ratio_panel;
215 static Widget	orig_hw_panel;
216 static Widget	font_panel;
217 static Widget	cur_fontsize_panel;
218 static Widget	fill_style_button;
219 static Widget	radius, num_objects;
220 static Widget	comments_panel;
221 static Widget	for_aform,back_aform;
222 static Widget	but1;
223 static Widget	unit_menu_button;
224 static Widget	unit_pulldown_menu(Widget below, Widget beside);
225 static Widget	min_depth_w, max_depth_w;
226 
227 /* for PIC object type */
228 static Widget	pic_size, pic_type_box[NUM_PIC_TYPES], pic_colors, transp_color;
229 
230 static Widget	pen_col_button, pen_color_popup=0;
231 static Widget	fill_col_button, fill_color_popup=0;
232 
233 DeclareStaticArgs(20);
234 static char	buf[64];
235 
236 static Widget	px_panel[MAXDISPTS];
237 static Widget	py_panel[MAXDISPTS];
238 
239 /* for our own fill % and fill pattern pixmap in the popup */
240 
241 #define FILL_SIZE 40	/* size of indicators */
242 static	Pixmap	fill_image_pm,fill_image_bm[NUMFILLPATS];
243 static	Boolean	fill_image_bm_exist = False;
244 static	GC	fill_image_gc = 0;
245 static	Boolean	fill_style_exists = False;
246 static	Pixel	form_bg = -1;
247 
248 /* pulldown menu for units of point coords */
249 
250 static char	*unit_items[] = {NULL,	 /* this is modified in unit_select() */
251 				 "Fig units"};
252 static intptr_t	points_units=0;		/*  0=Ruler scale, 1=Fig*/
253 static int	conv_array_idx = 0;	/* to keep track of widgets that need unit conversions */
254 static Widget	convert_array[MAXDISPTS*2]; /* array for those widgets */
255 
256 /* For edit all texts inside compound function */
257 
258 #define MAX_COMPOUND_TEXT_PANELS 2000	/* max number of texts that can be edited in compound */
259 static	Widget	compound_text_panels[MAX_COMPOUND_TEXT_PANELS];
260 Boolean	edit_remember_lib_mode = False;		/* Remember that we were in library mode */
261 Boolean	edit_remember_dimline_mode = False;	/* Remember that we were in dimension line mode */
262 Boolean	lib_cursor = False;			/* to reset cursor back to lib mode */
263 Boolean	dim_cursor = False;			/* to reset cursor back to line mode */
264 
265 /*********************************************************************/
266 /* NOTE: If you change this you must change pictypes in object.h too */
267 /*********************************************************************/
268 
269 static char	*pic_names[] = {
270 			"--", "EPS/PS", "PDF", "GIF",
271 #ifdef HAVE_JPEG
272 			"JPEG",
273 #endif
274 			"PCX",
275 #ifdef HAVE_PNG
276 			"PNG",
277 #endif
278 			"PPM", "TIFF", "XBM",
279 #ifdef USE_XPM
280 			"XPM",
281 #endif
282 		};
283 
284 static int	ellipse_flag;
285 static intptr_t	fill_flag;
286 static intptr_t	flip_pic_flag;
287 static void	(*done_proc) ();
288 static int	button_result;
289 static intptr_t	textjust;
290 static Color	pen_color, fill_color;
291 static intptr_t	hidden_text_flag;
292 static intptr_t	special_text_flag;
293 static intptr_t	rigid_text_flag;
294 static int	new_ps_font, new_latex_font;
295 static int	new_psflag;
296 static int	min_compound_depth;
297 static Boolean	changed, reread_file;
298 static Boolean  file_changed=False;
299 static Boolean	actions_added=False;
300 
301 static void     edit_cancel(Widget w, XButtonEvent *ev, String *params, Cardinal *num_params);
302 static void     edit_done(Widget w, XButtonEvent *ev, String *params, Cardinal *num_params), edit_apply(Widget w, XButtonEvent *ev, String *params, Cardinal *num_params);
303 static void	popdown_comments(void);
304 
305 /*
306  * the following pix_table and xxxx_pixmaps entries are guaranteed to be
307  * initialized to 0 by the compiler
308  */
309 
310 static struct {
311     icon_struct	   *image;
312     Pixmap	    image_pm;
313 }		pix_table[NUM_IMAGES];
314 
315 static Pixmap	    capstyle_pixmaps[NUM_JOINSTYLE_TYPES] = {0};
316 static Pixmap	    joinstyle_pixmaps[NUM_CAPSTYLE_TYPES] = {0};
317 
318 /* picture flip menu options */
319 static char    *flip_pic_items[] = {"Normal            ",
320 				"Flipped about diag"};
321 
322 /* picture rotation menu options */
323 static char    *rotation_items[] = {"  0", " 90", "180", "270"};
324 
325 /**********************************************/
326 /* Translations and actions for edit cancel   */
327 /* Make Escape cancel the edit in addition to */
328 /* destroy window                             */
329 /**********************************************/
330 
331 static String   edit_popup_translations =
332 	"<Key>Escape: CancelEdit()\n\
333 	<Message>WM_PROTOCOLS: CancelEdit()\n";
334 
335 static XtActionsRec     edit_actions[] =
336 {
337     {"CancelEdit", (XtActionProc) edit_cancel},
338 };
339 
340 /*************************************************/
341 /* Translations and actions for showing comments */
342 /*************************************************/
343 
344 static String   showcomment_popup_translations =
345 	"<Btn2Up>: PopdownComments()\n\
346 	<Message>WM_PROTOCOLS: PopdownComments()";
347 
348 static XtActionsRec     showcomment_actions[] =
349 {
350     {"PopdownComments", (XtActionProc) popdown_comments},
351 };
352 
353 /*********************************************/
354 /* Translations and actions for text widgets */
355 /*********************************************/
356 
357 /* don't allow newlines in text until we handle multiple line texts */
358 /** Add Ctrl-Return to do a quick apply and DONE */
359 /** Bound ^U to erase line instead of multiply(4) */
360 
361 static String         edit_text_translations =
362 	"Ctrl<Key>Return: DoneEdit()\n\
363 	<Key>Return:	ApplyEdit()\n\
364 	<Key>Escape:	CancelEdit()\n\
365 	Ctrl<Key>J:	no-op(RingBell)\n\
366 	Ctrl<Key>M:	no-op(RingBell)\n\
367 	Ctrl<Key>X:	EmptyTextKey()\n\
368 	Ctrl<Key>U:	EmptyTextKey()\n\
369 	<Key>F18:	PastePanelKey()\n";
370 
371 /* scroll in comments */
372 
373 static String	      edit_comment_translations =
374 	"<Btn4Down>:	scroll-one-line-up()\n\
375 	<Btn5Down>:	scroll-one-line-down()\n";
376 
377 static XtActionsRec     text_actions[] =
378 {
379     {"DoneEdit", (XtActionProc) edit_done},
380     {"ApplyEdit", (XtActionProc) edit_apply},
381 };
382 
383 static String edit_picture_pos_translations =
384 	"<Key>Return: RepositionPicture()\n";
385 
386 static XtActionsRec picture_pos_actions[] =
387 {
388     {"RepositionPicture", (XtActionProc) reposition_picture},
389 };
390 
391 static String edit_picture_size_translations =
392 	"<Key>Return: ResizePicture()\n";
393 
394 static XtActionsRec picture_size_actions[] =
395 {
396     {"ResizePicture", (XtActionProc) resize_picture},
397 };
398 
399 static String edit_compound_translations =
400 	"<Key>Return: ModifyCompound()\n";
401 
402 static XtActionsRec compound_actions[] =
403 {
404     {"ModifyCompound", (XtActionProc) modify_compound},
405 };
406 
407 #define CANCEL		0
408 #define DONE		1
409 #define APPLY		2
410 
411 /******************************/
412 /* specific stuff for splines */
413 /******************************/
414 
415 #define THUMB_H  0.05
416 #define STEP_VALUE 0.02
417 #define SFACTOR_BAR_HEIGHT 200
418 #define SFACTOR_BAR_WIDTH (SFACTOR_BAR_HEIGHT/10)
419 #define SFACTOR_SIGN(x) ( (x) < 0 ? 1.0 : -1.0)
420 #define SFACTOR_TO_PERCENTAGE(x) ((-(x) + 1.0) / 2.0)
421 /*
422  * The division by 1.- 0.5*THUMB_H allows to move the slider between
423  * 1.0 and -1.0, exactly and inclusively.
424  */
425 #define PERCENTAGE_TO_CONTROL(x) (-(2./(1.-0.5*THUMB_H)) * (x) + 1.0)
426 
427 static void update_sfactor_value(double new_value);
428 static struct sfactor_def
429 {
430   char label[13];
431   double value;
432 }
433   sfactor_type[3] =
434 {
435   { "Approximated", S_SPLINE_APPROX  },
436   { "Angular",      S_SPLINE_ANGULAR },
437   { "Interpolated", S_SPLINE_INTERP  }
438 };
439 
440 static void      make_window_spline_point(F_spline *s, int x, int y);
441 
442 static Widget    sfactor_bar;
443 static F_sfactor *edited_sfactor, *sub_sfactor;
444 static F_point   *edited_point;
445 static F_spline  *sub_new_s;
446 static int       num_spline_points;
447 
448 /*************************************/
449 /* end of specific stuff for splines */
450 /*************************************/
451 
452 
453 static struct {
454     int		 thickness;
455     Color	 pen_color;
456     Color	 fill_color;
457     int		 depth;
458     intptr_t	 arc_type;
459     int		 cap_style;
460     int		 join_style;
461     int		 style;
462     float	 style_val;
463     int		 pen_style;
464     int		 fill_style;
465     char	*comments;
466     F_arrow	 for_arrow;
467     F_arrow	 back_arrow;
468 }	generic_vals;
469 
470 #define put_generic_vals(x) \
471 	generic_vals.thickness	= x->thickness; \
472 	generic_vals.pen_color	= x->pen_color; \
473 	generic_vals.fill_color	= x->fill_color; \
474 	generic_vals.depth	= x->depth; \
475 	generic_vals.style	= x->style; \
476 	generic_vals.style_val	= x->style_val; \
477 	generic_vals.pen_style	= x->pen_style; \
478 	generic_vals.fill_style = x->fill_style
479 
480 #define get_generic_vals(x) \
481 	new_generic_values(); \
482 	x->thickness	= generic_vals.thickness; \
483 	x->pen_color	= generic_vals.pen_color; \
484 	x->fill_color	= generic_vals.fill_color; \
485 	x->depth	= generic_vals.depth; \
486 	x->style	= generic_vals.style; \
487 	x->style_val	= generic_vals.style_val; \
488 	x->pen_style	= generic_vals.pen_style; \
489 	x->fill_style	= generic_vals.fill_style; \
490 	x->comments	= generic_vals.comments
491 
492 #define put_join_style(x) \
493 	generic_vals.join_style = x->join_style;
494 
495 #define get_join_style(x) \
496 	x->join_style = generic_vals.join_style;
497 
498 #define put_cap_style(x) \
499 	generic_vals.cap_style = x->cap_style;
500 
501 #define get_cap_style(x) \
502 	x->cap_style = generic_vals.cap_style;
503 
504 #define put_arc_type(x) \
505 	generic_vals.arc_type = x->type;
506 
507 
508 static void	make_window_line(F_line *l);
509 static void	make_window_text(F_text *t);
510 static void	make_window_ellipse(F_ellipse *e);
511 static void	make_window_arc(F_arc *a);
512 static void	make_window_spline(F_spline *s);
513 static void	make_window_compound(F_compound *c);
514 static void	make_window_figure(void);
515 static void	check_depth(void);
516 static void	check_thick(void);
517 static void	text_transl(Widget w);
518 /* */
519 static void	reset_edit_cursor(void);
520 static void	arc_type_menu(void);
521 static void	fill_style_menu(int fill, int fill_flag);
522 static void	cap_style_panel_menu(void);
523 static void	join_style_panel_menu(void);
524 static void	set_image_pm(int val);
525 static void	fill_style_sens(Boolean state);
526 static void	fill_pat_sens(Boolean state);
527 static void	collapse_depths(F_compound *compound);
528 
get_arc_type(F_arc * arc)529 void get_arc_type(F_arc *arc)
530 {
531     arc->type = generic_vals.arc_type;
532     /* remove any arrowheads from pie-wedge style arc */
533     if (arc->type == T_PIE_WEDGE_ARC) {
534 	if (arc->for_arrow) {
535 	    free((char *) arc->for_arrow);
536 	    arc->for_arrow = NULL;
537 	}
538 	if (arc->back_arrow) {
539 	    free((char *) arc->back_arrow);
540 	    arc->back_arrow = NULL;
541 	}
542     }
543 }
544 
545 /* NOTE: This procedure requires that the structure components for f_arc, f_line
546 	and f_spline are in the same order up to and including the arrows */
547 
put_generic_arrows(F_line * x)548 void put_generic_arrows(F_line *x)
549 {
550     for_arrow = (x->for_arrow != NULL);
551     back_arrow = (x->back_arrow != NULL);
552     if (for_arrow) {
553 	generic_vals.for_arrow.type	= x->for_arrow->type;
554 	generic_vals.for_arrow.style	= x->for_arrow->style;
555 	generic_vals.for_arrow.thickness = x->for_arrow->thickness;
556 	generic_vals.for_arrow.wd	= x->for_arrow->wd;
557 	generic_vals.for_arrow.ht	= x->for_arrow->ht;
558     } else {
559 	generic_vals.for_arrow.type	= -1;
560 	generic_vals.for_arrow.style	= -1;
561 	/* no existing arrow, set dialog to current ind panel settings */
562 	if (use_abs_arrowvals) {
563 	    generic_vals.for_arrow.thickness = cur_arrowthick;
564 	    generic_vals.for_arrow.wd	= cur_arrowwidth;
565 	    generic_vals.for_arrow.ht	= cur_arrowheight;
566 	} else {
567 	    /* use multiple of current line thickness */
568 	    generic_vals.for_arrow.thickness = cur_arrow_multthick * x->thickness;
569 	    generic_vals.for_arrow.wd	= cur_arrow_multwidth * x->thickness;
570 	    generic_vals.for_arrow.ht	= cur_arrow_multheight * x->thickness;
571 	}
572     }
573     if (back_arrow) {
574 	generic_vals.back_arrow.type	= x->back_arrow->type;
575 	generic_vals.back_arrow.style	= x->back_arrow->style;
576 	generic_vals.back_arrow.thickness = x->back_arrow->thickness;
577 	generic_vals.back_arrow.wd	= x->back_arrow->wd;
578 	generic_vals.back_arrow.ht	= x->back_arrow->ht;
579     } else {
580 	generic_vals.back_arrow.type	= -1;
581 	generic_vals.back_arrow.style	= -1;
582 	/* no existing arrow, set dialog to current ind panel settings */
583 	if (use_abs_arrowvals) {
584 	    generic_vals.back_arrow.thickness = cur_arrowthick;
585 	    generic_vals.back_arrow.wd	= cur_arrowwidth;
586 	    generic_vals.back_arrow.ht	= cur_arrowheight;
587 	} else {
588 	    /* use multiple of current line thickness */
589 	    generic_vals.back_arrow.thickness = cur_arrow_multthick * x->thickness;
590 	    generic_vals.back_arrow.wd	= cur_arrow_multwidth * x->thickness;
591 	    generic_vals.back_arrow.ht	= cur_arrow_multheight * x->thickness;
592 	}
593     }
594 }
595 
596 /* NOTE: This procedure requires that the structure components for f_arc, f_line
597 	and f_spline are in the same order up to and including the arrows */
598 
get_generic_arrows(F_line * x)599 void get_generic_arrows(F_line *x)
600 {
601 	new_arrow_values();
602 	if (for_arrow) {
603 	    if (!x->for_arrow)
604 		x->for_arrow = create_arrow();
605 	    x->for_arrow->type = generic_vals.for_arrow.type;
606 	    x->for_arrow->style = generic_vals.for_arrow.style;
607 	    x->for_arrow->thickness = (float) fabs((double) generic_vals.for_arrow.thickness);
608 	    x->for_arrow->wd = (float) fabs((double) generic_vals.for_arrow.wd);
609 	    x->for_arrow->ht = (float) fabs((double) generic_vals.for_arrow.ht);
610 	} else {
611 	    if (x->for_arrow)
612 		free((char *) x->for_arrow);
613 	    x->for_arrow = (F_arrow *) NULL;
614 	}
615 	if (back_arrow) {
616 	    if (!x->back_arrow)
617 		x->back_arrow = create_arrow();
618 	    x->back_arrow->type = generic_vals.back_arrow.type;
619 	    x->back_arrow->style = generic_vals.back_arrow.style;
620 	    x->back_arrow->thickness = (float) fabs((double) generic_vals.back_arrow.thickness);
621 	    x->back_arrow->wd = (float) fabs((double) generic_vals.back_arrow.wd);
622 	    x->back_arrow->ht = (float) fabs((double) generic_vals.back_arrow.ht);
623 	} else {
624 	    if (x->back_arrow)
625 		free((char *) x->back_arrow);
626 	    x->back_arrow = (F_arrow *) NULL;
627 	}
628 }
629 
630 static void	edit_spline_point(F_spline *spline, int type, int x, int y,
631 				F_point *previous_point, F_point *the_point);
632 static void	edit_figure_comments(int x, int y, unsigned int shift);
633 
edit_item_selected(void)634 void edit_item_selected(void)
635 {
636     set_mousefun("edit object", "edit Main comment", "edit point",
637 			LOC_OBJ, "show comments", LOC_OBJ);
638     canvas_kbd_proc = null_proc;
639     canvas_locmove_proc = null_proc;
640     canvas_ref_proc = null_proc;
641     init_searchproc_left(edit_item);
642     init_searchproc_right(edit_spline_point);
643     canvas_leftbut_proc = object_search_left;
644     canvas_middlebut_proc = edit_figure_comments;
645     canvas_rightbut_proc = point_search_right;
646     set_cursor(pick9_cursor);
647     reset_action_on();
648 }
649 
650 /*
651    this handles both viewing of any object's comments (shift=1) and
652    editing of the whole figure comments (shift=0)
653 */
654 
655 static void	popup_show_comments(F_line *p, int type, int x, int y);
656 
657 static void				/* Shift Key Status from XEvent */
edit_figure_comments(int x,int y,unsigned int shift)658 edit_figure_comments(int x, int y, unsigned int shift)
659 {
660     if (shift) {
661 	/* locate the object and popup the comments panel */
662 	init_searchproc_left(popup_show_comments);
663 	object_search_left(x, y, False);
664 	/* reset search proc function */
665 	init_searchproc_left(edit_item);
666     } else {
667 	/* popup an edit window for the whole figure */
668 	edit_item(&objects, O_FIGURE, 0, 0);
669     }
670 }
671 
672 static void
popup_show_comments(F_line * p,int type,int x,int y)673 popup_show_comments(F_line *p, int type, int x, int y)
674 {
675 	Widget		form;
676 	static Boolean	actions_added = False;
677 	char		*comments;
678 	F_arc		*a;
679 	F_compound	*c;
680 	F_ellipse	*e;
681 	F_line		*l;
682 	F_spline	*s;
683 	F_text		*t;
684 
685 	switch (type) {
686 	    case O_ARC:
687 		a = (F_arc *) p;
688 		comments = a->comments;
689 		break;
690 	    case O_COMPOUND:
691 		c = (F_compound *) p;
692 		comments = c->comments;
693 		break;
694 	    case O_ELLIPSE:
695 		e = (F_ellipse *) p;
696 		comments = e->comments;
697 		break;
698 	    case O_POLYLINE:
699 		l = (F_line *) p;
700 		comments = l->comments;
701 		break;
702 	    case O_SPLINE:
703 		s = (F_spline *) p;
704 		comments = s->comments;
705 		break;
706 	    case O_TXT:
707 		t = (F_text *) p;
708 		comments = t->comments;
709 		break;
710 	} /* switch */
711 
712 	/* locate the mouse in screen coords */
713 	XtTranslateCoords(canvas_sw, ZOOMX(x), ZOOMY(y), &rootx, &rooty);
714 	/* popup a panel showing the object comments */
715 	FirstArg(XtNtitle, "Xfig: Object comments");
716 	NextArg(XtNcolormap, tool_cm);
717 	NextArg(XtNx, rootx-10);	/* pop it up just under the mouse */
718 	NextArg(XtNy, rooty-10);
719 	comment_popup = XtCreatePopupShell("show_comments",
720 			       overrideShellWidgetClass, tool,
721 			       Args, ArgCount);
722 	FirstArg(XtNborderWidth, 1);
723 	NextArg(XtNtop, XtChainTop);
724 	NextArg(XtNbottom, XtChainBottom);
725 	NextArg(XtNleft, XtChainLeft);
726 	NextArg(XtNright, XtChainLeft);
727 	form = XtCreateManagedWidget("comment_form", formWidgetClass,
728 				comment_popup, Args, ArgCount);
729 	FirstArg(XtNlabel, "Comments:");
730 	NextArg(XtNborderWidth, 0);
731 	NextArg(XtNtop, XtChainTop);
732 	NextArg(XtNbottom, XtChainBottom);
733 	NextArg(XtNleft, XtChainLeft);
734 	NextArg(XtNright, XtChainLeft);
735 	below = XtCreateManagedWidget("comment_label", labelWidgetClass,
736 				       form, Args, ArgCount);
737 	/* make label widgets for comment lines */
738 	if (comments == NULL)
739 	    comments = "(None)";
740 	FirstArg(XtNlabel, comments);
741 	NextArg(XtNfromVert, below);
742 	NextArg(XtNvertDistance, 2);
743 	NextArg(XtNtop, XtChainTop);
744 	NextArg(XtNbottom, XtChainBottom);
745 	NextArg(XtNleft, XtChainLeft);
746 	NextArg(XtNright, XtChainRight);
747 	below = XtCreateManagedWidget("comments", labelWidgetClass,
748 				form, Args, ArgCount);
749 	XtAugmentTranslations(comment_popup,
750 			XtParseTranslationTable(showcomment_popup_translations));
751 	if (!actions_added) {
752 	    XtAppAddActions(tool_app, showcomment_actions, XtNumber(showcomment_actions));
753 	    actions_added = True;
754 	}
755 	XtPopupSpringLoaded(comment_popup);
756 }
757 
758 static void
popdown_comments(void)759 popdown_comments(void)
760 {
761 	XtDestroyWidget(comment_popup);
762 }
763 
edit_item(void * p,int type,int x,int y)764 void edit_item(void *p, int type, int x, int y)
765 {
766     XtWidgetGeometry xtgeom,comp;
767     int		    llx, lly, urx, ury, dum;
768     Dimension	    w, h;
769     Position	    rootlx, rootly, rootux, rootuy;
770 
771     /* make some pixmaps if we haven't already */
772     if (joinstyle_pixmaps[0] == 0) {
773 	joinstyle_pixmaps[0] = XCreateBitmapFromData(tool_d,canvas_win,
774 			(char*) joinmiter_ic.bits, joinmiter_ic.width, joinmiter_ic.height);
775 	joinstyle_pixmaps[1] = XCreateBitmapFromData(tool_d,canvas_win,
776 			(char*) joinround_ic.bits, joinround_ic.width, joinround_ic.height);
777 	joinstyle_pixmaps[2] = XCreateBitmapFromData(tool_d,canvas_win,
778 			(char*) joinbevel_ic.bits, joinbevel_ic.width, joinbevel_ic.height);
779     }
780     if (capstyle_pixmaps[0] == 0) {
781 	capstyle_pixmaps[0] = XCreateBitmapFromData(tool_d,canvas_win,
782 			(char*) capbutt_ic.bits, capbutt_ic.width, capbutt_ic.height);
783 	capstyle_pixmaps[1] = XCreateBitmapFromData(tool_d,canvas_win,
784 			(char*) capround_ic.bits, capround_ic.width, capround_ic.height);
785 	capstyle_pixmaps[2] = XCreateBitmapFromData(tool_d,canvas_win,
786 			(char*) capproject_ic.bits, capproject_ic.width, capproject_ic.height);
787     }
788 
789     changed = False;
790     reread_file = False;
791     /* make a window based on the object being edited */
792     /* also get the bounds of the object to position the popup away from it */
793     switch (type) {
794       case O_POLYLINE:
795 	line_bound((F_line *) p, &llx, &lly, &urx, &ury);
796 	make_window_line((F_line *) p);
797 	break;
798       case O_TXT:
799 	text_bound((F_text *) p, &llx, &lly, &urx, &ury,
800 		&dum,&dum,&dum,&dum,&dum,&dum,&dum,&dum);
801 	make_window_text((F_text *) p);
802 	break;
803       case O_ELLIPSE:
804 	ellipse_bound((F_ellipse *) p, &llx, &lly, &urx, &ury);
805 	make_window_ellipse((F_ellipse *) p);
806 	break;
807       case O_ARC:
808 	arc_bound((F_arc *) p, &llx, &lly, &urx, &ury);
809 	make_window_arc((F_arc *) p);
810 	break;
811       case O_SPLINE:
812 	spline_bound((F_spline *) p, &llx, &lly, &urx, &ury);
813 	make_window_spline((F_spline *) p);
814 	break;
815       case O_COMPOUND:
816 	compound_bound((F_compound *) p, &llx, &lly, &urx, &ury);
817 	/* turn on the point positioning indicator since it is used for editing compound */
818 	update_indpanel(I_MIN2);
819 	make_window_compound((F_compound *) p);
820 	break;
821       case O_FIGURE:
822 	compound_bound((F_compound *) p, &llx, &lly, &urx, &ury);
823 	make_window_figure();
824 	break;
825     }
826 
827     /* try to position the window so it doesn't obscure the object being edited */
828 
829     /* first realize the popup widget so we can get its width */
830     XtRealizeWidget(popup);
831 
832     /* translate object coords to screen coords relative to the canvas */
833     llx = ZOOMX(llx);
834     urx = ZOOMX(urx);
835     lly = ZOOMY(lly);
836     ury = ZOOMY(ury);
837 
838     /* translate those to absolute screen coords */
839     XtTranslateCoords(canvas_sw, llx, lly, &rootlx, &rootly);
840     XtTranslateCoords(canvas_sw, urx, ury, &rootux, &rootuy);
841 
842     /* size of popup window */
843     FirstArg(XtNwidth, &w);
844     NextArg(XtNheight, &h);
845     GetValues(popup);
846 
847     /* try putting it just to the right of the object */
848     if (rootux + 10 + w < screen_wd) {
849 	x = rootux+10;
850     } else {
851 	/* else put it to the left of the object */
852 	x = rootlx - 10 - w;
853 	/* but always on the screen */
854 	if (x < 0)
855 	    x = 0;
856     }
857     y = 40;
858 
859     /* only change X position of widget */
860     xtgeom.request_mode = CWX|CWY;
861     xtgeom.x = x;
862     xtgeom.y = y;
863     (void) XtMakeGeometryRequest(popup, &xtgeom, &comp);
864 
865     /* now pop it up */
866     XtPopup(popup, XtGrabNonexclusive);
867     popup_up = True;
868     /* if the file message window is up add it to the grab */
869     file_msg_add_grab();
870 
871     /* insure that the most recent colormap is installed */
872     set_cmap(XtWindow(popup));
873     (void) XSetWMProtocols(tool_d, XtWindow(popup), &wm_delete_window, 1);
874 }
875 
876 static void
reread_picfile(Widget panel_local,XtPointer closure,XtPointer call_data)877 reread_picfile(Widget panel_local, XtPointer closure, XtPointer call_data)
878 {
879 	(void)panel_local;
880 	(void)closure;
881 	(void)call_data;
882     Boolean	    dum;
883 
884     if (new_l->pic->pic_cache == 0)
885 	return;		/* hmm, shouldn't get here if no picture */
886 
887     changed = True;
888     reread_file = True;	/* force remapping colors */
889     list_delete_line(&objects.lines, new_l);
890     redisplay_line(new_l);
891     /* reread the file */
892     read_picobj(new_l->pic, new_l->pic->pic_cache->file, new_l->pen_color, True, &dum);
893     /* calculate h/w ratio */
894     new_l->pic->hw_ratio = (float) new_l->pic->pic_cache->bit_size.y/new_l->pic->pic_cache->bit_size.x;
895     get_new_line_values();
896     list_add_line(&objects.lines, new_l);
897     redisplay_line(new_l);
898 }
899 
900 
901 static void
edit_spline_point(F_spline * spline,int type,int x,int y,F_point * previous_point,F_point * the_point)902 edit_spline_point(F_spline *spline, int type, int x, int y,
903 		F_point *previous_point, F_point *the_point)
904 {
905 	(void)x;
906 	(void)y;
907 
908     if (type!=O_SPLINE) {
909 	put_msg("Only spline points can be edited");
910 	return;
911     }
912 
913     if (open_spline(spline) && (previous_point==NULL || the_point->next==NULL)) {
914 	put_msg("Cannot edit end-points");
915 	return;
916     }
917 
918     changed = False;
919     make_window_spline_point(spline, the_point->x, the_point->y);
920 
921     XtPopup(popup, XtGrabNonexclusive);
922     /* if the file message window is up add it to the grab */
923     file_msg_add_grab();
924 
925     /* insure that the most recent colormap is installed */
926     set_cmap(XtWindow(popup));
927     (void) XSetWMProtocols(tool_d, XtWindow(popup), &wm_delete_window, 1);
928 }
929 
930 static void
expand_pic(Widget w,XButtonEvent * ev,String * params,Cardinal * num_params)931 expand_pic(Widget w, XButtonEvent *ev, String *params, Cardinal *num_params)
932 {
933 	(void)w;
934 	(void)ev;
935 	(void)params;
936 	(void)num_params;
937 
938     struct f_point  p1, p2;
939     int		    dx, dy, rotation;
940     float	    ratio;
941     register float  orig_ratio = new_l->pic->hw_ratio;
942 
943     p1.x = panel_get_dim_value(x1_panel);
944     p1.y = panel_get_dim_value(y1_panel);
945     p2.x = panel_get_dim_value(x2_panel);
946     p2.y = panel_get_dim_value(y2_panel);
947     /* size is upper-lower */
948     dx = p2.x - p1.x;
949     dy = p2.y - p1.y;
950     rotation = what_rotation(dx,dy);
951     if (dx == 0 || dy == 0 || orig_ratio == 0.0)
952 	return;
953     if (((rotation == 0 || rotation == 180) && !flip_pic_flag) ||
954 	(rotation != 0 && rotation != 180 && flip_pic_flag)) {
955 	ratio = (float) fabs((double) dy / (double) dx);
956 	if (ratio < orig_ratio)
957 	    p2.y = p1.y + signof(dy) * (int) (fabs((double) dx) * orig_ratio);
958 	else
959 	    p2.x = p1.x + signof(dx) * (int) (fabs((double) dy) / orig_ratio);
960     } else {
961 	ratio = (float) fabs((double) dx / (double) dy);
962 	if (ratio < orig_ratio)
963 	    p2.x = p1.x + signof(dx) * (int) (fabs((double) dy) * orig_ratio);
964 	else
965 	    p2.y = p1.y + signof(dy) * (int) (fabs((double) dx) / orig_ratio);
966     }
967     panel_set_scaled_int(x2_panel, p2.x);
968     panel_set_scaled_int(y2_panel, p2.y);
969     sprintf(buf, "%1.1f", orig_ratio);
970     FirstArg(XtNlabel, buf);
971     SetValues(hw_ratio_panel);
972 }
973 
974 static void
shrink_pic(Widget w,XButtonEvent * ev,String * params,Cardinal * num_params)975 shrink_pic(Widget w, XButtonEvent *ev, String *params, Cardinal *num_params)
976 {
977 	(void)w;
978 	(void)ev;
979 	(void)params;
980 	(void)num_params;
981 
982     struct f_point  p1, p2;
983     int		    dx, dy, rotation;
984     float	    ratio;
985     register float  orig_ratio = new_l->pic->hw_ratio;
986 
987     p1.x = panel_get_dim_value(x1_panel);
988     p1.y = panel_get_dim_value(y1_panel);
989     p2.x = panel_get_dim_value(x2_panel);
990     p2.y = panel_get_dim_value(y2_panel);
991     /* size is upper-lower */
992     dx = p2.x - p1.x;
993     dy = p2.y - p1.y;
994     rotation = what_rotation(dx,dy);
995     if (dx == 0 || dy == 0 || orig_ratio == 0.0)
996 	return;
997     if (((rotation == 0 || rotation == 180) && !flip_pic_flag) ||
998 	(rotation != 0 && rotation != 180 && flip_pic_flag)) {
999 	ratio = (float) fabs((double) dy / (double) dx);
1000 	/* upper coord is lower+size */
1001 	if (ratio > orig_ratio)
1002 	    p2.y = p1.y + signof(dy) * (int) (fabs((double) dx) * orig_ratio);
1003 	else
1004 	    p2.x = p1.x + signof(dx) * (int) (fabs((double) dy) / orig_ratio);
1005     } else {
1006 	ratio = (float) fabs((double) dx / (double) dy);
1007 	if (ratio > orig_ratio)
1008 	    p2.x = p1.x + signof(dx) * (int) (fabs((double) dy) * orig_ratio);
1009 	else
1010 	    p2.y = p1.y + signof(dy) * (int) (fabs((double) dx) / orig_ratio);
1011     }
1012     panel_set_scaled_int(x2_panel, p2.x);
1013     panel_set_scaled_int(y2_panel, p2.y);
1014     sprintf(buf, "%1.1f", orig_ratio);
1015     FirstArg(XtNlabel, buf);
1016     SetValues(hw_ratio_panel);
1017 }
1018 
1019 static void
origsize_pic(Widget w,XButtonEvent * ev,String * params,Cardinal * num_params)1020 origsize_pic(Widget w, XButtonEvent *ev, String *params, Cardinal *num_params)
1021 {
1022 	(void)w;
1023 	(void)ev;
1024 	(void)params;
1025 	(void)num_params;
1026 
1027     struct f_point  p1, p2;
1028     int		    dx, dy;
1029     register float  orig_ratio = new_l->pic->hw_ratio;
1030 
1031     p1.x = panel_get_dim_value(x1_panel);
1032     p1.y = panel_get_dim_value(y1_panel);
1033     p2.x = panel_get_dim_value(x2_panel);
1034     p2.y = panel_get_dim_value(y2_panel);
1035 
1036     /* size is upper-lower */
1037     dx = p2.x - p1.x;
1038     dy = p2.y - p1.y;
1039 
1040     if (dx == 0 || dy == 0 || orig_ratio == 0.0)
1041 	return;
1042 
1043     /* upper coord is lower+size */
1044     p2.x = p1.x + signof(dx) * new_l->pic->pic_cache->size_x;
1045     p2.y = p1.y + signof(dy) * new_l->pic->pic_cache->size_y;
1046     panel_set_scaled_int(x2_panel, p2.x);
1047     panel_set_scaled_int(y2_panel, p2.y);
1048     sprintf(buf, "%1.1f", orig_ratio);
1049     FirstArg(XtNlabel, buf);
1050     SetValues(hw_ratio_panel);
1051 }
1052 
1053 static void
scale_percent_pic(Widget w,XButtonEvent * ev,String * params,Cardinal * num_params)1054 scale_percent_pic(Widget w, XButtonEvent *ev, String *params,
1055 		Cardinal *num_params)
1056 {
1057 	(void)w;
1058 	(void)ev;
1059 	(void)params;
1060 	(void)num_params;
1061 
1062     struct f_point  p1, p2;
1063     int		    dx, dy;
1064     float	    orig_ratio = new_l->pic->hw_ratio;
1065     float	    pct;
1066 
1067     if (orig_ratio == 0.0)
1068 	return;
1069 
1070     p1.x = panel_get_dim_value(x1_panel);
1071     p1.y = panel_get_dim_value(y1_panel);
1072     p2.x = panel_get_dim_value(x2_panel);
1073     p2.y = panel_get_dim_value(y2_panel);
1074 
1075     /* get the percent scale */
1076     pct = atof(panel_get_value(percent_entry));
1077     if (pct <= 0.0) {
1078 	panel_set_value(percent_entry,"0.001");
1079 	pct = 0.001;
1080     }
1081 
1082     /* find direction of corners - size is upper-lower */
1083     dx = p2.x - p1.x;
1084     dy = p2.y - p1.y;
1085 
1086     /* upper coord is lower+size */
1087     p2.x = p1.x + (signof(dx) * new_l->pic->pic_cache->size_x * pct/100.0);
1088     p2.y = p1.y + (signof(dy) * new_l->pic->pic_cache->size_y * pct/100.0);
1089     panel_set_scaled_int(x2_panel, p2.x);
1090     panel_set_scaled_int(y2_panel, p2.y);
1091     sprintf(buf, "%1.1f", orig_ratio);
1092     FirstArg(XtNlabel, buf);
1093     SetValues(hw_ratio_panel);
1094 }
1095 
1096 
1097 /* make a panel for the user to change the comments for the whole figure */
1098 
1099 static void
make_window_figure(void)1100 make_window_figure(void)
1101 {
1102     generic_window("Whole Figure", "", &figure_ic, done_figure_comments,
1103 		NO_GENERICS, NO_ARROWS, objects.comments);
1104 }
1105 
1106 static void
done_figure_comments(void)1107 done_figure_comments(void)
1108 {
1109     char	*s;
1110 
1111     switch (button_result) {
1112       case DONE:
1113 	/* save old comments */
1114 	saved_objects.comments = objects.comments;
1115 	/* get new comments */
1116 	s = panel_get_value(comments_panel);
1117 	/* allocate space and copy */
1118 	copy_comments(&s, &objects.comments);
1119 	clean_up();
1120 	set_action_object(F_EDIT, O_FIGURE);
1121 	set_modifiedflag();
1122 	break;
1123       case CANCEL:
1124 	break;
1125     }
1126 }
1127 
1128 static void
make_window_compound(F_compound * c)1129 make_window_compound(F_compound *c)
1130 {
1131     F_text	*t;
1132     int		 i;
1133     Widget	 save_form, viewp;
1134     F_pos	 dimen;		/* need temp storage for width, height panel */
1135 
1136     set_cursor(panel_cursor);
1137     mask_toggle_compoundmarker(c);
1138     old_c = copy_compound(c);
1139     new_c = c;
1140 
1141     generic_window("COMPOUND", "", &glue_ic, done_compound,
1142 				NO_GENERICS, NO_ARROWS, c->comments);
1143 
1144     /* tell the pulldown unit menu which panels to convert */
1145     init_convert_array();
1146     f_pair_panel(&c->nwcorner, "Top left corner",
1147 				&x1_panel, "X =", &y1_panel, "Y =", True);
1148 
1149     /* override translations for Return to reposition top-left of compound */
1150     XtOverrideTranslations(x1_panel, XtParseTranslationTable(edit_compound_translations));
1151     XtOverrideTranslations(y1_panel, XtParseTranslationTable(edit_compound_translations));
1152 
1153     f_pair_panel(&c->secorner, "Bottom right corner",
1154 				&x2_panel, "X =", &y2_panel, "Y =", False);
1155 
1156     /* override translations for Return to reposition bottom-right of compound */
1157     XtOverrideTranslations(x2_panel, XtParseTranslationTable(edit_compound_translations));
1158     XtOverrideTranslations(y2_panel, XtParseTranslationTable(edit_compound_translations));
1159 
1160     dimen.x = c->secorner.x - c->nwcorner.x;
1161     dimen.y = c->secorner.y - c->nwcorner.y;
1162     f_pair_panel(&dimen, "Dimensions", &width_panel, "Width =",
1163 					&height_panel, "Height =", False);
1164 
1165     /* override translations for Return to scale compound */
1166     XtOverrideTranslations(width_panel, XtParseTranslationTable(edit_compound_translations));
1167     XtOverrideTranslations(height_panel, XtParseTranslationTable(edit_compound_translations));
1168 
1169     FirstArg(XtNlabel, "Depths");
1170     NextArg(XtNborderWidth, 0);
1171     NextArg(XtNfromVert, below);
1172     NextArg(XtNtop, XtChainBottom);
1173     NextArg(XtNbottom, XtChainBottom);
1174     NextArg(XtNleft, XtChainLeft);
1175     NextArg(XtNright, XtChainLeft);
1176     below = XtCreateManagedWidget("min_depth", labelWidgetClass,
1177 				       form, Args, ArgCount);
1178 
1179     /* show min/max depths in compound */
1180     min_compound_depth = find_smallest_depth(c);
1181     sprintf(buf,"Minimum: %d", min_compound_depth);
1182     FirstArg(XtNlabel, buf);
1183     NextArg(XtNborderWidth, 0);
1184     NextArg(XtNhorizDistance, 10);
1185     NextArg(XtNfromVert, below);
1186     NextArg(XtNtop, XtChainBottom);
1187     NextArg(XtNbottom, XtChainBottom);
1188     NextArg(XtNleft, XtChainLeft);
1189     NextArg(XtNright, XtChainLeft);
1190     min_depth_w = beside = XtCreateManagedWidget("min_depth", labelWidgetClass,
1191 				       form, Args, ArgCount);
1192     sprintf(buf,"Maximum: %d", find_largest_depth(c));
1193     FirstArg(XtNlabel, buf);
1194     NextArg(XtNborderWidth, 0);
1195     NextArg(XtNfromHoriz, beside);
1196     NextArg(XtNfromVert, below);
1197     NextArg(XtNtop, XtChainBottom);
1198     NextArg(XtNbottom, XtChainBottom);
1199     NextArg(XtNleft, XtChainLeft);
1200     NextArg(XtNright, XtChainLeft);
1201     max_depth_w = below = XtCreateManagedWidget("max_depth", labelWidgetClass,
1202 				       form, Args, ArgCount);
1203 
1204     /* button to collapse depths */
1205     FirstArg(XtNlabel, "Collapse Depths");
1206     NextArg(XtNfromVert, below);
1207     NextArg(XtNhorizDistance, 10);
1208     NextArg(XtNtop, XtChainBottom);
1209     NextArg(XtNbottom, XtChainBottom);
1210     NextArg(XtNleft, XtChainLeft);
1211     NextArg(XtNright, XtChainLeft);
1212     below = XtCreateManagedWidget("collapse_depths", commandWidgetClass,
1213 				       form, Args, ArgCount);
1214     XtAddCallback(below, XtNcallback, (XtCallbackProc) collapse_depth, (XtPointer) NULL);
1215 
1216     int_label(object_count(c), "Number of objects", &num_objects);
1217 
1218     /* make a form to contain the text objects in the compound */
1219     if (c->texts) {
1220 	/* save toplevel form so that the following widgets will go in this sub-form */
1221 	save_form = form;
1222 	/* form to frame the text heading with the texts */
1223 	FirstArg(XtNborderWidth, 1);
1224 	NextArg(XtNfromVert, below);
1225 	NextArg(XtNtop, XtChainBottom);
1226 	NextArg(XtNbottom, XtChainBottom);
1227 	NextArg(XtNleft, XtChainLeft);
1228 	NextArg(XtNright, XtChainRight);
1229 	form = XtCreateManagedWidget("form", formWidgetClass, save_form,
1230 					Args, ArgCount);
1231 	FirstArg(XtNlabel, "Text objects in this compound");
1232 	NextArg(XtNborderWidth, 0);
1233 	NextArg(XtNtop, XtChainBottom);
1234 	NextArg(XtNbottom, XtChainBottom);
1235 	NextArg(XtNleft, XtChainLeft);
1236 	NextArg(XtNright, XtChainLeft);
1237 	below = XtCreateManagedWidget("label", labelWidgetClass, form,
1238 					Args, ArgCount);
1239 	/* first make a viewport in case we need a scrollbar */
1240 	FirstArg(XtNallowVert, True);
1241 	NextArg(XtNborderWidth, 0);
1242 	NextArg(XtNfromVert, below);
1243 	NextArg(XtNtop, XtChainBottom);
1244 	NextArg(XtNbottom, XtChainBottom);
1245 	NextArg(XtNleft, XtChainLeft);
1246 	NextArg(XtNright, XtChainRight);
1247 	viewp = XtCreateManagedWidget("textview", viewportWidgetClass, form,
1248 					Args, ArgCount);
1249 	/* form in the viewport */
1250 	FirstArg(XtNborderWidth, 0);
1251 	NextArg(XtNtop, XtChainBottom);
1252 	NextArg(XtNbottom, XtChainBottom);
1253 	NextArg(XtNleft, XtChainLeft);
1254 	NextArg(XtNright, XtChainRight);
1255 	form = XtCreateManagedWidget("form", formWidgetClass, viewp, Args, ArgCount);
1256 	below = NULL;
1257 	for (t=c->texts, i=0; t && i<MAX_COMPOUND_TEXT_PANELS; t=t->next, i++) {
1258 	    str_panel(t->cstring, "Text", &compound_text_panels[i], 220, True, False);
1259 	    /* make the margins small */
1260 	    FirstArg(XtNhorizDistance, 1);
1261 	    SetValues(below);
1262 	    if (i>0) {
1263 		/* scrunch the texts together vertically */
1264 		FirstArg(XtNvertDistance, 1);
1265 		SetValues(below);
1266 	    }
1267 	}
1268 	/* if many texts, set height of viewport */
1269 	if (i > 8) {
1270 	    FirstArg(XtNheight, 320);
1271 	    SetValues(viewp);
1272 	}
1273 	/* restore original form */
1274 	form = save_form;
1275     }
1276 }
1277 
1278 /* come here when user presses return in any compound corner/size entry */
1279 
1280 static void
modify_compound(Widget w)1281 modify_compound(Widget w)
1282 {
1283     if (w == x1_panel || w == y1_panel)
1284 	reposition_top();
1285     else if (w == x2_panel || w == y2_panel)
1286 	reposition_bottom();
1287     else if (w == width_panel || w == height_panel)
1288 	rescale_compound();
1289 }
1290 
1291 /* come here when user presses return in picture X/Y position */
1292 
1293 static void
reposition_picture(Widget w)1294 reposition_picture(Widget w)
1295 {
1296     int x1, y1, x2, y2;
1297     int width, height, rotation;
1298 
1299     x1 = panel_get_dim_value(x1_panel);
1300     y1 = panel_get_dim_value(y1_panel);
1301     x2 = panel_get_dim_value(x2_panel);
1302     y2 = panel_get_dim_value(y2_panel);
1303     /* calculate new width, height - keep sign for now to determine rotation */
1304     width = x2-x1;
1305     height = y2-y1;
1306     rotation = 0;
1307     if (width < 0 && height < 0)
1308 	rotation = 2;	/* 180 degrees */
1309     else if (width < 0 && height >= 0)
1310 	rotation = 3;	/* 270 degrees */
1311     else if (height < 0 && width >= 0)
1312 	rotation = 1;	/* 90 degrees */
1313     FirstArg(XtNlabel, rotation_items[rotation]);
1314     SetValues(rotation_panel);
1315 
1316     /* absolute value */
1317     width = abs(width);
1318     height = abs(height);
1319     if (width > 50*PIX_PER_INCH) {
1320 	file_msg("Picture too wide (> 50 inches)");
1321 	return;
1322     }
1323     if (height > 50*PIX_PER_INCH) {
1324 	file_msg("Picture too tall (> 50 inches)");
1325 	return;
1326     }
1327     /* put back */
1328     panel_set_scaled_int(width_panel, width);
1329     panel_set_scaled_int(height_panel, height);
1330     /* resize the picture */
1331     edit_apply(w, (XButtonEvent *) 0, (String*) 0, (Cardinal*) 0);
1332 }
1333 
1334 /* come here when user presses return in picture width or height */
1335 
1336 static void
resize_picture(Widget w)1337 resize_picture(Widget w)
1338 {
1339     int x1, y1, x2, y2;
1340     int width, height;
1341 
1342     x1 = panel_get_dim_value(x1_panel);
1343     y1 = panel_get_dim_value(y1_panel);
1344     x2 = panel_get_dim_value(x2_panel);
1345     y2 = panel_get_dim_value(y2_panel);
1346     width = panel_get_dim_value(width_panel);
1347     height = panel_get_dim_value(height_panel);
1348     if (width > 50*PIX_PER_INCH) {
1349 	file_msg("Picture too wide (> 50 inches)");
1350 	return;
1351     }
1352     if (height > 50*PIX_PER_INCH) {
1353 	file_msg("Picture too tall (> 50 inches)");
1354 	return;
1355     }
1356     if (w == width_panel) {
1357 	/* adjust x to reflect new width */
1358 	if (x1 < x2) {
1359 	    x2 = x1 + width;
1360 	    panel_set_scaled_int(x2_panel, x2);
1361 	} else {
1362 	    x1 = x2 + width;
1363 	    panel_set_scaled_int(x1_panel, x1);
1364 	}
1365     } else {
1366 	/* adjust y to reflect new height */
1367 	if (y1 < y2) {
1368 	    y2 = y1 + height;
1369 	    panel_set_scaled_int(y2_panel, y2);
1370 	} else {
1371 	    y1 = y2 + height;
1372 	    panel_set_scaled_int(y1_panel, y1);
1373 	}
1374     }
1375     /* resize the picture */
1376     edit_apply(w, (XButtonEvent *) 0, (String*) 0, (Cardinal*) 0);
1377 }
1378 
1379 /* reposition the compound using the user's new upper-left values */
1380 
1381 static void
reposition_top(void)1382 reposition_top(void)
1383 {
1384     int		 nw_x, nw_y, se_x, se_y, dx, dy;
1385 
1386     /* get user's new top-left corner values */
1387     nw_x = panel_get_dim_value(x1_panel);
1388     nw_y = panel_get_dim_value(y1_panel);
1389 
1390     /* get shift */
1391     dx = nw_x - new_c->nwcorner.x;
1392     dy = nw_y - new_c->nwcorner.y;
1393 
1394     /* adjust lower-right corner */
1395     se_x = new_c->secorner.x + dx;
1396     se_y = new_c->secorner.y + dy;
1397 
1398     /* and update those values in panel */
1399     panel_set_scaled_int(x2_panel, se_x);
1400     panel_set_scaled_int(y2_panel, se_y);
1401 
1402     /* update the compound on the screen */
1403     button_result = APPLY;
1404     done_compound();
1405 }
1406 
1407 /* reposition the compound using the user's new lower-right values */
1408 
1409 static void
reposition_bottom(void)1410 reposition_bottom(void)
1411 {
1412     int		 nw_x, nw_y, se_x, se_y, dx, dy;
1413 
1414     /* get user's new lower-right corner values */
1415     se_x = panel_get_dim_value(x2_panel);
1416     se_y = panel_get_dim_value(y2_panel);
1417 
1418     /* get shift */
1419     dx = se_x - new_c->secorner.x;
1420     dy = se_y - new_c->secorner.y;
1421 
1422     /* adjust upper-left corner */
1423     nw_x = new_c->nwcorner.x + dx;
1424     nw_y = new_c->nwcorner.y + dy;
1425 
1426     /* and update those values in panel */
1427     panel_set_scaled_int(x1_panel, nw_x);
1428     panel_set_scaled_int(y1_panel, nw_y);
1429 
1430     /* update the compound on the screen */
1431     button_result = APPLY;
1432     done_compound();
1433 }
1434 
1435 /* rescale the compound using the user's new width/height values */
1436 /* it is rescaled relative to the upper-left corner */
1437 
1438 static void
rescale_compound(void)1439 rescale_compound(void)
1440 {
1441     int		 width, height, se_x, se_y;
1442 
1443     /* get user's new width/height values */
1444     width = panel_get_dim_value(width_panel);
1445     height = panel_get_dim_value(height_panel);
1446 
1447     /* adjust lower-right corner with new size */
1448     se_x = new_c->nwcorner.x + width;
1449     se_y = new_c->nwcorner.y + height;
1450 
1451     /* update the lower-right corner values in panel */
1452     panel_set_scaled_int(x2_panel, se_x);
1453     panel_set_scaled_int(y2_panel, se_y);
1454 
1455     /* update the compound on the screen */
1456     button_result = APPLY;
1457     done_compound();
1458 }
1459 
1460 static void
get_new_compound_values(void)1461 get_new_compound_values(void)
1462 {
1463     int		 dx, dy, nw_x, nw_y, se_x, se_y;
1464     float	 scalex, scaley;
1465     F_text	*t;
1466     int		 i;
1467     PR_SIZE	 size;
1468 
1469     nw_x = panel_get_dim_value(x1_panel);
1470     nw_y = panel_get_dim_value(y1_panel);
1471     se_x = panel_get_dim_value(x2_panel);
1472     se_y = panel_get_dim_value(y2_panel);
1473     dx = nw_x - new_c->nwcorner.x;
1474     dy = nw_y - new_c->nwcorner.y;
1475     if (new_c->nwcorner.x - new_c->secorner.x == 0)
1476 	scalex = 0.0;
1477     else
1478 	scalex = (float) (nw_x - se_x) /
1479 		(float) (new_c->nwcorner.x - new_c->secorner.x);
1480     if (new_c->nwcorner.y - new_c->secorner.y == 0)
1481 	scaley = 0.0;
1482     else
1483 	scaley = (float) (nw_y - se_y) /
1484 		(float) (new_c->nwcorner.y - new_c->secorner.y);
1485 
1486     /* get any comments */
1487     new_c->comments = strdup(panel_get_value(comments_panel));
1488 
1489     /* get any new text object values */
1490     for (t=new_c->texts,i=0; t ;t=t->next,i++) {
1491 	if (t->cstring)
1492 	    free(t->cstring);
1493 	t->cstring = strdup(panel_get_value(compound_text_panels[i]));
1494 	/* calculate new size */
1495 	/* get the fontstruct for zoom = 1 to get the size of the string */
1496 	canvas_font = lookfont(x_fontnum(psfont_text(t), t->font), t->size);
1497 	size = textsize(canvas_font, strlen(t->cstring), t->cstring);
1498 	t->length = size.length;
1499 	t->ascent = size.ascent;
1500 	t->descent = size.descent;
1501     }
1502 
1503     translate_compound(new_c, dx, dy);
1504     scale_compound(new_c, scalex, scaley, nw_x, nw_y);
1505 }
1506 
1507 static void
done_compound(void)1508 done_compound(void)
1509 {
1510     switch (button_result) {
1511 
1512       case APPLY:
1513 	changed = True;
1514 	list_delete_compound(&objects.compounds, new_c);
1515 	redisplay_compound(new_c);
1516 	get_new_compound_values();
1517 	compound_bound(new_c, &new_c->nwcorner.x, &new_c->nwcorner.y,
1518 		   &new_c->secorner.x, &new_c->secorner.y);
1519 	/* update top-left and bottom-right values in panel from new bounding box */
1520 	panel_set_scaled_int(x1_panel, new_c->nwcorner.x);
1521 	panel_set_scaled_int(y1_panel, new_c->nwcorner.y);
1522 	panel_set_scaled_int(x2_panel, new_c->secorner.x);
1523 	panel_set_scaled_int(y2_panel, new_c->secorner.y);
1524 	list_add_compound(&objects.compounds, new_c);
1525 	redisplay_compound(new_c);
1526 	toggle_compoundmarker(new_c);
1527 	break;
1528 
1529       case DONE:
1530 	get_new_compound_values();
1531 	compound_bound(new_c, &new_c->nwcorner.x, &new_c->nwcorner.y,
1532 		   &new_c->secorner.x, &new_c->secorner.y);
1533 	/* update top-left and bottom-right values in panel from new bounding box */
1534 	panel_set_scaled_int(x1_panel, new_c->nwcorner.x);
1535 	panel_set_scaled_int(y1_panel, new_c->nwcorner.y);
1536 	panel_set_scaled_int(x2_panel, new_c->secorner.x);
1537 	panel_set_scaled_int(y2_panel, new_c->secorner.y);
1538 	redisplay_compounds(new_c, old_c);
1539 	clean_up();
1540 	old_c->next = new_c;
1541 	set_latestcompound(old_c);
1542 	set_action_object(F_EDIT, O_COMPOUND);
1543 	set_modifiedflag();
1544 	remove_compound_depth(old_c);
1545 	add_compound_depth(new_c);
1546 	/* if this was a place-and-edit, continue with library place */
1547 	if (edit_remember_lib_mode) {
1548 	    edit_remember_lib_mode = False;
1549 	    put_selected();
1550 	    /* and set flag to reset cursor back to place lib */
1551 	    lib_cursor = True;
1552 	}
1553 	/* if this was a dimension line edit, continue with line mode */
1554 	if (edit_remember_dimline_mode) {
1555 	    edit_remember_dimline_mode = False;
1556 	    line_drawing_selected();
1557 	    /* and set flag to reset cursor back to place lib */
1558 	    dim_cursor = True;
1559 	}
1560 	break;
1561 
1562       case CANCEL:
1563 	list_delete_compound(&objects.compounds, new_c);
1564 	list_add_compound(&objects.compounds, old_c);
1565 	if (saved_objects.compounds && saved_objects.compounds->next &&
1566 	    saved_objects.compounds->next == new_c)
1567 		saved_objects.compounds->next = old_c;
1568 	else if (saved_objects.compounds == new_c)
1569 		saved_objects.compounds = old_c;
1570 	if (changed)
1571 	    redisplay_compounds(old_c, new_c);
1572 	else
1573 	    toggle_compoundmarker(old_c);
1574 	free_compound(&new_c);
1575 	/* if this was a place-and-edit, continue with library place */
1576 	if (edit_remember_lib_mode) {
1577 	    edit_remember_lib_mode = False;
1578 	    put_selected();
1579 	    /* and set flag to reset cursor back to place lib */
1580 	    lib_cursor = True;
1581 	}
1582 	/* if this was a dimension line edit, continue with line mode */
1583 	if (edit_remember_dimline_mode) {
1584 	    edit_remember_dimline_mode = False;
1585 	    line_drawing_selected();
1586 	    /* and set flag to reset cursor back to place lib */
1587 	    dim_cursor = True;
1588 	}
1589 	break;
1590     }
1591 }
1592 
1593 static void
make_window_line(F_line * l)1594 make_window_line(F_line *l)
1595 {
1596     F_point	p1, p2;
1597     int		dx, dy, rotation;
1598     float	ratio;
1599     unsigned	i;
1600     int		vdist;
1601     F_pos	dimen;		/* need temp storage for width, height panel */
1602     Widget	type;
1603 
1604     set_cursor(panel_cursor);
1605     mask_toggle_linemarker(l);
1606     old_l = copy_line(l);
1607     new_l = l;
1608 
1609     put_generic_vals(new_l);
1610     put_cap_style(new_l);
1611     put_join_style(new_l);
1612     pen_color = new_l->pen_color;
1613     fill_color = new_l->fill_color;
1614 
1615     /* tell the pulldown unit menu which panels to convert */
1616     init_convert_array();
1617 
1618     /* single-point lines don't get arrows - delete any that might already exist */
1619     if (new_l->points->next == NULL) {
1620 	if (new_l->for_arrow)
1621 		free((char *) new_l->for_arrow);
1622 	if (new_l->back_arrow)
1623 		free((char *) new_l->back_arrow);
1624 	new_l->for_arrow = new_l->back_arrow = (F_arrow *) NULL;
1625     }
1626     switch (new_l->type) {
1627       case T_POLYLINE:
1628 	put_generic_arrows(new_l);
1629 	/* don't make arrow panels if single-point line */
1630 	generic_window("POLYLINE", "Polyline", &line_ic, done_line,
1631 			GENERICS, (new_l->points->next? ARROWS: NO_ARROWS), l->comments);
1632 	points_panel(new_l->points);
1633 	break;
1634       case T_POLYGON:
1635 	generic_window("POLYLINE", "Polygon", &polygon_ic, done_line,
1636 			GENERICS, NO_ARROWS, l->comments);
1637 	points_panel(new_l->points);
1638 	break;
1639       case T_BOX:
1640 	generic_window("POLYLINE", "Box", &box_ic, done_line,
1641 			GENERICS, NO_ARROWS, l->comments);
1642 	p1 = *new_l->points;
1643 	p2 = *new_l->points->next->next;
1644 	xy_panel(p1.x, p1.y, "First corner", &x1_panel, &y1_panel, True);
1645 	xy_panel(p2.x, p2.y, "Opposite corner", &x2_panel, &y2_panel, False);
1646 	break;
1647       case T_ARCBOX:
1648 	generic_window("POLYLINE", "ArcBox", &arc_box_ic, done_line,
1649 			GENERICS, NO_ARROWS, l->comments);
1650 	p1 = *new_l->points;
1651 	p2 = *new_l->points->next->next;
1652 	(void) int_panel(new_l->radius, form, "Corner radius", (Widget) 0, &radius,
1653 					MIN_BOX_RADIUS, MAX_BOX_RADIUS, 1);
1654 	xy_panel(p1.x, p1.y, "First corner", &x1_panel, &y1_panel, True);
1655 	xy_panel(p2.x, p2.y, "Opposite corner", &x2_panel, &y2_panel, False);
1656 	break;
1657       case T_PICTURE:
1658 	old_l->type = T_BOX;	/* so colors of old won't be included in new */
1659 	generic_window("POLYLINE", "Picture Object", &picobj_ic, done_line,
1660 			NO_GENERICS, NO_ARROWS, l->comments);
1661 
1662 	below = pen_color_selection_panel();
1663 	/* only the XBM (bitmap) type has a pen color */
1664 	if (new_l->pic != 0 && new_l->pic->pic_cache && new_l->pic->pic_cache->subtype != T_PIC_XBM)
1665 	    XtSetSensitive(pen_col_button, False);
1666 
1667 	(void) int_panel(new_l->depth, form, "     Depth", (Widget) 0, &depth_panel,
1668 				MIN_DEPTH, MAX_DEPTH, 1);
1669 	str_panel(new_l->pic->pic_cache? new_l->pic->pic_cache->file: "", "Picture filename",
1670 				&pic_name_panel, 290, False, False);
1671 
1672 	/* make a button to reread the picture file */
1673 	FirstArg(XtNfromVert, beside);
1674 	NextArg(XtNhorizDistance, 10);
1675 	NextArg(XtNlabel, "Reread");
1676 	NextArg(XtNsensitive,
1677 		(new_l->pic->pic_cache && new_l->pic->pic_cache->file[0])); /* only sensitive if there is a filename */
1678 	NextArg(XtNtop, XtChainBottom);
1679 	NextArg(XtNbottom, XtChainBottom);
1680 	NextArg(XtNleft, XtChainLeft);
1681 	NextArg(XtNright, XtChainLeft);
1682 	reread = below = XtCreateManagedWidget("reread", commandWidgetClass,
1683 				       form, Args, ArgCount);
1684 	XtAddCallback(below, XtNcallback, (XtCallbackProc) reread_picfile, (XtPointer) NULL);
1685 
1686 	/* add browse button for image files */
1687 	FirstArg(XtNlabel, "Browse");
1688 	NextArg(XtNfromHoriz, below);
1689 	NextArg(XtNfromVert, beside);
1690 	NextArg(XtNhorizDistance, 10);
1691 	NextArg(XtNtop, XtChainBottom);
1692 	NextArg(XtNbottom, XtChainBottom);
1693 	NextArg(XtNleft, XtChainLeft);
1694 	NextArg(XtNright, XtChainLeft);
1695         but1 = XtCreateManagedWidget("browse", commandWidgetClass,
1696 			form, Args, ArgCount);
1697         XtAddCallback(but1, XtNcallback,
1698 		(XtCallbackProc) browse_button, (XtPointer) NULL);
1699 
1700 	FirstArg(XtNfromVert, below);
1701 	NextArg(XtNborderWidth, 0);
1702 	NextArg(XtNlabel, "Type:");
1703 	NextArg(XtNtop, XtChainBottom);
1704 	NextArg(XtNbottom, XtChainBottom);
1705 	NextArg(XtNleft, XtChainLeft);
1706 	NextArg(XtNright, XtChainLeft);
1707 	type = beside = XtCreateManagedWidget("pic_type_label", labelWidgetClass,
1708 				       form, Args, ArgCount);
1709 	vdist = 4;
1710 	for (i=0; i<NUM_PIC_TYPES; i++) {
1711 	    /* start new row after 6 */
1712 	    if (i == 6) {
1713 		below = pic_type_box[0];
1714 		beside = type;
1715 		vdist = 10;
1716 	    }
1717 	    FirstArg(XtNfromHoriz, beside);
1718 	    NextArg(XtNfromVert, below);
1719 	    NextArg(XtNhorizDistance, 7);
1720 	    NextArg(XtNvertDistance, vdist);
1721 	    NextArg(XtNborderWidth, 1);
1722 	    NextArg(XtNtop, XtChainBottom);
1723 	    NextArg(XtNbottom, XtChainBottom);
1724 	    NextArg(XtNleft, XtChainLeft);
1725 	    NextArg(XtNright, XtChainLeft);
1726 	    /* make box red indicating this type of picture file */
1727 	    if (new_l->pic != 0 && new_l->pic->pic_cache &&
1728 			    new_l->pic->pic_cache->subtype == i+1) {
1729 		NextArg(XtNbackground, colors[RED]);
1730 		NextArg(XtNsensitive, True);
1731 	    } else {
1732 		NextArg(XtNbackground, colors[WHITE]);
1733 		NextArg(XtNsensitive, False);
1734 	    }
1735 	    NextArg(XtNlabel, " ");
1736 	    pic_type_box[i] = XtCreateManagedWidget("pic_type_box",
1737 					labelWidgetClass, form, Args, ArgCount);
1738 	    FirstArg(XtNfromHoriz, pic_type_box[i]);
1739 	    NextArg(XtNfromVert, below);
1740 	    NextArg(XtNhorizDistance, 0);
1741 	    NextArg(XtNvertDistance, vdist);
1742 	    NextArg(XtNborderWidth, 0);
1743 	    NextArg(XtNlabel, pic_names[i+1]);
1744 	    NextArg(XtNtop, XtChainBottom);
1745 	    NextArg(XtNbottom, XtChainBottom);
1746 	    NextArg(XtNleft, XtChainLeft);
1747 	    NextArg(XtNright, XtChainLeft);
1748 	    beside = XtCreateManagedWidget("pic_type_name", labelWidgetClass,
1749 				       form, Args, ArgCount);
1750 	}
1751 
1752 	below = beside;
1753 	FirstArg(XtNfromVert, below);
1754 	NextArg(XtNborderWidth, 0);
1755 	NextArg(XtNlabel, "Size:");
1756 	NextArg(XtNtop, XtChainBottom);
1757 	NextArg(XtNbottom, XtChainBottom);
1758 	NextArg(XtNleft, XtChainLeft);
1759 	NextArg(XtNright, XtChainLeft);
1760 	beside = XtCreateManagedWidget("pic_size_label", labelWidgetClass,
1761 				       form, Args, ArgCount);
1762 
1763 	if (new_l->pic != 0 && new_l->pic->pic_cache && new_l->pic->pic_cache->subtype != T_PIC_NONE)
1764 	    sprintf(buf,"%4d x %4d",
1765 		new_l->pic->pic_cache->bit_size.x,new_l->pic->pic_cache->bit_size.y);
1766 	else
1767 	    strcpy(buf,"     --      ");
1768 
1769 	FirstArg(XtNfromVert, below);
1770 	NextArg(XtNfromHoriz, beside);
1771 	NextArg(XtNresizable, False);
1772 	NextArg(XtNborderWidth, 0);
1773 	NextArg(XtNlabel, buf);
1774 	NextArg(XtNtop, XtChainBottom);
1775 	NextArg(XtNbottom, XtChainBottom);
1776 	NextArg(XtNleft, XtChainLeft);
1777 	NextArg(XtNright, XtChainLeft);
1778 	pic_size = XtCreateManagedWidget("pic_size", labelWidgetClass,
1779 				       form, Args, ArgCount);
1780 
1781 	FirstArg(XtNfromVert, below);
1782 	NextArg(XtNborderWidth, 0);
1783 	NextArg(XtNfromHoriz, pic_size);
1784 	NextArg(XtNhorizDistance, 10);
1785 	NextArg(XtNlabel, "Colors:");
1786 	NextArg(XtNtop, XtChainBottom);
1787 	NextArg(XtNbottom, XtChainBottom);
1788 	NextArg(XtNleft, XtChainLeft);
1789 	NextArg(XtNright, XtChainLeft);
1790 	beside = XtCreateManagedWidget("pic_colors_label", labelWidgetClass,
1791 				       form, Args, ArgCount);
1792 
1793 	/* although the EPS may have colors, the actual number is not known */
1794 	if (new_l->pic != 0 && new_l->pic->pic_cache &&
1795 			new_l->pic->pic_cache->numcols > 0 && (
1796 #ifdef HAVE_PNG
1797 	     new_l->pic->pic_cache->subtype == T_PIC_PNG ||
1798 #endif
1799 #ifdef USE_XPM
1800 	     new_l->pic->pic_cache->subtype == T_PIC_XPM ||
1801 #endif
1802 	     new_l->pic->pic_cache->subtype == T_PIC_PCX ||
1803 	     new_l->pic->pic_cache->subtype == T_PIC_PPM ||
1804 	     new_l->pic->pic_cache->subtype == T_PIC_TIF ||
1805 #ifdef HAVE_JPEG
1806 	     new_l->pic->pic_cache->subtype == T_PIC_JPEG ||
1807 #endif
1808 	     new_l->pic->pic_cache->subtype == T_PIC_GIF))
1809 		sprintf(buf,"%3d",new_l->pic->pic_cache->numcols);
1810 	else
1811 		strcpy(buf,"N/A");
1812 
1813 	FirstArg(XtNfromVert, below);
1814 	NextArg(XtNfromHoriz, beside);
1815 	NextArg(XtNresizable, False);
1816 	NextArg(XtNborderWidth, 0);
1817 	NextArg(XtNlabel, buf);
1818 	NextArg(XtNtop, XtChainBottom);
1819 	NextArg(XtNbottom, XtChainBottom);
1820 	NextArg(XtNleft, XtChainLeft);
1821 	NextArg(XtNright, XtChainLeft);
1822 	pic_colors = XtCreateManagedWidget("pic_colors", labelWidgetClass,
1823 				       form, Args, ArgCount);
1824 
1825 	/* transparent color entry for GIF files */
1826 	FirstArg(XtNfromVert, below);
1827 	NextArg(XtNborderWidth, 0);
1828 	NextArg(XtNfromHoriz, pic_colors);
1829 	NextArg(XtNhorizDistance, 10);
1830 	NextArg(XtNlabel, "Transp color:");
1831 	NextArg(XtNtop, XtChainBottom);
1832 	NextArg(XtNbottom, XtChainBottom);
1833 	NextArg(XtNleft, XtChainLeft);
1834 	NextArg(XtNright, XtChainLeft);
1835 	beside = XtCreateManagedWidget("transp_label", labelWidgetClass,
1836 				       form, Args, ArgCount);
1837 	FirstArg(XtNfromVert, below);
1838 	NextArg(XtNborderWidth, 0);
1839 	NextArg(XtNfromHoriz, beside);
1840 	NextArg(XtNtop, XtChainBottom);
1841 	NextArg(XtNbottom, XtChainBottom);
1842 	NextArg(XtNleft, XtChainLeft);
1843 	NextArg(XtNright, XtChainLeft);
1844 	if (new_l->pic->pic_cache && new_l->pic->pic_cache->subtype == T_PIC_GIF) {
1845 	    if (new_l->pic->pic_cache->transp == TRANSP_NONE)
1846 		sprintf(buf,"None");
1847 	    else
1848 		sprintf(buf,"%4d",(unsigned int) new_l->pic->pic_cache->transp);
1849 	} else
1850 	    sprintf(buf," N/A");
1851 	NextArg(XtNlabel, buf);
1852 	transp_color = XtCreateManagedWidget("transp_color", labelWidgetClass,
1853 				       form, Args, ArgCount);
1854 	below = pic_colors;
1855 
1856 	p1 = *new_l->points;
1857 	p2 = *new_l->points->next->next;
1858 
1859 	xy_panel(p1.x, p1.y, "First corner", &x1_panel, &y1_panel, True);
1860 	xy_panel(p2.x, p2.y, "Opposite corner", &x2_panel, &y2_panel, False);
1861 	/* call the resize_picture proc when the user changes x or y */
1862 	XtOverrideTranslations(x1_panel, XtParseTranslationTable(edit_picture_pos_translations));
1863 	XtOverrideTranslations(y1_panel, XtParseTranslationTable(edit_picture_pos_translations));
1864 	XtOverrideTranslations(x2_panel, XtParseTranslationTable(edit_picture_pos_translations));
1865 	XtOverrideTranslations(y2_panel, XtParseTranslationTable(edit_picture_pos_translations));
1866 
1867 	/* width and height */
1868 	dimen.x = abs(p1.x - p2.x);
1869 	dimen.y = abs(p1.y - p2.y);
1870 	f_pair_panel(&dimen, "Dimensions", &width_panel, "Width =",
1871 					&height_panel, "Length =", False);
1872 	/* override translations for Return to resize picture */
1873 	XtOverrideTranslations(width_panel, XtParseTranslationTable(edit_picture_size_translations));
1874 	XtOverrideTranslations(height_panel, XtParseTranslationTable(edit_picture_size_translations));
1875 
1876 	/* make pulldown flipped menu */
1877 	FirstArg(XtNfromVert, below);
1878 	NextArg(XtNborderWidth, 0);
1879 	NextArg(XtNtop, XtChainBottom);
1880 	NextArg(XtNbottom, XtChainBottom);
1881 	NextArg(XtNleft, XtChainLeft);
1882 	NextArg(XtNright, XtChainLeft);
1883 	beside = XtCreateManagedWidget("     Orientation", labelWidgetClass,
1884 				       form, Args, ArgCount);
1885 	FirstArg(XtNfromVert, below);
1886 	NextArg(XtNfromHoriz, beside);
1887 	NextArg(XtNleftBitmap, menu_arrow);	/* use menu arrow for pull-down */
1888 	NextArg(XtNtop, XtChainBottom);
1889 	NextArg(XtNbottom, XtChainBottom);
1890 	NextArg(XtNleft, XtChainLeft);
1891 	NextArg(XtNright, XtChainLeft);
1892 	flip_pic_flag = new_l->pic->flipped;
1893 	flip_pic_panel = XtCreateManagedWidget(
1894 	       flip_pic_items[flip_pic_flag ? 1 : 0], menuButtonWidgetClass,
1895 					       form, Args, ArgCount);
1896 	below = flip_pic_panel;
1897 	make_pulldown_menu(flip_pic_items, XtNumber(flip_pic_items), -1, "",
1898 			       flip_pic_panel, flip_pic_select);
1899 
1900 	/* size is upper-lower */
1901 	dx = p2.x - p1.x;
1902 	dy = p2.y - p1.y;
1903 	rotation = 0;
1904 	if (dx < 0 && dy < 0)
1905 	    rotation = 2; /* 180 */
1906 	else if (dx < 0 && dy >= 0)
1907 	    rotation = 3; /* 270 */
1908 	else if (dx >= 0 && dy < 0)
1909 	    rotation = 1; /* 90 */
1910 	if (dx == 0 || dy == 0)
1911 	    ratio = 0.0;
1912 	else if (((rotation == 0 || rotation == 2) && !flip_pic_flag) ||
1913 		 (rotation != 0 && rotation != 2 && flip_pic_flag))
1914 	    ratio = (float) fabs((double) dy / (double) dx);
1915 	else
1916 	    ratio = (float) fabs((double) dx / (double) dy);
1917 
1918 	/* make pulldown rotation menu */
1919 	FirstArg(XtNfromVert, below);
1920 	NextArg(XtNborderWidth, 0);
1921 	NextArg(XtNtop, XtChainBottom);
1922 	NextArg(XtNbottom, XtChainBottom);
1923 	NextArg(XtNleft, XtChainLeft);
1924 	NextArg(XtNright, XtChainLeft);
1925 	beside = XtCreateManagedWidget("        Rotation", labelWidgetClass,
1926 				       form, Args, ArgCount);
1927 	FirstArg(XtNfromVert, below);
1928 	NextArg(XtNfromHoriz, beside);
1929 	NextArg(XtNleftBitmap, menu_arrow);	/* use menu arrow for pull-down */
1930 	NextArg(XtNtop, XtChainBottom);
1931 	NextArg(XtNbottom, XtChainBottom);
1932 	NextArg(XtNleft, XtChainLeft);
1933 	NextArg(XtNright, XtChainLeft);
1934 	rotation_panel = XtCreateManagedWidget(
1935 	       rotation_items[rotation], menuButtonWidgetClass,
1936 					       form, Args, ArgCount);
1937 	below = rotation_panel;
1938 	make_pulldown_menu(rotation_items, XtNumber(rotation_items), -1, "",
1939 			       rotation_panel, rotation_select);
1940 
1941 
1942 	float_label(ratio,  "  Curr h/w Ratio", &hw_ratio_panel);
1943 	float_label(new_l->pic->hw_ratio, "  Orig h/w Ratio", &orig_hw_panel);
1944 	below = orig_hw_panel;
1945 	FirstArg(XtNfromVert, below);
1946 	NextArg(XtNborderWidth, 0);
1947 	NextArg(XtNtop, XtChainBottom);
1948 	NextArg(XtNbottom, XtChainBottom);
1949 	NextArg(XtNleft, XtChainLeft);
1950 	NextArg(XtNright, XtChainLeft);
1951 	beside = XtCreateManagedWidget("Change h/w ratio", labelWidgetClass,
1952 				       form, Args, ArgCount);
1953 	FirstArg(XtNfromVert, below);
1954 	NextArg(XtNsensitive, new_l->pic->hw_ratio ? True : False);
1955 	NextArg(XtNtop, XtChainBottom);
1956 	NextArg(XtNbottom, XtChainBottom);
1957 	NextArg(XtNleft, XtChainLeft);
1958 	NextArg(XtNright, XtChainLeft);
1959 	NextArg(XtNfromHoriz, beside);
1960 	shrink = XtCreateManagedWidget("Shrink to orig", commandWidgetClass,
1961 				       form, Args, ArgCount);
1962 	XtAddEventHandler(shrink, ButtonReleaseMask, False,
1963 			  (XtEventHandler) shrink_pic, (XtPointer) NULL);
1964 	beside = shrink;
1965 
1966 	/* TRICK - make sure XtNfromHoriz is last resource above */
1967 	ArgCount--;
1968 	/*********************************************************/
1969 
1970 	NextArg(XtNfromHoriz, beside);
1971 	expand = XtCreateManagedWidget("Expand to orig", commandWidgetClass,
1972 				       form, Args, ArgCount);
1973 	XtAddEventHandler(expand, ButtonReleaseMask, False,
1974 			  (XtEventHandler) expand_pic, (XtPointer) NULL);
1975 
1976 	below = expand;
1977 	FirstArg(XtNfromVert, below);
1978 	NextArg(XtNsensitive, new_l->pic->hw_ratio ? True : False);
1979 	NextArg(XtNtop, XtChainBottom);
1980 	NextArg(XtNbottom, XtChainBottom);
1981 	NextArg(XtNleft, XtChainLeft);
1982 	NextArg(XtNright, XtChainLeft);
1983 	origsize = XtCreateManagedWidget("Use original size", commandWidgetClass,
1984 					form, Args, ArgCount);
1985 	XtAddEventHandler(origsize, ButtonReleaseMask, False,
1986 			  (XtEventHandler) origsize_pic, (XtPointer) NULL);
1987 
1988 	FirstArg(XtNfromVert, below);
1989 	NextArg(XtNfromHoriz, origsize);
1990 	NextArg(XtNhorizDistance, 15);
1991 	NextArg(XtNsensitive, new_l->pic->hw_ratio ? True : False);
1992 	NextArg(XtNtop, XtChainBottom);
1993 	NextArg(XtNbottom, XtChainBottom);
1994 	NextArg(XtNleft, XtChainLeft);
1995 	NextArg(XtNright, XtChainLeft);
1996 	percent_button = XtCreateManagedWidget("Scale by %", commandWidgetClass,
1997 					form, Args, ArgCount);
1998 	XtAddEventHandler(percent_button, ButtonReleaseMask, False,
1999 			  (XtEventHandler) scale_percent_pic, (XtPointer) NULL);
2000 
2001 	percent = MakeFloatSpinnerEntry(form, &percent_entry, "scale_percent",
2002 				below, percent_button,
2003 				(XtCallbackProc) 0, "100.0", 0.00001, 1000.0, 1.0, 45);
2004 	XtSetSensitive(percent, new_l->pic->hw_ratio ? True : False);
2005 
2006 	break;
2007     }
2008 }
2009 
2010 static void
get_new_line_values(void)2011 get_new_line_values(void)
2012 {
2013     struct f_point  p1, p2, *p;
2014     char	   *string;
2015     char	    longname[PATH_MAX];
2016     int		    dx, dy, rotation;
2017     float	    ratio;
2018     unsigned	    i;
2019     Boolean	    existing;
2020 
2021     switch (new_l->type) {
2022       case T_POLYLINE:
2023 	get_generic_vals(new_l);
2024 	get_cap_style(new_l);
2025 	get_join_style(new_l);
2026 	get_generic_arrows(new_l);
2027 	get_points(new_l->points);
2028 	return;
2029       case T_POLYGON:
2030 	get_generic_vals(new_l);
2031 	get_join_style(new_l);
2032 	get_points(new_l->points);
2033 	return;
2034       case T_ARCBOX:
2035 	new_l->radius = atoi(panel_get_value(radius));
2036       case T_BOX:
2037 	get_generic_vals(new_l);
2038 	get_join_style(new_l);
2039 	p1.x = panel_get_dim_value(x1_panel);
2040 	p1.y = panel_get_dim_value(y1_panel);
2041 	p2.x = panel_get_dim_value(x2_panel);
2042 	p2.y = panel_get_dim_value(y2_panel);
2043 	break;
2044       case T_PICTURE:
2045 	check_depth();
2046 	new_l->pen_color = pen_color;
2047 	new_l->fill_color = fill_color;
2048 	new_l->depth = atoi(panel_get_value(depth_panel));
2049 	/* get any comments (this is done in get_generic_vals for other line types) */
2050 	new_l->comments = strdup(panel_get_value(comments_panel));
2051 	p1.x = panel_get_dim_value(x1_panel);
2052 	p1.y = panel_get_dim_value(y1_panel);
2053 	p2.x = panel_get_dim_value(x2_panel);
2054 	p2.y = panel_get_dim_value(y2_panel);
2055 
2056 	/* size is upper-lower */
2057 	dx = p2.x - p1.x;
2058 	dy = p2.y - p1.y;
2059 	rotation = what_rotation(dx,dy);
2060 	if (dx == 0 || dy == 0)
2061 	    ratio = 0.0;
2062 	else if (((rotation == 0 || rotation == 180) && !flip_pic_flag) ||
2063 		 (rotation != 0 && rotation != 180 && flip_pic_flag))
2064 	    ratio = (float) fabs((double) dy / (double) dx);
2065 	else
2066 	    ratio = (float) fabs((double) dx / (double) dy);
2067 
2068 	new_l->pic->flipped = flip_pic_flag;
2069 	sprintf(buf, "%1.1f", ratio);
2070 	FirstArg(XtNlabel, buf);
2071 	SetValues(hw_ratio_panel);
2072 	string = panel_get_value(pic_name_panel);
2073 	if (string[0] == '\0')
2074 	    string = EMPTY_PIC;
2075 	else if (string[0] == '~') {
2076 	    /* if user typed tilde, parse user path and put in string panel */
2077 	    parseuserpath(string,longname);
2078 	    panel_set_value(pic_name_panel, longname);
2079 	    string = longname;
2080 	} else if (string[0] != '/') {
2081 	    /* make absolute */
2082 	    sprintf(longname, "%s/%s", cur_file_dir, string);
2083 	    panel_set_value(pic_name_panel, longname);
2084 	    string = longname;
2085 	}
2086 
2087 	file_changed = False;
2088 
2089 	/* if the filename changed, or this is a new picture */
2090 	if (!new_l->pic->pic_cache || strcmp(string, new_l->pic->pic_cache->file)) {
2091 	    reread_file = False;
2092 	    file_changed = True;
2093 	    if (new_l->pic->pic_cache) {
2094 		/* decrease ref count in picture repository for this name and free if 0 */
2095 		free_picture_entry(new_l->pic->pic_cache);
2096 	    }
2097 	    new_l->pic->hw_ratio = 0.0;
2098 	    /* read the new picture file */
2099 	    if (strcmp(string, EMPTY_PIC)) {
2100 		read_picobj(new_l->pic, string, new_l->pen_color, reread_file, &existing);
2101 		/* calculate h/w ratio */
2102 		new_l->pic->hw_ratio = (float) new_l->pic->pic_cache->bit_size.y/new_l->pic->pic_cache->bit_size.x;
2103 	    }
2104 	    /* enable reread button now */
2105 	    XtSetSensitive(reread, True);
2106 	}
2107 	/* update bitmap size */
2108 	if (new_l->pic->pic_cache && new_l->pic->pic_cache->subtype != T_PIC_NONE) {
2109 	    sprintf(buf,"%d x %d",
2110 			new_l->pic->pic_cache->bit_size.x,new_l->pic->pic_cache->bit_size.y);
2111 	    /* only the XBM (bitmap) type has a pen color */
2112 	    if (new_l->pic->pic_cache->subtype == T_PIC_XBM)
2113 		XtSetSensitive(pen_col_button, True);
2114 	    else
2115 		XtSetSensitive(pen_col_button, False);
2116 	} else {
2117 	    strcpy(buf,"--");
2118 	}
2119 	FirstArg(XtNlabel, buf);
2120 	SetValues(pic_size);
2121 	/* stop here if no picture file specified yet */
2122 	if (strcmp(string, EMPTY_PIC) == 0)
2123 	    break;
2124 
2125 	/* make box red indicating this type of picture file */
2126 	for (i=0; i<NUM_PIC_TYPES; i++) {
2127 	    if (new_l->pic->pic_cache->subtype == i+1) {
2128 		FirstArg(XtNbackground, colors[RED]);
2129 		NextArg(XtNsensitive, True);
2130 	    } else {
2131 		FirstArg(XtNbackground, colors[WHITE]);
2132 		NextArg(XtNsensitive, False);
2133 	    }
2134 	    SetValues(pic_type_box[i]);
2135 	}
2136 
2137 	/* number of colors */
2138 	/* although the FIG and EPS may have colors, the actual number is not known */
2139 	FirstArg(XtNlabel, buf);
2140 	if (new_l->pic->pic_cache->numcols > 0 && (
2141 	     new_l->pic->pic_cache->subtype == T_PIC_PCX ||
2142 	     new_l->pic->pic_cache->subtype == T_PIC_PPM ||
2143 	     new_l->pic->pic_cache->subtype == T_PIC_TIF ||
2144 #ifdef HAVE_PNG
2145 	     new_l->pic->pic_cache->subtype == T_PIC_PNG ||
2146 #endif
2147 #ifdef USE_XPM
2148 	     new_l->pic->pic_cache->subtype == T_PIC_XPM ||
2149 #endif
2150 #ifdef HAVE_JPEG
2151 	     new_l->pic->pic_cache->subtype == T_PIC_JPEG ||
2152 #endif
2153 	     new_l->pic->pic_cache->subtype == T_PIC_GIF))
2154 		sprintf(buf,"%3d",new_l->pic->pic_cache->numcols);
2155 	else
2156 		strcpy(buf,"N/A");
2157 	SetValues(pic_colors);
2158 
2159 	/* now transparent color if GIF file */
2160 	if (new_l->pic->pic_cache->subtype == T_PIC_GIF) {
2161 	    if (new_l->pic->pic_cache->transp == TRANSP_NONE)
2162 		sprintf(buf,"None");
2163 	    else
2164 		sprintf(buf,"%4d",(unsigned int) new_l->pic->pic_cache->transp);
2165 	} else
2166 	    sprintf(buf," N/A");
2167 	SetValues(transp_color);
2168 
2169 	/* h/w ratio */
2170 	sprintf(buf, "%1.1f", new_l->pic->hw_ratio);
2171 	FirstArg(XtNlabel, buf);
2172 	SetValues(orig_hw_panel);
2173 	app_flush();
2174 
2175 	if (new_l->pic->pic_cache->subtype == T_PIC_XBM)
2176 	     put_msg("Read XBM image of %dx%d pixels OK",
2177 		new_l->pic->pic_cache->bit_size.x, new_l->pic->pic_cache->bit_size.y);
2178 	/* recolor and redraw all pictures if this is a NEW picture */
2179 	if (reread_file || (!existing && file_changed && !appres.monochrome &&
2180 				(new_l->pic->pic_cache->numcols > 0) &&
2181 				(new_l->pic->pic_cache->bitmap != 0))) {
2182 		reread_file = False;
2183 		/* remap all picture colors */
2184 		remap_imagecolors();
2185 		/* make sure current colormap is installed */
2186 		set_cmap(XtWindow(popup));
2187 		/* and redraw all of the pictures already on the canvas */
2188 		redraw_images(&objects);
2189 		put_msg("Read %s image of %dx%d pixels and %d colors OK",
2190 				pic_names[new_l->pic->pic_cache->subtype],
2191 				new_l->pic->pic_cache->bit_size.x,
2192 				new_l->pic->pic_cache->bit_size.y,
2193 				new_l->pic->pic_cache->numcols);
2194 		app_flush();
2195 	}
2196 
2197 	FirstArg(XtNsensitive, new_l->pic->hw_ratio ? True : False);
2198 	SetValues(shrink);
2199 	SetValues(expand);
2200 	SetValues(origsize);
2201 	SetValues(percent_button);
2202 	/* must explicitely set a spinner with XtSetSensitive() */
2203 	XtSetSensitive(percent, new_l->pic->hw_ratio ? True : False);
2204 	break;
2205     } /* switch */
2206 
2207     p = new_l->points;
2208     p->x = p1.x;
2209     p->y = p1.y;
2210     p = p->next;
2211     p->x = p2.x;
2212     p->y = p1.y;
2213     p = p->next;
2214     p->x = p2.x;
2215     p->y = p2.y;
2216     p = p->next;
2217     p->x = p1.x;
2218     p->y = p2.y;
2219     p = p->next;
2220     p->x = p1.x;
2221     p->y = p1.y;
2222 }
2223 
2224 static void
done_line(void)2225 done_line(void)
2226 {
2227     int		prev_depth;
2228     switch (button_result) {
2229       case APPLY:
2230 	changed = True;
2231 	list_delete_line(&objects.lines, new_l);
2232 	redisplay_line(new_l);
2233 	get_new_line_values();
2234 	list_add_line(&objects.lines, new_l);
2235 	redisplay_line(new_l);
2236 	toggle_linemarker(new_l);
2237 	break;
2238       case DONE:
2239 	/* save in case user changed depth */
2240 	prev_depth = new_l->depth;
2241 	get_new_line_values();
2242 	if (new_l->pic)
2243 	    new_l->pic->new = False;		/* user has modified it */
2244 	if (prev_depth != new_l->depth) {
2245 	    remove_depth(O_POLYLINE, prev_depth);
2246 	    add_depth(O_POLYLINE, new_l->depth);
2247 	}
2248 	redisplay_lines(new_l, old_l);
2249 	if (new_l->type == T_PICTURE)
2250 	    old_l->type = T_PICTURE;		/* restore type */
2251 	clean_up();
2252 	old_l->next = new_l;
2253 	set_latestline(old_l);
2254 	set_action_object(F_EDIT, O_POLYLINE);
2255 	set_modifiedflag();
2256 	break;
2257       case CANCEL:
2258 	list_delete_line(&objects.lines, new_l);
2259 	/* if user created it but cancelled, delete it */
2260 	if (new_l->pic && new_l->pic->new) {
2261 	    redisplay_line(old_l);
2262 	    free_line(&new_l);
2263 	    return;
2264 	}
2265 	list_add_line(&objects.lines, old_l);
2266 	if (saved_objects.lines && saved_objects.lines->next &&
2267 	    saved_objects.lines->next == new_l)
2268 		saved_objects.lines->next = old_l;
2269 	else if (saved_objects.lines == new_l)
2270 		saved_objects.lines = old_l;
2271 	if (new_l->type == T_PICTURE) {
2272 	    old_l->type = T_PICTURE;		/* restore type */
2273 	    if (file_changed) {
2274 		remap_imagecolors();		/* and restore colors */
2275 		redraw_images(&objects);	/* and refresh them */
2276 	    }
2277 	}
2278 	if (changed)
2279 	    redisplay_lines(new_l, old_l);
2280 	else
2281 	    toggle_linemarker(old_l);
2282 	free_line(&new_l);
2283 	break;
2284     }
2285 
2286 }
2287 
2288 static void
make_window_text(F_text * t)2289 make_window_text(F_text *t)
2290 {
2291     static char	   *textjust_items[] = {
2292     "Left justified ", "Centered       ", "Right justified"};
2293     static char	   *hidden_text_items[] = {
2294     "Normal", "Hidden"};
2295     static char	   *rigid_text_items[] = {
2296     "Normal", "Rigid "};
2297     static char	   *special_text_items[] = {
2298     "Normal", "TeX   "};
2299 
2300     set_cursor(panel_cursor);
2301     toggle_textmarker(t);
2302     old_t = copy_text(t);
2303     new_t = t;
2304 
2305     textjust = new_t->type;	/* get current justification */
2306     hidden_text_flag = hidden_text(new_t) ? 1 : 0;
2307     new_psflag = psfont_text(new_t) ? 1 : 0;
2308     rigid_text_flag = (intptr_t) (rigid_text(new_t) ? 1 : 0);
2309     special_text_flag = special_text(new_t) ? 1 : 0;
2310     new_ps_font = cur_ps_font;
2311     new_latex_font = cur_latex_font;
2312     generic_vals.pen_color = new_t->color;
2313 
2314     pen_color = new_t->color;
2315     if (new_psflag)
2316 	new_ps_font = new_t->font;	/* get current font */
2317     else
2318 	new_latex_font = new_t->font;	/* get current font */
2319     generic_window("TEXT", "", &text_ic, done_text, NO_GENERICS, NO_ARROWS, t->comments);
2320 
2321     (void) int_panel(new_t->size, form, "      Size", (Widget) 0, &cur_fontsize_panel,
2322 				MIN_FONT_SIZE, MAX_FONT_SIZE, 1);
2323     below = pen_color_selection_panel();
2324     (void) int_panel(new_t->depth, form, "     Depth", (Widget) 0, &depth_panel,
2325 				MIN_DEPTH, MAX_DEPTH, 1);
2326     (void) float_panel(180.0 / M_PI * new_t->angle, form, "Angle (degrees)",
2327 	      (Widget) 0, &angle_panel, -360.0, 360.0, 1.0, 2);
2328 
2329     /* make text justification menu */
2330 
2331     FirstArg(XtNfromVert, below);
2332     NextArg(XtNborderWidth, 0);
2333     NextArg(XtNtop, XtChainBottom);
2334     NextArg(XtNbottom, XtChainBottom);
2335     NextArg(XtNleft, XtChainLeft);
2336     NextArg(XtNright, XtChainLeft);
2337     beside = XtCreateManagedWidget("  Justification", labelWidgetClass,
2338 				   form, Args, ArgCount);
2339 
2340     FirstArg(XtNlabel, textjust_items[textjust]);
2341     NextArg(XtNfromVert, below);
2342     NextArg(XtNfromHoriz, beside);
2343     NextArg(XtNleftBitmap, menu_arrow);	/* use menu arrow for pull-down */
2344     NextArg(XtNtop, XtChainBottom);
2345     NextArg(XtNbottom, XtChainBottom);
2346     NextArg(XtNleft, XtChainLeft);
2347     NextArg(XtNright, XtChainLeft);
2348     textjust_panel = XtCreateManagedWidget(
2349 			    "justify", menuButtonWidgetClass,
2350 					   form, Args, ArgCount);
2351     below = textjust_panel;
2352     make_pulldown_menu(textjust_items, XtNumber(textjust_items), -1, "",
2353 				    textjust_panel, textjust_select);
2354 
2355     /* make hidden text menu */
2356 
2357     FirstArg(XtNfromVert, below);
2358     NextArg(XtNborderWidth, 0);
2359     NextArg(XtNtop, XtChainBottom);
2360     NextArg(XtNbottom, XtChainBottom);
2361     NextArg(XtNleft, XtChainLeft);
2362     NextArg(XtNright, XtChainLeft);
2363     beside = XtCreateManagedWidget("    Hidden Flag", labelWidgetClass,
2364 				   form, Args, ArgCount);
2365 
2366     FirstArg(XtNfromVert, below);
2367     NextArg(XtNfromHoriz, beside);
2368     NextArg(XtNleftBitmap, menu_arrow);	/* use menu arrow for pull-down */
2369     NextArg(XtNtop, XtChainBottom);
2370     NextArg(XtNbottom, XtChainBottom);
2371     NextArg(XtNleft, XtChainLeft);
2372     NextArg(XtNright, XtChainLeft);
2373     hidden_text_panel = XtCreateManagedWidget(
2374 		 hidden_text_items[hidden_text_flag], menuButtonWidgetClass,
2375 					      form, Args, ArgCount);
2376     below = hidden_text_panel;
2377     make_pulldown_menu(hidden_text_items,
2378 				       XtNumber(hidden_text_items), -1, "",
2379 				     hidden_text_panel, hidden_text_select);
2380 
2381     /* make rigid text menu */
2382 
2383     FirstArg(XtNfromVert, below);
2384     NextArg(XtNborderWidth, 0);
2385     NextArg(XtNtop, XtChainBottom);
2386     NextArg(XtNbottom, XtChainBottom);
2387     NextArg(XtNleft, XtChainLeft);
2388     NextArg(XtNright, XtChainLeft);
2389     beside = XtCreateManagedWidget("     Rigid Flag", labelWidgetClass,
2390 				   form, Args, ArgCount);
2391 
2392     FirstArg(XtNfromVert, below);
2393     NextArg(XtNfromHoriz, beside);
2394     NextArg(XtNleftBitmap, menu_arrow);	/* use menu arrow for pull-down */
2395     NextArg(XtNtop, XtChainBottom);
2396     NextArg(XtNbottom, XtChainBottom);
2397     NextArg(XtNleft, XtChainLeft);
2398     NextArg(XtNright, XtChainLeft);
2399     rigid_text_panel = XtCreateManagedWidget(
2400 		   rigid_text_items[rigid_text_flag], menuButtonWidgetClass,
2401 					     form, Args, ArgCount);
2402     below = rigid_text_panel;
2403     make_pulldown_menu(rigid_text_items,
2404 				      XtNumber(rigid_text_items), -1, "",
2405 				      rigid_text_panel, rigid_text_select);
2406 
2407     /* make special text menu */
2408 
2409     FirstArg(XtNfromVert, below);
2410     NextArg(XtNborderWidth, 0);
2411     NextArg(XtNtop, XtChainBottom);
2412     NextArg(XtNbottom, XtChainBottom);
2413     NextArg(XtNleft, XtChainLeft);
2414     NextArg(XtNright, XtChainLeft);
2415     beside = XtCreateManagedWidget("       TeX Flag", labelWidgetClass,
2416 				   form, Args, ArgCount);
2417 
2418     FirstArg(XtNfromVert, below);
2419     NextArg(XtNfromHoriz, beside);
2420     NextArg(XtNleftBitmap, menu_arrow);	/* use menu arrow for pull-down */
2421     NextArg(XtNtop, XtChainBottom);
2422     NextArg(XtNbottom, XtChainBottom);
2423     NextArg(XtNleft, XtChainLeft);
2424     NextArg(XtNright, XtChainLeft);
2425     special_text_panel = XtCreateManagedWidget(
2426 				      special_text_items[special_text_flag],
2427 			       menuButtonWidgetClass, form, Args, ArgCount);
2428     below = special_text_panel;
2429     make_pulldown_menu(special_text_items,
2430 					XtNumber(special_text_items), -1, "",
2431 				   special_text_panel, special_text_select);
2432 
2433     /* tell the pulldown unit menu which panels to convert (xy_panel adds them automatically) */
2434     init_convert_array();
2435     xy_panel(new_t->base_x, new_t->base_y, "Origin", &x1_panel, &y1_panel, True);
2436 
2437     /* make the popup font menu */
2438     font_image_panel(new_psflag ? psfont_menu_bitmaps[new_t->font + 1] :
2439 		latexfont_menu_bitmaps[new_t->font], "Font", &font_panel);
2440 #ifdef I18N
2441     str_panel(new_t->cstring, "Text", &text_panel, 220, True,
2442 	      appres.latin_keyboard || is_i18n_font(new_t->fontstruct));
2443 #else
2444     str_panel(new_t->cstring, "Text", &text_panel, 220, True, False);
2445 #endif /* I18N */
2446 }
2447 
2448 static void
get_new_text_values(void)2449 get_new_text_values(void)
2450 {
2451     PR_SIZE	    size;
2452 
2453     check_depth();
2454     new_t->type = textjust;
2455     new_t->flags =
2456 	(rigid_text_flag ? RIGID_TEXT : 0)
2457 	| (special_text_flag ? SPECIAL_TEXT : 0)
2458 	| (hidden_text_flag ? HIDDEN_TEXT : 0)
2459 	| (new_psflag ? PSFONT_TEXT : 0);
2460     if (psfont_text(new_t))
2461 	new_t->font = new_ps_font;
2462     else
2463 	new_t->font = new_latex_font;
2464     new_t->size = atoi(panel_get_value(cur_fontsize_panel));
2465     if (new_t->size < 1) {
2466 	new_t->size = 1;
2467 	panel_set_int(cur_fontsize_panel, 1);
2468     }
2469     new_t->color = pen_color;
2470     new_t->depth = atoi(panel_get_value(depth_panel));
2471     new_t->angle = M_PI / 180.0 * atof(panel_get_value(angle_panel));
2472     fix_angle(&new_t->angle);	/* keep between 0 and 2PI */
2473     new_t->base_x = panel_get_dim_value(x1_panel);
2474     new_t->base_y = panel_get_dim_value(y1_panel);
2475     if (new_t->cstring)
2476 	free(new_t->cstring);
2477     /* get the text string itself */
2478     new_t->cstring = strdup(panel_get_value(text_panel));
2479     /* get any comments */
2480     new_t->comments = strdup(panel_get_value(comments_panel));
2481     /* get the fontstruct for zoom = 1 to get the size of the string */
2482     canvas_font = lookfont(x_fontnum(psfont_text(new_t), new_t->font), new_t->size);
2483     size = textsize(canvas_font, strlen(new_t->cstring), new_t->cstring);
2484     new_t->ascent = size.ascent;
2485     new_t->descent = size.descent;
2486     new_t->length = size.length;
2487     /* now set the fontstruct for this zoom scale */
2488     reload_text_fstruct(new_t);
2489 }
2490 
2491 static void
done_text(void)2492 done_text(void)
2493 {
2494     int		prev_depth;
2495     switch (button_result) {
2496       case APPLY:
2497 	changed = True;
2498 	list_delete_text(&objects.texts, new_t);
2499 	redisplay_text(new_t);
2500 	get_new_text_values();
2501 	list_add_text(&objects.texts, new_t);
2502 	redisplay_text(new_t);
2503 	toggle_textmarker(new_t);
2504 	break;
2505       case DONE:
2506 	/* save in case user changed depth */
2507 	prev_depth = new_t->depth;
2508 	get_new_text_values();
2509 	if (prev_depth != new_t->depth) {
2510 	    remove_depth(O_TXT, prev_depth);
2511 	    add_depth(O_TXT, new_t->depth);
2512 	}
2513 	redisplay_texts(new_t, old_t);
2514 	clean_up();
2515 	old_t->next = new_t;
2516 	set_latesttext(old_t);
2517 	set_action_object(F_EDIT, O_TXT);
2518 	set_modifiedflag();
2519 	break;
2520       case CANCEL:
2521 	list_delete_text(&objects.texts, new_t);
2522 	list_add_text(&objects.texts, old_t);
2523 	if (saved_objects.texts && saved_objects.texts->next &&
2524 	    saved_objects.texts->next == new_t)
2525 		saved_objects.texts->next = old_t;
2526 	else if (saved_objects.texts == new_t)
2527 		saved_objects.texts = old_t;
2528 	if (changed)
2529 	    redisplay_texts(new_t, old_t);
2530 	else
2531 	    toggle_textmarker(old_t);
2532 	free_text(&new_t);
2533 	break;
2534     }
2535 }
2536 
2537 static void
make_window_ellipse(F_ellipse * e)2538 make_window_ellipse(F_ellipse *e)
2539 {
2540     char	   *s1, *s2;
2541     icon_struct	   *image;
2542 
2543     set_cursor(panel_cursor);
2544     toggle_ellipsemarker(e);
2545     old_e = copy_ellipse(e);
2546     new_e = e;
2547 
2548     pen_color = new_e->pen_color;
2549     fill_color = new_e->fill_color;
2550     switch (new_e->type) {
2551       case T_ELLIPSE_BY_RAD:
2552 	s1 = "ELLIPSE";
2553 	s2 = "specified by radiii";
2554 	ellipse_flag = 1;
2555 	image = &ellrad_ic;
2556 	break;
2557       case T_ELLIPSE_BY_DIA:
2558 	s1 = "ELLIPSE";
2559 	s2 = "specified by diameters";
2560 	ellipse_flag = 1;
2561 	image = &elldia_ic;
2562 	break;
2563       case T_CIRCLE_BY_RAD:
2564 	s1 = "CIRCLE";
2565 	s2 = "specified by radius";
2566 	ellipse_flag = 0;
2567 	image = &ellrad_ic;
2568 	break;
2569       case T_CIRCLE_BY_DIA:
2570 	s1 = "CIRCLE";
2571 	s2 = "specified by diameter";
2572 	ellipse_flag = 0;
2573 	image = &elldia_ic;
2574 	break;
2575     }
2576     put_generic_vals(new_e);
2577     generic_window(s1, s2, image, done_ellipse, GENERICS, NO_ARROWS, e->comments);
2578     if (new_e->type == T_ELLIPSE_BY_RAD || new_e->type == T_ELLIPSE_BY_DIA) {
2579 	(void) int_panel(round(180 / M_PI * new_e->angle), form, "Angle (degrees)",
2580 	      (Widget) 0, &angle_panel, -360, 360, 1);
2581     }
2582 
2583     /* tell the pulldown unit menu which panels to convert */
2584     init_convert_array();
2585     if (ellipse_flag) {
2586 	f_pair_panel(&new_e->center, "Center",
2587 					&x1_panel, "X =", &y1_panel, "Y =", True);
2588 	f_pair_panel(&new_e->radiuses, "Radii",
2589 					&x2_panel, "X =", &y2_panel, "Y =", False);
2590     } else {
2591 	f_pair_panel(&new_e->center, "Center",
2592 					&x1_panel, "X =", &y1_panel, "Y =", True);
2593 	FirstArg(XtNlabel, "Radius");
2594 	NextArg(XtNfromVert, below);
2595 	NextArg(XtNborderWidth, 0);
2596 	NextArg(XtNtop, XtChainBottom);
2597 	NextArg(XtNbottom, XtChainBottom);
2598 	NextArg(XtNleft, XtChainLeft);
2599 	NextArg(XtNright, XtChainLeft);
2600 	beside = XtCreateManagedWidget("radius_label", labelWidgetClass, form, Args, ArgCount);
2601 
2602 	cvt_to_units_str(new_e->radiuses.x, buf);
2603 	FirstArg(XtNstring, buf);
2604 	NextArg(XtNfromVert, below);
2605 	NextArg(XtNfromHoriz, beside);
2606 	NextArg(XtNinsertPosition, strlen(buf));
2607 	NextArg(XtNeditType, XawtextEdit);
2608 	NextArg(XtNwidth, XY_WIDTH);
2609 	NextArg(XtNtop, XtChainBottom);
2610 	NextArg(XtNbottom, XtChainBottom);
2611 	NextArg(XtNleft, XtChainLeft);
2612 	NextArg(XtNright, XtChainLeft);
2613 	x2_panel = XtCreateManagedWidget("radius", asciiTextWidgetClass, form, Args, ArgCount);
2614 	text_transl(x2_panel);
2615 	add_to_convert(x2_panel);
2616     }
2617 }
2618 
2619 static void
get_new_ellipse_values(void)2620 get_new_ellipse_values(void)
2621 {
2622     get_generic_vals(new_e);
2623     if (new_e->type == T_ELLIPSE_BY_RAD || new_e->type == T_ELLIPSE_BY_DIA) {
2624 	new_e->angle = M_PI / 180 * atoi(panel_get_value(angle_panel));
2625 	fix_angle(&new_e->angle);	/* keep between 0 and 2PI */
2626     }
2627     get_f_pos(&new_e->center, x1_panel, y1_panel);
2628     if (ellipse_flag)
2629 	get_f_pos(&new_e->radiuses, x2_panel, y2_panel);
2630     else
2631 	new_e->radiuses.x = new_e->radiuses.y =
2632 	    panel_get_dim_value(x2_panel);
2633 
2634     if (new_e->type == T_ELLIPSE_BY_RAD || new_e->type == T_CIRCLE_BY_RAD) {
2635 	new_e->start = new_e->center;
2636     } else {
2637 	new_e->start.x = new_e->center.x - new_e->radiuses.x;
2638 	new_e->start.y = new_e->center.y;
2639     }
2640     new_e->end.x = new_e->center.x + new_e->radiuses.x;
2641     new_e->end.y = new_e->center.y;
2642 }
2643 
2644 static void
done_ellipse(void)2645 done_ellipse(void)
2646 {
2647     int		prev_depth;
2648     switch (button_result) {
2649       case APPLY:
2650 	changed = True;
2651 	list_delete_ellipse(&objects.ellipses, new_e);
2652 	redisplay_ellipse(new_e);
2653 	get_new_ellipse_values();
2654 	list_add_ellipse(&objects.ellipses, new_e);
2655 	redisplay_ellipse(new_e);
2656 	toggle_ellipsemarker(new_e);
2657 	break;
2658       case DONE:
2659 	/* save in case user changed depth */
2660 	prev_depth = new_e->depth;
2661 	get_new_ellipse_values();
2662 	if (prev_depth != new_e->depth) {
2663 	    remove_depth(O_ELLIPSE, prev_depth);
2664 	    add_depth(O_ELLIPSE, new_e->depth);
2665 	}
2666 	redisplay_ellipses(new_e, old_e);
2667 	clean_up();
2668 	old_e->next = new_e;
2669 	set_latestellipse(old_e);
2670 	set_action_object(F_EDIT, O_ELLIPSE);
2671 	set_modifiedflag();
2672 	break;
2673       case CANCEL:
2674 	list_delete_ellipse(&objects.ellipses, new_e);
2675 	list_add_ellipse(&objects.ellipses, old_e);
2676 	if (saved_objects.ellipses && saved_objects.ellipses->next &&
2677 	    saved_objects.ellipses->next == new_e)
2678 		saved_objects.ellipses->next = old_e;
2679 	else if (saved_objects.ellipses == new_e)
2680 		saved_objects.ellipses = old_e;
2681 	if (changed)
2682 	    redisplay_ellipses(new_e, old_e);
2683 	else
2684 	    toggle_ellipsemarker(old_e);
2685 	free_ellipse(&new_e);
2686 	break;
2687     }
2688 
2689 }
2690 
2691 Pixel arrow_panel_bg;
2692 
2693 static void
make_window_arc(F_arc * a)2694 make_window_arc(F_arc *a)
2695 {
2696     Widget	    save_form, save_below;
2697 
2698     set_cursor(panel_cursor);
2699     toggle_arcmarker(a);
2700     old_a = copy_arc(a);
2701     new_a = a;
2702 
2703     pen_color = new_a->pen_color;
2704     fill_color = new_a->fill_color;
2705     put_generic_vals(new_a);
2706     put_generic_arrows((F_line *) new_a);
2707     put_arc_type(new_a);
2708     put_cap_style(new_a);
2709 
2710     /* tell the pulldown unit menu which panels to convert */
2711     init_convert_array();
2712 
2713     /* create main window */
2714     generic_window("ARC", "Specified by 3 points", &arc_ic, done_arc,
2715 			GENERICS, ARROWS, a->comments);
2716     save_form = form;
2717     /* put the points panel in a sub-form */
2718     FirstArg(XtNborderWidth, 0);
2719     if (new_a->type == T_PIE_WEDGE_ARC) {
2720 	NextArg(XtNfromVert, above_arrows);	/* put it just below the stuff before arrows */
2721     } else {
2722 	NextArg(XtNfromVert, below);		/* after the arrow forms */
2723     }
2724     NextArg(XtNtop, XtChainBottom);
2725     NextArg(XtNbottom, XtChainBottom);
2726     NextArg(XtNleft, XtChainLeft);
2727     NextArg(XtNright, XtChainLeft);
2728     form = arc_points_form = XtCreateManagedWidget("form", formWidgetClass,
2729 				save_form, Args, ArgCount);
2730     save_below = below;
2731     below = (Widget) NULL;
2732     f_pair_panel(&new_a->point[0], "First point",
2733 				&x1_panel, "X =", &y1_panel, "Y =", True);
2734     f_pair_panel(&new_a->point[1], "Second point",
2735 				&x2_panel, "X =", &y2_panel, "Y =", False);
2736     f_pair_panel(&new_a->point[2], "Third point",
2737 				&x3_panel, "X =", &y3_panel, "Y =", False);
2738 
2739     form = save_form;
2740     below = save_below;
2741     /* if this is a pie-wedge arc, unmanage the arrow stuff until user changes
2742        it to an open type */
2743     if (new_a->type == T_PIE_WEDGE_ARC) {
2744 	XtRealizeWidget(popup);
2745 	XtUnmanageChild(form);
2746 	XtUnmanageChild(for_aform);
2747 	XtUnmanageChild(back_aform);
2748 	XtManageChild(form);
2749     }
2750 }
2751 
2752 static void
get_new_arc_values(void)2753 get_new_arc_values(void)
2754 {
2755     F_pos	    p0, p1, p2;
2756     float	    cx, cy;
2757 
2758     get_generic_vals(new_a);
2759     get_generic_arrows((F_line *) new_a);
2760     get_cap_style(new_a);
2761     get_arc_type(new_a);
2762     get_f_pos(&p0, x1_panel, y1_panel);
2763     get_f_pos(&p1, x2_panel, y2_panel);
2764     get_f_pos(&p2, x3_panel, y3_panel);
2765     if (compute_arccenter(p0, p1, p2, &cx, &cy)) {
2766 	new_a->point[0] = p0;
2767 	new_a->point[1] = p1;
2768 	new_a->point[2] = p2;
2769 	new_a->center.x = cx;
2770 	new_a->center.y = cy;
2771 	new_a->direction = compute_direction(p0, p1, p2);
2772     } else
2773 	put_msg("Invalid ARC points!");
2774 }
2775 
2776 static void
done_arc(void)2777 done_arc(void)
2778 {
2779     int		prev_depth;
2780     switch (button_result) {
2781       case APPLY:
2782 	changed = True;
2783 	list_delete_arc(&objects.arcs, new_a);
2784 	redisplay_arc(new_a);
2785 	get_new_arc_values();
2786 	list_add_arc(&objects.arcs, new_a);
2787 	redisplay_arc(new_a);
2788 	toggle_arcmarker(new_a);
2789 	break;
2790       case DONE:
2791 	/* save in case user changed depth */
2792 	prev_depth = new_a->depth;
2793 	get_new_arc_values();
2794 	if (prev_depth != new_a->depth) {
2795 	    remove_depth(O_ARC, prev_depth);
2796 	    add_depth(O_ARC, new_a->depth);
2797 	}
2798 	redisplay_arcs(new_a, old_a);
2799 	clean_up();
2800 	old_a->next = new_a;
2801 	set_latestarc(old_a);
2802 	set_action_object(F_EDIT, O_ARC);
2803 	set_modifiedflag();
2804 	break;
2805       case CANCEL:
2806 	list_delete_arc(&objects.arcs, new_a);
2807 	list_add_arc(&objects.arcs, old_a);
2808 	if (saved_objects.arcs && saved_objects.arcs->next &&
2809 	    saved_objects.arcs->next == new_a)
2810 		saved_objects.arcs->next = old_a;
2811 	else if (saved_objects.arcs == new_a)
2812 		saved_objects.arcs = old_a;
2813 	if (changed)
2814 	    redisplay_arcs(new_a, old_a);
2815 	else
2816 	    toggle_arcmarker(old_a);
2817 	free_arc(&new_a);
2818 	break;
2819     }
2820 
2821 }
2822 
2823 static void
make_window_spline(F_spline * s)2824 make_window_spline(F_spline *s)
2825 {
2826     set_cursor(panel_cursor);
2827     toggle_splinemarker(s);
2828     old_s = copy_spline(s);
2829     new_s = s;
2830 
2831     pen_color = new_s->pen_color;
2832     fill_color = new_s->fill_color;
2833     put_generic_vals(new_s);
2834     put_generic_arrows((F_line *) new_s);
2835     put_cap_style(new_s);
2836     switch (new_s->type) {
2837       case T_OPEN_APPROX:
2838 	generic_window("SPLINE", "Open approximated spline", &spl_ic,
2839 		       done_spline, GENERICS, ARROWS, s->comments);
2840 	points_panel(new_s->points);
2841 	break;
2842       case T_CLOSED_APPROX:
2843 	generic_window("SPLINE", "Closed approximated spline", &c_spl_ic,
2844 		       done_spline, GENERICS, NO_ARROWS, s->comments); /* no arrowheads */
2845 	points_panel(new_s->points);
2846 	break;
2847       case T_OPEN_INTERP:
2848 	generic_window("SPLINE", "Open interpolated spline", &intspl_ic,
2849 		       done_spline, GENERICS, ARROWS, s->comments);
2850 	points_panel(new_s->points);
2851 	break;
2852       case T_CLOSED_INTERP:
2853 	generic_window("SPLINE", "Closed interpolated spline", &c_intspl_ic,
2854 		       done_spline, GENERICS, NO_ARROWS, s->comments); /* no arrowheads */
2855 	points_panel(new_s->points);
2856 	break;
2857       case T_OPEN_XSPLINE:
2858 	generic_window("SPLINE", "X-Spline open", &xspl_ic,
2859 		       done_spline, GENERICS, ARROWS, s->comments);
2860 	points_panel(new_s->points);
2861 	break;
2862       case T_CLOSED_XSPLINE:
2863 	generic_window("SPLINE", "X-Spline closed", &c_xspl_ic,
2864 		       done_spline, GENERICS, ARROWS, s->comments);
2865 	points_panel(new_s->points);
2866 	break;
2867     }
2868 }
2869 
2870 
2871 static void
done_spline(void)2872 done_spline(void)
2873 {
2874     int		prev_depth;
2875     switch (button_result) {
2876       case APPLY:
2877 	changed = True;
2878 	list_delete_spline(&objects.splines, new_s);
2879 	redisplay_spline(new_s);
2880 	get_generic_vals(new_s);
2881 	get_generic_arrows((F_line *) new_s);
2882 	get_cap_style(new_s);
2883 	get_points(new_s->points);
2884 	list_add_spline(&objects.splines, new_s);
2885 	redisplay_spline(new_s);
2886 	toggle_splinemarker(new_s);
2887 	break;
2888       case DONE:
2889 	/* save in case user changed depth */
2890 	prev_depth = new_s->depth;
2891 	get_generic_vals(new_s);
2892 	get_generic_arrows((F_line *) new_s);
2893 	get_cap_style(new_s);
2894 	get_points(new_s->points);
2895 	if (prev_depth != new_s->depth) {
2896 	    remove_depth(O_SPLINE, prev_depth);
2897 	    add_depth(O_SPLINE, new_s->depth);
2898 	}
2899 	redisplay_splines(new_s, old_s);
2900 	clean_up();
2901 	old_s->next = new_s;
2902 	set_latestspline(old_s);
2903 	set_action_object(F_EDIT, O_SPLINE);
2904 	set_modifiedflag();
2905 	break;
2906       case CANCEL:
2907 	list_delete_spline(&objects.splines, new_s);
2908 	list_add_spline(&objects.splines, old_s);
2909 	if (saved_objects.splines && saved_objects.splines->next &&
2910 	    saved_objects.splines->next == new_s)
2911 		saved_objects.splines->next = old_s;
2912 	else if (saved_objects.splines == new_s)
2913 		saved_objects.splines = old_s;
2914 	if (changed)
2915 	    redisplay_splines(new_s, old_s);
2916 	else
2917 	    toggle_splinemarker(old_s);
2918 	free_spline(&new_s);
2919 	break;
2920     }
2921 }
2922 
2923 
2924 static void
make_window_spline_point(F_spline * s,int x,int y)2925 make_window_spline_point(F_spline *s, int x, int y)
2926 {
2927     set_cursor(panel_cursor);
2928     new_s = copy_spline(s);
2929     if (new_s == NULL)
2930       return;
2931     new_s->next = s;
2932 
2933     edited_point   = search_spline_point(new_s, x, y);
2934 
2935     sub_new_s = create_subspline(&num_spline_points, new_s, edited_point,
2936 				 &edited_sfactor, &sub_sfactor);
2937     if (sub_new_s == NULL)
2938       return;
2939 
2940     /* make solid, black unfilled spline of thickness 1 */
2941     s->thickness		= 1;
2942     s->pen_color		= BLACK;
2943     s->fill_style		= UNFILLED;
2944     s->style			= SOLID_LINE;
2945     sub_new_s->thickness	= 1;
2946     sub_new_s->pen_color	= BLACK;
2947     sub_new_s->fill_style	= UNFILLED;
2948     sub_new_s->style		= SOLID_LINE;
2949     redisplay_spline(s);
2950 
2951     spline_point_window(x, y);
2952 }
2953 
2954 static void
done_spline_point(void)2955 done_spline_point(void)
2956 {
2957     old_s = new_s->next;
2958     /* restore original attributes */
2959     old_s->thickness = new_s->thickness;
2960     old_s->pen_color = new_s->pen_color;
2961     old_s->fill_style = new_s->fill_style;
2962     old_s->style = new_s->style;
2963     edited_sfactor->s = sub_sfactor->s;
2964     free_subspline(num_spline_points, &sub_new_s);
2965 
2966     switch (button_result) {
2967       case DONE:
2968 	new_s->next = NULL;
2969 	change_spline(old_s, new_s);
2970 	redisplay_spline(new_s);
2971 	break;
2972       case CANCEL:
2973 	if (changed)
2974 	    draw_spline(new_s, ERASE);
2975 	redisplay_spline(old_s);
2976 	new_s->next = NULL;
2977 	free_spline(&new_s);
2978 	break;
2979     }
2980     return;
2981 }
2982 
2983 
2984 static void
new_generic_values(void)2985 new_generic_values(void)
2986 {
2987     int		    fill;
2988     char	   *val;
2989 
2990     generic_vals.thickness = atoi(panel_get_value(thickness_panel));
2991     generic_vals.pen_color = pen_color;
2992     generic_vals.fill_color = fill_color;
2993     check_thick();
2994     check_depth();
2995     generic_vals.depth = atoi(panel_get_value(depth_panel));
2996     /* get the comments */
2997     generic_vals.comments = strdup(panel_get_value(comments_panel));
2998     /* include dash length in panel, too */
2999     generic_vals.style_val = (float) atof(panel_get_value(style_val_panel));
3000     if (generic_vals.style == DASH_LINE || generic_vals.style == DOTTED_LINE ||
3001         generic_vals.style == DASH_DOT_LINE ||
3002         generic_vals.style == DASH_2_DOTS_LINE ||
3003         generic_vals.style == DASH_3_DOTS_LINE )
3004         if (generic_vals.style_val <= 0.0) {
3005 	    generic_vals.style_val = ((generic_vals.style == DASH_LINE ||
3006                 generic_vals.style == DASH_DOT_LINE ||
3007                 generic_vals.style == DASH_2_DOTS_LINE ||
3008                 generic_vals.style == DASH_3_DOTS_LINE)?
3009 					     cur_dashlength: cur_dotgap)*
3010 					(generic_vals.thickness + 1) / 2;
3011 	    panel_set_float(style_val_panel, generic_vals.style_val, "%1.1f");
3012 	}
3013 
3014     if (fill_flag==1) {		/* fill color */
3015 	val = panel_get_value(fill_intens_panel);
3016 	if (*val >= ' ' && *val <= '9') {
3017 	    /* if fill value > 200%, set to 100%.  Also if > 100% and fill color is
3018 	       black or white set to 100% */
3019 	    if ((fill = atoi(val)) > 200 ||
3020 		((fill_color == BLACK || fill_color == DEFAULT ||
3021 		 fill_color == WHITE) && fill > 100))
3022 		fill = 100;
3023 	    generic_vals.fill_style = fill / (200 / (NUMSHADEPATS+NUMTINTPATS - 1));
3024 	} else {
3025 	    generic_vals.fill_style = 0;
3026 	}
3027 	fill = generic_vals.fill_style * (200 / (NUMSHADEPATS+NUMTINTPATS - 1));
3028 	panel_set_int(fill_intens_panel, fill);
3029     } else if (fill_flag==2) {	/* fill pattern */
3030 	val = panel_get_value(fill_pat_panel);
3031 	if (*val >= ' ' && *val <= '9') {
3032 	    if ((fill = atoi(val)) >= NUMPATTERNS)
3033 		fill = NUMPATTERNS-1;
3034 	    if (fill < 0)
3035 		fill = 0;
3036 	    generic_vals.fill_style = fill+NUMSHADEPATS+NUMTINTPATS;
3037 	} else {
3038 	    fill = 0;
3039 	    generic_vals.fill_style = NUMSHADEPATS+NUMTINTPATS;
3040 	}
3041 	panel_set_int(fill_pat_panel, fill);
3042     } else {
3043 	generic_vals.fill_style = -1;		/* no fill */
3044     }
3045 }
3046 
3047 static void
new_arrow_values(void)3048 new_arrow_values(void)
3049 {
3050 	if (for_arrow) {
3051 	    generic_vals.for_arrow.thickness =
3052 				(float) fabs(atof(panel_get_value(for_arrow_thick)));
3053 	    generic_vals.for_arrow.wd =
3054 				(float) fabs(atof(panel_get_value(for_arrow_width)));
3055 	    generic_vals.for_arrow.ht =
3056 				(float) fabs(atof(panel_get_value(for_arrow_height)));
3057 	}
3058 	if (back_arrow) {
3059 	    generic_vals.back_arrow.thickness =
3060 				(float) fabs(atof(panel_get_value(back_arrow_thick)));
3061 	    generic_vals.back_arrow.wd =
3062 				(float) fabs(atof(panel_get_value(back_arrow_width)));
3063 	    generic_vals.back_arrow.ht =
3064 				(float) fabs(atof(panel_get_value(back_arrow_height)));
3065 	}
3066 }
3067 
3068 static void
done_button(Widget panel_local,XtPointer closure,XtPointer call_data)3069 done_button(Widget panel_local, XtPointer closure, XtPointer call_data)
3070 {
3071 	(void)panel_local;
3072 	(void)closure;
3073 	(void)call_data;
3074     button_result = DONE;
3075     done_proc();
3076     reset_edit_cursor();
3077     Quit();
3078 }
3079 
3080 static void
apply_button(Widget panel_local,XtPointer closure,XtPointer call_data)3081 apply_button(Widget panel_local, XtPointer closure, XtPointer call_data)
3082 {
3083 	(void)panel_local;
3084 	(void)closure;
3085 	(void)call_data;
3086     button_result = DONE;
3087     button_result = APPLY;
3088     /* make sure current colormap is installed */
3089     set_cmap(XtWindow(popup));
3090     done_proc();
3091 }
3092 
3093 static void
cancel_button(Widget panel_local,XtPointer closure,XtPointer call_data)3094 cancel_button(Widget panel_local, XtPointer closure, XtPointer call_data)
3095 {
3096 	(void)panel_local;
3097 	(void)closure;
3098 	(void)call_data;
3099     button_result = CANCEL;
3100     done_proc();
3101     reset_edit_cursor();
3102     Quit();
3103 }
3104 
3105 static void
edit_done(Widget w,XButtonEvent * ev,String * params,Cardinal * num_params)3106 edit_done(Widget w, XButtonEvent *ev, String *params, Cardinal *num_params)
3107 {
3108 	(void)ev;
3109 	(void)params;
3110 	(void)num_params;
3111     done_button(w, NULL, NULL);
3112 }
3113 
3114 static void
edit_apply(Widget w,XButtonEvent * ev,String * params,Cardinal * num_params)3115 edit_apply(Widget w, XButtonEvent *ev, String *params, Cardinal *num_params)
3116 {
3117 	(void)ev;
3118 	(void)params;
3119 	(void)num_params;
3120     apply_button(w, NULL, NULL);
3121 }
3122 
3123 static void
edit_cancel(Widget w,XButtonEvent * ev,String * params,Cardinal * num_params)3124 edit_cancel(Widget w, XButtonEvent *ev, String *params, Cardinal *num_params)
3125 {
3126 	(void)ev;
3127 	(void)params;
3128 	(void)num_params;
3129     cancel_button(w, NULL, NULL);
3130 }
3131 
3132 static void
reset_edit_cursor(void)3133 reset_edit_cursor(void)
3134 {
3135     if (lib_cursor)
3136 	set_cursor(null_cursor);
3137     else if (dim_cursor)
3138 	set_cursor(arrow_cursor);
3139     else
3140 	set_cursor(pick9_cursor);
3141     lib_cursor = False;
3142     dim_cursor = False;
3143 }
3144 
3145 static void
generic_window(char * object_type,char * sub_type,icon_struct * icon,void (* d_proc)(),Boolean generics,Boolean arrows,char * comments)3146 generic_window(char *object_type, char *sub_type, icon_struct *icon, void (*d_proc) (/* ??? */), Boolean generics, Boolean arrows, char *comments)
3147 {
3148     Dimension	    label_height, image_height;
3149     int		    button_distance;
3150     int		    i, fill;
3151     Widget	    image, cancel;
3152     Pixmap	    image_pm;
3153     XFontStruct	   *temp_font;
3154 
3155     FirstArg(XtNtitle, "Xfig: Edit panel");
3156     NextArg(XtNcolormap, tool_cm);
3157     NextArg(XtNallowShellResize, True);
3158     popup = XtCreatePopupShell("edit_panel",
3159 			       transientShellWidgetClass, tool,
3160 			       Args, ArgCount);
3161     XtAugmentTranslations(popup,
3162 			XtParseTranslationTable(edit_popup_translations));
3163     init_kbd_actions();
3164     if (!actions_added) {
3165         XtAppAddActions(tool_app, edit_actions, XtNumber(edit_actions));
3166 	XtAppAddActions(tool_app, picture_pos_actions, XtNumber(picture_pos_actions));
3167 	XtAppAddActions(tool_app, picture_size_actions, XtNumber(picture_size_actions));
3168 	XtAppAddActions(tool_app, text_actions, XtNumber(text_actions));
3169 	XtAppAddActions(tool_app, compound_actions, XtNumber(compound_actions));
3170 	actions_added = True;
3171     }
3172 
3173     form = XtCreateManagedWidget("form", formWidgetClass, popup, NULL, 0);
3174 
3175     done_proc = d_proc;
3176 
3177     /***************** LABEL and IMAGE of the object *****************/
3178 
3179     FirstArg(XtNtop, XtChainTop);
3180     NextArg(XtNbottom, XtChainTop);
3181     NextArg(XtNleft, XtChainLeft);
3182     NextArg(XtNright, XtChainLeft);
3183     image = XtCreateManagedWidget("image", labelWidgetClass, form,
3184 				  Args, ArgCount);
3185 
3186     /* put in the image */
3187     /* search to see if that pixmap has already been created */
3188     image_pm = 0;
3189     for (i = 0; i < NUM_IMAGES; i++) {
3190 	if (pix_table[i].image == 0)
3191 	    break;
3192 	if (pix_table[i].image == icon) {
3193 	    image_pm = pix_table[i].image_pm;
3194 	    break;
3195 	}
3196     }
3197 
3198     /* no need for colon (:) if no sub-type */
3199     if (strlen(sub_type) == 0)
3200 	sprintf(buf, "%s", object_type);
3201     else
3202 	sprintf(buf, "%s: %s", object_type, sub_type);
3203     FirstArg(XtNfromHoriz, image);
3204     NextArg(XtNborderWidth, 0);
3205     NextArg(XtNtop, XtChainTop);
3206     NextArg(XtNbottom, XtChainTop);
3207     NextArg(XtNleft, XtChainLeft);
3208     NextArg(XtNright, XtChainLeft);
3209     label = XtCreateManagedWidget(buf, labelWidgetClass, form, Args, ArgCount);
3210 
3211     /* doesn't already exist, create a pixmap from the data (ala panel.c) */
3212     /* OpenWindows bug doesn't handle a 1-plane bitmap on a n-plane display */
3213     /* so we use CreatePixmap.... */
3214     if (image_pm == 0) {
3215 	Pixel	    fg, bg;
3216 	/* get the foreground/background of the widget */
3217 	FirstArg(XtNforeground, &fg);
3218 	NextArg(XtNbackground, &bg);
3219 	GetValues(image);
3220 
3221 	image_pm = XCreatePixmapFromBitmapData(tool_d, canvas_win,
3222 				     icon->bits, icon->width, icon->height,
3223 				     fg, bg, tool_dpth);
3224 	pix_table[i].image_pm = image_pm;
3225 	pix_table[i].image = icon;
3226     }
3227     FirstArg(XtNbitmap, image_pm);
3228     SetValues(image);
3229 
3230     /* get height of label widget and distance between widgets */
3231     FirstArg(XtNheight, &label_height);
3232     NextArg(XtNvertDistance, &button_distance);
3233     GetValues(label);
3234     /* do the same for the image widget */
3235     FirstArg(XtNheight, &image_height);
3236     GetValues(image);
3237 
3238     /***************** BUTTONS *****************/
3239 
3240     FirstArg(XtNlabel, " Done ");
3241     NextArg(XtNfromHoriz, image);
3242     NextArg(XtNfromVert, label);
3243     NextArg(XtNtop, XtChainTop);
3244     NextArg(XtNbottom, XtChainTop);
3245     NextArg(XtNleft, XtChainLeft);
3246     NextArg(XtNright, XtChainLeft);
3247     but1 = XtCreateManagedWidget("done", commandWidgetClass, form, Args, ArgCount);
3248     XtAddCallback(but1, XtNcallback, (XtCallbackProc) done_button, (XtPointer) NULL);
3249 
3250     /* editing whole figure comments doesn't need an apply button, just done and cancel */
3251 
3252     if (strcmp("Whole Figure", object_type)) {
3253 	FirstArg(XtNlabel, "Apply ");
3254 	NextArg(XtNfromHoriz, but1);
3255 	NextArg(XtNfromVert, label);
3256 	NextArg(XtNtop, XtChainTop);
3257 	NextArg(XtNbottom, XtChainTop);
3258 	NextArg(XtNleft, XtChainLeft);
3259 	NextArg(XtNright, XtChainLeft);
3260 	but1 = XtCreateManagedWidget("apply", commandWidgetClass, form, Args, ArgCount);
3261 	XtAddCallback(but1, XtNcallback, (XtCallbackProc) apply_button, (XtPointer) NULL);
3262     }
3263 
3264     FirstArg(XtNlabel, "Cancel");
3265     NextArg(XtNfromHoriz, but1);
3266     NextArg(XtNfromVert, label);
3267     NextArg(XtNtop, XtChainTop);
3268     NextArg(XtNbottom, XtChainTop);
3269     NextArg(XtNleft, XtChainLeft);
3270     NextArg(XtNright, XtChainLeft);
3271     cancel = but1 = XtCreateManagedWidget("cancel", commandWidgetClass, form, Args, ArgCount);
3272     XtAddCallback(but1, XtNcallback, (XtCallbackProc) cancel_button, (XtPointer) NULL);
3273     below = but1;
3274 
3275     /* add "Screen Capture" and "Edit Image" buttons if picture object */
3276     if (!strcmp(sub_type,"Picture Object")) {
3277 	FirstArg(XtNlabel,"Screen Capture");
3278 	NextArg(XtNfromHoriz, but1);
3279 	NextArg(XtNfromVert, label);
3280 	NextArg(XtNtop, XtChainTop);
3281 	NextArg(XtNbottom, XtChainTop);
3282 	NextArg(XtNleft, XtChainLeft);
3283 	NextArg(XtNright, XtChainLeft);
3284 	but1 = XtCreateManagedWidget("screen_capture",
3285 	    commandWidgetClass, form, Args, ArgCount);
3286 	XtAddCallback(but1, XtNcallback,
3287 	    (XtCallbackProc) grab_button, (XtPointer) NULL);
3288 
3289 	if (*cur_image_editor != '\0') {
3290 	    FirstArg(XtNlabel,"Edit Image");
3291 	    NextArg(XtNfromHoriz, but1);
3292 	    NextArg(XtNfromVert, label);
3293 	    NextArg(XtNtop, XtChainTop);
3294 	    NextArg(XtNbottom, XtChainTop);
3295 	    NextArg(XtNleft, XtChainLeft);
3296 	    NextArg(XtNright, XtChainLeft);
3297 	    but1 = XtCreateManagedWidget("edit_image",
3298 		commandWidgetClass, form, Args, ArgCount);
3299 	    XtAddCallback(but1, XtNcallback,
3300 		(XtCallbackProc) image_edit_button, (XtPointer) NULL);
3301 	}
3302     }
3303 
3304     /***************** COMMENTS *****************/
3305 
3306     /* label for Comments */
3307     FirstArg(XtNfromVert, below);
3308     NextArg(XtNborderWidth, 0);
3309     NextArg(XtNtop, XtChainTop);
3310     NextArg(XtNbottom, XtChainTop);
3311     NextArg(XtNleft, XtChainLeft);
3312     NextArg(XtNright, XtChainLeft);
3313     below = XtCreateManagedWidget("Comments", labelWidgetClass,
3314 				       form, Args, ArgCount);
3315     /* get the font of above label widget */
3316     FirstArg(XtNfont, &temp_font);
3317     GetValues(below);
3318 
3319     /* make text widget for any comment lines */
3320     FirstArg(XtNfromVert, below);
3321     NextArg(XtNvertDistance, 2);
3322     NextArg(XtNstring, comments);
3323     NextArg(XtNinsertPosition, 0);
3324     NextArg(XtNeditType, XawtextEdit);
3325     if (!strcmp(sub_type,"Picture Object")) {
3326 	NextArg(XtNwidth, 415);		/* as wide as picture filename widget below */
3327     } else {
3328 	NextArg(XtNwidth, 300);
3329     }
3330     NextArg(XtNtop, XtChainTop);
3331     NextArg(XtNbottom, XtChainBottom);
3332     NextArg(XtNleft, XtChainLeft);
3333     NextArg(XtNright, XtChainRight);
3334     /* allow enough height for 3 lines + scrollbar */
3335     NextArg(XtNheight, max_char_height(temp_font) * 3 + 20);
3336     NextArg(XtNscrollHorizontal, XawtextScrollWhenNeeded);
3337     NextArg(XtNscrollVertical, XawtextScrollWhenNeeded);
3338 
3339     comments_panel = below = XtCreateManagedWidget("comments", asciiTextWidgetClass,
3340 				form, Args, ArgCount);
3341     XtOverrideTranslations(comments_panel,
3342 		    XtParseTranslationTable(edit_comment_translations));
3343 
3344     /***************** COMMON PARAMETERS *****************/
3345 
3346     if (generics) {
3347 	Widget lbelow, lbeside;
3348 
3349 	/***************** ARC TYPE MENU *****************/
3350 
3351 	if (!strcmp(object_type,"ARC"))
3352 		arc_type_menu();
3353 
3354 	/***************** LINE WIDTH *****************/
3355 
3356 	lbelow = below;
3357 	(void) int_panel(generic_vals.thickness, form, "Width",
3358 				(Widget) 0, &thickness_panel, 0, 1000, 1);
3359 
3360 	lbeside = below;
3361 	below = lbelow;
3362 	/***************** OBJECT DEPTH *****************/
3363 	(void) int_panel(generic_vals.depth,     form, "Depth",
3364 				lbeside, &depth_panel, MIN_DEPTH, MAX_DEPTH, 1);
3365 
3366 	/***************** COLOR MENUS *****************/
3367 
3368 	below = pen_color_selection_panel();
3369 	below = fill_color_selection_panel();
3370 
3371 	if (generic_vals.fill_style == -1) {
3372 	    fill = -1;
3373 	    fill_flag = 0;
3374 	} else if (generic_vals.fill_style < NUMSHADEPATS+NUMTINTPATS) {
3375 	    fill = generic_vals.fill_style * (200 / (NUMSHADEPATS+NUMTINTPATS - 1));
3376 	    fill_flag = 1;
3377 	} else {	/* fill pattern */
3378 	    fill = generic_vals.fill_style - NUMSHADEPATS - NUMTINTPATS;
3379 	    fill_flag = 2;
3380 	}
3381 
3382 	/***************** FILL STYLE MENU *****************/
3383 
3384 	fill_style_menu(fill, fill_flag);
3385 	below = fill_image;	/* line style goes below fill pattern image if
3386 				   there is no cap style and no join style */
3387 
3388 	/***************** LINE STYLE MENU *****************/
3389 
3390 	FirstArg(XtNfromVert, below);
3391 	NextArg(XtNborderWidth, 0);
3392 	NextArg(XtNtop, XtChainBottom);
3393 	NextArg(XtNbottom, XtChainBottom);
3394 	NextArg(XtNleft, XtChainLeft);
3395 	NextArg(XtNright, XtChainLeft);
3396 	beside = XtCreateManagedWidget("Line style", labelWidgetClass,
3397 				       form, Args, ArgCount);
3398 	FirstArg(XtNfromVert, below);
3399 	NextArg(XtNfromHoriz, beside);
3400 	NextArg(XtNbitmap, linestyle_pixmaps[generic_vals.style]);
3401 	NextArg(XtNtop, XtChainBottom);
3402 	NextArg(XtNbottom, XtChainBottom);
3403 	NextArg(XtNleft, XtChainLeft);
3404 	NextArg(XtNright, XtChainLeft);
3405 	line_style_panel = XtCreateManagedWidget("line_style", menuButtonWidgetClass,
3406 					    form, Args, ArgCount);
3407 	make_pulldown_menu_images(linestyle_choices, NUM_LINESTYLE_TYPES,
3408 			linestyle_pixmaps, NULL, line_style_panel, line_style_select);
3409 
3410 	/* new field for style_val */
3411 	style_val = float_panel(generic_vals.style_val, form, "Dash length/\nDot gap",
3412 		    line_style_panel, &style_val_panel, 0.0, 1000.0, 1.0, 1);
3413 	/* save pointer to dash/dot gap label panel */
3414 	style_val_label = beside;
3415 	FirstArg(XtNhorizDistance, 20);
3416 	SetValues(style_val_label);
3417 	if (generic_vals.style == SOLID_LINE) {
3418 	    XtSetSensitive(style_val,False);
3419 	    XtSetSensitive(style_val_label,False);
3420 	    /* and clear any value from the dash length panel */
3421 	    panel_clear_value(style_val_panel);
3422 	}
3423 	below = line_style_panel;
3424 
3425 	/***************** CAP STYLE MENU *****************/
3426 
3427 	/* if a polyline, arc or open spline make a panel for cap style */
3428 
3429 	lbelow = below;
3430 	beside = (Widget) 0;
3431 	if (!strcmp(object_type,"ARC") ||
3432 	    (!strcmp(object_type,"SPLINE") && strstr(sub_type,"Open")) ||
3433 	    (!strcmp(object_type,"POLYLINE") && !strcmp(sub_type,"Polyline"))) {
3434 		cap_style_panel_menu();
3435 		below = beside = cap_style_panel;
3436 	}
3437 
3438 	/***************** JOIN STYLE MENU *****************/
3439 
3440 	if (!strcmp(sub_type,"Polyline") || !strcmp(sub_type,"Polygon") ||
3441 	    !strcmp(sub_type,"Box")) {
3442 		below = lbelow;
3443 		join_style_panel_menu();
3444 		below = join_style_panel;
3445 	}
3446 
3447 	/* save widget that is just above the arrow panels for the arc window usage */
3448 	above_arrows = below;
3449 
3450 	/***************** ARROW panels *****************/
3451 
3452 	if (arrows) {
3453 	    int		type;
3454 
3455 	    /****** FIRST THE FORWARD ARROW ******/
3456 
3457 	    FirstArg(XtNfromVert, above_arrows);
3458 	    NextArg(XtNvertDistance, 2);
3459 	    NextArg(XtNhorizDistance, 20);
3460 	    NextArg(XtNtop, XtChainBottom);
3461 	    NextArg(XtNbottom, XtChainBottom);
3462 	    NextArg(XtNleft, XtChainLeft);
3463 	    NextArg(XtNright, XtChainLeft);
3464 	    for_aform = XtCreateManagedWidget("arrow_form", formWidgetClass,
3465 					  form, Args, ArgCount);
3466 
3467 	    FirstArg(XtNborderWidth, 0);
3468 	    NextArg(XtNtop, XtChainBottom);
3469 	    NextArg(XtNbottom, XtChainBottom);
3470 	    NextArg(XtNleft, XtChainLeft);
3471 	    NextArg(XtNright, XtChainLeft);
3472 	    beside = XtCreateManagedWidget("Forward\nArrow", labelWidgetClass,
3473 				       for_aform, Args, ArgCount);
3474 	    /* make pulldown arrow style menu */
3475 	    if (generic_vals.for_arrow.type == -1) {
3476 		type = -1;
3477 	    } else {
3478 		type = generic_vals.for_arrow.type*2 - 1 + generic_vals.for_arrow.style;
3479 		if (type < 0)
3480 		    type = 0;
3481 	    }
3482 
3483 	    FirstArg(XtNfromHoriz, beside);
3484 	    NextArg(XtNlabel, "");
3485 	    NextArg(XtNinternalWidth, 0);
3486 	    NextArg(XtNinternalHeight, 0);
3487 	    NextArg(XtNbitmap, arrow_pixmaps[type+1]);
3488 	    NextArg(XtNtop, XtChainBottom);
3489 	    NextArg(XtNbottom, XtChainBottom);
3490 	    NextArg(XtNleft, XtChainLeft);
3491 	    NextArg(XtNright, XtChainLeft);
3492 	    for_arrow_type_panel = XtCreateManagedWidget("Arrowtype",
3493 					    menuButtonWidgetClass,
3494 					    for_aform, Args, ArgCount);
3495 	    below = for_arrow_type_panel;
3496 
3497 	    /* make pulldown menu with arrow type images */
3498 	    make_pulldown_menu_images(dim_arrowtype_choices,
3499 			NUM_ARROW_TYPES, arrow_pixmaps, NULL,
3500 			for_arrow_type_panel, for_arrow_type_select);
3501 
3502 	    for_thick = float_panel(generic_vals.for_arrow.thickness, for_aform,
3503 			"Thick ", (Widget) 0, &for_arrow_thick, 0.0, 10000.0, 1.0, 1);
3504 	    for_thick_label = beside;
3505 	    for_width = float_panel(generic_vals.for_arrow.wd, for_aform,
3506 			"Width ", (Widget) 0, &for_arrow_width, 0.0, 10000.0, 1.0, 1);
3507 	    for_width_label = beside;
3508 	    for_height = float_panel(generic_vals.for_arrow.ht, for_aform,
3509 			"Length", (Widget) 0, &for_arrow_height, 0.0, 10000.0, 1.0, 1);
3510 	    for_height_label = beside;
3511 
3512 	    /****** NOW THE BACK ARROW ******/
3513 
3514 	    FirstArg(XtNfromVert, above_arrows);
3515 	    NextArg(XtNvertDistance, 2);
3516 	    NextArg(XtNfromHoriz, for_aform);
3517 	    NextArg(XtNtop, XtChainBottom);
3518 	    NextArg(XtNbottom, XtChainBottom);
3519 	    NextArg(XtNleft, XtChainLeft);
3520 	    NextArg(XtNright, XtChainLeft);
3521 	    back_aform = XtCreateManagedWidget("arrow_form", formWidgetClass,
3522 					  form, Args, ArgCount);
3523 	    FirstArg(XtNborderWidth, 0);
3524 	    NextArg(XtNtop, XtChainBottom);
3525 	    NextArg(XtNbottom, XtChainBottom);
3526 	    NextArg(XtNleft, XtChainLeft);
3527 	    NextArg(XtNright, XtChainLeft);
3528 	    beside = XtCreateManagedWidget("Backward\nArrow", labelWidgetClass,
3529 				       back_aform, Args, ArgCount);
3530 
3531 	    /* make pulldown arrow style menu */
3532 	    if (generic_vals.back_arrow.type == -1) {
3533 		type = -1;
3534 	    } else {
3535 		type = generic_vals.back_arrow.type*2 - 1 + generic_vals.back_arrow.style;
3536 		if (type < 0)
3537 		    type = 0;
3538 	    }
3539 	    FirstArg(XtNfromHoriz, beside);
3540 	    NextArg(XtNlabel, "");
3541 	    NextArg(XtNinternalWidth, 0);
3542 	    NextArg(XtNinternalHeight, 0);
3543 	    NextArg(XtNbitmap, arrow_pixmaps[type+1]);
3544 	    NextArg(XtNtop, XtChainBottom);
3545 	    NextArg(XtNbottom, XtChainBottom);
3546 	    NextArg(XtNleft, XtChainLeft);
3547 	    NextArg(XtNright, XtChainLeft);
3548 	    back_arrow_type_panel = XtCreateManagedWidget("Arrowtype",
3549 					    menuButtonWidgetClass,
3550 					    back_aform, Args, ArgCount);
3551 	    below = back_arrow_type_panel;
3552 
3553 	    /* make pulldown menu with arrow type images */
3554 	    make_pulldown_menu_images(dim_arrowtype_choices,
3555 			NUM_ARROW_TYPES, arrow_pixmaps, NULL,
3556 			back_arrow_type_panel, back_arrow_type_select);
3557 
3558 	    back_thick = float_panel(generic_vals.back_arrow.thickness, back_aform,
3559 			"Thick ", (Widget) 0, &back_arrow_thick, 0.0, 10000.0, 1.0, 1);
3560 	    back_thick_label = beside;
3561 	    back_width = float_panel(generic_vals.back_arrow.wd, back_aform,
3562 			"Width ", (Widget) 0, &back_arrow_width, 0.0, 10000.0, 1.0, 1);
3563 	    back_width_label = beside;
3564 	    back_height = float_panel(generic_vals.back_arrow.ht, back_aform,
3565 			"Length", (Widget) 0, &back_arrow_height, 0.0, 10000.0, 1.0, 1);
3566 	    back_height_label = beside;
3567 	    below = for_aform;	/* for the widget that follows us in the panel */
3568 	}
3569     }
3570     XtInstallAccelerators(form, cancel);
3571 }
3572 
3573 
3574 static void
spline_point_window(int x,int y)3575 spline_point_window(int x, int y)
3576 {
3577     Widget          but_spline[3];
3578     Dimension	    label_height, label_width;
3579     intptr_t	    i;
3580     int		    dist;
3581 
3582     static char use_item[]="Edit the behavior\nof the control point";
3583 
3584     /* locate the mouse in screen coords */
3585     XtTranslateCoords(canvas_sw, ZOOMX(x), ZOOMY(y), &rootx, &rooty);
3586 
3587     /* position the window to the right of the mouse */
3588     FirstArg(XtNx, rootx+30);
3589     NextArg(XtNy, rooty);
3590     NextArg(XtNtitle, "Edit spline point");
3591     NextArg(XtNcolormap, tool_cm);
3592     popup = XtCreatePopupShell("edit_spline_point_panel",
3593 			       transientShellWidgetClass, tool,
3594 			       Args, ArgCount);
3595     XtAugmentTranslations(popup,
3596 			  XtParseTranslationTable(edit_popup_translations));
3597     if (!actions_added) {
3598         XtAppAddActions(tool_app, edit_actions, XtNumber(edit_actions));
3599         XtAppAddActions(tool_app, text_actions, XtNumber(text_actions));
3600 	actions_added = True;
3601     }
3602 
3603     form = XtCreateManagedWidget("form", formWidgetClass, popup, NULL, 0);
3604 
3605     done_proc = done_spline_point;
3606 
3607     FirstArg(XtNwidth, SFACTOR_BAR_WIDTH);
3608     NextArg(XtNheight, SFACTOR_BAR_HEIGHT);
3609     NextArg(XtNtop, XtChainBottom);
3610     NextArg(XtNbottom, XtChainBottom);
3611     NextArg(XtNleft, XtChainLeft);
3612     NextArg(XtNright, XtChainLeft);
3613     sfactor_bar= XtCreateManagedWidget("sfactor_bar", scrollbarWidgetClass,
3614 				       form, Args, ArgCount);
3615     XtAddCallback(sfactor_bar, XtNjumpProc,
3616 		  (XtCallbackProc) change_sfactor_value, (XtPointer)NULL);
3617     XtAddCallback(sfactor_bar, XtNscrollProc,
3618 		  (XtCallbackProc) scroll_sfactor_value, (XtPointer)NULL);
3619 
3620     XawScrollbarSetThumb(sfactor_bar,
3621 			 SFACTOR_TO_PERCENTAGE(sub_sfactor->s), THUMB_H);
3622 
3623     FirstArg(XtNfromHoriz, sfactor_bar);
3624     NextArg(XtNborderWidth, 0);
3625     NextArg(XtNjustify, XtJustifyLeft);
3626     NextArg(XtNtop, XtChainBottom);
3627     NextArg(XtNbottom, XtChainBottom);
3628     NextArg(XtNleft, XtChainLeft);
3629     NextArg(XtNright, XtChainLeft);
3630     label= XtCreateManagedWidget(use_item, labelWidgetClass, form,
3631 			      Args, ArgCount);
3632 
3633     /* get height and width of label widget and distance between widgets */
3634     FirstArg(XtNheight, &label_height);
3635     NextArg(XtNwidth, &label_width);
3636     NextArg(XtNvertDistance, &dist);
3637     GetValues(label);
3638 
3639 
3640     FirstArg(XtNfromVert, label);
3641     NextArg(XtNfromHoriz, sfactor_bar);
3642     NextArg(XtNvertDistance, dist);
3643     NextArg(XtNtop, XtChainBottom);
3644     NextArg(XtNbottom, XtChainBottom);
3645     NextArg(XtNleft, XtChainLeft);
3646     NextArg(XtNright, XtChainLeft);
3647     but1 = XtCreateManagedWidget("Done", commandWidgetClass, form, Args, ArgCount);
3648     XtAddCallback(but1, XtNcallback, (XtCallbackProc) done_button, (XtPointer) NULL);
3649 
3650     below = but1;
3651     FirstArg(XtNfromHoriz, but1);
3652     NextArg(XtNfromVert, label);
3653     NextArg(XtNvertDistance, dist);
3654     NextArg(XtNtop, XtChainBottom);
3655     NextArg(XtNbottom, XtChainBottom);
3656     NextArg(XtNleft, XtChainLeft);
3657     NextArg(XtNright, XtChainLeft);
3658     but1 = XtCreateManagedWidget("Cancel", commandWidgetClass, form,
3659 				 Args, ArgCount);
3660     XtAddCallback(but1, XtNcallback, (XtCallbackProc) cancel_button,
3661 		  (XtPointer) NULL);
3662 
3663     /* fromVert and vertDistance  must be first, for direct access to the Args array in the loop */
3664     FirstArg(XtNfromVert, below);
3665     NextArg(XtNvertDistance, 7 * dist); /* it must be second, same reason */
3666     NextArg(XtNfromHoriz, sfactor_bar);
3667     NextArg(XtNwidth, label_width);
3668     NextArg(XtNtop, XtChainBottom);
3669     NextArg(XtNbottom, XtChainBottom);
3670     NextArg(XtNleft, XtChainLeft);
3671     NextArg(XtNright, XtChainLeft);
3672     for (i=0; i<3; i++)
3673       {
3674 	below = but_spline[i] = XtCreateManagedWidget(sfactor_type[i].label,
3675 				   commandWidgetClass, form, Args, ArgCount);
3676 	XtAddCallback(but_spline[i], XtNcallback,
3677 		      (XtCallbackProc) toggle_sfactor_type, (XtPointer) i);
3678 	XtSetArg(Args[0], XtNfromVert, below);        /* here are the direct */
3679 	XtSetArg(Args[1], XtNvertDistance, 3 * dist); /* accesses to Args    */
3680       }
3681 }
3682 
3683 
3684 static void
toggle_sfactor_type(Widget panel_local,XtPointer _sfactor_index,XtPointer call_data)3685 toggle_sfactor_type(Widget panel_local, XtPointer _sfactor_index,
3686 		XtPointer call_data)
3687 {
3688 	(void)panel_local;
3689 	(void)call_data;
3690   intptr_t         sfactor_index = (intptr_t)_sfactor_index;
3691 
3692   update_sfactor_value(sfactor_type[sfactor_index].value);
3693   XawScrollbarSetThumb(sfactor_bar,
3694 		       SFACTOR_TO_PERCENTAGE(sub_sfactor->s), THUMB_H);
3695 }
3696 
3697 
3698 static void
change_sfactor_value(Widget panel_local,XtPointer closure,XtPointer _top)3699 change_sfactor_value(Widget panel_local, XtPointer closure, XtPointer _top)
3700 {
3701 	(void)closure;
3702   float	   *top = (float *) _top;
3703 
3704   update_sfactor_value(PERCENTAGE_TO_CONTROL(*top));
3705   XawScrollbarSetThumb(panel_local, *top, THUMB_H);
3706 
3707 }
3708 
3709 static void
scroll_sfactor_value(Widget panel_local,XtPointer closure,XtPointer _num_pixels)3710 scroll_sfactor_value(Widget panel_local, XtPointer closure,
3711 		XtPointer _num_pixels)
3712 {
3713 	(void)closure;
3714   intptr_t	   num_pixels = (intptr_t) _num_pixels;
3715 
3716   update_sfactor_value(sub_sfactor->s +
3717 		       (STEP_VALUE * SFACTOR_SIGN(num_pixels)));
3718   XawScrollbarSetThumb(panel_local, SFACTOR_TO_PERCENTAGE(sub_sfactor->s),
3719 		       THUMB_H);
3720 }
3721 
3722 static void
update_sfactor_value(double new_value)3723 update_sfactor_value(double new_value)
3724 {
3725   /* To get exactly -1.0, a little bit of overshoot must be allowed.
3726      For +1.0, an overshoot is not necessary. */
3727   if (new_value < -1.01 || new_value > 1.)
3728     return;
3729 
3730   if (new_value == S_SPLINE_ANGULAR)
3731       new_value = 1.0E-5;
3732 
3733   toggle_pointmarker(edited_point->x, edited_point->y);
3734   draw_subspline(num_spline_points, sub_new_s, ERASE);
3735 
3736   sub_sfactor->s = new_value;
3737 
3738   if ((approx_spline(new_s) && new_value != S_SPLINE_APPROX)
3739       || (int_spline(new_s) && new_value != S_SPLINE_INTERP))
3740     new_s->type = (open_spline(new_s)) ? T_OPEN_XSPLINE : T_CLOSED_XSPLINE;
3741 
3742   changed = True;
3743   draw_subspline(num_spline_points, sub_new_s, PAINT);
3744   toggle_pointmarker(edited_point->x, edited_point->y);
3745 }
3746 
3747 /* come here when the user changes either the fill or pen color */
3748 /* update the fill intensity/pattern images */
3749 
recolor_fill_image(void)3750 void recolor_fill_image(void)
3751 {
3752     if (fill_style_exists) {
3753 	update_fill_image((Widget) 0, (XtPointer) 0, (XtPointer) 0);
3754     }
3755 }
3756 
3757 /* update the image of the fill intensity or pattern when user presses up/down in spinner */
3758 
3759 static void
update_fill_image(Widget w,XtPointer dummy,XtPointer dummy2)3760 update_fill_image(Widget w, XtPointer dummy, XtPointer dummy2)
3761 {
3762 	(void)w;
3763 	(void)dummy;
3764 	(void)dummy2;
3765     char	  *sval;
3766     int		   val;
3767     Pixel	   bg;
3768 
3769     /* get the background color of the main form if we haven't already done that */
3770     if (XtIsRealized(form)) {
3771 	FirstArg(XtNbackground, &form_bg);
3772 	GetValues(form);
3773     }
3774 
3775     /* get current value from the fill intensity spinner */
3776 
3777     sval = panel_get_value(fill_intens_panel);
3778     /* if there is a number there, then intensity is used */
3779     if (sval[0]!=' ') {
3780 	val = atoi(sval);
3781 	/* check for min/max */
3782 	if ((fill_color == BLACK || fill_color == WHITE)? (val > 100): (val > 200) || val < 0) {
3783 	    if (val < 0)
3784 		val = 0;
3785 	    else {
3786 		if (fill_color == BLACK || fill_color == WHITE)
3787 		    val = 100;
3788 		else
3789 		    val = 200;
3790 	    }
3791 	    panel_set_int(fill_intens_panel,val);
3792 	}
3793 
3794 	/* get current colors into the gc */
3795 	XSetForeground(tool_d,fill_image_gc,x_color(fill_color));
3796 	/* shade (use BLACK) or tint (use WHITE)? */
3797 	bg = (val <= 100? BLACK: WHITE);
3798 	XSetBackground(tool_d,fill_image_gc,x_color(bg));
3799 
3800 	/* convert intensity to shade/tint index */
3801 	val = val / (200 / (NUMSHADEPATS+NUMTINTPATS-1));
3802 
3803 	/* update the pixmap */
3804 	set_image_pm(val);
3805     } else {
3806 	/* get current value from the fill pattern spinner */
3807 	sval = panel_get_value(fill_pat_panel);
3808 	/* if there is a number there, then pattern is used */
3809 	if (sval[0]==' ') {
3810 	    FirstArg(XtNbitmap, None);
3811 	    NextArg(XtNbackground, form_bg);
3812 	    SetValues(fill_image);
3813 	} else {
3814 	    val = atoi(sval);
3815 	    /* check for min/max */
3816 	    if (val >= NUMPATTERNS || val < 0) {
3817 		if (val < 0)
3818 		    val = 0;
3819 		else
3820 		    val = NUMPATTERNS-1;
3821 	       panel_set_int(fill_pat_panel,val);
3822 	    }
3823 	    val += NUMSHADEPATS+NUMTINTPATS;
3824 
3825 	    /* get current colors into the gc */
3826 	    XSetForeground(tool_d,fill_image_gc,x_color(pen_color));
3827 	    XSetBackground(tool_d,fill_image_gc,x_color(fill_color));
3828 
3829 	    /* update the pixmap */
3830 	    set_image_pm(val);
3831 	}
3832     }
3833 }
3834 
3835 /* update the pixmap in the proper widget */
3836 
3837 static void
set_image_pm(int val)3838 set_image_pm(int val)
3839 {
3840 	/* set stipple from the one-bit bitmap */
3841 	XSetStipple(tool_d, fill_image_gc, fill_image_bm[val]);
3842 	/* stipple the bitmap into the pixmap with the desired color */
3843 	XFillRectangle(tool_d, fill_image_pm, fill_image_gc, 0, 0, FILL_SIZE, FILL_SIZE);
3844 	/* put the pixmap in the widget background */
3845 	FirstArg(XtNbitmap, None);
3846 	SetValues(fill_image);
3847 	FirstArg(XtNbitmap, fill_image_pm);
3848 	SetValues(fill_image);
3849 }
3850 
3851 /* make fill style menu and associated stuff */
3852 /* fill = fill value, fill_flag = 0 means no fill, 1=intensity, 2=pattern */
3853 
3854 static void
fill_style_menu(int fill,int fill_flag)3855 fill_style_menu(int fill, int fill_flag)
3856 {
3857 	static	char *fill_style_items[] = {
3858 			"No fill", "Filled ", "Pattern"};
3859 	int	i,j;
3860 	Pixel	fg,bg;
3861 
3862 	fg = x_color(pen_color);
3863 	bg = x_color(fill_color);
3864 	if (!fill_image_bm_exist) {
3865 	    fill_image_bm_exist = True;
3866 	    fill_image_gc = makegc(PAINT, fg, bg);
3867 	    fill_image_pm = XCreatePixmap(tool_d, tool_w, FILL_SIZE, FILL_SIZE, tool_dpth);
3868 	    XSetFillStyle(tool_d, fill_image_gc, FillOpaqueStippled);
3869 	    /* make the one-bit deep bitmaps and blank pixmaps */
3870 	    for (i = 0; i < NUMSHADEPATS; i++) {
3871 		fill_image_bm[i] = XCreateBitmapFromData(tool_d, tool_w,
3872 					(char*) shade_images[i], SHADE_IM_SIZE, SHADE_IM_SIZE);
3873 	    }
3874 	    for (i = NUMSHADEPATS; i < NUMSHADEPATS+NUMTINTPATS; i++) {
3875 		j = NUMSHADEPATS+NUMTINTPATS-i-1;	/* reverse the patterns */
3876 		fill_image_bm[i] = XCreateBitmapFromData(tool_d, tool_w,
3877 					(char*) shade_images[j], SHADE_IM_SIZE, SHADE_IM_SIZE);
3878 	    }
3879 	    for (i = NUMSHADEPATS+NUMTINTPATS; i < NUMFILLPATS; i++) {
3880 		j = i-(NUMSHADEPATS+NUMTINTPATS);
3881 		fill_image_bm[i] = XCreateBitmapFromData(tool_d, tool_w,
3882 				   pattern_images[j].cdata,
3883 				   pattern_images[j].cwidth,
3884 				   pattern_images[j].cheight);
3885 	    }
3886 	}
3887 	FirstArg(XtNfromVert, below);
3888 	NextArg(XtNborderWidth, 0);
3889 	NextArg(XtNtop, XtChainBottom);
3890 	NextArg(XtNbottom, XtChainBottom);
3891 	NextArg(XtNleft, XtChainLeft);
3892 	NextArg(XtNright, XtChainLeft);
3893 	beside = XtCreateManagedWidget("Fill style", labelWidgetClass,
3894 				       form, Args, ArgCount);
3895 	FirstArg(XtNfromVert, below);
3896 	NextArg(XtNfromHoriz, beside);
3897 	NextArg(XtNleftBitmap, menu_arrow);	/* use menu arrow for pull-down */
3898 	NextArg(XtNtop, XtChainBottom);
3899 	NextArg(XtNbottom, XtChainBottom);
3900 	NextArg(XtNleft, XtChainLeft);
3901 	NextArg(XtNright, XtChainLeft);
3902 	fill_style_button = XtCreateManagedWidget(fill_style_items[fill_flag],
3903 				menuButtonWidgetClass, form, Args, ArgCount);
3904 	below = fill_style_button;
3905 	make_pulldown_menu(fill_style_items, XtNumber(fill_style_items), -1, "",
3906 			       fill_style_button, fill_style_select);
3907 
3908 	fill_intens = int_panel_callb(fill, form, "Fill intensity %",
3909 				(Widget) 0, &fill_intens_panel, 0, 200, 5, update_fill_image);
3910 	fill_intens_label = beside;	/* save pointer to fill label */
3911 
3912 	fill_pat = int_panel_callb(fill, form, "Fill pattern    ",
3913 				(Widget) 0, &fill_pat_panel, 0, NUMPATTERNS-1, 1, update_fill_image);
3914 
3915 	fill_pat_label = beside;	/* save pointer to fill label */
3916 
3917 	/* make fill intensity spinner widget sensitive or not */
3918 	XtSetSensitive(fill_intens,(fill_flag==1));
3919 	FirstArg(XtNhorizDistance, 20);
3920 	NextArg(XtNsensitive, (fill_flag==1));
3921 	SetValues(fill_intens_label); /* and label (and position it) */
3922 	/* if fill is not a fill %, blank it out */
3923 	if (fill_flag != 1)
3924 	    panel_clear_value(fill_intens_panel);
3925 
3926 	/* make label widget to the right of fill intensity and pattern to show chosen */
3927 
3928 	FirstArg(XtNlabel,"");
3929 	NextArg(XtNwidth, FILL_SIZE);
3930 	NextArg(XtNheight, FILL_SIZE);
3931 	NextArg(XtNinternalWidth, 0);
3932 	NextArg(XtNinternalHeight, 0);
3933 	NextArg(XtNfromHoriz, fill_pat);
3934 	NextArg(XtNfromVert, fill_pat);
3935 	NextArg(XtNvertDistance, -FILL_SIZE-2);
3936 	NextArg(XtNhorizDistance, 5);
3937 	NextArg(XtNtop, XtChainBottom);
3938 	NextArg(XtNbottom, XtChainBottom);
3939 	NextArg(XtNleft, XtChainLeft);
3940 	NextArg(XtNright, XtChainLeft);
3941 	fill_image = XtCreateManagedWidget("fill_image", labelWidgetClass,
3942 				form, Args, ArgCount);
3943 	/* put the pixmap in the widget background */
3944 	if (fill_flag == 1 || fill_flag == 2) {
3945 	    update_fill_image((Widget) 0, (XtPointer) 0, (XtPointer) 0);
3946 	}
3947 
3948 	/* make fill pattern panel insensitive if not a fill pattern */
3949 	XtSetSensitive(fill_pat,(fill_flag==2));
3950 	FirstArg(XtNhorizDistance, 20);
3951 	NextArg(XtNsensitive, (fill_flag==2));
3952 	SetValues(fill_pat_label);
3953 
3954 	/* and blank value if not a pattern */
3955 	if (fill_flag != 2)
3956 	    panel_clear_value(fill_pat_panel);
3957 	/* say we exist */
3958 	fill_style_exists = True;
3959 }
3960 
3961 /* make a popup arc type menu */
3962 static void
arc_type_menu(void)3963 arc_type_menu(void)
3964 {
3965 	static char   *arc_type_items[] = {
3966 			 "Open     ", "Pie Wedge"};
3967 
3968 	FirstArg(XtNfromVert, below);
3969 	NextArg(XtNborderWidth, 0);
3970 	NextArg(XtNtop, XtChainBottom);
3971 	NextArg(XtNbottom, XtChainBottom);
3972 	NextArg(XtNleft, XtChainLeft);
3973 	NextArg(XtNright, XtChainLeft);
3974 	beside = XtCreateManagedWidget("  Arc type", labelWidgetClass,
3975 				       form, Args, ArgCount);
3976 	FirstArg(XtNfromVert, below);
3977 	NextArg(XtNfromHoriz, beside);
3978 	NextArg(XtNleftBitmap, menu_arrow);	/* use menu arrow for pull-down */
3979 	NextArg(XtNtop, XtChainBottom);
3980 	NextArg(XtNbottom, XtChainBottom);
3981 	NextArg(XtNleft, XtChainLeft);
3982 	NextArg(XtNright, XtChainLeft);
3983 	arc_type_panel = XtCreateManagedWidget(
3984 			arc_type_items[generic_vals.arc_type],
3985 			menuButtonWidgetClass,
3986 			form, Args, ArgCount);
3987 	below = arc_type_panel;
3988 	make_pulldown_menu(arc_type_items, XtNumber(arc_type_items), -1, "",
3989 			       arc_type_panel, arc_type_select);
3990 }
3991 
3992 static void
join_style_panel_menu(void)3993 join_style_panel_menu(void)
3994 {
3995 	FirstArg(XtNfromVert, below);
3996 	NextArg(XtNhorizDistance, 10);	/* space it a bit from the cap style */
3997 	NextArg(XtNfromHoriz, beside);
3998 	NextArg(XtNborderWidth, 0);
3999 	NextArg(XtNtop, XtChainBottom);
4000 	NextArg(XtNbottom, XtChainBottom);
4001 	NextArg(XtNleft, XtChainLeft);
4002 	NextArg(XtNright, XtChainLeft);
4003 	beside = XtCreateManagedWidget("Join style", labelWidgetClass,
4004 				       form, Args, ArgCount);
4005 	FirstArg(XtNfromVert, below);
4006 	NextArg(XtNfromHoriz, beside);
4007 	NextArg(XtNinternalWidth, 0);
4008 	NextArg(XtNinternalHeight, 0);
4009 	NextArg(XtNbitmap, joinstyle_choices[generic_vals.join_style].pixmap);
4010 	NextArg(XtNtop, XtChainBottom);
4011 	NextArg(XtNbottom, XtChainBottom);
4012 	NextArg(XtNleft, XtChainLeft);
4013 	NextArg(XtNright, XtChainLeft);
4014 	join_style_panel = XtCreateManagedWidget("join_style",
4015 				menuButtonWidgetClass, form, Args, ArgCount);
4016 	make_pulldown_menu_images(joinstyle_choices, NUM_JOINSTYLE_TYPES,
4017 			    joinstyle_pixmaps, NULL,
4018 			    join_style_panel, join_style_select);
4019 }
4020 
4021 /* make a popup cap style menu */
4022 static void
cap_style_panel_menu(void)4023 cap_style_panel_menu(void)
4024 {
4025 	FirstArg(XtNfromVert, below);
4026 	NextArg(XtNborderWidth, 0);
4027 	NextArg(XtNtop, XtChainBottom);
4028 	NextArg(XtNbottom, XtChainBottom);
4029 	NextArg(XtNleft, XtChainLeft);
4030 	NextArg(XtNright, XtChainLeft);
4031 	beside = XtCreateManagedWidget("Cap style", labelWidgetClass,
4032 				       form, Args, ArgCount);
4033 	FirstArg(XtNfromVert, below);
4034 	NextArg(XtNfromHoriz, beside);
4035 	NextArg(XtNinternalWidth, 0);
4036 	NextArg(XtNinternalHeight, 0);
4037 	NextArg(XtNbitmap, capstyle_choices[generic_vals.cap_style].pixmap);
4038 	NextArg(XtNtop, XtChainBottom);
4039 	NextArg(XtNbottom, XtChainBottom);
4040 	NextArg(XtNleft, XtChainLeft);
4041 	NextArg(XtNright, XtChainLeft);
4042 	cap_style_panel = XtCreateManagedWidget("cap_style_image", menuButtonWidgetClass,
4043 					form, Args, ArgCount);
4044 	FirstArg(XtNfromVert, below);
4045 	NextArg(XtNfromHoriz, cap_style_panel);
4046 	NextArg(XtNborderWidth, 0);
4047 	make_pulldown_menu_images(capstyle_choices, NUM_CAPSTYLE_TYPES,
4048 			    capstyle_pixmaps, NULL, cap_style_panel, cap_style_select);
4049 }
4050 
4051 /* make a button panel with the image 'pixmap' in it */
4052 /* for the font selection */
4053 
4054 void		f_menu_popup(void);
4055 
4056 static XtCallbackRec f_sel_callback[] =
4057 {
4058     {(XtCallbackProc)f_menu_popup, NULL},
4059     {NULL, NULL},
4060 };
4061 
set_font_image(Widget widget)4062 void set_font_image(Widget widget)
4063 {
4064     FirstArg(XtNbitmap, new_psflag ?
4065 	     psfont_menu_bitmaps[new_ps_font + 1] :
4066 	     latexfont_menu_bitmaps[new_latex_font]);
4067     SetValues(widget);
4068 }
4069 
4070 static void
font_image_panel(Pixmap pixmap,char * label,Widget * pi_x)4071 font_image_panel(Pixmap pixmap, char *label, Widget *pi_x)
4072 {
4073     FirstArg(XtNfromVert, below);
4074     NextArg(XtNlabel, label);
4075     NextArg(XtNborderWidth, 0);
4076     NextArg(XtNtop, XtChainBottom);
4077     NextArg(XtNbottom, XtChainBottom);
4078     NextArg(XtNleft, XtChainLeft);
4079     NextArg(XtNright, XtChainLeft);
4080     below = XtCreateManagedWidget(label, labelWidgetClass, form, Args, ArgCount);
4081 
4082     FirstArg(XtNfromVert, below);
4083     NextArg(XtNvertDistance, 2);
4084     NextArg(XtNbitmap, pixmap);
4085     NextArg(XtNcallback, f_sel_callback);
4086     NextArg(XtNwidth, MAX_FONTIMAGE_WIDTH);
4087     NextArg(XtNinternalWidth, 2);
4088     NextArg(XtNtop, XtChainBottom);
4089     NextArg(XtNbottom, XtChainBottom);
4090     NextArg(XtNleft, XtChainLeft);
4091     NextArg(XtNright, XtChainLeft);
4092     *pi_x = XtCreateManagedWidget(label, commandWidgetClass, form, Args, ArgCount);
4093     below = *pi_x;
4094 }
4095 
4096 /* come here when user presses font image button */
4097 
4098 void
f_menu_popup(void)4099 f_menu_popup(void)
4100 {
4101     fontpane_popup(&new_ps_font, &new_latex_font, &new_psflag,
4102 		   set_font_image, font_panel);
4103 }
4104 
4105 static Widget
pen_color_selection_panel(void)4106 pen_color_selection_panel(void)
4107 {
4108     color_selection_panel(" Pen color","border_colors", "Pen color", form, below, beside,
4109 			&pen_col_button, &pen_color_popup,
4110 			generic_vals.pen_color, pen_color_select);
4111     return pen_col_button;
4112 }
4113 
4114 static Widget
fill_color_selection_panel(void)4115 fill_color_selection_panel(void)
4116 {
4117     color_selection_panel("Fill color","fill_colors", "Fill color", form, below, beside,
4118 			&fill_col_button, &fill_color_popup,
4119 			generic_vals.fill_color, fill_color_select);
4120     return fill_col_button;
4121 }
4122 
4123 Widget
color_selection_panel(char * label,char * wname,char * name,Widget parent,Widget below,Widget beside,Widget * button,Widget * popup,int color,XtCallbackProc callback)4124 color_selection_panel(char *label, char *wname, char *name, Widget parent, Widget below, Widget beside, Widget *button, Widget *popup, int color, XtCallbackProc callback)
4125 {
4126 
4127 	/* avoid a -Wint-to-void-pointer-cast warning */
4128 	intptr_t	col = color;
4129     FirstArg(XtNfromVert, below);
4130     NextArg(XtNborderWidth, 0);
4131     NextArg(XtNtop, XtChainBottom);
4132     NextArg(XtNbottom, XtChainBottom);
4133     NextArg(XtNleft, XtChainLeft);
4134     NextArg(XtNright, XtChainLeft);
4135     beside = XtCreateManagedWidget(label, labelWidgetClass,
4136 				   parent, Args, ArgCount);
4137     set_color_name(color,buf);
4138 
4139     FirstArg(XtNfromVert, below);
4140     NextArg(XtNfromHoriz, beside);
4141     NextArg(XtNwidth, COLOR_BUT_WID);
4142     NextArg(XtNleftBitmap, menu_arrow);	/* use menu arrow for pull-down */
4143     NextArg(XtNtop, XtChainBottom);
4144     NextArg(XtNbottom, XtChainBottom);
4145     NextArg(XtNleft, XtChainLeft);
4146     NextArg(XtNright, XtChainLeft);
4147     below = *button = XtCreateManagedWidget(wname,
4148 		     menuButtonWidgetClass, parent, Args, ArgCount);
4149     /*
4150      * cheat a little - set the initial fore/background colors by calling the
4151      * callback
4152      */
4153     /* also set the label */
4154     (callback)(below, (XtPointer) col, NULL);
4155     *popup = make_color_popup_menu(below, name, callback, NO_TRANSP, NO_BACKG);
4156 
4157     return *button;
4158 }
4159 
4160 static Widget
int_panel(int x,Widget parent,char * label,Widget beside,Widget * pi_x,int min,int max,int inc)4161 int_panel(int x, Widget parent, char *label, Widget beside, Widget *pi_x, int min, int max, int inc)
4162 {
4163     return int_panel_callb(x, parent, label, beside, pi_x, min, max, inc, (XtCallbackProc) 0);
4164 }
4165 
4166 static Widget
int_panel_callb(int x,Widget parent,char * label,Widget pbeside,Widget * pi_x,int min,int max,int inc,XtCallbackProc callback)4167 int_panel_callb(int x, Widget parent, char *label, Widget pbeside, Widget *pi_x, int min, int max, int inc, XtCallbackProc callback)
4168 {
4169     FirstArg(XtNfromVert, below);
4170     NextArg(XtNfromHoriz, pbeside);
4171     NextArg(XtNlabel, label);
4172     NextArg(XtNborderWidth, 0);
4173     NextArg(XtNtop, XtChainBottom);
4174     NextArg(XtNbottom, XtChainBottom);
4175     NextArg(XtNleft, XtChainLeft);
4176     NextArg(XtNright, XtChainLeft);
4177     beside = XtCreateManagedWidget(label, labelWidgetClass, parent, Args, ArgCount);
4178 
4179     sprintf(buf, "%d", x);
4180     below = MakeIntSpinnerEntry(parent, pi_x, label, below, beside,
4181 		callback, buf, min, max, inc, 45);
4182     /* we want the spinner to be chained to the bottom (it's below the comments) */
4183     FirstArg(XtNtop, XtChainBottom);
4184     NextArg(XtNbottom, XtChainBottom);
4185     SetValues(below);
4186     text_transl(*pi_x);
4187     return below;
4188 }
4189 
4190 static Widget
float_panel(float x,Widget parent,char * label,Widget pbeside,Widget * pi_x,float min,float max,float inc,int prec)4191 float_panel(float x, Widget parent, char *label, Widget pbeside, Widget *pi_x, float min, float max, float inc, int prec)
4192 {
4193     char	    fmt[10];
4194 
4195     FirstArg(XtNfromVert, below);
4196     NextArg(XtNfromHoriz, pbeside);
4197     NextArg(XtNlabel, label);
4198     NextArg(XtNborderWidth, 0);
4199     NextArg(XtNtop, XtChainBottom);
4200     NextArg(XtNbottom, XtChainBottom);
4201     NextArg(XtNleft, XtChainLeft);
4202     NextArg(XtNright, XtChainLeft);
4203     beside = XtCreateManagedWidget(label, labelWidgetClass, parent,
4204 				   Args, ArgCount);
4205     /* first make format string from precision */
4206     sprintf(fmt, "%%.%df", prec);
4207     /* now format the value */
4208     sprintf(buf, fmt, x);
4209     below = MakeFloatSpinnerEntry(parent, pi_x, label, below, beside,
4210 		(XtCallbackProc) 0, buf, min, max, inc, 50);
4211     /* we want the spinner to be chained to the bottom (it's below the comments) */
4212     FirstArg(XtNtop, XtChainBottom);
4213     NextArg(XtNbottom, XtChainBottom);
4214     SetValues(below);
4215     text_transl(*pi_x);
4216     return below;
4217 }
4218 
4219 static void
float_label(float x,char * label,Widget * pi_x)4220 float_label(float x, char *label, Widget *pi_x)
4221 {
4222     FirstArg(XtNfromVert, below);
4223     NextArg(XtNlabel, label);
4224     NextArg(XtNborderWidth, 0);
4225     NextArg(XtNtop, XtChainBottom);
4226     NextArg(XtNbottom, XtChainBottom);
4227     NextArg(XtNleft, XtChainLeft);
4228     NextArg(XtNright, XtChainLeft);
4229     beside = XtCreateManagedWidget(label, labelWidgetClass, form,
4230 				   Args, ArgCount);
4231     sprintf(buf, "%1.1f", x);
4232     FirstArg(XtNfromVert, below);
4233     NextArg(XtNlabel, buf);
4234     NextArg(XtNfromHoriz, beside);
4235     NextArg(XtNwidth, 40);
4236     NextArg(XtNborderWidth, 0);
4237     NextArg(XtNtop, XtChainBottom);
4238     NextArg(XtNbottom, XtChainBottom);
4239     NextArg(XtNleft, XtChainLeft);
4240     NextArg(XtNright, XtChainLeft);
4241     *pi_x = XtCreateManagedWidget(label, labelWidgetClass, form,
4242 				  Args, ArgCount);
4243     below = *pi_x;
4244 }
4245 
4246 static void
int_label(int x,char * label,Widget * pi_x)4247 int_label(int x, char *label, Widget *pi_x)
4248 {
4249     FirstArg(XtNfromVert, below);
4250     NextArg(XtNlabel, label);
4251     NextArg(XtNborderWidth, 0);
4252     NextArg(XtNtop, XtChainBottom);
4253     NextArg(XtNbottom, XtChainBottom);
4254     NextArg(XtNleft, XtChainLeft);
4255     NextArg(XtNright, XtChainLeft);
4256     beside = XtCreateManagedWidget(label, labelWidgetClass, form,
4257 				   Args, ArgCount);
4258     sprintf(buf, "%d", x);
4259     FirstArg(XtNfromVert, below);
4260     NextArg(XtNlabel, buf);
4261     NextArg(XtNfromHoriz, beside);
4262     NextArg(XtNwidth, 40);
4263     NextArg(XtNborderWidth, 0);
4264     NextArg(XtNtop, XtChainBottom);
4265     NextArg(XtNbottom, XtChainBottom);
4266     NextArg(XtNleft, XtChainLeft);
4267     NextArg(XtNright, XtChainLeft);
4268     *pi_x = XtCreateManagedWidget(label, labelWidgetClass, form,
4269 				  Args, ArgCount);
4270     below = *pi_x;
4271 }
4272 
4273 static void
str_panel(char * string,char * name,Widget * pi_x,int width,Boolean size_to_width,Boolean international)4274 str_panel(char *string, char *name, Widget *pi_x, int width, Boolean size_to_width, Boolean international)
4275 {
4276     int		    nlines;
4277     size_t	    i;
4278     Dimension	    pwidth;
4279     XFontStruct	   *temp_font;
4280     char	   *labelname, *textname;
4281 
4282 
4283     /* does the user want a label beside the text widget? */
4284     if (name && strlen(name) > 0) {
4285 	/* yes, make it and manage it */
4286 	/* make the labels of the widgets xxx_label for the label part and xxx_text for
4287 	   the asciiwidget part */
4288 	labelname = (char *) new_string(strlen(name)+7);
4289 	textname = (char *) new_string(strlen(name)+6);
4290 	strcpy(labelname,name);
4291 	strcat(labelname,"_label");
4292 	strcpy(textname,name);
4293 	strcat(textname,"_text");
4294 	FirstArg(XtNfromVert, below);
4295 	NextArg(XtNlabel, name);
4296 	NextArg(XtNborderWidth, 0);
4297 	NextArg(XtNtop, XtChainBottom);
4298 	NextArg(XtNbottom, XtChainBottom);
4299 	NextArg(XtNleft, XtChainLeft);
4300 	NextArg(XtNright, XtChainLeft);
4301 	beside = XtCreateManagedWidget(labelname, labelWidgetClass, form, Args, ArgCount);
4302 	/* get the font and width of above label widget */
4303 	FirstArg(XtNfont, &temp_font);
4304 	NextArg(XtNwidth, &pwidth);
4305 	GetValues(beside);
4306     } else {
4307 	/* no, make a widget to get the font, but don't manage it */
4308 	beside = (Widget) 0;
4309 	pwidth = 0;
4310 	beside = XtCreateWidget("dummy", labelWidgetClass, form, Args, ArgCount);
4311 	textname = "text_text";
4312 	/* get the font of above label widget */
4313 	FirstArg(XtNfont, &temp_font);
4314 	GetValues(beside);
4315 	beside = 0;
4316     }
4317     /* make panel as wide as image pane above less the label widget's width */
4318     /* but at least "width" pixels wide */
4319     if (size_to_width)
4320 	width = max2(PS_FONTPANE_WD - pwidth + 2, width);
4321 
4322     /* count number of lines in this text string */
4323     nlines = 1;			/* number of lines in string */
4324     for (i = 0; i < strlen(string); i++) {
4325 	if (string[i] == '\n') {
4326 	    nlines++;
4327 	}
4328     }
4329     if (nlines > 4)	/* limit to displaying 4 lines and show scrollbars */
4330 	nlines = 4;
4331     FirstArg(XtNfromVert, below);
4332     NextArg(XtNstring, string);
4333     NextArg(XtNinsertPosition, strlen(string));
4334     NextArg(XtNfromHoriz, beside);
4335     NextArg(XtNeditType, XawtextEdit);
4336     NextArg(XtNwidth, width);
4337     /* allow enough height for scrollbar */
4338     NextArg(XtNheight, max_char_height(temp_font) * nlines + 20);
4339     NextArg(XtNscrollHorizontal, XawtextScrollWhenNeeded);
4340     NextArg(XtNscrollVertical, XawtextScrollWhenNeeded);
4341     NextArg(XtNtop, XtChainBottom);
4342     NextArg(XtNbottom, XtChainBottom);
4343     NextArg(XtNleft, XtChainLeft);
4344     NextArg(XtNright, XtChainRight);
4345 #ifdef I18N
4346     if (!appres.international || !international)
4347       NextArg(XtNinternational, False);
4348 #endif /* I18N */
4349     *pi_x = XtCreateManagedWidget(textname, asciiTextWidgetClass, form, Args, ArgCount);
4350 
4351     /* make CR do nothing for now */
4352     text_transl(*pi_x);
4353 
4354     /* read personal key configuration */
4355     XtOverrideTranslations(*pi_x, XtParseTranslationTable(local_translations));
4356 
4357     below = *pi_x;
4358 
4359     if (name && strlen(name) > 0) {
4360 	free((char *) textname);
4361 	free((char *) labelname);
4362     }
4363 }
4364 
4365 /* call with make_unit_menu = True to make pulldown unit menu beside first label */
4366 
4367 static void
xy_panel(int x,int y,char * label,Widget * pi_x,Widget * pi_y,Boolean make_unit_menu)4368 xy_panel(int x, int y, char *label, Widget *pi_x, Widget *pi_y, Boolean make_unit_menu)
4369 {
4370     Widget	    save_below = below;
4371 
4372     FirstArg(XtNfromVert, below);
4373     NextArg(XtNlabel, label);
4374     NextArg(XtNborderWidth, 0);
4375     NextArg(XtNtop, XtChainBottom);
4376     NextArg(XtNbottom, XtChainBottom);
4377     NextArg(XtNleft, XtChainLeft);
4378     NextArg(XtNright, XtChainLeft);
4379     below = XtCreateManagedWidget(label, labelWidgetClass, form, Args, ArgCount);
4380 
4381     /* pulldown menu for units */
4382     if (make_unit_menu)
4383 	(void) unit_pulldown_menu(save_below, below);
4384 
4385     FirstArg(XtNfromVert, below);
4386     NextArg(XtNhorizDistance, 20);
4387     NextArg(XtNlabel, "X =");
4388     NextArg(XtNborderWidth, 0);
4389     NextArg(XtNtop, XtChainBottom);
4390     NextArg(XtNbottom, XtChainBottom);
4391     NextArg(XtNleft, XtChainLeft);
4392     NextArg(XtNright, XtChainLeft);
4393     beside = XtCreateManagedWidget(label, labelWidgetClass, form, Args, ArgCount);
4394 
4395     cvt_to_units_str(x, buf);
4396     FirstArg(XtNfromVert, below);
4397     NextArg(XtNstring, buf);
4398     NextArg(XtNfromHoriz, beside);
4399     NextArg(XtNinsertPosition, strlen(buf));
4400     NextArg(XtNeditType, XawtextEdit);
4401     NextArg(XtNwidth, XY_WIDTH);
4402     NextArg(XtNtop, XtChainBottom);
4403     NextArg(XtNbottom, XtChainBottom);
4404     NextArg(XtNleft, XtChainLeft);
4405     NextArg(XtNright, XtChainLeft);
4406     *pi_x = XtCreateManagedWidget(label, asciiTextWidgetClass, form, Args, ArgCount);
4407     text_transl(*pi_x);
4408     add_to_convert(*pi_x);
4409 
4410     FirstArg(XtNfromVert, below);
4411     NextArg(XtNlabel, "Y =");
4412     NextArg(XtNborderWidth, 0);
4413     NextArg(XtNfromHoriz, *pi_x);
4414     NextArg(XtNtop, XtChainBottom);
4415     NextArg(XtNbottom, XtChainBottom);
4416     NextArg(XtNleft, XtChainLeft);
4417     NextArg(XtNright, XtChainLeft);
4418     beside = XtCreateManagedWidget(label, labelWidgetClass, form, Args, ArgCount);
4419 
4420     cvt_to_units_str(y, buf);
4421     FirstArg(XtNfromVert, below);
4422     NextArg(XtNstring, buf);
4423     NextArg(XtNfromHoriz, beside);
4424     NextArg(XtNinsertPosition, strlen(buf));
4425     NextArg(XtNeditType, XawtextEdit);
4426     NextArg(XtNwidth, XY_WIDTH);
4427     NextArg(XtNtop, XtChainBottom);
4428     NextArg(XtNbottom, XtChainBottom);
4429     NextArg(XtNleft, XtChainLeft);
4430     NextArg(XtNright, XtChainLeft);
4431     *pi_y = XtCreateManagedWidget(label, asciiTextWidgetClass, form, Args, ArgCount);
4432     text_transl(*pi_y);
4433     add_to_convert(*pi_y);
4434 
4435     below = *pi_x;
4436 }
4437 
4438 /* make an X= Y= pair of labels and text widgets with optional pulldown unit menu */
4439 /* Label for X and Y are variables */
4440 
4441 static void
f_pair_panel(F_pos * fp,char * label,Widget * pi_x,char * xlabel,Widget * pi_y,char * ylabel,Boolean make_unit_menu)4442 f_pair_panel(F_pos *fp, char *label, Widget *pi_x, char *xlabel, Widget *pi_y, char *ylabel, Boolean make_unit_menu)
4443 {
4444     Widget	    save_below = below;
4445 
4446     FirstArg(XtNfromVert, below);
4447     NextArg(XtNborderWidth, 0);
4448     NextArg(XtNtop, XtChainBottom);
4449     NextArg(XtNbottom, XtChainBottom);
4450     NextArg(XtNleft, XtChainLeft);
4451     NextArg(XtNright, XtChainLeft);
4452     below = XtCreateManagedWidget(label, labelWidgetClass, form, Args, ArgCount);
4453 
4454     /* pulldown menu for units */
4455     if (make_unit_menu)
4456 	(void) unit_pulldown_menu(save_below, below);
4457 
4458     FirstArg(XtNfromVert, below);
4459     NextArg(XtNhorizDistance, 20);
4460     NextArg(XtNlabel, xlabel);
4461     NextArg(XtNborderWidth, 0);
4462     NextArg(XtNtop, XtChainBottom);
4463     NextArg(XtNbottom, XtChainBottom);
4464     NextArg(XtNleft, XtChainLeft);
4465     NextArg(XtNright, XtChainLeft);
4466     beside = XtCreateManagedWidget(label, labelWidgetClass, form, Args, ArgCount);
4467 
4468     /* convert first number to desired units */
4469     cvt_to_units_str(fp->x, buf);
4470 
4471     FirstArg(XtNfromVert, below);
4472     NextArg(XtNstring, buf);
4473     NextArg(XtNfromHoriz, beside);
4474     NextArg(XtNinsertPosition, strlen(buf));
4475     NextArg(XtNeditType, XawtextEdit);
4476     NextArg(XtNwidth, XY_WIDTH);
4477     NextArg(XtNtop, XtChainBottom);
4478     NextArg(XtNbottom, XtChainBottom);
4479     NextArg(XtNleft, XtChainLeft);
4480     NextArg(XtNright, XtChainLeft);
4481     *pi_x = XtCreateManagedWidget(label, asciiTextWidgetClass, form, Args, ArgCount);
4482     text_transl(*pi_x);
4483     /* add this widget to the list that get conversions */
4484     add_to_convert(*pi_x);
4485 
4486     FirstArg(XtNfromVert, below);
4487     NextArg(XtNlabel, ylabel);
4488     NextArg(XtNborderWidth, 0);
4489     NextArg(XtNfromHoriz, *pi_x);
4490     NextArg(XtNtop, XtChainBottom);
4491     NextArg(XtNbottom, XtChainBottom);
4492     NextArg(XtNleft, XtChainLeft);
4493     NextArg(XtNright, XtChainLeft);
4494     beside = XtCreateManagedWidget(label, labelWidgetClass, form, Args, ArgCount);
4495 
4496     /* convert second number to desired units */
4497     cvt_to_units_str(fp->y, buf);
4498 
4499     FirstArg(XtNfromVert, below);
4500     NextArg(XtNstring, buf);
4501     NextArg(XtNfromHoriz, beside);
4502     NextArg(XtNinsertPosition, strlen(buf));
4503     NextArg(XtNeditType, XawtextEdit);
4504     NextArg(XtNwidth, XY_WIDTH);
4505     NextArg(XtNtop, XtChainBottom);
4506     NextArg(XtNbottom, XtChainBottom);
4507     NextArg(XtNleft, XtChainLeft);
4508     NextArg(XtNright, XtChainLeft);
4509     beside = *pi_y = XtCreateManagedWidget(label, asciiTextWidgetClass, form, Args, ArgCount);
4510     text_transl(*pi_y);
4511     /* add this widget to the list that get conversions */
4512     add_to_convert(*pi_y);
4513 
4514     below = *pi_x;
4515 }
4516 
4517 static void
get_f_pos(F_pos * fp,Widget pi_x,Widget pi_y)4518 get_f_pos(F_pos *fp, Widget pi_x, Widget pi_y)
4519 {
4520     fp->x = panel_get_dim_value(pi_x);
4521     fp->y = panel_get_dim_value(pi_y);
4522 }
4523 
4524 /* this makes a scrollable panel in which the x/y points for the
4525 	Fig object are displayed */
4526 
4527 static void
points_panel(struct f_point * p)4528 points_panel(struct f_point *p)
4529 {
4530     struct f_point *pts;
4531     char	    buf[32];
4532     int		    npts, j;
4533     Widget	    viewp,formw,beside,npoints;
4534 
4535     /* label */
4536     FirstArg(XtNfromVert, below);
4537     NextArg(XtNborderWidth, 0);
4538     NextArg(XtNtop, XtChainBottom);
4539     NextArg(XtNbottom, XtChainBottom);
4540     NextArg(XtNleft, XtChainLeft);
4541     NextArg(XtNright, XtChainLeft);
4542     beside = XtCreateManagedWidget("Points", labelWidgetClass, form,
4543 				  Args, ArgCount);
4544     /* number of points */
4545     FirstArg(XtNfromVert, below);
4546     NextArg(XtNlabel, "");
4547     NextArg(XtNfromHoriz, beside);
4548     NextArg(XtNborderWidth, 0);
4549     NextArg(XtNtop, XtChainBottom);
4550     NextArg(XtNbottom, XtChainBottom);
4551     NextArg(XtNleft, XtChainLeft);
4552     NextArg(XtNright, XtChainLeft);
4553     npoints = XtCreateManagedWidget("num_points", labelWidgetClass, form,
4554 				  Args, ArgCount);
4555     /* pulldown menu for units */
4556     below = unit_pulldown_menu(below, npoints);
4557 
4558     FirstArg(XtNallowVert, True);
4559     NextArg(XtNfromVert, below);
4560     NextArg(XtNvertDistance, 2);
4561     NextArg(XtNhorizDistance, 20);
4562     NextArg(XtNtop, XtChainBottom);
4563     NextArg(XtNbottom, XtChainBottom);
4564     NextArg(XtNleft, XtChainLeft);
4565     NextArg(XtNright, XtChainLeft);
4566     pts = p;
4567     for (npts = 0; pts != NULL; npts++)
4568 	pts = pts->next;
4569     /* limit size of points panel and scroll if more than 140 pixels */
4570     if (npts > 6)
4571 	    NextArg(XtNheight, 140);
4572     viewp = XtCreateManagedWidget("pointspanel", viewportWidgetClass, form, Args, ArgCount);
4573     formw = XtCreateManagedWidget("pointsform", formWidgetClass, viewp, NULL, 0);
4574     below = (Widget) 0;
4575     /* initialize which panels to convert */
4576     init_convert_array();
4577     for (j = 0; j < npts; j++) {
4578 	/* limit number of points displayed to prevent system failure :-) */
4579 	if (j >= MAXDISPTS) {
4580 	    FirstArg(XtNfromVert, below);
4581 	    NextArg(XtNtop, XtChainBottom);
4582 	    NextArg(XtNbottom, XtChainBottom);
4583 	    NextArg(XtNleft, XtChainLeft);
4584 	    NextArg(XtNright, XtChainLeft);
4585 	    XtCreateManagedWidget("Too many points to display  ", labelWidgetClass,
4586 						formw, Args, ArgCount);
4587 	    break;
4588 	}
4589 	FirstArg(XtNfromVert, below);
4590 	NextArg(XtNborderWidth, 0);
4591 	NextArg(XtNtop, XtChainBottom);
4592 	NextArg(XtNbottom, XtChainBottom);
4593 	NextArg(XtNleft, XtChainLeft);
4594 	NextArg(XtNright, XtChainLeft);
4595 	sprintf(buf, "X%d =", j);
4596 	beside = XtCreateManagedWidget(buf, labelWidgetClass, formw,
4597 				       Args, ArgCount);
4598 	cvt_to_units_str(p->x, buf);
4599 	FirstArg(XtNfromVert, below);
4600 	NextArg(XtNstring, buf);
4601 	NextArg(XtNfromHoriz, beside);
4602 	NextArg(XtNinsertPosition, strlen(buf));
4603 	NextArg(XtNeditType, XawtextEdit);
4604 	NextArg(XtNwidth, XY_WIDTH);
4605 	NextArg(XtNtop, XtChainBottom);
4606 	NextArg(XtNbottom, XtChainBottom);
4607 	NextArg(XtNleft, XtChainLeft);
4608 	NextArg(XtNright, XtChainLeft);
4609 	px_panel[j] = XtCreateManagedWidget("xy", asciiTextWidgetClass,
4610 					    formw, Args, ArgCount);
4611 	text_transl(px_panel[j]);
4612 	/* this panel is also converted by units */
4613 	add_to_convert(px_panel[j]);
4614 
4615 	sprintf(buf, "Y%d =", j);
4616 	FirstArg(XtNfromVert, below);
4617 	NextArg(XtNfromHoriz, px_panel[j]);
4618 	NextArg(XtNborderWidth, 0);
4619 	NextArg(XtNtop, XtChainBottom);
4620 	NextArg(XtNbottom, XtChainBottom);
4621 	NextArg(XtNleft, XtChainLeft);
4622 	NextArg(XtNright, XtChainLeft);
4623 	beside = XtCreateManagedWidget(buf, labelWidgetClass,
4624 				       formw, Args, ArgCount);
4625 
4626 	cvt_to_units_str(p->y, buf);
4627 	FirstArg(XtNfromVert, below);
4628 	NextArg(XtNstring, buf);
4629 	NextArg(XtNfromHoriz, beside);
4630 	NextArg(XtNinsertPosition, strlen(buf));
4631 	NextArg(XtNeditType, XawtextEdit);
4632 	NextArg(XtNwidth, XY_WIDTH);
4633 	NextArg(XtNtop, XtChainBottom);
4634 	NextArg(XtNbottom, XtChainBottom);
4635 	NextArg(XtNleft, XtChainLeft);
4636 	NextArg(XtNright, XtChainLeft);
4637 
4638 	py_panel[j] = XtCreateManagedWidget("xy", asciiTextWidgetClass,
4639 					    formw, Args, ArgCount);
4640 	text_transl(py_panel[j]);
4641 	/* this panel is also converted by units */
4642 	add_to_convert(py_panel[j]);
4643 
4644 	below = px_panel[j];
4645 
4646 	p = p->next;
4647     }
4648     /* now put the (actual) number of points in a label */
4649     sprintf(buf, "%d", npts);
4650     FirstArg(XtNlabel, buf);
4651     SetValues(npoints);
4652 }
4653 
4654 static void
get_points(struct f_point * p)4655 get_points(struct f_point *p)
4656 {
4657     struct f_point *q;
4658     int		    i;
4659 
4660     for (q = p, i = 0; q != NULL; i++) {
4661 	if (i >= MAXDISPTS)
4662 	    break;
4663 	q->x = panel_get_dim_value(px_panel[i]);
4664 	q->y = panel_get_dim_value(py_panel[i]);
4665 	q = q->next;
4666     }
4667 }
4668 
4669 /* make a unit pulldown menubutton and menu */
4670 
4671 static Widget
unit_pulldown_menu(Widget below,Widget beside)4672 unit_pulldown_menu(Widget below, Widget beside)
4673 {
4674 	/* put the current user units in unit_items[0] */
4675 	unit_items[0] = cur_fig_units;
4676 
4677 	FirstArg(XtNfromVert, below);
4678 	NextArg(XtNfromHoriz, beside);
4679 	NextArg(XtNhorizDistance, 15);
4680 	NextArg(XtNborderWidth, 0);
4681 	NextArg(XtNtop, XtChainBottom);
4682 	NextArg(XtNbottom, XtChainBottom);
4683 	NextArg(XtNleft, XtChainLeft);
4684 	NextArg(XtNright, XtChainLeft);
4685 	beside = XtCreateManagedWidget("Units:",labelWidgetClass, form, Args, ArgCount);
4686 	FirstArg(XtNfromVert, below);
4687 	NextArg(XtNwidth, 95);
4688 	NextArg(XtNfromHoriz, beside);
4689 	NextArg(XtNhorizDistance, 2);
4690 	NextArg(XtNleftBitmap, menu_arrow);	/* use menu arrow for pull-down */
4691 	NextArg(XtNtop, XtChainBottom);
4692 	NextArg(XtNbottom, XtChainBottom);
4693 	NextArg(XtNleft, XtChainLeft);
4694 	NextArg(XtNright, XtChainLeft);
4695 	unit_menu_button = XtCreateManagedWidget(unit_items[points_units],
4696 					menuButtonWidgetClass, form, Args, ArgCount);
4697 	/* pulldown menu for units */
4698 	make_pulldown_menu(unit_items, XtNumber(unit_items), -1, "",
4699 		       unit_menu_button, unit_select);
4700 	return unit_menu_button;
4701 }
4702 static void
init_convert_array(void)4703 init_convert_array(void)
4704 {
4705     conv_array_idx = 0;
4706 }
4707 
4708 static void
add_to_convert(Widget widget)4709 add_to_convert(Widget widget)
4710 {
4711     convert_array[conv_array_idx++] = widget;
4712 }
4713 
4714 /* unit conversion for displaying coordinates */
4715 
4716 static double
cvt_to_units(int fig_unit)4717 cvt_to_units(int fig_unit)
4718 {
4719     if (points_units == 1)
4720 	return (double) fig_unit;
4721     return (double) fig_unit /
4722 		(double) (appres.INCHES? PIX_PER_INCH: PIX_PER_CM)*appres.userscale;
4723 }
4724 
4725 /* unit conversion that writes ASCII to buf */
4726 
4727 static void
cvt_to_units_str(int x,char * buf)4728 cvt_to_units_str(int x, char *buf)
4729 {
4730     double	    dval;
4731 
4732     if (points_units) {
4733 	sprintf(buf, "%d", x);
4734     } else {
4735 	dval = cvt_to_units(x);
4736 	sprintf(buf, "%.4lf", dval);
4737     }
4738 }
4739 
4740 static int
cvt_to_fig(double real_unit)4741 cvt_to_fig(double real_unit)
4742 {
4743     if (points_units)
4744 	return round(real_unit);
4745     return round(real_unit/appres.userscale * (appres.INCHES? PIX_PER_INCH: PIX_PER_CM));
4746 }
4747 
4748 static void
unit_select(Widget w,XtPointer new_unit,XtPointer call_data)4749 unit_select(Widget w, XtPointer new_unit, XtPointer call_data)
4750 {
4751 	(void)w;
4752 	(void)call_data;
4753     int		    i;
4754     intptr_t	    new_points_units;
4755     char	    buf[30];
4756     int		    ival;
4757     double	    val;
4758 
4759     new_points_units = (intptr_t) new_unit;
4760     if (points_units == new_points_units)
4761 	return;
4762 
4763     /* change label in menu button */
4764     FirstArg(XtNlabel, unit_items[new_points_units]);
4765     SetValues(unit_menu_button);
4766 
4767     /* now go through the array of text widgets and convert their values */
4768     points_units = 0;
4769     for (i=0; i<conv_array_idx; i++) {
4770 	/* get the value from the next widget */
4771 	val = atof(panel_get_value(convert_array[i]));
4772 	if (new_points_units) {
4773 	    ival = cvt_to_fig(val);
4774 	    sprintf(buf, "%d", ival);
4775 	} else {
4776 	    cvt_to_units_str(round(val), buf);
4777 	}
4778 	/* put the value back */
4779 	panel_set_value(convert_array[i], buf);
4780     }
4781     points_units = new_points_units;
4782 }
4783 
4784 void
Quit(void)4785 Quit(void)
4786 {
4787     /* turn off the point positioning indicator now */
4788     update_indpanel(0);
4789     popup_up = False;
4790     XtDestroyWidget(popup);
4791     fill_style_exists = False;
4792     if (pen_color_popup) {
4793 	XtDestroyWidget(pen_color_popup);
4794 	pen_color_popup = 0;
4795     }
4796     if (fill_color_popup) {
4797 	XtDestroyWidget(fill_color_popup);
4798 	fill_color_popup = 0;
4799     }
4800 }
4801 
4802 static int
panel_get_dim_value(Widget widg)4803 panel_get_dim_value(Widget widg)
4804 {
4805     char	*str = panel_get_value(widg);
4806 
4807     if (strchr(str, 'i'))
4808 	return (atof(str) * PIX_PER_INCH);
4809     else if (strchr(str, 'c'))
4810 	return (atof(str) * PIX_PER_CM);
4811     else
4812 	return cvt_to_fig((atof(str)));
4813 }
4814 
4815 /* put an integer value into an ASCII text widget after converting
4816    it from Fig to (double) user units */
4817 
4818 static void
panel_set_scaled_int(Widget widg,int intval)4819 panel_set_scaled_int(Widget widg, int intval)
4820 {
4821     char	    buf[80];
4822     cvt_to_units_str(intval, buf);
4823     panel_set_value(widg, buf);
4824 }
4825 
4826 static void
panel_clear_value(Widget widg)4827 panel_clear_value(Widget widg)
4828 {
4829     FirstArg(XtNstring, " ");
4830     NextArg(XtNinsertPosition, 0);
4831     SetValues(widg);
4832 }
4833 
4834 static void
arc_type_select(Widget w,XtPointer new_style,XtPointer call_data)4835 arc_type_select(Widget w, XtPointer new_style, XtPointer call_data)
4836 {
4837 	(void)w;
4838 	(void)call_data;
4839     FirstArg(XtNlabel, XtName(w));
4840     SetValues(arc_type_panel);
4841 
4842     generic_vals.arc_type = (intptr_t) new_style;
4843     /* if now a pie-wedge type, make the arrow panels insensitive */
4844     if (generic_vals.arc_type == T_PIE_WEDGE_ARC) {
4845 	/* unmanage arrow forms */
4846 	XtUnmanageChild(for_aform);
4847 	XtUnmanageChild(back_aform);
4848 	/* unmanage and re-manage points form so it moves up */
4849 	XtUnmanageChild(arc_points_form);
4850 	/* position it just under the stuff above the arrow forms */
4851 	FirstArg(XtNfromVert, above_arrows);
4852 	SetValues(arc_points_form);
4853 	XtManageChild(arc_points_form);
4854     } else {
4855 	/* re-manage arrow forms */
4856 	XtManageChild(for_aform);
4857 	XtManageChild(back_aform);
4858 	/* unmanage and re-manage points form so it moves down */
4859 	XtUnmanageChild(arc_points_form);
4860 	/* position it just under the arrow forms */
4861 	FirstArg(XtNfromVert, for_aform);
4862 	SetValues(arc_points_form);
4863 	XtManageChild(arc_points_form);
4864     }
4865     /* allow the form to resize */
4866     XtUnmanageChild(form);
4867     XtManageChild(form);
4868 }
4869 
4870 static void
cap_style_select(Widget w,XtPointer new_type,XtPointer call_data)4871 cap_style_select(Widget w, XtPointer new_type, XtPointer call_data)
4872 {
4873 	(void)w;
4874 	(void)call_data;
4875     choice_info	    *choice;
4876 
4877     choice = (choice_info *) new_type;
4878     FirstArg(XtNbitmap, choice->pixmap);
4879     SetValues(cap_style_panel);
4880 
4881     generic_vals.cap_style = choice->value;
4882 }
4883 
4884 static void
join_style_select(Widget w,XtPointer new_type,XtPointer call_data)4885 join_style_select(Widget w, XtPointer new_type, XtPointer call_data)
4886 {
4887 	(void)w;
4888 	(void)call_data;
4889     choice_info	    *choice;
4890 
4891     choice = (choice_info *) new_type;
4892     FirstArg(XtNbitmap, choice->pixmap);
4893     SetValues(join_style_panel);
4894 
4895     generic_vals.join_style = choice->value;
4896 }
4897 
4898 static void
for_arrow_type_select(Widget w,XtPointer new_type,XtPointer call_data)4899 for_arrow_type_select(Widget w, XtPointer new_type, XtPointer call_data)
4900 {
4901 	(void)w;
4902 	(void)call_data;
4903     int		    choice;
4904 
4905     choice = (int) ((choice_info *) new_type)->value;
4906     FirstArg(XtNbitmap, arrow_pixmaps[choice+1]);
4907     SetValues(for_arrow_type_panel);
4908     for_arrow = (choice != -1);
4909 
4910     if (for_arrow) {
4911 	generic_vals.for_arrow.type = ARROW_TYPE(choice);
4912 	generic_vals.for_arrow.style = ARROW_STYLE(choice);
4913     }
4914 }
4915 
4916 static void
back_arrow_type_select(Widget w,XtPointer new_type,XtPointer call_data)4917 back_arrow_type_select(Widget w, XtPointer new_type, XtPointer call_data)
4918 {
4919 	(void)w;
4920 	(void)call_data;
4921     int		    choice;
4922 
4923     choice = (int) ((choice_info *) new_type)->value;
4924     FirstArg(XtNbitmap, arrow_pixmaps[choice+1]);
4925     SetValues(back_arrow_type_panel);
4926     back_arrow = (choice != -1);
4927 
4928     if (back_arrow) {
4929 	generic_vals.back_arrow.type = ARROW_TYPE(choice);
4930 	generic_vals.back_arrow.style = ARROW_STYLE(choice);
4931     }
4932 }
4933 
4934 static void
line_style_select(Widget w,XtPointer new_style,XtPointer call_data)4935 line_style_select(Widget w, XtPointer new_style, XtPointer call_data)
4936 {
4937 	(void)w;
4938 	(void)call_data;
4939     Boolean	    state;
4940     choice_info	    *choice;
4941 
4942     choice = (choice_info *) new_style;
4943     FirstArg(XtNbitmap, choice->pixmap);
4944     SetValues(line_style_panel);
4945 
4946     generic_vals.style = choice->value;
4947 
4948     switch (generic_vals.style) {
4949       case SOLID_LINE:
4950 	panel_clear_value(style_val_panel);
4951 	state = False;
4952 	break;
4953       case DASH_LINE:
4954 	/*
4955 	 * if style_val contains no useful value, set it to the default
4956 	 * dashlength, scaled by the line thickness
4957 	 */
4958 	if (generic_vals.style_val <= 0.0)
4959 	    generic_vals.style_val = cur_dashlength * (generic_vals.thickness + 1) / 2;
4960 	panel_set_float(style_val_panel, generic_vals.style_val, "%1.1f");
4961 	state = True;
4962 	break;
4963       default:		/* DOTTED, DASH-DOTTED, and the others */
4964 	if (generic_vals.style_val <= 0.0)
4965 	    generic_vals.style_val = cur_dotgap * (generic_vals.thickness + 1) / 2;
4966 	panel_set_float(style_val_panel, generic_vals.style_val, "%1.1f");
4967 	state = True;
4968 	break;
4969     }
4970     /* make both the label and value panels sensitive or insensitive */
4971     XtSetSensitive(style_val,state);
4972     XtSetSensitive(style_val_label,state);
4973 }
4974 
4975 static void
pen_color_select(Widget w,XtPointer client_data,XtPointer call_data)4976 pen_color_select(Widget w, XtPointer client_data, XtPointer call_data)
4977 {
4978 	(void)w;
4979 	(void)call_data;
4980 	ptr_int	new_color = {client_data};
4981 
4982     pen_color = (Color) new_color.val;
4983     color_select(pen_col_button, pen_color);
4984     if (pen_color_popup) {
4985 	XtPopdown(pen_color_popup);
4986     }
4987 }
4988 
4989 static void
fill_color_select(Widget w,XtPointer new_color,XtPointer call_data)4990 fill_color_select(Widget w, XtPointer new_color, XtPointer call_data)
4991 {
4992 	(void)w;
4993 	(void)call_data;
4994 	ptr_int	_new_color = {new_color};
4995 
4996     fill_color = (Color) _new_color.val;
4997     color_select(fill_col_button, fill_color);
4998     if (fill_color_popup) {
4999 	XtPopdown(fill_color_popup);
5000     }
5001 }
5002 
5003 void
color_select(Widget w,Color color)5004 color_select(Widget w, Color color)
5005 {
5006     XFontStruct	   *f;
5007 
5008     /* update colors for fill image gc */
5009     recolor_fill_image();
5010 
5011     FirstArg(XtNlabel, XtName(w));
5012     SetValues(w);
5013     set_color_name(color,buf);
5014     FirstArg(XtNfont, &f);
5015     GetValues(w);
5016     FirstArg(XtNlabel, buf);
5017     /* don't know why, but we *MUST* set the size again here or it
5018        will stay the width that it first had when created */
5019     NextArg(XtNwidth, COLOR_BUT_WID);
5020 
5021     if (all_colors_available) { /* set color if possible */
5022 	XColor		xcolor;
5023 	Pixel		col;
5024 
5025 	/* background in the color selected */
5026 	col = (color < 0 || color >= NUM_STD_COLS+num_usr_cols) ?
5027 			x_fg_color.pixel : colors[color];
5028 	NextArg(XtNbackground, col);
5029 	xcolor.pixel = col;
5030 	/* get RGB of the color to check intensity */
5031 	XQueryColor(tool_d, tool_cm, &xcolor);
5032 	/* set the foreground in a contrasting color (white or black) */
5033 	if ((0.3 * xcolor.red + 0.59 * xcolor.green + 0.11 * xcolor.blue) <
5034 			0.55 * (255 << 8))
5035 	    col = colors[WHITE];
5036 	else
5037 	    col = colors[BLACK];
5038 	NextArg(XtNforeground, col);
5039     }
5040     SetValues(w);
5041 }
5042 
5043 static void
hidden_text_select(Widget w,XtPointer new_hidden_text,XtPointer call_data)5044 hidden_text_select(Widget w, XtPointer new_hidden_text, XtPointer call_data)
5045 {
5046 	(void)call_data;
5047 
5048     FirstArg(XtNlabel, XtName(w));
5049     SetValues(hidden_text_panel);
5050     hidden_text_flag = (intptr_t) new_hidden_text;
5051 }
5052 
5053 static void
rigid_text_select(Widget w,XtPointer new_rigid_text,XtPointer call_data)5054 rigid_text_select(Widget w, XtPointer new_rigid_text, XtPointer call_data)
5055 {
5056 	(void)call_data;
5057 
5058     FirstArg(XtNlabel, XtName(w));
5059     SetValues(rigid_text_panel);
5060     rigid_text_flag = (intptr_t) new_rigid_text;
5061 }
5062 
5063 static void
special_text_select(Widget w,XtPointer new_special_text,XtPointer call_data)5064 special_text_select(Widget w, XtPointer new_special_text, XtPointer call_data)
5065 {
5066 	(void)call_data;
5067 
5068     FirstArg(XtNlabel, XtName(w));
5069     SetValues(special_text_panel);
5070     special_text_flag = (intptr_t) new_special_text;
5071 }
5072 
5073 static void
textjust_select(Widget w,XtPointer new_textjust,XtPointer call_data)5074 textjust_select(Widget w, XtPointer new_textjust, XtPointer call_data)
5075 {
5076 	(void)call_data;
5077 
5078     FirstArg(XtNlabel, XtName(w));
5079     SetValues(textjust_panel);
5080     textjust = (intptr_t) new_textjust;
5081 }
5082 
5083 static void
flip_pic_select(Widget w,XtPointer new_flipflag,XtPointer call_data)5084 flip_pic_select(Widget w, XtPointer new_flipflag, XtPointer call_data)
5085 {
5086 	(void)call_data;
5087 
5088     struct f_point  p1, p2;
5089     int		    dx, dy, rotation;
5090     float	    ratio;
5091 
5092     FirstArg(XtNlabel, XtName(w));
5093     SetValues(flip_pic_panel);
5094     flip_pic_flag = (intptr_t) new_flipflag;
5095     p1.x = panel_get_dim_value(x1_panel);
5096     p1.y = panel_get_dim_value(y1_panel);
5097     p2.x = panel_get_dim_value(x2_panel);
5098     p2.y = panel_get_dim_value(y2_panel);
5099 
5100     /* size is upper-lower */
5101     dx = p2.x - p1.x;
5102     dy = p2.y - p1.y;
5103     rotation = what_rotation(dx,dy);
5104 
5105     if (dx == 0 || dy == 0)
5106 	ratio = 0.0;
5107     else if (((rotation == 0 || rotation == 180) && !flip_pic_flag) ||
5108 	     (rotation != 0 && rotation != 180 && flip_pic_flag))
5109 	ratio = (float) fabs((double) dy / (double) dx);
5110     else
5111 	ratio = (float) fabs((double) dx / (double) dy);
5112     sprintf(buf, "%1.1f", ratio);
5113     FirstArg(XtNlabel, buf);
5114     SetValues(hw_ratio_panel);
5115 }
5116 
5117 static void
rotation_select(Widget w,XtPointer new_rotation,XtPointer call_data)5118 rotation_select(Widget w, XtPointer new_rotation, XtPointer call_data)
5119 {
5120 	(void)call_data;
5121 
5122     struct f_point  p1, p2;
5123     int		    dx, dy, cur_rotation;
5124     intptr_t    rotation;
5125     int		    x1, y1, x2, y2;
5126 
5127     FirstArg(XtNlabel, XtName(w));
5128     SetValues(rotation_panel);
5129     /* get new rotation (0 = 0 degrees, 1 = 90, 2 = 180, 3 = 270) */
5130     rotation = (intptr_t) new_rotation;
5131 
5132     /* get the two opposite corners */
5133     p1.x = panel_get_dim_value(x1_panel);
5134     p1.y = panel_get_dim_value(y1_panel);
5135     p2.x = panel_get_dim_value(x2_panel);
5136     p2.y = panel_get_dim_value(y2_panel);
5137 
5138     dx = p2.x - p1.x;
5139     dy = p2.y - p1.y;
5140     /* the current rotation based on the current corners */
5141     cur_rotation = what_rotation(dx,dy);
5142 
5143     /* adjust p2 relative to p1 to get desired rotation */
5144     x1 = p1.x;
5145     y1 = p1.y;
5146     x2 = p2.x;
5147     y2 = p2.y;
5148     switch (cur_rotation) {
5149 	case 0:
5150 	    switch (rotation) {
5151 		case 0:	/* 0 degrees */
5152 			break;
5153 		case 1:	/* 90 degrees */
5154 			x2 = x1 + dy;
5155 			y2 = y1 - dx;
5156 			break;
5157 		case 2:	/* 180 degrees */
5158 			x2 = x1 - dx;
5159 			y2 = y1 - dy;
5160 			break;
5161 		case 3:	/* 270 degrees */
5162 			x2 = x1 - dy;
5163 			y2 = y1 + dx;
5164 			break;
5165 	    }
5166 	    break;
5167 	case 90:
5168 	    switch (rotation) {
5169 		case 0:	/* 0 degrees */
5170 			x2 = x1 - dy;
5171 			y2 = y1 + dx;
5172 			break;
5173 		case 1:	/* 90 degrees */
5174 			break;
5175 		case 2:	/* 180 degrees */
5176 			x2 = x1 + dy;
5177 			y2 = y1 - dx;
5178 			break;
5179 		case 3:	/* 270 degrees */
5180 			x2 = x1 - dx;
5181 			y2 = y1 - dy;
5182 			break;
5183 	    }
5184 	    break;
5185 	case 180:
5186 	    switch (rotation) {
5187 		case 0:	/* 0 degrees */
5188 			x2 = x1 - dx;
5189 			y2 = y1 - dy;
5190 			break;
5191 		case 1:	/* 90 degrees */
5192 			x2 = x1 - dy;
5193 			y2 = y1 + dx;
5194 			break;
5195 		case 2:	/* 180 degrees */
5196 			break;
5197 		case 3:	/* 270 degrees */
5198 			x2 = x1 + dy;
5199 			y2 = y1 - dx;
5200 			break;
5201 	    }
5202 	    break;
5203 	case 270:
5204 	    switch (rotation) {
5205 		case 0:	/* 0 degrees */
5206 			x2 = x1 + dy;
5207 			y2 = y1 - dx;
5208 			break;
5209 		case 1:	/* 90 degrees */
5210 			x2 = x1 - dx;
5211 			y2 = y1 - dy;
5212 			break;
5213 		case 2:	/* 180 degrees */
5214 			x2 = x1 - dy;
5215 			y2 = y1 + dx;
5216 			break;
5217 		case 3:	/* 270 degrees */
5218 			break;
5219 	    }
5220 	    break;
5221     }
5222     /* put them back in the panel */
5223     panel_set_scaled_int(x2_panel, x2);
5224     panel_set_scaled_int(y2_panel, y2);
5225     /* finally, update width and height */
5226     panel_set_scaled_int(width_panel, abs(x2-x1));
5227     panel_set_scaled_int(height_panel, abs(y2-y1));
5228 }
5229 
5230 static void
fill_style_select(Widget w,XtPointer new_fillflag,XtPointer call_data)5231 fill_style_select(Widget w, XtPointer new_fillflag, XtPointer call_data)
5232 {
5233 	(void)call_data;
5234 
5235     int		    fill;
5236     char	   *sval;
5237 
5238     FirstArg(XtNlabel, XtName(w));
5239     SetValues(fill_style_button);
5240     fill_flag = (intptr_t) new_fillflag;
5241 
5242     if (fill_flag == 0) {
5243       /* no fill; blank out fill density value and pattern */
5244 	panel_clear_value(fill_intens_panel);
5245 	panel_clear_value(fill_pat_panel);
5246 	/* make fill% panel insensitive */
5247 	fill_style_sens(False);
5248 	/* and pattern */
5249 	fill_pat_sens(False);
5250     } else if (fill_flag == 1) {
5251       /* filled with color or gray */
5252 	sval = panel_get_value(fill_intens_panel);
5253 	/* if there is already a number there, use it */
5254 	if (sval[0]!=' ') {
5255 	    fill = atoi(sval);
5256 	} else {
5257 	    /* else use 100% */
5258 	    fill = 100;
5259 	}
5260 	if (fill < 0)
5261 	    fill = 100;
5262 	if (fill > 200)
5263 	    fill = 100;
5264 	panel_set_int(fill_intens_panel, fill);
5265 	/* clear value in pattern panel */
5266 	panel_clear_value(fill_pat_panel);
5267 	/* make fill% panel sensitive */
5268 	fill_style_sens(True);
5269 	/* make fill pattern panel insensitive */
5270 	fill_pat_sens(False);
5271     } else {
5272       /* filled with pattern */
5273 	sval = panel_get_value(fill_pat_panel);
5274 	/* if there is already a number there, use it */
5275 	if (sval[0]!=' ') {
5276 	    fill = atoi(sval);
5277 	} else {
5278 	    /* else use first pattern */
5279 	    fill = 0;
5280 	}
5281 	panel_set_int(fill_pat_panel, fill);
5282 	/* clear value in fill % panel */
5283 	panel_clear_value(fill_intens_panel);
5284 	/* make fill pattern panel sensitive */
5285 	fill_pat_sens(True);
5286 	/* make fill% panel insensitive */
5287 	fill_style_sens(False);
5288     }
5289 }
5290 
5291 static void
fill_style_sens(Boolean state)5292 fill_style_sens(Boolean state)
5293 {
5294 	XtSetSensitive(fill_intens,state);
5295 	XtSetSensitive(fill_intens_label,state);
5296 	update_fill_image((Widget) 0, (XtPointer) 0, (XtPointer) 0);
5297 }
5298 
5299 static void
fill_pat_sens(Boolean state)5300 fill_pat_sens(Boolean state)
5301 {
5302 	XtSetSensitive(fill_pat,state);
5303 	XtSetSensitive(fill_pat_label,state);
5304 	update_fill_image((Widget) 0, (XtPointer) 0, (XtPointer) 0);
5305 }
5306 
5307 void
clear_text_key(Widget w)5308 clear_text_key(Widget w)
5309 {
5310 	panel_set_value(w, "");
5311 }
5312 
5313 static void get_clipboard(Widget w, XtPointer client_data, Atom *selection,
5314 	Atom *type, XtPointer buf, long unsigned int *length, int *format);
5315 
5316 void
paste_panel_key(Widget w,XKeyEvent * event)5317 paste_panel_key(Widget w, XKeyEvent *event)
5318 {
5319 	Time event_time;
5320 
5321         event_time = event->time;
5322         XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, get_clipboard, w, event_time);
5323 }
5324 
5325 static void
get_clipboard(Widget w,XtPointer client_data,Atom * selection,Atom * type,XtPointer buf,long unsigned int * length,int * format)5326 get_clipboard(Widget w, XtPointer client_data, Atom *selection, Atom *type,
5327 		XtPointer buf, long unsigned int *length, int *format)
5328 {
5329 	(void)w;
5330 	(void)client_data;
5331 	(void)selection;
5332 	(void)type;
5333 	(void)format;
5334 
5335 	char *c, *p;
5336 	unsigned long i;
5337 	char s[256];
5338 
5339 	strcpy (s, panel_get_value(client_data));
5340 	p = strchr(s, '\0');
5341 	c = buf;
5342 	for (i=0; i<*length; i++) {
5343 		if (*c=='\0' || *c=='\n' || *c=='\r' || strlen(s)>=sizeof(s)-1)
5344 			break;
5345 		*p = *c;
5346 		p++;
5347 		*p = '\0';
5348 		c++;
5349 	}
5350 	XtFree(buf);
5351 	panel_set_value(client_data, s);
5352 }
5353 
5354 static void
text_transl(Widget w)5355 text_transl(Widget w)
5356 {
5357 	/* make CR finish edit */
5358 	XtOverrideTranslations(w, XtParseTranslationTable(edit_text_translations));
5359 
5360 	/* enable mousefun kbd display */
5361 	XtAugmentTranslations(w, XtParseTranslationTable(kbd_translations));
5362 }
5363 
5364 
5365 void
change_sfactor(int x,int y,unsigned int button)5366 change_sfactor(int x, int y, unsigned int button)
5367 {
5368   F_spline *spl, *spline;
5369   F_point  *prev, *the_point;
5370   F_point   p1, p2;
5371   F_sfactor *associated_sfactor;
5372 
5373   prev = &p1;
5374   the_point = &p2;
5375   spl = get_spline_point(x, y, &prev, &the_point);
5376 
5377   if (spl == NULL) {
5378     put_msg("Only spline points can be edited");
5379     return;
5380   }
5381 
5382   if (open_spline(spl) && ((prev == NULL) || (the_point->next == NULL))) {
5383     put_msg("Cannot edit end-points");
5384     return;
5385   }
5386   toggle_pointmarker(the_point->x,  the_point->y);
5387 
5388   spline = copy_spline(spl);
5389   if (spline == NULL)
5390     return;
5391   associated_sfactor = search_sfactor(spline,
5392 		      search_spline_point(spline, the_point->x, the_point->y));
5393 
5394   change_spline(spl, spline);
5395   draw_spline(spline, ERASE);
5396 
5397   switch (button) {
5398     case Button1:
5399       associated_sfactor->s += 2*STEP_VALUE;
5400       if (associated_sfactor->s > S_SPLINE_APPROX)
5401 	associated_sfactor->s = S_SPLINE_APPROX;
5402       break;
5403     case Button2:
5404       associated_sfactor->s = (round(associated_sfactor->s)) +
5405 	(S_SPLINE_APPROX - S_SPLINE_ANGULAR);
5406       if (associated_sfactor->s > S_SPLINE_APPROX)
5407 	associated_sfactor->s = S_SPLINE_INTERP;
5408       break;
5409     case Button3:
5410       associated_sfactor->s -= 2*STEP_VALUE;
5411       if (associated_sfactor->s < S_SPLINE_INTERP)
5412 	associated_sfactor->s = S_SPLINE_INTERP;
5413       break;
5414     }
5415 
5416   spline->type = open_spline(spline) ? T_OPEN_XSPLINE : T_CLOSED_XSPLINE;
5417   draw_spline(spline, PAINT);
5418   toggle_pointmarker(the_point->x, the_point->y);
5419 }
5420 
5421 static void
check_depth(void)5422 check_depth(void)
5423 {
5424     int depth;
5425     depth = atoi(panel_get_value(depth_panel));
5426     if (depth >= 0 && depth <= MAX_DEPTH)
5427 	return;
5428     if (depth < MIN_DEPTH)
5429 	depth = MIN_DEPTH;
5430     else if (depth > MAX_DEPTH)
5431 	depth = MAX_DEPTH;
5432     panel_set_int(depth_panel, depth);
5433 }
5434 
5435 static void
check_thick(void)5436 check_thick(void)
5437 {
5438     int thick;
5439     thick = atoi(panel_get_value(thickness_panel));
5440     if (thick >= 0 && thick <= MAX_LINE_WIDTH)
5441 	return;
5442     if (thick < 0)
5443 	thick = 0;
5444     else if (thick > MAX_LINE_WIDTH)
5445 	thick = MAX_LINE_WIDTH;
5446     panel_set_int(thickness_panel, thick);
5447 }
5448 
5449 /*
5450  these functions  push_apply_button, grab_button,
5451                        popup_browse_panel & image_edit_button
5452       implement gif screen capture facility
5453    note push_apply_button also called from w_browse.c
5454 */
5455 
5456 void
push_apply_button(void)5457 push_apply_button(void)
5458 {
5459     /* get rid of anything that ought to be done - X wise */
5460     app_flush();
5461 
5462     button_result = APPLY;
5463     done_proc();
5464 }
5465 
5466 
5467 static void
grab_button(Widget panel_local,XtPointer closure,XtPointer call_data)5468 grab_button(Widget panel_local, XtPointer closure, XtPointer call_data)
5469 {
5470 	(void)panel_local;
5471 	(void)closure;
5472 	(void)call_data;
5473 
5474     time_t	    tim;
5475     char	    tmpfile[PATH_MAX],tmpname[PATH_MAX];
5476     char	   *p;
5477 
5478     if (!canHandleCapture(tool_d)) {
5479       put_msg("Can't capture screen");
5480       beep();
5481       return;
5482     }
5483 
5484     /*  build up a temporary file name from the user login name and the current time */
5485     tim = time( (time_t*)0);
5486     /* get figure name without path */
5487     if (*cur_filename == '\0')
5488 	strcpy(tmpname, "NoName");	/* no name, use "NoName" */
5489     else
5490 	strcpy(tmpname,xf_basename(cur_filename));
5491     /* chop off any .suffix */
5492     if ((p=strrchr(tmpname,'.')))
5493 	*p='\0';
5494 
5495     sprintf(tmpfile,"%s_%ld.png",tmpname,tim);
5496 
5497     /* capture the screen area into our tmpfile */
5498 
5499     if (captureImage(popup, tmpfile) == True) {
5500       panel_set_value(pic_name_panel, tmpfile);
5501       push_apply_button();
5502     }
5503 }
5504 
5505 /*
5506   Edit button has been pushed - invoke an editor on the current file
5507 */
5508 
5509 static void
image_edit_button(Widget panel_local,XtPointer closure,XtPointer call_data)5510 image_edit_button(Widget panel_local, XtPointer closure, XtPointer call_data)
5511 {
5512 	(void)panel_local;
5513 	(void)closure;
5514 	(void)call_data;
5515 
5516     int		argc;
5517     char	*argv[20];
5518     pid_t	pid;
5519     char	cmd[PATH_MAX];
5520     char	s[PATH_MAX];
5521     struct stat	original_stat;
5522     int		err;
5523     char	*cp;
5524 
5525     /* get the filename for the picture object */
5526     strcpy(s,panel_get_value(pic_name_panel));
5527     if (*s == '\0')	/* no name, return */
5528 	return;
5529 
5530     /* uncompress the image file if it is compressed (new name returns in s) */
5531     if (uncompress_file(s) == False) /* failed! no point in continuing */
5532         return;
5533 
5534     /* store name back in case any .gz or .Z was removed after uncompressing */
5535     panel_set_value(pic_name_panel,s);
5536 
5537     button_result = APPLY;
5538 
5539     strcpy(cmd, cur_image_editor);
5540     argc = 0;
5541     /* get first word from string as the program */
5542     argv[argc++] = strtok(cmd," \t");
5543     /* if there is more than one word, separate args */
5544     while ((cp = strtok((char*) NULL," \t")) &&
5545 		    argc < (int)(sizeof(argv)/sizeof(argv[0])) - 2)
5546       argv[argc++] = cp;
5547     argv[argc++] = s;  /* put the filename last */
5548     argv[argc] = NULL;	/* terminate the list */
5549 
5550     /* get the file status (to compare file modification time later) */
5551     if (stat( s, &original_stat ) != 0 ) /* stat failed! no point in continuing */
5552         return;
5553 
5554     pid = fork();
5555     if ( pid == 0 ) {
5556 	err = execvp(argv[0], argv);
5557 	/* should only come here if an error in the execlp */
5558 	fprintf(stderr,"Error in exec'ing image editor (%s): %s\n",
5559 			argv[0], strerror(errno));
5560         exit(-1);
5561     }
5562 
5563     if ( pid > 0 ) { /* wait for the lad to finish */
5564         int status;
5565         struct stat new_stat;
5566 
5567         (void) waitpid( pid, &status, 0 );
5568 
5569         /* if file modification time has changed, set the changed flag -
5570            causes a reread of the file as it thinks the name has changed  */
5571         stat(s, &new_stat );
5572         if ( original_stat.st_mtime != new_stat.st_mtime ) {
5573 	    new_l->pic->pic_cache->bitmap = NULL;
5574 	    push_apply_button();
5575 	}
5576 
5577     } else {
5578         fprintf(stderr,"Unable to fork to exec image editor (%s): %s\n",
5579 		argv[0], strerror(errno));
5580     }
5581 }
5582 
5583 
5584 static void
browse_button(Widget panel_local,XtPointer closure,XtPointer call_data)5585 browse_button(Widget panel_local, XtPointer closure, XtPointer call_data)
5586 {
5587 	(void)panel_local;
5588 	(void)closure;
5589 	(void)call_data;
5590 
5591     popup_browse_panel( form );
5592 }
5593 
5594 /* collapse the depths in new_c to min_compound_depth and update the max depth value */
5595 
5596 static void
collapse_depth(Widget panel_local,XtPointer closure,XtPointer call_data)5597 collapse_depth(Widget panel_local, XtPointer closure, XtPointer call_data)
5598 {
5599 	(void)panel_local;
5600 	(void)closure;
5601 	(void)call_data;
5602 
5603     collapse_depths(new_c);
5604     sprintf(buf,"Maximum: %d", min_compound_depth);
5605     FirstArg(XtNlabel, buf);
5606     SetValues(max_depth_w);
5607 }
5608 
5609 /* need this to recurse through compounds inside new_c */
5610 
5611 static void
collapse_depths(F_compound * compound)5612 collapse_depths(F_compound *compound)
5613 {
5614 	F_line	 *l;
5615 	F_spline	 *s;
5616 	F_ellipse	 *e;
5617 	F_arc	 *a;
5618 	F_text	 *t;
5619 	F_compound *c;
5620 
5621 	for (l = compound->lines; l != NULL; l = l->next) {
5622 	    remove_depth(O_POLYLINE, l->depth);
5623 	    l->depth = min_compound_depth;
5624 	    add_depth(O_POLYLINE, l->depth);
5625 	}
5626 	for (s = compound->splines; s != NULL; s = s->next) {
5627 	    remove_depth(O_SPLINE, s->depth);
5628 	    s->depth = min_compound_depth;
5629 	    add_depth(O_SPLINE, s->depth);
5630 	}
5631 	for (e = compound->ellipses; e != NULL; e = e->next) {
5632 	    remove_depth(O_ELLIPSE, e->depth);
5633 	    e->depth = min_compound_depth;
5634 	    add_depth(O_ELLIPSE, e->depth);
5635 	}
5636 	for (a = compound->arcs; a != NULL; a = a->next) {
5637 	    remove_depth(O_ARC, a->depth);
5638 	    a->depth = min_compound_depth;
5639 	    add_depth(O_ARC, a->depth);
5640 	}
5641 	for (t = compound->texts; t != NULL; t = t->next) {
5642 	    remove_depth(O_TXT, t->depth);
5643 	    t->depth = min_compound_depth;
5644 	    add_depth(O_TXT, t->depth);
5645 	}
5646 	for (c = compound->compounds; c != NULL; c = c->next) {
5647 	    collapse_depths(c);
5648 	}
5649 }
5650 
5651 /* return rotation value based on the signs of dx, dy which come from the
5652  * two corners of the picture (dx = p2.x - p1.x, dy = p2.y - p1.y)
5653  */
5654 
5655 static int
what_rotation(int dx,int dy)5656 what_rotation(int dx, int dy)
5657 {
5658     int rotation;
5659 
5660     rotation = 0;
5661     if (dx >= 0 && dy < 0)
5662 	rotation = 90;
5663     else if (dx < 0 && dy < 0)
5664 	rotation = 180;
5665     else if (dx < 0 && dy >= 0)
5666 	rotation = 270;
5667     return rotation;
5668 }
5669