1 /*
2  * FIG : Facility for Interactive Generation of figures
3  * Copyright (c) 1989-2007 by Brian V. Smith
4  * Parts Copyright (c) 1991 by Paul King
5  *
6  * Any party obtaining a copy of these files is granted, free of charge, a
7  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
8  * nonexclusive right and license to deal in this software and documentation
9  * files (the "Software"), including without limitation the rights to use,
10  * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
11  * the Software, and to permit persons who receive copies from any such
12  * party to do so, with the only requirement being that the above copyright
13  * and this permission notice remain intact.
14  *
15  */
16 
17 #include "fig.h"
18 #include "figx.h"
19 #include "resources.h"
20 #include "object.h"
21 #include "mode.h"
22 #include "e_edit.h"
23 #include "f_read.h"
24 #include "f_util.h"
25 #include "u_create.h"
26 #include "u_redraw.h"
27 #include "w_drawprim.h"		/* for max_char_height */
28 #include "w_dir.h"
29 #include "w_export.h"
30 #include "w_file.h"
31 #include "w_indpanel.h"
32 #include "w_layers.h"
33 #include "w_msgpanel.h"
34 #include "w_util.h"
35 #include "w_setup.h"
36 #include "w_icons.h"
37 #include "w_zoom.h"
38 
39 #include "e_compound.h"
40 #include "f_load.h"
41 #include "f_save.h"
42 #include "u_free.h"
43 #include "u_list.h"
44 #include "w_canvas.h"
45 #include "w_cmdpanel.h"
46 #include "w_color.h"
47 #include "w_cursor.h"
48 
49 #define	FILE_WID	157	/* width of Current file etc to show preview to the right */
50 #define FILE_ALT_WID	260	/* width of file alternatives panel */
51 #define PREVIEW_CANVAS_W 232	/* width of landscape preview canvas (swap W, H for portrait) */
52 #define PREVIEW_CANVAS_H 180	/* height of landscape preview */
53 
54 /* file modes for popup panel */
55 
56 enum file_modes {
57 	F_SAVEAS,
58 	F_OPEN,
59 	F_MERGE
60 };
61 
62 /* EXPORTS */
63 
64 Boolean		file_up = False;	/* whether the file panel is up (or the export panel) */
65 Widget		file_panel;		/* the file panel itself */
66 Widget		cfile_text;		/* widget for the current filename */
67 Widget		file_selfile,		/* selected file widget */
68 		file_mask,		/* mask widget */
69 		file_dir,		/* current directory widget */
70 		file_flist,		/* file list widget */
71 		file_dlist;		/* dir list widget */
72 Widget		file_popup;
73 Boolean		colors_are_swapped = False;
74 Widget		preview_size, preview_widget, preview_widget_form, preview_name;
75 Widget		preview_stop, preview_label, dummy_label;
76 Widget		comments_widget;
77 Pixmap		preview_land_pixmap, preview_port_pixmap;
78 Boolean		cancel_preview = False;
79 Boolean		preview_in_progress = False;
80 void		load_request(Widget w, XButtonEvent *ev);		/* this is needed by main() */
81 
82 /* LOCALS */
83 
84 static void	file_preview_stop(Widget w, XButtonEvent *ev);
85 static Boolean	file_cancel_request = False;
86 static Boolean	file_load_request = False;
87 static Boolean	file_save_request = False;
88 static Boolean	file_merge_request = False;
89 static char	save_file_dir[PATH_MAX];
90 
91 /* these are in fig units */
92 
93 static float	offset_unit_conv[] = { (float)PIX_PER_INCH, (float)PIX_PER_CM, 1.0 };
94 
95 static char	*load_msg = "The current figure is modified.\nDo you want to discard it and load the new file?";
96 static char	buf[40];
97 
98 /* to save image colors when doing a figure preview */
99 
100 static XColor	save_image_cells[MAX_COLORMAP_SIZE];
101 static int	save_avail_image_cols;
102 static Boolean	image_colors_are_saved = False;
103 
104 static void	popup_file_panel(int mode);
105 static void	file_panel_cancel(Widget w, XButtonEvent *ev);
106 static void	do_load(Widget w, XButtonEvent *ev), do_merge(Widget w, XButtonEvent *ev);
107 static void	merge_request(Widget w, XButtonEvent *ev), cancel_request(Widget w, XButtonEvent *ev), save_request(Widget w, XButtonEvent *ev);
108 static void	clear_preview(void);
109 
110 DeclareStaticArgs(15);
111 static Widget	file_stat_label, file_status, num_obj_label, num_objects;
112 static Widget	figure_off, cfile_lab;
113 static Widget	cancel_button, save_button, merge_button;
114 static Widget	load_button, new_xfig_button;
115 static Widget	fig_offset_lbl_x, fig_offset_lbl_y;
116 static Widget	fig_offset_x, fig_offset_y;
117 static Widget	file_xoff_unit_panel;
118 static Widget	file_yoff_unit_panel;
119 static intptr_t	xoff_unit_setting, yoff_unit_setting;
120 
121 static String	file_list_load_translations =
122 			"<Btn1Down>,<Btn1Up>: Set()Notify()\n\
123 			<Btn1Up>(2): DoLoad()\n\
124 			<Key>Return: DoLoad()";
125 static String	file_name_load_translations =
126 			"<Key>Return: DoLoad()\n\
127 			<Key>Escape: CancelFile()";
128 static String	file_list_saveas_translations =
129 			"<Btn1Down>,<Btn1Up>: Set()Notify()\n\
130 			<Btn1Up>(2): SaveRequest()\n\
131 			<Key>Return: DoSave()\n\
132 			<Key>Escape: CancelFile()";
133 static String	file_name_saveas_translations =
134 			"<Key>Return: DoSave()\n\
135 			<Key>Escape: CancelFile()";
136 static String	file_list_merge_translations =
137 			"<Btn1Down>,<Btn1Up>: Set()Notify()\n\
138 			<Btn1Up>(2): DoMerge()\n\
139 			<Key>Return: DoMerge()";
140 static String	file_name_merge_translations =
141 			"<Key>Return: DoMerge()\n\
142 			<Key>Escape: CancelFile()";
143 
144 static XtActionsRec	file_name_actions[] =
145 {
146     {"DoLoad", (XtActionProc) load_request},
147     {"SaveRequest", (XtActionProc) save_request},
148     {"DoSave", (XtActionProc) do_save},
149     {"DoMerge", (XtActionProc) merge_request},
150     {"Load", (XtActionProc) popup_open_panel},
151     {"Merge", (XtActionProc) popup_merge_panel},
152 };
153 static String	file_translations =
154 	"<Message>WM_PROTOCOLS: DismissFile()";
155 static XtActionsRec	file_actions[] =
156 {
157     {"DismissFile", (XtActionProc) cancel_request},
158     {"CancelFile", (XtActionProc) cancel_request},
159     {"DoLoad", (XtActionProc) load_request},
160     {"DoMerge", (XtActionProc) merge_request},
161 };
162 
163 
164 int renamefile (char *file);
165 void create_file_panel (void);
166 
167 void
file_panel_dismiss(void)168 file_panel_dismiss(void)
169 {
170     int i;
171 
172     /* this function is only called from the Open, Save as and Merge panels */
173     if (save_file_dir[0] != '\0') {
174 	update_file_export_dir(save_file_dir);
175 	change_directory(save_file_dir);
176     }
177 
178     if (image_colors_are_saved) {
179 	/* restore image colors on canvas */
180 	avail_image_cols = save_avail_image_cols;
181 	for (i=0; i<avail_image_cols; i++) {
182 	    image_cells[i].red   = save_image_cells[i].red;
183 	    image_cells[i].green = save_image_cells[i].green;
184 	    image_cells[i].blue  = save_image_cells[i].blue;
185 	    image_cells[i].flags  = DoRed|DoGreen|DoBlue;
186         }
187 	YStoreColors(tool_cm, image_cells, avail_image_cols);
188 	image_colors_are_saved = False;
189     }
190     FirstArg(XtNstring, "\0");
191     SetValues(file_selfile);	/* clear Filename string */
192     XtPopdown(file_popup);
193     file_up = popup_up = False;
194     /* in case the colormap was switched while previewing */
195     redisplay_canvas();
196 }
197 
198 /* get x/y offsets from panel */
199 
file_getxyoff(int * ixoff,int * iyoff)200 void file_getxyoff(int *ixoff, int *iyoff)
201 {
202     float xoff, yoff;
203     *ixoff = *iyoff = 0;
204     /* if no file panel yet, use 0, 0 for offsets */
205     if (fig_offset_x == (Widget) 0 ||
206 	fig_offset_y == (Widget) 0)
207 	    return;
208 
209     sscanf(panel_get_value(fig_offset_x),"%f",&xoff);
210     *ixoff = round(xoff*offset_unit_conv[xoff_unit_setting]);
211     sscanf(panel_get_value(fig_offset_y),"%f",&yoff);
212     *iyoff = round(yoff*offset_unit_conv[yoff_unit_setting]);
213 }
214 
215 static void
merge_request(Widget w,XButtonEvent * ev)216 merge_request(Widget w, XButtonEvent *ev)
217 {
218     if (preview_in_progress) {
219 	file_merge_request = True;
220 	/* request to cancel the preview */
221 	cancel_preview = True;
222     } else {
223 	/* make sure this is false from any previous previewing */
224 	cancel_preview = False;
225 	do_merge(w, ev);
226     }
227 }
228 
229 static void
do_merge(Widget w,XButtonEvent * ev)230 do_merge(Widget w, XButtonEvent *ev)
231 {
232     char	    path[PATH_MAX], fname[PATH_MAX];
233     char	   *fval, *dval;
234     int		    xoff, yoff;
235 
236     FirstArg(XtNstring, &fval);
237     GetValues(file_selfile);	/* check the ascii widget for a filename */
238     strcpy(fname, fval);
239     if (emptyname(fname))		/* "Filename" widget empty, */
240 	strcpy(fname, cur_filename);	/*  use current filename */
241 
242     if (!strchr(fname,'.'))	/* if no suffix, add .fig */
243 	strcat(fname,".fig");
244 
245     if (emptyname_msg(fname, "MERGE"))
246 	return;
247 
248     FirstArg(XtNstring, &dval);
249     GetValues(file_dir);
250 
251     strcpy(path, dval);
252     strcat(path, "/");
253     strcat(path, fname);
254     file_getxyoff(&xoff,&yoff);	/* get x/y offsets from panel */
255     /* if the user colors are saved we must swap current colors to save them for the preview */
256     if (user_colors_saved) {
257 	swap_colors();
258 	/* get back the colors from the figure on the canvas */
259 	restore_user_colors();
260 	merge_file(path, xoff, yoff);
261     } else {
262 	merge_file(path, xoff, yoff);
263     }
264     /* we have merged any image colors from the file with the canvas */
265     image_colors_are_saved = False;
266     /* dismiss the panel */
267     file_panel_dismiss();
268 }
269 
270 /*
271    Set a flag requesting a load.  This is called by double clicking on a
272    filename or by pressing the Open button.
273 
274    If we aren't in the middle of previewing a file, do the actual load.
275 
276    Otherwise just set a flag here because we are in the middle of a preview,
277    since the first click on the filename started up preview_figure().
278 
279    We can't do the load yet because the canvas_win variable is occupied by
280    the pixmap for the preview, and we need to change it back to the real canvas
281    before we draw the figure we will load.
282 */
283 
284 void
load_request(Widget w,XButtonEvent * ev)285 load_request(Widget w, XButtonEvent *ev)
286 {
287     if (preview_in_progress) {
288 	file_load_request = True;
289 	/* request to cancel the preview */
290 	cancel_preview = True;
291     } else {
292 	/* make sure this is false from any previous previewing */
293 	cancel_preview = False;
294 	do_load(w, ev);
295     }
296 }
297 
298 static void
do_load(Widget w,XButtonEvent * ev)299 do_load(Widget w, XButtonEvent *ev)
300 {
301     char	    fname[PATH_MAX];
302     char	   *fval, *dval;
303     int		    xoff, yoff;
304 
305     /* don't load if in the middle of drawing/editing */
306     if (check_action_on())
307 	return;
308 
309     /* restore any colors that were saved during a preview */
310     restore_user_colors();
311     restore_nuser_colors();
312 
313     /* first check if the figure was modified before reloading it */
314     if (!emptyfigure() && figure_modified) {
315 	if (file_popup)
316 	    XtSetSensitive(load_button, False);
317 	if (popup_query(QUERY_YESCAN, load_msg) == RESULT_CANCEL) {
318 	    if (file_popup)
319 		XtSetSensitive(load_button, True);
320 	    return;
321 	}
322     }
323     /* if the user used a keyboard accelerator but the filename
324        is empty, popup the file panel to force him/her to enter a name */
325     if (emptyname(cur_filename) && !file_up) {
326 	put_msg("No filename, please enter name");
327 	beep();
328 	popup_open_panel();
329 	return;
330     }
331     if (file_popup) {
332 	app_flush();			/* make sure widget is updated (race condition) */
333 	FirstArg(XtNstring, &dval);
334 	GetValues(file_dir);
335 	FirstArg(XtNstring, &fval);
336 	GetValues(file_selfile);	/* check the ascii widget for a filename */
337 	if (emptyname(fval))
338 	    strcpy(fname, cur_filename); /* Filename widget empty, use current filename */
339 	else
340 	    strcpy(fname, fval);	/* get name from widget */
341 
342 	if (!strchr(fname,'.'))		/* if no suffix, add .fig */
343 	    strcat(fname,".fig");
344 
345 	if (emptyname_msg(fname, "LOAD"))
346 	    return;
347 	if (change_directory(dval) == 0) {
348 	    strcpy(save_file_dir, dval);
349 	    file_getxyoff(&xoff,&yoff);	/* get x/y offsets from panel */
350 	    if (load_file(fname, xoff, yoff) == 0) {
351 		FirstArg(XtNlabel, fname);
352 		SetValues(cfile_text);		/* set the current filename */
353 		update_def_filename();		/* update default export filename */
354 		XtSetSensitive(load_button, True);
355 		/* we have just loaded the image colors from the file */
356 		image_colors_are_saved = False;
357 		if (file_up)
358 		    file_panel_dismiss();
359 	    }
360 	}
361     } else {
362 	file_getxyoff(&xoff,&yoff);
363 	(void) load_file(cur_filename, xoff, yoff);
364     }
365 }
366 
367 void
new_xfig_request(Widget w,XButtonEvent * ev)368 new_xfig_request(Widget w, XButtonEvent *ev)
369 {
370     pid_t pid;
371     char *fval, fname[PATH_MAX];
372     char **xxargv;
373     int i, j;
374     extern int xargc;
375     extern char **xargv;
376     extern char *arg_filename;
377 
378     FirstArg(XtNstring, &fval);
379     GetValues(file_selfile);	/* check the ascii widget for a filename */
380     strcpy(fname, fval);
381 
382     /* restore any colors that were saved during a preview */
383     restore_user_colors();
384     restore_nuser_colors();
385 
386     if (emptyname(fname))
387 	put_msg("Launching new xfig...");
388     else {
389 	if (!strchr(fname,'.'))		/* if no suffix, add .fig */
390 	    strcat(fname,".fig");
391 	put_msg("Launching new xfig for file %s...", fname);
392     }
393 
394     pid = fork();
395     if (pid == -1) {
396 	file_msg("Couldn't fork the process: %s", strerror(errno));
397     } else if (pid == 0) {
398 	xxargv = (char **)XtMalloc((xargc+2) * sizeof (char *));
399 	for (i = j = 0; i < xargc; i++) {
400 	    if (emptyname(arg_filename) || strcmp(xargv[i], arg_filename) != 0)
401 		xxargv[j++] = xargv[i];
402 	}
403 	if (!emptyname(fname))
404 	    xxargv[j++] = fname;
405 	xxargv[j] = NULL;
406 	execvp(xxargv[0], xxargv);
407 
408 	fprintf(stderr, "xfig: couldn't exec %s: %s\n", xxargv[0], strerror(errno));
409 	exit(1);
410     }
411 
412     file_panel_dismiss();
413 }
414 
415 /* set a request to save.  See notes above for load_request() */
416 
417 void
save_request(Widget w,XButtonEvent * ev)418 save_request(Widget w, XButtonEvent *ev)
419 {
420     /* turn off Compose key LED */
421     setCompLED(0);
422 
423     if (preview_in_progress) {
424 	file_save_request = True;
425 	/* request to cancel the preview */
426 	cancel_preview = True;
427     } else {
428 	/* make sure this is false from any previous previewing */
429 	cancel_preview = False;
430 	do_save(w, ev);
431     }
432 }
433 
434 void
do_save(Widget w,XButtonEvent * ev)435 do_save(Widget w, XButtonEvent *ev)
436 {
437     char	   *fval, *dval, fname[PATH_MAX];
438     int		    qresult;
439 
440     /* don't save if in the middle of drawing/editing */
441     if (check_action_on())
442 	return;
443 
444     if (emptyfigure_msg("Save"))
445 	return;
446 
447     /* restore any colors that were saved during a preview */
448     restore_user_colors();
449     restore_nuser_colors();
450 
451     /* if the user is inside any compound objects, ask whether to save all or just this part */
452     if ((F_compound *)objects.parent != NULL) {
453 	qresult = popup_query(QUERY_ALLPARTCAN,
454 		"You have opened a compound. You may save just\nthe visible part or all of the figure.");
455 	if (qresult == RESULT_CANCEL)
456 		return;
457 	if (qresult == RESULT_ALL)
458 	    close_all_compounds();
459     }
460 
461     /*
462      * if the user used a keyboard accelerator or right button on File
463      * but the filename is empty, popup the file panel to force him/her
464      * to enter a name
465      */
466     if (emptyname(cur_filename) && !file_up) {
467 	put_msg("No filename, please enter name");
468 	beep();
469 	popup_saveas_panel();
470 	return;
471     }
472     if (file_popup) {
473 	FirstArg(XtNstring, &fval);
474 	GetValues(file_selfile);    /* check the ascii widget for a filename */
475 	strcpy(fname, fval);
476 	if (emptyname(fname)) {
477 	    strcpy(fname, cur_filename); /* "Filename" widget empty, use current filename */
478 	    warnexist = False;		/* don't warn if this file exists */
479 	/* copy the name from the file_name widget to the current filename */
480 	} else {
481 	    if (!strchr(fname,'.'))	/* if no suffix, add .fig */
482 		strcat(fname,".fig");
483 	    if (strcmp(cur_filename, fname) != 0)
484 		warnexist = True;	/* warn if this file exists */
485 	}
486 
487 	if (emptyname_msg(fname, "Save"))
488 	    return;
489 
490 	if (file_up) {
491 	    /* get the directory from the ascii widget */
492 	    FirstArg(XtNstring, &dval);
493 	    GetValues(file_dir);
494 	    strcpy(save_file_dir, dval);
495 	}
496 
497 	/* go to the file directory */
498 	if (change_directory(save_file_dir) == 0) {
499 	    if (!ok_to_write(fname, "SAVE"))
500 		return;
501 	    XtSetSensitive(save_button, False);
502 	    if (appres.write_bak == True)
503 		(void) renamefile(fname);
504 	    if (write_file(fname, True) == 0) {
505 		FirstArg(XtNlabel, fname);
506 		SetValues(cfile_text);
507 		if (strcmp(fname, cur_filename) != 0) {
508 		    update_cur_filename(fname);	/* update cur_filename */
509 		}
510 		reset_modifiedflag();
511 		if (file_up)
512 		    file_panel_dismiss();
513 	    }
514 	    XtSetSensitive(save_button, True);
515 	}
516     } else { /* !file_popup */
517 	/*
518 	 * !file_popup, so the file panel was never created and the user
519 	 * never had the possibility to change directory.
520 	 * Also, save_file_dir = "" (I believe)
521 	 */
522 	/* see if writable */
523 	if (!ok_to_write(cur_filename, "SAVE"))
524 	    return;
525 	/* not using popup => filename not changed so ok to write existing file */
526 	warnexist = False;
527 	(void) renamefile(cur_filename);
528 	if (write_file(cur_filename, True) == 0)
529 	    reset_modifiedflag();
530     }
531 }
532 
533 /* try to rename current to current.bak */
534 
renamefile(char * file)535 int renamefile(char *file)
536 {
537     char	    bak_name[PATH_MAX];
538 
539     strcpy(bak_name,file);
540     strcat(bak_name,".bak");
541     if (rename(file,bak_name) < 0)
542 	return (-1);
543     return 0;
544 }
545 
546 Boolean
query_save(char * msg)547 query_save(char *msg)
548 {
549     int		    qresult;
550     if (!emptyfigure() && figure_modified && !aborting) {
551 	if ((qresult = popup_query(QUERY_YESNOCAN, msg)) == RESULT_CANCEL)
552 	    return False;
553 	else if (qresult == RESULT_YES) {
554 	    save_request((Widget) 0, (XButtonEvent *) 0);
555 	    /*
556 	     * if saving was not successful, figure_modified is still true:
557 	     * do not quit!
558 	     */
559 	    if (figure_modified)
560 		return False;
561 	}
562     }
563     /* ok */
564     return True;
565 }
566 
567 static void
cancel_request(Widget w,XButtonEvent * ev)568 cancel_request(Widget w, XButtonEvent *ev)
569 {
570     if (preview_in_progress) {
571 	file_cancel_request = True;
572 	/* request to cancel the preview */
573 	cancel_preview = True;
574     } else {
575 	/* make sure this is false from any previous previewing */
576 	cancel_preview = False;
577 	file_panel_cancel(w, ev);
578     }
579 }
580 
581 static void
file_panel_cancel(Widget w,XButtonEvent * ev)582 file_panel_cancel(Widget w, XButtonEvent *ev)
583 {
584     if (user_colors_saved) {
585 	restore_user_colors();
586 	restore_nuser_colors();
587 	colors_are_swapped = 0;
588     }
589     if (colors_are_swapped)
590 	swap_colors();
591     file_panel_dismiss();
592 }
593 
594 void
popup_saveas_panel(void)595 popup_saveas_panel(void)
596 {
597 	popup_file_panel(F_SAVEAS);
598 }
599 
600 void
popup_open_panel(void)601 popup_open_panel(void)
602 {
603 	popup_file_panel(F_OPEN);
604 }
605 
606 void
popup_merge_panel(void)607 popup_merge_panel(void)
608 {
609 	popup_file_panel(F_MERGE);
610 }
611 
612 static void
popup_file_panel(int mode)613 popup_file_panel(int mode)
614 {
615 	DeclareArgs(5);
616 
617 	/* turn off Compose key LED */
618 	setCompLED(0);
619 
620 	/* already up? */
621 	if (file_up) {
622 	    /* yes, just raise to top */
623 	    XRaiseWindow(tool_d, XtWindow(file_popup));
624 	    return;
625 	}
626 
627 	/* clear flags */
628 	colors_are_swapped = False;
629 	image_colors_are_saved = False;
630 
631 	set_temp_cursor(wait_cursor);
632 	/* if the export panel is up get rid of it */
633 	if (export_up) {
634 	    export_up = False;
635 	    XtPopdown(export_popup);
636 	}
637 	file_up = popup_up = True;
638 
639 	/* create it if it isn't already created */
640 	if (!file_popup) {
641 	    create_file_panel();
642 	} else {
643 	    FirstArg(XtNstring, cur_file_dir);
644 	    SetValues(file_dir);
645 	    Rescan(0, 0, 0, 0);
646 	}
647 	XtSetSensitive(figure_off, mode != F_SAVEAS);
648 	XtSetSensitive(fig_offset_lbl_x, mode != F_SAVEAS);
649 	XtSetSensitive(fig_offset_lbl_y, mode != F_SAVEAS);
650 	XtSetSensitive(fig_offset_x, mode != F_SAVEAS);
651 	XtSetSensitive(fig_offset_y, mode != F_SAVEAS);
652 	XtSetSensitive(file_xoff_unit_panel, mode != F_SAVEAS);
653 	XtSetSensitive(file_yoff_unit_panel, mode != F_SAVEAS);
654 
655 	/* now add/remove appropriate buttons and set the title in the titlebar */
656 	if (mode == F_SAVEAS) {
657 	    XtUnmanageChild(load_button);
658 	    XtUnmanageChild(merge_button);
659 	    XtManageChild(save_button);
660 	    FirstArg(XtNtitle, "Xfig: SaveAs");
661 	    SetValues(file_popup);
662 	    /* make <return> in the filename window save the file */
663 	    XtOverrideTranslations(file_selfile,
664 			   XtParseTranslationTable(file_name_saveas_translations));
665 	    /* make <return> and a double click in the file list window save the file */
666 	    XtOverrideTranslations(file_flist,
667 			   XtParseTranslationTable(file_list_saveas_translations));
668 
669 	} else if (mode == F_OPEN) {
670 	    XtUnmanageChild(save_button);
671 	    XtUnmanageChild(merge_button);
672 	    XtManageChild(load_button);
673 	    XtManageChild(new_xfig_button);
674 	    FirstArg(XtNtitle, "Xfig: Open Figure");
675 	    SetValues(file_popup);
676 	    /* make <return> in the filename window load the file */
677 	    XtOverrideTranslations(file_selfile,
678 			   XtParseTranslationTable(file_name_load_translations));
679 	    /* make <return> and a double click in the file list window load the file */
680 	    XtOverrideTranslations(file_flist,
681 			   XtParseTranslationTable(file_list_load_translations));
682 
683 	} else { /* must be F_MERGE */
684 	    XtUnmanageChild(save_button);
685 	    XtUnmanageChild(load_button);
686 	    XtManageChild(merge_button);
687 	    FirstArg(XtNtitle, "Xfig: Merge Figure");
688 	    SetValues(file_popup);
689 	    /* make <return> in the filename window merge the file */
690 	    XtOverrideTranslations(file_selfile,
691 			   XtParseTranslationTable(file_name_merge_translations));
692 	    /* make <return> and a double click in the file list window merge the file */
693 	    XtOverrideTranslations(file_flist,
694 			   XtParseTranslationTable(file_list_merge_translations));
695 
696 	}
697 
698 	FirstArg(XtNlabel, (figure_modified ? "Modified    " :
699 					      "Not modified"));
700 	SetValues(file_status);
701 	sprintf(buf, "%d", object_count(&objects));
702 	FirstArg(XtNlabel, buf);
703 	SetValues(num_objects);
704 	XtPopup(file_popup, XtGrabNone);
705 
706 	/* get rid of the dummy label if we haven't already */
707 	XtUnmanageChild(dummy_label);
708 	/* and put in the real preview widget */
709 	XtManageChild(preview_widget);
710 	/* insure that the most recent colormap is installed */
711 	set_cmap(XtWindow(file_popup));
712 	(void) XSetWMProtocols(tool_d, XtWindow(file_popup), &wm_delete_window, 1);
713 	reset_cursor();
714 
715 	/* this will install the wheel accelerators on the scrollbars
716 	   now that the panel is realized */
717 	Rescan(0, 0, 0, 0);
718 }
719 
720 static void
file_xoff_unit_select(Widget w,XtPointer new_unit,XtPointer garbage)721 file_xoff_unit_select(Widget w, XtPointer new_unit, XtPointer garbage)
722 {
723     FirstArg(XtNlabel, XtName(w));
724     SetValues(file_xoff_unit_panel);
725     xoff_unit_setting = (intptr_t) new_unit;
726 }
727 
728 static void
file_yoff_unit_select(Widget w,XtPointer new_unit,XtPointer garbage)729 file_yoff_unit_select(Widget w, XtPointer new_unit, XtPointer garbage)
730 {
731     FirstArg(XtNlabel, XtName(w));
732     SetValues(file_yoff_unit_panel);
733     yoff_unit_setting = (intptr_t) new_unit;
734 }
735 
create_file_panel(void)736 void create_file_panel(void)
737 {
738 	Widget		 file, beside, below, butbelow;
739 	XFontStruct	*temp_font;
740 	static Boolean   actions_added=False;
741 	Widget		 preview_form;
742 	Position	 xposn, yposn;
743 
744 	xoff_unit_setting = yoff_unit_setting = (intptr_t) appres.INCHES? 0: 1;
745 
746 	XtTranslateCoords(tool, (Position) 0, (Position) 0, &xposn, &yposn);
747 
748 	FirstArg(XtNx, xposn+50);
749 	NextArg(XtNy, yposn+50);
750 	NextArg(XtNtitle, "Xfig: File menu");
751 	NextArg(XtNcolormap, tool_cm);
752 	file_popup = XtCreatePopupShell("file_popup",
753 					transientShellWidgetClass,
754 					tool, Args, ArgCount);
755 	XtOverrideTranslations(file_popup,
756 			   XtParseTranslationTable(file_translations));
757 
758 	file_panel = XtCreateManagedWidget("file_panel", formWidgetClass,
759 					   file_popup, NULL, ZERO);
760 
761 	FirstArg(XtNlabel, "  File Status");
762 	NextArg(XtNjustify, XtJustifyLeft);
763 	NextArg(XtNborderWidth, 0);
764 	NextArg(XtNresize, False);
765 	NextArg(XtNtop, XtChainTop);
766 	NextArg(XtNbottom, XtChainTop);
767 	NextArg(XtNleft, XtChainLeft);
768 	NextArg(XtNright, XtChainLeft);
769 	file_stat_label = XtCreateManagedWidget("file_status_label", labelWidgetClass,
770 					    file_panel, Args, ArgCount);
771 	/* start with long label so length is enough - it will be reset by calling proc */
772 	FirstArg(XtNlabel, "Not modified ");
773 	NextArg(XtNfromHoriz, file_stat_label);
774 	NextArg(XtNjustify, XtJustifyLeft);
775 	NextArg(XtNborderWidth, 0);
776 	NextArg(XtNresize, False);
777 	NextArg(XtNtop, XtChainTop);
778 	NextArg(XtNbottom, XtChainTop);
779 	NextArg(XtNleft, XtChainLeft);
780 	NextArg(XtNright, XtChainLeft);
781 	file_status = XtCreateManagedWidget("file_status", labelWidgetClass,
782 					    file_panel, Args, ArgCount);
783 
784 	FirstArg(XtNlabel, " # of Objects");
785 	NextArg(XtNfromVert, file_status);
786 	NextArg(XtNjustify, XtJustifyLeft);
787 	NextArg(XtNborderWidth, 0);
788 	NextArg(XtNtop, XtChainTop);
789 	NextArg(XtNbottom, XtChainTop);
790 	NextArg(XtNleft, XtChainLeft);
791 	NextArg(XtNright, XtChainLeft);
792 	num_obj_label = XtCreateManagedWidget("num_objects_label", labelWidgetClass,
793 					  file_panel, Args, ArgCount);
794 
795 	FirstArg(XtNwidth, 50);
796 	NextArg(XtNfromVert, file_status);
797 	NextArg(XtNfromHoriz, num_obj_label);
798 	NextArg(XtNjustify, XtJustifyLeft);
799 	NextArg(XtNborderWidth, 0);
800 	NextArg(XtNresize, False);
801 	NextArg(XtNtop, XtChainTop);
802 	NextArg(XtNbottom, XtChainTop);
803 	NextArg(XtNleft, XtChainLeft);
804 	NextArg(XtNright, XtChainLeft);
805 	num_objects = XtCreateManagedWidget("num_objects", labelWidgetClass,
806 					    file_panel, Args, ArgCount);
807 
808 	FirstArg(XtNlabel, "Figure Offset");
809 	NextArg(XtNfromVert, num_objects);
810 	NextArg(XtNborderWidth, 0);
811 	NextArg(XtNtop, XtChainTop);
812 	NextArg(XtNbottom, XtChainTop);
813 	NextArg(XtNleft, XtChainLeft);
814 	NextArg(XtNright, XtChainLeft);
815 	figure_off = XtCreateManagedWidget("fig_offset_label", labelWidgetClass,
816 				     file_panel, Args, ArgCount);
817 	FirstArg(XtNlabel, "X");
818 	NextArg(XtNfromHoriz, figure_off);
819 	NextArg(XtNfromVert, num_objects);
820 	NextArg(XtNborderWidth, 0);
821 	NextArg(XtNtop, XtChainTop);
822 	NextArg(XtNbottom, XtChainTop);
823 	NextArg(XtNleft, XtChainLeft);
824 	NextArg(XtNright, XtChainLeft);
825 	fig_offset_lbl_x = XtCreateManagedWidget("fig_offset_lbl_x", labelWidgetClass,
826 				     file_panel, Args, ArgCount);
827 
828 	FirstArg(XtNwidth, 40);
829 	NextArg(XtNleftMargin, 4);
830 	NextArg(XtNeditType, XawtextEdit);
831 	NextArg(XtNstring, "0");
832 	NextArg(XtNinsertPosition, 0);
833 	NextArg(XtNfromHoriz, fig_offset_lbl_x);
834 	NextArg(XtNfromVert, num_objects);
835 	NextArg(XtNborderWidth, INTERNAL_BW);
836 	NextArg(XtNscrollHorizontal, XawtextScrollWhenNeeded);
837 	NextArg(XtNtop, XtChainTop);
838 	NextArg(XtNbottom, XtChainTop);
839 	NextArg(XtNleft, XtChainLeft);
840 	NextArg(XtNright, XtChainLeft);
841 	fig_offset_x = XtCreateManagedWidget("fig_offset_x", asciiTextWidgetClass,
842 					     file_panel, Args, ArgCount);
843 	FirstArg(XtNfromHoriz, fig_offset_x);
844 	NextArg(XtNfromVert, num_objects);
845 	NextArg(XtNtop, XtChainTop);
846 	NextArg(XtNbottom, XtChainTop);
847 	NextArg(XtNleft, XtChainLeft);
848 	NextArg(XtNright, XtChainLeft);
849 	NextArg(XtNleftBitmap, menu_arrow);	/* use menu arrow for pull-down */
850 	file_xoff_unit_panel = XtCreateManagedWidget(offset_unit_items[appres.INCHES? 0: 1],
851 				menuButtonWidgetClass, file_panel, Args, ArgCount);
852 	make_pulldown_menu(offset_unit_items, XtNumber(offset_unit_items),
853 				   -1, "", file_xoff_unit_panel, file_xoff_unit_select);
854 
855 	/* put the Y offset below the X */
856 
857 	FirstArg(XtNlabel, "Y");
858 	NextArg(XtNfromHoriz, figure_off);
859 	NextArg(XtNfromVert, file_xoff_unit_panel);
860 	NextArg(XtNborderWidth, 0);
861 	NextArg(XtNtop, XtChainTop);
862 	NextArg(XtNbottom, XtChainTop);
863 	NextArg(XtNleft, XtChainLeft);
864 	NextArg(XtNright, XtChainLeft);
865 	fig_offset_lbl_y = XtCreateManagedWidget("fig_offset_lbl_y", labelWidgetClass,
866 				     file_panel, Args, ArgCount);
867 
868 	FirstArg(XtNwidth, 40);
869 	NextArg(XtNleftMargin, 4);
870 	NextArg(XtNeditType, XawtextEdit);
871 	NextArg(XtNstring, "0");
872 	NextArg(XtNinsertPosition, 0);
873 	NextArg(XtNfromHoriz, fig_offset_lbl_y);
874 	NextArg(XtNfromVert, file_xoff_unit_panel);
875 	NextArg(XtNborderWidth, INTERNAL_BW);
876 	NextArg(XtNscrollHorizontal, XawtextScrollWhenNeeded);
877 	NextArg(XtNtop, XtChainTop);
878 	NextArg(XtNbottom, XtChainTop);
879 	NextArg(XtNleft, XtChainLeft);
880 	NextArg(XtNright, XtChainLeft);
881 	fig_offset_y = XtCreateManagedWidget("fig_offset_y", asciiTextWidgetClass,
882 					     file_panel, Args, ArgCount);
883 	FirstArg(XtNfromHoriz, fig_offset_y);
884 	NextArg(XtNfromVert, file_xoff_unit_panel);
885 	NextArg(XtNtop, XtChainTop);
886 	NextArg(XtNbottom, XtChainTop);
887 	NextArg(XtNleft, XtChainLeft);
888 	NextArg(XtNright, XtChainLeft);
889 	NextArg(XtNleftBitmap, menu_arrow);	/* use menu arrow for pull-down */
890 	file_yoff_unit_panel = XtCreateManagedWidget(offset_unit_items[appres.INCHES? 0: 1],
891 				menuButtonWidgetClass, file_panel, Args, ArgCount);
892 	make_pulldown_menu(offset_unit_items, XtNumber(offset_unit_items),
893 				   -1, "", file_yoff_unit_panel, file_yoff_unit_select);
894 
895 	FirstArg(XtNlabel, " Current File");
896 	NextArg(XtNfromVert, file_yoff_unit_panel);
897 	NextArg(XtNjustify, XtJustifyLeft);
898 	NextArg(XtNborderWidth, 0);
899 	NextArg(XtNtop, XtChainTop);
900 	NextArg(XtNbottom, XtChainTop);
901 	NextArg(XtNleft, XtChainLeft);
902 	NextArg(XtNright, XtChainLeft);
903 	cfile_lab = XtCreateManagedWidget("cur_file_label", labelWidgetClass,
904 					  file_panel, Args, ArgCount);
905 
906 	FirstArg(XtNlabel, cur_filename);
907 	NextArg(XtNfromVert, file_yoff_unit_panel);
908 	NextArg(XtNfromHoriz, cfile_lab);
909 	NextArg(XtNjustify, XtJustifyLeft);
910 	NextArg(XtNborderWidth, 0);
911 	NextArg(XtNwidth, FILE_WID);
912 	NextArg(XtNtop, XtChainTop);
913 	NextArg(XtNbottom, XtChainTop);
914 	NextArg(XtNleft, XtChainLeft);
915 	NextArg(XtNright, XtChainRight);
916 	cfile_text = XtCreateManagedWidget("cur_file_name", labelWidgetClass,
917 					   file_panel, Args, ArgCount);
918 
919 	FirstArg(XtNlabel, "     Filename");
920 	NextArg(XtNfromVert, cfile_lab);
921 	NextArg(XtNborderWidth, 0);
922 	NextArg(XtNtop, XtChainTop);
923 	NextArg(XtNbottom, XtChainTop);
924 	NextArg(XtNleft, XtChainLeft);
925 	NextArg(XtNright, XtChainLeft);
926 	file = XtCreateManagedWidget("file_label", labelWidgetClass,
927 				     file_panel, Args, ArgCount);
928 	FirstArg(XtNfont, &temp_font);
929 	GetValues(file);
930 
931 	/* make the filename slot narrow so we can show the preview to the right */
932 	FirstArg(XtNwidth, FILE_WID);
933 	NextArg(XtNleftMargin, 4);
934 	NextArg(XtNheight, max_char_height(temp_font) * 2 + 4);
935 	NextArg(XtNeditType, XawtextEdit);
936 	NextArg(XtNstring, cur_filename);
937 	NextArg(XtNinsertPosition, strlen(cur_filename));
938 	NextArg(XtNfromHoriz, file);
939 	NextArg(XtNfromVert, cfile_lab);
940 	NextArg(XtNscrollHorizontal, XawtextScrollWhenNeeded);
941 	NextArg(XtNtop, XtChainTop);
942 	NextArg(XtNbottom, XtChainTop);
943 	NextArg(XtNleft, XtChainLeft);
944 	NextArg(XtNright, XtChainRight);
945 	file_selfile = XtCreateManagedWidget("file_name", asciiTextWidgetClass,
946 					     file_panel, Args, ArgCount);
947 	XtOverrideTranslations(file_selfile,
948 			   XtParseTranslationTable(text_translations));
949 
950 	if (!actions_added) {
951 	    XtAppAddActions(tool_app, file_actions, XtNumber(file_actions));
952 	    actions_added = True;
953 	    /* add action to load file */
954 	    XtAppAddActions(tool_app, file_name_actions, XtNumber(file_name_actions));
955 	}
956 
957 	/* make the directory list etc */
958 	change_directory(cur_file_dir);
959 	strcpy(save_file_dir, cur_file_dir);
960 	create_dirinfo(True, file_panel, file_selfile, &beside, &butbelow, &file_mask,
961 		       &file_dir, &file_flist, &file_dlist, FILE_ALT_WID, True);
962 
963 	/*****************************************************/
964 	/* now make a preview canvas on the whole right side */
965 	/*****************************************************/
966 
967 	/* first a form just to the right of the figure offset menu button */
968 	FirstArg(XtNfromHoriz, file_yoff_unit_panel);
969 	NextArg(XtNtop, XtChainTop);
970 	NextArg(XtNbottom, XtChainTop);
971 	NextArg(XtNleft, XtChainRight);
972 	NextArg(XtNright, XtChainRight);
973 	preview_form = XtCreateManagedWidget("preview_form", formWidgetClass,
974 				file_panel, Args, ArgCount);
975 
976 	/* a title */
977 	FirstArg(XtNlabel, "Preview   ");
978 	NextArg(XtNborderWidth, 0);
979 	preview_label = XtCreateManagedWidget("preview_label", labelWidgetClass,
980 					    preview_form, Args, ArgCount);
981 
982 	/* make a label for the figure size */
983 	FirstArg(XtNlabel, " ");
984 	NextArg(XtNfromHoriz, preview_label);
985 	NextArg(XtNborderWidth, 0);
986 	preview_size = XtCreateManagedWidget("preview_size", labelWidgetClass,
987 					    preview_form, Args, ArgCount);
988 
989 	/* and one for the figure name in the preview */
990 	FirstArg(XtNlabel, " ");
991 	NextArg(XtNfromVert, preview_label);
992 	NextArg(XtNborderWidth, 0);
993 	preview_name = XtCreateManagedWidget("preview_name", labelWidgetClass,
994 					    preview_form, Args, ArgCount);
995 
996 	/* now a label widget for the preview canvas */
997 
998 	/* first create a pixmap for its background, into which we'll draw the figure */
999 	/* actually, make one for landscape and one for portrait */
1000 	preview_land_pixmap = XCreatePixmap(tool_d, canvas_win,
1001 			PREVIEW_CANVAS_W, PREVIEW_CANVAS_H, tool_dpth);
1002 	preview_port_pixmap = XCreatePixmap(tool_d, canvas_win,
1003 			PREVIEW_CANVAS_H, PREVIEW_CANVAS_W, tool_dpth);
1004 
1005 	/* make a form for the preview widget so we can center it */
1006 
1007 	FirstArg(XtNwidth, PREVIEW_CANVAS_W+8);
1008 	NextArg(XtNheight, PREVIEW_CANVAS_W+8);
1009 	NextArg(XtNfromVert, preview_name);
1010 	NextArg(XtNtop, XtChainTop);
1011 	NextArg(XtNbottom, XtChainTop);
1012 	NextArg(XtNleft, XtChainLeft);
1013 	NextArg(XtNright, XtChainLeft);
1014 	preview_widget_form = XtCreateManagedWidget("preview_widget_form",
1015 				formWidgetClass, preview_form, Args, ArgCount);
1016 
1017 	/* make a dummy label to fill the space until we put up the preview */
1018 	FirstArg(XtNlabel, "");
1019 	NextArg(XtNwidth, PREVIEW_CANVAS_W);
1020 	NextArg(XtNheight, PREVIEW_CANVAS_W);
1021 	dummy_label = XtCreateManagedWidget("dummy_label", labelWidgetClass,
1022 					  preview_widget_form, Args, ArgCount);
1023 
1024 	/* start the widget preview in portrait */
1025 	/* don't manage it yet until the panel is popped up */
1026 
1027 	FirstArg(XtNlabel, "");
1028 	NextArg(XtNbackgroundPixmap, preview_port_pixmap);
1029 	NextArg(XtNhorizDistance, (PREVIEW_CANVAS_W-PREVIEW_CANVAS_H)/2+4); /* center */
1030 	NextArg(XtNvertDistance, 4);
1031 	NextArg(XtNwidth, PREVIEW_CANVAS_H);
1032 	NextArg(XtNheight, PREVIEW_CANVAS_W);
1033 	NextArg(XtNtop, XtChainTop);
1034 	NextArg(XtNbottom, XtChainTop);
1035 	NextArg(XtNleft, XtChainLeft);
1036 	NextArg(XtNright, XtChainLeft);
1037 	preview_widget = XtCreateWidget("preview_widget", labelWidgetClass,
1038 					  preview_widget_form, Args, ArgCount);
1039 	/* erase the preview pixmaps */
1040 	clear_preview();
1041 
1042 	/* label for the figure comments */
1043 
1044 	FirstArg(XtNlabel, "Figure comments:");
1045 	NextArg(XtNfromVert, preview_widget_form);
1046 	below = XtCreateManagedWidget("comments_label", labelWidgetClass,
1047 					  preview_form, Args, ArgCount);
1048 	/* window for the figure comments */
1049 
1050 	FirstArg(XtNwidth, PREVIEW_CANVAS_W+8);
1051 	NextArg(XtNleftMargin, 4);
1052 	NextArg(XtNheight, 50);
1053 	NextArg(XtNfromVert, below);
1054 	NextArg(XtNvertDistance, 1);
1055 	NextArg(XtNborderWidth, INTERNAL_BW);
1056 	NextArg(XtNscrollHorizontal, XawtextScrollWhenNeeded);
1057 	NextArg(XtNscrollVertical, XawtextScrollWhenNeeded);
1058 	NextArg(XtNdisplayCaret, False);
1059 	NextArg(XtNtop, XtChainTop);
1060 	NextArg(XtNbottom, XtChainTop);
1061 	NextArg(XtNleft, XtChainLeft);
1062 	NextArg(XtNright, XtChainLeft);
1063 	comments_widget = XtCreateManagedWidget("comments", asciiTextWidgetClass,
1064 					     preview_form, Args, ArgCount);
1065 
1066 	/* make cancel preview button */
1067 	FirstArg(XtNlabel, "Stop Preview");
1068 	NextArg(XtNsensitive, False);
1069 	NextArg(XtNfromVert, comments_widget);
1070 	preview_stop = XtCreateManagedWidget("preview_stop", commandWidgetClass,
1071 				       preview_form, Args, ArgCount);
1072 	XtAddEventHandler(preview_stop, ButtonReleaseMask, False,
1073 			  (XtEventHandler)file_preview_stop, (XtPointer) NULL);
1074 
1075 	/* end of preview form */
1076 
1077 	/* now make buttons along the bottom */
1078 
1079 	FirstArg(XtNlabel, "Cancel");
1080 	NextArg(XtNfromHoriz, beside);
1081 	NextArg(XtNhorizDistance, 25);
1082 	NextArg(XtNfromVert, butbelow);
1083 	NextArg(XtNvertDistance, 15);
1084 	NextArg(XtNheight, 25);
1085 	NextArg(XtNborderWidth, INTERNAL_BW);
1086 	NextArg(XtNtop, XtChainBottom);
1087 	NextArg(XtNbottom, XtChainBottom);
1088 	NextArg(XtNleft, XtChainLeft);
1089 	NextArg(XtNright, XtChainLeft);
1090 	beside = cancel_button = XtCreateManagedWidget("cancel", commandWidgetClass,
1091 				       file_panel, Args, ArgCount);
1092 	XtAddEventHandler(cancel_button, ButtonReleaseMask, False,
1093 			  (XtEventHandler)cancel_request, (XtPointer) NULL);
1094 
1095 	/* now create Save, Open and Merge buttons but don't manage them - that's
1096 	   done in popup_saveas_panel, popup_open_panel, and popup_merge_panel */
1097 
1098 	FirstArg(XtNlabel, " Save ");
1099 	NextArg(XtNvertDistance, 15);
1100 	NextArg(XtNfromVert, butbelow);
1101 	NextArg(XtNfromHoriz, beside);
1102 	NextArg(XtNhorizDistance, 25);
1103 	NextArg(XtNheight, 25);
1104 	NextArg(XtNborderWidth, INTERNAL_BW);
1105 	NextArg(XtNtop, XtChainBottom);
1106 	NextArg(XtNbottom, XtChainBottom);
1107 	NextArg(XtNleft, XtChainLeft);
1108 	NextArg(XtNright, XtChainLeft);
1109 	save_button = XtCreateWidget("save", commandWidgetClass,
1110 				     file_panel, Args, ArgCount);
1111 	XtAddEventHandler(save_button, ButtonReleaseMask, False,
1112 			  (XtEventHandler) do_save, (XtPointer) NULL);
1113 
1114 	FirstArg(XtNlabel, " Open ");
1115 	NextArg(XtNborderWidth, INTERNAL_BW);
1116 	NextArg(XtNvertDistance, 15);
1117 	NextArg(XtNfromVert, butbelow);
1118 	NextArg(XtNfromHoriz, beside);
1119 	NextArg(XtNhorizDistance, 25);
1120 	NextArg(XtNheight, 25);
1121 	NextArg(XtNtop, XtChainBottom);
1122 	NextArg(XtNbottom, XtChainBottom);
1123 	NextArg(XtNleft, XtChainLeft);
1124 	NextArg(XtNright, XtChainLeft);
1125 	load_button = XtCreateWidget("load", commandWidgetClass,
1126 				     file_panel, Args, ArgCount);
1127 	XtAddEventHandler(load_button, ButtonReleaseMask, False,
1128 			  (XtEventHandler)load_request, (XtPointer) NULL);
1129 
1130 	FirstArg(XtNlabel, "Merge ");
1131 	NextArg(XtNhorizDistance, 20);
1132 	NextArg(XtNfromVert, butbelow);
1133 	NextArg(XtNfromHoriz, beside);
1134 	NextArg(XtNvertDistance, 15);
1135 	NextArg(XtNborderWidth, INTERNAL_BW);
1136 	NextArg(XtNheight, 25);
1137 	NextArg(XtNtop, XtChainBottom);
1138 	NextArg(XtNbottom, XtChainBottom);
1139 	NextArg(XtNleft, XtChainLeft);
1140 	NextArg(XtNright, XtChainLeft);
1141 	merge_button = XtCreateWidget("merge", commandWidgetClass,
1142 				      file_panel, Args, ArgCount);
1143 	XtAddEventHandler(merge_button, ButtonReleaseMask, False,
1144 			  (XtEventHandler)merge_request, (XtPointer) NULL);
1145 
1146 	FirstArg(XtNlabel, "New xfig...");
1147 	NextArg(XtNborderWidth, INTERNAL_BW);
1148 	NextArg(XtNvertDistance, 15);
1149 	NextArg(XtNfromVert, butbelow);
1150 	NextArg(XtNfromHoriz, merge_button);
1151 	NextArg(XtNhorizDistance, 25);
1152 	NextArg(XtNheight, 25);
1153 	NextArg(XtNtop, XtChainBottom);
1154 	NextArg(XtNbottom, XtChainBottom);
1155 	NextArg(XtNleft, XtChainLeft);
1156 	NextArg(XtNright, XtChainLeft);
1157 	new_xfig_button = XtCreateWidget("new_xfig", commandWidgetClass,
1158 				     file_panel, Args, ArgCount);
1159 	XtAddEventHandler(new_xfig_button, ButtonReleaseMask, False,
1160 			  (XtEventHandler)new_xfig_request, (XtPointer) NULL);
1161 
1162 	XtInstallAccelerators(file_panel, cancel_button);
1163 	XtInstallAccelerators(file_panel, save_button);
1164 	XtInstallAccelerators(file_panel, load_button);
1165 	XtInstallAccelerators(file_panel, new_xfig_button);
1166 	XtInstallAccelerators(file_panel, merge_button);
1167 
1168 }
1169 
1170 /* check if user pressed cancel button */
1171 Boolean
check_cancel(void)1172 check_cancel(void)
1173 {
1174     if (preview_in_progress) {
1175 	process_pending();
1176 	return cancel_preview;
1177     }
1178     return False;
1179 
1180 }
1181 
1182 static void
clear_preview(void)1183 clear_preview(void)
1184 {
1185     FirstArg(XtNlabel, "                                 ");
1186     SetValues(preview_name);
1187 
1188     FirstArg(XtNlabel, "                     ");
1189     SetValues(preview_size);
1190 
1191     /* clear both port and land pixmap */
1192     XSetForeground(tool_d, gccache[ERASE], x_bg_color.pixel);
1193     XFillRectangle(tool_d, preview_land_pixmap, gccache[ERASE], 0, 0,
1194 		   PREVIEW_CANVAS_W, PREVIEW_CANVAS_H);
1195     XFillRectangle(tool_d, preview_port_pixmap, gccache[ERASE], 0, 0,
1196 		   PREVIEW_CANVAS_H, PREVIEW_CANVAS_W);
1197 
1198     FirstArg(XtNbackgroundPixmap, (Pixmap)0);
1199     SetValues(preview_widget);
1200     /* put port pixmap in widget */
1201     FirstArg(XtNbackgroundPixmap, preview_port_pixmap);
1202     SetValues(preview_widget);
1203 }
1204 
1205 static void
file_preview_stop(Widget w,XButtonEvent * ev)1206 file_preview_stop(Widget w, XButtonEvent *ev)
1207 {
1208     /* set the cancel flag */
1209     cancel_preview = True;
1210     /* make the cancel button insensitive */
1211     XtSetSensitive(preview_stop, False);
1212     process_pending();
1213 }
1214 
preview_figure(char * filename,Widget parent,Widget canvas,Widget size_widget,Pixmap port_pixmap,Pixmap land_pixmap)1215 void preview_figure(char *filename, Widget parent, Widget canvas, Widget size_widget, Pixmap port_pixmap, Pixmap land_pixmap)
1216 {
1217     fig_settings    settings;
1218     int		save_objmask;
1219     int		save_zoomxoff, save_zoomyoff;
1220     float	save_zoomscale;
1221     Boolean	save_shownums;
1222     F_compound	*figure;
1223     int		xmin, xmax, ymin, ymax;
1224     float	width, height, size;
1225     int		pixwidth, pixheight;
1226     int		i, status;
1227     char	figsize[50];
1228     Pixel	pb;
1229 
1230     /* alloc a compound object - we must do it this way so free_compound()
1231        works properly */
1232     figure = create_compound();
1233 
1234     /* if already previewing file, return */
1235     if (preview_in_progress == True)
1236 	return;
1237 
1238     /* clear the cancel flag */
1239     cancel_preview = False;
1240 
1241     /* and any request to load a file */
1242     file_load_request = False;
1243     /* and merge */
1244     file_merge_request = False;
1245     /* and save */
1246     file_save_request = False;
1247     /* and cancel */
1248     file_cancel_request = False;
1249 
1250     /* say we are in progress */
1251     preview_in_progress = True;
1252 
1253     /* save active layer array and set all to True */
1254     save_active_layers();
1255     save_depths();
1256     save_counts_and_clear();
1257     reset_layers();
1258 
1259     /* save user colors in case preview changes them */
1260     if (!user_colors_saved) {
1261 	save_user_colors();
1262 	save_nuser_colors();
1263     }
1264 
1265     /* make the cancel button sensitive */
1266     XtSetSensitive(preview_stop, True);
1267     /* change label to read "Previewing" */
1268     FirstArg(XtNlabel, "Previewing");
1269     SetValues(preview_label);
1270     /* get current background color of label */
1271     FirstArg(XtNbackground, &pb);
1272     GetValues(preview_label);
1273     /* set it to red while previewing */
1274     FirstArg(XtNbackground, x_color(YELLOW));
1275     SetValues(preview_label);
1276 
1277     /* give filename a chance to appear in the Filename field */
1278     process_pending();
1279 
1280     /* first, save current zoom settings */
1281     save_zoomscale	= display_zoomscale;
1282     save_zoomxoff	= zoomxoff;
1283     save_zoomyoff	= zoomyoff;
1284 
1285     /* save and turn off showing vertex numbers */
1286     save_shownums	= appres.shownums;
1287     appres.shownums	= False;
1288 
1289     /* insure that the most recent colormap is installed */
1290     set_cmap(XtWindow(parent));
1291 
1292     /* make wait cursor */
1293     XDefineCursor(tool_d, XtWindow(parent), wait_cursor);
1294     /* define it for the file list panel too */
1295     XDefineCursor(tool_d, XtWindow(file_flist), wait_cursor);
1296     /* but use a "hand" cursor for the Preview Stop button */
1297     XDefineCursor(tool_d, XtWindow(preview_stop), pick9_cursor);
1298     process_pending();
1299 
1300     /* if we haven't already saved colors of the images on the canvas */
1301     if (!image_colors_are_saved) {
1302 	image_colors_are_saved = True;
1303 	/* save current canvas image colors */
1304 	for (i=0; i<avail_image_cols; i++) {
1305 	    save_image_cells[i].red   = image_cells[i].red;
1306 	    save_image_cells[i].green = image_cells[i].green;
1307 	    save_image_cells[i].blue  = image_cells[i].blue;
1308 	}
1309 	save_avail_image_cols = avail_image_cols;
1310     }
1311 
1312     /* unmanage the preview widget in case we need to change its shape (port<->land) */
1313     XtUnmanageChild(canvas);
1314     /* fool the toolkit into drawing the new pixmap */
1315     FirstArg(XtNbackgroundPixmap, (Pixmap)0);
1316     SetValues(canvas);
1317 
1318     /* read the figure into the local F_compound "figure" */
1319 
1320     /* we'll ignore the stuff returned in "settings" */
1321     if ((status = read_figc(filename,figure, DONT_MERGE, REMAP_IMAGES, 0,0,&settings)) != 0) {
1322 	switch (status) {
1323 	   case -1: file_msg("Bad format");
1324 		   break;
1325 	   case -2: file_msg("File is empty");
1326 		   break;
1327 	   default: file_msg("Error reading %s: %s",filename,strerror(errno));
1328 	}
1329 	/* clear pixmap of any figure so user knows something went wrong */
1330 	clear_preview();
1331     } else {
1332 	/*
1333 	 *  successful read, get the size
1334 	*/
1335 
1336 	add_compound_depth(figure);	/* count objects at each depth */
1337 
1338 	/* update the preview name */
1339 	FirstArg(XtNlabel, filename);
1340 	SetValues(preview_name);
1341 
1342 	/* put in any comments */
1343 	if (figure->comments) {
1344 	    FirstArg(XtNstring, figure->comments);
1345 	} else {
1346 	    FirstArg(XtNstring, "");
1347 	}
1348 	SetValues(comments_widget);
1349 
1350 	/* get bounds of figure */
1351 	xmin = figure->nwcorner.x;
1352 	xmax = figure->secorner.x;
1353 	ymin = figure->nwcorner.y;
1354 	ymax = figure->secorner.y;
1355 	width = xmax - xmin;
1356 	height = ymax - ymin;
1357 	size = max2(width,height) / ZOOM_FACTOR;
1358 	/* calculate size in current units */
1359 	if (width < PIX_PER_INCH || height < PIX_PER_INCH) {
1360 	    /* for small figures, show more decimal places */
1361 	    if (appres.INCHES) {
1362 		sprintf(figsize, "%.2f x %.2f in",width/PIX_PER_INCH,height/PIX_PER_INCH);
1363 	    } else {
1364 		sprintf(figsize, "%.1f x %.1f cm",width/PIX_PER_CM,height/PIX_PER_CM);
1365 	    }
1366 	} else {
1367 	    if (appres.INCHES) {
1368 		sprintf(figsize, "%.1f x %.1f in",width/PIX_PER_INCH,height/PIX_PER_INCH);
1369 	    } else {
1370 		sprintf(figsize, "%.0f x %.0f cm",width/PIX_PER_CM,height/PIX_PER_CM);
1371 	    }
1372 	}
1373 
1374 	if (size_widget) {
1375 	    FirstArg(XtNlabel, figsize);
1376 	    SetValues(preview_size);
1377 	}
1378 
1379 	/* now switch the drawing canvas to our preview window and set width/height */
1380 	if (settings.landscape) {
1381 	    canvas_win = (Window) land_pixmap;
1382 	    pixwidth = PREVIEW_CANVAS_W;
1383 	    pixheight = PREVIEW_CANVAS_H;
1384 	} else {
1385 	    canvas_win = (Window) port_pixmap;
1386 	    pixwidth = PREVIEW_CANVAS_H;
1387 	    pixheight = PREVIEW_CANVAS_W;
1388 	}
1389 
1390 	/* scale to fit the preview canvas */
1391 	display_zoomscale =
1392 			min2((float)(pixwidth-8)/width, (float)(pixheight-8)/height) *
1393 				ZOOM_FACTOR;
1394 	/* limit magnification to 5.0 */
1395 	if (display_zoomscale > 5.0)
1396 		display_zoomscale = 5.0;
1397 	zoomscale = display_zoomscale/ZOOM_FACTOR;
1398 
1399 	/* center the figure in the canvas */
1400 	zoomxoff = -(pixwidth/zoomscale - width) / 2.0 + xmin;
1401 	zoomyoff = -(pixheight/zoomscale - height) / 2.0 + ymin;
1402 
1403 	/* insure that the most recent colormap is installed */
1404 	/* we may have switched to a private colormap when previewing this figure */
1405 	set_cmap(XtWindow(parent));
1406 
1407 	/* no markers */
1408 	save_objmask = cur_objmask;
1409 	cur_objmask = 0;
1410 
1411 	/* clear the pixmap with the canvas background color */
1412 	XSetForeground(tool_d, gccache[ERASE], x_bg_color.pixel);
1413 	XFillRectangle(tool_d, canvas_win, gccache[ERASE], 0, 0, pixwidth, pixheight);
1414 
1415 	/* if he pressed "cancel preview" while reading file, skip displaying figure */
1416 	if (! check_cancel()) {
1417 	    /* draw the preview into the pixmap */
1418 	    redisplay_objects(figure);
1419 	}
1420 
1421 	/* restore marker flag */
1422 	cur_objmask = save_objmask;
1423 
1424 	/* put the pixmap back in and set the width and height and center it */
1425 	FirstArg(XtNbackgroundPixmap, canvas_win);
1426 	NextArg(XtNwidth, pixwidth);
1427 	NextArg(XtNheight, pixheight);
1428 	if (settings.landscape) {
1429 	    NextArg(XtNvertDistance, (PREVIEW_CANVAS_W-PREVIEW_CANVAS_H)/2+4);
1430 	    NextArg(XtNhorizDistance, 4);
1431 	} else {
1432 	    NextArg(XtNvertDistance, 4);
1433 	    NextArg(XtNhorizDistance, (PREVIEW_CANVAS_W-PREVIEW_CANVAS_H)/2+4);
1434 	}
1435 	SetValues(canvas);
1436 	XtManageChild(canvas);
1437     }
1438 
1439     /* free the figure compound */
1440     free_compound(&figure);
1441 
1442     /* switch canvas back */
1443     canvas_win = main_canvas;
1444 
1445     /* restore active layer array */
1446     restore_active_layers();
1447     /* and depth and counts */
1448     restore_depths();
1449     restore_counts();
1450 
1451     /* now restore settings for main canvas/figure */
1452     display_zoomscale	= save_zoomscale;
1453     zoomxoff		= save_zoomxoff;
1454     zoomyoff		= save_zoomyoff;
1455     zoomscale		= display_zoomscale/ZOOM_FACTOR;
1456 
1457     /* restore shownums */
1458     appres.shownums	= save_shownums;
1459 
1460     /* reset cursors */
1461     XUndefineCursor(tool_d, XtWindow(parent));
1462     XUndefineCursor(tool_d, XtWindow(file_flist));
1463     XUndefineCursor(tool_d, XtWindow(preview_stop));
1464 
1465     /* reset the cancel button and flag */
1466     cancel_preview = False;
1467 
1468     /* make the cancel button insensitive */
1469     XtSetSensitive(preview_stop, False);
1470 
1471     /* change label to read "Preview" */
1472     FirstArg(XtNlabel, "Preview");
1473     /* and change background to original color */
1474     NextArg(XtNbackground, pb);
1475     SetValues(preview_label);
1476 
1477     process_pending();
1478     /* check if user had double clicked on filename which means he wanted
1479        to load the file, not just preview it */
1480 
1481     /* say we are finished */
1482     preview_in_progress = False;
1483 
1484     if (file_cancel_request) {
1485 	cancel_preview = False;
1486 	file_panel_cancel((Widget) 0, (XButtonEvent *) 0);
1487     }
1488     if (file_load_request) {
1489 	cancel_preview = False;
1490 	do_load((Widget) 0, (XButtonEvent *) 0);
1491 	/* if redisplay_region was called don't bother because
1492 	   we're loading a file over it */
1493 	request_redraw = False;
1494     }
1495     if (file_merge_request) {
1496 	cancel_preview = False;
1497 	do_merge((Widget) 0, (XButtonEvent *) 0);
1498     }
1499     if (file_save_request) {
1500 	cancel_preview = False;
1501 	do_save((Widget) 0, (XButtonEvent *) 0);
1502     }
1503     /* if user requested a canvas redraw while preview was being generated
1504        do that now for full canvas */
1505     if (request_redraw) {
1506 	redisplay_region(0, 0, CANVAS_WD, CANVAS_HT);
1507 	request_redraw = False;
1508     }
1509 }
1510