/*****************************************************************************
   Major portions of this software are copyrighted by the Medical College
   of Wisconsin, 1994-2000, and are released under the Gnu General Public
   License, Version 2.  See the file README.Copyright for details.
******************************************************************************/

/*----------------------------------------------------------------------
 * history:
 *
 *   2003 Dec 19 [rickr]
 *     - added Mean and Sigma to bottom of graph window
 *----------------------------------------------------------------------
*/

#undef MAIN
#include "afni_graph.h"
#include "afni.h"
#include <X11/keysym.h>  /* 24 Jan 2003 */

static int show_grapher_pixmap = 1 ;
static void fd_line( MCW_grapher *, int,int,int,int ) ;

/*------------------------------------------------------------*/
/*! Macro to call the getser function with correct prototype. */

#undef  CALL_getser
#define CALL_getser(gr,aa,bb,rtyp,rval)                         \
 do{ XtPointer (*gs)(int,int,XtPointer) =                       \
      (XtPointer (*)(int,int,XtPointer))(gr->getser) ;          \
    rval = (rtyp) gs(aa,bb,gr->getaux) ;                        \
 } while(0)

/*------------------------------------------------------------*/
/*! And to call the send_CB function with a good prototype.   */

#undef  CALL_sendback
#define CALL_sendback(gr,scb)                                                 \
 do{ void (*sb)(MCW_grapher *,XtPointer,GRA_cbs *) =                          \
      (void (*)(MCW_grapher *,XtPointer,GRA_cbs *))(gr->status->send_CB) ;    \
     if( sb != NULL ) sb(gr,gr->getaux,&scb) ;                                \
 } while(0)

/*------------------------------------------------------------*/
/*! Create a new MCW_grapher window and structure.            */

MCW_grapher * new_MCW_grapher( MCW_DC *dc , get_ptr getser , XtPointer aux )
{
   int ii ;
   MCW_grapher *grapher ;
   static int new_xsize = -1 , new_ysize = -1 ;
   char *buf , *cpt ;
   Widget rc_tmp , mb_tmp , form_tmp ;  /* 29 Sep 2000 */

ENTRY("new_MCW_grapher") ;

   grapher = myXtNew( MCW_grapher ) ;

   grapher->type   = MCW_GRAPHER_TYPE ;
   grapher->dc     = dc ;
   grapher->getser = getser ;
   grapher->getaux = aux ;
   grapher->parent = NULL ;
   grapher->valid  = 1 ;

   grapher->dont_redraw     = 0 ;  /* 27 Jan 2004 */
   grapher->timer_id        = 0 ;  /* 04 Dec 2003 */
   grapher->never_drawn     = 1 ;
   grapher->button2_enabled = 0 ;  /* Feb 1998 */
   grapher->mirror          = 0 ;  /* Jul 2000 */

   grapher->tschosen        = 0 ;  /* 31 Mar 2004 */

   grapher->gx_max = 0 ;
   grapher->gy_max = 0 ;
   grapher->fWIDE  = 0 ;
   grapher->fHIGH  = 0 ;

   grapher->glogo_pixmap = XmUNSPECIFIED_PIXMAP ;
   grapher->glogo_width  = grapher->glogo_height = 0 ;

#if 0
   grapher->status = (MCW_grapher_status *) getser(0,graCR_getstatus,aux) ;
#else
   CALL_getser( grapher , 0,graCR_getstatus , MCW_grapher_status *,grapher->status ) ;
#endif

   if( grapher->status->num_series < 1 ){
     fprintf(stderr,"*** Attempt to create grapher with < 1 time points! ***\a\n") ;
     myXtFree(grapher) ;
     RETURN(NULL) ;
   }

   GRA_NULL_tuser(grapher) ;  /* 22 Apr 1997 */

   /** make shell that holds all **/

   grapher->fdw_graph =
      XtVaAppCreateShell(
         "AFNI" , "AFNI" , topLevelShellWidgetClass , dc->display ,
           XmNminHeight , MIN_XSIZE + GL_DLX + GR_DLX ,
           XmNmaxHeight , dc->height ,
           XmNminWidth  , MIN_YSIZE + GT_DLY + GB_DLY ,
           XmNmaxWidth  , dc->width ,
           XmNdeleteResponse   , XmDO_NOTHING ,   /* deletion handled below */
           XmNallowShellResize , False ,          /* let code resize shell */
           XmNinitialResourcesPersistent , False ,
              XmNkeyboardFocusPolicy , XmEXPLICIT ,
      NULL ) ;

   DC_yokify( grapher->fdw_graph , dc ) ;  /* 14 Sep 1998 */

   /** find initial size of new graphs **/

   if( new_xsize < 0 ){
      new_xsize = GX_MAX ;
#if 0
      buf = XGetDefault(dc->display,"AFNI","graph_width") ;
#else
      buf = RWC_getname(dc->display,"graph_width") ;
#endif
      if( buf != NULL ){
         ii = strtol( buf , &cpt , 10 ) ;
         if( *cpt == '\0' || new_xsize >= MIN_XSIZE ||
                             new_xsize <= dc->width - GL_DLX - GR_DLX )
            new_xsize = ii ;
      }

      new_ysize = GY_MAX ;
#if 0
      buf = XGetDefault(dc->display,"AFNI","graph_height") ;
#else
      buf = RWC_getname(dc->display,"graph_height") ;
#endif
      if( buf != NULL ){
         ii = strtol( buf , &cpt , 10 ) ;
         if( *cpt == '\0' || new_ysize >= MIN_YSIZE ||
                             new_ysize <= dc->width - GT_DLY - GB_DLY )
            new_ysize = ii ;
      }
   }

   /** 29 Sep 2000: put in a Form to hold everything **/

   form_tmp = XtVaCreateWidget(
                  "dialog" , xmFormWidgetClass , grapher->fdw_graph ,
                    XmNwidth  , new_xsize + GL_DLX + GR_DLX ,
                    XmNheight , new_ysize + GT_DLY + GB_DLY ,
                    XmNborderWidth , 0 ,
                    XmNtraversalOn , True ,
                    XmNinitialResourcesPersistent , False ,
              NULL ) ;

   /** make a drawing area to get everything **/

   grapher->draw_fd =
       XtVaCreateManagedWidget(
         "dialog" , xmDrawingAreaWidgetClass , form_tmp ,

#if 0
          XmNwidth  , new_xsize + GL_DLX + GR_DLX ,
          XmNheight , new_ysize + GT_DLY + GB_DLY ,
#endif

          XmNtopAttachment    , XmATTACH_FORM ,
          XmNleftAttachment   , XmATTACH_FORM ,
          XmNrightAttachment  , XmATTACH_FORM ,
          XmNbottomAttachment , XmATTACH_FORM ,

          XmNmarginWidth  , 0 ,
          XmNmarginHeight , 0 ,

          XmNtraversalOn , True ,
          XmNinitialResourcesPersistent , False ,
       NULL ) ;

   XtInsertEventHandler( grapher->draw_fd ,     /* handle events in graphs */

                            0
                          | KeyPressMask        /* get keystrokes */
                          | ButtonPressMask     /* button presses */
                          | ExposureMask        /* exposures */
                          | StructureNotifyMask /* resizes */
                         ,
                         FALSE ,                /* nonmaskable events? */
                         GRA_drawing_EV ,       /* super-handler! */
                         (XtPointer) grapher ,  /* client data */
                         XtListTail ) ;         /* last in queue */

   MCW_register_help( grapher->draw_fd ,
                       "Button 1 in a sub-graph --> move it to center\n"
                       "Button 1 in the central --> move time index\n"
                       "              sub-graph     to closest point\n"
                       "                            on the graph\n"
#if 0
                       "Shift or Ctrl keys with --> single-step time\n"
                       "Button 1 in the central     index up or down\n"
                       "              sub-graph\n"
#endif
                       "\n"
                       "The red dot in the central sub-graph shows\n"
                       "the location of the current time index.\n"
                       "\n"
                       "Button 3 in a sub-graph --> show statistics\n"
                       "                            of time series\n"
                       "\n"
                       "To turn off the AFNI logo, click Button 1\n"
                       "inside the logo.\n"
                       "\n"
                       "Miscellaneous Keystrokes:\n"
                       "< or [ = move back in time 1 point\n"
                       "> or ] = move forward in time 1 point\n"
                       "1      = move to 1st time point\n"
                       "l      = move to last time point\n"
                       "L      = turn AFNI logo on/off\n"
                       "v/V    = Video up/down in time\n"
                       "r/R    = Video ricochet up/down in time\n"
                       "\n"
                       "See the 'Opt' menu for other keypress actions\n"
                       "and for other options to control graph display."
                    ) ;

   /*---------------------------*/
   /*--- Button 3 popup menu ---*/
   /*---------------------------*/

#ifdef BAD_BUTTON3_POPUPS    /* 21 Jul 2003 */
   grapher->but3_menu =
      XmCreatePopupMenu(          form_tmp, "menu" , NULL , 0 ) ;
#else
   grapher->but3_menu =
      XmCreatePopupMenu( grapher->draw_fd , "menu" , NULL , 0 ) ;
#endif

   SAVEUNDERIZE(XtParent(grapher->but3_menu)) ; /* 27 Feb 2001 */

   VISIBILIZE_WHEN_MAPPED(grapher->but3_menu) ;
   if( !AFNI_yesenv("AFNI_DISABLE_TEAROFF") ) TEAROFFIZE(grapher->but3_menu) ;

   grapher->but3_label =
      XtVaCreateManagedWidget(
         "dialog" , xmLabelWidgetClass , grapher->but3_menu ,
            XmNalignment , XmALIGNMENT_BEGINNING ,
            XmNtraversalOn , True ,
            XmNinitialResourcesPersistent , False ,
         NULL ) ;

   /*-------------------------------------*/
   /*--- RowColumn to hold all buttons ---*/
   /*-------------------------------------*/

   grapher->option_rowcol =
      XtVaCreateWidget(
         "dialog" , xmRowColumnWidgetClass , form_tmp ,
            XmNpacking     , XmPACK_TIGHT ,
            XmNorientation , XmHORIZONTAL ,
            XmNmarginWidth , 0 ,
            XmNmarginHeight, 0 ,
            XmNspacing     , 2 ,
            XmNbackground  , grapher->dc->ovc->pixov_brightest ,
            XmNtraversalOn , True ,
            XmNinitialResourcesPersistent , False ,
            XmNleftAttachment   , XmATTACH_NONE ,
            XmNtopAttachment    , XmATTACH_NONE ,
            XmNrightAttachment  , XmATTACH_FORM ,
            XmNbottomAttachment , XmATTACH_FORM ,
         NULL ) ;

#if 0
   allow_MCW_optmenu_popup( 0 ) ;  /* 12 Dec 2001 */
#endif

   /*------------------------*/
   /*--- FIM Menu Buttons ---*/
   /*------------------------*/

   /* 29 Sep 2000: move menu buttons each onto private menubars */

   rc_tmp = XtVaCreateWidget(
              "dialog" , xmRowColumnWidgetClass , grapher->option_rowcol ,
                 XmNorientation , XmHORIZONTAL ,
                 XmNpacking , XmPACK_TIGHT ,
                 XmNmarginWidth , 0 ,
                 XmNmarginHeight, 0 ,
                 XmNspacing     , 0 ,
                 XmNbackground  , grapher->dc->ovc->pixov_brightest ,
                 XmNtraversalOn , True ,
                 XmNinitialResourcesPersistent , False ,
              NULL ) ;
   mb_tmp = XmCreateMenuBar( rc_tmp , "dialog" , NULL,0 ) ;
   XtVaSetValues( mb_tmp ,
                     XmNmarginWidth  , 0 ,
                     XmNmarginHeight , 0 ,
                     XmNspacing      , 0 ,
                     XmNborderWidth  , 0 ,
                     XmNborderColor  , 0 ,
                     XmNtraversalOn  , True ,
                     XmNbackground   , grapher->dc->ovc->pixov_brightest ,
                  NULL ) ;
   XtManageChild( mb_tmp ) ;

   grapher->fmenu = AFNI_new_fim_menu( mb_tmp , GRA_fim_CB , 1 ) ;
   grapher->fmenu->parent = (XtPointer) grapher ;
   XtManageChild( rc_tmp ) ;

   grapher->polort = 1 ;  /* 27 May 1999 */

   /* macros to put double and single separator lines in a menu */

#define MENU_DLINE(wmenu)                                          \
   (void) XtVaCreateManagedWidget(                                 \
            "dialog" , xmSeparatorWidgetClass , grapher -> wmenu , \
             XmNseparatorType , XmDOUBLE_LINE , NULL )

#define MENU_SLINE(wmenu)                                          \
   (void) XtVaCreateManagedWidget(                                 \
            "dialog" , xmSeparatorWidgetClass , grapher -> wmenu , \
             XmNseparatorType , XmSINGLE_LINE , NULL )

   /*------------------------*/
   /*--- Opt Menu Buttons ---*/
   /*------------------------*/

   /* 29 Sep 2000: move menu buttons each onto private menubars */

   rc_tmp = XtVaCreateWidget(
              "dialog" , xmRowColumnWidgetClass , grapher->option_rowcol ,
                 XmNorientation , XmHORIZONTAL ,
                 XmNpacking , XmPACK_TIGHT ,
                 XmNmarginWidth , 0 ,
                 XmNmarginHeight, 0 ,
                 XmNspacing     , 0 ,
                 XmNbackground  , grapher->dc->ovc->pixov_brightest ,
                 XmNtraversalOn , True ,
                 XmNinitialResourcesPersistent , False ,
              NULL ) ;
   mb_tmp = XmCreateMenuBar( rc_tmp , "dialog" , NULL,0 ) ;
   XtVaSetValues( mb_tmp ,
                     XmNmarginWidth  , 0 ,
                     XmNmarginHeight , 0 ,
                     XmNspacing      , 0 ,
                     XmNborderWidth  , 0 ,
                     XmNborderColor  , 0 ,
                     XmNtraversalOn  , True ,
                     XmNbackground   , grapher->dc->ovc->pixov_brightest ,
                  NULL ) ;
   XtManageChild( mb_tmp ) ;

   grapher->opt_menu = XmCreatePulldownMenu( mb_tmp , "menu" , NULL,0 ) ;

   VISIBILIZE_WHEN_MAPPED(grapher->opt_menu) ;  /* 27 Sep 2000 */
   if( !AFNI_yesenv("AFNI_DISABLE_TEAROFF") ) TEAROFFIZE(grapher->opt_menu) ;

   grapher->opt_cbut =
         XtVaCreateManagedWidget(
            "dialog" , xmCascadeButtonWidgetClass , mb_tmp ,
               LABEL_ARG("Opt") ,
               XmNsubMenuId , grapher->opt_menu ,
               XmNmarginWidth  , 0 ,
               XmNmarginHeight , 0 ,
               XmNmarginBottom , 0 ,
               XmNmarginTop    , 0 ,
               XmNmarginRight  , 0 ,
               XmNmarginLeft   , 0 ,
               XmNtraversalOn  , True ,
               XmNinitialResourcesPersistent , False ,
            NULL ) ;

   XtManageChild( rc_tmp ) ;

   MCW_register_hint( grapher->opt_cbut , "Graphing options menu" ) ;

   MCW_register_help( grapher->opt_cbut ,
                      "********  Graph Display Options:  ********\n"
                      "\n"
                      "Scale       --> Change vertical scaling\n"
                      "Matrix      --> Change number of sub-graphs\n"
                      "Grid        --> Change number of grid lines;\n"
                      "                 also can Pin the number of\n"
                      "                 time points displayed.\n"
                      "Slice       --> Change slice number\n"
                      "Colors, Etc --> Change colors of various\n"
                      "                 parts of the graph window\n"
                      "Baseline    --> Display each sub-graph with\n"
                      "                 its minimum at the bottom of\n"
                      "                 its window (the default), OR\n"
                      "                 with the minimum of all sub-\n"
                      "                 graphs as the common baseline\n"
                      "Show Text?  --> Instead of graphs, show the\n"
                      "                 numerical values of the data\n"
                      "                 at the current time index\n"
                      "                 in each sub-graph box\n"
                      "Save PNM    --> Save the graph window as an\n"
                      "                 image to a PNM format file\n"
                      "Write Center--> Central voxel timeseries will\n"
                      "                 be written to a file with a\n"
                      "                 name like 'X_Y_Z.suffix.1D'\n"
                      "                 where X,Y,Z are voxel indexes\n"
                      "Tran 0D     --> Choose a function to apply to\n"
                      "                 each point in each timeseries\n"
                      "Tran 1D     --> Choose a function to apply to\n"
                      "                 the timeseries as a whole\n"
                      "Double Plot --> If 'Tran 1D' is active, then\n"
                      "                 plot the data timeseries AND\n"
                      "                 the transformed timeseries;\n"
                      "                Plus/Minus -> transformed data\n"
                      "                 is added/subtracted from real\n"
                      "                 data timeseries (use this with\n"
                      "                 Dataset#2 to plot error bands)\n"
                      "Done        --> Close this graphing window\n"
                      "\n"
                      "The keystrokes indicated in the menus will\n"
                      "carry out the same functions, if pressed\n"
                      "when the cursor focus is in the graph window.\n"
                      "\n"
                      "N.B.: keystrokes without menu items are:\n"
                      " <  -->  move time index down by 1\n"
                      " >  -->  move time index up by 1\n"
                      " 1  -->  move to first image (time index 0)\n"
                      " l  -->  move to last image in time series\n"
                      " L  -->  turn off the AFNI logo in the corner"
                    ) ;

   /** macro to create a new opt menu button **/

#define OPT_MENU_BUT(wname,label,hhh)                                \
   grapher -> wname =                                                \
         XtVaCreateManagedWidget(                                    \
            "dialog" , xmPushButtonWidgetClass , grapher->opt_menu , \
               LABEL_ARG( label ) ,                                  \
               XmNmarginHeight , 0 ,                                 \
               XmNtraversalOn , True ,                               \
               XmNinitialResourcesPersistent , False ,               \
            NULL ) ;                                                 \
      XtAddCallback( grapher -> wname , XmNactivateCallback ,        \
                     GRA_opt_CB , (XtPointer) grapher ) ;            \
      MCW_register_hint( grapher -> wname , hhh ) ;

   /** macro to create a new opt pullright menu **/
   /** 07 Jan 1999: added the mapCallback to fix position **/

#define OPT_MENU_PULLRIGHT(wmenu,wcbut,label,hhh)                      \
   grapher -> wmenu =                                                  \
     XmCreatePulldownMenu( grapher->opt_menu , "menu" , NULL , 0 ) ;   \
   grapher -> wcbut =                                                  \
     XtVaCreateManagedWidget(                                          \
       "dialog" , xmCascadeButtonWidgetClass , grapher->opt_menu ,     \
          LABEL_ARG( label ) ,                                         \
          XmNsubMenuId , grapher -> wmenu ,                            \
          XmNtraversalOn , True  ,                                     \
          XmNinitialResourcesPersistent , False ,                      \
       NULL ) ;                                                        \
   MCW_register_hint( grapher -> wcbut , hhh ) ;                       \
   XtAddCallback( grapher -> wmenu, XmNmapCallback, GRA_mapmenu_CB, NULL ) ;

   /** macro to create a new button on a pullright menu **/

#define OPT_MENU_PULL_BUT(wmenu,wname,label,hhh)                    \
   grapher -> wname =                                               \
         XtVaCreateManagedWidget(                                   \
            "dialog" , xmPushButtonWidgetClass , grapher -> wmenu , \
               LABEL_ARG( label ) ,                                 \
               XmNmarginHeight , 0 ,                                \
               XmNtraversalOn , True  ,                             \
               XmNinitialResourcesPersistent , False ,              \
            NULL ) ;                                                \
      XtAddCallback( grapher -> wname , XmNactivateCallback ,       \
                     GRA_opt_CB , (XtPointer) grapher ) ;           \
   MCW_register_hint( grapher -> wname , hhh ) ;

#ifdef USE_OPTMENUS
   /** macro to create an option menu on a pullright menu
       (this menu must be fixed up later in GRA_fix_optmenus) **/

#define OPT_MENU_OPTMENU(wmenu,wname,label,cb,hhh)                  \
   grapher -> wname =                                               \
      new_MCW_optmenu( grapher -> wmenu , label , 0,1,0,0 ,         \
                       cb , (XtPointer) grapher , NULL , NULL ) ;   \
   MCW_reghint_children( grapher -> wname -> wrowcol , hhh ) ;

#endif /* USE_OPTMENUS */

   /*** top of menu = a label to click on that does nothing at all ***/

   (void) XtVaCreateManagedWidget(
            "dialog" , xmLabelWidgetClass , grapher->opt_menu ,
               LABEL_ARG("--- Cancel ---") ,
               XmNrecomputeSize , False ,
               XmNinitialResourcesPersistent , False ,
            NULL ) ;

   MENU_SLINE(opt_menu) ;

   OPT_MENU_PULLRIGHT(opt_scale_menu,opt_scale_cbut     ,"Scale"   ,"Change vertical scale" );
   OPT_MENU_PULL_BUT(opt_scale_menu,opt_scale_down_pb  ,"Down [-]","Shrink graph heights"  );
   OPT_MENU_PULL_BUT(opt_scale_menu,opt_scale_up_pb    ,"Up   [+]","Increase graph heights");
   OPT_MENU_PULL_BUT(opt_scale_menu,opt_scale_choose_pb,"Choose"  ,"Set vertical scale"    );
   OPT_MENU_PULL_BUT(opt_scale_menu,opt_scale_auto_pb  ,"Auto [a]","Scale automatically"   );

   OPT_MENU_PULLRIGHT(opt_mat_menu,opt_mat_cbut      ,"Matrix"  , "Change number of graphs"   ) ;
   OPT_MENU_PULL_BUT( opt_mat_menu,opt_mat_down_pb   ,"Down [m]", "Reduce number of graphs"   ) ;
   OPT_MENU_PULL_BUT( opt_mat_menu,opt_mat_up_pb     ,"Up   [M]", "Increase number of graphs" ) ;
#ifdef USE_OPTMENUS
   OPT_MENU_OPTMENU( opt_mat_menu,opt_mat_choose_av , "# " , GRA_mat_choose_CB , "Set number of graphs" ) ;
#else
   OPT_MENU_PULL_BUT( opt_mat_menu,opt_mat_choose_pb ,"Choose" , "Set number of graphs" ) ;
#endif

   OPT_MENU_PULLRIGHT(opt_grid_menu,opt_grid_cbut     ,"Grid"    , "Change vertical grid spacing" ) ;
   OPT_MENU_PULL_BUT( opt_grid_menu,opt_grid_down_pb  ,"Down [g]", "Reduce vertical grid spacing" ) ;
   OPT_MENU_PULL_BUT( opt_grid_menu,opt_grid_up_pb    ,"Up   [G]", "Increase vertical grid spacing" ) ;
   OPT_MENU_PULL_BUT( opt_grid_menu,opt_grid_auto_pb  ,"AutoGrid", "Set grid spacing automatically" ) ;
   OPT_MENU_PULL_BUT( opt_grid_menu,opt_grid_choose_pb,"Choose"  , "Set vertical grid spacing" ) ;
   OPT_MENU_PULL_BUT( opt_grid_menu,opt_pin_choose_pb ,"Index Pin","Fix index range of graph window" ) ;  /* 17 Mar 2004 */
   OPT_MENU_PULL_BUT( opt_grid_menu,opt_grid_HorZ_pb  ,"HorZ [h]", "Horizontal line at Zero" ) ; /* 05 Jan 1999 */

   OPT_MENU_PULLRIGHT(opt_slice_menu,opt_slice_cbut      ,"Slice"   , "Change slice"  ) ;
   OPT_MENU_PULL_BUT( opt_slice_menu,opt_slice_down_pb   ,"Down [z]", "Decrement slice" ) ;
   OPT_MENU_PULL_BUT( opt_slice_menu,opt_slice_up_pb     ,"Up   [Z]", "Increment slice" ) ;
#ifdef USE_OPTMENUS
   OPT_MENU_OPTMENU( opt_slice_menu,opt_slice_choose_av , "# " , GRA_slice_choose_CB , "Set slice" ) ;
#else
   OPT_MENU_PULL_BUT( opt_slice_menu,opt_slice_choose_pb ,"Choose" , "Set slice" ) ;
#endif

   /***** 16 June 1997: Colors submenu *****/

   { static char * bbox_label[1] = { "Use Thick Lines" } ;
     static char * pts_label[2]  = { "Graph Points" , "Points+Lines" } ;
     char     toplabel[64] ;
     XmString xstr ;

     OPT_MENU_PULLRIGHT(opt_colors_menu,opt_colors_cbut,"Colors, Etc.","Change graph appearance");

     if( strlen(grapher->status->namecode) > 0 ){

        sprintf( toplabel , "--- %s ---" , grapher->status->namecode ) ;
        xstr = XmStringCreateLtoR( toplabel , XmFONTLIST_DEFAULT_TAG ) ;

        (void) XtVaCreateManagedWidget(
                 "dialog" , xmLabelWidgetClass , grapher->opt_colors_menu ,
                    XmNlabelString , xstr ,
                    XmNrecomputeSize , False ,
                    XmNinitialResourcesPersistent , False ,
                 NULL ) ;

        XmStringFree( xstr ) ;

        MENU_DLINE(opt_colors_menu) ;
     }

     if( gr_setup_default ){
        gr_color_default[0] = INIT_GR_boxes_color  ;
        gr_color_default[1] = INIT_GR_backg_color  ;
        gr_color_default[2] = INIT_GR_grid_color   ;
        gr_color_default[3] = INIT_GR_text_color   ;
        gr_color_default[4] = INIT_GR_data_color   ;
        gr_color_default[5] = INIT_GR_ideal_color  ;
        gr_color_default[6] = INIT_GR_ort_color    ;
        gr_color_default[7] = INIT_GR_ignore_color ;
        gr_color_default[8] = INIT_GR_dplot_color  ;

        gr_thick_default[0] = INIT_GR_boxes_thick  ;
        gr_thick_default[1] = -1  ;
        gr_thick_default[2] = INIT_GR_grid_thick   ;
        gr_thick_default[3] = -1   ;
        gr_thick_default[4] = INIT_GR_data_thick   ;
        gr_thick_default[5] = INIT_GR_ideal_thick  ;
        gr_thick_default[6] = INIT_GR_ort_thick    ;
        gr_thick_default[7] = -1 ;
        gr_thick_default[8] = INIT_GR_dplot_thick  ;

        gr_setup_default = 0 ;
     }

     for( ii=0 ; ii < NUM_COLOR_ITEMS ; ii++ ){

        grapher->color_index[ii] = GRA_COLOR(gr_color_default[ii]) ;
        grapher->thick_index[ii] = gr_thick_default[ii] ;
        grapher->points_index[ii]= gr_points_default[ii] ;  /* 09 Jan 1998 */

        grapher->opt_color_av[ii] =
           new_MCW_colormenu( grapher->opt_colors_menu ,
                              gr_color_label[ii] ,
                              grapher->dc ,
                              gr_color_start[ii] , grapher->dc->ovc->ncol_ov-1,
                              grapher->color_index[ii] ,
                              GRA_color_CB , (XtPointer) grapher ) ;
        MCW_reghint_children( grapher->opt_color_av[ii]->wrowcol ,
                              gr_color_hint[ii] ) ;           /* 28 Jan 2004 */

        if( grapher->thick_index[ii] >= 0 ){
           grapher->opt_thick_bbox[ii] =
              new_MCW_bbox( grapher->opt_colors_menu ,
                            1 , bbox_label , MCW_BB_check , MCW_BB_noframe ,
                            GRA_thick_CB , (XtPointer) grapher ) ;
           MCW_reghint_children( grapher->opt_thick_bbox[ii]->wrowcol ,
                                 "Draw these lines thicker" ) ;

           if( grapher->thick_index[ii] )
              MCW_set_bbox( grapher->opt_thick_bbox[ii] , 1 ) ;
        } else {
           grapher->opt_thick_bbox[ii] = NULL ;
        }

        /* 09 Jan 1998: add option to draw only points in graphs */
        /* 01 Aug 1998: allow points+lines to be drawn as well   */

        if( grapher->points_index[ii] >= 0 ){
           grapher->opt_points_bbox[ii] =
              new_MCW_bbox( grapher->opt_colors_menu ,
                            2 , pts_label , MCW_BB_radio_zero , MCW_BB_noframe ,
                            GRA_thick_CB , (XtPointer) grapher ) ;
           MCW_reghint_children(  grapher->opt_points_bbox[ii]->wrowcol ,
                                  "Plot graph as Points only, or as Points and Lines" ) ;

           if( grapher->points_index[ii] )
              MCW_set_bbox( grapher->opt_points_bbox[ii] ,
                            1 << (grapher->points_index[ii]-1) ) ;
        } else {
           grapher->opt_points_bbox[ii] = NULL ;
        }

        MENU_DLINE( opt_colors_menu ) ;
     }

     /* 12 Jan 1998: control gap between graphs */

     grapher->opt_ggap_av =
        new_MCW_optmenu( grapher->opt_colors_menu , "Graph Gap" ,
                         0 , 19 , INIT_GR_ggap , 0 ,
                         GRA_ggap_CB , (XtPointer) grapher , NULL , NULL ) ;
     AVOPT_columnize( grapher->opt_ggap_av , 4 ) ;
     MCW_reghint_children( grapher->opt_ggap_av->wrowcol ,
                           "Space sub-graphs apart" ) ;

     /* 06 Oct 2004: control 'thick' line size */

     grapher->opt_gthick_av =
        new_MCW_optmenu( grapher->opt_colors_menu , "'Thick'  " ,
                         2 , 10 , INIT_GR_gthick , 0 ,
                         GRA_gthick_CB , (XtPointer) grapher , NULL , NULL ) ;
     AVOPT_columnize( grapher->opt_gthick_av , 2 ) ;
     MCW_reghint_children( grapher->opt_gthick_av->wrowcol ,
                           "Width of 'Thick' lines" ) ;

   }
   /***** end colors submenu creation *****/

#if 0
   OPT_MENU_BUT(opt_color_up_pb     ,"Grid Color   [r]" , "Rotate grid color" ) ;
#endif

   /*-- 07 Aug 2001: Baseline sub-menu creation --*/

   { char * bbox_label[3] = { "Individual [b]" ,
                              "Common     [b]" ,
                              "Global     [b]" } ;
     XmString xstr ;
     char gbuf[32] ;  /* 08 Mar 2002 */

     /* 08 Mar 2002: set baseline parameters from environment variables */

     cpt = getenv( "AFNI_GRAPH_GLOBALBASE" ) ;
     if( cpt != NULL )
       grapher->global_base = strtod( cpt , NULL ) ;
     else
       grapher->global_base = 0.0 ;

     cpt = getenv( "AFNI_GRAPH_BASELINE" ) ;
     if( cpt != NULL ){
       switch( *cpt ){
         default:  grapher->common_base = BASELINE_INDIVIDUAL ; break ;

         case 'C':
         case 'c': grapher->common_base = BASELINE_COMMON     ; break ;

         case 'G':
         case 'g': grapher->common_base = BASELINE_GLOBAL     ; break ;
       }
     } else {
       grapher->common_base = BASELINE_INDIVIDUAL ;
     }

     /* now create menu items */

     OPT_MENU_PULLRIGHT(opt_baseline_menu,opt_baseline_cbut,
                        "Baseline","Change sub-graphs baseline");

     grapher->opt_baseline_bbox =
         new_MCW_bbox( grapher->opt_baseline_menu ,
                       3 , bbox_label , MCW_BB_radio_one , MCW_BB_noframe ,
                       GRA_baseline_CB , (XtPointer)grapher ) ;
     MCW_set_bbox( grapher->opt_baseline_bbox , grapher->common_base ) ;

     MCW_reghint_children( grapher->opt_baseline_bbox->wrowcol ,
                          "Graph baseline methods" ) ;

     MENU_SLINE( opt_baseline_menu ) ;

     OPT_MENU_PULL_BUT( opt_baseline_menu,opt_baseline_setglobal_pb ,
                        "Set Global" , "Global baseline level" ) ;

     MENU_SLINE( opt_baseline_menu ) ;

     strcpy(gbuf,"Global:") ;
     AV_fval_to_char(grapher->global_base,gbuf+7) ;
     xstr = XmStringCreateLtoR(gbuf,XmFONTLIST_DEFAULT_TAG) ;
     grapher->opt_baseline_global_label =
        XtVaCreateManagedWidget(
                 "dialog" , xmLabelWidgetClass , grapher->opt_baseline_menu ,
                    XmNlabelString , xstr ,
                    XmNrecomputeSize , False ,
                    XmNtraversalOn , True  ,
                    XmNinitialResourcesPersistent , False ,
                 NULL ) ;
     XmStringFree( xstr ) ;
   }

   /* 22 Sep 2000: Text toggle */

   { static char * bbox_label[1] = { "Show Text? [t]" } ;

    grapher->opt_textgraph_bbox =
         new_MCW_bbox( grapher->opt_menu ,
                       1 , bbox_label , MCW_BB_check , MCW_BB_noframe ,
                       GRA_textgraph_CB , (XtPointer)grapher ) ;

    MCW_reghint_children( grapher->opt_textgraph_bbox->wrowcol ,
                          "Display text, not graphs" ) ;

    grapher->textgraph = 0 ;
   }

   MENU_SLINE(opt_menu) ;
   OPT_MENU_BUT(opt_save_pb         ,"Save PNM     [S]" , "Save graph as an image" ) ;

   MENU_SLINE(opt_menu) ;
   OPT_MENU_BUT(opt_write_center_pb ,"Write Center [w]" , "Write central graph as a *.1D file" ) ;
   OPT_MENU_BUT(opt_write_suffix_pb ,"Set 'w' Suffix"   , "Set suffix for graph writing" ) ;

   /*-------------------------------------------*/
   /*--- Arrowval to list 0D transformations ---*/
   /*-------------------------------------------*/

#define COLSIZE AV_colsize()

   if( grapher->status->transforms0D != NULL &&
       grapher->status->transforms0D->num > 0  ){  /* 22 Oct 1996 */

      MENU_DLINE(opt_menu) ;

      grapher->transform0D_av =
         new_MCW_optmenu( grapher->opt_menu ,
                          "Tran 0D" ,
                          0 , grapher->status->transforms0D->num , 0 , 0 ,
                          GRA_transform_CB , (XtPointer) grapher ,
                          GRA_transform_label , (XtPointer) grapher->status->transforms0D ) ;

      if( grapher->status->transforms0D->num >= COLSIZE )
         AVOPT_columnize( grapher->transform0D_av ,
                          (grapher->status->transforms0D->num/COLSIZE)+1 ) ;

      MCW_reghint_children( grapher->transform0D_av->wrowcol ,
                            "Pointwise data transformations" ) ;

   } else {
      grapher->transform0D_av = NULL ;
   }
   grapher->transform0D_func  = NULL ;  /* no function to start with */
   grapher->transform0D_index = 0 ;

   /*-------------------------------------------*/
   /*--- Arrowval to list 1D transformations ---*/
   /*-------------------------------------------*/

   if( grapher->status->transforms1D != NULL &&
       grapher->status->transforms1D->num > 0  ){  /* 03 Nov 1996 */

      MENU_DLINE(opt_menu) ;

      grapher->transform1D_av =
         new_MCW_optmenu( grapher->opt_menu ,
                          "Tran 1D" ,
                          0 , grapher->status->transforms1D->num , 0 , 0 ,
                          GRA_transform_CB , (XtPointer) grapher ,
                          GRA_transform_label , (XtPointer) grapher->status->transforms1D ) ;

      if( grapher->status->transforms1D->num >= COLSIZE )
         AVOPT_columnize( grapher->transform1D_av ,
                          (grapher->status->transforms1D->num/COLSIZE)+1 ) ;

      MCW_reghint_children( grapher->transform1D_av->wrowcol ,
                            "Time series transformations" ) ;

      /* 08 Nov 1996: dplot = double plot */
      /* 07 Aug 2001: rewrite of dplot to make it have 3 states, not two */

      { char * bbox_label[3] = { "DPlot Off" ,
                                 "Overlay"   ,
                                 "Plus/Minus" } ;

        OPT_MENU_PULLRIGHT(opt_dplot_menu,opt_dplot_cbut,
                           "Double Plot","Graph Dataset and Tran 1D?");

        grapher->opt_dplot_bbox =
            new_MCW_bbox( grapher->opt_dplot_menu ,
                          3 , bbox_label , MCW_BB_radio_one , MCW_BB_noframe ,
                          GRA_dplot_change_CB , (XtPointer)grapher ) ;
        MCW_set_bbox( grapher->opt_dplot_bbox , DPLOT_OFF ) ;

        MCW_reghint_children( grapher->opt_dplot_bbox->wrowcol ,
                              "How to show 2 curves" ) ;
      }

   } else {
      grapher->transform1D_av = NULL ;
      grapher->opt_dplot_bbox = NULL ;
   }
   grapher->transform1D_func  = NULL ;  /* no function to start with */
   grapher->transform1D_index = 0 ;

   /*------ menu to control the x-axis drawing (09 Jan 1998) ------*/

   MENU_DLINE(opt_menu) ;

   OPT_MENU_PULLRIGHT( opt_xaxis_menu , opt_xaxis_cbut    , "X-axis" , "Alter x-axis" ) ;
   OPT_MENU_PULL_BUT(  opt_xaxis_menu , opt_xaxis_pick_pb ,
                       "Pick x-axis" , "Set timeseries for x-axis" ) ;
   OPT_MENU_PULL_BUT(  opt_xaxis_menu , opt_xaxis_center_pb ,
                       "X-axis=center" , "X-axis = center voxel" ) ;
   OPT_MENU_PULL_BUT(  opt_xaxis_menu , opt_xaxis_clear_pb ,
                       "Clear x-axis" , "Clear x-axis timeseries" ) ;

   /*------ last button on this menu ------*/

   MENU_DLINE(opt_menu) ;
   OPT_MENU_BUT(opt_quit_pb         ,"Done         [q]" , "Close window" ) ;
   MCW_set_widget_bg( grapher->opt_quit_pb ,
                      MCW_hotcolor(grapher->opt_quit_pb) , 0 ) ;

   /** done with option buttons -- manage the manager widget **/

   XtManageChild( grapher->option_rowcol ) ;

#if 0
   allow_MCW_optmenu_popup( 1 ) ;  /* 12 Dec 2001 */
#endif

   /** initialize the internal parameters **/

if(PRINT_TRACING)
{ char str[128] ;
  sprintf(str,"STATUS: num_series=%d nx=%d ny=%d",
          grapher->status->num_series,grapher->status->nx,grapher->status->ny ) ;
  STATUS(str) ; }

   grapher->fscale      =  0 ;
   grapher->mat         =  0 ;
   grapher->xpoint      = -1 ;
   grapher->ypoint      = -1 ;
   grapher->zpoint      = -1 ;
#if 0
   grapher->grid_color  = GRID_COLOR(grapher) ;
#endif
   grapher->grid_index  = -1 ;
   grapher->grid_fixed  =  0 ;  /* 02 Apr 2004 */
   grapher->key_Nlock   =  0 ;
   grapher->xFD         =  0 ;
   grapher->yFD         =  0 ;
   grapher->time_index  =  0 ;
   grapher->pin_top     =  0 ;  /* 27 Apr 1997 */
   grapher->pin_bot     =  0 ;  /* 17 Mar 2004 */
   grapher->ggap        =  INIT_GR_ggap ;    /* 12 Jan 1998 + 27 May 1999 */
   grapher->gthick      =  INIT_GR_gthick ;  /* 06 Oct 2004 */

   grapher->cen_line    =  NULL ;  /* coords of central graph plot */
   grapher->ncen_line   =  0 ;
   grapher->nncen       =  0 ;
   grapher->cen_tsim    =  NULL ;
   grapher->xax_tsim    =  NULL ;  /* 09 Jan 1998 */
   grapher->ave_tsim    =  NULL ;  /* 27 Jan 2004 */

   grapher->xx_text_1    =
    grapher->xx_text_2   =
     grapher->xx_text_2p = grapher->xx_text_3 = 1 ;

   grapher->ref_ts = NULL ;
   grapher->ort_ts = NULL ;

   grapher->ref_ts_plotall = grapher->ort_ts_plotall = 1 ;

   init_const( grapher ) ;

   grapher->setshift_inc_av   = NULL ;
   grapher->setshift_left_av  = NULL ;
   grapher->setshift_right_av = NULL ;
   grapher->dialog            = NULL ;
   grapher->setshift_inc      = 0.5 ;
   grapher->setshift_left     = 0 ;
   grapher->setshift_right    = 0 ;

   /** for the present, don't realize widgets (make the user do it later) **/

   XtManageChild( form_tmp ) ;  /* 29 Sep 2000 */

#if 0
STATUS("realizing widgets") ;
   XtRealizeWidget( grapher->fdw_graph ) ;

   WAIT_for_window(grapher->form_tmp) ;

   XtVaSetValues( grapher->option_rowcol ,
                    XmNleftAttachment   , XmATTACH_NONE ,
                    XmNtopAttachment    , XmATTACH_NONE ,
                    XmNrightAttachment  , XmATTACH_FORM ,
                    XmNbottomAttachment , XmATTACH_FORM ,
                  NULL ) ;
   XMapRaised( XtDisplay(grapher->option_rowcol) ,
               XtWindow(grapher->option_rowcol)   ) ;

   NORMAL_cursorize( grapher->fdw_graph ) ;

   grapher->valid = 2 ;
#ifdef USE_OPTMENUS
   GRA_fix_optmenus( grapher ) ;
#endif
#endif

   grapher->fd_pxWind = (Pixmap) 0 ;

   /*** add callback for the WM_DELETE_WINDOW protocol ***/

   XmAddWMProtocolCallback(
        grapher->fdw_graph , XmInternAtom(dc->display,"WM_DELETE_WINDOW",False) ,
        end_fd_graph_CB , (XtPointer) grapher ) ;

   RETURN(grapher) ;
}

/*----------------------------------
    Exit button action
------------------------------------*/

void end_fd_graph_CB( Widget w , XtPointer client_data , XtPointer call_data )
{
   MCW_grapher * grapher = (MCW_grapher *) client_data ;
   int ii ;

ENTRY("end_fd_graph_CB") ;

   if( ! GRA_VALID(grapher) ) EXRETURN ;

   GRA_timer_stop( grapher ) ;  /* 04 Dec 2003 */

   grapher->valid = 0 ;  /* can't do anything with this anymore */

   if( grapher->fd_pxWind != (Pixmap) 0 ){
STATUS("freeing Pixmap") ;
     XFreePixmap( grapher->dc->display , grapher->fd_pxWind ) ;
   }

#ifdef USE_OPTMENUS
STATUS("destroying optmenus") ;
   FREE_AV(grapher->opt_mat_choose_av) ;
   FREE_AV(grapher->opt_slice_choose_av) ;
   FREE_AV(grapher->fmenu->fim_ignore_choose_av) ;
   FREE_AV(grapher->fmenu->fim_polort_choose_av) ;
#endif

STATUS("destroying arrowvals") ;
   FREE_AV( grapher->setshift_right_av)    ;
   FREE_AV( grapher->setshift_left_av)     ;
   FREE_AV( grapher->setshift_inc_av)      ;
   FREE_AV( grapher->transform0D_av )      ;  /* 22 Oct 1996 */
   FREE_AV( grapher->transform1D_av )      ;  /* 03 Nov 1996 */
   FREE_AV( grapher->opt_ggap_av )         ;  /* 28 Sep 1998: via Purify */
   FREE_AV( grapher->opt_gthick_av )       ;  /* 06 Oct 2004 */

   for( ii=0 ; ii < NUM_COLOR_ITEMS ; ii++ )  /* 16 Jun 1997 */
     FREE_AV( grapher->opt_color_av[ii] ) ;

STATUS("destroying fmenu") ;
   myXtFree( grapher->fmenu->fim_editref_winaver_bbox );  /* 27 Jan 2004 */
   myXtFree( grapher->fmenu->fim_opt_bbox ) ;  /* Jan 1998 */
   myXtFree( grapher->fmenu->fimp_opt_bbox );  /* Jan 1998 */
   myXtFree( grapher->fmenu->fimp_user_bbox);  /* Feb 2000 */
   myXtFree( grapher->fmenu )               ;
   myXtFree( grapher->cen_line )            ;

STATUS("destroying bboxes") ;
   myXtFree( grapher->opt_dplot_bbox ) ;         /* 08 Nov 1996 */

   for( ii=0 ; ii < NUM_COLOR_ITEMS ; ii++ ){
     myXtFree( grapher->opt_thick_bbox[ii] ) ;   /* 16 Jun 1997 */
     myXtFree( grapher->opt_points_bbox[ii] ) ;  /* 09 Jan 1998 */
   }

   myXtFree( grapher->opt_baseline_bbox ) ;      /* 07 Aug 2001 */
   myXtFree( grapher->opt_textgraph_bbox ) ;

STATUS("freeing cen_tsim") ;
   mri_free( grapher->cen_tsim ) ;
   mri_free( grapher->xax_tsim ) ;  /* 09 Jan 1998 */
   mri_free( grapher->ave_tsim ) ;  /* 27 Jan 2004 */

STATUS("freeing tuser") ;
   GRA_CLEAR_tuser( grapher ) ;  /* 22 Apr 1997 */

   /* 31 Mar 2004:
      On the Mac, destroying widgets after the timeseries
      chooser is opened causes death for unknown reasons.
      So in that case, just hide them.  What the ....?    */

STATUS("destroying widgets") ;
#ifdef DARWIN
   if( grapher->tschosen ) XtUnrealizeWidget( grapher->fdw_graph ) ;
   else                    XtDestroyWidget  ( grapher->fdw_graph ) ;
#else
   XtUnrealizeWidget( grapher->fdw_graph ) ;
#endif
STATUS("widgets now destroyed") ;

   /** if AFNI has a notify callback, it will free the data **/

   if( grapher->status->send_CB != NULL ){
      GRA_cbs cbs ;
      cbs.reason = graCR_destroy ;
STATUS("calling AFNI") ;
#if 0
      grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
#else
      CALL_sendback( grapher , cbs ) ;
#endif
   } else {
STATUS("freeing grapher") ;
      myXtFree( grapher ) ;    /* otherwise, we will free the data */
   }

   EXRETURN ;
}

/*----------------------------------
   Erase pixmap to background color
------------------------------------*/

void erase_fdw( MCW_grapher *grapher )
{
ENTRY("erase_fdw") ;

   if( grapher->dont_redraw ) EXRETURN ;  /* 27 Jan 2004 */

   DC_fg_color ( grapher->dc , BG_COLOR(grapher) ) ;
   DC_linewidth( grapher->dc , 0 ) ;

   XFillRectangle( grapher->dc->display ,
                   grapher->fd_pxWind , grapher->dc->myGC ,
                   0 , 0 , grapher->fWIDE , grapher->fHIGH ) ;

   if( show_grapher_pixmap &&
       grapher->glogo_pixmap != XmUNSPECIFIED_PIXMAP &&
       grapher->glogo_height > 0 && grapher->glogo_width > 0 ){

      XCopyArea( grapher->dc->display ,
                 grapher->glogo_pixmap , grapher->fd_pxWind , grapher->dc->myGC ,
                 0,0 , grapher->glogo_width,grapher->glogo_height ,
                 0,grapher->fHIGH - grapher->glogo_height + 1 ) ;
   }

   EXRETURN ;
}

/*-----------------------------------------------------*/
   /* It plots line to point (x,y) for mod = 1 */
   /* or moves to this point for mod = 0.      */
   /* All into the fd_pxWind.                  */
/*-----------------------------------------------------*/

void plot_fdX( MCW_grapher * grapher , int x , int y , int mod )
{
   int iy = grapher->fHIGH - y;

   if( mod > 0 )
     XDrawLine( grapher->dc->display ,
                grapher->fd_pxWind , grapher->dc->myGC ,
                grapher->xFD , grapher->yFD , x , iy ) ;

   grapher->xFD = x ; grapher->yFD = iy ;
   return ;
}

/* ----------------------------------- */
/* Reload pixmap fd_pxWind to FDWindow */
/* ----------------------------------- */

void fd_px_store( MCW_grapher * grapher )
{
ENTRY("fd_px_store") ;

   if( ! MCW_widget_visible(grapher->draw_fd) ) EXRETURN ;  /* 03 Jan 1999 */

   XtVaSetValues( grapher->draw_fd ,
                     XmNbackgroundPixmap , grapher->fd_pxWind ,
                  NULL ) ;

   XClearWindow( grapher->dc->display , XtWindow(grapher->draw_fd) ) ;
   XFlush( grapher->dc->display ) ;
   EXRETURN ;
}

/*--------------------------------------------------------------
  draw a small circle somewhere:
    xwin,ywin = Window coordinates of center
    filled    = 1 or 0, if you want the circle solid or not
                14 Jan 1998: 2 if for points on a filled circle
----------------------------------------------------------------*/

#define NCIR 12  /* hollow circle */
#define NBAL 21  /* filled circle */
#define NBAX 25  /* with points   */

#define NBTOP NBAX  /* max # of points */

static XPoint xball[] = {
      {-1,-2},{ 0,-2},{ 1,-2},
      { 2,-1},{ 2, 0},{ 2, 1},
      { 1, 2},{ 0, 2},{-1, 2},
      {-2, 1},{-2, 0},{-2,-1},  /* NCIR ends here */
      {-1,-1},{-1, 0},{-1, 1},
      { 0,-1},{ 0, 0},{ 0, 1},
      { 1,-1},{ 1, 0},{ 1, 1},  /* NBAL ends here */
      { 0,-3},{ 0, 3},{ 3, 0},
      {-3, 0}                   /* NBAX ends here */
 } ;

/*------------------ draw into Pixmap (the graph itself) -----------------------*/

void GRA_small_circle( MCW_grapher *grapher, int xwin, int ywin, int filled )
{
   int  i, ncirc ;
   XPoint a[NBTOP] ;

   switch( filled ){
      default: ncirc = NCIR ; break ;
      case 1:  ncirc = NBAL ; break ;
      case 2:  ncirc = NBAX ; break ;
   }

   for( i=0 ; i < ncirc ; i++ ){
      a[i].x = xball[i].x + xwin ;
      a[i].y = xball[i].y + ywin ;
   }

   XDrawPoints( grapher->dc->display, grapher->fd_pxWind,
                grapher->dc->myGC, a, ncirc, CoordModeOrigin ) ;
   return ;
}

/*------------------ draw into window (the graph overlay) -----------------------*/

void GRA_overlay_circle( MCW_grapher *grapher, int xwin, int ywin, int filled )
{
   int  i, ncirc ;
   XPoint a[NBTOP] ;

   switch( filled ){
      default: ncirc = NCIR ; break ;
      case 1:  ncirc = NBAL ; break ;
      case 2:  ncirc = NBAX ; break ;
   }

   for( i=0 ; i < ncirc ; i++ ){
      a[i].x = xball[i].x + xwin ;
      a[i].y = xball[i].y + ywin ;
   }

   DC_linewidth( grapher->dc, 0 ) ;

   XDrawPoints( grapher->dc->display, XtWindow(grapher->draw_fd),
                grapher->dc->myGC, a, ncirc, CoordModeOrigin ) ;
   return ;
}

/*---------------------------------------------------------------------------*/

void GRA_draw_circle( MCW_grapher *grapher , int xc , int yc , int rad )
{
   int xb,yb ;
   unsigned int ww ;

   if( rad < 0 ) rad = 0 ;
   xb = xc-rad ; yb = yc-rad ; ww = 2*rad ;
   XDrawArc( grapher->dc->display , XtWindow(grapher->draw_fd) ,
             grapher->dc->myGC , xb,yb , ww,ww , 0,360*64 ) ;
}


/*-----------------------------------------------
   redraw stuff that overlays the pixmap
-------------------------------------------------*/

#define SHORT_NAME_WIDTH 384

static char * long_index_name  = "index="  ;
static char * short_index_name = "#"       ;
static char * long_value_name  = " value=" ;
static char * short_value_name = "="       ;
static char * long_time_name   = " at "    ;
static char * short_time_name  = "@"       ;

void GRA_redraw_overlay( MCW_grapher * grapher )
{
   Window    win ;
   Display * dis ;
   int       ii , xxx , jj ;
   float     val ;
   char buf[16] , strp[128] ;
   char * vbuf , *iname , *vname ;

ENTRY("GRA_redraw_overlay") ;

   if( ! GRA_REALZ(grapher) ){ STATUS("ILLEGAL CALL") ; EXRETURN ; }

   if( ! MCW_widget_visible(grapher->draw_fd) ) EXRETURN ;  /* 03 Jan 1999 */
   if( grapher->dont_redraw ) EXRETURN ;                    /* 27 Jan 2004 */

   /* erase contents of window (that aren't in the pixmap) */

   dis = grapher->dc->display ;
   win = XtWindow(grapher->draw_fd) ;
   XClearWindow( dis , win ) ;

   EXRONE(grapher) ;  /* 22 Sep 2000 */

   /* draw some circles over ignored data points [23 May 2005] */

   if( grapher->init_ignore > 0 && !grapher->textgraph ){
     DC_fg_color( grapher->dc , IGNORE_COLOR(grapher) ) ;
     jj  = NBOT(grapher) ;                     /* first point to plot */
     xxx = NTOP(grapher) ;                     /* last */
     xxx = MIN (xxx , grapher->init_ignore) ;  /* point */
     xxx = MIN (xxx , ii+grapher->nncen) ;     /* to plot */
     for( ii=jj ; ii < xxx ; ii++ )
#if 0
       GRA_overlay_circle( grapher , grapher->cen_line[ii-jj].x ,
                                     grapher->cen_line[ii-jj].y , 1 ) ;
#else
       GRA_draw_circle( grapher , grapher->cen_line[ii-jj].x ,
                                  grapher->cen_line[ii-jj].y , 4 ) ;
#endif
   }

   /* 22 July 1996:
      draw a ball on the graph at the currently display time_index */

   ii = grapher->time_index ; jj = NBOT(grapher) ;
   if( ii >= jj            &&
       ii <  NTOP(grapher) && ii-jj < grapher->nncen && !grapher->textgraph ){

      DC_fg_color( grapher->dc , IDEAL_COLOR(grapher) ) ;
      GRA_overlay_circle( grapher , grapher->cen_line[ii-jj].x ,
                                    grapher->cen_line[ii-jj].y , 2 ) ;
   }

   /* draw text showing value at currently displayed time_index */

   if( ii >= 0 && grapher->cen_tsim != NULL && ii < grapher->cen_tsim->nx ){
      val = MRI_FLOAT_PTR(grapher->cen_tsim)[ii] ;
      AV_fval_to_char( val , buf ) ;
      vbuf = (buf[0]==' ') ? buf+1 : buf ;

      if( grapher->fWIDE < SHORT_NAME_WIDTH ){
        iname = short_index_name ; vname = short_value_name ;
      } else {
        iname = long_index_name ; vname = long_value_name ;
      }

      sprintf( strp , "%s%d%s%s" , iname,ii , vname,vbuf ) ;

      if( grapher->cen_tsim->dx != 0.0 ){
        val = grapher->cen_tsim->xo + ii * grapher->cen_tsim->dx ;
        AV_fval_to_char( val , buf ) ;
        vbuf = (buf[0]==' ') ? buf+1 : buf ;
        ii = strlen(strp) ;
        sprintf( strp+ii , "%s%s" ,
                 (grapher->fWIDE < SHORT_NAME_WIDTH) ? short_time_name
                                                     : long_time_name, vbuf ) ;
      }

      xxx = MAX( grapher->xx_text_2 ,
                 grapher->xorigin[grapher->xc][grapher->yc] ) ;

      if( grapher->init_ignore > 0 ) xxx = MAX( xxx , grapher->xx_text_2p ) ;

      DC_fg_color( grapher->dc , IDEAL_COLOR(grapher) ) ;
      overlay_txt( grapher, xxx , GB_DLY-15 , strp ) ;
   }

   /* no more to do now */

   XFlush( dis ) ;
   EXRETURN ;
}

/*------------------------------------------------------------------
   redraw entire graph;
   code is a mask of special values:
     0                  = default action
     PLOTCODE_AUTOSCALE = scale graphs automatically
-------------------------------------------------------------------*/

void redraw_graph( MCW_grapher *grapher , int code )
{
   int x, y , www,xxx , rrr ;
   int xc = grapher->xc , yc = grapher->yc ;
   char strp[256] , buf[64] ;
   int xd,yd,zd ;

ENTRY("redraw_graph") ;

   if( ! GRA_REALZ(grapher) ){ STATUS("ILLEGAL ENTRY"); EXRETURN; }
   if( grapher->fd_pxWind == (Pixmap) 0 ){ STATUS("ILLEGAL ENTRY"); EXRETURN; }
   if( grapher->dont_redraw ) EXRETURN ;  /* 27 Jan 2004 */

   /*---- draw the graphs ----*/

   erase_fdw  ( grapher ) ;
   draw_grids ( grapher ) ;
   plot_graphs( grapher , code ) ;

   DC_fg_color( grapher->dc , TEXT_COLOR(grapher) ) ;

   if( TPTS(grapher) < 2 ){             /* 22 Sep 2000 */
      fd_txt( grapher , GL_DLX+5, 35,
              "Can't draw graphs for this dataset: Num < 2" ) ;
      fd_px_store( grapher ) ;
      EXRETURN ;
   }

   /*---- draw some strings for informative purposes ----*/

   DC_fg_color( grapher->dc , TEXT_COLOR(grapher) ) ;

   /*** y axis labels ***/

   if( !grapher->textgraph ){
      AV_fval_to_char( grapher->pmax[xc][yc] , strp ) ;
      www = DC_text_width(grapher->dc,strp) ;
      xxx = GL_DLX - www - 2 ;
      xxx = MAX(0,xxx) ;
      fd_txt( grapher , xxx , GB_DLY + grapher->gy_max - MYTXT, strp) ;

      AV_fval_to_char( grapher->pmax[xc][yc] - grapher->pmin[xc][yc] , buf ) ;
      if( buf[0] == ' ' ) buf[0] = '+' ;
      sprintf( strp , "[%s]" , buf ) ;
      www = DC_text_width(grapher->dc,strp) ;
      xxx = GL_DLX - www + 2 ;
      xxx = MAX(0,xxx) ;
      fd_txt( grapher , xxx , GB_DLY + grapher->gy_max - MYTXT - 14 , strp) ;

      AV_fval_to_char( grapher->pmin[xc][yc] , strp ) ;
      www = DC_text_width(grapher->dc,strp) ;
      xxx = GL_DLX - www - 2 ;
      xxx = MAX(0,xxx) ;
      fd_txt( grapher , xxx , GB_DLY + 5, strp) ;
   }

   /*** bottom of the page coordinates stuff ***/

   /* first column */

   grapher->xx_text_1 = GL_DLX+5 ;

   xd = grapher->xpoint ; yd = grapher->ypoint ; zd = grapher->zpoint ;
#ifndef DONT_MANGLE_XYZ
   { THD_ivec3 id ;
     id = THD_fdind_to_3dind( grapher->getaux , TEMP_IVEC3(xd,yd,zd) ) ;
     xd = id.ijk[0] ; yd = id.ijk[1] ; zd = id.ijk[2] ; }
#endif

   sprintf(strp,"X: %d", xd) ;
   fd_txt( grapher , GL_DLX+5 , 35, strp) ;
   xxx = DC_text_width(grapher->dc,strp) ;

   sprintf(strp,"Y: %d", yd) ;
   fd_txt( grapher , GL_DLX+5 , 21, strp) ;
   www = DC_text_width(grapher->dc,strp) ; xxx = MAX(xxx,www) ;

   if( grapher->status->nz > 1 ){
      sprintf(strp,"Z: %d", zd) ;
      fd_txt( grapher , GL_DLX+5 ,  7, strp) ;
      www = DC_text_width(grapher->dc,strp) ; xxx = MAX(xxx,www) ;
   }

   /* second column */

   grapher->xx_text_2 = xxx = xxx + GL_DLX + 15 ;

   DC_linewidth( grapher->dc , 0 ) ;
   fd_line( grapher , xxx-7 , 41 , xxx-7 , 5 ) ;

   if( grapher->init_ignore > 0 ){                    /* 23 May 2005 */
     sprintf(strp,"Ignore%4d",grapher->init_ignore) ;
     fd_txt( grapher , xxx , 35, strp) ;
   }

   sprintf(strp,"Grid:%5d", grapher->grid_spacing ) ;
   rrr = DC_text_width(grapher->dc,strp) ;

   if( !grapher->textgraph ){
      if( grapher->fscale > 0 ){                        /* 04 Feb 1998: */
         AV_fval_to_char( grapher->fscale , buf ) ;     /* put scale on graph, too */
         www = strlen(strp) ;
         sprintf(strp+www," Scale:%s pix/datum",buf) ;
      } else if( grapher->fscale < 0 ){
         AV_fval_to_char( -grapher->fscale , buf ) ;
         www = strlen(strp) ;
         sprintf(strp+www," Scale:%s datum/pix",buf) ;
      }
   }

   fd_txt( grapher , xxx , 21, strp) ;

   xxx = DC_text_width(grapher->dc,strp) ;           /* 19 Dec 2003 [rickr] */

   { int bb=TBOT(grapher) , tt=TTOP(grapher)-1 ;
     if( bb > 99 || tt > 99 )
       sprintf(strp,"#%4d:%-4d" , bb,tt ) ;
     else
       sprintf(strp,"Num%3d:%-3d" , bb,tt ) ;
   }
   fd_line( grapher ,
            grapher->xx_text_2+rrr+3 , (grapher->init_ignore > 0) ? 41 : 31 ,
            grapher->xx_text_2+rrr+3 , 5 ) ;

   grapher->xx_text_2p = grapher->xx_text_2+rrr+7 ;  /* 23 May 2005 */

   if( !grapher->textgraph ){
     switch( grapher->common_base ){
       default:
       case BASELINE_INDIVIDUAL:
         strcat(strp,"  Base: separate") ; break ;

       case BASELINE_COMMON:
         strcat(strp,"  Base: common") ; break ;

       case BASELINE_GLOBAL:
         strcat(strp,"  Base: global") ; break ;
     }
   }

   fd_txt( grapher , grapher->xx_text_2 ,  7, strp ) ;

   /* add third column        19 Dec 2003  [rickr] */

   www = DC_text_width(grapher->dc,strp) ; xxx = MAX(xxx,www) ;

   grapher->xx_text_3 = grapher->xx_text_2 + xxx + 15 ;

   if( !grapher->textgraph && !ISONE(grapher) ){
      sprintf(strp,"Mean: %10s", MV_format_fval(grapher->tmean[xc][yc]) ) ;

      fd_txt( grapher , grapher->xx_text_3 ,  21, strp ) ;

      sprintf(strp,"Sigma:%10s", MV_format_fval(grapher->tstd[xc][yc]) ) ;

      fd_txt( grapher , grapher->xx_text_3 ,   7, strp ) ;

      fd_line( grapher , grapher->xx_text_3-7 , 31 , grapher->xx_text_3-7 , 5 ) ;
   }

   /*** flush the pixmap to the screen ***/

   fd_px_store( grapher ) ;

   /*** draw any overlay stuff ***/

   GRA_redraw_overlay( grapher ) ;

#ifdef USE_OPTMENUS
   GRA_fix_optmenus( grapher ) ;
#endif

   /** 27 Jan 2004 **/

   if( MCW_val_bbox(grapher->fmenu->fim_editref_winaver_bbox) )
     GRA_winaver_setref( grapher ) ;

   grapher->never_drawn = 0 ;
   EXRETURN ;
}

