Skip to content

AFNI/NIfTI Server

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

Doxygen Source Code Documentation


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

plug_drawdset.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002    Major portions of this software are copyrighted by the Medical College
00003    of Wisconsin, 1994-2000, and are released under the Gnu General Public
00004    License, Version 2.  See the file README.Copyright for details.
00005 ******************************************************************************/
00006 
00007 #include "afni.h"
00008 
00009 #ifndef ALLOW_PLUGINS
00010 #  error "Plugins not properly set up -- see machdep.h"
00011 #endif
00012 
00013 /***********************************************************************
00014   Plugin to draw values into a dataset.
00015   Makes a custom interface.
00016 ************************************************************************/
00017 
00018 /*---------- prototypes for internal routines ----------*/
00019 
00020 char * DRAW_main( PLUGIN_interface * ) ;
00021 
00022 void DRAW_make_widgets(void) ;
00023 
00024 void DRAW_done_CB  ( Widget , XtPointer , XtPointer ) ;
00025 void DRAW_undo_CB  ( Widget , XtPointer , XtPointer ) ;
00026 void DRAW_redo_CB  ( Widget , XtPointer , XtPointer ) ;  /* 19 Nov 2003 */
00027 void DRAW_help_CB  ( Widget , XtPointer , XtPointer ) ;
00028 void DRAW_quit_CB  ( Widget , XtPointer , XtPointer ) ;
00029 void DRAW_save_CB  ( Widget , XtPointer , XtPointer ) ;
00030 void DRAW_saveas_CB( Widget , XtPointer , XtPointer ) ;  /* 24 Sep 2001 */
00031 void DRAW_choose_CB( Widget , XtPointer , XtPointer ) ;
00032 void DRAW_color_CB ( MCW_arrowval * , XtPointer ) ;
00033 void DRAW_mode_CB  ( MCW_arrowval * , XtPointer ) ;
00034 void DRAW_value_CB ( MCW_arrowval * , XtPointer ) ;
00035 void DRAW_fillin_CB( Widget , XtPointer , XtPointer ) ; /* 19 Mar 2001 */
00036 
00037 void DRAW_ttatlas_CB( Widget , XtPointer , XtPointer ) ; /* 22 Aug 2001 */
00038 
00039 void DRAW_label_CB( Widget , XtPointer , XtPointer ) ; /* 15 Oct 2003 */
00040 void DRAW_label_EV( Widget , XtPointer , XEvent * , Boolean * ) ;
00041 void DRAW_attach_dtable( Dtable *, char *, THD_3dim_dataset * ) ;
00042 
00043 void DRAW_receiver( int , int , void * , void * ) ;
00044 int  DRAW_into_dataset( int , int * , int * , int * , void * ) ;
00045 void DRAW_finalize_dset_CB( Widget , XtPointer , MCW_choose_cbs * ) ;
00046 void DRAW_2dfiller( int nx , int ny , int ix , int jy , byte * ar ) ;
00047 
00048 void DRAW_saveas_finalize_CB( Widget , XtPointer , MCW_choose_cbs * ) ;
00049 
00050 static void DRAW_2D_expand( int, int *, int *, int *, int, int *, int ** ) ;  /* 07 Oct 2002 */
00051 static void DRAW_3D_expand( int, int *, int *, int *, int, int *, int ** ) ;  /* 07 Oct 2002 */
00052 
00053 static void DRAW_2D_circle( int, int *, int *, int *, int, int *, int ** ) ;  /* 16 Oct 2002 */
00054 static void DRAW_3D_sphere( int, int *, int *, int *, int, int *, int ** ) ;  /* 16 Oct 2002 */
00055 
00056 #define USE_COLLAPSAR
00057 #ifdef  USE_COLLAPSAR
00058 static void DRAW_collapsar( int * , int * ) ;                                 /* 21 Oct 2002 */
00059 #endif
00060 
00061 static PLUGIN_interface * plint = NULL ;
00062 
00063 static int infill_mode = 0 ;
00064 
00065 void DRAW_set_value_label(void) ;
00066 char * DRAW_value_string( float val ) ;
00067 
00068 /***********************************************************************
00069    Set up the interface to the user.  Note that we bypass the
00070    normal interface creation, and simply have the menu selection
00071    directly call the main function, which will create a custom
00072    set of interface widgets.
00073 ************************************************************************/
00074 
00075 DEFINE_PLUGIN_PROTOTYPE
00076 
00077 PLUGIN_interface * PLUGIN_init( int ncall )
00078 {
00079 
00080    if( ncall > 0 ) return NULL ;  /* only one interface */
00081 
00082    plint = PLUTO_new_interface( "Draw Dataset" , NULL , NULL ,
00083                                 PLUGIN_CALL_IMMEDIATELY , DRAW_main ) ;
00084 
00085    PLUTO_add_hint( plint , "Interactive Dataset Editor" ) ;
00086 
00087    PLUTO_set_sequence( plint , "A:olddset:editor" ) ;
00088 
00089    return plint ;
00090 }
00091 
00092 /***************************************************************************
00093   Will be called from AFNI when user selects from Plugins menu.
00094 ****************************************************************************/
00095 
00096 /* Interface widgets */
00097 
00098 static Widget shell=NULL , rowcol , info_lab , choose_pb ;
00099 static Widget done_pb, undo_pb,redo_pb, help_pb, quit_pb, save_pb, saveas_pb ;
00100 static MCW_arrowval *value_av , *color_av , *mode_av ;
00101 static MCW_arrowval *rad_av ;                         /* 16 Oct 2002 */
00102 static Widget label_textf , label_label ;             /* 15 Oct 2003 */
00103 
00104 #if 0
00105 # define ENABLE_rad_av \
00106    AV_SENSITIZE( rad_av , (mode_ival >= FIRST_RAD_MODE && mode_ival <= LAST_RAD_MODE) )
00107 #else
00108 # define ENABLE_rad_av                                                   \
00109    do{ if( mode_ival >= FIRST_RAD_MODE && mode_ival <= LAST_RAD_MODE )  \
00110          XtManageChild( rad_av->wrowcol ) ;                             \
00111        else                                                             \
00112          XtUnmanageChild( rad_av->wrowcol ) ;                           \
00113    } while(0)
00114 #endif
00115 
00116 static MCW_arrowval * fillin_dir_av , * fillin_gap_av ; /* 19 Mar 2001 */
00117 static Widget fillin_doit_pb ;
00118 
00119 static Widget         ttatlas_rowcol=NULL ;             /* 22 Aug 2001 */
00120 static MCW_arrowval * ttatlas_region_av ,
00121                     * ttatlas_hemisphere_av ;
00122 static Widget         ttatlas_actar ;
00123 
00124 #define HAVE_TTATLAS (ttatlas_rowcol != NULL)
00125 
00126 #define NHEMI       3
00127 #define HEMI_LEFT   "Left only"
00128 #define HEMI_RIGHT  "Right only"
00129 #define HEMI_BOTH   "Both"
00130 static char *HEMI_strings[NHEMI] = { HEMI_LEFT , HEMI_RIGHT , HEMI_BOTH } ;
00131 
00132 #define NUM_TTATLAS_ACT         2
00133 #define TTATLAS_overwrite_label "Load: OverWrite"
00134 #define TTATLAS_infill_label    "Load: InFill"
00135 
00136 static MCW_action_item TTATLAS_act[] = {
00137  { TTATLAS_overwrite_label , DRAW_ttatlas_CB, NULL,NULL, NULL, 0 } ,
00138  { TTATLAS_infill_label    , DRAW_ttatlas_CB, NULL,NULL, NULL, 0 }
00139 } ;
00140 
00141 typedef struct {
00142    int reg_num ;                 /* number of regions               */
00143    char *reg_label [TTO_COUNT] ; /* region labels                   */
00144    short reg_tto   [TTO_COUNT] ; /* index into afni.h TTO_list      */
00145    short reg_ttbrik[TTO_COUNT] ; /* which sub-brick in TTatlas+tlrc */
00146    short reg_ttval [TTO_COUNT] ; /* what value in TTatlas+tlrc      */
00147 } ttatlas_compendium ;
00148 
00149 static ttatlas_compendium *ttatlas_list=NULL ;
00150 
00151 /* 24 Sep 2001: stuff for Copy on input */
00152 
00153 static MCW_bbox *copy_bbox ;
00154 static MCW_arrowval *copy_mode_av , *copy_type_av , *copy_datum_av ;
00155 
00156 void DRAW_copy_bbox_CB( Widget , XtPointer , XtPointer ) ;
00157 THD_3dim_dataset * DRAW_copy_dset( THD_3dim_dataset *, int,int,int ) ;
00158 
00159 /* Other data */
00160 
00161 #define MODE_CURVE       0
00162 #define MODE_CLOSED      1
00163 #define MODE_POINTS      2
00164 #define MODE_FLOOD_VAL   3
00165 #define MODE_FLOOD_NZ    4
00166 #define MODE_FLOOD_ZERO  5   /* 30 Jan 1999 */
00167 #define MODE_ZERO_VAL    6   /* 31 Jan 1999 */
00168 #define MODE_FLOOD_VZ    7   /* 30 Apr 2002 */
00169 #define MODE_FILLED      8   /* 25 Sep 2001 */
00170 
00171 #define MODE_2D_NN1      9   /* 07 Oct 2002 */
00172 #define MODE_2D_NN2     10
00173 #define MODE_2D_NN3     11
00174 #define MODE_2D_NN4     12
00175 #define MODE_2D_NN5     13
00176 
00177 #define MODE_3D_NN1     14
00178 #define MODE_3D_NN2     15
00179 #define MODE_3D_NN3     16
00180 #define MODE_3D_NN4     17
00181 #define MODE_3D_NN5     18
00182 #define MODE_3D_NN6     19
00183 #define MODE_3D_5x5     20   /* 08 Oct 2002 */
00184 
00185 #define MODE_2D_CIRC    21   /* 16 Oct 2002 */
00186 #define MODE_3D_SPHR    22   /* 16 Oct 2002 */
00187 
00188 #define FIRST_2D_MODE   MODE_2D_NN1
00189 #define LAST_2D_MODE    MODE_2D_NN5
00190 
00191 #define FIRST_3D_MODE   MODE_3D_NN1
00192 #define LAST_3D_MODE    MODE_3D_5x5
00193 
00194 #define FIRST_RAD_MODE  MODE_2D_CIRC
00195 #define LAST_RAD_MODE   MODE_3D_SPHR
00196 
00197 static char * mode_strings[] = {
00198   "Open Curve"       ,                 /* MODE_CURVE      */
00199   "Closed Curve"     ,                 /* MODE_CLOSED     */
00200   "Points"           ,                 /* MODE_POINTS     */
00201   "Flood->Value"     ,                 /* MODE_FLOOD_VAL  */
00202   "Flood->Nonzero"   ,                 /* MODE_FLOOD_NZ   */
00203   "Flood->Zero"      ,                 /* MODE_FLOOD_ZERO */
00204   "Zero->Value"      ,                 /* MODE_ZERO_VAL   */
00205   "Flood->Val/Zero"  ,                 /* MODE_FLOOD_VZ   */
00206   "Filled Curve"     ,                 /* MODE_FILLED     */
00207 
00208   " 2D Nbhd: 1st NN" ,                 /* 07 Oct 2002 */
00209   " 2D Nbhd: 2nd NN" ,
00210   " 2D Nbhd: 3rd NN" ,
00211   " 2D Nbhd: 4th NN" ,
00212   " 2D Nbhd: 5th NN" ,
00213 
00214   "*3D Nbhd: 1st NN" ,
00215   "*3D Nbhd: 2nd NN" ,
00216   "*3D Nbhd: 3rd NN" ,
00217   "*3D Nbhd: 4th NN" ,
00218   "*3D Nbhd: 5th NN" ,
00219   "*3D Nbhd: 6th NN" ,
00220   "*3D Nbhd: 5x5x5"  ,
00221 
00222   " 2D Circle"       ,                 /* 16 Oct 2002 */
00223   " 3D Sphere"
00224 } ;
00225 
00226 static int  mode_width[] = {    /* 08 Oct 2002: line width for button2 drawing */
00227   2,2 , 0,0,0,0,0,0 , 2 ,
00228   3,3,5,5,7 ,
00229   3,3,3,5,5,5,5 ,
00230   2,2
00231 } ;
00232 
00233 static int    mode_ints[] = {
00234   DRAWING_LINES  , DRAWING_FILL   , DRAWING_POINTS ,
00235   DRAWING_POINTS , DRAWING_POINTS , DRAWING_POINTS , DRAWING_POINTS ,
00236   DRAWING_POINTS ,
00237   DRAWING_FILL   ,
00238   DRAWING_LINES  , DRAWING_LINES  , DRAWING_LINES  , DRAWING_LINES  , DRAWING_LINES  ,
00239   DRAWING_LINES  , DRAWING_LINES  , DRAWING_LINES  , DRAWING_LINES  , DRAWING_LINES  ,
00240   DRAWING_LINES  , DRAWING_LINES  ,
00241   DRAWING_LINES  , DRAWING_LINES
00242 } ;
00243 
00244 #define NUM_modes (sizeof(mode_ints)/sizeof(int))
00245 
00246 #define NFILLIN_DIR 3
00247 static char * fillin_dir_strings[NFILLIN_DIR] = { "A-P" , "I-S" , "R-L" } ;
00248 #define NFILLIN_GAP 9
00249 
00250 static MCW_DC * dc ;                 /* display context */
00251 static Three_D_View * im3d ;         /* AFNI controller */
00252 static THD_3dim_dataset * dset ;     /* The dataset!    */
00253 static MCW_idcode         dset_idc ; /* 31 Mar 1999     */
00254 
00255 static Dtable *vl_dtable=NULL ;      /* 17 Oct 2003     */
00256 
00257 static int   color_index = 1 ;               /* from color_av */
00258 static int   mode_ival   = MODE_FILLED ;
00259 static int   mode_index  = DRAWING_FILL ;    /* from mode_av  */
00260 static int   value_int   = 1 ;               /* from value_av */
00261 static float value_float = 1.0 ;             /* ditto         */
00262 
00263 static int editor_open  = 0 ;
00264 static int dset_changed = 0 ;
00265 static int recv_open    = 0 ;
00266 static int recv_key     = -1;
00267 
00268 /****** 19 Nov 2003: new stuff for multiple undo/redo ******/
00269 
00270 typedef struct {   /* structure holds one drawing operation */
00271   int npt , btyp ; /* number of data points, type of data */
00272   int *xyz ;       /* 1D index into dataset array */
00273   void *buf ;      /* data from dataset array */
00274 } dobuf ;
00275 
00276   /* macro to create an empty buffer */
00277 
00278 #define CREATE_DOBUF(db,np,ip)                                       \
00279  do{ db      = (dobuf *)calloc(1 ,sizeof(dobuf)) ;                   \
00280      db->xyz = (int *)  calloc(np,sizeof(int)) ;                     \
00281      db->buf = (void *) calloc(np,mri_datum_size(ip)) ;              \
00282      db->npt = np ; db->btyp = ip ;                                  \
00283  } while(0)
00284 
00285   /* macro to delete a buffer from the Macrocosmic All */
00286 
00287 #define DESTROY_DOBUF(db)  do{ if( db != NULL ){                     \
00288                                 if( db->xyz != NULL ) free(db->xyz); \
00289                                 if( db->buf != NULL ) free(db->buf); \
00290                                 free(db) ;                           \
00291                            }} while(0)
00292 
00293   /* amount of memory used by a buffer */
00294 
00295 #define SIZEOF_DOBUF(db)                                             \
00296   ( db->npt * ( sizeof(int) + mri_datum_size(db->btyp) ) )
00297 
00298 static int undo_num       = 0 ;     /* depth of undo stack */
00299 static int redo_num       = 0 ;     /* depth of redo stack */
00300 static dobuf **undo_stack = NULL ;  /* undo stack */
00301 static dobuf **redo_stack = NULL ;  /* redo stack */
00302 static int undo_how       = 0 ;     /* where to save undo info */
00303 
00304 static void DRAW_undo_sizecheck(void) ;  /* check/limit undo stack size */
00305 
00306 static void DRAW_undo_butlab( Widget w , int ) ;  /* label undo/redo button */
00307 
00308 #define UNDO_button_labelize DRAW_undo_butlab(undo_pb,undo_num)
00309 #define REDO_button_labelize DRAW_undo_butlab(redo_pb,redo_num)
00310 
00311   /* this macro erases the undo stack */
00312 
00313 #define CLEAR_UNDOBUF                                                \
00314    do{ if( undo_num > 0 || undo_stack != NULL ){                     \
00315         int ii ;                                                     \
00316         for( ii=0 ; ii < undo_num ; ii++ )                           \
00317           DESTROY_DOBUF( undo_stack[ii] ) ;                          \
00318         if( undo_stack != NULL ) free( undo_stack ) ;                \
00319         undo_num = 0 ; undo_stack = NULL ;                           \
00320        }                                                             \
00321        UNDO_button_labelize ;                                        \
00322    } while(0)
00323 
00324   /* this macro erases the redo stack */
00325 
00326 #define CLEAR_REDOBUF                                                \
00327    do{ if( redo_num > 0 || redo_stack != NULL ){                     \
00328         int ii ;                                                     \
00329         for( ii=0 ; ii < redo_num ; ii++ )                           \
00330           DESTROY_DOBUF( redo_stack[ii] ) ;                          \
00331         if( redo_stack != NULL )free( redo_stack ) ;                 \
00332         redo_num = 0 ; redo_stack = NULL ;                           \
00333        }                                                             \
00334        REDO_button_labelize ;                                        \
00335    } while(0)
00336 
00337   /* this macro erases both stacks */
00338 
00339 #define CLEAR_UNREDOBUF                                              \
00340    do{ CLEAR_UNDOBUF ; CLEAR_REDOBUF ; undo_how = 0 ; } while(0)
00341 
00342 /******/
00343 
00344 static THD_dataxes dax_save ;    /* save this for later reference */
00345 
00346 static int old_stroke_autoplot = 0 ;  /* 27 Oct 2003 */
00347 
00348 char * DRAW_main( PLUGIN_interface * plint )
00349 {
00350    XmString xstr ;
00351 
00352    /*-- sanity checks --*/
00353 
00354    if( ! IM3D_OPEN(plint->im3d) )
00355       return " \n AFNI Controller\nnot opened?! \n " ;
00356 
00357    if( editor_open ){
00358       XtMapWidget(shell) ;
00359       XRaiseWindow( XtDisplay(shell) , XtWindow(shell) ) ;
00360       return NULL ;
00361    }
00362 
00363    im3d = plint->im3d ;  /* save for local use */
00364 
00365    /*-- create widgets, first time through --*/
00366 
00367    if( shell == NULL ){
00368       dc = im3d->dc ;        /* save this too */
00369       DRAW_make_widgets() ;
00370       PLUTO_set_topshell( plint , shell ) ;  /* 22 Sep 2000 */
00371       RWC_visibilize_widget( shell ) ;       /* 27 Sep 2000 */
00372    }
00373 
00374    /*-- set titlebar --*/
00375 
00376    { char ttl[PLUGIN_STRING_SIZE] ;
00377      sprintf(ttl , "AFNI Editor %s" , AFNI_controller_label(im3d) ) ;
00378      XtVaSetValues( shell , XmNtitle , ttl , NULL ) ;
00379    }
00380 
00381    /*-- set the info label --*/
00382 
00383    xstr = XmStringCreateLtoR( "[No dataset]" ,
00384                               XmFONTLIST_DEFAULT_TAG ) ;
00385    XtVaSetValues( info_lab , XmNlabelString , xstr , NULL ) ;
00386    XmStringFree(xstr) ;
00387 
00388    /*-- 22 Aug 2001: perhaps allow TT Atlas stuff --*/
00389 
00390    if( HAVE_TTATLAS )
00391       XtSetSensitive( ttatlas_rowcol , CAN_TALTO(im3d) ) ;
00392 
00393    /*-- pop the widget up --*/
00394 
00395    XtMapWidget(shell) ;
00396    PLUTO_cursorize(shell) ;
00397 
00398    /*-- misc initialization --*/
00399 
00400    dset         = NULL ;   /* not editing anything   */
00401    dset_changed = 0 ;      /* not yet changed */
00402    editor_open  = 1 ;      /* editor is now open for business */
00403    recv_open    = 0 ;      /* receiver is not yet open */
00404    recv_key     = -1;      /* and has no identifier key */
00405 
00406    if( vl_dtable != NULL ){   /* 20 Oct 2003 */
00407      destroy_Dtable(vl_dtable) ; vl_dtable = NULL ;
00408    }
00409 
00410    SENSITIZE(save_pb,0) ; SENSITIZE(saveas_pb,0) ;
00411    SENSITIZE(choose_pb,1) ;
00412 
00413    /* 19 Nov 2003: new undo/redo stuff */
00414 
00415    undo_num = redo_num = undo_how = 0 ;
00416    undo_stack = redo_stack = NULL ;
00417    UNDO_button_labelize ; REDO_button_labelize ;
00418 
00419    old_stroke_autoplot = AFNI_yesenv("AFNI_STROKE_AUTOPLOT") ;
00420    if( old_stroke_autoplot ) putenv("AFNI_STROKE_AUTOPLOT=NO") ;
00421 
00422    return NULL ;
00423 }
00424 
00425 /*------------------------------------------------------------------------
00426   Make the control popup for this thing
00427 --------------------------------------------------------------------------*/
00428 
00429 /*-- structures defining action buttons (at bottom of popup) --*/
00430 
00431 #define NACT 7  /* number of action buttons */
00432 
00433 static MCW_action_item DRAW_actor[NACT] = {
00434  {"Undo[0]",DRAW_undo_CB,NULL,
00435   "Undoes previous draw\naction, if possible","Undo last change",0} ,
00436 
00437  {"Redo[0]",DRAW_redo_CB,NULL,
00438   "Redoes previous undone\naction, if possible","Redo last undo",0} ,
00439 
00440  {"Help",DRAW_help_CB,NULL,
00441   "Displays more help" , "Displays more help",0} ,
00442 
00443  {"Quit",DRAW_quit_CB,NULL,
00444   "Discard edits since last Save\nand close Editor" ,
00445    "Discard edits and close",0} ,
00446 
00447  {"Save",DRAW_save_CB,NULL,
00448   "Save edits to disk\nand continue" , "Save to disk and continue",0} ,
00449 
00450  {"SaveAs",DRAW_saveas_CB,NULL,                        /* 24 Sep 2001 */
00451   "Save edits to disk\nin a new dataset\nand continue" ,
00452   "Save to disk in new dataset, continue",0} ,
00453 
00454  {"Done",DRAW_done_CB,NULL,
00455   "Save edits to disk\nand close Editor" , "Save and close",1}
00456 } ;
00457 
00458 void DRAW_make_widgets(void)
00459 {
00460    XmString xstr ;
00461 
00462    /*** top level shell for window manager ***/
00463 
00464    shell =
00465       XtVaAppCreateShell(
00466            "AFNI" , "AFNI" , topLevelShellWidgetClass , dc->display ,
00467 
00468            XmNtitle             , "AFNI Editor" , /* top of window */
00469            XmNiconName          , "Editor"      , /* label on icon */
00470            XmNdeleteResponse    , XmDO_NOTHING  , /* deletion handled below */
00471            XmNallowShellResize  , True ,          /* let code resize shell? */
00472            XmNmappedWhenManaged , False ,         /* must map it manually */
00473            XmNinitialResourcesPersistent , False ,
00474       NULL ) ;
00475 
00476    DC_yokify( shell , dc ) ; /* 14 Sep 1998 */
00477 
00478    if( afni48_good )             /* set icon pixmap */
00479       XtVaSetValues( shell ,
00480                         XmNiconPixmap , afni48_pixmap ,
00481                      NULL ) ;
00482 
00483    if( MCW_isitmwm(shell) )      /* remove some MWM functions */
00484       XtVaSetValues( shell ,
00485                        XmNmwmFunctions ,
00486                        MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE ,
00487                      NULL ) ;
00488 
00489    XmAddWMProtocolCallback(      /* make "Close" window menu work */
00490            shell ,
00491            XmInternAtom( dc->display , "WM_DELETE_WINDOW" , False ) ,
00492            DRAW_quit_CB , (XtPointer) plint ) ;
00493 
00494    /*** rowcolumn widget to hold all user interface stuff ***/
00495 
00496    rowcol = XtVaCreateWidget(
00497              "AFNI" , xmRowColumnWidgetClass , shell ,
00498                 XmNpacking     , XmPACK_TIGHT ,
00499                 XmNorientation , XmVERTICAL ,
00500                 XmNtraversalOn , False ,
00501                 XmNinitialResourcesPersistent , False ,
00502              NULL ) ;
00503 
00504    /*** label at top to let user know who we are ***/
00505 
00506    xstr = XmStringCreateLtoR( "[No dataset]" ,
00507                               XmFONTLIST_DEFAULT_TAG ) ;
00508    info_lab = XtVaCreateManagedWidget(
00509                  "AFNI" , xmLabelWidgetClass , rowcol ,
00510                     XmNlabelString , xstr ,
00511                     XmNinitialResourcesPersistent , False ,
00512                  NULL ) ;
00513    XmStringFree(xstr) ;
00514    MCW_register_help( info_lab , "Shows dataset being edited" ) ;
00515    MCW_register_hint( info_lab , "Shows dataset being edited" ) ;
00516 
00517    /*** separator for visual neatness ***/
00518 
00519    (void) XtVaCreateManagedWidget(
00520              "AFNI" , xmSeparatorWidgetClass , rowcol ,
00521                 XmNseparatorType , XmDOUBLE_LINE ,
00522                 XmNinitialResourcesPersistent , False ,
00523              NULL ) ;
00524 
00525    /*-- 24 Sep 2001: Copy mode stuff [moved up 06 Oct 2002] --*/
00526 
00527    { Widget rc ;
00528      static char *cbox_label[1]   = { "Copy Dataset" } ;
00529      static char *cmode_label[2]  = { "Data"  , "Zero" } ;
00530      static char *ctype_label[3]  = { "As Is" , "Func" , "Anat" } ;
00531      static char *cdatum_label[4] = { "As Is" , "Byte" , "Short" , "Float" } ;
00532 
00533      /*** rowcol to hold Copy widgets ***/
00534 
00535      rc = XtVaCreateWidget( "AFNI" , xmRowColumnWidgetClass , rowcol ,
00536                               XmNpacking      , XmPACK_TIGHT ,
00537                               XmNorientation  , XmHORIZONTAL ,
00538                               XmNmarginHeight , 0 ,
00539                               XmNmarginWidth  , 0 ,
00540                               XmNspacing      , 0 ,
00541                               XmNinitialResourcesPersistent , False ,
00542                               XmNtraversalOn , False ,
00543                            NULL ) ;
00544 
00545      /*** button box to turn copy mode on or off ***/
00546 
00547      copy_bbox = new_MCW_bbox( rc, 1,cbox_label,
00548                                MCW_BB_check,MCW_BB_noframe, DRAW_copy_bbox_CB,NULL ) ;
00549 
00550      MCW_reghint_children( copy_bbox->wrowcol ,
00551                            "Make copy of dataset on input" ) ;
00552      MCW_reghelp_children( copy_bbox->wrowcol ,
00553                            "Make copy of dataset on input?" ) ;
00554 
00555      /*** arrowvals to let user choose Copy method ***/
00556 
00557      copy_mode_av = new_MCW_optmenu( rc , NULL ,
00558                                      0 , 1 , 1 , 0 , NULL,NULL ,
00559                                      MCW_av_substring_CB , cmode_label ) ;
00560 
00561      MCW_reghint_children( copy_mode_av->wrowcol ,
00562                            "How to copy values from dataset" ) ;
00563      MCW_reghelp_children( copy_mode_av->wrowcol ,
00564                            "How to copy values from dataset:\n"
00565                            "Data => use input dataset values\n"
00566                            "Zero => fill dataset with zeros" ) ;
00567 
00568      copy_type_av = new_MCW_optmenu( rc , NULL ,
00569                                      0 , 2 , 1 , 0 , NULL,NULL ,
00570                                      MCW_av_substring_CB , ctype_label ) ;
00571 
00572      MCW_reghint_children( copy_type_av->wrowcol ,
00573                            "Copy is Functional overlay or Anatomical underlay" ) ;
00574      MCW_reghelp_children( copy_type_av->wrowcol ,
00575                            "Copy will be Functional overlay\n"
00576                            "or will be Anatomical underlay" ) ;
00577 
00578      copy_datum_av= new_MCW_optmenu( rc , NULL ,
00579                                      0 , 3 , 0 , 0 , NULL,NULL ,
00580                                      MCW_av_substring_CB , cdatum_label ) ;
00581 
00582      MCW_reghint_children( copy_datum_av->wrowcol ,
00583                            "Data storage type for copy" ) ;
00584      MCW_reghelp_children( copy_datum_av->wrowcol ,
00585                            "Data storage type for copy:\n"
00586                            "As Is => use data type in input dataset\n"
00587                            "Byte  => store new dataset as bytes\n"
00588                            "Short => store new dataset as shorts\n"
00589                            "Float => store new dataset as floats"   ) ;
00590 
00591      AV_SENSITIZE( copy_mode_av , False ) ;
00592      AV_SENSITIZE( copy_type_av , False ) ;
00593      AV_SENSITIZE( copy_datum_av, False ) ;
00594 
00595      XtManageChild(rc) ;
00596 
00597    } /* end of Copy mode stuff */
00598 
00599    /*** button to let user choose dataset to edit ***/
00600 
00601    xstr = XmStringCreateLtoR( "Choose Dataset on Which to Draw" , XmFONTLIST_DEFAULT_TAG ) ;
00602    choose_pb = XtVaCreateManagedWidget(
00603                   "AFNI" , xmPushButtonWidgetClass , rowcol ,
00604                      XmNlabelString , xstr ,
00605                      XmNtraversalOn , False ,
00606                      XmNinitialResourcesPersistent , False ,
00607                   NULL ) ;
00608    XmStringFree(xstr) ;
00609    XtAddCallback( choose_pb, XmNactivateCallback, DRAW_choose_CB, NULL ) ;
00610    MCW_register_help( choose_pb ,
00611                       "Use this to popup a\n"
00612                       "'chooser' that lets\n"
00613                       "you select which\n"
00614                       "dataset to edit."
00615                     ) ;
00616    MCW_register_hint( choose_pb , "Popup a dataset chooser" ) ;
00617 
00618    /*** separator for visual neatness ***/
00619 
00620    (void) XtVaCreateManagedWidget(
00621                "AFNI" , xmSeparatorWidgetClass , rowcol ,
00622                   XmNseparatorType , XmDOUBLE_LINE ,
00623                   XmNinitialResourcesPersistent , False ,
00624                NULL ) ;
00625 
00626    /***  arrowval to choose value that is drawn into dataset voxels  ***/
00627 
00628    { Widget rc ;
00629 
00630      rc = XtVaCreateWidget( "AFNI" , xmRowColumnWidgetClass , rowcol ,
00631                        XmNpacking      , XmPACK_TIGHT ,
00632                        XmNorientation  , XmHORIZONTAL ,
00633                        XmNmarginHeight , 0 ,
00634                        XmNmarginWidth  , 0 ,
00635                        XmNspacing      , 0 ,
00636                        XmNinitialResourcesPersistent , False ,
00637                        XmNtraversalOn , False ,
00638                     NULL ) ;
00639 
00640      value_av = new_MCW_arrowval( rc , "Value " ,
00641                                   MCW_AV_downup , -32767,32767,value_int ,
00642                                   MCW_AV_editext , 0 ,
00643                                   DRAW_value_CB , NULL , NULL,NULL ) ;
00644 
00645      MCW_reghelp_children( value_av->wrowcol ,
00646                            "Use this to set the value that\n"
00647                            "will be drawn into the dataset\n"
00648                            "using mouse button 2."
00649                          ) ;
00650      MCW_reghint_children( value_av->wrowcol , "Goes into dataset voxels" ) ;
00651 
00652      /*-- 15 Oct 2003: Label for the value --*/
00653 
00654      xstr = XmStringCreateLtoR( " Label" , XmFONTLIST_DEFAULT_TAG ) ;
00655      label_label = XtVaCreateManagedWidget(
00656                      "dialog" , xmLabelWidgetClass , rc ,
00657                        XmNlabelString   , xstr  ,
00658                        XmNrecomputeSize , False ,
00659                        XmNmarginWidth   , 0     ,
00660                        XmNinitialResourcesPersistent , False ,
00661                      NULL ) ;
00662      XmStringFree(xstr) ;
00663 
00664      label_textf = XtVaCreateManagedWidget(
00665                        "dialog" , xmTextFieldWidgetClass , rc ,
00666                            XmNcolumns      , 19 ,
00667                            XmNeditable     , True ,
00668                            XmNmaxLength    , 128 ,
00669                            XmNresizeWidth  , False ,
00670                            XmNmarginHeight , 1 ,
00671                            XmNmarginWidth  , 1 ,
00672                            XmNcursorPositionVisible , True ,
00673                            XmNblinkRate , 0 ,
00674                            XmNautoShowCursorPosition , True ,
00675                            XmNtraversalOn , False ,
00676                            XmNinitialResourcesPersistent , False ,
00677                         NULL ) ;
00678      XtSetSensitive( label_label , (Boolean)(value_int != 0) ) ;
00679      XtSetSensitive( label_textf , (Boolean)(value_int != 0) ) ;
00680 
00681      XtAddCallback( label_textf, XmNactivateCallback    ,
00682                                  DRAW_label_CB , NULL ) ; /* return key */
00683 
00684      XtAddCallback( label_textf, XmNlosingFocusCallback ,
00685                                  DRAW_label_CB , NULL ) ; /* tab key */
00686 
00687      XtInsertEventHandler( label_textf ,      /* notify when */
00688                            LeaveWindowMask ,  /* pointer leaves */
00689                            FALSE ,            /* this window */
00690                            DRAW_label_EV ,
00691                            (XtPointer) NULL ,
00692                            XtListTail ) ;     /* last in queue */
00693 
00694      XtInsertEventHandler( label_label ,      /* button press in label */
00695                            ButtonPressMask ,
00696                            FALSE ,
00697                            DRAW_label_EV ,
00698                            (XtPointer) NULL ,
00699                            XtListTail ) ;
00700      POPUP_cursorize( label_label ) ;
00701 
00702      XtManageChild(rc) ;
00703    }
00704 
00705    /*** option menu to choose drawing color ***/
00706 
00707    color_av = new_MCW_colormenu( rowcol , "Color " , dc ,
00708                                  1 , dc->ovc->ncol_ov - 1 , color_index ,
00709                                  DRAW_color_CB , NULL ) ;
00710 
00711    MCW_reghelp_children( color_av->wrowcol ,
00712                          "Use this to set the color that is\n"
00713                          "shown during mouse button 2 drawing.\n"
00714                          "N.B.: After drawing is completed,\n"
00715                          "  the dataset will be displayed\n"
00716                          "  with the chosen value replacing\n"
00717                          "  the drawing color.  This color\n"
00718                          "  is used ONLY while button 2 is\n"
00719                          "  actually pressed down."
00720                        ) ;
00721    MCW_reghint_children( color_av->wrowcol , "Used when button 2 is drawing" ) ;
00722 
00723    /*** arrowval to choose drawing mode ***/
00724    /*-- 16 Oct 2002: put in a horiz rowcol, and add rad_av button --*/
00725 
00726    { Widget rc ;
00727 
00728      rc = XtVaCreateWidget( "AFNI" , xmRowColumnWidgetClass , rowcol ,
00729                        XmNpacking      , XmPACK_TIGHT ,
00730                        XmNorientation  , XmHORIZONTAL ,
00731                        XmNmarginHeight , 0 ,
00732                        XmNmarginWidth  , 0 ,
00733                        XmNspacing      , 0 ,
00734                        XmNinitialResourcesPersistent , False ,
00735                        XmNtraversalOn , False ,
00736                     NULL ) ;
00737 
00738      mode_av = new_MCW_optmenu( rc , "Mode  " ,
00739                               0 , NUM_modes-1 , mode_ival,0 ,
00740                               DRAW_mode_CB , NULL ,
00741                               MCW_av_substring_CB , mode_strings ) ;
00742 
00743      AVOPT_columnize( mode_av , 2 ) ;
00744 
00745      MCW_reghelp_children( mode_av->wrowcol ,
00746                            "Use this to set the way in which\n"
00747                            "drawing pixels on the screen is\n"
00748                            "used to select dataset voxels:\n"
00749                            "Open Curve      = voxels picked along lines drawn;\n"
00750                            "Closed Curve    = voxels forming a closed curve\n"
00751                            "Points          = only voxels at X11 notify pixels;\n"
00752                            "Flood->Value    = flood fill from the chosen point\n"
00753                            "                   out to points = Value\n"
00754                            "Flood->Nonzero  = flood fill from chosen point out\n"
00755                            "                   to any nonzero point\n"
00756                            "Flood->Zero     = flood fill from chosen point out\n"
00757                            "                   to any zero point\n"
00758                            "Zero->Value     = flood fill with zeros until the\n"
00759                            "                   Value is hit\n"
00760                            "Flood->Val/Zero = flood fill from the chosen point\n"
00761                            "                   until the Value OR zero is hit\n"
00762                            "Filled Curve    = fill inside of closed curve with\n"
00763                            "                   Value\n"
00764                            "\n"
00765                            "2D Nbhd         = like Open Curve, but fills in around\n"
00766                            "                   the in-plane neighborhood of each\n"
00767                            "                   drawn point 'x' with the patterns:\n"
00768                            "                        5 4 3 4 5\n"
00769                            "                        4 2 1 2 4\n"
00770                            "                        3 1 x 1 3\n"
00771                            "                        4 2 1 2 4\n"
00772                            "                        5 4 3 4 5\n"
00773                            "                   where the number indicates the\n"
00774                            "                   Nearest Neighbor order of the\n"
00775                            "                   points nearby 'x'.\n"
00776                            "3D Nbhd         = Similar, but in 3D (out-of-plane)\n"
00777                            "\n"
00778                            "2D Circle       = Draw a circle of given Radius\n"
00779                            "3D Sphere       = Draw a sphere of given Radius\n"
00780                          ) ;
00781      MCW_reghint_children( mode_av->wrowcol , "How voxels are chosen") ;
00782 
00783      /** 16 Oct 2002: radius chooser **/
00784 
00785      rad_av = new_MCW_arrowval( rc             ,    /* parent */
00786                                 "R"            ,    /* label */
00787                                 MCW_AV_downup  ,    /* arrow directions */
00788                                 1              ,    /* min value (0.1 mm from decim) */
00789                                 999            ,    /* max value (99.9 mm) */
00790                                 40             ,    /* init value */
00791                                 MCW_AV_editext ,    /* input/output text display */
00792                                 1              ,    /* decimal shift */
00793                                 NULL           ,    /* routine to call when button */
00794                                 NULL           ,    /* is pressed, and its data */
00795                                 NULL,NULL           /* no special display */
00796                               ) ;
00797      XtVaSetValues( rad_av->wtext   , XmNcolumns , 5 , NULL ) ;
00798      MCW_reghint_children( rad_av->wrowcol , "Radius of Circles and Spheres" ) ;
00799      MCW_reghelp_children( rad_av->wrowcol ,
00800                             " \n"
00801                             "Sets the radius (in mm) of the 2D Circle\n"
00802                             "or 3D Sphere drawing modes.  Voxels whose\n"
00803                             "center-to-center distance is <= this value\n"
00804                             "will be filled in.\n"
00805                           ) ;
00806      ENABLE_rad_av ;   /* turn it on or off */
00807 
00808      XtManageChild(rc) ;
00809    }
00810 
00811    /*** 19 Mar 2001: stuff for linear fillin ***/
00812 
00813    { Widget rc ;
00814 
00815      /*** separator for visual neatness ***/
00816 
00817      (void) XtVaCreateManagedWidget(
00818                 "AFNI" , xmSeparatorWidgetClass , rowcol ,
00819                    XmNseparatorType , XmDOUBLE_LINE ,
00820                    XmNinitialResourcesPersistent , False ,
00821                 NULL ) ;
00822 
00823      rc = XtVaCreateWidget( "AFNI" , xmRowColumnWidgetClass , rowcol ,
00824                        XmNpacking      , XmPACK_TIGHT ,
00825                        XmNorientation  , XmHORIZONTAL ,
00826                        XmNmarginHeight , 0 ,
00827                        XmNmarginWidth  , 0 ,
00828                        XmNspacing      , 0 ,
00829                        XmNinitialResourcesPersistent , False ,
00830                        XmNtraversalOn , False ,
00831                     NULL ) ;
00832 
00833      fillin_dir_av = new_MCW_optmenu( rc , "Linear Fillin " ,
00834                                       0 , NFILLIN_DIR-1 , 0 , 0 ,
00835                                       NULL , NULL ,
00836                                       MCW_av_substring_CB , fillin_dir_strings ) ;
00837 
00838      fillin_gap_av = new_MCW_optmenu( rc , " Gap" ,
00839                                       1 , NFILLIN_GAP , 4 , 0 ,
00840                                       NULL,NULL,NULL,NULL ) ;
00841 
00842      xstr = XmStringCreateLtoR( "*Do the Fill*" , XmFONTLIST_DEFAULT_TAG ) ;
00843      fillin_doit_pb = XtVaCreateManagedWidget( "AFNI" , xmPushButtonWidgetClass , rc ,
00844                                                 XmNlabelString , xstr ,
00845                                                 XmNtraversalOn , False ,
00846                                                 XmNinitialResourcesPersistent , False ,
00847                                                NULL ) ;
00848      XtAddCallback( fillin_doit_pb , XmNactivateCallback, DRAW_fillin_CB, NULL ) ;
00849      XmStringFree(xstr) ;
00850      XtManageChild(rc) ;
00851 
00852    } /* end of fillin */
00853 
00854    /*** 22 Aug 2001: stuff for TT Atlas Regions ***/
00855 
00856    if( TT_load_atlas() > 0 ){
00857       Widget rc ;
00858       int ii , jj , nr , qq ;
00859       XmString xstr ;
00860 
00861       /*** separator for visual neatness ***/
00862 
00863       (void) XtVaCreateManagedWidget(
00864                  "AFNI" , xmSeparatorWidgetClass , rowcol ,
00865                     XmNseparatorType , XmDOUBLE_LINE ,
00866                     XmNinitialResourcesPersistent , False ,
00867                  NULL ) ;
00868 
00869        /*** rowcol to hold all widgets ***/
00870 
00871        ttatlas_rowcol = rc =
00872            XtVaCreateWidget( "AFNI" , xmRowColumnWidgetClass , rowcol ,
00873                       XmNpacking      , XmPACK_TIGHT ,
00874                       XmNorientation  , XmVERTICAL ,
00875                       XmNmarginHeight , 0 ,
00876                       XmNmarginWidth  , 0 ,
00877                       XmNspacing      , 0 ,
00878                       XmNinitialResourcesPersistent , False ,
00879                       XmNtraversalOn , False ,
00880                    NULL ) ;
00881 
00882        /*** label at top ***/
00883 
00884        xstr = XmStringCreateLtoR( "       TT Atlas Region to Load" ,
00885                                   XmFONTLIST_DEFAULT_TAG ) ;
00886        (void) XtVaCreateManagedWidget(
00887                     "dialog" , xmLabelWidgetClass , rc ,
00888                        XmNlabelString   , xstr  ,
00889                        XmNrecomputeSize , False ,
00890                        XmNmarginWidth   , 0     ,
00891                        XmNinitialResourcesPersistent , False ,
00892                     NULL ) ;
00893        XmStringFree(xstr) ;
00894 
00895        /*** make list of TT atlas regions to include ***/
00896 
00897       ttatlas_list = (ttatlas_compendium *) calloc(1,sizeof(ttatlas_compendium));
00898       nr = 0 ;
00899       for( ii=0 ; ii < TTO_COUNT ; ii++ ){
00900 
00901          if( strncmp(TTO_list[ii].name,"Left  ",6) != 0 ) continue ; /* skip */
00902          if( TTO_list[ii].tdval == 0 )                    continue ; /* skip */
00903 
00904          ttatlas_list->reg_label [nr] = strdup(TTO_list[ii].name+6) ;
00905          ttatlas_list->reg_tto   [nr] = ii ;
00906          ttatlas_list->reg_ttbrik[nr] = (TTO_list[ii].tdlev==2) ? 0 : 1 ;
00907          ttatlas_list->reg_ttval [nr] = TTO_list[ii].tdval ;
00908 
00909          /* trim trailing '.'s */
00910 
00911          qq = 0 ;
00912          for( jj=strlen(ttatlas_list->reg_label[nr])-1         ;
00913               jj > 0 && ttatlas_list->reg_label[nr][jj] == '.' ; jj -- ){
00914 
00915             ttatlas_list->reg_label[nr][jj] = '\0' ; qq++ ;
00916          }
00917          if( qq > 0 ){
00918             jj = strlen(ttatlas_list->reg_label[nr]) ;
00919             ttatlas_list->reg_label[nr][jj] = ' ' ;
00920          }
00921 
00922          nr++ ;
00923       }
00924       ttatlas_list->reg_num = nr ;
00925 
00926       /*** Region chooser ***/
00927 
00928       ttatlas_region_av = new_MCW_optmenu( rc , " " ,
00929                                            0 , nr-1 , 0 , 0 ,
00930                                            NULL,NULL ,
00931                                            MCW_av_substring_CB ,
00932                                            ttatlas_list->reg_label ) ;
00933       AVOPT_columnize( ttatlas_region_av , 3 ) ;
00934 
00935       /*** Hemisphere chooser */
00936 
00937       ttatlas_hemisphere_av = new_MCW_optmenu( rc , " Hemisphere(s)" ,
00938                                                0 , NHEMI-1 , NHEMI-1 , 0 ,
00939                                                NULL,NULL ,
00940                                                MCW_av_substring_CB, HEMI_strings );
00941 
00942       /*** row of pushbuttons ***/
00943 
00944       ttatlas_actar = MCW_action_area( rc , TTATLAS_act , NUM_TTATLAS_ACT ) ;
00945 
00946       XtManageChild( rc ) ;
00947 
00948    } /* end of TT Atlas */
00949 
00950    /*** separator for visual neatness ***/
00951 
00952    (void) XtVaCreateManagedWidget(
00953              "AFNI" , xmSeparatorWidgetClass , rowcol ,
00954                 XmNseparatorType , XmDOUBLE_LINE ,
00955                 XmNinitialResourcesPersistent , False ,
00956              NULL ) ;
00957 
00958    /*** a set of action buttons below the line ***/
00959 
00960    (void) MCW_action_area( rowcol , DRAW_actor , NACT ) ;
00961 
00962    undo_pb   = (Widget) DRAW_actor[0].data ;
00963    redo_pb   = (Widget) DRAW_actor[1].data ;  /* 19 Nov 2003 */
00964    help_pb   = (Widget) DRAW_actor[2].data ;
00965    quit_pb   = (Widget) DRAW_actor[3].data ;
00966    save_pb   = (Widget) DRAW_actor[4].data ;
00967    saveas_pb = (Widget) DRAW_actor[5].data ;  /* 24 Sep 2001 */
00968    done_pb   = (Widget) DRAW_actor[6].data ;
00969 
00970    /*** that's all ***/
00971 
00972    XtManageChild(rowcol) ;
00973    XtRealizeWidget(shell) ;  /* will not be mapped */
00974    return ;
00975 }
00976 
00977 /*-------------------------------------------------------------------
00978   Callback for copy_bbox -- 24 Sep 2001 - RWCox
00979 ---------------------------------------------------------------------*/
00980 
00981 void DRAW_copy_bbox_CB( Widget w, XtPointer client_data, XtPointer call_data )
00982 {
00983    int sens = (MCW_val_bbox(copy_bbox) != 0);
00984    AV_SENSITIZE( copy_mode_av , sens ) ;
00985    AV_SENSITIZE( copy_type_av , sens ) ;
00986    AV_SENSITIZE( copy_datum_av, sens ) ;
00987    return ;
00988 }
00989 
00990 /*-------------------------------------------------------------------
00991   Callback for done button
00992 ---------------------------------------------------------------------*/
00993 
00994 void DRAW_done_CB( Widget w, XtPointer client_data, XtPointer call_data )
00995 {
00996    if( dset != NULL ){
00997       if( recv_open )  /* 31 Mar 1999: changed shutdown to EVERYTHING */
00998          AFNI_receive_control( im3d, recv_key,EVERYTHING_SHUTDOWN, NULL ) ;
00999       if( dset_changed ){
01000          MCW_invert_widget( done_pb ) ;
01001          DRAW_attach_dtable( vl_dtable, "VALUE_LABEL_DTABLE",  dset ) ;
01002          DSET_write(dset) ;
01003          MCW_invert_widget( done_pb ) ;
01004       }
01005       DSET_unlock(dset) ; DSET_anyize(dset) ;
01006       dset = NULL ; dset_changed = 0 ;
01007    }
01008 
01009    CLEAR_UNREDOBUF ;  /* 19 Nov 2003 */
01010 
01011    XtUnmapWidget( shell ); editor_open = 0; recv_open = 0; recv_key = -1;
01012    if( old_stroke_autoplot ) putenv("AFNI_STROKE_AUTOPLOT=YES") ;
01013    return ;
01014 }
01015 
01016 /*-------------------------------------------------------------------
01017   Callback for undo button [heavily modified 19 Nov 2003]
01018 ---------------------------------------------------------------------*/
01019 
01020 void DRAW_undo_CB( Widget w, XtPointer client_data, XtPointer call_data )
01021 {
01022    dobuf *sb ;  /* saved drawing buffer that will be redrawn */
01023 
01024    if( undo_num <= 0 || undo_stack == NULL ){ XBell(dc->display,100); return; }
01025 
01026    undo_how = 1 ;  /* the next drawing save will be onto redo stack */
01027 
01028    sb = undo_stack[undo_num-1] ;  /* saved buffer */
01029 
01030    DRAW_into_dataset( sb->npt , sb->xyz,NULL,NULL , sb->buf ) ;
01031 
01032    DESTROY_DOBUF(sb) ;  /* purge and pop top of undo stack */
01033    undo_num-- ;
01034    UNDO_button_labelize ;
01035 
01036    AFNI_process_drawnotice( im3d ) ;  /* 30 Mar 1999 */
01037 
01038    undo_how = 0 ; /* further draws go onto undo stack */
01039    return ;
01040 }
01041 
01042 /*-------------------------------------------------------------------
01043   Callback for redo button [from DRAW_undo_CB(), 19 Nov 2003]
01044 ---------------------------------------------------------------------*/
01045 
01046 void DRAW_redo_CB( Widget w, XtPointer client_data, XtPointer call_data )
01047 {
01048    dobuf *sb ;
01049 
01050    if( redo_num <= 0 || redo_stack == NULL ){ XBell(dc->display,100); return; }
01051 
01052    undo_how = 2 ;  /* drawing save will be onto undo stack */
01053 
01054    sb = redo_stack[redo_num-1] ;  /* saved buffer */
01055 
01056    DRAW_into_dataset( sb->npt , sb->xyz,NULL,NULL , sb->buf ) ;
01057 
01058    DESTROY_DOBUF(sb) ;  /* purge and pop top of redo stack */
01059    redo_num-- ;
01060    REDO_button_labelize ;
01061 
01062    AFNI_process_drawnotice( im3d ) ;  /* 30 Mar 1999 */
01063 
01064    undo_how = 0 ; /* further draws go onto undo stack */
01065    return ;
01066 }
01067 
01068 /*-------------------------------------------------------------------
01069   Callback for quit button
01070 ---------------------------------------------------------------------*/
01071 
01072 void DRAW_quit_CB( Widget w, XtPointer client_data, XtPointer call_data )
01073 {
01074    if( dset != NULL ){
01075      if( recv_open ) AFNI_receive_control( im3d,recv_key,DRAWING_SHUTDOWN,NULL );
01076      DSET_unlock(dset) ;
01077      DSET_unload(dset) ; DSET_anyize(dset) ;
01078      if( dset_changed ){
01079        if( recv_open ){
01080          AFNI_process_drawnotice( im3d ) ;  /* 30 Mar 1999 */
01081          AFNI_receive_control( im3d, recv_key,EVERYTHING_SHUTDOWN, NULL ) ; /* 25 Sep 2001 */
01082        }
01083        MCW_invert_widget(quit_pb) ;
01084        THD_load_statistics( dset ) ;
01085        PLUTO_dset_redisplay( dset ) ;
01086        MCW_invert_widget(quit_pb) ;
01087      }
01088      dset = NULL ; dset_changed = 0 ;
01089    }
01090 
01091    CLEAR_UNREDOBUF ;  /* 19 Nov 2003 */
01092 
01093    XtUnmapWidget( shell ); editor_open = 0; recv_open = 0; recv_key = -1;
01094    if( old_stroke_autoplot ) putenv("AFNI_STROKE_AUTOPLOT=YES") ;
01095    return ;
01096 }
01097 
01098 /*-------------------------------------------------------------------
01099   Callback for Save button
01100 ---------------------------------------------------------------------*/
01101 
01102 void DRAW_save_CB( Widget w, XtPointer client_data, XtPointer call_data )
01103 {
01104    if( dset == NULL ){ XBell(dc->display,100) ; return ; }
01105 
01106    MCW_invert_widget(save_pb) ;
01107 
01108    DRAW_attach_dtable( vl_dtable, "VALUE_LABEL_DTABLE",  dset ) ;
01109    DSET_write(dset) ; dset_changed = 0 ; SENSITIZE(choose_pb,1) ;
01110 
01111    MCW_invert_widget(save_pb) ;
01112    SENSITIZE(save_pb,0) ; SENSITIZE(saveas_pb,0) ;
01113    return ;
01114 }
01115 
01116 /*-------------------------------------------------------------------
01117   24 Sep 2001: Callback for Save As button
01118 ---------------------------------------------------------------------*/
01119 
01120 void DRAW_saveas_CB( Widget w, XtPointer client_data, XtPointer call_data )
01121 {
01122    if( dset == NULL ){ XBell(dc->display,100) ; return ; }
01123 
01124    MCW_choose_string( saveas_pb , "Enter new prefix" ,
01125                       NULL , DRAW_saveas_finalize_CB , NULL ) ;
01126 }
01127 
01128 /*--------------------------------------------------------------------*/
01129 
01130 void DRAW_saveas_finalize_CB( Widget w, XtPointer fd, MCW_choose_cbs * cbs )
01131 {
01132    THD_3dim_dataset *cset ;
01133    char str[256] ;
01134    XmString xstr ;
01135 
01136    /*-- check for craziness --*/
01137 
01138    if( !editor_open || dset == NULL ){
01139      POPDOWN_strlist_chooser; XBell(dc->display,100); return;
01140    }
01141 
01142    if( !PLUTO_prefix_ok(cbs->cval) ){ XBell(dc->display,100); return; }
01143 
01144    /*-- make a copy of this dataset --*/
01145 
01146    MCW_invert_widget(saveas_pb) ;
01147 
01148    cset = DRAW_copy_dset( dset , 0,0,-1 ) ;
01149    if( cset == NULL ){                      /* should not happen */
01150      (void) MCW_popup_message( saveas_pb ,
01151                                  " \n"
01152                                  "*** Cannot make copy of edited  ***\n"
01153                                  "*** dataset for unknown reasons ***\n " ,
01154                                MCW_USER_KILL | MCW_TIMER_KILL ) ;
01155 
01156      MCW_invert_widget(saveas_pb); XBell(dc->display,100); return;
01157    }
01158    EDIT_dset_items( cset , ADN_prefix,cbs->cval , ADN_none ) ;
01159 
01160    if( THD_is_file(DSET_HEADNAME(cset)) ){  /* stupid user */
01161      (void) MCW_popup_message( saveas_pb ,
01162                                  " \n"
01163                                  "*** Cannot SaveAs this edited   ***\n"
01164                                  "*** dataset since a dataset     ***\n"
01165                                  "*** with that prefix is on disk ***\n " ,
01166                                MCW_USER_KILL | MCW_TIMER_KILL ) ;
01167      DSET_delete(cset) ;
01168      MCW_invert_widget(saveas_pb); XBell(dc->display,100); return;
01169    }
01170 
01171    /*-- tell AFNI about the new dataset --*/
01172 
01173    PLUTO_add_dset( plint , cset , DSET_ACTION_MAKE_CURRENT ) ;
01174 
01175    /*-- remove current dataset from further consideration --*/
01176 
01177    DSET_unlock(dset) ; DSET_unload(dset) ; DSET_anyize(dset) ;
01178 
01179    /*-- switch current dataset to be the copy just made --*/
01180 
01181    dset = cset ; dset_idc = dset->idcode ;
01182    DRAW_attach_dtable( vl_dtable, "VALUE_LABEL_DTABLE",  dset ) ;
01183    DSET_write(dset) ; DSET_mallocize(dset) ; DSET_load(dset) ; DSET_lock(dset) ;
01184 
01185    /*-- re-write the informational label --*/
01186 
01187    if( DSET_BRICK_FACTOR(dset,0) == 0.0 ){
01188       strcpy(str,DSET_FILECODE(dset)) ;
01189    } else {
01190       char abuf[16] ;
01191       AV_fval_to_char( DSET_BRICK_FACTOR(dset,0) , abuf ) ;
01192       sprintf(str,"%s\nbrick factor: %s", DSET_FILECODE(dset) , abuf ) ;
01193    }
01194    xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
01195    XtVaSetValues( info_lab , XmNlabelString , xstr , NULL ) ;
01196    XmStringFree(xstr) ;
01197 
01198    /*-- finish up --*/
01199 
01200    dset_changed = 0 ; SENSITIZE(choose_pb,1) ;
01201    MCW_invert_widget(saveas_pb) ;
01202    SENSITIZE(save_pb,0) ; SENSITIZE(saveas_pb,0) ;
01203    return ;
01204 }
01205 
01206 /*-------------------------------------------------------------------
01207   Callback for Help button
01208 ---------------------------------------------------------------------*/
01209 
01210 void DRAW_help_CB( Widget w, XtPointer client_data, XtPointer call_data )
01211 {
01212    (void ) new_MCW_textwin( help_pb ,
01213 
01214   "This plugin can be used to edit interactively the voxel contents\n"
01215   "of a dataset.  Since such changes are irreversible, it is best that\n"
01216   "you either edit a copy of a dataset, or create a dataset of all zeros.\n"
01217   "These tasks can be done with the 'Dataset Copy' plugin.\n"
01218   "\n"
01219   "***************** Read the WARNINGS section below. *****************\n"
01220   "\n"
01221   "---------------------- Bob Cox, February 1998 ----------------------\n"
01222   "\n"
01223   "Step 1) Choose a dataset to edit.\n"
01224   "        * Only datasets that have data BRIKs stored at the current\n"
01225   "            resolution can be edited.\n"
01226   "        * It is probably best that the dataset being edited be\n"
01227   "            displayed.  Otherwise it will be impossible to gauge\n"
01228   "            the effect of the editing operations.\n"
01229   "        * At this time, only datasets that have a single sub-brick\n"
01230   "            can be edited.\n"
01231   "        * Datasets may be copied with the 'Dataset Copy' plugin.\n"
01232   "            Making an empty dataset with a given geometry can be\n"
01233   "            done using the 'Zero [One]' option in that plugin.\n"
01234   "   [24 Sep 2001]:\n"
01235   "        * Datasets may also be copied when chosen by selecting the\n"
01236   "            'Copy' toggle.  The choosers to the right of this let\n"
01237   "            you control how the input dataset is copied:\n"
01238   "            (a)  Data => data value are copied\n"
01239   "                 Zero => copy is full of zeros\n"
01240   "            (b) As Is => copy is same dataset type as input dataset\n"
01241   "                 Func => copy is a functional overlay (fim) dataset\n"
01242   "                 Anat => copy is a anatomical underlay dataset\n"
01243   "            (c) As Is => copy is stored as input dataset is stored\n"
01244   "                 Byte => copy is stored as bytes\n"
01245   "                Short => copy is stored as shorts\n"
01246   "                Float => copy is stored as floats\n"
01247   "                NOTE: you can only change the data storage of the\n"
01248   "                      copy from the input if you are using 'Zero';\n"
01249   "                      with 'Data', the data storage of the copy will\n"
01250   "                      always be made 'As Is'.\n"
01251   "            The copy is made when you finalize the dataset choice.\n"
01252   "            The copied dataset has the same prefix as the input\n"
01253   "            dataset, with the string 'COPY_' prepended.  You can\n"
01254   "            alter this name later using the 'Dataset Rename' plugin,\n"
01255   "            AFTER the dataset has been Save-d, or with the '3drename'\n"
01256   "            program after you exit AFNI, or with the 'SaveAs' button\n"
01257   "            in this plugin.\n"
01258   "\n"
01259   "Step 2) Choose a drawing value.\n"
01260   "        * This is the number that will be placed into the dataset\n"
01261   "            voxels that are chosen.\n"
01262   "        * Integer valued datasets can only receive integer values;\n"
01263   "            float datasets can take floating point values.\n"
01264   "        * You can attach a label string to each drawing value.\n"
01265   "            The value-label table will be saved with in the dataset\n"
01266   "            .HEAD file when you use 'Save', 'SaveAs' or 'Done'.\n"
01267   "        * You can also setup a standard value-label table in a file,\n"
01268   "            whose name is specified by setting environment variable\n"
01269   "            AFNI_VALUE_LABEL_DTABLE -- cf. file README.environment.\n"
01270   "        * Button-3-clicking in the 'Label' next to the text-entry field\n"
01271   "            will bring up a menu of all current value-label pairs.\n"
01272   "            You can choose from them to set a new drawing value.\n"
01273   "        * Button-1-clicking in the 'Label' will ask for a filename\n"
01274   "            to read that loads the value-label pairs.  The format\n"
01275   "            of this file is described in README.environment.\n"
01276   "            Reading in a file like this will erase any existing\n"
01277   "            value-label associations in the plugin.\n"
01278   "\n"
01279   "Step 3) Choose a drawing color.\n"
01280   "        * This is the color that will be shown in the image windows\n"
01281   "            while drawing is going on (that is, while mouse button 2\n"
01282   "            is pressed).\n"
01283   "        * See 5) for more details about the drawing process.\n"
01284   "\n"
01285   "Step 4) Choose a drawing mode.\n"
01286   "        * 'Open Curve' means to select dataset voxels that lie under\n"
01287   "            the pixel lines drawn on the image as you move the mouse\n"
01288   "            with button 2 held down.\n"
01289   "        * 'Closed Curve' means to close the curve drawn from the last\n"
01290   "            point drawn (where button 2 is released) back to the\n"
01291   "            first point drawn (where button 2 was pressed).\n"
01292   "        * 'Points' means to take only the voxels corresponding\n"
01293   "            to the screen pixels about which X11 sends notice.\n"
01294   "        * 'Flood->Value' means to flood fill outwards from the first\n"
01295   "            chosen voxel, stopping when the Dataset Value is reached.\n"
01296   "            In conjunction with 'Closed Curve', it can be used to draw\n"
01297   "            an entire region in a plane.\n"
01298   "        * 'Flood->Nonzero' means to flood fill, but stopping when any\n"
01299   "            nonzero voxel value is reached.\n"
01300   "        * 'Flood->Zero' means to flood fill, but stopping when any\n"
01301   "            zero voxel value is reached.\n"
01302   "        * 'Zero->Value' means to flood fill the slice with zeros,\n"
01303   "            stopping when a voxel with the drawing value is reached.\n"
01304   "        * 'Flood->Val/Zero' means to flood fill the slice with the\n"
01305   "            Value until voxels whose values are either zero or the\n"
01306   "            Value are hit\n"
01307   "        * 'Filled Curve' means to draw a closed curve and then fill\n"
01308   "            its interior with the drawing value.  It is similar to\n"
01309   "            doing 'Closed Curve' followed by 'Flood->Value', but\n"
01310   "            more convenient.\n"
01311   "        * '2D Nbhd: Kth NN' is like 'Open Curve', but each the 2D in-slice\n"
01312   "            neighborhood of a point 'x' is filled in with the following\n"
01313   "            pattern of points, for K=1..5:\n"
01314   "                                              5 4 3 4 5\n"
01315   "                                              4 2 1 2 4\n"
01316   "                                              3 1 x 1 3\n"
01317   "                                              4 2 1 2 4\n"
01318   "                                              5 4 3 4 5\n"
01319   "            In a cubical lattice with voxel edge length=1, the 2D Kth NN\n"
01320   "            volume is a 'circle' out to radius:\n"
01321   "                  K=1  r=sqrt(1)  [e.g., (+1, 0)]\n"
01322   "                  K=2  r=sqrt(2)  [e.g., (+1,+1) => 3x3 square]\n"
01323   "                  K=3  r=sqrt(4)  [e.g., (+2, 0)]\n"
01324   "                  K=4  r=sqrt(5)  [e.g., (+2,+1)]\n"
01325   "                  K=5  r=sqrt(8)  [the whole 5x5 square about 'x']\n"
01326   "        * '3D Nbhd: Kth NN' is similar, but with the 3D neighborhood\n"
01327   "            of each point (so you are drawing out-of-slice).  In this\n"
01328   "            case, the 3D Kth NN volume is a 'sphere' out to radius\n"
01329   "                  K=1  r=sqrt(1)  [e.g., (+1, 0, 0)]\n"
01330   "                  K=2  r=sqrt(2)  [e.g., (+1,+1, 0)]\n"
01331   "                  K=3  r=sqrt(3)  [e.g., (+1,+1,+1) => 3x3x3 cube]\n"
01332   "                  K=4  r=sqrt(4)  [e.g., (+2, 0, 0)]\n"
01333   "                  K=5  r=sqrt(5)  [e.g., (+2,+1, 0)]\n"
01334   "                  K=6  r=sqrt(6)  [e.g., (+2,+1,+1)]\n"
01335   "                5x5x5  fills out the 5x5x5 cube about each drawn point.\n"
01336   "        * '2D Circle' and '3D Sphere' draw in-plane circles and 3D spheres\n"
01337   "            about each drawn point 'x'.  The radius (in mm) is set using\n"
01338   "            the 'R' chooser that becomes active when one of these drawing\n"
01339   "            modes is selected.  These drawing modes use the actual voxel\n"
01340   "            sizes in the dataset, unlike the 'Nbhd' modes described above.\n"
01341   "\n"
01342   "Step 5) Draw something in an image window.\n"
01343   "        * Drawing is done using mouse button 2.\n"
01344   "          [03 Oct 2002: You can also use mouse button 1 with the   ]\n"
01345   "          [             keyboard Shift key held down simultaneously]\n"
01346   "        * In an image window, drawing a set of pixels is done\n"
01347   "            by pressing and holding button 2, and dragging\n"
01348   "            the cursor across the desired pixels.  The drawing\n"
01349   "            color will be painted over these pixels while the\n"
01350   "            painting is going on (while button 2 is held down).\n"
01351   "        * After mouse button 2 is released, the drawing value for\n"
01352   "            the chosen voxels is copied into the dataset.  The\n"
01353   "            dataset is then redisplayed -- this will most likely\n"
01354   "            change the color of the selected voxels, since display\n"
01355   "            colors depend on the Define Function pbar (for Func\n"
01356   "            datasets) or on the grayscale map (for Anat datasets).\n"
01357   "        * That is, the drawing color is ONLY used while button2\n"
01358   "            is pressed down.  This color should simply be chosen\n"
01359   "            to provide good contrast for the drawing operations.\n"
01360   "        * Pressing and releasing button 2 in a graph window\n"
01361   "            sub-graph will cause that single voxel to get the\n"
01362   "            drawing value, as well.  You cannot select a group\n"
01363   "            of voxels in a graph window -- only one voxel per click.\n"
01364   "        * Linear Fillin provides the same functionality as program\n"
01365   "            3dRowFillin.  It lets you fill in gaps (zeros) between\n"
01366   "            the same value in a particular anatomical direction.\n"
01367   "            For example, you could draw on every 4th coronal slice,\n"
01368   "            and then use Fill in the A-P direction with a maximum\n"
01369   "            gap setting of 3 to fill in the slices you didn't draw.\n"
01370   "            (Then you could manually fix up the intermediate slices.)\n"
01371   "        ** N.B.: Linear Fillin can now be undone [as of 21 Nov 2003]!\n"
01372   "        * TT Atlas Regions can be loaded into the edited volume.  The\n"
01373   "            chosen region+hemisphere(s) will be loaded with the current\n"
01374   "            Value.  'OverWrite' loading means that all voxels from\n"
01375   "            the TT region will be replaced with the Value.\n"
01376   "            'InFill' loading means that only voxels that are currently\n"
01377   "            zero in the TT region will be replaced with the Value.\n"
01378   "           N.B.: TT Atlas regions may not be good representations of\n"
01379   "                   any given subject's anatomy.  You will probably\n"
01380   "                   want to edit the mask after doing the loading.\n"
01381   "                 This feature requires the presence of the TTatlas+tlrc\n"
01382   "                   (or TTatlas.nii.gz) dataset in the plugin directory.\n"
01383   "                   It also requires that you be editing in +tlrc coordinates,\n"
01384   "                   or in +orig coordinates with a mapping to +tlrc\n"
01385   "                   coordinates having already been established.\n"
01386   "                 Unlike Linear Fillin, TT Atlas drawing can be undone.\n"
01387   "\n"
01388   "Step 6) Undo and Redo.\n"
01389   "        * The last drawing operation can be undone -- that is,\n"
01390   "            pressing 'Undo' will restore the voxel values before\n"
01391   "            the last button 2 press-release operation.\n"
01392   "        * 'Redo' will undo the previous 'Undo'.\n"
01393   "        * Multiple levels of Undo/Redo are now available [19 Nov 2003].\n"
01394   "        * The amount of memory set aside for Undo/Redo operations\n"
01395   "            is controlled by environment variable AFNI_DRAW_UNDOSIZE,\n"
01396   "            which is in megabytes; its value defaults to 6.\n"
01397   "        * The numbers (as in '[3]') on the Undo and Redo buttons\n"
01398   "            indicate how many levels are available at any moment.\n"
01399   "\n"
01400   "Step 7) Save dataset (maybe).\n"
01401   "        * While a dataset is being edited, it is locked into memory.\n"
01402   "        * The edited values are saved to disk only when 'Save' or\n"
01403   "            'Done' are pressed.\n"
01404   "        * The 'Quit' button can be used to discard the edits of\n"
01405   "            a dataset.  In that case, the dataset values are\n"
01406   "            re-read from disk when it is redisplayed.\n"
01407   "        * Closing the AFNI Editor window using the window manager\n"
01408   "            is equivalent to pressing 'Quit'.\n"
01409   "   [24 Sep 2001]:\n"
01410   "        * The 'SaveAs' button lets you save the changes to a new\n"
01411   "            dataset.  The new dataset will become the current dataset\n"
01412   "            for further editing and for AFNI display.\n"
01413   "\n"
01414   "WARNINGS++:\n"
01415   "  * It is important to understand the distinction between 'pixels'\n"
01416   "      and 'voxels'.  Pixels are on the screen, and while you are\n"
01417   "      drawing, you are drawing pixels with the drawing color.  When\n"
01418   "      you release mouse button 2, those dataset voxels to which these\n"
01419   "      pixels correspond are computed.  The values stored in those\n"
01420   "      voxels are then altered, and the dataset display is refreshed.\n"
01421   "  * It is possible to draw on a montaged image window.  However,\n"
01422   "      only voxels from the first slice drawn into will be altered.\n"
01423   "  * Using button 2 in an image or graph window before choosing a\n"
01424   "      dataset to edit will cause the display to beep.\n"
01425   "  * Closing the AFNI controller window that this was started from\n"
01426   "      is the equivalent of pressing 'Quit'.\n"
01427   "  * Doing something that causes the AFNI controller window to\n"
01428   "      alter its 3D grid location or resolution is also the\n"
01429   "      equivalent of pressing 'Quit'.  This is because the 3D grid\n"
01430   "      for the dataset being edited will no longer correspond to\n"
01431   "      the 3D grid in the image and graph windows.  Such actions\n"
01432   "      include switching from 'View Brick' to 'Warp on Demand',\n"
01433   "      switching datasets or sessions, and switching views.\n"
01434   "  * You can only draw into the windows of the AFNI controller from\n"
01435   "      which the Editor was started.\n"
01436   "  * Only one copy of the Editor can be active at a time.  If you\n"
01437   "      use the plugin menu to call up the Editor when it is already\n"
01438   "      open, that will simply pop the window up to the top of the\n"
01439   "      stacking order.  If you want to restart the Editor in a\n"
01440   "      different AFNI controller, you must first close the Editor\n"
01441   "      (via 'Done' or 'Quit') and then start it from the other\n"
01442   "      controller's window.\n"
01443   "  * Peculiar and confusing things can happen using 'Warp-on-Demand'\n"
01444   "      with the Editor.  My advice is NOT to try this.\n"
01445   "  * Note that using a Session rescan button (from the 'Define Datamode'\n"
01446   "      control panel) will close all datasets while rescanning the\n"
01447   "      session.  This can result in the loss of un-Saved edits.\n"
01448   "  * It is possible to edit the same dataset that you are also viewing\n"
01449   "      with the 'Render Dataset' plugin.  In this way, you can see a\n"
01450   "      3D visualization of your drawing as you do it.  You need to turn\n"
01451   "      on 'DynaDraw' in the rendering plugin; then, if the dataset you\n"
01452   "      are drawing on is the same as the renderer's overlay, each drawing\n"
01453   "      action will cause a re-rendering.  This works well if you have\n"
01454   "      set the renderer's 'Color Opacity' to 'ShowThru'.  This is also\n"
01455   "      a lot of fun.\n"
01456   "  * If you are drawing anatomically-based ROIs, you can only draw every\n"
01457   "      5th slice (say) and then use program 3dRowFillin to fill in the\n"
01458   "      inter-slice gaps.\n"
01459   "  * Edit at your own risk!  You can destroy datasets this way.\n"
01460   "    Be careful out there.\n"
01461   "\n"
01462   "SUGGESTIONS?\n"
01463   "  * Please send them to " COXEMAIL "\n"
01464   "  * Better than suggestions are implementations.\n"
01465   "  * Better than implementations are pumpernickel bagels.\n"
01466   "Author -- RW Cox"
01467 
01468     , TEXT_READONLY ) ;
01469    return ;
01470 }
01471 
01472 /*-------------------------------------------------------------------
01473   Callback for choose button.
01474   Criteria for datasets that can be edited:
01475     - must be in current session
01476     - must have actual bricks
01477     - only datasets with nvals=1 can be edited
01478     - bricks must be on same grid (dataxes) as AFNI controller
01479   Much of this code is adapted from PLUG_choose_dataset_CB.
01480 ---------------------------------------------------------------------*/
01481 
01482 static int                  ndsl = 0 ;
01483 static PLUGIN_dataset_link * dsl = NULL ;
01484 
01485 void DRAW_choose_CB( Widget w, XtPointer client_data, XtPointer call_data )
01486 {
01487    THD_session * ss  = im3d->ss_now ;           /* current session */
01488    int           vv  = im3d->vinfo->view_type ; /* view type */
01489    THD_3dim_dataset * qset ;
01490    int id , ltop , llen ;
01491    char qnam[THD_MAX_NAME] , label[THD_MAX_NAME] ;
01492    static char ** strlist = NULL ;
01493 
01494    /* can't do this if a dataset is already active and changed */
01495 
01496    if( dset != NULL && dset_changed ){
01497       (void) MCW_popup_message( choose_pb ,
01498                                    "Can't change datasets until\n"
01499                                    "you save the changes you've\n"
01500                                    "already made.  Or you could\n"
01501                                    "'Quit' and re-start the Editor" ,
01502                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
01503       XBell(dc->display,100) ; return ;
01504    }
01505 
01506    /* initialize */
01507 
01508    ndsl = 0 ;
01509 
01510    /* scan datasets */
01511 
01512    for( id=0 ; id < ss->num_dsset ; id++ ){
01513       qset = ss->dsset[id][vv] ;
01514 
01515       if( ! ISVALID_DSET (qset)                        ) continue ;  /* skip */
01516       if( ! DSET_INMEMORY(qset)                        ) continue ;
01517       if( DSET_NVALS(qset) > 1                         ) continue ;
01518       if( ! EQUIV_DATAXES(qset->daxes,im3d->wod_daxes) ) continue ;
01519 
01520       ndsl++ ;
01521       dsl = (PLUGIN_dataset_link *)
01522               XtRealloc( (char *) dsl , sizeof(PLUGIN_dataset_link)*ndsl ) ;
01523 
01524       make_PLUGIN_dataset_link( qset , dsl + (ndsl-1) ) ;
01525    }
01526 
01527    /* found nothing?  exit */
01528 
01529    if( ndsl < 1 ){
01530       (void) MCW_popup_message( choose_pb ,
01531                                    " \n"
01532                                    "Didn't find any datasets to edit!\n"
01533                                    "Check if:\n"
01534                                    " - you are in 'Warp-on-Demand' mode\n"
01535                                    " - you are in the correct session\n"
01536                                    "Also:\n"
01537                                    " * Only datasets with 1 sub-brick can\n"
01538                                    "    be edited.\n"
01539                                    " * The dataset must match the resolution\n"
01540                                    "    of the current anatomical view.\n"
01541                                , MCW_USER_KILL | MCW_TIMER_KILL ) ;
01542       XBell(dc->display,100) ; return ;
01543    }
01544 
01545    /*--- 23 Nov 1996: loop over dataset links and patch their titles
01546                       to include an indicator of the dataset type    ---*/
01547 
01548    ltop = 4 ;
01549    for( id=0 ; id < ndsl ; id++ ){
01550       llen = strlen(dsl[id].title) ;
01551       ltop = MAX(ltop,llen) ;
01552    }
01553 
01554    for( id=0 ; id < ndsl ; id++ ){
01555       qset = PLUTO_find_dset( &(dsl[id].idcode) ) ;
01556       if( ! ISVALID_DSET(qset) ) continue ;
01557       if( ISANAT(qset) ){
01558          if( ISANATBUCKET(qset) )         /* 30 Nov 1997 */
01559             sprintf(qnam,"%-*s [%s:%d]" ,
01560                     ltop,dsl[id].title ,
01561                     ANAT_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
01562 
01563          else if( DSET_NUM_TIMES(qset) == 1 )
01564             sprintf(qnam,"%-*s [%s]" ,
01565                     ltop,dsl[id].title ,
01566                     ANAT_prefixstr[qset->func_type] ) ;
01567 
01568          else
01569             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
01570                     ltop,dsl[id].title ,
01571                     ANAT_prefixstr[qset->func_type] , DSET_NUM_TIMES(qset) ) ;
01572 
01573       } else {
01574          if( ISFUNCBUCKET(qset) )         /* 30 Nov 1997 */
01575             sprintf(qnam,"%-*s [%s:%d]" ,
01576                     ltop,dsl[id].title ,
01577                     FUNC_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
01578 
01579          else if( DSET_NUM_TIMES(qset) == 1 )
01580             sprintf(qnam,"%-*s [%s]" ,
01581                     ltop,dsl[id].title ,
01582                     FUNC_prefixstr[qset->func_type] ) ;
01583 
01584          else
01585             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
01586                     ltop,dsl[id].title ,
01587                     FUNC_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
01588       }
01589 
01590       if( DSET_COMPRESSED(qset) ) strcat(qnam,"z") ;
01591 
01592       strcpy( dsl[id].title , qnam ) ;
01593    }
01594 
01595    /*--- make a popup chooser for the user to browse ---*/
01596 
01597    POPDOWN_strlist_chooser ;
01598 
01599    strlist = (char **) XtRealloc( (char *)strlist , sizeof(char *)*ndsl ) ;
01600    for( id=0 ; id < ndsl ; id++ ) strlist[id] = dsl[id].title ;
01601 
01602    sprintf( label , "AFNI Dataset from\nthe %s" , VIEW_typestr[vv] ) ;
01603 
01604    MCW_choose_strlist( w , label , ndsl , -1 , strlist ,
01605                        DRAW_finalize_dset_CB , NULL     ) ;
01606 
01607    return ;
01608 }
01609 
01610 /*-----------------------------------------------------------------------------*/
01611 
01612 void DRAW_finalize_dset_CB( Widget w, XtPointer fd, MCW_choose_cbs *cbs )
01613 {
01614    int id=cbs->ival , copied=0 ;
01615    THD_3dim_dataset * qset ;
01616    XmString xstr ;
01617    char str[256] , *dtit ;
01618    THD_slist_find slf ;   /* 29 Jul 2003 */
01619    MCW_choose_cbs cbss ;
01620 
01621    /*-- check for errors --*/
01622 
01623    if( !editor_open ){ POPDOWN_strlist_chooser; XBell(dc->display,100); return; }
01624 
01625    if( dset != NULL && dset_changed ){ XBell(dc->display,100) ; return ; }
01626 
01627    if( id < 0 || id >= ndsl ){ XBell(dc->display,100) ; return ; }
01628 
01629    qset = PLUTO_find_dset( &(dsl[id].idcode) ) ;  /* the new dataset? */
01630 
01631    if( qset == NULL ){ XBell(dc->display,100) ; return ; }
01632 
01633    if( ! EQUIV_DATAXES( im3d->wod_daxes , qset->daxes ) ){
01634       XBell(dc->display,100) ; return ;
01635    }
01636 
01637    /*-- 24 Sep 2001: make a copy of the dataset, if desired --*/
01638 
01639    if( MCW_val_bbox(copy_bbox) != 0 ){
01640       THD_3dim_dataset *cset ;
01641       int zfill , ftype , dtype ;
01642 
01643       zfill = (copy_mode_av->ival == 1) ;     /* zero fill? */
01644 
01645       switch( copy_type_av->ival ){
01646          default: ftype = -1 ; break ;        /* As Is */
01647          case 1:  ftype =  1 ; break ;        /* Func  */
01648          case 2:  ftype =  2 ; break ;        /* Anat  */
01649       }
01650 
01651       switch( copy_datum_av->ival ){
01652          default: dtype = -1        ; break ; /* As Is */
01653          case 1:  dtype = MRI_byte  ; break ; /* Byte  */
01654          case 2:  dtype = MRI_short ; break ; /* Short */
01655          case 3:  dtype = MRI_float ; break ; /* Float */
01656       }
01657 
01658       cset = DRAW_copy_dset( qset , zfill,ftype,dtype ) ; /* make copy! */
01659 
01660       if( cset == NULL ){                                 /* this is bad */
01661          (void) MCW_popup_message( choose_pb ,
01662                                      " \n"
01663                                      "*** Cannot make copy of input   ***\n"
01664                                      "*** dataset for unknown reasons ***\n " ,
01665                                    MCW_USER_KILL ) ;
01666          XBell(dc->display,100) ; return ;
01667       }
01668 
01669       DSET_unload(qset) ;
01670       PLUTO_add_dset( plint , cset , DSET_ACTION_MAKE_CURRENT ) ;
01671       qset = cset ; copied = 1 ;
01672    }
01673 
01674    /*-- accept this dataset --*/
01675 
01676    dset = qset ; dset_changed = 0 ;
01677    dax_save = *(dset->daxes) ;
01678    dset_idc = dset->idcode ;   /* 31 Mar 1999 */
01679 
01680    SENSITIZE(save_pb,0) ; SENSITIZE(saveas_pb,0) ;
01681 
01682    /*-- write the informational label --*/
01683 
01684    if( copied ) dtit = DSET_FILECODE(dset) ;  /* 24 Sep 2001 */
01685    else         dtit = dsl[id].title ;
01686 
01687    if( DSET_BRICK_FACTOR(dset,0) == 0.0 ){
01688       strcpy(str,dtit) ;
01689    } else {
01690       char abuf[16] ;
01691       AV_fval_to_char( DSET_BRICK_FACTOR(dset,0) , abuf ) ;
01692       sprintf(str,"%s\nbrick factor: %s", dtit , abuf ) ;
01693    }
01694    xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
01695    XtVaSetValues( info_lab , XmNlabelString , xstr , NULL ) ;
01696    XmStringFree(xstr) ;
01697 
01698    /*-- setup AFNI for drawing --*/
01699 
01700    if( ! recv_open ){
01701       recv_key = id = AFNI_receive_init( im3d, RECEIVE_DRAWING_MASK   |
01702                                                RECEIVE_DSETCHANGE_MASK ,  /* 31 Mar 1999 */
01703                                          DRAW_receiver,NULL ,
01704                                         "DRAW_receiver" ) ;
01705 
01706       if( id < 0 ){
01707          (void) MCW_popup_message( im3d->vwid->top_shell ,
01708                                      "Unable to establish\n"
01709                                      "connection to AFNI\n"
01710                                      "drawing routines!" ,
01711                                    MCW_USER_KILL | MCW_TIMER_KILL ) ;
01712 
01713          dset = NULL ; XBell(dc->display,100) ; return ;
01714       }
01715    }
01716 
01717    DSET_mallocize(dset) ; DSET_lock(dset) ; DSET_load(dset) ;
01718 
01719    AFNI_receive_control( im3d, recv_key,mode_index , NULL ) ;
01720    AFNI_receive_control( im3d, recv_key,DRAWING_OVCINDEX, (void *)color_index ) ;
01721    recv_open = 1 ;
01722 
01723    CLEAR_UNREDOBUF ;  /* 19 Nov 2003 */
01724 
01725    /* 29 Jul 2003: switch to this dataset */
01726 
01727    slf = THD_dset_in_session( FIND_IDCODE , &(dset->idcode) , im3d->ss_now ) ;
01728    if( slf.dset_index >= 0 ){
01729      cbss.ival = slf.dset_index ;
01730      if( ISFUNC(dset) ){
01731        AFNI_finalize_dataset_CB( im3d->vwid->view->choose_func_pb ,
01732                                  (XtPointer) im3d ,  &cbss         ) ;
01733        AFNI_SEE_FUNC_ON(im3d) ; /* 30 Apr 2002 */
01734      } else {
01735        AFNI_finalize_dataset_CB( im3d->vwid->view->choose_anat_pb ,
01736                                  (XtPointer) im3d ,  &cbss         ) ;
01737      }
01738    }
01739 
01740    /* 20 Oct 2003: get VALUE_LABEL_DTABLE, if present */
01741 
01742    if( vl_dtable != NULL ){ destroy_Dtable(vl_dtable); vl_dtable = NULL; }
01743 
01744    { ATR_string *atr ;
01745      atr = THD_find_string_atr( dset->dblk , "VALUE_LABEL_DTABLE" ) ;
01746      if( atr != NULL && atr->nch > 5 )
01747        vl_dtable = Dtable_from_nimlstring( atr->ch ) ;
01748      if( vl_dtable == NULL ){
01749        char *str = AFNI_suck_file( getenv("AFNI_VALUE_LABEL_DTABLE") ) ;
01750        if( str != NULL ){ vl_dtable = Dtable_from_nimlstring(str); free(str); }
01751      }
01752      DRAW_set_value_label() ;
01753    }
01754 
01755    return ;
01756 }
01757 
01758 /*-------------------------------------------------------------------
01759   Callback for color menu
01760 ---------------------------------------------------------------------*/
01761 
01762 void DRAW_color_CB( MCW_arrowval * av , XtPointer cd )
01763 {
01764    color_index = av->ival ;
01765 
01766    if( dset != NULL && recv_open )
01767       AFNI_receive_control( im3d, recv_key,DRAWING_OVCINDEX, (void *)color_index ) ;
01768 
01769    return ;
01770 }
01771 
01772 /*-------------------------------------------------------------------
01773   Callback for mode menu
01774 ---------------------------------------------------------------------*/
01775 
01776 void DRAW_mode_CB( MCW_arrowval * av , XtPointer cd )
01777 {
01778    mode_ival  = av->ival ;
01779    mode_index = mode_ints[mode_ival] ;
01780 
01781    if( dset != NULL && recv_open ){
01782       AFNI_receive_control( im3d, recv_key,mode_index , NULL ) ;
01783 
01784       /* 08 Oct 2002: set drawing line width */
01785 
01786       AFNI_receive_control( im3d, recv_key, DRAWING_LINEWIDTH ,
01787                             (void *) mode_width[mode_ival]     ) ;
01788    }
01789 
01790    /* 16 Oct 2002: turn rad_av (radius) on if mode needs it */
01791 
01792    ENABLE_rad_av ;
01793 
01794    return ;
01795 }
01796 
01797 /*-------------------------------------------------------------------
01798   Callback for value menu
01799 ---------------------------------------------------------------------*/
01800 
01801 void DRAW_value_CB( MCW_arrowval * av , XtPointer cd )
01802 {
01803    value_int   = av->ival ;
01804    value_float = av->fval ;
01805 
01806    if( value_float != 0.0 ){
01807      XtSetSensitive( label_label , True ) ;
01808      XtSetSensitive( label_textf , True ) ;
01809    } else {
01810      XtSetSensitive( label_label , False ) ;
01811      XtSetSensitive( label_textf , False ) ;
01812    }
01813    DRAW_set_value_label() ;
01814    return ;
01815 }
01816 
01817 /*---------------------------------------------------------------------
01818   Callbacks and functions for value label and text field [15 Oct 2003]
01819 -----------------------------------------------------------------------*/
01820 
01821 static void dump_vallab(void)
01822 {
01823 #if 0
01824    char *str = Dtable_to_nimlstring( vl_dtable , "VALUE_LABEL_DTABLE" ) ;
01825    if( str != NULL ){ printf("%s\n",str); free(str); }
01826    return ;
01827 #endif
01828 }
01829 
01830 /*---------------------------------------------------------------------*/
01831 
01832 char * DRAW_value_string( float val )  /* returns a fixed pointer! */
01833 {
01834    static char str[32] ;
01835    sprintf(str,"%.5g",val) ;
01836    return str ;
01837 }
01838 
01839 /*---------------------------------------------------------------------*/
01840 
01841 void DRAW_set_value_label(void)
01842 {
01843    if( vl_dtable == NULL || value_float == 0.0 ){
01844      XmTextFieldSetString( label_textf , "" ) ;
01845    } else {
01846      char *str_val = DRAW_value_string( value_float ) ;
01847      char *str_lab = findin_Dtable_a( str_val , vl_dtable ) ;
01848      XmTextFieldSetString( label_textf ,
01849                            (str_lab != NULL) ? str_lab : "" ) ;
01850    }
01851    return ;
01852 }
01853 
01854 /*---------------------------------------------------------------------*/
01855 
01856 void DRAW_label_CB( Widget wtex , XtPointer cld, XtPointer cad )
01857 {
01858    char *str_val , *str_lab , *str_old ;
01859    int ll , ii ;
01860 
01861    /* get string from text field, see if it is empty or ends in blanks */
01862 
01863    str_lab = XmTextFieldGetString( label_textf ) ;
01864    if( str_lab == NULL ){
01865      if( vl_dtable == NULL ) return ;  /* do nothing */
01866    } else {
01867      ll = strlen(str_lab) ;
01868      for( ii=ll-1 ; ii >= 0 && isspace(str_lab[ii]) ; ii-- ) ; /* nada */
01869      if( ii < 0 ){                       /*-- all blanks */
01870        if( vl_dtable == NULL ) return ;    /* do nothing */
01871        free(str_lab) ; str_lab = NULL ;    /* otherwise, clobber entry */
01872      } else if( ii < ll-1 ){             /*-- ends in blanks */
01873        str_lab[ii+1] = '\0' ;              /* so truncate them */
01874      }
01875    }
01876 
01877    /* create (value,label) pair Dtable -- NULL label ==> erase old label */
01878 
01879    if( vl_dtable == NULL ) vl_dtable = new_Dtable(7) ;
01880 
01881    str_val = DRAW_value_string( value_float ) ;   /* value string */
01882 
01883    /* check if old label for this value is same as new label;
01884       if it is, then don't need to do anything                */
01885 
01886    str_old = findin_Dtable_a( str_val , vl_dtable ) ;
01887    if( str_old != NULL ){
01888      if( str_lab != NULL && strcmp(str_old,str_lab) == 0 ){  /* same as old */
01889        free(str_lab) ; return ;
01890      } else if( str_lab == NULL ){                     /* erase the old one */
01891        removefrom_Dtable_a( str_val , vl_dtable ) ;
01892        dump_vallab() ;
01893        return ;
01894      }
01895    }
01896    if( str_lab == NULL ) return ;  /* is NULL ==> nothing to do here */
01897 
01898    /* check if new label is already in the table under a different value */
01899 
01900    str_old = findin_Dtable_b( str_lab , vl_dtable ) ;
01901    if( str_old != NULL && strcmp(str_old,str_val) != 0 ){
01902      char msg[1024] ;
01903      sprintf(msg," \n"
01904                  " *********************************** \n"
01905                  " ** ERROR * ERROR * ERROR * ERROR ** \n"
01906                  " **\n"
01907                  " ** Label = %s\n"
01908                  " **   is already associated with\n"
01909                  " ** Value = %s\n"
01910                  " **\n"
01911                  " ** Value,Label pairs must be unique \n"
01912                  " *********************************** \n"
01913              , str_lab , str_old ) ;
01914      (void) MCW_popup_message( label_textf , msg , MCW_USER_KILL ) ;
01915      PLUTO_beep() ;
01916      free(str_lab) ; return ;
01917    }
01918 
01919    /* add new value,label pair to Dtable (will clobber old one, if present) */
01920 
01921    addto_Dtable( str_val , str_lab , vl_dtable ) ;
01922    free(str_lab) ;
01923 
01924    dump_vallab() ;
01925    return ;
01926 }
01927 
01928 /*--------------------------------------------------------------------------*/
01929 
01930 static char **vl_strlist=NULL ;
01931 static  int  vl_nstrlist=0 ;
01932 
01933 static void DRAW_label_finalize( Widget w, XtPointer cd, MCW_choose_cbs *cbs )
01934 {
01935    int ival = cbs->ival , nn ;
01936    float val=0.0 ;
01937 
01938    if( !editor_open ){ PLUTO_beep(); POPDOWN_strlist_chooser; return; }
01939 
01940    nn = sscanf( vl_strlist[ival] , "%f" , &val ) ;
01941    if( nn == 0 || val == 0.0 ) return ;
01942 
01943    AV_assign_fval( value_av ,  val ) ;
01944    value_int   = value_av->ival ;
01945    value_float = value_av->fval ;
01946    DRAW_set_value_label() ;
01947    return ;
01948 }
01949 
01950 /*---------------------------------------------------------------------*/
01951 
01952 static void DRAW_label_getfile( Widget w, XtPointer cd, MCW_choose_cbs *cbs )
01953 {
01954    char *str ;
01955 
01956    if( !editor_open ){ PLUTO_beep(); POPDOWN_string_chooser; return; }
01957 
01958    str = AFNI_suck_file( cbs->cval ) ;
01959    if( str != NULL ){
01960      if( vl_dtable != NULL ) destroy_Dtable(vl_dtable) ;
01961      vl_dtable = Dtable_from_nimlstring(str) ;
01962      DRAW_set_value_label() ;
01963    } else {
01964      PLUTO_beep() ;
01965    }
01966    return ;
01967 }
01968 
01969 /*---------------------------------------------------------------------*/
01970 
01971 void DRAW_label_EV( Widget w , XtPointer cld ,
01972                     XEvent *ev , Boolean *continue_to_dispatch )
01973 {
01974 
01975    /* handle leave event in text field */
01976 
01977    if( w == label_textf ){
01978      XmAnyCallbackStruct cbs ;
01979      XLeaveWindowEvent *lev = (XLeaveWindowEvent *) ev ;
01980      if( lev->type != LeaveNotify ) return ;
01981      cbs.reason = XmCR_ACTIVATE ;  /* simulate a return press */
01982      DRAW_label_CB( w , NULL , &cbs ) ;
01983    }
01984 
01985    /* handle Button-3 press in label */
01986 
01987    else if( w == label_label ){
01988      XButtonEvent *bev = (XButtonEvent *) ev ;
01989      int nn,ic,ll ; char **la, **lb ; float val ;
01990 
01991      if( bev->button == Button1 ){
01992        MCW_choose_string( w , "Enter Value-Label filename:" ,
01993                           NULL , DRAW_label_getfile , NULL   ) ;
01994        return ;
01995      }
01996      if( bev->button != Button3 ) return ;
01997      nn = listize_Dtable( vl_dtable , &la , &lb ) ;
01998      if( nn <= 0 || la == NULL || lb == NULL ) return ;
01999 
02000      /** get ready to popup a new list chooser **/
02001 
02002      POPDOWN_strlist_chooser ;
02003 
02004      /** clear old strings **/
02005 
02006      for( ic=0 ; ic < vl_nstrlist ; ic++ ) free(vl_strlist[ic]) ;
02007 
02008      /** make a list of value-label strings **/
02009 
02010      vl_nstrlist = nn ;
02011      vl_strlist  = (char **) realloc( vl_strlist , sizeof(char *)*vl_nstrlist ) ;
02012      for( nn=ic=0 ; ic < vl_nstrlist ; ic++ ){
02013        if( la[ic] != NULL && lb[ic] != NULL ){  /* should always be true */
02014          ll = strlen(la[ic])+strlen(lb[ic])+8 ;
02015          vl_strlist[nn] = calloc(1,ll) ;
02016          sprintf( vl_strlist[nn] , "%s = %s" , la[ic],lb[ic] ) ;
02017          nn++ ;
02018        }
02019      }
02020      free(la); free(lb); if( nn == 0 ) return ;
02021 
02022      /* sort list for the user's convenience */
02023 
02024      if( nn > 1 ){
02025        int redo ; char *t ;
02026       BSort:
02027        for( redo=ic=0 ; ic < nn-1 ; ic++ ){
02028          if( strcmp(vl_strlist[ic],vl_strlist[ic+1]) > 0 ){
02029            t=vl_strlist[ic]; vl_strlist[ic]=vl_strlist[ic+1]; vl_strlist[ic+1]=t;
02030            redo = 1 ;
02031          }
02032        }
02033        if( redo ) goto BSort ;
02034      }
02035 
02036      /* find current value in list, if any */
02037 
02038      for( ic=0 ; ic < nn ; ic++ ){
02039        sscanf( vl_strlist[ic] , "%f" , &val ) ;
02040        if( val == value_float ) break ;
02041      }
02042      if( ic == nn ) ic = -1 ;
02043 
02044      /* let the user choose one */
02045 
02046      MCW_choose_strlist( w , "Value = Label" , nn ,
02047                          ic , vl_strlist , DRAW_label_finalize , NULL ) ;
02048    }
02049 
02050    return ;
02051 }
02052 
02053 /*---------------------------------------------------------------------*/
02054 
02055 void DRAW_attach_dtable( Dtable *dt, char *atname, THD_3dim_dataset *ds )
02056 {
02057    char *str ;
02058    if( dt == NULL || atname == NULL || ds == NULL ) return ;
02059    str = Dtable_to_nimlstring( dt , atname ) ;
02060    if( str == NULL ) return ;
02061    THD_set_string_atr( ds->dblk , atname , str ) ;
02062    free(str) ; return ;
02063 }
02064 
02065 /*******************************************************************
02066    Receive data from AFNI after drawing, etc.
02067 ********************************************************************/
02068 
02069 void DRAW_receiver( int why , int np , void * vp , void * cbd )
02070 {
02071    switch( why ){
02072 
02073       default:
02074          fprintf(stderr,"DRAW_receiver: illegal why=%d\n",why) ;
02075       return ;
02076 
02077       /*-- we like this one --*/
02078 
02079       case RECEIVE_POINTS:{
02080          int **ip = (int **)vp ;
02081          int *xd=ip[0] , *yd=ip[1] , *zd=ip[2] ; /* pts coords */
02082          int mode=ip[3][0] ;                     /* how pts are organized */
02083          int plane ;
02084 
02085          /*-- 20 Feb 2003: undo via keypress --*/
02086 
02087          if( mode == UNDO_MODE ){
02088            if( undo_num > 0 ) DRAW_undo_CB( undo_pb,NULL,NULL ) ;
02089            else               XBell(dc->display,100) ;
02090            return ;
02091          }
02092 
02093          /*-- Did we get points? --*/
02094 
02095          if( np <= 0 ) return ;
02096 
02097          plane = mode - SINGLE_MODE ;
02098          if( plane < 1 || plane > 3 ) plane = mode - PLANAR_MODE ;
02099          if( plane < 1 || plane > 3 ) plane = 0 ;
02100 
02101          /* anything but flood mode --> just draw given points */
02102 
02103          if( plane == 0 ||
02104              ((mode_ival != MODE_FLOOD_VAL )  &&
02105               (mode_ival != MODE_FLOOD_NZ  )  &&
02106               (mode_ival != MODE_FLOOD_ZERO)  &&
02107               (mode_ival != MODE_ZERO_VAL  )  &&
02108               (mode_ival != MODE_FLOOD_VZ  )  &&
02109               (mode_ival != MODE_FILLED    ))   ){
02110 
02111             /* 07 Oct 2002: expand set of points using a mask? */
02112 
02113             if( plane != 0 && mode_ival >= FIRST_2D_MODE && mode_ival <= LAST_2D_MODE ){
02114               int nfill=0, *xyzf=NULL ;
02115 
02116               DRAW_2D_expand( np , xd,yd,zd , plane , &nfill , &xyzf ) ;
02117               if( nfill > 0 && xyzf != NULL ){
02118                 DRAW_into_dataset( nfill , xyzf,NULL,NULL , NULL ) ;
02119                 free(xyzf) ;
02120               }
02121 
02122             } else if( plane != 0 && mode_ival >= FIRST_3D_MODE && mode_ival <= LAST_3D_MODE ){
02123               int nfill=0, *xyzf=NULL ;
02124 
02125               DRAW_3D_expand( np , xd,yd,zd , plane , &nfill , &xyzf ) ;
02126               if( nfill > 0 && xyzf != NULL ){
02127                 DRAW_into_dataset( nfill , xyzf,NULL,NULL , NULL ) ;
02128                 free(xyzf) ;
02129               }
02130 
02131             /* 16 Oct 2002: expand geometrically (circle or sphere)? */
02132 
02133             } else if( plane != 0 && mode_ival >= FIRST_RAD_MODE && mode_ival <= LAST_RAD_MODE ){
02134               int nfill=0, *xyzf=NULL ;
02135 
02136               switch( mode_ival ){
02137                 case MODE_2D_CIRC:
02138                   DRAW_2D_circle( np , xd,yd,zd , plane , &nfill , &xyzf ) ;
02139                 break ;
02140                 case MODE_3D_SPHR:
02141                   DRAW_3D_sphere( np , xd,yd,zd , plane , &nfill , &xyzf ) ;
02142                 break ;
02143               }
02144 
02145               if( nfill > 0 && xyzf != NULL ){
02146                 DRAW_into_dataset( nfill , xyzf,NULL,NULL , NULL ) ;
02147                 free(xyzf) ;
02148               } else {
02149                 DRAW_into_dataset( np , xd,yd,zd , NULL ) ; /* should never happen */
02150               }
02151 
02152             } else {                                        /* the old way:     */
02153               DRAW_into_dataset( np , xd,yd,zd , NULL ) ;   /* just draw points */
02154             }
02155 
02156          } else {
02157 
02158             /* flood mode! */
02159 
02160             int   ityp = DSET_BRICK_TYPE(dset,0) ;
02161             float bfac = DSET_BRICK_FACTOR(dset,0) ;
02162             int nx=DSET_NX(dset) , ny=DSET_NY(dset) , nz=DSET_NZ(dset) ,
02163                 nxy = nx*ny , nxyz = nxy*nz , ii,jj , ixyz ;
02164             int base , di,dj , itop,jtop,nij , xx=xd[0],yy=yd[0],zz=zd[0] , ix,jy ;
02165             byte * pl ;
02166             int nfill , *xyzf , nf ;
02167 
02168             /* compute stuff for which plane we are in:
02169                 1 -> yz , 2 -> xz , 3 -> xy            */
02170 
02171             switch(plane){
02172               case 1: base=xx    ; di=nx; dj=nxy; itop=ny; jtop=nz; ix=yy; jy=zz; break;
02173               case 2: base=yy*nx ; di=1 ; dj=nxy; itop=nx; jtop=nz; ix=xx; jy=zz; break;
02174               case 3: base=zz*nxy; di=1 ; dj=nx ; itop=nx; jtop=ny; ix=xx; jy=yy; break;
02175             }
02176 
02177             /* create a 2D array with 0 where dataset != blocking value
02178                              and with 1 where dataset == blocking value */
02179 
02180             nij = itop*jtop ;
02181             pl  = (byte *) calloc( nij , sizeof(byte) ) ;
02182 
02183             if( mode_ival != MODE_FILLED ){  /* old code: flood to a dataset value */
02184 
02185               if( bfac == 0.0 ) bfac = 1.0 ;
02186               switch(ityp){
02187 
02188                  case MRI_short:{
02189                     short * bp  = (short *) DSET_BRICK_ARRAY(dset,0) ;
02190                     short   val = (short)   (value_float/bfac) ;
02191 
02192                     if( mode_ival == MODE_FLOOD_ZERO ) val = 0 ;
02193 
02194                     if( mode_ival == MODE_FLOOD_VAL  ||
02195                         mode_ival == MODE_FLOOD_ZERO || mode_ival == MODE_ZERO_VAL ){
02196                        for( jj=0 ; jj < jtop ; jj++ )
02197                           for( ii=0 ; ii < itop ; ii++ ){
02198                              ixyz = base + ii*di + jj*dj ;
02199                              if( bp[ixyz] == val ) pl[ii+jj*itop] = 1 ;
02200                           }
02201                     } else if( mode_ival == MODE_FLOOD_VZ ){  /* 30 Apr 2002 */
02202                        for( jj=0 ; jj < jtop ; jj++ )
02203                           for( ii=0 ; ii < itop ; ii++ ){
02204                              ixyz = base + ii*di + jj*dj ;
02205                              if( bp[ixyz] == val || bp[ixyz] == 0 ) pl[ii+jj*itop] = 1 ;
02206                           }
02207                     } else {
02208                        for( jj=0 ; jj < jtop ; jj++ )
02209                           for( ii=0 ; ii < itop ; ii++ ){
02210                              ixyz = base + ii*di + jj*dj ;
02211                              if( bp[ixyz] != 0 ) pl[ii+jj*itop] = 1 ;
02212                           }
02213                     }
02214                  }
02215                  break ;
02216 
02217                  case MRI_byte:{
02218                     byte * bp  = (byte *) DSET_BRICK_ARRAY(dset,0) ;
02219                     byte   val = (byte)   (value_float/bfac) ;
02220 
02221                     if( mode_ival == MODE_FLOOD_ZERO ) val = 0 ;
02222 
02223                     if( mode_ival == MODE_FLOOD_VAL  ||
02224                         mode_ival == MODE_FLOOD_ZERO || mode_ival == MODE_ZERO_VAL ){
02225                        for( jj=0 ; jj < jtop ; jj++ )
02226                           for( ii=0 ; ii < itop ; ii++ ){
02227                              ixyz = base + ii*di + jj*dj ;
02228                              if( bp[ixyz] == val ) pl[ii+jj*itop] = 1 ;
02229                           }
02230                     } else if( mode_ival == MODE_FLOOD_VZ ){  /* 30 Apr 2002 */
02231                        for( jj=0 ; jj < jtop ; jj++ )
02232                           for( ii=0 ; ii < itop ; ii++ ){
02233                              ixyz = base + ii*di + jj*dj ;
02234                              if( bp[ixyz] == val || bp[ixyz] == 0 ) pl[ii+jj*itop] = 1 ;
02235                           }
02236                     } else {
02237                        for( jj=0 ; jj < jtop ; jj++ )
02238                           for( ii=0 ; ii < itop ; ii++ ){
02239                              ixyz = base + ii*di + jj*dj ;
02240                              if( bp[ixyz] != 0 ) pl[ii+jj*itop] = 1 ;
02241                           }
02242                     }
02243                  }
02244                  break ;
02245 
02246                  case MRI_float:{
02247                     float * bp  = (float *) DSET_BRICK_ARRAY(dset,0) ;
02248                     float   val = (value_float/bfac) ;
02249 
02250                     if( mode_ival == MODE_FLOOD_ZERO ) val = 0 ;
02251 
02252                     if( mode_ival == MODE_FLOOD_VAL  ||
02253                         mode_ival == MODE_FLOOD_ZERO || mode_ival == MODE_ZERO_VAL ){
02254                        for( jj=0 ; jj < jtop ; jj++ )
02255                           for( ii=0 ; ii < itop ; ii++ ){
02256                              ixyz = base + ii*di + jj*dj ;
02257                              if( bp[ixyz] == val ) pl[ii+jj*itop] = 1 ;
02258                           }
02259                     } else if( mode_ival == MODE_FLOOD_VZ ){  /* 30 Apr 2002 */
02260                        for( jj=0 ; jj < jtop ; jj++ )
02261                           for( ii=0 ; ii < itop ; ii++ ){
02262                              ixyz = base + ii*di + jj*dj ;
02263                              if( bp[ixyz] == val || bp[ixyz] == 0 ) pl[ii+jj*itop] = 1 ;
02264                           }
02265                     } else {
02266                        for( jj=0 ; jj < jtop ; jj++ )
02267                           for( ii=0 ; ii < itop ; ii++ ){
02268                              ixyz = base + ii*di + jj*dj ;
02269                              if( bp[ixyz] != 0.0 ) pl[ii+jj*itop] = 1 ;
02270                           }
02271                     }
02272                  }
02273                  break ;
02274 
02275                  default:
02276                     free(pl) ;
02277                     fprintf(stderr,
02278                            "Flood not implemented for datasets of type %s\a\n",
02279                            MRI_TYPE_name[ityp] ) ;
02280                  return ;
02281 
02282               } /* end of switch on type */
02283 
02284               /* start point must be a 0 (can't fill from an edge) */
02285 
02286               if( pl[ix+jy*itop] == 1 ){
02287                  free(pl) ; XBell(dc->display,100) ; return ;
02288               }
02289 
02290               /* call a routine to fill the array */
02291 
02292               DRAW_2dfiller( itop,jtop , ix,jy , pl ) ;
02293 
02294               /* all filled points are 2 --> these are the locations to draw */
02295 
02296               nfill = 0 ;
02297               for( ii=0 ; ii < nij ; ii++ ) nfill += (pl[ii] == 2) ;
02298               if( nfill == 0 ){ free(pl) ; XBell(dc->display,100) ; return ; }
02299 
02300               xyzf = (int *) malloc( sizeof(int) * nfill ) ;
02301 
02302               for( nf=0,jj=0 ; jj < jtop ; jj++ ){
02303                  for( ii=0 ; ii < itop ; ii++ ){
02304                     if( pl[ii+jj*itop] == 2 )
02305                        xyzf[nf++] = base + ii*di + jj*dj ;
02306                  }
02307               }
02308 
02309               free(pl) ;
02310 
02311               if( mode_ival == MODE_ZERO_VAL ){ bfac = value_float; value_float = 0.0; }
02312 
02313               DRAW_into_dataset( nfill , xyzf,NULL,NULL , NULL ) ;
02314 
02315               if( mode_ival == MODE_ZERO_VAL ) value_float = bfac ;
02316 
02317               free(xyzf) ;
02318 
02319             } /*-- end of flood code --*/
02320 
02321             else {  /*-- 25 Sep 2001: fill the interior of the drawn curve --*/
02322 
02323               int *iip , *jjp ;
02324 
02325               switch(plane){                           /* select which   */
02326                 case 1: iip = yd ; jjp = zd ; break ;  /* arrays to draw */
02327                 case 2: iip = xd ; jjp = zd ; break ;  /* curve from     */
02328                 case 3: iip = xd ; jjp = yd ; break ;
02329               }
02330 
02331               for( ii=0 ; ii < np ; ii++ ){  /* draw curve into fill array */
02332                  pl[ iip[ii] + jjp[ii]*itop ] = 1 ;
02333               }
02334 
02335               /* now find an edge point that is not on the curve */
02336 
02337               ix = -1 ;
02338               for( ii=0 ; ii < itop ; ii++ ){
02339                  if( pl[ii]               == 0 ){ ix = ii; jy = 0     ; break; }
02340                  if( pl[ii+(jtop-1)*itop] == 0 ){ ix = ii; jy = jtop-1; break; }
02341               }
02342               if( ix < 0 ){
02343                 for( jj=0 ; jj < jtop ; jj++ ){
02344                   if( pl[jj*itop]          == 0 ){ ix = 0     ; jy = jj; break; }
02345                   if( pl[(itop-1)+jj*itop] == 0 ){ ix = itop-1; jy = jj; break; }
02346                 }
02347               }
02348               if( ix < 0 ){ /* should never happen */
02349                  free(pl) ; XBell(dc->display,100) ; return ;
02350               }
02351 
02352               /* fill the array from the edge */
02353 
02354               DRAW_2dfiller( itop,jtop , ix,jy , pl ) ;
02355 
02356               /* all filled points are 2 --> these are NOT the locations to draw */
02357 
02358               nfill = 0 ;
02359               for( ii=0 ; ii < nij ; ii++ ) nfill += (pl[ii] != 2) ;
02360               if( nfill == 0 ){ free(pl) ; XBell(dc->display,100) ; return ; }
02361 
02362               xyzf = (int *) malloc( sizeof(int) * nfill ) ;
02363 
02364               for( nf=0,jj=0 ; jj < jtop ; jj++ ){
02365                  for( ii=0 ; ii < itop ; ii++ ){
02366                     if( pl[ii+jj*itop] != 2 )
02367                        xyzf[nf++] = base + ii*di + jj*dj ;
02368                  }
02369               }
02370 
02371               free(pl) ;
02372 
02373               DRAW_into_dataset( nfill , xyzf,NULL,NULL , NULL ) ;
02374 
02375               free(xyzf) ;
02376 
02377             } /* end of interior fill code */
02378 
02379          } /* end of flooding or filling */
02380 
02381       } /* end of dealing with drawn points */
02382       break ;
02383 
02384       /*-- user closed the controller window!? (the fiend) */
02385 
02386       case RECEIVE_CLOSURE:{
02387          if( dset != NULL && dset_changed ) XBell(dc->display,100) ; /* protest */
02388          DRAW_quit_CB(NULL,NULL,NULL) ;                              /* and die */
02389       }
02390       break ;
02391 
02392       /*-- user altered the controller window!? */
02393 
02394       case RECEIVE_ALTERATION:{
02395 
02396          /* if we are already editing a dataset, then
02397             check if the grid has changed -- if it has, must quit */
02398 
02399          if( dset != NULL ){
02400             if( ! EQUIV_DATAXES( im3d->wod_daxes , &dax_save ) ){
02401                XBell(dc->display,100) ;        /* feeble protest */
02402                DRAW_quit_CB(NULL,NULL,NULL) ;  /* die */
02403 
02404                /* less feeble protest */
02405                (void) MCW_popup_message( im3d->vwid->top_shell ,
02406                                            "Controller grid was altered!\n"
02407                                            "Editor was forced to quit.\n"
02408                                            "Any un-Saved changes were lost." ,
02409                                          MCW_USER_KILL | MCW_TIMER_KILL ) ;
02410             }
02411          }
02412       }
02413       break ;
02414 
02415       /*-- user changed dataset pointers on us? --*/
02416 
02417       case RECEIVE_DSETCHANGE:{   /* 31 Mar 1999 */
02418          if( dset != NULL ){
02419             dset = PLUTO_find_dset( &dset_idc ) ;
02420             DSET_mallocize(dset) ; DSET_lock(dset) ; DSET_load(dset) ;
02421             if( dset_changed ){
02422                THD_load_statistics( dset ) ;
02423                PLUTO_dset_redisplay( dset ) ;
02424 
02425                XBell(dc->display,100) ;
02426                (void) MCW_popup_message( im3d->vwid->top_shell ,
02427                                             "********* WARNING *********\n"
02428                                             "* Session rescan may have *\n"
02429                                             "* caused loss of unsaved  *\n"
02430                                             "* editing changes!        *\n"
02431                                             "***************************"   ,
02432                                          MCW_USER_KILL | MCW_TIMER_KILL ) ;
02433             }
02434          }
02435       }
02436       break ;
02437 
02438    } /* end of switch on why */
02439 
02440    return ;
02441 }
02442 
02443 /*--------------------------------------------------------------------------
02444   Routine to draw into a dataset.
02445   If yd & zd are NULL, then xd is used as the direct 3D array index,
02446     otherwise xd,yd,zd are used as the 3-index.
02447   If var == NULL, then the value_av is used, otherwise the array var[]
02448     will be the source of the data.
02449 ----------------------------------------------------------------------------*/
02450 
02451 int DRAW_into_dataset( int np , int *xd , int *yd , int *zd , void *var )
02452 {
02453    int   ityp = DSET_BRICK_TYPE(dset,0) ;
02454    float bfac = DSET_BRICK_FACTOR(dset,0) ;
02455    int nx=DSET_NX(dset) , ny=DSET_NY(dset) , nz=DSET_NZ(dset) ,
02456        nxy = nx*ny , nxyz = nxy*nz , ii , ixyz ;
02457    int ndrawn=0 ;
02458    dobuf *sb ;  /* 19 Nov 2003: save buffer */
02459    int *xyz ;
02460 
02461    /* sanity check */
02462 
02463    if( dset==NULL || np <= 0 || xd==NULL ) return 0 ;
02464 
02465    /* make space for undo/redo (save old state in buffer) [19 Nov 2003] */
02466 
02467    CREATE_DOBUF(sb,np,ityp) ;
02468    xyz = sb->xyz ;             /* list of indexes to be altered */
02469 
02470    /* compute (or copy) data index into save buffer */
02471 
02472    if( yd == NULL ){                       /* direct supply of 1-index */
02473      memcpy(xyz,xd,sizeof(int)*np) ;
02474    } else {                                /* collapse 3-index into 1 */
02475      for( ii=0 ; ii < np ; ii++ )
02476        xyz[ii] = xd[ii] + yd[ii] * nx + zd[ii] * nxy ;
02477    }
02478 
02479    /* copy data into save buffer, based on type */
02480 
02481    if( bfac == 0.0 ) bfac = 1.0 ;
02482 
02483    switch( ityp ){
02484 
02485       default: fprintf(stderr,"Illegal brick type=%s in AFNI Editor!\n",
02486                        MRI_TYPE_name[ityp] ) ;
02487       break ;
02488 
02489 #define DOIT (infill_mode==0 || bp[ixyz]==0)
02490 
02491       case MRI_short:{
02492         short * bp  = (short *) DSET_BRICK_ARRAY(dset,0) ;
02493         short * up  = (short *) sb->buf ;
02494         short * vvv = (short *) var ;
02495         short   val = (short)   (value_float/bfac) ;
02496 
02497         for( ii=0 ; ii < np ; ii++ ){  /* save into buffer */
02498           ixyz = xyz[ii] ;
02499           up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : 0 ;
02500         }
02501         for( ii=0 ; ii < np ; ii++ ){  /* put into dataset */
02502           ixyz = xyz[ii] ;
02503           if( ixyz >= 0 && ixyz < nxyz && DOIT ){
02504             bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ; ndrawn++ ;
02505           }
02506         }
02507       }
02508       break ;
02509 
02510       case MRI_byte:{
02511         byte * bp  = (byte *) DSET_BRICK_ARRAY(dset,0) ;
02512         byte * up  = (byte *) sb->buf ;
02513         byte * vvv = (byte *) var ;
02514         byte   val = (byte)   (value_float/bfac) ;
02515 
02516         for( ii=0 ; ii < np ; ii++ ){
02517           ixyz = xyz[ii] ;
02518           up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : 0 ;
02519         }
02520         for( ii=0 ; ii < np ; ii++ ){
02521           ixyz = xyz[ii] ;
02522           if( ixyz >= 0 && ixyz < nxyz && DOIT ){
02523             bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ; ndrawn++ ;
02524           }
02525         }
02526       }
02527       break ;
02528 
02529       case MRI_float:{
02530         float * bp  = (float *) DSET_BRICK_ARRAY(dset,0) ;
02531         float * up  = (float *) sb->buf ;
02532         float * vvv = (float *) var ;
02533         float   val = (value_float/bfac) ;
02534 
02535         for( ii=0 ; ii < np ; ii++ ){
02536           ixyz = xyz[ii] ;
02537           up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : 0.0 ;
02538         }
02539         for( ii=0 ; ii < np ; ii++ ){
02540           ixyz = xyz[ii] ;
02541           if( ixyz >= 0 && ixyz < nxyz && DOIT ){
02542             bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ; ndrawn++ ;
02543           }
02544         }
02545       }
02546       break ;
02547 
02548       case MRI_complex:{
02549         complex * bp  = (complex *) DSET_BRICK_ARRAY(dset,0) ;
02550         complex * up  = (complex *) sb->buf ;
02551         complex * vvv = (complex *) var ;
02552         complex   val ;
02553         static complex cxzero = { 0.0 , 0.0 } ;
02554 
02555         val = CMPLX( (value_float/bfac) , 0.0 ) ;
02556 
02557         for( ii=0 ; ii < np ; ii++ ){
02558           ixyz = xyz[ii] ;
02559           up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : cxzero ;
02560         }
02561         for( ii=0 ; ii < np ; ii++ ){
02562           ixyz = xyz[ii] ;
02563           if( ixyz >= 0 && ixyz < nxyz && (infill_mode==0 || bp[ixyz].r==0) ){
02564             bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ; ndrawn++ ;
02565           }
02566         }
02567       }
02568       break ;
02569 
02570    } /* end of switch on brick type */
02571 
02572    /* recompute statistics */
02573 
02574    THD_load_statistics( dset ) ;
02575 
02576    /* now redisplay dataset, in case anyone is looking at it */
02577 
02578    PLUTO_dset_redisplay( dset ) ;
02579    dset_changed = 1 ;
02580    SENSITIZE(save_pb,1) ; SENSITIZE(saveas_pb,1) ;
02581    SENSITIZE(choose_pb,0) ;
02582 
02583    /* save buffer pushed onto appropriate stack */
02584 
02585    if( undo_how == 1 ){   /* save on redo stack */
02586      redo_stack = realloc( (void *)redo_stack, sizeof(dobuf *)*(redo_num+1) );
02587      redo_stack[redo_num++] = sb ;
02588      REDO_button_labelize ;
02589    } else {               /* save on undo stack */
02590      undo_stack = realloc( (void *)undo_stack, sizeof(dobuf *)*(undo_num+1) );
02591      undo_stack[undo_num++] = sb ;
02592      UNDO_button_labelize ;
02593      DRAW_undo_sizecheck() ;
02594      if( undo_how == 0 ){  /* normal draw ==> can't redo */
02595        CLEAR_REDOBUF ;
02596      }
02597    }
02598 
02599    return ndrawn ;
02600 }
02601 
02602 /*---------------------------------------------------------------------------*/
02603 /*!  Limit size of data allowed in undo buffers. [19 Nov 2003]
02604 -----------------------------------------------------------------------------*/
02605 
02606 static void DRAW_undo_sizecheck(void)
02607 {
02608   int ii,jj , ss , lim=6 ;
02609   char *eee ;
02610 
02611   if( undo_num <= 1 ) return ;  /* will always keep 1 level of undo */
02612 
02613   /* get the limit of allowed mem usage for the undo buffers */
02614 
02615   eee = getenv("AFNI_DRAW_UNDOSIZE") ;
02616   if( eee != NULL ){
02617     ii = 0 ; sscanf(eee,"%d",&ii) ;
02618     if( ii > 0 ) lim = ii ; if( lim > 1024 ) lim = 1024 ;
02619   }
02620   lim *= (1024*1024) ;  /* megabytes */
02621 
02622   /* scan from top of stack,
02623      stopping when total size goes over the limit */
02624 
02625   for( ss=0,ii=undo_num-1 ; ii >= 0 && ss < lim ; ii-- )
02626     ss += SIZEOF_DOBUF( undo_stack[ii] ) ;
02627 
02628   if( ii <= 0 ) return ;  /* didn't go over limit before bottom */
02629 
02630   /* if here, stack elements from 0..ii-1 should be removed
02631               and the elements above them moved down to fill in */
02632 
02633   for( jj=0 ; jj < ii ; jj++ )         /* removal */
02634     DESTROY_DOBUF( undo_stack[jj] ) ;
02635 
02636   for( jj=ii ; jj < undo_num ; jj++ )  /* move-al */
02637     undo_stack[jj-ii] = undo_stack[jj] ;
02638 
02639   undo_num = undo_num - ii ;
02640   return ;
02641 }
02642 
02643 /*---------------------------------------------------------------------------*/
02644 /*! Set label of Undo or Redo button to reflect number of levels
02645     available, and set sensitivity while we are at it.  [19 Nov 2003]
02646 -----------------------------------------------------------------------------*/
02647 
02648 static void DRAW_undo_butlab( Widget w , int n )
02649 {
02650    XmString xstr ;
02651    char label[32] ;
02652    int nfmt ;
02653    static char *fmt[3] = { "%s[%d]" , "%s:%d" , "%s%03d" } ;
02654 
02655    if( w == (Widget)NULL ) return ;  /* oom-possible? */
02656 
02657         if( n <  10  ) nfmt = 0 ;     /* choose format based */
02658    else if( n < 100  ) nfmt = 1 ;     /* on number of digits */
02659    else                nfmt = 2 ;
02660 
02661    sprintf( label, fmt[nfmt], (w==undo_pb) ? "Undo" : "Redo" , n%1000 ) ;
02662 
02663    xstr = XmStringCreateLtoR( label , XmFONTLIST_DEFAULT_TAG ) ;
02664    XtVaSetValues( w , XmNlabelString , xstr , NULL ) ;
02665    XmStringFree(xstr) ;
02666 
02667    SENSITIZE( w , (n>0) ) ;
02668    return ;
02669 }
02670 
02671 /*---------------------------------------------------------------------------
02672    Flood filling a byte array:
02673      nx = 1st dimension
02674      ny = 2nd dimension
02675      ix = start point
02676      jy = end point
02677      ar = array, with 0's everwhere except 1's as barriers to flooding
02678 
02679    All filled points (starting with ix,jy) will get the value 2.
02680 -----------------------------------------------------------------------------*/
02681 
02682 void DRAW_2dfiller( int nx , int ny , int ix , int jy , byte * ar )
02683 {
02684    int ii,jj , ip,jp , num ;
02685 
02686 #define AR(i,j) ar[(i)+(j)*nx]
02687 
02688    /* fill out in cross from 1st point */
02689 
02690    ip = ix ; jp = jy ; AR(ip,jp) = 2 ;
02691 
02692    for( ii=ip+1; ii < nx && AR(ii,jp) == 0; ii++ ) AR(ii,jp) = 2;
02693    for( ii=ip-1; ii >= 0 && AR(ii,jp) == 0; ii-- ) AR(ii,jp) = 2;
02694    for( jj=jp+1; jj < ny && AR(ip,jj) == 0; jj++ ) AR(ip,jj) = 2;
02695    for( jj=jp-1; jj >= 0 && AR(ip,jj) == 0; jj-- ) AR(ip,jj) = 2;
02696 
02697    /* brute force repetition of the cross technique */
02698 
02699    do {
02700       num = 0 ;
02701       for( jp=0 ; jp < ny ; jp++ ){
02702          for( ip=0 ; ip < nx ; ip++ ){
02703             if( AR(ip,jp) == 2 ){
02704                for( ii=ip+1; ii < nx && AR(ii,jp) == 0; ii++ ){ AR(ii,jp) = 2; num++; }
02705                for( ii=ip-1; ii >= 0 && AR(ii,jp) == 0; ii-- ){ AR(ii,jp) = 2; num++; }
02706                for( jj=jp+1; jj < ny && AR(ip,jj) == 0; jj++ ){ AR(ip,jj) = 2; num++; }
02707                for( jj=jp-1; jj >= 0 && AR(ip,jj) == 0; jj-- ){ AR(ip,jj) = 2; num++; }
02708             }
02709          }
02710       }
02711    } while( num > 0 ) ;
02712 
02713    return ;
02714 }
02715 
02716 /*----------------------------------------------------------------------------------*/
02717 
02718 void DRAW_fillin_CB( Widget w , XtPointer cd , XtPointer cb )
02719 {
02720    int dcode=-1 , maxgap , nftot ;
02721    char dir ;
02722    MRI_IMAGE *bim , *tbim ; /* 21 Nov 2003: to allow undo of fillin */
02723 
02724    /* check for errors */
02725 
02726    if( !editor_open || dset == NULL ){ XBell(dc->display,100); return; }
02727 
02728    dir = fillin_dir_strings[ fillin_dir_av->ival ][0] ;
02729 
02730    if( dir == ORIENT_tinystr[dset->daxes->xxorient][0] ||
02731        dir == ORIENT_tinystr[dset->daxes->xxorient][1]   ) dcode = 1 ;
02732 
02733    if( dir == ORIENT_tinystr[dset->daxes->yyorient][0] ||
02734        dir == ORIENT_tinystr[dset->daxes->yyorient][1]   ) dcode = 2 ;
02735 
02736    if( dir == ORIENT_tinystr[dset->daxes->zzorient][0] ||
02737        dir == ORIENT_tinystr[dset->daxes->zzorient][1]   ) dcode = 3 ;
02738 
02739    if( dcode < 0 ){ XBell(dc->display,100) ; return ; } /* should not happen! */
02740 
02741    maxgap = fillin_gap_av->ival ;
02742    if( maxgap < 1 ){ XBell(dc->display,100) ; return ; } /* should not happen! */
02743 
02744    bim  = DSET_BRICK(dset,0) ;  /* 21 Nov 2003: for undo */
02745    tbim = mri_copy( bim ) ;     /* copy brick before the change */
02746 
02747    nftot = THD_dataset_rowfillin( dset , 0 , dcode , maxgap ) ;
02748    if( nftot > 0 ){
02749      fprintf(stderr,"++ Fillin filled %d voxels\n",nftot) ;
02750      PLUTO_dset_redisplay( dset ) ;
02751      dset_changed = 1 ;
02752      SENSITIZE(save_pb,1) ; SENSITIZE(saveas_pb,1) ;
02753      if( recv_open ) AFNI_process_drawnotice( im3d ) ;
02754     
02755      { void *bar , *tbar ;     /* 21 Nov 2003: compute the undo stuff */
02756        int ityp=bim->kind, ii,jj, nvox=bim->nvox, ndel=0 ;
02757        dobuf *sb=NULL ;
02758        switch( ityp ){
02759          case MRI_short:{
02760            short *bar = MRI_SHORT_PTR(bim), *tbar = MRI_SHORT_PTR(tbim), *up ;
02761            for( ii=0 ; ii < nvox ; ii++ ) if( bar[ii] != tbar[ii] ) ndel++ ;
02762            if( ndel > 0 ){
02763              CREATE_DOBUF(sb,ndel,MRI_short) ; up = (short *)sb->buf ;
02764              for( ii=jj=0 ; ii < nvox ; ii++ )
02765                if( bar[ii] != tbar[ii] ){ sb->xyz[jj]=ii; up[jj++]=tbar[ii]; }
02766            }
02767          }
02768          break ;
02769          case MRI_float:{
02770            float *bar = MRI_FLOAT_PTR(bim), *tbar = MRI_FLOAT_PTR(tbim), *up ;
02771            for( ii=0 ; ii < nvox ; ii++ ) if( bar[ii] != tbar[ii] ) ndel++ ;
02772            if( ndel > 0 ){
02773              CREATE_DOBUF(sb,ndel,MRI_float) ; up = (float *)sb->buf ;
02774              for( ii=jj=0 ; ii < nvox ; ii++ )
02775                if( bar[ii] != tbar[ii] ){ sb->xyz[jj]=ii; up[jj++]=tbar[ii]; }
02776            }
02777          }
02778          break ;
02779          case MRI_byte:{
02780            byte *bar = MRI_BYTE_PTR(bim), *tbar = MRI_BYTE_PTR(tbim), *up ;
02781            for( ii=0 ; ii < nvox ; ii++ ) if( bar[ii] != tbar[ii] ) ndel++ ;
02782            if( ndel > 0 ){
02783              CREATE_DOBUF(sb,ndel,MRI_byte) ; up = (byte *)sb->buf ;
02784              for( ii=jj=0 ; ii < nvox ; ii++ )
02785                if( bar[ii] != tbar[ii] ){ sb->xyz[jj]=ii; up[jj++]=tbar[ii]; }
02786            }
02787          }
02788          break ;
02789        } /* end of switch on brick type */
02790 
02791        if( sb != NULL ){  /* if we created an undo buffer, push onto stack */
02792          undo_stack = realloc( (void *)undo_stack, sizeof(dobuf *)*(undo_num+1) );
02793          undo_stack[undo_num++] = sb ;
02794          UNDO_button_labelize ;
02795          DRAW_undo_sizecheck() ;
02796          CLEAR_REDOBUF ;         /* can't redo after a drawing */
02797        }
02798      } /* 21 Nov 2003: end of allowing for undo stuff */
02799 
02800    } else if( nftot < 0 ) {
02801       fprintf(stderr,"** Fillin failed for some reason!\n") ;
02802       XBell(dc->display,100) ;
02803    } else {
02804       fprintf(stderr,"++ No Fillin voxels found\n") ;
02805    }
02806 
02807    mri_free(tbim) ; /* 21 Nov 2003: toss old copy */
02808    return ;
02809 }
02810 
02811 /*--------------------------------------------------------------------------
02812    22 Aug 2001: TT Atlas Regions action callback
02813 ----------------------------------------------------------------------------*/
02814 
02815 void DRAW_ttatlas_CB( Widget w, XtPointer client_data, XtPointer call_data )
02816 {
02817    THD_3dim_dataset *dseTT ;
02818    byte *bb , *voxout , bval ;
02819    int nvoxTT, nvoxout , xx , brik , iv,jv,kv , ijk ;
02820    int hbot,htop , nzTT,nyTT,nxTT,nxyTT ,
02821        nxout,nyout,nzout,nxyout , i,j,k,ip,jp,kp , nftot ;
02822    float dxTT,dyTT,dzTT , xorgTT,yorgTT,zorgTT ;
02823    float dxout,dyout,dzout , xorgout,yorgout,zorgout ;
02824    float z1,z2 , y1,y2 , x1,x2 , xx1,xx2,yy1,yy2,zz1,zz2 ;
02825    float f1,f2,f , g1,g2,g , h1,h2,h , sx,sy,sz , tx,ty,tz , sxyz ;
02826    THD_fvec3 vv ;
02827 
02828    /* sanity checks */
02829 
02830    if( !editor_open || dset == NULL ){ XBell(dc->display,100) ; return ; }
02831 
02832    if( !CAN_TALTO(im3d) ){ XBell(dc->display,100); return; }
02833 
02834    /* get TTatlas+tlrc dataset */
02835 
02836    dseTT = TT_retrieve_atlas_either() ;
02837    DSET_load(dseTT) ;
02838 
02839    /* setup other info */
02840 
02841    bval = ttatlas_list->reg_ttval [ ttatlas_region_av->ival ] ;
02842    brik = ttatlas_list->reg_ttbrik[ ttatlas_region_av->ival ] ;
02843    bb   = DSET_ARRAY(dseTT,brik) ;
02844    if( bb == NULL ){ XBell(dc->display,100); return; }
02845 
02846    nvoxTT= DSET_NVOX(dseTT) ;
02847    nxTT  =dseTT->daxes->nxx  ; nyTT  =dseTT->daxes->nyy  ; nzTT  =dseTT->daxes->nzz  ;
02848    dxTT  =dseTT->daxes->xxdel; dyTT  =dseTT->daxes->yydel; dzTT  =dseTT->daxes->zzdel;
02849    xorgTT=dseTT->daxes->xxorg; yorgTT=dseTT->daxes->yyorg; zorgTT=dseTT->daxes->zzorg;
02850 
02851    nvoxout= DSET_NVOX(dset) ;
02852    voxout = (byte *) calloc(sizeof(byte),nvoxout) ;
02853    nxout  =dset->daxes->nxx  ; nyout  =dset->daxes->nyy  ; nzout  =dset->daxes->nzz  ;
02854    dxout  =dset->daxes->xxdel; dyout  =dset->daxes->yydel; dzout  =dset->daxes->zzdel;
02855    xorgout=dset->daxes->xxorg; yorgout=dset->daxes->yyorg; zorgout=dset->daxes->zzorg;
02856    nxyout = nxout*nyout ;
02857    nxyTT  = nxTT *nyTT  ;
02858 
02859    switch( ttatlas_hemisphere_av->ival ){
02860       case TTRR_HEMI_LEFT:  hbot=1+nxTT/2 ; htop=nxTT     ; break ;
02861       case TTRR_HEMI_RIGHT: hbot= 0       ; htop=1+nxTT/2 ; break ;
02862 
02863       default:
02864       case TTRR_HEMI_BOTH:  hbot= 0       ; htop=nxTT     ; break ;
02865    }
02866 
02867    /* loop over voxels in the TTatlas+tlrc dataset,
02868       transform to current dataset coordinates,
02869       count overlap (a la 3dfractionize)            */
02870 
02871    for( kv=0 ; kv < nzTT ; kv++ ){
02872     z1 = zorgTT + dzTT * (kv-0.5) ; z2 = zorgTT + dzTT * (kv+0.49999) ;
02873 
02874     for( jv=0 ; jv < nyTT ; jv++ ){
02875      y1 = yorgTT + dyTT * (jv-0.5) ; y2 = yorgTT + dyTT * (jv+0.49999) ;
02876 
02877      for( iv=hbot ; iv < htop ; iv++ ){
02878       ijk = iv + jv*nxTT + kv*nxyTT ;   /* 1D index of voxel (iv,jv,kv) */
02879       if( bb[ijk] != bval ) continue ;  /* not the right value, so skip it */
02880 
02881       x1 = xorgTT + dxTT * (iv-0.5) ; x2 = xorgTT + dxTT * (iv+0.49999) ;
02882 
02883       /* input voxel (iv,jv,kv) spans coordinates [x1,x2] X [y1,y2] X [z1,z2] */
02884 
02885       /* transform these corner coordinates to output dataset grid coordinates */
02886 
02887       if( dset->view_type == VIEW_TALAIRACH_TYPE ){
02888          xx1 = x1 ; yy1 = y1 ; zz1 = z1 ;
02889          xx2 = x2 ; yy2 = y2 ; zz2 = z2 ;
02890       } else {
02891          LOAD_FVEC3(vv , x1,y1,z1) ;
02892          vv = AFNI_transform_vector( im3d->anat_dset[VIEW_TALAIRACH_TYPE] ,
02893                                      vv , im3d->anat_now ) ;
02894          vv = THD_dicomm_to_3dmm( dset , vv );
02895          UNLOAD_FVEC3(vv , xx1,yy1,zz1) ;
02896 
02897          LOAD_FVEC3(vv , x2,y2,z2) ;
02898          vv = AFNI_transform_vector( im3d->anat_dset[VIEW_TALAIRACH_TYPE] ,
02899                                      vv , im3d->anat_now ) ;
02900          vv = THD_dicomm_to_3dmm( dset , vv ) ;
02901          UNLOAD_FVEC3(vv , xx2,yy2,zz2) ;
02902       }
02903 
02904       /* [xx1,xx2] X [yy1,yy2] X [zz1,zz2] is now in coordinates of output dataset */
02905 
02906       /* compute indices into output dataset voxel (keeping fractions) */
02907 
02908       f1 = (xx1-xorgout)/dxout + 0.49999 ; f2 = (xx2-xorgout)/dxout + 0.49999 ;
02909       if( f1 > f2 ){ tx = f1 ; f1 = f2 ; f2 = tx ; }
02910       if( f1 >= nxout || f2 <= 0.0 ) continue ;
02911       if( f1 < 0.0 ) f1 = 0.0 ;  if( f2 >= nxout ) f2 = nxout - 0.001 ;
02912 
02913       g1 = (yy1-yorgout)/dyout + 0.49999 ; g2 = (yy2-yorgout)/dyout + 0.49999 ;
02914       if( g1 > g2 ){ ty = g1 ; g1 = g2 ; g2 = ty ; }
02915       if( g1 >= nyout || g2 <= 0.0 ) continue ;
02916       if( g1 < 0.0 ) g1 = 0.0 ;  if( g2 >= nyout ) g2 = nyout - 0.001 ;
02917 
02918       h1 = (zz1-zorgout)/dzout + 0.49999 ; h2 = (zz2-zorgout)/dzout + 0.49999 ;
02919       if( h1 > h2 ){ tz = h1 ; h1 = h2 ; h2 = tz ; }
02920       if( h1 >= nzout || h2 <= 0.0 ) continue ;
02921       if( h1 < 0.0 ) h1 = 0.0 ;  if( h2 >= nzout ) h2 = nzout - 0.001 ;
02922 
02923       /* input voxel covers voxels [f1,f2] X [g1,g2] X [h1,h2] in the output */
02924 
02925       /* For example, [6.3,7.2] X [9.3,9.6] X [11.7,13.4], which must be     */
02926       /* distributed into these voxels:                                      */
02927       /*  (6,9,11), (7,9,11), (6,9,12), (7,9,12), (6,9,13), and (7,9,13)     */
02928 
02929       for( f=f1 ; f < f2 ; f = ip ){
02930          i = (int) f ; ip = i+1 ; tx = MIN(ip,f2) ; sx = tx - f ;
02931          for( g=g1 ; g < g2 ; g = jp ){
02932             j = (int) g ; jp = j+1 ; ty = MIN(jp,g2) ; sy = ty - g ;
02933             for( h=h1 ; h < h2 ; h = kp ){
02934                k = (int) h ; kp = k+1 ; tz = MIN(kp,h2) ; sz = tz - h ;
02935                sxyz = sx * sy * sz ;
02936                voxout[ i + j*nxout + k * nxyout ] += (byte)(100.0*sxyz) ;
02937             }
02938          }
02939       }
02940 
02941    }}} /* end of loop over voxels */
02942 
02943    /** at this point, voxout[ijk] stores how much overlap each output
02944        voxel has with an Atlas voxel which had the target value;
02945        now, count voxels with enough overlap, and store their indexes **/
02946 
02947 #define VTHRESH 49  /* at least 49% overlap */
02948 
02949    for( nftot=ijk=0 ; ijk < nvoxout ; ijk++ )
02950       if( voxout[ijk] >= VTHRESH ) nftot++ ;
02951 
02952    /* now load results into dataset */
02953 
02954    if( nftot > 0 ){
02955      int *xd = (int *) malloc(sizeof(int)*nftot) , ff ;
02956 
02957      for( ff=ijk=0 ; ijk < nvoxout ; ijk++ )
02958        if( voxout[ijk] >= VTHRESH ) xd[ff++] = ijk ;
02959 
02960      infill_mode = (strcmp(XtName(w),TTATLAS_infill_label) == 0) ;
02961      ff = DRAW_into_dataset( nftot , xd,NULL,NULL , NULL ) ;
02962      infill_mode = 0 ;
02963 
02964      free(xd) ;
02965 
02966      fprintf(stderr,"++ %d TT Atlas voxels drawn into dataset\n",ff) ;
02967      PLUTO_dset_redisplay( dset ) ;
02968      dset_changed = 1 ;
02969      SENSITIZE(save_pb,1) ; SENSITIZE(saveas_pb,1) ;
02970      if( recv_open ) AFNI_process_drawnotice( im3d ) ;
02971    } else {
02972       fprintf(stderr,"++ No TT Atlas voxels found for some reason!?\a\n") ;
02973    }
02974 
02975    free(voxout) ; /* toss trash */
02976    return ;
02977 }
02978 
02979 /*-----------------------------------------------------------------------
02980   Copy a dataset; new prefix is "COPY_" + old prefix.
02981     zfill != 0  ==> zero fill
02982     ftyp  <= 0  ==> same func type
02983     ftyp  == 1  ==> fim
02984     ftyp  == 2  ==> anat (omri)
02985     dtype <  0  ==> same datum
02986     dtype >= 0  ==> new datum (only valid for zfill)
02987                           Adapted from plug_copy.c -- 24 Sep 2001 - RWCox
02988 -------------------------------------------------------------------------*/
02989 
02990 THD_3dim_dataset * DRAW_copy_dset( THD_3dim_dataset *dset ,
02991                                    int zfill , int ftyp , int dtype )
02992 {
02993    THD_3dim_dataset *new_dset ;
02994    char new_prefix[THD_MAX_PREFIX] ;
02995    int ival ;
02996 
02997    if( !ISVALID_DSET(dset) ) return NULL ;
02998 
02999    if( strstr(DSET_PREFIX(dset),"COPY") != NULL ) strcpy(new_prefix,"C") ;
03000    else                                           strcpy(new_prefix,"COPY_") ;
03001    ival = strlen(new_prefix) ;
03002    MCW_strncpy(new_prefix+ival,DSET_PREFIX(dset),THD_MAX_PREFIX-ival) ;
03003 
03004    /*-- make a new dataset, somehow --*/
03005 
03006    if( zfill == 0 ){
03007      new_dset = PLUTO_copy_dset( dset , new_prefix ) ;  /* full copy */
03008      dtype = -1 ;
03009    } else {
03010      new_dset = EDIT_empty_copy( dset ) ;               /* zero fill */
03011      EDIT_dset_items( new_dset, ADN_prefix,new_prefix, ADN_none ) ;
03012    }
03013 
03014    if( new_dset == NULL ) return NULL ; /* bad, real bad */
03015 
03016    tross_Copy_History( dset , new_dset ) ;  /* make some History, dude! */
03017    { char str[256] ;
03018      strcpy(str,"Drawing plugin COPY:") ;
03019      if( zfill ) strcat(str," Fill->Zero") ;
03020      else        strcat(str," Fill->Data") ;
03021           if( ftyp == 1 ) strcat(str," Type->Func") ;
03022      else if( ftyp == 2 ) strcat(str," Type->Anat") ;
03023      if( dtype >= 0 ){
03024        strcat(str," Datum->") ; strcat(str,MRI_TYPE_name[dtype]) ;
03025      }
03026      tross_Append_History( new_dset , str ) ;
03027    }
03028 
03029    /*--- modify new dataset, if desired ---*/
03030 
03031    if( ftyp == 1 )
03032       EDIT_dset_items( new_dset ,
03033                          ADN_type      , HEAD_FUNC_TYPE ,
03034                          ADN_func_type , FUNC_FIM_TYPE  ,
03035                        ADN_none ) ;
03036    else if( ftyp == 2 )
03037       EDIT_dset_items( new_dset ,
03038                          ADN_type      , HEAD_ANAT_TYPE ,
03039                          ADN_func_type , ANAT_OMRI_TYPE ,
03040                        ADN_none ) ;
03041 
03042    if( zfill == 0 ) return new_dset ;  /* done if not zero-filling */
03043 
03044    /*--- change type of data stored? ---*/
03045 
03046    if( dtype >= 0 ) EDIT_dset_items( new_dset ,
03047                                        ADN_datum_all, dtype,
03048                                      ADN_none ) ;
03049    /* zero fill */
03050 
03051    {  int ityp , nbytes , nvals , ival ;
03052       void * new_brick , * bp ;
03053 
03054       nvals = DSET_NVALS(new_dset) ;
03055 
03056       for( ival=0 ; ival < nvals ; ival++)             /* get memory for bricks */
03057       {                                                /* and zero fill */
03058          ityp      = DSET_BRICK_TYPE(new_dset,ival) ;
03059          nbytes    = DSET_BRICK_BYTES(new_dset,ival) ; /* how much data */
03060          new_brick = malloc( nbytes ) ;
03061          EDIT_substitute_brick( new_dset , ival , ityp , new_brick ) ;
03062 
03063          bp = DSET_BRICK_ARRAY(new_dset,ival) ;        /* brick pointer */
03064          EDIT_BRICK_FACTOR(new_dset,ival,0.0) ;        /* brick factor  */
03065          memset( bp , 0 , nbytes ) ;
03066       }
03067    }
03068 
03069    /* 20 Oct 2003: copy VALUE_LABEL_DTABLE attribute, if present */
03070 
03071    { ATR_string *atr ;
03072      atr = THD_find_string_atr( dset->dblk , "VALUE_LABEL_DTABLE" ) ;
03073      if( atr != NULL )
03074        THD_set_char_atr( new_dset->dblk , "VALUE_LABEL_DTABLE" ,
03075                          atr->nch , atr->ch                     ) ;
03076    }
03077 
03078    /*-- done successfully!!! --*/
03079 
03080    return new_dset ;
03081 }
03082 
03083 /*-----------------------------------------------------------------------------*/
03084 /*! Expand set of points in 2D plane.  RWCox - 07 Oct 2002.
03085 -------------------------------------------------------------------------------*/
03086 
03087 static void DRAW_2D_expand( int np, int *xd, int *yd, int *zd, int plane ,
03088                             int *nfill , int **xyzf )
03089 {
03090    int base , di,dj , itop,jtop,nij , xx,yy,zz , ix,jy , *ip,*jp ;
03091    int nx=DSET_NX(dset) , ny=DSET_NY(dset) , nz=DSET_NZ(dset) , nxy = nx*ny ;
03092    int kadd , ii,jj,kk , ixn,jyn , mm,qq ;
03093    int nnew , *xyzn ;
03094 
03095    static int nadd[5] = { 4 , 8 , 12 , 20 , 24 } ;
03096    static int nn[24][2] = { {-1, 0} , { 1, 0} , { 0, 1} , { 0,-1} ,
03097                             {-1,-1} , {-1, 1} , { 1,-1} , { 1, 1} ,
03098                             {-2, 0} , { 2, 0} , { 0, 2} , { 0,-2} ,
03099                             {-2, 1} , {-2,-1} , {-1, 2} , {-1,-2} ,
03100                             { 2, 1} , { 2,-1} , { 1, 2} , { 1,-2} ,
03101                             {-2,-2} , {-2, 2} , { 2,-2} , { 2, 2}  } ;
03102 
03103    /* check inputs */
03104 
03105    if( np <= 0 || xd == NULL || yd == NULL || zd == NULL )     return ;
03106    if( mode_ival < FIRST_2D_MODE && mode_ival > LAST_2D_MODE ) return ;
03107    if( nfill == NULL || xyzf == NULL )                         return ;
03108 
03109    /* compute stuff for which plane we are in:
03110        1 -> yz , 2 -> xz , 3 -> xy            */
03111 
03112    xx = xd[0] ; yy = yd[0] ; zz = zd[0] ;
03113    switch(plane){
03114      case 1: base=xx    ; di=nx; dj=nxy; itop=ny; jtop=nz; ip=yd; jp=zd; break;
03115      case 2: base=yy*nx ; di=1 ; dj=nxy; itop=nx; jtop=nz; ip=xd; jp=zd; break;
03116      case 3: base=zz*nxy; di=1 ; dj=nx ; itop=nx; jtop=ny; ip=xd; jp=yd; break;
03117      default: return ;  /* bad input */
03118    }
03119 
03120    kadd = nadd[mode_ival-FIRST_2D_MODE] ;  /* how many pts around each input pt */
03121 
03122    xyzn = (int *) malloc( sizeof(int)*np*(kadd+1) ) ;   /* output array */
03123 
03124    /** add points around each input point, culling duplicates **/
03125 
03126    for( ii=jj=0 ; ii < np ; ii++ ){
03127      ix = ip[ii] ; jy = jp[ii] ;                                /* drawn point 2D index */
03128      if( ix >= 0 && ix < itop && jy >= 0 && jy < jtop ){
03129        xyzn[jj++] = base + ix*di + jy*dj ;                      /* load 3D index */
03130        for( kk=0 ; kk < kadd ; kk++ ){
03131          ixn = ix+nn[kk][0] ; jyn = jy+nn[kk][1] ;              /* nbhd pt 2D index */
03132          if( ixn >= 0 && ixn < itop && jyn >= 0 && jyn < jtop ){
03133            mm = base + ixn*di + jyn*dj ;                        /* 3D index */
03134            if( ii > 0 )
03135              for( qq=0 ; qq < jj && xyzn[qq] != mm ; qq++ ) ;   /* nada */
03136            else
03137              qq = jj ;
03138            if( qq == jj ) xyzn[jj++] = mm ;                     /* save 3D index */
03139          }
03140        }
03141      }
03142    }
03143 
03144    *nfill = jj ; *xyzf  = xyzn ; return ;
03145 }
03146 
03147 /*-----------------------------------------------------------------------------*/
03148 /*! Expand set of points in 3D space.  RWCox - 07 Oct 2002.
03149 -------------------------------------------------------------------------------*/
03150 
03151 static void DRAW_3D_expand( int np, int *xd, int *yd, int *zd, int plane ,
03152                             int *nfill , int **xyzf )
03153 {
03154    int ix,jy,kz ;
03155    int nx=DSET_NX(dset) , ny=DSET_NY(dset) , nz=DSET_NZ(dset) , nxy = nx*ny ;
03156    int kadd , ii,jj,kk , ixn,jyn,kzn , mm,qq ;
03157    int nnew , *xyzn ;
03158 
03159    static int nadd[7] = { 6 , 18 , 26 , 32 , 56 , 80 , 124 } ;
03160 
03161    static int nn[124][3] ={ {-1, 0, 0} , { 1, 0, 0} ,  /* r**2 = 1 */
03162                             { 0,-1, 0} , { 0, 1, 0} ,
03163                             { 0, 0,-1} , { 0, 0, 1} ,
03164 
03165                             {-1,-1, 0} , {-1, 1, 0} ,  /* r**2 = 2 */
03166                             { 1,-1, 0} , { 1, 1, 0} ,
03167                             { 0,-1,-1} , { 0,-1, 1} ,
03168                             { 0, 1,-1} , { 0, 1, 1} ,
03169                             {-1, 0,-1} , {-1, 0, 1} ,
03170                             { 1, 0,-1} , { 1, 0, 1} ,
03171 
03172                             {-1,-1,-1} , {-1,-1, 1} ,  /* r**2 = 3 */
03173                             {-1, 1,-1} , {-1, 1, 1} ,
03174                             { 1,-1,-1} , { 1,-1, 1} ,
03175                             { 1, 1,-1} , { 1, 1, 1} ,
03176 
03177                             {-2, 0, 0} , { 2, 0, 0} ,  /* r**2 = 4 */
03178                             { 0,-2, 0} , { 0, 2, 0} ,
03179                             { 0, 0,-2} , { 0, 0, 2} ,
03180 
03181                             {-2,-1, 0} , {-2, 1, 0} ,  /* r**2 = 5 */
03182                             { 2,-1, 0} , { 2, 1, 0} ,
03183                             { 0,-2,-1} , { 0,-2, 1} ,
03184                             { 0, 2,-1} , { 0, 2, 1} ,
03185                             {-2, 0,-1} , {-2, 0, 1} ,
03186                             { 2, 0,-1} , { 2, 0, 1} ,
03187                             {-1,-2, 0} , {-1, 2, 0} ,
03188                             { 1,-2, 0} , { 1, 2, 0} ,
03189                             { 0,-1,-2} , { 0,-1, 2} ,
03190                             { 0, 1,-2} , { 0, 1, 2} ,
03191                             {-1, 0,-2} , {-1, 0, 2} ,
03192                             { 1, 0,-2} , { 1, 0, 2} ,
03193 
03194                             {-2,-1,-1} , {-2,-1, 1} ,  /* r**2 = 6 */
03195                             {-2, 1,-1} , {-2, 1, 1} ,
03196                             { 2,-1,-1} , { 2,-1, 1} ,
03197                             { 2, 1,-1} , { 2, 1, 1} ,
03198                             {-1,-2,-1} , {-1,-2, 1} ,
03199                             {-1, 2,-1} , {-1, 2, 1} ,
03200                             { 1,-2,-1} , { 1,-2, 1} ,
03201                             { 1, 2,-1} , { 1, 2, 1} ,
03202                             {-1,-1,-2} , {-1,-1, 2} ,
03203                             {-1, 1,-2} , {-1, 1, 2} ,
03204                             { 1,-1,-2} , { 1,-1, 2} ,
03205                             { 1, 1,-2} , { 1, 1, 2} ,
03206 
03207                             {-2,-2, 0} , {-2, 2, 0} ,  /* r**2 = 8 */
03208                             { 2,-2, 0} , { 2, 2, 0} ,
03209                             { 0,-2,-2} , { 0,-2, 2} ,
03210                             { 0, 2,-2} , { 0, 2, 2} ,
03211                             {-2, 0,-2} , {-2, 0, 2} ,
03212                             { 2, 0,-2} , { 2, 0, 2} ,
03213 
03214                             {-2,-2, 1} , {-2, 2, 1} ,  /* r**2 = 9 */
03215                             { 2,-2, 1} , { 2, 2, 1} ,
03216                             { 1,-2,-2} , { 1,-2, 2} ,
03217                             { 1, 2,-2} , { 1, 2, 2} ,
03218                             {-2, 1,-2} , {-2, 1, 2} ,
03219                             { 2, 1,-2} , { 2, 1, 2} ,
03220                             {-2,-2,-1} , {-2, 2,-1} ,
03221                             { 2,-2,-1} , { 2, 2,-1} ,
03222                             {-1,-2,-2} , {-1,-2, 2} ,
03223                             {-1, 2,-2} , {-1, 2, 2} ,
03224                             {-2,-1,-2} , {-2,-1, 2} ,
03225                             { 2,-1,-2} , { 2,-1, 2} ,
03226 
03227                             {-2,-2,-2} , {-2,-2, 2} ,  /* r**2 = 12          */
03228                             {-2, 2,-2} , {-2, 2, 2} ,  /* [corners of 5x5x5] */
03229                             { 2,-2,-2} , { 2,-2, 2} ,
03230                             { 2, 2,-2} , { 2, 2, 2}
03231                           } ;
03232 
03233    /* check inputs */
03234 
03235    if( np <= 0 || xd == NULL || yd == NULL || zd == NULL )     return ;
03236    if( mode_ival < FIRST_3D_MODE && mode_ival > LAST_3D_MODE ) return ;
03237    if( nfill == NULL || xyzf == NULL )                         return ;
03238 
03239    kadd = nadd[mode_ival-FIRST_3D_MODE] ;  /* how many pts around each input pt */
03240 
03241    xyzn = (int *) malloc( sizeof(int)*np*(kadd+1) ) ;   /* output array */
03242 
03243    /** add points around each input point, culling duplicates **/
03244 
03245    for( ii=jj=0 ; ii < np ; ii++ ){
03246      ix = xd[ii] ; jy = yd[ii] ; kz = zd[ii] ;
03247      if( ix >= 0 && ix < nx && jy >= 0 && jy < ny && kz >= 0 && kz <= nz ){
03248        xyzn[jj++] = ix + jy*nx + kz*nxy ;                       /* load 3D index */
03249        for( kk=0 ; kk < kadd ; kk++ ){
03250          ixn = ix+nn[kk][0] ; jyn = jy+nn[kk][1] ; kzn = kz+nn[kk][2] ;
03251          if( ixn >= 0 && ixn < nx && jyn >= 0 && jyn < ny && kzn >= 0 && kzn < nz ){
03252            mm = ixn + jyn*nx + kzn*nxy ;                        /* 3D index */
03253            if( ii > 0 )
03254              for( qq=0 ; qq < jj && xyzn[qq] != mm ; qq++ ) ;   /* nada */
03255            else
03256              qq = jj ;
03257            if( qq == jj ) xyzn[jj++] = mm ;                     /* save 3D index */
03258          }
03259        }
03260      }
03261    }
03262 
03263    *nfill = jj ; *xyzf  = xyzn ; return ;
03264 }
03265 
03266 /*-----------------------------------------------------------------------------*/
03267 /*! Expand set of points in 2D plane, in a circle.  RWCox - 16 Oct 2002.
03268 -------------------------------------------------------------------------------*/
03269 
03270 static void DRAW_2D_circle( int np, int *xd, int *yd, int *zd, int plane ,
03271                             int *nfill , int **xyzf )
03272 {
03273    int base , di,dj , itop,jtop,nij , xx,yy,zz , ix,jy , *ip,*jp ;
03274    int nx=DSET_NX(dset) , ny=DSET_NY(dset) , nz=DSET_NZ(dset) , nxy = nx*ny ;
03275    int kadd , ii,jj,kk , ixn,jyn , mm,qq ;
03276    int nnew , *xyzn ;
03277 
03278    float dx = fabs(DSET_DX(dset)) ;
03279    float dy = fabs(DSET_DY(dset)) ;
03280    float dz = fabs(DSET_DZ(dset)) ;
03281    float rad= rad_av->fval ;
03282    float fdi,fdj , xq,yq,radq ;
03283    int idx , jdy , *nn ;
03284 
03285    /* check inputs */
03286 
03287    if( np <= 0 || xd == NULL || yd == NULL || zd == NULL ) return ;
03288    if( nfill == NULL || xyzf == NULL )                     return ;
03289 
03290    /* compute stuff for which plane we are in:
03291        1 -> yz , 2 -> xz , 3 -> xy            */
03292 
03293    xx = xd[0] ; yy = yd[0] ; zz = zd[0] ;
03294    switch(plane){
03295      case 1: base=xx    ; di=nx; dj=nxy; itop=ny; jtop=nz; ip=yd; jp=zd; fdi=dy; fdj=dz; break;
03296      case 2: base=yy*nx ; di=1 ; dj=nxy; itop=nx; jtop=nz; ip=xd; jp=zd; fdi=dx; fdj=dz; break;
03297      case 3: base=zz*nxy; di=1 ; dj=nx ; itop=nx; jtop=ny; ip=xd; jp=yd; fdi=dx; fdj=dy; break;
03298      default: return ;  /* bad input */
03299    }
03300 
03301    idx = rad / fdi ; jdy = rad / fdj ;
03302    if( idx < 1 && jdy < 1 ) return ;       /* circle smaller than in-plane voxel */
03303 
03304    /* make incremental mask */
03305 
03306    radq = 1.001*rad*rad ;
03307    nn   = (int *) malloc( sizeof(int)*(2*idx+1)*(2*jdy+1)*2 ) ;
03308    kadd = 0 ;
03309    for( jj=-jdy ; jj <= jdy ; jj++ ){
03310      yq = (jj*fdj)*(jj*fdj) ;
03311      for( ii=-idx ; ii <= idx ; ii++ ){
03312        xq = (ii*fdi)*(ii*fdi) + yq ;
03313        if( xq <= radq && xq > 0.0 ){
03314          nn[2*kadd]   = ii ;
03315          nn[2*kadd+1] = jj ;
03316          kadd++ ;
03317        }
03318      }
03319    }
03320 
03321    xyzn = (int *) malloc( sizeof(int)*np*(kadd+1) ) ;   /* output array */
03322 
03323    /** add points around each input point, culling duplicates **/
03324 
03325    for( ii=jj=0 ; ii < np ; ii++ ){
03326      ix = ip[ii] ; jy = jp[ii] ;                                /* drawn point 2D index */
03327      if( ix >= 0 && ix < itop && jy >= 0 && jy < jtop ){
03328        xyzn[jj++] = base + ix*di + jy*dj ;                      /* load 3D index */
03329        for( kk=0 ; kk < kadd ; kk++ ){
03330          ixn = ix+nn[2*kk] ; jyn = jy+nn[2*kk+1] ;              /* nbhd pt 2D index */
03331          if( ixn >= 0 && ixn < itop && jyn >= 0 && jyn < jtop ){
03332            mm = base + ixn*di + jyn*dj ;                        /* 3D index */
03333 #ifndef USE_COLLAPSAR
03334            if( ii > 0 )
03335              for( qq=0 ; qq < jj && xyzn[qq] != mm ; qq++ ) ;   /* nada */
03336            else
03337              qq = jj ;
03338            if( qq == jj ) xyzn[jj++] = mm ;                     /* save 3D index */
03339 #else
03340            xyzn[jj++] = mm ;                                    /* save 3D index */
03341 #endif
03342          }
03343        }
03344 
03345 #ifdef USE_COLLAPSAR
03346        if( ii > 9 && (ii==np-1 || ii%20==0) ) DRAW_collapsar( &jj , xyzn ) ;
03347 #endif
03348      }
03349    }
03350 
03351    *nfill = jj ; *xyzf = xyzn ; free(nn) ; return ;
03352 }
03353 
03354 /*-----------------------------------------------------------------------------*/
03355 /*! Expand set of points in 3D, in a sphere.  RWCox - 16 Oct 2002.
03356 -------------------------------------------------------------------------------*/
03357 
03358 static void DRAW_3D_sphere( int np, int *xd, int *yd, int *zd, int plane ,
03359                             int *nfill , int **xyzf )
03360 {
03361    int ix,jy,kz ;
03362    int nx=DSET_NX(dset) , ny=DSET_NY(dset) , nz=DSET_NZ(dset) , nxy = nx*ny ;
03363    int kadd , ii,jj,kk , ixn,jyn,kzn , mm,qq ;
03364    int nnew , *xyzn ;
03365 
03366    float dx = fabs(DSET_DX(dset)) ;
03367    float dy = fabs(DSET_DY(dset)) ;
03368    float dz = fabs(DSET_DZ(dset)) ;
03369    float rad= rad_av->fval ;
03370    float xq,yq,zq,radq ;
03371    int idx , jdy , kdz , *nn ;
03372    int www ;
03373 
03374    /* check inputs */
03375 
03376    if( np <= 0 || xd == NULL || yd == NULL || zd == NULL ) return ;
03377    if( nfill == NULL || xyzf == NULL )                     return ;
03378 
03379    idx = rad/dx ; jdy = rad/dy ; kdz = rad/dz ;
03380    if( idx < 1 && jdy < 1 && kdz < 1 ) return ;   /* sphere smaller than voxel */
03381 
03382 #if 0
03383 fprintf(stderr,"DRAW_3D_sphere: rad=%g  dx=%g idx=%d  dy=%g jdy=%d  dz=%g kdz=%d\n",
03384         rad,dx,idx,dy,jdy,dz,kdz ) ;
03385 #endif
03386 
03387    /* make incremental mask */
03388 
03389    radq = 1.001*rad*rad ;
03390    nn   = (int *) malloc( sizeof(int)*(2*idx+1)*(2*jdy+1)*(2*kdz+1)*3 ) ;
03391    kadd = 0 ;
03392    for( kk=-kdz ; kk <= kdz ; kk++ ){
03393      zq = (kk*dz)*(kk*dz) ;
03394      for( jj=-jdy ; jj <= jdy ; jj++ ){
03395        yq = zq + (jj*dy)*(jj*dy) ;
03396        for( ii=-idx ; ii <= idx ; ii++ ){
03397          xq = yq + (ii*dx)*(ii*dx) ;
03398          if( xq <= radq && xq > 0.0 ){
03399            nn[3*kadd]   = ii ;
03400            nn[3*kadd+1] = jj ;
03401            nn[3*kadd+2] = kk ;
03402            kadd++ ;
03403          }
03404        }
03405      }
03406    }
03407 
03408    xyzn = (int *) malloc( sizeof(int)*np*(kadd+1) ) ;   /* output array */
03409 
03410    if( xyzn == NULL ){
03411      fprintf(stderr,"\n** DRAW_3D_sphere ERROR: can't allocate memory!\n\a");
03412      free(nn); return;
03413    }
03414 
03415    www = (np*(kadd+1) > 1234567) && (np > 1) ;          /* show waiting? */
03416    if( www ) SHOW_AFNI_PAUSE ;
03417 
03418    /** add points around each input point **/
03419 
03420    for( ii=jj=0 ; ii < np ; ii++ ){
03421      ix = xd[ii] ; jy = yd[ii] ; kz = zd[ii] ;
03422      if( ix >= 0 && ix < nx && jy >= 0 && jy < ny && kz >= 0 && kz <= nz ){
03423        xyzn[jj++] = ix + jy*nx + kz*nxy ;                       /* load 3D index */
03424        for( kk=0 ; kk < kadd ; kk++ ){
03425          ixn = ix+nn[3*kk] ; jyn = jy+nn[3*kk+1] ; kzn = kz+nn[3*kk+2] ;
03426          if( ixn >= 0 && ixn < nx && jyn >= 0 && jyn < ny && kzn >= 0 && kzn < nz ){
03427            mm = ixn + jyn*nx + kzn*nxy ;                        /* 3D index */
03428 #ifndef USE_COLLAPSAR
03429            if( ii > 0 )
03430              for( qq=0 ; qq < jj && xyzn[qq] != mm ; qq++ ) ;   /* nada */
03431            else
03432              qq = jj ;
03433            if( qq == jj ) xyzn[jj++] = mm ;                     /* save 3D index */
03434 #else
03435            xyzn[jj++] = mm ;                                    /* save 3D index */
03436 #endif
03437          }
03438        }
03439 
03440 #ifdef USE_COLLAPSAR
03441        if( ii > 5 && (ii==np-1 || ii%16==0) ) DRAW_collapsar( &jj , xyzn ) ;
03442 #endif
03443      }
03444    }
03445 
03446    if( www ) SHOW_AFNI_READY ;
03447 
03448    *nfill = jj ; *xyzf = xyzn ; free(nn) ; return ;
03449 }
03450 
03451 /*--------------------------------------------------------------------------------*/
03452 
03453 #ifdef USE_COLLAPSAR
03454 
03455 /*! Collapses the input list of points to non-duplicates. */
03456 
03457 static void DRAW_collapsar( int *npt , int *xyzn )
03458 {
03459    int ii , jj , np ;
03460 
03461    if( npt == NULL || xyzn == NULL ) return ;
03462    np = *npt ; if( np <= 1 ) return ;
03463 
03464    qsort_int( np , xyzn ) ;                /* sort */
03465 
03466    for( ii=1 ; ii < np ; ii++ )            /* find 1st duplicates */
03467      if( xyzn[ii] == xyzn[ii-1] ) break ;
03468    if( ii == np ) return ;                 /* no duplicate => done */
03469 
03470    /* if [ii] is different from [jj],
03471       then add 1 to jj, and copy [ii] into the new [jj] location;
03472       otherwise, keep jj fixed (thus skipping [ii])               */
03473 
03474    for( jj=ii-1 ; ii < np ; ii++ ){
03475      if( xyzn[ii] != xyzn[jj] ) xyzn[++jj] = xyzn[ii] ;
03476    }
03477 
03478    *npt = jj+1 ; return ;
03479 }
03480 #endif  /* USE_COLLAPSAR */
 

Powered by Plone

This site conforms to the following standards: