#include "coxplot.h" #include #include #include "mcw_malloc.h" /* ZSS: Needed because SUMA_plot.c does allocate some pointers freed here Jan 09 */ #include "Amalloc.h" /***************************************************************************** This software is copyrighted and owned by the Medical College of Wisconsin. See the file README.Copyright for details. ******************************************************************************/ static char print_command[256] = "\0" ; static char *redcolor = NULL ; static char wintitle[128] = {"AFNI"}; /* ZSS Oct 7 2009 */ void set_wintitle_memplot( char *s ) /* ZSS Oct 7 2009 */ { if (s) { snprintf(wintitle, 125*sizeof(char), "%s", s); } else { sprintf(wintitle,"AFNI"); } return; } #ifndef LABEL_ARG #define LABEL_ARG(str) \ XtVaTypedArg , XmNlabelString , XmRString , (str) , strlen(str)+1 #endif /*--------------------------------------------------------------------------*/ #undef STRING_HAS_SUFFIX #define STRING_HAS_SUFFIX(ss,suf) \ ((ss != NULL) && (suf != NULL) && \ (strlen(ss) >= strlen(suf)) && \ (strcmp(ss+strlen(ss)-strlen(suf),suf) == 0)) typedef void vpfunc(char *,MEM_plotdata *) ; typedef struct { char *suf ; vpfunc *fun ; } saver_pair ; static int num_spair = 0 ; static saver_pair *spair = NULL ; void memplot_topshell_setsaver( char *suf, void (*fun)(char *,MEM_plotdata *) ) { int nn ; if( suf == NULL || *suf == '\0' || fun == NULL ) return ; for( nn=0 ; nn < num_spair ; nn++ ) if( strcmp(suf,spair[nn].suf) == 0 ) return ; nn = num_spair + 1 ; spair = (saver_pair *)realloc( (void *)spair , sizeof(saver_pair)*nn ) ; spair[num_spair].suf = strdup(suf) ; spair[num_spair].fun = fun ; num_spair = nn ; return ; } /*========================================================================== Callback routines for memplot_to_topshell ============================================================================*/ /*--------------------------------------------------------------------------*/ static void beep_CB( Widget w , XtPointer cd , XtPointer cb ) { char * str = (char *) cd ; if( w != NULL ) XBell(XtDisplay(w),100) ; if( str != NULL && str[0] != '\0' ) fprintf(stderr,"%s\a\n",str) ; return ; } /*-------------------------------------------------------------------------- Save plot to a PostScript file ----------------------------------------------------------------------------*/ /****** cancellation of a print request ******/ static void pscancel_CB( Widget w , XtPointer cd , XtPointer cb ) { MEM_topshell_data *mpcb = (MEM_topshell_data *) cd ; if( mpcb == NULL || ! MTD_VALID(mpcb) ) return ; if( mpcb->dial != NULL ) XtDestroyWidget( mpcb->dial ) ; mpcb->dial = mpcb->wtf = NULL ; return ; } /****** finalization of a print request ******/ static void psfinalize_CB( Widget w , XtPointer cd , XtPointer cb ) { MEM_topshell_data *mpcb = (MEM_topshell_data *) cd ; char *text , fname[128] ; int ii , ll ; if( mpcb == NULL || ! MTD_VALID(mpcb) ) return ; if( mpcb->dial == NULL ){ XBell(XtDisplay(w),100) ; return ; } text = XmTextFieldGetString( mpcb->wtf ) ; if( text == NULL || text[0] == '\0' ){ XBell(XtDisplay(w),100) ; return ; } ll = strlen(text) ; for( ii=0 ; ii < ll ; ii++ ){ if( iscntrl(text[ii]) || isspace(text[ii]) || text[ii] == '/' || text[ii] == ';' || text[ii] == '*' || text[ii] == '?' || text[ii] == '&' || text[ii] == '|' || text[ii] == '"' || text[ii] == '>' || text[ii] == '<' || text[ii] == '\'' || text[ii] == '[' || text[ii] == ']' ){ XBell(XtDisplay(w),100) ; return ; } } strcpy(fname,text) ; for( ii=0 ; ii < num_spair ; ii++ ){ /* 05 Dec 2007 */ if( STRING_HAS_SUFFIX(fname,spair[ii].suf) ){ spair[ii].fun( fname , mpcb->mp ) ; XtDestroyWidget( mpcb->dial ) ; mpcb->dial = mpcb->wtf = NULL ; return ; } } if( !STRING_HAS_SUFFIX(text,"ps") ) strcat(fname,".ps") ; memplot_to_postscript( fname , mpcb->mp ) ; XtDestroyWidget( mpcb->dial ) ; mpcb->dial = mpcb->wtf = NULL ; return ; } /****** initiation of a print request ******/ void pm_psfile_CB( Widget w , XtPointer cd , XtPointer cb ) { MEM_topshell_data * mpcb = (MEM_topshell_data *) cd ; Widget wpop , wrc , wlab , wtf , form , but0 , but1 ; int ibut = 0 ; Position xx,yy ; if( mpcb == NULL || ! MTD_VALID(mpcb) ) return ; if( mpcb->dial != NULL ){ XBell(XtDisplay(w),100) ; return ; } mpcb->dial = wpop = XtVaCreatePopupShell( "AFNI" , xmDialogShellWidgetClass , mpcb->top , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; XtVaSetValues( wpop , XmNmwmDecorations , MWM_DECOR_BORDER , XmNmwmFunctions , MWM_FUNC_MOVE , NULL ) ; wrc = XtVaCreateWidget( "menu" , xmRowColumnWidgetClass , wpop , XmNpacking , XmPACK_TIGHT , XmNorientation , XmVERTICAL , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; wlab = XtVaCreateManagedWidget( "menu" , xmLabelWidgetClass , wrc , LABEL_ARG("PostScript filename:\n[[or .jpg or .png ]]") , XmNinitialResourcesPersistent , False , NULL ) ; mpcb->wtf = wtf = XtVaCreateManagedWidget( "menu" , xmTextFieldWidgetClass , wrc , XmNcolumns , 20 , XmNeditable , True , XmNmaxLength , 32 , XmNresizeWidth , False , XmNmarginHeight , 1 , XmNmarginWidth , 1 , XmNcursorPositionVisible , True , XmNblinkRate , 0 , XmNautoShowCursorPosition , True , XmNinitialResourcesPersistent , False , XmNtraversalOn , False , NULL ) ; XtAddCallback( wtf, XmNactivateCallback, psfinalize_CB, cd ) ; /* return key */ #undef TIG #undef NBUT #define TIG 20 #define NBUT 2 form = XtVaCreateWidget( "menu" , xmFormWidgetClass , wrc , XmNborderWidth , 0 , XmNfractionBase , TIG*NBUT - 1 , XmNinitialResourcesPersistent , False , NULL ) ; ibut = 0 ; but0 = XtVaCreateManagedWidget( "menu" , xmPushButtonWidgetClass , form , LABEL_ARG("Cancel") , XmNtopAttachment , XmATTACH_FORM , XmNleftAttachment , (ibut!=0) ? XmATTACH_POSITION : XmATTACH_FORM , XmNleftPosition , ibut*TIG , XmNrightAttachment , (ibut==NBUT-1) ? XmATTACH_FORM : XmATTACH_POSITION , XmNrightPosition , ibut*TIG + (TIG-1) , XmNrecomputeSize , False , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; XtAddCallback( but0 , XmNactivateCallback , pscancel_CB , cd ) ; if( redcolor == NULL ){ HOTCOLOR(form,redcolor) ; } ibut++ ; but1 = XtVaCreateManagedWidget( "menu" , xmPushButtonWidgetClass , form , LABEL_ARG("Save") , #if 1 BGCOLOR_ARG(redcolor) , #endif XmNtopAttachment , XmATTACH_FORM , XmNleftAttachment , (ibut!=0) ? XmATTACH_POSITION : XmATTACH_FORM , XmNleftPosition , ibut*TIG , XmNrightAttachment , (ibut==NBUT-1) ? XmATTACH_FORM : XmATTACH_POSITION , XmNrightPosition , ibut*TIG + (TIG-1) , XmNrecomputeSize , False , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; XtAddCallback( but1 , XmNactivateCallback , psfinalize_CB , cd ) ; XtTranslateCoords( mpcb->top , 15,15 , &xx , &yy ) ; XtVaSetValues( wpop , XmNx , (int) xx , XmNy , (int) yy , NULL ) ; XtManageChild( form ) ; XtManageChild( wrc ) ; XtPopup( wpop , XtGrabNone ) ; return ; } /*-------------------------------------------------------------------------- Print plot to a PostScript printer (if possible) ----------------------------------------------------------------------------*/ void pm_psprint_CB( Widget w , XtPointer cd , XtPointer cb ) { MEM_topshell_data *mpcb = (MEM_topshell_data *) cd ; MEM_plotdata *mp ; if( mpcb == NULL ) return ; mp = mpcb->mp ; if( mp == NULL ) return ; memplot_to_postscript( print_command , mp ) ; return ; } /*-------------------------------------------------------------------------- Close plot window ----------------------------------------------------------------------------*/ void pm_donebut_CB( Widget w , XtPointer cd , XtPointer cb ) { MEM_topshell_data * mpcb = (MEM_topshell_data *) cd ; if( mpcb == NULL || ! MTD_VALID(mpcb) ) return ; mpcb->valid = 0 ; if( mpcb->killfunc != NULL ) #if 0 mpcb->killfunc( mpcb ) ; #else AFNI_CALL_VOID_1ARG( mpcb->killfunc , MEM_topshell_data * , mpcb ) ; #endif if( mpcb->dial != NULL ) XtDestroyWidget( mpcb->dial ) ; #ifdef HAVE_XDBE if( mpcb->have_xdbe ) XdbeDeallocateBackBufferName( XtDisplay(mpcb->top) , mpcb->buf_xdbe ) ; #endif XtDestroyWidget( mpcb->top ) ; delete_memplot( mpcb->mp ) ; free(mpcb) ; return ; } /*-------------------------------------------------------------------------- Draw plot window ----------------------------------------------------------------------------*/ void pm_expose_CB( Widget w , XtPointer cd , XtPointer cb ) { XmDrawingAreaCallbackStruct * cbs = (XmDrawingAreaCallbackStruct *) cb ; MEM_topshell_data * mpcb = (MEM_topshell_data *) cd ; MEM_plotdata * mp ; XEvent evjunk ; Display * dpy = XtDisplay(w) ; Window win = XtWindow(w) ; Drawable dw = win ; /* draw into this */ if( win == (Window) 0 ) return ; /* no window yet? */ if( mpcb == NULL ) return ; mp = mpcb->mp ; if( mp == NULL ) return ; if( cbs != NULL ){ XExposeEvent * ev = (XExposeEvent *) cbs->event ; if( ev->count > 0 ) return ; } #ifdef HAVE_XDBE if( use_xdbe > 0 && mpcb->have_xdbe == 0 && get_XDBE_suspension(0)==0 ){ XdbeSwapInfo info_xdbe ; mpcb->buf_xdbe = XdbeAllocateBackBufferName( dpy,win,XdbeBackground ); mpcb->have_xdbe = 1 ; set_X11_background( dpy , win , 255,255,255 ) ; info_xdbe.swap_window = win ; info_xdbe.swap_action = XdbeBackground ; XdbeSwapBuffers( dpy , &info_xdbe , 1 ) ; } if( mpcb->have_xdbe ) dw = mpcb->buf_xdbe ; /* draw into this */ #endif set_X11_background( dpy , win , 255,255,255 ) ; if( dw == win ) XClearWindow( dpy , win ) ; memplot_to_X11_sef( dpy , dw , mp , 0,0,MEMPLOT_FREE_ASPECT ) ; #ifdef HAVE_XDBE if( mpcb->have_xdbe ){ XdbeSwapInfo info_xdbe ; info_xdbe.swap_window = win ; info_xdbe.swap_action = XdbeBackground ; XdbeSwapBuffers( dpy , &info_xdbe , 1 ) ; } #endif /* skip any future pending Expose events */ while( XCheckWindowEvent(dpy, win , ExposureMask|StructureNotifyMask,&evjunk) ) ; return ; } void redraw_topshell( MEM_topshell_data * mpcb ) { if( mpcb == NULL ) return ; pm_expose_CB( mpcb->drawing , mpcb , NULL ) ; return ; } /*-------------------------------------------------------------------------- Redraw plot window after a resize notice ----------------------------------------------------------------------------*/ void pm_resize_CB( Widget w , XtPointer cd , XtPointer cb ) { pm_expose_CB( w , cd , NULL ) ; return ; } /*-------------------------------------------------------------------------- Handle input to the drawing area (key or button press) - 06 Aug 2001 ----------------------------------------------------------------------------*/ void pm_input_CB( Widget w , XtPointer cd , XtPointer cb ) { MEM_topshell_data * mpcb = (MEM_topshell_data *) cd ; XmDrawingAreaCallbackStruct * cbs = (XmDrawingAreaCallbackStruct *) cb ; if( mpcb == NULL || ! MTD_VALID(mpcb) ) return ; /* bad */ if( cbs == NULL || cbs->reason != XmCR_INPUT ) return ; /* real bad */ switch( cbs->event->type ){ default: break ; /*----- take key press -----*/ case KeyPress:{ XKeyEvent * event = (XKeyEvent *) cbs->event ; char buf[32] ; KeySym ks ; buf[0] = '\0' ; XLookupString( event , buf , 32 , &ks , NULL ) ; switch( buf[0] ){ default: break; case 'Q': case 'q': pm_donebut_CB( NULL , (XtPointer) mpcb , NULL ) ; break ; } break ; } break ; } return ; } /*------------------------------------------------------------------ External killer, for use by user routines --------------------------------------------------------------------*/ void plotkill_topshell( MEM_topshell_data * mpcb ) { if( mpcb == NULL || ! MTD_VALID(mpcb) ) return ; pm_donebut_CB( NULL , (XtPointer) mpcb , NULL ) ; return ; } /*---------------------------------------------------------------------------*/ void pm_decode_geom( char * geom , int *ww, int *hh , int *xx, int *yy ) { int has_x , has_plus ; *ww = *hh = *xx = *yy = -1 ; if( geom == NULL || geom[0] == '\0' ) return ; has_x = strstr(geom,"x") != NULL ; has_plus = strstr(geom,"+") != NULL ; if( has_x && has_plus ) sscanf(geom,"%dx%d+%d+%d",ww,hh,xx,yy) ; else if( has_x ) sscanf(geom,"%dx%d",ww,hh) ; else if( has_plus ) sscanf(geom,"+%d+%d",xx,yy) ; return ; } /*------------------------------------------------------------------ Make a toplevel widget and put an existing plot into it. If kfun is not NULL, when the user closes the window, it will be called as in kfun(mpcb) ; where mpcb is the pointer returned by this function. After this has been done, the memory used will be destroyed, including all the contents of mp and mpcb. The user may attach extra data to the void * pointer mpcb->userdata after this function returns mpcb. If this data involves the use of malloc, it is the user's responsibility to free it in the call to kfun. --------------------------------------------------------------------*/ MEM_topshell_data * memplot_to_topshell( Display *dpy, MEM_plotdata *mp, void_func *kfun ) { Widget topshell , drawing , donebut , form , psfilebut , psprintbut ; MEM_topshell_data *mpcb ; int hmin=400 , wmin , ibut=0 , hh,ww,xx,yy ; char *prc , *ept ; /* sanity check */ if( dpy == NULL || mp == NULL ) return NULL ; mpcb = (MEM_topshell_data *) malloc( sizeof(MEM_topshell_data) ) ; memset((void*)mpcb, 0, sizeof(MEM_topshell_data)); mpcb->valid = 0 ; #ifdef HAVE_XDBE init_XDBE(dpy) ; mpcb->have_xdbe = 0 ; #endif wmin = MEMPLOT_ASPECT(mp) * hmin ; /* 12 Oct 2000: a crude way to set the geometry of the popup */ pm_decode_geom( getenv("AFNI_tsplotgeom") , &ww,&hh,&xx,&yy ) ; if( ww < wmin ) ww = wmin ; if( hh < hmin ) hh = hmin ; /* shell to hold it all */ topshell = XtVaAppCreateShell( "AFNI" , "AFNI" , topLevelShellWidgetClass , dpy , XmNborderWidth , 0 , XmNminHeight , hmin , XmNheight , hh , XmNminWidth , wmin , XmNwidth , ww , XmNallowShellResize , False , XmNinitialResourcesPersistent , False , XmNdeleteResponse , XmDO_NOTHING , /* deletion handled below */ NULL ) ; XtVaSetValues(topshell, XmNtitle, wintitle, NULL); /* ZSS Oct 7 2009 */ XmAddWMProtocolCallback( topshell , XmInternAtom(dpy,"WM_DELETE_WINDOW",False) , pm_donebut_CB , (XtPointer) mpcb ) ; mpcb->top = topshell ; mpcb->mp = mp ; mpcb->dial= NULL ; mpcb->wtf = NULL ; mpcb->killfunc = kfun ; /* form to manage it all */ #undef TIG #undef NBUT #define TIG 20 #define NBUT 3 mpcb->form = form = XtVaCreateWidget( "dialog" , xmFormWidgetClass , topshell , XmNborderWidth , 0 , XmNfractionBase , TIG*NBUT - 1 , XmNinitialResourcesPersistent , False , NULL ) ; /* buttons across the top */ if( redcolor == NULL ){ HOTCOLOR(form,redcolor) ; } ibut = 0 ; psfilebut = XtVaCreateManagedWidget( "dialog" , xmPushButtonWidgetClass , form , LABEL_ARG("save image to file") , XmNtopAttachment , XmATTACH_FORM , XmNleftAttachment , (ibut!=0) ? XmATTACH_POSITION : XmATTACH_FORM , XmNleftPosition , ibut*TIG , XmNrightAttachment , (ibut==NBUT-1) ? XmATTACH_FORM : XmATTACH_POSITION , XmNrightPosition , ibut*TIG + (TIG-1) , XmNrecomputeSize , False , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; XtAddCallback( psfilebut , XmNactivateCallback , pm_psfile_CB , (XtPointer) mpcb ) ; ibut++ ; psprintbut = XtVaCreateManagedWidget( "dialog" , xmPushButtonWidgetClass , form , LABEL_ARG("to printer") , XmNtopAttachment , XmATTACH_FORM , XmNleftAttachment , (ibut!=0) ? XmATTACH_POSITION : XmATTACH_FORM , XmNleftPosition , ibut*TIG , XmNrightAttachment , (ibut==NBUT-1) ? XmATTACH_FORM : XmATTACH_POSITION , XmNrightPosition , ibut*TIG + (TIG-1) , XmNrecomputeSize , False , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; prc = getenv( "AFNI_PSPRINT" ) ; if( prc != NULL ){ sprintf( print_command , "|%.250s" , prc ) ; XtAddCallback( psprintbut , XmNactivateCallback , pm_psprint_CB , (XtPointer) mpcb ) ; } else { #if 0 XtAddCallback( psprintbut , XmNactivateCallback , beep_CB , (XtPointer)"*** AFNI_PSPRINT not defined - see README.environment" ); #elif 0 XtSetSensitive( psprintbut , False ) ; /* 05 Nov 2001 */ #else XtUnmanageChild( psprintbut ) ; #endif } ibut++ ; donebut = XtVaCreateManagedWidget( "dialog" , xmPushButtonWidgetClass , form , LABEL_ARG("Done") , #if 1 BGCOLOR_ARG(redcolor) , #endif XmNtopAttachment , XmATTACH_FORM , XmNleftAttachment , (ibut!=0) ? XmATTACH_POSITION : XmATTACH_FORM , XmNleftPosition , ibut*TIG , XmNrightAttachment , (ibut==NBUT-1) ? XmATTACH_FORM : XmATTACH_POSITION , XmNrightPosition , ibut*TIG + (TIG-1) , XmNrecomputeSize , False , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; XtAddCallback( donebut , XmNactivateCallback , pm_donebut_CB , (XtPointer) mpcb ) ; /* drawing area to receive the picture */ drawing = XtVaCreateManagedWidget( "dialog" , xmDrawingAreaWidgetClass , form , XmNtopAttachment , XmATTACH_WIDGET , XmNtopWidget , donebut , XmNleftAttachment , XmATTACH_FORM , XmNrightAttachment , XmATTACH_FORM , XmNbottomAttachment , XmATTACH_FORM , XmNinitialResourcesPersistent , False , NULL ) ; XtAddCallback( drawing , XmNexposeCallback , pm_expose_CB , (XtPointer) mpcb ) ; XtAddCallback( drawing , XmNresizeCallback , pm_resize_CB , (XtPointer) mpcb ) ; XtAddCallback( drawing , XmNinputCallback , pm_input_CB , (XtPointer) mpcb ) ; /* finish the job */ XtVaSetValues( form , BGCOLOR_ARG("white") , NULL ) ; if( xx >= 0 && yy >= 0 ) XtVaSetValues( topshell , XmNx,xx , XmNy,yy , NULL ) ; XtManageChild(form) ; XtRealizeWidget(topshell); mpcb->valid = 1 ; mpcb->userdata = NULL ; mpcb->drawing = drawing ; return mpcb ; }