/*------------------------------------------------
   Plot text in fd_pxWind at x,y position
   relative to lower left corner (!).
--------------------------------------------------*/

void fd_txt( MCW_grapher * grapher , int x , int y , char * str )
{
   XDrawString( grapher->dc->display, grapher->fd_pxWind,
                grapher->dc->myGC , x , grapher->fHIGH-y ,
                str , strlen(str) ) ;
   return ;
}

/*-----------------------------------------------*/

void overlay_txt( MCW_grapher * grapher , int x , int y , char * str )
{
   XDrawString( grapher->dc->display, XtWindow(grapher->draw_fd) ,
                grapher->dc->myGC , x , grapher->fHIGH-y ,
                str , strlen(str) ) ;
   return ;
}

/*-----------------------------------------------*/

static void fd_line( MCW_grapher *grapher , int x1,int y1, int x2,int y2 )
{
   XDrawLine( grapher->dc->display , grapher->fd_pxWind ,
              grapher->dc->myGC , x1,grapher->fHIGH-y1,x2,grapher->fHIGH-y2 ) ;
   return ;
}

/*-----------------------------------------------*/

#define GRID_MAX 12
static int grid_ar[GRID_MAX] =
   { 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000 } ;

static void auto_grid( MCW_grapher *grapher , int npoints )
{
   int ii ;
   if( npoints < 2 ) return ;            /* 02 Apr 2004 */
   for( ii=GRID_MAX-1 ; ii > 0 ; ii-- )
     if( grid_ar[ii] <= npoints/3 ) break;
   grapher->grid_index   = ii ;
   grapher->grid_spacing = grid_ar[ii] ;
   grapher->grid_fixed   = 0 ;           /* 02 Apr 2004 */
   return ;
}

/*-----------------------------------------------*/

void init_const( MCW_grapher *grapher )
{
   int ii ;

ENTRY("init_const") ;

   if( !GRA_VALID(grapher) ) EXRETURN ;

   if( grapher->fscale == 0 ) grapher->fscale = 1 ;

   grapher->mat_max = MAT_MAX ;
   grapher->mat_max = MIN( grapher->mat_max , grapher->status->nx ) ;
   grapher->mat_max = MIN( grapher->mat_max , grapher->status->ny ) ;

   if( grapher->mat <= 0 ) grapher->mat = INIT_GR_gmat ;
   grapher->mat = MIN( grapher->mat , grapher->mat_max ) ;

   if( grapher->xpoint < 0 || grapher->xpoint >= grapher->status->nx )
      grapher->xpoint = grapher->status->nx / 2 ;

   if( grapher->ypoint < 0 || grapher->ypoint >= grapher->status->ny )
      grapher->ypoint = grapher->status->ny / 2 ;

   if( grapher->zpoint < 0 || grapher->zpoint >= grapher->status->nz )
      grapher->zpoint = grapher->status->nz / 2 ;

   if( grapher->grid_index < 0 ) auto_grid( grapher, NPTS(grapher) ) ;

#if 0
   if( grapher->grid_color < 0 )
      grapher->grid_color = 1 ;  /* first overlay color */
#endif

   if( grapher->time_index < 0 )
     grapher->time_index = 0 ;
   else if( grapher->time_index >= grapher->status->num_series )
     grapher->time_index = grapher->status->num_series - 1 ;

   init_mat(grapher) ;
   EXRETURN ;
}

/*-----------------------------------------------------------
  Draw numbers instead of graphs -- 22 Sep 2000 -- RWCox
-------------------------------------------------------------*/

void text_graphs( MCW_grapher *grapher )
{
   MRI_IMAGE *tsim ;
   int index, ix, iy, xtemp,ytemp,ztemp , xoff,yoff ;
   int iv , jv , www ;
   char str[64] , *strp ;

ENTRY("text_graphs") ;
   if( grapher->dont_redraw ) EXRETURN ;  /* 27 Jan 2004 */

   DC_fg_color( grapher->dc , TEXT_COLOR(grapher) ) ;

   iv = grapher->time_index ;
   if( iv < 0 )
     iv = 0 ;
   else if( iv >= grapher->status->num_series )
     iv = grapher->status->num_series - 1 ;

   ztemp = grapher->zpoint * grapher->status->ny * grapher->status->nx ;

   for( ix=0 ; ix < grapher->mat ; ix++ ){
      xtemp  = grapher->xpoint + ix - grapher->xc ;
           if( xtemp <  0                   ) xtemp += grapher->status->nx ;
      else if( xtemp >= grapher->status->nx ) xtemp -= grapher->status->nx ;

      for( iy=0 ; iy < grapher->mat ; iy++ ){
         ytemp = grapher->ypoint - iy + grapher->yc ;
              if( ytemp <  0                   ) ytemp += grapher->status->ny ;
         else if( ytemp >= grapher->status->ny ) ytemp -= grapher->status->ny ;

         index = ztemp + ytemp * grapher->status->nx + xtemp ;

#if 0
         tsim  = (MRI_IMAGE *) grapher->getser( index , graCR_getseries ,
                                                        grapher->getaux ) ;
#else
         CALL_getser( grapher , index,graCR_getseries , MRI_IMAGE *,tsim ) ;
#endif

         if( tsim == NULL ) break ;
         if( tsim->nx < 1 ){ mri_free(tsim); break; }  /* shouldn't happen */

         if( tsim->kind != MRI_float ){
           MRI_IMAGE *qim = mri_to_float(tsim) ;
           mri_free(tsim) ; tsim = qim ;
         }

         if( ix == grapher->xc && iy == grapher->yc ){
           mri_free( grapher->cen_tsim ) ;             /* copy time series too */
           grapher->cen_tsim = mri_to_float( tsim ) ;
         }

#if 0
         if( grapher->transform0D_func != NULL )
# if 0
            grapher->transform0D_func( tsim->nx , MRI_FLOAT_PTR(tsim) ) ;
# else
            AFNI_CALL_0D_function( grapher->transform0D_func ,
                                   tsim->nx , MRI_FLOAT_PTR(tsim) ) ;
# endif
#endif

         jv = iv ; if( jv >= tsim->nx ) jv = tsim->nx - 1 ;
         AV_fval_to_char( MRI_FLOAT_PTR(tsim)[jv] , str ) ;
         mri_free(tsim) ;
         strp = (str[0] == ' ') ? str+1 : str ;
         www = DC_text_width(grapher->dc,strp) ;

         fd_txt( grapher , grapher->xorigin[ix][iy] + (grapher->gx-www)/2 ,
                           grapher->yorigin[ix][iy] + 2 ,
                 strp ) ;
      }
   }

   EXRETURN ;
}

/*-----------------------------------------------------------
    Plot real graphs to pixmap
-------------------------------------------------------------*/

void plot_graphs( MCW_grapher *grapher , int code )
{
   MRI_IMAGE *tsim ;
   MRI_IMARR *tsimar ;
   float     *tsar ;
   float       tsbot=0.0 , ftemp , tstop ;
   int i, m, index, ix, iy, xtemp,ytemp,ztemp , xoff,yoff , its,ibot,itop;
   int ptop,pbot,pnum,qnum , tbot,ttop,tnum , ntmax ;  /* 17 Mar 2004 */

   static int      *plot = NULL ;  /* arrays to hold plotting coordinates */
   static XPoint *a_line = NULL ;
   static int      nplot = 0 ;

   MRI_IMARR *dplot_imar = NULL ;  /* 08 Nov 1996 */
   int        dplot = 0 ;

   MRI_IMARR *eximar ;
   int        iex ;

   float nd_bot , nd_top , nd_dif ;                        /* 03 Feb 1998 */
   int   set_scale = ( (code & PLOTCODE_AUTOSCALE) != 0 ||
                       grapher->never_drawn ) ;

   MRI_IMAGE *dsim ; /* 07 Aug 2001: for double plot */
   float     *dsar ;

#define OVI_MAX 19
   int tt, use_ovi, ovi[OVI_MAX] ;  /* 29 Mar 2002: for multi-plots */

ENTRY("plot_graphs") ;
   if( grapher->dont_redraw ) EXRETURN ;  /* 27 Jan 2004 */

   /* check if we draw text instead of curves */

   if( grapher->status->num_series < 1 ){
     EXRETURN ;
   } else if( grapher->status->num_series == 1 ||
              grapher->textgraph               || TPTS(grapher) < 2 ){
     text_graphs( grapher ) ;
     EXRETURN ;
   }

   GRA_fixup_xaxis( grapher ) ;   /* 09 Jan 1998 */

   /* set colors and line widths */

   DC_fg_color ( grapher->dc , DATA_COLOR(grapher) ) ;
   DC_linewidth( grapher->dc , DATA_THICK(grapher) ) ;

   /* 17 Mar 2004: we will plot from pbot..ptop-1, with data from tbot..ttop-1 */

   ptop = NTOP(grapher) ; pbot = NBOT(grapher) ;
   if( pbot >= ptop ){
     pbot = 0 ; ptop = grapher->status->num_series ;
   }
   ttop = TTOP(grapher) ; ttop = MIN(ttop,ptop) ; tbot = pbot ;
   if( ttop <= tbot || ttop > grapher->status->num_series ){
     ttop = MIN(ptop,grapher->status->num_series) ;
   }
   pnum = ptop-pbot ; tnum = ttop-tbot ;
   if( pnum <= 1 || tnum <= 1 ) EXRETURN ;   /* should never happen? */

   /* set aside space for plotting, etc. */

#define NPLOT_INIT 9999  /* 29 Apr 1997 */
   itop = MAX( NPLOT_INIT , grapher->status->num_series ) ;
   if( nplot == 0 || nplot < itop ){
     myXtFree(a_line) ; myXtFree(plot) ;
     nplot  = itop ;
     plot   = (int *)    XtMalloc( sizeof(int)    * itop ) ;
     a_line = (XPoint *) XtMalloc( sizeof(XPoint) * itop ) ;
   }
   if( grapher->ncen_line < itop ){
     myXtFree(grapher->cen_line) ;
     grapher->cen_line  = (XPoint *) XtMalloc( sizeof(XPoint) * itop ) ;
     grapher->ncen_line = itop ;
   }

   /* set the bottom point at which to compute time series statistics */

   ibot = grapher->init_ignore ;
   if( ibot >= ttop-1 ) ibot = 0 ;
   ibot = MAX(ibot,tbot) ;                     /* 17 Mar 2004 */

   /** loop over matrix of graphs and get all the time series for later **/

   INIT_IMARR(tsimar) ;

   /** 08 Nov 1996: initialize second array for double plotting **/
   /** 07 Aug 2001: modify to allow for multiple dplot cases    **/

   if( grapher->transform1D_func != NULL &&
       MCW_val_bbox(grapher->opt_dplot_bbox) != DPLOT_OFF ){

     INIT_IMARR(dplot_imar) ;
     dplot = MCW_val_bbox(grapher->opt_dplot_bbox) ; /* 07 Aug 2001 */
   }

   GRA_CLEAR_tuser( grapher ) ;  /* 22 Apr 1997 */

   /* 3D index offset to correct slice number */
   ztemp = grapher->zpoint * grapher->status->ny * grapher->status->nx ;

   ntmax = 0 ; /* will be length of longest time series found below */

   for( ix=0 ; ix < grapher->mat ; ix++ ){

      /** compute the 3D index of the desired time series **/

      xtemp  = grapher->xpoint + ix - grapher->xc ;
           if( xtemp <  0                   ) xtemp += grapher->status->nx ;  /* wrap */
      else if( xtemp >= grapher->status->nx ) xtemp -= grapher->status->nx ;

      for( iy=0 ; iy < grapher->mat ; iy++ ){
         ytemp = grapher->ypoint - iy + grapher->yc ;
              if( ytemp <  0                   ) ytemp += grapher->status->ny;  /* wrap */
         else if( ytemp >= grapher->status->ny ) ytemp -= grapher->status->ny;

         index = ztemp + ytemp * grapher->status->nx + xtemp ;  /* 3D index in dataset */

         /** get the desired time series, using the provided routine **/

#if 0
         tsim  = (MRI_IMAGE *) grapher->getser( index , graCR_getseries ,
                                                        grapher->getaux ) ;
#else
         CALL_getser( grapher , index,graCR_getseries , MRI_IMAGE *,tsim ) ;
#endif

         /* 08 Nov 1996: allow for return of NULL timeseries */

         if( tsim == NULL ){
           ADDTO_IMARR(tsimar,NULL) ;
           if( dplot ) ADDTO_IMARR(dplot_imar,NULL) ;
           continue ;  /* skip to next iy */
         }

         ntmax = MAX( ntmax , tsim->nx ) ;

         /** convert time series to floats, if need be **/

         if( tsim->kind != MRI_float ){
           MRI_IMAGE *qim = mri_to_float(tsim) ;
           mri_free(tsim) ; tsim = qim ;
         }

         /* 22 Oct 1996: transform each point, if ordered */

         if( grapher->transform0D_func != NULL ){
STATUS("about to perform 0D transformation") ;
#if 0
            grapher->transform0D_func( tsim->nx , MRI_FLOAT_PTR(tsim) ) ;
#else
            AFNI_CALL_0D_function( grapher->transform0D_func ,
                                   tsim->nx , MRI_FLOAT_PTR(tsim) ) ;
#endif
         }

         /* 03 Nov 1996: 1D transformations, too */
         /* 08 Nov 1996: double plotting, too */

         if( grapher->transform1D_func != NULL ){
            MRI_IMAGE * qim ;                /* image to be transformed */

            if( dplot ){                      /* copy and save original */
              qim = mri_to_float(tsim) ;       /* if double plot is on */
              ADDTO_IMARR(dplot_imar,qim) ;
            }
            else
              qim = tsim ;                 /* transform original image */

STATUS("about to perform 1D transformation") ;

            if( grapher->transform1D_flags & NEEDS_DSET_INDEX ){ /* 18 May 2000 */
#ifdef BE_AFNI_AWARE
               FD_brick *br = (FD_brick *) grapher->getaux ;
               THD_ivec3 id ;
               id = THD_fdind_to_3dind( br ,
                                        TEMP_IVEC3(xtemp,ytemp,grapher->zpoint) );
               AFNI_store_dset_index(
                             id.ijk[0]
                            +id.ijk[1] * br->nxyz.ijk[0]
                            +id.ijk[2] * br->nxyz.ijk[0] * br->nxyz.ijk[1] , 0 ) ;
#else
               AFNI_store_dset_index(-1,0) ;
#endif
            }

            if( ! (grapher->transform1D_flags & PROCESS_MRI_IMAGE) ){  /* older code:   */
                                                                       /* process image */
              if( ! (grapher->transform1D_flags & RETURNS_STRING) ){   /* contents only */
#if 0
                 grapher->transform1D_func( qim->nx , qim->xo , qim->dx ,
                                            MRI_FLOAT_PTR(qim) ) ;
#else
                 AFNI_CALL_1D_function( grapher->transform1D_func ,
                                        qim->nx , qim->xo , qim->dx ,
                                        MRI_FLOAT_PTR(qim) ) ;
#endif
              } else {
                 char * quser = NULL ;
#if 0
                 grapher->transform1D_func( qim->nx , qim->xo , qim->dx ,
                                            MRI_FLOAT_PTR(qim) , &quser ) ;
#else
                 AFNI_CALL_1D_funcstr( grapher->transform1D_func ,
                                       qim->nx , qim->xo , qim->dx ,
                                       MRI_FLOAT_PTR(qim) , quser ) ;
#endif
                 if( quser != NULL )
                   grapher->tuser[ix][iy] = XtNewString(quser) ;
              }
            } else {                           /* 28 Mar 2002: process MRI_IMAGE struct */
                                                                            /* in place */
              if( ! (grapher->transform1D_flags & RETURNS_STRING) ){
#if 0
                 grapher->transform1D_func( qim ) ;
#else
                 AFNI_CALL_1D_funcmrim( grapher->transform1D_func , qim ) ;
#endif
              } else {
                 char *quser = NULL ;
#if 0
                 grapher->transform1D_func( qim , &quser ) ;
#else
                 AFNI_CALL_1D_funcmrimstr( grapher->transform1D_func , qim,quser ) ;
#endif
                 if( quser != NULL )
                   grapher->tuser[ix][iy] = XtNewString(quser) ;
              }
            }

            /* At this point, qim is transformed;
               if dplot is on, then it is saved in dplot_imar;
               if dplot is off, then qim == tsim, and it will be saved in tsimar, below */

         } /* end of transform1D */

         /* put this (possibly transformed) image on the list of those to plot */

         ADDTO_IMARR(tsimar,tsim) ;
      }
   }

   /** find the average time series [27 Jan 2004] **/

   if( ntmax > 1 && IMARR_COUNT(tsimar) > 0 ){
     float *avar , fac ; int nax ;
STATUS("about to make average time series") ;
     if( grapher->ave_tsim != NULL ) mri_free(grapher->ave_tsim) ;
     grapher->ave_tsim = mri_new( ntmax , 1 , MRI_float ) ;
     avar = MRI_FLOAT_PTR(grapher->ave_tsim) ;  /* is full of 0's already */
     for( ix=0 ; ix < IMARR_COUNT(tsimar) ; ix++ ){
       tsim = IMARR_SUBIMAGE(tsimar,ix) ; if( tsim == NULL ) continue ;
       tsar = MRI_FLOAT_PTR(tsim)       ; if( tsar == NULL ) continue ;
       nax  = MIN( ntmax , tsim->nx ) ;
       for( i=0 ; i < nax ; i++ ) avar[i] += tsar[i] ;
     }
     fac = 1.0 / IMARR_COUNT(tsimar) ;
     for( i=0 ; i < grapher->ave_tsim->nx ; i++ ) avar[i] *= fac ;

     if( MCW_val_bbox(grapher->fmenu->fim_editref_winaver_bbox) ){
       if( grapher->ref_ts == NULL ) INIT_IMARR( grapher->ref_ts ) ;
       if( IMARR_COUNT(grapher->ref_ts) == 0 ){
         ADDTO_IMARR( grapher->ref_ts , grapher->ave_tsim ) ;     /* create first one */
       } else {
         IMARR_SUBIMAGE(grapher->ref_ts,0) = grapher->ave_tsim ;  /* replace first one */
       }
     }
   } else if( grapher->ave_tsim != NULL ){
     mri_free(grapher->ave_tsim) ; grapher->ave_tsim = NULL ;
   }

   /** find some statistics of each time series **/

STATUS("finding statistics of time series") ;

   /* stuff for setting vertical scale */

   if( set_scale ){
     nd_bot = WAY_BIG ; nd_top = nd_dif = - WAY_BIG ;  /* 03 Feb 1998 */
   }

   for( ix=0,its=0 ; ix < grapher->mat ; ix++ ){
      for( iy=0 ; iy < grapher->mat ; iy++,its++ ){
         float qbot,qtop ;
         double qsum , qsumq ;

         tsim = IMARR_SUBIMAGE(tsimar,its) ;
         if( tsim == NULL || tsim->nx < 2 ){
           grapher->tmean[ix][iy] = grapher->tbot[ix][iy] =
             grapher->ttop[ix][iy] = grapher->tstd[ix][iy] = 0.0 ;
           grapher->tmed[ix][iy] = grapher->tmad[ix][iy] = 0.0 ;  /* 08 Mar 2001 */
           grapher->sbot[ix][iy] = grapher->stop[ix][iy] = 0 ;    /* 19 Mar 2004 */
           continue ;
         }

         tsar = MRI_FLOAT_PTR(tsim) ;     /* stats from ibot..itop-1 */
         itop = MIN( ttop , tsim->nx ) ;  /* ibot was set earlier    */

         if( itop-ibot < 2 ){                       /* too short to deal with */
           grapher->tmean[ix][iy] = grapher->tbot[ix][iy] =
             grapher->ttop[ix][iy] = grapher->tstd[ix][iy] = 0.0 ;
           grapher->tmed[ix][iy] = grapher->tmad[ix][iy] = 0.0 ;  /* 08 Mar 2001 */
           continue ;  /* to next iy */
         }

         qbot = qtop  = tsar[ibot] ;
         qsum = qsumq = 0.0 ;
         for( i=ibot ; i < itop ; i++ ){      /* compute stats over visible data */
           qbot   = MIN( qbot , tsar[i] ) ;
           qtop   = MAX( qtop , tsar[i] ) ;
           qsum  += tsar[i] ;
           qsumq += tsar[i] * tsar[i] ;
         }
         grapher->tbot[ix][iy] = qbot ; grapher->ttop[ix][iy] = qtop ;
         grapher->sbot[ix][iy] = ibot ; grapher->stop[ix][iy] = itop-1 ; /* 19 Mar 2004 */
         qsum  = qsum / (itop-ibot) ; grapher->tmean[ix][iy] = qsum ;
         qsumq = (qsumq - (itop-ibot) * qsum * qsum) / (itop-ibot-1.0) ;
         grapher->tstd[ix][iy] = (qsumq > 0.0) ? sqrt(qsumq) : 0.0 ;

         qmedmad_float( itop-ibot , tsar+ibot ,        /* 08 Mar 2001 */
                        &(grapher->tmed[ix][iy]) ,
                        &(grapher->tmad[ix][iy]) ) ;

         if( set_scale ){        /* 03 Feb 1998 */

           if( tsim->ny > 1 ){
             for( tt=1 ; tt < tsim->ny ; tt++ ){  /* get min/max over     */
               tsar += tsim->nx ;                 /* multiple time series */
               for( i=ibot ; i < itop ; i++ ){    /* if they are present  */
                 qbot = MIN( qbot , tsar[i] ) ;
                 qtop = MAX( qtop , tsar[i] ) ;
               }
             }
           }

           nd_bot = MIN( nd_bot , qbot ) ;        /* vertical scale stuff */
           nd_top = MAX( nd_top , qtop ) ;
           nd_dif = MAX( nd_dif , (qtop-qbot) ) ;
         }
      }
   }

   /* 03 Feb 1998: set the initial vertical scale factor */

   if( set_scale && nd_bot < nd_top && nd_dif > 0.0 ){

      switch( grapher->common_base ){
         default:
         case BASELINE_INDIVIDUAL:
            grapher->fscale = 0.9 * grapher->gy / nd_dif ;          /* biggest range */
         break ;

         case BASELINE_COMMON:
            grapher->fscale = 0.9 * grapher->gy / (nd_top-nd_bot) ; /* global range */
         break ;

         case BASELINE_GLOBAL:{
            float vbot = (nd_top > grapher->global_base)
                        ? grapher->global_base : nd_bot ;
            grapher->fscale = 0.9 * grapher->gy / (nd_top-vbot) ;
         }
         break ;
      }

      if( grapher->fscale > 0.0 && grapher->fscale < 1.0 )       /* switcheroo */
         grapher->fscale = -1.0 / grapher->fscale ;

           if( grapher->fscale > 4.0 )                           /* even value */
                  grapher->fscale = (int) grapher->fscale ;

      else if( grapher->fscale > 1.0 )
                  grapher->fscale = 0.5 * ((int)(2.0*grapher->fscale)) ;

      else if( grapher->fscale < -4.0 )
                  grapher->fscale = -((int)(1.0-grapher->fscale)) ;

      else if( grapher->fscale < -1.0 )
                  grapher->fscale = -0.5 * ((int)(1.0-2.0*grapher->fscale)) ;
   }

   /** find the smallest element in all the time series, if needed **/

   if( grapher->common_base == BASELINE_COMMON ){
     int first = 1 ;

STATUS("finding common base") ;

     for( ix=0 ; ix < tsimar->num ; ix++ ){
       tsim = IMARR_SUBIMAGE(tsimar,ix) ;
       if( tsim == NULL || tsim->nx < 2 ) continue ;   /* skip */
       tsar = MRI_FLOAT_PTR(tsim) ;
       itop = MIN( ttop , tsim->nx ) ;
       if( first && ibot < itop ){ tsbot = tsar[ibot] ; first = 0 ; }
       for( tt=0 ; tt < tsim->ny ; tt++ ){  /* 29 Mar 2002 */
         for( i=ibot ; i < itop ; i++ ) tsbot = MIN( tsbot , tsar[i] ) ;
         tsar += tsim->nx ;
       }
     }
   } else if( grapher->common_base == BASELINE_GLOBAL ){ /* 07 Aug 2001 */
     tsbot = grapher->global_base ;
   }

   /**** loop over matrix of graphs and plot them all to the pixmap ****/

STATUS("starting time series graph loop") ;
   for( ix=0,its=0 ; ix < grapher->mat ; ix++ ){

      for( iy=0 ; iy < grapher->mat ; iy++,its++ ){

         tsim = IMARR_SUBIMAGE(tsimar,its) ;
         if( tsim == NULL || tsim->nx < 2 ) continue ; /* skip to next iy */
         tsar = MRI_FLOAT_PTR(tsim) ;
         itop = MIN( ttop , tsim->nx ) ;
         qnum = itop - pbot ;          /* number of points to plot here */
         if( qnum < 2 ) continue ;     /* skip to next iy */

         /** find bottom value for this graph, if needed **/

         if( grapher->common_base == BASELINE_INDIVIDUAL ){
           tsbot = tsar[ibot] ;
           for( tt=0 ; tt < tsim->ny ; tt++ ){
             for( i=ibot ; i < itop ; i++ ) tsbot = MIN(tsbot,tsar[i]) ;
             tsar += tsim->nx ;
           }
         }
         grapher->pmin[ix][iy] = tsbot ;  /* value at graph bottom */

         /** 29 Mar 2002: decode 'color:' from tsim->name, if present **/

         use_ovi = (tsim->name!=NULL) && (strncmp(tsim->name,"color: ",7)==0) ;
         if( use_ovi ){
           char *cpt = tsim->name+6 ; int nuse, ngood ;
           for( tt=0 ; tt < OVI_MAX ; tt++ )
             ovi[tt] = DATA_COLOR(grapher) ;
           for( tt=0 ; tt < OVI_MAX ; tt++ ){
             ngood = sscanf(cpt,"%d%n",ovi+tt,&nuse) ;
             if( ngood < 1 ) break ;
             cpt += nuse ; if( *cpt == '\0' ) break ;
           }
         }

         tsar = MRI_FLOAT_PTR(tsim) ;
         for( tt=0 ; tt < tsim->ny ; tt++ ){  /* 29 Mar 2002: multi-plots */

          /** scale graph vertically:
               fscale > 0 ==> this many pixels per unit of tsar
               fscale < 0 ==> this many units of tsar per pixel **/

          ftemp = grapher->fscale ;
               if( ftemp == 0.0 ) ftemp =  1.0 ;
          else if( ftemp <  0.0 ) ftemp = -1.0 / ftemp ;

          /* scale to vertical pixels: before the ignore level */

          for( i=pbot ; i < MIN(ibot,itop) ; i++ )
            plot[i-pbot] = (tsar[ibot] - tsbot) * ftemp ;

          /* scale after the ignore level */

          for( i=ibot ; i < itop ; i++ )
            plot[i-pbot] = (tsar[i] - tsbot) * ftemp ;

          /* now have qnum points in plot[] */

          grapher->pmax[ix][iy] = tsbot + grapher->gy / ftemp ; /* value at graph top */

          /** Compute X11 line coords from pixel heights in plot[].
              N.B.: X11 y is DOWN the screen, but plot[] is UP the screen **/

          ftemp = grapher->gx / (pnum-1.0) ;  /* x scale factor */

          /* X11 box for graph:
             x = xorigin[ix][iy]          .. xorigin[ix][iy]+gx    (L..R)
             y = fHIGH-yorigin[ix][iy]-gy .. fHIGH-yorigin[ix][iy] (T..B) */

          xoff  = grapher->xorigin[ix][iy] ;
          yoff  = grapher->fHIGH - grapher->yorigin[ix][iy] ;

          /* 09 Jan 1998: allow x-axis to be chosen by a
                         timeseries that ranges between 0 and 1 */

#define XPIX(ii)                                                        \
   ( (grapher->xax_tsim != NULL && (ii) < grapher->xax_tsim->nx)        \
     ? (MRI_FLOAT_PTR(grapher->xax_tsim)[MAX((ii),ibot)] * grapher->gx) \
     : (((ii)-pbot) * ftemp) )

          for( i=0 ; i < qnum ; i++ ){         /* generate X11 plot lines */
            a_line[i].x = xoff + XPIX(i+pbot);
            a_line[i].y = yoff - plot[i] ;
          }

          if( use_ovi )                       /* 29 Mar 2002: line color */
            DC_fg_color( grapher->dc , ovi[tt%OVI_MAX] ) ;

          if( DATA_POINTS(grapher) ){         /* 09 Jan 1998 */
            for( i=0 ; i < qnum ; i++ )
              GRA_small_circle( grapher,a_line[i].x,a_line[i].y,DATA_IS_THICK(grapher) );
          }
          if( DATA_LINES(grapher) ){          /* 01 Aug 1998 */
            XDrawLines( grapher->dc->display ,
                        grapher->fd_pxWind , grapher->dc->myGC ,
                        a_line , qnum ,  CoordModeOrigin ) ;
          }

         /* 22 July 1996: save central graph data for later use */

          if( ix == grapher->xc && iy == grapher->yc && tt == 0 ){
            for( i=0 ; i < qnum ; i++ ) grapher->cen_line[i] = a_line[i] ;
            grapher->nncen = qnum ;
            mri_free( grapher->cen_tsim ) ;             /* copy time series too */
            grapher->cen_tsim = mri_to_float( tsim ) ;
          }

          tsar += tsim->nx ;  /* 29 Mar 2002: advance to next curve */
         } /* end of loop over multi-plot (tt) */

         if( use_ovi )
           DC_fg_color( grapher->dc , DATA_COLOR(grapher) ) ; /* reset color */

         /* 08 Nov 1996: double plot?  Duplicate the above drawing code! */
         /* 07 Aug 2001: old method was DPLOT_OVERLAY,
                         new method is  DPLOT_PLUSMINUS */
         /* 29 Mar 2002: allow multiple time series (dsim->ny > 1) */

         if( dplot ){
            int dny , id , qq,qtop ;
            dsim = IMARR_SUBIMAGE(dplot_imar,its) ;
            if( dsim == NULL || dsim->nx < 2 ) continue ;  /* skip to next iy */
            dsar = MRI_FLOAT_PTR(dsim) ;
            tsar = MRI_FLOAT_PTR(tsim) ;   /* 25 Feb 2003: reset this */
            itop = MIN( ttop , dsim->nx ); /* ibot was set long ago */
            qnum = itop - pbot ;           /* number of points to plot here */
            if( qnum < 2 ) continue ;      /* skip to next iy = next sub-graph */

            if( dplot == DPLOT_PLUSMINUS ) dny = 1 ;        /* 29 Mar 2002 */
            else                           dny = dsim->ny ;

            /** 29 Mar 2002: decode 'color:' from dsim->name, if present **/

            use_ovi = (dsim->name!=NULL) && (strncmp(dsim->name,"color: ",7)==0) ;
            if( use_ovi ){
              char *cpt = dsim->name+6 ; int nuse, ngood ;
              for( tt=0 ; tt < OVI_MAX ; tt++ )
                ovi[tt] = DPLOT_COLOR(grapher) ;
              for( tt=0 ; tt < OVI_MAX ; tt++ ){
                ngood = sscanf(cpt,"%d%n",ovi+tt,&nuse) ;
                if( ngood < 1 ) break ;
                cpt += nuse ; if( *cpt == '\0' ) break ;
              }
            }

            for( id=0 ; id < dny ; id++ ){          /* 29 Mar 2002: multi-plots */

             ftemp = grapher->fscale ;
                  if( ftemp == 0.0 ) ftemp =  1.0 ;
             else if( ftemp <  0.0 ) ftemp = -1.0 / ftemp ;

             /* 18 Mar 2004: scan backwards from itop to reject superlarge values */

             for( qtop=itop-1 ; qtop >= pbot ; qtop-- )
               if( dsar[qtop] < WAY_BIG ) break ;
             if( qtop <= ibot ){ dsar += dsim->nx; continue; }  /* skip */
             qtop++ ; qnum = qtop-pbot ;

             switch( dplot ){
               default:
               case DPLOT_OVERLAY:                       /* plot curve */
                 for( i=pbot ; i < MIN(ibot,qtop) ; i++ )
                   plot[i-pbot] = (dsar[ibot] - tsbot) * ftemp ;
                 for( i=ibot ; i < qtop ; i++ )
                   plot[i-pbot] = (dsar[i] - tsbot) * ftemp ;
               break ;

               case DPLOT_PLUSMINUS:                     /* plus side */
                 for( i=pbot ; i < MIN(ibot,qtop) ; i++ )
                   plot[i-pbot] = (tsar[ibot]+dsar[ibot] - tsbot) * ftemp ;
                 for( i=ibot ; i < qtop ; i++ )
                   plot[i-pbot] = (tsar[i]   +dsar[i]    - tsbot) * ftemp ;
               break ;
             }

             ftemp = grapher->gx / (pnum-1.0) ;  /* cf. XPIX */
             xoff  = grapher->xorigin[ix][iy] ;
             yoff  = grapher->fHIGH - grapher->yorigin[ix][iy] ;

             for( i=0 ; i < qnum ; i++ ){
               a_line[i].x = xoff + XPIX(i+pbot) ;  /* 09 Jan 1998 */
               a_line[i].y = yoff - plot[i] ;
             }

             if( use_ovi )                      /* 29 Mar 2002 */
               DC_fg_color( grapher->dc , ovi[id%OVI_MAX] ) ;
             else
               DC_fg_color( grapher->dc , DPLOT_COLOR(grapher) ) ;

             if( DPLOT_POINTS(grapher) ){       /* 09 Jan 1998 */
               for( i=0 ; i < qnum ; i++ )
                GRA_small_circle(grapher,a_line[i].x,a_line[i].y,DPLOT_IS_THICK(grapher));
             }
             if( DPLOT_LINES(grapher) ) {        /* 01 Aug 1998 */
               DC_linewidth( grapher->dc , DPLOT_THICK(grapher) ) ;
               XDrawLines( grapher->dc->display ,
                           grapher->fd_pxWind , grapher->dc->myGC ,
                           a_line , qnum ,  CoordModeOrigin ) ;
             }

             /* plot minus side of plus/minus curve? */

             if( dplot == DPLOT_PLUSMINUS ){  /* lots of duplicate code :-( */
              ftemp = grapher->fscale ;
                   if( ftemp == 0.0 ) ftemp =  1.0 ;
              else if( ftemp <  0.0 ) ftemp = -1.0 / ftemp ;
              for( i=pbot ; i < MIN(ibot,qtop) ; i++ )
                plot[i-pbot] = (tsar[ibot]-dsar[ibot] - tsbot) * ftemp ;
              for( i=ibot ; i < qtop ; i++ )
                plot[i-pbot] = (tsar[i]   -dsar[i]    - tsbot) * ftemp ;
              ftemp = grapher->gx / (pnum-1.0) ;
              for( i=0 ; i < qnum ; i++ ){
                a_line[i].x = xoff + XPIX(i+pbot) ;
                a_line[i].y = yoff - plot[i] ;
              }
              if( DPLOT_POINTS(grapher) ){
               for( i=0 ; i < qnum ; i++ )
                GRA_small_circle(grapher,a_line[i].x,a_line[i].y,DPLOT_IS_THICK(grapher));
              }
              if( DPLOT_LINES(grapher) ) {
                DC_linewidth( grapher->dc , DPLOT_THICK(grapher) ) ;
                XDrawLines( grapher->dc->display ,
                            grapher->fd_pxWind , grapher->dc->myGC ,
                            a_line , qnum ,  CoordModeOrigin ) ;
              }
             }

             dsar += dsim->nx ;      /* 29 Mar 2002: next curve */
            } /* end of loop over multiple dplots */

            DC_fg_color ( grapher->dc , DATA_COLOR(grapher) ) ;
            DC_linewidth( grapher->dc , DATA_THICK(grapher) ) ;

         } /* end of dplot */

         /* 05 Jan 1999: plot horizontal line through zero, if desired and needed */

         if( grapher->HorZ && grapher->pmin[ix][iy] < 0.0 && grapher->pmax[ix][iy] > 0.0 ){
           DC_fg_color ( grapher->dc , GRID_COLOR(grapher) ) ;
           DC_linewidth( grapher->dc , GRID_THICK(grapher) ) ;
           DC_dashed_line( grapher->dc ) ;

           ftemp = grapher->fscale ;
                if( ftemp == 0.0 ) ftemp =  1.0 ;
           else if( ftemp <  0.0 ) ftemp = -1.0 / ftemp ;

           XDrawLine( grapher->dc->display , grapher->fd_pxWind , grapher->dc->myGC ,
                      (int) xoff                , (int)(yoff + tsbot * ftemp) ,
                      (int)(xoff + grapher->gx) , (int)(yoff + tsbot * ftemp)  ) ;

           DC_fg_color ( grapher->dc , DATA_COLOR(grapher) ) ;
           DC_linewidth( grapher->dc , DATA_THICK(grapher) ) ;
           DC_solid_line( grapher->dc ) ;
         }

      } /* end of loop over y */
   } /* end of loop over x */

   /** cast away the data timeseries! */

   DESTROY_IMARR(tsimar) ;
   if( dplot_imar != NULL ) DESTROY_IMARR(dplot_imar) ;  /* 08 Nov 1996 */

   /*----- Now do extra plots in center frame, if any -----*/

#define REFTS_FRAC 0.38  /* fraction of one graph that this takes up */
#define REFTS_TOP  0.98  /* top of reference graph in frame */

#define ORTTS_FRAC 0.38
#define ORTTS_TOP  0.78

   /* 12 Nov 1996: include graphs of orts by looping "iex" */

   for( iex=0 ; iex <= 1 ; iex++ ){

      eximar = (iex==0) ? grapher->ref_ts : grapher->ort_ts ;

      if( eximar != NULL && IMARR_COUNT(eximar) > 0 ){
         float yscal , val , xscal , exfrac , extop ;
         int   nover , nvec , nx , ivec ;
         int   excolor , exthick ;

STATUS("plotting extra graphs") ;

         exfrac  = (iex==0) ? REFTS_FRAC : ORTTS_FRAC ;
         extop   = (iex==0) ? REFTS_TOP  : ORTTS_TOP  ;
         excolor = (iex==0) ? IDEAL_COLOR(grapher) : ORT_COLOR(grapher) ;
         exthick = (iex==0) ? IDEAL_THICK(grapher) : ORT_THICK(grapher) ;

         for( its=0 ; its < IMARR_COUNT(eximar) ; its++ ){

            tsim = IMARR_SUBIMAGE(eximar,its) ;

            if( tsim == NULL || tsim->kind != MRI_float || tsim->nx < 2 ) continue ;

            nx   = tsim->nx ;
            itop = MIN( ttop , nx ) ;
            qnum = itop - pbot ; if( qnum < 2 ) continue ;
            nvec = (grapher->ref_ts_plotall) ? (tsim->ny) : 1 ;

            for( ivec=0 ; ivec < nvec ; ivec++ ){  /* plot each sub-vector */
              tsar  = MRI_FLOAT_PTR(tsim) + (ivec*nx) ;
              tsbot = 99999999.0 ; tstop = -99999999.0 ;
              nover = grapher->init_ignore ;
              for( i=ibot ; i < itop ; i++ ){
                val = tsar[i] ;
                if( val < WAY_BIG ){ tstop = MAX(tstop,val); tsbot = MIN(tsbot,val); }
                else               { nover++ ; }
              }
              if( tstop >= WAY_BIG || tstop <= tsbot ) continue ; /* skip */

              /*** scale into a_line and draw it***/

              yscal = exfrac * grapher->gy / (tstop-tsbot) ;
              xscal = ftemp = grapher->gx / (pnum-1.0) ;

              xoff  = grapher->xorigin[grapher->xc][grapher->yc] ;
              yoff  = grapher->fHIGH - grapher->yorigin[grapher->xc][grapher->yc]
                                     - (extop - exfrac) * grapher->gy ;

              for( i=pbot ; i < itop; i++ ){
                val = (i >= ibot &&  tsar[i] < WAY_BIG) ? tsar[i] : tsbot ;

                a_line[i-pbot].x = xoff + XPIX(i) ;           /* 09 Jan 1998 */
                a_line[i-pbot].y = yoff - yscal*(val-tsbot) ;
              }

              /* if none are over the limit, draw in one operation;
                 otherwise, must plot each line separately in its needed color */

              if( nover == 0 ){
                DC_fg_color ( grapher->dc , excolor ) ;
                DC_linewidth( grapher->dc , exthick ) ;
                XDrawLines( grapher->dc->display ,
                            grapher->fd_pxWind , grapher->dc->myGC ,
                            a_line , qnum ,  CoordModeOrigin ) ;
              } else {
                for( i=pbot ; i < itop-1 ; i++ ){
                  if( i >= ibot && tsar[i] < WAY_BIG && tsar[i+1] < WAY_BIG ){
                    DC_fg_color ( grapher->dc , excolor ) ;
                    DC_linewidth( grapher->dc , exthick ) ;
                  } else {
                    DC_fg_color( grapher->dc , IGNORE_COLOR(grapher) ) ;
                    if( grapher->mat < 4 &&
                        ( i < ibot || tsar[i] >= WAY_BIG ) )
                      GRA_small_circle( grapher,a_line[i-pbot].x,a_line[i-pbot].y,0 );
                  }

                  XDrawLines( grapher->dc->display ,
                              grapher->fd_pxWind , grapher->dc->myGC ,
                              a_line + (i-pbot) , 2 ,  CoordModeOrigin ) ;
                }
                if( grapher->mat < 4 &&
                    ( i < ibot || tsar[i] >= WAY_BIG ) )
                  GRA_small_circle( grapher,a_line[i-pbot].x,a_line[i-pbot].y,0 );
              }
            } /* end of loop over sub-vectors */
         } /* end of loop over refs */
      } /* end of if refs exist */
   } /* end of loop over refs and orts */

   /*---- 09 Jan 1998: plot graph showing x-axis as well ----*/

   if( grapher->xax_tsim != NULL ){
     float yscal , ftemp , xscal , yoff ;
     int   npt ;

     xscal = GL_DLX / (float) grapher->gx ;
     yscal = grapher->gy / (pnum-1.0) ;
     yoff  = grapher->fHIGH - grapher->yorigin[grapher->xc][grapher->yc] ;
     ftemp = 1.0 ;
     npt   = ttop ;
     if( npt > grapher->xax_tsim->nx ) npt = grapher->xax_tsim->nx ;
     if( npt > pbot+1 ){
       for( i=pbot ; i < npt ; i++ ){
         a_line[i-pbot].x = XPIX(i) * xscal ;
         a_line[i-pbot].y = yoff - yscal*(i-pbot) ;
       }
       DC_fg_color ( grapher->dc , IDEAL_COLOR(grapher) ) ;
       DC_linewidth( grapher->dc , IDEAL_THICK(grapher) ) ;
       XDrawLines( grapher->dc->display , grapher->fd_pxWind , grapher->dc->myGC ,
                   a_line , npt-pbot ,  CoordModeOrigin ) ;
     }
   }

   /***** Done!!! *****/

   EXRETURN ;
}

