1 #include "coxplot.h"
2 #include <Xm/XmAll.h>
3 #include <ctype.h>
4 #include "mcw_malloc.h"    /* ZSS: Needed because SUMA_plot.c does
5                               allocate some pointers freed here Jan 09 */
6 #include "Amalloc.h"
7 
8 /*****************************************************************************
9   This software is copyrighted and owned by the Medical College of Wisconsin.
10   See the file README.Copyright for details.
11 ******************************************************************************/
12 
13 static char print_command[256] = "\0" ;
14 static char *redcolor = NULL ;
15 static char  wintitle[128] = {"AFNI"}; /* ZSS Oct 7 2009 */
16 
set_wintitle_memplot(char * s)17 void set_wintitle_memplot( char *s )   /* ZSS Oct 7 2009 */
18 {
19    if (s) {
20       snprintf(wintitle, 125*sizeof(char), "%s", s);
21    } else {
22       sprintf(wintitle,"AFNI");
23    }
24    return;
25 }
26 
27 #ifndef LABEL_ARG
28 #define LABEL_ARG(str) \
29   XtVaTypedArg , XmNlabelString , XmRString , (str) , strlen(str)+1
30 #endif
31 
32 
33 
34 /*--------------------------------------------------------------------------*/
35 #undef  STRING_HAS_SUFFIX
36 #define STRING_HAS_SUFFIX(ss,suf)              \
37   ((ss != NULL) && (suf != NULL) &&            \
38    (strlen(ss) >= strlen(suf))   &&            \
39    (strcmp(ss+strlen(ss)-strlen(suf),suf) == 0))
40 
41 typedef void vpfunc(char *,MEM_plotdata *) ;
42 typedef struct { char *suf ; vpfunc *fun ; } saver_pair ;
43 static int     num_spair = 0 ;
44 static saver_pair *spair = NULL ;
45 
memplot_topshell_setsaver(char * suf,void (* fun)(char *,MEM_plotdata *))46 void memplot_topshell_setsaver( char *suf, void (*fun)(char *,MEM_plotdata *) )
47 {
48    int nn ;
49 
50    if( suf == NULL || *suf == '\0' || fun == NULL ) return ;
51    for( nn=0 ; nn < num_spair ; nn++ )
52      if( strcmp(suf,spair[nn].suf) == 0 ) return ;
53 
54    nn = num_spair + 1 ;
55    spair = (saver_pair *)realloc( (void *)spair , sizeof(saver_pair)*nn ) ;
56    spair[num_spair].suf = strdup(suf) ;
57    spair[num_spair].fun = fun ;
58    num_spair            = nn ;
59    return ;
60 }
61 
62 /*==========================================================================
63   Callback routines for memplot_to_topshell
64 ============================================================================*/
65 
66 /*--------------------------------------------------------------------------*/
67 
beep_CB(Widget w,XtPointer cd,XtPointer cb)68 static void beep_CB( Widget w , XtPointer cd , XtPointer cb )
69 {
70    char * str = (char *) cd ;
71 
72    if( w != NULL ) XBell(XtDisplay(w),100) ;
73    if( str != NULL && str[0] != '\0' ) fprintf(stderr,"%s\a\n",str) ;
74    return ;
75 }
76 
77 /*--------------------------------------------------------------------------
78    Save plot to a PostScript file
79 ----------------------------------------------------------------------------*/
80 
81 /****** cancellation of a print request ******/
82 
pscancel_CB(Widget w,XtPointer cd,XtPointer cb)83 static void pscancel_CB( Widget w , XtPointer cd , XtPointer cb )
84 {
85    MEM_topshell_data *mpcb = (MEM_topshell_data *) cd ;
86 
87    if( mpcb == NULL || ! MTD_VALID(mpcb) ) return ;
88 
89    if( mpcb->dial != NULL ) XtDestroyWidget( mpcb->dial ) ;
90    mpcb->dial = mpcb->wtf = NULL ;
91    return ;
92 }
93 
94 /****** finalization of a print request ******/
95 
psfinalize_CB(Widget w,XtPointer cd,XtPointer cb)96 static void psfinalize_CB( Widget w , XtPointer cd , XtPointer cb )
97 {
98    MEM_topshell_data *mpcb = (MEM_topshell_data *) cd ;
99    char *text , fname[128] ;
100    int ii , ll ;
101 
102    if( mpcb == NULL || ! MTD_VALID(mpcb) ) return ;
103 
104    if( mpcb->dial == NULL ){ XBell(XtDisplay(w),100) ; return ; }
105 
106    text = XmTextFieldGetString( mpcb->wtf ) ;
107    if( text == NULL || text[0] == '\0' ){ XBell(XtDisplay(w),100) ; return ; }
108 
109    ll = strlen(text) ;
110    for( ii=0 ; ii < ll ; ii++ ){
111       if( iscntrl(text[ii]) || isspace(text[ii]) ||
112           text[ii] == '/'   || text[ii] == ';'   ||
113           text[ii] == '*'   || text[ii] == '?'   ||
114           text[ii] == '&'   || text[ii] == '|'   ||
115           text[ii] == '"'   || text[ii] == '>'   ||
116           text[ii] == '<'   || text[ii] == '\''  ||
117           text[ii] == '['   || text[ii] == ']'     ){
118 
119         XBell(XtDisplay(w),100) ; return ;
120       }
121    }
122 
123    strcpy(fname,text) ;
124 
125    for( ii=0 ; ii < num_spair ; ii++ ){               /* 05 Dec 2007 */
126      if( STRING_HAS_SUFFIX(fname,spair[ii].suf) ){
127        spair[ii].fun( fname , mpcb->mp ) ;
128        XtDestroyWidget( mpcb->dial ) ; mpcb->dial = mpcb->wtf = NULL ;
129        return ;
130      }
131    }
132 
133    if( !STRING_HAS_SUFFIX(text,"ps") ) strcat(fname,".ps") ;
134 
135    memplot_to_postscript( fname , mpcb->mp ) ;
136 
137    XtDestroyWidget( mpcb->dial ) ;
138    mpcb->dial = mpcb->wtf = NULL ;
139    return ;
140 }
141 
142 /****** initiation of a print request ******/
143 
pm_psfile_CB(Widget w,XtPointer cd,XtPointer cb)144 void pm_psfile_CB( Widget w , XtPointer cd , XtPointer cb )
145 {
146    MEM_topshell_data * mpcb = (MEM_topshell_data *) cd ;
147    Widget wpop , wrc , wlab , wtf , form , but0 , but1 ;
148    int ibut = 0 ;
149    Position xx,yy ;
150 
151    if( mpcb == NULL || ! MTD_VALID(mpcb) ) return ;
152 
153    if( mpcb->dial != NULL ){ XBell(XtDisplay(w),100) ; return ; }
154 
155    mpcb->dial = wpop = XtVaCreatePopupShell(
156              "AFNI" , xmDialogShellWidgetClass , mpcb->top ,
157                 XmNtraversalOn , False ,
158                 XmNinitialResourcesPersistent , False ,
159              NULL ) ;
160 
161    XtVaSetValues( wpop ,
162                      XmNmwmDecorations , MWM_DECOR_BORDER ,
163                      XmNmwmFunctions   ,  MWM_FUNC_MOVE ,
164                   NULL ) ;
165 
166    wrc  = XtVaCreateWidget(
167              "menu" , xmRowColumnWidgetClass , wpop ,
168                 XmNpacking      , XmPACK_TIGHT ,
169                 XmNorientation  , XmVERTICAL ,
170                 XmNtraversalOn , False ,
171                 XmNinitialResourcesPersistent , False ,
172              NULL ) ;
173 
174    wlab = XtVaCreateManagedWidget(
175              "menu" , xmLabelWidgetClass , wrc ,
176                 LABEL_ARG("PostScript filename:\n[[or .jpg or .png ]]") ,
177                 XmNinitialResourcesPersistent , False ,
178              NULL ) ;
179 
180    mpcb->wtf = wtf = XtVaCreateManagedWidget(
181              "menu" , xmTextFieldWidgetClass , wrc ,
182                  XmNcolumns         , 20 ,
183                  XmNeditable        , True ,
184                  XmNmaxLength       , 32 ,
185                  XmNresizeWidth     , False ,
186                  XmNmarginHeight    , 1 ,
187                  XmNmarginWidth     , 1 ,
188                  XmNcursorPositionVisible , True ,
189                  XmNblinkRate , 0 ,
190                  XmNautoShowCursorPosition , True ,
191                  XmNinitialResourcesPersistent , False ,
192                  XmNtraversalOn , False ,
193               NULL ) ;
194    XtAddCallback( wtf, XmNactivateCallback, psfinalize_CB, cd ) ; /* return key */
195 
196 #undef TIG
197 #undef NBUT
198 #define TIG  20
199 #define NBUT 2
200 
201    form = XtVaCreateWidget( "menu" , xmFormWidgetClass , wrc ,
202                                XmNborderWidth , 0 ,
203                                XmNfractionBase , TIG*NBUT - 1 ,
204                                XmNinitialResourcesPersistent , False ,
205                             NULL ) ;
206 
207    ibut = 0 ;
208    but0 = XtVaCreateManagedWidget(
209                  "menu" , xmPushButtonWidgetClass , form ,
210                     LABEL_ARG("Cancel") ,
211                     XmNtopAttachment  , XmATTACH_FORM ,
212 
213                     XmNleftAttachment   ,
214                         (ibut!=0) ? XmATTACH_POSITION : XmATTACH_FORM ,
215                     XmNleftPosition , ibut*TIG ,
216 
217                     XmNrightAttachment  ,
218                      (ibut==NBUT-1) ? XmATTACH_FORM : XmATTACH_POSITION ,
219                     XmNrightPosition , ibut*TIG + (TIG-1) ,
220 
221                     XmNrecomputeSize , False ,
222                     XmNtraversalOn   , False ,
223                     XmNinitialResourcesPersistent , False ,
224                  NULL ) ;
225    XtAddCallback( but0 , XmNactivateCallback , pscancel_CB , cd ) ;
226 
227 
228    if( redcolor == NULL ){ HOTCOLOR(form,redcolor) ; }
229    ibut++ ;
230    but1 = XtVaCreateManagedWidget(
231                  "menu" , xmPushButtonWidgetClass , form ,
232                     LABEL_ARG("Save") ,
233 #if 1
234                     BGCOLOR_ARG(redcolor) ,
235 #endif
236 
237                     XmNtopAttachment  , XmATTACH_FORM ,
238 
239                     XmNleftAttachment   ,
240                         (ibut!=0) ? XmATTACH_POSITION : XmATTACH_FORM ,
241                     XmNleftPosition , ibut*TIG ,
242 
243                     XmNrightAttachment  ,
244                      (ibut==NBUT-1) ? XmATTACH_FORM : XmATTACH_POSITION ,
245                     XmNrightPosition , ibut*TIG + (TIG-1) ,
246 
247                     XmNrecomputeSize , False ,
248                     XmNtraversalOn   , False ,
249                     XmNinitialResourcesPersistent , False ,
250                  NULL ) ;
251    XtAddCallback( but1 , XmNactivateCallback , psfinalize_CB , cd ) ;
252 
253    XtTranslateCoords( mpcb->top , 15,15 , &xx , &yy ) ;
254    XtVaSetValues( wpop , XmNx , (int) xx , XmNy , (int) yy , NULL ) ;
255 
256    XtManageChild( form ) ;
257    XtManageChild( wrc ) ;
258    XtPopup( wpop , XtGrabNone ) ;
259    return ;
260 }
261 
262 /*--------------------------------------------------------------------------
263    Print plot to a PostScript printer (if possible)
264 ----------------------------------------------------------------------------*/
265 
pm_psprint_CB(Widget w,XtPointer cd,XtPointer cb)266 void pm_psprint_CB( Widget w , XtPointer cd , XtPointer cb )
267 {
268    MEM_topshell_data *mpcb = (MEM_topshell_data *) cd ;
269    MEM_plotdata *mp ;
270 
271    if( mpcb == NULL ) return ;
272    mp = mpcb->mp ; if( mp == NULL ) return ;
273    memplot_to_postscript( print_command , mp ) ;
274    return ;
275 }
276 
277 /*--------------------------------------------------------------------------
278    Close plot window
279 ----------------------------------------------------------------------------*/
280 
pm_donebut_CB(Widget w,XtPointer cd,XtPointer cb)281 void pm_donebut_CB( Widget w , XtPointer cd , XtPointer cb )
282 {
283    MEM_topshell_data * mpcb = (MEM_topshell_data *) cd ;
284    if( mpcb == NULL || ! MTD_VALID(mpcb) ) return ;
285 
286    mpcb->valid = 0 ;
287 
288    if( mpcb->killfunc != NULL )
289 #if 0
290      mpcb->killfunc( mpcb ) ;
291 #else
292      AFNI_CALL_VOID_1ARG( mpcb->killfunc , MEM_topshell_data * , mpcb ) ;
293 #endif
294    if( mpcb->dial != NULL ) XtDestroyWidget( mpcb->dial ) ;
295 #ifdef HAVE_XDBE
296    if( mpcb->have_xdbe )
297       XdbeDeallocateBackBufferName( XtDisplay(mpcb->top) , mpcb->buf_xdbe ) ;
298 #endif
299    XtDestroyWidget( mpcb->top ) ;
300    delete_memplot( mpcb->mp ) ;
301    free(mpcb) ;
302 
303    return ;
304 }
305 
306 /*--------------------------------------------------------------------------
307    Draw plot window
308 ----------------------------------------------------------------------------*/
309 
pm_expose_CB(Widget w,XtPointer cd,XtPointer cb)310 void pm_expose_CB( Widget w , XtPointer cd , XtPointer cb )
311 {
312    XmDrawingAreaCallbackStruct * cbs = (XmDrawingAreaCallbackStruct *) cb ;
313    MEM_topshell_data * mpcb = (MEM_topshell_data *) cd ;
314    MEM_plotdata * mp ;
315    XEvent evjunk ;
316    Display * dpy = XtDisplay(w) ;
317    Window  win   = XtWindow(w) ;
318    Drawable dw   = win ;                               /* draw into this */
319 
320    if( win == (Window) 0 ) return ;  /* no window yet? */
321    if( mpcb == NULL ) return ;
322    mp = mpcb->mp ; if( mp == NULL ) return ;
323 
324    if( cbs != NULL ){
325       XExposeEvent * ev = (XExposeEvent *) cbs->event ;
326       if( ev->count > 0 ) return ;
327    }
328 
329 #ifdef HAVE_XDBE
330    if( use_xdbe > 0 && mpcb->have_xdbe == 0 && get_XDBE_suspension(0)==0 ){
331       XdbeSwapInfo info_xdbe ;
332 
333       mpcb->buf_xdbe  = XdbeAllocateBackBufferName( dpy,win,XdbeBackground );
334       mpcb->have_xdbe = 1 ;
335 
336       set_X11_background( dpy , win , 255,255,255 ) ;
337       info_xdbe.swap_window = win ;
338       info_xdbe.swap_action = XdbeBackground ;
339       XdbeSwapBuffers( dpy , &info_xdbe , 1 ) ;
340    }
341 
342    if( mpcb->have_xdbe ) dw = mpcb->buf_xdbe ;         /* draw into this */
343 #endif
344 
345    set_X11_background( dpy , win , 255,255,255 ) ;
346    if( dw == win ) XClearWindow( dpy , win ) ;
347    memplot_to_X11_sef( dpy , dw , mp , 0,0,MEMPLOT_FREE_ASPECT ) ;
348 
349 #ifdef HAVE_XDBE
350    if( mpcb->have_xdbe ){
351       XdbeSwapInfo info_xdbe ;
352       info_xdbe.swap_window = win ;
353       info_xdbe.swap_action = XdbeBackground ;
354       XdbeSwapBuffers( dpy , &info_xdbe , 1 ) ;
355     }
356 #endif
357 
358    /* skip any future pending Expose events */
359 
360    while( XCheckWindowEvent(dpy, win ,
361                             ExposureMask|StructureNotifyMask,&evjunk) ) ;
362    return ;
363 }
364 
redraw_topshell(MEM_topshell_data * mpcb)365 void redraw_topshell( MEM_topshell_data * mpcb )
366 {
367    if( mpcb == NULL ) return ;
368    pm_expose_CB( mpcb->drawing , mpcb , NULL ) ;
369    return ;
370 }
371 
372 /*--------------------------------------------------------------------------
373    Redraw plot window after a resize notice
374 ----------------------------------------------------------------------------*/
375 
pm_resize_CB(Widget w,XtPointer cd,XtPointer cb)376 void pm_resize_CB( Widget w , XtPointer cd , XtPointer cb )
377 {
378    pm_expose_CB( w , cd , NULL ) ;
379    return ;
380 }
381 
382 /*--------------------------------------------------------------------------
383    Handle input to the drawing area (key or button press) - 06 Aug 2001
384 ----------------------------------------------------------------------------*/
385 
pm_input_CB(Widget w,XtPointer cd,XtPointer cb)386 void pm_input_CB( Widget w , XtPointer cd , XtPointer cb )
387 {
388    MEM_topshell_data * mpcb = (MEM_topshell_data *) cd ;
389    XmDrawingAreaCallbackStruct * cbs = (XmDrawingAreaCallbackStruct *) cb ;
390 
391    if( mpcb == NULL || ! MTD_VALID(mpcb)         ) return ;  /* bad */
392    if( cbs  == NULL || cbs->reason != XmCR_INPUT ) return ;  /* real bad */
393 
394    switch( cbs->event->type ){
395 
396       default: break ;
397 
398       /*----- take key press -----*/
399 
400       case KeyPress:{
401          XKeyEvent * event = (XKeyEvent *) cbs->event ;
402          char           buf[32] ;
403          KeySym         ks ;
404 
405          buf[0] = '\0' ;
406          XLookupString( event , buf , 32 , &ks , NULL ) ;
407 
408          switch( buf[0] ){
409             default: break;
410             case 'Q':
411             case 'q':
412                pm_donebut_CB( NULL , (XtPointer) mpcb , NULL ) ;
413                break ;
414          }
415          break ;
416       }
417       break ;
418    }
419 
420    return ;
421 }
422 
423 /*------------------------------------------------------------------
424    External killer, for use by user routines
425 --------------------------------------------------------------------*/
426 
plotkill_topshell(MEM_topshell_data * mpcb)427 void plotkill_topshell( MEM_topshell_data * mpcb )
428 {
429    if( mpcb == NULL || ! MTD_VALID(mpcb) ) return ;
430 
431    pm_donebut_CB( NULL , (XtPointer) mpcb , NULL ) ;
432    return ;
433 }
434 
435 /*---------------------------------------------------------------------------*/
436 
pm_decode_geom(char * geom,int * ww,int * hh,int * xx,int * yy)437 void pm_decode_geom( char * geom , int *ww, int *hh , int *xx, int *yy )
438 {
439    int has_x , has_plus ;
440 
441    *ww = *hh = *xx = *yy = -1 ;
442    if( geom == NULL || geom[0] == '\0' ) return ;
443 
444    has_x    = strstr(geom,"x") != NULL ;
445    has_plus = strstr(geom,"+") != NULL ;
446 
447    if( has_x && has_plus )
448       sscanf(geom,"%dx%d+%d+%d",ww,hh,xx,yy) ;
449    else if( has_x )
450       sscanf(geom,"%dx%d",ww,hh) ;
451    else if( has_plus )
452       sscanf(geom,"+%d+%d",xx,yy) ;
453 
454    return ;
455 }
456 
457 /*------------------------------------------------------------------
458    Make a toplevel widget and put an existing plot into it.
459 
460    If kfun is not NULL, when the user closes the window, it
461    will be called as in
462         kfun(mpcb) ;
463    where mpcb is the pointer returned by this function.
464    After this has been done, the memory used will be destroyed,
465    including all the contents of mp and mpcb.
466 
467    The user may attach extra data to the void * pointer
468    mpcb->userdata after this function returns mpcb.  If this
469    data involves the use of malloc, it is the user's responsibility
470    to free it in the call to kfun.
471 --------------------------------------------------------------------*/
472 
memplot_to_topshell(Display * dpy,MEM_plotdata * mp,void_func * kfun)473 MEM_topshell_data * memplot_to_topshell( Display *dpy,
474                                          MEM_plotdata *mp, void_func *kfun )
475 {
476    Widget topshell , drawing , donebut , form , psfilebut ,
477          psprintbut ;
478    MEM_topshell_data *mpcb ;
479    int hmin=400 , wmin , ibut=0 , hh,ww,xx,yy ;
480    char *prc , *ept ;
481 
482    /* sanity check */
483 
484    if( dpy == NULL || mp == NULL ) return NULL ;
485 
486    mpcb = (MEM_topshell_data *) malloc( sizeof(MEM_topshell_data) ) ;
487    memset((void*)mpcb, 0, sizeof(MEM_topshell_data));
488    mpcb->valid = 0 ;
489 
490 #ifdef HAVE_XDBE
491    init_XDBE(dpy) ; mpcb->have_xdbe = 0 ;
492 #endif
493 
494    wmin = MEMPLOT_ASPECT(mp) * hmin ;
495 
496    /* 12 Oct 2000: a crude way to set the geometry of the popup */
497 
498    pm_decode_geom( getenv("AFNI_tsplotgeom") , &ww,&hh,&xx,&yy ) ;
499    if( ww < wmin ) ww = wmin ;
500    if( hh < hmin ) hh = hmin ;
501 
502    /* shell to hold it all */
503 
504    topshell = XtVaAppCreateShell(
505                  "AFNI" , "AFNI" , topLevelShellWidgetClass , dpy ,
506                    XmNborderWidth ,   0  ,
507                    XmNminHeight   , hmin , XmNheight , hh ,
508                    XmNminWidth    , wmin , XmNwidth  , ww ,
509                    XmNallowShellResize , False ,
510                    XmNinitialResourcesPersistent , False ,
511                    XmNdeleteResponse   , XmDO_NOTHING , /* deletion handled
512                                                             below */
513                  NULL ) ;
514    XtVaSetValues(topshell, XmNtitle, wintitle, NULL); /* ZSS Oct 7 2009 */
515 
516    XmAddWMProtocolCallback(
517         topshell , XmInternAtom(dpy,"WM_DELETE_WINDOW",False) ,
518         pm_donebut_CB , (XtPointer) mpcb ) ;
519 
520    mpcb->top = topshell ;
521    mpcb->mp  = mp ;
522    mpcb->dial= NULL ;
523    mpcb->wtf = NULL ;
524 
525    mpcb->killfunc = kfun ;
526 
527    /* form to manage it all */
528 
529 #undef TIG
530 #undef NBUT
531 #define TIG  20
532 #define NBUT 3
533 
534    mpcb->form = form =
535         XtVaCreateWidget( "dialog" , xmFormWidgetClass , topshell ,
536                              XmNborderWidth , 0 ,
537                              XmNfractionBase , TIG*NBUT - 1 ,
538                              XmNinitialResourcesPersistent , False ,
539                           NULL ) ;
540 
541    /* buttons across the top */
542 
543    if( redcolor == NULL ){ HOTCOLOR(form,redcolor) ; }
544 
545    ibut = 0 ;
546    psfilebut = XtVaCreateManagedWidget(
547                  "dialog" , xmPushButtonWidgetClass , form ,
548                     LABEL_ARG("save image to file") ,
549                     XmNtopAttachment  , XmATTACH_FORM ,
550 
551                     XmNleftAttachment   ,
552                         (ibut!=0) ? XmATTACH_POSITION : XmATTACH_FORM ,
553                     XmNleftPosition , ibut*TIG ,
554 
555                     XmNrightAttachment  ,
556                      (ibut==NBUT-1) ? XmATTACH_FORM : XmATTACH_POSITION ,
557                     XmNrightPosition , ibut*TIG + (TIG-1) ,
558 
559                     XmNrecomputeSize , False ,
560                     XmNtraversalOn   , False ,
561                     XmNinitialResourcesPersistent , False ,
562                  NULL ) ;
563    XtAddCallback( psfilebut , XmNactivateCallback , pm_psfile_CB , (XtPointer) mpcb ) ;
564 
565    ibut++ ;
566    psprintbut = XtVaCreateManagedWidget(
567                  "dialog" , xmPushButtonWidgetClass , form ,
568                     LABEL_ARG("to printer") ,
569                     XmNtopAttachment  , XmATTACH_FORM ,
570 
571                     XmNleftAttachment   ,
572                         (ibut!=0) ? XmATTACH_POSITION : XmATTACH_FORM ,
573                     XmNleftPosition , ibut*TIG ,
574 
575                     XmNrightAttachment  ,
576                      (ibut==NBUT-1) ? XmATTACH_FORM : XmATTACH_POSITION ,
577                     XmNrightPosition , ibut*TIG + (TIG-1) ,
578 
579                     XmNrecomputeSize , False ,
580                     XmNtraversalOn   , False ,
581                     XmNinitialResourcesPersistent , False ,
582                  NULL ) ;
583    prc = getenv( "AFNI_PSPRINT" ) ;
584    if( prc != NULL ){
585       sprintf( print_command , "|%.250s" , prc ) ;
586       XtAddCallback( psprintbut , XmNactivateCallback , pm_psprint_CB , (XtPointer) mpcb ) ;
587    } else {
588 #if 0
589       XtAddCallback( psprintbut , XmNactivateCallback , beep_CB ,
590                      (XtPointer)"*** AFNI_PSPRINT not defined - see README.environment" );
591 #elif 0
592       XtSetSensitive( psprintbut , False ) ;  /* 05 Nov 2001 */
593 #else
594       XtUnmanageChild( psprintbut ) ;
595 #endif
596    }
597 
598    ibut++ ;
599    donebut = XtVaCreateManagedWidget(
600                  "dialog" , xmPushButtonWidgetClass , form ,
601                     LABEL_ARG("Done") ,
602 #if 1
603                     BGCOLOR_ARG(redcolor) ,
604 #endif
605 
606                     XmNtopAttachment  , XmATTACH_FORM ,
607 
608                     XmNleftAttachment   ,
609                         (ibut!=0) ? XmATTACH_POSITION : XmATTACH_FORM ,
610                     XmNleftPosition , ibut*TIG ,
611 
612                     XmNrightAttachment  ,
613                      (ibut==NBUT-1) ? XmATTACH_FORM : XmATTACH_POSITION ,
614                     XmNrightPosition , ibut*TIG + (TIG-1) ,
615 
616                     XmNrecomputeSize , False ,
617                     XmNtraversalOn   , False ,
618                     XmNinitialResourcesPersistent , False ,
619                  NULL ) ;
620    XtAddCallback( donebut , XmNactivateCallback , pm_donebut_CB , (XtPointer) mpcb ) ;
621 
622    /* drawing area to receive the picture */
623 
624    drawing = XtVaCreateManagedWidget( "dialog" , xmDrawingAreaWidgetClass , form ,
625                                           XmNtopAttachment    , XmATTACH_WIDGET ,
626                                           XmNtopWidget        , donebut ,
627                                           XmNleftAttachment   , XmATTACH_FORM ,
628                                           XmNrightAttachment  , XmATTACH_FORM ,
629                                           XmNbottomAttachment , XmATTACH_FORM ,
630                                           XmNinitialResourcesPersistent , False ,
631                                         NULL ) ;
632 
633    XtAddCallback( drawing , XmNexposeCallback , pm_expose_CB , (XtPointer) mpcb ) ;
634    XtAddCallback( drawing , XmNresizeCallback , pm_resize_CB , (XtPointer) mpcb ) ;
635    XtAddCallback( drawing , XmNinputCallback  , pm_input_CB  , (XtPointer) mpcb ) ;
636 
637    /* finish the job */
638 
639    XtVaSetValues( form , BGCOLOR_ARG("white") , NULL ) ;
640 
641    if( xx >= 0 && yy >= 0 )
642       XtVaSetValues( topshell , XmNx,xx , XmNy,yy , NULL ) ;
643 
644    XtManageChild(form) ;
645    XtRealizeWidget(topshell);
646 
647    mpcb->valid = 1 ; mpcb->userdata = NULL ; mpcb->drawing = drawing ;
648    return mpcb ;
649 }
650