Continuing to track down the issue with a crash on startup on
[xcircuit.git] / help.c
blobbc1d027f2ddc4940d697edf3c86dd30556635677
1 /*----------------------------------------------------------------------*/
2 /* Copyright (c) 2002 Tim Edwards, Johns Hopkins University */
3 /*----------------------------------------------------------------------*/
5 /*----------------------------------------------------------------------*/
6 /* Spun off from xcircuit.c 10/4/98 */
7 /* Functionality will not be expanded in the Xt version. All new */
8 /* capabilities will be developed in the TCL version of help. */
9 /*----------------------------------------------------------------------*/
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
15 #ifndef XC_WIN32
16 #include <X11/Intrinsic.h>
17 #include <X11/StringDefs.h>
18 #include <X11/Shell.h>
19 #endif
21 #ifdef TCL_WRAPPER
22 #include <tk.h>
23 #else
24 #ifndef XC_WIN32
25 #include "Xw/Xw.h"
26 #include "Xw/Form.h"
27 #include "Xw/WorkSpace.h"
28 #include "Xw/MenuBtn.h"
29 #endif
30 #endif
32 /*----------------------------------------------------------------------*/
33 /* Local includes */
34 /*----------------------------------------------------------------------*/
36 #include "colordefs.h"
37 #include "xcircuit.h"
38 #include "menudep.h"
40 /*----------------------------------------------------------------------*/
41 /* Function prototype declarations */
42 /*----------------------------------------------------------------------*/
43 #include "prototypes.h"
45 /*----------------------------------------------------------------------*/
46 /* Global Variable definitions */
47 /*----------------------------------------------------------------------*/
49 #ifdef TCL_WRAPPER
50 extern Tcl_Interp *xcinterp;
51 #endif
53 #ifndef TCL_WRAPPER
55 extern Display *dpy;
56 extern GC hgc;
57 extern XCWindowData *areawin;
58 extern ApplicationData appdata;
59 extern xcWidget top;
60 extern colorindex *colorlist;
61 extern short popups;
62 extern xcWidget menuwidgets[];
63 extern char *function_names[NUM_FUNCTIONS];
65 Pixmap helppix = (Pixmap)NULL; /* For help window */
66 Dimension helpwidth, helpheight, hheight;
67 int helptop;
68 short help_up;
70 /*-----------------------------------------*/
71 /* Print help list into a pixmap */
72 /* Return width and height of map through */
73 /* global variables helpwidth, helpheight. */
74 /*-----------------------------------------*/
76 typedef struct {
77 int function;
78 char *text;
79 } helpstruct;
81 void printhelppix()
83 static char *helptitle = "Macro Key Binding Summary:";
84 static helpstruct helptext[] = {
85 { XCF_Finish, "Finish"},
86 { XCF_Cancel, "Cancel"},
87 { XCF_Zoom_In, "Zoom in 3/2"},
88 { XCF_Zoom_Out, "Zoom out 3/2"},
89 { XCF_Pan, "Pan (various modes)"},
90 { XCF_Double_Snap, "Double snap-to spacing"},
91 { XCF_Halve_Snap, "Halve snap-to spacing"},
92 { XCF_Next_Library, "Go To Next Library"},
93 { XCF_Library_Pop, "Return from Library"},
94 { XCF_Push, "Push object"},
95 { XCF_Pop, "Pop object"},
96 { XCF_Redraw, "Refresh screen"},
97 { XCF_Page, "Go To Page"},
98 { XCF_Write, "Popup Output dialog"},
99 #ifdef HAVE_PYTHON
100 { XCF_Prompt, "Python Command entry"},
101 #else
102 { XCF_Prompt, "Command entry"},
103 #endif
104 { XCF_Exit, "Quit XCircuit"},
105 { XCF_SPACER, NULL},
106 { XCF_Wire, "Begin Polygon"},
107 { XCF_Box, "Begin Box"},
108 { XCF_Arc, "Begin Arc"},
109 { XCF_Text, "Begin Text"},
110 { XCF_Spline, "Begin Spline"},
111 { XCF_Select_Save, "Make object"},
112 { XCF_Virtual, "Make library instance"},
113 { XCF_Join, "Join elements (make path)"},
114 { XCF_Unjoin, "Un-join elements"},
115 { XCF_Dot, "Place a dot"},
116 { XCF_SPACER, NULL},
117 { XCF_Delete, "Delete"},
118 { XCF_Undo, "Undo"},
119 { XCF_Redo, "Redo"},
120 { XCF_Select, "Select"},
121 { XCF_Unselect, "Deselect"},
122 { XCF_Copy, "Copy"},
123 { XCF_Edit, "Edit"},
124 { XCF_SPACER, NULL},
125 { XCF_Rotate, "Rotate"},
126 { XCF_Flip_X, "Flip horizontally"},
127 { XCF_Flip_Y, "Flip vertically"},
128 { XCF_Snap, "Snap to grid"},
129 { XCF_Attach, "Attach to"},
130 { XCF_Dashed, "Dashed line style"},
131 { XCF_Dotted, "Dotted line style"},
132 { XCF_Solid, "Solid line style"},
133 { XCF_SPACER, NULL},
134 { XCF_Anchor, "Text Anchoring"},
135 { XCF_Superscript, "Text Superscript"},
136 { XCF_Subscript, "Text Subscript"},
137 { XCF_Font, "Toggle text font"},
138 { XCF_Boldfont, "Begin Bold text"},
139 { XCF_Italicfont, "Begin Italic text"},
140 { XCF_Normalfont, "Resume normal text"},
141 { XCF_ISO_Encoding, "Begin Latin-1 encoding"},
142 { XCF_Overline, "Begin text overline"},
143 { XCF_Underline, "Begin text underline"},
144 { XCF_Parameter, "Insert parameter"},
145 { XCF_Halfspace, "Insert half-space"},
146 { XCF_Quarterspace, "Insert quarter-space"},
147 { XCF_Linebreak, "Insert return character"},
148 { XCF_Special, "Insert special character"},
149 { XCF_TabStop, "Set tab stop"},
150 { XCF_TabForward, "Forward tab"},
151 { XCF_TabBackward, "Backward tab"},
152 { XCF_Text_Home, "Go to label beginning"},
153 { XCF_Text_End, "Go to label end"},
154 { XCF_Text_Left, "Move left one position"},
155 { XCF_Text_Right, "Move right one position"},
156 { XCF_Text_Up, "Move up one line"},
157 { XCF_Text_Down, "Move down one line"},
158 { XCF_Text_Delete, "Delete character(s)"},
159 { XCF_Text_Delete_Param, "Delete parameter from text"},
160 { XCF_Text_Return, "End text edit"},
161 { XCF_Text_Split, "Split label at cursor"},
162 { XCF_SPACER, NULL},
163 { XCF_Edit_Next, "Edit: next position"},
164 { XCF_Edit_Delete, "Edit: delete point"},
165 { XCF_Edit_Insert, "Edit: insert point"},
166 { XCF_Edit_Param, "Edit: insert parameter"},
167 { XCF_SPACER, NULL},
168 { XCF_Library_Edit, "Library: name edit"},
169 { XCF_Library_Move, "Library: move object/page"},
170 { XCF_Library_Delete, "Library: object delete"},
171 { XCF_Library_Hide, "Library: hide object"},
172 { XCF_Library_Duplicate, "Library: copy object"},
173 { XCF_Library_Virtual, "Library: copy instance"},
174 { XCF_SPACER, NULL},
175 { XCF_Pin_Label, "Make Pin Label"},
176 { XCF_Pin_Global, "Make Global Pin"},
177 { XCF_Info_Label, "Make Info Label"},
178 { XCF_Swap, "Go to Symbol or Schematic"},
179 { XCF_Connectivity, "See net connectivity"},
180 { XCF_Sim, "Generate Sim netlist"},
181 { XCF_SPICE, "Generate SPICE netlist"},
182 { XCF_SPICEflat, "Generate flattened SPICE"},
183 { XCF_PCB, "Generate PCB netlist"},
184 { XCF_ENDDATA, NULL},
187 XGCValues values;
188 Window hwin = DefaultRootWindow(dpy);
189 Dimension htmp, vtmp, lineheight, mwidth;
190 int i, j, t1, t2, dum, numlines;
191 XCharStruct csdum;
192 char *bindings, *bptr, *cptr;
194 if (hwin == 0) return;
196 /* Set up the GC for drawing to the help window pixmap */
198 if (hgc == NULL) {
199 values.foreground = colorlist[FOREGROUND].color.pixel;
200 values.background = colorlist[BACKGROUND].color.pixel;
201 values.graphics_exposures = False;
202 values.font = appdata.helpfont->fid;
203 hgc = XCreateGC(dpy, hwin, GCForeground | GCBackground | GCFont
204 | GCGraphicsExposures, &values);
207 /* Determine the dimensions of the help text */
209 mwidth = helpwidth = lineheight = numlines = 0;
211 for (i = 0; helptext[i].function != XCF_ENDDATA; i++) {
212 if (helptext[i].function == XCF_SPACER) {
213 numlines++;
214 continue;
217 htmp = XTextWidth(appdata.helpfont, helptext[i].text, strlen(helptext[i].text));
218 if (htmp > mwidth) mwidth = htmp;
220 XTextExtents(appdata.helpfont, helptext[i].text, strlen(helptext[i].text),
221 &dum, &t1, &t2, &csdum);
222 vtmp = t1 + t2 + 5;
223 if (vtmp > lineheight) lineheight = vtmp;
225 bindings = function_binding_to_string(0, helptext[i].function);
227 /* Limit list to three key bindings per line */
228 bptr = bindings;
229 while (bptr != NULL) {
230 cptr = bptr;
231 for (j = 0; j < 3; j++) {
232 cptr = strchr(cptr + 1, ',');
233 if (cptr == NULL) break;
235 if (cptr != NULL) *(++cptr) = '\0';
237 htmp = XTextWidth(appdata.helpfont, bptr, strlen(bptr));
238 if (htmp > helpwidth) helpwidth = htmp;
240 XTextExtents(appdata.helpfont, bptr, strlen(bptr),
241 &dum, &t1, &t2, &csdum);
242 vtmp = t1 + t2 + 5;
243 if (vtmp > lineheight) lineheight = vtmp;
244 numlines++;
246 if (cptr == NULL) break;
247 bptr = cptr + 1;
249 free(bindings);
251 XTextExtents(appdata.helpfont, helptitle, strlen(helptitle), &dum, &t1,
252 &t2, &csdum);
253 t1 += t2;
254 helpwidth += mwidth + 15;
256 helpheight = lineheight * numlines + 15 + t1; /* full height of help text */
257 if (helppix != (Pixmap)NULL) {
258 Wprintf("Error: Help window not cancelled?");
259 return;
261 helppix = XCreatePixmap(dpy, hwin, helpwidth, helpheight,
262 DefaultDepthOfScreen(DefaultScreenOfDisplay(dpy)));
264 XSetForeground(dpy, hgc, colorlist[FOREGROUND].color.pixel);
265 XFillRectangle(dpy, helppix, hgc, 0, 0, helpwidth, helpheight);
267 XSetForeground(dpy, hgc, colorlist[BACKGROUND].color.pixel);
268 XDrawString(dpy, helppix, hgc, (helpwidth - XTextWidth(appdata.helpfont,
269 helptitle, strlen(helptitle))) >> 1, t1 + 2, helptitle, strlen(helptitle));
270 vtmp = lineheight + 15;
271 for (i = 0; helptext[i].function != XCF_ENDDATA; i++) {
272 if (helptext[i].function == XCF_SPACER) {
273 vtmp += lineheight;
274 continue;
276 XDrawString(dpy, helppix, hgc, 7, vtmp, helptext[i].text,
277 strlen(helptext[i].text));
278 bindings = function_binding_to_string(0, helptext[i].function);
279 bptr = bindings;
280 while (bptr != NULL) {
281 cptr = bptr;
282 for (j = 0; j < 3; j++) {
283 cptr = strchr(cptr + 1, ',');
284 if (cptr == NULL) break;
286 if (cptr != NULL) *(++cptr) = '\0';
287 XDrawString(dpy, helppix, hgc, 7 + mwidth, vtmp, bptr, strlen(bptr));
288 vtmp += lineheight;
289 if (cptr == NULL) break;
290 bptr = cptr + 1;
292 free(bindings);
294 XSetForeground(dpy, hgc, colorlist[AUXCOLOR].color.pixel);
295 XDrawLine(dpy, helppix, hgc, 0, t1 + 7, helpwidth, t1 + 7);
298 /*----------------------------------------------*/
299 /* Create the help popup window (Xt version) */
300 /*----------------------------------------------*/
302 #ifndef XC_WIN32
304 void starthelp(xcWidget button, caddr_t clientdata, caddr_t calldata)
306 Arg wargs[11];
307 xcWidget popup, cancelbutton, hspace, help2, hsb;
308 short n = 0;
309 popupstruct *okaystruct;
310 buttonsave *savebutton;
311 Dimension areawidth, bwidth, pheight;
312 Position xpos, ypos;
313 u_int xmax, ymax;
314 char *scale;
315 int sbarsize;
317 if (help_up) return; /* no multiple help windows */
319 #ifdef TCL_WRAPPER
320 scale = Tcl_GetVar2(xcinterp, "XCOps", "scale", TCL_GLOBAL_ONLY);
321 sbarsize = SBARSIZE * atoi(scale);
322 #else
323 sbarsize = SBARSIZE;
324 #endif
326 /* for positioning the help window outside of the xcircuit */
327 /* window, get information about the display width and height */
328 /* and the xcircuit window. */
330 /* The "- 50" leaves space for the Windows-95-type title bar that */
331 /* runs across the bottom of the screen in some window managers */
332 /* (specifically, fvwm95 which is the default for RedHat Linux) */
334 xmax = DisplayWidth(dpy, DefaultScreen(dpy)) - 100;
335 ymax = DisplayHeight(dpy, DefaultScreen(dpy)) - 50;
337 XtnSetArg(XtNwidth, &areawidth);
338 XtGetValues(areawin->area, wargs, n); n = 0;
339 XtTranslateCoords(areawin->area, (Position) (areawidth + 10), -50,
340 &xpos, &ypos);
342 savebutton = getgeneric(button, starthelp, NULL);
344 /* Generate the pixmap and write the help text to it */
346 if (helppix == (Pixmap)NULL) printhelppix();
348 /* Use the pixmap size to size the help window */
350 if (xpos + helpwidth + sbarsize > xmax) xpos = xmax - helpwidth - sbarsize - 4;
351 if (ypos + helpheight > ymax) ypos = ymax - helpheight - 4;
352 if (ypos < 4) ypos = 4;
354 XtnSetArg(XtNx, xpos);
355 XtnSetArg(XtNy, ypos);
356 popup = XtCreatePopupShell("help", transientShellWidgetClass,
357 button, wargs, n); n = 0;
358 popups++;
359 help_up = True;
360 helptop = 0;
362 XtnSetArg(XtNyResizable, True);
363 XtnSetArg(XtNxResizable, False);
364 help2 = XtCreateManagedWidget("help2", XwformWidgetClass,
365 popup, wargs, n); n = 0;
367 XtnSetArg(XtNfont, appdata.xcfont);
368 cancelbutton = XtCreateManagedWidget("Dismiss", XwmenuButtonWidgetClass,
369 help2, wargs, n); n = 0;
371 XtnSetArg(XtNwidth, helpwidth);
372 XtnSetArg(XtNheight, areawin->height);
373 XtnSetArg(XtNyRefWidget, cancelbutton);
374 XtnSetArg(XtNyAddHeight, True);
375 XtnSetArg(XtNyAttachBottom, True);
376 XtnSetArg(XtNyResizable, True);
377 XtnSetArg(XtNborderWidth, 0);
378 XtnSetArg(XtNxAttachRight, False);
379 hspace = XtCreateManagedWidget("HSpace", XwworkSpaceWidgetClass,
380 help2, wargs, n); n = 0;
382 /* Create scrollbar */
383 XtnSetArg(XtNwidth, sbarsize);
384 XtnSetArg(XtNxRefWidget, hspace);
385 XtnSetArg(XtNxAddWidth, True);
386 XtnSetArg(XtNyRefWidget, cancelbutton);
387 XtnSetArg(XtNyAddHeight, True);
388 XtnSetArg(XtNyResizable, True);
389 XtnSetArg(XtNyAttachBottom, True);
390 XtnSetArg(XtNborderWidth, 1);
391 hsb = XtCreateManagedWidget("HSB", XwworkSpaceWidgetClass,
392 help2, wargs, n); n = 0;
394 okaystruct = (popupstruct *) malloc(sizeof(popupstruct));
395 okaystruct->buttonptr = savebutton;
396 okaystruct->popup = popup;
397 okaystruct->filter = NULL;
399 XtPopup(popup, XtGrabNone);
401 /* reposition the "Dismiss" button to center */
403 XtSetArg(wargs[0], XtNwidth, &bwidth);
404 XtGetValues(cancelbutton, wargs, 1);
405 XtnSetArg(XtNx, ((helpwidth - bwidth) >> 1));
406 XtSetValues(cancelbutton, wargs, n); n = 0;
408 XtSetArg(wargs[0], XtNheight, &pheight);
409 XtGetValues(help2, wargs, 1);
411 if (pheight > (ymax - 8)) {
412 XtnSetArg(XtNheight, ymax - 8);
413 XtSetValues(help2, wargs, n); n = 0;
416 XtAddEventHandler(hsb, ButtonMotionMask | ButtonPressMask, False,
417 (XtEventHandler)simplescroll, hspace);
419 /* Expose and End callbacks */
421 XtAddCallback(cancelbutton, XtNselect, (XtCallbackProc)destroypopup, okaystruct);
422 XtAddCallback(hspace, XtNexpose, (XtCallbackProc)exposehelp, NULL);
423 XtAddCallback(hsb, XtNexpose, (XtCallbackProc)showhsb, NULL);
426 /*----------------------------------------------*/
427 /* Very simple scroll mechanism (grab-and-pan) */
428 /*----------------------------------------------*/
430 void simplescroll(xcWidget hsb, xcWidget hspace, XMotionEvent *event)
432 Dimension oldtop = helptop;
434 helptop = (((int)(event->y) * helpheight) / hheight) - (hheight / 2);
436 if (helptop < 0) helptop = 0;
437 else if (helptop > helpheight - hheight) helptop = helpheight - hheight;
439 if (helptop != oldtop) {
440 showhsb(hsb, NULL, NULL);
441 printhelp(hspace);
445 /*----------------------------------------------*/
446 /* Expose callback for the help scrollbar */
447 /*----------------------------------------------*/
449 void showhsb(xcWidget hsb, caddr_t clientdata, caddr_t calldata)
451 Window hwin = xcWindow(hsb);
452 Dimension sheight;
453 int pstart, pheight;
454 short n = 0;
455 int sbarsize;
457 #ifdef TCL_WRAPPER
458 char *scale;
459 scale = Tcl_GetVar2(xcinterp, "XCOps", "scale", TCL_GLOBAL_ONLY);
460 sbarsize = SBARSIZE * atoi(scale);
461 #else
462 sbarsize = SBARSIZE;
463 #endif
465 if (helppix == (Pixmap)NULL) printhelppix();
466 if (helpheight == 0) helpheight = 1;
468 pstart = (helptop * hheight) / helpheight;
469 pheight = (hheight * hheight) / helpheight;
471 if (pheight < 3) pheight = 3;
473 XClearArea(dpy, hwin, 0, 0, sbarsize, pstart, False);
474 XClearArea(dpy, hwin, 0, pstart + pheight, sbarsize,
475 hheight - (pstart + pheight), False);
477 XSetForeground(dpy, hgc, colorlist[BARCOLOR].color.pixel);
478 XFillRectangle(dpy, hwin, hgc, 0, pstart, sbarsize, pheight);
481 /*----------------------------------------------*/
482 /* Expose callback for the help window */
483 /*----------------------------------------------*/
485 void exposehelp(xcWidget hspace, caddr_t clientdata, caddr_t calldata)
487 Arg wargs[1];
489 XtSetArg(wargs[0], XtNheight, &hheight);
490 XtGetValues(hspace, wargs, 1);
492 if (helppix == (Pixmap)NULL) printhelppix();
493 if (hheight < 1) hheight = 1;
495 printhelp(hspace);
498 /*----------------------------------------------*/
499 /* Expose callback for the help window */
500 /*----------------------------------------------*/
502 void printhelp(xcWidget hspace)
504 Window hwin = xcWindow(hspace);
505 XEvent discard;
507 /* Draw the pixmap to the window */
509 XCopyArea(dpy, helppix, hwin, hgc, 0, helptop - 5, helpwidth, helpheight,
510 0, 0);
512 /* flush out multiple expose events */
514 while (XCheckWindowEvent(dpy, hwin, ExposureMask, &discard) == True);
517 #endif
519 /*----------------------------------------------------------------------*/
520 /* The TCL version assumes the existence of command "helpwindow". */
521 /*----------------------------------------------------------------------*/
523 #else
525 void starthelp(xcWidget button, caddr_t clientdata, caddr_t calldata)
527 Tcl_Eval(xcinterp, "catch xcircuit::helpwindow");
530 #endif /* !TCL_WRAPPER */