/*------------------------------------------------------------------------
   Draw frames around each sub-graph and grids inside them
   12 Jan 1998: modified to allow for gaps between graphs
--------------------------------------------------------------------------*/

void draw_grids( MCW_grapher * grapher )
{
   int i , mat=grapher->mat , gx=grapher->gx , gy=grapher->gy ;
   int j, k, g, xo, yo, npoints , m ;
   int xc = grapher->xc , yc = grapher->yc ;
   float ftemp ;

ENTRY("draw_grids") ;
   if( grapher->dont_redraw ) EXRETURN ;  /* 27 Jan 2004 */

   /* draw grid lines in the chosen color */

   if( GRID_COLOR(grapher) > 0 ){
      DC_fg_color ( grapher->dc , GRID_COLOR(grapher) ) ;
      DC_linewidth( grapher->dc , GRID_THICK(grapher) ) ;

      g       = grapher->grid_spacing ;
      npoints = NPTS(grapher) ;  /* number time points in 1 sub-graph window */

      if( npoints > 1 ){                /* this if: 22 Sep 2000 */
        ftemp = gx / (npoints-1.0) ;
        for( i=0 ; i < mat ; i++ ){
          for( m=0 ; m < mat ; m++ ){
            xo = grapher->xorigin[i][m] ; yo = grapher->yorigin[i][m] ;
            for( j=1 ; j <= (npoints-1)/g ; j++ ){
              k = xo + j * g * ftemp ;
              plot_fdX( grapher , k , yo    , 0 ) ;
              plot_fdX( grapher , k , yo+gy , 1 ) ;
            }
          }
        }
      }

      /* draw an interior framing box at the central square */

      xo = grapher->xorigin[xc][yc] ; yo = grapher->yorigin[xc][yc] ;
      g  = MIN( grapher->gy/3 , grapher->gx/3 ) ; g  = MIN( g , 4 ) ;
      for( j=1 ; j <= g ; j++ ){
         plot_fdX( grapher , xo+j    , yo+j    , 0 ) ;
         plot_fdX( grapher , xo+j    , yo+gy-j , 1 ) ;
         plot_fdX( grapher , xo+gx-j , yo+gy-j , 1 ) ;
         plot_fdX( grapher , xo+gx-j , yo+j    , 1 ) ;
         plot_fdX( grapher , xo+j    , yo+j    , 1 ) ;
      }
   }

   /* draw exterior frames */

   DC_fg_color ( grapher->dc , FG_COLOR(grapher) ) ;
   DC_linewidth( grapher->dc , FG_THICK(grapher) ) ;

   for( i=0 ; i < mat ; i++ ){
      for( j=0 ; j < mat ; j++ ){
         xo = grapher->xorigin[i][j] ; yo = grapher->yorigin[i][j] ;
         plot_fdX( grapher , xo    , yo    , 0 ) ;
         plot_fdX( grapher , xo+gx , yo    , 1 ) ;
         plot_fdX( grapher , xo+gx , yo+gy , 1 ) ;
         plot_fdX( grapher , xo    , yo+gy , 1 ) ;
         plot_fdX( grapher , xo    , yo    , 1 ) ;
      }
   }

   EXRETURN ;
}

/*------------------------------------------
  Send the caller info about the new graph
--------------------------------------------*/

void send_newinfo( MCW_grapher *grapher )
{
ENTRY("send_newinfo") ;

   if( GRA_VALID(grapher) && grapher->status->send_CB != NULL ){
      GRA_cbs cbs ;

      cbs.reason = graCR_newxyzm   ;
      cbs.xcen   = grapher->xpoint ;
      cbs.ycen   = grapher->ypoint ;
      cbs.zcen   = grapher->zpoint ;
      cbs.mat    = grapher->mat ;
#if 0
      grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
#else
      CALL_sendback( grapher , cbs ) ;
#endif
   }

   EXRETURN ;
}

/*---------------------------
   initialize matrix stuff
-----------------------------*/

void init_mat( MCW_grapher *grapher )
{
   int i, j ;
   int gg ;

ENTRY("init_mat") ;
   if( !GRA_VALID(grapher) ) EXRETURN ;

   grapher->gx = grapher->gx_max / grapher->mat;
   grapher->gy = grapher->gy_max / grapher->mat;

   for (i=0;i<grapher->mat;i++) {
     for (j=0;j<grapher->mat;j++) {
       grapher->xorigin[i][j] = MDX1 + i * grapher->gx;
       grapher->yorigin[i][j] = MDY1 + j * grapher->gy;
     }
   }

   if( grapher->mirror && grapher->mat > 1 ){  /* Jul 2000 */
      int mm = grapher->mat , m2 = mm/2 ;      /* swap left and right */

      for( j=0 ; j < mm ; j++ ){
         for( i=0 ; i < m2 ; i++ ){
           gg                          = grapher->xorigin[i][j] ;
           grapher->xorigin[i][j]      = grapher->xorigin[mm-1-i][j] ;
           grapher->xorigin[mm-1-i][j] = gg ;
         }
      }
   }

   grapher->xc = grapher->mat/2;
   grapher->yc = (grapher->mat-1)/2;

   gg = grapher->ggap ;                /* 12 Jan 1998 */
   if( gg > 0 ){
     gg = MIN( gg , grapher->gx / 2 ) ;  /* shrink sizes of graphs */
     gg = MIN( gg , grapher->gy / 2 ) ;
     grapher->gx -= gg ;
     grapher->gy -= gg ;
   }

   EXRETURN ;
}

/* ----------------------------- */   /* scale plot up and redraw  */
void scale_up( MCW_grapher * grapher )
/* ----------------------------- */
{
   if( !GRA_VALID(grapher) ) return ;
   if (grapher->fscale > 0) grapher->fscale *= 2;
   else if (grapher->fscale < -2) grapher->fscale /= 2;
   else grapher->fscale = 1;

   if( grapher->fscale > 1000000.0 ){
     static int nn=0 ;
     nn++ ; if( nn < 3 ) fprintf(stderr,"Is that you, Bellgowan?  If so, stop it!\a\n") ;
   }
   return ;
}

/* ----------------------------- */   /* scale plot up and redraw  */
void scale_down( MCW_grapher * grapher )
/* ----------------------------- */
{
   if( !GRA_VALID(grapher) ) return ;
   if (grapher->fscale > 1) grapher->fscale /= 2;
   else if (grapher->fscale < 0) grapher->fscale *= 2;
   else grapher->fscale = -2;
   return ;
}

/* ----------------------------- */   /* decrease matrix and redraw  */
void mat_down( MCW_grapher * grapher )
/* ----------------------------- */
{
   int old;

   if( !GRA_VALID(grapher) ) return ;
   old = grapher->mat;
   grapher->mat--;
   if (grapher->mat < 1) grapher->mat = 1;
   else if (grapher->mat > grapher->mat_max) grapher->mat = grapher->mat_max;
   if (grapher->mat!= old) {
      init_mat( grapher ) ;
      redraw_graph( grapher , 0 ) ;
   }
   return ;
}

/* ----------------------------- */   /* increase matrix and redraw  */
void mat_up( MCW_grapher * grapher )
/* ----------------------------- */
{
   int old;

   if( !GRA_VALID(grapher) ) return ;
   old = grapher->mat;
   grapher->mat++;
   if (grapher->mat < 1) grapher->mat = 1;
   else if (grapher->mat > grapher->mat_max) grapher->mat = grapher->mat_max;
   if (grapher->mat!= old) {
      init_mat(grapher) ;
      redraw_graph(grapher,0) ;
   }
   return ;
}

/* ----------------------------- */   /* decrease grid spacing and redraw  */
void grid_down( MCW_grapher * grapher )
/* ----------------------------- */
{
   int old;

   if( !GRA_VALID(grapher) ) return ;
   old = grapher->grid_index;
   grapher->grid_index--;
   if (grapher->grid_index < 0) grapher->grid_index = 0;
   grapher->grid_spacing = grid_ar[grapher->grid_index] ;
   grapher->grid_fixed   = 1 ;  /* 02 Apr 2004 */
   redraw_graph(grapher,0) ;
   return ;
}

/* ----------------------------- */   /* increase grid spacing and redraw  */
void grid_up( MCW_grapher * grapher )
/* ----------------------------- */
{
   int old;

   if( !GRA_VALID(grapher) ) return ;
   old = grapher->grid_index;
   grapher->grid_index++;
   if (grapher->grid_index >= GRID_MAX) grapher->grid_index = GRID_MAX - 1;
   grapher->grid_spacing = grid_ar[grapher->grid_index] ;
   grapher->grid_fixed   = 1 ;  /* 02 Apr 2004 */
   redraw_graph(grapher,0) ;
   return ;
}

/*-----------------------------------------------------------------------
   Handle all events in an grapher drawing area widget
-------------------------------------------------------------------------*/

