1 /*****************************************************************************
2    Major portions of this software are copyrighted by the Medical College
3    of Wisconsin, 1994-2000, and are released under the Gnu General Public
4    License, Version 2.  See the file README.Copyright for details.
5 ******************************************************************************/
6 
7 #undef MAIN
8 #include "afni.h"
9 
10 #include "mcw_graf.h"
11 #include "parser.h"
12 #include "whats_my_exepath.h"
13 /*========================================================================*/
14 /*==== Compile this only if plugins are properly enabled in machdep.h ====*/
15 
16 #ifdef ALLOW_PLUGINS
17 
18 #define EMPTY_STRING "\0"
19 
20 #define COLSIZE AV_colsize()
21 
22 static Widget wtemp ;
23 
24 /***************************************************************************
25    Routines to open and initialize plugins.  These should only
26    be called at the very end of AFNI initialization, since they
27    will call each plugin's internal initializer function, which
28    may make requests to get AFNI data structures.
29 ****************************************************************************/
30 
31 /*================ dynamic loading of plugins is allowed ==================*/
32 #ifndef NO_DYNAMIC_LOADING
33 
34 /*-------------------------------------------------------------------------
35    Routine to read in all plugins found in a given directory
36 ---------------------------------------------------------------------------*/
37 
PLUG_get_all_plugins(char * dname)38 AFNI_plugin_array * PLUG_get_all_plugins( char * dname )
39 {
40    THD_string_array * flist , * rlist ;
41    int ir , ii ;
42    char * fname , * suff ;
43    AFNI_plugin_array * outar ;
44    AFNI_plugin       * plin ;
45 
46    /*----- sanity check and initialize -----*/
47 
48 ENTRY("PLUG_get_all_plugins") ;
49 
50    if( dname == NULL || strlen(dname) == 0 ) RETURN(NULL) ;
51    if( ! THD_is_directory(dname) )           RETURN(NULL) ;
52 
53    INIT_PLUGIN_ARRAY( outar ) ;
54 
55 if(PRINT_TRACING)
56 { char str[256] ; sprintf(str,"scanning directory %s",dname) ; STATUS(str) ; }
57 
58    /*----- find all filenames -----*/
59 
60    flist = THD_get_all_filenames( dname ) ;
61    if( flist == NULL || flist->num <= 0 ){
62       DESTROY_SARR(flist) ;
63       DESTROY_PLUGIN_ARRAY(outar) ;
64       RETURN(NULL) ;
65    }
66 
67    rlist = THD_extract_regular_files( flist ) ;
68    DESTROY_SARR(flist) ;
69    if( rlist == NULL || rlist->num <= 0 ){
70       DESTROY_SARR(rlist) ;
71       DESTROY_PLUGIN_ARRAY(outar) ;
72       RETURN(NULL) ;
73    }
74 
75 if(PRINT_TRACING)
76 { char str[256] ; sprintf(str,"%d files to scan",rlist->num) ; STATUS(str) ; }
77 
78    /*----- scan thru and find all filenames ending in DYNAMIC_suffix -----*/
79 
80    for( ir=0 ; ir < rlist->num ; ir++ ){
81       fname = rlist->ar[ir] ; if( fname == NULL ) continue ;
82       if( strstr(fname,"plug") == NULL ) continue ;
83       if( strstr(fname,"plug_nlfit.") != NULL ) continue ; /* 13 Jul 2020 */
84 
85       suff = strstr(fname,DYNAMIC_suffix) ;
86       if( suff != NULL && strlen(suff) == strlen(DYNAMIC_suffix) ){
87          plin  = PLUG_read_plugin( fname ) ;
88          if( plin != NULL ) ADDTO_PLUGIN_ARRAY( outar , plin ) ;
89       }
90    }
91 
92 if(PRINT_TRACING)
93 { char str[256] ;
94   sprintf(str,"directory %s has %d plugins",dname,outar->num) ; STATUS(str) ; }
95 
96    DESTROY_SARR(rlist) ;
97    if( outar->num == 0 ) DESTROY_PLUGIN_ARRAY(outar) ;
98 
99    /* 06 Aug 1999: sort array by seqcodes */
100 
101    if( outar != NULL && outar->num > 1 ){
102       int iid , qq ; AFNI_plugin * plin ;
103       do{ qq = 0 ;
104           for( iid=1 ; iid < outar->num ; iid++ )
105              if( strcmp(outar->plar[iid-1]->seqcode,
106                         outar->plar[iid  ]->seqcode ) > 0 ){
107 
108                 plin               = outar->plar[iid-1] ;
109                 outar->plar[iid-1] = outar->plar[iid] ;
110                 outar->plar[iid]   = plin ;
111                 qq++ ;
112              }
113       } while( qq > 0 ) ;
114    }
115 
116    RETURN(outar) ;
117 }
118 
119 /*----------------------------------------------------------------------
120    Routine to open and initialize a single plugin
121 ------------------------------------------------------------------------*/
122 
PLUG_read_plugin(char * fname)123 AFNI_plugin * PLUG_read_plugin( char *fname )
124 {
125    AFNI_plugin *plin ;
126    PLUGIN_interface *plint=NULL ;
127    int nin ;
128    static int firsterr=1 ;
129 
130    /*----- sanity checks -----*/
131 
132 ENTRY("PLUG_read_plugin") ;
133 
134    if( fname == NULL || strlen(fname) == 0 ) RETURN(NULL) ;
135    if( ! THD_is_file(fname) )                RETURN(NULL) ;
136 
137    /*----- make space for new plugin -----*/
138 
139    plin = (AFNI_plugin *) XtMalloc( sizeof(AFNI_plugin) ) ;
140    memset(plin, 0, sizeof(AFNI_plugin)) ; /* 11 Feb 2009 [lesstif patrol] */
141    plin->type = AFNI_PLUGIN_TYPE ;
142 
143    /*----- copy name into plin structure -----*/
144 
145    MCW_strncpy( plin->libname , fname , MAX_PLUGIN_NAME ) ;
146 
147    /*----- open the library (we hope) -----*/
148 
149 if(PRINT_TRACING)
150 { char str[256] ;
151   sprintf(str,"opening plugin %s" , fname ) ; STATUS(str) ; }
152 
153    DYNAMIC_OPEN( fname , plin->libhandle ) ;
154 
155 STATUS("returned from DYNAMIC_OPEN()") ;
156 
157    if( ! ISVALID_DYNAMIC_handle( plin->libhandle ) ){  /* open failed */
158 
159       /* 24 May 2001: always print if there is an error */
160 
161       char *er ;
162       if( firsterr ){fprintf(stderr,"\n"); firsterr=0; }
163       fprintf(stderr,"Failed to open plugin %s",fname) ;
164       er = (char *)DYNAMIC_ERROR_STRING ;
165       if( er != NULL ) fprintf(stderr," -- %s\n",er) ;
166       else             fprintf(stderr,"\n") ;
167 
168       myXtFree(plin) ; RETURN(NULL) ;
169    }
170 
171    /* open was good */
172 
173 if(PRINT_TRACING)
174 { char str[256] ;
175   sprintf(str,"opened library %s with handle %p" , fname,plin->libhandle ) ;
176   STATUS(str) ; }
177 
178    /*----- find the required symbol -----*/
179    /*..... 13 Sep 2001: add _ for stupid Darwin .....*/
180    /*..... 30 Oct 2003: remove for OS X 10.3    .....*/
181 
182 #ifndef NEED_UNDERSCORE
183    DYNAMIC_SYMBOL(plin->libhandle, "PLUGIN_init" , plin->libinit_func );
184 #else
185    DYNAMIC_SYMBOL(plin->libhandle,"_PLUGIN_init" , plin->libinit_func );
186 #endif
187 
188    /*----- if symbol not found, complain and kill this plugin -----*/
189 
190    if( plin->libinit_func == (vptr_func *) NULL ){
191       char *er = (char *)DYNAMIC_ERROR_STRING ;
192       if( firsterr ){fprintf(stderr,"\n"); firsterr=0; }
193       fprintf(stderr,"plugin %s lacks PLUGIN_init() function\n",fname) ;
194       if( er != NULL ) fprintf(stderr," -- %s\n",er) ;
195       DYNAMIC_CLOSE( plin->libhandle ) ;
196       myXtFree(plin) ;
197       RETURN(NULL) ;
198    }
199 
200    /*----- create interface(s) by calling initialization function -----*/
201 
202    plin->interface_count = nin = 0 ;
203    plin->interface       = NULL ;
204 
205 #ifdef AFNI_DEBUG
206    MCHECK ;
207 #else
208    MPROBE ;
209 #endif
210 
211    do {
212 #if 0
213       plint = (PLUGIN_interface *) plin->libinit_func( nin ) ;
214 #else
215       AFNI_CALL_VALU_1ARG(plin->libinit_func ,
216                           PLUGIN_interface *,plint , int,nin ) ;
217 #endif
218       if( plint == NULL ) break ;
219 
220       plin->interface = (PLUGIN_interface **)
221                           XtRealloc( (char *) plin->interface ,
222                                      sizeof(PLUGIN_interface *) * (nin+1) ) ;
223 
224       plin->interface[nin] = plint ;
225       if( nin == 0 ) strcpy( plin->seqcode , plint->seqcode ) ;  /* 06 Aug 1999 */
226       nin++ ;
227    } while( plint != NULL ) ;
228 
229    plin->interface_count = nin ;
230 
231 #if 1
232    if( nin > 0 ){                                    /* 01 Nov 1999 */
233       char * bcol , benv[256] ;
234       int ii = strlen(DYNAMIC_suffix) , jj ;
235 
236       strcpy(benv,"AFNI_") ; strcat(benv,THD_trailname(fname,0)) ; /* make */
237       jj = strlen(benv) ; benv[jj-ii] = '\0' ;                     /* name */
238       strcat(benv,"_butcolor") ;
239       bcol = my_getenv(benv) ;                       /* find name */
240       if( bcol != NULL ){                            /* if have name: */
241          for( ii=0 ; ii < nin ; ii++ ){
242             plint = plin->interface[ii] ;
243             if( plint->butcolor[0] == '\0' )         /* set color if */
244                PLUTO_set_butcolor( plint , bcol ) ;  /* not defined */
245          }
246       }
247    }
248 #endif
249 
250 if(PRINT_TRACING)
251 { char str[256] ;
252   sprintf(str,"library %s created %d interfaces",fname,nin) ; STATUS(str) ; }
253 
254    /*----- done -----*/
255 
256    RETURN(plin) ;
257 }
258 
259 /*--------------------------------------------------------------------
260    Routine to read in all plugins in the desired list of directories
261    29 Mar 2001: pname = argv[0] = potential program name
262 ----------------------------------------------------------------------*/
263 
264 #ifdef DARWIN
265 #include <mach-o/dyld.h>
266 /* extern unsigned long _dyld_present(void); */
267 #endif
268 
PLUG_get_many_plugins(char * pname)269 AFNI_plugin_array * PLUG_get_many_plugins(char *pname)
270 {
271    char * epath , * elocal , * eee ;
272    char ename[THD_MAX_NAME] ;
273    AFNI_plugin_array * outar , * tmpar ;
274    int epos , ll , ii , id ;
275    THD_string_array *qlist ; /* 02 Feb 2002 */
276 #ifdef DARWIN
277    int size = PATH_MAX;
278 #else
279    int size = THD_MAX_NAME;
280 #endif
281    char *exe_path=NULL, *exe_dir=NULL, *lib_dir=NULL;
282 
283 
284    /*----- sanity checks -----*/
285 
286 ENTRY("PLUG_get_many_plugins") ;
287 
288 /**
289 #if defined(DARWIN) && !defined(c_plusplus) && !defined(__cplusplus)
290 **/
291 #if 0  /* formerly ifdef DARWIN */
292    if( _dyld_present() == 0 ) RETURN(NULL) ;  /* 05 Sep 2001: Mac OSX */
293 #endif
294 
295    epath = getenv("AFNI_PLUGINPATH") ;     /* get the path list to read from */
296 
297    if( epath == NULL )
298      epath = getenv("AFNI_PLUGIN_PATH") ; /* try another name? */
299 
300    if( epath == NULL ) {
301       exe_path = (char *)malloc(sizeof(char)*size);
302       if( whats_my_exepath(exe_path, size) ) {
303          fprintf(stderr,"** failure\n");
304          RETURN(NULL);
305       }
306       exe_dir = strdup(dirname(exe_path)) ;
307       /* contents of exe_path not guaranteed */
308       free(exe_path) ;
309 
310       /* get possible lib directory for alternative installation pattern */
311       lib_dir = malloc(strlen(exe_dir)+64) ;
312       strcpy(lib_dir,exe_dir) ; strcat(lib_dir,"/../lib") ;
313 
314       /* use putative bin and lib dirs to search for plugins */
315       epath = (char *)malloc(size) ;
316       strcpy(epath,exe_dir) ;
317       free(exe_dir) ;
318 
319       strcat(strcat(epath," "),lib_dir) ;
320       free(lib_dir) ;
321    }
322 
323    if( epath == NULL && pname != NULL && strchr(pname,'/') != NULL ){ /* 29 Mar 2001 */
324      char *ep = strdup(pname) ;                                       /* get path    */
325      char *tp = THD_trailname(ep,0) ;                                 /* to program  */
326      *tp = '\0' ;
327      if( strlen(ep) > 0 ) epath = ep ;    /* got some path */
328      else                 free(ep) ;      /* got zipperoni */
329    }
330 
331    if( epath == NULL ) /* abandon plugin search */
332       RETURN(NULL) ;
333 
334    INIT_SARR(qlist) ; /* 02 Feb 2002: list of checked directories */
335 
336    /*----- copy path list into local memory -----*/
337 
338    ll = strlen(epath) ;
339    elocal = (char *) XtMalloc( sizeof(char) * (ll+2) ) ;
340 
341    /*----- put a blank at the end -----*/
342 
343    strcpy( elocal , epath ) ; elocal[ll] = ' ' ; elocal[ll+1] = '\0' ;
344 
345    /*----- replace colons with blanks -----*/
346 
347    for( ii=0 ; ii < ll ; ii++ )
348      if( elocal[ii] == ':' ) elocal[ii] = ' ' ;
349 
350   printf("\nPath(s) to be searched for plugins: \n%s\n",elocal) ;
351   fflush(stdout) ;
352 
353    /*----- extract blank delimited strings;
354            use as directory names to get libraries -----*/
355 
356    INIT_PLUGIN_ARRAY( outar ) ;
357    epos = 0 ;
358 
359    do{
360       ii = sscanf( elocal+epos , "%s%n" , ename , &id ) ; /* next substring */
361       if( ii < 1 || id < 1 ) break ;                      /* none --> end of work */
362       epos += id ;                                        /* char after last scanned */
363 
364       if( !THD_is_directory(ename) ) continue ;           /* 21 May 2002 -rcr */
365 
366       /* 02 Feb 2002: did we check this one already? */
367 
368       for( ii=0 ; ii < qlist->num ; ii++ )
369          if( THD_equiv_files(qlist->ar[ii],ename) ) break ;
370       if( ii < qlist->num ) continue ;
371       ADDTO_SARR(qlist,ename) ;
372 
373       ii = strlen(ename) ;                                /* make sure name has */
374       if( ename[ii-1] != '/' ){                           /* a trailing '/' on it */
375           ename[ii]  = '/' ; ename[ii+1] = '\0' ;
376       }
377 
378       tmpar = PLUG_get_all_plugins( ename ) ;             /* read this directory */
379       if( tmpar != NULL ){
380          for( ii=0 ; ii < tmpar->num ; ii++ )             /* move results to output */
381            ADDTO_PLUGIN_ARRAY( outar , tmpar->plar[ii] ) ;
382 
383          FREE_PLUGIN_ARRAY(tmpar) ;                       /* toss temp array */
384       }
385    } while( epos < ll ) ;  /* scan until 'epos' is after end of epath */
386 
387    myXtFree(elocal) ;
388 
389 if(PRINT_TRACING)
390 { char str[256] ; sprintf(str,"found %d plugins",outar->num) ; STATUS(str) ; }
391 
392    if( outar->num == 0 ) DESTROY_PLUGIN_ARRAY(outar) ;
393    DESTROY_SARR(qlist) ; /* 02 Feb 2002 */
394    RETURN(outar) ;
395 }
396 
397 /*===================  Plugins are statically linked into AFNI ===================*/
398 
399 #else  /* NO_DYNAMIC_LOADING is defined (e.g., CYGWIN) */
400 
401 /* get the list of fixed (compiled-in) plugins */
402 
403 #include "fixed_plugins.h"
404 
405 /*-------------------------------------------------------------------------------*/
406 /*! Function to load one fixed plugin (for CYGWIN) */
407 
PLUG_load_fixed_plugin(FIXED_plugin pin)408 AFNI_plugin * PLUG_load_fixed_plugin( FIXED_plugin pin )
409 {
410    AFNI_plugin * plin ;
411    PLUGIN_interface * plint ;
412    int nin ;
413 
414    /*----- sanity checks -----*/
415 
416 ENTRY("PLUG_load_plugin") ;
417 
418    if( pin.pfunc == NULL ) RETURN(NULL) ;
419 
420    /*----- make space for new plugin -----*/
421 
422    plin = (AFNI_plugin *) XtMalloc( sizeof(AFNI_plugin) ) ;
423    memset(plin, 0, sizeof(AFNI_plugin)) ; /* 11 Feb 2009 [lesstif patrol] */
424    plin->type = AFNI_PLUGIN_TYPE ;
425 
426    /*----- copy name into plin structure -----*/
427 
428    MCW_strncpy( plin->libname , pin.pname , MAX_PLUGIN_NAME ) ;
429    plin->libinit_func = pin.pfunc ;
430 
431    /*----- create interface(s) by calling initialization function -----*/
432 
433    plin->interface_count = nin = 0 ;
434    plin->interface       = NULL ;
435 
436    do {
437       plint = (PLUGIN_interface *) plin->libinit_func( nin ) ;
438       if( plint == NULL ) break ;
439 
440       plin->interface = (PLUGIN_interface **)
441                           XtRealloc( (char *) plin->interface ,
442                                      sizeof(PLUGIN_interface *) * (nin+1) ) ;
443 
444       plin->interface[nin] = plint ;
445       if( nin == 0 ) strcpy( plin->seqcode , plint->seqcode ) ;  /* 06 Aug 1999 */
446       nin++ ;
447    } while( plint != NULL ) ;
448 
449    plin->interface_count = nin ;
450 
451    /*----- done -----*/
452 
453    RETURN(plin) ;
454 }
455 
456 /*------------------------------------------------------------------------*/
457 /*! Function to load all fixed plugins (for CYGWIN).  pname is ignored. */
458 
PLUG_get_many_plugins(char * pname)459 AFNI_plugin_array * PLUG_get_many_plugins(char *pname)
460 {
461    int ir ;
462    AFNI_plugin_array * outar ;
463    AFNI_plugin       * plin ;
464 
465    /*----- sanity check and initialize -----*/
466 
467 ENTRY("PLUG_get_many_plugins") ;
468 
469    INIT_PLUGIN_ARRAY( outar ) ;
470 
471    /*----- scan thru and create plugins from the fixed list -----*/
472 
473    for( ir=0 ; ir < NUM_FIXED_plugin_funcs ; ir++ ){
474       plin = PLUG_load_fixed_plugin( FIXED_plugin_funcs[ir] ) ;
475       if( plin != NULL ) ADDTO_PLUGIN_ARRAY( outar , plin ) ;
476    }
477 
478    RETURN(outar) ;
479 }
480 
481 #endif /* NO_DYNAMIC_LOADING */
482 
483 /*==============================================================================*/
484 
485 /****************************************************************************
486   Routines to create interface descriptions for new plugins. Usage:
487     1) Use "new_PLUGIN_interface" to create the initial data structure.
488     2) Use "add_option_to_PLUGIN_interface" to create an option line in the
489          AFNI interface menu.  There is no built-in limit to the number
490          of option lines that may be added to an AFNI interface menu.
491     2(abcdef)
492        Use "add_number_to_PLUGIN_interface"  , and
493            "add_string_to_PLUGIN_interface"  , and
494            "add_dataset_to_PLUGIN_interface" , et cetera,
495          to add control parameter choosers to the most recently created
496          option line.  Up to 6 choosers may be added to an option line.
497     3) When done, return the new "PLUGIN_interface *" to AFNI.
498 *****************************************************************************/
499 
500 /*--------------------------------------------------------------------------
501    Create a new plugin interface.
502 
503    label       = C string to go on the button that activates this interface
504                    (will be truncated to 15 characters)
505 
506    description = C string to go on the interface control panel popped-up
507                    when the button above is pressed -- this has no
508                    meaning for call_type = PLUGIN_CALL_IMMEDIATELY
509 
510    help        = C string to be popped up if the user presses "Help" on
511                    the interface control panel -- this has no
512                    meaning for call_type = PLUGIN_CALL_IMMEDIATELY.
513                    If this is NULL, then there will be no help available.
514 
515    call_type   = int that describes how the plugin is to be called from AFNI:
516                    PLUGIN_CALL_IMMEDIATELY means to call APL_main as soon
517                      as the activating button is pressed;
518                    PLUGIN_CALL_VIA_MENU means to have AFNI popup a menu
519                      to control the input parameters passed to APL_main.
520 
521    call_func   = routine that AFNI should call when the user activates
522                    this plugin.  The routine will be passed the the
523                    pointer "PLUGIN_interface *" created herein, which
524                    can be interrogated with the get_*_from_PLUGIN_interface
525                    routines.  The call_func should return a "char *", which
526                    is NULL if everything is OK, and points to an error
527                    message that AFNI will display if something bad happened.
528 
529    The value returned is the pointer to the new interface struct.
530 
531    Note that the three input strings are copied by AFNI, and so could
532    be freed after this routine returns.
533 ----------------------------------------------------------------------------*/
534 
new_PLUGIN_interface(char * label,char * description,char * help,int call_type,cptr_func * call_func)535 PLUGIN_interface * new_PLUGIN_interface( char * label , char * description ,
536                                          char * help ,
537                                          int call_type , cptr_func * call_func )
538 {
539    PLUGIN_interface * plint ;
540 
541 ENTRY("new_PLUGIN_interface") ;
542 
543    plint = new_PLUGIN_interface_1999( label , description , help ,
544                                       call_type , call_func , NULL ) ;
545    RETURN(plint) ;
546 }
547 
548 /**** 15 Jun 1999: modified to crosscheck compilation dates ****/
549 
550 #include <time.h>
551 
new_PLUGIN_interface_1999(char * label,char * description,char * help,int call_type,cptr_func * call_func,char * compile_date)552 PLUGIN_interface * new_PLUGIN_interface_1999( char * label , char * description ,
553                                               char * help ,
554                                               int call_type , cptr_func * call_func ,
555                                               char * compile_date )
556 {
557    PLUGIN_interface * plint ;
558    static int num_date_err = 0 ;
559 
560    /*-- sanity check --*/
561 
562 ENTRY("new_PLUGIN_interface_1999") ;
563 
564    if( label == NULL || strlen(label) == 0 ) RETURN(NULL) ;
565 
566    if( !( (call_type == PLUGIN_CALL_IMMEDIATELY) ||
567           (call_type == PLUGIN_CALL_VIA_MENU   )
568         ) ) RETURN(NULL) ;
569 
570    if( call_func == (cptr_func *) NULL ) RETURN(NULL) ;
571 
572    /*-- create new interface --*/
573 
574    plint = (PLUGIN_interface *) XtMalloc(sizeof(PLUGIN_interface)) ;
575    if( plint == NULL ) RETURN(NULL) ;
576    memset(plint, 0, sizeof(PLUGIN_interface)) ; /* 11 Feb 2009 [LPatrol] */
577 
578    plint->flags = 0 ;  /* 29 Mar 2002 */
579 
580    MCW_strncpy( plint->label , label , PLUGIN_LABEL_SIZE ) ;
581 
582    if( description != NULL )
583       MCW_strncpy( plint->description , description , PLUGIN_STRING_SIZE ) ;
584    else
585       MCW_strncpy( plint->description , label , PLUGIN_STRING_SIZE ) ;
586 
587    plint->call_method  = call_type ;
588    plint->call_func    = call_func ;
589    plint->option_count = 0 ;
590    plint->option       = NULL ;
591    plint->wid          = NULL ;
592    plint->im3d         = NULL ;
593    plint->hint         = NULL ;
594    plint->toplabel[0]  = '\0' ;  /* 13 May 2010 */
595 
596    if( help == NULL || strlen(help) == 0 )
597       plint->helpstring = NULL ;
598    else
599       plint->helpstring = XtNewString( help ) ;
600 
601    strcpy( plint->seqcode , "zzzzzzz" ) ; /* 06 Aug 1999 */
602    strcpy( plint->butcolor, "\0" ) ;      /* 01 Nov 1999 */
603 
604    /** 15 Jun 1999 stuff for date checking **/
605 
606 #ifndef DONT_USE_STRPTIME
607    if( compile_date == NULL ){
608 
609       if( num_date_err == 0 ) fprintf(stderr,"\n") ;
610       fprintf(stderr,
611               "*** Warning: Plugin %-15s was compiled with an earlier version of AFNI\n",
612               label ) ;
613       num_date_err++ ;
614 
615 #if 0
616 #  define AFNI_DATE "Jun 17 1999"  /* for testing purposes */
617 #else
618 #  define AFNI_DATE __DATE__
619 #endif
620 
621    } else {
622       struct tm compile_tm  ={0} , date_tm={0} ;
623       time_t    compile_time     , date_time   ;
624       double    date_minus_compile ;
625 
626       strptime( compile_date , "%b %d %Y" , &compile_tm ) ; compile_time = mktime( &compile_tm ) ;
627       strptime( AFNI_DATE    , "%b %d %Y" , &date_tm    ) ; date_time    = mktime( &date_tm    ) ;
628       date_minus_compile = difftime( date_time , compile_time ) ;
629 
630       if( date_minus_compile > 3600.0 ){
631          if( num_date_err == 0 ) fprintf(stderr,"\n") ;
632          fprintf(stderr,
633                  "\n*** Warning: Plugin %-15s compile date=%s predates AFNI=%s",
634                  label , compile_date , AFNI_DATE ) ;
635          num_date_err++ ;
636       } else if( PRINT_TRACING ){
637          char str[256] ;
638          sprintf(str,"Plugin %-15s compile date=%s  AFNI date=%s  difftime=%g\n",
639                  label , compile_date , AFNI_DATE , date_minus_compile ) ;
640          STATUS(str) ;
641       }
642    }
643 #endif
644 
645    plint->run_label[0]  = '\0' ;  /* 04 Nov 2003 */
646    plint->doit_label[0] = '\0' ;
647 
648    plint->wid           = NULL ;
649 
650    RETURN(plint) ;
651 }
652 
653 /*------------------------------------------------------------------------*/
654 /*! Set the "Run+Keep" and "Run+Close" labels for a plugin. [04 Nov 2003] */
655 /*------------------------------------------------------------------------*/
656 
PLUTO_set_runlabels(PLUGIN_interface * plint,char * rlab,char * dlab)657 void PLUTO_set_runlabels( PLUGIN_interface *plint , char *rlab , char *dlab )
658 {
659    if( plint == NULL ) return ;
660    if( rlab != NULL  ) MCW_strncpy( plint->run_label , rlab, PLUGIN_LABEL_SIZE );
661    if( dlab != NULL  ) MCW_strncpy( plint->doit_label, dlab, PLUGIN_LABEL_SIZE );
662    return ;
663 }
664 
665 /*----------------------------------------------------------------------
666   Set the seqcode in a plugin, for sorting in the interface.
667   [06 Aug 1999]
668 ------------------------------------------------------------------------*/
669 
PLUTO_set_sequence(PLUGIN_interface * plint,char * sq)670 void PLUTO_set_sequence( PLUGIN_interface * plint , char * sq )
671 {
672 ENTRY("PLUTO_set_sequence") ;
673    if( plint == NULL || sq == NULL || sq[0] == '\0' ) EXRETURN ;
674    MCW_strncpy( plint->seqcode , sq , PLUGIN_STRING_SIZE ) ;
675    EXRETURN ;
676 }
677 
678 /*----------------------------------------------------------------------
679   Set the button color in a plugin [01 Nov 1999]
680 ------------------------------------------------------------------------*/
681 
PLUTO_set_butcolor(PLUGIN_interface * plint,char * sq)682 void PLUTO_set_butcolor( PLUGIN_interface * plint , char * sq )
683 {
684 ENTRY("PLUTO_set_butcolor") ;
685    if( plint == NULL || sq == NULL || sq[0] == '\0' ) EXRETURN ;
686    if( strncmp(sq,"hot",3) == 0 ) sq = MCW_hotcolor(NULL) ;
687    MCW_strncpy( plint->butcolor , sq , PLUGIN_STRING_SIZE ) ;
688    EXRETURN ;
689 }
690 
691 /*----------------------------------------------------------------------
692   Change the top level label in a plugin [13 May 2010]
693 ------------------------------------------------------------------------*/
694 
PLUTO_set_toplabel(PLUGIN_interface * plint,char * lab)695 void PLUTO_set_toplabel( PLUGIN_interface *plint , char *lab )
696 {
697 ENTRY("PLUTO_set_toplabel") ;
698    if( plint != NULL ){
699      if( plint->wid != NULL )
700        MCW_set_widget_label( plint->wid->label , lab ) ;
701      MCW_strncpy( plint->toplabel , lab , PLUGIN_STRING_SIZE ) ;
702    }
703    EXRETURN ;
704 }
705 
706 /*---------------------------------------------------------------------------
707    Routine to add a new option line to a plugin interface menu.
708 
709    plint      = PLUGIN_interface * which will have the option added
710    label     = C string to be displayed in the menu describing this option
711    tag       = C string to be passed to the plugin when this option is used
712    mandatory = TRUE  (1)  if this option is always passed to the plugin
713                FALSE (0)  if the user may or may not select this option
714                MAYBE (-1) if it is to be turned on, but it can be turned off
715 -----------------------------------------------------------------------------*/
716 
add_option_to_PLUGIN_interface(PLUGIN_interface * plint,char * label,char * tag,int mandatory)717 void add_option_to_PLUGIN_interface( PLUGIN_interface * plint ,
718                                      char * label , char * tag , int mandatory )
719 {
720    int nopt , isv ;
721    PLUGIN_option * opt ;
722 
723 ENTRY("add_option_to_PLUGIN_interface") ;
724 
725    /*-- sanity check --*/
726 
727    if( plint == NULL ) EXRETURN ;
728    if( plint->call_method == PLUGIN_CALL_IMMEDIATELY ) EXRETURN ;
729 
730    if( label == NULL ) label = EMPTY_STRING ;
731    if( tag   == NULL ) tag   = EMPTY_STRING ;
732 
733    /*-- create space for new option --*/
734 
735    nopt = plint->option_count ;
736    plint->option = (PLUGIN_option **)
737                      XtRealloc( (char *) plint->option ,
738                                 sizeof(PLUGIN_option *) * (nopt+1) ) ;
739 
740    plint->option[nopt] = opt = (PLUGIN_option *)XtMalloc(sizeof(PLUGIN_option));
741    memset(opt, 0, sizeof(PLUGIN_option)) ; /* 11 Feb 2009 [lesstif patrol] */
742 
743    /*-- put values in new option --*/
744 
745    PLUGIN_LABEL_strcpy( opt->label , label ) ;
746    MCW_strncpy( opt->tag , tag , PLUGIN_STRING_SIZE ) ;
747 
748    opt->mandatory      = mandatory ;
749    opt->subvalue_count = 0 ;
750 
751    opt->hint = NULL ;
752    for( isv=0 ; isv < PLUGIN_MAX_SUBVALUES ; isv++ )
753       opt->subvalue[isv].hint = NULL ;
754 
755    (plint->option_count)++ ;  /* one more option */
756 
757 #if 0
758 {int qq; fprintf(stderr,"Option tags thus far:\n");
759  for(qq=0;qq<plint->option_count;qq++)
760    fprintf(stderr," %s",plint->option[qq]->tag) ;
761  fprintf(stderr,"\n"); }
762 #endif
763 
764    EXRETURN ;
765 }
766 
767 /*-------------------------------------------------------------------------
768   Add a hint to the most recently created interface item
769 ---------------------------------------------------------------------------*/
770 
PLUTO_add_hint(PLUGIN_interface * plint,char * hh)771 void PLUTO_add_hint( PLUGIN_interface * plint , char * hh )
772 {
773    int nopt , nsv ;
774    PLUGIN_option * opt ;
775    PLUGIN_subvalue * sv ;
776 
777 ENTRY("PLUTO_add_hint") ;
778 
779    if( plint == NULL || hh == NULL ) EXRETURN ;
780 
781    nopt = plint->option_count - 1 ;
782    if( nopt < 0 ){                  /* no options yet, so hint is global */
783       myXtFree(plint->hint) ;
784       plint->hint = XtNewString(hh) ;
785       EXRETURN ;
786    }
787 
788    opt  = plint->option[nopt] ;     /* latest option line */
789    nsv  = opt->subvalue_count ;     /* number of subvalues on it */
790 
791    if( nsv == 0 ){                  /* no subvalues yet */
792       myXtFree(opt->hint) ;         /* so put hint on the option line */
793       opt->hint = XtNewString(hh) ;
794    } else {                         /* add hint to last subvalue */
795       sv = &(opt->subvalue[nsv-1]) ;
796       myXtFree(sv->hint) ;
797       sv->hint = XtNewString(hh) ;
798 
799 #if 0
800 if(PRINT_TRACING)
801 { char str[256] ; sprintf(str,"%s: %s hint=%s",
802                           plint->label,sv->label,sv->hint) ; STATUS(str) ; }
803 #endif
804 
805    }
806 
807    EXRETURN ;
808 }
809 
810 /*-------------------------------------------------------------------------
811    Routine to add a number-type "chooser" to the most recently created
812    option within a plugin interface.  "Numbers" are always passed to
813    the plugin in float format, but are specified here using an
814    integer range with a decimal shift, sort of like the Motif Scale Widget.
815 
816    label     = C string to go in the menu, next to the "chooser" for
817                the integer.
818 
819    bot, top, = Smallest and largest integer values allowed in the chooser.
820    decim     = Number of decimals to shift to left for display of value.
821                For example, bot=1 top=100 with decim=2 will actually
822                specify a range of 0.01 to 1.00.  One function of decim
823                is simply to set the increments between values in the
824                chooser.  With decim=2, the increment is 0.01.
825 
826    defval    = Integer value for the default.  For example, if decim=2,
827                and defval=43, then the floating point default value
828                (as it appears to the user) is actually 0.43.
829 
830    editable  = TRUE (1) if the user will be allowed to type in any
831                  value in the chooser.  For example, this would allow
832                  the input of 0.43721.
833                FALSE (0) if the user is restricted to the range of
834                  values given by bot/10**decim to top/10**decim,
835                  in steps of 1/10**decim.
836 ---------------------------------------------------------------------------*/
837 
add_number_to_PLUGIN_interface(PLUGIN_interface * plint,char * label,int bot,int top,int decim,int defval,int editable)838 void add_number_to_PLUGIN_interface( PLUGIN_interface * plint ,
839                                      char * label ,
840                                      int bot , int top , int decim ,
841                                      int defval , int editable     )
842 {
843    int nopt , nsv ;
844    PLUGIN_option * opt ;
845    PLUGIN_subvalue * sv ;
846 
847    /*-- sanity check --*/
848 
849 ENTRY("add_number_to_PLUGIN_interface") ;
850 
851    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
852 
853    if( label == NULL ) label = EMPTY_STRING ;
854 
855    nopt = plint->option_count - 1 ;
856    opt  = plint->option[nopt] ;
857 
858    nsv = opt->subvalue_count ;
859    if( nsv == PLUGIN_MAX_SUBVALUES ){
860       fprintf(stderr,"*** Warning: maximum plugin subvalue count exceeded!\n");
861       EXRETURN ;
862    }
863 
864    /*-- load values into next subvalue --*/
865 
866    sv = &(opt->subvalue[nsv]) ;
867 
868    sv->data_type = PLUGIN_NUMBER_TYPE ;
869    PLUGIN_LABEL_strcpy( sv->label , label ) ;
870 
871    sv->int_range_bot   = bot ;
872    sv->int_range_top   = top ;
873    sv->int_range_decim = decim ;
874    sv->value_default   = defval ;
875    sv->editable        = editable ;
876 
877    (opt->subvalue_count)++ ;
878    EXRETURN ;
879 }
880 
881 /*-------------------------------------------------------------------
882    Routine to add a string-type "chooser" to the most recently created
883    option within a plugin interface.
884 
885    label     = C string to go in the menu, next to the "chooser" for
886                the string.
887 
888    num_str   = Count of the number of strings provided in strlist.
889    strlist   = strlist[i] is a pointer to the i'th string value
890                that the user is to choose from, for i=0...num_str-1.
891 
892    defval    = If num_str > 0:
893                  Integer from 0...num_str-1 indicating which string
894                  in strlist is the default value.
895                If num_str == 0:
896                  Gives width of field supplied for string input.
897 
898    Note that if num_str is <= 0, then instead of being presented with
899    a menu of fixed strings, the user will have to type in a string.
900 ---------------------------------------------------------------------*/
901 
add_string_to_PLUGIN_interface(PLUGIN_interface * plint,char * label,int num_str,char ** strlist,int defval)902 void add_string_to_PLUGIN_interface( PLUGIN_interface * plint ,
903                                      char * label ,
904                                      int num_str , char ** strlist ,
905                                      int defval )
906 {
907    int nopt , nsv , ii ;
908    PLUGIN_option * opt ;
909    PLUGIN_subvalue * sv ;
910 
911 ENTRY("add_string_to_PLUGIN_interface") ;
912 
913    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
914 
915    if( label == NULL ) label = EMPTY_STRING ;
916 
917    nopt = plint->option_count - 1 ;
918    opt  = plint->option[nopt] ;
919 
920    nsv = opt->subvalue_count ;
921    if( nsv == PLUGIN_MAX_SUBVALUES ){
922       fprintf(stderr,"*** Warning: maximum plugin subvalue count exceeded!\n");
923       EXRETURN ;
924    }
925 
926    /*-- load values into next subvalue --*/
927 
928    sv = &(opt->subvalue[nsv]) ;
929 
930    sv->data_type = PLUGIN_STRING_TYPE ;
931    PLUGIN_LABEL_strcpy( sv->label , label ) ;
932 
933    if( num_str > 0 ){
934       sv->string_range_count = num_str ;
935       if( num_str > PLUGIN_MAX_STRING_RANGE )
936         ERROR_message("num_str=%d > %d :(",num_str,PLUGIN_MAX_STRING_RANGE) ;
937       for( ii=0 ; ii < num_str ; ii++ ){
938          sv->string_range[ii] = (char*)XtMalloc( PLUGIN_STRING_SIZE ) ;
939          MCW_strncpy( sv->string_range[ii] , strlist[ii] , PLUGIN_STRING_SIZE ) ;
940       }
941       sv->value_default   = defval ;
942       sv->editable        = FALSE ;
943    } else {
944       sv->string_range_count = 0 ;
945       sv->editable           = TRUE ;
946       sv->value_default      = defval ;
947 
948       if( strlist != NULL && strlist[0] != NULL ){     /* 19 Jun 2000 */
949          sv->string_range_count = -1 ;
950          sv->string_range[0] = (char*)XtMalloc( PLUGIN_STRING_SIZE ) ;
951          MCW_strncpy( sv->string_range[0], strlist[0], PLUGIN_STRING_SIZE ) ;
952       }
953    }
954 
955    (opt->subvalue_count)++ ;
956    EXRETURN ;
957 }
958 
959 /*-----------------------------------------------------------------------
960    Routine to add a dataset "chooser" to the most recently created
961    option within a plugin interface.
962 
963    label = C string to go in the menu, next to the "chooser" for
964            the dataset.
965 
966    The _mask inputs are bitwise ORs (|) of dataset type masks.
967    These are used to specify the types of datasets that can be
968    passed to the plugin.  The first two _mask inputs below cannot both
969    be zero (for then no dataset would be allowed into the plugin!).
970 
971    anat_mask = Chosen from the list in 3ddata.h, which is currently
972                    ANAT_SPGR_MASK   ANAT_FSE_MASK   ANAT_EPI_MASK
973                    ANAT_MRAN_MASK   ANAT_CT_MASK    ANAT_SPECT_MASK
974                    ANAT_PET_MASK    ANAT_MRA_MASK   ANAT_BMAP_MASK
975                    ANAT_DIFF_MASK   ANAT_OMRI_MASK
976                and ANAT_ALL_MASK, which will allow any anatomical
977                dataset.  Entering 0 for this mask will mean that
978                no anatomical datasets will be choosable.
979 
980    func_mask = Similar mask for functional dataset types, chosen from
981                   FUNC_FIM_MASK   FUNC_THR_MASK
982                   FUNC_COR_MASK   FUNC_TT_MASK
983                and FUNC_ALL_MASK, which will allow any functional
984                dataset.  Entering 0 for this mask will mean that
985                no functional datasets will be choosable.
986 
987    ctrl_mask = An additional mask to specify further exactly which
988                  datasets should be choosable.  Mask options are:
989 
990                SESSION_ALL_MASK    = If this is set, then the choice of
991                                      datasets will be drawn from all
992                                      sessions now loaded into AFNI.
993                                    * By default, only the "current"
994                                      session will be included.
995 
996                DIMEN_3D_MASK       = Masks that define whether 3D and/or
997                DIMEN_4D_MASK         3D+time (4D) datasets are allowable.
998                DIMEN_ALL_MASK
999 
1000                WARP_ON_DEMAND_MASK = If this is set, then datasets that may
1001                                      not have a BRIK file will be included
1002                                      in the list of datasets to choose from.
1003                                      In this case, the plugin must be ready
1004                                      to deal with the warp-on-demand routines
1005                                      that return one slice at a time.
1006                                    * By default, only datasets with actual
1007                                      BRIKs will be included.
1008 
1009                BRICK_BYTE_MASK     = Masks that define what type of data
1010                BRICK_SHORT_MASK      should be stored in the sub-bricks
1011                BRICK_FLOAT_MASK      of the allowable datasets.
1012                BRICK_COMPLEX_MASK
1013                BRICK_RGB_MASK
1014                BRICK_ALLTYPE_MASK
1015                BRICK_ALLREAL_MASK
1016 
1017                *  Note that entering 0 for ctrl_mask means that no   *
1018                *  datasets will be choosable.  At the least, one of  *
1019                *  the DIMEN_ masks must be chosen, and one of the    *
1020                *  BRICK_ masks must be chosen.                       *
1021 -------------------------------------------------------------------------*/
1022 
add_dataset_to_PLUGIN_interface(PLUGIN_interface * plint,char * label,int anat_mask,int func_mask,int ctrl_mask)1023 void add_dataset_to_PLUGIN_interface( PLUGIN_interface * plint ,
1024                                       char * label ,
1025                                       int anat_mask , int func_mask , int ctrl_mask )
1026 {
1027    int nopt , nsv , ii ;
1028    PLUGIN_option * opt ;
1029    PLUGIN_subvalue * sv ;
1030 
1031 ENTRY("add_dataset_to_PLUGIN_interface") ;
1032 
1033    /*-- sanity checks --*/
1034 
1035    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
1036    if( anat_mask == 0 && func_mask == 0 ) EXRETURN ;
1037 
1038    if( label == NULL ) label = EMPTY_STRING ;
1039 
1040    if( (ctrl_mask & BRICK_ALLTYPE_MASK)==0 ||
1041        (ctrl_mask & DIMEN_ALL_MASK)    ==0   ) EXRETURN ;
1042 
1043    nopt = plint->option_count - 1 ;
1044    opt  = plint->option[nopt] ;
1045 
1046    nsv = opt->subvalue_count ;
1047    if( nsv == PLUGIN_MAX_SUBVALUES ){
1048       fprintf(stderr,"*** Warning: maximum plugin subvalue count exceeded!\n");
1049       EXRETURN ;
1050    }
1051 
1052    /*-- load values into next subvalue --*/
1053 
1054    sv = &(opt->subvalue[nsv]) ;
1055 
1056    sv->data_type = PLUGIN_DATASET_TYPE ;
1057    PLUGIN_LABEL_strcpy( sv->label , label ) ;
1058 
1059    sv->dset_anat_mask = anat_mask ;
1060    sv->dset_func_mask = func_mask ;
1061    sv->dset_ctrl_mask = ctrl_mask ;
1062 
1063    (opt->subvalue_count)++ ;
1064    EXRETURN ;
1065 }
1066 
add_dataset_list_to_PLUGIN_interface(PLUGIN_interface * plint,char * label,int anat_mask,int func_mask,int ctrl_mask)1067 void add_dataset_list_to_PLUGIN_interface( PLUGIN_interface * plint ,
1068                                            char * label ,
1069                                            int anat_mask , int func_mask , int ctrl_mask )
1070 {
1071    int nopt , nsv , ii ;
1072    PLUGIN_option * opt ;
1073    PLUGIN_subvalue * sv ;
1074 
1075 ENTRY("add_dataset_list_to_PLUGIN_interface") ;
1076 
1077    /*-- sanity checks --*/
1078 
1079    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
1080    if( anat_mask == 0 && func_mask == 0 ) EXRETURN ;
1081 
1082    if( label == NULL ) label = EMPTY_STRING ;
1083 
1084    if( (ctrl_mask & BRICK_ALLTYPE_MASK)==0 ||
1085        (ctrl_mask & DIMEN_ALL_MASK)    ==0   ) EXRETURN ;
1086 
1087    nopt = plint->option_count - 1 ;
1088    opt  = plint->option[nopt] ;
1089 
1090    nsv = opt->subvalue_count ;
1091    if( nsv == PLUGIN_MAX_SUBVALUES ){
1092       fprintf(stderr,"*** Warning: maximum plugin subvalue count exceeded!\n");
1093       EXRETURN ;
1094    }
1095 
1096    /*-- load values into next subvalue --*/
1097 
1098    sv = &(opt->subvalue[nsv]) ;
1099 
1100    sv->data_type = PLUGIN_DATASET_LIST_TYPE ;
1101    PLUGIN_LABEL_strcpy( sv->label , label ) ;
1102 
1103    sv->dset_anat_mask = anat_mask ;
1104    sv->dset_func_mask = func_mask ;
1105    sv->dset_ctrl_mask = ctrl_mask ;
1106 
1107    (opt->subvalue_count)++ ;
1108    EXRETURN ;
1109 }
1110 
1111 /*-----------------------------------------------------------------------
1112    Routine to add a timeseries "chooser" to the most recently created
1113    option within a plugin interface.
1114 
1115    label = C string to go in the menu, next to the "chooser" for
1116            the dataset.
1117 -------------------------------------------------------------------------*/
1118 
add_timeseries_to_PLUGIN_interface(PLUGIN_interface * plint,char * label)1119 void add_timeseries_to_PLUGIN_interface( PLUGIN_interface * plint, char * label )
1120 {
1121    int nopt , nsv , ii ;
1122    PLUGIN_option * opt ;
1123    PLUGIN_subvalue * sv ;
1124 
1125 ENTRY("add_timeseries_to_PLUGIN_interface") ;
1126 
1127    /*-- sanity checks --*/
1128 
1129    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
1130 
1131    if( label == NULL ) label = EMPTY_STRING ;
1132 
1133    nopt = plint->option_count - 1 ;
1134    opt  = plint->option[nopt] ;
1135 
1136    nsv = opt->subvalue_count ;
1137    if( nsv == PLUGIN_MAX_SUBVALUES ){
1138       fprintf(stderr,"*** Warning: maximum plugin subvalue count exceeded!\n");
1139       EXRETURN ;
1140    }
1141 
1142    /*-- load values into next subvalue --*/
1143 
1144    sv = &(opt->subvalue[nsv]) ;
1145 
1146    sv->data_type = PLUGIN_TIMESERIES_TYPE ;
1147    PLUGIN_LABEL_strcpy( sv->label , label ) ;
1148 
1149    (opt->subvalue_count)++ ;
1150    EXRETURN ;
1151 }
1152 
1153 /*-----------------------------------------------------------------------
1154    Routine to add a *.[tc]sv "chooser" to the most recently created
1155    option within a plugin interface.
1156 
1157    label = C string to go in the menu, next to the "chooser" for
1158            the dataset.
1159 -------------------------------------------------------------------------*/
1160 
add_tcsv_to_PLUGIN_interface(PLUGIN_interface * plint,char * label)1161 void add_tcsv_to_PLUGIN_interface( PLUGIN_interface * plint, char * label )
1162 {
1163    int nopt , nsv , ii ;
1164    PLUGIN_option * opt ;
1165    PLUGIN_subvalue * sv ;
1166 
1167 ENTRY("add_tcsv_to_PLUGIN_interface") ;
1168 
1169    /*-- sanity checks --*/
1170 
1171    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
1172 
1173    if( label == NULL ) label = EMPTY_STRING ;
1174 
1175    nopt = plint->option_count - 1 ;
1176    opt  = plint->option[nopt] ;
1177 
1178    nsv = opt->subvalue_count ;
1179    if( nsv == PLUGIN_MAX_SUBVALUES ){
1180       fprintf(stderr,"*** Warning: maximum plugin subvalue count exceeded!\n");
1181       EXRETURN ;
1182    }
1183 
1184    /*-- load values into next subvalue --*/
1185 
1186    sv = &(opt->subvalue[nsv]) ;
1187 
1188    sv->data_type = PLUGIN_TCSV_TYPE ;
1189    PLUGIN_LABEL_strcpy( sv->label , label ) ;
1190 
1191    (opt->subvalue_count)++ ;
1192    EXRETURN ;
1193 }
1194 
1195 /*-----------------------------------------------------------------------*/
1196 
1197 static int initcolorindex=1 ;
PLUTO_set_initcolorindex(int i)1198 void PLUTO_set_initcolorindex( int i ){ initcolorindex = i; } /* 10 Oct 2007 */
1199 
1200 /*-----------------------------------------------------------------------
1201    Routine to add a color overlay  "chooser" to the most recently
1202    created option within a plugin interface -- 11 Jul 2001 - RWCox.
1203 
1204    label = C string to go in the menu, next to the "chooser" for
1205            the color.
1206 -------------------------------------------------------------------------*/
1207 
add_overlaycolor_to_PLUGIN_interface(PLUGIN_interface * plint,char * label)1208 void add_overlaycolor_to_PLUGIN_interface( PLUGIN_interface *plint, char *label )
1209 {
1210    int nopt , nsv , ii ;
1211    PLUGIN_option *opt ;
1212    PLUGIN_subvalue *sv ;
1213 
1214 ENTRY("add_overlaycolor_to_PLUGIN_interface") ;
1215 
1216    /*-- sanity checks --*/
1217 
1218    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
1219 
1220    if( label == NULL ) label = EMPTY_STRING ;
1221 
1222    nopt = plint->option_count - 1 ;
1223    opt  = plint->option[nopt] ;
1224 
1225    nsv = opt->subvalue_count ;
1226    if( nsv == PLUGIN_MAX_SUBVALUES ){
1227      WARNING_message("maximum plugin subvalue count exceeded - overlaycolor");
1228      EXRETURN ;
1229    }
1230 
1231    /*-- load values into next subvalue --*/
1232 
1233    sv = &(opt->subvalue[nsv]) ;
1234 
1235    sv->data_type = PLUGIN_OVERLAY_COLOR_TYPE ;
1236    PLUGIN_LABEL_strcpy( sv->label , label ) ;
1237    sv->value_default = initcolorindex ;
1238 
1239    (opt->subvalue_count)++ ;
1240    EXRETURN ;
1241 }
1242 
1243 /*--------------------------------------------------------------------------*/
1244 
PLUG_nonblank_len(char * str)1245 int PLUG_nonblank_len( char *str )
1246 {
1247    int ii , ll ;
1248 
1249    if( str == NULL || *str == '\0' ) return 0 ;
1250    ll = strlen(str) ;
1251 
1252    for( ii=ll-1 ; ii >= 0 ; ii-- ) if( !isspace(str[ii]) ) break ;
1253 
1254    return (ii+1) ;
1255 }
1256 
1257 /*--------------------------------------------------------------------------
1258   Decide if a dataset prefix is OK.  The string itself is checked for
1259   legality, then the list of all datasets is checked for duplicates.
1260 ----------------------------------------------------------------------------*/
1261 
PLUTO_prefix_ok(char * str)1262 int PLUTO_prefix_ok( char *str )
1263 {
1264    int ll , ii ;
1265    THD_slist_find find ;
1266 
1267 ENTRY("PLUTO_prefix_ok") ;
1268 
1269    /*--- check the string itself for OK-osity ---*/
1270 
1271    if( str == NULL ) RETURN(0) ;
1272    ll = strlen( str ) ; if( ll == 0 ) RETURN(0) ;
1273 
1274    for( ii=0 ; ii < ll ; ii++ )
1275       if( iscntrl(str[ii]) || isspace(str[ii]) ||
1276           str[ii] == '/'   || str[ii] == ';'   ||
1277           str[ii] == '*'   || str[ii] == '?'   ||
1278           str[ii] == '&'   || str[ii] == '|'   ||
1279           str[ii] == '"'   || str[ii] == '>'   ||
1280           str[ii] == '<'   || str[ii] == '\''  ||
1281           str[ii] == '['   || str[ii] == ']'     ) RETURN(0) ;
1282 
1283    /*--- now see if the prefix already exists in AFNI ---*/
1284 
1285    find = THD_dset_in_sessionlist( FIND_PREFIX , str ,
1286                                    GLOBAL_library.sslist , -1 ) ;
1287 
1288    RETURN(find.dset == NULL) ;
1289 }
1290 
1291 /*------------------------------------------------------------------------------
1292   Routine to create (but not map) the widgets for a plugin interface.
1293 --------------------------------------------------------------------------------*/
1294 
1295 /***** definitions for the action area controls *****/
1296 
1297 #define PLUG_quit_label   "Quit"
1298 #define PLUG_run_label    "Run+Keep"
1299 #define PLUG_doit_label   "Run+Close"
1300 #define PLUG_help_label   "Help"
1301 
1302 #define PLUG_quit_help   "Press to close\nthis panel without\nrunning program."
1303 #define PLUG_run_help    "Press to run\nthe program\nand keep panel open."
1304 #define PLUG_doit_help   "Press to run\nthe program\nand close this panel."
1305 #define PLUG_help_help   "Press to get\nthe help for\nthis program."
1306 
1307 #define NUM_PLUG_ACT 4
1308 
1309 static MCW_action_item PLUG_act[] = {
1310  { PLUG_quit_label, PLUG_action_CB, NULL, PLUG_quit_help,"Close window"               , 0 },
1311  { PLUG_run_label , PLUG_action_CB, NULL, PLUG_run_help ,"Run plugin and keep window" , 0 },
1312  { PLUG_doit_label, PLUG_action_CB, NULL, PLUG_doit_help,"Run plugin and close window", 1 },
1313  { PLUG_help_label, PLUG_action_CB, NULL, PLUG_help_help,"Get help for plugin"        , 0 }
1314 } ;
1315 
PLUG_setup_widgets(PLUGIN_interface * plint,MCW_DC * dc)1316 void PLUG_setup_widgets( PLUGIN_interface * plint , MCW_DC * dc )
1317 {
1318    int iopt , ib , max_nsv , ww,hh , shh , toff , zlen ;
1319    XmString xstr ;
1320    char str[256] ;
1321    PLUGIN_widgets * wid ;
1322    PLUGIN_option_widgets ** opwid ;
1323    PLUGIN_option_widgets * ow ;
1324    PLUGIN_option * opt ;
1325    PLUGIN_subvalue * sv ;
1326    Widget actar , wframe , separator = NULL ;
1327    int opt_lwid , sv_lwid[PLUGIN_MAX_SUBVALUES] ;
1328    Widget widest_chooser[PLUGIN_MAX_SUBVALUES] ;
1329    int    widest_width[PLUGIN_MAX_SUBVALUES] ;
1330    Pixel  fg_pix=0 ;
1331 
1332 ENTRY("PLUG_setup_widgets") ;
1333 
1334    /**** sanity checks ****/
1335 
1336 STATUS("check plint") ;
1337    if( plint      == NULL ) EXRETURN ;
1338 STATUS("check plint->wid") ;
1339    if( plint->wid != NULL ) EXRETURN ;
1340 STATUS("check plint->call_method") ;
1341    if( plint->call_method == PLUGIN_CALL_IMMEDIATELY ) EXRETURN ;
1342 
1343    /**** create widgets structure ****/
1344 
1345 STATUS("create widget structure") ;
1346    plint->wid = wid = myXtNew(PLUGIN_widgets) ;
1347 
1348    /**** create Shell that can be opened up later ****/
1349    /* 'LessTif Widormous'
1350       With 64bit LessTif, some widgets get created with
1351       enormous sizes. To complicate matters, the problem
1352       occurred randomly so tracking it is a frustrating
1353       exercise. It looks like adding a few, harmless,
1354       XmNheight and XmNwidth parameters at widget creation
1355       fixed the problem. Those parameters have no effect
1356       on the final plugin's look so we won't bother to find
1357       out which of them was necessary for fixing the problem.
1358                   12 Feb 2009 9Lesstif patrol]
1359    */
1360 STATUS("create shell") ;
1361    wid->shell =
1362       XtVaAppCreateShell(
1363            "AFNI" , "AFNI" , topLevelShellWidgetClass , dc->display ,
1364 
1365            XmNtitle             , plint->label , /* top of window */
1366            XmNiconName          , plint->label , /* label on icon */
1367            XmNmappedWhenManaged , False ,        /* must map it manually */
1368            XmNdeleteResponse    , XmDO_NOTHING , /* deletion handled below */
1369            XmNallowShellResize  , False ,        /* let code resize shell? */
1370            XmNinitialResourcesPersistent , False ,
1371                XmNheight, 207, /* See 'LessTif Widormous' comment above */
1372                XmNwidth, 206,  /*         12 Feb 2009 9Lesstif patrol] */
1373            XmNkeyboardFocusPolicy , XmEXPLICIT ,
1374       NULL ) ;
1375 
1376    DC_yokify( wid->shell , dc ) ; /* 14 Sep 1998 */
1377 
1378    if( afni48_good )
1379       XtVaSetValues( wid->shell ,
1380                         XmNiconPixmap , afni48_pixmap ,
1381                      NULL ) ;
1382 
1383    if( MCW_isitmwm(wid->shell) )
1384       XtVaSetValues( wid->shell ,
1385                         XmNmwmDecorations , MWM_DECOR_ALL | MWM_DECOR_MAXIMIZE ,
1386                      NULL ) ;
1387 
1388    XmAddWMProtocolCallback(           /* make "Close" window menu work */
1389            wid->shell ,
1390            XmInternAtom( dc->display , "WM_DELETE_WINDOW" , False ) ,
1391            PLUG_delete_window_CB , (XtPointer) plint ) ;
1392 
1393    /**** create Form to hold all widgets ****/
1394 
1395 STATUS("create Form") ;
1396    wid->form = XtVaCreateWidget(
1397                  "AFNI" , xmFormWidgetClass , wid->shell ,
1398                      XmNborderWidth , 0 ,
1399                      XmNborderColor , 0 ,
1400                         XmNwidth, 70,/* See 'LessTif Widormous' comment above */
1401                         XmNheight, 100,/*         12 Feb 2009 9Lesstif patrol] */
1402                      XmNtraversalOn , True  ,
1403                      XmNinitialResourcesPersistent , False ,
1404                  NULL ) ;
1405 
1406    /**** create Label at top to hold description of this program ****/
1407 
1408    if( plint->toplabel[0] == '\0' )
1409      sprintf( str , "AFNI Plugin: %s" , plint->description ) ;
1410    else
1411      strcpy( str , plint->toplabel ) ;  /* 13 May 2010 */
1412 
1413 STATUS("Create Label") ;
1414    xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
1415    wid->label =
1416       XtVaCreateManagedWidget(
1417         "AFNI" , xmLabelWidgetClass ,  wid->form ,
1418            XmNlabelString , xstr ,
1419            XmNalignment  , XmALIGNMENT_CENTER ,
1420 
1421            XmNleftAttachment , XmATTACH_FORM ,
1422            XmNrightAttachment, XmATTACH_FORM ,
1423            XmNtopAttachment  , XmATTACH_FORM ,
1424            XmNtopOffset      , 5 ,
1425                XmNheight, 20, /* See 'LessTif Widormous' comment above */
1426                XmNwidth, 20, /*         12 Feb 2009 9Lesstif patrol] */
1427            XmNinitialResourcesPersistent , False ,
1428         NULL ) ;
1429     XmStringFree( xstr ) ; LABELIZE(wid->label) ;
1430 
1431     /* now that we have the label,
1432        find its sizes and make sure the shell doesn't get too small */
1433 
1434     MCW_widget_geom( wid->label , &ww , &hh , NULL , NULL ) ;
1435     XtVaSetValues( wid->shell ,
1436                       XmNminWidth  , ww+3*hh ,
1437                       XmNminHeight , (plint->option_count == 0) ? 5*hh : 7*hh ,
1438                    NULL ) ;
1439 
1440    /**** create an action area beneath to hold user control buttons ****/
1441 
1442    for( ib=0 ; ib < NUM_PLUG_ACT ; ib++ )
1443      PLUG_act[ib].data = (XtPointer) plint ;
1444 
1445    /* 04 Nov 2003: allow for change of Run+Close and Run+Keep labels */
1446 
1447    if( plint->run_label[0]  == '\0' ) strcpy(plint->run_label ,PLUG_run_label );
1448    if( plint->doit_label[0] == '\0' ) strcpy(plint->doit_label,PLUG_doit_label);
1449    PLUG_act[1].label = plint->run_label ;
1450    PLUG_act[2].label = plint->doit_label;
1451 
1452    actar = MCW_action_area( wid->form , PLUG_act ,
1453                             (plint->helpstring!=NULL) ? NUM_PLUG_ACT
1454                                                       : NUM_PLUG_ACT-1 ) ;
1455 
1456    XtVaSetValues( actar ,
1457                      XmNleftAttachment , XmATTACH_FORM ,
1458                      XmNrightAttachment, XmATTACH_FORM ,
1459                      XmNtopAttachment  , XmATTACH_WIDGET ,
1460                      XmNtopWidget      , wid->label ,
1461                      XmNtopOffset      , 7 ,
1462                   NULL ) ;
1463 
1464    /**** create a Scrolled Window and Form to hold
1465          the user input option widgets, if they will be needed ****/
1466 
1467    if( plint->option_count > 0 ){
1468 STATUS("create ScrolledWindow") ;
1469       wid->scrollw =
1470          XtVaCreateWidget(
1471            "AFNI" , xmScrolledWindowWidgetClass ,  wid->form ,
1472               XmNscrollingPolicy , XmAUTOMATIC ,
1473               XmNwidth  , ww+2*hh ,
1474               XmNheight ,    3*hh ,
1475               XmNleftAttachment  , XmATTACH_FORM ,
1476               XmNrightAttachment , XmATTACH_FORM ,
1477               XmNtopAttachment   , XmATTACH_WIDGET ,
1478               XmNbottomAttachment, XmATTACH_FORM ,
1479               XmNtopWidget       , actar ,
1480               XmNtopOffset       , 7 ,
1481               XmNtraversalOn , True  ,
1482               XmNinitialResourcesPersistent , False ,
1483            NULL ) ;
1484 
1485       wframe =
1486          XtVaCreateWidget(
1487            "AFNI" , xmFrameWidgetClass , wid->scrollw ,
1488                XmNshadowType , XmSHADOW_ETCHED_IN ,
1489                XmNshadowThickness , 5 ,
1490                XmNtraversalOn , True  ,
1491                XmNinitialResourcesPersistent , False ,
1492             NULL ) ;
1493 
1494       wid->workwin =
1495          XtVaCreateWidget(
1496            "AFNI" , xmFormWidgetClass , wframe ,
1497               XmNborderWidth , 0 ,
1498               XmNborderColor , 0 ,
1499               XmNtraversalOn , True  ,
1500               XmNinitialResourcesPersistent , False ,
1501            NULL ) ;
1502 
1503       wid->opwid = opwid =
1504              (PLUGIN_option_widgets **)
1505                 XtMalloc(sizeof(PLUGIN_option_widgets *) * plint->option_count) ;
1506 
1507       /** setup widest widgets for each column of the Form **/
1508 
1509       for( ib=0 ; ib < PLUGIN_MAX_SUBVALUES ; ib++ ){
1510          widest_chooser[ib] = NULL ;
1511          widest_width[ib]   = 0 ;
1512       }
1513 
1514       XtVaGetValues( wframe , XmNforeground , &fg_pix , NULL ) ;
1515 
1516    } else {
1517       wframe = wid->scrollw = wid->workwin = NULL ;
1518       opwid = NULL ;
1519    }
1520 
1521    /**** for each column within each option, find the max string width ****/
1522 
1523    opt_lwid = 1 ;
1524    for( ib=0 ; ib < PLUGIN_MAX_SUBVALUES ; ib++ ) sv_lwid[ib] = 1 ;
1525 
1526    for( iopt=0 ; iopt < plint->option_count ; iopt++ ){
1527       opt = plint->option[iopt] ;
1528       if( opt == NULL ) continue ; /* bad? */
1529 
1530       opt_lwid = MAX( opt_lwid , PLUG_nonblank_len(opt->label) ) ;
1531       for( ib=0 ; ib < opt->subvalue_count ; ib++ ){
1532          sv = &(opt->subvalue[ib]) ;
1533          sv_lwid[ib] = MAX( sv_lwid[ib] , PLUG_nonblank_len(sv->label) ) ;
1534       }
1535    }
1536 
1537    /**** now clip each label string to its column's width ****/
1538 
1539    for( iopt=0 ; iopt < plint->option_count ; iopt++ ){
1540       opt = plint->option[iopt] ;
1541       if( opt == NULL ) continue ; /* bad? */
1542 
1543 #define LPAD 0   /* 29 Mar 2002: used to be 1 */
1544 
1545       opt->label[ opt_lwid + LPAD ] = '\0' ;
1546       for( ib=0 ; ib < opt->subvalue_count ; ib++ ){
1547          sv = &(opt->subvalue[ib]) ;
1548          sv->label[ sv_lwid[ib] + LPAD ] = '\0' ;
1549       }
1550    }
1551 
1552    /**** create a row of Widgets for each option ****/
1553 
1554    for( iopt=0 ; iopt < plint->option_count ; iopt++ ){
1555       opt = plint->option[iopt] ;
1556       if( opt == NULL ) continue ; /* bad? */
1557 
1558       ow = opwid[iopt] = myXtNew(PLUGIN_option_widgets) ;
1559 
1560       for( ib=0 ; ib < PLUGIN_MAX_SUBVALUES ; ib++ ){  /* initialize */
1561          ow->chooser[ib]      = NULL ;                 /* all subvalue */
1562          ow->chtop[ib]        = NULL ;                 /* stuff */
1563          ow->chooser_type[ib] = OP_CHOOSER_NONE ;
1564          opt->callvalue[ib]   = NULL ;
1565       }
1566 
1567       /** create ToggleButton to indicate whether this is used **/
1568 
1569 STATUS("create ToggleButton for row") ;
1570       ow->toggle =
1571          XtVaCreateManagedWidget(
1572            "AFNI" , xmToggleButtonWidgetClass , wid->workwin ,
1573               XmNleftAttachment   , XmATTACH_FORM ,
1574               XmNtopAttachment    , (iopt==0) ? XmATTACH_FORM     /* first row */
1575                                               : XmATTACH_WIDGET , /* 2nd+ row */
1576               XmNtopOffset        , 1 ,
1577               XmNleftOffset       , 1 ,
1578               XmNtopWidget        , separator ,  /* 2nd+ row */
1579 
1580               XmNlabelType        , XmPIXMAP ,             /* No label attached */
1581               XmNlabelPixmap      , XmUNSPECIFIED_PIXMAP , /* Just the toggle!  */
1582 
1583               XmNset              , (opt->mandatory != FALSE) ? True  : False ,
1584               XmNsensitive        , (opt->mandatory == TRUE ) ? False : True  ,
1585 
1586               XmNindicatorSize    , hh-1 ,
1587               XmNmarginHeight     , 0  ,
1588               XmNmarginWidth      , 0  ,
1589               XmNselectColor      , fg_pix ,  /* fill with foreground when set */
1590                XmNheight, 20,
1591                XmNwidth, 20,
1592               XmNtraversalOn , True  ,
1593               XmNinitialResourcesPersistent , False ,
1594            NULL ) ;
1595 
1596       MCW_register_help( ow->toggle ,
1597                          "When pressed in and filled,\n"
1598                          "this button denotes that this\n"
1599                          "line of input will be passed\n"
1600                          "to the plugin.  If the plugin\n"
1601                          "has specified that this line\n"
1602                          "is required, then you cannot\n"
1603                          "toggle this button off."
1604                        ) ;
1605 
1606       if( opt->mandatory == TRUE )
1607          MCW_register_hint( ow->toggle ,
1608                             "This input line is mandatory" ) ;
1609       else
1610          MCW_register_hint( ow->toggle ,
1611                             "IN: this input line sent to plugin" ) ;
1612 
1613       /* this callback will change the appearance of the
1614          option's row of widgets when the toggle button is pressed */
1615 
1616       if( opt->mandatory != TRUE )
1617          XtAddCallback( ow->toggle , XmNvalueChangedCallback ,
1618                         PLUG_optional_toggle_CB , (XtPointer) ow ) ;
1619 
1620       /** create Label to describe this option **/
1621 
1622 #if 0
1623 fprintf(stderr,"Option setup %s\n",opt->label) ;
1624 #endif
1625 
1626 STATUS("create Label for row") ;
1627       zlen = (PLUG_nonblank_len(opt->label) == 0) ;
1628       xstr = XmStringCreateLtoR( opt->label , XmFONTLIST_DEFAULT_TAG ) ;
1629       ow->label =
1630          XtVaCreateManagedWidget(
1631            "AFNI" , xmLabelWidgetClass , wid->workwin ,
1632               XmNleftAttachment   , XmATTACH_WIDGET ,
1633               XmNtopAttachment    , (iopt==0) ? XmATTACH_FORM     /* 1st row */
1634                                               : XmATTACH_WIDGET , /* 2nd+ row */
1635               XmNtopOffset        , 6 ,
1636               XmNleftOffset       , 0 ,
1637               XmNleftWidget       , ow->toggle ,
1638               XmNtopWidget        , separator ,  /* 2nd+ row */
1639 
1640               XmNmarginHeight     , 0  ,
1641               XmNmarginWidth      , 0  ,
1642 
1643               XmNlabelString , xstr ,
1644               XmNuserData    , (XtPointer)ITOP(zlen) ,
1645               XmNinitialResourcesPersistent , False ,
1646            NULL ) ;
1647       XmStringFree( xstr ) ;
1648       if( opt->mandatory == TRUE && !zlen ){
1649          MCW_invert_widget( ow->label ) ;
1650          MCW_register_help( ow->label ,
1651                             "This label is inverted as a\n"
1652                             "signal that this line of inputs\n"
1653                             "is required by the plugin, and\n"
1654                             "can't be toggled off."
1655                           ) ;
1656       }
1657       if( opt->hint != NULL )
1658          MCW_register_hint( ow->label , opt->hint ) ;
1659 
1660       /** for each subvalue, create a chooser to select it **/
1661 
1662       for( ib=0 ; ib < opt->subvalue_count ; ib++ ){
1663          sv   = &(opt->subvalue[ib]) ;
1664          toff = 4 ;                      /* default top offset */
1665 
1666          switch( sv->data_type ){
1667 
1668             /** type I can't handle yet, so just put some label there **/
1669             default:
1670                WARNING_message("Plugin: unknown subvalue type %d", sv->data_type);
1671                xstr = XmStringCreateLtoR( "** N/A **" , XmFONTLIST_DEFAULT_TAG ) ;
1672                ow->chtop[ib] =
1673                   XtVaCreateManagedWidget(
1674                      "AFNI" , xmLabelWidgetClass , wid->workwin ,
1675                      XmNlabelString , xstr ,
1676                      XmNinitialResourcesPersistent , False ,
1677                   NULL ) ;
1678                XmStringFree( xstr ) ;
1679                ow->chooser_type[ib] = OP_CHOOSER_NONE ;
1680                ow->chooser[ib]      = NULL ;
1681             break ;
1682 
1683             /** overlay color type -- 11 Jul 2001 **/
1684 
1685             case PLUGIN_OVERLAY_COLOR_TYPE:{
1686                MCW_arrowval *av ; int iv=sv->value_default ;
1687 STATUS("create PLUGIN_OVERLAY_COLOR_TYPE") ;
1688 #if 0
1689 fprintf(stderr,"colormenu setup %s; opt->tag=%s.\n",sv->label,opt->tag) ;
1690 #endif
1691                if( iv < 0 || iv > dc->ovc->ncol_ov-1 ) iv = 1 ;
1692 
1693                av = new_MCW_colormenu(
1694                        wid->workwin ,                    /* parent */
1695                        sv->label ,                       /* label  */
1696                        dc ,                              /* display context */
1697                        1 ,                               /* first color */
1698                        dc->ovc->ncol_ov - 1 ,            /* last color */
1699                        iv ,                              /* initial color */
1700                        NULL,NULL                         /* callback func,data */
1701                     ) ;
1702 
1703                ow->chooser[ib] = (void *) av ;
1704                ow->chtop[ib]   = av->wrowcol ;  /* get the top widget */
1705                #ifdef USING_LESSTIF_NOT_DOING_THIS
1706                   if (CPU_IS_64_BIT() ){
1707                      ow->chtop[ib]   = XtParent(XtParent(av->wrowcol));
1708                               /* get the very top rowcol holding the
1709                                  optmenu rowcol, see function
1710                                  new_MCW_optmenu_64fix   [LPatrol Feb 19 2009] */
1711                   }
1712                #endif
1713 
1714                ow->chooser_type[ib] = OP_CHOOSER_COLORMENU ;
1715             }
1716             break ;
1717 
1718             /** number type: make an arrowval or an option menu **/
1719 
1720             case PLUGIN_NUMBER_TYPE:{
1721                int num_choice , use_optmenu ;
1722                MCW_arrowval * av ;
1723 
1724 STATUS("create PLUGIN_NUMBER_TYPE") ;
1725                num_choice  = abs(sv->int_range_top - sv->int_range_bot) + 1 ;
1726                use_optmenu = (num_choice < OP_OPTMENU_LIMIT) && !sv->editable ;
1727 
1728                av = new_MCW_arrowval(
1729                        wid->workwin ,                    /* parent */
1730                        sv->label ,                       /* label  */
1731                        (use_optmenu) ? MCW_AV_optmenu    /* type   */
1732                                      : MCW_AV_downup ,
1733                        sv->int_range_bot ,               /* min */
1734                        sv->int_range_top ,               /* max */
1735                        sv->value_default ,               /* initial */
1736                        (sv->editable) ? MCW_AV_editext   /* type */
1737                                       : MCW_AV_readtext ,
1738                        sv->int_range_decim ,             /* decimals? */
1739                        NULL , NULL , NULL , NULL
1740                      ) ;
1741 
1742                if( use_optmenu && num_choice > COLSIZE )
1743                   AVOPT_columnize(av, 1+(num_choice-1)/COLSIZE) ;
1744 
1745                ow->chooser[ib] = (void *) av ;
1746                ow->chtop[ib]   = av->wrowcol ;  /* get the top widget */
1747                #ifdef USING_LESSTIF_NOT_DOING_THIS
1748                   if (CPU_IS_64_BIT() && use_optmenu){
1749                      ow->chtop[ib]   = XtParent(XtParent(av->wrowcol));
1750                               /* get the very top rowcol holding the
1751                                  optmenu rowcol, see function
1752                                  new_MCW_optmenu_64fix [LPatrol Feb 19 2009]*/
1753                   }
1754                #endif
1755                ow->chooser_type[ib] = (use_optmenu) ? OP_CHOOSER_OPTMENU
1756                                                     : OP_CHOOSER_NUMBER ;
1757 
1758                if( !use_optmenu ) av->allow_wrap = 1 ;
1759                if(  use_optmenu ) toff-- ;
1760 
1761                if( !use_optmenu && (plint->flags & SHORT_NUMBER_FLAG) )
1762                   XtVaSetValues( av->wtext , XmNcolumns , 6 , NULL ) ;
1763             }
1764             break ;
1765 
1766             /** string type:
1767                   make an arrowval if a finite number of choices,
1768                   or a label+textfield if the user can type in anything **/
1769 
1770             case PLUGIN_STRING_TYPE:{
1771                if( sv->string_range_count > 0 ){    /* finite number of choices */
1772                   int num_choice , use_optmenu ;
1773                   MCW_arrowval * av ;
1774 
1775 STATUS("create PLUGIN_STRING_TYPE (fixed)") ;
1776                   num_choice  = sv->string_range_count ;
1777                   use_optmenu = (num_choice < OP_OPTMENU_LIMIT) ;
1778 
1779                   av = new_MCW_arrowval(
1780                           wid->workwin ,                    /* parent */
1781                           sv->label ,                       /* label  */
1782                           (use_optmenu) ? MCW_AV_optmenu    /* type   */
1783                                         : MCW_AV_downup ,
1784                           0 ,                               /* min */
1785                           num_choice-1 ,                    /* max */
1786                           sv->value_default ,               /* initial */
1787                           MCW_AV_readtext ,                 /* type */
1788                           0 ,                               /* decimals? */
1789                           NULL , NULL ,                     /* callbacks */
1790                           MCW_av_substring_CB ,             /* text routine */
1791                           sv->string_range                  /* text data */
1792                         ) ;
1793 
1794                   if( !use_optmenu ){                        /* 11 Jul 2001 */
1795                     int ss , ll , mm=9 ;                     /* increase   */
1796                     for( ss=0 ; ss < num_choice ; ss++ ){    /* width of  */
1797                        if( sv->string_range[ss] != NULL ){   /* widget,   */
1798                           ll = strlen(sv->string_range[ss]); /* if needed */
1799                           if( ll > mm ) mm = ll ;
1800                        }
1801                     }
1802                     if( mm > 9 )
1803                       XtVaSetValues( av->wtext ,
1804                                        XmNmaxLength,mm , XmNcolumns,mm ,
1805                                      NULL ) ;
1806                   }
1807 
1808                   if( use_optmenu && num_choice > COLSIZE )
1809                      AVOPT_columnize(av, 1+(num_choice-1)/COLSIZE) ;
1810 
1811                   ow->chooser[ib] = (void *) av ;
1812                   ow->chtop[ib]   = av->wrowcol ;  /* get the top widget */
1813                   #ifdef USING_LESSTIF_NOT_DOING_THIS
1814                   if (CPU_IS_64_BIT() && use_optmenu ){
1815                      ow->chtop[ib]   = XtParent(XtParent(av->wrowcol));
1816                               /* get the very top rowcol holding the
1817                                  optmenu rowcol, see function
1818                                  new_MCW_optmenu_64fix [LPatrol Feb 19 2009]*/
1819                   }
1820                   #endif
1821                   ow->chooser_type[ib] = (use_optmenu) ? OP_CHOOSER_OPTMENU
1822                                                        : OP_CHOOSER_STRING ;
1823 
1824                   if( !use_optmenu ) av->allow_wrap = 1 ;
1825                   if(  use_optmenu ) toff-- ;
1826 
1827                } else {  /* arbitrary string input allowed */
1828 
1829                   PLUGIN_strval * av = myXtNew(PLUGIN_strval) ;
1830 
1831 STATUS("create PLUGIN_STRING_TYPE (free)") ;
1832                   av->rowcol =
1833                      XtVaCreateWidget(
1834                        "AFNI" , xmRowColumnWidgetClass , wid->workwin ,
1835                           XmNpacking     , XmPACK_TIGHT ,
1836                           XmNorientation , XmHORIZONTAL ,
1837                           XmNmarginHeight, 0 ,
1838                           XmNmarginWidth , 0 ,
1839                           XmNspacing     , 0 ,
1840                           XmNtraversalOn , True  ,
1841                           XmNinitialResourcesPersistent , False ,
1842                        NULL ) ;
1843 
1844                   xstr = XmStringCreateLtoR( sv->label , XmFONTLIST_DEFAULT_TAG ) ;
1845                   av->label =
1846                      XtVaCreateManagedWidget(
1847                        "AFNI" , xmLabelWidgetClass , av->rowcol ,
1848                           XmNlabelString , xstr ,
1849                           XmNmarginWidth   , 0  ,
1850                           XmNinitialResourcesPersistent , False ,
1851                        NULL ) ;
1852                   XmStringFree( xstr ) ;
1853 
1854                   av->textf =
1855                      XtVaCreateManagedWidget(
1856                        "AFNI" , xmTextFieldWidgetClass , av->rowcol ,
1857                            XmNcolumns      , (sv->value_default > 1)
1858                                             ? sv->value_default : 9 ,
1859                            XmNeditable     , True ,
1860                            XmNmaxLength    , PLUGIN_STRING_SIZE ,
1861                            XmNresizeWidth  , False ,
1862                            XmNmarginHeight , 1 ,
1863                            XmNmarginWidth  , 1 ,
1864                            XmNcursorPositionVisible , True ,
1865                            XmNblinkRate , 0 ,
1866                            XmNautoShowCursorPosition , True ,
1867                            XmNtraversalOn , True  ,
1868                            XmNinitialResourcesPersistent , False ,
1869                         NULL ) ;
1870 
1871                   if( sv->string_range_count == -1 )
1872                     XmTextFieldSetString( av->textf , sv->string_range[0] ) ;
1873 
1874                   XtManageChild( av->rowcol ) ;
1875 
1876                   ow->chooser[ib] = (void *) av ;
1877                   ow->chtop[ib]   = av->rowcol ;  /* get the top widget */
1878 
1879                   ow->chooser_type[ib] = OP_CHOOSER_STRING ;
1880                }
1881             }
1882             break ;
1883 
1884             /** single dataset type: make a pushbutton to popup a chooser **/
1885             /** 24 Nov 1996: adapt to include dataset list type as well   **/
1886 
1887             case PLUGIN_DATASET_LIST_TYPE:
1888             case PLUGIN_DATASET_TYPE:{
1889                PLUGIN_dsetval * av = myXtNew(PLUGIN_dsetval) ;
1890 
1891 STATUS("create PLUGIN_DATASET_TYPE") ;
1892 
1893                av->sv = sv ;  /* what this is linked to */
1894 
1895                av->dset_count  = 0 ;     /* will be array of datasets */
1896                av->dset_link   = NULL ;  /* we can choose amongst */
1897 
1898                av->dset_choice = -1 ;    /* will be index of our choice */
1899 
1900                /* 24 Nov 1996 */
1901 
1902                av->multi   = (sv->data_type == PLUGIN_DATASET_LIST_TYPE) ;
1903                av->nchosen = 0 ;
1904                av->chosen  = NULL ;
1905                av->current = 0 ;
1906                av->idclist = NULL ;
1907 
1908                av->rowcol =
1909                   XtVaCreateWidget(
1910                     "AFNI" , xmRowColumnWidgetClass , wid->workwin ,
1911                        XmNpacking     , XmPACK_TIGHT ,
1912                        XmNorientation , XmHORIZONTAL ,
1913                        XmNmarginHeight, 0 ,
1914                        XmNmarginWidth , 0 ,
1915                        XmNspacing     , 0 ,
1916                        XmNtraversalOn , True  ,
1917                        XmNinitialResourcesPersistent , False ,
1918                     NULL ) ;
1919 
1920                xstr = XmStringCreateLtoR( sv->label , XmFONTLIST_DEFAULT_TAG ) ;
1921                av->label =
1922                   XtVaCreateManagedWidget(
1923                     "AFNI" , xmLabelWidgetClass , av->rowcol ,
1924                        XmNlabelString , xstr ,
1925                        XmNmarginWidth   , 0  ,
1926                        XmNinitialResourcesPersistent , False ,
1927                     NULL ) ;
1928                XmStringFree( xstr ) ;
1929 
1930                if( plint->flags & SHORT_CHOOSE_FLAG )
1931                  xstr = XmStringCreateLtoR(
1932                           (av->multi) ? "* Datasets *"
1933                                       : "- Dataset -" ,
1934                           XmFONTLIST_DEFAULT_TAG ) ;
1935                else
1936                  xstr = XmStringCreateLtoR(
1937                           (av->multi) ? "** Choose Datasets *"
1938                                       : "-- Choose Dataset --" ,
1939                           XmFONTLIST_DEFAULT_TAG ) ;
1940 
1941                av->pb = XtVaCreateManagedWidget(
1942                            "AFNI" , xmPushButtonWidgetClass , av->rowcol ,
1943                               XmNlabelString   , xstr ,
1944                               XmNmarginHeight  , 0 ,
1945                               XmNmarginWidth   , 0 ,
1946                               XmNrecomputeSize , False ,
1947                               XmNtraversalOn   , True  ,
1948                               XmNuserData      , (XtPointer) av ,
1949                               XmNinitialResourcesPersistent , False ,
1950                            NULL ) ;
1951 
1952                XtAddCallback( av->pb , XmNactivateCallback ,
1953                               PLUG_choose_dataset_CB , (XtPointer) plint ) ;
1954 
1955                XtManageChild( av->rowcol ) ;
1956 
1957                ow->chooser[ib] = (void *) av ;
1958                ow->chtop[ib]   = av->rowcol ;  /* get the top widget */
1959 
1960                ow->chooser_type[ib] = OP_CHOOSER_DSET ;
1961                toff-- ;
1962             }
1963             break ;
1964 
1965             /** single timeseries type (similiar to dataset above) **/
1966 
1967             case PLUGIN_TIMESERIES_TYPE:{
1968                PLUGIN_tsval * av = myXtNew(PLUGIN_tsval) ;
1969 
1970 STATUS("create PLUGIN_TIMESERIES_TYPE") ;
1971 
1972                av->sv        = sv ;                        /* a friend in need  */
1973                av->tsimar    = GLOBAL_library.timeseries ; /* to choose amongst */
1974                av->ts_choice = -1 ;                        /* no initial choice */
1975                av->tsim      = NULL ;
1976 
1977                av->rowcol =
1978                   XtVaCreateWidget(
1979                     "AFNI" , xmRowColumnWidgetClass , wid->workwin ,
1980                        XmNpacking     , XmPACK_TIGHT ,
1981                        XmNorientation , XmHORIZONTAL ,
1982                        XmNmarginHeight, 0 ,
1983                        XmNmarginWidth , 0 ,
1984                        XmNspacing     , 0 ,
1985                        XmNtraversalOn , True  ,
1986                               XmNheight, 20,
1987                               XmNwidth, 30,
1988                        XmNinitialResourcesPersistent , False ,
1989                     NULL ) ;
1990 
1991                xstr = XmStringCreateLtoR( sv->label , XmFONTLIST_DEFAULT_TAG ) ;
1992                av->label =
1993                   XtVaCreateManagedWidget(
1994                     "AFNI" , xmLabelWidgetClass , av->rowcol ,
1995                        XmNlabelString , xstr ,
1996                        XmNmarginWidth   , 0  ,
1997                        XmNinitialResourcesPersistent , False ,
1998                     NULL ) ;
1999                XmStringFree( xstr ) ;
2000 
2001                if( plint->flags & SHORT_CHOOSE_FLAG )
2002                  xstr = XmStringCreateLtoR( "-Timeseries-",XmFONTLIST_DEFAULT_TAG ) ;
2003                else
2004                  xstr = XmStringCreateLtoR( "-Choose Timeseries- ",XmFONTLIST_DEFAULT_TAG ) ;
2005 
2006                av->pb = XtVaCreateManagedWidget(
2007                            "AFNI" , xmPushButtonWidgetClass , av->rowcol ,
2008                               XmNlabelString   , xstr ,
2009                               XmNmarginHeight  , 0 ,
2010                               XmNmarginWidth   , 0 ,
2011                               XmNrecomputeSize , False ,
2012                               XmNtraversalOn   , True  ,
2013                               XmNuserData      , (XtPointer) av ,
2014                               XmNinitialResourcesPersistent , False ,
2015                            NULL ) ;
2016 
2017                XtAddCallback( av->pb , XmNactivateCallback ,
2018                               PLUG_choose_timeseries_CB , (XtPointer) plint ) ;
2019 
2020                XtManageChild( av->rowcol ) ;
2021 
2022                ow->chooser[ib] = (void *) av ;
2023                ow->chtop[ib]   = av->rowcol ;  /* get the top widget */
2024 
2025                ow->chooser_type[ib] = OP_CHOOSER_TIMESERIES ;
2026                toff-- ;
2027             }
2028             break ;
2029 
2030             /** single tcsv type (similiar to timeseries above) **/
2031 
2032             case PLUGIN_TCSV_TYPE:{
2033                PLUGIN_tcsvval * av = myXtNew(PLUGIN_tcsvval) ;
2034 
2035 STATUS("create PLUGIN_TCSV_TYPE") ;
2036 
2037                av->sv          = sv ;                       /* a friend in need  */
2038                av->elarr       = GLOBAL_library.tcsv_data ; /* to choose amongst */
2039                av->tcsv_choice = -1 ;                       /* no initial choice */
2040                av->tcsv_el     = NULL ;
2041 
2042                av->rowcol =
2043                   XtVaCreateWidget(
2044                     "AFNI" , xmRowColumnWidgetClass , wid->workwin ,
2045                        XmNpacking     , XmPACK_TIGHT ,
2046                        XmNorientation , XmHORIZONTAL ,
2047                        XmNmarginHeight, 0 ,
2048                        XmNmarginWidth , 0 ,
2049                        XmNspacing     , 0 ,
2050                        XmNtraversalOn , True  ,
2051                               XmNheight, 20,
2052                               XmNwidth, 30,
2053                        XmNinitialResourcesPersistent , False ,
2054                     NULL ) ;
2055 
2056                xstr = XmStringCreateLtoR( sv->label , XmFONTLIST_DEFAULT_TAG ) ;
2057                av->label =
2058                   XtVaCreateManagedWidget(
2059                     "AFNI" , xmLabelWidgetClass , av->rowcol ,
2060                        XmNlabelString , xstr ,
2061                        XmNmarginWidth   , 0  ,
2062                        XmNinitialResourcesPersistent , False ,
2063                     NULL ) ;
2064                XmStringFree( xstr ) ;
2065 
2066                if( plint->flags & SHORT_CHOOSE_FLAG )
2067                  xstr = XmStringCreateLtoR( "-*.[tc]sv-",XmFONTLIST_DEFAULT_TAG ) ;
2068                else
2069                  xstr = XmStringCreateLtoR( "-Choose *.[tc]sv -",XmFONTLIST_DEFAULT_TAG ) ;
2070 
2071                av->pb = XtVaCreateManagedWidget(
2072                            "AFNI" , xmPushButtonWidgetClass , av->rowcol ,
2073                               XmNlabelString   , xstr ,
2074                               XmNmarginHeight  , 0 ,
2075                               XmNmarginWidth   , 0 ,
2076                               XmNrecomputeSize , False ,
2077                               XmNtraversalOn   , True  ,
2078                               XmNuserData      , (XtPointer) av ,
2079                               XmNinitialResourcesPersistent , False ,
2080                            NULL ) ;
2081 
2082                XtAddCallback( av->pb , XmNactivateCallback ,
2083                               PLUG_choose_tcsv_CB , (XtPointer) plint ) ;
2084 
2085                XtManageChild( av->rowcol ) ;
2086 
2087                ow->chooser[ib] = (void *) av ;
2088                ow->chtop[ib]   = av->rowcol ;  /* get the top widget */
2089 
2090                ow->chooser_type[ib] = OP_CHOOSER_TCSV ;
2091                toff-- ;
2092             }
2093             break ;
2094 
2095          }  /* end of switch on subvalue type */
2096 
2097          /** set initial attachments for the topmost chooser widget **/
2098 
2099          XtVaSetValues(
2100             ow->chtop[ib] ,
2101                XmNleftAttachment   , (ib==0) ? XmATTACH_WIDGET    /* First column  */
2102                                              : XmATTACH_NONE ,    /* of widgets    */
2103                XmNleftOffset       , (ib==0) ? 6                  /* is attached   */
2104                                              : 0 ,                /* to the label. */
2105                XmNleftWidget       , (ib==0) ? ow->label          /* Later columns */
2106                                              : NULL ,             /* fixed below.  */
2107 
2108                XmNtopAttachment    , (iopt==0) ? XmATTACH_FORM     /* 1st row */
2109                                                : XmATTACH_WIDGET , /* 2nd+ row */
2110                XmNtopOffset        , toff ,
2111                XmNtopWidget        , separator ,
2112             NULL ) ;
2113 
2114          if( opt->mandatory == FALSE ) XtSetSensitive( ow->chtop[ib] , False ) ;
2115 
2116          if( sv->hint != NULL )
2117              MCW_reghint_children( ow->chtop[ib] , sv->hint ) ;
2118 
2119          /** find out if this is the widest one in its column so far **/
2120 
2121          MCW_widget_geom( ow->chtop[ib] , &ww , NULL,NULL,NULL ) ;
2122 
2123          if( ww > widest_width[ib] ){
2124             widest_width[ib]   = ww ;
2125             widest_chooser[ib] = ow->chtop[ib] ;
2126          }
2127 
2128       }  /* end of loop over subvalues */
2129 
2130       /** separator between option rows **/
2131 
2132 STATUS("create row Separator") ;
2133       separator = XtVaCreateManagedWidget(
2134                     "AFNI" , xmSeparatorWidgetClass , wid->workwin ,
2135                        XmNseparatorType  , XmSHADOW_ETCHED_OUT ,
2136                        XmNshadowThickness, 5 ,
2137                        XmNleftAttachment , XmATTACH_FORM ,
2138                        XmNrightAttachment, XmATTACH_FORM ,
2139                        XmNtopAttachment  , XmATTACH_WIDGET ,
2140                        XmNtopWidget      , ow->toggle ,
2141                        XmNtopOffset      , 7 ,
2142                     NULL ) ;
2143 
2144    } /* end of loop over options */
2145 
2146 #if 0
2147 fprintf(stderr,"Widget attachments\n") ;
2148 #endif
2149 
2150    /**** Now that we've created all the rows,
2151          and have found all the widest widgets in each column,
2152          go back and attach each column to the widest one to its left. ****/
2153 
2154    for( iopt=0 ; iopt < plint->option_count ; iopt++ ){
2155       opt = plint->option[iopt] ;
2156       if( opt == NULL ) continue ; /* bad? */
2157 
2158       ow = opwid[iopt] ;
2159       for( ib=1 ; ib < opt->subvalue_count ; ib++ ){
2160          XtVaSetValues( ow->chtop[ib] ,
2161                            XmNleftAttachment , XmATTACH_WIDGET ,
2162                            XmNleftWidget     , widest_chooser[ib-1] ,
2163                            XmNleftOffset     , 6 ,
2164                         NULL ) ;
2165       }
2166    }
2167 
2168 #if 0
2169 fprintf(stderr,"Widget separators\n") ;
2170 #endif
2171 
2172    /**** Create a vertical separator to the left of each column ****/
2173 
2174    if( plint->option_count > 0 ){
2175 STATUS("create vertical Separators") ;
2176       for( ib=0 ; ib < PLUGIN_MAX_SUBVALUES && widest_width[ib] > 0 ; ib++ ){
2177          separator = XtVaCreateManagedWidget(
2178                        "AFNI" , xmSeparatorWidgetClass , wid->workwin ,
2179                           XmNseparatorType   , XmSHADOW_ETCHED_OUT ,
2180                           XmNorientation     , XmVERTICAL ,
2181                           XmNtopAttachment   , XmATTACH_FORM ,
2182                           XmNbottomAttachment, XmATTACH_FORM ,
2183                           XmNrightAttachment , XmATTACH_WIDGET ,
2184                           XmNrightWidget     , widest_chooser[ib] ,
2185                           XmNrightOffset     , 2 ,
2186                        NULL ) ;
2187 
2188       }
2189    }
2190 
2191 #if 0
2192 fprintf(stderr,"Widget management\n") ;
2193 #endif
2194 
2195    /**** Manage the managers, and go home ****/
2196 
2197    if( plint->option_count > 0 ){
2198 STATUS("management") ;
2199       XtManageChild( wid->workwin ) ;
2200       XtManageChild( wframe ) ;
2201       XtManageChild( wid->scrollw ) ;
2202    }
2203    XtManageChild( wid->form ) ;
2204 
2205 #if 0
2206 fprintf(stderr,"Widget realization\n") ;
2207 #endif
2208 
2209 STATUS("realization") ;
2210    XtRealizeWidget( wid->shell ) ;  /* will not be mapped */
2211    NI_sleep(1) ;
2212 
2213    /** set its width after it is mapped **/
2214 
2215 #define OPC_MAX     8
2216 #define OPC_MAXMAX 10
2217 #define LUCK        5
2218 
2219    if( wframe != NULL ){
2220       Widget bar=NULL ;
2221       int fww , fhh , fyy , bww ;
2222 
2223 #if 0
2224 fprintf(stderr,"Widget geometrization\n") ;
2225 #endif
2226 
2227 STATUS("geometrization") ;
2228       MCW_widget_geom( wid->label   , &ww , &hh , NULL, NULL ) ;  /* get dimensions */
2229       MCW_widget_geom( wframe       , &fww, &fhh, NULL, NULL ) ;  /* of various */
2230       MCW_widget_geom( wid->scrollw , NULL, NULL, NULL, &fyy ) ;  /* pieces-parts */
2231 
2232       fww = MAX( fww+LUCK , ww ) ;  /* extra pixels for luck */
2233 
2234       ib = plint->option_count ;     /* too many options --> will use vertical scrollbar */
2235       if( ib > OPC_MAXMAX ){
2236          fhh = (OPC_MAX * fhh) / ib ;  /* set height to allow for OPC_MAX options visible */
2237 
2238          if( fww > ww ){               /* set width to allow for vertical scrollbar */
2239             XtVaGetValues( wid->scrollw , XmNverticalScrollBar , &bar , NULL ) ;
2240             MCW_widget_geom( bar , &bww , NULL,NULL,NULL ) ;
2241             fww += bww+LUCK+LUCK ;     /* need more luck here, I guess */
2242          }
2243       }
2244       fhh += fyy+LUCK ;  /* set height to allow for stuff above options */
2245 
2246       XtVaSetValues( wid->shell , XmNwidth , fww , XmNheight , fhh , NULL ) ;
2247    }
2248 
2249    /** set the popup meter to be nothing at all right now **/
2250 
2251    wid->meter = NULL ;
2252 
2253 #if 0
2254 fprintf(stderr,"Widgets done!\n") ;
2255 #endif
2256 
2257    EXRETURN ;
2258 }
2259 
2260 /*-----------------------------------------------------------------------
2261   21 Feb 2001: routine to turn off optional inputs
2262 -------------------------------------------------------------------------*/
2263 
PLUTO_turnoff_options(PLUGIN_interface * plint)2264 void PLUTO_turnoff_options( PLUGIN_interface * plint )
2265 {
2266    int kk ;
2267 
2268 ENTRY("PLUTO_turnoff_options") ;
2269 
2270    /**** sanity checks ****/
2271 
2272    if( plint == NULL || plint->wid == NULL ||
2273        plint->call_method == PLUGIN_CALL_IMMEDIATELY ) EXRETURN ;
2274 
2275    /**** loop over options */
2276 
2277    for( kk=0 ; kk < plint->option_count ; kk++ ){
2278       if( plint->option[kk]->mandatory != TRUE )
2279          XmToggleButtonSetState( plint->wid->opwid[kk]->toggle, False,True ) ;
2280    }
2281 
2282    EXRETURN ;
2283 }
2284 
2285 /*-----------------------------------------------------------------------
2286    What happens when a plugin interface action button is pressed
2287 -------------------------------------------------------------------------*/
2288 
PLUG_action_CB(Widget w,XtPointer cd,XtPointer cbs)2289 void PLUG_action_CB( Widget w , XtPointer cd , XtPointer cbs )
2290 {
2291    PLUGIN_interface *plint = (PLUGIN_interface *) cd ;
2292    char *wname = XtName(w) ;
2293    char *mesg=NULL ;
2294    int close , run , badrun=0 , help ;
2295 
2296 ENTRY("PLUG_action_CB") ;
2297 
2298    run   = (strcmp(wname,plint->doit_label)==0) || (strcmp(wname,plint->run_label)==0);
2299    close = (strcmp(wname,plint->doit_label)==0) || (strcmp(wname,PLUG_quit_label) ==0);
2300    help  = (strcmp(wname,PLUG_help_label)==0) ;
2301 
2302    if( run ){
2303       PLUG_fillin_values( plint ) ;       /* load callvalues  */
2304       plint->opnum = plint->svnum = -1 ;  /* initialize get_  */
2305 
2306       /***** CALL THE PLUGIN !!!! *****/
2307 
2308       MPROBE ;
2309 
2310       SHOW_AFNI_PAUSE ;
2311 #if 0
2312       mesg = plint->call_func( plint ) ;
2313 #else
2314       AFNI_CALL_VALU_1ARG( plint->call_func ,
2315                            char *,mesg , PLUGIN_interface *,plint ) ;
2316 #endif
2317       SHOW_AFNI_READY ;
2318 
2319       PLUTO_popdown_meter( plint ) ;  /* if the user forgets */
2320 
2321       MPROBE ;
2322 
2323       /********************************/
2324 
2325       badrun = (mesg != NULL) ;
2326       if( badrun ){
2327          if( w != NULL ){
2328             (void) MCW_popup_message( w , mesg , MCW_USER_KILL ) ;
2329             BEEPIT ;
2330          } else {
2331             fprintf(stderr,"\n%s\a\n",mesg) ;
2332          }
2333       }
2334    }
2335 
2336    if( close && !badrun ) PLUG_delete_window_CB( w , cd , cbs ) ;
2337 
2338    /* 28 Dec 1997: use a scrolling text window if help too big */
2339 
2340    if( help ){
2341       int nl = THD_linecount( plint->helpstring ) ;
2342       if( nl < 10 ) MCW_popup_message( plint->wid->label ,
2343                                        plint->helpstring , MCW_USER_KILL ) ;
2344       else          new_MCW_textwin  ( plint->wid->label ,
2345                                        plint->helpstring , TEXT_READONLY ) ;
2346    }
2347 
2348    EXRETURN ;
2349 }
2350 
2351 /*------------------------------------------------------------------------
2352    What happens when the user selects "Close" from the window
2353    menu in a plugin interface menu window.
2354 --------------------------------------------------------------------------*/
2355 
PLUG_delete_window_CB(Widget w,XtPointer cd,XtPointer cbs)2356 void PLUG_delete_window_CB( Widget w , XtPointer cd , XtPointer cbs )
2357 {
2358    PLUGIN_interface * plint = (PLUGIN_interface *) cd ;
2359 
2360 ENTRY("PLUG_delete_window_CB") ;
2361 
2362    if( plint != NULL && plint->wid != NULL ){
2363       XtUnmapWidget(plint->wid->shell) ;
2364       XmUpdateDisplay(plint->wid->shell) ;
2365    }
2366    EXRETURN ;
2367 }
2368 
2369 /*------------------------------------------------------------------------
2370    What happens when the user toggles an option's toggle button.
2371 --------------------------------------------------------------------------*/
2372 
PLUG_optional_toggle_CB(Widget w,XtPointer cd,XtPointer cbs)2373 void PLUG_optional_toggle_CB( Widget w , XtPointer cd , XtPointer cbs )
2374 {
2375    PLUGIN_option_widgets * ow = (PLUGIN_option_widgets *) cd ;
2376    int ib , zlen ;
2377    XtPointer xptr=NULL ;
2378 
2379 ENTRY("PLUG_optional_toggle_CB") ;
2380 
2381    /** invert label widget, and switch sensitivity of subvalue widgets **/
2382 
2383    if( ow != NULL ){
2384 #if 0
2385       if( ow->label != NULL ){
2386          XtVaGetValues( ow->label , XmNuserData , &xptr , NULL ) ;
2387          zlen = (int) xptr ;
2388          if( !zlen ) MCW_invert_widget( ow->label ) ;
2389       }
2390 #endif
2391 
2392       for( ib=0 ; ib < PLUGIN_MAX_SUBVALUES ; ib++ )
2393          if( ow->chtop[ib] != NULL )
2394             XtSetSensitive( ow->chtop[ib] , !XtIsSensitive(ow->chtop[ib]) ) ;
2395    }
2396    EXRETURN ;
2397 }
2398 
2399 /*--------------------------------------------------------------------------
2400   Routine to take the interface widgets and put their values into
2401   place, so that the plugin can get them out again.
2402 ----------------------------------------------------------------------------*/
2403 
PLUG_fillin_values(PLUGIN_interface * plint)2404 void PLUG_fillin_values( PLUGIN_interface * plint )
2405 {
2406    int iopt , ib ;
2407    PLUGIN_option_widgets ** opwid , * ow ;
2408    PLUGIN_option * opt ;
2409    PLUGIN_subvalue * sv ;
2410 
2411 ENTRY("PLUG_fillin_values") ;
2412 
2413    /*--- check if there is anything to do ---*/
2414 
2415    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
2416 
2417    /*--- scan thru options ---*/
2418 
2419    opwid = plint->wid->opwid ;
2420 
2421    for( iopt=0 ; iopt < plint->option_count ; iopt++){
2422 
2423       opt = plint->option[iopt] ;   /* option to deal with */
2424       if( opt == NULL ) continue ;  /* bad? */
2425 
2426       ow = opwid[iopt] ;  /* row of widgets to deal with */
2427 
2428       /*-- find if this option is chosen by the user --*/
2429 
2430       opt->chosen = (int) XmToggleButtonGetState( ow->toggle ) ;
2431 
2432       /*-- scan thru subvalues, and load callvalue.
2433            note that we do this even for unchosen options. --*/
2434 
2435       for( ib=0 ; ib < opt->subvalue_count ; ib++ ){
2436 
2437         myXtFree( opt->callvalue[ib]  ) ;  /* free any old value here */
2438         sv = &(opt->subvalue[ib]) ;        /* subvalue to deal with */
2439 
2440         /*-- deal with each type of subvalue --*/
2441 
2442         switch( sv->data_type ){
2443 
2444            /** some type I don't know, so just put NULL in **/
2445 
2446            default:
2447               opt->callvalue[ib] = NULL ;
2448            break ;
2449 
2450            /** 11 Jul 2001: overlay color type; send in the color index **/
2451 
2452            case PLUGIN_OVERLAY_COLOR_TYPE:{
2453               MCW_arrowval *av = (MCW_arrowval *)ow->chooser[ib] ;
2454               int *iptr ;
2455 
2456               iptr  = (int *)XtMalloc( sizeof(int) ) ;
2457               *iptr = av->ival ;
2458               opt->callvalue[ib] = (void *) iptr ;
2459            }
2460            break ;
2461 
2462            /** number type: uses arrowval interface;
2463                             send in the float value **/
2464 
2465            case PLUGIN_NUMBER_TYPE:{
2466               MCW_arrowval *av = (MCW_arrowval *) ow->chooser[ib] ;
2467               float *fptr ;
2468 
2469               fptr  = (float *) XtMalloc( sizeof(float) ) ;
2470               *fptr = av->fval ;
2471               opt->callvalue[ib] = (void *) fptr ;
2472            }
2473            break ;
2474 
2475            /** string type: may be an arrowval or a strval **/
2476 
2477            case PLUGIN_STRING_TYPE:{
2478               if( sv->string_range_count > 0 ){
2479                  MCW_arrowval * av = (MCW_arrowval *) ow->chooser[ib] ;
2480                  char * cptr ;
2481 
2482                  cptr = XtNewString( av->sval ) ;
2483                  opt->callvalue[ib] = (void *) cptr ;
2484               } else {
2485                  PLUGIN_strval * av = (PLUGIN_strval *) ow->chooser[ib] ;
2486                  char * cptr ;
2487 
2488                  cptr = XmTextFieldGetString( av->textf ) ;
2489                  opt->callvalue[ib] = (void *) cptr ;
2490               }
2491            }
2492            break ;
2493 
2494            /** dataset type **/
2495 
2496            case PLUGIN_DATASET_TYPE:{
2497               PLUGIN_dsetval * av = (PLUGIN_dsetval *) ow->chooser[ib] ;
2498               MCW_idcode * idc ;
2499 
2500               idc = myXtNew( MCW_idcode ) ;
2501               if( av->dset_choice < 0 )
2502                  ZERO_IDCODE(*idc) ;
2503               else
2504                  *idc = av->dset_link[av->dset_choice].idcode ;
2505 
2506               opt->callvalue[ib] = (void *) idc ;
2507            }
2508            break ;
2509 
2510            /** 25 Nov 1996: list of datasets **/
2511 
2512            case PLUGIN_DATASET_LIST_TYPE:{
2513               PLUGIN_dsetval * av = (PLUGIN_dsetval *) ow->chooser[ib] ;
2514               MCW_idclist ** llist ;
2515               int id ;
2516 
2517               llist = myXtNew(MCW_idclist *) ; *llist = av ;
2518 
2519               av->current = 0 ;
2520               if( av->nchosen <= 0 ){
2521                  myXtFree(av->idclist) ;
2522               } else {
2523                  av->idclist = (MCW_idcode *)
2524                                XtRealloc( (char *) av->idclist ,
2525                                           sizeof(MCW_idcode) * av->nchosen ) ;
2526                  for( id=0 ; id < av->nchosen ; id++ )
2527                     av->idclist[id] = av->dset_link[av->chosen[id]].idcode ;
2528               }
2529 
2530               opt->callvalue[ib] = (void *) llist ;
2531            }
2532            break ;
2533 
2534            /** timeseries type **/
2535 
2536            case PLUGIN_TIMESERIES_TYPE:{
2537               PLUGIN_tsval * av = (PLUGIN_tsval *) ow->chooser[ib] ;
2538               MRI_IMAGE ** imp ;
2539 
2540               imp  = myXtNew(MRI_IMAGE *) ;
2541               *imp = av->tsim ;
2542 
2543               opt->callvalue[ib] = (void *) imp ;
2544            }
2545            break ;
2546 
2547            /** tcsv type **/
2548 
2549            case PLUGIN_TCSV_TYPE:{
2550               PLUGIN_tcsvval * av = (PLUGIN_tcsvval *) ow->chooser[ib] ;
2551               NI_element ** imp ;
2552 
2553               imp  = myXtNew(NI_element *) ;
2554               *imp = av->tcsv_el ;
2555 
2556               opt->callvalue[ib] = (void *) imp ;
2557            }
2558            break ;
2559 
2560         } /* end of switch over subvalue type */
2561       }  /* end of scan thru subvalues */
2562    } /* end of scan thru options */
2563 
2564    EXRETURN ;
2565 }
2566 
2567 /*--------------------------------------------------------------------------
2568   Routine to take the interface widgets and clear their callvalues to NULL.
2569 ----------------------------------------------------------------------------*/
2570 
PLUG_freeup_values(PLUGIN_interface * plint)2571 void PLUG_freeup_values( PLUGIN_interface * plint )
2572 {
2573    int iopt , ib ;
2574    PLUGIN_option * opt ;
2575 
2576 ENTRY("PLUG_freeup_values") ;
2577 
2578    /*--- check if there is anything to do ---*/
2579 
2580    if( plint == NULL || plint->option_count == 0 ) EXRETURN ;
2581 
2582    /*--- scan thru options ---*/
2583 
2584    for( iopt=0 ; iopt < plint->option_count ; iopt++){
2585 
2586       opt = plint->option[iopt] ;   /* option to deal with */
2587       if( opt == NULL ) continue ;  /* bad? */
2588 
2589       /*-- scan thru subvalues, and free all callvalues --*/
2590 
2591       for( ib=0 ; ib < opt->subvalue_count ; ib++ ){
2592         XtFree( opt->callvalue[ib]  ) ;  /* free any old value here */
2593         opt->callvalue[ib] = NULL ;
2594       }
2595 
2596    } /* end of scan thru options */
2597 
2598    EXRETURN ;
2599 }
2600 
2601 /*-----------------------------------------------------------------------
2602    Routines to get values from a plugin interface, when passed
2603    to a plugin.
2604 -------------------------------------------------------------------------*/
2605 
get_label_from_PLUGIN_interface(PLUGIN_interface * plint)2606 char * get_label_from_PLUGIN_interface( PLUGIN_interface * plint )
2607 {
2608 ENTRY("get_label_from_PLUGIN_interface") ;
2609    if( plint == NULL ) RETURN(NULL) ;
2610    else                RETURN(plint->label) ;
2611 }
2612 
2613 /*-----------------------------------------------------------------------*/
2614 
get_description_from_PLUGIN_interface(PLUGIN_interface * plint)2615 char * get_description_from_PLUGIN_interface( PLUGIN_interface * plint )
2616 {
2617 ENTRY("get_description_from_PLUGIN_interface") ;
2618    if( plint == NULL ) RETURN(NULL) ;
2619    else                RETURN(plint->description) ;
2620 }
2621 
2622 /*-----------------------------------------------------------------------
2623    Get the next chosen option, and return its string "tag".
2624    If there is no "next chosen option", return NULL.
2625 -------------------------------------------------------------------------*/
2626 
get_optiontag_from_PLUGIN_interface(PLUGIN_interface * plint)2627 char * get_optiontag_from_PLUGIN_interface( PLUGIN_interface * plint )
2628 {
2629    int iopt ;
2630    PLUGIN_option * opt ;
2631 
2632 ENTRY("get_optiontag_from_PLUGIN_interface") ;
2633 
2634    if( plint == NULL ) RETURN(NULL) ;
2635 
2636    iopt = plint->opnum + 1 ;
2637    while( iopt < plint->option_count ){
2638 
2639       opt = plint->option[iopt++] ;
2640       if( opt == NULL )   continue ; /* bad? */
2641       if( ! opt->chosen ) continue ; /* not used this time */
2642 
2643       plint->opnum = iopt-1 ;        /* keep track of which option */
2644       plint->svnum = 0 ;             /* start at 1st subvalue */
2645       RETURN(opt->tag) ;
2646    }
2647 
2648    plint->opnum = plint->option_count ;
2649    RETURN(NULL) ;
2650 }
2651 
2652 /*-----------------------------------------------------------------------
2653    Return a string encaspulating information about how the plugin
2654    was called.  This string is created with malloc() and should be
2655    free()-ed when it is used up.  If NULL is returned, an error
2656    occurred (and you should be ashamed of yourself).
2657    -- 31 Aug 1999 -- RWCox
2658 -------------------------------------------------------------------------*/
2659 
2660 #include <stdarg.h>
2661 
blanktrim(char * ch)2662 static void blanktrim( char * ch )
2663 {
2664    int ii , ll ;
2665    if( ch == NULL ) return ;
2666    ll = strlen(ch) ; if( ll < 2 ) return ;
2667    for( ii=ll-1 ; ii > 0 ; ii-- )
2668       if( isspace(ch[ii]) ) ch[ii] = '\0' ; else break ;
2669    return ;
2670 }
2671 
2672 #undef BUFIT
2673 #define BUFIT(s) do{ strcpy(buf,s); blanktrim(buf); } while(0)
2674 
PLUTO_commandstring(PLUGIN_interface * plint)2675 char * PLUTO_commandstring( PLUGIN_interface * plint )
2676 {
2677    char * outbuf = NULL ;
2678    PLUGIN_option * opt ;
2679    PLUGIN_subvalue * sv ;
2680    int iopt , jsv ;
2681    char buf[256] ;
2682 
2683 ENTRY("PLUTO_commandstring") ;
2684 
2685    if( plint == NULL ) RETURN(outbuf) ;
2686 
2687    BUFIT(plint->label) ;
2688    outbuf = THD_zzprintf( outbuf , "%s " , buf ) ;  /* start with name */
2689 
2690    if( plint->call_method != PLUGIN_CALL_VIA_MENU ||
2691        plint->option_count == 0                   ||
2692        plint->option == NULL                        ) RETURN(outbuf) ;
2693 
2694    /* loop over each option for the plugin */
2695 
2696    for( iopt=0 ; iopt < plint->option_count ; iopt++ ){
2697       opt = plint->option[iopt] ;
2698       if( opt == NULL ) continue ;   /* bad? */
2699       if( ! opt->chosen ) continue ; /* not used this time */
2700 
2701       BUFIT(opt->label) ;
2702       outbuf = THD_zzprintf( outbuf , "{%s: " , buf ) ;
2703 
2704       /* if this option is used, put a list of its subvalues in the string */
2705 
2706       for( jsv=0 ; jsv < opt->subvalue_count ; jsv++ ){
2707          sv = &(opt->subvalue[jsv]) ;
2708          BUFIT(sv->label) ;
2709          outbuf = THD_zzprintf( outbuf , "%s=" , buf ) ;
2710          switch( sv->data_type ){
2711 
2712             default:
2713                outbuf = THD_zzprintf( outbuf,"?" ) ; break ;
2714 
2715             case PLUGIN_OVERLAY_COLOR_TYPE:{
2716                int *val = (int *) opt->callvalue[jsv] ;
2717                MCW_DC *dc = plint->im3d->dc ;
2718                if( val != NULL && *val >= 0 )
2719                  outbuf = THD_zzprintf( outbuf,"%s",dc->ovc->label_ov[*val] );
2720                else
2721                  outbuf = THD_zzprintf( outbuf,"?" ) ;
2722             }
2723             break ;
2724 
2725             case PLUGIN_NUMBER_TYPE:{
2726                float * val = (float *) opt->callvalue[jsv] ;
2727                if( val != NULL ) outbuf = THD_zzprintf( outbuf,"%g",*val) ;
2728                else              outbuf = THD_zzprintf( outbuf,"?" ) ;
2729             }
2730             break ;
2731 
2732             case PLUGIN_STRING_TYPE:{
2733                 char * val = (char *) opt->callvalue[jsv] ;
2734                 if( val != NULL ){ BUFIT(val); outbuf = THD_zzprintf( outbuf,"%s",buf); }
2735                 else                           outbuf = THD_zzprintf( outbuf,"?" ) ;
2736             }
2737             break ;
2738 
2739             case PLUGIN_DATASET_LIST_TYPE:{
2740                MCW_idclist ** llist = (MCW_idclist **) opt->callvalue[jsv] ;
2741                int nd = PLUTO_idclist_count(*llist) ;
2742                outbuf = THD_zzprintf( outbuf , "[%d dsets]" , nd ) ;
2743             }
2744             break ;
2745 
2746             case PLUGIN_DATASET_TYPE:{
2747                MCW_idcode * idc = (MCW_idcode *) opt->callvalue[jsv] ;
2748                THD_3dim_dataset * dset ;
2749 
2750                dset = PLUTO_find_dset( idc ) ;
2751                if( dset != NULL ){
2752                   char * qb = THD_trailname(DSET_HEADNAME(dset),SESSTRAIL+1) ;
2753                   outbuf = THD_zzprintf( outbuf,"%s",qb) ;
2754                } else
2755                   outbuf = THD_zzprintf( outbuf,"?" ) ;
2756             }
2757             break ;
2758 
2759             case PLUGIN_TIMESERIES_TYPE:{
2760                MRI_IMAGE ** imp = (MRI_IMAGE **) opt->callvalue[jsv] ;
2761 
2762                if( imp != NULL && *imp != NULL && (*imp)->name != NULL )
2763                   outbuf = THD_zzprintf( outbuf,"%s",(*imp)->name ) ;
2764                else
2765                   outbuf = THD_zzprintf( outbuf,"?" ) ;
2766             }
2767             break ;
2768 
2769          } /* end of switch on subvalue type */
2770 
2771          if( jsv < opt->subvalue_count - 1 )
2772             outbuf = THD_zzprintf( outbuf,"; ") ;
2773 
2774       } /* end of loop on subvalues */
2775 
2776       outbuf = THD_zzprintf( outbuf , "} " ) ;  /* end of this option */
2777 
2778    } /* end of loop on options */
2779 
2780    RETURN(outbuf) ;
2781 }
2782 
2783 /*-------------------------------------------------------------------------
2784    Find out what the next chosen option is, without actually retrieving it.
2785 ---------------------------------------------------------------------------*/
2786 
peek_optiontag_from_PLUGIN_interface(PLUGIN_interface * plint)2787 char * peek_optiontag_from_PLUGIN_interface( PLUGIN_interface * plint )
2788 {
2789    int iopt ;
2790    PLUGIN_option * opt ;
2791 
2792 ENTRY("peek_optiontag_from_PLUGIN_interface") ;
2793 
2794    if( plint == NULL ) RETURN(NULL) ;
2795 
2796    iopt = plint->opnum + 1 ;
2797    while( iopt < plint->option_count ){
2798       opt = plint->option[iopt++] ;
2799       if( opt == NULL ) continue ; /* bad? */
2800       if( opt->chosen ) RETURN(opt->tag) ;
2801    }
2802    RETURN(NULL) ;
2803 }
2804 
2805 /*-------------------------------------------------------------------------
2806    Find out what the next subvalue type is, without actually retrieving it.
2807    This will be one of the PLUGIN_*_TYPE codes.  If something is wrong,
2808    the return value will be ILLEGAL_TYPE.  This can be used to detect that
2809    no more subvalues are present in the option currently being processed.
2810 ---------------------------------------------------------------------------*/
2811 
peek_callvalue_type_from_PLUGIN_interface(PLUGIN_interface * plint)2812 int peek_callvalue_type_from_PLUGIN_interface( PLUGIN_interface * plint )
2813 {
2814    int isv ;
2815    PLUGIN_option * opt ;
2816 
2817 ENTRY("peek_callvalue_type_from_PLUGIN_interface") ;
2818 
2819    if( plint == NULL ) RETURN(ILLEGAL_TYPE) ;
2820    if( plint->opnum >= plint->option_count ) RETURN(ILLEGAL_TYPE) ;
2821 
2822    opt = plint->option[ plint->opnum ] ;
2823    if( opt == NULL ) RETURN(ILLEGAL_TYPE) ;
2824 
2825    isv = plint->svnum ;
2826    if( isv >= opt->subvalue_count ) RETURN(ILLEGAL_TYPE) ;
2827 
2828    RETURN(opt->subvalue[isv].data_type) ;
2829 }
2830 
2831 /*-------------------------------------------------------------------------
2832    Get the next subvalue, which should be of the type given by
2833    "type".  If it is not, return NULL, otherwise return a "void *",
2834    which must be properly de-referenced to get the true value:
2835 
2836      type                      output is really
2837      ------------------        ----------------
2838      PLUGIN_NUMBER_TYPE        float *         points to number
2839      PLUGIN_STRING_TYPE        char *          duh
2840      PLUGIN_DATASET_TYPE       MCW_idcode *    duh
2841      PLUGIN_TIMESERIES_TYPE    MRI_IMAGE **    duh
2842      PLUGIN_OVERLAY_COLOR_TYPE int *           points to overlay index
2843 
2844    Following this are convenience routines to do similar work on specific
2845    data types.
2846 ---------------------------------------------------------------------------*/
2847 
get_callvalue_from_PLUGIN_interface(PLUGIN_interface * plint,int type)2848 void * get_callvalue_from_PLUGIN_interface( PLUGIN_interface * plint , int type )
2849 {
2850    int isv ;
2851    PLUGIN_option * opt ;
2852 
2853 ENTRY("get_callvalue_from_PLUGIN_interface") ;
2854 
2855    if( plint == NULL ) RETURN( NULL );
2856 
2857    opt = plint->option[ plint->opnum ] ;
2858    if( opt == NULL ) RETURN( NULL );
2859 
2860    isv = plint->svnum ;
2861    if( isv >= opt->subvalue_count ) RETURN( NULL );
2862 
2863    if( opt->subvalue[isv].data_type != type ) RETURN( NULL );
2864 
2865    plint->svnum ++ ;
2866    RETURN( opt->callvalue[isv] );
2867 }
2868 
2869 /*----------------------------------------------------------------------------*/
2870 
get_timeseries_from_PLUGIN_interface(PLUGIN_interface * plint)2871 MRI_IMAGE * get_timeseries_from_PLUGIN_interface( PLUGIN_interface * plint )
2872 {
2873    MRI_IMAGE ** imp ;
2874 
2875 ENTRY("get_timeseries_from_PLUGIN_interface") ;
2876 
2877    imp = (MRI_IMAGE **)
2878          get_callvalue_from_PLUGIN_interface(plint,PLUGIN_TIMESERIES_TYPE) ;
2879 
2880    if( imp == NULL ) RETURN(NULL) ;
2881    RETURN(*imp) ;
2882 }
2883 
2884 /*----------------------------------------------------------------------------*/
2885 
get_tcsv_from_PLUGIN_interface(PLUGIN_interface * plint)2886 NI_element * get_tcsv_from_PLUGIN_interface( PLUGIN_interface * plint )
2887 {
2888    NI_element ** imp ;
2889 
2890 ENTRY("get_tcsv_from_PLUGIN_interface") ;
2891 
2892    imp = (NI_element **)
2893          get_callvalue_from_PLUGIN_interface(plint,PLUGIN_TCSV_TYPE) ;
2894 
2895    if( imp == NULL ) RETURN(NULL) ;
2896    RETURN(*imp) ;
2897 }
2898 
2899 /*----------------------------------------------------------------------------*/
2900 
get_number_from_PLUGIN_interface(PLUGIN_interface * plint)2901 float get_number_from_PLUGIN_interface( PLUGIN_interface * plint )
2902 {
2903    float * fp ;
2904 ENTRY("get_number_from_PLUGIN_interface") ;
2905    fp = (float *)get_callvalue_from_PLUGIN_interface(plint,PLUGIN_NUMBER_TYPE) ;
2906    if( fp == NULL ) RETURN(BAD_NUMBER) ;
2907    RETURN(*fp) ;
2908 }
2909 
2910 /*----------------------------------------------------------------------------*/
2911 
get_overlaycolor_from_PLUGIN_interface(PLUGIN_interface * plint)2912 int get_overlaycolor_from_PLUGIN_interface( PLUGIN_interface * plint )
2913 {
2914    int * ip ;
2915 ENTRY("get_overlaycolor_from_PLUGIN_interface") ;
2916    ip = (int *)get_callvalue_from_PLUGIN_interface(plint,PLUGIN_OVERLAY_COLOR_TYPE) ;
2917    if( ip == NULL ) RETURN(-1) ;
2918    RETURN(*ip) ;
2919 }
2920 
2921 /*----------------------------------------------------------------------------*/
2922 
get_string_from_PLUGIN_interface(PLUGIN_interface * plint)2923 char * get_string_from_PLUGIN_interface( PLUGIN_interface * plint )
2924 {
2925 ENTRY("get_string_from_PLUGIN_interface") ;
2926    RETURN(
2927      (char *) get_callvalue_from_PLUGIN_interface(plint,PLUGIN_STRING_TYPE) );
2928 }
2929 
2930 /*----------------------------------------------------------------------------*/
2931 
get_idcode_from_PLUGIN_interface(PLUGIN_interface * plint)2932 MCW_idcode * get_idcode_from_PLUGIN_interface( PLUGIN_interface * plint )
2933 {
2934 ENTRY("get_idcode_from_PLUGIN_interface") ;
2935    RETURN(
2936      (MCW_idcode *)get_callvalue_from_PLUGIN_interface(plint,PLUGIN_DATASET_TYPE) );
2937 }
2938 
2939 /*----------------------------------------------------------------------------*/
2940 
get_idclist_from_PLUGIN_interface(PLUGIN_interface * plint)2941 MCW_idclist * get_idclist_from_PLUGIN_interface( PLUGIN_interface * plint )
2942 {
2943    MCW_idclist ** llist ;
2944 
2945 ENTRY("get_idclist_from_PLUGIN_interface") ;
2946 
2947    llist = (MCW_idclist **)
2948            get_callvalue_from_PLUGIN_interface(plint,PLUGIN_DATASET_LIST_TYPE) ;
2949 
2950    if( llist != NULL ) RETURN(*llist) ;
2951    RETURN(NULL) ;
2952 }
2953 
2954 /*------------------------------------------------------------------------
2955    What happens when a dataset chooser button is pressed:
2956      1) Retrieve the pointers to the data structures associated
2957           with the button.
2958      2) Select the datasets that are allowable and make a list of
2959           their names and idcodes.
2960      3) Popup a strlist chooser to let the user make the choice.
2961 
2962    24 Nov 1996: add the option for multiple choices, flagged by av->multi.
2963 --------------------------------------------------------------------------*/
2964 
PLUG_choose_dataset_CB(Widget w,XtPointer cd,XtPointer cbs)2965 void PLUG_choose_dataset_CB( Widget w , XtPointer cd , XtPointer cbs )
2966 {
2967    PLUGIN_interface * plint = (PLUGIN_interface *) cd ;
2968    PLUGIN_dsetval   * av = NULL ;
2969    PLUGIN_subvalue  * sv = NULL ;
2970    Three_D_View     * im3d ;
2971 
2972    THD_session * ss ;
2973    THD_3dim_dataset * dset ;
2974    int iss_bot , iss_top , iss , vv ;
2975    int id , num_dset , qd ;
2976    MCW_idcode old_idcode ;
2977    static char ** strlist = NULL ;
2978    char label[64] ;
2979    int llen , ltop ;
2980    char qnam[THD_MAX_NAME+2048] ;
2981 
2982    int          num_old = 0 , qold ;  /* multi-choice stuff */
2983    MCW_idcode * old_chosen = NULL ;
2984    int        * indold = NULL ;
2985 
2986 ENTRY("PLUG_choose_dataset_CB") ;
2987 
2988    /** find the stuff that is associated with this button **/
2989 
2990    XtVaGetValues( w , XmNuserData , &av , NULL ) ;
2991 
2992    if( plint == NULL || av == NULL ) EXRETURN ;
2993    sv = av->sv ;
2994    if( sv == NULL ) EXRETURN ;
2995    im3d = plint->im3d ;
2996 
2997    /** Select the datasets **/
2998 
2999    if( ! IM3D_VALID(im3d) || (sv->dset_ctrl_mask & SESSION_ALL_MASK) != 0 ){
3000       iss_bot = 0 ;
3001       iss_top = GLOBAL_library.sslist->num_sess - 1 ;
3002    } else {
3003       iss_bot = iss_top = im3d->vinfo->sess_num ;
3004    }
3005 
3006    if( im3d != NULL ) vv = im3d->vinfo->view_type ;  /* select view type */
3007    else               vv = VIEW_ORIGINAL_TYPE ;
3008 
3009    /** Save the current selection, if any **/
3010 
3011    if( ! av->multi ){
3012       if( av->dset_choice >= 0 && av->dset_choice < av->dset_count )
3013          old_idcode = av->dset_link[av->dset_choice].idcode ;
3014       else
3015          ZERO_IDCODE(old_idcode) ;
3016    } else {
3017       for( id=0 ; id < av->nchosen ; id++ ){
3018          if( av->chosen[id] >= 0 && av->chosen[id] < av->dset_count ){
3019             num_old++ ;
3020             old_chosen = (MCW_idcode *) XtRealloc((char *)old_chosen,
3021                                                   sizeof(MCW_idcode)*num_old) ;
3022             old_chosen[num_old-1] = av->dset_link[av->chosen[id]].idcode ;
3023          }
3024       }
3025    }
3026 
3027    /** Scan sessions **/
3028 
3029    num_dset = 0 ;
3030    for( iss=iss_bot ; iss <= iss_top ; iss++ ){
3031       ss = GLOBAL_library.sslist->ssar[iss] ;
3032 
3033       /* check datasets in this session */
3034 
3035       for( id=0 ; id < ss->num_dsset ; id++ ){
3036              dset = GET_SESSION_DSET(ss, id, vv);
3037         /* dset = ss->dsset_xform_table[id][vv] ; */
3038         if( dset == NULL ) continue ;
3039 
3040         if( sv->dset_anat_mask != 0 && ISANAT(dset) )
3041           if( ! PLUGIN_dset_check( sv->dset_anat_mask ,
3042                                    sv->dset_ctrl_mask , dset ) ) continue ;
3043 
3044         if( sv->dset_func_mask != 0 && ISFUNC(dset) )
3045           if( ! PLUGIN_dset_check( sv->dset_func_mask ,
3046                                    sv->dset_ctrl_mask , dset ) ) continue ;
3047 
3048         /* if we get here, then this dataset is OK to choose! */
3049 
3050         num_dset++ ;
3051         av->dset_link = (PLUGIN_dataset_link *)
3052                          XtRealloc( (char *) av->dset_link ,
3053                                     sizeof(PLUGIN_dataset_link)*num_dset ) ;
3054 
3055         make_PLUGIN_dataset_link( dset , av->dset_link + (num_dset-1) ) ;
3056       }
3057 
3058    } /* end of loop over sessions */
3059 
3060    /*--- if nothing was found that fits, then nothing further can happen ---*/
3061 
3062    if( num_dset == 0 ){
3063       av->dset_count  = 0 ;
3064       av->dset_choice = -1 ;
3065       myXtFree(old_chosen) ;
3066       BEEPIT ;
3067       EXRETURN ;
3068    }
3069 
3070    /*--- 23 Nov 1996: loop over dataset links and patch their titles
3071                       to include an indicator of the dataset type    ---*/
3072 
3073    ltop = 4 ;
3074    for( id=0 ; id < num_dset ; id++ ){
3075       llen = strlen(av->dset_link[id].title) ;
3076       ltop = MAX(ltop,llen) ;
3077    }
3078 
3079    for( id=0 ; id < num_dset ; id++ ){
3080       dset = PLUTO_find_dset( &(av->dset_link[id].idcode) ) ;
3081       if( ! ISVALID_3DIM_DATASET(dset) ) continue ;
3082       if( ISANAT(dset) ){
3083          if( ISANATBUCKET(dset) )         /* 30 Nov 1997 */
3084             sprintf(qnam,"%-*s [%s:%d]" ,
3085                     ltop,av->dset_link[id].title ,
3086                     ANAT_prefixstr[dset->func_type] , DSET_NVALS(dset) ) ;
3087 
3088          else if( DSET_NUM_TIMES(dset) == 1 )
3089             sprintf(qnam,"%-*s [%s]" ,
3090                     ltop,av->dset_link[id].title ,
3091                     ANAT_prefixstr[dset->func_type] ) ;
3092 
3093          else
3094             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
3095                     ltop,av->dset_link[id].title ,
3096                     ANAT_prefixstr[dset->func_type] , DSET_NUM_TIMES(dset) ) ;
3097 
3098       } else {
3099          if( ISFUNCBUCKET(dset) )         /* 30 Nov 1997 */
3100             sprintf(qnam,"%-*s [%s:%d]" ,
3101                     ltop,av->dset_link[id].title ,
3102                     FUNC_prefixstr[dset->func_type] , DSET_NVALS(dset) ) ;
3103 
3104          else if( DSET_NUM_TIMES(dset) == 1 )
3105             sprintf(qnam,"%-*s [%s]" ,
3106                     ltop,av->dset_link[id].title ,
3107                     FUNC_prefixstr[dset->func_type] ) ;
3108 
3109          else
3110             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
3111                     ltop,av->dset_link[id].title ,
3112                     FUNC_prefixstr[dset->func_type] , DSET_NVALS(dset) ) ;
3113       }
3114 
3115       if( DSET_COMPRESSED(dset) ) strcat(qnam,"z") ;
3116 
3117       strcpy( av->dset_link[id].title , qnam ) ;
3118    }
3119 
3120    /*--- find the old choice in the current list, if any ---*/
3121 
3122    av->dset_count = num_dset ;
3123 
3124    if( ! av->multi ){
3125       if( !ISZERO_IDCODE(old_idcode) ){
3126          for( id=0 ; id < num_dset ; id++ )
3127             if( EQUIV_IDCODES(old_idcode,av->dset_link[id].idcode) ) break ;
3128 
3129          if( id < num_dset ) av->dset_choice = id ;
3130          else                av->dset_choice = -1 ;
3131       }
3132    } else {
3133       qold = 0 ;
3134       for( qd=0 ; qd < num_old ; qd++ ){
3135          if( !ISZERO_IDCODE(old_chosen[qd]) ){
3136             for( id=0 ; id < num_dset ; id++ )
3137                if( EQUIV_IDCODES(old_chosen[qd],av->dset_link[id].idcode) ) break ;
3138 
3139             if( id < num_dset ){
3140               qold++ ;
3141               indold = (int *) XtRealloc((char *)indold , sizeof(int)*qold) ;
3142               indold[qold-1] = id ;
3143               av->chosen[qold-1] = id ;
3144             }
3145           }
3146       }
3147       av->nchosen = qold ;
3148       if( qold > 0 ){
3149         qold++ ;
3150         indold = (int *) XtRealloc((char *)indold , sizeof(int)*qold) ;
3151         indold[qold-1] = -666 ;
3152       }
3153    }
3154 
3155    /*--- make a popup chooser for the user to browse ---*/
3156 
3157    POPDOWN_strlist_chooser ;
3158 
3159    strlist = (char **) XtRealloc( (char *)strlist , sizeof(char *)*num_dset ) ;
3160    for( id=0 ; id < num_dset ; id++ ) strlist[id] = av->dset_link[id].title ;
3161 
3162    sprintf( label , "AFNI Dataset from\nthe %s" , VIEW_typestr[vv] ) ;
3163 
3164    if( av->multi ){
3165       MCW_choose_multi_strlist( w , label , mcwCT_multi_mode ,
3166                                 num_dset , indold , strlist ,
3167                                 PLUG_finalize_dataset_CB , (XtPointer) plint ) ;
3168    } else {
3169       MCW_choose_strlist( w , label ,
3170                           num_dset , av->dset_choice , strlist ,
3171                           PLUG_finalize_dataset_CB , (XtPointer) plint ) ;
3172    }
3173 
3174    myXtFree(indold) ; myXtFree(old_chosen) ;
3175    EXRETURN ;
3176 }
3177 
3178 /*-----------------------------------------------------------------------
3179   Called when the user actually selects a dataset from the chooser.
3180   This routine just changes the original pushbutton label, and
3181   notes the index of the choice in the right place, for later retrieval.
3182 -------------------------------------------------------------------------*/
3183 
PLUG_finalize_dataset_CB(Widget w,XtPointer fd,MCW_choose_cbs * cbs)3184 void PLUG_finalize_dataset_CB( Widget w, XtPointer fd, MCW_choose_cbs * cbs )
3185 {
3186    PLUGIN_interface * plint = (PLUGIN_interface *) fd ;
3187    PLUGIN_dsetval   * av = NULL ;
3188    XmString           xstr ;
3189    int id ;
3190    char str[THD_MAX_NAME], *shrtit=NULL;
3191 
3192 ENTRY("PLUG_finalize_dataset_CB") ;
3193 
3194    /** find the stuff that is associated with this button **/
3195 
3196    XtVaGetValues( w , XmNuserData , &av , NULL ) ;
3197    if( plint == NULL || av == NULL ) EXRETURN ;
3198 
3199    shrtit = TrimString(av->dset_link[cbs->ival].title, 20); /* ZSS Jan 2012*/
3200    if( ! av->multi ){
3201       xstr = XmStringCreateLtoR( shrtit ,
3202                                  XmFONTLIST_DEFAULT_TAG ) ;
3203    } else {
3204       sprintf( str , "[%d]%s" , cbs->nilist , shrtit ) ;
3205       xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
3206    }
3207    XtVaSetValues( w , XmNlabelString , xstr , NULL ) ;
3208    XmStringFree( xstr ) ;
3209 
3210    if( ! av->multi ){
3211       av->dset_choice = cbs->ival ;
3212    } else {
3213       av->nchosen = cbs->nilist ;
3214       av->chosen  = (int *) XtRealloc( (char *) av->chosen ,
3215                                        sizeof(int) * av->nchosen ) ;
3216       for( id=0 ; id < av->nchosen ; id++ ) av->chosen[id] = cbs->ilist[id] ;
3217    }
3218 
3219    EXRETURN ;
3220 }
3221 
3222 /*-----------------------------------------------------------------------
3223   Fill in a PLUGIN_dataset_link
3224 -------------------------------------------------------------------------*/
3225 
make_PLUGIN_dataset_link(THD_3dim_dataset * dset,PLUGIN_dataset_link * dsl)3226 void make_PLUGIN_dataset_link( THD_3dim_dataset * dset ,
3227                                PLUGIN_dataset_link * dsl )
3228 {
3229    char nam[THD_MAX_NAME+2048] ;
3230    char * tnam ;
3231 
3232 ENTRY("make_PLUGIN_dataset_link") ;
3233 
3234    /*-- sanity checks --*/
3235 
3236    if( dsl == NULL ) EXRETURN ;
3237 
3238    if( ! ISVALID_3DIM_DATASET(dset) ){  /* should not happen */
3239       strcpy( dsl->title , "* garbage :( *" ) ;
3240       ZERO_IDCODE( dsl->idcode ) ;
3241       EXRETURN ;
3242    }
3243 
3244    /*-- make title (cf. AFNI_set_window_titles) --*/
3245 
3246    strcpy( nam , dset->dblk->diskptr->directory_name ) ;
3247    strcat( nam , dset->dblk->diskptr->filecode ) ;
3248    tnam = THD_trailname(nam,SESSTRAIL+1) ;
3249    MCW_strncpy( dsl->title , tnam , PLUGIN_STRING_SIZE ) ;
3250 
3251    /*-- copy idcode --*/
3252 
3253    dsl->idcode = dset->idcode ;
3254 
3255    EXRETURN ;
3256 }
3257 
3258 /*-----------------------------------------------------------------------
3259   Determine if a dataset passes the type_mask and ctrl_mask
3260   criteria for acceptability.
3261 -------------------------------------------------------------------------*/
3262 
PLUTO_dset_check(int anat_mask,int func_mask,int ctrl_mask,THD_3dim_dataset * dset)3263 int PLUTO_dset_check( int anat_mask, int func_mask,
3264                       int ctrl_mask, THD_3dim_dataset * dset )
3265 {
3266    int iv=0 ;
3267 
3268    if( ISANAT(dset) )
3269       iv = PLUGIN_dset_check( anat_mask , ctrl_mask , dset ) ;
3270    else if( ISFUNC(dset) )
3271       iv = PLUGIN_dset_check( func_mask , ctrl_mask , dset ) ;
3272 
3273    return iv ;
3274 }
3275 
PLUGIN_dset_check(int type_mask,int ctrl_mask,THD_3dim_dataset * dset)3276 int PLUGIN_dset_check( int type_mask , int ctrl_mask , THD_3dim_dataset * dset )
3277 {
3278    int itmp ;
3279 
3280 ENTRY("PLUGIN_dset_check") ;
3281 
3282    if( ! ISVALID_3DIM_DATASET(dset) ) RETURN(0) ;
3283 
3284    if( ((1 << dset->func_type) & type_mask) == 0 ) RETURN(0) ;
3285 
3286    itmp = (DSET_NVALS(dset) > 1) ? DIMEN_4D_MASK : DIMEN_3D_MASK ;
3287    if( (itmp & ctrl_mask) == 0 ) RETURN(0) ;
3288 
3289    if( !DSET_INMEMORY(dset) && (ctrl_mask & WARP_ON_DEMAND_MASK) == 0 ) RETURN(0) ;
3290 
3291    itmp = DSET_PRINCIPAL_VALUE(dset) ;  /* get the type of */
3292    itmp = DSET_BRICK_TYPE(dset,itmp) ;  /* the "principal" brick */
3293 
3294    if( itmp == MRI_byte    && (ctrl_mask & BRICK_BYTE_MASK)    == 0 ) RETURN(0) ;
3295    if( itmp == MRI_short   && (ctrl_mask & BRICK_SHORT_MASK)   == 0 ) RETURN(0) ;
3296    if( itmp == MRI_float   && (ctrl_mask & BRICK_FLOAT_MASK)   == 0 ) RETURN(0) ;
3297    if( itmp == MRI_complex && (ctrl_mask & BRICK_COMPLEX_MASK) == 0 ) RETURN(0) ;
3298    if( itmp == MRI_rgb     && (ctrl_mask & BRICK_RGB_MASK)     == 0 ) RETURN(0) ;
3299 
3300    RETURN(1) ;
3301 }
3302 
3303 /*-------------------------------------------------------------------------
3304    Loop over a bunch of dataset links and patch their
3305    titles to include an indicator of the dataset type, etc.
3306    23 October 1998 -- RWCox
3307 ---------------------------------------------------------------------------*/
3308 
patch_PLUGIN_dataset_links(int ndsl,PLUGIN_dataset_link * dsl)3309 void patch_PLUGIN_dataset_links( int ndsl , PLUGIN_dataset_link * dsl )
3310 {
3311    int id , ltop , llen ;
3312    char qnam[THD_MAX_NAME] ;
3313    THD_3dim_dataset * dset ;
3314 
3315 ENTRY("patch_PLUGIN_dataset_links") ;
3316 
3317    if( ndsl < 1 || dsl == NULL ) EXRETURN ;
3318 
3319    ltop = 4 ;
3320    for( id=0 ; id < ndsl ; id++ ){    /* find longest string */
3321       llen = strlen(dsl[id].title) ;
3322       ltop = MAX(ltop,llen) ;
3323    }
3324 
3325    /* patch each title string */
3326 
3327    for( id=0 ; id < ndsl ; id++ ){
3328       dset = PLUTO_find_dset( &(dsl[id].idcode) ) ;  /* get the dataset */
3329       if( ! ISVALID_3DIM_DATASET(dset) ) continue ;  /* bad news for Bozo */
3330 
3331       if( ISANAT(dset) ){
3332          if( ISANATBUCKET(dset) )         /* 30 Nov 1997 */
3333             sprintf(qnam,"%-*s [%s:%d]" ,
3334                     ltop,dsl[id].title ,
3335                     ANAT_prefixstr[dset->func_type] , DSET_NVALS(dset) ) ;
3336 
3337          else if( DSET_NUM_TIMES(dset) == 1 )
3338             sprintf(qnam,"%-*s [%s]" ,
3339                     ltop,dsl[id].title ,
3340                     ANAT_prefixstr[dset->func_type] ) ;
3341 
3342          else
3343             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
3344                     ltop,dsl[id].title ,
3345                     ANAT_prefixstr[dset->func_type] , DSET_NUM_TIMES(dset) ) ;
3346 
3347       } else {
3348          if( ISFUNCBUCKET(dset) )         /* 30 Nov 1997 */
3349             sprintf(qnam,"%-*s [%s:%d]" ,
3350                     ltop,dsl[id].title ,
3351                     FUNC_prefixstr[dset->func_type] , DSET_NVALS(dset) ) ;
3352 
3353          else if( DSET_NUM_TIMES(dset) == 1 )
3354             sprintf(qnam,"%-*s [%s]" ,
3355                     ltop,dsl[id].title ,
3356                     FUNC_prefixstr[dset->func_type] ) ;
3357 
3358          else
3359             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
3360                     ltop,dsl[id].title ,
3361                     FUNC_prefixstr[dset->func_type] , DSET_NVALS(dset) ) ;
3362       }
3363 
3364       if( DSET_COMPRESSED(dset) ) strcat(qnam,"z") ;
3365 
3366       strcpy( dsl[id].title , qnam ) ;
3367    }
3368 
3369    EXRETURN ;
3370 }
3371 
3372 /*------------------------------------------------------------------------
3373    Popup a chooser list of datasets that meet some criteria.
3374    Note that only one such chooser will be popped up at any given time.
3375    This routine is for use in user-written plugins with custom interfaces.
3376    23 October 1998 -- RWCox
3377 
3378    w = widget to popup near
3379 
3380    vv = view type of datasets (cf. VIEW_*_TYPE from 3ddata.h)
3381            [one way to select this is plint->im3d->vinfo->view_type]
3382 
3383    multi = 1 to allow selection of multiple datasets
3384          = 0 to allow selection of only 1 dataset at a time
3385 
3386    chk_func = int function( THD_3dim_dataset * dset, void * cd ) ;
3387                 If this function pointer is not NULL, it will be called to
3388                 check if each dataset should be allowed in.  A zero return
3389                 value means don't allow; any other return value means dset
3390                 will be in the displayed list.  If chk_func is NULL, then
3391                 all datasets known to AFNI will be allowed.  [The function
3392                 PLUTO_dset_check() may be useful inside chk_func.]
3393 
3394    cb_func  = void function( int num, THD_3dim_dataset ** dslist, void * cd ) ;
3395                 This function pointer must not be NULL.  It will be called
3396                 when the user makes a choice on the popup chooser.
3397                 The value num will be the number of datasets chosen.
3398                 dslist[i] will be a pointer to the i-th dataset, for
3399                 i=0..num-1.  If multi was 0, then num will be 1 and the
3400                 single selected dataset will be pointed to by dlist[0].
3401 
3402    cd = A pointer to anything the user likes.  It will be passed to
3403           chk_func and cb_func, as described above.  (Can be NULL.)
3404 --------------------------------------------------------------------------*/
3405 
3406 static int                   num_user_dset     = 0 ;
3407 static PLUGIN_dataset_link * user_dset_link    = NULL ;
3408 static char **               user_dset_strlist = NULL ;
3409 static int                   user_dset_numds   = 0 ;
3410 static THD_3dim_dataset **   user_dset_dslist  = NULL ;
3411 static void_func *           user_dset_cb_func = NULL ;
3412 static void *                user_dset_cb_data = NULL ;
3413 
PLUTO_popup_dset_chooser(Widget w,int vv,int multi,int_func * chk_func,void_func * cb_func,void * cd)3414 void PLUTO_popup_dset_chooser( Widget w , int vv , int multi ,
3415                                int_func * chk_func ,
3416                                void_func * cb_func , void * cd )
3417 {
3418    THD_session * ss ;
3419    THD_3dim_dataset * dset ;
3420    int iss_bot , iss_top , iss ;
3421    int id ;
3422    char label[64] ;
3423 
3424 ENTRY("PLUTO_popup_dset_chooser") ;
3425 
3426    if( w == NULL            || cb_func == NULL     ||
3427        vv < FIRST_VIEW_TYPE || vv > LAST_VIEW_TYPE   ) EXRETURN ;
3428 
3429    /** Scan sessions **/
3430 
3431    iss_bot  = 0 ;
3432    iss_top  = GLOBAL_library.sslist->num_sess - 1 ;
3433    num_user_dset = 0 ;
3434 
3435    for( iss=iss_bot ; iss <= iss_top ; iss++ ){
3436       ss = GLOBAL_library.sslist->ssar[iss] ;
3437 
3438       /* check datasets from this session */
3439 
3440       for( id=0 ; id < ss->num_dsset ; id++ ){
3441          dset = GET_SESSION_DSET(ss, id, vv);
3442          /* dset = ss->dsset_xform_table[id][vv] ; */
3443          if( dset == NULL ) continue ;
3444 #if 0
3445          if( chk_func != NULL && chk_func(dset,cd) == 0 ) continue ; /* skip */
3446 #else
3447          { int cval=1 ;
3448            AFNI_CALL_VALU_2ARG( chk_func ,
3449                                 int,cval , THD_3dim_dataset *,dset, void *,cd ) ;
3450            if( cval == 0 ) continue ;
3451          }
3452 #endif
3453 
3454          num_user_dset++ ;
3455          user_dset_link = (PLUGIN_dataset_link *)
3456                           XtRealloc( (char *) user_dset_link ,
3457                                      sizeof(PLUGIN_dataset_link)*num_user_dset ) ;
3458 
3459          make_PLUGIN_dataset_link( dset , user_dset_link + (num_user_dset-1) ) ;
3460 
3461       } /* end of loop over datasets */
3462 
3463    } /* end of loop over sessions */
3464 
3465    /*--- if nothing was found that fits, then nothing further can happen ---*/
3466 
3467    if( num_user_dset == 0 ){
3468       myXtFree(user_dset_link) ; BEEPIT ;
3469       MCW_popup_message( w ,
3470                         "No datasets that meet this\ncriterion are available!" ,
3471                         MCW_USER_KILL|MCW_TIMER_KILL ) ;
3472       EXRETURN ;
3473    }
3474 
3475    /*--- make a popup chooser for the user to browse ---*/
3476 
3477    POPDOWN_strlist_chooser ;  /* death to the old regime */
3478 
3479    /* fix the dataset titles to be more fun */
3480 
3481    patch_PLUGIN_dataset_links( num_user_dset , user_dset_link ) ;
3482 
3483    /* make an array of pointers to all the titles */
3484 
3485    user_dset_strlist = (char **) XtRealloc( (char *) user_dset_strlist ,
3486                                             sizeof(char *) * num_user_dset ) ;
3487    for( id=0 ; id < num_user_dset ; id++ )
3488       user_dset_strlist[id] = user_dset_link[id].title ;
3489 
3490    /* label for the top of the chooser */
3491 
3492    sprintf( label , "AFNI Dataset from\nthe %s" , VIEW_typestr[vv] ) ;
3493 
3494    /* and take it away, Goldie */
3495 
3496    user_dset_cb_func = cb_func ;
3497    user_dset_cb_data = cd ;
3498 
3499    if( multi ){
3500       MCW_choose_multi_strlist( w , label , mcwCT_multi_mode ,
3501                                 num_user_dset , NULL , user_dset_strlist ,
3502                                 PLUG_finalize_user_dset_CB , NULL ) ;
3503    } else {
3504       MCW_choose_strlist( w , label ,
3505                           num_user_dset , -1 , user_dset_strlist ,
3506                           PLUG_finalize_user_dset_CB , NULL ) ;
3507    }
3508 
3509    EXRETURN ;
3510 }
3511 
3512 /*-----------------------------------------------------------------------
3513    Called when the user actually selects a dataset from the chooser.
3514    Will call the user's pitiful and loathsome routine.
3515    23 October 1998 -- RWCox
3516 -------------------------------------------------------------------------*/
3517 
PLUG_finalize_user_dset_CB(Widget w,XtPointer fd,MCW_choose_cbs * cbs)3518 void PLUG_finalize_user_dset_CB( Widget w, XtPointer fd, MCW_choose_cbs * cbs )
3519 {
3520    int id , jd , num ;
3521 
3522 ENTRY("PLUG_finalize_user_dset_CB") ;
3523 
3524    if( cbs == NULL || cbs->nilist < 1 ) EXRETURN ;
3525 
3526    user_dset_numds = num = cbs->nilist ;
3527 
3528    user_dset_dslist = (THD_3dim_dataset **)
3529                          XtRealloc( (char *) user_dset_dslist ,
3530                                     sizeof(THD_3dim_dataset *) * num ) ;
3531 
3532    for( id=0 ; id < num ; id++ ){
3533       jd = cbs->ilist[id] ;
3534       user_dset_dslist[id] = PLUTO_find_dset( &(user_dset_link[jd].idcode) ) ;
3535    }
3536 
3537 #if 0
3538    user_dset_cb_func( num , user_dset_dslist , user_dset_cb_data ) ;
3539 #else
3540    AFNI_CALL_VOID_3ARG( user_dset_cb_func ,
3541                         int,num , THD_3dim_dataset **,user_dset_dslist ,
3542                         void *,user_dset_cb_data ) ;
3543 #endif
3544 
3545    EXRETURN ;
3546 }
3547 
3548 /*----------------------------------------------------------------------
3549    What happens when a timeseries chooser button is pressed:
3550      Popup a timeseries chooser window.
3551 ------------------------------------------------------------------------*/
3552 
PLUG_choose_timeseries_CB(Widget w,XtPointer cd,XtPointer cbs)3553 void PLUG_choose_timeseries_CB( Widget w , XtPointer cd , XtPointer cbs )
3554 {
3555    PLUGIN_interface * plint = (PLUGIN_interface *) cd ;
3556    PLUGIN_tsval     * av = NULL ;
3557    PLUGIN_subvalue  * sv = NULL ;
3558    Three_D_View     * im3d ;
3559    int init_ts ;
3560 
3561 ENTRY("PLUG_choose_timeseries_CB") ;
3562 
3563    /** find the stuff that is associated with this button **/
3564 
3565    XtVaGetValues( w , XmNuserData , &av , NULL ) ;
3566 
3567    if( plint == NULL || av == NULL ) EXRETURN ;
3568    sv = av->sv ;
3569    if( sv == NULL ) EXRETURN ;
3570    im3d = plint->im3d ;
3571 
3572    av->tsimar = GLOBAL_library.timeseries ; /* to choose amongst */
3573    if( av->tsimar==NULL || IMARR_COUNT(av->tsimar)==0 ){
3574       av->ts_choice = -1 ;
3575       av->tsim      = NULL ;
3576       BEEPIT ; EXRETURN ;
3577    }
3578 
3579    init_ts = AFNI_ts_in_library( av->tsim ) ;
3580 
3581    MCW_choose_timeseries( w , "Choose Timeseries" ,
3582                           av->tsimar , init_ts ,
3583                           PLUG_finalize_timeseries_CB , (XtPointer) plint ) ;
3584 
3585    EXRETURN ;
3586 }
3587 
3588 /*----------------------------------------------------------------------
3589    What happens when a tcsv chooser button is pressed:
3590      Popup a tcsv chooser window.
3591 ------------------------------------------------------------------------*/
3592 
PLUG_choose_tcsv_CB(Widget w,XtPointer cd,XtPointer cbs)3593 void PLUG_choose_tcsv_CB( Widget w , XtPointer cd , XtPointer cbs )
3594 {
3595    PLUGIN_interface * plint = (PLUGIN_interface *) cd ;
3596    PLUGIN_tcsvval   * av = NULL ;
3597    PLUGIN_subvalue  * sv = NULL ;
3598    Three_D_View     * im3d ;
3599    int init_ts ;
3600 
3601 ENTRY("PLUG_choose_tcsv_CB") ;
3602 
3603    /** find the stuff that is associated with this button **/
3604 
3605    XtVaGetValues( w , XmNuserData , &av , NULL ) ;
3606 
3607    if( plint == NULL || av == NULL ) EXRETURN ;
3608    sv = av->sv ;
3609    if( sv == NULL ) EXRETURN ;
3610    im3d = plint->im3d ;
3611 
3612    av->elarr = GLOBAL_library.tcsv_data ; /* to choose amongst */
3613    if( av->elarr==NULL || ELARR_COUNT(av->elarr)==0 ){
3614       av->tcsv_choice = -1 ;
3615       av->tcsv_el     = NULL ;
3616       BEEPIT ; EXRETURN ;
3617    }
3618 
3619 #if 0
3620    init_ts = AFNI_ts_in_library( av->tsim ) ;
3621 #else
3622    init_ts = -1 ;
3623 #endif
3624 
3625    MCW_choose_tcsv( w , "Choose Timeseries" ,
3626                           av->elarr , init_ts ,
3627                           PLUG_finalize_tcsv_CB , (XtPointer) plint ) ;
3628 
3629    EXRETURN ;
3630 }
3631 
3632 /*-----------------------------------------------------------------------
3633   Called when the user actually selects a timeseries from the chooser.
3634   This routine just changes the original pushbutton label, and
3635   notes the index of the choice in the right place, for later retrieval.
3636 -------------------------------------------------------------------------*/
3637 
PLUG_finalize_timeseries_CB(Widget w,XtPointer fd,MCW_choose_cbs * cbs)3638 void PLUG_finalize_timeseries_CB( Widget w, XtPointer fd, MCW_choose_cbs * cbs )
3639 {
3640    PLUGIN_interface * plint = (PLUGIN_interface *) fd ;
3641    PLUGIN_tsval     * av = NULL ;
3642    XmString           xstr ;
3643    int                its ;
3644 
3645 ENTRY("PLUG_finalize_timeseries_CB") ;
3646 
3647    /** find the stuff that is associated with this button **/
3648 
3649    XtVaGetValues( w , XmNuserData , &av , NULL ) ;
3650    if( plint == NULL || av == NULL || av->tsimar == NULL ) EXRETURN ;
3651    if( cbs->reason != mcwCR_timeseries ) EXRETURN ;  /* error */
3652 
3653    /** store the choice, and change the widget label **/
3654 
3655    its = cbs->ival ;
3656    if( its >= 0 && its < IMARR_COUNT(av->tsimar) ){
3657       av->tsim      = IMARR_SUBIMAGE(av->tsimar,its) ;
3658       av->ts_choice = its ;
3659 
3660       xstr = XmStringCreateLtoR( av->tsim->name , XmFONTLIST_DEFAULT_TAG ) ;
3661       XtVaSetValues( w , XmNlabelString , xstr , NULL ) ;
3662       XmStringFree( xstr ) ;
3663    }
3664 
3665    EXRETURN ;
3666 }
3667 
3668 /*-----------------------------------------------------------------------
3669   Called when the user actually selects a tcsv from the chooser.
3670   This routine just changes the original pushbutton label, and
3671   notes the index of the choice in the right place, for later retrieval.
3672 -------------------------------------------------------------------------*/
3673 
PLUG_finalize_tcsv_CB(Widget w,XtPointer fd,MCW_choose_cbs * cbs)3674 void PLUG_finalize_tcsv_CB( Widget w, XtPointer fd, MCW_choose_cbs * cbs )
3675 {
3676    PLUGIN_interface * plint = (PLUGIN_interface *) fd ;
3677    PLUGIN_tcsvval   * av = NULL ;
3678    XmString           xstr ;
3679    int                its ;
3680 
3681 ENTRY("PLUG_finalize_tcsv_CB") ;
3682 
3683    /** find the stuff that is associated with this button **/
3684 
3685    XtVaGetValues( w , XmNuserData , &av , NULL ) ;
3686    if( plint == NULL || av == NULL || av->elarr == NULL ) EXRETURN ;
3687    if( cbs->reason != mcwCR_tcsv ) EXRETURN ;  /* error */
3688 
3689    /** store the choice, and change the widget label **/
3690 
3691    its = cbs->ival ;
3692    if( its >= 0 && its < ELARR_COUNT(av->elarr) ){
3693       av->tcsv_el     = ELARR_SUBEL(av->elarr,its) ;
3694       av->tcsv_choice = its ;
3695 
3696       xstr = XmStringCreateLtoR( av->tcsv_el->filename , XmFONTLIST_DEFAULT_TAG ) ;
3697       XtVaSetValues( w , XmNlabelString , xstr , NULL ) ;
3698       XmStringFree( xstr ) ;
3699    }
3700 
3701    EXRETURN ;
3702 }
3703 
3704 /********************************************************************************
3705    Routine to interface to AFNI, after plugins are read in.
3706 *********************************************************************************/
3707 
AFNI_plugin_button(Three_D_View * im3d)3708 void AFNI_plugin_button( Three_D_View * im3d )
3709 {
3710    AFNI_plugin_array * exten = GLOBAL_library.plugins ;
3711    AFNI_plugin * plug ;
3712    int pp , ipl , nbut , npbut , kpl ;
3713    Widget rc , mbar , menu , cbut , pbut , wpar , sep ;
3714    XmString xstr ;
3715    PLUGIN_interface ** plintar ;  /* 28 Nov 2000 */
3716 
3717 ENTRY("AFNI_plugin_button") ;
3718 
3719    /*-- check inputs for legality --*/
3720 
3721    if( exten == NULL      ||
3722        ! IM3D_VALID(im3d) || im3d->type != AFNI_3DDATA_VIEW ) EXRETURN ;
3723 
3724    /*-- 23 Sep 2000: count number of buttons that will be made --*/
3725 
3726    npbut = 0 ;
3727    for( pp=0 ; pp < exten->num ; pp++ ){
3728       plug = exten->plar[pp] ;
3729       for( ipl=0 ; ipl < plug->interface_count ; ipl++ ){
3730          npbut++ ;
3731       }
3732    }
3733 
3734    /*-- make arrays to hold the plugin buttons (etc.),
3735         so that plugins can be started from layouts (in afni_splash.c) --*/
3736 
3737    /* from malloc    12 Feb 2009 [lesstif patrol] */
3738    im3d->vwid->nplugbut = npbut ;
3739    im3d->vwid->plugbut  = (Widget *)            calloc(1, sizeof(Widget)            *npbut) ;
3740    im3d->vwid->pluglab  = (char **)             calloc(1, sizeof(char *)            *npbut) ;
3741    im3d->vwid->plugint  = (PLUGIN_interface **) calloc(1, sizeof(PLUGIN_interface *)*npbut) ;
3742 
3743    /*-- create menu bar --*/
3744 
3745    wpar = im3d->vwid->dmode->mbar_rowcol ;
3746 
3747    rc =  XtVaCreateWidget(
3748            "dialog" , xmRowColumnWidgetClass , wpar ,
3749               XmNorientation , XmHORIZONTAL ,
3750               XmNpacking , XmPACK_TIGHT ,
3751               XmNtraversalOn , True  ,
3752               XmNinitialResourcesPersistent , False ,
3753            NULL ) ;
3754 
3755    mbar = XmCreateMenuBar( rc , "dialog" , NULL,0 ) ;
3756    XtVaSetValues( mbar ,
3757                      XmNmarginWidth  , 0 ,
3758                      XmNmarginHeight , 0 ,
3759                      XmNspacing      , 3 ,
3760                      XmNborderWidth  , 0 ,
3761                      XmNborderColor  , 0 ,
3762                      XmNtraversalOn  , True  ,
3763                      XmNbackground   , im3d->dc->ovc->pixov_brightest ,
3764                   NULL ) ;
3765    XtManageChild( mbar ) ;
3766 
3767    menu = XmCreatePulldownMenu( mbar , "menu" , NULL,0 ) ;
3768 
3769    VISIBILIZE_WHEN_MAPPED(menu) ;
3770 #if 0
3771    if( !AFNI_yesenv("AFNI_DISABLE_TEAROFF") ) TEAROFFIZE(menu) ;
3772 #endif
3773 
3774    xstr = XmStringCreateLtoR( "Plugins" , XmFONTLIST_DEFAULT_TAG ) ;
3775    cbut = XtVaCreateManagedWidget(
3776             "dialog" , xmCascadeButtonWidgetClass , mbar ,
3777                XmNlabelString , xstr ,
3778                XmNsubMenuId , menu ,
3779                XmNmarginWidth  , 0 ,
3780                XmNmarginHeight , 0 ,
3781                XmNmarginBottom , 0 ,
3782                XmNmarginTop    , 0 ,
3783                XmNmarginRight  , 0 ,
3784                XmNmarginLeft   , 0 ,
3785                XmNtraversalOn  , True  ,
3786                XmNinitialResourcesPersistent , False ,
3787             NULL ) ;
3788    XmStringFree( xstr ) ;
3789 
3790    MCW_register_help( cbut , "Pressing this drops down\n"
3791                              "the menu of the plugin\n"
3792                              "programs loaded when\n"
3793                              "AFNI started."
3794                     ) ;
3795    MCW_register_hint( cbut , "Plugins menu" ) ;
3796 
3797    /* macro to create a new menu button */
3798 
3799 #define MENU_BUT(pl)                                                      \
3800    do{                                                                    \
3801       xstr = XmStringCreateLtoR( (pl)->label , XmFONTLIST_DEFAULT_TAG ) ; \
3802       pbut = XtVaCreateManagedWidget(                                     \
3803                "dialog" , xmPushButtonWidgetClass , menu ,                \
3804                   XmNlabelString , xstr ,                                 \
3805                   XmNmarginHeight , 0 ,                                   \
3806                   XmNuserData , (XtPointer) im3d ,                        \
3807                   XmNtraversalOn , True  ,                                \
3808                   XmNinitialResourcesPersistent , False ,                 \
3809                NULL ) ;                                                   \
3810       im3d->vwid->plugbut[npbut] = pbut ;            /* 23 Sep 2000 */    \
3811       im3d->vwid->plugint[npbut] = (pl) ;                                 \
3812       im3d->vwid->pluglab[npbut] = XtNewString((pl)->label) ;             \
3813       XtAddCallback( pbut , XmNactivateCallback ,                         \
3814                      PLUG_startup_plugin_CB , (XtPointer)(pl) ) ;         \
3815       XmStringFree(xstr) ;                                                \
3816       if( (pl)->hint != NULL ) MCW_register_hint( pbut , (pl)->hint ) ;   \
3817       if( (pl)->butcolor[0] != '\0' )                                     \
3818          MCW_set_widget_bg( pbut , (pl)->butcolor , 0 ) ;                 \
3819    } while(0)
3820 
3821    /*** top of menu = a label to click on that does nothing at all ***/
3822 
3823    xstr = XmStringCreateLtoR( "-- Cancel --" , XmFONTLIST_DEFAULT_TAG ) ;
3824    wtemp = XtVaCreateManagedWidget(
3825             "dialog" , xmLabelWidgetClass , menu ,
3826                XmNlabelString , xstr ,
3827                XmNrecomputeSize , False ,
3828                XmNinitialResourcesPersistent , False ,
3829             NULL ) ;
3830    XmStringFree(xstr) ; LABELIZE(wtemp) ;
3831 
3832    sep = XtVaCreateManagedWidget(
3833             "dialog" , xmSeparatorWidgetClass , menu ,
3834                XmNseparatorType , XmSINGLE_LINE ,
3835             NULL ) ;
3836 
3837    /*-- 28 Nov 2000: allow user to specify that
3838                      button should be alphabetized --*/
3839 
3840    /* make single array of all plugin interfaces */
3841 
3842    plintar = (PLUGIN_interface **) malloc(sizeof(PLUGIN_interface *)*npbut) ;
3843    for( kpl=pp=0 ; pp < exten->num ; pp++ ){
3844       plug = exten->plar[pp] ;
3845       for( ipl=0 ; ipl < plug->interface_count ; ipl++ ){
3846          plintar[kpl++] = plug->interface[ipl] ;
3847       }
3848    }
3849 
3850    /* sort this array, if desired */
3851 
3852    if( !AFNI_noenv("AFNI_PLUGINS_ALPHABETIZE") ){
3853       int qq , ss ;
3854       PLUGIN_interface * tpl ;
3855 
3856       do{                                       /* bubble sort */
3857         for( ss=qq=0 ; qq < npbut-1 ; qq++ ){
3858            if( strcasecmp(plintar[qq]->label,plintar[qq+1]->label) > 0 ){
3859              tpl           = plintar[qq+1] ;
3860              plintar[qq+1] = plintar[qq] ;
3861              plintar[qq]   = tpl ;
3862              ss++ ;
3863            }
3864         }
3865       } while( ss ) ;
3866    }
3867 
3868    /*-- prepare to make the actual buttons --*/
3869 
3870    nbut  = 2 ;  /* allow for the Cancel label and separator */
3871    npbut = 0 ;  /* actual number of buttons */
3872 
3873    /*** make buttons for each interface ***/
3874 
3875    for( kpl=pp=0 ; pp < exten->num ; pp++ ){
3876       plug = exten->plar[pp] ;
3877       for( ipl=0 ; ipl < plug->interface_count ; ipl++ ){
3878          MENU_BUT( plintar[kpl] ) ;  /* uses npbut */
3879          nbut++ ; npbut++ ; kpl++ ;
3880       }
3881    }
3882 
3883    free(plintar) ;  /* don't need no more */
3884 
3885    if( nbut > COLSIZE ){
3886       int ncol = (nbut-2)/COLSIZE + 1 ;
3887       XtDestroyWidget(sep) ;
3888       XtVaSetValues( menu ,
3889                         XmNpacking , XmPACK_COLUMN ,
3890                         XmNnumColumns , ncol ,
3891                      NULL ) ;
3892    }
3893 
3894    XtManageChild( rc ) ;
3895    EXRETURN ;
3896 }
3897 
3898 /*------------------------------------------------------------------------
3899    Routine that actually starts up a plugin when the user makes
3900    his or her choice from the menu created above.
3901 --------------------------------------------------------------------------*/
3902 
PLUG_startup_plugin_CB(Widget w,XtPointer cd,XtPointer cbd)3903 void PLUG_startup_plugin_CB( Widget w , XtPointer cd , XtPointer cbd )
3904 {
3905    PLUGIN_interface *plint = (PLUGIN_interface *) cd ;
3906    XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) cbd ;
3907    char *mesg=NULL ;
3908    Widget wpop ;
3909    Three_D_View *im3d = NULL ;
3910 
3911 ENTRY("PLUG_startup_plugin_CB") ;
3912 
3913    if( plint == NULL ) EXRETURN ;  /* error? */
3914 
3915    if( w != NULL ){
3916      XtVaGetValues( w , XmNuserData , &im3d , NULL ) ;  /* set controller from */
3917      plint->im3d = im3d ;                               /* data on menu button */
3918    } else if( cbs != NULL ){                            /* 21 Jul 2003 */
3919      plint->im3d = (Three_D_View *) cbs ;
3920      cbs = NULL ;
3921    }
3922    if( plint->im3d == NULL ) plint->im3d = AFNI_find_open_controller() ;
3923 
3924    /*-- if no interface is needed, just call it --*/
3925 
3926    if( plint->call_method == PLUGIN_CALL_IMMEDIATELY ){
3927 
3928 STATUS("calling plugin") ;
3929 
3930       MPROBE ;
3931 
3932       SHOW_AFNI_PAUSE ;
3933 #if 0
3934       mesg = plint->call_func( plint ) ;
3935 #else
3936       AFNI_CALL_VALU_1ARG( plint->call_func ,
3937                            char *,mesg , PLUGIN_interface *,plint ) ;
3938 #endif
3939       SHOW_AFNI_READY ;
3940 
3941       MPROBE ;
3942 
3943       if( mesg != NULL ){
3944          if( w != NULL ){
3945             (void) MCW_popup_message( w , mesg , MCW_USER_KILL ) ;
3946             BEEPIT ;
3947          } else {
3948             fprintf(stderr,"\n%s\a\n",mesg) ;
3949          }
3950       }
3951       EXRETURN ;
3952    }
3953 
3954    /*-- if widgets not created yet, create them now --*/
3955 
3956    if( plint->wid == NULL )
3957       PLUG_setup_widgets( plint , GLOBAL_library.dc ) ;
3958 
3959    /*-- set labels to go on shell widget and icon;
3960         include the [] controller window index, if possible --*/
3961 
3962    { char ttl[PLUGIN_STRING_SIZE] ;
3963 
3964      sprintf(ttl , "%s%s" , AFNI_controller_label(plint->im3d) , plint->label ) ;
3965 
3966      XtVaSetValues( plint->wid->shell ,
3967                        XmNtitle     , ttl , /* top of window */
3968                        XmNiconName  , ttl , /* label on icon */
3969                     NULL ) ;
3970    }
3971 
3972    /*-- if possible, find where this popup should go --*/
3973 
3974    wpop = plint->wid->shell ;
3975 
3976    if( cbs != NULL && cbs->event != NULL
3977                    && cbs->event->type == ButtonRelease ){
3978 
3979       XButtonEvent * xev = (XButtonEvent *) cbs->event ;
3980       int xx = (int)xev->x_root , yy = (int)xev->y_root ;
3981       int ww,hh , sw,sh ;
3982 
3983 STATUS("trying to position popup") ;
3984 
3985       MCW_widget_geom( wpop , &ww,&hh , NULL,NULL ) ; /* widget width and height */
3986       sw = WidthOfScreen (XtScreen(wpop)) ;           /* screen width and height */
3987       sh = HeightOfScreen(XtScreen(wpop)) ;
3988 
3989       if( xx+ww+3 >= sw && ww <= sw ) xx = sw-ww ;    /* make sure is on screen */
3990       if( yy+hh+3 >= sh && hh <= sh ) yy = sh-hh ;
3991 
3992       XtVaSetValues( wpop , XmNx , xx , XmNy , yy , NULL ) ;
3993    }
3994 
3995    /*-- popup the widgets that control this plugin --*/
3996 
3997 STATUS("popping up interface") ;
3998 
3999    XtMapWidget( wpop ) ;
4000    RWC_visibilize_widget( wpop ) ; /* 27 Sep 2000 */
4001    PLUTO_cursorize( plint->wid->shell ) ;
4002    EXRETURN ;
4003 }
4004 
4005 /*---------------------------------------------------------------------------
4006    Routine to add a dataset to the AFNI global collection.
4007    Return value is 0 if all is OK, 1 if bad things happened.
4008    "action_flag" is the OR (|) of various possibilities:
4009       DSET_ACTION_NONE         == do nothing
4010       DSET_ACTION_MAKE_CURRENT == make this the currently viewed dataset
4011 -----------------------------------------------------------------------------*/
4012 
PLUTO_add_dset(PLUGIN_interface * plint,THD_3dim_dataset * dset,int action_flag)4013 int PLUTO_add_dset( PLUGIN_interface *plint ,
4014                     THD_3dim_dataset *dset , int action_flag )
4015 {
4016    Three_D_View *im3d ;
4017    THD_session *sess ;
4018    int iss , vv , id ;
4019    int make_current = (action_flag & DSET_ACTION_MAKE_CURRENT) ;
4020 
4021 ENTRY("PLUTO_add_dset") ;
4022 
4023    /** sanity check **/
4024 
4025    if( plint == NULL || ! ISVALID_3DIM_DATASET(dset) ) RETURN(1) ;
4026 
4027    /** find some indices **/
4028 
4029    im3d = plint->im3d ;
4030    iss  = IM3D_VALID(im3d) ? im3d->vinfo->sess_num : 0 ;
4031    sess = GLOBAL_library.sslist->ssar[iss] ;
4032    vv   = dset->view_type ;
4033 
4034    /** add the dataset to the session **/
4035 
4036    id = sess->num_dsset ;
4037    if( id >= THD_MAX_SESSION_SIZE ){
4038      fprintf(stderr,"*** Overflow session dataset limit ***\n") ;
4039      RETURN(1) ;
4040    }
4041    SET_SESSION_DSET(dset, sess, id, vv);
4042 
4043 /*   sess->dsset_xform_table[id][vv] = dset ; */
4044    sess->num_dsset ++ ;
4045 
4046    /** make sure the dataset is properly fit into the situation **/
4047 
4048    POPDOWN_strlist_chooser ;  /* added dataset --> old choosers are invalid */
4049 
4050 #if 0
4051    THD_load_statistics( dset ) ;
4052    THD_write_3dim_dataset( NULL,NULL , dset , True ) ;
4053 #else
4054    DSET_overwrite(dset) ;
4055 #endif
4056 
4057    if( dset->anat_parent == NULL )                          /* if() added 14 Dec 1999 */
4058      AFNI_force_adoption( sess , GLOBAL_argopt.warp_4D ) ;
4059 
4060    AFNI_make_descendants( GLOBAL_library.sslist ) ;
4061 
4062    /** if desired, jump to this puppy in the viewer **/
4063 
4064    if( make_current && IM3D_VALID(im3d) ){
4065      if( ISANAT(dset) )
4066        im3d->vinfo->anat_num = sess->num_dsset - 1 ;
4067      else
4068        im3d->vinfo->func_num = sess->num_dsset - 1 ;
4069 
4070      AFNI_initialize_view( im3d->anat_now , im3d ) ;
4071    }
4072 
4073    THD_force_malloc_type( dset->dblk , DATABLOCK_MEM_ANY ) ;
4074    RETURN(0) ;
4075 }
4076 
4077 /*---------------------------------------------------------------------
4078    Routine to make a copy of a dataset, with data attached.
4079    [Moved into edt_fullcopy.c -- RWCox, 07 Oct 1998]
4080 -----------------------------------------------------------------------*/
4081 
PLUTO_copy_dset(THD_3dim_dataset * dset,char * new_prefix)4082 THD_3dim_dataset * PLUTO_copy_dset( THD_3dim_dataset * dset , char * new_prefix )
4083 {
4084    THD_3dim_dataset * new_dset ;
4085    int ival , ityp , nbytes , nvals ;
4086    void * new_brick , * old_brick ;
4087 
4088 ENTRY("PLUTO_copy_dset") ;
4089 
4090    new_dset = EDIT_full_copy( dset , new_prefix ) ;
4091    RETURN(new_dset) ;
4092 }
4093 
4094 /*----------------------------------------------------------------------
4095    Routine to force AFNI to redisplay controllers that are attached
4096    to a given dataset.  (Feb 1998)
4097 ------------------------------------------------------------------------*/
4098 
PLUTO_dset_redisplay(THD_3dim_dataset * dset)4099 void PLUTO_dset_redisplay( THD_3dim_dataset *dset )
4100 {
4101    PLUTO_dset_redisplay_mode( dset , REDISPLAY_OPTIONAL ) ;
4102 }
4103 
4104 /*---- 23 Oct 1998: superseded above routine with this one; RWCox -----*/
4105 
PLUTO_dset_redisplay_mode(THD_3dim_dataset * dset,int mode)4106 void PLUTO_dset_redisplay_mode( THD_3dim_dataset *dset , int mode )
4107 {
4108    Three_D_View * im3d ;
4109    int ii , amode , fmode ;
4110 
4111 ENTRY("PLUTO_dset_redisplay_mode") ;
4112 
4113    if( mode == REDISPLAY_OPTIONAL ){
4114       amode = REDISPLAY_ALL ;
4115       fmode = REDISPLAY_OVERLAY ;
4116    } else {
4117       amode = fmode = mode ;
4118    }
4119 
4120    for( ii=0 ; ii < MAX_CONTROLLERS ; ii++ ){
4121       im3d = GLOBAL_library.controllers[ii] ;
4122       if( ! IM3D_OPEN(im3d) ) continue ;
4123       IM3D_CLEAR_TMASK(im3d) ;
4124       IM3D_CLEAR_THRSTAT(im3d) ; /* 12 Jun 2014 */
4125 
4126       if( ! ISVALID_DSET(dset) ){
4127          im3d->anat_voxwarp->type = ILLEGAL_TYPE ;
4128          im3d->fim_voxwarp->type  = ILLEGAL_TYPE ;
4129          AFNI_reset_func_range( im3d ) ;
4130          IM3D_VEDIT_FORCE(im3d) ; /* 01 Feb 2008 */
4131          AFNI_set_viewpoint( im3d , -1,-1,-1 , REDISPLAY_ALL ) ;
4132       } else if( im3d->anat_now == dset ){
4133          im3d->anat_voxwarp->type = ILLEGAL_TYPE ;
4134          AFNI_reset_func_range( im3d ) ;
4135          AFNI_imseq_clearstat( im3d ) ;
4136          IM3D_VEDIT_FORCE(im3d) ; /* 01 Feb 2008 */
4137          AFNI_set_viewpoint( im3d , -1,-1,-1 , amode ) ;
4138       } else if( im3d->fim_now == dset ){
4139          im3d->fim_voxwarp->type = ILLEGAL_TYPE ;
4140          AFNI_reset_func_range( im3d ) ;
4141          AFNI_imseq_clearstat( im3d ) ;
4142          IM3D_VEDIT_FORCE(im3d) ; /* 01 Feb 2008 */
4143          AFNI_redisplay_func( im3d ) ;
4144       }
4145    }
4146    EXRETURN ;
4147 }
4148 
4149 /*----------------------------------------------------------------------
4150    Routine to inform AFNI that some dataset names are now different,
4151    so stuff should be done about it.
4152 ------------------------------------------------------------------------*/
4153 
PLUTO_fixup_names(void)4154 void PLUTO_fixup_names(void)
4155 {
4156    Three_D_View * im3d ;
4157    int ii ;
4158 
4159 ENTRY("PLUTO_fixup_names") ;
4160 
4161    POPDOWN_strlist_chooser ;  /* get rid of any dataset chooser that is open */
4162 
4163    for( ii=0 ; ii < MAX_CONTROLLERS ; ii++ ){
4164       im3d = GLOBAL_library.controllers[ii] ;
4165       if( IM3D_OPEN(im3d) )
4166          AFNI_set_window_titles( im3d ) ;
4167    }
4168    EXRETURN ;
4169 }
4170 
4171 /*-----------------------------------------------------------------------
4172    Let the user popup a message
4173 -------------------------------------------------------------------------*/
4174 
PLUTO_popup_worker(PLUGIN_interface * plint,char * mesg,int flag)4175 void PLUTO_popup_worker( PLUGIN_interface * plint , char * mesg , int flag )
4176 {
4177    Widget w = NULL ;
4178    Three_D_View * im3d ;
4179    int ii ;
4180 
4181 ENTRY("PLUTO_popup_worker") ;
4182 
4183    if( mesg == NULL || strlen(mesg) == 0 ) EXRETURN ;
4184 
4185    /* find a widget to popup next to */
4186 
4187    if( plint->wid != NULL && plint->wid->label != NULL ){
4188       w = plint->wid->label ;
4189    } else {
4190       im3d = plint->im3d ;
4191       if( !IM3D_OPEN(im3d) ) im3d = AFNI_find_open_controller() ;
4192       w = im3d->vwid->top_shell ;
4193    }
4194 
4195    if( w != NULL ){
4196       if( flag >= 0 )
4197          (void) MCW_popup_message( w , mesg , flag ) ;
4198       else
4199          (void) new_MCW_textwin( w , mesg , TEXT_READONLY ) ;
4200    } else {
4201       fprintf(stderr,"\n%s\a\n",mesg) ;
4202    }
4203 
4204    EXRETURN ;
4205 }
4206 
4207 /*------------------------------------------------------------------*/
4208 
PLUTO_beep(void)4209 void PLUTO_beep(void)
4210 {
4211    BEEPIT ; return ;
4212 }
4213 
4214 /*------------------------------------------------------------------*/
4215 
4216 #include <ctype.h>
4217 
PLUTO_strncmp(char * aa,char * bb,int nn)4218 static int PLUTO_strncmp( char * aa , char * bb , int nn ) /* 09 Oct 2000 */
4219 {
4220    int ii ;
4221 
4222    if( aa == bb )                 return 0 ;  /* special cases */
4223    if( aa == NULL || bb == NULL ) return 1 ;
4224 
4225    for( ii=0 ; ii < nn ; ii++,aa++,bb++ ){
4226       if( *aa == '\0'  && *bb == '\0' )  return 0 ; /* got to end all same! */
4227       if( *aa == '\0'  || *bb == '\0' )  return 1 ; /* premature end of one */
4228       if( isspace(*aa) || isspace(*bb) ) continue ; /* don't compare blanks */
4229       if( toupper(*aa) != toupper(*bb) ) return 1 ; /* case insensitive     */
4230    }
4231 
4232    return 0 ;                                       /* finished max # chars */
4233 }
4234 
4235 /*------------------------------------------------------------------*/
4236 
PLUTO_string_index(char * target,int num,char * source[])4237 int PLUTO_string_index( char * target , int num , char * source[] )
4238 {
4239    int ii ;
4240 
4241    if( num <= 0 || source == NULL || target == NULL ) return -1 ;
4242 
4243    for( ii=0 ; ii < num ; ii++ )
4244       if( PLUTO_strncmp(target,source[ii],PLUGIN_STRING_SIZE) == 0 ) return ii ;
4245 
4246    return -1 ;
4247 }
4248 
4249 /*-----------------------------------------------------------------------
4250   Function to let an IMMEDIATE mode plugin let AFNI know where its
4251   toplevel shell is -- 22 Sep 2000 -- RWCox.
4252 -------------------------------------------------------------------------*/
4253 
PLUTO_set_topshell(PLUGIN_interface * plint,Widget ts)4254 void PLUTO_set_topshell( PLUGIN_interface * plint , Widget ts )
4255 {
4256 ENTRY("PLUTO_set_topshell") ;
4257 
4258    if( plint == NULL                                ||
4259        plint->wid != NULL                           ||
4260        ts == (Widget) 0                             ||
4261        plint->call_method != PLUGIN_CALL_IMMEDIATELY  ) EXRETURN ;
4262 
4263    plint->wid        = myXtNew(PLUGIN_widgets) ;
4264    plint->wid->shell = ts ;
4265    plint->wid->meter = NULL ;
4266    EXRETURN ;
4267 }
4268 
4269 /*-----------------------------------------------------------------------
4270   Routines to put a progress meter on the top of the interface shell
4271 -------------------------------------------------------------------------*/
4272 
PLUTO_popup_meter(PLUGIN_interface * plint)4273 void PLUTO_popup_meter( PLUGIN_interface * plint )
4274 {
4275 ENTRY("PLUTO_popup_meter") ;
4276 
4277    if( plint == NULL             || plint->wid == NULL       ||
4278        plint->wid->shell == NULL || plint->wid->meter != NULL  ) EXRETURN ;
4279 
4280    plint->wid->meter = MCW_popup_meter( plint->wid->shell , METER_TOP_WIDE ) ;
4281    EXRETURN ;
4282 }
4283 
PLUTO_popdown_meter(PLUGIN_interface * plint)4284 void PLUTO_popdown_meter( PLUGIN_interface * plint )
4285 {
4286 ENTRY("PLUTO_popdown_meter") ;
4287 
4288    if( plint == NULL             || plint->wid == NULL       ||
4289        plint->wid->shell == NULL || plint->wid->meter == NULL  ) EXRETURN ;
4290 
4291    MCW_popdown_meter( plint->wid->meter ) ;
4292    plint->wid->meter = NULL ;
4293    EXRETURN ;
4294 }
4295 
PLUTO_set_meter(PLUGIN_interface * plint,int percent)4296 void PLUTO_set_meter( PLUGIN_interface * plint , int percent )
4297 {
4298 ENTRY("PLUTO_set_meter") ;
4299 
4300    if( plint == NULL             || plint->wid == NULL       ||
4301        plint->wid->shell == NULL || plint->wid->meter == NULL  ) EXRETURN ;
4302 
4303    MCW_set_meter( plint->wid->meter , percent ) ;
4304    EXRETURN ;
4305 }
4306 
4307 /*-----------------------------------------------------------------------
4308    Routine to popup an image.
4309    Inputs:
4310      handle = (a) value returned from previous call to this routine
4311               (b) or NULL to start a new image display window
4312      im     = pointer to MRI_IMAGE structure
4313               (a) NULL to popdown the image display window
4314               (b) non-NULL to display this image in the window
4315 
4316    Output is a "handle" that can be used to control the next usage
4317    of this routine (whether to send an image to a new window or
4318    replace it in an old one).
4319 -------------------------------------------------------------------------*/
4320 
PLUTO_popup_image(void * handle,MRI_IMAGE * im)4321 void * PLUTO_popup_image( void * handle , MRI_IMAGE * im )
4322 {
4323    PLUGIN_impopper * imp = (PLUGIN_impopper *) handle ;
4324 
4325 ENTRY("PLUTO_popup_image") ;
4326 
4327    /*-- input image is NULL ==> popdown, if applicable --*/
4328 
4329    if( im == NULL ){
4330       if( imp != NULL )
4331          drive_MCW_imseq( imp->seq , isqDR_destroy , NULL ) ;
4332 
4333       RETURN((void *) imp) ;
4334    }
4335 
4336    /*-- input = no popper handle ==> create one --*/
4337 
4338    if( imp == NULL ){
4339       imp      = myXtNew(PLUGIN_impopper) ;
4340       imp->seq = NULL ; imp->im  = NULL ;
4341    }
4342 
4343    /*-- input = non-null image ==> replace image --*/
4344 
4345    mri_free( imp->im ) ;      /* toss old copy */
4346    imp->im = mri_copy( im ) ; /* make new copy */
4347 
4348    /*-- input = inactive popper handle ==> activate it --*/
4349 
4350    if( imp->seq == NULL ){
4351       imp->seq = open_MCW_imseq( GLOBAL_library.dc ,
4352                                  PLUGIN_imseq_getim , (XtPointer) imp ) ;
4353 
4354       drive_MCW_imseq( imp->seq , isqDR_realize, NULL ) ;
4355       drive_MCW_imseq( imp->seq , isqDR_onoffwid , (XtPointer) isqDR_offwid ) ;
4356 
4357       drive_MCW_imseq( imp->seq , isqDR_opacitybut , (XtPointer) 0 ) ; /* 07 Mar 2001 */
4358       drive_MCW_imseq( imp->seq , isqDR_zoombut    , (XtPointer) 0 ) ; /* 12 Mar 2002 */
4359       drive_MCW_imseq( imp->seq , isqDR_penbbox    , (XtPointer) 0 ) ; /* 18 Jul 2003 */
4360    }
4361 
4362    /*-- display image at last --*/
4363 
4364    if( im->name != NULL && strlen(im->name) > 0 )
4365       drive_MCW_imseq( imp->seq , isqDR_title, im->name ) ;
4366 
4367    drive_MCW_imseq( imp->seq , isqDR_clearstat , NULL ) ;
4368    drive_MCW_imseq( imp->seq , isqDR_reimage , (XtPointer) 0 ) ;
4369 
4370    RETURN((void *) imp) ;
4371 }
4372 
4373 /*------------------------------------------------------------------
4374    Routine to provide data to the imseq for PLUGIN_popup_image.
4375    Just returns the control information, or the given image.
4376 --------------------------------------------------------------------*/
4377 
PLUGIN_imseq_getim(int n,int type,XtPointer handle)4378 XtPointer PLUGIN_imseq_getim( int n , int type , XtPointer handle )
4379 {
4380    PLUGIN_impopper * imp = (PLUGIN_impopper *) handle ;
4381 
4382 ENTRY("PLUGIN_imseq_getim") ;
4383 
4384    if( imp == NULL ) RETURN(NULL) ;
4385 
4386    /*--- control info ---*/
4387 
4388    if( type == isqCR_getstatus ){
4389       MCW_imseq_status * stat = myXtNew( MCW_imseq_status ) ;
4390       stat->num_total  = 1 ;
4391       stat->num_series = 1 ;
4392       stat->send_CB    = PLUGIN_seq_send_CB ;
4393       stat->parent     = (XtPointer) imp  ;
4394       stat->aux        = NULL ;
4395 
4396       stat->transforms0D = & (GLOBAL_library.registered_0D) ;
4397       stat->transforms2D = & (GLOBAL_library.registered_2D) ;
4398       stat->slice_proj   = NULL ;
4399 
4400       RETURN((XtPointer) stat) ;
4401    }
4402 
4403    /*--- no overlay ---*/
4404 
4405    if( type == isqCR_getoverlay ) RETURN(NULL) ;
4406 
4407    /*--- return a copy of the image
4408          (since the imseq will delete it when it is done) ---*/
4409 
4410    if( type == isqCR_getimage || type == isqCR_getqimage ){
4411       MRI_IMAGE * im = NULL ;
4412       if( imp->im != NULL ) im = mri_copy( imp->im ) ;
4413       RETURN((XtPointer) im) ;
4414    }
4415 
4416    RETURN(NULL) ;  /* should not occur, but who knows? */
4417 }
4418 
4419 /*---------------------------------------------------------------------------
4420    Routine called when the imseq wants to send a message.
4421    In this case, all we need to handle is the destroy message,
4422    so that we can free some memory.
4423 -----------------------------------------------------------------------------*/
4424 
PLUGIN_seq_send_CB(MCW_imseq * seq,XtPointer handle,ISQ_cbs * cbs)4425 void PLUGIN_seq_send_CB( MCW_imseq * seq , XtPointer handle , ISQ_cbs * cbs )
4426 {
4427    PLUGIN_impopper * imp = (PLUGIN_impopper *) handle ;
4428 
4429 ENTRY("PLUGIN_seq_send_CB") ;
4430 
4431    if( imp == NULL ) EXRETURN ;
4432 
4433    switch( cbs->reason ){
4434 
4435       case isqCR_destroy:{
4436          XtFree((char*)imp->seq->status) ;
4437          XtFree((char*)imp->seq)         ; imp->seq = NULL ;
4438          mri_free( imp->im )             ; imp->im  = NULL ;
4439       }
4440       break ;
4441 
4442 #ifndef NO_FRIVOLITIES
4443       case isqCR_buttonpress:{
4444          XButtonEvent *xev = (XButtonEvent *) cbs->event ;
4445 #define NBIRN 11
4446          static int nold=0 ;
4447          static char *birn[NBIRN] = {
4448            " \n** Don't DO That! **\n "                        ,
4449            " \n** Stop it, Rasmus! **\n "                      ,
4450            " \n** Do NOT read this message! **\n "             ,
4451            " \n** Having fun yet? **\n "                       ,
4452            " \n** What do you want NOW? **\n "                 ,
4453            " \n** Too much time on your hands? **\n "          ,
4454            " \n** Why are you bothering me? **\n "             ,
4455            " \n** Danger! Danger, Will Robinson! **\n "        ,
4456            " \n** WARNING: Planetary meltdown imminent! **\n " ,
4457 
4458            " \n"
4459            " God of our fathers, known of old,\n"
4460            " Lord of our far-flung battle-line,\n"
4461            " Beneath whose awful hand we hold\n"
4462            " Dominion over palm and pine -\n"
4463            " Lord God of Hosts, be with us yet,\n"
4464            " Lest we forget - lest we forget!\n"
4465            " \n"
4466            " The tumult and the shouting dies;\n"
4467            " The captains and the kings depart:\n"
4468            " Still stands Thine ancient sacrifice,\n"
4469            " An humble and a contrite heart.\n"
4470            " Lord God of Hosts, be with us yet,\n"
4471            " Lest we forget - lest we forget!\n"
4472            " \n"
4473            " Far-called, our navies melt away;\n"
4474            " On dune and headland sinks the fire:\n"
4475            " Lo, all our pomp of yesterday\n"
4476            " Is one with Nineveh and Tyre!\n"
4477            " Judge of the Nations, spare us yet.\n"
4478            " Lest we forget - lest we forget!\n"
4479            " \n"
4480            " If, drunk with sight of power, we loose\n"
4481            " Wild tongues that have not Thee in awe,\n"
4482            " Such boastings as the Gentiles use,\n"
4483            " Or lesser breeds without the Law -\n"
4484            " Lord God of Hosts, be with us yet,\n"
4485            " Lest we forget - lest we forget!\n"
4486            " \n"
4487            " For heathen heart that puts her trust\n"
4488            " In reeking tube and iron shard,\n"
4489            " All valiant dust that builds on dust,\n"
4490            " And, guarding, calls not Thee to guard,\n"
4491            " For frantic boast and foolish word -\n"
4492            " The Mercy on Thy People, Lord!\n"           ,
4493 
4494            "*\n"
4495            " That's all there is, there ain't no more \n"
4496            "*"
4497          } ;
4498 
4499 #define NKLING 5
4500          static int nkl=0 ;
4501          static char *kling[NKLING] = {
4502             " \n What is this talk of 'release'?\n"
4503             " Klingons do not make software 'releases'.\n"
4504             " Our software 'escapes', leaving a bloody trail of\n"
4505             " designers and 'Quality Assurance' people in its wake.\n"        ,
4506 
4507             " \n Debugging? Klingons do not debug.\n"
4508             " Our software does not coddle the weak.\n"                       ,
4509 
4510             " \n Klingon software does NOT have BUGS.\n"
4511             " It has FEATURES, and those features are too\n"
4512             " sophisticated for a Romulan pig like you to understand.\n"      ,
4513 
4514             " \n Our users will know fear and cower before our software!\n"
4515             " Ship it! Ship it and let them flee like the dogs they are!\n"  ,
4516 
4517             " \n You question the worthiness of my code?\n"
4518             " I should kill you where you stand!\n"
4519          } ;
4520 
4521          /* button 1 = Birn strings */
4522          if( xev == NULL || xev->button == Button1 ){
4523            if( !NO_frivolities && nold < NBIRN ){
4524              if( strstr(birn[nold],"Rasmus") != NULL )
4525                AFNI_speak("Stop it, Rasmus", 0 ) ;
4526              MCW_popup_message( seq->wimage , birn[nold] ,
4527                                 (nold+1 < NBIRN) ? MCW_QUICK_KILL : MCW_USER_KILL ) ;
4528              nold++ ;
4529            } else {
4530              PLUTO_beep() ;
4531              if( nold == NBIRN ){ AFNI_speak("Stop it",0); nold++; }
4532            }
4533          /* button 3 = Klingon strings */
4534          } else if( xev->button == Button3 ){
4535            if( !NO_frivolities && nkl < NKLING ){
4536              MCW_popup_message( seq->wimage , kling[nkl++] , MCW_QUICK_KILL ) ;
4537            } else {
4538              PLUTO_beep() ;
4539              if( nkl == NKLING ){ AFNI_speak("Deesist at once",0); nkl++; }
4540            }
4541          }
4542       }
4543       break ;
4544 
4545       /*--------------------------------------*/
4546 
4547       case isqCR_keypress:{    /* 12 Sep 2002 */
4548         static char *nash[] = {
4549                    " \n"
4550                    "The ant has made himself illustrious\n"
4551                    "Through constant industry industrious.\n"
4552                    "So what?\n"
4553                    "Would you be calm and placid\n"
4554                    "If you were full of formic acid?\n"
4555                 ,
4556                    " \n"
4557                    "Celery, raw\n"
4558                    "Develops the jaw,\n"
4559                    "But celery, stewed,\n"
4560                    "Is more quietly chewed.\n"
4561                 ,
4562                    " \n"
4563                    "I objurgate the centipede,\n"
4564                    "A bug we do not really need.\n"
4565                    "At sleepy-time he beats a path\n"
4566                    "Straight to the bedroom or the bath.\n"
4567                    "You always wallop where he's not,\n"
4568                    "Or, if he is, he makes a spot. \n"
4569                 ,
4570                    " \n"
4571                    "The cow is of the bovine ilk;\n"
4572                    "One end is moo, the other, milk.\n"
4573                 ,
4574                    " \n"
4575                    "This is my dream,\n"
4576                    "It is my own dream,\n"
4577                    "I dreamt it.\n"
4578                    "I dreamt that my hair was kempt.\n"
4579                    "Then I dreamt that my true love unkempt it.\n"
4580                 ,
4581                    " \n"
4582                    "I find it very difficult to enthuse\n"
4583                    "Over the current news.\n"
4584                    "Just when you think that at least the outlook\n"
4585                    "   is so black that it can grow no blacker, it worsens,\n"
4586                    "And that is why I do not like the news, because there\n"
4587                    "   has never been an era when so many things were going\n"
4588                    "   so right for so many of the wrong persons. \n"
4589                 ,
4590                    " \n"
4591                    "I test my bath before I sit,\n"
4592                    "And I'm always moved to wonderment\n"
4593                    "That what chills the finger not a bit\n"
4594                    "Is so frigid upon the fundament.\n"
4595                 ,
4596                    " \n"
4597                    "The turtle lives 'twixt plated decks\n"
4598                    "Which practically conceal its sex.\n"
4599                    "I think it clever of the turtle\n"
4600                    "In such a fix to be so fertile.\n"
4601                 ,
4602                    " \n"
4603                    "Candy\n"
4604                    "Is Dandy\n"
4605                    "But liquor\n"
4606                    "Is quicker.\n"
4607                 ,
4608                    " \n"
4609                    "I've never seen an abominable snowman,\n"
4610                    "I'm hoping not to see one,\n"
4611                    "I'm also hoping, if I do,\n"
4612                    "That it will be a wee one. \n"
4613                 ,
4614                    " \n"
4615                    "Children aren't happy without\n"
4616                    "something to ignore, and that's\n"
4617                    "what parents were created for. \n"
4618                 ,
4619                    " \n"
4620                    "Middle age is when you've met so\n"
4621                    "many people that every new person\n"
4622                    "you meet reminds you of someone else.\n"
4623                 } ;
4624 #define NUM_NASH (sizeof(nash)/sizeof(char *)) ;
4625 
4626         static int iold=-1 ; int ii ;
4627         do{ ii=lrand48()%NUM_NASH; } while( ii==iold ) ; iold = ii ;
4628         MCW_popup_message( seq->wimage , nash[ii] ,
4629                            (strlen(nash[ii]) < 111) ? MCW_QUICK_KILL : MCW_TIMER_KILL ) ;
4630       }
4631       break ;
4632 #endif  /* NO_FRIVOLITIES */
4633 
4634    }
4635    EXRETURN ;
4636 }
4637 
4638 /*-----------------------------------------------------------------------
4639    28 April 2000: Open an image sequence display window.
4640    The input image(s) are copied, so they can be destroyed after
4641    these calls.
4642       PLUTO_imseq_popim(im,kfunc,kdata)
4643          starts the image window off with a single image;
4644          return value is a "handle" that is used in other calls;
4645          if kfunc is not NULL, it is a function that will be called
4646          with argument kdata when the imseq window is closed
4647          (e.g., this can be used to set the saved handle to NULL)
4648       PLUTO_imseq_popup(imar,kfunc,kdata)
4649          starts the window off with an array of images
4650       PLUTO_imseq_retitle(handle,string)
4651          changes the window manager title
4652       PLUTO_imseq_rekill(handle,kfunc,kdata)
4653          changes the kill function/data to kfunc/kdata;
4654       PLUTO_imseq_addto(handle,im)
4655          adds the single image "im" to the display
4656       PLUTO_imseq_setim(handle,n)
4657          sets the image index to 'n'
4658       PLUTO_imseq_destroy(handle)
4659          pops down the image viewer;
4660          destroys the internal copies of the images;
4661          calls kfunc(kdata) if kfunc is not NULL
4662          (so do PLUTO_imseq_rekill(handle,NULL,NULL); before
4663                 PLUTO_imseq_destroy(handle);
4664           if you don't want the kfunc to be called)
4665 -------------------------------------------------------------------------*/
4666 
PLUTO_imseq_popim(MRI_IMAGE * im,generic_func * kfunc,void * kdata)4667 void * PLUTO_imseq_popim( MRI_IMAGE * im, generic_func * kfunc, void * kdata )
4668 {
4669    MRI_IMARR * imar ;
4670    void * handle ;
4671 
4672    if( im == NULL ) return NULL ;
4673    INIT_IMARR(imar) ;
4674    ADDTO_IMARR(imar,im) ;
4675    handle = PLUTO_imseq_popup( imar,kfunc,kdata ) ;
4676    FREE_IMARR(imar) ;  /* not DESTROY_IMARR: we don't 'own' im */
4677    return handle ;
4678 }
4679 
PLUTO_imseq_popup(MRI_IMARR * imar,generic_func * kfunc,void * kdata)4680 void * PLUTO_imseq_popup( MRI_IMARR * imar, generic_func * kfunc, void * kdata )
4681 {
4682    int ntot , ii ;
4683    MRI_IMAGE * im=NULL , * cim=NULL ;
4684    PLUGIN_imseq * psq=NULL ;
4685 
4686    if( imar == NULL || IMARR_COUNT(imar) == 0 ) return NULL ;
4687 
4688    ntot = IMARR_COUNT(imar) ;
4689 
4690    psq = (PLUGIN_imseq *) calloc(1,sizeof(PLUGIN_imseq)) ;
4691    if( psq == NULL ) return NULL ;
4692 
4693    INIT_IMARR(psq->imar) ;
4694    psq->kill_func = kfunc ;
4695    psq->kill_data = kdata ;
4696    psq->rgb_count = 0 ;
4697 
4698    for( ii=0 ; ii < ntot ; ii++ ){
4699       im = IMARR_SUBIMAGE(imar,ii) ;
4700       if( im != NULL ){
4701          cim = mri_copy( im ) ;
4702          ADDTO_IMARR(psq->imar,cim) ;
4703          if( cim->kind == MRI_rgb ) psq->rgb_count++ ;
4704       }
4705    }
4706    ntot = IMARR_COUNT(psq->imar) ;
4707    if( ntot == 0 ){
4708       DESTROY_IMARR(psq->imar) ; free(psq) ; return NULL ;
4709    }
4710 
4711    psq->seq = open_MCW_imseq( GLOBAL_library.dc , PLUTO_imseq_getim , psq ) ;
4712 
4713    drive_MCW_imseq( psq->seq , isqDR_clearstat , NULL ) ;
4714 
4715    { ISQ_options opt ;       /* change some options from the defaults */
4716 
4717      memset(&opt, 0, sizeof(opt));
4718      ISQ_DEFAULT_OPT(opt) ;
4719      opt.save_one = False ;  /* change to Save:bkg */
4720      opt.save_pnm = False ;
4721      drive_MCW_imseq( psq->seq , isqDR_options      , (XtPointer) &opt ) ;
4722      drive_MCW_imseq( psq->seq , isqDR_periodicmont , (XtPointer) 0    ) ;
4723    }
4724 
4725    /* make it popup */
4726 
4727    drive_MCW_imseq( psq->seq , isqDR_realize, NULL ) ;
4728    drive_MCW_imseq( psq->seq , isqDR_title, "Images" ) ;
4729 
4730    if( ntot == 1 )
4731       drive_MCW_imseq( psq->seq , isqDR_onoffwid , (XtPointer) isqDR_offwid ) ;
4732    else {
4733       drive_MCW_imseq( psq->seq , isqDR_onoffwid , (XtPointer) isqDR_onwid ) ;
4734       drive_MCW_imseq( psq->seq , isqDR_opacitybut , (XtPointer) 0 ) ; /* 07 Mar 2001 */
4735       drive_MCW_imseq( psq->seq , isqDR_zoombut    , (XtPointer) 0 ) ; /* 12 Mar 2002 */
4736       drive_MCW_imseq( psq->seq , isqDR_penbbox    , (XtPointer) 0 ) ; /* 18 Jul 2003 */
4737    }
4738 
4739    return (void *) psq ;
4740 }
4741 
4742 /*-----------------------------------------------------------------------*/
4743 
PLUTO_imseq_retitle(void * handle,char * title)4744 void PLUTO_imseq_retitle( void * handle , char * title )
4745 {
4746    PLUGIN_imseq * psq = (PLUGIN_imseq *) handle ;
4747 
4748    if( psq == NULL || psq->seq == NULL || title == NULL ) return ;
4749    drive_MCW_imseq( psq->seq , isqDR_title, title ) ;
4750    return ;
4751 }
4752 
4753 /*-----------------------------------------------------------------------*/
4754 
PLUTO_imseq_rekill(void * handle,generic_func * kfunc,void * kdata)4755 void PLUTO_imseq_rekill( void * handle, generic_func * kfunc, void * kdata )
4756 {
4757    PLUGIN_imseq * psq = (PLUGIN_imseq *) handle ;
4758 
4759    if( psq == NULL ) return ;
4760    psq->kill_func = kfunc ;
4761    psq->kill_data = kdata ;
4762    return ;
4763 }
4764 
4765 /*-----------------------------------------------------------------------*/
4766 
PLUTO_imseq_addto(void * handle,MRI_IMAGE * im)4767 void PLUTO_imseq_addto( void * handle , MRI_IMAGE * im )
4768 {
4769    PLUGIN_imseq * psq = (PLUGIN_imseq *) handle ;
4770    int ntot , ii ;
4771    MRI_IMAGE * cim ;
4772 
4773    if( psq == NULL || psq->seq == NULL || im == NULL ) return ;
4774 
4775    ntot = IMARR_COUNT(psq->imar) ;
4776    cim  = mri_copy(im) ;
4777    if( cim->kind == MRI_rgb ) psq->rgb_count++ ;
4778    ADDTO_IMARR(psq->imar,cim) ;
4779 
4780    drive_MCW_imseq( psq->seq , isqDR_newseq , psq ) ;
4781 
4782    if( ntot == 1 )
4783       drive_MCW_imseq( psq->seq , isqDR_onoffwid , (XtPointer) isqDR_offwid ) ;
4784    else {
4785       drive_MCW_imseq( psq->seq , isqDR_onoffwid , (XtPointer) isqDR_onwid ) ;
4786       drive_MCW_imseq( psq->seq , isqDR_opacitybut , (XtPointer) 0 ) ; /* 07 Mar 2001 */
4787       drive_MCW_imseq( psq->seq , isqDR_zoombut    , (XtPointer) 0 ) ; /* 12 Mar 2002 */
4788    }
4789 
4790    drive_MCW_imseq( psq->seq , isqDR_reimage , (XtPointer)ITOP(ntot) ) ;
4791 
4792    return ;
4793 }
4794 
4795 /*-----------------------------------------------------------------------*/
4796 
PLUTO_imseq_setim(void * handle,int n)4797 void PLUTO_imseq_setim( void *handle , int n )    /* 17 Dec 2004 */
4798 {
4799    PLUGIN_imseq *psq = (PLUGIN_imseq *)handle ;
4800 
4801    if( psq == NULL || psq->seq == NULL ||
4802        n   <  0    || n        >= IMARR_COUNT(psq->imar) ) return ;
4803 
4804    drive_MCW_imseq( psq->seq , isqDR_reimage , (XtPointer)ITOP(n) ) ;
4805    return ;
4806 }
4807 
4808 /*-----------------------------------------------------------------------*/
4809 
PLUTO_imseq_destroy(void * handle)4810 void PLUTO_imseq_destroy( void * handle )
4811 {
4812    PLUGIN_imseq * psq = (PLUGIN_imseq *) handle ;
4813 
4814    if( psq == NULL ) return ;
4815    drive_MCW_imseq( psq->seq , isqDR_destroy , NULL ) ;
4816    return ;
4817 }
4818 
4819 /*------------------------------------------------------------------
4820    Routine to provide data to the imseq.
4821    Just returns the control information, or the selected image.
4822 --------------------------------------------------------------------*/
4823 
PLUTO_imseq_getim(int n,int type,XtPointer handle)4824 XtPointer PLUTO_imseq_getim( int n , int type , XtPointer handle )
4825 {
4826    PLUGIN_imseq * psq = (PLUGIN_imseq *) handle ;
4827 
4828    int ntot = 0 ;
4829 
4830    if( psq->imar != NULL ) ntot = IMARR_COUNT(psq->imar) ;
4831    if( ntot < 1 ) ntot = 1 ;
4832 
4833    /*--- send control info ---*/
4834 
4835    if( type == isqCR_getstatus ){
4836       MCW_imseq_status * stat = myXtNew( MCW_imseq_status ) ;  /* will be free-d */
4837                                                                /* when imseq is */
4838                                                                /* destroyed    */
4839       stat->num_total  = ntot ;
4840       stat->num_series = ntot ;
4841       stat->send_CB    = PLUTO_imseq_send_CB ;
4842       stat->parent     = NULL ;
4843       stat->aux        = NULL ;
4844 
4845       stat->transforms0D = &(GLOBAL_library.registered_0D) ;
4846       stat->transforms2D = &(GLOBAL_library.registered_2D) ;
4847       stat->slice_proj   = NULL ;
4848 
4849       return (XtPointer) stat ;
4850    }
4851 
4852    /*--- no overlay, never ---*/
4853 
4854    if( type == isqCR_getoverlay ) return NULL ;
4855 
4856    /*--- return a copy of an image
4857          (since the imseq will delete it when it is done) ---*/
4858 
4859    if( type == isqCR_getimage || type == isqCR_getqimage ){
4860       MRI_IMAGE * im = NULL , * rim ;
4861 
4862       if( psq->imar != NULL ){
4863          if( n < 0 ) n = 0 ; else if( n >= ntot ) n = ntot-1 ;
4864          rim = IMARR_SUBIMAGE(psq->imar,n) ;
4865          if( psq->rgb_count > 0 )
4866             im = mri_to_rgb( rim ) ;
4867          else
4868             im = mri_copy( rim ) ;
4869       }
4870       return (XtPointer) im ;
4871    }
4872 
4873    return NULL ; /* should not occur, but who knows? */
4874 }
4875 
4876 /*---------------------------------------------------------------------------
4877    Routine called when the imseq wants to send a message.
4878    In this case, all we need to handle is the destroy message,
4879    so that we can free some memory.
4880 -----------------------------------------------------------------------------*/
4881 
PLUTO_imseq_send_CB(MCW_imseq * seq,XtPointer handle,ISQ_cbs * cbs)4882 void PLUTO_imseq_send_CB( MCW_imseq * seq , XtPointer handle , ISQ_cbs * cbs )
4883 {
4884    PLUGIN_imseq * psq = (PLUGIN_imseq *) handle ;
4885 
4886    switch( cbs->reason ){
4887       case isqCR_destroy:{
4888          myXtFree(psq->seq) ;
4889          DESTROY_IMARR( psq->imar ) ;
4890 
4891          if( psq->kill_func != NULL )
4892 #if 0
4893             psq->kill_func( psq->kill_data ) ;
4894 #else
4895             AFNI_CALL_VOID_1ARG( psq->kill_func , void *,psq->kill_data ) ;
4896 #endif
4897 
4898          free(psq) ;
4899       }
4900       break ;
4901    }
4902    return ;
4903 }
4904 
4905 /*-------------------------------------------------------------------------*/
4906 
4907 /*-- 13 Dec 1997: moved guts into thd_make*.c --*/
4908 
PLUTO_4D_to_typed_fim(THD_3dim_dataset * old_dset,char * new_prefix,int new_datum,int ignore,int detrend,generic_func * user_func,void * user_data)4909 THD_3dim_dataset * PLUTO_4D_to_typed_fim( THD_3dim_dataset * old_dset ,
4910                                           char * new_prefix , int new_datum ,
4911                                           int ignore , int detrend ,
4912                                           generic_func * user_func ,
4913                                           void * user_data )
4914 {
4915    THD_3dim_dataset * new_dset ;  /* output dataset */
4916 
4917 ENTRY("PLUTO_4D_to_typed_fim") ;
4918 
4919    if( ! PLUTO_prefix_ok(new_prefix) ) RETURN(NULL) ;
4920 
4921    new_dset = MAKER_4D_to_typed_fim( old_dset , new_prefix , new_datum ,
4922                                      ignore , detrend , user_func , user_data ) ;
4923 
4924    RETURN(new_dset) ;
4925 }
4926 
4927 /*-------------------------------------------------------------------------*/
4928 
PLUTO_4D_to_typed_fith(THD_3dim_dataset * old_dset,char * new_prefix,int new_datum,int ignore,int detrend,generic_func * user_func,void * user_data)4929 THD_3dim_dataset * PLUTO_4D_to_typed_fith( THD_3dim_dataset * old_dset ,
4930                                            char * new_prefix , int new_datum ,
4931                                            int ignore , int detrend ,
4932                                            generic_func * user_func ,
4933                                            void * user_data )
4934 {
4935    THD_3dim_dataset * new_dset ;  /* output dataset */
4936 
4937 ENTRY("PLUTO_4D_to_typed_fith") ;
4938 
4939    if( ! PLUTO_prefix_ok(new_prefix) ) RETURN(NULL) ;
4940 
4941    new_dset = MAKER_4D_to_typed_fith( old_dset , new_prefix , new_datum ,
4942                                       ignore , detrend , user_func , user_data ) ;
4943 
4944    RETURN(new_dset) ;
4945 }
4946 
4947 /*-------------------------------------------------------------------------*/
4948 
PLUTO_4D_to_typed_fbuc(THD_3dim_dataset * old_dset,char * new_prefix,int new_datum,int ignore,int detrend,int nbrik,generic_func * user_func,void * user_data)4949 THD_3dim_dataset * PLUTO_4D_to_typed_fbuc( THD_3dim_dataset * old_dset ,
4950                                            char * new_prefix , int new_datum ,
4951                                            int ignore , int detrend ,
4952                                            int nbrik ,
4953                                            generic_func * user_func ,
4954                                            void * user_data )
4955 {
4956    THD_3dim_dataset * new_dset ;  /* output dataset */
4957 
4958 ENTRY("PLUTO_4D_to_typed_fbuc") ;
4959 
4960    if( ! PLUTO_prefix_ok(new_prefix) ) RETURN(NULL) ;
4961 
4962    new_dset = MAKER_4D_to_typed_fbuc( old_dset , new_prefix , new_datum ,
4963                                       ignore , detrend , nbrik , user_func ,
4964                                       user_data, NULL, 0 ) ;
4965 
4966    RETURN(new_dset) ;
4967 }
4968 
4969 /*----------------------------------------------------------------------------*/
4970 
PLUTO_report(PLUGIN_interface * plint,char * str)4971 void PLUTO_report( PLUGIN_interface *plint , char *str )
4972 {
4973    if( plint == NULL || str == NULL || !AFNI_VERBOSE ) return ;
4974    printf("\n%15.15s= %s" , plint->label , str ) ; fflush(stdout) ;
4975    return ;
4976 }
4977 
4978 /*----------------------------------------------------------------------------
4979   Routines to add a text entry box.
4980 ------------------------------------------------------------------------------*/
4981 
new_PLUGIN_strval(Widget wpar,char * str)4982 PLUGIN_strval * new_PLUGIN_strval( Widget wpar , char * str )
4983 {
4984    PLUGIN_strval * av ;
4985    XmString xstr ;
4986 
4987 ENTRY("new_PLUGIN_strval") ;
4988 
4989    if( wpar == (Widget) NULL ) RETURN(NULL) ;
4990 
4991    av = myXtNew(PLUGIN_strval) ;
4992 
4993    av->rowcol = XtVaCreateWidget(
4994                   "AFNI" , xmRowColumnWidgetClass , wpar ,
4995                      XmNpacking     , XmPACK_TIGHT ,
4996                      XmNorientation , XmHORIZONTAL ,
4997                      XmNmarginHeight, 0 ,
4998                      XmNmarginWidth , 0 ,
4999                      XmNspacing     , 0 ,
5000                      XmNtraversalOn , True  ,
5001                      XmNinitialResourcesPersistent , False ,
5002                   NULL ) ;
5003 
5004    xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
5005    av->label = XtVaCreateManagedWidget(
5006                   "AFNI" , xmLabelWidgetClass , av->rowcol ,
5007                      XmNlabelString , xstr ,
5008                      XmNmarginWidth   , 0  ,
5009                      XmNinitialResourcesPersistent , False ,
5010                   NULL ) ;
5011    XmStringFree( xstr ) ;
5012 
5013    av->textf = XtVaCreateManagedWidget(
5014                   "AFNI" , xmTextFieldWidgetClass , av->rowcol ,
5015                       XmNcolumns      , 9 ,
5016                       XmNeditable     , True ,
5017                       XmNmaxLength    , PLUGIN_STRING_SIZE ,
5018                       XmNresizeWidth  , False ,
5019                       XmNmarginHeight , 1 ,
5020                       XmNmarginWidth  , 1 ,
5021                       XmNcursorPositionVisible , True ,
5022                       XmNblinkRate , 0 ,
5023                       XmNautoShowCursorPosition , True ,
5024                       XmNtraversalOn , True  ,
5025                       XmNinitialResourcesPersistent , False ,
5026                    NULL ) ;
5027 
5028    XtManageChild( av->rowcol ) ;
5029    RETURN(av) ;
5030 }
5031 
5032 /*----------------------------------------------------------------------------*/
5033 
destroy_PLUGIN_strval(PLUGIN_strval * av)5034 void destroy_PLUGIN_strval( PLUGIN_strval * av )
5035 {
5036    if( av != NULL ){
5037       XtDestroyWidget( av->rowcol ) ;
5038       myXtFree(av) ;
5039    }
5040    return ;
5041 }
5042 
5043 /*----------------------------------------------------------------------------*/
5044 
alter_PLUGIN_strval_width(PLUGIN_strval * av,int nchar)5045 void alter_PLUGIN_strval_width( PLUGIN_strval * av , int nchar )
5046 {
5047    if( av != NULL && nchar > 0 )
5048       XtVaSetValues( av->textf , XmNcolumns , nchar , NULL ) ;
5049    return ;
5050 }
5051 
5052 /*----------------------------------------------------------------------------*/
5053 
set_PLUGIN_strval(PLUGIN_strval * av,char * str)5054 void set_PLUGIN_strval( PLUGIN_strval * av , char * str )
5055 {
5056    if( av != NULL && str != NULL )
5057       XmTextFieldSetString( av->textf , str ) ;
5058    return ;
5059 }
5060 
5061 /*----------------------------------------------------------------------------*/
5062 
get_PLUGIN_strval(PLUGIN_strval * av)5063 char * get_PLUGIN_strval( PLUGIN_strval * av )   /* must be XtFree-d */
5064 {
5065    if( av == NULL ) return NULL ;
5066                     return XmTextFieldGetString( av->textf ) ;
5067 }
5068 
5069 /*----------------------------------------------------------------------------*/
5070 
5071 /* Set the addresses of the main vol2surf globals.  Note that the
5072  * plugin options pointer is stored as (void *) so that vol2surf.h
5073  * will not need to percolate up to afni.h.  09 Sep 2004 [rickr]
5074  */
5075 #include "vol2surf.h"
PLUTO_set_v2s_addrs(void ** vopt,char *** maps,char ** hist)5076 int PLUTO_set_v2s_addrs(void ** vopt, char *** maps, char ** hist)
5077 {
5078     if ( !vopt || !maps || !hist ) return -1;
5079 
5080     *vopt = (void *)&gv2s_plug_opts;
5081     *maps = gv2s_map_names;
5082     *hist = gv2s_history;
5083 
5084     return 0;
5085 }
5086 
5087 /**************************************************************************/
5088 /*========================================================================*/
5089 /*============ These must remain the last lines of this file! ============*/
5090 
5091 /** put library routines here that must be loaded **/
5092 
5093 #include "cox_render.h"                 /* 14 Feb 2002 */
5094 
5095 #ifndef MATRIX_INCLUDED /* matrix.h is now included and matrix_initialize
5096                            prototype conflicts with this one. ZSS Nov. 21 2014 */
5097 extern void matrix_initialize(void *);  /* 30 Jul 2007 */
5098 #endif
5099 
5100 static vptr_func * forced_loads[] = {
5101 #ifndef NO_DYNAMIC_LOADING
5102    (vptr_func *) startup_lsqfit ,
5103    (vptr_func *) delayed_lsqfit ,
5104    (vptr_func *) mri_align_dfspace ,
5105    (vptr_func *) EDIT_one_dataset ,
5106    (vptr_func *) EDIT_add_brick ,
5107    (vptr_func *) mri_2dalign_setup ,
5108    (vptr_func *) mri_3dalign_setup ,
5109    (vptr_func *) qsort_floatint ,
5110    (vptr_func *) qsort_floatfloat ,
5111    (vptr_func *) symeig_double ,
5112    (vptr_func *) new_MCW_graf ,
5113    (vptr_func *) THD_makemask ,
5114    (vptr_func *) mri_copy ,
5115    (vptr_func *) beta_t2p ,
5116    (vptr_func *) get_laguerre_table ,
5117    (vptr_func *) mri_fix_data_pointer ,
5118    (vptr_func *) THD_zeropad ,
5119    (vptr_func *) THD_axcode ,
5120    (vptr_func *) THD_dataset_rowfillin ,
5121    (vptr_func *) mri_histobyte ,          /* 25 Jul 2001 */
5122    (vptr_func *) sphere_voronoi_vectors , /* 18 Oct 2001 */
5123    (vptr_func *) new_CREN_renderer ,      /* 14 Feb 2002 */
5124    (vptr_func *) THD_average_timeseries , /* 03 Apr 2002 */
5125    (vptr_func *) cl1_solve ,              /* 07 Aug 2002 */
5126    (vptr_func *) new_Dtable ,             /* 20 Oct 2003 */
5127    (vptr_func *) powell_newuoa ,          /* 24 Jul 2006 */
5128    (vptr_func *) matrix_initialize ,      /* 30 Jul 2007 */
5129    (vptr_func *) r_new_resam_dset ,       /* 31 Jul 2007 */
5130    (vptr_func *) r_hex_str_to_long ,      /* 31 Jul 2007 */
5131    (vptr_func *) r_idisp_vec3f ,          /* 31 Jul 2007 */
5132    (vptr_func *) THD_dataset_mismatch ,   /* 04 Sep 2009 */
5133    (vptr_func *) legendre ,               /* 16 Jul 2010 */
5134    (vptr_func *) AFNI_needs_dset_ijk ,    /* 13 Jan 2020 */
5135 #endif
5136 NULL } ;
5137 
MCW_onen_i_estel_edain(void * n)5138 vptr_func * MCW_onen_i_estel_edain(void *n){
5139   THD_3dim_dataset *ds = (THD_3dim_dataset *)n ;
5140   double             x = (double)(ds->dblk->total_bytes) ;
5141   return forced_loads[(int)x] ;
5142 }
5143 
5144 #else  /* not ALLOW_PLUGINS */
5145 
MCW_onen_i_estel_edain(void * n)5146 void * MCW_onen_i_estel_edain(void *n){} ;  /* dummy routine */
5147 
5148 #endif /* ALLOW_PLUGINS */
5149 
5150 /***********************************************************************
5151    Routines that are always compiled, since they are used in
5152    a few places in AFNI that are not plugin-specific.
5153 ************************************************************************/
5154 
PLUTO_register_timeseries(char * cname,MRI_IMAGE * tsim)5155 void PLUTO_register_timeseries( char *cname , MRI_IMAGE *tsim )
5156 {
5157    MRI_IMAGE *qim ;
5158 
5159 ENTRY("PLUTO_register_timeseries") ;
5160 
5161    if( tsim != NULL ){
5162       qim = mri_to_float( tsim ) ;  /* a copy */
5163       mri_add_name( cname , qim ) ; /* the name */
5164       AFNI_add_timeseries( qim ) ;  /* give it to AFNI */
5165    }
5166    EXRETURN ;
5167 }
5168 
5169 /*----------------------------------------------------------------------------
5170   Find a dataset, given its idcode string. [02 Mar 2002]
5171 ------------------------------------------------------------------------------*/
5172 
PLUTO_find_dset_idc(char * idc)5173 THD_3dim_dataset * PLUTO_find_dset_idc( char *idc )
5174 {
5175    MCW_idcode idcode ;
5176    if( idc == NULL ) return NULL ;
5177    MCW_strncpy( idcode.str , idc , MCW_IDSIZE ) ;
5178    return PLUTO_find_dset( &idcode ) ;
5179 }
5180 
5181 /*----------------------------------------------------------------------------
5182   Routine to find a dataset in the global sessionlist, given its idcode.
5183   If this returns NULL, then you are SOL.
5184 ------------------------------------------------------------------------------*/
5185 
PLUTO_find_dset(MCW_idcode * idcode)5186 THD_3dim_dataset * PLUTO_find_dset( MCW_idcode *idcode )
5187 {
5188    THD_slist_find find ;
5189 
5190 ENTRY("PLUTO_find_dset") ;
5191 
5192    if( idcode == NULL || ISZERO_IDCODE(*idcode) ) RETURN(NULL) ;
5193 
5194    find = THD_dset_in_sessionlist( FIND_IDCODE , idcode ,
5195                                    GLOBAL_library.sslist , -1 ) ;
5196 
5197    RETURN(find.dset) ;
5198 }
5199 
5200 /*-----------------------------------------------------------------*/
5201 
PLUTO_dset_finder(char * idc)5202 THD_slist_find PLUTO_dset_finder( char *idc )
5203 {
5204    MCW_idcode idcode ;
5205    THD_slist_find find ;
5206 
5207    BADFIND(find) ; if( idc == NULL || *idc == '\0' ) return find ;
5208 
5209    MCW_strncpy( idcode.str , idc , MCW_IDSIZE ) ;
5210    find = THD_dset_in_sessionlist( FIND_IDCODE , &idcode ,
5211                                    GLOBAL_library.sslist , -1 ) ;
5212    if( find.dset != NULL ) return find ;
5213 
5214    find = THD_dset_in_sessionlist( FIND_PREFIX , idc ,
5215                                    GLOBAL_library.sslist , -1 ) ;
5216    if( find.dset != NULL ) return find ;
5217 
5218    find = THD_dset_in_sessionlist( FIND_NAME , idc ,
5219                                    GLOBAL_library.sslist , -1 ) ;
5220    return find ;
5221 }
5222 
5223 /*----------------------------------------------------------------------*/
5224 /*!
5225   Look for a dataset by name and append it to session in question
5226   Search if needed for exact name matches under paths from find_afni_file()
5227   and then try get_atlas()
5228 
5229   Returns a 0 only when a dataset was found.
5230   Non-zero indicates stupidity, error, etc.
5231                                                          ZSS Oct. 2013
5232 ------------------------------------------------------------------------*/
AFNI_append_dset_to_session(char * fname,int sss)5233 int AFNI_append_dset_to_session( char *fname, int sss )
5234 {
5235    THD_3dim_dataset *new_dset=NULL;
5236    THD_session * this_ss ;
5237    THD_slist_find find;
5238 
5239    ENTRY("AFNI_append_dset_to_session");
5240 
5241    if( GLOBAL_library.have_dummy_dataset ){ RETURN(1); }
5242    if (!fname) { RETURN(2); }
5243    if( sss < 0 || sss >= GLOBAL_library.sslist->num_sess ){ RETURN(2); }
5244 
5245    this_ss = GLOBAL_library.sslist->ssar[sss] ;
5246    if( ! ISVALID_SESSION(this_ss) ){ RETURN(3); }
5247 
5248    /* not sure what to do with GLOBAL_library session yet.
5249       why not add to it too? Also, why not add to global
5250       if sss == -1 ? For now, return merrily */
5251    if( this_ss == GLOBAL_library.session ) RETURN(4);
5252 
5253    if( this_ss->num_dsset < THD_MAX_SESSION_SIZE ){
5254       if (!(new_dset = THD_open_dataset( fname ))) {
5255          /* now try looking for it */
5256          new_dset = THD_open_dataset(find_afni_file(fname, 0, NULL));
5257       }
5258       if (!new_dset) { /* try again, this works better if name
5259                          is not complete */
5260          new_dset = get_atlas(NULL, fname);
5261       }
5262       if( ISVALID_DSET(new_dset) ){
5263          /* make sure it is not in the session already */
5264          find = THD_dset_in_session( FIND_IDCODE, &(new_dset->idcode), this_ss );
5265          if( find.dset == NULL ){
5266             find = THD_dset_in_session(FIND_PREFIX,
5267                                        DSET_PREFIX(new_dset),this_ss);
5268             if(  find.dset != NULL &&
5269                  find.dset->view_type != new_dset->view_type ) find.dset = NULL ;
5270          }
5271          if (!find.dset) {
5272             SET_SESSION_DSET(new_dset, this_ss,
5273                              this_ss->num_dsset, new_dset->view_type);
5274             this_ss->num_dsset ++ ;
5275             AFNI_inconstancy_check(NULL,new_dset) ;
5276             RETURN(0);
5277          }
5278       }
5279    }
5280 
5281    RETURN(5);
5282 }
5283 
5284 /*-----------------------------------------------------------------
5285    Plot a histogram; input might be from mri_histogram():
5286      nbin = # of bins in hist[]
5287      bot  = bottom of hist[0] bin   } bin size is
5288      top  = top of hist[nbin-1] bin } (top-bot)/nbin
5289      hist = array of counts in each bin
5290      xlab } labels for x-axis,
5291      ylab }            y-axis
5292      tlab }        and top of graph (NULL => skip this label)
5293 
5294      njist = number of extra histograms [can be 0]
5295      jist  = "extra" histograms to plot atop hist
5296                (if jist == NULL, this plot is skipped)
5297    Graph is popped up and then "forgotten" -- RWCox - 30 Sep 1999.
5298 -------------------------------------------------------------------*/
5299 
PLUTO_histoplot_f(int nbin,float bot,float top,float * hist,char * xlab,char * ylab,char * tlab,int njist,float ** jist)5300 void PLUTO_histoplot_f( int nbin, float bot, float top, float *hist ,
5301                         char *xlab , char *ylab , char *tlab ,
5302                         int njist , float **jist )
5303 {
5304    int ii , nx , ny,jj ;
5305    float *xar , *yar , *zar=NULL , **yzar ;
5306    float dx ;
5307    int cumu = AFNI_yesenv("AFNI_HISTOG_CUMULATIVE")   ||
5308               AFNI_yesenv("AFNI_HISTOPLOT_CUMULATIVE")  ;
5309 
5310 ENTRY("PLUTO_histoplot_f") ;
5311 
5312    if( nbin < 2 || hist == NULL ) EXRETURN ;
5313    if( bot >= top ){ bot = 0.0f ; top = nbin ; }
5314 
5315    nx  = 2*(nbin+1) ;
5316    dx  = (top-bot)/nbin ;
5317    xar = (float *) malloc(sizeof(float)*nx) ;
5318    yar = (float *) malloc(sizeof(float)*nx) ;
5319 
5320    if( jist == NULL || njist < 0 ) njist = 0 ;
5321    ny = njist + 1 ;
5322 
5323    yzar = (float **) calloc(sizeof(float *),ny) ;
5324    yzar[0] = yar ;
5325    for( jj=0 ; jj < njist ; jj++ )
5326      yzar[jj+1] = (float *) calloc(sizeof(float),nx) ;
5327 
5328    xar[0] = bot ; yar[0] = 0.0f ;
5329    for( ii=0 ; ii < nbin ; ii++ ){
5330      xar[2*ii+1] = bot+ii*dx     ; yar[2*ii+1] = hist[ii] ;
5331      xar[2*ii+2] = bot+(ii+1)*dx ; yar[2*ii+2] = hist[ii] ;
5332 
5333      for( jj=0 ; jj < njist ; jj++ )
5334        yzar[jj+1][2*ii+1] = yzar[jj+1][2*ii+2] = jist[jj][ii] ;
5335    }
5336    xar[2*nbin+1] = top ; yar[2*nbin+1] = 0.0f ;
5337    for( jj=0 ; jj < njist ; jj++ )
5338      yzar[jj+1][0] = yzar[jj+1][2*nbin+1] = 0.0f ;
5339 
5340    if( cumu ){
5341      int nyy=2*ny ; float sum , ytop=0.0f , yfac ;
5342      for( jj=0 ; jj < ny ; jj++ ){
5343        for( ii=0 ; ii < nx ; ii++ ) if( yzar[jj][ii] > ytop ) ytop = yzar[jj][ii] ;
5344      }
5345      yzar = (float **)realloc(yzar,sizeof(float *)*nyy) ;
5346      for( jj=0 ; jj < ny ; jj++ ){
5347        yzar[ny+jj] = (float *)calloc(sizeof(float),nx) ;
5348        yzar[ny+jj][0] = sum = 0.0f ;
5349        for( ii=0 ; ii < nbin ;  ii++ ){
5350          sum += yzar[jj][2*ii+1] ;
5351          yzar[ny+jj][2*ii+1] = yzar[ny+jj][2*ii+2] = sum ;
5352        }
5353        yzar[ny+jj][2*nbin+1] = sum ;
5354        yfac = ytop / sum ;
5355        for( ii=0 ; ii < nx ; ii++ ) yzar[ny+jj][ii] *= yfac ;
5356      }
5357      plot_ts_setthik_12( ny , nyy , 0.002f ) ;
5358      ny = nyy ;
5359    }
5360 
5361    X11_SET_NEW_PLOT ;
5362    plot_ts_lab( GLOBAL_library.dc->display ,
5363                 nx , xar , ny , yzar ,
5364                 xlab,ylab,tlab , NULL , NULL ) ;
5365 
5366    for( jj=0 ; jj < ny ; jj++ ) free(yzar[jj]) ;
5367    free(yzar) ; free(xar) ;
5368    plot_ts_setthik_12( -555,-666,0.0f ) ;
5369    EXRETURN ;
5370 }
5371 
5372 /*----------------------------------------------------------------------*/
5373 
PLUTO_histoplot(int nbin,float bot,float top,int * hist,char * xlab,char * ylab,char * tlab,int njist,int ** jist)5374 void PLUTO_histoplot( int nbin, float bot, float top, int *hist ,
5375                       char *xlab , char *ylab , char *tlab ,
5376                       int njist , int **jist )
5377 {
5378    float *hist_f , **jist_f ;
5379    int ii,jj ;
5380 
5381 ENTRY("PLUTO_histoplot") ;
5382 
5383    if( nbin < 2 || hist == NULL ) EXRETURN ;
5384 
5385    hist_f = (float *)malloc(sizeof(float)*nbin) ;
5386    for( ii=0 ; ii < nbin ; ii++ ) hist_f[ii] = (float)hist[ii] ;
5387 
5388    if( njist <= 0 || jist == NULL ){
5389      PLUTO_histoplot_f( nbin, bot,top , hist_f , xlab,ylab,tlab , 0,NULL ) ;
5390      free((void *)hist_f) ;
5391      EXRETURN ;
5392    }
5393 
5394    jist_f = (float **)malloc(sizeof(float *)*njist) ;
5395    for( jj=0 ; jj < njist ; jj++ ){
5396      jist_f[jj] = (float *)malloc(sizeof(float)*nbin) ;
5397      for( ii=0 ; ii < nbin ; ii++ ) jist_f[jj][ii] = (float)jist[jj][ii] ;
5398    }
5399    PLUTO_histoplot_f( nbin,bot,top , hist_f , xlab,ylab,tlab , njist,jist_f );
5400    for( jj=0 ; jj < njist ; jj++ ) free((void *)jist_f[jj]) ;
5401    free((void *)jist_f) ; free((void *)hist_f) ;
5402    EXRETURN ;
5403 }
5404 
5405 /*----------------------------------------------------------------------
5406   Return p10 as a power of 10 such that
5407     p10 <= fabs(x) < 10*p10
5408   unless x == 0, in which case return 0.
5409 ------------------------------------------------------------------------*/
5410 
p10(float x)5411 static float p10( float x )
5412 {
5413    double y ;
5414    if( x == 0.0 ) return 0.0 ;
5415    if( x <  0.0 ) x = -x ;
5416    y = floor(log10(x)+0.000001) ; y = pow( 10.0 , y ) ;
5417    return (float) y ;
5418 }
5419 
5420 #define STGOOD(s) ( (s) != NULL && (s)[0] != '\0' )
5421 
5422 static int xpush=1 , ypush=1 ;
PLUTO_set_xypush(int a,int b)5423 void PLUTO_set_xypush( int a, int b ){ xpush=a; ypush=b; }
5424 
5425 /*-----------------------------------------------------------------
5426    Plot a scatterplot.
5427      npt  = # of points in x[] and y[]
5428      x    = x-axis values array
5429      y    = y-axis values array
5430      xlab } labels for x-axis,
5431      ylab }            y-axis
5432      tlab }        and top of graph (NULL => skip this label)
5433      nlin = number of straight lines to plot
5434      alin,blin,clin = slope, intercept, color of lines
5435    Graph is popped up and then "forgotten" -- RWCox - 13 Jan 2000
5436 -------------------------------------------------------------------*/
5437 
PLUTO_scatterplot_NEW(int npt,float * x,float * y,char * xlab,char * ylab,char * tlab,int nlin,float * alin,float * blin,float_triple * clin)5438 void PLUTO_scatterplot_NEW( int npt , float *x , float *y ,
5439                             char *xlab , char *ylab , char *tlab ,
5440                             int nlin , float *alin , float *blin , float_triple *clin )
5441 {
5442    int ii , np , nnax,mmax , nnay,mmay , ll ;
5443    float xbot,xtop , ybot,ytop , pbot,ptop ,
5444          xobot,xotop,yobot,yotop , xa,xb,ya,yb , dx,dy ;
5445    float *xar , *yar , *zar=NULL , **yzar ;
5446    float dsq , rx,ry , a,b ;
5447    char str[32] ;
5448    MEM_plotdata *mp ;
5449 
5450 ENTRY("PLUTO_scatterplot_NEW") ;
5451 
5452    if( npt < 2 || x == NULL || y == NULL ) EXRETURN ;
5453 
5454    /* find range of data */
5455 
5456    xbot = xtop = x[0] ; ybot = ytop = y[0] ;
5457    for( ii=1 ; ii < npt ; ii++ ){
5458            if( x[ii] < xbot ) xbot = x[ii] ;
5459       else if( x[ii] > xtop ) xtop = x[ii] ;
5460 
5461            if( y[ii] < ybot ) ybot = y[ii] ;
5462       else if( y[ii] > ytop ) ytop = y[ii] ;
5463    }
5464    if( xbot >= xtop || ybot >= ytop ){
5465       ERROR_message("Data has no range in PLUTO_scatterplot!\a") ;
5466       EXRETURN ;
5467    }
5468 
5469    /*-- push range of x outwards --*/
5470 
5471    pbot = p10(xbot) ; ptop = p10(xtop) ; if( ptop < pbot ) ptop = pbot ;
5472    if( ptop != 0.0 && xpush > 0 ){
5473       np = (xtop-xbot) / ptop + 0.5 ;
5474       switch( np ){
5475          case 1:  ptop *= 0.1  ; break ;
5476          case 2:  ptop *= 0.2  ; break ;
5477          case 3:  ptop *= 0.25 ; break ;
5478          case 4:
5479          case 5:  ptop *= 0.5  ; break ;
5480       }
5481       xbot = floor( xbot/ptop ) * ptop ;
5482       xtop =  ceil( xtop/ptop ) * ptop ;
5483       nnax = floor( (xtop-xbot) / ptop + 0.5 ) ;
5484       mmax = (nnax < 3) ? 10
5485                         : (nnax < 6) ? 5 : 2 ;
5486    } else {
5487       nnax = 1 ; mmax = 10 ;
5488       dx = 0.02*(xtop-xbot) ;
5489       if( xtop-floorf(xtop) > 0.001f ) xtop += dx ;
5490       if( xbot-floorf(xbot) > 0.001f ) xbot -= dx ;
5491    }
5492 
5493    /*-- push range of y outwards --*/
5494 
5495    pbot = p10(ybot) ; ptop = p10(ytop) ; if( ptop < pbot ) ptop = pbot ;
5496    if( ptop != 0.0 && ypush > 0 ){
5497       np = (ytop-ybot) / ptop + 0.5 ;
5498       switch( np ){
5499          case 1:  ptop *= 0.1  ; break ;
5500          case 2:  ptop *= 0.2  ; break ;
5501          case 3:  ptop *= 0.25 ; break ;
5502          case 4:
5503          case 5:  ptop *= 0.5  ; break ;
5504       }
5505       ybot = floor( ybot/ptop ) * ptop ;
5506       ytop =  ceil( ytop/ptop ) * ptop ;
5507       nnay = floor( (ytop-ybot) / ptop + 0.5 ) ;
5508       mmay = (nnay < 3) ? 10
5509                         : (nnay < 6) ? 5 : 2 ;
5510    } else {
5511       nnay = 1 ; mmay = 10 ;
5512       dy = 0.02*(ytop-ybot) ;
5513       if( ytop-floorf(ytop) > 0.001f ) ytop += dy ;
5514       if( ybot-floorf(ybot) > 0.001f ) ybot -= dy ;
5515    }
5516 
5517    /*-- setup to plot --*/
5518 
5519    create_memplot_surely( "ScatPlot" , 1.3 ) ;
5520 
5521    /*-- plot labels, if any --*/
5522 
5523    xobot = 0.15 ; xotop = 1.27 ;  /* set objective size of plot */
5524    yobot = 0.1  ; yotop = 0.95 ;
5525 
5526    if( STGOOD(tlab) ){ yotop -= 0.02 ; yobot -= 0.01 ; }
5527 
5528    /* x-axis label? */
5529 
5530    set_color_memplot( 0.0 , 0.0 , 0.0 ) ; set_thick_memplot( 0.002f ) ;
5531    if( STGOOD(xlab) )
5532       plotpak_pwritf( 0.5*(xobot+xotop) , yobot-0.06 , xlab , 16 , 0 , 0 ) ;
5533 
5534    /* y-axis label? */
5535 
5536    if( STGOOD(ylab) )
5537       plotpak_pwritf( xobot-0.12 , 0.5*(yobot+yotop) , ylab , 16 , 90 , 0 ) ;
5538 
5539    /* label at top? */
5540 
5541    if( STGOOD(tlab) )
5542       plotpak_pwritf( xobot+0.01 , yotop+0.01 , tlab , 18 , 0 , -2 ) ;
5543 
5544    /* plot axes */
5545 
5546    set_thick_memplot( 0.001f ) ;
5547    plotpak_set( xobot,xotop , yobot,yotop , xbot,xtop , ybot,ytop , 1 ) ;
5548    plotpak_periml( nnax,mmax , nnay,mmay ) ;
5549 
5550    /* plot data */
5551 
5552 #define DSQ 0.0011111
5553 
5554    set_thick_memplot( 0.0f ) ;
5555    set_color_memplot( 0.0 , 0.0 , 0.4 ) ;        /* 28 Feb 2011 */
5556    dsq = AFNI_numenv( "AFNI_SCATPLOT_FRAC" ) ;   /* 15 Feb 2005 */
5557    if( dsq <= 0.0 || dsq >= 0.01 ){
5558      dsq = 64.0f*DSQ / sqrtf((float)npt) ;
5559      if     ( dsq < 0.5f*DSQ )  dsq = 0.5f*DSQ ;
5560      else if( dsq > 5.0f*DSQ ){ dsq = 5.0f*DSQ ; set_thick_memplot(0.002f) ; }
5561    }
5562 
5563    dx = dsq*(xtop-xbot) ;
5564    dy = dsq*(ytop-ybot) * (xotop-xobot)/(yotop-yobot) ;
5565    for( ii=0 ; ii < npt ; ii++ ){
5566 
5567 #if 0
5568       rx = (drand48()-0.5)*dx ;
5569       ry = (drand48()-0.5)*dy ;
5570 #else
5571       rx = ry = 0.0 ;
5572 #endif
5573       xa = x[ii]+rx - dx ; xb = x[ii]+rx + dx ;
5574       ya = y[ii]+ry - dy ; yb = y[ii]+ry + dy ;
5575 
5576       plotpak_line( xa,ya , xa,yb ) ;
5577       plotpak_line( xa,yb , xb,yb ) ;
5578       plotpak_line( xb,yb , xb,ya ) ;
5579       plotpak_line( xb,ya , xa,ya ) ;
5580    }
5581 
5582 
5583    /* draw lines (showing the linear fit of y to x) */
5584 
5585    set_thick_memplot(0.003456789f) ; /* thick-ish lines */
5586    plotpak_setlin(2) ;               /* and dashed line mode */
5587    for( ll=0 ; ll < nlin ; ll++ ){
5588      a = alin[ll] ; b = blin[ll] ;
5589      if( a != 0.0f || b != 0.0f ){
5590 
5591        /* endpoints of line passing from left edge to right edge */
5592 
5593        xa = xbot ; ya = a*xa+b ; xb = xtop ; yb = a*xb+b ;
5594 
5595        /* clip line at left end */
5596 
5597             if( ya < ybot && a > 0.0f ){ xa = (ybot-b)/a ; ya = ybot ; }
5598        else if( ya > ytop && a < 0.0f ){ xa = (ytop-b)/a ; ya = ytop ; }
5599 
5600        /* clip line at right end */
5601 
5602             if( yb < ybot && a < 0.0f ){ xb = (ybot-b)/a ; yb = ybot ; }
5603        else if( yb > ytop && a > 0.0f ){ xb = (ytop-b)/a ; yb = ytop ; }
5604 
5605        set_color_memplot(clin[ll].a,clin[ll].b,clin[ll].c) ;
5606        plotpak_line( xa,ya , xb,yb ) ; /* draw it */
5607      }
5608    }
5609    plotpak_setlin(1) ;             /* back to solid line mode */
5610    set_thick_memplot(0.0f) ;       /* and thin lines */
5611 
5612    mp = get_active_memplot() ;
5613 
5614    X11_SET_NEW_PLOT ;
5615    (void) memplot_to_topshell( GLOBAL_library.dc->display , mp , NULL ) ;
5616 
5617    EXRETURN ;
5618 }
5619 
5620 /*----------------------------------------------------------------------*/
5621 /* The old interface, with 1 red line */
5622 
PLUTO_scatterplot(int npt,float * x,float * y,char * xlab,char * ylab,char * tlab,float a,float b)5623 void PLUTO_scatterplot( int npt , float *x , float *y ,
5624                         char *xlab , char *ylab , char *tlab ,
5625                         float a , float b )
5626 {
5627    float alin , blin ; float_triple clin ;
5628 
5629    alin = a ; blin = b ; clin.a = 0.7f ; clin.b = 0.0f ; clin.c = 0.0f ;
5630 
5631    PLUTO_scatterplot_NEW( npt,x,y , xlab,ylab,tlab , 1,&alin,&blin,&clin ) ;
5632    return ;
5633 }
5634 
5635 /*----------------------------------------------------------------------
5636    Routine to force AFNI to redisplay images in all open controllers.
5637 ------------------------------------------------------------------------*/
5638 
PLUTO_force_redisplay(void)5639 void PLUTO_force_redisplay(void)
5640 {
5641    Three_D_View * im3d ;
5642    int ii ;
5643 
5644 ENTRY("PLUTO_force_redisplay") ;
5645 
5646    for( ii=0 ; ii < MAX_CONTROLLERS ; ii++ ){
5647       im3d = GLOBAL_library.controllers[ii] ;
5648       if( IM3D_OPEN(im3d) ){
5649          im3d->anat_voxwarp->type =                       /* 11 Jul 1997 */
5650             im3d->fim_voxwarp->type = ILLEGAL_TYPE ;
5651          IM3D_CLEAR_TMASK(im3d) ;
5652          IM3D_CLEAR_THRSTAT(im3d) ; /* 12 Jun 2014 */
5653          AFNI_set_viewpoint( im3d , -1,-1,-1 , REDISPLAY_ALL ) ;
5654       }
5655    }
5656    EXRETURN ;
5657 }
5658 
5659 /*----------------------------------------------------------------------
5660    Force the redisplay of the color bars in all image windows.
5661    23 Aug 1998 -- RWCox.
5662 ------------------------------------------------------------------------*/
5663 
PLUTO_force_rebar(void)5664 void PLUTO_force_rebar(void)
5665 {
5666    Three_D_View * im3d ;
5667    int ii ;
5668 
5669 ENTRY("PLUTO_force_rebar") ;
5670 
5671    for( ii=0 ; ii < MAX_CONTROLLERS ; ii++ ){
5672       im3d = GLOBAL_library.controllers[ii] ;
5673       if( IM3D_OPEN(im3d) ){
5674          drive_MCW_imseq( im3d->s123 , isqDR_rebar , NULL ) ;
5675          drive_MCW_imseq( im3d->s231 , isqDR_rebar , NULL ) ;
5676          drive_MCW_imseq( im3d->s312 , isqDR_rebar , NULL ) ;
5677       }
5678    }
5679    EXRETURN ;
5680 }
5681 
5682 /*----------------------------------------------------------------------
5683    Force the change of opacity in all open image viewers
5684    06 Jun 2019 -- RWCox.
5685 ------------------------------------------------------------------------*/
5686 
PLUTO_force_opacity_change(void)5687 void PLUTO_force_opacity_change(void)
5688 {
5689    Three_D_View *im3d ;
5690    int ii , opval=GLOBAL_library.opacity_setting ;
5691 
5692 ENTRY("PLUTO_force_opacity_change") ;
5693 
5694    for( ii=0 ; ii < MAX_CONTROLLERS ; ii++ ){
5695       im3d = GLOBAL_library.controllers[ii] ;
5696       if( IM3D_OPEN(im3d) ){
5697          drive_MCW_imseq( im3d->s123, isqDR_setopacity, (XtPointer)ITOP(opval) );
5698          drive_MCW_imseq( im3d->s231, isqDR_setopacity, (XtPointer)ITOP(opval) );
5699          drive_MCW_imseq( im3d->s312, isqDR_setopacity, (XtPointer)ITOP(opval) );
5700       }
5701    }
5702    EXRETURN ;
5703 }
5704 
5705 /*------------------------------------------------------------------------*/
5706 static int num_workp      = 0 ;
5707 static XtWorkProc * workp = NULL ;
5708 static XtPointer *  datap = NULL ;
5709 static XtWorkProcId wpid ;
5710 
5711 #undef WPDEBUG
5712 
PLUTO_register_workproc(XtWorkProc func,XtPointer data)5713 void PLUTO_register_workproc( XtWorkProc func , XtPointer data )
5714 {
5715 ENTRY("PLUTO_register_workproc") ;
5716 
5717    if( func == NULL ){
5718       fprintf(stderr,"PLUTO_register_workproc: func=NULL on entry!\n") ;
5719       EXRETURN ;
5720    }
5721 
5722    if( num_workp == 0 ){
5723       workp = (XtWorkProc *) malloc( sizeof(XtWorkProc) ) ;
5724       datap = (XtPointer *)  malloc( sizeof(XtPointer) ) ;
5725       wpid  = XtAppAddWorkProc( PLUTO_Xt_appcontext, PLUG_workprocess, NULL ) ;
5726 #ifdef WPDEBUG
5727       fprintf(stderr,"PLUTO_register_workproc: wpid = %x\n",(int)wpid) ;
5728 #endif
5729    } else {
5730       workp = (XtWorkProc *) realloc( workp, sizeof(XtWorkProc)*(num_workp+1) ) ;
5731       datap = (XtPointer*)   realloc( datap, sizeof(XtPointer) *(num_workp+1) ) ;
5732    }
5733 
5734    workp[num_workp] = func ;
5735    datap[num_workp] = data ;
5736    num_workp++ ;
5737 
5738 #ifdef WPDEBUG
5739 fprintf(stderr,"PLUTO_register_workproc: have %d workprocs\n",num_workp) ;
5740 #endif
5741 
5742    EXRETURN ;
5743 }
5744 
5745 /*----------------------------------------------------------------------------*/
5746 
PLUTO_remove_workproc(XtWorkProc func)5747 void PLUTO_remove_workproc( XtWorkProc func )
5748 {
5749    int ii , ngood ;
5750 
5751 ENTRY("PLUTO_remove_workproc") ;
5752 
5753    if( func == NULL || num_workp == 0 ){
5754       fprintf(stderr,"*** PLUTO_remove_workproc: illegal parameters!\n") ;
5755       EXRETURN ;
5756    }
5757 
5758    for( ii=0 ; ii < num_workp ; ii++ ){
5759       if( func == workp[ii] ) workp[ii] = NULL ;
5760    }
5761 
5762    for( ii=0,ngood=0 ; ii < num_workp ; ii++ )
5763       if( workp[ii] != NULL ) ngood++ ;
5764 
5765    if( ngood == 0 ){
5766 #ifdef WPDEBUG
5767       fprintf(stderr,"PLUTO_remove_workproc: No workprocs left\n") ;
5768 #endif
5769       XtRemoveWorkProc( wpid ) ;
5770       free(workp) ; workp = NULL ; free(datap) ; datap = NULL ;
5771       num_workp = 0 ;
5772    } else {
5773 #ifdef WPDEBUG
5774       fprintf(stderr,"PLUTO_remove_workproc: %d workprocs left\n",ngood) ;
5775 #endif
5776    }
5777 
5778    EXRETURN ;
5779 }
5780 
5781 /*----------------------------------------------------------------------------*/
5782 
PLUG_workprocess(XtPointer fred)5783 RwcBoolean PLUG_workprocess( XtPointer fred )
5784 {
5785    int ii , ngood ;
5786    RwcBoolean done ;
5787 
5788 #ifdef WPDEBUG
5789    { static int ncall=0 ;
5790      if( (ncall++) % 1000 == 0 )
5791        fprintf(stderr,"PLUG_workprocess: entry %d\n",ncall) ; }
5792 #endif
5793 
5794    if( num_workp == 0 ) return True ;
5795 
5796    for( ii=0,ngood=0 ; ii < num_workp ; ii++ ){
5797       if( workp[ii] != NULL ){
5798          done = workp[ii]( datap[ii] ) ;
5799          if( done == True ) workp[ii] = NULL ;
5800          else               ngood++ ;
5801       }
5802    }
5803 
5804    if( ngood == 0 ){
5805 #ifdef WPDEBUG
5806       fprintf(stderr,"Found no workprocs left\n") ;
5807 #endif
5808       free(workp) ; workp = NULL ; free(datap) ; datap = NULL ;
5809       num_workp = 0 ;
5810       return True ;
5811    }
5812    return False ;
5813 }
5814 
5815 /*---------------------------------------------------------------*/
5816 
5817 typedef struct {
5818   generic_func * func ;
5819   XtPointer      cd ;
5820 } mytimeout ;
5821 
PLUG_dotimeout_CB(XtPointer cd,XtIntervalId * id)5822 static void PLUG_dotimeout_CB( XtPointer cd , XtIntervalId * id )
5823 {
5824    mytimeout * myt = (mytimeout *) cd ;
5825 
5826 ENTRY("PLUTO_dotimeout_CB") ;
5827 
5828    if( myt == NULL ) EXRETURN ;  /* bad news */
5829 
5830 STATUS("calling user timeout function") ;
5831 
5832 #if 0
5833    myt->func( myt->cd ) ;
5834 #else
5835    AFNI_CALL_VOID_1ARG( myt->func , XtPointer,myt->cd ) ;
5836 #endif
5837 
5838    myXtFree(myt) ; EXRETURN ;
5839 }
5840 
5841 /*----------------------------------------------------------------------------*/
5842 
PLUTO_register_timeout(int msec,generic_func * func,XtPointer cd)5843 void PLUTO_register_timeout( int msec, generic_func * func, XtPointer cd )
5844 {
5845    mytimeout * myt ;
5846 
5847 ENTRY("PLUTO_register_timeout") ;
5848 
5849    if( func == NULL ){
5850       fprintf(stderr,"PLUTO_register_timeout: func=NULL on entry!\n") ;
5851       EXRETURN ;
5852    }
5853 
5854    if( msec < 0 ) msec = 0 ;
5855 
5856    myt       = myXtNew(mytimeout) ;
5857    myt->func = func ;
5858    myt->cd   = cd ;
5859 
5860    (void) XtAppAddTimeOut( PLUTO_Xt_appcontext , msec ,
5861                            PLUG_dotimeout_CB , (XtPointer) myt ) ;
5862 
5863    EXRETURN ;
5864 }
5865 
5866 /*---------------------------------------------------------------*/
5867 
PLUTO_elapsed_time(void)5868 double PLUTO_elapsed_time(void) /* in seconds */
5869 {
5870    struct timeval  new_tval ;
5871    struct timezone tzone ;
5872    static struct timeval old_tval ;
5873    static int first = 1 ;
5874 
5875    gettimeofday( &new_tval , &tzone ) ;
5876 
5877    if( first ){
5878       old_tval = new_tval ;
5879       first    = 0 ;
5880       return 0.0 ;
5881    }
5882 
5883    if( old_tval.tv_usec > new_tval.tv_usec ){
5884       new_tval.tv_usec += 1000000 ;
5885       new_tval.tv_sec -- ;
5886    }
5887 
5888    return (double)( (new_tval.tv_sec  - old_tval.tv_sec )
5889                    +(new_tval.tv_usec - old_tval.tv_usec)*1.0e-6 ) ;
5890 }
5891 
5892 /*----------------------------------------------------------------------------*/
5893 
PLUTO_cpu_time(void)5894 double PLUTO_cpu_time(void)  /* in seconds */
5895 {
5896 #ifdef CLK_TCK
5897    struct tms ttt ;
5898 
5899    (void) times( &ttt ) ;
5900    return (  (double) (ttt.tms_utime
5901                                      /* + ttt.tms_stime */
5902                       )
5903            / (double) CLK_TCK ) ;
5904 #else
5905    return 0.0 ;
5906 #endif
5907 }
5908