1 /*****************************************************************************
2    Major portions of this software are copyrighted by the Medical College
3    of Wisconsin, 1994-2000, and are released under the Gnu General Public
4    License, Version 2.  See the file README.Copyright for details.
5 ******************************************************************************/
6 
7 /*------------------------------------------------------------------------*/
8 /* Please note that this file is not "integrated" into AFNI. By this I
9    mean that it doesn't know about AFNI controllers, datasets, and so on.
10    It is a graphing server, and the caller needs to provide a callback
11    function to get data to be graphed, and also provide some other info.
12 
13    The exceptions to the "not integrated into AFNI" ukase are the parts
14    of the code inside #ifdef BE_AFNI_AWARE ,,, #endif sections.
15 
16    The actual graphs are drawn in function plot_graphs().
17    All the rest of the code is decoration or bureaucracy.
18 
19    Note that XDrawLines and XFillPolygon are superseded by
20    function AFNI_XDrawLines and AFNI_XFillPolygon (way down in this file)
21    to provide for upsampling the curves with smoothing. Search below
22    for 'Upsampling' to find where these shenanigans begin.
23 *//*----------------------------------------------------------------------*/
24 
25 /*------------------------------------------------------------------------*/
26 /* The AFNI graph viewer is organized much like the image viewer (imseq.c).
27    It gets data and sends info to AFNI via a "callback" function get_ser().
28    It can be driven from outside by calling function drive_MCW_grapher().
29    Much of the early code was adapted from program FD2.c (by myself),
30    which was in turn lifted from program FD.c (by Andrzej Jesmanowicz).
31 
32    This history explains why there are 2 different X11 drawing objects:
33      fd_pxWind = a Pixmap, which is a non-visible object into which
34                  most of the graphing information is drawn -- the
35                  Pixmap is a client-side object, rather than a Window,
36                  which is an X11 server-side object. The idea is
37                  that drawing into the Pixmap does not require any
38                  AFNI-to-X11 communication.
39      draw_fd   = a Motif Drawing Area widget, whose Window on the X11
40                  server is where the actual display takes place
41    The Pixmap is drawn -- in functions redraw_graph() and plot_graphs() --
42    and then pushed in a single operation to the window via function
43    fd_px_store(). The reason AJ chose for this somewhat clumsy method was
44    speed -- on the slower computers/displays of the early 1990s, redrawing
45    all the graphs just to make a minor change was slow. Instead, the idea
46    was to fix the stuff that doesn't change often, and then re-draw into
47    the window only the overlay stuff that changes more often. Of course,
48    FD and FD2 had a fixed size window, which made this choice more sensible.
49    Now, with faster everything and resizable graph windows, this division
50    of display labor perhaps seems a little silly.
51 
52    But I'm not going to re-write it! -- RWCox -- January 2021
53 *//*----------------------------------------------------------------------*/
54 
55 /*------------------------------------------------------------------------*/
56 /* Another word of explanation. The FIM menu items in the graph viewer
57    are a legacy of FD2.c -- which was a mashup of the older programs
58    fim.c (functional image map via the correlation method) and FD.c
59    (display of one slice worth of EPI images and graphs). FD2.c allowed
60    for the first time for interactive exploration of FMRI results,
61    albeit in only 2D+time. When I came to add 3D+time data to AFNI (1996),
62    I naturally adapted FD2.c as the starting point for the graph viewer.
63    However, the FIM functions have not be changed or updated in any way
64    for years now -- they still work (I hope), but are not particularly
65    useful, as the FMRI data analysis world has gotten more complicated.
66    But interactive FIM was fun while it lasted. You kids don't know
67    what you are missing.
68 *//*----------------------------------------------------------------------*/
69 
70 /*----------------------------------------------------------------------
71  * history:
72  *
73  *   2003 Dec 19 [rickr]
74  *     - added Mean and Sigma to bottom of graph window
75  *----------------------------------------------------------------------
76 */
77 
78 #undef MAIN
79 #include "afni_graph.h"
80 #include "afni.h"
81 #include <X11/keysym.h>  /* 24 Jan 2003 */
82 
83 static int show_grapher_pixmap = 1 ;
84 static void fd_line( MCW_grapher *, int,int,int,int ) ;
85 static byte PLOT_FORCE_AUTOSCALE = 1;  /* change to 1 [08 Mar 2016 - Okazaki] */
86 static Widget wtemp ;
87 
88 #ifdef BE_AFNI_AWARE
89 static AFNI_dataset_choose_stuff cdds = { 0,0, NULL, NULL, NULL } ;
90 static void GRA_finalize_xaxis_dset_CB( Widget w, XtPointer cd, MCW_choose_cbs *cbs ) ;
91 extern void AFNI_choose_dataset_CB    ( Widget , XtPointer , XtPointer ) ;
92 extern FD_brick * THD_3dim_dataset_to_brick( THD_3dim_dataset *dset ,
93                                       int ax_1, int ax_2, int ax_3 ) ;
94 extern MRI_IMAGE * FD_brick_to_series( int , FD_brick * br ) ;
95 #endif
96 
97 static int fade_color = 19 ;
98 
99 static char *startup_1D_transform = NULL ;
100 
101 /*------------------------------------------------------------*/
102 /*! Macro to call the getser function with correct prototype. */
103 
104 #undef  CALL_getser
105 #define CALL_getser(gr,aa,bb,rtyp,rval)                         \
106  do{ XtPointer (*gs)(int,int,XtPointer) =                       \
107       (XtPointer (*)(int,int,XtPointer))(gr->getser) ;          \
108     rval = (rtyp) gs(aa,bb,gr->getaux) ;                        \
109  } while(0)
110 
111 /*------------------------------------------------------------*/
112 /*! And to call the send_CB function with a good prototype.   */
113 
114 #undef  CALL_sendback
115 #define CALL_sendback(gr,scb)                                                 \
116  do{ void (*sb)(MCW_grapher *,XtPointer,GRA_cbs *) =                          \
117       (void (*)(MCW_grapher *,XtPointer,GRA_cbs *))(gr->status->send_CB) ;    \
118      if( sb != NULL ) sb(gr,gr->getaux,&scb) ;                                \
119  } while(0)
120 
121 #undef  BOXOFF
122 #define BOXOFF 9 /* BOX vertical offset (pixels) - for various spacing things */
123 
124 /*------------------------------------------------------------*/
125 /*! Create a new MCW_grapher window and structure.            */
126 
new_MCW_grapher(MCW_DC * dc,get_ptr getser,XtPointer aux)127 MCW_grapher * new_MCW_grapher( MCW_DC *dc , get_ptr getser , XtPointer aux )
128 {
129    int ii ;
130    MCW_grapher *grapher ;
131    static int new_xsize = -1 , new_ysize = -1 ;
132    char *buf , *cpt ;
133    Widget rc_tmp , mb_tmp , form_tmp ;  /* 29 Sep 2000 */
134 
135 ENTRY("new_MCW_grapher") ;
136 
137    grapher = myXtNew( MCW_grapher ) ;
138 
139    grapher->type   = MCW_GRAPHER_TYPE ;
140    grapher->dc     = dc ;
141    grapher->getser = getser ;
142    grapher->getaux = aux ;
143    grapher->parent = NULL ;
144    grapher->valid  = 1 ;
145 
146    grapher->grid_spacing    = 10;  /* prevent div by 0, 15 Aug 2008 [rickr] */
147 
148    grapher->dont_redraw     = 0 ;  /* 27 Jan 2004 */
149    grapher->timer_id        = 0 ;  /* 04 Dec 2003 */
150    grapher->never_drawn     = 1 ;
151    grapher->button2_enabled = 0 ;  /* Feb 1998 */
152    grapher->mirror          = 0 ;  /* Jul 2000 */
153 
154    grapher->tschosen        = 0 ;  /* 31 Mar 2004 */
155    grapher->detrend         = -1;  /* 05 Dec 2012 */
156    grapher->thresh_fade     = AFNI_yesenv("AFNI_GRAPH_FADE") ;  /* Mar 2013 */
157 
158    grapher->gx_max = 0 ;
159    grapher->gy_max = 0 ;
160    grapher->fWIDE  = 0 ;
161    grapher->fHIGH  = 0 ;
162 
163    grapher->glogo_pixmap = XmUNSPECIFIED_PIXMAP ;
164    grapher->glogo_width  = grapher->glogo_height = 0 ;
165 
166 #if 0
167    grapher->status = (MCW_grapher_status *) getser(0,graCR_getstatus,aux) ;
168 #else
169    CALL_getser( grapher , 0,graCR_getstatus , MCW_grapher_status *,grapher->status ) ;
170 #endif
171 
172    if( grapher->status->num_series < 1 ){
173      fprintf(stderr,"*** Attempt to create grapher with < 1 time points! ***\a\n") ;
174      myXtFree(grapher) ;
175      RETURN(NULL) ;
176    }
177 
178    GRA_NULL_tuser(grapher) ;  /* 22 Apr 1997 */
179 
180    /** make shell that holds all **/
181 
182    grapher->fdw_graph =
183       XtVaAppCreateShell(
184          "AFNI" , "AFNI" , topLevelShellWidgetClass , dc->display ,
185            XmNminHeight , MIN_XSIZE + GL_DLX + GR_DLX ,
186            XmNmaxHeight , dc->height ,
187            XmNminWidth  , MIN_YSIZE + GT_DLY + GB_DLY ,
188            XmNmaxWidth  , dc->width ,
189            XmNdeleteResponse   , XmDO_NOTHING ,   /* deletion handled below */
190            XmNallowShellResize , False ,          /* let code resize shell */
191            XmNinitialResourcesPersistent , False ,
192               XmNkeyboardFocusPolicy , XmEXPLICIT ,
193       NULL ) ;
194 
195    DC_yokify( grapher->fdw_graph , dc ) ;  /* 14 Sep 1998 */
196 
197    /** find initial size of new graphs **/
198 
199    if( new_xsize < 0 ){
200       new_xsize = GX_MAX ;
201 #if 0
202       buf = XGetDefault(dc->display,"AFNI","graph_width") ;
203 #else
204       buf = RWC_getname(dc->display,"graph_width") ;
205 #endif
206       if( buf != NULL ){
207          ii = strtol( buf , &cpt , 10 ) ;
208          if( *cpt == '\0' || new_xsize >= MIN_XSIZE ||
209                              new_xsize <= dc->width - GL_DLX - GR_DLX )
210             new_xsize = ii ;
211       }
212 
213       new_ysize = GY_MAX ;
214 #if 0
215       buf = XGetDefault(dc->display,"AFNI","graph_height") ;
216 #else
217       buf = RWC_getname(dc->display,"graph_height") ;
218 #endif
219       if( buf != NULL ){
220          ii = strtol( buf , &cpt , 10 ) ;
221          if( *cpt == '\0' || new_ysize >= MIN_YSIZE ||
222                              new_ysize <= dc->width - GT_DLY - GB_DLY )
223             new_ysize = ii ;
224       }
225    }
226 
227    /** 29 Sep 2000: put in a Form to hold everything **/
228 
229    form_tmp = XtVaCreateWidget(
230                   "dialog" , xmFormWidgetClass , grapher->fdw_graph ,
231                     XmNwidth  , new_xsize + GL_DLX + GR_DLX ,
232                     XmNheight , new_ysize + GT_DLY + GB_DLY ,
233                     XmNborderWidth , 0 ,
234                     XmNtraversalOn , True ,
235                     XmNinitialResourcesPersistent , False ,
236               NULL ) ;
237 
238     grapher->top_form = form_tmp ; /* save this [24 May 2018] */
239 
240    /** make a drawing area to get everything **/
241 
242    grapher->draw_fd =
243        XtVaCreateManagedWidget(
244          "dialog" , xmDrawingAreaWidgetClass , form_tmp ,
245 
246 #if 0
247           XmNwidth  , new_xsize + GL_DLX + GR_DLX ,
248           XmNheight , new_ysize + GT_DLY + GB_DLY ,
249 #endif
250 
251           XmNtopAttachment    , XmATTACH_FORM ,
252           XmNleftAttachment   , XmATTACH_FORM ,
253           XmNrightAttachment  , XmATTACH_FORM ,
254           XmNbottomAttachment , XmATTACH_FORM ,
255 
256           XmNmarginWidth  , 0 ,
257           XmNmarginHeight , 0 ,
258 
259           XmNtraversalOn , True ,
260           XmNinitialResourcesPersistent , False ,
261        NULL ) ;
262 
263    XtInsertEventHandler( grapher->draw_fd ,     /* handle events in graphs */
264 
265                             0
266                           | KeyPressMask        /* get keystrokes */
267                           | ButtonPressMask     /* button presses */
268                           | ExposureMask        /* exposures */
269                           | StructureNotifyMask /* resizes */
270                          ,
271                          FALSE ,                /* nonmaskable events? */
272                          GRA_drawing_EV ,       /* super-handler! */
273                          (XtPointer) grapher ,  /* client data */
274                          XtListTail ) ;         /* last in queue */
275 
276    MCW_register_help( grapher->draw_fd ,
277                        "Button 1 in a sub-graph --> move it to center\n"
278                        "Button 1 in the central --> move time index\n"
279                        "              sub-graph     to closest point\n"
280                        "                            on the graph\n"
281 #if 0
282                        "Shift or Ctrl keys with --> single-step time\n"
283                        "Button 1 in the central     index up or down\n"
284                        "              sub-graph\n"
285 #endif
286                        "\n"
287                        "The red dot in the central sub-graph shows\n"
288                        "the location of the current time index.\n"
289                        "\n"
290                        "Button 3 in a sub-graph --> show statistics\n"
291                        "                            of time series\n"
292                        "\n"
293                        "To turn off the AFNI logo, click Button 1\n"
294                        "inside the logo.\n"
295                        "\n"
296                        "Miscellaneous Keystrokes:\n"
297                        "< or [ = move back in time 1 point\n"
298                        "> or ] = move forward in time 1 point\n"
299                        "1      = move to 1st time point\n"
300                        "l      = move to last time point\n"
301                        "L      = turn AFNI logo on/off\n"
302                        "F      = turn threshold 'Fading' on/off\n"
303                        "v/V    = Video up/down in time\n"
304                        "r/R    = Video ricochet up/down in time\n"
305                        "p      = play sound from central graph\n"
306                        "P      = play sound from average graph\n"
307                        "         and central graph (polyphony)\n"
308                        "K      = kill any running sound player\n"
309                        "C      = cycle color scheme\n"
310                        "s      = draw smooth graph curves\n"
311                        "^B     = cycle thru graph drawing modes\n"
312                        "\n"
313                        "See the 'Opt' menu for other keypress actions\n"
314                        "and for other options to control graph display."
315                     ) ;
316 
317    /*---------------------------*/
318    /*--- Button 3 popup menu ---*/
319    /*---------------------------*/
320 
321 #ifdef BAD_BUTTON3_POPUPS    /* 21 Jul 2003 */
322    grapher->but3_menu =
323       XmCreatePopupMenu(          form_tmp, "menu" , NULL , 0 ) ;
324 #else
325    grapher->but3_menu =
326       XmCreatePopupMenu( grapher->draw_fd , "menu" , NULL , 0 ) ;
327 #endif
328 
329    SAVEUNDERIZE(XtParent(grapher->but3_menu)) ; /* 27 Feb 2001 */
330 
331    VISIBILIZE_WHEN_MAPPED(grapher->but3_menu) ;
332 #if 0
333    if( !AFNI_yesenv("AFNI_DISABLE_TEAROFF") ) TEAROFFIZE(grapher->but3_menu) ;
334 #endif
335 
336    grapher->but3_label =
337       XtVaCreateManagedWidget(
338          "dialog" , xmLabelWidgetClass , grapher->but3_menu ,
339             XmNalignment , XmALIGNMENT_BEGINNING ,
340             XmNtraversalOn , True ,
341             XmNinitialResourcesPersistent , False ,
342          NULL ) ;
343    LABELIZE(grapher->but3_label) ;
344 
345    /*-------------------------------------*/
346    /*--- RowColumn to hold all buttons ---*/
347    /*-------------------------------------*/
348 
349    grapher->option_rowcol =
350       XtVaCreateWidget(
351          "dialog" , xmRowColumnWidgetClass , form_tmp ,
352             XmNpacking     , XmPACK_TIGHT ,
353             XmNorientation , XmHORIZONTAL ,
354             XmNmarginWidth , 0 ,
355             XmNmarginHeight, 0 ,
356             XmNspacing     , 2 ,
357             XmNbackground  , grapher->dc->ovc->pixov_brightest ,
358             XmNtraversalOn , True ,
359             XmNinitialResourcesPersistent , False ,
360             XmNleftAttachment   , XmATTACH_NONE ,
361             XmNtopAttachment    , XmATTACH_NONE ,
362             XmNrightAttachment  , XmATTACH_FORM ,
363             XmNbottomAttachment , XmATTACH_FORM ,
364          NULL ) ;
365 
366 #if 0
367    allow_MCW_optmenu_popup( 0 ) ;  /* 12 Dec 2001 */
368 #endif
369 
370    /*------------------------*/
371    /*--- FIM Menu Buttons ---*/
372    /*------------------------*/
373 
374    /* 29 Sep 2000: move menu buttons each onto private menubars */
375 
376    rc_tmp = XtVaCreateWidget(
377               "dialog" , xmRowColumnWidgetClass , grapher->option_rowcol ,
378                  XmNorientation , XmHORIZONTAL ,
379                  XmNpacking , XmPACK_TIGHT ,
380                  XmNmarginWidth , 0 ,
381                  XmNmarginHeight, 0 ,
382                  XmNspacing     , 0 ,
383                  XmNbackground  , grapher->dc->ovc->pixov_brightest ,
384                  XmNtraversalOn , True ,
385                  XmNinitialResourcesPersistent , False ,
386               NULL ) ;
387    mb_tmp = XmCreateMenuBar( rc_tmp , "dialog" , NULL,0 ) ;
388    XtVaSetValues( mb_tmp ,
389                      XmNmarginWidth  , 0 ,
390                      XmNmarginHeight , 0 ,
391                      XmNspacing      , 0 ,
392                      XmNborderWidth  , 0 ,
393                      XmNborderColor  , 0 ,
394                      XmNtraversalOn  , True ,
395                      XmNbackground   , grapher->dc->ovc->pixov_brightest ,
396                   NULL ) ;
397    XtManageChild( mb_tmp ) ;
398 
399    grapher->fmenu = AFNI_new_fim_menu( mb_tmp , GRA_fim_CB , 1 ) ;
400    grapher->fmenu->parent = (XtPointer) grapher ;
401    XtManageChild( rc_tmp ) ;
402 
403    grapher->polort = 1 ;  /* 27 May 1999 */
404 
405    /* macros to put double and single separator lines in a menu */
406 
407 #define MENU_DLINE(wmenu)                                          \
408    (void) XtVaCreateManagedWidget(                                 \
409             "dialog" , xmSeparatorWidgetClass , grapher -> wmenu , \
410              XmNseparatorType , XmDOUBLE_LINE , NULL )
411 
412 #define MENU_SLINE(wmenu)                                          \
413    (void) XtVaCreateManagedWidget(                                 \
414             "dialog" , xmSeparatorWidgetClass , grapher -> wmenu , \
415              XmNseparatorType , XmSINGLE_LINE , NULL )
416 
417    /*------------------------*/
418    /*--- Opt Menu Buttons ---*/
419    /*------------------------*/
420 
421    /* 29 Sep 2000: move menu buttons each onto private menubars */
422 
423    rc_tmp = XtVaCreateWidget(
424               "dialog" , xmRowColumnWidgetClass , grapher->option_rowcol ,
425                  XmNorientation , XmHORIZONTAL ,
426                  XmNpacking , XmPACK_TIGHT ,
427                  XmNmarginWidth , 0 ,
428                  XmNmarginHeight, 0 ,
429                  XmNspacing     , 0 ,
430                  XmNbackground  , grapher->dc->ovc->pixov_brightest ,
431                  XmNtraversalOn , True ,
432                  XmNinitialResourcesPersistent , False ,
433               NULL ) ;
434    mb_tmp = XmCreateMenuBar( rc_tmp , "dialog" , NULL,0 ) ;
435    XtVaSetValues( mb_tmp ,
436                      XmNmarginWidth  , 0 ,
437                      XmNmarginHeight , 0 ,
438                      XmNspacing      , 0 ,
439                      XmNborderWidth  , 0 ,
440                      XmNborderColor  , 0 ,
441                      XmNtraversalOn  , True ,
442                      XmNbackground   , grapher->dc->ovc->pixov_brightest ,
443                   NULL ) ;
444    XtManageChild( mb_tmp ) ;
445 
446    grapher->opt_menu = XmCreatePulldownMenu( mb_tmp , "menu" , NULL,0 ) ;
447 
448    VISIBILIZE_WHEN_MAPPED(grapher->opt_menu) ;  /* 27 Sep 2000 */
449 #if 0
450    if( !AFNI_yesenv("AFNI_DISABLE_TEAROFF") ) TEAROFFIZE(grapher->opt_menu) ;
451 #endif
452 
453    grapher->opt_cbut =
454          XtVaCreateManagedWidget(
455             "dialog" , xmCascadeButtonWidgetClass , mb_tmp ,
456                LABEL_ARG("Opt") ,
457                XmNsubMenuId , grapher->opt_menu ,
458                XmNmarginWidth  , 0 ,
459                XmNmarginHeight , 0 ,
460                XmNmarginBottom , 0 ,
461                XmNmarginTop    , 0 ,
462                XmNmarginRight  , 0 ,
463                XmNmarginLeft   , 0 ,
464                XmNtraversalOn  , True ,
465                XmNinitialResourcesPersistent , False ,
466             NULL ) ;
467 
468    XtManageChild( rc_tmp ) ;
469 
470    MCW_register_hint( grapher->opt_cbut , "Graphing options menu" ) ;
471 
472    MCW_register_help( grapher->opt_cbut ,
473                       "********  Graph Display Options:  ********\n"
474                       "\n"
475                       "Scale       --> Change vertical scaling\n"
476                       "Matrix      --> Change number of sub-graphs\n"
477                       "Grid        --> Change number of grid lines;\n"
478                       "                 also can Pin the number of\n"
479                       "                 time points displayed.\n"
480                       "Slice       --> Change slice number\n"
481                       "Colors, Etc --> Change colors of various\n"
482                       "                 parts of the graph window\n"
483                       "Baseline    --> Display each sub-graph with\n"
484                       "                 its minimum at the bottom of\n"
485                       "                 its window (the default), OR\n"
486                       "                 with the minimum of all sub-\n"
487                       "                 graphs as the common baseline\n"
488                       "Show Text?  --> Instead of graphs, show the\n"
489                       "                 numerical values of the data\n"
490                       "                 at the current time index\n"
491                       "                 in each sub-graph box\n"
492                       "Save PNM    --> Save the graph window as an\n"
493                       "                 image to a PNM format file\n"
494                       "                 [or .png or .jpg]\n"
495                       "Write Center--> Central voxel timeseries will\n"
496                       "                 be written to a file with a\n"
497                       "                 name like 'X_Y_Z.suffix.1D'\n"
498                       "                 where X,Y,Z are voxel indexes\n"
499                       "Tran 0D     --> Choose a function to apply to\n"
500                       "                 each point in each timeseries\n"
501                       "Tran 1D     --> Choose a function to apply to\n"
502                       "                 the timeseries as a whole\n"
503                       "Double Plot --> If 'Tran 1D' is active, then\n"
504                       "                 plot the data timeseries AND\n"
505                       "                 the transformed timeseries\n"
506                       "Done        --> Close this graphing window\n"
507                       "\n"
508                       "The keystrokes indicated in the menus will\n"
509                       "carry out the same functions, if pressed\n"
510                       "when the cursor focus is in the graph window.\n"
511                       "\n"
512                       "N.B.: keystrokes without menu items are:\n"
513                       " <  -->  move time index down by 1\n"
514                       " >  -->  move time index up by 1\n"
515                       " 1  -->  move to first image (time index 0)\n"
516                       " l  -->  move to last image in time series\n"
517                       " L  -->  turn off the AFNI logo in the corner"
518                     ) ;
519 
520    /** macro to create a new opt menu button **/
521 
522 #define OPT_MENU_BUT(wname,label,hhh)                                \
523    grapher -> wname =                                                \
524          XtVaCreateManagedWidget(                                    \
525             "dialog" , xmPushButtonWidgetClass , grapher->opt_menu , \
526                LABEL_ARG( label ) ,                                  \
527                XmNmarginHeight , 0 ,                                 \
528                XmNtraversalOn , True ,                               \
529                XmNinitialResourcesPersistent , False ,               \
530             NULL ) ;                                                 \
531       XtAddCallback( grapher -> wname , XmNactivateCallback ,        \
532                      GRA_opt_CB , (XtPointer) grapher ) ;            \
533       MCW_register_hint( grapher -> wname , hhh ) ;
534 
535    /** macro to create a new opt pullright menu **/
536    /** 07 Jan 1999: added the mapCallback to fix position **/
537 
538 #define OPT_MENU_PULLRIGHT(wmenu,wcbut,label,hhh)                      \
539    grapher -> wmenu =                                                  \
540      XmCreatePulldownMenu( grapher->opt_menu , "menu" , NULL , 0 ) ;   \
541    grapher -> wcbut =                                                  \
542      XtVaCreateManagedWidget(                                          \
543        "dialog" , xmCascadeButtonWidgetClass , grapher->opt_menu ,     \
544           LABEL_ARG( label ) ,                                         \
545           XmNsubMenuId , grapher -> wmenu ,                            \
546           XmNtraversalOn , True  ,                                     \
547           XmNinitialResourcesPersistent , False ,                      \
548        NULL ) ;                                                        \
549    MCW_register_hint( grapher -> wcbut , hhh ) ;                       \
550    XtAddCallback( grapher -> wmenu, XmNmapCallback, GRA_mapmenu_CB, NULL ) ;
551 
552    /** macro to create a new button on a pullright menu **/
553 
554 #define OPT_MENU_PULL_BUT(wmenu,wname,label,hhh)                    \
555    grapher -> wname =                                               \
556          XtVaCreateManagedWidget(                                   \
557             "dialog" , xmPushButtonWidgetClass , grapher -> wmenu , \
558                LABEL_ARG( label ) ,                                 \
559                XmNmarginHeight , 0 ,                                \
560                XmNtraversalOn , True  ,                             \
561                XmNinitialResourcesPersistent , False ,              \
562             NULL ) ;                                                \
563       XtAddCallback( grapher -> wname , XmNactivateCallback ,       \
564                      GRA_opt_CB , (XtPointer) grapher ) ;           \
565    MCW_register_hint( grapher -> wname , hhh ) ;
566 
567 #ifdef USE_OPTMENUS
568    /** macro to create an option menu on a pullright menu
569        (this menu must be fixed up later in GRA_fix_optmenus) **/
570 
571 #define OPT_MENU_OPTMENU(wmenu,wname,label,cb,hhh)                  \
572    grapher -> wname =                                               \
573       new_MCW_optmenu( grapher -> wmenu , label , 0,1,0,0 ,         \
574                        cb , (XtPointer) grapher , NULL , NULL ) ;   \
575    MCW_reghint_children( grapher -> wname -> wrowcol , hhh ) ;
576 
577 #endif /* USE_OPTMENUS */
578 
579    /*** top of menu = a label to click on that does nothing at all ***/
580 
581 #ifdef USING_LESSTIF
582                /* Using  xmLabelWidgetClass causes X11 to hang until
583                afni is terminated. The hangup occurs after an option
584                button, like:
585                    ignore --> |-3|
586                is set and then -- Cancel -- is clicked upon.
587                Also, it seems that the hangup does not occur unless we have:
588                   an 'option menu' inside a 'pulldown menu' which is in
589                   another  'pulldown menu' !
590 
591                So, not all Cancel LabelWidgets will be modified.
592 
593                            LessTif patrol      Jan. 07 09  */
594    (void) XtVaCreateManagedWidget(
595             "dialog" , xmPushButtonWidgetClass , grapher->opt_menu ,
596                LABEL_ARG("--- Cancel ---") ,
597                XmNrecomputeSize , False ,
598                XmNinitialResourcesPersistent , False ,
599             NULL ) ;
600 #else
601    wtemp = XtVaCreateManagedWidget(
602             "dialog" , xmLabelWidgetClass , grapher->opt_menu ,
603                LABEL_ARG("--- Cancel ---") ,
604                XmNrecomputeSize , False ,
605                XmNinitialResourcesPersistent , False ,
606             NULL ) ; LABELIZE(wtemp) ;
607 #endif
608 
609    MENU_SLINE(opt_menu) ;
610    OPT_MENU_BUT(opt_pin_choose_pb   ,"Index Pin/Stride" , "Fix index range of graph window" ) ;
611 
612    MENU_SLINE(opt_menu) ;
613 
614    OPT_MENU_PULLRIGHT(opt_scale_menu,opt_scale_cbut     ,"Scale"   ,"Change vertical scale" );
615    OPT_MENU_PULL_BUT(opt_scale_menu,opt_scale_down_pb  ,"Down [-]","Shrink graph heights"  );
616    OPT_MENU_PULL_BUT(opt_scale_menu,opt_scale_up_pb    ,"Up   [+]","Increase graph heights");
617    OPT_MENU_PULL_BUT(opt_scale_menu,opt_scale_choose_pb,"Choose"  ,"Set vertical scale"    );
618    OPT_MENU_PULL_BUT(opt_scale_menu,opt_scale_auto_pb  ,"Auto [a]","Scale automatically"   );
619    OPT_MENU_PULL_BUT(opt_scale_menu,opt_scale_AUTO_pb  ,"AUTO [A]","Always autoscale"   );
620 
621    OPT_MENU_PULLRIGHT(opt_mat_menu,opt_mat_cbut      ,"Matrix"  , "Change number of graphs"   ) ;
622    OPT_MENU_PULL_BUT( opt_mat_menu,opt_mat_down_pb   ,"Down [m]", "Reduce number of graphs"   ) ;
623    OPT_MENU_PULL_BUT( opt_mat_menu,opt_mat_up_pb     ,"Up   [M]", "Increase number of graphs" ) ;
624 #ifdef USE_OPTMENUS
625    OPT_MENU_OPTMENU( opt_mat_menu,opt_mat_choose_av , "# " , GRA_mat_choose_CB , "Set number of graphs" ) ;
626 #else
627    OPT_MENU_PULL_BUT( opt_mat_menu,opt_mat_choose_pb ,"Choose" , "Set number of graphs" ) ;
628 #endif
629 
630    OPT_MENU_PULLRIGHT(opt_grid_menu,opt_grid_cbut     ,"Grid"    , "Change vertical grid spacing" ) ;
631    OPT_MENU_PULL_BUT( opt_grid_menu,opt_grid_down_pb  ,"Down [g]", "Reduce vertical grid spacing" ) ;
632    OPT_MENU_PULL_BUT( opt_grid_menu,opt_grid_up_pb    ,"Up   [G]", "Increase vertical grid spacing" ) ;
633    OPT_MENU_PULL_BUT( opt_grid_menu,opt_grid_auto_pb  ,"AutoGrid", "Set grid spacing automatically" ) ;
634    OPT_MENU_PULL_BUT( opt_grid_menu,opt_grid_choose_pb,"Choose"  , "Set vertical grid spacing" ) ;
635    OPT_MENU_PULL_BUT( opt_grid_menu,opt_grid_HorZ_pb  ,"HorZ [h]", "Horizontal line at Zero" ) ; /* 05 Jan 1999 */
636 
637    OPT_MENU_PULLRIGHT(opt_slice_menu,opt_slice_cbut      ,"Slice"   , "Change slice"  ) ;
638    OPT_MENU_PULL_BUT( opt_slice_menu,opt_slice_down_pb   ,"Down [z]", "Decrement slice" ) ;
639    OPT_MENU_PULL_BUT( opt_slice_menu,opt_slice_up_pb     ,"Up   [Z]", "Increment slice" ) ;
640 #ifdef USE_OPTMENUS
641    OPT_MENU_OPTMENU( opt_slice_menu,opt_slice_choose_av , "# " , GRA_slice_choose_CB , "Set slice" ) ;
642 #else
643    OPT_MENU_PULL_BUT( opt_slice_menu,opt_slice_choose_pb ,"Choose" , "Set slice" ) ;
644 #endif
645 
646    /***** 16 June 1997: Colors submenu *****/
647 
648    { static char *bbox_label[1] = { "Use Thick Lines" } ;
649      static char *pts_label[6]  = { "Graph Points"   ,
650                                     "Points+Lines"   ,
651                                     "Boxes     [B]"  ,
652                                     "Box+LabelUp"    ,
653                                     "Box+LabelTop"   ,
654                                     "Box+LabelDown"   } ;
655      char     toplabel[64] ;
656      XmString xstr ;
657 
658      OPT_MENU_PULLRIGHT(opt_colors_menu,opt_colors_cbut,"Colors, Etc.","Change graph appearance");
659 
660      if( strlen(grapher->status->namecode) > 0 ){
661 
662         sprintf( toplabel , "--- %s ---" , grapher->status->namecode ) ;
663         xstr = XmStringCreateLtoR( toplabel , XmFONTLIST_DEFAULT_TAG ) ;
664 
665 #ifdef USING_LESSTIF
666 
667                /* Using  xmLabelWidgetClass causes X11 to hang until
668                afni is terminated. For details, see preceding comment.
669                for another --- Cancel --- button.
670 
671                            LessTif patrol      Jan. 07 09  */
672         (void) XtVaCreateManagedWidget(
673                  "dialog" , xmPushButtonWidgetClass , grapher->opt_colors_menu ,
674                     XmNlabelString , xstr ,
675                     XmNrecomputeSize , False ,
676                     XmNinitialResourcesPersistent , False ,
677                  NULL ) ;
678 #else
679         wtemp = XtVaCreateManagedWidget(
680                  "dialog" , xmLabelWidgetClass , grapher->opt_colors_menu ,
681                     XmNlabelString , xstr ,
682                     XmNrecomputeSize , False ,
683                     XmNinitialResourcesPersistent , False ,
684                  NULL ) ; LABELIZE(wtemp) ;
685 #endif
686         XmStringFree( xstr ) ;
687 
688         MENU_DLINE(opt_colors_menu) ;
689      }
690 
691      if( gr_setup_default ){
692         gr_color_default[0] = INIT_GR_boxes_color  ;
693         gr_color_default[1] = INIT_GR_backg_color  ;
694         gr_color_default[2] = INIT_GR_grid_color   ;
695         gr_color_default[3] = INIT_GR_text_color   ;
696         gr_color_default[4] = INIT_GR_data_color   ;
697         gr_color_default[5] = INIT_GR_ideal_color  ;
698         gr_color_default[6] = INIT_GR_ort_color    ;
699         gr_color_default[7] = INIT_GR_ignore_color ;
700         gr_color_default[8] = INIT_GR_dplot_color  ;
701         gr_color_default[9] = INIT_GR_pmplot_color ;
702 
703         gr_thick_default[0] = INIT_GR_boxes_thick  ;
704         gr_thick_default[1] = -1 ;
705         gr_thick_default[2] = INIT_GR_grid_thick   ;
706         gr_thick_default[3] = -1 ;
707         gr_thick_default[4] = INIT_GR_data_thick   ;
708         gr_thick_default[5] = INIT_GR_ideal_thick  ;
709         gr_thick_default[6] = INIT_GR_ort_thick    ;
710         gr_thick_default[7] = -1 ;
711         gr_thick_default[8] = INIT_GR_dplot_thick  ;
712         gr_thick_default[9] = INIT_GR_pmplot_thick ;
713 
714         gr_setup_default = 0 ;
715      }
716 
717      grapher->fixed_colors_setting = 0 ;  /* 16 Apr 2019 */
718 
719      for( ii=0 ; ii < NUM_COLOR_ITEMS ; ii++ ){
720 
721         grapher->color_index[ii] = GRA_COLOR(gr_color_default[ii]) ;
722         grapher->thick_index[ii] = gr_thick_default[ii] ;
723         grapher->points_index[ii]= gr_points_default[ii] ;  /* 09 Jan 1998 */
724 
725         grapher->opt_color_av[ii] =
726            new_MCW_colormenu( grapher->opt_colors_menu ,
727                               gr_color_label[ii] ,
728                               grapher->dc ,
729                               gr_color_start[ii] , grapher->dc->ovc->ncol_ov-1,
730                               grapher->color_index[ii] ,
731                               GRA_color_CB , (XtPointer) grapher ) ;
732         MCW_reghint_children( grapher->opt_color_av[ii]->wrowcol ,
733                               gr_color_hint[ii] ) ;           /* 28 Jan 2004 */
734 
735         if( grapher->thick_index[ii] >= 0 ){
736            grapher->opt_thick_bbox[ii] =
737               new_MCW_bbox( grapher->opt_colors_menu ,
738                             1 , bbox_label , MCW_BB_check , MCW_BB_noframe ,
739                             GRA_thick_CB , (XtPointer) grapher ) ;
740            MCW_reghint_children( grapher->opt_thick_bbox[ii]->wrowcol ,
741                                  "Draw these lines thicker" ) ;
742 
743            if( grapher->thick_index[ii] )
744               MCW_set_bbox( grapher->opt_thick_bbox[ii] , 1 ) ;
745         } else {
746            grapher->opt_thick_bbox[ii] = NULL ;
747         }
748 
749         /* 09 Jan 1998: add option to draw only points in graphs */
750         /* 01 Aug 1998: allow points+lines to be drawn as well   */
751 
752         if( grapher->points_index[ii] >= 0 && ii != PMPLOT_INDEX ){
753            int nbut = (ii==4) ? 6 : 2 ;
754            grapher->opt_points_bbox[ii] =
755               new_MCW_bbox( grapher->opt_colors_menu ,
756                             nbut , pts_label , MCW_BB_radio_zero , MCW_BB_noframe ,
757                             GRA_thick_CB , (XtPointer) grapher ) ;
758            MCW_reghint_children(  grapher->opt_points_bbox[ii]->wrowcol ,
759                                   "How to plot graph data" ) ;
760 
761            if( grapher->points_index[ii] )
762               MCW_set_bbox( grapher->opt_points_bbox[ii] ,
763                             1 << (grapher->points_index[ii]-1) ) ;
764         } else {
765            grapher->opt_points_bbox[ii] = NULL ;
766         }
767 
768         /* 01 Jun 2020: special case for PMPLOT */
769 
770         if( ii == PMPLOT_INDEX ){
771           static char *pm_label[4] = { "Off" , "Curves" , "Bars" , "Fill" } ;
772           grapher->opt_points_bbox[ii] =
773              new_MCW_bbox( grapher->opt_colors_menu ,
774                            4 , pm_label , MCW_BB_radio_one , MCW_BB_noframe ,
775                            GRA_thick_CB , (XtPointer) grapher ) ;
776            MCW_reghint_children(  grapher->opt_points_bbox[ii]->wrowcol ,
777                                   "If & How to plot Dplot as Plus/Minus" ) ;
778            MCW_set_bbox( grapher->opt_points_bbox[ii] , 1 ) ; /* Off */
779            grapher->points_index[ii] = 0 ;
780         }
781 
782         MENU_DLINE( opt_colors_menu ) ;
783      }
784 
785      /* 12 Jan 1998: control gap between graphs */
786 
787      grapher->opt_ggap_av =
788         new_MCW_optmenu( grapher->opt_colors_menu , "Graph Gap" ,
789                          0 , 19 , INIT_GR_ggap , 0 ,
790                          GRA_ggap_CB , (XtPointer) grapher , NULL , NULL ) ;
791      AVOPT_columnize( grapher->opt_ggap_av , 4 ) ;
792      MCW_reghint_children( grapher->opt_ggap_av->wrowcol ,
793                            "Space sub-graphs apart" ) ;
794 
795      /* 06 Oct 2004: control 'thick' line size */
796 
797      grapher->opt_gthick_av =
798         new_MCW_optmenu( grapher->opt_colors_menu , "'Thick'  " ,
799                          2 , 10 , INIT_GR_gthick , 0 ,
800                          GRA_gthick_CB , (XtPointer) grapher , NULL , NULL ) ;
801      AVOPT_columnize( grapher->opt_gthick_av , 2 ) ;
802      MCW_reghint_children( grapher->opt_gthick_av->wrowcol ,
803                            "Width of 'Thick' lines" ) ;
804 
805      /* 28 May 2020: control upsampling for smoother curves */
806 
807      { static char *strlist[2] = { "No" , "Yes" } ;
808        grapher->opt_upsam_av =
809          new_MCW_optmenu( grapher->opt_colors_menu , "Smooth?  " ,
810                           0 , 1 , 0 , 0 ,
811                           GRA_upsam_CB , (XtPointer)grapher ,
812                           MCW_av_substring_CB , strlist ) ;
813        AVOPT_columnize( grapher->opt_gthick_av , 2 ) ;
814        MCW_reghint_children( grapher->opt_upsam_av->wrowcol ,
815                              "Draw smoother curves?" ) ;
816        grapher->do_upsam = 0 ;
817      }
818 
819    }
820    /***** end colors submenu creation *****/
821 
822 #if 0
823    OPT_MENU_BUT(opt_color_up_pb     ,"Grid Color   [r]" , "Rotate grid color" ) ;
824 #endif
825 
826    /*-- 07 Aug 2001: Baseline sub-menu creation --*/
827 
828    { char * bbox_label[3] = { "Individual [b]" ,
829                               "Common     [b]" ,
830                               "Global     [b]" } ;
831      XmString xstr ;
832      char gbuf[32] ;  /* 08 Mar 2002 */
833 
834      /* 08 Mar 2002: set baseline parameters from environment variables */
835 
836      cpt = getenv( "AFNI_GRAPH_GLOBALBASE" ) ;
837      if( cpt != NULL )
838        grapher->global_base = strtod( cpt , NULL ) ;
839      else
840        grapher->global_base = 0.0 ;
841 
842      cpt = getenv( "AFNI_GRAPH_BASELINE" ) ;
843      if( cpt != NULL ){
844        switch( *cpt ){
845          default:  grapher->common_base = BASELINE_INDIVIDUAL ; break ;
846 
847          case 'C':
848          case 'c': grapher->common_base = BASELINE_COMMON     ; break ;
849 
850          case 'G':
851          case 'g': grapher->common_base = BASELINE_GLOBAL     ; break ;
852        }
853      } else {
854        grapher->common_base = BASELINE_INDIVIDUAL ;
855      }
856 
857      /*- now create menu items -*/
858 
859      OPT_MENU_PULLRIGHT(opt_baseline_menu,opt_baseline_cbut,
860                         "Baseline","Change sub-graphs baseline");
861 
862      grapher->opt_baseline_bbox =
863          new_MCW_bbox( grapher->opt_baseline_menu ,
864                        3 , bbox_label , MCW_BB_radio_one , MCW_BB_noframe ,
865                        GRA_baseline_CB , (XtPointer)grapher ) ;
866      MCW_set_bbox( grapher->opt_baseline_bbox , grapher->common_base ) ;
867 
868      MCW_reghint_children( grapher->opt_baseline_bbox->wrowcol ,
869                           "Graph baseline methods" ) ;
870 
871      MENU_SLINE( opt_baseline_menu ) ;
872 
873      OPT_MENU_PULL_BUT( opt_baseline_menu,opt_baseline_setglobal_pb ,
874                         "Set Global" , "Global baseline level" ) ;
875 
876      MENU_SLINE( opt_baseline_menu ) ;
877 
878      strcpy(gbuf,"Global:") ;
879      AV_fval_to_char(grapher->global_base,gbuf+7) ;
880      xstr = XmStringCreateLtoR(gbuf,XmFONTLIST_DEFAULT_TAG) ;
881      grapher->opt_baseline_global_label =
882         XtVaCreateManagedWidget(
883                  "dialog" , xmLabelWidgetClass , grapher->opt_baseline_menu ,
884                     XmNlabelString , xstr ,
885                     XmNrecomputeSize , False ,
886                     XmNtraversalOn , True  ,
887                     XmNinitialResourcesPersistent , False ,
888                  NULL ) ;
889      XmStringFree( xstr ) ; LABELIZE(grapher->opt_baseline_global_label) ;
890    }
891 
892    /*----- 22 Sep 2000: Text toggle -----*/
893 
894    { static char *bbox_label[1] = { "Show Text?   [t]" } ;
895 
896     grapher->opt_textgraph_bbox =
897          new_MCW_bbox( grapher->opt_menu ,
898                        1 , bbox_label , MCW_BB_check , MCW_BB_noframe ,
899                        GRA_textgraph_CB , (XtPointer)grapher ) ;
900 
901     MCW_reghint_children( grapher->opt_textgraph_bbox->wrowcol ,
902                           "Display text, not graphs" ) ;
903 
904     grapher->textgraph = 0 ;
905    }
906 
907    /*----- Mar 2013: thresh fade toggle -----*/
908 
909    { static char *bbox_label[1] = { "Thresh Fade? [F]" } ;
910 
911     grapher->opt_tfade_bbox =
912          new_MCW_bbox( grapher->opt_menu ,
913                        1 , bbox_label , MCW_BB_check , MCW_BB_noframe ,
914                        GRA_tfade_CB , (XtPointer)grapher ) ;
915 
916     MCW_set_bbox( grapher->opt_tfade_bbox , grapher->thresh_fade ) ;
917 
918     MCW_reghint_children( grapher->opt_tfade_bbox->wrowcol ,
919                           "Fade out below-threshold voxel sub-graphs" ) ;
920    }
921 
922    MENU_SLINE(opt_menu) ;
923    OPT_MENU_BUT(opt_save_pb         ,"Save Image   [S]" , "Save graph as an image" ) ;
924 
925    MENU_SLINE(opt_menu) ;
926    OPT_MENU_BUT(opt_write_center_pb ,"Write Center [w]" , "Write central graph as a *.1D file" ) ;
927    OPT_MENU_BUT(opt_write_suffix_pb ,"Set 'w' Suffix"   , "Set suffix for graph writing" ) ;
928 
929    /*-------------------------------------------*/
930    /*--- Arrowval to list 0D transformations ---*/
931    /*-------------------------------------------*/
932 
933 #define COLSIZE AV_colsize()
934 
935    if( grapher->status->transforms0D != NULL &&
936        grapher->status->transforms0D->num > 0  ){  /* 22 Oct 1996 */
937 
938       MENU_DLINE(opt_menu) ;
939 
940       grapher->transform0D_av =
941          new_MCW_optmenu( grapher->opt_menu ,
942                           "Tran 0D" ,
943                           0 , grapher->status->transforms0D->num , 0 , 0 ,
944                           GRA_transform_CB , (XtPointer) grapher ,
945                           GRA_transform_label , (XtPointer) grapher->status->transforms0D ) ;
946 
947       if( grapher->status->transforms0D->num >= COLSIZE )
948          AVOPT_columnize( grapher->transform0D_av ,
949                           (grapher->status->transforms0D->num/COLSIZE)+1 ) ;
950 
951       MCW_reghint_children( grapher->transform0D_av->wrowcol ,
952                             "Pointwise data transformations" ) ;
953 
954    } else {
955       grapher->transform0D_av = NULL ;
956    }
957    grapher->transform0D_func  = NULL ;  /* no function to start with */
958    grapher->transform0D_index = 0 ;
959 
960    /*-------------------------------------------*/
961    /*--- Arrowval to list 1D transformations ---*/
962    /*-------------------------------------------*/
963 
964    if( grapher->status->transforms1D != NULL &&
965        grapher->status->transforms1D->num > 0  ){  /* 03 Nov 1996 */
966 
967       MENU_DLINE(opt_menu) ;
968 
969       grapher->transform1D_av =
970          new_MCW_optmenu( grapher->opt_menu ,
971                           "Tran 1D" ,
972                           0 , grapher->status->transforms1D->num , 0 , 0 ,
973                           GRA_transform_CB , (XtPointer) grapher ,
974                           GRA_transform_label ,
975                           (XtPointer) grapher->status->transforms1D ) ;
976 
977       /* force the optmenu to call us even if the same button is chosen twice */
978       grapher->transform1D_av->optmenu_call_if_unchanged = 1 ;  /* 10 Oct 2007 */
979 
980       if( grapher->status->transforms1D->num >= COLSIZE )
981          AVOPT_columnize( grapher->transform1D_av ,
982                           (grapher->status->transforms1D->num/COLSIZE)+1 ) ;
983 
984       MCW_reghint_children( grapher->transform1D_av->wrowcol ,
985                             "Time series transformations" ) ;
986 
987       /* 08 Nov 1996: dplot = double plot */
988 
989       { char *bbox_label[2] = { "DPlot Off" , "Dplot On" } ;
990 
991         OPT_MENU_PULLRIGHT(opt_dplot_menu,opt_dplot_cbut,
992                            "Double Plot","Graph Dataset and Tran 1D?");
993 
994         grapher->opt_dplot_bbox =
995             new_MCW_bbox( grapher->opt_dplot_menu ,
996                           2 , bbox_label , MCW_BB_radio_one , MCW_BB_noframe ,
997                           GRA_dplot_change_CB , (XtPointer)grapher ) ;
998         MCW_set_bbox( grapher->opt_dplot_bbox , DPLOT_OFF ) ;
999 
1000         MCW_reghint_children( grapher->opt_dplot_bbox->wrowcol ,
1001                               "Show 'Double Plot' graphs?" ) ;
1002       }
1003 
1004    } else {
1005       grapher->transform1D_av = NULL ;
1006       grapher->opt_dplot_bbox = NULL ;
1007    }
1008    grapher->transform1D_func  = NULL ;  /* no function to start with */
1009    grapher->transform1D_index = 0 ;
1010 
1011    /*------ optmenu for Polort [05 Dec 2012] ------*/
1012 
1013    MENU_DLINE(opt_menu) ;
1014 
1015    grapher->detrend_av =
1016          new_MCW_optmenu( grapher->opt_menu ,
1017                           "Detrend" ,
1018                           -1 , GRA_MAX_DETREND , -1 , 0 ,
1019                           GRA_detrend_CB , (XtPointer)grapher ,
1020                           NULL , NULL ) ;
1021 
1022    MCW_reghint_children( grapher->detrend_av->wrowcol ,
1023                          "Order of time series L1 detrending / baseline removal" ) ;
1024 
1025    /*------ menu to control the x-axis drawing (09 Jan 1998) ------*/
1026 
1027    MENU_DLINE(opt_menu) ;
1028 
1029    OPT_MENU_PULLRIGHT( opt_xaxis_menu , opt_xaxis_cbut    , "X-axis" , "Alter x-axis" ) ;
1030    OPT_MENU_PULL_BUT(  opt_xaxis_menu , opt_xaxis_pick_pb ,
1031                        "X-axis=1D file" , "Set timeseries for x-axis" ) ;
1032 #ifdef BE_AFNI_AWARE
1033    OPT_MENU_PULL_BUT(  opt_xaxis_menu , opt_xaxis_dset_pb ,
1034                        "X-axis=dataset" , "Set timeseries for x-axis" ) ;
1035 #else
1036    opt_xaxis_dset_pb = NULL ;
1037 #endif
1038    OPT_MENU_PULL_BUT(  opt_xaxis_menu , opt_xaxis_center_pb ,
1039                        "X-axis=center" , "X-axis = center voxel" ) ;
1040    OPT_MENU_PULL_BUT(  opt_xaxis_menu , opt_xaxis_clear_pb ,
1041                        "Clear X-axis" , "Clear X-axis timeseries" ) ;
1042 
1043    /*------ last button on this menu ------*/
1044 
1045    MENU_DLINE(opt_menu) ;
1046    OPT_MENU_BUT(opt_quit_pb         ,"Done         [q]" , "Close window" ) ;
1047    MCW_set_widget_bg( grapher->opt_quit_pb ,
1048                       MCW_hotcolor(grapher->opt_quit_pb) , 0 ) ;
1049 
1050    /** done with option buttons -- manage the manager widget **/
1051 
1052    XtManageChild( grapher->option_rowcol ) ;
1053 
1054 #if 0
1055    allow_MCW_optmenu_popup( 1 ) ;  /* 12 Dec 2001 */
1056 #endif
1057 
1058    /** initialize the internal parameters **/
1059 
1060 if(PRINT_TRACING)
1061  { char str[128] ;
1062    sprintf(str,"STATUS: num_series=%d nx=%d ny=%d",
1063            grapher->status->num_series,grapher->status->nx,grapher->status->ny ) ;
1064    STATUS(str) ; }
1065 
1066    grapher->fscale      =  0 ;
1067    grapher->mat         =  0 ;
1068    grapher->xpoint      = -1 ;
1069    grapher->ypoint      = -1 ;
1070    grapher->zpoint      = -1 ;
1071 #if 0
1072    grapher->grid_color  = GRID_COLOR(grapher) ;
1073 #endif
1074    grapher->grid_index  = -1 ;
1075    grapher->grid_fixed  =  0 ;  /* 02 Apr 2004 */
1076    grapher->key_Nlock   =  0 ;
1077    grapher->xFD         =  0 ;
1078    grapher->yFD         =  0 ;
1079    grapher->time_index  =  0 ;
1080    grapher->pin_top     =  0 ;  /* 27 Apr 1997 */
1081    grapher->pin_bot     =  0 ;  /* 17 Mar 2004 */
1082    grapher->pin_stride  =  1 ;  /* 19 Jul 2013 */
1083    grapher->ggap        =  INIT_GR_ggap ;    /* 12 Jan 1998 + 27 May 1999 */
1084    grapher->gthick      =  INIT_GR_gthick ;  /* 06 Oct 2004 */
1085 
1086    grapher->cen_line    =  NULL ;  /* coords of central graph plot */
1087    grapher->ncen_line   =  0 ;
1088    grapher->nncen       =  0 ;
1089    grapher->cen_tsim    =  NULL ;
1090    grapher->xax_tsim    =  NULL ;  /* 09 Jan 1998 */
1091    grapher->xax_dset    =  NULL ;  /* 09 Feb 2015 */
1092    grapher->xax_fdbr    =  NULL ;
1093    grapher->ave_tsim    =  NULL ;  /* 27 Jan 2004 */
1094    grapher->xax_cen     =  NULL ;  /* 12 Feb 2015 */
1095 
1096    grapher->xx_text_1    =
1097     grapher->xx_text_2   =
1098      grapher->xx_text_2p = grapher->xx_text_3 = grapher->xx_text_igf = 1 ;
1099 
1100    grapher->ref_ts = NULL ;
1101    grapher->ort_ts = NULL ;
1102 
1103    grapher->ref_ts_plotall = grapher->ort_ts_plotall = 1 ;
1104 
1105    init_const( grapher ) ;
1106 
1107    grapher->setshift_inc_av   = NULL ;
1108    grapher->setshift_left_av  = NULL ;
1109    grapher->setshift_right_av = NULL ;
1110    grapher->dialog            = NULL ;
1111    grapher->setshift_inc      = 0.5 ;
1112    grapher->setshift_left     = 0 ;
1113    grapher->setshift_right    = 0 ;
1114 
1115    /** for the present, don't realize widgets (make the user do it later) **/
1116 
1117    XtManageChild( form_tmp ) ;  /* 29 Sep 2000 */
1118 
1119 #if 0
1120 STATUS("realizing widgets") ;
1121    XtRealizeWidget( grapher->fdw_graph ) ;
1122    WAIT_for_window(grapher->form_tmp) ;
1123 
1124    XtVaSetValues( grapher->option_rowcol ,
1125                     XmNleftAttachment   , XmATTACH_NONE ,
1126                     XmNtopAttachment    , XmATTACH_NONE ,
1127                     XmNrightAttachment  , XmATTACH_FORM ,
1128                     XmNbottomAttachment , XmATTACH_FORM ,
1129                   NULL ) ;
1130    XMapRaised( XtDisplay(grapher->option_rowcol) ,
1131                XtWindow(grapher->option_rowcol)   ) ;
1132 
1133    NORMAL_cursorize( grapher->fdw_graph ) ;
1134 
1135    grapher->valid = 2 ;
1136 #ifdef USE_OPTMENUS
1137    GRA_fix_optmenus( grapher ) ;
1138 #endif
1139 #endif
1140 
1141    grapher->fd_pxWind = (Pixmap) 0 ;
1142 
1143    /*** add callback for the WM_DELETE_WINDOW protocol ***/
1144 
1145    XmAddWMProtocolCallback(
1146         grapher->fdw_graph , XmInternAtom(dc->display,"WM_DELETE_WINDOW",False) ,
1147         end_fd_graph_CB , (XtPointer) grapher ) ;
1148 
1149    RETURN(grapher) ;
1150 }
1151 
1152 /*--------------------------------------------------------------------------*/
1153 /* Get the label for a time point. [18 Apr 2011]
1154 *//*------------------------------------------------------------------------*/
1155 
GRA_getlabel(MCW_grapher * grapher,int index)1156 char * GRA_getlabel( MCW_grapher *grapher , int index )
1157 {
1158    char *lab = NULL ;
1159 
1160    CALL_getser( grapher , index,graCR_getlabel , char * , lab ) ;
1161 
1162    if( lab == NULL || *lab == '\0' ) return NULL ;
1163 #if 0
1164    if( *lab == '?' || *lab == '#'  ) return NULL ;
1165 #endif
1166    return lab ;
1167 }
1168 
1169 /*--------------------------------------------------------------------------*/
1170 /* Get the float-valued time series for graphing.  [18 Apr 2011]
1171 *//*------------------------------------------------------------------------*/
1172 
GRA_getseries(MCW_grapher * grapher,int index)1173 MRI_IMAGE * GRA_getseries( MCW_grapher *grapher , int index )
1174 {
1175    MRI_IMAGE *tsim ;
1176 
1177    CALL_getser( grapher , index,graCR_getseries , MRI_IMAGE *,tsim ) ;
1178 
1179    if( tsim == NULL ) return NULL;
1180    if( tsim->nx < 1 ){ mri_free(tsim); return NULL; }
1181 
1182    MRI_floatscan(tsim) ;  /* 10 Jun 2021 */
1183 
1184    if( tsim->kind == MRI_complex ){
1185      MRI_IMAGE *qim ;
1186      char *eee = my_getenv("AFNI_GRAPH_CX2R") ;
1187      if( eee == NULL ) eee = "A" ;
1188      switch( *eee ){
1189        default:
1190        case 'A':
1191        case 'a':  qim = mri_complex_abs(tsim)  ; break ;
1192 
1193        case 'P':
1194        case 'p':  qim = mri_complex_phase(tsim); break ;
1195 
1196        case 'r':
1197        case 'R':  qim = mri_complex_real(tsim) ; break ;
1198 
1199        case 'i':
1200        case 'I':  qim = mri_complex_imag(tsim) ; break ;
1201      }
1202      qim->flags = tsim->flags ; mri_free(tsim) ; tsim = qim ;
1203 
1204    } else if( tsim->kind != MRI_float ){
1205      MRI_IMAGE *qim = mri_to_float(tsim) ;
1206      qim->flags = tsim->flags ; mri_free(tsim) ; tsim = qim ;
1207    }
1208 
1209    return tsim ;
1210 }
1211 
1212 #ifdef BE_AFNI_AWARE
1213 /*--------------------------------------------------------------------------*/
1214 /* Get the float-valued time series for x-axis graphing.  [10 Feb 2015]
1215 *//*------------------------------------------------------------------------*/
1216 
GRA_getseries_xax(MCW_grapher * grapher,int index)1217 MRI_IMAGE * GRA_getseries_xax( MCW_grapher *grapher , int index )
1218 {
1219    MRI_IMAGE *tsim ; int tf ;
1220 
1221 ENTRY("GRA_getseries_xax") ;
1222 
1223    if( grapher->xax_fdbr == NULL ) RETURN(NULL) ;  /* bad call */
1224 
1225    tsim = FD_brick_to_series( index , grapher->xax_fdbr ) ;
1226 
1227    if( tsim == NULL ) RETURN(NULL) ;
1228 
1229    if( tsim->nx < 1 ){ mri_free(tsim); RETURN(NULL); }
1230 
1231    MRI_floatscan(tsim) ; /* 10 Jun 2021 */
1232 
1233    if( tsim->kind == MRI_complex ){
1234      MRI_IMAGE *qim ;
1235      char *eee = my_getenv("AFNI_GRAPH_CX2R") ;
1236      if( eee == NULL ) eee = "A" ;
1237      switch( *eee ){
1238        default:
1239        case 'A':
1240        case 'a':  qim = mri_complex_abs(tsim)  ; break ;
1241 
1242        case 'P':
1243        case 'p':  qim = mri_complex_phase(tsim); break ;
1244 
1245        case 'r':
1246        case 'R':  qim = mri_complex_real(tsim) ; break ;
1247 
1248        case 'i':
1249        case 'I':  qim = mri_complex_imag(tsim) ; break ;
1250      }
1251      qim->flags = tsim->flags ; mri_free(tsim) ; tsim = qim ;
1252 
1253    } else if( tsim->kind != MRI_float ){
1254      MRI_IMAGE *qim = mri_to_float(tsim) ;
1255      qim->flags = tsim->flags ; mri_free(tsim) ; tsim = qim ;
1256    }
1257 
1258    RETURN(tsim) ;
1259 }
1260 #endif
1261 
1262 /*----------------------------------
1263     Exit button action
1264 ------------------------------------*/
1265 
end_fd_graph_CB(Widget w,XtPointer client_data,XtPointer call_data)1266 void end_fd_graph_CB( Widget w , XtPointer client_data , XtPointer call_data )
1267 {
1268    MCW_grapher *grapher = (MCW_grapher *) client_data ;
1269    int ii ;
1270 
1271 ENTRY("end_fd_graph_CB") ;
1272 
1273    if( ! GRA_VALID(grapher) ) EXRETURN ;
1274 
1275    GRA_timer_stop( grapher ) ;  NI_sleep(1) ; /* 04 Dec 2003 */
1276 
1277    grapher->valid = 0 ;  /* can't do anything with this anymore */
1278 
1279    if( grapher->fd_pxWind != (Pixmap) 0 ){
1280 STATUS("freeing Pixmap") ;
1281      XFreePixmap( grapher->dc->display , grapher->fd_pxWind ) ;
1282    }
1283 
1284 #ifdef USE_OPTMENUS
1285 STATUS("destroying optmenus") ;
1286    FREE_AV(grapher->opt_mat_choose_av) ;
1287    FREE_AV(grapher->opt_slice_choose_av) ;
1288    FREE_AV(grapher->fmenu->fim_ignore_choose_av) ;
1289    FREE_AV(grapher->fmenu->fim_polort_choose_av) ;
1290 #endif
1291 
1292 STATUS("destroying arrowvals") ;
1293    FREE_AV( grapher->setshift_right_av)    ;
1294    FREE_AV( grapher->setshift_left_av)     ;
1295    FREE_AV( grapher->setshift_inc_av)      ;
1296    FREE_AV( grapher->transform0D_av )      ;  /* 22 Oct 1996 */
1297    FREE_AV( grapher->transform1D_av )      ;  /* 03 Nov 1996 */
1298    FREE_AV( grapher->opt_ggap_av )         ;  /* 28 Sep 1998: via Purify */
1299    FREE_AV( grapher->opt_gthick_av )       ;  /* 06 Oct 2004 */
1300    FREE_AV( grapher->opt_upsam_av )        ;  /* 01 Jun 2020 */
1301 
1302    for( ii=0 ; ii < NUM_COLOR_ITEMS ; ii++ )  /* 16 Jun 1997 */
1303      FREE_AV( grapher->opt_color_av[ii] ) ;
1304 
1305 STATUS("destroying fmenu") ;
1306    myXtFree( grapher->fmenu->fim_editref_winaver_bbox );  /* 27 Jan 2004 */
1307    myXtFree( grapher->fmenu->fim_opt_bbox ) ;  /* Jan 1998 */
1308    myXtFree( grapher->fmenu->fimp_opt_bbox );  /* Jan 1998 */
1309    myXtFree( grapher->fmenu->fimp_user_bbox);  /* Feb 2000 */
1310    myXtFree( grapher->fmenu )               ;
1311    myXtFree( grapher->cen_line )            ;
1312 
1313 STATUS("destroying bboxes") ;
1314    myXtFree( grapher->opt_dplot_bbox ) ;         /* 08 Nov 1996 */
1315 
1316    for( ii=0 ; ii < NUM_COLOR_ITEMS ; ii++ ){
1317      myXtFree( grapher->opt_thick_bbox[ii] ) ;   /* 16 Jun 1997 */
1318      myXtFree( grapher->opt_points_bbox[ii] ) ;  /* 09 Jan 1998 */
1319    }
1320 
1321    myXtFree( grapher->opt_baseline_bbox ) ;      /* 07 Aug 2001 */
1322    myXtFree( grapher->opt_textgraph_bbox ) ;
1323    myXtFree( grapher->opt_tfade_bbox ) ;
1324 
1325 STATUS("freeing cen_tsim") ;
1326    mri_free( grapher->cen_tsim ) ;
1327    mri_free( grapher->xax_tsim ) ;  /* 09 Jan 1998 */
1328    mri_free( grapher->ave_tsim ) ;  /* 27 Jan 2004 */
1329    mri_free( grapher->xax_cen  ) ;  /* 12 Feb 2015 */
1330    grapher->xax_dset = NULL ;       /* 09 Feb 2015 */
1331    DESTROY_FD_BRICK(grapher->xax_fdbr) ; grapher->xax_fdbr = NULL ;
1332 
1333 STATUS("freeing tuser") ;
1334    GRA_CLEAR_tuser( grapher ) ;  /* 22 Apr 1997 */
1335 
1336    /* 31 Mar 2004:
1337       On the Mac, destroying widgets after the timeseries
1338       chooser is opened causes death for unknown reasons.
1339       So in that case, just hide them.  What the ....?    */
1340 
1341 STATUS("destroying widgets") ;
1342 #ifdef DARWIN
1343    if( grapher->tschosen ) XtUnrealizeWidget( grapher->fdw_graph ) ;
1344    else                    XtDestroyWidget  ( grapher->fdw_graph ) ;
1345 #else
1346    XtUnrealizeWidget( grapher->fdw_graph ) ;
1347 #endif
1348 STATUS("widgets now destroyed") ; NI_sleep(1) ;
1349 
1350    /** if AFNI has a notify callback, it will free the data **/
1351 
1352    if( grapher->status->send_CB != NULL ){
1353       GRA_cbs cbs ;
1354       cbs.reason = graCR_destroy ;
1355 STATUS("calling AFNI") ;
1356 #if 0
1357       grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
1358 #else
1359       CALL_sendback( grapher , cbs ) ;
1360 #endif
1361    } else {
1362 STATUS("freeing grapher") ;
1363       myXtFree( grapher ) ;    /* otherwise, we will free the data */
1364    }
1365 
1366    EXRETURN ;
1367 }
1368 
1369 /*----------------------------------
1370    Erase pixmap to background color
1371 ------------------------------------*/
1372 
erase_fdw(MCW_grapher * grapher)1373 void erase_fdw( MCW_grapher *grapher )
1374 {
1375 ENTRY("erase_fdw") ;
1376 
1377    if( grapher->dont_redraw ) EXRETURN ;  /* 27 Jan 2004 */
1378 
1379    DC_fg_color ( grapher->dc , BG_COLOR(grapher) ) ;
1380    DC_linewidth( grapher->dc , 0 ) ;
1381 
1382    XFillRectangle( grapher->dc->display ,
1383                    grapher->fd_pxWind , grapher->dc->myGC ,
1384                    0 , 0 , grapher->fWIDE , grapher->fHIGH ) ;
1385 
1386    if( show_grapher_pixmap &&
1387        grapher->glogo_pixmap != XmUNSPECIFIED_PIXMAP &&
1388        grapher->glogo_height > 0 && grapher->glogo_width > 0 ){
1389 
1390       XCopyArea( grapher->dc->display ,
1391                  grapher->glogo_pixmap , grapher->fd_pxWind , grapher->dc->myGC ,
1392                  0,0 , grapher->glogo_width,grapher->glogo_height ,
1393                  0,grapher->fHIGH - grapher->glogo_height + 1 ) ;
1394    }
1395 
1396    EXRETURN ;
1397 }
1398 
1399 /*-----------------------------------------------------*/
1400 
rectangle_fdX(MCW_grapher * grapher,int xb,int yb,int xw,int yw,int clr)1401 void rectangle_fdX( MCW_grapher *grapher, int xb,int yb, int xw,int yw, int clr )
1402 {
1403 ENTRY("rectangle_fdX") ;
1404 
1405    if( grapher->dont_redraw ) EXRETURN ;
1406 
1407    if( xw <= 0 || yw <= 0 ) EXRETURN ;
1408 
1409    if( xb < 0 ) xb = 0 ;
1410    if( yb < 0 ) yb = 0 ;
1411    yb = grapher->fHIGH - yb - yw ;
1412 
1413    DC_fg_color ( grapher->dc , clr ) ;  /* changing color in myGC */
1414 
1415    XFillRectangle( grapher->dc->display ,
1416                    grapher->fd_pxWind , grapher->dc->myGC , xb,yb , xw,yw ) ;
1417 
1418    EXRETURN ;
1419 }
1420 
1421 /*-----------------------------------------------------*/
1422    /* It plots line to point (x,y) for mod = 1 */
1423    /* or moves to this point for mod = 0.      */
1424    /* All into the fd_pxWind.                  */
1425 /*-----------------------------------------------------*/
1426 
plot_fdX(MCW_grapher * grapher,int x,int y,int mod)1427 void plot_fdX( MCW_grapher *grapher , int x , int y , int mod )
1428 {
1429    int iy = grapher->fHIGH - y ;
1430 
1431    if( mod > 0 )
1432      XDrawLine( grapher->dc->display ,
1433                 grapher->fd_pxWind , grapher->dc->myGC ,
1434                 grapher->xFD , grapher->yFD , x , iy ) ;
1435 
1436    grapher->xFD = x ; grapher->yFD = iy ;
1437    return ;
1438 }
1439 
1440 /* ----------------------------------- */
1441 /* Reload pixmap fd_pxWind to FDWindow */
1442 /* ----------------------------------- */
1443 
fd_px_store(MCW_grapher * grapher)1444 void fd_px_store( MCW_grapher * grapher )
1445 {
1446 ENTRY("fd_px_store") ;
1447 
1448    if( ! MCW_widget_visible(grapher->draw_fd) ) EXRETURN ;  /* 03 Jan 1999 */
1449 
1450    XtVaSetValues( grapher->draw_fd ,
1451                      XmNbackgroundPixmap , grapher->fd_pxWind ,
1452                   NULL ) ;
1453 
1454    XClearWindow( grapher->dc->display , XtWindow(grapher->draw_fd) ) ;
1455    XFlush( grapher->dc->display ) ;
1456    EXRETURN ;
1457 }
1458 
1459 /*--------------------------------------------------------------
1460   draw a small circle somewhere:
1461     xwin,ywin = Window coordinates of center
1462     filled    = 1 or 0, if you want the circle solid or not
1463                 14 Jan 1998: 2 if for points on a filled circle
1464 ----------------------------------------------------------------*/
1465 
1466 #define NCIR 12  /* number of points for hollow circle */
1467 #define NBAL 21  /* number of points for filled circle */
1468 #define NBAX 25  /* number of points for with points   */
1469 
1470 #define NBTOP NBAX  /* max # of points */
1471 
1472 static XPoint xball[] = {
1473       {-1,-2},{ 0,-2},{ 1,-2},
1474       { 2,-1},{ 2, 0},{ 2, 1},
1475       { 1, 2},{ 0, 2},{-1, 2},
1476       {-2, 1},{-2, 0},{-2,-1},  /* NCIR ends here */
1477       {-1,-1},{-1, 0},{-1, 1},
1478       { 0,-1},{ 0, 0},{ 0, 1},
1479       { 1,-1},{ 1, 0},{ 1, 1},  /* NBAL ends here */
1480       { 0,-3},{ 0, 3},{ 3, 0},
1481       {-3, 0}                   /* NBAX ends here */
1482  } ;
1483 
1484 /*------------------ draw into Pixmap (the graph itself) -----------------------*/
1485 
GRA_small_circle(MCW_grapher * grapher,int xwin,int ywin,int filled)1486 void GRA_small_circle( MCW_grapher *grapher, int xwin, int ywin, int filled )
1487 {
1488    int  i, ncirc ;
1489    XPoint a[NBTOP] ;
1490 
1491    switch( filled ){
1492       default: ncirc = NCIR ; break ;
1493       case 1:  ncirc = NBAL ; break ;
1494       case 2:  ncirc = NBAX ; break ;
1495    }
1496 
1497    for( i=0 ; i < ncirc ; i++ ){    /* fill pixel coords */
1498       a[i].x = xball[i].x + xwin ;
1499       a[i].y = xball[i].y + ywin ;
1500    }
1501 
1502    /* just draws pixels */
1503    XDrawPoints( grapher->dc->display, grapher->fd_pxWind,
1504                 grapher->dc->myGC, a, ncirc, CoordModeOrigin ) ;
1505    return ;
1506 }
1507 
1508 /*------------------ draw into window (the graph overlay) -----------------------*/
1509 
GRA_overlay_circle(MCW_grapher * grapher,int xwin,int ywin,int filled)1510 void GRA_overlay_circle( MCW_grapher *grapher, int xwin, int ywin, int filled )
1511 {
1512    int  i, ncirc ;
1513    XPoint a[NBTOP] ;
1514 
1515    switch( filled ){
1516       default: ncirc = NCIR ; break ;
1517       case 1:  ncirc = NBAL ; break ;
1518       case 2:  ncirc = NBAX ; break ;
1519    }
1520 
1521    for( i=0 ; i < ncirc ; i++ ){
1522       a[i].x = xball[i].x + xwin ;
1523       a[i].y = xball[i].y + ywin ;
1524    }
1525 
1526    DC_linewidth( grapher->dc, 0 ) ;
1527 
1528    XDrawPoints( grapher->dc->display, XtWindow(grapher->draw_fd),
1529                 grapher->dc->myGC, a, ncirc, CoordModeOrigin ) ;
1530    return ;
1531 }
1532 
1533 /*---------------------------------------------------------------------------*/
1534 /* Draw a complete circle using the XDrawArc function
1535    (where the angle of the arc is specified in units of degrees/64)
1536 *//*-------------------------------------------------------------------------*/
1537 
GRA_draw_circle(MCW_grapher * grapher,int xc,int yc,int rad)1538 void GRA_draw_circle( MCW_grapher *grapher , int xc , int yc , int rad )
1539 {
1540    int xb,yb ;
1541    unsigned int ww ;
1542 
1543    if( rad < 0 ) rad = 0 ;
1544    xb = xc-rad ; yb = yc-rad ; ww = 2*rad ;
1545    XDrawArc( grapher->dc->display , XtWindow(grapher->draw_fd) ,
1546              grapher->dc->myGC , xb,yb , ww,ww , 0,360*64 ) ;
1547    return ;
1548 }
1549 
1550 /*---------------------------------------------------------------------------*/
1551 /* Same thing, but a filled circle = a disk */
1552 
GRA_draw_disk(MCW_grapher * grapher,int xc,int yc,int rad)1553 void GRA_draw_disk( MCW_grapher *grapher , int xc , int yc , int rad )
1554 {
1555    int xb,yb ;
1556    unsigned int ww ;
1557 
1558    if( rad < 0 ) rad = 0 ;
1559    xb = xc-rad ; yb = yc-rad ; ww = 2*rad ;
1560    XFillArc( grapher->dc->display , grapher->fd_pxWind ,
1561              grapher->dc->myGC , xb,yb , ww,ww , 0,360*64 ) ;
1562    return ;
1563 }
1564 
1565 /*-----------------------------------------------
1566    redraw stuff that overlays the pixmap
1567 -------------------------------------------------*/
1568 
1569 #define SHORT_NAME_WIDTH 384
1570 
1571 static char *long_index_name  = "indx=" ;
1572 static char *short_index_name = "#"     ;
1573 static char *long_value_name  = " val=" ;
1574 static char *short_value_name = "="     ;
1575 static char *long_time_name   = " @t="  ;
1576 static char *short_time_name  = "@"     ;
1577 static char *long_xax_name    = " @x="  ;
1578 static char *short_xax_name   = "@"     ;
1579 
GRA_redraw_overlay(MCW_grapher * grapher)1580 void GRA_redraw_overlay( MCW_grapher *grapher )
1581 {
1582    Window   win ;
1583    Display *dis ;
1584    int      ii , xxx , jj , boff ;
1585    float    val ;
1586    char buf[16] , strp[256] ;
1587    char *vbuf , *iname , *vname ;
1588 
1589 ENTRY("GRA_redraw_overlay") ;
1590 
1591    if( ! GRA_REALZ(grapher) ){ STATUS("ILLEGAL CALL") ; EXRETURN ; }
1592 
1593    if( ! MCW_widget_visible(grapher->draw_fd) ) EXRETURN ;  /* 03 Jan 1999 */
1594    if( grapher->dont_redraw ) EXRETURN ;                    /* 27 Jan 2004 */
1595 
1596    /* erase contents of window (that aren't in the pixmap) */
1597 
1598    dis = grapher->dc->display ;
1599    win = XtWindow(grapher->draw_fd) ;
1600    XClearWindow( dis , win ) ;
1601 
1602    EXRONE(grapher) ;  /* 22 Sep 2000 */
1603 
1604    boff = DATA_BOXED(grapher) ? BOXOFF : 0 ;  /* boxes are elevated */
1605 
1606    /* draw some circles over ignored data points [23 May 2005] */
1607 
1608    if( NIGNORE(grapher) > 0 && !grapher->textgraph && NSTRIDE(grapher) == 1 ){
1609      DC_fg_color( grapher->dc , IGNORE_COLOR(grapher) ) ;
1610      jj  = NBOT(grapher) ;                     /* first point to plot */
1611      xxx = NTOP(grapher) ;                     /* last */
1612      xxx = MIN (xxx , NIGNORE(grapher)) ;      /* point */
1613      xxx = MIN (xxx , jj+grapher->nncen) ;     /* to plot */
1614      for( ii=jj ; ii < xxx ; ii++ )
1615        GRA_draw_circle( grapher , grapher->cen_line[ii-jj].x ,
1616                                   grapher->cen_line[ii-jj].y-boff , 4 ) ;
1617    }
1618 
1619    /* 22 July 1996:
1620       draw a ball on the graph at the currently display time_index */
1621 
1622    ii = grapher->time_index ; jj = NBOT(grapher) ;
1623    if( ii >= jj            && NSTRIDE(grapher) == 1  &&
1624        ii <  NTOP(grapher) && ii-jj < grapher->nncen && !grapher->textgraph ){
1625       int ww = MAX(4,DATA_THICK(grapher)) ;
1626 
1627       DC_fg_color( grapher->dc , IDEAL_COLOR(grapher) ) ;
1628       GRA_overlay_circle( grapher , grapher->cen_line[ii-jj].x ,
1629                                     grapher->cen_line[ii-jj].y-boff , 2 ) ;
1630       GRA_draw_circle   ( grapher , grapher->cen_line[ii-jj].x ,
1631                                     grapher->cen_line[ii-jj].y-boff , ww ) ;
1632    }
1633 
1634    /* draw text showing value at currently displayed time_index */
1635 
1636    if( ii >= 0                    && grapher->cen_tsim != NULL &&
1637        ii < grapher->cen_tsim->nx && NSTRIDE(grapher)  == 1      ){
1638       char *ilab=NULL ; MRI_IMAGE *xxim_cen=NULL ;
1639 
1640       val = MRI_FLOAT_PTR(grapher->cen_tsim)[ii] ;
1641       AV_fval_to_char( val , buf ) ;
1642       vbuf = (buf[0]==' ') ? buf+1 : buf ;
1643 
1644       if( grapher->fWIDE < SHORT_NAME_WIDTH ){
1645         iname = short_index_name ; vname = short_value_name ;
1646       } else {
1647         iname = long_index_name ; vname = long_value_name ;
1648         ilab = GRA_getlabel( grapher , ii ) ;
1649       }
1650 
1651       if( ilab == NULL || *ilab == '\0' )
1652         sprintf( strp , "%s%d%s%s" , iname,ii , vname,vbuf ) ;
1653       else
1654         sprintf( strp , "%s%d [%.31s]%s%s",iname,ii,ilab , vname,vbuf ) ;
1655 
1656       xxim_cen = (grapher->xax_cen != NULL) ? grapher->xax_cen : grapher->xax_tsim ;
1657       if( xxim_cen == NULL && grapher->cen_tsim->dx != 0.0 ){
1658         val = grapher->cen_tsim->xo + ii * grapher->cen_tsim->dx ;
1659         AV_fval_to_char( val , buf ) ;
1660         vbuf = (buf[0]==' ') ? buf+1 : buf ;
1661         sprintf( strp+strlen(strp) , "%s%s" ,
1662                  (grapher->fWIDE < SHORT_NAME_WIDTH) ? short_time_name
1663                                                      : long_time_name, vbuf ) ;
1664       } else if( xxim_cen != NULL ){
1665         if( ii >= 0 && ii < xxim_cen->nx ){
1666           val = MRI_FLOAT_PTR(xxim_cen)[ii] ;
1667           AV_fval_to_char( val , buf ) ;
1668           vbuf = (buf[0]==' ') ? buf+1 : buf ;
1669           sprintf( strp+strlen(strp) , "%s%s" ,
1670                    (grapher->fWIDE < SHORT_NAME_WIDTH) ? short_xax_name
1671                                                        : long_xax_name, vbuf ) ;
1672         }
1673       }
1674 
1675       xxx = MAX( grapher->xx_text_2 ,
1676                  grapher->xorigin[grapher->xc][grapher->yc]-39 ) ;
1677 
1678       if( NIGNORE(grapher) > 0 || grapher->thresh_fade ){
1679         xxx = MAX( xxx , grapher->xx_text_2p ) ;
1680         xxx = MAX( xxx , grapher->xx_text_igf ) ; /* this allows for Fading + Ignore together */
1681       }
1682 
1683       DC_fg_color( grapher->dc , IDEAL_COLOR(grapher) ) ;
1684       overlay_txt( grapher, xxx , GB_DLY-15 , strp ) ;
1685    }
1686 
1687    /* no more to do now */
1688 
1689    XFlush( dis ) ;
1690    EXRETURN ;
1691 }
1692 
1693 /*------------------------------------------------------------------
1694    redraw entire graph;
1695    code is a mask of special values:
1696      0                  = default action
1697      PLOTCODE_AUTOSCALE = scale graphs automatically
1698 -------------------------------------------------------------------*/
1699 
redraw_graph(MCW_grapher * grapher,int code)1700 void redraw_graph( MCW_grapher *grapher , int code )
1701 {
1702    int x, y , www,xxx , rrr ;
1703    int xc = grapher->xc , yc = grapher->yc ;
1704    char strp[256] , buf[64] ;
1705    int xd,yd,zd ;
1706 
1707 ENTRY("redraw_graph") ;
1708 
1709    if( ! GRA_REALZ(grapher) ){ STATUS("ILLEGAL ENTRY"); EXRETURN; }
1710    if( grapher->fd_pxWind == (Pixmap) 0 ){ STATUS("ILLEGAL ENTRY"); EXRETURN; }
1711    if( grapher->dont_redraw ) EXRETURN ;  /* 27 Jan 2004 */
1712 
1713    /*---- draw the graphs ----*/
1714 
1715    erase_fdw  ( grapher ) ;
1716    draw_grids ( grapher ) ;
1717 
1718    if (code == 0 && PLOT_FORCE_AUTOSCALE)
1719       code = PLOTCODE_AUTOSCALE; /* Daniel Glen
1720                                     July 14th Allons enfants de la patrie,
1721                                     la guillottine est arrivee! */
1722 
1723    /* this is where all the 'fun' lives */
1724    plot_graphs( grapher , code ) ;
1725 
1726    DC_fg_color( grapher->dc , TEXT_COLOR(grapher) ) ;
1727 
1728    if( TPTS(grapher) < 2 ){             /* 22 Sep 2000 */
1729       fd_txt( grapher , GL_DLX+5, 35,
1730               "Can't draw graphs for this dataset: Num < 2" ) ;
1731       fd_px_store( grapher ) ;
1732       EXRETURN ;
1733    }
1734 
1735    /*---- draw some strings for informative purposes ----*/
1736 
1737    DC_fg_color( grapher->dc , TEXT_COLOR(grapher) ) ;
1738 
1739    /*** y axis labels ***/
1740 
1741    if( !grapher->textgraph ){
1742       AV_fval_to_char( grapher->pmax[xc][yc] , strp ) ;
1743       www = DC_text_width(grapher->dc,strp) ;
1744       xxx = GL_DLX - www - 2 ;
1745       xxx = MAX(0,xxx) ;
1746       fd_txt( grapher , xxx , GB_DLY + grapher->gy_max - MYTXT, strp) ;
1747 
1748       AV_fval_to_char( grapher->pmax[xc][yc] - grapher->pmin[xc][yc] , buf ) ;
1749       if( buf[0] == ' ' ) buf[0] = '+' ;
1750       sprintf( strp , "[%s]" , buf ) ;
1751       www = DC_text_width(grapher->dc,strp) ;
1752       xxx = GL_DLX - www + 2 ;
1753       xxx = MAX(0,xxx) ;
1754       fd_txt( grapher , xxx , GB_DLY + grapher->gy_max - MYTXT - 14 , strp) ;
1755 
1756       AV_fval_to_char( grapher->pmin[xc][yc] , strp ) ;
1757       www = DC_text_width(grapher->dc,strp) ;
1758       xxx = GL_DLX - www - 2 ;
1759       xxx = MAX(0,xxx) ;
1760       fd_txt( grapher , xxx , GB_DLY + 5, strp) ;
1761    }
1762 
1763    /*** bottom of the page coordinates stuff ***/
1764 
1765    /* first column */
1766 
1767    grapher->xx_text_1 = GL_DLX+5 ;
1768 
1769    xd = grapher->xpoint ; yd = grapher->ypoint ; zd = grapher->zpoint ;
1770 #ifndef DONT_MANGLE_XYZ
1771    { THD_ivec3 id ;
1772      id = THD_fdind_to_3dind( grapher->getaux , TEMP_IVEC3(xd,yd,zd) ) ;
1773      xd = id.ijk[0] ; yd = id.ijk[1] ; zd = id.ijk[2] ; }
1774 #endif
1775 
1776    sprintf(strp,"I: %d", xd) ;
1777    fd_txt( grapher , GL_DLX+5 , 35, strp) ;
1778    xxx = DC_text_width(grapher->dc,strp) ;
1779 
1780    sprintf(strp,"J: %d", yd) ;
1781    fd_txt( grapher , GL_DLX+5 , 21, strp) ;
1782    www = DC_text_width(grapher->dc,strp) ; xxx = MAX(xxx,www) ;
1783 
1784    if( grapher->status->nz > 1 ){
1785      sprintf(strp,"K: %d", zd) ;
1786      fd_txt( grapher , GL_DLX+5 ,  7, strp) ;
1787      www = DC_text_width(grapher->dc,strp) ; xxx = MAX(xxx,www) ;
1788    }
1789 
1790    /* second column */
1791 
1792    grapher->xx_text_2 = xxx = xxx + GL_DLX + 15 ;
1793 
1794    DC_linewidth( grapher->dc , 0 ) ;
1795    fd_line( grapher , xxx-7 , 41 , xxx-7 , 5 ) ;
1796 
1797    if( NIGNORE(grapher) > 0 ){                    /* 23 May 2005 */
1798      sprintf(strp,"Ignore%4d",NIGNORE(grapher)) ;
1799      if( grapher->thresh_fade ) sprintf(strp+strlen(strp)," Fading") ;
1800      fd_txt( grapher , xxx , 35, strp) ; grapher->xx_text_igf = 1+xxx+DC_text_width(grapher->dc,strp) ;
1801    } else if( grapher->thresh_fade ){
1802      sprintf(strp,"Fading") ;
1803      fd_txt( grapher , xxx , 35, strp) ; grapher->xx_text_igf = 1+xxx+DC_text_width(grapher->dc,strp) ;
1804    }
1805 
1806    sprintf(strp,"Grid:%5d", grapher->grid_spacing ) ;
1807    rrr = DC_text_width(grapher->dc,strp) ;
1808 
1809    if( !grapher->textgraph ){
1810       if( grapher->fscale > 0 ){                        /* 04 Feb 1998: */
1811          AV_fval_to_char( grapher->fscale , buf ) ;     /* put scale on graph, too */
1812          www = strlen(strp) ;
1813          sprintf(strp+www," Scale:%s pix/datum",buf) ;
1814       } else if( grapher->fscale < 0 ){
1815          AV_fval_to_char( -grapher->fscale , buf ) ;
1816          www = strlen(strp) ;
1817          sprintf(strp+www," Scale:%s datum/pix",buf) ;
1818       }
1819    }
1820 
1821    fd_txt( grapher , xxx , 21, strp ) ;
1822 
1823    xxx = DC_text_width(grapher->dc,strp) ;           /* 19 Dec 2003 [rickr] */
1824 
1825    /* info about indexes we are viewing*/
1826 
1827    { int bb=TBOT(grapher) , tt=TTOP(grapher)-1 , ss = NSTRIDE(grapher) ;
1828      if( ss == 1 ){
1829        if( bb > 999 || tt > 999 )
1830          sprintf(strp,"#%4d:%-4d" , bb,tt ) ;
1831        else
1832          sprintf(strp,"Num%3d:%-3d" , bb,tt ) ;
1833      } else {                                        /* 11 Jun 2020 */
1834        if( bb > 999 || tt > 999 )
1835          sprintf(strp,"%3d:%-4d@%1d"  , bb,tt,ss ) ;
1836        else
1837          sprintf(strp,"#%3d:%-3d@%1d" , bb,tt,ss ) ;
1838      }
1839    }
1840    fd_line( grapher ,
1841             grapher->xx_text_2+rrr+3 ,
1842             (NIGNORE(grapher) > 0 || grapher->thresh_fade) ? 41 : 31 ,
1843             grapher->xx_text_2+rrr+3 , 5 ) ;
1844 
1845    grapher->xx_text_2p = grapher->xx_text_2+rrr+7 ;  /* 23 May 2005 */
1846 
1847    /* info about the baseline */
1848 
1849    if( !grapher->textgraph ){
1850      switch( grapher->common_base ){
1851        default:
1852        case BASELINE_INDIVIDUAL:
1853          strcat(strp,"  Base: separate") ; break ;
1854 
1855        case BASELINE_COMMON:
1856          strcat(strp,"  Base: common") ; break ;
1857 
1858        case BASELINE_GLOBAL:
1859          strcat(strp,"  Base: global") ; break ;
1860      }
1861    }
1862 
1863    fd_txt( grapher , grapher->xx_text_2 ,  7, strp ) ;
1864 
1865    /* add third column        19 Dec 2003  [rickr] */
1866 
1867    www = DC_text_width(grapher->dc,strp) ; xxx = MAX(xxx,www) ;
1868 
1869    grapher->xx_text_3 = grapher->xx_text_2 + xxx + 15 ;
1870 
1871    if( !grapher->textgraph && !ISONE(grapher) ){
1872       char *flab ;
1873 
1874       sprintf(strp,"Mean: %10s", MV_format_fval(grapher->tmean[xc][yc]) ) ;
1875 
1876       fd_txt( grapher , grapher->xx_text_3 ,  21, strp ) ;
1877       xxx = DC_text_width(grapher->dc,strp) ;
1878 
1879       sprintf(strp,"Sigma:%10s", MV_format_fval(grapher->tstd[xc][yc]) ) ;
1880 
1881       fd_txt( grapher , grapher->xx_text_3 ,   7, strp ) ;
1882       www = DC_text_width(grapher->dc,strp) ; xxx = MAX(xxx,www) ;
1883 
1884       fd_line( grapher , grapher->xx_text_3-7 , 31 , grapher->xx_text_3-7 , 5 ) ;
1885 
1886       www = grapher->xx_text_3 + xxx + 7 ;
1887       fd_line( grapher , www , 31 , www , 5 ) ;
1888 
1889       flab = GRA_transform_label( grapher->transform0D_av ,
1890                                   (XtPointer) grapher->status->transforms0D ) ;
1891       sprintf(strp,"Tran 0D = %s",flab) ;
1892       www = grapher->xx_text_3 + xxx + 15 ;
1893       fd_txt( grapher , www , 21 , strp ) ;
1894 
1895       flab = GRA_transform_label( grapher->transform1D_av ,
1896                                   (XtPointer) grapher->status->transforms1D ) ;
1897       sprintf(strp,"Tran 1D = %s",flab) ;
1898       www = grapher->xx_text_3 + xxx + 15 ;
1899       fd_txt( grapher , www , 7 , strp ) ;
1900     }
1901 
1902    /*** flush the pixmap to the screen ***/
1903 
1904    fd_px_store( grapher ) ;
1905 
1906    /*** draw any overlay stuff ***/
1907 
1908    GRA_redraw_overlay( grapher ) ;
1909 
1910 #ifdef USE_OPTMENUS
1911    GRA_fix_optmenus( grapher ) ;
1912 #endif
1913 
1914    /** 27 Jan 2004 **/
1915 
1916    if( MCW_val_bbox(grapher->fmenu->fim_editref_winaver_bbox) )
1917      GRA_winaver_setref( grapher ) ;
1918 
1919    grapher->never_drawn = 0 ;
1920    EXRETURN ;
1921 }
1922 
1923 /*------------------------------------------------
1924    Plot text in fd_pxWind at x,y position
1925    relative to lower left corner (!).
1926    Note that myGC was setup in display.c,
1927    where the font is defined.
1928 --------------------------------------------------*/
1929 
fd_txt(MCW_grapher * grapher,int x,int y,char * str)1930 void fd_txt( MCW_grapher *grapher , int x , int y , char * str )
1931 {
1932    XDrawString( grapher->dc->display, grapher->fd_pxWind,
1933                 grapher->dc->myGC , x , grapher->fHIGH-y ,
1934                 str , strlen(str) ) ;
1935    return ;
1936 }
1937 
1938 /*---------------------------------------------------------------------------*/
1939 /* Write the string one character at a time, upwards (for graph box labels) */
1940 
fd_txt_upwards(MCW_grapher * grapher,int x,int y,char * str)1941 void fd_txt_upwards( MCW_grapher *grapher , int x , int y , char *str )
1942 {
1943    int ii , nn ; int_pair ad ;
1944    if( str == NULL || *str == '\0' ) return ;
1945    for( nn=strlen(str)-1 ; nn >= 0 && isspace(str[nn]) ; nn-- ) ; /*nada*/
1946    for( ii=nn ; ii >= 0 ; ii-- ){
1947      if( isgraph(str[ii]) ){
1948        ad = DC_char_adscent(grapher->dc,str[ii]) ;
1949        y -= ad.j ;
1950        XDrawString( grapher->dc->display, grapher->fd_pxWind,
1951                     grapher->dc->myGC , x , y , str+ii , 1 ) ;
1952        y -= ad.i+2 ;
1953      } else {
1954        y -= 2 ;
1955      }
1956    }
1957    return ;
1958 }
1959 
1960 /*---------------------------------------------------------------------------*/
1961 
overlay_txt(MCW_grapher * grapher,int x,int y,char * str)1962 void overlay_txt( MCW_grapher *grapher , int x , int y , char *str )
1963 {
1964    if( str == NULL || *str == '\0' ) return ;
1965    XDrawString( grapher->dc->display, XtWindow(grapher->draw_fd) ,
1966                 grapher->dc->myGC , x , grapher->fHIGH-y ,
1967                 str , strlen(str) ) ;
1968    return ;
1969 }
1970 
1971 /*-----------------------------------------------*/
1972 /* draw a line in the Pixmap;
1973    this is used only for lines dividing
1974    the informative text below the graphs
1975 *//*---------------------------------------------*/
1976 
fd_line(MCW_grapher * grapher,int x1,int y1,int x2,int y2)1977 static void fd_line( MCW_grapher *grapher , int x1,int y1, int x2,int y2 )
1978 {
1979    XDrawLine( grapher->dc->display , grapher->fd_pxWind ,
1980               grapher->dc->myGC , x1,grapher->fHIGH-y1,x2,grapher->fHIGH-y2 ) ;
1981    return ;
1982 }
1983 
1984 /*------------------------------------------------------------------------*/
1985 /* get automatic vertical grid line spacings, given number of time points */
1986 
1987 #define GRID_MAX 13
1988 static int grid_ar[GRID_MAX] =
1989    { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000 } ;
1990 
auto_grid(MCW_grapher * grapher,int npoints)1991 static void auto_grid( MCW_grapher *grapher , int npoints )
1992 {
1993    int ii ;
1994    if( npoints < 2 ) return ;            /* 02 Apr 2004 */
1995    for( ii=GRID_MAX-1 ; ii > 0 ; ii-- )
1996      if( grid_ar[ii] <= npoints/3 ) break;
1997    grapher->grid_index   = ii ;
1998    grapher->grid_spacing = grid_ar[ii] ;
1999    grapher->grid_fixed   = 0 ;           /* 02 Apr 2004 */
2000    return ;
2001 }
2002 
2003 /*-----------------------------------------------*/
2004 /* Initialize some constants */
2005 
init_const(MCW_grapher * grapher)2006 void init_const( MCW_grapher *grapher )
2007 {
2008    int ii ;
2009 
2010 ENTRY("init_const") ;
2011 
2012    if( !GRA_VALID(grapher) ) EXRETURN ;
2013 
2014    /* vertical scale factor */
2015 
2016    if( grapher->fscale == 0 ) grapher->fscale = 1 ;
2017 
2018    /* max number of sub-graphs allowed */
2019 
2020    grapher->mat_max = MAT_MAX ;
2021    grapher->mat_max = MIN( grapher->mat_max , grapher->status->nx ) ;
2022    grapher->mat_max = MIN( grapher->mat_max , grapher->status->ny ) ;
2023 
2024    /* initial number of sub-graphs */
2025 
2026    if( grapher->mat <= 0 ) grapher->mat = INIT_GR_gmat ;
2027    grapher->mat = MIN( grapher->mat , grapher->mat_max ) ;
2028 
2029    /* initial center point in 3D space, if not previously set */
2030 
2031    if( grapher->xpoint < 0 || grapher->xpoint >= grapher->status->nx )
2032       grapher->xpoint = grapher->status->nx / 2 ;
2033 
2034    if( grapher->ypoint < 0 || grapher->ypoint >= grapher->status->ny )
2035       grapher->ypoint = grapher->status->ny / 2 ;
2036 
2037    if( grapher->zpoint < 0 || grapher->zpoint >= grapher->status->nz )
2038       grapher->zpoint = grapher->status->nz / 2 ;
2039 
2040    /* initial grid spacing */
2041 
2042    if( grapher->grid_index < 0 ) auto_grid( grapher, NPTS(grapher) ) ;
2043 
2044 #if 0
2045    if( grapher->grid_color < 0 )
2046       grapher->grid_color = 1 ;  /* first overlay color */
2047 #endif
2048 
2049    /* initial time point */
2050 
2051    if( grapher->time_index < 0 )
2052      grapher->time_index = 0 ;
2053    else if( grapher->time_index >= grapher->status->num_series )
2054      grapher->time_index = grapher->status->num_series - 1 ;
2055 
2056    /* setup the matrix-related constants */
2057 
2058    init_mat(grapher) ;
2059    EXRETURN ;
2060 }
2061 
2062 /*---------------------------------------------------------------*/
2063 /* Draw numbers instead of graphs -- 22 Sep 2000 -- RWCox
2064    Largely for the physicists out there, or the very inquisitive.
2065 *//*-------------------------------------------------------------*/
2066 
text_graphs(MCW_grapher * grapher)2067 void text_graphs( MCW_grapher *grapher )
2068 {
2069    MRI_IMAGE *tsim ;
2070    int index, ix, iy, xtemp,ytemp,ztemp , xoff,yoff ;
2071    int iv , jv , www ;
2072    char str[64] , *strp ;
2073 
2074 ENTRY("text_graphs") ;
2075    if( grapher->dont_redraw ) EXRETURN ;  /* 27 Jan 2004 */
2076 
2077    DC_fg_color( grapher->dc , TEXT_COLOR(grapher) ) ;
2078 
2079    iv = grapher->time_index ;
2080    if( iv < 0 )
2081      iv = 0 ;
2082    else if( iv >= grapher->status->num_series )
2083      iv = grapher->status->num_series - 1 ;
2084 
2085    ztemp = grapher->zpoint * grapher->status->ny * grapher->status->nx ;
2086 
2087    /* loop over sub-graph boxes */
2088 
2089    for( ix=0 ; ix < grapher->mat ; ix++ ){
2090       xtemp  = grapher->xpoint + ix - grapher->xc ;
2091            if( xtemp <  0                   ) xtemp += grapher->status->nx ;
2092       else if( xtemp >= grapher->status->nx ) xtemp -= grapher->status->nx ;
2093 
2094       for( iy=0 ; iy < grapher->mat ; iy++ ){
2095          ytemp = grapher->ypoint - iy + grapher->yc ;
2096               if( ytemp <  0                   ) ytemp += grapher->status->ny ;
2097          else if( ytemp >= grapher->status->ny ) ytemp -= grapher->status->ny ;
2098 
2099          index = ztemp + ytemp * grapher->status->nx + xtemp ;
2100 
2101          tsim = GRA_getseries( grapher , index ) ; /* get the data */
2102          if( tsim == NULL ) break ;
2103 
2104          if( ix == grapher->xc && iy == grapher->yc ){
2105            mri_free( grapher->cen_tsim ) ;             /* copy time series too */
2106            grapher->cen_tsim = mri_to_float( tsim ) ;
2107          }
2108 
2109          if( grapher->thresh_fade && tsim->flags == 0 ){ /* Mar 2013 */
2110            rectangle_fdX( grapher ,
2111                           grapher->xorigin[ix][iy]+1 , grapher->yorigin[ix][iy]+1 ,
2112                           grapher->gx-2              , grapher->gy-2 ,
2113                           fade_color ) ;
2114            DC_fg_color ( grapher->dc , DATA_COLOR(grapher) ) ;  /* must reset */
2115            DC_linewidth( grapher->dc , DATA_THICK(grapher) ) ;
2116          }
2117 
2118 #if 0
2119          if( grapher->transform0D_func != NULL )
2120 # if 0
2121             grapher->transform0D_func( tsim->nx , MRI_FLOAT_PTR(tsim) ) ;
2122 # else
2123             AFNI_CALL_0D_function( grapher->transform0D_func ,
2124                                    tsim->nx , MRI_FLOAT_PTR(tsim) ) ;
2125 # endif
2126 #endif
2127 
2128          jv = iv ; if( jv >= tsim->nx ) jv = tsim->nx - 1 ;
2129          AV_fval_to_char( MRI_FLOAT_PTR(tsim)[jv] , str ) ;
2130          mri_free(tsim) ;
2131          strp = (str[0] == ' ') ? str+1 : str ;
2132          www = DC_text_width(grapher->dc,strp) ; /* for centering, below */
2133 
2134          fd_txt( grapher , grapher->xorigin[ix][iy] + (grapher->gx-www)/2 ,
2135                            grapher->yorigin[ix][iy] + 2 ,
2136                  strp ) ;
2137       }
2138    }
2139 
2140    EXRETURN ;
2141 }
2142 
2143 /*-----------------------------------------------------------------------------*/
2144 /* Find the smallest/largest values in these images, for plotting [01 Jun 2020]
2145    Usage is tsim = main plot
2146             qim  = double plot
2147    Either (or both) images can be NULL.
2148    Smallest/largest values are found over index range tbot..ttop-1.
2149 *//*--------------------------------------------------------------------------*/
2150 
GRA_find_range(int tbot,int ttop,int tstep,MRI_IMAGE * tsim,MRI_IMAGE * qim)2151 float_pair GRA_find_range( int tbot, int ttop, int tstep, MRI_IMAGE *tsim , MRI_IMAGE *qim )
2152 {
2153    int tt , i , ibot=tbot , itop , first=1 ;
2154    float *far , tsbot=0.0f , tstop=0.0f ; float_pair tsout ;
2155 
2156 ENTRY("GRA_find_range") ;
2157 
2158    if( tstep < 1 ) tstep = 1 ; /* just to be safe */
2159 
2160    if( tsim != NULL && tsim->nx > 1 ){  /* scan first image */
2161      far  = MRI_FLOAT_PTR(tsim) ;
2162      itop = MIN( ttop , tsim->nx ) ;
2163      if( first && ibot < itop ){ tsbot = tstop = far[ibot] ; first = 0 ; }
2164      for( tt=0 ; tt < tsim->ny ; tt++ ){
2165        for( i=ibot ; i < itop ; i+=tstep ){
2166          tsbot = MIN( tsbot , far[i] ) ;
2167          tstop = MAX( tstop , far[i] ) ;
2168        }
2169        far += tsim->nx ;
2170      }
2171    }
2172 
2173    if( qim != NULL && qim->nx > 1 ){   /* scan second image */
2174      far  = MRI_FLOAT_PTR(qim) ;
2175      itop = MIN( ttop , qim->nx ) ;
2176      if( first && ibot < itop ){ tsbot = tstop = far[ibot] ; first = 0 ; }
2177      for( tt=0 ; tt < qim->ny ; tt++ ){
2178        for( i=ibot ; i < itop ; i+=tstep ){
2179          tsbot = MIN( tsbot , far[i] ) ;
2180          tstop = MAX( tstop , far[i] ) ;
2181        }
2182        far += qim->nx ;
2183      }
2184    }
2185 
2186    tsout.a = tsbot ; tsout.b = tstop ; RETURN(tsout) ;
2187 }
2188 
2189 /*-----------------------------------------------------------------------------*/
2190 /*! From the 'Detrend' menu */
2191 
GRA_detrend_CB(MCW_arrowval * av,XtPointer cd)2192 void GRA_detrend_CB( MCW_arrowval *av , XtPointer cd ) /* 05 Dec 2012 */
2193 {
2194    MCW_grapher *grapher = (MCW_grapher *)cd ; int avd ;
2195 
2196 ENTRY("GRA_detrend_CB") ;
2197 
2198    if( ! GRA_VALID(grapher) ) EXRETURN ;
2199    avd = av->ival ; if( avd == grapher->detrend ) EXRETURN ;
2200    grapher->detrend = avd ;
2201    redraw_graph( grapher , 0 ) ;
2202    EXRETURN ;
2203 }
2204 
2205 /*----------------------------------------------------------------------------*/
2206 /* Detrend each column of an image (L1, for robustness to outliers) */
2207 
GRA_detrend_im(int dord,MRI_IMAGE * im)2208 static void GRA_detrend_im( int dord , MRI_IMAGE *im ) /* 05 Dec 2012 */
2209 {
2210    int jy , nx,ny ; float *iar ;
2211 
2212    if( dord < 0 || im == NULL || im->kind != MRI_float ) return ;
2213    iar = MRI_FLOAT_PTR(im) ;           if( iar == NULL ) return ;
2214    nx = im->nx ; ny = im->ny ;         if( dord > nx+1 ) return ;
2215    for( jy=0 ; jy < ny ; jy++ )
2216      THD_generic_detrend_L1( nx , iar+(jy*nx) , dord , 0,NULL,NULL ) ;
2217 
2218    return ;
2219 }
2220 
2221 #if 0
2222 /*-----------------------------------------------------------------------------*/
2223 /* Detrend each column of each image [no longer used] */
2224 
2225 static void GRA_detrend_imarr( int dord , MRI_IMARR *imar ) /* 05 Dec 2012 */
2226 {
2227    int ii ;
2228 
2229    if( imar == NULL ) return ;
2230    for( ii=0 ; ii < IMARR_COUNT(imar) ; ii++ )
2231      GRA_detrend_im( dord , IMARR_SUBIM(imar,ii) ) ;
2232 
2233    return ;
2234 }
2235 #endif
2236 
2237 /*-----------------------------------------------------------
2238     Plot real graphs to pixmap [lots of code here]
2239     This is where the most of the 'fun' or 'work' is.
2240 -------------------------------------------------------------*/
2241 
plot_graphs(MCW_grapher * grapher,int code)2242 void plot_graphs( MCW_grapher *grapher , int code )
2243 {
2244    MRI_IMAGE *tsim , *qim=NULL;
2245    MRI_IMARR *tsimar=NULL ;
2246    float     *tsar , *qar=NULL;
2247    float      tsbot=0.0f, xpfac=0.0f, ypfac,fwid,foff , tstop ;
2248    int i, m, index, ix, iy, xtemp,ytemp,ztemp, xoff=0,yoff=0, its,ibot,itop;
2249    int ptop,pbot,pnum,qnum , ntmax , qq ;  /* 17 Mar 2004 */
2250 
2251    int pstep =1 , nstep=0 ;        /* stride thru data */
2252    int nupsam=0 ;                  /* 28 May 2020 */
2253    float_pair tsrange ;            /* 01 Jun 2020 */
2254    int          ntstemp=0 ;
2255    static float *tstemp=NULL ;     /* 09 Jun 2020 */
2256 
2257    static int      *plot = NULL ;  /* arrays to hold plotting coordinates */
2258    static XPoint *a_line = NULL ;  /* one XPoint = (x,y) coords of one point in window */
2259    static int  nplot_old = 0 ;
2260 
2261    /* stuff for plotting along an arbitrary x-axis,
2262       as opposed to the equal spacing provided by default */
2263 
2264    MRI_IMAGE *xxim=NULL, *xxim_cen=NULL , *xax_tsim=NULL ; /* 10 Feb 2015 */
2265    MRI_IMARR *xximar=NULL ;
2266    int do_xxim=0 ;
2267    double_pair xax_minmax ; float xax_tsim_bot=0.0f , xax_tsim_top=0.0f ;
2268 
2269    /*  boxes?       box labels? */
2270    int do_boxes=0 , do_boxlab=0 ;
2271 
2272    /* stuff for extra (overlaying) plots,
2273       in addition to the standard underlay plots */
2274 
2275    MRI_IMARR *dplot_imar = NULL ;  /* 08 Nov 1996 - for double plot */
2276    int        dplot = 0 ;
2277    int        pmplot_mode = 0 ;    /* 01 Jun 2020 - new PLUSMINUS plot modes */
2278    int        pmplot_color= 1 ;
2279 
2280    /* stuff for extra (above) plots -- FIM and ORTs (very old stuff) */
2281 
2282    MRI_IMARR *eximar = NULL ;
2283    int        iex ;
2284 
2285    /* things for setting the vertical scale between data and pixels */
2286 
2287    float nd_bot=0 , nd_top=0 , nd_dif=0 ;                  /* 03 Feb 1998 */
2288    int   set_scale = ( (code & PLOTCODE_AUTOSCALE) != 0 ||
2289                        grapher->never_drawn ) ;
2290 
2291    MRI_IMAGE *dsim ; /* 07 Aug 2001: also for double plot */
2292    float     *dsar ;
2293 
2294 #define OVI_MAX 19
2295    int tt, use_ovi, ovi[OVI_MAX] ;  /* 29 Mar 2002: for multi-plots */
2296 
2297    /*----- START OF EXECUTABLE CODE -----*/
2298 
2299 ENTRY("plot_graphs") ;
2300    if( grapher->dont_redraw ) EXRETURN ;  /* 27 Jan 2004 */
2301 
2302    /* check if we draw text instead of curves */
2303 
2304    if( grapher->status->num_series < 1 ){
2305      EXRETURN ;
2306    } else if( grapher->status->num_series == 1 ||
2307               grapher->textgraph               || TPTS(grapher) < 2 ){
2308      text_graphs( grapher ) ;  /* that was easy */
2309      EXRETURN ;
2310    }
2311 
2312    /* for the x-axis specified by a time series file */
2313 
2314    if( grapher->xax_tsim != NULL ){
2315      xax_tsim = mri_copy(grapher->xax_tsim) ;  /* scaled local copy */
2316      GRA_fixup_xaxis( grapher , xax_tsim ) ;   /* 09 Jan 1998 */
2317 
2318      xax_minmax   = mri_minmax( grapher->xax_tsim ) ;
2319      xax_tsim_bot = xax_minmax.a ;
2320      xax_tsim_top = xax_minmax.b ;
2321    }
2322 
2323    mri_free(grapher->xax_cen) ; grapher->xax_cen = NULL ; /* 12 Feb 2015 */
2324 
2325    /* special things to 'do' */
2326 
2327    do_boxes  = DATA_BOXED(grapher) ;
2328    do_boxlab = DATA_BOXLAB_CODE(grapher) ;
2329    do_xxim   = (grapher->xax_fdbr != NULL) && !do_boxes ;
2330 
2331    /* set colors and line widths [these alter the myGC X11 graphics context] */
2332 
2333    DC_fg_color ( grapher->dc , DATA_COLOR(grapher) ) ;
2334    DC_linewidth( grapher->dc , DATA_THICK(grapher) ) ;
2335 
2336    /* 17 Mar 2004: we will plot with x-axis = pbot..ptop-1 */
2337    /*    Jun 2020: with stride of pstep [for Gang Chen]    */
2338 
2339    ptop = NTOP(grapher) ; pbot = NBOT(grapher) ; pstep = NSTRIDE(grapher) ;
2340    if( pbot >= ptop ){
2341      pbot = 0 ; ptop = grapher->status->num_series ;
2342    }
2343    if( pstep > 1 ){                     /* adjust ptop so that pbot..ptop-1 */
2344      nstep = NABC(pbot,ptop,pstep) ;    /* is an integer number of steps */
2345      if( nstep < 2 ){ grapher->pin_stride = pstep = 1 ; }
2346      else           { ptop = pbot + (nstep-1)*pstep + 1 ; }
2347    }
2348    if( ptop <= pbot || ptop > grapher->status->num_series ){
2349      ptop = MIN(ptop,grapher->status->num_series) ;
2350    }
2351    pnum = NABC(pbot,ptop,pstep) ;  /* number of data points to plot */
2352    if( pnum <= 1 ) EXRETURN ;      /* should never happen?! */
2353 
2354    /* how much to upsample the lines between data values? */
2355 
2356    if( DO_UPSAM(grapher) ){               /* for smoothing [28 May 2020] */
2357      nupsam = XUPSAM(grapher->gx,pnum) ;  /* XUPSAM is in afni_graph.h */
2358      if( nupsam > 1 && xxim != NULL ) nupsam *= 2 ; /* ad hoc */
2359    }
2360 
2361    /* set aside static memory for plotting, etc. */
2362 
2363 #define NPLOT_INIT 9999  /* 29 Apr 1997 */
2364    itop = MAX( NPLOT_INIT , grapher->status->num_series ) ;
2365    if( nplot_old == 0 || nplot_old < itop ){  /* probably only executed once */
2366      myXtFree(a_line) ; myXtFree(plot) ;      /* unless a LOT of data comes in later */
2367      nplot_old = 2*itop+666 ; /* just to be safe */
2368      plot      = (int *)    XtMalloc( sizeof(int)    * nplot_old ) ;
2369      a_line    = (XPoint *) XtMalloc( sizeof(XPoint) * nplot_old ) ;
2370      tstemp    = (float *)  malloc  ( sizeof(float)  * nplot_old ) ; /* 09 Jun 2020 */
2371    }
2372    if( grapher->ncen_line < itop ){
2373      myXtFree(grapher->cen_line) ;
2374      grapher->cen_line  = (XPoint *) XtMalloc( sizeof(XPoint) * itop ) ;
2375      grapher->ncen_line = itop ;
2376    }
2377 
2378    /* set the bottom point (ibot) at which to compute time series statistics */
2379 
2380    ibot = NIGNORE(grapher) ;        /* first non-ignored data point */
2381    if( pstep >  1      ) ibot = 0 ; /* disable ignore for strides > 1 */
2382    if( ibot  >= ptop-1 ) ibot = 0 ; /* disable ignore if too long */
2383    ibot = MAX(ibot,pbot) ;
2384 
2385    /** loop over matrix of graphs and get all the time series for later use **/
2386 
2387    INIT_IMARR(tsimar) ; /* image array to store the data time series */
2388 
2389    if( do_xxim ) INIT_IMARR(xximar) ; /* to store x-axis time series, if needed */
2390 
2391    /** 08 Nov 1996: initialize second array for double plotting **/
2392    /** 07 Aug 2001: modify to allow for multiple dplot cases    **/
2393    /**  Double plotting is implemented by 'transforms' of the input data, **/
2394    /**  which in the case of Dataset#N simply provides entirely new data. **/
2395    /**  Why this way? Because transforms already existed in the code.     **/
2396 
2397    if( grapher->transform1D_func != NULL &&
2398        MCW_val_bbox(grapher->opt_dplot_bbox) != DPLOT_OFF ){
2399 
2400      STATUS("  initialize graph for DPLOT") ;
2401 
2402      INIT_IMARR(dplot_imar) ;
2403      dplot = MCW_val_bbox(grapher->opt_dplot_bbox) ; /* 07 Aug 2001 */
2404    }
2405 
2406    /* how to do the plus/minus double plot overlay [01 Jun 2020] */
2407    /* Cannot do pmplot with non-standard x-axis! */
2408 
2409    pmplot_mode = 0 ;
2410    if( dplot && !do_xxim && xax_tsim == NULL ){
2411      pmplot_mode  = PMPLOT_MODE(grapher) ; if( pmplot_mode == 1 ) pmplot_mode = 0;
2412      pmplot_color = PMPLOT_COLOR(grapher);
2413    }
2414 
2415    /* clear the time series statistics etc. for this array of time series */
2416 
2417    GRA_CLEAR_tuser( grapher ) ;  /* 22 Apr 1997 */
2418 
2419    /* 3D index offset to correct slice number */
2420    ztemp = grapher->zpoint * grapher->status->ny * grapher->status->nx ;
2421 
2422    ntmax = 0 ; /* will be length of longest time series found below */
2423 
2424    /**--- double loop to get the data for the (ix,iy)-th sub-graph ---**/
2425 
2426    for( ix=0 ; ix < grapher->mat ; ix++ ){  /* get data for the 'main' plots */
2427 
2428       /** compute the 3D index of the desired time series **/
2429 
2430       xtemp  = grapher->xpoint + ix - grapher->xc ;
2431            if( xtemp <  0                   ) xtemp += grapher->status->nx ;  /* wrap */
2432       else if( xtemp >= grapher->status->nx ) xtemp -= grapher->status->nx ;
2433 
2434       for( iy=0 ; iy < grapher->mat ; iy++ ){
2435 
2436          ytemp = grapher->ypoint - iy + grapher->yc ;
2437               if( ytemp <  0                   ) ytemp += grapher->status->ny;  /* wrap */
2438          else if( ytemp >= grapher->status->ny ) ytemp -= grapher->status->ny;
2439 
2440          index = ztemp + ytemp * grapher->status->nx + xtemp ;  /* 3D index in dataset */
2441 
2442          /** get the desired time series, using the provided routine **/
2443 
2444          tsim = GRA_getseries( grapher , index ) ;  /* this is kind of important */
2445 
2446          if( do_xxim ){                                  /* 10 Feb 2015 */
2447            xxim = GRA_getseries_xax( grapher , index ) ; /* for user-supplied */
2448            if( ix == grapher->xc && iy == grapher->yc ){ /* x-axis from a */
2449              xxim_cen = xxim ;                           /* dataset */
2450              mri_free(grapher->xax_cen) ; grapher->xax_cen = mri_copy(xxim) ;
2451            }
2452            xax_minmax = mri_minmax( xxim ) ;
2453            grapher->xax_bot[ix][iy] = xax_minmax.a ;  /* get the min/max of */
2454            grapher->xax_top[ix][iy] = xax_minmax.b ;  /* x-axis for (ix,iy) */
2455            GRA_fixup_xaxis( grapher , xxim ) ;       /* scale to range 0..1 */
2456            ADDTO_IMARR(xximar,xxim) ;                  /* save for graphing */
2457          } else if( xax_tsim != NULL ){
2458            grapher->xax_bot[ix][iy] = xax_tsim_bot ; /* for user-supplied */
2459            grapher->xax_top[ix][iy] = xax_tsim_top ; /* x-axis from a 1D file */
2460          }
2461 
2462          /* 08 Nov 1996: allow for return of NULL data timeseries */
2463 
2464          if( tsim == NULL ){
2465            ADDTO_IMARR(tsimar,NULL) ;
2466            if( dplot_imar != NULL ) ADDTO_IMARR(dplot_imar,NULL) ;
2467            continue ;                                      /* skip to next iy */
2468          }
2469 
2470          ntmax = MAX( ntmax , tsim->nx ) ;/* longest time series seen to here */
2471 
2472          /* 22 Oct 1996: transform each point, if ordered */
2473 
2474          if( grapher->transform0D_func != NULL ){  /* 0D = pointwise in place */
2475 STATUS("about to perform 0D transformation") ;
2476             AFNI_CALL_0D_function( grapher->transform0D_func ,
2477                                    tsim->nx , MRI_FLOAT_PTR(tsim) ) ;
2478          }
2479 
2480          /* 03 Nov 1996: 1D transformations, too [more cases to manage] */
2481          /* 08 Nov 1996: double plotting, too */
2482          /*              that is, the 'transformation' can */
2483          /*              just be an entirely new time series */
2484 
2485          if( grapher->transform1D_func != NULL ){
2486 
2487             if( dplot ){                     /* copy and save original */
2488               qim = mri_to_float(tsim) ;       /* if double plot is on */
2489               ADDTO_IMARR(dplot_imar,qim) ; /* so we can plot original */
2490             }                                 /* and the 'transformed' */
2491             else
2492               qim = tsim ;            /* just transform original image */
2493 
2494 STATUS("about to perform 1D transformation") ;
2495 
2496             /* 1D transform functions are coded with binary
2497                flags, which indicate how they are to be used here */
2498 
2499             if( grapher->transform1D_flags & NEEDS_DSET_INDEX ){ /* 18 May 2000 */
2500 #ifdef BE_AFNI_AWARE  /* if afni_graph.c is compiled for use with AFNI GUI */
2501                FD_brick *br=(FD_brick *)grapher->getaux ; THD_ivec3 id ;
2502                id = THD_fdind_to_3dind( br ,
2503                                         TEMP_IVEC3(xtemp,ytemp,grapher->zpoint) );
2504                AFNI_store_dset_index(
2505                              id.ijk[0]
2506                             +id.ijk[1] * br->nxyz.ijk[0]
2507                             +id.ijk[2] * br->nxyz.ijk[0] * br->nxyz.ijk[1] , 0 ) ;
2508 #else
2509                AFNI_store_dset_index(-1,0) ; /* older dumbshit code */
2510 #endif
2511             }
2512 
2513             /* over the centuries, the number of ways to
2514                call a 1D transform function kept metastasizing :( */
2515 
2516             if( ! (grapher->transform1D_flags & PROCESS_MRI_IMAGE) ){  /* older code:   */
2517                                                                        /* process image */
2518               if( ! (grapher->transform1D_flags & RETURNS_STRING) ){   /* contents only */
2519                  AFNI_CALL_1D_function( grapher->transform1D_func ,
2520                                         qim->nx , qim->xo , qim->dx , /* just change */
2521                                         MRI_FLOAT_PTR(qim) ) ;        /* the data */
2522               } else {
2523                  char *quser = NULL ;
2524                  AFNI_CALL_1D_funcstr( grapher->transform1D_func ,    /* also returns */
2525                                        qim->nx , qim->xo , qim->dx ,  /* a string */
2526                                        MRI_FLOAT_PTR(qim) , quser ) ;
2527                  if( quser != NULL )
2528                    grapher->tuser[ix][iy] = XtNewString(quser) ;      /* save string */
2529               }
2530 
2531             } else {                           /* 28 Mar 2002: process MRI_IMAGE struct */
2532                                                                             /* in place */
2533               if( ! (grapher->transform1D_flags & RETURNS_STRING) ){
2534                  AFNI_CALL_1D_funcmrim( grapher->transform1D_func , qim ) ;
2535               } else {
2536                  char *quser = NULL ;
2537                  AFNI_CALL_1D_funcmrimstr( grapher->transform1D_func , qim,quser ) ;
2538                  if( quser != NULL )
2539                    grapher->tuser[ix][iy] = XtNewString(quser) ;
2540               }
2541 
2542             } /* OK, the transformation/replacement of qim has happened */
2543 
2544             /* 04 Oct 2007: discard double-plotted data when
2545                             the transformation changed nothing */
2546 
2547             if( dplot && mri_equal(tsim,qim) ){  /* every point is equal */
2548               mri_free(qim) ; qim = NULL ; /* dplot is on, so qim is not tsim */
2549               IMARR_SUBIM( dplot_imar , IMARR_COUNT(dplot_imar)-1 ) = NULL ;
2550             }
2551 
2552             /* if this is a plus/minus double plot, we need to do some
2553                surgery on qim now:
2554                  to make it 2 curves with tsim+qim and tsim-qim.
2555                So there is a double 'transformation':
2556                  get the pmplot data into qim (from above)
2557                  then convert it to qqim with 2 curves (below)
2558                  and then pull a switcheroo, throwing qim away */
2559 
2560             if( pmplot_mode && qim != NULL ){ /* 01 Jun 2020 */
2561               MRI_IMAGE *qqim; float *qqar,*qar ; int kk,nx ;
2562               nx   = MIN( tsim->nx , qim->nx ) ;      /* length of substitute */
2563               qqim = mri_new( nx , 2 , MRI_float ) ;  /* substitute image */
2564               qqar = MRI_FLOAT_PTR(qqim) ;            /* data in substitute */
2565               tsar = MRI_FLOAT_PTR(tsim) ;            /* data in base */
2566               qar  = MRI_FLOAT_PTR(qim)  ;            /* data in plus/minus */
2567               for( kk=0 ; kk < nx ; kk++ ){
2568                 qqar[kk+0*nx] = tsar[kk] + qar[kk] ;   /* plus */
2569                 qqar[kk+1*nx] = tsar[kk] - qar[kk] ;   /* minus */
2570               }
2571               mri_free(qim) ; qim = qqim ; /* get rid of qim, substitute it */
2572               IMARR_SUBIM( dplot_imar , IMARR_COUNT(dplot_imar)-1 ) = qim ;
2573             }
2574 
2575             /* if we are detrending data time series,
2576                also detrend the other data to plot (if any) */
2577 
2578             if( qim != tsim ) GRA_detrend_im( grapher->detrend , qim ) ;
2579 
2580             /* At this point, qim is transformed and saved:
2581                if dplot is on,  then qim was saved in dplot_imar earlier;
2582                if dplot is off, then qim==tsim, will be saved in tsimar below */
2583 
2584          } /* end of transform1D (at last) */
2585 
2586          /* detrend data and then put this base image on list of those to plot */
2587 
2588          GRA_detrend_im( grapher->detrend , tsim ) ;
2589          ADDTO_IMARR(tsimar,tsim) ;
2590       }
2591    } /** end of double loop to get data for sub-graphs **/
2592 
2593    /** find the average data time series, for fun and profit [27 Jan 2004] **/
2594 
2595    if( ntmax > 1 && IMARR_COUNT(tsimar) > 0 ){
2596      float *avar , fac ; int nax , nts=0 ;
2597 STATUS("about to make average time series") ;
2598      if( grapher->ave_tsim != NULL ) mri_free(grapher->ave_tsim) ;
2599      grapher->ave_tsim = mri_new( ntmax , 1 , MRI_float ) ;
2600      avar = MRI_FLOAT_PTR(grapher->ave_tsim) ;  /* is full of 0's already */
2601      for( ix=0 ; ix < IMARR_COUNT(tsimar) ; ix++ ){
2602        tsim = IMARR_SUBIMAGE(tsimar,ix) ; if( tsim == NULL ) continue ;
2603        tsar = MRI_FLOAT_PTR(tsim)       ; if( tsar == NULL ) continue ;
2604        nax  = MIN( ntmax , tsim->nx ) ;
2605        for( i=0 ; i < nax ; i++ ) avar[i] += tsar[i] ;
2606        nts++ ;
2607      }
2608      fac = 1.0f / MAX(nts,1) ; /* in case there isn't any data! */
2609      for( i=0 ; i < grapher->ave_tsim->nx ; i++ ) avar[i] *= fac ;
2610 
2611      /* substitute new average into the
2612         FIM reference timeseries if that bbox is selected */
2613 
2614      if( MCW_val_bbox(grapher->fmenu->fim_editref_winaver_bbox) ){
2615        if( grapher->ref_ts == NULL ) INIT_IMARR( grapher->ref_ts ) ;
2616        if( IMARR_COUNT(grapher->ref_ts) == 0 ){
2617          ADDTO_IMARR( grapher->ref_ts , grapher->ave_tsim ) ;     /* create first one */
2618        } else {
2619          IMARR_SUBIMAGE(grapher->ref_ts,0) = grapher->ave_tsim ;  /* replace first one */
2620        }
2621      }
2622 
2623    } else if( grapher->ave_tsim != NULL ){
2624      mri_free(grapher->ave_tsim) ; grapher->ave_tsim = NULL ; /* no data to average */
2625    }
2626 
2627    /** find some statistics of each time series [for popup 'menu'] **/
2628 
2629 STATUS("finding statistics of time series") ;
2630 
2631    /* stuff for setting vertical scale */
2632 
2633    nd_bot = WAY_BIG ; nd_top = nd_dif = - WAY_BIG ;  /* 03 Feb 1998 */
2634 
2635    /* set the default entries for time series stat values,
2636       which is necessary if some sub-graphs don't return any data */
2637 
2638 #define DEFAULT_TSTAT(i,j)                               \
2639  do{ grapher->tmean[i][j] = grapher->tbot[i][j] =        \
2640       grapher->ttop[i][j] = grapher->tstd[i][j] = 0.0f;  \
2641      grapher->tmed[i][j] = grapher->tmad[i][j] = 0.0f;   \
2642      grapher->sbot[i][j] = grapher->stop[i][j] = 0 ;     \
2643      grapher->tbmv[i][j] = 0.0f ;                        \
2644      grapher->dbot[i][j] = 0.0f ;                        \
2645      grapher->dtop[i][j] = 0.0f ;                        \
2646      grapher->tsnr[i][j] = 0.0f ;                        \
2647  } while(0)
2648 
2649    /** double loop to statistic-ate each time series
2650           (just the parts being plotted, by the way) **/
2651 
2652    for( ix=0,its=0 ; ix < grapher->mat ; ix++ ){
2653       for( iy=0 ; iy < grapher->mat ; iy++,its++ ){
2654          float qbot,qtop ;
2655          double qsum , qsumq ;
2656 
2657          tsim = IMARR_SUBIMAGE(tsimar,its) ;             /* the data */
2658          DEFAULT_TSTAT(ix,iy) ;                    /* zero out stats */
2659          if( tsim == NULL || tsim->nx < 2 ) continue ; /* skip ahead */
2660 
2661          itop  = MIN( ptop , tsim->nx ) ;    /* ibot was set earlier */
2662          nstep = NABC(ibot,itop,pstep) ;    /* number of data points */
2663          if( nstep < 2 ) continue ;
2664          tsar = MRI_FLOAT_PTR(tsim) ;  /* do stats from ibot..itop-1 */
2665          if( tsar == NULL ) continue ;        /* should NEVER happen */
2666 
2667          qbot = qtop  = tsar[ibot] ;
2668          qsum = qsumq = 0.0 ;
2669          for( ntstemp=0,i=ibot ; i < itop ; i+=pstep ){ /* compute stats over visible data */
2670            qbot   = MIN( qbot , tsar[i] ) ;
2671            qtop   = MAX( qtop , tsar[i] ) ;
2672            qsum  += tsar[i] ;
2673            qsumq += tsar[i] * tsar[i] ;
2674            tstemp[ntstemp++] = tsar[i] ; /* temp save data for qmedmadbmv below */
2675          }
2676          grapher->tbot[ix][iy] = qbot ; grapher->ttop[ix][iy] = qtop ;
2677          grapher->sbot[ix][iy] = ibot ; grapher->stop[ix][iy] = i-pstep ;
2678          qsum  = qsum / ntstemp ; grapher->tmean[ix][iy] = qsum ;
2679          qsumq = (qsumq - ntstemp * qsum * qsum) / (ntstemp-0.999999) ;
2680          grapher->tstd[ix][iy] = (qsumq > 0.0) ? sqrt(qsumq) : 0.0 ;
2681          grapher->tsnr[ix][iy] = (qsumq > 0.0) ? fabs(qsum) / grapher->tstd[ix][iy]
2682                                                : 0.0 ;
2683          if( grapher->tsnr[ix][iy] > 9999.9f ) grapher->tsnr[ix][iy] = 9999.9f ;
2684 
2685          /* these statistics require a contiguous array = tstemp */
2686          qmedmadbmv_float( ntstemp , tstemp ,             /* 08 Mar 2001 */
2687                            &(grapher->tmed[ix][iy]) ,
2688                            &(grapher->tmad[ix][iy]) ,
2689                            &(grapher->tbmv[ix][iy])  ) ;  /* tbmv: 16 Oct 2009 */
2690 
2691          /* get range of values to be plotted in this sub-graph [01 Jun 2020] */
2692          /* - the old way was just to use the range of tsim,
2693               but now us advanced types use the range of all the data shown :) */
2694 
2695          qim = (dplot_imar != NULL) ? IMARR_SUBIMAGE(dplot_imar,its) : NULL ;
2696          tsrange = GRA_find_range( ibot,itop,pstep , tsim , qim ) ;
2697          grapher->dbot[ix][iy] = tsrange.a ;
2698          grapher->dtop[ix][iy] = tsrange.b ;
2699 
2700          /* and set the global values for ranges (for scale calculation) */
2701 
2702          nd_bot = MIN( nd_bot , tsrange.a ) ;             /* smallest bottom */
2703          nd_top = MAX( nd_top , tsrange.b ) ;             /* largest top */
2704          nd_dif = MAX( nd_dif , (tsrange.b-tsrange.a) ) ; /* largest range */
2705       }
2706    } /* end of loops over statistification of time series */
2707 
2708    /* 03 Feb 1998: set the vertical scale factor (maybe) */
2709 
2710    if( set_scale && nd_bot < nd_top && nd_dif > 0.0f ){
2711 
2712       /* here, fscale will be the number of pixels per data value */
2713 
2714       switch( grapher->common_base ){
2715          default:
2716          case BASELINE_INDIVIDUAL:
2717             grapher->fscale = 0.9f * grapher->gy / nd_dif ;          /* biggest range */
2718          break ;
2719 
2720          case BASELINE_COMMON:
2721             grapher->fscale = 0.9f * grapher->gy / (nd_top-nd_bot) ; /* global range */
2722          break ;
2723 
2724          case BASELINE_GLOBAL:{
2725             float vbot = (nd_top > grapher->global_base)
2726                         ? grapher->global_base : nd_bot ;
2727             grapher->fscale = 0.9f * grapher->gy / (nd_top-vbot) ;
2728          }
2729          break ;
2730       }
2731 
2732       /** switcheroo on fscale (holdover from old FD program):
2733             fscale > 0 ==> this many pixels per unit of tsar
2734             fscale < 0 ==> this many units of tsar per pixel **/
2735 
2736       if( grapher->fscale > 0.0f && grapher->fscale < 1.0f )
2737          grapher->fscale = -1.0f / grapher->fscale ;
2738 
2739            if( grapher->fscale > 4.0f )               /* make it an integer */
2740                   grapher->fscale = (int) grapher->fscale ;
2741 
2742       else if( grapher->fscale > 1.0f )                /* or a half-integer */
2743                   grapher->fscale = 0.5f * ((int)(2.0f*grapher->fscale)) ;
2744 
2745       else if( grapher->fscale < -4.0f )         /* ditto for the negatives */
2746                   grapher->fscale = -((int)(1.0f-grapher->fscale)) ;
2747 
2748       else if( grapher->fscale < -1.0f )
2749                   grapher->fscale = -0.5f * ((int)(1.0f-2.0f*grapher->fscale)) ;
2750    }
2751 
2752    /** if it will be the same for all graphs,
2753        set the bottom magnitude for them all now = tsbot **/
2754 
2755    if( grapher->common_base == BASELINE_COMMON ){
2756      tsbot = nd_bot ;
2757    } else if( grapher->common_base == BASELINE_GLOBAL ){
2758      tsbot = grapher->global_base ;
2759    }
2760 
2761    /* do something to mark infra-threshold voxels [Mar 2013] */
2762    /* note that this is done before plotting graphs, so that it
2763       appears as background color - X11 has no idea about translucency */
2764 
2765    if( grapher->thresh_fade ){
2766      for( ix=0,its=0 ; ix < grapher->mat ; ix++ ){
2767        for( iy=0 ; iy < grapher->mat ; iy++,its++ ){
2768          tsim = IMARR_SUBIMAGE(tsimar,its) ;
2769          if( tsim == NULL || tsim->flags == 0 ){
2770            rectangle_fdX( grapher ,
2771                           grapher->xorigin[ix][iy]+1 , grapher->yorigin[ix][iy]+1 ,
2772                           grapher->gx-2              , grapher->gy-2 ,
2773                           fade_color ) ;
2774          }
2775        }
2776      }
2777      DC_fg_color ( grapher->dc , DATA_COLOR(grapher) ) ;  /* must reset */
2778      DC_linewidth( grapher->dc , DATA_THICK(grapher) ) ;  /* drawing colors */
2779    }
2780 
2781    /**** loops over matrix of graphs and plot them all to the pixmap ****/
2782 
2783 STATUS("starting time series graph loop") ;
2784    for( ix=0,its=0 ; ix < grapher->mat ; ix++ ){
2785 
2786       for( iy=0 ; iy < grapher->mat ; iy++,its++ ){
2787 
2788          tsim = IMARR_SUBIMAGE(tsimar,its) ;
2789          if( tsim == NULL || tsim->nx < 2 ) continue ;    /* skip to next iy */
2790 
2791          itop = MIN( ptop , tsim->nx ) ;  /* ibot was set earlier */
2792          qnum = NABC(pbot,itop,pstep) ;   /* number of points to plot */
2793          if( qnum < 2 ) continue ;        /* skip if too few */
2794 
2795          qim = (dplot_imar != NULL && pmplot_mode )       /* PLUSMINUS */
2796                ? IMARR_SUBIMAGE(dplot_imar,its) : NULL ;  /* data */
2797 
2798                                          /* stuff for user-supplied x-axis */
2799          if( do_xxim ) xxim = IMARR_SUBIMAGE(xximar,its) ;  /* 10 Feb 2015 */
2800          else          xxim = xax_tsim ;                  /* might be NULL */
2801 
2802          /** find bottom value for this graph, if needed;
2803              otherwise, tsbot for all graphs was set above **/
2804 
2805          if( grapher->common_base == BASELINE_INDIVIDUAL ){
2806            tsbot = grapher->dbot[ix][iy] ;
2807          }
2808          grapher->pmin[ix][iy] = tsbot ;  /* value at graph bottom */
2809 
2810          /** 29 Mar 2002: decode 'color:' from tsim->name, if present **/
2811 
2812          use_ovi = (tsim->name!=NULL) && (strncmp(tsim->name,"color: ",7)==0) ;
2813          if( use_ovi ){
2814            char *cpt = tsim->name+6 ; int nuse, ngood ;
2815            for( tt=0 ; tt < OVI_MAX ; tt++ )
2816              ovi[tt] = DATA_COLOR(grapher) ;
2817            for( tt=0 ; tt < OVI_MAX ; tt++ ){
2818              ngood = sscanf(cpt,"%d%n",ovi+tt,&nuse) ;
2819              if( ngood < 1 ) break ;
2820              cpt += nuse ; if( *cpt == '\0' ) break ;
2821            }
2822          }
2823 
2824          /** set ypfac = scale factor for vertical (y):
2825               fscale > 0 ==> this many pixels per unit of tsar
2826               fscale < 0 ==> this many units of tsar per pixel **/
2827 
2828          ypfac = grapher->fscale ;
2829               if( ypfac == 0.0 ) ypfac =  1.0f ;   /* should not happen */
2830          else if( ypfac <  0.0 ) ypfac = -1.0f / ypfac ;
2831 
2832          xpfac = grapher->gx / (pnum-1.0f) ;  /* x scale factor */
2833 
2834          /* X11 pixel box for graph: (y runs DOWN the screen)
2835              x = xorigin[ix][iy]          .. xorigin[ix][iy]+gx    (L..R)
2836              y = fHIGH-yorigin[ix][iy]-gy .. fHIGH-yorigin[ix][iy] (T..B) */
2837 
2838          xoff  = grapher->xorigin[ix][iy] ;                  /* offsets */
2839          yoff  = grapher->fHIGH - grapher->yorigin[ix][iy] ;
2840 
2841          tsar = MRI_FLOAT_PTR(tsim) ; /* data to be plotted */
2842          qar  = MRI_FLOAT_PTR(qim) ;  /* will be NULL if image is NULL */
2843 
2844          /* do the plus/minus double plot first [01 Jun 2020],
2845             since we will want to draw all later stuff on top of it */
2846 
2847          if( pmplot_mode && qar != NULL && qim->ny == 2 ){
2848            int jtop = MIN(ptop,qim->nx) , jnum = NABC(pbot,jtop,pstep) ;
2849            if( jnum > 1 ){
2850              XPoint *d_line, *e_line, *f_line ; int nd_line = jnum+66 ;
2851              d_line = (XPoint *)malloc(sizeof(XPoint)*nd_line) ;  /* allocate space */
2852              e_line = (XPoint *)malloc(sizeof(XPoint)*nd_line) ;  /* for X11 points */
2853              /*--- plus lines = d_line array ---*/
2854               for( qq=0,i=pbot ; i < MIN(ibot,jtop) ; i+=pstep,qq++ ) /* pre-ignore */
2855                 plot[qq] = (tsar[ibot] - tsbot) * ypfac ;  /* just plot first value */
2856               for( ; i < jtop ; i+=pstep,qq++ )                      /* post-ignore */
2857                 plot[qq] = (qar[i] - tsbot) * ypfac ;       /* plot the actual data */
2858               jnum = qq ;
2859 
2860               for( i=0 ; i < jnum ; i++ ){                     /* convert to pixels */
2861                 d_line[i].x = xoff + i*xpfac ;
2862                 d_line[i].y = yoff - plot[i] ;    /* remember: -y is UP, +y is DOWN */
2863               }
2864              /*--- minus lines = e_line array [similar to above] ---*/
2865               for( qq=0,i=pbot ; i < MIN(ibot,jtop) ; i+=pstep,qq++ ) ; /*nada */
2866               for( ; i < jtop ; i+=pstep,qq++ )
2867                 plot[qq] = (qar[i+qim->nx] - tsbot) * ypfac ;
2868 
2869               for( i=0 ; i < jnum ; i++ ){
2870                 e_line[i].x = d_line[i].x ;
2871                 e_line[i].y = yoff - plot[i] ;
2872               }
2873               /*--- graphics choices ---*/
2874               DC_fg_color ( grapher->dc , pmplot_color ) ;
2875               DC_linewidth( grapher->dc , PMPLOT_THICK(grapher) ) ;
2876               switch( pmplot_mode ){
2877                 default:
2878                 case PMPLOT_CURVES: /* pretty much the olden way */
2879                   AFNI_XDrawLines( grapher->dc->display ,
2880                                    grapher->fd_pxWind , grapher->dc->myGC ,
2881                                    d_line , jnum , CoordModeOrigin , nupsam ) ;
2882                   AFNI_XDrawLines( grapher->dc->display ,
2883                                    grapher->fd_pxWind , grapher->dc->myGC ,
2884                                    e_line , jnum , CoordModeOrigin , nupsam ) ;
2885                 break ;
2886 
2887                 case PMPLOT_FILL:{ /* filled solid color */
2888                   f_line = (XPoint *)malloc(sizeof(XPoint)*nd_line*2) ;
2889                   for( i=0 ; i < jnum ; i++ ) f_line[i]          = d_line[i] ;
2890                   for( i=0 ; i < jnum ; i++ ) f_line[2*jnum-1-i] = e_line[i] ;
2891                   AFNI_XFillPolygon( grapher->dc->display ,
2892                                      grapher->fd_pxWind , grapher->dc->myGC ,
2893                                      f_line, 2*jnum, Complex, CoordModeOrigin, nupsam ) ;
2894                   free(f_line) ;
2895                 }
2896                 break ;
2897 
2898                 case PMPLOT_BARS:{ /* error bars, of a sort */
2899                   XPoint q_line[6] ; short dx ; float xd ;
2900                   xd = grapher->gx / ( 4.0f* jnum ) ; dx = SHORTIZE(xd) ;
2901                   if( dx > 16 ) dx = 16 ;
2902                   for( i=0 ; i < jnum ; i++ ){
2903                     q_line[0].x = e_line[i].x - dx ; q_line[0].y = e_line[i].y ;
2904                     q_line[1].x = e_line[i].x + dx ; q_line[1].y = e_line[i].y ;
2905                     q_line[2].x = e_line[i].x      ; q_line[2].y = e_line[i].y ;
2906                     q_line[3].x = d_line[i].x      ; q_line[3].y = d_line[i].y ;
2907                     q_line[4].x = d_line[i].x - dx ; q_line[4].y = d_line[i].y ;
2908                     q_line[5].x = d_line[i].x + dx ; q_line[5].y = d_line[i].y ;
2909                     AFNI_XDrawLines( grapher->dc->display ,
2910                                      grapher->fd_pxWind , grapher->dc->myGC ,
2911                                      q_line , 6 ,  CoordModeOrigin , 0 ) ;
2912                   }
2913                 }
2914                 break ;
2915               }
2916 
2917               free(e_line); free(d_line); /* free the XPoint arrays */
2918            }
2919          } /* end of pmplot BEFORE tsim plot! */
2920 
2921          /*-- now do the tsim plot(s) --*/
2922 
2923          DC_fg_color ( grapher->dc , DATA_COLOR(grapher) ) ; /* reset color */
2924          DC_linewidth( grapher->dc , DATA_THICK(grapher) ) ;
2925 
2926          for( tt=0 ; tt < tsim->ny ; tt++ ){  /* 29 Mar 2002: multi-plots in one image */
2927 
2928           /* scale to vertical pixels: before the ignore level */
2929 
2930           for( qq=0,i=pbot ; i < MIN(ibot,itop) ; i+=pstep,qq++ )
2931             plot[qq] = (tsar[ibot] - tsbot) * ypfac ;
2932 
2933           /* scale after the ignore level */
2934 
2935           for( ; i < itop ; i+=pstep,qq++ )
2936             plot[qq] = (tsar[i] - tsbot) * ypfac ;
2937 
2938           qnum = qq ; /* number of points in plot */
2939 
2940           /* now have qnum points in plot[] */
2941 
2942           grapher->pmax[ix][iy] = tsbot + grapher->gy / ypfac ; /* value at graph top */
2943 
2944           /** Compute X11 line coords from pixel heights in plot[].
2945               N.B.: X11 y is DOWN the screen, but plot[] is UP the screen **/
2946 
2947           if( do_boxes )
2948             xpfac = grapher->gx / (float)pnum ; /* x scale factor */
2949           else
2950             xpfac = grapher->gx / (pnum-1.0f) ; /* x scale factor */
2951 
2952           /* 09 Jan 1998: allow x-axis to be chosen by a
2953                           timeseries that ranges between 0 and 1
2954              '?' == get x pixel location from xxim
2955              ':' == get x pixel lcation from time series index ii */
2956 
2957 #define XPIX(ii)                                            \
2958    ( (xxim != NULL && (ii) < xxim->nx)                      \
2959      ? (MRI_FLOAT_PTR(xxim)[MAX((ii),ibot)] * grapher->gx)  \
2960      : (((ii)-pbot) * xpfac) )
2961 
2962           for( i=0 ; i < qnum ; i++ ){        /* generate X11 plot points */
2963             a_line[i].x = xoff + XPIX(i+pbot);
2964             a_line[i].y = yoff - plot[i] ;    /* X11 y-axis is down the screen */
2965           }
2966 
2967           if( use_ovi )                       /* 29 Mar 2002: line color */
2968             DC_fg_color( grapher->dc , ovi[tt%OVI_MAX] ) ;
2969 
2970 /* macro to draw a data point of size ww (ww is set below) */
2971 #define DRAW_A_DATA_POINT(x,y)                               \
2972   do{ if( ww < 3 ) GRA_small_circle(grapher,(x),(y),ww>1) ;  \
2973       else         GRA_draw_disk   (grapher,(x),(y),ww+2) ;  \
2974   } while(0)
2975 
2976           /* draw points at the data values? (using the above macro)  */
2977 
2978           if( DATA_POINTS(grapher) ){         /* 09 Jan 1998 */
2979             int ww = DATA_THICK(grapher) ;
2980             for( i=0 ; i < qnum ; i++ ) DRAW_A_DATA_POINT(a_line[i].x,a_line[i].y) ;
2981           }
2982 
2983           /* draw lines connecting the data values? */
2984 
2985           if( DATA_LINES(grapher) ){          /* 01 Aug 1998 */
2986             AFNI_XDrawLines( grapher->dc->display ,
2987                         grapher->fd_pxWind , grapher->dc->myGC ,
2988                         a_line , qnum ,  CoordModeOrigin , nupsam ) ;
2989           }
2990 
2991           /* draw boxes for the data values? (exclusive of the above) */
2992 
2993           if( do_boxes ){                    /* 26 Jun 2007 */
2994             XPoint q_line[4] ; short xb,xt ; float delt=xpfac/tsim->ny ;
2995             int labw=-1,labx=-1, aybas=0 ;
2996 
2997             /* setup for box labels as well */
2998 
2999             if( do_boxlab && grapher->mat <= 9 ){
3000               labw = labx = DC_char_width(grapher->dc,'M') ; /* widest character */
3001               /* labx will be the x-offset for the label position,
3002                  so that the label is centered above the box of width delt;
3003                  Note that if labx < 0, the box is too narrow to draw labels */
3004               if( labx > 0 ) labx = (int)(0.5*(delt-labx)-1.0f) ;
3005               switch( do_boxlab ){
3006 
3007                 case DATA_BOXLAB_CODE_UP:  /* labels start at top of highest box */
3008                   for( aybas=a_line[0].y,i=1 ; i < qnum ; i++ )
3009                     if( a_line[i].y < aybas ) aybas = a_line[i].y ;
3010                   aybas -= BOXOFF + grapher->gthick/3 ; /* shifted up by BOXOFF, and */
3011                 break ;                                 /* allowance for thick lines */
3012 
3013                 case DATA_BOXLAB_CODE_BOT: /* labels start at bottom of sub-graph */
3014                   aybas = yoff ;
3015                 break ;
3016               }
3017             }
3018 
3019             /* loop over data points and draw boxes + labels */
3020             /* note that the top of a box is shifted up by BOXOFF pixels */
3021             /* this is so that the shortest box doesn't have height=0 */
3022 
3023             for( i=0 ; i < qnum ; i++ ){
3024               xb = (short)(a_line[i].x + tt*delt + 0.499f) ;  /* x bot */
3025               xt = (short)(xb + delt-0.999f) ;                /* x top */
3026 
3027               /* setup the X11 corners of the box */
3028               q_line[0].x = xb ; q_line[0].y = yoff ;               /* lower left */
3029               q_line[1].x = xb ; q_line[1].y = a_line[i].y-BOXOFF ; /* upper left */
3030               q_line[2].x = xt ; q_line[2].y = a_line[i].y-BOXOFF ; /* upper right */
3031               q_line[3].x = xt ; q_line[3].y = yoff ;               /* lower right */
3032 
3033               AFNI_XDrawLines( grapher->dc->display ,
3034                           grapher->fd_pxWind , grapher->dc->myGC ,
3035                           q_line , 4 ,  CoordModeOrigin , 0 ) ;     /* draw box */
3036 
3037               if( labx >= 0 ){             /* if labels can be fit in box width */
3038                 char *lab = GRA_getlabel(grapher,pbot+i) ; /* get the label (duh) */
3039 
3040                 if( aybas > 0 ){ /* fixed y-location for all labels */
3041                   fd_txt_upwards(grapher,xb+labx,aybas-3,lab) ;
3042                 } else {         /* label goes on top of individual data box;  */
3043                                  /* adjustments of -3-grapher->gthick/3 are so */
3044                                  /* the label doesn't overlap the top box line */
3045                   fd_txt_upwards(grapher,xb+labx,a_line[i].y-3-BOXOFF-grapher->gthick/3,lab) ;
3046                 }
3047               }
3048             }
3049           } /* end of drawing boxes */
3050 
3051           /* 22 July 1996: save central graph data for later use */
3052 
3053           if( ix == grapher->xc && iy == grapher->yc && tt == 0 ){
3054             for( i=0 ; i < qnum ; i++ ) grapher->cen_line[i] = a_line[i] ;
3055             grapher->nncen = qnum ;
3056             mri_free( grapher->cen_tsim ) ;             /* copy time series too */
3057             grapher->cen_tsim = mri_to_float( tsim ) ;
3058           }
3059 
3060           tsar += tsim->nx ;  /* 29 Mar 2002: advance to next curve */
3061          } /* end of loop over multi-plot (tt) within a single tsim */
3062 
3063          if( use_ovi )
3064            DC_fg_color( grapher->dc , DATA_COLOR(grapher) ) ; /* reset color */
3065 
3066          /* 08 Nov 1996: double plot?  Duplicate the above drawing code! */
3067          /* 29 Mar 2002: allow multiple time series (dsim->ny > 1) */
3068          /* 01 Jun 2020: PLUSMINUS (pmplot) now taken care of earlier */
3069          /* Note no boxes or pmplot here! */
3070 
3071          if( dplot && pmplot_mode == 0 && !do_boxes ){
3072             int dny , id , qq,qtop ;
3073             dsim = IMARR_SUBIMAGE(dplot_imar,its) ;
3074             if( dsim == NULL || dsim->nx < 2 ) continue ;  /* skip to next iy */
3075             dsar = MRI_FLOAT_PTR(dsim) ;
3076             tsar = MRI_FLOAT_PTR(tsim) ;   /* 25 Feb 2003: reset this */
3077             itop = MIN( ptop , dsim->nx ); /* ibot was set long ago */
3078             qnum = NABC(pbot,itop,pstep) ; /* number of points to plot here */
3079             if( qnum < 2 ) continue ;      /* skip to next iy = next sub-graph */
3080 
3081             /** 29 Mar 2002: decode 'color:' from dsim->name, if present **/
3082 
3083             use_ovi = (dsim->name!=NULL) && (strncmp(dsim->name,"color: ",7)==0) ;
3084             if( use_ovi ){
3085               char *cpt = dsim->name+6 ; int nuse, ngood ;
3086               for( tt=0 ; tt < OVI_MAX ; tt++ )
3087                 ovi[tt] = DPLOT_COLOR(grapher) ;
3088               for( tt=0 ; tt < OVI_MAX ; tt++ ){
3089                 ngood = sscanf(cpt,"%d%n",ovi+tt,&nuse) ;
3090                 if( ngood < 1 ) break ;
3091                 cpt += nuse ; if( *cpt == '\0' ) break ;
3092               }
3093             }
3094 
3095             dny = dsim->ny ;
3096 
3097             for( id=0 ; id < dny ; id++ ){       /* 29 Mar 2002: multi-plots */
3098                                                  /* from the same dplot image */
3099              ypfac = grapher->fscale ;
3100                   if( ypfac == 0.0 ) ypfac =  1.0 ;
3101              else if( ypfac <  0.0 ) ypfac = -1.0 / ypfac ;
3102 
3103              /* 18 Mar 2004: scan backwards from itop to reject superlarge values */
3104 
3105              for( qtop=itop-1 ; qtop >= pbot ; qtop-- )
3106                if( dsar[qtop] < WAY_BIG ) break ;
3107              if( qtop <= ibot ){ dsar += dsim->nx; continue; }  /* skip */
3108              qtop++ ; qnum = NABC(pbot,qtop,pstep) ;
3109              if( qnum <  2    ){ dsar += dsim->nx; continue; }  /* skip */
3110 
3111              switch( dplot ){
3112                default:
3113                case DPLOT_OVERLAY:                       /* plot curve */
3114                  for( qq=0,i=pbot ; i < MIN(ibot,qtop) ; i+=pstep,qq++ )
3115                    plot[qq] = (dsar[ibot] - tsbot) * ypfac ;
3116                  for( ; i < qtop ; i+=pstep,qq++ )
3117                    plot[qq] = (dsar[i] - tsbot) * ypfac ;
3118 
3119                  qnum = qq ;
3120                break ;
3121              }
3122 
3123              xpfac = grapher->gx / (pnum-1.0) ;  /* cf. XPIX */
3124              xoff  = grapher->xorigin[ix][iy] ;
3125              yoff  = grapher->fHIGH - grapher->yorigin[ix][iy] ;
3126 
3127              for( i=0 ; i < qnum ; i++ ){
3128                a_line[i].x = xoff + XPIX(i+pbot) ;  /* 09 Jan 1998 */
3129                a_line[i].y = yoff - plot[i] ;
3130              }
3131 
3132              if( use_ovi )                      /* 29 Mar 2002 */
3133                DC_fg_color( grapher->dc , ovi[id%OVI_MAX] ) ;
3134              else
3135                DC_fg_color( grapher->dc , DPLOT_COLOR(grapher) ) ;
3136 
3137              if( DPLOT_POINTS(grapher) ){       /* 09 Jan 1998 */
3138                int ww = DPLOT_THICK(grapher) ;
3139                for( i=0 ; i < qnum ; i++ )
3140                  DRAW_A_DATA_POINT(a_line[i].x,a_line[i].y) ;
3141              }
3142              if( DPLOT_LINES(grapher) ) {        /* 01 Aug 1998 */
3143                DC_linewidth( grapher->dc , DPLOT_THICK(grapher) ) ;
3144                AFNI_XDrawLines( grapher->dc->display ,
3145                            grapher->fd_pxWind , grapher->dc->myGC ,
3146                            a_line , qnum ,  CoordModeOrigin , nupsam ) ;
3147              }
3148 
3149              dsar += dsim->nx ;      /* 29 Mar 2002: next curve */
3150             } /* end of loop over multiple dplots */
3151 
3152             DC_fg_color ( grapher->dc , DATA_COLOR(grapher) ) ;
3153             DC_linewidth( grapher->dc , DATA_THICK(grapher) ) ;
3154 
3155          } /* end of dplot */
3156 
3157          /* 05 Jan 1999: plot horizontal line through zero, if desired and needed */
3158 
3159          if( grapher->HorZ && grapher->pmin[ix][iy] < 0.0 && grapher->pmax[ix][iy] > 0.0 ){
3160            DC_fg_color ( grapher->dc , GRID_COLOR(grapher) ) ; /* change myGC */
3161            DC_linewidth( grapher->dc , GRID_THICK(grapher) ) ;
3162            DC_dashed_line( grapher->dc ) ;
3163 
3164            ypfac = grapher->fscale ;
3165                 if( ypfac == 0.0 ) ypfac =  1.0 ;
3166            else if( ypfac <  0.0 ) ypfac = -1.0 / ypfac ;
3167 
3168            XDrawLine( grapher->dc->display , grapher->fd_pxWind , grapher->dc->myGC ,
3169                       (int) xoff                , (int)(yoff + tsbot * ypfac) ,
3170                       (int)(xoff + grapher->gx) , (int)(yoff + tsbot * ypfac)  ) ;
3171 
3172            DC_fg_color ( grapher->dc , DATA_COLOR(grapher) ) ; /* change myGC back */
3173            DC_linewidth( grapher->dc , DATA_THICK(grapher) ) ;
3174            DC_solid_line( grapher->dc ) ;
3175          }
3176 
3177       } /* end of loop over y */
3178    } /* end of loop over x */
3179 
3180    /** cast away the data timeseries! **/
3181 
3182    DESTROY_IMARR(tsimar) ;
3183    if( dplot_imar != NULL ) DESTROY_IMARR(dplot_imar) ;  /* 08 Nov 1996 */
3184 
3185    /*---- Now do extra plots in center frame, if any [leftover from FD2] ----*/
3186 
3187 #define REFTS_FRAC 0.38  /* fraction of one graph that this takes up */
3188 #define REFTS_TOP  0.98  /* top of reference graph in frame */
3189 
3190 #define ORTTS_FRAC 0.38
3191 #define ORTTS_TOP  0.78
3192 
3193    /* 12 Nov 1996: include graphs of orts by looping "iex" */
3194 
3195    for( iex=0 ; iex <= 1 ; iex++ ){
3196 
3197       if( pstep > 1 ) continue ;  /* 11 Jun 2020 */
3198 
3199       eximar = (iex==0) ? grapher->ref_ts : grapher->ort_ts ;
3200 
3201       if( do_xxim ) xxim = xxim_cen ;             /* 10 Feb 2015 */
3202       else          xxim = xax_tsim ;             /* might be NULL */
3203 
3204       if( eximar != NULL && IMARR_COUNT(eximar) > 0 ){
3205          float yscal , val , xscal , exfrac , extop ;
3206          int   nover , nvec , nx , ivec ;
3207          int   excolor , exthick ;
3208          char *eee=NULL, *cnam=NULL; NI_str_array *cstr=NULL; int icc=0,ncstr=0;
3209 
3210 STATUS("plotting extra graphs") ;
3211 
3212          exfrac  = (iex==0) ? REFTS_FRAC : ORTTS_FRAC ;
3213          extop   = (iex==0) ? REFTS_TOP  : ORTTS_TOP  ;
3214          excolor = (iex==0) ? IDEAL_COLOR(grapher) : ORT_COLOR(grapher) ;
3215          exthick = (iex==0) ? IDEAL_THICK(grapher) : ORT_THICK(grapher) ;
3216 
3217          /* 06 Oct 2010: get a list of colors to use */
3218 
3219               if( iex == 0 ) eee = my_getenv("AFNI_IDEAL_COLORS") ;
3220          else if( iex == 1 ) eee = my_getenv("AFNI_ORT_COLORS") ;
3221 
3222          if( eee != NULL && strlen(eee) > 3 ){
3223            cstr = NI_decode_string_list( eee , ":," ) ;
3224            if( cstr != NULL && cstr->num == 0 ){
3225              NI_delete_str_array(cstr) ; cstr = NULL ;
3226            } else {
3227              ncstr = cstr->num ;
3228            }
3229          }
3230 
3231          for( its=0 ; its < IMARR_COUNT(eximar) ; its++ ){
3232 
3233             tsim = IMARR_SUBIMAGE(eximar,its) ;
3234 
3235             if( tsim == NULL || tsim->kind != MRI_float || tsim->nx < 2 ) continue ;
3236 
3237             nx   = tsim->nx ;
3238             itop = MIN( ptop , nx ) ;
3239             qnum = itop - pbot ; if( qnum < 2 ) continue ;
3240             nvec = (grapher->ref_ts_plotall) ? (tsim->ny) : 1 ;
3241 
3242             for( ivec=0 ; ivec < nvec ; ivec++ ){  /* plot each sub-vector */
3243               if( ncstr > 0 ){ cnam = cstr->str[icc%ncstr] ; icc++ ; }
3244               tsar  = MRI_FLOAT_PTR(tsim) + (ivec*nx) ;
3245               tsbot = 99999999.0 ; tstop = -99999999.0 ;
3246               nover = NIGNORE(grapher) ;
3247               for( i=ibot ; i < itop ; i++ ){
3248                 val = tsar[i] ;
3249                 if( val < WAY_BIG ){ tstop = MAX(tstop,val); tsbot = MIN(tsbot,val); }
3250                 else               { nover++ ; }
3251               }
3252               if( tstop >= WAY_BIG || tstop <= tsbot ) continue ; /* skip */
3253 
3254               /*** scale into a_line and draw it***/
3255 
3256               yscal = exfrac * grapher->gy / (tstop-tsbot) ;
3257               xscal = xpfac = grapher->gx / (pnum-1.0) ;
3258 
3259               xoff  = grapher->xorigin[grapher->xc][grapher->yc] ;
3260               yoff  = grapher->fHIGH - grapher->yorigin[grapher->xc][grapher->yc]
3261                                      - (extop - exfrac) * grapher->gy ;
3262 
3263               for( i=pbot ; i < itop; i++ ){
3264                 val = (i >= ibot &&  tsar[i] < WAY_BIG) ? tsar[i] : tsbot ;
3265 
3266                 a_line[i-pbot].x = xoff + XPIX(i) ;           /* 09 Jan 1998 */
3267                 a_line[i-pbot].y = yoff - yscal*(val-tsbot) ;
3268               }
3269 
3270               /* if none are over the limit, draw in one operation;
3271                  otherwise, must plot each line separately in its needed color */
3272 
3273               if( nover == 0 ){
3274                 if( cnam != NULL && *cnam != '\0' )
3275                   DC_fg_colortext( grapher->dc , cnam ) ;
3276                 else
3277                   DC_fg_color( grapher->dc , excolor ) ;
3278                 DC_linewidth( grapher->dc , exthick ) ;
3279                 AFNI_XDrawLines( grapher->dc->display ,
3280                             grapher->fd_pxWind , grapher->dc->myGC ,
3281                             a_line , qnum ,  CoordModeOrigin , nupsam ) ;
3282               } else {
3283                 for( i=pbot ; i < itop-1 ; i++ ){
3284                   if( i >= ibot && tsar[i] < WAY_BIG && tsar[i+1] < WAY_BIG ){
3285                     if( cnam != NULL && *cnam != '\0' )
3286                       DC_fg_colortext( grapher->dc , cnam ) ;
3287                     else
3288                       DC_fg_color( grapher->dc , excolor ) ;
3289                     DC_linewidth( grapher->dc , exthick ) ;
3290                   } else {
3291                     DC_fg_color( grapher->dc , IGNORE_COLOR(grapher) ) ;
3292                     if( grapher->mat < 4 &&
3293                         ( i < ibot || tsar[i] >= WAY_BIG ) )
3294                       GRA_small_circle( grapher,a_line[i-pbot].x,a_line[i-pbot].y,0 );
3295                   }
3296 
3297                   AFNI_XDrawLines( grapher->dc->display ,
3298                               grapher->fd_pxWind , grapher->dc->myGC ,
3299                               a_line + (i-pbot) , 2 ,  CoordModeOrigin , 0 ) ;
3300                 }
3301                 if( grapher->mat < 4 &&
3302                     ( i < ibot || tsar[i] >= WAY_BIG ) )
3303                   GRA_small_circle( grapher,a_line[i-pbot].x,a_line[i-pbot].y,0 );
3304               }
3305             } /* end of loop over sub-vectors */
3306          } /* end of loop over refs */
3307 
3308          if( cstr != NULL ){ NI_delete_str_array(cstr); cstr = NULL; }
3309 
3310       } /* end of if refs exist */
3311    } /* end of loop over refs and orts */
3312 
3313    /*---- 09 Jan 1998: plot graph showing x-axis as well ----*/
3314 
3315    xxim = (do_xxim) ? xxim_cen : xax_tsim ;
3316    if( pstep == 1 && xxim != NULL ){  /* show the x-axis vertically at the left */
3317      float yscal , ftemp , xscal , yoff ;
3318      int   npt ;
3319 
3320      xscal = GL_DLX / (float) grapher->gx ;
3321      yscal = grapher->gy / (pnum-1.0) ;
3322      yoff  = grapher->fHIGH - grapher->yorigin[grapher->xc][grapher->yc] ;
3323      ftemp = 1.0 ;
3324      npt   = ptop ;
3325      if( npt > xxim->nx ) npt = xxim->nx ;
3326      if( npt > pbot+1 ){
3327        for( i=pbot ; i < npt ; i++ ){
3328          a_line[i-pbot].x = XPIX(i) * xscal ;
3329          a_line[i-pbot].y = yoff - yscal*(i-pbot) ;
3330        }
3331        DC_fg_color ( grapher->dc , IDEAL_COLOR(grapher) ) ;
3332        DC_linewidth( grapher->dc , IDEAL_THICK(grapher) ) ;
3333        AFNI_XDrawLines( grapher->dc->display , grapher->fd_pxWind , grapher->dc->myGC ,
3334                    a_line , npt-pbot ,  CoordModeOrigin , 0 ) ;
3335      }
3336    } /* there is no code for showing the x-axis for pstep > 1, it's too hard */
3337 
3338    /***** Done!!! (at last) *****/
3339 
3340    if( do_xxim ) DESTROY_IMARR(xximar) ;  /* 10 Feb 2015 */
3341    mri_free(xax_tsim) ;
3342 
3343    EXRETURN ;
3344 }
3345 
3346 /*------------------------------------------------------------------------
3347    Draw frames around each sub-graph and grids inside them
3348    12 Jan 1998: modified to allow for gaps between graphs
3349 --------------------------------------------------------------------------*/
3350 
draw_grids(MCW_grapher * grapher)3351 void draw_grids( MCW_grapher *grapher )
3352 {
3353    int i , mat=grapher->mat , gx=grapher->gx , gy=grapher->gy ;
3354    int j, k, g, xo, yo, npoints , m ;
3355    int xc = grapher->xc , yc = grapher->yc ;
3356    float ftemp ;
3357 
3358 ENTRY("draw_grids") ;
3359    if( grapher->dont_redraw ) EXRETURN ;  /* 27 Jan 2004 */
3360 
3361    /* draw grid lines in the chosen color */
3362 
3363    if( GRID_COLOR(grapher) > 0 ){
3364       DC_fg_color ( grapher->dc , GRID_COLOR(grapher) ) ;
3365       DC_linewidth( grapher->dc , GRID_THICK(grapher) ) ;
3366 
3367       g       = grapher->grid_spacing ;
3368       npoints = NPTS(grapher) ;  /* number time points in 1 sub-graph window */
3369 
3370       if( npoints > 1 ){                /* this if: 22 Sep 2000 */
3371         if( DATA_BOXED(grapher) ) ftemp = gx / (float)npoints ;
3372         else                      ftemp = gx / (npoints-1.0f) ;
3373         for( i=0 ; i < mat ; i++ ){
3374           for( m=0 ; m < mat ; m++ ){
3375             xo = grapher->xorigin[i][m] ; yo = grapher->yorigin[i][m] ;
3376             for( j=1 ; j <= (npoints-1)/g ; j++ ){
3377               k = xo + j * g * ftemp ;
3378               plot_fdX( grapher , k , yo    , 0 ) ;
3379               plot_fdX( grapher , k , yo+gy , 1 ) ;
3380             }
3381           }
3382         }
3383       }
3384 
3385       /* draw an interior framing box at the central square */
3386 
3387       xo = grapher->xorigin[xc][yc] ; yo = grapher->yorigin[xc][yc] ;
3388       g  = MIN( grapher->gy/3 , grapher->gx/3 ) ; g  = MIN( g , 4 ) ;
3389       for( j=1 ; j <= g ; j++ ){
3390          plot_fdX( grapher , xo+j    , yo+j    , 0 ) ;
3391          plot_fdX( grapher , xo+j    , yo+gy-j , 1 ) ;
3392          plot_fdX( grapher , xo+gx-j , yo+gy-j , 1 ) ;
3393          plot_fdX( grapher , xo+gx-j , yo+j    , 1 ) ;
3394          plot_fdX( grapher , xo+j    , yo+j    , 1 ) ;
3395       }
3396    }
3397 
3398    /* draw exterior frames */
3399 
3400    DC_fg_color ( grapher->dc , FG_COLOR(grapher) ) ;
3401    DC_linewidth( grapher->dc , FG_THICK(grapher) ) ;
3402 
3403    for( i=0 ; i < mat ; i++ ){
3404       for( j=0 ; j < mat ; j++ ){
3405          xo = grapher->xorigin[i][j] ; yo = grapher->yorigin[i][j] ;
3406          plot_fdX( grapher , xo    , yo    , 0 ) ;
3407          plot_fdX( grapher , xo+gx , yo    , 1 ) ;
3408          plot_fdX( grapher , xo+gx , yo+gy , 1 ) ;
3409          plot_fdX( grapher , xo    , yo+gy , 1 ) ;
3410          plot_fdX( grapher , xo    , yo    , 1 ) ;
3411       }
3412    }
3413 
3414    EXRETURN ;
3415 }
3416 
3417 /*------------------------------------------
3418   Send the caller info about the new graph
3419 --------------------------------------------*/
3420 
send_newinfo(MCW_grapher * grapher)3421 void send_newinfo( MCW_grapher *grapher )
3422 {
3423 ENTRY("send_newinfo") ;
3424 
3425    if( GRA_VALID(grapher) && grapher->status->send_CB != NULL ){
3426       GRA_cbs cbs ;
3427 
3428       cbs.reason = graCR_newxyzm   ;
3429       cbs.xcen   = grapher->xpoint ;
3430       cbs.ycen   = grapher->ypoint ;
3431       cbs.zcen   = grapher->zpoint ;
3432       cbs.mat    = grapher->mat ;
3433 #if 0
3434       grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
3435 #else
3436       CALL_sendback( grapher , cbs ) ;
3437 #endif
3438    }
3439 
3440    EXRETURN ;
3441 }
3442 
3443 /*---------------------------
3444    initialize matrix stuff
3445 -----------------------------*/
3446 
init_mat(MCW_grapher * grapher)3447 void init_mat( MCW_grapher *grapher )
3448 {
3449    int i, j ;
3450    int gg ;
3451 
3452 ENTRY("init_mat") ;
3453    if( !GRA_VALID(grapher) ) EXRETURN ;
3454 
3455    grapher->gx = grapher->gx_max / grapher->mat;
3456    grapher->gy = grapher->gy_max / grapher->mat;
3457 
3458    for (i=0;i<grapher->mat;i++) {
3459      for (j=0;j<grapher->mat;j++) {
3460        grapher->xorigin[i][j] = MDX1 + i * grapher->gx;
3461        grapher->yorigin[i][j] = MDY1 + j * grapher->gy;
3462      }
3463    }
3464 
3465    if( grapher->mirror && grapher->mat > 1 ){  /* Jul 2000 */
3466       int mm = grapher->mat , m2 = mm/2 ;      /* swap left and right */
3467 
3468       for( j=0 ; j < mm ; j++ ){
3469          for( i=0 ; i < m2 ; i++ ){
3470            gg                          = grapher->xorigin[i][j] ;
3471            grapher->xorigin[i][j]      = grapher->xorigin[mm-1-i][j] ;
3472            grapher->xorigin[mm-1-i][j] = gg ;
3473          }
3474       }
3475    }
3476 
3477    grapher->xc = grapher->mat/2;
3478    grapher->yc = (grapher->mat-1)/2;
3479 
3480    gg = grapher->ggap ;                /* 12 Jan 1998 */
3481    if( gg > 0 ){
3482      gg = MIN( gg , grapher->gx / 2 ) ;  /* shrink sizes of graphs */
3483      gg = MIN( gg , grapher->gy / 2 ) ;
3484      grapher->gx -= gg ;
3485      grapher->gy -= gg ;
3486    }
3487 
3488    EXRETURN ;
3489 }
3490 
3491 /* ----------------------------- */   /* scale plot up and redraw  */
scale_up(MCW_grapher * grapher)3492 void scale_up( MCW_grapher * grapher )
3493 /* ----------------------------- */
3494 {
3495    if( !GRA_VALID(grapher) ) return ;
3496    if (grapher->fscale > 0) grapher->fscale *= 2;
3497    else if (grapher->fscale < -2) grapher->fscale /= 2;
3498    else grapher->fscale = 1;
3499 
3500    if( grapher->fscale > 1000000.0 ){
3501      static int nn=0 ;
3502      nn++ ; if( nn < 3 ) fprintf(stderr,"Is that you, Bellgowan?  If so, stop it!\a\n") ;
3503    }
3504    return ;
3505 }
3506 
3507 /* ----------------------------- */   /* scale plot up and redraw  */
scale_down(MCW_grapher * grapher)3508 void scale_down( MCW_grapher * grapher )
3509 /* ----------------------------- */
3510 {
3511    if( !GRA_VALID(grapher) ) return ;
3512    if (grapher->fscale > 1) grapher->fscale /= 2;
3513    else if (grapher->fscale < 0) grapher->fscale *= 2;
3514    else grapher->fscale = -2;
3515    return ;
3516 }
3517 
3518 /* ----------------------------- */   /* decrease matrix and redraw  */
mat_down(MCW_grapher * grapher)3519 void mat_down( MCW_grapher * grapher )
3520 /* ----------------------------- */
3521 {
3522    int old;
3523 
3524    if( !GRA_VALID(grapher) ) return ;
3525    old = grapher->mat;
3526    grapher->mat--;
3527    if (grapher->mat < 1) grapher->mat = 1;
3528    else if (grapher->mat > grapher->mat_max) grapher->mat = grapher->mat_max;
3529    if (grapher->mat!= old) {
3530       init_mat( grapher ) ;
3531       redraw_graph( grapher , 0 ) ;
3532    }
3533    return ;
3534 }
3535 
3536 /* ----------------------------- */   /* increase matrix and redraw  */
mat_up(MCW_grapher * grapher)3537 void mat_up( MCW_grapher * grapher )
3538 /* ----------------------------- */
3539 {
3540    int old;
3541 
3542    if( !GRA_VALID(grapher) ) return ;
3543    old = grapher->mat;
3544    grapher->mat++;
3545    if (grapher->mat < 1) grapher->mat = 1;
3546    else if (grapher->mat > grapher->mat_max) grapher->mat = grapher->mat_max;
3547    if (grapher->mat!= old) {
3548       init_mat(grapher) ;
3549       redraw_graph(grapher,0) ;
3550    }
3551    return ;
3552 }
3553 
3554 /* ----------------------------- */   /* decrease grid spacing and redraw  */
grid_down(MCW_grapher * grapher)3555 void grid_down( MCW_grapher * grapher )
3556 /* ----------------------------- */
3557 {
3558    int old;
3559 
3560    if( !GRA_VALID(grapher) ) return ;
3561    old = grapher->grid_index;
3562    grapher->grid_index--;
3563    if (grapher->grid_index < 0) grapher->grid_index = 0;
3564    grapher->grid_spacing = grid_ar[grapher->grid_index] ;
3565    grapher->grid_fixed   = 1 ;  /* 02 Apr 2004 */
3566    redraw_graph(grapher,0) ;
3567    return ;
3568 }
3569 
3570 /* ----------------------------- */   /* increase grid spacing and redraw  */
grid_up(MCW_grapher * grapher)3571 void grid_up( MCW_grapher * grapher )
3572 /* ----------------------------- */
3573 {
3574    int old;
3575 
3576    if( !GRA_VALID(grapher) ) return ;
3577    old = grapher->grid_index;
3578    grapher->grid_index++;
3579    if (grapher->grid_index >= GRID_MAX) grapher->grid_index = GRID_MAX - 1;
3580    grapher->grid_spacing = grid_ar[grapher->grid_index] ;
3581    grapher->grid_fixed   = 1 ;  /* 02 Apr 2004 */
3582    redraw_graph(grapher,0) ;
3583    return ;
3584 }
3585 
3586 /*-----------------------------------------------------------------------
3587    Handle all events in an grapher drawing area widget
3588 -------------------------------------------------------------------------*/
3589 
GRA_drawing_EV(Widget w,XtPointer client_data,XEvent * ev,RwcBoolean * continue_to_dispatch)3590 void GRA_drawing_EV( Widget w , XtPointer client_data ,
3591                      XEvent * ev , RwcBoolean * continue_to_dispatch )
3592 {
3593    MCW_grapher * grapher = (MCW_grapher *) client_data ;
3594 
3595 ENTRY("GRA_drawing_EV") ;
3596 
3597    if( ! GRA_REALZ(grapher) ){
3598 if(PRINT_TRACING){
3599 char str[256] ;
3600 sprintf(str,"unrealized grapher! Event type = %d",(int)ev->type) ;
3601 STATUS(str) ; }
3602       EXRETURN ;
3603    }
3604 
3605    if( grapher->valid == 666 ){  /* 06 Jan 1999 */
3606 if(PRINT_TRACING){
3607 char str[256] ;
3608 sprintf(str,"dying grapher! Event type = %d",(int)ev->type) ;
3609 STATUS(str) ; }
3610       EXRETURN ;
3611    }
3612 
3613    switch( ev->type ){
3614 
3615       /*----- redraw -----*/
3616 
3617       case Expose:{
3618          XExposeEvent *event = (XExposeEvent *) ev ;
3619 
3620 if(PRINT_TRACING){
3621 char str[256] ;
3622 sprintf(str,"Expose event with count = %d",event->count) ;
3623 STATUS(str) ; }
3624 
3625          /**
3626              With the first expose, create the new pixmap.
3627              For subsequent ones, just redraw the non-pixmap (overlay) stuff.
3628 
3629              06 Jan 1999: check event count
3630          **/
3631 
3632          XSync( XtDisplay(w) , False ) ;  /* 05 Feb 1999 */
3633 
3634          if( event->count == 0 ){
3635             if( grapher->fd_pxWind == (Pixmap) 0 ){
3636                int width , height ;
3637                MCW_widget_geom( grapher->draw_fd , &width , &height , NULL,NULL ) ;
3638                GRA_new_pixmap( grapher , width , height , 1 ) ;
3639             } else {
3640                GRA_redraw_overlay( grapher ) ;
3641             }
3642 #if defined(DISCARD_EXCESS_EXPOSES)
3643             STATUS("discarding excess Expose events") ;
3644             MCW_discard_events( w , ExposureMask ) ;
3645 #endif
3646          }
3647 
3648       }
3649       break ;
3650 
3651       /*----- take key press -----*/
3652 
3653       case KeyPress:{
3654          XKeyEvent *event = (XKeyEvent *) ev ;
3655          char          buf[32] ;
3656          KeySym        ks=0 ;
3657          int           nbuf ;
3658 
3659 STATUS("KeyPress event") ;
3660 
3661          GRA_timer_stop( grapher ) ;  /* 04 Dec 2003 */
3662 
3663          if( grapher->fd_pxWind != (Pixmap) 0 ){
3664             buf[0] = '\0' ;
3665             nbuf = XLookupString( event , buf , 32 , &ks , NULL ) ;
3666             if( nbuf == 0 ){   /* 24 Jan 2003: substitution for special keys */
3667               switch(ks){
3668                 case XK_KP_Left:
3669                 case XK_Left:      buf[0] = '<' ; break ;
3670                 case XK_KP_Right:
3671                 case XK_Right:     buf[0] = '>' ; break ;
3672                 case XK_KP_Page_Up:
3673                 case XK_Page_Up:   buf[0] = 'Z' ; break ;
3674                 case XK_KP_Page_Down:
3675                 case XK_Page_Down: buf[0] = 'z' ; break ;
3676 #if 0
3677                 case XK_F5:
3678                   MCW_melt_widget( grapher->draw_fd ) ; break ;
3679 #endif
3680               }
3681             }
3682             if( buf[0] != '\0' ) GRA_handle_keypress( grapher , buf , ev ) ;
3683             else if(PRINT_TRACING){
3684                char str[256] ;
3685                sprintf(str,"*** KeyPress was empty!?  nbuf=%d",nbuf) ;
3686                STATUS(str) ;
3687             }
3688          }
3689       }
3690       break ;
3691 
3692       /*----- take button press -----*/
3693 
3694       case ButtonPress:{
3695          XButtonEvent *event = (XButtonEvent *) ev ;
3696          int bx,by , width,height , but=event->button ;
3697          int i, j, gx , gy , mat , xloc,yloc ;
3698          unsigned int but_state ;
3699          int xd,yd,zd ;  /* 19 Mar 2004: for mangling to AFNI indexes */
3700 
3701 STATUS("button press") ;
3702 
3703          GRA_timer_stop(grapher) ;  /* 31 May 2010 = Memorial Day */
3704 
3705          /* 26 Feb 2007: Buttons 4 and 5 = scroll wheel = change time point */
3706 
3707          if( but == Button4 || but == Button5 ){
3708            int dd=(but==Button4)?-1:+1 , tt ;
3709            if( AFNI_yesenv("AFNI_INDEX_SCROLLREV") ) dd = -dd ;
3710            tt = grapher->time_index + dd*NSTRIDE(grapher) ;
3711            EXRONE(grapher) ;
3712            if( tt >= 0 && tt < grapher->status->num_series && NSTRIDE(grapher) == 1 ){
3713              if( grapher->status->send_CB != NULL ){
3714                GRA_cbs cbs ;
3715                cbs.reason = graCR_setindex; cbs.key = tt; cbs.event = NULL;
3716                CALL_sendback( grapher , cbs ) ;
3717              } else {
3718                (void) drive_MCW_grapher( grapher, graDR_setindex, (XtPointer)ITOP(tt)) ;
3719              }
3720            }
3721            MCW_discard_events( w , ButtonPressMask ) ; EXRETURN;
3722          }
3723 
3724          /*-- some other button --*/
3725 
3726          bx = event->x ; by = event->y ; but_state = event->state ;
3727          MCW_discard_events( w , ButtonPressMask ) ;
3728 
3729          /* Button 1 in pixmap logo = toggle on or off  */
3730          /* Button 3 in pixmap logo = raise up the dead */
3731 
3732          if( grapher->glogo_pixmap != XmUNSPECIFIED_PIXMAP &&
3733              bx                    < grapher->glogo_width  &&
3734              grapher->fHIGH - by   < grapher->glogo_height   ){
3735 
3736             if( but == Button1 ){
3737               show_grapher_pixmap = ! show_grapher_pixmap ;
3738               if( XtIsManaged(grapher->option_rowcol) )     /* 04 Nov 1996 */
3739                 XtUnmanageChild(grapher->option_rowcol) ;
3740               else
3741                 XtManageChild(grapher->option_rowcol) ;
3742               redraw_graph( grapher , 0 )  ;
3743             } else if( but == Button3 ){       /* 17 Jun 2011 */
3744                GRA_cbs cbs ;
3745                cbs.reason = graCR_raiseupthedead ;
3746                CALL_sendback( grapher , cbs ) ;
3747             }
3748             break ; /* break out of ButtonPress case */
3749          }
3750 
3751          /* compute which dataset pixel (xloc,yloc) the button press was in */
3752 
3753          /* X11 box for graph (i,j):
3754             x = xorigin[i][j]          .. xorigin[i][j]+gx    (L..R)
3755             y = fHIGH-yorigin[i][j]-gy .. fHIGH-yorigin[i][j] (T..B) */
3756 
3757          gx = grapher->gx ; gy = grapher->gy ; mat = grapher->mat ;
3758 
3759          for( i=0 ; i < mat ; i++ )
3760            if( bx > grapher->xorigin[i][0]      &&
3761                bx < grapher->xorigin[i][0] + gx   ) break ;  /* find in x */
3762 
3763          if( i == mat ) break ; /* break out of ButtonPress case */
3764 
3765          xloc = grapher->xpoint + i - grapher->xc ;
3766 
3767          for( j=0 ; j < mat ; j++ )                           /* find in y */
3768            if( by > grapher->fHIGH - grapher->yorigin[0][j] - gy &&
3769                by < grapher->fHIGH - grapher->yorigin[0][j]        ) break ;
3770 
3771          if( j == mat ) break ; /* break out of ButtonPress case */
3772 
3773          yloc = grapher->ypoint - j + grapher->yc ;
3774 
3775          /* adjust for possible wraparound */
3776 
3777          if (xloc < 0)                    xloc += grapher->status->nx ;
3778          if (xloc >= grapher->status->nx) xloc -= grapher->status->nx ;
3779          if (yloc < 0)                    yloc += grapher->status->ny ;
3780          if (yloc >= grapher->status->ny) yloc -= grapher->status->ny ;
3781 
3782          /* Feb 1998: button 2 --> send message back to AFNI, maybe */
3783          /* 03 Oct 2002: Shift+Button1 has the same effect */
3784 
3785          if( but == Button2 ||
3786              ( but == Button1 && (event->state & ShiftMask) &&
3787                                 !(event->state & ControlMask) ) ){
3788 
3789             if( grapher->button2_enabled && (bx > GL_DLX) ){
3790                GRA_cbs cbs ;
3791                cbs.reason = graCR_button2_points ;
3792                cbs.xcen   = xloc ;
3793                cbs.ycen   = yloc ;
3794                cbs.zcen   = grapher->zpoint ;
3795 #if 0
3796                grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
3797 #else
3798                CALL_sendback( grapher , cbs ) ;
3799 #endif
3800             } else {
3801                BEEPIT ;
3802             }
3803          }
3804 
3805          /* button 1 --> move to new square as center of matrix,
3806                          if it is actually a new center, that is,
3807                          and if graphing is enabled, and if not off left edge */
3808 
3809          if( grapher->fd_pxWind != (Pixmap) 0 &&
3810              but == Button1                   && (bx > GL_DLX) &&
3811              ( (xloc != grapher->xpoint) || (yloc != grapher->ypoint) ) ){
3812 
3813                grapher->xpoint = xloc ;
3814                grapher->ypoint = yloc ;
3815                redraw_graph( grapher , 0 ) ;
3816                send_newinfo( grapher ) ;
3817          }
3818 
3819          /* 22 July 1996:
3820             button 1 in central graph of matrix causes jump to time_index */
3821 
3822          else if( grapher->fd_pxWind != (Pixmap)0 &&
3823                   NPTS(grapher) > 1               && !grapher->textgraph     &&
3824                   (but==Button1)                  && (bx > GL_DLX)           &&
3825                   (xloc == grapher->xpoint)       && yloc == grapher->ypoint &&
3826                   grapher->cen_line != NULL       && grapher->nncen > 1      &&
3827                   NSTRIDE(grapher)  == 1                                        ){
3828 
3829            float dist , dmin=999999.9 ;
3830            int imin = 0 ;
3831 
3832            /*-- 09 Jan 1998: find closest pixel in central graph --*/
3833 
3834            for( i=0 ; i < grapher->nncen ; i++ ){
3835              dist =  abs( bx - grapher->cen_line[i].x )   /* L1 distance */
3836                    + abs( by - grapher->cen_line[i].y ) ;
3837              if( dist < dmin ){ dmin = dist; imin = i; if(dmin == 0) break; }
3838            }
3839            i = imin * NSTRIDE(grapher) + NBOT(grapher) ;
3840 
3841            if( i >= 0 && i < TTOP(grapher) ){
3842              if( grapher->status->send_CB != NULL ){
3843                GRA_cbs cbs ;
3844 
3845                cbs.reason = graCR_setindex ;
3846                cbs.key    = i ;
3847                cbs.event  = ev ;
3848 #if 0
3849                grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
3850 #else
3851                CALL_sendback( grapher , cbs ) ;
3852 #endif
3853              } else {
3854                (void) drive_MCW_grapher( grapher,graDR_setindex,(XtPointer)ITOP(i) );
3855              }
3856            }
3857          }
3858 
3859          /* Button 3 --> popup statistics of this graph */
3860 
3861          if( !AFNI_noenv("AFNI_GRAPH_BUT3") &&  /* stupid Xorg bug */
3862              but == Button3 && !ISONE(grapher) && !grapher->textgraph ){
3863             int ix , iy ;
3864 
3865             ix = xloc - grapher->xpoint + grapher->xc ;
3866                  if( ix <  0            ) ix += grapher->status->nx ;
3867             else if( ix >= grapher->mat ) ix -= grapher->status->nx ;
3868 
3869             iy = grapher->ypoint - yloc + grapher->yc ;
3870                  if( iy <  0            ) iy += grapher->status->ny ;
3871             else if( iy >= grapher->mat ) iy -= grapher->status->ny ;
3872 
3873             if( ix >= 0 && ix < grapher->mat && iy >= 0 && iy < grapher->mat ){
3874                XmString xstr ;
3875                char bmin[16],bmax[16],bmean[16],bstd[16] ;
3876                char bmed[16] , bmad[16] ; /* 08 Mar 2001 */
3877                char bbmv[16] ;            /* 16 Oct 2009 */
3878                char btsn[16] ;            /* 08 Jan 2021 */
3879                char *qstr , *eee ;        /* 07 Mar 2002 */
3880                int nlin , nltop=40 ;      /* 07 Mar 2002 */
3881 
3882                AV_fval_to_char( grapher->tbot[ix][iy]  , bmin ) ;
3883                AV_fval_to_char( grapher->ttop[ix][iy]  , bmax ) ;
3884                AV_fval_to_char( grapher->tmean[ix][iy] , bmean) ;
3885                AV_fval_to_char( grapher->tstd[ix][iy]  , bstd ) ;
3886                AV_fval_to_char( grapher->tsnr[ix][iy]  , btsn ) ;
3887 
3888                AV_fval_to_char( grapher->tmed[ix][iy]  , bmed ) ; /* 08 Mar 2001 */
3889                AV_fval_to_char( 1.4826*grapher->tmad[ix][iy]  , bmad ) ;
3890                AV_fval_to_char( grapher->tbmv[ix][iy]  , bbmv ) ; /* 16 Oct 2009 */
3891 
3892                if( grapher->tuser[ix][iy] == NULL )
3893                  qstr = AFMALL(char, 2048) ;
3894                else
3895                  qstr = AFMALL(char, 2048+strlen(grapher->tuser[ix][iy])) ;
3896 
3897                /* 19 Mar 2004: mangle FD_brick indexes to AFNI indexes */
3898 
3899                xd = xloc; yd = yloc; zd = grapher->zpoint ;
3900 #ifndef DONT_MANGLE_XYZ
3901                { THD_ivec3 id ;
3902                  id = THD_fdind_to_3dind( grapher->getaux , TEMP_IVEC3(xd,yd,zd) ) ;
3903                  xd = id.ijk[0] ; yd = id.ijk[1] ; zd = id.ijk[2] ; }
3904 #endif
3905                sprintf( qstr, "Data Statistics\n"
3906                               "---------------\n"
3907                               "Indexes = %d:%-d@%d\n" /* 19 Mar 2004 */
3908                               "x voxel = %d\n"
3909                               "y voxel = %d\n"
3910                               "z voxel = %d\n"
3911                               "Min     =%s\n"
3912                               "Max     =%s\n"
3913                               "Mean    =%s\n"
3914                               "Median  =%s\n"     /* 08 Mar 2001 */
3915                               "Sigma   =%s\n"
3916                               "Mean/Sig=%s\n"     /* 08 Jan 2021 */
3917                               "MAD*1.48=%s\n"
3918                               "BiwtMidV=%s"  ,    /* 16 Oct 2009 */
3919                         grapher->sbot[ix][iy], grapher->stop[ix][iy], /* 19 Mar 2004 */
3920                         NSTRIDE(grapher) ,                            /* 11 Jun 2020 */
3921                         xd , yd , zd ,
3922                         bmin,bmax,bmean,bmed,bstd,btsn,bmad,bbmv ) ;
3923 
3924                 /** 12 Feb 2015: incorporate x-axis range info for this voxel **/
3925 
3926                 if( grapher->xax_cen != NULL || grapher->xax_tsim != NULL ){
3927                   AV_fval_to_char( grapher->xax_bot[ix][iy]  , bmin ) ;
3928                   AV_fval_to_char( grapher->xax_top[ix][iy]  , bmax ) ;
3929                   sprintf( qstr+strlen(qstr) ,
3930                               "\n"
3931                               "X-ax min=%s\n"
3932                               "X-ax top=%s"  ,
3933                            bmin , bmax ) ;
3934                 }
3935 
3936                 /** 22 Apr 1997: incorporate user string for this voxel **/
3937 
3938                 if( grapher->tuser[ix][iy] != NULL ){
3939                   strcat( qstr , "\n------------------\n" ) ;
3940                   strcat( qstr , grapher->tuser[ix][iy] ) ;
3941                 }
3942 
3943                 /* 07 Mar 2002: if string is too long, popup textwin,
3944                                 otherwise just open a popup window    */
3945 
3946                 eee = getenv( "AFNI_GRAPH_TEXTLIMIT" ) ;
3947                 if( eee != NULL ){
3948                   nlin = strtol( eee , NULL , 10 ) ;
3949                   if( nlin > 0 ) nltop = nlin ;
3950                 }
3951 
3952                 for( nlin=1,eee=qstr ; *eee != '\0' ; eee++ )
3953                   if( *eee == '\n' ) nlin++ ;
3954 
3955                 if( nlin < nltop ){
3956                   xstr = XmStringCreateLtoR( qstr, XmFONTLIST_DEFAULT_TAG ) ;
3957                   XtVaSetValues( grapher->but3_label,XmNlabelString,xstr,NULL );
3958                   XmStringFree( xstr ) ;
3959                   XmMenuPosition( grapher->but3_menu , event ) ; /* where */
3960                   XtManageChild ( grapher->but3_menu ) ;         /* popup */
3961                 } else {
3962                   (void) new_MCW_textwin(grapher->fdw_graph,qstr,TEXT_READONLY);
3963                 }
3964                 free(qstr) ;
3965 
3966             } else {
3967               redraw_graph(grapher,0) ;  /* 11 Nov 1996 */
3968             }
3969          }
3970       }
3971       break ;
3972 
3973       /*----- window changed size -----*/
3974 
3975       case ConfigureNotify:{
3976          XConfigureEvent * event = (XConfigureEvent *) ev ;
3977          int new_width , new_height ;
3978 
3979 STATUS("ConfigureNotify event") ;
3980 
3981          XSync( XtDisplay(w) , False ) ;
3982          GRA_timer_stop(grapher) ;  /* 31 May 2010 = Memorial Day */
3983 
3984          new_width  = event->width ;
3985          new_height = event->height ;
3986 
3987          if( new_width != grapher->fWIDE || new_height != grapher->fHIGH ){
3988            GRA_new_pixmap( grapher , new_width , new_height , 1 ) ;
3989          }
3990       }
3991       break ;
3992 
3993       /*----- ignore all other events -----*/
3994 
3995       default:
3996 #ifdef AFNI_DEBUG
3997 {char str[256]; sprintf(str,"Event code = %d\n",(int)ev->type); STATUS(str);}
3998 #endif
3999       break ;
4000 
4001    } /* end of switch ev->type */
4002 
4003    EXRETURN ;
4004 }
4005 
4006 /*------------------------------------------------------------------
4007    Get a new pixmap for drawing purposes
4008 --------------------------------------------------------------------*/
4009 
GRA_new_pixmap(MCW_grapher * grapher,int new_width,int new_height,int redraw)4010 void GRA_new_pixmap( MCW_grapher * grapher ,
4011                      int new_width , int new_height , int redraw )
4012 {
4013    int ww,hh ;
4014 
4015 ENTRY("GRA_new_pixmap") ;
4016 
4017    if( ! GRA_REALZ(grapher) ) EXRETURN ;
4018 
4019    grapher->fWIDE  = new_width ;
4020    grapher->fHIGH  = new_height ;
4021    grapher->gx_max = new_width  - (GL_DLX + GR_DLX) ;
4022    grapher->gy_max = new_height - (GT_DLY + GB_DLY) ;
4023 
4024    if( grapher->fd_pxWind != (Pixmap) 0 ){
4025 STATUS("freeing old Pixmap") ;
4026       XFreePixmap( grapher->dc->display , grapher->fd_pxWind ) ;
4027    }
4028 
4029 STATUS("allocating new Pixmap") ;
4030    grapher->fd_pxWind = XCreatePixmap( grapher->dc->display ,
4031                                        XtWindow(grapher->draw_fd) ,
4032                                        grapher->fWIDE , grapher->fHIGH,
4033                                        grapher->dc->planes ) ;
4034 
4035    MCW_widget_geom( grapher->option_rowcol , &ww , &hh , NULL,NULL ) ;
4036    XtVaSetValues( grapher->option_rowcol ,
4037 #ifdef WANT_AFNI_BITMAP
4038                      XmNx , grapher->fWIDE - ww - 2 ,
4039 #else
4040                      XmNx , 2 ,
4041 #endif
4042                      XmNy , grapher->fHIGH - hh - 2 ,
4043                   NULL ) ;
4044 
4045    if( redraw ){
4046      init_mat( grapher ) ;
4047      redraw_graph( grapher , 0 ) ;
4048    }
4049 
4050    EXRETURN ;
4051 }
4052 
4053 /*----------------------------------------------------------
4054   Deal with keypresses in a graph window
4055 ------------------------------------------------------------*/
4056 
GRA_handle_keypress(MCW_grapher * grapher,char * buf,XEvent * ev)4057 void GRA_handle_keypress( MCW_grapher *grapher , char *buf , XEvent *ev )
4058 {
4059    int ii=0 ;
4060    static int first_sound=1 ;
4061 
4062 ENTRY("GRA_handle_keypress") ;
4063 
4064    if( buf[0] == '\0' ) EXRETURN ;
4065 
4066 if(PRINT_TRACING){
4067 char str[256] ;
4068 sprintf(str,"buf[0]=%c (%x)",(int)buf[0],(int)buf[0]) ;
4069 STATUS(str); }
4070 
4071    /*** deal with the key sequence 'N <digits> <Enter>' ***/
4072 
4073    /* first 'N' */
4074 
4075    if( AFNI_yesenv("AFNI_GRAPH_ALLOW_SHIFTN") && grapher->key_Nlock==0 && buf[0]=='N' ){
4076      grapher->key_Nlock = 1 ;
4077      HAND_cursorize( grapher->fdw_graph ) ;
4078      HAND_cursorize( grapher->draw_fd ) ;
4079      grapher->key_lock_sum = 0 ;
4080      EXRETURN ;
4081    }
4082 
4083    /* last <Enter> */
4084 
4085    if( grapher->key_Nlock && buf[0] == 13 ){
4086 
4087       /* if have a number, set the graph matrix size */
4088 
4089       if( grapher->key_lock_sum > 0 )
4090          grapher->mat = MIN( grapher->mat_max , grapher->key_lock_sum ) ;
4091 
4092       NORMAL_cursorize( grapher->fdw_graph ) ;
4093       if( ISONE(grapher) )
4094         NORMAL_cursorize( grapher->draw_fd ) ;
4095       else
4096         POPUP_cursorize( grapher->draw_fd ) ;
4097 
4098       init_mat    ( grapher ) ;
4099       redraw_graph( grapher , 0 ) ;
4100       send_newinfo( grapher ) ;
4101       grapher->key_Nlock = grapher->key_lock_sum = 0 ;
4102       EXRETURN ;
4103    }
4104 
4105    /* intermediate <digit> */
4106 
4107    if( grapher->key_Nlock ){
4108       if( isdigit(buf[0]) ){
4109          ii = buf[0] - 48;
4110          grapher->key_lock_sum = MIN( 10000, 10*grapher->key_lock_sum + ii ) ;
4111       }
4112       EXRETURN ;
4113    }
4114 
4115    /*-- other keys are single stroke commands --*/
4116 
4117    MCW_discard_events( grapher->draw_fd , KeyPressMask ) ;
4118 
4119    switch (buf[0]) {
4120 
4121       case '-':
4122       case '+':
4123         if( buf[0] == '-' ) scale_down( grapher ) ;
4124         else                scale_up  ( grapher ) ;
4125         if (PLOT_FORCE_AUTOSCALE) { /* turn it off, user wants to change */
4126          PLOT_FORCE_AUTOSCALE = !PLOT_FORCE_AUTOSCALE;
4127          MCW_invert_widget(grapher->opt_scale_AUTO_pb);
4128         }
4129         redraw_graph( grapher , 0 ) ;
4130       break;
4131 
4132       case 'A':
4133         PLOT_FORCE_AUTOSCALE = !PLOT_FORCE_AUTOSCALE;
4134         MCW_invert_widget(grapher->opt_scale_AUTO_pb);
4135         if (PLOT_FORCE_AUTOSCALE) INFO_message("Graph Viewer: Autoscale forced ON") ;
4136         else                      INFO_message("Graph Viewer: Autoscale forced OFF") ;
4137         redraw_graph( grapher , 0);
4138       break;
4139 
4140       case 'a':
4141         redraw_graph( grapher , PLOTCODE_AUTOSCALE ) ;         /* 03 Feb 1998 */
4142       break ;
4143 
4144       case 'i':
4145         if( !grapher->textgraph && NIGNORE(grapher) > 0 ){     /* 24 May 2005 */
4146           GRA_cbs cbs ;
4147           cbs.reason = graCR_setignore ; cbs.key = grapher->init_ignore - 1 ;
4148           CALL_sendback( grapher , cbs ) ;
4149         } else {
4150           BEEPIT ; WARNING_message("Can't lower Ignore any more") ;
4151         }
4152       break ;
4153 
4154       case 'I':
4155         if( !grapher->textgraph ){                             /* 24 May 2005 */
4156           GRA_cbs cbs ;
4157           cbs.reason = graCR_setignore ; cbs.key = grapher->init_ignore + 1 ;
4158           CALL_sendback( grapher , cbs ) ;
4159         } else {
4160           BEEPIT ; WARNING_message("Can't increase Ignore now") ;
4161         }
4162       break ;
4163 
4164       case 'm':
4165       case 'M':
4166         if( buf[0] == 'm' ) mat_down( grapher ) ;
4167         else                mat_up  ( grapher ) ;
4168         send_newinfo( grapher ) ;
4169       break;
4170 
4171       case 'g':
4172         grid_down( grapher ) ;
4173       break;
4174 
4175       case 'G':
4176         grid_up( grapher ) ;
4177       break;
4178 
4179       case 'h':   /* 05 Jan 1999 */
4180         grapher->HorZ = ! grapher->HorZ ;
4181         redraw_graph( grapher , 0 ) ;
4182       break ;
4183 
4184       case 'q':
4185       case 'Q':
4186         end_fd_graph_CB( NULL , (XtPointer) grapher , NULL ) ;
4187       break ;
4188 
4189       /* modified 07 Aug 2001 to account for more complex baseline scenario */
4190 
4191       case 'b':{
4192         int bbb = grapher->common_base << 1 ;
4193         if( bbb > BASELINE_GLOBAL ) bbb = BASELINE_INDIVIDUAL ;
4194         MCW_set_bbox( grapher->opt_baseline_bbox , bbb ) ;
4195         grapher->common_base = bbb ;
4196         redraw_graph( grapher , 0 ) ;
4197       }
4198       break ;
4199 
4200       case 'B':{                                        /* 29 Jun 2007 */
4201         int bbb=grapher->points_index[4] , ccc ;
4202         ccc = (bbb==4) ? 0 : 4 ;
4203         MCW_set_bbox( grapher->opt_points_bbox[4] , ccc ) ;
4204         grapher->points_index[4] = ccc ;
4205 #if 0
4206         if( DATA_BOXED(grapher) )
4207           MCW_set_bbox( grapher->opt_dplot_bbox , DPLOT_OFF ) ;
4208 #endif
4209         if( !grapher->textgraph ) redraw_graph( grapher , 0 ) ;
4210       }
4211       break ;
4212 
4213       case 2:{   /* keypress ctrl-B = cycle through Data [11 Jan 2021] */
4214         int bbb=grapher->points_index[4] , ccc=bbb ,
4215             nbut=grapher->opt_points_bbox[4]->nbut ;
4216         ccc = (ccc <= 0) ? 1 : 2*ccc ;      /* next highest value */
4217         if( ccc >= 2<<(nbut-1) ) ccc = 0 ;  /* back to beginning */
4218         MCW_set_bbox( grapher->opt_points_bbox[4] , ccc ) ;
4219         grapher->points_index[4] = ccc ;
4220         if( !grapher->textgraph ) redraw_graph( grapher , 0 ) ;
4221       }
4222       break ;
4223 
4224       case 't':{                                        /* 22 Sep 2000 */
4225         int bbb = ! grapher->textgraph ;
4226         MCW_set_bbox( grapher->opt_textgraph_bbox , bbb ) ;
4227         grapher->textgraph = bbb ;
4228         redraw_graph( grapher , 0 ) ;
4229       }
4230       break ;
4231 
4232       case 'S':
4233         MCW_choose_string( grapher->option_rowcol ,
4234                            "Save Image prefix:\n"
4235                            "  * end in .jpg or .png *\n"
4236                            "  * for those formats   *" , NULL ,
4237                            GRA_saver_CB , (XtPointer) grapher ) ;
4238       break ;
4239 
4240       case 's':{  /* 28 May 2020 */
4241         int uu = ! grapher->do_upsam ;
4242         grapher->do_upsam = uu ;
4243         AV_assign_ival( grapher->opt_upsam_av , uu ) ;
4244         init_mat( grapher ) ; redraw_graph( grapher , 0 ) ;
4245       }
4246       break ;
4247 
4248 #define POPUP_SOUND_ERROR_MESSAGE                                               \
4249  do{ if( first_sound ){                                                         \
4250        char msg[2048] ;                                                         \
4251        strcpy(msg," \n" "Cannot play sound:\n" ) ;                              \
4252        if( !GLOBAL_library.local_display )                                      \
4253          strcat( msg+strlen(msg) , " You are running AFNI remotely :(\n" ) ;    \
4254        if( GLOBAL_library.sound_player==NULL )                                  \
4255          strcat( msg+strlen(msg) , " No sound playing program is found :(\n") ; \
4256        strcat( msg+strlen(msg) , " \n") ;                                       \
4257        (void) MCW_popup_message(                                                \
4258                  grapher->fdw_graph , msg , MCW_USER_KILL | MCW_TIMER_KILL ) ;  \
4259  } } while(0)
4260 
4261 #define PRINT_SOUND_INFO_MESSAGE                                                           \
4262  do{ if( first_sound ){                                                                     \
4263          INFO_message("Use K keypress to kill playing sounds:") ;                            \
4264        ININFO_message(" might leave sound file named AFNI_SOUND_TEMP.something.au on disk;"); \
4265        ININFO_message(" if so, you will have to delete such files manually :(") ;             \
4266  } } while(0)
4267 
4268       case 'p':                             /* play sound [20 Aug 2018] */
4269         if( !GLOBAL_library.local_display || GLOBAL_library.sound_player==NULL ){
4270           POPUP_SOUND_ERROR_MESSAGE ;
4271         } else if( grapher->cen_tsim != NULL ){
4272           int ib = NIGNORE(grapher) ;
4273           PRINT_SOUND_INFO_MESSAGE ;
4274           mri_play_sound( grapher->cen_tsim , ib ) ;
4275         }
4276         first_sound = 0 ;
4277       break ;
4278 
4279       case 'P':                             /* play sound [20 Aug 2018] */
4280         if( !GLOBAL_library.local_display || GLOBAL_library.sound_player==NULL ){
4281           POPUP_SOUND_ERROR_MESSAGE ;
4282         } else if( grapher->ave_tsim != NULL && grapher->cen_tsim != NULL ){
4283           int ib = NIGNORE(grapher) ;
4284           MRI_IMARR *imar ; MRI_IMAGE *qim ;
4285           INIT_IMARR(imar) ;
4286           ADDTO_IMARR(imar,grapher->ave_tsim) ; /* glue the 2 */
4287           ADDTO_IMARR(imar,grapher->cen_tsim) ; /* timeseries */
4288           qim = mri_catvol_1D( imar , 2 ) ;     /* together   */
4289           PRINT_SOUND_INFO_MESSAGE ;
4290           mri_play_sound( qim , ib ) ;
4291           mri_free(qim) ; FREE_IMARR(imar) ;
4292         }
4293         first_sound = 0 ;
4294       break ;
4295 
4296       case 'K':                     /* kill sound players [27 Aug 2018] */
4297         if( !first_sound )
4298           kill_sound_players() ;
4299       break ;
4300 
4301       case 'L':
4302         show_grapher_pixmap = ! show_grapher_pixmap ;
4303         if( grapher->glogo_pixmap != XmUNSPECIFIED_PIXMAP )
4304            redraw_graph( grapher , 0 ) ;
4305       break ;
4306 
4307       case '<': case ',':   /* change time point */
4308       case '>': case '.':
4309       case '[': case ']':
4310       case '1':
4311       case 'l':{
4312          int di ;
4313          EXRONE(grapher) ;  /* 22 Sep 2000 */
4314          di = NSTRIDE(grapher) ; /* 11 Jun 2020 */
4315               if( buf[0]=='<' || buf[0]==',' || buf[0]=='[' ) ii = grapher->time_index-di;
4316          else if( buf[0]=='>' || buf[0]=='.' || buf[0]==']' ) ii = grapher->time_index+di;
4317          else if( buf[0] == '1'  ) ii = 1 ;
4318          else if( buf[0] == 'l'  ) ii = grapher->status->num_series-1;
4319 
4320          ii = (ii+grapher->status->num_series) % grapher->status->num_series ;
4321          if( ii >= 0 && ii < grapher->status->num_series && di == 1 ){
4322            if( grapher->status->send_CB != NULL ){
4323              GRA_cbs cbs ;
4324 
4325              cbs.reason = graCR_setindex ;
4326              cbs.key    = ii;
4327              cbs.event  = NULL ;
4328 #if 0
4329              grapher->status->send_CB( grapher, grapher->getaux, &cbs ) ;
4330 #else
4331              CALL_sendback( grapher , cbs ) ;
4332 #endif
4333            } else {
4334              (void) drive_MCW_grapher( grapher, graDR_setindex, (XtPointer)ITOP(ii)) ;
4335            }
4336          }
4337       }
4338       break ;
4339 
4340       case 'v':  /* 04 Dec 2003: video */
4341       case 'V':
4342         if( grapher->status->num_series > 1 ){
4343           grapher->timer_func  = GRA_TIMERFUNC_INDEX ;
4344           grapher->timer_delay = (int) AFNI_numenv("AFNI_VIDEO_DELAY") ;
4345           if( grapher->timer_delay <= 0 ) grapher->timer_delay = 1 ;
4346           grapher->timer_param = (buf[0] == 'v') ? 1 : -1 ;
4347           grapher->timer_id    =
4348            XtAppAddTimeOut( XtWidgetToApplicationContext(grapher->opt_quit_pb),
4349                             grapher->timer_delay , GRA_timer_CB , grapher ) ;
4350         } else {
4351           BEEPIT ; WARNING_message("Can't video current graph window") ;
4352         }
4353       break ;
4354 
4355       case 'r':
4356       case 'R':
4357         if( grapher->status->num_series > 1 ){
4358           grapher->timer_func  = GRA_TIMERFUNC_BOUNCE ;
4359           grapher->timer_delay = (int) AFNI_numenv("AFNI_VIDEO_DELAY") ;
4360           if( grapher->timer_delay <= 0 ) grapher->timer_delay = 1 ;
4361           grapher->timer_param = (buf[0] == 'r') ? 1 : -1 ;
4362           grapher->timer_id    =
4363            XtAppAddTimeOut( XtWidgetToApplicationContext(grapher->opt_quit_pb),
4364                             grapher->timer_delay , GRA_timer_CB , grapher ) ;
4365         } else {
4366           BEEPIT ; WARNING_message("Can't video current graph window") ;
4367         }
4368       break ;
4369 
4370       case 'F':
4371         grapher->thresh_fade = !grapher->thresh_fade ;
4372         MCW_set_bbox( grapher->opt_tfade_bbox , grapher->thresh_fade ) ;
4373         redraw_graph( grapher , 0 ) ;
4374       break ;
4375 
4376       case 'z':  /* change slice */
4377       case 'Z':
4378         if( buf[0] == 'z' ){
4379           grapher->zpoint -- ;
4380           if( grapher->zpoint < 0 ) grapher->zpoint = grapher->status->nz - 1 ;
4381         } else {
4382           grapher->zpoint ++ ;
4383           if( grapher->zpoint >= grapher->status->nz ) grapher->zpoint = 0 ;
4384         }
4385         redraw_graph( grapher , 0 ) ;
4386         send_newinfo( grapher ) ;
4387       break ;
4388 
4389       case 'w':{
4390          char * wcfname ;
4391          int ndig , ll ;
4392          MRI_IMAGE * tsim ;
4393          int xd,yd,zd ;     /* 24 Sep 1999 */
4394 
4395          /* EXRONE(grapher) ; */ /* 22 Sep 2000 */
4396 
4397          ll   = MAX( grapher->status->nx , grapher->status->ny ) ;
4398          ll   = MAX( grapher->status->nz , ll ) ;
4399          ndig = (ll < 1000) ? 3 : 4 ;
4400 
4401          ll   = 3*ndig + 16 ;
4402          if( Grapher_Stuff.wcsuffix != NULL )
4403             ll += strlen(Grapher_Stuff.wcsuffix) ;
4404          wcfname = (char *) XtMalloc(ll) ;
4405 
4406          /* 24 Sep 1999: mangle the name for the output */
4407 
4408          xd = grapher->xpoint; yd = grapher->ypoint; zd = grapher->zpoint;
4409 #ifndef DONT_MANGLE_XYZ
4410          { THD_ivec3 id;
4411            id = THD_fdind_to_3dind( grapher->getaux, TEMP_IVEC3(xd,yd,zd) );
4412            xd = id.ijk[0]; yd = id.ijk[1]; zd = id.ijk[2]; }
4413 #endif
4414 
4415          if( Grapher_Stuff.wcsuffix != NULL )
4416             sprintf(wcfname,"%0*d_%0*d_%0*d.%s.1D" ,
4417                     ndig,xd , ndig,yd , ndig,zd ,
4418                               Grapher_Stuff.wcsuffix ) ;
4419          else
4420             sprintf(wcfname,"%0*d_%0*d_%0*d.1D" ,
4421                     ndig,xd , ndig,yd , ndig,zd  ) ;
4422 
4423          ll = grapher->xpoint +
4424               grapher->ypoint * grapher->status->nx +
4425               grapher->zpoint * grapher->status->nx * grapher->status->ny ;
4426 
4427          tsim = GRA_getseries( grapher , ll ) ;
4428          if( tsim != NULL ){
4429            mri_write_1D( wcfname , tsim ) ;  /* 16 Nov 1999: replaces mri_write_ascii */
4430            mri_free( tsim ) ;
4431          }
4432          myXtFree(wcfname) ;
4433       }
4434       break ;
4435 
4436       case 'C':{   /* Change colors all at once [16 Apr 2019] */
4437         int fc = (grapher->fixed_colors_setting+1) % NUM_FIXED_COLORS_SETTING ;
4438         int ii,jj ;
4439         for( ii=0 ; ii < NUM_COLOR_ITEMS ; ii++ ){
4440           jj = GRA_COLOR(fixed_colors[fc][ii]) ;         /* color index */
4441           grapher->color_index[ii] = jj ;
4442           AV_assign_ival(grapher->opt_color_av[ii],jj) ; /* change  menu */
4443         }
4444         grapher->fixed_colors_setting = fc ;  /* for the next time through */
4445         redraw_graph(grapher,0) ;             /* show the new beauty */
4446       }
4447       break ;
4448 
4449       /*--- At this point, have a key not handled here.
4450             Call the creator to see if ze wishes to deal with it. ---*/
4451 
4452       default:
4453         if( grapher->status->send_CB != NULL ){
4454           GRA_cbs cbs ;
4455 
4456           cbs.reason = graCR_keypress ;
4457           cbs.key    = buf[0] ;
4458           cbs.event  = ev ;
4459 #if 0
4460           grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
4461 #else
4462           CALL_sendback( grapher , cbs ) ;
4463 #endif
4464         }
4465       break ;
4466    }
4467 
4468    EXRETURN ;
4469 }
4470 
4471 /*--------------------------------------------------------------------------
4472    06 Jan 1999: handle death after a timeout.
4473 ----------------------------------------------------------------------------*/
4474 
GRA_quit_timeout_CB(XtPointer client_data,XtIntervalId * id)4475 void GRA_quit_timeout_CB( XtPointer client_data , XtIntervalId * id )
4476 {
4477    MCW_grapher * grapher = (MCW_grapher *) client_data ;
4478 
4479 ENTRY("GRA_quit_timeout_CB") ;
4480    GRA_handle_keypress( grapher , "q" , NULL ) ;
4481    EXRETURN ;
4482 }
4483 
4484 /*--------------------------------------------------------------------------
4485    Handle buttons from the opt menu
4486 ----------------------------------------------------------------------------*/
4487 
GRA_opt_CB(Widget w,XtPointer client_data,XtPointer call_data)4488 void GRA_opt_CB( Widget w , XtPointer client_data , XtPointer call_data )
4489 {
4490    MCW_grapher * grapher = (MCW_grapher *) client_data ;
4491 
4492 ENTRY("GRA_opt_CB") ;
4493 
4494    if( w == grapher->opt_scale_down_pb ){
4495       GRA_handle_keypress( grapher , "-" , NULL ) ;
4496       EXRETURN ;
4497    }
4498 
4499    if( w == grapher->opt_scale_up_pb ){
4500       GRA_handle_keypress( grapher , "+" , NULL ) ;
4501       EXRETURN ;
4502    }
4503 
4504    if( w == grapher->opt_scale_AUTO_pb ){
4505       GRA_handle_keypress( grapher , "A" , NULL ) ;
4506       EXRETURN ;
4507    }
4508 
4509    if( w == grapher->opt_scale_auto_pb ){
4510       GRA_handle_keypress( grapher , "a" , NULL ) ;
4511       EXRETURN ;
4512    }
4513 
4514    if( w == grapher->opt_grid_down_pb ){
4515       GRA_handle_keypress( grapher , "g" , NULL ) ;
4516       EXRETURN ;
4517    }
4518 
4519    if( w == grapher->opt_grid_up_pb ){
4520       GRA_handle_keypress( grapher , "G" , NULL ) ;
4521       EXRETURN ;
4522    }
4523 
4524    if( w == grapher->opt_grid_auto_pb ){     /* 02 Apr 2004 */
4525      auto_grid( grapher , NPTS(grapher) ) ;
4526      redraw_graph(grapher,0) ;
4527      EXRETURN ;
4528    }
4529 
4530    if( w == grapher->opt_grid_HorZ_pb ){     /* 05 Jan 1999 */
4531       GRA_handle_keypress( grapher , "h" , NULL ) ;
4532       EXRETURN ;
4533    }
4534 
4535    if( w == grapher->opt_slice_down_pb ){
4536       GRA_handle_keypress( grapher , "z" , NULL ) ;
4537       EXRETURN ;
4538    }
4539 
4540    if( w == grapher->opt_slice_up_pb ){
4541       GRA_handle_keypress( grapher , "Z" , NULL ) ;
4542       EXRETURN ;
4543    }
4544 
4545    if( w == grapher->opt_mat_down_pb ){
4546       GRA_handle_keypress( grapher , "m" , NULL ) ;
4547       EXRETURN ;
4548    }
4549 
4550    if( w == grapher->opt_mat_up_pb ){
4551       GRA_handle_keypress( grapher , "M" , NULL ) ;
4552       EXRETURN ;
4553    }
4554 
4555 #if 0
4556    if( w == grapher->opt_color_up_pb ){
4557       GRA_handle_keypress( grapher , "r" , NULL ) ;
4558       EXRETURN ;
4559    }
4560 #endif
4561 
4562    if( w == grapher->opt_quit_pb ){
4563 #if 0
4564       GRA_handle_keypress( grapher , "q" , NULL ) ;
4565 #else
4566 STATUS("User pressed Done button: starting timeout") ;
4567       grapher->valid = 666 ;
4568       (void) XtAppAddTimeOut( XtWidgetToApplicationContext(w) ,
4569                               50 , GRA_quit_timeout_CB , grapher ) ;
4570 #endif
4571       EXRETURN ;
4572    }
4573 
4574    if( w == grapher->opt_save_pb ){
4575       GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
4576       GRA_handle_keypress( grapher , "S" , NULL ) ;
4577       EXRETURN ;
4578    }
4579 
4580    if( w == grapher->opt_write_center_pb ){
4581       GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
4582       GRA_handle_keypress( grapher , "w" , NULL ) ;
4583       EXRETURN ;
4584    }
4585 
4586    if( w == grapher->opt_write_suffix_pb ){
4587 /*      EXRONE(grapher) ; */ /* 22 Sep 2000 */
4588       GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
4589       MCW_choose_string( grapher->option_rowcol ,
4590                          "'Write Center' Suffix:" , Grapher_Stuff.wcsuffix ,
4591                          GRA_wcsuffix_choose_CB , NULL ) ;
4592       EXRETURN ;
4593    }
4594 
4595    if( w == grapher->opt_scale_choose_pb ){
4596      MCW_choose_integer( grapher->option_rowcol , "Scale" ,
4597                          -9999 , 9999 , (int)(grapher->fscale) ,
4598                          GRA_scale_choose_CB , (XtPointer) grapher ) ;
4599      EXRETURN ;
4600    }
4601 
4602 #ifndef USE_OPTMENUS
4603    if( w == grapher->opt_mat_choose_pb ){
4604      MCW_choose_integer( grapher->option_rowcol , "Matrix" ,
4605                          1 , grapher->mat_max , grapher->mat ,
4606                          GRA_mat_choose_CB , (XtPointer) grapher ) ;
4607      EXRETURN ;
4608    }
4609 #endif
4610 
4611    if( w == grapher->opt_grid_choose_pb ){
4612      MCW_choose_integer( grapher->option_rowcol , "Grid" ,
4613                          1 , grid_ar[GRID_MAX-1] , grapher->grid_spacing ,
4614                          GRA_grid_choose_CB , (XtPointer) grapher ) ;
4615      EXRETURN ;
4616    }
4617 
4618    if( w == grapher->opt_pin_choose_pb ){   /* 19 Mar 2004 */
4619      char *lvec[3] = { "Bot..." , "Top..." , "Stride" } ;
4620      float fvec[3] ;
4621      int nav ; MCW_arrowval **av ;
4622      fvec[0] = grapher->pin_bot ;
4623      fvec[1] = grapher->pin_top ;
4624      fvec[2] = grapher->pin_stride ;
4625      MCW_choose_vector( grapher->option_rowcol , "Graph Pins: Bot..Top-1" ,
4626                         3 , lvec,fvec ,
4627                         GRA_pin_choose_CB , (XtPointer)grapher ) ;
4628      /* adjust some stuff on the 'vector' choosers [08 Jun 2020] */
4629      av = MCW_choose_vector_avarray( &nav ) ;
4630      av[0]->fmin = av[0]->imin = 0 ;                    /* change min for Bot */
4631      av[1]->fmin = av[1]->imin = 0 ;                           /* min for Top */
4632      av[1]->fmax = av[1]->imax = grapher->status->num_series ; /* max for Top */
4633      av[2]->fmin = av[2]->imin = 1 ;                        /* min for Stride */
4634      av[2]->fmax = av[2]->imax = MAX_STRIDE ;               /* max for Stride */
4635      MCW_reghint_children( av[0]->wrowcol , "First index to graph" ) ;
4636      MCW_reghint_children( av[1]->wrowcol , "One AFTER last index to graph" ) ;
4637      MCW_reghint_children( av[2]->wrowcol , "Spacing between graphed indexes") ;
4638      EXRETURN ;
4639    }
4640 
4641 #ifndef USE_OPTMENUS
4642    if( w == grapher->opt_slice_choose_pb && grapher->status->nz > 1 ){
4643      MCW_choose_integer( grapher->option_rowcol , "Slice" ,
4644                          0 , grapher->status->nz - 1 , grapher->zpoint ,
4645                          GRA_slice_choose_CB , (XtPointer) grapher ) ;
4646      EXRETURN ;
4647    }
4648 #endif
4649 
4650    /*** 09 Jan 1998: x-axis stuff ***/
4651 
4652    if( w == grapher->opt_xaxis_clear_pb ){
4653      mri_free( grapher->xax_tsim ) ; grapher->xax_tsim = NULL ;
4654      mri_free( grapher->xax_cen  ) ; grapher->xax_cen  = NULL ; /* 12 Feb 2015 */
4655      grapher->xax_dset = NULL ;  /* 10 Feb 2015 */
4656      DESTROY_FD_BRICK(grapher->xax_fdbr) ; grapher->xax_fdbr = NULL ;
4657      GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
4658      redraw_graph( grapher , 0 ) ;
4659      EXRETURN ;
4660    }
4661 
4662    if( w == grapher->opt_xaxis_pick_pb ){
4663      GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
4664      if( IMARR_COUNT(GLOBAL_library.timeseries) > 0 ){
4665        POPDOWN_strlist_chooser ;
4666        MCW_choose_timeseries( grapher->fdw_graph , "Graph x-axis" ,
4667                               GLOBAL_library.timeseries , -1 ,
4668                               GRA_pick_xaxis_CB , (XtPointer) grapher ) ;
4669      } else {
4670        (void) MCW_popup_message(
4671                  grapher->option_rowcol ,
4672                  "No timeseries library\nexists to pick from!" ,
4673                  MCW_USER_KILL | MCW_TIMER_KILL ) ;
4674      }
4675      EXRETURN ;
4676    }
4677 
4678 #ifdef BE_AFNI_AWARE
4679    if( w == grapher->opt_xaxis_dset_pb ){  /* 09 Feb 2015 */
4680      FD_brick *br = (FD_brick *)grapher->getaux ;
4681      Three_D_View *im3d = (Three_D_View *)br->parent ;
4682      int vv , ii ; THD_3dim_dataset *dset ;
4683 
4684      if( !IM3D_OPEN(im3d) ){
4685        ERROR_message("can't access AFNI controller for grapher?!?") ;
4686        EXRETURN ;
4687      }
4688 
4689      cdds.ndset = 0 ;
4690      cdds.dset = (THD_3dim_dataset **)realloc(cdds.dset,
4691                                               sizeof(THD_3dim_dataset *)
4692                                              *im3d->ss_now->num_dsset  ) ;
4693      cdds.cb = GRA_finalize_xaxis_dset_CB ;
4694      cdds.parent = grapher ;
4695      vv = im3d->vinfo->view_type ;
4696      for( ii=0 ; ii < im3d->ss_now->num_dsset ; ii++ ){
4697        dset = GET_SESSION_DSET(im3d->ss_now, ii, vv) ;
4698        if( ISVALID_DSET(dset)                             &&  /* qualifications */
4699            EQUIV_GRIDS(dset,im3d->anat_now)               &&
4700            DSET_NVALS(dset) >= DSET_NVALS(im3d->anat_now) &&
4701            DSET_INMEMORY(dset)                              )
4702          cdds.dset[cdds.ndset++] = dset ;
4703      }
4704      if( cdds.ndset > 0 ){
4705        POPDOWN_timeseries_chooser ;
4706        AFNI_choose_dataset_CB( grapher->fdw_graph , im3d , &cdds ) ;
4707      } else {
4708        MCW_popup_message( grapher->fdw_graph ,
4709                             " \n"
4710                             "**  No usable datasets  **\n"
4711                             "** available for X-axis **\n " ,
4712                           MCW_USER_KILL | MCW_TIMER_KILL ) ;
4713      }
4714      EXRETURN ;
4715    }
4716 #endif
4717 
4718    if( w == grapher->opt_xaxis_center_pb ){
4719      EXRONE(grapher) ;           /* 22 Sep 2000 */
4720      GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
4721      if( grapher->cen_tsim != NULL ){
4722        mri_free( grapher->xax_tsim ) ;
4723        grapher->xax_tsim = mri_to_float( grapher->cen_tsim ) ;
4724        grapher->xax_dset = NULL ;  /* 10 Feb 2015 */
4725        DESTROY_FD_BRICK(grapher->xax_fdbr) ; grapher->xax_fdbr = NULL ;
4726        mri_free(grapher->xax_cen) ; grapher->xax_cen = NULL ; /* 12 Feb 2015 */
4727        redraw_graph(grapher,0) ;
4728      } else {
4729        BEEPIT ; WARNING_message("graph center time series not defined!?") ;
4730      }
4731      EXRETURN ;
4732    }
4733 
4734    /** 07 Aug 2001: Set Global baseline **/
4735 
4736    if( w == grapher->opt_baseline_setglobal_pb ){
4737      MCW_choose_integer( grapher->option_rowcol , "Global Baseline" ,
4738                          -29999 , 29999 , (int)(grapher->global_base) ,
4739                          GRA_finalize_global_baseline_CB ,
4740                          (XtPointer) grapher ) ;
4741      EXRETURN ;
4742    }
4743 
4744    /** shouldn't get to here, but who knows? **/
4745 
4746    EXRETURN ;
4747 }
4748 
4749 /*----------------------------------------------------------------------*/
4750 
GRA_fixup_xaxis(MCW_grapher * grapher,MRI_IMAGE * tsim)4751 void GRA_fixup_xaxis( MCW_grapher *grapher , MRI_IMAGE *tsim )  /* 09 Jan 1998 */
4752 {
4753    int ii , npt , nx , ibot , nover=0 , pbot,ptop ;
4754    float top,bot , fac ;
4755    float * xxx ;
4756 
4757 ENTRY("GRA_fixup_xaxis") ;
4758 
4759    if( !GRA_VALID(grapher) || tsim == NULL ) EXRETURN ;
4760 
4761    ptop = TTOP(grapher) ; pbot = TBOT(grapher) ;
4762    npt = ptop ; nx = tsim->nx ; npt = MIN(npt,nx) ;
4763    xxx = MRI_FLOAT_PTR(tsim) ; if( xxx == NULL ) EXRETURN ;
4764 
4765    ibot = NIGNORE(grapher) ;
4766    if( ibot >= npt-1 ) ibot = 0 ;
4767    ibot = MAX(ibot,pbot) ;
4768 
4769    /* find range over plotting interval (ibot..npt-1) */
4770 
4771    top = -WAY_BIG ; bot = WAY_BIG ;
4772    for( ii=ibot ; ii < npt ; ii++ ){
4773      if( xxx[ii] < WAY_BIG ){
4774        top = MAX(top,xxx[ii]) ; bot = MIN(bot,xxx[ii]) ;
4775      } else {
4776        nover++ ;
4777      }
4778    }
4779    if( bot >= top ){         /* no range to data? replace with ramp */
4780      fac = 1.0f/(nx-1.0f) ;
4781      for( ii=0 ; ii < nx ; ii++ ){
4782        if( xxx[ii] < WAY_BIG ) xxx[ii] = ii*fac ;
4783      }
4784      EXRETURN ;
4785    }
4786 
4787    /* scale all of the timeseries */
4788 
4789    fac = 1.0 / (top-bot) ;
4790    for( ii=0 ; ii < nx ; ii++ ){
4791      if( xxx[ii] < WAY_BIG ) xxx[ii] = fac * (xxx[ii]-bot) ;
4792      else                    xxx[ii] = 0.0 ;
4793    }
4794 
4795    EXRETURN ;
4796 }
4797 
4798 /*----------------------------------------------------------------------*/
4799 
GRA_pick_xaxis_CB(Widget wcall,XtPointer cd,MCW_choose_cbs * cbs)4800 void GRA_pick_xaxis_CB( Widget wcall , XtPointer cd , MCW_choose_cbs *cbs )
4801 {
4802    MCW_grapher *grapher = (MCW_grapher *) cd ;
4803    int its ;
4804    MRI_IMAGE *tsim ;
4805 
4806 ENTRY("GRA_pick_xaxis_CB") ;
4807 
4808    if( !GRA_VALID(grapher) || cbs->reason != mcwCR_timeseries ) EXRETURN ;
4809    GRA_timer_stop( grapher ) ;
4810 
4811    its = cbs->ival ;
4812    if( its >= 0 && its < IMARR_COUNT(GLOBAL_library.timeseries) ){
4813      tsim = IMARR_SUBIMAGE(GLOBAL_library.timeseries,its) ;
4814      mri_free( grapher->xax_tsim ) ;
4815      grapher->xax_tsim = mri_to_float(tsim) ;  /* a copy */
4816      grapher->xax_dset = NULL ;  /* 10 Feb 2015 */
4817      DESTROY_FD_BRICK(grapher->xax_fdbr) ; grapher->xax_fdbr = NULL ;
4818      mri_free(grapher->xax_cen) ; grapher->xax_cen = NULL ; /* 12 Feb 2015 */
4819    } else {
4820      mri_free( grapher->xax_tsim ) ; grapher->xax_tsim = NULL ;
4821    }
4822 
4823    redraw_graph( grapher , 0 ) ;
4824    EXRETURN ;
4825 }
4826 
4827 #ifdef BE_AFNI_AWARE
4828 /*----------------------------------------------------------------------*/
4829 /* Stuff for dataset as X-axis [09 Feb 2015] */
4830 
GRA_finalize_xaxis_dset_CB(Widget w,XtPointer cd,MCW_choose_cbs * cbs)4831 static void GRA_finalize_xaxis_dset_CB( Widget w, XtPointer cd, MCW_choose_cbs *cbs )
4832 {
4833    Three_D_View *im3d    = (Three_D_View *)cd ;
4834    MCW_grapher  *grapher = (MCW_grapher *)cdds.parent ;
4835    FD_brick      *br     = (FD_brick *)grapher->getaux ;
4836    THD_3dim_dataset *dset ;
4837    int ival ;
4838 
4839 ENTRY("GRA_finalize_xaxis_dset_CB") ;
4840 
4841    if( !GRA_REALZ(grapher) || cbs == NULL ){ POPDOWN_strlist_chooser; EXRETURN; }
4842    if( br == NULL )                        { POPDOWN_strlist_chooser; EXRETURN; }
4843    if( !IM3D_OPEN(im3d) )                  { POPDOWN_strlist_chooser; EXRETURN; }
4844 
4845    ival = cbs->ival ;
4846    if( ival < 0 || ival >= cdds.ndset )    { POPDOWN_strlist_chooser; EXRETURN; }
4847 
4848    dset = cdds.dset[ival] ;
4849    if( DSET_NVALS(dset) >= DSET_NVALS(im3d->anat_now) &&
4850        EQUIV_GRIDS(dset,im3d->anat_now)                  ){
4851      grapher->xax_dset = (void *)dset ;
4852    } else {
4853      grapher->xax_dset = NULL ;
4854    }
4855 
4856    /* make FD_brick corresponding to the one being viewed in this grapher */
4857 
4858    DESTROY_FD_BRICK(grapher->xax_fdbr) ; grapher->xax_fdbr = NULL ;
4859    if( grapher->xax_dset != NULL ){
4860      FD_brick *br = (FD_brick *)grapher->getaux ;
4861      grapher->xax_fdbr = THD_3dim_dataset_to_brick( dset , br->a123.ijk[0] ,
4862                                                            br->a123.ijk[1] ,
4863                                                            br->a123.ijk[2]  ) ;
4864    }
4865 
4866    mri_free( grapher->xax_tsim ) ; grapher->xax_tsim = NULL ;
4867 
4868    redraw_graph(grapher,0) ;
4869    EXRETURN ;
4870 }
4871 #endif
4872 
4873 /*----------------------------------------------------------------------
4874    Callbacks from popup choosers
4875 ------------------------------------------------------------------------*/
4876 
GRA_wcsuffix_choose_CB(Widget wcaller,XtPointer cd,MCW_choose_cbs * cbs)4877 void GRA_wcsuffix_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs *cbs )
4878 {
4879    int ll , ii ;
4880 
4881 ENTRY("GRA_wcsuffix_choose_CB") ;
4882 
4883    if( cbs->reason != mcwCR_string ||
4884        cbs->cval   == NULL         || (ll=strlen(cbs->cval)) == 0 ){
4885 
4886      BEEPIT ; WARNING_message("illegal suffix choice!?") ; EXRETURN ;
4887    }
4888 
4889    for( ii=0 ; ii < ll ; ii++ ){
4890      if( iscntrl(cbs->cval[ii]) ||
4891          isspace(cbs->cval[ii]) ||
4892          cbs->cval[ii] == '/'     ){
4893 
4894         BEEPIT ; WARNING_message("illegal suffix choice?!") ; EXRETURN ;
4895      }
4896    }
4897 
4898    if( Grapher_Stuff.wcsuffix != NULL ) myXtFree(Grapher_Stuff.wcsuffix) ;
4899 
4900    Grapher_Stuff.wcsuffix = XtNewString(cbs->cval) ;
4901    EXRETURN ;
4902 }
4903 
4904 /*-----------------------------------------------------------------------------*/
4905 
4906 #ifdef USE_OPTMENUS
GRA_mat_choose_CB(MCW_arrowval * cbs,XtPointer cd)4907 void GRA_mat_choose_CB( MCW_arrowval * cbs , XtPointer cd )
4908 #else
4909 void GRA_mat_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs *cbs )
4910 #endif
4911 {
4912    MCW_grapher *grapher = (MCW_grapher *) cd ;
4913 
4914 ENTRY("GRA_mat_choose_CB") ;
4915 
4916    if( ! GRA_VALID(grapher) || cbs->ival < 1 ) EXRETURN ;
4917 
4918    grapher->mat = MIN( grapher->mat_max , cbs->ival ) ;
4919    init_mat    ( grapher ) ;
4920    redraw_graph( grapher , 0 ) ;
4921    send_newinfo( grapher ) ;
4922    EXRETURN ;
4923 }
4924 
4925 /*-----------------------------------------------------------------------------*/
4926 
GRA_scale_choose_CB(Widget wcaller,XtPointer cd,MCW_choose_cbs * cbs)4927 void GRA_scale_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs *cbs )
4928 {
4929    MCW_grapher *grapher = (MCW_grapher *) cd ;
4930 
4931 ENTRY("GRA_scale_choose_CB") ;
4932 
4933    if( ! GRA_VALID(grapher) ) EXRETURN ;
4934 
4935    grapher->fscale = cbs->fval ;
4936    redraw_graph( grapher , 0 ) ;
4937    EXRETURN ;
4938 }
4939 
4940 /*-----------------------------------------------------------------------------*/
4941 
GRA_grid_choose_CB(Widget wcaller,XtPointer cd,MCW_choose_cbs * cbs)4942 void GRA_grid_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs *cbs )
4943 {
4944    MCW_grapher *grapher = (MCW_grapher *) cd ;
4945 
4946 ENTRY("GRA_grid_choose_CB") ;
4947 
4948    if( ! GRA_VALID(grapher) ) EXRETURN ;
4949    grapher->grid_spacing = cbs->ival ;
4950    grapher->grid_fixed   = 1 ;  /* 02 Apr 2004 */
4951    redraw_graph(grapher,0) ;
4952    EXRETURN ;
4953 }
4954 
4955 /*-----------------------------------------------------------------------------*/
4956 
GRA_pin_choose_CB(Widget wcaller,XtPointer cd,MCW_choose_cbs * cbs)4957 void GRA_pin_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs *cbs )
4958 {
4959    MCW_grapher *grapher = (MCW_grapher *) cd ;
4960    float *vec = (float *)(cbs->cval) ;
4961    int pb=(int)vec[0], pt=(int)vec[1], ps=(int)vec[2], pvec[3] ;
4962 
4963 ENTRY("GRA_pin_choose_CB") ;
4964 
4965    GRA_timer_stop( grapher ) ;
4966 
4967    /* check for criminal behaviour */
4968 
4969    if( ps <= 0 ) ps = 1 ;
4970    if( pt > grapher->status->num_series ) pt = grapher->status->num_series ;
4971 
4972    if( pb >= grapher->status->num_series-2 ||
4973        ps >  MAX_STRIDE                    ||
4974        (pt > 0 && NABC(pb,pt,ps) < 2)        ){   /* stupid user */
4975 
4976       BEEPIT ; WARNING_message("Illegal Pin/Stride indexes!?") ; EXRETURN ;
4977    }
4978 
4979    pvec[0] = pb ;
4980    pvec[1] = pt ;
4981    pvec[2] = ps ;
4982    drive_MCW_grapher( grapher , graDR_setpins , (XtPointer)pvec ) ;
4983    EXRETURN ;
4984 }
4985 
4986 /*-----------------------------------------------------------------------------*/
4987 
GRA_ggap_CB(MCW_arrowval * cbs,XtPointer cd)4988 void GRA_ggap_CB( MCW_arrowval *cbs , XtPointer cd )  /* 12 Jan 1998 */
4989 {
4990    MCW_grapher *grapher = (MCW_grapher *) cd ;
4991    int gg ;
4992 
4993 ENTRY("GRA_ggap_CB") ;
4994 
4995    if( ! GRA_VALID(grapher) ) EXRETURN ;
4996 
4997    gg = grapher->ggap ; grapher->ggap = cbs->ival ;
4998    if( gg != grapher->ggap ){
4999      init_mat( grapher ) ; redraw_graph( grapher , 0 ) ;
5000    }
5001 
5002    EXRETURN ;
5003 }
5004 
5005 /*-----------------------------------------------------------------------------*/
5006 
GRA_gthick_CB(MCW_arrowval * cbs,XtPointer cd)5007 void GRA_gthick_CB( MCW_arrowval *cbs , XtPointer cd )  /* 06 Oct 2004 */
5008 {
5009    MCW_grapher *grapher = (MCW_grapher *) cd ;
5010    int gg ;
5011 
5012 ENTRY("GRA_gthick_CB") ;
5013 
5014    if( ! GRA_VALID(grapher) ) EXRETURN ;
5015 
5016    gg = grapher->gthick ; grapher->gthick = cbs->ival ;
5017    if( gg != grapher->gthick ){
5018      init_mat( grapher ) ; redraw_graph( grapher , 0 ) ;
5019    }
5020 
5021    EXRETURN ;
5022 }
5023 
5024 /*-----------------------------------------------------------------------------*/
5025 
GRA_upsam_CB(MCW_arrowval * cbs,XtPointer cd)5026 void GRA_upsam_CB( MCW_arrowval *cbs , XtPointer cd )  /* 28 May 2020 */
5027 {
5028    MCW_grapher *grapher = (MCW_grapher *) cd ;
5029    int uu ;
5030 
5031 ENTRY("GRA_upsam_CB") ;
5032 
5033    if( ! GRA_VALID(grapher) ) EXRETURN ;
5034 
5035    uu = grapher->do_upsam ; grapher->do_upsam = cbs->ival ;
5036    if( uu != grapher->do_upsam ){
5037      init_mat( grapher ) ; redraw_graph( grapher , 0 ) ;
5038    }
5039 
5040    EXRETURN ;
5041 }
5042 
5043 /*-----------------------------------------------------------------------------*/
5044 
5045 #ifdef USE_OPTMENUS
GRA_slice_choose_CB(MCW_arrowval * cbs,XtPointer cd)5046 void GRA_slice_choose_CB( MCW_arrowval *cbs , XtPointer cd )
5047 #else
5048 void GRA_slice_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs *cbs )
5049 #endif
5050 {
5051    MCW_grapher *grapher = (MCW_grapher *) cd ;
5052 
5053 ENTRY("GRA_slice_choose_CB") ;
5054 
5055    if( ! GRA_VALID(grapher) ) EXRETURN ;
5056 
5057    grapher->zpoint = cbs->ival ;
5058    if( grapher->zpoint >= grapher->status->nz )
5059       grapher->zpoint = grapher->status->nz - 1 ;
5060    redraw_graph( grapher , 0 ) ;
5061    send_newinfo( grapher ) ;
5062    EXRETURN ;
5063 }
5064 
5065 /*-----------------------------------------------------------------------------*/
5066 
5067 #ifdef USE_OPTMENUS
GRA_ignore_choose_CB(MCW_arrowval * cbs,XtPointer cd)5068 void GRA_ignore_choose_CB( MCW_arrowval * cbs , XtPointer cd )
5069 #else
5070 void GRA_ignore_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs *cbs )
5071 #endif
5072 {
5073    MCW_grapher *grapher = (MCW_grapher *) cd ;
5074 
5075 ENTRY("GRA_ignore_choose_CB") ;
5076 
5077    if( ! GRA_VALID(grapher) || grapher->status->send_CB == NULL ) EXRETURN ;
5078 
5079    if( cbs->ival >= 0 && cbs->ival < TTOP(grapher)-1 ){
5080       GRA_cbs gbs ;
5081 
5082       gbs.reason = graCR_setignore ;
5083       gbs.key    = cbs->ival ;
5084 #if 0
5085       grapher->status->send_CB( grapher , grapher->getaux , &gbs ) ;
5086 #else
5087       CALL_sendback( grapher , gbs ) ;
5088 #endif
5089    }
5090    EXRETURN ;
5091 }
5092 
5093 /*-----------------------------------------------------------------------------*/
5094 
5095 #ifdef USE_OPTMENUS
GRA_polort_choose_CB(MCW_arrowval * cbs,XtPointer cd)5096 void GRA_polort_choose_CB( MCW_arrowval * cbs , XtPointer cd )
5097 #else
5098 void GRA_polort_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs * cbs )
5099 #endif
5100 {
5101    MCW_grapher * grapher = (MCW_grapher *) cd ;
5102 
5103 ENTRY("GRA_polort_choose_CB") ;
5104 
5105    if( ! GRA_VALID(grapher) || grapher->status->send_CB == NULL ) EXRETURN ;
5106 
5107    if( cbs->ival >= 0 && cbs->ival <= MAX_POLORT ){
5108       GRA_cbs gbs ;
5109 
5110       gbs.reason = graCR_polort ;
5111       gbs.key    = cbs->ival ;
5112 #if 0
5113       grapher->status->send_CB( grapher , grapher->getaux , &gbs ) ;
5114 #else
5115       CALL_sendback( grapher , gbs ) ;
5116 #endif
5117    }
5118    EXRETURN ;
5119 }
5120 
5121 /*-----------------------------------------------------------------------------*/
5122 
GRA_bkthr_choose_CB(Widget wcaller,XtPointer cd,MCW_choose_cbs * cbs)5123 void GRA_bkthr_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs * cbs )
5124 {
5125 ENTRY("GRA_bkthr_choose_CB") ;
5126    SET_FIM_bkthr( cbs->fval ) ;
5127    EXRETURN ;
5128 }
5129 
5130 /*-----------------------------------------------------------------------------*/
5131 
GRA_refread_choose_CB(Widget wcaller,XtPointer cd,MCW_choose_cbs * cbs)5132 void GRA_refread_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs * cbs )
5133 {
5134    MCW_grapher * grapher = (MCW_grapher *) cd ;
5135    MRI_IMAGE * flim ;
5136    float * far ;
5137    int ii ;
5138    GRA_cbs gbs ;
5139 
5140 ENTRY("GRA_refread_choose_CB") ;
5141 
5142    if( ! GRA_VALID(grapher)             ||
5143        grapher->status->send_CB == NULL ||
5144        cbs->reason != mcwCR_string      ||
5145        cbs->cval == NULL                || strlen(cbs->cval) == 0 ) EXRETURN ;
5146 
5147    EXRONE(grapher) ;  /* 22 Sep 2000 */
5148 
5149    flim = mri_read_1D( cbs->cval ) ;     /* 16 Nov 1999: replaces mri_read_ascii */
5150    if( flim == NULL || flim->nx < 2 ){
5151       BEEPIT ; mri_free(flim) ; WARNING_message("Can't read time seies file!?") ; EXRETURN ;
5152    }
5153 
5154    far = MRI_FLOAT_PTR(flim) ;
5155    for( ii=0 ; ii < flim->nvox ; ii++ )
5156       if( fabs(far[ii]) >= 33333.0 ) far[ii] = WAY_BIG ;
5157 
5158    { GRA_cbs cbs; cbs.reason=graCR_winaver; CALL_sendback(grapher,cbs); }
5159    MCW_set_bbox( grapher->fmenu->fim_editref_winaver_bbox , 0 ) ;
5160    gbs.reason   = graCR_refequals ;
5161    gbs.userdata = (XtPointer) flim ;
5162 #if 0
5163    grapher->status->send_CB( grapher , grapher->getaux , &gbs ) ;
5164 #else
5165    CALL_sendback( grapher , gbs ) ;
5166 #endif
5167    mri_free(flim) ;
5168    EXRETURN ;
5169 }
5170 
5171 /*-----------------------------------------------------------------------------*/
5172 
GRA_refstore_choose_CB(Widget wcaller,XtPointer cd,MCW_choose_cbs * cbs)5173 void GRA_refstore_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs * cbs )
5174 {
5175    MCW_grapher * grapher = (MCW_grapher *) cd ;
5176 
5177 ENTRY("GRA_refstore_choose_CB") ;
5178 
5179    if( ! GRA_VALID(grapher)             ||
5180        grapher->ref_ts == NULL          ||
5181        IMARR_COUNT(grapher->ref_ts) < 1 ||
5182        cbs->reason != mcwCR_string      ||
5183        cbs->cval == NULL                || strlen(cbs->cval) == 0 ) EXRETURN ;
5184 
5185    EXRONE(grapher) ;  /* 22 Sep 2000 */
5186 
5187    PLUTO_register_timeseries( cbs->cval , IMARR_SUBIMAGE(grapher->ref_ts,0) ) ;
5188    EXRETURN ;
5189 }
5190 
5191 /*-----------------------------------------------------------------------------*/
5192 
GRA_refwrite_choose_CB(Widget wcaller,XtPointer cd,MCW_choose_cbs * cbs)5193 void GRA_refwrite_choose_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs * cbs )
5194 {
5195    MCW_grapher * grapher = (MCW_grapher *) cd ;
5196    MRI_IMAGE * tsim ;
5197    int ii , ll ;
5198    GRA_cbs gbs ;
5199 
5200 ENTRY("GRA_refwrite_choose_CB") ;
5201 
5202    if( ! GRA_VALID(grapher)             ||
5203        grapher->ref_ts == NULL          ||
5204        IMARR_COUNT(grapher->ref_ts) < 1 ||
5205        cbs->reason != mcwCR_string      ||
5206        cbs->cval == NULL                || (ll=strlen(cbs->cval)) == 0 ) EXRETURN ;
5207 
5208    EXRONE(grapher) ;  /* 22 Sep 2000 */
5209 
5210    for( ii=0 ; ii < ll ; ii++ ){
5211       if( iscntrl(cbs->cval[ii]) || isspace(cbs->cval[ii]) ||
5212           cbs->cval[ii] == '/'   || cbs->cval[ii] == ';'   ||
5213           cbs->cval[ii] == '*'   || cbs->cval[ii] == '?'   ||
5214           cbs->cval[ii] == '&'   || cbs->cval[ii] == '|'   ||
5215           cbs->cval[ii] == '"'   || cbs->cval[ii] == '>'   ||
5216           cbs->cval[ii] == '<'   || cbs->cval[ii] == '\''  ||
5217           cbs->cval[ii] == '['   || cbs->cval[ii] == ']'     ){
5218 
5219          BEEPIT ; WARNING_message("Illegal filename") ; EXRETURN ;
5220       }
5221    }
5222 
5223 #if 0
5224    tsim = mri_transpose( IMARR_SUBIMAGE(grapher->ref_ts,0) ) ;
5225    mri_write_ascii( cbs->cval , tsim ) ;
5226    mri_free( tsim ) ;
5227 #else
5228    mri_write_1D( cbs->cval , IMARR_SUBIMAGE(grapher->ref_ts,0) ) ; /* 16 Nov 1999 */
5229 #endif
5230 
5231    /* 12 Nov 1996: put this in AFNI's list of library files */
5232 
5233    if( grapher->status->send_CB != NULL ){
5234       mri_add_name( cbs->cval , IMARR_SUBIMAGE(grapher->ref_ts,0) ) ;
5235       gbs.reason   = graCR_timeseries_library ;
5236       gbs.userdata = (XtPointer) IMARR_SUBIMAGE(grapher->ref_ts,0) ;
5237 #if 0
5238       grapher->status->send_CB( grapher , grapher->getaux , &gbs ) ;
5239 #else
5240       CALL_sendback( grapher , gbs ) ;
5241 #endif
5242    }
5243    EXRETURN ;
5244 }
5245 
5246 /*-----------------------------------------------------------------------
5247    External interface to drive an MCW_grapher:
5248      grapher    = pointer to structure returned by new_MCW_grapher
5249      drive_code = integer indicating which action to take
5250      drive_data = data or pointer to data controlling action
5251                   (you will probably have to cast this to
5252                    XtPointer to avoid ugly warnings from the compiler)
5253 
5254 OK   drive_code       drive_data should be
5255 --   ----------       --------------------
5256 *    graDR_cursor     (int) with new cursor id for the image window;
5257                        (if negative, means from cursorfont)
5258 
5259 *    graDR_realize    (ignored) an unrealized viewer is re-realized
5260 
5261 *    graDR_redraw     (int *) array of 4 ints: x,y,z,m
5262                         redraw the graph centered at x,y,z with matrix m
5263 
5264 *    graDR_destroy    (ignored) destroy this MCW_grapher, and delete its
5265                         own XtMalloc-ed internal data structures;
5266                         after this call, you must myXtFree(grapher) to finish
5267                         the job.
5268 
5269 *    graDR_newdata    (XtPointer) contains new auxiliary data for getser;
5270                         this call switches the data sequence to a
5271                         new one entirely.  As with imseq, this should
5272                         be followed by a call with graDR_redraw.
5273 
5274 *    graDR_title      (char *) contains new string for window title bar
5275 
5276 *    graDR_icon       (Pixmap) sets the icon for this window
5277 
5278 *    graDR_addref_ts  (MRI_IMAGE *) adds a reference timeseries to the list
5279                         input == NULL --> delete all references
5280                   ** N.B.: The input timeseries will not be copied, just
5281                            will keep a pointer to it.  Thus, the input
5282                            timeseries should not be destroyed.
5283 
5284 *    graDR_addort_ts  (MRI_IMAGE *) adds an ort timeseries to the list
5285                         input == NULL --> delete all orts
5286 
5287 *    graDR_winaver    (int) 0=off 1=on WinAver toggle on FIM menu
5288 
5289 *    graDR_setignore  (int) set the initial ignore level for graphs
5290 
5291 *    graDR_polort     (int) set the polort level for fimmery
5292 
5293 *    graDR_setindex   (int) contains the new time_index;
5294                         All this does is draw some stuff.
5295 
5296 *    graDR_button2_enable  (ignored) Turn button2 reporting on
5297 *    graDR_button2_disable (ignored) and off.
5298 
5299 *    graDR_fim_disable     (ignored) Turn all FIM stuff off (for good)
5300 
5301 *    graDR_mirror          (int) Turn mirroring on (==1) or off (==0)
5302 
5303 *    graDR_setmatrix       (int) These 3 items set their corresponding
5304 *    graDR_setgrid               parameters to the drive parameter.
5305 
5306 *    graDR_newlength       (int) set the expected length of time series
5307                             to be some new value (e.g., the pin number)
5308 *    graDR_setpinnum       [same as newlength]
5309 *    graDR_setpintop       [same as newlength]
5310 
5311 *    graDR_setpinbot       (int)   set the bottom index for plotting
5312 *    graDR_setpins         (int *) set top AND bottom index AND stride
5313                                    for plotting; points to array of 3 ints
5314 
5315 *    graDR_setglobalbaseline (float *) Global baseline value
5316 
5317 The RwcBoolean return value is True for success, False for failure.
5318 -------------------------------------------------------------------------*/
5319 
drive_MCW_grapher(MCW_grapher * grapher,int drive_code,XtPointer drive_data)5320 RwcBoolean drive_MCW_grapher( MCW_grapher * grapher ,
5321                            int drive_code , XtPointer drive_data )
5322 {
5323 
5324 ENTRY("drive_MCW_grapher") ;
5325 
5326    if( ! GRA_VALID(grapher) ) RETURN(False) ;
5327 
5328    switch( drive_code ){
5329 
5330       /*------- error! -------*/
5331 
5332       default:{
5333          WARNING_message("drive_MCW_grapher: code=%d illegal!",drive_code) ;
5334          BEEPIT ; RETURN(False) ;
5335       }
5336 
5337       /*------ winaver [27 Jan 2004] -----*/
5338 
5339       case graDR_winaver:{
5340         int vvv = PTOI(drive_data) ;
5341         MCW_set_bbox( grapher->fmenu->fim_editref_winaver_bbox , vvv ) ;
5342         RETURN( True ) ;
5343       }
5344 
5345       /*------ setglobalbaseline [07 Aug 2001] -----*/
5346 
5347       case graDR_setglobalbaseline:{
5348          float *vvv = (float *)drive_data ;    /* get value   */
5349          int ii = thd_floatscan( 1 , vvv ) ;   /* check value */
5350          MCW_choose_cbs cb ;
5351          if( ii != 0 ) RETURN( False ) ;       /* this is bad */
5352          cb.reason = mcwCR_integer ;
5353          cb.fval   = *vvv ;
5354          GRA_finalize_global_baseline_CB(NULL,(XtPointer)grapher,&cb) ;
5355          RETURN( True ) ;
5356       }
5357 
5358       /*------ setmatrix [22 Sep 2000] -----*/
5359 
5360       case graDR_setmatrix:{
5361          int mm = PTOI(drive_data) ;
5362          if( mm < 0 ) RETURN( False ) ;
5363          grapher->mat = MIN( grapher->mat_max , mm ) ;
5364          init_mat    ( grapher ) ;
5365          redraw_graph( grapher, PLOTCODE_AUTOSCALE ); /* 12 Oct 2000: autoscale */
5366          send_newinfo( grapher ) ;
5367          RETURN( True ) ;
5368       }
5369 
5370       /*------ setgrid [22 Sep 2000] -----*/
5371 
5372       case graDR_setgrid:{
5373          int mm = PTOI(drive_data) ;
5374          if( mm < 2 ) RETURN( False ) ;
5375          grapher->grid_spacing = mm ;
5376          grapher->grid_fixed   = 1 ;  /* 02 Apr 2004 */
5377          redraw_graph(grapher,0) ;
5378          RETURN( True ) ;
5379       }
5380 
5381       /*------ mirroring (Jul 2000) -----*/
5382 
5383       case graDR_mirror:{
5384          int ii = PTOI(drive_data) ;
5385 
5386          if( ii != grapher->mirror ){
5387            grapher->mirror = ii ;
5388            init_mat( grapher ) ; redraw_graph( grapher , 0 ) ;
5389          }
5390       }
5391       break ;
5392 
5393       /*------ fim disabling -----*/
5394 
5395       case graDR_fim_disable:{
5396          int ii ;
5397          XtUnmanageChild( grapher->fmenu->fim_cbut ) ;
5398          XtUnmanageChild( grapher->opt_xaxis_cbut ) ;
5399          for( ii=0 ; ii < NUM_COLOR_ITEMS ; ii++ ){
5400            if( gr_unfim[ii] ){
5401              if( grapher->opt_color_av[ii] != NULL )
5402                XtUnmanageChild( grapher->opt_color_av[ii]->wrowcol ) ;
5403              if( grapher->opt_thick_bbox[ii] != NULL )
5404                XtUnmanageChild( grapher->opt_thick_bbox[ii]->wtop  ) ;
5405              if( grapher->opt_points_bbox[ii] != NULL )
5406                XtUnmanageChild( grapher->opt_points_bbox[ii]->wtop ) ;
5407            }
5408          }
5409       }
5410       break ;
5411 
5412       /*------ button2 stuff -----*/
5413 
5414       case graDR_button2_enable:{
5415         grapher->button2_enabled = 1 ;
5416         GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
5417         RETURN( True ) ;
5418       }
5419 
5420       case graDR_button2_disable:{
5421         grapher->button2_enabled = 0 ;
5422         RETURN( True ) ;
5423       }
5424 
5425       /*------ set time index -----*/
5426 
5427       case graDR_setindex:{
5428          int new_index = PTOI(drive_data) ; /* Pointer to Integer cast */
5429 
5430          if( new_index < 0 || new_index >= grapher->status->num_series )
5431            RETURN( False ) ;
5432 
5433          if( new_index != grapher->time_index ){
5434            grapher->time_index = new_index ;
5435            if( grapher->textgraph )
5436              redraw_graph( grapher , 0 ) ;
5437            else
5438              GRA_redraw_overlay( grapher ) ;
5439          }
5440          RETURN( True ) ;
5441       }
5442 
5443       /*------ reset top of time series plotting ------*/
5444       /* (same as graDR_setpinnum and graDR_setpintop) */
5445 
5446       case graDR_newlength:{
5447          int newtop=PTOI(drive_data) ;
5448 
5449          if( newtop < MIN_PIN ) newtop = 0 ;
5450          if( newtop > MAX_PIN ) newtop = MAX_PIN ;
5451 
5452          grapher->pin_top = newtop ;
5453          if( NPTS(grapher) < 2 ) grapher->pin_bot = 0 ;
5454 
5455 #ifdef USE_OPTMENUS
5456          GRA_fix_optmenus( grapher ) ;
5457 #endif
5458          redraw_graph( grapher, 0 ) ;
5459          RETURN( True ) ;
5460       }
5461 
5462       /*------ reset bottom of time series plotting [17 Mar 2004] -----*/
5463 
5464       case graDR_setpinbot:{
5465          int newbot=PTOI(drive_data) ;
5466 
5467          if( newbot < 0               ) newbot = 0 ;
5468          if( newbot >= TTOP(grapher)  ) newbot = 0 ;
5469 
5470          grapher->pin_bot = newbot ;
5471 
5472 #ifdef USE_OPTMENUS
5473          GRA_fix_optmenus( grapher ) ;
5474 #endif
5475          redraw_graph( grapher, 0 ) ;
5476          RETURN( True ) ;
5477       }
5478 
5479       /*------ reset bot and top of time series plotting [19 Mar 2004] -----*/
5480 
5481       case graDR_setpins:{
5482          int *pvec = (int *)drive_data ;
5483          int newbot,newtop,newstride ;
5484 
5485          if( pvec == NULL ){
5486            newbot = newtop = 0 ; newstride = 1 ;
5487          } else {
5488            newbot = pvec[0] ; if( newbot < 0       ) newbot = 0 ;
5489            newtop = pvec[1] ; if( newtop < newbot  ) newtop = 0 ;
5490                               if( newtop < MIN_PIN ) newtop = 0 ;
5491            newstride = pvec[2] ;
5492            if( newstride <= 0 || newstride > 9 ) newstride = 1 ;
5493          }
5494          if( newtop > 0 && NABC(newbot,newtop,newstride) < 2 ){
5495            newbot = newtop = 0 ; newstride = 1 ;
5496          }
5497          if( newbot >= TTOP(grapher) ) newbot = 0 ;
5498 
5499          grapher->pin_bot    = newbot ;
5500          grapher->pin_top    = newtop ;
5501          grapher->pin_stride = newstride ;
5502 
5503 #ifdef USE_OPTMENUS
5504          GRA_fix_optmenus( grapher ) ;
5505 #endif
5506          redraw_graph( grapher, 0 ) ;
5507          RETURN( True ) ;
5508       }
5509 
5510       /*------ set ignore count -----*/
5511 
5512       case graDR_setignore:{
5513          int new_ignore = PTOI(drive_data) ;
5514 
5515          if( new_ignore >= 0 && new_ignore < TTOP(grapher)-1 ){
5516            grapher->init_ignore = new_ignore ;
5517            redraw_graph( grapher , PLOTCODE_AUTOSCALE ) ;
5518            RETURN( True ) ;
5519          } else {
5520            RETURN( False ) ;
5521          }
5522       }
5523 
5524       /*------- set polort [27 May 1999] --------*/
5525 
5526       case graDR_polort:{
5527          int new_polort = PTOI(drive_data) ;
5528 
5529          if( new_polort >= 0 ){
5530             grapher->polort = new_polort ;
5531 #ifdef USE_OPTMENUS
5532             GRA_fix_optmenus( grapher ) ;
5533 #endif
5534          }
5535          RETURN( True ) ;
5536       }
5537 
5538       /*----- set reference time series (currently limited to one) -----*/
5539 
5540       case graDR_addref_ts:{
5541          MRI_IMAGE *im = (MRI_IMAGE *) drive_data ;
5542 
5543          if( im == NULL ){                /* no input --> kill kill kill */
5544 STATUS("freeing reference timeseries") ;
5545             FREE_IMARR(grapher->ref_ts) ;  /* doesn't delete images inside */
5546             grapher->ref_ts = NULL ;
5547          } else{
5548             if( grapher->ref_ts == NULL ) INIT_IMARR( grapher->ref_ts ) ;
5549 
5550             if( IMARR_COUNT(grapher->ref_ts) == 0 ){
5551 STATUS("adding reference timeseries") ;
5552                ADDTO_IMARR( grapher->ref_ts , im ) ;     /* create first one */
5553             } else {
5554 STATUS("replacing reference timeseries") ;
5555                IMARR_SUBIMAGE(grapher->ref_ts,0) = im ;  /* replace first one */
5556             }
5557          }
5558 
5559          redraw_graph( grapher , 0 ) ;
5560          RETURN( True ) ;
5561       }
5562 
5563       /*----- set ort time series (currently limited to one) -----*/
5564 
5565       case graDR_addort_ts:{
5566          MRI_IMAGE *im = (MRI_IMAGE *) drive_data ;
5567 
5568          if( im == NULL ){                /* no input --> kill kill kill */
5569 STATUS("freeing ort timeseries") ;
5570             FREE_IMARR(grapher->ort_ts) ;
5571             grapher->ort_ts = NULL ;
5572          } else{
5573             if( grapher->ort_ts == NULL ) INIT_IMARR( grapher->ort_ts ) ;
5574 
5575             if( IMARR_COUNT(grapher->ort_ts) == 0 ){
5576 STATUS("adding ort timeseries") ;
5577                ADDTO_IMARR( grapher->ort_ts , im ) ;     /* create first one */
5578             } else {
5579 STATUS("replacing ort timeseries") ;
5580                IMARR_SUBIMAGE(grapher->ort_ts,0) = im ;  /* replace first one */
5581             }
5582          }
5583 
5584          redraw_graph( grapher , 0 ) ;
5585          RETURN( True ) ;
5586       }
5587 
5588       /*------ set icon pixmap -----*/
5589 
5590       case graDR_icon:{
5591          int xret , yret ;
5592          unsigned int wret,hret,bret,dret ;
5593          Window rret ;
5594 
5595          XtVaSetValues( grapher->fdw_graph , XmNiconPixmap , (Pixmap) drive_data , NULL ) ;
5596          grapher->glogo_pixmap = (Pixmap) drive_data ;
5597 
5598          /* get geometry for later use */
5599 
5600          if( grapher->glogo_pixmap != XmUNSPECIFIED_PIXMAP ){
5601             (void) XGetGeometry( grapher->dc->display , grapher->glogo_pixmap ,
5602                                  &rret , &xret , &yret , &wret , &hret , &bret , &dret ) ;
5603 
5604             grapher->glogo_width  = wret ;
5605             grapher->glogo_height = hret ;
5606          } else {
5607             grapher->glogo_width  = 0 ;
5608             grapher->glogo_height = 0 ;
5609          }
5610          RETURN( True ) ;
5611       }
5612 
5613       /*------- title --------*/
5614 
5615       case graDR_title:{
5616          char * title = (char *) drive_data ;
5617 
5618          if( title == NULL || strlen(title) == 0 ) RETURN( False ) ;
5619 
5620          XtVaSetValues( grapher->fdw_graph , XmNtitle , title , NULL ) ;
5621          RETURN( True ) ;
5622       }
5623 
5624       /*------- death! -------*/
5625 
5626       case graDR_destroy:{
5627          end_fd_graph_CB( NULL , (XtPointer) grapher , NULL ) ;
5628          RETURN( True ) ;
5629       }
5630 
5631       /*------- unrealize! -------*/
5632 
5633       case graDR_unrealize:{
5634          GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
5635          if( GRA_REALZ(grapher) ){
5636            XtUnrealizeWidget(grapher->fdw_graph); NI_sleep(1);
5637          }
5638          grapher->valid = 1 ;
5639 
5640          if( grapher->fd_pxWind != (Pixmap) 0 )
5641             XFreePixmap( grapher->dc->display , grapher->fd_pxWind ) ;
5642          RETURN( True ) ;
5643       }
5644 
5645       /*------- realize! -------*/
5646 
5647       case graDR_realize:{
5648          if( ! GRA_REALZ(grapher) ){
5649             int width , height ;
5650 
5651             grapher->valid = 2 ;
5652 
5653             XtRealizeWidget( grapher->fdw_graph ) ; NI_sleep(1) ;
5654             WAIT_for_window( grapher->fdw_graph ) ; NI_sleep(1) ;
5655 
5656             /* 29 Sep 2000: next 2 lines of code are for the Form change */
5657 
5658             XtVaSetValues( grapher->option_rowcol ,
5659                              XmNleftAttachment   , XmATTACH_NONE ,
5660                              XmNtopAttachment    , XmATTACH_NONE ,
5661                              XmNrightAttachment  , XmATTACH_FORM ,
5662                              XmNbottomAttachment , XmATTACH_FORM ,
5663                            NULL ) ;
5664             XMapRaised( XtDisplay(grapher->option_rowcol) ,
5665                         XtWindow(grapher->option_rowcol)   ) ;
5666 
5667             NORMAL_cursorize( grapher->fdw_graph ) ;
5668 
5669             if( ISONE(grapher) )
5670               NORMAL_cursorize( grapher->draw_fd ) ;  /* 07 Dec 2001 */
5671             else
5672               POPUP_cursorize( grapher->draw_fd ) ;
5673 
5674             MCW_widget_geom( grapher->draw_fd , &width , &height , NULL,NULL ) ;
5675             GRA_new_pixmap( grapher , width , height , 0 ) ;
5676 #ifdef USE_OPTMENUS
5677             GRA_fix_optmenus( grapher ) ;
5678 #endif
5679             NI_sleep(1) ;  /* 08 Mar 2002: for good luck */
5680 
5681            if( startup_1D_transform != NULL )  /* 19 Dec 2018 */
5682              GRA_set_1D_transform( grapher , startup_1D_transform ) ;
5683          }
5684          RETURN( True ) ;
5685       }
5686 
5687       /*------- new cursor for image -------*/
5688 
5689       case graDR_cursor:{
5690          int cur = PTOI(drive_data) ;
5691 
5692          MCW_alter_widget_cursor( grapher->fdw_graph , cur , "yellow" , "blue" ) ;
5693          RETURN( True ) ;
5694       }
5695 
5696       /*------- new data sequence!!! -------*/
5697 
5698       case graDR_newdata:{
5699          int npold = grapher->status->num_series ;  /* 22 Sep 2000 */
5700 
5701          GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
5702 
5703          grapher->getaux = drive_data ;
5704 #if 0
5705          grapher->status = (MCW_grapher_status *)
5706                               grapher->getser(0,graCR_getstatus,drive_data) ;
5707 #else
5708          CALL_getser( grapher , 0,graCR_getstatus , MCW_grapher_status *,grapher->status ) ;
5709 #endif
5710          init_const( grapher ) ;
5711 
5712          /* mustn't allow bottom of plotting range to be beyond top of data! */
5713 
5714          if( grapher->pin_bot >= grapher->status->num_series-1 ) grapher->pin_bot = 0 ;
5715 
5716          if( npold < 2 || !grapher->grid_fixed ){ /* 22 Sep 2000 */
5717            auto_grid( grapher , NPTS(grapher) ) ;
5718          }
5719 
5720 #ifdef USE_OPTMENUS
5721          GRA_fix_optmenus( grapher ) ;
5722 #endif
5723 
5724         if( ISONE(grapher) )                        /* 07 Dec 2001 */
5725           NORMAL_cursorize( grapher->draw_fd ) ;
5726         else
5727           POPUP_cursorize( grapher->draw_fd ) ;
5728 
5729          RETURN( True ) ;
5730       }
5731 
5732       /*------- redraw -------*/
5733 
5734       case graDR_redraw:{
5735          int *xym = (int *) drive_data ;
5736 
5737 STATUS("graDR_redraw") ;
5738 
5739          if( xym != NULL ){
5740             if( xym[0] >= 0 ) grapher->xpoint = xym[0] ;
5741             if( xym[1] >= 0 ) grapher->ypoint = xym[1] ;
5742             if( xym[2] >= 0 ) grapher->zpoint = xym[2] ;
5743             if( xym[3] >  0 ) grapher->mat    = xym[3] ;
5744             init_mat(grapher) ;
5745          }
5746          redraw_graph( grapher , 0 ) ;
5747          RETURN( True ) ;
5748       }
5749 
5750    }  /* end of switch on drive_code */
5751 
5752    RETURN( False ) ;  /* should never be reached! */
5753 }
5754 
5755 /*------------------------------------------------------------------
5756    Callback for all FIM menu buttons
5757 --------------------------------------------------------------------*/
5758 
GRA_fim_CB(Widget w,XtPointer client_data,XtPointer call_data)5759 void GRA_fim_CB( Widget w , XtPointer client_data , XtPointer call_data )
5760 {
5761    FIM_menu * fm = (FIM_menu *) client_data ;
5762    MCW_grapher * grapher = (MCW_grapher *) fm->parent ;
5763    GRA_cbs cbs ;
5764 
5765 ENTRY("GRA_fim_CB") ;
5766 
5767    if( ! GRA_VALID(grapher) || grapher->status->send_CB == NULL ) EXRETURN ;
5768 
5769    EXRONE(grapher) ;  /* 22 Sep 2000 */
5770 
5771    /*--- carry out action, depending on which widget called me ---*/
5772 
5773    /*** Pick reference ***/
5774 
5775    if( w == grapher->fmenu->fim_pickref_pb ){
5776       cbs.reason = graCR_pickref ;
5777 #if 0
5778       grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
5779 #else
5780       CALL_sendback( grapher , cbs ) ;
5781 #endif
5782       grapher->tschosen = 1 ;  /* 31 Mar 2004 */
5783    }
5784 
5785    /*** Pick ort ***/
5786 
5787    else if( w == grapher->fmenu->fim_pickort_pb ){
5788       cbs.reason = graCR_pickort ;
5789 #if 0
5790       grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
5791 #else
5792       CALL_sendback( grapher , cbs ) ;
5793 #endif
5794       grapher->tschosen = 1 ;  /* 31 Mar 2004 */
5795    }
5796 
5797    /*** Clear FIM ***/
5798 
5799    else if( w == grapher->fmenu->fim_editref_clear_pb ){
5800       cbs.reason = graCR_clearfim ;
5801 #if 0
5802       grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
5803 #else
5804       CALL_sendback( grapher , cbs ) ;
5805 #endif
5806    }
5807 
5808    /*** Clear Ort ***/
5809 
5810    else if( w == grapher->fmenu->fim_editort_clear_pb ){
5811       cbs.reason = graCR_clearort ;
5812 #if 0
5813       grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
5814 #else
5815       CALL_sendback( grapher , cbs ) ;
5816 #endif
5817    }
5818 
5819    /*** set ref to central time series ***/
5820 
5821    else if( w == grapher->fmenu->fim_editref_equals_pb ||
5822             w == grapher->fmenu->fim_editref_add_pb      ){
5823       int ll ;
5824       MRI_IMAGE * tsim ;
5825 
5826       ll = grapher->xpoint +
5827            grapher->ypoint * grapher->status->nx +
5828            grapher->zpoint * grapher->status->nx * grapher->status->ny ;
5829 
5830       tsim = GRA_getseries( grapher , ll ) ;
5831 
5832       if( tsim != NULL ){
5833          { GRA_cbs cbs; cbs.reason=graCR_winaver; CALL_sendback(grapher,cbs); }
5834          MCW_set_bbox( grapher->fmenu->fim_editref_winaver_bbox , 0 ) ;
5835          cbs.reason   = (w == grapher->fmenu->fim_editref_equals_pb)
5836                         ? graCR_refequals : graCR_refadd ;
5837          cbs.userdata = (XtPointer) tsim ;
5838 #if 0
5839          grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
5840 #else
5841          CALL_sendback( grapher , cbs ) ;
5842 #endif
5843          mri_free( tsim ) ;
5844       }
5845    }
5846 
5847    /*** read or write or smooth ***/
5848 
5849    else if( w == grapher->fmenu->fim_editref_read_pb ){
5850       MCW_choose_string( grapher->option_rowcol ,
5851                          "Ideal Input Filename:" , NULL ,
5852                          GRA_refread_choose_CB , (XtPointer) grapher ) ;
5853    }
5854 
5855    else if( w == grapher->fmenu->fim_editref_write_pb ){
5856       if( grapher->ref_ts != NULL && IMARR_COUNT(grapher->ref_ts) > 0 ){
5857          MCW_choose_string( grapher->option_rowcol ,
5858                             "Ideal Output Filename:" , NULL ,
5859                             GRA_refwrite_choose_CB , (XtPointer) grapher ) ;
5860       } else {
5861          BEEPIT ; WARNING_message("ref time series not defined!?") ;
5862       }
5863    }
5864 
5865    else if( w == grapher->fmenu->fim_editref_store_pb ){
5866       if( grapher->ref_ts != NULL && IMARR_COUNT(grapher->ref_ts) > 0 ){
5867          MCW_choose_string( grapher->option_rowcol ,
5868                             "Label to Store Ideal:" , NULL ,
5869                             GRA_refstore_choose_CB , (XtPointer) grapher ) ;
5870       } else {
5871          BEEPIT ; WARNING_message("ref time series not defined!?") ;
5872       }
5873    }
5874 
5875    else if( w == grapher->fmenu->fim_editref_smooth_pb ){
5876       cbs.reason = graCR_refsmooth ;
5877       if( grapher->ref_ts != NULL && IMARR_COUNT(grapher->ref_ts) > 0 ){
5878          { GRA_cbs cbs; cbs.reason=graCR_winaver; CALL_sendback(grapher,cbs); }
5879          MCW_set_bbox( grapher->fmenu->fim_editref_winaver_bbox , 0 ) ;
5880 #if 0
5881          grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
5882 #else
5883          CALL_sendback( grapher , cbs ) ;
5884 #endif
5885       } else {
5886          BEEPIT ; WARNING_message("ref time series not defined!?") ;
5887       }
5888    }
5889 
5890    /*** Set shifts ***/
5891 
5892    else if( w == grapher->fmenu->fim_editref_setshift_pb ){
5893       GRA_setshift_startup( grapher ) ;
5894    }
5895 
5896    /*** Execute FIM ***/
5897 
5898    else if( w == grapher->fmenu->fim_execute_pb ){
5899       int val = MCW_val_bbox(grapher->fmenu->fim_opt_bbox) ;
5900       cbs.reason = graCR_dofim ;
5901       switch(val){
5902          default:  cbs.key = FIM_ALPHA_MASK | FIM_CORR_MASK ; break ;
5903          case 2:   cbs.key = FIM_PERC_MASK  | FIM_CORR_MASK ; break ;
5904          case 4:   cbs.key = FIM_PAVE_MASK  | FIM_CORR_MASK ; break ;
5905          case 3:   cbs.key = FIM_PTOP_MASK  | FIM_CORR_MASK ; break ;
5906       }
5907       cbs.mat = 0 ; /* Feb 2000 */
5908       GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
5909 #if 0
5910       grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
5911 #else
5912       CALL_sendback( grapher , cbs ) ;
5913 #endif
5914    }
5915 
5916    else if( w == grapher->fmenu->fim_execfimp_pb ){
5917       cbs.reason = graCR_dofim ;
5918       cbs.key    = MCW_val_bbox(grapher->fmenu->fimp_opt_bbox) ;
5919       cbs.mat    = MCW_val_bbox(grapher->fmenu->fimp_user_bbox) ; /* Feb 2000 */
5920       GRA_timer_stop(grapher) ;   /* 04 Dec 2003 */
5921       if( cbs.key || cbs.mat )
5922 #if 0
5923          grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
5924 #else
5925          CALL_sendback( grapher , cbs ) ;
5926 #endif
5927       else
5928          { BEEPIT ; WARNING_message("Can't execute FIM+ -- invalid settings!?") ; }
5929    }
5930 
5931    /*** 04 Jan 2000: modify the FIM+ button settings ***/
5932 
5933    else if( w == grapher->fmenu->fimp_setdefault_pb ){
5934      char *ff = my_getenv( "AFNI_FIM_MASK" ) ; int mm=0 ;
5935      if( ff != NULL ) mm = strtol(ff,NULL,10) ;
5936      if( mm <= 0 ) mm = FIM_DEFAULT_MASK ;
5937      MCW_set_bbox( grapher->fmenu->fimp_opt_bbox , mm ) ;
5938    }
5939 
5940    else if( w == grapher->fmenu->fimp_setall_pb ){
5941       int mm = (2 << FIM_NUM_OPTS) - 1 ;
5942       MCW_set_bbox( grapher->fmenu->fimp_opt_bbox , mm ) ;
5943    }
5944 
5945    else if( w == grapher->fmenu->fimp_unsetall_pb ){
5946       MCW_set_bbox( grapher->fmenu->fimp_opt_bbox , 0 ) ;
5947    }
5948 
5949    /*** FIM plotting buttons ***/
5950 
5951    else if( w == grapher->fmenu->fim_plot_firstref_pb ){
5952       if( grapher->ref_ts_plotall != 0 ){
5953          grapher->ref_ts_plotall = 0 ;
5954          redraw_graph( grapher , 0 ) ;
5955       }
5956    }
5957 
5958    else if( w == grapher->fmenu->fim_plot_allrefs_pb ){
5959       if( grapher->ref_ts_plotall == 0 ){
5960          grapher->ref_ts_plotall = 1 ;
5961          redraw_graph( grapher , 0 ) ;
5962       }
5963    }
5964 
5965    /*** Ignore stuff ***/
5966 
5967    else if( w == grapher->fmenu->fim_ignore_down_pb && grapher->status->send_CB != NULL ){
5968       GRA_cbs cbs ;
5969 
5970       cbs.reason = graCR_setignore ;
5971       cbs.key    = grapher->init_ignore - 1 ;
5972 #if 0
5973       grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
5974 #else
5975       CALL_sendback( grapher , cbs ) ;
5976 #endif
5977    }
5978 
5979    else if( w == grapher->fmenu->fim_ignore_up_pb && grapher->status->send_CB != NULL ){
5980       GRA_cbs cbs ;
5981 
5982       cbs.reason = graCR_setignore ;
5983       cbs.key    = grapher->init_ignore + 1 ;
5984 #if 0
5985       grapher->status->send_CB( grapher , grapher->getaux , &cbs ) ;
5986 #else
5987       CALL_sendback( grapher , cbs ) ;
5988 #endif
5989    }
5990 
5991    else if( w == grapher->fmenu->fim_ignore_choose_pb && grapher->status->send_CB != NULL ){
5992 #ifdef USE_OPTMENUS
5993       GRA_ignore_choose_CB( grapher->fmenu->fim_ignore_choose_av , grapher ) ;
5994 #else
5995       MCW_choose_integer( grapher->option_rowcol , "Initial Ignore" ,
5996                           0 , grapher->status->num_series-1 , grapher->init_ignore ,
5997                           GRA_ignore_choose_CB , (XtPointer) grapher ) ;
5998 #endif
5999    }
6000 
6001    /* 27 May 1999: set polort */
6002 
6003    else if( w == grapher->fmenu->fim_polort_choose_pb && grapher->status->send_CB != NULL ){
6004 #ifdef USE_OPTMENUS
6005       GRA_polort_choose_CB( grapher->fmenu->fim_polort_choose_av , grapher ) ;
6006 #else
6007       MCW_choose_integer( grapher->option_rowcol , "Polort Order" ,
6008                           0 , MAX_POLORT , grapher->polort ,
6009                           GRA_polort_choose_CB , (XtPointer) grapher ) ;
6010 #endif
6011    }
6012 
6013    /* 02 Jun 1999: set FIM bkg threshold */
6014 
6015    else if( w == grapher->fmenu->fim_bkthr_choose_pb ){
6016       MCW_choose_integer( grapher->option_rowcol , "Bkg Thresh %" ,
6017                           0 , 99 , (int)(100*FIM_THR) ,
6018                           GRA_bkthr_choose_CB , (XtPointer) grapher ) ;
6019    }
6020 
6021    /*** Unimplemented Button ***/
6022 
6023    else {
6024       BEEPIT ; WARNING_message("You should never see this message!!") ;
6025    }
6026 
6027    /*--- Done!!! ---*/
6028 
6029    EXRETURN ;
6030 }
6031 
6032 /*-----------------------------------------------------------------------*/
6033 
6034 #define SETSHIFT_quit_label  "Quit"
6035 #define SETSHIFT_apply_label "Apply"
6036 #define SETSHIFT_done_label  "Set"
6037 
6038 #define SETSHIFT_quit_help   "Press to close\nthis control box"
6039 #define SETSHIFT_apply_help  "Press to apply this choice\nand keep this control box"
6040 #define SETSHIFT_done_help   "Press to apply this choice\nand close this control box"
6041 
6042 #define NUM_SETSHIFT_ACT 3
6043 
6044 static MCW_action_item SETSHIFT_act[NUM_SETSHIFT_ACT] = {
6045  { SETSHIFT_quit_label  , GRA_setshift_action_CB, NULL, SETSHIFT_quit_help ,"Close window"                 , 0 },
6046  { SETSHIFT_apply_label , GRA_setshift_action_CB, NULL, SETSHIFT_apply_help,"Apply choice and keep window" , 0 },
6047  { SETSHIFT_done_label  , GRA_setshift_action_CB, NULL, SETSHIFT_done_help ,"Apply choice and close window", 1 }
6048 } ;
6049 
6050 #define SETSHIFT_QUIT  0
6051 #define SETSHIFT_APPLY 1
6052 #define SETSHIFT_DONE  2
6053 
6054 /*-----------------------------------------------------------------------*/
6055 
GRA_setshift_startup(MCW_grapher * grapher)6056 void GRA_setshift_startup( MCW_grapher * grapher )
6057 {
6058    int ib , xx,yy ;
6059    Widget wrc ;
6060 
6061 ENTRY("GRA_setshift_startup") ;
6062 
6063    if( ! GRA_REALZ(grapher) || grapher->dialog != NULL ) EXRETURN ;
6064 
6065    MCW_widget_geom( grapher->fdw_graph , NULL,NULL,&xx,&yy ) ;  /* geometry of shell */
6066 
6067    grapher->dialog = XtVaCreatePopupShell(
6068                       "menu" , xmDialogShellWidgetClass , grapher->fdw_graph ,
6069                          XmNx , xx+15 ,
6070                          XmNy , yy+15 ,
6071                          XmNtitle , "Shifts" ,
6072                          XmNdeleteResponse , XmDO_NOTHING ,
6073                          XmNinitialResourcesPersistent , False ,
6074 
6075                          XmNvisual   , grapher->dc->visual ,         /* 14 Sep 1998 */
6076                          XmNcolormap , grapher->dc->colormap ,
6077                          XmNdepth    , grapher->dc->depth ,
6078                          XmNscreen   , grapher->dc->screen ,
6079                          XmNbackground  , 0 ,
6080                          XmNborderColor , 0 ,
6081               XmNkeyboardFocusPolicy , XmEXPLICIT ,
6082 
6083                       NULL ) ;
6084 
6085    if( MCW_isitmwm(grapher->fdw_graph) ){
6086       XtVaSetValues( grapher->dialog ,
6087                        XmNmwmDecorations , MWM_DECOR_BORDER ,
6088                        XmNmwmFunctions ,   MWM_FUNC_MOVE
6089                                          | MWM_FUNC_CLOSE ,
6090                      NULL ) ;
6091    }
6092 
6093    XmAddWMProtocolCallback(           /* make "Close" window menu work */
6094            grapher->dialog ,
6095            XmInternAtom( grapher->dc->display , "WM_DELETE_WINDOW" , False ) ,
6096            GRA_setshift_action_CB , grapher ) ;
6097 
6098    wrc = XtVaCreateWidget(                    /* RowColumn to hold all */
6099              "dialog" , xmRowColumnWidgetClass , grapher->dialog ,
6100                 XmNpacking     , XmPACK_TIGHT ,
6101                 XmNorientation , XmVERTICAL ,
6102                 XmNtraversalOn , True  ,
6103                 XmNinitialResourcesPersistent , False ,
6104              NULL ) ;
6105 
6106    wtemp = XtVaCreateManagedWidget(
6107             "dialog" , xmLabelWidgetClass , wrc ,
6108                LABEL_ARG("-- Shift Controls --") ,
6109                XmNalignment  , XmALIGNMENT_CENTER ,
6110                XmNinitialResourcesPersistent , False ,
6111             NULL ) ; LABELIZE(wtemp) ;
6112 
6113    (void) XtVaCreateManagedWidget(
6114             "dialog" , xmSeparatorWidgetClass , wrc ,
6115                XmNseparatorType , XmSHADOW_ETCHED_IN ,
6116                XmNinitialResourcesPersistent , False ,
6117             NULL ) ;
6118 
6119    grapher->setshift_inc_av = new_MCW_arrowval(
6120                                 wrc ,   "Increment  " , MCW_AV_downup ,
6121                                 1 , 1000 , (int)(100.0*grapher->setshift_inc) ,
6122                                 MCW_AV_edittext , 2 ,
6123                                 NULL , NULL , NULL , NULL ) ;
6124 
6125    grapher->setshift_left_av = new_MCW_arrowval(
6126                                   wrc , "Steps Left " , MCW_AV_downup ,
6127                                   0 , 29 , grapher->setshift_left ,
6128                                   MCW_AV_edittext , 0 ,
6129                                   NULL , NULL , NULL , NULL ) ;
6130 
6131    grapher->setshift_right_av = new_MCW_arrowval(
6132                                   wrc , "Steps Right" , MCW_AV_downup ,
6133                                   0 , 29 , grapher->setshift_right ,
6134                                   MCW_AV_edittext , 0 ,
6135                                   NULL , NULL , NULL , NULL ) ;
6136 
6137    grapher->setshift_inc_av->allow_wrap   = 1 ;   /* allow wrap at limits of values */
6138    grapher->setshift_left_av->allow_wrap  = 1 ;
6139    grapher->setshift_right_av->allow_wrap = 1 ;
6140 
6141    grapher->setshift_inc_av->fastdelay    = 250 ; /* slow down arrow repeat action */
6142    grapher->setshift_left_av->fastdelay   = 250 ;
6143    grapher->setshift_right_av->fastdelay  = 250 ;
6144 
6145    MCW_reghelp_children( grapher->setshift_inc_av->wrowcol ,
6146        "This controls the step size\n"
6147        "used to create the shifted\n"
6148        "time series -- for example,\n"
6149        "0.2 means a shift of 1/5\n"
6150        "of a time series stepsize."
6151    ) ;
6152    MCW_reghint_children( grapher->setshift_inc_av->wrowcol ,
6153                          "Size of shift" ) ;
6154 
6155    MCW_reghelp_children( grapher->setshift_left_av->wrowcol ,
6156       "This controls the number\n"
6157       "of left shifts used to\n"
6158       "create the desired multi-\n"
6159       "vector time series.\n\n"
6160       "N.B.: Steps Left plus\n"
6161       "      Steps Right should\n"
6162       "      be positive!"
6163    ) ;
6164    MCW_reghint_children( grapher->setshift_left_av->wrowcol ,
6165                          "Number of steps left" ) ;
6166 
6167    MCW_reghelp_children( grapher->setshift_right_av->wrowcol ,
6168       "This controls the number\n"
6169       "of right shifts used to\n"
6170       "create the desired multi-\n"
6171       "vector time series.\n\n"
6172       "N.B.: Steps Left plus\n"
6173       "      Steps Right should\n"
6174       "      be positive!"
6175    ) ;
6176    MCW_reghint_children( grapher->setshift_right_av->wrowcol ,
6177                          "Number of steps right" ) ;
6178 
6179    for( ib=0 ; ib < NUM_SETSHIFT_ACT ; ib++ )
6180       SETSHIFT_act[ib].data = (XtPointer) grapher ;
6181 
6182    (void) MCW_action_area( wrc , SETSHIFT_act , NUM_SETSHIFT_ACT ) ;
6183 
6184    XtManageChild( wrc ) ;
6185    XtPopup( grapher->dialog , XtGrabNone ) ; NI_sleep(1);
6186    RWC_visibilize_widget( grapher->dialog ) ; /* 09 Nov 1999 */
6187    NORMAL_cursorize( grapher->dialog ) ;
6188    EXRETURN ;
6189 }
6190 
6191 /*-----------------------------------------------------------------------*/
6192 
GRA_setshift_action_CB(Widget w,XtPointer client_data,XtPointer call_data)6193 void GRA_setshift_action_CB( Widget w , XtPointer client_data , XtPointer call_data )
6194 {
6195    MCW_grapher * grapher = (MCW_grapher *) client_data ;
6196    XmAnyCallbackStruct * cbs = (XmAnyCallbackStruct *) call_data ;
6197    char * wname ;
6198    int ib , close_window ;
6199 
6200 ENTRY("GRA_setshift_action_CB") ;
6201 
6202    if( !GRA_REALZ(grapher) || grapher->dialog==NULL ) EXRETURN ;
6203 
6204    wname = XtName(w) ;
6205 
6206    for( ib=0 ; ib < NUM_SETSHIFT_ACT ; ib++ )           /* button index, if any */
6207       if( strcmp(wname,SETSHIFT_act[ib].label) == 0 ) break ;
6208 
6209    close_window = (ib == SETSHIFT_DONE ||
6210                    ib == SETSHIFT_QUIT || ib == NUM_SETSHIFT_ACT) ;
6211 
6212    if( close_window ){
6213       RWC_XtPopdown( grapher->dialog ) ;
6214       XSync( XtDisplay(w) , False ) ;
6215       XmUpdateDisplay( w ) ;
6216    }
6217 
6218    switch( ib ){
6219 
6220       case SETSHIFT_APPLY:
6221       case SETSHIFT_DONE:{
6222          grapher->setshift_inc   = grapher->setshift_inc_av->fval ;
6223          grapher->setshift_left  = grapher->setshift_left_av->ival ;
6224          grapher->setshift_right = grapher->setshift_right_av->ival ;
6225 
6226          GRA_doshift( grapher ) ;
6227       }
6228       break ;
6229    }
6230 
6231    if( close_window ){                          /* close the window */
6232       XtDestroyWidget( grapher->dialog ) ; NI_sleep(1) ;
6233       grapher->dialog = NULL ;
6234       FREE_AV( grapher->setshift_right_av ) ;
6235       FREE_AV( grapher->setshift_left_av )  ;
6236       FREE_AV( grapher->setshift_inc_av )   ;
6237    }
6238 
6239    EXRETURN ;
6240 }
6241 
6242 /*-----------------------------------------------------------------------*/
6243 
GRA_doshift(MCW_grapher * grapher)6244 void GRA_doshift( MCW_grapher * grapher )
6245 {
6246    MRI_IMAGE * tsim , * newim , * tim ;
6247    float * tsar , * nar , * tar ;
6248    int ii,ivec , nx , newny , nleft,nright ;
6249    float shinc ;
6250    GRA_cbs gbs ;
6251 
6252 ENTRY("GRA_doshift") ;
6253 
6254    if( !GRA_VALID(grapher) ) EXRETURN ;
6255 
6256    if( grapher->status->send_CB == NULL                       ||
6257        grapher->setshift_inc <= 0.0                           ||
6258        grapher->setshift_left + grapher->setshift_right <= 0  ||
6259        grapher->ref_ts == NULL                                ||
6260        IMARR_COUNT(grapher->ref_ts) == 0                        ){
6261 
6262       BEEPIT ; WARNING_message("Can't execute shift operation!?") ; EXRETURN ;
6263    }
6264 
6265    tsim = IMARR_SUBIMAGE(grapher->ref_ts,0) ; /* current ref */
6266    tsar = MRI_FLOAT_PTR(tsim) ;
6267    nx   = tsim->nx ;
6268 
6269    shinc  = grapher->setshift_inc ;
6270    nleft  = grapher->setshift_left ;
6271    nright = grapher->setshift_right ;
6272    newny  = 1 + nleft + nright ;
6273    newim  = mri_new( nx , newny , MRI_float ) ;
6274    nar    = MRI_FLOAT_PTR(newim) ;
6275 
6276    for( ii=0 ; ii < nx ; ii++ )
6277       nar[ii] = (ii < NIGNORE(grapher) ) ? WAY_BIG : tsar[ii] ;
6278 
6279    for( ivec=1 ; ivec <= nleft ; ivec++ ){
6280       tim = mri_shift_1D( newim , -ivec * shinc ) ;
6281       tar = MRI_FLOAT_PTR(tim) ;
6282       for( ii=0 ; ii < nx ; ii++ ) nar[ii+ivec*nx] = tar[ii] ;
6283       mri_free(tim) ;
6284    }
6285 
6286    for( ivec=1 ; ivec <= nright ; ivec++ ){
6287       tim = mri_shift_1D( newim , ivec * shinc ) ;
6288       tar = MRI_FLOAT_PTR(tim) ;
6289       for( ii=0 ; ii < nx ; ii++ ) nar[ii+(ivec+nleft)*nx] = tar[ii] ;
6290       mri_free(tim) ;
6291    }
6292 
6293    { GRA_cbs cbs; cbs.reason=graCR_winaver; CALL_sendback(grapher,cbs); }
6294    MCW_set_bbox( grapher->fmenu->fim_editref_winaver_bbox , 0 ) ;
6295    gbs.reason   = graCR_refequals ;
6296    gbs.userdata = (XtPointer) newim ;
6297 #if 0
6298    grapher->status->send_CB( grapher , grapher->getaux , &gbs ) ;
6299 #else
6300    CALL_sendback( grapher , gbs ) ;
6301 #endif
6302    mri_free( newim ) ;
6303    EXRETURN ;
6304 }
6305 
6306 /*---------------------------------------------------------------------
6307   Returns a bunch of widgets in a structure.
6308   The parent widget is intended to be a menu bar.
6309 -----------------------------------------------------------------------*/
6310 
AFNI_new_fim_menu(Widget parent,XtCallbackProc cbfunc,int graphable)6311 FIM_menu * AFNI_new_fim_menu( Widget parent, XtCallbackProc cbfunc, int graphable )
6312 {
6313    FIM_menu *fmenu ;
6314    Widget qbut_menu = NULL ;
6315 
6316 ENTRY("AFNI_new_fim_menu") ;
6317 
6318    fmenu = myXtNew(FIM_menu) ;
6319    fmenu->cbfunc = cbfunc ;
6320 
6321    /*------------------------*/
6322    /*--- FIM Menu Buttons ---*/
6323    /*------------------------*/
6324 
6325    fmenu->fim_menu = XmCreatePulldownMenu( parent , "menu" , NULL,0 ) ;
6326 
6327    VISIBILIZE_WHEN_MAPPED(fmenu->fim_menu) ;  /* 27 Sep 2000 */
6328 #if 0
6329    if( !AFNI_yesenv("AFNI_DISABLE_TEAROFF") ) TEAROFFIZE(fmenu->fim_menu) ;
6330 #endif
6331 
6332    fmenu->fim_cbut =
6333          XtVaCreateManagedWidget(
6334             "dialog" , xmCascadeButtonWidgetClass , parent ,
6335                LABEL_ARG("FIM") ,
6336                XmNsubMenuId , fmenu->fim_menu ,
6337                XmNmarginWidth  , 0 ,
6338                XmNmarginHeight , 0 ,
6339                XmNmarginBottom , 0 ,
6340                XmNmarginTop    , 0 ,
6341                XmNmarginRight  , 0 ,
6342                XmNmarginLeft   , 0 ,
6343                XmNtraversalOn  , True  ,
6344                XmNinitialResourcesPersistent , False ,
6345             NULL ) ;
6346 
6347    if( graphable ){
6348       MCW_register_hint( fmenu->fim_cbut , "Functional Imaging menu" ) ;
6349       MCW_register_help( fmenu->fim_cbut ,
6350                       "*******  Functional Imaging Controls:  *******\n"
6351                       "\n"
6352                       "Ideal Vector Operations:\n"
6353                       " Pick Ideal --> Choose from a list\n"
6354                       " Pick Ort   --> Choose from a list\n"
6355                       " Edit: = Center --> Use voxel timeseries\n"
6356                       "      += Center --> Average with voxel\n"
6357                       "      Smooth    --> A 3 point filter\n"
6358                       "      Shift     --> Time-shifted copies\n"
6359                       "      Clear     --> Turn ideal off\n"
6360                       "      WinAver   --> Average of sub-graphs\n"
6361                       "      Read      --> Input from external file\n"
6362                       "      Write     --> Output to external file\n"
6363                       "      Store     --> Save in internal list\n"
6364                       " Ignore: Set how many points to ignore\n"
6365                       "         at beginning of time series\n"
6366                       "         [ Applies both to graphing ]\n"
6367                       "         [ and to FIM computations. ]\n"
6368                       "\n"
6369                       "FIM Plots:\n"
6370                       "  Can choose to graph only first vector in\n"
6371                       "  ideal family, or all of them superimposed.\n"
6372                       "\n"
6373                       "Refresh Freq --> Choose number of time steps\n"
6374                       "   between redisplay of the functional overlay\n"
6375                       "   during FIM computations (0 == no redisplay).\n"
6376                       "Compute FIM  --> Use the recursive method to\n"
6377                       "   compute the correlation of each voxel time\n"
6378                       "   series with each ideal vector;  uses the best\n"
6379                       "   correlation as the 'correct' waveform for\n"
6380                       "   each voxel, individually.  Time points that\n"
6381                       "   have an ideal vector value >= 33333 will be\n"
6382                       "   ignored in the computations, as will those\n"
6383                       "   at the beginning specified in the Opt menu\n"
6384                       "   'Ignore' function."
6385                     ) ;
6386    } else {
6387       MCW_register_hint( fmenu->fim_cbut , "Functional Imaging menu" ) ;
6388       MCW_register_help( fmenu->fim_cbut ,
6389                       "*******  Functional Imaging Controls:  *******\n"
6390                       "\n"
6391                       "Pick Dataset --> Choose time-dependent dataset\n"
6392                       "   from a list.  If there is only one possible\n"
6393                       "   choice, it will be selected for you without\n"
6394                       "   displaying the list.\n"
6395                       "\n"
6396                       "Pick Ideal --> Choose time series from a list.\n"
6397                       "Pick Ort   --> Choose time series from a list.\n"
6398                       "\n"
6399                       "Ignore --> Set how many points to ignore at the\n"
6400                       "   beginning of time series.\n"
6401                       "   [ Applies both to graphing and FIM-ing. ]\n"
6402                       "\n"
6403                       "Refresh Freq --> Choose number of time steps\n"
6404                       "   between redisplay of the functional overlay\n"
6405                       "   during FIM computations (0 == no redisplay).\n"
6406                       "\n"
6407                       "Compute FIM --> Use the recursive method to\n"
6408                       "   compute the correlation of each voxel time\n"
6409                       "   series with each ideal vector;  uses the best\n"
6410                       "   correlation as the 'correct' waveform for\n"
6411                       "   each voxel, individually.  Time points that\n"
6412                       "   have an ideal vector value >= 33333 will be\n"
6413                       "   ignored in the computations, as will those\n"
6414                       "   at the beginning specified in the Opt menu\n"
6415                       "   'Ignore' function."
6416                     ) ;
6417    }
6418 
6419    /* macros to put double and single separator lines in a menu */
6420 
6421 #undef MENU_DLINE
6422 #define MENU_DLINE(wmenu)                                        \
6423    (void) XtVaCreateManagedWidget(                               \
6424             "dialog" , xmSeparatorWidgetClass , fmenu -> wmenu , \
6425              XmNseparatorType , XmDOUBLE_LINE , NULL )
6426 
6427 #undef MENU_SLINE
6428 #define MENU_SLINE(wmenu)                                        \
6429    (void) XtVaCreateManagedWidget(                               \
6430             "dialog" , xmSeparatorWidgetClass , fmenu -> wmenu , \
6431              XmNseparatorType , XmSINGLE_LINE , NULL )
6432 
6433    /* macro to create a new FIM menu button */
6434 
6435 #define FIM_MENU_BUT(wname,label,hhh)                              \
6436    fmenu -> wname =                                                \
6437          XtVaCreateManagedWidget(                                  \
6438             "dialog" , xmPushButtonWidgetClass , fmenu->fim_menu , \
6439                LABEL_ARG( label ) ,                                \
6440                XmNmarginHeight , 0 ,                               \
6441                XmNtraversalOn , True  ,                            \
6442                XmNinitialResourcesPersistent , False ,             \
6443             NULL ) ;                                               \
6444       XtAddCallback( fmenu -> wname , XmNactivateCallback ,        \
6445                      cbfunc , (XtPointer) fmenu ) ;                \
6446       MCW_register_hint( fmenu -> wname , hhh ) ;
6447 
6448    /** macro to create a new fim pullright menu **/
6449    /** 07 Jan 1999: added the mapCallback to fix position **/
6450 
6451 #define FIM_MENU_PULLRIGHT(wmenu,wcbut,label,hhh)                  \
6452    fmenu -> wmenu =                                                \
6453      XmCreatePulldownMenu( fmenu->fim_menu , "menu" , NULL , 0 ) ; \
6454    fmenu -> wcbut =                                                \
6455      XtVaCreateManagedWidget(                                      \
6456        "dialog" , xmCascadeButtonWidgetClass , fmenu->fim_menu ,   \
6457           LABEL_ARG( label ) ,                                     \
6458           XmNsubMenuId , fmenu -> wmenu ,                          \
6459           XmNtraversalOn , True  ,                                 \
6460           XmNinitialResourcesPersistent , False ,                  \
6461        NULL ) ;                                                    \
6462    MCW_register_hint( fmenu -> wcbut , hhh ) ;                     \
6463    XtAddCallback( fmenu -> wmenu, XmNmapCallback, GRA_mapmenu_CB, NULL ) ;
6464 
6465    /** macro to create a new button on a pullright menu **/
6466 
6467 #define FIM_MENU_PULL_BUT(wmenu,wname,label,hhh)                  \
6468    fmenu -> wname =                                               \
6469          XtVaCreateManagedWidget(                                 \
6470             "dialog" , xmPushButtonWidgetClass , fmenu -> wmenu , \
6471                LABEL_ARG( label ) ,                               \
6472                XmNmarginHeight , 0 ,                              \
6473                XmNtraversalOn , True  ,                           \
6474                XmNinitialResourcesPersistent , False ,            \
6475             NULL ) ;                                              \
6476       XtAddCallback( fmenu -> wname , XmNactivateCallback ,       \
6477                      cbfunc , (XtPointer) fmenu ) ;               \
6478       MCW_register_hint( fmenu -> wname , hhh ) ;
6479 
6480 #define EMPTY_BUT(wname) fmenu -> wname = NULL
6481 
6482    /** 15 Dec 1997: a pullright menu with a single button **/
6483 
6484 #define FIM_MENU_QBUT(wname,label,qlab,hhh)                               \
6485  do { Widget ccc ;                                                        \
6486       qbut_menu = XmCreatePulldownMenu(fmenu->fim_menu,"menu",NULL,0);    \
6487             ccc = XtVaCreateManagedWidget( "dialog" ,                     \
6488                      xmCascadeButtonWidgetClass , fmenu->fim_menu ,       \
6489                      LABEL_ARG( label ) ,                                 \
6490                      XmNsubMenuId , qbut_menu ,                           \
6491                      XmNtraversalOn , True  ,                             \
6492                      XmNinitialResourcesPersistent , False , NULL ) ;     \
6493       fmenu -> wname = XtVaCreateManagedWidget( "dialog" ,                \
6494                          xmPushButtonWidgetClass , qbut_menu ,            \
6495                          LABEL_ARG( qlab ) ,                              \
6496                          XmNmarginHeight , 0 ,                            \
6497                          XmNtraversalOn , True  ,                         \
6498                          XmNinitialResourcesPersistent , False , NULL ) ; \
6499       MCW_register_hint( fmenu -> wname , hhh ) ;                         \
6500       XtAddCallback( fmenu -> wname , XmNactivateCallback ,               \
6501                      cbfunc , (XtPointer) fmenu ) ;                       \
6502       XtAddCallback( qbut_menu, XmNmapCallback, GRA_mapmenu_CB, NULL ) ;  \
6503  } while(0)
6504 
6505    /*** top of menu = a label to click on that does nothing at all ***/
6506 #ifdef USING_LESSTIF
6507 
6508                /* Using  xmLabelWidgetClass causes X11 to hang until
6509                afni is terminated. For details, see preceding comment.
6510                for another --- Cancel --- button.
6511 
6512                            LessTif patrol      Jan. 07 09  */
6513    (void) XtVaCreateManagedWidget(
6514             "dialog" , xmPushButtonWidgetClass , fmenu->fim_menu ,
6515                LABEL_ARG("--- Cancel ---") ,
6516                XmNrecomputeSize , False ,
6517                XmNinitialResourcesPersistent , False ,
6518             NULL ) ;
6519 #else
6520    wtemp = XtVaCreateManagedWidget(
6521             "dialog" , xmLabelWidgetClass , fmenu->fim_menu ,
6522                LABEL_ARG("--- Cancel ---") ,
6523                XmNrecomputeSize , False ,
6524                XmNinitialResourcesPersistent , False ,
6525             NULL ) ; LABELIZE(wtemp) ;
6526 #endif
6527 
6528    MENU_SLINE(fim_menu) ;
6529 
6530    if( graphable ){
6531       EMPTY_BUT(fim_pickdset_pb) ;
6532    } else {
6533       FIM_MENU_BUT( fim_pickdset_pb , "Pick Dataset" , "Choose Dataset to Graph" ) ;
6534    }
6535 
6536    FIM_MENU_BUT( fim_pickref_pb , "Pick Ideal" , "Pick Ideal Timeseries to Graph" ) ;
6537    FIM_MENU_BUT( fim_pickort_pb , "Pick Ort"   , "Pick Ort Timeseries to Graph"   ) ;
6538 
6539    if( graphable ){
6540       char *bbox_label[1] = { "Ideal=WinAver" } ;
6541       MENU_SLINE(fim_menu) ;
6542       FIM_MENU_PULLRIGHT(fim_editref_menu,fim_editref_cbut       ,"Edit Ideal"    , "Modify Ideal Timeseries" ) ;
6543       FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_equals_pb  ,"Ideal = Center", "Set to Center Sub-graph" ) ;
6544       FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_add_pb     ,"Ideal+= Center", "Add in Center Sub-graph" ) ;
6545       FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_smooth_pb  ,"Smooth Ideal"  , "Lowpass Filter Ideal"    ) ;
6546       FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_setshift_pb,"Shift Ideal"   , "Time Shift Ideal"        ) ;
6547       FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_clear_pb   ,"Clear Ideal"   , "Turn Ideal Off"          ) ;
6548       FIM_MENU_PULL_BUT (fim_editref_menu,fim_editort_clear_pb   ,"Clear Ort"     , "Turn Ort Off"            ) ;
6549 
6550       fmenu->fim_editref_winaver_bbox                      /* 27 Jan 2004 */
6551        = new_MCW_bbox( fmenu->fim_editref_menu ,
6552                        1 , bbox_label , MCW_BB_check , MCW_BB_noframe ,
6553                        GRA_winaver_CB , (XtPointer)fmenu ) ;
6554       MCW_reghint_children( fmenu->fim_editref_winaver_bbox->wrowcol ,
6555                             "Ideal = Average of all Graphs in Window" ) ;
6556 #ifdef USE_OPTMENUS
6557       fmenu->fim_polort_choose_av =
6558          new_MCW_optmenu( fmenu->fim_editref_menu , "Polort " , 0,MAX_POLORT,1,0 ,
6559                           GRA_fmenu_av_CB , (XtPointer) fmenu , NULL , NULL ) ;
6560       fmenu->fim_polort_choose_pb = fmenu->fim_polort_choose_av->wrowcol ;
6561       MCW_reghint_children( fmenu->fim_polort_choose_av->wrowcol , "Order of Polynomial Baseline for FIM" ) ;
6562 #else
6563       FIM_MENU_PULL_BUT( fim_editref_menu,fim_polort_choose_pb ,"Polort?", "Order of Polynomial Baseline for FIM") ;
6564 #endif
6565       FIM_MENU_PULL_BUT( fim_editref_menu,fim_bkthr_choose_pb  ,"Bkg Thresh" , "Choose Background Threshold for FIM") ;
6566       MENU_SLINE        (fim_editref_menu) ;
6567       FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_read_pb    ,"Read Ideal" , "Read from .1D file"   ) ;
6568       FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_write_pb   ,"Write Ideal", "Write to .1D file"    ) ;
6569       FIM_MENU_PULL_BUT (fim_editref_menu,fim_editref_store_pb   ,"Store Ideal", "Save in internal list of timeseries" ) ;
6570    } else {
6571       EMPTY_BUT(fim_editref_cbut) ;
6572       EMPTY_BUT(fim_editref_equals_pb) ;
6573       EMPTY_BUT(fim_editref_add_pb) ;
6574       EMPTY_BUT(fim_editref_smooth_pb) ;
6575       EMPTY_BUT(fim_editref_setshift_pb) ;
6576       EMPTY_BUT(fim_editref_clear_pb) ;
6577       EMPTY_BUT(fim_editref_read_pb) ;
6578       EMPTY_BUT(fim_editref_write_pb) ;
6579       EMPTY_BUT(fim_editref_store_pb) ;
6580       EMPTY_BUT(fim_editort_clear_pb) ;
6581       EMPTY_BUT(fim_polort_choose_pb) ;
6582       fmenu->fim_editref_winaver_bbox = NULL ;  /* 27 Jan 2004 */
6583    }
6584 
6585    FIM_MENU_PULLRIGHT(fim_ignore_menu,fim_ignore_cbut      ,"Ignore", "Number of initial timepoints to ignore" ) ;
6586    FIM_MENU_PULL_BUT( fim_ignore_menu,fim_ignore_down_pb   ,"Down"  , "Ignore fewer points" ) ;
6587    FIM_MENU_PULL_BUT( fim_ignore_menu,fim_ignore_up_pb     ,"Up"    , "Ignore more points"  ) ;
6588 #ifdef USE_OPTMENUS
6589    fmenu->fim_ignore_choose_av =
6590       new_MCW_optmenu( fmenu->fim_ignore_menu , "# " , 0,2,0,0 ,
6591                        GRA_fmenu_av_CB , (XtPointer) fmenu , NULL , NULL ) ;
6592    fmenu->fim_ignore_choose_pb = fmenu->fim_ignore_choose_av->wrowcol ;
6593    MCW_reghint_children( fmenu->fim_ignore_choose_av->wrowcol , "Pick number of ignored points" ) ;
6594 #else
6595    FIM_MENU_PULL_BUT( fim_ignore_menu,fim_ignore_choose_pb ,"Choose" , "Pick number of ignored points") ;
6596 #endif
6597 
6598    if( graphable ){
6599       FIM_MENU_PULLRIGHT(fim_plot_menu,fim_plot_cbut        ,"FIM Plots"   , "Number of Ideals to plot" ) ;
6600       FIM_MENU_PULL_BUT( fim_plot_menu,fim_plot_firstref_pb ,"First Ideal" , "Only plot 1 Ideal" ) ;
6601       FIM_MENU_PULL_BUT( fim_plot_menu,fim_plot_allrefs_pb  ,"All Ideals"  , "Plot all Ideals"   ) ;
6602    } else {
6603       EMPTY_BUT(fim_plot_cbut) ;
6604       EMPTY_BUT(fim_plot_firstref_pb) ;
6605       EMPTY_BUT(fim_plot_allrefs_pb) ;
6606    }
6607 
6608    MENU_DLINE(fim_menu) ;
6609    FIM_MENU_QBUT( fim_execute_pb   , "Compute FIM" , "-> fico" , "Correlation Analysis" ) ;
6610    MCW_set_widget_bg( fmenu->fim_execute_pb ,
6611                       MCW_hotcolor(fmenu->fim_execute_pb) , 0 ) ;
6612 
6613    { static char * blab[] = {"Fit Coef", "% Change", "% From Ave", "% From Top"};
6614      (void) XtVaCreateManagedWidget(
6615              "dialog" , xmSeparatorWidgetClass , qbut_menu ,
6616               XmNseparatorType , XmSINGLE_LINE , NULL ) ;
6617 
6618      fmenu->fim_opt_bbox = new_MCW_bbox( qbut_menu , 4 , blab ,
6619                                          MCW_BB_radio_one , MCW_BB_noframe ,
6620                                          NULL , NULL ) ;
6621      MCW_reghint_children( fmenu->fim_opt_bbox->wrowcol , "What to Compute" ) ;
6622    }
6623 
6624    MENU_DLINE(fim_menu) ;
6625    FIM_MENU_QBUT( fim_execfimp_pb  , "Compute FIM+" , "-> fbuc" , "Extended Correlation Analysis" ) ;
6626    MCW_set_widget_bg( fmenu->fim_execfimp_pb ,
6627                       MCW_hotcolor(fmenu->fim_execfimp_pb) , 0 ) ;
6628 
6629    (void) XtVaCreateManagedWidget(
6630            "dialog" , xmSeparatorWidgetClass , qbut_menu ,
6631             XmNseparatorType , XmSINGLE_LINE , NULL ) ;
6632 
6633    fmenu->fimp_opt_bbox = new_MCW_bbox( qbut_menu, FIM_NUM_OPTS, fim_opt_labels,
6634                                         MCW_BB_check , MCW_BB_noframe ,
6635                                         NULL , NULL ) ;
6636    MCW_reghint_children( fmenu->fimp_opt_bbox->wrowcol , "What to Compute" ) ;
6637 
6638    { char * ff = my_getenv( "AFNI_FIM_MASK" ) ; int mm=0 ;
6639      if( ff != NULL ) mm = strtol(ff,NULL,10) ;
6640      if( mm <= 0 ) mm = FIM_DEFAULT_MASK ;
6641      MCW_set_bbox( fmenu->fimp_opt_bbox , mm ) ;
6642    }
6643 
6644    /* 04 Jan 2000: add some more buttons */
6645 
6646    (void) XtVaCreateManagedWidget(
6647            "dialog" , xmSeparatorWidgetClass , qbut_menu ,
6648             XmNseparatorType , XmSINGLE_LINE , NULL ) ;
6649 
6650    fmenu->fimp_setdefault_pb =
6651       XtVaCreateManagedWidget( "dialog" , xmPushButtonWidgetClass , qbut_menu ,
6652                                  LABEL_ARG( "Set Defaults" ) ,
6653                                  XmNmarginHeight , 0 ,
6654                                  XmNtraversalOn , True  ,
6655                                  XmNinitialResourcesPersistent , False ,
6656                                NULL ) ;
6657    XtAddCallback( fmenu->fimp_setdefault_pb ,
6658                   XmNactivateCallback , cbfunc , (XtPointer) fmenu ) ;
6659    MCW_register_hint( fmenu->fimp_setdefault_pb , "Default computing options" ) ;
6660 
6661    fmenu->fimp_setall_pb =
6662       XtVaCreateManagedWidget( "dialog" , xmPushButtonWidgetClass , qbut_menu ,
6663                                  LABEL_ARG( "Set All" ) ,
6664                                  XmNmarginHeight , 0 ,
6665                                  XmNtraversalOn , True  ,
6666                                  XmNinitialResourcesPersistent , False ,
6667                                NULL ) ;
6668    XtAddCallback( fmenu->fimp_setall_pb ,
6669                   XmNactivateCallback , cbfunc , (XtPointer) fmenu ) ;
6670    MCW_register_hint( fmenu->fimp_setall_pb , "Set all computing options on" ) ;
6671 
6672    fmenu->fimp_unsetall_pb =
6673       XtVaCreateManagedWidget( "dialog" , xmPushButtonWidgetClass , qbut_menu ,
6674                                  LABEL_ARG( "Unset All" ) ,
6675                                  XmNmarginHeight , 0 ,
6676                                  XmNtraversalOn , True  ,
6677                                  XmNinitialResourcesPersistent , False ,
6678                                NULL ) ;
6679    XtAddCallback( fmenu->fimp_unsetall_pb ,
6680                   XmNactivateCallback , cbfunc , (XtPointer) fmenu ) ;
6681    MCW_register_hint( fmenu->fimp_unsetall_pb , "Set all computing options off" ) ;
6682 
6683    /* 01 Feb 2000: add user-contributed options (if any) */
6684 
6685    fmenu->fimp_user_bbox = NULL ; /* default = no menu */
6686 
6687    if( GLOBAL_library.registered_fim.num > 0 ){
6688 
6689       (void) XtVaCreateManagedWidget(
6690               "dialog" , xmSeparatorWidgetClass , qbut_menu ,
6691                XmNseparatorType , XmDOUBLE_LINE , NULL ) ;
6692 
6693       wtemp = XtVaCreateManagedWidget(
6694                "dialog" , xmLabelWidgetClass , qbut_menu ,
6695                   LABEL_ARG("--Extra Funcs--") ,
6696                   XmNrecomputeSize , False ,
6697                   XmNinitialResourcesPersistent , False ,
6698                NULL ) ; LABELIZE(wtemp) ;
6699 
6700       fmenu->fimp_user_bbox = new_MCW_bbox( qbut_menu,
6701                                             GLOBAL_library.registered_fim.num ,
6702                                             GLOBAL_library.registered_fim.labels ,
6703                                             MCW_BB_check , MCW_BB_noframe ,
6704                                             NULL , NULL ) ;
6705       MCW_reghint_children( fmenu->fimp_user_bbox->wrowcol , "Other correlation functions" ) ;
6706    }
6707 
6708    RETURN(fmenu) ;
6709 }
6710 
6711 /*-----------------------------------------------------------------------------
6712    Routines to handle point transformations of a timeseries (22 Oct 1996)
6713 -------------------------------------------------------------------------------*/
6714 
GRA_transform_label(MCW_arrowval * av,XtPointer cd)6715 char * GRA_transform_label( MCW_arrowval * av , XtPointer cd )
6716 {
6717    MCW_function_list * xforms = (MCW_function_list *) cd ;
6718 
6719    if( av == NULL    || xforms == NULL        ||
6720        av->ival <= 0 || av->ival > xforms->num  ) return "-none-" ;
6721 
6722    return xforms->labels[av->ival - 1] ;  /* label for each function */
6723 }
6724 
6725 /*-----------------------------------------------------------------------------*/
6726 /*! Will be called from both the 1D and 0D menus. */
6727 
GRA_transform_CB(MCW_arrowval * av,XtPointer cd)6728 void GRA_transform_CB( MCW_arrowval *av , XtPointer cd )
6729 {
6730    MCW_grapher *grapher = (MCW_grapher *)cd ;
6731    int set_dplot = 0 ;  /* 04 Oct 2007 */
6732 
6733 ENTRY("GRA_transform_CB") ;
6734 
6735    if( ! GRA_VALID(grapher) ) EXRETURN ;
6736 
6737    /** set the 0D transform function pointer **/
6738 
6739    if( av == grapher->transform0D_av && av != NULL ){
6740       if( grapher->status->transforms0D == NULL || av->ival <= 0 ||
6741           av->ival > grapher->status->transforms0D->num            ){
6742 
6743          grapher->transform0D_func  = NULL ;  /* no transform */
6744          grapher->transform0D_index = 0 ;
6745       } else {
6746          grapher->transform0D_func  = grapher->status->transforms0D->funcs[av->ival-1];
6747          grapher->transform0D_index = av->ival ;
6748          grapher->transform0D_flags = grapher->status->transforms0D->flags[av->ival-1];
6749 
6750          if( grapher->transform0D_flags & SET_DPLOT_OVERLAY ) set_dplot = 1 ;
6751 
6752          /* 21 Jul 2003: call the init function, if present */
6753 
6754          if( grapher->status->transforms0D->func_init[av->ival-1] != NULL )
6755           grapher->status->transforms0D->func_init[av->ival-1]() ;
6756       }
6757    }
6758 
6759    /** set the 1D transform function pointer **/
6760 
6761    if( av == grapher->transform1D_av && av != NULL ){
6762       if( grapher->status->transforms1D == NULL || av->ival <= 0 ||
6763           av->ival > grapher->status->transforms1D->num            ){
6764 
6765          grapher->transform1D_func  = NULL ;  /* no transform */
6766          grapher->transform1D_index = 0 ;
6767       } else {
6768          grapher->transform1D_func  = grapher->status->transforms1D->funcs[av->ival-1];
6769          grapher->transform1D_index = av->ival ;
6770          grapher->transform1D_flags = grapher->status->transforms1D->flags[av->ival-1];
6771 
6772          if( grapher->transform1D_flags & SET_DPLOT_OVERLAY ) set_dplot = 1 ;
6773 
6774          /* 21 Jul 2003: call the init function, if present */
6775 
6776          if( grapher->status->transforms1D->func_init[av->ival-1] != NULL )
6777           grapher->status->transforms1D->func_init[av->ival-1]() ;
6778       }
6779    }
6780 
6781    if( set_dplot == 1 && !DATA_BOXED(grapher) )  /* 04 Oct 2007 */
6782      MCW_set_bbox( grapher->opt_dplot_bbox , DPLOT_OVERLAY ) ;
6783 
6784    redraw_graph( grapher , 0 ) ;
6785    EXRETURN ;
6786 }
6787 
6788 /*----------------------------------------------------------------------------
6789    22 Sep 2000: for textgraph toggle
6790 ------------------------------------------------------------------------------*/
6791 
GRA_textgraph_CB(Widget w,XtPointer client_data,XtPointer call_data)6792 void GRA_textgraph_CB( Widget w , XtPointer client_data , XtPointer call_data )
6793 {
6794    MCW_grapher *grapher = (MCW_grapher *) client_data ;
6795    int bbb ;
6796 
6797 ENTRY("GRA_textgraph_CB") ;
6798 
6799    if( ! GRA_VALID(grapher) ) EXRETURN ;
6800 
6801    bbb = MCW_val_bbox( grapher->opt_textgraph_bbox ) ;
6802    if( bbb != grapher->textgraph ){
6803      grapher->textgraph = bbb ;
6804      redraw_graph( grapher , 0 ) ;
6805    }
6806    EXRETURN ;
6807 }
6808 
6809 /*----------------------------------------------------------------------------
6810    Mar 2013: thresh fade toggle
6811 ------------------------------------------------------------------------------*/
6812 
GRA_tfade_CB(Widget w,XtPointer client_data,XtPointer call_data)6813 void GRA_tfade_CB( Widget w , XtPointer client_data , XtPointer call_data )
6814 {
6815    MCW_grapher *grapher = (MCW_grapher *)client_data ;
6816    int bbb ;
6817 
6818 ENTRY("GRA_tfade_CB") ;
6819 
6820    if( ! GRA_VALID(grapher) ) EXRETURN ;
6821 
6822    bbb = MCW_val_bbox( grapher->opt_tfade_bbox ) ;
6823    if( bbb != grapher->thresh_fade ){
6824      grapher->thresh_fade = bbb ;
6825      redraw_graph( grapher , 0 ) ;
6826    }
6827    EXRETURN ;
6828 }
6829 
6830 /*----------------------------------------------------------------------------
6831    22 Sep 2000: for new baseline toggle
6832 ------------------------------------------------------------------------------*/
6833 
GRA_baseline_CB(Widget w,XtPointer client_data,XtPointer call_data)6834 void GRA_baseline_CB( Widget w , XtPointer client_data , XtPointer call_data )
6835 {
6836    MCW_grapher *grapher = (MCW_grapher *) client_data ;
6837    int bbb ;
6838 
6839 ENTRY("GRA_baseline_CB") ;
6840 
6841    if( ! GRA_VALID(grapher) ) EXRETURN ;
6842 
6843    bbb = MCW_val_bbox( grapher->opt_baseline_bbox ) ;
6844    if( bbb != grapher->common_base ){
6845      grapher->common_base = bbb ;
6846      redraw_graph( grapher , 0 ) ;
6847    }
6848    EXRETURN ;
6849 }
6850 
6851 /*----------------------------------------------------------------------------
6852    Set the global baseline value
6853 ------------------------------------------------------------------------------*/
6854 
GRA_finalize_global_baseline_CB(Widget w,XtPointer cd,MCW_choose_cbs * cbs)6855 void GRA_finalize_global_baseline_CB( Widget w,
6856                                       XtPointer cd , MCW_choose_cbs *cbs )
6857 {
6858    MCW_grapher *grapher = (MCW_grapher *) cd ;
6859    XmString xstr ;
6860    char str[32] ;
6861 
6862 ENTRY("GRA_finalize_global_baseline_CB") ;
6863 
6864    if( !GRA_VALID(grapher) ) EXRETURN ;
6865 
6866    grapher->global_base = cbs->fval ;
6867    if( grapher->common_base == BASELINE_GLOBAL ) redraw_graph(grapher,0) ;
6868 
6869    strcpy(str,"Global:") ;
6870    AV_fval_to_char(grapher->global_base,str+7) ;
6871    xstr = XmStringCreateLtoR( str,XmFONTLIST_DEFAULT_TAG ) ;
6872    XtVaSetValues( grapher->opt_baseline_global_label ,
6873                      XmNlabelString,xstr ,
6874                   NULL ) ;
6875    XmStringFree(xstr) ;
6876    EXRETURN ;
6877 }
6878 
6879 /*----------------------------------------------------------------------------*/
6880 /*** user presses Ideal=WinAver toggle [27 Jan 2004] ***/
6881 
GRA_winaver_CB(Widget w,XtPointer client_data,XtPointer call_data)6882 void GRA_winaver_CB( Widget w , XtPointer client_data , XtPointer call_data )
6883 {
6884    FIM_menu *fm = (FIM_menu *)client_data ;
6885    MCW_grapher *grapher = (MCW_grapher *)fm->parent ;
6886 
6887    if( MCW_val_bbox(grapher->fmenu->fim_editref_winaver_bbox) ){
6888      GRA_cbs cbs ;
6889      cbs.reason  = graCR_winaver ;
6890      CALL_sendback( grapher , cbs ) ;
6891      redraw_graph( grapher , 0 ) ;
6892    }
6893 }
6894 /*----------------------------------------------------------------------------*/
6895 
GRA_winavertimer_CB(XtPointer cd,XtIntervalId * id)6896 void GRA_winavertimer_CB( XtPointer cd , XtIntervalId *id )
6897 {
6898    MCW_grapher *grapher = (MCW_grapher *)cd ;
6899    GRA_cbs cbs ;
6900 
6901    if( !GRA_REALZ(grapher) || grapher->ave_tsim == NULL ) return ;
6902 
6903    cbs.reason   = graCR_refequals ;
6904    cbs.userdata = (XtPointer)grapher->ave_tsim ;
6905    grapher->dont_redraw = 1 ;
6906    CALL_sendback( grapher , cbs ) ;
6907    grapher->dont_redraw = 0 ;
6908    return ;
6909 }
6910 
6911 /*----------------------------------------------------------------------------*/
6912 /*** set ref to average time series [27 Jan 2004] ***/
6913 
GRA_winaver_setref(MCW_grapher * grapher)6914 void GRA_winaver_setref( MCW_grapher *grapher )
6915 {
6916    GRA_cbs cbs ;
6917 
6918 ENTRY("GRA_winaver_setref") ;
6919 
6920    if( !GRA_REALZ(grapher) || grapher->ave_tsim == NULL ){
6921     STATUS("nothing to do") ; EXRETURN ;
6922    }
6923 
6924    (void)XtAppAddTimeOut( XtWidgetToApplicationContext(grapher->opt_quit_pb) ,
6925                           1 , GRA_winavertimer_CB , grapher ) ;
6926    EXRETURN ;
6927 }
6928 
6929 /*----------------------------------------------------------------------------
6930    08 Nov 1996: for "double plots" -- just redraw everything
6931 ------------------------------------------------------------------------------*/
6932 
GRA_dplot_change_CB(Widget w,XtPointer client_data,XtPointer call_data)6933 void GRA_dplot_change_CB( Widget w , XtPointer client_data , XtPointer call_data )
6934 {
6935    MCW_grapher *grapher = (MCW_grapher *) client_data ;
6936 
6937 ENTRY("GRA_dplot_change_CB") ;
6938 
6939    if( ! GRA_REALZ(grapher) ) EXRETURN ;
6940    redraw_graph( grapher , 0 ) ;
6941    EXRETURN ;
6942 }
6943 
6944 #ifdef USE_OPTMENUS
6945 /*---------------------------------------------------------------------------
6946    Fix the optmenus for the grapher; used when the dataset changes
6947    and so the upper limits on the selectors must change too
6948 -----------------------------------------------------------------------------*/
6949 
GRA_fix_optmenus(MCW_grapher * grapher)6950 void GRA_fix_optmenus( MCW_grapher *grapher )
6951 {
6952    int igtop ;
6953 
6954 ENTRY("GRA_fix_optmenus") ;
6955 
6956    if( ! GRA_REALZ(grapher) ) EXRETURN ;
6957 
6958    /** matrix selection **/
6959 
6960    if( grapher->opt_mat_choose_av->imax != grapher->mat_max )
6961       refit_MCW_optmenu( grapher->opt_mat_choose_av ,
6962                          1 , grapher->mat_max , grapher->mat , 0 ,
6963                          NULL , NULL ) ;
6964 
6965    else
6966       AV_assign_ival( grapher->opt_mat_choose_av , grapher->mat ) ;
6967 
6968    /** slice selection **/
6969 
6970    if( grapher->opt_slice_choose_av->imax != grapher->status->nz-1 )
6971       refit_MCW_optmenu( grapher->opt_slice_choose_av ,
6972                          0, grapher->status->nz - 1, grapher->zpoint, 0,
6973                          NULL , NULL ) ;
6974 
6975    else
6976       AV_assign_ival( grapher->opt_slice_choose_av , grapher->zpoint ) ;
6977 
6978    /** fim ignoration **/
6979 
6980    igtop = MIN( grapher->status->num_series-2 , 99 ) ;
6981    igtop = MAX( igtop , 1 ) ;
6982 
6983    if( grapher->fmenu->fim_ignore_choose_av->imax != igtop )
6984       refit_MCW_optmenu( grapher->fmenu->fim_ignore_choose_av ,
6985                          0 , igtop , grapher->init_ignore, 0,
6986                          NULL , NULL ) ;
6987    else
6988       AV_assign_ival( grapher->fmenu->fim_ignore_choose_av , grapher->init_ignore ) ;
6989 
6990    /** 27 May 1999: fim polort **/
6991 
6992    AV_assign_ival( grapher->fmenu->fim_polort_choose_av , grapher->polort ) ;
6993 
6994    EXRETURN ;
6995 }
6996 
6997 /*--------------------------------------------------------------------------*/
6998 
GRA_fmenu_av_CB(MCW_arrowval * av,XtPointer cd)6999 void GRA_fmenu_av_CB( MCW_arrowval* av , XtPointer cd )
7000 {
7001    FIM_menu *fmenu = (FIM_menu *) cd ;
7002 
7003 ENTRY("GRA_fmenu_av_CB") ;
7004    fmenu->cbfunc( av->wrowcol , cd , NULL ) ;
7005    EXRETURN ;
7006 }
7007 #endif /* USE_OPTMENUS */
7008 
7009 /*--------------------------------------------------------------------------
7010    Selection of a color submenu item
7011 ----------------------------------------------------------------------------*/
7012 
GRA_color_CB(MCW_arrowval * av,XtPointer cd)7013 void GRA_color_CB( MCW_arrowval *av , XtPointer cd )
7014 {
7015    MCW_grapher *grapher = (MCW_grapher *) cd ;
7016    int ii , jj ;
7017 
7018 ENTRY("GRA_color_CB") ;
7019 
7020    if( ! GRA_VALID(grapher) ) EXRETURN ;
7021 
7022    for( ii=0 ; ii < NUM_COLOR_ITEMS ; ii++ )
7023      if( av == grapher->opt_color_av[ii] ) break ;
7024 
7025    if( ii < NUM_COLOR_ITEMS ){
7026      jj = grapher->color_index[ii] ;
7027      grapher->color_index[ii] = av->ival ;
7028      if( jj != grapher->color_index[ii] ) redraw_graph( grapher , 0 ) ;
7029    }
7030    EXRETURN ;
7031 }
7032 
7033 /*--------------------------------------------------------------------------*/
7034 
GRA_thick_CB(Widget w,XtPointer cd,XtPointer call_data)7035 void GRA_thick_CB( Widget w , XtPointer cd , XtPointer call_data )
7036 {
7037    MCW_grapher *grapher = (MCW_grapher *) cd ;
7038    int ii , jj ;
7039 
7040 ENTRY("GRA_thick_CB") ;
7041 
7042    if( ! GRA_VALID(grapher) ) EXRETURN ;
7043 
7044    for( ii=0 ; ii < NUM_COLOR_ITEMS ; ii++ )
7045      if( grapher->opt_thick_bbox[ii] != NULL &&
7046          w == grapher->opt_thick_bbox[ii]->wbut[0] ) break ;
7047 
7048    if( ii < NUM_COLOR_ITEMS ){
7049      jj = grapher->thick_index[ii] ;
7050      grapher->thick_index[ii] = MCW_val_bbox( grapher->opt_thick_bbox[ii] ) ;
7051      if( jj != grapher->thick_index[ii] ) redraw_graph( grapher , 0 ) ;
7052      EXRETURN ;
7053    }
7054 
7055    /* 09 Jan 1998 */
7056 
7057    for( ii=0 ; ii < NUM_COLOR_ITEMS ; ii++ ){
7058      if( grapher->opt_points_bbox[ii] != NULL ){
7059        for( jj=0 ; jj < grapher->opt_points_bbox[ii]->nbut ; jj++ )
7060          if( w == grapher->opt_points_bbox[ii]->wbut[jj] ) break ;
7061        if( jj < grapher->opt_points_bbox[ii]->nbut ) break ;
7062      }
7063    }
7064 
7065    if( ii < NUM_COLOR_ITEMS ){
7066      jj = grapher->points_index[ii] ;
7067      grapher->points_index[ii] = MCW_val_bbox( grapher->opt_points_bbox[ii] ) ;
7068      if( jj != grapher->points_index[ii] ){
7069 #if 0
7070        if( DATA_BOXED(grapher) )
7071          MCW_set_bbox( grapher->opt_dplot_bbox , DPLOT_OFF ) ;
7072 #endif
7073        redraw_graph( grapher , 0 ) ;
7074      }
7075      EXRETURN ;
7076    }
7077 
7078    EXRETURN ;  /* should not be reached */
7079 }
7080 
7081 /*--------------------------------------------------------------------------
7082    Save the background pixmap to a PNM file
7083 ----------------------------------------------------------------------------*/
7084 
GRA_saver_CB(Widget wcaller,XtPointer cd,MCW_choose_cbs * cbs)7085 void GRA_saver_CB( Widget wcaller , XtPointer cd , MCW_choose_cbs *cbs )
7086 {
7087    int ll , ii ;
7088    MCW_grapher *grapher = (MCW_grapher *)cd ;
7089    char *fname , *ppnm ;
7090 
7091 ENTRY("GRA_saver_CB") ;
7092 
7093    if( ! GRA_REALZ(grapher) ) EXRETURN ;
7094 
7095    if( cbs->reason != mcwCR_string ||
7096        cbs->cval   == NULL         || (ll=strlen(cbs->cval)) == 0 ){
7097 
7098       BEEPIT ; WARNING_message("Bad save filename!?") ; EXRETURN ;
7099    }
7100 
7101    fname = (char *) malloc( sizeof(char) * (ll+8) ) ;
7102    strcpy( fname , cbs->cval ) ;
7103 
7104    for( ii=0 ; ii < ll ; ii++ )
7105      if( iscntrl(fname[ii]) || isspace(fname[ii]) ) break ;
7106 
7107    if( ii < ll || ll < 2 || ll > 240 ){
7108      BEEPIT ; free(fname) ; WARNING_message("Bad save filename!?") ; EXRETURN ;
7109    }
7110 
7111                       ppnm = strstr( fname , ".ppm" ) ;
7112    if( ppnm == NULL ) ppnm = strstr( fname , ".pnm" ) ;
7113    if( ppnm == NULL ) ppnm = strstr( fname , ".jpg" ) ;
7114    if( ppnm == NULL ) ppnm = strstr( fname , ".JPG" ) ;
7115    if( ppnm == NULL ) ppnm = strstr( fname , ".png" ) ;
7116    if( ppnm == NULL ) ppnm = strstr( fname , ".PNG" ) ;
7117    if( ppnm == NULL ) strcat(fname,".ppm") ;
7118 
7119    GRA_file_pixmap( grapher , fname ) ;
7120    POPDOWN_string_chooser ;
7121    free(fname) ; EXRETURN ;
7122 }
7123 
7124 /*--------------------------------------------------------------------------*/
7125 
GRA_file_pixmap(MCW_grapher * grapher,char * fname)7126 void GRA_file_pixmap( MCW_grapher *grapher , char *fname )
7127 {
7128    XImage *xim ;
7129    XGCValues gcv ;
7130    MRI_IMAGE *tim ;
7131    int ii ;
7132 
7133 ENTRY("GRA_file_pixmap") ;
7134 
7135    if( ! GRA_REALZ(grapher) ) EXRETURN ;
7136    if( grapher->fd_pxWind == (Pixmap) 0 ) EXRETURN ;
7137 
7138    ii = XGetGCValues( grapher->dc->display ,
7139                       grapher->dc->myGC , GCPlaneMask , &gcv ) ;
7140    if( ii == 0 ) EXRETURN ;
7141 
7142    xim = XGetImage( grapher->dc->display , grapher->fd_pxWind ,
7143                     0 , 0 , grapher->fWIDE , grapher->fHIGH ,
7144                     gcv.plane_mask , ZPixmap ) ;
7145    if( xim == NULL ) EXRETURN ;
7146 
7147    tim = XImage_to_mri( grapher->dc , xim , 0 ) ;
7148    if( tim == NULL ){ MCW_kill_XImage( xim ) ; EXRETURN ; }
7149 
7150    INFO_message("Writing grapher image to '%s'",fname) ;
7151    mri_write_pnm( fname , tim ) ;
7152    mri_free( tim ) ;
7153    MCW_kill_XImage( xim ) ;  /* 10 Mar 1999 */
7154    EXRETURN ;
7155 }
7156 
7157 /*-----------------------------------------------------------------------------
7158    07 Jan 1999: change location of newly popped up menu
7159 -------------------------------------------------------------------------------*/
7160 
GRA_mapmenu_CB(Widget w,XtPointer client_data,XtPointer call_data)7161 void GRA_mapmenu_CB( Widget w , XtPointer client_data , XtPointer call_data )
7162 {
7163    int ww,hh,xx,yy ;
7164    int pw,ph,px,py ;
7165 
7166 ENTRY("GRA_mapmenu_CB") ;
7167 
7168    #ifdef USING_LESSTIF
7169       EXRETURN; /* 30 Dec 2008, the LESSTIF patrol */
7170    #endif
7171    if( AFNI_yesenv("AFNI_DONT_MOVE_MENUS") ) EXRETURN ;  /* 08 Aug 2001 */
7172 
7173    MCW_widget_geom( w                     , &ww,&hh , &xx,&yy ) ;
7174    MCW_widget_geom( XtParent(XtParent(w)) , &pw,&ph , &px,&py ) ;
7175 
7176 #if 1
7177 if(PRINT_TRACING){
7178  char str[256] ;
7179  sprintf(str,"menu:   width=%d height=%d x=%d y=%d",ww,hh,xx,yy); STATUS(str);
7180  sprintf(str,"parent: width=%d height=%d x=%d y=%d",pw,ph,px,py); STATUS(str); }
7181 #endif
7182 
7183    pw = pw >> 3 ;
7184    if( ! ( xx > px+7*pw || xx+ww < px+pw ) ){
7185       xx = px - ww ;  if( xx < 0 ) xx = 0 ;
7186 #if 1
7187 if(PRINT_TRACING){
7188  char str[256]; sprintf(str,"moving menu to x=%d",xx); STATUS(str); }
7189 #endif
7190       XtVaSetValues( w , XmNx , xx , NULL ) ;
7191    }
7192 
7193    RWC_xineramize( XtDisplay(w) , xx,yy,ww,hh , &xx,&yy ) ; /* 27 Sep 2000 */
7194    XtVaSetValues( w , XmNx,xx , XmNy,yy , NULL ) ;
7195    EXRETURN ;
7196 }
7197 
7198 /*----------------------------------------------------------------------------*/
7199 /*! Do something every so often. */
7200 
GRA_timer_CB(XtPointer cd,XtIntervalId * id)7201 void GRA_timer_CB( XtPointer cd , XtIntervalId *id ) /* 03 Dec 2003 */
7202 {
7203    MCW_grapher *grapher = (MCW_grapher *)cd ;
7204    int redo = 0 ;
7205 
7206 ENTRY("GRA_timer_CB") ;
7207 
7208    if( !GRA_REALZ(grapher) || grapher->timer_id == 0 ) EXRETURN ;
7209 
7210    switch( grapher->timer_func ){
7211 
7212      case GRA_TIMERFUNC_INDEX:{
7213        int nn = grapher->time_index , nt=grapher->status->num_series ;
7214        if( nt > 1 && grapher->timer_param != 0 ){
7215          nn = (nn+grapher->timer_param+nt) % nt ;
7216          redo = 1 ;
7217          if( grapher->status->send_CB != NULL ){
7218            GRA_cbs cbs ;
7219            cbs.reason = graCR_setindex ;
7220            cbs.key    = nn ;
7221            cbs.event  = NULL ;
7222 #if 0
7223            grapher->status->send_CB( grapher, grapher->getaux, &cbs ) ;
7224 #else
7225            CALL_sendback( grapher , cbs ) ;
7226 #endif
7227          } else {
7228            (void)drive_MCW_grapher( grapher, graDR_setindex, (XtPointer)ITOP(nn)) ;
7229          }
7230        }
7231      }
7232      break ;
7233 
7234      case GRA_TIMERFUNC_BOUNCE:{
7235        int nn = grapher->time_index , nt=grapher->status->num_series ;
7236        if( nt > 1 && grapher->timer_param != 0 ){
7237          nn = nn + grapher->timer_param ;
7238          if( nn <  0  ){
7239            nn = -nn; grapher->timer_param = -grapher->timer_param;
7240          } else if( nn >= nt ){
7241            nn = 2*(nt-1)-nn; grapher->timer_param = -grapher->timer_param;
7242          }
7243          redo = 1 ;
7244          if( grapher->status->send_CB != NULL ){
7245            GRA_cbs cbs ;
7246            cbs.reason = graCR_setindex ;
7247            cbs.key    = nn ;
7248            cbs.event  = NULL ;
7249 #if 0
7250            grapher->status->send_CB( grapher, grapher->getaux, &cbs ) ;
7251 #else
7252            CALL_sendback( grapher , cbs ) ;
7253 #endif
7254          } else {
7255            (void)drive_MCW_grapher( grapher, graDR_setindex, (XtPointer)ITOP(nn)) ;
7256          }
7257        }
7258      }
7259      break ;
7260 
7261    }
7262 
7263    if( redo ) grapher->timer_id = XtAppAddTimeOut(
7264                                    XtWidgetToApplicationContext(grapher->opt_quit_pb) ,
7265                                    grapher->timer_delay , GRA_timer_CB , grapher ) ;
7266    else       grapher->timer_id = 0 ;
7267 
7268    EXRETURN ;
7269 }
7270 
7271 /*--------------------------------------------------------------------------*/
7272 
GRA_timer_stop(MCW_grapher * grapher)7273 void GRA_timer_stop( MCW_grapher *grapher )
7274 {
7275    if( grapher->timer_id > 0 ){
7276      XtRemoveTimeOut(grapher->timer_id); grapher->timer_id = 0;
7277    }
7278 }
7279 
7280 /*--------------------------------------------------------------------------*/
7281 /* externally set 1D transformation [19 Dec 2018] */
7282 
GRA_find_1D_transform(MCW_grapher * grapher,char * nam)7283 int GRA_find_1D_transform( MCW_grapher *grapher , char *nam )
7284 {
7285    int ii ;
7286 
7287    if( grapher == NULL || grapher->status->transforms1D == NULL ) return -1 ;
7288    if( nam == NULL || *nam == '\0' ) return -1 ;
7289 
7290    for( ii=0 ; ii < grapher->status->transforms1D->num ; ii++ ){
7291      if( strcmp( grapher->status->transforms1D->labels[ii] , nam ) == 0 )
7292        return ii ;
7293    }
7294 
7295    return -1 ;
7296 }
7297 
GRA_startup_1D_transform(char * nam)7298 void GRA_startup_1D_transform( char *nam )
7299 {
7300    if( startup_1D_transform != NULL ){
7301      free(startup_1D_transform) ;
7302      startup_1D_transform = NULL ;
7303    }
7304    if( nam != NULL && *nam != '\0' )
7305      startup_1D_transform = strdup(nam) ;
7306    return ;
7307 }
7308 
GRA_set_1D_transform(MCW_grapher * grapher,char * nam)7309 void GRA_set_1D_transform( MCW_grapher *grapher , char *nam )
7310 {
7311    int tt ;
7312 
7313    if( grapher == NULL ) return ;
7314    tt = GRA_find_1D_transform( grapher , nam ) ; if( tt < 0 ) return ;
7315 
7316    AV_assign_ival( grapher->transform1D_av , tt+1 ) ;
7317 
7318    grapher->transform1D_func  = grapher->status->transforms1D->funcs[tt];
7319    grapher->transform1D_index = tt+1 ;
7320    grapher->transform1D_flags = grapher->status->transforms1D->flags[tt];
7321 
7322 #if 0
7323    if( (grapher->transform1D_flags & SET_DPLOT_OVERLAY) && !DATA_BOXED(grapher) ){
7324      MCW_set_bbox( grapher->opt_dplot_bbox , DPLOT_OVERLAY ) ;
7325    }
7326 #endif
7327 
7328    /** redraw_graph( grapher , 0 ) ; **/
7329    return ;
7330 }
7331 
7332 /*--------------------------------------------------------------------------*/
7333 /** AFNI_XDrawLines() was moved from here to xdraw.c -- 30 Aug 2021 -- RWC */
7334 /*--------------------------------------------------------------------------*/
7335