void GRA_drawing_EV( Widget w , XtPointer client_data ,
                     XEvent * ev , Boolean * continue_to_dispatch )
{
   MCW_grapher * grapher = (MCW_grapher *) client_data ;

ENTRY("GRA_drawing_EV") ;

   if( ! GRA_REALZ(grapher) ){
if(PRINT_TRACING){
char str[256] ;
sprintf(str,"unrealized grapher! Event type = %d",(int)ev->type) ;
STATUS(str) ; }
      EXRETURN ;
   }

   if( grapher->valid == 666 ){  /* 06 Jan 1999 */
if(PRINT_TRACING){
char str[256] ;
sprintf(str,"dying grapher! Event type = %d",(int)ev->type) ;
STATUS(str) ; }
      EXRETURN ;
   }

   switch( ev->type ){

      /*----- redraw -----*/

      case Expose:{
         XExposeEvent * event = (XExposeEvent *) ev ;

if(PRINT_TRACING){
char str[256] ;
sprintf(str,"Expose event with count = %d",event->count) ;
STATUS(str) ; }

         /**
             With the first expose, create the new pixmap.
             For subsequent ones, just redraw the non-pixmap (overlay) stuff.

             06 Jan 1999: check event count
         **/

         XSync( XtDisplay(w) , False ) ;  /* 05 Feb 1999 */

         if( event->count == 0 ){
            if( grapher->fd_pxWind == (Pixmap) 0 ){
               int width , height ;
               MCW_widget_geom( grapher->draw_fd , &width , &height , NULL,NULL ) ;
               GRA_new_pixmap( grapher , width , height , 1 ) ;
            } else {
               GRA_redraw_overlay( grapher ) ;
            }
         }
      }
      break ;

      /*----- take key press -----*/

      case KeyPress:{
         XKeyEvent * event = (XKeyEvent *) ev ;
         char           buf[32] ;
         KeySym         ks=0 ;
         int            nbuf ;

STATUS("KeyPress event") ;

         GRA_timer_stop( grapher ) ;  /* 04 Dec 2003 */

         if( grapher->fd_pxWind != (Pixmap) 0 ){
            buf[0] = '\0' ;
            nbuf = XLookupString( event , buf , 32 , &ks , NULL ) ;
            if( nbuf == 0 ){   /* 24 Jan 2003: substitution for special keys */
              switch(ks){
                case XK_KP_Left:
                case XK_Left:      buf[0] = '<' ; break ;
                case XK_KP_Right:
                case XK_Right:     buf[0] = '>' ; break ;
                case XK_KP_Page_Up:
                case XK_Page_Up:   buf[0] = 'Z' ; break ;
                case XK_KP_Page_Down:
                case XK_Page_Down: buf[0] = 'z' ; break ;
              }
            }
            if( buf[0] != '\0' ) GRA_handle_keypress( grapher , buf , ev ) ;
            else if(PRINT_TRACING){
               char str[256] ;
               sprintf(str,"*** KeyPress was empty!?  nbuf=%d",nbuf) ;
               STATUS(str) ;
            }
         }
      }
      break ;

      /*----- take button press -----*/

      case ButtonPress:{
         XButtonEvent *event = (XButtonEvent *) ev ;
         int bx,by , width,height , but=event->button ;
         int i, j, gx , gy , mat , xloc,yloc ;
         unsigned int but_state ;
         int xd,yd,zd ;  /* 19 Mar 2004: for mangling to AFNI indexes */

STATUS("button press") ;

         /* 26 Feb 2007: Buttons 4 and 5 = scroll wheel = change time point */

         if( but == Button4 || but == Button5 ){
           int tt = (but==Button4) ? grapher->time_index-1 : grapher->time_index+1 ;
           EXRONE(grapher) ; GRA_timer_stop(grapher) ;
           if( tt >= 0 && tt < grapher->status->num_series ){
             if( grapher->status->send_CB != NULL ){
               GRA_cbs cbs ;
               cbs.reason = graCR_setindex; cbs.key = tt; cbs.event = NULL;
               CALL_sendback( grapher , cbs ) ;
             } else {
               (void) drive_MCW_grapher( grapher, graDR_setindex, (XtPointer)tt) ;
             }
           }
           MCW_discard_events( w , ButtonPressMask ) ; EXRETURN;
         }

         bx = event->x ; by = event->y ; but_state = event->state ;
         MCW_discard_events( w , ButtonPressMask ) ;

         /* Button 1 in pixmap logo = toggle on or off */

         if( but == Button1                                &&
             grapher->glogo_pixmap != XmUNSPECIFIED_PIXMAP &&
             bx < grapher->glogo_width                     &&
             grapher->fHIGH - by < grapher->glogo_height     ){

            show_grapher_pixmap = ! show_grapher_pixmap ;

            if( XtIsManaged(grapher->option_rowcol) )     /* 04 Nov 1996 */
              XtUnmanageChild(grapher->option_rowcol) ;
            else
              XtManageChild(grapher->option_rowcol) ;

            redraw_graph( grapher , 0 )  ;
            break ; /* break out of ButtonPress case */
         }

         /* compute which dataset pixel (xloc,yloc) the button press was in */

         /* X11 box for graph (i,j):
            x = xorigin[i][j]          .. xorigin[i][j]+gx    (L..R)
            y = fHIGH-yorigin[i][j]-gy .. fHIGH-yorigin[i][j] (T..B) */

         gx = grapher->gx ; gy = grapher->gy ; mat = grapher->mat ;

         for( i=0 ; i < mat ; i++ )
           if( bx > grapher->xorigin[i][0]      &&
               bx < grapher->xorigin[i][0] + gx   ) break ;  /* find in x */

         if( i == mat ) break ; /* break out of ButtonPress case */

         xloc = grapher->xpoint + i - grapher->xc ;

         for( j=0 ; j < mat ; j++ )                           /* find in y */
           if( by > grapher->fHIGH - grapher->yorigin[0][j] - gy &&
               by < grapher->fHIGH - grapher->yorigin[0][j]        ) break ;

         if( j == mat ) break ; /* break out of ButtonPress case */

         yloc = grapher->ypoint - j + grapher->yc ;

         /* adjust for possible wraparound */

         if (xloc < 0)                    xloc += grapher->status->nx ;
         if (xloc >= grapher->status->nx) xloc -= grapher->status->nx ;
         if (yloc < 0)                    yloc += grapher->status->ny ;
         if (yloc >= grapher->status->ny) yloc -= grapher->status->ny ;

         /* Feb 1998: button 2 --> send message back to AFNI, maybe */
         /* 03 Oct 2002: Shift+Button1 has the same effect */

         if( but == Button2 ||
             ( but == Button1 && (event->state & ShiftMask) &&
                                !(event->state & ControlMask) ) ){

            if( grapher->button2_enabled && (bx > GL_DLX) ){
               GRA_cbs cbs ;
               cbs.reason = graCR_button2_points ;
               cbs.xcen   = xloc ;
               cbs.ycen   = yloc ;
               cbs.zcen   = grapher->zpoint ;
#if 0
               grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
#else
               CALL_sendback( grapher , cbs ) ;
#endif
            } else {
               XBell(XtDisplay(w),100) ;
            }
         }

         /* button 1 --> move to new square as center of matrix,
                         if it is actually a new center, that is,
                         and if graphing is enabled, and if not off left edge */

         if( grapher->fd_pxWind != (Pixmap) 0 &&
             but == Button1                   && (bx > GL_DLX) &&
             ( (xloc != grapher->xpoint) || (yloc != grapher->ypoint) ) ){

               grapher->xpoint = xloc ;
               grapher->ypoint = yloc ;
               redraw_graph( grapher , 0 ) ;
               send_newinfo( grapher ) ;
         }

         /* 22 July 1996:
            button 1 in central graph of matrix causes jump to time_index */

         else if( grapher->fd_pxWind != (Pixmap)0 &&
                  NPTS(grapher) > 1               && !grapher->textgraph     &&
                  (but==Button1)                  && (bx > GL_DLX)           &&
                  (xloc == grapher->xpoint)       && yloc == grapher->ypoint &&
                  grapher->cen_line != NULL       && grapher->nncen > 1        ){

           float dist , dmin=999999.9 ;
           int imin = 0 ;

           /*-- 09 Jan 1998: find closest pixel in central graph --*/

           for( i=0 ; i < grapher->nncen ; i++ ){
             dist =  abs( bx - grapher->cen_line[i].x )   /* L1 distance */
                   + abs( by - grapher->cen_line[i].y ) ;
             if( dist < dmin ){ dmin = dist; imin = i; if(dmin == 0) break; }
           }
           i = imin + NBOT(grapher) ;

           if( i >= 0 && i < TTOP(grapher) ){
             if( grapher->status->send_CB != NULL ){
               GRA_cbs cbs ;

               cbs.reason = graCR_setindex ;
               cbs.key    = i ;
               cbs.event  = ev ;
#if 0
               grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
#else
               CALL_sendback( grapher , cbs ) ;
#endif
             } else {
               (void) drive_MCW_grapher( grapher,graDR_setindex,(XtPointer)i );
             }
           }
         }

         /* Button 3 --> popup statistics of this graph */

         if( but == Button3 && !ISONE(grapher) && !grapher->textgraph ){
            int ix , iy ;

            ix = xloc - grapher->xpoint + grapher->xc ;
                 if( ix <  0            ) ix += grapher->status->nx ;
            else if( ix >= grapher->mat ) ix -= grapher->status->nx ;

            iy = grapher->ypoint - yloc + grapher->yc ;
                 if( iy <  0            ) iy += grapher->status->ny ;
            else if( iy >= grapher->mat ) iy -= grapher->status->ny ;

            if( ix >= 0 && ix < grapher->mat && iy >= 0 && iy < grapher->mat ){
               XmString xstr ;
               char bmin[16],bmax[16],bmean[16],bstd[16] ;
               char bmed[16] , bmad[16] ; /* 08 Mar 2001 */
               char *qstr , *eee ;        /* 07 Mar 2002 */
               int nlin , nltop=40 ;      /* 07 Mar 2002 */

               AV_fval_to_char( grapher->tbot[ix][iy]  , bmin ) ;
               AV_fval_to_char( grapher->ttop[ix][iy]  , bmax ) ;
               AV_fval_to_char( grapher->tmean[ix][iy] , bmean) ;
               AV_fval_to_char( grapher->tstd[ix][iy]  , bstd ) ;

               AV_fval_to_char( grapher->tmed[ix][iy]  , bmed ) ; /* 08 Mar 2001 */
               AV_fval_to_char( grapher->tmad[ix][iy]  , bmad ) ;

               if( grapher->tuser[ix][iy] == NULL )
                 qstr = AFMALL(char, 912) ;
               else
                 qstr = AFMALL(char, 912+strlen(grapher->tuser[ix][iy])) ;

               /* 19 Mar 2004: mangle FD_brick indexes to AFNI indexes */

               xd = xloc; yd = yloc; zd = grapher->zpoint ;
#ifndef DONT_MANGLE_XYZ
               { THD_ivec3 id ;
                 id = THD_fdind_to_3dind( grapher->getaux , TEMP_IVEC3(xd,yd,zd) ) ;
                 xd = id.ijk[0] ; yd = id.ijk[1] ; zd = id.ijk[2] ; }
#endif
               sprintf( qstr, "Data Statistics\n"
                              "---------------\n"
                              "Indexes = %d:%-d\n" /* 19 Mar 2004 */
                              "x voxel = %d\n"
                              "y voxel = %d\n"
                              "z voxel = %d\n"
                              "Min     =%s\n"
                              "Max     =%s\n"
                              "Mean    =%s\n"
                              "Sigma   =%s\n"
                              "Median  =%s\n"     /* 08 Mar 2001 */
                              "MAD     =%s" ,
                        grapher->sbot[ix][iy], grapher->stop[ix][iy], /* 19 Mar 2004 */
                        xd , yd , zd ,
                        bmin,bmax,bmean,bstd,bmed,bmad ) ;

                /** 22 Apr 1997: incorporate user string for this voxel **/

                if( grapher->tuser[ix][iy] != NULL ){
                  strcat( qstr , "\n------------------\n" ) ;
                  strcat( qstr , grapher->tuser[ix][iy] ) ;
                }

                /* 07 Mar 2002: if string is too long, popup textwin,
                                otherwise just open a popup window    */

                eee = getenv( "AFNI_GRAPH_TEXTLIMIT" ) ;
                if( eee != NULL ){
                  nlin = strtol( eee , NULL , 10 ) ;
                  if( nlin > 0 ) nltop = nlin ;
                }

                for( nlin=1,eee=qstr ; *eee != '\0' ; eee++ )
                  if( *eee == '\n' ) nlin++ ;

                if( nlin < nltop ){
                  xstr = XmStringCreateLtoR( qstr, XmFONTLIST_DEFAULT_TAG ) ;
                  XtVaSetValues( grapher->but3_label,XmNlabelString,xstr,NULL );
                  XmStringFree( xstr ) ;
                  XmMenuPosition( grapher->but3_menu , event ) ; /* where */
                  XtManageChild ( grapher->but3_menu ) ;         /* popup */
                } else {
                  (void) new_MCW_textwin(grapher->fdw_graph,qstr,TEXT_READONLY);
                }
                free(qstr) ;

            } else {
              redraw_graph(grapher,0) ;  /* 11 Nov 1996 */
            }
         }
      }
      break ;

      /*----- window changed size -----*/

      case ConfigureNotify:{
         XConfigureEvent * event = (XConfigureEvent *) ev ;
         int new_width , new_height ;

STATUS("ConfigureNotify event") ;

         XSync( XtDisplay(w) , False ) ;

         new_width  = event->width ;
         new_height = event->height ;

         if( new_width != grapher->fWIDE || new_height != grapher->fHIGH ){
           GRA_new_pixmap( grapher , new_width , new_height , 1 ) ;
         }
      }
      break ;

      /*----- ignore all other events -----*/

      default:
#ifdef AFNI_DEBUG
{char str[256]; sprintf(str,"Event code = %d\n",(int)ev->type); STATUS(str);}
#endif
      break ;

   } /* end of switch ev->type */

   EXRETURN ;
}

/*------------------------------------------------------------------
   Get a new pixmap for drawing purposes
--------------------------------------------------------------------*/

void GRA_new_pixmap( MCW_grapher * grapher ,
                     int new_width , int new_height , int redraw )
{
   int ww,hh ;

ENTRY("GRA_new_pixmap") ;

   if( ! GRA_REALZ(grapher) ) EXRETURN ;

   grapher->fWIDE  = new_width ;
   grapher->fHIGH  = new_height ;
   grapher->gx_max = new_width  - (GL_DLX + GR_DLX) ;
   grapher->gy_max = new_height - (GT_DLY + GB_DLY) ;

   if( grapher->fd_pxWind != (Pixmap) 0 ){
STATUS("freeing old Pixmap") ;
      XFreePixmap( grapher->dc->display , grapher->fd_pxWind ) ;
   }

STATUS("allocating new Pixmap") ;
   grapher->fd_pxWind = XCreatePixmap( grapher->dc->display ,
                                       XtWindow(grapher->draw_fd) ,
                                       grapher->fWIDE , grapher->fHIGH,
                                       grapher->dc->planes ) ;

   MCW_widget_geom( grapher->option_rowcol , &ww , &hh , NULL,NULL ) ;
   XtVaSetValues( grapher->option_rowcol ,
#ifdef WANT_AFNI_BITMAP
                     XmNx , grapher->fWIDE - ww - 2 ,
#else
                     XmNx , 2 ,
#endif
                     XmNy , grapher->fHIGH - hh - 2 ,
                  NULL ) ;

   if( redraw ){
     init_mat( grapher ) ;
     redraw_graph( grapher , 0 ) ;
   }

   EXRETURN ;
}

/*----------------------------------------------------------
  Deal with keypresses in a graph window
------------------------------------------------------------*/

void GRA_handle_keypress( MCW_grapher *grapher , char *buf , XEvent *ev )
{
   int ii ;

ENTRY("GRA_handle_keypress") ;

   if( buf[0] == '\0' ) EXRETURN ;

if(PRINT_TRACING){
char str[256] ;
sprintf(str,"buf[0]=%c (%x)",(int)buf[0],(int)buf[0]) ;
STATUS(str); }

   /*** deal with the key sequence 'N <digits> <Enter>' ***/

   /* first 'N' */

   if( grapher->key_Nlock==0 && buf[0]=='N' ){
     grapher->key_Nlock = 1 ;
     HAND_cursorize( grapher->fdw_graph ) ;
     HAND_cursorize( grapher->draw_fd ) ;
     grapher->key_lock_sum = 0 ;
     EXRETURN ;
   }

   /* last <Enter> */

   if( grapher->key_Nlock && buf[0] == 13 ){

      /* if have a number, set the graph matrix size */

      if( grapher->key_lock_sum > 0 )
         grapher->mat = MIN( grapher->mat_max , grapher->key_lock_sum ) ;

      NORMAL_cursorize( grapher->fdw_graph ) ;
      if( ISONE(grapher) )
        NORMAL_cursorize( grapher->draw_fd ) ;
      else
        POPUP_cursorize( grapher->draw_fd ) ;

      init_mat    ( grapher ) ;
      redraw_graph( grapher , 0 ) ;
      send_newinfo( grapher ) ;
      grapher->key_Nlock = grapher->key_lock_sum = 0 ;
      EXRETURN ;
   }

   /* intermediate <digit> */

   if( grapher->key_Nlock ){
      if( isdigit(buf[0]) ){
         ii = buf[0] - 48;
         grapher->key_lock_sum = MIN( 10000, 10*grapher->key_lock_sum + ii ) ;
      }
      EXRETURN ;
   }

   /*-- other keys are single stroke commands --*/

   MCW_discard_events( grapher->draw_fd , KeyPressMask ) ;

   switch (buf[0]) {

      case '-':
      case '+':
        if( buf[0] == '-' ) scale_down( grapher ) ;
        else                scale_up  ( grapher ) ;
        redraw_graph( grapher , 0 ) ;
      break;

      case 'a':
        redraw_graph( grapher , PLOTCODE_AUTOSCALE ) ;         /* 03 Feb 1998 */
      break ;

      case 'i':
        if( !grapher->textgraph && grapher->init_ignore > 0 ){ /* 24 May 2005 */
          GRA_cbs cbs ;
          cbs.reason = graCR_setignore ; cbs.key = grapher->init_ignore - 1 ;
          CALL_sendback( grapher , cbs ) ;
        } else {
          XBell(grapher->dc->display,100) ;
        }
      break ;

      case 'I':
        if( !grapher->textgraph ){                             /* 24 May 2005 */
          GRA_cbs cbs ;
          cbs.reason = graCR_setignore ; cbs.key = grapher->init_ignore + 1 ;
          CALL_sendback( grapher , cbs ) ;
        } else {
          XBell(grapher->dc->display,100) ;
        }
      break ;

      case 'm':
      case 'M':
        if( buf[0] == 'm' ) mat_down( grapher ) ;
        else                mat_up  ( grapher ) ;
        send_newinfo( grapher ) ;
      break;

      case 'g':
        grid_down( grapher ) ;
      break;

      case 'G':
        grid_up( grapher ) ;
      break;

      case 'h':   /* 05 Jan 1999 */
        grapher->HorZ = ! grapher->HorZ ;
        redraw_graph( grapher , 0 ) ;
      break ;

      case 'q':
      case 'Q':
        end_fd_graph_CB( NULL , (XtPointer) grapher , NULL ) ;
      break ;

      /* modified 07 Aug 2001 to account for more complex baseline scenario */

      case 'b':{
        int bbb = grapher->common_base << 1 ;
        if( bbb > BASELINE_GLOBAL ) bbb = BASELINE_INDIVIDUAL ;
        MCW_set_bbox( grapher->opt_baseline_bbox , bbb ) ;
        grapher->common_base = bbb ;
        redraw_graph( grapher , 0 ) ;
      }
      break ;

      case 't':{                                                  /* 22 Sep 2000 */
        int bbb = ! grapher->textgraph ;
        MCW_set_bbox( grapher->opt_textgraph_bbox , bbb ) ;
        grapher->textgraph = bbb ;
        redraw_graph( grapher , 0 ) ;
      }
      break ;

      case 'S':
        MCW_choose_string( grapher->option_rowcol ,
                           "Save PNM Prefix:" , NULL ,
                           GRA_saver_CB , (XtPointer) grapher ) ;
      break ;

      case 'L':
        show_grapher_pixmap = ! show_grapher_pixmap ;
        if( grapher->glogo_pixmap != XmUNSPECIFIED_PIXMAP )
           redraw_graph( grapher , 0 ) ;
      break ;

      case '<': case ',':   /* change time point */
      case '>': case '.':
      case '[': case ']':
      case '1':
      case 'l':
         EXRONE(grapher) ;  /* 22 Sep 2000 */

              if( buf[0]=='<' || buf[0]==',' || buf[0]=='[' ) ii = grapher->time_index-1;
         else if( buf[0]=='>' || buf[0]=='.' || buf[0]==']' ) ii = grapher->time_index+1;
         else if( buf[0] == '1'  ) ii = 1 ;
         else if( buf[0] == 'l'  ) ii = grapher->status->num_series-1;

         ii = (ii+grapher->status->num_series) % grapher->status->num_series ;
         if( ii >= 0 && ii < grapher->status->num_series ){
           if( grapher->status->send_CB != NULL ){
             GRA_cbs cbs ;

             cbs.reason = graCR_setindex ;
             cbs.key    = ii;
             cbs.event  = NULL ;
#if 0
             grapher->status->send_CB( grapher, grapher->getaux, &cbs ) ;
#else
             CALL_sendback( grapher , cbs ) ;
#endif
           } else {
             (void) drive_MCW_grapher( grapher, graDR_setindex, (XtPointer)ii) ;
           }
         }
      break ;

      case 'v':  /* 04 Dec 2003: video */
      case 'V':
        if( grapher->status->num_series > 1 ){
          grapher->timer_func  = GRA_TIMERFUNC_INDEX ;
          grapher->timer_delay = (int) AFNI_numenv("AFNI_VIDEO_DELAY") ;
          if( grapher->timer_delay <= 0 ) grapher->timer_delay = 1 ;
          grapher->timer_param = (buf[0] == 'v') ? 1 : -1 ;
          grapher->timer_id    =
           XtAppAddTimeOut( XtWidgetToApplicationContext(grapher->opt_quit_pb),
                            grapher->timer_delay , GRA_timer_CB , grapher ) ;
        } else {
          XBell(grapher->dc->display,100) ;
        }
      break ;

      case 'r':
      case 'R':
        if( grapher->status->num_series > 1 ){
          grapher->timer_func  = GRA_TIMERFUNC_BOUNCE ;
          grapher->timer_delay = (int) AFNI_numenv("AFNI_VIDEO_DELAY") ;
          if( grapher->timer_delay <= 0 ) grapher->timer_delay = 1 ;
          grapher->timer_param = (buf[0] == 'r') ? 1 : -1 ;
          grapher->timer_id    =
           XtAppAddTimeOut( XtWidgetToApplicationContext(grapher->opt_quit_pb),
                            grapher->timer_delay , GRA_timer_CB , grapher ) ;
        } else {
          XBell(grapher->dc->display,100) ;
        }
      break ;

      case 'z':  /* change slice */
      case 'Z':
        if( buf[0] == 'z' ){
          grapher->zpoint -- ;
          if( grapher->zpoint < 0 ) grapher->zpoint = grapher->status->nz - 1 ;
        } else {
          grapher->zpoint ++ ;
          if( grapher->zpoint >= grapher->status->nz ) grapher->zpoint = 0 ;
        }
        redraw_graph( grapher , 0 ) ;
        send_newinfo( grapher ) ;
      break ;

      case 'w':{
         char * wcfname ;
         int ndig , ll ;
         MRI_IMAGE * tsim ;
         int xd,yd,zd ;     /* 24 Sep 1999 */

         EXRONE(grapher) ;  /* 22 Sep 2000 */

         ll   = MAX( grapher->status->nx , grapher->status->ny ) ;
         ll   = MAX( grapher->status->nz , ll ) ;
         ndig = (ll < 1000) ? 3 : 4 ;

         ll   = 3*ndig + 16 ;
         if( Grapher_Stuff.wcsuffix != NULL )
            ll += strlen(Grapher_Stuff.wcsuffix) ;
         wcfname = (char *) XtMalloc(ll) ;

         /* 24 Sep 1999: mangle the name for the output */

         xd = grapher->xpoint; yd = grapher->ypoint; zd = grapher->zpoint;
#ifndef DONT_MANGLE_XYZ
         { THD_ivec3 id;
           id = THD_fdind_to_3dind( grapher->getaux, TEMP_IVEC3(xd,yd,zd) );
           xd = id.ijk[0]; yd = id.ijk[1]; zd = id.ijk[2]; }
#endif

         if( Grapher_Stuff.wcsuffix != NULL )
            sprintf(wcfname,"%0*d_%0*d_%0*d.%s.1D" ,
                    ndig,xd , ndig,yd , ndig,zd ,
                              Grapher_Stuff.wcsuffix ) ;
         else
            sprintf(wcfname,"%0*d_%0*d_%0*d.1D" ,
                    ndig,xd , ndig,yd , ndig,zd  ) ;

         ll = grapher->xpoint +
              grapher->ypoint * grapher->status->nx +
              grapher->zpoint * grapher->status->nx * grapher->status->ny ;

#if 0
         tsim  = (MRI_IMAGE *) grapher->getser( ll , graCR_getseries ,
                                                     grapher->getaux ) ;
#else
         CALL_getser( grapher , ll,graCR_getseries , MRI_IMAGE *,tsim ) ;
#endif

         if( tsim != NULL ){
           mri_write_1D( wcfname , tsim ) ;  /* 16 Nov 1999: replaces mri_write_ascii */
           mri_free( tsim ) ;
         }
         myXtFree(wcfname) ;
      }
      break ;

      /*--- At this point, have a key not handled here.
            Call the creator to see if it wishes to deal with it. ---*/

      default:
        if( grapher->status->send_CB != NULL ){
          GRA_cbs cbs ;

          cbs.reason = graCR_keypress ;
          cbs.key    = buf[0] ;
          cbs.event  = ev ;
#if 0
          grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
#else
          CALL_sendback( grapher , cbs ) ;
#endif
        }
      break ;
   }

   EXRETURN ;
}

/*--------------------------------------------------------------------------
   06 Jan 1999: handle death after a timeout.
----------------------------------------------------------------------------*/

void GRA_quit_timeout_CB( XtPointer client_data , XtIntervalId * id )
{
   MCW_grapher * grapher = (MCW_grapher *) client_data ;

ENTRY("GRA_quit_timeout_CB") ;
   GRA_handle_keypress( grapher , "q" , NULL ) ;
   EXRETURN ;
}

/*--------------------------------------------------------------------------
   Handle buttons from the opt menu
----------------------------------------------------------------------------*/

void GRA_opt_CB( Widget w , XtPointer client_data , XtPointer call_data )
{
   MCW_grapher * grapher = (MCW_grapher *) client_data ;

ENTRY("GRA_opt_CB") ;

   if( w == grapher->opt_scale_down_pb ){
      GRA_handle_keypress( grapher , "-" , NULL ) ;
      EXRETURN ;
   }

   if( w == grapher->opt_scale_up_pb ){
      GRA_handle_keypress( grapher , "+" , NULL ) ;
      EXRETURN ;
   }

   if( w == grapher->opt_scale_auto_pb ){
      GRA_handle_keypress( grapher , "a" , NULL ) ;
      EXRETURN ;
   }

   if( w == grapher->opt_grid_down_pb ){
      GRA_handle_keypress( grapher , "g" , NULL ) ;
      EXRETURN ;
   }

   if( w == grapher->opt_grid_up_pb ){
      GRA_handle_keypress( grapher , "G" , NULL ) ;
      EXRETURN ;
   }

   if( w == grapher->opt_grid_auto_pb ){     /* 02 Apr 2004 */
     auto_grid( grapher , NPTS(grapher) ) ;
     redraw_graph(grapher,0) ;
     EXRETURN ;
   }

   if( w == grapher->opt_grid_HorZ_pb ){     /* 05 Jan 1999 */
      GRA_handle_keypress( grapher , "h" , NULL ) ;
      EXRETURN ;
   }

   if( w == grapher->opt_slice_down_pb ){
      GRA_handle_keypress( grapher , "z" , NULL ) ;
      EXRETURN ;
   }

   if( w == grapher->opt_slice_up_pb ){
      GRA_handle_keypress( grapher , "Z" , NULL ) ;
      EXRETURN ;
   }

   if( w == grapher->opt_mat_down_pb ){
      GRA_handle_keypress( grapher , "m" , NULL ) ;
      EXRETURN ;
   }

   if( w == grapher->opt_mat_up_pb ){
      GRA_handle_keypress( grapher , "M" , NULL ) ;
      EXRETURN ;
   }

#if 0
   if( w == grapher->opt_color_up_pb ){
      GRA_handle_keypress( grapher , "r" , NULL ) ;
      EXRETURN ;
   }
#endif

   if( w == grapher->opt_quit_pb ){
#if 0
      GRA_handle_keypress( grapher , "q" , NULL ) ;
#else
STATUS("User pressed Done button: starting timeout") ;
      grapher->valid = 666 ;
      (void) XtAppAddTimeOut( XtWidgetToApplicationContext(w) ,
                              50 , GRA_quit_timeout_CB , grapher ) ;
#endif
      EXRETURN ;
   }

   if( w == grapher->opt_save_pb ){
      GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
      GRA_handle_keypress( grapher , "S" , NULL ) ;
      EXRETURN ;
   }

   if( w == grapher->opt_write_center_pb ){
      GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
      GRA_handle_keypress( grapher , "w" , NULL ) ;
      EXRETURN ;
   }

   if( w == grapher->opt_write_suffix_pb ){
      EXRONE(grapher) ;  /* 22 Sep 2000 */
      GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
      MCW_choose_string( grapher->option_rowcol ,
                         "'Write Center' Suffix:" , Grapher_Stuff.wcsuffix ,
                         GRA_wcsuffix_choose_CB , NULL ) ;
      EXRETURN ;
   }

   if( w == grapher->opt_scale_choose_pb ){
     MCW_choose_integer( grapher->option_rowcol , "Scale" ,
                         -9999 , 9999 , (int)(grapher->fscale) ,
                         GRA_scale_choose_CB , (XtPointer) grapher ) ;
     EXRETURN ;
   }

#ifndef USE_OPTMENUS
   if( w == grapher->opt_mat_choose_pb ){
     MCW_choose_integer( grapher->option_rowcol , "Matrix" ,
                         1 , grapher->mat_max , grapher->mat ,
                         GRA_mat_choose_CB , (XtPointer) grapher ) ;
     EXRETURN ;
   }
#endif

   if( w == grapher->opt_grid_choose_pb ){
     MCW_choose_integer( grapher->option_rowcol , "Grid" ,
                         grid_ar[0] , grid_ar[GRID_MAX-1] , grapher->grid_spacing ,
                         GRA_grid_choose_CB , (XtPointer) grapher ) ;
     EXRETURN ;
   }

   if( w == grapher->opt_pin_choose_pb ){   /* 19 Mar 2004 */
     char *lvec[2] = { "Bot" , "Top" } ;
     int   ivec[2] ;
     ivec[0] = grapher->pin_bot ; ivec[1] = grapher->pin_top ;
     MCW_choose_vector( grapher->option_rowcol , "Graph Pins: Bot..Top-1" ,
                        2 , lvec,ivec ,
                        GRA_pin_choose_CB , (XtPointer) grapher ) ;
     EXRETURN ;
   }

#ifndef USE_OPTMENUS
   if( w == grapher->opt_slice_choose_pb && grapher->status->nz > 1 ){
     MCW_choose_integer( grapher->option_rowcol , "Slice" ,
                         0 , grapher->status->nz - 1 , grapher->zpoint ,
                         GRA_slice_choose_CB , (XtPointer) grapher ) ;
     EXRETURN ;
   }
#endif

   /*** 09 Jan 1998: x-axis stuff ***/

   if( w == grapher->opt_xaxis_clear_pb ){
     mri_free( grapher->xax_tsim ) ;
     grapher->xax_tsim = NULL ;
     GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
     redraw_graph( grapher , 0 ) ;
     EXRETURN ;
   }

   if( w == grapher->opt_xaxis_pick_pb ){
     GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
     if( IMARR_COUNT(GLOBAL_library.timeseries) > 0 ){
       MCW_choose_timeseries( grapher->fdw_graph , "Graph x-axis" ,
                              GLOBAL_library.timeseries , -1 ,
                              GRA_pick_xaxis_CB , (XtPointer) grapher ) ;
     } else {
       (void) MCW_popup_message(
                 grapher->option_rowcol ,
                 "No timeseries library\nexists to pick from!" ,
                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
     }
     EXRETURN ;
   }

   if( w == grapher->opt_xaxis_center_pb ){
     EXRONE(grapher) ;  /* 22 Sep 2000 */
     GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
     if( grapher->cen_tsim != NULL ){
       mri_free( grapher->xax_tsim ) ;
       grapher->xax_tsim = mri_to_float( grapher->cen_tsim ) ;
       redraw_graph(grapher,0) ;
     } else {
       XBell(XtDisplay(w),100) ;
     }
     EXRETURN ;
   }

   /** 07 Aug 2001: Set Global baseline **/

   if( w == grapher->opt_baseline_setglobal_pb ){
     MCW_choose_integer( grapher->option_rowcol , "Global Baseline" ,
                         -29999 , 29999 , (int)(grapher->global_base) ,
                         GRA_finalize_global_baseline_CB ,
                         (XtPointer) grapher ) ;
     EXRETURN ;
   }

   /** shouldn't get to here, but who knows? **/

   EXRETURN ;
}

/*----------------------------------------------------------------------*/

void GRA_fixup_xaxis( MCW_grapher * grapher )  /* 09 Jan 1998 */
{
   int ii , npt , nx , ibot , nover=0 , pbot,ptop ;
   float top,bot , fac ;
   float * xxx ;

ENTRY("GRA_fixup_xaxis") ;

   if( !GRA_VALID(grapher) || grapher->xax_tsim == NULL ) EXRETURN ;

   ptop = TTOP(grapher) ; pbot = TBOT(grapher) ;
   npt = ptop ; nx = grapher->xax_tsim->nx ; npt = MIN(npt,nx) ;
   xxx = MRI_FLOAT_PTR(grapher->xax_tsim) ;

   ibot = grapher->init_ignore ;
   if( ibot >= npt-1 ) ibot = 0 ;
   ibot = MAX(ibot,pbot) ;

   /* find range over plotting interval (ibot..npt-1) */

   top = -WAY_BIG ; bot = WAY_BIG ;
   for( ii=ibot ; ii < npt ; ii++ ){
     if( xxx[ii] < WAY_BIG ){
       top = MAX(top,xxx[ii]) ; bot = MIN(bot,xxx[ii]) ;
     } else {
       nover++ ;
     }
   }
   if( bot >= top ){
     mri_free(grapher->xax_tsim) ;
     grapher->xax_tsim = NULL ;
     EXRETURN ;
   }

   /* scale all of the timeseries */

   fac = 1.0 / (top-bot) ;
   for( ii=0 ; ii < nx ; ii++ ){
     if( xxx[ii] < WAY_BIG ) xxx[ii] = fac * (xxx[ii]-bot) ;
     else                    xxx[ii] = 0.0 ;
   }

   EXRETURN ;
}

/*----------------------------------------------------------------------*/

void GRA_pick_xaxis_CB( Widget wcall , XtPointer cd , MCW_choose_cbs *cbs )
{
   MCW_grapher *grapher = (MCW_grapher *) cd ;
   int its ;
   MRI_IMAGE *tsim ;

ENTRY("GRA_pick_xaxis_CB") ;

   if( !GRA_VALID(grapher) || cbs->reason != mcwCR_timeseries ) EXRETURN ;
   GRA_timer_stop( grapher ) ;

   its = cbs->ival ;
   if( its >= 0 && its < IMARR_COUNT(GLOBAL_library.timeseries) ){
     tsim = IMARR_SUBIMAGE(GLOBAL_library.timeseries,its) ;
     mri_free( grapher->xax_tsim ) ;
     grapher->xax_tsim = mri_to_float(tsim) ;
     redraw_graph( grapher , 0 ) ;
   }

   EXRETURN ;
}

/*----------------------------------------------------------------------
   Callbacks from popup choosers
------------------------------------------------------------------------*/

void GRA_wcsuffix_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs *cbs )
{
   int ll , ii ;

ENTRY("GRA_wcsuffix_choose_CB") ;

   if( cbs->reason != mcwCR_string ||
       cbs->cval   == NULL         || (ll=strlen(cbs->cval)) == 0 ){

     XBell( XtDisplay(wcaller) , 100 ) ; EXRETURN ;
   }

   for( ii=0 ; ii < ll ; ii++ ){
     if( iscntrl(cbs->cval[ii]) ||
         isspace(cbs->cval[ii]) ||
         cbs->cval[ii] == '/'     ){

        XBell( XtDisplay(wcaller) , 100 ) ; EXRETURN ;
     }
   }

   if( Grapher_Stuff.wcsuffix != NULL ) myXtFree(Grapher_Stuff.wcsuffix) ;

   Grapher_Stuff.wcsuffix = XtNewString(cbs->cval) ;
   EXRETURN ;
}

