Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

afni_plugin.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002    Major portions of this software are copyrighted by the Medical College
00003    of Wisconsin, 1994-2000, and are released under the Gnu General Public
00004    License, Version 2.  See the file README.Copyright for details.
00005 ******************************************************************************/
00006 
00007 #undef MAIN
00008 #include "afni.h"
00009 
00010 #include "mri_render.h"
00011 #include "mcw_graf.h"
00012 #include "parser.h"
00013 
00014 /*========================================================================*/
00015 /*==== Compile this only if plugins are properly enabled in machdep.h ====*/
00016 
00017 #ifdef ALLOW_PLUGINS
00018 
00019 #define EMPTY_STRING "\0"
00020 
00021 #define COLSIZE AV_colsize()
00022 
00023 /***************************************************************************
00024    Routines to open and initialize plugins.  These should only
00025    be called at the very end of AFNI initialization, since they
00026    will call each plugin's internal initializer function, which
00027    may make requests to get AFNI data structures.
00028 ****************************************************************************/
00029 
00030 /*================ dynamic loading of plugins is allowed ==================*/
00031 #ifndef NO_DYNAMIC_LOADING
00032 
00033 /*-------------------------------------------------------------------------
00034    Routine to read in all plugins found in a given directory
00035 ---------------------------------------------------------------------------*/
00036 
00037 AFNI_plugin_array * PLUG_get_all_plugins( char * dname )
00038 {
00039    THD_string_array * flist , * rlist ;
00040    int ir , ii ;
00041    char * fname , * suff ;
00042    AFNI_plugin_array * outar ;
00043    AFNI_plugin       * plin ;
00044 
00045    /*----- sanity check and initialize -----*/
00046 
00047 ENTRY("PLUG_get_all_plugins") ;
00048 
00049    if( dname == NULL || strlen(dname) == 0 ) RETURN(NULL) ;
00050    if( ! THD_is_directory(dname) )           RETURN(NULL) ;
00051 
00052    INIT_PLUGIN_ARRAY( outar ) ;
00053 
00054 if(PRINT_TRACING)
00055 { char str[256] ; sprintf(str,"scanning directory %s",dname) ; STATUS(str) ; }
00056 
00057    /*----- find all filenames -----*/
00058 
00059    flist = THD_get_all_filenames( dname ) ;
00060    if( flist == NULL || flist->num <= 0 ){
00061       DESTROY_SARR(flist) ;
00062       DESTROY_PLUGIN_ARRAY(outar) ;
00063       RETURN(NULL) ;
00064    }
00065 
00066    rlist = THD_extract_regular_files( flist ) ;
00067    DESTROY_SARR(flist) ;
00068    if( rlist == NULL || rlist->num <= 0 ){
00069       DESTROY_SARR(rlist) ;
00070       DESTROY_PLUGIN_ARRAY(outar) ;
00071       RETURN(NULL) ;
00072    }
00073 
00074 if(PRINT_TRACING)
00075 { char str[256] ; sprintf(str,"%d files to scan",rlist->num) ; STATUS(str) ; }
00076 
00077    /*----- scan thru and find all filenames ending in DYNAMIC_suffix -----*/
00078 
00079    for( ir=0 ; ir < rlist->num ; ir++ ){
00080       fname = rlist->ar[ir] ; if( fname == NULL ) continue ;
00081       if( strstr(fname,"plug") == NULL ) continue ;
00082 
00083       suff = strstr(fname,DYNAMIC_suffix) ;
00084       if( suff != NULL && strlen(suff) == strlen(DYNAMIC_suffix) ){
00085          plin  = PLUG_read_plugin( fname ) ;
00086          if( plin != NULL ) ADDTO_PLUGIN_ARRAY( outar , plin ) ;
00087       }
00088    }
00089 
00090 if(PRINT_TRACING)
00091 { char str[256] ;
00092   sprintf(str,"directory %s has %d plugins",dname,outar->num) ; STATUS(str) ; }
00093 
00094    DESTROY_SARR(rlist) ;
00095    if( outar->num == 0 ) DESTROY_PLUGIN_ARRAY(outar) ;
00096 
00097    /* 06 Aug 1999: sort array by seqcodes */
00098 
00099    if( outar != NULL && outar->num > 1 ){
00100       int iid , qq ; AFNI_plugin * plin ;
00101       do{ qq = 0 ;
00102           for( iid=1 ; iid < outar->num ; iid++ )
00103              if( strcmp(outar->plar[iid-1]->seqcode,
00104                         outar->plar[iid  ]->seqcode ) > 0 ){
00105 
00106                 plin               = outar->plar[iid-1] ;
00107                 outar->plar[iid-1] = outar->plar[iid] ;
00108                 outar->plar[iid]   = plin ;
00109                 qq++ ;
00110              }
00111       } while( qq > 0 ) ;
00112    }
00113 
00114    RETURN(outar) ;
00115 }
00116 
00117 /*----------------------------------------------------------------------
00118    Routine to open and initialize a single plugin
00119 ------------------------------------------------------------------------*/
00120 
00121 AFNI_plugin * PLUG_read_plugin( char * fname )
00122 {
00123    AFNI_plugin * plin ;
00124    PLUGIN_interface * plint ;
00125    int nin ;
00126    static int firsterr=1 ;
00127 
00128    /*----- sanity checks -----*/
00129 
00130 ENTRY("PLUG_read_plugin") ;
00131 
00132    if( fname == NULL || strlen(fname) == 0 ) RETURN(NULL) ;
00133    if( ! THD_is_file(fname) )                RETURN(NULL) ;
00134 
00135    /*----- make space for new plugin -----*/
00136 
00137    plin = (AFNI_plugin *) XtMalloc( sizeof(AFNI_plugin) ) ;
00138    plin->type = AFNI_PLUGIN_TYPE ;
00139 
00140    /*----- copy name into plin structure -----*/
00141 
00142    MCW_strncpy( plin->libname , fname , MAX_PLUGIN_NAME ) ;
00143 
00144    /*----- open the library (we hope) -----*/
00145 
00146 if(PRINT_TRACING)
00147 { char str[256] ;
00148   sprintf(str,"opening plugin %s" , fname ) ; STATUS(str) ; }
00149 
00150    DYNAMIC_OPEN( fname , plin->libhandle ) ;
00151 
00152 STATUS("returned from DYNAMIC_OPEN()") ;
00153 
00154    if( ! ISVALID_DYNAMIC_handle( plin->libhandle ) ){  /* open failed */
00155 
00156       /* 24 May 2001: always print if there is an error */
00157 
00158       char *er ;
00159       if( firsterr ){fprintf(stderr,"\n"); firsterr=0; }
00160       fprintf(stderr,"Failed to open plugin %s",fname) ;
00161       er = (char *)DYNAMIC_ERROR_STRING ;
00162       if( er != NULL ) fprintf(stderr," -- %s\n",er) ;
00163       else             fprintf(stderr,"\n") ;
00164 
00165       myXtFree(plin) ; RETURN(NULL) ;
00166    }
00167 
00168    /* open was good */
00169 
00170 if(PRINT_TRACING)
00171 { char str[256] ;
00172   sprintf(str,"opened library %s with handle %p" , fname,plin->libhandle ) ;
00173   STATUS(str) ; }
00174 
00175    /*----- find the required symbol -----*/
00176    /*..... 13 Sep 2001: add _ for stupid Darwin .....*/
00177    /*..... 30 Oct 2003: remove for OS X 10.3    .....*/
00178 
00179 #ifndef NEED_UNDERSCORE
00180    DYNAMIC_SYMBOL(plin->libhandle, "PLUGIN_init" , plin->libinit_func );
00181 #else
00182    DYNAMIC_SYMBOL(plin->libhandle,"_PLUGIN_init" , plin->libinit_func );
00183 #endif
00184 
00185    /*----- if symbol not found, complain and kill this plugin -----*/
00186 
00187    if( plin->libinit_func == (vptr_func *) NULL ){
00188       char *er = (char *)DYNAMIC_ERROR_STRING ;
00189       if( firsterr ){fprintf(stderr,"\n"); firsterr=0; }
00190       fprintf(stderr,"plugin %s lacks PLUGIN_init() function\n",fname) ;
00191       if( er != NULL ) fprintf(stderr," -- %s\n",er) ;
00192       DYNAMIC_CLOSE( plin->libhandle ) ;
00193       myXtFree(plin) ;
00194       RETURN(NULL) ;
00195    }
00196 
00197    /*----- create interface(s) by calling initialization function -----*/
00198 
00199    plin->interface_count = nin = 0 ;
00200    plin->interface       = NULL ;
00201 
00202 #ifdef AFNI_DEBUG
00203    MCHECK ;
00204 #else
00205    MPROBE ;
00206 #endif
00207 
00208    do {
00209 #if 0
00210       plint = (PLUGIN_interface *) plin->libinit_func( nin ) ;
00211 #else
00212       AFNI_CALL_VALU_1ARG(plin->libinit_func ,
00213                           PLUGIN_interface *,plint , int,nin ) ;
00214 #endif
00215       if( plint == NULL ) break ;
00216 
00217       plin->interface = (PLUGIN_interface **)
00218                           XtRealloc( (char *) plin->interface ,
00219                                      sizeof(PLUGIN_interface *) * (nin+1) ) ;
00220 
00221       plin->interface[nin] = plint ;
00222       if( nin == 0 ) strcpy( plin->seqcode , plint->seqcode ) ;  /* 06 Aug 1999 */
00223       nin++ ;
00224    } while( plint != NULL ) ;
00225 
00226    plin->interface_count = nin ;
00227 
00228 #if 1
00229    if( nin > 0 ){                                    /* 01 Nov 1999 */
00230       char * bcol , benv[256] ;
00231       int ii = strlen(DYNAMIC_suffix) , jj ;
00232 
00233       strcpy(benv,"AFNI_") ; strcat(benv,THD_trailname(fname,0)) ; /* make */
00234       jj = strlen(benv) ; benv[jj-ii] = '\0' ;                     /* name */
00235       strcat(benv,"_butcolor") ;
00236       bcol = my_getenv(benv) ;                       /* find name */
00237       if( bcol != NULL ){                            /* if have name: */
00238          for( ii=0 ; ii < nin ; ii++ ){
00239             plint = plin->interface[ii] ;
00240             if( plint->butcolor[0] == '\0' )         /* set color if */
00241                PLUTO_set_butcolor( plint , bcol ) ;  /* not defined */
00242          }
00243       }
00244    }
00245 #endif
00246 
00247 if(PRINT_TRACING)
00248 { char str[256] ;
00249   sprintf(str,"library %s created %d interfaces",fname,nin) ; STATUS(str) ; }
00250 
00251    /*----- done -----*/
00252 
00253    RETURN(plin) ;
00254 }
00255 
00256 /*--------------------------------------------------------------------
00257    Routine to read in all plugins in the desired list of directories
00258    29 Mar 2001: pname = argv[0] = potential program name
00259 ----------------------------------------------------------------------*/
00260 
00261 #ifdef DARWIN
00262 #include <mach-o/dyld.h>
00263 /* extern unsigned long _dyld_present(void); */
00264 #endif
00265 
00266 AFNI_plugin_array * PLUG_get_many_plugins(char *pname)
00267 {
00268    char * epath , * elocal , * eee ;
00269    char ename[THD_MAX_NAME] ;
00270    AFNI_plugin_array * outar , * tmpar ;
00271    int epos , ll , ii , id ;
00272    THD_string_array *qlist ; /* 02 Feb 2002 */
00273 
00274    /*----- sanity checks -----*/
00275 
00276 ENTRY("PLUG_get_many_plugins") ;
00277 
00278 /**
00279 #if defined(DARWIN) && !defined(c_plusplus) && !defined(__cplusplus)
00280 **/
00281 #ifdef DARWIN
00282    if( _dyld_present() == 0 ) RETURN(NULL) ;  /* 05 Sep 2001: Mac OSX */
00283 #endif
00284 
00285    epath = getenv("AFNI_PLUGINPATH") ;     /* get the path list to read from */
00286 
00287    if( epath == NULL )
00288      epath = getenv("AFNI_PLUGIN_PATH") ; /* try another name? */
00289 
00290    if( epath == NULL ){
00291      epath = getenv("PATH") ;              /* try yet another name? */
00292 #if 0
00293      if( epath != NULL )
00294        fprintf(stderr,
00295                "\n++ WARNING: AFNI_PLUGINPATH not set; searching PATH\n") ;
00296 #endif
00297    }
00298 
00299    if( epath == NULL && pname != NULL && strchr(pname,'/') != NULL ){ /* 29 Mar 2001 */
00300      char *ep = strdup(pname) ;                                       /* get path    */
00301      char *tp = THD_trailname(ep,0) ;                                 /* to program  */
00302      *tp = '\0' ;
00303      if( strlen(ep) > 0 ) epath = ep ;    /* got some path */
00304      else                 free(ep) ;      /* got zipperoni */
00305    }
00306 
00307    if( epath == NULL )                                /* put in a fake path instead? */
00308      epath = "./ /usr/local/bin /sw/bin /opt/local/bin /Applications/AFNI" ;
00309 
00310    INIT_SARR(qlist) ; /* 02 Feb 2002: list of checked directories */
00311 
00312    /*----- copy path list into local memory -----*/
00313 
00314    ll = strlen(epath) ;
00315    elocal = (char *) XtMalloc( sizeof(char) * (ll+2) ) ;
00316 
00317    /*----- put a blank at the end -----*/
00318 
00319    strcpy( elocal , epath ) ; elocal[ll] = ' ' ; elocal[ll+1] = '\0' ;
00320 
00321    /*----- replace colons with blanks -----*/
00322 
00323    for( ii=0 ; ii < ll ; ii++ )
00324      if( elocal[ii] == ':' ) elocal[ii] = ' ' ;
00325 
00326 if(PRINT_TRACING)
00327 { STATUS("paths to be searched for plugins follows:") ;
00328   printf("%s\n",elocal) ; fflush(stdout) ; }
00329 
00330    /*----- extract blank delimited strings;
00331            use as directory names to get libraries -----*/
00332 
00333    INIT_PLUGIN_ARRAY( outar ) ;
00334    epos = 0 ;
00335 
00336    do{
00337       ii = sscanf( elocal+epos , "%s%n" , ename , &id ) ; /* next substring */
00338       if( ii < 1 || id < 1 ) break ;                      /* none --> end of work */
00339       epos += id ;                                        /* char after last scanned */
00340 
00341       if( !THD_is_directory(ename) ) continue ;           /* 21 May 2002 -rcr */
00342 
00343       /* 02 Feb 2002: did we check this one already? */
00344 
00345       for( ii=0 ; ii < qlist->num ; ii++ )
00346          if( THD_equiv_files(qlist->ar[ii],ename) ) break ;
00347       if( ii < qlist->num ) continue ;
00348       ADDTO_SARR(qlist,ename) ;
00349 
00350       ii = strlen(ename) ;                                /* make sure name has */
00351       if( ename[ii-1] != '/' ){                           /* a trailing '/' on it */
00352           ename[ii]  = '/' ; ename[ii+1] = '\0' ;
00353       }
00354 
00355       tmpar = PLUG_get_all_plugins( ename ) ;             /* read this directory */
00356       if( tmpar != NULL ){
00357          for( ii=0 ; ii < tmpar->num ; ii++ )             /* move results to output */
00358            ADDTO_PLUGIN_ARRAY( outar , tmpar->plar[ii] ) ;
00359 
00360          FREE_PLUGIN_ARRAY(tmpar) ;                       /* toss temp array */
00361       }
00362    } while( epos < ll ) ;  /* scan until 'epos' is after end of epath */
00363 
00364    myXtFree(elocal) ;
00365 
00366 if(PRINT_TRACING)
00367 { char str[256] ; sprintf(str,"found %d plugins",outar->num) ; STATUS(str) ; }
00368 
00369    if( outar->num == 0 ) DESTROY_PLUGIN_ARRAY(outar) ;
00370    DESTROY_SARR(qlist) ; /* 02 Feb 2002 */
00371    RETURN(outar) ;
00372 }
00373 
00374 /*===================  Plugins are statically linked into AFNI ===================*/
00375 
00376 #else  /* NO_DYNAMIC_LOADING is defined (e.g., CYGWIN) */
00377 
00378 /* get the list of fixed (compiled-in) plugins */
00379 
00380 #include "fixed_plugins.h"
00381 
00382 /*-------------------------------------------------------------------------------*/
00383 /*! Function to load one fixed plugin (for CYGWIN) */
00384 
00385 AFNI_plugin * PLUG_load_fixed_plugin( FIXED_plugin pin )
00386 {
00387    AFNI_plugin * plin ;
00388    PLUGIN_interface * plint ;
00389    int nin ;
00390 
00391    /*----- sanity checks -----*/
00392 
00393 ENTRY("PLUG_load_plugin") ;
00394 
00395    if( pin.pfunc == NULL ) RETURN(NULL) ;
00396 
00397    /*----- make space for new plugin -----*/
00398 
00399    plin = (AFNI_plugin *) XtMalloc( sizeof(AFNI_plugin) ) ;
00400    plin->type = AFNI_PLUGIN_TYPE ;
00401 
00402    /*----- copy name into plin structure -----*/
00403 
00404    MCW_strncpy( plin->libname , pin.pname , MAX_PLUGIN_NAME ) ;
00405    plin->libinit_func = pin.pfunc ;
00406 
00407    /*----- create interface(s) by calling initialization function -----*/
00408 
00409    plin->interface_count = nin = 0 ;
00410    plin->interface       = NULL ;
00411 
00412    do {
00413       plint = (PLUGIN_interface *) plin->libinit_func( nin ) ;
00414       if( plint == NULL ) break ;
00415 
00416       plin->interface = (PLUGIN_interface **)
00417                           XtRealloc( (char *) plin->interface ,
00418                                      sizeof(PLUGIN_interface *) * (nin+1) ) ;
00419 
00420       plin->interface[nin] = plint ;
00421       if( nin == 0 ) strcpy( plin->seqcode , plint->seqcode ) ;  /* 06 Aug 1999 */
00422       nin++ ;
00423    } while( plint != NULL ) ;
00424 
00425    plin->interface_count = nin ;
00426 
00427    /*----- done -----*/
00428 
00429    RETURN(plin) ;
00430 }
00431 
00432 /*------------------------------------------------------------------------*/
00433 /*! Function to load all fixed plugins (for CYGWIN).  pname is ignored. */
00434 
00435 AFNI_plugin_array * PLUG_get_many_plugins(char *pname)
00436 {
00437    int ir ;
00438    AFNI_plugin_array * outar ;
00439    AFNI_plugin       * plin ;
00440 
00441    /*----- sanity check and initialize -----*/
00442 
00443 ENTRY("PLUG_get_many_plugins") ;
00444 
00445    INIT_PLUGIN_ARRAY( outar ) ;
00446 
00447    /*----- scan thru and create plugins from the fixed list -----*/
00448 
00449    for( ir=0 ; ir < NUM_FIXED_plugin_funcs ; ir++ ){
00450       plin = PLUG_load_fixed_plugin( FIXED_plugin_funcs[ir] ) ;
00451       if( plin != NULL ) ADDTO_PLUGIN_ARRAY( outar , plin ) ;
00452    }
00453 
00454    RETURN(outar) ;
00455 }
00456 
00457 #endif /* NO_DYNAMIC_LOADING */
00458 
00459 /*==============================================================================*/
00460 
00461 /****************************************************************************
00462   Routines to create interface descriptions for new plugins. Usage:
00463     1) Use "new_PLUGIN_interface" to create the initial data structure.
00464     2) Use "add_option_to_PLUGIN_interface" to create an option line in the
00465          AFNI interface menu.  There is no built-in limit to the number
00466          of option lines that may be added to an AFNI interface menu.
00467     2(abcdef)
00468        Use "add_number_to_PLUGIN_interface"  , and
00469            "add_string_to_PLUGIN_interface"  , and
00470            "add_dataset_to_PLUGIN_interface" , et cetera,
00471          to add control parameter choosers to the most recently created
00472          option line.  Up to 6 choosers may be added to an option line.
00473     3) When done, return the new "PLUGIN_interface *" to AFNI.
00474 *****************************************************************************/
00475 
00476 /*--------------------------------------------------------------------------
00477    Create a new plugin interface.
00478 
00479    label       = C string to go on the button that activates this interface
00480                    (will be truncated to 15 characters)
00481 
00482    description = C string to go on the interface control panel popped-up
00483                    when the button above is pressed -- this has no
00484                    meaning for call_type = PLUGIN_CALL_IMMEDIATELY
00485 
00486    help        = C string to be popped up if the user presses "Help" on
00487                    the interface control panel -- this has no
00488                    meaning for call_type = PLUGIN_CALL_IMMEDIATELY.
00489                    If this is NULL, then there will be no help available.
00490 
00491    call_type   = int that describes how the plugin is to be called from AFNI:
00492                    PLUGIN_CALL_IMMEDIATELY means to call APL_main as soon
00493                      as the activating button is pressed;
00494                    PLUGIN_CALL_VIA_MENU means to have AFNI popup a menu
00495                      to control the input parameters passed to APL_main.
00496 
00497    call_func   = routine that AFNI should call when the user activates
00498                    this plugin.  The routine will be passed the the
00499                    pointer "PLUGIN_interface *" created herein, which
00500                    can be interrogated with the get_*_from_PLUGIN_interface
00501                    routines.  The call_func should return a "char *", which
00502                    is NULL if everything is OK, and points to an error
00503                    message that AFNI will display if something bad happened.
00504 
00505    The value returned is the pointer to the new interface struct.
00506 
00507    Note that the three input strings are copied by AFNI, and so could
00508    be freed after this routine returns.
00509 ----------------------------------------------------------------------------*/
00510 
00511 PLUGIN_interface * new_PLUGIN_interface( char * label , char * description ,
00512                                          char * help ,
00513                                          int call_type , cptr_func * call_func )
00514 {
00515    PLUGIN_interface * plint ;
00516 
00517 ENTRY("new_PLUGIN_interface") ;
00518 
00519    plint = new_PLUGIN_interface_1999( label , description , help ,
00520                                       call_type , call_func , NULL ) ;
00521    RETURN(plint) ;
00522 }
00523 
00524 /**** 15 Jun 1999: modified to crosscheck compilation dates ****/
00525 
00526 #include <time.h>
00527 
00528 PLUGIN_interface * new_PLUGIN_interface_1999( char * label , char * description ,
00529                                               char * help ,
00530                                               int call_type , cptr_func * call_func ,
00531                                               char * compile_date )
00532 {
00533    PLUGIN_interface * plint ;
00534    static int num_date_err = 0 ;
00535 
00536    /*-- sanity check --*/
00537 
00538 ENTRY("new_PLUGIN_interface_1999") ;
00539 
00540    if( label == NULL || strlen(label) == 0 ) RETURN(NULL) ;
00541 
00542    if( !( (call_type == PLUGIN_CALL_IMMEDIATELY) ||
00543           (call_type == PLUGIN_CALL_VIA_MENU   )
00544         ) ) RETURN(NULL) ;
00545 
00546    if( call_func == (cptr_func *) NULL ) RETURN(NULL) ;
00547 
00548    /*-- create new interface --*/
00549 
00550    plint = (PLUGIN_interface *) XtMalloc(sizeof(PLUGIN_interface)) ;
00551    if( plint == NULL ) RETURN(NULL) ;
00552 
00553    plint->flags = 0 ;  /* 29 Mar 2002 */
00554 
00555    MCW_strncpy( plint->label , label , PLUGIN_LABEL_SIZE ) ;
00556 
00557    if( description != NULL )
00558       MCW_strncpy( plint->description , description , PLUGIN_STRING_SIZE ) ;
00559    else
00560       MCW_strncpy( plint->description , label , PLUGIN_STRING_SIZE ) ;
00561 
00562    plint->call_method  = call_type ;
00563    plint->call_func    = call_func ;
00564    plint->option_count = 0 ;
00565    plint->option       = NULL ;
00566    plint->wid          = NULL ;
00567    plint->im3d         = NULL ;
00568    plint->hint         = NULL ;
00569 
00570    if( help == NULL || strlen(help) == 0 )
00571       plint->helpstring = NULL ;
00572    else
00573       plint->helpstring = XtNewString( help ) ;
00574 
00575    strcpy( plint->seqcode , "zzzzzzz" ) ; /* 06 Aug 1999 */
00576    strcpy( plint->butcolor, "\0" ) ;      /* 01 Nov 1999 */
00577 
00578    /** 15 Jun 1999 stuff for date checking **/
00579 
00580 #ifndef DONT_USE_STRPTIME
00581    if( compile_date == NULL ){
00582 
00583       if( num_date_err == 0 ) fprintf(stderr,"\n") ;
00584       fprintf(stderr,
00585               "*** Warning: Plugin %-15s was compiled with an earlier version of AFNI\n",
00586               label ) ;
00587       num_date_err++ ;
00588 
00589 #if 0
00590 #  define AFNI_DATE "Jun 17 1999"  /* for testing purposes */
00591 #else
00592 #  define AFNI_DATE __DATE__
00593 #endif
00594 
00595    } else {
00596       struct tm compile_tm  ={0} , date_tm={0} ;
00597       time_t    compile_time     , date_time   ;
00598       double    date_minus_compile ;
00599 
00600       strptime( compile_date , "%b %d %Y" , &compile_tm ) ; compile_time = mktime( &compile_tm ) ;
00601       strptime( AFNI_DATE    , "%b %d %Y" , &date_tm    ) ; date_time    = mktime( &date_tm    ) ;
00602       date_minus_compile = difftime( date_time , compile_time ) ;
00603 
00604       if( date_minus_compile > 3600.0 ){
00605          if( num_date_err == 0 ) fprintf(stderr,"\n") ;
00606          fprintf(stderr,
00607                  "\n*** Warning: Plugin %-15s compile date=%s predates AFNI=%s",
00608                  label , compile_date , AFNI_DATE ) ;
00609          num_date_err++ ;
00610       } else if( PRINT_TRACING ){
00611          char str[256] ;
00612          sprintf(str,"Plugin %-15s compile date=%s  AFNI date=%s  difftime=%g\n",
00613                  label , compile_date , AFNI_DATE , date_minus_compile ) ;
00614          STATUS(str) ;
00615       }
00616    }
00617 #endif
00618 
00619    plint->run_label[0]  = '\0' ;  /* 04 Nov 2003 */
00620    plint->doit_label[0] = '\0' ;
00621 
00622    RETURN(plint) ;
00623 }
00624 
00625 /*------------------------------------------------------------------------*/
00626 /*! Set the "Run+Keep" and "Run+Close" labels for a plugin. [04 Nov 2003] */
00627 /*------------------------------------------------------------------------*/
00628 
00629 void PLUTO_set_runlabels( PLUGIN_interface *plint , char *rlab , char *dlab )
00630 {
00631    if( plint == NULL ) return ;
00632    if( rlab != NULL  ) MCW_strncpy( plint->run_label , rlab, PLUGIN_LABEL_SIZE );
00633    if( dlab != NULL  ) MCW_strncpy( plint->doit_label, dlab, PLUGIN_LABEL_SIZE );
00634    return ;
00635 }
00636 
00637 /*----------------------------------------------------------------------
00638   Set the seqcode in a plugin, for sorting in the interface.
00639   [06 Aug 1999]
00640 ------------------------------------------------------------------------*/
00641 
00642 void PLUTO_set_sequence( PLUGIN_interface * plint , char * sq )
00643 {
00644 ENTRY("PLUTO_set_sequence") ;
00645    if( plint == NULL || sq == NULL || sq[0] == '\0' ) EXRETURN ;
00646    MCW_strncpy( plint->seqcode , sq , PLUGIN_STRING_SIZE ) ;
00647    EXRETURN ;
00648 }
00649 
00650 /*----------------------------------------------------------------------
00651   Set the button color in a plugin [01 Nov 1999]
00652 ------------------------------------------------------------------------*/
00653 
00654 void PLUTO_set_butcolor( PLUGIN_interface * plint , char * sq )
00655 {
00656 ENTRY("PLUTO_set_butcolor") ;
00657    if( plint == NULL || sq == NULL || sq[0] == '\0' ) EXRETURN ;
00658    if( strncmp(sq,"hot",3) == 0 ) sq = MCW_hotcolor(NULL) ;
00659    MCW_strncpy( plint->butcolor , sq , PLUGIN_STRING_SIZE ) ;
00660    EXRETURN ;
00661 }
00662 
00663 /*----------------------------------------------------------------------
00664    Routine to add a new option line to a plugin interface menu.
00665 
00666    plint      = PLUGIN_interface * which will have the option added
00667    label     = C string to be displayed in the menu describing this option
00668    tag       = C string to be passed to the plugin when this option is used
00669    mandatory = TRUE  (1) if this option is always passed to the plugin
00670                FALSE (0) if the user may or may not select this option
00671 ------------------------------------------------------------------------*/
00672 
00673 void add_option_to_PLUGIN_interface( PLUGIN_interface * plint ,
00674                                      char * label , char * tag , int mandatory )
00675 {
00676    int nopt , isv ;
00677    PLUGIN_option * opt ;
00678 
00679 ENTRY("add_option_to_PLUGIN_interface") ;
00680 
00681    /*-- sanity check --*/
00682 
00683    if( plint == NULL ) EXRETURN ;
00684    if( plint->call_method == PLUGIN_CALL_IMMEDIATELY ) EXRETURN ;
00685 
00686    if( label == NULL ) label = EMPTY_STRING ;
00687    if( tag   == NULL ) tag   = EMPTY_STRING ;
00688 
00689    /*-- create space for new option --*/
00690 
00691    nopt = plint->option_count ;
00692    plint->option = (PLUGIN_option **)
00693                      XtRealloc( (char *) plint->option ,
00694                                 sizeof(PLUGIN_option *) * (nopt+1) ) ;
00695 
00696    plint->option[nopt] = opt = (PLUGIN_option *) XtMalloc( sizeof(PLUGIN_option) ) ;
00697 
00698    /*-- put values in new option --*/
00699 
00700    PLUGIN_LABEL_strcpy( opt->label , label ) ;
00701    MCW_strncpy( opt->tag , tag , PLUGIN_STRING_SIZE ) ;
00702 
00703    opt->mandatory      = mandatory ;
00704    opt->subvalue_count = 0 ;
00705 
00706    opt->hint = NULL ;
00707    for( isv=0 ; isv < PLUGIN_MAX_SUBVALUES ; isv++ )
00708       opt->subvalue[isv].hint = NULL ;
00709 
00710    (plint->option_count)++ ;  /* one more option */
00711 
00712 #if 0
00713 {int qq; fprintf(stderr,"Option tags thus far:\n");
00714  for(qq=0;qq<plint->option_count;qq++)
00715    fprintf(stderr," %s",plint->option[qq]->tag) ;
00716  fprintf(stderr,"\n"); }
00717 #endif
00718 
00719    EXRETURN ;
00720 }
00721 
00722 /*-------------------------------------------------------------------------
00723   Add a hint to the most recently created interface item
00724 ---------------------------------------------------------------------------*/
00725 
00726 void PLUTO_add_hint( PLUGIN_interface * plint , char * hh )
00727 {
00728    int nopt , nsv ;
00729    PLUGIN_option * opt ;
00730    PLUGIN_subvalue * sv ;
00731 
00732 ENTRY("PLUTO_add_hint") ;
00733 
00734    if( plint == NULL || hh == NULL ) EXRETURN ;
00735 
00736    nopt = plint->option_count - 1 ;
00737    if( nopt < 0 ){                  /* no options yet, so hint is global */
00738       myXtFree(plint->hint) ;
00739       plint->hint = XtNewString(hh) ;
00740       EXRETURN ;
00741    }
00742 
00743    opt  = plint->option[nopt] ;     /* latest option line */
00744    nsv  = opt->subvalue_count ;     /* number of subvalues on it */
00745 
00746    if( nsv == 0 ){                  /* no subvalues yet */
00747       myXtFree(opt->hint) ;         /* so put hint on the option line */
00748       opt->hint = XtNewString(hh) ;
00749    } else {                         /* add hint to last subvalue */
00750       sv = &(opt->subvalue[nsv-1]) ;
00751       myXtFree(sv->hint) ;
00752       sv->hint = XtNewString(hh) ;
00753 
00754 #if 0
00755 if(PRINT_TRACING)
00756 { char str[256] ; sprintf(str,"%s: %s hint=%s",
00757                           plint->label,sv->label,sv->hint) ; STATUS(str) ; }
00758 #endif
00759 
00760    }
00761 
00762    EXRETURN ;
00763 }
00764 
00765 /*-------------------------------------------------------------------------
00766    Routine to add a number-type "chooser" to the most recently created
00767    option within a plugin interface.  "Numbers" are always passed to
00768    the plugin in float format, but are specified here using an
00769    integer range with a decimal shift, sort of like the Motif Scale Widget.
00770 
00771    label     = C string to go in the menu, next to the "chooser" for
00772                the integer.
00773 
00774    bot, top, = Smallest and largest integer values allowed in the chooser.
00775    decim     = Number of decimals to shift to left for display of value.
00776                For example, bot=1 top=100 with decim=2 will actually
00777                specify a range of 0.01 to 1.00.  One function of decim
00778                is simply to set the increments between values in the
00779                chooser.  With decim=2, the increment is 0.01.
00780 
00781    defval    = Integer value for the default.  For example, if decim=2,
00782                and defval=43, then the floating point default value
00783                (as it appears to the user) is actually 0.43.
00784 
00785    editable  = TRUE (1) if the user will be allowed to type in any
00786                  value in the chooser.  For example, this would allow
00787                  the input of 0.43721.
00788                FALSE (0) if the user is restricted to the range of
00789                  values given by bot/10**decim to top/10**decim,
00790                  in steps of 1/10**decim.
00791 ---------------------------------------------------------------------------*/
00792 
00793 void add_number_to_PLUGIN_interface( PLUGIN_interface * plint ,
00794                                      char * label ,
00795                                      int bot , int top , int decim ,
00796                                      int defval , int editable     )
00797 {
00798    int nopt , nsv ;
00799    PLUGIN_option * opt ;
00800    PLUGIN_subvalue * sv ;
00801 
00802    /*-- sanity check --*/
00803 
00804 ENTRY("add_number_to_PLUGIN_interface") ;
00805 
00806    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
00807 
00808    if( label == NULL ) label = EMPTY_STRING ;
00809 
00810    nopt = plint->option_count - 1 ;
00811    opt  = plint->option[nopt] ;
00812 
00813    nsv = opt->subvalue_count ;
00814    if( nsv == PLUGIN_MAX_SUBVALUES ){
00815       fprintf(stderr,"*** Warning: maximum plugin subvalue count exceeded!\n");
00816       EXRETURN ;
00817    }
00818 
00819    /*-- load values into next subvalue --*/
00820 
00821    sv = &(opt->subvalue[nsv]) ;
00822 
00823    sv->data_type = PLUGIN_NUMBER_TYPE ;
00824    PLUGIN_LABEL_strcpy( sv->label , label ) ;
00825 
00826    sv->int_range_bot   = bot ;
00827    sv->int_range_top   = top ;
00828    sv->int_range_decim = decim ;
00829    sv->value_default   = defval ;
00830    sv->editable        = editable ;
00831 
00832    (opt->subvalue_count)++ ;
00833    EXRETURN ;
00834 }
00835 
00836 /*-------------------------------------------------------------------
00837    Routine to add a string-type "chooser" to the most recently created
00838    option within a plugin interface.
00839 
00840    label     = C string to go in the menu, next to the "chooser" for
00841                the string.
00842 
00843    num_str   = Count of the number of strings provided in strlist.
00844    strlist   = strlist[i] is a pointer to the i'th string value
00845                that the user is to choose from, for i=0...num_str-1.
00846 
00847    defval    = If num_str > 0:
00848                  Integer from 0...num_str-1 indicating which string
00849                  in strlist is the default value.
00850                If num_str == 0:
00851                  Gives width of field supplied for string input.
00852 
00853    Note that if num_str is <= 0, then instead of being presented with
00854    a menu of fixed strings, the user will have to type in a string.
00855 ---------------------------------------------------------------------*/
00856 
00857 void add_string_to_PLUGIN_interface( PLUGIN_interface * plint ,
00858                                      char * label ,
00859                                      int num_str , char ** strlist ,
00860                                      int defval )
00861 {
00862    int nopt , nsv , ii ;
00863    PLUGIN_option * opt ;
00864    PLUGIN_subvalue * sv ;
00865 
00866 ENTRY("add_string_to_PLUGIN_interface") ;
00867 
00868    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
00869 
00870    if( label == NULL ) label = EMPTY_STRING ;
00871 
00872    nopt = plint->option_count - 1 ;
00873    opt  = plint->option[nopt] ;
00874 
00875    nsv = opt->subvalue_count ;
00876    if( nsv == PLUGIN_MAX_SUBVALUES ){
00877       fprintf(stderr,"*** Warning: maximum plugin subvalue count exceeded!\n");
00878       EXRETURN ;
00879    }
00880 
00881    /*-- load values into next subvalue --*/
00882 
00883    sv = &(opt->subvalue[nsv]) ;
00884 
00885    sv->data_type = PLUGIN_STRING_TYPE ;
00886    PLUGIN_LABEL_strcpy( sv->label , label ) ;
00887 
00888    if( num_str > 0 ){
00889       sv->string_range_count = num_str ;
00890       for( ii=0 ; ii < num_str ; ii++ ){
00891          sv->string_range[ii] = (char*)XtMalloc( PLUGIN_STRING_SIZE ) ;
00892          MCW_strncpy( sv->string_range[ii] , strlist[ii] , PLUGIN_STRING_SIZE ) ;
00893       }
00894       sv->value_default   = defval ;
00895       sv->editable        = FALSE ;
00896    } else {
00897       sv->string_range_count = 0 ;
00898       sv->editable           = TRUE ;
00899       sv->value_default      = defval ;
00900 
00901       if( strlist != NULL && strlist[0] != NULL ){     /* 19 Jun 2000 */
00902          sv->string_range_count = -1 ;
00903          sv->string_range[0] = (char*)XtMalloc( PLUGIN_STRING_SIZE ) ;
00904          MCW_strncpy( sv->string_range[0], strlist[0], PLUGIN_STRING_SIZE ) ;
00905       }
00906    }
00907 
00908    (opt->subvalue_count)++ ;
00909    EXRETURN ;
00910 }
00911 
00912 /*-----------------------------------------------------------------------
00913    Routine to add a dataset "chooser" to the most recently created
00914    option within a plugin interface.
00915 
00916    label = C string to go in the menu, next to the "chooser" for
00917            the dataset.
00918 
00919    The _mask inputs are bitwise ORs (|) of dataset type masks.
00920    These are used to specify the types of datasets that can be
00921    passed to the plugin.  The first two _mask inputs below cannot both
00922    be zero (for then no dataset would be allowed into the plugin!).
00923 
00924    anat_mask = Chosen from the list in 3ddata.h, which is currently
00925                    ANAT_SPGR_MASK   ANAT_FSE_MASK   ANAT_EPI_MASK
00926                    ANAT_MRAN_MASK   ANAT_CT_MASK    ANAT_SPECT_MASK
00927                    ANAT_PET_MASK    ANAT_MRA_MASK   ANAT_BMAP_MASK
00928                    ANAT_DIFF_MASK   ANAT_OMRI_MASK
00929                and ANAT_ALL_MASK, which will allow any anatomical
00930                dataset.  Entering 0 for this mask will mean that
00931                no anatomical datasets will be choosable.
00932 
00933    func_mask = Similar mask for functional dataset types, chosen from
00934                   FUNC_FIM_MASK   FUNC_THR_MASK
00935                   FUNC_COR_MASK   FUNC_TT_MASK
00936                and FUNC_ALL_MASK, which will allow any functional
00937                dataset.  Entering 0 for this mask will mean that
00938                no functional datasets will be choosable.
00939 
00940    ctrl_mask = An additional mask to specify further exactly which
00941                  datasets should be choosable.  Mask options are:
00942 
00943                SESSION_ALL_MASK    = If this is set, then the choice of
00944                                      datasets will be drawn from all
00945                                      sessions now loaded into AFNI.
00946                                    * By default, only the "current"
00947                                      session will be included.
00948 
00949                DIMEN_3D_MASK       = Masks that define whether 3D and/or
00950                DIMEN_4D_MASK         3D+time (4D) datasets are allowable.
00951                DIMEN_ALL_MASK
00952 
00953                WARP_ON_DEMAND_MASK = If this is set, then datasets that may
00954                                      not have a BRIK file will be included
00955                                      in the list of datasets to choose from.
00956                                      In this case, the plugin must be ready
00957                                      to deal with the warp-on-demand routines
00958                                      that return one slice at a time.
00959                                    * By default, only datasets with actual
00960                                      BRIKs will be included.
00961 
00962                BRICK_BYTE_MASK     = Masks that define what type of data
00963                BRICK_SHORT_MASK      should be stored in the sub-bricks
00964                BRICK_FLOAT_MASK      of the allowable datasets.
00965                BRICK_COMPLEX_MASK
00966                BRICK_RGB_MASK
00967                BRICK_ALLTYPE_MASK
00968                BRICK_ALLREAL_MASK
00969 
00970                *  Note that entering 0 for ctrl_mask means that no   *
00971                *  datasets will be choosable.  At the least, one of  *
00972                *  the DIMEN_ masks must be chosen, and one of the    *
00973                *  BRICK_ masks must be chosen.                       *
00974 -------------------------------------------------------------------------*/
00975 
00976 void add_dataset_to_PLUGIN_interface( PLUGIN_interface * plint ,
00977                                       char * label ,
00978                                       int anat_mask , int func_mask , int ctrl_mask )
00979 {
00980    int nopt , nsv , ii ;
00981    PLUGIN_option * opt ;
00982    PLUGIN_subvalue * sv ;
00983 
00984 ENTRY("add_dataset_to_PLUGIN_interface") ;
00985 
00986    /*-- sanity checks --*/
00987 
00988    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
00989    if( anat_mask == 0 && func_mask == 0 ) EXRETURN ;
00990 
00991    if( label == NULL ) label = EMPTY_STRING ;
00992 
00993    if( (ctrl_mask & BRICK_ALLTYPE_MASK)==0 ||
00994        (ctrl_mask & DIMEN_ALL_MASK)    ==0   ) EXRETURN ;
00995 
00996    nopt = plint->option_count - 1 ;
00997    opt  = plint->option[nopt] ;
00998 
00999    nsv = opt->subvalue_count ;
01000    if( nsv == PLUGIN_MAX_SUBVALUES ){
01001       fprintf(stderr,"*** Warning: maximum plugin subvalue count exceeded!\n");
01002       EXRETURN ;
01003    }
01004 
01005    /*-- load values into next subvalue --*/
01006 
01007    sv = &(opt->subvalue[nsv]) ;
01008 
01009    sv->data_type = PLUGIN_DATASET_TYPE ;
01010    PLUGIN_LABEL_strcpy( sv->label , label ) ;
01011 
01012    sv->dset_anat_mask = anat_mask ;
01013    sv->dset_func_mask = func_mask ;
01014    sv->dset_ctrl_mask = ctrl_mask ;
01015 
01016    (opt->subvalue_count)++ ;
01017    EXRETURN ;
01018 }
01019 
01020 void add_dataset_list_to_PLUGIN_interface( PLUGIN_interface * plint ,
01021                                            char * label ,
01022                                            int anat_mask , int func_mask , int ctrl_mask )
01023 {
01024    int nopt , nsv , ii ;
01025    PLUGIN_option * opt ;
01026    PLUGIN_subvalue * sv ;
01027 
01028 ENTRY("add_dataset_list_to_PLUGIN_interface") ;
01029 
01030    /*-- sanity checks --*/
01031 
01032    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
01033    if( anat_mask == 0 && func_mask == 0 ) EXRETURN ;
01034 
01035    if( label == NULL ) label = EMPTY_STRING ;
01036 
01037    if( (ctrl_mask & BRICK_ALLTYPE_MASK)==0 ||
01038        (ctrl_mask & DIMEN_ALL_MASK)    ==0   ) EXRETURN ;
01039 
01040    nopt = plint->option_count - 1 ;
01041    opt  = plint->option[nopt] ;
01042 
01043    nsv = opt->subvalue_count ;
01044    if( nsv == PLUGIN_MAX_SUBVALUES ){
01045       fprintf(stderr,"*** Warning: maximum plugin subvalue count exceeded!\n");
01046       EXRETURN ;
01047    }
01048 
01049    /*-- load values into next subvalue --*/
01050 
01051    sv = &(opt->subvalue[nsv]) ;
01052 
01053    sv->data_type = PLUGIN_DATASET_LIST_TYPE ;
01054    PLUGIN_LABEL_strcpy( sv->label , label ) ;
01055 
01056    sv->dset_anat_mask = anat_mask ;
01057    sv->dset_func_mask = func_mask ;
01058    sv->dset_ctrl_mask = ctrl_mask ;
01059 
01060    (opt->subvalue_count)++ ;
01061    EXRETURN ;
01062 }
01063 
01064 /*-----------------------------------------------------------------------
01065    Routine to add a timeseries "chooser" to the most recently created
01066    option within a plugin interface.
01067 
01068    label = C string to go in the menu, next to the "chooser" for
01069            the dataset.
01070 -------------------------------------------------------------------------*/
01071 
01072 void add_timeseries_to_PLUGIN_interface( PLUGIN_interface * plint, char * label )
01073 {
01074    int nopt , nsv , ii ;
01075    PLUGIN_option * opt ;
01076    PLUGIN_subvalue * sv ;
01077 
01078 ENTRY("add_timeseries_to_PLUGIN_interface") ;
01079 
01080    /*-- sanity checks --*/
01081 
01082    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
01083 
01084    if( label == NULL ) label = EMPTY_STRING ;
01085 
01086    nopt = plint->option_count - 1 ;
01087    opt  = plint->option[nopt] ;
01088 
01089    nsv = opt->subvalue_count ;
01090    if( nsv == PLUGIN_MAX_SUBVALUES ){
01091       fprintf(stderr,"*** Warning: maximum plugin subvalue count exceeded!\n");
01092       EXRETURN ;
01093    }
01094 
01095    /*-- load values into next subvalue --*/
01096 
01097    sv = &(opt->subvalue[nsv]) ;
01098 
01099    sv->data_type = PLUGIN_TIMESERIES_TYPE ;
01100    PLUGIN_LABEL_strcpy( sv->label , label ) ;
01101 
01102    (opt->subvalue_count)++ ;
01103    EXRETURN ;
01104 }
01105 
01106 /*-----------------------------------------------------------------------
01107    Routine to add a color overlay  "chooser" to the most recently
01108    created option within a plugin interface -- 11 Jul 2001 - RWCox.
01109 
01110    label = C string to go in the menu, next to the "chooser" for
01111            the color.
01112 -------------------------------------------------------------------------*/
01113 
01114 void add_overlaycolor_to_PLUGIN_interface( PLUGIN_interface * plint, char * label )
01115 {
01116    int nopt , nsv , ii ;
01117    PLUGIN_option * opt ;
01118    PLUGIN_subvalue * sv ;
01119 
01120 ENTRY("add_overlaycolor_to_PLUGIN_interface") ;
01121 
01122    /*-- sanity checks --*/
01123 
01124    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
01125 
01126    if( label == NULL ) label = EMPTY_STRING ;
01127 
01128    nopt = plint->option_count - 1 ;
01129    opt  = plint->option[nopt] ;
01130 
01131    nsv = opt->subvalue_count ;
01132    if( nsv == PLUGIN_MAX_SUBVALUES ){
01133       fprintf(stderr,"*** Warning: maximum plugin subvalue count exceeded!\n");
01134       EXRETURN ;
01135    }
01136 
01137    /*-- load values into next subvalue --*/
01138 
01139    sv = &(opt->subvalue[nsv]) ;
01140 
01141    sv->data_type = PLUGIN_OVERLAY_COLOR_TYPE ;
01142    PLUGIN_LABEL_strcpy( sv->label , label ) ;
01143 
01144    (opt->subvalue_count)++ ;
01145    EXRETURN ;
01146 }
01147 
01148 /*--------------------------------------------------------------------------*/
01149 
01150 int PLUG_nonblank_len( char * str )
01151 {
01152    int ii , ll ;
01153 
01154    if( str == NULL ) return 0 ;
01155    ll = strlen(str) ; if( ll == 0 ) return 0 ;
01156 
01157    for( ii=ll-1 ; ii >= 0 ; ii-- ) if( str[ii] != ' ' ) break ;
01158 
01159    return (ii+1) ;
01160 }
01161 
01162 /*--------------------------------------------------------------------------
01163   Decide if a dataset prefix is OK.  The string itself is checked for
01164   legality, then the list of all datasets is checked for duplicates.
01165 ----------------------------------------------------------------------------*/
01166 
01167 int PLUTO_prefix_ok( char * str )
01168 {
01169    int ll , ii ;
01170    THD_slist_find find ;
01171 
01172 ENTRY("PLUTO_prefix_ok") ;
01173 
01174    /*--- check the string itself for OK-osity ---*/
01175 
01176    if( str == NULL ) RETURN(0) ;
01177    ll = strlen( str ) ; if( ll == 0 ) RETURN(0) ;
01178 
01179    for( ii=0 ; ii < ll ; ii++ )
01180       if( iscntrl(str[ii]) || isspace(str[ii]) ||
01181           str[ii] == '/'   || str[ii] == ';'   ||
01182           str[ii] == '*'   || str[ii] == '?'   ||
01183           str[ii] == '&'   || str[ii] == '|'   ||
01184           str[ii] == '"'   || str[ii] == '>'   ||
01185           str[ii] == '<'   || str[ii] == '\''  ||
01186           str[ii] == '['   || str[ii] == ']'     ) RETURN(0) ;
01187 
01188    /*--- now see if the prefix already exists in AFNI ---*/
01189 
01190    find = THD_dset_in_sessionlist( FIND_PREFIX , str ,
01191                                    GLOBAL_library.sslist , -1 ) ;
01192 
01193    RETURN(find.dset == NULL) ;
01194 }
01195 
01196 /*------------------------------------------------------------------------------
01197   Routine to create (but not map) the widgets for a plugin interface.
01198 --------------------------------------------------------------------------------*/
01199 
01200 /***** definitions for the action area controls *****/
01201 
01202 #define PLUG_quit_label   "Quit"
01203 #define PLUG_run_label    "Run+Keep"
01204 #define PLUG_doit_label   "Run+Close"
01205 #define PLUG_help_label   "Help"
01206 
01207 #define PLUG_quit_help   "Press to close\nthis panel without\nrunning program."
01208 #define PLUG_run_help    "Press to run\nthe program\nand keep panel open."
01209 #define PLUG_doit_help   "Press to run\nthe program\nand close this panel."
01210 #define PLUG_help_help   "Press to get\nthe help for\nthis program."
01211 
01212 #define NUM_PLUG_ACT 4
01213 
01214 static MCW_action_item PLUG_act[] = {
01215  { PLUG_quit_label, PLUG_action_CB, NULL, PLUG_quit_help,"Close window"               , 0 },
01216  { PLUG_run_label , PLUG_action_CB, NULL, PLUG_run_help ,"Run plugin and keep window" , 0 },
01217  { PLUG_doit_label, PLUG_action_CB, NULL, PLUG_doit_help,"Run plugin and close window", 1 },
01218  { PLUG_help_label, PLUG_action_CB, NULL, PLUG_help_help,"Get help for plugin"        , 0 }
01219 } ;
01220 
01221 void PLUG_setup_widgets( PLUGIN_interface * plint , MCW_DC * dc )
01222 {
01223    int iopt , ib , max_nsv , ww,hh , shh , toff , zlen ;
01224    XmString xstr ;
01225    char str[256] ;
01226    PLUGIN_widgets * wid ;
01227    PLUGIN_option_widgets ** opwid ;
01228    PLUGIN_option_widgets * ow ;
01229    PLUGIN_option * opt ;
01230    PLUGIN_subvalue * sv ;
01231    Widget actar , wframe , separator = NULL ;
01232    int opt_lwid , sv_lwid[PLUGIN_MAX_SUBVALUES] ;
01233    Widget widest_chooser[PLUGIN_MAX_SUBVALUES] ;
01234    int    widest_width[PLUGIN_MAX_SUBVALUES] ;
01235    Pixel  fg_pix ;
01236 
01237 ENTRY("PLUG_setup_widgets") ;
01238 
01239    /**** sanity checks ****/
01240 
01241    if( plint == NULL || plint->wid != NULL ||
01242        plint->call_method == PLUGIN_CALL_IMMEDIATELY ) EXRETURN ;
01243 
01244    /**** create widgets structure ****/
01245 
01246    plint->wid = wid = myXtNew(PLUGIN_widgets) ;
01247 
01248    /**** create Shell that can be opened up later ****/
01249 
01250    wid->shell =
01251       XtVaAppCreateShell(
01252            "AFNI" , "AFNI" , topLevelShellWidgetClass , dc->display ,
01253 
01254            XmNtitle             , plint->label , /* top of window */
01255            XmNiconName          , plint->label , /* label on icon */
01256            XmNmappedWhenManaged , False ,        /* must map it manually */
01257            XmNdeleteResponse    , XmDO_NOTHING , /* deletion handled below */
01258            XmNallowShellResize  , False ,        /* let code resize shell? */
01259            XmNinitialResourcesPersistent , False ,
01260       NULL ) ;
01261 
01262    DC_yokify( wid->shell , dc ) ; /* 14 Sep 1998 */
01263 
01264    if( afni48_good )
01265       XtVaSetValues( wid->shell ,
01266                         XmNiconPixmap , afni48_pixmap ,
01267                      NULL ) ;
01268 
01269    if( MCW_isitmwm(wid->shell) )
01270       XtVaSetValues( wid->shell ,
01271                         XmNmwmDecorations , MWM_DECOR_ALL | MWM_DECOR_MAXIMIZE ,
01272                      NULL ) ;
01273 
01274    XmAddWMProtocolCallback(           /* make "Close" window menu work */
01275            wid->shell ,
01276            XmInternAtom( dc->display , "WM_DELETE_WINDOW" , False ) ,
01277            PLUG_delete_window_CB , (XtPointer) plint ) ;
01278 
01279    /**** create RowColumn to hold all widgets ****/
01280 
01281    wid->form = XtVaCreateWidget(
01282                  "AFNI" , xmFormWidgetClass , wid->shell ,
01283                      XmNborderWidth , 0 ,
01284                      XmNborderColor , 0 ,
01285                      XmNtraversalOn , False ,
01286                      XmNinitialResourcesPersistent , False ,
01287                  NULL ) ;
01288 
01289    /**** create Label at top to hold description of this program ****/
01290 
01291    sprintf( str , "AFNI Plugin: %s" , plint->description ) ;
01292    xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
01293    wid->label =
01294       XtVaCreateManagedWidget(
01295         "AFNI" , xmLabelWidgetClass ,  wid->form ,
01296            XmNlabelString , xstr ,
01297            XmNalignment  , XmALIGNMENT_CENTER ,
01298 
01299            XmNleftAttachment , XmATTACH_FORM ,
01300            XmNrightAttachment, XmATTACH_FORM ,
01301            XmNtopAttachment  , XmATTACH_FORM ,
01302            XmNtopOffset      , 5 ,
01303            XmNinitialResourcesPersistent , False ,
01304         NULL ) ;
01305     XmStringFree( xstr ) ;
01306 
01307     /* now that we have the label,
01308        find its sizes and make sure the shell doesn't get too small */
01309 
01310     MCW_widget_geom( wid->label , &ww , &hh , NULL , NULL ) ;
01311     XtVaSetValues( wid->shell ,
01312                       XmNminWidth  , ww+3*hh ,
01313                       XmNminHeight , (plint->option_count == 0) ? 5*hh : 7*hh ,
01314                    NULL ) ;
01315 
01316    /**** create an action area beneath to hold user control buttons ****/
01317 
01318    for( ib=0 ; ib < NUM_PLUG_ACT ; ib++ )
01319      PLUG_act[ib].data = (XtPointer) plint ;
01320 
01321    /* 04 Nov 2003: allow for change of Run+Close and Run+Keep labels */
01322 
01323    if( plint->run_label[0]  == '\0' ) strcpy(plint->run_label ,PLUG_run_label );
01324    if( plint->doit_label[0] == '\0' ) strcpy(plint->doit_label,PLUG_doit_label);
01325    PLUG_act[1].label = plint->run_label ;
01326    PLUG_act[2].label = plint->doit_label;
01327 
01328    actar = MCW_action_area( wid->form , PLUG_act ,
01329                             (plint->helpstring!=NULL) ? NUM_PLUG_ACT
01330                                                       : NUM_PLUG_ACT-1 ) ;
01331 
01332    XtVaSetValues( actar ,
01333                      XmNleftAttachment , XmATTACH_FORM ,
01334                      XmNrightAttachment, XmATTACH_FORM ,
01335                      XmNtopAttachment  , XmATTACH_WIDGET ,
01336                      XmNtopWidget      , wid->label ,
01337                      XmNtopOffset      , 7 ,
01338                   NULL ) ;
01339 
01340    /**** create a Scrolled Window and Form to hold
01341          the user input option widgets, if they will be needed ****/
01342 
01343    if( plint->option_count > 0 ){
01344       wid->scrollw =
01345          XtVaCreateWidget(
01346            "AFNI" , xmScrolledWindowWidgetClass ,  wid->form ,
01347               XmNscrollingPolicy , XmAUTOMATIC ,
01348               XmNwidth  , ww+2*hh ,
01349               XmNheight ,    3*hh ,
01350               XmNleftAttachment  , XmATTACH_FORM ,
01351               XmNrightAttachment , XmATTACH_FORM ,
01352               XmNtopAttachment   , XmATTACH_WIDGET ,
01353               XmNbottomAttachment, XmATTACH_FORM ,
01354               XmNtopWidget       , actar ,
01355               XmNtopOffset       , 7 ,
01356               XmNtraversalOn , False ,
01357               XmNinitialResourcesPersistent , False ,
01358            NULL ) ;
01359 
01360       wframe =
01361          XtVaCreateWidget(
01362            "AFNI" , xmFrameWidgetClass , wid->scrollw ,
01363                XmNshadowType , XmSHADOW_ETCHED_IN ,
01364                XmNshadowThickness , 5 ,
01365                XmNtraversalOn , False ,
01366                XmNinitialResourcesPersistent , False ,
01367             NULL ) ;
01368 
01369       wid->workwin =
01370          XtVaCreateWidget(
01371            "AFNI" , xmFormWidgetClass , wframe ,
01372               XmNborderWidth , 0 ,
01373               XmNborderColor , 0 ,
01374               XmNtraversalOn , False ,
01375               XmNinitialResourcesPersistent , False ,
01376            NULL ) ;
01377 
01378       wid->opwid = opwid =
01379              (PLUGIN_option_widgets **)
01380                 XtMalloc(sizeof(PLUGIN_option_widgets *) * plint->option_count) ;
01381 
01382       /** setup widest widgets for each column of the Form **/
01383 
01384       for( ib=0 ; ib < PLUGIN_MAX_SUBVALUES ; ib++ ){
01385          widest_chooser[ib] = NULL ;
01386          widest_width[ib]   = 0 ;
01387       }
01388 
01389       XtVaGetValues( wframe , XmNforeground , &fg_pix , NULL ) ;
01390 
01391    } else {
01392       wframe = wid->scrollw = wid->workwin = NULL ;
01393       opwid = NULL ;
01394    }
01395 
01396    /**** for each column within each option, find the max string width ****/
01397 
01398    opt_lwid = 1 ;
01399    for( ib=0 ; ib < PLUGIN_MAX_SUBVALUES ; ib++ ) sv_lwid[ib] = 1 ;
01400 
01401    for( iopt=0 ; iopt < plint->option_count ; iopt++ ){
01402       opt = plint->option[iopt] ;
01403       if( opt == NULL ) continue ; /* bad? */
01404 
01405       opt_lwid = MAX( opt_lwid , PLUG_nonblank_len(opt->label) ) ;
01406       for( ib=0 ; ib < opt->subvalue_count ; ib++ ){
01407          sv = &(opt->subvalue[ib]) ;
01408          sv_lwid[ib] = MAX( sv_lwid[ib] , PLUG_nonblank_len(sv->label) ) ;
01409       }
01410    }
01411 
01412    /**** now clip each label string to its column's width ****/
01413 
01414    for( iopt=0 ; iopt < plint->option_count ; iopt++ ){
01415       opt = plint->option[iopt] ;
01416       if( opt == NULL ) continue ; /* bad? */
01417 
01418 #define LPAD 0   /* 29 Mar 2002: used to be 1 */
01419 
01420       opt->label[ opt_lwid + LPAD ] = '\0' ;
01421       for( ib=0 ; ib < opt->subvalue_count ; ib++ ){
01422          sv = &(opt->subvalue[ib]) ;
01423          sv->label[ sv_lwid[ib] + LPAD ] = '\0' ;
01424       }
01425    }
01426 
01427    /**** create a row of Widgets for each option ****/
01428 
01429    for( iopt=0 ; iopt < plint->option_count ; iopt++ ){
01430       opt = plint->option[iopt] ;
01431       if( opt == NULL ) continue ; /* bad? */
01432 
01433       ow = opwid[iopt] = myXtNew(PLUGIN_option_widgets) ;
01434 
01435       for( ib=0 ; ib < PLUGIN_MAX_SUBVALUES ; ib++ ){  /* initialize */
01436          ow->chooser[ib]      = NULL ;                 /* all subvalue */
01437          ow->chtop[ib]        = NULL ;                 /* stuff */
01438          ow->chooser_type[ib] = OP_CHOOSER_NONE ;
01439          opt->callvalue[ib]   = NULL ;
01440       }
01441 
01442       /** create ToggleButton to indicate whether this is used **/
01443 
01444       ow->toggle =
01445          XtVaCreateManagedWidget(
01446            "AFNI" , xmToggleButtonWidgetClass , wid->workwin ,
01447               XmNleftAttachment   , XmATTACH_FORM ,
01448               XmNtopAttachment    , (iopt==0) ? XmATTACH_FORM     /* first row */
01449                                               : XmATTACH_WIDGET , /* 2nd+ row */
01450               XmNtopOffset        , 1 ,
01451               XmNleftOffset       , 1 ,
01452               XmNtopWidget        , separator ,  /* 2nd+ row */
01453 
01454               XmNlabelType        , XmPIXMAP ,             /* No label attached */
01455               XmNlabelPixmap      , XmUNSPECIFIED_PIXMAP , /* Just the toggle!  */
01456 
01457               XmNset              , (opt->mandatory) ? True  : False ,
01458               XmNsensitive        , (opt->mandatory) ? False : True  ,
01459 
01460               XmNindicatorSize    , hh-1 ,
01461               XmNmarginHeight     , 0  ,
01462               XmNmarginWidth      , 0  ,
01463               XmNselectColor      , fg_pix ,  /* fill with foreground when set */
01464 
01465               XmNtraversalOn , False ,
01466               XmNinitialResourcesPersistent , False ,
01467            NULL ) ;
01468 
01469       MCW_register_help( ow->toggle ,
01470                          "When pressed in and filled,\n"
01471                          "this button denotes that this\n"
01472                          "line of input will be passed\n"
01473                          "to the plugin.  If the plugin\n"
01474                          "has specified that this line\n"
01475                          "is required, then you cannot\n"
01476                          "toggle this button off."
01477                        ) ;
01478 
01479       if( opt->mandatory )
01480          MCW_register_hint( ow->toggle ,
01481                             "This input line is mandatory" ) ;
01482       else
01483          MCW_register_hint( ow->toggle ,
01484                             "IN: this input line sent to plugin" ) ;
01485 
01486       /* this callback will change the appearance of the
01487          option's row of widgets when the toggle button is pressed */
01488 
01489       if( ! opt->mandatory )
01490          XtAddCallback( ow->toggle , XmNvalueChangedCallback ,
01491                         PLUG_optional_toggle_CB , (XtPointer) ow ) ;
01492 
01493       /** create Label to describe this option **/
01494 
01495 #if 0
01496 fprintf(stderr,"Option setup %s\n",opt->label) ;
01497 #endif
01498 
01499       zlen = (PLUG_nonblank_len(opt->label) == 0) ;
01500       xstr = XmStringCreateLtoR( opt->label , XmFONTLIST_DEFAULT_TAG ) ;
01501       ow->label =
01502          XtVaCreateManagedWidget(
01503            "AFNI" , xmLabelWidgetClass , wid->workwin ,
01504               XmNleftAttachment   , XmATTACH_WIDGET ,
01505               XmNtopAttachment    , (iopt==0) ? XmATTACH_FORM     /* 1st row */
01506                                               : XmATTACH_WIDGET , /* 2nd+ row */
01507               XmNtopOffset        , 6 ,
01508               XmNleftOffset       , 0 ,
01509               XmNleftWidget       , ow->toggle ,
01510               XmNtopWidget        , separator ,  /* 2nd+ row */
01511 
01512               XmNmarginHeight     , 0  ,
01513               XmNmarginWidth      , 0  ,
01514 
01515               XmNlabelString , xstr ,
01516               XmNuserData    , (XtPointer) zlen ,
01517               XmNinitialResourcesPersistent , False ,
01518            NULL ) ;
01519       XmStringFree( xstr ) ;
01520       if( opt->mandatory && !zlen ){
01521          MCW_invert_widget( ow->label ) ;
01522          MCW_register_help( ow->label ,
01523                             "This label is inverted as a\n"
01524                             "signal that this line of inputs\n"
01525                             "is required by the plugin, and\n"
01526                             "can't be toggled off."
01527                           ) ;
01528       }
01529       if( opt->hint != NULL )
01530          MCW_register_hint( ow->label , opt->hint ) ;
01531 
01532       /** for each subvalue, create a chooser to select it **/
01533 
01534       for( ib=0 ; ib < opt->subvalue_count ; ib++ ){
01535          sv   = &(opt->subvalue[ib]) ;
01536          toff = 4 ;                      /* default top offset */
01537 
01538          switch( sv->data_type ){
01539 
01540             /** type I can't handle yet, so just put some label there **/
01541 
01542             default:
01543                xstr = XmStringCreateLtoR( "** N/A **" , XmFONTLIST_DEFAULT_TAG ) ;
01544                ow->chtop[ib] =
01545                   XtVaCreateManagedWidget(
01546                      "AFNI" , xmLabelWidgetClass , wid->workwin ,
01547                      XmNlabelString , xstr ,
01548                      XmNinitialResourcesPersistent , False ,
01549                   NULL ) ;
01550                XmStringFree( xstr ) ;
01551                ow->chooser_type[ib] = OP_CHOOSER_NONE ;
01552                ow->chooser[ib]      = NULL ;
01553             break ;
01554 
01555             /** overlay color type -- 11 Jul 2001 **/
01556 
01557             case PLUGIN_OVERLAY_COLOR_TYPE:{
01558                MCW_arrowval * av ;
01559 #if 0
01560 fprintf(stderr,"colormenu setup %s; opt->tag=%s.\n",sv->label,opt->tag) ;
01561 #endif
01562 
01563                av = new_MCW_colormenu(
01564                        wid->workwin ,                    /* parent */
01565                        sv->label ,                       /* label  */
01566                        dc ,                              /* display context */
01567                        1 ,                               /* first color */
01568                        dc->ovc->ncol_ov - 1 ,            /* last color */
01569                        1 ,                               /* initial color */
01570                        NULL,NULL                         /* callback func,data */
01571                     ) ;
01572 
01573                ow->chooser[ib] = (void *) av ;
01574                ow->chtop[ib]   = av->wrowcol ;  /* get the top widget */
01575 
01576                ow->chooser_type[ib] = OP_CHOOSER_COLORMENU ;
01577             }
01578             break ;
01579 
01580             /** number type: make an arrowval or an option menu **/
01581 
01582             case PLUGIN_NUMBER_TYPE:{
01583                int num_choice , use_optmenu ;
01584                MCW_arrowval * av ;
01585 
01586                num_choice  = abs(sv->int_range_top - sv->int_range_bot) + 1 ;
01587                use_optmenu = (num_choice < OP_OPTMENU_LIMIT) && !sv->editable ;
01588 
01589                av = new_MCW_arrowval(
01590                        wid->workwin ,                    /* parent */
01591                        sv->label ,                       /* label  */
01592                        (use_optmenu) ? MCW_AV_optmenu    /* type   */
01593                                      : MCW_AV_downup ,
01594                        sv->int_range_bot ,               /* min */
01595                        sv->int_range_top ,               /* max */
01596                        sv->value_default ,               /* initial */
01597                        (sv->editable) ? MCW_AV_editext   /* type */
01598                                       : MCW_AV_readtext ,
01599                        sv->int_range_decim ,             /* decimals? */
01600                        NULL , NULL , NULL , NULL
01601                      ) ;
01602 
01603                if( use_optmenu && num_choice > COLSIZE )
01604                   AVOPT_columnize(av, 1+(num_choice-1)/COLSIZE) ;
01605 
01606                ow->chooser[ib] = (void *) av ;
01607                ow->chtop[ib]   = av->wrowcol ;  /* get the top widget */
01608 
01609                ow->chooser_type[ib] = (use_optmenu) ? OP_CHOOSER_OPTMENU
01610                                                     : OP_CHOOSER_NUMBER ;
01611 
01612                if( !use_optmenu ) av->allow_wrap = 1 ;
01613                if(  use_optmenu ) toff-- ;
01614 
01615                if( !use_optmenu && (plint->flags & SHORT_NUMBER_FLAG) )
01616                   XtVaSetValues( av->wtext , XmNcolumns , 6 , NULL ) ;
01617             }
01618             break ;
01619 
01620             /** string type:
01621                   make an arrowval if a finite number of choices,
01622                   or a label+textfield if the user can type in anything **/
01623 
01624             case PLUGIN_STRING_TYPE:{
01625                if( sv->string_range_count > 0 ){    /* finite number of choices */
01626                   int num_choice , use_optmenu ;
01627                   MCW_arrowval * av ;
01628 
01629                   num_choice  = sv->string_range_count ;
01630                   use_optmenu = (num_choice < OP_OPTMENU_LIMIT) ;
01631 
01632                   av = new_MCW_arrowval(
01633                           wid->workwin ,                    /* parent */
01634                           sv->label ,                       /* label  */
01635                           (use_optmenu) ? MCW_AV_optmenu    /* type   */
01636                                         : MCW_AV_downup ,
01637                           0 ,                               /* min */
01638                           num_choice-1 ,                    /* max */
01639                           sv->value_default ,               /* initial */
01640                           MCW_AV_readtext ,                 /* type */
01641                           0 ,                               /* decimals? */
01642                           NULL , NULL ,                     /* callbacks */
01643                           MCW_av_substring_CB ,             /* text routine */
01644                           sv->string_range                  /* text data */
01645                         ) ;
01646 
01647                   if( !use_optmenu ){                        /* 11 Jul 2001 */
01648                     int ss , ll , mm=9 ;                     /* increase   */
01649                     for( ss=0 ; ss < num_choice ; ss++ ){    /* width of  */
01650                        if( sv->string_range[ss] != NULL ){   /* widget,   */
01651                           ll = strlen(sv->string_range[ss]); /* if needed */
01652                           if( ll > mm ) mm = ll ;
01653                        }
01654                     }
01655                     if( mm > 9 )
01656                       XtVaSetValues( av->wtext ,
01657                                        XmNmaxLength,mm , XmNcolumns,mm ,
01658                                      NULL ) ;
01659                   }
01660 
01661                   if( use_optmenu && num_choice > COLSIZE )
01662                      AVOPT_columnize(av, 1+(num_choice-1)/COLSIZE) ;
01663 
01664                   ow->chooser[ib] = (void *) av ;
01665                   ow->chtop[ib]   = av->wrowcol ;  /* get the top widget */
01666 
01667                   ow->chooser_type[ib] = (use_optmenu) ? OP_CHOOSER_OPTMENU
01668                                                        : OP_CHOOSER_STRING ;
01669 
01670                   if( !use_optmenu ) av->allow_wrap = 1 ;
01671                   if(  use_optmenu ) toff-- ;
01672 
01673                } else {  /* arbitrary string input allowed */
01674 
01675                   PLUGIN_strval * av = myXtNew(PLUGIN_strval) ;
01676 
01677                   av->rowcol =
01678                      XtVaCreateWidget(
01679                        "AFNI" , xmRowColumnWidgetClass , wid->workwin ,
01680                           XmNpacking     , XmPACK_TIGHT ,
01681                           XmNorientation , XmHORIZONTAL ,
01682                           XmNmarginHeight, 0 ,
01683                           XmNmarginWidth , 0 ,
01684                           XmNspacing     , 0 ,
01685                           XmNtraversalOn , False ,
01686                           XmNinitialResourcesPersistent , False ,
01687                        NULL ) ;
01688 
01689                   xstr = XmStringCreateLtoR( sv->label , XmFONTLIST_DEFAULT_TAG ) ;
01690                   av->label =
01691                      XtVaCreateManagedWidget(
01692                        "AFNI" , xmLabelWidgetClass , av->rowcol ,
01693                           XmNlabelString , xstr ,
01694                           XmNmarginWidth   , 0  ,
01695                           XmNinitialResourcesPersistent , False ,
01696                        NULL ) ;
01697                   XmStringFree( xstr ) ;
01698 
01699                   av->textf =
01700                      XtVaCreateManagedWidget(
01701                        "AFNI" , xmTextFieldWidgetClass , av->rowcol ,
01702                            XmNcolumns      , (sv->value_default > 1)
01703                                             ? sv->value_default : 9 ,
01704                            XmNeditable     , True ,
01705                            XmNmaxLength    , PLUGIN_STRING_SIZE ,
01706                            XmNresizeWidth  , False ,
01707                            XmNmarginHeight , 1 ,
01708                            XmNmarginWidth  , 1 ,
01709                            XmNcursorPositionVisible , True ,
01710                            XmNblinkRate , 0 ,
01711                            XmNautoShowCursorPosition , True ,
01712                            XmNtraversalOn , False ,
01713                            XmNinitialResourcesPersistent , False ,
01714                         NULL ) ;
01715 
01716                   if( sv->string_range_count == -1 )
01717                     XmTextFieldSetString( av->textf , sv->string_range[0] ) ;
01718 
01719                   XtManageChild( av->rowcol ) ;
01720 
01721                   ow->chooser[ib] = (void *) av ;
01722                   ow->chtop[ib]   = av->rowcol ;  /* get the top widget */
01723 
01724                   ow->chooser_type[ib] = OP_CHOOSER_STRING ;
01725                }
01726             }
01727             break ;
01728 
01729             /** single dataset type: make a pushbutton to popup a chooser **/
01730             /** 24 Nov 1996: adapt to include dataset list type as well   **/
01731 
01732             case PLUGIN_DATASET_LIST_TYPE:
01733             case PLUGIN_DATASET_TYPE:{
01734                PLUGIN_dsetval * av = myXtNew(PLUGIN_dsetval) ;
01735 
01736                av->sv = sv ;  /* what this is linked to */
01737 
01738                av->dset_count  = 0 ;     /* will be array of datasets */
01739                av->dset_link   = NULL ;  /* we can choose amongst */
01740 
01741                av->dset_choice = -1 ;    /* will be index of our choice */
01742 
01743                /* 24 Nov 1996 */
01744 
01745                av->multi   = (sv->data_type == PLUGIN_DATASET_LIST_TYPE) ;
01746                av->nchosen = 0 ;
01747                av->chosen  = NULL ;
01748                av->current = 0 ;
01749                av->idclist = NULL ;
01750 
01751                av->rowcol =
01752                   XtVaCreateWidget(
01753                     "AFNI" , xmRowColumnWidgetClass , wid->workwin ,
01754                        XmNpacking     , XmPACK_TIGHT ,
01755                        XmNorientation , XmHORIZONTAL ,
01756                        XmNmarginHeight, 0 ,
01757                        XmNmarginWidth , 0 ,
01758                        XmNspacing     , 0 ,
01759                        XmNtraversalOn , False ,
01760                        XmNinitialResourcesPersistent , False ,
01761                     NULL ) ;
01762 
01763                xstr = XmStringCreateLtoR( sv->label , XmFONTLIST_DEFAULT_TAG ) ;
01764                av->label =
01765                   XtVaCreateManagedWidget(
01766                     "AFNI" , xmLabelWidgetClass , av->rowcol ,
01767                        XmNlabelString , xstr ,
01768                        XmNmarginWidth   , 0  ,
01769                        XmNinitialResourcesPersistent , False ,
01770                     NULL ) ;
01771                XmStringFree( xstr ) ;
01772 
01773                if( plint->flags & SHORT_CHOOSE_FLAG )
01774                  xstr = XmStringCreateLtoR(
01775                           (av->multi) ? "* Datasets *"
01776                                       : "- Dataset -" ,
01777                           XmFONTLIST_DEFAULT_TAG ) ;
01778                else
01779                  xstr = XmStringCreateLtoR(
01780                           (av->multi) ? "** Choose Datasets *"
01781                                       : "-- Choose Dataset --" ,
01782                           XmFONTLIST_DEFAULT_TAG ) ;
01783 
01784                av->pb = XtVaCreateManagedWidget(
01785                            "AFNI" , xmPushButtonWidgetClass , av->rowcol ,
01786                               XmNlabelString   , xstr ,
01787                               XmNmarginHeight  , 0 ,
01788                               XmNmarginWidth   , 0 ,
01789                               XmNrecomputeSize , False ,
01790                               XmNtraversalOn   , False ,
01791                               XmNuserData      , (XtPointer) av ,
01792                               XmNinitialResourcesPersistent , False ,
01793                            NULL ) ;
01794 
01795                XtAddCallback( av->pb , XmNactivateCallback ,
01796                               PLUG_choose_dataset_CB , (XtPointer) plint ) ;
01797 
01798                XtManageChild( av->rowcol ) ;
01799 
01800                ow->chooser[ib] = (void *) av ;
01801                ow->chtop[ib]   = av->rowcol ;  /* get the top widget */
01802 
01803                ow->chooser_type[ib] = OP_CHOOSER_DSET ;
01804                toff-- ;
01805             }
01806             break ;
01807 
01808             /** single timeseries type (similiar to dataset above) **/
01809 
01810             case PLUGIN_TIMESERIES_TYPE:{
01811                PLUGIN_tsval * av = myXtNew(PLUGIN_tsval) ;
01812 
01813                av->sv        = sv ;                        /* a friend in need  */
01814                av->tsimar    = GLOBAL_library.timeseries ; /* to choose amongst */
01815                av->ts_choice = -1 ;                        /* no initial choice */
01816                av->tsim      = NULL ;
01817 
01818                av->rowcol =
01819                   XtVaCreateWidget(
01820                     "AFNI" , xmRowColumnWidgetClass , wid->workwin ,
01821                        XmNpacking     , XmPACK_TIGHT ,
01822                        XmNorientation , XmHORIZONTAL ,
01823                        XmNmarginHeight, 0 ,
01824                        XmNmarginWidth , 0 ,
01825                        XmNspacing     , 0 ,
01826                        XmNtraversalOn , False ,
01827                        XmNinitialResourcesPersistent , False ,
01828                     NULL ) ;
01829 
01830                xstr = XmStringCreateLtoR( sv->label , XmFONTLIST_DEFAULT_TAG ) ;
01831                av->label =
01832                   XtVaCreateManagedWidget(
01833                     "AFNI" , xmLabelWidgetClass , av->rowcol ,
01834                        XmNlabelString , xstr ,
01835                        XmNmarginWidth   , 0  ,
01836                        XmNinitialResourcesPersistent , False ,
01837                     NULL ) ;
01838                XmStringFree( xstr ) ;
01839 
01840                if( plint->flags & SHORT_CHOOSE_FLAG )
01841                  xstr = XmStringCreateLtoR( "-Timeseries-",XmFONTLIST_DEFAULT_TAG ) ;
01842                else
01843                  xstr = XmStringCreateLtoR( "-Choose Timeseries- ",XmFONTLIST_DEFAULT_TAG ) ;
01844 
01845                av->pb = XtVaCreateManagedWidget(
01846                            "AFNI" , xmPushButtonWidgetClass , av->rowcol ,
01847                               XmNlabelString   , xstr ,
01848                               XmNmarginHeight  , 0 ,
01849                               XmNmarginWidth   , 0 ,
01850                               XmNrecomputeSize , False ,
01851                               XmNtraversalOn   , False ,
01852                               XmNuserData      , (XtPointer) av ,
01853                               XmNinitialResourcesPersistent , False ,
01854                            NULL ) ;
01855 
01856                XtAddCallback( av->pb , XmNactivateCallback ,
01857                               PLUG_choose_timeseries_CB , (XtPointer) plint ) ;
01858 
01859                XtManageChild( av->rowcol ) ;
01860 
01861                ow->chooser[ib] = (void *) av ;
01862                ow->chtop[ib]   = av->rowcol ;  /* get the top widget */
01863 
01864                ow->chooser_type[ib] = OP_CHOOSER_TIMESERIES ;
01865                toff-- ;
01866             }
01867             break ;
01868 
01869          }  /* end of switch on subvalue type */
01870 
01871          /** set initial attachments for the topmost chooser widget **/
01872 
01873          XtVaSetValues(
01874             ow->chtop[ib] ,
01875                XmNleftAttachment   , (ib==0) ? XmATTACH_WIDGET    /* First column  */
01876                                              : XmATTACH_NONE ,    /* of widgets    */
01877                XmNleftOffset       , (ib==0) ? 6                  /* is attached   */
01878                                              : 0 ,                /* to the label. */
01879                XmNleftWidget       , (ib==0) ? ow->label          /* Later columns */
01880                                              : NULL ,             /* fixed below.  */
01881 
01882                XmNtopAttachment    , (iopt==0) ? XmATTACH_FORM     /* 1st row */
01883                                                : XmATTACH_WIDGET , /* 2nd+ row */
01884                XmNtopOffset        , toff ,
01885                XmNtopWidget        , separator ,
01886             NULL ) ;
01887 
01888          if( !opt->mandatory ) XtSetSensitive( ow->chtop[ib] , False ) ;
01889 
01890          if( sv->hint != NULL )
01891              MCW_reghint_children( ow->chtop[ib] , sv->hint ) ;
01892 
01893          /** find out if this is the widest one in its column so far **/
01894 
01895          MCW_widget_geom( ow->chtop[ib] , &ww , NULL,NULL,NULL ) ;
01896 
01897          if( ww > widest_width[ib] ){
01898             widest_width[ib]   = ww ;
01899             widest_chooser[ib] = ow->chtop[ib] ;
01900          }
01901 
01902       }  /* end of loop over subvalues */
01903 
01904       /** separator between option rows **/
01905 
01906       separator = XtVaCreateManagedWidget(
01907                     "AFNI" , xmSeparatorWidgetClass , wid->workwin ,
01908                        XmNseparatorType  , XmSHADOW_ETCHED_OUT ,
01909                        XmNshadowThickness, 5 ,
01910                        XmNleftAttachment , XmATTACH_FORM ,
01911                        XmNrightAttachment, XmATTACH_FORM ,
01912                        XmNtopAttachment  , XmATTACH_WIDGET ,
01913                        XmNtopWidget      , ow->toggle ,
01914                        XmNtopOffset      , 7 ,
01915                     NULL ) ;
01916 
01917    } /* end of loop over options */
01918 
01919 #if 0
01920 fprintf(stderr,"Widget attachments\n") ;
01921 #endif
01922 
01923    /**** Now that we've created all the rows,
01924          and have found all the widest widgets in each column,
01925          go back and attach each column to the widest one to its left. ****/
01926 
01927    for( iopt=0 ; iopt < plint->option_count ; iopt++ ){
01928       opt = plint->option[iopt] ;
01929       if( opt == NULL ) continue ; /* bad? */
01930 
01931       ow = opwid[iopt] ;
01932       for( ib=1 ; ib < opt->subvalue_count ; ib++ ){
01933          XtVaSetValues( ow->chtop[ib] ,
01934                            XmNleftAttachment , XmATTACH_WIDGET ,
01935                            XmNleftWidget     , widest_chooser[ib-1] ,
01936                            XmNleftOffset     , 6 ,
01937                         NULL ) ;
01938       }
01939    }
01940 
01941 #if 0
01942 fprintf(stderr,"Widget separators\n") ;
01943 #endif
01944 
01945    /**** Create a vertical separator to the left of each column ****/
01946 
01947    if( plint->option_count > 0 ){
01948       for( ib=0 ; ib < PLUGIN_MAX_SUBVALUES && widest_width[ib] > 0 ; ib++ ){
01949          separator = XtVaCreateManagedWidget(
01950                        "AFNI" , xmSeparatorWidgetClass , wid->workwin ,
01951                           XmNseparatorType   , XmSHADOW_ETCHED_OUT ,
01952                           XmNorientation     , XmVERTICAL ,
01953                           XmNtopAttachment   , XmATTACH_FORM ,
01954                           XmNbottomAttachment, XmATTACH_FORM ,
01955                           XmNrightAttachment , XmATTACH_WIDGET ,
01956                           XmNrightWidget     , widest_chooser[ib] ,
01957                           XmNrightOffset     , 2 ,
01958                        NULL ) ;
01959 
01960       }
01961    }
01962 
01963 #if 0
01964 fprintf(stderr,"Widget management\n") ;
01965 #endif
01966 
01967    /**** Manage the managers, and go home ****/
01968 
01969    if( plint->option_count > 0 ){
01970       XtManageChild( wid->workwin ) ;
01971       XtManageChild( wframe ) ;
01972       XtManageChild( wid->scrollw ) ;
01973    }
01974    XtManageChild( wid->form ) ;
01975 
01976 #if 0
01977 fprintf(stderr,"Widget realization\n") ;
01978 #endif
01979 
01980    XtRealizeWidget( wid->shell ) ;  /* will not be mapped */
01981 
01982    /** set its width after it is mapped **/
01983 
01984 #define OPC_MAX     8
01985 #define OPC_MAXMAX 10
01986 #define LUCK        5
01987 
01988    if( wframe != NULL ){
01989       Widget bar ;
01990       int fww , fhh , fyy , bww ;
01991 
01992 #if 0
01993 fprintf(stderr,"Widget geometrization\n") ;
01994 #endif
01995 
01996       MCW_widget_geom( wid->label   , &ww , &hh , NULL, NULL ) ;  /* get dimensions */
01997       MCW_widget_geom( wframe       , &fww, &fhh, NULL, NULL ) ;  /* of various */
01998       MCW_widget_geom( wid->scrollw , NULL, NULL, NULL, &fyy ) ;  /* pieces-parts */
01999 
02000       fww = MAX( fww+LUCK , ww ) ;  /* extra pixels for luck */
02001 
02002       ib = plint->option_count ;     /* too many options --> will use vertical scrollbar */
02003       if( ib > OPC_MAXMAX ){
02004          fhh = (OPC_MAX * fhh) / ib ;  /* set height to allow for OPC_MAX options visible */
02005 
02006          if( fww > ww ){               /* set width to allow for vertical scrollbar */
02007             XtVaGetValues( wid->scrollw , XmNverticalScrollBar , &bar , NULL ) ;
02008             MCW_widget_geom( bar , &bww , NULL,NULL,NULL ) ;
02009             fww += bww+LUCK+LUCK ;     /* need more luck here, I guess */
02010          }
02011       }
02012       fhh += fyy+LUCK ;  /* set height to allow for stuff above options */
02013 
02014       XtVaSetValues( wid->shell , XmNwidth , fww , XmNheight , fhh , NULL ) ;
02015    }
02016 
02017    /** set the popup meter to be nothing at all right now **/
02018 
02019    wid->meter = NULL ;
02020 
02021 #if 0
02022 fprintf(stderr,"Widgets done!\n") ;
02023 #endif
02024 
02025    EXRETURN ;
02026 }
02027 
02028 /*-----------------------------------------------------------------------
02029   21 Feb 2001: routine to turn off optional inputs
02030 -------------------------------------------------------------------------*/
02031 
02032 void PLUTO_turnoff_options( PLUGIN_interface * plint )
02033 {
02034    int kk ;
02035 
02036 ENTRY("PLUTO_turnoff_options") ;
02037 
02038    /**** sanity checks ****/
02039 
02040    if( plint == NULL || plint->wid == NULL ||
02041        plint->call_method == PLUGIN_CALL_IMMEDIATELY ) EXRETURN ;
02042 
02043    /**** loop over options */
02044 
02045    for( kk=0 ; kk < plint->option_count ; kk++ ){
02046       if( !plint->option[kk]->mandatory )
02047          XmToggleButtonSetState( plint->wid->opwid[kk]->toggle, False,True ) ;
02048    }
02049 
02050    EXRETURN ;
02051 }
02052 
02053 /*-----------------------------------------------------------------------
02054    What happens when a plugin interface action button is pressed
02055 -------------------------------------------------------------------------*/
02056 
02057 void PLUG_action_CB( Widget w , XtPointer cd , XtPointer cbs )
02058 {
02059    PLUGIN_interface * plint = (PLUGIN_interface *) cd ;
02060    char * wname = XtName(w) ;
02061    char * mesg ;
02062    int close , run , badrun=0 , help ;
02063 
02064 ENTRY("PLUG_action_CB") ;
02065 
02066    run   = (strcmp(wname,plint->doit_label)==0) || (strcmp(wname,plint->run_label)==0);
02067    close = (strcmp(wname,plint->doit_label)==0) || (strcmp(wname,PLUG_quit_label) ==0);
02068    help  = (strcmp(wname,PLUG_help_label)==0) ;
02069 
02070    if( run ){
02071       PLUG_fillin_values( plint ) ;       /* load callvalues  */
02072       plint->opnum = plint->svnum = -1 ;  /* initialize get_  */
02073 
02074       /***** CALL THE PLUGIN !!!! *****/
02075 
02076       MPROBE ;
02077 
02078       SHOW_AFNI_PAUSE ;
02079 #if 0
02080       mesg = plint->call_func( plint ) ;
02081 #else
02082       AFNI_CALL_VALU_1ARG( plint->call_func ,
02083                            char *,mesg , PLUGIN_interface *,plint ) ;
02084 #endif
02085       SHOW_AFNI_READY ;
02086 
02087       PLUTO_popdown_meter( plint ) ;  /* if the user forgets */
02088 
02089       MPROBE ;
02090 
02091       /********************************/
02092 
02093       badrun = (mesg != NULL) ;
02094       if( badrun ){
02095          if( w != NULL ){
02096             (void) MCW_popup_message( w , mesg , MCW_USER_KILL ) ;
02097             XBell( XtDisplay(w) , 100 ) ;
02098          } else {
02099             fprintf(stderr,"\n%s\a\n",mesg) ;
02100          }
02101       }
02102    }
02103 
02104    if( close && !badrun ) PLUG_delete_window_CB( w , cd , cbs ) ;
02105 
02106    /* 28 Dec 1997: use a scrolling text window if help too big */
02107 
02108    if( help ){
02109       int nl = THD_linecount( plint->helpstring ) ;
02110       if( nl < 10 ) MCW_popup_message( plint->wid->label ,
02111                                        plint->helpstring , MCW_USER_KILL ) ;
02112       else          new_MCW_textwin  ( plint->wid->label ,
02113                                        plint->helpstring , TEXT_READONLY ) ;
02114    }
02115 
02116    EXRETURN ;
02117 }
02118 
02119 /*------------------------------------------------------------------------
02120    What happens when the user selects "Close" from the window
02121    menu in a plugin interface menu window.
02122 --------------------------------------------------------------------------*/
02123 
02124 void PLUG_delete_window_CB( Widget w , XtPointer cd , XtPointer cbs )
02125 {
02126    PLUGIN_interface * plint = (PLUGIN_interface *) cd ;
02127 
02128 ENTRY("PLUG_delete_window_CB") ;
02129 
02130    if( plint != NULL && plint->wid != NULL ){
02131       XtUnmapWidget(plint->wid->shell) ;
02132       XmUpdateDisplay(plint->wid->shell) ;
02133    }
02134    EXRETURN ;
02135 }
02136 
02137 /*------------------------------------------------------------------------
02138    What happens when the user toggles an option's toggle button.
02139 --------------------------------------------------------------------------*/
02140 
02141 void PLUG_optional_toggle_CB( Widget w , XtPointer cd , XtPointer cbs )
02142 {
02143    PLUGIN_option_widgets * ow = (PLUGIN_option_widgets *) cd ;
02144    int ib , zlen ;
02145    XtPointer xptr ;
02146 
02147 ENTRY("PLUG_optional_toggle_CB") ;
02148 
02149    /** invert label widget, and switch sensitivity of subvalue widgets **/
02150 
02151    if( ow != NULL ){
02152 #if 0
02153       if( ow->label != NULL ){
02154          XtVaGetValues( ow->label , XmNuserData , &xptr , NULL ) ;
02155          zlen = (int) xptr ;
02156          if( !zlen ) MCW_invert_widget( ow->label ) ;
02157       }
02158 #endif
02159 
02160       for( ib=0 ; ib < PLUGIN_MAX_SUBVALUES ; ib++ )
02161          if( ow->chtop[ib] != NULL )
02162             XtSetSensitive( ow->chtop[ib] , !XtIsSensitive(ow->chtop[ib]) ) ;
02163    }
02164    EXRETURN ;
02165 }
02166 
02167 /*--------------------------------------------------------------------------
02168   Routine to take the interface widgets and put their values into
02169   place, so that the plugin can get them out again.
02170 ----------------------------------------------------------------------------*/
02171 
02172 void PLUG_fillin_values( PLUGIN_interface * plint )
02173 {
02174    int iopt , ib ;
02175    PLUGIN_option_widgets ** opwid , * ow ;
02176    PLUGIN_option * opt ;
02177    PLUGIN_subvalue * sv ;
02178 
02179 ENTRY("PLUG_fillin_values") ;
02180 
02181    /*--- check if there is anything to do ---*/
02182 
02183    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
02184 
02185    /*--- scan thru options ---*/
02186 
02187    opwid = plint->wid->opwid ;
02188 
02189    for( iopt=0 ; iopt < plint->option_count ; iopt++){
02190 
02191       opt = plint->option[iopt] ;   /* option to deal with */
02192       if( opt == NULL ) continue ;  /* bad? */
02193 
02194       ow = opwid[iopt] ;  /* row of widgets to deal with */
02195 
02196       /*-- find if this option is chosen by the user --*/
02197 
02198       opt->chosen = (int) XmToggleButtonGetState( ow->toggle ) ;
02199 
02200       /*-- scan thru subvalues, and load callvalue.
02201            note that we do this even for unchosen options. --*/
02202 
02203       for( ib=0 ; ib < opt->subvalue_count ; ib++ ){
02204 
02205         myXtFree( opt->callvalue[ib]  ) ;  /* free any old value here */
02206         sv = &(opt->subvalue[ib]) ;        /* subvalue to deal with */
02207 
02208         /*-- deal with each type of subvalue --*/
02209 
02210         switch( sv->data_type ){
02211 
02212            /** some type I don't know, so just put NULL in **/
02213 
02214            default:
02215               opt->callvalue[ib] = NULL ;
02216            break ;
02217 
02218            /** 11 Jul 2001: overlay color type; send in the color index **/
02219 
02220            case PLUGIN_OVERLAY_COLOR_TYPE:{
02221               MCW_arrowval * av = (MCW_arrowval *) ow->chooser[ib] ;
02222               int * iptr ;
02223 
02224               iptr  = (int *) XtMalloc( sizeof(int) ) ;
02225               *iptr = av->ival ;
02226               opt->callvalue[ib] = (void *) iptr ;
02227            }
02228            break ;
02229 
02230            /** number type: uses arrowval interface;
02231                             send in the float value **/
02232 
02233            case PLUGIN_NUMBER_TYPE:{
02234               MCW_arrowval * av = (MCW_arrowval *) ow->chooser[ib] ;
02235               float * fptr ;
02236 
02237               fptr  = (float *) XtMalloc( sizeof(float) ) ;
02238               *fptr = av->fval ;
02239               opt->callvalue[ib] = (void *) fptr ;
02240            }
02241            break ;
02242 
02243            /** string type: may be an arrowval or a strval **/
02244 
02245            case PLUGIN_STRING_TYPE:{
02246               if( sv->string_range_count > 0 ){
02247                  MCW_arrowval * av = (MCW_arrowval *) ow->chooser[ib] ;
02248                  char * cptr ;
02249 
02250                  cptr = XtNewString( av->sval ) ;
02251                  opt->callvalue[ib] = (void *) cptr ;
02252               } else {
02253                  PLUGIN_strval * av = (PLUGIN_strval *) ow->chooser[ib] ;
02254                  char * cptr ;
02255 
02256                  cptr = XmTextFieldGetString( av->textf ) ;
02257                  opt->callvalue[ib] = (void *) cptr ;
02258               }
02259            }
02260            break ;
02261 
02262            /** dataset type **/
02263 
02264            case PLUGIN_DATASET_TYPE:{
02265               PLUGIN_dsetval * av = (PLUGIN_dsetval *) ow->chooser[ib] ;
02266               MCW_idcode * idc ;
02267 
02268               idc = myXtNew( MCW_idcode ) ;
02269               if( av->dset_choice < 0 )
02270                  ZERO_IDCODE(*idc) ;
02271               else
02272                  *idc = av->dset_link[av->dset_choice].idcode ;
02273 
02274               opt->callvalue[ib] = (void *) idc ;
02275            }
02276            break ;
02277 
02278            /** 25 Nov 1996: list of datasets **/
02279 
02280            case PLUGIN_DATASET_LIST_TYPE:{
02281               PLUGIN_dsetval * av = (PLUGIN_dsetval *) ow->chooser[ib] ;
02282               MCW_idclist ** llist ;
02283               int id ;
02284 
02285               llist = myXtNew(MCW_idclist *) ; *llist = av ;
02286 
02287               av->current = 0 ;
02288               if( av->nchosen <= 0 ){
02289                  myXtFree(av->idclist) ;
02290               } else {
02291                  av->idclist = (MCW_idcode *)
02292                                XtRealloc( (char *) av->idclist ,
02293                                           sizeof(MCW_idcode) * av->nchosen ) ;
02294                  for( id=0 ; id < av->nchosen ; id++ )
02295                     av->idclist[id] = av->dset_link[av->chosen[id]].idcode ;
02296               }
02297 
02298               opt->callvalue[ib] = (void *) llist ;
02299            }
02300            break ;
02301            /** timeseries type **/
02302 
02303            case PLUGIN_TIMESERIES_TYPE:{
02304               PLUGIN_tsval * av = (PLUGIN_tsval *) ow->chooser[ib] ;
02305               MRI_IMAGE ** imp ;
02306 
02307               imp  = myXtNew(MRI_IMAGE *) ;
02308               *imp = av->tsim ;
02309 
02310               opt->callvalue[ib] = (void *) imp ;
02311            }
02312            break ;
02313 
02314         } /* end of switch over subvalue type */
02315       }  /* end of scan thru subvalues */
02316    } /* end of scan thru options */
02317 
02318    EXRETURN ;
02319 }
02320 
02321 /*--------------------------------------------------------------------------
02322   Routine to take the interface widgets and clear their callvalues to NULL.
02323 ----------------------------------------------------------------------------*/
02324 
02325 void PLUG_freeup_values( PLUGIN_interface * plint )
02326 {
02327    int iopt , ib ;
02328    PLUGIN_option * opt ;
02329 
02330 ENTRY("PLUG_freeup_values") ;
02331 
02332    /*--- check if there is anything to do ---*/
02333 
02334    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
02335 
02336    /*--- scan thru options ---*/
02337 
02338    for( iopt=0 ; iopt < plint->option_count ; iopt++){
02339 
02340       opt = plint->option[iopt] ;   /* option to deal with */
02341       if( opt == NULL ) continue ;  /* bad? */
02342 
02343       /*-- scan thru subvalues, and free all callvalues --*/
02344 
02345       for( ib=0 ; ib < opt->subvalue_count ; ib++ ){
02346         XtFree( opt->callvalue[ib]  ) ;  /* free any old value here */
02347         opt->callvalue[ib] = NULL ;
02348       }
02349 
02350    } /* end of scan thru options */
02351 
02352    EXRETURN ;
02353 }
02354 
02355 /*-----------------------------------------------------------------------
02356    Routines to get values from a plugin interface, when passed
02357    to a plugin.
02358 -------------------------------------------------------------------------*/
02359 
02360 char * get_label_from_PLUGIN_interface( PLUGIN_interface * plint )
02361 {
02362 ENTRY("get_label_from_PLUGIN_interface") ;
02363    if( plint == NULL ) RETURN(NULL) ;
02364    else                RETURN(plint->label) ;
02365 }
02366 
02367 char * get_description_from_PLUGIN_interface( PLUGIN_interface * plint )
02368 {
02369 ENTRY("get_description_from_PLUGIN_interface") ;
02370    if( plint == NULL ) RETURN(NULL) ;
02371    else                RETURN(plint->description) ;
02372 }
02373 
02374 /*-----------------------------------------------------------------------
02375    Get the next chosen option, and return its string "tag".
02376    If there is no "next chosen option", return NULL.
02377 -------------------------------------------------------------------------*/
02378 
02379 char * get_optiontag_from_PLUGIN_interface( PLUGIN_interface * plint )
02380 {
02381    int iopt ;
02382    PLUGIN_option * opt ;
02383 
02384 ENTRY("get_optiontag_from_PLUGIN_interface") ;
02385 
02386    if( plint == NULL ) RETURN(NULL) ;
02387 
02388    iopt = plint->opnum + 1 ;
02389    while( iopt < plint->option_count ){
02390 
02391       opt = plint->option[iopt++] ;
02392       if( opt == NULL )   continue ; /* bad? */
02393       if( ! opt->chosen ) continue ; /* not used this time */
02394 
02395       plint->opnum = iopt-1 ;        /* keep track of which option */
02396       plint->svnum = 0 ;             /* start at 1st subvalue */
02397       RETURN(opt->tag) ;
02398    }
02399 
02400    plint->opnum = plint->option_count ;
02401    RETURN(NULL) ;
02402 }
02403 
02404 /*-----------------------------------------------------------------------
02405    Return a string encaspulating information about how the plugin
02406    was called.  This string is created with malloc() and should be
02407    free()-ed when it is used up.  If NULL is returned, an error
02408    occurred (and you should be ashamed of yourself).
02409    -- 31 Aug 1999 -- RWCox
02410 -------------------------------------------------------------------------*/
02411 
02412 #include <stdarg.h>
02413 
02414 static void blanktrim( char * ch )
02415 {
02416    int ii , ll ;
02417    if( ch == NULL ) return ;
02418    ll = strlen(ch) ; if( ll < 2 ) return ;
02419    for( ii=ll-1 ; ii > 0 ; ii-- )
02420       if( isspace(ch[ii]) ) ch[ii] = '\0' ; else break ;
02421    return ;
02422 }
02423 
02424 #undef BUFIT
02425 #define BUFIT(s) do{ strcpy(buf,s); blanktrim(buf); } while(0)
02426 
02427 char * PLUTO_commandstring( PLUGIN_interface * plint )
02428 {
02429    char * outbuf = NULL ;
02430    PLUGIN_option * opt ;
02431    PLUGIN_subvalue * sv ;
02432    int iopt , jsv ;
02433    char buf[256] ;
02434 
02435 ENTRY("PLUTO_commandstring") ;
02436 
02437    if( plint == NULL ) RETURN(outbuf) ;
02438 
02439    BUFIT(plint->label) ;
02440    outbuf = THD_zzprintf( outbuf , "%s " , buf ) ;  /* start with name */
02441 
02442    if( plint->call_method != PLUGIN_CALL_VIA_MENU ||
02443        plint->option_count == 0                   ||
02444        plint->option == NULL                        ) RETURN(outbuf) ;
02445 
02446    /* loop over each option for the plugin */
02447 
02448    for( iopt=0 ; iopt < plint->option_count ; iopt++ ){
02449       opt = plint->option[iopt] ;
02450       if( opt == NULL ) continue ;   /* bad? */
02451       if( ! opt->chosen ) continue ; /* not used this time */
02452 
02453       BUFIT(opt->label) ;
02454       outbuf = THD_zzprintf( outbuf , "{%s: " , buf ) ;
02455 
02456       /* if this option is used, put a list of its subvalues in the string */
02457 
02458       for( jsv=0 ; jsv < opt->subvalue_count ; jsv++ ){
02459          sv = &(opt->subvalue[jsv]) ;
02460          BUFIT(sv->label) ;
02461          outbuf = THD_zzprintf( outbuf , "%s=" , buf ) ;
02462          switch( sv->data_type ){
02463 
02464             default:
02465                outbuf = THD_zzprintf( outbuf,"?" ) ; break ;
02466 
02467             case PLUGIN_OVERLAY_COLOR_TYPE:{
02468                int * val = (int *) opt->callvalue[jsv] ;
02469                MCW_DC * dc = plint->im3d->dc ;
02470                if( val != NULL && *val >= 0 )
02471                  outbuf = THD_zzprintf( outbuf,"%s",dc->ovc->label_ov[*val] );
02472                else
02473                  outbuf = THD_zzprintf( outbuf,"?" ) ;
02474             }
02475             break ;
02476 
02477             case PLUGIN_NUMBER_TYPE:{
02478                float * val = (float *) opt->callvalue[jsv] ;
02479                if( val != NULL ) outbuf = THD_zzprintf( outbuf,"%g",*val) ;
02480                else              outbuf = THD_zzprintf( outbuf,"?" ) ;
02481             }
02482             break ;
02483 
02484             case PLUGIN_STRING_TYPE:{
02485                 char * val = (char *) opt->callvalue[jsv] ;
02486                 if( val != NULL ){ BUFIT(val); outbuf = THD_zzprintf( outbuf,"%s",buf); }
02487                 else                           outbuf = THD_zzprintf( outbuf,"?" ) ;
02488             }
02489             break ;
02490 
02491             case PLUGIN_DATASET_LIST_TYPE:{
02492                MCW_idclist ** llist = (MCW_idclist **) opt->callvalue[jsv] ;
02493                int nd = PLUTO_idclist_count(*llist) ;
02494                outbuf = THD_zzprintf( outbuf , "[%d dsets]" , nd ) ;
02495             }
02496             break ;
02497 
02498             case PLUGIN_DATASET_TYPE:{
02499                MCW_idcode * idc = (MCW_idcode *) opt->callvalue[jsv] ;
02500                THD_3dim_dataset * dset ;
02501 
02502                dset = PLUTO_find_dset( idc ) ;
02503                if( dset != NULL ){
02504                   char * qb = THD_trailname(DSET_HEADNAME(dset),SESSTRAIL+1) ;
02505                   outbuf = THD_zzprintf( outbuf,"%s",qb) ;
02506                } else
02507                   outbuf = THD_zzprintf( outbuf,"?" ) ;
02508             }
02509             break ;
02510 
02511             case PLUGIN_TIMESERIES_TYPE:{
02512                MRI_IMAGE ** imp = (MRI_IMAGE **) opt->callvalue[jsv] ;
02513 
02514                if( imp != NULL && *imp != NULL && (*imp)->name != NULL )
02515                   outbuf = THD_zzprintf( outbuf,"%s",(*imp)->name ) ;
02516                else
02517                   outbuf = THD_zzprintf( outbuf,"?" ) ;
02518             }
02519             break ;
02520 
02521          } /* end of switch on subvalue type */
02522 
02523          if( jsv < opt->subvalue_count - 1 )
02524             outbuf = THD_zzprintf( outbuf,"; ") ;
02525 
02526       } /* end of loop on subvalues */
02527 
02528       outbuf = THD_zzprintf( outbuf , "} " ) ;  /* end of this option */
02529 
02530    } /* end of loop on options */
02531 
02532    RETURN(outbuf) ;
02533 }
02534 
02535 /*-------------------------------------------------------------------------
02536    Find out what the next chosen option is, without actually retrieving it.
02537 ---------------------------------------------------------------------------*/
02538 
02539 char * peek_optiontag_from_PLUGIN_interface( PLUGIN_interface * plint )
02540 {
02541    int iopt ;
02542    PLUGIN_option * opt ;
02543 
02544 ENTRY("peek_optiontag_from_PLUGIN_interface") ;
02545 
02546    if( plint == NULL ) RETURN(NULL) ;
02547 
02548    iopt = plint->opnum + 1 ;
02549    while( iopt < plint->option_count ){
02550       opt = plint->option[iopt++] ;
02551       if( opt == NULL ) continue ; /* bad? */
02552       if( opt->chosen ) RETURN(opt->tag) ;
02553    }
02554    RETURN(NULL) ;
02555 }
02556 
02557 /*-------------------------------------------------------------------------
02558    Find out what the next subvalue type is, without actually retrieving it.
02559    This will be one of the PLUGIN_*_TYPE codes.  If something is wrong,
02560    the return value will be ILLEGAL_TYPE.  This can be used to detect that
02561    no more subvalues are present in the option currently being processed.
02562 ---------------------------------------------------------------------------*/
02563 
02564 int peek_callvalue_type_from_PLUGIN_interface( PLUGIN_interface * plint )
02565 {
02566    int isv ;
02567    PLUGIN_option * opt ;
02568 
02569 ENTRY("peek_callvalue_type_from_PLUGIN_interface") ;
02570 
02571    if( plint == NULL ) RETURN(ILLEGAL_TYPE) ;
02572    if( plint->opnum >= plint->option_count ) RETURN(ILLEGAL_TYPE) ;
02573 
02574    opt = plint->option[ plint->opnum ] ;
02575    if( opt == NULL ) RETURN(ILLEGAL_TYPE) ;
02576 
02577    isv = plint->svnum ;
02578    if( isv >= opt->subvalue_count ) RETURN(ILLEGAL_TYPE) ;
02579 
02580    RETURN(opt->subvalue[isv].data_type) ;
02581 }
02582 
02583 /*-------------------------------------------------------------------------
02584    Get the next subvalue, which should be of the type given by
02585    "type".  If it is not, return NULL, otherwise return a "void *",
02586    which must be properly de-referenced to get the true value:
02587 
02588      type                      output is really
02589      ------------------        ----------------
02590      PLUGIN_NUMBER_TYPE        float *         points to number
02591      PLUGIN_STRING_TYPE        char *          duh
02592      PLUGIN_DATASET_TYPE       MCW_idcode *    duh
02593      PLUGIN_TIMESERIES_TYPE    MRI_IMAGE **    duh
02594      PLUGIN_OVERLAY_COLOR_TYPE int *           points to overlay index
02595 
02596    Following this are convenience routines to do similar work on specific
02597    data types.
02598 ---------------------------------------------------------------------------*/
02599 
02600 void * get_callvalue_from_PLUGIN_interface( PLUGIN_interface * plint , int type )
02601 {
02602    int isv ;
02603    PLUGIN_option * opt ;
02604 
02605 ENTRY("get_callvalue_from_PLUGIN_interface") ;
02606 
02607    if( plint == NULL ) RETURN( NULL );
02608 
02609    opt = plint->option[ plint->opnum ] ;
02610    if( opt == NULL ) RETURN( NULL );
02611 
02612    isv = plint->svnum ;
02613    if( isv >= opt->subvalue_count ) RETURN( NULL );
02614 
02615    if( opt->subvalue[isv].data_type != type ) RETURN( NULL );
02616 
02617    plint->svnum ++ ;
02618    RETURN( opt->callvalue[isv] );
02619 }
02620 
02621 /*----------------------------------------------------------------------------*/
02622 
02623 MRI_IMAGE * get_timeseries_from_PLUGIN_interface( PLUGIN_interface * plint )
02624 {
02625    MRI_IMAGE ** imp ;
02626 
02627 ENTRY("get_timeseries_from_PLUGIN_interface") ;
02628 
02629    imp = (MRI_IMAGE **)
02630          get_callvalue_from_PLUGIN_interface(plint,PLUGIN_TIMESERIES_TYPE) ;
02631 
02632    if( imp == NULL ) RETURN(NULL) ;
02633    RETURN(*imp) ;
02634 }
02635 
02636 /*----------------------------------------------------------------------------*/
02637 
02638 float get_number_from_PLUGIN_interface( PLUGIN_interface * plint )
02639 {
02640    float * fp ;
02641 ENTRY("get_number_from_PLUGIN_interface") ;
02642    fp = (float *)get_callvalue_from_PLUGIN_interface(plint,PLUGIN_NUMBER_TYPE) ;
02643    if( fp == NULL ) RETURN(BAD_NUMBER) ;
02644    RETURN(*fp) ;
02645 }
02646 
02647 /*----------------------------------------------------------------------------*/
02648 
02649 int get_overlaycolor_from_PLUGIN_interface( PLUGIN_interface * plint )
02650 {
02651    int * ip ;
02652 ENTRY("get_overlaycolor_from_PLUGIN_interface") ;
02653    ip = (int *)get_callvalue_from_PLUGIN_interface(plint,PLUGIN_OVERLAY_COLOR_TYPE) ;
02654    if( ip == NULL ) RETURN(-1) ;
02655    RETURN(*ip) ;
02656 }
02657 
02658 /*----------------------------------------------------------------------------*/
02659 
02660 char * get_string_from_PLUGIN_interface( PLUGIN_interface * plint )
02661 {
02662 ENTRY("get_string_from_PLUGIN_interface") ;
02663    RETURN(
02664      (char *) get_callvalue_from_PLUGIN_interface(plint,PLUGIN_STRING_TYPE) );
02665 }
02666 
02667 /*----------------------------------------------------------------------------*/
02668 
02669 MCW_idcode * get_idcode_from_PLUGIN_interface( PLUGIN_interface * plint )
02670 {
02671 ENTRY("get_idcode_from_PLUGIN_interface") ;
02672    RETURN(
02673      (MCW_idcode *)get_callvalue_from_PLUGIN_interface(plint,PLUGIN_DATASET_TYPE) );
02674 }
02675 
02676 /*----------------------------------------------------------------------------*/
02677 
02678 MCW_idclist * get_idclist_from_PLUGIN_interface( PLUGIN_interface * plint )
02679 {
02680    MCW_idclist ** llist ;
02681 
02682 ENTRY("get_idclist_from_PLUGIN_interface") ;
02683 
02684    llist = (MCW_idclist **)
02685            get_callvalue_from_PLUGIN_interface(plint,PLUGIN_DATASET_LIST_TYPE) ;
02686 
02687    if( llist != NULL ) RETURN(*llist) ;
02688    RETURN(NULL) ;
02689 }
02690 
02691 /*------------------------------------------------------------------------
02692    What happens when a dataset chooser button is pressed:
02693      1) Retrieve the pointers to the data structures associated
02694           with the button.
02695      2) Select the datasets that are allowable and make a list of
02696           their names and idcodes.
02697      3) Popup a strlist chooser to let the user make the choice.
02698 
02699    24 Nov 1996: add the option for multiple choices, flagged by av->multi.
02700 --------------------------------------------------------------------------*/
02701 
02702 void PLUG_choose_dataset_CB( Widget w , XtPointer cd , XtPointer cbs )
02703 {
02704    PLUGIN_interface * plint = (PLUGIN_interface *) cd ;
02705    PLUGIN_dsetval   * av = NULL ;
02706    PLUGIN_subvalue  * sv = NULL ;
02707    Three_D_View     * im3d ;
02708 
02709    THD_session * ss ;
02710    THD_3dim_dataset * dset ;
02711    int iss_bot , iss_top , iss , vv ;
02712    int id , num_dset , qd ;
02713    MCW_idcode old_idcode ;
02714    static char ** strlist = NULL ;
02715    char label[64] ;
02716    int llen , ltop ;
02717    char qnam[THD_MAX_NAME] ;
02718 
02719    int          num_old = 0 , qold ;  /* multi-choice stuff */
02720    MCW_idcode * old_chosen = NULL ;
02721    int        * indold = NULL ;
02722 
02723 ENTRY("PLUG_choose_dataset_CB") ;
02724 
02725    /** find the stuff that is associated with this button **/
02726 
02727    XtVaGetValues( w , XmNuserData , &av , NULL ) ;
02728 
02729    if( plint == NULL || av == NULL ) EXRETURN ;
02730    sv = av->sv ;
02731    if( sv == NULL ) EXRETURN ;
02732    im3d = plint->im3d ;
02733 
02734    /** Select the datasets **/
02735 
02736    if( ! IM3D_VALID(im3d) || (sv->dset_ctrl_mask & SESSION_ALL_MASK) != 0 ){
02737       iss_bot = 0 ;
02738       iss_top = GLOBAL_library.sslist->num_sess - 1 ;
02739    } else {
02740       iss_bot = iss_top = im3d->vinfo->sess_num ;
02741    }
02742 
02743    if( im3d != NULL ) vv = im3d->vinfo->view_type ;  /* select view type */
02744    else               vv = VIEW_ORIGINAL_TYPE ;
02745 
02746    /** Save the current selection, if any **/
02747 
02748    if( ! av->multi ){
02749       if( av->dset_choice >= 0 && av->dset_choice < av->dset_count )
02750          old_idcode = av->dset_link[av->dset_choice].idcode ;
02751       else
02752          ZERO_IDCODE(old_idcode) ;
02753    } else {
02754       for( id=0 ; id < av->nchosen ; id++ ){
02755          if( av->chosen[id] >= 0 && av->chosen[id] < av->dset_count ){
02756             num_old++ ;
02757             old_chosen = (MCW_idcode *) XtRealloc((char *)old_chosen,
02758                                                   sizeof(MCW_idcode)*num_old) ;
02759             old_chosen[num_old-1] = av->dset_link[av->chosen[id]].idcode ;
02760          }
02761       }
02762    }
02763 
02764    /** Scan sessions **/
02765 
02766    num_dset = 0 ;
02767    for( iss=iss_bot ; iss <= iss_top ; iss++ ){
02768       ss = GLOBAL_library.sslist->ssar[iss] ;
02769 
02770       /* check datasets in this session */
02771 
02772       for( id=0 ; id < ss->num_dsset ; id++ ){
02773         dset = ss->dsset[id][vv] ;            if( dset == NULL ) continue ;
02774 
02775         if( sv->dset_anat_mask != 0 && ISANAT(dset) )
02776           if( ! PLUGIN_dset_check( sv->dset_anat_mask ,
02777                                    sv->dset_ctrl_mask , dset ) ) continue ;
02778 
02779         if( sv->dset_func_mask != 0 && ISFUNC(dset) )
02780           if( ! PLUGIN_dset_check( sv->dset_func_mask ,
02781                                    sv->dset_ctrl_mask , dset ) ) continue ;
02782 
02783         /* if we get here, then this dataset is OK to choose! */
02784 
02785         num_dset++ ;
02786         av->dset_link = (PLUGIN_dataset_link *)
02787                          XtRealloc( (char *) av->dset_link ,
02788                                     sizeof(PLUGIN_dataset_link)*num_dset ) ;
02789 
02790         make_PLUGIN_dataset_link( dset , av->dset_link + (num_dset-1) ) ;
02791       }
02792 
02793    } /* end of loop over sessions */
02794 
02795    /*--- if nothing was found that fits, then nothing further can happen ---*/
02796 
02797    if( num_dset == 0 ){
02798       av->dset_count  = 0 ;
02799       av->dset_choice = -1 ;
02800       myXtFree(old_chosen) ;
02801       XBell( XtDisplay(w) , 100 ) ;
02802       EXRETURN ;
02803    }
02804 
02805    /*--- 23 Nov 1996: loop over dataset links and patch their titles
02806                       to include an indicator of the dataset type    ---*/
02807 
02808    ltop = 4 ;
02809    for( id=0 ; id < num_dset ; id++ ){
02810       llen = strlen(av->dset_link[id].title) ;
02811       ltop = MAX(ltop,llen) ;
02812    }
02813 
02814    for( id=0 ; id < num_dset ; id++ ){
02815       dset = PLUTO_find_dset( &(av->dset_link[id].idcode) ) ;
02816       if( ! ISVALID_3DIM_DATASET(dset) ) continue ;
02817       if( ISANAT(dset) ){
02818          if( ISANATBUCKET(dset) )         /* 30 Nov 1997 */
02819             sprintf(qnam,"%-*s [%s:%d]" ,
02820                     ltop,av->dset_link[id].title ,
02821                     ANAT_prefixstr[dset->func_type] , DSET_NVALS(dset) ) ;
02822 
02823          else if( DSET_NUM_TIMES(dset) == 1 )
02824             sprintf(qnam,"%-*s [%s]" ,
02825                     ltop,av->dset_link[id].title ,
02826                     ANAT_prefixstr[dset->func_type] ) ;
02827 
02828          else
02829             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
02830                     ltop,av->dset_link[id].title ,
02831                     ANAT_prefixstr[dset->func_type] , DSET_NUM_TIMES(dset) ) ;
02832 
02833       } else {
02834          if( ISFUNCBUCKET(dset) )         /* 30 Nov 1997 */
02835             sprintf(qnam,"%-*s [%s:%d]" ,
02836                     ltop,av->dset_link[id].title ,
02837                     FUNC_prefixstr[dset->func_type] , DSET_NVALS(dset) ) ;
02838 
02839          else if( DSET_NUM_TIMES(dset) == 1 )
02840             sprintf(qnam,"%-*s [%s]" ,
02841                     ltop,av->dset_link[id].title ,
02842                     FUNC_prefixstr[dset->func_type] ) ;
02843 
02844          else
02845             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
02846                     ltop,av->dset_link[id].title ,
02847                     FUNC_prefixstr[dset->func_type] , DSET_NVALS(dset) ) ;
02848       }
02849 
02850       if( DSET_COMPRESSED(dset) ) strcat(qnam,"z") ;
02851 
02852       strcpy( av->dset_link[id].title , qnam ) ;
02853    }
02854 
02855    /*--- find the old choice in the current list, if any ---*/
02856 
02857    av->dset_count = num_dset ;
02858 
02859    if( ! av->multi ){
02860       if( !ISZERO_IDCODE(old_idcode) ){
02861          for( id=0 ; id < num_dset ; id++ )
02862             if( EQUIV_IDCODES(old_idcode,av->dset_link[id].idcode) ) break ;
02863 
02864          if( id < num_dset ) av->dset_choice = id ;
02865          else                av->dset_choice = -1 ;
02866       }
02867    } else {
02868       qold = 0 ;
02869       for( qd=0 ; qd < num_old ; qd++ ){
02870          if( !ISZERO_IDCODE(old_chosen[qd]) ){
02871             for( id=0 ; id < num_dset ; id++ )
02872                if( EQUIV_IDCODES(old_chosen[qd],av->dset_link[id].idcode) ) break ;
02873 
02874             if( id < num_dset ){
02875               qold++ ;
02876               indold = (int *) XtRealloc((char *)indold , sizeof(int)*qold) ;
02877               indold[qold-1] = id ;
02878               av->chosen[qold-1] = id ;
02879             }
02880           }
02881       }
02882       av->nchosen = qold ;
02883       if( qold > 0 ){
02884         qold++ ;
02885         indold = (int *) XtRealloc((char *)indold , sizeof(int)*qold) ;
02886         indold[qold-1] = -666 ;
02887       }
02888    }
02889 
02890    /*--- make a popup chooser for the user to browse ---*/
02891 
02892    POPDOWN_strlist_chooser ;
02893 
02894    strlist = (char **) XtRealloc( (char *)strlist , sizeof(char *)*num_dset ) ;
02895    for( id=0 ; id < num_dset ; id++ ) strlist[id] = av->dset_link[id].title ;
02896 
02897    sprintf( label , "AFNI Dataset from\nthe %s" , VIEW_typestr[vv] ) ;
02898 
02899    if( av->multi ){
02900       MCW_choose_multi_strlist( w , label , mcwCT_multi_mode ,
02901                                 num_dset , indold , strlist ,
02902                                 PLUG_finalize_dataset_CB , (XtPointer) plint ) ;
02903    } else {
02904       MCW_choose_strlist( w , label ,
02905                           num_dset , av->dset_choice , strlist ,
02906                           PLUG_finalize_dataset_CB , (XtPointer) plint ) ;
02907    }
02908 
02909    myXtFree(indold) ; myXtFree(old_chosen) ;
02910    EXRETURN ;
02911 }
02912 
02913 /*-----------------------------------------------------------------------
02914   Called when the user actually selects a dataset from the chooser.
02915   This routine just changes the original pushbutton label, and
02916   notes the index of the choice in the right place, for later retrieval.
02917 -------------------------------------------------------------------------*/
02918 
02919 void PLUG_finalize_dataset_CB( Widget w, XtPointer fd, MCW_choose_cbs * cbs )
02920 {
02921    PLUGIN_interface * plint = (PLUGIN_interface *) fd ;
02922    PLUGIN_dsetval   * av = NULL ;
02923    XmString           xstr ;
02924    int id ;
02925    char str[THD_MAX_NAME] ;
02926 
02927 ENTRY("PLUG_finalize_dataset_CB") ;
02928 
02929    /** find the stuff that is associated with this button **/
02930 
02931    XtVaGetValues( w , XmNuserData , &av , NULL ) ;
02932    if( plint == NULL || av == NULL ) EXRETURN ;
02933 
02934    if( ! av->multi ){
02935       xstr = XmStringCreateLtoR( av->dset_link[cbs->ival].title ,
02936                                  XmFONTLIST_DEFAULT_TAG ) ;
02937    } else {
02938       sprintf( str , "[%d]%s" , cbs->nilist , av->dset_link[cbs->ival].title ) ;
02939       xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
02940    }
02941    XtVaSetValues( w , XmNlabelString , xstr , NULL ) ;
02942    XmStringFree( xstr ) ;
02943 
02944    if( ! av->multi ){
02945       av->dset_choice = cbs->ival ;
02946    } else {
02947       av->nchosen = cbs->nilist ;
02948       av->chosen  = (int *) XtRealloc( (char *) av->chosen ,
02949                                        sizeof(int) * av->nchosen ) ;
02950       for( id=0 ; id < av->nchosen ; id++ ) av->chosen[id] = cbs->ilist[id] ;
02951    }
02952 
02953    EXRETURN ;
02954 }
02955 
02956 /*-----------------------------------------------------------------------
02957   Fill in a PLUGIN_dataset_link
02958 -------------------------------------------------------------------------*/
02959 
02960 void make_PLUGIN_dataset_link( THD_3dim_dataset * dset ,
02961                                PLUGIN_dataset_link * dsl )
02962 {
02963    char nam[THD_MAX_NAME] ;
02964    char * tnam ;
02965 
02966 ENTRY("make_PLUGIN_dataset_link") ;
02967 
02968    /*-- sanity checks --*/
02969 
02970    if( dsl == NULL ) EXRETURN ;
02971 
02972    if( ! ISVALID_3DIM_DATASET(dset) ){
02973       strcpy( dsl->title , "* garbage *" ) ;
02974       ZERO_IDCODE( dsl->idcode ) ;
02975       EXRETURN ;
02976    }
02977 
02978    /*-- make title (cf. AFNI_set_window_titles) --*/
02979 
02980    strcpy( nam , dset->dblk->diskptr->directory_name ) ;
02981    strcat( nam , dset->dblk->diskptr->filecode ) ;
02982    tnam = THD_trailname(nam,SESSTRAIL+1) ;
02983    MCW_strncpy( dsl->title , tnam , PLUGIN_STRING_SIZE ) ;
02984 
02985    /*-- copy idcode --*/
02986 
02987    dsl->idcode = dset->idcode ;
02988 
02989    EXRETURN ;
02990 }
02991 
02992 /*-----------------------------------------------------------------------
02993   Determine if a dataset passes the type_mask and ctrl_mask
02994   criteria for acceptability.
02995 -------------------------------------------------------------------------*/
02996 
02997 int PLUTO_dset_check( int anat_mask, int func_mask,
02998                       int ctrl_mask, THD_3dim_dataset * dset )
02999 {
03000    int iv=0 ;
03001 
03002    if( ISANAT(dset) )
03003       iv = PLUGIN_dset_check( anat_mask , ctrl_mask , dset ) ;
03004    else if( ISFUNC(dset) )
03005       iv = PLUGIN_dset_check( func_mask , ctrl_mask , dset ) ;
03006 
03007    return iv ;
03008 }
03009 
03010 int PLUGIN_dset_check( int type_mask , int ctrl_mask , THD_3dim_dataset * dset )
03011 {
03012    int itmp ;
03013 
03014 ENTRY("PLUGIN_dset_check") ;
03015 
03016    if( ! ISVALID_3DIM_DATASET(dset) ) RETURN(0) ;
03017 
03018    if( ((1 << dset->func_type) & type_mask) == 0 ) RETURN(0) ;
03019 
03020    itmp = (DSET_NUM_TIMES(dset) > 1) ? DIMEN_4D_MASK : DIMEN_3D_MASK ;
03021    if( (itmp & ctrl_mask) == 0 ) RETURN(0) ;
03022 
03023    if( !DSET_INMEMORY(dset) && (ctrl_mask & WARP_ON_DEMAND_MASK) == 0 ) RETURN(0) ;
03024 
03025    itmp = DSET_PRINCIPAL_VALUE(dset) ;  /* get the type of */
03026    itmp = DSET_BRICK_TYPE(dset,itmp) ;  /* the "principal" brick */
03027 
03028    if( itmp == MRI_byte    && (ctrl_mask & BRICK_BYTE_MASK)    == 0 ) RETURN(0) ;
03029    if( itmp == MRI_short   && (ctrl_mask & BRICK_SHORT_MASK)   == 0 ) RETURN(0) ;
03030    if( itmp == MRI_float   && (ctrl_mask & BRICK_FLOAT_MASK)   == 0 ) RETURN(0) ;
03031    if( itmp == MRI_complex && (ctrl_mask & BRICK_COMPLEX_MASK) == 0 ) RETURN(0) ;
03032    if( itmp == MRI_rgb     && (ctrl_mask & BRICK_RGB_MASK)     == 0 ) RETURN(0) ;
03033 
03034    RETURN(1) ;
03035 }
03036 
03037 /*-------------------------------------------------------------------------
03038    Loop over a bunch of dataset links and patch their
03039    titles to include an indicator of the dataset type, etc.
03040    23 October 1998 -- RWCox
03041 ---------------------------------------------------------------------------*/
03042 
03043 void patch_PLUGIN_dataset_links( int ndsl , PLUGIN_dataset_link * dsl )
03044 {
03045    int id , ltop , llen ;
03046    char qnam[THD_MAX_NAME] ;
03047    THD_3dim_dataset * dset ;
03048 
03049 ENTRY("patch_PLUGIN_dataset_links") ;
03050 
03051    if( ndsl < 1 || dsl == NULL ) EXRETURN ;
03052 
03053    ltop = 4 ;
03054    for( id=0 ; id < ndsl ; id++ ){    /* find longest string */
03055       llen = strlen(dsl[id].title) ;
03056       ltop = MAX(ltop,llen) ;
03057    }
03058 
03059    /* patch each title string */
03060 
03061    for( id=0 ; id < ndsl ; id++ ){
03062       dset = PLUTO_find_dset( &(dsl[id].idcode) ) ;  /* get the dataset */
03063       if( ! ISVALID_3DIM_DATASET(dset) ) continue ;  /* bad news for Bozo */
03064 
03065       if( ISANAT(dset) ){
03066          if( ISANATBUCKET(dset) )         /* 30 Nov 1997 */
03067             sprintf(qnam,"%-*s [%s:%d]" ,
03068                     ltop,dsl[id].title ,
03069                     ANAT_prefixstr[dset->func_type] , DSET_NVALS(dset) ) ;
03070 
03071          else if( DSET_NUM_TIMES(dset) == 1 )
03072             sprintf(qnam,"%-*s [%s]" ,
03073                     ltop,dsl[id].title ,
03074                     ANAT_prefixstr[dset->func_type] ) ;
03075 
03076          else
03077             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
03078                     ltop,dsl[id].title ,
03079                     ANAT_prefixstr[dset->func_type] , DSET_NUM_TIMES(dset) ) ;
03080 
03081       } else {
03082          if( ISFUNCBUCKET(dset) )         /* 30 Nov 1997 */
03083             sprintf(qnam,"%-*s [%s:%d]" ,
03084                     ltop,dsl[id].title ,
03085                     FUNC_prefixstr[dset->func_type] , DSET_NVALS(dset) ) ;
03086 
03087          else if( DSET_NUM_TIMES(dset) == 1 )
03088             sprintf(qnam,"%-*s [%s]" ,
03089                     ltop,dsl[id].title ,
03090                     FUNC_prefixstr[dset->func_type] ) ;
03091 
03092          else
03093             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
03094                     ltop,dsl[id].title ,
03095                     FUNC_prefixstr[dset->func_type] , DSET_NVALS(dset) ) ;
03096       }
03097 
03098       if( DSET_COMPRESSED(dset) ) strcat(qnam,"z") ;
03099 
03100       strcpy( dsl[id].title , qnam ) ;
03101    }
03102 
03103    EXRETURN ;
03104 }
03105 
03106 /*------------------------------------------------------------------------
03107    Popup a chooser list of datasets that meet some criteria.
03108    Note that only one such chooser will be popped up at any given time.
03109    This routine is for use in user-written plugins with custom interfaces.
03110    23 October 1998 -- RWCox
03111 
03112    w = widget to popup near
03113 
03114    vv = view type of datasets (cf. VIEW_*_TYPE from 3ddata.h)
03115            [one way to select this is plint->im3d->vinfo->view_type]
03116 
03117    multi = 1 to allow selection of multiple datasets
03118          = 0 to allow selection of only 1 dataset at a time
03119 
03120    chk_func = int function( THD_3dim_dataset * dset, void * cd ) ;
03121                 If this function pointer is not NULL, it will be called to
03122                 check if each dataset should be allowed in.  A zero return
03123                 value means don't allow; any other return value means dset
03124                 will be in the displayed list.  If chk_func is NULL, then
03125                 all datasets known to AFNI will be allowed.  [The function
03126                 PLUTO_dset_check() may be useful inside chk_func.]
03127 
03128    cb_func  = void function( int num, THD_3dim_dataset ** dslist, void * cd ) ;
03129                 This function pointer must not be NULL.  It will be called
03130                 when the user makes a choice on the popup chooser.
03131                 The value num will be the number of datasets chosen.
03132                 dslist[i] will be a pointer to the i-th dataset, for
03133                 i=0..num-1.  If multi was 0, then num will be 1 and the
03134                 single selected dataset will be pointed to by dlist[0].
03135 
03136    cd = A pointer to anything the user likes.  It will be passed to
03137           chk_func and cb_func, as described above.  (Can be NULL.)
03138 --------------------------------------------------------------------------*/
03139 
03140 static int                   num_user_dset     = 0 ;
03141 static PLUGIN_dataset_link * user_dset_link    = NULL ;
03142 static char **               user_dset_strlist = NULL ;
03143 static int                   user_dset_numds   = 0 ;
03144 static THD_3dim_dataset **   user_dset_dslist  = NULL ;
03145 static void_func *           user_dset_cb_func = NULL ;
03146 static void *                user_dset_cb_data = NULL ;
03147 
03148 void PLUTO_popup_dset_chooser( Widget w , int vv , int multi ,
03149                                int_func * chk_func ,
03150                                void_func * cb_func , void * cd )
03151 {
03152    THD_session * ss ;
03153    THD_3dim_dataset * dset ;
03154    int iss_bot , iss_top , iss ;
03155    int id ;
03156    char label[64] ;
03157 
03158 ENTRY("PLUTO_popup_dset_chooser") ;
03159 
03160    if( w == NULL            || cb_func == NULL     ||
03161        vv < FIRST_VIEW_TYPE || vv > LAST_VIEW_TYPE   ) EXRETURN ;
03162 
03163    /** Scan sessions **/
03164 
03165    iss_bot  = 0 ;
03166    iss_top  = GLOBAL_library.sslist->num_sess - 1 ;
03167    num_user_dset = 0 ;
03168 
03169    for( iss=iss_bot ; iss <= iss_top ; iss++ ){
03170       ss = GLOBAL_library.sslist->ssar[iss] ;
03171 
03172       /* check datasets from this session */
03173 
03174       for( id=0 ; id < ss->num_dsset ; id++ ){
03175          dset = ss->dsset[id][vv] ;    if( dset == NULL ) continue ;
03176 #if 0
03177          if( chk_func != NULL && chk_func(dset,cd) == 0 ) continue ; /* skip */
03178 #else
03179          { int cval=1 ;
03180            AFNI_CALL_VALU_2ARG( chk_func ,
03181                                 int,cval , THD_3dim_dataset *,dset, void *,cd ) ;
03182            if( cval == 0 ) continue ;
03183          }
03184 #endif
03185 
03186          num_user_dset++ ;
03187          user_dset_link = (PLUGIN_dataset_link *)
03188                           XtRealloc( (char *) user_dset_link ,
03189                                      sizeof(PLUGIN_dataset_link)*num_user_dset ) ;
03190 
03191          make_PLUGIN_dataset_link( dset , user_dset_link + (num_user_dset-1) ) ;
03192 
03193       } /* end of loop over datasets */
03194 
03195    } /* end of loop over sessions */
03196 
03197    /*--- if nothing was found that fits, then nothing further can happen ---*/
03198 
03199    if( num_user_dset == 0 ){
03200       myXtFree(user_dset_link) ; BEEPIT ;
03201       MCW_popup_message( w ,
03202                         "No datasets that meet this\ncriterion are available!" ,
03203                         MCW_USER_KILL|MCW_TIMER_KILL ) ;
03204       EXRETURN ;
03205    }
03206 
03207    /*--- make a popup chooser for the user to browse ---*/
03208 
03209    POPDOWN_strlist_chooser ;  /* death to the old regime */
03210 
03211    /* fix the dataset titles to be more fun */
03212 
03213    patch_PLUGIN_dataset_links( num_user_dset , user_dset_link ) ;
03214 
03215    /* make an array of pointers to all the titles */
03216 
03217    user_dset_strlist = (char **) XtRealloc( (char *) user_dset_strlist ,
03218                                             sizeof(char *) * num_user_dset ) ;
03219    for( id=0 ; id < num_user_dset ; id++ )
03220       user_dset_strlist[id] = user_dset_link[id].title ;
03221 
03222    /* label for the top of the chooser */
03223 
03224    sprintf( label , "AFNI Dataset from\nthe %s" , VIEW_typestr[vv] ) ;
03225 
03226    /* and take it away, Goldie */
03227 
03228    user_dset_cb_func = cb_func ;
03229    user_dset_cb_data = cd ;
03230 
03231    if( multi ){
03232       MCW_choose_multi_strlist( w , label , mcwCT_multi_mode ,
03233                                 num_user_dset , NULL , user_dset_strlist ,
03234                                 PLUG_finalize_user_dset_CB , NULL ) ;
03235    } else {
03236       MCW_choose_strlist( w , label ,
03237                           num_user_dset , -1 , user_dset_strlist ,
03238                           PLUG_finalize_user_dset_CB , NULL ) ;
03239    }
03240 
03241    EXRETURN ;
03242 }
03243 
03244 /*-----------------------------------------------------------------------
03245    Called when the user actually selects a dataset from the chooser.
03246    Will call the user's pitiful and loathsome routine.
03247    23 October 1998 -- RWCox
03248 -------------------------------------------------------------------------*/
03249 
03250 void PLUG_finalize_user_dset_CB( Widget w, XtPointer fd, MCW_choose_cbs * cbs )
03251 {
03252    int id , jd , num ;
03253 
03254 ENTRY("PLUG_finalize_user_dset_CB") ;
03255 
03256    if( cbs == NULL || cbs->nilist < 1 ) EXRETURN ;
03257 
03258    user_dset_numds = num = cbs->nilist ;
03259 
03260    user_dset_dslist = (THD_3dim_dataset **)
03261                          XtRealloc( (char *) user_dset_dslist ,
03262                                     sizeof(THD_3dim_dataset *) * num ) ;
03263 
03264    for( id=0 ; id < num ; id++ ){
03265       jd = cbs->ilist[id] ;
03266       user_dset_dslist[id] = PLUTO_find_dset( &(user_dset_link[jd].idcode) ) ;
03267    }
03268 
03269 #if 0
03270    user_dset_cb_func( num , user_dset_dslist , user_dset_cb_data ) ;
03271 #else
03272    AFNI_CALL_VOID_3ARG( user_dset_cb_func ,
03273                         int,num , THD_3dim_dataset **,user_dset_dslist ,
03274                         void *,user_dset_cb_data ) ;
03275 #endif
03276 
03277    EXRETURN ;
03278 }
03279 
03280 /*----------------------------------------------------------------------
03281    What happens when a timeseries chooser button is pressed:
03282      Popup a timeseries chooser window.
03283 ------------------------------------------------------------------------*/
03284 
03285 void PLUG_choose_timeseries_CB( Widget w , XtPointer cd , XtPointer cbs )
03286 {
03287    PLUGIN_interface * plint = (PLUGIN_interface *) cd ;
03288    PLUGIN_tsval     * av = NULL ;
03289    PLUGIN_subvalue  * sv = NULL ;
03290    Three_D_View     * im3d ;
03291    int init_ts ;
03292 
03293 ENTRY("PLUG_choose_timeseries_CB") ;
03294 
03295    /** find the stuff that is associated with this button **/
03296 
03297    XtVaGetValues( w , XmNuserData , &av , NULL ) ;
03298 
03299    if( plint == NULL || av == NULL ) EXRETURN ;
03300    sv = av->sv ;
03301    if( sv == NULL ) EXRETURN ;
03302    im3d = plint->im3d ;
03303 
03304    av->tsimar = GLOBAL_library.timeseries ; /* to choose amongst */
03305    if( av->tsimar==NULL || IMARR_COUNT(av->tsimar)==0 ){
03306       av->ts_choice = -1 ;
03307       av->tsim      = NULL ;
03308       XBell( XtDisplay(w) , 100 ) ;
03309       EXRETURN ;
03310    }
03311 
03312    init_ts = AFNI_ts_in_library( av->tsim ) ;
03313 
03314    MCW_choose_timeseries( w , "Choose Timeseries" ,
03315                           av->tsimar , init_ts ,
03316                           PLUG_finalize_timeseries_CB , (XtPointer) plint ) ;
03317 
03318    EXRETURN ;
03319 }
03320 
03321 /*-----------------------------------------------------------------------
03322   Called when the user actually selects a timeseries from the chooser.
03323   This routine just changes the original pushbutton label, and
03324   notes the index of the choice in the right place, for later retrieval.
03325 -------------------------------------------------------------------------*/
03326 
03327 void PLUG_finalize_timeseries_CB( Widget w, XtPointer fd, MCW_choose_cbs * cbs )
03328 {
03329    PLUGIN_interface * plint = (PLUGIN_interface *) fd ;
03330    PLUGIN_tsval     * av = NULL ;
03331    XmString           xstr ;
03332    int                its ;
03333 
03334 ENTRY("PLUG_finalize_timeseries_CB") ;
03335 
03336    /** find the stuff that is associated with this button **/
03337 
03338    XtVaGetValues( w , XmNuserData , &av , NULL ) ;
03339    if( plint == NULL || av == NULL || av->tsimar == NULL ) EXRETURN ;
03340    if( cbs->reason != mcwCR_timeseries ) EXRETURN ;  /* error */
03341 
03342    /** store the choice, and change the widget label **/
03343 
03344    its = cbs->ival ;
03345    if( its >= 0 && its < IMARR_COUNT(av->tsimar) ){
03346       av->tsim      = IMARR_SUBIMAGE(av->tsimar,its) ;
03347       av->ts_choice = its ;
03348 
03349       xstr = XmStringCreateLtoR( av->tsim->name , XmFONTLIST_DEFAULT_TAG ) ;
03350       XtVaSetValues( w , XmNlabelString , xstr , NULL ) ;
03351       XmStringFree( xstr ) ;
03352    }
03353 
03354    EXRETURN ;
03355 }
03356 
03357 /********************************************************************************
03358    Routine to interface to AFNI, after plugins are read in.
03359 *********************************************************************************/
03360 
03361 void AFNI_plugin_button( Three_D_View * im3d )
03362 {
03363    AFNI_plugin_array * exten = GLOBAL_library.plugins ;
03364    AFNI_plugin * plug ;
03365    int pp , ipl , nbut , npbut , kpl ;
03366    Widget rc , mbar , menu , cbut , pbut , wpar , sep ;
03367    XmString xstr ;
03368    PLUGIN_interface ** plintar ;  /* 28 Nov 2000 */
03369 
03370 ENTRY("AFNI_plugin_button") ;
03371 
03372    /*-- check inputs for legality --*/
03373 
03374    if( exten == NULL      ||
03375        ! IM3D_VALID(im3d) || im3d->type != AFNI_3DDATA_VIEW ) EXRETURN ;
03376 
03377    /*-- 23 Sep 2000: count number of buttons that will be made --*/
03378 
03379    npbut = 0 ;
03380    for( pp=0 ; pp < exten->num ; pp++ ){
03381       plug = exten->plar[pp] ;
03382       for( ipl=0 ; ipl < plug->interface_count ; ipl++ ){
03383          npbut++ ;
03384       }
03385    }
03386 
03387    /*-- make arrays to hold the plugin buttons (etc.),
03388         so that plugins can be started from layouts (in afni_splash.c) --*/
03389 
03390    im3d->vwid->nplugbut = npbut ;
03391    im3d->vwid->plugbut  = (Widget *)            malloc(sizeof(Widget)            *npbut) ;
03392    im3d->vwid->pluglab  = (char **)             malloc(sizeof(char *)            *npbut) ;
03393    im3d->vwid->plugint  = (PLUGIN_interface **) malloc(sizeof(PLUGIN_interface *)*npbut) ;
03394 
03395    /*-- create menu bar --*/
03396 
03397    wpar = im3d->vwid->dmode->mbar_rowcol ;
03398 
03399    rc =  XtVaCreateWidget(
03400            "dialog" , xmRowColumnWidgetClass , wpar ,
03401               XmNorientation , XmHORIZONTAL ,
03402               XmNpacking , XmPACK_TIGHT ,
03403               XmNtraversalOn , False ,
03404               XmNinitialResourcesPersistent , False ,
03405            NULL ) ;
03406 
03407    mbar = XmCreateMenuBar( rc , "dialog" , NULL,0 ) ;
03408    XtVaSetValues( mbar ,
03409                      XmNmarginWidth  , 0 ,
03410                      XmNmarginHeight , 0 ,
03411                      XmNspacing      , 3 ,
03412                      XmNborderWidth  , 0 ,
03413                      XmNborderColor  , 0 ,
03414                      XmNtraversalOn  , False ,
03415                      XmNbackground   , im3d->dc->ovc->pixov_brightest ,
03416                   NULL ) ;
03417    XtManageChild( mbar ) ;
03418 
03419    menu = XmCreatePulldownMenu( mbar , "menu" , NULL,0 ) ;
03420 
03421    VISIBILIZE_WHEN_MAPPED(menu) ;
03422 
03423    xstr = XmStringCreateLtoR( "Plugins" , XmFONTLIST_DEFAULT_TAG ) ;
03424    cbut = XtVaCreateManagedWidget(
03425             "dialog" , xmCascadeButtonWidgetClass , mbar ,
03426                XmNlabelString , xstr ,
03427                XmNsubMenuId , menu ,
03428                XmNmarginWidth  , 0 ,
03429                XmNmarginHeight , 0 ,
03430                XmNmarginBottom , 0 ,
03431                XmNmarginTop    , 0 ,
03432                XmNmarginRight  , 0 ,
03433                XmNmarginLeft   , 0 ,
03434                XmNtraversalOn  , False ,
03435                XmNinitialResourcesPersistent , False ,
03436             NULL ) ;
03437    XmStringFree( xstr ) ;
03438 
03439    MCW_register_help( cbut , "Pressing this drops down\n"
03440                              "the menu of the plugin\n"
03441                              "programs loaded when\n"
03442                              "AFNI started."
03443                     ) ;
03444    MCW_register_hint( cbut , "Plugins menu" ) ;
03445 
03446    /* macro to create a new menu button */
03447 
03448 #define MENU_BUT(pl)                                                      \
03449    do{                                                                    \
03450       xstr = XmStringCreateLtoR( (pl)->label , XmFONTLIST_DEFAULT_TAG ) ; \
03451       pbut = XtVaCreateManagedWidget(                                     \
03452                "dialog" , xmPushButtonWidgetClass , menu ,                \
03453                   XmNlabelString , xstr ,                                 \
03454                   XmNmarginHeight , 0 ,                                   \
03455                   XmNuserData , (XtPointer) im3d ,                        \
03456                   XmNtraversalOn , False ,                                \
03457                   XmNinitialResourcesPersistent , False ,                 \
03458                NULL ) ;                                                   \
03459       im3d->vwid->plugbut[npbut] = pbut ;            /* 23 Sep 2000 */    \
03460       im3d->vwid->plugint[npbut] = (pl) ;                                 \
03461       im3d->vwid->pluglab[npbut] = XtNewString((pl)->label) ;             \
03462       XtAddCallback( pbut , XmNactivateCallback ,                         \
03463                      PLUG_startup_plugin_CB , (XtPointer)(pl) ) ;         \
03464       XmStringFree(xstr) ;                                                \
03465       if( (pl)->hint != NULL ) MCW_register_hint( pbut , (pl)->hint ) ;   \
03466       if( (pl)->butcolor[0] != '\0' )                                     \
03467          MCW_set_widget_bg( pbut , (pl)->butcolor , 0 ) ;                 \
03468    } while(0)
03469 
03470    /*** top of menu = a label to click on that does nothing at all ***/
03471 
03472    xstr = XmStringCreateLtoR( "-- Cancel --" , XmFONTLIST_DEFAULT_TAG ) ;
03473    (void) XtVaCreateManagedWidget(
03474             "dialog" , xmLabelWidgetClass , menu ,
03475                XmNlabelString , xstr ,
03476                XmNrecomputeSize , False ,
03477                XmNinitialResourcesPersistent , False ,
03478             NULL ) ;
03479    XmStringFree(xstr) ;
03480 
03481    sep = XtVaCreateManagedWidget(
03482             "dialog" , xmSeparatorWidgetClass , menu ,
03483                XmNseparatorType , XmSINGLE_LINE ,
03484             NULL ) ;
03485 
03486    /*-- 28 Nov 2000: allow user to specify that
03487                      button should be alphabetized --*/
03488 
03489    /* make single array of all plugin interfaces */
03490 
03491    plintar = (PLUGIN_interface **) malloc(sizeof(PLUGIN_interface *)*npbut) ;
03492    for( kpl=pp=0 ; pp < exten->num ; pp++ ){
03493       plug = exten->plar[pp] ;
03494       for( ipl=0 ; ipl < plug->interface_count ; ipl++ ){
03495          plintar[kpl++] = plug->interface[ipl] ;
03496       }
03497    }
03498 
03499    /* sort this array, if desired */
03500 
03501    if( !AFNI_noenv("AFNI_PLUGINS_ALPHABETIZE") ){
03502       int qq , ss ;
03503       PLUGIN_interface * tpl ;
03504 
03505       do{                                       /* bubble sort */
03506         for( ss=qq=0 ; qq < npbut-1 ; qq++ ){
03507            if( strcasecmp(plintar[qq]->label,plintar[qq+1]->label) > 0 ){
03508              tpl           = plintar[qq+1] ;
03509              plintar[qq+1] = plintar[qq] ;
03510              plintar[qq]   = tpl ;
03511              ss++ ;
03512            }
03513         }
03514       } while( ss ) ;
03515    }
03516 
03517    /*-- prepare to make the actual buttons --*/
03518 
03519    nbut  = 2 ;  /* allow for the Cancel label and separator */
03520    npbut = 0 ;  /* actual number of buttons */
03521 
03522    /*** make buttons for each interface ***/
03523 
03524    for( kpl=pp=0 ; pp < exten->num ; pp++ ){
03525       plug = exten->plar[pp] ;
03526       for( ipl=0 ; ipl < plug->interface_count ; ipl++ ){
03527          MENU_BUT( plintar[kpl] ) ;  /* uses npbut */
03528          nbut++ ; npbut++ ; kpl++ ;
03529       }
03530    }
03531 
03532    free(plintar) ;  /* don't need no more */
03533 
03534    if( nbut > COLSIZE ){
03535       int ncol = (nbut-2)/COLSIZE + 1 ;
03536       XtDestroyWidget(sep) ;
03537       XtVaSetValues( menu ,
03538                         XmNpacking , XmPACK_COLUMN ,
03539                         XmNnumColumns , ncol ,
03540                      NULL ) ;
03541    }
03542 
03543    XtManageChild( rc ) ;
03544    EXRETURN ;
03545 }
03546 
03547 /*------------------------------------------------------------------------
03548    Routine that actually starts up a plugin when the user makes
03549    his or her choice from the menu created above.
03550 --------------------------------------------------------------------------*/
03551 
03552 void PLUG_startup_plugin_CB( Widget w , XtPointer cd , XtPointer cbd )
03553 {
03554    PLUGIN_interface * plint = (PLUGIN_interface *) cd ;
03555    XmAnyCallbackStruct * cbs = (XmAnyCallbackStruct *) cbd ;
03556    char * mesg ;
03557    Widget wpop ;
03558    Three_D_View * im3d = NULL ;
03559 
03560 ENTRY("PLUG_startup_plugin_CB") ;
03561 
03562    if( plint == NULL ) EXRETURN ;  /* error? */
03563 
03564    if( w != NULL ){
03565      XtVaGetValues( w , XmNuserData , &im3d , NULL ) ;  /* set controller from */
03566      plint->im3d = im3d ;                               /* data on menu button */
03567    } else if( cbs != NULL ){                            /* 21 Jul 2003 */
03568      plint->im3d = (Three_D_View *) cbs ;
03569      cbs = NULL ;
03570    }
03571    if( plint->im3d == NULL ) plint->im3d = AFNI_find_open_controller() ;
03572 
03573    /*-- if no interface is needed, just call it --*/
03574 
03575    if( plint->call_method == PLUGIN_CALL_IMMEDIATELY ){
03576 
03577 STATUS("calling plugin") ;
03578 
03579       MPROBE ;
03580 
03581       SHOW_AFNI_PAUSE ;
03582 #if 0
03583       mesg = plint->call_func( plint ) ;
03584 #else
03585       AFNI_CALL_VALU_1ARG( plint->call_func ,
03586                            char *,mesg , PLUGIN_interface *,plint ) ;
03587 #endif
03588       SHOW_AFNI_READY ;
03589 
03590       MPROBE ;
03591 
03592       if( mesg != NULL ){
03593          if( w != NULL ){
03594             (void) MCW_popup_message( w , mesg , MCW_USER_KILL ) ;
03595             XBell( XtDisplay(w) , 100 ) ;
03596          } else {
03597             fprintf(stderr,"\n%s\a\n",mesg) ;
03598          }
03599       }
03600       EXRETURN ;
03601    }
03602 
03603    /*-- if widgets not created yet, create them now --*/
03604 
03605    if( plint->wid == NULL )
03606       PLUG_setup_widgets( plint , GLOBAL_library.dc ) ;
03607 
03608    /*-- set labels to go on shell widget and icon;
03609         include the [] controller window index, if possible --*/
03610 
03611    { char ttl[PLUGIN_STRING_SIZE] ;
03612 
03613      sprintf(ttl , "%s%s" , AFNI_controller_label(plint->im3d) , plint->label ) ;
03614 
03615      XtVaSetValues( plint->wid->shell ,
03616                        XmNtitle     , ttl , /* top of window */
03617                        XmNiconName  , ttl , /* label on icon */
03618                     NULL ) ;
03619    }
03620 
03621    /*-- if possible, find where this popup should go --*/
03622 
03623    wpop = plint->wid->shell ;
03624 
03625    if( cbs != NULL && cbs->event != NULL
03626                    && cbs->event->type == ButtonRelease ){
03627 
03628       XButtonEvent * xev = (XButtonEvent *) cbs->event ;
03629       int xx = (int)xev->x_root , yy = (int)xev->y_root ;
03630       int ww,hh , sw,sh ;
03631 
03632 STATUS("trying to position popup") ;
03633 
03634       MCW_widget_geom( wpop , &ww,&hh , NULL,NULL ) ; /* widget width and height */
03635       sw = WidthOfScreen (XtScreen(wpop)) ;           /* screen width and height */
03636       sh = HeightOfScreen(XtScreen(wpop)) ;
03637 
03638       if( xx+ww+3 >= sw && ww <= sw ) xx = sw-ww ;    /* make sure is on screen */
03639       if( yy+hh+3 >= sh && hh <= sh ) yy = sh-hh ;
03640 
03641       XtVaSetValues( wpop , XmNx , xx , XmNy , yy , NULL ) ;
03642    }
03643 
03644    /*-- popup the widgets that control this plugin --*/
03645 
03646 STATUS("popping up interface") ;
03647 
03648    XtMapWidget( wpop ) ;
03649    RWC_visibilize_widget( wpop ) ; /* 27 Sep 2000 */
03650    PLUTO_cursorize( plint->wid->shell ) ;
03651    EXRETURN ;
03652 }
03653 
03654 /*---------------------------------------------------------------------------
03655    Routine to add a dataset to the AFNI global collection.
03656    Return value is 0 if all is OK, 1 if bad things happened.
03657    "action_flag" is the OR (|) of various possibilities:
03658       DSET_ACTION_NONE         == do nothing
03659       DSET_ACTION_MAKE_CURRENT == make this the currently viewed dataset
03660 -----------------------------------------------------------------------------*/
03661 
03662 int PLUTO_add_dset( PLUGIN_interface *plint ,
03663                     THD_3dim_dataset *dset , int action_flag )
03664 {
03665    Three_D_View *im3d ;
03666    THD_session *sess ;
03667    int iss , vv , id ;
03668    int make_current = (action_flag & DSET_ACTION_MAKE_CURRENT) ;
03669 
03670 ENTRY("PLUTO_add_dset") ;
03671 
03672    /** sanity check **/
03673 
03674    if( plint == NULL || ! ISVALID_3DIM_DATASET(dset) ) RETURN(1) ;
03675 
03676    /** find some indices **/
03677 
03678    im3d = plint->im3d ;
03679    iss  = IM3D_VALID(im3d) ? im3d->vinfo->sess_num : 0 ;
03680    sess = GLOBAL_library.sslist->ssar[iss] ;
03681    vv   = dset->view_type ;
03682 
03683    /** add the dataset to the session **/
03684 
03685    id = sess->num_dsset ;
03686    if( id >= THD_MAX_SESSION_SIZE ){
03687      fprintf(stderr,"*** Overflow session dataset limit ***\n") ;
03688      RETURN(1) ;
03689    }
03690    sess->dsset[id][vv] = dset ;
03691    sess->num_dsset ++ ;
03692 
03693    /** make sure the dataset is properly fit into the situation **/
03694 
03695    POPDOWN_strlist_chooser ;  /* added dataset --> old choosers are invalid */
03696 
03697    THD_load_statistics( dset ) ;
03698    THD_write_3dim_dataset( NULL,NULL , dset , True ) ;
03699 
03700    if( dset->anat_parent == NULL )                          /* if() added 14 Dec 1999 */
03701      AFNI_force_adoption( sess , GLOBAL_argopt.warp_4D ) ;
03702 
03703    AFNI_make_descendants( GLOBAL_library.sslist ) ;
03704 
03705    /** if desired, jump to this puppy in the viewer **/
03706 
03707    if( make_current && IM3D_VALID(im3d) ){
03708      if( ISANAT(dset) )
03709        im3d->vinfo->anat_num = sess->num_dsset - 1 ;
03710      else
03711        im3d->vinfo->func_num = sess->num_dsset - 1 ;
03712 
03713      AFNI_initialize_view( im3d->anat_now , im3d ) ;
03714    }
03715 
03716    THD_force_malloc_type( dset->dblk , DATABLOCK_MEM_ANY ) ;
03717    RETURN(0) ;
03718 }
03719 
03720 /*---------------------------------------------------------------------
03721    Routine to make a copy of a dataset, with data attached.
03722    [Moved into edt_fullcopy.c -- RWCox, 07 Oct 1998]
03723 -----------------------------------------------------------------------*/
03724 
03725 THD_3dim_dataset * PLUTO_copy_dset( THD_3dim_dataset * dset , char * new_prefix )
03726 {
03727    THD_3dim_dataset * new_dset ;
03728    int ival , ityp , nbytes , nvals ;
03729    void * new_brick , * old_brick ;
03730 
03731 ENTRY("PLUTO_copy_dset") ;
03732 
03733    new_dset = EDIT_full_copy( dset , new_prefix ) ;
03734    RETURN(new_dset) ;
03735 }
03736 
03737 /*----------------------------------------------------------------------
03738    Routine to force AFNI to redisplay controllers that are attached
03739    to a given dataset.  (Feb 1998)
03740 ------------------------------------------------------------------------*/
03741 
03742 void PLUTO_dset_redisplay( THD_3dim_dataset *dset )
03743 {
03744    PLUTO_dset_redisplay_mode( dset , REDISPLAY_OPTIONAL ) ;
03745 }
03746 
03747 /*---- 23 Oct 1998: superseded above routine with this one; RWCox -----*/
03748 
03749 void PLUTO_dset_redisplay_mode( THD_3dim_dataset *dset , int mode )
03750 {
03751    Three_D_View * im3d ;
03752    int ii , amode , fmode ;
03753 
03754 ENTRY("PLUTO_dset_redisplay_mode") ;
03755 
03756    if( mode == REDISPLAY_OPTIONAL ){
03757       amode = REDISPLAY_ALL ;
03758       fmode = REDISPLAY_OVERLAY ;
03759    } else {
03760       amode = fmode = mode ;
03761    }
03762 
03763    for( ii=0 ; ii < MAX_CONTROLLERS ; ii++ ){
03764       im3d = GLOBAL_library.controllers[ii] ;
03765       if( ! IM3D_OPEN(im3d) ) continue ;
03766 
03767       if( ! ISVALID_DSET(dset) ){
03768          im3d->anat_voxwarp->type = ILLEGAL_TYPE ;
03769          im3d->fim_voxwarp->type  = ILLEGAL_TYPE ;
03770          AFNI_reset_func_range( im3d ) ;
03771          AFNI_set_viewpoint( im3d , -1,-1,-1 , REDISPLAY_ALL ) ;
03772       } else if( im3d->anat_now == dset ){
03773          im3d->anat_voxwarp->type = ILLEGAL_TYPE ;
03774          AFNI_reset_func_range( im3d ) ;
03775          AFNI_imseq_clearstat( im3d ) ;
03776          AFNI_set_viewpoint( im3d , -1,-1,-1 , amode ) ;
03777       } else if( im3d->fim_now == dset ){
03778          im3d->fim_voxwarp->type = ILLEGAL_TYPE ;
03779          AFNI_reset_func_range( im3d ) ;
03780          AFNI_imseq_clearstat( im3d ) ;
03781          AFNI_redisplay_func( im3d ) ;
03782       }
03783    }
03784    EXRETURN ;
03785 }
03786 
03787 /*----------------------------------------------------------------------
03788    Routine to inform AFNI that some dataset names are now different,
03789    so stuff should be done about it.
03790 ------------------------------------------------------------------------*/
03791 
03792 void PLUTO_fixup_names(void)
03793 {
03794    Three_D_View * im3d ;
03795    int ii ;
03796 
03797 ENTRY("PLUTO_fixup_names") ;
03798 
03799    POPDOWN_strlist_chooser ;  /* get rid of any dataset chooser that is open */
03800 
03801    for( ii=0 ; ii < MAX_CONTROLLERS ; ii++ ){
03802       im3d = GLOBAL_library.controllers[ii] ;
03803       if( IM3D_OPEN(im3d) )
03804          AFNI_set_window_titles( im3d ) ;
03805    }
03806    EXRETURN ;
03807 }
03808 
03809 /*-----------------------------------------------------------------------
03810    Let the user popup a message
03811 -------------------------------------------------------------------------*/
03812 
03813 void PLUTO_popup_worker( PLUGIN_interface * plint , char * mesg , int flag )
03814 {
03815    Widget w = NULL ;
03816    Three_D_View * im3d ;
03817    int ii ;
03818 
03819 ENTRY("PLUTO_popup_worker") ;
03820 
03821    if( mesg == NULL || strlen(mesg) == 0 ) EXRETURN ;
03822 
03823    /* find a widget to popup next to */
03824 
03825    if( plint->wid != NULL && plint->wid->label != NULL ){
03826       w = plint->wid->label ;
03827    } else {
03828       im3d = plint->im3d ;
03829       if( !IM3D_OPEN(im3d) ) im3d = AFNI_find_open_controller() ;
03830       w = im3d->vwid->top_shell ;
03831    }
03832 
03833    if( w != NULL ){
03834       if( flag >= 0 )
03835          (void) MCW_popup_message( w , mesg , flag ) ;
03836       else
03837          (void) new_MCW_textwin( w , mesg , TEXT_READONLY ) ;
03838    } else {
03839       fprintf(stderr,"\n%s\a\n",mesg) ;
03840    }
03841 
03842    EXRETURN ;
03843 }
03844 
03845 /*------------------------------------------------------------------*/
03846 
03847 void PLUTO_beep(void)
03848 {
03849    XBell( GLOBAL_library.dc->display , 100 ) ;
03850    return ;
03851 }
03852 
03853 /*------------------------------------------------------------------*/
03854 
03855 #include <ctype.h>
03856 
03857 static int PLUTO_strncmp( char * aa , char * bb , int nn ) /* 09 Oct 2000 */
03858 {
03859    int ii ;
03860 
03861    if( aa == bb )                 return 0 ;  /* special cases */
03862    if( aa == NULL || bb == NULL ) return 1 ;
03863 
03864    for( ii=0 ; ii < nn ; ii++,aa++,bb++ ){
03865       if( *aa == '\0'  && *bb == '\0' )  return 0 ; /* got to end all same! */
03866       if( *aa == '\0'  || *bb == '\0' )  return 1 ; /* premature end of one */
03867       if( isspace(*aa) || isspace(*bb) ) continue ; /* don't compare blanks */
03868       if( toupper(*aa) != toupper(*bb) ) return 1 ; /* case insensitive     */
03869    }
03870 
03871    return 0 ;                                       /* finished max # chars */
03872 }
03873 
03874 /*------------------------------------------------------------------*/
03875 
03876 int PLUTO_string_index( char * target , int num , char * source[] )
03877 {
03878    int ii ;
03879 
03880    if( num <= 0 || source == NULL || target == NULL ) return -1 ;
03881 
03882    for( ii=0 ; ii < num ; ii++ )
03883       if( PLUTO_strncmp(target,source[ii],PLUGIN_STRING_SIZE) == 0 ) return ii ;
03884 
03885    return -1 ;
03886 }
03887 
03888 /*-----------------------------------------------------------------------
03889   Function to let an IMMEDIATE mode plugin let AFNI know where its
03890   toplevel shell is -- 22 Sep 2000 -- RWCox.
03891 -------------------------------------------------------------------------*/
03892 
03893 void PLUTO_set_topshell( PLUGIN_interface * plint , Widget ts )
03894 {
03895 ENTRY("PLUTO_set_topshell") ;
03896 
03897    if( plint == NULL                                ||
03898        plint->wid != NULL                           ||
03899        ts == (Widget) 0                             ||
03900        plint->call_method != PLUGIN_CALL_IMMEDIATELY  ) EXRETURN ;
03901 
03902    plint->wid        = myXtNew(PLUGIN_widgets) ;
03903    plint->wid->shell = ts ;
03904    plint->wid->meter = NULL ;
03905    EXRETURN ;
03906 }
03907 
03908 /*-----------------------------------------------------------------------
03909   Routines to put a progress meter on the top of the interface shell
03910 -------------------------------------------------------------------------*/
03911 
03912 void PLUTO_popup_meter( PLUGIN_interface * plint )
03913 {
03914 ENTRY("PLUTO_popup_meter") ;
03915 
03916    if( plint == NULL             || plint->wid == NULL       ||
03917        plint->wid->shell == NULL || plint->wid->meter != NULL  ) EXRETURN ;
03918 
03919    plint->wid->meter = MCW_popup_meter( plint->wid->shell , METER_TOP_WIDE ) ;
03920    EXRETURN ;
03921 }
03922 
03923 void PLUTO_popdown_meter( PLUGIN_interface * plint )
03924 {
03925 ENTRY("PLUTO_popdown_meter") ;
03926 
03927    if( plint == NULL             || plint->wid == NULL       ||
03928        plint->wid->shell == NULL || plint->wid->meter == NULL  ) EXRETURN ;
03929 
03930    MCW_popdown_meter( plint->wid->meter ) ;
03931    plint->wid->meter = NULL ;
03932    EXRETURN ;
03933 }
03934 
03935 void PLUTO_set_meter( PLUGIN_interface * plint , int percent )
03936 {
03937 ENTRY("PLUTO_set_meter") ;
03938 
03939    if( plint == NULL             || plint->wid == NULL       ||
03940        plint->wid->shell == NULL || plint->wid->meter == NULL  ) EXRETURN ;
03941 
03942    MCW_set_meter( plint->wid->meter , percent ) ;
03943    EXRETURN ;
03944 }
03945 
03946 /*-----------------------------------------------------------------------
03947    Routine to popup an image.
03948    Inputs:
03949      handle = (a) value returned from previous call to this routine
03950               (b) or NULL to start a new image display window
03951      im     = pointer to MRI_IMAGE structure
03952               (a) NULL to popdown the image display window
03953               (b) non-NULL to display this image in the window
03954 
03955    Output is a "handle" that can be used to control the next usage
03956    of this routine (whether to send an image to a new window or
03957    replace it in an old one).
03958 -------------------------------------------------------------------------*/
03959 
03960 void * PLUTO_popup_image( void * handle , MRI_IMAGE * im )
03961 {
03962    PLUGIN_impopper * imp = (PLUGIN_impopper *) handle ;
03963 
03964 ENTRY("PLUTO_popup_image") ;
03965 
03966    /*-- input image is NULL ==> popdown, if applicable --*/
03967 
03968    if( im == NULL ){
03969       if( imp != NULL )
03970          drive_MCW_imseq( imp->seq , isqDR_destroy , NULL ) ;
03971 
03972       RETURN((void *) imp) ;
03973    }
03974 
03975    /*-- input = no popper handle ==> create one --*/
03976 
03977    if( imp == NULL ){
03978       imp      = myXtNew(PLUGIN_impopper) ;
03979       imp->seq = NULL ; imp->im  = NULL ;
03980    }
03981 
03982    /*-- input = non-null image ==> replace image --*/
03983 
03984    mri_free( imp->im ) ;      /* toss old copy */
03985    imp->im = mri_copy( im ) ; /* make new copy */
03986 
03987    /*-- input = inactive popper handle ==> activate it --*/
03988 
03989    if( imp->seq == NULL ){
03990       imp->seq = open_MCW_imseq( GLOBAL_library.dc ,
03991                                  PLUGIN_imseq_getim , (XtPointer) imp ) ;
03992 
03993       drive_MCW_imseq( imp->seq , isqDR_realize, NULL ) ;
03994       drive_MCW_imseq( imp->seq , isqDR_onoffwid , (XtPointer) isqDR_offwid ) ;
03995 
03996       drive_MCW_imseq( imp->seq , isqDR_opacitybut , (XtPointer) 0 ) ; /* 07 Mar 2001 */
03997       drive_MCW_imseq( imp->seq , isqDR_zoombut    , (XtPointer) 0 ) ; /* 12 Mar 2002 */
03998       drive_MCW_imseq( imp->seq , isqDR_penbbox    , (XtPointer) 0 ) ; /* 18 Jul 2003 */
03999    }
04000 
04001    /*-- display image at last --*/
04002 
04003    if( im->name != NULL && strlen(im->name) > 0 )
04004       drive_MCW_imseq( imp->seq , isqDR_title, im->name ) ;
04005 
04006    drive_MCW_imseq( imp->seq , isqDR_clearstat , NULL ) ;
04007    drive_MCW_imseq( imp->seq , isqDR_reimage , (XtPointer) 0 ) ;
04008 
04009    RETURN((void *) imp) ;
04010 }
04011 
04012 /*------------------------------------------------------------------
04013    Routine to provide data to the imseq for PLUGIN_popup_image.
04014    Just returns the control information, or the given image.
04015 --------------------------------------------------------------------*/
04016 
04017 XtPointer PLUGIN_imseq_getim( int n , int type , XtPointer handle )
04018 {
04019    PLUGIN_impopper * imp = (PLUGIN_impopper *) handle ;
04020 
04021 ENTRY("PLUGIN_imseq_getim") ;
04022 
04023    if( imp == NULL ) RETURN(NULL) ;
04024 
04025    /*--- control info ---*/
04026 
04027    if( type == isqCR_getstatus ){
04028       MCW_imseq_status * stat = myXtNew( MCW_imseq_status ) ;
04029       stat->num_total  = 1 ;
04030       stat->num_series = 1 ;
04031       stat->send_CB    = PLUGIN_seq_send_CB ;
04032       stat->parent     = (XtPointer) imp  ;
04033       stat->aux        = NULL ;
04034 
04035       stat->transforms0D = & (GLOBAL_library.registered_0D) ;
04036       stat->transforms2D = & (GLOBAL_library.registered_2D) ;
04037       stat->slice_proj   = NULL ;
04038 
04039       RETURN((XtPointer) stat) ;
04040    }
04041 
04042    /*--- no overlay ---*/
04043 
04044    if( type == isqCR_getoverlay ) RETURN(NULL) ;
04045 
04046    /*--- return a copy of the image
04047          (since the imseq will delete it when it is done) ---*/
04048 
04049    if( type == isqCR_getimage || type == isqCR_getqimage ){
04050       MRI_IMAGE * im = NULL ;
04051       if( imp->im != NULL ) im = mri_copy( imp->im ) ;
04052       RETURN((XtPointer) im) ;
04053    }
04054 
04055    RETURN(NULL) ;  /* should not occur, but who knows? */
04056 }
04057 
04058 /*---------------------------------------------------------------------------
04059    Routine called when the imseq wants to send a message.
04060    In this case, all we need to handle is the destroy message,
04061    so that we can free some memory.
04062 -----------------------------------------------------------------------------*/
04063 
04064 void PLUGIN_seq_send_CB( MCW_imseq * seq , XtPointer handle , ISQ_cbs * cbs )
04065 {
04066    PLUGIN_impopper * imp = (PLUGIN_impopper *) handle ;
04067 
04068 ENTRY("PLUGIN_seq_send_CB") ;
04069 
04070    if( imp == NULL ) EXRETURN ;
04071 
04072    switch( cbs->reason ){
04073 
04074       case isqCR_destroy:{
04075          XtFree((char*)imp->seq->status) ;
04076          XtFree((char*)imp->seq)         ; imp->seq = NULL ;
04077          mri_free( imp->im )             ; imp->im  = NULL ;
04078       }
04079       break ;
04080 
04081 #ifndef NO_FRIVOLITIES
04082       case isqCR_buttonpress:{
04083          XButtonEvent *xev = (XButtonEvent *) cbs->event ;
04084 #define NBIRN 10
04085          static int nold=0 ;
04086          static char * birn[NBIRN] = { " \n** Don't DO That! **\n "                        ,
04087                                        " \n** Stop it, Rasmus! **\n "                      ,
04088                                        " \n** Do NOT read this message! **\n "             ,
04089                                        " \n** Having fun yet? **\n "                       ,
04090                                        " \n** What do you want NOW? **\n "                 ,
04091                                        " \n** Too much time on your hands? **\n "          ,
04092                                        " \n** Why are you bothering me? **\n "             ,
04093                                        " \n** Danger! Danger, Will Robinson! **\n "        ,
04094                                        " \n** WARNING: Planetary meltdown imminent! **\n " ,
04095 
04096                                  " \n"
04097                                  " God of our fathers, known of old,\n"
04098                                  " Lord of our far-flung battle-line,\n"
04099                                  " Beneath whose awful hand we hold\n"
04100                                  " Dominion over palm and pine -\n"
04101                                  " Lord God of Hosts, be with us yet,\n"
04102                                  " Lest we forget - lest we forget!\n"
04103                                  " \n"
04104                                  " The tumult and the shouting dies;\n"
04105                                  " The captains and the kings depart:\n"
04106                                  " Still stands Thine ancient sacrifice,\n"
04107                                  " An humble and a contrite heart.\n"
04108                                  " Lord God of Hosts, be with us yet,\n"
04109                                  " Lest we forget - lest we forget!\n"
04110                                  " \n"
04111                                  " Far-called, our navies melt away;\n"
04112                                  " On dune and headland sinks the fire:\n"
04113                                  " Lo, all our pomp of yesterday\n"
04114                                  " Is one with Nineveh and Tyre!\n"
04115                                  " Judge of the Nations, spare us yet.\n"
04116                                  " Lest we forget - lest we forget!\n"
04117                                  " \n"
04118                                  " If, drunk with sight of power, we loose\n"
04119                                  " Wild tongues that have not Thee in awe,\n"
04120                                  " Such boastings as the Gentiles use,\n"
04121                                  " Or lesser breeds without the Law -\n"
04122                                  " Lord God of Hosts, be with us yet,\n"
04123                                  " Lest we forget - lest we forget!\n"
04124                                  " \n"
04125                                  " For heathen heart that puts her trust\n"
04126                                  " In reeking tube and iron shard,\n"
04127                                  " All valiant dust that builds on dust,\n"
04128                                  " And, guarding, calls not Thee to guard,\n"
04129                                  " For frantic boast and foolish word -\n"
04130                                  " The Mercy on Thy People, Lord!\n"
04131                                } ;
04132 
04133 #define NKLING 5
04134          static int nkl=0 ;
04135          static char *kling[NKLING] = {
04136                                  " \n What is this talk of 'release'?\n"
04137                                  " Klingons do not make software 'releases'.\n"
04138                                  " Our software 'escapes', leaving a bloody trail of\n"
04139                                  " designers and 'Quality Assurance' people in its wake.\n"        ,
04140 
04141                                  " \n Debugging? Klingons do not debug.\n"
04142                                  " Our software does not coddle the weak.\n"                       ,
04143 
04144                                  " \n Klingon software does NOT have BUGS.\n"
04145                                  " It has FEATURES, and those features are too\n"
04146                                  " sophisticated for a Romulan pig like you to understand.\n"      ,
04147 
04148                                  " \n Our users will know fear and cower before our software!\n"
04149                                  " Ship it! Ship it and let them flee like the dogs they are!\n"  ,
04150 
04151                                  " \n You question the worthiness of my code?\n"
04152                                  " I should kill you where you stand!\n"
04153                                } ;
04154 
04155          if( xev == NULL || xev->button == Button1 ){
04156            if( !NO_frivolities && nold < NBIRN ){
04157              if( strstr(birn[nold],"Rasmus") != NULL )
04158                AFNI_speak("Stop it, Rasmus", 0 ) ;
04159              MCW_popup_message( seq->wimage , birn[nold++] , MCW_USER_KILL ) ;
04160            } else {
04161              PLUTO_beep() ;
04162              if( nold == NBIRN ){ AFNI_speak("Stop it",0); nold++; }
04163            }
04164          } else if( xev->button == Button3 ){
04165            if( !NO_frivolities && nkl < NKLING ){
04166              MCW_popup_message( seq->wimage , kling[nkl++] , MCW_USER_KILL ) ;
04167            } else {
04168              PLUTO_beep() ;
04169              if( nkl == NKLING ){ AFNI_speak("Deesist at once",0); nkl++; }
04170            }
04171          }
04172       }
04173       break ;
04174 
04175       /*--------------------------------------*/
04176 
04177       case isqCR_keypress:{    /* 12 Sep 2002 */
04178         static char *nash[] = {
04179                    " \n"
04180                    "The ant has made himself illustrious\n"
04181                    "Through constant industry industrious.\n"
04182                    "So what?\n"
04183                    "Would you be calm and placid\n"
04184                    "If you were full of formic acid?\n"
04185                 ,
04186                    " \n"
04187                    "Celery, raw\n"
04188                    "Develops the jaw,\n"
04189                    "But celery, stewed,\n"
04190                    "Is more quietly chewed.\n"
04191                 ,
04192                    " \n"
04193                    "I objurgate the centipede,\n"
04194                    "A bug we do not really need.\n"
04195                    "At sleepy-time he beats a path\n"
04196                    "Straight to the bedroom or the bath.\n"
04197                    "You always wallop where he's not,\n"
04198                    "Or, if he is, he makes a spot. \n"
04199                 ,
04200                    " \n"
04201                    "The cow is of the bovine ilk;\n"
04202                    "One end is moo, the other, milk.\n"
04203                 ,
04204                    " \n"
04205                    "This is my dream,\n"
04206                    "It is my own dream,\n"
04207                    "I dreamt it.\n"
04208                    "I dreamt that my hair was kempt.\n"
04209                    "Then I dreamt that my true love unkempt it.\n"
04210                 ,
04211                    " \n"
04212                    "I find it very difficult to enthuse\n"
04213                    "Over the current news.\n"
04214                    "Just when you think that at least the outlook\n"
04215                    "   is so black that it can grow no blacker, it worsens,\n"
04216                    "And that is why I do not like the news, because there\n"
04217                    "   has never been an era when so many things were going\n"
04218                    "   so right for so many of the wrong persons. \n"
04219                 ,
04220                    " \n"
04221                    "I test my bath before I sit,\n"
04222                    "And I'm always moved to wonderment\n"
04223                    "That what chills the finger not a bit\n"
04224                    "Is so frigid upon the fundament.\n"
04225                 ,
04226                    " \n"
04227                    "The turtle lives 'twixt plated decks\n"
04228                    "Which practically conceal its sex.\n"
04229                    "I think it clever of the turtle\n"
04230                    "In such a fix to be so fertile.\n"
04231                 ,
04232                    " \n"
04233                    "Candy\n"
04234                    "Is Dandy\n"
04235                    "But liquor\n"
04236                    "Is quicker.\n"
04237                 ,
04238                    " \n"
04239                    "I've never seen an abominable snowman,\n"
04240                    "I'm hoping not to see one,\n"
04241                    "I'm also hoping, if I do,\n"
04242                    "That it will be a wee one. \n"
04243                 ,
04244                    " \n"
04245                    "Children aren't happy without\n"
04246                    "something to ignore, and that's\n"
04247                    "what parents were created for. \n"
04248                 ,
04249                    " \n"
04250                    "Middle age is when you've met so\n"
04251                    "many people that every new person\n"
04252                    "you meet reminds you of someone else.\n"
04253                 } ;
04254 #define NUM_NASH (sizeof(nash)/sizeof(char *)) ;
04255 
04256         static int iold=-1 ; int ii ;
04257         do{ ii=lrand48()%NUM_NASH; } while( ii==iold ) ; iold = ii ;
04258         MCW_popup_message( seq->wimage , nash[ii] , MCW_USER_KILL ) ;
04259       }
04260       break ;
04261 #endif  /* NO_FRIVOLITIES */
04262 
04263    }
04264    EXRETURN ;
04265 }
04266 
04267 /*-----------------------------------------------------------------------
04268    28 April 2000: Open an image sequence display window.
04269    The input image(s) are copied, so they can be destroyed after
04270    these calls.
04271       PLUTO_imseq_popim(im,kfunc,kdata)
04272          starts the image window off with a single image;
04273          return value is a "handle" that is used in other calls;
04274          if kfunc is not NULL, it is a function that will be called
04275          with argument kdata when the imseq window is closed
04276          (e.g., this can be used to set the saved handle to NULL)
04277       PLUTO_imseq_popup(imar,kfunc,kdata)
04278          starts the window off with an array of images
04279       PLUTO_imseq_retitle(handle,string)
04280          changes the window manager title
04281       PLUTO_imseq_rekill(handle,kfunc,kdata)
04282          changes the kill function/data to kfunc/kdata;
04283       PLUTO_imseq_addto(handle,im)
04284          adds the single image "im" to the display
04285       PLUTO_imseq_setim(handle,n)
04286          sets the image index to 'n'
04287       PLUTO_imseq_destroy(handle)
04288          pops down the image viewer;
04289          destroys the internal copies of the images;
04290          calls kfunc(kdata) if kfunc is not NULL
04291          (so do PLUTO_imseq_rekill(handle,NULL,NULL); before
04292                 PLUTO_imseq_destroy(handle);
04293           if you don't want the kfunc to be called)
04294 -------------------------------------------------------------------------*/
04295 
04296 void * PLUTO_imseq_popim( MRI_IMAGE * im, generic_func * kfunc, void * kdata )
04297 {
04298    MRI_IMARR * imar ;
04299    void * handle ;
04300 
04301    if( im == NULL ) return NULL ;
04302    INIT_IMARR(imar) ;
04303    ADDTO_IMARR(imar,im) ;
04304    handle = PLUTO_imseq_popup( imar,kfunc,kdata ) ;
04305    FREE_IMARR(imar) ;  /* not DESTROY_IMARR: we don't 'own' im */
04306    return handle ;
04307 }
04308 
04309 void * PLUTO_imseq_popup( MRI_IMARR * imar, generic_func * kfunc, void * kdata )
04310 {
04311    int ntot , ii ;
04312    MRI_IMAGE * im , * cim ;
04313    PLUGIN_imseq * psq ;
04314 
04315    if( imar == NULL || IMARR_COUNT(imar) == 0 ) return NULL ;
04316 
04317    ntot = IMARR_COUNT(imar) ;
04318 
04319    psq = (PLUGIN_imseq *) calloc(1,sizeof(PLUGIN_imseq)) ;
04320    if( psq == NULL ) return NULL ;
04321 
04322    INIT_IMARR(psq->imar) ;
04323    psq->kill_func = kfunc ;
04324    psq->kill_data = kdata ;
04325    psq->rgb_count = 0 ;
04326 
04327    for( ii=0 ; ii < ntot ; ii++ ){
04328       im = IMARR_SUBIMAGE(imar,ii) ;
04329       if( im != NULL ){
04330          cim = mri_copy( im ) ;
04331          ADDTO_IMARR(psq->imar,cim) ;
04332          if( cim->kind == MRI_rgb ) psq->rgb_count++ ;
04333       }
04334    }
04335    ntot = IMARR_COUNT(psq->imar) ;
04336    if( ntot == 0 ){
04337       DESTROY_IMARR(psq->imar) ; free(psq) ; return NULL ;
04338    }
04339 
04340    psq->seq = open_MCW_imseq( GLOBAL_library.dc , PLUTO_imseq_getim , psq ) ;
04341 
04342    drive_MCW_imseq( psq->seq , isqDR_clearstat , NULL ) ;
04343 
04344    { ISQ_options opt ;       /* change some options from the defaults */
04345 
04346      ISQ_DEFAULT_OPT(opt) ;
04347      opt.save_one = False ;  /* change to Save:bkg */
04348      opt.save_pnm = False ;
04349      drive_MCW_imseq( psq->seq , isqDR_options      , (XtPointer) &opt ) ;
04350      drive_MCW_imseq( psq->seq , isqDR_periodicmont , (XtPointer) 0    ) ;
04351    }
04352 
04353    /* make it popup */
04354 
04355    drive_MCW_imseq( psq->seq , isqDR_realize, NULL ) ;
04356    drive_MCW_imseq( psq->seq , isqDR_title, "Images" ) ;
04357 
04358    if( ntot == 1 )
04359       drive_MCW_imseq( psq->seq , isqDR_onoffwid , (XtPointer) isqDR_offwid ) ;
04360    else {
04361       drive_MCW_imseq( psq->seq , isqDR_onoffwid , (XtPointer) isqDR_onwid ) ;
04362       drive_MCW_imseq( psq->seq , isqDR_opacitybut , (XtPointer) 0 ) ; /* 07 Mar 2001 */
04363       drive_MCW_imseq( psq->seq , isqDR_zoombut    , (XtPointer) 0 ) ; /* 12 Mar 2002 */
04364       drive_MCW_imseq( psq->seq , isqDR_penbbox    , (XtPointer) 0 ) ; /* 18 Jul 2003 */
04365    }
04366 
04367    return (void *) psq ;
04368 }
04369 
04370 /*-----------------------------------------------------------------------*/
04371 
04372 void PLUTO_imseq_retitle( void * handle , char * title )
04373 {
04374    PLUGIN_imseq * psq = (PLUGIN_imseq *) handle ;
04375 
04376    if( psq == NULL || psq->seq == NULL || title == NULL ) return ;
04377    drive_MCW_imseq( psq->seq , isqDR_title, title ) ;
04378    return ;
04379 }
04380 
04381 /*-----------------------------------------------------------------------*/
04382 
04383 void PLUTO_imseq_rekill( void * handle, generic_func * kfunc, void * kdata )
04384 {
04385    PLUGIN_imseq * psq = (PLUGIN_imseq *) handle ;
04386 
04387    if( psq == NULL ) return ;
04388    psq->kill_func = kfunc ;
04389    psq->kill_data = kdata ;
04390    return ;
04391 }
04392 
04393 /*-----------------------------------------------------------------------*/
04394 
04395 void PLUTO_imseq_addto( void * handle , MRI_IMAGE * im )
04396 {
04397    PLUGIN_imseq * psq = (PLUGIN_imseq *) handle ;
04398    int ntot , ii ;
04399    MRI_IMAGE * cim ;
04400 
04401    if( psq == NULL || psq->seq == NULL || im == NULL ) return ;
04402 
04403    ntot = IMARR_COUNT(psq->imar) ;
04404    cim  = mri_copy(im) ;
04405    if( cim->kind == MRI_rgb ) psq->rgb_count++ ;
04406    ADDTO_IMARR(psq->imar,cim) ;
04407 
04408    drive_MCW_imseq( psq->seq , isqDR_newseq , psq ) ;
04409 
04410    if( ntot == 1 )
04411       drive_MCW_imseq( psq->seq , isqDR_onoffwid , (XtPointer) isqDR_offwid ) ;
04412    else {
04413       drive_MCW_imseq( psq->seq , isqDR_onoffwid , (XtPointer) isqDR_onwid ) ;
04414       drive_MCW_imseq( psq->seq , isqDR_opacitybut , (XtPointer) 0 ) ; /* 07 Mar 2001 */
04415       drive_MCW_imseq( psq->seq , isqDR_zoombut    , (XtPointer) 0 ) ; /* 12 Mar 2002 */
04416    }
04417 
04418    drive_MCW_imseq( psq->seq , isqDR_reimage , (XtPointer)(ntot) ) ;
04419 
04420    return ;
04421 }
04422 
04423 /*-----------------------------------------------------------------------*/
04424 
04425 void PLUTO_imseq_setim( void *handle , int n )    /* 17 Dec 2004 */
04426 {
04427    PLUGIN_imseq *psq = (PLUGIN_imseq *)handle ;
04428 
04429    if( psq == NULL || psq->seq == NULL ||
04430        n   <  0    || n        >= IMARR_COUNT(psq->imar) ) return ;
04431 
04432    drive_MCW_imseq( psq->seq , isqDR_reimage , (XtPointer)(n) ) ;
04433    return ;
04434 }
04435 
04436 /*-----------------------------------------------------------------------*/
04437 
04438 void PLUTO_imseq_destroy( void * handle )
04439 {
04440    PLUGIN_imseq * psq = (PLUGIN_imseq *) handle ;
04441 
04442    if( psq == NULL ) return ;
04443    drive_MCW_imseq( psq->seq , isqDR_destroy , NULL ) ;
04444    return ;
04445 }
04446 
04447 /*------------------------------------------------------------------
04448    Routine to provide data to the imseq.
04449    Just returns the control information, or the selected image.
04450 --------------------------------------------------------------------*/
04451 
04452 XtPointer PLUTO_imseq_getim( int n , int type , XtPointer handle )
04453 {
04454    PLUGIN_imseq * psq = (PLUGIN_imseq *) handle ;
04455 
04456    int ntot = 0 ;
04457 
04458    if( psq->imar != NULL ) ntot = IMARR_COUNT(psq->imar) ;
04459    if( ntot < 1 ) ntot = 1 ;
04460 
04461    /*--- send control info ---*/
04462 
04463    if( type == isqCR_getstatus ){
04464       MCW_imseq_status * stat = myXtNew( MCW_imseq_status ) ;  /* will be free-d */
04465                                                                /* when imseq is */
04466                                                                /* destroyed    */
04467       stat->num_total  = ntot ;
04468       stat->num_series = ntot ;
04469       stat->send_CB    = PLUTO_imseq_send_CB ;
04470       stat->parent     = NULL ;
04471       stat->aux        = NULL ;
04472 
04473       stat->transforms0D = &(GLOBAL_library.registered_0D) ;
04474       stat->transforms2D = &(GLOBAL_library.registered_2D) ;
04475       stat->slice_proj   = NULL ;
04476 
04477       return (XtPointer) stat ;
04478    }
04479 
04480    /*--- no overlay, never ---*/
04481 
04482    if( type == isqCR_getoverlay ) return NULL ;
04483 
04484    /*--- return a copy of an image
04485          (since the imseq will delete it when it is done) ---*/
04486 
04487    if( type == isqCR_getimage || type == isqCR_getqimage ){
04488       MRI_IMAGE * im = NULL , * rim ;
04489 
04490       if( psq->imar != NULL ){
04491          if( n < 0 ) n = 0 ; else if( n >= ntot ) n = ntot-1 ;
04492          rim = IMARR_SUBIMAGE(psq->imar,n) ;
04493          if( psq->rgb_count > 0 )
04494             im = mri_to_rgb( rim ) ;
04495          else
04496             im = mri_copy( rim ) ;
04497       }
04498       return (XtPointer) im ;
04499    }
04500 
04501    return NULL ; /* should not occur, but who knows? */
04502 }
04503 
04504 /*---------------------------------------------------------------------------
04505    Routine called when the imseq wants to send a message.
04506    In this case, all we need to handle is the destroy message,
04507    so that we can free some memory.
04508 -----------------------------------------------------------------------------*/
04509 
04510 void PLUTO_imseq_send_CB( MCW_imseq * seq , XtPointer handle , ISQ_cbs * cbs )
04511 {
04512    PLUGIN_imseq * psq = (PLUGIN_imseq *) handle ;
04513 
04514    switch( cbs->reason ){
04515       case isqCR_destroy:{
04516          myXtFree(psq->seq) ;
04517          DESTROY_IMARR( psq->imar ) ;
04518 
04519          if( psq->kill_func != NULL )
04520 #if 0
04521             psq->kill_func( psq->kill_data ) ;
04522 #else
04523             AFNI_CALL_VOID_1ARG( psq->kill_func , void *,psq->kill_data ) ;
04524 #endif
04525 
04526          free(psq) ;
04527       }
04528       break ;
04529    }
04530    return ;
04531 }
04532 
04533 /*-------------------------------------------------------------------------*/
04534 
04535 /*-- 13 Dec 1997: moved guts into thd_make*.c --*/
04536 
04537 THD_3dim_dataset * PLUTO_4D_to_typed_fim( THD_3dim_dataset * old_dset ,
04538                                           char * new_prefix , int new_datum ,
04539                                           int ignore , int detrend ,
04540                                           generic_func * user_func ,
04541                                           void * user_data )
04542 {
04543    THD_3dim_dataset * new_dset ;  /* output dataset */
04544 
04545 ENTRY("PLUTO_4D_to_typed_fim") ;
04546 
04547    if( ! PLUTO_prefix_ok(new_prefix) ) RETURN(NULL) ;
04548 
04549    new_dset = MAKER_4D_to_typed_fim( old_dset , new_prefix , new_datum ,
04550                                      ignore , detrend , user_func , user_data ) ;
04551 
04552    RETURN(new_dset) ;
04553 }
04554 
04555 /*-------------------------------------------------------------------------*/
04556 
04557 THD_3dim_dataset * PLUTO_4D_to_typed_fith( THD_3dim_dataset * old_dset ,
04558                                            char * new_prefix , int new_datum ,
04559                                            int ignore , int detrend ,
04560                                            generic_func * user_func ,
04561                                            void * user_data )
04562 {
04563    THD_3dim_dataset * new_dset ;  /* output dataset */
04564 
04565 ENTRY("PLUTO_4D_to_typed_fith") ;
04566 
04567    if( ! PLUTO_prefix_ok(new_prefix) ) RETURN(NULL) ;
04568 
04569    new_dset = MAKER_4D_to_typed_fith( old_dset , new_prefix , new_datum ,
04570                                       ignore , detrend , user_func , user_data ) ;
04571 
04572    RETURN(new_dset) ;
04573 }
04574 
04575 /*-------------------------------------------------------------------------*/
04576 
04577 THD_3dim_dataset * PLUTO_4D_to_typed_fbuc( THD_3dim_dataset * old_dset ,
04578                                            char * new_prefix , int new_datum ,
04579                                            int ignore , int detrend ,
04580                                            int nbrik ,
04581                                            generic_func * user_func ,
04582                                            void * user_data )
04583 {
04584    THD_3dim_dataset * new_dset ;  /* output dataset */
04585 
04586 ENTRY("PLUTO_4D_to_typed_fbuc") ;
04587 
04588    if( ! PLUTO_prefix_ok(new_prefix) ) RETURN(NULL) ;
04589 
04590    new_dset = MAKER_4D_to_typed_fbuc( old_dset , new_prefix , new_datum ,
04591                                       ignore , detrend , nbrik , user_func , user_data ) ;
04592 
04593    RETURN(new_dset) ;
04594 }
04595 
04596 void PLUTO_report( PLUGIN_interface * plint , char * str )
04597 {
04598    if( plint == NULL || str == NULL || !AFNI_VERBOSE ) return ;
04599    printf("\n%15.15s= %s" , plint->label , str ) ; fflush(stdout) ;
04600    return ;
04601 }
04602 
04603 /*----------------------------------------------------------------------------
04604   Routines to add a text entry box.
04605 ------------------------------------------------------------------------------*/
04606 
04607 PLUGIN_strval * new_PLUGIN_strval( Widget wpar , char * str )
04608 {
04609    PLUGIN_strval * av ;
04610    XmString xstr ;
04611 
04612 ENTRY("new_PLUGIN_strval") ;
04613 
04614    if( wpar == (Widget) NULL ) RETURN(NULL) ;
04615 
04616    av = myXtNew(PLUGIN_strval) ;
04617 
04618    av->rowcol = XtVaCreateWidget(
04619                   "AFNI" , xmRowColumnWidgetClass , wpar ,
04620                      XmNpacking     , XmPACK_TIGHT ,
04621                      XmNorientation , XmHORIZONTAL ,
04622                      XmNmarginHeight, 0 ,
04623                      XmNmarginWidth , 0 ,
04624                      XmNspacing     , 0 ,
04625                      XmNtraversalOn , False ,
04626                      XmNinitialResourcesPersistent , False ,
04627                   NULL ) ;
04628 
04629    xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
04630    av->label = XtVaCreateManagedWidget(
04631                   "AFNI" , xmLabelWidgetClass , av->rowcol ,
04632                      XmNlabelString , xstr ,
04633                      XmNmarginWidth   , 0  ,
04634                      XmNinitialResourcesPersistent , False ,
04635                   NULL ) ;
04636    XmStringFree( xstr ) ;
04637 
04638    av->textf = XtVaCreateManagedWidget(
04639                   "AFNI" , xmTextFieldWidgetClass , av->rowcol ,
04640                       XmNcolumns      , 9 ,
04641                       XmNeditable     , True ,
04642                       XmNmaxLength    , PLUGIN_STRING_SIZE ,
04643                       XmNresizeWidth  , False ,
04644                       XmNmarginHeight , 1 ,
04645                       XmNmarginWidth  , 1 ,
04646                       XmNcursorPositionVisible , True ,
04647                       XmNblinkRate , 0 ,
04648                       XmNautoShowCursorPosition , True ,
04649                       XmNtraversalOn , False ,
04650                       XmNinitialResourcesPersistent , False ,
04651                    NULL ) ;
04652 
04653    XtManageChild( av->rowcol ) ;
04654    RETURN(av) ;
04655 }
04656 
04657 void destroy_PLUGIN_strval( PLUGIN_strval * av )
04658 {
04659    if( av != NULL ){
04660       XtDestroyWidget( av->rowcol ) ;
04661       myXtFree(av) ;
04662    }
04663    return ;
04664 }
04665 
04666 void alter_PLUGIN_strval_width( PLUGIN_strval * av , int nchar )
04667 {
04668    if( av != NULL && nchar > 0 )
04669       XtVaSetValues( av->textf , XmNcolumns , nchar , NULL ) ;
04670    return ;
04671 }
04672 
04673 void set_PLUGIN_strval( PLUGIN_strval * av , char * str )
04674 {
04675    if( av != NULL && str != NULL )
04676       XmTextFieldSetString( av->textf , str ) ;
04677    return ;
04678 }
04679 
04680 char * get_PLUGIN_strval( PLUGIN_strval * av )   /* must be XtFree-d */
04681 {
04682    if( av == NULL ) return NULL ;
04683                     return XmTextFieldGetString( av->textf ) ;
04684 }
04685 
04686 /* Set the addresses of the main vol2surf globals.  Note that the
04687  * plugin options pointer is stored as (void *) so that vol2surf.h
04688  * will not need to percolate up to afni.h.     09 Sep 2004 [rickr]
04689  */
04690 #include "vol2surf.h"
04691 int PLUTO_set_v2s_addrs(void ** vopt, char *** maps, char ** hist)
04692 {
04693     if ( !vopt || !maps || !hist ) return -1;
04694 
04695     *vopt = (void *)&gv2s_plug_opts;
04696     *maps = gv2s_map_names;
04697     *hist = gv2s_history;
04698 
04699     return 0;
04700 }
04701 
04702 /**************************************************************************/
04703 /*========================================================================*/
04704 /*============ These must remain the last lines of this file! ============*/
04705 
04706 /** put library routines here that must be loaded **/
04707 
04708 #include "cox_render.h"  /* 14 Feb 2002 */
04709 
04710 static vptr_func * forced_loads[] = {
04711 #ifndef NO_DYNAMIC_LOADING
04712    (vptr_func *) startup_lsqfit ,
04713    (vptr_func *) delayed_lsqfit ,
04714    (vptr_func *) mri_align_dfspace ,
04715    (vptr_func *) EDIT_one_dataset ,
04716    (vptr_func *) EDIT_add_brick ,
04717    (vptr_func *) mri_2dalign_setup ,
04718    (vptr_func *) mri_3dalign_setup ,
04719    (vptr_func *) qsort_floatint ,
04720    (vptr_func *) qsort_floatfloat ,
04721    (vptr_func *) symeig_double ,
04722 #ifndef DONT_USE_VOLPACK
04723    (vptr_func *) MREN_render ,
04724 #endif
04725    (vptr_func *) new_MCW_graf ,
04726    (vptr_func *) THD_makemask ,
04727    (vptr_func *) mri_copy ,
04728    (vptr_func *) beta_t2p ,
04729    (vptr_func *) get_laguerre_table ,
04730    (vptr_func *) mri_fix_data_pointer ,
04731    (vptr_func *) THD_zeropad ,
04732    (vptr_func *) THD_axcode ,
04733    (vptr_func *) THD_dataset_rowfillin ,
04734    (vptr_func *) mri_histobyte ,          /* 25 Jul 2001 */
04735    (vptr_func *) sphere_voronoi_vectors , /* 18 Oct 2001 */
04736    (vptr_func *) new_CREN_renderer ,      /* 14 Feb 2002 */
04737    (vptr_func *) THD_average_timeseries , /* 03 Apr 2002 */
04738    (vptr_func *) cl1_solve ,              /* 07 Aug 2002 */
04739    (vptr_func *) new_Dtable ,             /* 20 Oct 2003 */
04740 #endif
04741 NULL } ;
04742 
04743 vptr_func * MCW_onen_i_estel_edain(void *n){
04744   THD_3dim_dataset *ds = (THD_3dim_dataset *)n ;
04745   double             x = (double)(ds->dblk->total_bytes) ;
04746   return forced_loads[(int)x] ;
04747 }
04748 
04749 #else  /* not ALLOW_PLUGINS */
04750 
04751 void * MCW_onen_i_estel_edain(void *n){} ;  /* dummy routine */
04752 
04753 #endif /* ALLOW_PLUGINS */
04754 
04755 /***********************************************************************
04756    Routines that are always compiled, since they are used in
04757    a few places in AFNI that are not plugin-specific.
04758 ************************************************************************/
04759 
04760 void PLUTO_register_timeseries( char * cname , MRI_IMAGE * tsim )
04761 {
04762    MRI_IMAGE * qim ;
04763 
04764 ENTRY("PLUTO_register_timeseries") ;
04765 
04766    if( tsim != NULL ){
04767       qim = mri_to_float( tsim ) ;  /* a copy */
04768       mri_add_name( cname , qim ) ; /* the name */
04769       AFNI_add_timeseries( qim ) ;  /* give it to AFNI */
04770    }
04771    EXRETURN ;
04772 }
04773 
04774 /*----------------------------------------------------------------------------
04775   Find a dataset, given its idcode string. [02 Mar 2002]
04776 ------------------------------------------------------------------------------*/
04777 
04778 THD_3dim_dataset * PLUTO_find_dset_idc( char * idc )
04779 {
04780    MCW_idcode idcode ;
04781    if( idc == NULL ) return NULL ;
04782    MCW_strncpy( idcode.str , idc , MCW_IDSIZE ) ;
04783    return PLUTO_find_dset( &idcode ) ;
04784 }
04785 
04786 /*----------------------------------------------------------------------------
04787   Routine to find a dataset in the global sessionlist, given its idcode.
04788   If this returns NULL, then you are SOL.
04789 ------------------------------------------------------------------------------*/
04790 
04791 THD_3dim_dataset * PLUTO_find_dset( MCW_idcode * idcode )
04792 {
04793    THD_slist_find find ;
04794 
04795 ENTRY("PLUTO_find_dset") ;
04796 
04797    if( idcode == NULL || ISZERO_IDCODE(*idcode) ) RETURN(NULL) ;
04798 
04799    find = THD_dset_in_sessionlist( FIND_IDCODE , idcode ,
04800                                    GLOBAL_library.sslist , -1 ) ;
04801 
04802    RETURN(find.dset) ;
04803 }
04804 
04805 /*-----------------------------------------------------------------*/
04806 
04807 THD_slist_find PLUTO_dset_finder( char *idc )
04808 {
04809    MCW_idcode idcode ;
04810    THD_slist_find find ;
04811 
04812    BADFIND(find) ;
04813    if( idc == NULL ) return find ;
04814    MCW_strncpy( idcode.str , idc , MCW_IDSIZE ) ;
04815    find = THD_dset_in_sessionlist( FIND_IDCODE , &idcode ,
04816                                    GLOBAL_library.sslist , -1 ) ;
04817    return find ;
04818 }
04819 
04820 /*-----------------------------------------------------------------
04821    Plot a histogram; input might be from mri_histogram():
04822      nbin = # of bins in hist[]
04823      bot  = bottom of hist[0] bin   } bin size is
04824      top  = top of hist[nbin-1] bin } (top-bot)/nbin
04825      hist = array of counts in each bin
04826      xlab } labels for x-axis,
04827      ylab }            y-axis
04828      tlab }        and top of graph (NULL => skip this label)
04829 
04830      njist = number of extra histograms [can be 0]
04831      jist  = "extra" histograms to plot atop hist
04832                (if jist == NULL, this plot is skipped)
04833    Graph is popped up and then "forgotten" -- RWCox - 30 Sep 1999.
04834 -------------------------------------------------------------------*/
04835 
04836 void PLUTO_histoplot( int nbin, float bot, float top, int * hist ,
04837                       char * xlab , char * ylab , char * tlab ,
04838                       int njist , int ** jist )
04839 {
04840    int ii , nx , ny,jj ;
04841    float * xar , * yar , * zar=NULL , ** yzar ;
04842    float dx ;
04843 
04844 ENTRY("PLUTO_histoplot") ;
04845 
04846    if( nbin < 2 || hist == NULL ) EXRETURN ;
04847    if( bot >= top ){ bot = 0.0 ; top = nbin ; }
04848 
04849    nx  = 2*(nbin+1) ;
04850    dx  = (top-bot)/nbin ;
04851    xar = (float *) malloc(sizeof(float)*nx) ;
04852    yar = (float *) malloc(sizeof(float)*nx) ;
04853 
04854    if( jist == NULL || njist < 0 ) njist = 0 ;
04855    ny = njist + 1 ;
04856 
04857    yzar = (float **) malloc(sizeof(float *)*ny) ;
04858    yzar[0] = yar ;
04859    for( jj=0 ; jj < njist ; jj++ )
04860      yzar[jj+1] = (float *) malloc(sizeof(float)*nx) ;
04861 
04862    xar[0] = bot ; yar[0] = 0.0 ;
04863    for( ii=0 ; ii < nbin ; ii++ ){
04864      xar[2*ii+1] = bot+ii*dx     ; yar[2*ii+1] = (float) hist[ii] ;
04865      xar[2*ii+2] = bot+(ii+1)*dx ; yar[2*ii+2] = (float) hist[ii] ;
04866 
04867      for( jj=0 ; jj < njist ; jj++ )
04868        yzar[jj+1][2*ii+1] = yzar[jj+1][2*ii+2] = (float) jist[jj][ii] ;
04869    }
04870    xar[2*nbin+1] = top ; yar[2*nbin+1] = 0.0 ;
04871    for( jj=0 ; jj < njist ; jj++ )
04872      yzar[jj+1][0] = yzar[jj+1][2*nbin+1] = 0.0 ;
04873 
04874    plot_ts_lab( GLOBAL_library.dc->display ,
04875                 nx , xar , ny , yzar ,
04876                 xlab,ylab,tlab , NULL , NULL ) ;
04877 
04878    for( jj=0 ; jj < njist ; jj++ ) free(yzar[jj+1]) ;
04879    free(yzar) ; free(xar) ; free(yar) ;
04880    EXRETURN ;
04881 }
04882 
04883 /*----------------------------------------------------------------------
04884   Return p10 as a power of 10 such that
04885     p10 <= fabs(x) < 10*p10
04886   unless x == 0, in which case return 0.
04887 ------------------------------------------------------------------------*/
04888 
04889 static float p10( float x )
04890 {
04891    double y ;
04892    if( x == 0.0 ) return 0.0 ;
04893    if( x <  0.0 ) x = -x ;
04894    y = floor(log10(x)+0.000001) ; y = pow( 10.0 , y ) ;
04895    return (float) y ;
04896 }
04897 
04898 #define STGOOD(s) ( (s) != NULL && (s)[0] != '\0' )
04899 
04900 /*-----------------------------------------------------------------
04901    Plot a scatterplot.
04902      npt  = # of points in x[] and y[]
04903      x    = x-axis values array
04904      y    = y-axis values array
04905      xlab } labels for x-axis,
04906      ylab }            y-axis
04907      tlab }        and top of graph (NULL => skip this label)
04908      a,b  = if nonzero, plots line y=ax+b on top
04909    Graph is popped up and then "forgotten" -- RWCox - 13 Jan 2000
04910 -------------------------------------------------------------------*/
04911 
04912 void PLUTO_scatterplot( int npt , float *x , float *y ,
04913                         char *xlab , char *ylab , char *tlab ,
04914                         float a , float b )
04915 {
04916    int ii , np , nnax,mmax , nnay,mmay ;
04917    float xbot,xtop , ybot,ytop , pbot,ptop ,
04918          xobot,xotop,yobot,yotop , xa,xb,ya,yb , dx,dy ;
04919    float *xar , *yar , *zar=NULL , **yzar ;
04920    float dsq , rx,ry ;
04921    char str[32] ;
04922    MEM_plotdata * mp ;
04923 
04924 ENTRY("PLUTO_scatterplot") ;
04925 
04926    if( npt < 2 || x == NULL || y == NULL ) EXRETURN ;
04927 
04928    /* find range of data */
04929 
04930    xbot = xtop = x[0] ; ybot = ytop = y[0] ;
04931    for( ii=1 ; ii < npt ; ii++ ){
04932            if( x[ii] < xbot ) xbot = x[ii] ;
04933       else if( x[ii] > xtop ) xtop = x[ii] ;
04934 
04935            if( y[ii] < ybot ) ybot = y[ii] ;
04936       else if( y[ii] > ytop ) ytop = y[ii] ;
04937    }
04938    if( xbot >= xtop || ybot >= ytop ){
04939       fprintf(stderr,"*** Data has no range in PLUTO_scatterplot!\n\a");
04940       EXRETURN ;
04941    }
04942 
04943    /*-- push range of x outwards --*/
04944 
04945    pbot = p10(xbot) ; ptop = p10(xtop) ; if( ptop < pbot ) ptop = pbot ;
04946    if( ptop != 0.0 ){
04947       np = (xtop-xbot) / ptop + 0.5 ;
04948       switch( np ){
04949          case 1:  ptop *= 0.1  ; break ;
04950          case 2:  ptop *= 0.2  ; break ;
04951          case 3:  ptop *= 0.25 ; break ;
04952          case 4:
04953          case 5:  ptop *= 0.5  ; break ;
04954       }
04955       xbot = floor( xbot/ptop ) * ptop ;
04956       xtop =  ceil( xtop/ptop ) * ptop ;
04957       nnax = floor( (xtop-xbot) / ptop + 0.5 ) ;
04958       mmax = (nnax < 3) ? 10
04959                         : (nnax < 6) ? 5 : 2 ;
04960    } else {
04961       nnax = 1 ; mmax = 10 ;
04962    }
04963 
04964    /*-- push range of y outwards --*/
04965 
04966    pbot = p10(ybot) ; ptop = p10(ytop) ; if( ptop < pbot ) ptop = pbot ;
04967    if( ptop != 0.0 ){
04968       np = (ytop-ybot) / ptop + 0.5 ;
04969       switch( np ){
04970          case 1:  ptop *= 0.1  ; break ;
04971          case 2:  ptop *= 0.2  ; break ;
04972          case 3:  ptop *= 0.25 ; break ;
04973          case 4:
04974          case 5:  ptop *= 0.5  ; break ;
04975       }
04976       ybot = floor( ybot/ptop ) * ptop ;
04977       ytop =  ceil( ytop/ptop ) * ptop ;
04978       nnay = floor( (ytop-ybot) / ptop + 0.5 ) ;
04979       mmay = (nnay < 3) ? 10
04980                         : (nnay < 6) ? 5 : 2 ;
04981    } else {
04982       nnay = 1 ; mmay = 10 ;
04983    }
04984 
04985    /*-- setup to plot --*/
04986 
04987    create_memplot_surely( "ScatPlot" , 1.3 ) ;
04988    set_thick_memplot( 0.0 ) ;
04989 
04990    /*-- plot labels, if any --*/
04991 
04992    xobot = 0.15 ; xotop = 1.27 ;  /* set objective size of plot */
04993    yobot = 0.1  ; yotop = 0.95 ;
04994 
04995    if( STGOOD(tlab) ){ yotop -= 0.02 ; yobot -= 0.01 ; }
04996 
04997    /* x-axis label? */
04998 
04999    set_color_memplot( 0.0 , 0.0 , 0.0 ) ;
05000    if( STGOOD(xlab) )
05001       plotpak_pwritf( 0.5*(xobot+xotop) , yobot-0.06 , xlab , 16 , 0 , 0 ) ;
05002 
05003    /* y-axis label? */
05004 
05005    set_color_memplot( 0.0 , 0.0 , 0.0 ) ;
05006    if( STGOOD(ylab) )
05007       plotpak_pwritf( xobot-0.12 , 0.5*(yobot+yotop) , ylab , 16 , 90 , 0 ) ;
05008 
05009    /* label at top? */
05010 
05011    set_color_memplot( 0.0 , 0.0 , 0.0 ) ;
05012    if( STGOOD(tlab) )
05013       plotpak_pwritf( xobot+0.01 , yotop+0.01 , tlab , 18 , 0 , -2 ) ;
05014 
05015    /* plot axes */
05016 
05017    set_color_memplot( 0.0 , 0.0 , 0.0 ) ;
05018    plotpak_set( xobot,xotop , yobot,yotop , xbot,xtop , ybot,ytop , 1 ) ;
05019    plotpak_periml( nnax,mmax , nnay,mmay ) ;
05020 
05021    /* plot data */
05022 
05023 #define DSQ 0.001
05024 
05025    dsq = AFNI_numenv( "AFNI_SCATPLOT_FRAC" ) ;   /* 15 Feb 2005 */
05026    if( dsq <= 0.0 || dsq >= 0.01 ) dsq = DSQ ;
05027 
05028    dx = dsq*(xtop-xbot) ;
05029    dy = dsq*(ytop-ybot) * (xotop-xobot)/(yotop-yobot) ;
05030    for( ii=0 ; ii < npt ; ii++ ){
05031 
05032 #if 0
05033       rx = (drand48()-0.5)*dx ;
05034       ry = (drand48()-0.5)*dy ;
05035 #else
05036       rx = ry = 0.0 ;
05037 #endif
05038       xa = x[ii]+rx - dx ; xb = x[ii]+rx + dx ;
05039       ya = y[ii]+ry - dy ; yb = y[ii]+ry + dy ;
05040 
05041       plotpak_line( xa,ya , xa,yb ) ;
05042       plotpak_line( xa,yb , xb,yb ) ;
05043       plotpak_line( xb,yb , xb,ya ) ;
05044       plotpak_line( xb,ya , xa,ya ) ;
05045    }
05046 
05047    if( a != 0.0f || b != 0.0f ){              /* 02 May 2005 */
05048      set_color_memplot( 0.8 , 0.0 , 0.0 ) ;
05049      plotpak_line( xbot,a*xbot+b , xtop,a*xtop+b ) ;
05050    }
05051 
05052    mp = get_active_memplot() ;
05053 
05054    (void) memplot_to_topshell( GLOBAL_library.dc->display , mp , NULL ) ;
05055 
05056    EXRETURN ;
05057 }
05058 
05059 /*----------------------------------------------------------------------
05060    Routine to force AFNI to redisplay images in all open controllers.
05061 ------------------------------------------------------------------------*/
05062 
05063 void PLUTO_force_redisplay(void)
05064 {
05065    Three_D_View * im3d ;
05066    int ii ;
05067 
05068 ENTRY("PLUTO_force_redisplay") ;
05069 
05070    for( ii=0 ; ii < MAX_CONTROLLERS ; ii++ ){
05071       im3d = GLOBAL_library.controllers[ii] ;
05072       if( IM3D_OPEN(im3d) ){
05073          im3d->anat_voxwarp->type =                       /* 11 Jul 1997 */
05074             im3d->fim_voxwarp->type = ILLEGAL_TYPE ;
05075          AFNI_set_viewpoint( im3d , -1,-1,-1 , REDISPLAY_ALL ) ;
05076       }
05077    }
05078    EXRETURN ;
05079 }
05080 
05081 /*----------------------------------------------------------------------
05082    Force the redisplay of the color bars in all image windows.
05083    23 Aug 1998 -- RWCox.
05084 ------------------------------------------------------------------------*/
05085 
05086 void PLUTO_force_rebar(void)
05087 {
05088    Three_D_View * im3d ;
05089    int ii ;
05090 
05091 ENTRY("PLUTO_force_rebar") ;
05092 
05093    for( ii=0 ; ii < MAX_CONTROLLERS ; ii++ ){
05094       im3d = GLOBAL_library.controllers[ii] ;
05095       if( IM3D_OPEN(im3d) ){
05096          drive_MCW_imseq( im3d->s123 , isqDR_rebar , NULL ) ;
05097          drive_MCW_imseq( im3d->s231 , isqDR_rebar , NULL ) ;
05098          drive_MCW_imseq( im3d->s312 , isqDR_rebar , NULL ) ;
05099       }
05100    }
05101    EXRETURN ;
05102 }
05103 
05104 /*------------------------------------------------------------------------*/
05105 static int num_workp      = 0 ;
05106 static XtWorkProc * workp = NULL ;
05107 static XtPointer *  datap = NULL ;
05108 static XtWorkProcId wpid ;
05109 
05110 #undef WPDEBUG
05111 
05112 void PLUTO_register_workproc( XtWorkProc func , XtPointer data )
05113 {
05114 ENTRY("PLUTO_register_workproc") ;
05115 
05116    if( func == NULL ){
05117       fprintf(stderr,"PLUTO_register_workproc: func=NULL on entry!\n") ;
05118       EXRETURN ;
05119    }
05120 
05121    if( num_workp == 0 ){
05122       workp = (XtWorkProc *) malloc( sizeof(XtWorkProc) ) ;
05123       datap = (XtPointer *)  malloc( sizeof(XtPointer) ) ;
05124       wpid  = XtAppAddWorkProc( PLUTO_Xt_appcontext, PLUG_workprocess, NULL ) ;
05125 #ifdef WPDEBUG
05126       fprintf(stderr,"PLUTO_register_workproc: wpid = %x\n",(int)wpid) ;
05127 #endif
05128    } else {
05129       workp = (XtWorkProc *) realloc( workp, sizeof(XtWorkProc)*(num_workp+1) ) ;
05130       datap = (XtPointer*)   realloc( datap, sizeof(XtPointer) *(num_workp+1) ) ;
05131    }
05132 
05133    workp[num_workp] = func ;
05134    datap[num_workp] = data ;
05135    num_workp++ ;
05136 
05137 #ifdef WPDEBUG
05138 fprintf(stderr,"PLUTO_register_workproc: have %d workprocs\n",num_workp) ;
05139 #endif
05140 
05141    EXRETURN ;
05142 }
05143 
05144 void PLUTO_remove_workproc( XtWorkProc func )
05145 {
05146    int ii , ngood ;
05147 
05148 ENTRY("PLUTO_remove_workproc") ;
05149 
05150    if( func == NULL || num_workp == 0 ){
05151       fprintf(stderr,"*** PLUTO_remove_workproc: illegal parameters!\n") ;
05152       EXRETURN ;
05153    }
05154 
05155    for( ii=0 ; ii < num_workp ; ii++ ){
05156       if( func == workp[ii] ) workp[ii] = NULL ;
05157    }
05158 
05159    for( ii=0,ngood=0 ; ii < num_workp ; ii++ )
05160       if( workp[ii] != NULL ) ngood++ ;
05161 
05162    if( ngood == 0 ){
05163 #ifdef WPDEBUG
05164       fprintf(stderr,"PLUTO_remove_workproc: No workprocs left\n") ;
05165 #endif
05166       XtRemoveWorkProc( wpid ) ;
05167       free(workp) ; workp = NULL ; free(datap) ; datap = NULL ;
05168       num_workp = 0 ;
05169    } else {
05170 #ifdef WPDEBUG
05171       fprintf(stderr,"PLUTO_remove_workproc: %d workprocs left\n",ngood) ;
05172 #endif
05173    }
05174 
05175    EXRETURN ;
05176 }
05177 
05178 Boolean PLUG_workprocess( XtPointer fred )
05179 {
05180    int ii , ngood ;
05181    Boolean done ;
05182 
05183 #ifdef WPDEBUG
05184    { static int ncall=0 ;
05185      if( (ncall++) % 1000 == 0 )
05186        fprintf(stderr,"PLUG_workprocess: entry %d\n",ncall) ; }
05187 #endif
05188 
05189    if( num_workp == 0 ) return True ;
05190 
05191    for( ii=0,ngood=0 ; ii < num_workp ; ii++ ){
05192       if( workp[ii] != NULL ){
05193          done = workp[ii]( datap[ii] ) ;
05194          if( done == True ) workp[ii] = NULL ;
05195          else               ngood++ ;
05196       }
05197    }
05198 
05199    if( ngood == 0 ){
05200 #ifdef WPDEBUG
05201       fprintf(stderr,"Found no workprocs left\n") ;
05202 #endif
05203       free(workp) ; workp = NULL ; free(datap) ; datap = NULL ;
05204       num_workp = 0 ;
05205       return True ;
05206    }
05207    return False ;
05208 }
05209 
05210 /*---------------------------------------------------------------*/
05211 
05212 typedef struct {
05213   generic_func * func ;
05214   XtPointer      cd ;
05215 } mytimeout ;
05216 
05217 static void PLUG_dotimeout_CB( XtPointer cd , XtIntervalId * id )
05218 {
05219    mytimeout * myt = (mytimeout *) cd ;
05220 
05221 ENTRY("PLUTO_dotimeout_CB") ;
05222 
05223    if( myt == NULL ) EXRETURN ;  /* bad news */
05224 
05225 STATUS("calling user timeout function") ;
05226 
05227 #if 0
05228    myt->func( myt->cd ) ;
05229 #else
05230    AFNI_CALL_VOID_1ARG( myt->func , XtPointer,myt->cd ) ;
05231 #endif
05232 
05233    myXtFree(myt) ; EXRETURN ;
05234 }
05235 
05236 void PLUTO_register_timeout( int msec, generic_func * func, XtPointer cd )
05237 {
05238    mytimeout * myt ;
05239 
05240 ENTRY("PLUTO_register_timeout") ;
05241 
05242    if( func == NULL ){
05243       fprintf(stderr,"PLUTO_register_timeout: func=NULL on entry!\n") ;
05244       EXRETURN ;
05245    }
05246 
05247    if( msec < 0 ) msec = 0 ;
05248 
05249    myt       = myXtNew(mytimeout) ;
05250    myt->func = func ;
05251    myt->cd   = cd ;
05252 
05253    (void) XtAppAddTimeOut( PLUTO_Xt_appcontext , msec ,
05254                            PLUG_dotimeout_CB , (XtPointer) myt ) ;
05255 
05256    EXRETURN ;
05257 }
05258 
05259 /*---------------------------------------------------------------*/
05260 
05261 double PLUTO_elapsed_time(void) /* in seconds */
05262 {
05263    struct timeval  new_tval ;
05264    struct timezone tzone ;
05265    static struct timeval old_tval ;
05266    static int first = 1 ;
05267 
05268    gettimeofday( &new_tval , &tzone ) ;
05269 
05270    if( first ){
05271       old_tval = new_tval ;
05272       first    = 0 ;
05273       return 0.0 ;
05274    }
05275 
05276    if( old_tval.tv_usec > new_tval.tv_usec ){
05277       new_tval.tv_usec += 1000000 ;
05278       new_tval.tv_sec -- ;
05279    }
05280 
05281    return (double)( (new_tval.tv_sec  - old_tval.tv_sec )
05282                    +(new_tval.tv_usec - old_tval.tv_usec)*1.0e-6 ) ;
05283 }
05284 
05285 double PLUTO_cpu_time(void)  /* in seconds */
05286 {
05287 #ifdef CLK_TCK
05288    struct tms ttt ;
05289 
05290    (void) times( &ttt ) ;
05291    return (  (double) (ttt.tms_utime
05292                                      /* + ttt.tms_stime */
05293                       )
05294            / (double) CLK_TCK ) ;
05295 #else
05296    return 0.0l ;
05297 #endif
05298 }
05299 
 

Powered by Plone

This site conforms to the following standards: