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 "main.h"
21 #include "mode.h"
22 #include "object.h"
23 #include "d_text.h"
24 #include "f_read.h"
25 #include "f_util.h"
26 #include "u_create.h"
27 #include "u_fonts.h"
28 #include "u_pan.h"
29 #include "u_redraw.h"
30 #include "u_search.h"
31 #include "u_undo.h"
32 #include "w_canvas.h"
33 #include "w_cmdpanel.h"
34 #include "w_digitize.h"
35 #include "w_drawprim.h"
36 #include "w_export.h"
37 #include "w_file.h"
38 #include "w_help.h"
39 #include "w_icons.h"
40 #include "w_indpanel.h"
41 #include "w_layers.h"
42 #include "w_msgpanel.h"
43 #include "w_mousefun.h"
44 #include "w_print.h"
45 #include "w_rulers.h"
46 #include "w_srchrepl.h"
47 #include "w_util.h"
48 #include "w_setup.h"
49 #include "w_style.h"
50 #include "w_zoom.h"
51 #include "w_snap.h"
52 #include "e_delete.h"
53 #include "f_load.h"
54 #include "u_bound.h"
55 #include "u_draw.h"
56 #include "u_free.h"
57 #include "u_list.h"
58 #include "u_translate.h"
59 #include "w_cursor.h"
60 #include "w_modepanel.h"
61
62 #ifndef XAW3D1_5E
63 #include "w_menuentry.h"
64 #endif
65 #ifdef I18N
66 #include "d_text.h"
67 #endif /* I18N */
68
69 #include <X11/IntrinsicP.h> /* XtResizeWidget() */
70
71 /* internal features and definitions */
72
73 DeclareStaticArgs(12);
74
75 #define menu_item_bitmap_width 9
76 #define menu_item_bitmap_height 8
77 static unsigned char menu_item_bitmap_bits[] = {
78 0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x60, 0x00,
79 0x31, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04, 0x00
80 };
81
82 static Pixmap menu_item_bitmap = None;
83
84 /* Widgets holding the ascii values for the string-based settings */
85
86 Widget bal_delay;
87 Widget n_freehand_resolution;
88 Widget n_recent_files;
89 Widget max_colors;
90 Widget image_ed;
91 Widget spell_chk;
92 Widget browser;
93 Widget pdfview;
94
95 /* global settings */
96
97 Widget global_popup = (Widget) 0;
98 Widget global_panel;
99
100 /* prototypes */
101
102 static void enter_cmd_but(Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch);
103 void delete_all_cmd(Widget w, int closure, int call_data);
104 static void init_move_paste_object(int x, int y),move_paste_object(int x, int y);
105 static void place_object(int x, int y, unsigned int shift),cancel_paste(void);
106 static void paste_draw(int paint_mode);
107 static void place_object_orig_posn(int x, int y, unsigned int shift);
108 static void place_menu(Widget w, XEvent *event, String *params, Cardinal *nparams), popup_menu(Widget w, XEvent *event, String *params, Cardinal *nparams);
109 static void load_recent_file(Widget w, XtPointer client_data, XtPointer call_data);
110
111 static void popup_global_panel(Widget w);
112 static void global_panel_done(Widget w, XButtonEvent *ev);
113 static void global_panel_cancel(Widget w, XButtonEvent *ev);
114 static void character_panel_close(void);
115 static void paste_char(Widget w, XtPointer client_data, XtPointer call_data);
116
117 Widget CreateLabelledAscii(Widget *text_widg, char *label, char *widg_name, Widget parent, Widget below, char *str, int width);
118 static Widget create_main_menu(int menu_num, Widget beside);
119
120 static int off_paste_x,off_paste_y;
121 static int orig_paste_x,orig_paste_y;
122
123 static Widget character_map_popup = (Widget) 0;
124 static Widget character_map_panel, close_but;
125
126 #ifdef XAW3D1_5E
127 #else
128 /* popup message over command button when mouse enters it */
129 static void cmd_balloon_trigger(Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch);
130 static void cmd_unballoon(Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch);
131
132 /* popup message over filename window when mouse enters it */
133 static void filename_balloon_trigger(Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch);
134 static void filename_unballoon(Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch);
135 #endif /* XAW3D1_5E */
136
137 String global_translations =
138 "<Message>WM_PROTOCOLS: DismissGlobal()\n";
139
140 String charmap_translations =
141 "<Message>WM_PROTOCOLS: DismissCharmap()\n";
142
143 static XtActionsRec global_actions[] =
144 {
145 {"DismissGlobal", (XtActionProc) global_panel_cancel},
146 };
147 static XtActionsRec charmap_actions[] =
148 {
149 {"DismissCharmap", (XtActionProc) character_panel_close},
150 };
151
152 static XtActionsRec menu_actions[] =
153 {
154 {"xMenuPopup", (XtActionProc) popup_menu},
155 {"PlaceMenu", (XtActionProc) place_menu},
156 };
157
158 menu_def file_menu_items[] = {
159 {"New (Meta-N)", 0, new, False},
160 {"Open... (Meta-O)", 0, popup_open_panel, False},
161 {"Merge... (Meta-M)", 0, popup_merge_panel, False},
162 #ifdef DIGITIZE
163 {"Digitize... (Meta-Z)", 0, popup_digitize_panel, False},
164 #endif /* DIGITIZE */
165 {"Save (Meta-S)", 0, do_save, False},
166 {"Save As... (Meta-A)", 5, popup_saveas_panel, False},
167 {"Export... (Meta-X) (Quick = Shift-Meta-X)", 0, popup_export_panel, False},
168 {"Print... (Meta-P) (Quick = Shift-Meta-P)", 0, popup_print_panel, False},
169 {"Exit (Meta-Q)", 1, quit, False},
170 {(char *) -1, 0, NULL, False}, /* makes a line separator followed by */
171 {NULL, 0, NULL, False}, /* recently loaded files */
172 };
173
174 menu_def edit_menu_items[] = {
175 {"Undo (Meta-U) ", 0, undo, False},
176 {"Paste Objects (Meta-T) ", 0, paste, False},
177 {"Paste Text (F18/F20)", 6, paste_primary_selection, False},
178 {"Search/Replace... (Meta-I) ", -1, popup_search_panel, False},
179 {"Spell Check... (Meta-K) ", 0, spell_check, False},
180 {"Delete All (Meta-D) ", 0, delete_all_cmd, False},
181 {"-", 0, NULL, False}, /* divider line */
182 {"Global settings... (Meta-G) ", 0, show_global_settings, False},
183 {"Set units... (Shift-U)", 5, popup_unit_panel, False},
184 {NULL, 0, NULL, False},
185 };
186
187 #define PAGE_BRD_MSG "Show page borders (Meta-B)"
188 #define DPTH_MGR_MSG "Show depth manager "
189 #define INFO_BAL_MSG "Show info balloons (Meta-Y)"
190 #define LINE_LEN_MSG "Show line lengths (Meta-L)"
191 #define VRTX_NUM_MSG "Show vertex numbers "
192 #define AUTO_RFS_MSG "Autorefresh mode "
193
194 menu_def view_menu_items[] = {
195 {"Manage Styles... (Ctrl-Y)", 7, popup_manage_style_panel, False},
196 {"Redraw (Ctrl-L)", 0, redisplay_canvas, False},
197 {"Portrait/Landscape (Meta-C)", 3, change_orient, False},
198 {"Zoom In (Shift-Z)", 5, inc_zoom_centered, False},
199 {"Zoom Out (z)", 5, dec_zoom_centered, False},
200 {"Zoom to Fit canvas (Ctrl-Z)", 8, fit_zoom, False},
201 {"Unzoom", 0, unzoom, False},
202 {"Pan to origin", 0, pan_origin, False},
203 {"Character map", 0, popup_character_map, False},
204 {"-", 0, NULL, False}, /* divider line */
205 /* the following menu labels will be refreshed in refresh_view_menu() */
206 {PAGE_BRD_MSG, 10, toggle_show_borders, True},
207 {DPTH_MGR_MSG, 5, toggle_show_depths, True},
208 {INFO_BAL_MSG, 6, toggle_show_balloons, True},
209 {LINE_LEN_MSG, 10, toggle_show_lengths, True},
210 {VRTX_NUM_MSG, 5, toggle_show_vertexnums, True},
211 {AUTO_RFS_MSG, 0, toggle_refresh_mode, True},
212 {NULL, 0, NULL, False},
213 };
214
215 menu_def help_menu_items[] = {
216 {"Xfig Reference (HTML)...", 0, launch_refman, False},
217 #ifdef FIXED_JAPANESE_PDF
218 {"Xfig Reference (PDF, English)...", 0, launch_refpdf_en, False},
219 /* Tom Sato said that the Japanese version of the pdf looked ugly so we'll not distribute it now */
220 {"Xfig Reference (PDF, Japanese)...", 0, launch_refpdf_jp, False},
221 #else
222 {"Xfig Reference (PDF)...", 0, launch_refpdf_en, False},
223 #endif /* FIXED_JAPANESE_PDF */
224 {"Xfig Man Pages (HTML)...", 5, launch_man, False},
225 {"How-To Guide (PDF)...", 0, launch_howto, False},
226 {"About Xfig...", 0, launch_about, False},
227 {NULL, 0, NULL, False},
228 };
229
230 menu_def snap_menu_items[] = {
231 {"Hold", 0, snap_hold}, /* hol snap mode until released */
232 {"Release", 0, snap_release}, /* release hold */
233 {"-", 0, NULL}, /* make a dividing line */
234 /* selections that always work */
235 {"Endpoint", 0, snap_endpoint}, /* snap to vertices or other endpoints */
236 {"Midpoint", 0, snap_midpoint}, /* snap to segment or other midpoints */
237 {"Nearest", 0, snap_nearest}, /* snap to nearest object */
238 {"Focus", 0, snap_focus}, /* snap to ellipse focus or circle centerpoint */
239 {"-", 0, NULL}, /* make a dividing line */
240 /* selections that only work as a polyline vertex (other stuff?) */
241 {"Normal", 0, snap_normal}, /* snap to point that results in a seg normal to snapped-to obj */
242 {"Tangent", 0, snap_tangent}, /* snap to point that results in a seg tangent to obj */
243 {"Intersection", 0, snap_intersect}, /* snap to intersection of picked objs */
244 {"Diameter", 0, snap_diameter}, /* snap to ellipse or circle opposite diameter */
245 {"-", 0, NULL}, /* make a dividing line */
246 {NULL, 0, NULL},
247 };
248
249 /* command panel of menus */
250
251 main_menu_info main_menus[] = {
252 {"File", "filemenu", "File menu", file_menu_items},
253 {"Edit", "editmenu", "Edit menu", edit_menu_items},
254 {"View", "viewmenu", "View menu", view_menu_items},
255 {"Snap", "snapmenu", "Snap menu", snap_menu_items},
256 {"Help", "helpmenu", "Help menu", help_menu_items},
257 };
258 #define NUM_CMD_MENUS (sizeof(main_menus) / sizeof(main_menu_info))
259
260 /* needed by setup_sizes() */
261
262
263 void create_global_panel (Widget w);
264 int locate_menu (String *params, Cardinal *nparams);
265
266
267 int
num_main_menus(void)268 num_main_menus(void)
269 {
270 return (NUM_CMD_MENUS);
271 }
272
273 /* command panel */
274 void
init_main_menus(Widget tool,char * filename)275 init_main_menus(Widget tool, char *filename)
276 {
277 register int i;
278 Widget beside = NULL;
279 DeclareArgs(11);
280
281 FirstArg(XtNborderWidth, 0);
282 NextArg(XtNcolormap, tool_cm);
283 NextArg(XtNdefaultDistance, 0);
284 NextArg(XtNhorizDistance, 0);
285 NextArg(XtNvertDistance, 0);
286 NextArg(XtNleft, XtChainLeft);
287 NextArg(XtNright, XtChainLeft);
288 NextArg(XtNtop, XtChainTop);
289 NextArg(XtNbottom, XtChainTop);
290 cmd_form = XtCreateWidget("commands", formWidgetClass, tool, Args, ArgCount);
291
292 for (i = 0; i < NUM_CMD_MENUS; ++i) {
293 beside = create_main_menu(i, beside);
294 }
295
296 /* now setup the filename label widget to the right of the command menu buttons */
297
298 FirstArg(XtNlabel, filename);
299 NextArg(XtNfromHoriz, cmd_form);
300 NextArg(XtNhorizDistance, -INTERNAL_BW);
301 NextArg(XtNfont, bold_font);
302 NextArg(XtNjustify, XtJustifyLeft);
303 NextArg(XtNwidth, NAMEPANEL_WD);
304 NextArg(XtNheight, CMD_BUT_HT+INTERNAL_BW);
305 NextArg(XtNtop, XtChainTop);
306 NextArg(XtNbottom, XtChainTop);
307 NextArg(XtNborderWidth, INTERNAL_BW);
308 name_panel = XtCreateManagedWidget("file_name", labelWidgetClass, tool,
309 Args, ArgCount);
310 #ifndef XAW3D1_5E
311 /* popup balloon when mouse passes over filename */
312 XtAddEventHandler(name_panel, EnterWindowMask, False,
313 filename_balloon_trigger, (XtPointer) name_panel);
314 XtAddEventHandler(name_panel, LeaveWindowMask, False,
315 filename_unballoon, (XtPointer) name_panel);
316 #endif
317 /* add actions to position the menus if the user uses an accelerator */
318 refresh_view_menu();
319 }
320
321 void
add_cmd_actions(void)322 add_cmd_actions(void)
323 {
324 XtAppAddActions(tool_app, menu_actions, XtNumber(menu_actions));
325 }
326
327 static Widget
create_main_menu(int menu_num,Widget beside)328 create_main_menu(int menu_num, Widget beside)
329 {
330 register main_menu_info *menu;
331
332 menu = &main_menus[menu_num];
333 FirstArg(XtNborderWidth, INTERNAL_BW);
334 NextArg(XtNfont, button_font);
335 NextArg(XtNwidth, CMD_BUT_WD);
336 NextArg(XtNheight, CMD_BUT_HT);
337 NextArg(XtNvertDistance, 0);
338 NextArg(XtNhorizDistance, -INTERNAL_BW);
339 NextArg(XtNlabel, menu->label);
340 NextArg(XtNfromHoriz, beside);
341 NextArg(XtNmenuName, menu->menu_name);
342 /* make button to popup each menu */
343 menu->widget = XtCreateManagedWidget(menu->label, menuButtonWidgetClass,
344 cmd_form, Args, ArgCount);
345 XtAddEventHandler(menu->widget, EnterWindowMask, False,
346 enter_cmd_but, (XtPointer) menu);
347
348 /* now the menu itself */
349 menu->menuwidget = create_menu_item(menu);
350
351 #ifndef XAW3D1_5E
352 /* popup when mouse passes over button */
353 XtAddEventHandler(menu->widget, EnterWindowMask, False,
354 cmd_balloon_trigger, (XtPointer) menu);
355 XtAddEventHandler(menu->widget, LeaveWindowMask, False,
356 cmd_unballoon, (XtPointer) menu);
357 #endif
358
359 return menu->widget;
360 }
361
362 void
rebuild_file_menu(Widget menu)363 rebuild_file_menu(Widget menu)
364 {
365 static Boolean first = TRUE;
366 Widget entry;
367 int j;
368 char id[10];
369
370 if (menu == None)
371 menu = main_menus[0].menuwidget;
372
373 if (first) {
374 first = FALSE;
375 for (j = 0; j < MAX_RECENT_FILES; j++) {
376 sprintf(id, "%1d", j + 1);
377 FirstArg(XtNvertSpace, 10);
378 #ifndef XAW3D1_5E
379 NextArg(XtNunderline, 0); /* underline # digit */
380 entry = XtCreateWidget(id, figSmeBSBObjectClass, menu, Args, ArgCount);
381 #else
382 entry = XtCreateWidget(id, smeBSBObjectClass, menu, Args, ArgCount);
383 #endif
384 XtAddCallback(entry, XtNcallback, load_recent_file, (XtPointer) strdup(id));
385 if (j < max_recent_files)
386 XtManageChild(entry);
387 }
388 }
389 for (j = 0; j < max_recent_files; j++) {
390 sprintf(id, "%1d", j + 1);
391 entry = XtNameToWidget(menu, id);
392 if (entry != None) {
393 if (j < num_recent_files) {
394 FirstArg(XtNlabel, recent_files[j].name);
395 NextArg(XtNsensitive, True);
396 SetValues(entry);
397 } else {
398 FirstArg(XtNlabel, id);
399 NextArg(XtNsensitive, False);
400 SetValues(entry);
401 }
402 }
403 }
404 }
405
406 Widget
create_menu_item(main_menu_info * menup)407 create_menu_item(main_menu_info *menup)
408 {
409 int i;
410 Widget menu, entry;
411 DeclareArgs(5);
412
413 FirstArg(XtNallowShellResize, True);
414 menu = XtCreatePopupShell(menup->menu_name, simpleMenuWidgetClass,
415 menup->widget, Args, ArgCount);
416 /* make the menu items */
417 for (i = 0; menup->menu[i].name != NULL; i++) {
418 if ((intptr_t) menup->menu[i].name == -1) {
419 /* put in a separator line */
420 FirstArg(XtNlineWidth, 2);
421 (void) XtCreateManagedWidget("line", smeLineObjectClass,
422 menu, Args, ArgCount);
423 /* and add recently loaded files to the menu */
424 rebuild_file_menu(menu);
425 } else if (strcmp(menup->menu[i].name, "-") == 0) {
426 /* put in a separator line */
427 (void) XtCreateManagedWidget("line", smeLineObjectClass, menu, NULL, 0);
428 } else {
429 /* normal menu entry */
430 FirstArg(XtNvertSpace, 10);
431 /* leave space for the checkmark bitmap */
432 if (menup->menu[i].checkmark) {
433 NextArg(XtNleftMargin, 12);
434 }
435 #ifndef XAW3D1_5E
436 NextArg(XtNunderline, menup->menu[i].u_line); /* any underline */
437 entry = XtCreateManagedWidget(menup->menu[i].name, figSmeBSBObjectClass,
438 menu, Args, ArgCount);
439 #else
440 entry = XtCreateManagedWidget(menup->menu[i].name, smeBSBObjectClass,
441 menu, Args, ArgCount);
442 #endif
443 XtAddCallback(entry, XtNcallback, menup->menu[i].func,
444 (XtPointer) menup->widget);
445 }
446 }
447 return menu;
448 }
449
450 void
setup_main_menus(void)451 setup_main_menus(void)
452 {
453 register int i;
454 register main_menu_info *menu;
455 DeclareArgs(2);
456
457 XDefineCursor(tool_d, XtWindow(cmd_form), arrow_cursor);
458
459 for (i = 0; i < NUM_CMD_MENUS; ++i) {
460 menu = &main_menus[i];
461 FirstArg(XtNfont, button_font); /* label font */
462 if ( menu->menu )
463 NextArg(XtNleftBitmap, menu_arrow); /* use menu arrow for pull-down */
464 SetValues(menu->widget);
465 }
466 }
467
468 #ifndef XAW3D1_5E
469 /* come here when the mouse passes over a button in the command panel */
470
471 static Widget cmd_balloon_popup = (Widget) 0;
472 static XtIntervalId balloon_id = (XtIntervalId) 0;
473 static Widget balloon_w;
474 static XtPointer clos;
475
476 static void cmd_balloon(Widget w, XtPointer closure, XtPointer call_data);
477
478 static void
cmd_balloon_trigger(Widget widget,XtPointer closure,XEvent * event,Boolean * continue_to_dispatch)479 cmd_balloon_trigger(Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch)
480 {
481 if (!appres.showballoons)
482 return;
483 balloon_w = widget;
484 clos = closure;
485 /* if an old balloon is still up, destroy it */
486 if ((balloon_id != 0) || (cmd_balloon_popup != (Widget) 0)) {
487 cmd_unballoon((Widget) 0, (XtPointer) 0, (XEvent*) 0, (Boolean*) 0);
488 }
489 balloon_id = XtAppAddTimeOut(tool_app, appres.balloon_delay,
490 (XtTimerCallbackProc) cmd_balloon, (XtPointer) NULL);
491 }
492
493 static void
cmd_balloon(Widget w,XtPointer closure,XtPointer call_data)494 cmd_balloon(Widget w, XtPointer closure, XtPointer call_data)
495 {
496 Position x, y;
497 Dimension wid, ht;
498 main_menu_info *menu= (main_menu_info *) clos;
499 Widget box, balloons_label;
500
501 /* get width and height of this button */
502 FirstArg(XtNwidth, &wid);
503 NextArg(XtNheight, &ht);
504 GetValues(balloon_w);
505 /* find middle and lower edge */
506 XtTranslateCoords(balloon_w, wid/2, ht+2, &x, &y);
507 /* put popup there */
508 FirstArg(XtNx, x);
509 NextArg(XtNy, y);
510 cmd_balloon_popup = XtCreatePopupShell("cmd_balloon_popup",overrideShellWidgetClass,
511 tool, Args, ArgCount);
512 FirstArg(XtNborderWidth, 0);
513 NextArg(XtNhSpace, 0);
514 NextArg(XtNvSpace, 0);
515 NextArg(XtNorientation, XtorientVertical);
516 box = XtCreateManagedWidget("box", boxWidgetClass, cmd_balloon_popup, Args, ArgCount);
517
518 /* put left/right mouse button labels as message */
519 FirstArg(XtNborderWidth, 0);
520 NextArg(XtNlabel, menu->hint);
521 balloons_label = XtCreateManagedWidget("label", labelWidgetClass,
522 box, Args, ArgCount);
523
524 XtPopup(cmd_balloon_popup,XtGrabNone);
525 XtRemoveTimeOut(balloon_id);
526 balloon_id = (XtIntervalId) 0;
527 }
528
529 /* come here when the mouse leaves a button in the command panel */
530
531 static void
cmd_unballoon(Widget widget,XtPointer closure,XEvent * event,Boolean * continue_to_dispatch)532 cmd_unballoon(Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch)
533 {
534 if (balloon_id) {
535 XtRemoveTimeOut(balloon_id);
536 }
537 balloon_id = (XtIntervalId) 0;
538 if (cmd_balloon_popup != (Widget) 0) {
539 XtDestroyWidget(cmd_balloon_popup);
540 cmd_balloon_popup = (Widget) 0;
541 }
542 }
543 #endif /* XAW3D1_5E */
544
545 static void
enter_cmd_but(Widget widget,XtPointer closure,XEvent * event,Boolean * continue_to_dispatch)546 enter_cmd_but(Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch)
547 {
548 main_menu_info *menu = (main_menu_info *) closure;
549 draw_mousefun(menu->hint, "", "");
550 }
551
552 static char quit_msg[] = "The current figure is modified.\nDo you want to save it before quitting?";
553
554 void
quit(Widget w,XtPointer closure,XtPointer call_data)555 quit(Widget w, XtPointer closure, XtPointer call_data)
556 {
557 /* turn off Compose key LED */
558 setCompLED(0);
559
560 /* don't quit if in the middle of drawing/editing */
561 if (check_action_on())
562 return;
563
564 XtSetSensitive(w, False);
565 /* if modified (and non-empty) ask to save first */
566 if (!query_save(quit_msg)) {
567 XtSetSensitive(w, True);
568 return; /* cancel, do not quit */
569 }
570 /* if the user hasn't saved changes to the named styles confirm */
571 if (style_dirty_flag)
572 if (confirm_close_style() == RESULT_CANCEL) {
573 XtSetSensitive(w, True);
574 return; /* cancel, don't quit */
575 }
576
577 goodbye(False); /* finish up and exit */
578 }
579
goodbye(Boolean abortflag)580 void goodbye(Boolean abortflag)
581 {
582 #ifdef I18N
583 #ifdef I18N_USE_PREEDIT
584 kill_preedit();
585 #endif /* I18N_USE_PREEDIT */
586 #endif /* I18N */
587 /* delete the cut buffer only if it is in a temporary directory */
588 if (strncmp(cut_buf_name, TMPDIR, strlen(TMPDIR)) == 0)
589 unlink(cut_buf_name);
590
591 /* delete any batch print file */
592 if (batch_exists)
593 unlink(batch_file);
594
595 XSync(tool_d, False); /* https://sourceforge.net/p/mcj/tickets/54 */
596
597 /* free all the GC's */
598 free_GCs();
599 /* free all the loaded X-Fonts*/
600 free_Fonts();
601
602 XtDestroyWidget(tool);
603
604 /* generate a fault to cause core dump */
605 if (abortflag) {
606 /* go to orig_dir, in case core dumps go to the cwd */
607 (void) change_directory(orig_dir);
608 abort();
609 }
610 exit(0);
611 }
612
613 void
paste(Widget w,XtPointer closure,XtPointer call_data)614 paste(Widget w, XtPointer closure, XtPointer call_data)
615 {
616 fig_settings settings;
617 int x,y;
618 struct stat file_status;
619
620 /* turn off Compose key LED */
621 setCompLED(0);
622
623 /* don't paste if in the middle of drawing/editing */
624 if (check_action_on())
625 return;
626
627 /* turn off anypointposn so cur_pointposn is used for pasting (user may
628 * be in a mode that doesn't use the point positioning grid */
629 anypointposn = 0;
630
631 set_cursor(wait_cursor);
632 turn_off_current();
633 set_mousefun("place object","place at orig posn","cancel paste",
634 "place object", "place at orig posn", "cancel paste");
635 /* set to paste mode */
636 set_action_on();
637 cur_mode = F_PASTE;
638
639 cur_c = create_compound();
640 cur_c->parent = NULL;
641 cur_c->GABPtr = NULL;
642 cur_c->arcs = NULL;
643 cur_c->compounds = NULL;
644 cur_c->ellipses = NULL;
645 cur_c->lines = NULL;
646 cur_c->splines = NULL;
647 cur_c->texts = NULL;
648 cur_c->comments = NULL;
649 cur_c->next = NULL;
650
651 /* read in the cut buf file */
652 if (read_figc(cut_buf_name,cur_c,MERGE,DONT_REMAP_IMAGES,0,0,&settings)==0) {
653 compound_bound(cur_c,
654 &cur_c->nwcorner.x,
655 &cur_c->nwcorner.y,
656 &cur_c->secorner.x,
657 &cur_c->secorner.y);
658
659 /* save orig coords of object */
660 orig_paste_x = cur_c->nwcorner.x;
661 orig_paste_y = cur_c->nwcorner.y;
662
663 /* make it relative for mouse positioning */
664 translate_compound(cur_c, -cur_c->nwcorner.x, -cur_c->nwcorner.y);
665 } else {
666 /* an error reading the .xfig file */
667 if (stat(cut_buf_name, &file_status) == 0) { /* file exists */
668 file_msg("Error reading %s",cut_buf_name);
669 } else if (errno == ENOENT) {
670 file_msg("Cut buffer (%s) is empty",cut_buf_name);
671 }
672 reset_action_on();
673 turn_off_current();
674 set_cursor(arrow_cursor);
675 free_compound(&cur_c);
676 return;
677 }
678 /* redraw all of the pictures already on the canvas */
679 canvas_ref_proc = null_proc;
680 redraw_images(&objects);
681
682 put_msg("Reading objects from \"%s\" ...Done", cut_buf_name);
683 new_c=copy_compound(cur_c);
684 /* add it to the depths so it is displayed */
685 add_compound_depth(new_c);
686 off_paste_x=new_c->secorner.x;
687 off_paste_y=new_c->secorner.y;
688 canvas_locmove_proc = init_move_paste_object;
689 canvas_ref_proc = move_paste_object;
690 canvas_leftbut_proc = place_object;
691 canvas_middlebut_proc = place_object_orig_posn;
692 canvas_rightbut_proc = cancel_paste;
693
694 /* set crosshair cursor */
695 set_cursor(null_cursor);
696
697 /* get the pointer position */
698 get_pointer_win_xy(&x, &y);
699 /* if pasting from the command button, reset coords so object is fully on canvas */
700 if (x<0)
701 x = 20;
702 if (y<0)
703 y = 20;
704 /* draw the first image */
705 init_move_paste_object(BACKX(x), BACKY(y));
706 }
707
708 static void
cancel_paste(void)709 cancel_paste(void)
710 {
711 reset_action_on();
712 canvas_leftbut_proc = null_proc;
713 canvas_middlebut_proc = null_proc;
714 canvas_rightbut_proc = null_proc;
715 canvas_locmove_proc = null_proc;
716 canvas_ref_proc = null_proc;
717 clear_mousefun();
718 set_mousefun("","","", "", "", "");
719 turn_off_current();
720 set_cursor(arrow_cursor);
721 cur_mode = F_NULL;
722 paste_draw(ERASE);
723 /* remove it from the depths */
724 remove_compound_depth(new_c);
725 }
726
727 static void
paste_draw(int paint_mode)728 paste_draw(int paint_mode)
729 {
730 if (paint_mode==ERASE)
731 redisplay_compound(new_c);
732 else
733 redisplay_objects(new_c);
734 }
735
736 static void
move_paste_object(int x,int y)737 move_paste_object(int x, int y)
738 {
739 int dx,dy;
740 void (*save_canvas_locmove_proc) ();
741 void (*save_canvas_ref_proc) ();
742
743 save_canvas_locmove_proc = canvas_locmove_proc;
744 save_canvas_ref_proc = canvas_ref_proc;
745 /* so we don't recurse infinitely */
746 canvas_locmove_proc = null_proc;
747 canvas_ref_proc = null_proc;
748 paste_draw(ERASE);
749 dx=x-cur_x;
750 dy=y-cur_y;
751 translate_compound(new_c,dx,dy);
752 cur_x=x;
753 cur_y=y;
754 paste_draw(PAINT);
755 canvas_locmove_proc = save_canvas_locmove_proc;
756 canvas_ref_proc = save_canvas_ref_proc;
757 }
758
759 static void
init_move_paste_object(int x,int y)760 init_move_paste_object(int x, int y)
761 {
762 cur_x=x;
763 cur_y=y;
764 translate_compound(new_c,x,y);
765
766 paste_draw(PAINT);
767 canvas_locmove_proc = move_paste_object;
768 canvas_ref_proc = move_paste_object;
769 }
770
771 /* button 1: paste object at current position of mouse */
772
773 static void
place_object(int x,int y,unsigned int shift)774 place_object(int x, int y, unsigned int shift)
775 {
776 clean_up();
777 add_compound(new_c);
778 set_modifiedflag();
779 redisplay_compound(new_c);
780 cancel_paste();
781 }
782
783 /* button 2: paste object in original location whence it came */
784
785 static void
place_object_orig_posn(int x,int y,unsigned int shift)786 place_object_orig_posn(int x, int y, unsigned int shift)
787 {
788 int dx,dy;
789
790 canvas_ref_proc = null_proc;
791 paste_draw(ERASE);
792 clean_up();
793 /* move back to original position */
794 dx = orig_paste_x-x;
795 dy = orig_paste_y-y;
796 translate_compound(new_c,dx,dy);
797 add_compound(new_c);
798 set_modifiedflag();
799 redisplay_compound(new_c);
800 cancel_paste();
801 }
802
803 void
new(Widget w,XtPointer closure,XtPointer call_data)804 new(Widget w, XtPointer closure, XtPointer call_data)
805 {
806 /* turn off Compose key LED */
807 setCompLED(0);
808
809 /* don't allow if in the middle of drawing/editing */
810 if (check_action_on())
811 return;
812 if (!emptyfigure()) {
813 /* check if user wants to save figure first */
814 if (query_save("The current figure is modified, do you want to save it first?")) {
815 delete_all();
816 strcpy(save_filename,cur_filename);
817 } else {
818 /* cancel new */
819 return;
820 }
821 }
822 set_action(F_LOAD);
823 update_cur_filename("");
824 put_msg("Immediate Undo will restore the figure");
825 redisplay_canvas();
826 }
827
828 void
delete_all_cmd(Widget w,int closure,int call_data)829 delete_all_cmd(Widget w, int closure, int call_data)
830 {
831 /* turn off Compose key LED */
832 setCompLED(0);
833
834 /* don't allow if in the middle of drawing/editing */
835 if (check_action_on())
836 return;
837 if (emptyfigure()) {
838 put_msg("Figure already empty");
839 return;
840 }
841 delete_all();
842 put_msg("Immediate Undo will restore the figure");
843 redisplay_canvas();
844 }
845
846 /* Toggle canvas orientation from Portrait to Landscape or vice versa */
847
848 void
change_orient()849 change_orient()
850 {
851 Dimension formw, formh;
852 int dx, dy;
853
854 /* turn off Compose key LED */
855 setCompLED(0);
856
857 /* don't change orientation if in the middle of drawing/editing */
858 if (check_action_on())
859 return;
860
861 /* don't resize anything if the user specified xfig's geometry */
862 if (!geomspec) {
863 /* get the current size of the canvas */
864 FirstArg(XtNwidth, &formw);
865 NextArg(XtNheight, &formh);
866 GetValues(canvas_sw);
867
868 if (appres.landscape) {
869 /* save current size for switching back */
870 CANVAS_WD_LAND = CANVAS_WD;
871 CANVAS_HT_LAND = CANVAS_HT;
872 dx = CANVAS_WD_PORT - formw;
873 dy = CANVAS_HT_PORT - formh;
874 TOOL_WD += dx;
875 TOOL_HT += dy;
876 XtResizeWidget(tool, TOOL_WD, TOOL_HT, 0);
877 resize_all((int) (CANVAS_WD_PORT), (int) (CANVAS_HT_PORT));
878 appres.landscape = False;
879 } else {
880 /* save current size for switching back */
881 CANVAS_WD_PORT = CANVAS_WD;
882 CANVAS_HT_PORT = CANVAS_HT;
883 dx = CANVAS_WD_LAND - formw;
884 dy = CANVAS_HT_LAND - formh;
885 TOOL_WD += dx;
886 TOOL_HT += dy;
887 XtResizeWidget(tool, TOOL_WD, TOOL_HT, 0);
888 resize_all((int) (CANVAS_WD_LAND), (int) (CANVAS_HT_LAND));
889 appres.landscape = True;
890 }
891 } else {
892 /* just toggle the flag */
893 appres.landscape = !appres.landscape;
894 }
895 /* change the printer and export orientation labels */
896 FirstArg(XtNlabel, orient_items[appres.landscape]);
897 if (print_orient_panel)
898 SetValues(print_orient_panel);
899 if (export_orient_panel)
900 SetValues(export_orient_panel);
901
902 /* draw the new orientation of the page border */
903 clear_canvas();
904 redisplay_canvas();
905
906 /* the figure has been modified */
907 set_modifiedflag();
908 #ifdef I18N
909 if (xim_ic != NULL)
910 xim_set_ic_geometry(xim_ic, CANVAS_WD, CANVAS_HT);
911 #endif /* I18N */
912 }
913
914 /*
915 * Popup a global settings panel with:
916 *
917 * Widget Type Description
918 * ----------- -----------------------------------------
919 * checkbutton mouse tracking (ruler arrows)
920 * checkbutton show page borders in red
921 * checkbutton show balloons
922 * entry balloon delay
923 * checkbutton show lengths of lines
924 * checkbutton show point numbers above polyline points
925 * int entry max image colors
926 * str entry image editor
927 * str entry spelling checker
928 * str entry html browser
929 * str entry pdf viewer
930 *
931 */
932
933 typedef struct _global {
934 Boolean tracking; /* show mouse tracking in rulers */
935 Boolean autorefresh; /* autorefresh mode */
936 Boolean show_pageborder; /* show page borders in red on canvas */
937 Boolean showdepthmanager; /* show depth manager panel */
938 Boolean showballoons; /* show popup messages */
939 Boolean showlengths; /* length/width lines */
940 Boolean shownums; /* print point numbers */
941 Boolean allownegcoords; /* allow negative x/y coordinates for panning */
942 Boolean showaxislines; /* draw lines through 0,0 */
943 } globalStruct;
944
945 globalStruct global;
946
947 void
show_global_settings(Widget w)948 show_global_settings(Widget w)
949 {
950 /* turn off Compose key LED */
951 setCompLED(0);
952
953 global.tracking = appres.tracking;
954 global.autorefresh = appres.autorefresh;
955 global.show_pageborder = appres.show_pageborder;
956 global.showdepthmanager = appres.showdepthmanager;
957 global.showballoons = appres.showballoons;
958 global.showlengths = appres.showlengths;
959 global.shownums = appres.shownums;
960 global.allownegcoords = appres.allownegcoords;
961 global.showaxislines = appres.showaxislines;
962
963 popup_global_panel(w);
964 }
965
966 static Widget show_bal, delay_label;
967
968 static void
popup_global_panel(Widget w)969 popup_global_panel(Widget w)
970 {
971 Dimension ht;
972
973 if (global_popup == 0) {
974 create_global_panel(w);
975 XtPopup(global_popup, XtGrabNonexclusive);
976 (void) XSetWMProtocols(tool_d, XtWindow(global_popup), &wm_delete_window, 1);
977 XtUnmanageChild(delay_label);
978 /* make the balloon delay label as tall as the checkbutton */
979 FirstArg(XtNheight, &ht);
980 GetValues(show_bal);
981 FirstArg(XtNheight, ht);
982 SetValues(delay_label);
983 /* remanage the label */
984 XtManageChild(delay_label);
985 return;
986 }
987 XtPopup(global_popup, XtGrabNonexclusive);
988 }
989
create_global_panel(Widget w)990 void create_global_panel(Widget w)
991 {
992 DeclareArgs(10);
993 Widget beside, below, n_freehand, freehand, n_recent, recent;
994 Widget delay_form, delay_spinner;
995 Position xposn, yposn;
996 char buf[80];
997
998 XtTranslateCoords(tool, (Position) 0, (Position) 0, &xposn, &yposn);
999
1000 FirstArg(XtNtitle, "Xfig: Global Settings");
1001 NextArg(XtNx, xposn+50);
1002 NextArg(XtNy, yposn+50);
1003 NextArg(XtNcolormap, tool_cm);
1004 global_popup = XtCreatePopupShell("global_settings",
1005 transientShellWidgetClass,
1006 tool, Args, ArgCount);
1007 XtOverrideTranslations(global_popup,
1008 XtParseTranslationTable(global_translations));
1009 XtAppAddActions(tool_app, global_actions, XtNumber(global_actions));
1010
1011 global_panel = XtCreateManagedWidget("global_panel", formWidgetClass,
1012 global_popup, NULL, ZERO);
1013
1014 below = CreateCheckbutton("Autorefresh figure ", "auto_refresh",
1015 global_panel, NULL, NULL, MANAGE, LARGE_CHK,
1016 &global.autorefresh, 0,0);
1017 below = CreateCheckbutton("Track mouse in rulers ", "track_mouse",
1018 global_panel, NULL, NULL, MANAGE, LARGE_CHK,
1019 &global.tracking, 0,0);
1020 below = CreateCheckbutton("Show page borders ", "page_borders",
1021 global_panel, below, NULL, MANAGE, LARGE_CHK,
1022 &global.show_pageborder, 0,0);
1023 below = CreateCheckbutton("Show depth manager ", "depth_manager",
1024 global_panel, below, NULL, MANAGE, LARGE_CHK,
1025 &global.showdepthmanager, 0,0);
1026 show_bal = CreateCheckbutton("Show info balloons ", "show_balloons",
1027 global_panel, below, NULL, MANAGE, LARGE_CHK,
1028 &global.showballoons,0,0);
1029
1030 /* put the delay label and spinner in a form to group them */
1031 FirstArg(XtNdefaultDistance, 1);
1032 NextArg(XtNfromHoriz, show_bal);
1033 NextArg(XtNfromVert, below);
1034 NextArg(XtNborderWidth, 0);
1035 NextArg(XtNtop, XtChainTop);
1036 NextArg(XtNbottom, XtChainTop);
1037 NextArg(XtNleft, XtChainLeft);
1038 NextArg(XtNright, XtChainLeft);
1039 delay_form = XtCreateManagedWidget("bal_del_form", formWidgetClass, global_panel,
1040 Args, ArgCount);
1041
1042 FirstArg(XtNlabel,"Delay (ms):");
1043 NextArg(XtNborderWidth, 0);
1044 NextArg(XtNtop, XtChainTop);
1045 NextArg(XtNbottom, XtChainTop);
1046 NextArg(XtNleft, XtChainLeft);
1047 NextArg(XtNright, XtChainLeft);
1048 delay_label = beside = XtCreateManagedWidget("balloon_delay", labelWidgetClass,
1049 delay_form, Args, ArgCount);
1050 sprintf(buf, "%d", appres.balloon_delay);
1051 delay_spinner = MakeIntSpinnerEntry(delay_form, &bal_delay, "balloon_delay",
1052 NULL, beside, (XtCallbackProc) NULL, buf, 0, 100000, 1, 40);
1053 FirstArg(XtNtop, XtChainTop);
1054 NextArg(XtNbottom, XtChainTop);
1055 NextArg(XtNleft, XtChainLeft);
1056 NextArg(XtNright, XtChainLeft);
1057 SetValues(delay_spinner);
1058
1059 below = CreateCheckbutton("Show line lengths ", "show_lengths",
1060 global_panel, show_bal, NULL, MANAGE, LARGE_CHK,
1061 &global.showlengths, 0, 0);
1062 below = CreateCheckbutton("Show vertex numbers ", "show_vertexnums",
1063 global_panel, below, NULL, MANAGE, LARGE_CHK,
1064 &global.shownums, 0, 0);
1065 below = CreateCheckbutton("Allow negative coords ", "show_vertexnums",
1066 global_panel, below, NULL, MANAGE, LARGE_CHK,
1067 &global.allownegcoords, 0, 0);
1068 below = CreateCheckbutton("Draw axis lines ", "showaxislines",
1069 global_panel, below, NULL, MANAGE, LARGE_CHK,
1070 &global.showaxislines, 0, 0);
1071
1072 FirstArg(XtNlabel, "Freehand drawing resolution");
1073 NextArg(XtNfromVert, below);
1074 NextArg(XtNborderWidth, 0);
1075 NextArg(XtNtop, XtChainTop);
1076 NextArg(XtNbottom, XtChainTop);
1077 NextArg(XtNleft, XtChainLeft);
1078 NextArg(XtNright, XtChainLeft);
1079 freehand = XtCreateManagedWidget("freehand_resolution", labelWidgetClass,
1080 global_panel, Args, ArgCount);
1081 sprintf(buf,"%d",appres.freehand_resolution);
1082 n_freehand = MakeIntSpinnerEntry(global_panel, &n_freehand_resolution, "freehand_res",
1083 below, freehand, (XtCallbackProc) NULL, buf, 0, 100000, 10, 26);
1084 below = freehand;
1085
1086 FirstArg(XtNlabel, "Recently used files ");
1087 NextArg(XtNfromVert, below);
1088 NextArg(XtNborderWidth, 0);
1089 NextArg(XtNtop, XtChainTop);
1090 NextArg(XtNbottom, XtChainTop);
1091 NextArg(XtNleft, XtChainLeft);
1092 NextArg(XtNright, XtChainLeft);
1093 recent = XtCreateManagedWidget("recent_file_entries", labelWidgetClass,
1094 global_panel, Args, ArgCount);
1095 sprintf(buf,"%d",max_recent_files);
1096 n_recent = MakeIntSpinnerEntry(global_panel, &n_recent_files, "max_recent_files",
1097 below, recent, (XtCallbackProc) NULL, buf, 0, MAX_RECENT_FILES, 1, 26);
1098 below = recent;
1099
1100 sprintf(buf,"%d",appres.max_image_colors);
1101 below = CreateLabelledAscii(&max_colors, "Maximum image colors ", "max_image_colors",
1102 global_panel, below, buf, 40);
1103 below = CreateLabelledAscii(&image_ed, "Image editor ", "image_editor",
1104 global_panel, below, cur_image_editor, 340);
1105 below = CreateLabelledAscii(&spell_chk, "Spell checker", "spell_check",
1106 global_panel, below, cur_spellchk, 340);
1107 below = CreateLabelledAscii(&browser, "HTML Browser ", "html_browser",
1108 global_panel, below, cur_browser, 340);
1109 below = CreateLabelledAscii(&pdfview, "PDF Viewer ", "pdf_viewer",
1110 global_panel, below, cur_pdfviewer, 340);
1111
1112 FirstArg(XtNlabel, "Cancel");
1113 NextArg(XtNfromVert, below);
1114 NextArg(XtNvertDistance, 15);
1115 NextArg(XtNheight, 25);
1116 NextArg(XtNborderWidth, INTERNAL_BW);
1117 NextArg(XtNtop, XtChainBottom);
1118 NextArg(XtNbottom, XtChainBottom);
1119 NextArg(XtNleft, XtChainLeft);
1120 NextArg(XtNright, XtChainLeft);
1121 beside = XtCreateManagedWidget("cancel", commandWidgetClass,
1122 global_panel, Args, ArgCount);
1123 XtAddEventHandler(beside, ButtonReleaseMask, False,
1124 (XtEventHandler) global_panel_cancel, (XtPointer) NULL);
1125
1126 FirstArg(XtNlabel, " Ok ");
1127 NextArg(XtNfromVert, below);
1128 NextArg(XtNvertDistance, 15);
1129 NextArg(XtNfromHoriz, beside);
1130 NextArg(XtNheight, 25);
1131 NextArg(XtNborderWidth, INTERNAL_BW);
1132 NextArg(XtNtop, XtChainBottom);
1133 NextArg(XtNbottom, XtChainBottom);
1134 NextArg(XtNleft, XtChainLeft);
1135 NextArg(XtNright, XtChainLeft);
1136 below = XtCreateManagedWidget("global_ok", commandWidgetClass,
1137 global_panel, Args, ArgCount);
1138 XtAddEventHandler(below, ButtonReleaseMask, False,
1139 (XtEventHandler) global_panel_done, (XtPointer) NULL);
1140
1141 /* install accelerators for the following functions */
1142 XtInstallAccelerators(global_panel, below);
1143
1144 }
1145
1146 /* make a label and asciiText widget to its right */
1147
1148 Widget
CreateLabelledAscii(Widget * text_widg,char * label,char * widg_name,Widget parent,Widget below,char * str,int width)1149 CreateLabelledAscii(Widget *text_widg, char *label, char *widg_name, Widget parent, Widget below, char *str, int width)
1150 {
1151 DeclareArgs(10);
1152 Widget lab_widg;
1153
1154 FirstArg(XtNlabel, label);
1155 NextArg(XtNfromVert, below);
1156 NextArg(XtNjustify, XtJustifyLeft);
1157 NextArg(XtNborderWidth, 0);
1158 NextArg(XtNtop, XtChainTop);
1159 NextArg(XtNbottom, XtChainTop);
1160 NextArg(XtNleft, XtChainLeft);
1161 NextArg(XtNright, XtChainLeft);
1162 lab_widg = XtCreateManagedWidget("label", labelWidgetClass,
1163 parent, Args, ArgCount);
1164
1165 FirstArg(XtNstring, str);
1166 NextArg(XtNinsertPosition, strlen(str));
1167 NextArg(XtNeditType, XawtextEdit);
1168 NextArg(XtNfromVert, below);
1169 NextArg(XtNfromHoriz, lab_widg);
1170 NextArg(XtNwidth, width);
1171 NextArg(XtNtop, XtChainTop);
1172 NextArg(XtNbottom, XtChainTop);
1173 NextArg(XtNleft, XtChainLeft);
1174 NextArg(XtNright, XtChainLeft);
1175 *text_widg = XtCreateManagedWidget(widg_name, asciiTextWidgetClass,
1176 parent, Args, ArgCount);
1177 /* install "standard" translations */
1178 XtOverrideTranslations(*text_widg,
1179 XtParseTranslationTable(text_translations));
1180 return lab_widg;
1181 }
1182
1183 static void
global_panel_done(Widget w,XButtonEvent * ev)1184 global_panel_done(Widget w, XButtonEvent *ev)
1185 {
1186 Boolean asp, gsp, adz, gdz;
1187 int temp;
1188 char buf[80];
1189
1190 /* copy all new values back to masters */
1191 appres.tracking = global.tracking;
1192 if (appres.autorefresh && !global.autorefresh)
1193 cancel_autorefresh();
1194 else if (!appres.autorefresh && global.autorefresh)
1195 set_autorefresh();
1196 appres.autorefresh = global.autorefresh;
1197 asp = appres.show_pageborder;
1198 gsp = global.show_pageborder;
1199 adz = appres.showaxislines;
1200 gdz = global.showaxislines;
1201 /* update settings */
1202 appres.show_pageborder = gsp;
1203 appres.showaxislines = gdz;
1204
1205 /* if show_pageborder or showaxislines WAS on and is now off, redraw */
1206 if ((asp && !gsp) || (adz && !gdz)) {
1207 /* was on, turn off */
1208 clear_canvas();
1209 redisplay_canvas();
1210 } else if ((!asp && gsp) || (!adz && gdz)) {
1211 /* if show_pageborder or showaxislines WAS off and is now on, draw them */
1212 /* was off, turn on */
1213 redisplay_pageborder();
1214 }
1215 /* see if user toggled the depth manager setting */
1216 if (appres.showdepthmanager != global.showdepthmanager)
1217 toggle_show_depths();
1218 appres.showdepthmanager = global.showdepthmanager;
1219 appres.showballoons = global.showballoons;
1220 temp = atoi(panel_get_value(bal_delay));
1221 if (temp < 0) {
1222 temp = 0;
1223 panel_set_int(bal_delay, temp);
1224 }
1225 appres.balloon_delay = temp;
1226 appres.showlengths = global.showlengths;
1227 appres.shownums = global.shownums;
1228 appres.allownegcoords = global.allownegcoords;
1229 appres.showaxislines = global.showaxislines;
1230 /* go to 0,0 if user turned off neg coords and we're in the negative */
1231 if (!appres.allownegcoords)
1232 if (zoomxoff < 0 || zoomyoff < 0)
1233 pan_origin();
1234
1235 /* get the freehand resolution spinner value */
1236 temp = atoi(panel_get_value(n_freehand_resolution));
1237 if (temp < 0) {
1238 temp = 0;
1239 panel_set_int(n_freehand_resolution, temp);
1240 }
1241 appres.freehand_resolution = temp;
1242
1243 /* get the number of recent files spinner value */
1244 temp = atoi(panel_get_value(n_recent_files));
1245 if (temp > MAX_RECENT_FILES)
1246 temp = MAX_RECENT_FILES;
1247 else if (temp < 0)
1248 temp = 0;
1249 panel_set_int(n_recent_files, temp);
1250 /* if number of recent files has changed, update it in the .xfigrc file */
1251 if (max_recent_files != temp) {
1252 Widget menu, entry;
1253 int i;
1254 char id[10];
1255
1256 menu = main_menus[0].menuwidget;
1257 max_recent_files = temp;
1258 num_recent_files = min2(num_recent_files, max_recent_files);
1259 sprintf(buf,"%d",max_recent_files);
1260 update_xfigrc("max_recent_files", buf);
1261 for (i=0; i<MAX_RECENT_FILES; i++) {
1262 sprintf(id, "%1d", i + 1);
1263 entry = XtNameToWidget(menu, id);
1264 if (i < max_recent_files) {
1265 XtManageChild(entry);
1266 /* if new entries created, clear them */
1267 if (i >= num_recent_files) {
1268 FirstArg(XtNlabel, id);
1269 NextArg(XtNsensitive, False);
1270 SetValues(entry);
1271 }
1272 } else {
1273 XtUnmanageChild(entry);
1274 }
1275 }
1276 /* remanage menu so it resizes */
1277 XtUnmanageChild(main_menus[0].widget);
1278 XtManageChild(main_menus[0].widget);
1279 }
1280 temp = atoi(panel_get_value(max_colors));
1281 if (temp <= 0) {
1282 temp = 10;
1283 panel_set_int(max_colors, temp);
1284 }
1285 appres.max_image_colors = temp;
1286 strcpy(cur_image_editor, panel_get_value(image_ed));
1287 strcpy(cur_spellchk, panel_get_value(spell_chk));
1288 strcpy(cur_browser, panel_get_value(browser));
1289 strcpy(cur_pdfviewer, panel_get_value(pdfview));
1290
1291 XtPopdown(global_popup);
1292
1293 refresh_view_menu();
1294 }
1295
1296 static void
global_panel_cancel(Widget w,XButtonEvent * ev)1297 global_panel_cancel(Widget w, XButtonEvent *ev)
1298 {
1299 XtDestroyWidget(global_popup);
1300 global_popup = (Widget) 0;
1301 }
1302
1303 #ifndef XAW3D1_5E
1304 /* come here when the mouse passes over the filename window */
1305
1306 static Widget filename_balloon_popup = (Widget) 0;
1307
1308 static XtIntervalId fballoon_id = (XtIntervalId) 0;
1309 static Widget fballoon_w;
1310
1311 static void file_balloon(void);
1312
1313 static void
filename_balloon_trigger(Widget widget,XtPointer closure,XEvent * event,Boolean * continue_to_dispatch)1314 filename_balloon_trigger(Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch)
1315 {
1316 if (!appres.showballoons)
1317 return;
1318 fballoon_w = widget;
1319 fballoon_id = XtAppAddTimeOut(tool_app, appres.balloon_delay,
1320 (XtTimerCallbackProc) file_balloon, (XtPointer) NULL);
1321 }
1322
1323 static void
file_balloon(void)1324 file_balloon(void)
1325 {
1326 Position x, y;
1327 Dimension w, h;
1328 Widget box, balloons_label;
1329
1330 /* get width and height of this window */
1331 FirstArg(XtNwidth, &w);
1332 NextArg(XtNheight, &h);
1333 GetValues(fballoon_w);
1334 /* find center and lower edge */
1335 XtTranslateCoords(fballoon_w, w/2, h+2, &x, &y);
1336
1337 /* put popup there */
1338 FirstArg(XtNx, x);
1339 NextArg(XtNy, y);
1340 filename_balloon_popup = XtCreatePopupShell("filename_balloon_popup",
1341 overrideShellWidgetClass, tool, Args, ArgCount);
1342 FirstArg(XtNborderWidth, 0);
1343 NextArg(XtNhSpace, 0);
1344 NextArg(XtNvSpace, 0);
1345 box = XtCreateManagedWidget("box", boxWidgetClass,
1346 filename_balloon_popup, Args, ArgCount);
1347 FirstArg(XtNborderWidth, 0);
1348 NextArg(XtNlabel, "Current filename");
1349 balloons_label = XtCreateManagedWidget("label", labelWidgetClass,
1350 box, Args, ArgCount);
1351 XtPopup(filename_balloon_popup,XtGrabNone);
1352 }
1353
1354 /* come here when the mouse leaves the filename window */
1355
1356 static void
filename_unballoon(Widget widget,XtPointer closure,XEvent * event,Boolean * continue_to_dispatch)1357 filename_unballoon(Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch)
1358 {
1359 if (fballoon_id)
1360 XtRemoveTimeOut(fballoon_id);
1361 fballoon_id = (XtIntervalId) 0;
1362 if (filename_balloon_popup != (Widget) 0) {
1363 XtDestroyWidget(filename_balloon_popup);
1364 filename_balloon_popup = (Widget) 0;
1365 }
1366 }
1367 #endif /* XAW3D1_5E */
1368
1369 /*
1370 * Update the current filename in the name_panel widget, and the xfig icon.
1371 * Also update the current filename in the File popup (if it has been created).
1372 */
1373
update_cur_filename(char * newname)1374 void update_cur_filename(char *newname)
1375 {
1376 if (cur_filename!=newname) strcpy(cur_filename,newname);
1377 /* store the new filename in the name_panel widget */
1378 FirstArg(XtNlabel, newname);
1379 SetValues(name_panel);
1380 if (cfile_text) /* if the name widget in the file popup exists... */
1381 SetValues(cfile_text);
1382
1383 /* put the filename being edited in the icon */
1384 XSetIconName(tool_d, tool_w, xf_basename(cur_filename));
1385
1386 update_def_filename(); /* update default filename in export panel */
1387 update_wm_title(cur_filename); /* and window title bar */
1388 }
1389
1390 static void
popup_menu(Widget w,XEvent * event,String * params,Cardinal * nparams)1391 popup_menu(Widget w, XEvent *event, String *params, Cardinal *nparams)
1392 {
1393 int which;
1394
1395 which = locate_menu(params, nparams);
1396 if (which < 0)
1397 return;
1398 XtPopupSpringLoaded(main_menus[which].menuwidget);
1399 }
1400
1401 static void
place_menu(Widget w,XEvent * event,String * params,Cardinal * nparams)1402 place_menu(Widget w, XEvent *event, String *params, Cardinal *nparams)
1403 {
1404 Position x, y;
1405 Dimension height;
1406 int which;
1407
1408 which = locate_menu(params, nparams);
1409 if (which < 0)
1410 return;
1411 /* get the height of the menu button on the command panel */
1412 FirstArg(XtNheight, &height);
1413 GetValues(main_menus[which].widget);
1414 XtTranslateCoords(main_menus[which].widget, (Position) 0, height+4, &x, &y);
1415 /* position the popup menu just under the button */
1416 FirstArg(XtNx, x);
1417 NextArg(XtNy, y);
1418 SetValues(main_menus[which].menuwidget);
1419 }
1420
1421 int
locate_menu(String * params,Cardinal * nparams)1422 locate_menu(String *params, Cardinal *nparams)
1423 {
1424 int which;
1425
1426 if (*nparams < 1)
1427 return -1;
1428
1429 /* find which menu the user wants */
1430 for (which=0; which<NUM_CMD_MENUS; which++)
1431 if (strcmp(params[0],main_menus[which].menu_name)==0)
1432 break;
1433 if (which >= NUM_CMD_MENUS)
1434 return -1;
1435 return which;
1436 }
1437
1438 /* callback to load a recently used file (from the File menu) */
1439
1440 static void
load_recent_file(Widget w,XtPointer client_data,XtPointer call_data)1441 load_recent_file(Widget w, XtPointer client_data, XtPointer call_data)
1442 {
1443 int which = atoi((char *) client_data);
1444 char *filename;
1445 char dir[PATH_MAX], *c;
1446
1447 filename = recent_files[which-1].name+2; /* point past number, space */
1448 /* if file panel is open, popdown it */
1449 if (file_up)
1450 file_panel_dismiss();
1451
1452 /* check if modified, unsaved figure on canvas */
1453 if (!query_save(quit_msg))
1454 return;
1455 /* go to the directory where the figure is in case it has imported pictures */
1456 strcpy(dir,filename);
1457 if (c=strrchr(dir,'/')) {
1458 *c = '\0'; /* terminate dir at last '/' */
1459 change_directory(dir);
1460 strcpy(cur_file_dir, dir); /* update current directory */
1461 strcpy(cur_export_dir, dir); /* and export current directory */
1462 }
1463 /* load the file */
1464 (void) load_file(filename, 0, 0);
1465 }
1466
1467 /* this one is called by the accelerator (File) 1/2/3... */
1468
1469 void
acc_load_recent_file(Widget w,XEvent * event,String * params,Cardinal * nparams)1470 acc_load_recent_file(Widget w, XEvent *event, String *params, Cardinal *nparams)
1471 {
1472 /* get file number from passed arg */
1473 int which = atoi(*params);
1474
1475 /* turn off Compose key LED */
1476 setCompLED(0);
1477
1478 /* see if that file exists in the list */
1479 if (which > num_recent_files)
1480 return;
1481
1482 /* now load by calling the callback */
1483 load_recent_file(w, (XtPointer) *params, (XtPointer) NULL);
1484 }
1485
1486 static Widget charmap_font_label;
1487
1488 /* refresh character map (e.g. when user changes font) by changing the font label and font in the buttons */
1489
1490 void
refresh_character_panel(void)1491 refresh_character_panel(void)
1492 {
1493 int nchildren, i;
1494 char fname[80];
1495 XFontStruct *font;
1496 WidgetList children;
1497
1498 if (!character_map_popup)
1499 return;
1500 sprintf(fname, "%s font characters:",
1501 using_ps? ps_fontinfo[work_font+1].name: latex_fontinfo[work_font+1].name);
1502 /* change font name label */
1503 FirstArg(XtNlabel, fname);
1504 SetValues(charmap_font_label);
1505
1506 /* get the buttons (children) of the form */
1507 FirstArg(XtNnumChildren, &nchildren);
1508 NextArg(XtNchildren, &children);
1509 GetValues(character_map_panel);
1510 /* get the current font */
1511 font = lookfont(work_font, 12);
1512 FirstArg(XtNfont, font);
1513 /* loop over all but the last button, which is the close button */
1514 for (i=0; i<nchildren-1; i++) {
1515 if (XtClass(*children) == commandWidgetClass)
1516 SetValues(*children);
1517 children++;
1518 }
1519 }
1520
1521 static void
character_panel_close(void)1522 character_panel_close(void)
1523 {
1524 XtDestroyWidget(character_map_popup);
1525 character_map_popup = (Widget) 0;
1526 }
1527
1528 /*
1529 * popup a window showing the symbol character map, each char in a
1530 * different button widget so the user paste directly into text
1531 * Activated from the View/Character Map menu
1532 */
1533
1534 #define LASTCHAR 255
1535
1536 void
popup_character_map(void)1537 popup_character_map(void)
1538 {
1539 Widget beside, below;
1540 XFontStruct *font;
1541 intptr_t i;
1542 int vertDist;
1543 char fname[80], chr[2];
1544 static Boolean actions_added=False;
1545
1546 /* only allow one copy */
1547 if (character_map_popup)
1548 return;
1549
1550 FirstArg(XtNtitle, "Xfig: Character Map");
1551 NextArg(XtNcolormap, tool_cm);
1552 character_map_popup = XtCreatePopupShell("character_map_popup",
1553 transientShellWidgetClass,
1554 tool, Args, ArgCount);
1555 XtOverrideTranslations(character_map_popup,
1556 XtParseTranslationTable(charmap_translations));
1557 if (!actions_added) {
1558 XtAppAddActions(tool_app, charmap_actions, XtNumber(charmap_actions));
1559 actions_added = True;
1560 }
1561
1562 character_map_panel = XtCreateManagedWidget("character_map_panel", formWidgetClass,
1563 character_map_popup, NULL, ZERO);
1564
1565 sprintf(fname, "%s font characters:",
1566 using_ps? ps_fontinfo[work_font+1].name: latex_fontinfo[work_font+1].name);
1567 FirstArg(XtNlabel, fname);
1568 NextArg(XtNborderWidth, 0);
1569 charmap_font_label = below = XtCreateManagedWidget("charmap_font_label", labelWidgetClass,
1570 character_map_panel, Args, ArgCount);
1571 /* get the font */
1572 font = lookfont(work_font, 12);
1573 beside = (Widget) 0;
1574 vertDist = 3;
1575 chr[1] = '\0';
1576 for (i=32; i<=LASTCHAR; i++) {
1577 chr[0] = (char) i;
1578 FirstArg(XtNlabel, chr);
1579 NextArg(XtNfont, font);
1580 NextArg(XtNwidth, 20);
1581 NextArg(XtNheight, 20);
1582 NextArg(XtNfromVert, below);
1583 NextArg(XtNvertDistance, vertDist);
1584 NextArg(XtNfromHoriz, beside);
1585 beside = XtCreateManagedWidget("char_button", commandWidgetClass,
1586 character_map_panel, Args, ArgCount);
1587 /* add callback to paste character into current text */
1588 XtAddCallback(beside, XtNcallback, paste_char, (XtPointer) i);
1589 /* skip empty entries and 127 (delete) */
1590 if (i==126) {
1591 below = beside;
1592 beside = (Widget) 0;
1593 i += 33;
1594 /* and make a gap */
1595 vertDist = 10;
1596 } else if ((i+1)%16 == 0 && i != LASTCHAR) {
1597 below = beside;
1598 beside = (Widget) 0;
1599 vertDist = 3;
1600 }
1601 }
1602 /* close button */
1603 FirstArg(XtNlabel, "Close");
1604 NextArg(XtNfromVert, beside);
1605 NextArg(XtNvertDistance, 15);
1606 NextArg(XtNheight, 25);
1607 NextArg(XtNborderWidth, INTERNAL_BW);
1608 close_but = XtCreateManagedWidget("close", commandWidgetClass,
1609 character_map_panel, Args, ArgCount);
1610 XtAddEventHandler(close_but, ButtonReleaseMask, False,
1611 (XtEventHandler) character_panel_close, (XtPointer) NULL);
1612 XtPopup(character_map_popup, XtGrabNone);
1613 (void) XSetWMProtocols(tool_d, XtWindow(character_map_popup), &wm_delete_window, 1);
1614 }
1615
1616 static void
paste_char(Widget w,XtPointer client_data,XtPointer call_data)1617 paste_char(Widget w, XtPointer client_data, XtPointer call_data)
1618 {
1619 union {
1620 XtPointer ptr;
1621 unsigned char val;
1622 } ptr_val = {client_data};
1623
1624 unsigned char chr = ptr_val.val;
1625
1626 /* only allow during text input */
1627 if (canvas_kbd_proc != (void (*)())char_handler)
1628 return;
1629 char_handler((XKeyEvent *) 0, chr, (KeySym) 0);
1630 }
1631
1632 /* add or remove a checkmark to a menu entry to show that it
1633 is selected or unselected respectively */
1634
1635 static void
refresh_view_menu_item(char * name,Boolean state)1636 refresh_view_menu_item(char *name, Boolean state)
1637 {
1638 Widget menu, w;
1639 Pixmap bitmap;
1640 DeclareStaticArgs(10);
1641
1642 menu = XtNameToWidget(tool, "*viewmenu");
1643 if (menu == NULL) {
1644 fprintf(stderr, "xfig: refresh_view_menu: can't find *viewmenu\n");
1645 } else {
1646 w = XtNameToWidget(menu, name);
1647 if (w == NULL) {
1648 fprintf(stderr, "xfig: can't find \"viewmenu%s\"\n", name);
1649 } else {
1650 if (state) {
1651 if (menu_item_bitmap == None)
1652 menu_item_bitmap = XCreateBitmapFromData(XtDisplay(menu),
1653 RootWindowOfScreen(XtScreen(menu)),
1654 (char *)menu_item_bitmap_bits,
1655 menu_item_bitmap_width,
1656 menu_item_bitmap_height);
1657 bitmap = menu_item_bitmap;
1658 } else {
1659 bitmap = None;
1660 }
1661 FirstArg(XtNleftBitmap, bitmap);
1662 SetValues(w);
1663 }
1664 }
1665 }
1666
1667 /* update the menu entries with or without an asterisk */
1668
1669 void
refresh_view_menu(void)1670 refresh_view_menu(void)
1671 {
1672 #ifdef XAW3D1_5E
1673 int i;
1674 register main_menu_info *menu;
1675 #endif /* XAW3D1_5E */
1676 /* turn off Compose key LED */
1677 setCompLED(0);
1678
1679 refresh_view_menu_item(PAGE_BRD_MSG, appres.show_pageborder);
1680 refresh_view_menu_item(DPTH_MGR_MSG, appres.showdepthmanager);
1681 refresh_view_menu_item(INFO_BAL_MSG, appres.showballoons);
1682 refresh_view_menu_item(LINE_LEN_MSG, appres.showlengths);
1683 refresh_view_menu_item(VRTX_NUM_MSG, appres.shownums);
1684 refresh_view_menu_item(AUTO_RFS_MSG, appres.autorefresh);
1685
1686 #ifdef XAW3D1_5E
1687 if (appres.showballoons) {
1688 XawTipEnable(name_panel, "Current filename");
1689 for (i = 0; i < NUM_CMD_MENUS; ++i) {
1690 menu = &main_menus[i];
1691 XawTipEnable(menu->widget, menu->hint);
1692 }
1693 } else {
1694 XawTipDisable(name_panel);
1695 for (i = 0; i < NUM_CMD_MENUS; ++i) {
1696 menu = &main_menus[i];
1697 XawTipDisable(menu->widget);
1698 }
1699 }
1700 update_indpanel(cur_indmask);
1701 update_modepanel();
1702 update_layerpanel();
1703 update_mousepanel();
1704 update_rulerpanel();
1705 #endif /* XAW3D1_5E */
1706 }
1707