/*-----------------------------------------------------------------------------*/

#ifdef USE_OPTMENUS
void GRA_mat_choose_CB( MCW_arrowval * cbs , XtPointer cd )
#else
void GRA_mat_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs *cbs )
#endif
{
   MCW_grapher *grapher = (MCW_grapher *) cd ;

ENTRY("GRA_mat_choose_CB") ;

   if( ! GRA_VALID(grapher) || cbs->ival < 1 ) EXRETURN ;

   grapher->mat = MIN( grapher->mat_max , cbs->ival ) ;
   init_mat    ( grapher ) ;
   redraw_graph( grapher , 0 ) ;
   send_newinfo( grapher ) ;
   EXRETURN ;
}

/*-----------------------------------------------------------------------------*/

void GRA_scale_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs *cbs )
{
   MCW_grapher *grapher = (MCW_grapher *) cd ;

ENTRY("GRA_scale_choose_CB") ;

   if( ! GRA_VALID(grapher) ) EXRETURN ;

   grapher->fscale = cbs->fval ;
   redraw_graph( grapher , 0 ) ;
   EXRETURN ;
}

/*-----------------------------------------------------------------------------*/

void GRA_grid_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs *cbs )
{
   MCW_grapher *grapher = (MCW_grapher *) cd ;

ENTRY("GRA_grid_choose_CB") ;

   if( ! GRA_VALID(grapher) ) EXRETURN ;
   grapher->grid_spacing = cbs->ival ;
   grapher->grid_fixed   = 1 ;  /* 02 Apr 2004 */
   redraw_graph(grapher,0) ;
   EXRETURN ;
}

/*-----------------------------------------------------------------------------*/

void GRA_pin_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs *cbs )
{
   MCW_grapher *grapher = (MCW_grapher *) cd ;
   float *vec = (float *)(cbs->cval) ;
   int pb=(int)vec[0] , pt=(int)vec[1] , ii ;

ENTRY("GRA_pin_choose_CB") ;

   GRA_timer_stop( grapher ) ;

   if( pb >= grapher->status->num_series-2 ||
       pb <  0                             ||
       (pt > 0 && pt-pb < 2)                 ){   /* stupid user */

      XBell(grapher->dc->display,100) ; EXRETURN ;
   }

   ii = 100000*pt + pb ;
   drive_MCW_grapher( grapher , graDR_setpins , (XtPointer)(ii) ) ;
   EXRETURN ;
}

/*-----------------------------------------------------------------------------*/

void GRA_ggap_CB( MCW_arrowval *cbs , XtPointer cd )  /* 12 Jan 1998 */
{
   MCW_grapher *grapher = (MCW_grapher *) cd ;
   int gg ;

ENTRY("GRA_ggap_CB") ;

   if( ! GRA_VALID(grapher) ) EXRETURN ;

   gg = grapher->ggap ; grapher->ggap = cbs->ival ;
   if( gg != grapher->ggap ){
     init_mat( grapher ) ; redraw_graph( grapher , 0 ) ;
   }

   EXRETURN ;
}

/*-----------------------------------------------------------------------------*/

void GRA_gthick_CB( MCW_arrowval *cbs , XtPointer cd )  /* 06 Oct 2004 */
{
   MCW_grapher *grapher = (MCW_grapher *) cd ;
   int gg ;

ENTRY("GRA_gthick_CB") ;

   if( ! GRA_VALID(grapher) ) EXRETURN ;

   gg = grapher->gthick ; grapher->gthick = cbs->ival ;
   if( gg != grapher->gthick ){
     init_mat( grapher ) ; redraw_graph( grapher , 0 ) ;
   }

   EXRETURN ;
}

/*-----------------------------------------------------------------------------*/

#ifdef USE_OPTMENUS
void GRA_slice_choose_CB( MCW_arrowval *cbs , XtPointer cd )
#else
void GRA_slice_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs *cbs )
#endif
{
   MCW_grapher *grapher = (MCW_grapher *) cd ;

ENTRY("GRA_slice_choose_CB") ;

   if( ! GRA_VALID(grapher) ) EXRETURN ;

   grapher->zpoint = cbs->ival ;
   if( grapher->zpoint >= grapher->status->nz )
      grapher->zpoint = grapher->status->nz - 1 ;
   redraw_graph( grapher , 0 ) ;
   send_newinfo( grapher ) ;
   EXRETURN ;
}

/*-----------------------------------------------------------------------------*/

#ifdef USE_OPTMENUS
void GRA_ignore_choose_CB( MCW_arrowval * cbs , XtPointer cd )
#else
void GRA_ignore_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs *cbs )
#endif
{
   MCW_grapher *grapher = (MCW_grapher *) cd ;

ENTRY("GRA_ignore_choose_CB") ;

   if( ! GRA_VALID(grapher) || grapher->status->send_CB == NULL ) EXRETURN ;

   if( cbs->ival >= 0 && cbs->ival < TTOP(grapher)-1 ){
      GRA_cbs gbs ;

      gbs.reason = graCR_setignore ;
      gbs.key    = cbs->ival ;
#if 0
      grapher->status->send_CB( grapher , grapher->getaux , &gbs ) ;
#else
      CALL_sendback( grapher , gbs ) ;
#endif
   }
   EXRETURN ;
}

/*-----------------------------------------------------------------------------*/

#ifdef USE_OPTMENUS
void GRA_polort_choose_CB( MCW_arrowval * cbs , XtPointer cd )
#else
void GRA_polort_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs * cbs )
#endif
{
   MCW_grapher * grapher = (MCW_grapher *) cd ;

ENTRY("GRA_polort_choose_CB") ;

   if( ! GRA_VALID(grapher) || grapher->status->send_CB == NULL ) EXRETURN ;

   if( cbs->ival >= 0 && cbs->ival <= MAX_POLORT ){
      GRA_cbs gbs ;

      gbs.reason = graCR_polort ;
      gbs.key    = cbs->ival ;
#if 0
      grapher->status->send_CB( grapher , grapher->getaux , &gbs ) ;
#else
      CALL_sendback( grapher , gbs ) ;
#endif
   }
   EXRETURN ;
}

/*-----------------------------------------------------------------------------*/

void GRA_bkthr_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs * cbs )
{
ENTRY("GRA_bkthr_choose_CB") ;
   SET_FIM_bkthr( cbs->fval ) ;
   EXRETURN ;
}

/*-----------------------------------------------------------------------------*/

void GRA_refread_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs * cbs )
{
   MCW_grapher * grapher = (MCW_grapher *) cd ;
   MRI_IMAGE * flim ;
   float * far ;
   int ii ;
   GRA_cbs gbs ;

ENTRY("GRA_refread_choose_CB") ;

   if( ! GRA_VALID(grapher)             ||
       grapher->status->send_CB == NULL ||
       cbs->reason != mcwCR_string      ||
       cbs->cval == NULL                || strlen(cbs->cval) == 0 ) EXRETURN ;

   EXRONE(grapher) ;  /* 22 Sep 2000 */

   flim = mri_read_1D( cbs->cval ) ;     /* 16 Nov 1999: replaces mri_read_ascii */
   if( flim == NULL || flim->nx < 2 ){
      XBell(grapher->dc->display,100) ; mri_free(flim) ; EXRETURN ;
   }

   far = MRI_FLOAT_PTR(flim) ;
   for( ii=0 ; ii < flim->nvox ; ii++ )
      if( fabs(far[ii]) >= 33333.0 ) far[ii] = WAY_BIG ;

   { GRA_cbs cbs; cbs.reason=graCR_winaver; CALL_sendback(grapher,cbs); }
   MCW_set_bbox( grapher->fmenu->fim_editref_winaver_bbox , 0 ) ;
   gbs.reason   = graCR_refequals ;
   gbs.userdata = (XtPointer) flim ;
#if 0
   grapher->status->send_CB( grapher , grapher->getaux , &gbs ) ;
#else
   CALL_sendback( grapher , gbs ) ;
#endif
   mri_free(flim) ;
   EXRETURN ;
}

/*-----------------------------------------------------------------------------*/

void GRA_refstore_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs * cbs )
{
   MCW_grapher * grapher = (MCW_grapher *) cd ;

ENTRY("GRA_refstore_choose_CB") ;

   if( ! GRA_VALID(grapher)             ||
       grapher->ref_ts == NULL          ||
       IMARR_COUNT(grapher->ref_ts) < 1 ||
       cbs->reason != mcwCR_string      ||
       cbs->cval == NULL                || strlen(cbs->cval) == 0 ) EXRETURN ;

   EXRONE(grapher) ;  /* 22 Sep 2000 */

   PLUTO_register_timeseries( cbs->cval , IMARR_SUBIMAGE(grapher->ref_ts,0) ) ;
   EXRETURN ;
}

/*-----------------------------------------------------------------------------*/

void GRA_refwrite_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs * cbs )
{
   MCW_grapher * grapher = (MCW_grapher *) cd ;
   MRI_IMAGE * tsim ;
   int ii , ll ;
   GRA_cbs gbs ;

ENTRY("GRA_refwrite_choose_CB") ;

   if( ! GRA_VALID(grapher)             ||
       grapher->ref_ts == NULL          ||
       IMARR_COUNT(grapher->ref_ts) < 1 ||
       cbs->reason != mcwCR_string      ||
       cbs->cval == NULL                || (ll=strlen(cbs->cval)) == 0 ) EXRETURN ;

   EXRONE(grapher) ;  /* 22 Sep 2000 */

   for( ii=0 ; ii < ll ; ii++ ){
      if( iscntrl(cbs->cval[ii]) || isspace(cbs->cval[ii]) ||
          cbs->cval[ii] == '/'   || cbs->cval[ii] == ';'   ||
          cbs->cval[ii] == '*'   || cbs->cval[ii] == '?'   ||
          cbs->cval[ii] == '&'   || cbs->cval[ii] == '|'   ||
          cbs->cval[ii] == '"'   || cbs->cval[ii] == '>'   ||
          cbs->cval[ii] == '<'   || cbs->cval[ii] == '\''  ||
          cbs->cval[ii] == '['   || cbs->cval[ii] == ']'     ){

         XBell( XtDisplay(wcaller) , 100 ) ; EXRETURN ;
      }
   }

#if 0
   tsim = mri_transpose( IMARR_SUBIMAGE(grapher->ref_ts,0) ) ;
   mri_write_ascii( cbs->cval , tsim ) ;
   mri_free( tsim ) ;
#else
   mri_write_1D( cbs->cval , IMARR_SUBIMAGE(grapher->ref_ts,0) ) ; /* 16 Nov 1999 */
#endif

   /* 12 Nov 1996: put this in AFNI's list of library files */

   if( grapher->status->send_CB != NULL ){
      mri_add_name( cbs->cval , IMARR_SUBIMAGE(grapher->ref_ts,0) ) ;
      gbs.reason   = graCR_timeseries_library ;
      gbs.userdata = (XtPointer) IMARR_SUBIMAGE(grapher->ref_ts,0) ;
#if 0
      grapher->status->send_CB( grapher , grapher->getaux , &gbs ) ;
#else
      CALL_sendback( grapher , gbs ) ;
#endif
   }
   EXRETURN ;
}

/*-----------------------------------------------------------------------
   External interface to drive an MCW_grapher:
     grapher    = pointer to structure returned by new_MCW_grapher
     drive_code = integer indicating which action to take
     drive_data = data or pointer to data controlling action
                  (you will probably have to cast this to
                   XtPointer to avoid ugly warnings from the compiler)

OK   drive_code       drive_data should be
--   ----------       --------------------
*    graDR_cursor     (int) with new cursor id for the image window;
                       (if negative, means from cursorfont)

*    graDR_realize    (ignored) an unrealized viewer is re-realized

*    graDR_redraw     (int *) array of 4 ints: x,y,z,m
                        redraw the graph centered at x,y,z with matrix m

*    graDR_destroy    (ignored) destroy this MCW_grapher, and delete its
                        own XtMalloc-ed internal data structures;
                        after this call, you must myXtFree(grapher) to finish
                        the job.

*    graDR_newdata    (XtPointer) contains new auxiliary data for getser;
                        this call switches the data sequence to a
                        new one entirely.  As with imseq, this should
                        be followed by a call with graDR_redraw.

*    graDR_title      (char *) contains new string for window title bar

*    graDR_icon       (Pixmap) sets the icon for this window

*    graDR_addref_ts  (MRI_IMAGE *) adds a reference timeseries to the list
                        input == NULL --> delete all references
                  ** N.B.: The input timeseries will not be copied, just
                           will keep a pointer to it.  Thus, the input
                           timeseries should not be destroyed.

*    graDR_addort_ts  (MRI_IMAGE *) adds an ort timeseries to the list
                        input == NULL --> delete all orts

*    graDR_winaver    (int) 0=off 1=on WinAver toggle on FIM menu

*    graDR_setignore  (int) set the initial ignore level for graphs

*    graDR_polort     (int) set the polort level for fimmery

*    graDR_setindex   (int) contains the new time_index;
                        All this does is draw some stuff.

*    graDR_button2_enable  (ignored) Turn button2 reporting on
*    graDR_button2_disable (ignored) and off.

*    graDR_fim_disable     (ignored) Turn all FIM stuff off (for good)

*    graDR_mirror          (int) Turn mirroring on (==1) or off (==0)

*    graDR_setmatrix       (int) These 3 items set their corresponding
*    graDR_setgrid               parameters to the drive parameter.

*    graDR_newlength       (int) set the expected length of time series
                            to be some new value (e.g., the pin number)
*    graDR_setpinnum       [same as newlength]
*    graDR_setpintop       [same as newlength]

*    graDR_setpinbot       (int) set the bottom index for plotting
*    graDR_setpins         (int) set top AND bottom index for plotting;
                             value = 100000*top + bot

*    graDR_setglobalbaseline (float *) Global baseline value

The Boolean return value is True for success, False for failure.
-------------------------------------------------------------------------*/

Boolean drive_MCW_grapher( MCW_grapher * grapher ,
                           int drive_code , XtPointer drive_data )
{

ENTRY("drive_MCW_grapher") ;

   if( ! GRA_VALID(grapher) ) RETURN(False) ;

   switch( drive_code ){

      /*------- error! -------*/

      default:{
         fprintf(stderr,"\a\n*** drive_MCW_grapher: code=%d illegal!\n",
                 drive_code) ;
         XBell( grapher->dc->display , 100 ) ;
         RETURN( False ) ;
      }

      /*------ winaver [27 Jan 2004] -----*/

      case graDR_winaver:{
        int vvv = (int)drive_data ;
        MCW_set_bbox( grapher->fmenu->fim_editref_winaver_bbox , vvv ) ;
        RETURN( True ) ;
      }

      /*------ setglobalbaseline [07 Aug 2001] -----*/

      case graDR_setglobalbaseline:{
         float *vvv = (float *) drive_data ;   /* get value   */
         int ii = thd_floatscan( 1 , vvv ) ;   /* check value */
         MCW_choose_cbs cb ;
         if( ii != 0 ) RETURN( False ) ;       /* this is bad */
         cb.reason = mcwCR_integer ;
         cb.fval   = *vvv ;
         GRA_finalize_global_baseline_CB(NULL,(XtPointer)grapher,&cb) ;
         RETURN( True ) ;
      }

      /*------ setmatrix [22 Sep 2000] -----*/

      case graDR_setmatrix:{
         int mm = (int) drive_data ;
         if( mm < 0 ) RETURN( False ) ;
         grapher->mat = MIN( grapher->mat_max , mm ) ;
         init_mat    ( grapher ) ;
         redraw_graph( grapher, PLOTCODE_AUTOSCALE ); /* 12 Oct 2000: autoscale */
         send_newinfo( grapher ) ;
         RETURN( True ) ;
      }

      /*------ setgrid [22 Sep 2000] -----*/

      case graDR_setgrid:{
         int mm = (int) drive_data ;
         if( mm < 2 ) RETURN( False ) ;
         grapher->grid_spacing = mm ;
         grapher->grid_fixed   = 1 ;  /* 02 Apr 2004 */
         redraw_graph(grapher,0) ;
         RETURN( True ) ;
      }

      /*------ mirroring (Jul 2000) -----*/

      case graDR_mirror:{
         int ii = (int) drive_data ;

         if( ii != grapher->mirror ){
           grapher->mirror = ii ;
           init_mat( grapher ) ; redraw_graph( grapher , 0 ) ;
         }
      }
      break ;

      /*------ fim disabling -----*/

      case graDR_fim_disable:{
         int ii ;
         XtUnmanageChild( grapher->fmenu->fim_cbut ) ;
         XtUnmanageChild( grapher->opt_xaxis_cbut ) ;
         for( ii=0 ; ii < NUM_COLOR_ITEMS ; ii++ ){
           if( gr_unfim[ii] ){
             if( grapher->opt_color_av[ii] != NULL )
               XtUnmanageChild( grapher->opt_color_av[ii]->wrowcol ) ;
             if( grapher->opt_thick_bbox[ii] != NULL )
               XtUnmanageChild( grapher->opt_thick_bbox[ii]->wtop  ) ;
             if( grapher->opt_points_bbox[ii] != NULL )
               XtUnmanageChild( grapher->opt_points_bbox[ii]->wtop ) ;
           }
         }
      }
      break ;

      /*------ button2 stuff -----*/

      case graDR_button2_enable:{
        grapher->button2_enabled = 1 ;
        GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
        RETURN( True ) ;
      }

      case graDR_button2_disable:{
        grapher->button2_enabled = 0 ;
        RETURN( True ) ;
      }

      /*------ set time index -----*/

      case graDR_setindex:{
         int new_index = (int) drive_data ;

         if( new_index < 0 || new_index >= grapher->status->num_series )
           RETURN( False ) ;

         if( new_index != grapher->time_index ){
           grapher->time_index = new_index ;
           if( grapher->textgraph )
             redraw_graph( grapher , 0 ) ;
           else
             GRA_redraw_overlay( grapher ) ;
         }
         RETURN( True ) ;
      }

      /*------ reset top of time series plotting ------*/
      /* (same as graDR_setpinnum and graDR_setpintop) */

      case graDR_newlength:{
         int newtop=(int)drive_data ;

         if( newtop < MIN_PIN ) newtop = 0 ;
         if( newtop > MAX_PIN ) newtop = MAX_PIN ;

         grapher->pin_top = newtop ;
         if( NPTS(grapher) < 2 ) grapher->pin_bot = 0 ;

#ifdef USE_OPTMENUS
         GRA_fix_optmenus( grapher ) ;
#endif
         redraw_graph( grapher, 0 ) ;
         RETURN( True ) ;
      }

      /*------ reset bottom of time series plotting [17 Mar 2004] -----*/

      case graDR_setpinbot:{
         int newbot=(int)drive_data ;

         if( newbot < 0               ) newbot = 0 ;
         if( newbot >= TTOP(grapher)  ) newbot = 0 ;

         grapher->pin_bot = newbot ;

#ifdef USE_OPTMENUS
         GRA_fix_optmenus( grapher ) ;
#endif
         redraw_graph( grapher, 0 ) ;
         RETURN( True ) ;
      }

      /*------ reset bot and top of time series plotting [19 Mar 2004] -----*/

      case graDR_setpins:{
         int ii=(int)drive_data , newbot,newtop ;

         if( ii <= 0 ){
           newbot = newtop = 0 ;
         } else {
           newbot = ii % 100000 ;
           newtop = ii / 100000 ;
           if( newtop < MIN_PIN ) newtop = 0 ;
         }
         if( newtop > 0 && newtop-newbot < 2 ) newbot = 0 ;
         if( newbot >= TTOP(grapher)         ) newbot = 0 ;

         grapher->pin_bot = newbot ;
         grapher->pin_top = newtop ;

#ifdef USE_OPTMENUS
         GRA_fix_optmenus( grapher ) ;
#endif
         redraw_graph( grapher, 0 ) ;
         RETURN( True ) ;
      }

      /*------ set ignore count -----*/

      case graDR_setignore:{
         int new_ignore = (int) drive_data ;

         if( new_ignore >= 0 && new_ignore < TTOP(grapher)-1 ){
           grapher->init_ignore = new_ignore ;
           redraw_graph( grapher , PLOTCODE_AUTOSCALE ) ;
           RETURN( True ) ;
         } else {
           RETURN( False ) ;
         }
      }

      /*------- set polort [27 May 1999] --------*/

      case graDR_polort:{
         int new_polort = (int) drive_data ;

         if( new_polort >= 0 ){
            grapher->polort = new_polort ;
#ifdef USE_OPTMENUS
            GRA_fix_optmenus( grapher ) ;
#endif
         }
         RETURN( True ) ;
      }

      /*----- set reference time series (currently limited to one) -----*/

      case graDR_addref_ts:{
         MRI_IMAGE *im = (MRI_IMAGE *) drive_data ;

         if( im == NULL ){                /* no input --> kill kill kill */
STATUS("freeing reference timeseries") ;
            FREE_IMARR(grapher->ref_ts) ;
            grapher->ref_ts = NULL ;
         } else{
            if( grapher->ref_ts == NULL ) INIT_IMARR( grapher->ref_ts ) ;

            if( IMARR_COUNT(grapher->ref_ts) == 0 ){
STATUS("adding reference timeseries") ;
               ADDTO_IMARR( grapher->ref_ts , im ) ;     /* create first one */
            } else {
STATUS("replacing reference timeseries") ;
               IMARR_SUBIMAGE(grapher->ref_ts,0) = im ;  /* replace first one */
            }
         }

         redraw_graph( grapher , 0 ) ;
         RETURN( True ) ;
      }

      /*----- set ort time series (currently limited to one) -----*/

      case graDR_addort_ts:{
         MRI_IMAGE *im = (MRI_IMAGE *) drive_data ;

         if( im == NULL ){                /* no input --> kill kill kill */
STATUS("freeing ort timeseries") ;
            FREE_IMARR(grapher->ort_ts) ;
            grapher->ort_ts = NULL ;
         } else{
            if( grapher->ort_ts == NULL ) INIT_IMARR( grapher->ort_ts ) ;

            if( IMARR_COUNT(grapher->ort_ts) == 0 ){
STATUS("adding ort timeseries") ;
               ADDTO_IMARR( grapher->ort_ts , im ) ;     /* create first one */
            } else {
STATUS("replacing ort timeseries") ;
               IMARR_SUBIMAGE(grapher->ort_ts,0) = im ;  /* replace first one */
            }
         }

         redraw_graph( grapher , 0 ) ;
         RETURN( True ) ;
      }

      /*------ set icon pixmap -----*/

      case graDR_icon:{
         int xret , yret ;
         unsigned int wret,hret,bret,dret ;
         Window rret ;

         XtVaSetValues( grapher->fdw_graph , XmNiconPixmap , (Pixmap) drive_data , NULL ) ;
         grapher->glogo_pixmap = (Pixmap) drive_data ;

         /* get geometry for later use */

         if( grapher->glogo_pixmap != XmUNSPECIFIED_PIXMAP ){
            (void) XGetGeometry( grapher->dc->display , grapher->glogo_pixmap ,
                                 &rret , &xret , &yret , &wret , &hret , &bret , &dret ) ;

            grapher->glogo_width  = wret ;
            grapher->glogo_height = hret ;
         } else {
            grapher->glogo_width  = 0 ;
            grapher->glogo_height = 0 ;
         }
         RETURN( True ) ;
      }

      /*------- title --------*/

      case graDR_title:{
         char * title = (char *) drive_data ;

         if( title == NULL || strlen(title) == 0 ) RETURN( False ) ;

         XtVaSetValues( grapher->fdw_graph , XmNtitle , title , NULL ) ;
         RETURN( True ) ;
      }

      /*------- death! -------*/

      case graDR_destroy:{
         end_fd_graph_CB( NULL , (XtPointer) grapher , NULL ) ;
         RETURN( True ) ;
      }

      /*------- unrealize! -------*/

      case graDR_unrealize:{
         GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
         if( GRA_REALZ(grapher) ) XtUnrealizeWidget( grapher->fdw_graph ) ;
         grapher->valid = 1 ;

         if( grapher->fd_pxWind != (Pixmap) 0 )
            XFreePixmap( grapher->dc->display , grapher->fd_pxWind ) ;
         RETURN( True ) ;
      }

      /*------- realize! -------*/

      case graDR_realize:{
         if( ! GRA_REALZ(grapher) ){
            int width , height ;

            grapher->valid = 2 ;

            XtRealizeWidget( grapher->fdw_graph ) ;

            WAIT_for_window(grapher->fdw_graph) ;

            /* 29 Sep 2000: next 2 lines of code are for the Form change */

            XtVaSetValues( grapher->option_rowcol ,
                             XmNleftAttachment   , XmATTACH_NONE ,
                             XmNtopAttachment    , XmATTACH_NONE ,
                             XmNrightAttachment  , XmATTACH_FORM ,
                             XmNbottomAttachment , XmATTACH_FORM ,
                           NULL ) ;
            XMapRaised( XtDisplay(grapher->option_rowcol) ,
                        XtWindow(grapher->option_rowcol)   ) ;

            NORMAL_cursorize( grapher->fdw_graph ) ;

            if( ISONE(grapher) )
              NORMAL_cursorize( grapher->draw_fd ) ;  /* 07 Dec 2001 */
            else
              POPUP_cursorize( grapher->draw_fd ) ;

            MCW_widget_geom( grapher->draw_fd , &width , &height , NULL,NULL ) ;
            GRA_new_pixmap( grapher , width , height , 0 ) ;
#ifdef USE_OPTMENUS
            GRA_fix_optmenus( grapher ) ;
#endif
            AFNI_sleep(1) ;  /* 08 Mar 2002: for good luck */
         }
         RETURN( True ) ;
      }

      /*------- new cursor for image -------*/

      case graDR_cursor:{
         int cur = (int) drive_data ;

         MCW_alter_widget_cursor( grapher->fdw_graph , cur , "yellow" , "blue" ) ;
         RETURN( True ) ;
      }

      /*------- new data sequence!!! -------*/

      case graDR_newdata:{
         int npold = grapher->status->num_series ;  /* 22 Sep 2000 */

         GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */

         grapher->getaux = drive_data ;
#if 0
         grapher->status = (MCW_grapher_status *)
                              grapher->getser(0,graCR_getstatus,drive_data) ;
#else
         CALL_getser( grapher , 0,graCR_getstatus , MCW_grapher_status *,grapher->status ) ;
#endif
         init_const( grapher ) ;

         /* mustn't allow bottom of plotting range to be beyond top of data! */

         if( grapher->pin_bot >= grapher->status->num_series-1 ) grapher->pin_bot = 0 ;

         if( npold < 2 || !grapher->grid_fixed ){ /* 22 Sep 2000 */
           auto_grid( grapher , NPTS(grapher) ) ;
         }

#ifdef USE_OPTMENUS
         GRA_fix_optmenus( grapher ) ;
#endif

        if( ISONE(grapher) )                        /* 07 Dec 2001 */
          NORMAL_cursorize( grapher->draw_fd ) ;
        else
          POPUP_cursorize( grapher->draw_fd ) ;

         RETURN( True ) ;
      }

      /*------- redraw -------*/

      case graDR_redraw:{
         int *xym = (int *) drive_data ;

STATUS("graDR_redraw") ;

         if( xym != NULL ){
            if( xym[0] >= 0 ) grapher->xpoint = xym[0] ;
            if( xym[1] >= 0 ) grapher->ypoint = xym[1] ;
            if( xym[2] >= 0 ) grapher->zpoint = xym[2] ;
            if( xym[3] >  0 ) grapher->mat    = xym[3] ;
            init_mat(grapher) ;
         }
         redraw_graph( grapher , 0 ) ;
         RETURN( True ) ;
      }

   }  /* end of switch on drive_code */

   RETURN( False ) ;  /* should never be reached! */
}

/*------------------------------------------------------------------
   Callback for all FIM menu buttons
--------------------------------------------------------------------*/

