Update at Wed Oct 24 21:17:23 EDT 2018 by tim
[xcircuit.git] / help.c
blobe4c3eff45c2a4443a27032ebe0721e61313c1d8d
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;
315 if (help_up) return; /* no multiple help windows */
317 /* for positioning the help window outside of the xcircuit */
318 /* window, get information about the display width and height */
319 /* and the xcircuit window. */
321 /* The "- 50" leaves space for the Windows-95-type title bar that */
322 /* runs across the bottom of the screen in some window managers */
323 /* (specifically, fvwm95 which is the default for RedHat Linux) */
325 xmax = DisplayWidth(dpy, DefaultScreen(dpy)) - 100;
326 ymax = DisplayHeight(dpy, DefaultScreen(dpy)) - 50;
328 XtnSetArg(XtNwidth, &areawidth);
329 XtGetValues(areawin->area, wargs, n); n = 0;
330 XtTranslateCoords(areawin->area, (Position) (areawidth + 10), -50,
331 &xpos, &ypos);
333 /* Always direct the call to the main menu button. */
334 button = OptionsHelpButton;
336 savebutton = getgeneric(button, starthelp, NULL);
338 /* Generate the pixmap and write the help text to it */
340 if (helppix == (Pixmap)NULL) printhelppix();
342 /* Use the pixmap size to size the help window */
344 if (xpos + helpwidth + SBARSIZE > xmax) xpos = xmax - helpwidth - SBARSIZE - 4;
345 if (ypos + helpheight > ymax) ypos = ymax - helpheight - 4;
346 if (ypos < 4) ypos = 4;
348 XtnSetArg(XtNx, xpos);
349 XtnSetArg(XtNy, ypos);
350 popup = XtCreatePopupShell("help", transientShellWidgetClass,
351 button, wargs, n); n = 0;
352 popups++;
353 help_up = True;
354 helptop = 0;
356 XtnSetArg(XtNyResizable, True);
357 XtnSetArg(XtNxResizable, False);
358 help2 = XtCreateManagedWidget("help2", XwformWidgetClass,
359 popup, wargs, n); n = 0;
361 XtnSetArg(XtNfont, appdata.xcfont);
362 cancelbutton = XtCreateManagedWidget("Dismiss", XwmenuButtonWidgetClass,
363 help2, wargs, n); n = 0;
365 XtnSetArg(XtNwidth, helpwidth);
366 XtnSetArg(XtNheight, areawin->height);
367 XtnSetArg(XtNyRefWidget, cancelbutton);
368 XtnSetArg(XtNyAddHeight, True);
369 XtnSetArg(XtNyAttachBottom, True);
370 XtnSetArg(XtNyResizable, True);
371 XtnSetArg(XtNborderWidth, 0);
372 XtnSetArg(XtNxAttachRight, False);
373 hspace = XtCreateManagedWidget("HSpace", XwworkSpaceWidgetClass,
374 help2, wargs, n); n = 0;
376 /* Create scrollbar */
377 XtnSetArg(XtNwidth, SBARSIZE);
378 XtnSetArg(XtNxRefWidget, hspace);
379 XtnSetArg(XtNxAddWidth, True);
380 XtnSetArg(XtNyRefWidget, cancelbutton);
381 XtnSetArg(XtNyAddHeight, True);
382 XtnSetArg(XtNyResizable, True);
383 XtnSetArg(XtNyAttachBottom, True);
384 XtnSetArg(XtNborderWidth, 1);
385 hsb = XtCreateManagedWidget("HSB", XwworkSpaceWidgetClass,
386 help2, wargs, n); n = 0;
388 okaystruct = (popupstruct *) malloc(sizeof(popupstruct));
389 okaystruct->buttonptr = savebutton;
390 okaystruct->popup = popup;
391 okaystruct->filter = NULL;
393 XtPopup(popup, XtGrabNone);
395 /* reposition the "Dismiss" button to center */
397 XtSetArg(wargs[0], XtNwidth, &bwidth);
398 XtGetValues(cancelbutton, wargs, 1);
399 XtnSetArg(XtNx, ((helpwidth - bwidth) >> 1));
400 XtSetValues(cancelbutton, wargs, n); n = 0;
402 XtSetArg(wargs[0], XtNheight, &pheight);
403 XtGetValues(help2, wargs, 1);
405 if (pheight > (ymax - 8)) {
406 XtnSetArg(XtNheight, ymax - 8);
407 XtSetValues(help2, wargs, n); n = 0;
410 XtAddEventHandler(hsb, ButtonMotionMask | ButtonPressMask, False,
411 (XtEventHandler)simplescroll, hspace);
413 /* Expose and End callbacks */
415 XtAddCallback(cancelbutton, XtNselect, (XtCallbackProc)destroypopup, okaystruct);
416 XtAddCallback(hspace, XtNexpose, (XtCallbackProc)exposehelp, NULL);
417 XtAddCallback(hsb, XtNexpose, (XtCallbackProc)showhsb, NULL);
420 /*----------------------------------------------*/
421 /* Very simple scroll mechanism (grab-and-pan) */
422 /*----------------------------------------------*/
424 void simplescroll(xcWidget hsb, xcWidget hspace, XMotionEvent *event)
426 Dimension oldtop = helptop;
428 helptop = (((int)(event->y) * helpheight) / hheight) - (hheight / 2);
430 if (helptop < 0) helptop = 0;
431 else if (helptop > helpheight - hheight) helptop = helpheight - hheight;
433 if (helptop != oldtop) {
434 showhsb(hsb, NULL, NULL);
435 printhelp(hspace);
439 /*----------------------------------------------*/
440 /* Expose callback for the help scrollbar */
441 /*----------------------------------------------*/
443 void showhsb(xcWidget hsb, caddr_t clientdata, caddr_t calldata)
445 Window hwin = xcWindow(hsb);
446 Dimension sheight;
447 int pstart, pheight;
448 short n = 0;
450 if (helppix == (Pixmap)NULL) printhelppix();
451 if (helpheight == 0) helpheight = 1;
453 pstart = (helptop * hheight) / helpheight;
454 pheight = (hheight * hheight) / helpheight;
456 if (pheight < 3) pheight = 3;
458 XClearArea(dpy, hwin, 0, 0, SBARSIZE, pstart, False);
459 XClearArea(dpy, hwin, 0, pstart + pheight, SBARSIZE,
460 hheight - (pstart + pheight), False);
462 XSetForeground(dpy, hgc, colorlist[BARCOLOR].color.pixel);
463 XFillRectangle(dpy, hwin, hgc, 0, pstart, SBARSIZE, pheight);
466 /*----------------------------------------------*/
467 /* Expose callback for the help window */
468 /*----------------------------------------------*/
470 void exposehelp(xcWidget hspace, caddr_t clientdata, caddr_t calldata)
472 Arg wargs[1];
474 XtSetArg(wargs[0], XtNheight, &hheight);
475 XtGetValues(hspace, wargs, 1);
477 if (helppix == (Pixmap)NULL) printhelppix();
478 if (hheight < 1) hheight = 1;
480 printhelp(hspace);
483 /*----------------------------------------------*/
484 /* Expose callback for the help window */
485 /*----------------------------------------------*/
487 void printhelp(xcWidget hspace)
489 Window hwin = xcWindow(hspace);
490 XEvent discard;
492 /* Draw the pixmap to the window */
494 XCopyArea(dpy, helppix, hwin, hgc, 0, helptop - 5, helpwidth, helpheight,
495 0, 0);
497 /* flush out multiple expose events */
499 while (XCheckWindowEvent(dpy, hwin, ExposureMask, &discard) == True);
502 #endif
504 /*----------------------------------------------------------------------*/
505 /* The TCL version assumes the existence of command "helpwindow". */
506 /*----------------------------------------------------------------------*/
508 #else
510 void starthelp(xcWidget button, caddr_t clientdata, caddr_t calldata)
512 Tcl_Eval(xcinterp, "catch xcircuit::helpwindow");
515 #endif /* !TCL_WRAPPER */