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 /***********************************************************************
8  *
9  * plug_roiedit.c               - a region of interest editor (afni plugin)
10  *
11  * Rick Reynolds
12  * Medical College of WI
13  *
14  *************
15  * history:
16  *
17  * October 7, 2003  [rickr]
18  *   - renamed old and new fields of r_alg_s to Bold and Bnew
19  * June 10, 2005 [rickr]
20  *   - added lots of ENTRY/RETURN pairs
21  *   - continue on 'set fill point' with no data
22  *   - use DSET_load in case use has not opened afni windows yet
23  ***********************************************************************
24  */
25 
26 #include <Xm/FileSB.h>
27 
28 #include "afni.h"
29 
30 #ifndef ALLOW_PLUGINS
31 #  error "Plugins not properly set up -- see machdep.h"
32 #endif
33 
34 #include "plug_roiedit.h"               /* RCR stuff */
35 
36 /***********************************************************************
37   Plugin to draw values into a dataset.
38   Makes a custom interface.
39 ************************************************************************/
40 
41 /*---------- prototypes for internal routines ----------*/
42 
43 static char * DRAW_main( PLUGIN_interface * ) ;
44 
45 static void DRAW_make_widgets(void) ;
46 
47 static void DRAW_done_CB  ( Widget , XtPointer , XtPointer ) ;
48 static void DRAW_undo_CB  ( Widget , XtPointer , XtPointer ) ;
49 static void DRAW_help_CB  ( Widget , XtPointer , XtPointer ) ;
50 static void DRAW_quit_CB  ( Widget , XtPointer , XtPointer ) ;
51 static void DRAW_save_CB  ( Widget , XtPointer , XtPointer ) ;
52 static void DRAW_choose_CB( Widget , XtPointer , XtPointer ) ;
53 static void DRAW_color_CB ( MCW_arrowval * , XtPointer ) ;
54 static void DRAW_mode_CB  ( MCW_arrowval * , XtPointer ) ;
55 static void DRAW_value_CB ( MCW_arrowval * , XtPointer ) ;
56 
57 static void DRAW_receiver( int , int , void * , void * ) ;
58 static void DRAW_into_dataset( int , int * , int * , int * , void * ) ;
59 static void DRAW_finalize_dset_CB( Widget , XtPointer , MCW_choose_cbs * ) ;
60 static void DRAW_2dfiller( int nx , int ny , int ix , int jy , byte * ar ) ;
61 
62 static PLUGIN_interface * plint = NULL ;
63 
64 /***********************************************************************
65    Set up the interface to the user.  Note that we bypass the
66    normal interface creation, and simply have the menu selection
67    directly call the main function, which will create a custom
68    set of interface widgets.
69 ************************************************************************/
70 
71 
72 DEFINE_PLUGIN_PROTOTYPE
73 
PLUGIN_init(int ncall)74 PLUGIN_interface * PLUGIN_init( int ncall )
75 {
76    if( ncall > 0 ) return NULL ;  /* only one interface */
77 
78    CHECK_IF_ALLOWED("GYRUSFINDER","Gyrus Finder") ;  /* 30 Sep 2016 */
79 
80    plint = PLUTO_new_interface( "Gyrus Finder" , NULL , NULL ,
81 				PLUGIN_CALL_IMMEDIATELY , DRAW_main ) ;
82 
83    PLUTO_add_hint( plint , "Interactive Region of Interest Editor" ) ;
84 
85    PLUTO_set_sequence( plint , "z:Reynolds" ) ;
86 
87    return plint ;
88 }
89 
90 /***************************************************************************
91   Will be called from AFNI when user selects from Plugins menu.
92 ****************************************************************************/
93 
94 /* Interface widgets */
95 
96 static Widget shell=NULL , rowcol , info_lab , choose_pb ;
97 static Widget done_pb , undo_pb , help_pb , quit_pb , save_pb ;
98 static MCW_arrowval * value_av , * color_av , * mode_av ;
99 
100 /* Other data */
101 
102 #define MODE_CURVE       0
103 #define MODE_CLOSED      1
104 #define MODE_POINTS      2
105 #define MODE_FLOOD_VAL   3
106 #define MODE_FLOOD_NZ    4
107 #define MODE_VOL_FILL    5
108 #define MODE_CONN_PTS    6
109 
110 static char * mode_strings[] = {
111   "Open Curve" , "Closed Curve" , "Points" , "Flood->Value",
112   "Flood->Nonzero", "Set Fill Point", "Connect Points" };
113 
114 static int    mode_ints[] = {
115   DRAWING_LINES , DRAWING_FILL , DRAWING_POINTS , DRAWING_POINTS ,
116   DRAWING_POINTS, DRAWING_POINTS, DRAWING_POINTS };
117 
118 #define NUM_modes (sizeof(mode_ints)/sizeof(int))
119 
120 static MCW_DC * dc ;                /* display context */
121 static Three_D_View * im3d ;        /* AFNI controller */
122 static THD_3dim_dataset * dset ;    /* The dataset!    */
123 
124 static int   color_index = 1 ;               /* from color_av */
125 static int   mode_ival   = MODE_CURVE ;
126 static int   mode_index  = DRAWING_LINES ;   /* from mode_av  */
127 static int   value_int   = 1 ;               /* from value_av */
128 static float value_float = 1.0 ;             /* ditto         */
129 
130 static int editor_open  = 0 ;
131 static int dset_changed = 0 ;
132 static int recv_open    = 0 ;
133 static int recv_key     = -1 ;   /* 15 Jun 1999 by RWCox */
134 
135 static int undo_bufsiz = 0 ;     /* size of undo_buf in bytes */
136 static int undo_bufnum = 0 ;     /* size of undo_xyz in ints */
137 static int undo_bufuse = 0 ;     /* number of entries in undo buffer */
138 static void * undo_buf = NULL ;  /* stores data to be copied back to dataset */
139 static int  * undo_xyz = NULL ;  /* stores voxel indices for copying */
140 
141 static THD_dataxes dax_save ;    /* save this for later referenc */
142 
DRAW_main(PLUGIN_interface * plint)143 char * DRAW_main( PLUGIN_interface * plint )
144 {
145    XmString xstr ;
146 
147    ENTRY("DRAW_main");
148 
149 #if 0
150    /* RCR - this plugin is not authorized outside of the mcw domain */
151    if ( ! r_check_host( ) )
152       return NULL;
153 #endif
154 
155    /*-- sanity checks --*/
156 
157    if( ! IM3D_OPEN(plint->im3d) ) RETURN( "AFNI Controller\nnot opened?!") ;
158 
159    if( editor_open )
160    {
161       XMapRaised( XtDisplay(shell) , XtWindow(shell) ) ; NI_sleep(1);
162 
163       if ( gRX.main_is_open )
164       {
165 	  XMapRaised( XtDisplay( gRX.main ) , XtWindow( gRX.main ) ) ; NI_sleep(1);
166       }
167       else
168       {
169 	  XtMapWidget( gRX.main ); NI_sleep(1) ;
170 	  gRX.main_is_open = 1;
171       }
172 
173       RETURN(NULL);
174    }
175 
176    im3d = plint->im3d ;  /* save for local use */
177 
178    /*-- create widgets, first time through --*/
179 
180    if( shell == NULL ){
181       dc = im3d->dc ;        /* save this too */
182       DRAW_make_widgets() ;
183       PLUTO_set_topshell( plint , shell ) ;  /* 22 Sep 2000 */
184       RWC_visibilize_widget( shell ) ;       /* 27 Sep 2000 */
185    }
186 
187    /*-- set titlebar --*/
188 
189    { static char clabel[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ; /* see afni_func.c */
190      char ttl[PLUGIN_STRING_SIZE] ; int ic ;
191 
192      ic = AFNI_controller_index(im3d) ;  /* find out which controller */
193 
194      if( ic >=0 && ic < 26 ){
195 	sprintf( ttl , "'AFNI' GyrusFinder [%c]" , clabel[ic] ) ;
196 	XtVaSetValues( shell , XmNtitle , ttl , NULL ) ;
197      }
198    }
199 
200    /*-- set the info label --*/
201 
202    xstr = XmStringCreateLtoR( "[No dataset]" ,
203 			      XmFONTLIST_DEFAULT_TAG ) ;
204    XtVaSetValues( info_lab , XmNlabelString , xstr , NULL ) ;
205    XmStringFree(xstr) ;
206 
207    /*-- pop the widget up --*/
208 
209    XtMapWidget(shell) ; NI_sleep(1) ;
210 
211    if ( gRX.main_is_open )
212    {
213       XMapRaised( XtDisplay( gRX.main ) , XtWindow( gRX.main ) ) ; NI_sleep(1);
214    }
215    else
216    {
217       XtMapWidget( gRX.main ); NI_sleep(1) ;
218       gRX.main_is_open = 1;
219    }
220 
221 
222    /*-- misc initialization --*/
223 
224    dset         = NULL ;   /* not editing anything   */
225    dset_changed = 0 ;      /* not yet changed */
226    editor_open  = 1 ;      /* editor is now open for business */
227    recv_open    = 0 ;      /* receiver is not yet open */
228    recv_key     = -1;
229 
230    SENSITIZE(undo_pb,0) ;  undo_bufuse = 0 ;
231    SENSITIZE(save_pb,0) ;
232    SENSITIZE(choose_pb,1) ;
233 
234    RETURN(NULL) ;
235 }
236 
237 /*------------------------------------------------------------------------
238   Make the control popup for this thing
239 --------------------------------------------------------------------------*/
240 
241 /*-- structures defining action buttons (at bottom of popup) --*/
242 
243 #define NACT 5  /* number of action buttons */
244 
245 static MCW_action_item DRAW_actor[NACT] = {
246  {"Undo",DRAW_undo_CB,NULL,
247   "Undoes previous draw\naction, if possible","Undo last change",0} ,
248 
249  {"Help",DRAW_help_CB,NULL,
250   "Displays more help" , "Displays more help",0} ,
251 
252  {"Quit",DRAW_quit_CB,NULL,
253   "Discard edits since last Save\nand close Editor" ,
254    "Discard edits and close",0} ,
255 
256  {"Save",DRAW_save_CB,NULL,
257   "Save edits to disk\nand continue" , "Save to disk and continue",0} ,
258 
259  {"Done",DRAW_done_CB,NULL,
260   "Save edits to disk\nand close Editor" , "Save and close",1}
261 } ;
262 
DRAW_make_widgets(void)263 static void DRAW_make_widgets(void)
264 {
265    XmString xstr ;
266 
267    ENTRY("DRAW_make_widgets");
268 
269    /*** top level shell for window manager ***/
270 
271    shell =
272       XtVaAppCreateShell(
273 	   "AFNI" , "AFNI" , topLevelShellWidgetClass , dc->display ,
274 	   XmNtitle             , "GFinder Editor", /* top of window */
275 	   XmNiconName          , "GFinder"       , /* label on icon */
276 	   XmNdeleteResponse    , XmDO_NOTHING    , /* deletion handled below */
277 	   XmNallowShellResize  , True ,            /* let code resize shell? */
278 	   XmNmappedWhenManaged , False ,           /* must map it manually */
279 	   XmNinitialResourcesPersistent , False ,
280       NULL ) ;
281 
282    if( afni48_good )             /* set icon pixmap */
283       XtVaSetValues( shell ,
284 			XmNiconPixmap , afni48_pixmap ,
285 		     NULL ) ;
286 
287    if( MCW_isitmwm(shell) )      /* remove some MWM functions */
288       XtVaSetValues( shell ,
289 		       XmNmwmFunctions ,
290 		       MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE ,
291 		     NULL ) ;
292 
293    XmAddWMProtocolCallback(      /* make "Close" window menu work */
294 	   shell ,
295 	   XmInternAtom( dc->display , "WM_DELETE_WINDOW" , False ) ,
296 	   DRAW_quit_CB , (XtPointer) plint ) ;
297 
298    /*** rowcolumn widget to hold all user interface stuff ***/
299 
300    rowcol = XtVaCreateWidget(
301 	     "AFNI" , xmRowColumnWidgetClass , shell ,
302 		XmNpacking     , XmPACK_TIGHT ,
303 		XmNorientation , XmVERTICAL ,
304 		XmNtraversalOn , True  ,
305 		XmNinitialResourcesPersistent , False ,
306 	     NULL ) ;
307 
308    /*** label at top to let user know who we are ***/
309 
310    xstr = XmStringCreateLtoR( "[No dataset]" ,
311 			      XmFONTLIST_DEFAULT_TAG ) ;
312    info_lab = XtVaCreateManagedWidget(
313 		 "AFNI" , xmLabelWidgetClass , rowcol ,
314 		    XmNlabelString , xstr ,
315 		    XmNinitialResourcesPersistent , False ,
316 		 NULL ) ;
317    XmStringFree(xstr) ;
318    MCW_register_help( info_lab , "Shows dataset being edited" ) ;
319    MCW_register_hint( info_lab , "Shows dataset being edited" ) ;
320 
321    /*** separator for visual neatness ***/
322 
323    (void) XtVaCreateManagedWidget(
324 	     "AFNI" , xmSeparatorWidgetClass , rowcol ,
325 		XmNseparatorType , XmSINGLE_LINE ,
326 		XmNinitialResourcesPersistent , False ,
327 	     NULL ) ;
328 
329    /*** button to let user choose dataset to edit ***/
330 
331    xstr = XmStringCreateLtoR( "Choose Dataset" , XmFONTLIST_DEFAULT_TAG ) ;
332    choose_pb = XtVaCreateManagedWidget(
333 		  "AFNI" , xmPushButtonWidgetClass , rowcol ,
334 		     XmNlabelString , xstr ,
335 		     XmNtraversalOn , True  ,
336 		     XmNinitialResourcesPersistent , False ,
337 		  NULL ) ;
338    XmStringFree(xstr) ;
339    XtAddCallback( choose_pb, XmNactivateCallback, DRAW_choose_CB, NULL ) ;
340    MCW_register_help( choose_pb ,
341 		      "Use this to popup a\n"
342 		      "'chooser' that lets\n"
343 		      "you select which\n"
344 		      "dataset to edit."
345 		    ) ;
346    MCW_register_hint( choose_pb , "Popup a dataset chooser" ) ;
347 
348    /***  arrowval to choose value that is drawn into dataset voxels  ***/
349 
350    value_av = new_MCW_arrowval( rowcol , "Drawing Value " ,
351 				MCW_AV_downup , -32767,32767,value_int ,
352 				MCW_AV_editext , 0 ,
353 				DRAW_value_CB , NULL , NULL,NULL ) ;
354 
355    MCW_reghelp_children( value_av->wrowcol ,
356 			 "Use this to set the value that\n"
357 			 "will be drawn into the dataset\n"
358 			 "using mouse button 2."
359 		       ) ;
360    MCW_reghint_children( value_av->wrowcol , "Goes into dataset voxels" ) ;
361 
362    /*** option menu to choose drawing color ***/
363 
364    color_av = new_MCW_colormenu( rowcol , "Drawing Color " , dc ,
365 				 1 , dc->ovc->ncol_ov - 1 , color_index ,
366 				 DRAW_color_CB , NULL ) ;
367 
368    MCW_reghelp_children( color_av->wrowcol ,
369 			 "Use this to set the color that is\n"
370 			 "shown during mouse button 2 drawing.\n"
371 			 "N.B.: After drawing is completed,\n"
372 			 "  the dataset will be displayed\n"
373 			 "  with the chosen value replacing\n"
374 			 "  the drawing color.  This color\n"
375 			 "  is used ONLY while button 2 is\n"
376 			 "  actually pressed down."
377 		       ) ;
378    MCW_reghint_children( color_av->wrowcol , "Used when button 2 is drawing" ) ;
379 
380    /*** arrowval to choose drawing mode ***/
381 
382    mode_av = new_MCW_optmenu( rowcol , "Drawing Mode  " ,
383 			      0 , NUM_modes-1 , 0,0 ,
384 			      DRAW_mode_CB , NULL ,
385 			      MCW_av_substring_CB , mode_strings ) ;
386 
387    MCW_reghelp_children( mode_av->wrowcol ,
388 			 "Use this to set the way in which\n"
389 			 "drawing pixels on the screen is\n"
390 			 "used to select dataset voxels:\n"
391 			 "Open Curve     = voxels picked along lines drawn;\n"
392 			 "Closed Curve   = voxels forming a closed curve\n"
393 			 "Points         = only voxels at X11 notify pixels;\n"
394 			 "Flood->Value   = flood fill from the chosen point\n"
395 			 "                 out to points = Drawing Value\n"
396 			 "Flood->Nonzero = flood fill from chosen point out\n"
397 			 "                 to any nonzero point"
398 		       ) ;
399    MCW_reghint_children( mode_av->wrowcol , "How voxels are chosen") ;
400 
401    /*** separator for visual neatness ***/
402 
403    (void) XtVaCreateManagedWidget(
404 	     "AFNI" , xmSeparatorWidgetClass , rowcol ,
405 		XmNseparatorType , XmSINGLE_LINE ,
406 		XmNinitialResourcesPersistent , False ,
407 	     NULL ) ;
408 
409    /*** a set of action buttons below the line ***/
410 
411    (void) MCW_action_area( rowcol , DRAW_actor , NACT ) ;
412 
413    undo_pb = (Widget) DRAW_actor[0].data ;
414    help_pb = (Widget) DRAW_actor[1].data ;
415    quit_pb = (Widget) DRAW_actor[2].data ;
416    save_pb = (Widget) DRAW_actor[3].data ;
417    done_pb = (Widget) DRAW_actor[4].data ;
418 
419    /*** that's all  (for Bob) ***/
420 
421    XtManageChild(rowcol) ;
422    XtRealizeWidget(shell) ; NI_sleep(1) ;       /* will not be mapped */
423 
424    r_main_mk_main_shell( );
425 
426    EXRETURN;
427 }
428 
429 
430 /*----------------------------------------------------------------------
431 **
432 **  Check the hostname of the computer.  If the name is not part of the
433 **  mcw.edu domain, then the machine is not authorized to use this plugin.
434 **
435 **----------------------------------------------------------------------
436  */
437 #if 0
438 static int
439 r_check_host( void )
440 {
441     long hostid = 0;
442 
443     hostid = gethostid( );
444 
445     if ( ( hostid & R_HOSTID_MASK ) != R_HOSTID_VAL )
446     {
447 	rERROR( "Your machine is not currently authorized to use this plugin.");
448 
449 	system( "echo GF usage :`whoami`@`hostname`|mail rickr@mcw.edu" );
450 
451 	return 0;
452     }
453 
454     return 1;
455 }
456 #endif
457 
458 /*----------------------------------------------------------------------
459 **
460 **  Create main GyrusFinder shell.
461 **
462 **----------------------------------------------------------------------
463  */
464 static void
r_main_mk_main_shell(void)465 r_main_mk_main_shell( void )
466 {
467     ENTRY("r_main_mk_main_shell");
468 #ifdef R_LOG_INFO_D
469     if ( ! r_open_log_file( ) ) EXRETURN ;
470 #endif
471 
472     r_wtgr_mk_main_shell  ( &gRX );
473     r_INT_mk_main_shell   ( &gRI );             /* interpolation shell */
474     r_HL_mk_main_shell    ( &gRH );             /* hole filler shell */
475     r_main_mk_show_buttons( );
476 
477     EXRETURN;
478 }
479 
480 
481 #ifdef R_LOG_INFO_D
482 /*----------------------------------------------------------------------
483 **
484 **  Open R_LOG_FILE to log messages to.
485 **
486 **----------------------------------------------------------------------
487  */
488 static int
r_open_log_file(void)489 r_open_log_file( void )
490 {
491     if ( ( gr_logfile = fopen( R_LOG_FILE, "a" ) ) == NULL )
492     {
493 	sprintf( gRmessage, "Failed to open '%s' for append.", R_LOG_FILE );
494 	rERROR( gRmessage );
495 
496 	return 0;
497     }
498 
499     return 1;
500 }
501 #endif
502 
503 
504 /*----------------------------------------------------------------------
505 **
506 **  Main window for buttons to show other windows.
507 **
508 **----------------------------------------------------------------------
509  */
510 static void
r_main_mk_show_buttons(void)511 r_main_mk_show_buttons( void )
512 {
513     int      ac;
514     Arg      al[ 10 ];
515     Widget   button, tmpb, tmpb2;
516     XmString xstr;
517 
518     ENTRY("r_main_mk_show_buttons");
519 
520     gRX.main_is_open = 1;
521 
522     ac = 0;
523     XtSetArg( al[ac], XmNinitialResourcesPersistent, False );  ac++;
524     XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING );  ac++;
525     gRX.main = XtAppCreateShell( "GyrusFinder", "rshell",
526 			topLevelShellWidgetClass, gRX.display, al, ac );
527 
528     XmAddWMProtocolCallback( gRX.main,
529 	XmInternAtom( gRX.display, "WM_DELETE_WINDOW", False ),
530 	( XtCallbackProc )r_main_cb_quit, ( XtPointer )NULL );
531 
532     ac = 0;
533     gRX.mainForm = XmCreateForm( gRX.main, "form", al, ac );
534 
535 
536     /* raise interpolator button */
537     ac = 0;
538     XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER );  ac++;
539     XtSetArg( al[ac], XmNwidth, 220 );  ac++;
540     xstr = XmStringCreateLtoR( "Interpolator", gRX.charset );
541     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
542     button = XmCreatePushButton( gRX.mainForm, "INT", al, ac );
543     XtManageChild( button );
544     XtAddCallback( button, XmNactivateCallback,
545 		   ( XtCallbackProc )r_any_cb_raise, "INT" );
546     XtSetSensitive( button, True );
547     XmStringFree(xstr) ;
548     tmpb = button;
549 
550     /* raise wtgr button */
551     ac = 0;
552     XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER );  ac++;
553     XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET );  ac++;
554     XtSetArg( al[ac], XmNtopWidget, tmpb );  ac++;
555     XtSetArg( al[ac], XmNwidth, 220 );  ac++;
556     xstr = XmStringCreateLtoR( "White/Gray Finder", gRX.charset );
557     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
558     button = XmCreatePushButton( gRX.mainForm, "WhiteGray", al, ac );
559     XtManageChild( button );
560     XtAddCallback( button, XmNactivateCallback,
561 		   ( XtCallbackProc )r_any_cb_raise, "wtgr" );
562     XtSetSensitive( button, True );
563     XmStringFree( xstr );
564     tmpb = button;
565 
566 
567     /* raise holes button */
568     ac = 0;
569     XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER );  ac++;
570     XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET );  ac++;
571     XtSetArg( al[ac], XmNtopWidget, tmpb );  ac++;
572     XtSetArg( al[ac], XmNwidth, 220 );  ac++;
573     xstr = XmStringCreateLtoR( "Hole Filler", gRX.charset );
574     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
575     button = XmCreatePushButton( gRX.mainForm, "fillholes", al, ac );
576     XtManageChild( button );
577     XtAddCallback( button, XmNactivateCallback,
578 		   ( XtCallbackProc )r_any_cb_raise, "HL" );
579     XtSetSensitive( button, True );
580     XmStringFree( xstr );
581     tmpb = button;
582 
583 
584     /* UNDO button */
585 
586     ac = 0;
587     XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER );  ac++;
588     XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET );  ac++;
589     XtSetArg( al[ac], XmNtopWidget, tmpb );  ac++;
590     XtSetArg( al[ac], XmNwidth, 110 );  ac++;
591     xstr = XmStringCreateLtoR( "UNDO", gRX.charset );
592     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
593     button = XmCreatePushButton( gRX.mainForm, "saveas", al, ac );
594     XtManageChild( button );
595     XtAddCallback( button, XmNactivateCallback,
596 		   ( XtCallbackProc )r_any_cb_undo, NULL );
597     XtSetSensitive( button, True );
598     XmStringFree( xstr );
599     tmpb2 = button;
600 
601 
602     /* save as button */
603 
604     ac = 0;
605     XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER );  ac++;
606     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
607     XtSetArg( al[ac], XmNleftWidget, button );  ac++;
608     XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET );  ac++;
609     XtSetArg( al[ac], XmNtopWidget, tmpb );  ac++;
610     XtSetArg( al[ac], XmNwidth, 110 );  ac++;
611     xstr = XmStringCreateLtoR( "Save As", gRX.charset );
612     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
613     button = XmCreatePushButton( gRX.mainForm, "saveas", al, ac );
614     XtManageChild( button );
615     XtAddCallback( button, XmNactivateCallback,
616 		   ( XtCallbackProc )r_any_cb_raise, "saveas" );
617     XtSetSensitive( button, True );
618     XmStringFree( xstr );
619     tmpb = button;
620 
621     /*
622     **  We're going to cheat a little here.  The "save as" widget will
623     **  be implemented as a child of the main RC.  So we need to create
624     **  the widget now, so the main "save as" button can raise/manage it.
625     */
626 
627     r_main_mk_save_as_fr( gRX.mainForm );
628 
629 
630     /* help button */
631     ac = 0;
632     XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER );  ac++;
633     XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET );  ac++;
634     XtSetArg( al[ac], XmNtopWidget, tmpb2 );  ac++;
635     XtSetArg( al[ac], XmNwidth, 110 );  ac++;
636     xstr = XmStringCreateLtoR( "Help", gRX.charset );
637     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
638     button = XmCreatePushButton( gRX.mainForm, "help", al, ac );
639     XtManageChild( button );
640     XtAddCallback( button, XmNactivateCallback,
641 		   ( XtCallbackProc )r_main_cb_help, NULL );
642     XtSetSensitive( button, True );
643     XmStringFree( xstr );
644 
645 
646     /* show data structures button */
647     ac = 0;
648     XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER );  ac++;
649     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
650     XtSetArg( al[ac], XmNleftWidget, button );  ac++;
651     XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET );  ac++;
652     XtSetArg( al[ac], XmNtopWidget, tmpb );  ac++;
653     XtSetArg( al[ac], XmNwidth, 110 );  ac++;
654     xstr = XmStringCreateLtoR( "structs", gRX.charset );
655     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
656     button = XmCreatePushButton( gRX.mainForm, "structs", al, ac );
657     XtManageChild( button );
658     XtAddCallback( button, XmNactivateCallback,
659 		   ( XtCallbackProc )r_main_cb_show_structs, NULL );
660     XtSetSensitive( button, True );
661     XmStringFree( xstr );
662 
663 
664     XtManageChild( gRX.mainForm );
665     XtRealizeWidget( gRX.main ); NI_sleep(1) ;
666 
667     EXRETURN;
668 }
669 
670 
671 /*----------------------------------------------------------------------
672 **
673 **  Create the save as widget under the main RC.
674 **
675 **----------------------------------------------------------------------
676  */
677 static void
r_main_mk_save_as_fr(Widget parent)678 r_main_mk_save_as_fr( Widget parent )
679 {
680     Widget   button, junk, hrc, vrc, frame;
681     Arg      al[ 10 ];
682     int      ac;
683     char     string[ 25 ];
684 
685     ENTRY("r_main_mk_save_as_fr");
686 
687       XtVaSetValues( shell ,
688 		       XmNmwmFunctions ,
689 		       MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE ,
690 		     NULL ) ;
691     ac = 0;
692     XtSetArg( al[ ac ], XmNdialogTitle,
693 	    XmStringCreateLtoR( "Save As", gRX.charset ) );  ac++;
694     XtSetArg( al[ ac ], XmNtextString,
695 	    XmStringCreateLtoR( gRA.save_as_name, gRX.charset ) );  ac++;
696     XtSetArg( al[ ac ], XmNselectionLabelString,
697 	    XmStringCreateLtoR( "AFNI prefix : ", gRX.charset ) );  ac++;
698     XtSetArg( al[ ac ], XmNokLabelString,
699 	    XmStringCreateLtoR( "save", gRX.charset ) );            ac++;
700     XtSetArg( al[ ac ], XmNapplyLabelString,
701 	    XmStringCreateLtoR( "overwrite", gRX.charset ) );       ac++;
702     XtSetArg( al[ ac ], XmNcancelLabelString,
703 	    XmStringCreateLtoR( "hide", gRX.charset ) );            ac++;
704     XtSetArg( al[ ac ], XmNminimizeButtons, True );                 ac++;
705     XtSetArg( al[ac], XmNinitialResourcesPersistent, False );       ac++;
706     XtSetArg( al[ac], XmNmappedWhenManaged, False );                ac++;
707     XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING );            ac++;
708     gRX.save_as_file_d = XmCreatePromptDialog( parent, "dialog", al, ac );
709 
710     XmAddWMProtocolCallback( gRX.save_as_file_d,
711 	XmInternAtom( gRX.display, "WM_DELETE_WINDOW", False ),
712 	( XtCallbackProc )r_any_cb_hide, "saveas" );
713 
714     XtAddCallback( gRX.save_as_file_d, XmNokCallback,
715 	    ( XtCallbackProc )r_main_cb_saveas, ( XtPointer )0 );
716     XtAddCallback( gRX.save_as_file_d, XmNapplyCallback,
717 	    ( XtCallbackProc )r_main_cb_saveas, ( XtPointer )1 );
718     XtAddCallback( gRX.save_as_file_d, XmNcancelCallback,
719 	    ( XtCallbackProc )r_any_cb_hide, "saveas" );
720 
721     XtManageChild( XmSelectionBoxGetChild( gRX.save_as_file_d,
722 					     XmDIALOG_APPLY_BUTTON ) );
723     XtUnmanageChild( XmSelectionBoxGetChild( gRX.save_as_file_d,
724 					     XmDIALOG_HELP_BUTTON ) );
725 
726     XtManageChild( gRX.save_as_file_d );
727 
728     VISIBILIZE_WHEN_MAPPED(gRX.save_as_file_d) ; /* 27 Sep 2000 */
729 
730     /*
731     ** Once we prevent it from popping up immediately, set it to display
732     ** anytime it's managed.
733     */
734     ac = 0;
735     XtSetArg( al[ac], XmNmappedWhenManaged, True );  ac++;
736     XtSetValues( gRX.save_as_file_d, al, ac );
737 
738     EXRETURN;
739 }
740 
741 
742 /*----------------------------------------------------------------------
743 **
744 **  Create main shell and gray and white matter function frames.
745 **
746 **----------------------------------------------------------------------
747  */
748 static void
r_wtgr_mk_main_shell(r_X_s * X)749 r_wtgr_mk_main_shell( r_X_s * X )
750 {
751     Widget    junk, frame, rc;
752     XmString  xstring;
753     Arg       al[ 20 ];
754     int       ac;
755 
756     ENTRY("r_wtgr_mk_main_shell");
757 
758 /* create a main RC widget with four frame children */
759 
760     if ( ! r_init_Alg_values( &gRA ) )
761 	EXRETURN;
762 
763     if ( ! r_init_pt_conn_s( &gRCP ) )
764 	EXRETURN;
765 
766     X->display = dc->display;
767     X->charset = XmSTRING_DEFAULT_CHARSET;
768 
769     ac = 0;
770     XtSetArg( al[ac], XmNinitialResourcesPersistent, False );  ac++;
771     XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING );  ac++;
772     XtSetArg( al[ac], XmNmappedWhenManaged, False );  ac++;
773     X->wtgr_main = XtAppCreateShell( "White/Gray Finder", "rshell",
774 		topLevelShellWidgetClass, X->display, al, ac );
775 
776     XmAddWMProtocolCallback( gRX.wtgr_main,
777 	XmInternAtom( gRX.display, "WM_DELETE_WINDOW", False ),
778 	( XtCallbackProc )r_any_cb_hide, "wtgr" );
779 
780     ac = 0;
781     XtSetArg( al[ac], XmNspacing,      15 );  ac++;
782     XtSetArg( al[ac], XmNmarginWidth,  10 );  ac++;
783     XtSetArg( al[ac], XmNmarginHeight, 10 );  ac++;
784     X->wtgr_mainRC = XmCreateRowColumn( X->wtgr_main, "rowcolumn", al, ac );
785 
786     /* create the main white and gray selection frames */
787     ( void )r_wt_mk_main_frame( X, X->wtgr_mainRC );
788     ( void )r_gr_mk_main_frame( X, X->wtgr_mainRC );
789 
790 
791     XtManageChild( X->wtgr_mainRC );
792     XtRealizeWidget( X->wtgr_main );
793 
794     EXRETURN ;
795 }
796 
797 
798 /*----------------------------------------------------------------------
799 **
800 **  Create the Hole Filler shell.
801 **
802 **----------------------------------------------------------------------
803  */
804 static void
r_HL_mk_main_shell(holes_s * H)805 r_HL_mk_main_shell( holes_s * H )
806 {
807     Widget    junk, frame, rc;
808     XmString  xstring;
809     Arg       al[ 20 ];
810     int       ac;
811 
812     ENTRY("r_HL_mk_main_shell");
813 
814     if ( ! r_init_holes_vals( H ) )
815 	EXRETURN;
816 
817     ac = 0;
818     XtSetArg( al[ac], XmNinitialResourcesPersistent, False );  ac++;
819     XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING );  ac++;
820     XtSetArg( al[ac], XmNmappedWhenManaged, False );  ac++;
821     H->main = XtAppCreateShell( "Hole Filler", "rshell",
822 			topLevelShellWidgetClass, gRX.display, al, ac );
823 
824     XmAddWMProtocolCallback( gRH.main,
825 	XmInternAtom( gRX.display, "WM_DELETE_WINDOW", False ),
826 	( XtCallbackProc )r_any_cb_hide, "HL" );
827 
828     ac = 0;
829     XtSetArg( al[ac], XmNspacing,      15 );  ac++;
830     XtSetArg( al[ac], XmNmarginWidth,  10 );  ac++;
831     XtSetArg( al[ac], XmNmarginHeight, 10 );  ac++;
832     H->mainRC = XmCreateRowColumn( H->main, "rowcolumn", al, ac );
833 
834     ( void )r_HL_mk_fillval_fr( H, H->mainRC );
835     ( void )r_HL_mk_maxsize_fr( H, H->mainRC );
836     ( void )r_HL_mk_buttons   ( H, H->mainRC );
837 
838     XtManageChild  ( H->mainRC );
839     XtRealizeWidget( H->main ); NI_sleep(1) ;
840 
841     EXRETURN;
842 }
843 
844 
845 /*----------------------------------------------------------------------
846 **
847 **  Create buttons for the "hole filling" app.
848 **
849 **----------------------------------------------------------------------
850  */
851 static Widget
r_HL_mk_buttons(holes_s * H,Widget parent)852 r_HL_mk_buttons( holes_s * H, Widget parent )
853 {
854     int      ac;
855     Arg      al[ 10 ];
856     Widget   form, frame, button1, button2;
857     XmString xstr;
858 
859     ENTRY("r_HL_mk_buttons");
860 
861     /* create frame to hold form and buttons */
862     ac = 0;
863     frame = XmCreateFrame( parent, "frame", al, ac );
864 
865     /* create form to hold push buttons */
866     ac = 0;
867     XtSetArg( al[ac], XmNhorizontalSpacing, R_BUTTON_SPACE );  ac++;
868     form = XmCreateForm( frame, "form", al, ac );
869 
870 
871     /* region fill button */
872     ac = 0;
873     xstr = XmStringCreateLtoR( "FILL", gRX.charset );
874     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
875     button1 = XmCreatePushButton( form, "fill", al, ac );
876     XtManageChild( button1 );
877     XtAddCallback( button1, XmNactivateCallback,
878 		   ( XtCallbackProc )r_HL_cb_fill, H );
879     XtSetSensitive( button1, True );
880     XmStringFree( xstr );
881 
882     /* unfill button */
883     ac = 0;
884     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
885     XtSetArg( al[ac], XmNleftWidget, button1 );  ac++;
886     xstr = XmStringCreateLtoR( "unfill", gRX.charset );
887     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
888     button2 = XmCreatePushButton( form, "unfill", al, ac );
889     XtManageChild( button2 );
890     XtAddCallback( button2, XmNactivateCallback,
891 		   ( XtCallbackProc )r_any_cb_unfill, &H->fill_val );
892     XtSetSensitive( button2, True );
893     XmStringFree( xstr );
894 
895 
896     /* stats button */
897     ac = 0;
898     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
899     XtSetArg( al[ac], XmNleftWidget, button2 );  ac++;
900     xstr = XmStringCreateLtoR( "stats", gRX.charset );
901     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
902     button1 = XmCreatePushButton( form, "stats", al, ac );
903     XtManageChild( button1 );
904     XtAddCallback( button1, XmNactivateCallback,
905 		   ( XtCallbackProc )r_any_cb_fill_stats, &gRH.fill_val );
906     XtSetSensitive( button1, True );
907     XmStringFree( xstr );
908 
909     /* hide button */
910     ac = 0;
911     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
912     XtSetArg( al[ac], XmNleftWidget, button1 );  ac++;
913     xstr = XmStringCreateLtoR( "hide", gRX.charset );
914     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
915     button2 = XmCreatePushButton( form, "hide", al, ac );
916     XtManageChild( button2 );
917     XtAddCallback( button2, XmNactivateCallback,
918 		   ( XtCallbackProc )r_any_cb_hide, "HL" );
919     XtSetSensitive( button2, True );
920     XmStringFree( xstr );
921 
922 
923     XtManageChild( form );
924     XtManageChild( frame );
925 
926     RETURN( frame );
927 }
928 
929 
930 /*----------------------------------------------------------------------
931 **
932 **  Create the "max hole size" widget for hole filler window.
933 **
934 **----------------------------------------------------------------------
935  */
936 static Widget
r_HL_mk_maxsize_fr(holes_s * H,Widget parent)937 r_HL_mk_maxsize_fr( holes_s * H, Widget parent )
938 {
939     Widget   junk, rc, frame;
940     XmString xstr;
941     Arg      al[ 10 ];
942     int      ac;
943     char     string[ 15 ];
944 
945     ENTRY("r_HL_mk_maxsize_fr");
946 
947     ac = 0;
948     frame = XmCreateFrame( parent, "frame", al, ac );
949 
950     ac = 0;
951     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
952     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
953     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
954 
955 
956     sprintf( string, "%d", H->max_size );
957 
958     ac = 0;
959     xstr = XmStringCreateLtoR( "max size      : ", gRX.charset );
960     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
961     junk = XmCreateLabel( rc, "label", al, ac );
962     XtManageChild( junk );
963     XmStringFree( xstr );
964 
965     ac = 0;
966     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
967     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
968     H->maxsize_w = XmCreateText( rc, "text", al, ac );
969     XtManageChild( H->maxsize_w );
970     XtAddCallback( H->maxsize_w, XmNactivateCallback,
971 	    ( XtCallbackProc )r_HL_cb_set_maxsize, NULL );
972     XtAddCallback( H->maxsize_w, XmNlosingFocusCallback,
973 	    ( XtCallbackProc )r_HL_cb_set_maxsize, NULL );
974 
975 
976     XtManageChild( rc );
977     XtManageChild( frame );
978 
979     RETURN( frame );
980 }
981 
982 
983 /*----------------------------------------------------------------------
984 **
985 **  Create the "fill value" widget for hole filler window.
986 **
987 **----------------------------------------------------------------------
988 */
989 static Widget
r_HL_mk_fillval_fr(holes_s * H,Widget parent)990 r_HL_mk_fillval_fr( holes_s * H, Widget parent )
991 {
992     Widget   junk, rc, frame;
993     XmString xstr;
994     Arg      al[ 10 ];
995     int      ac;
996     char     string[ 15 ];
997 
998     ENTRY("r_HL_mk_fillval_fr");
999 
1000     ac = 0;
1001     frame = XmCreateFrame( parent, "frame", al, ac );
1002 
1003     ac = 0;
1004     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
1005     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
1006     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
1007 
1008 
1009     sprintf( string, "%d", H->fill_val );
1010 
1011     ac = 0;
1012     xstr = XmStringCreateLtoR( "fill value    : ", gRX.charset );
1013     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
1014     junk = XmCreateLabel( rc, "label", al, ac );
1015     XtManageChild( junk );
1016     XmStringFree( xstr );
1017 
1018     ac = 0;
1019     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
1020     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
1021     H->fillval_w = XmCreateText( rc, "text", al, ac );
1022     XtManageChild( H->fillval_w );
1023     XtAddCallback( H->fillval_w, XmNactivateCallback,
1024 	    ( XtCallbackProc )r_HL_cb_set_fill_val, NULL );
1025     XtAddCallback( H->fillval_w, XmNlosingFocusCallback,
1026 	    ( XtCallbackProc )r_HL_cb_set_fill_val, NULL );
1027 
1028 
1029     XtManageChild( rc );
1030     XtManageChild( frame );
1031 
1032     RETURN( frame );
1033 }
1034 
1035 
1036 /*----------------------------------------------------------------------
1037 **
1038 **  Initialize the holes_s structure.
1039 **
1040 **----------------------------------------------------------------------
1041  */
1042 static int
r_init_holes_vals(holes_s * H)1043 r_init_holes_vals( holes_s * H )
1044 {
1045     ENTRY("r_init_holes_vals");
1046 
1047     H->max_size = 6;
1048     H->fill_val = 3;
1049 
1050     H->filled.points = NULL;
1051     H->filled.used   = 0;
1052     H->filled.M      = 0;
1053 
1054     RETURN(1);
1055 }
1056 
1057 
1058 /*----------------------------------------------------------------------
1059 **
1060 **  Fill all interior holes, subject to a size restriction.
1061 **
1062 **----------------------------------------------------------------------
1063  */
1064 static void
r_HL_cb_fill(Widget w,XtPointer client_data,XtPointer call_data)1065 r_HL_cb_fill(
1066 	Widget w,
1067 	XtPointer client_data,
1068 	XtPointer call_data
1069 	)
1070 {
1071     points_t   Marked, Search;
1072     holes_s  * H = (holes_s *)client_data;
1073     short    * fdata = gRA.fdata;
1074     short    * fptr, * uptr;
1075     int      * wgpts, *tmpp;
1076     int        count, fill_size, coord, status, pcount;
1077 
1078     ENTRY("r_HL_cb_fill");
1079 
1080     /* first store fdata to undo_data  */
1081     fptr = gRA.fdata; uptr = gRA.undo_data;
1082     for ( count = 0; count < gRA.nvox; count++ )
1083 	*uptr++ = *fptr++;
1084 
1085 
1086     Search.points = Marked.points = NULL;
1087 
1088     /* add gRA.border and gr_edge to wtgr_edge */
1089     H->wtgr_edge.used = 0;
1090     for ( count = 0, wgpts = H->gr_edge.points;
1091 	  count < H->gr_edge.used;
1092 	  count++, wgpts++ )
1093 	if ( ! r_add_to_boundary( &H->wtgr_edge, *wgpts ) )
1094 	    EXRETURN;
1095 
1096     for ( count = 0, wgpts = gRA.border.points;
1097 	  count < gRA.border.used;
1098 	  count++, wgpts++ )
1099 	if ( ! r_add_to_boundary( &H->wtgr_edge, *wgpts ) )
1100 	    EXRETURN;
1101 
1102     /* for each point in white/gray boundary - try to grow */
1103     /* (watch for 3-D brick edges) */
1104     for ( count = 0, wgpts = H->wtgr_edge.points;
1105 	  count < H->wtgr_edge.used;
1106 	  count++, wgpts++ )
1107     {
1108 
1109 	fill_size = 0;                  /* init for current fill region */
1110 
1111 	fptr = fdata + *wgpts;          /* addr + coordinate (offset) */
1112 	if ( *fptr )
1113 	   continue;
1114 
1115 	if ( ! r_add_to_boundary( &Search, *wgpts ) )
1116 	    EXRETURN;
1117 
1118 	while ( Search.used > 0 )
1119 	{
1120 	    coord = Search.points[Search.used - 1];
1121 	    Search.used--;
1122 
1123 	    *(fdata + coord) = H->fill_val;     /* mark as found */
1124 	    if ( ! r_add_to_boundary( &Marked, coord ) )
1125 		EXRETURN;
1126 
1127 	    fill_size++;
1128 
1129 	    /* 1 = OK, 0 = BAD point found, -1 = memory error */
1130 	    if ( ( status = r_HL_check_neighbors( &Search, coord ) ) == -1 )
1131 		EXRETURN;
1132 
1133 	    if ( ( fill_size > H->max_size ) || ( status == 0 ) )
1134 	    {
1135 		status = 0;     /* if we enter through fill_size */
1136 
1137 		for ( pcount = 0, tmpp = Search.points;
1138 		      pcount < Search.used;
1139 		      pcount++, tmpp++ )
1140 		    *(fdata + *tmpp) = R_HL_BAD_VAL;
1141 
1142 		Search.used = 0;        /* will terminate search loop */
1143 
1144 		for ( pcount = 0, tmpp = Marked.points;
1145 		      pcount < Marked.used;
1146 		      pcount++, tmpp++ )
1147 		    *(fdata + *tmpp) = R_HL_BAD_VAL;
1148 
1149 		Marked.used = 0;
1150 	    }
1151 	}
1152 
1153 	Marked.used = 0;
1154     }
1155 
1156     /* reset all BAD_VAL points - we haven't saved them */
1157     for ( count = 0, fptr = fdata; count < gRA.nvox; count++, fptr++ )
1158 	if ( *fptr == R_HL_BAD_VAL )
1159 	    *fptr = 0;
1160 
1161 
1162     THD_load_statistics( gRA.func ) ;
1163     PLUTO_dset_redisplay( gRA.func ) ;
1164 
1165     dset_changed = 1;
1166 
1167     EXRETURN;
1168 }
1169 
1170 
1171 /*----------------------------------------------------------------------
1172 **
1173 **  Check neighbors for insertion into searchlist, or for BAD values.
1174 **
1175 **  Make sure we don't "leave" the 3-D image.
1176 **
1177 **  return 1 - normal
1178 **         0 - BAD point found
1179 **        -1 - memory error ( r_add_to_boundary() )
1180 **
1181 **----------------------------------------------------------------------
1182  */
1183 static int
r_HL_check_neighbors(points_t * P,int coord)1184 r_HL_check_neighbors( points_t * P, int coord )
1185 {
1186     short * nptr  = gRA.neighbors;
1187     short * fvalp = NULL;
1188     int     nx, nxy, value;
1189 
1190     ENTRY("r_HL_check_neighbors");
1191 
1192     nx  = gRA.nx;
1193     nxy = gRA.nxy;
1194 
1195     if ( nptr[ coord ] == -1 )  /* do not accept edge points */
1196 	RETURN(1);  /* normal return */
1197 
1198     fvalp = gRA.fdata + coord;
1199 
1200     value = *(fvalp - 1);
1201     if ( value == R_HL_BAD_VAL )
1202 	RETURN(0);
1203     else if ( ! value )
1204 	if ( ! r_add_to_boundary( P, coord - 1 ) )
1205 	    RETURN(-1);
1206 
1207     value = *(fvalp + 1);
1208     if ( value == R_HL_BAD_VAL )
1209 	RETURN(0);
1210     else if ( ! value )
1211 	if ( ! r_add_to_boundary( P, coord + 1 ) )
1212 	    RETURN(-1);
1213 
1214     value = *(fvalp - nx);
1215     if ( value == R_HL_BAD_VAL )
1216 	RETURN(0);
1217     else if ( ! value )
1218 	if ( ! r_add_to_boundary( P, coord - nx ) )
1219 	    RETURN(-1);
1220 
1221     value = *(fvalp + nx);
1222     if ( value == R_HL_BAD_VAL )
1223 	RETURN(0);
1224     else if ( ! value )
1225 	if ( ! r_add_to_boundary( P, coord + nx ) )
1226 	    RETURN(-1);
1227 
1228     value = *(fvalp - nxy);
1229     if ( value == R_HL_BAD_VAL )
1230 	RETURN(0);
1231     else if ( ! value )
1232 	if ( ! r_add_to_boundary( P, coord - nxy ) )
1233 	    RETURN(-1);
1234 
1235     value = *(fvalp + nxy);
1236     if ( value == R_HL_BAD_VAL )
1237 	RETURN(0);
1238     else if ( ! value )
1239 	if ( ! r_add_to_boundary( P, coord + nxy ) )
1240 	    RETURN(-1);
1241 
1242     RETURN(0);
1243 }
1244 
1245 
1246 /*----------------------------------------------------------------------
1247 **
1248 **  Create interpolation shell.
1249 **
1250 **----------------------------------------------------------------------
1251  */
1252 static void
r_INT_mk_main_shell(interp_s * I)1253 r_INT_mk_main_shell( interp_s * I )
1254 {
1255     Widget    junk, frame, rc;
1256     XmString  xstring;
1257     Arg       al[ 20 ];
1258     int       ac;
1259 
1260     ENTRY("r_INT_mk_main_shell");
1261 
1262     if ( ! r_init_interp_vals( I ) )
1263 	EXRETURN;
1264 
1265     ac = 0;
1266     XtSetArg( al[ac], XmNinitialResourcesPersistent, False );  ac++;
1267     XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING );  ac++;
1268     XtSetArg( al[ac], XmNmappedWhenManaged, False );  ac++;
1269     I->main = XtAppCreateShell( "The Interpolator",
1270 		"rshell", topLevelShellWidgetClass, gRX.display, al, ac );
1271 
1272     XmAddWMProtocolCallback( I->main,
1273 	XmInternAtom( gRX.display, "WM_DELETE_WINDOW", False ),
1274 	( XtCallbackProc )r_any_cb_hide, "INT" );
1275 
1276     ac = 0;
1277     XtSetArg( al[ac], XmNspacing,      15 );  ac++;
1278     XtSetArg( al[ac], XmNmarginWidth,  10 );  ac++;
1279     XtSetArg( al[ac], XmNmarginHeight, 10 );  ac++;
1280     I->mainRC = XmCreateRowColumn( I->main, "rowcolumn", al, ac );
1281 
1282     /* create the main white and gray selection frames */
1283     ( void )r_INT_mk_fillval_fr ( I, I->mainRC );
1284     ( void )r_INT_mk_app_buttons( I, I->mainRC );
1285 
1286     XtManageChild( I->mainRC );
1287     XtRealizeWidget( I->main ); NI_sleep(1) ;
1288 
1289     EXRETURN ;
1290 }
1291 
1292 
1293 /*----------------------------------------------------------------------
1294 **
1295 **  Create boundary (gray matter) buttons.
1296 **
1297 **----------------------------------------------------------------------
1298  */
1299 static Widget
r_INT_mk_app_buttons(interp_s * I,Widget parent)1300 r_INT_mk_app_buttons( interp_s * I, Widget parent )
1301 {
1302     int      ac;
1303     Arg      al[ 10 ];
1304     Widget   form, frame, button1, button2;
1305     XmString xstr;
1306 
1307     ENTRY("r_INT_mk_app_buttons");
1308 
1309     /* create frame to hold form and buttons */
1310     ac = 0;
1311     frame = XmCreateFrame( parent, "frame", al, ac );
1312 
1313     /* create form to hold push buttons */
1314     ac = 0;
1315     XtSetArg( al[ac], XmNhorizontalSpacing, R_BUTTON_SPACE );  ac++;
1316     form = XmCreateForm( frame, "form", al, ac );
1317 
1318 
1319     /* region fill button */
1320     ac = 0;
1321     xstr = XmStringCreateLtoR( "FILL", gRX.charset );
1322     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
1323     button1 = XmCreatePushButton( form, "fill", al, ac );
1324     XtManageChild( button1 );
1325     XtAddCallback( button1, XmNactivateCallback,
1326 		   ( XtCallbackProc )r_INT_cb_fill, I );
1327     XtSetSensitive( button1, True );
1328     XmStringFree( xstr );
1329     MCW_register_hint( button1 , "interpolate between the last two lines" );
1330 
1331     /* unfill button */
1332     ac = 0;
1333     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
1334     XtSetArg( al[ac], XmNleftWidget, button1 );  ac++;
1335     xstr = XmStringCreateLtoR( "unfill", gRX.charset );
1336     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
1337     button2 = XmCreatePushButton( form, "unfill", al, ac );
1338     XtManageChild( button2 );
1339     XtAddCallback( button2, XmNactivateCallback,
1340 		   ( XtCallbackProc )r_any_cb_unfill, &gRI.fill_val );
1341     XtSetSensitive( button2, True );
1342     XmStringFree( xstr );
1343     MCW_register_hint( button2 , "unfill at interpolation \"fill value\"" );
1344 
1345     /* apply button - set interpolation values to draw values */
1346     ac = 0;
1347     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
1348     XtSetArg( al[ac], XmNleftWidget, button2 );  ac++;
1349     xstr = XmStringCreateLtoR( "apply", gRX.charset );
1350     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
1351     button1 = XmCreatePushButton( form, "apply", al, ac );
1352     XtManageChild( button1 );
1353     XtAddCallback( button1, XmNactivateCallback,
1354 		   ( XtCallbackProc )r_any_cb_apply, &gRI.fill_val );
1355     XtSetSensitive( button1, True );
1356     XmStringFree( xstr );
1357     MCW_register_hint( button1 , "sets fill values to main draw values" );
1358 
1359 
1360     /* stats button */
1361     ac = 0;
1362     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
1363     XtSetArg( al[ac], XmNleftWidget, button1 );  ac++;
1364     xstr = XmStringCreateLtoR( "stats", gRX.charset );
1365     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
1366     button2 = XmCreatePushButton( form, "stats", al, ac );
1367     XtManageChild( button2 );
1368     XtAddCallback( button2, XmNactivateCallback,
1369 		   ( XtCallbackProc )r_any_cb_fill_stats, &gRI.fill_val );
1370     XtSetSensitive( button2, True );
1371     XmStringFree( xstr );
1372 
1373     /* hide button */
1374     ac = 0;
1375     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
1376     XtSetArg( al[ac], XmNleftWidget, button2 );  ac++;
1377     xstr = XmStringCreateLtoR( "hide", gRX.charset );
1378     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
1379     button1 = XmCreatePushButton( form, "hide", al, ac );
1380     XtManageChild( button1 );
1381     XtAddCallback( button1, XmNactivateCallback,
1382 		   ( XtCallbackProc )r_any_cb_hide, "INT" );
1383     XtSetSensitive( button1, True );
1384     XmStringFree( xstr );
1385 
1386 
1387     XtManageChild( form );
1388     XtManageChild( frame );
1389 
1390     RETURN( frame );
1391 }
1392 
1393 
1394 /*----------------------------------------------------------------------
1395 **
1396 **  Create the "fill value" widget for interpolation window.
1397 **
1398 **----------------------------------------------------------------------
1399  */
1400 static Widget
r_INT_mk_fillval_fr(interp_s * I,Widget parent)1401 r_INT_mk_fillval_fr( interp_s * I, Widget parent )
1402 {
1403     Widget   junk, rc, frame;
1404     XmString xstr;
1405     Arg      al[ 10 ];
1406     int      ac;
1407     char     string[ 15 ];
1408 
1409     ENTRY("r_INT_mk_fillval_fr");
1410 
1411     ac = 0;
1412     frame = XmCreateFrame( parent, "frame", al, ac );
1413 
1414     ac = 0;
1415     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
1416     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
1417     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
1418 
1419 
1420     sprintf( string, "%d", I->fill_val );
1421 
1422     ac = 0;
1423     xstr = XmStringCreateLtoR( "fill value   : ", gRX.charset );
1424     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
1425     junk = XmCreateLabel( rc, "label", al, ac );
1426     XtManageChild( junk );
1427     XmStringFree( xstr );
1428 
1429     ac = 0;
1430     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
1431     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
1432     I->fillval_w = XmCreateText( rc, "text", al, ac );
1433     XtManageChild( I->fillval_w );
1434     XtAddCallback( I->fillval_w, XmNactivateCallback,
1435 	    ( XtCallbackProc )r_INT_cb_set_fill_val, NULL );
1436     XtAddCallback( I->fillval_w, XmNlosingFocusCallback,
1437 	    ( XtCallbackProc )r_INT_cb_set_fill_val, NULL );
1438 
1439 
1440     XtManageChild( rc );
1441     XtManageChild( frame );
1442 
1443     RETURN( frame );
1444 }
1445 
1446 
1447 /*----------------------------------------------------------------------
1448 **
1449 **  Callback to apply the interpolation values (change them to
1450 **  drawn values).
1451 **
1452 **----------------------------------------------------------------------
1453  */
1454 static void
r_any_cb_apply(Widget w,XtPointer client_data,XtPointer call_data)1455 r_any_cb_apply(
1456 	Widget w,
1457 	XtPointer client_data,
1458 	XtPointer call_data
1459 	)
1460 {
1461     short  * fptr, * uptr;
1462     int      clear_val = *( (int *)client_data );
1463     int      count;
1464 
1465     ENTRY("r_any_cb_apply");
1466 
1467     if ( ! gRA.fdata )  /* error beep */
1468     {
1469 	fprintf( stderr, "%c", 7 );
1470 	EXRETURN;
1471     }
1472 
1473     /* first store to undo_data */
1474     fptr = gRA.fdata; uptr = gRA.undo_data;
1475     for ( count = 0; count < gRA.nvox; count++ )
1476 	*uptr++ = *fptr++;
1477 
1478     for ( count = 0, fptr = gRA.fdata; count < gRA.nvox; count++, fptr++ )
1479 	if ( *fptr == clear_val )
1480 	    *fptr = value_int;
1481 
1482     THD_load_statistics( gRA.func ) ;
1483     PLUTO_dset_redisplay( gRA.func ) ;
1484 
1485     EXRETURN;
1486 }
1487 
1488 
1489 /*----------------------------------------------------------------------
1490 **
1491 **  Callback to hide windows.
1492 **
1493 **----------------------------------------------------------------------
1494  */
1495 static void
r_any_cb_hide(Widget w,char * client_data,XtPointer call_data)1496 r_any_cb_hide(
1497 	Widget w,
1498 	char *    client_data,
1499 	XtPointer call_data
1500 	)
1501 {
1502     ENTRY("r_any_cb_hide");
1503 
1504     if      ( ! strcmp( client_data, "INT" ) )
1505 	XtUnmapWidget( gRI.main );
1506     else if ( ! strcmp( client_data, "HL" ) )
1507 	XtUnmapWidget( gRH.main );
1508     else if ( ! strcmp( client_data, "wtgr" ) )
1509 	XtUnmapWidget( gRX.wtgr_main );
1510     else if ( ! strcmp( client_data, "saveas" ) )
1511 	XtUnmanageChild( gRX.save_as_file_d );
1512     else if ( ! strcmp( client_data, "all" ) )
1513     {
1514 	XtUnmapWidget( gRI.main );
1515 	XtUnmapWidget( gRH.main );
1516 	XtUnmapWidget( gRX.wtgr_main );
1517 	XtUnmanageChild( gRX.save_as_file_d );
1518     }
1519     else
1520     {
1521 	sprintf( gRmessage, "rach_10 : client_data is '%s'\n", client_data );
1522 	rERROR( gRmessage );
1523     }
1524 
1525     EXRETURN;
1526 }
1527 
1528 
1529 /*----------------------------------------------------------------------
1530 **
1531 **  Callback to raise windows.
1532 **
1533 **----------------------------------------------------------------------
1534  */
1535 static void
r_any_cb_raise(Widget w,char * client_data,XtPointer call_data)1536 r_any_cb_raise(
1537 	Widget w,
1538 	char    * client_data,
1539 	XtPointer call_data
1540 	)
1541 {
1542     ENTRY("r_any_cb_raise");
1543 
1544     if      ( ! strcmp( client_data, "INT" ) )
1545     {
1546 	XMapRaised( XtDisplay( gRI.main ) , XtWindow( gRI.main ) ); NI_sleep(1);
1547     }
1548     else if ( ! strcmp( client_data, "HL" ) )
1549     {
1550 	XMapRaised( XtDisplay( gRH.main ) , XtWindow( gRH.main ) ); NI_sleep(1);
1551     }
1552     else if ( ! strcmp( client_data, "wtgr" ) )
1553     {
1554 	XMapRaised( XtDisplay( gRX.wtgr_main ) , XtWindow( gRX.wtgr_main ) ); NI_sleep(1);
1555     }
1556     else if ( ! strcmp( client_data, "saveas" ) )
1557     {
1558 	XtManageChild( gRX.save_as_file_d );
1559 	XtPopup( XtParent( gRX.save_as_file_d ), XtGrabNone ); NI_sleep(1);
1560     }
1561     else if ( ! strcmp( client_data, "all" ) )
1562     {
1563 	XMapRaised( XtDisplay( gRI.main ) , XtWindow( gRI.main ) ); NI_sleep(1);
1564 	XMapRaised( XtDisplay( gRH.main ) , XtWindow( gRH.main ) ); NI_sleep(1);
1565 	XMapRaised( XtDisplay( gRX.wtgr_main ) , XtWindow( gRX.wtgr_main ) ); NI_sleep(1);
1566 	XtManageChild( gRX.save_as_file_d );
1567 	XtPopup( XtParent( gRX.save_as_file_d ), XtGrabNone ); NI_sleep(1);
1568     }
1569     else
1570     {
1571 	sprintf( gRmessage, "racr_10 : client_data is '%s'\n", client_data );
1572 	rERROR( gRmessage );
1573     }
1574 
1575     EXRETURN;
1576 }
1577 
1578 
1579 /*----------------------------------------------------------------------
1580 **
1581 **  Callback to undo previous action (restore fdata from undo_data).
1582 **
1583 **----------------------------------------------------------------------
1584  */
1585 static void
r_any_cb_undo(Widget w,XtPointer client_data,XtPointer call_data)1586 r_any_cb_undo(
1587 	Widget    w,
1588 	XtPointer client_data,
1589 	XtPointer call_data
1590 	)
1591 {
1592     short * fptr, * uptr;
1593     int     count;
1594 
1595     ENTRY("r_any_cb_undo");
1596 
1597     fptr = gRA.fdata; uptr = gRA.undo_data;
1598     if ( !fptr || !uptr )
1599     {
1600         fprintf(stderr,"** undo without pointers: (%p,%p)\n",fptr,uptr);
1601         EXRETURN;
1602     }
1603 
1604     for ( count = 0; count < gRA.nvox; count++ )
1605 	*fptr++ = *uptr++;
1606 
1607     THD_load_statistics( gRA.func ) ;
1608     PLUTO_dset_redisplay( gRA.func ) ;
1609 
1610     EXRETURN;
1611 }
1612 
1613 
1614 /*----------------------------------------------------------------------
1615 **
1616 **  Callback to interpolate between user drawn lines.
1617 **
1618 **----------------------------------------------------------------------
1619  */
1620 static void
r_INT_cb_fill(Widget w,XtPointer client_data,XtPointer call_data)1621 r_INT_cb_fill(
1622 	Widget w,
1623 	XtPointer client_data,
1624 	XtPointer call_data
1625 	)
1626 {
1627     r_ipt_t    sourcep, destp;
1628     interp_s * I = (interp_s *)client_data;
1629     points_t * lb, * sb;
1630     double     index_ratio, tot_dist;
1631     double     dx, dy, dz, dcurr;
1632     double     fx, fy, fz;
1633     short    * fnptr = gRA.fdata, * sptr;
1634     short    * fptr, * uptr;
1635     int      * ip1;
1636     int        count, dest_index, coord;
1637     int        nx = gRA.nx, ny = gRA.ny, nz = gRA.nz;
1638 
1639     ENTRY("r_INT_cb_fill");
1640 
1641     if ( ! gRA.fdata )
1642     {
1643 	fprintf( stderr, "%c", 7 );
1644 	EXRETURN;
1645     }
1646 
1647     if ( ! I )
1648     {
1649 	rERROR( "Error : entered r_INT_cb_fill() without client_data." );
1650 	EXRETURN;
1651     }
1652 
1653     /* check that neither border is empty */
1654     if ( I->A.used <= 0 || I->B.used <= 0 )
1655     {
1656 	fprintf( stderr, "%c", 7 );
1657 	rWARNING( "Missing bounding curve for interpolation." );
1658 	EXRETURN;
1659     }
1660 
1661     /* first store to undo_data */
1662     fptr = gRA.fdata; uptr = gRA.undo_data;
1663     for ( count = 0; count < gRA.nvox; count++ )
1664 	*uptr++ = *fptr++;
1665 
1666     if ( I->A.used >= I->B.used )
1667     {
1668 	lb = &I->A;
1669 	sb = &I->B;
1670 	index_ratio = I->B.used / (double)I->A.used;
1671     }
1672     else
1673     {
1674 	lb = &I->B;
1675 	sb = &I->A;
1676 	index_ratio = I->A.used / (double)I->B.used;
1677     }
1678 
1679     for ( count = 0, ip1 = lb->points; count < lb->used; count++, ip1++ )
1680     {
1681 	sourcep    = r_index2pt( *ip1, nx, ny, nz );
1682 	dest_index = count * index_ratio + 0.0001;
1683 	destp      = r_index2pt( sb->points[dest_index], nx, ny, nz );
1684 
1685 	tot_dist   = r_p_distance( sourcep, destp );
1686 	dx         = R_DIST_STEP * ( destp.x - sourcep.x ) / tot_dist;
1687 	dy         = R_DIST_STEP * ( destp.y - sourcep.y ) / tot_dist;
1688 	dz         = R_DIST_STEP * ( destp.z - sourcep.z ) / tot_dist;
1689 	fx         = sourcep.x + dx;
1690 	fy         = sourcep.y + dy;
1691 	fz         = sourcep.z + dz;
1692 
1693 	for ( dcurr = R_DIST_STEP; dcurr < tot_dist; dcurr += R_DIST_STEP )
1694 	{
1695 	    coord = (int)fx + nx * ( (int)fy + ny  * (int)fz );
1696 
1697 	    sptr = fnptr + coord;
1698 
1699 	    /* if ( ! *sptr )   -  draw through anything? */
1700 	    *sptr = I->fill_val;
1701 
1702 	    fx += dx;
1703 	    fy += dy;
1704 	    fz += dz;
1705 	}
1706     }
1707 
1708     THD_load_statistics( gRA.func );
1709     PLUTO_dset_redisplay( gRA.func );
1710     dset_changed = 1;
1711 
1712     EXRETURN;
1713 }
1714 
1715 
1716 /*----------------------------------------------------------------------
1717 **
1718 **  Compute the distance between two points.
1719 **
1720 **----------------------------------------------------------------------
1721  */
1722 static double
r_p_distance(r_ipt_t p1,r_ipt_t p2)1723 r_p_distance( r_ipt_t p1, r_ipt_t p2 )
1724 {
1725     return( sqrt( ( p1.x - p2.x ) * ( p1.x - p2.x ) +
1726 		  ( p1.y - p2.y ) * ( p1.y - p2.y ) +
1727 		  ( p1.z - p2.z ) * ( p1.z - p2.z ) )
1728 	  );
1729 }
1730 
1731 
1732 /*----------------------------------------------------------------------
1733 **
1734 **  Convert the coordinate to a point.
1735 **
1736 **  We assume coord is of the form coord = X + nx * ( Y + ny * Z ).
1737 **  The resulting point is P = { X, Y, Z }.
1738 **
1739 **----------------------------------------------------------------------
1740  */
1741 static r_ipt_t
r_index2pt(int coord,int nx,int ny,int nz)1742 r_index2pt( int coord, int nx, int ny, int nz )
1743 {
1744     r_ipt_t p = { 0, 0, 0 };
1745     int     tmp;
1746 
1747     ENTRY("r_index2pt");
1748 
1749     if ( coord < 0 )
1750     {
1751 	sprintf( gRmessage, "Coordinate %d is out of range!\n", coord );
1752 	rERROR( gRmessage );
1753 	RETURN(p);
1754     }
1755 
1756     p.x = coord % nx;
1757     tmp = coord / nx;
1758     p.y = tmp   % ny;
1759     p.z = tmp   / ny;
1760 
1761     if ( p.z >= nz )
1762     {
1763 	sprintf( gRmessage, "Coordinate %d is out of range!\n"
1764 		 "Associated point is (%d,%d,%d).\n",
1765 		 coord, p.x, p.y, p.z );
1766 	rERROR( gRmessage );
1767     }
1768 
1769     RETURN(p);
1770 }
1771 
1772 
1773 /*----------------------------------------------------------------------
1774 **
1775 **  Initialize the point connection structure.
1776 **
1777 **  structure :
1778 **
1779 ** typedef struct
1780 ** {
1781 **     r_ipt_t   source;
1782 **     r_ipt_t   dest;
1783 **
1784 **     int       cur_pt;        * flag denoting first or second point *
1785 ** } r_pt_conn_s;
1786 **
1787 **----------------------------------------------------------------------
1788  */
1789 static int
r_init_pt_conn_s(r_pt_conn_s * P)1790 r_init_pt_conn_s( r_pt_conn_s * P )
1791 {
1792     r_ipt_t p = { 0, 0, 0 };
1793 
1794     P->cur_pt = 1;              /* may be either 1 or 2            */
1795     P->source = p;              /* just to initialize to SOMEthing */
1796     P->dest   = p;
1797 
1798     P->plist.points = NULL;     /* init border structure */
1799     P->plist.used   = 0;
1800     P->plist.M      = 0;
1801 
1802     return 1;
1803 }
1804 
1805 
1806 /*----------------------------------------------------------------------
1807 **
1808 **  Initialize the Algorithm values.
1809 **
1810 **  structure :
1811 **
1812 **  typedef struct
1813 **  {
1814 **      Widget    main;         * main application widget *
1815 **      Widget    mainRC;       * main rowcolumn widget   *
1816 **
1817 **      int       fill_val;
1818 **      int       afni_undo;
1819 **
1820 **      points_t  A, B;         * two point structures for interpolation *
1821 **  } interp_s;
1822 **
1823 **----------------------------------------------------------------------
1824  */
1825 static int
r_init_interp_vals(interp_s * I)1826 r_init_interp_vals( interp_s * I )
1827 {
1828     ENTRY("r_init_interp_vals");
1829 
1830     I->fill_val  = 2;
1831     I->afni_undo = 0;
1832 
1833     I->A.used   = 0;
1834     I->A.M      = 100;
1835     I->A.points = (int *)malloc( I->A.M * sizeof( int ) );
1836 
1837     if ( I->A.points == NULL )
1838     {
1839 	fprintf( stderr, "\nError: riiv10\n"
1840 		 "Failed to allocate %d ints for interpolation struct.\n\n",
1841 		 I->A.M );
1842 	RETURN(0);
1843     }
1844 
1845     I->B.used   = 0;
1846     I->B.M      = 100;
1847     I->B.points = (int *)malloc( I->B.M * sizeof( int ) );
1848 
1849     if ( I->B.points == NULL )
1850     {
1851 	fprintf( stderr, "\nError: riiv20\n"
1852 		 "Failed to allocate %d ints for interpolation struct.\n\n",
1853 		 I->B.M );
1854 	RETURN(0);
1855     }
1856 
1857     RETURN(1);
1858 }
1859 
1860 
1861 /*----------------------------------------------------------------------
1862 **
1863 **  Create main filling widgets.
1864 **
1865 **----------------------------------------------------------------------
1866  */
1867 static Widget
r_wt_mk_main_frame(r_X_s * X,Widget parent)1868 r_wt_mk_main_frame( r_X_s * X, Widget parent )
1869 {
1870     Widget    frame, rc, label;
1871     XmString  xstring;
1872     Arg       al[ 20 ];
1873     int       ac;
1874 
1875     ENTRY("r_wt_mk_main_frame");
1876 
1877     ac = 0;
1878     XtSetArg( al[ ac ], XmNmarginHeight, 3 );  ac++;
1879     frame = XmCreateFrame( parent, "frame", al, ac );
1880 
1881     ac = 0;
1882     XtSetArg( al[ ac ], XmNlabelString,
1883 		XmStringCreate( "White Matter Fill :", X->charset ) );  ac++;
1884     XtSetArg( al[ ac ], XmNchildType, XmFRAME_TITLE_CHILD );  ac++;
1885     XtSetArg( al[ ac ], XmNchildVerticalAlignment,
1886 		XmALIGNMENT_BASELINE_BOTTOM);  ac++;
1887     label = XmCreateLabel( frame, "label", al, ac );
1888     XtManageChild( label );
1889 
1890     ac = 0;
1891     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
1892 
1893     ( void )r_wt_mk_range_fr      ( X, rc );
1894     ( void )r_wt_mk_fillval_fr    ( X, rc );
1895     ( void )r_wt_mk_nbrs_fr       ( X, rc );
1896     ( void )r_wt_mk_diag_conn_fr  ( X, rc );
1897     ( void )r_wt_mk_strong_bord_fr( X, rc );
1898 
1899     r_wt_mk_fill_buttons( X, rc );
1900 
1901 
1902     XtManageChild( rc );
1903     XtManageChild( frame );
1904 
1905     RETURN(frame);
1906 }
1907 
1908 
1909 /*----------------------------------------------------------------------
1910 **
1911 **  Create the main gray matter function frame.
1912 **
1913 **----------------------------------------------------------------------
1914  */
1915 static Widget
r_gr_mk_main_frame(r_X_s * X,Widget parent)1916 r_gr_mk_main_frame( r_X_s * X, Widget parent )
1917 {
1918     Widget    frame, rc, label;
1919     XmString  xstring;
1920     Arg       al[ 20 ];
1921     int       ac;
1922 
1923     ENTRY("r_gr_mk_main_frame");
1924 
1925     ac = 0;
1926     XtSetArg( al[ ac ], XmNmarginHeight, 3 );  ac++;
1927     frame = XmCreateFrame( parent, "frame", al, ac );
1928 
1929     ac = 0;
1930     XtSetArg( al[ ac ], XmNlabelString,
1931 		XmStringCreate( "Gray Matter Fill :", X->charset ) );  ac++;
1932     XtSetArg( al[ ac ], XmNchildType, XmFRAME_TITLE_CHILD );  ac++;
1933     XtSetArg( al[ ac ], XmNchildVerticalAlignment,
1934 		XmALIGNMENT_BASELINE_BOTTOM);  ac++;
1935     label = XmCreateLabel( frame, "label", al, ac );
1936     XtManageChild( label );
1937 
1938     ac = 0;
1939     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
1940 
1941 
1942     ( void )r_gr_mk_range_fr    ( X, rc );
1943     ( void )r_gr_mk_fillval_fr  ( X, rc );
1944     ( void )r_gr_mk_max_dist_w  ( X, rc );
1945     ( void )r_gr_mk_fill_buttons( X, rc );
1946 
1947 
1948 
1949     XtManageChild( rc );
1950     XtManageChild( frame );
1951 
1952     RETURN(frame);
1953 }
1954 
1955 
1956 /*----------------------------------------------------------------------
1957 **
1958 **  Initialize the Algorithm values.
1959 **
1960 **----------------------------------------------------------------------
1961  */
1962 static int
r_init_Alg_values(r_alg_s * A)1963 r_init_Alg_values( r_alg_s * A )
1964 {
1965     ENTRY("r_init_Alg_values");
1966 
1967     A->point_value       = 75;
1968     A->point_coord       = -1;  /* means user has not yet selected a point */
1969     A->adjust_point      = 0;
1970 
1971     strcpy( A->save_as_name, "default" );
1972 
1973     A->wt_fill_val       = 5;
1974     A->wt_range_min      = r_wtgr_calc_min_frm_val( A->point_value );
1975     A->wt_range_max      = r_wtgr_calc_max_frm_val( A->point_value );
1976     A->wt_diag_connect   = 0;   /* any connection */
1977 
1978     A->gr_fill_val       = 10;
1979     A->gr_range_min      = r_wtgr_calc_min_frm_val( 42 );
1980     A->gr_range_max      = r_wtgr_calc_max_frm_val( 42 );
1981     A->gr_max_dist       = 4;
1982 
1983     A->anat              = plint->im3d->anat_now;
1984 
1985     fprintf(stderr,"r_init_Alg_values(): A->anat = %p\n",A->anat);
1986     if ( A->anat )
1987     {
1988         if ( ! DSET_LOADED(A->anat) )
1989         {
1990             DSET_load( A->anat );
1991             fprintf(stderr,"-d loading anat...\n");
1992         }
1993 	A->adata = (short *)DSET_BRICK_ARRAY( A->anat, 0 );
1994 	/*fprintf(stderr,"Set A->adata to %p\n",A->adata);*/
1995     }
1996 
1997     /*
1998     ** Create boundary memory and check for malloc success.
1999     */
2000     A->Bold.used   = 0;
2001     A->Bold.M      = 1000;
2002     A->Bold.points = (int *)malloc( A->Bold.M * sizeof( int ) );
2003 
2004     if ( A->Bold.points == NULL )
2005     {
2006 	fprintf( stderr, "Error: riAv10\n"
2007 		 "Failed to allocate %d ints for boundary.\n", A->Bold.M );
2008 	RETURN(0);
2009     }
2010 
2011     A->Bnew.used   = 0;
2012     A->Bnew.M      = 1000;
2013     A->Bnew.points = (int *)malloc( A->Bnew.M * sizeof( int ) );
2014 
2015     if ( A->Bnew.points == NULL )
2016     {
2017 	fprintf( stderr, "\nError: riAv20\n"
2018 		 "Failed to allocate %d ints for boundary.\n\n", A->Bnew.M );
2019 	RETURN(0);
2020     }
2021 
2022     A->border.used   = 0;
2023     A->border.M      = 1000;
2024     A->border.points = (int *)malloc( A->border.M * sizeof( int ) );
2025 
2026     if ( A->border.points == NULL )
2027     {
2028 	fprintf( stderr, "\nError: riAv30\n"
2029 		 "Failed to allocate %d ints for boundary.\n\n",
2030 		 A->border.M );
2031 	RETURN(0);
2032     }
2033 
2034     /* we will initialize this after we know we have data */
2035     A->neighbors = NULL;                /* - will be nvox */
2036     A->undo_data = NULL;                /* - will be nvox */
2037 
2038     A->min_nbrs  = 0;
2039     A->strong_borders = 1;
2040 
2041 
2042     RETURN(1);
2043 }
2044 
2045 
2046 /*----------------------------------------------------------------------
2047 **
2048 **  Initialize the afni values.
2049 **
2050 **----------------------------------------------------------------------
2051  */
2052 static void
r_init_afni_vars(r_alg_s * A,THD_3dim_dataset * func)2053 r_init_afni_vars( r_alg_s * A, THD_3dim_dataset * func )
2054 {
2055     ENTRY("r_init_afni_vars");
2056 
2057     A->anat              = plint->im3d->anat_now;
2058 
2059     if ( func )
2060     {
2061 	if ( DSET_BRICK_TYPE( func, 0 ) != MRI_short )
2062 	{
2063 	    ( void )MCW_popup_message( gRX.main,
2064 			"Serious error.\n"
2065 			"\n"
2066 			"Functional data is not of\n"
2067 			"type short.  Please choose\n"
2068 			"another dataset.\n",
2069 			MCW_USER_KILL | MCW_TIMER_KILL );
2070 	    EXRETURN;
2071 	}
2072 
2073 	A->func   = func;
2074 
2075 	A->factor = DSET_BRICK_FACTOR( A->func, 0 );
2076 	A->factor = ( A->factor == 0.0 ) ? 1.0 : A->factor;
2077 	A->fdata  = (short *)DSET_BRICK_ARRAY( A->func, 0 );
2078 
2079 	A->nx     = DSET_NX( A->func );
2080 	A->ny     = DSET_NY( A->func );
2081 	A->nz     = DSET_NZ( A->func );
2082 	A->nxy    = A->nx * A->ny;
2083 	A->nvox   = A->nx * A->ny * A->nz;
2084 
2085 	if ( A->neighbors == NULL )
2086 	{
2087 	    A->neighbors = malloc( A->nvox * sizeof( short ) );
2088 	    if ( A->neighbors == NULL )
2089 	    {
2090 		fprintf( stderr, "\nError: riav10\n"
2091 		"Failed to allocate %d ints for neighbors.\n\n", A->nvox );
2092 	    }
2093 
2094 	    A->undo_data = calloc( A->nvox, sizeof( short ) );
2095 	    if ( A->undo_data == NULL )
2096 	    {
2097 		fprintf( stderr, "\nError: riav20\n"
2098 		"Failed to allocate %d ints for undo_data.\n\n", A->nvox );
2099 	    }
2100 	}
2101     }
2102     else
2103 	( void )MCW_popup_message( gRX.main,
2104 		    "Serious error.\n"
2105 		    "\n"
2106 		    "Missing functional dataset.\n"
2107 		    "Please choose another dataset.\n",
2108 		    MCW_USER_KILL | MCW_TIMER_KILL );
2109 
2110     fprintf(stderr,"r_init_afni_vars(): A->anat = %p\n",A->anat);
2111     if ( A->anat )
2112     {
2113 	if ( DSET_BRICK_TYPE( A->anat, 0 ) != MRI_short )
2114 	{
2115 	    ( void )MCW_popup_message( gRX.main,
2116 			"Serious error.\n"
2117 			"\n"
2118 			"Anatomical data is not of\n"
2119 			"type short.  Please choose\n"
2120 			"another dataset.\n",
2121 			MCW_USER_KILL | MCW_TIMER_KILL );
2122 	    EXRETURN;
2123 	}
2124 
2125         if ( ! DSET_LOADED(A->anat) )
2126         {
2127             fprintf(stderr,"-d loading anat...\n");
2128             DSET_load( A->anat );
2129         }
2130 
2131 	A->adata = (short *)DSET_BRICK_ARRAY( A->anat, 0 );
2132 	/*fprintf(stderr,"Set A->adata to %p\n",A->adata);*/
2133     }
2134     else
2135 	( void )MCW_popup_message( gRX.main,
2136 		    "Serious error.\n"
2137 		    "\n"
2138 		    "Missing anatomical dataset.\n"
2139 		    "Please choose another dataset.\n",
2140 		    MCW_USER_KILL | MCW_TIMER_KILL );
2141 
2142     EXRETURN;
2143 }
2144 
2145 
2146 /*----------------------------------------------------------------------
2147 **
2148 **  Callback to output statistics on selected matter.
2149 **
2150 **----------------------------------------------------------------------
2151  */
2152 static void
r_any_cb_fill_stats(Widget w,XtPointer client_data,XtPointer call_data)2153 r_any_cb_fill_stats(
2154 	Widget w,
2155 	XtPointer client_data,
2156 	XtPointer call_data
2157 	)
2158 {
2159     short * fptr = gRA.fdata;
2160     short * aptr = gRA.adata;
2161     int     fillval = *(int *)client_data;
2162     int     count, min = 30000, max = -30000, size = 0;
2163 
2164     ENTRY("r_any_cb_fill_stats");
2165 
2166     if ( ! gRA.fdata )
2167     {
2168 	fputc( 7, stderr );      /* hard-code a beep */
2169 	EXRETURN;
2170     }
2171 
2172     for ( count = 0; count < gRA.nvox; count++ )
2173     {
2174 	if ( *fptr == fillval )
2175 	{
2176 	    if ( *aptr > max )
2177 		max = *aptr;
2178 	    if ( *aptr < min )
2179 		min = *aptr;
2180 	    size++;
2181 	}
2182 
2183 	aptr++;
2184 	fptr++;
2185     }
2186 
2187     printf( "------------------------------------------------------------\n" );
2188 
2189     if ( size > 0 )
2190     {
2191 	printf( "fill region min  = %d\n", min  );
2192 	printf( "fill region max  = %d\n", max  );
2193 	printf( "fill region size = %d\n", size );
2194 	printf( "\n" );
2195 
2196 	r_histogram( &gRA, min, max, fillval );
2197     }
2198     else
2199 	rWARNING( "Fill region is empty." );
2200 
2201     printf( "------------------------------------------------------------\n" );
2202 
2203     EXRETURN;
2204 }
2205 
2206 
2207 /*----------------------------------------------------------------------
2208 **
2209 **  Make a histogram from the selected data.
2210 **
2211 **----------------------------------------------------------------------
2212  */
2213 static void
r_histogram(r_alg_s * A,int min,int max,int check_val)2214 r_histogram( r_alg_s * A, int min, int max, int check_val )
2215 {
2216     int   * hist;
2217 
2218     short * fptr = gRA.fdata;
2219     short * aptr = gRA.adata;
2220     int     count, size = max - min + 1, total = 0;
2221 
2222     ENTRY("r_histogram");
2223 
2224     if ( ( hist = (int *)malloc( size * sizeof( int ) ) ) == NULL )
2225     {
2226 	sprintf( gRmessage, "Error: pr_rh_10\n"
2227 		 "Failed alloca for %d ints.", size );
2228 	rWARNING( gRmessage );
2229 	EXRETURN;
2230     }
2231 
2232     for ( count = 0; count < size; count++ )
2233 	hist[count] = 0;
2234 
2235     for ( count = 0; count < A->nvox; count++ )
2236     {
2237 	if ( *fptr == check_val )
2238 	{
2239 	    hist[*aptr - min]++;
2240 	    total++;
2241 	}
2242 
2243 	aptr++;
2244 	fptr++;
2245     }
2246 
2247     printf( "  value   \t   nvox    \t    %%\n" );
2248     printf( "--------- \t --------- \t --------- \n" );
2249 
2250     for ( count = 0; count < size; count++)
2251 	printf( " %6d   \t %7d   \t  %7.3f\n",
2252 		min + count, hist[ count ], 100.0 * hist[ count ] / total );
2253     free(hist);
2254     EXRETURN;
2255 }
2256 
2257 
2258 /*----------------------------------------------------------------------
2259 **
2260 **  Callback to toggle the strong borders flag.
2261 **
2262 **----------------------------------------------------------------------
2263 */
2264 static void
r_wt_cb_SB_toggle(Widget w,XtPointer client_data,XtPointer call_data)2265 r_wt_cb_SB_toggle(
2266 	Widget w,
2267 	XtPointer client_data,
2268 	XtPointer call_data
2269 	)
2270 {
2271     RwcBoolean set;
2272     Arg     al[ 10 ];
2273     int     ac;
2274 
2275     ac = 0;
2276     XtSetArg( al[ ac ], XmNset, &set );  ac++;
2277     XtGetValues( w, al, ac );
2278 
2279     if ( set )
2280 	gRA.strong_borders = 1;
2281     else
2282 	gRA.strong_borders = 0;
2283 
2284     return;
2285 }
2286 
2287 
2288 /*----------------------------------------------------------------------
2289 **
2290 **  Given an integer value, return the suggested minimum search value.
2291 **
2292 **----------------------------------------------------------------------
2293  */
2294 static int
r_wtgr_calc_min_frm_val(int value)2295 r_wtgr_calc_min_frm_val( int value )
2296 {
2297     return( (int)(0.94 * value - 5) );
2298 }
2299 
2300 
2301 /*----------------------------------------------------------------------
2302 **
2303 **  Given an integer value, return the suggested minimum search value.
2304 **
2305 **----------------------------------------------------------------------
2306  */
2307 static int
r_wtgr_calc_max_frm_val(int value)2308 r_wtgr_calc_max_frm_val( int value )
2309 {
2310     return( (int)(1.06 * value + 5) );
2311 }
2312 
2313 
2314 /*----------------------------------------------------------------------
2315 **
2316 **  Hide the main white/gray matter finder.
2317 **
2318 **----------------------------------------------------------------------
2319  */
2320 static void
r_wtgr_cb_hide(void)2321 r_wtgr_cb_hide( void )
2322 {
2323     XtUnmapWidget( gRX.wtgr_main );
2324 }
2325 
2326 
2327 /*----------------------------------------------------------------------
2328 **
2329 **  Callback to suggest range limits for white AND gray matter search.
2330 **
2331 **  Values will be set in the wt_range_min_w and wt_range_max_w widgets.
2332 **
2333 **----------------------------------------------------------------------
2334  */
2335 static void
r_wtgr_cb_suggest_limits(Widget w,XtPointer client_data,XtPointer call_data)2336 r_wtgr_cb_suggest_limits(
2337 	Widget w,
2338 	XtPointer client_data,
2339 	XtPointer call_data
2340 	)
2341 {
2342     Widget minw, maxw;
2343     char * cdptr = (char *)client_data;
2344     char   string[ 10 ] = "";
2345     Arg    al[ 10 ];
2346     int    ac, min, max;
2347 
2348     ENTRY("r_wtgr_cb_suggest_limits");
2349 
2350     if ( ! cdptr )
2351     {
2352 	fprintf( stderr,
2353 		 "Entered r_wtgr_cb_suggest_limits() without a type.\n" );
2354 	EXRETURN;
2355     }
2356 
2357     min = r_wtgr_calc_min_frm_val( gRA.point_value );
2358     max = r_wtgr_calc_max_frm_val( gRA.point_value );
2359 
2360     if ( ! strcmp( cdptr, "white" ) )
2361     {
2362 	gRA.wt_range_min = min;         /* apply the new values */
2363 	gRA.wt_range_max = max;
2364 
2365 	minw = gRX.wt_range_min_w;      /* set the widgets to be updated */
2366 	maxw = gRX.wt_range_max_w;
2367     }
2368     else        /* then gray */
2369     {
2370 	max = min - 1;                  /* assume the gray starts below white */
2371 	min = 0.60 * min;
2372 
2373 	gRA.gr_range_max = max;
2374 	gRA.gr_range_min = min;
2375 
2376 	minw = gRX.gr_range_min_w;
2377 	maxw = gRX.gr_range_max_w;
2378     }
2379 
2380     /* set the values into the range widgets */
2381 
2382     sprintf( string, "%d", min );
2383 
2384     ac = 0;
2385     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
2386     XtSetValues( minw, al, ac );
2387 
2388 
2389     sprintf( string, "%d", max );
2390 
2391     ac = 0;
2392     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
2393     XtSetValues( maxw, al, ac );
2394 
2395     EXRETURN;
2396 }
2397 
2398 
2399 /*----------------------------------------------------------------------
2400 **
2401 **  Create boundary (gray matter) buttons.
2402 **
2403 **----------------------------------------------------------------------
2404  */
2405 static Widget
r_gr_mk_fill_buttons(r_X_s * X,Widget parent)2406 r_gr_mk_fill_buttons( r_X_s * X, Widget parent )
2407 {
2408     int      ac;
2409     Arg      al[ 10 ];
2410     Widget   form, frame, button;
2411     XmString xstr;
2412 
2413     ENTRY("r_gr_mk_fill_buttons");
2414 
2415     /* create frame to hold form and buttons */
2416     ac = 0;
2417     frame = XmCreateFrame( parent, "frame", al, ac );
2418 
2419     /* create form to hold push buttons */
2420     ac = 0;
2421     XtSetArg( al[ac], XmNhorizontalSpacing, R_BUTTON_SPACE );  ac++;
2422     form = XmCreateForm( frame, "form", al, ac );
2423 
2424 
2425     /* region fill button */
2426     ac = 0;
2427     xstr = XmStringCreateLtoR( "FILL", gRX.charset );
2428     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
2429     button = XmCreatePushButton( form, "fill", al, ac );
2430     XtManageChild( button );
2431     XtAddCallback( button, XmNactivateCallback,
2432 		   ( XtCallbackProc )r_gr_cb_fill, NULL );
2433     XtSetSensitive( button, True );
2434     XmStringFree( xstr );
2435     MCW_register_hint( button , "fill the gray matter region" );
2436 
2437     /* unfill button */
2438     ac = 0;
2439     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
2440     XtSetArg( al[ac], XmNleftWidget, button );  ac++;
2441     xstr = XmStringCreateLtoR( "unfill", gRX.charset );
2442     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
2443     button = XmCreatePushButton( form, "unfill", al, ac );
2444     XtManageChild( button );
2445     XtAddCallback( button, XmNactivateCallback,
2446 		   ( XtCallbackProc )r_any_cb_unfill, &gRA.gr_fill_val );
2447     XtSetSensitive( button, True );
2448     XmStringFree( xstr );
2449     MCW_register_hint( button , "unfill the \"fill value\" region" );
2450 
2451 
2452     /* suggest range button */
2453     ac = 0;
2454     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
2455     XtSetArg( al[ac], XmNleftWidget, button );  ac++;
2456     xstr = XmStringCreateLtoR( "suggest range", gRX.charset );
2457     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
2458     button = XmCreatePushButton( form, "suggest_range", al, ac );
2459     XtManageChild( button );
2460     XtAddCallback( button, XmNactivateCallback,
2461 		   ( XtCallbackProc )r_wtgr_cb_suggest_limits, "gray" );
2462     XtSetSensitive( button, True );
2463     XmStringFree( xstr );
2464     MCW_register_hint( button , "suggest a range for gray matter values" );
2465 
2466 
2467     /* stats button */
2468     ac = 0;
2469     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
2470     XtSetArg( al[ac], XmNleftWidget, button );  ac++;
2471     xstr = XmStringCreateLtoR( "stats", gRX.charset );
2472     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
2473     button = XmCreatePushButton( form, "stats", al, ac );
2474     XtManageChild( button );
2475     XtAddCallback( button, XmNactivateCallback,
2476 		   ( XtCallbackProc )r_any_cb_fill_stats, &gRA.gr_fill_val );
2477     XtSetSensitive( button, True );
2478     XmStringFree( xstr );
2479     MCW_register_hint( button , "get stats for this \"fill value\"" );
2480 
2481 
2482     /* hide window button */
2483     ac = 0;
2484     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
2485     XtSetArg( al[ac], XmNleftWidget, button );  ac++;
2486     xstr = XmStringCreateLtoR( "hide", gRX.charset );
2487     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
2488     button = XmCreatePushButton( form, "hide", al, ac );
2489     XtManageChild( button );
2490     XtAddCallback( button, XmNactivateCallback,
2491 		   ( XtCallbackProc )r_any_cb_hide, "wtgr" );
2492     XtSetSensitive( button, True );
2493     XmStringFree( xstr );
2494     MCW_register_hint( button , "temporarily close this window" );
2495 
2496 
2497     XtManageChild( form );
2498     XtManageChild( frame );
2499 
2500     RETURN( frame );
2501 }
2502 
2503 
2504 /*----------------------------------------------------------------------
2505 **
2506 **  Create FILL type buttons for the white matter search.
2507 **
2508 **----------------------------------------------------------------------
2509  */
2510 static void
r_wt_mk_fill_buttons(r_X_s * X,Widget parent)2511 r_wt_mk_fill_buttons( r_X_s * X, Widget parent )
2512 {
2513     int      ac;
2514     Arg      al[ 10 ];
2515     Widget   form, frame, button1, button2, button3;
2516     XmString xstr;
2517 
2518     ENTRY("r_wt_mk_fill_buttons");
2519 
2520     /* create frame to hold form and buttons */
2521     ac = 0;
2522     frame = XmCreateFrame( parent, "frame", al, ac );
2523 
2524     /* create form to hold push buttons */
2525     ac = 0;
2526     XtSetArg( al[ac], XmNhorizontalSpacing, R_BUTTON_SPACE );  ac++;
2527     form = XmCreateForm( frame, "form", al, ac );
2528 
2529 
2530     /* region fill button */
2531     ac = 0;
2532     xstr = XmStringCreateLtoR( "FILL", gRX.charset );
2533     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
2534     button1 = XmCreatePushButton( form, "fill", al, ac );
2535     XtManageChild( button1 );
2536     XtAddCallback( button1, XmNactivateCallback,
2537 		   ( XtCallbackProc )r_wt_cb_fill, NULL );
2538     XtSetSensitive( button1, True );
2539     XmStringFree( xstr );
2540     MCW_register_hint( button1 , "fill the white matter region" );
2541 
2542 
2543     /* MORE region fill button */
2544     ac = 0;
2545     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
2546     XtSetArg( al[ac], XmNleftWidget, button1 );  ac++;
2547     xstr = XmStringCreateLtoR( "MORE", gRX.charset );
2548     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
2549     button3 = XmCreatePushButton( form, "more", al, ac );
2550     XtManageChild( button3 );
2551     XtAddCallback( button3, XmNactivateCallback,
2552 		   ( XtCallbackProc )r_wt_cb_fill, "0" );
2553     XtSetSensitive( button3, True );
2554     XmStringFree( xstr );
2555     MCW_register_hint( button3 , "fill more white matter (no unfill)" );
2556 
2557 
2558     /* unfill button */
2559     ac = 0;
2560     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
2561     XtSetArg( al[ac], XmNleftWidget, button3 );  ac++;
2562     xstr = XmStringCreateLtoR( "unfill", gRX.charset );
2563     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
2564     button2 = XmCreatePushButton( form, "unfill", al, ac );
2565     XtManageChild( button2 );
2566     XtAddCallback( button2, XmNactivateCallback,
2567 		   ( XtCallbackProc )r_any_cb_unfill, &gRA.wt_fill_val );
2568     XtSetSensitive( button2, True );
2569     XmStringFree( xstr );
2570     MCW_register_hint( button2 , "unfill all matter for the \"fill value\"" );
2571 
2572 
2573     /* suggest range button */
2574     ac = 0;
2575     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
2576     XtSetArg( al[ac], XmNleftWidget, button2 );  ac++;
2577     xstr = XmStringCreateLtoR( "suggest range", gRX.charset );
2578     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
2579     button1 = XmCreatePushButton( form, "suggest_range", al, ac );
2580     XtManageChild( button1 );
2581     XtAddCallback( button1, XmNactivateCallback,
2582 		   ( XtCallbackProc )r_wtgr_cb_suggest_limits, "white" );
2583     XtSetSensitive( button1, True );
2584     XmStringFree( xstr );
2585     MCW_register_hint( button1 , "suggest a white matter range" );
2586 
2587 
2588     /* stats button */
2589     ac = 0;
2590     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
2591     XtSetArg( al[ac], XmNleftWidget, button1 );  ac++;
2592     xstr = XmStringCreateLtoR( "stats", gRX.charset );
2593     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
2594     button2 = XmCreatePushButton( form, "stats", al, ac );
2595     XtManageChild( button2 );
2596     XtAddCallback( button2, XmNactivateCallback,
2597 		   ( XtCallbackProc )r_any_cb_fill_stats, &gRA.wt_fill_val );
2598     XtSetSensitive( button2, True );
2599     XmStringFree( xstr );
2600     MCW_register_hint( button2 , "get stats for this \"fill value\"" );
2601 
2602 
2603     XtManageChild( form );
2604     XtManageChild( frame );
2605 
2606     EXRETURN;
2607 }
2608 
2609 
2610 /*----------------------------------------------------------------------
2611 **
2612 **  Create the diagonal connections frame.
2613 **
2614 **  This will be a radio button widget for the user flag.
2615 **
2616 **----------------------------------------------------------------------
2617  */
2618 static Widget
r_wt_mk_diag_conn_fr(r_X_s * X,Widget parent)2619 r_wt_mk_diag_conn_fr( r_X_s * X, Widget parent )
2620 {
2621     Widget   junk, rc, frame;
2622     XmString xstr;
2623     Arg      al[ 10 ];
2624     int      ac;
2625     char     string[ 15 ];
2626 
2627     ENTRY("r_wt_mk_diag_conn_fr");
2628 
2629     ac = 0;
2630     frame = XmCreateFrame( parent, "frame", al, ac );
2631 
2632     ac = 0;
2633     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
2634     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
2635     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
2636 
2637     ac = 0;
2638     xstr = XmStringCreateLtoR( "connection constraint (0-2) : ", gRX.charset );
2639     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
2640     junk = XmCreateLabel( rc, "label", al, ac );
2641     XtManageChild( junk );
2642     XmStringFree( xstr );
2643 
2644 
2645     sprintf( string, "%d", gRA.wt_diag_connect );
2646 
2647     ac = 0;
2648     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
2649     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
2650     X->wt_diag_conn_w = XmCreateText( rc, "text", al, ac );
2651     XtManageChild( X->wt_diag_conn_w );
2652     XtAddCallback( X->wt_diag_conn_w, XmNactivateCallback,
2653 	    ( XtCallbackProc )r_wt_cb_set_diag_conn, NULL );
2654     XtAddCallback( X->wt_diag_conn_w, XmNlosingFocusCallback,
2655 	    ( XtCallbackProc )r_wt_cb_set_diag_conn, NULL );
2656 
2657 
2658     XtManageChild( rc );
2659     XtManageChild( frame );
2660 
2661     RETURN( frame );
2662 }
2663 
2664 /*----------------------------------------------------------------------
2665 **
2666 **  Create the strong borders frame.
2667 **
2668 **  This will be a radio button widget.
2669 **
2670 **----------------------------------------------------------------------
2671  */
2672 static Widget
r_wt_mk_strong_bord_fr(r_X_s * X,Widget parent)2673 r_wt_mk_strong_bord_fr( r_X_s * X, Widget parent )
2674 {
2675     Widget   junk, frame;
2676     XmString xstr;
2677     Arg      al[ 10 ];
2678     int      ac;
2679     char     string[ 15 ];
2680 
2681     ENTRY("r_wt_mk_strong_bord_fr");
2682 
2683     ac = 0;
2684     frame = XmCreateFrame( parent, "frame", al, ac );
2685 
2686     ac = 0;
2687     XtSetArg( al[ ac ], XmNset,     True );  ac++;
2688     XtSetArg( al[ ac ], XmNwidth, 1 ); ac++;
2689     XtSetArg( al[ ac ], XmNspacing, 1 ); ac++;
2690     XtSetArg( al[ ac ], XmNmarginLeft, 1 ); ac++;
2691     xstr = XmStringCreateLtoR( "strong borders                ", gRX.charset );
2692     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
2693     junk = XmCreateToggleButton( frame, "toggle", al, ac );
2694     XtManageChild( junk );
2695     XtAddCallback( junk, XmNvalueChangedCallback, r_wt_cb_SB_toggle, NULL);
2696     XmStringFree( xstr );
2697 
2698     XtManageChild( frame );
2699 
2700     RETURN( frame );
2701 }
2702 
2703 
2704 /*----------------------------------------------------------------------
2705 **
2706 **  Create the min_nbrs (minimum neighbors) frame.
2707 **
2708 **----------------------------------------------------------------------
2709  */
2710 static Widget
r_wt_mk_nbrs_fr(r_X_s * X,Widget parent)2711 r_wt_mk_nbrs_fr( r_X_s * X, Widget parent )
2712 {
2713     Widget   junk, rc, frame;
2714     XmString xstr;
2715     Arg      al[ 10 ];
2716     int      ac;
2717     char     string[ 15 ];
2718 
2719     ENTRY("r_wt_mk_nbrs_fr");
2720 
2721     ac = 0;
2722     frame = XmCreateFrame( parent, "frame", al, ac );
2723 
2724     ac = 0;
2725     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
2726     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
2727     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
2728 
2729     ac = 0;
2730     xstr = XmStringCreateLtoR( "neighbors  constraint (0-6) : ", gRX.charset );
2731     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
2732     junk = XmCreateLabel( rc, "label", al, ac );
2733     XtManageChild( junk );
2734     XmStringFree( xstr );
2735 
2736 
2737     sprintf( string, "%d", gRA.min_nbrs );
2738 
2739     ac = 0;
2740     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
2741     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
2742     X->wt_min_nbrs_w = XmCreateText( rc, "text", al, ac );
2743     XtManageChild( X->wt_min_nbrs_w );
2744     XtAddCallback( X->wt_min_nbrs_w, XmNactivateCallback,
2745 	    ( XtCallbackProc )r_wt_cb_set_min_nbrs, NULL );
2746     XtAddCallback( X->wt_min_nbrs_w, XmNlosingFocusCallback,
2747 	    ( XtCallbackProc )r_wt_cb_set_min_nbrs, NULL );
2748 
2749 
2750     XtManageChild( rc );
2751     XtManageChild( frame );
2752 
2753     RETURN( frame );
2754 }
2755 
2756 
2757 /*----------------------------------------------------------------------
2758 **
2759 **  Create the frame to handle max distance in the gray search.
2760 **
2761 **----------------------------------------------------------------------
2762  */
2763 static Widget
r_gr_mk_max_dist_w(r_X_s * X,Widget parent)2764 r_gr_mk_max_dist_w( r_X_s * X, Widget parent )
2765 {
2766     Widget   junk, rc, frame;
2767     XmString xstr;
2768     Arg      al[ 10 ];
2769     int      ac;
2770     char     string[ 15 ];
2771 
2772     ENTRY("r_gr_mk_max_dist_w");
2773 
2774     ac = 0;
2775     frame = XmCreateFrame( parent, "frame", al, ac );
2776 
2777     ac = 0;
2778     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
2779     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
2780     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
2781 
2782     ac = 0;
2783     xstr = XmStringCreateLtoR( "max distance : ", gRX.charset );
2784     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
2785     junk = XmCreateLabel( rc, "label", al, ac );
2786     XtManageChild( junk );
2787     XmStringFree( xstr );
2788 
2789 
2790     sprintf( string, "%d", gRA.gr_max_dist );
2791 
2792     ac = 0;
2793     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
2794     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
2795     junk = XmCreateText( rc, "text", al, ac );
2796     XtManageChild( junk );
2797     XtAddCallback( junk, XmNactivateCallback,
2798 	    ( XtCallbackProc )r_gr_cb_set_max_dist, NULL );
2799     XtAddCallback( junk, XmNlosingFocusCallback,
2800 	    ( XtCallbackProc )r_gr_cb_set_max_dist, NULL );
2801 
2802 
2803     XtManageChild( rc );
2804     XtManageChild( frame );
2805 
2806     RETURN( frame );
2807 }
2808 
2809 
2810 /*----------------------------------------------------------------------
2811 **
2812 **  Create the "fill value" widgets.
2813 **
2814 **----------------------------------------------------------------------
2815  */
2816 static Widget
r_wt_mk_fillval_fr(r_X_s * X,Widget parent)2817 r_wt_mk_fillval_fr( r_X_s * X, Widget parent )
2818 {
2819     Widget   junk, rc, frame;
2820     XmString xstr;
2821     Arg      al[ 10 ];
2822     int      ac;
2823     char     string[ 15 ];
2824 
2825 
2826     ac = 0;
2827     frame = XmCreateFrame( parent, "frame", al, ac );
2828 
2829     ac = 0;
2830     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
2831     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
2832     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
2833 
2834     ac = 0;
2835     xstr = XmStringCreateLtoR( "fill value   : ", gRX.charset );
2836     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
2837     junk = XmCreateLabel( rc, "label", al, ac );
2838     XtManageChild( junk );
2839     XmStringFree( xstr );
2840 
2841 
2842     sprintf( string, "%d", gRA.wt_fill_val );
2843 
2844     ac = 0;
2845     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
2846     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
2847     X->wt_fill_val_w = XmCreateText( rc, "text", al, ac );
2848     XtManageChild( X->wt_fill_val_w );
2849     XtAddCallback( X->wt_fill_val_w, XmNactivateCallback,
2850 	    ( XtCallbackProc )r_wt_cb_set_fill_val, NULL );
2851     XtAddCallback( X->wt_fill_val_w, XmNlosingFocusCallback,
2852 	    ( XtCallbackProc )r_wt_cb_set_fill_val, NULL );
2853 
2854 
2855     XtManageChild( rc );
2856     XtManageChild( frame );
2857 
2858     return( frame );
2859 }
2860 
2861 
2862 /*----------------------------------------------------------------------
2863 **
2864 **  Create the "fill value" widget for the gray matter search.
2865 **
2866 **----------------------------------------------------------------------
2867  */
2868 static Widget
r_gr_mk_fillval_fr(r_X_s * X,Widget parent)2869 r_gr_mk_fillval_fr( r_X_s * X, Widget parent )
2870 {
2871     Widget   junk, rc, frame;
2872     XmString xstr;
2873     Arg      al[ 10 ];
2874     int      ac;
2875     char     string[ 15 ];
2876 
2877 
2878     ac = 0;
2879     frame = XmCreateFrame( parent, "frame", al, ac );
2880 
2881     ac = 0;
2882     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
2883     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
2884     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
2885 
2886     ac = 0;
2887     xstr = XmStringCreateLtoR( "fill value   : ", gRX.charset );
2888     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
2889     junk = XmCreateLabel( rc, "label", al, ac );
2890     XtManageChild( junk );
2891     XmStringFree( xstr );
2892 
2893 
2894     sprintf( string, "%d", gRA.gr_fill_val );
2895 
2896     ac = 0;
2897     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
2898     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
2899     X->gr_fill_val_w = XmCreateText( rc, "text", al, ac );
2900     XtManageChild( X->gr_fill_val_w );
2901     XtAddCallback( X->gr_fill_val_w, XmNactivateCallback,
2902 	    ( XtCallbackProc )r_gr_set_fill_val, NULL );
2903     XtAddCallback( X->gr_fill_val_w, XmNlosingFocusCallback,
2904 	    ( XtCallbackProc )r_gr_set_fill_val, NULL );
2905 
2906 
2907     XtManageChild( rc );
2908     XtManageChild( frame );
2909 
2910     return( frame );
2911 }
2912 
2913 
2914 /*----------------------------------------------------------------------
2915 **
2916 **  Create the gray matter range frame.
2917 **
2918 **----------------------------------------------------------------------
2919  */
2920 static Widget
r_gr_mk_range_fr(r_X_s * X,Widget parent)2921 r_gr_mk_range_fr( r_X_s * X, Widget parent )
2922 {
2923     Widget   junk, rc, frame;
2924     XmString xstr;
2925     Arg      al[ 10 ];
2926     int      ac;
2927     char     string[ 15 ];
2928 
2929 
2930     ac = 0;
2931     frame = XmCreateFrame( parent, "frame", al, ac );
2932 
2933     ac = 0;                     /* to hold labels and text */
2934     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
2935     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
2936     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
2937 
2938     ac = 0;
2939     xstr = XmStringCreateLtoR( "search range : ", gRX.charset );
2940     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
2941     junk = XmCreateLabel( rc, "label", al, ac );
2942     XtManageChild( junk );
2943     XmStringFree( xstr );
2944 
2945 
2946     sprintf( string, "%d", gRA.gr_range_min );  /* init value */
2947 
2948     ac = 0;
2949     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
2950     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
2951     X->gr_range_min_w = XmCreateText( rc, "text", al, ac );
2952     XtManageChild( X->gr_range_min_w );
2953     XtAddCallback( X->gr_range_min_w, XmNactivateCallback,
2954 	    ( XtCallbackProc )r_gr_cb_set_range, "from" );
2955     XtAddCallback( X->gr_range_min_w, XmNlosingFocusCallback,
2956 	    ( XtCallbackProc )r_gr_cb_set_range, "from" );
2957 
2958     ac = 0;
2959     xstr = XmStringCreateLtoR( " to ", gRX.charset );
2960     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
2961     junk = XmCreateLabel( rc, "label", al, ac );
2962     XtManageChild( junk );
2963     XmStringFree( xstr );
2964 
2965 
2966     sprintf( string, "%d", gRA.gr_range_max );
2967 
2968     ac = 0;
2969     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
2970     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
2971     X->gr_range_max_w = XmCreateText( rc, "text", al, ac );
2972     XtManageChild( X->gr_range_max_w );
2973     XtAddCallback( X->gr_range_max_w, XmNactivateCallback,
2974 	    ( XtCallbackProc )r_gr_cb_set_range, "to" );
2975     XtAddCallback( X->gr_range_max_w, XmNlosingFocusCallback,
2976 	    ( XtCallbackProc )r_gr_cb_set_range, "to" );
2977 
2978     XtManageChild( rc );
2979     XtManageChild( frame );
2980 
2981     return( frame );
2982 }
2983 
2984 
2985 /*----------------------------------------------------------------------
2986 **
2987 **  Create the range widgets.
2988 **
2989 **----------------------------------------------------------------------
2990  */
2991 static Widget
r_wt_mk_range_fr(r_X_s * X,Widget parent)2992 r_wt_mk_range_fr( r_X_s * X, Widget parent )
2993 {
2994     Widget   junk, rc, frame;
2995     XmString xstr;
2996     Arg      al[ 10 ];
2997     int      ac;
2998     char     string[ 15 ];
2999 
3000 
3001     ac = 0;
3002     frame = XmCreateFrame( parent, "frame", al, ac );
3003 
3004     ac = 0;                     /* to hold labels and text */
3005     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
3006     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
3007     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
3008 
3009     ac = 0;
3010     xstr = XmStringCreateLtoR( "search range : ", gRX.charset );
3011     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
3012     junk = XmCreateLabel( rc, "label", al, ac );
3013     XtManageChild( junk );
3014     XmStringFree( xstr );
3015 
3016 
3017     sprintf( string, "%d", gRA.wt_range_min );  /* init value */
3018 
3019     ac = 0;
3020     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
3021     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
3022     X->wt_range_min_w = XmCreateText( rc, "text", al, ac );
3023     XtManageChild( X->wt_range_min_w );
3024     XtAddCallback( X->wt_range_min_w, XmNactivateCallback,
3025 	    ( XtCallbackProc )r_wt_cb_set_range, "from" );
3026     XtAddCallback( X->wt_range_min_w, XmNlosingFocusCallback,
3027 	    ( XtCallbackProc )r_wt_cb_set_range, "from" );
3028 
3029     ac = 0;
3030     xstr = XmStringCreateLtoR( " to ", gRX.charset );
3031     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
3032     junk = XmCreateLabel( rc, "label", al, ac );
3033     XtManageChild( junk );
3034     XmStringFree( xstr );
3035 
3036 
3037     sprintf( string, "%d", gRA.wt_range_max );
3038 
3039     ac = 0;
3040     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
3041     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
3042     X->wt_range_max_w = XmCreateText( rc, "text", al, ac );
3043     XtManageChild( X->wt_range_max_w );
3044     XtAddCallback( X->wt_range_max_w, XmNactivateCallback,
3045 	    ( XtCallbackProc )r_wt_cb_set_range, "to" );
3046     XtAddCallback( X->wt_range_max_w, XmNlosingFocusCallback,
3047 	    ( XtCallbackProc )r_wt_cb_set_range, "to" );
3048 
3049     XtManageChild( rc );
3050     XtManageChild( frame );
3051 
3052     return( frame );
3053 }
3054 
3055 
3056 /*----------------------------------------------------------------------
3057 **
3058 **  Clear the filled region for the white matter search.
3059 **
3060 **----------------------------------------------------------------------
3061  */
3062 static void
r_any_cb_unfill(Widget w,XtPointer client_data,XtPointer call_data)3063 r_any_cb_unfill(
3064 	Widget w,
3065 	XtPointer client_data,
3066 	XtPointer call_data
3067 	)
3068 {
3069     short * fptr, * uptr;
3070     int     count;
3071     int     unfill_val = *((int *)client_data);
3072 
3073     ENTRY("r_any_cb_unfill");
3074 
3075     if ( ! gRA.fdata )
3076 	EXRETURN;
3077 
3078     /* first store to undo_data */
3079     fptr = gRA.fdata; uptr = gRA.undo_data;
3080     for ( count = 0; count < gRA.nvox; count++ )
3081 	*uptr++ = *fptr++;
3082 
3083     for ( count = 0, fptr = gRA.fdata; count < gRA.nvox; count++, fptr++ )
3084 	if ( *fptr == unfill_val )
3085 	    *fptr = 0;
3086 
3087     THD_load_statistics( gRA.func ) ;
3088     PLUTO_dset_redisplay( gRA.func ) ;
3089 
3090     EXRETURN;
3091 }
3092 
3093 
3094 /*----------------------------------------------------------------------
3095 **
3096 **  Make the check to see if a user boundary neighbor exists.
3097 **
3098 **  Okay neighbors values are zero and testval.
3099 **
3100 **----------------------------------------------------------------------
3101  */
3102 static int
r_wt_bad_ngbr_exists(r_alg_s * A,int current,int testval)3103 r_wt_bad_ngbr_exists( r_alg_s * A, int current, int testval )
3104 {
3105     int     last;
3106     int     nx, nxy;
3107     short   val;
3108     short * data;
3109 
3110     ENTRY("r_wt_bad_ngbr_exists");
3111 
3112     data = A->fdata + current;
3113     nx   = A->nx;
3114     nxy  = A->nxy;
3115     last = A->nvox - nxy;
3116 
3117     if ( ( current < nxy ) || ( current >= last ) )
3118 	RETURN(1);
3119 
3120     val = data[ -1 ];
3121     if ( val && ( val != testval ) && ( val != R_BOUND_VAL )  )
3122 	RETURN(1);
3123 
3124     val = data[ 1 ];
3125     if ( val && ( val != testval ) && ( val != R_BOUND_VAL )  )
3126 	RETURN(1);
3127 
3128     val = data[ -nx ];
3129     if ( val && ( val != testval ) && ( val != R_BOUND_VAL )  )
3130 	RETURN(1);
3131 
3132     val = data[ nx ];
3133     if ( val && ( val != testval ) && ( val != R_BOUND_VAL )  )
3134 	RETURN(1);
3135 
3136     val = data[ -nxy ];
3137     if ( val && ( val != testval ) && ( val != R_BOUND_VAL )  )
3138 	RETURN(1);
3139 
3140     val = data[ nxy ];
3141     if ( val && ( val != testval ) && ( val != R_BOUND_VAL )  )
3142 	RETURN(1);
3143 
3144     RETURN(0);
3145 }
3146 
3147 
3148 /*----------------------------------------------------------------------
3149 **
3150 **  Make the check for adding a point to the border.
3151 **
3152 **----------------------------------------------------------------------
3153  */
3154 static int
r_wt_check_insert(r_alg_s * A,int current)3155 r_wt_check_insert( r_alg_s * A, int current )
3156 {
3157     short * aptr = A->adata;
3158     short * fptr = A->fdata;
3159     short * nptr = A->neighbors;
3160     short * fvp  = fptr + current;      /* pointer to function value */
3161 
3162     int value, added = 0;
3163 
3164     ENTRY("r_wt_check_insert");
3165 
3166     value = aptr[ current ];
3167 
3168     /* if new and in range, we will set as a result voxel */
3169     if ( *fvp == 0 )
3170     {
3171 	if ( ( value >= A->wt_range_min ) &&
3172 	     ( value <= A->wt_range_max ) )
3173 	{
3174 	    /* if it also has enough neighbors */
3175 	    if ( nptr[ current ] >= A->min_nbrs )
3176 	    {
3177 		/* also check for neighbor in the user's boundary */
3178 		if ( ( ! A->strong_borders ) ||
3179 		     ! r_wt_bad_ngbr_exists( A, current, A->wt_fill_val ) )
3180 		{
3181 		    if ( ! r_add_to_boundary( &A->Bnew, current ) )
3182 			RETURN(-1);
3183 		    else
3184 			added = 1;
3185 		}
3186 	    }
3187 
3188 	    /* either way, set point as wt_fill_val */
3189 	    *fvp = A->wt_fill_val;
3190 	}
3191 	else    /* add to the 3d boundary */
3192 	{
3193 	    *fvp = R_BOUND_VAL; /* mark as in boundary, clear later */
3194 
3195 	    if ( ! r_add_to_boundary( &A->border, current ) )
3196 		RETURN(-1);
3197 	}
3198     }
3199 
3200     RETURN(added);
3201 }
3202 
3203 
3204 /*----------------------------------------------------------------------
3205 **
3206 **  Callback to fill the local region for a mask.
3207 **
3208 **----------------------------------------------------------------------
3209  */
3210 static void
r_wt_cb_fill(Widget w,XtPointer client_data,XtPointer call_data)3211 r_wt_cb_fill(
3212 	Widget w,
3213 	XtPointer client_data,
3214 	XtPointer call_data
3215 	)
3216 {
3217     short  * nptr, * fnptr, * flptr, * aptr, * uptr;
3218     int      count, value, current;
3219     int      nxy = gRA.nxy, nx = gRA.nx;
3220     char   * cp = (char *)client_data;
3221     points_t B;
3222 
3223     ENTRY("r_wt_cb_fill");
3224 
3225     /* check that we are ready to fill anything */
3226     if ( ( gRA.point_coord == -1 ) || ( ! gRA.fdata ) )
3227     {
3228 	fputc( 7, stderr );      /* hard-code a beep */
3229 	EXRETURN;
3230     }
3231 
3232     if ( !gRA.Bold.points || !gRA.Bnew.points ||
3233 	   !gRA.neighbors || !gRA.undo_data)
3234     {
3235 	fprintf( stderr, "Error: rcfr10\n"
3236 		 "Memory failure, addresses are %p, %p, %p and %p.\n",
3237 		 gRA.Bold.points, gRA.Bnew.points,
3238 		 gRA.neighbors, gRA.undo_data );
3239 	EXRETURN;
3240     }
3241 
3242     /* first store to undo_data */
3243     fnptr = gRA.fdata; uptr = gRA.undo_data;
3244     for ( count = 0; count < gRA.nvox; count++ )
3245 	*uptr++ = *fnptr++;
3246 
3247     /* give the user an idea of what is happening */
3248     rWARNING( "filling white matter" );
3249 
3250     if ( ( cp == NULL ) || ( *cp != '0' ) )
3251     {
3252 	for ( count = 0, fnptr = gRA.fdata; count < gRA.nvox; count++, fnptr++ )            if ( *fnptr == gRA.wt_fill_val )
3253 		*fnptr = 0;
3254     }
3255 
3256     r_wt_set_neighbors( &gRA );
3257 
3258     /* set borders to nothing */
3259     gRA.Bold.used    = 0;
3260     gRA.Bnew.used    = 0;
3261     gRA.border.used  = 0;
3262 
3263     if ( r_wt_check_insert( &gRA, gRA.point_coord ) != 1 )
3264 	EXRETURN;
3265 
3266     while ( gRA.Bnew.used > 0 )  /* while boundary exists */
3267     {
3268 	B             = gRA.Bold; /* swap memory and reset Bnew.used to zero */
3269 	gRA.Bold      = gRA.Bnew; /*    - this simply preserves the memory  */
3270 	gRA.Bnew      = B;
3271 	gRA.Bnew.used = 0;
3272 	fputs( ".", stderr );
3273 
3274 	for ( count = 0; count < gRA.Bold.used; count++ )
3275 	{
3276 	    current = gRA.Bold.points[count];
3277 
3278 	    /* 6 'face sharing' points */
3279 	    r_wt_check_insert( &gRA, current - 1 );
3280 	    r_wt_check_insert( &gRA, current + 1 );
3281 	    r_wt_check_insert( &gRA, current - nx );
3282 	    r_wt_check_insert( &gRA, current + nx );
3283 	    r_wt_check_insert( &gRA, current - nxy );
3284 	    r_wt_check_insert( &gRA, current + nxy );
3285 
3286 	    /* 12 'edge sharing' points */
3287 	    if ( gRA.wt_diag_connect < 2 )
3288 	    {
3289 		r_wt_check_insert( &gRA, current + nx - 1 );
3290 		r_wt_check_insert( &gRA, current + nx + 1 );
3291 		r_wt_check_insert( &gRA, current - nx - 1 );
3292 		r_wt_check_insert( &gRA, current - nx + 1 );
3293 		r_wt_check_insert( &gRA, current + nxy - 1 );
3294 		r_wt_check_insert( &gRA, current + nxy + 1 );
3295 		r_wt_check_insert( &gRA, current - nxy - 1 );
3296 		r_wt_check_insert( &gRA, current - nxy + 1 );
3297 		r_wt_check_insert( &gRA, current + nxy - nx );
3298 		r_wt_check_insert( &gRA, current + nxy + nx );
3299 		r_wt_check_insert( &gRA, current - nxy - nx );
3300 		r_wt_check_insert( &gRA, current - nxy + nx );
3301 
3302 		/* 8 'corner sharing' points */
3303 		if ( gRA.wt_diag_connect == 0 )
3304 		{
3305 		    r_wt_check_insert( &gRA, current - nxy - nx - 1 );
3306 		    r_wt_check_insert( &gRA, current - nxy - nx + 1 );
3307 		    r_wt_check_insert( &gRA, current - nxy + nx - 1 );
3308 		    r_wt_check_insert( &gRA, current - nxy + nx + 1 );
3309 		    r_wt_check_insert( &gRA, current + nxy - nx - 1 );
3310 		    r_wt_check_insert( &gRA, current + nxy - nx + 1 );
3311 		    r_wt_check_insert( &gRA, current + nxy + nx - 1 );
3312 		    r_wt_check_insert( &gRA, current + nxy + nx + 1 );
3313 		}
3314 	    }
3315 	}
3316     }
3317 
3318     /* clear bound markings */
3319     for( count = 0, fnptr = gRA.fdata; count < gRA.nvox; count++, fnptr++ )
3320 	if ( *fnptr == R_BOUND_VAL )
3321 	    *fnptr = 0;
3322 
3323     /* recompute statistics, if the loaded value is big or small */
3324 
3325     THD_load_statistics( gRA.func ) ;
3326 
3327     /* now redisplay dataset, in case anyone is looking at it */
3328 
3329     PLUTO_dset_redisplay( gRA.func ) ;
3330     dset_changed = 1;
3331 
3332     fputs( "done\n\n", stderr );
3333     EXRETURN;
3334 }
3335 
3336 
3337 /*----------------------------------------------------------------------
3338 **
3339 **  Callback to fill the gray matter (or so we somewhat suppose).
3340 **
3341 **----------------------------------------------------------------------
3342  */
3343 static void
r_gr_cb_fill(Widget w,XtPointer client_data,XtPointer call_data)3344 r_gr_cb_fill(
3345 	Widget w,
3346 	XtPointer client_data,
3347 	XtPointer call_data
3348 	)
3349 {
3350     points_t B;
3351     short  * fnptr, * uptr;
3352     int    * iptr;
3353     int      count, dist, added, current;
3354     int      nx, nxy;
3355 
3356     ENTRY("r_gr_cb_fill");
3357 
3358     nx   = gRA.nx;
3359     nxy  = gRA.nxy;
3360 
3361 
3362     if ( ( gRA.point_coord == -1 ) || ( ! gRA.fdata ) )
3363     {
3364 	fputc( 7, stderr );      /* hard-code a beep */
3365 	EXRETURN;
3366     }
3367 
3368     if ( gRA.gr_max_dist <= 0 )
3369 	EXRETURN;
3370 
3371     if ( !gRA.Bold.points || !gRA.Bnew.points ||
3372 	   !gRA.neighbors || !gRA.undo_data)    {
3373 	fprintf( stderr, "Error: rcfg10\n"
3374 		 "Memory failure, addresses are %p, %p, %p and %p.\n",
3375 		 gRA.Bold.points, gRA.Bnew.points,
3376 		 gRA.neighbors, gRA.undo_data );
3377 	EXRETURN;
3378     }
3379 
3380     /* give the user an idea of what is happening */
3381     rWARNING( "filling gray matter" );
3382 
3383 
3384     /* first store to undo_data */
3385     fnptr = gRA.fdata; uptr = gRA.undo_data;
3386     for ( count = 0; count < gRA.nvox; count++ )
3387 	*uptr++ = *fnptr++;
3388 
3389     /* clear old memory */
3390     for ( count = 0, fnptr = gRA.fdata; count < gRA.nvox; count++, fnptr++ )
3391 	if ( *fnptr == gRA.gr_fill_val )
3392 	    *fnptr = 0;
3393 
3394     /* set old and new borders to nothing */
3395     gRA.Bold.used     = 0;
3396     gRA.Bnew.used     = 0;
3397 
3398     gRH.gr_edge.used = 0;               /* trash the old gray edge */
3399 
3400     iptr = gRA.border.points;
3401     for ( count = 0; count < gRA.border.used; count++ )
3402     {
3403 	if ( ( added = r_gr_check_insert( &gRA, &gRA.Bold, *iptr ) ) == -1 )
3404 	    EXRETURN;
3405 	iptr++;
3406     }
3407 
3408 
3409     dist = 1;
3410     fputc( '.', stdout );
3411     while ( ( gRA.Bold.used > 0 ) && ( dist < gRA.gr_max_dist ) )
3412     {
3413 	iptr = gRA.Bold.points;
3414 	for ( count = 0; count < gRA.Bold.used; count++ )
3415 	{
3416 	    current = *iptr;
3417 
3418 	    ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current - 1 );
3419 	    ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current + 1 );
3420 	    ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current - nx );
3421 	    ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current + nx );
3422 	    ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current - nxy );
3423 	    ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current + nxy );
3424 
3425 	    iptr++;
3426 	}
3427 
3428 	B             = gRA.Bold;
3429 	gRA.Bold      = gRA.Bnew;
3430 	gRA.Bnew      = B;
3431 	gRA.Bnew.used = 0;
3432 
3433 	dist++;
3434 	fputc( '.', stdout );
3435     }
3436 
3437     /* clear bound markings */
3438     for( count = 0, fnptr = gRA.fdata; count < gRA.nvox; count++, fnptr++ )
3439 	if ( *fnptr == R_BOUND_VAL )
3440 	    *fnptr = 0;
3441 
3442     fputs( "done\n\n", stdout );
3443 
3444     /* recompute statistics, if the loaded value is big or small */
3445 
3446     THD_load_statistics( gRA.func ) ;
3447 
3448     /* now redisplay dataset, in case anyone is looking at it */
3449 
3450     PLUTO_dset_redisplay( gRA.func ) ;
3451     dset_changed = 1;
3452     EXRETURN;
3453 }
3454 
3455 
3456 /*----------------------------------------------------------------------
3457 **
3458 **  Make the check for adding a point to the border.
3459 **
3460 **----------------------------------------------------------------------
3461  */
3462 static int
r_gr_check_insert(r_alg_s * A,points_t * B,int current)3463 r_gr_check_insert( r_alg_s * A, points_t * B, int current )
3464 {
3465     short    * aptr = A->adata;
3466     short    * fptr = A->fdata;
3467     short    * nptr = A->neighbors;
3468     short    * fvalp;
3469     int        value, added = 0;
3470 
3471     ENTRY("r_gr_check_insert");
3472 
3473     if ( nptr[ current ] == -1 )        /* do not accept edge points */
3474 	RETURN(0);
3475 
3476     fvalp = fptr + current;
3477     value = aptr[ current ];
3478 
3479     /* if new and in range, we will consider setting it as a result */
3480     if ( *fvalp == 0 )
3481     {
3482 	if ( ( value >= A->gr_range_min ) &&
3483 	     ( value <= A->gr_range_max ) )
3484 	{
3485 	    if ( ! r_add_to_boundary( B, current ) )
3486 		RETURN(-1);
3487 
3488 	    *fvalp = A->gr_fill_val;
3489 
3490 	    added = 1;
3491 	}
3492 	else    /* mark as in boundary, add to HOLE's search set */
3493 	{
3494 	    *fvalp = R_BOUND_VAL;
3495 	    if ( ! r_add_to_boundary( &gRH.gr_edge, current ) )
3496 		RETURN(-1);
3497 	}
3498     }
3499 
3500     RETURN(added);
3501 }
3502 
3503 
3504 /*----------------------------------------------------------------------
3505 **
3506 **  Add a point to the boundary.
3507 **
3508 **----------------------------------------------------------------------
3509  */
3510 static int
r_add_to_boundary(points_t * B,int index)3511 r_add_to_boundary( points_t * B, int index )
3512 {
3513     ENTRY("r_add_to_boundary");
3514 
3515     if ( !B )
3516     {
3517 	fprintf( stderr, "Error: atb10\n"
3518 		 "Unexpected error - missing memory for bound structure!\n" );
3519 	RETURN(0);
3520     }
3521     else if ( ! B->points )             /* we need initial memory */
3522     {
3523 	B->used = 0;
3524 	B->M    = 50;
3525 	B->points = (int *)malloc( B->M * sizeof( int ) );
3526 
3527 	if ( B->points == NULL )
3528 	{
3529 	    fprintf( stderr, "Error: atb15\n"
3530 		     "Failed to allocate %d ints for boundary.\n", B->M );
3531 	    RETURN(0);
3532 	}
3533     }
3534     else if ( B->used == B->M )         /* then we need more memory */
3535     {
3536 	B->M     *= 2;
3537 	B->points = (int *)realloc( B->points, B->M * sizeof( int ) );
3538 
3539 	if ( B->points == NULL )
3540 	{
3541 	    fprintf( stderr, "Error: atb20\n"
3542 		     "Failed to reallocate %d ints for boundary.\n", B->M );
3543 	    RETURN(0);
3544 	}
3545     }
3546 
3547     B->points[B->used] = index;
3548     B->used++;
3549 
3550     RETURN(1);
3551 }
3552 
3553 
3554 /*----------------------------------------------------------------------
3555 **
3556 **  Fill the neighbors-in-range array.
3557 **
3558 **  init values to zero
3559 **  for each inner value
3560 **      count the number of neighbors (max of 6 - no diagonals) in range
3561 **      ( skip all edges )
3562 **
3563 **----------------------------------------------------------------------
3564  */
3565 static void
r_wt_set_neighbors(r_alg_s * A)3566 r_wt_set_neighbors( r_alg_s * A )
3567 {
3568     short * aptr = A->adata;
3569     short * nptr = A->neighbors;
3570     int     cx, cy, cz;
3571     int     nxy = A->nxy, nx = A->nx;
3572 
3573     ENTRY("r_wt_set_neighbors");
3574 
3575 
3576     for ( cz = 0; cz < A->nz; cz++ )
3577 	for ( cy = 0; cy < A->ny; cy++ )
3578 	    for ( cx = 0; cx < A->nx; cx++ )
3579 	    {
3580 		*nptr = 0;
3581 
3582 		if ( ( cx == 0 ) || ( cx == A->nx - 1 ) ||
3583 		     ( cy == 0 ) || ( cy == A->ny - 1 ) ||
3584 		     ( cz == 0 ) || ( cz == A->nz - 1 )
3585 		   )
3586 		{
3587 		    aptr++;
3588 		    *nptr++ = -1;    /* no future consideration */
3589 		    continue;
3590 		}
3591 		else if ( *aptr > A->wt_range_max || *aptr < A->wt_range_min )
3592 		{
3593 		    aptr++;
3594 		    nptr++;
3595 		    continue;
3596 		}
3597 
3598 		if ( ( *(aptr-1) <= A->wt_range_max ) &&
3599 		     ( *(aptr-1) >= A->wt_range_min ) )
3600 		    (*nptr)++;
3601 
3602 		if ( ( *(aptr+1) <= A->wt_range_max ) &&
3603 		     ( *(aptr+1) >= A->wt_range_min ) )
3604 		    (*nptr)++;
3605 
3606 		if ( ( *(aptr-nx) <= A->wt_range_max ) &&
3607 		     ( *(aptr-nx) >= A->wt_range_min ) )
3608 		    (*nptr)++;
3609 
3610 		if ( ( *(aptr+nx) <= A->wt_range_max ) &&
3611 		     ( *(aptr+nx) >= A->wt_range_min ) )
3612 		    (*nptr)++;
3613 
3614 		if ( ( *(aptr-nxy) <= A->wt_range_max ) &&
3615 		     ( *(aptr-nxy) >= A->wt_range_min) )
3616 		    (*nptr)++;
3617 
3618 		if ( ( *(aptr+nxy) <= A->wt_range_max ) &&
3619 		     ( *(aptr+nxy) >= A->wt_range_min) )
3620 		    (*nptr)++;
3621 
3622 		aptr++;
3623 		nptr++;
3624 	    }
3625 
3626     EXRETURN;
3627 }
3628 
3629 
3630 /*----------------------------------------------------------------------
3631 **
3632 **  Callback to set the minimum neighbors in search (1 to 6).
3633 **
3634 **----------------------------------------------------------------------
3635  */
3636 static void
r_wt_cb_set_diag_conn(Widget w,XtPointer client_data,XtPointer call_data)3637 r_wt_cb_set_diag_conn(
3638 	Widget w,
3639 	XtPointer client_data,
3640 	XtPointer call_data
3641 	)
3642 {
3643     char * text;
3644     int    ival;
3645 
3646     ENTRY("r_wt_cb_set_diag_conn");
3647 
3648     text = XmTextGetString( w );
3649 
3650     if ( ! text || ! *text )    /* nothing typed */
3651     {
3652 	if ( text )
3653 	    XtFree( text );
3654 	EXRETURN;
3655     }
3656 
3657     /*
3658     **  Make sure a value has changed (to something acceptable)
3659     **  before applying.
3660     */
3661 
3662     ival = atoi( text );
3663     if ( ( ival < 0 ) || ( ival > 2 ) )
3664     {
3665 	sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 0, 2 );
3666 	rERROR( gRmessage );
3667 	EXRETURN;
3668     }
3669 
3670     if ( gRA.wt_diag_connect != ival )
3671 	gRA.wt_diag_connect = ival;
3672 
3673     XtFree( text );
3674     EXRETURN;
3675 }
3676 
3677 
3678 /*----------------------------------------------------------------------
3679 **
3680 **  Callback to set the minimum neighbors in search (1 to 6).
3681 **
3682 **----------------------------------------------------------------------
3683  */
3684 static void
r_wt_cb_set_min_nbrs(Widget w,XtPointer client_data,XtPointer call_data)3685 r_wt_cb_set_min_nbrs(
3686 	Widget w,
3687 	XtPointer client_data,
3688 	XtPointer call_data
3689 	)
3690 {
3691     char * text;
3692     int    ival;
3693 
3694     text = XmTextGetString( w );
3695 
3696     if ( ! text || ! *text )    /* nothing typed */
3697     {
3698 	if ( text )
3699 	    XtFree( text );
3700 	return;
3701     }
3702 
3703     /*
3704     **  Make sure a value has changed (to something acceptable)
3705     **  before applying.
3706     */
3707 
3708     ival = atoi( text );
3709     if ( ( ival < 0 ) || ( ival > 6 ) )
3710     {
3711 	sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 0, 6 );
3712 	rERROR( gRmessage );
3713 	return;
3714     }
3715 
3716     if ( gRA.min_nbrs != ival )
3717 	gRA.min_nbrs = ival;
3718 
3719 
3720     XtFree( text );
3721 }
3722 
3723 
3724 /*----------------------------------------------------------------------
3725 **
3726 **  Callback to set the maximum distance in gray search.
3727 **
3728 **----------------------------------------------------------------------
3729  */
3730 static void
r_gr_cb_set_max_dist(Widget w,XtPointer client_data,XtPointer call_data)3731 r_gr_cb_set_max_dist(
3732 	Widget w,
3733 	XtPointer client_data,
3734 	XtPointer call_data
3735 	)
3736 {
3737     char * text;
3738     int    ival;
3739 
3740     text = XmTextGetString( w );
3741 
3742     if ( ! text || ! *text )    /* nothing typed */
3743     {
3744 	if ( text )
3745 	    XtFree( text );
3746 	return;
3747     }
3748 
3749     /*
3750     **  Make sure a value has changed (to something acceptable)
3751     **  before applying.
3752     */
3753 
3754     ival = atoi( text );
3755     if ( ( ival < 1 ) || ( ival > 200 ) )
3756     {
3757 	sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 1, 200 );
3758 	rERROR( gRmessage );
3759 	return;
3760     }
3761 
3762     if ( gRA.gr_max_dist != ival )
3763 	gRA.gr_max_dist = ival;
3764 
3765 
3766     XtFree( text );
3767 }
3768 
3769 
3770 /*----------------------------------------------------------------------
3771 **
3772 **  Callback to set the maximum fill size for the holes app.
3773 **
3774 **----------------------------------------------------------------------
3775  */
3776 static void
r_HL_cb_set_maxsize(Widget w,XtPointer client_data,XtPointer call_data)3777 r_HL_cb_set_maxsize(
3778 	Widget w,
3779 	XtPointer client_data,
3780 	XtPointer call_data
3781 	)
3782 {
3783     char * text;
3784     int    ival;
3785 
3786     text = XmTextGetString( w );
3787 
3788     if ( ! text || ! *text )    /* nothing typed */
3789     {
3790 	if ( text )
3791 	    XtFree( text );
3792 	return;
3793     }
3794 
3795     /*
3796     **  Make sure a value has changed (to something acceptable)
3797     **  before applying.
3798     */
3799 
3800     ival = atoi( text );
3801     if ( ival < 1 )
3802     {
3803 	sprintf( gRmessage, "Value %d is not in range [%d,oo).", ival, 1 );
3804 	rERROR( gRmessage );
3805 	return;
3806     }
3807 
3808     if ( gRH.max_size != ival )
3809 	gRH.max_size = ival;
3810 
3811     XtFree( text );
3812 }
3813 
3814 
3815 /*----------------------------------------------------------------------
3816 **
3817 **  Callback to set the fill value for the holes app.
3818 **
3819 **----------------------------------------------------------------------
3820  */
3821 static void
r_HL_cb_set_fill_val(Widget w,XtPointer client_data,XtPointer call_data)3822 r_HL_cb_set_fill_val(
3823 	Widget w,
3824 	XtPointer client_data,
3825 	XtPointer call_data
3826 	)
3827 {
3828     char * text;
3829     int    ival;
3830 
3831     text = XmTextGetString( w );
3832 
3833     if ( ! text || ! *text )    /* nothing typed */
3834     {
3835 	if ( text )
3836 	    XtFree( text );
3837 	return;
3838     }
3839 
3840     /*
3841     **  Make sure a value has changed (to something acceptable)
3842     **  before applying.
3843     */
3844 
3845     ival = atoi( text );
3846     if ( ( ival < 0 ) || ( ival > 255 ) )
3847     {
3848 	sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 0, 255 );
3849 	rERROR( gRmessage );
3850 	return;
3851     }
3852     else if ( ival == 0 )
3853     {
3854 	rWARNING( "Using hole fill value of 0." );
3855     }
3856 
3857 
3858     if ( gRH.fill_val != ival )
3859 	gRH.fill_val = ival;
3860 
3861 
3862     XtFree( text );
3863 }
3864 
3865 
3866 /*----------------------------------------------------------------------
3867 **
3868 **  Callback to set the fill value.
3869 **
3870 **----------------------------------------------------------------------
3871  */
3872 static void
r_INT_cb_set_fill_val(Widget w,XtPointer client_data,XtPointer call_data)3873 r_INT_cb_set_fill_val(
3874 	Widget w,
3875 	XtPointer client_data,
3876 	XtPointer call_data
3877 	)
3878 {
3879     char * text;
3880     int    ival;
3881 
3882     text = XmTextGetString( w );
3883 
3884     if ( ! text || ! *text )    /* nothing typed */
3885     {
3886 	if ( text )
3887 	    XtFree( text );
3888 	return;
3889     }
3890 
3891     /*
3892     **  Make sure a value has changed (to something acceptable)
3893     **  before applying.
3894     */
3895 
3896     ival = atoi( text );
3897     if ( ( ival < 0 ) || ( ival > 255 ) )
3898     {
3899 	sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 0, 255 );
3900 	rERROR( gRmessage );
3901 	return;
3902     }
3903     else if ( ival == 0 )
3904     {
3905 	rWARNING( "Using interpolation fill value of 0." );
3906     }
3907 
3908     if ( gRI.fill_val != ival )
3909 	gRI.fill_val = ival;
3910 
3911 
3912     XtFree( text );
3913 }
3914 
3915 
3916 /*----------------------------------------------------------------------
3917 **
3918 **  Callback to set the fill value.
3919 **
3920 **----------------------------------------------------------------------
3921  */
3922 static void
r_wt_cb_set_fill_val(Widget w,XtPointer client_data,XtPointer call_data)3923 r_wt_cb_set_fill_val(
3924 	Widget w,
3925 	XtPointer client_data,
3926 	XtPointer call_data
3927 	)
3928 {
3929     char * text;
3930     int    ival;
3931 
3932     text = XmTextGetString( w );
3933 
3934     if ( ! text || ! *text )    /* nothing typed */
3935     {
3936 	if ( text )
3937 	    XtFree( text );
3938 	return;
3939     }
3940 
3941     /*
3942     **  Make sure a value has changed (to something acceptable)
3943     **  before applying.
3944     */
3945 
3946     ival = atoi( text );
3947     if ( ( ival < 0 ) || ( ival > 255 ) )
3948     {
3949 	sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 0, 255 );
3950 	rERROR( gRmessage );
3951 	return;
3952     }
3953     else if ( ival == 0 )
3954     {
3955 	rWARNING( "Warning : using white matter fill value of 0." );
3956     }
3957 
3958     if ( gRA.wt_fill_val != ival )
3959 	gRA.wt_fill_val = ival;
3960 
3961 
3962     XtFree( text );
3963 }
3964 
3965 
3966 /*----------------------------------------------------------------------
3967 **
3968 **  Callback to set the fill value.
3969 **
3970 **----------------------------------------------------------------------
3971  */
3972 static void
r_gr_set_fill_val(Widget w,XtPointer client_data,XtPointer call_data)3973 r_gr_set_fill_val(
3974 	Widget w,
3975 	XtPointer client_data,
3976 	XtPointer call_data
3977 	)
3978 {
3979     char * text;
3980     int    ival;
3981 
3982     text = XmTextGetString( w );
3983 
3984     if ( ! text || ! *text )    /* nothing typed */
3985     {
3986 	if ( text )
3987 	    XtFree( text );
3988 	return;
3989     }
3990 
3991     /*
3992     **  Make sure a value has changed (to something acceptable)
3993     **  before applying.
3994     */
3995 
3996     ival = atoi( text );
3997     if ( ( ival < 1 ) || ( ival > 255 ) )
3998     {
3999 	sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 1, 255 );
4000 	rERROR( gRmessage );
4001 	return;
4002     }
4003 
4004     if ( gRA.gr_fill_val != ival )
4005 	gRA.gr_fill_val = ival;
4006 
4007 
4008     XtFree( text );
4009 }
4010 
4011 
4012 /*----------------------------------------------------------------------
4013 **
4014 **  Callback to set the white search range.
4015 **
4016 **----------------------------------------------------------------------
4017  */
4018 static void
r_wt_cb_set_range(Widget w,XtPointer client_data,XtPointer call_data)4019 r_wt_cb_set_range(
4020 	Widget w,
4021 	XtPointer client_data,
4022 	XtPointer call_data
4023 	)
4024 {
4025     char * string = ( char * )client_data;
4026     char * text;
4027     int    ival;
4028 
4029     text = XmTextGetString( w );
4030 
4031     if ( ! text || ! *text )    /* nothing typed */
4032     {
4033 	if ( text )
4034 	    XtFree( text );
4035 	return;
4036     }
4037 
4038     if ( ! string )  /* strange error - complain and return */
4039     {
4040 	fprintf( stderr, "r_wt_cb_set_range error - string is NULL\n" );
4041 	return;
4042     }
4043     else if ( ! *string )
4044     {
4045 	fprintf( stderr, "r_wt_cb_set_range error - string is empty\n" );
4046 	return;
4047     }
4048     else if ( ! strcmp( string, "to" ) && ! strcmp( string, "from" ) )
4049     {
4050 	fprintf( stderr, "r_wt_cb_set_range error -\n"
4051 			 "'%s' should be 'to' or 'from'.\n", string );
4052 	return;
4053     }
4054 
4055     /*
4056     **  Make sure a value has changed (to something acceptable)
4057     **  before applying.  Use short range.
4058     */
4059 
4060     ival = atoi( text );
4061     if ( ( ival < -32768 ) || ( ival > 32767 ) )
4062     {
4063 	fprintf( stderr, "Value %d is not in range [%d,%d].\n",
4064 			 ival, -32768, 32767 );
4065 	return;
4066     }
4067 
4068     if ( ! strcmp( string, "from" ) )
4069     {
4070 	if ( gRA.wt_range_min != ival )
4071 	{
4072 	    gRA.wt_range_min = ival;
4073 
4074 	    if ( gRA.wt_range_min > gRA.wt_range_max )
4075 	    {
4076 		sprintf( gRmessage, "\nWarning!"
4077 		    "  Min value should be less than max value.\n"
4078 		    "Value are %d and %d, respectively.\n",
4079 			 gRA.wt_range_min, gRA.wt_range_max );
4080 		rERROR( gRmessage );
4081 	    }
4082 	}
4083     }
4084     else
4085     {
4086 	if ( gRA.wt_range_max != ival )
4087 	{
4088 	    gRA.wt_range_max = ival;
4089 
4090 	    if ( gRA.wt_range_min > gRA.wt_range_max )
4091 	    {
4092 		sprintf( gRmessage, "\nWarning!"
4093 			 "  Min value should be less than max value.\n"
4094 			 "Value are %d and %d, respectively.\n",
4095 			 gRA.wt_range_min, gRA.wt_range_max );
4096 		rERROR( gRmessage );
4097 	    }
4098 	}
4099     }
4100 
4101     XtFree( text );
4102 }
4103 
4104 
4105 /*----------------------------------------------------------------------
4106 **
4107 **  Callback to set the search range.
4108 **
4109 **----------------------------------------------------------------------
4110  */
4111 static void
r_gr_cb_set_range(Widget w,XtPointer client_data,XtPointer call_data)4112 r_gr_cb_set_range(
4113 	Widget w,
4114 	XtPointer client_data,
4115 	XtPointer call_data
4116 	)
4117 {
4118     char * string = ( char * )client_data;
4119     char * text;
4120     int    ival;
4121 
4122     text = XmTextGetString( w );
4123 
4124     if ( ! text || ! *text )    /* nothing typed */
4125     {
4126 	if ( text )
4127 	    XtFree( text );
4128 	return;
4129     }
4130 
4131     if ( ! string )  /* strange error - complain and return */
4132     {
4133 	fprintf( stderr, "r_gr_cb_set_range error - string is NULL\n" );
4134 	return;
4135     }
4136     else if ( ! *string )
4137     {
4138 	fprintf( stderr, "r_gr_cb_set_range error - string is empty\n" );
4139 	return;
4140     }
4141     else if ( ! strcmp( string, "to" ) && ! strcmp( string, "from" ) )
4142     {
4143 	fprintf( stderr, "r_gr_cb_set_range error -\n"
4144 			 "'%s' should be 'to' or 'from'.\n", string );
4145 	return;
4146     }
4147 
4148     /*
4149     **  Make sure a value has changed (to something acceptable)
4150     **  before applying.  Use short range.
4151     */
4152 
4153     ival = atoi( text );
4154     if ( ( ival < -32768 ) || ( ival > 32767 ) )
4155     {
4156 	sprintf( gRmessage, "Value %d is not in range [%d,%d].",
4157 			 ival, -32768, 32767 );
4158 	rERROR( gRmessage );
4159 	return;
4160     }
4161 
4162     if ( ! strcmp( string, "from" ) )
4163     {
4164 	if ( gRA.gr_range_min != ival )
4165 	{
4166 	    gRA.gr_range_min = ival;
4167 
4168 	    if ( gRA.gr_range_min > gRA.gr_range_max )
4169 	    {
4170 		sprintf( gRmessage, "\nWarning!"
4171 		    "  Min value should be less than max value.\n"
4172 		    "Value are %d and %d, respectively.\n",
4173 			 gRA.gr_range_min, gRA.gr_range_max );
4174 		rERROR( gRmessage );
4175 	    }
4176 	}
4177     }
4178     else
4179     {
4180 	if ( gRA.gr_range_max != ival )
4181 	{
4182 	    gRA.gr_range_max = ival;
4183 
4184 	    if ( gRA.gr_range_min > gRA.gr_range_max )
4185 	    {
4186 		sprintf( gRmessage, "\nWarning!"
4187 			 "  Min value should be less than max value.\n"
4188 			 "Value are %d and %d, respectively.\n",
4189 			 gRA.gr_range_min, gRA.gr_range_max );
4190 		rERROR( gRmessage );
4191 	    }
4192 	}
4193     }
4194 
4195     XtFree( text );
4196 }
4197 
4198 
4199 /*----------------------------------------------------------------------
4200 **
4201 **  The user has selected an initial fill point.
4202 **
4203 **  Update the search range.  If the user wants the initial point
4204 **  aligned (moved to local extrema), do it.
4205 **
4206 **----------------------------------------------------------------------
4207  */
4208 static int
r_afni_set_fill_point(int * coord,r_alg_s * A)4209 r_afni_set_fill_point(
4210 	int       * coord,      /* offset of initial point (modifiable) */
4211 	r_alg_s * A             /* algorithm structure                  */
4212 	)
4213 {
4214     ENTRY("r_afni_set_fill_point");
4215 
4216     A->point_coord = *coord;
4217 
4218     /*printf("A = %p,  A->adata = %p,  A->point_coord = %d\n",
4219 	    A,A->adata,A->point_coord);
4220     fflush(stdout);*/
4221 
4222     if ( A->adata == NULL )
4223     {
4224 	/*fprintf(stderr,"Loading data...\n");
4225 	DSET_load(A->anat);*/
4226 	fputs("r_afni_set_fill_point(): Error: No anatomical data. ( A->adata = NULL )\n",stderr);
4227 	fputs("This may have been caused by selecting Talairach\n",stderr);
4228 	fputs("view before Switch Underlay or Switch Overlay.\n",stderr);
4229 	fputs("Try setting the environment variable AFNI_VIEW_ANAT_BRICK\n",stderr);
4230 	fputs("(The value is irrelevant) and run afni again.\n",stderr);
4231 	RETURN(-1);
4232     }
4233     A->point_value = A->adata[A->point_coord];   /* no anat factor? */
4234 
4235 
4236     printf( "coord = %d, adata = %d, fdata = %d, ndata = %d\n",
4237 	     *coord, A->adata[*coord], A->fdata[*coord], A->neighbors[*coord] );
4238 
4239     RETURN(0);
4240 }
4241 
4242 
4243 /*----------------------------------------------------------------------
4244 **
4245 **  Create a scale bar.
4246 **
4247 **----------------------------------------------------------------------
4248  */
4249 
4250 static Widget
r_mk_scale_bar(Widget parent,char * title,int min,int max,int value,int decimal_places,XtCallbackProc callback)4251 r_mk_scale_bar(
4252 	Widget          parent,
4253 	char          * title,
4254 	int             min,
4255 	int             max,
4256 	int             value,
4257 	int             decimal_places,
4258 	XtCallbackProc  callback
4259 	)
4260 {
4261     int         ac;
4262     Arg         al[ 20 ];
4263     XmString    Xtitle;
4264     Widget      scale;
4265 
4266     Xtitle = XmStringCreateLtoR( title, gRX.charset );
4267 
4268     ac = 0;
4269     XtSetArg( al[ac], XmNtitleString,      Xtitle );         ac++;
4270     XtSetArg( al[ac], XmNorientation,      XmHORIZONTAL );   ac++;
4271     XtSetArg( al[ac], XmNminimum,          min    );         ac++;
4272     XtSetArg( al[ac], XmNmaximum,          max    );         ac++;
4273     XtSetArg( al[ac], XmNvalue,            value  );         ac++;
4274     XtSetArg( al[ac], XmNshowValue,        True   );         ac++;
4275 
4276     if ( decimal_places > 0 )
4277     {
4278 	XtSetArg( al[ac], XmNdecimalPoints, decimal_places );
4279 	ac++;
4280     }
4281 
4282 
4283     scale = XmCreateScale( parent, "scale_bar", al, ac );
4284 
4285     XmStringFree( Xtitle );
4286 
4287     XtManageChild( scale );
4288 
4289     XtAddCallback( scale, XmNvalueChangedCallback, callback, NULL );
4290 
4291     return scale;
4292 }
4293 
4294 
4295 /*----------------------------------------------------------------------
4296 **
4297 **  Display the contents of the algorithm structure.
4298 **
4299 **---------------------------------------------------------------------
4300  */
4301 
4302 static void
r_main_show_alg_vals(r_alg_s * A)4303 r_main_show_alg_vals( r_alg_s * A )
4304 {
4305     printf( "-----------------------------------\n" );
4306 
4307     printf(
4308 	"gRA :\n"
4309 	"\n"
4310 	"point value             : %d\n"
4311 	"point coord             : %d\n"
4312 	"adjust point            : %d\n"
4313 	"'save as' name          : %s\n"
4314 	"\n"
4315 	"white fill value        : %d\n"
4316 	"white range min         : %d\n"
4317 	"white range max         : %d\n"
4318 	"white diag connect      : %d\n"
4319 	"\n"
4320 	"gray fill value         : %d\n"
4321 	"gray range min          : %d\n"
4322 	"gray range max          : %d\n"
4323 	"gray max distance       : %d\n"
4324 	"\n"
4325 	"anat dset        (addr) : %p\n"
4326 	"func dset        (addr) : %p\n"
4327 	"adata data       (addr) : %p\n"
4328 	"fdata data       (addr) : %p\n"
4329 	"factor                  : %f\n"
4330 	"nx                      : %d\n"
4331 	"ny                      : %d\n"
4332 	"nz                      : %d\n"
4333 	"nvox                    : %d\n"
4334 	"\n"
4335 	"old bound.M             : %d\n"
4336 	"old bound.used          : %d\n"
4337 	"old bound.points (addr) : %p\n"
4338 	"new bound.M             : %d\n"
4339 	"new bound.used          : %d\n"
4340 	"new bound.points (addr) : %p\n"
4341 	"border.M                : %d\n"
4342 	"border.used             : %d\n"
4343 	"border.points    (addr) : %p\n"
4344 	"\n"
4345 	"neighbors        (addr) : %p\n"
4346 	"undo data        (addr) : %p\n"
4347 	"\n"
4348 	"min neighbors           : %d\n"
4349 	"strong borders          : %d\n",
4350 	A->point_value, A->point_coord, A->adjust_point, A->save_as_name,
4351 	A->wt_fill_val, A->wt_range_min, A->wt_range_max,
4352 	    A->wt_diag_connect,
4353 	A->gr_fill_val, A->gr_range_min, A->gr_range_max, A->gr_max_dist,
4354 	A->anat, A->func,
4355 	A->adata, A->fdata,
4356 	A->factor, A->nx, A->ny, A->nz, A->nvox,
4357 	A->Bold.M, A->Bold.used, A->Bold.points,
4358 	A->Bnew.M, A->Bnew.used, A->Bnew.points,
4359 	A->border.M, A->border.used, A->border.points,
4360 	A->neighbors, A->undo_data,
4361 	A->min_nbrs, A->strong_borders
4362 	);
4363 
4364     printf( "-----------------------------------\n" );
4365 }
4366 
4367 
4368 /*----------------------------------------------------------------------
4369 **
4370 **  Display the contents of the interpolation structure.
4371 **
4372 **----------------------------------------------------------------------
4373  */
4374 static void
r_main_show_INT_vals(interp_s * I)4375 r_main_show_INT_vals( interp_s * I )
4376 {
4377     printf( "-----------------------------------\n" );
4378 
4379     printf(
4380 	"gRI :\n"
4381 	"\n"
4382 	"fill value       : %d\n"
4383 	"afni undo        : %d\n"
4384 	"\n"
4385 	"A.M              : %d\n"
4386 	"A.used           : %d\n"
4387 	"A.points  (addr) : %p\n"
4388 	"B.M              : %d\n"
4389 	"B.used           : %d\n"
4390 	"B.points  (addr) : %p\n",
4391 	I->fill_val, I->afni_undo,
4392 	I->A.M, I->A.used, I->A.points,
4393 	I->B.M, I->B.used, I->B.points
4394 	);
4395 
4396     printf( "-----------------------------------\n" );
4397 }
4398 
4399 
4400 /*----------------------------------------------------------------------
4401 **
4402 **  Display the contents of the holes structure.
4403 **
4404 **----------------------------------------------------------------------
4405  */
4406 static void
r_main_show_HL_vals(holes_s * H)4407 r_main_show_HL_vals( holes_s * H )
4408 {
4409     printf( "-----------------------------------\n" );
4410     printf(
4411 	"gRH :\n"
4412 	"\n"
4413 	"max size                : %d\n"
4414 	"fill value              : %d\n"
4415 	"wtgr_edge.M             : %d\n"
4416 	"wtgr_edge.used          : %d\n"
4417 	"wtgr_edge.points (addr) : %p\n"
4418 	"filled.M                : %d\n"
4419 	"filled.used             : %d\n"
4420 	"filled.points (addr)    : %p\n",
4421 	H->max_size, H->fill_val,
4422 	H->wtgr_edge.M, H->wtgr_edge.used, H->wtgr_edge.points,
4423 	H->filled.M, H->filled.used, H->filled.points
4424 	);
4425     printf( "-----------------------------------\n" );
4426 }
4427 
4428 
4429 /*----------------------------------------------------------------------
4430 **
4431 **  Display the contents of the point connection structure.
4432 **
4433 **----------------------------------------------------------------------
4434  */
4435 static void
r_main_show_pt_conn_vals(r_pt_conn_s * PC)4436 r_main_show_pt_conn_vals( r_pt_conn_s * PC )
4437 {
4438     printf( "-----------------------------------\n" );
4439     printf(
4440 	"gRCP :\n"
4441 	"\n"
4442 	"plist.M             : %d\n"
4443 	"plist.used          : %d\n"
4444 	"plist.points (addr) : %p\n"
4445 	"source point        : (%d,%d,%d)\n"
4446 	"dest point          : (%d,%d,%d)\n"
4447 	"which point         : %d\n",
4448 	PC->plist.M, PC->plist.used, PC->plist.points,
4449 	PC->source.x, PC->source.y, PC->source.z,
4450 	PC->dest.x, PC->dest.y, PC->dest.z,
4451 	PC->cur_pt
4452 	);
4453     printf( "-----------------------------------\n" );
4454 }
4455 
4456 
4457 /*----------------------------------------------------------------------
4458 **
4459 **  Callback to get help.  This displays a general process overview.
4460 **
4461 **----------------------------------------------------------------------
4462  */
4463 static void
r_main_cb_help(Widget w,XtPointer client_data,XtPointer call_data)4464 r_main_cb_help(
4465 	Widget    w,
4466 	XtPointer client_data,
4467 	XtPointer call_data
4468 	)
4469 {
4470     ( void )new_MCW_textwin( w,
4471 
4472 #include "plug_roiedit.hhh"
4473 
4474 	 "Compiled: "
4475 	 __DATE__
4476 	 ", "
4477 	 __TIME__
4478 	 "\n"
4479 
4480 	, TEXT_READONLY );
4481 
4482     return;
4483 }
4484 
4485 
4486 /*----------------------------------------------------------------------
4487 **
4488 **  Callback to quit ( this merely unmanages all the widgets ).
4489 **
4490 **----------------------------------------------------------------------
4491  */
4492 static void
r_main_cb_quit(void)4493 r_main_cb_quit( void )
4494 {
4495     r_any_cb_hide( NULL, "all", NULL );
4496     XtUnmapWidget( gRX.main );
4497     gRX.main_is_open = 0;
4498 }
4499 
4500 
4501 /*----------------------------------------------------------------------
4502 **
4503 **  Callback to save the current dataset under a new name.
4504 **
4505 **----------------------------------------------------------------------
4506  */
4507 static void
r_main_cb_saveas(Widget w,int client_data,XtPointer call_data)4508 r_main_cb_saveas(
4509 	Widget w,
4510 	int       client_data,
4511 	XtPointer call_data
4512 	)
4513 {
4514     XmSelectionBoxCallbackStruct * cbs;
4515     char * text;
4516     int    ival;
4517 
4518     ENTRY("r_main_cb_saveas");
4519 
4520     cbs = ( XmSelectionBoxCallbackStruct * )call_data;
4521 
4522     if ( ! XmStringGetLtoR( cbs->value, gRX.charset, &text ) )
4523     {
4524 	rERROR( "Failed to get filename from text." );
4525 	EXRETURN;
4526     }
4527     else if ( ! *text )
4528     {
4529 	XtFree( text );
4530 	EXRETURN;
4531     }
4532 
4533     /* Make sure file name is not too long.  */
4534 
4535     if ( strlen( text ) > R_FILE_L - 14 )  /* leave from for +tlrc.BRIK.gz_ */
4536     {
4537 	sprintf( gRmessage, "Output filename '%s' exceeds %d characters.\n",
4538 			    text, R_FILE_L - 14 );
4539 	rERROR( gRmessage );
4540     }
4541     else
4542 	strcpy( gRA.save_as_name, text );
4543 
4544     XtFree( text );
4545 
4546     r_save_dataset_as( gRA.save_as_name, client_data );
4547     EXRETURN;
4548 }
4549 
4550 
4551 /*----------------------------------------------------------------------
4552 **
4553 **  Actually save the new dataset.  Make a copy of the original dset,
4554 **  change the prefix and save the file.
4555 **
4556 **----------------------------------------------------------------------
4557  */
4558 static int
r_save_dataset_as(char * filename,int overwrite)4559 r_save_dataset_as( char * filename, int overwrite )
4560 {
4561     THD_3dim_dataset * dset = NULL;
4562 
4563     ENTRY("r_save_dataset_as");
4564 
4565     if ( ! ( dset = PLUTO_copy_dset( gRA.func, filename ) ) )
4566     {
4567 	sprintf( gRmessage,"Failed to copy dataset with name '%s'.", filename );
4568 	rERROR( gRmessage );
4569 	RETURN(0);
4570     }
4571 
4572     if( ! overwrite && THD_is_file( dset->dblk->diskptr->header_name ) )
4573     {
4574 	sprintf( gRmessage, "File '%s' already exists!", filename );
4575 	rERROR( gRmessage );
4576     }
4577     else
4578     {
4579 	DSET_overwrite( dset ) ;
4580 
4581 	sprintf( gRmessage, "Dataset copied as '%s'.", filename );
4582 	rWARNING( gRmessage );
4583     }
4584 
4585     THD_delete_3dim_dataset( dset, False );
4586 
4587     RETURN(1);
4588 }
4589 
4590 
4591 /*----------------------------------------------------------------------
4592 **
4593 **  Display the contents of internal structures.
4594 **
4595 **----------------------------------------------------------------------
4596  */
4597 static void
r_main_cb_show_structs(void)4598 r_main_cb_show_structs( void )
4599 {
4600     ENTRY("r_main_cb_show_structs");
4601 
4602     printf( "------------------------------------------------------------\n" );
4603 
4604     r_main_show_alg_vals    ( &gRA );
4605     r_main_show_INT_vals    ( &gRI );
4606     r_main_show_HL_vals     ( &gRH );
4607     r_main_show_pt_conn_vals( &gRCP );
4608 
4609     printf( "------------------------------------------------------------\n" );
4610     EXRETURN;
4611 }
4612 
4613 
4614 /*----------------------------------------------------------------------
4615 **------                                --------------------------------
4616 **------  Begin interpolation routines  --------------------------------
4617 **------                                --------------------------------
4618 **----------------------------------------------------------------------
4619 **
4620 **  The technique here is to keep two curves of data stored.
4621 **
4622 **  Operations that we need to consider are :
4623 **
4624 **      o  inserting a new line ( on any line draw )
4625 **              if none     { insert first  }
4626 **              else if one { insert second }
4627 **              else        { move second to first, insert second }
4628 **      o  UNDO move
4629 **              if two      { remove second }
4630 **              else        { remove first  }
4631 **      o  interpolate  ( use special interpolation value )
4632 **              - only with the two lines
4633 **              - store previous interpolation first
4634 **                  ( change interpolation values to draw values )
4635 **      o  undo interpolation
4636 **              remove all interpolation values
4637 **
4638 **----------------------------------------------------------------------
4639  */
4640 
4641 
4642 /*-------------------------------------------------------------------
4643   Callback for done button
4644 ---------------------------------------------------------------------*/
4645 
DRAW_done_CB(Widget w,XtPointer client_data,XtPointer call_data)4646 static void DRAW_done_CB( Widget w, XtPointer client_data, XtPointer call_data )
4647 {
4648     ENTRY("DRAW_done_CB");
4649 
4650    if( dset != NULL ){
4651       if( recv_open ) AFNI_receive_control( im3d, recv_key, DRAWING_SHUTDOWN, NULL ) ;
4652       if( dset_changed ){
4653 	 MCW_invert_widget( done_pb ) ;
4654 	 DSET_overwrite(dset) ;
4655 	 MCW_invert_widget( done_pb ) ;
4656       }
4657       DSET_unlock(dset) ; DSET_anyize(dset) ;
4658       dset = NULL ; dset_changed = 0 ;
4659    }
4660 
4661    if( undo_buf != NULL ){
4662       free(undo_buf) ; free(undo_xyz) ;
4663       undo_buf = NULL; undo_xyz = NULL;
4664       undo_bufsiz = undo_bufnum = undo_bufuse = 0 ;
4665    }
4666 
4667    XtUnmapWidget( shell ) ; editor_open = 0 ; recv_open = 0 ; recv_key = -1 ;
4668    EXRETURN;
4669 }
4670 
4671 /*-------------------------------------------------------------------
4672   Callback for undo button
4673 ---------------------------------------------------------------------*/
4674 
DRAW_undo_CB(Widget w,XtPointer client_data,XtPointer call_data)4675 static void DRAW_undo_CB( Widget w, XtPointer client_data, XtPointer call_data )
4676 {
4677    void * ub ; int * ux, * uy, * uz ;
4678    int ubs = undo_bufsiz , uis = sizeof(int)*undo_bufuse ;
4679 
4680    ENTRY("DRAW_undo_CB");
4681 
4682    if( undo_bufuse <= 0 ){ XBell( dc->display , 100 ) ; EXRETURN ; }
4683 
4684    /* since the undo_stuff will be modified by the
4685       drawing function, we must make temporary copies */
4686 
4687    ub =         malloc(ubs) ; memcpy(ub,undo_buf,ubs) ;
4688    ux = (int *) malloc(uis) ; memcpy(ux,undo_xyz,uis) ;
4689 
4690    gRI.afni_undo = 1;
4691    DRAW_into_dataset( undo_bufuse , ux,NULL,NULL , ub ) ;
4692    gRI.afni_undo = 0;
4693 
4694    if ( ( mode_ival == MODE_CURVE ) || ( mode_ival == MODE_CLOSED ) ||
4695 	( mode_ival == MODE_CONN_PTS ) )
4696    {
4697 	gRI.B.used = 0;         /* RCR - clear any new I-data */
4698 
4699 	if ( mode_ival == MODE_CONN_PTS )
4700 	    gRCP.cur_pt = 1;
4701    }
4702 
4703    free(ub) ; free(ux) ;
4704    EXRETURN ;
4705 }
4706 
4707 /*-------------------------------------------------------------------
4708   Callback for quit button
4709 ---------------------------------------------------------------------*/
4710 
DRAW_quit_CB(Widget w,XtPointer client_data,XtPointer call_data)4711 static void DRAW_quit_CB( Widget w, XtPointer client_data, XtPointer call_data )
4712 {
4713    ENTRY("DRAW_quit_CB");
4714 
4715    if( dset != NULL ){
4716       if( recv_open ) AFNI_receive_control( im3d, recv_key, DRAWING_SHUTDOWN, NULL ) ;
4717       DSET_unlock(dset) ;
4718       DSET_unload(dset) ; DSET_anyize(dset) ;
4719       if( dset_changed ){
4720 	 MCW_invert_widget(quit_pb) ;
4721 	 THD_load_statistics( dset ) ;
4722 	 PLUTO_dset_redisplay( dset ) ;
4723 	 MCW_invert_widget(quit_pb) ;
4724       }
4725       dset = NULL ; dset_changed = 0 ;
4726    }
4727 
4728    if( undo_buf != NULL ){
4729       free(undo_buf) ; free(undo_xyz) ;
4730       undo_buf = NULL; undo_xyz = NULL;
4731       undo_bufsiz = undo_bufnum = undo_bufuse = 0 ;
4732    }
4733 
4734    XtUnmapWidget( shell ) ; editor_open = 0 ; recv_open = 0 ; recv_key = -1 ;
4735    EXRETURN ;
4736 }
4737 
4738 /*-------------------------------------------------------------------
4739   Callback for save button
4740 ---------------------------------------------------------------------*/
4741 
DRAW_save_CB(Widget w,XtPointer client_data,XtPointer call_data)4742 static void DRAW_save_CB( Widget w, XtPointer client_data, XtPointer call_data )
4743 {
4744    ENTRY("DRAW_save_CB");
4745 
4746    if( dset == NULL ){ XBell( dc->display , 100 ) ; EXRETURN ; }
4747 
4748    MCW_invert_widget(save_pb) ;
4749 
4750    DSET_overwrite(dset); dset_changed = 0; SENSITIZE(choose_pb,1);
4751 
4752    MCW_invert_widget(save_pb) ; SENSITIZE(save_pb,0) ;
4753    EXRETURN ;
4754 }
4755 
4756 /*-------------------------------------------------------------------
4757   Callback for help button
4758 ---------------------------------------------------------------------*/
4759 
DRAW_help_CB(Widget w,XtPointer client_data,XtPointer call_data)4760 static void DRAW_help_CB( Widget w, XtPointer client_data, XtPointer call_data )
4761 {
4762    (void ) new_MCW_textwin( help_pb ,
4763 
4764   "The GyrusFinder plugin is based on the original 'Draw Dataset' plugin\n"
4765   "by RW Cox.  The original help for that plugin is below.  Help for the\n"
4766   "new features can be found in the new windows created by GyrusFinder.\n"
4767   "======================================================================\n"
4768   "This plugin can be used to edit interactively the voxel contents\n"
4769   "of a dataset.  Since such changes are irreversible, it is best that\n"
4770   "you either edit a copy of a dataset, or create a dataset of all zeros.\n"
4771   "These tasks can be done with the 'Dataset Copy' plugin.\n"
4772   "\n"
4773   "***************** Read the WARNINGS section below. *****************\n"
4774   "\n"
4775   "---------------------- Bob Cox, February 1998 ----------------------\n"
4776   "\n"
4777   "Step 1) Choose a dataset to edit.\n"
4778   "        * Only datasets that have data BRIKs stored at the current\n"
4779   "            resolution can be edited.\n"
4780   "        * Datasets may be copied with the 'Dataset Copy' plugin.\n"
4781   "        * It is probably best that the dataset being edited be\n"
4782   "            displayed.  Otherwise it will be impossible to gauge\n"
4783   "            the effect of the editing operations.\n"
4784   "        * At this time, only datasets that have a single sub-brick\n"
4785   "            can be edited.\n"
4786   "\n"
4787   "Step 2) Choose a drawing value.\n"
4788   "        * This is the number that will be placed into the dataset\n"
4789   "            voxels that are chosen.\n"
4790   "        * Integer valued datasets can only receive integer values;\n"
4791   "            float datasets can take floating point values.\n"
4792   "\n"
4793   "Step 3) Choose a drawing color.\n"
4794   "        * This is the color that will be shown in the image windows\n"
4795   "            while drawing is going on (that is, while mouse button 2\n"
4796   "            is pressed).\n"
4797   "        * See 5) for more details about the drawing process.\n"
4798   "\n"
4799   "Step 4) Choose a drawing mode.\n"
4800   "        * 'Open Curve' means to select dataset voxels that lie under\n"
4801   "            the pixel lines drawn on the image as you move the mouse\n"
4802   "            with button 2 held down.\n"
4803   "        * 'Closed Curve ' means to close the curve drawn from the last\n"
4804   "            point drawn (where button 2 is released) back to the\n"
4805   "            first point drawn (where button 2 was pressed).\n"
4806   "        * 'Points' means to take only the voxels corresponding\n"
4807   "            to the screen pixels about which X11 sends notice\n"
4808   "            (this is not very useful).\n"
4809   "        * 'Flood->Value' means to flood fill outwards from the first\n"
4810   "            chosen voxel, stopping when the Dataset Value is reached.\n"
4811   "            In conjunction with 'Closed Curve', it can be used to draw\n"
4812   "            an entire region in a plane.\n"
4813   "        * 'Flood->Nonzero' means to flood fill, but stopping when any\n"
4814   "            nonzero voxel value is reached.\n"
4815   "\n"
4816   "Step 5) Draw something in an image window.\n"
4817   "        * Drawing is done using mouse button 2.\n"
4818   "        * In an image window, drawing a set of pixels is done\n"
4819   "            by pressing and holding button 2, and dragging\n"
4820   "            the cursor across the desired pixels.  The drawing\n"
4821   "            color will be painted over these pixels while the\n"
4822   "            painting is going on (while button 2 is held down).\n"
4823   "        * After mouse button 2 is released, the drawing value for\n"
4824   "            the chosen voxels is copied into the dataset.  The\n"
4825   "            dataset is then redisplayed -- this will most likely\n"
4826   "            change the color of the selected voxels, since display\n"
4827   "            colors depend on the Define Function pbar (for Func\n"
4828   "            datasets) or on the greyscale map (for Anat datasets).\n"
4829   "        * That is, the drawing color is ONLY used while button2\n"
4830   "            is pressed down.  This color should simply be chosen\n"
4831   "            to provide good contrast for the drawing operations.\n"
4832   "        * Pressing and releasing button 2 in a graph window\n"
4833   "            sub-graph will cause that single voxel to get the\n"
4834   "            drawing value, as well.  You cannot select a group\n"
4835   "            of voxels in a graph window -- only one voxel per click.\n"
4836   "\n"
4837   "Step 6) Undo.\n"
4838   "        * The last drawing operation can be undone -- that is,\n"
4839   "            pressing 'Undo' will restore the voxel values before\n"
4840   "            the last button 2 press-release operation.\n"
4841   "        * There is only one level of undo.  Undo-ing the undo\n"
4842   "            will put things back the way they were.  Anyone who\n"
4843   "            implements a better undo system will be appreciated.\n"
4844   "\n"
4845   "Step 7) Save dataset (maybe).\n"
4846   "        * While a dataset is being edited, it is locked into memory.\n"
4847   "        * The edited values are saved to disk only when 'Save' or\n"
4848   "            'Done' are pressed.\n"
4849   "        * The 'Quit' button can be used to discard the edits of\n"
4850   "            a dataset.  In that case, the dataset values are\n"
4851   "            re-read from disk when it is redisplayed.\n"
4852   "        * Closing the AFNI Editor window using the window manager\n"
4853   "            is equivalent to pressing 'Quit'.\n"
4854   "\n"
4855   "WARNINGS:\n"
4856   "  * It is important to understand the distinction between 'pixels'\n"
4857   "      and 'voxels'.  Pixels are on the screen, and while you are\n"
4858   "      drawing, you are drawing pixels with the drawing color.  When\n"
4859   "      you release mouse button 2, those dataset voxels to which these\n"
4860   "      pixels correspond are computed.  The values stored in those\n"
4861   "      voxels are then altered, and the dataset display is refreshed.\n"
4862   "  * It is possible to draw on a montaged image window.  However,\n"
4863   "      only voxels from the first slice drawn into will be altered.\n"
4864   "  * Using button 2 in an image or graph window before choosing a\n"
4865   "      dataset to edit will cause the display to beep.\n"
4866   "  * Closing the AFNI controller window that this was started from\n"
4867   "      is the equivalent of pressing 'Quit'.\n"
4868   "  * Doing something that causes the AFNI controller window to\n"
4869   "      alter its 3D grid location or resolution is also the\n"
4870   "      equivalent of pressing 'Quit'.  This is because the 3D grid\n"
4871   "      for the dataset being edited will no longer correspond to\n"
4872   "      the 3D grid in the image and graph windows.  Such actions\n"
4873   "      include switching from 'View Brick' to 'Warp on Demand',\n"
4874   "      switching datasets or sessions, and switching views.\n"
4875   "  * You can only draw into the windows of the controller from which\n"
4876   "      the Editor was started.\n"
4877   "  * Only one copy of the Editor can be active at a time.  If you\n"
4878   "      use the plugin menu to call up the Editor when it is already\n"
4879   "      open, that will simply pop the window up to the top of the\n"
4880   "      stacking order.  If you want to restart the Editor in a\n"
4881   "      different AFNI controller, you must first close the Editor\n"
4882   "      (via 'Done' or 'Quit') and then start it from the other\n"
4883   "      controller's window.\n"
4884   "  * Peculiar and confusing things can happen using 'Warp-on-Demand'\n"
4885   "      with the Editor.  My advice is not to try this.\n"
4886   "  * Edit at your own risk!  Be careful out there.\n"
4887   "\n"
4888   "SUGGESTIONS?\n"
4889   "  * Please send them to " COXEMAIL "\n"
4890   "  * Even better than suggestions are implementations.\n"
4891 
4892 
4893     , TEXT_READONLY ) ;
4894    return ;
4895 }
4896 
4897 /*-------------------------------------------------------------------
4898   Callback for choose button.
4899   Criteria for datasets that can be edited:
4900     - must be in current session
4901     - must have actual bricks
4902     - only datasets with nvals=1 can be edited
4903     - bricks must be on same grid (dataxes) as AFNI controller
4904   Much of this code is adapted from PLUG_choose_dataset_CB.
4905   [28 Jul 2003] Modified for new THD_session struct.
4906 ---------------------------------------------------------------------*/
4907 
4908 static int                  ndsl = 0 ;
4909 static PLUGIN_dataset_link * dsl = NULL ;
4910 
DRAW_choose_CB(Widget w,XtPointer client_data,XtPointer call_data)4911 static void DRAW_choose_CB( Widget w, XtPointer client_data, XtPointer call_data )
4912 {
4913    THD_session * ss  = im3d->ss_now ;           /* current session */
4914    int           vv  = im3d->vinfo->view_type ; /* view type */
4915    THD_3dim_dataset * qset ;
4916    int id , ltop , llen ;
4917    char qnam[THD_MAX_NAME] , label[THD_MAX_NAME] ;
4918    static char ** strlist = NULL ;
4919 
4920    ENTRY("DRAW_choose_CB");
4921 
4922    /* can't do this if a dataset is already active and changed */
4923 
4924    if( dset != NULL && dset_changed ){
4925       (void) MCW_popup_message( choose_pb ,
4926 				   "Can't change datasets until\n"
4927 				   "you save the changes you've\n"
4928 				   "already made.  Or you could\n"
4929 				   "'Quit' and re-start the Editor" ,
4930 				MCW_USER_KILL | MCW_TIMER_KILL ) ;
4931       XBell( dc->display , 100 ) ;
4932       EXRETURN ;
4933    }
4934 
4935    /* RCR - If data is not on disk, do not accept it (must be a warp).
4936 	Inform the user that they might have to write the anat.
4937    */
4938    if ( ! DSET_ONDISK( im3d->anat_now ) )
4939    {
4940       (void) MCW_popup_message( choose_pb ,
4941 		   "Anat data is not actually on disk!\n"
4942 		   "You may be in 'Warp-on-Demand' mode.\n"
4943 		   "\n"
4944 		   "Please take the following steps :\n"
4945 		   "   1. 'Write Anat'\n"
4946 		   "   2. 'Rescan This'\n"
4947 		   "   3. Set to 'View Anat Data Brick'",
4948 		MCW_USER_KILL | MCW_TIMER_KILL ) ;
4949       XBell( dc->display , 100 ) ;
4950       EXRETURN ;
4951    }
4952 
4953    /* initialize */
4954 
4955    ndsl = 0 ;
4956 
4957    /* scan anats */
4958 
4959    for( id=0 ; id < ss->num_dsset ; id++ ){
4960       qset = GET_SESSION_DSET(ss, id, vv);
4961 /*      qset = ss->dsset_xform_table[id][vv] ;*/
4962 
4963       if( ! ISVALID_DSET (qset)                        ) continue ;  /* skip */
4964       if( ! DSET_INMEMORY(qset)                        ) continue ;
4965       if(   DSET_NVALS(qset) > 1                       ) continue ;
4966       if( ! EQUIV_DATAXES(qset->daxes,im3d->wod_daxes) ) continue ;
4967 
4968       ndsl++ ;
4969       dsl = (PLUGIN_dataset_link *)
4970 	      XtRealloc( (char *) dsl , sizeof(PLUGIN_dataset_link)*ndsl ) ;
4971 
4972       make_PLUGIN_dataset_link( qset , dsl + (ndsl-1) ) ;
4973    }
4974 
4975    /* found nothing?  exit */
4976 
4977    if( ndsl < 1 ){
4978       (void) MCW_popup_message( choose_pb ,
4979 				   "Didn't find any datasets to edit!\n"
4980 				   "Check if:\n"
4981 				   " - you are in 'Warp-on-Demand' mode\n"
4982 				   " - you are in the correct session" ,
4983 				MCW_USER_KILL | MCW_TIMER_KILL ) ;
4984       XBell( dc->display , 100 ) ;
4985       EXRETURN ;
4986    }
4987 
4988    /*--- 23 Nov 1996: loop over dataset links and patch their titles
4989 		      to include an indicator of the dataset type    ---*/
4990 
4991    ltop = 4 ;
4992    for( id=0 ; id < ndsl ; id++ ){
4993       llen = strlen(dsl[id].title) ;
4994       ltop = MAX(ltop,llen) ;
4995    }
4996 
4997    for( id=0 ; id < ndsl ; id++ ){
4998       qset = PLUTO_find_dset( &(dsl[id].idcode) ) ;
4999       if( ! ISVALID_DSET(qset) ) continue ;
5000       if( ISANAT(qset) ){
5001 	 if( ISANATBUCKET(qset) )         /* 30 Nov 1997 */
5002 	    sprintf(qnam,"%-*s [%s:%d]" ,
5003 		    ltop,dsl[id].title ,
5004 		    ANAT_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
5005 
5006 	 else if( DSET_NUM_TIMES(qset) == 1 )
5007 	    sprintf(qnam,"%-*s [%s]" ,
5008 		    ltop,dsl[id].title ,
5009 		    ANAT_prefixstr[qset->func_type] ) ;
5010 
5011 	 else
5012 	    sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
5013 		    ltop,dsl[id].title ,
5014 		    ANAT_prefixstr[qset->func_type] , DSET_NUM_TIMES(qset) ) ;
5015 
5016       } else {
5017 	 if( ISFUNCBUCKET(qset) )         /* 30 Nov 1997 */
5018 	    sprintf(qnam,"%-*s [%s:%d]" ,
5019 		    ltop,dsl[id].title ,
5020 		    FUNC_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
5021 
5022 	 else if( DSET_NUM_TIMES(qset) == 1 )
5023 	    sprintf(qnam,"%-*s [%s]" ,
5024 		    ltop,dsl[id].title ,
5025 		    FUNC_prefixstr[qset->func_type] ) ;
5026 
5027 	 else
5028 	    sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
5029 		    ltop,dsl[id].title ,
5030 		    FUNC_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
5031       }
5032 
5033       if( DSET_COMPRESSED(qset) ) strcat(qnam,"z") ;
5034 
5035       strcpy( dsl[id].title , qnam ) ;
5036    }
5037 
5038    /*--- make a popup chooser for the user to browse ---*/
5039 
5040    POPDOWN_strlist_chooser ;
5041 
5042    strlist = (char **) XtRealloc( (char *)strlist , sizeof(char *)*ndsl ) ;
5043    for( id=0 ; id < ndsl ; id++ ) strlist[id] = dsl[id].title ;
5044 
5045    sprintf( label , "AFNI Dataset from\nthe %s" , VIEW_typestr[vv] ) ;
5046 
5047    MCW_choose_strlist( w , label , ndsl , -1 , strlist ,
5048 		       DRAW_finalize_dset_CB , NULL     ) ;
5049 
5050    EXRETURN ;
5051 }
5052 
DRAW_finalize_dset_CB(Widget w,XtPointer fd,MCW_choose_cbs * cbs)5053 static void DRAW_finalize_dset_CB( Widget w, XtPointer fd, MCW_choose_cbs * cbs )
5054 {
5055    int id = cbs->ival ;
5056    THD_3dim_dataset * qset ;
5057    XmString xstr ;
5058    char str[256] ;
5059 
5060    ENTRY("DRAW_finalize_dset_CB");
5061 
5062    /* check for errors */
5063 
5064    if( ! editor_open ){ POPDOWN_strlist_chooser ; XBell(dc->display,100) ; EXRETURN ; }
5065 
5066    if( dset != NULL && dset_changed ){ XBell(dc->display,100) ; EXRETURN ; }
5067 
5068    if( id < 0 || id >= ndsl ){ XBell(dc->display,100) ; EXRETURN ; }
5069 
5070    qset = PLUTO_find_dset( &(dsl[id].idcode) ) ;  /* the new dataset? */
5071 
5072    if( qset == NULL ){ XBell(dc->display,100) ; EXRETURN ; }
5073 
5074    if( ! EQUIV_DATAXES( im3d->wod_daxes , qset->daxes ) ){
5075       XBell(dc->display,100) ; EXRETURN ;
5076    }
5077 
5078    /* accept this dataset */
5079 
5080    dset = qset ; dset_changed = 0 ; SENSITIZE(save_pb,0) ;
5081    dax_save = *(dset->daxes) ;
5082 
5083    /* write the informational label */
5084 
5085    if( DSET_BRICK_FACTOR(dset,0) == 0.0 ){
5086       strcpy(str,dsl[id].title) ;
5087    } else {
5088       char abuf[16] ;
5089       AV_fval_to_char( DSET_BRICK_FACTOR(dset,0) , abuf ) ;
5090       sprintf(str,"%s\nbrick factor: %s", dsl[id].title , abuf ) ;
5091    }
5092    xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
5093    XtVaSetValues( info_lab , XmNlabelString , xstr , NULL ) ;
5094    XmStringFree(xstr) ;
5095 
5096    /* setup AFNI for drawing */
5097 
5098    if( ! recv_open ){
5099       recv_key = AFNI_receive_init( im3d, RECEIVE_DRAWING_MASK,
5100                                     DRAW_receiver,NULL,"DRAW_receiver" ) ;
5101 
5102       if( recv_key < 0 ){
5103 	 (void) MCW_popup_message( im3d->vwid->top_shell ,
5104 				     "Unable to establish\n"
5105 				     "connection to AFNI\n"
5106 				     "drawing routines!" ,
5107 				   MCW_USER_KILL | MCW_TIMER_KILL ) ;
5108 
5109 	 dset = NULL ; XBell(dc->display,100) ; EXRETURN ;
5110       }
5111    }
5112 
5113    DSET_mallocize(dset) ; DSET_lock(dset) ; DSET_load(dset) ;
5114 
5115    AFNI_receive_control( im3d, recv_key , mode_index , NULL ) ;
5116    AFNI_receive_control( im3d, recv_key , DRAWING_OVCINDEX, ITOP(color_index) ) ;
5117    recv_open = 1 ;
5118 
5119    undo_bufuse = 0 ; SENSITIZE(undo_pb,0) ;
5120 
5121    r_init_afni_vars( &gRA, dset );
5122 
5123    EXRETURN ;
5124 }
5125 
5126 /*-------------------------------------------------------------------
5127   Callback for color menu
5128 ---------------------------------------------------------------------*/
5129 
DRAW_color_CB(MCW_arrowval * av,XtPointer cd)5130 static void DRAW_color_CB( MCW_arrowval * av , XtPointer cd )
5131 {
5132    color_index = av->ival ;
5133 
5134    if( dset != NULL && recv_open )
5135      AFNI_receive_control( im3d, recv_key, DRAWING_OVCINDEX, ITOP(color_index) ) ;
5136 
5137    return ;
5138 }
5139 
5140 /*-------------------------------------------------------------------
5141   Callback for mode menu
5142 ---------------------------------------------------------------------*/
5143 
DRAW_mode_CB(MCW_arrowval * av,XtPointer cd)5144 static void DRAW_mode_CB( MCW_arrowval * av , XtPointer cd )
5145 {
5146    mode_ival  = av->ival ;
5147    mode_index = mode_ints[mode_ival] ;
5148 
5149    if( dset != NULL && recv_open )
5150       AFNI_receive_control( im3d, recv_key, mode_index , NULL ) ;
5151 
5152    return ;
5153 }
5154 
5155 /*-------------------------------------------------------------------
5156   Callback for value menu
5157 ---------------------------------------------------------------------*/
5158 
DRAW_value_CB(MCW_arrowval * av,XtPointer cd)5159 static void DRAW_value_CB( MCW_arrowval * av , XtPointer cd )
5160 {
5161    value_int   = av->ival ;
5162    value_float = av->fval ;
5163    return ;
5164 }
5165 
5166 /*******************************************************************
5167    Receive data from AFNI after drawing, etc.
5168 ********************************************************************/
5169 
DRAW_receiver(int why,int np,void * vp,void * cbd)5170 static void DRAW_receiver( int why , int np , void * vp , void * cbd )
5171 {
5172    ENTRY("DRAW_receiver");
5173 
5174    switch( why ){
5175 
5176       default:
5177 	 fprintf(stderr,"DRAW_receiver: illegal why=%d\n",why) ;
5178       EXRETURN ;
5179 
5180       /*-- we like this one --*/
5181 
5182       case RECEIVE_POINTS:{
5183 	 int **ip = (int **)vp ;
5184 	 int *xd=ip[0] , *yd=ip[1] , *zd=ip[2] ; /* pts coords */
5185 	 int mode=ip[3][0] ;                     /* how pts are organized */
5186 	 int plane ;
5187 
5188 	 if( np <= 0 ) EXRETURN ;  /* some error? */
5189 
5190 	 plane = mode - SINGLE_MODE ;
5191 	 if( plane < 1 || plane > 3 ) plane = mode - PLANAR_MODE ;
5192 	 if( plane < 1 || plane > 3 ) plane = 0 ;
5193 
5194 	 /* handle selection of initial point for vol_fill, otherwise, */
5195 	 /* anything but flood mode --> just draw given points         */
5196 
5197 	 if ( mode_ival == MODE_VOL_FILL )
5198 	 {
5199 	     int coord;
5200 
5201 	     if ( yd == NULL )
5202 		 coord = *xd;
5203 	     else
5204 		 coord = *xd +
5205 			 *yd * DSET_NX(gRA.anat) +
5206 			 *zd * DSET_NX(gRA.anat) * DSET_NY(gRA.anat);
5207 
5208 	     if ( r_afni_set_fill_point( &coord, &gRA ) < 0 )
5209                 EXRETURN ;
5210 
5211 	     DRAW_into_dataset( 0, &coord, NULL, NULL, NULL );
5212 	 }
5213 	 else if ( mode_ival == MODE_CONN_PTS )
5214 	 {   /* store the points into xd and DRAW_into_dataset */
5215 	     r_ipt_t * pptr;
5216 	     int       coord;
5217 
5218 	     if ( gRCP.cur_pt == 1 )
5219 		 pptr = &gRCP.source;
5220 	     else if ( gRCP.cur_pt == 2 )
5221 		 pptr = &gRCP.dest;
5222 	     else
5223 	     {
5224 		 rERROR( "In DRAW_receiver() - gRCP.cur_pt is unset." );
5225 		 EXRETURN;
5226 	     }
5227 
5228 	     if ( yd == NULL )
5229 		 *pptr = r_index2pt( *xd, gRA.nx, gRA.ny, gRA.nz );
5230 	     else
5231 	     {
5232 		 pptr->x = *xd;
5233 		 pptr->y = *yd;
5234 		 pptr->z = *zd;
5235 	     }
5236 
5237 	     /* If first point, just store it.   Otherwise draw entire line. */
5238 
5239 	     if ( gRCP.cur_pt == 1 )
5240 	     {
5241 		 gRCP.cur_pt = 2;
5242 		 DRAW_into_dataset( 0, xd, yd, zd, NULL );
5243 		 EXRETURN;
5244 	     }
5245 	     else
5246 	     {
5247 		 points_t * Bp = &gRCP.plist;
5248 		 r_ipt_t    p;
5249 		 float      dx, dy, dz, fx, fy, fz, dcurr;
5250 		 float      tot_dist = r_p_distance( gRCP.source, gRCP.dest );
5251 		 int        pcount = 0;
5252 
5253 		 Bp->used = 0;
5254 
5255 		 dx = R_DIST_STEP * ( gRCP.dest.x - gRCP.source.x ) / tot_dist;
5256 		 dy = R_DIST_STEP * ( gRCP.dest.y - gRCP.source.y ) / tot_dist;
5257 		 dz = R_DIST_STEP * ( gRCP.dest.z - gRCP.source.z ) / tot_dist;
5258 		 fx = gRCP.source.x;
5259 		 fy = gRCP.source.y;
5260 		 fz = gRCP.source.z;
5261 
5262 		 for ( dcurr = 0; dcurr < tot_dist; dcurr += R_DIST_STEP )
5263 		 {
5264 		     coord = (int)fx + gRA.nx*((int)fy + gRA.ny*(int)fz);
5265 		     r_add_to_boundary( Bp, coord );
5266 
5267 		     fx += dx;
5268 		     fy += dy;
5269 		     fz += dz;
5270 		 }
5271 
5272 		 coord = gRCP.dest.x + gRA.nx*(gRCP.dest.y+gRA.ny*gRCP.dest.z);
5273 		 r_add_to_boundary( Bp, coord );        /* add last point */
5274 
5275 		 DRAW_into_dataset( Bp->used, Bp->points, NULL, NULL, NULL );
5276 
5277 		 gRCP.cur_pt = 1;
5278 
5279 		 /*
5280 		 ** store the line as an interpolator line :
5281 		 ** DRAW_into_dataset() was edited to check for MODE_CONN_PTS
5282 		 ** when it stores the incoming line (point set).
5283 		 */
5284 	     }
5285 	 }
5286 	 else if( plane == 0 ||
5287 	     ((mode_ival != MODE_FLOOD_VAL) && (mode_ival != MODE_FLOOD_NZ)) ){
5288 
5289 	    DRAW_into_dataset( np , xd,yd,zd , NULL ) ;
5290 
5291 	 } else {
5292 
5293 	    /* flood mode! */
5294 
5295 	    int   ityp = DSET_BRICK_TYPE(dset,0) ;
5296 	    float bfac = DSET_BRICK_FACTOR(dset,0) ;
5297 	    int nx=DSET_NX(dset) , ny=DSET_NY(dset) , nz=DSET_NZ(dset) ,
5298 		nxy = nx*ny , nxyz = nxy*nz , ii,jj , ixyz ;
5299 	    int base=0 , di=0,dj=0 , itop=0,jtop=0,nij , xx=xd[0],yy=yd[0],zz=zd[0] ,
5300 		ix=0,jy=0 ;
5301 	    byte * pl ;
5302 	    int nfill , * xyzf , nf ;
5303 
5304 	    /* compute stuff for which plane we are in:
5305 		1 -> yz , 2 -> xz , 3 -> xy            */
5306 
5307 	    switch(plane){
5308 	       case 1: base=xx    ; di=nx; dj=nxy; itop=ny; jtop=nz;
5309 			ix=yy; jy=zz; break;
5310 	       case 2: base=yy*nx ; di=1 ; dj=nxy; itop=nx; jtop=nz;
5311 			ix=xx; jy=zz; break;
5312 	       case 3: base=zz*nxy; di=1 ; dj=nx ; itop=nx; jtop=ny;
5313 			ix=xx; jy=yy; break;
5314 	    }
5315 
5316 	    /* create a 2D array with 0 where dataset != blocking value
5317 			     and with 1 where dataset == blocking value */
5318 
5319 	    nij = itop*jtop ;
5320 	    pl  = (byte *) malloc( sizeof(byte) * nij ) ;
5321 	    memset( pl , 0 , sizeof(byte) * nij ) ;
5322 
5323 	    if( bfac == 0.0 ) bfac = 1.0 ;
5324 	    switch(ityp){
5325 
5326 	       case MRI_short:{
5327 		  short * bp  = (short *) DSET_BRICK_ARRAY(dset,0) ;
5328 		  short   val = (short)   (value_float/bfac) ;
5329 
5330 		  if( mode_ival == MODE_FLOOD_VAL ){
5331 		     for( jj=0 ; jj < jtop ; jj++ )
5332 			for( ii=0 ; ii < itop ; ii++ ){
5333 			   ixyz = base + ii*di + jj*dj ;
5334 			   if( bp[ixyz] == val ) pl[ii+jj*itop] = 1 ;
5335 			}
5336 		  } else {
5337 		     for( jj=0 ; jj < jtop ; jj++ )
5338 			for( ii=0 ; ii < itop ; ii++ ){
5339 			   ixyz = base + ii*di + jj*dj ;
5340 			   if( bp[ixyz] != 0 ) pl[ii+jj*itop] = 1 ;
5341 			}
5342 		  }
5343 	       }
5344 	       break ;
5345 
5346 	       case MRI_byte:{
5347 		  byte * bp  = (byte *) DSET_BRICK_ARRAY(dset,0) ;
5348 		  byte   val = (byte)   (value_float/bfac) ;
5349 
5350 		  if( mode_ival == MODE_FLOOD_VAL ){
5351 		     for( jj=0 ; jj < jtop ; jj++ )
5352 			for( ii=0 ; ii < itop ; ii++ ){
5353 			   ixyz = base + ii*di + jj*dj ;
5354 			   if( bp[ixyz] == val ) pl[ii+jj*itop] = 1 ;
5355 			}
5356 		  } else {
5357 		     for( jj=0 ; jj < jtop ; jj++ )
5358 			for( ii=0 ; ii < itop ; ii++ ){
5359 			   ixyz = base + ii*di + jj*dj ;
5360 			   if( bp[ixyz] != 0 ) pl[ii+jj*itop] = 1 ;
5361 			}
5362 		  }
5363 	       }
5364 	       break ;
5365 
5366 	       case MRI_float:{
5367 		  float * bp  = (float *) DSET_BRICK_ARRAY(dset,0) ;
5368 		  float   val = (value_float/bfac) ;
5369 
5370 		  if( mode_ival == MODE_FLOOD_VAL ){
5371 		     for( jj=0 ; jj < jtop ; jj++ )
5372 			for( ii=0 ; ii < itop ; ii++ ){
5373 			   ixyz = base + ii*di + jj*dj ;
5374 			   if( bp[ixyz] == val ) pl[ii+jj*itop] = 1 ;
5375 			}
5376 		  } else {
5377 		     for( jj=0 ; jj < jtop ; jj++ )
5378 			for( ii=0 ; ii < itop ; ii++ ){
5379 			   ixyz = base + ii*di + jj*dj ;
5380 			   if( bp[ixyz] != 0.0 ) pl[ii+jj*itop] = 1 ;
5381 			}
5382 		  }
5383 	       }
5384 	       break ;
5385 
5386 	       default:
5387 		  free(pl) ;
5388 		  fprintf(stderr,
5389 			 "Flood not implemented for datasets of type %s\a\n",
5390 			 MRI_TYPE_name[ityp] ) ;
5391 	       EXRETURN ;
5392 
5393 	    } /* end of switch on type */
5394 
5395 	    /* start point must be a 0 (can't fill from an edge) */
5396 
5397 	    if( pl[ix+jy*itop] == 1 ){
5398 	       free(pl) ; XBell(dc->display,100) ; EXRETURN ;
5399 	    }
5400 
5401 	    /* call a routine to fill the array */
5402 
5403 	    DRAW_2dfiller( itop,jtop , ix,jy , pl ) ;
5404 
5405 	    /* all filled points are 2 --> these are the locations to draw */
5406 
5407 	    nfill = 0 ;
5408 	    for( ii=0 ; ii < nij ; ii++ ) nfill += (pl[ii] == 2) ;
5409 	    if( nfill == 0 ){ free(pl) ; XBell(dc->display,100) ; EXRETURN ; }
5410 
5411 	    xyzf = (int *) malloc( sizeof(int) * nfill ) ;
5412 
5413 	    for( nf=0,jj=0 ; jj < jtop ; jj++ ){
5414 	       for( ii=0 ; ii < itop ; ii++ ){
5415 		  if( pl[ii+jj*itop] == 2 )
5416 		     xyzf[nf++] = base + ii*di + jj*dj ;
5417 	       }
5418 	    }
5419 
5420 	    free(pl) ;
5421 	    DRAW_into_dataset( nfill , xyzf,NULL,NULL , NULL ) ;
5422 	    free(xyzf) ;
5423 
5424 	 } /* end of flooding */
5425 
5426       } /* end of dealing with drawn points */
5427       break ;
5428 
5429       /*-- user closed the controller window!? (the fiend) */
5430 
5431       case RECEIVE_CLOSURE:{
5432 	 if( dset != NULL && dset_changed ) XBell(dc->display,100) ; /* protest */
5433 	 DRAW_quit_CB(NULL,NULL,NULL) ;                              /* and die */
5434       }
5435       break ;
5436 
5437       /*-- user altered the controller window!? */
5438 
5439       case RECEIVE_ALTERATION:{
5440 
5441 	 /* if we are already editing a dataset, then
5442 	    check if the grid has changed -- if it has, must quit */
5443 
5444 	 if( dset != NULL ){
5445 	    if( ! EQUIV_DATAXES( im3d->wod_daxes , &dax_save ) ){
5446 	       XBell( dc->display , 100 ) ;    /* feeble protest */
5447 	       DRAW_quit_CB(NULL,NULL,NULL) ;  /* die */
5448 
5449 
5450 		{       /* RCR stuff */
5451 
5452 		    printf("Initializing gRA...\n");
5453 		    gRA.anat  = NULL;
5454 		    gRA.func  = NULL;
5455 		    gRA.adata = NULL;
5456 		    gRA.fdata = NULL;
5457 
5458 		    r_main_cb_quit();
5459 		}
5460 
5461 	       /* less feeble protest */
5462 	       (void) MCW_popup_message( im3d->vwid->top_shell ,
5463 					   "Controller grid was altered!\n"
5464 					   "Editor was forced to quit.\n"
5465 					   "Any un-Saved changes were lost." ,
5466 					 MCW_USER_KILL | MCW_TIMER_KILL ) ;
5467 	    }
5468 	 }
5469       }
5470       break ;
5471 
5472    } /* end of switch on why */
5473 
5474    EXRETURN ;
5475 }
5476 
5477 /*--------------------------------------------------------------------------
5478   Routine to draw into a dataset.
5479   If yd & zd are NULL, then xd is used as the direct 3D array index,
5480     otherwise xd,yd,zd are used as the 3-index.
5481   If var == NULL, then the value_av is used, otherwise the array var[]
5482     will be the source of the data.
5483 ----------------------------------------------------------------------------*/
5484 
DRAW_into_dataset(int np,int * xd,int * yd,int * zd,void * var)5485 static void DRAW_into_dataset( int np , int * xd , int * yd , int * zd , void * var )
5486 {
5487    int   ityp = DSET_BRICK_TYPE(dset,0) ;
5488    float bfac = DSET_BRICK_FACTOR(dset,0) ;
5489    int nx=DSET_NX(dset) , ny=DSET_NY(dset) , nz=DSET_NZ(dset) ,
5490        nxy = nx*ny , nxyz = nxy*nz , ii , ixyz ;
5491    float vload = 0.0 ;
5492    int nbytes ;
5493 
5494    ENTRY("DRAW_into_dataset");
5495 
5496    /* sanity check */
5497 
5498    if( dset==NULL || np <= 0 || xd==NULL ) EXRETURN ;
5499 
5500    /* make space for undo */
5501 
5502    nbytes = np * mri_datum_size((MRI_TYPE)ityp) ; /* bytes needed for save */
5503    if( nbytes > undo_bufsiz ){
5504       if( undo_buf != NULL ) free(undo_buf) ;
5505       undo_buf    = malloc(nbytes) ;
5506       undo_bufsiz = nbytes ;
5507    }
5508    if( np > undo_bufnum ){
5509       if( undo_xyz != NULL ) free(undo_xyz);
5510       undo_xyz    = (int *) malloc(sizeof(int)*np) ;
5511       undo_bufnum = np ;
5512    }
5513 
5514    /* compute (or copy) data index into undo_xyz */
5515 
5516    if( yd == NULL ){                       /* direct supply of index */
5517       memcpy(undo_xyz,xd,sizeof(int)*np) ;
5518    } else {                                /* collapse 3-index into 1 */
5519       for( ii=0 ; ii < np ; ii++ )
5520 	 undo_xyz[ii] = xd[ii] + yd[ii] * nx + zd[ii] * nxy ;
5521    }
5522 
5523    /* actually copy data, based on type */
5524 
5525    if( bfac == 0.0 ) bfac = 1.0 ;
5526    vload = value_float ;
5527 
5528    /* RCR - code for interpolation */
5529    if ( ! gRI.afni_undo &&
5530 	( ( mode_ival == MODE_CURVE ) || ( mode_ival == MODE_CLOSED ) ||
5531 	  ( mode_ival == MODE_CONN_PTS ) )
5532       )
5533    {
5534 	/* insert the points into the interpolation structure */
5535 
5536 	int        count, coord;
5537 	int      * ipA, * ipB, * ipc;
5538 	points_t * Bp, tmpB;
5539 
5540 	if ( gRI.A.used == 0 )  /* if first IP set is empty, use it */
5541 	    Bp = &gRI.A;
5542 	else if ( gRI.B.used == 0 )     /* else, similarly for second       */
5543 	    Bp = &gRI.B;
5544 	else                            /* else, move 2->1 and use second   */
5545 	{
5546 	    tmpB       = gRI.A;         /* swap and empty new one */
5547 	    gRI.A      = gRI.B;
5548 	    gRI.B      = tmpB;
5549 	    gRI.B.used = 0;
5550 
5551 	    Bp = &gRI.B;
5552 	}
5553 
5554 	for ( count = 0; count < np; count++ )
5555 	{
5556 	    coord = undo_xyz[ count ];
5557 
5558 	    if ( coord >= 0 && coord < nxyz )
5559 		r_add_to_boundary( Bp, coord );
5560 	}
5561    }
5562 
5563    switch( ityp ){
5564 
5565       default: fprintf(stderr,"Illegal brick type=%s in AFNI Editor!\n",
5566 		       MRI_TYPE_name[ityp] ) ;
5567       break ;
5568 
5569       case MRI_short:{
5570 	 short * bp  = (short *) DSET_BRICK_ARRAY(dset,0) ;
5571 	 short * up  = (short *) undo_buf ;
5572 	 short * vvv = (short *) var ;
5573 	 short   val = (short)   (value_float/bfac) ;
5574 
5575 	 for( ii=0 ; ii < np ; ii++ ){  /* save into undo buffer */
5576 	    ixyz = undo_xyz[ii] ;
5577 	    up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : 0 ;
5578 	 }
5579 
5580 	 for( ii=0 ; ii < np ; ii++ ){  /* put into dataset */
5581 	    ixyz = undo_xyz[ii] ;
5582 	    if( ixyz >= 0 && ixyz < nxyz )
5583 	       bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ;
5584 	 }
5585       }
5586       break ;
5587 
5588       case MRI_byte:{
5589 	 byte * bp  = (byte *) DSET_BRICK_ARRAY(dset,0) ;
5590 	 byte * up  = (byte *) undo_buf ;
5591 	 byte * vvv = (byte *) var ;
5592 	 byte   val = (byte)   (value_float/bfac) ;
5593 
5594 	 for( ii=0 ; ii < np ; ii++ ){
5595 	    ixyz = undo_xyz[ii] ;
5596 	    up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : 0 ;
5597 	 }
5598 	 for( ii=0 ; ii < np ; ii++ ){
5599 	    ixyz = undo_xyz[ii] ;
5600 	    if( ixyz >= 0 && ixyz < nxyz )
5601 	       bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ;
5602 	 }
5603       }
5604       break ;
5605 
5606       case MRI_float:{
5607 	 float * bp  = (float *) DSET_BRICK_ARRAY(dset,0) ;
5608 	 float * up  = (float *) undo_buf ;
5609 	 float * vvv = (float *) var ;
5610 	 float   val = (value_float/bfac) ;
5611 
5612 	 for( ii=0 ; ii < np ; ii++ ){
5613 	    ixyz = undo_xyz[ii] ;
5614 	    up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : 0.0 ;
5615 	 }
5616 	 for( ii=0 ; ii < np ; ii++ ){
5617 	    ixyz = undo_xyz[ii] ;
5618 	    if( ixyz >= 0 && ixyz < nxyz )
5619 	       bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ;
5620 	 }
5621       }
5622       break ;
5623 
5624       case MRI_complex:{
5625 	 complex * bp  = (complex *) DSET_BRICK_ARRAY(dset,0) ;
5626 	 complex * up  = (complex *) undo_buf ;
5627 	 complex * vvv = (complex *) var ;
5628 	 complex   val ;
5629 	 static complex cxzero = { 0.0 , 0.0 } ;
5630 
5631 	 val = CMPLX( (value_float/bfac) , 0.0 ) ;
5632 
5633 	 for( ii=0 ; ii < np ; ii++ ){
5634 	    ixyz = undo_xyz[ii] ;
5635 	    up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : cxzero ;
5636 	 }
5637 	 for( ii=0 ; ii < np ; ii++ ){
5638 	    ixyz = undo_xyz[ii] ;
5639 	    if( ixyz >= 0 && ixyz < nxyz )
5640 	       bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ;
5641 	 }
5642       }
5643       break ;
5644 
5645    } /* end of switch on brick type */
5646 
5647    /* recompute statistics, if the loaded value is big or small */
5648 
5649    if( !ISVALID_STATISTIC(dset->stats)   ||
5650        vload > dset->stats->bstat[0].max ||
5651        vload < dset->stats->bstat[0].min   ) THD_load_statistics( dset ) ;
5652 
5653    /* now redisplay dataset, in case anyone is looking at it */
5654 
5655    PLUTO_dset_redisplay( dset ) ;
5656 
5657    undo_bufuse  = np ;
5658    dset_changed = 1 ;
5659    SENSITIZE(save_pb,1) ;
5660    SENSITIZE(choose_pb,0) ;
5661    SENSITIZE(undo_pb,1) ;
5662 
5663    EXRETURN ;
5664 }
5665 
5666 /*---------------------------------------------------------------------------
5667    Flood filling a byte array:
5668      nx = 1st dimension
5669      ny = 2nd dimension
5670      ix = start point
5671      jy = end point
5672      ar = array, with 0's everwhere except 1's as barriers to flooding
5673 
5674    All filled points (starting with ix,jy) will get the value 2.
5675 -----------------------------------------------------------------------------*/
5676 
DRAW_2dfiller(int nx,int ny,int ix,int jy,byte * ar)5677 static void DRAW_2dfiller( int nx , int ny , int ix , int jy , byte * ar )
5678 {
5679    int ii,jj , ip,jp , num ;
5680 
5681    ENTRY("DRAW_2dfiller");
5682 
5683 #define AR(i,j) ar[(i)+(j)*nx]
5684 
5685    /* fill out in cross from 1st point */
5686 
5687    ip = ix ; jp = jy ; AR(ip,jp) = 2 ;
5688 
5689    for( ii=ip+1; ii < nx && AR(ii,jp) == 0; ii++ ) AR(ii,jp) = 2;
5690    for( ii=ip-1; ii >= 0 && AR(ii,jp) == 0; ii-- ) AR(ii,jp) = 2;
5691    for( jj=jp+1; jj < ny && AR(ip,jj) == 0; jj++ ) AR(ip,jj) = 2;
5692    for( jj=jp-1; jj >= 0 && AR(ip,jj) == 0; jj-- ) AR(ip,jj) = 2;
5693 
5694    /* brute force repetition of the cross technique */
5695 
5696    do {
5697       num = 0 ;
5698       for( jp=0 ; jp < ny ; jp++ ){
5699 	 for( ip=0 ; ip < nx ; ip++ ){
5700 	    if( AR(ip,jp) == 2 ){
5701 	       for( ii=ip+1; ii < nx && AR(ii,jp) == 0; ii++ ){ AR(ii,jp) = 2; num++; }
5702 	       for( ii=ip-1; ii >= 0 && AR(ii,jp) == 0; ii-- ){ AR(ii,jp) = 2; num++; }
5703 	       for( jj=jp+1; jj < ny && AR(ip,jj) == 0; jj++ ){ AR(ip,jj) = 2; num++; }
5704 	       for( jj=jp-1; jj >= 0 && AR(ip,jj) == 0; jj-- ){ AR(ip,jj) = 2; num++; }
5705 	    }
5706 	 }
5707       }
5708    } while( num > 0 ) ;
5709 
5710    EXRETURN ;
5711 }
5712 
5713