void GRA_fim_CB( Widget w , XtPointer client_data , XtPointer call_data )
{
   FIM_menu * fm = (FIM_menu *) client_data ;
   MCW_grapher * grapher = (MCW_grapher *) fm->parent ;
   GRA_cbs cbs ;

ENTRY("GRA_fim_CB") ;

   if( ! GRA_VALID(grapher) || grapher->status->send_CB == NULL ) EXRETURN ;

   EXRONE(grapher) ;  /* 22 Sep 2000 */

   /*--- carry out action, depending on which widget called me ---*/

   /*** Pick reference ***/

   if( w == grapher->fmenu->fim_pickref_pb ){
      cbs.reason = graCR_pickref ;
#if 0
      grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
#else
      CALL_sendback( grapher , cbs ) ;
#endif
      grapher->tschosen = 1 ;  /* 31 Mar 2004 */
   }

   /*** Pick ort ***/

   else if( w == grapher->fmenu->fim_pickort_pb ){
      cbs.reason = graCR_pickort ;
#if 0
      grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
#else
      CALL_sendback( grapher , cbs ) ;
#endif
      grapher->tschosen = 1 ;  /* 31 Mar 2004 */
   }

   /*** Clear FIM ***/

   else if( w == grapher->fmenu->fim_editref_clear_pb ){
      cbs.reason = graCR_clearfim ;
#if 0
      grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
#else
      CALL_sendback( grapher , cbs ) ;
#endif
   }

   /*** Clear Ort ***/

   else if( w == grapher->fmenu->fim_editort_clear_pb ){
      cbs.reason = graCR_clearort ;
#if 0
      grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
#else
      CALL_sendback( grapher , cbs ) ;
#endif
   }

   /*** set ref to central time series ***/

   else if( w == grapher->fmenu->fim_editref_equals_pb ||
            w == grapher->fmenu->fim_editref_add_pb      ){
      int ll ;
      MRI_IMAGE * tsim ;

      ll = grapher->xpoint +
           grapher->ypoint * grapher->status->nx +
           grapher->zpoint * grapher->status->nx * grapher->status->ny ;

#if 0
      tsim  = (MRI_IMAGE *) grapher->getser( ll , graCR_getseries ,
                                                  grapher->getaux ) ;
#else
      CALL_getser( grapher , ll,graCR_getseries , MRI_IMAGE *,tsim ) ;
#endif

      if( tsim != NULL ){
         { GRA_cbs cbs; cbs.reason=graCR_winaver; CALL_sendback(grapher,cbs); }
         MCW_set_bbox( grapher->fmenu->fim_editref_winaver_bbox , 0 ) ;
         cbs.reason   = (w == grapher->fmenu->fim_editref_equals_pb)
                        ? graCR_refequals : graCR_refadd ;
         cbs.userdata = (XtPointer) tsim ;
#if 0
         grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
#else
         CALL_sendback( grapher , cbs ) ;
#endif
         mri_free( tsim ) ;
      }
   }

   /*** read or write or smooth ***/

   else if( w == grapher->fmenu->fim_editref_read_pb ){
      MCW_choose_string( grapher->option_rowcol ,
                         "Ideal Input Filename:" , NULL ,
                         GRA_refread_choose_CB , (XtPointer) grapher ) ;
   }

   else if( w == grapher->fmenu->fim_editref_write_pb ){
      if( grapher->ref_ts != NULL && IMARR_COUNT(grapher->ref_ts) > 0 ){
         MCW_choose_string( grapher->option_rowcol ,
                            "Ideal Output Filename:" , NULL ,
                            GRA_refwrite_choose_CB , (XtPointer) grapher ) ;
      } else {
         XBell( grapher->dc->display , 100 ) ;
      }
   }

   else if( w == grapher->fmenu->fim_editref_store_pb ){
      if( grapher->ref_ts != NULL && IMARR_COUNT(grapher->ref_ts) > 0 ){
         MCW_choose_string( grapher->option_rowcol ,
                            "Label to Store Ideal:" , NULL ,
                            GRA_refstore_choose_CB , (XtPointer) grapher ) ;
      } else {
         XBell( grapher->dc->display , 100 ) ;
      }
   }

   else if( w == grapher->fmenu->fim_editref_smooth_pb ){
      cbs.reason = graCR_refsmooth ;
      if( grapher->ref_ts != NULL && IMARR_COUNT(grapher->ref_ts) > 0 ){
         { GRA_cbs cbs; cbs.reason=graCR_winaver; CALL_sendback(grapher,cbs); }
         MCW_set_bbox( grapher->fmenu->fim_editref_winaver_bbox , 0 ) ;
#if 0
         grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
#else
         CALL_sendback( grapher , cbs ) ;
#endif
      } else {
         XBell( grapher->dc->display , 100 ) ;
      }
   }

   /*** Set shifts ***/

   else if( w == grapher->fmenu->fim_editref_setshift_pb ){
      GRA_setshift_startup( grapher ) ;
   }

   /*** Execute FIM ***/

   else if( w == grapher->fmenu->fim_execute_pb ){
      int val = MCW_val_bbox(grapher->fmenu->fim_opt_bbox) ;
      cbs.reason = graCR_dofim ;
      switch(val){
         default:  cbs.key = FIM_ALPHA_MASK | FIM_CORR_MASK ; break ;
         case 2:   cbs.key = FIM_PERC_MASK  | FIM_CORR_MASK ; break ;
         case 4:   cbs.key = FIM_PAVE_MASK  | FIM_CORR_MASK ; break ;
         case 3:   cbs.key = FIM_PTOP_MASK  | FIM_CORR_MASK ; break ;
      }
      cbs.mat = 0 ; /* Feb 2000 */
      GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
#if 0
      grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
#else
      CALL_sendback( grapher , cbs ) ;
#endif
   }

   else if( w == grapher->fmenu->fim_execfimp_pb ){
      cbs.reason = graCR_dofim ;
      cbs.key    = MCW_val_bbox(grapher->fmenu->fimp_opt_bbox) ;
      cbs.mat    = MCW_val_bbox(grapher->fmenu->fimp_user_bbox) ; /* Feb 2000 */
      GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
      if( cbs.key || cbs.mat )
#if 0
         grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
#else
         CALL_sendback( grapher , cbs ) ;
#endif
      else
         XBell( grapher->dc->display , 100 ) ;
   }

   /*** 04 Jan 2000: modify the FIM+ button settings ***/

   else if( w == grapher->fmenu->fimp_setdefault_pb ){
     char * ff = my_getenv( "AFNI_FIM_MASK" ) ; int mm=0 ;
     if( ff != NULL ) mm = strtol(ff,NULL,10) ;
     if( mm <= 0 ) mm = FIM_DEFAULT_MASK ;
     MCW_set_bbox( grapher->fmenu->fimp_opt_bbox , mm ) ;
   }

   else if( w == grapher->fmenu->fimp_setall_pb ){
      int mm = (2 << FIM_NUM_OPTS) - 1 ;
      MCW_set_bbox( grapher->fmenu->fimp_opt_bbox , mm ) ;
   }

   else if( w == grapher->fmenu->fimp_unsetall_pb ){
      MCW_set_bbox( grapher->fmenu->fimp_opt_bbox , 0 ) ;
   }

   /*** FIM plotting buttons ***/

   else if( w == grapher->fmenu->fim_plot_firstref_pb ){
      if( grapher->ref_ts_plotall != 0 ){
         grapher->ref_ts_plotall = 0 ;
         redraw_graph( grapher , 0 ) ;
      }
   }

   else if( w == grapher->fmenu->fim_plot_allrefs_pb ){
      if( grapher->ref_ts_plotall == 0 ){
         grapher->ref_ts_plotall = 1 ;
         redraw_graph( grapher , 0 ) ;
      }
   }

   /*** Ignore stuff ***/

   else if( w == grapher->fmenu->fim_ignore_down_pb && grapher->status->send_CB != NULL ){
      GRA_cbs cbs ;

      cbs.reason = graCR_setignore ;
      cbs.key    = grapher->init_ignore - 1 ;
#if 0
      grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
#else
      CALL_sendback( grapher , cbs ) ;
#endif
   }

   else if( w == grapher->fmenu->fim_ignore_up_pb && grapher->status->send_CB != NULL ){
      GRA_cbs cbs ;

      cbs.reason = graCR_setignore ;
      cbs.key    = grapher->init_ignore + 1 ;
#if 0
      grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
#else
      CALL_sendback( grapher , cbs ) ;
#endif
   }

   else if( w == grapher->fmenu->fim_ignore_choose_pb && grapher->status->send_CB != NULL ){
#ifdef USE_OPTMENUS
      GRA_ignore_choose_CB( grapher->fmenu->fim_ignore_choose_av , grapher ) ;
#else
      MCW_choose_integer( grapher->option_rowcol , "Initial Ignore" ,
                          0 , grapher->status->num_series-1 , grapher->init_ignore ,
                          GRA_ignore_choose_CB , (XtPointer) grapher ) ;
#endif
   }

   /* 27 May 1999: set polort */

   else if( w == grapher->fmenu->fim_polort_choose_pb && grapher->status->send_CB != NULL ){
#ifdef USE_OPTMENUS
      GRA_polort_choose_CB( grapher->fmenu->fim_polort_choose_av , grapher ) ;
#else
      MCW_choose_integer( grapher->option_rowcol , "Polort Order" ,
                          0 , MAX_POLORT , grapher->polort ,
                          GRA_polort_choose_CB , (XtPointer) grapher ) ;
#endif
   }

   /* 02 Jun 1999: set FIM bkg threshold */

   else if( w == grapher->fmenu->fim_bkthr_choose_pb ){
      MCW_choose_integer( grapher->option_rowcol , "Bkg Thresh %" ,
                          0 , 99 , (int)(100*FIM_THR) ,
                          GRA_bkthr_choose_CB , (XtPointer) grapher ) ;
   }

   /*** Unimplemented Button ***/

   else {
      XBell( grapher->dc->display , 100 ) ;
   }

   /*--- Done!!! ---*/

   EXRETURN ;
}

/*-----------------------------------------------------------------------*/

#define SETSHIFT_quit_label  "Quit"
#define SETSHIFT_apply_label "Apply"
#define SETSHIFT_done_label  "Set"

#define SETSHIFT_quit_help   "Press to close\nthis control box"
#define SETSHIFT_apply_help  "Press to apply this choice\nand keep this control box"
#define SETSHIFT_done_help   "Press to apply this choice\nand close this control box"

#define NUM_SETSHIFT_ACT 3

static MCW_action_item SETSHIFT_act[NUM_SETSHIFT_ACT] = {
 { SETSHIFT_quit_label  , GRA_setshift_action_CB, NULL, SETSHIFT_quit_help ,"Close window"                 , 0 },
 { SETSHIFT_apply_label , GRA_setshift_action_CB, NULL, SETSHIFT_apply_help,"Apply choice and keep window" , 0 },
 { SETSHIFT_done_label  , GRA_setshift_action_CB, NULL, SETSHIFT_done_help ,"Apply choice and close window", 1 }
} ;

#define SETSHIFT_QUIT  0
#define SETSHIFT_APPLY 1
#define SETSHIFT_DONE  2

/*-----------------------------------------------------------------------*/

void GRA_setshift_startup( MCW_grapher * grapher )
{
   int ib , xx,yy ;
   Widget wrc ;

ENTRY("GRA_setshift_startup") ;

   if( ! GRA_REALZ(grapher) || grapher->dialog != NULL ) EXRETURN ;

   MCW_widget_geom( grapher->fdw_graph , NULL,NULL,&xx,&yy ) ;  /* geometry of shell */

   grapher->dialog = XtVaCreatePopupShell(
                      "menu" , xmDialogShellWidgetClass , grapher->fdw_graph ,
                         XmNx , xx+15 ,
                         XmNy , yy+15 ,
                         XmNtitle , "Shifts" ,
                         XmNdeleteResponse , XmDO_NOTHING ,
                         XmNinitialResourcesPersistent , False ,

                         XmNvisual   , grapher->dc->visual ,         /* 14 Sep 1998 */
                         XmNcolormap , grapher->dc->colormap ,
                         XmNdepth    , grapher->dc->depth ,
                         XmNscreen   , grapher->dc->screen ,
                         XmNbackground  , 0 ,
                         XmNborderColor , 0 ,
              XmNkeyboardFocusPolicy , XmEXPLICIT ,

                      NULL ) ;

   if( MCW_isitmwm(grapher->fdw_graph) ){
      XtVaSetValues( grapher->dialog ,
                       XmNmwmDecorations , MWM_DECOR_BORDER ,
                       XmNmwmFunctions ,   MWM_FUNC_MOVE
                                         | MWM_FUNC_CLOSE ,
                     NULL ) ;
   }

   XmAddWMProtocolCallback(           /* make "Close" window menu work */
           grapher->dialog ,
           XmInternAtom( grapher->dc->display , "WM_DELETE_WINDOW" , False ) ,
           GRA_setshift_action_CB , grapher ) ;

   wrc = XtVaCreateWidget(                    /* RowColumn to hold all */
             "dialog" , xmRowColumnWidgetClass , grapher->dialog ,
                XmNpacking     , XmPACK_TIGHT ,
                XmNorientation , XmVERTICAL ,
                XmNtraversalOn , True  ,
                XmNinitialResourcesPersistent , False ,
             NULL ) ;

   (void) XtVaCreateManagedWidget(
            "dialog" , xmLabelWidgetClass , wrc ,
               LABEL_ARG("-- Shift Controls --") ,
               XmNalignment  , XmALIGNMENT_CENTER ,
               XmNinitialResourcesPersistent , False ,
            NULL ) ;

   (void) XtVaCreateManagedWidget(
            "dialog" , xmSeparatorWidgetClass , wrc ,
               XmNseparatorType , XmSHADOW_ETCHED_IN ,
               XmNinitialResourcesPersistent , False ,
            NULL ) ;

   grapher->setshift_inc_av = new_MCW_arrowval(
                                wrc ,   "Increment  " , MCW_AV_downup ,
                                1 , 1000 , (int)(100.0*grapher->setshift_inc) ,
                                MCW_AV_edittext , 2 ,
                                NULL , NULL , NULL , NULL ) ;

   grapher->setshift_left_av = new_MCW_arrowval(
                                  wrc , "Steps Left " , MCW_AV_downup ,
                                  0 , 29 , grapher->setshift_left ,
                                  MCW_AV_edittext , 0 ,
                                  NULL , NULL , NULL , NULL ) ;

   grapher->setshift_right_av = new_MCW_arrowval(
                                  wrc , "Steps Right" , MCW_AV_downup ,
                                  0 , 29 , grapher->setshift_right ,
                                  MCW_AV_edittext , 0 ,
                                  NULL , NULL , NULL , NULL ) ;

   grapher->setshift_inc_av->allow_wrap   = 1 ;   /* allow wrap at limits of values */
   grapher->setshift_left_av->allow_wrap  = 1 ;
   grapher->setshift_right_av->allow_wrap = 1 ;

   grapher->setshift_inc_av->fastdelay    = 250 ; /* slow down arrow repeat action */
   grapher->setshift_left_av->fastdelay   = 250 ;
   grapher->setshift_right_av->fastdelay  = 250 ;

   MCW_reghelp_children( grapher->setshift_inc_av->wrowcol ,
       "This controls the step size\n"
       "used to create the shifted\n"
       "time series -- for example,\n"
       "0.2 means a shift of 1/5\n"
       "of a time series stepsize."
   ) ;
   MCW_reghint_children( grapher->setshift_inc_av->wrowcol ,
                         "Size of shift" ) ;

   MCW_reghelp_children( grapher->setshift_left_av->wrowcol ,
      "This controls the number\n"
      "of left shifts used to\n"
      "create the desired multi-\n"
      "vector time series.\n\n"
      "N.B.: Steps Left plus\n"
      "      Steps Right should\n"
      "      be positive!"
   ) ;
   MCW_reghint_children( grapher->setshift_left_av->wrowcol ,
                         "Number of steps left" ) ;

   MCW_reghelp_children( grapher->setshift_right_av->wrowcol ,
      "This controls the number\n"
      "of right shifts used to\n"
      "create the desired multi-\n"
      "vector time series.\n\n"
      "N.B.: Steps Left plus\n"
      "      Steps Right should\n"
      "      be positive!"
   ) ;
   MCW_reghint_children( grapher->setshift_right_av->wrowcol ,
                         "Number of steps right" ) ;

   for( ib=0 ; ib < NUM_SETSHIFT_ACT ; ib++ )
      SETSHIFT_act[ib].data = (XtPointer) grapher ;

   (void) MCW_action_area( wrc , SETSHIFT_act , NUM_SETSHIFT_ACT ) ;

   XtManageChild( wrc ) ;
   XtPopup( grapher->dialog , XtGrabNone ) ; RWC_sleep(1);
   RWC_visibilize_widget( grapher->dialog ) ; /* 09 Nov 1999 */
   NORMAL_cursorize( grapher->dialog ) ;
   EXRETURN ;
}

/*-----------------------------------------------------------------------*/

void GRA_setshift_action_CB( Widget w , XtPointer client_data , XtPointer call_data )
{
   MCW_grapher * grapher = (MCW_grapher *) client_data ;
   XmAnyCallbackStruct * cbs = (XmAnyCallbackStruct *) call_data ;
   char * wname ;
   int ib , close_window ;

ENTRY("GRA_setshift_action_CB") ;

   if( !GRA_REALZ(grapher) || grapher->dialog==NULL ) EXRETURN ;

   wname = XtName(w) ;

   for( ib=0 ; ib < NUM_SETSHIFT_ACT ; ib++ )           /* button index, if any */
      if( strcmp(wname,SETSHIFT_act[ib].label) == 0 ) break ;

   close_window = (ib == SETSHIFT_DONE ||
                   ib == SETSHIFT_QUIT || ib == NUM_SETSHIFT_ACT) ;

   if( close_window ){
      RWC_XtPopdown( grapher->dialog ) ;
      XSync( XtDisplay(w) , False ) ;
      XmUpdateDisplay( w ) ;
   }

   switch( ib ){

      case SETSHIFT_APPLY:
      case SETSHIFT_DONE:{
         grapher->setshift_inc   = grapher->setshift_inc_av->fval ;
         grapher->setshift_left  = grapher->setshift_left_av->ival ;
         grapher->setshift_right = grapher->setshift_right_av->ival ;

         GRA_doshift( grapher ) ;
      }
      break ;
   }

   if( close_window ){                          /* close the window */
      XtDestroyWidget( grapher->dialog ) ;
      grapher->dialog = NULL ;
      FREE_AV( grapher->setshift_right_av ) ;
      FREE_AV( grapher->setshift_left_av )  ;
      FREE_AV( grapher->setshift_inc_av )   ;
   }

   EXRETURN ;
}

/*-----------------------------------------------------------------------*/

void GRA_doshift( MCW_grapher * grapher )
{
   MRI_IMAGE * tsim , * newim , * tim ;
   float * tsar , * nar , * tar ;
   int ii,ivec , nx , newny , nleft,nright ;
   float shinc ;
   GRA_cbs gbs ;

ENTRY("GRA_doshift") ;

   if( !GRA_VALID(grapher) ) EXRETURN ;

   if( grapher->status->send_CB == NULL                       ||
       grapher->setshift_inc <= 0.0                           ||
       grapher->setshift_left + grapher->setshift_right <= 0  ||
       grapher->ref_ts == NULL                                ||
       IMARR_COUNT(grapher->ref_ts) == 0                        ){

      XBell( grapher->dc->display , 100 ) ; EXRETURN ;
   }

   tsim = IMARR_SUBIMAGE(grapher->ref_ts,0) ; /* current ref */
   tsar = MRI_FLOAT_PTR(tsim) ;
   nx   = tsim->nx ;

   shinc  = grapher->setshift_inc ;
   nleft  = grapher->setshift_left ;
   nright = grapher->setshift_right ;
   newny  = 1 + nleft + nright ;
   newim  = mri_new( nx , newny , MRI_float ) ;
   nar    = MRI_FLOAT_PTR(newim) ;

   for( ii=0 ; ii < nx ; ii++ )
      nar[ii] = (ii < grapher->init_ignore) ? WAY_BIG : tsar[ii] ;

   for( ivec=1 ; ivec <= nleft ; ivec++ ){
      tim = mri_shift_1D( newim , -ivec * shinc ) ;
      tar = MRI_FLOAT_PTR(tim) ;
      for( ii=0 ; ii < nx ; ii++ ) nar[ii+ivec*nx] = tar[ii] ;
      mri_free(tim) ;
   }

   for( ivec=1 ; ivec <= nright ; ivec++ ){
      tim = mri_shift_1D( newim , ivec * shinc ) ;
      tar = MRI_FLOAT_PTR(tim) ;
      for( ii=0 ; ii < nx ; ii++ ) nar[ii+(ivec+nleft)*nx] = tar[ii] ;
      mri_free(tim) ;
   }

   { GRA_cbs cbs; cbs.reason=graCR_winaver; CALL_sendback(grapher,cbs); }
   MCW_set_bbox( grapher->fmenu->fim_editref_winaver_bbox , 0 ) ;
   gbs.reason   = graCR_refequals ;
   gbs.userdata = (XtPointer) newim ;
#if 0
   grapher->status->send_CB( grapher , grapher->getaux , &gbs ) ;
#else
   CALL_sendback( grapher , gbs ) ;
#endif
   mri_free( newim ) ;
   EXRETURN ;
}

/*---------------------------------------------------------------------
  Returns a bunch of widgets in a structure.
  The parent widget is intended to be a menu bar.
-----------------------------------------------------------------------*/

FIM_menu * AFNI_new_fim_menu( Widget parent, XtCallbackProc cbfunc, int graphable )
{
   FIM_menu *fmenu ;
   Widget qbut_menu = NULL ;

ENTRY("AFNI_new_fim_menu") ;

   fmenu = myXtNew(FIM_menu) ;
   fmenu->cbfunc = cbfunc ;

   /*------------------------*/
   /*--- FIM Menu Buttons ---*/
   /*------------------------*/

   fmenu->fim_menu = XmCreatePulldownMenu( parent , "menu" , NULL,0 ) ;

   VISIBILIZE_WHEN_MAPPED(fmenu->fim_menu) ;  /* 27 Sep 2000 */

   if( !AFNI_yesenv("AFNI_DISABLE_TEAROFF") ) TEAROFFIZE(fmenu->fim_menu) ;

   fmenu->fim_cbut =
         XtVaCreateManagedWidget(
            "dialog" , xmCascadeButtonWidgetClass , parent ,
               LABEL_ARG("FIM") ,
               XmNsubMenuId , fmenu->fim_menu ,
               XmNmarginWidth  , 0 ,
               XmNmarginHeight , 0 ,
               XmNmarginBottom , 0 ,
               XmNmarginTop    , 0 ,
               XmNmarginRight  , 0 ,
               XmNmarginLeft   , 0 ,
               XmNtraversalOn  , True  ,
               XmNinitialResourcesPersistent , False ,
            NULL ) ;

   if( graphable ){
      MCW_register_hint( fmenu->fim_cbut , "Functional Imaging menu" ) ;
      MCW_register_help( fmenu->fim_cbut ,
                      "*******  Functional Imaging Controls:  *******\n"
                      "\n"
                      "Ideal Vector Operations:\n"
                      " Pick Ideal --> Choose from a list\n"
                      " Pick Ort   --> Choose from a list\n"
                      " Edit: = Center --> Use voxel timeseries\n"
                      "      += Center --> Average with voxel\n"
                      "      Smooth    --> A 3 point filter\n"
                      "      Shift     --> Time-shifted copies\n"
                      "      Clear     --> Turn ideal off\n"
                      "      WinAver   --> Average of sub-graphs\n"
                      "      Read      --> Input from external file\n"
                      "      Write     --> Output to external file\n"
                      "      Store     --> Save in internal list\n"
                      " Ignore: Set how many points to ignore\n"
                      "         at beginning of time series\n"
                      "         [ Applies both to graphing ]\n"
                      "         [ and to FIM computations. ]\n"
                      "\n"
                      "FIM Plots:\n"
                      "  Can choose to graph only first vector in\n"
                      "  ideal family, or all of them superimposed.\n"
                      "\n"
                      "Refresh Freq --> Choose number of time steps\n"
                      "   between redisplay of the functional overlay\n"
                      "   during FIM computations (0 == no redisplay).\n"
                      "Compute FIM  --> Use the recursive method to\n"
                      "   compute the correlation of each voxel time\n"
                      "   series with each ideal vector;  uses the best\n"
                      "   correlation as the 'correct' waveform for\n"
                      "   each voxel, individually.  Time points that\n"
                      "   have an ideal vector value >= 33333 will be\n"
                      "   ignored in the computations, as will those\n"
                      "   at the beginning specified in the Opt menu\n"
                      "   'Ignore' function."
                    ) ;
   } else {
      MCW_register_hint( fmenu->fim_cbut , "Functional Imaging menu" ) ;
      MCW_register_help( fmenu->fim_cbut ,
                      "*******  Functional Imaging Controls:  *******\n"
                      "\n"
                      "Pick Dataset --> Choose time-dependent dataset\n"
                      "   from a list.  If there is only one possible\n"
                      "   choice, it will be selected for you without\n"
                      "   displaying the list.\n"
                      "\n"
                      "Pick Ideal --> Choose time series from a list.\n"
                      "Pick Ort   --> Choose time series from a list.\n"
                      "\n"
                      "Ignore --> Set how many points to ignore at the\n"
                      "   beginning of time series.\n"
                      "   [ Applies both to graphing and FIM-ing. ]\n"
                      "\n"
                      "Refresh Freq --> Choose number of time steps\n"
                      "   between redisplay of the functional overlay\n"
                      "   during FIM computations (0 == no redisplay).\n"
                      "\n"
                      "Compute FIM --> Use the recursive method to\n"
                      "   compute the correlation of each voxel time\n"
                      "   series with each ideal vector;  uses the best\n"
                      "   correlation as the 'correct' waveform for\n"
                      "   each voxel, individually.  Time points that\n"
                      "   have an ideal vector value >= 33333 will be\n"
                      "   ignored in the computations, as will those\n"
                      "   at the beginning specified in the Opt menu\n"
                      "   'Ignore' function."
                    ) ;
   }

   /* macros to put double and single separator lines in a menu */

#undef MENU_DLINE
#define MENU_DLINE(wmenu)                                        \
   (void) XtVaCreateManagedWidget(                               \
            "dialog" , xmSeparatorWidgetClass , fmenu -> wmenu , \
             XmNseparatorType , XmDOUBLE_LINE , NULL )

#undef MENU_SLINE
#define MENU_SLINE(wmenu)                                        \
   (void) XtVaCreateManagedWidget(                               \
            "dialog" , xmSeparatorWidgetClass , fmenu -> wmenu , \
             XmNseparatorType , XmSINGLE_LINE , NULL )

   /* macro to create a new FIM menu button */

#define FIM_MENU_BUT(wname,label,hhh)                              \
   fmenu -> wname =                                                \
         XtVaCreateManagedWidget(                                  \
            "dialog" , xmPushButtonWidgetClass , fmenu->fim_menu , \
               LABEL_ARG( label ) ,                                \
               XmNmarginHeight , 0 ,                               \
               XmNtraversalOn , True  ,                            \
               XmNinitialResourcesPersistent , False ,             \
            NULL ) ;                                               \
      XtAddCallback( fmenu -> wname , XmNactivateCallback ,        \
                     cbfunc , (XtPointer) fmenu ) ;                \
      MCW_register_hint( fmenu -> wname , hhh ) ;

   /** macro to create a new fim pullright menu **/
   /** 07 Jan 1999: added the mapCallback to fix position **/

#define FIM_MENU_PULLRIGHT(wmenu,wcbut,label,hhh)                  \
   fmenu -> wmenu =                                                \
     XmCreatePulldownMenu( fmenu->fim_menu , "menu" , NULL , 0 ) ; \
   fmenu -> wcbut =                                                \
     XtVaCreateManagedWidget(                                      \
       "dialog" , xmCascadeButtonWidgetClass , fmenu->fim_menu ,   \
          LABEL_ARG( label ) ,                                     \
          XmNsubMenuId , fmenu -> wmenu ,                          \
          XmNtraversalOn , True  ,                                 \
          XmNinitialResourcesPersistent , False ,                  \
       NULL ) ;                                                    \
   MCW_register_hint( fmenu -> wcbut , hhh ) ;                     \
   XtAddCallback( fmenu -> wmenu, XmNmapCallback, GRA_mapmenu_CB, NULL ) ;

   /** macro to create a new button on a pullright menu **/

#define FIM_MENU_PULL_BUT(wmenu,wname,label,hhh)                  \
   fmenu -> wname =                                               \
         XtVaCreateManagedWidget(                                 \
            "dialog" , xmPushButtonWidgetClass , fmenu -> wmenu , \
               LABEL_ARG( label ) ,                               \
               XmNmarginHeight , 0 ,                              \
               XmNtraversalOn , True  ,                           \
               XmNinitialResourcesPersistent , False ,            \
            NULL ) ;                                              \
      XtAddCallback( fmenu -> wname , XmNactivateCallback ,       \
                     cbfunc , (XtPointer) fmenu ) ;               \
      MCW_register_hint( fmenu -> wname , hhh ) ;

#define EMPTY_BUT(wname) fmenu -> wname = NULL

   /** 15 Dec 1997: a pullright menu with a single button **/

#define FIM_MENU_QBUT(wname,label,qlab,hhh)                               \
 do { Widget ccc ;                                                        \
      qbut_menu = XmCreatePulldownMenu(fmenu->fim_menu,"menu",NULL,0);    \
            ccc = XtVaCreateManagedWidget( "dialog" ,                     \
                     xmCascadeButtonWidgetClass , fmenu->fim_menu ,       \
                     LABEL_ARG( label ) ,                                 \
                     XmNsubMenuId , qbut_menu ,                           \
                     XmNtraversalOn , True  ,                             \
                     XmNinitialResourcesPersistent , False , NULL ) ;     \
      fmenu -> wname = XtVaCreateManagedWidget( "dialog" ,                \
                         xmPushButtonWidgetClass , qbut_menu ,            \
                         LABEL_ARG( qlab ) ,                              \
                         XmNmarginHeight , 0 ,                            \
                         XmNtraversalOn , True  ,                         \
                         XmNinitialResourcesPersistent , False , NULL ) ; \
      MCW_register_hint( fmenu -> wname , hhh ) ;                         \
      XtAddCallback( fmenu -> wname , XmNactivateCallback ,               \
                     cbfunc , (XtPointer) fmenu ) ;                       \
      XtAddCallback( qbut_menu, XmNmapCallback, GRA_mapmenu_CB, NULL ) ;  \
 } while(0)

   /*** top of menu = a label to click on that does nothing at all ***/

   (void) XtVaCreateManagedWidget(
            "dialog" , xmLabelWidgetClass , fmenu->fim_menu ,
               LABEL_ARG("--- Cancel ---") ,
               XmNrecomputeSize , False ,
               XmNinitialResourcesPersistent , False ,
            NULL ) ;

   MENU_SLINE(fim_menu) ;

   if( graphable ){
      EMPTY_BUT(fim_pickdset_pb) ;
   } else {
      FIM_MENU_BUT( fim_pickdset_pb , "Pick Dataset" , "Choose Dataset to Graph" ) ;
   }

   FIM_MENU_BUT( fim_pickref_pb , "Pick Ideal" , "Pick Ideal Timeseries to Graph" ) ;
   FIM_MENU_BUT( fim_pickort_pb , "Pick Ort"   , "Pick Ort Timeseries to Graph"   ) ;

   if( graphable ){
      char *bbox_label[1] = { "Ideal=WinAver" } ;
      MENU_SLINE(fim_menu) ;
      FIM_MENU_PULLRIGHT(fim_editref_menu,fim_editref_cbut       ,"Edit Ideal"    , "Modify Ideal Timeseries" ) ;
      FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_equals_pb  ,"Ideal = Center", "Set to Center Sub-graph" ) ;
      FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_add_pb     ,"Ideal+= Center", "Add in Center Sub-graph" ) ;
      FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_smooth_pb  ,"Smooth Ideal"  , "Lowpass Filter Ideal"    ) ;
      FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_setshift_pb,"Shift Ideal"   , "Time Shift Ideal"        ) ;
      FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_clear_pb   ,"Clear Ideal"   , "Turn Ideal Off"          ) ;
      FIM_MENU_PULL_BUT (fim_editref_menu,fim_editort_clear_pb   ,"Clear Ort"     , "Turn Ort Off"            ) ;

      fmenu->fim_editref_winaver_bbox                      /* 27 Jan 2004 */
       = new_MCW_bbox( fmenu->fim_editref_menu ,
                       1 , bbox_label , MCW_BB_check , MCW_BB_noframe ,
                       GRA_winaver_CB , (XtPointer)fmenu ) ;
      MCW_reghint_children( fmenu->fim_editref_winaver_bbox->wrowcol ,
                            "Ideal = Average of all Graphs in Window" ) ;
