1 /*
2 * Copyright (C) 1989-1992 Yale University
3 *
4 * This work is distributed in the hope that it will be useful; you can
5 * redistribute it and/or modify it under the terms of the
6 * GNU General Public License as published by the Free Software Foundation;
7 * either version 2 of the License,
8 * or any later version, on the following conditions:
9 *
10 * (a) YALE MAKES NO, AND EXPRESSLY DISCLAIMS
11 * ALL, REPRESENTATIONS OR WARRANTIES THAT THE MANUFACTURE, USE, PRACTICE,
12 * SALE OR
13 * OTHER DISPOSAL OF THE SOFTWARE DOES NOT OR WILL NOT INFRINGE UPON ANY
14 * PATENT OR
15 * OTHER RIGHTS NOT VESTED IN YALE.
16 *
17 * (b) YALE MAKES NO, AND EXPRESSLY DISCLAIMS ALL, REPRESENTATIONS AND
18 * WARRANTIES
19 * WHATSOEVER WITH RESPECT TO THE SOFTWARE, EITHER EXPRESS OR IMPLIED,
20 * INCLUDING,
21 * BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
22 * PARTICULAR
23 * PURPOSE.
24 *
25 * (c) LICENSEE SHALL MAKE NO STATEMENTS, REPRESENTATION OR WARRANTIES
26 * WHATSOEVER TO
27 * ANY THIRD PARTIES THAT ARE INCONSISTENT WITH THE DISCLAIMERS BY YALE IN
28 * ARTICLE
29 * (a) AND (b) above.
30 *
31 * (d) IN NO EVENT SHALL YALE, OR ITS TRUSTEES, DIRECTORS, OFFICERS,
32 * EMPLOYEES AND
33 * AFFILIATES BE LIABLE FOR DAMAGES OF ANY KIND, INCLUDING ECONOMIC DAMAGE OR
34 * INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER YALE SHALL BE
35 * ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF THE
36 * POSSIBILITY OF THE FOREGOING.
37 *
38 */
39
40 /* -----------------------------------------------------------------
41 FILE: dialog.c
42 DESCRIPTION:creates a dialog box for TimberWolf pgms.
43 It returns information for the user.
44 CONTENTS: TWDRETURNPTR TWdialog( fieldp )
45 TWDIALOGPTR fieldp ;
46 TWDRETURNPTR TWread_dialog( filename )
47 char *filename ;
48 DATE: Aug 16, 1989 - original coding.
49 REVISIONS: Sep 16, 1989 - all debug directed to stderr.
50 Sep 23, 1989 - rewrote data structures to handle cases
51 Oct 2, 1989 - now user can set position of dialog box.
52 Also fixed bug with font size.
53 Feb 20, 1990 - tell the user data has changed.
54 Sep 25, 1990 - added B&W mode.
55 Dec 5, 1990 - now handle stipple correctly and added
56 user_function to the dialog procedure.
57 Dec 27, 1990 - eliminated multiple redraws upon startup.
58 Mon Jan 7 18:17:44 CST 1991 - made SAFE_WAIT_TIME
59 user programmable for slow machines.
60 Fri Jan 18 18:36:44 PST 1991 - added event debug.
61 Fri Jan 25 16:17:21 PST 1991 - now look for backspace
62 or delete key when in window.
63 Fri Feb 22 23:36:13 EST 1991 - wait for screen to appear.
64 Thu Mar 7 01:24:55 EST 1991 - added focus requests for
65 SUN openwindows. Also added draw screen refresh.
66 Sun Nov 3 12:50:53 EST 1991 - fixed gcc complaints.
67 Thu Jan 30 02:55:16 EST 1992 - added window manager hints
68 and now allow different font for dialog box.
69 ----------------------------------------------------------------- */
70
71 #ifndef NOGRAPHICS
72
73 #include <stdio.h>
74 #include <string.h>
75 #include <X11/Xlib.h>
76 #include <X11/Xatom.h>
77 #include <X11/Xutil.h>
78 #include <X11/cursorfont.h>
79
80 /* #define TURNOFFPRINTD */
81
82 #include <yalecad/base.h>
83 #include <yalecad/file.h>
84 #include <yalecad/colors.h>
85 #include <yalecad/message.h>
86 #include <yalecad/hash.h>
87 #include <yalecad/string.h>
88 #include <yalecad/debug.h>
89 #include <yalecad/draw.h>
90 #include <yalecad/dialog.h>
91 #include <yalecad/time.h>
92 #include "info.h"
93
94 #define WHITE 1 /* white parent gc is one in array */
95 #define BLACK 2 /* black parent gc is two in array */
96 #define CANCEL 0 /* code for cancel menu activity */
97 #define DELETE_CH '\177' /* delete character */
98 #define BACKSPACE '\010' /* backspace character */
99 #define RETURN '\015' /* return charachter */
100 #define COMMENT '#' /* comment character in first col */
101 #define RATIO 0.70
102 #define ACCEPTWIN 0
103 #define REJECTWIN 1
104
105 /* definitions for parsing dialog file */
106 #define FIELD 0
107 #define FIELDNUM 1
108 #define COLUMN 2
109 #define ROW 3
110 #define STRING 4
111 #define LEN 5
112 #define TYPE 6
113 #define COLOR 7
114 #define CASEGROUP 8
115
116 /* definitions for the fonts */
117 #define NEW_FONT TRUE
118 #define REVERT_FONT 2
119
120 static TWINFOPTR infoS ; /* information about main details */
121 static Display *dpyS; /* the display */
122 static Window menuS; /* the current menu window */
123 static Window wS; /* the main TW display window */
124 static Window dialogS; /* the dialog display window */
125 static GC *contextArrayS ; /* array of context window */
126 static GC reverseGCS ; /* reverse gc for dialog */
127 static INT screenS ; /* the current screen */
128 static UNSIGNED_INT backgrdS ;
129 static UNSIGNED_INT foregrdS ;
130 static INT winwidthS ; /* window width */
131 static Window *winS ; /* contains info about menus */
132 static XFontStruct *fontinfoS ; /* font information */
133 static Font fontS ; /* current font */
134 static int xdS ; /* origin of dialog window */
135 static int ydS ; /* origin of dialog window */
136 static INT fwidthS ; /* font width in pixels */
137 static INT fheightS ; /* font height in pixels */
138 static INT numwinS ; /* number of window in dialog box */
139 static TWDRETURNPTR dataS ; /* return data array */
140 static TWDIALOGPTR fieldS ; /* the current dialog array */
141
142 /* function definitions */
143 static INT world2pix_x(int) ;
144 static INT world2pix_y(int) ;
145 static INT world2fonty(int) ;
146 static INT pixlen() ;
147 static void set_stipple_font( P2(BOOL stippleOn, INT font_change ) ) ;
148 static void debug_dialog( P1( TWDIALOGPTR fieldp ) ) ;
149 static void check_cases( P3( TWDIALOGPTR fieldp, INT select,
150 INT (*user_function)() )) ;
151 static void draw_fields( P1(TWDIALOGPTR fieldp) ) ;
152 static void TWfreeWindows() ;
153 static void find_font_boundary() ;
154 static void edit_field( P4( INT field, Window win, XEvent event, INT (*user_function)() ) ) ;
155
156 /* build a dialog box and get info */
TWdialog(fieldp,dialogname,user_function)157 TWDRETURNPTR TWdialog( fieldp, dialogname, user_function )
158 TWDIALOGPTR fieldp ;
159 char *dialogname ;
160 INT (*user_function)() ;
161 {
162 UNSIGNED_INT white, black ;
163 INT i ; /* counter */
164 long event_mask ; /* set up event catching with this mask */
165 INT screenwidth ; /* width of root window */
166 unsigned int widthd ; /* adjusted width of dialog screen */
167 INT screenheight ; /* height of root window */
168 unsigned int heightd ;/* adjusted height of dialog screen */
169 INT win_num ; /* window counter */
170 INT time ; /* current time */
171 TWDIALOGPTR fptr ; /* current dialog field */
172 TWDRETURNPTR dptr ; /* current return field */
173 BOOL press ; /* tells whether button has been pushed */
174 BOOL bw ; /* tells whether display is color or not */
175 BOOL foundWindow ; /* used in window search to find match */
176 static INT lasttimeL; /* last time of exposure event */
177 XEvent event ; /* describes button event */
178 Window win ; /* temporary for selected window */
179 Cursor cursor ; /* cursor for typing */
180 char *winstr ; /* used for get user window default */
181 INT m ; /* mask for determining window position */
182 char resource[LRECL] ;/* look for match in database */
183 XSizeHints hints ; /* setup hints for window manager */
184 char *font ; /* user font request */
185 BOOL font_loaded ; /* whether dialog box has its own font */
186
187
188 /* get static information from main draw module */
189 /* try to do crude object oriented programming */
190 infoS = TWgetDrawInfo() ;
191 /* save display info for future use */
192 dpyS = infoS->dpy ;
193 screenS = infoS->screen ;
194 wS = infoS->rootWindow ;
195
196 black = BlackPixel(dpyS,screenS);
197 white = WhitePixel(dpyS,screenS);
198 backgrdS = black ;
199 foregrdS = white ;
200
201 /* check whether machine is color or not */
202 if( (bw = XDisplayCells( dpyS, screenS )) > 2 ){
203 /* if color number of display cells > 0 */
204 bw = FALSE ;
205 } else {
206 bw = TRUE ;
207 }
208
209 /* calculate where to put master window */
210 /* we want to center the window and take 70% of */
211 /* the available screen */
212 screenwidth = XDisplayWidth(dpyS,screenS);
213 screenheight = XDisplayHeight(dpyS,screenS);
214
215 sprintf( resource, "geometry_%s", dialogname ) ;
216 D( "dialog", fprintf( stderr, "resource:%s\n", resource ) ) ;
217 if( winstr = XGetDefault( dpyS, GRAPHICS, resource )){
218 m = XParseGeometry( winstr,&xdS,&ydS,&widthd,&heightd) ;
219 if( m & XNegative ){
220 xdS += screenwidth ;
221 }
222 if( m & YNegative ){
223 ydS += screenheight ;
224 }
225 /* these two lines insure that uses doesn't have to press */
226 /* button using twm window manager */
227 if( xdS == 0 ) xdS++ ;
228 if( ydS == 0 ) ydS++ ;
229 hints.flags = USPosition | USSize ;
230 } else {
231 widthd = (INT) (RATIO * (DOUBLE) screenwidth ) ;
232 heightd = (INT) (RATIO * (DOUBLE) screenheight ) ;
233 xdS = (screenwidth - widthd ) / 2 ;
234 ydS = (screenheight - heightd ) / 2 ;
235 hints.flags = PPosition | PSize ;
236 }
237 sprintf( resource, "font_%s", dialogname ) ;
238 D( "dialog", fprintf( stderr, "font resource:%s\n", resource ) ) ;
239 /* set font and get font info */
240 font_loaded = FALSE ;
241 if(font = XGetDefault( dpyS, GRAPHICS, resource )){
242 if( strcmp( font, infoS->fontname ) != STRINGEQ ){
243 fontinfoS = TWgetfont( font, &fontS ) ;
244 font_loaded = TRUE ;
245 }
246 } else {
247 fontinfoS = infoS->fontinfo ;
248 fontS = fontinfoS->fid ;
249 }
250
251 /* normal case - need to create menu window */
252 dialogS = XCreateSimpleWindow( dpyS, wS, xdS, ydS,
253 widthd, heightd, 1L, backgrdS, foregrdS ) ;
254
255 event_mask = ExposureMask | VisibilityChangeMask ;
256 XSelectInput(dpyS,dialogS,event_mask);
257
258 cursor = XCreateFontCursor( dpyS, XC_hand2 ) ;
259 XDefineCursor( dpyS, dialogS, cursor ) ;
260
261 /* set the window manager hints */
262 hints.x = xdS ;
263 hints.y = ydS ;
264 hints.width = widthd ;
265 hints.height = heightd ;
266 XSetStandardProperties(dpyS,dialogS,dialogname,dialogname,None,NULL,0,&hints);
267
268 /* set graphic contexts */
269 contextArrayS = infoS->graphicContext ;
270 reverseGCS = contextArrayS[WHITE] ;
271 set_stipple_font( FALSE, font_loaded ) ;
272
273 /* count number of windows required */
274 fieldS = fieldp ;
275 numwinS = 0 ;
276 for( i=0 ; fieldp[i].row ; i++ ){
277 numwinS++ ;
278 }
279 /* allocate an array of windows */
280 winS = YCALLOC( numwinS+1, Window ) ;
281 dataS = YCALLOC( numwinS+1,TWDRETURNBOX ) ;
282
283 /* find pixel bounding box */
284 /* we assume fixed fonts but variable fonts will be ok */
285 find_font_boundary() ;
286
287 for( i=0 ; i < numwinS ; i++ ){
288 fptr = &(fieldp[i]) ;
289 dptr = &(dataS[i]) ;
290 if( fptr->string ){
291 dptr->string = Ystrclone( fptr->string ) ;
292 } else {
293 dptr->string = NULL ;
294 }
295 if( bw ){
296 /* on a black and white machine set color to backgrd color */
297 fptr->color = BLACK ;
298 }
299 if( fptr->type == INPUTTYPE || fptr->type == BUTTONTYPE ){
300 winS[i] = XCreateSimpleWindow( dpyS, dialogS,
301 world2pix_x( fptr->column ),
302 world2pix_y( fptr->row - 1 ),
303 pixlen( fptr->len ), fheightS,
304 1L, backgrdS, foregrdS ) ;
305 XDefineCursor( dpyS, winS[i], cursor ) ;
306
307 } else if( fptr->type == CASETYPE ){
308 /* initial on button of a case switch */
309 ASSERTNCONT( fptr->group > 0 && fptr->group < numwinS,
310 "TWdialog", "init_switch out of bounds\n" ) ;
311 dataS[fptr->group].bool = TRUE ;
312 }
313 }
314 /* now raise all the subwindows */
315 /* and initialize input selection*/
316 for( i=0; i< numwinS; i++ ){
317 if(!(winS[i])){
318 /* skip over label fields which don't have windows */
319 continue ;
320 }
321
322 /* now set all window masks */
323 fptr = &(fieldp[i]) ;
324 if( fptr->type == BUTTONTYPE ){
325 event_mask = ButtonPressMask | EnterWindowMask | LeaveWindowMask ;
326 } else if( fptr->type == INPUTTYPE ){
327 event_mask = KeyPressMask | EnterWindowMask | LeaveWindowMask ;
328 } else {
329 /* use just exposure mask here */
330 event_mask = ExposureMask ;
331 }
332 XSelectInput(dpyS,winS[i],event_mask);
333 XMapRaised( dpyS, winS[i] ) ;
334 }
335
336 /* now raise menu window so we can see it */
337 XMapWindow( dpyS, dialogS ) ;
338
339 /* wait for all the windows to be raised */
340 XSync( dpyS, FALSE ) ;
341 /* -------------------------------------------------------------
342 Now wait to window to become visible. This code is necessary
343 since some window managers (uwm) map the window as a ghost
344 image and wait for user to resize window. Other window
345 managers (twm) map window as requested. Need to accomodate
346 both.
347 -------------------------------------------------------------- */
348 while( TRUE ){
349 if( XCheckTypedWindowEvent(dpyS,dialogS,VisibilityNotify,&event)){
350 if( event.xvisibility.state == VisibilityUnobscured ||
351 event.xvisibility.state == VisibilityPartiallyObscured ){
352 break ;
353 }
354 }
355 }
356 event_mask = ExposureMask ;
357 XSelectInput(dpyS,dialogS,event_mask);
358 XClearWindow( dpyS, dialogS ) ;
359
360 draw_fields( fieldp ) ;
361 /* update time for slow machines */
362 (void) YcurTime( &lasttimeL ) ;
363
364 /* now look for button press to end */
365 event_mask = ButtonPressMask | KeyPressMask | EnterWindowMask |
366 LeaveWindowMask | ExposureMask ;
367 while( TRUE ){
368 if( XCheckMaskEvent( dpyS, event_mask, &event ) ){
369 D( "TWdialog/event",
370 fprintf( stderr, "Event:%d window:%d\n",
371 event.type, event.xany.window ) ;
372 ) ;
373 switch( event.type ){
374 case ButtonPress:
375 /* how we exit */
376 win = event.xbutton.window ;
377 if( win == winS[ACCEPTWIN] ){
378 TWfreeWindows() ;
379 set_stipple_font( TRUE, REVERT_FONT ) ;
380 return( dataS ) ;
381 } else if( win == winS[REJECTWIN] ){
382 TWfreeWindows() ;
383 set_stipple_font( TRUE, REVERT_FONT ) ;
384 return( NULL ) ;
385 } else {
386 /* BUTTON TYPE which is a case switch */
387 foundWindow = FALSE ;
388 for( i = 0; i < numwinS; i++ ){
389 if( win == winS[i] ){
390 foundWindow = TRUE ;
391 break ;
392 }
393 } /* end search for window */
394 if( foundWindow ){
395 check_cases( fieldp, i, user_function ) ;
396 }
397 }
398 break ;
399 case EnterNotify:
400 /* light up window */
401 /* find window match */
402 win = event.xcrossing.window ;
403 foundWindow = FALSE ;
404 for( i = 0; i < numwinS; i++ ){
405 if( win == winS[i] ){
406 foundWindow = TRUE ;
407 break ;
408 }
409 } /* end search for window */
410
411 if( foundWindow ){ /* a match light up window */
412 fptr = &(fieldp[i]) ;
413 dptr = &(dataS[i]) ;
414 XFillRectangle( dpyS,win, contextArrayS[fptr->color],
415 0,0,
416 pixlen( fptr->len ), fheightS ) ;
417 if( dptr->string ){
418 XDrawString( dpyS, win, reverseGCS,
419 0L, world2fonty( 0L ),
420 dptr->string, strlen(dptr->string)) ;
421 }
422 XSetInputFocus( dpyS, win,
423 RevertToPointerRoot, CurrentTime ) ;
424 }
425 break ;
426
427 case LeaveNotify:
428 /* turn off window */
429 /* find window match */
430 win = event.xcrossing.window ;
431 foundWindow = FALSE ;
432 for( i = 0; i < numwinS; i++ ){
433 if( win == winS[i] ){
434 foundWindow = TRUE ;
435 break ;
436 }
437 } /* end search for window */
438
439 if( foundWindow ){ /* turn off window */
440 dptr = &(dataS[i]) ;
441 XClearWindow( dpyS, win ) ;
442 if( dptr->string ){
443 if( fieldp[i].type != BUTTONTYPE ){
444 /* normal case */
445 XDrawString( dpyS, winS[i],
446 contextArrayS[fptr->color],
447 0L, world2fonty( 0L ),
448 dptr->string,
449 strlen(dptr->string)) ;
450 } else if( dptr->bool ){
451 /* a case switch that is on */
452 XFillRectangle( dpyS,win,
453 contextArrayS[fptr->color],
454 0,0,
455 pixlen( fptr->len ), fheightS ) ;
456 XDrawString( dpyS, win, reverseGCS,
457 0L, world2fonty( 0L ),
458 dptr->string, strlen(dptr->string)) ;
459 } else {
460 /* a case switch that is off */
461 XDrawString( dpyS, winS[i],
462 contextArrayS[fptr->color],
463 0L, world2fonty( 0L ),
464 dptr->string,
465 strlen(dptr->string)) ;
466 }
467 }
468 XSetInputFocus( dpyS, PointerRoot,
469 RevertToParent, CurrentTime );
470 }
471 break ;
472 case KeyPress:
473 win = event.xkey.window ;
474 foundWindow = FALSE ;
475 for( i = 0; i < numwinS; i++ ){
476 if( win == winS[i] ){
477 foundWindow = TRUE ;
478 break ;
479 }
480 } /* end search for window */
481
482 if( foundWindow ){ /* turn off window */
483 edit_field( i, win, event, user_function ) ;
484 }
485 break ;
486 case Expose:
487 win = event.xexpose.window ;
488 if( win == infoS->drawWindow ){
489 (*infoS->refresh_func)() ;
490 } else {
491 /* window managers sometimes send us too many */
492 /* exposure events therefore check time and */
493 /* make multiple exposures invalid */
494 if( event.xexpose.count == 0 ){
495 (void) YcurTime( &time ) ;
496 if( time - lasttimeL < TWsafe_wait_timeG ){
497 D( "TWdialog/exposure",
498 fprintf( stderr,
499 "Dialog Exposure:0 @time = %d\n",
500 time);
501 ) ;
502 break ;
503 }
504 D( "TWdialog/exposure",
505 fprintf( stderr,
506 "Dialog Exposure:1 @time = %d\n",
507 time);
508 ) ;
509 draw_fields( fieldp ) ;
510 /* update time for slow machines */
511 (void) YcurTime( &time ) ;
512 lasttimeL = time ;
513 }
514 }
515 break ;
516 } /* end event switch */
517 } /* end check on event */
518 } /* end wait loop */
519
520 } /* end TWdialog */
521
set_stipple_font(BOOL stippleOn,INT font_change)522 static void set_stipple_font( BOOL stippleOn, INT font_change )
523 {
524 INT i ; /* counter */
525
526 if( infoS->stipple ){
527 if( stippleOn ){
528 for( i = 3; i <= infoS->numColors; i++ ){
529 XSetFillStyle( dpyS, contextArrayS[i], FillTiled ) ;
530 }
531 } else {
532 for( i = 3; i <= infoS->numColors; i++ ){
533 XSetFillStyle( dpyS, contextArrayS[i], FillSolid ) ;
534 }
535 }
536 }
537 if( font_change ){
538 if( font_change == NEW_FONT ){
539 for( i=0; i <= infoS->numColors; i++ ){
540 XSetFont( dpyS, contextArrayS[i], fontS ) ;
541 }
542 } else if( font_change = REVERT_FONT ){
543 for( i=0; i <= infoS->numColors; i++ ){
544 XSetFont( dpyS, contextArrayS[i], infoS->fontinfo->fid ) ;
545 }
546 }
547 }
548 } /* end set_stipple_font */
549
550 /* check the case fields and set all member of group to false */
check_cases(fieldp,select,user_function)551 static void check_cases( fieldp, select, user_function )
552 TWDIALOGPTR fieldp ;
553 INT select ;
554 INT (*user_function)() ;
555 {
556 INT i ; /* counter */
557 INT group ; /* case group */
558 TWDIALOGPTR fptr ; /* current dialog field */
559 TWDRETURNPTR dptr ; /* current return field */
560
561 group = fieldp[select].group ;
562 for( i=0 ; i < numwinS ; i++ ){
563 fptr = &(fieldp[i]) ;
564 dptr = &(dataS[i]) ;
565 if( fptr->group == group ){
566 if( i == select ){
567 dptr->bool = TRUE ;
568 } else {
569 dptr->bool = FALSE ;
570 }
571 }
572 }
573 if( user_function ){
574 (*user_function)( dataS, select ) ;
575 }
576 /* redraw fields so user can see change */
577 draw_fields( fieldp ) ;
578
579 XFlush( dpyS ) ;
580
581 } /* end check_cases */
582
draw_fields(TWDIALOGPTR fieldp)583 static void draw_fields( TWDIALOGPTR fieldp )
584 {
585 INT i ; /* counter */
586 TWDIALOGPTR fptr ; /* current dialog field */
587 TWDRETURNPTR dptr ; /* current return field */
588
589 /* now draw all the strings to dialog window */
590 XClearWindow( dpyS, dialogS ) ;
591 for( i=0 ; i < numwinS ; i++ ){
592 fptr = &(fieldp[i]) ;
593 dptr = &(dataS[i]) ;
594 if(!(dptr->string)){
595 /* avoid null strings */
596 continue ;
597 }
598 if( fptr->type == LABELTYPE || fptr->type == CASETYPE ){
599 XDrawString( dpyS, dialogS, contextArrayS[fptr->color],
600 world2pix_x( fptr->column ),
601 world2fonty( fptr->row - 1 ),
602 dptr->string, strlen(dptr->string)) ;
603 } else if( fptr->type == INPUTTYPE ){
604 /* input case */
605 XClearWindow( dpyS, winS[i] ) ;
606 XDrawString( dpyS, winS[i], contextArrayS[fptr->color],
607 0L, world2fonty( 0L ),
608 dptr->string, strlen(dptr->string)) ;
609 } else if( fptr->type == BUTTONTYPE ){
610 XClearWindow( dpyS, winS[i] ) ;
611 if( dptr->bool ){
612 /* true initially */
613 XFillRectangle( dpyS,winS[i], contextArrayS[fptr->color],
614 0,0,
615 pixlen( fptr->len ), fheightS ) ;
616 XDrawString( dpyS, winS[i], reverseGCS,
617 0L, world2fonty( 0L ),
618 dptr->string, strlen(dptr->string)) ;
619 } else { /* off */
620 XDrawString( dpyS, winS[i], contextArrayS[fptr->color],
621 0L, world2fonty( 0L ),
622 dptr->string, strlen(dptr->string)) ;
623 }
624 }
625 }
626 } /* end draw_fields */
627
628
TWfreeWindows()629 static void TWfreeWindows()
630 {
631 INT i, j ; /* counters */
632
633 for( i = 0; winS[i] ; i++ ){
634 /* we must free window this way */
635 XDestroyWindow( dpyS, winS[i] ) ;
636 }
637 YFREE( winS ) ;
638 XDestroyWindow( dpyS, dialogS ) ;
639
640 } /* end TWfreeWindows */
641
find_font_boundary()642 static void find_font_boundary()
643 {
644 fwidthS = fontinfoS->max_bounds.rbearing -
645 fontinfoS->min_bounds.lbearing ;
646
647 fheightS = fontinfoS->ascent + fontinfoS->descent ;
648
649 } /* end find_font_boundary */
650
651 /* tranforms the world coordinate character column format */
652 /* to pixel coordinates */
world2pix_x(int x)653 static INT world2pix_x( int x )
654 {
655 return( x * fwidthS ) ;
656 } /* end world2pix_x */
657
world2pix_y(int y)658 static INT world2pix_y( int y )
659 {
660 return( y * fheightS ) ;
661 } /* end world2pix_y */
662
world2fonty(int y)663 static INT world2fonty( int y )
664 {
665 return( (++y) * fheightS - fontinfoS->max_bounds.descent ) ;
666 } /* end world2pix_y */
667
668 /* change length of string to pixel length */
pixlen(length)669 static INT pixlen( length )
670 INT length ;
671 {
672 return( fwidthS * length ) ;
673 } /* end pixlen */
674
edit_field(INT field,Window win,XEvent event,INT (* user_function)())675 static void edit_field( INT field, Window win, XEvent event, INT (*user_function)() )
676 {
677 TWDIALOGPTR fptr; /* current field of dialog */
678 TWDRETURNPTR dptr; /* return field of dialog */
679 BOOL press ; /* tells whether keyboard has been pushed */
680 BOOL finish ; /* tells whether we have received a return */
681 long event_mask ; /* setup menus */
682 char buffer[LRECL] ; /* used for keyboard translation */
683 char curMsg[LRECL] ; /* current value of message window */
684 char data[LRECL]; /* current value of users input */
685 KeySym keysym ; /* return of keysym from user */
686 XComposeStatus status ; /* where a compose key was pressed */
687 INT strwidth ; /* width of string in pixels */
688 INT dataCount ; /* number of characters in user input */
689
690 fptr = &( fieldS[field] ) ;
691 dptr = &( dataS[field] ) ;
692
693 if( dptr->string ){
694 /* initialize string buffers */
695 dataCount = strlen( dptr->string ) ;
696 strcpy( data, dptr->string ) ;
697 /* now move pointer to end of current data */
698 strwidth = XTextWidth( fontinfoS, dptr->string, dataCount) ;
699 /* now warp pointer to message window */
700 XWarpPointer( dpyS, None, win, 0, 0, 0, 0,
701 strwidth + fwidthS/3, fheightS/2 ) ;
702 } else {
703 /* initialize string buffers */
704 data[0] = EOS ;
705 dataCount = 0 ;
706 }
707
708 /* now look for keyboard action */
709 finish = FALSE ;
710 press = TRUE ; /* initially we got a keyboard event */
711 /* tell user data has changed */
712 dptr->bool = TRUE ;
713 do {
714 if( press ){
715 /* initialize buffer */
716 buffer[0] = EOS ;
717 /* find what the user entered */
718 XLookupString( &(event.xkey), buffer,LRECL,&keysym, &status );
719 buffer[1] = EOS ; /* only get one character at a time */
720 D( "Yedit_field",fprintf( stderr, "char:%c\n", buffer[0] ) ) ;
721
722 /* look to see if we got a return */
723 if( buffer[0] == RETURN ){
724 finish = TRUE ;
725 if( dptr->string ){
726 YFREE( dptr->string ) ;
727 }
728 /* return answer in dptr field */
729 dptr->string = Ystrclone( data ) ;
730 } else {
731 /* look for more data */
732 /* but first copy the data we have */
733 if( buffer[0] == BACKSPACE || buffer[0] == DELETE_CH ){
734 /* look for backspace or delete */
735 if( dataCount > 0 ){
736 dataCount-- ;
737 }
738 data[dataCount] = EOS ;
739
740 } else {
741 /* save data */
742 strcat( data, buffer ) ;
743 dataCount += strlen( buffer ) ;
744 }
745 /* now echo to screen */
746 XFillRectangle( dpyS,win, contextArrayS[fptr->color],
747 0,0,
748 pixlen( fptr->len ), fheightS ) ;
749 XDrawString( dpyS, win, reverseGCS,
750 0L, world2fonty( 0L ),
751 data, dataCount) ;
752 D( "Yedit_field",fprintf( stderr, "data:%s\n", data ) ) ;
753 D( "Yedit_field",fprintf( stderr,"datacount:%d\n",
754 dataCount ) ) ;
755 /* now move pointer to end of current data */
756 strwidth = XTextWidth( fontinfoS, data,dataCount) ;
757 /* now warp pointer to message window */
758 XWarpPointer( dpyS, None, win, 0, 0, 0, 0,
759 strwidth + fwidthS/3, fheightS/2 ) ;
760
761 }
762 }
763 /* get next keyboard stroke */
764 press = XCheckTypedWindowEvent( dpyS,win,KeyPress,&event );
765
766 } while(!finish) ; /* end wait loop */
767
768 if( user_function ){
769 (*user_function)( dataS, field ) ;
770 /* redraw fields so user can see change */
771 draw_fields( fieldS ) ;
772 }
773
774
775 } /* end edit_field */
776
777 #ifdef DEBUG
778
TWread_dialog(filename)779 TWDIALOGPTR TWread_dialog( filename )
780 char *filename ;
781 {
782
783 #define KEYWORD "numfields"
784 #define FIELDKEYWORD "field"
785
786 FILE *fp ;
787 char buffer[LRECL], *bufferptr ;
788 char group[LRECL] ; /* for parsing case groups */
789 char **tokens ; /* for parsing menu file */
790 char **colors ; /* the standard color array */
791 INT numtokens ; /* number of tokens on line */
792 INT group_num ; /* number of case fields given */
793 INT i ; /* counter */
794 INT line ; /* line number of TWmenu file */
795 INT length ; /* length of string */
796 INT numfields ; /* number of dialog fields */
797 INT curfield ; /* current dialog field */
798 INT case_label ; /* current case field */
799 INT numcolors ; /* the number of colors in color array */
800 BOOL found ; /* whether color was found */
801 TWDIALOGPTR fields; /* dialog array information */
802 TWDIALOGPTR fptr; /* current field of dialog */
803
804 /* get colors for dialog window */
805 infoS = TWgetDrawInfo() ;
806 colors = infoS->colors ;
807 numcolors = infoS->numColors ;
808
809 /* parse dialog file */
810 line = 0 ;
811 curfield = -1 ;
812 group_num = 0 ;
813 fields = NULL ;
814 fp = TWOPEN( filename, "r", ABORT ) ;
815 while( bufferptr=fgets(buffer,LRECL,fp )){
816 /* parse file */
817 line++ ; /* increment line number */
818 /* skip comments */
819 if( *bufferptr == COMMENT ){
820 continue ;
821 }
822 tokens = Ystrparser( bufferptr, ";\t\n", &numtokens );
823
824 if( numtokens == 0 ){
825 /* skip over empty lines */
826 continue ;
827 } else if( strcmp( tokens[0], KEYWORD ) == STRINGEQ){
828 /* look at first field for menu keyword */
829
830 /* there better be only two tokens on this line */
831 if( numtokens != 2 ){
832 sprintf( YmsgG, "Syntax error on line:%d\n", line ) ;
833 M(ERRMSG, "TWread_dialog", YmsgG ) ;
834 break ;
835 }
836 numfields = atoi( tokens[1] ) ;
837 ASSERTNBREAK( numfields > 0,"TWread_dialog","numfields must be >0\n" ) ;
838 fields = YCALLOC( numfields+1, TWDIALOGBOX ) ;
839
840 } else if( strcmp( tokens[FIELD], FIELDKEYWORD ) == STRINGEQ){
841 if( ++curfield >= numfields ){
842 M( ERRMSG,"TWread_dialog","number of fields mismatch\n" ) ;
843 return( NULL ) ;
844 }
845 fptr = &(fields[curfield]) ;
846 if( numtokens != 8 && numtokens != 9 ){
847 sprintf( YmsgG, "Problem parsing line:%d in dialog file\n",
848 line ) ;
849 M( ERRMSG,"TWread_dialog", YmsgG ) ;
850 continue ;
851
852 }
853 fptr->column = atoi( tokens[COLUMN] ) ;
854 fptr->row = atoi( tokens[ROW] ) ;
855 fptr->len = atoi( tokens[LEN] ) ;
856 /* check color to make sure it is valid */
857 found = FALSE ;
858 for( i=1; i <= numcolors; i++ ){
859 if( strcmp( tokens[COLOR], colors[i] ) == STRINGEQ ){
860 fptr->color = i ;
861 found = TRUE ;
862 break ;
863 }
864 }
865 if(!(found)){
866 sprintf( YmsgG,
867 "Color:%s has not been allocated\n",
868 tokens[COLOR] ) ;
869 M( ERRMSG, "TWread_dialog", YmsgG ) ;
870 return( NULL ) ;
871
872 }
873 if( strcmp( tokens[STRING], "NULL") == STRINGEQ ){
874 fptr->string = NULL ;
875 } else {
876 fptr->string = Ystrclone( tokens[STRING] ) ;
877 }
878
879 /* look at types */
880 if( strcmp( tokens[TYPE], "input") == STRINGEQ ){
881 fptr->type = INPUTTYPE ;
882 } else if( strcmp( tokens[TYPE], "label") == STRINGEQ ){
883 fptr->type = LABELTYPE ;
884 } else if( strcmp( tokens[TYPE], "accept") == STRINGEQ ){
885 fptr->type = BUTTONTYPE ;
886 if( curfield != 0 ){
887 M( ERRMSG, "TWread_dialog",
888 "accept must be 1st field\n" ) ;
889 return( NULL ) ;
890 }
891 } else if( strcmp( tokens[TYPE], "reject") == STRINGEQ ){
892 fptr->type = BUTTONTYPE ;
893 if( curfield != 1 ){
894 M( ERRMSG, "TWread_dialog",
895 "reject must be 2nd field\n" ) ;
896 return( NULL ) ;
897 }
898 } else if( strcmp( tokens[TYPE], "clabel") == STRINGEQ ){
899 fptr->type = BUTTONTYPE ;
900 } else if( strcmp( tokens[TYPE], "case") == STRINGEQ ){
901 fptr->type = CASETYPE ;
902 group_num++ ;
903 if( numtokens == 9 ){
904 strcpy( group, tokens[CASEGROUP] ) ;
905 tokens = Ystrparser( group, ",\t\n", &numtokens );
906 ASSERTNRETURN( numtokens>0,"TWread_dialog",
907 "no cases found\n" ) ;
908 for( i = numtokens-1; i >= 0;i-- ){
909 case_label = atoi( tokens[i] ) ;
910 ASSERTNCONT( case_label > 0 && case_label <=numfields,
911 "TWdialog", "case_label out of bounds\n" ) ;
912 fields[case_label].group = group_num ;
913 }
914 /* first one in list is default on switch */
915 fptr->group = case_label ;
916 } else {
917 M( ERRMSG, "TWread_dialog",
918 "wrong number of tokens for case type field\n" );
919 return( NULL ) ;
920 }
921 } else {
922 sprintf( YmsgG, "Problem parsing line:%d in dialog file\n",
923 line ) ;
924 M( ERRMSG,"TWread_dialog", YmsgG ) ;
925 }
926 }
927 } /* end parsing loop */
928
929 TWCLOSE( fp ) ;
930
931 if( fields[0].type != BUTTONTYPE ||
932 fields[1].type != BUTTONTYPE ){
933 M( ERRMSG, "TWread_dialog",
934 "accept and reject fields not setup correctly\n" ) ;
935 return( NULL ) ;
936 }
937
938 if( fields ){
939 debug_dialog( fields ) ;
940 return( fields ) ;
941 } else {
942 return( NULL ) ;
943 }
944
945 } /* end TWread_dialog */
946
debug_dialog(fieldp)947 static debug_dialog( fieldp )
948 TWDIALOGPTR fieldp ;
949 {
950 INT i ; /* counter */
951 INT count ; /* number of fields */
952 FILE *fp ; /* file pointer */
953 TWDIALOGPTR fptr ; /* temporary pointer */
954
955 fp = TWOPEN( "dialog.h", "w", ABORT ) ;
956
957 count = 0 ;
958 for( i=0 ; fieldp[i].row ; i++ ){
959 count++ ;
960 }
961
962 fprintf( fp, "static TWDIALOGBOX dialogS[%d] = {\n", count+1 ) ;
963
964 for( i=0 ; fieldp[i].row; i++ ){
965 fptr = &(fieldp[i]) ;
966 fprintf( fp, " %d,%d,%d,",fptr->row,fptr->column,fptr->len ) ;
967 fprintf( fp, "\"%s\",%d,%d,%d,\n", fptr->string,fptr->type,
968 fptr->color, fptr->group ) ;
969 }
970 fprintf( fp, " 0,0,0,0,0,0,0\n" ) ;
971 fprintf( fp, "} ;\n\n" ) ;
972 TWCLOSE(fp) ;
973 } /* end debug_dialog() */
974
975 #endif /* DEBUG */
976
977 #endif /* no graphics */
978