1 /*----------------------------------------------------------------------*/
2 /* Copyright (c) 2002  Tim Edwards, Johns Hopkins University        	*/
3 /*----------------------------------------------------------------------*/
4 
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 /*----------------------------------------------------------------------*/
10 
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 
15 #ifndef XC_WIN32
16 #include <X11/Intrinsic.h>
17 #include <X11/StringDefs.h>
18 #include <X11/Shell.h>
19 #endif
20 
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
31 
32 /*----------------------------------------------------------------------*/
33 /* Local includes							*/
34 /*----------------------------------------------------------------------*/
35 
36 #include "colordefs.h"
37 #include "xcircuit.h"
38 #include "menudep.h"
39 
40 /*----------------------------------------------------------------------*/
41 /* Function prototype declarations                                      */
42 /*----------------------------------------------------------------------*/
43 #include "prototypes.h"
44 
45 /*----------------------------------------------------------------------*/
46 /* Global Variable definitions						*/
47 /*----------------------------------------------------------------------*/
48 
49 #ifdef TCL_WRAPPER
50 extern Tcl_Interp *xcinterp;
51 #endif
52 
53 #ifndef TCL_WRAPPER
54 
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];
64 
65 Pixmap   helppix = (Pixmap)NULL;     /* For help window */
66 Dimension helpwidth, helpheight, hheight;
67 int helptop;
68 short help_up;
69 
70 /*-----------------------------------------*/
71 /* Print help list into a pixmap           */
72 /* Return width and height of map through  */
73 /* global variables helpwidth, helpheight. */
74 /*-----------------------------------------*/
75 
76 typedef struct {
77    int function;
78    char *text;
79 } helpstruct;
80 
printhelppix()81 void printhelppix()
82 {
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},
185     };
186 
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;
193 
194     if (hwin == 0) return;
195 
196     /* Set up the GC for drawing to the help window pixmap */
197 
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);
205     }
206 
207     /* Determine the dimensions of the help text */
208 
209     mwidth = helpwidth = lineheight = numlines = 0;
210 
211     for (i = 0; helptext[i].function != XCF_ENDDATA; i++) {
212        if (helptext[i].function == XCF_SPACER) {
213 	  numlines++;
214 	  continue;
215        }
216 
217        htmp = XTextWidth(appdata.helpfont, helptext[i].text, strlen(helptext[i].text));
218        if (htmp > mwidth) mwidth = htmp;
219 
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;
224 
225        bindings = function_binding_to_string(0, helptext[i].function);
226 
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;
234           }
235 	  if (cptr != NULL) *(++cptr) = '\0';
236 
237           htmp = XTextWidth(appdata.helpfont, bptr, strlen(bptr));
238           if (htmp > helpwidth) helpwidth = htmp;
239 
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++;
245 
246 	  if (cptr == NULL) break;
247 	  bptr = cptr + 1;
248        }
249        free(bindings);
250     }
251     XTextExtents(appdata.helpfont, helptitle, strlen(helptitle), &dum, &t1,
252 	&t2, &csdum);
253     t1 += t2;
254     helpwidth += mwidth + 15;
255 
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;
260     }
261     helppix = XCreatePixmap(dpy, hwin, helpwidth, helpheight,
262 	   	  DefaultDepthOfScreen(DefaultScreenOfDisplay(dpy)));
263 
264     XSetForeground(dpy, hgc, colorlist[FOREGROUND].color.pixel);
265     XFillRectangle(dpy, helppix, hgc, 0, 0, helpwidth, helpheight);
266 
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;
275        }
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;
285           }
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;
291        }
292        free(bindings);
293     }
294     XSetForeground(dpy, hgc, colorlist[AUXCOLOR].color.pixel);
295     XDrawLine(dpy, helppix, hgc, 0, t1 + 7, helpwidth, t1 + 7);
296 }
297 
298 /*----------------------------------------------*/
299 /* Create the help popup window	(Xt version)	*/
300 /*----------------------------------------------*/
301 
302 #ifndef XC_WIN32
303 
starthelp(xcWidget button,caddr_t clientdata,caddr_t calldata)304 void starthelp(xcWidget button, caddr_t clientdata, caddr_t calldata)
305 {
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 
315    if (help_up) return;  /* no multiple help windows */
316 
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.					  */
320 
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)   */
324 
325    xmax = DisplayWidth(dpy, DefaultScreen(dpy)) - 100;
326    ymax = DisplayHeight(dpy, DefaultScreen(dpy)) - 50;
327 
328    XtnSetArg(XtNwidth, &areawidth);
329    XtGetValues(areawin->area, wargs, n); n = 0;
330    XtTranslateCoords(areawin->area, (Position) (areawidth + 10), -50,
331 	&xpos, &ypos);
332 
333    savebutton = getgeneric(button, starthelp, NULL);
334 
335    /* Generate the pixmap and write the help text to it */
336 
337    if (helppix == (Pixmap)NULL) printhelppix();
338 
339    /* Use the pixmap size to size the help window */
340 
341    if (xpos + helpwidth + SBARSIZE > xmax)  xpos = xmax - helpwidth - SBARSIZE - 4;
342    if (ypos + helpheight > ymax) ypos = ymax - helpheight - 4;
343    if (ypos < 4) ypos = 4;
344 
345    XtnSetArg(XtNx, xpos);
346    XtnSetArg(XtNy, ypos);
347    popup = XtCreatePopupShell("help", transientShellWidgetClass,
348 	button, wargs, n); n = 0;
349    popups++;
350    help_up = True;
351    helptop = 0;
352 
353    XtnSetArg(XtNyResizable, True);
354    XtnSetArg(XtNxResizable, False);
355    help2 = XtCreateManagedWidget("help2", XwformWidgetClass,
356 	popup, wargs, n); n = 0;
357 
358    XtnSetArg(XtNfont, appdata.xcfont);
359    cancelbutton = XtCreateManagedWidget("Dismiss", XwmenuButtonWidgetClass,
360 	help2, wargs, n); n = 0;
361 
362    XtnSetArg(XtNwidth, helpwidth);
363    XtnSetArg(XtNheight, areawin->height);
364    XtnSetArg(XtNyRefWidget, cancelbutton);
365    XtnSetArg(XtNyAddHeight, True);
366    XtnSetArg(XtNyAttachBottom, True);
367    XtnSetArg(XtNyResizable, True);
368    XtnSetArg(XtNborderWidth, 0);
369    XtnSetArg(XtNxAttachRight, False);
370    hspace = XtCreateManagedWidget("HSpace", XwworkSpaceWidgetClass,
371 	help2, wargs, n); n = 0;
372 
373    /* Create scrollbar */
374    XtnSetArg(XtNwidth, SBARSIZE);
375    XtnSetArg(XtNxRefWidget, hspace);
376    XtnSetArg(XtNxAddWidth, True);
377    XtnSetArg(XtNyRefWidget, cancelbutton);
378    XtnSetArg(XtNyAddHeight, True);
379    XtnSetArg(XtNyResizable, True);
380    XtnSetArg(XtNyAttachBottom, True);
381    XtnSetArg(XtNborderWidth, 1);
382    hsb = XtCreateManagedWidget("HSB", XwworkSpaceWidgetClass,
383 		help2, wargs, n); n = 0;
384 
385    okaystruct = (popupstruct *) malloc(sizeof(popupstruct));
386    okaystruct->buttonptr = savebutton;
387    okaystruct->popup = popup;
388    okaystruct->filter = NULL;
389 
390    XtPopup(popup, XtGrabNone);
391 
392    /* reposition the "Dismiss" button to center */
393 
394    XtSetArg(wargs[0], XtNwidth, &bwidth);
395    XtGetValues(cancelbutton, wargs, 1);
396    XtnSetArg(XtNx, ((helpwidth - bwidth) >> 1));
397    XtSetValues(cancelbutton, wargs, n); n = 0;
398 
399    XtSetArg(wargs[0], XtNheight, &pheight);
400    XtGetValues(help2, wargs, 1);
401 
402    if (pheight > (ymax - 8)) {
403       XtnSetArg(XtNheight, ymax - 8);
404       XtSetValues(help2, wargs, n); n = 0;
405    }
406 
407    XtAddEventHandler(hsb, ButtonMotionMask | ButtonPressMask, False,
408 		(XtEventHandler)simplescroll, hspace);
409 
410    /* Expose and End callbacks */
411 
412    XtAddCallback(cancelbutton, XtNselect, (XtCallbackProc)destroypopup, okaystruct);
413    XtAddCallback(hspace, XtNexpose, (XtCallbackProc)exposehelp, NULL);
414    XtAddCallback(hsb, XtNexpose, (XtCallbackProc)showhsb, NULL);
415 }
416 
417 /*----------------------------------------------*/
418 /* Very simple scroll mechanism	 (grab-and-pan)	*/
419 /*----------------------------------------------*/
420 
simplescroll(xcWidget hsb,xcWidget hspace,XMotionEvent * event)421 void simplescroll(xcWidget hsb, xcWidget hspace, XMotionEvent *event)
422 {
423    Dimension oldtop = helptop;
424 
425    helptop = (((int)(event->y) * helpheight) / hheight) - (hheight / 2);
426 
427    if (helptop < 0) helptop = 0;
428    else if (helptop > helpheight - hheight) helptop = helpheight - hheight;
429 
430    if (helptop != oldtop) {
431       showhsb(hsb, NULL, NULL);
432       printhelp(hspace);
433    }
434 }
435 
436 /*----------------------------------------------*/
437 /* Expose callback for the help scrollbar	*/
438 /*----------------------------------------------*/
439 
showhsb(xcWidget hsb,caddr_t clientdata,caddr_t calldata)440 void showhsb(xcWidget hsb, caddr_t clientdata, caddr_t calldata)
441 {
442    Window hwin = xcWindow(hsb);
443    Dimension sheight;
444    int pstart, pheight;
445    short n = 0;
446 
447    if (helppix == (Pixmap)NULL) printhelppix();
448    if (helpheight == 0) helpheight = 1;
449 
450    pstart = (helptop * hheight) / helpheight;
451    pheight = (hheight * hheight) / helpheight;
452 
453    if (pheight < 3) pheight = 3;
454 
455    XClearArea(dpy, hwin, 0, 0, SBARSIZE, pstart, False);
456    XClearArea(dpy, hwin, 0, pstart + pheight, SBARSIZE,
457 		hheight - (pstart + pheight), False);
458 
459    XSetForeground(dpy, hgc, colorlist[BARCOLOR].color.pixel);
460    XFillRectangle(dpy, hwin, hgc, 0, pstart, SBARSIZE, pheight);
461 }
462 
463 /*----------------------------------------------*/
464 /* Expose callback for the help window		*/
465 /*----------------------------------------------*/
466 
exposehelp(xcWidget hspace,caddr_t clientdata,caddr_t calldata)467 void exposehelp(xcWidget hspace, caddr_t clientdata, caddr_t calldata)
468 {
469    Arg wargs[1];
470 
471    XtSetArg(wargs[0], XtNheight, &hheight);
472    XtGetValues(hspace, wargs, 1);
473 
474    if (helppix == (Pixmap)NULL) printhelppix();
475    if (hheight < 1) hheight = 1;
476 
477    printhelp(hspace);
478 }
479 
480 /*----------------------------------------------*/
481 /* Expose callback for the help window		*/
482 /*----------------------------------------------*/
483 
printhelp(xcWidget hspace)484 void printhelp(xcWidget hspace)
485 {
486    Window hwin = xcWindow(hspace);
487    XEvent discard;
488 
489    /* Draw the pixmap to the window */
490 
491    XCopyArea(dpy, helppix, hwin, hgc, 0, helptop - 5, helpwidth, helpheight,
492 	0, 0);
493 
494    /* flush out multiple expose events */
495 
496    while (XCheckWindowEvent(dpy, hwin, ExposureMask, &discard) == True);
497 }
498 
499 #endif
500 
501 /*----------------------------------------------------------------------*/
502 /* The TCL version assumes the existence of command "helpwindow".	*/
503 /*----------------------------------------------------------------------*/
504 
505 #else
506 
starthelp(xcWidget button,caddr_t clientdata,caddr_t calldata)507 void starthelp(xcWidget button, caddr_t clientdata, caddr_t calldata)
508 {
509    Tcl_Eval(xcinterp, "catch xcircuit::helpwindow");
510 }
511 
512 #endif /* !TCL_WRAPPER */
513