#ifdef USE_OPTMENUS
      fmenu->fim_polort_choose_av =
         new_MCW_optmenu( fmenu->fim_editref_menu , "Polort " , 0,MAX_POLORT,1,0 ,
                          GRA_fmenu_av_CB , (XtPointer) fmenu , NULL , NULL ) ;
      fmenu->fim_polort_choose_pb = fmenu->fim_polort_choose_av->wrowcol ;
      MCW_reghint_children( fmenu->fim_polort_choose_av->wrowcol , "Order of Polynomial Baseline for FIM" ) ;
#else
      FIM_MENU_PULL_BUT( fim_editref_menu,fim_polort_choose_pb ,"Polort?", "Order of Polynomial Baseline for FIM") ;
#endif
      FIM_MENU_PULL_BUT( fim_editref_menu,fim_bkthr_choose_pb  ,"Bkg Thresh" , "Choose Background Threshold for FIM") ;
      MENU_SLINE        (fim_editref_menu) ;
      FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_read_pb    ,"Read Ideal" , "Read from .1D file"   ) ;
      FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_write_pb   ,"Write Ideal", "Write to .1D file"    ) ;
      FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_store_pb   ,"Store Ideal", "Save in internal list of timeseries" ) ;
   } else {
      EMPTY_BUT(fim_editref_cbut) ;
      EMPTY_BUT(fim_editref_equals_pb) ;
      EMPTY_BUT(fim_editref_add_pb) ;
      EMPTY_BUT(fim_editref_smooth_pb) ;
      EMPTY_BUT(fim_editref_setshift_pb) ;
      EMPTY_BUT(fim_editref_clear_pb) ;
      EMPTY_BUT(fim_editref_read_pb) ;
      EMPTY_BUT(fim_editref_write_pb) ;
      EMPTY_BUT(fim_editref_store_pb) ;
      EMPTY_BUT(fim_editort_clear_pb) ;
      EMPTY_BUT(fim_polort_choose_pb) ;
      fmenu->fim_editref_winaver_bbox = NULL ;  /* 27 Jan 2004 */
   }

   FIM_MENU_PULLRIGHT(fim_ignore_menu,fim_ignore_cbut      ,"Ignore", "Number of initial timepoints to ignore" ) ;
   FIM_MENU_PULL_BUT( fim_ignore_menu,fim_ignore_down_pb   ,"Down"  , "Ignore fewer points" ) ;
   FIM_MENU_PULL_BUT( fim_ignore_menu,fim_ignore_up_pb     ,"Up"    , "Ignore more points"  ) ;
#ifdef USE_OPTMENUS
   fmenu->fim_ignore_choose_av =
      new_MCW_optmenu( fmenu->fim_ignore_menu , "# " , 0,2,0,0 ,
                       GRA_fmenu_av_CB , (XtPointer) fmenu , NULL , NULL ) ;
   fmenu->fim_ignore_choose_pb = fmenu->fim_ignore_choose_av->wrowcol ;
   MCW_reghint_children( fmenu->fim_ignore_choose_av->wrowcol , "Pick number of ignored points" ) ;
#else
   FIM_MENU_PULL_BUT( fim_ignore_menu,fim_ignore_choose_pb ,"Choose" , "Pick number of ignored points") ;
#endif

   if( graphable ){
      FIM_MENU_PULLRIGHT(fim_plot_menu,fim_plot_cbut        ,"FIM Plots"   , "Number of Ideals to plot" ) ;
      FIM_MENU_PULL_BUT( fim_plot_menu,fim_plot_firstref_pb ,"First Ideal" , "Only plot 1 Ideal" ) ;
      FIM_MENU_PULL_BUT( fim_plot_menu,fim_plot_allrefs_pb  ,"All Ideals"  , "Plot all Ideals"   ) ;
   } else {
      EMPTY_BUT(fim_plot_cbut) ;
      EMPTY_BUT(fim_plot_firstref_pb) ;
      EMPTY_BUT(fim_plot_allrefs_pb) ;
   }

   MENU_DLINE(fim_menu) ;
   FIM_MENU_QBUT( fim_execute_pb   , "Compute FIM" , "-> fico" , "Correlation Analysis" ) ;
   MCW_set_widget_bg( fmenu->fim_execute_pb ,
                      MCW_hotcolor(fmenu->fim_execute_pb) , 0 ) ;

   { static char * blab[] = {"Fit Coef", "% Change", "% From Ave", "% From Top"};
     (void) XtVaCreateManagedWidget(
             "dialog" , xmSeparatorWidgetClass , qbut_menu ,
              XmNseparatorType , XmSINGLE_LINE , NULL ) ;

     fmenu->fim_opt_bbox = new_MCW_bbox( qbut_menu , 4 , blab ,
                                         MCW_BB_radio_one , MCW_BB_noframe ,
                                         NULL , NULL ) ;
     MCW_reghint_children( fmenu->fim_opt_bbox->wrowcol , "What to Compute" ) ;
   }

   MENU_DLINE(fim_menu) ;
   FIM_MENU_QBUT( fim_execfimp_pb  , "Compute FIM+" , "-> fbuc" , "Extended Correlation Analysis" ) ;
   MCW_set_widget_bg( fmenu->fim_execfimp_pb ,
                      MCW_hotcolor(fmenu->fim_execfimp_pb) , 0 ) ;

   (void) XtVaCreateManagedWidget(
           "dialog" , xmSeparatorWidgetClass , qbut_menu ,
            XmNseparatorType , XmSINGLE_LINE , NULL ) ;

   fmenu->fimp_opt_bbox = new_MCW_bbox( qbut_menu, FIM_NUM_OPTS, fim_opt_labels,
                                        MCW_BB_check , MCW_BB_noframe ,
                                        NULL , NULL ) ;
   MCW_reghint_children( fmenu->fimp_opt_bbox->wrowcol , "What to Compute" ) ;

   { char * ff = my_getenv( "AFNI_FIM_MASK" ) ; int mm=0 ;
     if( ff != NULL ) mm = strtol(ff,NULL,10) ;
     if( mm <= 0 ) mm = FIM_DEFAULT_MASK ;
     MCW_set_bbox( fmenu->fimp_opt_bbox , mm ) ;
   }

   /* 04 Jan 2000: add some more buttons */

   (void) XtVaCreateManagedWidget(
           "dialog" , xmSeparatorWidgetClass , qbut_menu ,
            XmNseparatorType , XmSINGLE_LINE , NULL ) ;

   fmenu->fimp_setdefault_pb =
      XtVaCreateManagedWidget( "dialog" , xmPushButtonWidgetClass , qbut_menu ,
                                 LABEL_ARG( "Set Defaults" ) ,
                                 XmNmarginHeight , 0 ,
                                 XmNtraversalOn , True  ,
                                 XmNinitialResourcesPersistent , False ,
                               NULL ) ;
   XtAddCallback( fmenu->fimp_setdefault_pb ,
                  XmNactivateCallback , cbfunc , (XtPointer) fmenu ) ;
   MCW_register_hint( fmenu->fimp_setdefault_pb , "Default computing options" ) ;

   fmenu->fimp_setall_pb =
      XtVaCreateManagedWidget( "dialog" , xmPushButtonWidgetClass , qbut_menu ,
                                 LABEL_ARG( "Set All" ) ,
                                 XmNmarginHeight , 0 ,
                                 XmNtraversalOn , True  ,
                                 XmNinitialResourcesPersistent , False ,
                               NULL ) ;
   XtAddCallback( fmenu->fimp_setall_pb ,
                  XmNactivateCallback , cbfunc , (XtPointer) fmenu ) ;
   MCW_register_hint( fmenu->fimp_setall_pb , "Set all computing options on" ) ;

   fmenu->fimp_unsetall_pb =
      XtVaCreateManagedWidget( "dialog" , xmPushButtonWidgetClass , qbut_menu ,
                                 LABEL_ARG( "Unset All" ) ,
                                 XmNmarginHeight , 0 ,
                                 XmNtraversalOn , True  ,
                                 XmNinitialResourcesPersistent , False ,
                               NULL ) ;
   XtAddCallback( fmenu->fimp_unsetall_pb ,
                  XmNactivateCallback , cbfunc , (XtPointer) fmenu ) ;
   MCW_register_hint( fmenu->fimp_unsetall_pb , "Set all computing options off" ) ;

   /* 01 Feb 2000: add user-contributed options (if any) */

   fmenu->fimp_user_bbox = NULL ; /* default = no menu */

   if( GLOBAL_library.registered_fim.num > 0 ){

      (void) XtVaCreateManagedWidget(
              "dialog" , xmSeparatorWidgetClass , qbut_menu ,
               XmNseparatorType , XmDOUBLE_LINE , NULL ) ;

      (void) XtVaCreateManagedWidget(
               "dialog" , xmLabelWidgetClass , qbut_menu ,
                  LABEL_ARG("--Extra Funcs--") ,
                  XmNrecomputeSize , False ,
                  XmNinitialResourcesPersistent , False ,
               NULL ) ;

      fmenu->fimp_user_bbox = new_MCW_bbox( qbut_menu,
                                            GLOBAL_library.registered_fim.num ,
                                            GLOBAL_library.registered_fim.labels ,
                                            MCW_BB_check , MCW_BB_noframe ,
                                            NULL , NULL ) ;
      MCW_reghint_children( fmenu->fimp_user_bbox->wrowcol , "Other correlation functions" ) ;
   }

   RETURN(fmenu) ;
}

/*-----------------------------------------------------------------------------
   Routines to handle point transformations of a timeseries (22 Oct 1996)
-------------------------------------------------------------------------------*/

char * GRA_transform_label( MCW_arrowval * av , XtPointer cd )
{
   MCW_function_list * xforms = (MCW_function_list *) cd ;

   if( av == NULL    || xforms == NULL        ||
       av->ival <= 0 || av->ival > xforms->num  ) return "-none-" ;

   return xforms->labels[av->ival - 1] ;  /* label for each function */
}

/*-----------------------------------------------------------------------------*/
/*! Will be called from both the 1D and 0D menus. */

void GRA_transform_CB( MCW_arrowval * av , XtPointer cd )
{
   MCW_grapher * grapher = (MCW_grapher *) cd ;

ENTRY("GRA_transform_CB") ;

   if( ! GRA_VALID(grapher) ) EXRETURN ;

   /** set the 0D transform function pointer **/

   if( av == grapher->transform0D_av && av != NULL ){
      if( grapher->status->transforms0D == NULL || av->ival <= 0 ||
          av->ival > grapher->status->transforms0D->num            ){

         grapher->transform0D_func  = NULL ;  /* no transform */
         grapher->transform0D_index = 0 ;
      } else {
         grapher->transform0D_func  = grapher->status->transforms0D->funcs[av->ival-1];
         grapher->transform0D_index = av->ival ;
         grapher->transform0D_flags = grapher->status->transforms0D->flags[av->ival-1];

         /* 21 Jul 2003: call the init function, if present */

         if( grapher->status->transforms0D->func_init[av->ival-1] != NULL )
          grapher->status->transforms0D->func_init[av->ival-1]() ;
      }
   }

   /** set the 1D transform function pointer **/

   if( av == grapher->transform1D_av && av != NULL ){
      if( grapher->status->transforms1D == NULL || av->ival <= 0 ||
          av->ival > grapher->status->transforms1D->num            ){

         grapher->transform1D_func  = NULL ;  /* no transform */
         grapher->transform1D_index = 0 ;
      } else {
         grapher->transform1D_func  = grapher->status->transforms1D->funcs[av->ival-1];
         grapher->transform1D_index = av->ival ;
         grapher->transform1D_flags = grapher->status->transforms1D->flags[av->ival-1];

         /* 21 Jul 2003: call the init function, if present */

         if( grapher->status->transforms1D->func_init[av->ival-1] != NULL )
          grapher->status->transforms1D->func_init[av->ival-1]() ;
      }
   }

   redraw_graph( grapher , 0 ) ;
   EXRETURN ;
}

/*----------------------------------------------------------------------------
   22 Sep 2000: for textgraph toggle
------------------------------------------------------------------------------*/

void GRA_textgraph_CB( Widget w , XtPointer client_data , XtPointer call_data )
{
   MCW_grapher *grapher = (MCW_grapher *) client_data ;
   int bbb ;

ENTRY("GRA_textgraph_CB") ;

   if( ! GRA_VALID(grapher) ) EXRETURN ;

   bbb = MCW_val_bbox( grapher->opt_textgraph_bbox ) ;
   if( bbb != grapher->textgraph ){
     grapher->textgraph = bbb ;
     redraw_graph( grapher , 0 ) ;
   }
   EXRETURN ;
}

/*----------------------------------------------------------------------------
   22 Sep 2000: for new baseline toggle
------------------------------------------------------------------------------*/

void GRA_baseline_CB( Widget w , XtPointer client_data , XtPointer call_data )
{
   MCW_grapher *grapher = (MCW_grapher *) client_data ;
   int bbb ;

ENTRY("GRA_baseline_CB") ;

   if( ! GRA_VALID(grapher) ) EXRETURN ;

   bbb = MCW_val_bbox( grapher->opt_baseline_bbox ) ;
   if( bbb != grapher->common_base ){
     grapher->common_base = bbb ;
     redraw_graph( grapher , 0 ) ;
   }
   EXRETURN ;
}

/*----------------------------------------------------------------------------
   Set the global baseline value
------------------------------------------------------------------------------*/

void GRA_finalize_global_baseline_CB( Widget w,
                                      XtPointer cd , MCW_choose_cbs *cbs )
{
   MCW_grapher *grapher = (MCW_grapher *) cd ;
   XmString xstr ;
   char str[32] ;

ENTRY("GRA_finalize_global_baseline_CB") ;

   if( !GRA_VALID(grapher) ) EXRETURN ;

   grapher->global_base = cbs->fval ;
   if( grapher->common_base == BASELINE_GLOBAL ) redraw_graph(grapher,0) ;

   strcpy(str,"Global:") ;
   AV_fval_to_char(grapher->global_base,str+7) ;
   xstr = XmStringCreateLtoR( str,XmFONTLIST_DEFAULT_TAG ) ;
   XtVaSetValues( grapher->opt_baseline_global_label ,
                     XmNlabelString,xstr ,
                  NULL ) ;
   XmStringFree(xstr) ;
   EXRETURN ;
}

/*----------------------------------------------------------------------------*/
/*** user presses Ideal=WinAver toggle [27 Jan 2004] ***/

void GRA_winaver_CB( Widget w , XtPointer client_data , XtPointer call_data )
{
   FIM_menu *fm = (FIM_menu *)client_data ;
   MCW_grapher *grapher = (MCW_grapher *)fm->parent ;

   if( MCW_val_bbox(grapher->fmenu->fim_editref_winaver_bbox) ){
     GRA_cbs cbs ;
     cbs.reason  = graCR_winaver ;
     CALL_sendback( grapher , cbs ) ;
     redraw_graph( grapher , 0 ) ;
   }
}
/*----------------------------------------------------------------------------*/

void GRA_winavertimer_CB( XtPointer cd , XtIntervalId *id )
{
   MCW_grapher *grapher = (MCW_grapher *)cd ;
   GRA_cbs cbs ;

   if( !GRA_REALZ(grapher) || grapher->ave_tsim == NULL ) return ;

   cbs.reason   = graCR_refequals ;
   cbs.userdata = (XtPointer)grapher->ave_tsim ;
   grapher->dont_redraw = 1 ;
   CALL_sendback( grapher , cbs ) ;
   grapher->dont_redraw = 0 ;
   return ;
}

/*----------------------------------------------------------------------------*/
/*** set ref to average time series [27 Jan 2004] ***/

void GRA_winaver_setref( MCW_grapher *grapher )
{
   GRA_cbs cbs ;

ENTRY("GRA_winaver_setref") ;

   if( !GRA_REALZ(grapher) || grapher->ave_tsim == NULL ){
    STATUS("nothing to do") ; EXRETURN ;
   }

   (void)XtAppAddTimeOut( XtWidgetToApplicationContext(grapher->opt_quit_pb) ,
                          1 , GRA_winavertimer_CB , grapher ) ;
   EXRETURN ;
}

/*----------------------------------------------------------------------------
   08 Nov 1996: for "double plots" -- just redraw everything
------------------------------------------------------------------------------*/

void GRA_dplot_change_CB( Widget w , XtPointer client_data , XtPointer call_data )
{
   MCW_grapher *grapher = (MCW_grapher *) client_data ;

ENTRY("GRA_dplot_change_CB") ;

   if( ! GRA_REALZ(grapher) ) EXRETURN ;
   redraw_graph( grapher , 0 ) ;
   EXRETURN ;
}

#ifdef USE_OPTMENUS
/*---------------------------------------------------------------------------
   Fix the optmenus for the grapher; used when the dataset changes
   and so the upper limits on the selectors must change too
-----------------------------------------------------------------------------*/

void GRA_fix_optmenus( MCW_grapher *grapher )
{
   int igtop ;

ENTRY("GRA_fix_optmenus") ;

   if( ! GRA_REALZ(grapher) ) EXRETURN ;

   /** matrix selection **/

   if( grapher->opt_mat_choose_av->imax != grapher->mat_max )
      refit_MCW_optmenu( grapher->opt_mat_choose_av ,
                         1 , grapher->mat_max , grapher->mat , 0 ,
                         NULL , NULL ) ;

   else
      AV_assign_ival( grapher->opt_mat_choose_av , grapher->mat ) ;

   /** slice selection **/

   if( grapher->opt_slice_choose_av->imax != grapher->status->nz-1 )
      refit_MCW_optmenu( grapher->opt_slice_choose_av ,
                         0, grapher->status->nz - 1, grapher->zpoint, 0,
                         NULL , NULL ) ;

   else
      AV_assign_ival( grapher->opt_slice_choose_av , grapher->zpoint ) ;

   /** fim ignoration **/

   igtop = MIN( grapher->status->num_series-2 , 99 ) ;
   igtop = MAX( igtop , 1 ) ;

   if( grapher->fmenu->fim_ignore_choose_av->imax != igtop )
      refit_MCW_optmenu( grapher->fmenu->fim_ignore_choose_av ,
                         0 , igtop , grapher->init_ignore, 0,
                         NULL , NULL ) ;
   else
      AV_assign_ival( grapher->fmenu->fim_ignore_choose_av , grapher->init_ignore ) ;

   /** 27 May 1999: fim polort **/

   AV_assign_ival( grapher->fmenu->fim_polort_choose_av , grapher->polort ) ;

   EXRETURN ;
}

/*--------------------------------------------------------------------------*/

void GRA_fmenu_av_CB( MCW_arrowval* av , XtPointer cd )
{
   FIM_menu *fmenu = (FIM_menu *) cd ;

ENTRY("GRA_fmenu_av_CB") ;
   fmenu->cbfunc( av->wrowcol , cd , NULL ) ;
   EXRETURN ;
}
#endif /* USE_OPTMENUS */

/*--------------------------------------------------------------------------
   Selection of a color submenu item
----------------------------------------------------------------------------*/

void GRA_color_CB( MCW_arrowval *av , XtPointer cd )
{
   MCW_grapher *grapher = (MCW_grapher *) cd ;
   int ii , jj ;

ENTRY("GRA_color_CB") ;

   if( ! GRA_VALID(grapher) ) EXRETURN ;

   for( ii=0 ; ii < NUM_COLOR_ITEMS ; ii++ )
     if( av == grapher->opt_color_av[ii] ) break ;

   if( ii < NUM_COLOR_ITEMS ){
     jj = grapher->color_index[ii] ;
     grapher->color_index[ii] = av->ival ;
     if( jj != grapher->color_index[ii] ) redraw_graph( grapher , 0 ) ;
   }
   EXRETURN ;
}

/*--------------------------------------------------------------------------*/

void GRA_thick_CB( Widget w , XtPointer cd , XtPointer call_data )
{
   MCW_grapher * grapher = (MCW_grapher *) cd ;
   int ii , jj ;

ENTRY("GRA_thick_CB") ;

   if( ! GRA_VALID(grapher) ) EXRETURN ;

   for( ii=0 ; ii < NUM_COLOR_ITEMS ; ii++ )
      if( grapher->opt_thick_bbox[ii] != NULL &&
          w == grapher->opt_thick_bbox[ii]->wbut[0] ) break ;

   if( ii < NUM_COLOR_ITEMS ){
      jj = grapher->thick_index[ii] ;
      grapher->thick_index[ii] = MCW_val_bbox( grapher->opt_thick_bbox[ii] ) ;
      if( jj != grapher->thick_index[ii] ) redraw_graph( grapher , 0 ) ;
      EXRETURN ;
   }

   /* 09 Jan 1998 */

   for( ii=0 ; ii < NUM_COLOR_ITEMS ; ii++ )
      if( grapher->opt_points_bbox[ii] != NULL &&
          ( w == grapher->opt_points_bbox[ii]->wbut[0] ||
            w == grapher->opt_points_bbox[ii]->wbut[1]   ) ) break ;

   if( ii < NUM_COLOR_ITEMS ){
      jj = grapher->points_index[ii] ;
      grapher->points_index[ii] = MCW_val_bbox( grapher->opt_points_bbox[ii] ) ;
      if( jj != grapher->points_index[ii] ) redraw_graph( grapher , 0 ) ;
      EXRETURN ;
   }

   EXRETURN ;  /* should not be reached */
}

/*--------------------------------------------------------------------------
   Save the background pixmap to a PNM file
----------------------------------------------------------------------------*/

void GRA_saver_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs * cbs )
{
   int ll , ii ;
   MCW_grapher * grapher = (MCW_grapher *) cd ;
   char * fname , * ppnm ;

ENTRY("GRA_saver_CB") ;

   if( ! GRA_REALZ(grapher) ) EXRETURN ;

   if( cbs->reason != mcwCR_string ||
       cbs->cval   == NULL         || (ll=strlen(cbs->cval)) == 0 ){

      XBell( XtDisplay(wcaller) , 100 ) ; EXRETURN ;
   }

   fname = (char *) malloc( sizeof(char) * (ll+8) ) ;
   strcpy( fname , cbs->cval ) ;

   for( ii=0 ; ii < ll ; ii++ )
      if( iscntrl(fname[ii]) || isspace(fname[ii]) ) break ;

   if( ii < ll || ll < 2 || ll > 240 ){
      XBell( XtDisplay(wcaller) , 100 ) ;
      free( fname ) ; EXRETURN ;
   }

                      ppnm = strstr( fname , ".ppm" ) ;
   if( ppnm == NULL ) ppnm = strstr( fname , ".pnm" ) ;
   if( ppnm == NULL ) ppnm = strstr( fname , ".jpg" ) ;
   if( ppnm == NULL ) strcat(fname,".ppm") ;

   GRA_file_pixmap( grapher , fname ) ;
   POPDOWN_string_chooser ;
   free(fname) ; EXRETURN ;
}

/*--------------------------------------------------------------------------*/

void GRA_file_pixmap( MCW_grapher *grapher , char *fname )
{
   XImage *xim ;
   XGCValues gcv ;
   MRI_IMAGE *tim ;
   int ii ;

ENTRY("GRA_file_pixmap") ;

   if( ! GRA_REALZ(grapher) ) EXRETURN ;
   if( grapher->fd_pxWind == (Pixmap) 0 ) EXRETURN ;

   ii = XGetGCValues( grapher->dc->display ,
                      grapher->dc->myGC , GCPlaneMask , &gcv ) ;
   if( ii == 0 ) EXRETURN ;

   xim = XGetImage( grapher->dc->display , grapher->fd_pxWind ,
                    0 , 0 , grapher->fWIDE , grapher->fHIGH ,
                    gcv.plane_mask , ZPixmap ) ;
   if( xim == NULL ) EXRETURN ;

   tim = XImage_to_mri( grapher->dc , xim , 0 ) ;
   if( tim == NULL ){ MCW_kill_XImage( xim ) ; EXRETURN ; }

   INFO_message("Writing grapher image to '%s'",fname) ;
   mri_write_pnm( fname , tim ) ;
   mri_free( tim ) ;
   MCW_kill_XImage( xim ) ;  /* 10 Mar 1999 */
   EXRETURN ;
}

/*-----------------------------------------------------------------------------
   07 Jan 1999: change location of newly popped up menu
-------------------------------------------------------------------------------*/

void GRA_mapmenu_CB( Widget w , XtPointer client_data , XtPointer call_data )
{
   int ww,hh,xx,yy ;
   int pw,ph,px,py ;

ENTRY("GRA_mapmenu_CB") ;

   if( AFNI_yesenv("AFNI_DONT_MOVE_MENUS") ) EXRETURN ;  /* 08 Aug 2001 */

   MCW_widget_geom( w                     , &ww,&hh , &xx,&yy ) ;
   MCW_widget_geom( XtParent(XtParent(w)) , &pw,&ph , &px,&py ) ;

#if 1
if(PRINT_TRACING){
 char str[256] ;
 sprintf(str,"menu:   width=%d height=%d x=%d y=%d",ww,hh,xx,yy); STATUS(str);
 sprintf(str,"parent: width=%d height=%d x=%d y=%d",pw,ph,px,py); STATUS(str); }
#endif

   pw = pw >> 3 ;
   if( ! ( xx > px+7*pw || xx+ww < px+pw ) ){
      xx = px - ww ;  if( xx < 0 ) xx = 0 ;
#if 1
if(PRINT_TRACING){
 char str[256]; sprintf(str,"moving menu to x=%d",xx); STATUS(str); }
#endif
      XtVaSetValues( w , XmNx , xx , NULL ) ;
   }

   RWC_xineramize( XtDisplay(w) , xx,yy,ww,hh , &xx,&yy ) ; /* 27 Sep 2000 */
   XtVaSetValues( w , XmNx,xx , XmNy,yy , NULL ) ;
   EXRETURN ;
}

/*----------------------------------------------------------------------------*/
/*! Do something every so often. */

void GRA_timer_CB( XtPointer cd , XtIntervalId *id ) /* 03 Dec 2003 */
{
   MCW_grapher *grapher = (MCW_grapher *)cd ;
   int redo = 0 ;

ENTRY("GRA_timer_CB") ;

   if( !GRA_REALZ(grapher) || grapher->timer_id == 0 ) EXRETURN ;

   switch( grapher->timer_func ){

     case GRA_TIMERFUNC_INDEX:{
       int nn = grapher->time_index , nt=grapher->status->num_series ;
       if( nt > 1 && grapher->timer_param != 0 ){
         nn = (nn+grapher->timer_param+nt) % nt ;
         redo = 1 ;
         if( grapher->status->send_CB != NULL ){
           GRA_cbs cbs ;
           cbs.reason = graCR_setindex ;
           cbs.key    = nn ;
           cbs.event  = NULL ;
#if 0
           grapher->status->send_CB( grapher, grapher->getaux, &cbs ) ;
#else
           CALL_sendback( grapher , cbs ) ;
#endif
         } else {
           (void) drive_MCW_grapher( grapher, graDR_setindex, (XtPointer)nn) ;
         }
       }
     }
     break ;

     case GRA_TIMERFUNC_BOUNCE:{
       int nn = grapher->time_index , nt=grapher->status->num_series ;
       if( nt > 1 && grapher->timer_param != 0 ){
         nn = nn + grapher->timer_param ;
         if( nn <  0  ){
           nn = -nn; grapher->timer_param = -grapher->timer_param;
         } else if( nn >= nt ){
           nn = 2*(nt-1)-nn; grapher->timer_param = -grapher->timer_param;
         }
         redo = 1 ;
         if( grapher->status->send_CB != NULL ){
           GRA_cbs cbs ;
           cbs.reason = graCR_setindex ;
           cbs.key    = nn ;
           cbs.event  = NULL ;
#if 0
           grapher->status->send_CB( grapher, grapher->getaux, &cbs ) ;
#else
           CALL_sendback( grapher , cbs ) ;
#endif
         } else {
           (void) drive_MCW_grapher( grapher, graDR_setindex, (XtPointer)nn) ;
         }
       }
     }
     break ;

   }

   if( redo ) grapher->timer_id = XtAppAddTimeOut(
                                   XtWidgetToApplicationContext(grapher->opt_quit_pb) ,
                                   grapher->timer_delay , GRA_timer_CB , grapher ) ;
   else       grapher->timer_id = 0 ;

   EXRETURN ;
}

/*--------------------------------------------------------------------------*/

void GRA_timer_stop( MCW_grapher *grapher )
{
   if( grapher->timer_id > 0 ){
     XtRemoveTimeOut(grapher->timer_id); grapher->timer_id = 0;
   }
}


syntax highlighted by Code2HTML, v. 0.9.1